diff --git a/.gitignore b/.gitignore index 047cf97..ba38703 100644 --- a/.gitignore +++ b/.gitignore @@ -98,3 +98,7 @@ cache/ # Blender portable specific # These are typically generated or downloaded at runtime *.log + +# Extension platform cache and local Python installs (rebuilt by Blender/extensions) +extensions/.cache/ +extensions/.local/ diff --git a/extensions/.cache/compat.dat b/extensions/.cache/compat.dat deleted file mode 100644 index a09bd0b..0000000 --- a/extensions/.cache/compat.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bef97ba74e24d8c8a602943ef94742df583d3be1b849107f5180ffd403c1c5a4 -size 858 diff --git a/extensions/.local/lib/python3.11/site-packages/attr/__init__.py b/extensions/.local/lib/python3.11/site-packages/attr/__init__.py deleted file mode 100644 index 5c6e065..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Classes Without Boilerplate -""" - -from functools import partial -from typing import Callable, Literal, Protocol - -from . import converters, exceptions, filters, setters, validators -from ._cmp import cmp_using -from ._config import get_run_validators, set_run_validators -from ._funcs import asdict, assoc, astuple, has, resolve_types -from ._make import ( - NOTHING, - Attribute, - Converter, - Factory, - _Nothing, - attrib, - attrs, - evolve, - fields, - fields_dict, - make_class, - validate, -) -from ._next_gen import define, field, frozen, mutable -from ._version_info import VersionInfo - - -s = attributes = attrs -ib = attr = attrib -dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) - - -class AttrsInstance(Protocol): - pass - - -NothingType = Literal[_Nothing.NOTHING] - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "asdict", - "assoc", - "astuple", - "attr", - "attrib", - "attributes", - "attrs", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "get_run_validators", - "has", - "ib", - "make_class", - "mutable", - "resolve_types", - "s", - "set_run_validators", - "setters", - "validate", - "validators", -] - - -def _make_getattr(mod_name: str) -> Callable: - """ - Create a metadata proxy for packaging information that uses *mod_name* in - its warnings and errors. - """ - - def __getattr__(name: str) -> str: - if name not in ("__version__", "__version_info__"): - msg = f"module {mod_name} has no attribute {name}" - raise AttributeError(msg) - - from importlib.metadata import metadata - - meta = metadata("attrs") - - if name == "__version_info__": - return VersionInfo._from_version_string(meta["version"]) - - return meta["version"] - - return __getattr__ - - -__getattr__ = _make_getattr(__name__) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/__init__.pyi b/extensions/.local/lib/python3.11/site-packages/attr/__init__.pyi deleted file mode 100644 index 133e501..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/__init__.pyi +++ /dev/null @@ -1,389 +0,0 @@ -import enum -import sys - -from typing import ( - Any, - Callable, - Generic, - Literal, - Mapping, - Protocol, - Sequence, - TypeVar, - overload, -) - -# `import X as X` is required to make these public -from . import converters as converters -from . import exceptions as exceptions -from . import filters as filters -from . import setters as setters -from . import validators as validators -from ._cmp import cmp_using as cmp_using -from ._typing_compat import AttrsInstance_ -from ._version_info import VersionInfo -from attrs import ( - define as define, - field as field, - mutable as mutable, - frozen as frozen, - _EqOrderType, - _ValidatorType, - _ConverterType, - _ReprArgType, - _OnSetAttrType, - _OnSetAttrArgType, - _FieldTransformer, - _ValidatorArgType, -) - -if sys.version_info >= (3, 10): - from typing import TypeGuard, TypeAlias -else: - from typing_extensions import TypeGuard, TypeAlias - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -__version__: str -__version_info__: VersionInfo -__title__: str -__description__: str -__url__: str -__uri__: str -__author__: str -__email__: str -__license__: str -__copyright__: str - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_FilterType = Callable[["Attribute[_T]", _T], bool] - -# We subclass this here to keep the protocol's qualified name clean. -class AttrsInstance(AttrsInstance_, Protocol): - pass - -_A = TypeVar("_A", bound=type[AttrsInstance]) - -class _Nothing(enum.Enum): - NOTHING = enum.auto() - -NOTHING = _Nothing.NOTHING -NothingType: TypeAlias = Literal[_Nothing.NOTHING] - -# NOTE: Factory lies about its return type to make this possible: -# `x: List[int] # = Factory(list)` -# Work around mypy issue #4554 in the common case by using an overload. - -@overload -def Factory(factory: Callable[[], _T]) -> _T: ... -@overload -def Factory( - factory: Callable[[Any], _T], - takes_self: Literal[True], -) -> _T: ... -@overload -def Factory( - factory: Callable[[], _T], - takes_self: Literal[False], -) -> _T: ... - -In = TypeVar("In") -Out = TypeVar("Out") - -class Converter(Generic[In, Out]): - @overload - def __init__(self, converter: Callable[[In], Out]) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance, Attribute], Out], - *, - takes_self: Literal[True], - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, Attribute], Out], - *, - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance], Out], - *, - takes_self: Literal[True], - ) -> None: ... - -class Attribute(Generic[_T]): - name: str - default: _T | None - validator: _ValidatorType[_T] | None - repr: _ReprArgType - cmp: _EqOrderType - eq: _EqOrderType - order: _EqOrderType - hash: bool | None - init: bool - converter: Converter | None - metadata: dict[Any, Any] - type: type[_T] | None - kw_only: bool - on_setattr: _OnSetAttrType - alias: str | None - - def evolve(self, **changes: Any) -> "Attribute[Any]": ... - -# NOTE: We had several choices for the annotation to use for type arg: -# 1) Type[_T] -# - Pros: Handles simple cases correctly -# - Cons: Might produce less informative errors in the case of conflicting -# TypeVars e.g. `attr.ib(default='bad', type=int)` -# 2) Callable[..., _T] -# - Pros: Better error messages than #1 for conflicting TypeVars -# - Cons: Terrible error messages for validator checks. -# e.g. attr.ib(type=int, validator=validate_str) -# -> error: Cannot infer function type argument -# 3) type (and do all of the work in the mypy plugin) -# - Pros: Simple here, and we could customize the plugin with our own errors. -# - Cons: Would need to write mypy plugin code to handle all the cases. -# We chose option #1. - -# `attr` lies about its return type to make the following possible: -# attr() -> Any -# attr(8) -> int -# attr(validator=) -> Whatever the callable expects. -# This makes this type of assignments possible: -# x: int = attr(8) -# -# This form catches explicit None or no default but with no other arguments -# returns Any. -@overload -def attrib( - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def attrib( - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def attrib( - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def attrib( - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: object = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: _C, - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> _C: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: None = ..., - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> Callable[[_C], _C]: ... -def fields(cls: type[AttrsInstance]) -> Any: ... -def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... -def validate(inst: AttrsInstance) -> None: ... -def resolve_types( - cls: _A, - globalns: dict[str, Any] | None = ..., - localns: dict[str, Any] | None = ..., - attribs: list[Attribute[Any]] | None = ..., - include_extras: bool = ..., -) -> _A: ... - -# TODO: add support for returning a proper attrs class from the mypy plugin -# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', -# [attr.ib()])` is valid -def make_class( - name: str, - attrs: list[str] | tuple[str, ...] | dict[str, Any], - bases: tuple[type, ...] = ..., - class_body: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - collect_by_mro: bool = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., -) -> type: ... - -# _funcs -- - -# TODO: add support for returning TypedDict from the mypy plugin -# FIXME: asdict/astuple do not honor their factory args. Waiting on one of -# these: -# https://github.com/python/mypy/issues/4236 -# https://github.com/python/typing/issues/253 -# XXX: remember to fix attrs.asdict/astuple too! -def asdict( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - dict_factory: type[Mapping[Any, Any]] = ..., - retain_collection_types: bool = ..., - value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., - tuple_keys: bool | None = ..., -) -> dict[str, Any]: ... - -# TODO: add support for returning NamedTuple from the mypy plugin -def astuple( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - tuple_factory: type[Sequence[Any]] = ..., - retain_collection_types: bool = ..., -) -> tuple[Any, ...]: ... -def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... -def assoc(inst: _T, **changes: Any) -> _T: ... -def evolve(inst: _T, **changes: Any) -> _T: ... - -# _config -- - -def set_run_validators(run: bool) -> None: ... -def get_run_validators() -> bool: ... - -# aliases -- - -s = attributes = attrs -ib = attr = attrib -dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_cmp.py b/extensions/.local/lib/python3.11/site-packages/attr/_cmp.py deleted file mode 100644 index 09bab49..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_cmp.py +++ /dev/null @@ -1,160 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import functools -import types - -from ._make import __ne__ - - -_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} - - -def cmp_using( - eq=None, - lt=None, - le=None, - gt=None, - ge=None, - require_same_type=True, - class_name="Comparable", -): - """ - Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, - and ``cmp`` arguments to customize field comparison. - - The resulting class will have a full set of ordering methods if at least - one of ``{lt, le, gt, ge}`` and ``eq`` are provided. - - Args: - eq (typing.Callable | None): - Callable used to evaluate equality of two objects. - - lt (typing.Callable | None): - Callable used to evaluate whether one object is less than another - object. - - le (typing.Callable | None): - Callable used to evaluate whether one object is less than or equal - to another object. - - gt (typing.Callable | None): - Callable used to evaluate whether one object is greater than - another object. - - ge (typing.Callable | None): - Callable used to evaluate whether one object is greater than or - equal to another object. - - require_same_type (bool): - When `True`, equality and ordering methods will return - `NotImplemented` if objects are not of the same type. - - class_name (str | None): Name of class. Defaults to "Comparable". - - See `comparison` for more details. - - .. versionadded:: 21.1.0 - """ - - body = { - "__slots__": ["value"], - "__init__": _make_init(), - "_requirements": [], - "_is_comparable_to": _is_comparable_to, - } - - # Add operations. - num_order_functions = 0 - has_eq_function = False - - if eq is not None: - has_eq_function = True - body["__eq__"] = _make_operator("eq", eq) - body["__ne__"] = __ne__ - - if lt is not None: - num_order_functions += 1 - body["__lt__"] = _make_operator("lt", lt) - - if le is not None: - num_order_functions += 1 - body["__le__"] = _make_operator("le", le) - - if gt is not None: - num_order_functions += 1 - body["__gt__"] = _make_operator("gt", gt) - - if ge is not None: - num_order_functions += 1 - body["__ge__"] = _make_operator("ge", ge) - - type_ = types.new_class( - class_name, (object,), {}, lambda ns: ns.update(body) - ) - - # Add same type requirement. - if require_same_type: - type_._requirements.append(_check_same_type) - - # Add total ordering if at least one operation was defined. - if 0 < num_order_functions < 4: - if not has_eq_function: - # functools.total_ordering requires __eq__ to be defined, - # so raise early error here to keep a nice stack. - msg = "eq must be define is order to complete ordering from lt, le, gt, ge." - raise ValueError(msg) - type_ = functools.total_ordering(type_) - - return type_ - - -def _make_init(): - """ - Create __init__ method. - """ - - def __init__(self, value): - """ - Initialize object with *value*. - """ - self.value = value - - return __init__ - - -def _make_operator(name, func): - """ - Create operator method. - """ - - def method(self, other): - if not self._is_comparable_to(other): - return NotImplemented - - result = func(self.value, other.value) - if result is NotImplemented: - return NotImplemented - - return result - - method.__name__ = f"__{name}__" - method.__doc__ = ( - f"Return a {_operation_names[name]} b. Computed by attrs." - ) - - return method - - -def _is_comparable_to(self, other): - """ - Check whether `other` is comparable to `self`. - """ - return all(func(self, other) for func in self._requirements) - - -def _check_same_type(self, other): - """ - Return True if *self* and *other* are of the same type, False otherwise. - """ - return other.value.__class__ is self.value.__class__ diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_cmp.pyi b/extensions/.local/lib/python3.11/site-packages/attr/_cmp.pyi deleted file mode 100644 index cc7893b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_cmp.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any, Callable - -_CompareWithType = Callable[[Any, Any], bool] - -def cmp_using( - eq: _CompareWithType | None = ..., - lt: _CompareWithType | None = ..., - le: _CompareWithType | None = ..., - gt: _CompareWithType | None = ..., - ge: _CompareWithType | None = ..., - require_same_type: bool = ..., - class_name: str = ..., -) -> type: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_compat.py b/extensions/.local/lib/python3.11/site-packages/attr/_compat.py deleted file mode 100644 index 22fcd78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_compat.py +++ /dev/null @@ -1,94 +0,0 @@ -# SPDX-License-Identifier: MIT - -import inspect -import platform -import sys -import threading - -from collections.abc import Mapping, Sequence # noqa: F401 -from typing import _GenericAlias - - -PYPY = platform.python_implementation() == "PyPy" -PY_3_9_PLUS = sys.version_info[:2] >= (3, 9) -PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) -PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) -PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) -PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) -PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) - - -if PY_3_14_PLUS: # pragma: no cover - import annotationlib - - _get_annotations = annotationlib.get_annotations - -else: - - def _get_annotations(cls): - """ - Get annotations for *cls*. - """ - return cls.__dict__.get("__annotations__", {}) - - -class _AnnotationExtractor: - """ - Extract type annotations from a callable, returning None whenever there - is none. - """ - - __slots__ = ["sig"] - - def __init__(self, callable): - try: - self.sig = inspect.signature(callable) - except (ValueError, TypeError): # inspect failed - self.sig = None - - def get_first_param_type(self): - """ - Return the type annotation of the first argument if it's not empty. - """ - if not self.sig: - return None - - params = list(self.sig.parameters.values()) - if params and params[0].annotation is not inspect.Parameter.empty: - return params[0].annotation - - return None - - def get_return_type(self): - """ - Return the return type if it's not empty. - """ - if ( - self.sig - and self.sig.return_annotation is not inspect.Signature.empty - ): - return self.sig.return_annotation - - return None - - -# Thread-local global to track attrs instances which are already being repr'd. -# This is needed because there is no other (thread-safe) way to pass info -# about the instances that are already being repr'd through the call stack -# in order to ensure we don't perform infinite recursion. -# -# For instance, if an instance contains a dict which contains that instance, -# we need to know that we're already repr'ing the outside instance from within -# the dict's repr() call. -# -# This lives here rather than in _make.py so that the functions in _make.py -# don't have a direct reference to the thread-local in their globals dict. -# If they have such a reference, it breaks cloudpickle. -repr_context = threading.local() - - -def get_generic_base(cl): - """If this is a generic class (A[str]), return the generic base for it.""" - if cl.__class__ is _GenericAlias: - return cl.__origin__ - return None diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_config.py b/extensions/.local/lib/python3.11/site-packages/attr/_config.py deleted file mode 100644 index 4b25772..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_config.py +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: MIT - -__all__ = ["get_run_validators", "set_run_validators"] - -_run_validators = True - - -def set_run_validators(run): - """ - Set whether or not validators are run. By default, they are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` - instead. - """ - if not isinstance(run, bool): - msg = "'run' must be bool." - raise TypeError(msg) - global _run_validators - _run_validators = run - - -def get_run_validators(): - """ - Return whether or not validators are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` - instead. - """ - return _run_validators diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_funcs.py b/extensions/.local/lib/python3.11/site-packages/attr/_funcs.py deleted file mode 100644 index c39fb8a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_funcs.py +++ /dev/null @@ -1,468 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import copy - -from ._compat import PY_3_9_PLUS, get_generic_base -from ._make import _OBJ_SETATTR, NOTHING, fields -from .exceptions import AttrsAttributeNotFoundError - - -def asdict( - inst, - recurse=True, - filter=None, - dict_factory=dict, - retain_collection_types=False, - value_serializer=None, -): - """ - Return the *attrs* attribute values of *inst* as a dict. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - dict_factory (~typing.Callable): - A callable to produce dictionaries from. For example, to produce - ordered dictionaries instead of normal Python dictionaries, pass in - ``collections.OrderedDict``. - - retain_collection_types (bool): - Do not convert to `list` when encountering an attribute whose type - is `tuple` or `set`. Only meaningful if *recurse* is `True`. - - value_serializer (typing.Callable | None): - A hook that is called for every attribute or dict key/value. It - receives the current instance, field and value and must return the - (updated) value. The hook is run *after* the optional *filter* has - been applied. - - Returns: - Return type of *dict_factory*. - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.0.0 *dict_factory* - .. versionadded:: 16.1.0 *retain_collection_types* - .. versionadded:: 20.3.0 *value_serializer* - .. versionadded:: 21.3.0 - If a dict has a collection for a key, it is serialized as a tuple. - """ - attrs = fields(inst.__class__) - rv = dict_factory() - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - - if value_serializer is not None: - v = value_serializer(inst, a, v) - - if recurse is True: - if has(v.__class__): - rv[a.name] = asdict( - v, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain_collection_types is True else list - items = [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in v - ] - try: - rv[a.name] = cf(items) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv[a.name] = cf(*items) - elif isinstance(v, dict): - df = dict_factory - rv[a.name] = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in v.items() - ) - else: - rv[a.name] = v - else: - rv[a.name] = v - return rv - - -def _asdict_anything( - val, - is_key, - filter, - dict_factory, - retain_collection_types, - value_serializer, -): - """ - ``asdict`` only works on attrs instances, this works on anything. - """ - if getattr(val.__class__, "__attrs_attrs__", None) is not None: - # Attrs class. - rv = asdict( - val, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif isinstance(val, (tuple, list, set, frozenset)): - if retain_collection_types is True: - cf = val.__class__ - elif is_key: - cf = tuple - else: - cf = list - - rv = cf( - [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in val - ] - ) - elif isinstance(val, dict): - df = dict_factory - rv = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in val.items() - ) - else: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - - return rv - - -def astuple( - inst, - recurse=True, - filter=None, - tuple_factory=tuple, - retain_collection_types=False, -): - """ - Return the *attrs* attribute values of *inst* as a tuple. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): - Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - tuple_factory (~typing.Callable): - A callable to produce tuples from. For example, to produce lists - instead of tuples. - - retain_collection_types (bool): - Do not convert to `list` or `dict` when encountering an attribute - which type is `tuple`, `dict` or `set`. Only meaningful if - *recurse* is `True`. - - Returns: - Return type of *tuple_factory* - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.2.0 - """ - attrs = fields(inst.__class__) - rv = [] - retain = retain_collection_types # Very long. :/ - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - if recurse is True: - if has(v.__class__): - rv.append( - astuple( - v, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - ) - elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain is True else list - items = [ - ( - astuple( - j, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(j.__class__) - else j - ) - for j in v - ] - try: - rv.append(cf(items)) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv.append(cf(*items)) - elif isinstance(v, dict): - df = v.__class__ if retain is True else dict - rv.append( - df( - ( - ( - astuple( - kk, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(kk.__class__) - else kk - ), - ( - astuple( - vv, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(vv.__class__) - else vv - ), - ) - for kk, vv in v.items() - ) - ) - else: - rv.append(v) - else: - rv.append(v) - - return rv if tuple_factory is list else tuple_factory(rv) - - -def has(cls): - """ - Check whether *cls* is a class with *attrs* attributes. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - Returns: - bool: - """ - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is not None: - return True - - # No attrs, maybe it's a specialized generic (A[str])? - generic_base = get_generic_base(cls) - if generic_base is not None: - generic_attrs = getattr(generic_base, "__attrs_attrs__", None) - if generic_attrs is not None: - # Stick it on here for speed next time. - cls.__attrs_attrs__ = generic_attrs - return generic_attrs is not None - return False - - -def assoc(inst, **changes): - """ - Copy *inst* and apply *changes*. - - This is different from `evolve` that applies the changes to the arguments - that create the new instance. - - `evolve`'s behavior is preferable, but there are `edge cases`_ where it - doesn't work. Therefore `assoc` is deprecated, but will not be removed. - - .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 - - Args: - inst: Instance of a class with *attrs* attributes. - - changes: Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - attrs.exceptions.AttrsAttributeNotFoundError: - If *attr_name* couldn't be found on *cls*. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. deprecated:: 17.1.0 - Use `attrs.evolve` instead if you can. This function will not be - removed du to the slightly different approach compared to - `attrs.evolve`, though. - """ - new = copy.copy(inst) - attrs = fields(inst.__class__) - for k, v in changes.items(): - a = getattr(attrs, k, NOTHING) - if a is NOTHING: - msg = f"{k} is not an attrs attribute on {new.__class__}." - raise AttrsAttributeNotFoundError(msg) - _OBJ_SETATTR(new, k, v) - return new - - -def resolve_types( - cls, globalns=None, localns=None, attribs=None, include_extras=True -): - """ - Resolve any strings and forward annotations in type annotations. - - This is only required if you need concrete types in :class:`Attribute`'s - *type* field. In other words, you don't need to resolve your types if you - only use them for static type checking. - - With no arguments, names will be looked up in the module in which the class - was created. If this is not what you want, for example, if the name only - exists inside a method, you may pass *globalns* or *localns* to specify - other dictionaries in which to look up these names. See the docs of - `typing.get_type_hints` for more details. - - Args: - cls (type): Class to resolve. - - globalns (dict | None): Dictionary containing global variables. - - localns (dict | None): Dictionary containing local variables. - - attribs (list | None): - List of attribs for the given class. This is necessary when calling - from inside a ``field_transformer`` since *cls* is not an *attrs* - class yet. - - include_extras (bool): - Resolve more accurately, if possible. Pass ``include_extras`` to - ``typing.get_hints``, if supported by the typing module. On - supported Python versions (3.9+), this resolves the types more - accurately. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class and you didn't pass any attribs. - - NameError: If types cannot be resolved because of missing variables. - - Returns: - *cls* so you can use this function also as a class decorator. Please - note that you have to apply it **after** `attrs.define`. That means the - decorator has to come in the line **before** `attrs.define`. - - .. versionadded:: 20.1.0 - .. versionadded:: 21.1.0 *attribs* - .. versionadded:: 23.1.0 *include_extras* - """ - # Since calling get_type_hints is expensive we cache whether we've - # done it already. - if getattr(cls, "__attrs_types_resolved__", None) != cls: - import typing - - kwargs = {"globalns": globalns, "localns": localns} - - if PY_3_9_PLUS: - kwargs["include_extras"] = include_extras - - hints = typing.get_type_hints(cls, **kwargs) - for field in fields(cls) if attribs is None else attribs: - if field.name in hints: - # Since fields have been frozen we must work around it. - _OBJ_SETATTR(field, "type", hints[field.name]) - # We store the class we resolved so that subclasses know they haven't - # been resolved. - cls.__attrs_types_resolved__ = cls - - # Return the class so you can use it as a decorator too. - return cls diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_make.py b/extensions/.local/lib/python3.11/site-packages/attr/_make.py deleted file mode 100644 index e84d979..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_make.py +++ /dev/null @@ -1,3123 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import abc -import contextlib -import copy -import enum -import inspect -import itertools -import linecache -import sys -import types -import unicodedata - -from collections.abc import Callable, Mapping -from functools import cached_property -from typing import Any, NamedTuple, TypeVar - -# We need to import _compat itself in addition to the _compat members to avoid -# having the thread-local in the globals here. -from . import _compat, _config, setters -from ._compat import ( - PY_3_10_PLUS, - PY_3_11_PLUS, - PY_3_13_PLUS, - _AnnotationExtractor, - _get_annotations, - get_generic_base, -) -from .exceptions import ( - DefaultAlreadySetError, - FrozenInstanceError, - NotAnAttrsClassError, - UnannotatedAttributeError, -) - - -# This is used at least twice, so cache it here. -_OBJ_SETATTR = object.__setattr__ -_INIT_FACTORY_PAT = "__attr_factory_%s" -_CLASSVAR_PREFIXES = ( - "typing.ClassVar", - "t.ClassVar", - "ClassVar", - "typing_extensions.ClassVar", -) -# we don't use a double-underscore prefix because that triggers -# name mangling when trying to create a slot for the field -# (when slots=True) -_HASH_CACHE_FIELD = "_attrs_cached_hash" - -_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) - -# Unique object for unequivocal getattr() defaults. -_SENTINEL = object() - -_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) - - -class _Nothing(enum.Enum): - """ - Sentinel to indicate the lack of a value when `None` is ambiguous. - - If extending attrs, you can use ``typing.Literal[NOTHING]`` to show - that a value may be ``NOTHING``. - - .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. - .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. - """ - - NOTHING = enum.auto() - - def __repr__(self): - return "NOTHING" - - def __bool__(self): - return False - - -NOTHING = _Nothing.NOTHING -""" -Sentinel to indicate the lack of a value when `None` is ambiguous. - -When using in 3rd party code, use `attrs.NothingType` for type annotations. -""" - - -class _CacheHashWrapper(int): - """ - An integer subclass that pickles / copies as None - - This is used for non-slots classes with ``cache_hash=True``, to avoid - serializing a potentially (even likely) invalid hash value. Since `None` - is the default value for uncalculated hashes, whenever this is copied, - the copy's value for the hash should automatically reset. - - See GH #613 for more details. - """ - - def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 - return _none_constructor, _args - - -def attrib( - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=False, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new field / attribute on a class. - - Identical to `attrs.field`, except it's not keyword-only. - - Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, - though). - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attr.s` (or similar)! - - - .. versionadded:: 15.2.0 *convert* - .. versionadded:: 16.3.0 *metadata* - .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. - .. versionchanged:: 17.1.0 - *hash* is `None` and therefore mirrors *eq* by default. - .. versionadded:: 17.3.0 *type* - .. deprecated:: 17.4.0 *convert* - .. versionadded:: 17.4.0 - *converter* as a replacement for the deprecated *convert* to achieve - consistency with other noun-based arguments. - .. versionadded:: 18.1.0 - ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. - .. versionadded:: 18.2.0 *kw_only* - .. versionchanged:: 19.2.0 *convert* keyword argument removed. - .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 22.2.0 *alias* - """ - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq, order, True - ) - - if hash is not None and hash is not True and hash is not False: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if factory is not None: - if default is not NOTHING: - msg = ( - "The `default` and `factory` arguments are mutually exclusive." - ) - raise ValueError(msg) - if not callable(factory): - msg = "The `factory` argument must be a callable." - raise ValueError(msg) - default = Factory(factory) - - if metadata is None: - metadata = {} - - # Apply syntactic sugar by auto-wrapping. - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - if validator and isinstance(validator, (list, tuple)): - validator = and_(*validator) - - if converter and isinstance(converter, (list, tuple)): - converter = pipe(*converter) - - return _CountingAttr( - default=default, - validator=validator, - repr=repr, - cmp=None, - hash=hash, - init=init, - converter=converter, - metadata=metadata, - type=type, - kw_only=kw_only, - eq=eq, - eq_key=eq_key, - order=order, - order_key=order_key, - on_setattr=on_setattr, - alias=alias, - ) - - -def _compile_and_eval( - script: str, - globs: dict[str, Any] | None, - locs: Mapping[str, object] | None = None, - filename: str = "", -) -> None: - """ - Evaluate the script with the given global (globs) and local (locs) - variables. - """ - bytecode = compile(script, filename, "exec") - eval(bytecode, globs, locs) - - -def _linecache_and_compile( - script: str, - filename: str, - globs: dict[str, Any] | None, - locals: Mapping[str, object] | None = None, -) -> dict[str, Any]: - """ - Cache the script with _linecache_, compile it and return the _locals_. - """ - - locs = {} if locals is None else locals - - # In order of debuggers like PDB being able to step through the code, - # we add a fake linecache entry. - count = 1 - base_filename = filename - while True: - linecache_tuple = ( - len(script), - None, - script.splitlines(True), - filename, - ) - old_val = linecache.cache.setdefault(filename, linecache_tuple) - if old_val == linecache_tuple: - break - - filename = f"{base_filename[:-1]}-{count}>" - count += 1 - - _compile_and_eval(script, globs, locs, filename) - - return locs - - -def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: - """ - Create a tuple subclass to hold `Attribute`s for an `attrs` class. - - The subclass is a bare tuple with properties for names. - - class MyClassAttributes(tuple): - __slots__ = () - x = property(itemgetter(0)) - """ - attr_class_name = f"{cls_name}Attributes" - body = {} - for i, attr_name in enumerate(attr_names): - - def getter(self, i=i): - return self[i] - - body[attr_name] = property(getter) - return type(attr_class_name, (tuple,), body) - - -# Tuple class for extracted attributes from a class definition. -# `base_attrs` is a subset of `attrs`. -class _Attributes(NamedTuple): - attrs: type - base_attrs: list[Attribute] - base_attrs_map: dict[str, type] - - -def _is_class_var(annot): - """ - Check whether *annot* is a typing.ClassVar. - - The string comparison hack is used to avoid evaluating all string - annotations which would put attrs-based classes at a performance - disadvantage compared to plain old classes. - """ - annot = str(annot) - - # Annotation can be quoted. - if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): - annot = annot[1:-1] - - return annot.startswith(_CLASSVAR_PREFIXES) - - -def _has_own_attribute(cls, attrib_name): - """ - Check whether *cls* defines *attrib_name* (and doesn't just inherit it). - """ - return attrib_name in cls.__dict__ - - -def _collect_base_attrs( - cls, taken_attr_names -) -> tuple[list[Attribute], dict[str, type]]: - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in reversed(cls.__mro__[1:-1]): - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.inherited or a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - # For each name, only keep the freshest definition i.e. the furthest at the - # back. base_attr_map is fine because it gets overwritten with every new - # instance. - filtered = [] - seen = set() - for a in reversed(base_attrs): - if a.name in seen: - continue - filtered.insert(0, a) - seen.add(a.name) - - return filtered, base_attr_map - - -def _collect_base_attrs_broken(cls, taken_attr_names): - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - - N.B. *taken_attr_names* will be mutated. - - Adhere to the old incorrect behavior. - - Notably it collects from the front and considers inherited attributes which - leads to the buggy behavior reported in #428. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in cls.__mro__[1:-1]: - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - taken_attr_names.add(a.name) - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - return base_attrs, base_attr_map - - -def _transform_attrs( - cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer -) -> _Attributes: - """ - Transform all `_CountingAttr`s on a class into `Attribute`s. - - If *these* is passed, use that and don't look for them on the class. - - If *collect_by_mro* is True, collect them in the correct MRO order, - otherwise use the old -- incorrect -- order. See #428. - - Return an `_Attributes`. - """ - cd = cls.__dict__ - anns = _get_annotations(cls) - - if these is not None: - ca_list = list(these.items()) - elif auto_attribs is True: - ca_names = { - name - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - } - ca_list = [] - annot_names = set() - for attr_name, type in anns.items(): - if _is_class_var(type): - continue - annot_names.add(attr_name) - a = cd.get(attr_name, NOTHING) - - if a.__class__ is not _CountingAttr: - a = attrib(a) - ca_list.append((attr_name, a)) - - unannotated = ca_names - annot_names - if unannotated: - raise UnannotatedAttributeError( - "The following `attr.ib`s lack a type annotation: " - + ", ".join( - sorted(unannotated, key=lambda n: cd.get(n).counter) - ) - + "." - ) - else: - ca_list = sorted( - ( - (name, attr) - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - ), - key=lambda e: e[1].counter, - ) - - fca = Attribute.from_counting_attr - own_attrs = [ - fca(attr_name, ca, anns.get(attr_name)) for attr_name, ca in ca_list - ] - - if collect_by_mro: - base_attrs, base_attr_map = _collect_base_attrs( - cls, {a.name for a in own_attrs} - ) - else: - base_attrs, base_attr_map = _collect_base_attrs_broken( - cls, {a.name for a in own_attrs} - ) - - if kw_only: - own_attrs = [a.evolve(kw_only=True) for a in own_attrs] - base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - - attrs = base_attrs + own_attrs - - if field_transformer is not None: - attrs = tuple(field_transformer(cls, attrs)) - - # Check attr order after executing the field_transformer. - # Mandatory vs non-mandatory attr order only matters when they are part of - # the __init__ signature and when they aren't kw_only (which are moved to - # the end and can be mandatory or non-mandatory in any order, as they will - # be specified as keyword args anyway). Check the order of those attrs: - had_default = False - for a in (a for a in attrs if a.init is not False and a.kw_only is False): - if had_default is True and a.default is NOTHING: - msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" - raise ValueError(msg) - - if had_default is False and a.default is not NOTHING: - had_default = True - - # Resolve default field alias after executing field_transformer. - # This allows field_transformer to differentiate between explicit vs - # default aliases and supply their own defaults. - for a in attrs: - if not a.alias: - # Evolve is very slow, so we hold our nose and do it dirty. - _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) - - # Create AttrsClass *after* applying the field_transformer since it may - # add or remove attributes! - attr_names = [a.name for a in attrs] - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - - return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) - - -def _make_cached_property_getattr(cached_properties, original_getattr, cls): - lines = [ - # Wrapped to get `__class__` into closure cell for super() - # (It will be replaced with the newly constructed class after construction). - "def wrapper(_cls):", - " __class__ = _cls", - " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", - " func = cached_properties.get(item)", - " if func is not None:", - " result = func(self)", - " _setter = _cached_setattr_get(self)", - " _setter(item, result)", - " return result", - ] - if original_getattr is not None: - lines.append( - " return original_getattr(self, item)", - ) - else: - lines.extend( - [ - " try:", - " return super().__getattribute__(item)", - " except AttributeError:", - " if not hasattr(super(), '__getattr__'):", - " raise", - " return super().__getattr__(item)", - " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", - " raise AttributeError(original_error)", - ] - ) - - lines.extend( - [ - " return __getattr__", - "__getattr__ = wrapper(_cls)", - ] - ) - - unique_filename = _generate_unique_filename(cls, "getattr") - - glob = { - "cached_properties": cached_properties, - "_cached_setattr_get": _OBJ_SETATTR.__get__, - "original_getattr": original_getattr, - } - - return _linecache_and_compile( - "\n".join(lines), unique_filename, glob, locals={"_cls": cls} - )["__getattr__"] - - -def _frozen_setattrs(self, name, value): - """ - Attached to frozen classes as __setattr__. - """ - if isinstance(self, BaseException) and name in ( - "__cause__", - "__context__", - "__traceback__", - "__suppress_context__", - "__notes__", - ): - BaseException.__setattr__(self, name, value) - return - - raise FrozenInstanceError - - -def _frozen_delattrs(self, name): - """ - Attached to frozen classes as __delattr__. - """ - if isinstance(self, BaseException) and name in ("__notes__",): - BaseException.__delattr__(self, name) - return - - raise FrozenInstanceError - - -def evolve(*args, **changes): - """ - Create a new instance, based on the first positional argument with - *changes* applied. - - .. tip:: - - On Python 3.13 and later, you can also use `copy.replace` instead. - - Args: - - inst: - Instance of a class with *attrs* attributes. *inst* must be passed - as a positional argument. - - changes: - Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - TypeError: - If *attr_name* couldn't be found in the class ``__init__``. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 17.1.0 - .. deprecated:: 23.1.0 - It is now deprecated to pass the instance using the keyword argument - *inst*. It will raise a warning until at least April 2024, after which - it will become an error. Always pass the instance as a positional - argument. - .. versionchanged:: 24.1.0 - *inst* can't be passed as a keyword argument anymore. - """ - try: - (inst,) = args - except ValueError: - msg = ( - f"evolve() takes 1 positional argument, but {len(args)} were given" - ) - raise TypeError(msg) from None - - cls = inst.__class__ - attrs = fields(cls) - for a in attrs: - if not a.init: - continue - attr_name = a.name # To deal with private attributes. - init_name = a.alias - if init_name not in changes: - changes[init_name] = getattr(inst, attr_name) - - return cls(**changes) - - -class _ClassBuilder: - """ - Iteratively build *one* class. - """ - - __slots__ = ( - "_add_method_dunders", - "_attr_names", - "_attrs", - "_base_attr_map", - "_base_names", - "_cache_hash", - "_cls", - "_cls_dict", - "_delete_attribs", - "_frozen", - "_has_custom_setattr", - "_has_post_init", - "_has_pre_init", - "_is_exc", - "_on_setattr", - "_pre_init_has_args", - "_repr_added", - "_script_snippets", - "_slots", - "_weakref_slot", - "_wrote_own_setattr", - ) - - def __init__( - self, - cls: type, - these, - slots, - frozen, - weakref_slot, - getstate_setstate, - auto_attribs, - kw_only, - cache_hash, - is_exc, - collect_by_mro, - on_setattr, - has_custom_setattr, - field_transformer, - ): - attrs, base_attrs, base_map = _transform_attrs( - cls, - these, - auto_attribs, - kw_only, - collect_by_mro, - field_transformer, - ) - - self._cls = cls - self._cls_dict = dict(cls.__dict__) if slots else {} - self._attrs = attrs - self._base_names = {a.name for a in base_attrs} - self._base_attr_map = base_map - self._attr_names = tuple(a.name for a in attrs) - self._slots = slots - self._frozen = frozen - self._weakref_slot = weakref_slot - self._cache_hash = cache_hash - self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) - self._pre_init_has_args = False - if self._has_pre_init: - # Check if the pre init method has more arguments than just `self` - # We want to pass arguments if pre init expects arguments - pre_init_func = cls.__attrs_pre_init__ - pre_init_signature = inspect.signature(pre_init_func) - self._pre_init_has_args = len(pre_init_signature.parameters) > 1 - self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) - self._delete_attribs = not bool(these) - self._is_exc = is_exc - self._on_setattr = on_setattr - - self._has_custom_setattr = has_custom_setattr - self._wrote_own_setattr = False - - self._cls_dict["__attrs_attrs__"] = self._attrs - - if frozen: - self._cls_dict["__setattr__"] = _frozen_setattrs - self._cls_dict["__delattr__"] = _frozen_delattrs - - self._wrote_own_setattr = True - elif on_setattr in ( - _DEFAULT_ON_SETATTR, - setters.validate, - setters.convert, - ): - has_validator = has_converter = False - for a in attrs: - if a.validator is not None: - has_validator = True - if a.converter is not None: - has_converter = True - - if has_validator and has_converter: - break - if ( - ( - on_setattr == _DEFAULT_ON_SETATTR - and not (has_validator or has_converter) - ) - or (on_setattr == setters.validate and not has_validator) - or (on_setattr == setters.convert and not has_converter) - ): - # If class-level on_setattr is set to convert + validate, but - # there's no field to convert or validate, pretend like there's - # no on_setattr. - self._on_setattr = None - - if getstate_setstate: - ( - self._cls_dict["__getstate__"], - self._cls_dict["__setstate__"], - ) = self._make_getstate_setstate() - - # tuples of script, globs, hook - self._script_snippets: list[ - tuple[str, dict, Callable[[dict, dict], Any]] - ] = [] - self._repr_added = False - - # We want to only do this check once; in 99.9% of cases these - # exist. - if not hasattr(self._cls, "__module__") or not hasattr( - self._cls, "__qualname__" - ): - self._add_method_dunders = self._add_method_dunders_safe - else: - self._add_method_dunders = self._add_method_dunders_unsafe - - def __repr__(self): - return f"<_ClassBuilder(cls={self._cls.__name__})>" - - def _eval_snippets(self) -> None: - """ - Evaluate any registered snippets in one go. - """ - script = "\n".join([snippet[0] for snippet in self._script_snippets]) - globs = {} - for _, snippet_globs, _ in self._script_snippets: - globs.update(snippet_globs) - - locs = _linecache_and_compile( - script, - _generate_unique_filename(self._cls, "methods"), - globs, - ) - - for _, _, hook in self._script_snippets: - hook(self._cls_dict, locs) - - def build_class(self): - """ - Finalize class based on the accumulated configuration. - - Builder cannot be used after calling this method. - """ - self._eval_snippets() - if self._slots is True: - cls = self._create_slots_class() - else: - cls = self._patch_original_class() - if PY_3_10_PLUS: - cls = abc.update_abstractmethods(cls) - - # The method gets only called if it's not inherited from a base class. - # _has_own_attribute does NOT work properly for classmethods. - if ( - getattr(cls, "__attrs_init_subclass__", None) - and "__attrs_init_subclass__" not in cls.__dict__ - ): - cls.__attrs_init_subclass__() - - return cls - - def _patch_original_class(self): - """ - Apply accumulated methods and return the class. - """ - cls = self._cls - base_names = self._base_names - - # Clean class of attribute definitions (`attr.ib()`s). - if self._delete_attribs: - for name in self._attr_names: - if ( - name not in base_names - and getattr(cls, name, _SENTINEL) is not _SENTINEL - ): - # An AttributeError can happen if a base class defines a - # class variable and we want to set an attribute with the - # same name by using only a type annotation. - with contextlib.suppress(AttributeError): - delattr(cls, name) - - # Attach our dunder methods. - for name, value in self._cls_dict.items(): - setattr(cls, name, value) - - # If we've inherited an attrs __setattr__ and don't write our own, - # reset it to object's. - if not self._wrote_own_setattr and getattr( - cls, "__attrs_own_setattr__", False - ): - cls.__attrs_own_setattr__ = False - - if not self._has_custom_setattr: - cls.__setattr__ = _OBJ_SETATTR - - return cls - - def _create_slots_class(self): - """ - Build and return a new class with a `__slots__` attribute. - """ - cd = { - k: v - for k, v in self._cls_dict.items() - if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") - } - - # If our class doesn't have its own implementation of __setattr__ - # (either from the user or by us), check the bases, if one of them has - # an attrs-made __setattr__, that needs to be reset. We don't walk the - # MRO because we only care about our immediate base classes. - # XXX: This can be confused by subclassing a slotted attrs class with - # XXX: a non-attrs class and subclass the resulting class with an attrs - # XXX: class. See `test_slotted_confused` for details. For now that's - # XXX: OK with us. - if not self._wrote_own_setattr: - cd["__attrs_own_setattr__"] = False - - if not self._has_custom_setattr: - for base_cls in self._cls.__bases__: - if base_cls.__dict__.get("__attrs_own_setattr__", False): - cd["__setattr__"] = _OBJ_SETATTR - break - - # Traverse the MRO to collect existing slots - # and check for an existing __weakref__. - existing_slots = {} - weakref_inherited = False - for base_cls in self._cls.__mro__[1:-1]: - if base_cls.__dict__.get("__weakref__", None) is not None: - weakref_inherited = True - existing_slots.update( - { - name: getattr(base_cls, name) - for name in getattr(base_cls, "__slots__", []) - } - ) - - base_names = set(self._base_names) - - names = self._attr_names - if ( - self._weakref_slot - and "__weakref__" not in getattr(self._cls, "__slots__", ()) - and "__weakref__" not in names - and not weakref_inherited - ): - names += ("__weakref__",) - - cached_properties = { - name: cached_prop.func - for name, cached_prop in cd.items() - if isinstance(cached_prop, cached_property) - } - - # Collect methods with a `__class__` reference that are shadowed in the new class. - # To know to update them. - additional_closure_functions_to_update = [] - if cached_properties: - class_annotations = _get_annotations(self._cls) - for name, func in cached_properties.items(): - # Add cached properties to names for slotting. - names += (name,) - # Clear out function from class to avoid clashing. - del cd[name] - additional_closure_functions_to_update.append(func) - annotation = inspect.signature(func).return_annotation - if annotation is not inspect.Parameter.empty: - class_annotations[name] = annotation - - original_getattr = cd.get("__getattr__") - if original_getattr is not None: - additional_closure_functions_to_update.append(original_getattr) - - cd["__getattr__"] = _make_cached_property_getattr( - cached_properties, original_getattr, self._cls - ) - - # We only add the names of attributes that aren't inherited. - # Setting __slots__ to inherited attributes wastes memory. - slot_names = [name for name in names if name not in base_names] - - # There are slots for attributes from current class - # that are defined in parent classes. - # As their descriptors may be overridden by a child class, - # we collect them here and update the class dict - reused_slots = { - slot: slot_descriptor - for slot, slot_descriptor in existing_slots.items() - if slot in slot_names - } - slot_names = [name for name in slot_names if name not in reused_slots] - cd.update(reused_slots) - if self._cache_hash: - slot_names.append(_HASH_CACHE_FIELD) - - cd["__slots__"] = tuple(slot_names) - - cd["__qualname__"] = self._cls.__qualname__ - - # Create new class based on old class and our methods. - cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) - - # The following is a fix for - # . - # If a method mentions `__class__` or uses the no-arg super(), the - # compiler will bake a reference to the class in the method itself - # as `method.__closure__`. Since we replace the class with a - # clone, we rewrite these references so it keeps working. - for item in itertools.chain( - cls.__dict__.values(), additional_closure_functions_to_update - ): - if isinstance(item, (classmethod, staticmethod)): - # Class- and staticmethods hide their functions inside. - # These might need to be rewritten as well. - closure_cells = getattr(item.__func__, "__closure__", None) - elif isinstance(item, property): - # Workaround for property `super()` shortcut (PY3-only). - # There is no universal way for other descriptors. - closure_cells = getattr(item.fget, "__closure__", None) - else: - closure_cells = getattr(item, "__closure__", None) - - if not closure_cells: # Catch None or the empty list. - continue - for cell in closure_cells: - try: - match = cell.cell_contents is self._cls - except ValueError: # noqa: PERF203 - # ValueError: Cell is empty - pass - else: - if match: - cell.cell_contents = cls - return cls - - def add_repr(self, ns): - script, globs = _make_repr_script(self._attrs, ns) - - def _attach_repr(cls_dict, globs): - cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) - - self._script_snippets.append((script, globs, _attach_repr)) - self._repr_added = True - return self - - def add_str(self): - if not self._repr_added: - msg = "__str__ can only be generated if a __repr__ exists." - raise ValueError(msg) - - def __str__(self): - return self.__repr__() - - self._cls_dict["__str__"] = self._add_method_dunders(__str__) - return self - - def _make_getstate_setstate(self): - """ - Create custom __setstate__ and __getstate__ methods. - """ - # __weakref__ is not writable. - state_attr_names = tuple( - an for an in self._attr_names if an != "__weakref__" - ) - - def slots_getstate(self): - """ - Automatically created by attrs. - """ - return {name: getattr(self, name) for name in state_attr_names} - - hash_caching_enabled = self._cache_hash - - def slots_setstate(self, state): - """ - Automatically created by attrs. - """ - __bound_setattr = _OBJ_SETATTR.__get__(self) - if isinstance(state, tuple): - # Backward compatibility with attrs instances pickled with - # attrs versions before v22.2.0 which stored tuples. - for name, value in zip(state_attr_names, state): - __bound_setattr(name, value) - else: - for name in state_attr_names: - if name in state: - __bound_setattr(name, state[name]) - - # The hash code cache is not included when the object is - # serialized, but it still needs to be initialized to None to - # indicate that the first call to __hash__ should be a cache - # miss. - if hash_caching_enabled: - __bound_setattr(_HASH_CACHE_FIELD, None) - - return slots_getstate, slots_setstate - - def make_unhashable(self): - self._cls_dict["__hash__"] = None - return self - - def add_hash(self): - script, globs = _make_hash_script( - self._cls, - self._attrs, - frozen=self._frozen, - cache_hash=self._cache_hash, - ) - - def attach_hash(cls_dict: dict, locs: dict) -> None: - cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) - - self._script_snippets.append((script, globs, attach_hash)) - - return self - - def add_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=False, - ) - - def _attach_init(cls_dict, globs): - init = globs["__init__"] - init.__annotations__ = annotations - cls_dict["__init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_init)) - - return self - - def add_replace(self): - self._cls_dict["__replace__"] = self._add_method_dunders( - lambda self, **changes: evolve(self, **changes) - ) - return self - - def add_match_args(self): - self._cls_dict["__match_args__"] = tuple( - field.name - for field in self._attrs - if field.init and not field.kw_only - ) - - def add_attrs_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=True, - ) - - def _attach_attrs_init(cls_dict, globs): - init = globs["__attrs_init__"] - init.__annotations__ = annotations - cls_dict["__attrs_init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_attrs_init)) - - return self - - def add_eq(self): - cd = self._cls_dict - - script, globs = _make_eq_script(self._attrs) - - def _attach_eq(cls_dict, globs): - cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) - - self._script_snippets.append((script, globs, _attach_eq)) - - cd["__ne__"] = __ne__ - - return self - - def add_order(self): - cd = self._cls_dict - - cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( - self._add_method_dunders(meth) - for meth in _make_order(self._cls, self._attrs) - ) - - return self - - def add_setattr(self): - sa_attrs = {} - for a in self._attrs: - on_setattr = a.on_setattr or self._on_setattr - if on_setattr and on_setattr is not setters.NO_OP: - sa_attrs[a.name] = a, on_setattr - - if not sa_attrs: - return self - - if self._has_custom_setattr: - # We need to write a __setattr__ but there already is one! - msg = "Can't combine custom __setattr__ with on_setattr hooks." - raise ValueError(msg) - - # docstring comes from _add_method_dunders - def __setattr__(self, name, val): - try: - a, hook = sa_attrs[name] - except KeyError: - nval = val - else: - nval = hook(self, a, val) - - _OBJ_SETATTR(self, name, nval) - - self._cls_dict["__attrs_own_setattr__"] = True - self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) - self._wrote_own_setattr = True - - return self - - def _add_method_dunders_unsafe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method*. - """ - method.__module__ = self._cls.__module__ - - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - method.__doc__ = ( - f"Method generated by attrs for class {self._cls.__qualname__}." - ) - - return method - - def _add_method_dunders_safe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method* if possible. - """ - with contextlib.suppress(AttributeError): - method.__module__ = self._cls.__module__ - - with contextlib.suppress(AttributeError): - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - with contextlib.suppress(AttributeError): - method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." - - return method - - -def _determine_attrs_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - return cmp, cmp - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq = default_eq - - if order is None: - order = eq - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, order - - -def _determine_attrib_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - def decide_callable_or_boolean(value): - """ - Decide whether a key function is used. - """ - if callable(value): - value, key = True, value - else: - key = None - return value, key - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - cmp, cmp_key = decide_callable_or_boolean(cmp) - return cmp, cmp_key, cmp, cmp_key - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq, eq_key = default_eq, None - else: - eq, eq_key = decide_callable_or_boolean(eq) - - if order is None: - order, order_key = eq, eq_key - else: - order, order_key = decide_callable_or_boolean(order) - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, eq_key, order, order_key - - -def _determine_whether_to_implement( - cls, flag, auto_detect, dunders, default=True -): - """ - Check whether we should implement a set of methods for *cls*. - - *flag* is the argument passed into @attr.s like 'init', *auto_detect* the - same as passed into @attr.s and *dunders* is a tuple of attribute names - whose presence signal that the user has implemented it themselves. - - Return *default* if no reason for either for or against is found. - """ - if flag is True or flag is False: - return flag - - if flag is None and auto_detect is False: - return default - - # Logically, flag is None and auto_detect is True here. - for dunder in dunders: - if _has_own_attribute(cls, dunder): - return False - - return default - - -def attrs( - maybe_cls=None, - these=None, - repr_ns=None, - repr=None, - cmp=None, - hash=None, - init=None, - slots=False, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=False, - kw_only=False, - cache_hash=False, - auto_exc=False, - eq=None, - order=None, - auto_detect=False, - collect_by_mro=False, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - unsafe_hash=None, -): - r""" - A class decorator that adds :term:`dunder methods` according to the - specified attributes using `attr.ib` or the *these* argument. - - Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will - *never* go away, though). - - Args: - repr_ns (str): - When using nested classes, there was no way in Python 2 to - automatically detect that. This argument allows to set a custom - name for a more meaningful ``repr`` output. This argument is - pointless in Python 3 and is therefore deprecated. - - .. caution:: - Refer to `attrs.define` for the rest of the parameters, but note that they - can have different defaults. - - Notably, leaving *on_setattr* as `None` will **not** add any hooks. - - .. versionadded:: 16.0.0 *slots* - .. versionadded:: 16.1.0 *frozen* - .. versionadded:: 16.3.0 *str* - .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. - .. versionchanged:: 17.1.0 - *hash* supports `None` as value which is also the default now. - .. versionadded:: 17.3.0 *auto_attribs* - .. versionchanged:: 18.1.0 - If *these* is passed, no attributes are deleted from the class body. - .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. - .. versionadded:: 18.2.0 *weakref_slot* - .. deprecated:: 18.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a - `DeprecationWarning` if the classes compared are subclasses of - each other. ``__eq`` and ``__ne__`` never tried to compared subclasses - to each other. - .. versionchanged:: 19.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider - subclasses comparable anymore. - .. versionadded:: 18.2.0 *kw_only* - .. versionadded:: 18.2.0 *cache_hash* - .. versionadded:: 19.1.0 *auto_exc* - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *auto_detect* - .. versionadded:: 20.1.0 *collect_by_mro* - .. versionadded:: 20.1.0 *getstate_setstate* - .. versionadded:: 20.1.0 *on_setattr* - .. versionadded:: 20.3.0 *field_transformer* - .. versionchanged:: 21.1.0 - ``init=False`` injects ``__attrs_init__`` - .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 21.3.0 *match_args* - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. deprecated:: 24.1.0 *repr_ns* - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - """ - if repr_ns is not None: - import warnings - - warnings.warn( - DeprecationWarning( - "The `repr_ns` argument is deprecated and will be removed in or after August 2025." - ), - stacklevel=2, - ) - - eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) - - # unsafe_hash takes precedence due to PEP 681. - if unsafe_hash is not None: - hash = unsafe_hash - - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - def wrap(cls): - is_frozen = frozen or _has_frozen_base_class(cls) - is_exc = auto_exc is True and issubclass(cls, BaseException) - has_own_setattr = auto_detect and _has_own_attribute( - cls, "__setattr__" - ) - - if has_own_setattr and is_frozen: - msg = "Can't freeze a class with a custom __setattr__." - raise ValueError(msg) - - builder = _ClassBuilder( - cls, - these, - slots, - is_frozen, - weakref_slot, - _determine_whether_to_implement( - cls, - getstate_setstate, - auto_detect, - ("__getstate__", "__setstate__"), - default=slots, - ), - auto_attribs, - kw_only, - cache_hash, - is_exc, - collect_by_mro, - on_setattr, - has_own_setattr, - field_transformer, - ) - - if _determine_whether_to_implement( - cls, repr, auto_detect, ("__repr__",) - ): - builder.add_repr(repr_ns) - - if str is True: - builder.add_str() - - eq = _determine_whether_to_implement( - cls, eq_, auto_detect, ("__eq__", "__ne__") - ) - if not is_exc and eq is True: - builder.add_eq() - if not is_exc and _determine_whether_to_implement( - cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") - ): - builder.add_order() - - if not frozen: - builder.add_setattr() - - nonlocal hash - if ( - hash is None - and auto_detect is True - and _has_own_attribute(cls, "__hash__") - ): - hash = False - - if hash is not True and hash is not False and hash is not None: - # Can't use `hash in` because 1 == True for example. - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if hash is False or (hash is None and eq is False) or is_exc: - # Don't do anything. Should fall back to __object__'s __hash__ - # which is by id. - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - elif hash is True or ( - hash is None and eq is True and is_frozen is True - ): - # Build a __hash__ if told so, or if it's safe. - builder.add_hash() - else: - # Raise TypeError on attempts to hash. - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - builder.make_unhashable() - - if _determine_whether_to_implement( - cls, init, auto_detect, ("__init__",) - ): - builder.add_init() - else: - builder.add_attrs_init() - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, init must be True." - raise TypeError(msg) - - if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): - builder.add_replace() - - if ( - PY_3_10_PLUS - and match_args - and not _has_own_attribute(cls, "__match_args__") - ): - builder.add_match_args() - - return builder.build_class() - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -_attrs = attrs -""" -Internal alias so we can use it in functions that take an argument called -*attrs*. -""" - - -def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return cls.__setattr__ is _frozen_setattrs - - -def _generate_unique_filename(cls: type, func_name: str) -> str: - """ - Create a "filename" suitable for a function being generated. - """ - return ( - f"" - ) - - -def _make_hash_script( - cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool -) -> tuple[str, dict]: - attrs = tuple( - a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) - ) - - tab = " " - - type_hash = hash(_generate_unique_filename(cls, "hash")) - # If eq is custom generated, we need to include the functions in globs - globs = {} - - hash_def = "def __hash__(self" - hash_func = "hash((" - closing_braces = "))" - if not cache_hash: - hash_def += "):" - else: - hash_def += ", *" - - hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" - hash_func = "_cache_wrapper(" + hash_func - closing_braces += ")" - - method_lines = [hash_def] - - def append_hash_computation_lines(prefix, indent): - """ - Generate the code for actually computing the hash code. - Below this will either be returned directly or used to compute - a value which is then cached, depending on the value of cache_hash - """ - - method_lines.extend( - [ - indent + prefix + hash_func, - indent + f" {type_hash},", - ] - ) - - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - globs[cmp_name] = a.eq_key - method_lines.append( - indent + f" {cmp_name}(self.{a.name})," - ) - else: - method_lines.append(indent + f" self.{a.name},") - - method_lines.append(indent + " " + closing_braces) - - if cache_hash: - method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") - if frozen: - append_hash_computation_lines( - f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 - ) - method_lines.append(tab * 2 + ")") # close __setattr__ - else: - append_hash_computation_lines( - f"self.{_HASH_CACHE_FIELD} = ", tab * 2 - ) - method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") - else: - append_hash_computation_lines("return ", tab) - - script = "\n".join(method_lines) - return script, globs - - -def _add_hash(cls: type, attrs: list[Attribute]): - """ - Add a hash method to *cls*. - """ - script, globs = _make_hash_script( - cls, attrs, frozen=False, cache_hash=False - ) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__hash__") - ) - cls.__hash__ = globs["__hash__"] - return cls - - -def __ne__(self, other): - """ - Check equality and either forward a NotImplemented or - return the result negated. - """ - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - - return not result - - -def _make_eq_script(attrs: list) -> tuple[str, dict]: - """ - Create __eq__ method for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.eq] - - lines = [ - "def __eq__(self, other):", - " if other.__class__ is not self.__class__:", - " return NotImplemented", - ] - - globs = {} - if attrs: - lines.append(" return (") - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - # Add the key function to the global namespace - # of the evaluated function. - globs[cmp_name] = a.eq_key - lines.append( - f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" - ) - else: - lines.append(f" self.{a.name} == other.{a.name}") - if a is not attrs[-1]: - lines[-1] = f"{lines[-1]} and" - lines.append(" )") - else: - lines.append(" return True") - - script = "\n".join(lines) - - return script, globs - - -def _make_order(cls, attrs): - """ - Create ordering methods for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.order] - - def attrs_to_tuple(obj): - """ - Save us some typing. - """ - return tuple( - key(value) if key else value - for value, key in ( - (getattr(obj, a.name), a.order_key) for a in attrs - ) - ) - - def __lt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) < attrs_to_tuple(other) - - return NotImplemented - - def __le__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) <= attrs_to_tuple(other) - - return NotImplemented - - def __gt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) > attrs_to_tuple(other) - - return NotImplemented - - def __ge__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) >= attrs_to_tuple(other) - - return NotImplemented - - return __lt__, __le__, __gt__, __ge__ - - -def _add_eq(cls, attrs=None): - """ - Add equality methods to *cls* with *attrs*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_eq_script(attrs) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__eq__") - ) - cls.__eq__ = globs["__eq__"] - cls.__ne__ = __ne__ - - return cls - - -def _make_repr_script(attrs, ns) -> tuple[str, dict]: - """ - Create the source and globs for a __repr__ and return it. - """ - # Figure out which attributes to include, and which function to use to - # format them. The a.repr value can be either bool or a custom - # callable. - attr_names_with_reprs = tuple( - (a.name, (repr if a.repr is True else a.repr), a.init) - for a in attrs - if a.repr is not False - ) - globs = { - name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr - } - globs["_compat"] = _compat - globs["AttributeError"] = AttributeError - globs["NOTHING"] = NOTHING - attribute_fragments = [] - for name, r, i in attr_names_with_reprs: - accessor = ( - "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' - ) - fragment = ( - "%s={%s!r}" % (name, accessor) - if r == repr - else "%s={%s_repr(%s)}" % (name, name, accessor) - ) - attribute_fragments.append(fragment) - repr_fragment = ", ".join(attribute_fragments) - - if ns is None: - cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' - else: - cls_name_fragment = ns + ".{self.__class__.__name__}" - - lines = [ - "def __repr__(self):", - " try:", - " already_repring = _compat.repr_context.already_repring", - " except AttributeError:", - " already_repring = {id(self),}", - " _compat.repr_context.already_repring = already_repring", - " else:", - " if id(self) in already_repring:", - " return '...'", - " else:", - " already_repring.add(id(self))", - " try:", - f" return f'{cls_name_fragment}({repr_fragment})'", - " finally:", - " already_repring.remove(id(self))", - ] - - return "\n".join(lines), globs - - -def _add_repr(cls, ns=None, attrs=None): - """ - Add a repr method to *cls*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_repr_script(attrs, ns) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__repr__") - ) - cls.__repr__ = globs["__repr__"] - return cls - - -def fields(cls): - """ - Return the tuple of *attrs* attributes for a class. - - The tuple also allows accessing the fields by their names (see below for - examples). - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - tuple (with name accessors) of `attrs.Attribute` - - .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields - by name. - .. versionchanged:: 23.1.0 Add support for generic classes. - """ - generic_base = get_generic_base(cls) - - if generic_base is None and not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - - attrs = getattr(cls, "__attrs_attrs__", None) - - if attrs is None: - if generic_base is not None: - attrs = getattr(generic_base, "__attrs_attrs__", None) - if attrs is not None: - # Even though this is global state, stick it on here to speed - # it up. We rely on `cls` being cached for this to be - # efficient. - cls.__attrs_attrs__ = attrs - return attrs - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - - return attrs - - -def fields_dict(cls): - """ - Return an ordered dictionary of *attrs* attributes for a class, whose keys - are the attribute names. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - dict[str, attrs.Attribute]: Dict of attribute name to definition - - .. versionadded:: 18.1.0 - """ - if not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - return {a.name: a for a in attrs} - - -def validate(inst): - """ - Validate all attributes on *inst* that have a validator. - - Leaves all exceptions through. - - Args: - inst: Instance of a class with *attrs* attributes. - """ - if _config._run_validators is False: - return - - for a in fields(inst.__class__): - v = a.validator - if v is not None: - v(inst, a, getattr(inst, a.name)) - - -def _is_slot_attr(a_name, base_attr_map): - """ - Check if the attribute name comes from a slot class. - """ - cls = base_attr_map.get(a_name) - return cls and "__slots__" in cls.__dict__ - - -def _make_init_script( - cls, - attrs, - pre_init, - pre_init_has_args, - post_init, - frozen, - slots, - cache_hash, - base_attr_map, - is_exc, - cls_on_setattr, - attrs_init, -) -> tuple[str, dict, dict]: - has_cls_on_setattr = ( - cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP - ) - - if frozen and has_cls_on_setattr: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = cache_hash or frozen - filtered_attrs = [] - attr_dict = {} - for a in attrs: - if not a.init and a.default is NOTHING: - continue - - filtered_attrs.append(a) - attr_dict[a.name] = a - - if a.on_setattr is not None: - if frozen is True: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = True - elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: - needs_cached_setattr = True - - script, globs, annotations = _attrs_to_init_script( - filtered_attrs, - frozen, - slots, - pre_init, - pre_init_has_args, - post_init, - cache_hash, - base_attr_map, - is_exc, - needs_cached_setattr, - has_cls_on_setattr, - "__attrs_init__" if attrs_init else "__init__", - ) - if cls.__module__ in sys.modules: - # This makes typing.get_type_hints(CLS.__init__) resolve string types. - globs.update(sys.modules[cls.__module__].__dict__) - - globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) - - if needs_cached_setattr: - # Save the lookup overhead in __init__ if we need to circumvent - # setattr hooks. - globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ - - return script, globs, annotations - - -def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*. - """ - return f"_setattr('{attr_name}', {value_var})" - - -def _setattr_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*, but run - its converter first. - """ - return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" - - -def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise - relegate to _setattr. - """ - if has_on_setattr: - return _setattr(attr_name, value, True) - - return f"self.{attr_name} = {value}" - - -def _assign_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment after - conversion. Otherwise relegate to _setattr_with_converter. - """ - if has_on_setattr: - return _setattr_with_converter(attr_name, value_var, True, converter) - - return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" - - -def _determine_setters( - frozen: bool, slots: bool, base_attr_map: dict[str, type] -): - """ - Determine the correct setter functions based on whether a class is frozen - and/or slotted. - """ - if frozen is True: - if slots is True: - return (), _setattr, _setattr_with_converter - - # Dict frozen classes assign directly to __dict__. - # But only if the attribute doesn't come from an ancestor slot - # class. - # Note _inst_dict will be used again below if cache_hash is True - - def fmt_setter( - attr_name: str, value_var: str, has_on_setattr: bool - ) -> str: - if _is_slot_attr(attr_name, base_attr_map): - return _setattr(attr_name, value_var, has_on_setattr) - - return f"_inst_dict['{attr_name}'] = {value_var}" - - def fmt_setter_with_converter( - attr_name: str, - value_var: str, - has_on_setattr: bool, - converter: Converter, - ) -> str: - if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): - return _setattr_with_converter( - attr_name, value_var, has_on_setattr, converter - ) - - return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" - - return ( - ("_inst_dict = self.__dict__",), - fmt_setter, - fmt_setter_with_converter, - ) - - # Not frozen -- we can just assign directly. - return (), _assign, _assign_with_converter - - -def _attrs_to_init_script( - attrs: list[Attribute], - is_frozen: bool, - is_slotted: bool, - call_pre_init: bool, - pre_init_has_args: bool, - call_post_init: bool, - does_cache_hash: bool, - base_attr_map: dict[str, type], - is_exc: bool, - needs_cached_setattr: bool, - has_cls_on_setattr: bool, - method_name: str, -) -> tuple[str, dict, dict]: - """ - Return a script of an initializer for *attrs*, a dict of globals, and - annotations for the initializer. - - The globals are required by the generated script. - """ - lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] - - if needs_cached_setattr: - lines.append( - # Circumvent the __setattr__ descriptor to save one lookup per - # assignment. Note _setattr will be used again below if - # does_cache_hash is True. - "_setattr = _cached_setattr_get(self)" - ) - - extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( - is_frozen, is_slotted, base_attr_map - ) - lines.extend(extra_lines) - - args = [] - kw_only_args = [] - attrs_to_validate = [] - - # This is a dictionary of names to validator and converter callables. - # Injecting this into __init__ globals lets us avoid lookups. - names_for_globals = {} - annotations = {"return": None} - - for a in attrs: - if a.validator: - attrs_to_validate.append(a) - - attr_name = a.name - has_on_setattr = a.on_setattr is not None or ( - a.on_setattr is not setters.NO_OP and has_cls_on_setattr - ) - # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not - # explicitly provided - arg_name = a.alias - - has_factory = isinstance(a.default, Factory) - maybe_self = "self" if has_factory and a.default.takes_self else "" - - if a.converter is not None and not isinstance(a.converter, Converter): - converter = Converter(a.converter) - else: - converter = a.converter - - if a.init is False: - if has_factory: - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - elif converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - ) - ) - elif a.default is not NOTHING and not has_factory: - arg = f"{arg_name}=attr_dict['{attr_name}'].default" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - elif has_factory: - arg = f"{arg_name}=NOTHING" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - lines.append(f"if {arg_name} is not NOTHING:") - - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - " " - + fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter_with_converter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - " " + fmt_setter(attr_name, arg_name, has_on_setattr) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.kw_only: - kw_only_args.append(arg_name) - else: - args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - if a.init is True: - if a.type is not None and converter is None: - annotations[arg_name] = a.type - elif converter is not None and converter._first_param_type: - # Use the type from the converter if present. - annotations[arg_name] = converter._first_param_type - - if attrs_to_validate: # we can skip this if there are no validators. - names_for_globals["_config"] = _config - lines.append("if _config._run_validators is True:") - for a in attrs_to_validate: - val_name = "__attr_validator_" + a.name - attr_name = "__attr_" + a.name - lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") - names_for_globals[val_name] = a.validator - names_for_globals[attr_name] = a - - if call_post_init: - lines.append("self.__attrs_post_init__()") - - # Because this is set only after __attrs_post_init__ is called, a crash - # will result if post-init tries to access the hash code. This seemed - # preferable to setting this beforehand, in which case alteration to field - # values during post-init combined with post-init accessing the hash code - # would result in silent bugs. - if does_cache_hash: - if is_frozen: - if is_slotted: - init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" - else: - init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" - else: - init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" - lines.append(init_hash_cache) - - # For exceptions we rely on BaseException.__init__ for proper - # initialization. - if is_exc: - vals = ",".join(f"self.{a.name}" for a in attrs if a.init) - - lines.append(f"BaseException.__init__(self, {vals})") - - args = ", ".join(args) - pre_init_args = args - if kw_only_args: - # leading comma & kw_only args - args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" - pre_init_kw_only_args = ", ".join( - [ - f"{kw_arg_name}={kw_arg_name}" - # We need to remove the defaults from the kw_only_args. - for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) - ] - ) - pre_init_args += ", " if pre_init_args else "" - pre_init_args += pre_init_kw_only_args - - if call_pre_init and pre_init_has_args: - # If pre init method has arguments, pass same arguments as `__init__`. - lines[0] = f"self.__attrs_pre_init__({pre_init_args})" - - # Python <3.12 doesn't allow backslashes in f-strings. - NL = "\n " - return ( - f"""def {method_name}(self, {args}): - {NL.join(lines) if lines else "pass"} -""", - names_for_globals, - annotations, - ) - - -def _default_init_alias_for(name: str) -> str: - """ - The default __init__ parameter name for a field. - - This performs private-name adjustment via leading-unscore stripping, - and is the default value of Attribute.alias if not provided. - """ - - return name.lstrip("_") - - -class Attribute: - """ - *Read-only* representation of an attribute. - - .. warning:: - - You should never instantiate this class yourself. - - The class has *all* arguments of `attr.ib` (except for ``factory`` which is - only syntactic sugar for ``default=Factory(...)`` plus the following: - - - ``name`` (`str`): The name of the attribute. - - ``alias`` (`str`): The __init__ parameter name of the attribute, after - any explicit overrides and default private-attribute-name handling. - - ``inherited`` (`bool`): Whether or not that attribute has been inherited - from a base class. - - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The - callables that are used for comparing and ordering objects by this - attribute, respectively. These are set by passing a callable to - `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also - :ref:`comparison customization `. - - Instances of this class are frequently used for introspection purposes - like: - - - `fields` returns a tuple of them. - - Validators get them passed as the first argument. - - The :ref:`field transformer ` hook receives a list of - them. - - The ``alias`` property exposes the __init__ parameter name of the field, - with any overrides and default private-attribute handling applied. - - - .. versionadded:: 20.1.0 *inherited* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.2.0 *inherited* is not taken into account for - equality checks and hashing anymore. - .. versionadded:: 21.1.0 *eq_key* and *order_key* - .. versionadded:: 22.2.0 *alias* - - For the full version history of the fields, see `attr.ib`. - """ - - # These slots must NOT be reordered because we use them later for - # instantiation. - __slots__ = ( # noqa: RUF023 - "name", - "default", - "validator", - "repr", - "eq", - "eq_key", - "order", - "order_key", - "hash", - "init", - "metadata", - "type", - "converter", - "kw_only", - "inherited", - "on_setattr", - "alias", - ) - - def __init__( - self, - name, - default, - validator, - repr, - cmp, # XXX: unused, remove along with other cmp code. - hash, - init, - inherited, - metadata=None, - type=None, - converter=None, - kw_only=False, - eq=None, - eq_key=None, - order=None, - order_key=None, - on_setattr=None, - alias=None, - ): - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq_key or eq, order_key or order, True - ) - - # Cache this descriptor here to speed things up later. - bound_setattr = _OBJ_SETATTR.__get__(self) - - # Despite the big red warning, people *do* instantiate `Attribute` - # themselves. - bound_setattr("name", name) - bound_setattr("default", default) - bound_setattr("validator", validator) - bound_setattr("repr", repr) - bound_setattr("eq", eq) - bound_setattr("eq_key", eq_key) - bound_setattr("order", order) - bound_setattr("order_key", order_key) - bound_setattr("hash", hash) - bound_setattr("init", init) - bound_setattr("converter", converter) - bound_setattr( - "metadata", - ( - types.MappingProxyType(dict(metadata)) # Shallow copy - if metadata - else _EMPTY_METADATA_SINGLETON - ), - ) - bound_setattr("type", type) - bound_setattr("kw_only", kw_only) - bound_setattr("inherited", inherited) - bound_setattr("on_setattr", on_setattr) - bound_setattr("alias", alias) - - def __setattr__(self, name, value): - raise FrozenInstanceError - - @classmethod - def from_counting_attr(cls, name: str, ca: _CountingAttr, type=None): - # type holds the annotated value. deal with conflicts: - if type is None: - type = ca.type - elif ca.type is not None: - msg = f"Type annotation and type argument cannot both be present for '{name}'." - raise ValueError(msg) - return cls( - name, - ca._default, - ca._validator, - ca.repr, - None, - ca.hash, - ca.init, - False, - ca.metadata, - type, - ca.converter, - ca.kw_only, - ca.eq, - ca.eq_key, - ca.order, - ca.order_key, - ca.on_setattr, - ca.alias, - ) - - # Don't use attrs.evolve since fields(Attribute) doesn't work - def evolve(self, **changes): - """ - Copy *self* and apply *changes*. - - This works similarly to `attrs.evolve` but that function does not work - with :class:`attrs.Attribute`. - - It is mainly meant to be used for `transform-fields`. - - .. versionadded:: 20.3.0 - """ - new = copy.copy(self) - - new._setattrs(changes.items()) - - return new - - # Don't use _add_pickle since fields(Attribute) doesn't work - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple( - getattr(self, name) if name != "metadata" else dict(self.metadata) - for name in self.__slots__ - ) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - self._setattrs(zip(self.__slots__, state)) - - def _setattrs(self, name_values_pairs): - bound_setattr = _OBJ_SETATTR.__get__(self) - for name, value in name_values_pairs: - if name != "metadata": - bound_setattr(name, value) - else: - bound_setattr( - name, - ( - types.MappingProxyType(dict(value)) - if value - else _EMPTY_METADATA_SINGLETON - ), - ) - - -_a = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=(name != "metadata"), - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in Attribute.__slots__ -] - -Attribute = _add_hash( - _add_eq( - _add_repr(Attribute, attrs=_a), - attrs=[a for a in _a if a.name != "inherited"], - ), - attrs=[a for a in _a if a.hash and a.name != "inherited"], -) - - -class _CountingAttr: - """ - Intermediate representation of attributes that uses a counter to preserve - the order in which the attributes have been defined. - - *Internal* data structure of the attrs library. Running into is most - likely the result of a bug like a forgotten `@attr.s` decorator. - """ - - __slots__ = ( - "_default", - "_validator", - "alias", - "converter", - "counter", - "eq", - "eq_key", - "hash", - "init", - "kw_only", - "metadata", - "on_setattr", - "order", - "order_key", - "repr", - "type", - ) - __attrs_attrs__ = ( - *tuple( - Attribute( - name=name, - alias=_default_init_alias_for(name), - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=True, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ) - for name in ( - "counter", - "_default", - "repr", - "eq", - "order", - "hash", - "init", - "on_setattr", - "alias", - ) - ), - Attribute( - name="metadata", - alias="metadata", - default=None, - validator=None, - repr=True, - cmp=None, - hash=False, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ), - ) - cls_counter = 0 - - def __init__( - self, - default, - validator, - repr, - cmp, - hash, - init, - converter, - metadata, - type, - kw_only, - eq, - eq_key, - order, - order_key, - on_setattr, - alias, - ): - _CountingAttr.cls_counter += 1 - self.counter = _CountingAttr.cls_counter - self._default = default - self._validator = validator - self.converter = converter - self.repr = repr - self.eq = eq - self.eq_key = eq_key - self.order = order - self.order_key = order_key - self.hash = hash - self.init = init - self.metadata = metadata - self.type = type - self.kw_only = kw_only - self.on_setattr = on_setattr - self.alias = alias - - def validator(self, meth): - """ - Decorator that adds *meth* to the list of validators. - - Returns *meth* unchanged. - - .. versionadded:: 17.1.0 - """ - if self._validator is None: - self._validator = meth - else: - self._validator = and_(self._validator, meth) - return meth - - def default(self, meth): - """ - Decorator that allows to set the default for an attribute. - - Returns *meth* unchanged. - - Raises: - DefaultAlreadySetError: If default has been set before. - - .. versionadded:: 17.1.0 - """ - if self._default is not NOTHING: - raise DefaultAlreadySetError - - self._default = Factory(meth, takes_self=True) - - return meth - - -_CountingAttr = _add_eq(_add_repr(_CountingAttr)) - - -class Factory: - """ - Stores a factory callable. - - If passed as the default value to `attrs.field`, the factory is used to - generate a new value. - - Args: - factory (typing.Callable): - A callable that takes either none or exactly one mandatory - positional argument depending on *takes_self*. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. - - .. versionadded:: 17.1.0 *takes_self* - """ - - __slots__ = ("factory", "takes_self") - - def __init__(self, factory, takes_self=False): - self.factory = factory - self.takes_self = takes_self - - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple(getattr(self, name) for name in self.__slots__) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - for name, value in zip(self.__slots__, state): - setattr(self, name, value) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in Factory.__slots__ -] - -Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) - - -class Converter: - """ - Stores a converter callable. - - Allows for the wrapped converter to take additional arguments. The - arguments are passed in the order they are documented. - - Args: - converter (Callable): A callable that converts the passed value. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. (default: `False`) - - takes_field (bool): - Pass the field definition (an :class:`Attribute`) into the - converter as a positional argument. (default: `False`) - - .. versionadded:: 24.1.0 - """ - - __slots__ = ( - "__call__", - "_first_param_type", - "_global_name", - "converter", - "takes_field", - "takes_self", - ) - - def __init__(self, converter, *, takes_self=False, takes_field=False): - self.converter = converter - self.takes_self = takes_self - self.takes_field = takes_field - - ex = _AnnotationExtractor(converter) - self._first_param_type = ex.get_first_param_type() - - if not (self.takes_self or self.takes_field): - self.__call__ = lambda value, _, __: self.converter(value) - elif self.takes_self and not self.takes_field: - self.__call__ = lambda value, instance, __: self.converter( - value, instance - ) - elif not self.takes_self and self.takes_field: - self.__call__ = lambda value, __, field: self.converter( - value, field - ) - else: - self.__call__ = lambda value, instance, field: self.converter( - value, instance, field - ) - - rt = ex.get_return_type() - if rt is not None: - self.__call__.__annotations__["return"] = rt - - @staticmethod - def _get_global_name(attr_name: str) -> str: - """ - Return the name that a converter for an attribute name *attr_name* - would have. - """ - return f"__attr_converter_{attr_name}" - - def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: - """ - Return a string that calls the converter for an attribute name - *attr_name* and the value in variable named *value_var* according to - `self.takes_self` and `self.takes_field`. - """ - if not (self.takes_self or self.takes_field): - return f"{self._get_global_name(attr_name)}({value_var})" - - if self.takes_self and self.takes_field: - return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" - - if self.takes_self: - return f"{self._get_global_name(attr_name)}({value_var}, self)" - - return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" - - def __getstate__(self): - """ - Return a dict containing only converter and takes_self -- the rest gets - computed when loading. - """ - return { - "converter": self.converter, - "takes_self": self.takes_self, - "takes_field": self.takes_field, - } - - def __setstate__(self, state): - """ - Load instance from state. - """ - self.__init__(**state) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in ("converter", "takes_self", "takes_field") -] - -Converter = _add_hash( - _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f -) - - -def make_class( - name, attrs, bases=(object,), class_body=None, **attributes_arguments -): - r""" - A quick way to create a new class called *name* with *attrs*. - - .. note:: - - ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` - which means that it doesn't come with some of the improved defaults. - - For example, if you want the same ``on_setattr`` behavior as in - `attrs.define`, you have to pass the hooks yourself: ``make_class(..., - on_setattr=setters.pipe(setters.convert, setters.validate)`` - - .. warning:: - - It is *your* duty to ensure that the class name and the attribute names - are valid identifiers. ``make_class()`` will *not* validate them for - you. - - Args: - name (str): The name for the new class. - - attrs (list | dict): - A list of names or a dictionary of mappings of names to `attr.ib`\ - s / `attrs.field`\ s. - - The order is deduced from the order of the names or attributes - inside *attrs*. Otherwise the order of the definition of the - attributes is used. - - bases (tuple[type, ...]): Classes that the new class will subclass. - - class_body (dict): - An optional dictionary of class attributes for the new class. - - attributes_arguments: Passed unmodified to `attr.s`. - - Returns: - type: A new class with *attrs*. - - .. versionadded:: 17.1.0 *bases* - .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. - .. versionchanged:: 23.2.0 *class_body* - .. versionchanged:: 25.2.0 Class names can now be unicode. - """ - # Class identifiers are converted into the normal form NFKC while parsing - name = unicodedata.normalize("NFKC", name) - - if isinstance(attrs, dict): - cls_dict = attrs - elif isinstance(attrs, (list, tuple)): - cls_dict = {a: attrib() for a in attrs} - else: - msg = "attrs argument must be a dict or a list." - raise TypeError(msg) - - pre_init = cls_dict.pop("__attrs_pre_init__", None) - post_init = cls_dict.pop("__attrs_post_init__", None) - user_init = cls_dict.pop("__init__", None) - - body = {} - if class_body is not None: - body.update(class_body) - if pre_init is not None: - body["__attrs_pre_init__"] = pre_init - if post_init is not None: - body["__attrs_post_init__"] = post_init - if user_init is not None: - body["__init__"] = user_init - - type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) - - # For pickling to work, the __module__ variable needs to be set to the - # frame where the class is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython). - with contextlib.suppress(AttributeError, ValueError): - type_.__module__ = sys._getframe(1).f_globals.get( - "__name__", "__main__" - ) - - # We do it here for proper warnings with meaningful stacklevel. - cmp = attributes_arguments.pop("cmp", None) - ( - attributes_arguments["eq"], - attributes_arguments["order"], - ) = _determine_attrs_eq_order( - cmp, - attributes_arguments.get("eq"), - attributes_arguments.get("order"), - True, - ) - - cls = _attrs(these=cls_dict, **attributes_arguments)(type_) - # Only add type annotations now or "_attrs()" will complain: - cls.__annotations__ = { - k: v.type for k, v in cls_dict.items() if v.type is not None - } - return cls - - -# These are required by within this module so we define them here and merely -# import into .validators / .converters. - - -@attrs(slots=True, unsafe_hash=True) -class _AndValidator: - """ - Compose many validators to a single one. - """ - - _validators = attrib() - - def __call__(self, inst, attr, value): - for v in self._validators: - v(inst, attr, value) - - -def and_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - .. versionadded:: 17.1.0 - """ - vals = [] - for validator in validators: - vals.extend( - validator._validators - if isinstance(validator, _AndValidator) - else [validator] - ) - - return _AndValidator(tuple(vals)) - - -def pipe(*converters): - """ - A converter that composes multiple converters into one. - - When called on a value, it runs all wrapped converters, returning the - *last* value. - - Type annotations will be inferred from the wrapped converters', if they - have any. - - converters (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of converters. - - .. versionadded:: 20.1.0 - """ - - return_instance = any(isinstance(c, Converter) for c in converters) - - if return_instance: - - def pipe_converter(val, inst, field): - for c in converters: - val = ( - c(val, inst, field) if isinstance(c, Converter) else c(val) - ) - - return val - - else: - - def pipe_converter(val): - for c in converters: - val = c(val) - - return val - - if not converters: - # If the converter list is empty, pipe_converter is the identity. - A = TypeVar("A") - pipe_converter.__annotations__.update({"val": A, "return": A}) - else: - # Get parameter type from first converter. - t = _AnnotationExtractor(converters[0]).get_first_param_type() - if t: - pipe_converter.__annotations__["val"] = t - - last = converters[-1] - if not PY_3_11_PLUS and isinstance(last, Converter): - last = last.__call__ - - # Get return type from last converter. - rt = _AnnotationExtractor(last).get_return_type() - if rt: - pipe_converter.__annotations__["return"] = rt - - if return_instance: - return Converter(pipe_converter, takes_self=True, takes_field=True) - return pipe_converter diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_next_gen.py b/extensions/.local/lib/python3.11/site-packages/attr/_next_gen.py deleted file mode 100644 index 9290664..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_next_gen.py +++ /dev/null @@ -1,623 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -These are keyword-only APIs that call `attr.s` and `attr.ib` with different -default values. -""" - -from functools import partial - -from . import setters -from ._funcs import asdict as _asdict -from ._funcs import astuple as _astuple -from ._make import ( - _DEFAULT_ON_SETATTR, - NOTHING, - _frozen_setattrs, - attrib, - attrs, -) -from .exceptions import UnannotatedAttributeError - - -def define( - maybe_cls=None, - *, - these=None, - repr=None, - unsafe_hash=None, - hash=None, - init=None, - slots=True, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=None, - kw_only=False, - cache_hash=False, - auto_exc=True, - eq=None, - order=False, - auto_detect=True, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, -): - r""" - A class decorator that adds :term:`dunder methods` according to - :term:`fields ` specified using :doc:`type annotations `, - `field()` calls, or the *these* argument. - - Since *attrs* patches or replaces an existing class, you cannot use - `object.__init_subclass__` with *attrs* classes, because it runs too early. - As a replacement, you can define ``__attrs_init_subclass__`` on your class. - It will be called by *attrs* classes that subclass it after they're - created. See also :ref:`init-subclass`. - - Args: - slots (bool): - Create a :term:`slotted class ` that's more - memory-efficient. Slotted classes are generally superior to the - default dict classes, but have some gotchas you should know about, - so we encourage you to read the :term:`glossary entry `. - - auto_detect (bool): - Instead of setting the *init*, *repr*, *eq*, and *hash* arguments - explicitly, assume they are set to True **unless any** of the - involved methods for one of the arguments is implemented in the - *current* class (meaning, it is *not* inherited from some base - class). - - So, for example by implementing ``__eq__`` on a class yourself, - *attrs* will deduce ``eq=False`` and will create *neither* - ``__eq__`` *nor* ``__ne__`` (but Python classes come with a - sensible ``__ne__`` by default, so it *should* be enough to only - implement ``__eq__`` in most cases). - - Passing True or False` to *init*, *repr*, *eq*, or *hash* - overrides whatever *auto_detect* would determine. - - auto_exc (bool): - If the class subclasses `BaseException` (which implicitly includes - any subclass of any exception), the following happens to behave - like a well-behaved Python exception class: - - - the values for *eq*, *order*, and *hash* are ignored and the - instances compare and hash by the instance's ids [#]_ , - - all attributes that are either passed into ``__init__`` or have a - default value are additionally available as a tuple in the - ``args`` attribute, - - the value of *str* is ignored leaving ``__str__`` to base - classes. - - .. [#] - Note that *attrs* will *not* remove existing implementations of - ``__hash__`` or the equality methods. It just won't add own - ones. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - A callable that is run whenever the user attempts to set an - attribute (either by assignment like ``i.x = 42`` or by using - `setattr` like ``setattr(i, "x", 42)``). It receives the same - arguments as validators: the instance, the attribute that is being - modified, and the new value. - - If no exception is raised, the attribute is set to the return value - of the callable. - - If a list of callables is passed, they're automatically wrapped in - an `attrs.setters.pipe`. - - If left None, the default behavior is to run converters and - validators whenever an attribute is set. - - init (bool): - Create a ``__init__`` method that initializes the *attrs* - attributes. Leading underscores are stripped for the argument name, - unless an alias is set on the attribute. - - .. seealso:: - `init` shows advanced ways to customize the generated - ``__init__`` method, including executing code before and after. - - repr(bool): - Create a ``__repr__`` method with a human readable representation - of *attrs* attributes. - - str (bool): - Create a ``__str__`` method that is identical to ``__repr__``. This - is usually not necessary except for `Exception`\ s. - - eq (bool | None): - If True or None (default), add ``__eq__`` and ``__ne__`` methods - that check two instances for equality. - - .. seealso:: - `comparison` describes how to customize the comparison behavior - going as far comparing NumPy arrays. - - order (bool | None): - If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` - methods that behave like *eq* above and allow instances to be - ordered. - - They compare the instances as if they were tuples of their *attrs* - attributes if and only if the types of both classes are - *identical*. - - If `None` mirror value of *eq*. - - .. seealso:: `comparison` - - unsafe_hash (bool | None): - If None (default), the ``__hash__`` method is generated according - how *eq* and *frozen* are set. - - 1. If *both* are True, *attrs* will generate a ``__hash__`` for - you. - 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set - to None, marking it unhashable (which it is). - 3. If *eq* is False, ``__hash__`` will be left untouched meaning - the ``__hash__`` method of the base class will be used. If the - base class is `object`, this means it will fall back to id-based - hashing. - - Although not recommended, you can decide for yourself and force - *attrs* to create one (for example, if the class is immutable even - though you didn't freeze it programmatically) by passing True or - not. Both of these cases are rather special and should be used - carefully. - - .. seealso:: - - - Our documentation on `hashing`, - - Python's documentation on `object.__hash__`, - - and the `GitHub issue that led to the default \ behavior - `_ for more - details. - - hash (bool | None): - Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. - - cache_hash (bool): - Ensure that the object's hash code is computed only once and stored - on the object. If this is set to True, hashing must be either - explicitly or implicitly enabled for this class. If the hash code - is cached, avoid any reassignments of fields involved in hash code - computation or mutations of the objects those fields point to after - object creation. If such changes occur, the behavior of the - object's hash code is undefined. - - frozen (bool): - Make instances immutable after initialization. If someone attempts - to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` - is raised. - - .. note:: - - 1. This is achieved by installing a custom ``__setattr__`` - method on your class, so you can't implement your own. - - 2. True immutability is impossible in Python. - - 3. This *does* have a minor a runtime performance `impact - ` when initializing new instances. In other - words: ``__init__`` is slightly slower with ``frozen=True``. - - 4. If a class is frozen, you cannot modify ``self`` in - ``__attrs_post_init__`` or a self-written ``__init__``. You - can circumvent that limitation by using - ``object.__setattr__(self, "attribute_name", value)``. - - 5. Subclasses of a frozen class are frozen too. - - kw_only (bool): - Make all attributes keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). - - weakref_slot (bool): - Make instances weak-referenceable. This has no effect unless - *slots* is True. - - field_transformer (~typing.Callable | None): - A function that is called with the original class object and all - fields right before *attrs* finalizes the class. You can use this, - for example, to automatically add converters or validators to - fields based on their types. - - .. seealso:: `transform-fields` - - match_args (bool): - If True (default), set ``__match_args__`` on the class to support - :pep:`634` (*Structural Pattern Matching*). It is a tuple of all - non-keyword-only ``__init__`` parameter names on Python 3.10 and - later. Ignored on older Python versions. - - collect_by_mro (bool): - If True, *attrs* collects attributes from base classes correctly - according to the `method resolution order - `_. If False, *attrs* - will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. - - See also `issue #428 - `_. - - getstate_setstate (bool | None): - .. note:: - - This is usually only interesting for slotted classes and you - should probably just set *auto_detect* to True. - - If True, ``__getstate__`` and ``__setstate__`` are generated and - attached to the class. This is necessary for slotted classes to be - pickleable. If left None, it's True by default for slotted classes - and False for dict classes. - - If *auto_detect* is True, and *getstate_setstate* is left None, and - **either** ``__getstate__`` or ``__setstate__`` is detected - directly on the class (meaning: not inherited), it is set to False - (this is usually what you want). - - auto_attribs (bool | None): - If True, look at type annotations to determine which attributes to - use, like `dataclasses`. If False, it will only look for explicit - :func:`field` class attributes, like classic *attrs*. - - If left None, it will guess: - - 1. If any attributes are annotated and no unannotated - `attrs.field`\ s are found, it assumes *auto_attribs=True*. - 2. Otherwise it assumes *auto_attribs=False* and tries to collect - `attrs.field`\ s. - - If *attrs* decides to look at type annotations, **all** fields - **must** be annotated. If *attrs* encounters a field that is set to - a :func:`field` / `attr.ib` but lacks a type annotation, an - `attrs.exceptions.UnannotatedAttributeError` is raised. Use - ``field_name: typing.Any = field(...)`` if you don't want to set a - type. - - .. warning:: - - For features that use the attribute name to create decorators - (for example, :ref:`validators `), you still *must* - assign :func:`field` / `attr.ib` to them. Otherwise Python will - either not find the name or try to use the default value to - call, for example, ``validator`` on it. - - Attributes annotated as `typing.ClassVar`, and attributes that are - neither annotated nor set to an `field()` are **ignored**. - - these (dict[str, object]): - A dictionary of name to the (private) return value of `field()` - mappings. This is useful to avoid the definition of your attributes - within the class body because you can't (for example, if you want - to add ``__repr__`` methods to Django models) or don't want to. - - If *these* is not `None`, *attrs* will *not* search the class body - for attributes and will *not* remove any attributes from it. - - The order is deduced from the order of the attributes inside - *these*. - - Arguably, this is a rather obscure feature. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionadded:: 24.3.0 - Unless already present, a ``__replace__`` method is automatically - created for `copy.replace` (Python 3.13+ only). - - .. note:: - - The main differences to the classic `attr.s` are: - - - Automatically detect whether or not *auto_attribs* should be `True` - (c.f. *auto_attribs* parameter). - - Converters and validators run when attributes are set by default -- - if *frozen* is `False`. - - *slots=True* - - Usually, this has only upsides and few visible effects in everyday - programming. But it *can* lead to some surprising behaviors, so - please make sure to read :term:`slotted classes`. - - - *auto_exc=True* - - *auto_detect=True* - - *order=False* - - Some options that were only relevant on Python 2 or were kept around - for backwards-compatibility have been removed. - - """ - - def do_it(cls, auto_attribs): - return attrs( - maybe_cls=cls, - these=these, - repr=repr, - hash=hash, - unsafe_hash=unsafe_hash, - init=init, - slots=slots, - frozen=frozen, - weakref_slot=weakref_slot, - str=str, - auto_attribs=auto_attribs, - kw_only=kw_only, - cache_hash=cache_hash, - auto_exc=auto_exc, - eq=eq, - order=order, - auto_detect=auto_detect, - collect_by_mro=True, - getstate_setstate=getstate_setstate, - on_setattr=on_setattr, - field_transformer=field_transformer, - match_args=match_args, - ) - - def wrap(cls): - """ - Making this a wrapper ensures this code runs during class creation. - - We also ensure that frozen-ness of classes is inherited. - """ - nonlocal frozen, on_setattr - - had_on_setattr = on_setattr not in (None, setters.NO_OP) - - # By default, mutable classes convert & validate on setattr. - if frozen is False and on_setattr is None: - on_setattr = _DEFAULT_ON_SETATTR - - # However, if we subclass a frozen class, we inherit the immutability - # and disable on_setattr. - for base_cls in cls.__bases__: - if base_cls.__setattr__ is _frozen_setattrs: - if had_on_setattr: - msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." - raise ValueError(msg) - - on_setattr = setters.NO_OP - break - - if auto_attribs is not None: - return do_it(cls, auto_attribs) - - try: - return do_it(cls, True) - except UnannotatedAttributeError: - return do_it(cls, False) - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -mutable = define -frozen = partial(define, frozen=True, on_setattr=None) - - -def field( - *, - default=NOTHING, - validator=None, - repr=True, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=False, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new :term:`field` / :term:`attribute` on a class. - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attrs.define` (or similar)! - - Args: - default: - A value that is used if an *attrs*-generated ``__init__`` is used - and no value is passed while instantiating or the attribute is - excluded using ``init=False``. - - If the value is an instance of `attrs.Factory`, its callable will - be used to construct a new value (useful for mutable data types - like lists or dicts). - - If a default is not set (or set manually to `attrs.NOTHING`), a - value *must* be supplied when instantiating; otherwise a - `TypeError` will be raised. - - .. seealso:: `defaults` - - factory (~typing.Callable): - Syntactic sugar for ``default=attr.Factory(factory)``. - - validator (~typing.Callable | list[~typing.Callable]): - Callable that is called by *attrs*-generated ``__init__`` methods - after the instance has been initialized. They receive the - initialized instance, the :func:`~attrs.Attribute`, and the passed - value. - - The return value is *not* inspected so the validator has to throw - an exception itself. - - If a `list` is passed, its items are treated as validators and must - all pass. - - Validators can be globally disabled and re-enabled using - `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. - - The validator can also be set using decorator notation as shown - below. - - .. seealso:: :ref:`validators` - - repr (bool | ~typing.Callable): - Include this attribute in the generated ``__repr__`` method. If - True, include the attribute; if False, omit it. By default, the - built-in ``repr()`` function is used. To override how the attribute - value is formatted, pass a ``callable`` that takes a single value - and returns a string. Note that the resulting string is used as-is, - which means it will be used directly *instead* of calling - ``repr()`` (the default). - - eq (bool | ~typing.Callable): - If True (default), include this attribute in the generated - ``__eq__`` and ``__ne__`` methods that check two instances for - equality. To override how the attribute value is compared, pass a - callable that takes a single value and returns the value to be - compared. - - .. seealso:: `comparison` - - order (bool | ~typing.Callable): - If True (default), include this attributes in the generated - ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To - override how the attribute value is ordered, pass a callable that - takes a single value and returns the value to be ordered. - - .. seealso:: `comparison` - - hash (bool | None): - Include this attribute in the generated ``__hash__`` method. If - None (default), mirror *eq*'s value. This is the correct behavior - according the Python spec. Setting this value to anything else - than None is *discouraged*. - - .. seealso:: `hashing` - - init (bool): - Include this attribute in the generated ``__init__`` method. - - It is possible to set this to False and set a default value. In - that case this attributed is unconditionally initialized with the - specified default value or factory. - - .. seealso:: `init` - - converter (typing.Callable | Converter): - A callable that is called by *attrs*-generated ``__init__`` methods - to convert attribute's value to the desired format. - - If a vanilla callable is passed, it is given the passed-in value as - the only positional argument. It is possible to receive additional - arguments by wrapping the callable in a `Converter`. - - Either way, the returned value will be used as the new value of the - attribute. The value is converted before being passed to the - validator, if any. - - .. seealso:: :ref:`converters` - - metadata (dict | None): - An arbitrary mapping, to be used by third-party code. - - .. seealso:: `extending-metadata`. - - type (type): - The type of the attribute. Nowadays, the preferred method to - specify the type is using a variable annotation (see :pep:`526`). - This argument is provided for backwards-compatibility and for usage - with `make_class`. Regardless of the approach used, the type will - be stored on ``Attribute.type``. - - Please note that *attrs* doesn't do anything with this metadata by - itself. You can use it as part of your own code or for `static type - checking `. - - kw_only (bool): - Make this attribute keyword-only in the generated ``__init__`` (if - ``init`` is False, this parameter is ignored). - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - Allows to overwrite the *on_setattr* setting from `attr.s`. If left - None, the *on_setattr* value from `attr.s` is used. Set to - `attrs.setters.NO_OP` to run **no** `setattr` hooks for this - attribute -- regardless of the setting in `define()`. - - alias (str | None): - Override this attribute's parameter name in the generated - ``__init__`` method. If left None, default to ``name`` stripped - of leading underscores. See `private-attributes`. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionadded:: 22.2.0 *alias* - .. versionadded:: 23.1.0 - The *type* parameter has been re-added; mostly for `attrs.make_class`. - Please note that type checkers ignore this metadata. - - .. seealso:: - - `attr.ib` - """ - return attrib( - default=default, - validator=validator, - repr=repr, - hash=hash, - init=init, - metadata=metadata, - type=type, - converter=converter, - factory=factory, - kw_only=kw_only, - eq=eq, - order=order, - on_setattr=on_setattr, - alias=alias, - ) - - -def asdict(inst, *, recurse=True, filter=None, value_serializer=None): - """ - Same as `attr.asdict`, except that collections types are always retained - and dict is always used as *dict_factory*. - - .. versionadded:: 21.3.0 - """ - return _asdict( - inst=inst, - recurse=recurse, - filter=filter, - value_serializer=value_serializer, - retain_collection_types=True, - ) - - -def astuple(inst, *, recurse=True, filter=None): - """ - Same as `attr.astuple`, except that collections types are always retained - and `tuple` is always used as the *tuple_factory*. - - .. versionadded:: 21.3.0 - """ - return _astuple( - inst=inst, recurse=recurse, filter=filter, retain_collection_types=True - ) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_typing_compat.pyi b/extensions/.local/lib/python3.11/site-packages/attr/_typing_compat.pyi deleted file mode 100644 index ca7b71e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_typing_compat.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, ClassVar, Protocol - -# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. -MYPY = False - -if MYPY: - # A protocol to be able to statically accept an attrs class. - class AttrsInstance_(Protocol): - __attrs_attrs__: ClassVar[Any] - -else: - # For type checkers without plug-in support use an empty protocol that - # will (hopefully) be combined into a union. - class AttrsInstance_(Protocol): - pass diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_version_info.py b/extensions/.local/lib/python3.11/site-packages/attr/_version_info.py deleted file mode 100644 index 51a1312..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_version_info.py +++ /dev/null @@ -1,86 +0,0 @@ -# SPDX-License-Identifier: MIT - - -from functools import total_ordering - -from ._funcs import astuple -from ._make import attrib, attrs - - -@total_ordering -@attrs(eq=False, order=False, slots=True, frozen=True) -class VersionInfo: - """ - A version object that can be compared to tuple of length 1--4: - - >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) - True - >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) - True - >>> vi = attr.VersionInfo(19, 2, 0, "final") - >>> vi < (19, 1, 1) - False - >>> vi < (19,) - False - >>> vi == (19, 2,) - True - >>> vi == (19, 2, 1) - False - - .. versionadded:: 19.2 - """ - - year = attrib(type=int) - minor = attrib(type=int) - micro = attrib(type=int) - releaselevel = attrib(type=str) - - @classmethod - def _from_version_string(cls, s): - """ - Parse *s* and return a _VersionInfo. - """ - v = s.split(".") - if len(v) == 3: - v.append("final") - - return cls( - year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] - ) - - def _ensure_tuple(self, other): - """ - Ensure *other* is a tuple of a valid length. - - Returns a possibly transformed *other* and ourselves as a tuple of - the same length as *other*. - """ - - if self.__class__ is other.__class__: - other = astuple(other) - - if not isinstance(other, tuple): - raise NotImplementedError - - if not (1 <= len(other) <= 4): - raise NotImplementedError - - return astuple(self)[: len(other)], other - - def __eq__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - return us == them - - def __lt__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't - # have to do anything special with releaselevel for now. - return us < them diff --git a/extensions/.local/lib/python3.11/site-packages/attr/_version_info.pyi b/extensions/.local/lib/python3.11/site-packages/attr/_version_info.pyi deleted file mode 100644 index 45ced08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/_version_info.pyi +++ /dev/null @@ -1,9 +0,0 @@ -class VersionInfo: - @property - def year(self) -> int: ... - @property - def minor(self) -> int: ... - @property - def micro(self) -> int: ... - @property - def releaselevel(self) -> str: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attr/converters.py b/extensions/.local/lib/python3.11/site-packages/attr/converters.py deleted file mode 100644 index 0a79dee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/converters.py +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful converters. -""" - -import typing - -from ._compat import _AnnotationExtractor -from ._make import NOTHING, Converter, Factory, pipe - - -__all__ = [ - "default_if_none", - "optional", - "pipe", - "to_bool", -] - - -def optional(converter): - """ - A converter that allows an attribute to be optional. An optional attribute - is one which can be set to `None`. - - Type annotations will be inferred from the wrapped converter's, if it has - any. - - Args: - converter (typing.Callable): - the converter that is used for non-`None` values. - - .. versionadded:: 17.1.0 - """ - - if isinstance(converter, Converter): - - def optional_converter(val, inst, field): - if val is None: - return None - return converter(val, inst, field) - - else: - - def optional_converter(val): - if val is None: - return None - return converter(val) - - xtr = _AnnotationExtractor(converter) - - t = xtr.get_first_param_type() - if t: - optional_converter.__annotations__["val"] = typing.Optional[t] - - rt = xtr.get_return_type() - if rt: - optional_converter.__annotations__["return"] = typing.Optional[rt] - - if isinstance(converter, Converter): - return Converter(optional_converter, takes_self=True, takes_field=True) - - return optional_converter - - -def default_if_none(default=NOTHING, factory=None): - """ - A converter that allows to replace `None` values by *default* or the result - of *factory*. - - Args: - default: - Value to be used if `None` is passed. Passing an instance of - `attrs.Factory` is supported, however the ``takes_self`` option is - *not*. - - factory (typing.Callable): - A callable that takes no parameters whose result is used if `None` - is passed. - - Raises: - TypeError: If **neither** *default* or *factory* is passed. - - TypeError: If **both** *default* and *factory* are passed. - - ValueError: - If an instance of `attrs.Factory` is passed with - ``takes_self=True``. - - .. versionadded:: 18.2.0 - """ - if default is NOTHING and factory is None: - msg = "Must pass either `default` or `factory`." - raise TypeError(msg) - - if default is not NOTHING and factory is not None: - msg = "Must pass either `default` or `factory` but not both." - raise TypeError(msg) - - if factory is not None: - default = Factory(factory) - - if isinstance(default, Factory): - if default.takes_self: - msg = "`takes_self` is not supported by default_if_none." - raise ValueError(msg) - - def default_if_none_converter(val): - if val is not None: - return val - - return default.factory() - - else: - - def default_if_none_converter(val): - if val is not None: - return val - - return default - - return default_if_none_converter - - -def to_bool(val): - """ - Convert "boolean" strings (for example, from environment variables) to real - booleans. - - Values mapping to `True`: - - - ``True`` - - ``"true"`` / ``"t"`` - - ``"yes"`` / ``"y"`` - - ``"on"`` - - ``"1"`` - - ``1`` - - Values mapping to `False`: - - - ``False`` - - ``"false"`` / ``"f"`` - - ``"no"`` / ``"n"`` - - ``"off"`` - - ``"0"`` - - ``0`` - - Raises: - ValueError: For any other value. - - .. versionadded:: 21.3.0 - """ - if isinstance(val, str): - val = val.lower() - - if val in (True, "true", "t", "yes", "y", "on", "1", 1): - return True - if val in (False, "false", "f", "no", "n", "off", "0", 0): - return False - - msg = f"Cannot convert value to bool: {val!r}" - raise ValueError(msg) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/converters.pyi b/extensions/.local/lib/python3.11/site-packages/attr/converters.pyi deleted file mode 100644 index 12bd0c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/converters.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Callable, Any, overload - -from attrs import _ConverterType, _CallableConverterType - -@overload -def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... -@overload -def pipe(*validators: _ConverterType) -> _ConverterType: ... -@overload -def optional(converter: _CallableConverterType) -> _CallableConverterType: ... -@overload -def optional(converter: _ConverterType) -> _ConverterType: ... -@overload -def default_if_none(default: Any) -> _CallableConverterType: ... -@overload -def default_if_none( - *, factory: Callable[[], Any] -) -> _CallableConverterType: ... -def to_bool(val: str | int | bool) -> bool: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attr/exceptions.py b/extensions/.local/lib/python3.11/site-packages/attr/exceptions.py deleted file mode 100644 index 3b7abb8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/exceptions.py +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -from typing import ClassVar - - -class FrozenError(AttributeError): - """ - A frozen/immutable instance or attribute have been attempted to be - modified. - - It mirrors the behavior of ``namedtuples`` by using the same error message - and subclassing `AttributeError`. - - .. versionadded:: 20.1.0 - """ - - msg = "can't set attribute" - args: ClassVar[tuple[str]] = [msg] - - -class FrozenInstanceError(FrozenError): - """ - A frozen instance has been attempted to be modified. - - .. versionadded:: 16.1.0 - """ - - -class FrozenAttributeError(FrozenError): - """ - A frozen attribute has been attempted to be modified. - - .. versionadded:: 20.1.0 - """ - - -class AttrsAttributeNotFoundError(ValueError): - """ - An *attrs* function couldn't find an attribute that the user asked for. - - .. versionadded:: 16.2.0 - """ - - -class NotAnAttrsClassError(ValueError): - """ - A non-*attrs* class has been passed into an *attrs* function. - - .. versionadded:: 16.2.0 - """ - - -class DefaultAlreadySetError(RuntimeError): - """ - A default has been set when defining the field and is attempted to be reset - using the decorator. - - .. versionadded:: 17.1.0 - """ - - -class UnannotatedAttributeError(RuntimeError): - """ - A class with ``auto_attribs=True`` has a field without a type annotation. - - .. versionadded:: 17.3.0 - """ - - -class PythonTooOldError(RuntimeError): - """ - It was attempted to use an *attrs* feature that requires a newer Python - version. - - .. versionadded:: 18.2.0 - """ - - -class NotCallableError(TypeError): - """ - A field requiring a callable has been set with a value that is not - callable. - - .. versionadded:: 19.2.0 - """ - - def __init__(self, msg, value): - super(TypeError, self).__init__(msg, value) - self.msg = msg - self.value = value - - def __str__(self): - return str(self.msg) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/exceptions.pyi b/extensions/.local/lib/python3.11/site-packages/attr/exceptions.pyi deleted file mode 100644 index f268011..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any - -class FrozenError(AttributeError): - msg: str = ... - -class FrozenInstanceError(FrozenError): ... -class FrozenAttributeError(FrozenError): ... -class AttrsAttributeNotFoundError(ValueError): ... -class NotAnAttrsClassError(ValueError): ... -class DefaultAlreadySetError(RuntimeError): ... -class UnannotatedAttributeError(RuntimeError): ... -class PythonTooOldError(RuntimeError): ... - -class NotCallableError(TypeError): - msg: str = ... - value: Any = ... - def __init__(self, msg: str, value: Any) -> None: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attr/filters.py b/extensions/.local/lib/python3.11/site-packages/attr/filters.py deleted file mode 100644 index 689b170..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/filters.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful filters for `attrs.asdict` and `attrs.astuple`. -""" - -from ._make import Attribute - - -def _split_what(what): - """ - Returns a tuple of `frozenset`s of classes and attributes. - """ - return ( - frozenset(cls for cls in what if isinstance(cls, type)), - frozenset(cls for cls in what if isinstance(cls, str)), - frozenset(cls for cls in what if isinstance(cls, Attribute)), - ) - - -def include(*what): - """ - Create a filter that only allows *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to include. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.1.0 Accept strings with field names. - """ - cls, names, attrs = _split_what(what) - - def include_(attribute, value): - return ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return include_ - - -def exclude(*what): - """ - Create a filter that does **not** allow *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to exclude. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.3.0 Accept field name string as input argument - """ - cls, names, attrs = _split_what(what) - - def exclude_(attribute, value): - return not ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return exclude_ diff --git a/extensions/.local/lib/python3.11/site-packages/attr/filters.pyi b/extensions/.local/lib/python3.11/site-packages/attr/filters.pyi deleted file mode 100644 index 974abdc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/filters.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Any - -from . import Attribute, _FilterType - -def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... -def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attr/py.typed b/extensions/.local/lib/python3.11/site-packages/attr/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/attr/setters.py b/extensions/.local/lib/python3.11/site-packages/attr/setters.py deleted file mode 100644 index 78b0839..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/setters.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly used hooks for on_setattr. -""" - -from . import _config -from .exceptions import FrozenAttributeError - - -def pipe(*setters): - """ - Run all *setters* and return the return value of the last one. - - .. versionadded:: 20.1.0 - """ - - def wrapped_pipe(instance, attrib, new_value): - rv = new_value - - for setter in setters: - rv = setter(instance, attrib, rv) - - return rv - - return wrapped_pipe - - -def frozen(_, __, ___): - """ - Prevent an attribute to be modified. - - .. versionadded:: 20.1.0 - """ - raise FrozenAttributeError - - -def validate(instance, attrib, new_value): - """ - Run *attrib*'s validator on *new_value* if it has one. - - .. versionadded:: 20.1.0 - """ - if _config._run_validators is False: - return new_value - - v = attrib.validator - if not v: - return new_value - - v(instance, attrib, new_value) - - return new_value - - -def convert(instance, attrib, new_value): - """ - Run *attrib*'s converter -- if it has one -- on *new_value* and return the - result. - - .. versionadded:: 20.1.0 - """ - c = attrib.converter - if c: - # This can be removed once we drop 3.8 and use attrs.Converter instead. - from ._make import Converter - - if not isinstance(c, Converter): - return c(new_value) - - return c(new_value, instance, attrib) - - return new_value - - -# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. -# Sphinx's autodata stopped working, so the docstring is inlined in the API -# docs. -NO_OP = object() diff --git a/extensions/.local/lib/python3.11/site-packages/attr/setters.pyi b/extensions/.local/lib/python3.11/site-packages/attr/setters.pyi deleted file mode 100644 index 73abf36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/setters.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any, NewType, NoReturn, TypeVar - -from . import Attribute -from attrs import _OnSetAttrType - -_T = TypeVar("_T") - -def frozen( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> NoReturn: ... -def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... -def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... - -# convert is allowed to return Any, because they can be chained using pipe. -def convert( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> Any: ... - -_NoOpType = NewType("_NoOpType", object) -NO_OP: _NoOpType diff --git a/extensions/.local/lib/python3.11/site-packages/attr/validators.py b/extensions/.local/lib/python3.11/site-packages/attr/validators.py deleted file mode 100644 index e7b7552..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/validators.py +++ /dev/null @@ -1,710 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful validators. -""" - -import operator -import re - -from contextlib import contextmanager -from re import Pattern - -from ._config import get_run_validators, set_run_validators -from ._make import _AndValidator, and_, attrib, attrs -from .converters import default_if_none -from .exceptions import NotCallableError - - -__all__ = [ - "and_", - "deep_iterable", - "deep_mapping", - "disabled", - "ge", - "get_disabled", - "gt", - "in_", - "instance_of", - "is_callable", - "le", - "lt", - "matches_re", - "max_len", - "min_len", - "not_", - "optional", - "or_", - "set_disabled", -] - - -def set_disabled(disabled): - """ - Globally disable or enable running validators. - - By default, they are run. - - Args: - disabled (bool): If `True`, disable running all validators. - - .. warning:: - - This function is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(not disabled) - - -def get_disabled(): - """ - Return a bool indicating whether validators are currently disabled or not. - - Returns: - bool:`True` if validators are currently disabled. - - .. versionadded:: 21.3.0 - """ - return not get_run_validators() - - -@contextmanager -def disabled(): - """ - Context manager that disables running validators within its context. - - .. warning:: - - This context manager is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(False) - try: - yield - finally: - set_run_validators(True) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InstanceOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not isinstance(value, self.type): - msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def instance_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `isinstance` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type]): The type to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _InstanceOfValidator(type) - - -@attrs(repr=False, frozen=True, slots=True) -class _MatchesReValidator: - pattern = attrib() - match_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.match_func(value): - msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" - raise ValueError( - msg, - attr, - self.pattern, - value, - ) - - def __repr__(self): - return f"" - - -def matches_re(regex, flags=0, func=None): - r""" - A validator that raises `ValueError` if the initializer is called with a - string that doesn't match *regex*. - - Args: - regex (str, re.Pattern): - A regex string or precompiled pattern to match against - - flags (int): - Flags that will be passed to the underlying re function (default 0) - - func (typing.Callable): - Which underlying `re` function to call. Valid options are - `re.fullmatch`, `re.search`, and `re.match`; the default `None` - means `re.fullmatch`. For performance reasons, the pattern is - always precompiled using `re.compile`. - - .. versionadded:: 19.2.0 - .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. - """ - valid_funcs = (re.fullmatch, None, re.search, re.match) - if func not in valid_funcs: - msg = "'func' must be one of {}.".format( - ", ".join( - sorted((e and e.__name__) or "None" for e in set(valid_funcs)) - ) - ) - raise ValueError(msg) - - if isinstance(regex, Pattern): - if flags: - msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" - raise TypeError(msg) - pattern = regex - else: - pattern = re.compile(regex, flags) - - if func is re.match: - match_func = pattern.match - elif func is re.search: - match_func = pattern.search - else: - match_func = pattern.fullmatch - - return _MatchesReValidator(pattern, match_func) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OptionalValidator: - validator = attrib() - - def __call__(self, inst, attr, value): - if value is None: - return - - self.validator(inst, attr, value) - - def __repr__(self): - return f"" - - -def optional(validator): - """ - A validator that makes an attribute optional. An optional attribute is one - which can be set to `None` in addition to satisfying the requirements of - the sub-validator. - - Args: - validator - (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): - A validator (or validators) that is used for non-`None` values. - - .. versionadded:: 15.1.0 - .. versionchanged:: 17.1.0 *validator* can be a list of validators. - .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. - """ - if isinstance(validator, (list, tuple)): - return _OptionalValidator(_AndValidator(validator)) - - return _OptionalValidator(validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InValidator: - options = attrib() - _original_options = attrib(hash=False) - - def __call__(self, inst, attr, value): - try: - in_options = value in self.options - except TypeError: # e.g. `1 in "abc"` - in_options = False - - if not in_options: - msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" - raise ValueError( - msg, - attr, - self._original_options, - value, - ) - - def __repr__(self): - return f"" - - -def in_(options): - """ - A validator that raises a `ValueError` if the initializer is called with a - value that does not belong in the *options* provided. - - The check is performed using ``value in options``, so *options* has to - support that operation. - - To keep the validator hashable, dicts, lists, and sets are transparently - transformed into a `tuple`. - - Args: - options: Allowed options. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected options, and the value it got. - - .. versionadded:: 17.1.0 - .. versionchanged:: 22.1.0 - The ValueError was incomplete until now and only contained the human - readable error message. Now it contains all the information that has - been promised since 17.1.0. - .. versionchanged:: 24.1.0 - *options* that are a list, dict, or a set are now transformed into a - tuple to keep the validator hashable. - """ - repr_options = options - if isinstance(options, (list, dict, set)): - options = tuple(options) - - return _InValidator(options, repr_options) - - -@attrs(repr=False, slots=False, unsafe_hash=True) -class _IsCallableValidator: - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not callable(value): - message = ( - "'{name}' must be callable " - "(got {value!r} that is a {actual!r})." - ) - raise NotCallableError( - msg=message.format( - name=attr.name, value=value, actual=value.__class__ - ), - value=value, - ) - - def __repr__(self): - return "" - - -def is_callable(): - """ - A validator that raises a `attrs.exceptions.NotCallableError` if the - initializer is called with a value for this particular attribute that is - not callable. - - .. versionadded:: 19.1.0 - - Raises: - attrs.exceptions.NotCallableError: - With a human readable error message containing the attribute - (`attrs.Attribute`) name, and the value it got. - """ - return _IsCallableValidator() - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepIterable: - member_validator = attrib(validator=is_callable()) - iterable_validator = attrib( - default=None, validator=optional(is_callable()) - ) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.iterable_validator is not None: - self.iterable_validator(inst, attr, value) - - for member in value: - self.member_validator(inst, attr, member) - - def __repr__(self): - iterable_identifier = ( - "" - if self.iterable_validator is None - else f" {self.iterable_validator!r}" - ) - return ( - f"" - ) - - -def deep_iterable(member_validator, iterable_validator=None): - """ - A validator that performs deep validation of an iterable. - - Args: - member_validator: Validator to apply to iterable members. - - iterable_validator: - Validator to apply to iterable itself (optional). - - Raises - TypeError: if any sub-validators fail - - .. versionadded:: 19.1.0 - """ - if isinstance(member_validator, (list, tuple)): - member_validator = and_(*member_validator) - return _DeepIterable(member_validator, iterable_validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepMapping: - key_validator = attrib(validator=is_callable()) - value_validator = attrib(validator=is_callable()) - mapping_validator = attrib(default=None, validator=optional(is_callable())) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.mapping_validator is not None: - self.mapping_validator(inst, attr, value) - - for key in value: - self.key_validator(inst, attr, key) - self.value_validator(inst, attr, value[key]) - - def __repr__(self): - return f"" - - -def deep_mapping(key_validator, value_validator, mapping_validator=None): - """ - A validator that performs deep validation of a dictionary. - - Args: - key_validator: Validator to apply to dictionary keys. - - value_validator: Validator to apply to dictionary values. - - mapping_validator: - Validator to apply to top-level mapping attribute (optional). - - .. versionadded:: 19.1.0 - - Raises: - TypeError: if any sub-validators fail - """ - return _DeepMapping(key_validator, value_validator, mapping_validator) - - -@attrs(repr=False, frozen=True, slots=True) -class _NumberValidator: - bound = attrib() - compare_op = attrib() - compare_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.compare_func(value, self.bound): - msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def lt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number larger or equal to *val*. - - The validator uses `operator.lt` to compare the values. - - Args: - val: Exclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<", operator.lt) - - -def le(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number greater than *val*. - - The validator uses `operator.le` to compare the values. - - Args: - val: Inclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<=", operator.le) - - -def ge(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller than *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Inclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">=", operator.ge) - - -def gt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller or equal to *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Exclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">", operator.gt) - - -@attrs(repr=False, frozen=True, slots=True) -class _MaxLengthValidator: - max_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) > self.max_length: - msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def max_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is longer than *length*. - - Args: - length (int): Maximum length of the string or iterable - - .. versionadded:: 21.3.0 - """ - return _MaxLengthValidator(length) - - -@attrs(repr=False, frozen=True, slots=True) -class _MinLengthValidator: - min_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) < self.min_length: - msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def min_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is shorter than *length*. - - Args: - length (int): Minimum length of the string or iterable - - .. versionadded:: 22.1.0 - """ - return _MinLengthValidator(length) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _SubclassOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not issubclass(value, self.type): - msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def _subclass_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `issubclass` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type, ...]): The type(s) to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _SubclassOfValidator(type) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _NotValidator: - validator = attrib() - msg = attrib( - converter=default_if_none( - "not_ validator child '{validator!r}' " - "did not raise a captured error" - ) - ) - exc_types = attrib( - validator=deep_iterable( - member_validator=_subclass_of(Exception), - iterable_validator=instance_of(tuple), - ), - ) - - def __call__(self, inst, attr, value): - try: - self.validator(inst, attr, value) - except self.exc_types: - pass # suppress error to invert validity - else: - raise ValueError( - self.msg.format( - validator=self.validator, - exc_types=self.exc_types, - ), - attr, - self.validator, - value, - self.exc_types, - ) - - def __repr__(self): - return f"" - - -def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): - """ - A validator that wraps and logically 'inverts' the validator passed to it. - It will raise a `ValueError` if the provided validator *doesn't* raise a - `ValueError` or `TypeError` (by default), and will suppress the exception - if the provided validator *does*. - - Intended to be used with existing validators to compose logic without - needing to create inverted variants, for example, ``not_(in_(...))``. - - Args: - validator: A validator to be logically inverted. - - msg (str): - Message to raise if validator fails. Formatted with keys - ``exc_types`` and ``validator``. - - exc_types (tuple[type, ...]): - Exception type(s) to capture. Other types raised by child - validators will not be intercepted and pass through. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the validator that failed to raise an - exception, the value it got, and the expected exception types. - - .. versionadded:: 22.2.0 - """ - try: - exc_types = tuple(exc_types) - except TypeError: - exc_types = (exc_types,) - return _NotValidator(validator, msg, exc_types) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OrValidator: - validators = attrib() - - def __call__(self, inst, attr, value): - for v in self.validators: - try: - v(inst, attr, value) - except Exception: # noqa: BLE001, PERF203, S112 - continue - else: - return - - msg = f"None of {self.validators!r} satisfied for value {value!r}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def or_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators until one of them is - satisfied. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - Raises: - ValueError: - If no validator is satisfied. Raised with a human-readable error - message listing all the wrapped validators and the value that - failed all of them. - - .. versionadded:: 24.1.0 - """ - vals = [] - for v in validators: - vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) - - return _OrValidator(tuple(vals)) diff --git a/extensions/.local/lib/python3.11/site-packages/attr/validators.pyi b/extensions/.local/lib/python3.11/site-packages/attr/validators.pyi deleted file mode 100644 index a0fdda7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attr/validators.pyi +++ /dev/null @@ -1,86 +0,0 @@ -from types import UnionType -from typing import ( - Any, - AnyStr, - Callable, - Container, - ContextManager, - Iterable, - Mapping, - Match, - Pattern, - TypeVar, - overload, -) - -from attrs import _ValidatorType -from attrs import _ValidatorArgType - -_T = TypeVar("_T") -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -_T3 = TypeVar("_T3") -_I = TypeVar("_I", bound=Iterable) -_K = TypeVar("_K") -_V = TypeVar("_V") -_M = TypeVar("_M", bound=Mapping) - -def set_disabled(run: bool) -> None: ... -def get_disabled() -> bool: ... -def disabled() -> ContextManager[None]: ... - -# To be more precise on instance_of use some overloads. -# If there are more than 3 items in the tuple then we fall back to Any -@overload -def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... -@overload -def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2]], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2], type[_T3]], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... -@overload -def instance_of(type: UnionType) -> _ValidatorType[Any]: ... -def optional( - validator: ( - _ValidatorType[_T] - | list[_ValidatorType[_T]] - | tuple[_ValidatorType[_T]] - ), -) -> _ValidatorType[_T | None]: ... -def in_(options: Container[_T]) -> _ValidatorType[_T]: ... -def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... -def matches_re( - regex: Pattern[AnyStr] | AnyStr, - flags: int = ..., - func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., -) -> _ValidatorType[AnyStr]: ... -def deep_iterable( - member_validator: _ValidatorArgType[_T], - iterable_validator: _ValidatorType[_I] | None = ..., -) -> _ValidatorType[_I]: ... -def deep_mapping( - key_validator: _ValidatorType[_K], - value_validator: _ValidatorType[_V], - mapping_validator: _ValidatorType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -def is_callable() -> _ValidatorType[_T]: ... -def lt(val: _T) -> _ValidatorType[_T]: ... -def le(val: _T) -> _ValidatorType[_T]: ... -def ge(val: _T) -> _ValidatorType[_T]: ... -def gt(val: _T) -> _ValidatorType[_T]: ... -def max_len(length: int) -> _ValidatorType[_T]: ... -def min_len(length: int) -> _ValidatorType[_T]: ... -def not_( - validator: _ValidatorType[_T], - *, - msg: str | None = None, - exc_types: type[Exception] | Iterable[type[Exception]] = ..., -) -> _ValidatorType[_T]: ... -def or_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/METADATA deleted file mode 100644 index 029afee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/METADATA +++ /dev/null @@ -1,232 +0,0 @@ -Metadata-Version: 2.4 -Name: attrs -Version: 25.3.0 -Summary: Classes Without Boilerplate -Project-URL: Documentation, https://www.attrs.org/ -Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html -Project-URL: GitHub, https://github.com/python-attrs/attrs -Project-URL: Funding, https://github.com/sponsors/hynek -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi -Author-email: Hynek Schlawack -License-Expression: MIT -License-File: LICENSE -Keywords: attribute,boilerplate,class -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Provides-Extra: benchmark -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'benchmark' -Requires-Dist: hypothesis; extra == 'benchmark' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' -Requires-Dist: pympler; extra == 'benchmark' -Requires-Dist: pytest-codspeed; extra == 'benchmark' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' -Requires-Dist: pytest-xdist[psutil]; extra == 'benchmark' -Requires-Dist: pytest>=4.3.0; extra == 'benchmark' -Provides-Extra: cov -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'cov' -Requires-Dist: coverage[toml]>=5.3; extra == 'cov' -Requires-Dist: hypothesis; extra == 'cov' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' -Requires-Dist: pympler; extra == 'cov' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' -Requires-Dist: pytest-xdist[psutil]; extra == 'cov' -Requires-Dist: pytest>=4.3.0; extra == 'cov' -Provides-Extra: dev -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'dev' -Requires-Dist: hypothesis; extra == 'dev' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' -Requires-Dist: pre-commit-uv; extra == 'dev' -Requires-Dist: pympler; extra == 'dev' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' -Requires-Dist: pytest-xdist[psutil]; extra == 'dev' -Requires-Dist: pytest>=4.3.0; extra == 'dev' -Provides-Extra: docs -Requires-Dist: cogapp; extra == 'docs' -Requires-Dist: furo; extra == 'docs' -Requires-Dist: myst-parser; extra == 'docs' -Requires-Dist: sphinx; extra == 'docs' -Requires-Dist: sphinx-notfound-page; extra == 'docs' -Requires-Dist: sphinxcontrib-towncrier; extra == 'docs' -Requires-Dist: towncrier; extra == 'docs' -Provides-Extra: tests -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests' -Requires-Dist: hypothesis; extra == 'tests' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' -Requires-Dist: pympler; extra == 'tests' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' -Requires-Dist: pytest-xdist[psutil]; extra == 'tests' -Requires-Dist: pytest>=4.3.0; extra == 'tests' -Provides-Extra: tests-mypy -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' -Description-Content-Type: text/markdown - -

- - attrs - -

- - -*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). -[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020! - -Its main goal is to help you to write **concise** and **correct** software without slowing down your code. - - -## Sponsors - -*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). -Especially those generously supporting us at the *The Organization* tier and higher: - - - -

- - - - - - - - - - - -

- - - -

- Please consider joining them to help make attrs’s maintenance more sustainable! -

- - - -## Example - -*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: - - - -```pycon ->>> from attrs import asdict, define, make_class, Factory - ->>> @define -... class SomeClass: -... a_number: int = 42 -... list_of_numbers: list[int] = Factory(list) -... -... def hard_math(self, another_number): -... return self.a_number + sum(self.list_of_numbers) * another_number - - ->>> sc = SomeClass(1, [1, 2, 3]) ->>> sc -SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) - ->>> sc.hard_math(3) -19 ->>> sc == SomeClass(1, [1, 2, 3]) -True ->>> sc != SomeClass(2, [3, 2, 1]) -True - ->>> asdict(sc) -{'a_number': 1, 'list_of_numbers': [1, 2, 3]} - ->>> SomeClass() -SomeClass(a_number=42, list_of_numbers=[]) - ->>> C = make_class("C", ["a", "b"]) ->>> C("foo", "bar") -C(a='foo', b='bar') -``` - -After *declaring* your attributes, *attrs* gives you: - -- a concise and explicit overview of the class's attributes, -- a nice human-readable `__repr__`, -- equality-checking methods, -- an initializer, -- and much more, - -*without* writing dull boilerplate code again and again and *without* runtime performance penalties. - ---- - -This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. -The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. - -Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! - - -### Hate Type Annotations!? - -No problem! -Types are entirely **optional** with *attrs*. -Simply assign `attrs.field()` to the attributes instead of annotating them with types: - -```python -from attrs import define, field - -@define -class SomeClass: - a_number = field(default=42) - list_of_numbers = field(factory=list) -``` - - -## Data Classes - -On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). -In practice it does a lot more and is more flexible. -For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. - -For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. - - -## Project Information - -- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) -- [**Documentation**](https://www.attrs.org/) -- [**PyPI**](https://pypi.org/project/attrs/) -- [**Source Code**](https://github.com/python-attrs/attrs) -- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) -- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) -- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) - - -### *attrs* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. - -## Release Information - -### Changes - -- Restore support for generator-based `field_transformer`s. - [#1417](https://github.com/python-attrs/attrs/issues/1417) - - - ---- - -[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/RECORD deleted file mode 100644 index c4d22c8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/RECORD +++ /dev/null @@ -1,35 +0,0 @@ -attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 -attr/__init__.pyi,sha256=QIXnnHPoucmDWkbpNsWTP-cgJ1bn8le7DjyRa_wYdew,11281 -attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 -attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 -attr/_compat.py,sha256=4hlXbWhdDjQCDK6FKF1EgnZ3POiHgtpp54qE0nxaGHg,2704 -attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 -attr/_funcs.py,sha256=5-tUKJtp3h5El55EcDl6GWXFp68fT8D8U7uCRN6497I,15854 -attr/_make.py,sha256=lBUPPmxiA1BeHzB6OlHoCEh--tVvM1ozXO8eXOa6g4c,96664 -attr/_next_gen.py,sha256=7FRkbtl_N017SuBhf_Vw3mw2c2pGZhtCGOzadgz7tp4,24395 -attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 -attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121 -attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 -attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 -attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 -attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977 -attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 -attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 -attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 -attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 -attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 -attr/validators.py,sha256=WaB1HLAHHqRHWsrv_K9H-sJ7ESil3H3Cmv2d8TtVZx4,20046 -attr/validators.pyi,sha256=s2WhKPqskxbsckJfKk8zOuuB088GfgpyxcCYSNFLqNU,2603 -attrs/__init__.py,sha256=qeQJZ4O08yczSn840v9bYOaZyRE81WsVi-QCrY3krCU,1107 -attrs/__init__.pyi,sha256=nZmInocjM7tHV4AQw0vxO_fo6oJjL_PonlV9zKKW8DY,7931 -attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 -attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 -attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 -attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 -attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 -attrs-25.3.0.dist-info/METADATA,sha256=W38cREj7s1wqNf1fg4hVwZmL1xh0AdSp4IhtTMROinw,10993 -attrs-25.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -attrs-25.3.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 -attrs-25.3.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE b/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE deleted file mode 100644 index 2bd6453..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack and the attrs contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/__init__.py b/extensions/.local/lib/python3.11/site-packages/attrs/__init__.py deleted file mode 100644 index e8023ff..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr import ( - NOTHING, - Attribute, - AttrsInstance, - Converter, - Factory, - NothingType, - _make_getattr, - assoc, - cmp_using, - define, - evolve, - field, - fields, - fields_dict, - frozen, - has, - make_class, - mutable, - resolve_types, - validate, -) -from attr._next_gen import asdict, astuple - -from . import converters, exceptions, filters, setters, validators - - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "__author__", - "__copyright__", - "__description__", - "__doc__", - "__email__", - "__license__", - "__title__", - "__url__", - "__version__", - "__version_info__", - "asdict", - "assoc", - "astuple", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "has", - "make_class", - "mutable", - "resolve_types", - "setters", - "validate", - "validators", -] - -__getattr__ = _make_getattr(__name__) diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/__init__.pyi b/extensions/.local/lib/python3.11/site-packages/attrs/__init__.pyi deleted file mode 100644 index 648fa7a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/__init__.pyi +++ /dev/null @@ -1,263 +0,0 @@ -import sys - -from typing import ( - Any, - Callable, - Mapping, - Sequence, - overload, - TypeVar, -) - -# Because we need to type our own stuff, we have to make everything from -# attr explicitly public too. -from attr import __author__ as __author__ -from attr import __copyright__ as __copyright__ -from attr import __description__ as __description__ -from attr import __email__ as __email__ -from attr import __license__ as __license__ -from attr import __title__ as __title__ -from attr import __url__ as __url__ -from attr import __version__ as __version__ -from attr import __version_info__ as __version_info__ -from attr import assoc as assoc -from attr import Attribute as Attribute -from attr import AttrsInstance as AttrsInstance -from attr import cmp_using as cmp_using -from attr import converters as converters -from attr import Converter as Converter -from attr import evolve as evolve -from attr import exceptions as exceptions -from attr import Factory as Factory -from attr import fields as fields -from attr import fields_dict as fields_dict -from attr import filters as filters -from attr import has as has -from attr import make_class as make_class -from attr import NOTHING as NOTHING -from attr import resolve_types as resolve_types -from attr import setters as setters -from attr import validate as validate -from attr import validators as validators -from attr import attrib, asdict as asdict, astuple as astuple -from attr import NothingType as NothingType - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_EqOrderType = bool | Callable[[Any], Any] -_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] -_CallableConverterType = Callable[[Any], Any] -_ConverterType = _CallableConverterType | Converter[Any, Any] -_ReprType = Callable[[Any], str] -_ReprArgType = bool | _ReprType -_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] -_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType -_FieldTransformer = Callable[ - [type, list["Attribute[Any]"]], list["Attribute[Any]"] -] -# FIXME: in reality, if multiple validators are passed they must be in a list -# or tuple, but those are invariant and so would prevent subtypes of -# _ValidatorType from working when passed in a list or tuple. -_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] - -@overload -def field( - *, - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def field( - *, - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def field( - *, - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def field( - *, - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -mutable = define - -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/converters.py b/extensions/.local/lib/python3.11/site-packages/attrs/converters.py deleted file mode 100644 index 7821f6c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/converters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.converters import * # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/exceptions.py b/extensions/.local/lib/python3.11/site-packages/attrs/exceptions.py deleted file mode 100644 index 3323f9d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/exceptions.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.exceptions import * # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/filters.py b/extensions/.local/lib/python3.11/site-packages/attrs/filters.py deleted file mode 100644 index 3080f48..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/filters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.filters import * # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/py.typed b/extensions/.local/lib/python3.11/site-packages/attrs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/setters.py b/extensions/.local/lib/python3.11/site-packages/attrs/setters.py deleted file mode 100644 index f3d73bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/setters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.setters import * # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/attrs/validators.py b/extensions/.local/lib/python3.11/site-packages/attrs/validators.py deleted file mode 100644 index 037e124..0000000 --- a/extensions/.local/lib/python3.11/site-packages/attrs/validators.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.validators import * # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/LICENSE deleted file mode 100644 index 6ddae98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013-2025 by the Babel Team, see AUTHORS for more information. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/METADATA deleted file mode 100644 index 8cdc846..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/METADATA +++ /dev/null @@ -1,54 +0,0 @@ -Metadata-Version: 2.2 -Name: babel -Version: 2.17.0 -Summary: Internationalization utilities -Home-page: https://babel.pocoo.org/ -Author: Armin Ronacher -Author-email: armin.ronacher@active-4.com -Maintainer: Aarni Koskela -Maintainer-email: akx@iki.fi -License: BSD-3-Clause -Project-URL: Source, https://github.com/python-babel/babel -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.8 -License-File: LICENSE -Requires-Dist: pytz>=2015.7; python_version < "3.9" -Provides-Extra: dev -Requires-Dist: tzdata; sys_platform == "win32" and extra == "dev" -Requires-Dist: backports.zoneinfo; python_version < "3.9" and extra == "dev" -Requires-Dist: freezegun~=1.0; extra == "dev" -Requires-Dist: jinja2>=3.0; extra == "dev" -Requires-Dist: pytest-cov; extra == "dev" -Requires-Dist: pytest>=6.0; extra == "dev" -Requires-Dist: pytz; extra == "dev" -Requires-Dist: setuptools; extra == "dev" -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: maintainer -Dynamic: maintainer-email -Dynamic: project-url -Dynamic: provides-extra -Dynamic: requires-dist -Dynamic: requires-python -Dynamic: summary - -A collection of tools for internationalizing Python applications. diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/RECORD deleted file mode 100644 index b088723..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/RECORD +++ /dev/null @@ -1,1103 +0,0 @@ -babel/__init__.py,sha256=Ow3KHphrtw4WSFK-FzacGR8JVX5JQZ1YCdfJKD8UYS0,882 -babel/core.py,sha256=QbuWyWBg4RJlYQ5Avg-ci71j4ZQ07VUGhhVxdI9y-Qo,45371 -babel/dates.py,sha256=fJCaifpved33Rf5T1thxxPG6d3MmPU99wnIO2RAA-mc,76378 -babel/global.dat,sha256=wRYHp_nSwZk6S1S0kn3g20zHAYm2vr7ThmvV7uqDqgM,459316 -babel/languages.py,sha256=2LDTV9WizAuZVam0vfw-Q-QKYCQpF5DxLbmVoat7TKI,2844 -babel/lists.py,sha256=Y4m1gScEDZlHAweDb-H5J6bEhlzTFmhKCWywS2h6V8M,4361 -babel/localedata.py,sha256=gzh3fMZIkA0k70eqXSRA46nbGWl-4BfQnB59czUmp7o,9116 -babel/numbers.py,sha256=GhjFEdksEkfmvPN7VjGjlptbtmVaboBZdRaB5zPMZvY,62758 -babel/plural.py,sha256=9NWPLtYleF8gsi23S9OIRth4WhND56E5fdFatwVb-uI,23112 -babel/py.typed,sha256=DtCsIDq6KOv2NOEdQjTbeMWJKRh6ZEL2E-6Mf1RLeMA,59 -babel/support.py,sha256=PLxaklxjez4pysEQ1n3rGbGMRKOPkOeszy73RZ1qctU,27516 -babel/units.py,sha256=K8CDi8z6u9envHjP1s2_TqDvVtbeg6zBN6QuksrtjIU,13753 -babel/util.py,sha256=gC2c7exKpi9yDALyoL4yGGW3S-BkADAZw9dIWXw95TM,9071 -babel/locale-data/LICENSE.unicode,sha256=tMCujvBPcFn5bOW74EZ_n-b22Bu-E1F3Ad_rlh-00LY,2033 -babel/locale-data/aa.dat,sha256=CI5kOVaXWX2CQoHT6AXhrOMwFPCiQyd7Wke2QBJ1UtE,2795 -babel/locale-data/aa_DJ.dat,sha256=VKjSgKVsftG91nj0-AQMYFuF_p4YAGfRkgAvycB2EYU,1112 -babel/locale-data/aa_ER.dat,sha256=6b6qROwoeOq0-batM1Z7Ji2gvGDogl3ODcftt1Jkm9g,637 -babel/locale-data/aa_ET.dat,sha256=piwFu94H7e-jPwd4ZaWiDc-j2nAH_GiC5UZ2IxMx7bs,635 -babel/locale-data/ab.dat,sha256=xeio1NLBNIAXcafnonWjO3w0zofwM-aKr0-RiaL7pRQ,95311 -babel/locale-data/ab_GE.dat,sha256=b5be2Uv1YtP-bkMasJMzoQPxJPNLFqifXnCiK8rCyLE,635 -babel/locale-data/af.dat,sha256=pO9_3BpJSQAJ3gZ_j6ZdUpGq3zqEv6CIZZ-CpJTXwr4,144732 -babel/locale-data/af_NA.dat,sha256=zif__TyNY44mSCYOCrrglsyr_H31JhBNPwSJftg8200,1450 -babel/locale-data/af_ZA.dat,sha256=6lT-mLg7LRtyAEhWhiF2xVtiPyzEa28U6hsFw_BMrZE,635 -babel/locale-data/agq.dat,sha256=JJbF6NFR9qwwQTrIyrLh04DFJniIqDuFsbmHDGu5ThM,16628 -babel/locale-data/agq_CM.dat,sha256=hYtg7pRw7J6TsYHvhlEEv7DqpyXoK3KS9DAqtYtgBX0,636 -babel/locale-data/ak.dat,sha256=L73y_ylhZy39SlEaAwA4jCqP_92qLvIlsagl-o2RlKE,116224 -babel/locale-data/ak_GH.dat,sha256=tM-OSpXWyBwZFfKPVStWBbFv3dwNj_7AqcBz4ONrOQs,616 -babel/locale-data/am.dat,sha256=TddfeRISFvzjTFpB-vH3gjSKs2r8iT3CYckrriibXZY,173260 -babel/locale-data/am_ET.dat,sha256=2VZDSh5bY9vLLuTqcKYG66p5OYlvPRPX58rpNTFWPok,635 -babel/locale-data/an.dat,sha256=a1gEztcqWoMLW3f5_jlDxcPsYY-ItHKVud7gjisrS4E,28050 -babel/locale-data/an_ES.dat,sha256=rQuq-zKj7-fCjY-5fGGoGJT1x60pAyCEAVEswXPnHrI,653 -babel/locale-data/ann.dat,sha256=fUenvOdPjqayLEiVDRNncK8SOBi9gAGAdxMuOATlsI0,737 -babel/locale-data/ann_NG.dat,sha256=0i2K6cv6eCurgFgwtiCr09hYwZCA1kHkQaKnDyCD86M,617 -babel/locale-data/apc.dat,sha256=G96W-ebLqQlTuPN3-VqSfAY-GF0K99c6uXHza5f4e2g,1564 -babel/locale-data/apc_SY.dat,sha256=tagFeQz8BA9Pc7RMqkce1ZalfKIBjqg0SR4NlpGQaaM,679 -babel/locale-data/ar.dat,sha256=yAijlkkaH-RgRQidvCyNBkpi9Z7OTC9cNfIbKo4n4gk,288582 -babel/locale-data/ar_001.dat,sha256=hRKDI3wzxO5T191MfSdCn_MZ6ckM2Rz_r__0JZqS00s,1707 -babel/locale-data/ar_AE.dat,sha256=hEbIYUoNE5mRLOVXhmkGsvT0NAcq-rxs51VIMMzG9LY,982 -babel/locale-data/ar_BH.dat,sha256=FoQ2c3E3TDqKcioarWBvLi_MllJmSd_56r0U45_gHWw,720 -babel/locale-data/ar_DJ.dat,sha256=qbNam_QAmhobsIUfJLCL9pe146SvcmNIE_L3cWpmkBs,698 -babel/locale-data/ar_DZ.dat,sha256=_Y-JLC5hincnxze7sGmEpb7N4JnBh7LdFdaVPcSMDvM,1263 -babel/locale-data/ar_EG.dat,sha256=qE3gLQ6BzLaBOPNJVgaBhPQiIL2kQ4AiD_jLl7o52IM,720 -babel/locale-data/ar_EH.dat,sha256=a0xJdGJYzGFzfvwxZVDP7yURlTm93FQSTQ5qp3XDMYo,658 -babel/locale-data/ar_ER.dat,sha256=l-WjJfxm7kP05-Hnr5PingHaKWJ46ScfW4KEBcwD5HM,679 -babel/locale-data/ar_IL.dat,sha256=O3UYAjf4BB3NdcSQTn-RzNjyj4kzTBhX3q7E8-9Aihw,1264 -babel/locale-data/ar_IQ.dat,sha256=7-DnoHqsoBDe-ZXe0rIcEotb-F_CFyChc73dwnXuUoE,1975 -babel/locale-data/ar_JO.dat,sha256=hT1z-Me5SOjul3BHFubcqlyEk9H57fwD4EFENddiVt8,1398 -babel/locale-data/ar_KM.dat,sha256=Zx5XtfTuRPiW6iViOjeal_Fq-18EA7GuERViMP1_mc4,1230 -babel/locale-data/ar_KW.dat,sha256=1wSXHTcgFKwhNciVS8IvGKvkzzqOIMBFykEJEQXdhEE,720 -babel/locale-data/ar_LB.dat,sha256=-SuXO6LdhXNi4f_PHNrlxl8iXX47perQ_oS19bwRGpI,1414 -babel/locale-data/ar_LY.dat,sha256=2OxSGD1gkiWPcaRHd1qQv9ifG82WEjGahKqhsoFXfnY,1249 -babel/locale-data/ar_MA.dat,sha256=hTOwsXC8tsJxBVlksxmAMlIkn4kK50juJa6TuAPFkp0,1559 -babel/locale-data/ar_MR.dat,sha256=Kq7uT5LxvYXnGWz-cVcI6yDNximu9hZIpoKydmVse78,1359 -babel/locale-data/ar_OM.dat,sha256=HVOqTfoH3JVTHJL-yDBiIafNfckU7CIcO_sIzXBffKw,720 -babel/locale-data/ar_PS.dat,sha256=F-HZRPcMe_tJ8r9V01h-7mQ0UKQxQmuWuXNSi94MVMM,1336 -babel/locale-data/ar_QA.dat,sha256=UKfLpyX856fNgeifdr22wXpDncirWJi9NxqfSnS-7fw,720 -babel/locale-data/ar_SA.dat,sha256=8WE8HwCwO-OT_G2JBSgmPWSzyHOdIA3zajXPbBZr2Tg,24787 -babel/locale-data/ar_SD.dat,sha256=f7aUKlrKmmC7ijTjVwn5r9m3mfZfEob1a7GHVCj4Qxk,720 -babel/locale-data/ar_SO.dat,sha256=4LD_gds2VsvxdFHpFo56CxTFenzNdvEkMofc4oTGBTU,677 -babel/locale-data/ar_SS.dat,sha256=T6eeWPeFejmBC7InKqg-6qmWoer1vjl6srHe_5ybkDU,700 -babel/locale-data/ar_SY.dat,sha256=u42uhje_zt806WlUMpp5sIdi1yjw3Yv7vYbl6aELsyc,1398 -babel/locale-data/ar_TD.dat,sha256=OG7NYtRrJiDeRt7HP-B4ta5ri-6fdSnYomppfy2A4ec,658 -babel/locale-data/ar_TN.dat,sha256=xO974NyO5T-pRs-5b55sfQFGIwU2Y4q3VQUeqtqWf80,1201 -babel/locale-data/ar_YE.dat,sha256=vu8wYJgzcJ1douKfKLx3-hAg1sjndD5_PTHWG_bzRL0,720 -babel/locale-data/arn.dat,sha256=JB-QfwCOVQbVrLRlq2LMxU6SHO-V4ZaU2_0W15-0Rfs,721 -babel/locale-data/arn_CL.dat,sha256=cf_JrdIAxFwbltVwtloNC9527Du7zaoBDM-_KmctSvE,636 -babel/locale-data/as.dat,sha256=xoTmhieoAVjw59h2-_pLp0wjfZPVvYMV6qDSJjLrjq8,209876 -babel/locale-data/as_IN.dat,sha256=bE-OZ0Y3d2-QtD23ztjluSsFk1_RFNYMFzKgBC3waw4,658 -babel/locale-data/asa.dat,sha256=zzPu7L8RV8SVEKqeRiGIoWLBCJkeS0acDh0pYq87qMI,15492 -babel/locale-data/asa_TZ.dat,sha256=U0GU10aP58LxCeqyjl69RQCZi_6tTQxm2vni6XVkoqY,617 -babel/locale-data/ast.dat,sha256=_Qeoc0gz1ag9MkmNIuv4ufVjk0fH5xtW4M7vp8ST4hY,168961 -babel/locale-data/ast_ES.dat,sha256=51kFxigV5COuiPiNisp-OBFYMith5rUgBmU48rGk7Hc,654 -babel/locale-data/az.dat,sha256=2EcwMc8qIqCW_F0Ic2XjFQthkCGyfLNzJzJZU99ZcaA,173802 -babel/locale-data/az_Arab.dat,sha256=IGBla73oKavlLHhtIW37idHxTkmQWZ-S8NE54b65d4k,7499 -babel/locale-data/az_Arab_IQ.dat,sha256=VsM0-KQPCP4MUw-2wMsBv-F467cr2Bup3jfxx8Fc3ZE,678 -babel/locale-data/az_Arab_IR.dat,sha256=ROb0gFTPwK5CcjpQMB7CJ662eld9sZj7IA6QMrvxgto,678 -babel/locale-data/az_Arab_TR.dat,sha256=EV6cNf3keBNREHkfF98GGZGOZz4L5dxf8pFbujInaQY,635 -babel/locale-data/az_Cyrl.dat,sha256=ru4QYee174toLQsGPJn-d6xe65FsLQ87vBV9AW0o4D8,35540 -babel/locale-data/az_Cyrl_AZ.dat,sha256=GRZjR-gp6JYeLNxoiAKNdv9bkTmS1bpYnRJ0c9YIGws,635 -babel/locale-data/az_Latn.dat,sha256=aK2ziytg5Ig6GYk9tVCq4BEyV6UYy9Ip7F1_i4Pq1jw,2258 -babel/locale-data/az_Latn_AZ.dat,sha256=GRZjR-gp6JYeLNxoiAKNdv9bkTmS1bpYnRJ0c9YIGws,635 -babel/locale-data/ba.dat,sha256=Ly1V4wBNM4KCDGtuy9oCug4fZzVNEFqXOI8XKhkWFOQ,732 -babel/locale-data/ba_RU.dat,sha256=8YcwUOx3h4BcSfUIumKJ4wcFyiSgBM74SqenVIQUKi8,653 -babel/locale-data/bal.dat,sha256=mYMTNzej_lac3GimNq9dYgLY3Q4RtXpEvUkQ-zfzVqw,12849 -babel/locale-data/bal_Arab.dat,sha256=25CVl5rF7FqKEeHzAmt0BccVI_ODqmMP86KqQ4i6PL8,934 -babel/locale-data/bal_Arab_PK.dat,sha256=sy4tpUtN1St5yFoTp8C6-vi2bFGPjSaG_zDbY16Q988,636 -babel/locale-data/bal_Latn.dat,sha256=X9sEvC7SU0VUFnapzFKUq0nvc1az1c9lHmrCPHPCg4U,116909 -babel/locale-data/bal_Latn_PK.dat,sha256=sy4tpUtN1St5yFoTp8C6-vi2bFGPjSaG_zDbY16Q988,636 -babel/locale-data/bas.dat,sha256=hts2-gooZheGxndoyiVM9NwFrAitthfb4IPr7TtYb2U,16673 -babel/locale-data/bas_CM.dat,sha256=WBq-_rOvkBnT5pBaCyq844LLSRReQzg2HM0u7GmhKKM,636 -babel/locale-data/be.dat,sha256=8L6Q0C4wjbLMC9I7ltFoY1prATuRd-8nn0udprYBI6A,272322 -babel/locale-data/be_BY.dat,sha256=yN4Rf2-HqinMscTfe4jKEYpsCEaddHce6K25ol595Ag,635 -babel/locale-data/be_TARASK.dat,sha256=93xDxO06nuAugpWjrnx6C5k8Fs26HIAolUcUPuoHhbg,104118 -babel/locale-data/bem.dat,sha256=zBh5HxY-hRgaQd95anmqMAPP0UVzSV7JdcuqtJ78t1c,5782 -babel/locale-data/bem_ZM.dat,sha256=nQvsLK0FOSlgf6wspQdbj00IveO62c2Mvxjzn4eHGSs,617 -babel/locale-data/bew.dat,sha256=mfKR23PSPyS0AHxbaSuMvufZZQlMICxDGuPv78MtDbU,122095 -babel/locale-data/bew_ID.dat,sha256=JWKbnUQc4ZsJYTcBFypK3gSyFRK6Kp8UFEqdytnPMnM,636 -babel/locale-data/bez.dat,sha256=_saESrmbxsbQnGLACykFIs-aLUC-N7IigpyPWGLBebI,16300 -babel/locale-data/bez_TZ.dat,sha256=OwcKelhUxQWu-8Jm9nf2vCay6-8LQvg-ueZSN_mrGz0,617 -babel/locale-data/bg.dat,sha256=ofd_Tv4onIP1cE1pVO-171ySR9JJXuHKzpWqc-vtLP8,227940 -babel/locale-data/bg_BG.dat,sha256=CERFyuC4Dw9BfAZapqaq69iKAp7rBXWNCkLWAL5tAhQ,653 -babel/locale-data/bgc.dat,sha256=gW0lkQNX_h1SATbqzIqe0twmGqqfigkbqo7gvBCG1AI,2493 -babel/locale-data/bgc_IN.dat,sha256=hO39nPiyUx1kfCdagpCQ8lzPLycjdfk59jFQgsd3Qec,659 -babel/locale-data/bgn.dat,sha256=8RKzmGYGYkn5IF7NHRgPtaI9ozwCeEKoUE4aXQpItKY,28964 -babel/locale-data/bgn_AE.dat,sha256=5jo7AWXMNdiiEf-RqzB5xRVj0R89NFdwq5RAIEAeeRE,636 -babel/locale-data/bgn_AF.dat,sha256=UXCb78n57adZBdKHEGnhbmeVYppzlSscVOWnQNxfJOQ,679 -babel/locale-data/bgn_IR.dat,sha256=iXxyPD5Z-ouDWFpOE2atoi6-HHGoD6PNaT9c-TH6x7o,679 -babel/locale-data/bgn_OM.dat,sha256=3O0CzFrjWxOQFdN6-lDhCxRngoXfadd_dwYoVyjK9jA,679 -babel/locale-data/bgn_PK.dat,sha256=gdVUcc-isHd9lf0S-AmFoPIMwDZ8ay6NY4o1udWI6Yo,636 -babel/locale-data/bho.dat,sha256=JQAEhmajFwUOKB7ACN1-ZPcoKcXJaq0-FhsFCVcvn_8,2875 -babel/locale-data/bho_IN.dat,sha256=UcL_aZq35dOHME0Fux9zyt9B6BOTxyR5UvaGWKLs1jE,659 -babel/locale-data/blo.dat,sha256=I0gfsGv80xf7do-oxzjkh2or934YxYgDMkM9RHf7UXk,168499 -babel/locale-data/blo_BJ.dat,sha256=LM79oUzVI4JtLYEUklfbQxoweFAslN9jS-Ex-dya0mE,617 -babel/locale-data/blt.dat,sha256=6G2E9osBy9OrG1iUKLD9cwcRk3IV7fT11iI8zFkLaeo,723 -babel/locale-data/blt_VN.dat,sha256=vpTQEJYssmuBUn_pYqx7ZtYONNNz02_oBYlDMdWqKAc,636 -babel/locale-data/bm.dat,sha256=K0dLlxoDfJb4QLwa_D0SXfrbD53Xed_EJ21843fY9hY,15798 -babel/locale-data/bm_ML.dat,sha256=PAGrUwc1S6q32DDHTu5LkePFXe_M_i_WxIY4oLuUnzw,616 -babel/locale-data/bm_Nkoo.dat,sha256=UiQ-oKSXYmbnUj9nNXi-9Afx2taBc5EiN-JM1huGOno,2805 -babel/locale-data/bm_Nkoo_ML.dat,sha256=PAGrUwc1S6q32DDHTu5LkePFXe_M_i_WxIY4oLuUnzw,616 -babel/locale-data/bn.dat,sha256=00cRKYrwyk5snhrekLj0TQBVzZlV_PjQ0aLlsApgwxw,219185 -babel/locale-data/bn_BD.dat,sha256=mVW90kQmhDcwzKmkmgNAt5iMq1pLWmNndNID9fspVjY,635 -babel/locale-data/bn_IN.dat,sha256=Y4d5tMv6rG2A1fTcfN7-cMeZ1iH8XuqdZgpEBUy_FTg,4035 -babel/locale-data/bo.dat,sha256=2eVqnOFPv04Ix-1FVPHlDQ9UVTQC1JtC7-5lQ89aX7A,20102 -babel/locale-data/bo_CN.dat,sha256=xOnyre81Z1IHnWV5mJH0x313h-ZWu84hIXcMuB50IT0,635 -babel/locale-data/bo_IN.dat,sha256=GvYCgtrOD5zYYsfMtVmkCv8-y6His8Lg7iuytEGjnMI,1307 -babel/locale-data/br.dat,sha256=rBs1Bp9H6Q4ECO2mouoJmnCW0ux5CLPx1zy32GvpkCo,272612 -babel/locale-data/br_FR.dat,sha256=3oVDdZd7Xf4Q-hwmYraF42SM_3NtvSoiZlmlh6gSNOs,653 -babel/locale-data/brx.dat,sha256=0L8rfQwjwtj3y5M5zzdEB10way4I9P2m8A2E0mTIcac,160164 -babel/locale-data/brx_IN.dat,sha256=NKuJh0cEhRQasy6JAGUi5HbqdnhhEFTQ_7osgtdG5Iw,659 -babel/locale-data/bs.dat,sha256=YVLbXGLHf6QZ9vYnCjxjO3uBImuYnoxR-cEuBPVbP_w,213968 -babel/locale-data/bs_Cyrl.dat,sha256=oqFwEFFfYqyzkVvswj8CR2B_RCb51Myv8jQaDDjz0u8,219235 -babel/locale-data/bs_Cyrl_BA.dat,sha256=oA7rsQckE_IxCpXXB3F3KWQwM3WZTR7WAdYxJN98oeM,635 -babel/locale-data/bs_Latn.dat,sha256=6L9SY85hONRHO4Jz389C2Ziy7llKcDoyVNiE96ozCJ8,1990 -babel/locale-data/bs_Latn_BA.dat,sha256=oA7rsQckE_IxCpXXB3F3KWQwM3WZTR7WAdYxJN98oeM,635 -babel/locale-data/bss.dat,sha256=n9LaBwBIJ7adjJ63G7Q9o00llhPJtkgmeEp08nAa4D4,978 -babel/locale-data/bss_CM.dat,sha256=TD7ixCHREfOLDsDJn8FY5YqGYH9czdEzdULCIl_0GhM,636 -babel/locale-data/byn.dat,sha256=qT32E4jh6H_qm7HYSsAbKmaKluaLrGNXNl3F3FivncE,13403 -babel/locale-data/byn_ER.dat,sha256=oAaZEqMJuTbMITO-ZO6gg8qjwROukzh5VgjtLp6rqD4,617 -babel/locale-data/ca.dat,sha256=CIT0-7X7_e8RKWRrhLSmG-aBC2D51-hvRrTV-7iBav8,184038 -babel/locale-data/ca_AD.dat,sha256=tsLumbhbbeXw627WKi-sQdSTFwNpcSRvJIEYcrOMqOM,653 -babel/locale-data/ca_ES.dat,sha256=T-zv3FfnCJA2WUQTeBADKV82ghY-r60wk8mXtD9wbnI,653 -babel/locale-data/ca_ES_VALENCIA.dat,sha256=7Q59_PX0VWyLsDkC-qscZ-dKJ9AFzz7kCzJz4fTdBWY,2976 -babel/locale-data/ca_FR.dat,sha256=5HUFYUl5QRaUMwJxGLIqUhDO4_wF_crrr346wJmEOZo,672 -babel/locale-data/ca_IT.dat,sha256=Zh2rtOq8MIDC2CQXWnhp5HOvPfXNxhRGnnZViOgc1Mg,653 -babel/locale-data/cad.dat,sha256=XxlMk1b9CWE3wERhhQQN0wxW7iq8Mrngb05RXenmaSI,2476 -babel/locale-data/cad_US.dat,sha256=FWV1sofgr9no5P9yBxNDLeKWoQd80XEYEilmLwamkSc,654 -babel/locale-data/cch.dat,sha256=J4S73psT7C_cXs1VNNYow47plBodQ4PKINC59kzvfAw,2430 -babel/locale-data/cch_NG.dat,sha256=0adhw9xNMlVEqDVKvHe4HCPtbjcw5NSo4ny_pOjl0-4,617 -babel/locale-data/ccp.dat,sha256=Jn_O5MwN6DMGxNrXUpdrhT_z5ZOYh3-Sm5yGUcV8bII,207292 -babel/locale-data/ccp_BD.dat,sha256=f00776fnI484B-mzW0rY22KNkzV6wtmk7uxrSK_x9bU,636 -babel/locale-data/ccp_IN.dat,sha256=jMJimrQrx-b96hBSLi8sOyHtYRwNZryt-he0rhwEZ2s,659 -babel/locale-data/ce.dat,sha256=yuopW5QCq1u8E1Rs0hEOv_y1uvbem_P3lK-_AvU5zLE,135403 -babel/locale-data/ce_RU.dat,sha256=NgNmp1uFnm2MT-s_yx_V8KuW1dSR6_SEWf4NcqrAL9o,653 -babel/locale-data/ceb.dat,sha256=fwgJPAV6TfvyavZUW-9pKeLUacMuH03hCkSkHdIGm8I,100779 -babel/locale-data/ceb_PH.dat,sha256=Z2zXPyNI3Yu3QcGL6lT1nIsl04vDDLFvyd9GeucDtqA,636 -babel/locale-data/cgg.dat,sha256=vgLxp4dDUjKyHy-36IvfaPEy6IiXbDiMKShuEKJuXHU,15621 -babel/locale-data/cgg_UG.dat,sha256=HZBma4MFuX2Q7sk-SOYk5OUkbMXWWr_tEInOqPboNYs,640 -babel/locale-data/cho.dat,sha256=hWEL5XrIWAnqjYSb78iPaj2xh34KDcPYAMc46S7ZLuU,795 -babel/locale-data/cho_US.dat,sha256=T3CacgkE-uKPi0CV7fbcCLTNfdjEco_A50vYciuXGGI,654 -babel/locale-data/chr.dat,sha256=4a6eJjX1JZ-inCk-J8gHJq1QtoK3FpOXhOlQMDbHjwM,187187 -babel/locale-data/chr_US.dat,sha256=wZE2RrJ-5jjUQa1RCJgL7hkXdsU3t91orD-ULDYMXSM,654 -babel/locale-data/cic.dat,sha256=KgrmFl1fudc1tdR_g39YkGR6bcIedQMFnUjh831VIhM,2732 -babel/locale-data/cic_US.dat,sha256=DvW1XJS1hEp_W_5ol0pIECeUb3RqXsyieKVS8J6caJ4,654 -babel/locale-data/ckb.dat,sha256=s6wh2TRjabPo4G64RMoQD_J7FK77RBwsK8R0TH1xytI,35553 -babel/locale-data/ckb_IQ.dat,sha256=Osgu1RAUf2yQpZ-nNBKMxTFJnH32ItLg0kVVzjNfmeo,679 -babel/locale-data/ckb_IR.dat,sha256=6wWzlZWn7oDmGIdnF7UtCfIcUgQ1zvMxtAcEw4bbM-g,1231 -babel/locale-data/co.dat,sha256=NbKZ99wTpG7Y64LnyxTQJIo5SYQaUAOybc68DN6IbUY,12637 -babel/locale-data/co_FR.dat,sha256=DAmwXn4n1mRSsT17-DcU0vdVSI_JfVR8oGOnj7hTFHk,653 -babel/locale-data/cs.dat,sha256=o7qnhuIqxpPIfD-oyVLsvpmhtRiIOzgJBoMaZvyvPL4,247800 -babel/locale-data/cs_CZ.dat,sha256=keaiqSsGtB_axj8FvdYDOCDmlg2PbQMI6qnW-2mFUTY,653 -babel/locale-data/csw.dat,sha256=a31wJpIkcegvNW9_O8LfIY4-HK0zpLn4MBUEBb9C3PQ,20303 -babel/locale-data/csw_CA.dat,sha256=aWccZHGNU7G4JJdlGRnqyqm0ROubX0rwI9SnH_EhAxU,636 -babel/locale-data/cu.dat,sha256=mlGQkibxBcukKPAJawHruBMuw21x1j42ebTnraxW55w,16865 -babel/locale-data/cu_RU.dat,sha256=GcbqgE8Mlglk5EGGSVcCR-Zb8AmCqHGE8cbmAUSbpdY,653 -babel/locale-data/cv.dat,sha256=BUqS-4RvAuycOlAm_k33eV98VCp5bIUmrWUqjhmsqls,198348 -babel/locale-data/cv_RU.dat,sha256=oVPRtcHzmRmkAy26Bv1jLiWmm0P18ruvHlCQ5F3IFY4,653 -babel/locale-data/cy.dat,sha256=-bN00WqRhdnCL9VdnGgtUtwbmZ7n2r96oZdLuxSP8KM,276313 -babel/locale-data/cy_GB.dat,sha256=dyPULIteKk9gP7lGQiDtsiH5QDqNdlxMdK__2dq90dg,653 -babel/locale-data/da.dat,sha256=VUVxNljiubvj3e_PhimeMLBVZlAt1GT2bAfnyYu671E,171756 -babel/locale-data/da_DK.dat,sha256=qNTw1H8WXsV8qGBHxu6noCUOV3BcoR63ERJF8Xc86Ls,653 -babel/locale-data/da_GL.dat,sha256=9BNeKX1-U4NDr3pBU1ZnCGAasdYZjBMsvpdS5uTf9qs,616 -babel/locale-data/dav.dat,sha256=LBf1uH_Q7632sBVhZgQSrdn5LU2pyIU389h4LircJM4,15690 -babel/locale-data/dav_KE.dat,sha256=MfFFEDT6fib5be-EmziiEF0NAnEV6lXD7svYtHUtmn0,636 -babel/locale-data/de.dat,sha256=l6ABVg2zXPX9Ws9g2-Weve05S46ii0hnbuCViS6mtmA,178630 -babel/locale-data/de_AT.dat,sha256=OhoRvklFcyYUJXplBoK2rAITKRi6r81lwOaixIuffcA,2010 -babel/locale-data/de_BE.dat,sha256=wvdWykhix9Slofcjm2tx2aEhMjffmMLsNrd8709NIR0,653 -babel/locale-data/de_CH.dat,sha256=PH2rDxHA3lpTBkPMCwWjapEDJtgrkHhq2_pAdSKSiXE,4091 -babel/locale-data/de_DE.dat,sha256=SM44YjGlqgh7bKlXvUdt53t9hnCX5o46ujI4IrGPpeI,653 -babel/locale-data/de_IT.dat,sha256=ALPY2QGlR9-kphEk4KggHVS51fQwEDVRd7aHLIiP9fw,1448 -babel/locale-data/de_LI.dat,sha256=FnGRiippDTTFRFswU_4PblQruAuWuPEpa8cGbXPJpbE,1413 -babel/locale-data/de_LU.dat,sha256=QAkvLfyKmZdQVfkk2BbE2AMisK1i7yhRetcApqn4dxA,1067 -babel/locale-data/dje.dat,sha256=6NxQgBas9S5kmjbRcbcuuIIxKaI5_MlfmSUltxJuraY,15530 -babel/locale-data/dje_NE.dat,sha256=lU1vag_HJ4OrbYNYWFXuSdtqLwSlwBbvD6Tg-hl36e4,617 -babel/locale-data/doi.dat,sha256=JrHDjsVlGntLL6qYf9NH52BWAGCSGeGVaHg_rgUiGkM,47442 -babel/locale-data/doi_IN.dat,sha256=-q_oAqvdTizFG1DB_1p8sZVyjbaFFQ_FFPtNCyVn9ZA,659 -babel/locale-data/dsb.dat,sha256=KvZxymKZ5ZbxQ-4gS_uvnNkrYMYn3D-BKz0MGAn5488,203926 -babel/locale-data/dsb_DE.dat,sha256=Z2Dzjx7eXscEBEAb-ymvb1GKP4GVNCt5L4i-BYC_vrE,654 -babel/locale-data/dua.dat,sha256=lmO8ssPF9bIgTU2SM_SzrGWodmsGsmbS485uZNDasq4,4827 -babel/locale-data/dua_CM.dat,sha256=Z3vD8WEr2Wlqqt39anvKXVhz4_yBSm4t5BoAaEz9PgE,636 -babel/locale-data/dv.dat,sha256=-1zCv4GXiRHdWjQk0qXWNPSf4FX4Zp-Ij2jwgz5BsGk,2225 -babel/locale-data/dv_MV.dat,sha256=lvuU5gj3vDykU2ftU1_4Lza-130DB6_ZwylDrdb_GlY,635 -babel/locale-data/dyo.dat,sha256=w71HDmFfCuKN9nUJnuqpHR9DDAmPLkwIu9E0abhYjWM,9854 -babel/locale-data/dyo_SN.dat,sha256=Z6N-NIVcKkx6sFUm8LfN74usyZfgeI6swJL_A_XbBcc,617 -babel/locale-data/dz.dat,sha256=dbPhCcTpoQh6szaBA4TN5eCi3sbG1UBvlQQxtMGHLEU,85026 -babel/locale-data/dz_BT.dat,sha256=KWd6cypWse4XfXbY4BmTlxGjlnRksYNcQYi_iyXluKw,635 -babel/locale-data/ebu.dat,sha256=S8bggVknCbVHw5x9aJQGB9kUBFNcwj9EONHRNtbaWCA,15583 -babel/locale-data/ebu_KE.dat,sha256=GEcGqVmH0WwgP1BCsd9vnSGxGXl8ON4UPTRbyeaNDfw,636 -babel/locale-data/ee.dat,sha256=xJ5vpKJa546rTvKKQI75-HvYmu6VjEedXENlPSeDgCg,88730 -babel/locale-data/ee_GH.dat,sha256=SkQi-aVmtqi3S99DUTLQzZqUE4LrAIWuy25QuZqYAfI,616 -babel/locale-data/ee_TG.dat,sha256=7y8-rDvag7_EQtEObq3fpHaRedVmuEREnQwjktmLwgk,1168 -babel/locale-data/el.dat,sha256=pMPkYRvK3y4IF93Z-127ZF_-_P_QV-_460LgZAHCw9o,247970 -babel/locale-data/el_CY.dat,sha256=POPjzTYMuP7Ijf1S88cAFR0ge9Id_sSRNembKdhk2aE,635 -babel/locale-data/el_GR.dat,sha256=S32Cm-1ENgLL_lDecCDI4qDfyd3wlQ1JbUwOnW1whm8,653 -babel/locale-data/el_POLYTON.dat,sha256=lkcs2uXW6mWXztmsAXnapnSuQ6gkns1WwsVgrg-24Uo,14964 -babel/locale-data/en.dat,sha256=C0EMuCmMqd7xbacUUkDzM6xvzhEWWQgbd0sIPvX5QbA,217633 -babel/locale-data/en_001.dat,sha256=X7NFTy08b5AyR9I6BDy79hP3x_nq018WoQmMSzR5S1U,31614 -babel/locale-data/en_150.dat,sha256=cjKCV1ZLhNY4TvqJF8BXvQR1jVUBFrdjL1RKSnBa0vc,1851 -babel/locale-data/en_AE.dat,sha256=T2jBGVJpPTUgTICdaQnAVjSsYCVkQLfjabyStaPl2CU,4164 -babel/locale-data/en_AG.dat,sha256=POWSM98pRq9k7lqCsxr-MS9PA-zLoOVUKUcI9iXtKq4,654 -babel/locale-data/en_AI.dat,sha256=7iwWKftqPdOdWJ7v94jsre2ZIq2cDpbVGAs_ScBztbs,1206 -babel/locale-data/en_AS.dat,sha256=M-N7v6BuP47wkTFmv5by1w42IQCUiSqKbaVTXtnwF8Q,635 -babel/locale-data/en_AT.dat,sha256=05-bVy1aMFWZlHMBC86A7OVy1zlhJw7hsjyvIOjxE70,1309 -babel/locale-data/en_AU.dat,sha256=kEhWopkI0vkAChxsUmnaAX4htgJ36t9hiVtaS6t5Gvk,20023 -babel/locale-data/en_BB.dat,sha256=J8vppKlBp03jJvVuVp6Z4GMc_N0BukeQ8f8q14y8fwU,635 -babel/locale-data/en_BE.dat,sha256=0JXHgqUIWZYe88FYC97spm2TqyIaNOwDJBt3LBmUF7A,1547 -babel/locale-data/en_BI.dat,sha256=AbdI5FjEqQLOMbBtD3wLW_7AccuOwY9MZUFpMF1uEco,1189 -babel/locale-data/en_BM.dat,sha256=cZE8sxf44ETY6nCxOgbvJN2RhABZrRaP8SjwsbSepuE,654 -babel/locale-data/en_BS.dat,sha256=sGvlF2LPwG5eVA3IuH8-4S5X7BrvQ5LcgZ8gfAkkwwc,752 -babel/locale-data/en_BW.dat,sha256=k5bc9gYBdl_8ZyCelrlS9ZenMzs8cdfl2MxeCnOAr88,2850 -babel/locale-data/en_BZ.dat,sha256=LJsn2M0RWMbxDmGRxs2lk2ZvkgoguwPf7oLBYQydU4A,2979 -babel/locale-data/en_CA.dat,sha256=za7pG-TGpows2k_XJL8dpzLVs1oOSMKN3zwyG79OAqI,37924 -babel/locale-data/en_CC.dat,sha256=34a3Vb57hT2reRvwn0Ud1nXkoYQJoPmaqh1n5qflFdI,1187 -babel/locale-data/en_CH.dat,sha256=Nfkwk2HNOccSH8Co5SWYnFdHWEDEpKNPQ2o9a67vt_k,1866 -babel/locale-data/en_CK.dat,sha256=gvU21BSAugpjE7CT3xnpHML6oRgHPaBoq7W11YbG-1U,1187 -babel/locale-data/en_CM.dat,sha256=r_7Yzep6S0ZOFvk_TORm5Qhi55yjehVQAotaLnn7igQ,1437 -babel/locale-data/en_CX.dat,sha256=lKYbIRS6r-WMUd1ewX7Q4TpX0PBVcsYN7Cs263_xosM,1187 -babel/locale-data/en_CY.dat,sha256=kQZfhQdPfdBeePOngn-4CpA3ZJ7Th-lmZ-jOrBe115o,635 -babel/locale-data/en_DE.dat,sha256=oI3TmMDoQZsGddvDb0fbbwd_LdTeFbFPdFkZhst2q7Y,1027 -babel/locale-data/en_DG.dat,sha256=xtjjxkuFB7I4p3n0f4Evz631RtMQhIzpoYwUzOzICqA,1168 -babel/locale-data/en_DK.dat,sha256=pE7x4MDJvZGFnqQqXMCDWoMV3Ovu2qH-QO2oYNvgL4Y,2425 -babel/locale-data/en_DM.dat,sha256=gbriVhXcdXi5GWmpgWdGB1LUwI2yquuLk1khkzpo1UU,654 -babel/locale-data/en_Dsrt.dat,sha256=Ttd13uhdXKMHpNCWaH5q74JJ3fok1gV4MFIGd1fGxRk,38656 -babel/locale-data/en_Dsrt_US.dat,sha256=p8c_L5tEvzYmacz0tmq58Wsbfp9wMV_PBgz5R_v7I-k,653 -babel/locale-data/en_ER.dat,sha256=U1vYaQVwnVgfmO9l2_GjBnAhHrShbiHU_E-hAclDvck,887 -babel/locale-data/en_FI.dat,sha256=i4gKdljmc9cXO-E1IT6JGmq2JsRRH71sKe3yUmkhIa8,2357 -babel/locale-data/en_FJ.dat,sha256=k-hXekogcQzt00qXdcWODsHbg7Vh9U8Vx84bERd8CHM,672 -babel/locale-data/en_FK.dat,sha256=r6OGl7mX4ep5aeFMlhog6Xr--kDKFEVhDcepSJBYZWw,1210 -babel/locale-data/en_FM.dat,sha256=88mCYM5_VDSYpJ_mV4AStjiDpKAo_1W7GbmKcI9f_sk,616 -babel/locale-data/en_GB.dat,sha256=2qd2bKhxJeiwIneKwRmH89UCmnYfBdpOFvL02en-YKU,3440 -babel/locale-data/en_GD.dat,sha256=c2ap41e5x-OY5dEYZ5wD4ByRbEzlx0845R1lPBLnJus,635 -babel/locale-data/en_GG.dat,sha256=qhfvbRdldEA4467X0_8N09HwT1ZRPJJtb7Evpvbbarg,1273 -babel/locale-data/en_GH.dat,sha256=bBpzsHl9QhNAQ7hrUtKb6TwGvZYibXQwXfuJVgLMlZ0,889 -babel/locale-data/en_GI.dat,sha256=veSOVDagnkTwyqxP4u5mOkRG8_W4MCZ5ptMBoGOg9SE,1228 -babel/locale-data/en_GM.dat,sha256=jfHQeiMTDNgnIpx3WZ9hOpCR_LXCYLLrVN4SUakudi8,885 -babel/locale-data/en_GU.dat,sha256=WDR_uybAkUii6RHT2x62pzCLvX4bMstibEztBvLSuxI,715 -babel/locale-data/en_GY.dat,sha256=TDiVa4YSapsK9rjQN3ATnrj3m267l35pqRLI7r5bLFc,694 -babel/locale-data/en_HK.dat,sha256=meLPc5_3zahna_xycXEf75TrW5_4BHuqMQcMyoo1eYQ,2315 -babel/locale-data/en_ID.dat,sha256=b8R7owdV-fl30WrUhFz-1YGHiFweaoYs_bBFr9pGhD0,3172 -babel/locale-data/en_IE.dat,sha256=ZNe5XFbdM4UnYu6KaGYHggQqzIVCWwWof5C5ktTsHn4,2094 -babel/locale-data/en_IL.dat,sha256=O4-JPTBiiLezF-iUSDu73id-0VWlSiE0ie8z9qRaxq8,1424 -babel/locale-data/en_IM.dat,sha256=u3JX9jrrsW_G5RQXHsQIGl6ikVduckeldeS_FjKG5Y0,1273 -babel/locale-data/en_IN.dat,sha256=2d4aWIy6Q72ExhZHnku5HKbKmSSavvB7zkflqlBsRQA,14809 -babel/locale-data/en_IO.dat,sha256=TOM0TxdcWcu1wyBXJxsrE-uCIZsbYTCmUkTdfCaOO-E,1168 -babel/locale-data/en_JE.dat,sha256=IxL3Ry70pMOXDbCwU6LZllHXZmg8XHbjocavEWvb9jY,1273 -babel/locale-data/en_JM.dat,sha256=Z9GFZ6aFGEvIEzlbOlA5bBBvxgcxXx6s_7AxPMp2Yg4,1666 -babel/locale-data/en_KE.dat,sha256=oJa3lUdjavkdhkMK_bcnJ08waK9lfIRs8mFkG0JYf-4,1458 -babel/locale-data/en_KI.dat,sha256=3yfkrwv7Yd9yxDNnXz9Sv8ghbDvqczZTAELr3uGNYn0,635 -babel/locale-data/en_KN.dat,sha256=cFebccXOrQo2X1zmHoHYB2vzXynoroYImJTMnK9j3h0,635 -babel/locale-data/en_KY.dat,sha256=slmSWk0IEz_UK7PfHX4KyHlf_iBRfuoOWVuEB0aKaYI,733 -babel/locale-data/en_LC.dat,sha256=jUYdKd248Jkj5XVxXXbvXnfxu4BH_3s4Ld-O67qbPkE,635 -babel/locale-data/en_LR.dat,sha256=ribT8_azFjDC8uzIsOwkGTjfgEiFlSG_wAb_wG1Fmnw,885 -babel/locale-data/en_LS.dat,sha256=2HtV3gUrynDl2mVvqywMfff8VnVjz2ryoNS7D2n5T9c,885 -babel/locale-data/en_MG.dat,sha256=dtMrsBqOpwQExs7dVukbUzWojz_6swx5Ng6OXdKxsSs,1438 -babel/locale-data/en_MH.dat,sha256=NZjQknLyokLgJRNPicAZ55_VoRCATz_WvAxMo_I-HOg,1368 -babel/locale-data/en_MO.dat,sha256=UJVR7td-vlRY_a36ZWbxr_PcK6egIUQSKoky3DeAmEA,830 -babel/locale-data/en_MP.dat,sha256=Sd2vA3CdR_GBw1vQQQBfKIY0asJGsVUwZ6gD-h7Or8o,1349 -babel/locale-data/en_MS.dat,sha256=BXrA3odGnWSeR6404L85ErqMKxTnRCZ16UWL2RpD7TY,1187 -babel/locale-data/en_MT.dat,sha256=sODJaESHndxdT9SYZcnESDA6G6oln6n9NCojeHhKvJg,1990 -babel/locale-data/en_MU.dat,sha256=SefoZho0XzSzzU_Y_-udWPCuRgz8ujdUVkL7hhzZO8Q,1438 -babel/locale-data/en_MV.dat,sha256=Spp5zsOCHzCeZOyUdYqXoqmSoIJ0pxRR3b3nI27jvTs,2034 -babel/locale-data/en_MW.dat,sha256=5d20Ih8j6iwBY545I4nObBWdv9FL37nE-ggfpGeXSVs,886 -babel/locale-data/en_MY.dat,sha256=nUwwM17W9W78nnbXGmrx2zComZQ9Fg_pu3va9wPZzvY,716 -babel/locale-data/en_NA.dat,sha256=-yNAAmx38RoVJt3YRH7Tp1xO9o3GsSVDU6uF_GKhGb0,885 -babel/locale-data/en_NF.dat,sha256=6LqhwHyOnkQA4TNvseuiE1a5Ov7DV3y46CZ0ENcibXE,1187 -babel/locale-data/en_NG.dat,sha256=dvbDZYdlkmhF-IU8M6s2p_kHswy8HhdmR3LLc4EhePI,1439 -babel/locale-data/en_NL.dat,sha256=dDCtXReh9uMfUOVqGWaWjfV1-dLe5_yj-o_HrKZGMeM,1192 -babel/locale-data/en_NR.dat,sha256=ZiUNBY0c1T3LQP-qGmtuxLW2Jfc-lcVTuWpB2jxfAGI,1187 -babel/locale-data/en_NU.dat,sha256=jU4HXz_3l5k-luPPsjZmZBsdOVB5ZfkN1Xuk5i2pduc,1187 -babel/locale-data/en_NZ.dat,sha256=z_qul-H3zQn0Q_lrrHceySj1m2TQaaJZd3QMXE31CcA,2340 -babel/locale-data/en_PG.dat,sha256=WV6D2yT-4GX6ftbnUkK-ihfNg8Y-ImX1Af56okx8LTA,635 -babel/locale-data/en_PH.dat,sha256=oPz_wDvxfCHBpkBUaZ0RiwtPrLtx-9IigR0TIK1b-IM,635 -babel/locale-data/en_PK.dat,sha256=KS_KXItkhkUULbKd9mHdWD9ok4WjZbVSXhU8e5u8blo,2074 -babel/locale-data/en_PN.dat,sha256=qpEWWX0fvhzV6gcX_SHNbJW7E-5FikKwXrQAP9BWmXc,1187 -babel/locale-data/en_PR.dat,sha256=bpAu9yoeKxzQTF5Be7AfXtyE3wax0eP0m-Eu-Cr0jKE,635 -babel/locale-data/en_PW.dat,sha256=--3_iiNqupR9R3ccq5foj9HzkADBEwBYdKE_AxLZD3w,714 -babel/locale-data/en_RW.dat,sha256=Et3hOZwaSDECrCzypgYq1QxKxxnB3XYziIeEe_WiY7c,1438 -babel/locale-data/en_SB.dat,sha256=h9TJ69YThzzLGTh49BBEmRBxSiZhZpQrVJif0QglLVs,635 -babel/locale-data/en_SC.dat,sha256=omYtCZBrLl8fHuT6XInezdetV7WqWZVYriJRnlWKbTg,1188 -babel/locale-data/en_SD.dat,sha256=ozd3rV_icr8p2H9V6StOSMkoHBPNBsXsay1GMRWZ1zs,928 -babel/locale-data/en_SE.dat,sha256=96guhEOzGr2Lcbd3xZ4j7HTj-0H0oaGMQIbI9a_5g48,1502 -babel/locale-data/en_SG.dat,sha256=u9U5CLnqs0iJmSnMsPBHF71HQLpFM3siADzZeC7iaJ0,2096 -babel/locale-data/en_SH.dat,sha256=rBm_0zxjHnEVzs_CPCyuz5LpI9isA2S6copUuNbxCcM,1210 -babel/locale-data/en_SI.dat,sha256=kkeEkPnW48iNoiwNZb0KV29DPU0oVNuENTi_Wmp2ALc,1046 -babel/locale-data/en_SL.dat,sha256=4hJLAAnyuEVVQZ13NC7wZ0JYJQ3rvX0SsOAp0OoW7_U,886 -babel/locale-data/en_SS.dat,sha256=C4kpyEFjyKT9-6wt2pGl4125aN0Bp0wpcYBrr62nPOc,908 -babel/locale-data/en_SX.dat,sha256=7vESruRIiaBqWxuSRpIE2U6PgWwJ9mxgbjjH_XAraa0,1190 -babel/locale-data/en_SZ.dat,sha256=A9wkzZ5cFffcEf1FobYRPxR1EAFwqQvqELsqRpNleOg,885 -babel/locale-data/en_Shaw.dat,sha256=5NskTfYsGHZ63w2s3eYrzrogPpVZeqY3wd60hViYIbo,4774 -babel/locale-data/en_Shaw_GB.dat,sha256=uAIWlJ5gr_NR6lncmMaBrjXUPhZ33rGsXoHz8hrd_E0,653 -babel/locale-data/en_TC.dat,sha256=UWqEc9zpN3NdS1dymbUv2iGKhLkH65Kk9uNFxdXGnOw,616 -babel/locale-data/en_TK.dat,sha256=qz4RHtHQ6cNjB8xW8_BIHdzW1cEcQuyJfdqFIybXAs0,1187 -babel/locale-data/en_TO.dat,sha256=OehJQf8kvWi7A-Rwo2hPjs1Z9pTdg7_Hyx_ewWxbLQ8,636 -babel/locale-data/en_TT.dat,sha256=L23iDn_zvh16iPE5uBlLCRvECSozqyzU9W2OcSjYogE,654 -babel/locale-data/en_TV.dat,sha256=3sj3NCjQg-9UOdTz7wDJRpjx57bI0bntpmx0T50OK9E,1187 -babel/locale-data/en_TZ.dat,sha256=5Q87mjSEaCMmWeWwtesb9lJw2tIWOsvyScG1CqSpWvs,1439 -babel/locale-data/en_UG.dat,sha256=aQLfdbfozsYhK3EG9JXVxsmT4B7UvfSzNBo7kO2WSsc,1462 -babel/locale-data/en_UM.dat,sha256=qd26Sl5bJTEgHU25hvskp4LMxvRJByLOSvUikqz0J4I,653 -babel/locale-data/en_US.dat,sha256=p8c_L5tEvzYmacz0tmq58Wsbfp9wMV_PBgz5R_v7I-k,653 -babel/locale-data/en_US_POSIX.dat,sha256=U8r77o6qQID3Sd5FiZqukSpQnq4LV1BDwHUeuNZjW10,1321 -babel/locale-data/en_VC.dat,sha256=ES4c4Xt6OvJDhxoAZpWR2HFbtyENOl9CrV7XFCBs-MY,635 -babel/locale-data/en_VG.dat,sha256=sqiVUOEtDV2pAc5DzGl76qV1mL5K-UWhMRzG-Ff6r30,616 -babel/locale-data/en_VI.dat,sha256=AGffygfBAafQMxKAAoxt6kwmbES4R_ybbXRV2tHpy04,653 -babel/locale-data/en_VU.dat,sha256=ji2cRB8B-c8uJR7L56HzbkiTR8eJZziVTMcEzuiK2g0,636 -babel/locale-data/en_WS.dat,sha256=gowKsveED3UIWyLgnSWxyE6qq87lH2dMgOVLDGCEcBk,656 -babel/locale-data/en_ZA.dat,sha256=uoSLsVWiMu6x-DYwISGhEwveg0kVsDwgnIhq2Jn0hXo,3411 -babel/locale-data/en_ZM.dat,sha256=8y814a5GtYcC5gvh3YBlcYf5Imr0yNEIV_v8jH3SXqk,885 -babel/locale-data/en_ZW.dat,sha256=GUDDEesQRkUuLyyDlnJ3MGlGzG-kDPxt8OTIqVRKDyw,3320 -babel/locale-data/eo.dat,sha256=kSIbuCrTJF0ZuNV8FzhyheJT33iKwteIHLaYgdfPO4I,101326 -babel/locale-data/eo_001.dat,sha256=3-tP9zaTDfbBBjpd2qKVIhS7WWbmtVKGGW_BmGIhrHQ,850 -babel/locale-data/es.dat,sha256=c62rMW3rHT7taFSTKPt8je50jtFex4sL8nvuVey9224,191377 -babel/locale-data/es_419.dat,sha256=s-JLmJhGKoIbnsjZm-6UXnDsAsgFhIKk9OJk7SPR_oI,27973 -babel/locale-data/es_AR.dat,sha256=rFeyqcUDLb3yYYWMuCP8R4O1n4rT1XCeayaIaoPaOPY,7087 -babel/locale-data/es_BO.dat,sha256=9zgEUshMb69M3LZS_3TOk4kGOt73fnB2UWWR7HPFAgk,1477 -babel/locale-data/es_BR.dat,sha256=oCD_7IoQ5w-C-YXpQ_wBcS0wUkcY268QDcg5y7Vo7KU,1207 -babel/locale-data/es_BZ.dat,sha256=Z3ZskA42UBcpOPDI66F6YBTvzt-g61PmxhiEpdGXpwA,1206 -babel/locale-data/es_CL.dat,sha256=tpiiCMc68Ab3YYDqi_zh0dw_IfsZmLciylujbf72XqQ,4848 -babel/locale-data/es_CO.dat,sha256=_ZNmqQnEj8EoNse4lJuK0Qrg1ZnPSgUVCPCNo7K6FE4,7436 -babel/locale-data/es_CR.dat,sha256=GknsR2O3LbFhHagGvUvgNgBVCVbXZxk-yzivTPR-Q_0,1308 -babel/locale-data/es_CU.dat,sha256=N-TqpCs34sjlEMeJgvrfOSpmnnlGxuuGtSBSaUKDbvg,656 -babel/locale-data/es_DO.dat,sha256=HMY1U9RiyiBlQKc_kUERQ-GHqWCgjaqrBY0mKUE9Gp4,2700 -babel/locale-data/es_EA.dat,sha256=V4UU6BM3pjbuEleLA_MaJtWl8IejNcHzUM660pfKa80,616 -babel/locale-data/es_EC.dat,sha256=i6oUe_5GL6b8ZnbnORW1csbq1-qgo6VN0Z6x9G2xIWk,2941 -babel/locale-data/es_ES.dat,sha256=fd1TSjdlf2lSMxwi0NhYGR2eyiABBaSJvhLlwLO46j0,653 -babel/locale-data/es_GQ.dat,sha256=a7A-hqM9wNt51_CdpjzU8aT9KEeMz165-MyhkWyqJOM,638 -babel/locale-data/es_GT.dat,sha256=zk_WqHmzYsoIAiErSYC9G62MlbgAuySSTAPZLtOX__c,4132 -babel/locale-data/es_HN.dat,sha256=71FLaDfVW5pgllY-BoQoPaDjJ4lvhs_Fi9EBmJQjZj0,3051 -babel/locale-data/es_IC.dat,sha256=hwey8h4GM8i25i-YZR_K-jvCij95wZqr0zdTIKauP58,616 -babel/locale-data/es_MX.dat,sha256=6jxhdWleuQwI_O1FZOl2I5DEwUs3oXjAhJhyBmBCMGM,25204 -babel/locale-data/es_NI.dat,sha256=cF62A52GuQD-QU9-jBmK_8AJ5pZ1W_nJ7NwraSAhMvA,1227 -babel/locale-data/es_PA.dat,sha256=fBNNQGv937Iu4OPHxSuYtPu8M-u6xhUmG0LtMbxDC0E,2775 -babel/locale-data/es_PE.dat,sha256=G6ZcerCUvlSGQmeysFNtMNJEZwPAerVqwOG2hHUpZ_U,7244 -babel/locale-data/es_PH.dat,sha256=fEMZmVPQb97bBjEtCVMLn9JUtosTePmRuQqhpfNYkZQ,1248 -babel/locale-data/es_PR.dat,sha256=wPOPeV-O9rnLzNHObqs9JEUo2ouyqmaiXqtsxHtKpWM,3307 -babel/locale-data/es_PY.dat,sha256=KXiw-rkQCdcoeTv0t0SnA8ioZrHQYfPxen8491aSq80,4442 -babel/locale-data/es_SV.dat,sha256=JM9uw_EVtB6J8bH_Nz0GL_yr6ehay4uAPm4OJIiUmfw,1260 -babel/locale-data/es_US.dat,sha256=ifZ5PL9mZhnqv3E6uRoRS2Sqlkgyz53m2RJs9wDcpMY,22533 -babel/locale-data/es_UY.dat,sha256=31KdHVEWnE6fWuHa7KOdTLcmlWXn8M5liZZMDWlaVrk,2703 -babel/locale-data/es_VE.dat,sha256=kyxdQ51DhLNf6dQauAPw4vOlpjftw9CQgc3yH_uAoKc,2509 -babel/locale-data/et.dat,sha256=eTq6nG039wKW81vnFtx-qzaWVo0wiUey2Y2ZUQLl49k,175652 -babel/locale-data/et_EE.dat,sha256=JpcyzIDpGwHlLSiInuYO3HfxkMEFsDPBeMc-B8Rj3MM,653 -babel/locale-data/eu.dat,sha256=lEQD4nzng6_Fmu8zQtkrvoFWV5AvUaCpOaAlv7vknt4,178023 -babel/locale-data/eu_ES.dat,sha256=ABS9lrwjRkWenVB4fNrwKpr0mOuMF_eOlOrSrobcDl4,653 -babel/locale-data/ewo.dat,sha256=tHyC9Uj5Gkz_nGEiTCFjXn3veej5z1GUhr-j-Dl2vgE,16881 -babel/locale-data/ewo_CM.dat,sha256=likxlZJqzYOVxcG4oSUQLTiH5DjGjdAFsJPIjnnj2Iw,636 -babel/locale-data/fa.dat,sha256=ci_F95dki3wTXhl10yqZP7IomDg1FHIOArxqTEMUEyk,192269 -babel/locale-data/fa_AF.dat,sha256=3lXNqz0r7fjXSYzqZBKGD5gtS0cPs-lx1ExY_s1ucfk,8639 -babel/locale-data/fa_IR.dat,sha256=nPuexwzRHDb9TFMjILK_V43sVIzbcn_fgp0msY3eFQ8,678 -babel/locale-data/ff.dat,sha256=gT8MoHYFJcGDoVjBCYPzsrkMTKylOjXkE64Sc0L-rvM,15911 -babel/locale-data/ff_Adlm.dat,sha256=GbwYyVBbA8SAJP-1BYMW4b3HXivgi8HvRDzIaKuJtvg,326252 -babel/locale-data/ff_Adlm_BF.dat,sha256=eYQLbHvxtEqcJCMbXSkqN2dRSuYHVc6Tg9kOUKayJQs,637 -babel/locale-data/ff_Adlm_CM.dat,sha256=b3VqkcWqXc7s1hCxN60dd-yBRXkcXfMMQ0uAJKmSsg8,656 -babel/locale-data/ff_Adlm_GH.dat,sha256=r1CRe9Z8kZ3B3PDxmZQbvgpsEcY3OjJek9Z_S8FBb5Y,1236 -babel/locale-data/ff_Adlm_GM.dat,sha256=ZM17aBc8xznEjoP4f7HRCHaKn-DIxCSDGkL6GvDYvDw,1232 -babel/locale-data/ff_Adlm_GN.dat,sha256=HWkLsTj8Sd0fWYuYysHhShl08hg0iAvSXhPjy-rUjB0,616 -babel/locale-data/ff_Adlm_GW.dat,sha256=vIUl_C4PZSWmypeEmnsAUbGN2dSquM3nEOdBs22_qNE,637 -babel/locale-data/ff_Adlm_LR.dat,sha256=277rY6zAWlxetFe0D0JpVEY9MNcQiJU9kt1jRoiXE7g,1232 -babel/locale-data/ff_Adlm_MR.dat,sha256=qz618w1XY_zwZ27nB6LBgbzsjsh4UinfnuOVx2bqLgk,1233 -babel/locale-data/ff_Adlm_NE.dat,sha256=waY1EIQKuOkVzrtJ-t-5VY7cK2uKL0SIBO0PQbx4x9Y,637 -babel/locale-data/ff_Adlm_NG.dat,sha256=9UdHELj5G90YopBKktxDyWVQyLxl5f7P3ToBElwlvCo,658 -babel/locale-data/ff_Adlm_SL.dat,sha256=7jLKofwQBRggP61keprrbfFGXvrcJPIOvwEVmUNjcTI,1233 -babel/locale-data/ff_Adlm_SN.dat,sha256=nGazz6Tun3D-XsO6SljxQeeBuzvAb1sBQw21IbkDQKo,637 -babel/locale-data/ff_Latn.dat,sha256=APyNmlFYRwCQOlboY58qsqiF57rrI3F4fHu-uQTdt4g,866 -babel/locale-data/ff_Latn_BF.dat,sha256=Nym5keR3dDPMJBFr7ZyW2cuuY-qTMkdHzXnIHSmfD4Y,616 -babel/locale-data/ff_Latn_CM.dat,sha256=rWaVAF6D5gv_hDhNmSGbcWGpPV7X4gp53FBMXyMjT-8,635 -babel/locale-data/ff_Latn_GH.dat,sha256=-kMvFNIQyikTD2dFakV81ghSR2H584AigLgtmrzlhN8,1231 -babel/locale-data/ff_Latn_GM.dat,sha256=1Air8sk0wb0McqLZXDWIYQeiKgPusBaVjr4zk54IaoU,1227 -babel/locale-data/ff_Latn_GN.dat,sha256=7R-6dXYMBdveo2-9Vc7CjIA2H6y_hGJVbfVGIaJUgbI,636 -babel/locale-data/ff_Latn_GW.dat,sha256=2kbqhzcDeSPQxefHxynmrv2tmFVnWdRNjO7I3AZ6lxk,616 -babel/locale-data/ff_Latn_LR.dat,sha256=MQxcDQnMZC5hN52abzqCjVIL9Z5mA9wOyTqGPP4Oj0g,1227 -babel/locale-data/ff_Latn_MR.dat,sha256=CDUb5owq0Ntsd2lIZJejvYxOjl-NOUPP-v3tgVj1_qU,1228 -babel/locale-data/ff_Latn_NE.dat,sha256=R8C0fI8ql5XpnT29CrwBG8rgdHB1AASDBSdvqIqIQ1o,616 -babel/locale-data/ff_Latn_NG.dat,sha256=00rtiYbJD_ci8-0M4ye95rzGpbyX8qQ-dmFFIajAtRQ,637 -babel/locale-data/ff_Latn_SL.dat,sha256=UaWOeokdbSoxG0JUyyGWkDyz70sXy-cZbc3lXZxmQK0,1228 -babel/locale-data/ff_Latn_SN.dat,sha256=mPVac9iCnwNay8c7Ko3uUvg48lfyfEZrvhpyEFFGmFk,616 -babel/locale-data/fi.dat,sha256=Vd-z6RH112cP0k5AGOlAoYU1U0f5mpQQkiHypB844Jw,204853 -babel/locale-data/fi_FI.dat,sha256=cpbJU4KKG8OWbmLnc9TKTdzmpoi2AJh_Pu1cHhDwVSM,653 -babel/locale-data/fil.dat,sha256=g0INTCXppDgjTGgBHy9hqQ8Mcw7G9K3XLTLyVshWuuA,144724 -babel/locale-data/fil_PH.dat,sha256=JjoZt3zNxy1X6RnHoxUKOMzT-xMh3tGZBRq8cvrBwqA,636 -babel/locale-data/fo.dat,sha256=4P7HQxbB7uhYUyAt1rFID1mHXUe9zlQBvWCt8LDRhNM,148411 -babel/locale-data/fo_DK.dat,sha256=HUuarLNFSsV_gN2fg-OqrPr-6Ry6KFgitCp173jxAOM,674 -babel/locale-data/fo_FO.dat,sha256=SLeNQ33QTZ92kXCzQcFfo-OgwZVFPJKIeRivuvz0zo8,653 -babel/locale-data/fr.dat,sha256=HvPCR3ft-_VxUpJsVp1wKU8aiJ7eCKZEz9XZVlM5jek,213357 -babel/locale-data/fr_BE.dat,sha256=ODfkJC5kWWEEkjr1UV8AaLtKKc4sPCUxlIGkEDkTr6s,1085 -babel/locale-data/fr_BF.dat,sha256=7piWVeMMrZ-YbO9MNqJAu7ZeIdueVnhg07eeMwJHy94,616 -babel/locale-data/fr_BI.dat,sha256=R4kaU1OtMcNIcibkw8OFGP6FaYMxt2uKMRyidkEqbiA,637 -babel/locale-data/fr_BJ.dat,sha256=sel3fdwegY5W4NRg32t4MuXoqpGqTAGO_ffCF2NPggE,616 -babel/locale-data/fr_BL.dat,sha256=n-MRZjeHNkRMwCtGgPZq52Lj0ijntBsxfskC324i2k4,616 -babel/locale-data/fr_CA.dat,sha256=Nu60QdYyJaiQnz1EbBLSWIO86Rf57q3FWoU7ywZMKQ4,72420 -babel/locale-data/fr_CD.dat,sha256=HWaY-wrLseHcf0fGlRkAWt118iQjRZaTGlqs7G23ZrU,1138 -babel/locale-data/fr_CF.dat,sha256=wxzk0Nf6_pKO2VDivQprUY9WvaxRSkrfQBoUE1UVrAA,616 -babel/locale-data/fr_CG.dat,sha256=zP3HTP-nqZjG-OD_DLrDEPPbB3t9g4T2kHVzI-HxhaU,616 -babel/locale-data/fr_CH.dat,sha256=DiO5jczUyCwTWpWSoxVHE6kLMXQPru-XotJQLDInjKw,2876 -babel/locale-data/fr_CI.dat,sha256=TrHL8hQRuJI3Auxe3aTHYa_rljyUvT_s0q-jdSJflJM,616 -babel/locale-data/fr_CM.dat,sha256=31oDAmeRb3F8a4fvVn1QJyIbrla04w8kfC4oQO0vwkk,1970 -babel/locale-data/fr_DJ.dat,sha256=Jqu2FOJQD41B6fLSBEc_Wf-dIQ-B6MWlT0m1buQnmxo,1248 -babel/locale-data/fr_DZ.dat,sha256=uOe9lbjO51q30G0UMs5nKrMLta5CtLW2Fg4dvsfRX3M,1290 -babel/locale-data/fr_FR.dat,sha256=bwtjtv0NG-lxlXO7fJd6r--l38WKaQmqlmn7PpXJdJs,653 -babel/locale-data/fr_GA.dat,sha256=rMwS-msXjMO5T5k1BP2B2S9B_dYvDHlP8HMS-Lq8XU0,616 -babel/locale-data/fr_GF.dat,sha256=x97-H7H0h4_MUTpjMdrkYB790vBvPKKxmnUTu-FOwLg,719 -babel/locale-data/fr_GN.dat,sha256=6KVlBWrF76ZhgyYg47F1TcR8_fbE5Ii2pJzPhmbr3Pk,636 -babel/locale-data/fr_GP.dat,sha256=W99xHjqPQj_NJ1X34ismj8A4xeZcHu_vyqH8tIwXgeI,653 -babel/locale-data/fr_GQ.dat,sha256=Ogf5NI4zMvbVROeIb8F6h1NxJNKOqY4fKU6G2SPJXDk,616 -babel/locale-data/fr_HT.dat,sha256=S2Vvt2b9Wu4dY5Tsd9xxFAx_RLcWXCGf_XeSSQFYbKQ,1836 -babel/locale-data/fr_KM.dat,sha256=ChLpzCyulxYg8Qmm5HK8YkK203GRSUEBNPSl8war7lA,636 -babel/locale-data/fr_LU.dat,sha256=0sYBhn8-9lvfOrU-ZEIbnO5v03qQOQq4wXCKp70b2sw,729 -babel/locale-data/fr_MA.dat,sha256=Um7dK7MvHkPB_h_r0pk47rMFCng1LWFgIekS7cDX9ZE,1098 -babel/locale-data/fr_MC.dat,sha256=IfTCZ89rqHzUxdKyIz86Zs_VUH2zc5JAvntdhyKsNR0,653 -babel/locale-data/fr_MF.dat,sha256=xU0grNJKWgpfArwpLt7vuOpSTSkyPx3o6gFkmZLCxd4,616 -babel/locale-data/fr_MG.dat,sha256=A9zYBbE6gIWuGDPxv92ReIcR49gtIEYaEkCj9ZONHHI,636 -babel/locale-data/fr_ML.dat,sha256=-PoWsHBtnaZisIOqZyaEFmwooRXb2R2xEMe6DYad_sk,1153 -babel/locale-data/fr_MQ.dat,sha256=45qWAev4p2ZaFVky1Qlrw5q907PDfbRJq9q2UACahm8,653 -babel/locale-data/fr_MR.dat,sha256=mVSOABz3cRa1-HEeUKW13sLw1ZR6PmB9h_DPfZsK4Uc,1228 -babel/locale-data/fr_MU.dat,sha256=c4ERuS1GI8h7waxcW6BRtloW7BThLlgqdYTf31Ioh_U,636 -babel/locale-data/fr_NC.dat,sha256=Su2DaGZPnLCaONmgosMYke9kH6dP8xJ8wJF6P5xrJq4,616 -babel/locale-data/fr_NE.dat,sha256=D6ghYGdDXlhaVQ5gAr8wWHxEHYR7mBs0QaiNL5nfxWM,616 -babel/locale-data/fr_PF.dat,sha256=oPN2EBo1hpLjlpDYPB51qEAx_4HNMWG5-Bh9JN6Kal0,616 -babel/locale-data/fr_PM.dat,sha256=gEP6Ay7r-p7uIjOGXP8eCa62yujlTBntENdeNd9KKes,616 -babel/locale-data/fr_RE.dat,sha256=pxNaLi-BUbe3E-Xf5ZXPoeut9NdT0D9OGEgmoSWZEr0,1055 -babel/locale-data/fr_RW.dat,sha256=gP8mpM7gx_X_9NKDm8B9PuTg83jwT5Nn3NOKPpVhi3w,636 -babel/locale-data/fr_SC.dat,sha256=qvz0N08LKCsPCPDZK1NmAhhzmaszBQ8mSlDbAsEwAoI,636 -babel/locale-data/fr_SN.dat,sha256=n6ijBmMl-ztuCLSePI-Q3yIyhzejn7KvRw5ZqjDoXsA,1018 -babel/locale-data/fr_SY.dat,sha256=tpDovgZ3aK7OumRwbntHTknV-tRL_HjcPK1aQINC-x8,1290 -babel/locale-data/fr_TD.dat,sha256=1H47veWKRj_iV9CxHMz7x7tfrL8IYdQaRWhTV455efw,1208 -babel/locale-data/fr_TG.dat,sha256=r_E5Vnj0Kb5CG16ApHFls4UreDeO7-o3uzpQdJjpbRM,616 -babel/locale-data/fr_TN.dat,sha256=hcGRJ2UjuFEFJqb1BDglGsXY8jCEIdM8--OrU3OqRhc,1228 -babel/locale-data/fr_VU.dat,sha256=FYYsiaoM8QZeClMnQzLiLZNXW9hULz-rCgRTYWvrIvs,1228 -babel/locale-data/fr_WF.dat,sha256=jn6VFRw_qpJFxpO-I6C9nhz_wRZ8cV2b2XRBgSzi710,616 -babel/locale-data/fr_YT.dat,sha256=x0WpQCLoqrLY3_nCF7JlcuekkoUtcpE4llC8kRmeRmY,616 -babel/locale-data/frr.dat,sha256=Itmd93DOwAMGcTkWE83BWDS1oXEVckX0EE6mSiOKyoA,102994 -babel/locale-data/frr_DE.dat,sha256=2ohnodzECbJBUTEta36Ts4amZKl2_LDhuD0-Hu5JBo0,654 -babel/locale-data/fur.dat,sha256=pvg46WO2uwbg27leWyWYXkoqYFiaE1u9Txsd_iZJeC8,32441 -babel/locale-data/fur_IT.dat,sha256=PpDH1opUDjndOtvpPadiOtITGyGxKZY0ziEhb-4HKbE,654 -babel/locale-data/fy.dat,sha256=zJce96OaCoG-oKfhQFisyjgVEK3pNVtF9RT-f9h7y1g,108200 -babel/locale-data/fy_NL.dat,sha256=I_M2hFVCAaVAL90yVMloW2eYmzO5C3NZztfEDAes3_I,653 -babel/locale-data/ga.dat,sha256=rx5MLgtNUisB9V7gu0e2dNyCXF2H9KhLVULuYvLNUh0,261523 -babel/locale-data/ga_GB.dat,sha256=NKphVJhmH8egga1dgfO-hSRVFhbxms2JvGMU3ybgj_Q,653 -babel/locale-data/ga_IE.dat,sha256=P948T1Tl4B7kL1T-uxii27q4IWO3yQQ5emTLv7iHvW8,653 -babel/locale-data/gaa.dat,sha256=W9tUKmjglnSUxVlpiGA0clKmagjmzgF1Fwj_UPmg8Ik,33806 -babel/locale-data/gaa_GH.dat,sha256=FF7vo24vzA2ru3t8py246uanyOqyoSkpD65F7KFTXlA,617 -babel/locale-data/gd.dat,sha256=AtSvR97H05LvFNLHpLsb7tOgKYaOjYvWFOLaDDH6xMk,280763 -babel/locale-data/gd_GB.dat,sha256=weaRul21diYZoqLk7SXacBy8GD1bH30cQO6AHejilPM,653 -babel/locale-data/gez.dat,sha256=6gIHA3BFc3-A6-dOq0pc6bqP2ej6kmG9Xvwa0EEhoMo,12743 -babel/locale-data/gez_ER.dat,sha256=MKpSW7Upkpe42Q2mbJStbjtnrW6Kyo8Tg0zXAxnHWqM,638 -babel/locale-data/gez_ET.dat,sha256=93QTSMihpcfFyRhttFplgAcsAhzrPjlbrz5HI4feRSc,636 -babel/locale-data/gl.dat,sha256=N2zvS1gg8f3l6SOLqIIiKCBsbxAcArFclISemEyGx7Y,153642 -babel/locale-data/gl_ES.dat,sha256=us8xWRQnNTO_KC42-FOU2cnLCNl96591qnxZ4exq5Fc,653 -babel/locale-data/gn.dat,sha256=2CbBgzd3kHlm8uIpKVV3yurmEXB_yNUfM2NKTFV95dU,2477 -babel/locale-data/gn_PY.dat,sha256=tArgCo85T_BUNmPc4sXVRz8X5wcHJmBS6XP0r8dPgA0,635 -babel/locale-data/gsw.dat,sha256=TGHS38pKauNWMdFFsCyCJ_9p17aLt14jMA56gxTDBM4,95265 -babel/locale-data/gsw_CH.dat,sha256=fQlRCd1MJ_gI6rcnkrU-lUE7ZM4syRLh-suMRT0DCOk,654 -babel/locale-data/gsw_FR.dat,sha256=vHNQ1q9Zyf6xLfsJpmqpaX1iHerMRt1dsJSPQdQDoTE,654 -babel/locale-data/gsw_LI.dat,sha256=dsg7TA7MECMrbTXC7i7zXIjrEoqrF2jZ_ckGiTMholo,654 -babel/locale-data/gu.dat,sha256=5A_T6q__RzuWdGg9Sfte2wOqRw_Adz-LJMJJzFJ87cg,208242 -babel/locale-data/gu_IN.dat,sha256=shXUMyk4ogB8uJPazALoReGyLqRXSYOeVBVMn313_Y4,658 -babel/locale-data/guz.dat,sha256=491I3x6EkMG0roSEKI3sHxtaweXWNXhXyk4vsG-LzDg,15427 -babel/locale-data/guz_KE.dat,sha256=Uz_x0_YFKJHDkSd46SvuIfO7W0c-uqYnasmmLNib3WU,636 -babel/locale-data/gv.dat,sha256=Ye3v_q7SrnCeiOVw1r7NRcTtUZ3RwOr1ZKs6skxYTos,3960 -babel/locale-data/gv_IM.dat,sha256=bXOsSoV303kSUECHz2xd5HhASRI-XCjqjxnxpk0Bt10,634 -babel/locale-data/ha.dat,sha256=fVfNqCuIXaCTV5E9XNMNVROCwgalJ8f4MKfEvKun3Ao,150526 -babel/locale-data/ha_Arab.dat,sha256=AUoCyyrZDTrf5SEZ2SRizimC11NMSCyonIkMRer1PxY,2197 -babel/locale-data/ha_Arab_NG.dat,sha256=oYJYqTkaDX2p4IJ9j3sEJT49dcVn_f9JyjO0rUJTmAc,616 -babel/locale-data/ha_Arab_SD.dat,sha256=7DD6pzCmpEdjwbTMAbAb_vJey6Qh0tIeSs8LjEpJxBo,678 -babel/locale-data/ha_GH.dat,sha256=Cwfuh0nEMJu4LGZmdOXJHp_5fZRdpTIODJ_Tpd83uPM,1231 -babel/locale-data/ha_NE.dat,sha256=glKzRtSaovyoiyBc-vjFbJ0wNuxfga49w_zeK3ANtvU,616 -babel/locale-data/ha_NG.dat,sha256=oYJYqTkaDX2p4IJ9j3sEJT49dcVn_f9JyjO0rUJTmAc,616 -babel/locale-data/haw.dat,sha256=aNXNxqponTYIxzV21MX0jIzG73qbhbNO6px2WGael6o,10375 -babel/locale-data/haw_US.dat,sha256=W2qJBTNdETpoN-Ue0UYbqyblj-gIbQNOUMr01RwJ2fw,654 -babel/locale-data/he.dat,sha256=o6AACO6FcY_o6bcUuLkcWgbWIT77K8N8BTBDLY0hk7A,217062 -babel/locale-data/he_IL.dat,sha256=KpQ8sod_QOZ94Tr0tfhlATzVVsrqXck6eq7txoQgCbc,678 -babel/locale-data/hi.dat,sha256=TZ6kgfAZH0cuoX3Y7FpTEFJUEmlrSGccY9nWPDk27C8,221948 -babel/locale-data/hi_IN.dat,sha256=UMkxSHgYSdX-hPgYa7rOOzft7xtJwcM0m5nTphUe9xM,658 -babel/locale-data/hi_Latn.dat,sha256=Dn0MJdILlsVYU9R5BJFSPGGr1a35jF4k9ebJMKLX69U,30945 -babel/locale-data/hi_Latn_IN.dat,sha256=UMkxSHgYSdX-hPgYa7rOOzft7xtJwcM0m5nTphUe9xM,658 -babel/locale-data/hnj.dat,sha256=ryXdpBMEUzFyZ_u_YiqAK689QOsEuUO_Auyuhty_4jY,2117 -babel/locale-data/hnj_Hmnp.dat,sha256=6GekZXtZVXtGcI_zk6NqXq3WxMnOx83IpRlJOyUws6s,746 -babel/locale-data/hnj_Hmnp_US.dat,sha256=OydEowg2bNVks5nd5ij7ZJqqQT0ztYv4HL1ZZ4gNajw,654 -babel/locale-data/hr.dat,sha256=kdzKpWmyLAIFw7D5DPKG7aHUQjYlM5fctcBLRoHeujg,207636 -babel/locale-data/hr_BA.dat,sha256=E_S8FRdn0yszTWFg9RlqTV5zEwCc7-qtod45Ud8LHyI,1188 -babel/locale-data/hr_HR.dat,sha256=PqaNYKNdTFgfgmeiINdYp2d3q8qpfkCUs1y4ZHmsphA,635 -babel/locale-data/hsb.dat,sha256=w5bDS336hxU-RChl4QgaayXgMgN_VBUh5GJXznPI_Bs,206887 -babel/locale-data/hsb_DE.dat,sha256=_ELT9KBswSqeyiwbcsP9nFY793FE8PQzEu_2w78Amro,654 -babel/locale-data/hu.dat,sha256=dmS-7GInw1eGbifjgMyXc1m1nBg6dK6IOJIDoLb_Epo,147032 -babel/locale-data/hu_HU.dat,sha256=r3RZskHfUdk1Ba226wqBHAoRMXorlh-IkWLlnY_mBTs,653 -babel/locale-data/hy.dat,sha256=R6n2G8QdkkxlAxBgpTK7l-cPhwHg03vIG1pwmWVrCV4,202316 -babel/locale-data/hy_AM.dat,sha256=r1Bb6WWX2QxVlLP5vRVgox0HgoDOosA-h3oYKLeZMIY,635 -babel/locale-data/ia.dat,sha256=Wa4yDTDv9TA2Imo69v_49GqgV8LvQP1iuWGq6LFAMOk,133538 -babel/locale-data/ia_001.dat,sha256=fzAkHPu7PNj2TOl-kQcJLIdlEK6z-KfVFUVcy-YF5Zg,941 -babel/locale-data/id.dat,sha256=CfCCzK3VV98obeH7x1Ueax-xYczfCwextwJ7aetTQ5A,126977 -babel/locale-data/id_ID.dat,sha256=GvwO35RP_Y8vswE60ItYMQa7XUOBXGLk8tvL8kSJkY4,635 -babel/locale-data/ie.dat,sha256=9nzS8srJ9Mze83D7nKqXSlGvjOtu7utOyAJCLaffEm4,77957 -babel/locale-data/ie_EE.dat,sha256=93dmapYNE5HEAfIRwL_HjNV4fpCJhy1CseggbriCXL0,653 -babel/locale-data/ig.dat,sha256=ts_BawFD_ves9B7kX6GAIxwBY8FP4jNmkZidIdAVaDA,78550 -babel/locale-data/ig_NG.dat,sha256=2MR603ed1L8Y_aZhXPk7K7J8bgQPE4xvvpn8R9Jodiw,616 -babel/locale-data/ii.dat,sha256=WBkpukOuFcoryzq0QnHhdafGfad_u9vdJy0JO9vo-iI,7477 -babel/locale-data/ii_CN.dat,sha256=Vr_Oe23kFnz-EDfl7XeDv6GeTY0LSK-VV6UJpzU8yJE,635 -babel/locale-data/io.dat,sha256=laqBHV7QB933VjLibEOmRezXV9StwhKVzKvWp8e62YA,932 -babel/locale-data/io_001.dat,sha256=T6zZvvSVOcdpy3fhXbdPAWmHCvDTluick2U8_hUDu2E,912 -babel/locale-data/is.dat,sha256=r9gnQpf81NqPVskVKUiSGWa6VU3_NXzJcna1Gho28d8,163097 -babel/locale-data/is_IS.dat,sha256=f3tUj_oYhQ6_tGnn8yda4PZfqChiHmcZXo_nMDCtzSQ,653 -babel/locale-data/it.dat,sha256=n8pxKaMuS2ekD7EOSV-3PmVfdzm9NqxF5zA073x5itU,173579 -babel/locale-data/it_CH.dat,sha256=Tvtge1s4BcbCeKJmPBiSbtbf_qv8wrw3Eb4Dc1sF3dE,2942 -babel/locale-data/it_IT.dat,sha256=-e6EK0A6gEd_G4_BHlmd8_caQ-k_JrEemNgdA0czhsQ,653 -babel/locale-data/it_SM.dat,sha256=xjE63TohE8bjkNiOh-BhOkuB9YWpQ0n2rrBMJoAql5E,653 -babel/locale-data/it_VA.dat,sha256=wwsl_eAmNu9m2JPZnpBwFVh4gsk5AM9lSx8UAXhrMlE,653 -babel/locale-data/iu.dat,sha256=vZIG1AsqwcrTA6zfwBeQydVAn5qDQXT8yTK8wvbaVAA,3209 -babel/locale-data/iu_CA.dat,sha256=C449KxuskTW8w7z56Vv602QRYsQ90O0WbazR7VqlDa8,635 -babel/locale-data/iu_Latn.dat,sha256=oYsdWLomYvVJg6kIQIKYOdSGWyrEHftc2U9bZ0sHFD8,904 -babel/locale-data/iu_Latn_CA.dat,sha256=C449KxuskTW8w7z56Vv602QRYsQ90O0WbazR7VqlDa8,635 -babel/locale-data/ja.dat,sha256=86xPBOY1H1e0fLC6g_61R_ipS4QGbB9sXst_JwwdAWo,179695 -babel/locale-data/ja_JP.dat,sha256=o2pbFmlkEZjV7CHE9cYENYVv2kQA8texhNDhEecgQ9w,635 -babel/locale-data/jbo.dat,sha256=2eB9ymOoFb8abB-v7ISAGcAg4HEEMmpuseHIXFgtqkU,1008 -babel/locale-data/jbo_001.dat,sha256=wwLKEXJOwULYD-q92kQdvpiwW2fgis5YcsP2mT4tnT0,746 -babel/locale-data/jgo.dat,sha256=9X63SqWqQ7TK7Z2RKaQwFBP9sMog_4cQN5Sr_KBlyL0,9031 -babel/locale-data/jgo_CM.dat,sha256=1lDyjZLpK6fS6oSpfnVLdYd2IUgGlUQfF53BDdK7TLY,636 -babel/locale-data/jmc.dat,sha256=lRstulkfCj6kDI8VLH_3GS4awAqVsylMU1hvvWH7kJg,15374 -babel/locale-data/jmc_TZ.dat,sha256=fODp_OsVygbH0UoRsx4HHcXrde02bRKc-hy80sDkcK4,617 -babel/locale-data/jv.dat,sha256=SucM3ZDoHXO7PsbOYNLdx0UmQqWUll2i1hDqn-zJY9U,103138 -babel/locale-data/jv_ID.dat,sha256=G3zTSeqWMngemp5lAcghudTcv-i8egZS12P0-T1DNXw,635 -babel/locale-data/ka.dat,sha256=dIskDjc7ZdRZ1rGJIHxOP_47WO_cdjLDx4eltYETbUE,230234 -babel/locale-data/ka_GE.dat,sha256=zzw4NZBk8dsHIBeEzB3Vtf2_1nC4DhqblLoBUXfNHN8,635 -babel/locale-data/kaa.dat,sha256=KjLQ7_UT8pqVmgqy5BXJHe9hbPceKi6AIyefM4_0pYU,17585 -babel/locale-data/kaa_Cyrl.dat,sha256=zW7tFPX2CPo0NwR2o1DCKu8Tsvm-Aef9RAuy6AcaJXs,693 -babel/locale-data/kaa_Cyrl_UZ.dat,sha256=DugGAZvImbUSHvvGmGw0ekXXBj34vEjSkHhSxVXbc-g,636 -babel/locale-data/kaa_Latn.dat,sha256=zW7tFPX2CPo0NwR2o1DCKu8Tsvm-Aef9RAuy6AcaJXs,693 -babel/locale-data/kaa_Latn_UZ.dat,sha256=DugGAZvImbUSHvvGmGw0ekXXBj34vEjSkHhSxVXbc-g,636 -babel/locale-data/kab.dat,sha256=ykLRvdRtHpY8y7JDHOgC03KxAyvAfxzYQUl44CKKr6s,121528 -babel/locale-data/kab_DZ.dat,sha256=v6fd0kyletm1kfN2ibSUh6oddckpLHjPd_qrq6FQpd8,679 -babel/locale-data/kaj.dat,sha256=tKKi4eYHT0zEJLSHi2DefEGyTTu4RCKpnANu7NQhAPg,2696 -babel/locale-data/kaj_NG.dat,sha256=1RODrBAPxCrrlTgfhpdz-VxQkTdjJEJYHaJEsOgQsNk,617 -babel/locale-data/kam.dat,sha256=br3FOMP0rS2tAq1tSXwYq197v2XXHqWtX_TM-39QP1k,15506 -babel/locale-data/kam_KE.dat,sha256=8AQQhHQdaI4rBKXfTivg884XIDfZlbDEQM28KwvB2Og,636 -babel/locale-data/kcg.dat,sha256=dOZR1bP8sPbhD2Mk496Twz8MOivgGQoliuDMAWSO9fY,2549 -babel/locale-data/kcg_NG.dat,sha256=jCObRZa-t9Khgx_M8ps0PLbeit7rPCFtHeCOhtfCnOY,617 -babel/locale-data/kde.dat,sha256=cFVUYeayn6-kMX6PwQQ3J8rpHMql07_V7lSluInC2x8,15810 -babel/locale-data/kde_TZ.dat,sha256=2sfb3gejYM15YtZeRrc0AJgdaJhqgbVJ9c9yF9SlJmg,617 -babel/locale-data/kea.dat,sha256=o2awnBismFEWQemtUPASmZMVLlOkJNDtuD6egmvMatw,76097 -babel/locale-data/kea_CV.dat,sha256=LyzxPE6yP0f9hdD4uvu8CvEp8nmcmRDVuRI8YxBQ5wM,617 -babel/locale-data/ken.dat,sha256=PMrEuqYRQIhbpP2dPowHOL_NKKFpEBd8qNUV_NpZnDw,719 -babel/locale-data/ken_CM.dat,sha256=jNEojAAtQqJMkEq84kxHU5hGOVQCOW_hnGQScxycYMo,636 -babel/locale-data/kgp.dat,sha256=OKx1ZbBdHw75AdzrT-petm32Dj8wJdtUQH_oai7v0qI,184092 -babel/locale-data/kgp_BR.dat,sha256=FNSYAqPhkzoZzholxTydgasgkuw7jgxCfyKDbeRiLt4,636 -babel/locale-data/khq.dat,sha256=OcW4Zprt-WlTePo7DzquB-yS8vwfPqjaijpkrX5l75w,15753 -babel/locale-data/khq_ML.dat,sha256=ViqThOcZTHZBtebV8LJY-DXdWVX5jAR5pdlBrTKws2Q,617 -babel/locale-data/ki.dat,sha256=vffpb6Wy7TN__hZQH1SJYi81AxamhBnEK_XBCiF3OFc,15451 -babel/locale-data/ki_KE.dat,sha256=PNoxhP-WLxW2vH3fS8N9Nuy0tVimMP-ZAaCfLfnfDN0,635 -babel/locale-data/kk.dat,sha256=93jtpKcfiQBRbyeOyJgqETZXGOntosB2nGedgHShM1w,200871 -babel/locale-data/kk_Arab.dat,sha256=TBsZm6iLJ_dw2mNxDdQk95jELZ87mArNl12iktCwKwo,222820 -babel/locale-data/kk_Arab_CN.dat,sha256=HCoaBi32ENdpJx5usXdBR9aR__MHFeKV-wTo_53tQNk,635 -babel/locale-data/kk_Cyrl.dat,sha256=z3n_4vbUD_OcZhi9Tm8vkSu9h4RUgavZ_CFrujFbuWE,1584 -babel/locale-data/kk_Cyrl_KZ.dat,sha256=eaQW7Va1z2L34hs-D9QgrmyvOo4Lpy2uxxvxms6kL4s,635 -babel/locale-data/kk_KZ.dat,sha256=eaQW7Va1z2L34hs-D9QgrmyvOo4Lpy2uxxvxms6kL4s,635 -babel/locale-data/kkj.dat,sha256=IYeF4Uoeb0kfxooFLFcqmdIwGWbWh0MUfBpztTxWFEw,3373 -babel/locale-data/kkj_CM.dat,sha256=gqHwzVPG_Lo3svaIVe0Kfhj4DaKtstOxJJhUGvvpSbI,636 -babel/locale-data/kl.dat,sha256=D8SSjxLZliXOxyTxpC1x7jYbFQn4WbSV3lfotFFt3Jw,47570 -babel/locale-data/kl_GL.dat,sha256=c49k11GtBG8-vExsQNo_d1pFaQm0LYmXl7QcMSTEApA,616 -babel/locale-data/kln.dat,sha256=pldtRERWUhEOA85_zeFJfshpMl6gtgdELjGyNGtJzOo,17427 -babel/locale-data/kln_KE.dat,sha256=ZhkKgZ2lTdWAvWVOJEFlp4ASvjk2hcyTc2_P9s3mykQ,636 -babel/locale-data/km.dat,sha256=TueDML7PuHjlME0Bew9xgkFSFIxBOsJTzpMwyjyvuXs,176653 -babel/locale-data/km_KH.dat,sha256=bnykdq-RYJ0ZwajV5dFBVtM4anVkLjXutFdUxKByQ2o,635 -babel/locale-data/kn.dat,sha256=n0AHHLkpl4FIYeiSCEMDJF9mFr5nCgHcV8HSCOKz8yw,267281 -babel/locale-data/kn_IN.dat,sha256=rx1LJYeAP8xU6MIU3yhHLuije5OQWL_wzz5glztIdi0,658 -babel/locale-data/ko.dat,sha256=tYIinjTM5ZLw-AvWerUR8h4FRQ09LGfoRNyutl2iMLI,154621 -babel/locale-data/ko_CN.dat,sha256=U_q1api28ucaC-ABOBb822CgSq4nywhMN02uS7TCREI,1187 -babel/locale-data/ko_KP.dat,sha256=BCMOKQSzXNnjAUWfZZ8pbFoSDBed9tnnatyqIePNWio,816 -babel/locale-data/ko_KR.dat,sha256=CJqKij0oULIeCIG8McohdnhEsfJxUwmJHOpJY1bLrNY,635 -babel/locale-data/kok.dat,sha256=1pS0SXgetR-9DHtL71PAw2VIRp51a9KfxoSnw3BoxFs,179992 -babel/locale-data/kok_Deva.dat,sha256=EP15THeV74hd5G3DDXlwIHzxQvpECa67TioBGaur3l8,693 -babel/locale-data/kok_Deva_IN.dat,sha256=GiRy8Q6VCULzgIxNPFEZzABKOg13Un-DblBwXnBSeEk,659 -babel/locale-data/kok_Latn.dat,sha256=jVrQX1SeylbWO6B3ana7r9r1sRvMyOvBVwPfyXxB4uM,29867 -babel/locale-data/kok_Latn_IN.dat,sha256=GiRy8Q6VCULzgIxNPFEZzABKOg13Un-DblBwXnBSeEk,659 -babel/locale-data/kpe.dat,sha256=AHR_ZG1p518D4yulM_cs5E58iMsVXKk4Hi6k0V0IDhQ,1331 -babel/locale-data/kpe_GN.dat,sha256=7eabSFmszupn0IlzP6TRg1-7FZS9AB3JdBkDgJtIs64,1210 -babel/locale-data/kpe_LR.dat,sha256=4O2gzHn_orogC0qOiIyIox-JjyA73hEAe_fZ3Fj5tYc,617 -babel/locale-data/ks.dat,sha256=KySSApsfBfxM26TaXsK2gChd3noV1e5l41gUsaC3DA4,111691 -babel/locale-data/ks_Arab.dat,sha256=fzDL_rCiC-BqymPhF6GBX-d5uVkvZCE4e8JS2L8cjRU,850 -babel/locale-data/ks_Arab_IN.dat,sha256=-OE8PBigMDH8zQrxiaffmabm91Mi8-OVdDR2JEK8xPA,658 -babel/locale-data/ks_Deva.dat,sha256=weXN4SV8247g4MW8R7MHXM6sKk1qhf2Wmowls_zowAM,12510 -babel/locale-data/ks_Deva_IN.dat,sha256=-OE8PBigMDH8zQrxiaffmabm91Mi8-OVdDR2JEK8xPA,658 -babel/locale-data/ksb.dat,sha256=vbB4JVStmpZIu9_vi6f9-Dt40sN2wPvF9Y2JzJJ9oEY,15356 -babel/locale-data/ksb_TZ.dat,sha256=PvWBMUhpMhV27zE9BCEJW8oMqRXWK-6VwmSsXZDMTPY,617 -babel/locale-data/ksf.dat,sha256=IIgvqtnlTxMmLSk38JyZe0PA5gLEX86ZDcaVIULp7Zc,15952 -babel/locale-data/ksf_CM.dat,sha256=0OOsuUS0S_AUxUPySFQOZVbPcB3F2I4yzHZm63YypDU,636 -babel/locale-data/ksh.dat,sha256=M6W02xiGUibDW13RIB7psbwMA2wdNYQHz3Bp9XljhZ0,76781 -babel/locale-data/ksh_DE.dat,sha256=EhgYIJQaC3LGiWrcE2sdfUC8LOWJnciWORi_yoRkOvw,654 -babel/locale-data/ku.dat,sha256=beByrhXjB8iRhaNGxkQaxnUckutus3MJ61Pm-Ro8SqU,117087 -babel/locale-data/ku_TR.dat,sha256=LoNyoL-poYXgqejDzB9-zI_0TIJF3amwyzcs6UnHUII,635 -babel/locale-data/kw.dat,sha256=x5JFxfv4DvLd5Xnq5J7JlbcffhYNXwIn5-Jp3Q5QV5A,7242 -babel/locale-data/kw_GB.dat,sha256=ol7LWhJJFNoNkFEjtk4x1PpLkML9UbuVmZAuG47LokY,653 -babel/locale-data/kxv.dat,sha256=AMdZKJIlfkcpSetPdGRHX8LLN0O1s14NAtDzekSi01E,69503 -babel/locale-data/kxv_Deva.dat,sha256=MlejiNswS_LJAemj-vyEyvXc2SyminqNCWbaq3eceKk,86834 -babel/locale-data/kxv_Deva_IN.dat,sha256=Z43Yc1G4Bsmu7KukFfgXfIl1Cq2Rqa7RQQNYygE5Aak,659 -babel/locale-data/kxv_Latn.dat,sha256=XqtuF9yh0tBrDPoRpZj_1Mw-QUqt98klOlgZXh7qPus,693 -babel/locale-data/kxv_Latn_IN.dat,sha256=Z43Yc1G4Bsmu7KukFfgXfIl1Cq2Rqa7RQQNYygE5Aak,659 -babel/locale-data/kxv_Orya.dat,sha256=lsjWswZU3LWmYNE5tLn9cla-WSbdfqAoltC_OvxtR28,85964 -babel/locale-data/kxv_Orya_IN.dat,sha256=Z43Yc1G4Bsmu7KukFfgXfIl1Cq2Rqa7RQQNYygE5Aak,659 -babel/locale-data/kxv_Telu.dat,sha256=rXJrWxHMFrPeheoNt9NvKLzNoGLpNXiHpc4PsuS4tX0,88218 -babel/locale-data/kxv_Telu_IN.dat,sha256=Z43Yc1G4Bsmu7KukFfgXfIl1Cq2Rqa7RQQNYygE5Aak,659 -babel/locale-data/ky.dat,sha256=PAH_ov1xcnJAie5ltB3I_XAUJsrE_8tFwFlOjorRBts,179889 -babel/locale-data/ky_KG.dat,sha256=CdtjRR2iZgfG5pdz13MX-EHTDtN6BdLeZwGCmrZnrkU,635 -babel/locale-data/la.dat,sha256=0TAdiOxADg0C2AeIj5RRxiLgMbVO-PqRMf4GAm1M4dE,33982 -babel/locale-data/la_VA.dat,sha256=dhULocaXyJGitrljd1w688DTmezcmmY8YcoKsT30n34,653 -babel/locale-data/lag.dat,sha256=mtjtyLHLCfoUr4STtBqLXOxLnZ0igugTC9fZiyJZk8E,16281 -babel/locale-data/lag_TZ.dat,sha256=LlfEls8DDvoVp07MYnFdLBPUhkJs2kzwUDk45BZIO-g,617 -babel/locale-data/lb.dat,sha256=lUGm84DfwLgQ3vC0mL_foFf5dSZZKDTIuwCRf5BjgVs,135641 -babel/locale-data/lb_LU.dat,sha256=s0AY2-F7BqA4tMcRPjCfbzbXRbHsKnD6uIQGSkulCT8,653 -babel/locale-data/lg.dat,sha256=LnMo-qAcWHbbAuRmCTz4_nBGHgUx0aojWG7C8TFn__Q,15834 -babel/locale-data/lg_UG.dat,sha256=nyn_HKdBHGkHlbjlDX28L5Z9k59MKFqvmVL3vg222s0,639 -babel/locale-data/lij.dat,sha256=Ic982St82mPMfuQqqLswPtOy8LlglfcLYk_ftIDM65Q,129648 -babel/locale-data/lij_IT.dat,sha256=rtPerU7ltwkHHc7HErfwJfX8TDSCpTHvBzwKBdSt4x4,654 -babel/locale-data/lkt.dat,sha256=U_yXNWWJkqlepaZ9kS-FVOAHQKVmc0vhwgWgFRzXnqc,11180 -babel/locale-data/lkt_US.dat,sha256=ywWg9m80tNjumAxGNrBwYhXhc28rC4OSdyvkdXAKs5Y,654 -babel/locale-data/lld.dat,sha256=2JBQPu8T-cMVqzVOFs0Vz-0hU2RtHMyTvj0F8wPl2EU,95451 -babel/locale-data/lld_IT.dat,sha256=rHSiZg_-Ba6si2LONUCmQ841RxcX2p7V1jDSuwNNBg4,654 -babel/locale-data/lmo.dat,sha256=GYoR98Ap5hosG9bfENEA3sCkR-msF_KvxV2nLydjs9s,1659 -babel/locale-data/lmo_IT.dat,sha256=Xg4Qvye_hPNJLCTwoBuRMAvhtjQb8VlD9SaH_5hVG9s,654 -babel/locale-data/ln.dat,sha256=OHqUbo7M-600CtpOUNqq3B-Tt0_L3c2GgyR2xZhuMmE,23909 -babel/locale-data/ln_AO.dat,sha256=VNcFViSaGw3f92D60Uk7vxQ8i6Q9H1FD6paDpJh-r4M,636 -babel/locale-data/ln_CD.dat,sha256=Ao_lUWuswJgGHhVJYs2_Z8LyN4iqgYsAda8f9UarT6s,616 -babel/locale-data/ln_CF.dat,sha256=g5Jy7ovUkwcn0W5Ov5bu5SBc2iM4SWwUFwtzWzAAb34,616 -babel/locale-data/ln_CG.dat,sha256=jQld0yw63ufWbhlOt81wjf731zZluc2zWc1A65kBlAM,616 -babel/locale-data/lo.dat,sha256=hXtgT4nkqb8h669TsazfIFBsK23QNpcCZbqvb6SXWBo,189363 -babel/locale-data/lo_LA.dat,sha256=gNa7KRGYWI0h0PcHJ35bwnPskILOH-1jLjHCXP85jaU,635 -babel/locale-data/lrc.dat,sha256=GbK-bWw4TlGvGRyM4WxDujkUr7Gdz9k2A__fSelwEdk,13594 -babel/locale-data/lrc_IQ.dat,sha256=cy9DO9oAKI51NMitAb2MTbZoxtaAPzaYVGV0-xd0mGA,1255 -babel/locale-data/lrc_IR.dat,sha256=-ca4EmTX5VAi_5tDfimpevJFb-g8vAjgpe_jkDTDZWQ,679 -babel/locale-data/lt.dat,sha256=1h5TjFvNSuqrE3JntTmnLN9wW69jfkVakAIICcmoVbc,262613 -babel/locale-data/lt_LT.dat,sha256=j8dIQrFc0s77xJ4P-UGiDcaNqZW6CXOEiOh30FemNiY,653 -babel/locale-data/ltg.dat,sha256=qRaChoBWcmkL8As9MgCysSh58BP_F3US65EaA97ZgZQ,2632 -babel/locale-data/ltg_LV.dat,sha256=Gm8suGbSLaNGzzWPjuEKVdEqJH18ABue4htegryH3bw,636 -babel/locale-data/lu.dat,sha256=4TGAGkYbDHz6QAKQHHXoRkl0Wx-0LOiMkTjDgwJq0TU,15331 -babel/locale-data/lu_CD.dat,sha256=K3k0wMpIbjusgPC2W1q2sxyxynx2M78zOLjt4ikcoZA,616 -babel/locale-data/luo.dat,sha256=xJNSb25OVQogO42d-Jy2fR1FzeSfW9Swwt9Wat4EmsA,15201 -babel/locale-data/luo_KE.dat,sha256=jVUd3oO_U7IP6KmvSkVHYNmlCc8_-m2mpJMBaqArSFI,636 -babel/locale-data/luy.dat,sha256=pcTbaSctQyVgVVh4nXoXxMQGZa3Ip7hsfRN096zwEsY,15030 -babel/locale-data/luy_KE.dat,sha256=NVkQAtmDBXUws3KybnM706J3lwUc5fJo-YEjKd1zhiw,636 -babel/locale-data/lv.dat,sha256=s10obHsTYkBF99rADGvkxupv--JkRPQS2aM6sWvbM4A,201861 -babel/locale-data/lv_LV.dat,sha256=oS9W0pdiTNtMTeGOsef2K7Va2O6k-dQEtN02qCaAoFw,635 -babel/locale-data/mai.dat,sha256=Foj4spiHhuOjBZqaXQxZNCWwdCoslwB7KSX6nXQReu8,95488 -babel/locale-data/mai_IN.dat,sha256=DoclpHa5nlHcAflg286ycOjQ6trZP8uHThzcp37Y91E,659 -babel/locale-data/mas.dat,sha256=xxugbgGc3JxvM2GzV1vmKy1buszviy7NtSH-y6GdMZ4,16595 -babel/locale-data/mas_KE.dat,sha256=zH3Le4j03YNsPjt_-GL5RvPG0znnJKQ3ifbLhMZsoYQ,636 -babel/locale-data/mas_TZ.dat,sha256=VyRJlBqV_fukTqSR9Jxr-PujSA7u-MP9aXrJBVJCKiA,638 -babel/locale-data/mdf.dat,sha256=NQH9Yo77oyvxZj_93XIf0e00JDAoI2ydlCSS3klNgwk,2240 -babel/locale-data/mdf_RU.dat,sha256=sVnTxgzU2rEwl7P4d5UY6XOKv1XUCbtkEQO0cu2OlOk,654 -babel/locale-data/mer.dat,sha256=WFl2qQThWrilUbBaN4UJQb97ZrV3uOB4ZTO9kXsjtnQ,15426 -babel/locale-data/mer_KE.dat,sha256=WqDQTsO6BtbROdcj3p3omUZk8XB6HiJrIlCCj_wLPxo,636 -babel/locale-data/mfe.dat,sha256=n5lJPfd4pjC3xmVm123ivVpjg-WAkLQq9YONw1JlpTs,14835 -babel/locale-data/mfe_MU.dat,sha256=MHUOKiQPHuUbhT6hQXJEkpGDvTUyMV4btJTuiLhJQ4k,617 -babel/locale-data/mg.dat,sha256=9PbZhJ2v9RP2XSzwv7bBPTGlSNYJrUUISNkTwdF1Z7g,18776 -babel/locale-data/mg_MG.dat,sha256=uJbGeEzIn4Rh5Bh4hyV-Hs0_qez9KBeOi4hvfC3zkIw,616 -babel/locale-data/mgh.dat,sha256=ezIhzOd-qzUBRud5ZPjbtBBc_mON2HuKGu_okOahCbk,9753 -babel/locale-data/mgh_MZ.dat,sha256=aFZZ41qtARE6CeecCEx99tzW_fp-XfkAc10wpQ5YeGM,636 -babel/locale-data/mgo.dat,sha256=xyRaEmGV6Fw9nVfReQJY7KfgGwdnvQzScLiH0appsLU,3549 -babel/locale-data/mgo_CM.dat,sha256=Nsp33t4abZsKdDmIgB8tb08OsEh-7JXMY_JKCsd61zY,636 -babel/locale-data/mhn.dat,sha256=RpSxxevhvYxyX0dq1RAhIqoREyyPwKjsByXvOhQkAMc,693 -babel/locale-data/mhn_IT.dat,sha256=3UoH_l7yItN5qXKPaq6bWK_CvK_wD68zkxzLrCwxr9A,654 -babel/locale-data/mi.dat,sha256=ZlyyKSUJCtl7z94uIwEFuC6uBGWXOTM8F1TJLiJeSmw,85086 -babel/locale-data/mi_NZ.dat,sha256=RElP_P4F1HDHjSHsdt54vriFcz0TcIeT26pm-_dy-Mk,635 -babel/locale-data/mic.dat,sha256=Sp71dA3ZhTiiPTfk3b0Mm6y6CM0J-mGR0av-psrUGtI,1638 -babel/locale-data/mic_CA.dat,sha256=uZoBvRFux6M40HcGau7E6V0Pyxh45Bxi0SFngOxLWRQ,636 -babel/locale-data/mk.dat,sha256=xVJU-aubw2FQ_THzBUGd5LHR5IU1VjGkPOeRHpU-T98,216606 -babel/locale-data/mk_MK.dat,sha256=qlI1ZtLgyX2fcYS9pnTa8illdSnPmfNXORjws-H93lc,635 -babel/locale-data/ml.dat,sha256=tR0lt2uQuzmsBgXWIuRpz-AzD00S_OrvLc-QkiYAX-U,246736 -babel/locale-data/ml_IN.dat,sha256=VwCnSFs3oh7xo4-nS1HzWj_xICDzG6E-AW0Oxi6Lu08,658 -babel/locale-data/mn.dat,sha256=O3oSpnDd3Pt-dRrwdg1v245S6Iym3SBnZZ3gqOhQW5A,183647 -babel/locale-data/mn_MN.dat,sha256=qhJGIDXSglsa3BYCalsusoyiKgOj7PJ90Yi4ET2-nxc,635 -babel/locale-data/mn_Mong.dat,sha256=zqCuL28Sx1DS8LGqtC2nyTCoEpSFpF0vE3wvBxpHK1o,1726 -babel/locale-data/mn_Mong_CN.dat,sha256=WTF89EShdtBd0Vz62erFwl9KTG-GgEyzjjmKWuJCFH0,635 -babel/locale-data/mn_Mong_MN.dat,sha256=BTah7qfU9QayUb7evUKdF9c4Ptf4NqqO6SUeUql2Bak,12935 -babel/locale-data/mni.dat,sha256=aS_XIOmHRptFT_dTFuxgTvB2cEPKHJVVM_vtURTFo7A,12972 -babel/locale-data/mni_Beng.dat,sha256=7PTKZT_UE3WNiipyGHnn2SDNFNhAcqHhEJ8T0Y3O7gI,693 -babel/locale-data/mni_Beng_IN.dat,sha256=nAW_LfRtJqC6-ehdC8yyszjhibXqMAXPkuaz8POQav8,659 -babel/locale-data/mni_Mtei.dat,sha256=zdzwNyaRIil7lkjEf6ProQX0nwYlc5VF4r4gHNTUVTY,1720 -babel/locale-data/mni_Mtei_IN.dat,sha256=nAW_LfRtJqC6-ehdC8yyszjhibXqMAXPkuaz8POQav8,659 -babel/locale-data/moh.dat,sha256=FuywEiFRXQe1GUv9zPR15KOsZLr1TykmuglinLINTqE,1316 -babel/locale-data/moh_CA.dat,sha256=AXdrS_As8DrrTGs5IHmQwXoEXndFuoWoTGXPXcL4Pk4,636 -babel/locale-data/mr.dat,sha256=UG0FkufUtQ7qvzcK_WENRq6SgPy4zAcviYDQL-NrGY8,234157 -babel/locale-data/mr_IN.dat,sha256=HOu9QR1BLbciqF6BeTfWvD0L5Igwv5HrCWu9y_vNns0,658 -babel/locale-data/ms.dat,sha256=l_YQob4w4jdu0U-Z-eMYK2bPAyU0Xeekar0olT5G21s,114970 -babel/locale-data/ms_Arab.dat,sha256=9zretwvdo_9N3SIxLKsUtDVNZlmh0OhrPDxmtWqw22U,14359 -babel/locale-data/ms_Arab_BN.dat,sha256=vTEKSh0hjyiWJhf503-fwjADvTCN0AqRSzF6muL52JE,1335 -babel/locale-data/ms_Arab_MY.dat,sha256=w6ZZrz3qEmnsLsWtJA8rTohqF1cxctkzSj4WN0XHuHE,635 -babel/locale-data/ms_BN.dat,sha256=vTEKSh0hjyiWJhf503-fwjADvTCN0AqRSzF6muL52JE,1335 -babel/locale-data/ms_ID.dat,sha256=ZPgnDJgiycDHGZnN3Eg7OgZp1jIYtiZzMqm9f3LOtR8,3440 -babel/locale-data/ms_MY.dat,sha256=w6ZZrz3qEmnsLsWtJA8rTohqF1cxctkzSj4WN0XHuHE,635 -babel/locale-data/ms_SG.dat,sha256=jsfNag5WQWdejzh5hayA7_-IbY03MUVPAPDHUJyCZRg,654 -babel/locale-data/mt.dat,sha256=Xx_-as8jJEXOBAgfFX7vE6-2Qex4FWJ5rYW3DlCbu0A,49384 -babel/locale-data/mt_MT.dat,sha256=L5q5LizZQL0-FLj2U-wn2YhkpL3p7ZvjdyAvH1wwUG0,635 -babel/locale-data/mua.dat,sha256=N4zi8XyQdW_TmszNHQyn4zmia-MpCNWx_Vudoaj075Q,15861 -babel/locale-data/mua_CM.dat,sha256=Ib4K67KfndwGsoZDH0ehHA-F7V_SUj7q9VsK2juzaIQ,636 -babel/locale-data/mus.dat,sha256=zPqFwR9oCIJ0mA6evYwT75cWt_QBF-0eDZx1n6fmsDY,2722 -babel/locale-data/mus_US.dat,sha256=xcd4KKUIqBwSefSC0GGSDkvXL46eDWgWolJsGuSf654,654 -babel/locale-data/my.dat,sha256=9crk_2tyVPKBH_YWC_D0h8o1nbHH9k34e414JywM_6E,183534 -babel/locale-data/my_MM.dat,sha256=l53-D5YL-BbmLZYveFV2ISa4NcrSwTfKsRRc41Jd42U,635 -babel/locale-data/myv.dat,sha256=78-9U5eDf3V2q3Mj0MazIxh1n8sjyVjQ1O0Oyt5875M,16828 -babel/locale-data/myv_RU.dat,sha256=sncxwOpjfFkRASKHMP1ytKcjpF4w4GjU_JEVqXv84Tg,654 -babel/locale-data/mzn.dat,sha256=8Y5VGlzCxKXzBP5iFsyflLZSS1x0_3T8sqbwivfU45s,46144 -babel/locale-data/mzn_IR.dat,sha256=fjN1ek2fAzZyzFJpjX_MIc5oFOEqj7LS_SNdBOQS9ZY,679 -babel/locale-data/naq.dat,sha256=N07nsBSSEuNZ4feWvo7b4YWwbgjBwlxG9653O-OlhmI,15797 -babel/locale-data/naq_NA.dat,sha256=e5gAIOo7le-dVOAX_k2OW6gEyVfEUxcYDUJu_MBDY5M,617 -babel/locale-data/nb.dat,sha256=-bGHDSonSEdqfb2PxNC1_3jOHELm3CwV7xzEtpmWZUE,1330 -babel/locale-data/nb_NO.dat,sha256=J1UiN-AG900acMz4p0fBHtXDpS0HD6uGAi7gg9gOrsY,653 -babel/locale-data/nb_SJ.dat,sha256=XcK9_nKriUY_4k09kmgJalGTls-e5-YS-MCPEKLP8vA,634 -babel/locale-data/nd.dat,sha256=ITmP8mLDb63INBKlxe3yCZqRbvL83DrVBkIIAA_YjmA,15730 -babel/locale-data/nd_ZW.dat,sha256=KpZHrPr_0Ru0t9ojSK9ZiqGZ6-rSpvA7cX9C483ocRk,635 -babel/locale-data/nds.dat,sha256=q3dxEsEcdLTOigPQxhEXuaA4U03umMzIBNC4NkFvino,47839 -babel/locale-data/nds_DE.dat,sha256=Qmh5DjX65W58jXXXX3pxfxS_HVTJVavMspBPdph9sfc,654 -babel/locale-data/nds_NL.dat,sha256=E_EO3ylaBjJNThr211Yzefh5DRbkEFFVpbBMXIQ4U1U,654 -babel/locale-data/ne.dat,sha256=5Ob8IUrudfJp6yCzhHkmYC2mkVY1sd10I79pSXzups0,210152 -babel/locale-data/ne_IN.dat,sha256=SFloADZtyb42wygQmrMy7yx-aADGQECZJUey796oqnw,1292 -babel/locale-data/ne_NP.dat,sha256=LGc7Z5TRi0HRNQdY4bqPitV73gzTPWLd_g-6aPyvryc,635 -babel/locale-data/nl.dat,sha256=zO55PQW5wWMzjRmUGEi5l4H1D1rC90NQt262jbRIyzY,150031 -babel/locale-data/nl_AW.dat,sha256=HYycPPe5HDhuP_zN89ysXR2AqjIbx_-XB2n0-TUPhxw,638 -babel/locale-data/nl_BE.dat,sha256=xHmyTOK9-rwPAH6fYdlPFZv-xinmTFNRN-LIGxb59HE,1876 -babel/locale-data/nl_BQ.dat,sha256=lZQzrmWsFTpiWwT9l6FakrNoll3QNP3drIMcxFkAy6Y,635 -babel/locale-data/nl_CW.dat,sha256=doEeLSsQVaSocP4jr5LxNrT5luSiG4hkgsMvoYjJBtY,638 -babel/locale-data/nl_NL.dat,sha256=bGo4nyjhqe1VtDHlP5EUmNkBKsViUSiH3h_ikXcPuRo,653 -babel/locale-data/nl_SR.dat,sha256=d-YXA5QA5b2Bh-WhxNTkyKQ4ROhuEg1CeGN5XmzWcZM,696 -babel/locale-data/nl_SX.dat,sha256=ciTQIntv0njAJGIUENzo6stN8yarfh-eBpmEzxmpJbs,638 -babel/locale-data/nmg.dat,sha256=NEWUb0RI43oeWByH9l1FvrLDvVQY6501jviEYmM_CCs,15468 -babel/locale-data/nmg_CM.dat,sha256=0A-cVUgt1l1ITnPRdcgWiQ68ZGqHDYd-k2wSc_nXnMQ,636 -babel/locale-data/nn.dat,sha256=E-Y0lC-8QKCXdc8CC_ZPN3bstsXsM3MD4Lu62XMMq3U,64042 -babel/locale-data/nn_NO.dat,sha256=98eWK3CBq5T_dI4a6dQH2TktRygMH0EnpO1EO7w8lVY,653 -babel/locale-data/nnh.dat,sha256=cWTTqJEXln6pUYON7H4PRrYr_uRWktSzcLGCC8jnTno,3530 -babel/locale-data/nnh_CM.dat,sha256=dt9ZNHX5ZQo-kcyT4-mVRCUiuzL-H2A9e0s0JrHwZts,636 -babel/locale-data/no.dat,sha256=xxkSV9bwDKWKK6dmGIaZGo4snfkON9eJUp3-uvlEC1w,191212 -babel/locale-data/nqo.dat,sha256=VQzcAnkUnAETAL8xosXBsQltlC4yqpSZNMkwtsWPRgI,109412 -babel/locale-data/nqo_GN.dat,sha256=3eOSTBaZM0RNLUDZFr__KTR_9iZoGUFq9M6bhtmHjcU,617 -babel/locale-data/nr.dat,sha256=ZHIIC8BaR5XBmnULOTfmAYzXmqImq5QmELqbFPKKQJo,2167 -babel/locale-data/nr_ZA.dat,sha256=e4_czqcyMye0qthJd2hzn_9inTS8WjjbFOzRJ3wAS24,635 -babel/locale-data/nso.dat,sha256=dsq0mvwg5QK35al0bVwZGUL961EuGS05vlFR5qb4HwM,6470 -babel/locale-data/nso_ZA.dat,sha256=TdOqVTzKNigLD6zOPR7W7QHT-Aw40ylsUE7bmMwgaKY,636 -babel/locale-data/nus.dat,sha256=4G1Wwsq1yWIew4nA-QBo2j8LmbqBTRZ0gCU0LYLUSUk,8215 -babel/locale-data/nus_SS.dat,sha256=Is_mWvnSS7j05Vk9RHcCfyLOdhOeOWRqgXDf8FGNEJQ,617 -babel/locale-data/nv.dat,sha256=7CBom-BDX6Wk2o878hmZ8DBY8QAS8Z99ExdmdVpq-vQ,721 -babel/locale-data/nv_US.dat,sha256=ak7j2GDaOMbAAmXQhfC9PRM8E9h_hJZL3UDqxqjCtoI,653 -babel/locale-data/ny.dat,sha256=XXvyFcRnNcH9KcAH1K7jzS5xLFsXMlXVW3yowhXPIO0,2152 -babel/locale-data/ny_MW.dat,sha256=kyhkcpqgIwSrUcfxve2OS2P9S1AfXItRHmy94K7cQ48,616 -babel/locale-data/nyn.dat,sha256=nVlbaYbL0QCkpVvX2rYYUFRsuI8BOjcReljkcamobSY,15668 -babel/locale-data/nyn_UG.dat,sha256=fEm-RMI6-PvIjbMUoZK68dTaiAmOqH1iDQBn23a6r2w,640 -babel/locale-data/oc.dat,sha256=0GZZe142JNEQ78GP7q1Sq7ZolzkVuvuK-QDCpLu4Z6Y,66841 -babel/locale-data/oc_ES.dat,sha256=H-3UJZkJCacW_BELiE_wXsXSVHp-dfxv59o3Hed8uho,33273 -babel/locale-data/oc_FR.dat,sha256=L80Ivl6dUpQJF4fAY1xaAeCRO9BkN0l6oCr8nRwogsM,653 -babel/locale-data/om.dat,sha256=wbIQO2bCc4PnuCB14zg9Gw9XW3mlv8D_D0C39SMnAnw,67446 -babel/locale-data/om_ET.dat,sha256=v0wHN7iwcuJN-iFgWFPrGdplH6P-0c8B2OEqYOEeb40,635 -babel/locale-data/om_KE.dat,sha256=DZ-2HywpH9NGEronFox-2AprzyoSg0xJAS62LNqZxcQ,1365 -babel/locale-data/or.dat,sha256=bdzcLCC-BRprtZBlm8pvQhvGKe2zTqjQM1JPQZrGapM,226771 -babel/locale-data/or_IN.dat,sha256=ur6a2cCdapMoKd-6KLXR2xAF2YU8xaueeW7UTPL2yLU,658 -babel/locale-data/os.dat,sha256=2ARxbjnZ_WYF6VQTsvXN4epcXlWpkXaVEhUNOJpAv8Q,14821 -babel/locale-data/os_GE.dat,sha256=8NgIdMuGlNow1dXmjW6y4xOis1_3raiXcj_jLBPirpI,635 -babel/locale-data/os_RU.dat,sha256=76MsfCZxiy_RXfhW7Do3Z8q4-jhp1hOXTBIsA6SlA-Q,695 -babel/locale-data/osa.dat,sha256=Ob-cu1978hig_-zOnB-PJW1_496aZ_yT6S7VTFkHoEY,4538 -babel/locale-data/osa_US.dat,sha256=qFfjNw8tVOdprzqK2wBlGH4eNMxDxDQqDDReucJZR-E,654 -babel/locale-data/pa.dat,sha256=pMTu_1agUQqVCaM7VB5fe9wM45MEsfVkDyzkKp6UlUE,202684 -babel/locale-data/pa_Arab.dat,sha256=VBfuWzoA5UdGbWTTG3cPAYL0ApWSup5U9LWBBh4bGUE,3789 -babel/locale-data/pa_Arab_PK.dat,sha256=1Si67Mz8DZfo2D8Ld0b5IlZpvnSMgg4W8_zZLrHrWQ0,635 -babel/locale-data/pa_Guru.dat,sha256=fs7wqdmuGaKQCCwGkT3lRQSKmf1dxG3jyLboZeVtPmE,1276 -babel/locale-data/pa_Guru_IN.dat,sha256=kpz873B1I65nfS3Z5vDLmmGliFVPlPM58sB6jW9nkBY,658 -babel/locale-data/pap.dat,sha256=EzSKg0e-PaX4UNpqi0JTYSjLYwqljGKI-uJLjR1uWhQ,28121 -babel/locale-data/pap_AW.dat,sha256=XZSGzQPijHNf5GjxUjDJQt88iD0ETRdZSTF8gn-1U4M,617 -babel/locale-data/pap_CW.dat,sha256=Mu-gCfh3bv9pzz9RrylMffuphhqgiRaODEZm6TtCpaI,617 -babel/locale-data/pcm.dat,sha256=BPyAoOzA7PpWZ4G9w2NMBzu1JqtXwnZbeCSrLk7j-Qs,161833 -babel/locale-data/pcm_NG.dat,sha256=3gBp38NIuVEbHlKAtQPQXJjT3DKvy7zvUqMAZS6pGzk,617 -babel/locale-data/pis.dat,sha256=aCXK39YyoYqy97wCU2idxYXLL9cC7myCIiJZeKgq-po,1510 -babel/locale-data/pis_SB.dat,sha256=-CDkXv_877c__o56bBeYHAAq2X9CcnKdI65DiE61_M0,617 -babel/locale-data/pl.dat,sha256=zWkc9nD_Ipzoj-nuymRuCLdWD3dG_wQicGQE5NpjSLU,227506 -babel/locale-data/pl_PL.dat,sha256=3s2XpVyaKha_K9MesXKD6sZNGSn1PVRtuz9XYp1xrsg,653 -babel/locale-data/prg.dat,sha256=vsad78h5dkCtaL_Gc-AGmXy3cc6Od1j4WCPGBdX6Tt0,17267 -babel/locale-data/prg_PL.dat,sha256=5jT2Yeek_e_MpGShmy2v-0WWhzQkQ0WsJQlUYfIOcfU,654 -babel/locale-data/ps.dat,sha256=2Yvun7eRlWEkh6Om_QxdW3Hq3AwyYqoM8n0418VjcbU,158607 -babel/locale-data/ps_AF.dat,sha256=sNE6bgx_nV0VWKa8InelUaFYSa3Fpx6byJw0KT4B1o4,678 -babel/locale-data/ps_PK.dat,sha256=ZtzTnH2thc6-J5PbuMOq3lPu57kbqDFxO53s7BSdVSQ,7119 -babel/locale-data/pt.dat,sha256=6Db_e_tQGLJop802pMj8aeNGcuKxa9iKTCZYBNM4crs,183448 -babel/locale-data/pt_AO.dat,sha256=49hMN9AJBDNjcsQw-nl-jY_VKHanO0PGfvd--OxqOxI,1022 -babel/locale-data/pt_BR.dat,sha256=dVKYp9IwRMbjZ_ee-eXFPudSuTRrROvbFzY3dYTYmn0,635 -babel/locale-data/pt_CH.dat,sha256=zAvD0sYytEquwzY8ZRbVCcy7DS2ZzUXofl5qXOixZH4,653 -babel/locale-data/pt_CV.dat,sha256=zOQn8d7--PKrhRUhQ5mPKW1Km6Tyh5JF8hstfxpITzM,1039 -babel/locale-data/pt_GQ.dat,sha256=qI1hvtuSHOev12ips9o3Vy78NJpOMjhkW625M60lqZU,616 -babel/locale-data/pt_GW.dat,sha256=SRxbFDIg9FwEjGjutRI9P1SeLiZBqStwSqPuHBFZwLQ,1002 -babel/locale-data/pt_LU.dat,sha256=z9aq0BTWEnk4lXveNpmi89TKcXN_t6Ud4A_C97uyOuw,672 -babel/locale-data/pt_MO.dat,sha256=shItJIIDrxwlcQhWLhlZG0uhyTlSBDcTag5ivxmb9TA,1635 -babel/locale-data/pt_MZ.dat,sha256=UZ1nkXS9CpiCM1IpOG5XpGK2QqM5mE5lAgRLTGAWl-4,1042 -babel/locale-data/pt_PT.dat,sha256=_H5DG5pOSZR_5gjjycrMBKaOJd_euwJln1pa3MPd1Mg,96277 -babel/locale-data/pt_ST.dat,sha256=Cm2HUxlGtZaz8IXX5Ohms-HYuKgazuBcOZBz5rWOzEU,1022 -babel/locale-data/pt_TL.dat,sha256=CIIDM_Zo0xiu4gXngxYtkYK6ldTNZMRaikSD_sAokMw,1002 -babel/locale-data/qu.dat,sha256=UueUbNLnx5ZwsqJcvzKUTdK5_wKBOmR2haCj0zhd4RQ,93300 -babel/locale-data/qu_BO.dat,sha256=7RUvNrmuLtwqP-qab667GocH_c4gIvpas3dbN1uaGxU,878 -babel/locale-data/qu_EC.dat,sha256=_5V4RYoPb3eCAA7jOCNfB7WZqd9sWP1E0tlF8mGeqFc,837 -babel/locale-data/qu_PE.dat,sha256=Vdd0fcK2dtFgyui3Q9NElHuJ841RI-T5l2UHeBq8MQ8,635 -babel/locale-data/quc.dat,sha256=dIAxk2IuDZhWTj-NKC9PiHBZOnG9ARyANdJZUfoVlJw,775 -babel/locale-data/quc_GT.dat,sha256=8M8KtmnsJiTCaf-Nl5X174Omtyc6a0ri07kysDC3-5Y,636 -babel/locale-data/raj.dat,sha256=qkuyRruXTTQLDgijSA0Equfz19Aqg0p5Mg0heaGKT00,2428 -babel/locale-data/raj_IN.dat,sha256=SS8GPzJu5j6nfXlDoX4NFPN2QScl4M0YNsrFmWklymM,659 -babel/locale-data/rhg.dat,sha256=dHahMWjQ_tUshtlLauqf9b4Y36LNJFGrMBsVmjBzlqQ,4611 -babel/locale-data/rhg_Rohg.dat,sha256=DAOuwC-7uaIuZtrIXvUkYt6YkxqaKpHOma1m0-XTtrI,693 -babel/locale-data/rhg_Rohg_BD.dat,sha256=DcLSBtf_k_f6B102-vbhBOjfzNZjiTDvEUdIOQfVc8M,1212 -babel/locale-data/rhg_Rohg_MM.dat,sha256=HspZzbytcZQ853Jstp-eFEdqSMAD3-shgjrdxY_KQrE,636 -babel/locale-data/rif.dat,sha256=4KtUTy4D-OsLftEaIHU2fw1NUhx0pwJXXie51jI3X10,49902 -babel/locale-data/rif_MA.dat,sha256=Qq7ZdymuPdjHeYDUDGCjMuQBRU7w5qGdgzzZ6wPfN2o,617 -babel/locale-data/rm.dat,sha256=aQ4MmwhjJbBakV6-C-6yjDvN8jvVa8Mk0ovdYgVkR9k,95006 -babel/locale-data/rm_CH.dat,sha256=JHAlYXMD9Vks43cU_gcSEQmqo6pogWPl_R4VMUK2iHI,653 -babel/locale-data/rn.dat,sha256=LwQTzbFINNeIhU5qJsEnh-raxcCDXVMGA6ZL95aU9UE,16241 -babel/locale-data/rn_BI.dat,sha256=r5Cweh7L4EAZK-qTmJuloWc33iXeR4IJUbknrl0XC3g,616 -babel/locale-data/ro.dat,sha256=13UpR66j-nQg4kbgGH4ja6ygDq1k3CCErykEWeeG8yY,200714 -babel/locale-data/ro_MD.dat,sha256=pUZY970zkBSBpVOIA3Ss-6vDJUF3ZCEWYNs4_LXcpAY,2881 -babel/locale-data/ro_RO.dat,sha256=lLYIYWhDUmq1EZ9oV5SETauVa_5uNN5p52dW7XeemRk,635 -babel/locale-data/rof.dat,sha256=Yafgax503CHjHvrc_njDTMVOOD2B36sRvWvDE99geMI,15473 -babel/locale-data/rof_TZ.dat,sha256=I_qwGjqqrcwUR_3UNydHOm_EiiLZYyRV0q-s1qfSSi0,617 -babel/locale-data/root.dat,sha256=vcYJrDi6WVier8432VEhdQ3ZZH8ptAXszNP747aIiq0,51983 -babel/locale-data/ru.dat,sha256=8WD_7_Tz0ieaEjXNlFQy8xFSfCwsVf_CUcoHyFfqkgs,305832 -babel/locale-data/ru_BY.dat,sha256=99UlyhoMWnfyhI5ltXGaJkycWLVfJ3FwdxyRm-yr6kM,676 -babel/locale-data/ru_KG.dat,sha256=X-iAT1QuQGhk1mIetpGyWqDlwiBskLfwqrK6ant1XS8,659 -babel/locale-data/ru_KZ.dat,sha256=P1_Gn3esOwDLL8sd8vVYbFA8J7QEsaDAWfZvDsn-WwA,656 -babel/locale-data/ru_MD.dat,sha256=LU12oBwr7MfPTzfs8Dx7uUZVgHin8ybX_oPHrPIJTkw,654 -babel/locale-data/ru_RU.dat,sha256=IVG440mXjphW6iCsKysZCW1Gem_z5_O0lZI6-R3oG_E,653 -babel/locale-data/ru_UA.dat,sha256=WYPDEOUjHl7mtejs302KAURq_ckDn6CFjH-IwmiFF6g,1210 -babel/locale-data/rw.dat,sha256=1KiBkw5N7hioc-ESs0oqgdyOaVdOlsNp1iIz7g3k83E,8418 -babel/locale-data/rw_RW.dat,sha256=tw-gtzH64PeIAmNGeobgUypw7RAyKITeFAcQPGY0MG8,616 -babel/locale-data/rwk.dat,sha256=hCqo5glP1WqFJrEGyW6r3t43NZ7bVHAOGFGDkUzeM3Y,15369 -babel/locale-data/rwk_TZ.dat,sha256=s9duai8NRoHwn8YpQrlMd3VDf6jtQxxcUmu9CIIMzC0,617 -babel/locale-data/sa.dat,sha256=8r4iZXIQ3vnGxlSmOtDhwM-T_iaYN4SXuTSdGh-2JMg,15978 -babel/locale-data/sa_IN.dat,sha256=ABNamoPpYRbO7bK6BGm0tK92kd7su7_OP7Di0wW0zZo,658 -babel/locale-data/sah.dat,sha256=Qlb3HEv5JslfLAkUjLJz_XdRdyLhloQ9uf9q2b_O6jM,39310 -babel/locale-data/sah_RU.dat,sha256=jHlseiwMbtN-IsETeG2dsaIn6OB2kqtAogazMnn0f60,654 -babel/locale-data/saq.dat,sha256=grj85np3tZzXQmLdtYQcu76ynQv5Jq__KIyaDECFIj0,15787 -babel/locale-data/saq_KE.dat,sha256=kN94cJJt8AT0yBRDqUPGoJtMZdOb2e-83NNsq8hmQ64,636 -babel/locale-data/sat.dat,sha256=K_IKB3mSsOkYuYDtbGW3lbGjVk4ctB56WWkJJvE0-mI,66131 -babel/locale-data/sat_Deva.dat,sha256=0EHZ6UcxsVOfi399xQbOkzaH1OU4jkZ10uqmmWnK8VI,1943 -babel/locale-data/sat_Deva_IN.dat,sha256=Bzh9Vmzia_8KLAryt9VqCl9ter9tKxng4b8oFYbYK6I,659 -babel/locale-data/sat_Olck.dat,sha256=mszOmf6B29mFbE6qN6Moy6SfBjwsjaCsbk75dJR245Q,905 -babel/locale-data/sat_Olck_IN.dat,sha256=Bzh9Vmzia_8KLAryt9VqCl9ter9tKxng4b8oFYbYK6I,659 -babel/locale-data/sbp.dat,sha256=1qHxon8_TpGGnLHUBzy5cR1mCEnZmw1EuYz3QLgnT-c,15609 -babel/locale-data/sbp_TZ.dat,sha256=chWs0tZniO53SbtBquTHGS6E4v36tgYL2b3enxHcdCU,617 -babel/locale-data/sc.dat,sha256=ItaljMMLxOEM4DEG_yDNVk8H4AmQrq1xCnDE8AfRDDs,189970 -babel/locale-data/sc_IT.dat,sha256=0G0vL9YXZQLkTmnzJuuygM5ty2Tw5liDg_aWHLvg32k,653 -babel/locale-data/scn.dat,sha256=UKMqekdt_t_Qe_ebhg3eaRsTs37ECpWLEiWSCFjMTLI,70373 -babel/locale-data/scn_IT.dat,sha256=dTXZIHDRhbFDCw02T0wL1iaJ2kfY1ZUzfbvUs4_WKLs,654 -babel/locale-data/sd.dat,sha256=VDMIluqNpBChcALvjd2lGll6sRK6srAF7p2CogEgXlE,154300 -babel/locale-data/sd_Arab.dat,sha256=jgkaYGUhPXll1T7CT68ridccZaERHeZdwUzGoAZBUps,879 -babel/locale-data/sd_Arab_PK.dat,sha256=c3AXdatnrTNDHW_SOh8fNNye4CVey81FnkSXwj7MmcI,635 -babel/locale-data/sd_Deva.dat,sha256=ZZathBrGJyoqspPsHF769J84zQq1y62vN8RAjGj_Cms,13957 -babel/locale-data/sd_Deva_IN.dat,sha256=0KQFEKHV6hHidc5hxrxQEvhO-YyvFf5P5z6t9hPenH4,658 -babel/locale-data/sdh.dat,sha256=5cD8u88qanpCtA8kPvHH9AdAi2-HbhznORqis1PYx6M,1032 -babel/locale-data/sdh_IQ.dat,sha256=B_vUMOiGWVcD1HaR4Zk8XxVzcmMFSISe2vRscyA1lYY,679 -babel/locale-data/sdh_IR.dat,sha256=hwMmQnne41X_lyjbyNbQq34Lpkl91bAgoavPZRuozwU,679 -babel/locale-data/se.dat,sha256=JnN5s3b1OrcP7qmurb8Rb9NKc-ICOr_RmdFs2EBKoRA,54830 -babel/locale-data/se_FI.dat,sha256=9_VJ0wzYFPto0YF2Ge0qieFV9_DOVqqYnPjlC5wnAr8,44207 -babel/locale-data/se_NO.dat,sha256=nm5u2VQ3ne0SUFZtFqwsRa8Gg97Xn1OSxjoP2I-i_PU,653 -babel/locale-data/se_SE.dat,sha256=6M9OxtmQAY_p9fZ_6L8zqo6i--bo_X00cvhTDEbX_UU,694 -babel/locale-data/seh.dat,sha256=viFuK-Mg4wPnvTcrvL-iEzNqFc7Ri_VP_r9pC673SNE,15433 -babel/locale-data/seh_MZ.dat,sha256=Sv94DueqrM3R5RjhCdwrKZsnNdL1WpjLBg6QhBnoaX0,636 -babel/locale-data/ses.dat,sha256=aRW4cH7nGNS5S3B3ff7o02GqcIqn1mVbBRGg3NdxXUc,15812 -babel/locale-data/ses_ML.dat,sha256=y14qGwP_r6VxzJhklYIWfYkolu0OHB-6nJ4tvF7J-iU,617 -babel/locale-data/sg.dat,sha256=ERl6d_xd8JRnkG_D857gWi2xONyI-cEmzt-Un_hXbu4,16476 -babel/locale-data/sg_CF.dat,sha256=QCNYqo_5l2Sv9JUFEWF6YLDR3MknhgkyMz1mO5j2Gv8,616 -babel/locale-data/shi.dat,sha256=fuYtv_xjgmJ0-aAQiuWcJXZY3mpeq__hz4lnouEUyWE,21830 -babel/locale-data/shi_Latn.dat,sha256=aQrfwwcvkgPaWFSev9-3WgwQXhhXj1_5myuR-QifnPo,15435 -babel/locale-data/shi_Latn_MA.dat,sha256=X8cwkkvm2LjcClQWzHRxxmiA8P0c37D7P8lf6RO4iNQ,617 -babel/locale-data/shi_Tfng.dat,sha256=VjsR4oSiK9oFfdIdpaVDwNSIBvFbQ3Jvm63K24bRqk0,974 -babel/locale-data/shi_Tfng_MA.dat,sha256=X8cwkkvm2LjcClQWzHRxxmiA8P0c37D7P8lf6RO4iNQ,617 -babel/locale-data/shn.dat,sha256=awBFmgdlHbpKsnUqWZaGAQ-YbTPm9UWkJKMn9IdJ7pM,890 -babel/locale-data/shn_MM.dat,sha256=7VauV3cmVfAJz7kA76hsF3FdwM75CVjvHdjx6lCoH4M,636 -babel/locale-data/shn_TH.dat,sha256=QHPmr3V4GzTbb6QA5SDl2EsVzQBjpbaDP6OHfJZ0S0Y,636 -babel/locale-data/si.dat,sha256=iuq-0rbecyzhX0pRX5UYdgKKzrn09pkLucKursW_Z94,216775 -babel/locale-data/si_LK.dat,sha256=cWCgV9WmnEwIIsBmhsIVzSzbrV8hkkXaV1xH1ultlUw,635 -babel/locale-data/sid.dat,sha256=zyKwuzw51B0E8sWg60qJ3kO4rzqTtcNBRnH5D3Zm1mU,2176 -babel/locale-data/sid_ET.dat,sha256=vtwy9BuaZwb5A3XdIl-3mws1cEAVk4s8oKy7i-GnM9o,636 -babel/locale-data/sk.dat,sha256=u_TnuG4-zvLxkxQupdNvPS-TYi28xeiPxLit28hxwZM,218242 -babel/locale-data/sk_SK.dat,sha256=eMjPq18mQOAXvkJN5WV6lKEAPyt7-eleGme2pHHevgA,653 -babel/locale-data/skr.dat,sha256=Mrx5bET3kh5Gzd8-2J9Rm4_b_wPZTDoHuhcxqdYj5hA,1702 -babel/locale-data/skr_PK.dat,sha256=UJpLMmJJIM5jeI-tXWPBNX4Qd3WS2nTwp3bvJg5D3WY,636 -babel/locale-data/sl.dat,sha256=eEJU8du-WwCkCviFmusUqH8H6sMl2PHG_khSumUB3co,210137 -babel/locale-data/sl_SI.dat,sha256=3Hk2t-MUfAUtqu_Gy0_fTjOhwBUtxdnndQ7Kowg0qek,635 -babel/locale-data/sma.dat,sha256=BaBVbhsEPN9V4JGtMt2TpMdf0oIrL8Maxt2FXDIEEss,944 -babel/locale-data/sma_NO.dat,sha256=OeIJ-EJtvWH6z2dZ1Hv8QdmQC7M7r51t-_C6LD6ZyxE,654 -babel/locale-data/sma_SE.dat,sha256=M_zYllAUd2UaWvccZ6ShB9-Gd8JYzIEln-88Q23syaU,654 -babel/locale-data/smj.dat,sha256=eyHR5AZqbxxlTYhyxJfvTjpz_v6zfh3TrDtcDkCgTig,939 -babel/locale-data/smj_NO.dat,sha256=5fz-YVJEoXswvC-RdFcJWmt-EMGcNXA3c9j_pfmxqCA,654 -babel/locale-data/smj_SE.dat,sha256=7l73FEZcAemOwXSrfPB3X7a0cto3J4oM7AO9i9PMIBU,654 -babel/locale-data/smn.dat,sha256=LGkyaifqt24L0NeExCtzhg8rKEKnkfJNEKtt67B-ViE,40399 -babel/locale-data/smn_FI.dat,sha256=VRY3dbCyxEmDUTep9bQXDRldd5wSg4skqQpztnMXplk,654 -babel/locale-data/sms.dat,sha256=ylATYbrfu8SVEVdQRbC7dTSOKCNSX7O1gjS2wJXA1tU,6521 -babel/locale-data/sms_FI.dat,sha256=b-Mk20lC32xysqU5v6jGjDUYDZaMDvoMwWOZNdT5yuA,654 -babel/locale-data/sn.dat,sha256=FNTHDspBYVPY7Nse1haEc19O0Sf3btsqNWQFs2Zzcgc,16732 -babel/locale-data/sn_ZW.dat,sha256=8HnH2raHHl8PI25abODlThEhjIOGXJb_u7cyQd5YzZw,635 -babel/locale-data/so.dat,sha256=sAFkgMg-qaZYhHT_lyoaggZ8UM_KX1xbS4miB3l5KN8,166227 -babel/locale-data/so_DJ.dat,sha256=VWnaj_MuW4dJnlO84t60ySCvfJL7FXI4nIP9PTL5Amo,656 -babel/locale-data/so_ET.dat,sha256=EvRRqU4yQPMYhkEK8a4MR808fwKHmW7EvPvEJdjltnE,655 -babel/locale-data/so_KE.dat,sha256=OSiRggRZ7CTNmqiGOvW1W2Cw2RqjVESTVOdUfgVgWyU,1208 -babel/locale-data/so_SO.dat,sha256=2IPbOqSxQGB5FukQ-B-MEme9FHYn22ClXmAV4x08pNE,616 -babel/locale-data/sq.dat,sha256=8lTejyAm-94ixpS6Dly7NQSHNsamftqLIdO4OxPWqok,160229 -babel/locale-data/sq_AL.dat,sha256=MN2RvkKGG2PXjCRsMHsvcnwnIOOp9tNSpcInh2uCWaI,635 -babel/locale-data/sq_MK.dat,sha256=L_GaZJ9XuQMs0zw-xZlrefPF36SH0sJqMrdDDbwicZM,1208 -babel/locale-data/sq_XK.dat,sha256=qILZGRwAhuIBJ9xi_T5WTrrZAVouFjQSvybrwgXTsog,1187 -babel/locale-data/sr.dat,sha256=AAE3LN_CLRWzljEERIYedZepxLIDWzENkL4wmu8Ib6c,265725 -babel/locale-data/sr_Cyrl.dat,sha256=Tbo90CyBAWciKeDesPhmXf7sdBQfjWsmyyrKBco_NzU,1990 -babel/locale-data/sr_Cyrl_BA.dat,sha256=sKEcBX9G9OwCmIZEpTphQyW_LM4xoDGe90s_470_AJs,41992 -babel/locale-data/sr_Cyrl_ME.dat,sha256=rDZOf-zykN151tfgGiO1SUJiClzQ6t40gF927bMLn1I,2320 -babel/locale-data/sr_Cyrl_RS.dat,sha256=Tn9u1EvJAZZEIdgXloi326qjpq8b1N087nRQ9R1JbWE,635 -babel/locale-data/sr_Cyrl_XK.dat,sha256=qVevTILYnuaIjRyPy4rDTavVg-VXxKcZ5fVdh5c-aHQ,1574 -babel/locale-data/sr_Latn.dat,sha256=1joKXYRv5UiiT21s_Za6qE-VA8XpFi1HzYnVOjKpxb8,217950 -babel/locale-data/sr_Latn_BA.dat,sha256=of4wpeCglVK_Td6HnHUjHRwuFtCVtWj3kHb3nl4B0D8,32834 -babel/locale-data/sr_Latn_ME.dat,sha256=Mr0GNVLFIMZpBakd4dEUzJUlAN4nyX2BMAqydgtMzWo,2089 -babel/locale-data/sr_Latn_RS.dat,sha256=Tn9u1EvJAZZEIdgXloi326qjpq8b1N087nRQ9R1JbWE,635 -babel/locale-data/sr_Latn_XK.dat,sha256=wIz7XXQrRFYpzMpR_cgSWikPWI0ehSx5a0gRBgt3rFo,1486 -babel/locale-data/ss.dat,sha256=UAB0p3UMDn8KfBY32a7HVWXWpHlPa26Nr_Woaah2c3U,2178 -babel/locale-data/ss_SZ.dat,sha256=X-Va1uVrsPa1ZX5hwhQ-ME6Q_bovUb24XXFS8UQ87lQ,1208 -babel/locale-data/ss_ZA.dat,sha256=xwT3vZ4tmKEvJpVwFMV9U2j2FLF1tC9PEDN6MC6Qbf4,635 -babel/locale-data/ssy.dat,sha256=QyBWLhH_sreFEBHMQ7aiqBsrGvDeQHyYAKioqksa2iU,2999 -babel/locale-data/ssy_ER.dat,sha256=9CRIaVxgOMeMTc0tcV0Yz9yZzq_uD3g3ylZzqVpYzsM,617 -babel/locale-data/st.dat,sha256=b-jiK03L_9F4QqWW8qmRJ3UZntZDI9eMJglRho3MN7c,8016 -babel/locale-data/st_LS.dat,sha256=pSzdNm6-O5V6-14VcgF2iGNYQPFYIXQlY3SqUW3GcjA,1227 -babel/locale-data/st_ZA.dat,sha256=5tdUX7dxXEL2xiS_0IvHvqhKF-gWXFsi4supkP0RDAc,635 -babel/locale-data/su.dat,sha256=G66EuouIQrCxgKGW9JzPfMZ94NAN87P6REyULyyrFGw,11817 -babel/locale-data/su_Latn.dat,sha256=ievzq_m7eD5pZWLnVlH7oMIdeadf8GIMqEuVPJTBjyM,745 -babel/locale-data/su_Latn_ID.dat,sha256=axNaukDpD_-G-_4R7P1u5w4dh-ToRPN_Yo-QpC1cFRU,635 -babel/locale-data/sv.dat,sha256=RTvQ2li9cKHIEbVl7fI8ENVrmcCa1gERk3S9O2bHKmA,198967 -babel/locale-data/sv_AX.dat,sha256=QFGzIe9UCr5gCpgHunvdPiZ-126vP7GYORL9jjip9-E,653 -babel/locale-data/sv_FI.dat,sha256=Pn3EDh-VD0QJFWupEZ6w4TqAa-WC5GZ8oTA4oqLazvc,2526 -babel/locale-data/sv_SE.dat,sha256=c9PG5p2y_4rnxepGD4uOzemBU3EOQhQNO4BtUS1m3rE,653 -babel/locale-data/sw.dat,sha256=w0uX0MB-_bZQWOnbdyDVg1uRVe1j-K-egjRExoZpE8U,145419 -babel/locale-data/sw_CD.dat,sha256=W7Fw8Wqwo3_x4hWlssmWbVTj4hhSQmRv8c-VSnQdlg8,2577 -babel/locale-data/sw_KE.dat,sha256=YMNWSTJ8qxo0d1KvQwAN5ECRaZ9LGc0BDfX4enggVlc,47036 -babel/locale-data/sw_TZ.dat,sha256=I1bDbpEDiR1jkCgJ_W9fWCPuPxMhjQmwG3sIueKb-Rk,616 -babel/locale-data/sw_UG.dat,sha256=kuNdg2N_dLwUKFm7wSheL1wLOdyrukPxLfDw0PN7tT8,660 -babel/locale-data/syr.dat,sha256=ehEqE2rAN5_5X-4zoWys-oUwiajRRhwkGx-yd-kL4Q4,111439 -babel/locale-data/syr_IQ.dat,sha256=Mrw63eJwh0vRe3Lpj0vRf6Q4cUZXJcx9tlWkuAmMrss,679 -babel/locale-data/syr_SY.dat,sha256=l0Yl2UMjm_7kuzvoG2-KqBp5XR88gdjf1ZlpRRNFMuc,679 -babel/locale-data/szl.dat,sha256=8PpGSXa6ES6yxXD2YOBjG16b6BW9jDZo86RKB0MCNn8,88759 -babel/locale-data/szl_PL.dat,sha256=1D5dKaG2l2Haxde8uraWI2J5lzw1dIWGeJtBesua-IM,654 -babel/locale-data/ta.dat,sha256=RRIrxhZ9pdpGShIrQx7ZQBOPKWn15OGkeL8yQOy-tz8,277264 -babel/locale-data/ta_IN.dat,sha256=BOFaDBw7fc7C6xSSFYNfkhCgCUd7ydHprJ6u0DaneSE,658 -babel/locale-data/ta_LK.dat,sha256=Od6ln5oUnWfaAHwt_SDafWv844c7A7_7fTT2OPVTuyw,1208 -babel/locale-data/ta_MY.dat,sha256=PEUmjhs_RUr1R5kH9uHExdnG59Hy8LmbU18vXZYYPtA,1325 -babel/locale-data/ta_SG.dat,sha256=tbuefTSiXPMwpeV085Qp53l5uDHLsMMXmt8TPEG2fWY,1344 -babel/locale-data/te.dat,sha256=oRTQlv5dIZYav2aQWijvc2wm0VwoR1TwWUPL_qhzkuU,261668 -babel/locale-data/te_IN.dat,sha256=LICnXU-D0uhvxVpQ986Ul1JeAQktXaX53sXZSUY3L2g,658 -babel/locale-data/teo.dat,sha256=jJ-266Aw_zTeJjwGj_VASqzm6Y3CcQYkVPXKuV_kzT8,16012 -babel/locale-data/teo_KE.dat,sha256=S_lAg36VkA1w384kzPfXRLmJmGWfmz3ll7MzOQAtcr8,657 -babel/locale-data/teo_UG.dat,sha256=0WlDglms5bCe1AMwCqroaXpOXu9jQroxllMwXWLb8q0,640 -babel/locale-data/tg.dat,sha256=ErMv0Y4SGno9gTSJbhMVKZXiSe_KNSUFaoBeIDaP8tk,117163 -babel/locale-data/tg_TJ.dat,sha256=TCrsEipGp0reAS2mAvwT58tyzBnYJfL5oNHWpEe1ttc,635 -babel/locale-data/th.dat,sha256=lyG_l3_QzfpnjCv8LVaRTvpvfImkVrqcDoUKrnXlIR4,215576 -babel/locale-data/th_TH.dat,sha256=_QhA0WcHmW6Cr_-gU9e6cdpzTMDT19WyHas58fWDUnc,635 -babel/locale-data/ti.dat,sha256=K4kS476YQonyQifjLpS4UkE7hNa2k5aIDBJRIdh2eDg,214273 -babel/locale-data/ti_ER.dat,sha256=m9w0P5TPQ8IqpWKldwdfnw5_1Upv09AjLdO5WUbcRic,962 -babel/locale-data/ti_ET.dat,sha256=q0b9svPg8aj9xmbXr7F6fPHqeTJmclBl5t_hqQk7IuU,635 -babel/locale-data/tig.dat,sha256=cgqxy3wiehP8yceqa5-mrJVT23IP_bjlkeUOEvxspUM,13481 -babel/locale-data/tig_ER.dat,sha256=OoQ0U6yyzmjKwDtzLUpqR09h_ZaGvzXlp7t-HqNxmm4,617 -babel/locale-data/tk.dat,sha256=z5i4kshTasDEolkNpqXnzlZh75EgbAhL0ylT0_0oioo,164932 -babel/locale-data/tk_TM.dat,sha256=lADxEQoz-_ImDBmpCFUqDPuZ0ozVUhZKOQF2ZwyXVlw,635 -babel/locale-data/tn.dat,sha256=LgoZgcUCS4t_RsyQQKiVsJ7Kbs7HoInZAMndRk6DUCM,8596 -babel/locale-data/tn_BW.dat,sha256=jWMFP1tw-o7rslHAlAIgjEXflko8UCDNaSuQ8ccvNHI,654 -babel/locale-data/tn_ZA.dat,sha256=S3dMOsYSpBwkUv0tW9q0kKawQQl6yx77LexAL5wQqDU,635 -babel/locale-data/to.dat,sha256=CBr6gRgu0qo_-kIoOluPwu_ZdH4-SPPJHto_ERcDzHA,145255 -babel/locale-data/to_TO.dat,sha256=jcfJ2Pjof8jGE4q1y5LHSP9rb4IanN58kR7OgG8d5Q0,616 -babel/locale-data/tok.dat,sha256=kuSPgVhnv8Rr55G-epQDVyh8FfeKxJbd2J0hierJdUQ,8870 -babel/locale-data/tok_001.dat,sha256=PPUMevT2TBOGFSq-U-AccYkLHSbkWnBRDvxtpokTCD4,693 -babel/locale-data/tpi.dat,sha256=mqTAJweAOy1SAH2l4mJAKktX-ZeAdvTC8JnBPxXjB0A,4030 -babel/locale-data/tpi_PG.dat,sha256=uZD_c8yCtiYwt2EO2VOYPzhSTqWMQBOJMCuMCXe3Css,617 -babel/locale-data/tr.dat,sha256=ULbjOvmQqcT1Z2_8bBOe7LzwgBUg3LWM2MiLkmb8M6w,150824 -babel/locale-data/tr_CY.dat,sha256=3EmCqxcPvFuZcHCzpTmHb6pjtPwqQvwCfn27B8rtXNw,1227 -babel/locale-data/tr_TR.dat,sha256=7lS5CMZw76SVlMJxsmIJW5IfL7k9t8MrfKcnElqISSI,635 -babel/locale-data/trv.dat,sha256=iEbFtCCE_U5rmjAv0Pe5J_UigixMKq1cPIThdZui1Lg,9404 -babel/locale-data/trv_TW.dat,sha256=CTQtGdDW4Z0n2Ckb6B63HgEwNE44YTFnJCetwd8q9GU,636 -babel/locale-data/trw.dat,sha256=1e1LGCtVq79RclEMJbgRE4ATdqflV_KDHxBwInSfAKc,110107 -babel/locale-data/trw_PK.dat,sha256=pBHdOulrwRLiQuC96g8ilUzpKBeG6kglBqUXB8MlURA,636 -babel/locale-data/ts.dat,sha256=p7EFPucK9HkTVXeNKTU00s-Oas5U_HCPGX9hqT15p9I,5522 -babel/locale-data/ts_ZA.dat,sha256=AByEO55W3DVVOBIBxIp1F2QwY01-5v6v8sDFOGSxCF0,635 -babel/locale-data/tt.dat,sha256=X-J0BKEHy01aoARwwb0SWDuNm1lZFrT0akKrzBZjHPM,111014 -babel/locale-data/tt_RU.dat,sha256=cmv2MzolKOrsRoqQcFZGcXQj_33dLWGh9oUjnebCnz0,653 -babel/locale-data/twq.dat,sha256=nOSN5UZAxcCgdTxQFh14Cyk5K38olCyAuT6MrVW5PeE,15509 -babel/locale-data/twq_NE.dat,sha256=y8xQDxMtyStWC83tm_JiekFxAY0Fj-CWWdmic9GBwd4,617 -babel/locale-data/tyv.dat,sha256=y90_CH7Yksd1Kuc6KhykhpkdGVLUgFDV-B4oSxGqn5E,693 -babel/locale-data/tyv_RU.dat,sha256=vP_6cjMLB8I8YL7Nqrq4Gu_AWGFuANbZSdBc7ORn_IA,654 -babel/locale-data/tzm.dat,sha256=wYFO2vX38bht1nAdcVA7dxKVMh-3yC5sItggFaXkKBo,15436 -babel/locale-data/tzm_MA.dat,sha256=8eku_7voAqAjN651VYKCuIWvdYGOScCyqbt1rtSVO_g,617 -babel/locale-data/ug.dat,sha256=jRJJxRRKuYljj6kYicIhxWk8ySzpMT9AOePaBk3EO94,117801 -babel/locale-data/ug_CN.dat,sha256=2UselU1_d6K7NgQj0EDnDfb4Llk51eQZ7z78oYE-Ywg,635 -babel/locale-data/uk.dat,sha256=b8iEhvLdQxq7rtlqpx1c9vp6-n3jNGPGSuBWNhZAnFA,339125 -babel/locale-data/uk_UA.dat,sha256=usJw_J4Uu9OD9nrUxNQAx6vMJBWDjbGuc9l7ssJAyuw,635 -babel/locale-data/ur.dat,sha256=RTL85URWDMA3albZQODUCbVTA9oxeYXo5kWtuL1XW6g,167002 -babel/locale-data/ur_IN.dat,sha256=9GV9YIa7Mftq14Po2C6fjMG5sWkU8J5LS5bq1iIcsHg,10550 -babel/locale-data/ur_PK.dat,sha256=EEAGl6fLd1-a7X0n2PwRxlqwYZ0a0ELm2DuLII9spX0,635 -babel/locale-data/uz.dat,sha256=iwj3ukxb4FK0rZYtC66ftQmTtr1SgTzy12Wu3KkQYQo,138052 -babel/locale-data/uz_Arab.dat,sha256=wt8BwimSNmoFzrnduGDXMHhqj3B8-XqqN6ghg2Xm74A,3814 -babel/locale-data/uz_Arab_AF.dat,sha256=68eUCR8KeB0QDQRCvNMiOIkZVRozGKFTDednrQL1X_Y,678 -babel/locale-data/uz_Cyrl.dat,sha256=RpmyW2YhTwN_o6sKyfJxcktFI6VMqkO6YDzDE8XoOTE,76581 -babel/locale-data/uz_Cyrl_UZ.dat,sha256=MWJtHPdj_pF2h6abRP4wUwDWAUF4-zr7jBn2RQcZ0z8,635 -babel/locale-data/uz_Latn.dat,sha256=L5H7Xfz2Ho-vMqviRPC4ai0MnqoF9CIebiq7muISvSA,1292 -babel/locale-data/uz_Latn_UZ.dat,sha256=MWJtHPdj_pF2h6abRP4wUwDWAUF4-zr7jBn2RQcZ0z8,635 -babel/locale-data/vai.dat,sha256=T_MWlDAfbp9qgeArFd8yPDPbyThU15kFu19QTQqAlCE,17416 -babel/locale-data/vai_Latn.dat,sha256=MecJYJumVm7wCyCo-YeAY4eAon5WZ4ZqR0shQ3Pdpu8,14255 -babel/locale-data/vai_Latn_LR.dat,sha256=LdVmBAL7nzDp-Ab_uHidBAi2crIf9nXhf8tBNfa7xdI,617 -babel/locale-data/vai_Vaii.dat,sha256=l_IXC76zzJ2lPLfWfjWzSw6xVtFwr-x8LofcHQsSG_0,693 -babel/locale-data/vai_Vaii_LR.dat,sha256=LdVmBAL7nzDp-Ab_uHidBAi2crIf9nXhf8tBNfa7xdI,617 -babel/locale-data/ve.dat,sha256=5bInQioXkePSDbBerQqf4sYPTiB9-zpKuDokCXX5eNA,2372 -babel/locale-data/ve_ZA.dat,sha256=uJndHi9RMKtDWd58f_Q3g5WgXjL3W7KLQj91rVueabQ,635 -babel/locale-data/vec.dat,sha256=zokLfsgTK7cSP4KaSV8EMpPlHiOkI6tG3rWM7o7vcAM,160413 -babel/locale-data/vec_IT.dat,sha256=mC9jRfk9ndmkpRIpWZNCwdMwvxvB6QX6_9HanawdaUw,654 -babel/locale-data/vi.dat,sha256=F95a-fvLPIeJqOlwx4gr9TnWZ0VpSPyzNwJ0RPc1qE8,134138 -babel/locale-data/vi_VN.dat,sha256=cGwN0vw-qIaeA2g89U97N1xHSMmmaIVNPCLL2P_QJMk,635 -babel/locale-data/vmw.dat,sha256=mhERiGM-732X9KO0CThGEyjFtSbquT1_rmzYPnru2SM,1796 -babel/locale-data/vmw_MZ.dat,sha256=sz0j5RufN9oAzTalcjWNhKtCoEXzeRr5Cv6qCouK45E,636 -babel/locale-data/vo.dat,sha256=werwY25uwomUcf9q1dyQ8Rwgg2aCoLp78XUzBeSw0LY,4609 -babel/locale-data/vo_001.dat,sha256=iF2xY9XIdxC0mOYEp9hjYZp2EG-si_YaNYXri_60-4w,850 -babel/locale-data/vun.dat,sha256=VGNPlnoRipnocGYPgeb39d9MmE6fe5nTMWtCk4m1AEY,15373 -babel/locale-data/vun_TZ.dat,sha256=YKrOeOS1VnU3BWQ7HWtxjS-gMKJcKAPQLf4HTgkzf70,617 -babel/locale-data/wa.dat,sha256=1r6krApI8oecIKQt_9RzbpwSN0LcWSjlG34Y9Rfh07Y,880 -babel/locale-data/wa_BE.dat,sha256=j4YADQloo07Oek1j3aOrLYkzcFkrViS1UdRrA0Z56-o,653 -babel/locale-data/wae.dat,sha256=qBKStFqpkAruVDgeZJvX6U0X-hq_NkETTqgR2e7A4UQ,29641 -babel/locale-data/wae_CH.dat,sha256=Z0Wzu5Q9IVTnLGwWu54ozVx-fgnFz0IE3yrky8Y1IkQ,654 -babel/locale-data/wal.dat,sha256=AD9ZfdNNjEhX2n9T0ykd_XwEbXK-wxmsLqq39O4BjWU,8406 -babel/locale-data/wal_ET.dat,sha256=tNjeuU4GPTWtDmsroGmi4VUql0dA57v1tEtDF4rslVg,636 -babel/locale-data/wbp.dat,sha256=kzXK04f538n-PrJl6nRKIaYHMid6rJ4ACmzPcCz7NgU,746 -babel/locale-data/wbp_AU.dat,sha256=BT2E1-WiomuRrteCzN1_AfLyDUdEOm0ehT5miAiepBQ,636 -babel/locale-data/wo.dat,sha256=iB86SoTMrnphiHy_om1Yxs-J8L5YFWYlbmiQjK6jc2k,61849 -babel/locale-data/wo_SN.dat,sha256=fvlwe-ImWs04fsxSjTsXf8IPxEIiEi45BX8xhoBC_yg,616 -babel/locale-data/xh.dat,sha256=xRy095MO_brgAUoDB3UKwhgDvOkBlhJ3cWj9dM2fvHI,64334 -babel/locale-data/xh_ZA.dat,sha256=9p6wHW1sxOghJMAgsP6BC3RdUhuvLpHoCkqvjsCmPps,635 -babel/locale-data/xnr.dat,sha256=Ot10zi4F4H5Yqx6kIJGPay65Rm-Gam2eJ7kAOgoJoJ0,142585 -babel/locale-data/xnr_IN.dat,sha256=UbNwudCNihEFVZu3ymanDhJ52YoupG0SDGwmDByPhzQ,659 -babel/locale-data/xog.dat,sha256=V4U36ibPCWDoUMf31-o9mDCwylsYU0nZEx5pt-MWecM,15866 -babel/locale-data/xog_UG.dat,sha256=bMX0Tk5zS4P2LqlOLLpVP4nZxBFhS_qc-ndXjilDCNI,640 -babel/locale-data/yav.dat,sha256=UupgFFmPVcV-IgY3Fd8Y9GoOcOWgY1P22ZHuA-4QSMU,14543 -babel/locale-data/yav_CM.dat,sha256=CsaKwep5CARetyBX-JXHFvUVsFe1KTN4Pyz1Wh7NTHw,636 -babel/locale-data/yi.dat,sha256=OWr2zb3k_toEmkSXcPweqE13Tr5RhvlMm4z358uCQiY,24264 -babel/locale-data/yi_UA.dat,sha256=DesjWHTuxEBrjOeq8c-B82j4Hnwu0ElR2IH3fZPmq-A,635 -babel/locale-data/yo.dat,sha256=iWLg-08Fk9QJLZPuokgbCeXkyfyQNaov51TT3i1pKgY,110427 -babel/locale-data/yo_BJ.dat,sha256=CP4B5N8cEouMKth-iCTTBEN74dEpdyZQTJbrbYayZFs,50036 -babel/locale-data/yo_NG.dat,sha256=BEIndIiMT1Mo18S5DAWpjefthptCVQkIPeVs0umSop0,616 -babel/locale-data/yrl.dat,sha256=2nwDuw5Q_dL4H2Oxl5ClzZU2Uw10j-koP5RgfnJ67y0,186854 -babel/locale-data/yrl_BR.dat,sha256=aUgLCNwgEORk2wtuez8AqkYahB8_mX41IWSqogt39YE,636 -babel/locale-data/yrl_CO.dat,sha256=pT0rllDKHZAUIK_itrkWP7irmih4im131Ume_wKzyks,9211 -babel/locale-data/yrl_VE.dat,sha256=_Tqu_pGUkzrd4M9SKXpn4g93z7Q5xlUMAtGvROS5x6M,9211 -babel/locale-data/yue.dat,sha256=lvTaoHXSVZHqcb5UCR8IeDiVRCE9IRsrDkhv0bGwzCg,143872 -babel/locale-data/yue_Hans.dat,sha256=ybTM8LU-H-QunhqnLmCQ9bE6zdsYMJPHdlh_hBv3AWk,145194 -babel/locale-data/yue_Hans_CN.dat,sha256=MOZnu5r0xokf672rwAXfgzG3VEeTfNlDbu36fR1bB6I,636 -babel/locale-data/yue_Hant.dat,sha256=76wefuhsGIjk0jT05KSTEU_pbb7AfNE2u56jdRoJaDM,1306 -babel/locale-data/yue_Hant_CN.dat,sha256=MOZnu5r0xokf672rwAXfgzG3VEeTfNlDbu36fR1bB6I,636 -babel/locale-data/yue_Hant_HK.dat,sha256=eMZ7mOTEyKzQz0MDIjvP_Z57CS9nFIP4-Uf0Jpx1CY4,636 -babel/locale-data/za.dat,sha256=5EbAmE-qqvt_e4geaFxBGJi81CVoZFK4dCcJ346P4yU,12705 -babel/locale-data/za_CN.dat,sha256=WzhnaughSM1C1twuKYBVrelLEer-guzT43a9yBNXCsg,635 -babel/locale-data/zgh.dat,sha256=Q2D9KQFgDfWk4fXOdEbPcLq3yX_zxjhlK_PVI61Ok4U,22018 -babel/locale-data/zgh_MA.dat,sha256=sV8aPBmHY23lKIzsRna-tPz3UiXoKCMQ1Ur2tCyx2YA,617 -babel/locale-data/zh.dat,sha256=SpSkmdVN5PX7CCdso1B-SyQZKMDTyZfZeT2l_kj2FoI,152100 -babel/locale-data/zh_Hans.dat,sha256=-wR64b65stjA2KWj4GWcBWiF3yI0A24p4K7wApj8qtc,1305 -babel/locale-data/zh_Hans_CN.dat,sha256=zz2qPpWEP9ba12T9cGsPXGI7Bg5LcmZ3NkAMiVTf61A,635 -babel/locale-data/zh_Hans_HK.dat,sha256=yPyZyU-xXSNyU1FYJIYpWwnh0d3uXOra9V9aj2j_YQU,3621 -babel/locale-data/zh_Hans_MO.dat,sha256=08kUXwHOXA0pRA8qIX7e4p0Nzl1XHSBjwhMh7f-nZBE,3752 -babel/locale-data/zh_Hans_MY.dat,sha256=iEFxl2XEm1zBzd1K0wXpiZFvU7l0UrNURh2p9DZdRLU,1300 -babel/locale-data/zh_Hans_SG.dat,sha256=OHZNiUfnteSXuzel-lZAMVgv58iiVTNhjq81T9Qu94s,3948 -babel/locale-data/zh_Hant.dat,sha256=31aRGt18bl6MdiI9iAozwltdkSQQ370TvzI8gid8CBI,154802 -babel/locale-data/zh_Hant_HK.dat,sha256=NXPCE_4pYgLatoeKLdQ0d8PQ-Mk_GeMF1s1JYX9m27M,49152 -babel/locale-data/zh_Hant_MO.dat,sha256=qCWPPEr87U1aemaIuf6nCYQ-Q3w_1HcXrYoncYVBd3g,657 -babel/locale-data/zh_Hant_MY.dat,sha256=3n4syQpQ9sXVe82sOEH7yQIdrU3dAtMhp7fEhzGN8_E,1203 -babel/locale-data/zh_Hant_TW.dat,sha256=5N4K8I3XG89knCaSoy97HGzTVOTiUcd_VmfvNJlA4Bg,635 -babel/locale-data/zh_Latn.dat,sha256=-wR64b65stjA2KWj4GWcBWiF3yI0A24p4K7wApj8qtc,1305 -babel/locale-data/zh_Latn_CN.dat,sha256=zz2qPpWEP9ba12T9cGsPXGI7Bg5LcmZ3NkAMiVTf61A,635 -babel/locale-data/zu.dat,sha256=e48g3oI1FjkROV3yHZ2GAwn_8wr2y3dMkj98NHW4X8Q,138626 -babel/locale-data/zu_ZA.dat,sha256=jHloBfkNbQETXgE-3xVxvESitWb994_-SoY0G4_JL5E,635 -babel/localtime/__init__.py,sha256=_6ed9ZDImaEkVQdCbNitxCvRS7Cljpa5wsah0fl_628,1043 -babel/localtime/_fallback.py,sha256=kBPMTXycRen_6lRxSj-VCGcXmzD1gklJpJ7ouxGLuMU,1207 -babel/localtime/_helpers.py,sha256=ZmLc8m46W-3GtsstLBdrw6BU3ZhSob8vKHkxgcZG9uw,1704 -babel/localtime/_unix.py,sha256=63rA_pJWM5FEKpJ3XAChL6Eosu5k-tla7C6n4mBkpyQ,3902 -babel/localtime/_win32.py,sha256=nSNnxSMOVAlvqvX50h9HSCzBfP7mj8njJ80JZ3pOIWk,3211 -babel/messages/__init__.py,sha256=1maeVkLsWdXYovEAxGOcGlNHM80PfphZmmivZJo5yTw,349 -babel/messages/_compat.py,sha256=DNyCNMwH5vXgl_pq7cUYz3VcRC2gIPqeQLO5nN5neWE,1163 -babel/messages/catalog.py,sha256=2231tYkaywOeeb96nxm13aT9rLU9zPCqyA-hedf_QTc,37802 -babel/messages/checkers.py,sha256=VutlPZQQ_a4CqsGBNrywgC5QyW5yOhGpwZ2T3lNemqY,6219 -babel/messages/extract.py,sha256=NRMXMPjsdzirUdmgT3SFWkeZnRQUpj3VGcUPX7AxsPs,34274 -babel/messages/frontend.py,sha256=WsxpORPikJ8uhu7TM290y6d7Vxw35edYeGBlECLNkss,45408 -babel/messages/jslexer.py,sha256=6nGIZfX0dQlY0wlJ1zy5yWwoOaELY_ZWV26a5uKdsIQ,7207 -babel/messages/mofile.py,sha256=Qf0X-vIRYTQQpSJqWFY3nXPgCzxyUWAzrtle2fIpIPU,7265 -babel/messages/plurals.py,sha256=jsEnofU5b4PZKIloX0MjchYSxD3r1RRZ_GfEVRuETWQ,7495 -babel/messages/pofile.py,sha256=lMllxTXYRBa3m8wVsxXsJsayjCOePKYYZtFSZU5DVF4,25955 -babel/messages/setuptools_frontend.py,sha256=m1l9NHuawj1pSncZeC82cUJfdwxib_C7JSUb_2EhbUM,3485 -babel-2.17.0.dist-info/LICENSE,sha256=eAGoT-gRJ5yzUL20-xj5TDaxjvgT-mqsBDtsbTlITQ0,1531 -babel-2.17.0.dist-info/METADATA,sha256=xbADd4FX7x9g3Jol93V9dBRbALmMLlTVcQCDcl12nnw,2032 -babel-2.17.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91 -babel-2.17.0.dist-info/entry_points.txt,sha256=Y2Cr1P3E8Yt7kqzvVz4wnTvD1H3-BVD4FOkVqHIGBfc,750 -babel-2.17.0.dist-info/top_level.txt,sha256=mQO3vNkqlcYs_xRaL5EpRIy1IRjMp4N9_vdwmiemPXo,6 -babel-2.17.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/WHEEL deleted file mode 100644 index 505164b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.8.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/entry_points.txt deleted file mode 100644 index 95235a5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/entry_points.txt +++ /dev/null @@ -1,20 +0,0 @@ -[babel.checkers] -num_plurals = babel.messages.checkers:num_plurals -python_format = babel.messages.checkers:python_format - -[babel.extractors] -ignore = babel.messages.extract:extract_nothing -javascript = babel.messages.extract:extract_javascript -python = babel.messages.extract:extract_python - -[console_scripts] -pybabel = babel.messages.frontend:main - -[distutils.commands] -compile_catalog = babel.messages.setuptools_frontend:compile_catalog -extract_messages = babel.messages.setuptools_frontend:extract_messages -init_catalog = babel.messages.setuptools_frontend:init_catalog -update_catalog = babel.messages.setuptools_frontend:update_catalog - -[distutils.setup_keywords] -message_extractors = babel.messages.setuptools_frontend:check_message_extractors diff --git a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/top_level.txt deleted file mode 100644 index 98f6593..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel-2.17.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -babel diff --git a/extensions/.local/lib/python3.11/site-packages/babel/__init__.py b/extensions/.local/lib/python3.11/site-packages/babel/__init__.py deleted file mode 100644 index 7b27745..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -""" - babel - ~~~~~ - - Integrated collection of utilities that assist in internationalizing and - localizing applications. - - This package is basically composed of two major parts: - - * tools to build and work with ``gettext`` message catalogs - * a Python interface to the CLDR (Common Locale Data Repository), providing - access to various locale display names, localized number and date - formatting, etc. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from babel.core import ( - Locale, - UnknownLocaleError, - default_locale, - get_locale_identifier, - negotiate_locale, - parse_locale, -) - -__version__ = '2.17.0' - -__all__ = [ - 'Locale', - 'UnknownLocaleError', - '__version__', - 'default_locale', - 'get_locale_identifier', - 'negotiate_locale', - 'parse_locale', -] diff --git a/extensions/.local/lib/python3.11/site-packages/babel/core.py b/extensions/.local/lib/python3.11/site-packages/babel/core.py deleted file mode 100644 index 5762bbe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/core.py +++ /dev/null @@ -1,1337 +0,0 @@ -""" - babel.core - ~~~~~~~~~~ - - Core locale representation and locale data access. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import annotations - -import os -import pickle -from collections.abc import Iterable, Mapping -from typing import TYPE_CHECKING, Any, Literal - -from babel import localedata -from babel.plural import PluralRule - -__all__ = [ - 'Locale', - 'UnknownLocaleError', - 'default_locale', - 'get_global', - 'get_locale_identifier', - 'negotiate_locale', - 'parse_locale', -] - -if TYPE_CHECKING: - from typing_extensions import TypeAlias - - _GLOBAL_KEY: TypeAlias = Literal[ - "all_currencies", - "currency_fractions", - "language_aliases", - "likely_subtags", - "meta_zones", - "parent_exceptions", - "script_aliases", - "territory_aliases", - "territory_currencies", - "territory_languages", - "territory_zones", - "variant_aliases", - "windows_zone_mapping", - "zone_aliases", - "zone_territories", - ] - - _global_data: Mapping[_GLOBAL_KEY, Mapping[str, Any]] | None - -_global_data = None -_default_plural_rule = PluralRule({}) - - -def _raise_no_data_error(): - raise RuntimeError('The babel data files are not available. ' - 'This usually happens because you are using ' - 'a source checkout from Babel and you did ' - 'not build the data files. Just make sure ' - 'to run "python setup.py import_cldr" before ' - 'installing the library.') - - -def get_global(key: _GLOBAL_KEY) -> Mapping[str, Any]: - """Return the dictionary for the given key in the global data. - - The global data is stored in the ``babel/global.dat`` file and contains - information independent of individual locales. - - >>> get_global('zone_aliases')['UTC'] - u'Etc/UTC' - >>> get_global('zone_territories')['Europe/Berlin'] - u'DE' - - The keys available are: - - - ``all_currencies`` - - ``currency_fractions`` - - ``language_aliases`` - - ``likely_subtags`` - - ``parent_exceptions`` - - ``script_aliases`` - - ``territory_aliases`` - - ``territory_currencies`` - - ``territory_languages`` - - ``territory_zones`` - - ``variant_aliases`` - - ``windows_zone_mapping`` - - ``zone_aliases`` - - ``zone_territories`` - - .. note:: The internal structure of the data may change between versions. - - .. versionadded:: 0.9 - - :param key: the data key - """ - global _global_data - if _global_data is None: - dirname = os.path.join(os.path.dirname(__file__)) - filename = os.path.join(dirname, 'global.dat') - if not os.path.isfile(filename): - _raise_no_data_error() - with open(filename, 'rb') as fileobj: - _global_data = pickle.load(fileobj) - assert _global_data is not None - return _global_data.get(key, {}) - - -LOCALE_ALIASES = { - 'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ', - 'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', - 'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES', - 'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT', - 'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV', - 'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL', - 'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI', - 'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA', -} - - -class UnknownLocaleError(Exception): - """Exception thrown when a locale is requested for which no locale data - is available. - """ - - def __init__(self, identifier: str) -> None: - """Create the exception. - - :param identifier: the identifier string of the unsupported locale - """ - Exception.__init__(self, f"unknown locale {identifier!r}") - - #: The identifier of the locale that could not be found. - self.identifier = identifier - - -class Locale: - """Representation of a specific locale. - - >>> locale = Locale('en', 'US') - >>> repr(locale) - "Locale('en', territory='US')" - >>> locale.display_name - u'English (United States)' - - A `Locale` object can also be instantiated from a raw locale string: - - >>> locale = Locale.parse('en-US', sep='-') - >>> repr(locale) - "Locale('en', territory='US')" - - `Locale` objects provide access to a collection of locale data, such as - territory and language names, number and date format patterns, and more: - - >>> locale.number_symbols['latn']['decimal'] - u'.' - - If a locale is requested for which no locale data is available, an - `UnknownLocaleError` is raised: - - >>> Locale.parse('en_XX') - Traceback (most recent call last): - ... - UnknownLocaleError: unknown locale 'en_XX' - - For more information see :rfc:`3066`. - """ - - def __init__( - self, - language: str, - territory: str | None = None, - script: str | None = None, - variant: str | None = None, - modifier: str | None = None, - ) -> None: - """Initialize the locale object from the given identifier components. - - >>> locale = Locale('en', 'US') - >>> locale.language - 'en' - >>> locale.territory - 'US' - - :param language: the language code - :param territory: the territory (country or region) code - :param script: the script code - :param variant: the variant code - :param modifier: a modifier (following the '@' symbol, sometimes called '@variant') - :raise `UnknownLocaleError`: if no locale data is available for the - requested locale - """ - #: the language code - self.language = language - #: the territory (country or region) code - self.territory = territory - #: the script code - self.script = script - #: the variant code - self.variant = variant - #: the modifier - self.modifier = modifier - self.__data: localedata.LocaleDataDict | None = None - - identifier = str(self) - identifier_without_modifier = identifier.partition('@')[0] - if localedata.exists(identifier): - self.__data_identifier = identifier - elif localedata.exists(identifier_without_modifier): - self.__data_identifier = identifier_without_modifier - else: - raise UnknownLocaleError(identifier) - - @classmethod - def default(cls, category: str | None = None, aliases: Mapping[str, str] = LOCALE_ALIASES) -> Locale: - """Return the system default locale for the specified category. - - >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: - ... os.environ[name] = '' - >>> os.environ['LANG'] = 'fr_FR.UTF-8' - >>> Locale.default('LC_MESSAGES') - Locale('fr', territory='FR') - - The following fallbacks to the variable are always considered: - - - ``LANGUAGE`` - - ``LC_ALL`` - - ``LC_CTYPE`` - - ``LANG`` - - :param category: one of the ``LC_XXX`` environment variable names - :param aliases: a dictionary of aliases for locale identifiers - """ - # XXX: use likely subtag expansion here instead of the - # aliases dictionary. - locale_string = default_locale(category, aliases=aliases) - return cls.parse(locale_string) - - @classmethod - def negotiate( - cls, - preferred: Iterable[str], - available: Iterable[str], - sep: str = '_', - aliases: Mapping[str, str] = LOCALE_ALIASES, - ) -> Locale | None: - """Find the best match between available and requested locale strings. - - >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) - Locale('de', territory='DE') - >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) - Locale('de') - >>> Locale.negotiate(['de_DE', 'de'], ['en_US']) - - You can specify the character used in the locale identifiers to separate - the different components. This separator is applied to both lists. Also, - case is ignored in the comparison: - - >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-') - Locale('de', territory='DE') - - :param preferred: the list of locale identifiers preferred by the user - :param available: the list of locale identifiers available - :param aliases: a dictionary of aliases for locale identifiers - :param sep: separator for parsing; e.g. Windows tends to use '-' instead of '_'. - """ - identifier = negotiate_locale(preferred, available, sep=sep, - aliases=aliases) - if identifier: - return Locale.parse(identifier, sep=sep) - return None - - @classmethod - def parse( - cls, - identifier: Locale | str | None, - sep: str = '_', - resolve_likely_subtags: bool = True, - ) -> Locale: - """Create a `Locale` instance for the given locale identifier. - - >>> l = Locale.parse('de-DE', sep='-') - >>> l.display_name - u'Deutsch (Deutschland)' - - If the `identifier` parameter is not a string, but actually a `Locale` - object, that object is returned: - - >>> Locale.parse(l) - Locale('de', territory='DE') - - If the `identifier` parameter is neither of these, such as `None` - or an empty string, e.g. because a default locale identifier - could not be determined, a `TypeError` is raised: - - >>> Locale.parse(None) - Traceback (most recent call last): - ... - TypeError: ... - - This also can perform resolving of likely subtags which it does - by default. This is for instance useful to figure out the most - likely locale for a territory you can use ``'und'`` as the - language tag: - - >>> Locale.parse('und_AT') - Locale('de', territory='AT') - - Modifiers are optional, and always at the end, separated by "@": - - >>> Locale.parse('de_AT@euro') - Locale('de', territory='AT', modifier='euro') - - :param identifier: the locale identifier string - :param sep: optional component separator - :param resolve_likely_subtags: if this is specified then a locale will - have its likely subtag resolved if the - locale otherwise does not exist. For - instance ``zh_TW`` by itself is not a - locale that exists but Babel can - automatically expand it to the full - form of ``zh_hant_TW``. Note that this - expansion is only taking place if no - locale exists otherwise. For instance - there is a locale ``en`` that can exist - by itself. - :raise `ValueError`: if the string does not appear to be a valid locale - identifier - :raise `UnknownLocaleError`: if no locale data is available for the - requested locale - :raise `TypeError`: if the identifier is not a string or a `Locale` - :raise `ValueError`: if the identifier is not a valid string - """ - if isinstance(identifier, Locale): - return identifier - - if not identifier: - msg = ( - f"Empty locale identifier value: {identifier!r}\n\n" - f"If you didn't explicitly pass an empty value to a Babel function, " - f"this could be caused by there being no suitable locale environment " - f"variables for the API you tried to use.", - ) - if isinstance(identifier, str): - raise ValueError(msg) # `parse_locale` would raise a ValueError, so let's do that here - raise TypeError(msg) - - if not isinstance(identifier, str): - raise TypeError(f"Unexpected value for identifier: {identifier!r}") - - parts = parse_locale(identifier, sep=sep) - input_id = get_locale_identifier(parts) - - def _try_load(parts): - try: - return cls(*parts) - except UnknownLocaleError: - return None - - def _try_load_reducing(parts): - # Success on first hit, return it. - locale = _try_load(parts) - if locale is not None: - return locale - - # Now try without script and variant - locale = _try_load(parts[:2]) - if locale is not None: - return locale - - locale = _try_load(parts) - if locale is not None: - return locale - if not resolve_likely_subtags: - raise UnknownLocaleError(input_id) - - # From here onwards is some very bad likely subtag resolving. This - # whole logic is not entirely correct but good enough (tm) for the - # time being. This has been added so that zh_TW does not cause - # errors for people when they upgrade. Later we should properly - # implement ICU like fuzzy locale objects and provide a way to - # maximize and minimize locale tags. - - if len(parts) == 5: - language, territory, script, variant, modifier = parts - else: - language, territory, script, variant = parts - modifier = None - language = get_global('language_aliases').get(language, language) - territory = get_global('territory_aliases').get(territory or '', (territory,))[0] - script = get_global('script_aliases').get(script or '', script) - variant = get_global('variant_aliases').get(variant or '', variant) - - if territory == 'ZZ': - territory = None - if script == 'Zzzz': - script = None - - parts = language, territory, script, variant, modifier - - # First match: try the whole identifier - new_id = get_locale_identifier(parts) - likely_subtag = get_global('likely_subtags').get(new_id) - if likely_subtag is not None: - locale = _try_load_reducing(parse_locale(likely_subtag)) - if locale is not None: - return locale - - # If we did not find anything so far, try again with a - # simplified identifier that is just the language - likely_subtag = get_global('likely_subtags').get(language) - if likely_subtag is not None: - parts2 = parse_locale(likely_subtag) - if len(parts2) == 5: - language2, _, script2, variant2, modifier2 = parts2 - else: - language2, _, script2, variant2 = parts2 - modifier2 = None - locale = _try_load_reducing((language2, territory, script2, variant2, modifier2)) - if locale is not None: - return locale - - raise UnknownLocaleError(input_id) - - def __eq__(self, other: object) -> bool: - for key in ('language', 'territory', 'script', 'variant', 'modifier'): - if not hasattr(other, key): - return False - return ( - self.language == getattr(other, 'language') and # noqa: B009 - self.territory == getattr(other, 'territory') and # noqa: B009 - self.script == getattr(other, 'script') and # noqa: B009 - self.variant == getattr(other, 'variant') and # noqa: B009 - self.modifier == getattr(other, 'modifier') # noqa: B009 - ) - - def __ne__(self, other: object) -> bool: - return not self.__eq__(other) - - def __hash__(self) -> int: - return hash((self.language, self.territory, self.script, - self.variant, self.modifier)) - - def __repr__(self) -> str: - parameters = [''] - for key in ('territory', 'script', 'variant', 'modifier'): - value = getattr(self, key) - if value is not None: - parameters.append(f"{key}={value!r}") - return f"Locale({self.language!r}{', '.join(parameters)})" - - def __str__(self) -> str: - return get_locale_identifier((self.language, self.territory, - self.script, self.variant, - self.modifier)) - - @property - def _data(self) -> localedata.LocaleDataDict: - if self.__data is None: - self.__data = localedata.LocaleDataDict(localedata.load(self.__data_identifier)) - return self.__data - - def get_display_name(self, locale: Locale | str | None = None) -> str | None: - """Return the display name of the locale using the given locale. - - The display name will include the language, territory, script, and - variant, if those are specified. - - >>> Locale('zh', 'CN', script='Hans').get_display_name('en') - u'Chinese (Simplified, China)' - - Modifiers are currently passed through verbatim: - - >>> Locale('it', 'IT', modifier='euro').get_display_name('en') - u'Italian (Italy, euro)' - - :param locale: the locale to use - """ - if locale is None: - locale = self - locale = Locale.parse(locale) - retval = locale.languages.get(self.language) - if retval and (self.territory or self.script or self.variant): - details = [] - if self.script: - details.append(locale.scripts.get(self.script)) - if self.territory: - details.append(locale.territories.get(self.territory)) - if self.variant: - details.append(locale.variants.get(self.variant)) - if self.modifier: - details.append(self.modifier) - detail_string = ', '.join(atom for atom in details if atom) - if detail_string: - retval += f" ({detail_string})" - return retval - - display_name = property(get_display_name, doc="""\ - The localized display name of the locale. - - >>> Locale('en').display_name - u'English' - >>> Locale('en', 'US').display_name - u'English (United States)' - >>> Locale('sv').display_name - u'svenska' - - :type: `unicode` - """) - - def get_language_name(self, locale: Locale | str | None = None) -> str | None: - """Return the language of this locale in the given locale. - - >>> Locale('zh', 'CN', script='Hans').get_language_name('de') - u'Chinesisch' - - .. versionadded:: 1.0 - - :param locale: the locale to use - """ - if locale is None: - locale = self - locale = Locale.parse(locale) - return locale.languages.get(self.language) - - language_name = property(get_language_name, doc="""\ - The localized language name of the locale. - - >>> Locale('en', 'US').language_name - u'English' - """) - - def get_territory_name(self, locale: Locale | str | None = None) -> str | None: - """Return the territory name in the given locale.""" - if locale is None: - locale = self - locale = Locale.parse(locale) - return locale.territories.get(self.territory or '') - - territory_name = property(get_territory_name, doc="""\ - The localized territory name of the locale if available. - - >>> Locale('de', 'DE').territory_name - u'Deutschland' - """) - - def get_script_name(self, locale: Locale | str | None = None) -> str | None: - """Return the script name in the given locale.""" - if locale is None: - locale = self - locale = Locale.parse(locale) - return locale.scripts.get(self.script or '') - - script_name = property(get_script_name, doc="""\ - The localized script name of the locale if available. - - >>> Locale('sr', 'ME', script='Latn').script_name - u'latinica' - """) - - @property - def english_name(self) -> str | None: - """The english display name of the locale. - - >>> Locale('de').english_name - u'German' - >>> Locale('de', 'DE').english_name - u'German (Germany)' - - :type: `unicode`""" - return self.get_display_name(Locale('en')) - - # { General Locale Display Names - - @property - def languages(self) -> localedata.LocaleDataDict: - """Mapping of language codes to translated language names. - - >>> Locale('de', 'DE').languages['ja'] - u'Japanisch' - - See `ISO 639 `_ for - more information. - """ - return self._data['languages'] - - @property - def scripts(self) -> localedata.LocaleDataDict: - """Mapping of script codes to translated script names. - - >>> Locale('en', 'US').scripts['Hira'] - u'Hiragana' - - See `ISO 15924 `_ - for more information. - """ - return self._data['scripts'] - - @property - def territories(self) -> localedata.LocaleDataDict: - """Mapping of script codes to translated script names. - - >>> Locale('es', 'CO').territories['DE'] - u'Alemania' - - See `ISO 3166 `_ - for more information. - """ - return self._data['territories'] - - @property - def variants(self) -> localedata.LocaleDataDict: - """Mapping of script codes to translated script names. - - >>> Locale('de', 'DE').variants['1901'] - u'Alte deutsche Rechtschreibung' - """ - return self._data['variants'] - - # { Number Formatting - - @property - def currencies(self) -> localedata.LocaleDataDict: - """Mapping of currency codes to translated currency names. This - only returns the generic form of the currency name, not the count - specific one. If an actual number is requested use the - :func:`babel.numbers.get_currency_name` function. - - >>> Locale('en').currencies['COP'] - u'Colombian Peso' - >>> Locale('de', 'DE').currencies['COP'] - u'Kolumbianischer Peso' - """ - return self._data['currency_names'] - - @property - def currency_symbols(self) -> localedata.LocaleDataDict: - """Mapping of currency codes to symbols. - - >>> Locale('en', 'US').currency_symbols['USD'] - u'$' - >>> Locale('es', 'CO').currency_symbols['USD'] - u'US$' - """ - return self._data['currency_symbols'] - - @property - def number_symbols(self) -> localedata.LocaleDataDict: - """Symbols used in number formatting by number system. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('fr', 'FR').number_symbols["latn"]['decimal'] - u',' - >>> Locale('fa', 'IR').number_symbols["arabext"]['decimal'] - u'Ù«' - >>> Locale('fa', 'IR').number_symbols["latn"]['decimal'] - u'.' - """ - return self._data['number_symbols'] - - @property - def other_numbering_systems(self) -> localedata.LocaleDataDict: - """ - Mapping of other numbering systems available for the locale. - See: https://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems - - >>> Locale('el', 'GR').other_numbering_systems['traditional'] - u'grek' - - .. note:: The format of the value returned may change between - Babel versions. - """ - return self._data['numbering_systems'] - - @property - def default_numbering_system(self) -> str: - """The default numbering system used by the locale. - >>> Locale('el', 'GR').default_numbering_system - u'latn' - """ - return self._data['default_numbering_system'] - - @property - def decimal_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for decimal number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').decimal_formats[None] - - """ - return self._data['decimal_formats'] - - @property - def compact_decimal_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for compact decimal number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').compact_decimal_formats["short"]["one"]["1000"] - - """ - return self._data['compact_decimal_formats'] - - @property - def currency_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for currency number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').currency_formats['standard'] - - >>> Locale('en', 'US').currency_formats['accounting'] - - """ - return self._data['currency_formats'] - - @property - def compact_currency_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for compact currency number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').compact_currency_formats["short"]["one"]["1000"] - - """ - return self._data['compact_currency_formats'] - - @property - def percent_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for percent number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').percent_formats[None] - - """ - return self._data['percent_formats'] - - @property - def scientific_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for scientific number formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').scientific_formats[None] - - """ - return self._data['scientific_formats'] - - # { Calendar Information and Date Formatting - - @property - def periods(self) -> localedata.LocaleDataDict: - """Locale display names for day periods (AM/PM). - - >>> Locale('en', 'US').periods['am'] - u'AM' - """ - try: - return self._data['day_periods']['stand-alone']['wide'] - except KeyError: - return localedata.LocaleDataDict({}) # pragma: no cover - - @property - def day_periods(self) -> localedata.LocaleDataDict: - """Locale display names for various day periods (not necessarily only AM/PM). - - These are not meant to be used without the relevant `day_period_rules`. - """ - return self._data['day_periods'] - - @property - def day_period_rules(self) -> localedata.LocaleDataDict: - """Day period rules for the locale. Used by `get_period_id`. - """ - return self._data.get('day_period_rules', localedata.LocaleDataDict({})) - - @property - def days(self) -> localedata.LocaleDataDict: - """Locale display names for weekdays. - - >>> Locale('de', 'DE').days['format']['wide'][3] - u'Donnerstag' - """ - return self._data['days'] - - @property - def months(self) -> localedata.LocaleDataDict: - """Locale display names for months. - - >>> Locale('de', 'DE').months['format']['wide'][10] - u'Oktober' - """ - return self._data['months'] - - @property - def quarters(self) -> localedata.LocaleDataDict: - """Locale display names for quarters. - - >>> Locale('de', 'DE').quarters['format']['wide'][1] - u'1. Quartal' - """ - return self._data['quarters'] - - @property - def eras(self) -> localedata.LocaleDataDict: - """Locale display names for eras. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').eras['wide'][1] - u'Anno Domini' - >>> Locale('en', 'US').eras['abbreviated'][0] - u'BC' - """ - return self._data['eras'] - - @property - def time_zones(self) -> localedata.LocaleDataDict: - """Locale display names for time zones. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] - u'British Summer Time' - >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] - u'St. John\u2019s' - """ - return self._data['time_zones'] - - @property - def meta_zones(self) -> localedata.LocaleDataDict: - """Locale display names for meta time zones. - - Meta time zones are basically groups of different Olson time zones that - have the same GMT offset and daylight savings time. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight'] - u'Central European Summer Time' - - .. versionadded:: 0.9 - """ - return self._data['meta_zones'] - - @property - def zone_formats(self) -> localedata.LocaleDataDict: - """Patterns related to the formatting of time zones. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').zone_formats['fallback'] - u'%(1)s (%(0)s)' - >>> Locale('pt', 'BR').zone_formats['region'] - u'Hor\\xe1rio %s' - - .. versionadded:: 0.9 - """ - return self._data['zone_formats'] - - @property - def first_week_day(self) -> int: - """The first day of a week, with 0 being Monday. - - >>> Locale('de', 'DE').first_week_day - 0 - >>> Locale('en', 'US').first_week_day - 6 - """ - return self._data['week_data']['first_day'] - - @property - def weekend_start(self) -> int: - """The day the weekend starts, with 0 being Monday. - - >>> Locale('de', 'DE').weekend_start - 5 - """ - return self._data['week_data']['weekend_start'] - - @property - def weekend_end(self) -> int: - """The day the weekend ends, with 0 being Monday. - - >>> Locale('de', 'DE').weekend_end - 6 - """ - return self._data['week_data']['weekend_end'] - - @property - def min_week_days(self) -> int: - """The minimum number of days in a week so that the week is counted as - the first week of a year or month. - - >>> Locale('de', 'DE').min_week_days - 4 - """ - return self._data['week_data']['min_days'] - - @property - def date_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for date formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').date_formats['short'] - - >>> Locale('fr', 'FR').date_formats['long'] - - """ - return self._data['date_formats'] - - @property - def time_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for time formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en', 'US').time_formats['short'] - - >>> Locale('fr', 'FR').time_formats['long'] - - """ - return self._data['time_formats'] - - @property - def datetime_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for datetime formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en').datetime_formats['full'] - u'{1}, {0}' - >>> Locale('th').datetime_formats['medium'] - u'{1} {0}' - """ - return self._data['datetime_formats'] - - @property - def datetime_skeletons(self) -> localedata.LocaleDataDict: - """Locale patterns for formatting parts of a datetime. - - >>> Locale('en').datetime_skeletons['MEd'] - - >>> Locale('fr').datetime_skeletons['MEd'] - - >>> Locale('fr').datetime_skeletons['H'] - - """ - return self._data['datetime_skeletons'] - - @property - def interval_formats(self) -> localedata.LocaleDataDict: - """Locale patterns for interval formatting. - - .. note:: The format of the value returned may change between - Babel versions. - - How to format date intervals in Finnish when the day is the - smallest changing component: - - >>> Locale('fi_FI').interval_formats['MEd']['d'] - [u'E d.\u2009\u2013\u2009', u'E d.M.'] - - .. seealso:: - - The primary API to use this data is :py:func:`babel.dates.format_interval`. - - - :rtype: dict[str, dict[str, list[str]]] - """ - return self._data['interval_formats'] - - @property - def plural_form(self) -> PluralRule: - """Plural rules for the locale. - - >>> Locale('en').plural_form(1) - 'one' - >>> Locale('en').plural_form(0) - 'other' - >>> Locale('fr').plural_form(0) - 'one' - >>> Locale('ru').plural_form(100) - 'many' - """ - return self._data.get('plural_form', _default_plural_rule) - - @property - def list_patterns(self) -> localedata.LocaleDataDict: - """Patterns for generating lists - - .. note:: The format of the value returned may change between - Babel versions. - - >>> Locale('en').list_patterns['standard']['start'] - u'{0}, {1}' - >>> Locale('en').list_patterns['standard']['end'] - u'{0}, and {1}' - >>> Locale('en_GB').list_patterns['standard']['end'] - u'{0} and {1}' - """ - return self._data['list_patterns'] - - @property - def ordinal_form(self) -> PluralRule: - """Plural rules for the locale. - - >>> Locale('en').ordinal_form(1) - 'one' - >>> Locale('en').ordinal_form(2) - 'two' - >>> Locale('en').ordinal_form(3) - 'few' - >>> Locale('fr').ordinal_form(2) - 'other' - >>> Locale('ru').ordinal_form(100) - 'other' - """ - return self._data.get('ordinal_form', _default_plural_rule) - - @property - def measurement_systems(self) -> localedata.LocaleDataDict: - """Localized names for various measurement systems. - - >>> Locale('fr', 'FR').measurement_systems['US'] - u'am\\xe9ricain' - >>> Locale('en', 'US').measurement_systems['US'] - u'US' - - """ - return self._data['measurement_systems'] - - @property - def character_order(self) -> str: - """The text direction for the language. - - >>> Locale('de', 'DE').character_order - 'left-to-right' - >>> Locale('ar', 'SA').character_order - 'right-to-left' - """ - return self._data['character_order'] - - @property - def text_direction(self) -> str: - """The text direction for the language in CSS short-hand form. - - >>> Locale('de', 'DE').text_direction - 'ltr' - >>> Locale('ar', 'SA').text_direction - 'rtl' - """ - return ''.join(word[0] for word in self.character_order.split('-')) - - @property - def unit_display_names(self) -> localedata.LocaleDataDict: - """Display names for units of measurement. - - .. seealso:: - - You may want to use :py:func:`babel.units.get_unit_name` instead. - - .. note:: The format of the value returned may change between - Babel versions. - - """ - return self._data['unit_display_names'] - - -def default_locale( - category: str | tuple[str, ...] | list[str] | None = None, - aliases: Mapping[str, str] = LOCALE_ALIASES, -) -> str | None: - """Returns the system default locale for a given category, based on - environment variables. - - >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']: - ... os.environ[name] = '' - >>> os.environ['LANG'] = 'fr_FR.UTF-8' - >>> default_locale('LC_MESSAGES') - 'fr_FR' - - The "C" or "POSIX" pseudo-locales are treated as aliases for the - "en_US_POSIX" locale: - - >>> os.environ['LC_MESSAGES'] = 'POSIX' - >>> default_locale('LC_MESSAGES') - 'en_US_POSIX' - - The following fallbacks to the variable are always considered: - - - ``LANGUAGE`` - - ``LC_ALL`` - - ``LC_CTYPE`` - - ``LANG`` - - :param category: one or more of the ``LC_XXX`` environment variable names - :param aliases: a dictionary of aliases for locale identifiers - """ - - varnames = ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG') - if category: - if isinstance(category, str): - varnames = (category, *varnames) - elif isinstance(category, (list, tuple)): - varnames = (*category, *varnames) - else: - raise TypeError(f"Invalid type for category: {category!r}") - - for name in varnames: - if not name: - continue - locale = os.getenv(name) - if locale: - if name == 'LANGUAGE' and ':' in locale: - # the LANGUAGE variable may contain a colon-separated list of - # language codes; we just pick the language on the list - locale = locale.split(':')[0] - if locale.split('.')[0] in ('C', 'POSIX'): - locale = 'en_US_POSIX' - elif aliases and locale in aliases: - locale = aliases[locale] - try: - return get_locale_identifier(parse_locale(locale)) - except ValueError: - pass - return None - - -def negotiate_locale(preferred: Iterable[str], available: Iterable[str], sep: str = '_', aliases: Mapping[str, str] = LOCALE_ALIASES) -> str | None: - """Find the best match between available and requested locale strings. - - >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) - 'de_DE' - >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) - 'de' - - Case is ignored by the algorithm, the result uses the case of the preferred - locale identifier: - - >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) - 'de_DE' - - >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) - 'de_DE' - - By default, some web browsers unfortunately do not include the territory - in the locale identifier for many locales, and some don't even allow the - user to easily add the territory. So while you may prefer using qualified - locale identifiers in your web-application, they would not normally match - the language-only locale sent by such browsers. To workaround that, this - function uses a default mapping of commonly used language-only locale - identifiers to identifiers including the territory: - - >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) - 'ja_JP' - - Some browsers even use an incorrect or outdated language code, such as "no" - for Norwegian, where the correct locale identifier would actually be "nb_NO" - (BokmÃ¥l) or "nn_NO" (Nynorsk). The aliases are intended to take care of - such cases, too: - - >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) - 'nb_NO' - - You can override this default mapping by passing a different `aliases` - dictionary to this function, or you can bypass the behavior althogher by - setting the `aliases` parameter to `None`. - - :param preferred: the list of locale strings preferred by the user - :param available: the list of locale strings available - :param sep: character that separates the different parts of the locale - strings - :param aliases: a dictionary of aliases for locale identifiers - """ - available = [a.lower() for a in available if a] - for locale in preferred: - ll = locale.lower() - if ll in available: - return locale - if aliases: - alias = aliases.get(ll) - if alias: - alias = alias.replace('_', sep) - if alias.lower() in available: - return alias - parts = locale.split(sep) - if len(parts) > 1 and parts[0].lower() in available: - return parts[0] - return None - - -def parse_locale( - identifier: str, - sep: str = '_', -) -> tuple[str, str | None, str | None, str | None] | tuple[str, str | None, str | None, str | None, str | None]: - """Parse a locale identifier into a tuple of the form ``(language, - territory, script, variant, modifier)``. - - >>> parse_locale('zh_CN') - ('zh', 'CN', None, None) - >>> parse_locale('zh_Hans_CN') - ('zh', 'CN', 'Hans', None) - >>> parse_locale('ca_es_valencia') - ('ca', 'ES', None, 'VALENCIA') - >>> parse_locale('en_150') - ('en', '150', None, None) - >>> parse_locale('en_us_posix') - ('en', 'US', None, 'POSIX') - >>> parse_locale('it_IT@euro') - ('it', 'IT', None, None, 'euro') - >>> parse_locale('it_IT@custom') - ('it', 'IT', None, None, 'custom') - >>> parse_locale('it_IT@') - ('it', 'IT', None, None) - - The default component separator is "_", but a different separator can be - specified using the `sep` parameter. - - The optional modifier is always separated with "@" and at the end: - - >>> parse_locale('zh-CN', sep='-') - ('zh', 'CN', None, None) - >>> parse_locale('zh-CN@custom', sep='-') - ('zh', 'CN', None, None, 'custom') - - If the identifier cannot be parsed into a locale, a `ValueError` exception - is raised: - - >>> parse_locale('not_a_LOCALE_String') - Traceback (most recent call last): - ... - ValueError: 'not_a_LOCALE_String' is not a valid locale identifier - - Encoding information is removed from the identifier, while modifiers are - kept: - - >>> parse_locale('en_US.UTF-8') - ('en', 'US', None, None) - >>> parse_locale('de_DE.iso885915@euro') - ('de', 'DE', None, None, 'euro') - - See :rfc:`4646` for more information. - - :param identifier: the locale identifier string - :param sep: character that separates the different components of the locale - identifier - :raise `ValueError`: if the string does not appear to be a valid locale - identifier - """ - if not identifier: - raise ValueError("empty locale identifier") - identifier, _, modifier = identifier.partition('@') - if '.' in identifier: - # this is probably the charset/encoding, which we don't care about - identifier = identifier.split('.', 1)[0] - - parts = identifier.split(sep) - lang = parts.pop(0).lower() - if not lang.isalpha(): - raise ValueError(f"expected only letters, got {lang!r}") - - script = territory = variant = None - if parts and len(parts[0]) == 4 and parts[0].isalpha(): - script = parts.pop(0).title() - - if parts: - if len(parts[0]) == 2 and parts[0].isalpha(): - territory = parts.pop(0).upper() - elif len(parts[0]) == 3 and parts[0].isdigit(): - territory = parts.pop(0) - - if parts and ( - len(parts[0]) == 4 and parts[0][0].isdigit() or - len(parts[0]) >= 5 and parts[0][0].isalpha() - ): - variant = parts.pop().upper() - - if parts: - raise ValueError(f"{identifier!r} is not a valid locale identifier") - - # TODO(3.0): always return a 5-tuple - if modifier: - return lang, territory, script, variant, modifier - else: - return lang, territory, script, variant - - -def get_locale_identifier( - tup: tuple[str] - | tuple[str, str | None] - | tuple[str, str | None, str | None] - | tuple[str, str | None, str | None, str | None] - | tuple[str, str | None, str | None, str | None, str | None], - sep: str = "_", -) -> str: - """The reverse of :func:`parse_locale`. It creates a locale identifier out - of a ``(language, territory, script, variant, modifier)`` tuple. Items can be set to - ``None`` and trailing ``None``\\s can also be left out of the tuple. - - >>> get_locale_identifier(('de', 'DE', None, '1999', 'custom')) - 'de_DE_1999@custom' - >>> get_locale_identifier(('fi', None, None, None, 'custom')) - 'fi@custom' - - - .. versionadded:: 1.0 - - :param tup: the tuple as returned by :func:`parse_locale`. - :param sep: the separator for the identifier. - """ - tup = tuple(tup[:5]) # type: ignore # length should be no more than 5 - lang, territory, script, variant, modifier = tup + (None,) * (5 - len(tup)) - ret = sep.join(filter(None, (lang, script, territory, variant))) - return f'{ret}@{modifier}' if modifier else ret diff --git a/extensions/.local/lib/python3.11/site-packages/babel/dates.py b/extensions/.local/lib/python3.11/site-packages/babel/dates.py deleted file mode 100644 index 355a923..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/dates.py +++ /dev/null @@ -1,1999 +0,0 @@ -""" - babel.dates - ~~~~~~~~~~~ - - Locale dependent formatting and parsing of dates and times. - - The default locale for the functions in this module is determined by the - following environment variables, in that order: - - * ``LC_TIME``, - * ``LC_ALL``, and - * ``LANG`` - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import annotations - -import math -import re -import warnings -from functools import lru_cache -from typing import TYPE_CHECKING, Literal, SupportsInt - -try: - import pytz -except ModuleNotFoundError: - pytz = None - import zoneinfo - -import datetime -from collections.abc import Iterable - -from babel import localtime -from babel.core import Locale, default_locale, get_global -from babel.localedata import LocaleDataDict - -if TYPE_CHECKING: - from typing_extensions import TypeAlias - _Instant: TypeAlias = datetime.date | datetime.time | float | None - _PredefinedTimeFormat: TypeAlias = Literal['full', 'long', 'medium', 'short'] - _Context: TypeAlias = Literal['format', 'stand-alone'] - _DtOrTzinfo: TypeAlias = datetime.datetime | datetime.tzinfo | str | int | datetime.time | None - -# "If a given short metazone form is known NOT to be understood in a given -# locale and the parent locale has this value such that it would normally -# be inherited, the inheritance of this value can be explicitly disabled by -# use of the 'no inheritance marker' as the value, which is 3 simultaneous [sic] -# empty set characters ( U+2205 )." -# - https://www.unicode.org/reports/tr35/tr35-dates.html#Metazone_Names - -NO_INHERITANCE_MARKER = '\u2205\u2205\u2205' - -UTC = datetime.timezone.utc -LOCALTZ = localtime.LOCALTZ - -LC_TIME = default_locale('LC_TIME') - - -def _localize(tz: datetime.tzinfo, dt: datetime.datetime) -> datetime.datetime: - # Support localizing with both pytz and zoneinfo tzinfos - # nothing to do - if dt.tzinfo is tz: - return dt - - if hasattr(tz, 'localize'): # pytz - return tz.localize(dt) - - if dt.tzinfo is None: - # convert naive to localized - return dt.replace(tzinfo=tz) - - # convert timezones - return dt.astimezone(tz) - - -def _get_dt_and_tzinfo(dt_or_tzinfo: _DtOrTzinfo) -> tuple[datetime.datetime | None, datetime.tzinfo]: - """ - Parse a `dt_or_tzinfo` value into a datetime and a tzinfo. - - See the docs for this function's callers for semantics. - - :rtype: tuple[datetime, tzinfo] - """ - if dt_or_tzinfo is None: - dt = datetime.datetime.now() - tzinfo = LOCALTZ - elif isinstance(dt_or_tzinfo, str): - dt = None - tzinfo = get_timezone(dt_or_tzinfo) - elif isinstance(dt_or_tzinfo, int): - dt = None - tzinfo = UTC - elif isinstance(dt_or_tzinfo, (datetime.datetime, datetime.time)): - dt = _get_datetime(dt_or_tzinfo) - tzinfo = dt.tzinfo if dt.tzinfo is not None else UTC - else: - dt = None - tzinfo = dt_or_tzinfo - return dt, tzinfo - - -def _get_tz_name(dt_or_tzinfo: _DtOrTzinfo) -> str: - """ - Get the timezone name out of a time, datetime, or tzinfo object. - - :rtype: str - """ - dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo) - if hasattr(tzinfo, 'zone'): # pytz object - return tzinfo.zone - elif hasattr(tzinfo, 'key') and tzinfo.key is not None: # ZoneInfo object - return tzinfo.key - else: - return tzinfo.tzname(dt or datetime.datetime.now(UTC)) - - -def _get_datetime(instant: _Instant) -> datetime.datetime: - """ - Get a datetime out of an "instant" (date, time, datetime, number). - - .. warning:: The return values of this function may depend on the system clock. - - If the instant is None, the current moment is used. - If the instant is a time, it's augmented with today's date. - - Dates are converted to naive datetimes with midnight as the time component. - - >>> from datetime import date, datetime - >>> _get_datetime(date(2015, 1, 1)) - datetime.datetime(2015, 1, 1, 0, 0) - - UNIX timestamps are converted to datetimes. - - >>> _get_datetime(1400000000) - datetime.datetime(2014, 5, 13, 16, 53, 20) - - Other values are passed through as-is. - - >>> x = datetime(2015, 1, 1) - >>> _get_datetime(x) is x - True - - :param instant: date, time, datetime, integer, float or None - :type instant: date|time|datetime|int|float|None - :return: a datetime - :rtype: datetime - """ - if instant is None: - return datetime.datetime.now(UTC).replace(tzinfo=None) - elif isinstance(instant, (int, float)): - return datetime.datetime.fromtimestamp(instant, UTC).replace(tzinfo=None) - elif isinstance(instant, datetime.time): - return datetime.datetime.combine(datetime.date.today(), instant) - elif isinstance(instant, datetime.date) and not isinstance(instant, datetime.datetime): - return datetime.datetime.combine(instant, datetime.time()) - # TODO (3.x): Add an assertion/type check for this fallthrough branch: - return instant - - -def _ensure_datetime_tzinfo(dt: datetime.datetime, tzinfo: datetime.tzinfo | None = None) -> datetime.datetime: - """ - Ensure the datetime passed has an attached tzinfo. - - If the datetime is tz-naive to begin with, UTC is attached. - - If a tzinfo is passed in, the datetime is normalized to that timezone. - - >>> from datetime import datetime - >>> _get_tz_name(_ensure_datetime_tzinfo(datetime(2015, 1, 1))) - 'UTC' - - >>> tz = get_timezone("Europe/Stockholm") - >>> _ensure_datetime_tzinfo(datetime(2015, 1, 1, 13, 15, tzinfo=UTC), tzinfo=tz).hour - 14 - - :param datetime: Datetime to augment. - :param tzinfo: optional tzinfo - :return: datetime with tzinfo - :rtype: datetime - """ - if dt.tzinfo is None: - dt = dt.replace(tzinfo=UTC) - if tzinfo is not None: - dt = dt.astimezone(get_timezone(tzinfo)) - if hasattr(tzinfo, 'normalize'): # pytz - dt = tzinfo.normalize(dt) - return dt - - -def _get_time( - time: datetime.time | datetime.datetime | None, - tzinfo: datetime.tzinfo | None = None, -) -> datetime.time: - """ - Get a timezoned time from a given instant. - - .. warning:: The return values of this function may depend on the system clock. - - :param time: time, datetime or None - :rtype: time - """ - if time is None: - time = datetime.datetime.now(UTC) - elif isinstance(time, (int, float)): - time = datetime.datetime.fromtimestamp(time, UTC) - - if time.tzinfo is None: - time = time.replace(tzinfo=UTC) - - if isinstance(time, datetime.datetime): - if tzinfo is not None: - time = time.astimezone(tzinfo) - if hasattr(tzinfo, 'normalize'): # pytz - time = tzinfo.normalize(time) - time = time.timetz() - elif tzinfo is not None: - time = time.replace(tzinfo=tzinfo) - return time - - -def get_timezone(zone: str | datetime.tzinfo | None = None) -> datetime.tzinfo: - """Looks up a timezone by name and returns it. The timezone object - returned comes from ``pytz`` or ``zoneinfo``, whichever is available. - It corresponds to the `tzinfo` interface and can be used with all of - the functions of Babel that operate with dates. - - If a timezone is not known a :exc:`LookupError` is raised. If `zone` - is ``None`` a local zone object is returned. - - :param zone: the name of the timezone to look up. If a timezone object - itself is passed in, it's returned unchanged. - """ - if zone is None: - return LOCALTZ - if not isinstance(zone, str): - return zone - - if pytz: - try: - return pytz.timezone(zone) - except pytz.UnknownTimeZoneError as e: - exc = e - else: - assert zoneinfo - try: - return zoneinfo.ZoneInfo(zone) - except zoneinfo.ZoneInfoNotFoundError as e: - exc = e - - raise LookupError(f"Unknown timezone {zone}") from exc - - -def get_period_names( - width: Literal['abbreviated', 'narrow', 'wide'] = 'wide', - context: _Context = 'stand-alone', - locale: Locale | str | None = None, -) -> LocaleDataDict: - """Return the names for day periods (AM/PM) used by the locale. - - >>> get_period_names(locale='en_US')['am'] - u'AM' - - :param width: the width to use, one of "abbreviated", "narrow", or "wide" - :param context: the context, either "format" or "stand-alone" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).day_periods[context][width] - - -def get_day_names( - width: Literal['abbreviated', 'narrow', 'short', 'wide'] = 'wide', - context: _Context = 'format', - locale: Locale | str | None = None, -) -> LocaleDataDict: - """Return the day names used by the locale for the specified format. - - >>> get_day_names('wide', locale='en_US')[1] - u'Tuesday' - >>> get_day_names('short', locale='en_US')[1] - u'Tu' - >>> get_day_names('abbreviated', locale='es')[1] - u'mar' - >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1] - u'D' - - :param width: the width to use, one of "wide", "abbreviated", "short" or "narrow" - :param context: the context, either "format" or "stand-alone" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).days[context][width] - - -def get_month_names( - width: Literal['abbreviated', 'narrow', 'wide'] = 'wide', - context: _Context = 'format', - locale: Locale | str | None = None, -) -> LocaleDataDict: - """Return the month names used by the locale for the specified format. - - >>> get_month_names('wide', locale='en_US')[1] - u'January' - >>> get_month_names('abbreviated', locale='es')[1] - u'ene' - >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1] - u'J' - - :param width: the width to use, one of "wide", "abbreviated", or "narrow" - :param context: the context, either "format" or "stand-alone" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).months[context][width] - - -def get_quarter_names( - width: Literal['abbreviated', 'narrow', 'wide'] = 'wide', - context: _Context = 'format', - locale: Locale | str | None = None, -) -> LocaleDataDict: - """Return the quarter names used by the locale for the specified format. - - >>> get_quarter_names('wide', locale='en_US')[1] - u'1st quarter' - >>> get_quarter_names('abbreviated', locale='de_DE')[1] - u'Q1' - >>> get_quarter_names('narrow', locale='de_DE')[1] - u'1' - - :param width: the width to use, one of "wide", "abbreviated", or "narrow" - :param context: the context, either "format" or "stand-alone" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).quarters[context][width] - - -def get_era_names( - width: Literal['abbreviated', 'narrow', 'wide'] = 'wide', - locale: Locale | str | None = None, -) -> LocaleDataDict: - """Return the era names used by the locale for the specified format. - - >>> get_era_names('wide', locale='en_US')[1] - u'Anno Domini' - >>> get_era_names('abbreviated', locale='de_DE')[1] - u'n. Chr.' - - :param width: the width to use, either "wide", "abbreviated", or "narrow" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).eras[width] - - -def get_date_format( - format: _PredefinedTimeFormat = 'medium', - locale: Locale | str | None = None, -) -> DateTimePattern: - """Return the date formatting patterns used by the locale for the specified - format. - - >>> get_date_format(locale='en_US') - - >>> get_date_format('full', locale='de_DE') - - - :param format: the format to use, one of "full", "long", "medium", or - "short" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).date_formats[format] - - -def get_datetime_format( - format: _PredefinedTimeFormat = 'medium', - locale: Locale | str | None = None, -) -> DateTimePattern: - """Return the datetime formatting patterns used by the locale for the - specified format. - - >>> get_datetime_format(locale='en_US') - u'{1}, {0}' - - :param format: the format to use, one of "full", "long", "medium", or - "short" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - patterns = Locale.parse(locale or LC_TIME).datetime_formats - if format not in patterns: - format = None - return patterns[format] - - -def get_time_format( - format: _PredefinedTimeFormat = 'medium', - locale: Locale | str | None = None, -) -> DateTimePattern: - """Return the time formatting patterns used by the locale for the specified - format. - - >>> get_time_format(locale='en_US') - - >>> get_time_format('full', locale='de_DE') - - - :param format: the format to use, one of "full", "long", "medium", or - "short" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - """ - return Locale.parse(locale or LC_TIME).time_formats[format] - - -def get_timezone_gmt( - datetime: _Instant = None, - width: Literal['long', 'short', 'iso8601', 'iso8601_short'] = 'long', - locale: Locale | str | None = None, - return_z: bool = False, -) -> str: - """Return the timezone associated with the given `datetime` object formatted - as string indicating the offset from GMT. - - >>> from datetime import datetime - >>> dt = datetime(2007, 4, 1, 15, 30) - >>> get_timezone_gmt(dt, locale='en') - u'GMT+00:00' - >>> get_timezone_gmt(dt, locale='en', return_z=True) - 'Z' - >>> get_timezone_gmt(dt, locale='en', width='iso8601_short') - u'+00' - >>> tz = get_timezone('America/Los_Angeles') - >>> dt = _localize(tz, datetime(2007, 4, 1, 15, 30)) - >>> get_timezone_gmt(dt, locale='en') - u'GMT-07:00' - >>> get_timezone_gmt(dt, 'short', locale='en') - u'-0700' - >>> get_timezone_gmt(dt, locale='en', width='iso8601_short') - u'-07' - - The long format depends on the locale, for example in France the acronym - UTC string is used instead of GMT: - - >>> get_timezone_gmt(dt, 'long', locale='fr_FR') - u'UTC-07:00' - - .. versionadded:: 0.9 - - :param datetime: the ``datetime`` object; if `None`, the current date and - time in UTC is used - :param width: either "long" or "short" or "iso8601" or "iso8601_short" - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - :param return_z: True or False; Function returns indicator "Z" - when local time offset is 0 - """ - datetime = _ensure_datetime_tzinfo(_get_datetime(datetime)) - locale = Locale.parse(locale or LC_TIME) - - offset = datetime.tzinfo.utcoffset(datetime) - seconds = offset.days * 24 * 60 * 60 + offset.seconds - hours, seconds = divmod(seconds, 3600) - if return_z and hours == 0 and seconds == 0: - return 'Z' - elif seconds == 0 and width == 'iso8601_short': - return '%+03d' % hours - elif width == 'short' or width == 'iso8601_short': - pattern = '%+03d%02d' - elif width == 'iso8601': - pattern = '%+03d:%02d' - else: - pattern = locale.zone_formats['gmt'] % '%+03d:%02d' - return pattern % (hours, seconds // 60) - - -def get_timezone_location( - dt_or_tzinfo: _DtOrTzinfo = None, - locale: Locale | str | None = None, - return_city: bool = False, -) -> str: - """Return a representation of the given timezone using "location format". - - The result depends on both the local display name of the country and the - city associated with the time zone: - - >>> tz = get_timezone('America/St_Johns') - >>> print(get_timezone_location(tz, locale='de_DE')) - Kanada (St. John’s) (Ortszeit) - >>> print(get_timezone_location(tz, locale='en')) - Canada (St. John’s) Time - >>> print(get_timezone_location(tz, locale='en', return_city=True)) - St. John’s - >>> tz = get_timezone('America/Mexico_City') - >>> get_timezone_location(tz, locale='de_DE') - u'Mexiko (Mexiko-Stadt) (Ortszeit)' - - If the timezone is associated with a country that uses only a single - timezone, just the localized country name is returned: - - >>> tz = get_timezone('Europe/Berlin') - >>> get_timezone_name(tz, locale='de_DE') - u'Mitteleurop\\xe4ische Zeit' - - .. versionadded:: 0.9 - - :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines - the timezone; if `None`, the current date and time in - UTC is assumed - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - :param return_city: True or False, if True then return exemplar city (location) - for the time zone - :return: the localized timezone name using location format - - """ - locale = Locale.parse(locale or LC_TIME) - - zone = _get_tz_name(dt_or_tzinfo) - - # Get the canonical time-zone code - zone = get_global('zone_aliases').get(zone, zone) - - info = locale.time_zones.get(zone, {}) - - # Otherwise, if there is only one timezone for the country, return the - # localized country name - region_format = locale.zone_formats['region'] - territory = get_global('zone_territories').get(zone) - if territory not in locale.territories: - territory = 'ZZ' # invalid/unknown - territory_name = locale.territories[territory] - if not return_city and territory and len(get_global('territory_zones').get(territory, [])) == 1: - return region_format % territory_name - - # Otherwise, include the city in the output - fallback_format = locale.zone_formats['fallback'] - if 'city' in info: - city_name = info['city'] - else: - metazone = get_global('meta_zones').get(zone) - metazone_info = locale.meta_zones.get(metazone, {}) - if 'city' in metazone_info: - city_name = metazone_info['city'] - elif '/' in zone: - city_name = zone.split('/', 1)[1].replace('_', ' ') - else: - city_name = zone.replace('_', ' ') - - if return_city: - return city_name - return region_format % (fallback_format % { - '0': city_name, - '1': territory_name, - }) - - -def get_timezone_name( - dt_or_tzinfo: _DtOrTzinfo = None, - width: Literal['long', 'short'] = 'long', - uncommon: bool = False, - locale: Locale | str | None = None, - zone_variant: Literal['generic', 'daylight', 'standard'] | None = None, - return_zone: bool = False, -) -> str: - r"""Return the localized display name for the given timezone. The timezone - may be specified using a ``datetime`` or `tzinfo` object. - - >>> from datetime import time - >>> dt = time(15, 30, tzinfo=get_timezone('America/Los_Angeles')) - >>> get_timezone_name(dt, locale='en_US') # doctest: +SKIP - u'Pacific Standard Time' - >>> get_timezone_name(dt, locale='en_US', return_zone=True) - 'America/Los_Angeles' - >>> get_timezone_name(dt, width='short', locale='en_US') # doctest: +SKIP - u'PST' - - If this function gets passed only a `tzinfo` object and no concrete - `datetime`, the returned display name is independent of daylight savings - time. This can be used for example for selecting timezones, or to set the - time of events that recur across DST changes: - - >>> tz = get_timezone('America/Los_Angeles') - >>> get_timezone_name(tz, locale='en_US') - u'Pacific Time' - >>> get_timezone_name(tz, 'short', locale='en_US') - u'PT' - - If no localized display name for the timezone is available, and the timezone - is associated with a country that uses only a single timezone, the name of - that country is returned, formatted according to the locale: - - >>> tz = get_timezone('Europe/Berlin') - >>> get_timezone_name(tz, locale='de_DE') - u'Mitteleurop\xe4ische Zeit' - >>> get_timezone_name(tz, locale='pt_BR') - u'Hor\xe1rio da Europa Central' - - On the other hand, if the country uses multiple timezones, the city is also - included in the representation: - - >>> tz = get_timezone('America/St_Johns') - >>> get_timezone_name(tz, locale='de_DE') - u'Neufundland-Zeit' - - Note that short format is currently not supported for all timezones and - all locales. This is partially because not every timezone has a short - code in every locale. In that case it currently falls back to the long - format. - - For more information see `LDML Appendix J: Time Zone Display Names - `_ - - .. versionadded:: 0.9 - - .. versionchanged:: 1.0 - Added `zone_variant` support. - - :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines - the timezone; if a ``tzinfo`` object is used, the - resulting display name will be generic, i.e. - independent of daylight savings time; if `None`, the - current date in UTC is assumed - :param width: either "long" or "short" - :param uncommon: deprecated and ignored - :param zone_variant: defines the zone variation to return. By default the - variation is defined from the datetime object - passed in. If no datetime object is passed in, the - ``'generic'`` variation is assumed. The following - values are valid: ``'generic'``, ``'daylight'`` and - ``'standard'``. - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - :param return_zone: True or False. If true then function - returns long time zone ID - """ - dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo) - locale = Locale.parse(locale or LC_TIME) - - zone = _get_tz_name(dt_or_tzinfo) - - if zone_variant is None: - if dt is None: - zone_variant = 'generic' - else: - dst = tzinfo.dst(dt) - zone_variant = "daylight" if dst else "standard" - else: - if zone_variant not in ('generic', 'standard', 'daylight'): - raise ValueError('Invalid zone variation') - - # Get the canonical time-zone code - zone = get_global('zone_aliases').get(zone, zone) - if return_zone: - return zone - info = locale.time_zones.get(zone, {}) - # Try explicitly translated zone names first - if width in info and zone_variant in info[width]: - return info[width][zone_variant] - - metazone = get_global('meta_zones').get(zone) - if metazone: - metazone_info = locale.meta_zones.get(metazone, {}) - if width in metazone_info: - name = metazone_info[width].get(zone_variant) - if width == 'short' and name == NO_INHERITANCE_MARKER: - # If the short form is marked no-inheritance, - # try to fall back to the long name instead. - name = metazone_info.get('long', {}).get(zone_variant) - if name: - return name - - # If we have a concrete datetime, we assume that the result can't be - # independent of daylight savings time, so we return the GMT offset - if dt is not None: - return get_timezone_gmt(dt, width=width, locale=locale) - - return get_timezone_location(dt_or_tzinfo, locale=locale) - - -def format_date( - date: datetime.date | None = None, - format: _PredefinedTimeFormat | str = 'medium', - locale: Locale | str | None = None, -) -> str: - """Return a date formatted according to the given pattern. - - >>> from datetime import date - >>> d = date(2007, 4, 1) - >>> format_date(d, locale='en_US') - u'Apr 1, 2007' - >>> format_date(d, format='full', locale='de_DE') - u'Sonntag, 1. April 2007' - - If you don't want to use the locale default formats, you can specify a - custom date pattern: - - >>> format_date(d, "EEE, MMM d, ''yy", locale='en') - u"Sun, Apr 1, '07" - - :param date: the ``date`` or ``datetime`` object; if `None`, the current - date is used - :param format: one of "full", "long", "medium", or "short", or a custom - date/time pattern - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - """ - if date is None: - date = datetime.date.today() - elif isinstance(date, datetime.datetime): - date = date.date() - - locale = Locale.parse(locale or LC_TIME) - if format in ('full', 'long', 'medium', 'short'): - format = get_date_format(format, locale=locale) - pattern = parse_pattern(format) - return pattern.apply(date, locale) - - -def format_datetime( - datetime: _Instant = None, - format: _PredefinedTimeFormat | str = 'medium', - tzinfo: datetime.tzinfo | None = None, - locale: Locale | str | None = None, -) -> str: - r"""Return a date formatted according to the given pattern. - - >>> from datetime import datetime - >>> dt = datetime(2007, 4, 1, 15, 30) - >>> format_datetime(dt, locale='en_US') - u'Apr 1, 2007, 3:30:00\u202fPM' - - For any pattern requiring the display of the timezone: - - >>> format_datetime(dt, 'full', tzinfo=get_timezone('Europe/Paris'), - ... locale='fr_FR') - 'dimanche 1 avril 2007, 17:30:00 heure d’été d’Europe centrale' - >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz", - ... tzinfo=get_timezone('US/Eastern'), locale='en') - u'2007.04.01 AD at 11:30:00 EDT' - - :param datetime: the `datetime` object; if `None`, the current date and - time is used - :param format: one of "full", "long", "medium", or "short", or a custom - date/time pattern - :param tzinfo: the timezone to apply to the time for display - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - """ - datetime = _ensure_datetime_tzinfo(_get_datetime(datetime), tzinfo) - - locale = Locale.parse(locale or LC_TIME) - if format in ('full', 'long', 'medium', 'short'): - return get_datetime_format(format, locale=locale) \ - .replace("'", "") \ - .replace('{0}', format_time(datetime, format, tzinfo=None, - locale=locale)) \ - .replace('{1}', format_date(datetime, format, locale=locale)) - else: - return parse_pattern(format).apply(datetime, locale) - - -def format_time( - time: datetime.time | datetime.datetime | float | None = None, - format: _PredefinedTimeFormat | str = 'medium', - tzinfo: datetime.tzinfo | None = None, - locale: Locale | str | None = None, -) -> str: - r"""Return a time formatted according to the given pattern. - - >>> from datetime import datetime, time - >>> t = time(15, 30) - >>> format_time(t, locale='en_US') - u'3:30:00\u202fPM' - >>> format_time(t, format='short', locale='de_DE') - u'15:30' - - If you don't want to use the locale default formats, you can specify a - custom time pattern: - - >>> format_time(t, "hh 'o''clock' a", locale='en') - u"03 o'clock PM" - - For any pattern requiring the display of the time-zone a - timezone has to be specified explicitly: - - >>> t = datetime(2007, 4, 1, 15, 30) - >>> tzinfo = get_timezone('Europe/Paris') - >>> t = _localize(tzinfo, t) - >>> format_time(t, format='full', tzinfo=tzinfo, locale='fr_FR') - '15:30:00 heure d’été d’Europe centrale' - >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=get_timezone('US/Eastern'), - ... locale='en') - u"09 o'clock AM, Eastern Daylight Time" - - As that example shows, when this function gets passed a - ``datetime.datetime`` value, the actual time in the formatted string is - adjusted to the timezone specified by the `tzinfo` parameter. If the - ``datetime`` is "naive" (i.e. it has no associated timezone information), - it is assumed to be in UTC. - - These timezone calculations are **not** performed if the value is of type - ``datetime.time``, as without date information there's no way to determine - what a given time would translate to in a different timezone without - information about whether daylight savings time is in effect or not. This - means that time values are left as-is, and the value of the `tzinfo` - parameter is only used to display the timezone name if needed: - - >>> t = time(15, 30) - >>> format_time(t, format='full', tzinfo=get_timezone('Europe/Paris'), - ... locale='fr_FR') # doctest: +SKIP - u'15:30:00 heure normale d\u2019Europe centrale' - >>> format_time(t, format='full', tzinfo=get_timezone('US/Eastern'), - ... locale='en_US') # doctest: +SKIP - u'3:30:00\u202fPM Eastern Standard Time' - - :param time: the ``time`` or ``datetime`` object; if `None`, the current - time in UTC is used - :param format: one of "full", "long", "medium", or "short", or a custom - date/time pattern - :param tzinfo: the time-zone to apply to the time for display - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - """ - - # get reference date for if we need to find the right timezone variant - # in the pattern - ref_date = time.date() if isinstance(time, datetime.datetime) else None - - time = _get_time(time, tzinfo) - - locale = Locale.parse(locale or LC_TIME) - if format in ('full', 'long', 'medium', 'short'): - format = get_time_format(format, locale=locale) - return parse_pattern(format).apply(time, locale, reference_date=ref_date) - - -def format_skeleton( - skeleton: str, - datetime: _Instant = None, - tzinfo: datetime.tzinfo | None = None, - fuzzy: bool = True, - locale: Locale | str | None = None, -) -> str: - r"""Return a time and/or date formatted according to the given pattern. - - The skeletons are defined in the CLDR data and provide more flexibility - than the simple short/long/medium formats, but are a bit harder to use. - The are defined using the date/time symbols without order or punctuation - and map to a suitable format for the given locale. - - >>> from datetime import datetime - >>> t = datetime(2007, 4, 1, 15, 30) - >>> format_skeleton('MMMEd', t, locale='fr') - u'dim. 1 avr.' - >>> format_skeleton('MMMEd', t, locale='en') - u'Sun, Apr 1' - >>> format_skeleton('yMMd', t, locale='fi') # yMMd is not in the Finnish locale; yMd gets used - u'1.4.2007' - >>> format_skeleton('yMMd', t, fuzzy=False, locale='fi') # yMMd is not in the Finnish locale, an error is thrown - Traceback (most recent call last): - ... - KeyError: yMMd - >>> format_skeleton('GH', t, fuzzy=True, locale='fi_FI') # GH is not in the Finnish locale and there is no close match, an error is thrown - Traceback (most recent call last): - ... - KeyError: None - - After the skeleton is resolved to a pattern `format_datetime` is called so - all timezone processing etc is the same as for that. - - :param skeleton: A date time skeleton as defined in the cldr data. - :param datetime: the ``time`` or ``datetime`` object; if `None`, the current - time in UTC is used - :param tzinfo: the time-zone to apply to the time for display - :param fuzzy: If the skeleton is not found, allow choosing a skeleton that's - close enough to it. If there is no close match, a `KeyError` - is thrown. - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - """ - locale = Locale.parse(locale or LC_TIME) - if fuzzy and skeleton not in locale.datetime_skeletons: - skeleton = match_skeleton(skeleton, locale.datetime_skeletons) - format = locale.datetime_skeletons[skeleton] - return format_datetime(datetime, format, tzinfo, locale) - - -TIMEDELTA_UNITS: tuple[tuple[str, int], ...] = ( - ('year', 3600 * 24 * 365), - ('month', 3600 * 24 * 30), - ('week', 3600 * 24 * 7), - ('day', 3600 * 24), - ('hour', 3600), - ('minute', 60), - ('second', 1), -) - - -def format_timedelta( - delta: datetime.timedelta | int, - granularity: Literal['year', 'month', 'week', 'day', 'hour', 'minute', 'second'] = 'second', - threshold: float = .85, - add_direction: bool = False, - format: Literal['narrow', 'short', 'medium', 'long'] = 'long', - locale: Locale | str | None = None, -) -> str: - """Return a time delta according to the rules of the given locale. - - >>> from datetime import timedelta - >>> format_timedelta(timedelta(weeks=12), locale='en_US') - u'3 months' - >>> format_timedelta(timedelta(seconds=1), locale='es') - u'1 segundo' - - The granularity parameter can be provided to alter the lowest unit - presented, which defaults to a second. - - >>> format_timedelta(timedelta(hours=3), granularity='day', locale='en_US') - u'1 day' - - The threshold parameter can be used to determine at which value the - presentation switches to the next higher unit. A higher threshold factor - means the presentation will switch later. For example: - - >>> format_timedelta(timedelta(hours=23), threshold=0.9, locale='en_US') - u'1 day' - >>> format_timedelta(timedelta(hours=23), threshold=1.1, locale='en_US') - u'23 hours' - - In addition directional information can be provided that informs - the user if the date is in the past or in the future: - - >>> format_timedelta(timedelta(hours=1), add_direction=True, locale='en') - u'in 1 hour' - >>> format_timedelta(timedelta(hours=-1), add_direction=True, locale='en') - u'1 hour ago' - - The format parameter controls how compact or wide the presentation is: - - >>> format_timedelta(timedelta(hours=3), format='short', locale='en') - u'3 hr' - >>> format_timedelta(timedelta(hours=3), format='narrow', locale='en') - u'3h' - - :param delta: a ``timedelta`` object representing the time difference to - format, or the delta in seconds as an `int` value - :param granularity: determines the smallest unit that should be displayed, - the value can be one of "year", "month", "week", "day", - "hour", "minute" or "second" - :param threshold: factor that determines at which point the presentation - switches to the next higher unit - :param add_direction: if this flag is set to `True` the return value will - include directional information. For instance a - positive timedelta will include the information about - it being in the future, a negative will be information - about the value being in the past. - :param format: the format, can be "narrow", "short" or "long". ( - "medium" is deprecated, currently converted to "long" to - maintain compatibility) - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - """ - if format not in ('narrow', 'short', 'medium', 'long'): - raise TypeError('Format must be one of "narrow", "short" or "long"') - if format == 'medium': - warnings.warn( - '"medium" value for format param of format_timedelta' - ' is deprecated. Use "long" instead', - category=DeprecationWarning, - stacklevel=2, - ) - format = 'long' - if isinstance(delta, datetime.timedelta): - seconds = int((delta.days * 86400) + delta.seconds) - else: - seconds = delta - locale = Locale.parse(locale or LC_TIME) - date_fields = locale._data["date_fields"] - unit_patterns = locale._data["unit_patterns"] - - def _iter_patterns(a_unit): - if add_direction: - # Try to find the length variant version first ("year-narrow") - # before falling back to the default. - unit_rel_patterns = (date_fields.get(f"{a_unit}-{format}") or date_fields[a_unit]) - if seconds >= 0: - yield unit_rel_patterns['future'] - else: - yield unit_rel_patterns['past'] - a_unit = f"duration-{a_unit}" - unit_pats = unit_patterns.get(a_unit, {}) - yield unit_pats.get(format) - # We do not support `` tags at all while ingesting CLDR data, - # so these aliases specified in `root.xml` are hard-coded here: - # - # - if format in ("long", "narrow"): - yield unit_pats.get("short") - - for unit, secs_per_unit in TIMEDELTA_UNITS: - value = abs(seconds) / secs_per_unit - if value >= threshold or unit == granularity: - if unit == granularity and value > 0: - value = max(1, value) - value = int(round(value)) - plural_form = locale.plural_form(value) - pattern = None - for patterns in _iter_patterns(unit): - if patterns is not None: - pattern = patterns.get(plural_form) or patterns.get('other') - if pattern: - break - # This really should not happen - if pattern is None: - return '' - return pattern.replace('{0}', str(value)) - - return '' - - -def _format_fallback_interval( - start: _Instant, - end: _Instant, - skeleton: str | None, - tzinfo: datetime.tzinfo | None, - locale: Locale, -) -> str: - if skeleton in locale.datetime_skeletons: # Use the given skeleton - format = lambda dt: format_skeleton(skeleton, dt, tzinfo, locale=locale) - elif all((isinstance(d, datetime.date) and not isinstance(d, datetime.datetime)) for d in (start, end)): # Both are just dates - format = lambda dt: format_date(dt, locale=locale) - elif all((isinstance(d, datetime.time) and not isinstance(d, datetime.date)) for d in (start, end)): # Both are times - format = lambda dt: format_time(dt, tzinfo=tzinfo, locale=locale) - else: - format = lambda dt: format_datetime(dt, tzinfo=tzinfo, locale=locale) - - formatted_start = format(start) - formatted_end = format(end) - - if formatted_start == formatted_end: - return format(start) - - return ( - locale.interval_formats.get(None, "{0}-{1}"). - replace("{0}", formatted_start). - replace("{1}", formatted_end) - ) - - -def format_interval( - start: _Instant, - end: _Instant, - skeleton: str | None = None, - tzinfo: datetime.tzinfo | None = None, - fuzzy: bool = True, - locale: Locale | str | None = None, -) -> str: - """ - Format an interval between two instants according to the locale's rules. - - >>> from datetime import date, time - >>> format_interval(date(2016, 1, 15), date(2016, 1, 17), "yMd", locale="fi") - u'15.\u201317.1.2016' - - >>> format_interval(time(12, 12), time(16, 16), "Hm", locale="en_GB") - '12:12\u201316:16' - - >>> format_interval(time(5, 12), time(16, 16), "hm", locale="en_US") - '5:12\u202fAM\u2009–\u20094:16\u202fPM' - - >>> format_interval(time(16, 18), time(16, 24), "Hm", locale="it") - '16:18\u201316:24' - - If the start instant equals the end instant, the interval is formatted like the instant. - - >>> format_interval(time(16, 18), time(16, 18), "Hm", locale="it") - '16:18' - - Unknown skeletons fall back to "default" formatting. - - >>> format_interval(date(2015, 1, 1), date(2017, 1, 1), "wzq", locale="ja") - '2015/01/01\uff5e2017/01/01' - - >>> format_interval(time(16, 18), time(16, 24), "xxx", locale="ja") - '16:18:00\uff5e16:24:00' - - >>> format_interval(date(2016, 1, 15), date(2016, 1, 17), "xxx", locale="de") - '15.01.2016\u2009–\u200917.01.2016' - - :param start: First instant (datetime/date/time) - :param end: Second instant (datetime/date/time) - :param skeleton: The "skeleton format" to use for formatting. - :param tzinfo: tzinfo to use (if none is already attached) - :param fuzzy: If the skeleton is not found, allow choosing a skeleton that's - close enough to it. - :param locale: A locale object or identifier. Defaults to the system time locale. - :return: Formatted interval - """ - locale = Locale.parse(locale or LC_TIME) - - # NB: The quote comments below are from the algorithm description in - # https://www.unicode.org/reports/tr35/tr35-dates.html#intervalFormats - - # > Look for the intervalFormatItem element that matches the "skeleton", - # > starting in the current locale and then following the locale fallback - # > chain up to, but not including root. - - interval_formats = locale.interval_formats - - if skeleton not in interval_formats or not skeleton: - # > If no match was found from the previous step, check what the closest - # > match is in the fallback locale chain, as in availableFormats. That - # > is, this allows for adjusting the string value field's width, - # > including adjusting between "MMM" and "MMMM", and using different - # > variants of the same field, such as 'v' and 'z'. - if skeleton and fuzzy: - skeleton = match_skeleton(skeleton, interval_formats) - else: - skeleton = None - if not skeleton: # Still no match whatsoever? - # > Otherwise, format the start and end datetime using the fallback pattern. - return _format_fallback_interval(start, end, skeleton, tzinfo, locale) - - skel_formats = interval_formats[skeleton] - - if start == end: - return format_skeleton(skeleton, start, tzinfo, fuzzy=fuzzy, locale=locale) - - start = _ensure_datetime_tzinfo(_get_datetime(start), tzinfo=tzinfo) - end = _ensure_datetime_tzinfo(_get_datetime(end), tzinfo=tzinfo) - - start_fmt = DateTimeFormat(start, locale=locale) - end_fmt = DateTimeFormat(end, locale=locale) - - # > If a match is found from previous steps, compute the calendar field - # > with the greatest difference between start and end datetime. If there - # > is no difference among any of the fields in the pattern, format as a - # > single date using availableFormats, and return. - - for field in PATTERN_CHAR_ORDER: # These are in largest-to-smallest order - if field in skel_formats and start_fmt.extract(field) != end_fmt.extract(field): - # > If there is a match, use the pieces of the corresponding pattern to - # > format the start and end datetime, as above. - return "".join( - parse_pattern(pattern).apply(instant, locale) - for pattern, instant - in zip(skel_formats[field], (start, end)) - ) - - # > Otherwise, format the start and end datetime using the fallback pattern. - - return _format_fallback_interval(start, end, skeleton, tzinfo, locale) - - -def get_period_id( - time: _Instant, - tzinfo: datetime.tzinfo | None = None, - type: Literal['selection'] | None = None, - locale: Locale | str | None = None, -) -> str: - """ - Get the day period ID for a given time. - - This ID can be used as a key for the period name dictionary. - - >>> from datetime import time - >>> get_period_names(locale="de")[get_period_id(time(7, 42), locale="de")] - u'Morgen' - - >>> get_period_id(time(0), locale="en_US") - u'midnight' - - >>> get_period_id(time(0), type="selection", locale="en_US") - u'night1' - - :param time: The time to inspect. - :param tzinfo: The timezone for the time. See ``format_time``. - :param type: The period type to use. Either "selection" or None. - The selection type is used for selecting among phrases such as - “Your email arrived yesterday evening†or “Your email arrived last nightâ€. - :param locale: the `Locale` object, or a locale string. Defaults to the system time locale. - :return: period ID. Something is always returned -- even if it's just "am" or "pm". - """ - time = _get_time(time, tzinfo) - seconds_past_midnight = int(time.hour * 60 * 60 + time.minute * 60 + time.second) - locale = Locale.parse(locale or LC_TIME) - - # The LDML rules state that the rules may not overlap, so iterating in arbitrary - # order should be alright, though `at` periods should be preferred. - rulesets = locale.day_period_rules.get(type, {}).items() - - for rule_id, rules in rulesets: - for rule in rules: - if "at" in rule and rule["at"] == seconds_past_midnight: - return rule_id - - for rule_id, rules in rulesets: - for rule in rules: - if "from" in rule and "before" in rule: - if rule["from"] < rule["before"]: - if rule["from"] <= seconds_past_midnight < rule["before"]: - return rule_id - else: - # e.g. from="21:00" before="06:00" - if rule["from"] <= seconds_past_midnight < 86400 or \ - 0 <= seconds_past_midnight < rule["before"]: - return rule_id - - start_ok = end_ok = False - - if "from" in rule and seconds_past_midnight >= rule["from"]: - start_ok = True - if "to" in rule and seconds_past_midnight <= rule["to"]: - # This rule type does not exist in the present CLDR data; - # excuse the lack of test coverage. - end_ok = True - if "before" in rule and seconds_past_midnight < rule["before"]: - end_ok = True - if "after" in rule: - raise NotImplementedError("'after' is deprecated as of CLDR 29.") - - if start_ok and end_ok: - return rule_id - - if seconds_past_midnight < 43200: - return "am" - else: - return "pm" - - -class ParseError(ValueError): - pass - - -def parse_date( - string: str, - locale: Locale | str | None = None, - format: _PredefinedTimeFormat | str = 'medium', -) -> datetime.date: - """Parse a date from a string. - - If an explicit format is provided, it is used to parse the date. - - >>> parse_date('01.04.2004', format='dd.MM.yyyy') - datetime.date(2004, 4, 1) - - If no format is given, or if it is one of "full", "long", "medium", - or "short", the function first tries to interpret the string as - ISO-8601 date format and then uses the date format for the locale - as a hint to determine the order in which the date fields appear in - the string. - - >>> parse_date('4/1/04', locale='en_US') - datetime.date(2004, 4, 1) - >>> parse_date('01.04.2004', locale='de_DE') - datetime.date(2004, 4, 1) - >>> parse_date('2004-04-01', locale='en_US') - datetime.date(2004, 4, 1) - >>> parse_date('2004-04-01', locale='de_DE') - datetime.date(2004, 4, 1) - >>> parse_date('01.04.04', locale='de_DE', format='short') - datetime.date(2004, 4, 1) - - :param string: the string containing the date - :param locale: a `Locale` object or a locale identifier - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - :param format: the format to use, either an explicit date format, - or one of "full", "long", "medium", or "short" - (see ``get_time_format``) - """ - numbers = re.findall(r'(\d+)', string) - if not numbers: - raise ParseError("No numbers were found in input") - - use_predefined_format = format in ('full', 'long', 'medium', 'short') - # we try ISO-8601 format first, meaning similar to formats - # extended YYYY-MM-DD or basic YYYYMMDD - iso_alike = re.match(r'^(\d{4})-?([01]\d)-?([0-3]\d)$', - string, flags=re.ASCII) # allow only ASCII digits - if iso_alike and use_predefined_format: - try: - return datetime.date(*map(int, iso_alike.groups())) - except ValueError: - pass # a locale format might fit better, so let's continue - - if use_predefined_format: - fmt = get_date_format(format=format, locale=locale) - else: - fmt = parse_pattern(format) - format_str = fmt.pattern.lower() - year_idx = format_str.index('y') - month_idx = format_str.find('m') - if month_idx < 0: - month_idx = format_str.index('l') - day_idx = format_str.index('d') - - indexes = sorted([(year_idx, 'Y'), (month_idx, 'M'), (day_idx, 'D')]) - indexes = {item[1]: idx for idx, item in enumerate(indexes)} - - # FIXME: this currently only supports numbers, but should also support month - # names, both in the requested locale, and english - - year = numbers[indexes['Y']] - year = 2000 + int(year) if len(year) == 2 else int(year) - month = int(numbers[indexes['M']]) - day = int(numbers[indexes['D']]) - if month > 12: - month, day = day, month - return datetime.date(year, month, day) - - -def parse_time( - string: str, - locale: Locale | str | None = None, - format: _PredefinedTimeFormat | str = 'medium', -) -> datetime.time: - """Parse a time from a string. - - This function uses the time format for the locale as a hint to determine - the order in which the time fields appear in the string. - - If an explicit format is provided, the function will use it to parse - the time instead. - - >>> parse_time('15:30:00', locale='en_US') - datetime.time(15, 30) - >>> parse_time('15:30:00', format='H:mm:ss') - datetime.time(15, 30) - - :param string: the string containing the time - :param locale: a `Locale` object or a locale identifier. Defaults to the system time locale. - :param format: the format to use, either an explicit time format, - or one of "full", "long", "medium", or "short" - (see ``get_time_format``) - :return: the parsed time - :rtype: `time` - """ - numbers = re.findall(r'(\d+)', string) - if not numbers: - raise ParseError("No numbers were found in input") - - # TODO: try ISO format first? - if format in ('full', 'long', 'medium', 'short'): - fmt = get_time_format(format=format, locale=locale) - else: - fmt = parse_pattern(format) - format_str = fmt.pattern.lower() - hour_idx = format_str.find('h') - if hour_idx < 0: - hour_idx = format_str.index('k') - min_idx = format_str.index('m') - # format might not contain seconds - if (sec_idx := format_str.find('s')) < 0: - sec_idx = math.inf - - indexes = sorted([(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')]) - indexes = {item[1]: idx for idx, item in enumerate(indexes)} - - # TODO: support time zones - - # Check if the format specifies a period to be used; - # if it does, look for 'pm' to figure out an offset. - hour_offset = 0 - if 'a' in format_str and 'pm' in string.lower(): - hour_offset = 12 - - # Parse up to three numbers from the string. - minute = second = 0 - hour = int(numbers[indexes['H']]) + hour_offset - if len(numbers) > 1: - minute = int(numbers[indexes['M']]) - if len(numbers) > 2: - second = int(numbers[indexes['S']]) - return datetime.time(hour, minute, second) - - -class DateTimePattern: - - def __init__(self, pattern: str, format: DateTimeFormat): - self.pattern = pattern - self.format = format - - def __repr__(self) -> str: - return f"<{type(self).__name__} {self.pattern!r}>" - - def __str__(self) -> str: - pat = self.pattern - return pat - - def __mod__(self, other: DateTimeFormat) -> str: - if not isinstance(other, DateTimeFormat): - return NotImplemented - return self.format % other - - def apply( - self, - datetime: datetime.date | datetime.time, - locale: Locale | str | None, - reference_date: datetime.date | None = None, - ) -> str: - return self % DateTimeFormat(datetime, locale, reference_date) - - -class DateTimeFormat: - - def __init__( - self, - value: datetime.date | datetime.time, - locale: Locale | str, - reference_date: datetime.date | None = None, - ) -> None: - assert isinstance(value, (datetime.date, datetime.datetime, datetime.time)) - if isinstance(value, (datetime.datetime, datetime.time)) and value.tzinfo is None: - value = value.replace(tzinfo=UTC) - self.value = value - self.locale = Locale.parse(locale) - self.reference_date = reference_date - - def __getitem__(self, name: str) -> str: - char = name[0] - num = len(name) - if char == 'G': - return self.format_era(char, num) - elif char in ('y', 'Y', 'u'): - return self.format_year(char, num) - elif char in ('Q', 'q'): - return self.format_quarter(char, num) - elif char in ('M', 'L'): - return self.format_month(char, num) - elif char in ('w', 'W'): - return self.format_week(char, num) - elif char == 'd': - return self.format(self.value.day, num) - elif char == 'D': - return self.format_day_of_year(num) - elif char == 'F': - return self.format_day_of_week_in_month() - elif char in ('E', 'e', 'c'): - return self.format_weekday(char, num) - elif char in ('a', 'b', 'B'): - return self.format_period(char, num) - elif char == 'h': - if self.value.hour % 12 == 0: - return self.format(12, num) - else: - return self.format(self.value.hour % 12, num) - elif char == 'H': - return self.format(self.value.hour, num) - elif char == 'K': - return self.format(self.value.hour % 12, num) - elif char == 'k': - if self.value.hour == 0: - return self.format(24, num) - else: - return self.format(self.value.hour, num) - elif char == 'm': - return self.format(self.value.minute, num) - elif char == 's': - return self.format(self.value.second, num) - elif char == 'S': - return self.format_frac_seconds(num) - elif char == 'A': - return self.format_milliseconds_in_day(num) - elif char in ('z', 'Z', 'v', 'V', 'x', 'X', 'O'): - return self.format_timezone(char, num) - else: - raise KeyError(f"Unsupported date/time field {char!r}") - - def extract(self, char: str) -> int: - char = str(char)[0] - if char == 'y': - return self.value.year - elif char == 'M': - return self.value.month - elif char == 'd': - return self.value.day - elif char == 'H': - return self.value.hour - elif char == 'h': - return self.value.hour % 12 or 12 - elif char == 'm': - return self.value.minute - elif char == 'a': - return int(self.value.hour >= 12) # 0 for am, 1 for pm - else: - raise NotImplementedError(f"Not implemented: extracting {char!r} from {self.value!r}") - - def format_era(self, char: str, num: int) -> str: - width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[max(3, num)] - era = int(self.value.year >= 0) - return get_era_names(width, self.locale)[era] - - def format_year(self, char: str, num: int) -> str: - value = self.value.year - if char.isupper(): - month = self.value.month - if month == 1 and self.value.day < 7 and self.get_week_of_year() >= 52: - value -= 1 - elif month == 12 and self.value.day > 25 and self.get_week_of_year() <= 2: - value += 1 - year = self.format(value, num) - if num == 2: - year = year[-2:] - return year - - def format_quarter(self, char: str, num: int) -> str: - quarter = (self.value.month - 1) // 3 + 1 - if num <= 2: - return '%0*d' % (num, quarter) - width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] - context = {'Q': 'format', 'q': 'stand-alone'}[char] - return get_quarter_names(width, context, self.locale)[quarter] - - def format_month(self, char: str, num: int) -> str: - if num <= 2: - return '%0*d' % (num, self.value.month) - width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] - context = {'M': 'format', 'L': 'stand-alone'}[char] - return get_month_names(width, context, self.locale)[self.value.month] - - def format_week(self, char: str, num: int) -> str: - if char.islower(): # week of year - week = self.get_week_of_year() - return self.format(week, num) - else: # week of month - week = self.get_week_of_month() - return str(week) - - def format_weekday(self, char: str = 'E', num: int = 4) -> str: - """ - Return weekday from parsed datetime according to format pattern. - - >>> from datetime import date - >>> format = DateTimeFormat(date(2016, 2, 28), Locale.parse('en_US')) - >>> format.format_weekday() - u'Sunday' - - 'E': Day of week - Use one through three letters for the abbreviated day name, four for the full (wide) name, - five for the narrow name, or six for the short name. - >>> format.format_weekday('E',2) - u'Sun' - - 'e': Local day of week. Same as E except adds a numeric value that will depend on the local starting day of the - week, using one or two letters. For this example, Monday is the first day of the week. - >>> format.format_weekday('e',2) - '01' - - 'c': Stand-Alone local day of week - Use one letter for the local numeric value (same as 'e'), three for the - abbreviated day name, four for the full (wide) name, five for the narrow name, or six for the short name. - >>> format.format_weekday('c',1) - '1' - - :param char: pattern format character ('e','E','c') - :param num: count of format character - - """ - if num < 3: - if char.islower(): - value = 7 - self.locale.first_week_day + self.value.weekday() - return self.format(value % 7 + 1, num) - num = 3 - weekday = self.value.weekday() - width = {3: 'abbreviated', 4: 'wide', 5: 'narrow', 6: 'short'}[num] - context = "stand-alone" if char == "c" else "format" - return get_day_names(width, context, self.locale)[weekday] - - def format_day_of_year(self, num: int) -> str: - return self.format(self.get_day_of_year(), num) - - def format_day_of_week_in_month(self) -> str: - return str((self.value.day - 1) // 7 + 1) - - def format_period(self, char: str, num: int) -> str: - """ - Return period from parsed datetime according to format pattern. - - >>> from datetime import datetime, time - >>> format = DateTimeFormat(time(13, 42), 'fi_FI') - >>> format.format_period('a', 1) - u'ip.' - >>> format.format_period('b', 1) - u'iltap.' - >>> format.format_period('b', 4) - u'iltapäivä' - >>> format.format_period('B', 4) - u'iltapäivällä' - >>> format.format_period('B', 5) - u'ip.' - - >>> format = DateTimeFormat(datetime(2022, 4, 28, 6, 27), 'zh_Hant') - >>> format.format_period('a', 1) - u'上åˆ' - >>> format.format_period('B', 1) - u'清晨' - - :param char: pattern format character ('a', 'b', 'B') - :param num: count of format character - - """ - widths = [{3: 'abbreviated', 4: 'wide', 5: 'narrow'}[max(3, num)], - 'wide', 'narrow', 'abbreviated'] - if char == 'a': - period = 'pm' if self.value.hour >= 12 else 'am' - context = 'format' - else: - period = get_period_id(self.value, locale=self.locale) - context = 'format' if char == 'B' else 'stand-alone' - for width in widths: - period_names = get_period_names(context=context, width=width, locale=self.locale) - if period in period_names: - return period_names[period] - raise ValueError(f"Could not format period {period} in {self.locale}") - - def format_frac_seconds(self, num: int) -> str: - """ Return fractional seconds. - - Rounds the time's microseconds to the precision given by the number \ - of digits passed in. - """ - value = self.value.microsecond / 1000000 - return self.format(round(value, num) * 10**num, num) - - def format_milliseconds_in_day(self, num): - msecs = self.value.microsecond // 1000 + self.value.second * 1000 + \ - self.value.minute * 60000 + self.value.hour * 3600000 - return self.format(msecs, num) - - def format_timezone(self, char: str, num: int) -> str: - width = {3: 'short', 4: 'long', 5: 'iso8601'}[max(3, num)] - - # It could be that we only receive a time to format, but also have a - # reference date which is important to distinguish between timezone - # variants (summer/standard time) - value = self.value - if self.reference_date: - value = datetime.datetime.combine(self.reference_date, self.value) - - if char == 'z': - return get_timezone_name(value, width, locale=self.locale) - elif char == 'Z': - if num == 5: - return get_timezone_gmt(value, width, locale=self.locale, return_z=True) - return get_timezone_gmt(value, width, locale=self.locale) - elif char == 'O': - if num == 4: - return get_timezone_gmt(value, width, locale=self.locale) - # TODO: To add support for O:1 - elif char == 'v': - return get_timezone_name(value.tzinfo, width, - locale=self.locale) - elif char == 'V': - if num == 1: - return get_timezone_name(value.tzinfo, width, - uncommon=True, locale=self.locale) - elif num == 2: - return get_timezone_name(value.tzinfo, locale=self.locale, return_zone=True) - elif num == 3: - return get_timezone_location(value.tzinfo, locale=self.locale, return_city=True) - return get_timezone_location(value.tzinfo, locale=self.locale) - # Included additional elif condition to add support for 'Xx' in timezone format - elif char == 'X': - if num == 1: - return get_timezone_gmt(value, width='iso8601_short', locale=self.locale, - return_z=True) - elif num in (2, 4): - return get_timezone_gmt(value, width='short', locale=self.locale, - return_z=True) - elif num in (3, 5): - return get_timezone_gmt(value, width='iso8601', locale=self.locale, - return_z=True) - elif char == 'x': - if num == 1: - return get_timezone_gmt(value, width='iso8601_short', locale=self.locale) - elif num in (2, 4): - return get_timezone_gmt(value, width='short', locale=self.locale) - elif num in (3, 5): - return get_timezone_gmt(value, width='iso8601', locale=self.locale) - - def format(self, value: SupportsInt, length: int) -> str: - return '%0*d' % (length, value) - - def get_day_of_year(self, date: datetime.date | None = None) -> int: - if date is None: - date = self.value - return (date - date.replace(month=1, day=1)).days + 1 - - def get_week_of_year(self) -> int: - """Return the week of the year.""" - day_of_year = self.get_day_of_year(self.value) - week = self.get_week_number(day_of_year) - if week == 0: - date = datetime.date(self.value.year - 1, 12, 31) - week = self.get_week_number(self.get_day_of_year(date), - date.weekday()) - elif week > 52: - weekday = datetime.date(self.value.year + 1, 1, 1).weekday() - if self.get_week_number(1, weekday) == 1 and \ - 32 - (weekday - self.locale.first_week_day) % 7 <= self.value.day: - week = 1 - return week - - def get_week_of_month(self) -> int: - """Return the week of the month.""" - return self.get_week_number(self.value.day) - - def get_week_number(self, day_of_period: int, day_of_week: int | None = None) -> int: - """Return the number of the week of a day within a period. This may be - the week number in a year or the week number in a month. - - Usually this will return a value equal to or greater than 1, but if the - first week of the period is so short that it actually counts as the last - week of the previous period, this function will return 0. - - >>> date = datetime.date(2006, 1, 8) - >>> DateTimeFormat(date, 'de_DE').get_week_number(6) - 1 - >>> DateTimeFormat(date, 'en_US').get_week_number(6) - 2 - - :param day_of_period: the number of the day in the period (usually - either the day of month or the day of year) - :param day_of_week: the week day; if omitted, the week day of the - current date is assumed - """ - if day_of_week is None: - day_of_week = self.value.weekday() - first_day = (day_of_week - self.locale.first_week_day - - day_of_period + 1) % 7 - if first_day < 0: - first_day += 7 - week_number = (day_of_period + first_day - 1) // 7 - if 7 - first_day >= self.locale.min_week_days: - week_number += 1 - return week_number - - -PATTERN_CHARS: dict[str, list[int] | None] = { - 'G': [1, 2, 3, 4, 5], # era - 'y': None, 'Y': None, 'u': None, # year - 'Q': [1, 2, 3, 4, 5], 'q': [1, 2, 3, 4, 5], # quarter - 'M': [1, 2, 3, 4, 5], 'L': [1, 2, 3, 4, 5], # month - 'w': [1, 2], 'W': [1], # week - 'd': [1, 2], 'D': [1, 2, 3], 'F': [1], 'g': None, # day - 'E': [1, 2, 3, 4, 5, 6], 'e': [1, 2, 3, 4, 5, 6], 'c': [1, 3, 4, 5, 6], # week day - 'a': [1, 2, 3, 4, 5], 'b': [1, 2, 3, 4, 5], 'B': [1, 2, 3, 4, 5], # period - 'h': [1, 2], 'H': [1, 2], 'K': [1, 2], 'k': [1, 2], # hour - 'm': [1, 2], # minute - 's': [1, 2], 'S': None, 'A': None, # second - 'z': [1, 2, 3, 4], 'Z': [1, 2, 3, 4, 5], 'O': [1, 4], 'v': [1, 4], # zone - 'V': [1, 2, 3, 4], 'x': [1, 2, 3, 4, 5], 'X': [1, 2, 3, 4, 5], # zone -} - -#: The pattern characters declared in the Date Field Symbol Table -#: (https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table) -#: in order of decreasing magnitude. -PATTERN_CHAR_ORDER = "GyYuUQqMLlwWdDFgEecabBChHKkjJmsSAzZOvVXx" - - -def parse_pattern(pattern: str | DateTimePattern) -> DateTimePattern: - """Parse date, time, and datetime format patterns. - - >>> parse_pattern("MMMMd").format - u'%(MMMM)s%(d)s' - >>> parse_pattern("MMM d, yyyy").format - u'%(MMM)s %(d)s, %(yyyy)s' - - Pattern can contain literal strings in single quotes: - - >>> parse_pattern("H:mm' Uhr 'z").format - u'%(H)s:%(mm)s Uhr %(z)s' - - An actual single quote can be used by using two adjacent single quote - characters: - - >>> parse_pattern("hh' o''clock'").format - u"%(hh)s o'clock" - - :param pattern: the formatting pattern to parse - """ - if isinstance(pattern, DateTimePattern): - return pattern - return _cached_parse_pattern(pattern) - - -@lru_cache(maxsize=1024) -def _cached_parse_pattern(pattern: str) -> DateTimePattern: - result = [] - - for tok_type, tok_value in tokenize_pattern(pattern): - if tok_type == "chars": - result.append(tok_value.replace('%', '%%')) - elif tok_type == "field": - fieldchar, fieldnum = tok_value - limit = PATTERN_CHARS[fieldchar] - if limit and fieldnum not in limit: - raise ValueError(f"Invalid length for field: {fieldchar * fieldnum!r}") - result.append('%%(%s)s' % (fieldchar * fieldnum)) - else: - raise NotImplementedError(f"Unknown token type: {tok_type}") - return DateTimePattern(pattern, ''.join(result)) - - -def tokenize_pattern(pattern: str) -> list[tuple[str, str | tuple[str, int]]]: - """ - Tokenize date format patterns. - - Returns a list of (token_type, token_value) tuples. - - ``token_type`` may be either "chars" or "field". - - For "chars" tokens, the value is the literal value. - - For "field" tokens, the value is a tuple of (field character, repetition count). - - :param pattern: Pattern string - :type pattern: str - :rtype: list[tuple] - """ - result = [] - quotebuf = None - charbuf = [] - fieldchar = [''] - fieldnum = [0] - - def append_chars(): - result.append(('chars', ''.join(charbuf).replace('\0', "'"))) - del charbuf[:] - - def append_field(): - result.append(('field', (fieldchar[0], fieldnum[0]))) - fieldchar[0] = '' - fieldnum[0] = 0 - - for char in pattern.replace("''", '\0'): - if quotebuf is None: - if char == "'": # quote started - if fieldchar[0]: - append_field() - elif charbuf: - append_chars() - quotebuf = [] - elif char in PATTERN_CHARS: - if charbuf: - append_chars() - if char == fieldchar[0]: - fieldnum[0] += 1 - else: - if fieldchar[0]: - append_field() - fieldchar[0] = char - fieldnum[0] = 1 - else: - if fieldchar[0]: - append_field() - charbuf.append(char) - - elif quotebuf is not None: - if char == "'": # end of quote - charbuf.extend(quotebuf) - quotebuf = None - else: # inside quote - quotebuf.append(char) - - if fieldchar[0]: - append_field() - elif charbuf: - append_chars() - - return result - - -def untokenize_pattern(tokens: Iterable[tuple[str, str | tuple[str, int]]]) -> str: - """ - Turn a date format pattern token stream back into a string. - - This is the reverse operation of ``tokenize_pattern``. - - :type tokens: Iterable[tuple] - :rtype: str - """ - output = [] - for tok_type, tok_value in tokens: - if tok_type == "field": - output.append(tok_value[0] * tok_value[1]) - elif tok_type == "chars": - if not any(ch in PATTERN_CHARS for ch in tok_value): # No need to quote - output.append(tok_value) - else: - output.append("'%s'" % tok_value.replace("'", "''")) - return "".join(output) - - -def split_interval_pattern(pattern: str) -> list[str]: - """ - Split an interval-describing datetime pattern into multiple pieces. - - > The pattern is then designed to be broken up into two pieces by determining the first repeating field. - - https://www.unicode.org/reports/tr35/tr35-dates.html#intervalFormats - - >>> split_interval_pattern(u'E d.M. \u2013 E d.M.') - [u'E d.M. \u2013 ', 'E d.M.'] - >>> split_interval_pattern("Y 'text' Y 'more text'") - ["Y 'text '", "Y 'more text'"] - >>> split_interval_pattern(u"E, MMM d \u2013 E") - [u'E, MMM d \u2013 ', u'E'] - >>> split_interval_pattern("MMM d") - ['MMM d'] - >>> split_interval_pattern("y G") - ['y G'] - >>> split_interval_pattern(u"MMM d \u2013 d") - [u'MMM d \u2013 ', u'd'] - - :param pattern: Interval pattern string - :return: list of "subpatterns" - """ - - seen_fields = set() - parts = [[]] - - for tok_type, tok_value in tokenize_pattern(pattern): - if tok_type == "field": - if tok_value[0] in seen_fields: # Repeated field - parts.append([]) - seen_fields.clear() - seen_fields.add(tok_value[0]) - parts[-1].append((tok_type, tok_value)) - - return [untokenize_pattern(tokens) for tokens in parts] - - -def match_skeleton(skeleton: str, options: Iterable[str], allow_different_fields: bool = False) -> str | None: - """ - Find the closest match for the given datetime skeleton among the options given. - - This uses the rules outlined in the TR35 document. - - >>> match_skeleton('yMMd', ('yMd', 'yMMMd')) - 'yMd' - - >>> match_skeleton('yMMd', ('jyMMd',), allow_different_fields=True) - 'jyMMd' - - >>> match_skeleton('yMMd', ('qyMMd',), allow_different_fields=False) - - >>> match_skeleton('hmz', ('hmv',)) - 'hmv' - - :param skeleton: The skeleton to match - :type skeleton: str - :param options: An iterable of other skeletons to match against - :type options: Iterable[str] - :param allow_different_fields: Whether to allow a match that uses different fields - than the skeleton requested. - :type allow_different_fields: bool - - :return: The closest skeleton match, or if no match was found, None. - :rtype: str|None - """ - - # TODO: maybe implement pattern expansion? - - # Based on the implementation in - # https://github.com/unicode-org/icu/blob/main/icu4j/main/core/src/main/java/com/ibm/icu/text/DateIntervalInfo.java - - # Filter out falsy values and sort for stability; when `interval_formats` is passed in, there may be a None key. - options = sorted(option for option in options if option) - - if 'z' in skeleton and not any('z' in option for option in options): - skeleton = skeleton.replace('z', 'v') - if 'k' in skeleton and not any('k' in option for option in options): - skeleton = skeleton.replace('k', 'H') - if 'K' in skeleton and not any('K' in option for option in options): - skeleton = skeleton.replace('K', 'h') - if 'a' in skeleton and not any('a' in option for option in options): - skeleton = skeleton.replace('a', '') - if 'b' in skeleton and not any('b' in option for option in options): - skeleton = skeleton.replace('b', '') - - get_input_field_width = dict(t[1] for t in tokenize_pattern(skeleton) if t[0] == "field").get - best_skeleton = None - best_distance = None - for option in options: - get_opt_field_width = dict(t[1] for t in tokenize_pattern(option) if t[0] == "field").get - distance = 0 - for field in PATTERN_CHARS: - input_width = get_input_field_width(field, 0) - opt_width = get_opt_field_width(field, 0) - if input_width == opt_width: - continue - if opt_width == 0 or input_width == 0: - if not allow_different_fields: # This one is not okay - option = None - break - distance += 0x1000 # Magic weight constant for "entirely different fields" - elif field == 'M' and ((input_width > 2 and opt_width <= 2) or (input_width <= 2 and opt_width > 2)): - distance += 0x100 # Magic weight for "text turns into a number" - else: - distance += abs(input_width - opt_width) - - if not option: # We lost the option along the way (probably due to "allow_different_fields") - continue - - if not best_skeleton or distance < best_distance: - best_skeleton = option - best_distance = distance - - if distance == 0: # Found a perfect match! - break - - return best_skeleton diff --git a/extensions/.local/lib/python3.11/site-packages/babel/global.dat b/extensions/.local/lib/python3.11/site-packages/babel/global.dat deleted file mode 100644 index 386193b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/global.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c11607a7f9d2c1993a4b54b4927de0db4cc70189b6bebed3866bd5eeea83aa03 -size 459316 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/languages.py b/extensions/.local/lib/python3.11/site-packages/babel/languages.py deleted file mode 100644 index 564f555..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/languages.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from babel.core import get_global - - -def get_official_languages(territory: str, regional: bool = False, de_facto: bool = False) -> tuple[str, ...]: - """ - Get the official language(s) for the given territory. - - The language codes, if any are known, are returned in order of descending popularity. - - If the `regional` flag is set, then languages which are regionally official are also returned. - - If the `de_facto` flag is set, then languages which are "de facto" official are also returned. - - .. warning:: Note that the data is as up to date as the current version of the CLDR used - by Babel. If you need scientifically accurate information, use another source! - - :param territory: Territory code - :type territory: str - :param regional: Whether to return regionally official languages too - :type regional: bool - :param de_facto: Whether to return de-facto official languages too - :type de_facto: bool - :return: Tuple of language codes - :rtype: tuple[str] - """ - - territory = str(territory).upper() - allowed_stati = {"official"} - if regional: - allowed_stati.add("official_regional") - if de_facto: - allowed_stati.add("de_facto_official") - - languages = get_global("territory_languages").get(territory, {}) - pairs = [ - (info['population_percent'], language) - for language, info in languages.items() - if info.get('official_status') in allowed_stati - ] - pairs.sort(reverse=True) - return tuple(lang for _, lang in pairs) - - -def get_territory_language_info(territory: str) -> dict[str, dict[str, float | str | None]]: - """ - Get a dictionary of language information for a territory. - - The dictionary is keyed by language code; the values are dicts with more information. - - The following keys are currently known for the values: - - * `population_percent`: The percentage of the territory's population speaking the - language. - * `official_status`: An optional string describing the officiality status of the language. - Known values are "official", "official_regional" and "de_facto_official". - - .. warning:: Note that the data is as up to date as the current version of the CLDR used - by Babel. If you need scientifically accurate information, use another source! - - .. note:: Note that the format of the dict returned may change between Babel versions. - - See https://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html - - :param territory: Territory code - :type territory: str - :return: Language information dictionary - :rtype: dict[str, dict] - """ - territory = str(territory).upper() - return get_global("territory_languages").get(territory, {}).copy() diff --git a/extensions/.local/lib/python3.11/site-packages/babel/lists.py b/extensions/.local/lib/python3.11/site-packages/babel/lists.py deleted file mode 100644 index 353171c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/lists.py +++ /dev/null @@ -1,132 +0,0 @@ -""" - babel.lists - ~~~~~~~~~~~ - - Locale dependent formatting of lists. - - The default locale for the functions in this module is determined by the - following environment variables, in that order: - - * ``LC_ALL``, and - * ``LANG`` - - :copyright: (c) 2015-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Literal - -from babel.core import Locale, default_locale - -_DEFAULT_LOCALE = default_locale() # TODO(3.0): Remove this. - - -def __getattr__(name): - if name == "DEFAULT_LOCALE": - warnings.warn( - "The babel.lists.DEFAULT_LOCALE constant is deprecated and will be removed.", - DeprecationWarning, - stacklevel=2, - ) - return _DEFAULT_LOCALE - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - - -def format_list( - lst: Sequence[str], - style: Literal['standard', 'standard-short', 'or', 'or-short', 'unit', 'unit-short', 'unit-narrow'] = 'standard', - locale: Locale | str | None = None, -) -> str: - """ - Format the items in `lst` as a list. - - >>> format_list(['apples', 'oranges', 'pears'], locale='en') - u'apples, oranges, and pears' - >>> format_list(['apples', 'oranges', 'pears'], locale='zh') - u'apples\u3001oranges\u548cpears' - >>> format_list(['omena', 'peruna', 'aplari'], style='or', locale='fi') - u'omena, peruna tai aplari' - - Not all styles are necessarily available in all locales. - The function will attempt to fall back to replacement styles according to the rules - set forth in the CLDR root XML file, and raise a ValueError if no suitable replacement - can be found. - - The following text is verbatim from the Unicode TR35-49 spec [1]. - - * standard: - A typical 'and' list for arbitrary placeholders. - eg. "January, February, and March" - * standard-short: - A short version of an 'and' list, suitable for use with short or abbreviated placeholder values. - eg. "Jan., Feb., and Mar." - * or: - A typical 'or' list for arbitrary placeholders. - eg. "January, February, or March" - * or-short: - A short version of an 'or' list. - eg. "Jan., Feb., or Mar." - * unit: - A list suitable for wide units. - eg. "3 feet, 7 inches" - * unit-short: - A list suitable for short units - eg. "3 ft, 7 in" - * unit-narrow: - A list suitable for narrow units, where space on the screen is very limited. - eg. "3′ 7″" - - [1]: https://www.unicode.org/reports/tr35/tr35-49/tr35-general.html#ListPatterns - - :param lst: a sequence of items to format in to a list - :param style: the style to format the list with. See above for description. - :param locale: the locale. Defaults to the system locale. - """ - locale = Locale.parse(locale or _DEFAULT_LOCALE) - if not lst: - return '' - if len(lst) == 1: - return lst[0] - - patterns = _resolve_list_style(locale, style) - - if len(lst) == 2 and '2' in patterns: - return patterns['2'].format(*lst) - - result = patterns['start'].format(lst[0], lst[1]) - for elem in lst[2:-1]: - result = patterns['middle'].format(result, elem) - result = patterns['end'].format(result, lst[-1]) - - return result - - -# Based on CLDR 45's root.xml file's ``es. -# The root file defines both `standard` and `or`, -# so they're always available. -# TODO: It would likely be better to use the -# babel.localedata.Alias mechanism for this, -# but I'm not quite sure how it's supposed to -# work with inheritance and data in the root. -_style_fallbacks = { - "or-narrow": ["or-short", "or"], - "or-short": ["or"], - "standard-narrow": ["standard-short", "standard"], - "standard-short": ["standard"], - "unit": ["unit-short", "standard"], - "unit-narrow": ["unit-short", "unit", "standard"], - "unit-short": ["standard"], -} - - -def _resolve_list_style(locale: Locale, style: str): - for style in (style, *(_style_fallbacks.get(style, []))): # noqa: B020 - if style in locale.list_patterns: - return locale.list_patterns[style] - raise ValueError( - f"Locale {locale} does not support list formatting style {style!r} " - f"(supported are {sorted(locale.list_patterns)})", - ) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/LICENSE.unicode b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/LICENSE.unicode deleted file mode 100644 index 861b74f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/LICENSE.unicode +++ /dev/null @@ -1,41 +0,0 @@ -UNICODE LICENSE V3 - -COPYRIGHT AND PERMISSION NOTICE - -Copyright © 2004-2025 Unicode, Inc. - -NOTICE TO USER: Carefully read the following legal agreement. BY -DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR -SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT -DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of data files and any associated documentation (the "Data Files") or -software and any associated documentation (the "Software") to deal in the -Data Files or Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Data Files or Software, and to permit persons to whom the -Data Files or Software are furnished to do so, provided that either (a) -this copyright and permission notice appear with all copies of the Data -Files or Software, or (b) this copyright and permission notice appear in -associated Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -THIRD PARTY RIGHTS. - -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE -BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, -OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA -FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder shall -not be used in advertising or otherwise to promote the sale, use or other -dealings in these Data Files or Software without prior written -authorization of the copyright holder. - -SPDX-License-Identifier: Unicode-3.0 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa.dat deleted file mode 100644 index 0c737e9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:088e64395697597d824281d3e805e1ace33014f0a243277b5a47b640127552d1 -size 2795 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_DJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_DJ.dat deleted file mode 100644 index 2c81d35..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_DJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54a8d280a56c7ed1bdd678f4f8040c605b85fe9e180067d192002fc9c0761185 -size 1112 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ER.dat deleted file mode 100644 index 9d30036..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e9beaa44ec2878eab4f9b6ad33567b262da0bc60e8825dce0dc7edb752649bd8 -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ET.dat deleted file mode 100644 index 9c85980..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/aa_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a62c05bbde07edefa33f077865a5a20dcfa3da7007fc6882e54676231331edbb -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab.dat deleted file mode 100644 index e5b5435..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c5e8a8d4d2c134801771a7e7a275a33b7c34ce87f033e68aaf4f9189a2fba514 -size 95311 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab_GE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab_GE.dat deleted file mode 100644 index b5e4cd6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ab_GE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f96ded94bf562d3fe6e431ab09333a103f124f34b16a89f5e70a22bcac2c8b1 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af.dat deleted file mode 100644 index 0302946..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a4ef7fdc1a49490009de067f8fa65d5291aadf3a84bfa088659f82a494d7c2be -size 144732 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_NA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_NA.dat deleted file mode 100644 index e8209d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_NA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce27fffd3c8d638e2648260e0abae096ccabfc7df526104d3f04897ed83cdb4d -size 1450 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_ZA.dat deleted file mode 100644 index a9be8a3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/af_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ea54fe98b83b2d1b72004856862176c55b623f2cc46b6f14ea1b05c3f04cad91 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq.dat deleted file mode 100644 index 5af0545..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2496c5e8d151f6ac30413ac8cab2e1d380c5267888a83b85b1b9870c6bb94e13 -size 16628 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq_CM.dat deleted file mode 100644 index 94babca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/agq_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:858b60ee9470ec9e93b181ef865104bfb0eaa725e82b7292f4302ab58b60057d -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak.dat deleted file mode 100644 index c3b4981..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2fbdf2ff2961672dfd4a511a0300388c2a8fffddaa2ef225b1a825fa8d9194a1 -size 116224 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak_GH.dat deleted file mode 100644 index 4864606..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ak_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b4cf8e4a95d6c81c1915f28f552b5605b16fdddc0d8ffec0a9c073e0e36b390b -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am.dat deleted file mode 100644 index 50fd1c7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4dd75f79121216fce34c5a41faf1f782348ab36afc893dc261c92bae289b5d96 -size 173260 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am_ET.dat deleted file mode 100644 index c4a641a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/am_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d956434a1e5b63dbcb2ee4ea70a606ebaa7939896f3d13d7e7cae93531563e89 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an.dat deleted file mode 100644 index abe6e94..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b5804ced72a5a830b5b77f9fe3943c5c3ec618f88b47295b9dee08e2b2b4b81 -size 28050 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an_ES.dat deleted file mode 100644 index 1cb3222..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/an_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad0baafb32a3efe7c28d8fb97c61a81894f5c7ad2903208401512cc173e71eb2 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann.dat deleted file mode 100644 index f8e0956..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7d47a7bce74f8ea6b22c48950d136770af123818bd80018077132e3804e5b08d -size 737 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann_NG.dat deleted file mode 100644 index 0173868..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ann_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d22d8ae9cbfa782bab805830b620abd3d858c19080d641e441a2a70f2083f3a3 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc.dat deleted file mode 100644 index 9f5d80e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1bde96f9e6cba90953b8f377f95a927c063e185d0af7d73ab971f36b97f87b68 -size 1564 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc_SY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc_SY.dat deleted file mode 100644 index 7f0220d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/apc_SY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5a805790cfc040f4f73b44caa471ed596a57ca2018ea834491e0d96919069a3 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar.dat deleted file mode 100644 index ca4fdcd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c808a396491a1fe46045089dbc2c8d064a62f59ece4c2f5c35f21b2a8e27e209 -size 288582 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_001.dat deleted file mode 100644 index 64ca376..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:851283237c33c4ee53d7dd4c7d27429ff319e9c90cd91cffaffff4259a92d34b -size 1707 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_AE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_AE.dat deleted file mode 100644 index c5fa4a3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_AE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8446c8614a0d1399912ce557866906b2f4f434072afabc6ce7554830ccc6f4b6 -size 982 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_BH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_BH.dat deleted file mode 100644 index 6b6826d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_BH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1684367371374c3a8a722a1aad606f2e2fcc96526649dff9eabd14e39fe01d6c -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DJ.dat deleted file mode 100644 index ee221c5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a9b35a9bf4009a1a1bb0851f24b08bf697b5e3a4af72634813f2f7716a66901b -size 698 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DZ.dat deleted file mode 100644 index d12b20e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_DZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd8f892c2e618a7727c737bbb06984a5becde099c187b2dd15d6953dc48c0ef3 -size 1263 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EG.dat deleted file mode 100644 index 230fe0b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a84de02d0e81ccb68138f34956068184f42220bda44380220ff8cb97ba39d883 -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EH.dat deleted file mode 100644 index ee30fbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_EH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b4c49746258cc61737efc316550cfef25119539bddc54124d0e6aa775c3318a -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_ER.dat deleted file mode 100644 index 442635e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:97e5a325fc66ee43f4e7e1e7af93e29e01da296278e9271f5b828405cc03e473 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IL.dat deleted file mode 100644 index 0257f00..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b75180237f8041dcd75c4904e7f91ccd8f28f89334c1857deaec4f3ef408a1c -size 1264 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IQ.dat deleted file mode 100644 index 9b6b9dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efe0e7a07aaca010def995ded2b21c128b5bf85fc21720a173bdddc275ee5281 -size 1975 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_JO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_JO.dat deleted file mode 100644 index 6ca4d8a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_JO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:853d73f8c7b948e8ee97704716e6dcaa5c8493d1f9edfc03e0414435d76256df -size 1398 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KM.dat deleted file mode 100644 index 900de8e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:671e57b5f4ee44f896ea25623a379a97f16afb5f0403b1ae11156230fd7f99ce -size 1230 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KW.dat deleted file mode 100644 index fdb4a1f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_KW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d704971d372014ac2135c8954bc22f18abe4cf3a8e20c045ca41091105dd8441 -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LB.dat deleted file mode 100644 index 2e7876d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f92b973ba2dd857362e1ffcf1cdae5c65f225d7e3ba5ead0fe84b5f5bc111a92 -size 1414 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LY.dat deleted file mode 100644 index 976d901..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_LY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8ec52183d6092258f71a447775a90bfd89f1bcd9612319a84aaa1b281577e76 -size 1249 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MA.dat deleted file mode 100644 index 7530222..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8533b0b170bcb6c271055964b319803252249f890ae748ee25ae93b803c5929d -size 1559 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MR.dat deleted file mode 100644 index a0c3304..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_MR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2aaeee4f92f1bd85e7196cfe715708eb20cdc629aef61648a682b276656c7bbf -size 1359 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_OM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_OM.dat deleted file mode 100644 index b67cc79..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_OM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d53aa4dfa07dc95531c92fec8306221a7cd7dc914ec221c3bfb08cd705f7cac -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_PS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_PS.dat deleted file mode 100644 index af9b18d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_PS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:17e1d944f70c7bfb49f2bf55d3587eee643450a431426b96b973528bde0c54c3 -size 1336 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_QA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_QA.dat deleted file mode 100644 index 45f9099..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_QA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50a7cba725fce7a7cd81e89f76bdb6c17a439dc8ab5898bd371a9f4a74beedfc -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SA.dat deleted file mode 100644 index 876f365..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f1613c1f00b03be393fc6d890528263d64b3c8739d200df36a35cf6c166bd938 -size 24787 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SD.dat deleted file mode 100644 index 5c61002..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7fb6942a5aca9a60bb8a34e35709f9afd9b799f65f1286f56bb1875428f84319 -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SO.dat deleted file mode 100644 index 7e8575f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0b0ff81db3656cbf17451e9168e7a0b14c57a7ccd76f1243287dce284c60535 -size 677 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SS.dat deleted file mode 100644 index 0d9769a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4fa79e58f7857a39810bb2272aa83eeaa996a1eaf5be397ab2b1deff9c9b9035 -size 700 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SY.dat deleted file mode 100644 index ebc8d7e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_SY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bb8dae8637bfcedf34e96954329a79b08762d728f0dd8bfbbd86e5e9a10bb327 -size 1398 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TD.dat deleted file mode 100644 index 0d28788..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:386ecd62d46b2620de46dec73fe078b5ae6b8bee9f7529d8a26a697f2d80e1e7 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TN.dat deleted file mode 100644 index 07f13cb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_TN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c4ef7be0dc8ee53fa946cfb96f9e6c7d0146230536638ab755051eaada967fcd -size 1201 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_YE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_YE.dat deleted file mode 100644 index 7944f8c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ar_YE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:beef30609833709d5da2e29f28bc77fa1020d6c8e7743e7f3d31d61bf6f344bd -size 720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn.dat deleted file mode 100644 index bcdf3aa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:241f907f008e5506d5acb465ab62ccc54e921cef95e19694dbfd16d79fb445fb -size 721 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn_CL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn_CL.dat deleted file mode 100644 index 33d75b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/arn_CL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:71ffc9add200c45c1b96d570b65a0d0bde76ec3bbbcdaa010ccfbf2a672d4af1 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as.dat deleted file mode 100644 index cbd8993..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c684e68627a80158f0e7d876fbfa4ba74c237d93d5bd8315eaa0d22632eb8eaf -size 209876 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as_IN.dat deleted file mode 100644 index a3301b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/as_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c4f8e674637776f90b43db7ced8e5b92b05935fd114d60c1732a0042df06b0e -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa.dat deleted file mode 100644 index 50ec8dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf33eeecbf1157c49510aa9e462188a162c108991e4b469c0e1d2962af3ba8c2 -size 15492 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa_TZ.dat deleted file mode 100644 index 5abaa7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/asa_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:534194d7468fe7c2f109eab28e5ebd4500998bfead4d0c66daf9e2e97564a2a6 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast.dat deleted file mode 100644 index 6074e89..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd07a8734833d5a83d32498d22ebf8b9f5639347c7e71b56e0ceefa7c493e216 -size 168961 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast_ES.dat deleted file mode 100644 index 8e56a2e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ast_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e75905c62815e423ae88f88d8aca7e381158322b61e6b520066538f2b1a4ec77 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az.dat deleted file mode 100644 index 9a838a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8473031cf2a22a096fc5d087365e3150b619021b27cb37327325953df5971a0 -size 173802 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab.dat deleted file mode 100644 index 35acf50..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2060656bbde829abe52c786d216dfb89d1f14e4990599f92f0d139e1beb97789 -size 7499 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IQ.dat deleted file mode 100644 index 0d76e84..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:56c334f8a40f08fe0c530fb6c0cb01bfe178ebb72bd81ba9de37f1c7c15cdd91 -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IR.dat deleted file mode 100644 index 9062913..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:44e6f48054cfc0ae42723a50301ec227aeb67a577db198fb200e9032bbf182da -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_TR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_TR.dat deleted file mode 100644 index 375198b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Arab_TR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:115e9c35fde478135110791f17df0619918e673e0be5dc5ff2915bba32276906 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl.dat deleted file mode 100644 index 37da9c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aeee1061e7b5ef8b682d0b063c99fe77ac5eeb916c2d0f3bbc157d016d28e03f -size 35540 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl_AZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl_AZ.dat deleted file mode 100644 index 2457458..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Cyrl_AZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19166347e829e8961e2cdc6888028d76ff5b913992d5ba589d127473d6081b0b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn.dat deleted file mode 100644 index 7e34cdc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:68adb38b2b60e4883a19893db550aae0113257a518cbd229ec5d7f8b83ead63c -size 2258 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn_AZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn_AZ.dat deleted file mode 100644 index 2457458..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/az_Latn_AZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19166347e829e8961e2cdc6888028d76ff5b913992d5ba589d127473d6081b0b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba.dat deleted file mode 100644 index 26fe238..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f2d55e3004d3382820c6b6ecbda02ba0e1f67354d105a97388f172a191614e4 -size 732 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba_RU.dat deleted file mode 100644 index 504f28f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ba_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f1873050ec7787805c49f508ba6289e30705ca24a004cef84aa7a75484142a2f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal.dat deleted file mode 100644 index ef758f9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9983133737a3fe569cdc68a636af5d6202d8dd0e11b57a44bd4910fb37f356ac -size 12849 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab.dat deleted file mode 100644 index 891fc08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:db9095979ac5ec5a8a11e1f3026b7405c71523f383aa630ff3a2aa4388ba3cbf -size 934 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab_PK.dat deleted file mode 100644 index 55cdb87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Arab_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b32e2da54b4dd52b79c85a13a7c0bafaf8b66c518f8d2686ff30db635e90f7cf -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn.dat deleted file mode 100644 index d04ea38..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fdb04bc2ed25345541676a9cc5294ab49ef7356b3d5cf651e6ac23c73c28385 -size 116909 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn_PK.dat deleted file mode 100644 index 55cdb87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bal_Latn_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b32e2da54b4dd52b79c85a13a7c0bafaf8b66c518f8d2686ff30db635e90f7cf -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas.dat deleted file mode 100644 index 7d0014c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:86db36fa0a28661786c67768ca254cf4dc05ac08adb617dbe083ebed3b586f65 -size 16673 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas_CM.dat deleted file mode 100644 index 6caf4c5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bas_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:581abefeb3af9019d3e6905a0b2abce382cb49145e4338361ccd2eec69a128a3 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be.dat deleted file mode 100644 index 79bcdb7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0be90d02e308db2cc0bd23b96d168635a6b013b9177ef279f4b9da6b60123a0 -size 272322 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_BY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_BY.dat deleted file mode 100644 index 4968f22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_BY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c8de117f6f87aa29ccb1c4df7b88ca118a6c08469d74771ee8adb9a25e7de408 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_TARASK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_TARASK.dat deleted file mode 100644 index ad50053..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/be_TARASK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f77c43c4ed3a9ee02e8295a3ae7c7a0b993c16cdba1c80289547143eea0785b8 -size 104118 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem.dat deleted file mode 100644 index ed3d101..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc18791f163e85181a41df796a79aa3003cfd14573495ec975cbaab49efcb757 -size 5782 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem_ZM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem_ZM.dat deleted file mode 100644 index f564bca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bem_ZM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d0bec2cad053929607fac2ca5075b8f4d08bde3bad9cd8cbf18f39f8787192b -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew.dat deleted file mode 100644 index 0459f5d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:99f291db73d23f24b4007c5b692b8cbee7d965094c202c431ae3efefc32d0db5 -size 122095 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew_ID.dat deleted file mode 100644 index a03ab70..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bew_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:25629b9d441ce19b09613701172a4ade04b21512ba2a9f14144a9dcad9cf3273 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez.dat deleted file mode 100644 index 58b85db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fec6844ab99bc6c6d09c62c00b290522cf9a2d40be37b222829c8f5862c179b2 -size 16300 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez_TZ.dat deleted file mode 100644 index 656eef8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bez_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b070a7a5854c505aefbc266f677f6bc26b2ebef0b42f83eb9e65237f9ab1b3d -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg.dat deleted file mode 100644 index 02efa9b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a1f77f4efe289c83f5704d6954efb5ef5c9247d2495ee1cace95aa73ebed2cff -size 227940 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg_BG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg_BG.dat deleted file mode 100644 index 58a3ecc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bg_BG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:084445cae0b80f0f417c065aa6a6aaebd88a029eeb05758d0a42d600be6d0214 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc.dat deleted file mode 100644 index 8332396..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:816d25910357fe1d520136eacc8a9ed2dc261aaa9f8a091baa8ee0bc1086d402 -size 2493 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc_IN.dat deleted file mode 100644 index 94f65fe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgc_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:84edfd9cf8b2531d647c275a829090f25ccf2f272375f939f6315082c77741e7 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn.dat deleted file mode 100644 index 947ecb5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f112b39866066249f9205ecd1d180fb5a23da33c027842a8504e1a5d0a48b4a6 -size 28964 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AE.dat deleted file mode 100644 index f91b7b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e63a3b0165cc35d8a211ff91ab3079c51563d11f3d345770ab944020401e7911 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AF.dat deleted file mode 100644 index a0792e2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_AF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51709befc9f9eda75905d2871069e16e6795629a73952b1c54e5a740dc5f24e4 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_IR.dat deleted file mode 100644 index 1557ff1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:897c723c3e59fa8b83585a4e1366ada22ebe1c71a80fa3cd693f5cf931fac7ba -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_OM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_OM.dat deleted file mode 100644 index cba0e3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_OM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dced02cc5ae35b139015d37afa50e10b14678285df69d77f7706285728caf630 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_PK.dat deleted file mode 100644 index ddaf916..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bgn_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:81d55471cfa2b0777d95fd12f80985a0f20cc0367c6b2e8d638a35b9d588e98a -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho.dat deleted file mode 100644 index 32a4010..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2500048666a317050e281ec008dd7e64f72829c5c96aad3e161b0509572f9fff -size 2875 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho_IN.dat deleted file mode 100644 index 3376770..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bho_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51c2ff699ab7e5d387304d05bb1f73cadf41e81393c7247952f68658a2ecd631 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo.dat deleted file mode 100644 index 012c577..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23481fb06bfcd317fb768fa8c738e4876a2bf77e18c5880332433d4477fb5179 -size 168499 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo_BJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo_BJ.dat deleted file mode 100644 index 01eadc1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blo_BJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2ccefda14cd523826d2d81149257db431a3078502c94df634be131f9dc9ad261 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt.dat deleted file mode 100644 index 3f31e8d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e86d84f68b01cbd3ab1b589428b0fd730711937215edf4f5d6223ccc590b69ea -size 723 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt_VN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt_VN.dat deleted file mode 100644 index 3d2d279..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/blt_VN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be94d010962cb26b81527fe962ac7b66d60e34d373d36fe805894331d5aa2807 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm.dat deleted file mode 100644 index 2dfae2b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2b474b971a037c96f840bc1afc3d125dfadb0f9dd779dfc4276d7ce377d8f616 -size 15798 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_ML.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_ML.dat deleted file mode 100644 index 4615c5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_ML.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c01ab5307354baab7d830c74eee4b91e3c55defccfe2fd6c48638a0bb949f3c -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo.dat deleted file mode 100644 index fd2ea92..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52243ea0a4976266e7523f673578bef407f1dad68173912237e24cd61b863a7a -size 2805 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo_ML.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo_ML.dat deleted file mode 100644 index 4615c5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bm_Nkoo_ML.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c01ab5307354baab7d830c74eee4b91e3c55defccfe2fd6c48638a0bb949f3c -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn.dat deleted file mode 100644 index 0711d8e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d34711298af0ca4e6c9e1ade90b8f44d0055cd9955fcf8d0d1a2e5b00a60c31c -size 219185 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_BD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_BD.dat deleted file mode 100644 index 8bc2b15..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_BD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9955bdd24426843730cca9a49a0340b7988cab5a4b5a636774d203f5fb295636 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_IN.dat deleted file mode 100644 index aca5411..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bn_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:638779b4cbfaac6d80d5f4dc7cdefe70c799d621fc5eea9d660a44054cbf1538 -size 4035 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo.dat deleted file mode 100644 index d0e5bae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d9e56a9ce14fbf4e08c7ed4554f1e50d0f54553402d49b42efee6543cf5a5fb0 -size 20102 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_CN.dat deleted file mode 100644 index 349d8b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c4e9f2adef356752079d65799891f4c77d7787e656bbce2121770cb81e74213d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_IN.dat deleted file mode 100644 index 4de7319..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bo_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1af60282dace0f9cd862c7ccb559a40aff3ecba1e2b3c2e0ee2bb2b441a39cc2 -size 1307 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br.dat deleted file mode 100644 index 089ba80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac1b35069f47e90e0408eda6a2ea099a7096d2ec7908b3f1d73cb7d86be9902a -size 272612 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br_FR.dat deleted file mode 100644 index 9a16d6d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/br_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:de854375977b5dfe10fa1c2662b685e3648cff736dbd2a226659a587a81234eb -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx.dat deleted file mode 100644 index dc01835..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d0bf2b7d0c23c2d8f7cb9339cf3744075d306b2e08f4fda6f00d84d264c871a7 -size 160164 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx_IN.dat deleted file mode 100644 index 2c4191b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/brx_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:34ab8987470485141ab32e89006522e476ea7678611054d0ffba2c82d746e48c -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs.dat deleted file mode 100644 index b1a395e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6152db5c62c77fa419f6f6270a3c633b7b81226b989e8c51f9c12e04f55b3ffc -size 213968 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl.dat deleted file mode 100644 index fe8b2cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2a17010515f62acb3915becc23f0247607f4426f9d4ccaff2341a0c38f3d2ef -size 219235 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl_BA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl_BA.dat deleted file mode 100644 index 3b72106..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Cyrl_BA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a00eebb1072413f2310a95d70771772964303375994d1ed601d63124df7ca1e3 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn.dat deleted file mode 100644 index 3e2b413..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8bf5263ce6138d4473b8273dfcf42d998b2ee594a703a3254d884f7aa33089f -size 1990 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn_BA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn_BA.dat deleted file mode 100644 index 3b72106..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bs_Latn_BA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a00eebb1072413f2310a95d70771772964303375994d1ed601d63124df7ca1e3 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss.dat deleted file mode 100644 index a20b8b5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9fd2da07004827b69d8c9eb71bb43da34d259613c9b64826784a74f2701ae03e -size 978 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss_CM.dat deleted file mode 100644 index 7a2a884..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/bss_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c3ee2c421d111f38b0ec0c99fc158e58a86607f5ccdd1337542c2225ff41a13 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn.dat deleted file mode 100644 index 0ee906c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a93df61388e1e87fea9bb1d84ac01b2a668a96e68bac6357365dc5dc58af9dc1 -size 13403 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn_ER.dat deleted file mode 100644 index a1fe736..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/byn_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a0069912a309b936cc2133be64eea083caa3c113ae9338795608ed2e9eaba83e -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca.dat deleted file mode 100644 index fa9bfb8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0884f4fbb5fbfdef1129646b84b4a61be6810b60f9d7e86f46b4d5fbb8816aff -size 184038 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_AD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_AD.dat deleted file mode 100644 index 1db4bca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_AD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b6c2ee99b85b6de5f0eb6ed62a2fac41d49317036971246f24811872b38ca8e3 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES.dat deleted file mode 100644 index e62685d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4fecefdc57e7089036594413781003295f3682163eafad3093c997b43f706e72 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES_VALENCIA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES_VALENCIA.dat deleted file mode 100644 index b6cbbdb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_ES_VALENCIA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed0e7dfcf5f4556c8bb03902faab1c67e74a27d005cf3ee40b3273e1f4dd0566 -size 2976 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_FR.dat deleted file mode 100644 index 37b168d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4750561497941169433027118b22a5210cee3fc05fdcaebaf7e3ac09984399a -size 672 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_IT.dat deleted file mode 100644 index e47dcd0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ca_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:661dabb4eabc3080c2d824175a7869e473af3df5cdc614469e765588e81cd4c8 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad.dat deleted file mode 100644 index 03e18f9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5f194c9356fd096137c0446185040dd30c56ee2abc32b9e06f4e515de9e66922 -size 2476 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad_US.dat deleted file mode 100644 index a762608..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cad_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:156575b287e0afd9e8e4ff720713432de296a1077cd171181229662f06a69127 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch.dat deleted file mode 100644 index 2b4076e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2784bbde9b13ec2fdc5ecd5534d628c38ee9941a1d4383ca20d0b9f64cef7c0c -size 2430 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch_NG.dat deleted file mode 100644 index c1ca39a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cch_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d1a761c3dc4d325544a8354abc77b81c23ed6e3730e4d4a8e27cbfa4e8e5d3ee -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp.dat deleted file mode 100644 index a71077f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:267fcee4cc0de83306c4dad752976b853ff3e59398877f929b9c8651c57c6c82 -size 207292 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_BD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_BD.dat deleted file mode 100644 index b6b3228..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_BD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f4d3befa7e7238f3807e9b35b4ad8db628d93357ac2d9a4eeec6b48aff1f5b5 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_IN.dat deleted file mode 100644 index e46cb59..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ccp_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8cc2629ab42bc7e6fdea10522e2f2c3b21ed611c0d66bcadfa17b4ae1c04676b -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce.dat deleted file mode 100644 index 93170ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:caea295b9402ab5bbc13546cd2110ebffcb5baf6de9bf3f794afbf02f539ccb1 -size 135403 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce_RU.dat deleted file mode 100644 index c71c227..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ce_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:360366a75b859e6d8c4feb3fcb1fd5f0ab96d5d491ebf48459fe0d72aac02fda -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb.dat deleted file mode 100644 index 495b64f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f08093c057a4dfbf26af6545bef6929e2d469c32e1f4de10a44a41dd2069bc2 -size 100779 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb_PH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb_PH.dat deleted file mode 100644 index 52a69d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ceb_PH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:676cd73f2348dd8bb741c18bea54f59c8b25d38bc30cb16fc9df467ae703b6a0 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg.dat deleted file mode 100644 index 416a3af..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be02f1a787435232b21f2fb7e88bdf68f132e888976c388c29286e10a26e5c75 -size 15621 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg_UG.dat deleted file mode 100644 index 8ebd1d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cgg_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d90666b8305b97d90eec93e48e624e4e5246cc5d65abfed1089cea8f6e8358b -size 640 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho.dat deleted file mode 100644 index 2b60fa3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:85610be57ac85809ea8d849befc88f6a3db1877e0a0dc3d800c738e92ed92ee5 -size 795 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho_US.dat deleted file mode 100644 index a314b9f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cho_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4f709a720904fae28f8b4095edf6dc08b4cd7dd8c4728fc0e74bd8722b971862 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr.dat deleted file mode 100644 index 1043620..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e1ae9e2635f5259fa29c293e27c80726ad50b682b716939784e9503036c78f03 -size 187187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr_US.dat deleted file mode 100644 index ee36a4d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/chr_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1913646b27ee638d441ad5108980bee191776c537b7dd68ac3f942c360c5d23 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic.dat deleted file mode 100644 index 045228b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a0ae6165d5fb9d735b5d47f837f5890647a6dc21e7503059d48e1f37d552213 -size 2732 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic_US.dat deleted file mode 100644 index 87ef73b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cic_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0ef5b55c94b5844a7f5bfe68974a481027946f746a5ecca278a552f09e9c689e -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb.dat deleted file mode 100644 index d98e66e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3ac21d9346369b3e8e06eb844ca100ff27b14aefb441c2c2bc4744c7d71cad2 -size 35553 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IQ.dat deleted file mode 100644 index 5210f5a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ac82ed510147f6c90a59fa734128cc531499c7df622d2e0d24555ce335f99ea -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IR.dat deleted file mode 100644 index ff3d76f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ckb_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eb05b39595a7ee80e618876717b52d09f21c520435cef331b40704c386db33e8 -size 1231 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co.dat deleted file mode 100644 index 6db93f7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35b299f7dc13a46ed8eb82e7cb14d0248a3949841a5003b26dcebc0cde886d46 -size 12637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co_FR.dat deleted file mode 100644 index b256cea..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/co_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c09b05e7e27d66452b13d7bf83714d2f755488fc97d547ca063a78fb8531479 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs.dat deleted file mode 100644 index 9b308b6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3baa786e22ac693c87c3fa8c952ecbe99a1b518883b380906831a66fcaf3cbe -size 247800 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs_CZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs_CZ.dat deleted file mode 100644 index 09b2feb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cs_CZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91e6a2a92b06b41fdac63f05bdd6033820e6960d8f6d0308eaa9d6fb69855136 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw.dat deleted file mode 100644 index 5319698..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b7d7026922471e82f356f7f3bc2df218e3e1cad33a4b9f830150405bf42dcf4 -size 20303 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw_CA.dat deleted file mode 100644 index 87c63d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/csw_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:69671c64718d53b1b82497651919eacaa9b444eb9b5f4af023d4a71ff1210315 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu.dat deleted file mode 100644 index bc52eb5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9a51909226f105cba428f0096b01ebb8132ec36d71d63e3679b4e7adac56e79c -size 16865 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu_RU.dat deleted file mode 100644 index 6e0f5e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cu_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19c6ea804f0c960964e4418649570247e65bf00982a87184f1c6e601449ba5d6 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv.dat deleted file mode 100644 index 128323a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:054a92fb846f02ec9c3a5026fe4df7795f7c542a796c8526ad652a8e19acaa5b -size 198348 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv_RU.dat deleted file mode 100644 index a5a6cc7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cv_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a153d1b5c1f39919a4032dba06fd632e25a69b43f5f2bbaf1e5090e45dc8158e -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy.dat deleted file mode 100644 index 88828a6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f9b374d16a9185d9c22fd55d9c682d52dc1b999ee7dabf7aa1974bbb148ff0a3 -size 276313 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy_GB.dat deleted file mode 100644 index 9df32e2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/cy_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7723d42c8b5e2a4f603fb9464220edb221f9403a8d765c4c74afffd9dabdd1d8 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da.dat deleted file mode 100644 index cd659eb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5545713658e2b9bbe3ddefcf86299e30b05566502dd464f66c07e7c98bbaef51 -size 171756 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_DK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_DK.dat deleted file mode 100644 index 57e9b6f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_DK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a8d4f0d47f165ec57ca86047c6eea7a0250e57705ca11eb7111245f1773ce8bb -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_GL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_GL.dat deleted file mode 100644 index 850b5e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/da_GL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f4135e297d7e538343af7a4153566708601ab1d6198c132cbe9752e6e4dff6ab -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav.dat deleted file mode 100644 index 8d4b1cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c17f5b87fd0efadf6b01561660412add9f92d4da9c88537f3d8782e2adc24ce -size 15690 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav_KE.dat deleted file mode 100644 index 617a749..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dav_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31f1451034fa7e26f96def849b38a2105d0d027115ea55c3eecbd8b4752d9a7d -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de.dat deleted file mode 100644 index a44a3a1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:97a001560db35cf5fd5acf60dbe59ebded394b8ea28b48676ee095892ea6b660 -size 178630 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_AT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_AT.dat deleted file mode 100644 index baee6ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_AT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a1a11be4945732614257a650682b6ac02132918baafcd65c0e6a2c48b9f7dc0 -size 2010 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_BE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_BE.dat deleted file mode 100644 index 024a507..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_BE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c2f756ca4862c7d4a5a1f7239b6b71d9a1213237df98c2ec36b77cef4f4d211d -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_CH.dat deleted file mode 100644 index a707222..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c7dab0f11c0de5a530643cc0b05a36a910326d82b90786adbfa407522928971 -size 4091 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_DE.dat deleted file mode 100644 index 03a807d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:48ce386231a5aa087b6ca957bd476de77b7d867097e68e3aba323822b18fa5e2 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_IT.dat deleted file mode 100644 index fb8e169..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00b3d8d901a547dfa4a61124e0a8201d54b9d5f43010355177b6872c888ff5fc -size 1448 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LI.dat deleted file mode 100644 index 38a1c76..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1671918a2a690d34c5445b3053fe0f6e542bb80b96b8f1296bc7066d73c9a5b1 -size 1413 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LU.dat deleted file mode 100644 index f140502..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/de_LU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40092f2dfc8a99975055f924d816c4d80322b0ad62ef28517ad700a6a9f87710 -size 1067 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje.dat deleted file mode 100644 index 189eeab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8dc508016acf52e649a36d171b72eb8823129a239fcc95f992525b7126eada6 -size 15530 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje_NE.dat deleted file mode 100644 index 6e5f27f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dje_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:954d6f6a0fc72783ab6d83585855ee49db6a2f04a5c016ef0fa4e0fa1977e9ee -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi.dat deleted file mode 100644 index 19e0028..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26b1c38ec5651a7b4b2faa987fd347e7605600609219e19568783fae05221a43 -size 47442 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi_IN.dat deleted file mode 100644 index 0bf3d9a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/doi_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:faafe802abdd4e2cc51b50c1ff5a7cb195728db685150fc514fb4d0b2567f590 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb.dat deleted file mode 100644 index d73fbe1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2af671ca6299e596f143ee204bfbaf9cd92b60c627dc3f812b3d0c1809f9e3cf -size 203926 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb_DE.dat deleted file mode 100644 index 5275ca7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dsb_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6760f38f1ede5ec70404401bfb29af6f518a3f8195342b792f88be0580bfbeb1 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua.dat deleted file mode 100644 index 0ff8141..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9663bcb2c3c5f5b2204d4d9233f4b3ac65a8766b06b266d2e3ce6e64d0dab2ae -size 4827 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua_CM.dat deleted file mode 100644 index af13511..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dua_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:677bc3f1612bd9696aaaddfd6a7bca5d5873e3fc814a6e2de41a00684cfd3e01 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv.dat deleted file mode 100644 index e638af3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb5cc2bf81978911dd5a3424d2a5d634f49fe055f8669f888f68f0833e41b069 -size 2225 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv_MV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv_MV.dat deleted file mode 100644 index 1755ffd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dv_MV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96fb94e608f7bc3ca45367ed535ff82f36bed77d0307afd9c32943add6ff1a56 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo.dat deleted file mode 100644 index f530008..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c3bd470e615f0ae28df675099eeaa91d1f430c098f2e4c08bbd13469b8588d63 -size 9854 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo_SN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo_SN.dat deleted file mode 100644 index 5d24ad9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dyo_SN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67a37e34855c2a4c7ab05526f0b7cdef8bacc997e0788eacc092ff03f5db05c7 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz.dat deleted file mode 100644 index eb4aa17..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:75b3e109c4e9a1087ab336810384cde5e0a2dec6c6d5406f950431b4c1872c45 -size 85026 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz_BT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz_BT.dat deleted file mode 100644 index a2fc84d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/dz_BT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:29677a732a56b1ee177d76d8e019939711a3967464b1835c4188bf8b25e5b8ac -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu.dat deleted file mode 100644 index 1da1d1b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4bc6e081592709b547c39c7d68940607d91404535cc23f4438d1d136d6da5820 -size 15583 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu_KE.dat deleted file mode 100644 index 0b2ceaf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ebu_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:184706a95987d16c203f5042b1df6f9d21b119797c38de143d345bc9e68d0dfc -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee.dat deleted file mode 100644 index d31f28f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c49e6fa4a25ae78eab4ef28a408ef9f87bd89aee958c479d5c43653d27838028 -size 88730 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_GH.dat deleted file mode 100644 index 04262b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a4422f9a566b6a8b74bdf435132d0cd9a941382eb0085aecb6e50b99a9801f2 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_TG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_TG.dat deleted file mode 100644 index 26de01e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ee_TG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ef2f3eac3bda83bfc442d10e6eaddfa4769179d566b844449d0c2392d98bc209 -size 1168 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el.dat deleted file mode 100644 index 0cf2e14..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a4c3e4611bcadf2e0817ddd9fb5dbb645ffefcffd057eff8eb42e06401c2c3da -size 247970 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_CY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_CY.dat deleted file mode 100644 index 6ef8f0e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_CY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ce3e3cd360cb8fec88dfd52f3c700151d207bd21dfec49135e99b29d864d9a1 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_GR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_GR.dat deleted file mode 100644 index dc41099..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_GR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b7d829bed443602cbfe50de7020c8e2a0dfc9ddf0950d496d4c0e9d6d70866f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_POLYTON.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_POLYTON.dat deleted file mode 100644 index fa58a05..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/el_POLYTON.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96472cdae5d6ea6597ced9ac0179daa674ae43a8249ecd56c2c560ae0fb6e14a -size 14964 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en.dat deleted file mode 100644 index 034ae45..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b410cb8298ca9def16da7145240f333ac6fce111659081b774b083ef5f941b0 -size 217633 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_001.dat deleted file mode 100644 index 2781549..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fb3454f2d3c6f903247d23a043cbbf613f7c7f9ead35f16a1098c4b34794b55 -size 31614 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_150.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_150.dat deleted file mode 100644 index 20b7050..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_150.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:72328257564b84d6384efa8917c057bd04758d550116b7632f544a4a705ad2f7 -size 1851 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AE.dat deleted file mode 100644 index d23362a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4f68c11952693d35204c809d6909c05634ac60256440b7e369bc92b5a3e5d825 -size 4164 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AG.dat deleted file mode 100644 index c52fb57..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ce59233df2946af64ee5a82b31afe312f4f03eccba0e554294708f625ed2aae -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AI.dat deleted file mode 100644 index ed1696e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee2c1629fb6a3dd39d589eeff788ecaded9922ad9c0e96d5180b3f49c073b5bb -size 1206 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AS.dat deleted file mode 100644 index 0acc82e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:33e37bbfa06e3f8ef0913166bf96f2d70e36210094892a8a6da5535ed9f017c4 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AT.dat deleted file mode 100644 index 8b73aa8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d39f9b572d5a3055999473010bce80ece572d73961270ee1b23caf20e8f113bd -size 1309 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AU.dat deleted file mode 100644 index 9647753..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_AU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:904856a29908d2f9000a1c6c5269da017e21b60277eadf61895b5a4bab791af9 -size 20023 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BB.dat deleted file mode 100644 index 385565a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27cbe9a4a941a74de326f56e569e99e0631cfcdd01ba4790f1ff2ad78cbc7f05 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BE.dat deleted file mode 100644 index 9773459..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d095c782a50859961ef3c1580bdeeca66d93ab221a34ec03241b772c199417b0 -size 1547 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BI.dat deleted file mode 100644 index 211624f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:01b748e458c4a902ce31b06d0f7c0b5bfec071cb8ec18f4c654169305d6e11ca -size 1189 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BM.dat deleted file mode 100644 index a3592dc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:71913cb317f8e044d8ea70b13a06ef24dd91840059ad168ff128f0b1b49ea6e1 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BS.dat deleted file mode 100644 index 0020f09..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b06be51762cfc06e5e540dc8b87f3ee12e57ec1aef4392dc819f207c0924c307 -size 752 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BW.dat deleted file mode 100644 index d4812b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9396dcf60601765ffc67209e96b952f597a7333b3c71d7e5d8cc5e0a7380afcf -size 2850 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BZ.dat deleted file mode 100644 index 14ae125..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_BZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c9b27d8cd1158c6f10e6191c6cda593666f920a20bb03dfee82c1610c9d5380 -size 2979 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CA.dat deleted file mode 100644 index 400d8e9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cdaee91be4c6a68c2cda4fd724bf1da732d5b35a0e48c28ddf3c321bbf4e02a2 -size 37924 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CC.dat deleted file mode 100644 index 89167ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df86b755be7b853dab791bf09f451dd675e4a18409a0f99aaa1d67e6a7e515d2 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CH.dat deleted file mode 100644 index 8d20dbb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35f9309361cd39c7121fc0a8e525989c57475840c4a4a34f436a3d6baeefb7f9 -size 1866 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CK.dat deleted file mode 100644 index 7dcef18..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82f536d41480ba0a6313b093df19e91cc2faa118073da068abb5b5d586c6fb55 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CM.dat deleted file mode 100644 index 72c2c08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:affed8cdea7a4b464e16f93f4ce466e50862e79ca37a1550028b5a2e79fb8a04 -size 1437 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CX.dat deleted file mode 100644 index d2cf789..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:94a61b2114baafe58c51dd5ec17ed0e13a57d0f05572c60dec2b36eb7ff1a2c3 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CY.dat deleted file mode 100644 index 712529a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_CY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91065f85074f7dd05e78f3a7827fb80a9037649ed387e96667e8ceac17b5d79a -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DE.dat deleted file mode 100644 index 2e67dec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a08dd398c0e8419b0675dbc36f47db6f077f2dd4de15b14f74591986cb76abb6 -size 1027 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DG.dat deleted file mode 100644 index edb3a95..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c6d8e3c64b8507b238a779f47f812fcfadf546d310848ce9a18c14ccecc80aa0 -size 1168 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DK.dat deleted file mode 100644 index 39966d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a44ef1e0c0c9bd91859ea42a5cc0835a8315dcebeedaa1fe40eda860dbe02f86 -size 2425 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DM.dat deleted file mode 100644 index 5a323b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_DM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:81bae25615dc7578b91969a98167460752d4c08db2aaeb8b935921933a68d545 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt.dat deleted file mode 100644 index 5f04a44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ed775dee85d5ca307a4d096687e6aef8249ddfa24d605783052067757c6c519 -size 38656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt_US.dat deleted file mode 100644 index 8d8ae20..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Dsrt_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7c73f2f9b44bf362669ccf4b66ab9f16b1b7e9f70315fcf060cf947fbfb23e9 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ER.dat deleted file mode 100644 index 7556341..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:535bd86905709d581f98ef65dbf1a30670211eb4a16e21d4fc4fa101c943bdc9 -size 887 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FI.dat deleted file mode 100644 index 28f9394..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b880a7658e673d7173be135213e891a6ab626c4511fbd6c29edf252692121af -size 2357 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FJ.dat deleted file mode 100644 index 9b78829..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:93e8577a4a20710cedd34a9775c58e0ec1db83b561f54f15c7ce1b11177c0873 -size 672 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FK.dat deleted file mode 100644 index 3f60557..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:afa38697b997e1ea7969e14c961a20e97afefa40ca1445610dc7a9489058656c -size 1210 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FM.dat deleted file mode 100644 index 76f0def..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_FM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f3c98260ce7f543498a49fe6578012b63883a4a028ff55bb19b98a708f5ffec9 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GB.dat deleted file mode 100644 index 7564028..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:daa7766ca87125e8b022778ac11987f3d5029a761f05da4e16f2f4d9e9fe60a5 -size 3440 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GD.dat deleted file mode 100644 index 875bc28..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7366a9e357b9c7e398e5d118679c03e01c916c4ce5c74f38e51d653c12e726eb -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GG.dat deleted file mode 100644 index 83f063d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa17ef6d1765744038e3aed7d3ff0dd3d1f04f56513c926d6fb12fa6f6db6ab8 -size 1273 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GH.dat deleted file mode 100644 index 7c434b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c1a73b0797d42134043b86b52d29be93c06bd96226d74305dfb895602cc959d -size 889 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GI.dat deleted file mode 100644 index a17d397..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bde48e5436a09e44f0caac4fe2ee663a4446f3f5b8302679a6d301a063a0f521 -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GM.dat deleted file mode 100644 index c949da0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8df1d07a23130cd827229c77599f613a9091fcb5c260b2eb54de1251a92e762f -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GU.dat deleted file mode 100644 index 60f0147..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:58347fbb26c09148a2e911d3db1eb6a7308bbd7e1b32cb626c4ced06f2d2bb12 -size 715 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GY.dat deleted file mode 100644 index b5e583d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_GY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c38956b86126a9b0af6b8d03770139eb8f79b6ebb977e69a912c8eebe5b2c57 -size 694 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_HK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_HK.dat deleted file mode 100644 index 597de33..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_HK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:99e2cf739ff7cda8676bfc7271711fef94eb5b9ff8047baa31070cca8a357984 -size 2315 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ID.dat deleted file mode 100644 index c1d5d72..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fc47ba30755f9f977d16ad4845cfed58187885c1e6a862cfdb045afda46843d -size 3172 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IE.dat deleted file mode 100644 index 3f1e4d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:64d7b95c56dd33852762ee8a68660782042acc85425b05a87f90b992d4ec1e7e -size 2094 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IL.dat deleted file mode 100644 index c822d1c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b8f893d306288b7b317e894483bbbde277ed155a54a213489ef33f6a45ac6af -size 1424 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IM.dat deleted file mode 100644 index 792fce5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bb7257f63aebb16fc6e514171ec4081a5ea291576e7247a575e4bf163286e58d -size 1273 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IN.dat deleted file mode 100644 index 4778bf6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d9de1a588cba43bd84c616479e4bb91ca6ca99249abef07bce47e5aa506c4500 -size 14809 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IO.dat deleted file mode 100644 index 37aaca5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_IO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ce3344f175c59cbb5c32057271b2b13eb82219b1b6130a65244dd7c268e3be1 -size 1168 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JE.dat deleted file mode 100644 index ef7030a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2312f7472ef4a4c3970db0b053a2d99651d766683c5c76e3a1c6af116bdbf636 -size 1273 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JM.dat deleted file mode 100644 index a74c8dc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_JM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67d18567a685184bc813395b3a50396c106fc607315f1eacffb0313cca76620e -size 1666 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KE.dat deleted file mode 100644 index a79cf27..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a096b79547636af91d86430afdb727274f3068af657c846cf261641b42587fee -size 1458 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KI.dat deleted file mode 100644 index 7081028..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df27e4af0bfb61df72c433675f3f52bfc8216c3bea7336530042ebdee18d627d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KN.dat deleted file mode 100644 index b896478..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:70579b71c5cead0a365f5ce61e81d8076bf35f29e8ae86089894cc9caf63de1d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KY.dat deleted file mode 100644 index 9048a44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_KY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b259925a4d08133fd42bb3df1d7e0ac8795ffe20517eea0e595b8407468a6982 -size 733 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LC.dat deleted file mode 100644 index 83f90c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d461d29ddb8f09923e575715d76ef5e77f1bb8047ff7b382ddf8eebba9b3e41 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LR.dat deleted file mode 100644 index 60dd23f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae26d3f3f6b31630c2f2ecc8b0ec241938df8048859521bfc006ffc06d459a7c -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LS.dat deleted file mode 100644 index b033537..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_LS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d87b55de052bca70e5da656fab2c0c7df7fc567563cf6af2a0d4bb0f69f94fd7 -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MG.dat deleted file mode 100644 index e047ee7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76d32bb01a8ea70404c6cedd56e91b5335a88f3ffab30c79360e8e5dd2b1b12b -size 1438 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MH.dat deleted file mode 100644 index 95af27b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3598d09272f2a242e025134f89c019e79fd5a110804f3fd6bc0c4ca3f23e1ce8 -size 1368 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MO.dat deleted file mode 100644 index a441c12..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:509551eed77ebe5458fdadfa6566f1aff3dc2ba7a02144122a8932dc37809840 -size 830 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MP.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MP.dat deleted file mode 100644 index a793006..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MP.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:49ddaf03709d47f181c35bd041005f2886346ac246b1553067a803fa1eceafca -size 1349 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MS.dat deleted file mode 100644 index 803f6bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:057ac0de87469d649e47ae34e0bf3912ba8c2b14e7442675e9458bd91a43ed36 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MT.dat deleted file mode 100644 index 0c34973..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0e0c96844879ddc5d4fd49865c9c448303a1baa259fa9fd342a2378784abc98 -size 1990 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MU.dat deleted file mode 100644 index d29d325..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:49e7e8661a345f34b3cd4fd8ffeb9d58f0ae460cfcba37545642fb861cd93bc4 -size 1438 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MV.dat deleted file mode 100644 index 81f8789..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a9a79cec3821f309e64ec94758a97a2a992a08274a71451ddbde7236ee3bd3b -size 2034 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MW.dat deleted file mode 100644 index b32a41f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5ddb4221f23ea2c01639e392389ce6c159dbfd14bdfb9c4fa081fa46797495b -size 886 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MY.dat deleted file mode 100644 index 034bd66..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d4c30335ed6f56efc9e76d71a6af1db30a899943d160fe9bb7bdaf703d9cef6 -size 716 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NA.dat deleted file mode 100644 index de7ee70..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb2340026c77f11a1526ddd8447ed3a75c4ef68dc6b1254353ab85fc62a119bd -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NF.dat deleted file mode 100644 index 3eb3cf0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8baa1c07c8e9e4400e1336fb1eba21356b93afec3577cb8e8267410d7226d71 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NG.dat deleted file mode 100644 index 3e46ba6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76f6c3658765926845f8853c33ab36a7f907b30cbc1e17664772cb73812178f2 -size 1439 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NL.dat deleted file mode 100644 index 74c1366..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7430ad5d17a1f6e31f50e56a1966968df575f9d2dee7fca3fa8fc7aca64631e3 -size 1192 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NR.dat deleted file mode 100644 index c887bdf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:66250d058d1cd53dcb40ffaa1a6b6ec4b5b625f73e95c553b96a41da3c5f0062 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NU.dat deleted file mode 100644 index 30fb51e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d4e075f3ff797993e96e3cfb23666641b1d39507965f90dd57ba4e62da976e7 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NZ.dat deleted file mode 100644 index d6afd80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_NZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cffaae97e1f7cd09f443f96bac771ec928f59b64d069a25977740c5c4df509c0 -size 2340 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PG.dat deleted file mode 100644 index 4f6b607..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:595e83db24fee065fa7ed6e75242be8a17cd83c63e2265f501fe7aa24c7c2d30 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PH.dat deleted file mode 100644 index ddbeda2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a0fcffc03bf17c21c1a64054699d118b0b4facbb71fbd222811d1320ad5bf883 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PK.dat deleted file mode 100644 index 505492d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:292fca5c8b648645142db29df661dd583f689385a365b5525e153c7b9bbc6e5a -size 2074 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PN.dat deleted file mode 100644 index 74aabbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa9116597d1fbe1cd5ea0717fd21cd6c95bb13ee458a42b05eb4003fd0569977 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PR.dat deleted file mode 100644 index 39b582f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6e902ef72a1e2b1cd04c5e417bb01f5edc84df06b1d1e3f49be12ef82af48ca1 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PW.dat deleted file mode 100644 index 3d62f2c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_PW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fbedff8a236aba947d47771cab97e88fd1f39000c113005874a13f0312d90f7c -size 714 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_RW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_RW.dat deleted file mode 100644 index 3356b04..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_RW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12dde1399c1a483102ac2cf2a6062ad50c4ac719c1dd76338887847bf5a263b7 -size 1438 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SB.dat deleted file mode 100644 index 22bd06b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:87d4c9ebd613873ccb193878f410449910714a266166942b54989fd108252d5b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SC.dat deleted file mode 100644 index b7c212c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2662d09906b2e5f1f1ee4fa5c89decdd7ad57b5aa599558ae22519e558a6d38 -size 1188 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SD.dat deleted file mode 100644 index 7904bf9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a33777ad5fe272bf29d87f55e92b4e48c9281c13cd06c5ec6b2d46311599d73b -size 928 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SE.dat deleted file mode 100644 index be70af8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7a82e8443b31abd8b71b777c59e23ec74e3fb41f4a1a18c4086c8f5aff9838f -size 1502 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SG.dat deleted file mode 100644 index ae45f8b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bbd53908b9eab348899929ccb0f04717bd4740ba45337b22003cd9782ee2689d -size 2096 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SH.dat deleted file mode 100644 index 32734fb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac19bfd33c631e7115cecfc23c2caecf92e923d8ac0364ba728a54b8d6f109c3 -size 1210 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SI.dat deleted file mode 100644 index ad0c03e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:92478490f9d6e3c88da22c0d65bd0a576f433d4d2854db843538bf5a6a7600b7 -size 1046 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SL.dat deleted file mode 100644 index 9db2f57..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e2124b0009f2b84555419d77342ef0674258250debbd7d12b0e029d0ea16eff5 -size 886 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SS.dat deleted file mode 100644 index 8f057b7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b8929c84163c8a4fdfbac2dda91a5e35db968dd01a74c2971806bafada73ce7 -size 908 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SX.dat deleted file mode 100644 index d266426..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eef112aee44889a06a5b1b92469204d94e8f816c09f66c606e38c7fd702b69ad -size 1190 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SZ.dat deleted file mode 100644 index 0880f63..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_SZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:03dc24cd9e5c15f7dc11fd45a1b6113f1475100170a90bea10bb2a46936578e8 -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw.dat deleted file mode 100644 index ac5056e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4db244df62c18767adf0dacdde62bceba203e95597aa637c1deb485589821ba -size 4774 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw_GB.dat deleted file mode 100644 index f073a5d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_Shaw_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b80216949e60aff351ea59dc98c681ae35d43e1677deb1ac5e81f3f21addfc4d -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TC.dat deleted file mode 100644 index da8abcb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:516a8473dce937735d4b577299b52fda218a84b907eb92a4f6e345c5d5c69cec -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TK.dat deleted file mode 100644 index 56a5fe1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ab3e111ed1d0e9c36307cc56f3f0481ddcd6d5c11c42ec897dda852326d702cd -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TO.dat deleted file mode 100644 index 16c4529..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39e84941ff24bd68bb03e470a3684f8ecd59f694dd83bfc7cb1fdec16c5b2d0f -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TT.dat deleted file mode 100644 index a108884..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f6de20e7ff3be1d7a88f139b8194b091bc4092a33ab2cd4f56d8e7128d8a201 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TV.dat deleted file mode 100644 index cdd7875..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dec8f73428d083ef5439d4f3ef00c94698f1e7b6c8d1b9eda66c744f9d0e2bd1 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TZ.dat deleted file mode 100644 index c02d658..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e50f3b9a348468232659e5b0b5eb1bf65270dad2163acbf249c1b50aa4a95afb -size 1439 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UG.dat deleted file mode 100644 index f0649ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6902df75b7e8cec6212b7106f495d5c6c993e01ed4bdf4b3341a3b90ed964ac7 -size 1462 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UM.dat deleted file mode 100644 index 73b0d46..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_UM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a9ddba4a5e5b2531201d4db986fb24a782ccc6f4490722ce4af52292acf42782 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US.dat deleted file mode 100644 index 8d8ae20..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7c73f2f9b44bf362669ccf4b66ab9f16b1b7e9f70315fcf060cf947fbfb23e9 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US_POSIX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US_POSIX.dat deleted file mode 100644 index 7d16137..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_US_POSIX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:53cafbee8eaa4080f749de45899aae912a509eae0b575043c0751eb8d6635b5d -size 1321 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VC.dat deleted file mode 100644 index 7de3225..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:112e1ce17b7a3af243871a00669591d8715bb7210d3a5f42ad5ed714206cf8c6 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VG.dat deleted file mode 100644 index 2c770c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b2a89550e12d0d5da901ce43cc697beaa57598be4af945a1311cc6f857faaf7d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VI.dat deleted file mode 100644 index 5fdd8e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0067dfca07c101a7d0331280028c6dea4c266c44b847fc9b6d7455dad1e9cb4e -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VU.dat deleted file mode 100644 index acfd28d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_VU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e2d9c441f01f9cf2e251ecbe7a1f36e489347c7896738954cc704cee88ada0d -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_WS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_WS.dat deleted file mode 100644 index 82d0005..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_WS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:828c0ab2f7840f75085b22e09d25b1c84eaaabcee51f674c80e54b0c60847019 -size 656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZA.dat deleted file mode 100644 index 0f550da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba848bb155a232eeb1f836302121a1130bde834915b03c209c886ad899f4857a -size 3411 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZM.dat deleted file mode 100644 index 040f5cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f32f35e1ae46b58702e60be1dd80657187f9226af4c8d10857fbfc8c7dd25ea9 -size 885 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZW.dat deleted file mode 100644 index ca420f6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/en_ZW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1940c311eb1046452e2f2c83967277306946cc6fa40cfc6df0e4c8a9544a0f2c -size 3320 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo.dat deleted file mode 100644 index d9971b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91221bb82ad3245d19b8d57c17387285e253df788ac2d7881cb69881d7cf3b82 -size 101326 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo_001.dat deleted file mode 100644 index afdf1b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eo_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dfeb4ff736930df6c1063a5ddaa2952214bb5966e6b55286196fc1986221ac74 -size 850 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es.dat deleted file mode 100644 index f849bc3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73adab316deb1d3eed68549328fb7c8dee748ed15ec78b0bf27bee55ecbddb6e -size 191377 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_419.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_419.dat deleted file mode 100644 index 228be42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_419.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3e24b9898462a821b9ec8d99bee945e70ec02c8058482a4f4e264ed23d1fe82 -size 27973 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_AR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_AR.dat deleted file mode 100644 index ff182ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_AR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac57b2a9c5032dbdf261858cb823fc4783b59f8ad3d5709e6b26886a83da38f6 -size 7087 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BO.dat deleted file mode 100644 index ab762ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7380452c84c6faf4cdcb652ff74ce9389063adef77e7076516591ec73c50209 -size 1477 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BR.dat deleted file mode 100644 index d44450b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a020ffec8a10e70f82f985e943fc01712d30524718dbaf100dc839cbb568eca5 -size 1207 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BZ.dat deleted file mode 100644 index c3f329e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_BZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67766c900e3650172938f0c8eba17a6014efcedfa0eb53e6c61884a5d197a700 -size 1206 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CL.dat deleted file mode 100644 index 0c9fa48..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b698a208c73af006f76180ea8bfce1d1dc3f21fb1998b722ca5ba36dfef65ea4 -size 4848 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CO.dat deleted file mode 100644 index bd23877..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd9366a909c48fc12836c7b8949b8ad10ae0d599cf4a051508f08da3b2ba144e -size 7436 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CR.dat deleted file mode 100644 index 03af768..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a49ec4763b72db1611da806bd4be03600550956d767193ecb38af4cf47e43fd -size 1308 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CU.dat deleted file mode 100644 index 2a6b0fc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_CU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:37e4eaa42b37e2c8e510c78982fadf392a669e7946c6eb86b520526942836ef8 -size 656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_DO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_DO.dat deleted file mode 100644 index facea22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_DO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1cc63553d462ca206540a73f91411143e187a960a08daaab058d2629413d1a9e -size 2700 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EA.dat deleted file mode 100644 index d7118c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:578514e81337a636ee12578b03f31a26d5a5f087a335c1f350cebad297ca6bcd -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EC.dat deleted file mode 100644 index 134e86e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_EC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8baa147bfe462fa6fc6676e73915b572c6ead7eaa0a3a54dd19eb1f46db12169 -size 2941 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_ES.dat deleted file mode 100644 index ddf67a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ddd534a37657f6952331c22d0d858191d9eca200105a489be12e5c0b3b8ea3d -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GQ.dat deleted file mode 100644 index 062d13d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6bb03e86a33dc0db79d7f09da63cd4f1a4fd28478ccf5eb9f8cca1916caa24e3 -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GT.dat deleted file mode 100644 index 372b13b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_GT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce4fd6a879b362ca0802212b4980bd1bad8c95b800bb24924c03d92ed397fff7 -size 4132 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_HN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_HN.dat deleted file mode 100644 index 3702500..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_HN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ef514b6837d55b9a6096563e0684283da0e327896f86cfc58bd101989423663d -size 3051 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_IC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_IC.dat deleted file mode 100644 index 91f5604..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_IC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8707b2f21e0633c8b6e62f98651fcafa3bc28a3f79c19aabd3375320a6ae3f9f -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_MX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_MX.dat deleted file mode 100644 index c11d07b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_MX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ea3c6175695eb90c08fced4564e9762390c4c14b37a178c08498720660423063 -size 25204 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_NI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_NI.dat deleted file mode 100644 index 5c565b6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_NI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:705eb6039d86b900fe414f7e8c198affc009e696755bf9c9ecdc2b69202132f0 -size 1227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PA.dat deleted file mode 100644 index be96baf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7c134d406bfddfb22ee0e3c7c52b98b4fbbc33ebbac615261b42ed31bc430b41 -size 2775 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PE.dat deleted file mode 100644 index afd628b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1ba65c7ab094be54864267b2b0536d30d2446703c07ab56ac0e1b684752967f5 -size 7244 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PH.dat deleted file mode 100644 index 41b9747..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7c43199953d06fdedb06312d09530b9fd254b68b1378f991b90aa1a5f3589194 -size 1248 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PR.dat deleted file mode 100644 index 00488cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c0f38f795f8ef6b9cbccd1ce6eab3d244528da8bb2aa66a25eab6cc47b4aa563 -size 3307 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PY.dat deleted file mode 100644 index 10e311a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_PY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2978b0fab91009d728793bf4b744a703c8a866b1d061f3f17a7f38f75692abcd -size 4442 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_SV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_SV.dat deleted file mode 100644 index 3d79833..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_SV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:24cf6ec3f115b41e89f1b1ff373d062ffcabe9e85acb8b803e6e0e24889499fc -size 1260 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_US.dat deleted file mode 100644 index 078fffd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:89f6793cbf666619eabf713ab91a114b64aa964832cf9de6d9126cf700dca4c6 -size 22533 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_UY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_UY.dat deleted file mode 100644 index d6094e9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_UY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df529d1d51169c4e9f5ae1daeca39d4cb7269565e7f0ce6589964c0d695a56b9 -size 2703 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_VE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_VE.dat deleted file mode 100644 index 1213a7d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/es_VE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:932c5d439d4384b35fe9d41ab803f0e2f3a5a637edc3d09081cdf21ffb80a0a7 -size 2509 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et.dat deleted file mode 100644 index 7441f7d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:793aba9c6d37f70296f35be716dc7eab3696568d308947b2d98d995102e5e3d9 -size 175652 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et_EE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et_EE.dat deleted file mode 100644 index 6f39356..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/et_EE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:269732cc80e91b01e52d28889ee60edc77f190c105b033c178c73e07c463dcc3 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu.dat deleted file mode 100644 index e9d70a6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:944403e27ce783afc59aef3342d92bbe815657902f51a0a939a025bfbbe49ede -size 178023 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu_ES.dat deleted file mode 100644 index 5a7987c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/eu_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0014bd96bc2346459e9d50787cdaf02a9af498eb8c17f78e94ead2ae86dc0e5e -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo.dat deleted file mode 100644 index 376f642..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b47c82f548f91a4cff9c61224c21635e7def79e8f9cf519486bfa3f83976be01 -size 16881 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo_CM.dat deleted file mode 100644 index 53309b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ewo_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96293195926acd8395c5c1b8a125102d3887e438c68dd005b093c88e79e3d88c -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa.dat deleted file mode 100644 index 427d10f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:722fc5f797648b7c135e1975d32a993fb22898383514720e02bc6a4c43141329 -size 192269 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_AF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_AF.dat deleted file mode 100644 index b49dd4b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_AF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:de55cdab3d2bedf8d7498cea6412860f982d4b470fb3e971d44c58fecd6e71f9 -size 8639 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_IR.dat deleted file mode 100644 index 2ad64a7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fa_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9cfb9ec70cd11c36fd4c532320b2bf578dec548cdb727fdf829d26b18dde150f -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff.dat deleted file mode 100644 index e663255..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:813f0ca0760525c183a158c10983f3b2b90c4caca53a35e413ae127342feaef3 -size 15911 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm.dat deleted file mode 100644 index 0dd0f6e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19bc18c9505b03c48024ffb5058316e1bdc75e2be08bc1ef443cc868ab89b6f8 -size 326252 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_BF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_BF.dat deleted file mode 100644 index 92ef401..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_BF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:79840b6c7bf1b44a9c24231b5d292a3767514ae60755ce9383d90e50a6b2250b -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_CM.dat deleted file mode 100644 index a012f51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f756a91c5aa5dceecd610b137ad1d77ec8145791c5df30c434b8024a992b20f -size 656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GH.dat deleted file mode 100644 index 80d0480..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af50917bd67c919dc1dcf0f199941bbe0a6c11c6373a325e93d67f4bc1416f96 -size 1236 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GM.dat deleted file mode 100644 index 4b55c5f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:64cd7b68173cc739c48e83f87fb1d108768a9fe0c8c424831a42fa1af0d8bc3c -size 1232 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GN.dat deleted file mode 100644 index 7e9b036..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d690bb138fc49dd1f598b98cac1e14a1974f21834880bd25e13e3cbead48c1d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GW.dat deleted file mode 100644 index 14f63bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_GW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bc8525fc2e0f6525a6ca97849a7b0051b18dd9d4aab8cde710e741b36dbfa8d1 -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_LR.dat deleted file mode 100644 index 7cafe87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dbbeeb63acc05a5c5eb457b40f426954463d30d71088953d92dd6346889713b8 -size 1232 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_MR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_MR.dat deleted file mode 100644 index a12ed78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_MR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ab3eb5f30d5763fcf0676ee707a2c181bcec8ec8785229df9ee395c766ea2e09 -size 1233 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NE.dat deleted file mode 100644 index ec815fe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1a63510840ab8e915cebb49fadfb9558edc2b6b8a2f448804ed0f41bc78c7d6 -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NG.dat deleted file mode 100644 index e861410..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5474710b8f91bdd18a2904a92dc43c96550c8bc65e5fecfdd3a01125c25bc2a -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SL.dat deleted file mode 100644 index 700108d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee32caa1fc100518203fad647a9aeb6df1465efadc24f20ebf01159943637132 -size 1233 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SN.dat deleted file mode 100644 index 5d013a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Adlm_SN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9c66b3cfa4ee9f70fe5ec3ba4a58f141e781bb3bc06f5b01430db521b90340aa -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn.dat deleted file mode 100644 index a4c6620..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00fc8d9a51584700903a56e8639f2ab2a885e7baeb2371787c7bbeb904ddb788 -size 866 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_BF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_BF.dat deleted file mode 100644 index fcc4ec9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_BF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3729b991e4777433cc24116bed9c96d9cbae63ea93324747cd79c81d299f0f86 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_CM.dat deleted file mode 100644 index 1f9899f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad6695005e83e60bff84384d99219b7161a93d5ed7e20a79dc504c5f23234fef -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GH.dat deleted file mode 100644 index 986bbdd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fa432f14d210ca29130f67456a457cd608524761f9f3802280b82d9abce584df -size 1231 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GM.dat deleted file mode 100644 index eb7c96b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d408abf2c934c1bd0c72a2d95c35886107a22a03eeb016958ebe33939e086a85 -size 1227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GN.dat deleted file mode 100644 index f9f2f0d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed1fba75760c05dbdea36fbd55cec28c80361facbf8462556df54621a25481b2 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GW.dat deleted file mode 100644 index d7b018f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_GW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:da46ea8737037923d0c5e7c7c729e6aefdad98556759d44d8ceec8dc067a9719 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_LR.dat deleted file mode 100644 index 04c90dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:310c5c0d09cc642e61379d9a6f3a828d520bf59e6603dc0ec93a863cfe0e8f48 -size 1227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_MR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_MR.dat deleted file mode 100644 index e45f704..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_MR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08351be68c2ad0db6c7769486497a3bd8c4e8e5f8d3943cffafded8158f5fea5 -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NE.dat deleted file mode 100644 index 10f828c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:47c0b47c8f2a9795e99d3dbd0abc011bcae074707500048305276fa88a88435a -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NG.dat deleted file mode 100644 index 558dc1c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d34aed8986c90ff722f3ed0ce327bde6bcc6a5bc97f2a43e76614521a8c0b514 -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SL.dat deleted file mode 100644 index 74bbe9c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51a58e7a891d6d2a311b4254cb2196903cb3ef4b17cbe7196dcde55d9c6640ad -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SN.dat deleted file mode 100644 index 16aa069..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ff_Latn_SN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98f55a73d8829f035acbc73b2a8dee52f838f257f27c466bbe1a721051469859 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi.dat deleted file mode 100644 index 68c8801..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:55dfb3e911f5d7670fd24e4018e940a185355347f99a94109221f2a41f38e09c -size 204853 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi_FI.dat deleted file mode 100644 index 419ca98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fi_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7296c953828a1bc3966e62e773d4ca4ddce6a688b600987f3eed5c1e10f05523 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil.dat deleted file mode 100644 index b7cb20f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:83420d4c25e9a438234c68011f2f61a90f0c730ec6f4add72d32f256c856bae0 -size 144724 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil_PH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil_PH.dat deleted file mode 100644 index 1700c98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fil_PH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:263a19b77ccdc72d57e919c7a3150a38ccd3fb1321ded199051abc72fac1c2a0 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo.dat deleted file mode 100644 index 8e5d5d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0fec74316c1eee85853202dd6b1480f59875d47bdce5401bd60adf0b0d184d3 -size 148411 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_DK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_DK.dat deleted file mode 100644 index 7bbd402..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_DK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d4b9aacb3454ac57f80dd9f83e3aaacfafee91cba285822b42a75ef78f100e3 -size 674 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_FO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_FO.dat deleted file mode 100644 index 07bc652..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fo_FO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:48b78d437dd04d9f769170b341c15fa3e3a0c195453c92887918afbafcf4ce8f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr.dat deleted file mode 100644 index ead1259..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1ef3c24777edfbf57152926c569d70294f1a889ede08a644cfd5d95653398de9 -size 213357 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BE.dat deleted file mode 100644 index 5e97590..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3837e4242e64596104923af5515f0068bb4a29ce2c3c25319481a4103913afab -size 1085 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BF.dat deleted file mode 100644 index e2ae1e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee989655e30cad9f986cef4c36a240bbb65e21db9e567860d3b79e330247cbde -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BI.dat deleted file mode 100644 index 2f68336..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:47891a5353ad31c3487226e4c3c38518fe85698331b76b8a311ca276412a6e20 -size 637 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BJ.dat deleted file mode 100644 index 068c68d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b1e9777ddc1e818e56e0d460df6b7832e5e8aa91aa4c018efdf7c217634f8201 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BL.dat deleted file mode 100644 index 3ced0e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_BL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9fe31166378736444cc02b4680f66ae762e3d228e7b41b317ec902df6e22da4e -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CA.dat deleted file mode 100644 index 1af1825..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36eeb441d63225a8909f3d446c12d25883bce917f9eeadc55a853bcb064c290e -size 72420 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CD.dat deleted file mode 100644 index 8962795..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d6698fb0acbb1e1dc7f47c69519005add75f224234596931a5aacec6db766b5 -size 1138 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CF.dat deleted file mode 100644 index dc7d2b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c31ce4d0d7fafe928ed950e2bd0a6b518f56bdac514a4adf401a14135515ac00 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CG.dat deleted file mode 100644 index 909ee62..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccfdc74cffa7a998c6f8e0ff0cbac310f3db077b7d8384f690757323e1f185a5 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CH.dat deleted file mode 100644 index ab2b469..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e23b98dccd4c82c135a9592a3154713a90b31740faeef97a2d2502c32278cac -size 2876 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CI.dat deleted file mode 100644 index 49fafbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4eb1cbf21411b8923702ec5edda4c761afeb963c94bd3fecd2afa375225f9493 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CM.dat deleted file mode 100644 index 229f0df..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df5a030267916f717c6b87ef567d5027221bae56b4e30f247c2e2840ed2fc249 -size 1970 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DJ.dat deleted file mode 100644 index 6815a71..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26abb614e2500f8d41e9f2d204473f59ff9d210f81e8c5a54f49b56ee4279b1a -size 1248 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DZ.dat deleted file mode 100644 index 1126d4d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_DZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b8e7bd95b8cee75ab7d06d1432ce672ab30bb5ae42b4b5b6160e1dbec7d15f73 -size 1290 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_FR.dat deleted file mode 100644 index 546fa9f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f0b63b6fd0d1be9719573bb7c977aafefa5dfc58a6909aa9669fb3e95c9749b -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GA.dat deleted file mode 100644 index 67a6454..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:accc12fa6b178cc3b94f993504fd81d92f41fdd62f0c794ff07312f8babc5d4d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GF.dat deleted file mode 100644 index f8ab2e2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c7defe1fb1f4878fcc513a6331dae4601efdd2f06f3ca2b19a7513bbe14ec0b8 -size 719 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GN.dat deleted file mode 100644 index bc8d1dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8a565056ac5efa661832620e3b1754dc47cfdf6c4e488b6a49ccf8666ebdcf9 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GP.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GP.dat deleted file mode 100644 index 5479cf9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GP.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5bdf711e3a8f423fcd2755f7e22b268fc038c5e65c1eefefcaa1fcb48c1781e2 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GQ.dat deleted file mode 100644 index 0110400..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_GQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a07f9348e3332f6d544e7886fc17a87537124d28ea98e1f294e86d923c95c39 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_HT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_HT.dat deleted file mode 100644 index b889388..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_HT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b656fb766fd5aee1d6394ec77dc71140c7f44b7165c219ffd77924901586ca4 -size 1836 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_KM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_KM.dat deleted file mode 100644 index 9ed2369..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_KM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0a12e9cc2cae971620f109a6e472bc6242b6d3719149410134f4a5f306abee50 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_LU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_LU.dat deleted file mode 100644 index 08ee440..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_LU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d2c601867f3ef65bdf3ab53e64421b9cee6fd37a90390ab8c1708aa7bd1bdacc -size 729 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MA.dat deleted file mode 100644 index 2fe9b13..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:526edd2bb32f1e43c1fe1febd29938eeb3050a78352d616021e912edc0d7f591 -size 1098 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MC.dat deleted file mode 100644 index 017e6b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21f4c267cf6ba87cd4c5d2b2233f3a66cfd5507db3739240be7b5d8722ac351d -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MF.dat deleted file mode 100644 index c360332..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c54d20acd24a5a0a5f02bc292edeefb8ea524d29323f1de8ea01649992c2c5de -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MG.dat deleted file mode 100644 index 5b0c9be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:03dcd805b13a8085ae1833f1bfdd91788711e3d82d20461a1240a3f5938d1c72 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_ML.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_ML.dat deleted file mode 100644 index db54594..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_ML.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8fa16b0706d9da662b083aa672684166c28a115dbd91db110c7ba0d869dfec9 -size 1153 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MQ.dat deleted file mode 100644 index c144c5f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e39a9601ebf8a7665a155932d5096bc39abdd3b3c37db449abdab650009a866f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MR.dat deleted file mode 100644 index 845800b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:99548e001cf77116b5f8711e50a5b5dec2f0d5947a3e607d87f0cf7d9b0ae147 -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MU.dat deleted file mode 100644 index 0649279..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_MU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:738111b92d4623c87bc1ac5c5ba051b65a16ec14e12e582a7584dfdf522887f5 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NC.dat deleted file mode 100644 index 1af83f5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4aed8368664f9cb09a38d9a0a2c31891ef641fa74ff3127cc0917a3f9c6b26ae -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NE.dat deleted file mode 100644 index 1ef7d22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0fa8216067435e585a550e6002bf30587c441d847b981b3441a88d2f99dfc563 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PF.dat deleted file mode 100644 index 88fd8a5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a0f376101a358692e39690d83c1e75a84031ff81cd3161b9f8187d24de8a6a5d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PM.dat deleted file mode 100644 index 446631e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_PM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8043fa032eebfa9eee2233865cff1e09aeb6cae8e54c19ed10d75e35df4a29eb -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RE.dat deleted file mode 100644 index 5b781a6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7135a2e2f8151b7b713e5dfe595cfa1ebadf4d753d03f4e184826a1259912bd -size 1055 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RW.dat deleted file mode 100644 index 39ec41f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_RW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:80ff26a4cee0c7f5fff4d2839bc07d3ee4e0f378f04f9367dcd38a3e95618b7c -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SC.dat deleted file mode 100644 index 9ebc1ea..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aafcf4374f0b282b0f08f0d92b536602187399ab33050f264a50db02c1300282 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SN.dat deleted file mode 100644 index fde1595..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9fa8a3066325fb3b6e08b49e3c8f90df22328737a39fb2af470e59aa30e85ec0 -size 1018 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SY.dat deleted file mode 100644 index c3da27d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_SY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b690e8be067768aeceba64706e7b474e49d5fad44bfc78dc3cad5a408342fb1f -size 1290 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TD.dat deleted file mode 100644 index 09b59d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d47e3bbde58a463fe257d0b11cccfbc7bb5facbf0861d41a456853578e7979fc -size 1208 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TG.dat deleted file mode 100644 index 6689227..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aff1395678f429be421b5e80a47165b3852b78378eefea37bb3a507498e96d13 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TN.dat deleted file mode 100644 index ecf546b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_TN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:85c191276523b8510526a6f50438251ac5d8f2308421d33cfbe3ab5373aa4617 -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_VU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_VU.dat deleted file mode 100644 index db4dc99..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_VU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:15862c89aa0cf1065e0a53274332e22d93575bd8542f3fab0a0453616beb22fb -size 1228 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_WF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_WF.dat deleted file mode 100644 index 8ad2a3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_WF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e7e95151c3faa9245c693be23a0bd9e1cffc1167c715d9bd97441812ce2ef5d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_YT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_YT.dat deleted file mode 100644 index 4f5d8cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fr_YT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c745a94022e8aab2d8dff9c217b26572e7a492852d7291389650bc91199e4666 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr.dat deleted file mode 100644 index 72f5352..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:22d99df770cec0030671391613cdc15834b5a171157245f4104ea64a238aca80 -size 102994 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr_DE.dat deleted file mode 100644 index 4e3631e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/frr_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:da8867a1dcc409b24151312d6b7e93b386a664a976fcb0e1b83d3e1eee49068d -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur.dat deleted file mode 100644 index 557127d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a6f838e963b6bb06e0dbb95e5b25985e4a2a60589a135bbd4f1b1dfe2649782f -size 32441 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur_IT.dat deleted file mode 100644 index f26d972..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fur_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3e90c7d68a540e39dd3adbe93da7623ad2131b21b1299634ce21216fee0729b1 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy.dat deleted file mode 100644 index 4c7af8a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc971ef7a39a0a81bea0a7e14058acca381510ade9355b45f514fe7fd87bcb58 -size 108200 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy_NL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy_NL.dat deleted file mode 100644 index 03ca24b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/fy_NL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23f33684554201a5402fdd3254c9685b67989b33b90b7359ced7c40c07acdff2 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga.dat deleted file mode 100644 index 2059c48..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af1e4c2e0b4d522b01f55ee0bb47b674dc825c5d87f4a84b5542ee62f2cd521d -size 261523 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_GB.dat deleted file mode 100644 index 0fc8985..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:34aa615498661fc7a081ad5d81f3be8524551616f19acd89bc6314df26e08ff4 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_IE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_IE.dat deleted file mode 100644 index a12ea41..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ga_IE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3fde3c4f54e5e01ee42f54febb18a2dbbab82163b7c904397a64cbbfb887bd6f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa.dat deleted file mode 100644 index a9e7d31..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5bdb542a68e0967494c559698860347252a66a08e6ce01751708ff50f9a0f089 -size 33806 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa_GH.dat deleted file mode 100644 index 94d74a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gaa_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:145eefa36e2fcc0dabbb7b7ca72db8eae6a7c8eab2a129290fae45eca1535e50 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd.dat deleted file mode 100644 index 4afb551..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:02d4af47dec7d392ef14d2c7a4bb1beed3a029868e8d8bd614e2da0c31fac4c9 -size 280763 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd_GB.dat deleted file mode 100644 index 982addc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gd_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1e691ba5db5762619a2a2e4ed25da701cbc183d5b1f7d1c40ee801de8e294f3 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez.dat deleted file mode 100644 index df9c24d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ea0207037045737f80ebe74eab4a5ce9ba8fd9e8fa9261bd5efc1ad04121a0ca -size 12743 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ER.dat deleted file mode 100644 index b8f8839..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30aa525bb5299297b8d90da66c94ad6e3b67ad6e8aca8f13834cd70319c75aa3 -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ET.dat deleted file mode 100644 index 99548cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gez_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7741348c8a1a5c7c5c9186db45a6580072c021ceb3e395baf3e472387de4527 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl.dat deleted file mode 100644 index f12978b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:376cef4b5820f1fde5e9238ba8822228206c6f101c02b15c94849e984c86c7b6 -size 153642 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl_ES.dat deleted file mode 100644 index 4263f4f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gl_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bacf315914273533bf282e36f85394d9c9cb08d97deb9f75aa7c59e1ec6ae457 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn.dat deleted file mode 100644 index 9002b45..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d826c1833777907966f2e229295577caeae611707fc8d51f33634a4c557de5d5 -size 2477 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn_PY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn_PY.dat deleted file mode 100644 index fdcac6c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gn_PY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b40ae00a8f394ff0543663dce2c5d5473f17e70707266052e973f4afc74f800d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw.dat deleted file mode 100644 index 2b95f5c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c61d2dfca4a6ae35631d145b02c8227ff69d7b68bb75e23300e7a8314c304ce -size 95265 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_CH.dat deleted file mode 100644 index 67ba9b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7d095109dd4c27f808eab72792b53e95413b64ce2cc912e1facb8c453d0308e9 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_FR.dat deleted file mode 100644 index 3da664b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bc7350d6af59c9feb12dfb09a66aa9697d621deacc46dd5db0948f41d403a131 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_LI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_LI.dat deleted file mode 100644 index 2d60c1c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gsw_LI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76c83b4c0ecc10232b6d35c2ee2ef35c88eb128aab1768d9fdc906893321a25a -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu.dat deleted file mode 100644 index 454076b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e40fd3eaafff473b9674683d49fb5edb03aa470fc0773f8b24c249cc527cedc8 -size 208242 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu_IN.dat deleted file mode 100644 index 07c2142..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gu_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b215d4332938a2007cb893dacc02e845e1b22ea45749839e54154c9f7d77fd8e -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz.dat deleted file mode 100644 index 16aa682..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e3dd48df1e8490c1b4ae8484288dec1f1b5ac1e5d6357857ca4e2fb06f8bcc38 -size 15427 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz_KE.dat deleted file mode 100644 index 5b44968..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/guz_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:533ff1d3f6052891c3912778e92bee21f3bb5b473ebaa6276ac9a62cd89bdd65 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv.dat deleted file mode 100644 index f739365..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:61edeffeaed2ae709e88e570d6becd45c4ed519dd1c0eaf564ab3ab24c584e8b -size 3960 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv_IM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv_IM.dat deleted file mode 100644 index 9f47a89..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/gv_IM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6d73ac4a8577d37912504087cf6c5de4784049123e5c28ea8f19f1a64d01b75d -size 634 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha.dat deleted file mode 100644 index ac7515a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7d57cda82b885da09357913d5cd30d551382c206a527c7f830a7c4bcaba7dc0a -size 150526 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab.dat deleted file mode 100644 index a20d8e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:014a02cb2ad90d3adfe52119d92462ce2982d7534c482ca89c890c45eaf53f16 -size 2197 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_NG.dat deleted file mode 100644 index 9d3e87b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a18258a9391a0d7da9e0827d8f7b04253e3d75c567fdff49ca33b4ad42539807 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_SD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_SD.dat deleted file mode 100644 index caa3e5e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_Arab_SD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ec30faa730a6a44763c1b4cc01b01bfef25ecba421d2d21e4acf0b8c4a49c41a -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_GH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_GH.dat deleted file mode 100644 index befe025..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_GH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b07ee8749c4309bb82c666674e5c91e9ff97d945da5320e0c9fd3a5df37b8f3 -size 1231 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NE.dat deleted file mode 100644 index 202a2f5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8252b346d49aa2fca88b205cfaf8c56c9d3036ec5f81ae3dc3fcde2b700db6f5 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NG.dat deleted file mode 100644 index 9d3e87b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ha_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a18258a9391a0d7da9e0827d8f7b04253e3d75c567fdff49ca33b4ad42539807 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw.dat deleted file mode 100644 index 9fccdd3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:68d5cdc6aa689d3608c73576d4c5f48c8cc6ef7a9b85b34eea9c7658669e97aa -size 10375 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw_US.dat deleted file mode 100644 index 6aeccd2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/haw_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5b6a8905335d113a6837e51ed1461bab26e58fe8086d034e50caf4d51c09d9fc -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he.dat deleted file mode 100644 index 11232e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3a00008ee85718fe8e9b714b8b91c5a06d6213efb2bc37c0530432d8d2193b0 -size 217062 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he_IL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he_IL.dat deleted file mode 100644 index 746cee2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/he_IL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a943cb2877f40e67de13af4b5f865013cd556caea5dc93a7aaeedc6842009b7 -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi.dat deleted file mode 100644 index 3f9b863..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4d9ea481f0191f472ea17dd8ec5a5310525412696b48671c63d9d63c3936ec2f -size 221948 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_IN.dat deleted file mode 100644 index 5533ecb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50c93148781849d5fe84f8186bbace3b37edef1b49c1c3349b99d3a6151ef713 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn.dat deleted file mode 100644 index f8f2cc1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e7d0c25d20b96c55853d4790491523c61abd5adf98c5e24f5e6c930a2d7ebd5 -size 30945 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn_IN.dat deleted file mode 100644 index 5533ecb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hi_Latn_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50c93148781849d5fe84f8186bbace3b37edef1b49c1c3349b99d3a6151ef713 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj.dat deleted file mode 100644 index 65a6f88..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af25dda4130453317267fbbf622a802baf3d40eb04b943bf02ecae86dcbfe236 -size 2117 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp.dat deleted file mode 100644 index 4a0495d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e867a4657b59557b46708ff393a36a5eadd6c4c9cec7cdc8a519493b2530b3ab -size 746 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp_US.dat deleted file mode 100644 index 519783e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hnj_Hmnp_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b2744a308366cd564b399dde628fb649aaa413d33b58bf81cbd5967880d6a3c -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr.dat deleted file mode 100644 index 4da448d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91dccaa569b22c0205c3b0f90cf286eda1d44236253397dcb5c04b4681deba38 -size 207636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_BA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_BA.dat deleted file mode 100644 index cdaa9dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_BA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13f4bc151767d32b334d6160f5196a4d5e7313009cefeaada1de3951df0b1f22 -size 1188 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_HR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_HR.dat deleted file mode 100644 index 9d6ad5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hr_HR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ea68d60a35d4c581f8267a220d758a76777abcaa97e4094b35cb86479aca610 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb.dat deleted file mode 100644 index 7dd4c60..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c396c34b7dfa87153e442865e1081a6b25e032037f541521e46257ce73c8fc1b -size 206887 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb_DE.dat deleted file mode 100644 index 4116d8d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hsb_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fc42d3f4a06cc12a9eca2c1b72c3fd9c563bf77144f0f43312eff6c3bf009aba -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu.dat deleted file mode 100644 index 3ebbaa5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7664beec6227c357866e27e380cc977359b59c183a74ae88389203a0b6ff129a -size 147032 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu_HU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu_HU.dat deleted file mode 100644 index 7c93bb3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hu_HU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af7459b241df51d93505adb6eb0a811c0a11317a2b961f889162e59d8fe6053b -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy.dat deleted file mode 100644 index f4add8b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:47a9f61bc41d924c65031060a532bb97e70f8701e0d37bc81b5a7099656b095e -size 202316 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy_AM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy_AM.dat deleted file mode 100644 index 7634125..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/hy_AM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af505be96597d90c5594b3f9bd1560a31d078280cea2c03e877a1828b7993086 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia.dat deleted file mode 100644 index da30ba0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:59ae320d30eff53036226a3af6fff8f46aa057c2ef40fd62b961aae8b14030e9 -size 133538 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia_001.dat deleted file mode 100644 index 04d1e69..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ia_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f30241cfbbb3cd8f64ce97e9107092c876510aeb3f8a7d515455ccbe605e598 -size 941 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id.dat deleted file mode 100644 index 3cfc485..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09f082ccadd557df286de1fbc7551e6b1fb161ccdf0b07b1b7027b69eb534390 -size 126977 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id_ID.dat deleted file mode 100644 index c5d6d6c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/id_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1afc0edf944ffd8f2fb3013ad08b583106bb5d43815c62e4f2dbcbf24489918e -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie.dat deleted file mode 100644 index 6b42bc7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f67cd2f2cac9f4ccdef370fb9caa974a51af8ceb6eeeeb4ec802422da7df126e -size 77957 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie_EE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie_EE.dat deleted file mode 100644 index 4965812..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ie_EE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f777666a960d1391c401f211c0bfc78cd5787e9089872d42b1e8206eb8825cbd -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig.dat deleted file mode 100644 index 6a42beb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b6cfc16b0143fef7acf41ee45fa180231c0163c14fe2336691989d21d0156830 -size 78550 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig_NG.dat deleted file mode 100644 index 98ee487..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ig_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8c47ad3779dd4bf18fda6615cf93b2bb27c6e040f138c6fbe99fc47d268762c -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii.dat deleted file mode 100644 index 773049e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:581929ba43ae15ca2bcb3ab44271e175a7c67da77fbbdbdd272d093bdbe8fa22 -size 7477 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii_CN.dat deleted file mode 100644 index 9eaafa7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ii_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:56bfce7b6de4167cfe1037e5ed7783bfa19e4d8d0b48af9557a509a7353cc891 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io.dat deleted file mode 100644 index a749dd0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:95aa811d5ed007ddf75632e26c43a645ecd757d4adc21295ccabd6a7c7bad980 -size 932 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io_001.dat deleted file mode 100644 index 63042d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/io_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4facd9bef49539c769cb77e15db74f0169870af0d396e89c93653cfe1503bb61 -size 912 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is.dat deleted file mode 100644 index 52328f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:afd8274297fcd4da8f56c9152948921966ba554dff357cc97276b51a1a36f1df -size 163097 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is_IS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is_IS.dat deleted file mode 100644 index 99ba5c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/is_IS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f7b548ffa18850ebfb469e7f3275ae0f65fa828621e67195e8fe73030adcd24 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it.dat deleted file mode 100644 index 1b8299c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9fca7129a32e4b67a40fb10e495fb73e655f7739bd36ac45e73034ef7c798ad5 -size 173579 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_CH.dat deleted file mode 100644 index 05e84ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4efb607b5b3805c6c278a2663c18926ed6dffeabfcc2bc3711be03735b05ddd1 -size 2942 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_IT.dat deleted file mode 100644 index 07ec807..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f9ee842b403a80477f1b8fc11e599df3f71a43e93f26b11e98d81d03473386c4 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_SM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_SM.dat deleted file mode 100644 index 2e28932..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_SM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c6313add3a2113c6e390d88e87e0613a4b81f585a94349f6aeb04c26802a9791 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_VA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_VA.dat deleted file mode 100644 index 9d7aadc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/it_VA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c30b25fde02636ef66d893d99e907015587882c93900cf654b1f1401786b3251 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu.dat deleted file mode 100644 index d0af26e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd9206d40b2ac1cad303acdfc01790c9d5409f9a834174fcc932bcc2f6da5400 -size 3209 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_CA.dat deleted file mode 100644 index 99a86fe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b8e3d2b1bac9135bcc3bcf9e95bfad3641162c43dd0ed166dacd1ed5aa50daf -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn.dat deleted file mode 100644 index caca264..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a18b1d58ba2662f54983a90840829839d4865b2ac41dfb5cd94f5b674b07143f -size 904 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn_CA.dat deleted file mode 100644 index 99a86fe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/iu_Latn_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b8e3d2b1bac9135bcc3bcf9e95bfad3641162c43dd0ed166dacd1ed5aa50daf -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja.dat deleted file mode 100644 index 77c14fb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f3ac4f04e6351f57b47cb0ba83feb547f8a94b84066c1f6c5ecb7f270c1d016a -size 179695 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja_JP.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja_JP.dat deleted file mode 100644 index 83613e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ja_JP.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a36a5b1669641198d5ec21c4f5c60435856fda4400f2d7b184d0e111e72043dc -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo.dat deleted file mode 100644 index db608d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d9e07dca63a815bf1a6c1fafec848019c020e07104326a6eb1e1c85c582daa45 -size 1008 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo_001.dat deleted file mode 100644 index f520bb8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jbo_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c302ca11724ec142d80feabdda441dbe98b05b67e08ace5872c3f6993e2d9d3d -size 746 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo.dat deleted file mode 100644 index 7ab080f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f57eb74aa5aa43b4caed9d9129a4301413fdb0ca20ff87103794abfca065c8bd -size 9031 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo_CM.dat deleted file mode 100644 index 60efddd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jgo_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d650f28d92e92ba7d2ea84a97e754b75877621480695441f179dc10dd2bb4cb6 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc.dat deleted file mode 100644 index b58f920..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:951b2dba591f0a3ea40c8f152c7ff7192e1ac00a95b3294c53586fbd61fb9098 -size 15374 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc_TZ.dat deleted file mode 100644 index c9bf280..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jmc_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ce0e9fceb15ca06c7d14a11b31e071dc5eb75ed366d129cfa1cbcd2c0e470ae -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv.dat deleted file mode 100644 index cdb610f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ae70cdd90e81d73bb3ec6ce60d2ddc7452642a594965da2d610ea9fecc963d5 -size 103138 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv_ID.dat deleted file mode 100644 index 54e77fa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/jv_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1b7cd349ea9632781e9a9e6501c821b9d4dcbfe8bc7a0652d763f4f93d43357c -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka.dat deleted file mode 100644 index 5e3dcf0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:748b240e373b65d459d6b189207c4e3ffe3b58efdc7632c3c787a5b581136d41 -size 230234 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka_GE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka_GE.dat deleted file mode 100644 index 098f536..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ka_GE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf3c38359064f1db07201784cc1dd5b5fdbfd670b80e1a9b94ba015177cd1cdf -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa.dat deleted file mode 100644 index 61c2713..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a32d0eff513f29a959a0ab2e415c91def616cf71e2a2e8023279f338ff4a585 -size 17585 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl.dat deleted file mode 100644 index 0fc0694..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd6eed14f5f608fa34370476a350c22aef13b2f9be01e7fd440bb2e8071a257b -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl_UZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl_UZ.dat deleted file mode 100644 index 9d6e2c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Cyrl_UZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0ee806019bc899b5121efbc6986c347a45d7063df8bc48d2907852c555db73e8 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn.dat deleted file mode 100644 index 0fc0694..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd6eed14f5f608fa34370476a350c22aef13b2f9be01e7fd440bb2e8071a257b -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn_UZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn_UZ.dat deleted file mode 100644 index 9d6e2c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaa_Latn_UZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0ee806019bc899b5121efbc6986c347a45d7063df8bc48d2907852c555db73e8 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab.dat deleted file mode 100644 index 8ac4d77..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ca42d1bdd46d1e963ccbb2431ce802d372b1032bc07f1cd8414978e0228aafab -size 121528 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab_DZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab_DZ.dat deleted file mode 100644 index 7206106..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kab_DZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bfa7ddd24ca57ad9b591f37689b49487aa1d75c9292c78cf77faababa150a5df -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj.dat deleted file mode 100644 index a79e089..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b4a2a2e1e6074f4cc424b4878b60de7c41b24d3bb84422a99c036eecd42100f8 -size 2696 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj_NG.dat deleted file mode 100644 index c6c26df..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kaj_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d51383ac100fc42aeb95381f869773f95c509137632442581da244b0e810b0d9 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam.dat deleted file mode 100644 index e9b2683..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ebdc538c3f4ad2dad02ad6d497c18ab5f7bbf65d71ea5ad5ff4ccfb7f503f59 -size 15506 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam_KE.dat deleted file mode 100644 index dc40f27..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kam_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0041084741d688e2b04a5df4e2be0f3ce172037d995b0c440cdbc2b0bc1d8e8 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg.dat deleted file mode 100644 index 3757885..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:74e651d5b3fcb0f6e10f6324e3de93c33f0c3a2be0190a258ae0cc01648ef5f6 -size 2549 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg_NG.dat deleted file mode 100644 index 6273e5e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kcg_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c239b4596beb7d2a1831fccf29b343cb6de8adeeb3c216d1de08e86d7c29ce6 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde.dat deleted file mode 100644 index f0c73db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:70555461e6b29fafa4317e8fc1043727cae91ccaa5d3bfd5ee54a5b889c2db1f -size 15810 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde_TZ.dat deleted file mode 100644 index 48495c0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kde_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dac7dbde07a360cd7962d65e46b73400981d68986a81b549f5cf7217d4a52668 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea.dat deleted file mode 100644 index 07b45f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a366b09c18ac98511641e9ad50f0129993152e53a424d0edb83e9e826bcc6adc -size 76097 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea_CV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea_CV.dat deleted file mode 100644 index 5849157..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kea_CV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f2cf13c4eb23f47fd85d0f8bafbbc0af129f2799c9910d5b9123c631050e703 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken.dat deleted file mode 100644 index d17631b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ccac4baa61140885ba4fd9d3e8c0738bfcd28a16910177ca8d515fcda599c3c -size 719 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken_CM.dat deleted file mode 100644 index 1cbc301..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ken_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8cd1288c002d42a24c904abce24c47539846395402396fe19c6412731c9c60ca -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp.dat deleted file mode 100644 index ab907ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:38ac7565b05d1f0ef901dceb4fea5eb66df60e3f3025db54407fe86a2eefd2a2 -size 184092 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp_BR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp_BR.dat deleted file mode 100644 index 90ce73b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kgp_BR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:14d49802a3e1933a19ce1a25c53c9d81ab2092ec3b8e0c427f22836de4622ede -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq.dat deleted file mode 100644 index 10fb012..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39c5b8669aedf9695378fa3b0f3aae07ec92f2fc1f3ea8da8a3a64ad7e65ef9c -size 15753 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq_ML.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq_ML.dat deleted file mode 100644 index b576b2f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/khq_ML.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:562a9384e7194c7641b5e6d5f0b258f835dd5955f98c0479a5d941ad32b0b364 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki.dat deleted file mode 100644 index 6399a98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bdf7e96fa5b2ed337ffe16501f5489622f350316a68419c42bf5c10a21773857 -size 15451 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki_KE.dat deleted file mode 100644 index a0a3717..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ki_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3cda3184ff962f15b6bc7ddf4bc37d36ecb4b558a630ff9901a09f2df9df0cdd -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk.dat deleted file mode 100644 index 99edbd3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f778eda4a71f8900516f278ec8982a11365718e9eda2c0769c679d8074a1335c -size 200871 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab.dat deleted file mode 100644 index 6df9c5c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c1b199ba88b27f770da63710dd424f798c42d9f3b980acd975da292d0b02b0a -size 222820 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab_CN.dat deleted file mode 100644 index d58bb51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Arab_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1c2a1a062df610d769271e6eb1774147d691fff30715e295fb04e8ff9ded40d9 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl.dat deleted file mode 100644 index 676d723..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf79ffe2f6d40ff39c6618bd4e6f2f912bbd87845481abd9fc216bba315bb961 -size 1584 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl_KZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl_KZ.dat deleted file mode 100644 index 14fa081..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_Cyrl_KZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:79a416ed56b5cf62f7e21b3e0fd420ae6caf3a8e0ba72daec71bf19acea42f8b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_KZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_KZ.dat deleted file mode 100644 index 14fa081..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kk_KZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:79a416ed56b5cf62f7e21b3e0fd420ae6caf3a8e0ba72daec71bf19acea42f8b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj.dat deleted file mode 100644 index 3eeebeb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:218785e14a1e6f491fc68a052c572a99d2301966d68743147c1a73b53c56144c -size 3373 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj_CM.dat deleted file mode 100644 index 52bd4ee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kkj_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82a1f0cd53c6fcba37b2f68855ed0a7e18f80da2adb2d3b12498541afbe949b2 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl.dat deleted file mode 100644 index 2eef5cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0fc4928f12d99625cec724f1a42d71ee361b1509f859b495de57e8b4516ddc9c -size 47570 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl_GL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl_GL.dat deleted file mode 100644 index 1ae3ac8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kl_GL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:738f64d751ad046f3ebc4c6c40da3f775a456909b42d899797b41c3124c40290 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln.dat deleted file mode 100644 index 69bb346..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a6576d44445652110e03ce7fcde1497ec869325ea0b607442e31b2346b49ccea -size 17427 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln_KE.dat deleted file mode 100644 index 96f8ff0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kln_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:66190a819da54dd580bd654e244165a78012be393685cc93736fcff6cde6ca44 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km.dat deleted file mode 100644 index 6b85012..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ee78330becfb878e5304d017b0f71824152148c413ac253ce9330ca3cafb97b -size 176653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km_KH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km_KH.dat deleted file mode 100644 index 6633fd1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/km_KH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6e7ca476af91609d19c1a8d5e5d14156d3386a75642e35eeb45754c4a072436a -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn.dat deleted file mode 100644 index f7c575b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9f40071cb92997814861e892084303245f6616be670a01dc57c1d208e2b3f32c -size 267281 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn_IN.dat deleted file mode 100644 index 28e9141..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kn_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af1d4b2587803fcc54e8c214df28472ee8a37b939058bff0cf3e60973b48762d -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko.dat deleted file mode 100644 index 157ab51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b582229e34cce592f0f80bd67ab511f21e05450d3d2c67e844dcaeb65da230b2 -size 154621 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_CN.dat deleted file mode 100644 index aa7e40d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:53fab56a98b6f2e71a0be0013816fcdb60a04aae27cb084c374dae4bb4c24442 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KP.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KP.dat deleted file mode 100644 index afab37d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KP.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04230e2904b35cd9e301459f659f296c5a120c179df6d9e76adcaa21e3cd5a2a -size 816 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KR.dat deleted file mode 100644 index 785a5a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ko_KR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:089a8a8a3d2850b21e0881bc31ca21767844b1f2715309891cea496356cbacd6 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok.dat deleted file mode 100644 index f0677ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d694b449781eb51fbd0c7b4bef53c0c36548469e756bd29fc684a7c37068c45b -size 179992 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva.dat deleted file mode 100644 index 3cfbe19..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:10fd794c7795ef885de46dc30d7970207cf142fa4409aebb4e2a0119ababde5f -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva_IN.dat deleted file mode 100644 index b783d08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Deva_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a2472f10e950942f3808c4d3c5119cc004a3a0d77527f836e50705e70527849 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn.dat deleted file mode 100644 index 0459705..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d5ad05f549eca56d63ba0776a76bbafdaf5b11bccc8ebc15703dfc97c41e2e3 -size 29867 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn_IN.dat deleted file mode 100644 index b783d08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kok_Latn_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a2472f10e950942f3808c4d3c5119cc004a3a0d77527f836e50705e70527849 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe.dat deleted file mode 100644 index fb6cc0a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00747f646d69e75f03e32ba533f72ce44e7c88cb155ca9381e2ea4d15d080e14 -size 1331 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_GN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_GN.dat deleted file mode 100644 index 2dfbf78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_GN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ede69b4859acceea67d089733fa4d1835fbb1594bd001dc9741903809b48b3ae -size 1210 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_LR.dat deleted file mode 100644 index 4b106f9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kpe_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0eda0cc79ffa2ba200b4a8e888c88a31f898f203bde11007bf7d9dc58f9b587 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks.dat deleted file mode 100644 index 7b19918..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2b2492029b1f05fc4cdba4da5ec2b680285dde7a15d5ee65e35814b1a0b70c0e -size 111691 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab.dat deleted file mode 100644 index 0699e82..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f30cbfeb0a20be06aca63e117a1815fe779b9592f6421387bc252d8bf1c8d15 -size 850 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab_IN.dat deleted file mode 100644 index 3e7f854..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Arab_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8e13c3c18a03031fccd0af189a7df99a6e6f75322f3e3957434762442bcc4f0 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva.dat deleted file mode 100644 index cfbce84..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1e5cde1257cdb8ee0e0c5bc47b3075cceac2a4d6a85fd969a8c25b3fce8c003 -size 12510 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva_IN.dat deleted file mode 100644 index 3e7f854..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ks_Deva_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8e13c3c18a03031fccd0af189a7df99a6e6f75322f3e3957434762442bcc4f0 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb.dat deleted file mode 100644 index fd6ac12..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bdb0782554ad9a9648bbdfef8ba7fdf83b78d2c376c0fbc5f58d89cc927da046 -size 15356 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb_TZ.dat deleted file mode 100644 index fa65ebc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksb_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ef581314869321576ef313d0421095bca0ca915d62bee95c264ac5d90cc4cf6 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf.dat deleted file mode 100644 index a792008..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:20882faad9e54f13262d2937f09c997b43c0e602c45fce990dc6952142e9ed97 -size 15952 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf_CM.dat deleted file mode 100644 index 55dea3f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksf_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d0e3acb944b44bf014c543f248540e6556cf701dc5d88e32cc7666eb7632a435 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh.dat deleted file mode 100644 index 4564928..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:33a5b4db18865226c35b5dd1201ee9b1bc0c036c1d358407cf7069f57963859d -size 76781 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh_DE.dat deleted file mode 100644 index 8b6e221..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ksh_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12181820941a0b72c6896adc136b1d7d40bc2ce5899dc8963918bfca84643afc -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku.dat deleted file mode 100644 index 8430e80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6de072ae15e307c89185a346c6441ac6751c92eb6eb37309eb53e6f91a3c4aa5 -size 117087 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku_TR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku_TR.dat deleted file mode 100644 index 4e62065..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ku_TR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e8372a0bfa9a185e0a9e8c3cc1f7ecc8ff44c8245dda9b0cb372ce949c75082 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw.dat deleted file mode 100644 index da34888..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c79245c5fbf80ef2dde579eae49ec995b71f7e160d5f0227e7e269dd0e505790 -size 7242 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw_GB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw_GB.dat deleted file mode 100644 index 2bfbf3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kw_GB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a25ecb5a124914da0d905123b64e31d4fa4b90c2fd51bb9599902e1b8ecba246 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv.dat deleted file mode 100644 index 8b2aa44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00c7592892257e472949eb4f7464475fc2cb3743b5b35e0d02d0f37a44a2d351 -size 69503 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva.dat deleted file mode 100644 index 99266b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3257a388db304bf2c901e9a3fafc84caf5dcd92ca68a7a8d0966daab779c78a9 -size 86834 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva_IN.dat deleted file mode 100644 index e92e7ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Deva_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:678dd87351b806c9aeecaba415f8177c89750aad91a9aed1410358ca013901a9 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn.dat deleted file mode 100644 index cd2699b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5eab6e17dca1d2d06b0cfa11a598ffd4cc3e414aadf7c9253a58195e1eea3eeb -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn_IN.dat deleted file mode 100644 index e92e7ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Latn_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:678dd87351b806c9aeecaba415f8177c89750aad91a9aed1410358ca013901a9 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya.dat deleted file mode 100644 index 444c025..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96c8d6b30654dcb5a660d139b4b9fd7256be5926dd7ea02896d0bf3afc6d476f -size 85964 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya_IN.dat deleted file mode 100644 index e92e7ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Orya_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:678dd87351b806c9aeecaba415f8177c89750aad91a9aed1410358ca013901a9 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu.dat deleted file mode 100644 index f281f56..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad726b5b11cc16b3de85ea0db7d36f28bccda062e9357887a5ce0fb2e4b8b57d -size 88218 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu_IN.dat deleted file mode 100644 index e92e7ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/kxv_Telu_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:678dd87351b806c9aeecaba415f8177c89750aad91a9aed1410358ca013901a9 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky.dat deleted file mode 100644 index a83894b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c01ffa2fd7172724089ee65b41dc8fd701426cac4ffcb45c0594e8e8ad106db -size 179889 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky_KG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky_KG.dat deleted file mode 100644 index ad9775d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ky_KG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09db63451da26607c6e69773d77317f841d30ed37a05d2de6701829ab667ae45 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la.dat deleted file mode 100644 index 6a11ac5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d1301d88ec400e0d02d807888f9451c622e031b54ef8fa9131fe06026d4ce1d1 -size 33982 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la_VA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la_VA.dat deleted file mode 100644 index beada0d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/la_VA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76150ba1c697c891a2b6b963775c3af3c0d399ecdc9a663c61ca0ab13df49f7e -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag.dat deleted file mode 100644 index 7ab7f0c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9ad8edc8b1cb09fa14af8493b41a8b5cec4b9d9d2282e8130bd7d98b225993c1 -size 16281 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag_TZ.dat deleted file mode 100644 index 29ea287..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lag_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e57c496cf030efa15a74ecc62715d2c13d486426cda4cf0503938e416483be8 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb.dat deleted file mode 100644 index a5d8338..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9541a6f380dfc0b810def0b498bfdfa057f97526592834c8bb00917f9063815b -size 135641 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb_LU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb_LU.dat deleted file mode 100644 index e78426a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lb_LU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b34018dbe17b06a038b4c7113e309f6f36d745b1ec2a70fab884064a4ba5093f -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg.dat deleted file mode 100644 index e905185..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e7328faa01c5876db02e466093cf8fe70461e0531d1aa23586ec2f13167fff4 -size 15834 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg_UG.dat deleted file mode 100644 index 3259456..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lg_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9f29ff1ca7411c690795b8e50d7dbc2f967d939f4c285aaf9952f7be0db6dacd -size 639 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij.dat deleted file mode 100644 index f3062e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21cf7cd92b7cda63cc7ee42aa8bb303ed3b2f0b96095f70b624fdfb480cceb94 -size 129648 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij_IT.dat deleted file mode 100644 index e8a85b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lij_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aed3dead4ee5b709071dcec712b7f025f5fc4c3482a531ef073c0a05d4ade31e -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt.dat deleted file mode 100644 index 7baa411..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:53fc9735658992a95ea5a67d912f8554e00740a566734be1c205a0151cd79ea7 -size 11180 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt_US.dat deleted file mode 100644 index bb1bb26..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lkt_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cb05a0f66f34b4d8ee980c4636b0706215e1736f2b0b8392772be475700ab396 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld.dat deleted file mode 100644 index 9be1f63..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d890503eef13f9c315ab354e16cd15cfed2153646d1ccc93be3d05f303e5d845 -size 95451 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld_IT.dat deleted file mode 100644 index ccca113..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lld_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac74a2660ffe05aeac8b62ce3540a643ce35471717da9ed5d630d2bb034d060e -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo.dat deleted file mode 100644 index f009104..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:198a11f7c029e61a2c1bd6df10d100dec0a447e9ac17f2afc55da72f2763b3db -size 1659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo_IT.dat deleted file mode 100644 index 6838903..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lmo_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5e0e10bf27bf84f3492c24f0a01b91300be1b6341bf15943f52687ff98551bdb -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln.dat deleted file mode 100644 index 07bae5f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:387a946e8eccfbad340ada4e50daaadc1f93b74fcbddcd86832476c5986e3261 -size 23909 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_AO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_AO.dat deleted file mode 100644 index c944347..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_AO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54d70556249a1b0ddff760fad1493bbf143c8ba43d1f5143ea9683a4987eaf83 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CD.dat deleted file mode 100644 index f08946c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:028fe5516bacc098061e154962cdbf67c2f23788aa818b0075af1ff546ab4fab -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CF.dat deleted file mode 100644 index 5e3836f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:839272ee8bd4930727d16e4ebf96eee5205cda2338496c14170b735b30006f7e -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CG.dat deleted file mode 100644 index 8159a91..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ln_CG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d095dd32c3adee7d66e194eb7cd708dfef7d73665b9cdb359cd40eb99019403 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo.dat deleted file mode 100644 index a239731..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:857b604f89e4a9bf21ebaf53b1acdf20506c2b6dd036970265baaf6fa497581a -size 189363 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo_LA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo_LA.dat deleted file mode 100644 index 17ec412..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lo_LA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:80d6bb291198588d21d0f707277e5bc273ec9082ce1fed632e31c25cff398da5 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc.dat deleted file mode 100644 index e93d926..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19b2be6d6c384e51af191c8ce16c43ba3914afb19dcfd93603ffdf49e97011d9 -size 13594 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IQ.dat deleted file mode 100644 index e4997d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:732f433bda00288e7534c8ad01bd8c4db668c6d6803f3698546574fb17749860 -size 1255 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IR.dat deleted file mode 100644 index 07452b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lrc_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f9c6b81264d7e55022ff9b437e29a97af2456fe83cbc08e0a5efe39034c36564 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt.dat deleted file mode 100644 index 8e2997f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d61e538c5bcd4aeaab137267b539a72cdf705baf637e455a90020809c9a855b7 -size 262613 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt_LT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt_LT.dat deleted file mode 100644 index 971e75d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lt_LT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8fc74842b15cd2cefbc49e0ff941a20dc68da995ba09738488e877d057a63626 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg.dat deleted file mode 100644 index 69dd17e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a9168286805672690bf00b3d3200b2b12879f013ff177512eb911a03ded98194 -size 2632 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg_LV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg_LV.dat deleted file mode 100644 index 1f44479..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ltg_LV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a6f2cb866d22da346cf358f8ee10a55d12a247d7c001b9ee21b5e82bc87ddbc -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu.dat deleted file mode 100644 index 4222923..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e131801a461b0c7cfa4002901c75e84649745b1fb42ce88c9138c383026ad135 -size 15331 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu_CD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu_CD.dat deleted file mode 100644 index c007ca3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lu_CD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2b7934c0ca486e3bac80f0b65b5ab6b31cb1ca7c7633bf3338b8ede2291ca190 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo.dat deleted file mode 100644 index 9e171b2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c493526f6e4e550a203b8d9df89cb67d1d45cde49f5bd4b0c2df566ade049ac0 -size 15201 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo_KE.dat deleted file mode 100644 index 0554b87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luo_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d551dde83bf53b20fe8a9af4a454760d9a509cf3ffa6da6a493016aa02b4852 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy.dat deleted file mode 100644 index 3900dc9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a5c4db69272d4325605558789d7a17c4c40665adc8a7b86c7d1374f7acf012c6 -size 15030 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy_KE.dat deleted file mode 100644 index 468eded..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/luy_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35591002d983057530b372b26e733bd3a27797051ce5f268f9812329dd73862c -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv.dat deleted file mode 100644 index 45fc147..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b35d286c7b13624045f7dac00c6be4c6ea6ffbe26444f412d9a33ab16bdb3380 -size 201861 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv_LV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv_LV.dat deleted file mode 100644 index ff99754..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/lv_LV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a12f56d297624cdb4c4de18eb1e7f62bb55ad8eea4f9d404b4dd36a82680a05c -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai.dat deleted file mode 100644 index b385143..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1688f8b2988786e3a3059a9a5d0c593425b0742a2c97007b2925fa9d74117aef -size 95488 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai_IN.dat deleted file mode 100644 index 49b991f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mai_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e8725a476b99e51dc01f960dbceb270e8d0eadad93fcb874e1cdca77ed8f751 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas.dat deleted file mode 100644 index b448052..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c71ba06e019cdc9c6f3361b3575be62b2d5bbaccef8b2ecdb521fecba19d319e -size 16595 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_KE.dat deleted file mode 100644 index 3452920..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc7dcb7b88f4dd836c3e3b7ff862f946f3c6d339e724a43789f6cb84c66ca184 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_TZ.dat deleted file mode 100644 index 7fdd0d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mas_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:572449941a95fdfba44ea491f49c6bf8fba3480eeef8c3fd697ac90552422a20 -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf.dat deleted file mode 100644 index dda30ae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3501fd628efba32bf1663ffddd721fd1ed34243028236c9d942492de494d8309 -size 2240 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf_RU.dat deleted file mode 100644 index ccbb389..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mdf_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b159d3c60cd4dab13097b3f8779518e9738abf55d409bb641103b472ed8e94e9 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer.dat deleted file mode 100644 index b5ea853..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:585976a904e15ab8a551b05a37850941bf7b66b577b8e0786533bd917b23b674 -size 15426 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer_KE.dat deleted file mode 100644 index 3f32c04..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mer_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5aa0d04ec3ba06d6d139d723de9de8994664f1707a1e226b2250828ffc0b3f1a -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe.dat deleted file mode 100644 index 052dcd6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9f99493df778a630b7c66566d76de2bd5a6383e58090b42af5838dc35265a53b -size 14835 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe_MU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe_MU.dat deleted file mode 100644 index 915649e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mfe_MU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30750e2a240f1ee51b853ea1417244929183bd3532315e1bb494ee88b8494389 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg.dat deleted file mode 100644 index efb617f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f4f6d9849daff513f65d2cf0bfb6c13d31a548d609ad450848d913c1d17567b8 -size 18776 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg_MG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg_MG.dat deleted file mode 100644 index 3e44b51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mg_MG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b896c6784cc89f8461e4187887257e1ecd3fa9ecfd28178e8b886f7c2df3908c -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh.dat deleted file mode 100644 index c27c15f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b3221cce77eab350146e77964f8dbb4105cfe638dd87b8a1aefe890e6a109b9 -size 9753 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh_MZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh_MZ.dat deleted file mode 100644 index 42cbcd5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgh_MZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:685659e35aad01113a09e79c084c7df6dcd6fdfa7e5df900735d30a50e587863 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo.dat deleted file mode 100644 index 85789fb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c7245a126195e85c3d9d57d1790258eca7e01b0767bd0cd270b887d1aa69b0b5 -size 3549 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo_CM.dat deleted file mode 100644 index 3ef6572..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mgo_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36ca77dede1a6d9b0a743988801f2d6f4f0eb0487eec95cc63f24a0ac77ad736 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn.dat deleted file mode 100644 index 6f18dc7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4694b1c5ebe1bd8c725f476ad5102122aa11132c8fc0a8ec0725ef3a142400c7 -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn_IT.dat deleted file mode 100644 index 0c021bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mhn_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd4a07fe5ef222d379a9728f6aae9b58afc2bcaff00faf33931ccbac2c31afd0 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi.dat deleted file mode 100644 index b1697d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:665cb22925090ad97bcfde2e230105b82eae04659739333c1754c92e225e4a6c -size 85086 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi_NZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi_NZ.dat deleted file mode 100644 index a1e2756..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mi_NZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:44494ffcfe05d470c78d21ec76de78beb885733d13708793dbaa66fbf772f8c9 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic.dat deleted file mode 100644 index c6ab8cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a9ef5740dd98538a23d37e4ddbd0c9bacba08cd09fa6191d1abfea6cad41ad2 -size 1638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic_CA.dat deleted file mode 100644 index aabd656..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mic_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b99a01bd116ec7a338d077066aeec4e95d0fcb1878e41c62d1216780ec4b5914 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk.dat deleted file mode 100644 index a9db94a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c55254f9ab9bc36150fd31f305419de4b1d1e485355631a43ce7911e953e4fdf -size 216606 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk_MK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk_MK.dat deleted file mode 100644 index 502314e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mk_MK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa523566d2e0c97d9f7184bda674daf229657529cf99f3573918f0b3e1fdde57 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml.dat deleted file mode 100644 index d60b610..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b51d25b76b90bb39ac0605d622e469cfe0330f4d12fceaef2dcf909226005fe5 -size 246736 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml_IN.dat deleted file mode 100644 index 6c3c1cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ml_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5700a7485b37a21ef1a38fa74b51f35a3ff12020f31ba13e016d0ec62e8bbb4f -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn.dat deleted file mode 100644 index 9e47305..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b7a12a670dddcfb7e751af0760d6fdb8e52e88ca6dd2067659de0a8e8505b90 -size 183647 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_MN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_MN.dat deleted file mode 100644 index ddffa89..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_MN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa12462035d2825b1adc16026a5b2eb28ca22a03a3ecf27dd188b8113dbe9f17 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong.dat deleted file mode 100644 index 50f0d7d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cea0ae2f6f12c750d2f0b1aab42da7c930a8129485a45d2f137c2f071a472b5a -size 1726 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_CN.dat deleted file mode 100644 index b5362d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:59317cf444a176d05dd15cfad9eac5c25f4a4c6f86804cb38e398a5ae242147d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_MN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_MN.dat deleted file mode 100644 index fca5113..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mn_Mong_MN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0536a1eea7d4f506b251bedebd429d17d7383ed7f836aa8ee9251e52a97605a9 -size 12935 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni.dat deleted file mode 100644 index a24ce49..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:692fd720e987469b454ff75316ec604ef0767043ca1c955533fbed5114c5a3b0 -size 12972 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng.dat deleted file mode 100644 index 621599a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ecf4ca653fd413758d8a2a721879e7d920cd14d84072a1e1109f13d18dceee02 -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng_IN.dat deleted file mode 100644 index 34dfddf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Beng_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9c05bf2df46d26a0baf9e85d0bccb2b338e189b5ea3005cf92e6b3f0f3906aff -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei.dat deleted file mode 100644 index ebb267a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cddcf037269122297b9648c47fa3eba105f49f0625739545e2be201cd4d45536 -size 1720 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei_IN.dat deleted file mode 100644 index 34dfddf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mni_Mtei_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9c05bf2df46d26a0baf9e85d0bccb2b338e189b5ea3005cf92e6b3f0f3906aff -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh.dat deleted file mode 100644 index ad6482f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:16ecb01221515d07b5194bfdccf475e4a3ac64baf54f2926ba09629cb20d4ea1 -size 1316 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh_CA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh_CA.dat deleted file mode 100644 index 1115e62..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/moh_CA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:01776b4bf02cf03aeb4c6b39207990c17a045e7745ba85a84c65cf5dc2f83e4e -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr.dat deleted file mode 100644 index d095895..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:506d0592e7d4b50eeabf370afd610d46ae9280fcb8cc072f8980d02fe36b198f -size 234157 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr_IN.dat deleted file mode 100644 index f9f29a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mr_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1cebbd411d412db722a85e817937d6bc3d0be48830bf91eb096bbdcbfbcd9ecd -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms.dat deleted file mode 100644 index fceed36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:97f610a1be30e2376ed14f99f9e3182b66cf0325345de7a46abd28953e46db5b -size 114970 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab.dat deleted file mode 100644 index 587052e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f73adeb70bdda3ff4ddd22312cab14b4354d6659a1d0e86b3c3c66b56ab0db65 -size 14359 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_BN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_BN.dat deleted file mode 100644 index 385f8c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_BN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd310a4a1d218f28962617f9d37f9fc23003bd308dd00a914b317a9ae2f9d891 -size 1335 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_MY.dat deleted file mode 100644 index 1164a3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_Arab_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c3a659af3dea1269ec2ec5ad240f2b4e886a17573172d9334a3e163745c7b871 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_BN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_BN.dat deleted file mode 100644 index 385f8c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_BN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd310a4a1d218f28962617f9d37f9fc23003bd308dd00a914b317a9ae2f9d891 -size 1335 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_ID.dat deleted file mode 100644 index c509608..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:64f8270c9822c9c0c71999cddc483b3a0669d63218b6267332a9bd7f72ceb51f -size 3440 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_MY.dat deleted file mode 100644 index 1164a3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c3a659af3dea1269ec2ec5ad240f2b4e886a17573172d9334a3e163745c7b871 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_SG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_SG.dat deleted file mode 100644 index fa72926..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ms_SG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8ec7cd6a0e5641675e8f387985ac80efff886d8d3731454f00f0c7509c826518 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt.dat deleted file mode 100644 index 72a1e67..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5f1ffe6acf232445ce04081f157eef13afb641ec78156279ad85b70e509bbb40 -size 49384 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt_MT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt_MT.dat deleted file mode 100644 index 3a4abc9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mt_MT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f9ab92e2cd940bd3e14b8f653ec27d98864a4bde9ed9be377202f1f5c30506d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua.dat deleted file mode 100644 index b03aea7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:378ce2f17c90756fd39acccd1d0ca7e339a26be32908d5b1fd5b9da1a8f4ef94 -size 15861 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua_CM.dat deleted file mode 100644 index efe29d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mua_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21be0aebb29f9ddc06b286431f47a11c0f85ed5fd2523eeaf55b0ada3bb36884 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus.dat deleted file mode 100644 index a761248..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccfa85c11f68088274980e9ebd8c13ef9716b7f40117ed1e0d9c759fa7e6b036 -size 2722 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus_US.dat deleted file mode 100644 index a4662da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mus_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c5c77828a508a81c1279f482d061920e4bd72f8e9e0d6816a2526c1ae49feb9e -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my.dat deleted file mode 100644 index 0bf3edb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5cae4ff6b7254f2811ff6160bf0f487ca359db1c7f64df87b8d78272c0cffa1 -size 183534 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my_MM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my_MM.dat deleted file mode 100644 index 27cd5b7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/my_MM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:979dfe0f960bf816e62d962f7855762126b835cad2c137cab1145ce3525de365 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv.dat deleted file mode 100644 index 623fc9c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efcfbd5397837f7576ab7323d0c6b32318759fcb23c958d0d4ed0ecade7cef93 -size 16828 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv_RU.dat deleted file mode 100644 index 86fbdf8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/myv_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b27731c0ea637c591101228730fd72b4a723a45e30e068d4fc9115a97bfce138 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn.dat deleted file mode 100644 index adc6736..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f18e551a5cc2c4a5f304fe6216cc9f94b6524b5c74ff74fcb2a6f08af7d4e39b -size 46144 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn_IR.dat deleted file mode 100644 index 11110c7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/mzn_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7e33757a4d9f033672cc52698d7fcc21ce6814e12a8fb2d2fd235d04e412f596 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq.dat deleted file mode 100644 index 0bb9267..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:374ee7b0149212e359e1f796be8edbe185b06e08c1c25c46f7ae773be3a58662 -size 15797 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq_NA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq_NA.dat deleted file mode 100644 index 1a753ac..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/naq_NA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b980020ea3b95ef9d54e017fe4d8e5ba804c957c45317180d426efcc0436393 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb.dat deleted file mode 100644 index e08e01c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f9b1870d2a2748476a7dbd8fc4d0b5ff78ce1c42e6dc2c15ef1cc4b699966541 -size 1330 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_NO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_NO.dat deleted file mode 100644 index afe242e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_NO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27552237e006f74d1a70ccf8a747c11ed5c3a52d070fab86022ee083d80eaec6 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_SJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_SJ.dat deleted file mode 100644 index b67c409..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nb_SJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5dc2bdfe72ab89463fe24d3d9268096a519396cf9ee7e612f8c08f10a2cff2f0 -size 634 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd.dat deleted file mode 100644 index e6782f3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21398ff262c36fadc83412a5c5edf2099a916ef2fcdc3ad5064208000fd88e60 -size 15730 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd_ZW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd_ZW.dat deleted file mode 100644 index 75ace5d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nd_ZW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a9647acfaffd11bb4b7da2348af598aa199ebead2a6f03b717f42e3cde87119 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds.dat deleted file mode 100644 index a654139..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ab777112c11c74b4ce8a03d0c61117b9a038534dee98ccc804d0b836416f8a7a -size 47839 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_DE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_DE.dat deleted file mode 100644 index d05e2b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_DE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4268790e35fae56e7c8d75d75f7a717f14bf1d54c955abccb2904f76987db1f7 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_NL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_NL.dat deleted file mode 100644 index 754dc42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nds_NL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13f10edf295a06324d4e1af6d7563379f8790d16e4105155a5b04c5c84385355 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne.dat deleted file mode 100644 index fbaf6cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4e6fc214aee75f269eb20b3847926602da6915635b1dd7423bf69497ceea6cd -size 210152 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_IN.dat deleted file mode 100644 index a302910..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:48596800366dc9be36c328109ab332ef2c7e6800c64040992547b2efdea8aa7c -size 1292 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_NP.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_NP.dat deleted file mode 100644 index e26d639..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ne_NP.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c673b6794d18b41d1350758e1ba8f8ad57bde0cd33d62ddfe0fba68fcafaf27 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl.dat deleted file mode 100644 index 9a0e02d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccee793d05b9c163338d19941848b99781f50f5ac2f74350b76eb68db448cb36 -size 150031 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_AW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_AW.dat deleted file mode 100644 index 5a93b58..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_AW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d8c9c3cf7b91c386e3ffccdf3dcac5d1d80aa321bc7ff970769f4f9350f871c -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BE.dat deleted file mode 100644 index 5572444..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c479b24ce2bdfabc0f007e9f61d94f159bfec629e64c535137e2c81b16f9f471 -size 1876 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BQ.dat deleted file mode 100644 index 5cf0f9e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_BQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:959433ae65ac153a625b04fd97a15a92b368965dd034fdddac831cc45900cba6 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_CW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_CW.dat deleted file mode 100644 index 79b3123..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_CW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76811e2d2b1055a4a870fe23af92f136b4f996e4a21b886482c32fa188c906d6 -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_NL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_NL.dat deleted file mode 100644 index 74faab6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_NL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c6a389f28e1a9ed55b431e53f911498d9012ac562512887de1fe291770fb91a -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SR.dat deleted file mode 100644 index e501da5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:77e617039400e5bd8187e5a1c4d4e4c8a43844e86e120d427863795e6cd67193 -size 696 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SX.dat deleted file mode 100644 index f8eeb58..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nl_SX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7224d0227b6fd278c024621410dce8eacb4df326ab7e1f9e069984cf19a925bb -size 638 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg.dat deleted file mode 100644 index 0e6091d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3445946f4448e37a1e581c87f65d45beb2c3bd5418eb9d358ef88462633f082b -size 15468 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg_CM.dat deleted file mode 100644 index 2192a97..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nmg_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d00f9c55482dd65d484e73d175c816890ebc646a870d877e936c1273f9d79cc4 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn.dat deleted file mode 100644 index 92be101..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13e634942fbc40a09775cf020bf64f3776ecb6c5ec337303e0bbbad9730cab75 -size 64042 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn_NO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn_NO.dat deleted file mode 100644 index 73b6962..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nn_NO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7c7962b7081ab94ff748e1ae9d407d9392d47280c1f4127a4ed443bbc3c9556 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh.dat deleted file mode 100644 index e3ce6f4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7164d3a89117967ea951838dec7e0f46b62bfee45692d4b370b1820bc8e74e7a -size 3530 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh_CM.dat deleted file mode 100644 index 12e338e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nnh_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76df593475f9650a3e91cc93e3e995442522bb32fe1f603d7b4b3426b1f066db -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/no.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/no.dat deleted file mode 100644 index 0ded99c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/no.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c7191257d6f00ca58a2ba7661886991a8e2c9df90e37d789529dfebaf9440b5c -size 191212 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo.dat deleted file mode 100644 index 3cdde12..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:550cdc0279149c011300bf31a2c5c1b1096d942e32aa949934c930b6c58f4602 -size 109412 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo_GN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo_GN.dat deleted file mode 100644 index e4fcd2f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nqo_GN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dde3924c169933444d2d40d916bfff29347ff6266819416af4ce9b86d9878dc5 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr.dat deleted file mode 100644 index 82a3598..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6472080bc05a4795c19a750b3937e6018cd79aa226ab942610ba9b14f28a409a -size 2167 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr_ZA.dat deleted file mode 100644 index 5f5b5e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nr_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b8fdccea7323327b4aad8497768739fff629d34bc5a38db14ecd1277c004b6e -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso.dat deleted file mode 100644 index 90b52ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76cab49afc20e502b7e5a9746d5c191942fdeb512e192d39be5151e6a6f81f03 -size 6470 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso_ZA.dat deleted file mode 100644 index b7efad3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nso_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4dd3aa553cca36280b0facce3d1ed6ed01d3f80c38d3296c504edb98cc2068a6 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus.dat deleted file mode 100644 index 1e5c884..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e06d56c2cab5c9621ec389c0f90068da3f0b99ba814d16748025342d82d44949 -size 8215 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus_SS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus_SS.dat deleted file mode 100644 index 7a49ae3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nus_SS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:22cfe65af9d24bb8f4e5593d4477027f22ce76139e39646a8170dff0518d1094 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv.dat deleted file mode 100644 index 3ef24c2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ec20689be0435fa5a4da8f3bf21999f03058f10012f19f7d131766755a6afaf4 -size 721 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv_US.dat deleted file mode 100644 index 76e397f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nv_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6a4ee3d860da38c6c00265d085f0bd3d133c13d87f84964bdd40eac6a8c2b682 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny.dat deleted file mode 100644 index 6791cb9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d7bf215c46735c1fd29c007d4aee3cd2e712c5b173255d55b7ca8c215cf20ed -size 2152 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny_MW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny_MW.dat deleted file mode 100644 index 97e2aa9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ny_MW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:932864729aa02304ab51c7f1bded8e4b63fd4b501f5c8b511e6cbde0aedc438f -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn.dat deleted file mode 100644 index 8288262..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d595b6986cbd100a4a55bd7dab61850546cb88f013a37117a58e471a9a86d26 -size 15668 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn_UG.dat deleted file mode 100644 index faa4685..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/nyn_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7c49be44c23af8fbc88db314a192baf1d4da88098ea87d620d0067db76baaf6c -size 640 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc.dat deleted file mode 100644 index 2441bc8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d066597b5e3624d110efc18feead52abb668973915bafb8af900c2a4bbb867a6 -size 66841 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_ES.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_ES.dat deleted file mode 100644 index b113d7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_ES.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1fedd425990909a716fc110b884ff05ec5d2547a7e75fc6fe7da371de77cba1a -size 33273 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_FR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_FR.dat deleted file mode 100644 index 49a518e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/oc_FR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2fcd08be5e9d5294091787c0635c5a01e0913bd06437497aa02afc9d1c2882c3 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om.dat deleted file mode 100644 index f882e72..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1b2103b66c27383e7b82075e3383d1b0f575b79a5bfc0ff0f40b7f52327027c -size 67446 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_ET.dat deleted file mode 100644 index c8b514f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf4c0737b8b072e24dfa21605853eb19da651fa3fed1cf01d8e12a60e11e6f8d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_KE.dat deleted file mode 100644 index 366abfb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/om_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0d9fb61f2c291fd34612ba27168c7ed80a6bcf2a12834c49012eb62cda99c5c4 -size 1365 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or.dat deleted file mode 100644 index fbf2098..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ddcdc2c20be051a6bb590659bca6f421bc629edb34ea8d033524f419ac66a93 -size 226771 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or_IN.dat deleted file mode 100644 index cd3ddc5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/or_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:babe9ad9c09d6a932829dfba28b5d1db1005d9853cc5ab9e796ed44cf2f6c8b5 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os.dat deleted file mode 100644 index 0dc4f2f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d804716e39d9fd6605e95413b2f5cde1ea5c5e55a991769512150d389a40bfc4 -size 14821 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_GE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_GE.dat deleted file mode 100644 index d839ff5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_GE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0d80874cb8694da30d5d5e68d6eb2e313a2b35ff7ada897723fe32c13e2ae92 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_RU.dat deleted file mode 100644 index 7a3c2ed..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/os_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efa32c7c26718b2fd15df856ec3a3767cab8fa3869d613974c122c03a4a503e4 -size 695 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa.dat deleted file mode 100644 index 7364552..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39bf9cbb5f7bf218a0ffecce9c1f8f256d7fe3de9a67fc93e92ed54c5907a046 -size 4538 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa_US.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa_US.dat deleted file mode 100644 index 6d942c6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/osa_US.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a857e3370f2d54e769af3a8adb0065187e1e34cc43c4342a0c345eb9c25947e1 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa.dat deleted file mode 100644 index c81978e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a4c4eeff56a0510a9509a33b541e5f7bdc0ce39304b1f5640f2ce42a9e949541 -size 202684 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab.dat deleted file mode 100644 index e19316e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5417ee5b3a00e547466d64d31b770f0182f4029592ba9e54f4b581061e1b1941 -size 3789 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab_PK.dat deleted file mode 100644 index 5061d1d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Arab_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d528baecccfc0d97e8d83f0b7746f9225669be748c820e16f3fcd92eb1eb590d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru.dat deleted file mode 100644 index 1232293..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ecef0a9d9ae19a290082c06913de545048a99fd5dc46de3c8b6e865e56d3e61 -size 1276 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru_IN.dat deleted file mode 100644 index 7ad9987..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pa_Guru_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:929cfcef707523ae677d2dd9e6f0cb9a61a588554f94f339f2c07a8d6f679016 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap.dat deleted file mode 100644 index 741272e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13348a8347be3da5f850da6a8b42536128cb630aa58c6288fae24b8d1d6e5a14 -size 28121 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_AW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_AW.dat deleted file mode 100644 index 5b6cd22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_AW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d9486cd03e28c735fe468f15230c942df3c883d044d175949317c827fb55383 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_CW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_CW.dat deleted file mode 100644 index 4966c54..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pap_CW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:32efa009f8776eff69cf3f51af294c7dfba9861aa089168e0c4666e93b42a5a2 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm.dat deleted file mode 100644 index 412ced0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04fc80a0ecc0ecfa566781bdc3634c073bb526ab57c2765b7824ab2e4ee3f90b -size 161833 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm_NG.dat deleted file mode 100644 index b3a8546..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pcm_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:de0069dfc348b9511b1e5280b503d05c98d3dc32afcbbcef52a300652ea91b39 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis.dat deleted file mode 100644 index a8adc6c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6825cadfd632a18ab2f7bc0253689dc585cb2fd702ee6c8222225978a82afa9a -size 1510 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis_SB.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis_SB.dat deleted file mode 100644 index cfedd54..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pis_SB.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f820e45efffcefb73ffe8e7a6c17981c002ad97f4272729d23ae43884eb5fccd -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl.dat deleted file mode 100644 index e9efd87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd691cf670ff229ce88fe9eeca646e08b7560f7746ff0422706404e4da6348b5 -size 227506 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl_PL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl_PL.dat deleted file mode 100644 index acff3ef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pl_PL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:decd97a55c9a2a16bf2bd31eb17283eac64d1929f53d546dbb3f57629d71aec8 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg.dat deleted file mode 100644 index 6c31b4f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bec69defc8797640ad68bfc673e006997cb771ce8e7758f85823c605d5fa4edd -size 17267 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg_PL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg_PL.dat deleted file mode 100644 index 6bd6756..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/prg_PL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e634f661e7a4fdefcca464a19b2daffb45968734244345ac25095461f20e71f5 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps.dat deleted file mode 100644 index d865951..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d98bee9fb79195612487a3a6fd0c5d5b71eadc0c3262aa0cf27d38d7c56371b5 -size 158607 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_AF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_AF.dat deleted file mode 100644 index 56ca9b7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_AF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0d13a6e0c7f9d5d1558a6bc2277a551a15849adc5a71e9bc89c34293e01d68e -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_PK.dat deleted file mode 100644 index 6209c31..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ps_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:66dcd39c7dad85cebe2793dbb8c3aade53eee7b91ba831713b9decec149d5524 -size 7119 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt.dat deleted file mode 100644 index 0156921..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e836ff7bfb5018b268a7cd36a4c8fc69e34672e2b16bd88a4c265804d33872bb -size 183448 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_AO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_AO.dat deleted file mode 100644 index 2e30738..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_AO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e3d84c37d00904336372c430fa797e8d8fd52876a73b43c67ef77ef8ec6a3b12 -size 1022 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_BR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_BR.dat deleted file mode 100644 index 71bf5b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_BR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:755298a7d23044c6e367f79ef9e5c53ee752b9346b44ebdb1736377584d89a7d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CH.dat deleted file mode 100644 index 7478d4b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc0bc3d2c632b44aaec3363c6516d509ccbb0d2d99cd45e87e5e6a5ce8b1647e -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CV.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CV.dat deleted file mode 100644 index 4dff9e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_CV.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cce427f1defef8f2ab85152143998f296d4a9ba4f2879245f21b2d7f1a484f33 -size 1039 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GQ.dat deleted file mode 100644 index a818ca5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a88d61bedb921ce7afd768a9b3da37572efc349a4e3238645badb933ad25a995 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GW.dat deleted file mode 100644 index f34fcc1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_GW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:491c5b143220f45c048c68eeb5123d3f549e2e2641a92b704aa3ee1c1159c0b4 -size 1002 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_LU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_LU.dat deleted file mode 100644 index 829cc85..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_LU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cfd6aad014d6127938957bde3699a2f3d4ca71737fb7a51de00fc2f7bbb23aec -size 672 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MO.dat deleted file mode 100644 index a65e4b2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b2122d248203af1c257108562e19591b4ba1c939520437136a0e62bf199bf530 -size 1635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MZ.dat deleted file mode 100644 index 7d7820c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_MZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:519d679174bd0a9882335229386e57a462b642a339984e6502044b4c601697ee -size 1042 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_PT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_PT.dat deleted file mode 100644 index 372d4aa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_PT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fc7e431b9a4e49947fe608e3c9cacc04a68e25dfdebb02659f5a5adcc3ddd4c8 -size 96277 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_ST.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_ST.dat deleted file mode 100644 index 0a8ca3b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_ST.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0a6d87531946b596b3f085d7e4e866b3e1d8b8a81acee05c399073e6b58ecc45 -size 1022 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_TL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_TL.dat deleted file mode 100644 index 10011f4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/pt_TL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08820333f668d318aee205e783162d9182ba95d4cd64c45a8a4483fec02890cc -size 1002 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu.dat deleted file mode 100644 index 54fda63..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52e7946cd2e7c79670b2a25cbf32944dd2b9ff02813a647685a0a3d3385de114 -size 93300 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_BO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_BO.dat deleted file mode 100644 index 93466d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_BO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed152f36b9ae2edc2a3fea9a6faebb1a8707fdce2022fa5ab3775b375b9a1b15 -size 878 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_EC.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_EC.dat deleted file mode 100644 index 80c8971..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_EC.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ff9578458a0f6f7782000ee338235f07b599a9df6c58fd44d2d945f2619ea857 -size 837 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_PE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_PE.dat deleted file mode 100644 index f0dfab8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/qu_PE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:55d7747dc2b676d160cae8b743d344947b89f38d5123e4f9976507781abc310f -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc.dat deleted file mode 100644 index a8db12e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:74803193622e0d98564e3f8d282f4f8870593a71bd011c8035d25951fa15949c -size 775 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc_GT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc_GT.dat deleted file mode 100644 index dfea93a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/quc_GT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0cf0ab669ec2624c269ff8d9795f5ef83a6b7273a6b4ae2d3b932b030b7fb96 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj.dat deleted file mode 100644 index b4cc296..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa4bb246bb974d340b0e08a3480d04aae7f3d7d02a834a79320d2179a18a4f4d -size 2428 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj_IN.dat deleted file mode 100644 index 08bae08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/raj_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:492f063f326ee63ea77d7943a17e0d14f376412725e0cd1836cac5996925ca63 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg.dat deleted file mode 100644 index b2f6252..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7476a13168d0fed52c86d94b6aea9ff5be18dfa2cd2451ab301b159a307396a4 -size 4611 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg.dat deleted file mode 100644 index c37131d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c03aec02fbbb9a22e66dac85ef52462de98931a9a2a91ce99ad66d3e5d3b6b2 -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_BD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_BD.dat deleted file mode 100644 index b77a310..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_BD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0dc2d206d7ff93f7fa075d36faf6e104e8dfccd6638930ef1147483907d573c3 -size 1212 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_MM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_MM.dat deleted file mode 100644 index 0479fe9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rhg_Rohg_MM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1eca59cdbcad71943ce7726cb69f9e14476a48c003dfeb21823addc58fca42b1 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif.dat deleted file mode 100644 index ca1fbb2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0ab544f2e03f8eb0b7ed11a2075367f0d4d521c74a702575e27b9d632375f5d -size 49902 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif_MA.dat deleted file mode 100644 index 88b699c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rif_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:42aed97729ae3dd8c77980d40c60a332e401454ef0e6a19d833cd9eb03df376a -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm.dat deleted file mode 100644 index 6447e36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:690e0c9b086325b05a915ebe0beeb28c3bcdf23bd56bc324d28bdd62056447d9 -size 95006 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm_CH.dat deleted file mode 100644 index b5907b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rm_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:247025617303f5592ce37714fe07121109aaa3aa688163e5fd1e153142b68872 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn.dat deleted file mode 100644 index cf87357..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f0413cdb14834d788854e6a26c12787eadac5c0835d530603a64bf79694f541 -size 16241 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn_BI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn_BI.dat deleted file mode 100644 index ae354b6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rn_BI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af90b07a1ecbe040192bea93989ba5a16737de25de47820951b927ae5d170b78 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro.dat deleted file mode 100644 index 5e52836..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d7752947aea3fa7420e246e0187e236baca00ead64dc2084af290459e786f326 -size 200714 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_MD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_MD.dat deleted file mode 100644 index 6e2e907..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_MD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a54658f7bd33901481a553880374acfbabc325417764211660db38fcb5dca406 -size 2881 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_RO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_RO.dat deleted file mode 100644 index ebdf184..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ro_RO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:94b608616843526ab5119f685794844dab956bfe6e34de69e76756ed779e9919 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof.dat deleted file mode 100644 index c835ed6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:61a7e06b1e74dc21e31efadcfe78c34cc54e383d81dfab11bd6bc313df6078c2 -size 15473 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof_TZ.dat deleted file mode 100644 index c870a16..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rof_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23fab01a3aaaadcc1447fdd43727473a6fc48a22d9632455d2afacd6a7d24a2d -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/root.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/root.dat deleted file mode 100644 index 1804a51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/root.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bdc609ac38ba59589eafce37d95121750dd9647f29b405ecccd3fbe3b6888aad -size 51983 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru.dat deleted file mode 100644 index 1da8625..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f160ffeff4f3d2279a1235cd945432f311527c2c2c55ffc251ca07c857ea920b -size 305832 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_BY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_BY.dat deleted file mode 100644 index c7138f3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_BY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7d525ca1a0c5a77f2848e65b5719a264c9c58b55f277170771c919becabea43 -size 676 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KG.dat deleted file mode 100644 index adfe113..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fe8804f542e406864d6621eb691b25aa0e5c2206c90b7f0aab2ba6a7b755d2f -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KZ.dat deleted file mode 100644 index a046f92..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_KZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3f5fc69f77ac3b00cb2fcb1df2f5586c503c27b404b1a0c059f66f0ec9fe5b00 -size 656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_MD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_MD.dat deleted file mode 100644 index e0f76fa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_MD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d4d76a01c2becc7cf4f37ecf03c7bb946558078a7f326d7fe83c7acf2094e4c -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_RU.dat deleted file mode 100644 index cd974c8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2151b8e349978e9856ea20ac2b2b19096d467a6ff3e7f3b495923af91de81bf1 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_UA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_UA.dat deleted file mode 100644 index 702eb68..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ru_UA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5983c310e5231e5ee6b5e8ecdf4d8a01446afdc9039fa0858c7f88c2688517a8 -size 1210 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw.dat deleted file mode 100644 index d41c9fd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d4a881930e4dee18a873e112b34a2a81dc8e69574e96c369d62233ee0de4f371 -size 8418 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw_RW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw_RW.dat deleted file mode 100644 index 3bf1504..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rw_RW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b70fa0b731fae0f7880263467a86e0532a70ed10322884de1407103c6634306f -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk.dat deleted file mode 100644 index d65c94a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:842aa8e6094fd56a8526b106c96eabdede37359edb54700e185183914cde3376 -size 15369 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk_TZ.dat deleted file mode 100644 index db6e8bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/rwk_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3d76e6a2f0d4681f09fc62942b94c7775437fa8ed431c5c526bbd08820ccc2d -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa.dat deleted file mode 100644 index 160b5ee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f2be22657210def9c6c654a63ad0e1c0cf93fe2698378497b9349d1a1fb624c8 -size 15978 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa_IN.dat deleted file mode 100644 index 86f6e13..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sa_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00135a9a83e96116ceedb2ba0469b4b4af7691deecbbbfce3fb0e2d305b4cd9a -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah.dat deleted file mode 100644 index 137a912..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4256f71c4bf926c95f2c09148cb273fd77517722e196843db9ff6ad9bfceea33 -size 39310 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah_RU.dat deleted file mode 100644 index 7b8319d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sah_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c796c7a2c0c6ed37e22c113786d9db1a227e8e07692ab40a206b33279f47fad -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq.dat deleted file mode 100644 index f8893b7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82b8fce67a77b59cd74262ddb5841cbbbeb29d0bf926afff288c9a0c4085223d -size 15787 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq_KE.dat deleted file mode 100644 index 023ac5d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/saq_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:90df7870926df004f4c81443a943c6a09b4c65d39bd9efbcdcd36cabc86643ae -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat.dat deleted file mode 100644 index 1bd1ec7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2bf20a077992b0e918b980ed6c65b795b1a3564e1cb41e7a59690926f134fa62 -size 66131 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva.dat deleted file mode 100644 index 123a728..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d041d9e94731b1539f8b7f7dc506ce933687d4e5388e4675d2eaa69969caf152 -size 1943 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva_IN.dat deleted file mode 100644 index 77852a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Deva_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:07387d566ce26bff0a2c0af2b7d56a0a5f6d7abf6d2b19e0e1bf281586d82ba2 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck.dat deleted file mode 100644 index 560c841..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9accce99fe81dbd9856c4eaa37a328cba49f063c2c8da0ac6e4ef9749476e394 -size 905 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck_IN.dat deleted file mode 100644 index 77852a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sat_Olck_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:07387d566ce26bff0a2c0af2b7d56a0a5f6d7abf6d2b19e0e1bf281586d82ba2 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp.dat deleted file mode 100644 index a9c34ef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6a1f1a27f3f4e91869cb1d4073cb9711d660849d99b0d44b98cf740b8274fe7 -size 15609 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp_TZ.dat deleted file mode 100644 index d8cfcd3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sbp_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7215acd2d66788ee7749bb41aae4c7192e84e2fdfab6060bd9bdde9f11dc7425 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc.dat deleted file mode 100644 index 3623311..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:22d6a58cc30bc4e10ce03106ff20cd564f07e00990aead710a70c4f007d10c3b -size 189970 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc_IT.dat deleted file mode 100644 index bb97b67..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sc_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d06d2f2fd6176502e44e69f326ebb280ce6dcb64f0e6588383f6961cbbe0df69 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn.dat deleted file mode 100644 index a4ce385..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50a32a7a476dfedfd07bf79b860dde691b13b37ec40a958b1225920858cc4cb2 -size 70373 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn_IT.dat deleted file mode 100644 index 29b6117..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/scn_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7535d92070d185b1430b0d364f4c0bd62689da47d8d595337dbbd4b38fd628bb -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd.dat deleted file mode 100644 index 11e9ad2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54330896ea8da410a17002ef8ddda51a597ab112bab2b005ee9d82a201205e51 -size 154300 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab.dat deleted file mode 100644 index 2550555..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e091a6065213d7965d53ec24faf2b89d71c65a1111de65dc14cc6a00641529b -size 879 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab_PK.dat deleted file mode 100644 index dc20e5d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Arab_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73701775ab67ad33431d6fd23a1f1f34dc9ee0255ecbcd459e4497c23ecc99c2 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva.dat deleted file mode 100644 index c109715..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6596ad841ac6272a2ab293ec1c5efaf49f38cd0ab5cbadaf37c4408c68ff0a6b -size 13957 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva_IN.dat deleted file mode 100644 index d01c793..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sd_Deva_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d0a40510a1d5ea11e275ce61c6bc5012f84ef98caf15fe4fe73eadf613de9c7e -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh.dat deleted file mode 100644 index 057f75a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5c0fcbbcf2a6a7a42b40f243ef1c7f407408b6f876e1ce7391aa2b353d8c7a3 -size 1032 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IQ.dat deleted file mode 100644 index d593c96..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:07fbd430e886595703d47691e1993c5f157372630548849edaf46c7320359586 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IR.dat deleted file mode 100644 index 0a7a2c5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sdh_IR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8703264279dee355ff9728dbc8d6d0ab7e0ba6497dd5b020a1abcf651ba8cf05 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se.dat deleted file mode 100644 index 7eb2de6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:267379b376f53ab70feea9aeadbf116fd34a73e2023abfd199d16cd8404aa110 -size 54830 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_FI.dat deleted file mode 100644 index 62e306f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7f549d30cd814fb68d1817619ed2a89e155f7f0ce56aa989cf8e50b9c2702bf -size 44207 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_NO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_NO.dat deleted file mode 100644 index 93575b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_NO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9e6e6ed954379ded1250566d16ac2c45af0683ded79f5392c63a0fd88fa2fcf5 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_SE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_SE.dat deleted file mode 100644 index 8786493..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/se_SE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8cf4ec6d990018fe9f5f67fe8bf33aa8ea2fbe6e8fd7d3472f8530c46d7fd45 -size 694 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh.dat deleted file mode 100644 index faa6896..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be216e2be320e303e7bd372bbcbfa213336a15ced18bf54ffebf690baef748d1 -size 15433 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh_MZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh_MZ.dat deleted file mode 100644 index c8488bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/seh_MZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4aff780ee7aaaccdd1e518e109dc2b299b2735d2f55a98cb060e908419e8697d -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses.dat deleted file mode 100644 index e43322a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6915b8707ee718d4b94b70777dfee8d361aa708aa7d6655b0511a0dcd7715d47 -size 15812 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses_ML.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses_ML.dat deleted file mode 100644 index 77dea36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ses_ML.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cb5e2a1b03ffafa571cc98649582167d892896ed0e1c1fba9c9e2dbc5ec9fa25 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg.dat deleted file mode 100644 index 58b23b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:11197a77fc5df09467906fc3f39ee05a2db138dc88f9c126cedf949ff8576eee -size 16476 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg_CF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg_CF.dat deleted file mode 100644 index 591f9bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sg_CF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:402358aa8ff99764aff4950511617a60b0d1dcc927860932333d663b98f61aff -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi.dat deleted file mode 100644 index 1db7524..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ee62dbffc63826274f9a0108ae59c257658de6a5eabffe1cf8967a2e114c961 -size 21830 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn.dat deleted file mode 100644 index b481f2b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:690adfc3072f9203da58549ebfdfb75a0c105e18578f5ff99b2b91f9089f9cfa -size 15435 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn_MA.dat deleted file mode 100644 index a411f7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Latn_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fc730924be6d8b8dc0a5416cc7471c66880f0fd1cdfb0fb3fc95fe913b888d4 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng.dat deleted file mode 100644 index e377d44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:563b11e284a22bda057dd21da5a543c0d48806f15b43726f9badcadb86d1aa4d -size 974 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng_MA.dat deleted file mode 100644 index a411f7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shi_Tfng_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fc730924be6d8b8dc0a5416cc7471c66880f0fd1cdfb0fb3fc95fe913b888d4 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn.dat deleted file mode 100644 index 2119692..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b00459a07651dba4ab2752a599686010f986d33e6f545a424a327f48749ee93 -size 890 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_MM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_MM.dat deleted file mode 100644 index bd91a29..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_MM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed56ae57772655f009cfb900efa86c17715dc0cef90958ef1dd8f1ea50a81f83 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_TH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_TH.dat deleted file mode 100644 index d610263..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/shn_TH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4073e6af75781b34db6fa400e520e5d84b15cd0063a5b6833fa3877c96744b46 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si.dat deleted file mode 100644 index 96f8ab3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8aeabed2b6de732ce15f4a515f951876028aceb9f4f6990bb9c2aeaec5bf67de -size 216775 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si_LK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si_LK.dat deleted file mode 100644 index 9f2ea80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/si_LK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7160a057d5a69c4c0822c06686c215cd2cdbad5f219245da575c47d6e96d954c -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid.dat deleted file mode 100644 index b6f4ca5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf22b0bb3c39d41d04f2c5a0eb4a89de43b8af3a93b5c3414671f90f7666d665 -size 2176 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid_ET.dat deleted file mode 100644 index 679bf42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sid_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bedc32f41b9a6706f90375dd225fb79b0b35704015938b3ca0acbb8be1a733da -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk.dat deleted file mode 100644 index bbab1b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bbf4e7b86e3ecef2f193142ea5d36f3d2f93622dbcc5e88fc4b8addbc871c193 -size 218242 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk_SK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk_SK.dat deleted file mode 100644 index f62c4b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sk_SK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78c8cfab5f2640e017be424de5657a94a1003f2b7bf9e95e1a67b6a471debe00 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr.dat deleted file mode 100644 index 64749ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:32bc796c44f7921e46cddf3ed89f519b8fdbff03d94c3a07ba1731a9d623e610 -size 1702 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr_PK.dat deleted file mode 100644 index e47cecc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/skr_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:509a4b32624920ce63788fad5d63c1357e10777592da74f0a776ef260e43dd66 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl.dat deleted file mode 100644 index bea4b6d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:784254f1dbbe5b00a40af8859aeb14a87f07eac325d8f1c6fe4852ba6501ddca -size 210137 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl_SI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl_SI.dat deleted file mode 100644 index d5b0567..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sl_SI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc7936b7e3147c052daaefc6cb4fdf4e33a1c0152dc5d9e7750ecaa30834a9e9 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma.dat deleted file mode 100644 index 80c563d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:05a0556e1b043cdf55e091ad32dd93a4c75fd2822b2fc31ac6dd855c320412cb -size 944 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_NO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_NO.dat deleted file mode 100644 index fba29cb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_NO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39e209f8426dbd61facf6759d47bfc41d9900bb33baf9d6dfbf0ba2c3e99cb11 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_SE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_SE.dat deleted file mode 100644 index 0442f08..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sma_SE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:33fcd896501477651a5af71c67a4a107df8677c258cc81259fef3c436decc9a5 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj.dat deleted file mode 100644 index d2eba86..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b21d1e4066a6f1c654d8872c497ef4e3a73fefeb37e1dd3ac3b5c0e40a04e28 -size 939 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_NO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_NO.dat deleted file mode 100644 index 4846dae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_NO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5fcfe615244a17b30bc2f917457095a6b7e10c19c35703773d8ffa5f9b1a820 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_SE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_SE.dat deleted file mode 100644 index 7e68cc2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smj_SE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee5ef714465c01e98ec174ab7cf0775fb6b472da37278a0cec03bd8bd3cc2015 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn.dat deleted file mode 100644 index 720e191..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c69326a27eab76e0bd0d784c42b73860f2b2842a791f24d10ab6debb07e5621 -size 40399 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn_FI.dat deleted file mode 100644 index 7cc6703..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/smn_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:55163775b0b2c449835137a9f5b4170d195d779c12838b24a90a73b67317a659 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms.dat deleted file mode 100644 index 12e290f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ca501361badfbbc49511575045b0bb75348e2823525fb3b58234b6c095c0d6d5 -size 6521 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms_FI.dat deleted file mode 100644 index 79abd95..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sms_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fe324db4942df6c72b2a539bfa8c68c35180d968c0efa0cc1639935d4f9cae0 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn.dat deleted file mode 100644 index 9008d02..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:14d4c70eca416153d8ecdb1ed61684735f4ed127f76edb2a356405b366737207 -size 16732 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn_ZW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn_ZW.dat deleted file mode 100644 index f6bd08f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sn_ZW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f079c7dab6871e5f0f236e5a6ce0e54e11218c83865c96ffbbb73241de58cd9c -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so.dat deleted file mode 100644 index e4be169..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0016480c83ea9a6588474ff972a1a82067c50cfca5f5c5b4b89a207797928df -size 166227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_DJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_DJ.dat deleted file mode 100644 index 3068743..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_DJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5569da8ff32e5b87499e53bce2deb4c920af7c92fb1572389c83fd3d32f9026a -size 656 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_ET.dat deleted file mode 100644 index bdb0de9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12f451a94e3240f31886410af1ae0c47cd3c7f0287996ec4bcfbc425d8e5b671 -size 655 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_KE.dat deleted file mode 100644 index 2825404..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:392891820459ec24cd9aa8863af5b55b60b0d91aa354449354e7547e05605b25 -size 1208 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_SO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_SO.dat deleted file mode 100644 index 8ff8e78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/so_SO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d883db3aa4b140607916e910f81f8c1267bd147627db60a55e6015e31d3ca4d1 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq.dat deleted file mode 100644 index 10bb2f1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f254de8f2026fbde22c694ba0e5cbb35048736c6a67eda8b21d3b83b13d6aa89 -size 160229 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_AL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_AL.dat deleted file mode 100644 index fc0e17e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_AL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30dd91be42861b63d78c246c307b2f727c2720e3a9f6d352a5c227876b8259a2 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_MK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_MK.dat deleted file mode 100644 index 4d67de4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_MK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2ff19a649f57b9032cd33c3ec5996b79f3c5dfa487d2c26a32b7430dbc227193 -size 1208 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_XK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_XK.dat deleted file mode 100644 index 53ec2e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sq_XK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a882d9191c0086e20127dc62fd3e564ebad9015a2e163412bf26ebc205d3b288 -size 1187 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr.dat deleted file mode 100644 index 5a547ae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0001372cdfc22d15b396310444861e7597a9c4b2035b310d90be309aef086fa7 -size 265725 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl.dat deleted file mode 100644 index a292709..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4dba3dd02c8101672229e0deb0f8665dfeec74141f8d6b26cb2aca05ca3f3735 -size 1990 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_BA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_BA.dat deleted file mode 100644 index cef11ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_BA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0a11c057f46f4ec02988644a53a614325bf2cce31a0319ef74b3fe3bd3f009b -size 41992 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_ME.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_ME.dat deleted file mode 100644 index e6dc415..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_ME.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac364e7fecf290dd79d6d7e01a23b54942620a5cd0eade34805f76edb30b9f52 -size 2320 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_RS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_RS.dat deleted file mode 100644 index 3cf85ab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_RS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4e7f6ed44bc901964421d8179688b7dbaaa3a6af1bd4dd3cee7450f51d496d61 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_XK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_XK.dat deleted file mode 100644 index 9d30e66..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Cyrl_XK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a957af4c82d89ee6888d1c8fcb8ac34dabd583e557c4a719e5f55d87973e6874 -size 1574 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn.dat deleted file mode 100644 index efcc3d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d63a0a5d846fe548a24f6d6cfd96baa84f9503c5e9162d47cd89d53a32a9c5bf -size 217950 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_BA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_BA.dat deleted file mode 100644 index 459a146..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_BA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a1fe30a5e0a09552bf4dde879c75231d1c2e16d095b568f79076f79e5e01d03f -size 32834 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_ME.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_ME.dat deleted file mode 100644 index eb39e55..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_ME.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:32bd063552c520c66905a91de1d114cc952500de27c97d81300ab2760b4ccd6a -size 2089 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_RS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_RS.dat deleted file mode 100644 index 3cf85ab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_RS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4e7f6ed44bc901964421d8179688b7dbaaa3a6af1bd4dd3cee7450f51d496d61 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_XK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_XK.dat deleted file mode 100644 index 8501f06..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sr_Latn_XK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c08cfb5d742b445629ccca51fdc8125a290f588d1e852c796b4811060b77ac5a -size 1486 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss.dat deleted file mode 100644 index 096566e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:500074a7750c0e7f0a7c1637d9aec75565d6a4794f6b6e8daff5a869a8767375 -size 2178 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_SZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_SZ.dat deleted file mode 100644 index d069475..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_SZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fe55ad6e56bb0f6b5657e61c2143e304e90fdba2f51bdb85d7152f1443cee54 -size 1208 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_ZA.dat deleted file mode 100644 index 30effbd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ss_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c704f7bd9e2d98a12f26957014c57d5368f614b175b42f4f10337a302e906dfe -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy.dat deleted file mode 100644 index e4b6cfc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4320562e11ffb2b7851011cc43b6a2a81b2b1af0de407c9800a8a8aa4b1ada25 -size 2999 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy_ER.dat deleted file mode 100644 index c98db3c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ssy_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f42448695c6038c78c4dcd2d715d18cfdc99ceafee0f7837ca5673a95a58cec3 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st.dat deleted file mode 100644 index 62fb224..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fe8e22b4dcbffd17842a596f2a9912775199ed64323d78c260951868dcc37b7 -size 8016 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_LS.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_LS.dat deleted file mode 100644 index 4ec41cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_LS.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a52cdd366ebe3b957afb5e1572017688635840f1582174256374aa516dc67230 -size 1227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_ZA.dat deleted file mode 100644 index 501c695..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/st_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e6d7545fb7715c42f6c624bfd08bc7bea84a17e8165c5b22e2cba990fd110c07 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su.dat deleted file mode 100644 index 4f4ecb2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1bae84ba8b8842b0b180a196f49ccf7cc67de0d00df3b3fa444c942f2cab146c -size 11817 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn.dat deleted file mode 100644 index 5af1a97..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:89ebf3abf9bb783e696562e75651fba0c21d79a75ff0620ca84b953c94c18f23 -size 745 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn_ID.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn_ID.dat deleted file mode 100644 index 6e6add4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/su_Latn_ID.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b135aba40e90fff86fbfe11ecfd6ee70e1d87e4e844f37f628f90a42d5c1515 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv.dat deleted file mode 100644 index 40e146e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:453bd0da58bd70a1c811b565edf23c10d56b99c09ad601119374bd3b66c72a60 -size 198967 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_AX.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_AX.dat deleted file mode 100644 index e6ec78f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_AX.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4051b321ef540abe600a9807ba7bdd3e267ed76eaf3fb1983912fd8e38a9f7e1 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_FI.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_FI.dat deleted file mode 100644 index 3394ac3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_FI.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3e7dc40e1f950f4409156ba9119eb0e13a806be582e4667ca13038a2a2dacef7 -size 2526 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_SE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_SE.dat deleted file mode 100644 index a22f5ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sv_SE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73d3c6e69db2ff8ae7c5ea460f8b8ecde98153710e42140d3b806d512d66deb1 -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw.dat deleted file mode 100644 index 39c35e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c34b97d0c07efdb65058e9db7720d5835b9155ed63f8af9e823444c6866913c5 -size 145419 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_CD.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_CD.dat deleted file mode 100644 index 4c731aa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_CD.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5bb170f16ab0a37ff1e215a5b2c9966d54e3e2185242646ff1cf954a741d960f -size 2577 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_KE.dat deleted file mode 100644 index 0e967e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:60c35649327cab1a347752af43000de44091699f4b19cd010df5f87a78205657 -size 47036 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_TZ.dat deleted file mode 100644 index cbad428..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2356c36e9103891d63902809fd6f5f5823ee3f13218d09b01b7b08b9e29bf919 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_UG.dat deleted file mode 100644 index 84b9899..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/sw_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:92e35d83637f74bc142859bbc1285e2f5c0b39dcabba43f12df0f0d0f37bb53f -size 660 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr.dat deleted file mode 100644 index 3e2a4f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7a112a136ac0379ff95fee33a16cacfa853089a8d1461c241b1fb277e90be10e -size 111439 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_IQ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_IQ.dat deleted file mode 100644 index 5239079..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_IQ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:32bc3adde270874bd17b72e98f4bd17fa43871465725cc7db655a4b8098caecb -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_SY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_SY.dat deleted file mode 100644 index c95de5c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/syr_SY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:974625d943239bfee4bb3be81b6f8aa81a795d1f3c81d8dfd5996945134532e7 -size 679 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl.dat deleted file mode 100644 index ddbe308..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0fa464976ba112eb2c570f660e0631b5e9be815bd8c3668f3a44a074302367f -size 88759 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl_PL.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl_PL.dat deleted file mode 100644 index be2985a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/szl_PL.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d43e5d29a1b69761dac5d7bcbab696236279973c35748586789b417acb9af883 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta.dat deleted file mode 100644 index 7356dbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:45122bc6167da5da464a122b431ed940138f2969f5e4e1a478bf3240ecbeb73f -size 277264 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_IN.dat deleted file mode 100644 index 14d5300..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04e15a0c1c3b7dcec2eb149215835f9210a009477bc9d1e9ac9eaed036a77921 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_LK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_LK.dat deleted file mode 100644 index c2e5682..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_LK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39dea59f9a149d67da007c2dfd20da7d6bfce3873b03bffb7d34f638f553bb2c -size 1208 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_MY.dat deleted file mode 100644 index 0d99cb9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c45268e1b3f454af5479907f6e1c4c5d9c6e7d1f2f0b99b535f2f5d96183ed0 -size 1325 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_SG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_SG.dat deleted file mode 100644 index 28d138f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ta_SG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5bb9e7d34a25cf330a5e574f39429e77979b831cbb0c3179adf133c41b67d66 -size 1344 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te.dat deleted file mode 100644 index 19729f5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a114d096fe5d21961abf66905a28ef736c26d15c284754f05943cbfea87392e5 -size 261668 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te_IN.dat deleted file mode 100644 index 7938886..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/te_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c80a75d4f83d2e86fc55a50f7ce9497525e01092d5da5f9dec5d94946372f68 -size 658 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo.dat deleted file mode 100644 index d95a660..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c9fb6eba030ff34de263c068ff5404aace6e98dc271062454f5cab95fe4cd3f -size 16012 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_KE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_KE.dat deleted file mode 100644 index b76b315..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_KE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4bf940837e95900d70dfce24ccf7d744b98998659f9b3de597b33339002d72bf -size 657 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_UG.dat deleted file mode 100644 index 1b517f9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/teo_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d169438259ace5b09ed403300aaae8697a4e5eef6342ba319653305d62dbf2ad -size 640 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg.dat deleted file mode 100644 index a64c36d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12b32fd18e121a7a3d8134896e13152995e249efca3525056a805e20368ff2d9 -size 117163 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg_TJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg_TJ.dat deleted file mode 100644 index 21c5b9b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tg_TJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c2aec122a46a74ade012da602fc13e7cb72cc19d825f2f9a0d1d6a447b5b6d7 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th.dat deleted file mode 100644 index 7a40b1f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9721bf977fd0cdfa678c2bfc2d56914efa6f7c89a456ba9c0e850aae75e5211e -size 215576 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th_TH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th_TH.dat deleted file mode 100644 index 44e6b7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/th_TH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd0840d16707996e82afffa053d7ba71da734cc0d3d7d5b21dab39f1f5835277 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti.dat deleted file mode 100644 index 0cef333..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2b8912e3be984289f24227e32e94b852413b84d6b69396880c125121d8767838 -size 214273 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ER.dat deleted file mode 100644 index 29e3b78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9bdc343f94cf43c22aa562a577075f9f0e7fd54a6fd3d0232dd3b95946dc4627 -size 962 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ET.dat deleted file mode 100644 index 404e923..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ti_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ab46fdb2f3e0f1a8fdc666d7afb17a7cf1ea793266725065e6dfe1a9093b22e5 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig.dat deleted file mode 100644 index a82e881..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:720ab1cb7c227a13fcc9c7aa6b9fa6ac9553db720ffdb8e591e50e12fc6ca543 -size 13481 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig_ER.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig_ER.dat deleted file mode 100644 index ce4a541..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tig_ER.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a843453acb2ce68cac03b732d4a6a474f61fd9686bf35e5a7bb7e1ea3719a6e -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk.dat deleted file mode 100644 index f885fcc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf98b892c8536ac0c4a2590da6a5e7ce5661ef91206c084bd32953d3fd288a8a -size 164932 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk_TM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk_TM.dat deleted file mode 100644 index 26af175..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tk_TM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9400f1110a33fbf2260c19a908552a0cfb99d28cd552164a390176670c97565c -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn.dat deleted file mode 100644 index 1d4db0c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e0a1981c5024b8b7f46cc9040a895b09eca6ecec7a089d900c9dd464e835023 -size 8596 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_BW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_BW.dat deleted file mode 100644 index a10dd1e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_BW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d63053f5b70fa8eebb251c09402208c45df964a3c5020cd692b90f1c72f3472 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_ZA.dat deleted file mode 100644 index 0c88791..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tn_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b774c3ac612a41c2452fd2d5bdab490a6b041097acb1efb2dec402f9c10a835 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to.dat deleted file mode 100644 index f36af97..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:081afa81182ed2aa3ffa42283a5b8fc2efd9747e3e48f3c91eda3f111703cc70 -size 145255 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to_TO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to_TO.dat deleted file mode 100644 index 41f1264..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/to_TO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8dc7c9d8f8e87fc8c6138ab5cb92c748ff6b6f821a9cde7c911ece806f1de50d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok.dat deleted file mode 100644 index f0cac2c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:92e48f815867bfc46be791be7a940357287c15f78ac496ddd89d2189eac97544 -size 8870 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok_001.dat deleted file mode 100644 index 61a3603..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tok_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3cf50c7af4f64c1386152abe53e01c71890b1d26e45a70510efc6da68913083e -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi.dat deleted file mode 100644 index 2d71764..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9aa4c02707803b2d52007da5e262402a4b57f9978076f4c2f099c13f15e30740 -size 4030 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi_PG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi_PG.dat deleted file mode 100644 index f1deea2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tpi_PG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b990ff73cc82b62630b7610ed953983f38524ea58c401389302b8c0977b70acb -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr.dat deleted file mode 100644 index a772d53..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50b6e33af990a9c4f5676ffc6c139eecbcf0801520dcb58cd8c88b9266fc33ac -size 150824 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_CY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_CY.dat deleted file mode 100644 index 78f529c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_CY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc4982ab170fbc5b997070b3a539876faa63b4fc2a42fc027e7dbb07caed5cdc -size 1227 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_TR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_TR.dat deleted file mode 100644 index 54b88e9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tr_TR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee54b908c670efa49594c271b262095b921f2fb93db7c32b7ca727125a884922 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv.dat deleted file mode 100644 index 4d88e15..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8846c5b42084fd4e6b9a302fd0f7b927f522822c4c2aad5c3c84e1759ba2d4b8 -size 9404 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv_TW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv_TW.dat deleted file mode 100644 index 5adceae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trv_TW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09342d19d0d6e19d27d8291be81eb71e0130344e386131672427adc1df2af465 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw.dat deleted file mode 100644 index debc800..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5ed4b182b55abbf5172510c25b81113801376a7e557f2831f107022749f00a7 -size 110107 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw_PK.dat deleted file mode 100644 index 131315c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/trw_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a411dd3ae96bc112e242e0bdea0f22954ce9281786ea482506a51707c3255110 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts.dat deleted file mode 100644 index cc0699a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7b1053ee70af4791355778d293534d2cf8e6ace54fc708f197f61a93d79a7d2 -size 5522 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts_ZA.dat deleted file mode 100644 index 007f7c8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ts_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:001c843b9e56dc3555381201c48a75176430634d7ee6feaff2c0c53864b1085d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt.dat deleted file mode 100644 index a4f34eb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fe27404a107cb4d5aa00470c1bd12583b8d9b595916b4f46a42abcc16631cf3 -size 111014 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt_RU.dat deleted file mode 100644 index 8b2ef7c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tt_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:726bf6333a2528eaec468a90705646717423ff7ddd2d61a1f685239de6c29f3d -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq.dat deleted file mode 100644 index c57d161..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9ce48de54640c5c0a0753c50161d780b29392b7f28942c80b93e8cad55b93de1 -size 15509 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq_NE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq_NE.dat deleted file mode 100644 index d2ecd36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/twq_NE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cbcc500f132dc92b560bcded9bf2627a4171018d058fe09659d9a273d181c1de -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv.dat deleted file mode 100644 index 0bf7fe2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cbdd3f087ed892c7752ae73a2a1ca486991d1952d48050d5f81e284b11aa9f91 -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv_RU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv_RU.dat deleted file mode 100644 index a5ae442..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tyv_RU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcfffa72330b07c23c60becdaabab81aefc058616e00d6d949d05cece467fc80 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm.dat deleted file mode 100644 index e29e3c2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1814edaf5f7f1b86dd6701d71503b771295321fb7c82e6c22d82015a5e4281a -size 15436 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm_MA.dat deleted file mode 100644 index 6691002..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/tzm_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f1e92effbbe802a02337ae75558282b885af75818e49c0b2a9bb75aed4953bf8 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug.dat deleted file mode 100644 index 3a8222c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d1249c5144ab989638fa91889c221c5693cc92ce9313f4039e3da064dc43bde -size 117801 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug_CN.dat deleted file mode 100644 index 54bd5e0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ug_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d94b1e954d7f77a2bb360423d040e70df6f82e5939d5e419ef3efca1813e6308 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk.dat deleted file mode 100644 index 79ee78c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fc88486f2dd431abbaed96aa71d5cf6fa7afa7de33463c64ae0563616409c50 -size 339125 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk_UA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk_UA.dat deleted file mode 100644 index 0a81cf8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uk_UA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bac270fc9e14bbd383f67ad4c4d400c7abcc2415838db1ae73d97bb2c240caec -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur.dat deleted file mode 100644 index 02c1b63..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4532fce544560cc0376a56d940e0d409b55303da317985e8e645adb8bd575ba8 -size 167002 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_IN.dat deleted file mode 100644 index 17184d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f4657d6086bb31fb6ad783e8d82e9f8cc1b9b16914f09e4b4b96ead6221cb078 -size 10550 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_PK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_PK.dat deleted file mode 100644 index 76ce8f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ur_PK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:10400697a7cb775f9aed7d27d8fc11c65ab0619d1ad042e6d83b8b208f6ca57d -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz.dat deleted file mode 100644 index c8bf626..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b08f7ba4c5be052b4ad962d0bae9fb50993b6bd52813cf2d765aedca910610a -size 138052 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab.dat deleted file mode 100644 index ef00109..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c2df01c22992366a05ceb9ddb860d730786a8f707cf97aaa37a8218365e6ef80 -size 3814 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab_AF.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab_AF.dat deleted file mode 100644 index 6729174..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Arab_AF.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ebc794091f0a781d100d0442bcd322388919551a3318a1530de767ad02f55ff6 -size 678 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl.dat deleted file mode 100644 index afa7cb3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4699b25b66214f037fa3ab0ac9f271724b4523a54caa43ba603cc313c5e83931 -size 76581 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl_UZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl_UZ.dat deleted file mode 100644 index e9f698b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Cyrl_UZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31626d1cf763fe917687a69b44fe305300d6014178fb3afb8c19f6450719d33f -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn.dat deleted file mode 100644 index 79813e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f91fb5dfcf61e8faf32abe244f0b86a2d0c9eaa05f4221e6e2abb9ae212bd20 -size 1292 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn_UZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn_UZ.dat deleted file mode 100644 index e9f698b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/uz_Latn_UZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31626d1cf763fe917687a69b44fe305300d6014178fb3afb8c19f6450719d33f -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai.dat deleted file mode 100644 index 2bd3d2f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ff31694301f6e9f6a81e02b15df323c33dbc93854d79905bb5f504d0a809421 -size 17416 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn.dat deleted file mode 100644 index ffc05bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31e709609ba6566ef00b20a8f98780638780a27e5667866a474b214373dda6ef -size 14255 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn_LR.dat deleted file mode 100644 index e7bc33c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Latn_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2dd5660402fb9f30e9f806ffb8789d0408b672b21ff675e17fcb4135f6bbc5d2 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii.dat deleted file mode 100644 index fdbfc63..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:97f2170bbeb3cc9da53cb7d67e35b34b0eb156d170afec7c2e87dc1d0b121bfd -size 693 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii_LR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii_LR.dat deleted file mode 100644 index e7bc33c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vai_Vaii_LR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2dd5660402fb9f30e9f806ffb8789d0408b672b21ff675e17fcb4135f6bbc5d2 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve.dat deleted file mode 100644 index f31190f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5b227422a1791e3d20db05ead0a9fe2c60f4e207dfb3a4ab83a240975f978d0 -size 2372 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve_ZA.dat deleted file mode 100644 index 1cc58f3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/ve_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b899dd1e2f5130ab4359de7c7ff4378395a05e32f75bb28b423f75ad5b9e69b4 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec.dat deleted file mode 100644 index ec089c3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce890b7ec8132bb7123f829a495f043293e51e23a423ab46deb58cee8eef7003 -size 160413 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec_IT.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec_IT.dat deleted file mode 100644 index 5a70b33..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vec_IT.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:982f6345f93d9dd9a4a51229599342c1d330bf1bc1e905faffd1da9dac1d694c -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi.dat deleted file mode 100644 index 6437bb0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:17de5af9fbcb3c8789a8e970c7882bf539d667456948fcb337027444f735a84f -size 134138 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi_VN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi_VN.dat deleted file mode 100644 index 2ee5b90..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vi_VN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:706c0dd2fc3ea8869e03683cf54f7b375c4748c9a668854d3c22cbd8ffd024c9 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw.dat deleted file mode 100644 index 3103b90..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9a111188633eef7d97f4a3b40938461328c5b526eab93d7fae6cd83e7aeed923 -size 1796 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw_MZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw_MZ.dat deleted file mode 100644 index f069635..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vmw_MZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b33d23e51b9f37da00cd36a572358d84ab42a045f3791af90afeaa0a8b8ae391 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo.dat deleted file mode 100644 index 6575af1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1eaf0636e6ec2899471ff6ad5dc90f11c20836682a0ba7bf1753305e4b0d0b6 -size 4609 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo_001.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo_001.dat deleted file mode 100644 index 346f80a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vo_001.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:885db163d5c87710b498e604a7d863619a76106fac8bf61a3585eb8bfeb4fb8c -size 850 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun.dat deleted file mode 100644 index 70f60e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54634f967a118a99e870660f81e6f7f5df4c984e9f7b99d3316b429389b50046 -size 15373 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun_TZ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun_TZ.dat deleted file mode 100644 index d889d87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/vun_TZ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:60aace78e4b556753705643b1d6b718d2fa030a25c2803d02dfe074e09337fbd -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa.dat deleted file mode 100644 index 01a3b61..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6bea4ac0a48f2879c20a42dffd4736e9c123742dc5928e51b7e18f517e1d3b6 -size 880 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa_BE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa_BE.dat deleted file mode 100644 index fc2cdfc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wa_BE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f86000d0968a34ece7a4d63dda3ab2d893370592b5624b551d46b034679ebea -size 653 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae.dat deleted file mode 100644 index 60aaead..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a81292b45aa9900aee54381e649bd7e94d17fa1abf3641134ea811d9eec0e144 -size 29641 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae_CH.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae_CH.dat deleted file mode 100644 index 572c3d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wae_CH.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6745b3bb943d2154e72c6c16bb9e28cd5c7e7e09c5cf4204df2ae4cbc6352244 -size 654 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal.dat deleted file mode 100644 index a09a038..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:003f597dd34d8c4857da7f53d3291dfd7c046d72bec319ac2eaab7f4ee018d65 -size 8406 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal_ET.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal_ET.dat deleted file mode 100644 index 43d18d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wal_ET.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b4d8deb94e063d35ad0e6b2ba069a2e1552a974740e7bbf5b44b43178aec9558 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp.dat deleted file mode 100644 index 0686b39..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9335cad387f9dfc9fe3eb265ea744a21a60732277aac9e000a6ccf702cfb3605 -size 746 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp_AU.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp_AU.dat deleted file mode 100644 index d18cc93..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wbp_AU.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:053d84d7e5a2a26b91aed782ccdd7f01f2f20d47443a6d1e853e6688089ea414 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo.dat deleted file mode 100644 index 67d9d81..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:881f3a4a84ccae7a61887cbfa26d58c6cf89f0be581566256e68908caea37369 -size 61849 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo_SN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo_SN.dat deleted file mode 100644 index 1f152d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/wo_SN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ef9707be2265acd387ecc528d3b177fc20fc44222122e39057f31868042ff28 -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh.dat deleted file mode 100644 index 1d1ff1d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c51cb4f7930efdbae0014a0307750ac21803bce9019612777168fd74cd9fbc72 -size 64334 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh_ZA.dat deleted file mode 100644 index e643da1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xh_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f69eb01d6d6cc4e82124c020b0fe810b745d521baf2e91e80a4aaf8ec0a63e9b -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr.dat deleted file mode 100644 index 598d61c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3add74ce2e05e07e58ab1ea420918f6b2eb9466f866a6d9e27b9003a0a09a09d -size 142585 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr_IN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr_IN.dat deleted file mode 100644 index 4567bb1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xnr_IN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51b370b9d08d8a1105559bb7ca66a70e1279d98a2ea46d120c6c260c1c8f8734 -size 659 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog.dat deleted file mode 100644 index d9b4770..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:578537ea26cf0960e850c7f7d7ea3d9830b0ca5b185349d9131e69b7e31679c3 -size 15866 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog_UG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog_UG.dat deleted file mode 100644 index cf4625a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/xog_UG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6cc5f44e4e734b83f62ea94e2cba553f89d9c411614bfa9cfa77578e294308d2 -size 640 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav.dat deleted file mode 100644 index d153015..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52ea6014598f55c57e22063715df18f46a0e70e5a06353f6d991ee03ee1048c5 -size 14543 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav_CM.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav_CM.dat deleted file mode 100644 index f84ead9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yav_CM.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0ac68ac1ea7908045eb72057f895c716f515b057b52933783f2cf55a1ecd4c7c -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi.dat deleted file mode 100644 index 27ced31..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:396af6cdbde4feda049a449770fc1ea84d774ebe5186f94c9b8cf7e7cb824226 -size 24264 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi_UA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi_UA.dat deleted file mode 100644 index 2fd0fd5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yi_UA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0deb235874eec4406b8ce7aaf1cf81f368f81e7c2ed04951d881f77d93e6abe0 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo.dat deleted file mode 100644 index f0aa6c3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8962e0fb4f0593d4092d93eea2481b09e5e4c9fc9035aa2fe754d3de2d692a06 -size 110427 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_BJ.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_BJ.dat deleted file mode 100644 index d45d92f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_BJ.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08fe01e4df1c128b8c2ad87e8824d304437be1d1297726504c96eb6d86b2645b -size 50036 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_NG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_NG.dat deleted file mode 100644 index 5a82b47..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yo_NG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04422774888c4f5328d7c4b90c05a98de7ed869b425509083de56cd2e992a29d -size 616 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl.dat deleted file mode 100644 index 1434548..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:da7c03bb0e50fdd2f81f63b19790a5cd9536530d748fe9283f94607e727aef2d -size 186854 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_BR.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_BR.dat deleted file mode 100644 index f89dd25..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_BR.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:69480b08dc2010e464db0b6e7b3f00aa461a841f3f997e352164aaa20b77f581 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_CO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_CO.dat deleted file mode 100644 index a853530..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_CO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a53d2b9650ca1d901420afe2b6b9163fb8ab9a28788a6d77d5499eff02b3ca4b -size 9211 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_VE.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_VE.dat deleted file mode 100644 index 90c639d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yrl_VE.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd3aaefe9194933adde0cf52297a67e20f77cfb439c6550c02d1af44e4b9c7a3 -size 9211 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue.dat deleted file mode 100644 index 9715b5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96f4daa075d25591ea71be54091f0878389544213d211b2b0e486fd1b1b0cc28 -size 143872 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans.dat deleted file mode 100644 index 19b0c46..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9b4ccf0b53e1fe42e9e1aa72e6090f5b13acddb183093c776587f841bf70169 -size 145194 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans_CN.dat deleted file mode 100644 index 32d0a5c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hans_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30e667bb9af4c6891febbdabc005df8331b75447937cd9436eedfa7d1d5b07a2 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant.dat deleted file mode 100644 index a2f44f5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efac1e7ee86c1888e4d234f4e4a493114fe96dbec07cd136bb9ea3751a096833 -size 1306 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_CN.dat deleted file mode 100644 index 32d0a5c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30e667bb9af4c6891febbdabc005df8331b75447937cd9436eedfa7d1d5b07a2 -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_HK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_HK.dat deleted file mode 100644 index 40785d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/yue_Hant_HK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78c67b98e4c4c8acd0cf4303223bcffd9e7b092f671483f8f947f4269c75098e -size 636 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za.dat deleted file mode 100644 index af9b2f3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e446c0984faaaafb7f7b881e685c411898bcd425686452b8742709df8e8fe325 -size 12705 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za_CN.dat deleted file mode 100644 index a363fe5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/za_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5b38676ae82148cd42d6dc2e298055ade94b11eafe82ecd3e376bdc813570ac8 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh.dat deleted file mode 100644 index 87e4e1b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4360fd2901600df5a4e1f5ce7446cf70bab7c97ff3c638652bf3d523ad4e9385 -size 22018 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh_MA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh_MA.dat deleted file mode 100644 index cf23f9d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zgh_MA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b15f1a3c1987636de5288cec4676beb4fcf75225e8282310d54af6b42cb1d980 -size 617 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh.dat deleted file mode 100644 index 9bc2142..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a94a499d54de4f5fb08276ca3507e4b241928c0d3c997d9793da5fe48f61682 -size 152100 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans.dat deleted file mode 100644 index 4286062..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb047ae1beb9b2d8c0d8a5a3e0659c056885df2234036e29e0aef00298fcaad7 -size 1305 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_CN.dat deleted file mode 100644 index 26c6d26..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf3daa3e95843fd6dad764fd706b0f5c623b060e4b72667736400c8954dfeb50 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_HK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_HK.dat deleted file mode 100644 index fdcce00..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_HK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c8fc99c94fb15d23725351582486295b09e1d1ddee5ceadaf55f5a8f68ff6105 -size 3621 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MO.dat deleted file mode 100644 index e8b5f8c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3c9145f01ce5c0d29440f2a217edee29d0dce5d571d2063c21321edffa76411 -size 3752 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MY.dat deleted file mode 100644 index 19bf143..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8841719765c49b5cc1cddd4ad305e989916f53b97452b354461da9f4365d44b5 -size 1300 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_SG.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_SG.dat deleted file mode 100644 index ee949bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hans_SG.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:38764d8947e7b5e497bb37a5fa564031582fe7c8a25533618eaf354fd42ef78b -size 3948 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant.dat deleted file mode 100644 index 99ee342..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df56911add7c6e5e8c76223d880a33c25b5d912410dfbd13bf323c82277c0812 -size 154802 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_HK.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_HK.dat deleted file mode 100644 index 7342625..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_HK.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3573c213fe296202dab6878a2dd43477c3d0f8c93f19e305d6cd49617f66dbb3 -size 49152 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MO.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MO.dat deleted file mode 100644 index d5b2a81..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MO.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a8258f3c4afced4d5a7a6688b9fea709843e437c3fd47717ad8a277185417778 -size 657 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MY.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MY.dat deleted file mode 100644 index 9bfe45b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_MY.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:de7e2cc90a50f6c5d57bcdac3841fbc9021dad4ddd02d321a7b7c487318df3f1 -size 1203 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_TW.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_TW.dat deleted file mode 100644 index 7fcd69c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Hant_TW.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4de0af08dd71bcf649c2692a32f7b1c6cd354e4e251c77f5667ef349940e018 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn.dat deleted file mode 100644 index 4286062..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb047ae1beb9b2d8c0d8a5a3e0659c056885df2234036e29e0aef00298fcaad7 -size 1305 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn_CN.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn_CN.dat deleted file mode 100644 index 26c6d26..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zh_Latn_CN.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf3daa3e95843fd6dad764fd706b0f5c623b060e4b72667736400c8954dfeb50 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu.dat deleted file mode 100644 index c623e6c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b8f20de8235163911395df21d9d860309fff30af6cb774c923f7c3475b85fc4 -size 138626 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu_ZA.dat b/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu_ZA.dat deleted file mode 100644 index 851faae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/locale-data/zu_ZA.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c796805f90d6d01135e013edf1571bc44a2b566fdf78ffe4a86341b8fc92f91 -size 635 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localedata.py b/extensions/.local/lib/python3.11/site-packages/babel/localedata.py deleted file mode 100644 index 59f1db0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localedata.py +++ /dev/null @@ -1,278 +0,0 @@ -""" - babel.localedata - ~~~~~~~~~~~~~~~~ - - Low-level locale data access. - - :note: The `Locale` class, which uses this module under the hood, provides a - more convenient interface for accessing the locale data. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import annotations - -import os -import pickle -import re -import sys -import threading -from collections import abc -from collections.abc import Iterator, Mapping, MutableMapping -from functools import lru_cache -from itertools import chain -from typing import Any - -_cache: dict[str, Any] = {} -_cache_lock = threading.RLock() -_dirname = os.path.join(os.path.dirname(__file__), 'locale-data') -_windows_reserved_name_re = re.compile("^(con|prn|aux|nul|com[0-9]|lpt[0-9])$", re.I) - - -def normalize_locale(name: str) -> str | None: - """Normalize a locale ID by stripping spaces and apply proper casing. - - Returns the normalized locale ID string or `None` if the ID is not - recognized. - """ - if not name or not isinstance(name, str): - return None - name = name.strip().lower() - for locale_id in chain.from_iterable([_cache, locale_identifiers()]): - if name == locale_id.lower(): - return locale_id - - -def resolve_locale_filename(name: os.PathLike[str] | str) -> str: - """ - Resolve a locale identifier to a `.dat` path on disk. - """ - - # Clean up any possible relative paths. - name = os.path.basename(name) - - # Ensure we're not left with one of the Windows reserved names. - if sys.platform == "win32" and _windows_reserved_name_re.match(os.path.splitext(name)[0]): - raise ValueError(f"Name {name} is invalid on Windows") - - # Build the path. - return os.path.join(_dirname, f"{name}.dat") - - -def exists(name: str) -> bool: - """Check whether locale data is available for the given locale. - - Returns `True` if it exists, `False` otherwise. - - :param name: the locale identifier string - """ - if not name or not isinstance(name, str): - return False - if name in _cache: - return True - file_found = os.path.exists(resolve_locale_filename(name)) - return True if file_found else bool(normalize_locale(name)) - - -@lru_cache(maxsize=None) -def locale_identifiers() -> list[str]: - """Return a list of all locale identifiers for which locale data is - available. - - This data is cached after the first invocation. - You can clear the cache by calling `locale_identifiers.cache_clear()`. - - .. versionadded:: 0.8.1 - - :return: a list of locale identifiers (strings) - """ - return [ - stem - for stem, extension in - (os.path.splitext(filename) for filename in os.listdir(_dirname)) - if extension == '.dat' and stem != 'root' - ] - - -def _is_non_likely_script(name: str) -> bool: - """Return whether the locale is of the form ``lang_Script``, - and the script is not the likely script for the language. - - This implements the behavior of the ``nonlikelyScript`` value of the - ``localRules`` attribute for parent locales added in CLDR 45. - """ - from babel.core import get_global, parse_locale - - try: - lang, territory, script, variant, *rest = parse_locale(name) - except ValueError: - return False - - if lang and script and not territory and not variant and not rest: - likely_subtag = get_global('likely_subtags').get(lang) - _, _, likely_script, *_ = parse_locale(likely_subtag) - return script != likely_script - return False - - -def load(name: os.PathLike[str] | str, merge_inherited: bool = True) -> dict[str, Any]: - """Load the locale data for the given locale. - - The locale data is a dictionary that contains much of the data defined by - the Common Locale Data Repository (CLDR). This data is stored as a - collection of pickle files inside the ``babel`` package. - - >>> d = load('en_US') - >>> d['languages']['sv'] - u'Swedish' - - Note that the results are cached, and subsequent requests for the same - locale return the same dictionary: - - >>> d1 = load('en_US') - >>> d2 = load('en_US') - >>> d1 is d2 - True - - :param name: the locale identifier string (or "root") - :param merge_inherited: whether the inherited data should be merged into - the data of the requested locale - :raise `IOError`: if no locale data file is found for the given locale - identifier, or one of the locales it inherits from - """ - name = os.path.basename(name) - _cache_lock.acquire() - try: - data = _cache.get(name) - if not data: - # Load inherited data - if name == 'root' or not merge_inherited: - data = {} - else: - from babel.core import get_global - parent = get_global('parent_exceptions').get(name) - if not parent: - if _is_non_likely_script(name): - parent = 'root' - else: - parts = name.split('_') - parent = "root" if len(parts) == 1 else "_".join(parts[:-1]) - data = load(parent).copy() - filename = resolve_locale_filename(name) - with open(filename, 'rb') as fileobj: - if name != 'root' and merge_inherited: - merge(data, pickle.load(fileobj)) - else: - data = pickle.load(fileobj) - _cache[name] = data - return data - finally: - _cache_lock.release() - - -def merge(dict1: MutableMapping[Any, Any], dict2: Mapping[Any, Any]) -> None: - """Merge the data from `dict2` into the `dict1` dictionary, making copies - of nested dictionaries. - - >>> d = {1: 'foo', 3: 'baz'} - >>> merge(d, {1: 'Foo', 2: 'Bar'}) - >>> sorted(d.items()) - [(1, 'Foo'), (2, 'Bar'), (3, 'baz')] - - :param dict1: the dictionary to merge into - :param dict2: the dictionary containing the data that should be merged - """ - for key, val2 in dict2.items(): - if val2 is not None: - val1 = dict1.get(key) - if isinstance(val2, dict): - if val1 is None: - val1 = {} - if isinstance(val1, Alias): - val1 = (val1, val2) - elif isinstance(val1, tuple): - alias, others = val1 - others = others.copy() - merge(others, val2) - val1 = (alias, others) - else: - val1 = val1.copy() - merge(val1, val2) - else: - val1 = val2 - dict1[key] = val1 - - -class Alias: - """Representation of an alias in the locale data. - - An alias is a value that refers to some other part of the locale data, - as specified by the `keys`. - """ - - def __init__(self, keys: tuple[str, ...]) -> None: - self.keys = tuple(keys) - - def __repr__(self) -> str: - return f"<{type(self).__name__} {self.keys!r}>" - - def resolve(self, data: Mapping[str | int | None, Any]) -> Mapping[str | int | None, Any]: - """Resolve the alias based on the given data. - - This is done recursively, so if one alias resolves to a second alias, - that second alias will also be resolved. - - :param data: the locale data - :type data: `dict` - """ - base = data - for key in self.keys: - data = data[key] - if isinstance(data, Alias): - data = data.resolve(base) - elif isinstance(data, tuple): - alias, others = data - data = alias.resolve(base) - return data - - -class LocaleDataDict(abc.MutableMapping): - """Dictionary wrapper that automatically resolves aliases to the actual - values. - """ - - def __init__(self, data: MutableMapping[str | int | None, Any], base: Mapping[str | int | None, Any] | None = None): - self._data = data - if base is None: - base = data - self.base = base - - def __len__(self) -> int: - return len(self._data) - - def __iter__(self) -> Iterator[str | int | None]: - return iter(self._data) - - def __getitem__(self, key: str | int | None) -> Any: - orig = val = self._data[key] - if isinstance(val, Alias): # resolve an alias - val = val.resolve(self.base) - if isinstance(val, tuple): # Merge a partial dict with an alias - alias, others = val - val = alias.resolve(self.base).copy() - merge(val, others) - if isinstance(val, dict): # Return a nested alias-resolving dict - val = LocaleDataDict(val, base=self.base) - if val is not orig: - self._data[key] = val - return val - - def __setitem__(self, key: str | int | None, value: Any) -> None: - self._data[key] = value - - def __delitem__(self, key: str | int | None) -> None: - del self._data[key] - - def copy(self) -> LocaleDataDict: - return LocaleDataDict(self._data.copy(), base=self.base) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localtime/__init__.py b/extensions/.local/lib/python3.11/site-packages/babel/localtime/__init__.py deleted file mode 100644 index 854c074..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localtime/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ -""" - babel.localtime - ~~~~~~~~~~~~~~~ - - Babel specific fork of tzlocal to determine the local timezone - of the system. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -import datetime -import sys - -if sys.platform == 'win32': - from babel.localtime._win32 import _get_localzone -else: - from babel.localtime._unix import _get_localzone - - -# TODO(3.0): the offset constants are not part of the public API -# and should be removed -from babel.localtime._fallback import ( - DSTDIFF, # noqa: F401 - DSTOFFSET, # noqa: F401 - STDOFFSET, # noqa: F401 - ZERO, # noqa: F401 - _FallbackLocalTimezone, -) - - -def get_localzone() -> datetime.tzinfo: - """Returns the current underlying local timezone object. - Generally this function does not need to be used, it's a - better idea to use the :data:`LOCALTZ` singleton instead. - """ - return _get_localzone() - - -try: - LOCALTZ = get_localzone() -except LookupError: - LOCALTZ = _FallbackLocalTimezone() diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_fallback.py b/extensions/.local/lib/python3.11/site-packages/babel/localtime/_fallback.py deleted file mode 100644 index fab6867..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_fallback.py +++ /dev/null @@ -1,44 +0,0 @@ -""" - babel.localtime._fallback - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Emulated fallback local timezone when all else fails. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -import datetime -import time - -STDOFFSET = datetime.timedelta(seconds=-time.timezone) -DSTOFFSET = datetime.timedelta(seconds=-time.altzone) if time.daylight else STDOFFSET - -DSTDIFF = DSTOFFSET - STDOFFSET -ZERO = datetime.timedelta(0) - - -class _FallbackLocalTimezone(datetime.tzinfo): - - def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta: - if self._isdst(dt): - return DSTOFFSET - else: - return STDOFFSET - - def dst(self, dt: datetime.datetime) -> datetime.timedelta: - if self._isdst(dt): - return DSTDIFF - else: - return ZERO - - def tzname(self, dt: datetime.datetime) -> str: - return time.tzname[self._isdst(dt)] - - def _isdst(self, dt: datetime.datetime) -> bool: - tt = (dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second, - dt.weekday(), 0, -1) - stamp = time.mktime(tt) - tt = time.localtime(stamp) - return tt.tm_isdst > 0 diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_helpers.py b/extensions/.local/lib/python3.11/site-packages/babel/localtime/_helpers.py deleted file mode 100644 index e7e6705..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_helpers.py +++ /dev/null @@ -1,57 +0,0 @@ -try: - import pytz -except ModuleNotFoundError: - pytz = None - -try: - import zoneinfo -except ModuleNotFoundError: - zoneinfo = None - - -def _get_tzinfo(tzenv: str): - """Get the tzinfo from `zoneinfo` or `pytz` - - :param tzenv: timezone in the form of Continent/City - :return: tzinfo object or None if not found - """ - if pytz: - try: - return pytz.timezone(tzenv) - except pytz.UnknownTimeZoneError: - pass - else: - try: - return zoneinfo.ZoneInfo(tzenv) - except ValueError as ve: - # This is somewhat hacky, but since _validate_tzfile_path() doesn't - # raise a specific error type, we'll need to check the message to be - # one we know to be from that function. - # If so, we pretend it meant that the TZ didn't exist, for the benefit - # of `babel.localtime` catching the `LookupError` raised by - # `_get_tzinfo_or_raise()`. - # See https://github.com/python-babel/babel/issues/1092 - if str(ve).startswith("ZoneInfo keys "): - return None - except zoneinfo.ZoneInfoNotFoundError: - pass - - return None - - -def _get_tzinfo_or_raise(tzenv: str): - tzinfo = _get_tzinfo(tzenv) - if tzinfo is None: - raise LookupError( - f"Can not find timezone {tzenv}. \n" - "Timezone names are generally in the form `Continent/City`.", - ) - return tzinfo - - -def _get_tzinfo_from_file(tzfilename: str): - with open(tzfilename, 'rb') as tzfile: - if pytz: - return pytz.tzfile.build_tzinfo('local', tzfile) - else: - return zoneinfo.ZoneInfo.from_file(tzfile) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_unix.py b/extensions/.local/lib/python3.11/site-packages/babel/localtime/_unix.py deleted file mode 100644 index 782a7d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_unix.py +++ /dev/null @@ -1,104 +0,0 @@ -import datetime -import os -import re - -from babel.localtime._helpers import ( - _get_tzinfo, - _get_tzinfo_from_file, - _get_tzinfo_or_raise, -) - - -def _tz_from_env(tzenv: str) -> datetime.tzinfo: - if tzenv[0] == ':': - tzenv = tzenv[1:] - - # TZ specifies a file - if os.path.exists(tzenv): - return _get_tzinfo_from_file(tzenv) - - # TZ specifies a zoneinfo zone. - return _get_tzinfo_or_raise(tzenv) - - -def _get_localzone(_root: str = '/') -> datetime.tzinfo: - """Tries to find the local timezone configuration. - This method prefers finding the timezone name and passing that to - zoneinfo or pytz, over passing in the localtime file, as in the later - case the zoneinfo name is unknown. - The parameter _root makes the function look for files like /etc/localtime - beneath the _root directory. This is primarily used by the tests. - In normal usage you call the function without parameters. - """ - - tzenv = os.environ.get('TZ') - if tzenv: - return _tz_from_env(tzenv) - - # This is actually a pretty reliable way to test for the local time - # zone on operating systems like OS X. On OS X especially this is the - # only one that actually works. - try: - link_dst = os.readlink('/etc/localtime') - except OSError: - pass - else: - pos = link_dst.find('/zoneinfo/') - if pos >= 0: - # On occasion, the `/etc/localtime` symlink has a double slash, e.g. - # "/usr/share/zoneinfo//UTC", which would make `zoneinfo.ZoneInfo` - # complain (no absolute paths allowed), and we'd end up returning - # `None` (as a fix for #1092). - # Instead, let's just "fix" the double slash symlink by stripping - # leading slashes before passing the assumed zone name forward. - zone_name = link_dst[pos + 10:].lstrip("/") - tzinfo = _get_tzinfo(zone_name) - if tzinfo is not None: - return tzinfo - - # Now look for distribution specific configuration files - # that contain the timezone name. - tzpath = os.path.join(_root, 'etc/timezone') - if os.path.exists(tzpath): - with open(tzpath, 'rb') as tzfile: - data = tzfile.read() - - # Issue #3 in tzlocal was that /etc/timezone was a zoneinfo file. - # That's a misconfiguration, but we need to handle it gracefully: - if data[:5] != b'TZif2': - etctz = data.strip().decode() - # Get rid of host definitions and comments: - if ' ' in etctz: - etctz, dummy = etctz.split(' ', 1) - if '#' in etctz: - etctz, dummy = etctz.split('#', 1) - - return _get_tzinfo_or_raise(etctz.replace(' ', '_')) - - # CentOS has a ZONE setting in /etc/sysconfig/clock, - # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and - # Gentoo has a TIMEZONE setting in /etc/conf.d/clock - # We look through these files for a timezone: - timezone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"(?P.+)"') - - for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): - tzpath = os.path.join(_root, filename) - if not os.path.exists(tzpath): - continue - with open(tzpath) as tzfile: - for line in tzfile: - match = timezone_re.match(line) - if match is not None: - # We found a timezone - etctz = match.group("etctz") - return _get_tzinfo_or_raise(etctz.replace(' ', '_')) - - # No explicit setting existed. Use localtime - for filename in ('etc/localtime', 'usr/local/etc/localtime'): - tzpath = os.path.join(_root, filename) - - if not os.path.exists(tzpath): - continue - return _get_tzinfo_from_file(tzpath) - - raise LookupError('Can not find any timezone configuration') diff --git a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_win32.py b/extensions/.local/lib/python3.11/site-packages/babel/localtime/_win32.py deleted file mode 100644 index 1a52567..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/localtime/_win32.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import annotations - -try: - import winreg -except ImportError: - winreg = None - -import datetime -from typing import Any, Dict, cast - -from babel.core import get_global -from babel.localtime._helpers import _get_tzinfo_or_raise - -# When building the cldr data on windows this module gets imported. -# Because at that point there is no global.dat yet this call will -# fail. We want to catch it down in that case then and just assume -# the mapping was empty. -try: - tz_names: dict[str, str] = cast(Dict[str, str], get_global('windows_zone_mapping')) -except RuntimeError: - tz_names = {} - - -def valuestodict(key) -> dict[str, Any]: - """Convert a registry key's values to a dictionary.""" - dict = {} - size = winreg.QueryInfoKey(key)[1] - for i in range(size): - data = winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict - - -def get_localzone_name() -> str: - # Windows is special. It has unique time zone names (in several - # meanings of the word) available, but unfortunately, they can be - # translated to the language of the operating system, so we need to - # do a backwards lookup, by going through all time zones and see which - # one matches. - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - - TZLOCALKEYNAME = r'SYSTEM\CurrentControlSet\Control\TimeZoneInformation' - localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) - keyvalues = valuestodict(localtz) - localtz.Close() - if 'TimeZoneKeyName' in keyvalues: - # Windows 7 (and Vista?) - - # For some reason this returns a string with loads of NUL bytes at - # least on some systems. I don't know if this is a bug somewhere, I - # just work around it. - tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] - else: - # Windows 2000 or XP - - # This is the localized name: - tzwin = keyvalues['StandardName'] - - # Open the list of timezones to look up the real name: - TZKEYNAME = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones' - tzkey = winreg.OpenKey(handle, TZKEYNAME) - - # Now, match this value to Time Zone information - tzkeyname = None - for i in range(winreg.QueryInfoKey(tzkey)[0]): - subkey = winreg.EnumKey(tzkey, i) - sub = winreg.OpenKey(tzkey, subkey) - data = valuestodict(sub) - sub.Close() - if data.get('Std', None) == tzwin: - tzkeyname = subkey - break - - tzkey.Close() - handle.Close() - - if tzkeyname is None: - raise LookupError('Can not find Windows timezone configuration') - - timezone = tz_names.get(tzkeyname) - if timezone is None: - # Nope, that didn't work. Try adding 'Standard Time', - # it seems to work a lot of times: - timezone = tz_names.get(f"{tzkeyname} Standard Time") - - # Return what we have. - if timezone is None: - raise LookupError(f"Can not find timezone {tzkeyname}") - - return timezone - - -def _get_localzone() -> datetime.tzinfo: - if winreg is None: - raise LookupError( - 'Runtime support not available') - - return _get_tzinfo_or_raise(get_localzone_name()) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/__init__.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/__init__.py deleted file mode 100644 index ca83faa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" - babel.messages - ~~~~~~~~~~~~~~ - - Support for ``gettext`` message catalogs. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from babel.messages.catalog import ( - Catalog, - Message, - TranslationError, -) - -__all__ = [ - "Catalog", - "Message", - "TranslationError", -] diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/_compat.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/_compat.py deleted file mode 100644 index 319b545..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/_compat.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys -from functools import partial - - -def find_entrypoints(group_name: str): - """ - Find entrypoints of a given group using either `importlib.metadata` or the - older `pkg_resources` mechanism. - - Yields tuples of the entrypoint name and a callable function that will - load the actual entrypoint. - """ - if sys.version_info >= (3, 10): - # "Changed in version 3.10: importlib.metadata is no longer provisional." - try: - from importlib.metadata import entry_points - except ImportError: - pass - else: - eps = entry_points(group=group_name) - # Only do this if this implementation of `importlib.metadata` is - # modern enough to not return a dict. - if not isinstance(eps, dict): - for entry_point in eps: - yield (entry_point.name, entry_point.load) - return - - try: - from pkg_resources import working_set - except ImportError: - pass - else: - for entry_point in working_set.iter_entry_points(group_name): - yield (entry_point.name, partial(entry_point.load, require=True)) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/catalog.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/catalog.py deleted file mode 100644 index f84a5bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/catalog.py +++ /dev/null @@ -1,1000 +0,0 @@ -""" - babel.messages.catalog - ~~~~~~~~~~~~~~~~~~~~~~ - - Data structures for message catalogs. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" -from __future__ import annotations - -import datetime -import re -from collections.abc import Iterable, Iterator -from copy import copy -from difflib import SequenceMatcher -from email import message_from_string -from heapq import nlargest -from string import Formatter -from typing import TYPE_CHECKING - -from babel import __version__ as VERSION -from babel.core import Locale, UnknownLocaleError -from babel.dates import format_datetime -from babel.messages.plurals import get_plural -from babel.util import LOCALTZ, FixedOffsetTimezone, _cmp, distinct - -if TYPE_CHECKING: - from typing_extensions import TypeAlias - - _MessageID: TypeAlias = str | tuple[str, ...] | list[str] - -__all__ = [ - 'DEFAULT_HEADER', - 'PYTHON_FORMAT', - 'Catalog', - 'Message', - 'TranslationError', -] - - -def get_close_matches(word, possibilities, n=3, cutoff=0.6): - """A modified version of ``difflib.get_close_matches``. - - It just passes ``autojunk=False`` to the ``SequenceMatcher``, to work - around https://github.com/python/cpython/issues/90825. - """ - if not n > 0: # pragma: no cover - raise ValueError(f"n must be > 0: {n!r}") - if not 0.0 <= cutoff <= 1.0: # pragma: no cover - raise ValueError(f"cutoff must be in [0.0, 1.0]: {cutoff!r}") - result = [] - s = SequenceMatcher(autojunk=False) # only line changed from difflib.py - s.set_seq2(word) - for x in possibilities: - s.set_seq1(x) - if s.real_quick_ratio() >= cutoff and \ - s.quick_ratio() >= cutoff and \ - s.ratio() >= cutoff: - result.append((s.ratio(), x)) - - # Move the best scorers to head of list - result = nlargest(n, result) - # Strip scores for the best n matches - return [x for score, x in result] - - -PYTHON_FORMAT = re.compile(r''' - \% - (?:\(([\w]*)\))? - ( - [-#0\ +]?(?:\*|[\d]+)? - (?:\.(?:\*|[\d]+))? - [hlL]? - ) - ([diouxXeEfFgGcrs%]) -''', re.VERBOSE) - - -def _has_python_brace_format(string: str) -> bool: - if "{" not in string: - return False - fmt = Formatter() - try: - # `fmt.parse` returns 3-or-4-tuples of the form - # `(literal_text, field_name, format_spec, conversion)`; - # if `field_name` is set, this smells like brace format - field_name_seen = False - for t in fmt.parse(string): - if t[1] is not None: - field_name_seen = True - # We cannot break here, as we need to consume the whole string - # to ensure that it is a valid format string. - except ValueError: - return False - return field_name_seen - - -def _parse_datetime_header(value: str) -> datetime.datetime: - match = re.match(r'^(?P.*?)(?P[+-]\d{4})?$', value) - - dt = datetime.datetime.strptime(match.group('datetime'), '%Y-%m-%d %H:%M') - - # Separate the offset into a sign component, hours, and # minutes - tzoffset = match.group('tzoffset') - if tzoffset is not None: - plus_minus_s, rest = tzoffset[0], tzoffset[1:] - hours_offset_s, mins_offset_s = rest[:2], rest[2:] - - # Make them all integers - plus_minus = int(f"{plus_minus_s}1") - hours_offset = int(hours_offset_s) - mins_offset = int(mins_offset_s) - - # Calculate net offset - net_mins_offset = hours_offset * 60 - net_mins_offset += mins_offset - net_mins_offset *= plus_minus - - # Create an offset object - tzoffset = FixedOffsetTimezone(net_mins_offset) - - # Store the offset in a datetime object - dt = dt.replace(tzinfo=tzoffset) - - return dt - - -class Message: - """Representation of a single message in a catalog.""" - - def __init__( - self, - id: _MessageID, - string: _MessageID | None = '', - locations: Iterable[tuple[str, int]] = (), - flags: Iterable[str] = (), - auto_comments: Iterable[str] = (), - user_comments: Iterable[str] = (), - previous_id: _MessageID = (), - lineno: int | None = None, - context: str | None = None, - ) -> None: - """Create the message object. - - :param id: the message ID, or a ``(singular, plural)`` tuple for - pluralizable messages - :param string: the translated message string, or a - ``(singular, plural)`` tuple for pluralizable messages - :param locations: a sequence of ``(filename, lineno)`` tuples - :param flags: a set or sequence of flags - :param auto_comments: a sequence of automatic comments for the message - :param user_comments: a sequence of user comments for the message - :param previous_id: the previous message ID, or a ``(singular, plural)`` - tuple for pluralizable messages - :param lineno: the line number on which the msgid line was found in the - PO file, if any - :param context: the message context - """ - self.id = id - if not string and self.pluralizable: - string = ('', '') - self.string = string - self.locations = list(distinct(locations)) - self.flags = set(flags) - if id and self.python_format: - self.flags.add('python-format') - else: - self.flags.discard('python-format') - if id and self.python_brace_format: - self.flags.add('python-brace-format') - else: - self.flags.discard('python-brace-format') - self.auto_comments = list(distinct(auto_comments)) - self.user_comments = list(distinct(user_comments)) - if isinstance(previous_id, str): - self.previous_id = [previous_id] - else: - self.previous_id = list(previous_id) - self.lineno = lineno - self.context = context - - def __repr__(self) -> str: - return f"<{type(self).__name__} {self.id!r} (flags: {list(self.flags)!r})>" - - def __cmp__(self, other: object) -> int: - """Compare Messages, taking into account plural ids""" - def values_to_compare(obj): - if isinstance(obj, Message) and obj.pluralizable: - return obj.id[0], obj.context or '' - return obj.id, obj.context or '' - return _cmp(values_to_compare(self), values_to_compare(other)) - - def __gt__(self, other: object) -> bool: - return self.__cmp__(other) > 0 - - def __lt__(self, other: object) -> bool: - return self.__cmp__(other) < 0 - - def __ge__(self, other: object) -> bool: - return self.__cmp__(other) >= 0 - - def __le__(self, other: object) -> bool: - return self.__cmp__(other) <= 0 - - def __eq__(self, other: object) -> bool: - return self.__cmp__(other) == 0 - - def __ne__(self, other: object) -> bool: - return self.__cmp__(other) != 0 - - def is_identical(self, other: Message) -> bool: - """Checks whether messages are identical, taking into account all - properties. - """ - assert isinstance(other, Message) - return self.__dict__ == other.__dict__ - - def clone(self) -> Message: - return Message(*map(copy, (self.id, self.string, self.locations, - self.flags, self.auto_comments, - self.user_comments, self.previous_id, - self.lineno, self.context))) - - def check(self, catalog: Catalog | None = None) -> list[TranslationError]: - """Run various validation checks on the message. Some validations - are only performed if the catalog is provided. This method returns - a sequence of `TranslationError` objects. - - :rtype: ``iterator`` - :param catalog: A catalog instance that is passed to the checkers - :see: `Catalog.check` for a way to perform checks for all messages - in a catalog. - """ - from babel.messages.checkers import checkers - errors: list[TranslationError] = [] - for checker in checkers: - try: - checker(catalog, self) - except TranslationError as e: - errors.append(e) - return errors - - @property - def fuzzy(self) -> bool: - """Whether the translation is fuzzy. - - >>> Message('foo').fuzzy - False - >>> msg = Message('foo', 'foo', flags=['fuzzy']) - >>> msg.fuzzy - True - >>> msg - - - :type: `bool`""" - return 'fuzzy' in self.flags - - @property - def pluralizable(self) -> bool: - """Whether the message is plurizable. - - >>> Message('foo').pluralizable - False - >>> Message(('foo', 'bar')).pluralizable - True - - :type: `bool`""" - return isinstance(self.id, (list, tuple)) - - @property - def python_format(self) -> bool: - """Whether the message contains Python-style parameters. - - >>> Message('foo %(name)s bar').python_format - True - >>> Message(('foo %(name)s', 'foo %(name)s')).python_format - True - - :type: `bool`""" - ids = self.id - if not isinstance(ids, (list, tuple)): - ids = [ids] - return any(PYTHON_FORMAT.search(id) for id in ids) - - @property - def python_brace_format(self) -> bool: - """Whether the message contains Python f-string parameters. - - >>> Message('Hello, {name}!').python_brace_format - True - >>> Message(('One apple', '{count} apples')).python_brace_format - True - - :type: `bool`""" - ids = self.id - if not isinstance(ids, (list, tuple)): - ids = [ids] - return any(_has_python_brace_format(id) for id in ids) - - -class TranslationError(Exception): - """Exception thrown by translation checkers when invalid message - translations are encountered.""" - - -DEFAULT_HEADER = """\ -# Translations template for PROJECT. -# Copyright (C) YEAR ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , YEAR. -#""" - - -def parse_separated_header(value: str) -> dict[str, str]: - # Adapted from https://peps.python.org/pep-0594/#cgi - from email.message import Message - m = Message() - m['content-type'] = value - return dict(m.get_params()) - - -def _force_text(s: str | bytes, encoding: str = 'utf-8', errors: str = 'strict') -> str: - if isinstance(s, str): - return s - if isinstance(s, bytes): - return s.decode(encoding, errors) - return str(s) - - -class Catalog: - """Representation of a message catalog.""" - - def __init__( - self, - locale: Locale | str | None = None, - domain: str | None = None, - header_comment: str | None = DEFAULT_HEADER, - project: str | None = None, - version: str | None = None, - copyright_holder: str | None = None, - msgid_bugs_address: str | None = None, - creation_date: datetime.datetime | str | None = None, - revision_date: datetime.datetime | datetime.time | float | str | None = None, - last_translator: str | None = None, - language_team: str | None = None, - charset: str | None = None, - fuzzy: bool = True, - ) -> None: - """Initialize the catalog object. - - :param locale: the locale identifier or `Locale` object, or `None` - if the catalog is not bound to a locale (which basically - means it's a template) - :param domain: the message domain - :param header_comment: the header comment as string, or `None` for the - default header - :param project: the project's name - :param version: the project's version - :param copyright_holder: the copyright holder of the catalog - :param msgid_bugs_address: the email address or URL to submit bug - reports to - :param creation_date: the date the catalog was created - :param revision_date: the date the catalog was revised - :param last_translator: the name and email of the last translator - :param language_team: the name and email of the language team - :param charset: the encoding to use in the output (defaults to utf-8) - :param fuzzy: the fuzzy bit on the catalog header - """ - self.domain = domain - self.locale = locale - self._header_comment = header_comment - self._messages: dict[str | tuple[str, str], Message] = {} - - self.project = project or 'PROJECT' - self.version = version or 'VERSION' - self.copyright_holder = copyright_holder or 'ORGANIZATION' - self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS' - - self.last_translator = last_translator or 'FULL NAME ' - """Name and email address of the last translator.""" - self.language_team = language_team or 'LANGUAGE ' - """Name and email address of the language team.""" - - self.charset = charset or 'utf-8' - - if creation_date is None: - creation_date = datetime.datetime.now(LOCALTZ) - elif isinstance(creation_date, datetime.datetime) and not creation_date.tzinfo: - creation_date = creation_date.replace(tzinfo=LOCALTZ) - self.creation_date = creation_date - if revision_date is None: - revision_date = 'YEAR-MO-DA HO:MI+ZONE' - elif isinstance(revision_date, datetime.datetime) and not revision_date.tzinfo: - revision_date = revision_date.replace(tzinfo=LOCALTZ) - self.revision_date = revision_date - self.fuzzy = fuzzy - - # Dictionary of obsolete messages - self.obsolete: dict[str | tuple[str, str], Message] = {} - self._num_plurals = None - self._plural_expr = None - - def _set_locale(self, locale: Locale | str | None) -> None: - if locale is None: - self._locale_identifier = None - self._locale = None - return - - if isinstance(locale, Locale): - self._locale_identifier = str(locale) - self._locale = locale - return - - if isinstance(locale, str): - self._locale_identifier = str(locale) - try: - self._locale = Locale.parse(locale) - except UnknownLocaleError: - self._locale = None - return - - raise TypeError(f"`locale` must be a Locale, a locale identifier string, or None; got {locale!r}") - - def _get_locale(self) -> Locale | None: - return self._locale - - def _get_locale_identifier(self) -> str | None: - return self._locale_identifier - - locale = property(_get_locale, _set_locale) - locale_identifier = property(_get_locale_identifier) - - def _get_header_comment(self) -> str: - comment = self._header_comment - year = datetime.datetime.now(LOCALTZ).strftime('%Y') - if hasattr(self.revision_date, 'strftime'): - year = self.revision_date.strftime('%Y') - comment = comment.replace('PROJECT', self.project) \ - .replace('VERSION', self.version) \ - .replace('YEAR', year) \ - .replace('ORGANIZATION', self.copyright_holder) - locale_name = (self.locale.english_name if self.locale else self.locale_identifier) - if locale_name: - comment = comment.replace("Translations template", f"{locale_name} translations") - return comment - - def _set_header_comment(self, string: str | None) -> None: - self._header_comment = string - - header_comment = property(_get_header_comment, _set_header_comment, doc="""\ - The header comment for the catalog. - - >>> catalog = Catalog(project='Foobar', version='1.0', - ... copyright_holder='Foo Company') - >>> print(catalog.header_comment) #doctest: +ELLIPSIS - # Translations template for Foobar. - # Copyright (C) ... Foo Company - # This file is distributed under the same license as the Foobar project. - # FIRST AUTHOR , .... - # - - The header can also be set from a string. Any known upper-case variables - will be replaced when the header is retrieved again: - - >>> catalog = Catalog(project='Foobar', version='1.0', - ... copyright_holder='Foo Company') - >>> catalog.header_comment = '''\\ - ... # The POT for my really cool PROJECT project. - ... # Copyright (C) 1990-2003 ORGANIZATION - ... # This file is distributed under the same license as the PROJECT - ... # project. - ... #''' - >>> print(catalog.header_comment) - # The POT for my really cool Foobar project. - # Copyright (C) 1990-2003 Foo Company - # This file is distributed under the same license as the Foobar - # project. - # - - :type: `unicode` - """) - - def _get_mime_headers(self) -> list[tuple[str, str]]: - if isinstance(self.revision_date, (datetime.datetime, datetime.time, int, float)): - revision_date = format_datetime(self.revision_date, 'yyyy-MM-dd HH:mmZ', locale='en') - else: - revision_date = self.revision_date - - language_team = self.language_team - if self.locale_identifier and 'LANGUAGE' in language_team: - language_team = language_team.replace('LANGUAGE', str(self.locale_identifier)) - - headers: list[tuple[str, str]] = [ - ("Project-Id-Version", f"{self.project} {self.version}"), - ('Report-Msgid-Bugs-To', self.msgid_bugs_address), - ('POT-Creation-Date', format_datetime(self.creation_date, 'yyyy-MM-dd HH:mmZ', locale='en')), - ('PO-Revision-Date', revision_date), - ('Last-Translator', self.last_translator), - ] - if self.locale_identifier: - headers.append(('Language', str(self.locale_identifier))) - headers.append(('Language-Team', language_team)) - if self.locale is not None: - headers.append(('Plural-Forms', self.plural_forms)) - headers += [ - ('MIME-Version', '1.0'), - ("Content-Type", f"text/plain; charset={self.charset}"), - ('Content-Transfer-Encoding', '8bit'), - ("Generated-By", f"Babel {VERSION}\n"), - ] - return headers - - def _set_mime_headers(self, headers: Iterable[tuple[str, str]]) -> None: - for name, value in headers: - name = _force_text(name.lower(), encoding=self.charset) - value = _force_text(value, encoding=self.charset) - if name == 'project-id-version': - parts = value.split(' ') - self.project = ' '.join(parts[:-1]) - self.version = parts[-1] - elif name == 'report-msgid-bugs-to': - self.msgid_bugs_address = value - elif name == 'last-translator': - self.last_translator = value - elif name == 'language': - value = value.replace('-', '_') - # The `or None` makes sure that the locale is set to None - # if the header's value is an empty string, which is what - # some tools generate (instead of eliding the empty Language - # header altogether). - self._set_locale(value or None) - elif name == 'language-team': - self.language_team = value - elif name == 'content-type': - params = parse_separated_header(value) - if 'charset' in params: - self.charset = params['charset'].lower() - elif name == 'plural-forms': - params = parse_separated_header(f" ;{value}") - self._num_plurals = int(params.get('nplurals', 2)) - self._plural_expr = params.get('plural', '(n != 1)') - elif name == 'pot-creation-date': - self.creation_date = _parse_datetime_header(value) - elif name == 'po-revision-date': - # Keep the value if it's not the default one - if 'YEAR' not in value: - self.revision_date = _parse_datetime_header(value) - - mime_headers = property(_get_mime_headers, _set_mime_headers, doc="""\ - The MIME headers of the catalog, used for the special ``msgid ""`` entry. - - The behavior of this property changes slightly depending on whether a locale - is set or not, the latter indicating that the catalog is actually a template - for actual translations. - - Here's an example of the output for such a catalog template: - - >>> from babel.dates import UTC - >>> from datetime import datetime - >>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC) - >>> catalog = Catalog(project='Foobar', version='1.0', - ... creation_date=created) - >>> for name, value in catalog.mime_headers: - ... print('%s: %s' % (name, value)) - Project-Id-Version: Foobar 1.0 - Report-Msgid-Bugs-To: EMAIL@ADDRESS - POT-Creation-Date: 1990-04-01 15:30+0000 - PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE - Last-Translator: FULL NAME - Language-Team: LANGUAGE - MIME-Version: 1.0 - Content-Type: text/plain; charset=utf-8 - Content-Transfer-Encoding: 8bit - Generated-By: Babel ... - - And here's an example of the output when the locale is set: - - >>> revised = datetime(1990, 8, 3, 12, 0, tzinfo=UTC) - >>> catalog = Catalog(locale='de_DE', project='Foobar', version='1.0', - ... creation_date=created, revision_date=revised, - ... last_translator='John Doe ', - ... language_team='de_DE ') - >>> for name, value in catalog.mime_headers: - ... print('%s: %s' % (name, value)) - Project-Id-Version: Foobar 1.0 - Report-Msgid-Bugs-To: EMAIL@ADDRESS - POT-Creation-Date: 1990-04-01 15:30+0000 - PO-Revision-Date: 1990-08-03 12:00+0000 - Last-Translator: John Doe - Language: de_DE - Language-Team: de_DE - Plural-Forms: nplurals=2; plural=(n != 1); - MIME-Version: 1.0 - Content-Type: text/plain; charset=utf-8 - Content-Transfer-Encoding: 8bit - Generated-By: Babel ... - - :type: `list` - """) - - @property - def num_plurals(self) -> int: - """The number of plurals used by the catalog or locale. - - >>> Catalog(locale='en').num_plurals - 2 - >>> Catalog(locale='ga').num_plurals - 5 - - :type: `int`""" - if self._num_plurals is None: - num = 2 - if self.locale: - num = get_plural(self.locale)[0] - self._num_plurals = num - return self._num_plurals - - @property - def plural_expr(self) -> str: - """The plural expression used by the catalog or locale. - - >>> Catalog(locale='en').plural_expr - '(n != 1)' - >>> Catalog(locale='ga').plural_expr - '(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)' - >>> Catalog(locale='ding').plural_expr # unknown locale - '(n != 1)' - - :type: `str`""" - if self._plural_expr is None: - expr = '(n != 1)' - if self.locale: - expr = get_plural(self.locale)[1] - self._plural_expr = expr - return self._plural_expr - - @property - def plural_forms(self) -> str: - """Return the plural forms declaration for the locale. - - >>> Catalog(locale='en').plural_forms - 'nplurals=2; plural=(n != 1);' - >>> Catalog(locale='pt_BR').plural_forms - 'nplurals=2; plural=(n > 1);' - - :type: `str`""" - return f"nplurals={self.num_plurals}; plural={self.plural_expr};" - - def __contains__(self, id: _MessageID) -> bool: - """Return whether the catalog has a message with the specified ID.""" - return self._key_for(id) in self._messages - - def __len__(self) -> int: - """The number of messages in the catalog. - - This does not include the special ``msgid ""`` entry.""" - return len(self._messages) - - def __iter__(self) -> Iterator[Message]: - """Iterates through all the entries in the catalog, in the order they - were added, yielding a `Message` object for every entry. - - :rtype: ``iterator``""" - buf = [] - for name, value in self.mime_headers: - buf.append(f"{name}: {value}") - flags = set() - if self.fuzzy: - flags |= {'fuzzy'} - yield Message('', '\n'.join(buf), flags=flags) - for key in self._messages: - yield self._messages[key] - - def __repr__(self) -> str: - locale = '' - if self.locale: - locale = f" {self.locale}" - return f"<{type(self).__name__} {self.domain!r}{locale}>" - - def __delitem__(self, id: _MessageID) -> None: - """Delete the message with the specified ID.""" - self.delete(id) - - def __getitem__(self, id: _MessageID) -> Message: - """Return the message with the specified ID. - - :param id: the message ID - """ - return self.get(id) - - def __setitem__(self, id: _MessageID, message: Message) -> None: - """Add or update the message with the specified ID. - - >>> catalog = Catalog() - >>> catalog[u'foo'] = Message(u'foo') - >>> catalog[u'foo'] - - - If a message with that ID is already in the catalog, it is updated - to include the locations and flags of the new message. - - >>> catalog = Catalog() - >>> catalog[u'foo'] = Message(u'foo', locations=[('main.py', 1)]) - >>> catalog[u'foo'].locations - [('main.py', 1)] - >>> catalog[u'foo'] = Message(u'foo', locations=[('utils.py', 5)]) - >>> catalog[u'foo'].locations - [('main.py', 1), ('utils.py', 5)] - - :param id: the message ID - :param message: the `Message` object - """ - assert isinstance(message, Message), 'expected a Message object' - key = self._key_for(id, message.context) - current = self._messages.get(key) - if current: - if message.pluralizable and not current.pluralizable: - # The new message adds pluralization - current.id = message.id - current.string = message.string - current.locations = list(distinct(current.locations + - message.locations)) - current.auto_comments = list(distinct(current.auto_comments + - message.auto_comments)) - current.user_comments = list(distinct(current.user_comments + - message.user_comments)) - current.flags |= message.flags - elif id == '': - # special treatment for the header message - self.mime_headers = message_from_string(message.string).items() - self.header_comment = "\n".join([f"# {c}".rstrip() for c in message.user_comments]) - self.fuzzy = message.fuzzy - else: - if isinstance(id, (list, tuple)): - assert isinstance(message.string, (list, tuple)), \ - f"Expected sequence but got {type(message.string)}" - self._messages[key] = message - - def add( - self, - id: _MessageID, - string: _MessageID | None = None, - locations: Iterable[tuple[str, int]] = (), - flags: Iterable[str] = (), - auto_comments: Iterable[str] = (), - user_comments: Iterable[str] = (), - previous_id: _MessageID = (), - lineno: int | None = None, - context: str | None = None, - ) -> Message: - """Add or update the message with the specified ID. - - >>> catalog = Catalog() - >>> catalog.add(u'foo') - - >>> catalog[u'foo'] - - - This method simply constructs a `Message` object with the given - arguments and invokes `__setitem__` with that object. - - :param id: the message ID, or a ``(singular, plural)`` tuple for - pluralizable messages - :param string: the translated message string, or a - ``(singular, plural)`` tuple for pluralizable messages - :param locations: a sequence of ``(filename, lineno)`` tuples - :param flags: a set or sequence of flags - :param auto_comments: a sequence of automatic comments - :param user_comments: a sequence of user comments - :param previous_id: the previous message ID, or a ``(singular, plural)`` - tuple for pluralizable messages - :param lineno: the line number on which the msgid line was found in the - PO file, if any - :param context: the message context - """ - message = Message(id, string, list(locations), flags, auto_comments, - user_comments, previous_id, lineno=lineno, - context=context) - self[id] = message - return message - - def check(self) -> Iterable[tuple[Message, list[TranslationError]]]: - """Run various validation checks on the translations in the catalog. - - For every message which fails validation, this method yield a - ``(message, errors)`` tuple, where ``message`` is the `Message` object - and ``errors`` is a sequence of `TranslationError` objects. - - :rtype: ``generator`` of ``(message, errors)`` - """ - for message in self._messages.values(): - errors = message.check(catalog=self) - if errors: - yield message, errors - - def get(self, id: _MessageID, context: str | None = None) -> Message | None: - """Return the message with the specified ID and context. - - :param id: the message ID - :param context: the message context, or ``None`` for no context - """ - return self._messages.get(self._key_for(id, context)) - - def delete(self, id: _MessageID, context: str | None = None) -> None: - """Delete the message with the specified ID and context. - - :param id: the message ID - :param context: the message context, or ``None`` for no context - """ - key = self._key_for(id, context) - if key in self._messages: - del self._messages[key] - - def update( - self, - template: Catalog, - no_fuzzy_matching: bool = False, - update_header_comment: bool = False, - keep_user_comments: bool = True, - update_creation_date: bool = True, - ) -> None: - """Update the catalog based on the given template catalog. - - >>> from babel.messages import Catalog - >>> template = Catalog() - >>> template.add('green', locations=[('main.py', 99)]) - - >>> template.add('blue', locations=[('main.py', 100)]) - - >>> template.add(('salad', 'salads'), locations=[('util.py', 42)]) - - >>> catalog = Catalog(locale='de_DE') - >>> catalog.add('blue', u'blau', locations=[('main.py', 98)]) - - >>> catalog.add('head', u'Kopf', locations=[('util.py', 33)]) - - >>> catalog.add(('salad', 'salads'), (u'Salat', u'Salate'), - ... locations=[('util.py', 38)]) - - - >>> catalog.update(template) - >>> len(catalog) - 3 - - >>> msg1 = catalog['green'] - >>> msg1.string - >>> msg1.locations - [('main.py', 99)] - - >>> msg2 = catalog['blue'] - >>> msg2.string - u'blau' - >>> msg2.locations - [('main.py', 100)] - - >>> msg3 = catalog['salad'] - >>> msg3.string - (u'Salat', u'Salate') - >>> msg3.locations - [('util.py', 42)] - - Messages that are in the catalog but not in the template are removed - from the main collection, but can still be accessed via the `obsolete` - member: - - >>> 'head' in catalog - False - >>> list(catalog.obsolete.values()) - [] - - :param template: the reference catalog, usually read from a POT file - :param no_fuzzy_matching: whether to use fuzzy matching of message IDs - :param update_header_comment: whether to copy the header comment from the template - :param keep_user_comments: whether to keep user comments from the old catalog - :param update_creation_date: whether to copy the creation date from the template - """ - messages = self._messages - remaining = messages.copy() - self._messages = {} - - # Prepare for fuzzy matching - fuzzy_candidates = {} - if not no_fuzzy_matching: - for msgid in messages: - if msgid and messages[msgid].string: - key = self._key_for(msgid) - ctxt = messages[msgid].context - fuzzy_candidates[self._to_fuzzy_match_key(key)] = (key, ctxt) - fuzzy_matches = set() - - def _merge(message: Message, oldkey: tuple[str, str] | str, newkey: tuple[str, str] | str) -> None: - message = message.clone() - fuzzy = False - if oldkey != newkey: - fuzzy = True - fuzzy_matches.add(oldkey) - oldmsg = messages.get(oldkey) - assert oldmsg is not None - if isinstance(oldmsg.id, str): - message.previous_id = [oldmsg.id] - else: - message.previous_id = list(oldmsg.id) - else: - oldmsg = remaining.pop(oldkey, None) - assert oldmsg is not None - message.string = oldmsg.string - - if keep_user_comments: - message.user_comments = list(distinct(oldmsg.user_comments)) - - if isinstance(message.id, (list, tuple)): - if not isinstance(message.string, (list, tuple)): - fuzzy = True - message.string = tuple( - [message.string] + ([''] * (len(message.id) - 1)), - ) - elif len(message.string) != self.num_plurals: - fuzzy = True - message.string = tuple(message.string[:len(oldmsg.string)]) - elif isinstance(message.string, (list, tuple)): - fuzzy = True - message.string = message.string[0] - message.flags |= oldmsg.flags - if fuzzy: - message.flags |= {'fuzzy'} - self[message.id] = message - - for message in template: - if message.id: - key = self._key_for(message.id, message.context) - if key in messages: - _merge(message, key, key) - else: - if not no_fuzzy_matching: - # do some fuzzy matching with difflib - matches = get_close_matches( - self._to_fuzzy_match_key(key), - fuzzy_candidates.keys(), - 1, - ) - if matches: - modified_key = matches[0] - newkey, newctxt = fuzzy_candidates[modified_key] - if newctxt is not None: - newkey = newkey, newctxt - _merge(message, newkey, key) - continue - - self[message.id] = message - - for msgid in remaining: - if no_fuzzy_matching or msgid not in fuzzy_matches: - self.obsolete[msgid] = remaining[msgid] - - if update_header_comment: - # Allow the updated catalog's header to be rewritten based on the - # template's header - self.header_comment = template.header_comment - - # Make updated catalog's POT-Creation-Date equal to the template - # used to update the catalog - if update_creation_date: - self.creation_date = template.creation_date - - def _to_fuzzy_match_key(self, key: tuple[str, str] | str) -> str: - """Converts a message key to a string suitable for fuzzy matching.""" - if isinstance(key, tuple): - matchkey = key[0] # just the msgid, no context - else: - matchkey = key - return matchkey.lower().strip() - - def _key_for(self, id: _MessageID, context: str | None = None) -> tuple[str, str] | str: - """The key for a message is just the singular ID even for pluralizable - messages, but is a ``(msgid, msgctxt)`` tuple for context-specific - messages. - """ - key = id - if isinstance(key, (list, tuple)): - key = id[0] - if context is not None: - key = (key, context) - return key - - def is_identical(self, other: Catalog) -> bool: - """Checks if catalogs are identical, taking into account messages and - headers. - """ - assert isinstance(other, Catalog) - for key in self._messages.keys() | other._messages.keys(): - message_1 = self.get(key) - message_2 = other.get(key) - if ( - message_1 is None - or message_2 is None - or not message_1.is_identical(message_2) - ): - return False - return dict(self.mime_headers) == dict(other.mime_headers) diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/checkers.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/checkers.py deleted file mode 100644 index df7c3ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/checkers.py +++ /dev/null @@ -1,168 +0,0 @@ -""" - babel.messages.checkers - ~~~~~~~~~~~~~~~~~~~~~~~ - - Various routines that help with validation of translations. - - :since: version 0.9 - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" -from __future__ import annotations - -from collections.abc import Callable - -from babel.messages.catalog import PYTHON_FORMAT, Catalog, Message, TranslationError - -#: list of format chars that are compatible to each other -_string_format_compatibilities = [ - {'i', 'd', 'u'}, - {'x', 'X'}, - {'f', 'F', 'g', 'G'}, -] - - -def num_plurals(catalog: Catalog | None, message: Message) -> None: - """Verify the number of plurals in the translation.""" - if not message.pluralizable: - if not isinstance(message.string, str): - raise TranslationError("Found plural forms for non-pluralizable " - "message") - return - - # skip further tests if no catalog is provided. - elif catalog is None: - return - - msgstrs = message.string - if not isinstance(msgstrs, (list, tuple)): - msgstrs = (msgstrs,) - if len(msgstrs) != catalog.num_plurals: - raise TranslationError("Wrong number of plural forms (expected %d)" % - catalog.num_plurals) - - -def python_format(catalog: Catalog | None, message: Message) -> None: - """Verify the format string placeholders in the translation.""" - if 'python-format' not in message.flags: - return - msgids = message.id - if not isinstance(msgids, (list, tuple)): - msgids = (msgids,) - msgstrs = message.string - if not isinstance(msgstrs, (list, tuple)): - msgstrs = (msgstrs,) - - for msgid, msgstr in zip(msgids, msgstrs): - if msgstr: - _validate_format(msgid, msgstr) - - -def _validate_format(format: str, alternative: str) -> None: - """Test format string `alternative` against `format`. `format` can be the - msgid of a message and `alternative` one of the `msgstr`\\s. The two - arguments are not interchangeable as `alternative` may contain less - placeholders if `format` uses named placeholders. - - If the string formatting of `alternative` is compatible to `format` the - function returns `None`, otherwise a `TranslationError` is raised. - - Examples for compatible format strings: - - >>> _validate_format('Hello %s!', 'Hallo %s!') - >>> _validate_format('Hello %i!', 'Hallo %d!') - - Example for an incompatible format strings: - - >>> _validate_format('Hello %(name)s!', 'Hallo %s!') - Traceback (most recent call last): - ... - TranslationError: the format strings are of different kinds - - This function is used by the `python_format` checker. - - :param format: The original format string - :param alternative: The alternative format string that should be checked - against format - :raises TranslationError: on formatting errors - """ - - def _parse(string: str) -> list[tuple[str, str]]: - result: list[tuple[str, str]] = [] - for match in PYTHON_FORMAT.finditer(string): - name, format, typechar = match.groups() - if typechar == '%' and name is None: - continue - result.append((name, str(typechar))) - return result - - def _compatible(a: str, b: str) -> bool: - if a == b: - return True - for set in _string_format_compatibilities: - if a in set and b in set: - return True - return False - - def _check_positional(results: list[tuple[str, str]]) -> bool: - positional = None - for name, _char in results: - if positional is None: - positional = name is None - else: - if (name is None) != positional: - raise TranslationError('format string mixes positional ' - 'and named placeholders') - return bool(positional) - - a, b = map(_parse, (format, alternative)) - - if not a: - return - - # now check if both strings are positional or named - a_positional, b_positional = map(_check_positional, (a, b)) - if a_positional and not b_positional and not b: - raise TranslationError('placeholders are incompatible') - elif a_positional != b_positional: - raise TranslationError('the format strings are of different kinds') - - # if we are operating on positional strings both must have the - # same number of format chars and those must be compatible - if a_positional: - if len(a) != len(b): - raise TranslationError('positional format placeholders are ' - 'unbalanced') - for idx, ((_, first), (_, second)) in enumerate(zip(a, b)): - if not _compatible(first, second): - raise TranslationError('incompatible format for placeholder ' - '%d: %r and %r are not compatible' % - (idx + 1, first, second)) - - # otherwise the second string must not have names the first one - # doesn't have and the types of those included must be compatible - else: - type_map = dict(a) - for name, typechar in b: - if name not in type_map: - raise TranslationError(f'unknown named placeholder {name!r}') - elif not _compatible(typechar, type_map[name]): - raise TranslationError( - f'incompatible format for placeholder {name!r}: ' - f'{typechar!r} and {type_map[name]!r} are not compatible', - ) - - -def _find_checkers() -> list[Callable[[Catalog | None, Message], object]]: - from babel.messages._compat import find_entrypoints - checkers: list[Callable[[Catalog | None, Message], object]] = [] - checkers.extend(load() for (name, load) in find_entrypoints('babel.checkers')) - if len(checkers) == 0: - # if entrypoints are not available or no usable egg-info was found - # (see #230), just resort to hard-coded checkers - return [num_plurals, python_format] - return checkers - - -checkers: list[Callable[[Catalog | None, Message], object]] = _find_checkers() diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/extract.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/extract.py deleted file mode 100644 index 7f4230f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/extract.py +++ /dev/null @@ -1,852 +0,0 @@ -""" - babel.messages.extract - ~~~~~~~~~~~~~~~~~~~~~~ - - Basic infrastructure for extracting localizable messages from source files. - - This module defines an extensible system for collecting localizable message - strings from a variety of sources. A native extractor for Python source - files is builtin, extractors for other sources can be added using very - simple plugins. - - The main entry points into the extraction functionality are the functions - `extract_from_dir` and `extract_from_file`. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" -from __future__ import annotations - -import ast -import io -import os -import sys -import tokenize -from collections.abc import ( - Callable, - Collection, - Generator, - Iterable, - Mapping, - MutableSequence, -) -from functools import lru_cache -from os.path import relpath -from textwrap import dedent -from tokenize import COMMENT, NAME, NL, OP, STRING, generate_tokens -from typing import TYPE_CHECKING, Any, TypedDict - -from babel.messages._compat import find_entrypoints -from babel.util import parse_encoding, parse_future_flags, pathmatch - -if TYPE_CHECKING: - from typing import IO, Final, Protocol - - from _typeshed import SupportsItems, SupportsRead, SupportsReadline - from typing_extensions import TypeAlias - - class _PyOptions(TypedDict, total=False): - encoding: str - - class _JSOptions(TypedDict, total=False): - encoding: str - jsx: bool - template_string: bool - parse_template_string: bool - - class _FileObj(SupportsRead[bytes], SupportsReadline[bytes], Protocol): - def seek(self, __offset: int, __whence: int = ...) -> int: ... - def tell(self) -> int: ... - - _SimpleKeyword: TypeAlias = tuple[int | tuple[int, int] | tuple[int, str], ...] | None - _Keyword: TypeAlias = dict[int | None, _SimpleKeyword] | _SimpleKeyword - - # 5-tuple of (filename, lineno, messages, comments, context) - _FileExtractionResult: TypeAlias = tuple[str, int, str | tuple[str, ...], list[str], str | None] - - # 4-tuple of (lineno, message, comments, context) - _ExtractionResult: TypeAlias = tuple[int, str | tuple[str, ...], list[str], str | None] - - # Required arguments: fileobj, keywords, comment_tags, options - # Return value: Iterable of (lineno, message, comments, context) - _CallableExtractionMethod: TypeAlias = Callable[ - [_FileObj | IO[bytes], Mapping[str, _Keyword], Collection[str], Mapping[str, Any]], - Iterable[_ExtractionResult], - ] - - _ExtractionMethod: TypeAlias = _CallableExtractionMethod | str - -GROUP_NAME: Final[str] = 'babel.extractors' - -DEFAULT_KEYWORDS: dict[str, _Keyword] = { - '_': None, - 'gettext': None, - 'ngettext': (1, 2), - 'ugettext': None, - 'ungettext': (1, 2), - 'dgettext': (2,), - 'dngettext': (2, 3), - 'N_': None, - 'pgettext': ((1, 'c'), 2), - 'npgettext': ((1, 'c'), 2, 3), -} - -DEFAULT_MAPPING: list[tuple[str, str]] = [('**.py', 'python')] - -# New tokens in Python 3.12, or None on older versions -FSTRING_START = getattr(tokenize, "FSTRING_START", None) -FSTRING_MIDDLE = getattr(tokenize, "FSTRING_MIDDLE", None) -FSTRING_END = getattr(tokenize, "FSTRING_END", None) - - -def _strip_comment_tags(comments: MutableSequence[str], tags: Iterable[str]): - """Helper function for `extract` that strips comment tags from strings - in a list of comment lines. This functions operates in-place. - """ - def _strip(line: str): - for tag in tags: - if line.startswith(tag): - return line[len(tag):].strip() - return line - comments[:] = map(_strip, comments) - - -def default_directory_filter(dirpath: str | os.PathLike[str]) -> bool: - subdir = os.path.basename(dirpath) - # Legacy default behavior: ignore dot and underscore directories - return not (subdir.startswith('.') or subdir.startswith('_')) - - -def extract_from_dir( - dirname: str | os.PathLike[str] | None = None, - method_map: Iterable[tuple[str, str]] = DEFAULT_MAPPING, - options_map: SupportsItems[str, dict[str, Any]] | None = None, - keywords: Mapping[str, _Keyword] = DEFAULT_KEYWORDS, - comment_tags: Collection[str] = (), - callback: Callable[[str, str, dict[str, Any]], object] | None = None, - strip_comment_tags: bool = False, - directory_filter: Callable[[str], bool] | None = None, -) -> Generator[_FileExtractionResult, None, None]: - """Extract messages from any source files found in the given directory. - - This function generates tuples of the form ``(filename, lineno, message, - comments, context)``. - - Which extraction method is used per file is determined by the `method_map` - parameter, which maps extended glob patterns to extraction method names. - For example, the following is the default mapping: - - >>> method_map = [ - ... ('**.py', 'python') - ... ] - - This basically says that files with the filename extension ".py" at any - level inside the directory should be processed by the "python" extraction - method. Files that don't match any of the mapping patterns are ignored. See - the documentation of the `pathmatch` function for details on the pattern - syntax. - - The following extended mapping would also use the "genshi" extraction - method on any file in "templates" subdirectory: - - >>> method_map = [ - ... ('**/templates/**.*', 'genshi'), - ... ('**.py', 'python') - ... ] - - The dictionary provided by the optional `options_map` parameter augments - these mappings. It uses extended glob patterns as keys, and the values are - dictionaries mapping options names to option values (both strings). - - The glob patterns of the `options_map` do not necessarily need to be the - same as those used in the method mapping. For example, while all files in - the ``templates`` folders in an application may be Genshi applications, the - options for those files may differ based on extension: - - >>> options_map = { - ... '**/templates/**.txt': { - ... 'template_class': 'genshi.template:TextTemplate', - ... 'encoding': 'latin-1' - ... }, - ... '**/templates/**.html': { - ... 'include_attrs': '' - ... } - ... } - - :param dirname: the path to the directory to extract messages from. If - not given the current working directory is used. - :param method_map: a list of ``(pattern, method)`` tuples that maps of - extraction method names to extended glob patterns - :param options_map: a dictionary of additional options (optional) - :param keywords: a dictionary mapping keywords (i.e. names of functions - that should be recognized as translation functions) to - tuples that specify which of their arguments contain - localizable strings - :param comment_tags: a list of tags of translator comments to search for - and include in the results - :param callback: a function that is called for every file that message are - extracted from, just before the extraction itself is - performed; the function is passed the filename, the name - of the extraction method and and the options dictionary as - positional arguments, in that order - :param strip_comment_tags: a flag that if set to `True` causes all comment - tags to be removed from the collected comments. - :param directory_filter: a callback to determine whether a directory should - be recursed into. Receives the full directory path; - should return True if the directory is valid. - :see: `pathmatch` - """ - if dirname is None: - dirname = os.getcwd() - if options_map is None: - options_map = {} - if directory_filter is None: - directory_filter = default_directory_filter - - absname = os.path.abspath(dirname) - for root, dirnames, filenames in os.walk(absname): - dirnames[:] = [ - subdir for subdir in dirnames - if directory_filter(os.path.join(root, subdir)) - ] - dirnames.sort() - filenames.sort() - for filename in filenames: - filepath = os.path.join(root, filename).replace(os.sep, '/') - - yield from check_and_call_extract_file( - filepath, - method_map, - options_map, - callback, - keywords, - comment_tags, - strip_comment_tags, - dirpath=absname, - ) - - -def check_and_call_extract_file( - filepath: str | os.PathLike[str], - method_map: Iterable[tuple[str, str]], - options_map: SupportsItems[str, dict[str, Any]], - callback: Callable[[str, str, dict[str, Any]], object] | None, - keywords: Mapping[str, _Keyword], - comment_tags: Collection[str], - strip_comment_tags: bool, - dirpath: str | os.PathLike[str] | None = None, -) -> Generator[_FileExtractionResult, None, None]: - """Checks if the given file matches an extraction method mapping, and if so, calls extract_from_file. - - Note that the extraction method mappings are based relative to dirpath. - So, given an absolute path to a file `filepath`, we want to check using - just the relative path from `dirpath` to `filepath`. - - Yields 5-tuples (filename, lineno, messages, comments, context). - - :param filepath: An absolute path to a file that exists. - :param method_map: a list of ``(pattern, method)`` tuples that maps of - extraction method names to extended glob patterns - :param options_map: a dictionary of additional options (optional) - :param callback: a function that is called for every file that message are - extracted from, just before the extraction itself is - performed; the function is passed the filename, the name - of the extraction method and and the options dictionary as - positional arguments, in that order - :param keywords: a dictionary mapping keywords (i.e. names of functions - that should be recognized as translation functions) to - tuples that specify which of their arguments contain - localizable strings - :param comment_tags: a list of tags of translator comments to search for - and include in the results - :param strip_comment_tags: a flag that if set to `True` causes all comment - tags to be removed from the collected comments. - :param dirpath: the path to the directory to extract messages from. - :return: iterable of 5-tuples (filename, lineno, messages, comments, context) - :rtype: Iterable[tuple[str, int, str|tuple[str], list[str], str|None] - """ - # filename is the relative path from dirpath to the actual file - filename = relpath(filepath, dirpath) - - for pattern, method in method_map: - if not pathmatch(pattern, filename): - continue - - options = {} - for opattern, odict in options_map.items(): - if pathmatch(opattern, filename): - options = odict - break - if callback: - callback(filename, method, options) - for message_tuple in extract_from_file( - method, filepath, - keywords=keywords, - comment_tags=comment_tags, - options=options, - strip_comment_tags=strip_comment_tags, - ): - yield (filename, *message_tuple) - - break - - -def extract_from_file( - method: _ExtractionMethod, - filename: str | os.PathLike[str], - keywords: Mapping[str, _Keyword] = DEFAULT_KEYWORDS, - comment_tags: Collection[str] = (), - options: Mapping[str, Any] | None = None, - strip_comment_tags: bool = False, -) -> list[_ExtractionResult]: - """Extract messages from a specific file. - - This function returns a list of tuples of the form ``(lineno, message, comments, context)``. - - :param filename: the path to the file to extract messages from - :param method: a string specifying the extraction method (.e.g. "python") - :param keywords: a dictionary mapping keywords (i.e. names of functions - that should be recognized as translation functions) to - tuples that specify which of their arguments contain - localizable strings - :param comment_tags: a list of translator tags to search for and include - in the results - :param strip_comment_tags: a flag that if set to `True` causes all comment - tags to be removed from the collected comments. - :param options: a dictionary of additional options (optional) - :returns: list of tuples of the form ``(lineno, message, comments, context)`` - :rtype: list[tuple[int, str|tuple[str], list[str], str|None] - """ - if method == 'ignore': - return [] - - with open(filename, 'rb') as fileobj: - return list(extract(method, fileobj, keywords, comment_tags, - options, strip_comment_tags)) - - -def _match_messages_against_spec( - lineno: int, - messages: list[str | None], - comments: list[str], - fileobj: _FileObj, - spec: tuple[int | tuple[int, str], ...], -): - translatable = [] - context = None - - # last_index is 1 based like the keyword spec - last_index = len(messages) - for index in spec: - if isinstance(index, tuple): # (n, 'c') - context = messages[index[0] - 1] - continue - if last_index < index: - # Not enough arguments - return - message = messages[index - 1] - if message is None: - return - translatable.append(message) - - # keyword spec indexes are 1 based, therefore '-1' - if isinstance(spec[0], tuple): - # context-aware *gettext method - first_msg_index = spec[1] - 1 - else: - first_msg_index = spec[0] - 1 - # An empty string msgid isn't valid, emit a warning - if not messages[first_msg_index]: - filename = (getattr(fileobj, "name", None) or "(unknown)") - sys.stderr.write( - f"{filename}:{lineno}: warning: Empty msgid. It is reserved by GNU gettext: gettext(\"\") " - f"returns the header entry with meta information, not the empty string.\n", - ) - return - - translatable = tuple(translatable) - if len(translatable) == 1: - translatable = translatable[0] - - return lineno, translatable, comments, context - - -@lru_cache(maxsize=None) -def _find_extractor(name: str): - for ep_name, load in find_entrypoints(GROUP_NAME): - if ep_name == name: - return load() - return None - - -def extract( - method: _ExtractionMethod, - fileobj: _FileObj, - keywords: Mapping[str, _Keyword] = DEFAULT_KEYWORDS, - comment_tags: Collection[str] = (), - options: Mapping[str, Any] | None = None, - strip_comment_tags: bool = False, -) -> Generator[_ExtractionResult, None, None]: - """Extract messages from the given file-like object using the specified - extraction method. - - This function returns tuples of the form ``(lineno, message, comments, context)``. - - The implementation dispatches the actual extraction to plugins, based on the - value of the ``method`` parameter. - - >>> source = b'''# foo module - ... def run(argv): - ... print(_('Hello, world!')) - ... ''' - - >>> from io import BytesIO - >>> for message in extract('python', BytesIO(source)): - ... print(message) - (3, u'Hello, world!', [], None) - - :param method: an extraction method (a callable), or - a string specifying the extraction method (.e.g. "python"); - if this is a simple name, the extraction function will be - looked up by entry point; if it is an explicit reference - to a function (of the form ``package.module:funcname`` or - ``package.module.funcname``), the corresponding function - will be imported and used - :param fileobj: the file-like object the messages should be extracted from - :param keywords: a dictionary mapping keywords (i.e. names of functions - that should be recognized as translation functions) to - tuples that specify which of their arguments contain - localizable strings - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - :param strip_comment_tags: a flag that if set to `True` causes all comment - tags to be removed from the collected comments. - :raise ValueError: if the extraction method is not registered - :returns: iterable of tuples of the form ``(lineno, message, comments, context)`` - :rtype: Iterable[tuple[int, str|tuple[str], list[str], str|None] - """ - if callable(method): - func = method - elif ':' in method or '.' in method: - if ':' not in method: - lastdot = method.rfind('.') - module, attrname = method[:lastdot], method[lastdot + 1:] - else: - module, attrname = method.split(':', 1) - func = getattr(__import__(module, {}, {}, [attrname]), attrname) - else: - func = _find_extractor(method) - if func is None: - # if no named entry point was found, - # we resort to looking up a builtin extractor - func = _BUILTIN_EXTRACTORS.get(method) - - if func is None: - raise ValueError(f"Unknown extraction method {method!r}") - - results = func(fileobj, keywords.keys(), comment_tags, - options=options or {}) - - for lineno, funcname, messages, comments in results: - if not isinstance(messages, (list, tuple)): - messages = [messages] - if not messages: - continue - - specs = keywords[funcname] or None if funcname else None - # {None: x} may be collapsed into x for backwards compatibility. - if not isinstance(specs, dict): - specs = {None: specs} - - if strip_comment_tags: - _strip_comment_tags(comments, comment_tags) - - # None matches all arities. - for arity in (None, len(messages)): - try: - spec = specs[arity] - except KeyError: - continue - if spec is None: - spec = (1,) - result = _match_messages_against_spec(lineno, messages, comments, fileobj, spec) - if result is not None: - yield result - - -def extract_nothing( - fileobj: _FileObj, - keywords: Mapping[str, _Keyword], - comment_tags: Collection[str], - options: Mapping[str, Any], -) -> list[_ExtractionResult]: - """Pseudo extractor that does not actually extract anything, but simply - returns an empty list. - """ - return [] - - -def extract_python( - fileobj: IO[bytes], - keywords: Mapping[str, _Keyword], - comment_tags: Collection[str], - options: _PyOptions, -) -> Generator[_ExtractionResult, None, None]: - """Extract messages from Python source code. - - It returns an iterator yielding tuples in the following form ``(lineno, - funcname, message, comments)``. - - :param fileobj: the seekable, file-like object the messages should be - extracted from - :param keywords: a list of keywords (i.e. function names) that should be - recognized as translation functions - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - :rtype: ``iterator`` - """ - funcname = lineno = message_lineno = None - call_stack = -1 - buf = [] - messages = [] - translator_comments = [] - in_def = in_translator_comments = False - comment_tag = None - - encoding = parse_encoding(fileobj) or options.get('encoding', 'UTF-8') - future_flags = parse_future_flags(fileobj, encoding) - next_line = lambda: fileobj.readline().decode(encoding) - - tokens = generate_tokens(next_line) - - # Current prefix of a Python 3.12 (PEP 701) f-string, or None if we're not - # currently parsing one. - current_fstring_start = None - - for tok, value, (lineno, _), _, _ in tokens: - if call_stack == -1 and tok == NAME and value in ('def', 'class'): - in_def = True - elif tok == OP and value == '(': - if in_def: - # Avoid false positives for declarations such as: - # def gettext(arg='message'): - in_def = False - continue - if funcname: - call_stack += 1 - elif in_def and tok == OP and value == ':': - # End of a class definition without parens - in_def = False - continue - elif call_stack == -1 and tok == COMMENT: - # Strip the comment token from the line - value = value[1:].strip() - if in_translator_comments and \ - translator_comments[-1][0] == lineno - 1: - # We're already inside a translator comment, continue appending - translator_comments.append((lineno, value)) - continue - # If execution reaches this point, let's see if comment line - # starts with one of the comment tags - for comment_tag in comment_tags: - if value.startswith(comment_tag): - in_translator_comments = True - translator_comments.append((lineno, value)) - break - elif funcname and call_stack == 0: - nested = (tok == NAME and value in keywords) - if (tok == OP and value == ')') or nested: - if buf: - messages.append(''.join(buf)) - del buf[:] - else: - messages.append(None) - - messages = tuple(messages) if len(messages) > 1 else messages[0] - # Comments don't apply unless they immediately - # precede the message - if translator_comments and \ - translator_comments[-1][0] < message_lineno - 1: - translator_comments = [] - - yield (message_lineno, funcname, messages, - [comment[1] for comment in translator_comments]) - - funcname = lineno = message_lineno = None - call_stack = -1 - messages = [] - translator_comments = [] - in_translator_comments = False - if nested: - funcname = value - elif tok == STRING: - val = _parse_python_string(value, encoding, future_flags) - if val is not None: - if not message_lineno: - message_lineno = lineno - buf.append(val) - - # Python 3.12+, see https://peps.python.org/pep-0701/#new-tokens - elif tok == FSTRING_START: - current_fstring_start = value - if not message_lineno: - message_lineno = lineno - elif tok == FSTRING_MIDDLE: - if current_fstring_start is not None: - current_fstring_start += value - elif tok == FSTRING_END: - if current_fstring_start is not None: - fstring = current_fstring_start + value - val = _parse_python_string(fstring, encoding, future_flags) - if val is not None: - buf.append(val) - - elif tok == OP and value == ',': - if buf: - messages.append(''.join(buf)) - del buf[:] - else: - messages.append(None) - if translator_comments: - # We have translator comments, and since we're on a - # comma(,) user is allowed to break into a new line - # Let's increase the last comment's lineno in order - # for the comment to still be a valid one - old_lineno, old_comment = translator_comments.pop() - translator_comments.append((old_lineno + 1, old_comment)) - - elif tok != NL and not message_lineno: - message_lineno = lineno - elif call_stack > 0 and tok == OP and value == ')': - call_stack -= 1 - elif funcname and call_stack == -1: - funcname = None - elif tok == NAME and value in keywords: - funcname = value - - if current_fstring_start is not None and tok not in {FSTRING_START, FSTRING_MIDDLE}: - # In Python 3.12, tokens other than FSTRING_* mean the - # f-string is dynamic, so we don't wan't to extract it. - # And if it's FSTRING_END, we've already handled it above. - # Let's forget that we're in an f-string. - current_fstring_start = None - - -def _parse_python_string(value: str, encoding: str, future_flags: int) -> str | None: - # Unwrap quotes in a safe manner, maintaining the string's encoding - # https://sourceforge.net/tracker/?func=detail&atid=355470&aid=617979&group_id=5470 - code = compile( - f'# coding={str(encoding)}\n{value}', - '', - 'eval', - ast.PyCF_ONLY_AST | future_flags, - ) - if isinstance(code, ast.Expression): - body = code.body - if isinstance(body, ast.Constant): - return body.value - if isinstance(body, ast.JoinedStr): # f-string - if all(isinstance(node, ast.Constant) for node in body.values): - return ''.join(node.value for node in body.values) - # TODO: we could raise an error or warning when not all nodes are constants - return None - - -def extract_javascript( - fileobj: _FileObj, - keywords: Mapping[str, _Keyword], - comment_tags: Collection[str], - options: _JSOptions, - lineno: int = 1, -) -> Generator[_ExtractionResult, None, None]: - """Extract messages from JavaScript source code. - - :param fileobj: the seekable, file-like object the messages should be - extracted from - :param keywords: a list of keywords (i.e. function names) that should be - recognized as translation functions - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - Supported options are: - * `jsx` -- set to false to disable JSX/E4X support. - * `template_string` -- if `True`, supports gettext(`key`) - * `parse_template_string` -- if `True` will parse the - contents of javascript - template strings. - :param lineno: line number offset (for parsing embedded fragments) - """ - from babel.messages.jslexer import Token, tokenize, unquote_string - funcname = message_lineno = None - messages = [] - last_argument = None - translator_comments = [] - concatenate_next = False - encoding = options.get('encoding', 'utf-8') - last_token = None - call_stack = -1 - dotted = any('.' in kw for kw in keywords) - for token in tokenize( - fileobj.read().decode(encoding), - jsx=options.get("jsx", True), - template_string=options.get("template_string", True), - dotted=dotted, - lineno=lineno, - ): - if ( # Turn keyword`foo` expressions into keyword("foo") calls: - funcname and # have a keyword... - (last_token and last_token.type == 'name') and # we've seen nothing after the keyword... - token.type == 'template_string' # this is a template string - ): - message_lineno = token.lineno - messages = [unquote_string(token.value)] - call_stack = 0 - token = Token('operator', ')', token.lineno) - - if options.get('parse_template_string') and not funcname and token.type == 'template_string': - yield from parse_template_string(token.value, keywords, comment_tags, options, token.lineno) - - elif token.type == 'operator' and token.value == '(': - if funcname: - message_lineno = token.lineno - call_stack += 1 - - elif call_stack == -1 and token.type == 'linecomment': - value = token.value[2:].strip() - if translator_comments and \ - translator_comments[-1][0] == token.lineno - 1: - translator_comments.append((token.lineno, value)) - continue - - for comment_tag in comment_tags: - if value.startswith(comment_tag): - translator_comments.append((token.lineno, value.strip())) - break - - elif token.type == 'multilinecomment': - # only one multi-line comment may precede a translation - translator_comments = [] - value = token.value[2:-2].strip() - for comment_tag in comment_tags: - if value.startswith(comment_tag): - lines = value.splitlines() - if lines: - lines[0] = lines[0].strip() - lines[1:] = dedent('\n'.join(lines[1:])).splitlines() - for offset, line in enumerate(lines): - translator_comments.append((token.lineno + offset, - line)) - break - - elif funcname and call_stack == 0: - if token.type == 'operator' and token.value == ')': - if last_argument is not None: - messages.append(last_argument) - if len(messages) > 1: - messages = tuple(messages) - elif messages: - messages = messages[0] - else: - messages = None - - # Comments don't apply unless they immediately precede the - # message - if translator_comments and \ - translator_comments[-1][0] < message_lineno - 1: - translator_comments = [] - - if messages is not None: - yield (message_lineno, funcname, messages, - [comment[1] for comment in translator_comments]) - - funcname = message_lineno = last_argument = None - concatenate_next = False - translator_comments = [] - messages = [] - call_stack = -1 - - elif token.type in ('string', 'template_string'): - new_value = unquote_string(token.value) - if concatenate_next: - last_argument = (last_argument or '') + new_value - concatenate_next = False - else: - last_argument = new_value - - elif token.type == 'operator': - if token.value == ',': - if last_argument is not None: - messages.append(last_argument) - last_argument = None - else: - messages.append(None) - concatenate_next = False - elif token.value == '+': - concatenate_next = True - - elif call_stack > 0 and token.type == 'operator' \ - and token.value == ')': - call_stack -= 1 - - elif funcname and call_stack == -1: - funcname = None - - elif call_stack == -1 and token.type == 'name' and \ - token.value in keywords and \ - (last_token is None or last_token.type != 'name' or - last_token.value != 'function'): - funcname = token.value - - last_token = token - - -def parse_template_string( - template_string: str, - keywords: Mapping[str, _Keyword], - comment_tags: Collection[str], - options: _JSOptions, - lineno: int = 1, -) -> Generator[_ExtractionResult, None, None]: - """Parse JavaScript template string. - - :param template_string: the template string to be parsed - :param keywords: a list of keywords (i.e. function names) that should be - recognized as translation functions - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - :param lineno: starting line number (optional) - """ - from babel.messages.jslexer import line_re - prev_character = None - level = 0 - inside_str = False - expression_contents = '' - for character in template_string[1:-1]: - if not inside_str and character in ('"', "'", '`'): - inside_str = character - elif inside_str == character and prev_character != r'\\': - inside_str = False - if level: - expression_contents += character - if not inside_str: - if character == '{' and prev_character == '$': - level += 1 - elif level and character == '}': - level -= 1 - if level == 0 and expression_contents: - expression_contents = expression_contents[0:-1] - fake_file_obj = io.BytesIO(expression_contents.encode()) - yield from extract_javascript(fake_file_obj, keywords, comment_tags, options, lineno) - lineno += len(line_re.findall(expression_contents)) - expression_contents = '' - prev_character = character - - -_BUILTIN_EXTRACTORS = { - 'ignore': extract_nothing, - 'python': extract_python, - 'javascript': extract_javascript, -} diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/frontend.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/frontend.py deleted file mode 100644 index 29e5a2a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/frontend.py +++ /dev/null @@ -1,1202 +0,0 @@ -""" - babel.messages.frontend - ~~~~~~~~~~~~~~~~~~~~~~~ - - Frontends for the message extraction functionality. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import annotations - -import datetime -import fnmatch -import logging -import optparse -import os -import re -import shutil -import sys -import tempfile -import warnings -from configparser import RawConfigParser -from io import StringIO -from typing import BinaryIO, Iterable, Literal - -from babel import Locale, localedata -from babel import __version__ as VERSION -from babel.core import UnknownLocaleError -from babel.messages.catalog import DEFAULT_HEADER, Catalog -from babel.messages.extract import ( - DEFAULT_KEYWORDS, - DEFAULT_MAPPING, - check_and_call_extract_file, - extract_from_dir, -) -from babel.messages.mofile import write_mo -from babel.messages.pofile import read_po, write_po -from babel.util import LOCALTZ - -log = logging.getLogger('babel') - - -class BaseError(Exception): - pass - - -class OptionError(BaseError): - pass - - -class SetupError(BaseError): - pass - - -class ConfigurationError(BaseError): - """ - Raised for errors in configuration files. - """ - - -def listify_value(arg, split=None): - """ - Make a list out of an argument. - - Values from `distutils` argument parsing are always single strings; - values from `optparse` parsing may be lists of strings that may need - to be further split. - - No matter the input, this function returns a flat list of whitespace-trimmed - strings, with `None` values filtered out. - - >>> listify_value("foo bar") - ['foo', 'bar'] - >>> listify_value(["foo bar"]) - ['foo', 'bar'] - >>> listify_value([["foo"], "bar"]) - ['foo', 'bar'] - >>> listify_value([["foo"], ["bar", None, "foo"]]) - ['foo', 'bar', 'foo'] - >>> listify_value("foo, bar, quux", ",") - ['foo', 'bar', 'quux'] - - :param arg: A string or a list of strings - :param split: The argument to pass to `str.split()`. - :return: - """ - out = [] - - if not isinstance(arg, (list, tuple)): - arg = [arg] - - for val in arg: - if val is None: - continue - if isinstance(val, (list, tuple)): - out.extend(listify_value(val, split=split)) - continue - out.extend(s.strip() for s in str(val).split(split)) - assert all(isinstance(val, str) for val in out) - return out - - -class CommandMixin: - # This class is a small shim between Distutils commands and - # optparse option parsing in the frontend command line. - - #: Option name to be input as `args` on the script command line. - as_args = None - - #: Options which allow multiple values. - #: This is used by the `optparse` transmogrification code. - multiple_value_options = () - - #: Options which are booleans. - #: This is used by the `optparse` transmogrification code. - # (This is actually used by distutils code too, but is never - # declared in the base class.) - boolean_options = () - - #: Option aliases, to retain standalone command compatibility. - #: Distutils does not support option aliases, but optparse does. - #: This maps the distutils argument name to an iterable of aliases - #: that are usable with optparse. - option_aliases = {} - - #: Choices for options that needed to be restricted to specific - #: list of choices. - option_choices = {} - - #: Log object. To allow replacement in the script command line runner. - log = log - - def __init__(self, dist=None): - # A less strict version of distutils' `__init__`. - self.distribution = dist - self.initialize_options() - self._dry_run = None - self.verbose = False - self.force = None - self.help = 0 - self.finalized = 0 - - def initialize_options(self): - pass - - def ensure_finalized(self): - if not self.finalized: - self.finalize_options() - self.finalized = 1 - - def finalize_options(self): - raise RuntimeError( - f"abstract method -- subclass {self.__class__} must override", - ) - - -class CompileCatalog(CommandMixin): - description = 'compile message catalogs to binary MO files' - user_options = [ - ('domain=', 'D', - "domains of PO files (space separated list, default 'messages')"), - ('directory=', 'd', - 'path to base directory containing the catalogs'), - ('input-file=', 'i', - 'name of the input file'), - ('output-file=', 'o', - "name of the output file (default " - "'//LC_MESSAGES/.mo')"), - ('locale=', 'l', - 'locale of the catalog to compile'), - ('use-fuzzy', 'f', - 'also include fuzzy translations'), - ('statistics', None, - 'print statistics about translations'), - ] - boolean_options = ['use-fuzzy', 'statistics'] - - def initialize_options(self): - self.domain = 'messages' - self.directory = None - self.input_file = None - self.output_file = None - self.locale = None - self.use_fuzzy = False - self.statistics = False - - def finalize_options(self): - self.domain = listify_value(self.domain) - if not self.input_file and not self.directory: - raise OptionError('you must specify either the input file or the base directory') - if not self.output_file and not self.directory: - raise OptionError('you must specify either the output file or the base directory') - - def run(self): - n_errors = 0 - for domain in self.domain: - for errors in self._run_domain(domain).values(): - n_errors += len(errors) - if n_errors: - self.log.error('%d errors encountered.', n_errors) - return (1 if n_errors else 0) - - def _run_domain(self, domain): - po_files = [] - mo_files = [] - - if not self.input_file: - if self.locale: - po_files.append((self.locale, - os.path.join(self.directory, self.locale, - 'LC_MESSAGES', - f"{domain}.po"))) - mo_files.append(os.path.join(self.directory, self.locale, - 'LC_MESSAGES', - f"{domain}.mo")) - else: - for locale in os.listdir(self.directory): - po_file = os.path.join(self.directory, locale, - 'LC_MESSAGES', f"{domain}.po") - if os.path.exists(po_file): - po_files.append((locale, po_file)) - mo_files.append(os.path.join(self.directory, locale, - 'LC_MESSAGES', - f"{domain}.mo")) - else: - po_files.append((self.locale, self.input_file)) - if self.output_file: - mo_files.append(self.output_file) - else: - mo_files.append(os.path.join(self.directory, self.locale, - 'LC_MESSAGES', - f"{domain}.mo")) - - if not po_files: - raise OptionError('no message catalogs found') - - catalogs_and_errors = {} - - for idx, (locale, po_file) in enumerate(po_files): - mo_file = mo_files[idx] - with open(po_file, 'rb') as infile: - catalog = read_po(infile, locale) - - if self.statistics: - translated = 0 - for message in list(catalog)[1:]: - if message.string: - translated += 1 - percentage = 0 - if len(catalog): - percentage = translated * 100 // len(catalog) - self.log.info( - '%d of %d messages (%d%%) translated in %s', - translated, len(catalog), percentage, po_file, - ) - - if catalog.fuzzy and not self.use_fuzzy: - self.log.info('catalog %s is marked as fuzzy, skipping', po_file) - continue - - catalogs_and_errors[catalog] = catalog_errors = list(catalog.check()) - for message, errors in catalog_errors: - for error in errors: - self.log.error( - 'error: %s:%d: %s', po_file, message.lineno, error, - ) - - self.log.info('compiling catalog %s to %s', po_file, mo_file) - - with open(mo_file, 'wb') as outfile: - write_mo(outfile, catalog, use_fuzzy=self.use_fuzzy) - - return catalogs_and_errors - - -def _make_directory_filter(ignore_patterns): - """ - Build a directory_filter function based on a list of ignore patterns. - """ - - def cli_directory_filter(dirname): - basename = os.path.basename(dirname) - return not any( - fnmatch.fnmatch(basename, ignore_pattern) - for ignore_pattern - in ignore_patterns - ) - - return cli_directory_filter - - -class ExtractMessages(CommandMixin): - description = 'extract localizable strings from the project code' - user_options = [ - ('charset=', None, - 'charset to use in the output file (default "utf-8")'), - ('keywords=', 'k', - 'space-separated list of keywords to look for in addition to the ' - 'defaults (may be repeated multiple times)'), - ('no-default-keywords', None, - 'do not include the default keywords'), - ('mapping-file=', 'F', - 'path to the mapping configuration file'), - ('no-location', None, - 'do not include location comments with filename and line number'), - ('add-location=', None, - 'location lines format. If it is not given or "full", it generates ' - 'the lines with both file name and line number. If it is "file", ' - 'the line number part is omitted. If it is "never", it completely ' - 'suppresses the lines (same as --no-location).'), - ('omit-header', None, - 'do not include msgid "" entry in header'), - ('output-file=', 'o', - 'name of the output file'), - ('width=', 'w', - 'set output line width (default 76)'), - ('no-wrap', None, - 'do not break long message lines, longer than the output line width, ' - 'into several lines'), - ('sort-output', None, - 'generate sorted output (default False)'), - ('sort-by-file', None, - 'sort output by file location (default False)'), - ('msgid-bugs-address=', None, - 'set report address for msgid'), - ('copyright-holder=', None, - 'set copyright holder in output'), - ('project=', None, - 'set project name in output'), - ('version=', None, - 'set project version in output'), - ('add-comments=', 'c', - 'place comment block with TAG (or those preceding keyword lines) in ' - 'output file. Separate multiple TAGs with commas(,)'), # TODO: Support repetition of this argument - ('strip-comments', 's', - 'strip the comment TAGs from the comments.'), - ('input-paths=', None, - 'files or directories that should be scanned for messages. Separate multiple ' - 'files or directories with commas(,)'), # TODO: Support repetition of this argument - ('input-dirs=', None, # TODO (3.x): Remove me. - 'alias for input-paths (does allow files as well as directories).'), - ('ignore-dirs=', None, - 'Patterns for directories to ignore when scanning for messages. ' - 'Separate multiple patterns with spaces (default ".* ._")'), - ('header-comment=', None, - 'header comment for the catalog'), - ('last-translator=', None, - 'set the name and email of the last translator in output'), - ] - boolean_options = [ - 'no-default-keywords', 'no-location', 'omit-header', 'no-wrap', - 'sort-output', 'sort-by-file', 'strip-comments', - ] - as_args = 'input-paths' - multiple_value_options = ( - 'add-comments', - 'keywords', - 'ignore-dirs', - ) - option_aliases = { - 'keywords': ('--keyword',), - 'mapping-file': ('--mapping',), - 'output-file': ('--output',), - 'strip-comments': ('--strip-comment-tags',), - 'last-translator': ('--last-translator',), - } - option_choices = { - 'add-location': ('full', 'file', 'never'), - } - - def initialize_options(self): - self.charset = 'utf-8' - self.keywords = None - self.no_default_keywords = False - self.mapping_file = None - self.no_location = False - self.add_location = None - self.omit_header = False - self.output_file = None - self.input_dirs = None - self.input_paths = None - self.width = None - self.no_wrap = False - self.sort_output = False - self.sort_by_file = False - self.msgid_bugs_address = None - self.copyright_holder = None - self.project = None - self.version = None - self.add_comments = None - self.strip_comments = False - self.include_lineno = True - self.ignore_dirs = None - self.header_comment = None - self.last_translator = None - - def finalize_options(self): - if self.input_dirs: - if not self.input_paths: - self.input_paths = self.input_dirs - else: - raise OptionError( - 'input-dirs and input-paths are mutually exclusive', - ) - - keywords = {} if self.no_default_keywords else DEFAULT_KEYWORDS.copy() - - keywords.update(parse_keywords(listify_value(self.keywords))) - - self.keywords = keywords - - if not self.keywords: - raise OptionError( - 'you must specify new keywords if you disable the default ones', - ) - - if not self.output_file: - raise OptionError('no output file specified') - if self.no_wrap and self.width: - raise OptionError( - "'--no-wrap' and '--width' are mutually exclusive", - ) - if not self.no_wrap and not self.width: - self.width = 76 - elif self.width is not None: - self.width = int(self.width) - - if self.sort_output and self.sort_by_file: - raise OptionError( - "'--sort-output' and '--sort-by-file' are mutually exclusive", - ) - - if self.input_paths: - if isinstance(self.input_paths, str): - self.input_paths = re.split(r',\s*', self.input_paths) - elif self.distribution is not None: - self.input_paths = dict.fromkeys([ - k.split('.', 1)[0] - for k in (self.distribution.packages or ()) - ]).keys() - else: - self.input_paths = [] - - if not self.input_paths: - raise OptionError("no input files or directories specified") - - for path in self.input_paths: - if not os.path.exists(path): - raise OptionError(f"Input path: {path} does not exist") - - self.add_comments = listify_value(self.add_comments or (), ",") - - if self.distribution: - if not self.project: - self.project = self.distribution.get_name() - if not self.version: - self.version = self.distribution.get_version() - - if self.add_location == 'never': - self.no_location = True - elif self.add_location == 'file': - self.include_lineno = False - - ignore_dirs = listify_value(self.ignore_dirs) - if ignore_dirs: - self.directory_filter = _make_directory_filter(ignore_dirs) - else: - self.directory_filter = None - - def _build_callback(self, path: str): - def callback(filename: str, method: str, options: dict): - if method == 'ignore': - return - - # If we explicitly provide a full filepath, just use that. - # Otherwise, path will be the directory path and filename - # is the relative path from that dir to the file. - # So we can join those to get the full filepath. - if os.path.isfile(path): - filepath = path - else: - filepath = os.path.normpath(os.path.join(path, filename)) - - optstr = '' - if options: - opt_values = ", ".join(f'{k}="{v}"' for k, v in options.items()) - optstr = f" ({opt_values})" - self.log.info('extracting messages from %s%s', filepath, optstr) - - return callback - - def run(self): - mappings = self._get_mappings() - with open(self.output_file, 'wb') as outfile: - catalog = Catalog(project=self.project, - version=self.version, - msgid_bugs_address=self.msgid_bugs_address, - copyright_holder=self.copyright_holder, - charset=self.charset, - header_comment=(self.header_comment or DEFAULT_HEADER), - last_translator=self.last_translator) - - for path, method_map, options_map in mappings: - callback = self._build_callback(path) - if os.path.isfile(path): - current_dir = os.getcwd() - extracted = check_and_call_extract_file( - path, method_map, options_map, - callback, self.keywords, self.add_comments, - self.strip_comments, current_dir, - ) - else: - extracted = extract_from_dir( - path, method_map, options_map, - keywords=self.keywords, - comment_tags=self.add_comments, - callback=callback, - strip_comment_tags=self.strip_comments, - directory_filter=self.directory_filter, - ) - for filename, lineno, message, comments, context in extracted: - if os.path.isfile(path): - filepath = filename # already normalized - else: - filepath = os.path.normpath(os.path.join(path, filename)) - - catalog.add(message, None, [(filepath, lineno)], - auto_comments=comments, context=context) - - self.log.info('writing PO template file to %s', self.output_file) - write_po(outfile, catalog, width=self.width, - no_location=self.no_location, - omit_header=self.omit_header, - sort_output=self.sort_output, - sort_by_file=self.sort_by_file, - include_lineno=self.include_lineno) - - def _get_mappings(self): - mappings = [] - - if self.mapping_file: - if self.mapping_file.endswith(".toml"): - with open(self.mapping_file, "rb") as fileobj: - file_style = ( - "pyproject.toml" - if os.path.basename(self.mapping_file) == "pyproject.toml" - else "standalone" - ) - method_map, options_map = _parse_mapping_toml( - fileobj, - filename=self.mapping_file, - style=file_style, - ) - else: - with open(self.mapping_file) as fileobj: - method_map, options_map = parse_mapping_cfg(fileobj, filename=self.mapping_file) - for path in self.input_paths: - mappings.append((path, method_map, options_map)) - - elif getattr(self.distribution, 'message_extractors', None): - message_extractors = self.distribution.message_extractors - for path, mapping in message_extractors.items(): - if isinstance(mapping, str): - method_map, options_map = parse_mapping_cfg(StringIO(mapping)) - else: - method_map, options_map = [], {} - for pattern, method, options in mapping: - method_map.append((pattern, method)) - options_map[pattern] = options or {} - mappings.append((path, method_map, options_map)) - - else: - for path in self.input_paths: - mappings.append((path, DEFAULT_MAPPING, {})) - - return mappings - - -class InitCatalog(CommandMixin): - description = 'create a new catalog based on a POT file' - user_options = [ - ('domain=', 'D', - "domain of PO file (default 'messages')"), - ('input-file=', 'i', - 'name of the input file'), - ('output-dir=', 'd', - 'path to output directory'), - ('output-file=', 'o', - "name of the output file (default " - "'//LC_MESSAGES/.po')"), - ('locale=', 'l', - 'locale for the new localized catalog'), - ('width=', 'w', - 'set output line width (default 76)'), - ('no-wrap', None, - 'do not break long message lines, longer than the output line width, ' - 'into several lines'), - ] - boolean_options = ['no-wrap'] - - def initialize_options(self): - self.output_dir = None - self.output_file = None - self.input_file = None - self.locale = None - self.domain = 'messages' - self.no_wrap = False - self.width = None - - def finalize_options(self): - if not self.input_file: - raise OptionError('you must specify the input file') - - if not self.locale: - raise OptionError('you must provide a locale for the new catalog') - try: - self._locale = Locale.parse(self.locale) - except UnknownLocaleError as e: - raise OptionError(e) from e - - if not self.output_file and not self.output_dir: - raise OptionError('you must specify the output directory') - if not self.output_file: - self.output_file = os.path.join(self.output_dir, self.locale, - 'LC_MESSAGES', f"{self.domain}.po") - - if not os.path.exists(os.path.dirname(self.output_file)): - os.makedirs(os.path.dirname(self.output_file)) - if self.no_wrap and self.width: - raise OptionError("'--no-wrap' and '--width' are mutually exclusive") - if not self.no_wrap and not self.width: - self.width = 76 - elif self.width is not None: - self.width = int(self.width) - - def run(self): - self.log.info( - 'creating catalog %s based on %s', self.output_file, self.input_file, - ) - - with open(self.input_file, 'rb') as infile: - # Although reading from the catalog template, read_po must be fed - # the locale in order to correctly calculate plurals - catalog = read_po(infile, locale=self.locale) - - catalog.locale = self._locale - catalog.revision_date = datetime.datetime.now(LOCALTZ) - catalog.fuzzy = False - - with open(self.output_file, 'wb') as outfile: - write_po(outfile, catalog, width=self.width) - - -class UpdateCatalog(CommandMixin): - description = 'update message catalogs from a POT file' - user_options = [ - ('domain=', 'D', - "domain of PO file (default 'messages')"), - ('input-file=', 'i', - 'name of the input file'), - ('output-dir=', 'd', - 'path to base directory containing the catalogs'), - ('output-file=', 'o', - "name of the output file (default " - "'//LC_MESSAGES/.po')"), - ('omit-header', None, - "do not include msgid "" entry in header"), - ('locale=', 'l', - 'locale of the catalog to compile'), - ('width=', 'w', - 'set output line width (default 76)'), - ('no-wrap', None, - 'do not break long message lines, longer than the output line width, ' - 'into several lines'), - ('ignore-obsolete=', None, - 'whether to omit obsolete messages from the output'), - ('init-missing=', None, - 'if any output files are missing, initialize them first'), - ('no-fuzzy-matching', 'N', - 'do not use fuzzy matching'), - ('update-header-comment', None, - 'update target header comment'), - ('previous', None, - 'keep previous msgids of translated messages'), - ('check=', None, - 'don\'t update the catalog, just return the status. Return code 0 ' - 'means nothing would change. Return code 1 means that the catalog ' - 'would be updated'), - ('ignore-pot-creation-date=', None, - 'ignore changes to POT-Creation-Date when updating or checking'), - ] - boolean_options = [ - 'omit-header', 'no-wrap', 'ignore-obsolete', 'init-missing', - 'no-fuzzy-matching', 'previous', 'update-header-comment', - 'check', 'ignore-pot-creation-date', - ] - - def initialize_options(self): - self.domain = 'messages' - self.input_file = None - self.output_dir = None - self.output_file = None - self.omit_header = False - self.locale = None - self.width = None - self.no_wrap = False - self.ignore_obsolete = False - self.init_missing = False - self.no_fuzzy_matching = False - self.update_header_comment = False - self.previous = False - self.check = False - self.ignore_pot_creation_date = False - - def finalize_options(self): - if not self.input_file: - raise OptionError('you must specify the input file') - if not self.output_file and not self.output_dir: - raise OptionError('you must specify the output file or directory') - if self.output_file and not self.locale: - raise OptionError('you must specify the locale') - - if self.init_missing: - if not self.locale: - raise OptionError( - 'you must specify the locale for ' - 'the init-missing option to work', - ) - - try: - self._locale = Locale.parse(self.locale) - except UnknownLocaleError as e: - raise OptionError(e) from e - else: - self._locale = None - - if self.no_wrap and self.width: - raise OptionError("'--no-wrap' and '--width' are mutually exclusive") - if not self.no_wrap and not self.width: - self.width = 76 - elif self.width is not None: - self.width = int(self.width) - if self.no_fuzzy_matching and self.previous: - self.previous = False - - def run(self): - check_status = {} - po_files = [] - if not self.output_file: - if self.locale: - po_files.append((self.locale, - os.path.join(self.output_dir, self.locale, - 'LC_MESSAGES', - f"{self.domain}.po"))) - else: - for locale in os.listdir(self.output_dir): - po_file = os.path.join(self.output_dir, locale, - 'LC_MESSAGES', - f"{self.domain}.po") - if os.path.exists(po_file): - po_files.append((locale, po_file)) - else: - po_files.append((self.locale, self.output_file)) - - if not po_files: - raise OptionError('no message catalogs found') - - domain = self.domain - if not domain: - domain = os.path.splitext(os.path.basename(self.input_file))[0] - - with open(self.input_file, 'rb') as infile: - template = read_po(infile) - - for locale, filename in po_files: - if self.init_missing and not os.path.exists(filename): - if self.check: - check_status[filename] = False - continue - self.log.info( - 'creating catalog %s based on %s', filename, self.input_file, - ) - - with open(self.input_file, 'rb') as infile: - # Although reading from the catalog template, read_po must - # be fed the locale in order to correctly calculate plurals - catalog = read_po(infile, locale=self.locale) - - catalog.locale = self._locale - catalog.revision_date = datetime.datetime.now(LOCALTZ) - catalog.fuzzy = False - - with open(filename, 'wb') as outfile: - write_po(outfile, catalog) - - self.log.info('updating catalog %s based on %s', filename, self.input_file) - with open(filename, 'rb') as infile: - catalog = read_po(infile, locale=locale, domain=domain) - - catalog.update( - template, self.no_fuzzy_matching, - update_header_comment=self.update_header_comment, - update_creation_date=not self.ignore_pot_creation_date, - ) - - tmpname = os.path.join(os.path.dirname(filename), - tempfile.gettempprefix() + - os.path.basename(filename)) - try: - with open(tmpname, 'wb') as tmpfile: - write_po(tmpfile, catalog, - omit_header=self.omit_header, - ignore_obsolete=self.ignore_obsolete, - include_previous=self.previous, width=self.width) - except Exception: - os.remove(tmpname) - raise - - if self.check: - with open(filename, "rb") as origfile: - original_catalog = read_po(origfile) - with open(tmpname, "rb") as newfile: - updated_catalog = read_po(newfile) - updated_catalog.revision_date = original_catalog.revision_date - check_status[filename] = updated_catalog.is_identical(original_catalog) - os.remove(tmpname) - continue - - try: - os.rename(tmpname, filename) - except OSError: - # We're probably on Windows, which doesn't support atomic - # renames, at least not through Python - # If the error is in fact due to a permissions problem, that - # same error is going to be raised from one of the following - # operations - os.remove(filename) - shutil.copy(tmpname, filename) - os.remove(tmpname) - - if self.check: - for filename, up_to_date in check_status.items(): - if up_to_date: - self.log.info('Catalog %s is up to date.', filename) - else: - self.log.warning('Catalog %s is out of date.', filename) - if not all(check_status.values()): - raise BaseError("Some catalogs are out of date.") - else: - self.log.info("All the catalogs are up-to-date.") - return - - -class CommandLineInterface: - """Command-line interface. - - This class provides a simple command-line interface to the message - extraction and PO file generation functionality. - """ - - usage = '%%prog %s [options] %s' - version = f'%prog {VERSION}' - commands = { - 'compile': 'compile message catalogs to MO files', - 'extract': 'extract messages from source files and generate a POT file', - 'init': 'create new message catalogs from a POT file', - 'update': 'update existing message catalogs from a POT file', - } - - command_classes = { - 'compile': CompileCatalog, - 'extract': ExtractMessages, - 'init': InitCatalog, - 'update': UpdateCatalog, - } - - log = None # Replaced on instance level - - def run(self, argv=None): - """Main entry point of the command-line interface. - - :param argv: list of arguments passed on the command-line - """ - - if argv is None: - argv = sys.argv - - self.parser = optparse.OptionParser(usage=self.usage % ('command', '[args]'), - version=self.version) - self.parser.disable_interspersed_args() - self.parser.print_help = self._help - self.parser.add_option('--list-locales', dest='list_locales', - action='store_true', - help="print all known locales and exit") - self.parser.add_option('-v', '--verbose', action='store_const', - dest='loglevel', const=logging.DEBUG, - help='print as much as possible') - self.parser.add_option('-q', '--quiet', action='store_const', - dest='loglevel', const=logging.ERROR, - help='print as little as possible') - self.parser.set_defaults(list_locales=False, loglevel=logging.INFO) - - options, args = self.parser.parse_args(argv[1:]) - - self._configure_logging(options.loglevel) - if options.list_locales: - identifiers = localedata.locale_identifiers() - id_width = max(len(identifier) for identifier in identifiers) + 1 - for identifier in sorted(identifiers): - locale = Locale.parse(identifier) - print(f"{identifier:<{id_width}} {locale.english_name}") - return 0 - - if not args: - self.parser.error('no valid command or option passed. ' - 'Try the -h/--help option for more information.') - - cmdname = args[0] - if cmdname not in self.commands: - self.parser.error(f'unknown command "{cmdname}"') - - cmdinst = self._configure_command(cmdname, args[1:]) - return cmdinst.run() - - def _configure_logging(self, loglevel): - self.log = log - self.log.setLevel(loglevel) - # Don't add a new handler for every instance initialization (#227), this - # would cause duplicated output when the CommandLineInterface as an - # normal Python class. - if self.log.handlers: - handler = self.log.handlers[0] - else: - handler = logging.StreamHandler() - self.log.addHandler(handler) - handler.setLevel(loglevel) - formatter = logging.Formatter('%(message)s') - handler.setFormatter(formatter) - - def _help(self): - print(self.parser.format_help()) - print("commands:") - cmd_width = max(8, max(len(command) for command in self.commands) + 1) - for name, description in sorted(self.commands.items()): - print(f" {name:<{cmd_width}} {description}") - - def _configure_command(self, cmdname, argv): - """ - :type cmdname: str - :type argv: list[str] - """ - cmdclass = self.command_classes[cmdname] - cmdinst = cmdclass() - if self.log: - cmdinst.log = self.log # Use our logger, not distutils'. - assert isinstance(cmdinst, CommandMixin) - cmdinst.initialize_options() - - parser = optparse.OptionParser( - usage=self.usage % (cmdname, ''), - description=self.commands[cmdname], - ) - as_args: str | None = getattr(cmdclass, "as_args", None) - for long, short, help in cmdclass.user_options: - name = long.strip("=") - default = getattr(cmdinst, name.replace("-", "_")) - strs = [f"--{name}"] - if short: - strs.append(f"-{short}") - strs.extend(cmdclass.option_aliases.get(name, ())) - choices = cmdclass.option_choices.get(name, None) - if name == as_args: - parser.usage += f"<{name}>" - elif name in cmdclass.boolean_options: - parser.add_option(*strs, action="store_true", help=help) - elif name in cmdclass.multiple_value_options: - parser.add_option(*strs, action="append", help=help, choices=choices) - else: - parser.add_option(*strs, help=help, default=default, choices=choices) - options, args = parser.parse_args(argv) - - if as_args: - setattr(options, as_args.replace('-', '_'), args) - - for key, value in vars(options).items(): - setattr(cmdinst, key, value) - - try: - cmdinst.ensure_finalized() - except OptionError as err: - parser.error(str(err)) - - return cmdinst - - -def main(): - return CommandLineInterface().run(sys.argv) - - -def parse_mapping(fileobj, filename=None): - warnings.warn( - "parse_mapping is deprecated, use parse_mapping_cfg instead", - DeprecationWarning, - stacklevel=2, - ) - return parse_mapping_cfg(fileobj, filename) - - -def parse_mapping_cfg(fileobj, filename=None): - """Parse an extraction method mapping from a file-like object. - - :param fileobj: a readable file-like object containing the configuration - text to parse - :param filename: the name of the file being parsed, for error messages - """ - extractors = {} - method_map = [] - options_map = {} - - parser = RawConfigParser() - parser.read_file(fileobj, filename) - - for section in parser.sections(): - if section == 'extractors': - extractors = dict(parser.items(section)) - else: - method, pattern = (part.strip() for part in section.split(':', 1)) - method_map.append((pattern, method)) - options_map[pattern] = dict(parser.items(section)) - - if extractors: - for idx, (pattern, method) in enumerate(method_map): - if method in extractors: - method = extractors[method] - method_map[idx] = (pattern, method) - - return method_map, options_map - - -def _parse_config_object(config: dict, *, filename="(unknown)"): - extractors = {} - method_map = [] - options_map = {} - - extractors_read = config.get("extractors", {}) - if not isinstance(extractors_read, dict): - raise ConfigurationError(f"{filename}: extractors: Expected a dictionary, got {type(extractors_read)!r}") - for method, callable_spec in extractors_read.items(): - if not isinstance(method, str): - # Impossible via TOML, but could happen with a custom object. - raise ConfigurationError(f"{filename}: extractors: Extraction method must be a string, got {method!r}") - if not isinstance(callable_spec, str): - raise ConfigurationError(f"{filename}: extractors: Callable specification must be a string, got {callable_spec!r}") - extractors[method] = callable_spec - - if "mapping" in config: - raise ConfigurationError(f"{filename}: 'mapping' is not a valid key, did you mean 'mappings'?") - - mappings_read = config.get("mappings", []) - if not isinstance(mappings_read, list): - raise ConfigurationError(f"{filename}: mappings: Expected a list, got {type(mappings_read)!r}") - for idx, entry in enumerate(mappings_read): - if not isinstance(entry, dict): - raise ConfigurationError(f"{filename}: mappings[{idx}]: Expected a dictionary, got {type(entry)!r}") - entry = entry.copy() - - method = entry.pop("method", None) - if not isinstance(method, str): - raise ConfigurationError(f"{filename}: mappings[{idx}]: 'method' must be a string, got {method!r}") - method = extractors.get(method, method) # Map the extractor name to the callable now - - pattern = entry.pop("pattern", None) - if not isinstance(pattern, (list, str)): - raise ConfigurationError(f"{filename}: mappings[{idx}]: 'pattern' must be a list or a string, got {pattern!r}") - if not isinstance(pattern, list): - pattern = [pattern] - - for pat in pattern: - if not isinstance(pat, str): - raise ConfigurationError(f"{filename}: mappings[{idx}]: 'pattern' elements must be strings, got {pat!r}") - method_map.append((pat, method)) - options_map[pat] = entry - - return method_map, options_map - - -def _parse_mapping_toml( - fileobj: BinaryIO, - filename: str = "(unknown)", - style: Literal["standalone", "pyproject.toml"] = "standalone", -): - """Parse an extraction method mapping from a binary file-like object. - - .. warning: As of this version of Babel, this is a private API subject to changes. - - :param fileobj: a readable binary file-like object containing the configuration TOML to parse - :param filename: the name of the file being parsed, for error messages - :param style: whether the file is in the style of a `pyproject.toml` file, i.e. whether to look for `tool.babel`. - """ - try: - import tomllib - except ImportError: - try: - import tomli as tomllib - except ImportError as ie: # pragma: no cover - raise ImportError("tomli or tomllib is required to parse TOML files") from ie - - try: - parsed_data = tomllib.load(fileobj) - except tomllib.TOMLDecodeError as e: - raise ConfigurationError(f"{filename}: Error parsing TOML file: {e}") from e - - if style == "pyproject.toml": - try: - babel_data = parsed_data["tool"]["babel"] - except (TypeError, KeyError) as e: - raise ConfigurationError(f"{filename}: No 'tool.babel' section found in file") from e - elif style == "standalone": - babel_data = parsed_data - if "babel" in babel_data: - raise ConfigurationError(f"{filename}: 'babel' should not be present in a stand-alone configuration file") - else: # pragma: no cover - raise ValueError(f"Unknown TOML style {style!r}") - - return _parse_config_object(babel_data, filename=filename) - - -def _parse_spec(s: str) -> tuple[int | None, tuple[int | tuple[int, str], ...]]: - inds = [] - number = None - for x in s.split(','): - if x[-1] == 't': - number = int(x[:-1]) - elif x[-1] == 'c': - inds.append((int(x[:-1]), 'c')) - else: - inds.append(int(x)) - return number, tuple(inds) - - -def parse_keywords(strings: Iterable[str] = ()): - """Parse keywords specifications from the given list of strings. - - >>> import pprint - >>> keywords = ['_', 'dgettext:2', 'dngettext:2,3', 'pgettext:1c,2', - ... 'polymorphic:1', 'polymorphic:2,2t', 'polymorphic:3c,3t'] - >>> pprint.pprint(parse_keywords(keywords)) - {'_': None, - 'dgettext': (2,), - 'dngettext': (2, 3), - 'pgettext': ((1, 'c'), 2), - 'polymorphic': {None: (1,), 2: (2,), 3: ((3, 'c'),)}} - - The input keywords are in GNU Gettext style; see :doc:`cmdline` for details. - - The output is a dictionary mapping keyword names to a dictionary of specifications. - Keys in this dictionary are numbers of arguments, where ``None`` means that all numbers - of arguments are matched, and a number means only calls with that number of arguments - are matched (which happens when using the "t" specifier). However, as a special - case for backwards compatibility, if the dictionary of specifications would - be ``{None: x}``, i.e., there is only one specification and it matches all argument - counts, then it is collapsed into just ``x``. - - A specification is either a tuple or None. If a tuple, each element can be either a number - ``n``, meaning that the nth argument should be extracted as a message, or the tuple - ``(n, 'c')``, meaning that the nth argument should be extracted as context for the - messages. A ``None`` specification is equivalent to ``(1,)``, extracting the first - argument. - """ - keywords = {} - for string in strings: - if ':' in string: - funcname, spec_str = string.split(':') - number, spec = _parse_spec(spec_str) - else: - funcname = string - number = None - spec = None - keywords.setdefault(funcname, {})[number] = spec - - # For best backwards compatibility, collapse {None: x} into x. - for k, v in keywords.items(): - if set(v) == {None}: - keywords[k] = v[None] - - return keywords - - -def __getattr__(name: str): - # Re-exports for backwards compatibility; - # `setuptools_frontend` is the canonical import location. - if name in {'check_message_extractors', 'compile_catalog', 'extract_messages', 'init_catalog', 'update_catalog'}: - from babel.messages import setuptools_frontend - - return getattr(setuptools_frontend, name) - - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - - -if __name__ == '__main__': - main() diff --git a/extensions/.local/lib/python3.11/site-packages/babel/messages/jslexer.py b/extensions/.local/lib/python3.11/site-packages/babel/messages/jslexer.py deleted file mode 100644 index 5fc4956..0000000 --- a/extensions/.local/lib/python3.11/site-packages/babel/messages/jslexer.py +++ /dev/null @@ -1,204 +0,0 @@ -""" - babel.messages.jslexer - ~~~~~~~~~~~~~~~~~~~~~~ - - A simple JavaScript 1.5 lexer which is used for the JavaScript - extractor. - - :copyright: (c) 2013-2025 by the Babel Team. - :license: BSD, see LICENSE for more details. -""" -from __future__ import annotations - -import re -from collections.abc import Generator -from typing import NamedTuple - -operators: list[str] = sorted([ - '+', '-', '*', '%', '!=', '==', '<', '>', '<=', '>=', '=', - '+=', '-=', '*=', '%=', '<<', '>>', '>>>', '<<=', '>>=', - '>>>=', '&', '&=', '|', '|=', '&&', '||', '^', '^=', '(', ')', - '[', ']', '{', '}', '!', '--', '++', '~', ',', ';', '.', ':', -], key=len, reverse=True) - -escapes: dict[str, str] = {'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t'} - -name_re = re.compile(r'[\w$_][\w\d$_]*', re.UNICODE) -dotted_name_re = re.compile(r'[\w$_][\w\d$_.]*[\w\d$_.]', re.UNICODE) -division_re = re.compile(r'/=?') -regex_re = re.compile(r'/(?:[^/\\]*(?:\\.[^/\\]*)*)/[a-zA-Z]*', re.DOTALL) -line_re = re.compile(r'(\r\n|\n|\r)') -line_join_re = re.compile(r'\\' + line_re.pattern) -uni_escape_re = re.compile(r'[a-fA-F0-9]{1,4}') -hex_escape_re = re.compile(r'[a-fA-F0-9]{1,2}') - - -class Token(NamedTuple): - type: str - value: str - lineno: int - - -_rules: list[tuple[str | None, re.Pattern[str]]] = [ - (None, re.compile(r'\s+', re.UNICODE)), - (None, re.compile(r' 424 it = izip(iterable, count(0,-1)) # decorate - 425 result = _nlargest(n, it) - 426 return map(itemgetter(0), result) # undecorate - 427 - 428 # General case, slowest method - TypeError: izip argument #1 must support iteration - _______________________________________________________________________ - - - Using pre_dispatch in a producer/consumer situation, where the - data is generated on the fly. Note how the producer is first - called 3 times before the parallel loop is initiated, and then - called to generate new data on the fly: - - >>> from math import sqrt - >>> from joblib import Parallel, delayed - >>> def producer(): - ... for i in range(6): - ... print('Produced %s' % i) - ... yield i - >>> out = Parallel(n_jobs=2, verbose=100, pre_dispatch='1.5*n_jobs')( - ... delayed(sqrt)(i) for i in producer()) #doctest: +SKIP - Produced 0 - Produced 1 - Produced 2 - [Parallel(n_jobs=2)]: Done 1 jobs | elapsed: 0.0s - Produced 3 - [Parallel(n_jobs=2)]: Done 2 jobs | elapsed: 0.0s - Produced 4 - [Parallel(n_jobs=2)]: Done 3 jobs | elapsed: 0.0s - Produced 5 - [Parallel(n_jobs=2)]: Done 4 jobs | elapsed: 0.0s - [Parallel(n_jobs=2)]: Done 6 out of 6 | elapsed: 0.0s remaining: 0.0s - [Parallel(n_jobs=2)]: Done 6 out of 6 | elapsed: 0.0s finished - - ''' # noqa: E501 - def __init__( - self, - n_jobs=default_parallel_config["n_jobs"], - backend=default_parallel_config['backend'], - return_as="list", - verbose=default_parallel_config["verbose"], - timeout=None, - pre_dispatch='2 * n_jobs', - batch_size='auto', - temp_folder=default_parallel_config["temp_folder"], - max_nbytes=default_parallel_config["max_nbytes"], - mmap_mode=default_parallel_config["mmap_mode"], - prefer=default_parallel_config["prefer"], - require=default_parallel_config["require"], - ): - # Initiate parent Logger class state - super().__init__() - - # Interpret n_jobs=None as 'unset' - if n_jobs is None: - n_jobs = default_parallel_config["n_jobs"] - - active_backend, context_config = _get_active_backend( - prefer=prefer, require=require, verbose=verbose - ) - - nesting_level = active_backend.nesting_level - - self.verbose = _get_config_param(verbose, context_config, "verbose") - self.timeout = timeout - self.pre_dispatch = pre_dispatch - - if return_as not in {"list", "generator", "generator_unordered"}: - raise ValueError( - 'Expected `return_as` parameter to be a string equal to "list"' - f',"generator" or "generator_unordered", but got {return_as} ' - "instead." - ) - self.return_as = return_as - self.return_generator = return_as != "list" - self.return_ordered = return_as != "generator_unordered" - - # Check if we are under a parallel_config or parallel_backend - # context manager and use the config from the context manager - # for arguments that are not explicitly set. - self._backend_args = { - k: _get_config_param(param, context_config, k) for param, k in [ - (max_nbytes, "max_nbytes"), - (temp_folder, "temp_folder"), - (mmap_mode, "mmap_mode"), - (prefer, "prefer"), - (require, "require"), - (verbose, "verbose"), - ] - } - - if isinstance(self._backend_args["max_nbytes"], str): - self._backend_args["max_nbytes"] = memstr_to_bytes( - self._backend_args["max_nbytes"] - ) - self._backend_args["verbose"] = max( - 0, self._backend_args["verbose"] - 50 - ) - - if DEFAULT_MP_CONTEXT is not None: - self._backend_args['context'] = DEFAULT_MP_CONTEXT - elif hasattr(mp, "get_context"): - self._backend_args['context'] = mp.get_context() - - if backend is default_parallel_config['backend'] or backend is None: - backend = active_backend - - elif isinstance(backend, ParallelBackendBase): - # Use provided backend as is, with the current nesting_level if it - # is not set yet. - if backend.nesting_level is None: - backend.nesting_level = nesting_level - - elif hasattr(backend, 'Pool') and hasattr(backend, 'Lock'): - # Make it possible to pass a custom multiprocessing context as - # backend to change the start method to forkserver or spawn or - # preload modules on the forkserver helper process. - self._backend_args['context'] = backend - backend = MultiprocessingBackend(nesting_level=nesting_level) - - elif backend not in BACKENDS and backend in MAYBE_AVAILABLE_BACKENDS: - warnings.warn( - f"joblib backend '{backend}' is not available on " - f"your system, falling back to {DEFAULT_BACKEND}.", - UserWarning, - stacklevel=2) - BACKENDS[backend] = BACKENDS[DEFAULT_BACKEND] - backend = BACKENDS[DEFAULT_BACKEND](nesting_level=nesting_level) - - else: - try: - backend_factory = BACKENDS[backend] - except KeyError as e: - raise ValueError("Invalid backend: %s, expected one of %r" - % (backend, sorted(BACKENDS.keys()))) from e - backend = backend_factory(nesting_level=nesting_level) - - n_jobs = _get_config_param(n_jobs, context_config, "n_jobs") - if n_jobs is None: - # No specific context override and no specific value request: - # default to the default of the backend. - n_jobs = backend.default_n_jobs - try: - n_jobs = int(n_jobs) - except ValueError: - raise ValueError("n_jobs could not be converted to int") - self.n_jobs = n_jobs - - if (require == 'sharedmem' and - not getattr(backend, 'supports_sharedmem', False)): - raise ValueError("Backend %s does not support shared memory" - % backend) - - if (batch_size == 'auto' or isinstance(batch_size, Integral) and - batch_size > 0): - self.batch_size = batch_size - else: - raise ValueError( - "batch_size must be 'auto' or a positive integer, got: %r" - % batch_size) - - if not isinstance(backend, SequentialBackend): - if self.return_generator and not backend.supports_return_generator: - raise ValueError( - "Backend {} does not support " - "return_as={}".format(backend, return_as) - ) - # This lock is used to coordinate the main thread of this process - # with the async callback thread of our the pool. - self._lock = threading.RLock() - self._jobs = collections.deque() - self._pending_outputs = list() - self._ready_batches = queue.Queue() - self._reducer_callback = None - - # Internal variables - self._backend = backend - self._running = False - self._managed_backend = False - self._id = uuid4().hex - self._call_ref = None - - def __enter__(self): - self._managed_backend = True - self._calling = False - self._initialize_backend() - return self - - def __exit__(self, exc_type, exc_value, traceback): - self._managed_backend = False - if self.return_generator and self._calling: - self._abort() - self._terminate_and_reset() - - def _initialize_backend(self): - """Build a process or thread pool and return the number of workers""" - try: - n_jobs = self._backend.configure(n_jobs=self.n_jobs, parallel=self, - **self._backend_args) - if self.timeout is not None and not self._backend.supports_timeout: - warnings.warn( - 'The backend class {!r} does not support timeout. ' - "You have set 'timeout={}' in Parallel but " - "the 'timeout' parameter will not be used.".format( - self._backend.__class__.__name__, - self.timeout)) - - except FallbackToBackend as e: - # Recursively initialize the backend in case of requested fallback. - self._backend = e.backend - n_jobs = self._initialize_backend() - - return n_jobs - - def _effective_n_jobs(self): - if self._backend: - return self._backend.effective_n_jobs(self.n_jobs) - return 1 - - def _terminate_and_reset(self): - if hasattr(self._backend, 'stop_call') and self._calling: - self._backend.stop_call() - self._calling = False - if not self._managed_backend: - self._backend.terminate() - - def _dispatch(self, batch): - """Queue the batch for computing, with or without multiprocessing - - WARNING: this method is not thread-safe: it should be only called - indirectly via dispatch_one_batch. - - """ - # If job.get() catches an exception, it closes the queue: - if self._aborting: - return - - batch_size = len(batch) - - self.n_dispatched_tasks += batch_size - self.n_dispatched_batches += 1 - - dispatch_timestamp = time.time() - - batch_tracker = BatchCompletionCallBack( - dispatch_timestamp, batch_size, self - ) - - if self.return_ordered: - self._jobs.append(batch_tracker) - - # If return_ordered is False, the batch_tracker is not stored in the - # jobs queue at the time of submission. Instead, it will be appended to - # the queue by itself as soon as the callback is triggered to be able - # to return the results in the order of completion. - - job = self._backend.apply_async(batch, callback=batch_tracker) - batch_tracker.register_job(job) - - def dispatch_next(self): - """Dispatch more data for parallel processing - - This method is meant to be called concurrently by the multiprocessing - callback. We rely on the thread-safety of dispatch_one_batch to protect - against concurrent consumption of the unprotected iterator. - - """ - if not self.dispatch_one_batch(self._original_iterator): - self._iterating = False - self._original_iterator = None - - def dispatch_one_batch(self, iterator): - """Prefetch the tasks for the next batch and dispatch them. - - The effective size of the batch is computed here. - If there are no more jobs to dispatch, return False, else return True. - - The iterator consumption and dispatching is protected by the same - lock so calling this function should be thread safe. - - """ - - if self._aborting: - return False - - batch_size = self._get_batch_size() - - with self._lock: - # to ensure an even distribution of the workload between workers, - # we look ahead in the original iterators more than batch_size - # tasks - However, we keep consuming only one batch at each - # dispatch_one_batch call. The extra tasks are stored in a local - # queue, _ready_batches, that is looked-up prior to re-consuming - # tasks from the origal iterator. - try: - tasks = self._ready_batches.get(block=False) - except queue.Empty: - # slice the iterator n_jobs * batchsize items at a time. If the - # slice returns less than that, then the current batchsize puts - # too much weight on a subset of workers, while other may end - # up starving. So in this case, re-scale the batch size - # accordingly to distribute evenly the last items between all - # workers. - n_jobs = self._cached_effective_n_jobs - big_batch_size = batch_size * n_jobs - - try: - islice = list(itertools.islice(iterator, big_batch_size)) - except Exception as e: - # Handle the fact that the generator of task raised an - # exception. As this part of the code can be executed in - # a thread internal to the backend, register a task with - # an error that will be raised in the user's thread. - if isinstance(e.__context__, queue.Empty): - # Suppress the cause of the exception if it is - # queue.Empty to avoid cluttered traceback. Only do it - # if the __context__ is really empty to avoid messing - # with causes of the original error. - e.__cause__ = None - batch_tracker = BatchCompletionCallBack( - 0, batch_size, self - ) - self._jobs.append(batch_tracker) - batch_tracker._register_outcome(dict( - result=e, status=TASK_ERROR - )) - return True - - if len(islice) == 0: - return False - elif (iterator is self._original_iterator and - len(islice) < big_batch_size): - # We reached the end of the original iterator (unless - # iterator is the ``pre_dispatch``-long initial slice of - # the original iterator) -- decrease the batch size to - # account for potential variance in the batches running - # time. - final_batch_size = max(1, len(islice) // (10 * n_jobs)) - else: - final_batch_size = max(1, len(islice) // n_jobs) - - # enqueue n_jobs batches in a local queue - for i in range(0, len(islice), final_batch_size): - tasks = BatchedCalls(islice[i:i + final_batch_size], - self._backend.get_nested_backend(), - self._reducer_callback, - self._pickle_cache) - self._ready_batches.put(tasks) - - # finally, get one task. - tasks = self._ready_batches.get(block=False) - if len(tasks) == 0: - # No more tasks available in the iterator: tell caller to stop. - return False - else: - self._dispatch(tasks) - return True - - def _get_batch_size(self): - """Returns the effective batch size for dispatch""" - if self.batch_size == 'auto': - return self._backend.compute_batch_size() - else: - # Fixed batch size strategy - return self.batch_size - - def _print(self, msg): - """Display the message on stout or stderr depending on verbosity""" - # XXX: Not using the logger framework: need to - # learn to use logger better. - if not self.verbose: - return - if self.verbose < 50: - writer = sys.stderr.write - else: - writer = sys.stdout.write - writer(f"[{self}]: {msg}\n") - - def _is_completed(self): - """Check if all tasks have been completed""" - return self.n_completed_tasks == self.n_dispatched_tasks and not ( - self._iterating or self._aborting - ) - - def print_progress(self): - """Display the process of the parallel execution only a fraction - of time, controlled by self.verbose. - """ - - if not self.verbose: - return - - elapsed_time = time.time() - self._start_time - - if self._is_completed(): - # Make sure that we get a last message telling us we are done - self._print( - f"Done {self.n_completed_tasks:3d} out of " - f"{self.n_completed_tasks:3d} | elapsed: " - f"{short_format_time(elapsed_time)} finished" - ) - return - - # Original job iterator becomes None once it has been fully - # consumed: at this point we know the total number of jobs and we are - # able to display an estimation of the remaining time based on already - # completed jobs. Otherwise, we simply display the number of completed - # tasks. - elif self._original_iterator is not None: - if _verbosity_filter(self.n_dispatched_batches, self.verbose): - return - self._print( - f"Done {self.n_completed_tasks:3d} tasks | elapsed: " - f"{short_format_time(elapsed_time)}" - ) - else: - index = self.n_completed_tasks - # We are finished dispatching - total_tasks = self.n_dispatched_tasks - # We always display the first loop - if not index == 0: - # Display depending on the number of remaining items - # A message as soon as we finish dispatching, cursor is 0 - cursor = (total_tasks - index + 1 - - self._pre_dispatch_amount) - frequency = (total_tasks // self.verbose) + 1 - is_last_item = (index + 1 == total_tasks) - if (is_last_item or cursor % frequency): - return - remaining_time = (elapsed_time / index) * \ - (self.n_dispatched_tasks - index * 1.0) - # only display status if remaining time is greater or equal to 0 - self._print( - f"Done {index:3d} out of {total_tasks:3d} | elapsed: " - f"{short_format_time(elapsed_time)} remaining: " - f"{short_format_time(remaining_time)}" - ) - - def _abort(self): - # Stop dispatching new jobs in the async callback thread - self._aborting = True - - # If the backend allows it, cancel or kill remaining running - # tasks without waiting for the results as we will raise - # the exception we got back to the caller instead of returning - # any result. - backend = self._backend - if (not self._aborted and hasattr(backend, 'abort_everything')): - # If the backend is managed externally we need to make sure - # to leave it in a working state to allow for future jobs - # scheduling. - ensure_ready = self._managed_backend - backend.abort_everything(ensure_ready=ensure_ready) - self._aborted = True - - def _start(self, iterator, pre_dispatch): - # Only set self._iterating to True if at least a batch - # was dispatched. In particular this covers the edge - # case of Parallel used with an exhausted iterator. If - # self._original_iterator is None, then this means either - # that pre_dispatch == "all", n_jobs == 1 or that the first batch - # was very quick and its callback already dispatched all the - # remaining jobs. - self._iterating = False - if self.dispatch_one_batch(iterator): - self._iterating = self._original_iterator is not None - - while self.dispatch_one_batch(iterator): - pass - - if pre_dispatch == "all": - # The iterable was consumed all at once by the above for loop. - # No need to wait for async callbacks to trigger to - # consumption. - self._iterating = False - - def _get_outputs(self, iterator, pre_dispatch): - """Iterator returning the tasks' output as soon as they are ready.""" - dispatch_thread_id = threading.get_ident() - detach_generator_exit = False - try: - self._start(iterator, pre_dispatch) - # first yield returns None, for internal use only. This ensures - # that we enter the try/except block and start dispatching the - # tasks. - yield - - with self._backend.retrieval_context(): - yield from self._retrieve() - - except GeneratorExit: - # The generator has been garbage collected before being fully - # consumed. This aborts the remaining tasks if possible and warn - # the user if necessary. - self._exception = True - - # In some interpreters such as PyPy, GeneratorExit can be raised in - # a different thread than the one used to start the dispatch of the - # parallel tasks. This can lead to hang when a thread attempts to - # join itself. As workaround, we detach the execution of the - # aborting code to a dedicated thread. We then need to make sure - # the rest of the function does not call `_terminate_and_reset` - # in finally. - if dispatch_thread_id != threading.get_ident(): - if not IS_PYPY: - warnings.warn( - "A generator produced by joblib.Parallel has been " - "gc'ed in an unexpected thread. This behavior should " - "not cause major -issues but to make sure, please " - "report this warning and your use case at " - "https://github.com/joblib/joblib/issues so it can " - "be investigated." - ) - - detach_generator_exit = True - _parallel = self - - class _GeneratorExitThread(threading.Thread): - def run(self): - _parallel._abort() - if _parallel.return_generator: - _parallel._warn_exit_early() - _parallel._terminate_and_reset() - - _GeneratorExitThread( - name="GeneratorExitThread" - ).start() - return - - # Otherwise, we are in the thread that started the dispatch: we can - # safely abort the execution and warn the user. - self._abort() - if self.return_generator: - self._warn_exit_early() - - raise - - # Note: we catch any BaseException instead of just Exception instances - # to also include KeyboardInterrupt - except BaseException: - self._exception = True - self._abort() - raise - finally: - # Store the unconsumed tasks and terminate the workers if necessary - _remaining_outputs = ([] if self._exception else self._jobs) - self._jobs = collections.deque() - self._running = False - if not detach_generator_exit: - self._terminate_and_reset() - - while len(_remaining_outputs) > 0: - batched_results = _remaining_outputs.popleft() - batched_results = batched_results.get_result(self.timeout) - for result in batched_results: - yield result - - def _wait_retrieval(self): - """Return True if we need to continue retrieving some tasks.""" - - # If the input load is still being iterated over, it means that tasks - # are still on the dispatch waitlist and their results will need to - # be retrieved later on. - if self._iterating: - return True - - # If some of the dispatched tasks are still being processed by the - # workers, wait for the compute to finish before starting retrieval - if self.n_completed_tasks < self.n_dispatched_tasks: - return True - - # For backends that does not support retrieving asynchronously the - # result to the main process, all results must be carefully retrieved - # in the _retrieve loop in the main thread while the backend is alive. - # For other backends, the actual retrieval is done asynchronously in - # the callback thread, and we can terminate the backend before the - # `self._jobs` result list has been emptied. The remaining results - # will be collected in the `finally` step of the generator. - if not self._backend.supports_retrieve_callback: - if len(self._jobs) > 0: - return True - - return False - - def _retrieve(self): - while self._wait_retrieval(): - - # If the callback thread of a worker has signaled that its task - # triggered an exception, or if the retrieval loop has raised an - # exception (e.g. `GeneratorExit`), exit the loop and surface the - # worker traceback. - if self._aborting: - self._raise_error_fast() - break - - # If the next job is not ready for retrieval yet, we just wait for - # async callbacks to progress. - if ((len(self._jobs) == 0) or - (self._jobs[0].get_status( - timeout=self.timeout) == TASK_PENDING)): - time.sleep(0.01) - continue - - # We need to be careful: the job list can be filling up as - # we empty it and Python list are not thread-safe by - # default hence the use of the lock - with self._lock: - batched_results = self._jobs.popleft() - - # Flatten the batched results to output one output at a time - batched_results = batched_results.get_result(self.timeout) - for result in batched_results: - self._nb_consumed += 1 - yield result - - def _raise_error_fast(self): - """If we are aborting, raise if a job caused an error.""" - - # Find the first job whose status is TASK_ERROR if it exists. - with self._lock: - error_job = next((job for job in self._jobs - if job.status == TASK_ERROR), None) - - # If this error job exists, immediately raise the error by - # calling get_result. This job might not exists if abort has been - # called directly or if the generator is gc'ed. - if error_job is not None: - error_job.get_result(self.timeout) - - def _warn_exit_early(self): - """Warn the user if the generator is gc'ed before being consumned.""" - ready_outputs = self.n_completed_tasks - self._nb_consumed - is_completed = self._is_completed() - msg = "" - if ready_outputs: - msg += ( - f"{ready_outputs} tasks have been successfully executed " - " but not used." - ) - if not is_completed: - msg += " Additionally, " - - if not is_completed: - msg += ( - f"{self.n_dispatched_tasks - self.n_completed_tasks} tasks " - "which were still being processed by the workers have been " - "cancelled." - ) - - if msg: - msg += ( - " You could benefit from adjusting the input task " - "iterator to limit unnecessary computation time." - ) - - warnings.warn(msg) - - def _get_sequential_output(self, iterable): - """Separate loop for sequential output. - - This simplifies the traceback in case of errors and reduces the - overhead of calling sequential tasks with `joblib`. - """ - try: - self._iterating = True - self._original_iterator = iterable - batch_size = self._get_batch_size() - - if batch_size != 1: - it = iter(iterable) - iterable_batched = iter( - lambda: tuple(itertools.islice(it, batch_size)), () - ) - iterable = ( - task for batch in iterable_batched for task in batch - ) - - # first yield returns None, for internal use only. This ensures - # that we enter the try/except block and setup the generator. - yield None - - # Sequentially call the tasks and yield the results. - for func, args, kwargs in iterable: - self.n_dispatched_batches += 1 - self.n_dispatched_tasks += 1 - res = func(*args, **kwargs) - self.n_completed_tasks += 1 - self.print_progress() - yield res - self._nb_consumed += 1 - except BaseException: - self._exception = True - self._aborting = True - self._aborted = True - raise - finally: - self.print_progress() - self._running = False - self._iterating = False - self._original_iterator = None - - def _reset_run_tracking(self): - """Reset the counters and flags used to track the execution.""" - - # Makes sur the parallel instance was not previously running in a - # thread-safe way. - with getattr(self, '_lock', nullcontext()): - if self._running: - msg = 'This Parallel instance is already running !' - if self.return_generator is True: - msg += ( - " Before submitting new tasks, you must wait for the " - "completion of all the previous tasks, or clean all " - "references to the output generator." - ) - raise RuntimeError(msg) - self._running = True - - # Counter to keep track of the task dispatched and completed. - self.n_dispatched_batches = 0 - self.n_dispatched_tasks = 0 - self.n_completed_tasks = 0 - - # Following count is incremented by one each time the user iterates - # on the output generator, it is used to prepare an informative - # warning message in case the generator is deleted before all the - # dispatched tasks have been consumed. - self._nb_consumed = 0 - - # Following flags are used to synchronize the threads in case one of - # the tasks error-out to ensure that all workers abort fast and that - # the backend terminates properly. - - # Set to True as soon as a worker signals that a task errors-out - self._exception = False - # Set to True in case of early termination following an incident - self._aborting = False - # Set to True after abortion is complete - self._aborted = False - - def __call__(self, iterable): - """Main function to dispatch parallel tasks.""" - - self._reset_run_tracking() - self._start_time = time.time() - - if not self._managed_backend: - n_jobs = self._initialize_backend() - else: - n_jobs = self._effective_n_jobs() - - if n_jobs == 1: - # If n_jobs==1, run the computation sequentially and return - # immediately to avoid overheads. - output = self._get_sequential_output(iterable) - next(output) - return output if self.return_generator else list(output) - - # Let's create an ID that uniquely identifies the current call. If the - # call is interrupted early and that the same instance is immediately - # re-used, this id will be used to prevent workers that were - # concurrently finalizing a task from the previous call to run the - # callback. - with self._lock: - self._call_id = uuid4().hex - - # self._effective_n_jobs should be called in the Parallel.__call__ - # thread only -- store its value in an attribute for further queries. - self._cached_effective_n_jobs = n_jobs - - if isinstance(self._backend, LokyBackend): - # For the loky backend, we add a callback executed when reducing - # BatchCalls, that makes the loky executor use a temporary folder - # specific to this Parallel object when pickling temporary memmaps. - # This callback is necessary to ensure that several Parallel - # objects using the same reusable executor don't use the same - # temporary resources. - - def _batched_calls_reducer_callback(): - # Relevant implementation detail: the following lines, called - # when reducing BatchedCalls, are called in a thread-safe - # situation, meaning that the context of the temporary folder - # manager will not be changed in between the callback execution - # and the end of the BatchedCalls pickling. The reason is that - # pickling (the only place where set_current_context is used) - # is done from a single thread (the queue_feeder_thread). - self._backend._workers._temp_folder_manager.set_current_context( # noqa - self._id - ) - self._reducer_callback = _batched_calls_reducer_callback - - # self._effective_n_jobs should be called in the Parallel.__call__ - # thread only -- store its value in an attribute for further queries. - self._cached_effective_n_jobs = n_jobs - - backend_name = self._backend.__class__.__name__ - if n_jobs == 0: - raise RuntimeError("%s has no active worker." % backend_name) - - self._print( - f"Using backend {backend_name} with {n_jobs} concurrent workers." - ) - if hasattr(self._backend, 'start_call'): - self._backend.start_call() - - # Following flag prevents double calls to `backend.stop_call`. - self._calling = True - - iterator = iter(iterable) - pre_dispatch = self.pre_dispatch - - if pre_dispatch == 'all': - # prevent further dispatch via multiprocessing callback thread - self._original_iterator = None - self._pre_dispatch_amount = 0 - else: - self._original_iterator = iterator - if hasattr(pre_dispatch, 'endswith'): - pre_dispatch = eval_expr( - pre_dispatch.replace("n_jobs", str(n_jobs)) - ) - self._pre_dispatch_amount = pre_dispatch = int(pre_dispatch) - - # The main thread will consume the first pre_dispatch items and - # the remaining items will later be lazily dispatched by async - # callbacks upon task completions. - - # TODO: this iterator should be batch_size * n_jobs - iterator = itertools.islice(iterator, self._pre_dispatch_amount) - - # Use a caching dict for callables that are pickled with cloudpickle to - # improve performances. This cache is used only in the case of - # functions that are defined in the __main__ module, functions that - # are defined locally (inside another function) and lambda expressions. - self._pickle_cache = dict() - - output = self._get_outputs(iterator, pre_dispatch) - self._call_ref = weakref.ref(output) - - # The first item from the output is blank, but it makes the interpreter - # progress until it enters the Try/Except block of the generator and - # reaches the first `yield` statement. This starts the asynchronous - # dispatch of the tasks to the workers. - next(output) - - return output if self.return_generator else list(output) - - def __repr__(self): - return '%s(n_jobs=%s)' % (self.__class__.__name__, self.n_jobs) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/pool.py b/extensions/.local/lib/python3.11/site-packages/joblib/pool.py deleted file mode 100644 index c0c3549..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/pool.py +++ /dev/null @@ -1,354 +0,0 @@ -"""Custom implementation of multiprocessing.Pool with custom pickler. - -This module provides efficient ways of working with data stored in -shared memory with numpy.memmap arrays without inducing any memory -copy between the parent and child processes. - -This module should not be imported if multiprocessing is not -available as it implements subclasses of multiprocessing Pool -that uses a custom alternative to SimpleQueue. - -""" -# Author: Olivier Grisel -# Copyright: 2012, Olivier Grisel -# License: BSD 3 clause - -import copyreg -import sys -import warnings -from time import sleep - -try: - WindowsError -except NameError: - WindowsError = type(None) - -from pickle import Pickler - -from pickle import HIGHEST_PROTOCOL -from io import BytesIO - -from ._memmapping_reducer import get_memmapping_reducers -from ._memmapping_reducer import TemporaryResourcesManager -from ._multiprocessing_helpers import mp, assert_spawning - -# We need the class definition to derive from it, not the multiprocessing.Pool -# factory function -from multiprocessing.pool import Pool - -try: - import numpy as np -except ImportError: - np = None - - -############################################################################### -# Enable custom pickling in Pool queues - -class CustomizablePickler(Pickler): - """Pickler that accepts custom reducers. - - TODO python2_drop : can this be simplified ? - - HIGHEST_PROTOCOL is selected by default as this pickler is used - to pickle ephemeral datastructures for interprocess communication - hence no backward compatibility is required. - - `reducers` is expected to be a dictionary with key/values - being `(type, callable)` pairs where `callable` is a function that - give an instance of `type` will return a tuple `(constructor, - tuple_of_objects)` to rebuild an instance out of the pickled - `tuple_of_objects` as would return a `__reduce__` method. See the - standard library documentation on pickling for more details. - - """ - - # We override the pure Python pickler as its the only way to be able to - # customize the dispatch table without side effects in Python 2.7 - # to 3.2. For Python 3.3+ leverage the new dispatch_table - # feature from https://bugs.python.org/issue14166 that makes it possible - # to use the C implementation of the Pickler which is faster. - - def __init__(self, writer, reducers=None, protocol=HIGHEST_PROTOCOL): - Pickler.__init__(self, writer, protocol=protocol) - if reducers is None: - reducers = {} - if hasattr(Pickler, 'dispatch'): - # Make the dispatch registry an instance level attribute instead of - # a reference to the class dictionary under Python 2 - self.dispatch = Pickler.dispatch.copy() - else: - # Under Python 3 initialize the dispatch table with a copy of the - # default registry - self.dispatch_table = copyreg.dispatch_table.copy() - for type, reduce_func in reducers.items(): - self.register(type, reduce_func) - - def register(self, type, reduce_func): - """Attach a reducer function to a given type in the dispatch table.""" - if hasattr(Pickler, 'dispatch'): - # Python 2 pickler dispatching is not explicitly customizable. - # Let us use a closure to workaround this limitation. - def dispatcher(self, obj): - reduced = reduce_func(obj) - self.save_reduce(obj=obj, *reduced) - self.dispatch[type] = dispatcher - else: - self.dispatch_table[type] = reduce_func - - -class CustomizablePicklingQueue(object): - """Locked Pipe implementation that uses a customizable pickler. - - This class is an alternative to the multiprocessing implementation - of SimpleQueue in order to make it possible to pass custom - pickling reducers, for instance to avoid memory copy when passing - memory mapped datastructures. - - `reducers` is expected to be a dict with key / values being - `(type, callable)` pairs where `callable` is a function that, given an - instance of `type`, will return a tuple `(constructor, tuple_of_objects)` - to rebuild an instance out of the pickled `tuple_of_objects` as would - return a `__reduce__` method. - - See the standard library documentation on pickling for more details. - """ - - def __init__(self, context, reducers=None): - self._reducers = reducers - self._reader, self._writer = context.Pipe(duplex=False) - self._rlock = context.Lock() - if sys.platform == 'win32': - self._wlock = None - else: - self._wlock = context.Lock() - self._make_methods() - - def __getstate__(self): - assert_spawning(self) - return (self._reader, self._writer, self._rlock, self._wlock, - self._reducers) - - def __setstate__(self, state): - (self._reader, self._writer, self._rlock, self._wlock, - self._reducers) = state - self._make_methods() - - def empty(self): - return not self._reader.poll() - - def _make_methods(self): - self._recv = recv = self._reader.recv - racquire, rrelease = self._rlock.acquire, self._rlock.release - - def get(): - racquire() - try: - return recv() - finally: - rrelease() - - self.get = get - - if self._reducers: - def send(obj): - buffer = BytesIO() - CustomizablePickler(buffer, self._reducers).dump(obj) - self._writer.send_bytes(buffer.getvalue()) - self._send = send - else: - self._send = send = self._writer.send - if self._wlock is None: - # writes to a message oriented win32 pipe are atomic - self.put = send - else: - wlock_acquire, wlock_release = ( - self._wlock.acquire, self._wlock.release) - - def put(obj): - wlock_acquire() - try: - return send(obj) - finally: - wlock_release() - - self.put = put - - -class PicklingPool(Pool): - """Pool implementation with customizable pickling reducers. - - This is useful to control how data is shipped between processes - and makes it possible to use shared memory without useless - copies induces by the default pickling methods of the original - objects passed as arguments to dispatch. - - `forward_reducers` and `backward_reducers` are expected to be - dictionaries with key/values being `(type, callable)` pairs where - `callable` is a function that, given an instance of `type`, will return a - tuple `(constructor, tuple_of_objects)` to rebuild an instance out of the - pickled `tuple_of_objects` as would return a `__reduce__` method. - See the standard library documentation about pickling for more details. - - """ - - def __init__(self, processes=None, forward_reducers=None, - backward_reducers=None, **kwargs): - if forward_reducers is None: - forward_reducers = dict() - if backward_reducers is None: - backward_reducers = dict() - self._forward_reducers = forward_reducers - self._backward_reducers = backward_reducers - poolargs = dict(processes=processes) - poolargs.update(kwargs) - super(PicklingPool, self).__init__(**poolargs) - - def _setup_queues(self): - context = getattr(self, '_ctx', mp) - self._inqueue = CustomizablePicklingQueue(context, - self._forward_reducers) - self._outqueue = CustomizablePicklingQueue(context, - self._backward_reducers) - self._quick_put = self._inqueue._send - self._quick_get = self._outqueue._recv - - -class MemmappingPool(PicklingPool): - """Process pool that shares large arrays to avoid memory copy. - - This drop-in replacement for `multiprocessing.pool.Pool` makes - it possible to work efficiently with shared memory in a numpy - context. - - Existing instances of numpy.memmap are preserved: the child - suprocesses will have access to the same shared memory in the - original mode except for the 'w+' mode that is automatically - transformed as 'r+' to avoid zeroing the original data upon - instantiation. - - Furthermore large arrays from the parent process are automatically - dumped to a temporary folder on the filesystem such as child - processes to access their content via memmapping (file system - backed shared memory). - - Note: it is important to call the terminate method to collect - the temporary folder used by the pool. - - Parameters - ---------- - processes: int, optional - Number of worker processes running concurrently in the pool. - initializer: callable, optional - Callable executed on worker process creation. - initargs: tuple, optional - Arguments passed to the initializer callable. - temp_folder: (str, callable) optional - If str: - Folder to be used by the pool for memmapping large arrays - for sharing memory with worker processes. If None, this will try in - order: - - a folder pointed by the JOBLIB_TEMP_FOLDER environment variable, - - /dev/shm if the folder exists and is writable: this is a RAMdisk - filesystem available by default on modern Linux distributions, - - the default system temporary folder that can be overridden - with TMP, TMPDIR or TEMP environment variables, typically /tmp - under Unix operating systems. - if callable: - An callable in charge of dynamically resolving a temporary folder - for memmapping large arrays. - max_nbytes int or None, optional, 1e6 by default - Threshold on the size of arrays passed to the workers that - triggers automated memory mapping in temp_folder. - Use None to disable memmapping of large arrays. - mmap_mode: {'r+', 'r', 'w+', 'c'} - Memmapping mode for numpy arrays passed to workers. - See 'max_nbytes' parameter documentation for more details. - forward_reducers: dictionary, optional - Reducers used to pickle objects passed from main process to worker - processes: see below. - backward_reducers: dictionary, optional - Reducers used to pickle return values from workers back to the - main process. - verbose: int, optional - Make it possible to monitor how the communication of numpy arrays - with the subprocess is handled (pickling or memmapping) - prewarm: bool or str, optional, "auto" by default. - If True, force a read on newly memmapped array to make sure that OS - pre-cache it in memory. This can be useful to avoid concurrent disk - access when the same data array is passed to different worker - processes. If "auto" (by default), prewarm is set to True, unless the - Linux shared memory partition /dev/shm is available and used as temp - folder. - - `forward_reducers` and `backward_reducers` are expected to be - dictionaries with key/values being `(type, callable)` pairs where - `callable` is a function that give an instance of `type` will return - a tuple `(constructor, tuple_of_objects)` to rebuild an instance out - of the pickled `tuple_of_objects` as would return a `__reduce__` - method. See the standard library documentation on pickling for more - details. - - """ - - def __init__(self, processes=None, temp_folder=None, max_nbytes=1e6, - mmap_mode='r', forward_reducers=None, backward_reducers=None, - verbose=0, context_id=None, prewarm=False, **kwargs): - - if context_id is not None: - warnings.warn('context_id is deprecated and ignored in joblib' - ' 0.9.4 and will be removed in 0.11', - DeprecationWarning) - - manager = TemporaryResourcesManager(temp_folder) - self._temp_folder_manager = manager - - # The usage of a temp_folder_resolver over a simple temp_folder is - # superfluous for multiprocessing pools, as they don't get reused, see - # get_memmapping_executor for more details. We still use it for code - # simplicity. - forward_reducers, backward_reducers = \ - get_memmapping_reducers( - temp_folder_resolver=manager.resolve_temp_folder_name, - max_nbytes=max_nbytes, mmap_mode=mmap_mode, - forward_reducers=forward_reducers, - backward_reducers=backward_reducers, verbose=verbose, - unlink_on_gc_collect=False, prewarm=prewarm) - - poolargs = dict( - processes=processes, - forward_reducers=forward_reducers, - backward_reducers=backward_reducers) - poolargs.update(kwargs) - super(MemmappingPool, self).__init__(**poolargs) - - def terminate(self): - n_retries = 10 - for i in range(n_retries): - try: - super(MemmappingPool, self).terminate() - break - except OSError as e: - if isinstance(e, WindowsError): - # Workaround occasional "[Error 5] Access is denied" issue - # when trying to terminate a process under windows. - sleep(0.1) - if i + 1 == n_retries: - warnings.warn("Failed to terminate worker processes in" - " multiprocessing pool: %r" % e) - - # Clean up the temporary resources as the workers should now be off. - self._temp_folder_manager._clean_temporary_resources() - - @property - def _temp_folder(self): - # Legacy property in tests. could be removed if we refactored the - # memmapping tests. SHOULD ONLY BE USED IN TESTS! - # We cache this property because it is called late in the tests - at - # this point, all context have been unregistered, and - # resolve_temp_folder_name raises an error. - if getattr(self, '_cached_temp_folder', None) is not None: - return self._cached_temp_folder - else: - self._cached_temp_folder = self._temp_folder_manager.resolve_temp_folder_name() # noqa - return self._cached_temp_folder diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/__init__.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/common.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/common.py deleted file mode 100644 index b0ca0c6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/common.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Small utilities for testing. -""" -import os -import gc -import sys - -from joblib._multiprocessing_helpers import mp -from joblib.testing import SkipTest, skipif - -try: - import lz4 -except ImportError: - lz4 = None - -IS_PYPY = hasattr(sys, "pypy_version_info") - -# A decorator to run tests only when numpy is available -try: - import numpy as np - - def with_numpy(func): - """A decorator to skip tests requiring numpy.""" - return func - -except ImportError: - def with_numpy(func): - """A decorator to skip tests requiring numpy.""" - def my_func(): - raise SkipTest('Test requires numpy') - return my_func - np = None - -# TODO: Turn this back on after refactoring yield based tests in test_hashing -# with_numpy = skipif(not np, reason='Test requires numpy.') - -# we use memory_profiler library for memory consumption checks -try: - from memory_profiler import memory_usage - - def with_memory_profiler(func): - """A decorator to skip tests requiring memory_profiler.""" - return func - - def memory_used(func, *args, **kwargs): - """Compute memory usage when executing func.""" - gc.collect() - mem_use = memory_usage((func, args, kwargs), interval=.001) - return max(mem_use) - min(mem_use) - -except ImportError: - def with_memory_profiler(func): - """A decorator to skip tests requiring memory_profiler.""" - def dummy_func(): - raise SkipTest('Test requires memory_profiler.') - return dummy_func - - memory_usage = memory_used = None - - -def force_gc_pypy(): - # The gc in pypy can be delayed. Force it to test the behavior when it - # will eventually be collected. - if IS_PYPY: - # Run gc.collect() twice to make sure the weakref is collected, as - # mentionned in the pypy doc: - # https://doc.pypy.org/en/latest/config/objspace.usemodules._weakref.html - import gc - gc.collect() - gc.collect() - - -with_multiprocessing = skipif( - mp is None, reason='Needs multiprocessing to run.') - - -with_dev_shm = skipif( - not os.path.exists('/dev/shm'), - reason='This test requires a large /dev/shm shared memory fs.') - -with_lz4 = skipif(lz4 is None, reason='Needs lz4 compression to run') - -without_lz4 = skipif( - lz4 is not None, reason='Needs lz4 not being installed to run') diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/data/__init__.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/data/create_numpy_pickle.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/data/create_numpy_pickle.py deleted file mode 100644 index ba903d6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/data/create_numpy_pickle.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -This script is used to generate test data for joblib/test/test_numpy_pickle.py -""" - -import sys -import re - -# pytest needs to be able to import this module even when numpy is -# not installed -try: - import numpy as np -except ImportError: - np = None - -import joblib - - -def get_joblib_version(joblib_version=joblib.__version__): - """Normalize joblib version by removing suffix. - - >>> get_joblib_version('0.8.4') - '0.8.4' - >>> get_joblib_version('0.8.4b1') - '0.8.4' - >>> get_joblib_version('0.9.dev0') - '0.9' - """ - matches = [re.match(r'(\d+).*', each) - for each in joblib_version.split('.')] - return '.'.join([m.group(1) for m in matches if m is not None]) - - -def write_test_pickle(to_pickle, args): - kwargs = {} - compress = args.compress - method = args.method - joblib_version = get_joblib_version() - py_version = '{0[0]}{0[1]}'.format(sys.version_info) - numpy_version = ''.join(np.__version__.split('.')[:2]) - - # The game here is to generate the right filename according to the options. - body = '_compressed' if (compress and method == 'zlib') else '' - if compress: - if method == 'zlib': - kwargs['compress'] = True - extension = '.gz' - else: - kwargs['compress'] = (method, 3) - extension = '.pkl.{}'.format(method) - if args.cache_size: - kwargs['cache_size'] = 0 - body += '_cache_size' - else: - extension = '.pkl' - - pickle_filename = 'joblib_{}{}_pickle_py{}_np{}{}'.format( - joblib_version, body, py_version, numpy_version, extension) - - try: - joblib.dump(to_pickle, pickle_filename, **kwargs) - except Exception as e: - # With old python version (=< 3.3.), we can arrive there when - # dumping compressed pickle with LzmaFile. - print("Error: cannot generate file '{}' with arguments '{}'. " - "Error was: {}".format(pickle_filename, kwargs, e)) - else: - print("File '{}' generated successfully.".format(pickle_filename)) - - -if __name__ == '__main__': - import argparse - parser = argparse.ArgumentParser(description="Joblib pickle data " - "generator.") - parser.add_argument('--cache_size', action="store_true", - help="Force creation of companion numpy " - "files for pickled arrays.") - parser.add_argument('--compress', action="store_true", - help="Generate compress pickles.") - parser.add_argument('--method', type=str, default='zlib', - choices=['zlib', 'gzip', 'bz2', 'xz', 'lzma', 'lz4'], - help="Set compression method.") - # We need to be specific about dtypes in particular endianness - # because the pickles can be generated on one architecture and - # the tests run on another one. See - # https://github.com/joblib/joblib/issues/279. - to_pickle = [np.arange(5, dtype=np.dtype(' 0 - - -@with_numpy -@with_multiprocessing -def test_parallel_config_params_explicit_set(tmpdir): - with parallel_config(n_jobs=3, max_nbytes=1, temp_folder=tmpdir): - with Parallel(n_jobs=2, prefer="processes", max_nbytes='1M') as p: - assert isinstance(p._backend, LokyBackend) - assert p.n_jobs == 2 - - # Checks that memmapping is disabled - with raises(TypeError, match="Expected np.memmap instance"): - p(delayed(check_memmap)(a) for a in [np.random.random(10)] * 2) - - -@parametrize("param", ["prefer", "require"]) -def test_parallel_config_bad_params(param): - # Check that an error is raised when setting a wrong backend - # hint or constraint - with raises(ValueError, match=f"{param}=wrong is not a valid"): - with parallel_config(**{param: "wrong"}): - Parallel() - - -def test_parallel_config_constructor_params(): - # Check that an error is raised when backend is None - # but backend constructor params are given - with raises(ValueError, match="only supported when backend is not None"): - with parallel_config(inner_max_num_threads=1): - pass - - with raises(ValueError, match="only supported when backend is not None"): - with parallel_config(backend_param=1): - pass - - -def test_parallel_config_nested(): - # Check that nested configuration retrieves the info from the - # parent config and do not reset them. - - with parallel_config(n_jobs=2): - p = Parallel() - assert isinstance(p._backend, BACKENDS[DEFAULT_BACKEND]) - assert p.n_jobs == 2 - - with parallel_config(backend='threading'): - with parallel_config(n_jobs=2): - p = Parallel() - assert isinstance(p._backend, ThreadingBackend) - assert p.n_jobs == 2 - - with parallel_config(verbose=100): - with parallel_config(n_jobs=2): - p = Parallel() - assert p.verbose == 100 - assert p.n_jobs == 2 - - -@with_numpy -@with_multiprocessing -@parametrize('backend', ['multiprocessing', 'threading', - MultiprocessingBackend(), ThreadingBackend()]) -@parametrize("context", [parallel_config, parallel_backend]) -def test_threadpool_limitation_in_child_context_error(context, backend): - - with raises(AssertionError, match=r"does not acc.*inner_max_num_threads"): - context(backend, inner_max_num_threads=1) - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_parallel_n_jobs_none(context): - # Check that n_jobs=None is interpreted as "unset" in Parallel - # non regression test for #1473 - with context(backend="threading", n_jobs=2): - with Parallel(n_jobs=None) as p: - assert p.n_jobs == 2 - - with context(backend="threading"): - default_n_jobs = Parallel().n_jobs - with Parallel(n_jobs=None) as p: - assert p.n_jobs == default_n_jobs - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_parallel_config_n_jobs_none(context): - # Check that n_jobs=None is interpreted as "explicitly set" in - # parallel_(config/backend) - # non regression test for #1473 - with context(backend="threading", n_jobs=2): - with context(backend="threading", n_jobs=None): - # n_jobs=None resets n_jobs to backend's default - with Parallel() as p: - assert p.n_jobs == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_dask.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_dask.py deleted file mode 100644 index aebe655..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_dask.py +++ /dev/null @@ -1,499 +0,0 @@ -from __future__ import print_function, division, absolute_import -import os -import warnings - -import pytest -from random import random -from uuid import uuid4 -from time import sleep - -from .. import Parallel, delayed, parallel_config -from ..parallel import ThreadingBackend, AutoBatchingMixin -from .._dask import DaskDistributedBackend - -distributed = pytest.importorskip('distributed') -dask = pytest.importorskip('dask') - -# These imports need to be after the pytest.importorskip hence the noqa: E402 -from distributed import Client, LocalCluster, get_client # noqa: E402 -from distributed.metrics import time # noqa: E402 -# Note: pytest requires to manually import all fixtures used in the test -# and their dependencies. -from distributed.utils_test import cluster, inc, cleanup # noqa: E402, F401 - - -def noop(*args, **kwargs): - pass - - -def slow_raise_value_error(condition, duration=0.05): - sleep(duration) - if condition: - raise ValueError("condition evaluated to True") - - -def count_events(event_name, client): - worker_events = client.run(lambda dask_worker: dask_worker.log) - event_counts = {} - for w, events in worker_events.items(): - event_counts[w] = len([event for event in list(events) - if event[1] == event_name]) - return event_counts - - -def test_simple(loop): - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask'): - seq = Parallel()(delayed(inc)(i) for i in range(10)) - assert seq == [inc(i) for i in range(10)] - - with pytest.raises(ValueError): - Parallel()(delayed(slow_raise_value_error)(i == 3) - for i in range(10)) - - seq = Parallel()(delayed(inc)(i) for i in range(10)) - assert seq == [inc(i) for i in range(10)] - - -def test_dask_backend_uses_autobatching(loop): - assert (DaskDistributedBackend.compute_batch_size - is AutoBatchingMixin.compute_batch_size) - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask'): - with Parallel() as parallel: - # The backend should be initialized with a default - # batch size of 1: - backend = parallel._backend - assert isinstance(backend, DaskDistributedBackend) - assert backend.parallel is parallel - assert backend._effective_batch_size == 1 - - # Launch many short tasks that should trigger - # auto-batching: - parallel( - delayed(lambda: None)() - for _ in range(int(1e4)) - ) - assert backend._effective_batch_size > 10 - - -def random2(): - return random() - - -def test_dont_assume_function_purity(loop): - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask'): - x, y = Parallel()(delayed(random2)() for i in range(2)) - assert x != y - - -@pytest.mark.parametrize("mixed", [True, False]) -def test_dask_funcname(loop, mixed): - from joblib._dask import Batch - if not mixed: - tasks = [delayed(inc)(i) for i in range(4)] - batch_repr = 'batch_of_inc_4_calls' - else: - tasks = [ - delayed(abs)(i) if i % 2 else delayed(inc)(i) for i in range(4) - ] - batch_repr = 'mixed_batch_of_inc_4_calls' - - assert repr(Batch(tasks)) == batch_repr - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: - with parallel_config(backend='dask'): - _ = Parallel(batch_size=2, pre_dispatch='all')(tasks) - - def f(dask_scheduler): - return list(dask_scheduler.transition_log) - batch_repr = batch_repr.replace('4', '2') - log = client.run_on_scheduler(f) - assert all('batch_of_inc' in tup[0] for tup in log) - - -def test_no_undesired_distributed_cache_hit(): - # Dask has a pickle cache for callables that are called many times. Because - # the dask backends used to wrap both the functions and the arguments - # under instances of the Batch callable class this caching mechanism could - # lead to bugs as described in: https://github.com/joblib/joblib/pull/1055 - # The joblib-dask backend has been refactored to avoid bundling the - # arguments as an attribute of the Batch instance to avoid this problem. - # This test serves as non-regression problem. - - # Use a large number of input arguments to give the AutoBatchingMixin - # enough tasks to kick-in. - lists = [[] for _ in range(100)] - np = pytest.importorskip('numpy') - X = np.arange(int(1e6)) - - def isolated_operation(list_, data=None): - if data is not None: - np.testing.assert_array_equal(data, X) - list_.append(uuid4().hex) - return list_ - - cluster = LocalCluster(n_workers=1, threads_per_worker=2) - client = Client(cluster) - try: - with parallel_config(backend='dask'): - # dispatches joblib.parallel.BatchedCalls - res = Parallel()( - delayed(isolated_operation)(list_) for list_ in lists - ) - - # The original arguments should not have been mutated as the mutation - # happens in the dask worker process. - assert lists == [[] for _ in range(100)] - - # Here we did not pass any large numpy array as argument to - # isolated_operation so no scattering event should happen under the - # hood. - counts = count_events('receive-from-scatter', client) - assert sum(counts.values()) == 0 - assert all([len(r) == 1 for r in res]) - - with parallel_config(backend='dask'): - # Append a large array which will be scattered by dask, and - # dispatch joblib._dask.Batch - res = Parallel()( - delayed(isolated_operation)(list_, data=X) for list_ in lists - ) - - # This time, auto-scattering should have kicked it. - counts = count_events('receive-from-scatter', client) - assert sum(counts.values()) > 0 - assert all([len(r) == 1 for r in res]) - finally: - client.close(timeout=30) - cluster.close(timeout=30) - - -class CountSerialized(object): - def __init__(self, x): - self.x = x - self.count = 0 - - def __add__(self, other): - return self.x + getattr(other, 'x', other) - - __radd__ = __add__ - - def __reduce__(self): - self.count += 1 - return (CountSerialized, (self.x,)) - - -def add5(a, b, c, d=0, e=0): - return a + b + c + d + e - - -def test_manual_scatter(loop): - x = CountSerialized(1) - y = CountSerialized(2) - z = CountSerialized(3) - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask', scatter=[x, y]): - f = delayed(add5) - tasks = [f(x, y, z, d=4, e=5), - f(x, z, y, d=5, e=4), - f(y, x, z, d=x, e=5), - f(z, z, x, d=z, e=y)] - expected = [func(*args, **kwargs) - for func, args, kwargs in tasks] - results = Parallel()(tasks) - - # Scatter must take a list/tuple - with pytest.raises(TypeError): - with parallel_config(backend='dask', loop=loop, scatter=1): - pass - - assert results == expected - - # Scattered variables only serialized once - assert x.count == 1 - assert y.count == 1 - # Depending on the version of distributed, the unscattered z variable - # is either pickled 4 or 6 times, possibly because of the memoization - # of objects that appear several times in the arguments of a delayed - # task. - assert z.count in (4, 6) - - -# When the same IOLoop is used for multiple clients in a row, use -# loop_in_thread instead of loop to prevent the Client from closing it. See -# dask/distributed #4112 -def test_auto_scatter(loop_in_thread): - np = pytest.importorskip('numpy') - data1 = np.ones(int(1e4), dtype=np.uint8) - data2 = np.ones(int(1e4), dtype=np.uint8) - data_to_process = ([data1] * 3) + ([data2] * 3) - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop_in_thread) as client: - with parallel_config(backend='dask'): - # Passing the same data as arg and kwarg triggers a single - # scatter operation whose result is reused. - Parallel()(delayed(noop)(data, data, i, opt=data) - for i, data in enumerate(data_to_process)) - # By default large array are automatically scattered with - # broadcast=1 which means that one worker must directly receive - # the data from the scatter operation once. - counts = count_events('receive-from-scatter', client) - assert counts[a['address']] + counts[b['address']] == 2 - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop_in_thread) as client: - with parallel_config(backend='dask'): - Parallel()(delayed(noop)(data1[:3], i) for i in range(5)) - # Small arrays are passed within the task definition without going - # through a scatter operation. - counts = count_events('receive-from-scatter', client) - assert counts[a['address']] == 0 - assert counts[b['address']] == 0 - - -@pytest.mark.parametrize("retry_no", list(range(2))) -def test_nested_scatter(loop, retry_no): - - np = pytest.importorskip('numpy') - - NUM_INNER_TASKS = 10 - NUM_OUTER_TASKS = 10 - - def my_sum(x, i, j): - return np.sum(x) - - def outer_function_joblib(array, i): - client = get_client() # noqa - with parallel_config(backend="dask"): - results = Parallel()( - delayed(my_sum)(array[j:], i, j) for j in range( - NUM_INNER_TASKS) - ) - return sum(results) - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as _: - with parallel_config(backend="dask"): - my_array = np.ones(10000) - _ = Parallel()( - delayed(outer_function_joblib)( - my_array[i:], i) for i in range(NUM_OUTER_TASKS) - ) - - -def test_nested_backend_context_manager(loop_in_thread): - def get_nested_pids(): - pids = set(Parallel(n_jobs=2)(delayed(os.getpid)() for _ in range(2))) - pids |= set(Parallel(n_jobs=2)(delayed(os.getpid)() for _ in range(2))) - return pids - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop_in_thread) as client: - with parallel_config(backend='dask'): - pid_groups = Parallel(n_jobs=2)( - delayed(get_nested_pids)() - for _ in range(10) - ) - for pid_group in pid_groups: - assert len(set(pid_group)) <= 2 - - # No deadlocks - with Client(s['address'], loop=loop_in_thread) as client: # noqa: F841 - with parallel_config(backend='dask'): - pid_groups = Parallel(n_jobs=2)( - delayed(get_nested_pids)() - for _ in range(10) - ) - for pid_group in pid_groups: - assert len(set(pid_group)) <= 2 - - -def test_nested_backend_context_manager_implicit_n_jobs(loop): - # Check that Parallel with no explicit n_jobs value automatically selects - # all the dask workers, including in nested calls. - - def _backend_type(p): - return p._backend.__class__.__name__ - - def get_nested_implicit_n_jobs(): - with Parallel() as p: - return _backend_type(p), p.n_jobs - - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask'): - with Parallel() as p: - assert _backend_type(p) == "DaskDistributedBackend" - assert p.n_jobs == -1 - all_nested_n_jobs = p( - delayed(get_nested_implicit_n_jobs)() - for _ in range(2) - ) - for backend_type, nested_n_jobs in all_nested_n_jobs: - assert backend_type == "DaskDistributedBackend" - assert nested_n_jobs == -1 - - -def test_errors(loop): - with pytest.raises(ValueError) as info: - with parallel_config(backend='dask'): - pass - - assert "create a dask client" in str(info.value).lower() - - -def test_correct_nested_backend(loop): - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - # No requirement, should be us - with parallel_config(backend='dask'): - result = Parallel(n_jobs=2)( - delayed(outer)(nested_require=None) for _ in range(1)) - assert isinstance(result[0][0][0], DaskDistributedBackend) - - # Require threads, should be threading - with parallel_config(backend='dask'): - result = Parallel(n_jobs=2)( - delayed(outer)(nested_require='sharedmem') - for _ in range(1)) - assert isinstance(result[0][0][0], ThreadingBackend) - - -def outer(nested_require): - return Parallel(n_jobs=2, prefer='threads')( - delayed(middle)(nested_require) for _ in range(1) - ) - - -def middle(require): - return Parallel(n_jobs=2, require=require)( - delayed(inner)() for _ in range(1) - ) - - -def inner(): - return Parallel()._backend - - -def test_secede_with_no_processes(loop): - # https://github.com/dask/distributed/issues/1775 - with Client(loop=loop, processes=False, set_as_default=True): - with parallel_config(backend='dask'): - Parallel(n_jobs=4)(delayed(id)(i) for i in range(2)) - - -def _worker_address(_): - from distributed import get_worker - return get_worker().address - - -def test_dask_backend_keywords(loop): - with cluster() as (s, [a, b]): - with Client(s['address'], loop=loop) as client: # noqa: F841 - with parallel_config(backend='dask', workers=a['address']): - seq = Parallel()( - delayed(_worker_address)(i) for i in range(10)) - assert seq == [a['address']] * 10 - - with parallel_config(backend='dask', workers=b['address']): - seq = Parallel()( - delayed(_worker_address)(i) for i in range(10)) - assert seq == [b['address']] * 10 - - -def test_scheduler_tasks_cleanup(loop): - with Client(processes=False, loop=loop) as client: - with parallel_config(backend='dask'): - Parallel()(delayed(inc)(i) for i in range(10)) - - start = time() - while client.cluster.scheduler.tasks: - sleep(0.01) - assert time() < start + 5 - - assert not client.futures - - -@pytest.mark.parametrize("cluster_strategy", ["adaptive", "late_scaling"]) -@pytest.mark.skipif( - distributed.__version__ <= '2.1.1' and distributed.__version__ >= '1.28.0', - reason="distributed bug - https://github.com/dask/distributed/pull/2841") -def test_wait_for_workers(cluster_strategy): - cluster = LocalCluster(n_workers=0, processes=False, threads_per_worker=2) - client = Client(cluster) - if cluster_strategy == "adaptive": - cluster.adapt(minimum=0, maximum=2) - elif cluster_strategy == "late_scaling": - # Tell the cluster to start workers but this is a non-blocking call - # and new workers might take time to connect. In this case the Parallel - # call should wait for at least one worker to come up before starting - # to schedule work. - cluster.scale(2) - try: - with parallel_config(backend='dask'): - # The following should wait a bit for at least one worker to - # become available. - Parallel()(delayed(inc)(i) for i in range(10)) - finally: - client.close() - cluster.close() - - -def test_wait_for_workers_timeout(): - # Start a cluster with 0 worker: - cluster = LocalCluster(n_workers=0, processes=False, threads_per_worker=2) - client = Client(cluster) - try: - with parallel_config(backend='dask', wait_for_workers_timeout=0.1): - # Short timeout: DaskDistributedBackend - msg = "DaskDistributedBackend has no worker after 0.1 seconds." - with pytest.raises(TimeoutError, match=msg): - Parallel()(delayed(inc)(i) for i in range(10)) - - with parallel_config(backend='dask', wait_for_workers_timeout=0): - # No timeout: fallback to generic joblib failure: - msg = "DaskDistributedBackend has no active worker" - with pytest.raises(RuntimeError, match=msg): - Parallel()(delayed(inc)(i) for i in range(10)) - finally: - client.close() - cluster.close() - - -@pytest.mark.parametrize("backend", ["loky", "multiprocessing"]) -def test_joblib_warning_inside_dask_daemonic_worker(backend): - cluster = LocalCluster(n_workers=2) - client = Client(cluster) - try: - - def func_using_joblib_parallel(): - # Somehow trying to check the warning type here (e.g. with - # pytest.warns(UserWarning)) make the test hang. Work-around: - # return the warning record to the client and the warning check is - # done client-side. - with warnings.catch_warnings(record=True) as record: - Parallel(n_jobs=2, backend=backend)( - delayed(inc)(i) for i in range(10)) - - return record - - fut = client.submit(func_using_joblib_parallel) - record = fut.result() - - assert len(record) == 1 - warning = record[0].message - assert isinstance(warning, UserWarning) - assert "distributed.worker.daemon" in str(warning) - finally: - client.close(timeout=30) - cluster.close(timeout=30) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_disk.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_disk.py deleted file mode 100644 index b825a8b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_disk.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Unit tests for the disk utilities. -""" - -# Authors: Gael Varoquaux -# Lars Buitinck -# Copyright (c) 2010 Gael Varoquaux -# License: BSD Style, 3 clauses. - -from __future__ import with_statement -import array -import os - -from joblib.disk import disk_used, memstr_to_bytes, mkdirp, rm_subdirs -from joblib.testing import parametrize, raises - -############################################################################### - - -def test_disk_used(tmpdir): - cachedir = tmpdir.strpath - # Not write a file that is 1M big in this directory, and check the - # size. The reason we use such a big file is that it makes us robust - # to errors due to block allocation. - a = array.array('i') - sizeof_i = a.itemsize - target_size = 1024 - n = int(target_size * 1024 / sizeof_i) - a = array.array('i', n * (1,)) - with open(os.path.join(cachedir, 'test'), 'wb') as output: - a.tofile(output) - assert disk_used(cachedir) >= target_size - assert disk_used(cachedir) < target_size + 12 - - -@parametrize('text,value', - [('80G', 80 * 1024 ** 3), - ('1.4M', int(1.4 * 1024 ** 2)), - ('120M', 120 * 1024 ** 2), - ('53K', 53 * 1024)]) -def test_memstr_to_bytes(text, value): - assert memstr_to_bytes(text) == value - - -@parametrize('text,exception,regex', - [('fooG', ValueError, r'Invalid literal for size.*fooG.*'), - ('1.4N', ValueError, r'Invalid literal for size.*1.4N.*')]) -def test_memstr_to_bytes_exception(text, exception, regex): - with raises(exception) as excinfo: - memstr_to_bytes(text) - assert excinfo.match(regex) - - -def test_mkdirp(tmpdir): - mkdirp(os.path.join(tmpdir.strpath, 'ham')) - mkdirp(os.path.join(tmpdir.strpath, 'ham')) - mkdirp(os.path.join(tmpdir.strpath, 'spam', 'spam')) - - # Not all OSErrors are ignored - with raises(OSError): - mkdirp('') - - -def test_rm_subdirs(tmpdir): - sub_path = os.path.join(tmpdir.strpath, "am", "stram") - full_path = os.path.join(sub_path, "gram") - mkdirp(os.path.join(full_path)) - - rm_subdirs(sub_path) - assert os.path.exists(sub_path) - assert not os.path.exists(full_path) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect.py deleted file mode 100644 index dba237d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect.py +++ /dev/null @@ -1,310 +0,0 @@ -""" -Test the func_inspect module. -""" - -# Author: Gael Varoquaux -# Copyright (c) 2009 Gael Varoquaux -# License: BSD Style, 3 clauses. - -import functools - -from joblib.func_inspect import filter_args, get_func_name, get_func_code -from joblib.func_inspect import _clean_win_chars, format_signature -from joblib.memory import Memory -from joblib.test.common import with_numpy -from joblib.testing import fixture, parametrize, raises - - -############################################################################### -# Module-level functions and fixture, for tests -def f(x, y=0): - pass - - -def g(x): - pass - - -def h(x, y=0, *args, **kwargs): - pass - - -def i(x=1): - pass - - -def j(x, y, **kwargs): - pass - - -def k(*args, **kwargs): - pass - - -def m1(x, *, y): - pass - - -def m2(x, *, y, z=3): - pass - - -@fixture(scope='module') -def cached_func(tmpdir_factory): - # Create a Memory object to test decorated functions. - # We should be careful not to call the decorated functions, so that - # cache directories are not created in the temp dir. - cachedir = tmpdir_factory.mktemp("joblib_test_func_inspect") - mem = Memory(cachedir.strpath) - - @mem.cache - def cached_func_inner(x): - return x - - return cached_func_inner - - -class Klass(object): - - def f(self, x): - return x - - -############################################################################### -# Tests - -@parametrize('func,args,filtered_args', - [(f, [[], (1, )], {'x': 1, 'y': 0}), - (f, [['x'], (1, )], {'y': 0}), - (f, [['y'], (0, )], {'x': 0}), - (f, [['y'], (0, ), {'y': 1}], {'x': 0}), - (f, [['x', 'y'], (0, )], {}), - (f, [[], (0,), {'y': 1}], {'x': 0, 'y': 1}), - (f, [['y'], (), {'x': 2, 'y': 1}], {'x': 2}), - (g, [[], (), {'x': 1}], {'x': 1}), - (i, [[], (2, )], {'x': 2})]) -def test_filter_args(func, args, filtered_args): - assert filter_args(func, *args) == filtered_args - - -def test_filter_args_method(): - obj = Klass() - assert filter_args(obj.f, [], (1, )) == {'x': 1, 'self': obj} - - -@parametrize('func,args,filtered_args', - [(h, [[], (1, )], - {'x': 1, 'y': 0, '*': [], '**': {}}), - (h, [[], (1, 2, 3, 4)], - {'x': 1, 'y': 2, '*': [3, 4], '**': {}}), - (h, [[], (1, 25), {'ee': 2}], - {'x': 1, 'y': 25, '*': [], '**': {'ee': 2}}), - (h, [['*'], (1, 2, 25), {'ee': 2}], - {'x': 1, 'y': 2, '**': {'ee': 2}})]) -def test_filter_varargs(func, args, filtered_args): - assert filter_args(func, *args) == filtered_args - - -test_filter_kwargs_extra_params = [ - (m1, [[], (1,), {'y': 2}], {'x': 1, 'y': 2}), - (m2, [[], (1,), {'y': 2}], {'x': 1, 'y': 2, 'z': 3}) -] - - -@parametrize('func,args,filtered_args', - [(k, [[], (1, 2), {'ee': 2}], - {'*': [1, 2], '**': {'ee': 2}}), - (k, [[], (3, 4)], - {'*': [3, 4], '**': {}})] + - test_filter_kwargs_extra_params) -def test_filter_kwargs(func, args, filtered_args): - assert filter_args(func, *args) == filtered_args - - -def test_filter_args_2(): - assert (filter_args(j, [], (1, 2), {'ee': 2}) == - {'x': 1, 'y': 2, '**': {'ee': 2}}) - - ff = functools.partial(f, 1) - # filter_args has to special-case partial - assert filter_args(ff, [], (1, )) == {'*': [1], '**': {}} - assert filter_args(ff, ['y'], (1, )) == {'*': [1], '**': {}} - - -@parametrize('func,funcname', [(f, 'f'), (g, 'g'), - (cached_func, 'cached_func')]) -def test_func_name(func, funcname): - # Check that we are not confused by decoration - # here testcase 'cached_func' is the function itself - assert get_func_name(func)[1] == funcname - - -def test_func_name_on_inner_func(cached_func): - # Check that we are not confused by decoration - # here testcase 'cached_func' is the 'cached_func_inner' function - # returned by 'cached_func' fixture - assert get_func_name(cached_func)[1] == 'cached_func_inner' - - -def test_func_name_collision_on_inner_func(): - # Check that two functions defining and caching an inner function - # with the same do not cause (module, name) collision - def f(): - def inner_func(): - return # pragma: no cover - return get_func_name(inner_func) - - def g(): - def inner_func(): - return # pragma: no cover - return get_func_name(inner_func) - - module, name = f() - other_module, other_name = g() - - assert name == other_name - assert module != other_module - - -def test_func_inspect_errors(): - # Check that func_inspect is robust and will work on weird objects - assert get_func_name('a'.lower)[-1] == 'lower' - assert get_func_code('a'.lower)[1:] == (None, -1) - ff = lambda x: x # noqa: E731 - assert get_func_name(ff, win_characters=False)[-1] == '' - assert get_func_code(ff)[1] == __file__.replace('.pyc', '.py') - # Simulate a function defined in __main__ - ff.__module__ = '__main__' - assert get_func_name(ff, win_characters=False)[-1] == '' - assert get_func_code(ff)[1] == __file__.replace('.pyc', '.py') - - -def func_with_kwonly_args(a, b, *, kw1='kw1', kw2='kw2'): - pass - - -def func_with_signature(a: int, b: int) -> None: - pass - - -def test_filter_args_edge_cases(): - assert ( - filter_args(func_with_kwonly_args, [], (1, 2), - {'kw1': 3, 'kw2': 4}) == - {'a': 1, 'b': 2, 'kw1': 3, 'kw2': 4}) - - # filter_args doesn't care about keyword-only arguments so you - # can pass 'kw1' into *args without any problem - with raises(ValueError) as excinfo: - filter_args(func_with_kwonly_args, [], (1, 2, 3), {'kw2': 2}) - excinfo.match("Keyword-only parameter 'kw1' was passed as positional " - "parameter") - - assert ( - filter_args(func_with_kwonly_args, ['b', 'kw2'], (1, 2), - {'kw1': 3, 'kw2': 4}) == - {'a': 1, 'kw1': 3}) - - assert (filter_args(func_with_signature, ['b'], (1, 2)) == {'a': 1}) - - -def test_bound_methods(): - """ Make sure that calling the same method on two different instances - of the same class does resolv to different signatures. - """ - a = Klass() - b = Klass() - assert filter_args(a.f, [], (1, )) != filter_args(b.f, [], (1, )) - - -@parametrize('exception,regex,func,args', - [(ValueError, 'ignore_lst must be a list of parameters to ignore', - f, ['bar', (None, )]), - (ValueError, r'Ignore list: argument \'(.*)\' is not defined', - g, [['bar'], (None, )]), - (ValueError, 'Wrong number of arguments', - h, [[]])]) -def test_filter_args_error_msg(exception, regex, func, args): - """ Make sure that filter_args returns decent error messages, for the - sake of the user. - """ - with raises(exception) as excinfo: - filter_args(func, *args) - excinfo.match(regex) - - -def test_filter_args_no_kwargs_mutation(): - """None-regression test against 0.12.0 changes. - - https://github.com/joblib/joblib/pull/75 - - Make sure filter args doesn't mutate the kwargs dict that gets passed in. - """ - kwargs = {'x': 0} - filter_args(g, [], [], kwargs) - assert kwargs == {'x': 0} - - -def test_clean_win_chars(): - string = r'C:\foo\bar\main.py' - mangled_string = _clean_win_chars(string) - for char in ('\\', ':', '<', '>', '!'): - assert char not in mangled_string - - -@parametrize('func,args,kwargs,sgn_expected', - [(g, [list(range(5))], {}, 'g([0, 1, 2, 3, 4])'), - (k, [1, 2, (3, 4)], {'y': True}, 'k(1, 2, (3, 4), y=True)')]) -def test_format_signature(func, args, kwargs, sgn_expected): - # Test signature formatting. - path, sgn_result = format_signature(func, *args, **kwargs) - assert sgn_result == sgn_expected - - -def test_format_signature_long_arguments(): - shortening_threshold = 1500 - # shortening gets it down to 700 characters but there is the name - # of the function in the signature and a few additional things - # like dots for the ellipsis - shortening_target = 700 + 10 - - arg = 'a' * shortening_threshold - _, signature = format_signature(h, arg) - assert len(signature) < shortening_target - - nb_args = 5 - args = [arg for _ in range(nb_args)] - _, signature = format_signature(h, *args) - assert len(signature) < shortening_target * nb_args - - kwargs = {str(i): arg for i, arg in enumerate(args)} - _, signature = format_signature(h, **kwargs) - assert len(signature) < shortening_target * nb_args - - _, signature = format_signature(h, *args, **kwargs) - assert len(signature) < shortening_target * 2 * nb_args - - -@with_numpy -def test_format_signature_numpy(): - """ Test the format signature formatting with numpy. - """ - - -def test_special_source_encoding(): - from joblib.test.test_func_inspect_special_encoding import big5_f - func_code, source_file, first_line = get_func_code(big5_f) - assert first_line == 5 - assert "def big5_f():" in func_code - assert "test_func_inspect_special_encoding" in source_file - - -def _get_code(): - from joblib.test.test_func_inspect_special_encoding import big5_f - return get_func_code(big5_f)[0] - - -def test_func_code_consistency(): - from joblib.parallel import Parallel, delayed - codes = Parallel(n_jobs=2)(delayed(_get_code)() for _ in range(5)) - assert len(set(codes)) == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect_special_encoding.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect_special_encoding.py deleted file mode 100644 index 6c41a59..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_func_inspect_special_encoding.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: big5 -*- - - -# Some Traditional Chinese characters: ¤@¨Ç¤¤¤å¦r²Å -def big5_f(): - """¥Î©ó´ú¸Õªº¨ç¼Æ - """ - # µùÄÀ - return 0 diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_hashing.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_hashing.py deleted file mode 100644 index 85593d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_hashing.py +++ /dev/null @@ -1,495 +0,0 @@ -""" -Test the hashing module. -""" - -# Author: Gael Varoquaux -# Copyright (c) 2009 Gael Varoquaux -# License: BSD Style, 3 clauses. - -import time -import hashlib -import sys -import gc -import io -import collections -import itertools -import pickle -import random -from concurrent.futures import ProcessPoolExecutor -from decimal import Decimal - -from joblib.hashing import hash -from joblib.func_inspect import filter_args -from joblib.memory import Memory -from joblib.testing import raises, skipif, fixture, parametrize -from joblib.test.common import np, with_numpy - - -def unicode(s): - return s - - -############################################################################### -# Helper functions for the tests -def time_func(func, *args): - """ Time function func on *args. - """ - times = list() - for _ in range(3): - t1 = time.time() - func(*args) - times.append(time.time() - t1) - return min(times) - - -def relative_time(func1, func2, *args): - """ Return the relative time between func1 and func2 applied on - *args. - """ - time_func1 = time_func(func1, *args) - time_func2 = time_func(func2, *args) - relative_diff = 0.5 * (abs(time_func1 - time_func2) - / (time_func1 + time_func2)) - return relative_diff - - -class Klass(object): - - def f(self, x): - return x - - -class KlassWithCachedMethod(object): - - def __init__(self, cachedir): - mem = Memory(location=cachedir) - self.f = mem.cache(self.f) - - def f(self, x): - return x - - -############################################################################### -# Tests - -input_list = [1, 2, 1., 2., 1 + 1j, 2. + 1j, - 'a', 'b', - (1,), (1, 1,), [1, ], [1, 1, ], - {1: 1}, {1: 2}, {2: 1}, - None, - gc.collect, - [1, ].append, - # Next 2 sets have unorderable elements in python 3. - set(('a', 1)), - set(('a', 1, ('a', 1))), - # Next 2 dicts have unorderable type of keys in python 3. - {'a': 1, 1: 2}, - {'a': 1, 1: 2, 'd': {'a': 1}}] - - -@parametrize('obj1', input_list) -@parametrize('obj2', input_list) -def test_trivial_hash(obj1, obj2): - """Smoke test hash on various types.""" - # Check that 2 objects have the same hash only if they are the same. - are_hashes_equal = hash(obj1) == hash(obj2) - are_objs_identical = obj1 is obj2 - assert are_hashes_equal == are_objs_identical - - -def test_hash_methods(): - # Check that hashing instance methods works - a = io.StringIO(unicode('a')) - assert hash(a.flush) == hash(a.flush) - a1 = collections.deque(range(10)) - a2 = collections.deque(range(9)) - assert hash(a1.extend) != hash(a2.extend) - - -@fixture(scope='function') -@with_numpy -def three_np_arrays(): - rnd = np.random.RandomState(0) - arr1 = rnd.random_sample((10, 10)) - arr2 = arr1.copy() - arr3 = arr2.copy() - arr3[0] += 1 - return arr1, arr2, arr3 - - -def test_hash_numpy_arrays(three_np_arrays): - arr1, arr2, arr3 = three_np_arrays - - for obj1, obj2 in itertools.product(three_np_arrays, repeat=2): - are_hashes_equal = hash(obj1) == hash(obj2) - are_arrays_equal = np.all(obj1 == obj2) - assert are_hashes_equal == are_arrays_equal - - assert hash(arr1) != hash(arr1.T) - - -def test_hash_numpy_dict_of_arrays(three_np_arrays): - arr1, arr2, arr3 = three_np_arrays - - d1 = {1: arr1, 2: arr2} - d2 = {1: arr2, 2: arr1} - d3 = {1: arr2, 2: arr3} - - assert hash(d1) == hash(d2) - assert hash(d1) != hash(d3) - - -@with_numpy -@parametrize('dtype', ['datetime64[s]', 'timedelta64[D]']) -def test_numpy_datetime_array(dtype): - # memoryview is not supported for some dtypes e.g. datetime64 - # see https://github.com/joblib/joblib/issues/188 for more details - a_hash = hash(np.arange(10)) - array = np.arange(0, 10, dtype=dtype) - assert hash(array) != a_hash - - -@with_numpy -def test_hash_numpy_noncontiguous(): - a = np.asarray(np.arange(6000).reshape((1000, 2, 3)), - order='F')[:, :1, :] - b = np.ascontiguousarray(a) - assert hash(a) != hash(b) - - c = np.asfortranarray(a) - assert hash(a) != hash(c) - - -@with_numpy -@parametrize('coerce_mmap', [True, False]) -def test_hash_memmap(tmpdir, coerce_mmap): - """Check that memmap and arrays hash identically if coerce_mmap is True.""" - filename = tmpdir.join('memmap_temp').strpath - try: - m = np.memmap(filename, shape=(10, 10), mode='w+') - a = np.asarray(m) - are_hashes_equal = (hash(a, coerce_mmap=coerce_mmap) == - hash(m, coerce_mmap=coerce_mmap)) - assert are_hashes_equal == coerce_mmap - finally: - if 'm' in locals(): - del m - # Force a garbage-collection cycle, to be certain that the - # object is delete, and we don't run in a problem under - # Windows with a file handle still open. - gc.collect() - - -@with_numpy -@skipif(sys.platform == 'win32', reason='This test is not stable under windows' - ' for some reason') -def test_hash_numpy_performance(): - """ Check the performance of hashing numpy arrays: - - In [22]: a = np.random.random(1000000) - - In [23]: %timeit hashlib.md5(a).hexdigest() - 100 loops, best of 3: 20.7 ms per loop - - In [24]: %timeit hashlib.md5(pickle.dumps(a, protocol=2)).hexdigest() - 1 loops, best of 3: 73.1 ms per loop - - In [25]: %timeit hashlib.md5(cPickle.dumps(a, protocol=2)).hexdigest() - 10 loops, best of 3: 53.9 ms per loop - - In [26]: %timeit hash(a) - 100 loops, best of 3: 20.8 ms per loop - """ - rnd = np.random.RandomState(0) - a = rnd.random_sample(1000000) - - def md5_hash(x): - return hashlib.md5(memoryview(x)).hexdigest() - - relative_diff = relative_time(md5_hash, hash, a) - assert relative_diff < 0.3 - - # Check that hashing an tuple of 3 arrays takes approximately - # 3 times as much as hashing one array - time_hashlib = 3 * time_func(md5_hash, a) - time_hash = time_func(hash, (a, a, a)) - relative_diff = 0.5 * (abs(time_hash - time_hashlib) - / (time_hash + time_hashlib)) - assert relative_diff < 0.3 - - -def test_bound_methods_hash(): - """ Make sure that calling the same method on two different instances - of the same class does resolve to the same hashes. - """ - a = Klass() - b = Klass() - assert (hash(filter_args(a.f, [], (1, ))) == - hash(filter_args(b.f, [], (1, )))) - - -def test_bound_cached_methods_hash(tmpdir): - """ Make sure that calling the same _cached_ method on two different - instances of the same class does resolve to the same hashes. - """ - a = KlassWithCachedMethod(tmpdir.strpath) - b = KlassWithCachedMethod(tmpdir.strpath) - assert (hash(filter_args(a.f.func, [], (1, ))) == - hash(filter_args(b.f.func, [], (1, )))) - - -@with_numpy -def test_hash_object_dtype(): - """ Make sure that ndarrays with dtype `object' hash correctly.""" - - a = np.array([np.arange(i) for i in range(6)], dtype=object) - b = np.array([np.arange(i) for i in range(6)], dtype=object) - - assert hash(a) == hash(b) - - -@with_numpy -def test_numpy_scalar(): - # Numpy scalars are built from compiled functions, and lead to - # strange pickling paths explored, that can give hash collisions - a = np.float64(2.0) - b = np.float64(3.0) - assert hash(a) != hash(b) - - -def test_dict_hash(tmpdir): - # Check that dictionaries hash consistently, even though the ordering - # of the keys is not guaranteed - k = KlassWithCachedMethod(tmpdir.strpath) - - d = {'#s12069__c_maps.nii.gz': [33], - '#s12158__c_maps.nii.gz': [33], - '#s12258__c_maps.nii.gz': [33], - '#s12277__c_maps.nii.gz': [33], - '#s12300__c_maps.nii.gz': [33], - '#s12401__c_maps.nii.gz': [33], - '#s12430__c_maps.nii.gz': [33], - '#s13817__c_maps.nii.gz': [33], - '#s13903__c_maps.nii.gz': [33], - '#s13916__c_maps.nii.gz': [33], - '#s13981__c_maps.nii.gz': [33], - '#s13982__c_maps.nii.gz': [33], - '#s13983__c_maps.nii.gz': [33]} - - a = k.f(d) - b = k.f(a) - - assert hash(a) == hash(b) - - -def test_set_hash(tmpdir): - # Check that sets hash consistently, even though their ordering - # is not guaranteed - k = KlassWithCachedMethod(tmpdir.strpath) - - s = set(['#s12069__c_maps.nii.gz', - '#s12158__c_maps.nii.gz', - '#s12258__c_maps.nii.gz', - '#s12277__c_maps.nii.gz', - '#s12300__c_maps.nii.gz', - '#s12401__c_maps.nii.gz', - '#s12430__c_maps.nii.gz', - '#s13817__c_maps.nii.gz', - '#s13903__c_maps.nii.gz', - '#s13916__c_maps.nii.gz', - '#s13981__c_maps.nii.gz', - '#s13982__c_maps.nii.gz', - '#s13983__c_maps.nii.gz']) - - a = k.f(s) - b = k.f(a) - - assert hash(a) == hash(b) - - -def test_set_decimal_hash(): - # Check that sets containing decimals hash consistently, even though - # ordering is not guaranteed - assert (hash(set([Decimal(0), Decimal('NaN')])) == - hash(set([Decimal('NaN'), Decimal(0)]))) - - -def test_string(): - # Test that we obtain the same hash for object owning several strings, - # whatever the past of these strings (which are immutable in Python) - string = 'foo' - a = {string: 'bar'} - b = {string: 'bar'} - c = pickle.loads(pickle.dumps(b)) - assert hash([a, b]) == hash([a, c]) - - -@with_numpy -def test_numpy_dtype_pickling(): - # numpy dtype hashing is tricky to get right: see #231, #239, #251 #1080, - # #1082, and explanatory comments inside - # ``joblib.hashing.NumpyHasher.save``. - - # In this test, we make sure that the pickling of numpy dtypes is robust to - # object identity and object copy. - - dt1 = np.dtype('f4') - dt2 = np.dtype('f4') - - # simple dtypes objects are interned - assert dt1 is dt2 - assert hash(dt1) == hash(dt2) - - dt1_roundtripped = pickle.loads(pickle.dumps(dt1)) - assert dt1 is not dt1_roundtripped - assert hash(dt1) == hash(dt1_roundtripped) - - assert hash([dt1, dt1]) == hash([dt1_roundtripped, dt1_roundtripped]) - assert hash([dt1, dt1]) == hash([dt1, dt1_roundtripped]) - - complex_dt1 = np.dtype( - [('name', np.str_, 16), ('grades', np.float64, (2,))] - ) - complex_dt2 = np.dtype( - [('name', np.str_, 16), ('grades', np.float64, (2,))] - ) - - # complex dtypes objects are not interned - assert hash(complex_dt1) == hash(complex_dt2) - - complex_dt1_roundtripped = pickle.loads(pickle.dumps(complex_dt1)) - assert complex_dt1_roundtripped is not complex_dt1 - assert hash(complex_dt1) == hash(complex_dt1_roundtripped) - - assert hash([complex_dt1, complex_dt1]) == hash( - [complex_dt1_roundtripped, complex_dt1_roundtripped] - ) - assert hash([complex_dt1, complex_dt1]) == hash( - [complex_dt1_roundtripped, complex_dt1] - ) - - -@parametrize('to_hash,expected', - [('This is a string to hash', - '71b3f47df22cb19431d85d92d0b230b2'), - (u"C'est l\xe9t\xe9", - '2d8d189e9b2b0b2e384d93c868c0e576'), - ((123456, 54321, -98765), - 'e205227dd82250871fa25aa0ec690aa3'), - ([random.Random(42).random() for _ in range(5)], - 'a11ffad81f9682a7d901e6edc3d16c84'), - ({'abcde': 123, 'sadfas': [-9999, 2, 3]}, - 'aeda150553d4bb5c69f0e69d51b0e2ef')]) -def test_hashes_stay_the_same(to_hash, expected): - # We want to make sure that hashes don't change with joblib - # version. For end users, that would mean that they have to - # regenerate their cache from scratch, which potentially means - # lengthy recomputations. - # Expected results have been generated with joblib 0.9.2 - assert hash(to_hash) == expected - - -@with_numpy -def test_hashes_are_different_between_c_and_fortran_contiguous_arrays(): - # We want to be sure that the c-contiguous and f-contiguous versions of the - # same array produce 2 different hashes. - rng = np.random.RandomState(0) - arr_c = rng.random_sample((10, 10)) - arr_f = np.asfortranarray(arr_c) - assert hash(arr_c) != hash(arr_f) - - -@with_numpy -def test_0d_array(): - hash(np.array(0)) - - -@with_numpy -def test_0d_and_1d_array_hashing_is_different(): - assert hash(np.array(0)) != hash(np.array([0])) - - -@with_numpy -def test_hashes_stay_the_same_with_numpy_objects(): - # Note: joblib used to test numpy objects hashing by comparing the produced - # hash of an object with some hard-coded target value to guarantee that - # hashing remains the same across joblib versions. However, since numpy - # 1.20 and joblib 1.0, joblib relies on potentially unstable implementation - # details of numpy to hash np.dtype objects, which makes the stability of - # hash values across different environments hard to guarantee and to test. - # As a result, hashing stability across joblib versions becomes best-effort - # only, and we only test the consistency within a single environment by - # making sure: - # - the hash of two copies of the same objects is the same - # - hashing some object in two different python processes produces the same - # value. This should be viewed as a proxy for testing hash consistency - # through time between Python sessions (provided no change in the - # environment was done between sessions). - - def create_objects_to_hash(): - rng = np.random.RandomState(42) - # Being explicit about dtypes in order to avoid - # architecture-related differences. Also using 'f4' rather than - # 'f8' for float arrays because 'f8' arrays generated by - # rng.random.randn don't seem to be bit-identical on 32bit and - # 64bit machines. - to_hash_list = [ - rng.randint(-1000, high=1000, size=50).astype(' -# Copyright (c) 2009 Gael Varoquaux -# License: BSD Style, 3 clauses. -import re - -from joblib.logger import PrintTime - - -def test_print_time(tmpdir, capsys): - # A simple smoke test for PrintTime. - logfile = tmpdir.join('test.log').strpath - print_time = PrintTime(logfile=logfile) - print_time('Foo') - # Create a second time, to smoke test log rotation. - print_time = PrintTime(logfile=logfile) - print_time('Foo') - # And a third time - print_time = PrintTime(logfile=logfile) - print_time('Foo') - - out_printed_text, err_printed_text = capsys.readouterr() - # Use regexps to be robust to time variations - match = r"Foo: 0\..s, 0\..min\nFoo: 0\..s, 0..min\nFoo: " + \ - r".\..s, 0..min\n" - if not re.match(match, err_printed_text): - raise AssertionError('Excepted %s, got %s' % - (match, err_printed_text)) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memmapping.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memmapping.py deleted file mode 100644 index 42a297a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memmapping.py +++ /dev/null @@ -1,1191 +0,0 @@ -import os -import mmap -import sys -import platform -import gc -import pickle -import itertools -from time import sleep -import subprocess -import threading -import faulthandler - -import pytest - -from joblib.test.common import with_numpy, np -from joblib.test.common import with_multiprocessing -from joblib.test.common import with_dev_shm -from joblib.testing import raises, parametrize, skipif -from joblib.backports import make_memmap -from joblib.parallel import Parallel, delayed - -from joblib.pool import MemmappingPool -from joblib.executor import _TestingMemmappingExecutor as TestExecutor -from joblib._memmapping_reducer import has_shareable_memory -from joblib._memmapping_reducer import ArrayMemmapForwardReducer -from joblib._memmapping_reducer import _strided_from_memmap -from joblib._memmapping_reducer import _get_temp_dir -from joblib._memmapping_reducer import _WeakArrayKeyMap -from joblib._memmapping_reducer import _get_backing_memmap -import joblib._memmapping_reducer as jmr - - -def setup_module(): - faulthandler.dump_traceback_later(timeout=300, exit=True) - - -def teardown_module(): - faulthandler.cancel_dump_traceback_later() - - -def check_memmap_and_send_back(array): - assert _get_backing_memmap(array) is not None - return array - - -def check_array(args): - """Dummy helper function to be executed in subprocesses - - Check that the provided array has the expected values in the provided - range. - - """ - data, position, expected = args - np.testing.assert_array_equal(data[position], expected) - - -def inplace_double(args): - """Dummy helper function to be executed in subprocesses - - - Check that the input array has the right values in the provided range - and perform an inplace modification to double the values in the range by - two. - - """ - data, position, expected = args - assert data[position] == expected - data[position] *= 2 - np.testing.assert_array_equal(data[position], 2 * expected) - - -@with_numpy -@with_multiprocessing -def test_memmap_based_array_reducing(tmpdir): - """Check that it is possible to reduce a memmap backed array""" - assert_array_equal = np.testing.assert_array_equal - filename = tmpdir.join('test.mmap').strpath - - # Create a file larger than what will be used by a - buffer = np.memmap(filename, dtype=np.float64, shape=500, mode='w+') - - # Fill the original buffer with negative markers to detect over of - # underflow in case of test failures - buffer[:] = - 1.0 * np.arange(buffer.shape[0], dtype=buffer.dtype) - buffer.flush() - - # Memmap a 2D fortran array on a offsetted subsection of the previous - # buffer - a = np.memmap(filename, dtype=np.float64, shape=(3, 5, 4), - mode='r+', order='F', offset=4) - a[:] = np.arange(60).reshape(a.shape) - - # Build various views that share the buffer with the original memmap - - # b is an memmap sliced view on an memmap instance - b = a[1:-1, 2:-1, 2:4] - - # c and d are array views - c = np.asarray(b) - d = c.T - - # Array reducer with auto dumping disabled - reducer = ArrayMemmapForwardReducer(None, tmpdir.strpath, 'c', True) - - def reconstruct_array_or_memmap(x): - cons, args = reducer(x) - return cons(*args) - - # Reconstruct original memmap - a_reconstructed = reconstruct_array_or_memmap(a) - assert has_shareable_memory(a_reconstructed) - assert isinstance(a_reconstructed, np.memmap) - assert_array_equal(a_reconstructed, a) - - # Reconstruct strided memmap view - b_reconstructed = reconstruct_array_or_memmap(b) - assert has_shareable_memory(b_reconstructed) - assert_array_equal(b_reconstructed, b) - - # Reconstruct arrays views on memmap base - c_reconstructed = reconstruct_array_or_memmap(c) - assert not isinstance(c_reconstructed, np.memmap) - assert has_shareable_memory(c_reconstructed) - assert_array_equal(c_reconstructed, c) - - d_reconstructed = reconstruct_array_or_memmap(d) - assert not isinstance(d_reconstructed, np.memmap) - assert has_shareable_memory(d_reconstructed) - assert_array_equal(d_reconstructed, d) - - # Test graceful degradation on fake memmap instances with in-memory - # buffers - a3 = a * 3 - assert not has_shareable_memory(a3) - a3_reconstructed = reconstruct_array_or_memmap(a3) - assert not has_shareable_memory(a3_reconstructed) - assert not isinstance(a3_reconstructed, np.memmap) - assert_array_equal(a3_reconstructed, a * 3) - - # Test graceful degradation on arrays derived from fake memmap instances - b3 = np.asarray(a3) - assert not has_shareable_memory(b3) - - b3_reconstructed = reconstruct_array_or_memmap(b3) - assert isinstance(b3_reconstructed, np.ndarray) - assert not has_shareable_memory(b3_reconstructed) - assert_array_equal(b3_reconstructed, b3) - - -@with_multiprocessing -@skipif((sys.platform != "win32") or (), - reason="PermissionError only easily triggerable on Windows") -def test_resource_tracker_retries_when_permissionerror(tmpdir): - # Test resource_tracker retry mechanism when unlinking memmaps. See more - # thorough information in the ``unlink_file`` documentation of joblib. - filename = tmpdir.join('test.mmap').strpath - cmd = """if 1: - import os - import numpy as np - import time - from joblib.externals.loky.backend import resource_tracker - resource_tracker.VERBOSE = 1 - - # Start the resource tracker - resource_tracker.ensure_running() - time.sleep(1) - - # Create a file containing numpy data - memmap = np.memmap(r"{filename}", dtype=np.float64, shape=10, mode='w+') - memmap[:] = np.arange(10).astype(np.int8).data - memmap.flush() - assert os.path.exists(r"{filename}") - del memmap - - # Create a np.memmap backed by this file - memmap = np.memmap(r"{filename}", dtype=np.float64, shape=10, mode='w+') - resource_tracker.register(r"{filename}", "file") - - # Ask the resource_tracker to delete the file backing the np.memmap , this - # should raise PermissionError that the resource_tracker will log. - resource_tracker.maybe_unlink(r"{filename}", "file") - - # Wait for the resource_tracker to process the maybe_unlink before cleaning - # up the memmap - time.sleep(2) - """.format(filename=filename) - p = subprocess.Popen([sys.executable, '-c', cmd], stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - p.wait() - out, err = p.communicate() - assert p.returncode == 0 - assert out == b'' - msg = 'tried to unlink {}, got PermissionError'.format(filename) - assert msg in err.decode() - - -@with_numpy -@with_multiprocessing -def test_high_dimension_memmap_array_reducing(tmpdir): - assert_array_equal = np.testing.assert_array_equal - - filename = tmpdir.join('test.mmap').strpath - - # Create a high dimensional memmap - a = np.memmap(filename, dtype=np.float64, shape=(100, 15, 15, 3), - mode='w+') - a[:] = np.arange(100 * 15 * 15 * 3).reshape(a.shape) - - # Create some slices/indices at various dimensions - b = a[0:10] - c = a[:, 5:10] - d = a[:, :, :, 0] - e = a[1:3:4] - - # Array reducer with auto dumping disabled - reducer = ArrayMemmapForwardReducer(None, tmpdir.strpath, 'c', True) - - def reconstruct_array_or_memmap(x): - cons, args = reducer(x) - return cons(*args) - - a_reconstructed = reconstruct_array_or_memmap(a) - assert has_shareable_memory(a_reconstructed) - assert isinstance(a_reconstructed, np.memmap) - assert_array_equal(a_reconstructed, a) - - b_reconstructed = reconstruct_array_or_memmap(b) - assert has_shareable_memory(b_reconstructed) - assert_array_equal(b_reconstructed, b) - - c_reconstructed = reconstruct_array_or_memmap(c) - assert has_shareable_memory(c_reconstructed) - assert_array_equal(c_reconstructed, c) - - d_reconstructed = reconstruct_array_or_memmap(d) - assert has_shareable_memory(d_reconstructed) - assert_array_equal(d_reconstructed, d) - - e_reconstructed = reconstruct_array_or_memmap(e) - assert has_shareable_memory(e_reconstructed) - assert_array_equal(e_reconstructed, e) - - -@with_numpy -def test__strided_from_memmap(tmpdir): - fname = tmpdir.join('test.mmap').strpath - size = 5 * mmap.ALLOCATIONGRANULARITY - offset = mmap.ALLOCATIONGRANULARITY + 1 - # This line creates the mmap file that is reused later - memmap_obj = np.memmap(fname, mode='w+', shape=size + offset) - # filename, dtype, mode, offset, order, shape, strides, total_buffer_len - memmap_obj = _strided_from_memmap(fname, dtype='uint8', mode='r', - offset=offset, order='C', shape=size, - strides=None, total_buffer_len=None, - unlink_on_gc_collect=False) - assert isinstance(memmap_obj, np.memmap) - assert memmap_obj.offset == offset - memmap_backed_obj = _strided_from_memmap( - fname, dtype='uint8', mode='r', offset=offset, order='C', - shape=(size // 2,), strides=(2,), total_buffer_len=size, - unlink_on_gc_collect=False - ) - assert _get_backing_memmap(memmap_backed_obj).offset == offset - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_pool_with_memmap(factory, tmpdir): - """Check that subprocess can access and update shared memory memmap""" - assert_array_equal = np.testing.assert_array_equal - - # Fork the subprocess before allocating the objects to be passed - pool_temp_folder = tmpdir.mkdir('pool').strpath - p = factory(10, max_nbytes=2, temp_folder=pool_temp_folder) - try: - filename = tmpdir.join('test.mmap').strpath - a = np.memmap(filename, dtype=np.float32, shape=(3, 5), mode='w+') - a.fill(1.0) - - p.map(inplace_double, [(a, (i, j), 1.0) - for i in range(a.shape[0]) - for j in range(a.shape[1])]) - - assert_array_equal(a, 2 * np.ones(a.shape)) - - # Open a copy-on-write view on the previous data - b = np.memmap(filename, dtype=np.float32, shape=(5, 3), mode='c') - - p.map(inplace_double, [(b, (i, j), 2.0) - for i in range(b.shape[0]) - for j in range(b.shape[1])]) - - # Passing memmap instances to the pool should not trigger the creation - # of new files on the FS - assert os.listdir(pool_temp_folder) == [] - - # the original data is untouched - assert_array_equal(a, 2 * np.ones(a.shape)) - assert_array_equal(b, 2 * np.ones(b.shape)) - - # readonly maps can be read but not updated - c = np.memmap(filename, dtype=np.float32, shape=(10,), mode='r', - offset=5 * 4) - - with raises(AssertionError): - p.map(check_array, [(c, i, 3.0) for i in range(c.shape[0])]) - - # depending on the version of numpy one can either get a RuntimeError - # or a ValueError - with raises((RuntimeError, ValueError)): - p.map(inplace_double, [(c, i, 2.0) for i in range(c.shape[0])]) - finally: - # Clean all filehandlers held by the pool - p.terminate() - del p - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_pool_with_memmap_array_view(factory, tmpdir): - """Check that subprocess can access and update shared memory array""" - assert_array_equal = np.testing.assert_array_equal - - # Fork the subprocess before allocating the objects to be passed - pool_temp_folder = tmpdir.mkdir('pool').strpath - p = factory(10, max_nbytes=2, temp_folder=pool_temp_folder) - try: - - filename = tmpdir.join('test.mmap').strpath - a = np.memmap(filename, dtype=np.float32, shape=(3, 5), mode='w+') - a.fill(1.0) - - # Create an ndarray view on the memmap instance - a_view = np.asarray(a) - assert not isinstance(a_view, np.memmap) - assert has_shareable_memory(a_view) - - p.map(inplace_double, [(a_view, (i, j), 1.0) - for i in range(a.shape[0]) - for j in range(a.shape[1])]) - - # Both a and the a_view have been updated - assert_array_equal(a, 2 * np.ones(a.shape)) - assert_array_equal(a_view, 2 * np.ones(a.shape)) - - # Passing memmap array view to the pool should not trigger the - # creation of new files on the FS - assert os.listdir(pool_temp_folder) == [] - - finally: - p.terminate() - del p - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_permission_error_windows_reference_cycle(backend): - # Non regression test for: - # https://github.com/joblib/joblib/issues/806 - # - # The issue happens when trying to delete a memory mapped file that has - # not yet been closed by one of the worker processes. - cmd = """if 1: - import numpy as np - from joblib import Parallel, delayed - - - data = np.random.rand(int(2e6)).reshape((int(1e6), 2)) - - # Build a complex cyclic reference that is likely to delay garbage - # collection of the memmapped array in the worker processes. - first_list = current_list = [data] - for i in range(10): - current_list = [current_list] - first_list.append(current_list) - - if __name__ == "__main__": - results = Parallel(n_jobs=2, backend="{b}")( - delayed(len)(current_list) for i in range(10)) - assert results == [1] * 10 - """.format(b=backend) - p = subprocess.Popen([sys.executable, '-c', cmd], stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - p.wait() - out, err = p.communicate() - assert p.returncode == 0, out.decode() + "\n\n" + err.decode() - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_permission_error_windows_memmap_sent_to_parent(backend): - # Second non-regression test for: - # https://github.com/joblib/joblib/issues/806 - # previously, child process would not convert temporary memmaps to numpy - # arrays when sending the data back to the parent process. This would lead - # to permission errors on windows when deleting joblib's temporary folder, - # as the memmaped files handles would still opened in the parent process. - cmd = '''if 1: - import os - import time - - import numpy as np - - from joblib import Parallel, delayed - from testutils import return_slice_of_data - - data = np.ones(int(2e6)) - - if __name__ == '__main__': - # warm-up call to launch the workers and start the resource_tracker - _ = Parallel(n_jobs=2, verbose=5, backend='{b}')( - delayed(id)(i) for i in range(20)) - - time.sleep(0.5) - - slice_of_data = Parallel(n_jobs=2, verbose=5, backend='{b}')( - delayed(return_slice_of_data)(data, 0, 20) for _ in range(10)) - '''.format(b=backend) - - for _ in range(3): - env = os.environ.copy() - env['PYTHONPATH'] = os.path.dirname(__file__) - p = subprocess.Popen([sys.executable, '-c', cmd], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, env=env) - p.wait() - out, err = p.communicate() - assert p.returncode == 0, err - assert out == b'' - if sys.version_info[:3] not in [(3, 8, 0), (3, 8, 1)]: - # In early versions of Python 3.8, a reference leak - # https://github.com/cloudpipe/cloudpickle/issues/327, holds - # references to pickled objects, generating race condition during - # cleanup finalizers of joblib and noisy resource_tracker outputs. - assert b'resource_tracker' not in err - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_parallel_isolated_temp_folders(backend): - # Test that consecutive Parallel call use isolated subfolders, even - # for the loky backend that reuses its executor instance across calls. - array = np.arange(int(1e2)) - [filename_1] = Parallel(n_jobs=2, backend=backend, max_nbytes=10)( - delayed(getattr)(array, 'filename') for _ in range(1) - ) - [filename_2] = Parallel(n_jobs=2, backend=backend, max_nbytes=10)( - delayed(getattr)(array, 'filename') for _ in range(1) - ) - assert os.path.dirname(filename_2) != os.path.dirname(filename_1) - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_managed_backend_reuse_temp_folder(backend): - # Test that calls to a managed parallel object reuse the same memmaps. - array = np.arange(int(1e2)) - with Parallel(n_jobs=2, backend=backend, max_nbytes=10) as p: - [filename_1] = p( - delayed(getattr)(array, 'filename') for _ in range(1) - ) - [filename_2] = p( - delayed(getattr)(array, 'filename') for _ in range(1) - ) - assert os.path.dirname(filename_2) == os.path.dirname(filename_1) - - -@with_numpy -@with_multiprocessing -def test_memmapping_temp_folder_thread_safety(): - # Concurrent calls to Parallel with the loky backend will use the same - # executor, and thus the same reducers. Make sure that those reducers use - # different temporary folders depending on which Parallel objects called - # them, which is necessary to limit potential race conditions during the - # garbage collection of temporary memmaps. - array = np.arange(int(1e2)) - - temp_dirs_thread_1 = set() - temp_dirs_thread_2 = set() - - def concurrent_get_filename(array, temp_dirs): - with Parallel(backend='loky', n_jobs=2, max_nbytes=10) as p: - for i in range(10): - [filename] = p( - delayed(getattr)(array, 'filename') for _ in range(1) - ) - temp_dirs.add(os.path.dirname(filename)) - - t1 = threading.Thread( - target=concurrent_get_filename, args=(array, temp_dirs_thread_1) - ) - t2 = threading.Thread( - target=concurrent_get_filename, args=(array, temp_dirs_thread_2) - ) - - t1.start() - t2.start() - - t1.join() - t2.join() - - assert len(temp_dirs_thread_1) == 1 - assert len(temp_dirs_thread_2) == 1 - - assert temp_dirs_thread_1 != temp_dirs_thread_2 - - -@with_numpy -@with_multiprocessing -def test_multithreaded_parallel_termination_resource_tracker_silent(): - # test that concurrent termination attempts of a same executor does not - # emit any spurious error from the resource_tracker. We test various - # situations making 0, 1 or both parallel call sending a task that will - # make the worker (and thus the whole Parallel call) error out. - cmd = '''if 1: - import os - import numpy as np - from joblib import Parallel, delayed - from joblib.externals.loky.backend import resource_tracker - from concurrent.futures import ThreadPoolExecutor, wait - - resource_tracker.VERBOSE = 0 - - array = np.arange(int(1e2)) - - temp_dirs_thread_1 = set() - temp_dirs_thread_2 = set() - - - def raise_error(array): - raise ValueError - - - def parallel_get_filename(array, temp_dirs): - with Parallel(backend="loky", n_jobs=2, max_nbytes=10) as p: - for i in range(10): - [filename] = p( - delayed(getattr)(array, "filename") for _ in range(1) - ) - temp_dirs.add(os.path.dirname(filename)) - - - def parallel_raise(array, temp_dirs): - with Parallel(backend="loky", n_jobs=2, max_nbytes=10) as p: - for i in range(10): - [filename] = p( - delayed(raise_error)(array) for _ in range(1) - ) - temp_dirs.add(os.path.dirname(filename)) - - - executor = ThreadPoolExecutor(max_workers=2) - - # both function calls will use the same loky executor, but with a - # different Parallel object. - future_1 = executor.submit({f1}, array, temp_dirs_thread_1) - future_2 = executor.submit({f2}, array, temp_dirs_thread_2) - - # Wait for both threads to terminate their backend - wait([future_1, future_2]) - - future_1.result() - future_2.result() - ''' - functions_and_returncodes = [ - ("parallel_get_filename", "parallel_get_filename", 0), - ("parallel_get_filename", "parallel_raise", 1), - ("parallel_raise", "parallel_raise", 1) - ] - - for f1, f2, returncode in functions_and_returncodes: - p = subprocess.Popen([sys.executable, '-c', cmd.format(f1=f1, f2=f2)], - stderr=subprocess.PIPE, stdout=subprocess.PIPE) - p.wait() - out, err = p.communicate() - assert p.returncode == returncode, out.decode() - assert b"resource_tracker" not in err, err.decode() - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_many_parallel_calls_on_same_object(backend): - # After #966 got merged, consecutive Parallel objects were sharing temp - # folder, which would lead to race conditions happening during the - # temporary resources management with the resource_tracker. This is a - # non-regression test that makes sure that consecutive Parallel operations - # on the same object do not error out. - cmd = '''if 1: - import os - import time - - import numpy as np - - from joblib import Parallel, delayed - from testutils import return_slice_of_data - - data = np.ones(100) - - if __name__ == '__main__': - for i in range(5): - slice_of_data = Parallel( - n_jobs=2, max_nbytes=1, backend='{b}')( - delayed(return_slice_of_data)(data, 0, 20) - for _ in range(10) - ) - '''.format(b=backend) - env = os.environ.copy() - env['PYTHONPATH'] = os.path.dirname(__file__) - p = subprocess.Popen( - [sys.executable, '-c', cmd], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - env=env, - ) - p.wait() - out, err = p.communicate() - assert p.returncode == 0, err - assert out == b'' - if sys.version_info[:3] not in [(3, 8, 0), (3, 8, 1)]: - # In early versions of Python 3.8, a reference leak - # https://github.com/cloudpipe/cloudpickle/issues/327, holds - # references to pickled objects, generating race condition during - # cleanup finalizers of joblib and noisy resource_tracker outputs. - assert b'resource_tracker' not in err - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_memmap_returned_as_regular_array(backend): - data = np.ones(int(1e3)) - # Check that child processes send temporary memmaps back as numpy arrays. - [result] = Parallel(n_jobs=2, backend=backend, max_nbytes=100)( - delayed(check_memmap_and_send_back)(data) for _ in range(1)) - assert _get_backing_memmap(result) is None - - -@with_numpy -@with_multiprocessing -@parametrize("backend", ["multiprocessing", "loky"]) -def test_resource_tracker_silent_when_reference_cycles(backend): - # There is a variety of reasons that can make joblib with loky backend - # output noisy warnings when a reference cycle is preventing a memmap from - # being garbage collected. Especially, joblib's main process finalizer - # deletes the temporary folder if it was not done before, which can - # interact badly with the resource_tracker. We don't risk leaking any - # resources, but this will likely make joblib output a lot of low-level - # confusing messages. - # - # This test makes sure that the resource_tracker is silent when a reference - # has been collected concurrently on non-Windows platforms. - # - # Note that the script in ``cmd`` is the exact same script as in - # test_permission_error_windows_reference_cycle. - if backend == "loky" and sys.platform.startswith('win'): - # XXX: on Windows, reference cycles can delay timely garbage collection - # and make it impossible to properly delete the temporary folder in the - # main process because of permission errors. - pytest.xfail( - "The temporary folder cannot be deleted on Windows in the " - "presence of a reference cycle" - ) - - cmd = """if 1: - import numpy as np - from joblib import Parallel, delayed - - - data = np.random.rand(int(2e6)).reshape((int(1e6), 2)) - - # Build a complex cyclic reference that is likely to delay garbage - # collection of the memmapped array in the worker processes. - first_list = current_list = [data] - for i in range(10): - current_list = [current_list] - first_list.append(current_list) - - if __name__ == "__main__": - results = Parallel(n_jobs=2, backend="{b}")( - delayed(len)(current_list) for i in range(10)) - assert results == [1] * 10 - """.format(b=backend) - p = subprocess.Popen([sys.executable, '-c', cmd], stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - p.wait() - out, err = p.communicate() - out = out.decode() - err = err.decode() - assert p.returncode == 0, out + "\n\n" + err - assert "resource_tracker" not in err, err - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_memmapping_pool_for_large_arrays(factory, tmpdir): - """Check that large arrays are not copied in memory""" - - # Check that the tempfolder is empty - assert os.listdir(tmpdir.strpath) == [] - - # Build an array reducers that automatically dump large array content - # to filesystem backed memmap instances to avoid memory explosion - p = factory(3, max_nbytes=40, temp_folder=tmpdir.strpath, verbose=2) - try: - # The temporary folder for the pool is not provisioned in advance - assert os.listdir(tmpdir.strpath) == [] - assert not os.path.exists(p._temp_folder) - - small = np.ones(5, dtype=np.float32) - assert small.nbytes == 20 - p.map(check_array, [(small, i, 1.0) for i in range(small.shape[0])]) - - # Memory has been copied, the pool filesystem folder is unused - assert os.listdir(tmpdir.strpath) == [] - - # Try with a file larger than the memmap threshold of 40 bytes - large = np.ones(100, dtype=np.float64) - assert large.nbytes == 800 - p.map(check_array, [(large, i, 1.0) for i in range(large.shape[0])]) - - # The data has been dumped in a temp folder for subprocess to share it - # without per-child memory copies - assert os.path.isdir(p._temp_folder) - dumped_filenames = os.listdir(p._temp_folder) - assert len(dumped_filenames) == 1 - - # Check that memory mapping is not triggered for arrays with - # dtype='object' - objects = np.array(['abc'] * 100, dtype='object') - results = p.map(has_shareable_memory, [objects]) - assert not results[0] - - finally: - # check FS garbage upon pool termination - p.terminate() - for i in range(10): - sleep(.1) - if not os.path.exists(p._temp_folder): - break - else: # pragma: no cover - raise AssertionError( - 'temporary folder {} was not deleted'.format(p._temp_folder) - ) - del p - - -@with_numpy -@with_multiprocessing -@parametrize( - "backend", - [ - pytest.param( - "multiprocessing", - marks=pytest.mark.xfail( - reason='https://github.com/joblib/joblib/issues/1086' - ), - ), - "loky", - ] -) -def test_child_raises_parent_exits_cleanly(backend): - # When a task executed by a child process raises an error, the parent - # process's backend is notified, and calls abort_everything. - # In loky, abort_everything itself calls shutdown(kill_workers=True) which - # sends SIGKILL to the worker, preventing it from running the finalizers - # supposed to signal the resource_tracker when the worker is done using - # objects relying on a shared resource (e.g np.memmaps). Because this - # behavior is prone to : - # - cause a resource leak - # - make the resource tracker emit noisy resource warnings - # we explicitly test that, when the said situation occurs: - # - no resources are actually leaked - # - the temporary resources are deleted as soon as possible (typically, at - # the end of the failing Parallel call) - # - the resource_tracker does not emit any warnings. - cmd = """if 1: - import os - from pathlib import Path - from time import sleep - - import numpy as np - from joblib import Parallel, delayed - from testutils import print_filename_and_raise - - data = np.random.rand(1000) - - def get_temp_folder(parallel_obj, backend): - if "{b}" == "loky": - return Path(parallel_obj._backend._workers._temp_folder) - else: - return Path(parallel_obj._backend._pool._temp_folder) - - - if __name__ == "__main__": - try: - with Parallel(n_jobs=2, backend="{b}", max_nbytes=100) as p: - temp_folder = get_temp_folder(p, "{b}") - p(delayed(print_filename_and_raise)(data) - for i in range(1)) - except ValueError as e: - # the temporary folder should be deleted by the end of this - # call but apparently on some file systems, this takes - # some time to be visible. - # - # We attempt to write into the temporary folder to test for - # its existence and we wait for a maximum of 10 seconds. - for i in range(100): - try: - with open(temp_folder / "some_file.txt", "w") as f: - f.write("some content") - except FileNotFoundError: - # temp_folder has been deleted, all is fine - break - - # ... else, wait a bit and try again - sleep(.1) - else: - raise AssertionError( - str(temp_folder) + " was not deleted" - ) from e - """.format(b=backend) - env = os.environ.copy() - env['PYTHONPATH'] = os.path.dirname(__file__) - p = subprocess.Popen([sys.executable, '-c', cmd], stderr=subprocess.PIPE, - stdout=subprocess.PIPE, env=env) - p.wait() - out, err = p.communicate() - out, err = out.decode(), err.decode() - filename = out.split('\n')[0] - assert p.returncode == 0, err or out - assert err == '' # no resource_tracker warnings. - assert not os.path.exists(filename) - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_memmapping_pool_for_large_arrays_disabled(factory, tmpdir): - """Check that large arrays memmapping can be disabled""" - # Set max_nbytes to None to disable the auto memmapping feature - p = factory(3, max_nbytes=None, temp_folder=tmpdir.strpath) - try: - - # Check that the tempfolder is empty - assert os.listdir(tmpdir.strpath) == [] - - # Try with a file largish than the memmap threshold of 40 bytes - large = np.ones(100, dtype=np.float64) - assert large.nbytes == 800 - p.map(check_array, [(large, i, 1.0) for i in range(large.shape[0])]) - - # Check that the tempfolder is still empty - assert os.listdir(tmpdir.strpath) == [] - - finally: - # Cleanup open file descriptors - p.terminate() - del p - - -@with_numpy -@with_multiprocessing -@with_dev_shm -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_memmapping_on_large_enough_dev_shm(factory): - """Check that memmapping uses /dev/shm when possible""" - orig_size = jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE - try: - # Make joblib believe that it can use /dev/shm even when running on a - # CI container where the size of the /dev/shm is not very large (that - # is at least 32 MB instead of 2 GB by default). - jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE = int(32e6) - p = factory(3, max_nbytes=10) - try: - # Check that the pool has correctly detected the presence of the - # shared memory filesystem. - pool_temp_folder = p._temp_folder - folder_prefix = '/dev/shm/joblib_memmapping_folder_' - assert pool_temp_folder.startswith(folder_prefix) - assert os.path.exists(pool_temp_folder) - - # Try with a file larger than the memmap threshold of 10 bytes - a = np.ones(100, dtype=np.float64) - assert a.nbytes == 800 - p.map(id, [a] * 10) - # a should have been memmapped to the pool temp folder: the joblib - # pickling procedure generate one .pkl file: - assert len(os.listdir(pool_temp_folder)) == 1 - - # create a new array with content that is different from 'a' so - # that it is mapped to a different file in the temporary folder of - # the pool. - b = np.ones(100, dtype=np.float64) * 2 - assert b.nbytes == 800 - p.map(id, [b] * 10) - # A copy of both a and b are now stored in the shared memory folder - assert len(os.listdir(pool_temp_folder)) == 2 - finally: - # Cleanup open file descriptors - p.terminate() - del p - - for i in range(100): - # The temp folder is cleaned up upon pool termination - if not os.path.exists(pool_temp_folder): - break - sleep(.1) - else: # pragma: no cover - raise AssertionError('temporary folder of pool was not deleted') - finally: - jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE = orig_size - - -@with_numpy -@with_multiprocessing -@with_dev_shm -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_memmapping_on_too_small_dev_shm(factory): - orig_size = jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE - try: - # Make joblib believe that it cannot use /dev/shm unless there is - # 42 exabytes of available shared memory in /dev/shm - jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE = int(42e18) - - p = factory(3, max_nbytes=10) - try: - # Check that the pool has correctly detected the presence of the - # shared memory filesystem. - pool_temp_folder = p._temp_folder - assert not pool_temp_folder.startswith('/dev/shm') - finally: - # Cleanup open file descriptors - p.terminate() - del p - - # The temp folder is cleaned up upon pool termination - assert not os.path.exists(pool_temp_folder) - finally: - jmr.SYSTEM_SHARED_MEM_FS_MIN_SIZE = orig_size - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_memmapping_pool_for_large_arrays_in_return(factory, tmpdir): - """Check that large arrays are not copied in memory in return""" - assert_array_equal = np.testing.assert_array_equal - - # Build an array reducers that automatically dump large array content - # but check that the returned datastructure are regular arrays to avoid - # passing a memmap array pointing to a pool controlled temp folder that - # might be confusing to the user - - # The MemmappingPool user can always return numpy.memmap object explicitly - # to avoid memory copy - p = factory(3, max_nbytes=10, temp_folder=tmpdir.strpath) - try: - res = p.apply_async(np.ones, args=(1000,)) - large = res.get() - assert not has_shareable_memory(large) - assert_array_equal(large, np.ones(1000)) - finally: - p.terminate() - del p - - -def _worker_multiply(a, n_times): - """Multiplication function to be executed by subprocess""" - assert has_shareable_memory(a) - return a * n_times - - -@with_numpy -@with_multiprocessing -@parametrize("factory", [MemmappingPool, TestExecutor.get_memmapping_executor], - ids=["multiprocessing", "loky"]) -def test_workaround_against_bad_memmap_with_copied_buffers(factory, tmpdir): - """Check that memmaps with a bad buffer are returned as regular arrays - - Unary operations and ufuncs on memmap instances return a new memmap - instance with an in-memory buffer (probably a numpy bug). - """ - assert_array_equal = np.testing.assert_array_equal - - p = factory(3, max_nbytes=10, temp_folder=tmpdir.strpath) - try: - # Send a complex, large-ish view on a array that will be converted to - # a memmap in the worker process - a = np.asarray(np.arange(6000).reshape((1000, 2, 3)), - order='F')[:, :1, :] - - # Call a non-inplace multiply operation on the worker and memmap and - # send it back to the parent. - b = p.apply_async(_worker_multiply, args=(a, 3)).get() - assert not has_shareable_memory(b) - assert_array_equal(b, 3 * a) - finally: - p.terminate() - del p - - -def identity(arg): - return arg - - -@with_numpy -@with_multiprocessing -@parametrize( - "factory,retry_no", - list(itertools.product( - [MemmappingPool, TestExecutor.get_memmapping_executor], range(3))), - ids=['{}, {}'.format(x, y) for x, y in itertools.product( - ["multiprocessing", "loky"], map(str, range(3)))]) -def test_pool_memmap_with_big_offset(factory, retry_no, tmpdir): - # Test that numpy memmap offset is set correctly if greater than - # mmap.ALLOCATIONGRANULARITY, see - # https://github.com/joblib/joblib/issues/451 and - # https://github.com/numpy/numpy/pull/8443 for more details. - fname = tmpdir.join('test.mmap').strpath - size = 5 * mmap.ALLOCATIONGRANULARITY - offset = mmap.ALLOCATIONGRANULARITY + 1 - obj = make_memmap(fname, mode='w+', shape=size, dtype='uint8', - offset=offset) - - p = factory(2, temp_folder=tmpdir.strpath) - result = p.apply_async(identity, args=(obj,)).get() - assert isinstance(result, np.memmap) - assert result.offset == offset - np.testing.assert_array_equal(obj, result) - p.terminate() - - -def test_pool_get_temp_dir(tmpdir): - pool_folder_name = 'test.tmpdir' - pool_folder, shared_mem = _get_temp_dir(pool_folder_name, tmpdir.strpath) - assert shared_mem is False - assert pool_folder == tmpdir.join('test.tmpdir').strpath - - pool_folder, shared_mem = _get_temp_dir(pool_folder_name, temp_folder=None) - if sys.platform.startswith('win'): - assert shared_mem is False - assert pool_folder.endswith(pool_folder_name) - - -def test_pool_get_temp_dir_no_statvfs(tmpdir, monkeypatch): - """Check that _get_temp_dir works when os.statvfs is not defined - - Regression test for #902 - """ - pool_folder_name = 'test.tmpdir' - import joblib._memmapping_reducer - if hasattr(joblib._memmapping_reducer.os, 'statvfs'): - # We are on Unix, since Windows doesn't have this function - monkeypatch.delattr(joblib._memmapping_reducer.os, 'statvfs') - - pool_folder, shared_mem = _get_temp_dir(pool_folder_name, temp_folder=None) - if sys.platform.startswith('win'): - assert shared_mem is False - assert pool_folder.endswith(pool_folder_name) - - -@with_numpy -@skipif(sys.platform == 'win32', reason='This test fails with a ' - 'PermissionError on Windows') -@parametrize("mmap_mode", ["r+", "w+"]) -def test_numpy_arrays_use_different_memory(mmap_mode): - def func(arr, value): - arr[:] = value - return arr - - arrays = [np.zeros((10, 10), dtype='float64') for i in range(10)] - - results = Parallel(mmap_mode=mmap_mode, max_nbytes=0, n_jobs=2)( - delayed(func)(arr, i) for i, arr in enumerate(arrays)) - - for i, arr in enumerate(results): - np.testing.assert_array_equal(arr, i) - - -@with_numpy -def test_weak_array_key_map(): - - def assert_empty_after_gc_collect(container, retries=100): - for i in range(retries): - if len(container) == 0: - return - gc.collect() - sleep(.1) - assert len(container) == 0 - - a = np.ones(42) - m = _WeakArrayKeyMap() - m.set(a, 'a') - assert m.get(a) == 'a' - - b = a - assert m.get(b) == 'a' - m.set(b, 'b') - assert m.get(a) == 'b' - - del a - gc.collect() - assert len(m._data) == 1 - assert m.get(b) == 'b' - - del b - assert_empty_after_gc_collect(m._data) - - c = np.ones(42) - m.set(c, 'c') - assert len(m._data) == 1 - assert m.get(c) == 'c' - - with raises(KeyError): - m.get(np.ones(42)) - - del c - assert_empty_after_gc_collect(m._data) - - # Check that creating and dropping numpy arrays with potentially the same - # object id will not cause the map to get confused. - def get_set_get_collect(m, i): - a = np.ones(42) - with raises(KeyError): - m.get(a) - m.set(a, i) - assert m.get(a) == i - return id(a) - - unique_ids = set([get_set_get_collect(m, i) for i in range(1000)]) - if platform.python_implementation() == 'CPython': - # On CPython (at least) the same id is often reused many times for the - # temporary arrays created under the local scope of the - # get_set_get_collect function without causing any spurious lookups / - # insertions in the map. Apparently on Python nogil, the id is not - # reused as often. - max_len_unique_ids = 400 if getattr(sys.flags, 'nogil', False) else 100 - assert len(unique_ids) < max_len_unique_ids - - -def test_weak_array_key_map_no_pickling(): - m = _WeakArrayKeyMap() - with raises(pickle.PicklingError): - pickle.dumps(m) - - -@with_numpy -@with_multiprocessing -def test_direct_mmap(tmpdir): - testfile = str(tmpdir.join('arr.dat')) - a = np.arange(10, dtype='uint8') - a.tofile(testfile) - - def _read_array(): - with open(testfile) as fd: - mm = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ, offset=0) - return np.ndarray((10,), dtype=np.uint8, buffer=mm, offset=0) - - def func(x): - return x**2 - - arr = _read_array() - - # this is expected to work and gives the reference - ref = Parallel(n_jobs=2)(delayed(func)(x) for x in [a]) - - # now test that it work with the mmap array - results = Parallel(n_jobs=2)(delayed(func)(x) for x in [arr]) - np.testing.assert_array_equal(results, ref) - - # also test with a mmap array read in the subprocess - def worker(): - return _read_array() - - results = Parallel(n_jobs=2)(delayed(worker)() for _ in range(1)) - np.testing.assert_array_equal(results[0], arr) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory.py deleted file mode 100644 index f360e2b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory.py +++ /dev/null @@ -1,1526 +0,0 @@ -""" -Test the memory module. -""" - -# Author: Gael Varoquaux -# Copyright (c) 2009 Gael Varoquaux -# License: BSD Style, 3 clauses. - -import functools -import gc -import logging -import shutil -import os -import os.path -import pathlib -import pickle -import sys -import time -import datetime -import textwrap - -import pytest - -from joblib.memory import Memory -from joblib.memory import expires_after -from joblib.memory import MemorizedFunc, NotMemorizedFunc -from joblib.memory import MemorizedResult, NotMemorizedResult -from joblib.memory import _FUNCTION_HASHES -from joblib.memory import register_store_backend, _STORE_BACKENDS -from joblib.memory import _build_func_identifier, _store_backend_factory -from joblib.memory import JobLibCollisionWarning -from joblib.parallel import Parallel, delayed -from joblib._store_backends import StoreBackendBase, FileSystemStoreBackend -from joblib.test.common import with_numpy, np -from joblib.test.common import with_multiprocessing -from joblib.testing import parametrize, raises, warns -from joblib.hashing import hash - - -############################################################################### -# Module-level variables for the tests -def f(x, y=1): - """ A module-level function for testing purposes. - """ - return x ** 2 + y - - -############################################################################### -# Helper function for the tests -def check_identity_lazy(func, accumulator, location): - """ Given a function and an accumulator (a list that grows every - time the function is called), check that the function can be - decorated by memory to be a lazy identity. - """ - # Call each function with several arguments, and check that it is - # evaluated only once per argument. - memory = Memory(location=location, verbose=0) - func = memory.cache(func) - for i in range(3): - for _ in range(2): - assert func(i) == i - assert len(accumulator) == i + 1 - - -def corrupt_single_cache_item(memory): - single_cache_item, = memory.store_backend.get_items() - output_filename = os.path.join(single_cache_item.path, 'output.pkl') - with open(output_filename, 'w') as f: - f.write('garbage') - - -def monkeypatch_cached_func_warn(func, monkeypatch_fixture): - # Need monkeypatch because pytest does not - # capture stdlib logging output (see - # https://github.com/pytest-dev/pytest/issues/2079) - - recorded = [] - - def append_to_record(item): - recorded.append(item) - monkeypatch_fixture.setattr(func, 'warn', append_to_record) - return recorded - - -############################################################################### -# Tests -def test_memory_integration(tmpdir): - """ Simple test of memory lazy evaluation. - """ - accumulator = list() - - # Rmk: this function has the same name than a module-level function, - # thus it serves as a test to see that both are identified - # as different. - def f(arg): - accumulator.append(1) - return arg - - check_identity_lazy(f, accumulator, tmpdir.strpath) - - # Now test clearing - for compress in (False, True): - for mmap_mode in ('r', None): - memory = Memory(location=tmpdir.strpath, verbose=10, - mmap_mode=mmap_mode, compress=compress) - # First clear the cache directory, to check that our code can - # handle that - # NOTE: this line would raise an exception, as the database file is - # still open; we ignore the error since we want to test what - # happens if the directory disappears - shutil.rmtree(tmpdir.strpath, ignore_errors=True) - g = memory.cache(f) - g(1) - g.clear(warn=False) - current_accumulator = len(accumulator) - out = g(1) - - assert len(accumulator) == current_accumulator + 1 - # Also, check that Memory.eval works similarly - assert memory.eval(f, 1) == out - assert len(accumulator) == current_accumulator + 1 - - # Now do a smoke test with a function defined in __main__, as the name - # mangling rules are more complex - f.__module__ = '__main__' - memory = Memory(location=tmpdir.strpath, verbose=0) - memory.cache(f)(1) - - -@parametrize("call_before_reducing", [True, False]) -def test_parallel_call_cached_function_defined_in_jupyter( - tmpdir, call_before_reducing -): - # Calling an interactively defined memory.cache()'d function inside a - # Parallel call used to clear the existing cache related to the said - # function (https://github.com/joblib/joblib/issues/1035) - - # This tests checks that this is no longer the case. - - # TODO: test that the cache related to the function cache persists across - # ipython sessions (provided that no code change were made to the - # function's source)? - - # The first part of the test makes the necessary low-level calls to emulate - # the definition of a function in an jupyter notebook cell. Joblib has - # some custom code to treat functions defined specifically in jupyter - # notebooks/ipython session -- we want to test this code, which requires - # the emulation to be rigorous. - for session_no in [0, 1]: - ipython_cell_source = ''' - def f(x): - return x - ''' - - ipython_cell_id = ''.format(session_no) - - exec( - compile( - textwrap.dedent(ipython_cell_source), - filename=ipython_cell_id, - mode='exec' - ) - ) - # f is now accessible in the locals mapping - but for some unknown - # reason, f = locals()['f'] throws a KeyError at runtime, we need to - # bind locals()['f'] to a different name in the local namespace - aliased_f = locals()['f'] - aliased_f.__module__ = "__main__" - - # Preliminary sanity checks, and tests checking that joblib properly - # identified f as an interactive function defined in a jupyter notebook - assert aliased_f(1) == 1 - assert aliased_f.__code__.co_filename == ipython_cell_id - - memory = Memory(location=tmpdir.strpath, verbose=0) - cached_f = memory.cache(aliased_f) - - assert len(os.listdir(tmpdir / 'joblib')) == 1 - f_cache_relative_directory = os.listdir(tmpdir / 'joblib')[0] - assert 'ipython-input' in f_cache_relative_directory - - f_cache_directory = tmpdir / 'joblib' / f_cache_relative_directory - - if session_no == 0: - # The cache should be empty as cached_f has not been called yet. - assert os.listdir(f_cache_directory) == ['f'] - assert os.listdir(f_cache_directory / 'f') == [] - - if call_before_reducing: - cached_f(3) - # Two files were just created, func_code.py, and a folder - # containing the information (inputs hash/ouptput) of - # cached_f(3) - assert len(os.listdir(f_cache_directory / 'f')) == 2 - - # Now, testing #1035: when calling a cached function, joblib - # used to dynamically inspect the underlying function to - # extract its source code (to verify it matches the source code - # of the function as last inspected by joblib) -- however, - # source code introspection fails for dynamic functions sent to - # child processes - which would eventually make joblib clear - # the cache associated to f - res = Parallel(n_jobs=2)(delayed(cached_f)(i) for i in [1, 2]) - else: - # Submit the function to the joblib child processes, although - # the function has never been called in the parent yet. This - # triggers a specific code branch inside - # MemorizedFunc.__reduce__. - res = Parallel(n_jobs=2)(delayed(cached_f)(i) for i in [1, 2]) - assert len(os.listdir(f_cache_directory / 'f')) == 3 - - cached_f(3) - - # Making sure f's cache does not get cleared after the parallel - # calls, and contains ALL cached functions calls (f(1), f(2), f(3)) - # and 'func_code.py' - assert len(os.listdir(f_cache_directory / 'f')) == 4 - else: - # For the second session, there should be an already existing cache - assert len(os.listdir(f_cache_directory / 'f')) == 4 - - cached_f(3) - - # The previous cache should not be invalidated after calling the - # function in a new session - assert len(os.listdir(f_cache_directory / 'f')) == 4 - - -def test_no_memory(): - """ Test memory with location=None: no memoize """ - accumulator = list() - - def ff(arg): - accumulator.append(1) - return arg - - memory = Memory(location=None, verbose=0) - gg = memory.cache(ff) - for _ in range(4): - current_accumulator = len(accumulator) - gg(1) - assert len(accumulator) == current_accumulator + 1 - - -def test_memory_kwarg(tmpdir): - " Test memory with a function with keyword arguments." - accumulator = list() - - def g(arg1=None, arg2=1): - accumulator.append(1) - return arg1 - - check_identity_lazy(g, accumulator, tmpdir.strpath) - - memory = Memory(location=tmpdir.strpath, verbose=0) - g = memory.cache(g) - # Smoke test with an explicit keyword argument: - assert g(arg1=30, arg2=2) == 30 - - -def test_memory_lambda(tmpdir): - " Test memory with a function with a lambda." - accumulator = list() - - def helper(x): - """ A helper function to define l as a lambda. - """ - accumulator.append(1) - return x - - check_identity_lazy(lambda x: helper(x), accumulator, tmpdir.strpath) - - -def test_memory_name_collision(tmpdir): - " Check that name collisions with functions will raise warnings" - memory = Memory(location=tmpdir.strpath, verbose=0) - - @memory.cache - def name_collision(x): - """ A first function called name_collision - """ - return x - - a = name_collision - - @memory.cache - def name_collision(x): - """ A second function called name_collision - """ - return x - - b = name_collision - - with warns(JobLibCollisionWarning) as warninfo: - a(1) - b(1) - - assert len(warninfo) == 1 - assert "collision" in str(warninfo[0].message) - - -def test_memory_warning_lambda_collisions(tmpdir): - # Check that multiple use of lambda will raise collisions - memory = Memory(location=tmpdir.strpath, verbose=0) - a = memory.cache(lambda x: x) - b = memory.cache(lambda x: x + 1) - - with warns(JobLibCollisionWarning) as warninfo: - assert a(0) == 0 - assert b(1) == 2 - assert a(1) == 1 - - # In recent Python versions, we can retrieve the code of lambdas, - # thus nothing is raised - assert len(warninfo) == 4 - - -def test_memory_warning_collision_detection(tmpdir): - # Check that collisions impossible to detect will raise appropriate - # warnings. - memory = Memory(location=tmpdir.strpath, verbose=0) - a1 = eval('lambda x: x') - a1 = memory.cache(a1) - b1 = eval('lambda x: x+1') - b1 = memory.cache(b1) - - with warns(JobLibCollisionWarning) as warninfo: - a1(1) - b1(1) - a1(0) - - assert len(warninfo) == 2 - assert "cannot detect" in str(warninfo[0].message).lower() - - -def test_memory_partial(tmpdir): - " Test memory with functools.partial." - accumulator = list() - - def func(x, y): - """ A helper function to define l as a lambda. - """ - accumulator.append(1) - return y - - import functools - function = functools.partial(func, 1) - - check_identity_lazy(function, accumulator, tmpdir.strpath) - - -def test_memory_eval(tmpdir): - " Smoke test memory with a function with a function defined in an eval." - memory = Memory(location=tmpdir.strpath, verbose=0) - - m = eval('lambda x: x') - mm = memory.cache(m) - - assert mm(1) == 1 - - -def count_and_append(x=[]): - """ A function with a side effect in its arguments. - - Return the length of its argument and append one element. - """ - len_x = len(x) - x.append(None) - return len_x - - -def test_argument_change(tmpdir): - """ Check that if a function has a side effect in its arguments, it - should use the hash of changing arguments. - """ - memory = Memory(location=tmpdir.strpath, verbose=0) - func = memory.cache(count_and_append) - # call the function for the first time, is should cache it with - # argument x=[] - assert func() == 0 - # the second time the argument is x=[None], which is not cached - # yet, so the functions should be called a second time - assert func() == 1 - - -@with_numpy -@parametrize('mmap_mode', [None, 'r']) -def test_memory_numpy(tmpdir, mmap_mode): - " Test memory with a function with numpy arrays." - accumulator = list() - - def n(arg=None): - accumulator.append(1) - return arg - - memory = Memory(location=tmpdir.strpath, mmap_mode=mmap_mode, - verbose=0) - cached_n = memory.cache(n) - - rnd = np.random.RandomState(0) - for i in range(3): - a = rnd.random_sample((10, 10)) - for _ in range(3): - assert np.all(cached_n(a) == a) - assert len(accumulator) == i + 1 - - -@with_numpy -def test_memory_numpy_check_mmap_mode(tmpdir, monkeypatch): - """Check that mmap_mode is respected even at the first call""" - - memory = Memory(location=tmpdir.strpath, mmap_mode='r', verbose=0) - - @memory.cache() - def twice(a): - return a * 2 - - a = np.ones(3) - - b = twice(a) - c = twice(a) - - assert isinstance(c, np.memmap) - assert c.mode == 'r' - - assert isinstance(b, np.memmap) - assert b.mode == 'r' - - # Corrupts the file, Deleting b and c mmaps - # is necessary to be able edit the file - del b - del c - gc.collect() - corrupt_single_cache_item(memory) - - # Make sure that corrupting the file causes recomputation and that - # a warning is issued. - recorded_warnings = monkeypatch_cached_func_warn(twice, monkeypatch) - d = twice(a) - assert len(recorded_warnings) == 1 - exception_msg = 'Exception while loading results' - assert exception_msg in recorded_warnings[0] - # Asserts that the recomputation returns a mmap - assert isinstance(d, np.memmap) - assert d.mode == 'r' - - -def test_memory_exception(tmpdir): - """ Smoketest the exception handling of Memory. - """ - memory = Memory(location=tmpdir.strpath, verbose=0) - - class MyException(Exception): - pass - - @memory.cache - def h(exc=0): - if exc: - raise MyException - - # Call once, to initialise the cache - h() - - for _ in range(3): - # Call 3 times, to be sure that the Exception is always raised - with raises(MyException): - h(1) - - -def test_memory_ignore(tmpdir): - " Test the ignore feature of memory " - memory = Memory(location=tmpdir.strpath, verbose=0) - accumulator = list() - - @memory.cache(ignore=['y']) - def z(x, y=1): - accumulator.append(1) - - assert z.ignore == ['y'] - - z(0, y=1) - assert len(accumulator) == 1 - z(0, y=1) - assert len(accumulator) == 1 - z(0, y=2) - assert len(accumulator) == 1 - - -def test_memory_ignore_decorated(tmpdir): - " Test the ignore feature of memory on a decorated function " - memory = Memory(location=tmpdir.strpath, verbose=0) - accumulator = list() - - def decorate(f): - @functools.wraps(f) - def wrapped(*args, **kwargs): - return f(*args, **kwargs) - return wrapped - - @memory.cache(ignore=['y']) - @decorate - def z(x, y=1): - accumulator.append(1) - - assert z.ignore == ['y'] - - z(0, y=1) - assert len(accumulator) == 1 - z(0, y=1) - assert len(accumulator) == 1 - z(0, y=2) - assert len(accumulator) == 1 - - -def test_memory_args_as_kwargs(tmpdir): - """Non-regression test against 0.12.0 changes. - - https://github.com/joblib/joblib/pull/751 - """ - memory = Memory(location=tmpdir.strpath, verbose=0) - - @memory.cache - def plus_one(a): - return a + 1 - - # It's possible to call a positional arg as a kwarg. - assert plus_one(1) == 2 - assert plus_one(a=1) == 2 - - # However, a positional argument that joblib hadn't seen - # before would cause a failure if it was passed as a kwarg. - assert plus_one(a=2) == 3 - - -@parametrize('ignore, verbose, mmap_mode', [(['x'], 100, 'r'), - ([], 10, None)]) -def test_partial_decoration(tmpdir, ignore, verbose, mmap_mode): - "Check cache may be called with kwargs before decorating" - memory = Memory(location=tmpdir.strpath, verbose=0) - - @memory.cache(ignore=ignore, verbose=verbose, mmap_mode=mmap_mode) - def z(x): - pass - - assert z.ignore == ignore - assert z._verbose == verbose - assert z.mmap_mode == mmap_mode - - -def test_func_dir(tmpdir): - # Test the creation of the memory cache directory for the function. - memory = Memory(location=tmpdir.strpath, verbose=0) - path = __name__.split('.') - path.append('f') - path = tmpdir.join('joblib', *path).strpath - - g = memory.cache(f) - # Test that the function directory is created on demand - func_id = _build_func_identifier(f) - location = os.path.join(g.store_backend.location, func_id) - assert location == path - assert os.path.exists(path) - assert memory.location == os.path.dirname(g.store_backend.location) - - # Test that the code is stored. - # For the following test to be robust to previous execution, we clear - # the in-memory store - _FUNCTION_HASHES.clear() - assert not g._check_previous_func_code() - assert os.path.exists(os.path.join(path, 'func_code.py')) - assert g._check_previous_func_code() - - # Test the robustness to failure of loading previous results. - args_id = g._get_args_id(1) - output_dir = os.path.join(g.store_backend.location, g.func_id, args_id) - a = g(1) - assert os.path.exists(output_dir) - os.remove(os.path.join(output_dir, 'output.pkl')) - assert a == g(1) - - -def test_persistence(tmpdir): - # Test the memorized functions can be pickled and restored. - memory = Memory(location=tmpdir.strpath, verbose=0) - g = memory.cache(f) - output = g(1) - - h = pickle.loads(pickle.dumps(g)) - - args_id = h._get_args_id(1) - output_dir = os.path.join(h.store_backend.location, h.func_id, args_id) - assert os.path.exists(output_dir) - assert output == h.store_backend.load_item([h.func_id, args_id]) - memory2 = pickle.loads(pickle.dumps(memory)) - assert memory.store_backend.location == memory2.store_backend.location - - # Smoke test that pickling a memory with location=None works - memory = Memory(location=None, verbose=0) - pickle.loads(pickle.dumps(memory)) - g = memory.cache(f) - gp = pickle.loads(pickle.dumps(g)) - gp(1) - - -def test_check_call_in_cache(tmpdir): - for func in (MemorizedFunc(f, tmpdir.strpath), - Memory(location=tmpdir.strpath, verbose=0).cache(f)): - result = func.check_call_in_cache(2) - assert not result - assert isinstance(result, bool) - assert func(2) == 5 - result = func.check_call_in_cache(2) - assert result - assert isinstance(result, bool) - func.clear() - - -def test_call_and_shelve(tmpdir): - # Test MemorizedFunc outputting a reference to cache. - - for func, Result in zip((MemorizedFunc(f, tmpdir.strpath), - NotMemorizedFunc(f), - Memory(location=tmpdir.strpath, - verbose=0).cache(f), - Memory(location=None).cache(f), - ), - (MemorizedResult, NotMemorizedResult, - MemorizedResult, NotMemorizedResult)): - assert func(2) == 5 - result = func.call_and_shelve(2) - assert isinstance(result, Result) - assert result.get() == 5 - - result.clear() - with raises(KeyError): - result.get() - result.clear() # Do nothing if there is no cache. - - -def test_call_and_shelve_argument_hash(tmpdir): - # Verify that a warning is raised when accessing arguments_hash - # attribute from MemorizedResult - func = Memory(location=tmpdir.strpath, verbose=0).cache(f) - result = func.call_and_shelve(2) - assert isinstance(result, MemorizedResult) - with warns(DeprecationWarning) as w: - assert result.argument_hash == result.args_id - assert len(w) == 1 - assert "The 'argument_hash' attribute has been deprecated" \ - in str(w[-1].message) - - -def test_call_and_shelve_lazily_load_stored_result(tmpdir): - """Check call_and_shelve only load stored data if needed.""" - test_access_time_file = tmpdir.join('test_access') - test_access_time_file.write('test_access') - test_access_time = os.stat(test_access_time_file.strpath).st_atime - # check file system access time stats resolution is lower than test wait - # timings. - time.sleep(0.5) - assert test_access_time_file.read() == 'test_access' - - if test_access_time == os.stat(test_access_time_file.strpath).st_atime: - # Skip this test when access time cannot be retrieved with enough - # precision from the file system (e.g. NTFS on windows). - pytest.skip("filesystem does not support fine-grained access time " - "attribute") - - memory = Memory(location=tmpdir.strpath, verbose=0) - func = memory.cache(f) - args_id = func._get_args_id(2) - result_path = os.path.join(memory.store_backend.location, - func.func_id, args_id, 'output.pkl') - assert func(2) == 5 - first_access_time = os.stat(result_path).st_atime - time.sleep(1) - - # Should not access the stored data - result = func.call_and_shelve(2) - assert isinstance(result, MemorizedResult) - assert os.stat(result_path).st_atime == first_access_time - time.sleep(1) - - # Read the stored data => last access time is greater than first_access - assert result.get() == 5 - assert os.stat(result_path).st_atime > first_access_time - - -def test_memorized_pickling(tmpdir): - for func in (MemorizedFunc(f, tmpdir.strpath), NotMemorizedFunc(f)): - filename = tmpdir.join('pickling_test.dat').strpath - result = func.call_and_shelve(2) - with open(filename, 'wb') as fp: - pickle.dump(result, fp) - with open(filename, 'rb') as fp: - result2 = pickle.load(fp) - assert result2.get() == result.get() - os.remove(filename) - - -def test_memorized_repr(tmpdir): - func = MemorizedFunc(f, tmpdir.strpath) - result = func.call_and_shelve(2) - - func2 = MemorizedFunc(f, tmpdir.strpath) - result2 = func2.call_and_shelve(2) - assert result.get() == result2.get() - assert repr(func) == repr(func2) - - # Smoke test with NotMemorizedFunc - func = NotMemorizedFunc(f) - repr(func) - repr(func.call_and_shelve(2)) - - # Smoke test for message output (increase code coverage) - func = MemorizedFunc(f, tmpdir.strpath, verbose=11, timestamp=time.time()) - result = func.call_and_shelve(11) - result.get() - - func = MemorizedFunc(f, tmpdir.strpath, verbose=11) - result = func.call_and_shelve(11) - result.get() - - func = MemorizedFunc(f, tmpdir.strpath, verbose=5, timestamp=time.time()) - result = func.call_and_shelve(11) - result.get() - - func = MemorizedFunc(f, tmpdir.strpath, verbose=5) - result = func.call_and_shelve(11) - result.get() - - -def test_memory_file_modification(capsys, tmpdir, monkeypatch): - # Test that modifying a Python file after loading it does not lead to - # Recomputation - dir_name = tmpdir.mkdir('tmp_import').strpath - filename = os.path.join(dir_name, 'tmp_joblib_.py') - content = 'def f(x):\n print(x)\n return x\n' - with open(filename, 'w') as module_file: - module_file.write(content) - - # Load the module: - monkeypatch.syspath_prepend(dir_name) - import tmp_joblib_ as tmp - - memory = Memory(location=tmpdir.strpath, verbose=0) - f = memory.cache(tmp.f) - # First call f a few times - f(1) - f(2) - f(1) - - # Now modify the module where f is stored without modifying f - with open(filename, 'w') as module_file: - module_file.write('\n\n' + content) - - # And call f a couple more times - f(1) - f(1) - - # Flush the .pyc files - shutil.rmtree(dir_name) - os.mkdir(dir_name) - # Now modify the module where f is stored, modifying f - content = 'def f(x):\n print("x=%s" % x)\n return x\n' - with open(filename, 'w') as module_file: - module_file.write(content) - - # And call f more times prior to reloading: the cache should not be - # invalidated at this point as the active function definition has not - # changed in memory yet. - f(1) - f(1) - - # Now reload - sys.stdout.write('Reloading\n') - sys.modules.pop('tmp_joblib_') - import tmp_joblib_ as tmp - f = memory.cache(tmp.f) - - # And call f more times - f(1) - f(1) - - out, err = capsys.readouterr() - assert out == '1\n2\nReloading\nx=1\n' - - -def _function_to_cache(a, b): - # Just a place holder function to be mutated by tests - pass - - -def _sum(a, b): - return a + b - - -def _product(a, b): - return a * b - - -def test_memory_in_memory_function_code_change(tmpdir): - _function_to_cache.__code__ = _sum.__code__ - - memory = Memory(location=tmpdir.strpath, verbose=0) - f = memory.cache(_function_to_cache) - - assert f(1, 2) == 3 - assert f(1, 2) == 3 - - with warns(JobLibCollisionWarning): - # Check that inline function modification triggers a cache invalidation - _function_to_cache.__code__ = _product.__code__ - assert f(1, 2) == 2 - assert f(1, 2) == 2 - - -def test_clear_memory_with_none_location(): - memory = Memory(location=None) - memory.clear() - - -def func_with_kwonly_args(a, b, *, kw1='kw1', kw2='kw2'): - return a, b, kw1, kw2 - - -def func_with_signature(a: int, b: float) -> float: - return a + b - - -def test_memory_func_with_kwonly_args(tmpdir): - memory = Memory(location=tmpdir.strpath, verbose=0) - func_cached = memory.cache(func_with_kwonly_args) - - assert func_cached(1, 2, kw1=3) == (1, 2, 3, 'kw2') - - # Making sure that providing a keyword-only argument by - # position raises an exception - with raises(ValueError) as excinfo: - func_cached(1, 2, 3, kw2=4) - excinfo.match("Keyword-only parameter 'kw1' was passed as positional " - "parameter") - - # Keyword-only parameter passed by position with cached call - # should still raise ValueError - func_cached(1, 2, kw1=3, kw2=4) - - with raises(ValueError) as excinfo: - func_cached(1, 2, 3, kw2=4) - excinfo.match("Keyword-only parameter 'kw1' was passed as positional " - "parameter") - - # Test 'ignore' parameter - func_cached = memory.cache(func_with_kwonly_args, ignore=['kw2']) - assert func_cached(1, 2, kw1=3, kw2=4) == (1, 2, 3, 4) - assert func_cached(1, 2, kw1=3, kw2='ignored') == (1, 2, 3, 4) - - -def test_memory_func_with_signature(tmpdir): - memory = Memory(location=tmpdir.strpath, verbose=0) - func_cached = memory.cache(func_with_signature) - - assert func_cached(1, 2.) == 3. - - -def _setup_toy_cache(tmpdir, num_inputs=10): - memory = Memory(location=tmpdir.strpath, verbose=0) - - @memory.cache() - def get_1000_bytes(arg): - return 'a' * 1000 - - inputs = list(range(num_inputs)) - for arg in inputs: - get_1000_bytes(arg) - - func_id = _build_func_identifier(get_1000_bytes) - hash_dirnames = [get_1000_bytes._get_args_id(arg) - for arg in inputs] - - full_hashdirs = [os.path.join(get_1000_bytes.store_backend.location, - func_id, dirname) - for dirname in hash_dirnames] - return memory, full_hashdirs, get_1000_bytes - - -def test__get_items(tmpdir): - memory, expected_hash_dirs, _ = _setup_toy_cache(tmpdir) - items = memory.store_backend.get_items() - hash_dirs = [ci.path for ci in items] - assert set(hash_dirs) == set(expected_hash_dirs) - - def get_files_size(directory): - full_paths = [os.path.join(directory, fn) - for fn in os.listdir(directory)] - return sum(os.path.getsize(fp) for fp in full_paths) - - expected_hash_cache_sizes = [get_files_size(hash_dir) - for hash_dir in hash_dirs] - hash_cache_sizes = [ci.size for ci in items] - assert hash_cache_sizes == expected_hash_cache_sizes - - output_filenames = [os.path.join(hash_dir, 'output.pkl') - for hash_dir in hash_dirs] - - expected_last_accesses = [ - datetime.datetime.fromtimestamp(os.path.getatime(fn)) - for fn in output_filenames] - last_accesses = [ci.last_access for ci in items] - assert last_accesses == expected_last_accesses - - -def test__get_items_to_delete(tmpdir): - # test empty cache - memory, _, _ = _setup_toy_cache(tmpdir, num_inputs=0) - items_to_delete = memory.store_backend._get_items_to_delete('1K') - assert items_to_delete == [] - - memory, expected_hash_cachedirs, _ = _setup_toy_cache(tmpdir) - items = memory.store_backend.get_items() - # bytes_limit set to keep only one cache item (each hash cache - # folder is about 1000 bytes + metadata) - items_to_delete = memory.store_backend._get_items_to_delete('2K') - nb_hashes = len(expected_hash_cachedirs) - assert set.issubset(set(items_to_delete), set(items)) - assert len(items_to_delete) == nb_hashes - 1 - - # Sanity check bytes_limit=2048 is the same as bytes_limit='2K' - items_to_delete_2048b = memory.store_backend._get_items_to_delete(2048) - assert sorted(items_to_delete) == sorted(items_to_delete_2048b) - - # bytes_limit greater than the size of the cache - items_to_delete_empty = memory.store_backend._get_items_to_delete('1M') - assert items_to_delete_empty == [] - - # All the cache items need to be deleted - bytes_limit_too_small = 500 - items_to_delete_500b = memory.store_backend._get_items_to_delete( - bytes_limit_too_small - ) - assert set(items_to_delete_500b), set(items) - - # Test LRU property: surviving cache items should all have a more - # recent last_access that the ones that have been deleted - items_to_delete_6000b = memory.store_backend._get_items_to_delete(6000) - surviving_items = set(items).difference(items_to_delete_6000b) - - assert (max(ci.last_access for ci in items_to_delete_6000b) <= - min(ci.last_access for ci in surviving_items)) - - -def test_memory_reduce_size_bytes_limit(tmpdir): - memory, _, _ = _setup_toy_cache(tmpdir) - ref_cache_items = memory.store_backend.get_items() - - # By default memory.bytes_limit is None and reduce_size is a noop - memory.reduce_size() - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # No cache items deleted if bytes_limit greater than the size of - # the cache - memory.reduce_size(bytes_limit='1M') - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # bytes_limit is set so that only two cache items are kept - memory.reduce_size(bytes_limit='3K') - cache_items = memory.store_backend.get_items() - assert set.issubset(set(cache_items), set(ref_cache_items)) - assert len(cache_items) == 2 - - # bytes_limit set so that no cache item is kept - bytes_limit_too_small = 500 - memory.reduce_size(bytes_limit=bytes_limit_too_small) - cache_items = memory.store_backend.get_items() - assert cache_items == [] - - -def test_memory_reduce_size_items_limit(tmpdir): - memory, _, _ = _setup_toy_cache(tmpdir) - ref_cache_items = memory.store_backend.get_items() - - # By default reduce_size is a noop - memory.reduce_size() - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # No cache items deleted if items_limit greater than the size of - # the cache - memory.reduce_size(items_limit=10) - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # items_limit is set so that only two cache items are kept - memory.reduce_size(items_limit=2) - cache_items = memory.store_backend.get_items() - assert set.issubset(set(cache_items), set(ref_cache_items)) - assert len(cache_items) == 2 - - # item_limit set so that no cache item is kept - memory.reduce_size(items_limit=0) - cache_items = memory.store_backend.get_items() - assert cache_items == [] - - -def test_memory_reduce_size_age_limit(tmpdir): - import time - import datetime - memory, _, put_cache = _setup_toy_cache(tmpdir) - ref_cache_items = memory.store_backend.get_items() - - # By default reduce_size is a noop - memory.reduce_size() - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # No cache items deleted if age_limit big. - memory.reduce_size(age_limit=datetime.timedelta(days=1)) - cache_items = memory.store_backend.get_items() - assert sorted(ref_cache_items) == sorted(cache_items) - - # age_limit is set so that only two cache items are kept - time.sleep(1) - put_cache(-1) - put_cache(-2) - memory.reduce_size(age_limit=datetime.timedelta(seconds=1)) - cache_items = memory.store_backend.get_items() - assert not set.issubset(set(cache_items), set(ref_cache_items)) - assert len(cache_items) == 2 - - # age_limit set so that no cache item is kept - memory.reduce_size(age_limit=datetime.timedelta(seconds=0)) - cache_items = memory.store_backend.get_items() - assert cache_items == [] - - -def test_memory_clear(tmpdir): - memory, _, g = _setup_toy_cache(tmpdir) - memory.clear() - - assert os.listdir(memory.store_backend.location) == [] - - # Check that the cache for functions hash is also reset. - assert not g._check_previous_func_code(stacklevel=4) - - -def fast_func_with_complex_output(): - complex_obj = ['a' * 1000] * 1000 - return complex_obj - - -def fast_func_with_conditional_complex_output(complex_output=True): - complex_obj = {str(i): i for i in range(int(1e5))} - return complex_obj if complex_output else 'simple output' - - -@with_multiprocessing -def test_cached_function_race_condition_when_persisting_output(tmpdir, capfd): - # Test race condition where multiple processes are writing into - # the same output.pkl. See - # https://github.com/joblib/joblib/issues/490 for more details. - memory = Memory(location=tmpdir.strpath) - func_cached = memory.cache(fast_func_with_complex_output) - - Parallel(n_jobs=2)(delayed(func_cached)() for i in range(3)) - - stdout, stderr = capfd.readouterr() - - # Checking both stdout and stderr (ongoing PR #434 may change - # logging destination) to make sure there is no exception while - # loading the results - exception_msg = 'Exception while loading results' - assert exception_msg not in stdout - assert exception_msg not in stderr - - -@with_multiprocessing -def test_cached_function_race_condition_when_persisting_output_2(tmpdir, - capfd): - # Test race condition in first attempt at solving - # https://github.com/joblib/joblib/issues/490. The race condition - # was due to the delay between seeing the cache directory created - # (interpreted as the result being cached) and the output.pkl being - # pickled. - memory = Memory(location=tmpdir.strpath) - func_cached = memory.cache(fast_func_with_conditional_complex_output) - - Parallel(n_jobs=2)(delayed(func_cached)(True if i % 2 == 0 else False) - for i in range(3)) - - stdout, stderr = capfd.readouterr() - - # Checking both stdout and stderr (ongoing PR #434 may change - # logging destination) to make sure there is no exception while - # loading the results - exception_msg = 'Exception while loading results' - assert exception_msg not in stdout - assert exception_msg not in stderr - - -def test_memory_recomputes_after_an_error_while_loading_results( - tmpdir, monkeypatch): - memory = Memory(location=tmpdir.strpath) - - def func(arg): - # This makes sure that the timestamp returned by two calls of - # func are different. This is needed on Windows where - # time.time resolution may not be accurate enough - time.sleep(0.01) - return arg, time.time() - - cached_func = memory.cache(func) - input_arg = 'arg' - arg, timestamp = cached_func(input_arg) - - # Make sure the function is correctly cached - assert arg == input_arg - - # Corrupting output.pkl to make sure that an error happens when - # loading the cached result - corrupt_single_cache_item(memory) - - # Make sure that corrupting the file causes recomputation and that - # a warning is issued. - recorded_warnings = monkeypatch_cached_func_warn(cached_func, monkeypatch) - recomputed_arg, recomputed_timestamp = cached_func(arg) - assert len(recorded_warnings) == 1 - exception_msg = 'Exception while loading results' - assert exception_msg in recorded_warnings[0] - assert recomputed_arg == arg - assert recomputed_timestamp > timestamp - - # Corrupting output.pkl to make sure that an error happens when - # loading the cached result - corrupt_single_cache_item(memory) - reference = cached_func.call_and_shelve(arg) - try: - reference.get() - raise AssertionError( - "It normally not possible to load a corrupted" - " MemorizedResult" - ) - except KeyError as e: - message = "is corrupted" - assert message in str(e.args) - - -class IncompleteStoreBackend(StoreBackendBase): - """This backend cannot be instantiated and should raise a TypeError.""" - pass - - -class DummyStoreBackend(StoreBackendBase): - """A dummy store backend that does nothing.""" - - def _open_item(self, *args, **kwargs): - """Open an item on store.""" - "Does nothing" - - def _item_exists(self, location): - """Check if an item location exists.""" - "Does nothing" - - def _move_item(self, src, dst): - """Move an item from src to dst in store.""" - "Does nothing" - - def create_location(self, location): - """Create location on store.""" - "Does nothing" - - def exists(self, obj): - """Check if an object exists in the store""" - return False - - def clear_location(self, obj): - """Clear object on store""" - "Does nothing" - - def get_items(self): - """Returns the whole list of items available in cache.""" - return [] - - def configure(self, location, *args, **kwargs): - """Configure the store""" - "Does nothing" - - -@parametrize("invalid_prefix", [None, dict(), list()]) -def test_register_invalid_store_backends_key(invalid_prefix): - # verify the right exceptions are raised when passing a wrong backend key. - with raises(ValueError) as excinfo: - register_store_backend(invalid_prefix, None) - excinfo.match(r'Store backend name should be a string*') - - -def test_register_invalid_store_backends_object(): - # verify the right exceptions are raised when passing a wrong backend - # object. - with raises(ValueError) as excinfo: - register_store_backend("fs", None) - excinfo.match(r'Store backend should inherit StoreBackendBase*') - - -def test_memory_default_store_backend(): - # test an unknown backend falls back into a FileSystemStoreBackend - with raises(TypeError) as excinfo: - Memory(location='/tmp/joblib', backend='unknown') - excinfo.match(r"Unknown location*") - - -def test_warning_on_unknown_location_type(): - class NonSupportedLocationClass: - pass - unsupported_location = NonSupportedLocationClass() - - with warns(UserWarning) as warninfo: - _store_backend_factory("local", location=unsupported_location) - - expected_mesage = ("Instantiating a backend using a " - "NonSupportedLocationClass as a location is not " - "supported by joblib") - assert expected_mesage in str(warninfo[0].message) - - -def test_instanciate_incomplete_store_backend(): - # Verify that registering an external incomplete store backend raises an - # exception when one tries to instantiate it. - backend_name = "isb" - register_store_backend(backend_name, IncompleteStoreBackend) - assert (backend_name, IncompleteStoreBackend) in _STORE_BACKENDS.items() - with raises(TypeError) as excinfo: - _store_backend_factory(backend_name, "fake_location") - excinfo.match(r"Can't instantiate abstract class IncompleteStoreBackend " - "(without an implementation for|with) abstract methods*") - - -def test_dummy_store_backend(): - # Verify that registering an external store backend works. - - backend_name = "dsb" - register_store_backend(backend_name, DummyStoreBackend) - assert (backend_name, DummyStoreBackend) in _STORE_BACKENDS.items() - - backend_obj = _store_backend_factory(backend_name, "dummy_location") - assert isinstance(backend_obj, DummyStoreBackend) - - -def test_instanciate_store_backend_with_pathlib_path(): - # Instantiate a FileSystemStoreBackend using a pathlib.Path object - path = pathlib.Path("some_folder") - backend_obj = _store_backend_factory("local", path) - assert backend_obj.location == "some_folder" - - -def test_filesystem_store_backend_repr(tmpdir): - # Verify string representation of a filesystem store backend. - - repr_pattern = 'FileSystemStoreBackend(location="{location}")' - backend = FileSystemStoreBackend() - assert backend.location is None - - repr(backend) # Should not raise an exception - - assert str(backend) == repr_pattern.format(location=None) - - # backend location is passed explicitly via the configure method (called - # by the internal _store_backend_factory function) - backend.configure(tmpdir.strpath) - - assert str(backend) == repr_pattern.format(location=tmpdir.strpath) - - repr(backend) # Should not raise an exception - - -def test_memory_objects_repr(tmpdir): - # Verify printable reprs of MemorizedResult, MemorizedFunc and Memory. - - def my_func(a, b): - return a + b - - memory = Memory(location=tmpdir.strpath, verbose=0) - memorized_func = memory.cache(my_func) - - memorized_func_repr = 'MemorizedFunc(func={func}, location={location})' - - assert str(memorized_func) == memorized_func_repr.format( - func=my_func, - location=memory.store_backend.location) - - memorized_result = memorized_func.call_and_shelve(42, 42) - - memorized_result_repr = ('MemorizedResult(location="{location}", ' - 'func="{func}", args_id="{args_id}")') - - assert str(memorized_result) == memorized_result_repr.format( - location=memory.store_backend.location, - func=memorized_result.func_id, - args_id=memorized_result.args_id) - - assert str(memory) == 'Memory(location={location})'.format( - location=memory.store_backend.location) - - -def test_memorized_result_pickle(tmpdir): - # Verify a MemoryResult object can be pickled/depickled. Non regression - # test introduced following issue - # https://github.com/joblib/joblib/issues/747 - - memory = Memory(location=tmpdir.strpath) - - @memory.cache - def g(x): - return x**2 - - memorized_result = g.call_and_shelve(4) - memorized_result_pickle = pickle.dumps(memorized_result) - memorized_result_loads = pickle.loads(memorized_result_pickle) - - assert memorized_result.store_backend.location == \ - memorized_result_loads.store_backend.location - assert memorized_result.func == memorized_result_loads.func - assert memorized_result.args_id == memorized_result_loads.args_id - assert str(memorized_result) == str(memorized_result_loads) - - -def compare(left, right, ignored_attrs=None): - if ignored_attrs is None: - ignored_attrs = [] - - left_vars = vars(left) - right_vars = vars(right) - assert set(left_vars.keys()) == set(right_vars.keys()) - for attr in left_vars.keys(): - if attr in ignored_attrs: - continue - assert left_vars[attr] == right_vars[attr] - - -@pytest.mark.parametrize('memory_kwargs', - [{'compress': 3, 'verbose': 2}, - {'mmap_mode': 'r', 'verbose': 5, - 'backend_options': {'parameter': 'unused'}}]) -def test_memory_pickle_dump_load(tmpdir, memory_kwargs): - memory = Memory(location=tmpdir.strpath, **memory_kwargs) - - memory_reloaded = pickle.loads(pickle.dumps(memory)) - - # Compare Memory instance before and after pickle roundtrip - compare(memory.store_backend, memory_reloaded.store_backend) - compare(memory, memory_reloaded, - ignored_attrs=set(['store_backend', 'timestamp', '_func_code_id'])) - assert hash(memory) == hash(memory_reloaded) - - func_cached = memory.cache(f) - - func_cached_reloaded = pickle.loads(pickle.dumps(func_cached)) - - # Compare MemorizedFunc instance before/after pickle roundtrip - compare(func_cached.store_backend, func_cached_reloaded.store_backend) - compare(func_cached, func_cached_reloaded, - ignored_attrs=set(['store_backend', 'timestamp', '_func_code_id'])) - assert hash(func_cached) == hash(func_cached_reloaded) - - # Compare MemorizedResult instance before/after pickle roundtrip - memorized_result = func_cached.call_and_shelve(1) - memorized_result_reloaded = pickle.loads(pickle.dumps(memorized_result)) - - compare(memorized_result.store_backend, - memorized_result_reloaded.store_backend) - compare(memorized_result, memorized_result_reloaded, - ignored_attrs=set(['store_backend', 'timestamp', '_func_code_id'])) - assert hash(memorized_result) == hash(memorized_result_reloaded) - - -def test_info_log(tmpdir, caplog): - caplog.set_level(logging.INFO) - x = 3 - - memory = Memory(location=tmpdir.strpath, verbose=20) - - @memory.cache - def f(x): - return x ** 2 - - _ = f(x) - assert "Querying" in caplog.text - caplog.clear() - - memory = Memory(location=tmpdir.strpath, verbose=0) - - @memory.cache - def f(x): - return x ** 2 - - _ = f(x) - assert "Querying" not in caplog.text - caplog.clear() - - -def test_deprecated_bytes_limit(tmpdir): - from joblib import __version__ - if __version__ >= "1.5": - raise DeprecationWarning( - "Bytes limit is deprecated and should be removed by 1.4" - ) - with pytest.warns(DeprecationWarning, match="bytes_limit"): - _ = Memory(location=tmpdir.strpath, bytes_limit='1K') - - -class TestCacheValidationCallback: - "Tests on parameter `cache_validation_callback`" - - def foo(self, x, d, delay=None): - d["run"] = True - if delay is not None: - time.sleep(delay) - return x * 2 - - def test_invalid_cache_validation_callback(self, memory): - "Test invalid values for `cache_validation_callback" - match = "cache_validation_callback needs to be callable. Got True." - with pytest.raises(ValueError, match=match): - memory.cache(cache_validation_callback=True) - - @pytest.mark.parametrize("consider_cache_valid", [True, False]) - def test_constant_cache_validation_callback( - self, memory, consider_cache_valid - ): - "Test expiry of old results" - f = memory.cache( - self.foo, cache_validation_callback=lambda _: consider_cache_valid, - ignore=["d"] - ) - - d1, d2 = {"run": False}, {"run": False} - assert f(2, d1) == 4 - assert f(2, d2) == 4 - - assert d1["run"] - assert d2["run"] != consider_cache_valid - - def test_memory_only_cache_long_run(self, memory): - "Test cache validity based on run duration." - - def cache_validation_callback(metadata): - duration = metadata['duration'] - if duration > 0.1: - return True - - f = memory.cache( - self.foo, cache_validation_callback=cache_validation_callback, - ignore=["d"] - ) - - # Short run are not cached - d1, d2 = {"run": False}, {"run": False} - assert f(2, d1, delay=0) == 4 - assert f(2, d2, delay=0) == 4 - assert d1["run"] - assert d2["run"] - - # Longer run are cached - d1, d2 = {"run": False}, {"run": False} - assert f(2, d1, delay=0.2) == 4 - assert f(2, d2, delay=0.2) == 4 - assert d1["run"] - assert not d2["run"] - - def test_memory_expires_after(self, memory): - "Test expiry of old cached results" - - f = memory.cache( - self.foo, cache_validation_callback=expires_after(seconds=.3), - ignore=["d"] - ) - - d1, d2, d3 = {"run": False}, {"run": False}, {"run": False} - assert f(2, d1) == 4 - assert f(2, d2) == 4 - time.sleep(.5) - assert f(2, d3) == 4 - - assert d1["run"] - assert not d2["run"] - assert d3["run"] - - -class TestMemorizedFunc: - "Tests for the MemorizedFunc and NotMemorizedFunc classes" - - @staticmethod - def f(x, counter): - counter[x] = counter.get(x, 0) + 1 - return counter[x] - - def test_call_method_memorized(self, memory): - "Test calling the function" - - f = memory.cache(self.f, ignore=['counter']) - - counter = {} - assert f(2, counter) == 1 - assert f(2, counter) == 1 - - x, meta = f.call(2, counter) - assert x == 2, "f has not been called properly" - assert isinstance(meta, dict), ( - "Metadata are not returned by MemorizedFunc.call." - ) - - def test_call_method_not_memorized(self, memory): - "Test calling the function" - - f = NotMemorizedFunc(self.f) - - counter = {} - assert f(2, counter) == 1 - assert f(2, counter) == 2 - - x, meta = f.call(2, counter) - assert x == 3, "f has not been called properly" - assert isinstance(meta, dict), ( - "Metadata are not returned by MemorizedFunc.call." - ) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory_async.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory_async.py deleted file mode 100644 index 53ddeff..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_memory_async.py +++ /dev/null @@ -1,170 +0,0 @@ -import asyncio -import gc -import shutil - -import pytest - -from joblib.memory import (AsyncMemorizedFunc, AsyncNotMemorizedFunc, - MemorizedResult, Memory, NotMemorizedResult) -from joblib.test.common import np, with_numpy -from joblib.testing import raises - -from .test_memory import (corrupt_single_cache_item, - monkeypatch_cached_func_warn) - - -async def check_identity_lazy_async(func, accumulator, location): - """ Similar to check_identity_lazy_async for coroutine functions""" - memory = Memory(location=location, verbose=0) - func = memory.cache(func) - for i in range(3): - for _ in range(2): - value = await func(i) - assert value == i - assert len(accumulator) == i + 1 - - -@pytest.mark.asyncio -async def test_memory_integration_async(tmpdir): - accumulator = list() - - async def f(n): - await asyncio.sleep(0.1) - accumulator.append(1) - return n - - await check_identity_lazy_async(f, accumulator, tmpdir.strpath) - - # Now test clearing - for compress in (False, True): - for mmap_mode in ('r', None): - memory = Memory(location=tmpdir.strpath, verbose=10, - mmap_mode=mmap_mode, compress=compress) - # First clear the cache directory, to check that our code can - # handle that - # NOTE: this line would raise an exception, as the database - # file is still open; we ignore the error since we want to - # test what happens if the directory disappears - shutil.rmtree(tmpdir.strpath, ignore_errors=True) - g = memory.cache(f) - await g(1) - g.clear(warn=False) - current_accumulator = len(accumulator) - out = await g(1) - - assert len(accumulator) == current_accumulator + 1 - # Also, check that Memory.eval works similarly - evaled = await memory.eval(f, 1) - assert evaled == out - assert len(accumulator) == current_accumulator + 1 - - # Now do a smoke test with a function defined in __main__, as the name - # mangling rules are more complex - f.__module__ = '__main__' - memory = Memory(location=tmpdir.strpath, verbose=0) - await memory.cache(f)(1) - - -@pytest.mark.asyncio -async def test_no_memory_async(): - accumulator = list() - - async def ff(x): - await asyncio.sleep(0.1) - accumulator.append(1) - return x - - memory = Memory(location=None, verbose=0) - gg = memory.cache(ff) - for _ in range(4): - current_accumulator = len(accumulator) - await gg(1) - assert len(accumulator) == current_accumulator + 1 - - -@with_numpy -@pytest.mark.asyncio -async def test_memory_numpy_check_mmap_mode_async(tmpdir, monkeypatch): - """Check that mmap_mode is respected even at the first call""" - - memory = Memory(location=tmpdir.strpath, mmap_mode='r', verbose=0) - - @memory.cache() - async def twice(a): - return a * 2 - - a = np.ones(3) - b = await twice(a) - c = await twice(a) - - assert isinstance(c, np.memmap) - assert c.mode == 'r' - - assert isinstance(b, np.memmap) - assert b.mode == 'r' - - # Corrupts the file, Deleting b and c mmaps - # is necessary to be able edit the file - del b - del c - gc.collect() - corrupt_single_cache_item(memory) - - # Make sure that corrupting the file causes recomputation and that - # a warning is issued. - recorded_warnings = monkeypatch_cached_func_warn(twice, monkeypatch) - d = await twice(a) - assert len(recorded_warnings) == 1 - exception_msg = 'Exception while loading results' - assert exception_msg in recorded_warnings[0] - # Asserts that the recomputation returns a mmap - assert isinstance(d, np.memmap) - assert d.mode == 'r' - - -@pytest.mark.asyncio -async def test_call_and_shelve_async(tmpdir): - async def f(x, y=1): - await asyncio.sleep(0.1) - return x ** 2 + y - - # Test MemorizedFunc outputting a reference to cache. - for func, Result in zip((AsyncMemorizedFunc(f, tmpdir.strpath), - AsyncNotMemorizedFunc(f), - Memory(location=tmpdir.strpath, - verbose=0).cache(f), - Memory(location=None).cache(f), - ), - (MemorizedResult, NotMemorizedResult, - MemorizedResult, NotMemorizedResult, - )): - for _ in range(2): - result = await func.call_and_shelve(2) - assert isinstance(result, Result) - assert result.get() == 5 - - result.clear() - with raises(KeyError): - result.get() - result.clear() # Do nothing if there is no cache. - - -@pytest.mark.asyncio -async def test_memorized_func_call_async(memory): - - async def ff(x, counter): - await asyncio.sleep(0.1) - counter[x] = counter.get(x, 0) + 1 - return counter[x] - - gg = memory.cache(ff, ignore=['counter']) - - counter = {} - assert await gg(2, counter) == 1 - assert await gg(2, counter) == 1 - - x, meta = await gg.call(2, counter) - assert x == 2, "f has not been called properly" - assert isinstance(meta, dict), ( - "Metadata are not returned by MemorizedFunc.call." - ) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_missing_multiprocessing.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_missing_multiprocessing.py deleted file mode 100644 index 251925c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_missing_multiprocessing.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Pyodide and other single-threaded Python builds will be missing the -_multiprocessing module. Test that joblib still works in this environment. -""" - -import os -import subprocess -import sys - - -def test_missing_multiprocessing(tmp_path): - """ - Test that import joblib works even if _multiprocessing is missing. - - pytest has already imported everything from joblib. The most reasonable way - to test importing joblib with modified environment is to invoke a separate - Python process. This also ensures that we don't break other tests by - importing a bad `_multiprocessing` module. - """ - (tmp_path / "_multiprocessing.py").write_text( - 'raise ImportError("No _multiprocessing module!")' - ) - env = dict(os.environ) - # For subprocess, use current sys.path with our custom version of - # multiprocessing inserted. - env["PYTHONPATH"] = ":".join([str(tmp_path)] + sys.path) - subprocess.check_call( - [sys.executable, "-c", - "import joblib, math; " - "joblib.Parallel(n_jobs=1)(" - "joblib.delayed(math.sqrt)(i**2) for i in range(10))" - ], env=env) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_module.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_module.py deleted file mode 100644 index a2257a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_module.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys -import joblib -from joblib.testing import check_subprocess_call -from joblib.test.common import with_multiprocessing - - -def test_version(): - assert hasattr(joblib, '__version__'), ( - "There are no __version__ argument on the joblib module") - - -@with_multiprocessing -def test_no_start_method_side_effect_on_import(): - # check that importing joblib does not implicitly set the global - # start_method for multiprocessing. - code = """if True: - import joblib - import multiprocessing as mp - # The following line would raise RuntimeError if the - # start_method is already set. - mp.set_start_method("loky") - """ - check_subprocess_call([sys.executable, '-c', code]) - - -@with_multiprocessing -def test_no_semaphore_tracker_on_import(): - # check that importing joblib does not implicitly spawn a resource tracker - # or a semaphore tracker - code = """if True: - import joblib - from multiprocessing import semaphore_tracker - # The following line would raise RuntimeError if the - # start_method is already set. - msg = "multiprocessing.semaphore_tracker has been spawned on import" - assert semaphore_tracker._semaphore_tracker._fd is None, msg""" - if sys.version_info >= (3, 8): - # semaphore_tracker was renamed in Python 3.8: - code = code.replace("semaphore_tracker", "resource_tracker") - check_subprocess_call([sys.executable, '-c', code]) - - -@with_multiprocessing -def test_no_resource_tracker_on_import(): - code = """if True: - import joblib - from joblib.externals.loky.backend import resource_tracker - # The following line would raise RuntimeError if the - # start_method is already set. - msg = "loky.resource_tracker has been spawned on import" - assert resource_tracker._resource_tracker._fd is None, msg - """ - check_subprocess_call([sys.executable, '-c', code]) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle.py deleted file mode 100644 index 9fee585..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle.py +++ /dev/null @@ -1,1159 +0,0 @@ -"""Test the numpy pickler as a replacement of the standard pickler.""" - -import copy -import os -import random -import re -import io -import sys -import warnings -import gzip -import zlib -import bz2 -import pickle -import socket -from contextlib import closing -import mmap -from pathlib import Path - -try: - import lzma -except ImportError: - lzma = None - -import pytest - -from joblib.test.common import np, with_numpy, with_lz4, without_lz4 -from joblib.test.common import with_memory_profiler, memory_used -from joblib.testing import parametrize, raises, warns - -# numpy_pickle is not a drop-in replacement of pickle, as it takes -# filenames instead of open files as arguments. -from joblib import numpy_pickle, register_compressor -from joblib.test import data - -from joblib.numpy_pickle_utils import _IO_BUFFER_SIZE -from joblib.numpy_pickle_utils import _detect_compressor -from joblib.numpy_pickle_utils import _is_numpy_array_byte_order_mismatch -from joblib.numpy_pickle_utils import _ensure_native_byte_order -from joblib.compressor import (_COMPRESSORS, _LZ4_PREFIX, CompressorWrapper, - LZ4_NOT_INSTALLED_ERROR, BinaryZlibFile) - - -############################################################################### -# Define a list of standard types. -# Borrowed from dill, initial author: Micheal McKerns: -# http://dev.danse.us/trac/pathos/browser/dill/dill_test2.py - -typelist = [] - -# testing types -_none = None -typelist.append(_none) -_type = type -typelist.append(_type) -_bool = bool(1) -typelist.append(_bool) -_int = int(1) -typelist.append(_int) -_float = float(1) -typelist.append(_float) -_complex = complex(1) -typelist.append(_complex) -_string = str(1) -typelist.append(_string) -_tuple = () -typelist.append(_tuple) -_list = [] -typelist.append(_list) -_dict = {} -typelist.append(_dict) -_builtin = len -typelist.append(_builtin) - - -def _function(x): - yield x - - -class _class: - def _method(self): - pass - - -class _newclass(object): - def _method(self): - pass - - -typelist.append(_function) -typelist.append(_class) -typelist.append(_newclass) # -_instance = _class() -typelist.append(_instance) -_object = _newclass() -typelist.append(_object) # - - -############################################################################### -# Tests - -@parametrize('compress', [0, 1]) -@parametrize('member', typelist) -def test_standard_types(tmpdir, compress, member): - # Test pickling and saving with standard types. - filename = tmpdir.join('test.pkl').strpath - numpy_pickle.dump(member, filename, compress=compress) - _member = numpy_pickle.load(filename) - # We compare the pickled instance to the reloaded one only if it - # can be compared to a copied one - if member == copy.deepcopy(member): - assert member == _member - - -def test_value_error(): - # Test inverting the input arguments to dump - with raises(ValueError): - numpy_pickle.dump('foo', dict()) - - -@parametrize('wrong_compress', [-1, 10, dict()]) -def test_compress_level_error(wrong_compress): - # Verify that passing an invalid compress argument raises an error. - exception_msg = ('Non valid compress level given: ' - '"{0}"'.format(wrong_compress)) - with raises(ValueError) as excinfo: - numpy_pickle.dump('dummy', 'foo', compress=wrong_compress) - excinfo.match(exception_msg) - - -@with_numpy -@parametrize('compress', [False, True, 0, 3, 'zlib']) -def test_numpy_persistence(tmpdir, compress): - filename = tmpdir.join('test.pkl').strpath - rnd = np.random.RandomState(0) - a = rnd.random_sample((10, 2)) - # We use 'a.T' to have a non C-contiguous array. - for index, obj in enumerate(((a,), (a.T,), (a, a), [a, a, a])): - filenames = numpy_pickle.dump(obj, filename, compress=compress) - - # All is cached in one file - assert len(filenames) == 1 - # Check that only one file was created - assert filenames[0] == filename - # Check that this file does exist - assert os.path.exists(filenames[0]) - - # Unpickle the object - obj_ = numpy_pickle.load(filename) - # Check that the items are indeed arrays - for item in obj_: - assert isinstance(item, np.ndarray) - # And finally, check that all the values are equal. - np.testing.assert_array_equal(np.array(obj), np.array(obj_)) - - # Now test with an array subclass - obj = np.memmap(filename + 'mmap', mode='w+', shape=4, dtype=np.float64) - filenames = numpy_pickle.dump(obj, filename, compress=compress) - # All is cached in one file - assert len(filenames) == 1 - - obj_ = numpy_pickle.load(filename) - if (type(obj) is not np.memmap and - hasattr(obj, '__array_prepare__')): - # We don't reconstruct memmaps - assert isinstance(obj_, type(obj)) - - np.testing.assert_array_equal(obj_, obj) - - # Test with an object containing multiple numpy arrays - obj = ComplexTestObject() - filenames = numpy_pickle.dump(obj, filename, compress=compress) - # All is cached in one file - assert len(filenames) == 1 - - obj_loaded = numpy_pickle.load(filename) - assert isinstance(obj_loaded, type(obj)) - np.testing.assert_array_equal(obj_loaded.array_float, obj.array_float) - np.testing.assert_array_equal(obj_loaded.array_int, obj.array_int) - np.testing.assert_array_equal(obj_loaded.array_obj, obj.array_obj) - - -@with_numpy -def test_numpy_persistence_bufferred_array_compression(tmpdir): - big_array = np.ones((_IO_BUFFER_SIZE + 100), dtype=np.uint8) - filename = tmpdir.join('test.pkl').strpath - numpy_pickle.dump(big_array, filename, compress=True) - arr_reloaded = numpy_pickle.load(filename) - - np.testing.assert_array_equal(big_array, arr_reloaded) - - -@with_numpy -def test_memmap_persistence(tmpdir): - rnd = np.random.RandomState(0) - a = rnd.random_sample(10) - filename = tmpdir.join('test1.pkl').strpath - numpy_pickle.dump(a, filename) - b = numpy_pickle.load(filename, mmap_mode='r') - - assert isinstance(b, np.memmap) - - # Test with an object containing multiple numpy arrays - filename = tmpdir.join('test2.pkl').strpath - obj = ComplexTestObject() - numpy_pickle.dump(obj, filename) - obj_loaded = numpy_pickle.load(filename, mmap_mode='r') - assert isinstance(obj_loaded, type(obj)) - assert isinstance(obj_loaded.array_float, np.memmap) - assert not obj_loaded.array_float.flags.writeable - assert isinstance(obj_loaded.array_int, np.memmap) - assert not obj_loaded.array_int.flags.writeable - # Memory map not allowed for numpy object arrays - assert not isinstance(obj_loaded.array_obj, np.memmap) - np.testing.assert_array_equal(obj_loaded.array_float, - obj.array_float) - np.testing.assert_array_equal(obj_loaded.array_int, - obj.array_int) - np.testing.assert_array_equal(obj_loaded.array_obj, - obj.array_obj) - - # Test we can write in memmapped arrays - obj_loaded = numpy_pickle.load(filename, mmap_mode='r+') - assert obj_loaded.array_float.flags.writeable - obj_loaded.array_float[0:10] = 10.0 - assert obj_loaded.array_int.flags.writeable - obj_loaded.array_int[0:10] = 10 - - obj_reloaded = numpy_pickle.load(filename, mmap_mode='r') - np.testing.assert_array_equal(obj_reloaded.array_float, - obj_loaded.array_float) - np.testing.assert_array_equal(obj_reloaded.array_int, - obj_loaded.array_int) - - # Test w+ mode is caught and the mode has switched to r+ - numpy_pickle.load(filename, mmap_mode='w+') - assert obj_loaded.array_int.flags.writeable - assert obj_loaded.array_int.mode == 'r+' - assert obj_loaded.array_float.flags.writeable - assert obj_loaded.array_float.mode == 'r+' - - -@with_numpy -def test_memmap_persistence_mixed_dtypes(tmpdir): - # loading datastructures that have sub-arrays with dtype=object - # should not prevent memmapping on fixed size dtype sub-arrays. - rnd = np.random.RandomState(0) - a = rnd.random_sample(10) - b = np.array([1, 'b'], dtype=object) - construct = (a, b) - filename = tmpdir.join('test.pkl').strpath - numpy_pickle.dump(construct, filename) - a_clone, b_clone = numpy_pickle.load(filename, mmap_mode='r') - - # the floating point array has been memory mapped - assert isinstance(a_clone, np.memmap) - - # the object-dtype array has been loaded in memory - assert not isinstance(b_clone, np.memmap) - - -@with_numpy -def test_masked_array_persistence(tmpdir): - # The special-case picker fails, because saving masked_array - # not implemented, but it just delegates to the standard pickler. - rnd = np.random.RandomState(0) - a = rnd.random_sample(10) - a = np.ma.masked_greater(a, 0.5) - filename = tmpdir.join('test.pkl').strpath - numpy_pickle.dump(a, filename) - b = numpy_pickle.load(filename, mmap_mode='r') - assert isinstance(b, np.ma.masked_array) - - -@with_numpy -def test_compress_mmap_mode_warning(tmpdir): - # Test the warning in case of compress + mmap_mode - rnd = np.random.RandomState(0) - a = rnd.random_sample(10) - this_filename = tmpdir.join('test.pkl').strpath - numpy_pickle.dump(a, this_filename, compress=1) - with warns(UserWarning) as warninfo: - numpy_pickle.load(this_filename, mmap_mode='r+') - debug_msg = "\n".join([str(w) for w in warninfo]) - warninfo = [w.message for w in warninfo] - assert len(warninfo) == 1, debug_msg - assert ( - str(warninfo[0]) == - 'mmap_mode "r+" is not compatible with compressed ' - f'file {this_filename}. "r+" flag will be ignored.' - ) - - -@with_numpy -@parametrize('cache_size', [None, 0, 10]) -def test_cache_size_warning(tmpdir, cache_size): - # Check deprecation warning raised when cache size is not None - filename = tmpdir.join('test.pkl').strpath - rnd = np.random.RandomState(0) - a = rnd.random_sample((10, 2)) - - warnings.simplefilter("always") - with warnings.catch_warnings(record=True) as warninfo: - numpy_pickle.dump(a, filename, cache_size=cache_size) - expected_nb_warnings = 1 if cache_size is not None else 0 - assert len(warninfo) == expected_nb_warnings - for w in warninfo: - assert w.category == DeprecationWarning - assert (str(w.message) == - "Please do not set 'cache_size' in joblib.dump, this " - "parameter has no effect and will be removed. You " - "used 'cache_size={0}'".format(cache_size)) - - -@with_numpy -@with_memory_profiler -@parametrize('compress', [True, False]) -def test_memory_usage(tmpdir, compress): - # Verify memory stays within expected bounds. - filename = tmpdir.join('test.pkl').strpath - small_array = np.ones((10, 10)) - big_array = np.ones(shape=100 * int(1e6), dtype=np.uint8) - - for obj in (small_array, big_array): - size = obj.nbytes / 1e6 - obj_filename = filename + str(np.random.randint(0, 1000)) - mem_used = memory_used(numpy_pickle.dump, - obj, obj_filename, compress=compress) - - # The memory used to dump the object shouldn't exceed the buffer - # size used to write array chunks (16MB). - write_buf_size = _IO_BUFFER_SIZE + 16 * 1024 ** 2 / 1e6 - assert mem_used <= write_buf_size - - mem_used = memory_used(numpy_pickle.load, obj_filename) - # memory used should be less than array size + buffer size used to - # read the array chunk by chunk. - read_buf_size = 32 + _IO_BUFFER_SIZE # MiB - assert mem_used < size + read_buf_size - - -@with_numpy -def test_compressed_pickle_dump_and_load(tmpdir): - expected_list = [np.arange(5, dtype=np.dtype('i8')), - np.arange(5, dtype=np.dtype('f8')), - np.array([1, 'abc', {'a': 1, 'b': 2}], dtype='O'), - np.arange(256, dtype=np.uint8).tobytes(), - u"C'est l'\xe9t\xe9 !"] - - fname = tmpdir.join('temp.pkl.gz').strpath - - dumped_filenames = numpy_pickle.dump(expected_list, fname, compress=1) - assert len(dumped_filenames) == 1 - result_list = numpy_pickle.load(fname) - for result, expected in zip(result_list, expected_list): - if isinstance(expected, np.ndarray): - expected = _ensure_native_byte_order(expected) - assert result.dtype == expected.dtype - np.testing.assert_equal(result, expected) - else: - assert result == expected - - -def _check_pickle(filename, expected_list, mmap_mode=None): - """Helper function to test joblib pickle content. - - Note: currently only pickles containing an iterable are supported - by this function. - """ - version_match = re.match(r'.+py(\d)(\d).+', filename) - py_version_used_for_writing = int(version_match.group(1)) - - py_version_to_default_pickle_protocol = {2: 2, 3: 3} - pickle_reading_protocol = py_version_to_default_pickle_protocol.get(3, 4) - pickle_writing_protocol = py_version_to_default_pickle_protocol.get( - py_version_used_for_writing, 4) - if pickle_reading_protocol >= pickle_writing_protocol: - try: - with warnings.catch_warnings(record=True) as warninfo: - warnings.simplefilter('always') - warnings.filterwarnings( - 'ignore', module='numpy', - message='The compiler package is deprecated') - result_list = numpy_pickle.load(filename, mmap_mode=mmap_mode) - filename_base = os.path.basename(filename) - expected_nb_deprecation_warnings = 1 if ( - "_0.9" in filename_base or "_0.8.4" in filename_base) else 0 - - expected_nb_user_warnings = 3 if ( - re.search("_0.1.+.pkl$", filename_base) and - mmap_mode is not None) else 0 - expected_nb_warnings = \ - expected_nb_deprecation_warnings + expected_nb_user_warnings - assert len(warninfo) == expected_nb_warnings - - deprecation_warnings = [ - w for w in warninfo if issubclass( - w.category, DeprecationWarning)] - user_warnings = [ - w for w in warninfo if issubclass( - w.category, UserWarning)] - for w in deprecation_warnings: - assert (str(w.message) == - "The file '{0}' has been generated with a joblib " - "version less than 0.10. Please regenerate this " - "pickle file.".format(filename)) - - for w in user_warnings: - escaped_filename = re.escape(filename) - assert re.search( - f"memmapped.+{escaped_filename}.+segmentation fault", - str(w.message)) - - for result, expected in zip(result_list, expected_list): - if isinstance(expected, np.ndarray): - expected = _ensure_native_byte_order(expected) - assert result.dtype == expected.dtype - np.testing.assert_equal(result, expected) - else: - assert result == expected - except Exception as exc: - # When trying to read with python 3 a pickle generated - # with python 2 we expect a user-friendly error - if py_version_used_for_writing == 2: - assert isinstance(exc, ValueError) - message = ('You may be trying to read with ' - 'python 3 a joblib pickle generated with python 2.') - assert message in str(exc) - elif filename.endswith('.lz4') and with_lz4.args[0]: - assert isinstance(exc, ValueError) - assert LZ4_NOT_INSTALLED_ERROR in str(exc) - else: - raise - else: - # Pickle protocol used for writing is too high. We expect a - # "unsupported pickle protocol" error message - try: - numpy_pickle.load(filename) - raise AssertionError('Numpy pickle loading should ' - 'have raised a ValueError exception') - except ValueError as e: - message = 'unsupported pickle protocol: {0}'.format( - pickle_writing_protocol) - assert message in str(e.args) - - -@with_numpy -def test_joblib_pickle_across_python_versions(): - # We need to be specific about dtypes in particular endianness - # because the pickles can be generated on one architecture and - # the tests run on another one. See - # https://github.com/joblib/joblib/issues/279. - expected_list = [np.arange(5, dtype=np.dtype('i8'), ('', '>f8')]), - np.arange(3, dtype=np.dtype('>i8')), - np.arange(3, dtype=np.dtype('>f8'))] - - # Verify the byteorder mismatch is correctly detected. - for array in be_arrays: - if sys.byteorder == 'big': - assert not _is_numpy_array_byte_order_mismatch(array) - else: - assert _is_numpy_array_byte_order_mismatch(array) - converted = _ensure_native_byte_order(array) - if converted.dtype.fields: - for f in converted.dtype.fields.values(): - f[0].byteorder == '=' - else: - assert converted.dtype.byteorder == "=" - - # List of numpy arrays with little endian byteorder. - le_arrays = [np.array([(1, 2.0), (3, 4.0)], - dtype=[('', ' size - np.testing.assert_array_equal(obj, memmaps) - - -def test_register_compressor(tmpdir): - # Check that registering compressor file works. - compressor_name = 'test-name' - compressor_prefix = 'test-prefix' - - class BinaryCompressorTestFile(io.BufferedIOBase): - pass - - class BinaryCompressorTestWrapper(CompressorWrapper): - - def __init__(self): - CompressorWrapper.__init__(self, obj=BinaryCompressorTestFile, - prefix=compressor_prefix) - - register_compressor(compressor_name, BinaryCompressorTestWrapper()) - - assert (_COMPRESSORS[compressor_name].fileobj_factory == - BinaryCompressorTestFile) - assert _COMPRESSORS[compressor_name].prefix == compressor_prefix - - # Remove this dummy compressor file from extra compressors because other - # tests might fail because of this - _COMPRESSORS.pop(compressor_name) - - -@parametrize('invalid_name', [1, (), {}]) -def test_register_compressor_invalid_name(invalid_name): - # Test that registering an invalid compressor name is not allowed. - with raises(ValueError) as excinfo: - register_compressor(invalid_name, None) - excinfo.match("Compressor name should be a string") - - -def test_register_compressor_invalid_fileobj(): - # Test that registering an invalid file object is not allowed. - - class InvalidFileObject(): - pass - - class InvalidFileObjectWrapper(CompressorWrapper): - def __init__(self): - CompressorWrapper.__init__(self, obj=InvalidFileObject, - prefix=b'prefix') - - with raises(ValueError) as excinfo: - register_compressor('invalid', InvalidFileObjectWrapper()) - - excinfo.match("Compressor 'fileobj_factory' attribute should implement " - "the file object interface") - - -class AnotherZlibCompressorWrapper(CompressorWrapper): - - def __init__(self): - CompressorWrapper.__init__(self, obj=BinaryZlibFile, prefix=b'prefix') - - -class StandardLibGzipCompressorWrapper(CompressorWrapper): - - def __init__(self): - CompressorWrapper.__init__(self, obj=gzip.GzipFile, prefix=b'prefix') - - -def test_register_compressor_already_registered(): - # Test registration of existing compressor files. - compressor_name = 'test-name' - - # register a test compressor - register_compressor(compressor_name, AnotherZlibCompressorWrapper()) - - with raises(ValueError) as excinfo: - register_compressor(compressor_name, - StandardLibGzipCompressorWrapper()) - excinfo.match("Compressor '{}' already registered." - .format(compressor_name)) - - register_compressor(compressor_name, StandardLibGzipCompressorWrapper(), - force=True) - - assert compressor_name in _COMPRESSORS - assert _COMPRESSORS[compressor_name].fileobj_factory == gzip.GzipFile - - # Remove this dummy compressor file from extra compressors because other - # tests might fail because of this - _COMPRESSORS.pop(compressor_name) - - -@with_lz4 -def test_lz4_compression(tmpdir): - # Check that lz4 can be used when dependency is available. - import lz4.frame - compressor = 'lz4' - assert compressor in _COMPRESSORS - assert _COMPRESSORS[compressor].fileobj_factory == lz4.frame.LZ4FrameFile - - fname = tmpdir.join('test.pkl').strpath - data = 'test data' - numpy_pickle.dump(data, fname, compress=compressor) - - with open(fname, 'rb') as f: - assert f.read(len(_LZ4_PREFIX)) == _LZ4_PREFIX - assert numpy_pickle.load(fname) == data - - # Test that LZ4 is applied based on file extension - numpy_pickle.dump(data, fname + '.lz4') - with open(fname, 'rb') as f: - assert f.read(len(_LZ4_PREFIX)) == _LZ4_PREFIX - assert numpy_pickle.load(fname) == data - - -@without_lz4 -def test_lz4_compression_without_lz4(tmpdir): - # Check that lz4 cannot be used when dependency is not available. - fname = tmpdir.join('test.nolz4').strpath - data = 'test data' - msg = LZ4_NOT_INSTALLED_ERROR - with raises(ValueError) as excinfo: - numpy_pickle.dump(data, fname, compress='lz4') - excinfo.match(msg) - - with raises(ValueError) as excinfo: - numpy_pickle.dump(data, fname + '.lz4') - excinfo.match(msg) - - -protocols = [pickle.DEFAULT_PROTOCOL] -if pickle.HIGHEST_PROTOCOL != pickle.DEFAULT_PROTOCOL: - protocols.append(pickle.HIGHEST_PROTOCOL) - - -@with_numpy -@parametrize('protocol', protocols) -def test_memmap_alignment_padding(tmpdir, protocol): - # Test that memmaped arrays returned by numpy.load are correctly aligned - fname = tmpdir.join('test.mmap').strpath - - a = np.random.randn(2) - numpy_pickle.dump(a, fname, protocol=protocol) - memmap = numpy_pickle.load(fname, mmap_mode='r') - assert isinstance(memmap, np.memmap) - np.testing.assert_array_equal(a, memmap) - assert ( - memmap.ctypes.data % numpy_pickle.NUMPY_ARRAY_ALIGNMENT_BYTES == 0) - assert memmap.flags.aligned - - array_list = [ - np.random.randn(2), np.random.randn(2), - np.random.randn(2), np.random.randn(2) - ] - - # On Windows OSError 22 if reusing the same path for memmap ... - fname = tmpdir.join('test1.mmap').strpath - numpy_pickle.dump(array_list, fname, protocol=protocol) - l_reloaded = numpy_pickle.load(fname, mmap_mode='r') - - for idx, memmap in enumerate(l_reloaded): - assert isinstance(memmap, np.memmap) - np.testing.assert_array_equal(array_list[idx], memmap) - assert ( - memmap.ctypes.data % numpy_pickle.NUMPY_ARRAY_ALIGNMENT_BYTES == 0) - assert memmap.flags.aligned - - array_dict = { - 'a0': np.arange(2, dtype=np.uint8), - 'a1': np.arange(3, dtype=np.uint8), - 'a2': np.arange(5, dtype=np.uint8), - 'a3': np.arange(7, dtype=np.uint8), - 'a4': np.arange(11, dtype=np.uint8), - 'a5': np.arange(13, dtype=np.uint8), - 'a6': np.arange(17, dtype=np.uint8), - 'a7': np.arange(19, dtype=np.uint8), - 'a8': np.arange(23, dtype=np.uint8), - } - - # On Windows OSError 22 if reusing the same path for memmap ... - fname = tmpdir.join('test2.mmap').strpath - numpy_pickle.dump(array_dict, fname, protocol=protocol) - d_reloaded = numpy_pickle.load(fname, mmap_mode='r') - - for key, memmap in d_reloaded.items(): - assert isinstance(memmap, np.memmap) - np.testing.assert_array_equal(array_dict[key], memmap) - assert ( - memmap.ctypes.data % numpy_pickle.NUMPY_ARRAY_ALIGNMENT_BYTES == 0) - assert memmap.flags.aligned diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_compat.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_compat.py deleted file mode 100644 index 9e95393..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_compat.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Test the old numpy pickler, compatibility version.""" - -# numpy_pickle is not a drop-in replacement of pickle, as it takes -# filenames instead of open files as arguments. -from joblib import numpy_pickle_compat - - -def test_z_file(tmpdir): - # Test saving and loading data with Zfiles. - filename = tmpdir.join('test.pkl').strpath - data = numpy_pickle_compat.asbytes('Foo, \n Bar, baz, \n\nfoobar') - with open(filename, 'wb') as f: - numpy_pickle_compat.write_zfile(f, data) - with open(filename, 'rb') as f: - data_read = numpy_pickle_compat.read_zfile(f) - assert data == data_read diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_utils.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_utils.py deleted file mode 100644 index 5c414a2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_numpy_pickle_utils.py +++ /dev/null @@ -1,9 +0,0 @@ -from joblib.compressor import BinaryZlibFile -from joblib.testing import parametrize - - -@parametrize('filename', ['test', u'test']) # testing str and unicode names -def test_binary_zlib_file(tmpdir, filename): - """Testing creation of files depending on the type of the filenames.""" - binary_file = BinaryZlibFile(tmpdir.join(filename).strpath, mode='wb') - binary_file.close() diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_parallel.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_parallel.py deleted file mode 100644 index f171375..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_parallel.py +++ /dev/null @@ -1,2056 +0,0 @@ -""" -Test the parallel module. -""" - -# Author: Gael Varoquaux -# Copyright (c) 2010-2011 Gael Varoquaux -# License: BSD Style, 3 clauses. - -import os -import sys -import time -import mmap -import weakref -import warnings -import threading -from traceback import format_exception -from math import sqrt -from time import sleep -from pickle import PicklingError -from contextlib import nullcontext -from multiprocessing import TimeoutError -import pytest - -import joblib -from joblib import parallel -from joblib import dump, load - -from joblib._multiprocessing_helpers import mp - -from joblib.test.common import np, with_numpy -from joblib.test.common import with_multiprocessing -from joblib.test.common import IS_PYPY, force_gc_pypy -from joblib.testing import (parametrize, raises, check_subprocess_call, - skipif, warns) - -if mp is not None: - # Loky is not available if multiprocessing is not - from joblib.externals.loky import get_reusable_executor - -from queue import Queue - -try: - import posix -except ImportError: - posix = None - -try: - from ._openmp_test_helper.parallel_sum import parallel_sum -except ImportError: - parallel_sum = None - -try: - import distributed -except ImportError: - distributed = None - -from joblib._parallel_backends import SequentialBackend -from joblib._parallel_backends import ThreadingBackend -from joblib._parallel_backends import MultiprocessingBackend -from joblib._parallel_backends import ParallelBackendBase -from joblib._parallel_backends import LokyBackend - -from joblib.parallel import Parallel, delayed -from joblib.parallel import parallel_config -from joblib.parallel import parallel_backend -from joblib.parallel import register_parallel_backend -from joblib.parallel import effective_n_jobs, cpu_count - -from joblib.parallel import mp, BACKENDS, DEFAULT_BACKEND - - -RETURN_GENERATOR_BACKENDS = BACKENDS.copy() -RETURN_GENERATOR_BACKENDS.pop("multiprocessing", None) - -ALL_VALID_BACKENDS = [None] + sorted(BACKENDS.keys()) -# Add instances of backend classes deriving from ParallelBackendBase -ALL_VALID_BACKENDS += [BACKENDS[backend_str]() for backend_str in BACKENDS] -if mp is None: - PROCESS_BACKENDS = [] -else: - PROCESS_BACKENDS = ['multiprocessing', 'loky'] -PARALLEL_BACKENDS = PROCESS_BACKENDS + ['threading'] - -if hasattr(mp, 'get_context'): - # Custom multiprocessing context in Python 3.4+ - ALL_VALID_BACKENDS.append(mp.get_context('spawn')) - -DefaultBackend = BACKENDS[DEFAULT_BACKEND] - - -def get_workers(backend): - return getattr(backend, '_pool', getattr(backend, '_workers', None)) - - -def division(x, y): - return x / y - - -def square(x): - return x ** 2 - - -class MyExceptionWithFinickyInit(Exception): - """An exception class with non trivial __init__ - """ - def __init__(self, a, b, c, d): - pass - - -def exception_raiser(x, custom_exception=False): - if x == 7: - raise (MyExceptionWithFinickyInit('a', 'b', 'c', 'd') - if custom_exception else ValueError) - return x - - -def interrupt_raiser(x): - time.sleep(.05) - raise KeyboardInterrupt - - -def f(x, y=0, z=0): - """ A module-level function so that it can be spawn with - multiprocessing. - """ - return x ** 2 + y + z - - -def _active_backend_type(): - return type(parallel.get_active_backend()[0]) - - -def parallel_func(inner_n_jobs, backend): - return Parallel(n_jobs=inner_n_jobs, backend=backend)( - delayed(square)(i) for i in range(3)) - - -############################################################################### -def test_cpu_count(): - assert cpu_count() > 0 - - -def test_effective_n_jobs(): - assert effective_n_jobs() > 0 - - -@parametrize("context", [parallel_config, parallel_backend]) -@pytest.mark.parametrize( - "backend_n_jobs, expected_n_jobs", - [(3, 3), (-1, effective_n_jobs(n_jobs=-1)), (None, 1)], - ids=["positive-int", "negative-int", "None"] -) -@with_multiprocessing -def test_effective_n_jobs_None(context, backend_n_jobs, expected_n_jobs): - # check the number of effective jobs when `n_jobs=None` - # non-regression test for https://github.com/joblib/joblib/issues/984 - with context("threading", n_jobs=backend_n_jobs): - # when using a backend, the default of number jobs will be the one set - # in the backend - assert effective_n_jobs(n_jobs=None) == expected_n_jobs - # without any backend, None will default to a single job - assert effective_n_jobs(n_jobs=None) == 1 - - -############################################################################### -# Test parallel - -@parametrize('backend', ALL_VALID_BACKENDS) -@parametrize('n_jobs', [1, 2, -1, -2]) -@parametrize('verbose', [2, 11, 100]) -def test_simple_parallel(backend, n_jobs, verbose): - assert ([square(x) for x in range(5)] == - Parallel(n_jobs=n_jobs, backend=backend, - verbose=verbose)( - delayed(square)(x) for x in range(5))) - - -@parametrize('backend', ALL_VALID_BACKENDS) -def test_main_thread_renamed_no_warning(backend, monkeypatch): - # Check that no default backend relies on the name of the main thread: - # https://github.com/joblib/joblib/issues/180#issuecomment-253266247 - # Some programs use a different name for the main thread. This is the case - # for uWSGI apps for instance. - monkeypatch.setattr(target=threading.current_thread(), name='name', - value='some_new_name_for_the_main_thread') - - with warnings.catch_warnings(record=True) as warninfo: - results = Parallel(n_jobs=2, backend=backend)( - delayed(square)(x) for x in range(3)) - assert results == [0, 1, 4] - - # Due to the default parameters of LokyBackend, there is a chance that - # warninfo catches Warnings from worker timeouts. We remove it if it exists - warninfo = [w for w in warninfo if "worker timeout" not in str(w.message)] - - # The multiprocessing backend will raise a warning when detecting that is - # started from the non-main thread. Let's check that there is no false - # positive because of the name change. - assert len(warninfo) == 0 - - -def _assert_warning_nested(backend, inner_n_jobs, expected): - with warnings.catch_warnings(record=True) as warninfo: - warnings.simplefilter("always") - parallel_func(backend=backend, inner_n_jobs=inner_n_jobs) - - warninfo = [w.message for w in warninfo] - if expected: - if warninfo: - warnings_are_correct = all( - 'backed parallel loops cannot' in each.args[0] - for each in warninfo - ) - # With Python nogil, when the outer backend is threading, we might - # see more that one warning - warnings_have_the_right_length = ( - len(warninfo) >= 1 if getattr(sys.flags, 'nogil', False) - else len(warninfo) == 1) - return warnings_are_correct and warnings_have_the_right_length - - return False - else: - assert not warninfo - return True - - -@with_multiprocessing -@parametrize('parent_backend,child_backend,expected', [ - ('loky', 'multiprocessing', True), - ('loky', 'loky', False), - ('multiprocessing', 'multiprocessing', True), - ('multiprocessing', 'loky', True), - ('threading', 'multiprocessing', True), - ('threading', 'loky', True), -]) -def test_nested_parallel_warnings(parent_backend, child_backend, expected): - - # no warnings if inner_n_jobs=1 - Parallel(n_jobs=2, backend=parent_backend)( - delayed(_assert_warning_nested)( - backend=child_backend, inner_n_jobs=1, - expected=False) - for _ in range(5)) - - # warnings if inner_n_jobs != 1 and expected - res = Parallel(n_jobs=2, backend=parent_backend)( - delayed(_assert_warning_nested)( - backend=child_backend, inner_n_jobs=2, - expected=expected) - for _ in range(5)) - - # warning handling is not thread safe. One thread might see multiple - # warning or no warning at all. - if parent_backend == "threading": - if IS_PYPY and not any(res): - # Related to joblib#1426, should be removed once it is solved. - pytest.xfail(reason="This test often fails in PyPy.") - assert any(res) - else: - assert all(res) - - -@with_multiprocessing -@parametrize('backend', ['loky', 'multiprocessing', 'threading']) -def test_background_thread_parallelism(backend): - is_run_parallel = [False] - - def background_thread(is_run_parallel): - with warnings.catch_warnings(record=True) as warninfo: - Parallel(n_jobs=2)( - delayed(sleep)(.1) for _ in range(4)) - print(len(warninfo)) - is_run_parallel[0] = len(warninfo) == 0 - - t = threading.Thread(target=background_thread, args=(is_run_parallel,)) - t.start() - t.join() - assert is_run_parallel[0] - - -def nested_loop(backend): - Parallel(n_jobs=2, backend=backend)( - delayed(square)(.01) for _ in range(2)) - - -@parametrize('child_backend', BACKENDS) -@parametrize('parent_backend', BACKENDS) -def test_nested_loop(parent_backend, child_backend): - Parallel(n_jobs=2, backend=parent_backend)( - delayed(nested_loop)(child_backend) for _ in range(2)) - - -def raise_exception(backend): - raise ValueError - - -@with_multiprocessing -def test_nested_loop_with_exception_with_loky(): - with raises(ValueError): - with Parallel(n_jobs=2, backend="loky") as parallel: - parallel([delayed(nested_loop)("loky"), - delayed(raise_exception)("loky")]) - - -def test_mutate_input_with_threads(): - """Input is mutable when using the threading backend""" - q = Queue(maxsize=5) - Parallel(n_jobs=2, backend="threading")( - delayed(q.put)(1) for _ in range(5)) - assert q.full() - - -@parametrize('n_jobs', [1, 2, 3]) -def test_parallel_kwargs(n_jobs): - """Check the keyword argument processing of pmap.""" - lst = range(10) - assert ([f(x, y=1) for x in lst] == - Parallel(n_jobs=n_jobs)(delayed(f)(x, y=1) for x in lst)) - - -@parametrize('backend', PARALLEL_BACKENDS) -def test_parallel_as_context_manager(backend): - lst = range(10) - expected = [f(x, y=1) for x in lst] - - with Parallel(n_jobs=4, backend=backend) as p: - # Internally a pool instance has been eagerly created and is managed - # via the context manager protocol - managed_backend = p._backend - - # We make call with the managed parallel object several times inside - # the managed block: - assert expected == p(delayed(f)(x, y=1) for x in lst) - assert expected == p(delayed(f)(x, y=1) for x in lst) - - # Those calls have all used the same pool instance: - if mp is not None: - assert get_workers(managed_backend) is get_workers(p._backend) - - # As soon as we exit the context manager block, the pool is terminated and - # no longer referenced from the parallel object: - if mp is not None: - assert get_workers(p._backend) is None - - # It's still possible to use the parallel instance in non-managed mode: - assert expected == p(delayed(f)(x, y=1) for x in lst) - if mp is not None: - assert get_workers(p._backend) is None - - -@with_multiprocessing -def test_parallel_pickling(): - """ Check that pmap captures the errors when it is passed an object - that cannot be pickled. - """ - class UnpicklableObject(object): - def __reduce__(self): - raise RuntimeError('123') - - with raises(PicklingError, match=r"the task to send"): - Parallel(n_jobs=2, backend='loky')(delayed(id)( - UnpicklableObject()) for _ in range(10)) - - -@with_numpy -@with_multiprocessing -@parametrize('byteorder', ['<', '>', '=']) -def test_parallel_byteorder_corruption(byteorder): - - def inspect_byteorder(x): - return x, x.dtype.byteorder - - x = np.arange(6).reshape((2, 3)).view(f'{byteorder}i4') - - initial_np_byteorder = x.dtype.byteorder - - result = Parallel(n_jobs=2, backend='loky')( - delayed(inspect_byteorder)(x) for _ in range(3) - ) - - for x_returned, byteorder_in_worker in result: - assert byteorder_in_worker == initial_np_byteorder - assert byteorder_in_worker == x_returned.dtype.byteorder - np.testing.assert_array_equal(x, x_returned) - - -@parametrize('backend', PARALLEL_BACKENDS) -def test_parallel_timeout_success(backend): - # Check that timeout isn't thrown when function is fast enough - assert len(Parallel(n_jobs=2, backend=backend, timeout=30)( - delayed(sleep)(0.001) for x in range(10))) == 10 - - -@with_multiprocessing -@parametrize('backend', PARALLEL_BACKENDS) -def test_parallel_timeout_fail(backend): - # Check that timeout properly fails when function is too slow - with raises(TimeoutError): - Parallel(n_jobs=2, backend=backend, timeout=0.01)( - delayed(sleep)(10) for x in range(10)) - - -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_error_capture(backend): - # Check that error are captured, and that correct exceptions - # are raised. - if mp is not None: - with raises(ZeroDivisionError): - Parallel(n_jobs=2, backend=backend)( - [delayed(division)(x, y) - for x, y in zip((0, 1), (1, 0))]) - - with raises(KeyboardInterrupt): - Parallel(n_jobs=2, backend=backend)( - [delayed(interrupt_raiser)(x) for x in (1, 0)]) - - # Try again with the context manager API - with Parallel(n_jobs=2, backend=backend) as parallel: - assert get_workers(parallel._backend) is not None - original_workers = get_workers(parallel._backend) - - with raises(ZeroDivisionError): - parallel([delayed(division)(x, y) - for x, y in zip((0, 1), (1, 0))]) - - # The managed pool should still be available and be in a working - # state despite the previously raised (and caught) exception - assert get_workers(parallel._backend) is not None - - # The pool should have been interrupted and restarted: - assert get_workers(parallel._backend) is not original_workers - - assert ([f(x, y=1) for x in range(10)] == - parallel(delayed(f)(x, y=1) for x in range(10))) - - original_workers = get_workers(parallel._backend) - with raises(KeyboardInterrupt): - parallel([delayed(interrupt_raiser)(x) for x in (1, 0)]) - - # The pool should still be available despite the exception - assert get_workers(parallel._backend) is not None - - # The pool should have been interrupted and restarted: - assert get_workers(parallel._backend) is not original_workers - - assert ([f(x, y=1) for x in range(10)] == - parallel(delayed(f)(x, y=1) for x in range(10))), ( - parallel._iterating, parallel.n_completed_tasks, - parallel.n_dispatched_tasks, parallel._aborting - ) - - # Check that the inner pool has been terminated when exiting the - # context manager - assert get_workers(parallel._backend) is None - else: - with raises(KeyboardInterrupt): - Parallel(n_jobs=2)( - [delayed(interrupt_raiser)(x) for x in (1, 0)]) - - # wrapped exceptions should inherit from the class of the original - # exception to make it easy to catch them - with raises(ZeroDivisionError): - Parallel(n_jobs=2)( - [delayed(division)(x, y) for x, y in zip((0, 1), (1, 0))]) - - with raises(MyExceptionWithFinickyInit): - Parallel(n_jobs=2, verbose=0)( - (delayed(exception_raiser)(i, custom_exception=True) - for i in range(30))) - - -@with_multiprocessing -@parametrize('backend', BACKENDS) -def test_error_in_task_iterator(backend): - - def my_generator(raise_at=0): - for i in range(20): - if i == raise_at: - raise ValueError("Iterator Raising Error") - yield i - - with Parallel(n_jobs=2, backend=backend) as p: - # The error is raised in the pre-dispatch phase - with raises(ValueError, match="Iterator Raising Error"): - p(delayed(square)(i) for i in my_generator(raise_at=0)) - - # The error is raised when dispatching a new task after the - # pre-dispatch (likely to happen in a different thread) - with raises(ValueError, match="Iterator Raising Error"): - p(delayed(square)(i) for i in my_generator(raise_at=5)) - - # Same, but raises long after the pre-dispatch phase - with raises(ValueError, match="Iterator Raising Error"): - p(delayed(square)(i) for i in my_generator(raise_at=19)) - - -def consumer(queue, item): - queue.append('Consumed %s' % item) - - -@parametrize('backend', BACKENDS) -@parametrize('batch_size, expected_queue', - [(1, ['Produced 0', 'Consumed 0', - 'Produced 1', 'Consumed 1', - 'Produced 2', 'Consumed 2', - 'Produced 3', 'Consumed 3', - 'Produced 4', 'Consumed 4', - 'Produced 5', 'Consumed 5']), - (4, [ # First Batch - 'Produced 0', 'Produced 1', 'Produced 2', 'Produced 3', - 'Consumed 0', 'Consumed 1', 'Consumed 2', 'Consumed 3', - # Second batch - 'Produced 4', 'Produced 5', 'Consumed 4', 'Consumed 5'])]) -def test_dispatch_one_job(backend, batch_size, expected_queue): - """ Test that with only one job, Parallel does act as a iterator. - """ - queue = list() - - def producer(): - for i in range(6): - queue.append('Produced %i' % i) - yield i - - Parallel(n_jobs=1, batch_size=batch_size, backend=backend)( - delayed(consumer)(queue, x) for x in producer()) - assert queue == expected_queue - assert len(queue) == 12 - - -@with_multiprocessing -@parametrize('backend', PARALLEL_BACKENDS) -def test_dispatch_multiprocessing(backend): - """ Check that using pre_dispatch Parallel does indeed dispatch items - lazily. - """ - manager = mp.Manager() - queue = manager.list() - - def producer(): - for i in range(6): - queue.append('Produced %i' % i) - yield i - - Parallel(n_jobs=2, batch_size=1, pre_dispatch=3, backend=backend)( - delayed(consumer)(queue, 'any') for _ in producer()) - - queue_contents = list(queue) - assert queue_contents[0] == 'Produced 0' - - # Only 3 tasks are pre-dispatched out of 6. The 4th task is dispatched only - # after any of the first 3 jobs have completed. - first_consumption_index = queue_contents[:4].index('Consumed any') - assert first_consumption_index > -1 - - produced_3_index = queue_contents.index('Produced 3') # 4th task produced - assert produced_3_index > first_consumption_index - - assert len(queue) == 12 - - -def test_batching_auto_threading(): - # batching='auto' with the threading backend leaves the effective batch - # size to 1 (no batching) as it has been found to never be beneficial with - # this low-overhead backend. - - with Parallel(n_jobs=2, batch_size='auto', backend='threading') as p: - p(delayed(id)(i) for i in range(5000)) # many very fast tasks - assert p._backend.compute_batch_size() == 1 - - -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_batching_auto_subprocesses(backend): - with Parallel(n_jobs=2, batch_size='auto', backend=backend) as p: - p(delayed(id)(i) for i in range(5000)) # many very fast tasks - - # It should be strictly larger than 1 but as we don't want heisen - # failures on clogged CI worker environment be safe and only check that - # it's a strictly positive number. - assert p._backend.compute_batch_size() > 0 - - -def test_exception_dispatch(): - """Make sure that exception raised during dispatch are indeed captured""" - with raises(ValueError): - Parallel(n_jobs=2, pre_dispatch=16, verbose=0)( - delayed(exception_raiser)(i) for i in range(30)) - - -def nested_function_inner(i): - Parallel(n_jobs=2)( - delayed(exception_raiser)(j) for j in range(30)) - - -def nested_function_outer(i): - Parallel(n_jobs=2)( - delayed(nested_function_inner)(j) for j in range(30)) - - -@with_multiprocessing -@parametrize('backend', PARALLEL_BACKENDS) -@pytest.mark.xfail(reason="https://github.com/joblib/loky/pull/255") -def test_nested_exception_dispatch(backend): - """Ensure errors for nested joblib cases gets propagated - - We rely on the Python 3 built-in __cause__ system that already - report this kind of information to the user. - """ - with raises(ValueError) as excinfo: - Parallel(n_jobs=2, backend=backend)( - delayed(nested_function_outer)(i) for i in range(30)) - - # Check that important information such as function names are visible - # in the final error message reported to the user - report_lines = format_exception(excinfo.type, excinfo.value, excinfo.tb) - report = "".join(report_lines) - assert 'nested_function_outer' in report - assert 'nested_function_inner' in report - assert 'exception_raiser' in report - - assert type(excinfo.value) is ValueError - - -class FakeParallelBackend(SequentialBackend): - """Pretends to run concurrently while running sequentially.""" - - def configure(self, n_jobs=1, parallel=None, **backend_args): - self.n_jobs = self.effective_n_jobs(n_jobs) - self.parallel = parallel - return n_jobs - - def effective_n_jobs(self, n_jobs=1): - if n_jobs < 0: - n_jobs = max(mp.cpu_count() + 1 + n_jobs, 1) - return n_jobs - - -def test_invalid_backend(): - with raises(ValueError, match="Invalid backend:"): - Parallel(backend='unit-testing') - - with raises(ValueError, match="Invalid backend:"): - with parallel_config(backend='unit-testing'): - pass - - with raises(ValueError, match="Invalid backend:"): - with parallel_config(backend='unit-testing'): - pass - - -@parametrize('backend', ALL_VALID_BACKENDS) -def test_invalid_njobs(backend): - with raises(ValueError) as excinfo: - Parallel(n_jobs=0, backend=backend)._initialize_backend() - assert "n_jobs == 0 in Parallel has no meaning" in str(excinfo.value) - - with raises(ValueError) as excinfo: - Parallel(n_jobs=0.5, backend=backend)._initialize_backend() - assert "n_jobs == 0 in Parallel has no meaning" in str(excinfo.value) - - with raises(ValueError) as excinfo: - Parallel(n_jobs="2.3", backend=backend)._initialize_backend() - assert "n_jobs could not be converted to int" in str(excinfo.value) - - with raises(ValueError) as excinfo: - Parallel(n_jobs="invalid_str", backend=backend)._initialize_backend() - assert "n_jobs could not be converted to int" in str(excinfo.value) - - -@with_multiprocessing -@parametrize('backend', PARALLEL_BACKENDS) -@parametrize('n_jobs', ['2', 2.3, 2]) -def test_njobs_converted_to_int(backend, n_jobs): - p = Parallel(n_jobs=n_jobs, backend=backend) - assert p._effective_n_jobs() == 2 - - res = p(delayed(square)(i) for i in range(10)) - assert all(r == square(i) for i, r in enumerate(res)) - - -def test_register_parallel_backend(): - try: - register_parallel_backend("test_backend", FakeParallelBackend) - assert "test_backend" in BACKENDS - assert BACKENDS["test_backend"] == FakeParallelBackend - finally: - del BACKENDS["test_backend"] - - -def test_overwrite_default_backend(): - assert _active_backend_type() == DefaultBackend - try: - register_parallel_backend("threading", BACKENDS["threading"], - make_default=True) - assert _active_backend_type() == ThreadingBackend - finally: - # Restore the global default manually - parallel.DEFAULT_BACKEND = DEFAULT_BACKEND - assert _active_backend_type() == DefaultBackend - - -@skipif(mp is not None, reason="Only without multiprocessing") -def test_backend_no_multiprocessing(): - with warns(UserWarning, - match="joblib backend '.*' is not available on.*"): - Parallel(backend='loky')(delayed(square)(i) for i in range(3)) - - # The below should now work without problems - with parallel_config(backend='loky'): - Parallel()(delayed(square)(i) for i in range(3)) - - -def check_backend_context_manager(context, backend_name): - with context(backend_name, n_jobs=3): - active_backend, active_n_jobs = parallel.get_active_backend() - assert active_n_jobs == 3 - assert effective_n_jobs(3) == 3 - p = Parallel() - assert p.n_jobs == 3 - if backend_name == 'multiprocessing': - assert type(active_backend) is MultiprocessingBackend - assert type(p._backend) is MultiprocessingBackend - elif backend_name == 'loky': - assert type(active_backend) is LokyBackend - assert type(p._backend) is LokyBackend - elif backend_name == 'threading': - assert type(active_backend) is ThreadingBackend - assert type(p._backend) is ThreadingBackend - elif backend_name.startswith('test_'): - assert type(active_backend) is FakeParallelBackend - assert type(p._backend) is FakeParallelBackend - - -all_backends_for_context_manager = PARALLEL_BACKENDS[:] -all_backends_for_context_manager.extend( - ['test_backend_%d' % i for i in range(3)] -) - - -@with_multiprocessing -@parametrize('backend', all_backends_for_context_manager) -@parametrize('context', [parallel_backend, parallel_config]) -def test_backend_context_manager(monkeypatch, backend, context): - if backend not in BACKENDS: - monkeypatch.setitem(BACKENDS, backend, FakeParallelBackend) - - assert _active_backend_type() == DefaultBackend - # check that this possible to switch parallel backends sequentially - check_backend_context_manager(context, backend) - - # The default backend is restored - assert _active_backend_type() == DefaultBackend - - # Check that context manager switching is thread safe: - Parallel(n_jobs=2, backend='threading')( - delayed(check_backend_context_manager)(context, b) - for b in all_backends_for_context_manager if not b) - - # The default backend is again restored - assert _active_backend_type() == DefaultBackend - - -class ParameterizedParallelBackend(SequentialBackend): - """Pretends to run conncurrently while running sequentially.""" - - def __init__(self, param=None): - if param is None: - raise ValueError('param should not be None') - self.param = param - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_parameterized_backend_context_manager(monkeypatch, context): - monkeypatch.setitem(BACKENDS, 'param_backend', - ParameterizedParallelBackend) - assert _active_backend_type() == DefaultBackend - - with context('param_backend', param=42, n_jobs=3): - active_backend, active_n_jobs = parallel.get_active_backend() - assert type(active_backend) is ParameterizedParallelBackend - assert active_backend.param == 42 - assert active_n_jobs == 3 - p = Parallel() - assert p.n_jobs == 3 - assert p._backend is active_backend - results = p(delayed(sqrt)(i) for i in range(5)) - assert results == [sqrt(i) for i in range(5)] - - # The default backend is again restored - assert _active_backend_type() == DefaultBackend - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_directly_parameterized_backend_context_manager(context): - assert _active_backend_type() == DefaultBackend - - # Check that it's possible to pass a backend instance directly, - # without registration - with context(ParameterizedParallelBackend(param=43), n_jobs=5): - active_backend, active_n_jobs = parallel.get_active_backend() - assert type(active_backend) is ParameterizedParallelBackend - assert active_backend.param == 43 - assert active_n_jobs == 5 - p = Parallel() - assert p.n_jobs == 5 - assert p._backend is active_backend - results = p(delayed(sqrt)(i) for i in range(5)) - assert results == [sqrt(i) for i in range(5)] - - # The default backend is again restored - assert _active_backend_type() == DefaultBackend - - -def sleep_and_return_pid(): - sleep(.1) - return os.getpid() - - -def get_nested_pids(): - assert _active_backend_type() == ThreadingBackend - # Assert that the nested backend does not change the default number of - # jobs used in Parallel - assert Parallel()._effective_n_jobs() == 1 - - # Assert that the tasks are running only on one process - return Parallel(n_jobs=2)(delayed(sleep_and_return_pid)() - for _ in range(2)) - - -class MyBackend(joblib._parallel_backends.LokyBackend): - """Backend to test backward compatibility with older backends""" - def get_nested_backend(self, ): - # Older backends only return a backend, without n_jobs indications. - return super(MyBackend, self).get_nested_backend()[0] - - -register_parallel_backend('back_compat_backend', MyBackend) - - -@with_multiprocessing -@parametrize('backend', ['threading', 'loky', 'multiprocessing', - 'back_compat_backend']) -@parametrize("context", [parallel_config, parallel_backend]) -def test_nested_backend_context_manager(context, backend): - # Check that by default, nested parallel calls will always use the - # ThreadingBackend - - with context(backend): - pid_groups = Parallel(n_jobs=2)( - delayed(get_nested_pids)() - for _ in range(10) - ) - for pid_group in pid_groups: - assert len(set(pid_group)) == 1 - - -@with_multiprocessing -@parametrize('n_jobs', [2, -1, None]) -@parametrize('backend', PARALLEL_BACKENDS) -@parametrize("context", [parallel_config, parallel_backend]) -def test_nested_backend_in_sequential(backend, n_jobs, context): - # Check that by default, nested parallel calls will always use the - # ThreadingBackend - - def check_nested_backend(expected_backend_type, expected_n_job): - # Assert that the sequential backend at top level, does not change the - # backend for nested calls. - assert _active_backend_type() == BACKENDS[expected_backend_type] - - # Assert that the nested backend in SequentialBackend does not change - # the default number of jobs used in Parallel - expected_n_job = effective_n_jobs(expected_n_job) - assert Parallel()._effective_n_jobs() == expected_n_job - - Parallel(n_jobs=1)( - delayed(check_nested_backend)(DEFAULT_BACKEND, 1) - for _ in range(10) - ) - - with context(backend, n_jobs=n_jobs): - Parallel(n_jobs=1)( - delayed(check_nested_backend)(backend, n_jobs) - for _ in range(10) - ) - - -def check_nesting_level(context, inner_backend, expected_level): - with context(inner_backend) as ctx: - if context is parallel_config: - backend = ctx["backend"] - if context is parallel_backend: - backend = ctx[0] - assert backend.nesting_level == expected_level - - -@with_multiprocessing -@parametrize('outer_backend', PARALLEL_BACKENDS) -@parametrize('inner_backend', PARALLEL_BACKENDS) -@parametrize("context", [parallel_config, parallel_backend]) -def test_backend_nesting_level(context, outer_backend, inner_backend): - # Check that the nesting level for the backend is correctly set - check_nesting_level(context, outer_backend, 0) - - Parallel(n_jobs=2, backend=outer_backend)( - delayed(check_nesting_level)(context, inner_backend, 1) - for _ in range(10) - ) - - with context(inner_backend, n_jobs=2): - Parallel()(delayed(check_nesting_level)(context, inner_backend, 1) - for _ in range(10)) - - -@with_multiprocessing -@parametrize("context", [parallel_config, parallel_backend]) -@parametrize('with_retrieve_callback', [True, False]) -def test_retrieval_context(context, with_retrieve_callback): - import contextlib - - class MyBackend(ThreadingBackend): - i = 0 - supports_retrieve_callback = with_retrieve_callback - - @contextlib.contextmanager - def retrieval_context(self): - self.i += 1 - yield - - register_parallel_backend("retrieval", MyBackend) - - def nested_call(n): - return Parallel(n_jobs=2)(delayed(id)(i) for i in range(n)) - - with context("retrieval") as ctx: - Parallel(n_jobs=2)( - delayed(nested_call)(i) - for i in range(5) - ) - if context is parallel_config: - assert ctx["backend"].i == 1 - if context is parallel_backend: - assert ctx[0].i == 1 - - -############################################################################### -# Test helpers - -@parametrize('batch_size', [0, -1, 1.42]) -def test_invalid_batch_size(batch_size): - with raises(ValueError): - Parallel(batch_size=batch_size) - - -@parametrize('n_tasks, n_jobs, pre_dispatch, batch_size', - [(2, 2, 'all', 'auto'), - (2, 2, 'n_jobs', 'auto'), - (10, 2, 'n_jobs', 'auto'), - (517, 2, 'n_jobs', 'auto'), - (10, 2, 'n_jobs', 'auto'), - (10, 4, 'n_jobs', 'auto'), - (200, 12, 'n_jobs', 'auto'), - (25, 12, '2 * n_jobs', 1), - (250, 12, 'all', 1), - (250, 12, '2 * n_jobs', 7), - (200, 12, '2 * n_jobs', 'auto')]) -def test_dispatch_race_condition(n_tasks, n_jobs, pre_dispatch, batch_size): - # Check that using (async-)dispatch does not yield a race condition on the - # iterable generator that is not thread-safe natively. - # This is a non-regression test for the "Pool seems closed" class of error - params = {'n_jobs': n_jobs, 'pre_dispatch': pre_dispatch, - 'batch_size': batch_size} - expected = [square(i) for i in range(n_tasks)] - results = Parallel(**params)(delayed(square)(i) for i in range(n_tasks)) - assert results == expected - - -@with_multiprocessing -def test_default_mp_context(): - mp_start_method = mp.get_start_method() - p = Parallel(n_jobs=2, backend='multiprocessing') - context = p._backend_args.get('context') - start_method = context.get_start_method() - assert start_method == mp_start_method - - -@with_numpy -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_no_blas_crash_or_freeze_with_subprocesses(backend): - if backend == 'multiprocessing': - # Use the spawn backend that is both robust and available on all - # platforms - backend = mp.get_context('spawn') - - # Check that on recent Python version, the 'spawn' start method can make - # it possible to use multiprocessing in conjunction of any BLAS - # implementation that happens to be used by numpy with causing a freeze or - # a crash - rng = np.random.RandomState(42) - - # call BLAS DGEMM to force the initialization of the internal thread-pool - # in the main process - a = rng.randn(1000, 1000) - np.dot(a, a.T) - - # check that the internal BLAS thread-pool is not in an inconsistent state - # in the worker processes managed by multiprocessing - Parallel(n_jobs=2, backend=backend)( - delayed(np.dot)(a, a.T) for i in range(2)) - - -UNPICKLABLE_CALLABLE_SCRIPT_TEMPLATE_NO_MAIN = """\ -from joblib import Parallel, delayed - -def square(x): - return x ** 2 - -backend = "{}" -if backend == "spawn": - from multiprocessing import get_context - backend = get_context(backend) - -print(Parallel(n_jobs=2, backend=backend)( - delayed(square)(i) for i in range(5))) -""" - - -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_parallel_with_interactively_defined_functions(backend): - # When using the "-c" flag, interactive functions defined in __main__ - # should work with any backend. - if backend == "multiprocessing" and mp.get_start_method() != "fork": - pytest.skip("Require fork start method to use interactively defined " - "functions with multiprocessing.") - code = UNPICKLABLE_CALLABLE_SCRIPT_TEMPLATE_NO_MAIN.format(backend) - check_subprocess_call( - [sys.executable, '-c', code], timeout=10, - stdout_regex=r'\[0, 1, 4, 9, 16\]') - - -UNPICKLABLE_CALLABLE_SCRIPT_TEMPLATE_MAIN = """\ -import sys -# Make sure that joblib is importable in the subprocess launching this -# script. This is needed in case we run the tests from the joblib root -# folder without having installed joblib -sys.path.insert(0, {joblib_root_folder!r}) - -from joblib import Parallel, delayed - -def run(f, x): - return f(x) - -{define_func} - -if __name__ == "__main__": - backend = "{backend}" - if backend == "spawn": - from multiprocessing import get_context - backend = get_context(backend) - - callable_position = "{callable_position}" - if callable_position == "delayed": - print(Parallel(n_jobs=2, backend=backend)( - delayed(square)(i) for i in range(5))) - elif callable_position == "args": - print(Parallel(n_jobs=2, backend=backend)( - delayed(run)(square, i) for i in range(5))) - else: - print(Parallel(n_jobs=2, backend=backend)( - delayed(run)(f=square, x=i) for i in range(5))) -""" - -SQUARE_MAIN = """\ -def square(x): - return x ** 2 -""" -SQUARE_LOCAL = """\ -def gen_square(): - def square(x): - return x ** 2 - return square -square = gen_square() -""" -SQUARE_LAMBDA = """\ -square = lambda x: x ** 2 -""" - - -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS + ([] if mp is None else ['spawn'])) -@parametrize('define_func', [SQUARE_MAIN, SQUARE_LOCAL, SQUARE_LAMBDA]) -@parametrize('callable_position', ['delayed', 'args', 'kwargs']) -def test_parallel_with_unpicklable_functions_in_args( - backend, define_func, callable_position, tmpdir): - if backend in ['multiprocessing', 'spawn'] and ( - define_func != SQUARE_MAIN or sys.platform == "win32"): - pytest.skip("Not picklable with pickle") - code = UNPICKLABLE_CALLABLE_SCRIPT_TEMPLATE_MAIN.format( - define_func=define_func, backend=backend, - callable_position=callable_position, - joblib_root_folder=os.path.dirname(os.path.dirname(joblib.__file__))) - code_file = tmpdir.join("unpicklable_func_script.py") - code_file.write(code) - check_subprocess_call( - [sys.executable, code_file.strpath], timeout=10, - stdout_regex=r'\[0, 1, 4, 9, 16\]') - - -INTERACTIVE_DEFINED_FUNCTION_AND_CLASS_SCRIPT_CONTENT = """\ -import sys -import faulthandler -# Make sure that joblib is importable in the subprocess launching this -# script. This is needed in case we run the tests from the joblib root -# folder without having installed joblib -sys.path.insert(0, {joblib_root_folder!r}) - -from joblib import Parallel, delayed -from functools import partial - -class MyClass: - '''Class defined in the __main__ namespace''' - def __init__(self, value): - self.value = value - - -def square(x, ignored=None, ignored2=None): - '''Function defined in the __main__ namespace''' - return x.value ** 2 - - -square2 = partial(square, ignored2='something') - -# Here, we do not need the `if __name__ == "__main__":` safeguard when -# using the default `loky` backend (even on Windows). - -# To make debugging easier -faulthandler.dump_traceback_later(30, exit=True) - -# The following baroque function call is meant to check that joblib -# introspection rightfully uses cloudpickle instead of the (faster) pickle -# module of the standard library when necessary. In particular cloudpickle is -# necessary for functions and instances of classes interactively defined in the -# __main__ module. - -print(Parallel(backend="loky", n_jobs=2)( - delayed(square2)(MyClass(i), ignored=[dict(a=MyClass(1))]) - for i in range(5) -)) -""".format(joblib_root_folder=os.path.dirname( - os.path.dirname(joblib.__file__))) - - -@with_multiprocessing -def test_parallel_with_interactively_defined_functions_loky(tmpdir): - # loky accepts interactive functions defined in __main__ and does not - # require if __name__ == '__main__' even when the __main__ module is - # defined by the result of the execution of a filesystem script. - script = tmpdir.join('joblib_interactively_defined_function.py') - script.write(INTERACTIVE_DEFINED_FUNCTION_AND_CLASS_SCRIPT_CONTENT) - check_subprocess_call( - [sys.executable, script.strpath], - stdout_regex=r'\[0, 1, 4, 9, 16\]', - timeout=None, # rely on faulthandler to kill the process - ) - - -INTERACTIVELY_DEFINED_SUBCLASS_WITH_METHOD_SCRIPT_CONTENT = """\ -import sys -# Make sure that joblib is importable in the subprocess launching this -# script. This is needed in case we run the tests from the joblib root -# folder without having installed joblib -sys.path.insert(0, {joblib_root_folder!r}) - -from joblib import Parallel, delayed, hash -import multiprocessing as mp -mp.util.log_to_stderr(5) - -class MyList(list): - '''MyList is interactively defined by MyList.append is a built-in''' - def __hash__(self): - # XXX: workaround limitation in cloudpickle - return hash(self).__hash__() - -l = MyList() - -print(Parallel(backend="loky", n_jobs=2)( - delayed(l.append)(i) for i in range(3) -)) -""".format(joblib_root_folder=os.path.dirname( - os.path.dirname(joblib.__file__))) - - -@with_multiprocessing -def test_parallel_with_interactively_defined_bound_method_loky(tmpdir): - script = tmpdir.join('joblib_interactive_bound_method_script.py') - script.write(INTERACTIVELY_DEFINED_SUBCLASS_WITH_METHOD_SCRIPT_CONTENT) - check_subprocess_call([sys.executable, script.strpath], - stdout_regex=r'\[None, None, None\]', - stderr_regex=r'LokyProcess', - timeout=15) - - -def test_parallel_with_exhausted_iterator(): - exhausted_iterator = iter([]) - assert Parallel(n_jobs=2)(exhausted_iterator) == [] - - -def _cleanup_worker(): - """Helper function to force gc in each worker.""" - force_gc_pypy() - time.sleep(.1) - - -def check_memmap(a): - if not isinstance(a, np.memmap): - raise TypeError('Expected np.memmap instance, got %r', - type(a)) - return a.copy() # return a regular array instead of a memmap - - -@with_numpy -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_auto_memmap_on_arrays_from_generator(backend): - # Non-regression test for a problem with a bad interaction between the - # GC collecting arrays recently created during iteration inside the - # parallel dispatch loop and the auto-memmap feature of Parallel. - # See: https://github.com/joblib/joblib/pull/294 - def generate_arrays(n): - for i in range(n): - yield np.ones(10, dtype=np.float32) * i - # Use max_nbytes=1 to force the use of memory-mapping even for small - # arrays - results = Parallel(n_jobs=2, max_nbytes=1, backend=backend)( - delayed(check_memmap)(a) for a in generate_arrays(100)) - for result, expected in zip(results, generate_arrays(len(results))): - np.testing.assert_array_equal(expected, result) - - # Second call to force loky to adapt the executor by growing the number - # of worker processes. This is a non-regression test for: - # https://github.com/joblib/joblib/issues/629. - results = Parallel(n_jobs=4, max_nbytes=1, backend=backend)( - delayed(check_memmap)(a) for a in generate_arrays(100)) - for result, expected in zip(results, generate_arrays(len(results))): - np.testing.assert_array_equal(expected, result) - - -def identity(arg): - return arg - - -@with_numpy -@with_multiprocessing -def test_memmap_with_big_offset(tmpdir): - fname = tmpdir.join('test.mmap').strpath - size = mmap.ALLOCATIONGRANULARITY - obj = [np.zeros(size, dtype='uint8'), np.ones(size, dtype='uint8')] - dump(obj, fname) - memmap = load(fname, mmap_mode='r') - result, = Parallel(n_jobs=2)(delayed(identity)(memmap) for _ in [0]) - assert isinstance(memmap[1], np.memmap) - assert memmap[1].offset > size - np.testing.assert_array_equal(obj, result) - - -def test_warning_about_timeout_not_supported_by_backend(): - with warnings.catch_warnings(record=True) as warninfo: - Parallel(n_jobs=1, timeout=1)(delayed(square)(i) for i in range(50)) - assert len(warninfo) == 1 - w = warninfo[0] - assert isinstance(w.message, UserWarning) - assert str(w.message) == ( - "The backend class 'SequentialBackend' does not support timeout. " - "You have set 'timeout=1' in Parallel but the 'timeout' parameter " - "will not be used.") - - -def set_list_value(input_list, index, value): - input_list[index] = value - return value - - -@pytest.mark.parametrize('n_jobs', [1, 2, 4]) -def test_parallel_return_order_with_return_as_generator_parameter(n_jobs): - # This test inserts values in a list in some expected order - # in sequential computing, and then checks that this order has been - # respected by Parallel output generator. - input_list = [0] * 5 - result = Parallel(n_jobs=n_jobs, return_as="generator", - backend='threading')( - delayed(set_list_value)(input_list, i, i) for i in range(5)) - - # Ensure that all the tasks are completed before checking the result - result = list(result) - - assert all(v == r for v, r in zip(input_list, result)) - - -def _sqrt_with_delay(e, delay): - if delay: - sleep(30) - return sqrt(e) - - -def _test_parallel_unordered_generator_returns_fastest_first(backend, n_jobs): - # This test submits 10 tasks, but the second task is super slow. This test - # checks that the 9 other tasks return before the slow task is done, when - # `return_as` parameter is set to `'generator_unordered'` - result = Parallel(n_jobs=n_jobs, return_as="generator_unordered", - backend=backend)( - delayed(_sqrt_with_delay)(i**2, (i == 1)) for i in range(10)) - - quickly_returned = sorted(next(result) for _ in range(9)) - - expected_quickly_returned = [0] + list(range(2, 10)) - - assert all( - v == r for v, r in zip(expected_quickly_returned, quickly_returned) - ) - - del result - force_gc_pypy() - - -@pytest.mark.parametrize('n_jobs', [2, 4]) -# NB: for this test to work, the backend must be allowed to process tasks -# concurrently, so at least two jobs with a non-sequential backend are -# mandatory. -@with_multiprocessing -@parametrize('backend', set(RETURN_GENERATOR_BACKENDS) - {"sequential"}) -def test_parallel_unordered_generator_returns_fastest_first(backend, n_jobs): - _test_parallel_unordered_generator_returns_fastest_first(backend, n_jobs) - - -@pytest.mark.parametrize('n_jobs', [2, -1]) -@parametrize("context", [parallel_config, parallel_backend]) -@skipif(distributed is None, reason='This test requires dask') -def test_parallel_unordered_generator_returns_fastest_first_with_dask( - n_jobs, context -): - with distributed.Client( - n_workers=2, threads_per_worker=2 - ), context("dask"): - _test_parallel_unordered_generator_returns_fastest_first(None, n_jobs) - - -@parametrize('backend', ALL_VALID_BACKENDS) -@parametrize('n_jobs', [1, 2, -2, -1]) -def test_abort_backend(n_jobs, backend): - delays = ["a"] + [10] * 100 - with raises(TypeError): - t_start = time.time() - Parallel(n_jobs=n_jobs, backend=backend)( - delayed(time.sleep)(i) for i in delays) - dt = time.time() - t_start - assert dt < 20 - - -def get_large_object(arg): - result = np.ones(int(5 * 1e5), dtype=bool) - result[0] = False - return result - - -def _test_deadlock_with_generator(backend, return_as, n_jobs): - # Non-regression test for a race condition in the backends when the pickler - # is delayed by a large object. - with Parallel(n_jobs=n_jobs, backend=backend, - return_as=return_as) as parallel: - result = parallel(delayed(get_large_object)(i) for i in range(10)) - next(result) - next(result) - del result - # The gc in pypy can be delayed. Force it to make sure this test does - # not cause timeout on the CI. - force_gc_pypy() - - -@with_numpy -@parametrize('backend', RETURN_GENERATOR_BACKENDS) -@parametrize('return_as', ["generator", "generator_unordered"]) -@parametrize('n_jobs', [1, 2, -2, -1]) -def test_deadlock_with_generator(backend, return_as, n_jobs): - _test_deadlock_with_generator(backend, return_as, n_jobs) - - -@with_numpy -@pytest.mark.parametrize('n_jobs', [2, -1]) -@parametrize('return_as', ["generator", "generator_unordered"]) -@parametrize("context", [parallel_config, parallel_backend]) -@skipif(distributed is None, reason='This test requires dask') -def test_deadlock_with_generator_and_dask(context, return_as, n_jobs): - with distributed.Client( - n_workers=2, threads_per_worker=2 - ), context("dask"): - _test_deadlock_with_generator(None, return_as, n_jobs) - - -@parametrize('backend', RETURN_GENERATOR_BACKENDS) -@parametrize('return_as', ["generator", "generator_unordered"]) -@parametrize('n_jobs', [1, 2, -2, -1]) -def test_multiple_generator_call(backend, return_as, n_jobs): - # Non-regression test that ensures the dispatch of the tasks starts - # immediately when Parallel.__call__ is called. This test relies on the - # assumption that only one generator can be submitted at a time. - with raises(RuntimeError, - match="This Parallel instance is already running"): - parallel = Parallel(n_jobs, backend=backend, return_as=return_as) - g = parallel(delayed(sleep)(1) for _ in range(10)) # noqa: F841 - t_start = time.time() - gen2 = parallel(delayed(id)(i) for i in range(100)) # noqa: F841 - - # Make sure that the error is raised quickly - assert time.time() - t_start < 2, ( - "The error should be raised immediatly when submitting a new task " - "but it took more than 2s." - ) - - del g - # The gc in pypy can be delayed. Force it to make sure this test does not - # cause timeout on the CI. - force_gc_pypy() - - -@parametrize('backend', RETURN_GENERATOR_BACKENDS) -@parametrize('return_as', ["generator", "generator_unordered"]) -@parametrize('n_jobs', [1, 2, -2, -1]) -def test_multiple_generator_call_managed(backend, return_as, n_jobs): - # Non-regression test that ensures the dispatch of the tasks starts - # immediately when Parallel.__call__ is called. This test relies on the - # assumption that only one generator can be submitted at a time. - with Parallel(n_jobs, backend=backend, - return_as=return_as) as parallel: - g = parallel(delayed(sleep)(10) for _ in range(10)) # noqa: F841 - t_start = time.time() - with raises(RuntimeError, - match="This Parallel instance is already running"): - g2 = parallel(delayed(id)(i) for i in range(100)) # noqa: F841 - - # Make sure that the error is raised quickly - assert time.time() - t_start < 2, ( - "The error should be raised immediatly when submitting a new task " - "but it took more than 2s." - ) - - # The gc in pypy can be delayed. Force it to make sure this test does not - # cause timeout on the CI. - del g - force_gc_pypy() - - -@parametrize('backend', RETURN_GENERATOR_BACKENDS) -@parametrize('return_as_1', ["generator", "generator_unordered"]) -@parametrize('return_as_2', ["generator", "generator_unordered"]) -@parametrize('n_jobs', [1, 2, -2, -1]) -def test_multiple_generator_call_separated( - backend, return_as_1, return_as_2, n_jobs -): - # Check that for separated Parallel, both tasks are correctly returned. - g = Parallel(n_jobs, backend=backend, return_as=return_as_1)( - delayed(sqrt)(i ** 2) for i in range(10) - ) - g2 = Parallel(n_jobs, backend=backend, return_as=return_as_2)( - delayed(sqrt)(i ** 2) for i in range(10, 20) - ) - - if return_as_1 == "generator_unordered": - g = sorted(g) - - if return_as_2 == "generator_unordered": - g2 = sorted(g2) - - assert all(res == i for res, i in zip(g, range(10))) - assert all(res == i for res, i in zip(g2, range(10, 20))) - - -@parametrize('backend, error', [ - ('loky', True), - ('threading', False), - ('sequential', False), -]) -@parametrize('return_as_1', ["generator", "generator_unordered"]) -@parametrize('return_as_2', ["generator", "generator_unordered"]) -def test_multiple_generator_call_separated_gc( - backend, return_as_1, return_as_2, error -): - - if (backend == 'loky') and (mp is None): - pytest.skip("Requires multiprocessing") - - # Check that in loky, only one call can be run at a time with - # a single executor. - parallel = Parallel(2, backend=backend, return_as=return_as_1) - g = parallel(delayed(sleep)(10) for i in range(10)) - g_wr = weakref.finalize(g, lambda: print("Generator collected")) - ctx = ( - raises(RuntimeError, match="The executor underlying Parallel") - if error else nullcontext() - ) - with ctx: - # For loky, this call will raise an error as the gc of the previous - # generator will shutdown the shared executor. - # For the other backends, as the worker pools are not shared between - # the two calls, this should proceed correctly. - t_start = time.time() - g = Parallel(2, backend=backend, return_as=return_as_2)( - delayed(sqrt)(i ** 2) for i in range(10, 20) - ) - - # The gc in pypy can be delayed. Force it to test the behavior when it - # will eventually be collected. - force_gc_pypy() - - if return_as_2 == "generator_unordered": - g = sorted(g) - - assert all(res == i for res, i in zip(g, range(10, 20))) - - assert time.time() - t_start < 5 - - # Make sure that the computation are stopped for the gc'ed generator - retry = 0 - while g_wr.alive and retry < 3: - retry += 1 - time.sleep(.5) - assert time.time() - t_start < 5 - - if parallel._effective_n_jobs() != 1: - # check that the first parallel object is aborting (the final _aborted - # state might be delayed). - assert parallel._aborting - - -@with_numpy -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_memmapping_leaks(backend, tmpdir): - # Non-regression test for memmapping backends. Ensure that the data - # does not stay too long in memory - tmpdir = tmpdir.strpath - - # Use max_nbytes=1 to force the use of memory-mapping even for small - # arrays - with Parallel(n_jobs=2, max_nbytes=1, backend=backend, - temp_folder=tmpdir) as p: - p(delayed(check_memmap)(a) for a in [np.random.random(10)] * 2) - - # The memmap folder should not be clean in the context scope - assert len(os.listdir(tmpdir)) > 0 - - # Cleaning of the memmap folder is triggered by the garbage - # collection. With pypy the garbage collection has been observed to be - # delayed, sometimes up until the shutdown of the interpreter. This - # cleanup job executed in the worker ensures that it's triggered - # immediately. - p(delayed(_cleanup_worker)() for _ in range(2)) - - # Make sure that the shared memory is cleaned at the end when we exit - # the context - for _ in range(100): - if not os.listdir(tmpdir): - break - sleep(.1) - else: - raise AssertionError('temporary directory of Parallel was not removed') - - # Make sure that the shared memory is cleaned at the end of a call - p = Parallel(n_jobs=2, max_nbytes=1, backend=backend) - p(delayed(check_memmap)(a) for a in [np.random.random(10)] * 2) - p(delayed(_cleanup_worker)() for _ in range(2)) - - for _ in range(100): - if not os.listdir(tmpdir): - break - sleep(.1) - else: - raise AssertionError('temporary directory of Parallel was not removed') - - -@parametrize('backend', - ([None, 'threading'] if mp is None - else [None, 'loky', 'threading']) - ) -def test_lambda_expression(backend): - # cloudpickle is used to pickle delayed callables - results = Parallel(n_jobs=2, backend=backend)( - delayed(lambda x: x ** 2)(i) for i in range(10)) - assert results == [i ** 2 for i in range(10)] - - -@with_multiprocessing -@parametrize('backend', PROCESS_BACKENDS) -def test_backend_batch_statistics_reset(backend): - """Test that a parallel backend correctly resets its batch statistics.""" - n_jobs = 2 - n_inputs = 500 - task_time = 2. / n_inputs - - p = Parallel(verbose=10, n_jobs=n_jobs, backend=backend) - p(delayed(time.sleep)(task_time) for i in range(n_inputs)) - assert (p._backend._effective_batch_size == - p._backend._DEFAULT_EFFECTIVE_BATCH_SIZE) - assert (p._backend._smoothed_batch_duration == - p._backend._DEFAULT_SMOOTHED_BATCH_DURATION) - - p(delayed(time.sleep)(task_time) for i in range(n_inputs)) - assert (p._backend._effective_batch_size == - p._backend._DEFAULT_EFFECTIVE_BATCH_SIZE) - assert (p._backend._smoothed_batch_duration == - p._backend._DEFAULT_SMOOTHED_BATCH_DURATION) - - -@with_multiprocessing -@parametrize("context", [parallel_config, parallel_backend]) -def test_backend_hinting_and_constraints(context): - for n_jobs in [1, 2, -1]: - assert type(Parallel(n_jobs=n_jobs)._backend) == DefaultBackend - - p = Parallel(n_jobs=n_jobs, prefer='threads') - assert type(p._backend) is ThreadingBackend - - p = Parallel(n_jobs=n_jobs, prefer='processes') - assert type(p._backend) is DefaultBackend - - p = Parallel(n_jobs=n_jobs, require='sharedmem') - assert type(p._backend) is ThreadingBackend - - # Explicit backend selection can override backend hinting although it - # is useless to pass a hint when selecting a backend. - p = Parallel(n_jobs=2, backend='loky', prefer='threads') - assert type(p._backend) is LokyBackend - - with context('loky', n_jobs=2): - # Explicit backend selection by the user with the context manager - # should be respected when combined with backend hints only. - p = Parallel(prefer='threads') - assert type(p._backend) is LokyBackend - assert p.n_jobs == 2 - - with context('loky', n_jobs=2): - # Locally hard-coded n_jobs value is respected. - p = Parallel(n_jobs=3, prefer='threads') - assert type(p._backend) is LokyBackend - assert p.n_jobs == 3 - - with context('loky', n_jobs=2): - # Explicit backend selection by the user with the context manager - # should be ignored when the Parallel call has hard constraints. - # In this case, the default backend that supports shared mem is - # used an the default number of processes is used. - p = Parallel(require='sharedmem') - assert type(p._backend) is ThreadingBackend - assert p.n_jobs == 1 - - with context('loky', n_jobs=2): - p = Parallel(n_jobs=3, require='sharedmem') - assert type(p._backend) is ThreadingBackend - assert p.n_jobs == 3 - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_backend_hinting_and_constraints_with_custom_backends( - capsys, context -): - # Custom backends can declare that they use threads and have shared memory - # semantics: - class MyCustomThreadingBackend(ParallelBackendBase): - supports_sharedmem = True - use_threads = True - - def apply_async(self): - pass - - def effective_n_jobs(self, n_jobs): - return n_jobs - - with context(MyCustomThreadingBackend()): - p = Parallel(n_jobs=2, prefer='processes') # ignored - assert type(p._backend) is MyCustomThreadingBackend - - p = Parallel(n_jobs=2, require='sharedmem') - assert type(p._backend) is MyCustomThreadingBackend - - class MyCustomProcessingBackend(ParallelBackendBase): - supports_sharedmem = False - use_threads = False - - def apply_async(self): - pass - - def effective_n_jobs(self, n_jobs): - return n_jobs - - with context(MyCustomProcessingBackend()): - p = Parallel(n_jobs=2, prefer='processes') - assert type(p._backend) is MyCustomProcessingBackend - - out, err = capsys.readouterr() - assert out == "" - assert err == "" - - p = Parallel(n_jobs=2, require='sharedmem', verbose=10) - assert type(p._backend) is ThreadingBackend - - out, err = capsys.readouterr() - expected = ("Using ThreadingBackend as joblib backend " - "instead of MyCustomProcessingBackend as the latter " - "does not provide shared memory semantics.") - assert out.strip() == expected - assert err == "" - - with raises(ValueError): - Parallel(backend=MyCustomProcessingBackend(), require='sharedmem') - - -def test_invalid_backend_hinting_and_constraints(): - with raises(ValueError): - Parallel(prefer='invalid') - - with raises(ValueError): - Parallel(require='invalid') - - with raises(ValueError): - # It is inconsistent to prefer process-based parallelism while - # requiring shared memory semantics. - Parallel(prefer='processes', require='sharedmem') - - if mp is not None: - # It is inconsistent to ask explicitly for a process-based - # parallelism while requiring shared memory semantics. - with raises(ValueError): - Parallel(backend='loky', require='sharedmem') - with raises(ValueError): - Parallel(backend='multiprocessing', require='sharedmem') - - -def _recursive_backend_info(limit=3, **kwargs): - """Perform nested parallel calls and introspect the backend on the way""" - - with Parallel(n_jobs=2) as p: - this_level = [(type(p._backend).__name__, p._backend.nesting_level)] - if limit == 0: - return this_level - results = p(delayed(_recursive_backend_info)(limit=limit - 1, **kwargs) - for i in range(1)) - return this_level + results[0] - - -@with_multiprocessing -@parametrize('backend', ['loky', 'threading']) -@parametrize("context", [parallel_config, parallel_backend]) -def test_nested_parallelism_limit(context, backend): - with context(backend, n_jobs=2): - backend_types_and_levels = _recursive_backend_info() - - if cpu_count() == 1: - second_level_backend_type = 'SequentialBackend' - max_level = 1 - else: - second_level_backend_type = 'ThreadingBackend' - max_level = 2 - - top_level_backend_type = backend.title() + 'Backend' - expected_types_and_levels = [ - (top_level_backend_type, 0), - (second_level_backend_type, 1), - ('SequentialBackend', max_level), - ('SequentialBackend', max_level) - ] - assert backend_types_and_levels == expected_types_and_levels - - -@with_numpy -@parametrize("context", [parallel_config, parallel_backend]) -@skipif(distributed is None, reason='This test requires dask') -def test_nested_parallelism_with_dask(context): - with distributed.Client(n_workers=2, threads_per_worker=2): - # 10 MB of data as argument to trigger implicit scattering - data = np.ones(int(1e7), dtype=np.uint8) - for i in range(2): - with context('dask'): - backend_types_and_levels = _recursive_backend_info(data=data) - assert len(backend_types_and_levels) == 4 - assert all(name == 'DaskDistributedBackend' - for name, _ in backend_types_and_levels) - - # No argument - with context('dask'): - backend_types_and_levels = _recursive_backend_info() - assert len(backend_types_and_levels) == 4 - assert all(name == 'DaskDistributedBackend' - for name, _ in backend_types_and_levels) - - -def _recursive_parallel(nesting_limit=None): - """A horrible function that does recursive parallel calls""" - return Parallel()(delayed(_recursive_parallel)() for i in range(2)) - - -@pytest.mark.no_cover -@parametrize("context", [parallel_config, parallel_backend]) -@parametrize( - 'backend', (['threading'] if mp is None else ['loky', 'threading']) -) -def test_thread_bomb_mitigation(context, backend): - # Test that recursive parallelism raises a recursion rather than - # saturating the operating system resources by creating a unbounded number - # of threads. - with context(backend, n_jobs=2): - with raises(BaseException) as excinfo: - _recursive_parallel() - exc = excinfo.value - if backend == "loky": - # Local import because loky may not be importable for lack of - # multiprocessing - from joblib.externals.loky.process_executor import TerminatedWorkerError # noqa - if isinstance(exc, (TerminatedWorkerError, PicklingError)): - # The recursion exception can itself cause an error when - # pickling it to be send back to the parent process. In this - # case the worker crashes but the original traceback is still - # printed on stderr. This could be improved but does not seem - # simple to do and this is not critical for users (as long - # as there is no process or thread bomb happening). - pytest.xfail("Loky worker crash when serializing RecursionError") - - assert isinstance(exc, RecursionError) - - -def _run_parallel_sum(): - env_vars = {} - for var in ['OMP_NUM_THREADS', 'OPENBLAS_NUM_THREADS', 'MKL_NUM_THREADS', - 'VECLIB_MAXIMUM_THREADS', 'NUMEXPR_NUM_THREADS', - 'NUMBA_NUM_THREADS', 'ENABLE_IPC']: - env_vars[var] = os.environ.get(var) - return env_vars, parallel_sum(100) - - -@parametrize("backend", ([None, 'loky'] if mp is not None else [None])) -@skipif(parallel_sum is None, reason="Need OpenMP helper compiled") -def test_parallel_thread_limit(backend): - results = Parallel(n_jobs=2, backend=backend)( - delayed(_run_parallel_sum)() for _ in range(2) - ) - expected_num_threads = max(cpu_count() // 2, 1) - for worker_env_vars, omp_num_threads in results: - assert omp_num_threads == expected_num_threads - for name, value in worker_env_vars.items(): - if name.endswith("_THREADS"): - assert value == str(expected_num_threads) - else: - assert name == "ENABLE_IPC" - assert value == "1" - - -@parametrize("context", [parallel_config, parallel_backend]) -@skipif(distributed is not None, reason='This test requires dask') -def test_dask_backend_when_dask_not_installed(context): - with raises(ValueError, match='Please install dask'): - context('dask') - - -@parametrize("context", [parallel_config, parallel_backend]) -def test_zero_worker_backend(context): - # joblib.Parallel should reject with an explicit error message parallel - # backends that have no worker. - class ZeroWorkerBackend(ThreadingBackend): - def configure(self, *args, **kwargs): - return 0 - - def apply_async(self, func, callback=None): # pragma: no cover - raise TimeoutError("No worker available") - - def effective_n_jobs(self, n_jobs): # pragma: no cover - return 0 - - expected_msg = "ZeroWorkerBackend has no active worker" - with context(ZeroWorkerBackend()): - with pytest.raises(RuntimeError, match=expected_msg): - Parallel(n_jobs=2)(delayed(id)(i) for i in range(2)) - - -def test_globals_update_at_each_parallel_call(): - # This is a non-regression test related to joblib issues #836 and #833. - # Cloudpickle versions between 0.5.4 and 0.7 introduced a bug where global - # variables changes in a parent process between two calls to - # joblib.Parallel would not be propagated into the workers. - global MY_GLOBAL_VARIABLE - MY_GLOBAL_VARIABLE = "original value" - - def check_globals(): - global MY_GLOBAL_VARIABLE - return MY_GLOBAL_VARIABLE - - assert check_globals() == "original value" - - workers_global_variable = Parallel(n_jobs=2)( - delayed(check_globals)() for i in range(2)) - assert set(workers_global_variable) == {"original value"} - - # Change the value of MY_GLOBAL_VARIABLE, and make sure this change gets - # propagated into the workers environment - MY_GLOBAL_VARIABLE = "changed value" - assert check_globals() == "changed value" - - workers_global_variable = Parallel(n_jobs=2)( - delayed(check_globals)() for i in range(2)) - assert set(workers_global_variable) == {"changed value"} - - -############################################################################## -# Test environment variable in child env, in particular for limiting -# the maximal number of threads in C-library threadpools. -# - -def _check_numpy_threadpool_limits(): - import numpy as np - # Let's call BLAS on a Matrix Matrix multiplication with dimensions large - # enough to ensure that the threadpool managed by the underlying BLAS - # implementation is actually used so as to force its initialization. - a = np.random.randn(100, 100) - np.dot(a, a) - from threadpoolctl import threadpool_info - return threadpool_info() - - -def _parent_max_num_threads_for(child_module, parent_info): - for parent_module in parent_info: - if parent_module['filepath'] == child_module['filepath']: - return parent_module['num_threads'] - raise ValueError("An unexpected module was loaded in child:\n{}" - .format(child_module)) - - -def check_child_num_threads(workers_info, parent_info, num_threads): - # Check that the number of threads reported in workers_info is consistent - # with the expectation. We need to be careful to handle the cases where - # the requested number of threads is below max_num_thread for the library. - for child_threadpool_info in workers_info: - for child_module in child_threadpool_info: - parent_max_num_threads = _parent_max_num_threads_for( - child_module, parent_info) - expected = {min(num_threads, parent_max_num_threads), num_threads} - assert child_module['num_threads'] in expected - - -@with_numpy -@with_multiprocessing -@parametrize('n_jobs', [2, 4, -2, -1]) -def test_threadpool_limitation_in_child_loky(n_jobs): - # Check that the protection against oversubscription in workers is working - # using threadpoolctl functionalities. - - # Skip this test if numpy is not linked to a BLAS library - parent_info = _check_numpy_threadpool_limits() - if len(parent_info) == 0: - pytest.skip(reason="Need a version of numpy linked to BLAS") - - workers_threadpool_infos = Parallel(backend="loky", n_jobs=n_jobs)( - delayed(_check_numpy_threadpool_limits)() for i in range(2)) - - n_jobs = effective_n_jobs(n_jobs) - expected_child_num_threads = max(cpu_count() // n_jobs, 1) - - check_child_num_threads(workers_threadpool_infos, parent_info, - expected_child_num_threads) - - -@with_numpy -@with_multiprocessing -@parametrize('inner_max_num_threads', [1, 2, 4, None]) -@parametrize('n_jobs', [2, -1]) -@parametrize("context", [parallel_config, parallel_backend]) -def test_threadpool_limitation_in_child_context( - context, n_jobs, inner_max_num_threads -): - # Check that the protection against oversubscription in workers is working - # using threadpoolctl functionalities. - - # Skip this test if numpy is not linked to a BLAS library - parent_info = _check_numpy_threadpool_limits() - if len(parent_info) == 0: - pytest.skip(reason="Need a version of numpy linked to BLAS") - - with context('loky', inner_max_num_threads=inner_max_num_threads): - workers_threadpool_infos = Parallel(n_jobs=n_jobs)( - delayed(_check_numpy_threadpool_limits)() for i in range(2)) - - n_jobs = effective_n_jobs(n_jobs) - if inner_max_num_threads is None: - expected_child_num_threads = max(cpu_count() // n_jobs, 1) - else: - expected_child_num_threads = inner_max_num_threads - - check_child_num_threads(workers_threadpool_infos, parent_info, - expected_child_num_threads) - - -@with_multiprocessing -@parametrize('n_jobs', [2, -1]) -@parametrize('var_name', ["OPENBLAS_NUM_THREADS", - "MKL_NUM_THREADS", - "OMP_NUM_THREADS"]) -@parametrize("context", [parallel_config, parallel_backend]) -def test_threadpool_limitation_in_child_override(context, n_jobs, var_name): - # Check that environment variables set by the user on the main process - # always have the priority. - - # Clean up the existing executor because we change the environment of the - # parent at runtime and it is not detected in loky intentionally. - get_reusable_executor(reuse=True).shutdown() - - def _get_env(var_name): - return os.environ.get(var_name) - - original_var_value = os.environ.get(var_name) - try: - os.environ[var_name] = "4" - # Skip this test if numpy is not linked to a BLAS library - results = Parallel(n_jobs=n_jobs)( - delayed(_get_env)(var_name) for i in range(2)) - assert results == ["4", "4"] - - with context('loky', inner_max_num_threads=1): - results = Parallel(n_jobs=n_jobs)( - delayed(_get_env)(var_name) for i in range(2)) - assert results == ["1", "1"] - - finally: - if original_var_value is None: - del os.environ[var_name] - else: - os.environ[var_name] = original_var_value - - -@with_multiprocessing -@parametrize('n_jobs', [2, 4, -1]) -def test_loky_reuse_workers(n_jobs): - # Non-regression test for issue #967 where the workers are not reused when - # calling multiple Parallel loops. - - def parallel_call(n_jobs): - x = range(10) - Parallel(n_jobs=n_jobs)(delayed(sum)(x) for i in range(10)) - - # Run a parallel loop and get the workers used for computations - parallel_call(n_jobs) - first_executor = get_reusable_executor(reuse=True) - - # Ensure that the workers are reused for the next calls, as the executor is - # not restarted. - for _ in range(10): - parallel_call(n_jobs) - executor = get_reusable_executor(reuse=True) - assert executor == first_executor diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_store_backends.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_store_backends.py deleted file mode 100644 index e5db167..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_store_backends.py +++ /dev/null @@ -1,94 +0,0 @@ - -try: - # Python 2.7: use the C pickle to speed up - # test_concurrency_safe_write which pickles big python objects - import cPickle as cpickle -except ImportError: - import pickle as cpickle -import functools -from pickle import PicklingError -import time - -import pytest - -from joblib.testing import parametrize, timeout -from joblib.test.common import with_multiprocessing -from joblib.backports import concurrency_safe_rename -from joblib import Parallel, delayed -from joblib._store_backends import ( - concurrency_safe_write, - FileSystemStoreBackend, - CacheWarning, -) - - -def write_func(output, filename): - with open(filename, 'wb') as f: - cpickle.dump(output, f) - - -def load_func(expected, filename): - for i in range(10): - try: - with open(filename, 'rb') as f: - reloaded = cpickle.load(f) - break - except (OSError, IOError): - # On Windows you can have WindowsError ([Error 5] Access - # is denied or [Error 13] Permission denied) when reading the file, - # probably because a writer process has a lock on the file - time.sleep(0.1) - else: - raise - assert expected == reloaded - - -def concurrency_safe_write_rename(to_write, filename, write_func): - temporary_filename = concurrency_safe_write(to_write, - filename, write_func) - concurrency_safe_rename(temporary_filename, filename) - - -@timeout(0) # No timeout as this test can be long -@with_multiprocessing -@parametrize('backend', ['multiprocessing', 'loky', 'threading']) -def test_concurrency_safe_write(tmpdir, backend): - # Add one item to cache - filename = tmpdir.join('test.pkl').strpath - - obj = {str(i): i for i in range(int(1e5))} - funcs = [functools.partial(concurrency_safe_write_rename, - write_func=write_func) - if i % 3 != 2 else load_func for i in range(12)] - Parallel(n_jobs=2, backend=backend)( - delayed(func)(obj, filename) for func in funcs) - - -def test_warning_on_dump_failure(tmpdir): - # Check that a warning is raised when the dump fails for any reason but - # a PicklingError. - class UnpicklableObject(object): - def __reduce__(self): - raise RuntimeError("some exception") - - backend = FileSystemStoreBackend() - backend.location = tmpdir.join('test_warning_on_pickling_error').strpath - backend.compress = None - - with pytest.warns(CacheWarning, match="some exception"): - backend.dump_item("testpath", UnpicklableObject()) - - -def test_warning_on_pickling_error(tmpdir): - # This is separate from test_warning_on_dump_failure because in the - # future we will turn this into an exception. - class UnpicklableObject(object): - def __reduce__(self): - raise PicklingError("not picklable") - - backend = FileSystemStoreBackend() - backend.location = tmpdir.join('test_warning_on_pickling_error').strpath - backend.compress = None - - with pytest.warns(FutureWarning, match="not picklable"): - backend.dump_item("testpath", UnpicklableObject()) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_testing.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_testing.py deleted file mode 100644 index e8095aa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_testing.py +++ /dev/null @@ -1,75 +0,0 @@ -import sys -import re - -from joblib.testing import raises, check_subprocess_call - - -def test_check_subprocess_call(): - code = '\n'.join(['result = 1 + 2 * 3', - 'print(result)', - 'my_list = [1, 2, 3]', - 'print(my_list)']) - - check_subprocess_call([sys.executable, '-c', code]) - - # Now checking stdout with a regex - check_subprocess_call([sys.executable, '-c', code], - # Regex needed for platform-specific line endings - stdout_regex=r'7\s{1,2}\[1, 2, 3\]') - - -def test_check_subprocess_call_non_matching_regex(): - code = '42' - non_matching_pattern = '_no_way_this_matches_anything_' - - with raises(ValueError) as excinfo: - check_subprocess_call([sys.executable, '-c', code], - stdout_regex=non_matching_pattern) - excinfo.match('Unexpected stdout.+{}'.format(non_matching_pattern)) - - -def test_check_subprocess_call_wrong_command(): - wrong_command = '_a_command_that_does_not_exist_' - with raises(OSError): - check_subprocess_call([wrong_command]) - - -def test_check_subprocess_call_non_zero_return_code(): - code_with_non_zero_exit = '\n'.join([ - 'import sys', - 'print("writing on stdout")', - 'sys.stderr.write("writing on stderr")', - 'sys.exit(123)']) - - pattern = re.compile('Non-zero return code: 123.+' - 'Stdout:\nwriting on stdout.+' - 'Stderr:\nwriting on stderr', re.DOTALL) - - with raises(ValueError) as excinfo: - check_subprocess_call([sys.executable, '-c', code_with_non_zero_exit]) - excinfo.match(pattern) - - -def test_check_subprocess_call_timeout(): - code_timing_out = '\n'.join([ - 'import time', - 'import sys', - 'print("before sleep on stdout")', - 'sys.stdout.flush()', - 'sys.stderr.write("before sleep on stderr")', - 'sys.stderr.flush()', - # We need to sleep for at least 2 * timeout seconds in case the SIGKILL - # is triggered. - 'time.sleep(10)', - 'print("process should have be killed before")', - 'sys.stdout.flush()']) - - pattern = re.compile('Non-zero return code:.+' - 'Stdout:\nbefore sleep on stdout\\s+' - 'Stderr:\nbefore sleep on stderr', - re.DOTALL) - - with raises(ValueError) as excinfo: - check_subprocess_call([sys.executable, '-c', code_timing_out], - timeout=1) - excinfo.match(pattern) diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_utils.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/test_utils.py deleted file mode 100644 index 4999a21..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/test_utils.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest - -from joblib._utils import eval_expr - - -@pytest.mark.parametrize( - "expr", - ["exec('import os')", "print(1)", "import os", "1+1; import os", "1^1"], -) -def test_eval_expr_invalid(expr): - with pytest.raises( - ValueError, match="is not a valid or supported arithmetic" - ): - eval_expr(expr) - - -@pytest.mark.parametrize( - "expr, result", - [ - ("2*6", 12), - ("2**6", 64), - ("1 + 2*3**(4) / (6 + -7)", -161.0), - ("(20 // 3) % 5", 1), - ], -) -def test_eval_expr_valid(expr, result): - assert eval_expr(expr) == result diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/test/testutils.py b/extensions/.local/lib/python3.11/site-packages/joblib/test/testutils.py deleted file mode 100644 index 20ec8c1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/test/testutils.py +++ /dev/null @@ -1,8 +0,0 @@ -def return_slice_of_data(arr, start_idx, end_idx): - return arr[start_idx:end_idx] - - -def print_filename_and_raise(arr): - from joblib._memmapping_reducer import _get_backing_memmap - print(_get_backing_memmap(arr).filename) - raise ValueError diff --git a/extensions/.local/lib/python3.11/site-packages/joblib/testing.py b/extensions/.local/lib/python3.11/site-packages/joblib/testing.py deleted file mode 100644 index caab7d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/joblib/testing.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Helper for testing. -""" - -import sys -import warnings -import os.path -import re -import subprocess -import threading - -import pytest -import _pytest - - -raises = pytest.raises -warns = pytest.warns -SkipTest = _pytest.runner.Skipped -skipif = pytest.mark.skipif -fixture = pytest.fixture -parametrize = pytest.mark.parametrize -timeout = pytest.mark.timeout -xfail = pytest.mark.xfail -param = pytest.param - - -def warnings_to_stdout(): - """ Redirect all warnings to stdout. - """ - showwarning_orig = warnings.showwarning - - def showwarning(msg, cat, fname, lno, file=None, line=0): - showwarning_orig(msg, cat, os.path.basename(fname), line, sys.stdout) - - warnings.showwarning = showwarning - # warnings.simplefilter('always') - - -def check_subprocess_call(cmd, timeout=5, stdout_regex=None, - stderr_regex=None): - """Runs a command in a subprocess with timeout in seconds. - - A SIGTERM is sent after `timeout` and if it does not terminate, a - SIGKILL is sent after `2 * timeout`. - - Also checks returncode is zero, stdout if stdout_regex is set, and - stderr if stderr_regex is set. - """ - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - def terminate_process(): # pragma: no cover - """ - Attempt to terminate a leftover process spawned during test execution: - ideally this should not be needed but can help avoid clogging the CI - workers in case of deadlocks. - """ - warnings.warn(f"Timeout running {cmd}") - proc.terminate() - - def kill_process(): # pragma: no cover - """ - Kill a leftover process spawned during test execution: ideally this - should not be needed but can help avoid clogging the CI workers in - case of deadlocks. - """ - warnings.warn(f"Timeout running {cmd}") - proc.kill() - - try: - if timeout is not None: - terminate_timer = threading.Timer(timeout, terminate_process) - terminate_timer.start() - kill_timer = threading.Timer(2 * timeout, kill_process) - kill_timer.start() - stdout, stderr = proc.communicate() - stdout, stderr = stdout.decode(), stderr.decode() - if proc.returncode != 0: - message = ( - 'Non-zero return code: {}.\nStdout:\n{}\n' - 'Stderr:\n{}').format( - proc.returncode, stdout, stderr) - raise ValueError(message) - - if (stdout_regex is not None and - not re.search(stdout_regex, stdout)): - raise ValueError( - "Unexpected stdout: {!r} does not match:\n{!r}".format( - stdout_regex, stdout)) - if (stderr_regex is not None and - not re.search(stderr_regex, stderr)): - raise ValueError( - "Unexpected stderr: {!r} does not match:\n{!r}".format( - stderr_regex, stderr)) - - finally: - if timeout is not None: - terminate_timer.cancel() - kill_timer.cancel() diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/METADATA deleted file mode 100644 index d9536b6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/METADATA +++ /dev/null @@ -1,176 +0,0 @@ -Metadata-Version: 2.3 -Name: jsonschema -Version: 4.23.0 -Summary: An implementation of JSON Schema validation for Python -Project-URL: Homepage, https://github.com/python-jsonschema/jsonschema -Project-URL: Documentation, https://python-jsonschema.readthedocs.io/ -Project-URL: Issues, https://github.com/python-jsonschema/jsonschema/issues/ -Project-URL: Funding, https://github.com/sponsors/Julian -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema?utm_source=pypi-jsonschema&utm_medium=referral&utm_campaign=pypi-link -Project-URL: Changelog, https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst -Project-URL: Source, https://github.com/python-jsonschema/jsonschema -Author-email: Julian Berman -License: MIT -License-File: COPYING -Keywords: data validation,json,json schema,jsonschema,validation -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: File Formats :: JSON -Classifier: Topic :: File Formats :: JSON :: JSON Schema -Requires-Python: >=3.8 -Requires-Dist: attrs>=22.2.0 -Requires-Dist: importlib-resources>=1.4.0; python_version < '3.9' -Requires-Dist: jsonschema-specifications>=2023.03.6 -Requires-Dist: pkgutil-resolve-name>=1.3.10; python_version < '3.9' -Requires-Dist: referencing>=0.28.4 -Requires-Dist: rpds-py>=0.7.1 -Provides-Extra: format -Requires-Dist: fqdn; extra == 'format' -Requires-Dist: idna; extra == 'format' -Requires-Dist: isoduration; extra == 'format' -Requires-Dist: jsonpointer>1.13; extra == 'format' -Requires-Dist: rfc3339-validator; extra == 'format' -Requires-Dist: rfc3987; extra == 'format' -Requires-Dist: uri-template; extra == 'format' -Requires-Dist: webcolors>=1.11; extra == 'format' -Provides-Extra: format-nongpl -Requires-Dist: fqdn; extra == 'format-nongpl' -Requires-Dist: idna; extra == 'format-nongpl' -Requires-Dist: isoduration; extra == 'format-nongpl' -Requires-Dist: jsonpointer>1.13; extra == 'format-nongpl' -Requires-Dist: rfc3339-validator; extra == 'format-nongpl' -Requires-Dist: rfc3986-validator>0.1.0; extra == 'format-nongpl' -Requires-Dist: uri-template; extra == 'format-nongpl' -Requires-Dist: webcolors>=24.6.0; extra == 'format-nongpl' -Description-Content-Type: text/x-rst - -========== -jsonschema -========== - -|PyPI| |Pythons| |CI| |ReadTheDocs| |Precommit| |Zenodo| - -.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema.svg - :alt: PyPI version - :target: https://pypi.org/project/jsonschema/ - -.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema.svg - :alt: Supported Python versions - :target: https://pypi.org/project/jsonschema/ - -.. |CI| image:: https://github.com/python-jsonschema/jsonschema/workflows/CI/badge.svg - :alt: Build status - :target: https://github.com/python-jsonschema/jsonschema/actions?query=workflow%3ACI - -.. |ReadTheDocs| image:: https://readthedocs.org/projects/python-jsonschema/badge/?version=stable&style=flat - :alt: ReadTheDocs status - :target: https://python-jsonschema.readthedocs.io/en/stable/ - -.. |Precommit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/jsonschema/main.svg - :alt: pre-commit.ci status - :target: https://results.pre-commit.ci/latest/github/python-jsonschema/jsonschema/main - -.. |Zenodo| image:: https://zenodo.org/badge/3072629.svg - :alt: Zenodo DOI - :target: https://zenodo.org/badge/latestdoi/3072629 - - -``jsonschema`` is an implementation of the `JSON Schema `_ specification for Python. - -.. code:: python - - >>> from jsonschema import validate - - >>> # A sample schema, like what we'd get from json.load() - >>> schema = { - ... "type" : "object", - ... "properties" : { - ... "price" : {"type" : "number"}, - ... "name" : {"type" : "string"}, - ... }, - ... } - - >>> # If no exception is raised by validate(), the instance is valid. - >>> validate(instance={"name" : "Eggs", "price" : 34.99}, schema=schema) - - >>> validate( - ... instance={"name" : "Eggs", "price" : "Invalid"}, schema=schema, - ... ) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - ValidationError: 'Invalid' is not of type 'number' - -It can also be used from the command line by installing `check-jsonschema `_. - -Features --------- - -* Full support for `Draft 2020-12 `_, `Draft 2019-09 `_, `Draft 7 `_, `Draft 6 `_, `Draft 4 `_ and `Draft 3 `_ - -* `Lazy validation `_ that can iteratively report *all* validation errors. - -* `Programmatic querying `_ of which properties or items failed validation. - - -Installation ------------- - -``jsonschema`` is available on `PyPI `_. You can install using `pip `_: - -.. code:: bash - - $ pip install jsonschema - - -Extras -====== - -Two extras are available when installing the package, both currently related to ``format`` validation: - - * ``format`` - * ``format-nongpl`` - -They can be used when installing in order to include additional dependencies, e.g.: - -.. code:: bash - - $ pip install jsonschema'[format]' - -Be aware that the mere presence of these dependencies – or even the specification of ``format`` checks in a schema – do *not* activate format checks (as per the specification). -Please read the `format validation documentation `_ for further details. - -About ------ - -I'm Julian Berman. - -``jsonschema`` is on `GitHub `_. - -Get in touch, via GitHub or otherwise, if you've got something to contribute, it'd be most welcome! - -You can also generally find me on Libera (nick: ``Julian``) in various channels, including ``#python``. - -If you feel overwhelmingly grateful, you can also `sponsor me `_. - -And for companies who appreciate ``jsonschema`` and its continued support and growth, ``jsonschema`` is also now supportable via `TideLift `_. - - -Release Information -------------------- - -v4.23.0 -======= - -* Do not reorder dictionaries (schemas, instances) that are printed as part of validation errors. -* Declare support for Py3.13 diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/RECORD deleted file mode 100644 index 5ae1f6d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/RECORD +++ /dev/null @@ -1,40 +0,0 @@ -jsonschema/__init__.py,sha256=LkPwscySlJ9lTOp7ZB1M7jQ8mbG7-bYG41iBwbZ-o9s,3941 -jsonschema/__main__.py,sha256=iLsZf2upUB3ilBKTlMnyK-HHt2Cnnfkwwxi_c6gLvSA,115 -jsonschema/_format.py,sha256=F_MA52IkrhOIxDqD8x-01bH37mG5nh0kyNrWUSLtWb8,14591 -jsonschema/_keywords.py,sha256=r8_DrqAfn6QLwQnmXEggveiSU-UaIL2p2nuPINelfFc,14949 -jsonschema/_legacy_keywords.py,sha256=2tWuwRPWbYS7EAl8wBIC_rabGuv1J4dfYLqNEPpShhA,15191 -jsonschema/_types.py,sha256=HQ5QD_oL85zF1FSW2v-5rvfYF0967HJdxSR88kzw2mY,5367 -jsonschema/_typing.py,sha256=NZhPhkBOn9INYZk8G69rDeuRamztgXCMLh10z9cfT6g,610 -jsonschema/_utils.py,sha256=ODga3vrJ6K2wMGxerpgn4ipc9q7ZSqBsvwKU4embLEE,10642 -jsonschema/cli.py,sha256=SGy9JPg02mgXhNxugU8iXhYNivfSjBhKTNAgV90ty-M,8551 -jsonschema/exceptions.py,sha256=RxE2T5xxgg_B6ttR8a3lCbZyh29RUtFe4oZKMoHPBAE,15035 -jsonschema/protocols.py,sha256=7mpZxO1gfRNMCGXwldwsSN3nEugVfIVyKZ_HZgN1vSw,7174 -jsonschema/validators.py,sha256=H31FwHdyB7LP5eunxdBrZ9E57hpvozfnRlZaOYy45jU,47045 -jsonschema/benchmarks/__init__.py,sha256=A0sQrxDBVHSyQ-8ru3L11hMXf3q9gVuB9x_YgHb4R9M,70 -jsonschema/benchmarks/const_vs_enum.py,sha256=DVFi3WDqBalZFOibnjpX1uTSr3Rxa2cPgFcowd7Ukrs,830 -jsonschema/benchmarks/contains.py,sha256=gexQoUrCOwECofbt19BeosQZ7WFL6PDdkX49DWwBlOg,786 -jsonschema/benchmarks/issue232.py,sha256=3LLYLIlBGQnVuyyo2iAv-xky5P6PRFHANx4-zIIQOoE,521 -jsonschema/benchmarks/json_schema_test_suite.py,sha256=PvfabpUYcF4_7csYDTcTauED8rnFEGYbdY5RqTXD08s,320 -jsonschema/benchmarks/nested_schemas.py,sha256=mo07dx-CIgmSOI62CNs4g5xu1FzHklLBpkQoDxWYcKs,1892 -jsonschema/benchmarks/subcomponents.py,sha256=fEyiMzsWeK2pd7DEGCuuY-vzGunwhHczRBWEnBRLKIo,1113 -jsonschema/benchmarks/unused_registry.py,sha256=hwRwONc9cefPtYzkoX_TYRO3GyUojriv0-YQaK3vnj0,940 -jsonschema/benchmarks/useless_applicator_schemas.py,sha256=EVm5-EtOEFoLP_Vt2j4SrCwlx05NhPqNuZQ6LIMP1Dc,3342 -jsonschema/benchmarks/useless_keywords.py,sha256=bj_zKr1oVctFlqyZaObCsYTgFjiiNgPzC0hr1Y868mE,867 -jsonschema/benchmarks/validator_creation.py,sha256=UkUQlLAnussnr_KdCIdad6xx2pXxQLmYtsXoiirKeWQ,285 -jsonschema/benchmarks/issue232/issue.json,sha256=eaPOZjMRu5u8RpKrsA9uk7ucPZS5tkKG4D_hkOTQ3Hk,117105 -jsonschema/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -jsonschema/tests/_suite.py,sha256=QAfBj34zMbJQ5_JJ2ogpiTlw9hQ6Is43dvo_bpS0EdM,8156 -jsonschema/tests/fuzz_validate.py,sha256=fUA7yTJIihaCwJplkUehZeyB84HcXEcqtY5oPJXIO7I,1114 -jsonschema/tests/test_cli.py,sha256=uFMu2YbIfbSDCnykhLL4-VR3-jg1tvQLJn2Bliwp_Bw,28587 -jsonschema/tests/test_deprecations.py,sha256=9VxOCfWzMG1Tg4OD8riU_Znd6HDOQZkepzVgxsdUdU8,15760 -jsonschema/tests/test_exceptions.py,sha256=JgC-E1ZFZK2puVBp35WFRnG8CNOiSWLYtyLjh9IvFKI,22591 -jsonschema/tests/test_format.py,sha256=eVm5SMaWF2lOPO28bPAwNvkiQvHCQKy-MnuAgEchfEc,3188 -jsonschema/tests/test_jsonschema_test_suite.py,sha256=a2saPs2Cwwg0sdRdu-uJ8goSXLbqrS-pC48QJy0K4DE,8674 -jsonschema/tests/test_types.py,sha256=cF51KTDmdsx06MrIc4fXKt0X9fIsVgw5uhT8CamVa8U,6977 -jsonschema/tests/test_utils.py,sha256=sao74o1PyYMxBfqweokQN48CFSS6yhJk5FkCfMJ5PsI,4163 -jsonschema/tests/test_validators.py,sha256=eiaigsZMzHYYsniQ1UPygaS56a1d-_7-9NC4wVXAhzs,87975 -jsonschema-4.23.0.dist-info/METADATA,sha256=Hd96gAfdO0v5RpFeT25qjyo7PvhASy56F4Jw3FUUTlo,7906 -jsonschema-4.23.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87 -jsonschema-4.23.0.dist-info/entry_points.txt,sha256=vO7rX4Fs_xIVJy2pnAtKgTSxfpnozAVQ0DjCmpMxnWE,51 -jsonschema-4.23.0.dist-info/licenses/COPYING,sha256=T5KgFaE8TRoEC-8BiqE0MLTxvHO0Gxa7hGw0Z2bedDk,1057 -jsonschema-4.23.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/WHEEL deleted file mode 100644 index cdd68a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.25.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/entry_points.txt deleted file mode 100644 index eecef9d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -jsonschema = jsonschema.cli:main diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/licenses/COPYING b/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/licenses/COPYING deleted file mode 100644 index af9cfbd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema-4.23.0.dist-info/licenses/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Julian Berman - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/__init__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/__init__.py deleted file mode 100644 index 79924cf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/__init__.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -An implementation of JSON Schema for Python. - -The main functionality is provided by the validator classes for each of the -supported JSON Schema versions. - -Most commonly, `jsonschema.validators.validate` is the quickest way to simply -validate a given instance under a schema, and will create a validator -for you. -""" -import warnings - -from jsonschema._format import FormatChecker -from jsonschema._types import TypeChecker -from jsonschema.exceptions import SchemaError, ValidationError -from jsonschema.validators import ( - Draft3Validator, - Draft4Validator, - Draft6Validator, - Draft7Validator, - Draft201909Validator, - Draft202012Validator, - validate, -) - - -def __getattr__(name): - if name == "__version__": - warnings.warn( - "Accessing jsonschema.__version__ is deprecated and will be " - "removed in a future release. Use importlib.metadata directly " - "to query for jsonschema's version.", - DeprecationWarning, - stacklevel=2, - ) - - from importlib import metadata - return metadata.version("jsonschema") - elif name == "RefResolver": - from jsonschema.validators import _RefResolver - warnings.warn( - _RefResolver._DEPRECATION_MESSAGE, - DeprecationWarning, - stacklevel=2, - ) - return _RefResolver - elif name == "ErrorTree": - warnings.warn( - "Importing ErrorTree directly from the jsonschema package " - "is deprecated and will become an ImportError. Import it from " - "jsonschema.exceptions instead.", - DeprecationWarning, - stacklevel=2, - ) - from jsonschema.exceptions import ErrorTree - return ErrorTree - elif name == "FormatError": - warnings.warn( - "Importing FormatError directly from the jsonschema package " - "is deprecated and will become an ImportError. Import it from " - "jsonschema.exceptions instead.", - DeprecationWarning, - stacklevel=2, - ) - from jsonschema.exceptions import FormatError - return FormatError - elif name == "Validator": - warnings.warn( - "Importing Validator directly from the jsonschema package " - "is deprecated and will become an ImportError. Import it from " - "jsonschema.protocols instead.", - DeprecationWarning, - stacklevel=2, - ) - from jsonschema.protocols import Validator - return Validator - elif name == "RefResolutionError": - from jsonschema.exceptions import _RefResolutionError - warnings.warn( - _RefResolutionError._DEPRECATION_MESSAGE, - DeprecationWarning, - stacklevel=2, - ) - return _RefResolutionError - - format_checkers = { - "draft3_format_checker": Draft3Validator, - "draft4_format_checker": Draft4Validator, - "draft6_format_checker": Draft6Validator, - "draft7_format_checker": Draft7Validator, - "draft201909_format_checker": Draft201909Validator, - "draft202012_format_checker": Draft202012Validator, - } - ValidatorForFormat = format_checkers.get(name) - if ValidatorForFormat is not None: - warnings.warn( - f"Accessing jsonschema.{name} is deprecated and will be " - "removed in a future release. Instead, use the FORMAT_CHECKER " - "attribute on the corresponding Validator.", - DeprecationWarning, - stacklevel=2, - ) - return ValidatorForFormat.FORMAT_CHECKER - - raise AttributeError(f"module {__name__} has no attribute {name}") - - -__all__ = [ - "Draft201909Validator", - "Draft202012Validator", - "Draft3Validator", - "Draft4Validator", - "Draft6Validator", - "Draft7Validator", - "FormatChecker", - "SchemaError", - "TypeChecker", - "ValidationError", - "validate", -] diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/__main__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/__main__.py deleted file mode 100644 index fb260ae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -The jsonschema CLI is now deprecated in favor of check-jsonschema. -""" -from jsonschema.cli import main - -main() diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_format.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_format.py deleted file mode 100644 index 6e87620..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_format.py +++ /dev/null @@ -1,519 +0,0 @@ -from __future__ import annotations - -from contextlib import suppress -from datetime import date, datetime -from uuid import UUID -import ipaddress -import re -import typing -import warnings - -from jsonschema.exceptions import FormatError - -_FormatCheckCallable = typing.Callable[[object], bool] -#: A format checker callable. -_F = typing.TypeVar("_F", bound=_FormatCheckCallable) -_RaisesType = typing.Union[ - typing.Type[Exception], typing.Tuple[typing.Type[Exception], ...], -] - -_RE_DATE = re.compile(r"^\d{4}-\d{2}-\d{2}$", re.ASCII) - - -class FormatChecker: - """ - A ``format`` property checker. - - JSON Schema does not mandate that the ``format`` property actually do any - validation. If validation is desired however, instances of this class can - be hooked into validators to enable format validation. - - `FormatChecker` objects always return ``True`` when asked about - formats that they do not know how to validate. - - To add a check for a custom format use the `FormatChecker.checks` - decorator. - - Arguments: - - formats: - - The known formats to validate. This argument can be used to - limit which formats will be used during validation. - - """ - - checkers: dict[ - str, - tuple[_FormatCheckCallable, _RaisesType], - ] = {} # noqa: RUF012 - - def __init__(self, formats: typing.Iterable[str] | None = None): - if formats is None: - formats = self.checkers.keys() - self.checkers = {k: self.checkers[k] for k in formats} - - def __repr__(self): - return f"" - - def checks( - self, format: str, raises: _RaisesType = (), - ) -> typing.Callable[[_F], _F]: - """ - Register a decorated function as validating a new format. - - Arguments: - - format: - - The format that the decorated function will check. - - raises: - - The exception(s) raised by the decorated function when an - invalid instance is found. - - The exception object will be accessible as the - `jsonschema.exceptions.ValidationError.cause` attribute of the - resulting validation error. - - """ - - def _checks(func: _F) -> _F: - self.checkers[format] = (func, raises) - return func - - return _checks - - @classmethod - def cls_checks( - cls, format: str, raises: _RaisesType = (), - ) -> typing.Callable[[_F], _F]: - warnings.warn( - ( - "FormatChecker.cls_checks is deprecated. Call " - "FormatChecker.checks on a specific FormatChecker instance " - "instead." - ), - DeprecationWarning, - stacklevel=2, - ) - return cls._cls_checks(format=format, raises=raises) - - @classmethod - def _cls_checks( - cls, format: str, raises: _RaisesType = (), - ) -> typing.Callable[[_F], _F]: - def _checks(func: _F) -> _F: - cls.checkers[format] = (func, raises) - return func - - return _checks - - def check(self, instance: object, format: str) -> None: - """ - Check whether the instance conforms to the given format. - - Arguments: - - instance (*any primitive type*, i.e. str, number, bool): - - The instance to check - - format: - - The format that instance should conform to - - Raises: - - FormatError: - - if the instance does not conform to ``format`` - - """ - if format not in self.checkers: - return - - func, raises = self.checkers[format] - result, cause = None, None - try: - result = func(instance) - except raises as e: - cause = e - if not result: - raise FormatError(f"{instance!r} is not a {format!r}", cause=cause) - - def conforms(self, instance: object, format: str) -> bool: - """ - Check whether the instance conforms to the given format. - - Arguments: - - instance (*any primitive type*, i.e. str, number, bool): - - The instance to check - - format: - - The format that instance should conform to - - Returns: - - bool: whether it conformed - - """ - try: - self.check(instance, format) - except FormatError: - return False - else: - return True - - -draft3_format_checker = FormatChecker() -draft4_format_checker = FormatChecker() -draft6_format_checker = FormatChecker() -draft7_format_checker = FormatChecker() -draft201909_format_checker = FormatChecker() -draft202012_format_checker = FormatChecker() - -_draft_checkers: dict[str, FormatChecker] = dict( - draft3=draft3_format_checker, - draft4=draft4_format_checker, - draft6=draft6_format_checker, - draft7=draft7_format_checker, - draft201909=draft201909_format_checker, - draft202012=draft202012_format_checker, -) - - -def _checks_drafts( - name=None, - draft3=None, - draft4=None, - draft6=None, - draft7=None, - draft201909=None, - draft202012=None, - raises=(), -) -> typing.Callable[[_F], _F]: - draft3 = draft3 or name - draft4 = draft4 or name - draft6 = draft6 or name - draft7 = draft7 or name - draft201909 = draft201909 or name - draft202012 = draft202012 or name - - def wrap(func: _F) -> _F: - if draft3: - func = _draft_checkers["draft3"].checks(draft3, raises)(func) - if draft4: - func = _draft_checkers["draft4"].checks(draft4, raises)(func) - if draft6: - func = _draft_checkers["draft6"].checks(draft6, raises)(func) - if draft7: - func = _draft_checkers["draft7"].checks(draft7, raises)(func) - if draft201909: - func = _draft_checkers["draft201909"].checks(draft201909, raises)( - func, - ) - if draft202012: - func = _draft_checkers["draft202012"].checks(draft202012, raises)( - func, - ) - - # Oy. This is bad global state, but relied upon for now, until - # deprecation. See #519 and test_format_checkers_come_with_defaults - FormatChecker._cls_checks( - draft202012 or draft201909 or draft7 or draft6 or draft4 or draft3, - raises, - )(func) - return func - - return wrap - - -@_checks_drafts(name="idn-email") -@_checks_drafts(name="email") -def is_email(instance: object) -> bool: - if not isinstance(instance, str): - return True - return "@" in instance - - -@_checks_drafts( - draft3="ip-address", - draft4="ipv4", - draft6="ipv4", - draft7="ipv4", - draft201909="ipv4", - draft202012="ipv4", - raises=ipaddress.AddressValueError, -) -def is_ipv4(instance: object) -> bool: - if not isinstance(instance, str): - return True - return bool(ipaddress.IPv4Address(instance)) - - -@_checks_drafts(name="ipv6", raises=ipaddress.AddressValueError) -def is_ipv6(instance: object) -> bool: - if not isinstance(instance, str): - return True - address = ipaddress.IPv6Address(instance) - return not getattr(address, "scope_id", "") - - -with suppress(ImportError): - from fqdn import FQDN - - @_checks_drafts( - draft3="host-name", - draft4="hostname", - draft6="hostname", - draft7="hostname", - draft201909="hostname", - draft202012="hostname", - ) - def is_host_name(instance: object) -> bool: - if not isinstance(instance, str): - return True - return FQDN(instance, min_labels=1).is_valid - - -with suppress(ImportError): - # The built-in `idna` codec only implements RFC 3890, so we go elsewhere. - import idna - - @_checks_drafts( - draft7="idn-hostname", - draft201909="idn-hostname", - draft202012="idn-hostname", - raises=(idna.IDNAError, UnicodeError), - ) - def is_idn_host_name(instance: object) -> bool: - if not isinstance(instance, str): - return True - idna.encode(instance) - return True - - -try: - import rfc3987 -except ImportError: - with suppress(ImportError): - from rfc3986_validator import validate_rfc3986 - - @_checks_drafts(name="uri") - def is_uri(instance: object) -> bool: - if not isinstance(instance, str): - return True - return validate_rfc3986(instance, rule="URI") - - @_checks_drafts( - draft6="uri-reference", - draft7="uri-reference", - draft201909="uri-reference", - draft202012="uri-reference", - raises=ValueError, - ) - def is_uri_reference(instance: object) -> bool: - if not isinstance(instance, str): - return True - return validate_rfc3986(instance, rule="URI_reference") - -else: - - @_checks_drafts( - draft7="iri", - draft201909="iri", - draft202012="iri", - raises=ValueError, - ) - def is_iri(instance: object) -> bool: - if not isinstance(instance, str): - return True - return rfc3987.parse(instance, rule="IRI") - - @_checks_drafts( - draft7="iri-reference", - draft201909="iri-reference", - draft202012="iri-reference", - raises=ValueError, - ) - def is_iri_reference(instance: object) -> bool: - if not isinstance(instance, str): - return True - return rfc3987.parse(instance, rule="IRI_reference") - - @_checks_drafts(name="uri", raises=ValueError) - def is_uri(instance: object) -> bool: - if not isinstance(instance, str): - return True - return rfc3987.parse(instance, rule="URI") - - @_checks_drafts( - draft6="uri-reference", - draft7="uri-reference", - draft201909="uri-reference", - draft202012="uri-reference", - raises=ValueError, - ) - def is_uri_reference(instance: object) -> bool: - if not isinstance(instance, str): - return True - return rfc3987.parse(instance, rule="URI_reference") - - -with suppress(ImportError): - from rfc3339_validator import validate_rfc3339 - - @_checks_drafts(name="date-time") - def is_datetime(instance: object) -> bool: - if not isinstance(instance, str): - return True - return validate_rfc3339(instance.upper()) - - @_checks_drafts( - draft7="time", - draft201909="time", - draft202012="time", - ) - def is_time(instance: object) -> bool: - if not isinstance(instance, str): - return True - return is_datetime("1970-01-01T" + instance) - - -@_checks_drafts(name="regex", raises=re.error) -def is_regex(instance: object) -> bool: - if not isinstance(instance, str): - return True - return bool(re.compile(instance)) - - -@_checks_drafts( - draft3="date", - draft7="date", - draft201909="date", - draft202012="date", - raises=ValueError, -) -def is_date(instance: object) -> bool: - if not isinstance(instance, str): - return True - return bool(_RE_DATE.fullmatch(instance) and date.fromisoformat(instance)) - - -@_checks_drafts(draft3="time", raises=ValueError) -def is_draft3_time(instance: object) -> bool: - if not isinstance(instance, str): - return True - return bool(datetime.strptime(instance, "%H:%M:%S")) # noqa: DTZ007 - - -with suppress(ImportError): - import webcolors - - @_checks_drafts(draft3="color", raises=(ValueError, TypeError)) - def is_css21_color(instance: object) -> bool: - if isinstance(instance, str): - try: - webcolors.name_to_hex(instance) - except ValueError: - webcolors.normalize_hex(instance.lower()) - return True - - -with suppress(ImportError): - import jsonpointer - - @_checks_drafts( - draft6="json-pointer", - draft7="json-pointer", - draft201909="json-pointer", - draft202012="json-pointer", - raises=jsonpointer.JsonPointerException, - ) - def is_json_pointer(instance: object) -> bool: - if not isinstance(instance, str): - return True - return bool(jsonpointer.JsonPointer(instance)) - - # TODO: I don't want to maintain this, so it - # needs to go either into jsonpointer (pending - # https://github.com/stefankoegl/python-json-pointer/issues/34) or - # into a new external library. - @_checks_drafts( - draft7="relative-json-pointer", - draft201909="relative-json-pointer", - draft202012="relative-json-pointer", - raises=jsonpointer.JsonPointerException, - ) - def is_relative_json_pointer(instance: object) -> bool: - # Definition taken from: - # https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01#section-3 - if not isinstance(instance, str): - return True - if not instance: - return False - - non_negative_integer, rest = [], "" - for i, character in enumerate(instance): - if character.isdigit(): - # digits with a leading "0" are not allowed - if i > 0 and int(instance[i - 1]) == 0: - return False - - non_negative_integer.append(character) - continue - - if not non_negative_integer: - return False - - rest = instance[i:] - break - return (rest == "#") or bool(jsonpointer.JsonPointer(rest)) - - -with suppress(ImportError): - import uri_template - - @_checks_drafts( - draft6="uri-template", - draft7="uri-template", - draft201909="uri-template", - draft202012="uri-template", - ) - def is_uri_template(instance: object) -> bool: - if not isinstance(instance, str): - return True - return uri_template.validate(instance) - - -with suppress(ImportError): - import isoduration - - @_checks_drafts( - draft201909="duration", - draft202012="duration", - raises=isoduration.DurationParsingException, - ) - def is_duration(instance: object) -> bool: - if not isinstance(instance, str): - return True - isoduration.parse_duration(instance) - # FIXME: See bolsote/isoduration#25 and bolsote/isoduration#21 - return instance.endswith(tuple("DMYWHMS")) - - -@_checks_drafts( - draft201909="uuid", - draft202012="uuid", - raises=ValueError, -) -def is_uuid(instance: object) -> bool: - if not isinstance(instance, str): - return True - UUID(instance) - return all(instance[position] == "-" for position in (8, 13, 18, 23)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_keywords.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_keywords.py deleted file mode 100644 index f30f954..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_keywords.py +++ /dev/null @@ -1,449 +0,0 @@ -from fractions import Fraction -import re - -from jsonschema._utils import ( - ensure_list, - equal, - extras_msg, - find_additional_properties, - find_evaluated_item_indexes_by_schema, - find_evaluated_property_keys_by_schema, - uniq, -) -from jsonschema.exceptions import FormatError, ValidationError - - -def patternProperties(validator, patternProperties, instance, schema): - if not validator.is_type(instance, "object"): - return - - for pattern, subschema in patternProperties.items(): - for k, v in instance.items(): - if re.search(pattern, k): - yield from validator.descend( - v, subschema, path=k, schema_path=pattern, - ) - - -def propertyNames(validator, propertyNames, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property in instance: - yield from validator.descend(instance=property, schema=propertyNames) - - -def additionalProperties(validator, aP, instance, schema): - if not validator.is_type(instance, "object"): - return - - extras = set(find_additional_properties(instance, schema)) - - if validator.is_type(aP, "object"): - for extra in extras: - yield from validator.descend(instance[extra], aP, path=extra) - elif not aP and extras: - if "patternProperties" in schema: - verb = "does" if len(extras) == 1 else "do" - joined = ", ".join(repr(each) for each in sorted(extras)) - patterns = ", ".join( - repr(each) for each in sorted(schema["patternProperties"]) - ) - error = f"{joined} {verb} not match any of the regexes: {patterns}" - yield ValidationError(error) - else: - error = "Additional properties are not allowed (%s %s unexpected)" - yield ValidationError(error % extras_msg(sorted(extras, key=str))) - - -def items(validator, items, instance, schema): - if not validator.is_type(instance, "array"): - return - - prefix = len(schema.get("prefixItems", [])) - total = len(instance) - extra = total - prefix - if extra <= 0: - return - - if items is False: - rest = instance[prefix:] if extra != 1 else instance[prefix] - item = "items" if prefix != 1 else "item" - yield ValidationError( - f"Expected at most {prefix} {item} but found {extra} " - f"extra: {rest!r}", - ) - else: - for index in range(prefix, total): - yield from validator.descend( - instance=instance[index], - schema=items, - path=index, - ) - - -def const(validator, const, instance, schema): - if not equal(instance, const): - yield ValidationError(f"{const!r} was expected") - - -def contains(validator, contains, instance, schema): - if not validator.is_type(instance, "array"): - return - - matches = 0 - min_contains = schema.get("minContains", 1) - max_contains = schema.get("maxContains", len(instance)) - - contains_validator = validator.evolve(schema=contains) - - for each in instance: - if contains_validator.is_valid(each): - matches += 1 - if matches > max_contains: - yield ValidationError( - "Too many items match the given schema " - f"(expected at most {max_contains})", - validator="maxContains", - validator_value=max_contains, - ) - return - - if matches < min_contains: - if not matches: - yield ValidationError( - f"{instance!r} does not contain items " - "matching the given schema", - ) - else: - yield ValidationError( - "Too few items match the given schema (expected at least " - f"{min_contains} but only {matches} matched)", - validator="minContains", - validator_value=min_contains, - ) - - -def exclusiveMinimum(validator, minimum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if instance <= minimum: - yield ValidationError( - f"{instance!r} is less than or equal to " - f"the minimum of {minimum!r}", - ) - - -def exclusiveMaximum(validator, maximum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if instance >= maximum: - yield ValidationError( - f"{instance!r} is greater than or equal " - f"to the maximum of {maximum!r}", - ) - - -def minimum(validator, minimum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if instance < minimum: - message = f"{instance!r} is less than the minimum of {minimum!r}" - yield ValidationError(message) - - -def maximum(validator, maximum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if instance > maximum: - message = f"{instance!r} is greater than the maximum of {maximum!r}" - yield ValidationError(message) - - -def multipleOf(validator, dB, instance, schema): - if not validator.is_type(instance, "number"): - return - - if isinstance(dB, float): - quotient = instance / dB - try: - failed = int(quotient) != quotient - except OverflowError: - # When `instance` is large and `dB` is less than one, - # quotient can overflow to infinity; and then casting to int - # raises an error. - # - # In this case we fall back to Fraction logic, which is - # exact and cannot overflow. The performance is also - # acceptable: we try the fast all-float option first, and - # we know that fraction(dB) can have at most a few hundred - # digits in each part. The worst-case slowdown is therefore - # for already-slow enormous integers or Decimals. - failed = (Fraction(instance) / Fraction(dB)).denominator != 1 - else: - failed = instance % dB - - if failed: - yield ValidationError(f"{instance!r} is not a multiple of {dB}") - - -def minItems(validator, mI, instance, schema): - if validator.is_type(instance, "array") and len(instance) < mI: - message = "should be non-empty" if mI == 1 else "is too short" - yield ValidationError(f"{instance!r} {message}") - - -def maxItems(validator, mI, instance, schema): - if validator.is_type(instance, "array") and len(instance) > mI: - message = "is expected to be empty" if mI == 0 else "is too long" - yield ValidationError(f"{instance!r} {message}") - - -def uniqueItems(validator, uI, instance, schema): - if ( - uI - and validator.is_type(instance, "array") - and not uniq(instance) - ): - yield ValidationError(f"{instance!r} has non-unique elements") - - -def pattern(validator, patrn, instance, schema): - if ( - validator.is_type(instance, "string") - and not re.search(patrn, instance) - ): - yield ValidationError(f"{instance!r} does not match {patrn!r}") - - -def format(validator, format, instance, schema): - if validator.format_checker is not None: - try: - validator.format_checker.check(instance, format) - except FormatError as error: - yield ValidationError(error.message, cause=error.cause) - - -def minLength(validator, mL, instance, schema): - if validator.is_type(instance, "string") and len(instance) < mL: - message = "should be non-empty" if mL == 1 else "is too short" - yield ValidationError(f"{instance!r} {message}") - - -def maxLength(validator, mL, instance, schema): - if validator.is_type(instance, "string") and len(instance) > mL: - message = "is expected to be empty" if mL == 0 else "is too long" - yield ValidationError(f"{instance!r} {message}") - - -def dependentRequired(validator, dependentRequired, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property, dependency in dependentRequired.items(): - if property not in instance: - continue - - for each in dependency: - if each not in instance: - message = f"{each!r} is a dependency of {property!r}" - yield ValidationError(message) - - -def dependentSchemas(validator, dependentSchemas, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property, dependency in dependentSchemas.items(): - if property not in instance: - continue - yield from validator.descend( - instance, dependency, schema_path=property, - ) - - -def enum(validator, enums, instance, schema): - if all(not equal(each, instance) for each in enums): - yield ValidationError(f"{instance!r} is not one of {enums!r}") - - -def ref(validator, ref, instance, schema): - yield from validator._validate_reference(ref=ref, instance=instance) - - -def dynamicRef(validator, dynamicRef, instance, schema): - yield from validator._validate_reference(ref=dynamicRef, instance=instance) - - -def type(validator, types, instance, schema): - types = ensure_list(types) - - if not any(validator.is_type(instance, type) for type in types): - reprs = ", ".join(repr(type) for type in types) - yield ValidationError(f"{instance!r} is not of type {reprs}") - - -def properties(validator, properties, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property, subschema in properties.items(): - if property in instance: - yield from validator.descend( - instance[property], - subschema, - path=property, - schema_path=property, - ) - - -def required(validator, required, instance, schema): - if not validator.is_type(instance, "object"): - return - for property in required: - if property not in instance: - yield ValidationError(f"{property!r} is a required property") - - -def minProperties(validator, mP, instance, schema): - if validator.is_type(instance, "object") and len(instance) < mP: - message = ( - "should be non-empty" if mP == 1 - else "does not have enough properties" - ) - yield ValidationError(f"{instance!r} {message}") - - -def maxProperties(validator, mP, instance, schema): - if not validator.is_type(instance, "object"): - return - if validator.is_type(instance, "object") and len(instance) > mP: - message = ( - "is expected to be empty" if mP == 0 - else "has too many properties" - ) - yield ValidationError(f"{instance!r} {message}") - - -def allOf(validator, allOf, instance, schema): - for index, subschema in enumerate(allOf): - yield from validator.descend(instance, subschema, schema_path=index) - - -def anyOf(validator, anyOf, instance, schema): - all_errors = [] - for index, subschema in enumerate(anyOf): - errs = list(validator.descend(instance, subschema, schema_path=index)) - if not errs: - break - all_errors.extend(errs) - else: - yield ValidationError( - f"{instance!r} is not valid under any of the given schemas", - context=all_errors, - ) - - -def oneOf(validator, oneOf, instance, schema): - subschemas = enumerate(oneOf) - all_errors = [] - for index, subschema in subschemas: - errs = list(validator.descend(instance, subschema, schema_path=index)) - if not errs: - first_valid = subschema - break - all_errors.extend(errs) - else: - yield ValidationError( - f"{instance!r} is not valid under any of the given schemas", - context=all_errors, - ) - - more_valid = [ - each for _, each in subschemas - if validator.evolve(schema=each).is_valid(instance) - ] - if more_valid: - more_valid.append(first_valid) - reprs = ", ".join(repr(schema) for schema in more_valid) - yield ValidationError(f"{instance!r} is valid under each of {reprs}") - - -def not_(validator, not_schema, instance, schema): - if validator.evolve(schema=not_schema).is_valid(instance): - message = f"{instance!r} should not be valid under {not_schema!r}" - yield ValidationError(message) - - -def if_(validator, if_schema, instance, schema): - if validator.evolve(schema=if_schema).is_valid(instance): - if "then" in schema: - then = schema["then"] - yield from validator.descend(instance, then, schema_path="then") - elif "else" in schema: - else_ = schema["else"] - yield from validator.descend(instance, else_, schema_path="else") - - -def unevaluatedItems(validator, unevaluatedItems, instance, schema): - if not validator.is_type(instance, "array"): - return - evaluated_item_indexes = find_evaluated_item_indexes_by_schema( - validator, instance, schema, - ) - unevaluated_items = [ - item for index, item in enumerate(instance) - if index not in evaluated_item_indexes - ] - if unevaluated_items: - error = "Unevaluated items are not allowed (%s %s unexpected)" - yield ValidationError(error % extras_msg(unevaluated_items)) - - -def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): - if not validator.is_type(instance, "object"): - return - evaluated_keys = find_evaluated_property_keys_by_schema( - validator, instance, schema, - ) - unevaluated_keys = [] - for property in instance: - if property not in evaluated_keys: - for _ in validator.descend( - instance[property], - unevaluatedProperties, - path=property, - schema_path=property, - ): - # FIXME: Include context for each unevaluated property - # indicating why it's invalid under the subschema. - unevaluated_keys.append(property) # noqa: PERF401 - - if unevaluated_keys: - if unevaluatedProperties is False: - error = "Unevaluated properties are not allowed (%s %s unexpected)" - extras = sorted(unevaluated_keys, key=str) - yield ValidationError(error % extras_msg(extras)) - else: - error = ( - "Unevaluated properties are not valid under " - "the given schema (%s %s unevaluated and invalid)" - ) - yield ValidationError(error % extras_msg(unevaluated_keys)) - - -def prefixItems(validator, prefixItems, instance, schema): - if not validator.is_type(instance, "array"): - return - - for (index, item), subschema in zip(enumerate(instance), prefixItems): - yield from validator.descend( - instance=item, - schema=subschema, - schema_path=index, - path=index, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_legacy_keywords.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_legacy_keywords.py deleted file mode 100644 index c691589..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_legacy_keywords.py +++ /dev/null @@ -1,449 +0,0 @@ -import re - -from referencing.jsonschema import lookup_recursive_ref - -from jsonschema import _utils -from jsonschema.exceptions import ValidationError - - -def ignore_ref_siblings(schema): - """ - Ignore siblings of ``$ref`` if it is present. - - Otherwise, return all keywords. - - Suitable for use with `create`'s ``applicable_validators`` argument. - """ - ref = schema.get("$ref") - if ref is not None: - return [("$ref", ref)] - else: - return schema.items() - - -def dependencies_draft3(validator, dependencies, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property, dependency in dependencies.items(): - if property not in instance: - continue - - if validator.is_type(dependency, "object"): - yield from validator.descend( - instance, dependency, schema_path=property, - ) - elif validator.is_type(dependency, "string"): - if dependency not in instance: - message = f"{dependency!r} is a dependency of {property!r}" - yield ValidationError(message) - else: - for each in dependency: - if each not in instance: - message = f"{each!r} is a dependency of {property!r}" - yield ValidationError(message) - - -def dependencies_draft4_draft6_draft7( - validator, - dependencies, - instance, - schema, -): - """ - Support for the ``dependencies`` keyword from pre-draft 2019-09. - - In later drafts, the keyword was split into separate - ``dependentRequired`` and ``dependentSchemas`` validators. - """ - if not validator.is_type(instance, "object"): - return - - for property, dependency in dependencies.items(): - if property not in instance: - continue - - if validator.is_type(dependency, "array"): - for each in dependency: - if each not in instance: - message = f"{each!r} is a dependency of {property!r}" - yield ValidationError(message) - else: - yield from validator.descend( - instance, dependency, schema_path=property, - ) - - -def disallow_draft3(validator, disallow, instance, schema): - for disallowed in _utils.ensure_list(disallow): - if validator.evolve(schema={"type": [disallowed]}).is_valid(instance): - message = f"{disallowed!r} is disallowed for {instance!r}" - yield ValidationError(message) - - -def extends_draft3(validator, extends, instance, schema): - if validator.is_type(extends, "object"): - yield from validator.descend(instance, extends) - return - for index, subschema in enumerate(extends): - yield from validator.descend(instance, subschema, schema_path=index) - - -def items_draft3_draft4(validator, items, instance, schema): - if not validator.is_type(instance, "array"): - return - - if validator.is_type(items, "object"): - for index, item in enumerate(instance): - yield from validator.descend(item, items, path=index) - else: - for (index, item), subschema in zip(enumerate(instance), items): - yield from validator.descend( - item, subschema, path=index, schema_path=index, - ) - - -def additionalItems(validator, aI, instance, schema): - if ( - not validator.is_type(instance, "array") - or validator.is_type(schema.get("items", {}), "object") - ): - return - - len_items = len(schema.get("items", [])) - if validator.is_type(aI, "object"): - for index, item in enumerate(instance[len_items:], start=len_items): - yield from validator.descend(item, aI, path=index) - elif not aI and len(instance) > len(schema.get("items", [])): - error = "Additional items are not allowed (%s %s unexpected)" - yield ValidationError( - error % _utils.extras_msg(instance[len(schema.get("items", [])):]), - ) - - -def items_draft6_draft7_draft201909(validator, items, instance, schema): - if not validator.is_type(instance, "array"): - return - - if validator.is_type(items, "array"): - for (index, item), subschema in zip(enumerate(instance), items): - yield from validator.descend( - item, subschema, path=index, schema_path=index, - ) - else: - for index, item in enumerate(instance): - yield from validator.descend(item, items, path=index) - - -def minimum_draft3_draft4(validator, minimum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if schema.get("exclusiveMinimum", False): - failed = instance <= minimum - cmp = "less than or equal to" - else: - failed = instance < minimum - cmp = "less than" - - if failed: - message = f"{instance!r} is {cmp} the minimum of {minimum!r}" - yield ValidationError(message) - - -def maximum_draft3_draft4(validator, maximum, instance, schema): - if not validator.is_type(instance, "number"): - return - - if schema.get("exclusiveMaximum", False): - failed = instance >= maximum - cmp = "greater than or equal to" - else: - failed = instance > maximum - cmp = "greater than" - - if failed: - message = f"{instance!r} is {cmp} the maximum of {maximum!r}" - yield ValidationError(message) - - -def properties_draft3(validator, properties, instance, schema): - if not validator.is_type(instance, "object"): - return - - for property, subschema in properties.items(): - if property in instance: - yield from validator.descend( - instance[property], - subschema, - path=property, - schema_path=property, - ) - elif subschema.get("required", False): - error = ValidationError(f"{property!r} is a required property") - error._set( - validator="required", - validator_value=subschema["required"], - instance=instance, - schema=schema, - ) - error.path.appendleft(property) - error.schema_path.extend([property, "required"]) - yield error - - -def type_draft3(validator, types, instance, schema): - types = _utils.ensure_list(types) - - all_errors = [] - for index, type in enumerate(types): - if validator.is_type(type, "object"): - errors = list(validator.descend(instance, type, schema_path=index)) - if not errors: - return - all_errors.extend(errors) - elif validator.is_type(instance, type): - return - - reprs = [] - for type in types: - try: - reprs.append(repr(type["name"])) - except Exception: # noqa: BLE001 - reprs.append(repr(type)) - yield ValidationError( - f"{instance!r} is not of type {', '.join(reprs)}", - context=all_errors, - ) - - -def contains_draft6_draft7(validator, contains, instance, schema): - if not validator.is_type(instance, "array"): - return - - if not any( - validator.evolve(schema=contains).is_valid(element) - for element in instance - ): - yield ValidationError( - f"None of {instance!r} are valid under the given schema", - ) - - -def recursiveRef(validator, recursiveRef, instance, schema): - resolved = lookup_recursive_ref(validator._resolver) - yield from validator.descend( - instance, - resolved.contents, - resolver=resolved.resolver, - ) - - -def find_evaluated_item_indexes_by_schema(validator, instance, schema): - """ - Get all indexes of items that get evaluated under the current schema. - - Covers all keywords related to unevaluatedItems: items, prefixItems, if, - then, else, contains, unevaluatedItems, allOf, oneOf, anyOf - """ - if validator.is_type(schema, "boolean"): - return [] - evaluated_indexes = [] - - ref = schema.get("$ref") - if ref is not None: - resolved = validator._resolver.lookup(ref) - evaluated_indexes.extend( - find_evaluated_item_indexes_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - if "$recursiveRef" in schema: - resolved = lookup_recursive_ref(validator._resolver) - evaluated_indexes.extend( - find_evaluated_item_indexes_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - if "items" in schema: - if "additionalItems" in schema: - return list(range(len(instance))) - - if validator.is_type(schema["items"], "object"): - return list(range(len(instance))) - evaluated_indexes += list(range(len(schema["items"]))) - - if "if" in schema: - if validator.evolve(schema=schema["if"]).is_valid(instance): - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["if"], - ) - if "then" in schema: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["then"], - ) - elif "else" in schema: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["else"], - ) - - for keyword in ["contains", "unevaluatedItems"]: - if keyword in schema: - for k, v in enumerate(instance): - if validator.evolve(schema=schema[keyword]).is_valid(v): - evaluated_indexes.append(k) - - for keyword in ["allOf", "oneOf", "anyOf"]: - if keyword in schema: - for subschema in schema[keyword]: - errs = next(validator.descend(instance, subschema), None) - if errs is None: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, subschema, - ) - - return evaluated_indexes - - -def unevaluatedItems_draft2019(validator, unevaluatedItems, instance, schema): - if not validator.is_type(instance, "array"): - return - evaluated_item_indexes = find_evaluated_item_indexes_by_schema( - validator, instance, schema, - ) - unevaluated_items = [ - item for index, item in enumerate(instance) - if index not in evaluated_item_indexes - ] - if unevaluated_items: - error = "Unevaluated items are not allowed (%s %s unexpected)" - yield ValidationError(error % _utils.extras_msg(unevaluated_items)) - - -def find_evaluated_property_keys_by_schema(validator, instance, schema): - if validator.is_type(schema, "boolean"): - return [] - evaluated_keys = [] - - ref = schema.get("$ref") - if ref is not None: - resolved = validator._resolver.lookup(ref) - evaluated_keys.extend( - find_evaluated_property_keys_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - if "$recursiveRef" in schema: - resolved = lookup_recursive_ref(validator._resolver) - evaluated_keys.extend( - find_evaluated_property_keys_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - for keyword in [ - "properties", "additionalProperties", "unevaluatedProperties", - ]: - if keyword in schema: - schema_value = schema[keyword] - if validator.is_type(schema_value, "boolean") and schema_value: - evaluated_keys += instance.keys() - - elif validator.is_type(schema_value, "object"): - for property in schema_value: - if property in instance: - evaluated_keys.append(property) - - if "patternProperties" in schema: - for property in instance: - for pattern in schema["patternProperties"]: - if re.search(pattern, property): - evaluated_keys.append(property) - - if "dependentSchemas" in schema: - for property, subschema in schema["dependentSchemas"].items(): - if property not in instance: - continue - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, subschema, - ) - - for keyword in ["allOf", "oneOf", "anyOf"]: - if keyword in schema: - for subschema in schema[keyword]: - errs = next(validator.descend(instance, subschema), None) - if errs is None: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, subschema, - ) - - if "if" in schema: - if validator.evolve(schema=schema["if"]).is_valid(instance): - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["if"], - ) - if "then" in schema: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["then"], - ) - elif "else" in schema: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["else"], - ) - - return evaluated_keys - - -def unevaluatedProperties_draft2019(validator, uP, instance, schema): - if not validator.is_type(instance, "object"): - return - evaluated_keys = find_evaluated_property_keys_by_schema( - validator, instance, schema, - ) - unevaluated_keys = [] - for property in instance: - if property not in evaluated_keys: - for _ in validator.descend( - instance[property], - uP, - path=property, - schema_path=property, - ): - # FIXME: Include context for each unevaluated property - # indicating why it's invalid under the subschema. - unevaluated_keys.append(property) # noqa: PERF401 - - if unevaluated_keys: - if uP is False: - error = "Unevaluated properties are not allowed (%s %s unexpected)" - extras = sorted(unevaluated_keys, key=str) - yield ValidationError(error % _utils.extras_msg(extras)) - else: - error = ( - "Unevaluated properties are not valid under " - "the given schema (%s %s unevaluated and invalid)" - ) - yield ValidationError(error % _utils.extras_msg(unevaluated_keys)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_types.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_types.py deleted file mode 100644 index bf25e7e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_types.py +++ /dev/null @@ -1,200 +0,0 @@ -from __future__ import annotations - -from typing import Any, Callable, Mapping -import numbers - -from attrs import evolve, field, frozen -from rpds import HashTrieMap - -from jsonschema.exceptions import UndefinedTypeCheck - - -# unfortunately, the type of HashTrieMap is generic, and if used as an attrs -# converter, the generic type is presented to mypy, which then fails to match -# the concrete type of a type checker mapping -# this "do nothing" wrapper presents the correct information to mypy -def _typed_map_converter( - init_val: Mapping[str, Callable[[TypeChecker, Any], bool]], -) -> HashTrieMap[str, Callable[[TypeChecker, Any], bool]]: - return HashTrieMap.convert(init_val) - - -def is_array(checker, instance): - return isinstance(instance, list) - - -def is_bool(checker, instance): - return isinstance(instance, bool) - - -def is_integer(checker, instance): - # bool inherits from int, so ensure bools aren't reported as ints - if isinstance(instance, bool): - return False - return isinstance(instance, int) - - -def is_null(checker, instance): - return instance is None - - -def is_number(checker, instance): - # bool inherits from int, so ensure bools aren't reported as ints - if isinstance(instance, bool): - return False - return isinstance(instance, numbers.Number) - - -def is_object(checker, instance): - return isinstance(instance, dict) - - -def is_string(checker, instance): - return isinstance(instance, str) - - -def is_any(checker, instance): - return True - - -@frozen(repr=False) -class TypeChecker: - """ - A :kw:`type` property checker. - - A `TypeChecker` performs type checking for a `Validator`, converting - between the defined JSON Schema types and some associated Python types or - objects. - - Modifying the behavior just mentioned by redefining which Python objects - are considered to be of which JSON Schema types can be done using - `TypeChecker.redefine` or `TypeChecker.redefine_many`, and types can be - removed via `TypeChecker.remove`. Each of these return a new `TypeChecker`. - - Arguments: - - type_checkers: - - The initial mapping of types to their checking functions. - - """ - - _type_checkers: HashTrieMap[ - str, Callable[[TypeChecker, Any], bool], - ] = field(default=HashTrieMap(), converter=_typed_map_converter) - - def __repr__(self): - types = ", ".join(repr(k) for k in sorted(self._type_checkers)) - return f"<{self.__class__.__name__} types={{{types}}}>" - - def is_type(self, instance, type: str) -> bool: - """ - Check if the instance is of the appropriate type. - - Arguments: - - instance: - - The instance to check - - type: - - The name of the type that is expected. - - Raises: - - `jsonschema.exceptions.UndefinedTypeCheck`: - - if ``type`` is unknown to this object. - - """ - try: - fn = self._type_checkers[type] - except KeyError: - raise UndefinedTypeCheck(type) from None - - return fn(self, instance) - - def redefine(self, type: str, fn) -> TypeChecker: - """ - Produce a new checker with the given type redefined. - - Arguments: - - type: - - The name of the type to check. - - fn (collections.abc.Callable): - - A callable taking exactly two parameters - the type - checker calling the function and the instance to check. - The function should return true if instance is of this - type and false otherwise. - - """ - return self.redefine_many({type: fn}) - - def redefine_many(self, definitions=()) -> TypeChecker: - """ - Produce a new checker with the given types redefined. - - Arguments: - - definitions (dict): - - A dictionary mapping types to their checking functions. - - """ - type_checkers = self._type_checkers.update(definitions) - return evolve(self, type_checkers=type_checkers) - - def remove(self, *types) -> TypeChecker: - """ - Produce a new checker with the given types forgotten. - - Arguments: - - types: - - the names of the types to remove. - - Raises: - - `jsonschema.exceptions.UndefinedTypeCheck`: - - if any given type is unknown to this object - - """ - type_checkers = self._type_checkers - for each in types: - try: - type_checkers = type_checkers.remove(each) - except KeyError: - raise UndefinedTypeCheck(each) from None - return evolve(self, type_checkers=type_checkers) - - -draft3_type_checker = TypeChecker( - { - "any": is_any, - "array": is_array, - "boolean": is_bool, - "integer": is_integer, - "object": is_object, - "null": is_null, - "number": is_number, - "string": is_string, - }, -) -draft4_type_checker = draft3_type_checker.remove("any") -draft6_type_checker = draft4_type_checker.redefine( - "integer", - lambda checker, instance: ( - is_integer(checker, instance) - or isinstance(instance, float) and instance.is_integer() - ), -) -draft7_type_checker = draft6_type_checker -draft201909_type_checker = draft7_type_checker -draft202012_type_checker = draft201909_type_checker diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_typing.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_typing.py deleted file mode 100644 index d283dc4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_typing.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -Some (initially private) typing helpers for jsonschema's types. -""" -from typing import Any, Callable, Iterable, Protocol, Tuple, Union - -import referencing.jsonschema - -from jsonschema.protocols import Validator - - -class SchemaKeywordValidator(Protocol): - def __call__( - self, - validator: Validator, - value: Any, - instance: Any, - schema: referencing.jsonschema.Schema, - ) -> None: - ... - - -id_of = Callable[[referencing.jsonschema.Schema], Union[str, None]] - - -ApplicableValidators = Callable[ - [referencing.jsonschema.Schema], - Iterable[Tuple[str, Any]], -] diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/_utils.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/_utils.py deleted file mode 100644 index 54d28c0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/_utils.py +++ /dev/null @@ -1,351 +0,0 @@ -from collections.abc import Mapping, MutableMapping, Sequence -from urllib.parse import urlsplit -import itertools -import re - - -class URIDict(MutableMapping): - """ - Dictionary which uses normalized URIs as keys. - """ - - def normalize(self, uri): - return urlsplit(uri).geturl() - - def __init__(self, *args, **kwargs): - self.store = dict() - self.store.update(*args, **kwargs) - - def __getitem__(self, uri): - return self.store[self.normalize(uri)] - - def __setitem__(self, uri, value): - self.store[self.normalize(uri)] = value - - def __delitem__(self, uri): - del self.store[self.normalize(uri)] - - def __iter__(self): - return iter(self.store) - - def __len__(self): # pragma: no cover -- untested, but to be removed - return len(self.store) - - def __repr__(self): # pragma: no cover -- untested, but to be removed - return repr(self.store) - - -class Unset: - """ - An as-of-yet unset attribute or unprovided default parameter. - """ - - def __repr__(self): # pragma: no cover - return "" - - -def format_as_index(container, indices): - """ - Construct a single string containing indexing operations for the indices. - - For example for a container ``bar``, [1, 2, "foo"] -> bar[1][2]["foo"] - - Arguments: - - container (str): - - A word to use for the thing being indexed - - indices (sequence): - - The indices to format. - - """ - if not indices: - return container - return f"{container}[{']['.join(repr(index) for index in indices)}]" - - -def find_additional_properties(instance, schema): - """ - Return the set of additional properties for the given ``instance``. - - Weeds out properties that should have been validated by ``properties`` and - / or ``patternProperties``. - - Assumes ``instance`` is dict-like already. - """ - properties = schema.get("properties", {}) - patterns = "|".join(schema.get("patternProperties", {})) - for property in instance: - if property not in properties: - if patterns and re.search(patterns, property): - continue - yield property - - -def extras_msg(extras): - """ - Create an error message for extra items or properties. - """ - verb = "was" if len(extras) == 1 else "were" - return ", ".join(repr(extra) for extra in extras), verb - - -def ensure_list(thing): - """ - Wrap ``thing`` in a list if it's a single str. - - Otherwise, return it unchanged. - """ - if isinstance(thing, str): - return [thing] - return thing - - -def _mapping_equal(one, two): - """ - Check if two mappings are equal using the semantics of `equal`. - """ - if len(one) != len(two): - return False - return all( - key in two and equal(value, two[key]) - for key, value in one.items() - ) - - -def _sequence_equal(one, two): - """ - Check if two sequences are equal using the semantics of `equal`. - """ - if len(one) != len(two): - return False - return all(equal(i, j) for i, j in zip(one, two)) - - -def equal(one, two): - """ - Check if two things are equal evading some Python type hierarchy semantics. - - Specifically in JSON Schema, evade `bool` inheriting from `int`, - recursing into sequences to do the same. - """ - if one is two: - return True - if isinstance(one, str) or isinstance(two, str): - return one == two - if isinstance(one, Sequence) and isinstance(two, Sequence): - return _sequence_equal(one, two) - if isinstance(one, Mapping) and isinstance(two, Mapping): - return _mapping_equal(one, two) - return unbool(one) == unbool(two) - - -def unbool(element, true=object(), false=object()): - """ - A hack to make True and 1 and False and 0 unique for ``uniq``. - """ - if element is True: - return true - elif element is False: - return false - return element - - -def uniq(container): - """ - Check if all of a container's elements are unique. - - Tries to rely on the container being recursively sortable, or otherwise - falls back on (slow) brute force. - """ - try: - sort = sorted(unbool(i) for i in container) - sliced = itertools.islice(sort, 1, None) - - for i, j in zip(sort, sliced): - if equal(i, j): - return False - - except (NotImplementedError, TypeError): - seen = [] - for e in container: - e = unbool(e) - - for i in seen: - if equal(i, e): - return False - - seen.append(e) - return True - - -def find_evaluated_item_indexes_by_schema(validator, instance, schema): - """ - Get all indexes of items that get evaluated under the current schema. - - Covers all keywords related to unevaluatedItems: items, prefixItems, if, - then, else, contains, unevaluatedItems, allOf, oneOf, anyOf - """ - if validator.is_type(schema, "boolean"): - return [] - evaluated_indexes = [] - - if "items" in schema: - return list(range(len(instance))) - - ref = schema.get("$ref") - if ref is not None: - resolved = validator._resolver.lookup(ref) - evaluated_indexes.extend( - find_evaluated_item_indexes_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - dynamicRef = schema.get("$dynamicRef") - if dynamicRef is not None: - resolved = validator._resolver.lookup(dynamicRef) - evaluated_indexes.extend( - find_evaluated_item_indexes_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - if "prefixItems" in schema: - evaluated_indexes += list(range(len(schema["prefixItems"]))) - - if "if" in schema: - if validator.evolve(schema=schema["if"]).is_valid(instance): - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["if"], - ) - if "then" in schema: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["then"], - ) - elif "else" in schema: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, schema["else"], - ) - - for keyword in ["contains", "unevaluatedItems"]: - if keyword in schema: - for k, v in enumerate(instance): - if validator.evolve(schema=schema[keyword]).is_valid(v): - evaluated_indexes.append(k) - - for keyword in ["allOf", "oneOf", "anyOf"]: - if keyword in schema: - for subschema in schema[keyword]: - errs = next(validator.descend(instance, subschema), None) - if errs is None: - evaluated_indexes += find_evaluated_item_indexes_by_schema( - validator, instance, subschema, - ) - - return evaluated_indexes - - -def find_evaluated_property_keys_by_schema(validator, instance, schema): - """ - Get all keys of items that get evaluated under the current schema. - - Covers all keywords related to unevaluatedProperties: properties, - additionalProperties, unevaluatedProperties, patternProperties, - dependentSchemas, allOf, oneOf, anyOf, if, then, else - """ - if validator.is_type(schema, "boolean"): - return [] - evaluated_keys = [] - - ref = schema.get("$ref") - if ref is not None: - resolved = validator._resolver.lookup(ref) - evaluated_keys.extend( - find_evaluated_property_keys_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - dynamicRef = schema.get("$dynamicRef") - if dynamicRef is not None: - resolved = validator._resolver.lookup(dynamicRef) - evaluated_keys.extend( - find_evaluated_property_keys_by_schema( - validator.evolve( - schema=resolved.contents, - _resolver=resolved.resolver, - ), - instance, - resolved.contents, - ), - ) - - for keyword in [ - "properties", "additionalProperties", "unevaluatedProperties", - ]: - if keyword in schema: - schema_value = schema[keyword] - if validator.is_type(schema_value, "boolean") and schema_value: - evaluated_keys += instance.keys() - - elif validator.is_type(schema_value, "object"): - for property in schema_value: - if property in instance: - evaluated_keys.append(property) - - if "patternProperties" in schema: - for property in instance: - for pattern in schema["patternProperties"]: - if re.search(pattern, property): - evaluated_keys.append(property) - - if "dependentSchemas" in schema: - for property, subschema in schema["dependentSchemas"].items(): - if property not in instance: - continue - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, subschema, - ) - - for keyword in ["allOf", "oneOf", "anyOf"]: - if keyword in schema: - for subschema in schema[keyword]: - errs = next(validator.descend(instance, subschema), None) - if errs is None: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, subschema, - ) - - if "if" in schema: - if validator.evolve(schema=schema["if"]).is_valid(instance): - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["if"], - ) - if "then" in schema: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["then"], - ) - elif "else" in schema: - evaluated_keys += find_evaluated_property_keys_by_schema( - validator, instance, schema["else"], - ) - - return evaluated_keys diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/__init__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/__init__.py deleted file mode 100644 index e3dcc68..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -Benchmarks for validation. - -This package is *not* public API. -""" diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/const_vs_enum.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/const_vs_enum.py deleted file mode 100644 index c6fecd1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/const_vs_enum.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -A benchmark for comparing equivalent validation of `const` and `enum`. -""" - -from pyperf import Runner - -from jsonschema import Draft202012Validator - -value = [37] * 100 -const_schema = {"const": list(value)} -enum_schema = {"enum": [list(value)]} - -valid = list(value) -invalid = [*valid, 73] - -const = Draft202012Validator(const_schema) -enum = Draft202012Validator(enum_schema) - -assert const.is_valid(valid) -assert enum.is_valid(valid) -assert not const.is_valid(invalid) -assert not enum.is_valid(invalid) - - -if __name__ == "__main__": - runner = Runner() - runner.bench_func("const valid", lambda: const.is_valid(valid)) - runner.bench_func("const invalid", lambda: const.is_valid(invalid)) - runner.bench_func("enum valid", lambda: enum.is_valid(valid)) - runner.bench_func("enum invalid", lambda: enum.is_valid(invalid)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/contains.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/contains.py deleted file mode 100644 index 739cd04..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/contains.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -A benchmark for validation of the `contains` keyword. -""" - -from pyperf import Runner - -from jsonschema import Draft202012Validator - -schema = { - "type": "array", - "contains": {"const": 37}, -} -validator = Draft202012Validator(schema) - -size = 1000 -beginning = [37] + [0] * (size - 1) -middle = [0] * (size // 2) + [37] + [0] * (size // 2) -end = [0] * (size - 1) + [37] -invalid = [0] * size - - -if __name__ == "__main__": - runner = Runner() - runner.bench_func("baseline", lambda: validator.is_valid([])) - runner.bench_func("beginning", lambda: validator.is_valid(beginning)) - runner.bench_func("middle", lambda: validator.is_valid(middle)) - runner.bench_func("end", lambda: validator.is_valid(end)) - runner.bench_func("invalid", lambda: validator.is_valid(invalid)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232.py deleted file mode 100644 index efd0715..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -A performance benchmark using the example from issue #232. - -See https://github.com/python-jsonschema/jsonschema/pull/232. -""" -from pathlib import Path - -from pyperf import Runner -from referencing import Registry - -from jsonschema.tests._suite import Version -import jsonschema - -issue232 = Version( - path=Path(__file__).parent / "issue232", - remotes=Registry(), - name="issue232", -) - - -if __name__ == "__main__": - issue232.benchmark( - runner=Runner(), - Validator=jsonschema.Draft4Validator, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232/issue.json b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232/issue.json deleted file mode 100644 index 804c340..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/issue232/issue.json +++ /dev/null @@ -1,2653 +0,0 @@ -[ - { - "description": "Petstore", - "schema": { - "title": "A JSON Schema for Swagger 2.0 API.", - "id": "http://swagger.io/v2/schema.json#", - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "required": [ - "swagger", - "info", - "paths" - ], - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "swagger": { - "type": "string", - "enum": [ - "2.0" - ], - "description": "The Swagger version of this document." - }, - "info": { - "$ref": "#/definitions/info" - }, - "host": { - "type": "string", - "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", - "description": "The host (name or ip) of the API. Example: 'swagger.io'" - }, - "basePath": { - "type": "string", - "pattern": "^/", - "description": "The base path to the API. Example: '/api'." - }, - "schemes": { - "$ref": "#/definitions/schemesList" - }, - "consumes": { - "description": "A list of MIME types accepted by the API.", - "allOf": [ - { - "$ref": "#/definitions/mediaTypeList" - } - ] - }, - "produces": { - "description": "A list of MIME types the API can produce.", - "allOf": [ - { - "$ref": "#/definitions/mediaTypeList" - } - ] - }, - "paths": { - "$ref": "#/definitions/paths" - }, - "definitions": { - "$ref": "#/definitions/definitions" - }, - "parameters": { - "$ref": "#/definitions/parameterDefinitions" - }, - "responses": { - "$ref": "#/definitions/responseDefinitions" - }, - "security": { - "$ref": "#/definitions/security" - }, - "securityDefinitions": { - "$ref": "#/definitions/securityDefinitions" - }, - "tags": { - "type": "array", - "items": { - "$ref": "#/definitions/tag" - }, - "uniqueItems": true - }, - "externalDocs": { - "$ref": "#/definitions/externalDocs" - } - }, - "definitions": { - "info": { - "type": "object", - "description": "General information about the API.", - "required": [ - "version", - "title" - ], - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "title": { - "type": "string", - "description": "A unique and precise title of the API." - }, - "version": { - "type": "string", - "description": "A semantic version number of the API." - }, - "description": { - "type": "string", - "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." - }, - "termsOfService": { - "type": "string", - "description": "The terms of service for the API." - }, - "contact": { - "$ref": "#/definitions/contact" - }, - "license": { - "$ref": "#/definitions/license" - } - } - }, - "contact": { - "type": "object", - "description": "Contact information for the owners of the API.", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "The identifying name of the contact person/organization." - }, - "url": { - "type": "string", - "description": "The URL pointing to the contact information.", - "format": "uri" - }, - "email": { - "type": "string", - "description": "The email address of the contact person/organization.", - "format": "email" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "license": { - "type": "object", - "required": [ - "name" - ], - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "The name of the license type. It's encouraged to use an OSI compatible license." - }, - "url": { - "type": "string", - "description": "The URL pointing to the license.", - "format": "uri" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "paths": { - "type": "object", - "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - }, - "^/": { - "$ref": "#/definitions/pathItem" - } - }, - "additionalProperties": false - }, - "definitions": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/schema" - }, - "description": "One or more JSON objects describing the schemas being consumed and produced by the API." - }, - "parameterDefinitions": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/parameter" - }, - "description": "One or more JSON representations for parameters" - }, - "responseDefinitions": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/response" - }, - "description": "One or more JSON representations for parameters" - }, - "externalDocs": { - "type": "object", - "additionalProperties": false, - "description": "information about external documentation", - "required": [ - "url" - ], - "properties": { - "description": { - "type": "string" - }, - "url": { - "type": "string", - "format": "uri" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "examples": { - "type": "object", - "additionalProperties": true - }, - "mimeType": { - "type": "string", - "description": "The MIME type of the HTTP message." - }, - "operation": { - "type": "object", - "required": [ - "responses" - ], - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - }, - "summary": { - "type": "string", - "description": "A brief summary of the operation." - }, - "description": { - "type": "string", - "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." - }, - "externalDocs": { - "$ref": "#/definitions/externalDocs" - }, - "operationId": { - "type": "string", - "description": "A unique identifier of the operation." - }, - "produces": { - "description": "A list of MIME types the API can produce.", - "allOf": [ - { - "$ref": "#/definitions/mediaTypeList" - } - ] - }, - "consumes": { - "description": "A list of MIME types the API can consume.", - "allOf": [ - { - "$ref": "#/definitions/mediaTypeList" - } - ] - }, - "parameters": { - "$ref": "#/definitions/parametersList" - }, - "responses": { - "$ref": "#/definitions/responses" - }, - "schemes": { - "$ref": "#/definitions/schemesList" - }, - "deprecated": { - "type": "boolean", - "default": false - }, - "security": { - "$ref": "#/definitions/security" - } - } - }, - "pathItem": { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "$ref": { - "type": "string" - }, - "get": { - "$ref": "#/definitions/operation" - }, - "put": { - "$ref": "#/definitions/operation" - }, - "post": { - "$ref": "#/definitions/operation" - }, - "delete": { - "$ref": "#/definitions/operation" - }, - "options": { - "$ref": "#/definitions/operation" - }, - "head": { - "$ref": "#/definitions/operation" - }, - "patch": { - "$ref": "#/definitions/operation" - }, - "parameters": { - "$ref": "#/definitions/parametersList" - } - } - }, - "responses": { - "type": "object", - "description": "Response objects names can either be any valid HTTP status code or 'default'.", - "minProperties": 1, - "additionalProperties": false, - "patternProperties": { - "^([0-9]{3})$|^(default)$": { - "$ref": "#/definitions/responseValue" - }, - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "not": { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - } - }, - "responseValue": { - "oneOf": [ - { - "$ref": "#/definitions/response" - }, - { - "$ref": "#/definitions/jsonReference" - } - ] - }, - "response": { - "type": "object", - "required": [ - "description" - ], - "properties": { - "description": { - "type": "string" - }, - "schema": { - "oneOf": [ - { - "$ref": "#/definitions/schema" - }, - { - "$ref": "#/definitions/fileSchema" - } - ] - }, - "headers": { - "$ref": "#/definitions/headers" - }, - "examples": { - "$ref": "#/definitions/examples" - } - }, - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "headers": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/header" - } - }, - "header": { - "type": "object", - "additionalProperties": false, - "required": [ - "type" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "string", - "number", - "integer", - "boolean", - "array" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormat" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "vendorExtension": { - "description": "Any property starting with x- is valid.", - "additionalProperties": true, - "additionalItems": true - }, - "bodyParameter": { - "type": "object", - "required": [ - "name", - "in", - "schema" - ], - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "description": { - "type": "string", - "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." - }, - "name": { - "type": "string", - "description": "The name of the parameter." - }, - "in": { - "type": "string", - "description": "Determines the location of the parameter.", - "enum": [ - "body" - ] - }, - "required": { - "type": "boolean", - "description": "Determines whether or not this parameter is required or optional.", - "default": false - }, - "schema": { - "$ref": "#/definitions/schema" - } - }, - "additionalProperties": false - }, - "headerParameterSubSchema": { - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "required": { - "type": "boolean", - "description": "Determines whether or not this parameter is required or optional.", - "default": false - }, - "in": { - "type": "string", - "description": "Determines the location of the parameter.", - "enum": [ - "header" - ] - }, - "description": { - "type": "string", - "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." - }, - "name": { - "type": "string", - "description": "The name of the parameter." - }, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormat" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - } - } - }, - "queryParameterSubSchema": { - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "required": { - "type": "boolean", - "description": "Determines whether or not this parameter is required or optional.", - "default": false - }, - "in": { - "type": "string", - "description": "Determines the location of the parameter.", - "enum": [ - "query" - ] - }, - "description": { - "type": "string", - "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." - }, - "name": { - "type": "string", - "description": "The name of the parameter." - }, - "allowEmptyValue": { - "type": "boolean", - "default": false, - "description": "allows sending a parameter by name only or with an empty value." - }, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormatWithMulti" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - } - } - }, - "formDataParameterSubSchema": { - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "required": { - "type": "boolean", - "description": "Determines whether or not this parameter is required or optional.", - "default": false - }, - "in": { - "type": "string", - "description": "Determines the location of the parameter.", - "enum": [ - "formData" - ] - }, - "description": { - "type": "string", - "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." - }, - "name": { - "type": "string", - "description": "The name of the parameter." - }, - "allowEmptyValue": { - "type": "boolean", - "default": false, - "description": "allows sending a parameter by name only or with an empty value." - }, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array", - "file" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormatWithMulti" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - } - } - }, - "pathParameterSubSchema": { - "additionalProperties": false, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "required": [ - "required" - ], - "properties": { - "required": { - "type": "boolean", - "enum": [ - true - ], - "description": "Determines whether or not this parameter is required or optional." - }, - "in": { - "type": "string", - "description": "Determines the location of the parameter.", - "enum": [ - "path" - ] - }, - "description": { - "type": "string", - "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." - }, - "name": { - "type": "string", - "description": "The name of the parameter." - }, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormat" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - } - } - }, - "nonBodyParameter": { - "type": "object", - "required": [ - "name", - "in", - "type" - ], - "oneOf": [ - { - "$ref": "#/definitions/headerParameterSubSchema" - }, - { - "$ref": "#/definitions/formDataParameterSubSchema" - }, - { - "$ref": "#/definitions/queryParameterSubSchema" - }, - { - "$ref": "#/definitions/pathParameterSubSchema" - } - ] - }, - "parameter": { - "oneOf": [ - { - "$ref": "#/definitions/bodyParameter" - }, - { - "$ref": "#/definitions/nonBodyParameter" - } - ] - }, - "schema": { - "type": "object", - "description": "A deterministic version of a JSON Schema object.", - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "properties": { - "$ref": { - "type": "string" - }, - "format": { - "type": "string" - }, - "title": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/title" - }, - "description": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/description" - }, - "default": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/default" - }, - "multipleOf": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" - }, - "maximum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" - }, - "exclusiveMaximum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" - }, - "minimum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" - }, - "exclusiveMinimum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" - }, - "maxLength": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" - }, - "minLength": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" - }, - "pattern": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" - }, - "maxItems": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" - }, - "minItems": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" - }, - "uniqueItems": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" - }, - "maxProperties": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" - }, - "minProperties": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" - }, - "required": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" - }, - "enum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" - }, - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/definitions/schema" - }, - { - "type": "boolean" - } - ], - "default": {} - }, - "type": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/type" - }, - "items": { - "anyOf": [ - { - "$ref": "#/definitions/schema" - }, - { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/definitions/schema" - } - } - ], - "default": {} - }, - "allOf": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/definitions/schema" - } - }, - "properties": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/schema" - }, - "default": {} - }, - "discriminator": { - "type": "string" - }, - "readOnly": { - "type": "boolean", - "default": false - }, - "xml": { - "$ref": "#/definitions/xml" - }, - "externalDocs": { - "$ref": "#/definitions/externalDocs" - }, - "example": {} - }, - "additionalProperties": false - }, - "fileSchema": { - "type": "object", - "description": "A deterministic version of a JSON Schema object.", - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - }, - "required": [ - "type" - ], - "properties": { - "format": { - "type": "string" - }, - "title": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/title" - }, - "description": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/description" - }, - "default": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/default" - }, - "required": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" - }, - "type": { - "type": "string", - "enum": [ - "file" - ] - }, - "readOnly": { - "type": "boolean", - "default": false - }, - "externalDocs": { - "$ref": "#/definitions/externalDocs" - }, - "example": {} - }, - "additionalProperties": false - }, - "primitivesItems": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "type": "string", - "enum": [ - "string", - "number", - "integer", - "boolean", - "array" - ] - }, - "format": { - "type": "string" - }, - "items": { - "$ref": "#/definitions/primitivesItems" - }, - "collectionFormat": { - "$ref": "#/definitions/collectionFormat" - }, - "default": { - "$ref": "#/definitions/default" - }, - "maximum": { - "$ref": "#/definitions/maximum" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/exclusiveMaximum" - }, - "minimum": { - "$ref": "#/definitions/minimum" - }, - "exclusiveMinimum": { - "$ref": "#/definitions/exclusiveMinimum" - }, - "maxLength": { - "$ref": "#/definitions/maxLength" - }, - "minLength": { - "$ref": "#/definitions/minLength" - }, - "pattern": { - "$ref": "#/definitions/pattern" - }, - "maxItems": { - "$ref": "#/definitions/maxItems" - }, - "minItems": { - "$ref": "#/definitions/minItems" - }, - "uniqueItems": { - "$ref": "#/definitions/uniqueItems" - }, - "enum": { - "$ref": "#/definitions/enum" - }, - "multipleOf": { - "$ref": "#/definitions/multipleOf" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "security": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRequirement" - }, - "uniqueItems": true - }, - "securityRequirement": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - } - }, - "xml": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "namespace": { - "type": "string" - }, - "prefix": { - "type": "string" - }, - "attribute": { - "type": "boolean", - "default": false - }, - "wrapped": { - "type": "boolean", - "default": false - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "tag": { - "type": "object", - "additionalProperties": false, - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "externalDocs": { - "$ref": "#/definitions/externalDocs" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "securityDefinitions": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/basicAuthenticationSecurity" - }, - { - "$ref": "#/definitions/apiKeySecurity" - }, - { - "$ref": "#/definitions/oauth2ImplicitSecurity" - }, - { - "$ref": "#/definitions/oauth2PasswordSecurity" - }, - { - "$ref": "#/definitions/oauth2ApplicationSecurity" - }, - { - "$ref": "#/definitions/oauth2AccessCodeSecurity" - } - ] - } - }, - "basicAuthenticationSecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "basic" - ] - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "apiKeySecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type", - "name", - "in" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "apiKey" - ] - }, - "name": { - "type": "string" - }, - "in": { - "type": "string", - "enum": [ - "header", - "query" - ] - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "oauth2ImplicitSecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type", - "flow", - "authorizationUrl" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "oauth2" - ] - }, - "flow": { - "type": "string", - "enum": [ - "implicit" - ] - }, - "scopes": { - "$ref": "#/definitions/oauth2Scopes" - }, - "authorizationUrl": { - "type": "string", - "format": "uri" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "oauth2PasswordSecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type", - "flow", - "tokenUrl" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "oauth2" - ] - }, - "flow": { - "type": "string", - "enum": [ - "password" - ] - }, - "scopes": { - "$ref": "#/definitions/oauth2Scopes" - }, - "tokenUrl": { - "type": "string", - "format": "uri" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "oauth2ApplicationSecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type", - "flow", - "tokenUrl" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "oauth2" - ] - }, - "flow": { - "type": "string", - "enum": [ - "application" - ] - }, - "scopes": { - "$ref": "#/definitions/oauth2Scopes" - }, - "tokenUrl": { - "type": "string", - "format": "uri" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "oauth2AccessCodeSecurity": { - "type": "object", - "additionalProperties": false, - "required": [ - "type", - "flow", - "authorizationUrl", - "tokenUrl" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "oauth2" - ] - }, - "flow": { - "type": "string", - "enum": [ - "accessCode" - ] - }, - "scopes": { - "$ref": "#/definitions/oauth2Scopes" - }, - "authorizationUrl": { - "type": "string", - "format": "uri" - }, - "tokenUrl": { - "type": "string", - "format": "uri" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": { - "$ref": "#/definitions/vendorExtension" - } - } - }, - "oauth2Scopes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "mediaTypeList": { - "type": "array", - "items": { - "$ref": "#/definitions/mimeType" - }, - "uniqueItems": true - }, - "parametersList": { - "type": "array", - "description": "The parameters needed to send a valid API call.", - "additionalItems": false, - "items": { - "oneOf": [ - { - "$ref": "#/definitions/parameter" - }, - { - "$ref": "#/definitions/jsonReference" - } - ] - }, - "uniqueItems": true - }, - "schemesList": { - "type": "array", - "description": "The transfer protocol of the API.", - "items": { - "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss" - ] - }, - "uniqueItems": true - }, - "collectionFormat": { - "type": "string", - "enum": [ - "csv", - "ssv", - "tsv", - "pipes" - ], - "default": "csv" - }, - "collectionFormatWithMulti": { - "type": "string", - "enum": [ - "csv", - "ssv", - "tsv", - "pipes", - "multi" - ], - "default": "csv" - }, - "title": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/title" - }, - "description": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/description" - }, - "default": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/default" - }, - "multipleOf": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" - }, - "maximum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" - }, - "exclusiveMaximum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" - }, - "minimum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" - }, - "exclusiveMinimum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" - }, - "maxLength": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" - }, - "minLength": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" - }, - "pattern": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" - }, - "maxItems": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" - }, - "minItems": { - "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" - }, - "uniqueItems": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" - }, - "enum": { - "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" - }, - "jsonReference": { - "type": "object", - "required": [ - "$ref" - ], - "additionalProperties": false, - "properties": { - "$ref": { - "type": "string" - } - } - } - } - }, - "tests": [ - { - "description": "Example petsore", - "data": { - "swagger": "2.0", - "info": { - "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", - "version": "1.0.0", - "title": "Swagger Petstore", - "termsOfService": "http://swagger.io/terms/", - "contact": { - "email": "apiteam@swagger.io" - }, - "license": { - "name": "Apache 2.0", - "url": "http://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "host": "petstore.swagger.io", - "basePath": "/v2", - "tags": [ - { - "name": "pet", - "description": "Everything about your Pets", - "externalDocs": { - "description": "Find out more", - "url": "http://swagger.io" - } - }, - { - "name": "store", - "description": "Access to Petstore orders" - }, - { - "name": "user", - "description": "Operations about user", - "externalDocs": { - "description": "Find out more about our store", - "url": "http://swagger.io" - } - } - ], - "schemes": [ - "http" - ], - "paths": { - "/pet": { - "post": { - "tags": [ - "pet" - ], - "summary": "Add a new pet to the store", - "description": "", - "operationId": "addPet", - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "Pet object that needs to be added to the store", - "required": true, - "schema": { - "$ref": "#/definitions/Pet" - } - } - ], - "responses": { - "405": { - "description": "Invalid input" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - }, - "put": { - "tags": [ - "pet" - ], - "summary": "Update an existing pet", - "description": "", - "operationId": "updatePet", - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "Pet object that needs to be added to the store", - "required": true, - "schema": { - "$ref": "#/definitions/Pet" - } - } - ], - "responses": { - "400": { - "description": "Invalid ID supplied" - }, - "404": { - "description": "Pet not found" - }, - "405": { - "description": "Validation exception" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, - "/pet/findByStatus": { - "get": { - "tags": [ - "pet" - ], - "summary": "Finds Pets by status", - "description": "Multiple status values can be provided with comma separated strings", - "operationId": "findPetsByStatus", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "status", - "in": "query", - "description": "Status values that need to be considered for filter", - "required": true, - "type": "array", - "items": { - "type": "string", - "enum": [ - "available", - "pending", - "sold" - ], - "default": "available" - }, - "collectionFormat": "multi" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/Pet" - } - } - }, - "400": { - "description": "Invalid status value" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, - "/pet/findByTags": { - "get": { - "tags": [ - "pet" - ], - "summary": "Finds Pets by tags", - "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", - "operationId": "findPetsByTags", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "tags", - "in": "query", - "description": "Tags to filter by", - "required": true, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/Pet" - } - } - }, - "400": { - "description": "Invalid tag value" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ], - "deprecated": true - } - }, - "/pet/{petId}": { - "get": { - "tags": [ - "pet" - ], - "summary": "Find pet by ID", - "description": "Returns a single pet", - "operationId": "getPetById", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "petId", - "in": "path", - "description": "ID of pet to return", - "required": true, - "type": "integer", - "format": "int64" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "$ref": "#/definitions/Pet" - } - }, - "400": { - "description": "Invalid ID supplied" - }, - "404": { - "description": "Pet not found" - } - }, - "security": [ - { - "api_key": [] - } - ] - }, - "post": { - "tags": [ - "pet" - ], - "summary": "Updates a pet in the store with form data", - "description": "", - "operationId": "updatePetWithForm", - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "petId", - "in": "path", - "description": "ID of pet that needs to be updated", - "required": true, - "type": "integer", - "format": "int64" - }, - { - "name": "name", - "in": "formData", - "description": "Updated name of the pet", - "required": false, - "type": "string" - }, - { - "name": "status", - "in": "formData", - "description": "Updated status of the pet", - "required": false, - "type": "string" - } - ], - "responses": { - "405": { - "description": "Invalid input" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - }, - "delete": { - "tags": [ - "pet" - ], - "summary": "Deletes a pet", - "description": "", - "operationId": "deletePet", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "api_key", - "in": "header", - "required": false, - "type": "string" - }, - { - "name": "petId", - "in": "path", - "description": "Pet id to delete", - "required": true, - "type": "integer", - "format": "int64" - } - ], - "responses": { - "400": { - "description": "Invalid ID supplied" - }, - "404": { - "description": "Pet not found" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, - "/pet/{petId}/uploadImage": { - "post": { - "tags": [ - "pet" - ], - "summary": "uploads an image", - "description": "", - "operationId": "uploadFile", - "consumes": [ - "multipart/form-data" - ], - "produces": [ - "application/json" - ], - "parameters": [ - { - "name": "petId", - "in": "path", - "description": "ID of pet to update", - "required": true, - "type": "integer", - "format": "int64" - }, - { - "name": "additionalMetadata", - "in": "formData", - "description": "Additional data to pass to server", - "required": false, - "type": "string" - }, - { - "name": "file", - "in": "formData", - "description": "file to upload", - "required": false, - "type": "file" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "$ref": "#/definitions/ApiResponse" - } - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, - "/store/inventory": { - "get": { - "tags": [ - "store" - ], - "summary": "Returns pet inventories by status", - "description": "Returns a map of status codes to quantities", - "operationId": "getInventory", - "produces": [ - "application/json" - ], - "parameters": [], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int32" - } - } - } - }, - "security": [ - { - "api_key": [] - } - ] - } - }, - "/store/order": { - "post": { - "tags": [ - "store" - ], - "summary": "Place an order for a pet", - "description": "", - "operationId": "placeOrder", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "order placed for purchasing the pet", - "required": true, - "schema": { - "$ref": "#/definitions/Order" - } - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "$ref": "#/definitions/Order" - } - }, - "400": { - "description": "Invalid Order" - } - } - } - }, - "/store/order/{orderId}": { - "get": { - "tags": [ - "store" - ], - "summary": "Find purchase order by ID", - "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions", - "operationId": "getOrderById", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "orderId", - "in": "path", - "description": "ID of pet that needs to be fetched", - "required": true, - "type": "integer", - "maximum": 10.0, - "minimum": 1.0, - "format": "int64" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "$ref": "#/definitions/Order" - } - }, - "400": { - "description": "Invalid ID supplied" - }, - "404": { - "description": "Order not found" - } - } - }, - "delete": { - "tags": [ - "store" - ], - "summary": "Delete purchase order by ID", - "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors", - "operationId": "deleteOrder", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "orderId", - "in": "path", - "description": "ID of the order that needs to be deleted", - "required": true, - "type": "integer", - "minimum": 1.0, - "format": "int64" - } - ], - "responses": { - "400": { - "description": "Invalid ID supplied" - }, - "404": { - "description": "Order not found" - } - } - } - }, - "/user": { - "post": { - "tags": [ - "user" - ], - "summary": "Create user", - "description": "This can only be done by the logged in user.", - "operationId": "createUser", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "Created user object", - "required": true, - "schema": { - "$ref": "#/definitions/User" - } - } - ], - "responses": { - "default": { - "description": "successful operation" - } - } - } - }, - "/user/createWithArray": { - "post": { - "tags": [ - "user" - ], - "summary": "Creates list of users with given input array", - "description": "", - "operationId": "createUsersWithArrayInput", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "List of user object", - "required": true, - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/User" - } - } - } - ], - "responses": { - "default": { - "description": "successful operation" - } - } - } - }, - "/user/createWithList": { - "post": { - "tags": [ - "user" - ], - "summary": "Creates list of users with given input array", - "description": "", - "operationId": "createUsersWithListInput", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "in": "body", - "name": "body", - "description": "List of user object", - "required": true, - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/User" - } - } - } - ], - "responses": { - "default": { - "description": "successful operation" - } - } - } - }, - "/user/login": { - "get": { - "tags": [ - "user" - ], - "summary": "Logs user into the system", - "description": "", - "operationId": "loginUser", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "username", - "in": "query", - "description": "The user name for login", - "required": true, - "type": "string" - }, - { - "name": "password", - "in": "query", - "description": "The password for login in clear text", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "type": "string" - }, - "headers": { - "X-Rate-Limit": { - "type": "integer", - "format": "int32", - "description": "calls per hour allowed by the user" - }, - "X-Expires-After": { - "type": "string", - "format": "date-time", - "description": "date in UTC when token expires" - } - } - }, - "400": { - "description": "Invalid username/password supplied" - } - } - } - }, - "/user/logout": { - "get": { - "tags": [ - "user" - ], - "summary": "Logs out current logged in user session", - "description": "", - "operationId": "logoutUser", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [], - "responses": { - "default": { - "description": "successful operation" - } - } - } - }, - "/user/{username}": { - "get": { - "tags": [ - "user" - ], - "summary": "Get user by user name", - "description": "", - "operationId": "getUserByName", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "username", - "in": "path", - "description": "The name that needs to be fetched. Use user1 for testing. ", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "successful operation", - "schema": { - "$ref": "#/definitions/User" - } - }, - "400": { - "description": "Invalid username supplied" - }, - "404": { - "description": "User not found" - } - } - }, - "put": { - "tags": [ - "user" - ], - "summary": "Updated user", - "description": "This can only be done by the logged in user.", - "operationId": "updateUser", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "username", - "in": "path", - "description": "name that need to be updated", - "required": true, - "type": "string" - }, - { - "in": "body", - "name": "body", - "description": "Updated user object", - "required": true, - "schema": { - "$ref": "#/definitions/User" - } - } - ], - "responses": { - "400": { - "description": "Invalid user supplied" - }, - "404": { - "description": "User not found" - } - } - }, - "delete": { - "tags": [ - "user" - ], - "summary": "Delete user", - "description": "This can only be done by the logged in user.", - "operationId": "deleteUser", - "produces": [ - "application/xml", - "application/json" - ], - "parameters": [ - { - "name": "username", - "in": "path", - "description": "The name that needs to be deleted", - "required": true, - "type": "string" - } - ], - "responses": { - "400": { - "description": "Invalid username supplied" - }, - "404": { - "description": "User not found" - } - } - } - } - }, - "securityDefinitions": { - "petstore_auth": { - "type": "oauth2", - "authorizationUrl": "http://petstore.swagger.io/oauth/dialog", - "flow": "implicit", - "scopes": { - "write:pets": "modify pets in your account", - "read:pets": "read your pets" - } - }, - "api_key": { - "type": "apiKey", - "name": "api_key", - "in": "header" - } - }, - "definitions": { - "Order": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "petId": { - "type": "integer", - "format": "int64" - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "shipDate": { - "type": "string", - "format": "date-time" - }, - "status": { - "type": "string", - "description": "Order Status", - "enum": [ - "placed", - "approved", - "delivered" - ] - }, - "complete": { - "type": "boolean", - "default": false - } - }, - "xml": { - "name": "Order" - } - }, - "Category": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - } - }, - "xml": { - "name": "Category" - } - }, - "User": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "userStatus": { - "type": "integer", - "format": "int32", - "description": "User Status" - } - }, - "xml": { - "name": "User" - } - }, - "Tag": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - } - }, - "xml": { - "name": "Tag" - } - }, - "Pet": { - "type": "object", - "required": [ - "name", - "photoUrls" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "category": { - "$ref": "#/definitions/Category" - }, - "name": { - "type": "string", - "example": "doggie" - }, - "photoUrls": { - "type": "array", - "xml": { - "name": "photoUrl", - "wrapped": true - }, - "items": { - "type": "string" - } - }, - "tags": { - "type": "array", - "xml": { - "name": "tag", - "wrapped": true - }, - "items": { - "$ref": "#/definitions/Tag" - } - }, - "status": { - "type": "string", - "description": "pet status in the store", - "enum": [ - "available", - "pending", - "sold" - ] - } - }, - "xml": { - "name": "Pet" - } - }, - "ApiResponse": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string" - }, - "message": { - "type": "string" - } - } - } - }, - "externalDocs": { - "description": "Find out more about Swagger", - "url": "http://swagger.io" - } - }, - "valid": true - } - ] - } -] diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/json_schema_test_suite.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/json_schema_test_suite.py deleted file mode 100644 index 905fb6a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/json_schema_test_suite.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -A performance benchmark using the official test suite. - -This benchmarks jsonschema using every valid example in the -JSON-Schema-Test-Suite. It will take some time to complete. -""" -from pyperf import Runner - -from jsonschema.tests._suite import Suite - -if __name__ == "__main__": - Suite().benchmark(runner=Runner()) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/nested_schemas.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/nested_schemas.py deleted file mode 100644 index b025c47..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/nested_schemas.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Validating highly nested schemas shouldn't cause exponential time blowups. - -See https://github.com/python-jsonschema/jsonschema/issues/1097. -""" -from itertools import cycle - -from jsonschema.validators import validator_for - -metaschemaish = { - "$id": "https://example.com/draft/2020-12/schema/strict", - "$schema": "https://json-schema.org/draft/2020-12/schema", - - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/core": True, - "https://json-schema.org/draft/2020-12/vocab/applicator": True, - "https://json-schema.org/draft/2020-12/vocab/unevaluated": True, - "https://json-schema.org/draft/2020-12/vocab/validation": True, - "https://json-schema.org/draft/2020-12/vocab/meta-data": True, - "https://json-schema.org/draft/2020-12/vocab/format-annotation": True, - "https://json-schema.org/draft/2020-12/vocab/content": True, - }, - "$dynamicAnchor": "meta", - - "$ref": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": False, -} - - -def nested_schema(levels): - """ - Produce a schema which validates deeply nested objects and arrays. - """ - - names = cycle(["foo", "bar", "baz", "quux", "spam", "eggs"]) - schema = {"type": "object", "properties": {"ham": {"type": "string"}}} - for _, name in zip(range(levels - 1), names): - schema = {"type": "object", "properties": {name: schema}} - return schema - - -validator = validator_for(metaschemaish)(metaschemaish) - -if __name__ == "__main__": - from pyperf import Runner - runner = Runner() - - not_nested = nested_schema(levels=1) - runner.bench_func("not nested", lambda: validator.is_valid(not_nested)) - - for levels in range(1, 11, 3): - schema = nested_schema(levels=levels) - runner.bench_func( - f"nested * {levels}", - lambda schema=schema: validator.is_valid(schema), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/subcomponents.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/subcomponents.py deleted file mode 100644 index 6d78c7b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/subcomponents.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -A benchmark which tries to compare the possible slow subparts of validation. -""" -from referencing import Registry -from referencing.jsonschema import DRAFT202012 -from rpds import HashTrieMap, HashTrieSet - -from jsonschema import Draft202012Validator - -schema = { - "type": "array", - "minLength": 1, - "maxLength": 1, - "items": {"type": "integer"}, -} - -hmap = HashTrieMap() -hset = HashTrieSet() - -registry = Registry() - -v = Draft202012Validator(schema) - - -def registry_data_structures(): - return hmap.insert("foo", "bar"), hset.insert("foo") - - -def registry_add(): - resource = DRAFT202012.create_resource(schema) - return registry.with_resource(uri="urn:example", resource=resource) - - -if __name__ == "__main__": - from pyperf import Runner - runner = Runner() - - runner.bench_func("HashMap/HashSet insertion", registry_data_structures) - runner.bench_func("Registry insertion", registry_add) - runner.bench_func("Success", lambda: v.is_valid([1])) - runner.bench_func("Failure", lambda: v.is_valid(["foo"])) - runner.bench_func("Metaschema validation", lambda: v.check_schema(schema)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/unused_registry.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/unused_registry.py deleted file mode 100644 index 7b272c2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/unused_registry.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -An unused schema registry should not cause slower validation. - -"Unused" here means one where no reference resolution is occurring anyhow. - -See https://github.com/python-jsonschema/jsonschema/issues/1088. -""" -from pyperf import Runner -from referencing import Registry -from referencing.jsonschema import DRAFT201909 - -from jsonschema import Draft201909Validator - -registry = Registry().with_resource( - "urn:example:foo", - DRAFT201909.create_resource({}), -) - -schema = {"$ref": "https://json-schema.org/draft/2019-09/schema"} -instance = {"maxLength": 4} - -no_registry = Draft201909Validator(schema) -with_useless_registry = Draft201909Validator(schema, registry=registry) - -if __name__ == "__main__": - runner = Runner() - - runner.bench_func( - "no registry", - lambda: no_registry.is_valid(instance), - ) - runner.bench_func( - "useless registry", - lambda: with_useless_registry.is_valid(instance), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_applicator_schemas.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_applicator_schemas.py deleted file mode 100644 index f3229c0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_applicator_schemas.py +++ /dev/null @@ -1,106 +0,0 @@ - -""" -A benchmark for validation of applicators containing lots of useless schemas. - -Signals a small possible optimization to remove all such schemas ahead of time. -""" - -from pyperf import Runner - -from jsonschema import Draft202012Validator as Validator - -NUM_USELESS = 100000 - -subschema = {"const": 37} - -valid = 37 -invalid = 12 - -baseline = Validator(subschema) - - -# These should be indistinguishable from just `subschema` -by_name = { - "single subschema": { - "anyOf": Validator({"anyOf": [subschema]}), - "allOf": Validator({"allOf": [subschema]}), - "oneOf": Validator({"oneOf": [subschema]}), - }, - "redundant subschemas": { - "anyOf": Validator({"anyOf": [subschema] * NUM_USELESS}), - "allOf": Validator({"allOf": [subschema] * NUM_USELESS}), - }, - "useless successful subschemas (beginning)": { - "anyOf": Validator({"anyOf": [subschema, *[True] * NUM_USELESS]}), - "allOf": Validator({"allOf": [subschema, *[True] * NUM_USELESS]}), - }, - "useless successful subschemas (middle)": { - "anyOf": Validator( - { - "anyOf": [ - *[True] * (NUM_USELESS // 2), - subschema, - *[True] * (NUM_USELESS // 2), - ], - }, - ), - "allOf": Validator( - { - "allOf": [ - *[True] * (NUM_USELESS // 2), - subschema, - *[True] * (NUM_USELESS // 2), - ], - }, - ), - }, - "useless successful subschemas (end)": { - "anyOf": Validator({"anyOf": [*[True] * NUM_USELESS, subschema]}), - "allOf": Validator({"allOf": [*[True] * NUM_USELESS, subschema]}), - }, - "useless failing subschemas (beginning)": { - "anyOf": Validator({"anyOf": [subschema, *[False] * NUM_USELESS]}), - "oneOf": Validator({"oneOf": [subschema, *[False] * NUM_USELESS]}), - }, - "useless failing subschemas (middle)": { - "anyOf": Validator( - { - "anyOf": [ - *[False] * (NUM_USELESS // 2), - subschema, - *[False] * (NUM_USELESS // 2), - ], - }, - ), - "oneOf": Validator( - { - "oneOf": [ - *[False] * (NUM_USELESS // 2), - subschema, - *[False] * (NUM_USELESS // 2), - ], - }, - ), - }, - "useless failing subschemas (end)": { - "anyOf": Validator({"anyOf": [*[False] * NUM_USELESS, subschema]}), - "oneOf": Validator({"oneOf": [*[False] * NUM_USELESS, subschema]}), - }, -} - -if __name__ == "__main__": - runner = Runner() - - runner.bench_func("baseline valid", lambda: baseline.is_valid(valid)) - runner.bench_func("baseline invalid", lambda: baseline.is_valid(invalid)) - - for group, applicators in by_name.items(): - for applicator, validator in applicators.items(): - runner.bench_func( - f"{group}: {applicator} valid", - lambda validator=validator: validator.is_valid(valid), - ) - runner.bench_func( - f"{group}: {applicator} invalid", - lambda validator=validator: validator.is_valid(invalid), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_keywords.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_keywords.py deleted file mode 100644 index 50f4359..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/useless_keywords.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -A benchmark for validation of schemas containing lots of useless keywords. - -Checks we filter them out once, ahead of time. -""" - -from pyperf import Runner - -from jsonschema import Draft202012Validator - -NUM_USELESS = 100000 -schema = dict( - [ - ("not", {"const": 42}), - *((str(i), i) for i in range(NUM_USELESS)), - ("type", "integer"), - *((str(i), i) for i in range(NUM_USELESS, NUM_USELESS)), - ("minimum", 37), - ], -) -validator = Draft202012Validator(schema) - -valid = 3737 -invalid = 12 - - -if __name__ == "__main__": - runner = Runner() - runner.bench_func("beginning of schema", lambda: validator.is_valid(42)) - runner.bench_func("middle of schema", lambda: validator.is_valid("foo")) - runner.bench_func("end of schema", lambda: validator.is_valid(12)) - runner.bench_func("valid", lambda: validator.is_valid(3737)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/validator_creation.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/validator_creation.py deleted file mode 100644 index 4baeb3a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/benchmarks/validator_creation.py +++ /dev/null @@ -1,14 +0,0 @@ -from pyperf import Runner - -from jsonschema import Draft202012Validator - -schema = { - "type": "array", - "minLength": 1, - "maxLength": 1, - "items": {"type": "integer"}, -} - - -if __name__ == "__main__": - Runner().bench_func("validator creation", Draft202012Validator, schema) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/cli.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/cli.py deleted file mode 100644 index cf6298e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/cli.py +++ /dev/null @@ -1,296 +0,0 @@ -""" -The ``jsonschema`` command line. -""" - -from importlib import metadata -from json import JSONDecodeError -from textwrap import dedent -import argparse -import json -import sys -import traceback -import warnings - -try: - from pkgutil import resolve_name -except ImportError: - from pkgutil_resolve_name import resolve_name # type: ignore[no-redef] - -from attrs import define, field - -from jsonschema.exceptions import SchemaError -from jsonschema.validators import _RefResolver, validator_for - -warnings.warn( - ( - "The jsonschema CLI is deprecated and will be removed in a future " - "version. Please use check-jsonschema instead, which can be installed " - "from https://pypi.org/project/check-jsonschema/" - ), - DeprecationWarning, - stacklevel=2, -) - - -class _CannotLoadFile(Exception): - pass - - -@define -class _Outputter: - - _formatter = field() - _stdout = field() - _stderr = field() - - @classmethod - def from_arguments(cls, arguments, stdout, stderr): - if arguments["output"] == "plain": - formatter = _PlainFormatter(arguments["error_format"]) - elif arguments["output"] == "pretty": - formatter = _PrettyFormatter() - return cls(formatter=formatter, stdout=stdout, stderr=stderr) - - def load(self, path): - try: - file = open(path) # noqa: SIM115, PTH123 - except FileNotFoundError as error: - self.filenotfound_error(path=path, exc_info=sys.exc_info()) - raise _CannotLoadFile() from error - - with file: - try: - return json.load(file) - except JSONDecodeError as error: - self.parsing_error(path=path, exc_info=sys.exc_info()) - raise _CannotLoadFile() from error - - def filenotfound_error(self, **kwargs): - self._stderr.write(self._formatter.filenotfound_error(**kwargs)) - - def parsing_error(self, **kwargs): - self._stderr.write(self._formatter.parsing_error(**kwargs)) - - def validation_error(self, **kwargs): - self._stderr.write(self._formatter.validation_error(**kwargs)) - - def validation_success(self, **kwargs): - self._stdout.write(self._formatter.validation_success(**kwargs)) - - -@define -class _PrettyFormatter: - - _ERROR_MSG = dedent( - """\ - ===[{type}]===({path})=== - - {body} - ----------------------------- - """, - ) - _SUCCESS_MSG = "===[SUCCESS]===({path})===\n" - - def filenotfound_error(self, path, exc_info): - return self._ERROR_MSG.format( - path=path, - type="FileNotFoundError", - body=f"{path!r} does not exist.", - ) - - def parsing_error(self, path, exc_info): - exc_type, exc_value, exc_traceback = exc_info - exc_lines = "".join( - traceback.format_exception(exc_type, exc_value, exc_traceback), - ) - return self._ERROR_MSG.format( - path=path, - type=exc_type.__name__, - body=exc_lines, - ) - - def validation_error(self, instance_path, error): - return self._ERROR_MSG.format( - path=instance_path, - type=error.__class__.__name__, - body=error, - ) - - def validation_success(self, instance_path): - return self._SUCCESS_MSG.format(path=instance_path) - - -@define -class _PlainFormatter: - - _error_format = field() - - def filenotfound_error(self, path, exc_info): - return f"{path!r} does not exist.\n" - - def parsing_error(self, path, exc_info): - return "Failed to parse {}: {}\n".format( - "" if path == "" else repr(path), - exc_info[1], - ) - - def validation_error(self, instance_path, error): - return self._error_format.format(file_name=instance_path, error=error) - - def validation_success(self, instance_path): - return "" - - -def _resolve_name_with_default(name): - if "." not in name: - name = "jsonschema." + name - return resolve_name(name) - - -parser = argparse.ArgumentParser( - description="JSON Schema Validation CLI", -) -parser.add_argument( - "-i", "--instance", - action="append", - dest="instances", - help=""" - a path to a JSON instance (i.e. filename.json) to validate (may - be specified multiple times). If no instances are provided via this - option, one will be expected on standard input. - """, -) -parser.add_argument( - "-F", "--error-format", - help=""" - the format to use for each validation error message, specified - in a form suitable for str.format. This string will be passed - one formatted object named 'error' for each ValidationError. - Only provide this option when using --output=plain, which is the - default. If this argument is unprovided and --output=plain is - used, a simple default representation will be used. - """, -) -parser.add_argument( - "-o", "--output", - choices=["plain", "pretty"], - default="plain", - help=""" - an output format to use. 'plain' (default) will produce minimal - text with one line for each error, while 'pretty' will produce - more detailed human-readable output on multiple lines. - """, -) -parser.add_argument( - "-V", "--validator", - type=_resolve_name_with_default, - help=""" - the fully qualified object name of a validator to use, or, for - validators that are registered with jsonschema, simply the name - of the class. - """, -) -parser.add_argument( - "--base-uri", - help=""" - a base URI to assign to the provided schema, even if it does not - declare one (via e.g. $id). This option can be used if you wish to - resolve relative references to a particular URI (or local path) - """, -) -parser.add_argument( - "--version", - action="version", - version=metadata.version("jsonschema"), -) -parser.add_argument( - "schema", - help="the path to a JSON Schema to validate with (i.e. schema.json)", -) - - -def parse_args(args): # noqa: D103 - arguments = vars(parser.parse_args(args=args or ["--help"])) - if arguments["output"] != "plain" and arguments["error_format"]: - raise parser.error( - "--error-format can only be used with --output plain", - ) - if arguments["output"] == "plain" and arguments["error_format"] is None: - arguments["error_format"] = "{error.instance}: {error.message}\n" - return arguments - - -def _validate_instance(instance_path, instance, validator, outputter): - invalid = False - for error in validator.iter_errors(instance): - invalid = True - outputter.validation_error(instance_path=instance_path, error=error) - - if not invalid: - outputter.validation_success(instance_path=instance_path) - return invalid - - -def main(args=sys.argv[1:]): # noqa: D103 - sys.exit(run(arguments=parse_args(args=args))) - - -def run(arguments, stdout=sys.stdout, stderr=sys.stderr, stdin=sys.stdin): # noqa: D103 - outputter = _Outputter.from_arguments( - arguments=arguments, - stdout=stdout, - stderr=stderr, - ) - - try: - schema = outputter.load(arguments["schema"]) - except _CannotLoadFile: - return 1 - - Validator = arguments["validator"] - if Validator is None: - Validator = validator_for(schema) - - try: - Validator.check_schema(schema) - except SchemaError as error: - outputter.validation_error( - instance_path=arguments["schema"], - error=error, - ) - return 1 - - if arguments["instances"]: - load, instances = outputter.load, arguments["instances"] - else: - def load(_): - try: - return json.load(stdin) - except JSONDecodeError as error: - outputter.parsing_error( - path="", exc_info=sys.exc_info(), - ) - raise _CannotLoadFile() from error - instances = [""] - - resolver = _RefResolver( - base_uri=arguments["base_uri"], - referrer=schema, - ) if arguments["base_uri"] is not None else None - - validator = Validator(schema, resolver=resolver) - exit_code = 0 - for each in instances: - try: - instance = load(each) - except _CannotLoadFile: - exit_code = 1 - else: - exit_code |= _validate_instance( - instance_path=each, - instance=instance, - validator=validator, - outputter=outputter, - ) - - return exit_code diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/exceptions.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/exceptions.py deleted file mode 100644 index 78da49f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/exceptions.py +++ /dev/null @@ -1,487 +0,0 @@ -""" -Validation errors, and some surrounding helpers. -""" -from __future__ import annotations - -from collections import defaultdict, deque -from pprint import pformat -from textwrap import dedent, indent -from typing import TYPE_CHECKING, Any, ClassVar -import heapq -import itertools -import warnings - -from attrs import define -from referencing.exceptions import Unresolvable as _Unresolvable - -from jsonschema import _utils - -if TYPE_CHECKING: - from collections.abc import Iterable, Mapping, MutableMapping, Sequence - - from jsonschema import _types - -WEAK_MATCHES: frozenset[str] = frozenset(["anyOf", "oneOf"]) -STRONG_MATCHES: frozenset[str] = frozenset() - -_unset = _utils.Unset() - - -def _pretty(thing: Any, prefix: str): - """ - Format something for an error message as prettily as we currently can. - """ - return indent(pformat(thing, width=72, sort_dicts=False), prefix).lstrip() - - -def __getattr__(name): - if name == "RefResolutionError": - warnings.warn( - _RefResolutionError._DEPRECATION_MESSAGE, - DeprecationWarning, - stacklevel=2, - ) - return _RefResolutionError - raise AttributeError(f"module {__name__} has no attribute {name}") - - -class _Error(Exception): - - _word_for_schema_in_error_message: ClassVar[str] - _word_for_instance_in_error_message: ClassVar[str] - - def __init__( - self, - message: str, - validator: str = _unset, # type: ignore[assignment] - path: Iterable[str | int] = (), - cause: Exception | None = None, - context=(), - validator_value: Any = _unset, - instance: Any = _unset, - schema: Mapping[str, Any] | bool = _unset, # type: ignore[assignment] - schema_path: Iterable[str | int] = (), - parent: _Error | None = None, - type_checker: _types.TypeChecker = _unset, # type: ignore[assignment] - ) -> None: - super().__init__( - message, - validator, - path, - cause, - context, - validator_value, - instance, - schema, - schema_path, - parent, - ) - self.message = message - self.path = self.relative_path = deque(path) - self.schema_path = self.relative_schema_path = deque(schema_path) - self.context = list(context) - self.cause = self.__cause__ = cause - self.validator = validator - self.validator_value = validator_value - self.instance = instance - self.schema = schema - self.parent = parent - self._type_checker = type_checker - - for error in context: - error.parent = self - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}: {self.message!r}>" - - def __str__(self) -> str: - essential_for_verbose = ( - self.validator, self.validator_value, self.instance, self.schema, - ) - if any(m is _unset for m in essential_for_verbose): - return self.message - - schema_path = _utils.format_as_index( - container=self._word_for_schema_in_error_message, - indices=list(self.relative_schema_path)[:-1], - ) - instance_path = _utils.format_as_index( - container=self._word_for_instance_in_error_message, - indices=self.relative_path, - ) - prefix = 16 * " " - - return dedent( - f"""\ - {self.message} - - Failed validating {self.validator!r} in {schema_path}: - {_pretty(self.schema, prefix=prefix)} - - On {instance_path}: - {_pretty(self.instance, prefix=prefix)} - """.rstrip(), - ) - - @classmethod - def create_from(cls, other: _Error): - return cls(**other._contents()) - - @property - def absolute_path(self) -> Sequence[str | int]: - parent = self.parent - if parent is None: - return self.relative_path - - path = deque(self.relative_path) - path.extendleft(reversed(parent.absolute_path)) - return path - - @property - def absolute_schema_path(self) -> Sequence[str | int]: - parent = self.parent - if parent is None: - return self.relative_schema_path - - path = deque(self.relative_schema_path) - path.extendleft(reversed(parent.absolute_schema_path)) - return path - - @property - def json_path(self) -> str: - path = "$" - for elem in self.absolute_path: - if isinstance(elem, int): - path += "[" + str(elem) + "]" - else: - path += "." + elem - return path - - def _set( - self, - type_checker: _types.TypeChecker | None = None, - **kwargs: Any, - ) -> None: - if type_checker is not None and self._type_checker is _unset: - self._type_checker = type_checker - - for k, v in kwargs.items(): - if getattr(self, k) is _unset: - setattr(self, k, v) - - def _contents(self): - attrs = ( - "message", "cause", "context", "validator", "validator_value", - "path", "schema_path", "instance", "schema", "parent", - ) - return {attr: getattr(self, attr) for attr in attrs} - - def _matches_type(self) -> bool: - try: - # We ignore this as we want to simply crash if this happens - expected = self.schema["type"] # type: ignore[index] - except (KeyError, TypeError): - return False - - if isinstance(expected, str): - return self._type_checker.is_type(self.instance, expected) - - return any( - self._type_checker.is_type(self.instance, expected_type) - for expected_type in expected - ) - - -class ValidationError(_Error): - """ - An instance was invalid under a provided schema. - """ - - _word_for_schema_in_error_message = "schema" - _word_for_instance_in_error_message = "instance" - - -class SchemaError(_Error): - """ - A schema was invalid under its corresponding metaschema. - """ - - _word_for_schema_in_error_message = "metaschema" - _word_for_instance_in_error_message = "schema" - - -@define(slots=False) -class _RefResolutionError(Exception): - """ - A ref could not be resolved. - """ - - _DEPRECATION_MESSAGE = ( - "jsonschema.exceptions.RefResolutionError is deprecated as of version " - "4.18.0. If you wish to catch potential reference resolution errors, " - "directly catch referencing.exceptions.Unresolvable." - ) - - _cause: Exception - - def __eq__(self, other): - if self.__class__ is not other.__class__: - return NotImplemented # pragma: no cover -- uncovered but deprecated # noqa: E501 - return self._cause == other._cause - - def __str__(self) -> str: - return str(self._cause) - - -class _WrappedReferencingError(_RefResolutionError, _Unresolvable): # pragma: no cover -- partially uncovered but to be removed # noqa: E501 - def __init__(self, cause: _Unresolvable): - object.__setattr__(self, "_wrapped", cause) - - def __eq__(self, other): - if other.__class__ is self.__class__: - return self._wrapped == other._wrapped - elif other.__class__ is self._wrapped.__class__: - return self._wrapped == other - return NotImplemented - - def __getattr__(self, attr): - return getattr(self._wrapped, attr) - - def __hash__(self): - return hash(self._wrapped) - - def __repr__(self): - return f"" - - def __str__(self): - return f"{self._wrapped.__class__.__name__}: {self._wrapped}" - - -class UndefinedTypeCheck(Exception): - """ - A type checker was asked to check a type it did not have registered. - """ - - def __init__(self, type: str) -> None: - self.type = type - - def __str__(self) -> str: - return f"Type {self.type!r} is unknown to this type checker" - - -class UnknownType(Exception): - """ - A validator was asked to validate an instance against an unknown type. - """ - - def __init__(self, type, instance, schema): - self.type = type - self.instance = instance - self.schema = schema - - def __str__(self): - prefix = 16 * " " - - return dedent( - f"""\ - Unknown type {self.type!r} for validator with schema: - {_pretty(self.schema, prefix=prefix)} - - While checking instance: - {_pretty(self.instance, prefix=prefix)} - """.rstrip(), - ) - - -class FormatError(Exception): - """ - Validating a format failed. - """ - - def __init__(self, message, cause=None): - super().__init__(message, cause) - self.message = message - self.cause = self.__cause__ = cause - - def __str__(self): - return self.message - - -class ErrorTree: - """ - ErrorTrees make it easier to check which validations failed. - """ - - _instance = _unset - - def __init__(self, errors: Iterable[ValidationError] = ()): - self.errors: MutableMapping[str, ValidationError] = {} - self._contents: Mapping[str, ErrorTree] = defaultdict(self.__class__) - - for error in errors: - container = self - for element in error.path: - container = container[element] - container.errors[error.validator] = error - - container._instance = error.instance - - def __contains__(self, index: str | int): - """ - Check whether ``instance[index]`` has any errors. - """ - return index in self._contents - - def __getitem__(self, index): - """ - Retrieve the child tree one level down at the given ``index``. - - If the index is not in the instance that this tree corresponds - to and is not known by this tree, whatever error would be raised - by ``instance.__getitem__`` will be propagated (usually this is - some subclass of `LookupError`. - """ - if self._instance is not _unset and index not in self: - self._instance[index] - return self._contents[index] - - def __setitem__(self, index: str | int, value: ErrorTree): - """ - Add an error to the tree at the given ``index``. - - .. deprecated:: v4.20.0 - - Setting items on an `ErrorTree` is deprecated without replacement. - To populate a tree, provide all of its sub-errors when you - construct the tree. - """ - warnings.warn( - "ErrorTree.__setitem__ is deprecated without replacement.", - DeprecationWarning, - stacklevel=2, - ) - self._contents[index] = value # type: ignore[index] - - def __iter__(self): - """ - Iterate (non-recursively) over the indices in the instance with errors. - """ - return iter(self._contents) - - def __len__(self): - """ - Return the `total_errors`. - """ - return self.total_errors - - def __repr__(self): - total = len(self) - errors = "error" if total == 1 else "errors" - return f"<{self.__class__.__name__} ({total} total {errors})>" - - @property - def total_errors(self): - """ - The total number of errors in the entire tree, including children. - """ - child_errors = sum(len(tree) for _, tree in self._contents.items()) - return len(self.errors) + child_errors - - -def by_relevance(weak=WEAK_MATCHES, strong=STRONG_MATCHES): - """ - Create a key function that can be used to sort errors by relevance. - - Arguments: - weak (set): - a collection of validation keywords to consider to be - "weak". If there are two errors at the same level of the - instance and one is in the set of weak validation keywords, - the other error will take priority. By default, :kw:`anyOf` - and :kw:`oneOf` are considered weak keywords and will be - superseded by other same-level validation errors. - - strong (set): - a collection of validation keywords to consider to be - "strong" - - """ - - def relevance(error): - validator = error.validator - return ( # prefer errors which are ... - -len(error.path), # 'deeper' and thereby more specific - error.path, # earlier (for sibling errors) - validator not in weak, # for a non-low-priority keyword - validator in strong, # for a high priority keyword - not error._matches_type(), # at least match the instance's type - ) # otherwise we'll treat them the same - - return relevance - - -relevance = by_relevance() -""" -A key function (e.g. to use with `sorted`) which sorts errors by relevance. - -Example: - -.. code:: python - - sorted(validator.iter_errors(12), key=jsonschema.exceptions.relevance) -""" - - -def best_match(errors, key=relevance): - """ - Try to find an error that appears to be the best match among given errors. - - In general, errors that are higher up in the instance (i.e. for which - `ValidationError.path` is shorter) are considered better matches, - since they indicate "more" is wrong with the instance. - - If the resulting match is either :kw:`oneOf` or :kw:`anyOf`, the - *opposite* assumption is made -- i.e. the deepest error is picked, - since these keywords only need to match once, and any other errors - may not be relevant. - - Arguments: - errors (collections.abc.Iterable): - - the errors to select from. Do not provide a mixture of - errors from different validation attempts (i.e. from - different instances or schemas), since it won't produce - sensical output. - - key (collections.abc.Callable): - - the key to use when sorting errors. See `relevance` and - transitively `by_relevance` for more details (the default is - to sort with the defaults of that function). Changing the - default is only useful if you want to change the function - that rates errors but still want the error context descent - done by this function. - - Returns: - the best matching error, or ``None`` if the iterable was empty - - .. note:: - - This function is a heuristic. Its return value may change for a given - set of inputs from version to version if better heuristics are added. - - """ - errors = iter(errors) - best = next(errors, None) - if best is None: - return - best = max(itertools.chain([best], errors), key=key) - - while best.context: - # Calculate the minimum via nsmallest, because we don't recurse if - # all nested errors have the same relevance (i.e. if min == max == all) - smallest = heapq.nsmallest(2, best.context, key=key) - if len(smallest) == 2 and key(smallest[0]) == key(smallest[1]): # noqa: PLR2004 - return best - best = smallest[0] - return best diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/protocols.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/protocols.py deleted file mode 100644 index 39e56d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/protocols.py +++ /dev/null @@ -1,236 +0,0 @@ -""" -typing.Protocol classes for jsonschema interfaces. -""" - -# for reference material on Protocols, see -# https://www.python.org/dev/peps/pep-0544/ - -from __future__ import annotations - -from typing import ( - TYPE_CHECKING, - Any, - ClassVar, - Iterable, - Protocol, - runtime_checkable, -) - -# in order for Sphinx to resolve references accurately from type annotations, -# it needs to see names like `jsonschema.TypeChecker` -# therefore, only import at type-checking time (to avoid circular references), -# but use `jsonschema` for any types which will otherwise not be resolvable -if TYPE_CHECKING: - from collections.abc import Mapping - - import referencing.jsonschema - - from jsonschema import _typing - from jsonschema.exceptions import ValidationError - import jsonschema - import jsonschema.validators - -# For code authors working on the validator protocol, these are the three -# use-cases which should be kept in mind: -# -# 1. As a protocol class, it can be used in type annotations to describe the -# available methods and attributes of a validator -# 2. It is the source of autodoc for the validator documentation -# 3. It is runtime_checkable, meaning that it can be used in isinstance() -# checks. -# -# Since protocols are not base classes, isinstance() checking is limited in -# its capabilities. See docs on runtime_checkable for detail - - -@runtime_checkable -class Validator(Protocol): - """ - The protocol to which all validator classes adhere. - - Arguments: - - schema: - - The schema that the validator object will validate with. - It is assumed to be valid, and providing - an invalid schema can lead to undefined behavior. See - `Validator.check_schema` to validate a schema first. - - registry: - - a schema registry that will be used for looking up JSON references - - resolver: - - a resolver that will be used to resolve :kw:`$ref` - properties (JSON references). If unprovided, one will be created. - - .. deprecated:: v4.18.0 - - `RefResolver <_RefResolver>` has been deprecated in favor of - `referencing`, and with it, this argument. - - format_checker: - - if provided, a checker which will be used to assert about - :kw:`format` properties present in the schema. If unprovided, - *no* format validation is done, and the presence of format - within schemas is strictly informational. Certain formats - require additional packages to be installed in order to assert - against instances. Ensure you've installed `jsonschema` with - its `extra (optional) dependencies ` when - invoking ``pip``. - - .. deprecated:: v4.12.0 - - Subclassing validator classes now explicitly warns this is not part of - their public API. - - """ - - #: An object representing the validator's meta schema (the schema that - #: describes valid schemas in the given version). - META_SCHEMA: ClassVar[Mapping] - - #: A mapping of validation keywords (`str`\s) to functions that - #: validate the keyword with that name. For more information see - #: `creating-validators`. - VALIDATORS: ClassVar[Mapping] - - #: A `jsonschema.TypeChecker` that will be used when validating - #: :kw:`type` keywords in JSON schemas. - TYPE_CHECKER: ClassVar[jsonschema.TypeChecker] - - #: A `jsonschema.FormatChecker` that will be used when validating - #: :kw:`format` keywords in JSON schemas. - FORMAT_CHECKER: ClassVar[jsonschema.FormatChecker] - - #: A function which given a schema returns its ID. - ID_OF: _typing.id_of - - #: The schema that will be used to validate instances - schema: Mapping | bool - - def __init__( - self, - schema: Mapping | bool, - registry: referencing.jsonschema.SchemaRegistry, - format_checker: jsonschema.FormatChecker | None = None, - ) -> None: - ... - - @classmethod - def check_schema(cls, schema: Mapping | bool) -> None: - """ - Validate the given schema against the validator's `META_SCHEMA`. - - Raises: - - `jsonschema.exceptions.SchemaError`: - - if the schema is invalid - - """ - - def is_type(self, instance: Any, type: str) -> bool: - """ - Check if the instance is of the given (JSON Schema) type. - - Arguments: - - instance: - - the value to check - - type: - - the name of a known (JSON Schema) type - - Returns: - - whether the instance is of the given type - - Raises: - - `jsonschema.exceptions.UnknownType`: - - if ``type`` is not a known type - - """ - - def is_valid(self, instance: Any) -> bool: - """ - Check if the instance is valid under the current `schema`. - - Returns: - - whether the instance is valid or not - - >>> schema = {"maxItems" : 2} - >>> Draft202012Validator(schema).is_valid([2, 3, 4]) - False - - """ - - def iter_errors(self, instance: Any) -> Iterable[ValidationError]: - r""" - Lazily yield each of the validation errors in the given instance. - - >>> schema = { - ... "type" : "array", - ... "items" : {"enum" : [1, 2, 3]}, - ... "maxItems" : 2, - ... } - >>> v = Draft202012Validator(schema) - >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str): - ... print(error.message) - 4 is not one of [1, 2, 3] - [2, 3, 4] is too long - - .. deprecated:: v4.0.0 - - Calling this function with a second schema argument is deprecated. - Use `Validator.evolve` instead. - """ - - def validate(self, instance: Any) -> None: - """ - Check if the instance is valid under the current `schema`. - - Raises: - - `jsonschema.exceptions.ValidationError`: - - if the instance is invalid - - >>> schema = {"maxItems" : 2} - >>> Draft202012Validator(schema).validate([2, 3, 4]) - Traceback (most recent call last): - ... - ValidationError: [2, 3, 4] is too long - - """ - - def evolve(self, **kwargs) -> Validator: - """ - Create a new validator like this one, but with given changes. - - Preserves all other attributes, so can be used to e.g. create a - validator with a different schema but with the same :kw:`$ref` - resolution behavior. - - >>> validator = Draft202012Validator({}) - >>> validator.evolve(schema={"type": "number"}) - Draft202012Validator(schema={'type': 'number'}, format_checker=None) - - The returned object satisfies the validator protocol, but may not - be of the same concrete class! In particular this occurs - when a :kw:`$ref` occurs to a schema with a different - :kw:`$schema` than this one (i.e. for a different draft). - - >>> validator.evolve( - ... schema={"$schema": Draft7Validator.META_SCHEMA["$id"]} - ... ) - Draft7Validator(schema=..., format_checker=None) - """ diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/_suite.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/_suite.py deleted file mode 100644 index 0da6503..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/_suite.py +++ /dev/null @@ -1,276 +0,0 @@ -""" -Python representations of the JSON Schema Test Suite tests. -""" -from __future__ import annotations - -from contextlib import suppress -from functools import partial -from pathlib import Path -from typing import TYPE_CHECKING, Any -import json -import os -import re -import subprocess -import sys -import unittest - -from attrs import field, frozen -from referencing import Registry -import referencing.jsonschema - -if TYPE_CHECKING: - from collections.abc import Iterable, Mapping, Sequence - - import pyperf - -from jsonschema.validators import _VALIDATORS -import jsonschema - -_DELIMITERS = re.compile(r"[\W\- ]+") - - -def _find_suite(): - root = os.environ.get("JSON_SCHEMA_TEST_SUITE") - if root is not None: - return Path(root) - - root = Path(jsonschema.__file__).parent.parent / "json" - if not root.is_dir(): # pragma: no cover - raise ValueError( - ( - "Can't find the JSON-Schema-Test-Suite directory. " - "Set the 'JSON_SCHEMA_TEST_SUITE' environment " - "variable or run the tests from alongside a checkout " - "of the suite." - ), - ) - return root - - -@frozen -class Suite: - - _root: Path = field(factory=_find_suite) - _remotes: referencing.jsonschema.SchemaRegistry = field(init=False) - - def __attrs_post_init__(self): - jsonschema_suite = self._root.joinpath("bin", "jsonschema_suite") - argv = [sys.executable, str(jsonschema_suite), "remotes"] - remotes = subprocess.check_output(argv).decode("utf-8") - - resources = json.loads(remotes) - - li = "http://localhost:1234/locationIndependentIdentifierPre2019.json" - li4 = "http://localhost:1234/locationIndependentIdentifierDraft4.json" - - registry = Registry().with_resources( - [ - ( - li, - referencing.jsonschema.DRAFT7.create_resource( - contents=resources.pop(li), - ), - ), - ( - li4, - referencing.jsonschema.DRAFT4.create_resource( - contents=resources.pop(li4), - ), - ), - ], - ).with_contents( - resources.items(), - default_specification=referencing.jsonschema.DRAFT202012, - ) - object.__setattr__(self, "_remotes", registry) - - def benchmark(self, runner: pyperf.Runner): # pragma: no cover - for name, Validator in _VALIDATORS.items(): - self.version(name=name).benchmark( - runner=runner, - Validator=Validator, - ) - - def version(self, name) -> Version: - return Version( - name=name, - path=self._root / "tests" / name, - remotes=self._remotes, - ) - - -@frozen -class Version: - - _path: Path - _remotes: referencing.jsonschema.SchemaRegistry - - name: str - - def benchmark(self, **kwargs): # pragma: no cover - for case in self.cases(): - case.benchmark(**kwargs) - - def cases(self) -> Iterable[_Case]: - return self._cases_in(paths=self._path.glob("*.json")) - - def format_cases(self) -> Iterable[_Case]: - return self._cases_in(paths=self._path.glob("optional/format/*.json")) - - def optional_cases_of(self, name: str) -> Iterable[_Case]: - return self._cases_in(paths=[self._path / "optional" / f"{name}.json"]) - - def to_unittest_testcase(self, *groups, **kwargs): - name = kwargs.pop("name", "Test" + self.name.title().replace("-", "")) - methods = { - method.__name__: method - for method in ( - test.to_unittest_method(**kwargs) - for group in groups - for case in group - for test in case.tests - ) - } - cls = type(name, (unittest.TestCase,), methods) - - # We're doing crazy things, so if they go wrong, like a function - # behaving differently on some other interpreter, just make them - # not happen. - with suppress(Exception): - cls.__module__ = _someone_save_us_the_module_of_the_caller() - - return cls - - def _cases_in(self, paths: Iterable[Path]) -> Iterable[_Case]: - for path in paths: - for case in json.loads(path.read_text(encoding="utf-8")): - yield _Case.from_dict( - case, - version=self, - subject=path.stem, - remotes=self._remotes, - ) - - -@frozen -class _Case: - - version: Version - - subject: str - description: str - schema: Mapping[str, Any] | bool - tests: list[_Test] - comment: str | None = None - specification: Sequence[dict[str, str]] = () - - @classmethod - def from_dict(cls, data, remotes, **kwargs): - data.update(kwargs) - tests = [ - _Test( - version=data["version"], - subject=data["subject"], - case_description=data["description"], - schema=data["schema"], - remotes=remotes, - **test, - ) for test in data.pop("tests") - ] - return cls(tests=tests, **data) - - def benchmark(self, runner: pyperf.Runner, **kwargs): # pragma: no cover - for test in self.tests: - runner.bench_func( - test.fully_qualified_name, - partial(test.validate_ignoring_errors, **kwargs), - ) - - -@frozen(repr=False) -class _Test: - - version: Version - - subject: str - case_description: str - description: str - - data: Any - schema: Mapping[str, Any] | bool - - valid: bool - - _remotes: referencing.jsonschema.SchemaRegistry - - comment: str | None = None - - def __repr__(self): # pragma: no cover - return f"" - - @property - def fully_qualified_name(self): # pragma: no cover - return " > ".join( # noqa: FLY002 - [ - self.version.name, - self.subject, - self.case_description, - self.description, - ], - ) - - def to_unittest_method(self, skip=lambda test: None, **kwargs): - if self.valid: - def fn(this): - self.validate(**kwargs) - else: - def fn(this): - with this.assertRaises(jsonschema.ValidationError): - self.validate(**kwargs) - - fn.__name__ = "_".join( - [ - "test", - _DELIMITERS.sub("_", self.subject), - _DELIMITERS.sub("_", self.case_description), - _DELIMITERS.sub("_", self.description), - ], - ) - reason = skip(self) - if reason is None or os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": - return fn - elif os.environ.get("JSON_SCHEMA_EXPECTED_FAILURES", "0") != "0": # pragma: no cover # noqa: E501 - return unittest.expectedFailure(fn) - else: - return unittest.skip(reason)(fn) - - def validate(self, Validator, **kwargs): - Validator.check_schema(self.schema) - validator = Validator( - schema=self.schema, - registry=self._remotes, - **kwargs, - ) - if os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": # pragma: no cover - breakpoint() # noqa: T100 - validator.validate(instance=self.data) - - def validate_ignoring_errors(self, Validator): # pragma: no cover - with suppress(jsonschema.ValidationError): - self.validate(Validator=Validator) - - -def _someone_save_us_the_module_of_the_caller(): - """ - The FQON of the module 2nd stack frames up from here. - - This is intended to allow us to dynamically return test case classes that - are indistinguishable from being defined in the module that wants them. - - Otherwise, trial will mis-print the FQON, and copy pasting it won't re-run - the class that really is running. - - Save us all, this is all so so so so so terrible. - """ - - return sys._getframe(2).f_globals["__name__"] diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/fuzz_validate.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/fuzz_validate.py deleted file mode 100644 index c12e88b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/fuzz_validate.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Fuzzing setup for OSS-Fuzz. - -See https://github.com/google/oss-fuzz/tree/master/projects/jsonschema for the -other half of the setup here. -""" -import sys - -from hypothesis import given, strategies - -import jsonschema - -PRIM = strategies.one_of( - strategies.booleans(), - strategies.integers(), - strategies.floats(allow_nan=False, allow_infinity=False), - strategies.text(), -) -DICT = strategies.recursive( - base=strategies.one_of( - strategies.booleans(), - strategies.dictionaries(strategies.text(), PRIM), - ), - extend=lambda inner: strategies.dictionaries(strategies.text(), inner), -) - - -@given(obj1=DICT, obj2=DICT) -def test_schemas(obj1, obj2): - try: - jsonschema.validate(instance=obj1, schema=obj2) - except jsonschema.exceptions.ValidationError: - pass - except jsonschema.exceptions.SchemaError: - pass - - -def main(): - atheris.instrument_all() - atheris.Setup( - sys.argv, - test_schemas.hypothesis.fuzz_one_input, - enable_python_coverage=True, - ) - atheris.Fuzz() - - -if __name__ == "__main__": - import atheris - main() diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_cli.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_cli.py deleted file mode 100644 index 79d2a15..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_cli.py +++ /dev/null @@ -1,907 +0,0 @@ -from contextlib import redirect_stderr, redirect_stdout -from importlib import metadata -from io import StringIO -from json import JSONDecodeError -from pathlib import Path -from textwrap import dedent -from unittest import TestCase -import json -import os -import subprocess -import sys -import tempfile -import warnings - -from jsonschema import Draft4Validator, Draft202012Validator -from jsonschema.exceptions import ( - SchemaError, - ValidationError, - _RefResolutionError, -) -from jsonschema.validators import _LATEST_VERSION, validate - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - from jsonschema import cli - - -def fake_validator(*errors): - errors = list(reversed(errors)) - - class FakeValidator: - def __init__(self, *args, **kwargs): - pass - - def iter_errors(self, instance): - if errors: - return errors.pop() - return [] # pragma: no cover - - @classmethod - def check_schema(self, schema): - pass - - return FakeValidator - - -def fake_open(all_contents): - def open(path): - contents = all_contents.get(path) - if contents is None: - raise FileNotFoundError(path) - return StringIO(contents) - return open - - -def _message_for(non_json): - try: - json.loads(non_json) - except JSONDecodeError as error: - return str(error) - else: # pragma: no cover - raise RuntimeError("Tried and failed to capture a JSON dump error.") - - -class TestCLI(TestCase): - def run_cli( - self, argv, files=None, stdin=StringIO(), exit_code=0, **override, - ): - arguments = cli.parse_args(argv) - arguments.update(override) - - self.assertFalse(hasattr(cli, "open")) - cli.open = fake_open(files or {}) - try: - stdout, stderr = StringIO(), StringIO() - actual_exit_code = cli.run( - arguments, - stdin=stdin, - stdout=stdout, - stderr=stderr, - ) - finally: - del cli.open - - self.assertEqual( - actual_exit_code, exit_code, msg=dedent( - f""" - Expected an exit code of {exit_code} != {actual_exit_code}. - - stdout: {stdout.getvalue()} - - stderr: {stderr.getvalue()} - """, - ), - ) - return stdout.getvalue(), stderr.getvalue() - - def assertOutputs(self, stdout="", stderr="", **kwargs): - self.assertEqual( - self.run_cli(**kwargs), - (dedent(stdout), dedent(stderr)), - ) - - def test_invalid_instance(self): - error = ValidationError("I am an error!", instance=12) - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_instance=json.dumps(error.instance), - ), - validator=fake_validator([error]), - - argv=["-i", "some_instance", "some_schema"], - - exit_code=1, - stderr="12: I am an error!\n", - ) - - def test_invalid_instance_pretty_output(self): - error = ValidationError("I am an error!", instance=12) - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_instance=json.dumps(error.instance), - ), - validator=fake_validator([error]), - - argv=["-i", "some_instance", "--output", "pretty", "some_schema"], - - exit_code=1, - stderr="""\ - ===[ValidationError]===(some_instance)=== - - I am an error! - ----------------------------- - """, - ) - - def test_invalid_instance_explicit_plain_output(self): - error = ValidationError("I am an error!", instance=12) - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_instance=json.dumps(error.instance), - ), - validator=fake_validator([error]), - - argv=["--output", "plain", "-i", "some_instance", "some_schema"], - - exit_code=1, - stderr="12: I am an error!\n", - ) - - def test_invalid_instance_multiple_errors(self): - instance = 12 - first = ValidationError("First error", instance=instance) - second = ValidationError("Second error", instance=instance) - - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_instance=json.dumps(instance), - ), - validator=fake_validator([first, second]), - - argv=["-i", "some_instance", "some_schema"], - - exit_code=1, - stderr="""\ - 12: First error - 12: Second error - """, - ) - - def test_invalid_instance_multiple_errors_pretty_output(self): - instance = 12 - first = ValidationError("First error", instance=instance) - second = ValidationError("Second error", instance=instance) - - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_instance=json.dumps(instance), - ), - validator=fake_validator([first, second]), - - argv=["-i", "some_instance", "--output", "pretty", "some_schema"], - - exit_code=1, - stderr="""\ - ===[ValidationError]===(some_instance)=== - - First error - ----------------------------- - ===[ValidationError]===(some_instance)=== - - Second error - ----------------------------- - """, - ) - - def test_multiple_invalid_instances(self): - first_instance = 12 - first_errors = [ - ValidationError("An error", instance=first_instance), - ValidationError("Another error", instance=first_instance), - ] - second_instance = "foo" - second_errors = [ValidationError("BOOM", instance=second_instance)] - - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_first_instance=json.dumps(first_instance), - some_second_instance=json.dumps(second_instance), - ), - validator=fake_validator(first_errors, second_errors), - - argv=[ - "-i", "some_first_instance", - "-i", "some_second_instance", - "some_schema", - ], - - exit_code=1, - stderr="""\ - 12: An error - 12: Another error - foo: BOOM - """, - ) - - def test_multiple_invalid_instances_pretty_output(self): - first_instance = 12 - first_errors = [ - ValidationError("An error", instance=first_instance), - ValidationError("Another error", instance=first_instance), - ] - second_instance = "foo" - second_errors = [ValidationError("BOOM", instance=second_instance)] - - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_first_instance=json.dumps(first_instance), - some_second_instance=json.dumps(second_instance), - ), - validator=fake_validator(first_errors, second_errors), - - argv=[ - "--output", "pretty", - "-i", "some_first_instance", - "-i", "some_second_instance", - "some_schema", - ], - - exit_code=1, - stderr="""\ - ===[ValidationError]===(some_first_instance)=== - - An error - ----------------------------- - ===[ValidationError]===(some_first_instance)=== - - Another error - ----------------------------- - ===[ValidationError]===(some_second_instance)=== - - BOOM - ----------------------------- - """, - ) - - def test_custom_error_format(self): - first_instance = 12 - first_errors = [ - ValidationError("An error", instance=first_instance), - ValidationError("Another error", instance=first_instance), - ] - second_instance = "foo" - second_errors = [ValidationError("BOOM", instance=second_instance)] - - self.assertOutputs( - files=dict( - some_schema='{"does not": "matter since it is stubbed"}', - some_first_instance=json.dumps(first_instance), - some_second_instance=json.dumps(second_instance), - ), - validator=fake_validator(first_errors, second_errors), - - argv=[ - "--error-format", ":{error.message}._-_.{error.instance}:", - "-i", "some_first_instance", - "-i", "some_second_instance", - "some_schema", - ], - - exit_code=1, - stderr=":An error._-_.12::Another error._-_.12::BOOM._-_.foo:", - ) - - def test_invalid_schema(self): - self.assertOutputs( - files=dict(some_schema='{"type": 12}'), - argv=["some_schema"], - - exit_code=1, - stderr="""\ - 12: 12 is not valid under any of the given schemas - """, - ) - - def test_invalid_schema_pretty_output(self): - schema = {"type": 12} - - with self.assertRaises(SchemaError) as e: - validate(schema=schema, instance="") - error = str(e.exception) - - self.assertOutputs( - files=dict(some_schema=json.dumps(schema)), - argv=["--output", "pretty", "some_schema"], - - exit_code=1, - stderr=( - "===[SchemaError]===(some_schema)===\n\n" - + str(error) - + "\n-----------------------------\n" - ), - ) - - def test_invalid_schema_multiple_errors(self): - self.assertOutputs( - files=dict(some_schema='{"type": 12, "items": 57}'), - argv=["some_schema"], - - exit_code=1, - stderr="""\ - 57: 57 is not of type 'object', 'boolean' - """, - ) - - def test_invalid_schema_multiple_errors_pretty_output(self): - schema = {"type": 12, "items": 57} - - with self.assertRaises(SchemaError) as e: - validate(schema=schema, instance="") - error = str(e.exception) - - self.assertOutputs( - files=dict(some_schema=json.dumps(schema)), - argv=["--output", "pretty", "some_schema"], - - exit_code=1, - stderr=( - "===[SchemaError]===(some_schema)===\n\n" - + str(error) - + "\n-----------------------------\n" - ), - ) - - def test_invalid_schema_with_invalid_instance(self): - """ - "Validating" an instance that's invalid under an invalid schema - just shows the schema error. - """ - self.assertOutputs( - files=dict( - some_schema='{"type": 12, "minimum": 30}', - some_instance="13", - ), - argv=["-i", "some_instance", "some_schema"], - - exit_code=1, - stderr="""\ - 12: 12 is not valid under any of the given schemas - """, - ) - - def test_invalid_schema_with_invalid_instance_pretty_output(self): - instance, schema = 13, {"type": 12, "minimum": 30} - - with self.assertRaises(SchemaError) as e: - validate(schema=schema, instance=instance) - error = str(e.exception) - - self.assertOutputs( - files=dict( - some_schema=json.dumps(schema), - some_instance=json.dumps(instance), - ), - argv=["--output", "pretty", "-i", "some_instance", "some_schema"], - - exit_code=1, - stderr=( - "===[SchemaError]===(some_schema)===\n\n" - + str(error) - + "\n-----------------------------\n" - ), - ) - - def test_invalid_instance_continues_with_the_rest(self): - self.assertOutputs( - files=dict( - some_schema='{"minimum": 30}', - first_instance="not valid JSON!", - second_instance="12", - ), - argv=[ - "-i", "first_instance", - "-i", "second_instance", - "some_schema", - ], - - exit_code=1, - stderr="""\ - Failed to parse 'first_instance': {} - 12: 12 is less than the minimum of 30 - """.format(_message_for("not valid JSON!")), - ) - - def test_custom_error_format_applies_to_schema_errors(self): - instance, schema = 13, {"type": 12, "minimum": 30} - - with self.assertRaises(SchemaError): - validate(schema=schema, instance=instance) - - self.assertOutputs( - files=dict(some_schema=json.dumps(schema)), - - argv=[ - "--error-format", ":{error.message}._-_.{error.instance}:", - "some_schema", - ], - - exit_code=1, - stderr=":12 is not valid under any of the given schemas._-_.12:", - ) - - def test_instance_is_invalid_JSON(self): - instance = "not valid JSON!" - - self.assertOutputs( - files=dict(some_schema="{}", some_instance=instance), - argv=["-i", "some_instance", "some_schema"], - - exit_code=1, - stderr=f"""\ - Failed to parse 'some_instance': {_message_for(instance)} - """, - ) - - def test_instance_is_invalid_JSON_pretty_output(self): - stdout, stderr = self.run_cli( - files=dict( - some_schema="{}", - some_instance="not valid JSON!", - ), - - argv=["--output", "pretty", "-i", "some_instance", "some_schema"], - - exit_code=1, - ) - self.assertFalse(stdout) - self.assertIn( - "(some_instance)===\n\nTraceback (most recent call last):\n", - stderr, - ) - self.assertNotIn("some_schema", stderr) - - def test_instance_is_invalid_JSON_on_stdin(self): - instance = "not valid JSON!" - - self.assertOutputs( - files=dict(some_schema="{}"), - stdin=StringIO(instance), - - argv=["some_schema"], - - exit_code=1, - stderr=f"""\ - Failed to parse : {_message_for(instance)} - """, - ) - - def test_instance_is_invalid_JSON_on_stdin_pretty_output(self): - stdout, stderr = self.run_cli( - files=dict(some_schema="{}"), - stdin=StringIO("not valid JSON!"), - - argv=["--output", "pretty", "some_schema"], - - exit_code=1, - ) - self.assertFalse(stdout) - self.assertIn( - "()===\n\nTraceback (most recent call last):\n", - stderr, - ) - self.assertNotIn("some_schema", stderr) - - def test_schema_is_invalid_JSON(self): - schema = "not valid JSON!" - - self.assertOutputs( - files=dict(some_schema=schema), - - argv=["some_schema"], - - exit_code=1, - stderr=f"""\ - Failed to parse 'some_schema': {_message_for(schema)} - """, - ) - - def test_schema_is_invalid_JSON_pretty_output(self): - stdout, stderr = self.run_cli( - files=dict(some_schema="not valid JSON!"), - - argv=["--output", "pretty", "some_schema"], - - exit_code=1, - ) - self.assertFalse(stdout) - self.assertIn( - "(some_schema)===\n\nTraceback (most recent call last):\n", - stderr, - ) - - def test_schema_and_instance_are_both_invalid_JSON(self): - """ - Only the schema error is reported, as we abort immediately. - """ - schema, instance = "not valid JSON!", "also not valid JSON!" - self.assertOutputs( - files=dict(some_schema=schema, some_instance=instance), - - argv=["some_schema"], - - exit_code=1, - stderr=f"""\ - Failed to parse 'some_schema': {_message_for(schema)} - """, - ) - - def test_schema_and_instance_are_both_invalid_JSON_pretty_output(self): - """ - Only the schema error is reported, as we abort immediately. - """ - stdout, stderr = self.run_cli( - files=dict( - some_schema="not valid JSON!", - some_instance="also not valid JSON!", - ), - - argv=["--output", "pretty", "-i", "some_instance", "some_schema"], - - exit_code=1, - ) - self.assertFalse(stdout) - self.assertIn( - "(some_schema)===\n\nTraceback (most recent call last):\n", - stderr, - ) - self.assertNotIn("some_instance", stderr) - - def test_instance_does_not_exist(self): - self.assertOutputs( - files=dict(some_schema="{}"), - argv=["-i", "nonexisting_instance", "some_schema"], - - exit_code=1, - stderr="""\ - 'nonexisting_instance' does not exist. - """, - ) - - def test_instance_does_not_exist_pretty_output(self): - self.assertOutputs( - files=dict(some_schema="{}"), - argv=[ - "--output", "pretty", - "-i", "nonexisting_instance", - "some_schema", - ], - - exit_code=1, - stderr="""\ - ===[FileNotFoundError]===(nonexisting_instance)=== - - 'nonexisting_instance' does not exist. - ----------------------------- - """, - ) - - def test_schema_does_not_exist(self): - self.assertOutputs( - argv=["nonexisting_schema"], - - exit_code=1, - stderr="'nonexisting_schema' does not exist.\n", - ) - - def test_schema_does_not_exist_pretty_output(self): - self.assertOutputs( - argv=["--output", "pretty", "nonexisting_schema"], - - exit_code=1, - stderr="""\ - ===[FileNotFoundError]===(nonexisting_schema)=== - - 'nonexisting_schema' does not exist. - ----------------------------- - """, - ) - - def test_neither_instance_nor_schema_exist(self): - self.assertOutputs( - argv=["-i", "nonexisting_instance", "nonexisting_schema"], - - exit_code=1, - stderr="'nonexisting_schema' does not exist.\n", - ) - - def test_neither_instance_nor_schema_exist_pretty_output(self): - self.assertOutputs( - argv=[ - "--output", "pretty", - "-i", "nonexisting_instance", - "nonexisting_schema", - ], - - exit_code=1, - stderr="""\ - ===[FileNotFoundError]===(nonexisting_schema)=== - - 'nonexisting_schema' does not exist. - ----------------------------- - """, - ) - - def test_successful_validation(self): - self.assertOutputs( - files=dict(some_schema="{}", some_instance="{}"), - argv=["-i", "some_instance", "some_schema"], - stdout="", - stderr="", - ) - - def test_successful_validation_pretty_output(self): - self.assertOutputs( - files=dict(some_schema="{}", some_instance="{}"), - argv=["--output", "pretty", "-i", "some_instance", "some_schema"], - stdout="===[SUCCESS]===(some_instance)===\n", - stderr="", - ) - - def test_successful_validation_of_stdin(self): - self.assertOutputs( - files=dict(some_schema="{}"), - stdin=StringIO("{}"), - argv=["some_schema"], - stdout="", - stderr="", - ) - - def test_successful_validation_of_stdin_pretty_output(self): - self.assertOutputs( - files=dict(some_schema="{}"), - stdin=StringIO("{}"), - argv=["--output", "pretty", "some_schema"], - stdout="===[SUCCESS]===()===\n", - stderr="", - ) - - def test_successful_validation_of_just_the_schema(self): - self.assertOutputs( - files=dict(some_schema="{}", some_instance="{}"), - argv=["-i", "some_instance", "some_schema"], - stdout="", - stderr="", - ) - - def test_successful_validation_of_just_the_schema_pretty_output(self): - self.assertOutputs( - files=dict(some_schema="{}", some_instance="{}"), - argv=["--output", "pretty", "-i", "some_instance", "some_schema"], - stdout="===[SUCCESS]===(some_instance)===\n", - stderr="", - ) - - def test_successful_validation_via_explicit_base_uri(self): - ref_schema_file = tempfile.NamedTemporaryFile(delete=False) - ref_schema_file.close() - self.addCleanup(os.remove, ref_schema_file.name) - - ref_path = Path(ref_schema_file.name) - ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') - - schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}' - - self.assertOutputs( - files=dict(some_schema=schema, some_instance="1"), - argv=[ - "-i", "some_instance", - "--base-uri", ref_path.parent.as_uri() + "/", - "some_schema", - ], - stdout="", - stderr="", - ) - - def test_unsuccessful_validation_via_explicit_base_uri(self): - ref_schema_file = tempfile.NamedTemporaryFile(delete=False) - ref_schema_file.close() - self.addCleanup(os.remove, ref_schema_file.name) - - ref_path = Path(ref_schema_file.name) - ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') - - schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}' - - self.assertOutputs( - files=dict(some_schema=schema, some_instance='"1"'), - argv=[ - "-i", "some_instance", - "--base-uri", ref_path.parent.as_uri() + "/", - "some_schema", - ], - exit_code=1, - stdout="", - stderr="1: '1' is not of type 'integer'\n", - ) - - def test_nonexistent_file_with_explicit_base_uri(self): - schema = '{"$ref": "someNonexistentFile.json#definitions/num"}' - instance = "1" - - with self.assertRaises(_RefResolutionError) as e: - self.assertOutputs( - files=dict( - some_schema=schema, - some_instance=instance, - ), - argv=[ - "-i", "some_instance", - "--base-uri", Path.cwd().as_uri(), - "some_schema", - ], - ) - error = str(e.exception) - self.assertIn(f"{os.sep}someNonexistentFile.json'", error) - - def test_invalid_explicit_base_uri(self): - schema = '{"$ref": "foo.json#definitions/num"}' - instance = "1" - - with self.assertRaises(_RefResolutionError) as e: - self.assertOutputs( - files=dict( - some_schema=schema, - some_instance=instance, - ), - argv=[ - "-i", "some_instance", - "--base-uri", "not@UR1", - "some_schema", - ], - ) - error = str(e.exception) - self.assertEqual( - error, "unknown url type: 'foo.json'", - ) - - def test_it_validates_using_the_latest_validator_when_unspecified(self): - # There isn't a better way now I can think of to ensure that the - # latest version was used, given that the call to validator_for - # is hidden inside the CLI, so guard that that's the case, and - # this test will have to be updated when versions change until - # we can think of a better way to ensure this behavior. - self.assertIs(Draft202012Validator, _LATEST_VERSION) - - self.assertOutputs( - files=dict(some_schema='{"const": "check"}', some_instance='"a"'), - argv=["-i", "some_instance", "some_schema"], - exit_code=1, - stdout="", - stderr="a: 'check' was expected\n", - ) - - def test_it_validates_using_draft7_when_specified(self): - """ - Specifically, `const` validation applies for Draft 7. - """ - schema = """ - { - "$schema": "http://json-schema.org/draft-07/schema#", - "const": "check" - } - """ - instance = '"foo"' - self.assertOutputs( - files=dict(some_schema=schema, some_instance=instance), - argv=["-i", "some_instance", "some_schema"], - exit_code=1, - stdout="", - stderr="foo: 'check' was expected\n", - ) - - def test_it_validates_using_draft4_when_specified(self): - """ - Specifically, `const` validation *does not* apply for Draft 4. - """ - schema = """ - { - "$schema": "http://json-schema.org/draft-04/schema#", - "const": "check" - } - """ - instance = '"foo"' - self.assertOutputs( - files=dict(some_schema=schema, some_instance=instance), - argv=["-i", "some_instance", "some_schema"], - stdout="", - stderr="", - ) - - -class TestParser(TestCase): - - FakeValidator = fake_validator() - - def test_find_validator_by_fully_qualified_object_name(self): - arguments = cli.parse_args( - [ - "--validator", - "jsonschema.tests.test_cli.TestParser.FakeValidator", - "--instance", "mem://some/instance", - "mem://some/schema", - ], - ) - self.assertIs(arguments["validator"], self.FakeValidator) - - def test_find_validator_in_jsonschema(self): - arguments = cli.parse_args( - [ - "--validator", "Draft4Validator", - "--instance", "mem://some/instance", - "mem://some/schema", - ], - ) - self.assertIs(arguments["validator"], Draft4Validator) - - def cli_output_for(self, *argv): - stdout, stderr = StringIO(), StringIO() - with redirect_stdout(stdout), redirect_stderr(stderr): # noqa: SIM117 - with self.assertRaises(SystemExit): - cli.parse_args(argv) - return stdout.getvalue(), stderr.getvalue() - - def test_unknown_output(self): - stdout, stderr = self.cli_output_for( - "--output", "foo", - "mem://some/schema", - ) - self.assertIn("invalid choice: 'foo'", stderr) - self.assertFalse(stdout) - - def test_useless_error_format(self): - stdout, stderr = self.cli_output_for( - "--output", "pretty", - "--error-format", "foo", - "mem://some/schema", - ) - self.assertIn( - "--error-format can only be used with --output plain", - stderr, - ) - self.assertFalse(stdout) - - -class TestCLIIntegration(TestCase): - def test_license(self): - output = subprocess.check_output( - [sys.executable, "-m", "pip", "show", "jsonschema"], - stderr=subprocess.STDOUT, - ) - self.assertIn(b"License: MIT", output) - - def test_version(self): - version = subprocess.check_output( - [sys.executable, "-W", "ignore", "-m", "jsonschema", "--version"], - stderr=subprocess.STDOUT, - ) - version = version.decode("utf-8").strip() - self.assertEqual(version, metadata.version("jsonschema")) - - def test_no_arguments_shows_usage_notes(self): - output = subprocess.check_output( - [sys.executable, "-m", "jsonschema"], - stderr=subprocess.STDOUT, - ) - output_for_help = subprocess.check_output( - [sys.executable, "-m", "jsonschema", "--help"], - stderr=subprocess.STDOUT, - ) - self.assertEqual(output, output_for_help) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_deprecations.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_deprecations.py deleted file mode 100644 index aea922d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_deprecations.py +++ /dev/null @@ -1,432 +0,0 @@ -from contextlib import contextmanager -from io import BytesIO -from unittest import TestCase, mock -import importlib.metadata -import json -import subprocess -import sys -import urllib.request - -import referencing.exceptions - -from jsonschema import FormatChecker, exceptions, protocols, validators - - -class TestDeprecations(TestCase): - def test_version(self): - """ - As of v4.0.0, __version__ is deprecated in favor of importlib.metadata. - """ - - message = "Accessing jsonschema.__version__ is deprecated" - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import __version__ - - self.assertEqual(__version__, importlib.metadata.version("jsonschema")) - self.assertEqual(w.filename, __file__) - - def test_validators_ErrorTree(self): - """ - As of v4.0.0, importing ErrorTree from jsonschema.validators is - deprecated in favor of doing so from jsonschema.exceptions. - """ - - message = "Importing ErrorTree from jsonschema.validators is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema.validators import ErrorTree - - self.assertEqual(ErrorTree, exceptions.ErrorTree) - self.assertEqual(w.filename, __file__) - - def test_import_ErrorTree(self): - """ - As of v4.18.0, importing ErrorTree from the package root is - deprecated in favor of doing so from jsonschema.exceptions. - """ - - message = "Importing ErrorTree directly from the jsonschema package " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import ErrorTree - - self.assertEqual(ErrorTree, exceptions.ErrorTree) - self.assertEqual(w.filename, __file__) - - def test_ErrorTree_setitem(self): - """ - As of v4.20.0, setting items on an ErrorTree is deprecated. - """ - - e = exceptions.ValidationError("some error", path=["foo"]) - tree = exceptions.ErrorTree() - subtree = exceptions.ErrorTree(errors=[e]) - - message = "ErrorTree.__setitem__ is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - tree["foo"] = subtree - - self.assertEqual(tree["foo"], subtree) - self.assertEqual(w.filename, __file__) - - def test_import_FormatError(self): - """ - As of v4.18.0, importing FormatError from the package root is - deprecated in favor of doing so from jsonschema.exceptions. - """ - - message = "Importing FormatError directly from the jsonschema package " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import FormatError - - self.assertEqual(FormatError, exceptions.FormatError) - self.assertEqual(w.filename, __file__) - - def test_import_Validator(self): - """ - As of v4.19.0, importing Validator from the package root is - deprecated in favor of doing so from jsonschema.protocols. - """ - - message = "Importing Validator directly from the jsonschema package " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import Validator - - self.assertEqual(Validator, protocols.Validator) - self.assertEqual(w.filename, __file__) - - def test_validators_validators(self): - """ - As of v4.0.0, accessing jsonschema.validators.validators is - deprecated. - """ - - message = "Accessing jsonschema.validators.validators is deprecated" - with self.assertWarnsRegex(DeprecationWarning, message) as w: - value = validators.validators - - self.assertEqual(value, validators._VALIDATORS) - self.assertEqual(w.filename, __file__) - - def test_validators_meta_schemas(self): - """ - As of v4.0.0, accessing jsonschema.validators.meta_schemas is - deprecated. - """ - - message = "Accessing jsonschema.validators.meta_schemas is deprecated" - with self.assertWarnsRegex(DeprecationWarning, message) as w: - value = validators.meta_schemas - - self.assertEqual(value, validators._META_SCHEMAS) - self.assertEqual(w.filename, __file__) - - def test_RefResolver_in_scope(self): - """ - As of v4.0.0, RefResolver.in_scope is deprecated. - """ - - resolver = validators._RefResolver.from_schema({}) - message = "jsonschema.RefResolver.in_scope is deprecated " - with self.assertWarnsRegex(DeprecationWarning, message) as w: # noqa: SIM117 - with resolver.in_scope("foo"): - pass - - self.assertEqual(w.filename, __file__) - - def test_Validator_is_valid_two_arguments(self): - """ - As of v4.0.0, calling is_valid with two arguments (to provide a - different schema) is deprecated. - """ - - validator = validators.Draft7Validator({}) - message = "Passing a schema to Validator.is_valid is deprecated " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - result = validator.is_valid("foo", {"type": "number"}) - - self.assertFalse(result) - self.assertEqual(w.filename, __file__) - - def test_Validator_iter_errors_two_arguments(self): - """ - As of v4.0.0, calling iter_errors with two arguments (to provide a - different schema) is deprecated. - """ - - validator = validators.Draft7Validator({}) - message = "Passing a schema to Validator.iter_errors is deprecated " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - error, = validator.iter_errors("foo", {"type": "number"}) - - self.assertEqual(error.validator, "type") - self.assertEqual(w.filename, __file__) - - def test_Validator_resolver(self): - """ - As of v4.18.0, accessing Validator.resolver is deprecated. - """ - - validator = validators.Draft7Validator({}) - message = "Accessing Draft7Validator.resolver is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - self.assertIsInstance(validator.resolver, validators._RefResolver) - - self.assertEqual(w.filename, __file__) - - def test_RefResolver(self): - """ - As of v4.18.0, RefResolver is fully deprecated. - """ - - message = "jsonschema.RefResolver is deprecated" - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import RefResolver - self.assertEqual(w.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema.validators import RefResolver # noqa: F401, F811 - self.assertEqual(w.filename, __file__) - - def test_RefResolutionError(self): - """ - As of v4.18.0, RefResolutionError is deprecated in favor of directly - catching errors from the referencing library. - """ - - message = "jsonschema.exceptions.RefResolutionError is deprecated" - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import RefResolutionError - - self.assertEqual(RefResolutionError, exceptions._RefResolutionError) - self.assertEqual(w.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema.exceptions import RefResolutionError - - self.assertEqual(RefResolutionError, exceptions._RefResolutionError) - self.assertEqual(w.filename, __file__) - - def test_catching_Unresolvable_directly(self): - """ - This behavior is the intended behavior (i.e. it's not deprecated), but - given we do "tricksy" things in the iterim to wrap exceptions in a - multiple inheritance subclass, we need to be extra sure it works and - stays working. - """ - validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) - - with self.assertRaises(referencing.exceptions.Unresolvable) as e: - validator.validate(12) - - expected = referencing.exceptions.Unresolvable(ref="urn:nothing") - self.assertEqual( - (e.exception, str(e.exception)), - (expected, "Unresolvable: urn:nothing"), - ) - - def test_catching_Unresolvable_via_RefResolutionError(self): - """ - Until RefResolutionError is removed, it is still possible to catch - exceptions from reference resolution using it, even though they may - have been raised by referencing. - """ - with self.assertWarns(DeprecationWarning): - from jsonschema import RefResolutionError - - validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) - - with self.assertRaises(referencing.exceptions.Unresolvable) as u: - validator.validate(12) - - with self.assertRaises(RefResolutionError) as e: - validator.validate(12) - - self.assertEqual( - (e.exception, str(e.exception)), - (u.exception, "Unresolvable: urn:nothing"), - ) - - def test_WrappedReferencingError_hashability(self): - """ - Ensure the wrapped referencing errors are hashable when possible. - """ - with self.assertWarns(DeprecationWarning): - from jsonschema import RefResolutionError - - validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) - - with self.assertRaises(referencing.exceptions.Unresolvable) as u: - validator.validate(12) - - with self.assertRaises(RefResolutionError) as e: - validator.validate(12) - - self.assertIn(e.exception, {u.exception}) - self.assertIn(u.exception, {e.exception}) - - def test_Validator_subclassing(self): - """ - As of v4.12.0, subclassing a validator class produces an explicit - deprecation warning. - - This was never intended to be public API (and some comments over the - years in issues said so, but obviously that's not a great way to make - sure it's followed). - - A future version will explicitly raise an error. - """ - - message = "Subclassing validator classes is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - class Subclass(validators.Draft202012Validator): - pass - - self.assertEqual(w.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, message) as w: - class AnotherSubclass(validators.create(meta_schema={})): - pass - - def test_FormatChecker_cls_checks(self): - """ - As of v4.14.0, FormatChecker.cls_checks is deprecated without - replacement. - """ - - self.addCleanup(FormatChecker.checkers.pop, "boom", None) - - message = "FormatChecker.cls_checks " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - FormatChecker.cls_checks("boom") - - self.assertEqual(w.filename, __file__) - - def test_draftN_format_checker(self): - """ - As of v4.16.0, accessing jsonschema.draftn_format_checker is deprecated - in favor of Validator.FORMAT_CHECKER. - """ - - message = "Accessing jsonschema.draft202012_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft202012_format_checker - - self.assertIs( - draft202012_format_checker, - validators.Draft202012Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - message = "Accessing jsonschema.draft201909_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft201909_format_checker - - self.assertIs( - draft201909_format_checker, - validators.Draft201909Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - message = "Accessing jsonschema.draft7_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft7_format_checker - - self.assertIs( - draft7_format_checker, - validators.Draft7Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - message = "Accessing jsonschema.draft6_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft6_format_checker - - self.assertIs( - draft6_format_checker, - validators.Draft6Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - message = "Accessing jsonschema.draft4_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft4_format_checker - - self.assertIs( - draft4_format_checker, - validators.Draft4Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - message = "Accessing jsonschema.draft3_format_checker is " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - from jsonschema import draft3_format_checker - - self.assertIs( - draft3_format_checker, - validators.Draft3Validator.FORMAT_CHECKER, - ) - self.assertEqual(w.filename, __file__) - - with self.assertRaises(ImportError): - from jsonschema import draft1234_format_checker # noqa: F401 - - def test_import_cli(self): - """ - As of v4.17.0, importing jsonschema.cli is deprecated. - """ - - message = "The jsonschema CLI is deprecated and will be removed " - with self.assertWarnsRegex(DeprecationWarning, message) as w: - import jsonschema.cli - importlib.reload(jsonschema.cli) - - self.assertEqual(w.filename, importlib.__file__) - - def test_cli(self): - """ - As of v4.17.0, the jsonschema CLI is deprecated. - """ - - process = subprocess.run( - [sys.executable, "-m", "jsonschema"], - capture_output=True, - check=True, - ) - self.assertIn(b"The jsonschema CLI is deprecated ", process.stderr) - - def test_automatic_remote_retrieval(self): - """ - Automatic retrieval of remote references is deprecated as of v4.18.0. - """ - ref = "http://bar#/$defs/baz" - schema = {"$defs": {"baz": {"type": "integer"}}} - - if "requests" in sys.modules: # pragma: no cover - self.addCleanup( - sys.modules.__setitem__, "requests", sys.modules["requests"], - ) - sys.modules["requests"] = None - - @contextmanager - def fake_urlopen(request): - self.assertIsInstance(request, urllib.request.Request) - self.assertEqual(request.full_url, "http://bar") - - # Ha ha urllib.request.Request "normalizes" header names and - # Request.get_header does not also normalize them... - (header, value), = request.header_items() - self.assertEqual(header.lower(), "user-agent") - self.assertEqual( - value, "python-jsonschema (deprecated $ref resolution)", - ) - yield BytesIO(json.dumps(schema).encode("utf8")) - - validator = validators.Draft202012Validator({"$ref": ref}) - - message = "Automatically retrieving remote references " - patch = mock.patch.object(urllib.request, "urlopen", new=fake_urlopen) - - with patch, self.assertWarnsRegex(DeprecationWarning, message): - self.assertEqual( - (validator.is_valid({}), validator.is_valid(37)), - (False, True), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_exceptions.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_exceptions.py deleted file mode 100644 index 69114e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_exceptions.py +++ /dev/null @@ -1,702 +0,0 @@ -from unittest import TestCase -import textwrap - -from jsonschema import exceptions -from jsonschema.validators import _LATEST_VERSION - - -class TestBestMatch(TestCase): - def best_match_of(self, instance, schema): - errors = list(_LATEST_VERSION(schema).iter_errors(instance)) - msg = f"No errors found for {instance} under {schema!r}!" - self.assertTrue(errors, msg=msg) - - best = exceptions.best_match(iter(errors)) - reversed_best = exceptions.best_match(reversed(errors)) - - self.assertEqual( - best._contents(), - reversed_best._contents(), - f"No consistent best match!\nGot: {best}\n\nThen: {reversed_best}", - ) - return best - - def test_shallower_errors_are_better_matches(self): - schema = { - "properties": { - "foo": { - "minProperties": 2, - "properties": {"bar": {"type": "object"}}, - }, - }, - } - best = self.best_match_of(instance={"foo": {"bar": []}}, schema=schema) - self.assertEqual(best.validator, "minProperties") - - def test_oneOf_and_anyOf_are_weak_matches(self): - """ - A property you *must* match is probably better than one you have to - match a part of. - """ - - schema = { - "minProperties": 2, - "anyOf": [{"type": "string"}, {"type": "number"}], - "oneOf": [{"type": "string"}, {"type": "number"}], - } - best = self.best_match_of(instance={}, schema=schema) - self.assertEqual(best.validator, "minProperties") - - def test_if_the_most_relevant_error_is_anyOf_it_is_traversed(self): - """ - If the most relevant error is an anyOf, then we traverse its context - and select the otherwise *least* relevant error, since in this case - that means the most specific, deep, error inside the instance. - - I.e. since only one of the schemas must match, we look for the most - relevant one. - """ - - schema = { - "properties": { - "foo": { - "anyOf": [ - {"type": "string"}, - {"properties": {"bar": {"type": "array"}}}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) - self.assertEqual(best.validator_value, "array") - - def test_no_anyOf_traversal_for_equally_relevant_errors(self): - """ - We don't traverse into an anyOf (as above) if all of its context errors - seem to be equally "wrong" against the instance. - """ - - schema = { - "anyOf": [ - {"type": "string"}, - {"type": "integer"}, - {"type": "object"}, - ], - } - best = self.best_match_of(instance=[], schema=schema) - self.assertEqual(best.validator, "anyOf") - - def test_anyOf_traversal_for_single_equally_relevant_error(self): - """ - We *do* traverse anyOf with a single nested error, even though it is - vacuously equally relevant to itself. - """ - - schema = { - "anyOf": [ - {"type": "string"}, - ], - } - best = self.best_match_of(instance=[], schema=schema) - self.assertEqual(best.validator, "type") - - def test_anyOf_traversal_for_single_sibling_errors(self): - """ - We *do* traverse anyOf with a single subschema that fails multiple - times (e.g. on multiple items). - """ - - schema = { - "anyOf": [ - {"items": {"const": 37}}, - ], - } - best = self.best_match_of(instance=[12, 12], schema=schema) - self.assertEqual(best.validator, "const") - - def test_anyOf_traversal_for_non_type_matching_sibling_errors(self): - """ - We *do* traverse anyOf with multiple subschemas when one does not type - match. - """ - - schema = { - "anyOf": [ - {"type": "object"}, - {"items": {"const": 37}}, - ], - } - best = self.best_match_of(instance=[12, 12], schema=schema) - self.assertEqual(best.validator, "const") - - def test_if_the_most_relevant_error_is_oneOf_it_is_traversed(self): - """ - If the most relevant error is an oneOf, then we traverse its context - and select the otherwise *least* relevant error, since in this case - that means the most specific, deep, error inside the instance. - - I.e. since only one of the schemas must match, we look for the most - relevant one. - """ - - schema = { - "properties": { - "foo": { - "oneOf": [ - {"type": "string"}, - {"properties": {"bar": {"type": "array"}}}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) - self.assertEqual(best.validator_value, "array") - - def test_no_oneOf_traversal_for_equally_relevant_errors(self): - """ - We don't traverse into an oneOf (as above) if all of its context errors - seem to be equally "wrong" against the instance. - """ - - schema = { - "oneOf": [ - {"type": "string"}, - {"type": "integer"}, - {"type": "object"}, - ], - } - best = self.best_match_of(instance=[], schema=schema) - self.assertEqual(best.validator, "oneOf") - - def test_oneOf_traversal_for_single_equally_relevant_error(self): - """ - We *do* traverse oneOf with a single nested error, even though it is - vacuously equally relevant to itself. - """ - - schema = { - "oneOf": [ - {"type": "string"}, - ], - } - best = self.best_match_of(instance=[], schema=schema) - self.assertEqual(best.validator, "type") - - def test_oneOf_traversal_for_single_sibling_errors(self): - """ - We *do* traverse oneOf with a single subschema that fails multiple - times (e.g. on multiple items). - """ - - schema = { - "oneOf": [ - {"items": {"const": 37}}, - ], - } - best = self.best_match_of(instance=[12, 12], schema=schema) - self.assertEqual(best.validator, "const") - - def test_oneOf_traversal_for_non_type_matching_sibling_errors(self): - """ - We *do* traverse oneOf with multiple subschemas when one does not type - match. - """ - - schema = { - "oneOf": [ - {"type": "object"}, - {"items": {"const": 37}}, - ], - } - best = self.best_match_of(instance=[12, 12], schema=schema) - self.assertEqual(best.validator, "const") - - def test_if_the_most_relevant_error_is_allOf_it_is_traversed(self): - """ - Now, if the error is allOf, we traverse but select the *most* relevant - error from the context, because all schemas here must match anyways. - """ - - schema = { - "properties": { - "foo": { - "allOf": [ - {"type": "string"}, - {"properties": {"bar": {"type": "array"}}}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) - self.assertEqual(best.validator_value, "string") - - def test_nested_context_for_oneOf(self): - """ - We traverse into nested contexts (a oneOf containing an error in a - nested oneOf here). - """ - - schema = { - "properties": { - "foo": { - "oneOf": [ - {"type": "string"}, - { - "oneOf": [ - {"type": "string"}, - { - "properties": { - "bar": {"type": "array"}, - }, - }, - ], - }, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) - self.assertEqual(best.validator_value, "array") - - def test_it_prioritizes_matching_types(self): - schema = { - "properties": { - "foo": { - "anyOf": [ - {"type": "array", "minItems": 2}, - {"type": "string", "minLength": 10}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": "bar"}, schema=schema) - self.assertEqual(best.validator, "minLength") - - reordered = { - "properties": { - "foo": { - "anyOf": [ - {"type": "string", "minLength": 10}, - {"type": "array", "minItems": 2}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) - self.assertEqual(best.validator, "minLength") - - def test_it_prioritizes_matching_union_types(self): - schema = { - "properties": { - "foo": { - "anyOf": [ - {"type": ["array", "object"], "minItems": 2}, - {"type": ["integer", "string"], "minLength": 10}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": "bar"}, schema=schema) - self.assertEqual(best.validator, "minLength") - - reordered = { - "properties": { - "foo": { - "anyOf": [ - {"type": "string", "minLength": 10}, - {"type": "array", "minItems": 2}, - ], - }, - }, - } - best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) - self.assertEqual(best.validator, "minLength") - - def test_boolean_schemas(self): - schema = {"properties": {"foo": False}} - best = self.best_match_of(instance={"foo": "bar"}, schema=schema) - self.assertIsNone(best.validator) - - def test_one_error(self): - validator = _LATEST_VERSION({"minProperties": 2}) - error, = validator.iter_errors({}) - self.assertEqual( - exceptions.best_match(validator.iter_errors({})).validator, - "minProperties", - ) - - def test_no_errors(self): - validator = _LATEST_VERSION({}) - self.assertIsNone(exceptions.best_match(validator.iter_errors({}))) - - -class TestByRelevance(TestCase): - def test_short_paths_are_better_matches(self): - shallow = exceptions.ValidationError("Oh no!", path=["baz"]) - deep = exceptions.ValidationError("Oh yes!", path=["foo", "bar"]) - match = max([shallow, deep], key=exceptions.relevance) - self.assertIs(match, shallow) - - match = max([deep, shallow], key=exceptions.relevance) - self.assertIs(match, shallow) - - def test_global_errors_are_even_better_matches(self): - shallow = exceptions.ValidationError("Oh no!", path=[]) - deep = exceptions.ValidationError("Oh yes!", path=["foo"]) - - errors = sorted([shallow, deep], key=exceptions.relevance) - self.assertEqual( - [list(error.path) for error in errors], - [["foo"], []], - ) - - errors = sorted([deep, shallow], key=exceptions.relevance) - self.assertEqual( - [list(error.path) for error in errors], - [["foo"], []], - ) - - def test_weak_keywords_are_lower_priority(self): - weak = exceptions.ValidationError("Oh no!", path=[], validator="a") - normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") - - best_match = exceptions.by_relevance(weak="a") - - match = max([weak, normal], key=best_match) - self.assertIs(match, normal) - - match = max([normal, weak], key=best_match) - self.assertIs(match, normal) - - def test_strong_keywords_are_higher_priority(self): - weak = exceptions.ValidationError("Oh no!", path=[], validator="a") - normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") - strong = exceptions.ValidationError("Oh fine!", path=[], validator="c") - - best_match = exceptions.by_relevance(weak="a", strong="c") - - match = max([weak, normal, strong], key=best_match) - self.assertIs(match, strong) - - match = max([strong, normal, weak], key=best_match) - self.assertIs(match, strong) - - -class TestErrorTree(TestCase): - def test_it_knows_how_many_total_errors_it_contains(self): - # FIXME: #442 - errors = [ - exceptions.ValidationError("Something", validator=i) - for i in range(8) - ] - tree = exceptions.ErrorTree(errors) - self.assertEqual(tree.total_errors, 8) - - def test_it_contains_an_item_if_the_item_had_an_error(self): - errors = [exceptions.ValidationError("a message", path=["bar"])] - tree = exceptions.ErrorTree(errors) - self.assertIn("bar", tree) - - def test_it_does_not_contain_an_item_if_the_item_had_no_error(self): - errors = [exceptions.ValidationError("a message", path=["bar"])] - tree = exceptions.ErrorTree(errors) - self.assertNotIn("foo", tree) - - def test_keywords_that_failed_appear_in_errors_dict(self): - error = exceptions.ValidationError("a message", validator="foo") - tree = exceptions.ErrorTree([error]) - self.assertEqual(tree.errors, {"foo": error}) - - def test_it_creates_a_child_tree_for_each_nested_path(self): - errors = [ - exceptions.ValidationError("a bar message", path=["bar"]), - exceptions.ValidationError("a bar -> 0 message", path=["bar", 0]), - ] - tree = exceptions.ErrorTree(errors) - self.assertIn(0, tree["bar"]) - self.assertNotIn(1, tree["bar"]) - - def test_children_have_their_errors_dicts_built(self): - e1, e2 = ( - exceptions.ValidationError("1", validator="foo", path=["bar", 0]), - exceptions.ValidationError("2", validator="quux", path=["bar", 0]), - ) - tree = exceptions.ErrorTree([e1, e2]) - self.assertEqual(tree["bar"][0].errors, {"foo": e1, "quux": e2}) - - def test_multiple_errors_with_instance(self): - e1, e2 = ( - exceptions.ValidationError( - "1", - validator="foo", - path=["bar", "bar2"], - instance="i1"), - exceptions.ValidationError( - "2", - validator="quux", - path=["foobar", 2], - instance="i2"), - ) - exceptions.ErrorTree([e1, e2]) - - def test_it_does_not_contain_subtrees_that_are_not_in_the_instance(self): - error = exceptions.ValidationError("123", validator="foo", instance=[]) - tree = exceptions.ErrorTree([error]) - - with self.assertRaises(IndexError): - tree[0] - - def test_if_its_in_the_tree_anyhow_it_does_not_raise_an_error(self): - """ - If a keyword refers to a path that isn't in the instance, the - tree still properly returns a subtree for that path. - """ - - error = exceptions.ValidationError( - "a message", validator="foo", instance={}, path=["foo"], - ) - tree = exceptions.ErrorTree([error]) - self.assertIsInstance(tree["foo"], exceptions.ErrorTree) - - def test_iter(self): - e1, e2 = ( - exceptions.ValidationError( - "1", - validator="foo", - path=["bar", "bar2"], - instance="i1"), - exceptions.ValidationError( - "2", - validator="quux", - path=["foobar", 2], - instance="i2"), - ) - tree = exceptions.ErrorTree([e1, e2]) - self.assertEqual(set(tree), {"bar", "foobar"}) - - def test_repr_single(self): - error = exceptions.ValidationError( - "1", - validator="foo", - path=["bar", "bar2"], - instance="i1", - ) - tree = exceptions.ErrorTree([error]) - self.assertEqual(repr(tree), "") - - def test_repr_multiple(self): - e1, e2 = ( - exceptions.ValidationError( - "1", - validator="foo", - path=["bar", "bar2"], - instance="i1"), - exceptions.ValidationError( - "2", - validator="quux", - path=["foobar", 2], - instance="i2"), - ) - tree = exceptions.ErrorTree([e1, e2]) - self.assertEqual(repr(tree), "") - - def test_repr_empty(self): - tree = exceptions.ErrorTree([]) - self.assertEqual(repr(tree), "") - - -class TestErrorInitReprStr(TestCase): - def make_error(self, **kwargs): - defaults = dict( - message="hello", - validator="type", - validator_value="string", - instance=5, - schema={"type": "string"}, - ) - defaults.update(kwargs) - return exceptions.ValidationError(**defaults) - - def assertShows(self, expected, **kwargs): - expected = textwrap.dedent(expected).rstrip("\n") - - error = self.make_error(**kwargs) - message_line, _, rest = str(error).partition("\n") - self.assertEqual(message_line, error.message) - self.assertEqual(rest, expected) - - def test_it_calls_super_and_sets_args(self): - error = self.make_error() - self.assertGreater(len(error.args), 1) - - def test_repr(self): - self.assertEqual( - repr(exceptions.ValidationError(message="Hello!")), - "", - ) - - def test_unset_error(self): - error = exceptions.ValidationError("message") - self.assertEqual(str(error), "message") - - kwargs = { - "validator": "type", - "validator_value": "string", - "instance": 5, - "schema": {"type": "string"}, - } - # Just the message should show if any of the attributes are unset - for attr in kwargs: - k = dict(kwargs) - del k[attr] - error = exceptions.ValidationError("message", **k) - self.assertEqual(str(error), "message") - - def test_empty_paths(self): - self.assertShows( - """ - Failed validating 'type' in schema: - {'type': 'string'} - - On instance: - 5 - """, - path=[], - schema_path=[], - ) - - def test_one_item_paths(self): - self.assertShows( - """ - Failed validating 'type' in schema: - {'type': 'string'} - - On instance[0]: - 5 - """, - path=[0], - schema_path=["items"], - ) - - def test_multiple_item_paths(self): - self.assertShows( - """ - Failed validating 'type' in schema['items'][0]: - {'type': 'string'} - - On instance[0]['a']: - 5 - """, - path=[0, "a"], - schema_path=["items", 0, 1], - ) - - def test_uses_pprint(self): - self.assertShows( - """ - Failed validating 'maxLength' in schema: - {0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - 10: 10, - 11: 11, - 12: 12, - 13: 13, - 14: 14, - 15: 15, - 16: 16, - 17: 17, - 18: 18, - 19: 19} - - On instance: - [0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24] - """, - instance=list(range(25)), - schema=dict(zip(range(20), range(20))), - validator="maxLength", - ) - - def test_does_not_reorder_dicts(self): - self.assertShows( - """ - Failed validating 'type' in schema: - {'do': 3, 'not': 7, 'sort': 37, 'me': 73} - - On instance: - {'here': 73, 'too': 37, 'no': 7, 'sorting': 3} - """, - schema={ - "do": 3, - "not": 7, - "sort": 37, - "me": 73, - }, - instance={ - "here": 73, - "too": 37, - "no": 7, - "sorting": 3, - }, - ) - - def test_str_works_with_instances_having_overriden_eq_operator(self): - """ - Check for #164 which rendered exceptions unusable when a - `ValidationError` involved instances with an `__eq__` method - that returned truthy values. - """ - - class DontEQMeBro: - def __eq__(this, other): # pragma: no cover - self.fail("Don't!") - - def __ne__(this, other): # pragma: no cover - self.fail("Don't!") - - instance = DontEQMeBro() - error = exceptions.ValidationError( - "a message", - validator="foo", - instance=instance, - validator_value="some", - schema="schema", - ) - self.assertIn(repr(instance), str(error)) - - -class TestHashable(TestCase): - def test_hashable(self): - {exceptions.ValidationError("")} - {exceptions.SchemaError("")} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_format.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_format.py deleted file mode 100644 index d829f98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_format.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Tests for the parts of jsonschema related to the :kw:`format` keyword. -""" - -from unittest import TestCase - -from jsonschema import FormatChecker, ValidationError -from jsonschema.exceptions import FormatError -from jsonschema.validators import Draft4Validator - -BOOM = ValueError("Boom!") -BANG = ZeroDivisionError("Bang!") - - -def boom(thing): - if thing == "bang": - raise BANG - raise BOOM - - -class TestFormatChecker(TestCase): - def test_it_can_validate_no_formats(self): - checker = FormatChecker(formats=()) - self.assertFalse(checker.checkers) - - def test_it_raises_a_key_error_for_unknown_formats(self): - with self.assertRaises(KeyError): - FormatChecker(formats=["o noes"]) - - def test_it_can_register_cls_checkers(self): - original = dict(FormatChecker.checkers) - self.addCleanup(FormatChecker.checkers.pop, "boom") - with self.assertWarns(DeprecationWarning): - FormatChecker.cls_checks("boom")(boom) - self.assertEqual( - FormatChecker.checkers, - dict(original, boom=(boom, ())), - ) - - def test_it_can_register_checkers(self): - checker = FormatChecker() - checker.checks("boom")(boom) - self.assertEqual( - checker.checkers, - dict(FormatChecker.checkers, boom=(boom, ())), - ) - - def test_it_catches_registered_errors(self): - checker = FormatChecker() - checker.checks("boom", raises=type(BOOM))(boom) - - with self.assertRaises(FormatError) as cm: - checker.check(instance=12, format="boom") - - self.assertIs(cm.exception.cause, BOOM) - self.assertIs(cm.exception.__cause__, BOOM) - self.assertEqual(str(cm.exception), "12 is not a 'boom'") - - # Unregistered errors should not be caught - with self.assertRaises(type(BANG)): - checker.check(instance="bang", format="boom") - - def test_format_error_causes_become_validation_error_causes(self): - checker = FormatChecker() - checker.checks("boom", raises=ValueError)(boom) - validator = Draft4Validator({"format": "boom"}, format_checker=checker) - - with self.assertRaises(ValidationError) as cm: - validator.validate("BOOM") - - self.assertIs(cm.exception.cause, BOOM) - self.assertIs(cm.exception.__cause__, BOOM) - - def test_format_checkers_come_with_defaults(self): - # This is bad :/ but relied upon. - # The docs for quite awhile recommended people do things like - # validate(..., format_checker=FormatChecker()) - # We should change that, but we can't without deprecation... - checker = FormatChecker() - with self.assertRaises(FormatError): - checker.check(instance="not-an-ipv4", format="ipv4") - - def test_repr(self): - checker = FormatChecker(formats=()) - checker.checks("foo")(lambda thing: True) # pragma: no cover - checker.checks("bar")(lambda thing: True) # pragma: no cover - checker.checks("baz")(lambda thing: True) # pragma: no cover - self.assertEqual( - repr(checker), - "", - ) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_jsonschema_test_suite.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_jsonschema_test_suite.py deleted file mode 100644 index 282c136..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_jsonschema_test_suite.py +++ /dev/null @@ -1,269 +0,0 @@ -""" -Test runner for the JSON Schema official test suite - -Tests comprehensive correctness of each draft's validator. - -See https://github.com/json-schema-org/JSON-Schema-Test-Suite for details. -""" - -import sys - -from jsonschema.tests._suite import Suite -import jsonschema - -SUITE = Suite() -DRAFT3 = SUITE.version(name="draft3") -DRAFT4 = SUITE.version(name="draft4") -DRAFT6 = SUITE.version(name="draft6") -DRAFT7 = SUITE.version(name="draft7") -DRAFT201909 = SUITE.version(name="draft2019-09") -DRAFT202012 = SUITE.version(name="draft2020-12") - - -def skip(message, **kwargs): - def skipper(test): - if all(value == getattr(test, attr) for attr, value in kwargs.items()): - return message - return skipper - - -def missing_format(Validator): - def missing_format(test): # pragma: no cover - schema = test.schema - if ( - schema is True - or schema is False - or "format" not in schema - or schema["format"] in Validator.FORMAT_CHECKER.checkers - or test.valid - ): - return - - return f"Format checker {schema['format']!r} not found." - return missing_format - - -def complex_email_validation(test): - if test.subject != "email": - return - - message = "Complex email validation is (intentionally) unsupported." - return skip( - message=message, - description="an invalid domain", - )(test) or skip( - message=message, - description="an invalid IPv4-address-literal", - )(test) or skip( - message=message, - description="dot after local part is not valid", - )(test) or skip( - message=message, - description="dot before local part is not valid", - )(test) or skip( - message=message, - description="two subsequent dots inside local part are not valid", - )(test) - - -if sys.version_info < (3, 9): # pragma: no cover - message = "Rejecting leading zeros is 3.9+" - allowed_leading_zeros = skip( - message=message, - subject="ipv4", - description="invalid leading zeroes, as they are treated as octals", - ) -else: - def allowed_leading_zeros(test): # pragma: no cover - return - - -def leap_second(test): - message = "Leap seconds are unsupported." - return skip( - message=message, - subject="time", - description="a valid time string with leap second", - )(test) or skip( - message=message, - subject="time", - description="a valid time string with leap second, Zulu", - )(test) or skip( - message=message, - subject="time", - description="a valid time string with leap second with offset", - )(test) or skip( - message=message, - subject="time", - description="valid leap second, positive time-offset", - )(test) or skip( - message=message, - subject="time", - description="valid leap second, negative time-offset", - )(test) or skip( - message=message, - subject="time", - description="valid leap second, large positive time-offset", - )(test) or skip( - message=message, - subject="time", - description="valid leap second, large negative time-offset", - )(test) or skip( - message=message, - subject="time", - description="valid leap second, zero time-offset", - )(test) or skip( - message=message, - subject="date-time", - description="a valid date-time with a leap second, UTC", - )(test) or skip( - message=message, - subject="date-time", - description="a valid date-time with a leap second, with minus offset", - )(test) - - -TestDraft3 = DRAFT3.to_unittest_testcase( - DRAFT3.cases(), - DRAFT3.format_cases(), - DRAFT3.optional_cases_of(name="bignum"), - DRAFT3.optional_cases_of(name="non-bmp-regex"), - DRAFT3.optional_cases_of(name="zeroTerminatedFloats"), - Validator=jsonschema.Draft3Validator, - format_checker=jsonschema.Draft3Validator.FORMAT_CHECKER, - skip=lambda test: ( - missing_format(jsonschema.Draft3Validator)(test) - or complex_email_validation(test) - ), -) - - -TestDraft4 = DRAFT4.to_unittest_testcase( - DRAFT4.cases(), - DRAFT4.format_cases(), - DRAFT4.optional_cases_of(name="bignum"), - DRAFT4.optional_cases_of(name="float-overflow"), - DRAFT4.optional_cases_of(name="id"), - DRAFT4.optional_cases_of(name="non-bmp-regex"), - DRAFT4.optional_cases_of(name="zeroTerminatedFloats"), - Validator=jsonschema.Draft4Validator, - format_checker=jsonschema.Draft4Validator.FORMAT_CHECKER, - skip=lambda test: ( - allowed_leading_zeros(test) - or leap_second(test) - or missing_format(jsonschema.Draft4Validator)(test) - or complex_email_validation(test) - ), -) - - -TestDraft6 = DRAFT6.to_unittest_testcase( - DRAFT6.cases(), - DRAFT6.format_cases(), - DRAFT6.optional_cases_of(name="bignum"), - DRAFT6.optional_cases_of(name="float-overflow"), - DRAFT6.optional_cases_of(name="id"), - DRAFT6.optional_cases_of(name="non-bmp-regex"), - Validator=jsonschema.Draft6Validator, - format_checker=jsonschema.Draft6Validator.FORMAT_CHECKER, - skip=lambda test: ( - allowed_leading_zeros(test) - or leap_second(test) - or missing_format(jsonschema.Draft6Validator)(test) - or complex_email_validation(test) - ), -) - - -TestDraft7 = DRAFT7.to_unittest_testcase( - DRAFT7.cases(), - DRAFT7.format_cases(), - DRAFT7.optional_cases_of(name="bignum"), - DRAFT7.optional_cases_of(name="cross-draft"), - DRAFT7.optional_cases_of(name="float-overflow"), - DRAFT6.optional_cases_of(name="id"), - DRAFT7.optional_cases_of(name="non-bmp-regex"), - DRAFT7.optional_cases_of(name="unknownKeyword"), - Validator=jsonschema.Draft7Validator, - format_checker=jsonschema.Draft7Validator.FORMAT_CHECKER, - skip=lambda test: ( - allowed_leading_zeros(test) - or leap_second(test) - or missing_format(jsonschema.Draft7Validator)(test) - or complex_email_validation(test) - ), -) - - -TestDraft201909 = DRAFT201909.to_unittest_testcase( - DRAFT201909.cases(), - DRAFT201909.optional_cases_of(name="anchor"), - DRAFT201909.optional_cases_of(name="bignum"), - DRAFT201909.optional_cases_of(name="cross-draft"), - DRAFT201909.optional_cases_of(name="float-overflow"), - DRAFT201909.optional_cases_of(name="id"), - DRAFT201909.optional_cases_of(name="no-schema"), - DRAFT201909.optional_cases_of(name="non-bmp-regex"), - DRAFT201909.optional_cases_of(name="refOfUnknownKeyword"), - DRAFT201909.optional_cases_of(name="unknownKeyword"), - Validator=jsonschema.Draft201909Validator, - skip=skip( - message="Vocabulary support is still in-progress.", - subject="vocabulary", - description=( - "no validation: invalid number, but it still validates" - ), - ), -) - - -TestDraft201909Format = DRAFT201909.to_unittest_testcase( - DRAFT201909.format_cases(), - name="TestDraft201909Format", - Validator=jsonschema.Draft201909Validator, - format_checker=jsonschema.Draft201909Validator.FORMAT_CHECKER, - skip=lambda test: ( - complex_email_validation(test) - or allowed_leading_zeros(test) - or leap_second(test) - or missing_format(jsonschema.Draft201909Validator)(test) - or complex_email_validation(test) - ), -) - - -TestDraft202012 = DRAFT202012.to_unittest_testcase( - DRAFT202012.cases(), - DRAFT201909.optional_cases_of(name="anchor"), - DRAFT202012.optional_cases_of(name="bignum"), - DRAFT202012.optional_cases_of(name="cross-draft"), - DRAFT202012.optional_cases_of(name="float-overflow"), - DRAFT202012.optional_cases_of(name="id"), - DRAFT202012.optional_cases_of(name="no-schema"), - DRAFT202012.optional_cases_of(name="non-bmp-regex"), - DRAFT202012.optional_cases_of(name="refOfUnknownKeyword"), - DRAFT202012.optional_cases_of(name="unknownKeyword"), - Validator=jsonschema.Draft202012Validator, - skip=skip( - message="Vocabulary support is still in-progress.", - subject="vocabulary", - description=( - "no validation: invalid number, but it still validates" - ), - ), -) - - -TestDraft202012Format = DRAFT202012.to_unittest_testcase( - DRAFT202012.format_cases(), - name="TestDraft202012Format", - Validator=jsonschema.Draft202012Validator, - format_checker=jsonschema.Draft202012Validator.FORMAT_CHECKER, - skip=lambda test: ( - complex_email_validation(test) - or allowed_leading_zeros(test) - or leap_second(test) - or missing_format(jsonschema.Draft202012Validator)(test) - or complex_email_validation(test) - ), -) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_types.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_types.py deleted file mode 100644 index bd97b18..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_types.py +++ /dev/null @@ -1,221 +0,0 @@ -""" -Tests for the `TypeChecker`-based type interface. - -The actual correctness of the type checking is handled in -`test_jsonschema_test_suite`; these tests check that TypeChecker -functions correctly at a more granular level. -""" -from collections import namedtuple -from unittest import TestCase - -from jsonschema import ValidationError, _keywords -from jsonschema._types import TypeChecker -from jsonschema.exceptions import UndefinedTypeCheck, UnknownType -from jsonschema.validators import Draft202012Validator, extend - - -def equals_2(checker, instance): - return instance == 2 - - -def is_namedtuple(instance): - return isinstance(instance, tuple) and getattr(instance, "_fields", None) - - -def is_object_or_named_tuple(checker, instance): - if Draft202012Validator.TYPE_CHECKER.is_type(instance, "object"): - return True - return is_namedtuple(instance) - - -class TestTypeChecker(TestCase): - def test_is_type(self): - checker = TypeChecker({"two": equals_2}) - self.assertEqual( - ( - checker.is_type(instance=2, type="two"), - checker.is_type(instance="bar", type="two"), - ), - (True, False), - ) - - def test_is_unknown_type(self): - with self.assertRaises(UndefinedTypeCheck) as e: - TypeChecker().is_type(4, "foobar") - self.assertIn( - "'foobar' is unknown to this type checker", - str(e.exception), - ) - self.assertTrue( - e.exception.__suppress_context__, - msg="Expected the internal KeyError to be hidden.", - ) - - def test_checks_can_be_added_at_init(self): - checker = TypeChecker({"two": equals_2}) - self.assertEqual(checker, TypeChecker().redefine("two", equals_2)) - - def test_redefine_existing_type(self): - self.assertEqual( - TypeChecker().redefine("two", object()).redefine("two", equals_2), - TypeChecker().redefine("two", equals_2), - ) - - def test_remove(self): - self.assertEqual( - TypeChecker({"two": equals_2}).remove("two"), - TypeChecker(), - ) - - def test_remove_unknown_type(self): - with self.assertRaises(UndefinedTypeCheck) as context: - TypeChecker().remove("foobar") - self.assertIn("foobar", str(context.exception)) - - def test_redefine_many(self): - self.assertEqual( - TypeChecker().redefine_many({"foo": int, "bar": str}), - TypeChecker().redefine("foo", int).redefine("bar", str), - ) - - def test_remove_multiple(self): - self.assertEqual( - TypeChecker({"foo": int, "bar": str}).remove("foo", "bar"), - TypeChecker(), - ) - - def test_type_check_can_raise_key_error(self): - """ - Make sure no one writes: - - try: - self._type_checkers[type](...) - except KeyError: - - ignoring the fact that the function itself can raise that. - """ - - error = KeyError("Stuff") - - def raises_keyerror(checker, instance): - raise error - - with self.assertRaises(KeyError) as context: - TypeChecker({"foo": raises_keyerror}).is_type(4, "foo") - - self.assertIs(context.exception, error) - - def test_repr(self): - checker = TypeChecker({"foo": is_namedtuple, "bar": is_namedtuple}) - self.assertEqual(repr(checker), "") - - -class TestCustomTypes(TestCase): - def test_simple_type_can_be_extended(self): - def int_or_str_int(checker, instance): - if not isinstance(instance, (int, str)): - return False - try: - int(instance) - except ValueError: - return False - return True - - CustomValidator = extend( - Draft202012Validator, - type_checker=Draft202012Validator.TYPE_CHECKER.redefine( - "integer", int_or_str_int, - ), - ) - validator = CustomValidator({"type": "integer"}) - - validator.validate(4) - validator.validate("4") - - with self.assertRaises(ValidationError): - validator.validate(4.4) - - with self.assertRaises(ValidationError): - validator.validate("foo") - - def test_object_can_be_extended(self): - schema = {"type": "object"} - - Point = namedtuple("Point", ["x", "y"]) - - type_checker = Draft202012Validator.TYPE_CHECKER.redefine( - "object", is_object_or_named_tuple, - ) - - CustomValidator = extend( - Draft202012Validator, - type_checker=type_checker, - ) - validator = CustomValidator(schema) - - validator.validate(Point(x=4, y=5)) - - def test_object_extensions_require_custom_validators(self): - schema = {"type": "object", "required": ["x"]} - - type_checker = Draft202012Validator.TYPE_CHECKER.redefine( - "object", is_object_or_named_tuple, - ) - - CustomValidator = extend( - Draft202012Validator, - type_checker=type_checker, - ) - validator = CustomValidator(schema) - - Point = namedtuple("Point", ["x", "y"]) - # Cannot handle required - with self.assertRaises(ValidationError): - validator.validate(Point(x=4, y=5)) - - def test_object_extensions_can_handle_custom_validators(self): - schema = { - "type": "object", - "required": ["x"], - "properties": {"x": {"type": "integer"}}, - } - - type_checker = Draft202012Validator.TYPE_CHECKER.redefine( - "object", is_object_or_named_tuple, - ) - - def coerce_named_tuple(fn): - def coerced(validator, value, instance, schema): - if is_namedtuple(instance): - instance = instance._asdict() - return fn(validator, value, instance, schema) - return coerced - - required = coerce_named_tuple(_keywords.required) - properties = coerce_named_tuple(_keywords.properties) - - CustomValidator = extend( - Draft202012Validator, - type_checker=type_checker, - validators={"required": required, "properties": properties}, - ) - - validator = CustomValidator(schema) - - Point = namedtuple("Point", ["x", "y"]) - # Can now process required and properties - validator.validate(Point(x=4, y=5)) - - with self.assertRaises(ValidationError): - validator.validate(Point(x="not an integer", y=5)) - - # As well as still handle objects. - validator.validate({"x": 4, "y": 5}) - - with self.assertRaises(ValidationError): - validator.validate({"x": "not an integer", "y": 5}) - - def test_unknown_type(self): - with self.assertRaises(UnknownType) as e: - Draft202012Validator({}).is_type(12, "some unknown type") - self.assertIn("'some unknown type'", str(e.exception)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_utils.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_utils.py deleted file mode 100644 index d9764b0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_utils.py +++ /dev/null @@ -1,138 +0,0 @@ -from math import nan -from unittest import TestCase - -from jsonschema._utils import equal - - -class TestEqual(TestCase): - def test_none(self): - self.assertTrue(equal(None, None)) - - def test_nan(self): - self.assertTrue(equal(nan, nan)) - - -class TestDictEqual(TestCase): - def test_equal_dictionaries(self): - dict_1 = {"a": "b", "c": "d"} - dict_2 = {"c": "d", "a": "b"} - self.assertTrue(equal(dict_1, dict_2)) - - def test_equal_dictionaries_with_nan(self): - dict_1 = {"a": nan, "c": "d"} - dict_2 = {"c": "d", "a": nan} - self.assertTrue(equal(dict_1, dict_2)) - - def test_missing_key(self): - dict_1 = {"a": "b", "c": "d"} - dict_2 = {"c": "d", "x": "b"} - self.assertFalse(equal(dict_1, dict_2)) - - def test_additional_key(self): - dict_1 = {"a": "b", "c": "d"} - dict_2 = {"c": "d", "a": "b", "x": "x"} - self.assertFalse(equal(dict_1, dict_2)) - - def test_missing_value(self): - dict_1 = {"a": "b", "c": "d"} - dict_2 = {"c": "d", "a": "x"} - self.assertFalse(equal(dict_1, dict_2)) - - def test_empty_dictionaries(self): - dict_1 = {} - dict_2 = {} - self.assertTrue(equal(dict_1, dict_2)) - - def test_one_none(self): - dict_1 = None - dict_2 = {"a": "b", "c": "d"} - self.assertFalse(equal(dict_1, dict_2)) - - def test_same_item(self): - dict_1 = {"a": "b", "c": "d"} - self.assertTrue(equal(dict_1, dict_1)) - - def test_nested_equal(self): - dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} - dict_2 = {"c": "d", "a": {"a": "b", "c": "d"}} - self.assertTrue(equal(dict_1, dict_2)) - - def test_nested_dict_unequal(self): - dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} - dict_2 = {"c": "d", "a": {"a": "b", "c": "x"}} - self.assertFalse(equal(dict_1, dict_2)) - - def test_mixed_nested_equal(self): - dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} - dict_2 = {"c": "d", "a": ["a", "b", "c", "d"]} - self.assertTrue(equal(dict_1, dict_2)) - - def test_nested_list_unequal(self): - dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} - dict_2 = {"c": "d", "a": ["b", "c", "d", "a"]} - self.assertFalse(equal(dict_1, dict_2)) - - -class TestListEqual(TestCase): - def test_equal_lists(self): - list_1 = ["a", "b", "c"] - list_2 = ["a", "b", "c"] - self.assertTrue(equal(list_1, list_2)) - - def test_equal_lists_with_nan(self): - list_1 = ["a", nan, "c"] - list_2 = ["a", nan, "c"] - self.assertTrue(equal(list_1, list_2)) - - def test_unsorted_lists(self): - list_1 = ["a", "b", "c"] - list_2 = ["b", "b", "a"] - self.assertFalse(equal(list_1, list_2)) - - def test_first_list_larger(self): - list_1 = ["a", "b", "c"] - list_2 = ["a", "b"] - self.assertFalse(equal(list_1, list_2)) - - def test_second_list_larger(self): - list_1 = ["a", "b"] - list_2 = ["a", "b", "c"] - self.assertFalse(equal(list_1, list_2)) - - def test_list_with_none_unequal(self): - list_1 = ["a", "b", None] - list_2 = ["a", "b", "c"] - self.assertFalse(equal(list_1, list_2)) - - list_1 = ["a", "b", None] - list_2 = [None, "b", "c"] - self.assertFalse(equal(list_1, list_2)) - - def test_list_with_none_equal(self): - list_1 = ["a", None, "c"] - list_2 = ["a", None, "c"] - self.assertTrue(equal(list_1, list_2)) - - def test_empty_list(self): - list_1 = [] - list_2 = [] - self.assertTrue(equal(list_1, list_2)) - - def test_one_none(self): - list_1 = None - list_2 = [] - self.assertFalse(equal(list_1, list_2)) - - def test_same_list(self): - list_1 = ["a", "b", "c"] - self.assertTrue(equal(list_1, list_1)) - - def test_equal_nested_lists(self): - list_1 = ["a", ["b", "c"], "d"] - list_2 = ["a", ["b", "c"], "d"] - self.assertTrue(equal(list_1, list_2)) - - def test_unequal_nested_lists(self): - list_1 = ["a", ["b", "c"], "d"] - list_2 = ["a", [], "c"] - self.assertFalse(equal(list_1, list_2)) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_validators.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_validators.py deleted file mode 100644 index 28cc402..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/tests/test_validators.py +++ /dev/null @@ -1,2575 +0,0 @@ -from __future__ import annotations - -from collections import deque, namedtuple -from contextlib import contextmanager -from decimal import Decimal -from io import BytesIO -from typing import Any -from unittest import TestCase, mock -from urllib.request import pathname2url -import json -import os -import sys -import tempfile -import warnings - -from attrs import define, field -from referencing.jsonschema import DRAFT202012 -import referencing.exceptions - -from jsonschema import ( - FormatChecker, - TypeChecker, - exceptions, - protocols, - validators, -) - - -def fail(validator, errors, instance, schema): - for each in errors: - each.setdefault("message", "You told me to fail!") - yield exceptions.ValidationError(**each) - - -class TestCreateAndExtend(TestCase): - def setUp(self): - self.addCleanup( - self.assertEqual, - validators._META_SCHEMAS, - dict(validators._META_SCHEMAS), - ) - self.addCleanup( - self.assertEqual, - validators._VALIDATORS, - dict(validators._VALIDATORS), - ) - - self.meta_schema = {"$id": "some://meta/schema"} - self.validators = {"fail": fail} - self.type_checker = TypeChecker() - self.Validator = validators.create( - meta_schema=self.meta_schema, - validators=self.validators, - type_checker=self.type_checker, - ) - - def test_attrs(self): - self.assertEqual( - ( - self.Validator.VALIDATORS, - self.Validator.META_SCHEMA, - self.Validator.TYPE_CHECKER, - ), ( - self.validators, - self.meta_schema, - self.type_checker, - ), - ) - - def test_init(self): - schema = {"fail": []} - self.assertEqual(self.Validator(schema).schema, schema) - - def test_iter_errors_successful(self): - schema = {"fail": []} - validator = self.Validator(schema) - - errors = list(validator.iter_errors("hello")) - self.assertEqual(errors, []) - - def test_iter_errors_one_error(self): - schema = {"fail": [{"message": "Whoops!"}]} - validator = self.Validator(schema) - - expected_error = exceptions.ValidationError( - "Whoops!", - instance="goodbye", - schema=schema, - validator="fail", - validator_value=[{"message": "Whoops!"}], - schema_path=deque(["fail"]), - ) - - errors = list(validator.iter_errors("goodbye")) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0]._contents(), expected_error._contents()) - - def test_iter_errors_multiple_errors(self): - schema = { - "fail": [ - {"message": "First"}, - {"message": "Second!", "validator": "asdf"}, - {"message": "Third"}, - ], - } - validator = self.Validator(schema) - - errors = list(validator.iter_errors("goodbye")) - self.assertEqual(len(errors), 3) - - def test_if_a_version_is_provided_it_is_registered(self): - Validator = validators.create( - meta_schema={"$id": "something"}, - version="my version", - ) - self.addCleanup(validators._META_SCHEMAS.pop, "something") - self.addCleanup(validators._VALIDATORS.pop, "my version") - self.assertEqual(Validator.__name__, "MyVersionValidator") - self.assertEqual(Validator.__qualname__, "MyVersionValidator") - - def test_repr(self): - Validator = validators.create( - meta_schema={"$id": "something"}, - version="my version", - ) - self.addCleanup(validators._META_SCHEMAS.pop, "something") - self.addCleanup(validators._VALIDATORS.pop, "my version") - self.assertEqual( - repr(Validator({})), - "MyVersionValidator(schema={}, format_checker=None)", - ) - - def test_long_repr(self): - Validator = validators.create( - meta_schema={"$id": "something"}, - version="my version", - ) - self.addCleanup(validators._META_SCHEMAS.pop, "something") - self.addCleanup(validators._VALIDATORS.pop, "my version") - self.assertEqual( - repr(Validator({"a": list(range(1000))})), ( - "MyVersionValidator(schema={'a': [0, 1, 2, 3, 4, 5, ...]}, " - "format_checker=None)" - ), - ) - - def test_repr_no_version(self): - Validator = validators.create(meta_schema={}) - self.assertEqual( - repr(Validator({})), - "Validator(schema={}, format_checker=None)", - ) - - def test_dashes_are_stripped_from_validator_names(self): - Validator = validators.create( - meta_schema={"$id": "something"}, - version="foo-bar", - ) - self.addCleanup(validators._META_SCHEMAS.pop, "something") - self.addCleanup(validators._VALIDATORS.pop, "foo-bar") - self.assertEqual(Validator.__qualname__, "FooBarValidator") - - def test_if_a_version_is_not_provided_it_is_not_registered(self): - original = dict(validators._META_SCHEMAS) - validators.create(meta_schema={"id": "id"}) - self.assertEqual(validators._META_SCHEMAS, original) - - def test_validates_registers_meta_schema_id(self): - meta_schema_key = "meta schema id" - my_meta_schema = {"id": meta_schema_key} - - validators.create( - meta_schema=my_meta_schema, - version="my version", - id_of=lambda s: s.get("id", ""), - ) - self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) - self.addCleanup(validators._VALIDATORS.pop, "my version") - - self.assertIn(meta_schema_key, validators._META_SCHEMAS) - - def test_validates_registers_meta_schema_draft6_id(self): - meta_schema_key = "meta schema $id" - my_meta_schema = {"$id": meta_schema_key} - - validators.create( - meta_schema=my_meta_schema, - version="my version", - ) - self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) - self.addCleanup(validators._VALIDATORS.pop, "my version") - - self.assertIn(meta_schema_key, validators._META_SCHEMAS) - - def test_create_default_types(self): - Validator = validators.create(meta_schema={}, validators=()) - self.assertTrue( - all( - Validator({}).is_type(instance=instance, type=type) - for type, instance in [ - ("array", []), - ("boolean", True), - ("integer", 12), - ("null", None), - ("number", 12.0), - ("object", {}), - ("string", "foo"), - ] - ), - ) - - def test_check_schema_with_different_metaschema(self): - """ - One can create a validator class whose metaschema uses a different - dialect than itself. - """ - - NoEmptySchemasValidator = validators.create( - meta_schema={ - "$schema": validators.Draft202012Validator.META_SCHEMA["$id"], - "not": {"const": {}}, - }, - ) - NoEmptySchemasValidator.check_schema({"foo": "bar"}) - - with self.assertRaises(exceptions.SchemaError): - NoEmptySchemasValidator.check_schema({}) - - NoEmptySchemasValidator({"foo": "bar"}).validate("foo") - - def test_check_schema_with_different_metaschema_defaults_to_self(self): - """ - A validator whose metaschema doesn't declare $schema defaults to its - own validation behavior, not the latest "normal" specification. - """ - - NoEmptySchemasValidator = validators.create( - meta_schema={"fail": [{"message": "Meta schema whoops!"}]}, - validators={"fail": fail}, - ) - with self.assertRaises(exceptions.SchemaError): - NoEmptySchemasValidator.check_schema({}) - - def test_extend(self): - original = dict(self.Validator.VALIDATORS) - new = object() - - Extended = validators.extend( - self.Validator, - validators={"new": new}, - ) - self.assertEqual( - ( - Extended.VALIDATORS, - Extended.META_SCHEMA, - Extended.TYPE_CHECKER, - self.Validator.VALIDATORS, - ), ( - dict(original, new=new), - self.Validator.META_SCHEMA, - self.Validator.TYPE_CHECKER, - original, - ), - ) - - def test_extend_idof(self): - """ - Extending a validator preserves its notion of schema IDs. - """ - def id_of(schema): - return schema.get("__test__", self.Validator.ID_OF(schema)) - correct_id = "the://correct/id/" - meta_schema = { - "$id": "the://wrong/id/", - "__test__": correct_id, - } - Original = validators.create( - meta_schema=meta_schema, - validators=self.validators, - type_checker=self.type_checker, - id_of=id_of, - ) - self.assertEqual(Original.ID_OF(Original.META_SCHEMA), correct_id) - - Derived = validators.extend(Original) - self.assertEqual(Derived.ID_OF(Derived.META_SCHEMA), correct_id) - - def test_extend_applicable_validators(self): - """ - Extending a validator preserves its notion of applicable validators. - """ - - schema = { - "$defs": {"test": {"type": "number"}}, - "$ref": "#/$defs/test", - "maximum": 1, - } - - draft4 = validators.Draft4Validator(schema) - self.assertTrue(draft4.is_valid(37)) # as $ref ignores siblings - - Derived = validators.extend(validators.Draft4Validator) - self.assertTrue(Derived(schema).is_valid(37)) - - -class TestValidationErrorMessages(TestCase): - def message_for(self, instance, schema, *args, **kwargs): - cls = kwargs.pop("cls", validators._LATEST_VERSION) - cls.check_schema(schema) - validator = cls(schema, *args, **kwargs) - errors = list(validator.iter_errors(instance)) - self.assertTrue(errors, msg=f"No errors were raised for {instance!r}") - self.assertEqual( - len(errors), - 1, - msg=f"Expected exactly one error, found {errors!r}", - ) - return errors[0].message - - def test_single_type_failure(self): - message = self.message_for(instance=1, schema={"type": "string"}) - self.assertEqual(message, "1 is not of type 'string'") - - def test_single_type_list_failure(self): - message = self.message_for(instance=1, schema={"type": ["string"]}) - self.assertEqual(message, "1 is not of type 'string'") - - def test_multiple_type_failure(self): - types = "string", "object" - message = self.message_for(instance=1, schema={"type": list(types)}) - self.assertEqual(message, "1 is not of type 'string', 'object'") - - def test_object_with_named_type_failure(self): - schema = {"type": [{"name": "Foo", "minimum": 3}]} - message = self.message_for( - instance=1, - schema=schema, - cls=validators.Draft3Validator, - ) - self.assertEqual(message, "1 is not of type 'Foo'") - - def test_minimum(self): - message = self.message_for(instance=1, schema={"minimum": 2}) - self.assertEqual(message, "1 is less than the minimum of 2") - - def test_maximum(self): - message = self.message_for(instance=1, schema={"maximum": 0}) - self.assertEqual(message, "1 is greater than the maximum of 0") - - def test_dependencies_single_element(self): - depend, on = "bar", "foo" - schema = {"dependencies": {depend: on}} - message = self.message_for( - instance={"bar": 2}, - schema=schema, - cls=validators.Draft3Validator, - ) - self.assertEqual(message, "'foo' is a dependency of 'bar'") - - def test_object_without_title_type_failure_draft3(self): - type = {"type": [{"minimum": 3}]} - message = self.message_for( - instance=1, - schema={"type": [type]}, - cls=validators.Draft3Validator, - ) - self.assertEqual( - message, - "1 is not of type {'type': [{'minimum': 3}]}", - ) - - def test_dependencies_list_draft3(self): - depend, on = "bar", "foo" - schema = {"dependencies": {depend: [on]}} - message = self.message_for( - instance={"bar": 2}, - schema=schema, - cls=validators.Draft3Validator, - ) - self.assertEqual(message, "'foo' is a dependency of 'bar'") - - def test_dependencies_list_draft7(self): - depend, on = "bar", "foo" - schema = {"dependencies": {depend: [on]}} - message = self.message_for( - instance={"bar": 2}, - schema=schema, - cls=validators.Draft7Validator, - ) - self.assertEqual(message, "'foo' is a dependency of 'bar'") - - def test_additionalItems_single_failure(self): - message = self.message_for( - instance=[2], - schema={"items": [], "additionalItems": False}, - cls=validators.Draft3Validator, - ) - self.assertIn("(2 was unexpected)", message) - - def test_additionalItems_multiple_failures(self): - message = self.message_for( - instance=[1, 2, 3], - schema={"items": [], "additionalItems": False}, - cls=validators.Draft3Validator, - ) - self.assertIn("(1, 2, 3 were unexpected)", message) - - def test_additionalProperties_single_failure(self): - additional = "foo" - schema = {"additionalProperties": False} - message = self.message_for(instance={additional: 2}, schema=schema) - self.assertIn("('foo' was unexpected)", message) - - def test_additionalProperties_multiple_failures(self): - schema = {"additionalProperties": False} - message = self.message_for( - instance=dict.fromkeys(["foo", "bar"]), - schema=schema, - ) - - self.assertIn(repr("foo"), message) - self.assertIn(repr("bar"), message) - self.assertIn("were unexpected)", message) - - def test_const(self): - schema = {"const": 12} - message = self.message_for( - instance={"foo": "bar"}, - schema=schema, - ) - self.assertIn("12 was expected", message) - - def test_contains_draft_6(self): - schema = {"contains": {"const": 12}} - message = self.message_for( - instance=[2, {}, []], - schema=schema, - cls=validators.Draft6Validator, - ) - self.assertEqual( - message, - "None of [2, {}, []] are valid under the given schema", - ) - - def test_invalid_format_default_message(self): - checker = FormatChecker(formats=()) - checker.checks("thing")(lambda value: False) - - schema = {"format": "thing"} - message = self.message_for( - instance="bla", - schema=schema, - format_checker=checker, - ) - - self.assertIn(repr("bla"), message) - self.assertIn(repr("thing"), message) - self.assertIn("is not a", message) - - def test_additionalProperties_false_patternProperties(self): - schema = {"type": "object", - "additionalProperties": False, - "patternProperties": { - "^abc$": {"type": "string"}, - "^def$": {"type": "string"}, - }} - message = self.message_for( - instance={"zebra": 123}, - schema=schema, - cls=validators.Draft4Validator, - ) - self.assertEqual( - message, - "{} does not match any of the regexes: {}, {}".format( - repr("zebra"), repr("^abc$"), repr("^def$"), - ), - ) - message = self.message_for( - instance={"zebra": 123, "fish": 456}, - schema=schema, - cls=validators.Draft4Validator, - ) - self.assertEqual( - message, - "{}, {} do not match any of the regexes: {}, {}".format( - repr("fish"), repr("zebra"), repr("^abc$"), repr("^def$"), - ), - ) - - def test_False_schema(self): - message = self.message_for( - instance="something", - schema=False, - ) - self.assertEqual(message, "False schema does not allow 'something'") - - def test_multipleOf(self): - message = self.message_for( - instance=3, - schema={"multipleOf": 2}, - ) - self.assertEqual(message, "3 is not a multiple of 2") - - def test_minItems(self): - message = self.message_for(instance=[], schema={"minItems": 2}) - self.assertEqual(message, "[] is too short") - - def test_maxItems(self): - message = self.message_for(instance=[1, 2, 3], schema={"maxItems": 2}) - self.assertEqual(message, "[1, 2, 3] is too long") - - def test_minItems_1(self): - message = self.message_for(instance=[], schema={"minItems": 1}) - self.assertEqual(message, "[] should be non-empty") - - def test_maxItems_0(self): - message = self.message_for(instance=[1, 2, 3], schema={"maxItems": 0}) - self.assertEqual(message, "[1, 2, 3] is expected to be empty") - - def test_minLength(self): - message = self.message_for( - instance="", - schema={"minLength": 2}, - ) - self.assertEqual(message, "'' is too short") - - def test_maxLength(self): - message = self.message_for( - instance="abc", - schema={"maxLength": 2}, - ) - self.assertEqual(message, "'abc' is too long") - - def test_minLength_1(self): - message = self.message_for(instance="", schema={"minLength": 1}) - self.assertEqual(message, "'' should be non-empty") - - def test_maxLength_0(self): - message = self.message_for(instance="abc", schema={"maxLength": 0}) - self.assertEqual(message, "'abc' is expected to be empty") - - def test_minProperties(self): - message = self.message_for(instance={}, schema={"minProperties": 2}) - self.assertEqual(message, "{} does not have enough properties") - - def test_maxProperties(self): - message = self.message_for( - instance={"a": {}, "b": {}, "c": {}}, - schema={"maxProperties": 2}, - ) - self.assertEqual( - message, - "{'a': {}, 'b': {}, 'c': {}} has too many properties", - ) - - def test_minProperties_1(self): - message = self.message_for(instance={}, schema={"minProperties": 1}) - self.assertEqual(message, "{} should be non-empty") - - def test_maxProperties_0(self): - message = self.message_for( - instance={1: 2}, - schema={"maxProperties": 0}, - ) - self.assertEqual(message, "{1: 2} is expected to be empty") - - def test_prefixItems_with_items(self): - message = self.message_for( - instance=[1, 2, "foo"], - schema={"items": False, "prefixItems": [{}, {}]}, - ) - self.assertEqual( - message, - "Expected at most 2 items but found 1 extra: 'foo'", - ) - - def test_prefixItems_with_multiple_extra_items(self): - message = self.message_for( - instance=[1, 2, "foo", 5], - schema={"items": False, "prefixItems": [{}, {}]}, - ) - self.assertEqual( - message, - "Expected at most 2 items but found 2 extra: ['foo', 5]", - ) - - def test_pattern(self): - message = self.message_for( - instance="bbb", - schema={"pattern": "^a*$"}, - ) - self.assertEqual(message, "'bbb' does not match '^a*$'") - - def test_does_not_contain(self): - message = self.message_for( - instance=[], - schema={"contains": {"type": "string"}}, - ) - self.assertEqual( - message, - "[] does not contain items matching the given schema", - ) - - def test_contains_too_few(self): - message = self.message_for( - instance=["foo", 1], - schema={"contains": {"type": "string"}, "minContains": 2}, - ) - self.assertEqual( - message, - "Too few items match the given schema " - "(expected at least 2 but only 1 matched)", - ) - - def test_contains_too_few_both_constrained(self): - message = self.message_for( - instance=["foo", 1], - schema={ - "contains": {"type": "string"}, - "minContains": 2, - "maxContains": 4, - }, - ) - self.assertEqual( - message, - "Too few items match the given schema (expected at least 2 but " - "only 1 matched)", - ) - - def test_contains_too_many(self): - message = self.message_for( - instance=["foo", "bar", "baz"], - schema={"contains": {"type": "string"}, "maxContains": 2}, - ) - self.assertEqual( - message, - "Too many items match the given schema (expected at most 2)", - ) - - def test_contains_too_many_both_constrained(self): - message = self.message_for( - instance=["foo"] * 5, - schema={ - "contains": {"type": "string"}, - "minContains": 2, - "maxContains": 4, - }, - ) - self.assertEqual( - message, - "Too many items match the given schema (expected at most 4)", - ) - - def test_exclusiveMinimum(self): - message = self.message_for( - instance=3, - schema={"exclusiveMinimum": 5}, - ) - self.assertEqual( - message, - "3 is less than or equal to the minimum of 5", - ) - - def test_exclusiveMaximum(self): - message = self.message_for(instance=3, schema={"exclusiveMaximum": 2}) - self.assertEqual( - message, - "3 is greater than or equal to the maximum of 2", - ) - - def test_required(self): - message = self.message_for(instance={}, schema={"required": ["foo"]}) - self.assertEqual(message, "'foo' is a required property") - - def test_dependentRequired(self): - message = self.message_for( - instance={"foo": {}}, - schema={"dependentRequired": {"foo": ["bar"]}}, - ) - self.assertEqual(message, "'bar' is a dependency of 'foo'") - - def test_oneOf_matches_none(self): - message = self.message_for(instance={}, schema={"oneOf": [False]}) - self.assertEqual( - message, - "{} is not valid under any of the given schemas", - ) - - def test_oneOf_matches_too_many(self): - message = self.message_for(instance={}, schema={"oneOf": [True, True]}) - self.assertEqual(message, "{} is valid under each of True, True") - - def test_unevaluated_items(self): - schema = {"type": "array", "unevaluatedItems": False} - message = self.message_for(instance=["foo", "bar"], schema=schema) - self.assertIn( - message, - "Unevaluated items are not allowed ('foo', 'bar' were unexpected)", - ) - - def test_unevaluated_items_on_invalid_type(self): - schema = {"type": "array", "unevaluatedItems": False} - message = self.message_for(instance="foo", schema=schema) - self.assertEqual(message, "'foo' is not of type 'array'") - - def test_unevaluated_properties_invalid_against_subschema(self): - schema = { - "properties": {"foo": {"type": "string"}}, - "unevaluatedProperties": {"const": 12}, - } - message = self.message_for( - instance={ - "foo": "foo", - "bar": "bar", - "baz": 12, - }, - schema=schema, - ) - self.assertEqual( - message, - "Unevaluated properties are not valid under the given schema " - "('bar' was unevaluated and invalid)", - ) - - def test_unevaluated_properties_disallowed(self): - schema = {"type": "object", "unevaluatedProperties": False} - message = self.message_for( - instance={ - "foo": "foo", - "bar": "bar", - }, - schema=schema, - ) - self.assertEqual( - message, - "Unevaluated properties are not allowed " - "('bar', 'foo' were unexpected)", - ) - - def test_unevaluated_properties_on_invalid_type(self): - schema = {"type": "object", "unevaluatedProperties": False} - message = self.message_for(instance="foo", schema=schema) - self.assertEqual(message, "'foo' is not of type 'object'") - - def test_single_item(self): - schema = {"prefixItems": [{}], "items": False} - message = self.message_for( - instance=["foo", "bar", "baz"], - schema=schema, - ) - self.assertEqual( - message, - "Expected at most 1 item but found 2 extra: ['bar', 'baz']", - ) - - def test_heterogeneous_additionalItems_with_Items(self): - schema = {"items": [{}], "additionalItems": False} - message = self.message_for( - instance=["foo", "bar", 37], - schema=schema, - cls=validators.Draft7Validator, - ) - self.assertEqual( - message, - "Additional items are not allowed ('bar', 37 were unexpected)", - ) - - def test_heterogeneous_items_prefixItems(self): - schema = {"prefixItems": [{}], "items": False} - message = self.message_for( - instance=["foo", "bar", 37], - schema=schema, - ) - self.assertEqual( - message, - "Expected at most 1 item but found 2 extra: ['bar', 37]", - ) - - def test_heterogeneous_unevaluatedItems_prefixItems(self): - schema = {"prefixItems": [{}], "unevaluatedItems": False} - message = self.message_for( - instance=["foo", "bar", 37], - schema=schema, - ) - self.assertEqual( - message, - "Unevaluated items are not allowed ('bar', 37 were unexpected)", - ) - - def test_heterogeneous_properties_additionalProperties(self): - """ - Not valid deserialized JSON, but this should not blow up. - """ - schema = {"properties": {"foo": {}}, "additionalProperties": False} - message = self.message_for( - instance={"foo": {}, "a": "baz", 37: 12}, - schema=schema, - ) - self.assertEqual( - message, - "Additional properties are not allowed (37, 'a' were unexpected)", - ) - - def test_heterogeneous_properties_unevaluatedProperties(self): - """ - Not valid deserialized JSON, but this should not blow up. - """ - schema = {"properties": {"foo": {}}, "unevaluatedProperties": False} - message = self.message_for( - instance={"foo": {}, "a": "baz", 37: 12}, - schema=schema, - ) - self.assertEqual( - message, - "Unevaluated properties are not allowed (37, 'a' were unexpected)", - ) - - -class TestValidationErrorDetails(TestCase): - # TODO: These really need unit tests for each individual keyword, rather - # than just these higher level tests. - def test_anyOf(self): - instance = 5 - schema = { - "anyOf": [ - {"minimum": 20}, - {"type": "string"}, - ], - } - - validator = validators.Draft4Validator(schema) - errors = list(validator.iter_errors(instance)) - self.assertEqual(len(errors), 1) - e = errors[0] - - self.assertEqual(e.validator, "anyOf") - self.assertEqual(e.validator_value, schema["anyOf"]) - self.assertEqual(e.instance, instance) - self.assertEqual(e.schema, schema) - self.assertIsNone(e.parent) - - self.assertEqual(e.path, deque([])) - self.assertEqual(e.relative_path, deque([])) - self.assertEqual(e.absolute_path, deque([])) - self.assertEqual(e.json_path, "$") - - self.assertEqual(e.schema_path, deque(["anyOf"])) - self.assertEqual(e.relative_schema_path, deque(["anyOf"])) - self.assertEqual(e.absolute_schema_path, deque(["anyOf"])) - - self.assertEqual(len(e.context), 2) - - e1, e2 = sorted_errors(e.context) - - self.assertEqual(e1.validator, "minimum") - self.assertEqual(e1.validator_value, schema["anyOf"][0]["minimum"]) - self.assertEqual(e1.instance, instance) - self.assertEqual(e1.schema, schema["anyOf"][0]) - self.assertIs(e1.parent, e) - - self.assertEqual(e1.path, deque([])) - self.assertEqual(e1.absolute_path, deque([])) - self.assertEqual(e1.relative_path, deque([])) - self.assertEqual(e1.json_path, "$") - - self.assertEqual(e1.schema_path, deque([0, "minimum"])) - self.assertEqual(e1.relative_schema_path, deque([0, "minimum"])) - self.assertEqual( - e1.absolute_schema_path, deque(["anyOf", 0, "minimum"]), - ) - - self.assertFalse(e1.context) - - self.assertEqual(e2.validator, "type") - self.assertEqual(e2.validator_value, schema["anyOf"][1]["type"]) - self.assertEqual(e2.instance, instance) - self.assertEqual(e2.schema, schema["anyOf"][1]) - self.assertIs(e2.parent, e) - - self.assertEqual(e2.path, deque([])) - self.assertEqual(e2.relative_path, deque([])) - self.assertEqual(e2.absolute_path, deque([])) - self.assertEqual(e2.json_path, "$") - - self.assertEqual(e2.schema_path, deque([1, "type"])) - self.assertEqual(e2.relative_schema_path, deque([1, "type"])) - self.assertEqual(e2.absolute_schema_path, deque(["anyOf", 1, "type"])) - - self.assertEqual(len(e2.context), 0) - - def test_type(self): - instance = {"foo": 1} - schema = { - "type": [ - {"type": "integer"}, - { - "type": "object", - "properties": {"foo": {"enum": [2]}}, - }, - ], - } - - validator = validators.Draft3Validator(schema) - errors = list(validator.iter_errors(instance)) - self.assertEqual(len(errors), 1) - e = errors[0] - - self.assertEqual(e.validator, "type") - self.assertEqual(e.validator_value, schema["type"]) - self.assertEqual(e.instance, instance) - self.assertEqual(e.schema, schema) - self.assertIsNone(e.parent) - - self.assertEqual(e.path, deque([])) - self.assertEqual(e.relative_path, deque([])) - self.assertEqual(e.absolute_path, deque([])) - self.assertEqual(e.json_path, "$") - - self.assertEqual(e.schema_path, deque(["type"])) - self.assertEqual(e.relative_schema_path, deque(["type"])) - self.assertEqual(e.absolute_schema_path, deque(["type"])) - - self.assertEqual(len(e.context), 2) - - e1, e2 = sorted_errors(e.context) - - self.assertEqual(e1.validator, "type") - self.assertEqual(e1.validator_value, schema["type"][0]["type"]) - self.assertEqual(e1.instance, instance) - self.assertEqual(e1.schema, schema["type"][0]) - self.assertIs(e1.parent, e) - - self.assertEqual(e1.path, deque([])) - self.assertEqual(e1.relative_path, deque([])) - self.assertEqual(e1.absolute_path, deque([])) - self.assertEqual(e1.json_path, "$") - - self.assertEqual(e1.schema_path, deque([0, "type"])) - self.assertEqual(e1.relative_schema_path, deque([0, "type"])) - self.assertEqual(e1.absolute_schema_path, deque(["type", 0, "type"])) - - self.assertFalse(e1.context) - - self.assertEqual(e2.validator, "enum") - self.assertEqual(e2.validator_value, [2]) - self.assertEqual(e2.instance, 1) - self.assertEqual(e2.schema, {"enum": [2]}) - self.assertIs(e2.parent, e) - - self.assertEqual(e2.path, deque(["foo"])) - self.assertEqual(e2.relative_path, deque(["foo"])) - self.assertEqual(e2.absolute_path, deque(["foo"])) - self.assertEqual(e2.json_path, "$.foo") - - self.assertEqual( - e2.schema_path, deque([1, "properties", "foo", "enum"]), - ) - self.assertEqual( - e2.relative_schema_path, deque([1, "properties", "foo", "enum"]), - ) - self.assertEqual( - e2.absolute_schema_path, - deque(["type", 1, "properties", "foo", "enum"]), - ) - - self.assertFalse(e2.context) - - def test_single_nesting(self): - instance = {"foo": 2, "bar": [1], "baz": 15, "quux": "spam"} - schema = { - "properties": { - "foo": {"type": "string"}, - "bar": {"minItems": 2}, - "baz": {"maximum": 10, "enum": [2, 4, 6, 8]}, - }, - } - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2, e3, e4 = sorted_errors(errors) - - self.assertEqual(e1.path, deque(["bar"])) - self.assertEqual(e2.path, deque(["baz"])) - self.assertEqual(e3.path, deque(["baz"])) - self.assertEqual(e4.path, deque(["foo"])) - - self.assertEqual(e1.relative_path, deque(["bar"])) - self.assertEqual(e2.relative_path, deque(["baz"])) - self.assertEqual(e3.relative_path, deque(["baz"])) - self.assertEqual(e4.relative_path, deque(["foo"])) - - self.assertEqual(e1.absolute_path, deque(["bar"])) - self.assertEqual(e2.absolute_path, deque(["baz"])) - self.assertEqual(e3.absolute_path, deque(["baz"])) - self.assertEqual(e4.absolute_path, deque(["foo"])) - - self.assertEqual(e1.json_path, "$.bar") - self.assertEqual(e2.json_path, "$.baz") - self.assertEqual(e3.json_path, "$.baz") - self.assertEqual(e4.json_path, "$.foo") - - self.assertEqual(e1.validator, "minItems") - self.assertEqual(e2.validator, "enum") - self.assertEqual(e3.validator, "maximum") - self.assertEqual(e4.validator, "type") - - def test_multiple_nesting(self): - instance = [1, {"foo": 2, "bar": {"baz": [1]}}, "quux"] - schema = { - "type": "string", - "items": { - "type": ["string", "object"], - "properties": { - "foo": {"enum": [1, 3]}, - "bar": { - "type": "array", - "properties": { - "bar": {"required": True}, - "baz": {"minItems": 2}, - }, - }, - }, - }, - } - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2, e3, e4, e5, e6 = sorted_errors(errors) - - self.assertEqual(e1.path, deque([])) - self.assertEqual(e2.path, deque([0])) - self.assertEqual(e3.path, deque([1, "bar"])) - self.assertEqual(e4.path, deque([1, "bar", "bar"])) - self.assertEqual(e5.path, deque([1, "bar", "baz"])) - self.assertEqual(e6.path, deque([1, "foo"])) - - self.assertEqual(e1.json_path, "$") - self.assertEqual(e2.json_path, "$[0]") - self.assertEqual(e3.json_path, "$[1].bar") - self.assertEqual(e4.json_path, "$[1].bar.bar") - self.assertEqual(e5.json_path, "$[1].bar.baz") - self.assertEqual(e6.json_path, "$[1].foo") - - self.assertEqual(e1.schema_path, deque(["type"])) - self.assertEqual(e2.schema_path, deque(["items", "type"])) - self.assertEqual( - list(e3.schema_path), ["items", "properties", "bar", "type"], - ) - self.assertEqual( - list(e4.schema_path), - ["items", "properties", "bar", "properties", "bar", "required"], - ) - self.assertEqual( - list(e5.schema_path), - ["items", "properties", "bar", "properties", "baz", "minItems"], - ) - self.assertEqual( - list(e6.schema_path), ["items", "properties", "foo", "enum"], - ) - - self.assertEqual(e1.validator, "type") - self.assertEqual(e2.validator, "type") - self.assertEqual(e3.validator, "type") - self.assertEqual(e4.validator, "required") - self.assertEqual(e5.validator, "minItems") - self.assertEqual(e6.validator, "enum") - - def test_recursive(self): - schema = { - "definitions": { - "node": { - "anyOf": [{ - "type": "object", - "required": ["name", "children"], - "properties": { - "name": { - "type": "string", - }, - "children": { - "type": "object", - "patternProperties": { - "^.*$": { - "$ref": "#/definitions/node", - }, - }, - }, - }, - }], - }, - }, - "type": "object", - "required": ["root"], - "properties": {"root": {"$ref": "#/definitions/node"}}, - } - - instance = { - "root": { - "name": "root", - "children": { - "a": { - "name": "a", - "children": { - "ab": { - "name": "ab", - # missing "children" - }, - }, - }, - }, - }, - } - validator = validators.Draft4Validator(schema) - - e, = validator.iter_errors(instance) - self.assertEqual(e.absolute_path, deque(["root"])) - self.assertEqual( - e.absolute_schema_path, deque(["properties", "root", "anyOf"]), - ) - self.assertEqual(e.json_path, "$.root") - - e1, = e.context - self.assertEqual(e1.absolute_path, deque(["root", "children", "a"])) - self.assertEqual( - e1.absolute_schema_path, deque( - [ - "properties", - "root", - "anyOf", - 0, - "properties", - "children", - "patternProperties", - "^.*$", - "anyOf", - ], - ), - ) - self.assertEqual(e1.json_path, "$.root.children.a") - - e2, = e1.context - self.assertEqual( - e2.absolute_path, deque( - ["root", "children", "a", "children", "ab"], - ), - ) - self.assertEqual( - e2.absolute_schema_path, deque( - [ - "properties", - "root", - "anyOf", - 0, - "properties", - "children", - "patternProperties", - "^.*$", - "anyOf", - 0, - "properties", - "children", - "patternProperties", - "^.*$", - "anyOf", - ], - ), - ) - self.assertEqual(e2.json_path, "$.root.children.a.children.ab") - - def test_additionalProperties(self): - instance = {"bar": "bar", "foo": 2} - schema = {"additionalProperties": {"type": "integer", "minimum": 5}} - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2 = sorted_errors(errors) - - self.assertEqual(e1.path, deque(["bar"])) - self.assertEqual(e2.path, deque(["foo"])) - - self.assertEqual(e1.json_path, "$.bar") - self.assertEqual(e2.json_path, "$.foo") - - self.assertEqual(e1.validator, "type") - self.assertEqual(e2.validator, "minimum") - - def test_patternProperties(self): - instance = {"bar": 1, "foo": 2} - schema = { - "patternProperties": { - "bar": {"type": "string"}, - "foo": {"minimum": 5}, - }, - } - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2 = sorted_errors(errors) - - self.assertEqual(e1.path, deque(["bar"])) - self.assertEqual(e2.path, deque(["foo"])) - - self.assertEqual(e1.json_path, "$.bar") - self.assertEqual(e2.json_path, "$.foo") - - self.assertEqual(e1.validator, "type") - self.assertEqual(e2.validator, "minimum") - - def test_additionalItems(self): - instance = ["foo", 1] - schema = { - "items": [], - "additionalItems": {"type": "integer", "minimum": 5}, - } - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2 = sorted_errors(errors) - - self.assertEqual(e1.path, deque([0])) - self.assertEqual(e2.path, deque([1])) - - self.assertEqual(e1.json_path, "$[0]") - self.assertEqual(e2.json_path, "$[1]") - - self.assertEqual(e1.validator, "type") - self.assertEqual(e2.validator, "minimum") - - def test_additionalItems_with_items(self): - instance = ["foo", "bar", 1] - schema = { - "items": [{}], - "additionalItems": {"type": "integer", "minimum": 5}, - } - - validator = validators.Draft3Validator(schema) - errors = validator.iter_errors(instance) - e1, e2 = sorted_errors(errors) - - self.assertEqual(e1.path, deque([1])) - self.assertEqual(e2.path, deque([2])) - - self.assertEqual(e1.json_path, "$[1]") - self.assertEqual(e2.json_path, "$[2]") - - self.assertEqual(e1.validator, "type") - self.assertEqual(e2.validator, "minimum") - - def test_propertyNames(self): - instance = {"foo": 12} - schema = {"propertyNames": {"not": {"const": "foo"}}} - - validator = validators.Draft7Validator(schema) - error, = validator.iter_errors(instance) - - self.assertEqual(error.validator, "not") - self.assertEqual( - error.message, - "'foo' should not be valid under {'const': 'foo'}", - ) - self.assertEqual(error.path, deque([])) - self.assertEqual(error.json_path, "$") - self.assertEqual(error.schema_path, deque(["propertyNames", "not"])) - - def test_if_then(self): - schema = { - "if": {"const": 12}, - "then": {"const": 13}, - } - - validator = validators.Draft7Validator(schema) - error, = validator.iter_errors(12) - - self.assertEqual(error.validator, "const") - self.assertEqual(error.message, "13 was expected") - self.assertEqual(error.path, deque([])) - self.assertEqual(error.json_path, "$") - self.assertEqual(error.schema_path, deque(["then", "const"])) - - def test_if_else(self): - schema = { - "if": {"const": 12}, - "else": {"const": 13}, - } - - validator = validators.Draft7Validator(schema) - error, = validator.iter_errors(15) - - self.assertEqual(error.validator, "const") - self.assertEqual(error.message, "13 was expected") - self.assertEqual(error.path, deque([])) - self.assertEqual(error.json_path, "$") - self.assertEqual(error.schema_path, deque(["else", "const"])) - - def test_boolean_schema_False(self): - validator = validators.Draft7Validator(False) - error, = validator.iter_errors(12) - - self.assertEqual( - ( - error.message, - error.validator, - error.validator_value, - error.instance, - error.schema, - error.schema_path, - error.json_path, - ), - ( - "False schema does not allow 12", - None, - None, - 12, - False, - deque([]), - "$", - ), - ) - - def test_ref(self): - ref, schema = "someRef", {"additionalProperties": {"type": "integer"}} - validator = validators.Draft7Validator( - {"$ref": ref}, - resolver=validators._RefResolver("", {}, store={ref: schema}), - ) - error, = validator.iter_errors({"foo": "notAnInteger"}) - - self.assertEqual( - ( - error.message, - error.validator, - error.validator_value, - error.instance, - error.absolute_path, - error.schema, - error.schema_path, - error.json_path, - ), - ( - "'notAnInteger' is not of type 'integer'", - "type", - "integer", - "notAnInteger", - deque(["foo"]), - {"type": "integer"}, - deque(["additionalProperties", "type"]), - "$.foo", - ), - ) - - def test_prefixItems(self): - schema = {"prefixItems": [{"type": "string"}, {}, {}, {"maximum": 3}]} - validator = validators.Draft202012Validator(schema) - type_error, min_error = validator.iter_errors([1, 2, "foo", 5]) - self.assertEqual( - ( - type_error.message, - type_error.validator, - type_error.validator_value, - type_error.instance, - type_error.absolute_path, - type_error.schema, - type_error.schema_path, - type_error.json_path, - ), - ( - "1 is not of type 'string'", - "type", - "string", - 1, - deque([0]), - {"type": "string"}, - deque(["prefixItems", 0, "type"]), - "$[0]", - ), - ) - self.assertEqual( - ( - min_error.message, - min_error.validator, - min_error.validator_value, - min_error.instance, - min_error.absolute_path, - min_error.schema, - min_error.schema_path, - min_error.json_path, - ), - ( - "5 is greater than the maximum of 3", - "maximum", - 3, - 5, - deque([3]), - {"maximum": 3}, - deque(["prefixItems", 3, "maximum"]), - "$[3]", - ), - ) - - def test_prefixItems_with_items(self): - schema = { - "items": {"type": "string"}, - "prefixItems": [{}], - } - validator = validators.Draft202012Validator(schema) - e1, e2 = validator.iter_errors(["foo", 2, "bar", 4, "baz"]) - self.assertEqual( - ( - e1.message, - e1.validator, - e1.validator_value, - e1.instance, - e1.absolute_path, - e1.schema, - e1.schema_path, - e1.json_path, - ), - ( - "2 is not of type 'string'", - "type", - "string", - 2, - deque([1]), - {"type": "string"}, - deque(["items", "type"]), - "$[1]", - ), - ) - self.assertEqual( - ( - e2.message, - e2.validator, - e2.validator_value, - e2.instance, - e2.absolute_path, - e2.schema, - e2.schema_path, - e2.json_path, - ), - ( - "4 is not of type 'string'", - "type", - "string", - 4, - deque([3]), - {"type": "string"}, - deque(["items", "type"]), - "$[3]", - ), - ) - - def test_contains_too_many(self): - """ - `contains` + `maxContains` produces only one error, even if there are - many more incorrectly matching elements. - """ - schema = {"contains": {"type": "string"}, "maxContains": 2} - validator = validators.Draft202012Validator(schema) - error, = validator.iter_errors(["foo", 2, "bar", 4, "baz", "quux"]) - self.assertEqual( - ( - error.message, - error.validator, - error.validator_value, - error.instance, - error.absolute_path, - error.schema, - error.schema_path, - error.json_path, - ), - ( - "Too many items match the given schema (expected at most 2)", - "maxContains", - 2, - ["foo", 2, "bar", 4, "baz", "quux"], - deque([]), - {"contains": {"type": "string"}, "maxContains": 2}, - deque(["contains"]), - "$", - ), - ) - - def test_contains_too_few(self): - schema = {"contains": {"type": "string"}, "minContains": 2} - validator = validators.Draft202012Validator(schema) - error, = validator.iter_errors(["foo", 2, 4]) - self.assertEqual( - ( - error.message, - error.validator, - error.validator_value, - error.instance, - error.absolute_path, - error.schema, - error.schema_path, - error.json_path, - ), - ( - ( - "Too few items match the given schema " - "(expected at least 2 but only 1 matched)" - ), - "minContains", - 2, - ["foo", 2, 4], - deque([]), - {"contains": {"type": "string"}, "minContains": 2}, - deque(["contains"]), - "$", - ), - ) - - def test_contains_none(self): - schema = {"contains": {"type": "string"}, "minContains": 2} - validator = validators.Draft202012Validator(schema) - error, = validator.iter_errors([2, 4]) - self.assertEqual( - ( - error.message, - error.validator, - error.validator_value, - error.instance, - error.absolute_path, - error.schema, - error.schema_path, - error.json_path, - ), - ( - "[2, 4] does not contain items matching the given schema", - "contains", - {"type": "string"}, - [2, 4], - deque([]), - {"contains": {"type": "string"}, "minContains": 2}, - deque(["contains"]), - "$", - ), - ) - - def test_ref_sibling(self): - schema = { - "$defs": {"foo": {"required": ["bar"]}}, - "properties": { - "aprop": { - "$ref": "#/$defs/foo", - "required": ["baz"], - }, - }, - } - - validator = validators.Draft202012Validator(schema) - e1, e2 = validator.iter_errors({"aprop": {}}) - self.assertEqual( - ( - e1.message, - e1.validator, - e1.validator_value, - e1.instance, - e1.absolute_path, - e1.schema, - e1.schema_path, - e1.relative_schema_path, - e1.json_path, - ), - ( - "'bar' is a required property", - "required", - ["bar"], - {}, - deque(["aprop"]), - {"required": ["bar"]}, - deque(["properties", "aprop", "required"]), - deque(["properties", "aprop", "required"]), - "$.aprop", - ), - ) - self.assertEqual( - ( - e2.message, - e2.validator, - e2.validator_value, - e2.instance, - e2.absolute_path, - e2.schema, - e2.schema_path, - e2.relative_schema_path, - e2.json_path, - ), - ( - "'baz' is a required property", - "required", - ["baz"], - {}, - deque(["aprop"]), - {"$ref": "#/$defs/foo", "required": ["baz"]}, - deque(["properties", "aprop", "required"]), - deque(["properties", "aprop", "required"]), - "$.aprop", - ), - ) - - -class MetaSchemaTestsMixin: - # TODO: These all belong upstream - def test_invalid_properties(self): - with self.assertRaises(exceptions.SchemaError): - self.Validator.check_schema({"properties": 12}) - - def test_minItems_invalid_string(self): - with self.assertRaises(exceptions.SchemaError): - # needs to be an integer - self.Validator.check_schema({"minItems": "1"}) - - def test_enum_allows_empty_arrays(self): - """ - Technically, all the spec says is they SHOULD have elements, not MUST. - - (As of Draft 6. Previous drafts do say MUST). - - See #529. - """ - if self.Validator in { - validators.Draft3Validator, - validators.Draft4Validator, - }: - with self.assertRaises(exceptions.SchemaError): - self.Validator.check_schema({"enum": []}) - else: - self.Validator.check_schema({"enum": []}) - - def test_enum_allows_non_unique_items(self): - """ - Technically, all the spec says is they SHOULD be unique, not MUST. - - (As of Draft 6. Previous drafts do say MUST). - - See #529. - """ - if self.Validator in { - validators.Draft3Validator, - validators.Draft4Validator, - }: - with self.assertRaises(exceptions.SchemaError): - self.Validator.check_schema({"enum": [12, 12]}) - else: - self.Validator.check_schema({"enum": [12, 12]}) - - def test_schema_with_invalid_regex(self): - with self.assertRaises(exceptions.SchemaError): - self.Validator.check_schema({"pattern": "*notaregex"}) - - def test_schema_with_invalid_regex_with_disabled_format_validation(self): - self.Validator.check_schema( - {"pattern": "*notaregex"}, - format_checker=None, - ) - - -class ValidatorTestMixin(MetaSchemaTestsMixin): - def test_it_implements_the_validator_protocol(self): - self.assertIsInstance(self.Validator({}), protocols.Validator) - - def test_valid_instances_are_valid(self): - schema, instance = self.valid - self.assertTrue(self.Validator(schema).is_valid(instance)) - - def test_invalid_instances_are_not_valid(self): - schema, instance = self.invalid - self.assertFalse(self.Validator(schema).is_valid(instance)) - - def test_non_existent_properties_are_ignored(self): - self.Validator({object(): object()}).validate(instance=object()) - - def test_evolve(self): - schema, format_checker = {"type": "integer"}, FormatChecker() - original = self.Validator( - schema, - format_checker=format_checker, - ) - new = original.evolve( - schema={"type": "string"}, - format_checker=self.Validator.FORMAT_CHECKER, - ) - - expected = self.Validator( - {"type": "string"}, - format_checker=self.Validator.FORMAT_CHECKER, - _resolver=new._resolver, - ) - - self.assertEqual(new, expected) - self.assertNotEqual(new, original) - - def test_evolve_with_subclass(self): - """ - Subclassing validators isn't supported public API, but some users have - done it, because we don't actually error entirely when it's done :/ - - We need to deprecate doing so first to help as many of these users - ensure they can move to supported APIs, but this test ensures that in - the interim, we haven't broken those users. - """ - - with self.assertWarns(DeprecationWarning): - @define - class OhNo(self.Validator): - foo = field(factory=lambda: [1, 2, 3]) - _bar = field(default=37) - - validator = OhNo({}, bar=12) - self.assertEqual(validator.foo, [1, 2, 3]) - - new = validator.evolve(schema={"type": "integer"}) - self.assertEqual(new.foo, [1, 2, 3]) - self.assertEqual(new._bar, 12) - - def test_is_type_is_true_for_valid_type(self): - self.assertTrue(self.Validator({}).is_type("foo", "string")) - - def test_is_type_is_false_for_invalid_type(self): - self.assertFalse(self.Validator({}).is_type("foo", "array")) - - def test_is_type_evades_bool_inheriting_from_int(self): - self.assertFalse(self.Validator({}).is_type(True, "integer")) - self.assertFalse(self.Validator({}).is_type(True, "number")) - - def test_it_can_validate_with_decimals(self): - schema = {"items": {"type": "number"}} - Validator = validators.extend( - self.Validator, - type_checker=self.Validator.TYPE_CHECKER.redefine( - "number", - lambda checker, thing: isinstance( - thing, (int, float, Decimal), - ) and not isinstance(thing, bool), - ), - ) - - validator = Validator(schema) - validator.validate([1, 1.1, Decimal(1) / Decimal(8)]) - - invalid = ["foo", {}, [], True, None] - self.assertEqual( - [error.instance for error in validator.iter_errors(invalid)], - invalid, - ) - - def test_it_returns_true_for_formats_it_does_not_know_about(self): - validator = self.Validator( - {"format": "carrot"}, format_checker=FormatChecker(), - ) - validator.validate("bugs") - - def test_it_does_not_validate_formats_by_default(self): - validator = self.Validator({}) - self.assertIsNone(validator.format_checker) - - def test_it_validates_formats_if_a_checker_is_provided(self): - checker = FormatChecker() - bad = ValueError("Bad!") - - @checker.checks("foo", raises=ValueError) - def check(value): - if value == "good": - return True - elif value == "bad": - raise bad - else: # pragma: no cover - self.fail(f"What is {value}? [Baby Don't Hurt Me]") - - validator = self.Validator( - {"format": "foo"}, format_checker=checker, - ) - - validator.validate("good") - with self.assertRaises(exceptions.ValidationError) as cm: - validator.validate("bad") - - # Make sure original cause is attached - self.assertIs(cm.exception.cause, bad) - - def test_non_string_custom_type(self): - non_string_type = object() - schema = {"type": [non_string_type]} - Crazy = validators.extend( - self.Validator, - type_checker=self.Validator.TYPE_CHECKER.redefine( - non_string_type, - lambda checker, thing: isinstance(thing, int), - ), - ) - Crazy(schema).validate(15) - - def test_it_properly_formats_tuples_in_errors(self): - """ - A tuple instance properly formats validation errors for uniqueItems. - - See #224 - """ - TupleValidator = validators.extend( - self.Validator, - type_checker=self.Validator.TYPE_CHECKER.redefine( - "array", - lambda checker, thing: isinstance(thing, tuple), - ), - ) - with self.assertRaises(exceptions.ValidationError) as e: - TupleValidator({"uniqueItems": True}).validate((1, 1)) - self.assertIn("(1, 1) has non-unique elements", str(e.exception)) - - def test_check_redefined_sequence(self): - """ - Allow array to validate against another defined sequence type - """ - schema = {"type": "array", "uniqueItems": True} - MyMapping = namedtuple("MyMapping", "a, b") - Validator = validators.extend( - self.Validator, - type_checker=self.Validator.TYPE_CHECKER.redefine_many( - { - "array": lambda checker, thing: isinstance( - thing, (list, deque), - ), - "object": lambda checker, thing: isinstance( - thing, (dict, MyMapping), - ), - }, - ), - ) - validator = Validator(schema) - - valid_instances = [ - deque(["a", None, "1", "", True]), - deque([[False], [0]]), - [deque([False]), deque([0])], - [[deque([False])], [deque([0])]], - [[[[[deque([False])]]]], [[[[deque([0])]]]]], - [deque([deque([False])]), deque([deque([0])])], - [MyMapping("a", 0), MyMapping("a", False)], - [ - MyMapping("a", [deque([0])]), - MyMapping("a", [deque([False])]), - ], - [ - MyMapping("a", [MyMapping("a", deque([0]))]), - MyMapping("a", [MyMapping("a", deque([False]))]), - ], - [deque(deque(deque([False]))), deque(deque(deque([0])))], - ] - - for instance in valid_instances: - validator.validate(instance) - - invalid_instances = [ - deque(["a", "b", "a"]), - deque([[False], [False]]), - [deque([False]), deque([False])], - [[deque([False])], [deque([False])]], - [[[[[deque([False])]]]], [[[[deque([False])]]]]], - [deque([deque([False])]), deque([deque([False])])], - [MyMapping("a", False), MyMapping("a", False)], - [ - MyMapping("a", [deque([False])]), - MyMapping("a", [deque([False])]), - ], - [ - MyMapping("a", [MyMapping("a", deque([False]))]), - MyMapping("a", [MyMapping("a", deque([False]))]), - ], - [deque(deque(deque([False]))), deque(deque(deque([False])))], - ] - - for instance in invalid_instances: - with self.assertRaises(exceptions.ValidationError): - validator.validate(instance) - - def test_it_creates_a_ref_resolver_if_not_provided(self): - with self.assertWarns(DeprecationWarning): - resolver = self.Validator({}).resolver - self.assertIsInstance(resolver, validators._RefResolver) - - def test_it_upconverts_from_deprecated_RefResolvers(self): - ref, schema = "someCoolRef", {"type": "integer"} - resolver = validators._RefResolver("", {}, store={ref: schema}) - validator = self.Validator({"$ref": ref}, resolver=resolver) - - with self.assertRaises(exceptions.ValidationError): - validator.validate(None) - - def test_it_upconverts_from_yet_older_deprecated_legacy_RefResolvers(self): - """ - Legacy RefResolvers support only the context manager form of - resolution. - """ - - class LegacyRefResolver: - @contextmanager - def resolving(this, ref): - self.assertEqual(ref, "the ref") - yield {"type": "integer"} - - resolver = LegacyRefResolver() - schema = {"$ref": "the ref"} - - with self.assertRaises(exceptions.ValidationError): - self.Validator(schema, resolver=resolver).validate(None) - - -class AntiDraft6LeakMixin: - """ - Make sure functionality from draft 6 doesn't leak backwards in time. - """ - - def test_True_is_not_a_schema(self): - with self.assertRaises(exceptions.SchemaError) as e: - self.Validator.check_schema(True) - self.assertIn("True is not of type", str(e.exception)) - - def test_False_is_not_a_schema(self): - with self.assertRaises(exceptions.SchemaError) as e: - self.Validator.check_schema(False) - self.assertIn("False is not of type", str(e.exception)) - - def test_True_is_not_a_schema_even_if_you_forget_to_check(self): - with self.assertRaises(Exception) as e: - self.Validator(True).validate(12) - self.assertNotIsInstance(e.exception, exceptions.ValidationError) - - def test_False_is_not_a_schema_even_if_you_forget_to_check(self): - with self.assertRaises(Exception) as e: - self.Validator(False).validate(12) - self.assertNotIsInstance(e.exception, exceptions.ValidationError) - - -class TestDraft3Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): - Validator = validators.Draft3Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - def test_any_type_is_valid_for_type_any(self): - validator = self.Validator({"type": "any"}) - validator.validate(object()) - - def test_any_type_is_redefinable(self): - """ - Sigh, because why not. - """ - Crazy = validators.extend( - self.Validator, - type_checker=self.Validator.TYPE_CHECKER.redefine( - "any", lambda checker, thing: isinstance(thing, int), - ), - ) - validator = Crazy({"type": "any"}) - validator.validate(12) - with self.assertRaises(exceptions.ValidationError): - validator.validate("foo") - - def test_is_type_is_true_for_any_type(self): - self.assertTrue(self.Validator({"type": "any"}).is_valid(object())) - - def test_is_type_does_not_evade_bool_if_it_is_being_tested(self): - self.assertTrue(self.Validator({}).is_type(True, "boolean")) - self.assertTrue(self.Validator({"type": "any"}).is_valid(True)) - - -class TestDraft4Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): - Validator = validators.Draft4Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - -class TestDraft6Validator(ValidatorTestMixin, TestCase): - Validator = validators.Draft6Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - -class TestDraft7Validator(ValidatorTestMixin, TestCase): - Validator = validators.Draft7Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - -class TestDraft201909Validator(ValidatorTestMixin, TestCase): - Validator = validators.Draft201909Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - -class TestDraft202012Validator(ValidatorTestMixin, TestCase): - Validator = validators.Draft202012Validator - valid: tuple[dict, dict] = ({}, {}) - invalid = {"type": "integer"}, "foo" - - -class TestLatestValidator(TestCase): - """ - These really apply to multiple versions but are easiest to test on one. - """ - - def test_ref_resolvers_may_have_boolean_schemas_stored(self): - ref = "someCoolRef" - schema = {"$ref": ref} - resolver = validators._RefResolver("", {}, store={ref: False}) - validator = validators._LATEST_VERSION(schema, resolver=resolver) - - with self.assertRaises(exceptions.ValidationError): - validator.validate(None) - - -class TestValidatorFor(TestCase): - def test_draft_3(self): - schema = {"$schema": "http://json-schema.org/draft-03/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft3Validator, - ) - - schema = {"$schema": "http://json-schema.org/draft-03/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft3Validator, - ) - - def test_draft_4(self): - schema = {"$schema": "http://json-schema.org/draft-04/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft4Validator, - ) - - schema = {"$schema": "http://json-schema.org/draft-04/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft4Validator, - ) - - def test_draft_6(self): - schema = {"$schema": "http://json-schema.org/draft-06/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft6Validator, - ) - - schema = {"$schema": "http://json-schema.org/draft-06/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft6Validator, - ) - - def test_draft_7(self): - schema = {"$schema": "http://json-schema.org/draft-07/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft7Validator, - ) - - schema = {"$schema": "http://json-schema.org/draft-07/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft7Validator, - ) - - def test_draft_201909(self): - schema = {"$schema": "https://json-schema.org/draft/2019-09/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft201909Validator, - ) - - schema = {"$schema": "https://json-schema.org/draft/2019-09/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft201909Validator, - ) - - def test_draft_202012(self): - schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} - self.assertIs( - validators.validator_for(schema), - validators.Draft202012Validator, - ) - - schema = {"$schema": "https://json-schema.org/draft/2020-12/schema#"} - self.assertIs( - validators.validator_for(schema), - validators.Draft202012Validator, - ) - - def test_True(self): - self.assertIs( - validators.validator_for(True), - validators._LATEST_VERSION, - ) - - def test_False(self): - self.assertIs( - validators.validator_for(False), - validators._LATEST_VERSION, - ) - - def test_custom_validator(self): - Validator = validators.create( - meta_schema={"id": "meta schema id"}, - version="12", - id_of=lambda s: s.get("id", ""), - ) - schema = {"$schema": "meta schema id"} - self.assertIs( - validators.validator_for(schema), - Validator, - ) - - def test_custom_validator_draft6(self): - Validator = validators.create( - meta_schema={"$id": "meta schema $id"}, - version="13", - ) - schema = {"$schema": "meta schema $id"} - self.assertIs( - validators.validator_for(schema), - Validator, - ) - - def test_validator_for_jsonschema_default(self): - self.assertIs(validators.validator_for({}), validators._LATEST_VERSION) - - def test_validator_for_custom_default(self): - self.assertIs(validators.validator_for({}, default=None), None) - - def test_warns_if_meta_schema_specified_was_not_found(self): - with self.assertWarns(DeprecationWarning) as cm: - validators.validator_for(schema={"$schema": "unknownSchema"}) - - self.assertEqual(cm.filename, __file__) - self.assertEqual( - str(cm.warning), - "The metaschema specified by $schema was not found. " - "Using the latest draft to validate, but this will raise " - "an error in the future.", - ) - - def test_does_not_warn_if_meta_schema_is_unspecified(self): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - validators.validator_for(schema={}, default={}) - self.assertFalse(w) - - def test_validator_for_custom_default_with_schema(self): - schema, default = {"$schema": "mailto:foo@example.com"}, object() - self.assertIs(validators.validator_for(schema, default), default) - - -class TestValidate(TestCase): - def assertUses(self, schema, Validator): - result = [] - with mock.patch.object(Validator, "check_schema", result.append): - validators.validate({}, schema) - self.assertEqual(result, [schema]) - - def test_draft3_validator_is_chosen(self): - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-03/schema#"}, - Validator=validators.Draft3Validator, - ) - # Make sure it works without the empty fragment - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-03/schema"}, - Validator=validators.Draft3Validator, - ) - - def test_draft4_validator_is_chosen(self): - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-04/schema#"}, - Validator=validators.Draft4Validator, - ) - # Make sure it works without the empty fragment - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-04/schema"}, - Validator=validators.Draft4Validator, - ) - - def test_draft6_validator_is_chosen(self): - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-06/schema#"}, - Validator=validators.Draft6Validator, - ) - # Make sure it works without the empty fragment - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-06/schema"}, - Validator=validators.Draft6Validator, - ) - - def test_draft7_validator_is_chosen(self): - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-07/schema#"}, - Validator=validators.Draft7Validator, - ) - # Make sure it works without the empty fragment - self.assertUses( - schema={"$schema": "http://json-schema.org/draft-07/schema"}, - Validator=validators.Draft7Validator, - ) - - def test_draft202012_validator_is_chosen(self): - self.assertUses( - schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema#", - }, - Validator=validators.Draft202012Validator, - ) - # Make sure it works without the empty fragment - self.assertUses( - schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - }, - Validator=validators.Draft202012Validator, - ) - - def test_draft202012_validator_is_the_default(self): - self.assertUses(schema={}, Validator=validators.Draft202012Validator) - - def test_validation_error_message(self): - with self.assertRaises(exceptions.ValidationError) as e: - validators.validate(12, {"type": "string"}) - self.assertRegex( - str(e.exception), - "(?s)Failed validating '.*' in schema.*On instance", - ) - - def test_schema_error_message(self): - with self.assertRaises(exceptions.SchemaError) as e: - validators.validate(12, {"type": 12}) - self.assertRegex( - str(e.exception), - "(?s)Failed validating '.*' in metaschema.*On schema", - ) - - def test_it_uses_best_match(self): - schema = { - "oneOf": [ - {"type": "number", "minimum": 20}, - {"type": "array"}, - ], - } - with self.assertRaises(exceptions.ValidationError) as e: - validators.validate(12, schema) - self.assertIn("12 is less than the minimum of 20", str(e.exception)) - - -class TestThreading(TestCase): - """ - Threading-related functionality tests. - - jsonschema doesn't promise thread safety, and its validation behavior - across multiple threads may change at any time, but that means it isn't - safe to share *validators* across threads, not that anytime one has - multiple threads that jsonschema won't work (it certainly is intended to). - - These tests ensure that this minimal level of functionality continues to - work. - """ - - def test_validation_across_a_second_thread(self): - failed = [] - - def validate(): - try: - validators.validate(instance=37, schema=True) - except: # pragma: no cover # noqa: E722 - failed.append(sys.exc_info()) - - validate() # just verify it succeeds - - from threading import Thread - thread = Thread(target=validate) - thread.start() - thread.join() - self.assertEqual((thread.is_alive(), failed), (False, [])) - - -class TestReferencing(TestCase): - def test_registry_with_retrieve(self): - def retrieve(uri): - return DRAFT202012.create_resource({"type": "integer"}) - - registry = referencing.Registry(retrieve=retrieve) - schema = {"$ref": "https://example.com/"} - validator = validators.Draft202012Validator(schema, registry=registry) - - self.assertEqual( - (validator.is_valid(12), validator.is_valid("foo")), - (True, False), - ) - - def test_custom_registries_do_not_autoretrieve_remote_resources(self): - registry = referencing.Registry() - schema = {"$ref": "https://example.com/"} - validator = validators.Draft202012Validator(schema, registry=registry) - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - with self.assertRaises(referencing.exceptions.Unresolvable): - validator.validate(12) - self.assertFalse(w) - - -class TestRefResolver(TestCase): - - base_uri = "" - stored_uri = "foo://stored" - stored_schema = {"stored": "schema"} - - def setUp(self): - self.referrer = {} - self.store = {self.stored_uri: self.stored_schema} - self.resolver = validators._RefResolver( - self.base_uri, self.referrer, self.store, - ) - - def test_it_does_not_retrieve_schema_urls_from_the_network(self): - ref = validators.Draft3Validator.META_SCHEMA["id"] - with mock.patch.object(self.resolver, "resolve_remote") as patched: # noqa: SIM117 - with self.resolver.resolving(ref) as resolved: - pass - self.assertEqual(resolved, validators.Draft3Validator.META_SCHEMA) - self.assertFalse(patched.called) - - def test_it_resolves_local_refs(self): - ref = "#/properties/foo" - self.referrer["properties"] = {"foo": object()} - with self.resolver.resolving(ref) as resolved: - self.assertEqual(resolved, self.referrer["properties"]["foo"]) - - def test_it_resolves_local_refs_with_id(self): - schema = {"id": "http://bar/schema#", "a": {"foo": "bar"}} - resolver = validators._RefResolver.from_schema( - schema, - id_of=lambda schema: schema.get("id", ""), - ) - with resolver.resolving("#/a") as resolved: - self.assertEqual(resolved, schema["a"]) - with resolver.resolving("http://bar/schema#/a") as resolved: - self.assertEqual(resolved, schema["a"]) - - def test_it_retrieves_stored_refs(self): - with self.resolver.resolving(self.stored_uri) as resolved: - self.assertIs(resolved, self.stored_schema) - - self.resolver.store["cached_ref"] = {"foo": 12} - with self.resolver.resolving("cached_ref#/foo") as resolved: - self.assertEqual(resolved, 12) - - def test_it_retrieves_unstored_refs_via_requests(self): - ref = "http://bar#baz" - schema = {"baz": 12} - - if "requests" in sys.modules: # pragma: no cover - self.addCleanup( - sys.modules.__setitem__, "requests", sys.modules["requests"], - ) - sys.modules["requests"] = ReallyFakeRequests({"http://bar": schema}) - - with self.resolver.resolving(ref) as resolved: - self.assertEqual(resolved, 12) - - def test_it_retrieves_unstored_refs_via_urlopen(self): - ref = "http://bar#baz" - schema = {"baz": 12} - - if "requests" in sys.modules: # pragma: no cover - self.addCleanup( - sys.modules.__setitem__, "requests", sys.modules["requests"], - ) - sys.modules["requests"] = None - - @contextmanager - def fake_urlopen(url): - self.assertEqual(url, "http://bar") - yield BytesIO(json.dumps(schema).encode("utf8")) - - self.addCleanup(setattr, validators, "urlopen", validators.urlopen) - validators.urlopen = fake_urlopen - - with self.resolver.resolving(ref) as resolved: - pass - self.assertEqual(resolved, 12) - - def test_it_retrieves_local_refs_via_urlopen(self): - with tempfile.NamedTemporaryFile(delete=False, mode="wt") as tempf: - self.addCleanup(os.remove, tempf.name) - json.dump({"foo": "bar"}, tempf) - - ref = f"file://{pathname2url(tempf.name)}#foo" - with self.resolver.resolving(ref) as resolved: - self.assertEqual(resolved, "bar") - - def test_it_can_construct_a_base_uri_from_a_schema(self): - schema = {"id": "foo"} - resolver = validators._RefResolver.from_schema( - schema, - id_of=lambda schema: schema.get("id", ""), - ) - self.assertEqual(resolver.base_uri, "foo") - self.assertEqual(resolver.resolution_scope, "foo") - with resolver.resolving("") as resolved: - self.assertEqual(resolved, schema) - with resolver.resolving("#") as resolved: - self.assertEqual(resolved, schema) - with resolver.resolving("foo") as resolved: - self.assertEqual(resolved, schema) - with resolver.resolving("foo#") as resolved: - self.assertEqual(resolved, schema) - - def test_it_can_construct_a_base_uri_from_a_schema_without_id(self): - schema = {} - resolver = validators._RefResolver.from_schema(schema) - self.assertEqual(resolver.base_uri, "") - self.assertEqual(resolver.resolution_scope, "") - with resolver.resolving("") as resolved: - self.assertEqual(resolved, schema) - with resolver.resolving("#") as resolved: - self.assertEqual(resolved, schema) - - def test_custom_uri_scheme_handlers(self): - def handler(url): - self.assertEqual(url, ref) - return schema - - schema = {"foo": "bar"} - ref = "foo://bar" - resolver = validators._RefResolver("", {}, handlers={"foo": handler}) - with resolver.resolving(ref) as resolved: - self.assertEqual(resolved, schema) - - def test_cache_remote_on(self): - response = [object()] - - def handler(url): - try: - return response.pop() - except IndexError: # pragma: no cover - self.fail("Response must not have been cached!") - - ref = "foo://bar" - resolver = validators._RefResolver( - "", {}, cache_remote=True, handlers={"foo": handler}, - ) - with resolver.resolving(ref): - pass - with resolver.resolving(ref): - pass - - def test_cache_remote_off(self): - response = [object()] - - def handler(url): - try: - return response.pop() - except IndexError: # pragma: no cover - self.fail("Handler called twice!") - - ref = "foo://bar" - resolver = validators._RefResolver( - "", {}, cache_remote=False, handlers={"foo": handler}, - ) - with resolver.resolving(ref): - pass - - def test_if_you_give_it_junk_you_get_a_resolution_error(self): - error = ValueError("Oh no! What's this?") - - def handler(url): - raise error - - ref = "foo://bar" - resolver = validators._RefResolver("", {}, handlers={"foo": handler}) - with self.assertRaises(exceptions._RefResolutionError) as err: # noqa: SIM117 - with resolver.resolving(ref): - self.fail("Shouldn't get this far!") # pragma: no cover - self.assertEqual(err.exception, exceptions._RefResolutionError(error)) - - def test_helpful_error_message_on_failed_pop_scope(self): - resolver = validators._RefResolver("", {}) - resolver.pop_scope() - with self.assertRaises(exceptions._RefResolutionError) as exc: - resolver.pop_scope() - self.assertIn("Failed to pop the scope", str(exc.exception)) - - def test_pointer_within_schema_with_different_id(self): - """ - See #1085. - """ - schema = validators.Draft7Validator.META_SCHEMA - one = validators._RefResolver("", schema) - validator = validators.Draft7Validator(schema, resolver=one) - self.assertFalse(validator.is_valid({"maxLength": "foo"})) - - another = { - "allOf": [{"$ref": validators.Draft7Validator.META_SCHEMA["$id"]}], - } - two = validators._RefResolver("", another) - validator = validators.Draft7Validator(another, resolver=two) - self.assertFalse(validator.is_valid({"maxLength": "foo"})) - - def test_newly_created_validator_with_ref_resolver(self): - """ - See https://github.com/python-jsonschema/jsonschema/issues/1061#issuecomment-1624266555. - """ - - def handle(uri): - self.assertEqual(uri, "http://example.com/foo") - return {"type": "integer"} - - resolver = validators._RefResolver("", {}, handlers={"http": handle}) - Validator = validators.create( - meta_schema={}, - validators=validators.Draft4Validator.VALIDATORS, - ) - schema = {"$id": "http://example.com/bar", "$ref": "foo"} - validator = Validator(schema, resolver=resolver) - self.assertEqual( - (validator.is_valid({}), validator.is_valid(37)), - (False, True), - ) - - def test_refresolver_with_pointer_in_schema_with_no_id(self): - """ - See https://github.com/python-jsonschema/jsonschema/issues/1124#issuecomment-1632574249. - """ - - schema = { - "properties": {"x": {"$ref": "#/definitions/x"}}, - "definitions": {"x": {"type": "integer"}}, - } - - validator = validators.Draft202012Validator( - schema, - resolver=validators._RefResolver("", schema), - ) - self.assertEqual( - (validator.is_valid({"x": "y"}), validator.is_valid({"x": 37})), - (False, True), - ) - - - -def sorted_errors(errors): - def key(error): - return ( - [str(e) for e in error.path], - [str(e) for e in error.schema_path], - ) - return sorted(errors, key=key) - - -@define -class ReallyFakeRequests: - - _responses: dict[str, Any] - - def get(self, url): - response = self._responses.get(url) - if url is None: # pragma: no cover - raise ValueError("Unknown URL: " + repr(url)) - return _ReallyFakeJSONResponse(json.dumps(response)) - - -@define -class _ReallyFakeJSONResponse: - - _response: str - - def json(self): - return json.loads(self._response) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema/validators.py b/extensions/.local/lib/python3.11/site-packages/jsonschema/validators.py deleted file mode 100644 index 85c3916..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema/validators.py +++ /dev/null @@ -1,1410 +0,0 @@ -""" -Creation and extension of validators, with implementations for existing drafts. -""" -from __future__ import annotations - -from collections import deque -from collections.abc import Iterable, Mapping, Sequence -from functools import lru_cache -from operator import methodcaller -from typing import TYPE_CHECKING -from urllib.parse import unquote, urldefrag, urljoin, urlsplit -from urllib.request import urlopen -from warnings import warn -import contextlib -import json -import reprlib -import warnings - -from attrs import define, field, fields -from jsonschema_specifications import REGISTRY as SPECIFICATIONS -from rpds import HashTrieMap -import referencing.exceptions -import referencing.jsonschema - -from jsonschema import ( - _format, - _keywords, - _legacy_keywords, - _types, - _typing, - _utils, - exceptions, -) - -if TYPE_CHECKING: - from jsonschema.protocols import Validator - -_UNSET = _utils.Unset() - -_VALIDATORS: dict[str, Validator] = {} -_META_SCHEMAS = _utils.URIDict() - - -def __getattr__(name): - if name == "ErrorTree": - warnings.warn( - "Importing ErrorTree from jsonschema.validators is deprecated. " - "Instead import it from jsonschema.exceptions.", - DeprecationWarning, - stacklevel=2, - ) - from jsonschema.exceptions import ErrorTree - return ErrorTree - elif name == "validators": - warnings.warn( - "Accessing jsonschema.validators.validators is deprecated. " - "Use jsonschema.validators.validator_for with a given schema.", - DeprecationWarning, - stacklevel=2, - ) - return _VALIDATORS - elif name == "meta_schemas": - warnings.warn( - "Accessing jsonschema.validators.meta_schemas is deprecated. " - "Use jsonschema.validators.validator_for with a given schema.", - DeprecationWarning, - stacklevel=2, - ) - return _META_SCHEMAS - elif name == "RefResolver": - warnings.warn( - _RefResolver._DEPRECATION_MESSAGE, - DeprecationWarning, - stacklevel=2, - ) - return _RefResolver - raise AttributeError(f"module {__name__} has no attribute {name}") - - -def validates(version): - """ - Register the decorated validator for a ``version`` of the specification. - - Registered validators and their meta schemas will be considered when - parsing :kw:`$schema` keywords' URIs. - - Arguments: - - version (str): - - An identifier to use as the version's name - - Returns: - - collections.abc.Callable: - - a class decorator to decorate the validator with the version - - """ - - def _validates(cls): - _VALIDATORS[version] = cls - meta_schema_id = cls.ID_OF(cls.META_SCHEMA) - _META_SCHEMAS[meta_schema_id] = cls - return cls - return _validates - - -def _warn_for_remote_retrieve(uri: str): - from urllib.request import Request, urlopen - headers = {"User-Agent": "python-jsonschema (deprecated $ref resolution)"} - request = Request(uri, headers=headers) # noqa: S310 - with urlopen(request) as response: # noqa: S310 - warnings.warn( - "Automatically retrieving remote references can be a security " - "vulnerability and is discouraged by the JSON Schema " - "specifications. Relying on this behavior is deprecated " - "and will shortly become an error. If you are sure you want to " - "remotely retrieve your reference and that it is safe to do so, " - "you can find instructions for doing so via referencing.Registry " - "in the referencing documentation " - "(https://referencing.readthedocs.org).", - DeprecationWarning, - stacklevel=9, # Ha ha ha ha magic numbers :/ - ) - return referencing.Resource.from_contents( - json.load(response), - default_specification=referencing.jsonschema.DRAFT202012, - ) - - -_REMOTE_WARNING_REGISTRY = SPECIFICATIONS.combine( - referencing.Registry(retrieve=_warn_for_remote_retrieve), # type: ignore[call-arg] -) - - -def create( - meta_schema: referencing.jsonschema.ObjectSchema, - validators: ( - Mapping[str, _typing.SchemaKeywordValidator] - | Iterable[tuple[str, _typing.SchemaKeywordValidator]] - ) = (), - version: str | None = None, - type_checker: _types.TypeChecker = _types.draft202012_type_checker, - format_checker: _format.FormatChecker = _format.draft202012_format_checker, - id_of: _typing.id_of = referencing.jsonschema.DRAFT202012.id_of, - applicable_validators: _typing.ApplicableValidators = methodcaller( - "items", - ), -): - """ - Create a new validator class. - - Arguments: - - meta_schema: - - the meta schema for the new validator class - - validators: - - a mapping from names to callables, where each callable will - validate the schema property with the given name. - - Each callable should take 4 arguments: - - 1. a validator instance, - 2. the value of the property being validated within the - instance - 3. the instance - 4. the schema - - version: - - an identifier for the version that this validator class will - validate. If provided, the returned validator class will - have its ``__name__`` set to include the version, and also - will have `jsonschema.validators.validates` automatically - called for the given version. - - type_checker: - - a type checker, used when applying the :kw:`type` keyword. - - If unprovided, a `jsonschema.TypeChecker` will be created - with a set of default types typical of JSON Schema drafts. - - format_checker: - - a format checker, used when applying the :kw:`format` keyword. - - If unprovided, a `jsonschema.FormatChecker` will be created - with a set of default formats typical of JSON Schema drafts. - - id_of: - - A function that given a schema, returns its ID. - - applicable_validators: - - A function that, given a schema, returns the list of - applicable schema keywords and associated values - which will be used to validate the instance. - This is mostly used to support pre-draft 7 versions of JSON Schema - which specified behavior around ignoring keywords if they were - siblings of a ``$ref`` keyword. If you're not attempting to - implement similar behavior, you can typically ignore this argument - and leave it at its default. - - Returns: - - a new `jsonschema.protocols.Validator` class - - """ - # preemptively don't shadow the `Validator.format_checker` local - format_checker_arg = format_checker - - specification = referencing.jsonschema.specification_with( - dialect_id=id_of(meta_schema) or "urn:unknown-dialect", - default=referencing.Specification.OPAQUE, - ) - - @define - class Validator: - - VALIDATORS = dict(validators) # noqa: RUF012 - META_SCHEMA = dict(meta_schema) # noqa: RUF012 - TYPE_CHECKER = type_checker - FORMAT_CHECKER = format_checker_arg - ID_OF = staticmethod(id_of) - - _APPLICABLE_VALIDATORS = applicable_validators - _validators = field(init=False, repr=False, eq=False) - - schema: referencing.jsonschema.Schema = field(repr=reprlib.repr) - _ref_resolver = field(default=None, repr=False, alias="resolver") - format_checker: _format.FormatChecker | None = field(default=None) - # TODO: include new meta-schemas added at runtime - _registry: referencing.jsonschema.SchemaRegistry = field( - default=_REMOTE_WARNING_REGISTRY, - kw_only=True, - repr=False, - ) - _resolver = field( - alias="_resolver", - default=None, - kw_only=True, - repr=False, - ) - - def __init_subclass__(cls): - warnings.warn( - ( - "Subclassing validator classes is not intended to " - "be part of their public API. A future version " - "will make doing so an error, as the behavior of " - "subclasses isn't guaranteed to stay the same " - "between releases of jsonschema. Instead, prefer " - "composition of validators, wrapping them in an object " - "owned entirely by the downstream library." - ), - DeprecationWarning, - stacklevel=2, - ) - - def evolve(self, **changes): - cls = self.__class__ - schema = changes.setdefault("schema", self.schema) - NewValidator = validator_for(schema, default=cls) - - for field in fields(cls): # noqa: F402 - if not field.init: - continue - attr_name = field.name - init_name = field.alias - if init_name not in changes: - changes[init_name] = getattr(self, attr_name) - - return NewValidator(**changes) - - cls.evolve = evolve - - def __attrs_post_init__(self): - if self._resolver is None: - registry = self._registry - if registry is not _REMOTE_WARNING_REGISTRY: - registry = SPECIFICATIONS.combine(registry) - resource = specification.create_resource(self.schema) - self._resolver = registry.resolver_with_root(resource) - - if self.schema is True or self.schema is False: - self._validators = [] - else: - self._validators = [ - (self.VALIDATORS[k], k, v) - for k, v in applicable_validators(self.schema) - if k in self.VALIDATORS - ] - - # REMOVEME: Legacy ref resolution state management. - push_scope = getattr(self._ref_resolver, "push_scope", None) - if push_scope is not None: - id = id_of(self.schema) - if id is not None: - push_scope(id) - - @classmethod - def check_schema(cls, schema, format_checker=_UNSET): - Validator = validator_for(cls.META_SCHEMA, default=cls) - if format_checker is _UNSET: - format_checker = Validator.FORMAT_CHECKER - validator = Validator( - schema=cls.META_SCHEMA, - format_checker=format_checker, - ) - for error in validator.iter_errors(schema): - raise exceptions.SchemaError.create_from(error) - - @property - def resolver(self): - warnings.warn( - ( - f"Accessing {self.__class__.__name__}.resolver is " - "deprecated as of v4.18.0, in favor of the " - "https://github.com/python-jsonschema/referencing " - "library, which provides more compliant referencing " - "behavior as well as more flexible APIs for " - "customization." - ), - DeprecationWarning, - stacklevel=2, - ) - if self._ref_resolver is None: - self._ref_resolver = _RefResolver.from_schema( - self.schema, - id_of=id_of, - ) - return self._ref_resolver - - def evolve(self, **changes): - schema = changes.setdefault("schema", self.schema) - NewValidator = validator_for(schema, default=self.__class__) - - for (attr_name, init_name) in evolve_fields: - if init_name not in changes: - changes[init_name] = getattr(self, attr_name) - - return NewValidator(**changes) - - def iter_errors(self, instance, _schema=None): - if _schema is not None: - warnings.warn( - ( - "Passing a schema to Validator.iter_errors " - "is deprecated and will be removed in a future " - "release. Call validator.evolve(schema=new_schema)." - "iter_errors(...) instead." - ), - DeprecationWarning, - stacklevel=2, - ) - validators = [ - (self.VALIDATORS[k], k, v) - for k, v in applicable_validators(_schema) - if k in self.VALIDATORS - ] - else: - _schema, validators = self.schema, self._validators - - if _schema is True: - return - elif _schema is False: - yield exceptions.ValidationError( - f"False schema does not allow {instance!r}", - validator=None, - validator_value=None, - instance=instance, - schema=_schema, - ) - return - - for validator, k, v in validators: - errors = validator(self, v, instance, _schema) or () - for error in errors: - # set details if not already set by the called fn - error._set( - validator=k, - validator_value=v, - instance=instance, - schema=_schema, - type_checker=self.TYPE_CHECKER, - ) - if k not in {"if", "$ref"}: - error.schema_path.appendleft(k) - yield error - - def descend( - self, - instance, - schema, - path=None, - schema_path=None, - resolver=None, - ): - if schema is True: - return - elif schema is False: - yield exceptions.ValidationError( - f"False schema does not allow {instance!r}", - validator=None, - validator_value=None, - instance=instance, - schema=schema, - ) - return - - if self._ref_resolver is not None: - evolved = self.evolve(schema=schema) - else: - if resolver is None: - resolver = self._resolver.in_subresource( - specification.create_resource(schema), - ) - evolved = self.evolve(schema=schema, _resolver=resolver) - - for k, v in applicable_validators(schema): - validator = evolved.VALIDATORS.get(k) - if validator is None: - continue - - errors = validator(evolved, v, instance, schema) or () - for error in errors: - # set details if not already set by the called fn - error._set( - validator=k, - validator_value=v, - instance=instance, - schema=schema, - type_checker=evolved.TYPE_CHECKER, - ) - if k not in {"if", "$ref"}: - error.schema_path.appendleft(k) - if path is not None: - error.path.appendleft(path) - if schema_path is not None: - error.schema_path.appendleft(schema_path) - yield error - - def validate(self, *args, **kwargs): - for error in self.iter_errors(*args, **kwargs): - raise error - - def is_type(self, instance, type): - try: - return self.TYPE_CHECKER.is_type(instance, type) - except exceptions.UndefinedTypeCheck: - exc = exceptions.UnknownType(type, instance, self.schema) - raise exc from None - - def _validate_reference(self, ref, instance): - if self._ref_resolver is None: - try: - resolved = self._resolver.lookup(ref) - except referencing.exceptions.Unresolvable as err: - raise exceptions._WrappedReferencingError(err) from err - - return self.descend( - instance, - resolved.contents, - resolver=resolved.resolver, - ) - else: - resolve = getattr(self._ref_resolver, "resolve", None) - if resolve is None: - with self._ref_resolver.resolving(ref) as resolved: - return self.descend(instance, resolved) - else: - scope, resolved = resolve(ref) - self._ref_resolver.push_scope(scope) - - try: - return list(self.descend(instance, resolved)) - finally: - self._ref_resolver.pop_scope() - - def is_valid(self, instance, _schema=None): - if _schema is not None: - warnings.warn( - ( - "Passing a schema to Validator.is_valid is deprecated " - "and will be removed in a future release. Call " - "validator.evolve(schema=new_schema).is_valid(...) " - "instead." - ), - DeprecationWarning, - stacklevel=2, - ) - self = self.evolve(schema=_schema) - - error = next(self.iter_errors(instance), None) - return error is None - - evolve_fields = [ - (field.name, field.alias) - for field in fields(Validator) - if field.init - ] - - if version is not None: - safe = version.title().replace(" ", "").replace("-", "") - Validator.__name__ = Validator.__qualname__ = f"{safe}Validator" - Validator = validates(version)(Validator) # type: ignore[misc] - - return Validator - - -def extend( - validator, - validators=(), - version=None, - type_checker=None, - format_checker=None, -): - """ - Create a new validator class by extending an existing one. - - Arguments: - - validator (jsonschema.protocols.Validator): - - an existing validator class - - validators (collections.abc.Mapping): - - a mapping of new validator callables to extend with, whose - structure is as in `create`. - - .. note:: - - Any validator callables with the same name as an - existing one will (silently) replace the old validator - callable entirely, effectively overriding any validation - done in the "parent" validator class. - - If you wish to instead extend the behavior of a parent's - validator callable, delegate and call it directly in - the new validator function by retrieving it using - ``OldValidator.VALIDATORS["validation_keyword_name"]``. - - version (str): - - a version for the new validator class - - type_checker (jsonschema.TypeChecker): - - a type checker, used when applying the :kw:`type` keyword. - - If unprovided, the type checker of the extended - `jsonschema.protocols.Validator` will be carried along. - - format_checker (jsonschema.FormatChecker): - - a format checker, used when applying the :kw:`format` keyword. - - If unprovided, the format checker of the extended - `jsonschema.protocols.Validator` will be carried along. - - Returns: - - a new `jsonschema.protocols.Validator` class extending the one - provided - - .. note:: Meta Schemas - - The new validator class will have its parent's meta schema. - - If you wish to change or extend the meta schema in the new - validator class, modify ``META_SCHEMA`` directly on the returned - class. Note that no implicit copying is done, so a copy should - likely be made before modifying it, in order to not affect the - old validator. - - """ - all_validators = dict(validator.VALIDATORS) - all_validators.update(validators) - - if type_checker is None: - type_checker = validator.TYPE_CHECKER - if format_checker is None: - format_checker = validator.FORMAT_CHECKER - return create( - meta_schema=validator.META_SCHEMA, - validators=all_validators, - version=version, - type_checker=type_checker, - format_checker=format_checker, - id_of=validator.ID_OF, - applicable_validators=validator._APPLICABLE_VALIDATORS, - ) - - -Draft3Validator = create( - meta_schema=SPECIFICATIONS.contents( - "http://json-schema.org/draft-03/schema#", - ), - validators={ - "$ref": _keywords.ref, - "additionalItems": _legacy_keywords.additionalItems, - "additionalProperties": _keywords.additionalProperties, - "dependencies": _legacy_keywords.dependencies_draft3, - "disallow": _legacy_keywords.disallow_draft3, - "divisibleBy": _keywords.multipleOf, - "enum": _keywords.enum, - "extends": _legacy_keywords.extends_draft3, - "format": _keywords.format, - "items": _legacy_keywords.items_draft3_draft4, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maximum": _legacy_keywords.maximum_draft3_draft4, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minimum": _legacy_keywords.minimum_draft3_draft4, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "properties": _legacy_keywords.properties_draft3, - "type": _legacy_keywords.type_draft3, - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft3_type_checker, - format_checker=_format.draft3_format_checker, - version="draft3", - id_of=referencing.jsonschema.DRAFT3.id_of, - applicable_validators=_legacy_keywords.ignore_ref_siblings, -) - -Draft4Validator = create( - meta_schema=SPECIFICATIONS.contents( - "http://json-schema.org/draft-04/schema#", - ), - validators={ - "$ref": _keywords.ref, - "additionalItems": _legacy_keywords.additionalItems, - "additionalProperties": _keywords.additionalProperties, - "allOf": _keywords.allOf, - "anyOf": _keywords.anyOf, - "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, - "enum": _keywords.enum, - "format": _keywords.format, - "items": _legacy_keywords.items_draft3_draft4, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maxProperties": _keywords.maxProperties, - "maximum": _legacy_keywords.maximum_draft3_draft4, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minProperties": _keywords.minProperties, - "minimum": _legacy_keywords.minimum_draft3_draft4, - "multipleOf": _keywords.multipleOf, - "not": _keywords.not_, - "oneOf": _keywords.oneOf, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "properties": _keywords.properties, - "required": _keywords.required, - "type": _keywords.type, - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft4_type_checker, - format_checker=_format.draft4_format_checker, - version="draft4", - id_of=referencing.jsonschema.DRAFT4.id_of, - applicable_validators=_legacy_keywords.ignore_ref_siblings, -) - -Draft6Validator = create( - meta_schema=SPECIFICATIONS.contents( - "http://json-schema.org/draft-06/schema#", - ), - validators={ - "$ref": _keywords.ref, - "additionalItems": _legacy_keywords.additionalItems, - "additionalProperties": _keywords.additionalProperties, - "allOf": _keywords.allOf, - "anyOf": _keywords.anyOf, - "const": _keywords.const, - "contains": _legacy_keywords.contains_draft6_draft7, - "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, - "enum": _keywords.enum, - "exclusiveMaximum": _keywords.exclusiveMaximum, - "exclusiveMinimum": _keywords.exclusiveMinimum, - "format": _keywords.format, - "items": _legacy_keywords.items_draft6_draft7_draft201909, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maxProperties": _keywords.maxProperties, - "maximum": _keywords.maximum, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minProperties": _keywords.minProperties, - "minimum": _keywords.minimum, - "multipleOf": _keywords.multipleOf, - "not": _keywords.not_, - "oneOf": _keywords.oneOf, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "properties": _keywords.properties, - "propertyNames": _keywords.propertyNames, - "required": _keywords.required, - "type": _keywords.type, - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft6_type_checker, - format_checker=_format.draft6_format_checker, - version="draft6", - id_of=referencing.jsonschema.DRAFT6.id_of, - applicable_validators=_legacy_keywords.ignore_ref_siblings, -) - -Draft7Validator = create( - meta_schema=SPECIFICATIONS.contents( - "http://json-schema.org/draft-07/schema#", - ), - validators={ - "$ref": _keywords.ref, - "additionalItems": _legacy_keywords.additionalItems, - "additionalProperties": _keywords.additionalProperties, - "allOf": _keywords.allOf, - "anyOf": _keywords.anyOf, - "const": _keywords.const, - "contains": _legacy_keywords.contains_draft6_draft7, - "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, - "enum": _keywords.enum, - "exclusiveMaximum": _keywords.exclusiveMaximum, - "exclusiveMinimum": _keywords.exclusiveMinimum, - "format": _keywords.format, - "if": _keywords.if_, - "items": _legacy_keywords.items_draft6_draft7_draft201909, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maxProperties": _keywords.maxProperties, - "maximum": _keywords.maximum, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minProperties": _keywords.minProperties, - "minimum": _keywords.minimum, - "multipleOf": _keywords.multipleOf, - "not": _keywords.not_, - "oneOf": _keywords.oneOf, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "properties": _keywords.properties, - "propertyNames": _keywords.propertyNames, - "required": _keywords.required, - "type": _keywords.type, - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft7_type_checker, - format_checker=_format.draft7_format_checker, - version="draft7", - id_of=referencing.jsonschema.DRAFT7.id_of, - applicable_validators=_legacy_keywords.ignore_ref_siblings, -) - -Draft201909Validator = create( - meta_schema=SPECIFICATIONS.contents( - "https://json-schema.org/draft/2019-09/schema", - ), - validators={ - "$recursiveRef": _legacy_keywords.recursiveRef, - "$ref": _keywords.ref, - "additionalItems": _legacy_keywords.additionalItems, - "additionalProperties": _keywords.additionalProperties, - "allOf": _keywords.allOf, - "anyOf": _keywords.anyOf, - "const": _keywords.const, - "contains": _keywords.contains, - "dependentRequired": _keywords.dependentRequired, - "dependentSchemas": _keywords.dependentSchemas, - "enum": _keywords.enum, - "exclusiveMaximum": _keywords.exclusiveMaximum, - "exclusiveMinimum": _keywords.exclusiveMinimum, - "format": _keywords.format, - "if": _keywords.if_, - "items": _legacy_keywords.items_draft6_draft7_draft201909, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maxProperties": _keywords.maxProperties, - "maximum": _keywords.maximum, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minProperties": _keywords.minProperties, - "minimum": _keywords.minimum, - "multipleOf": _keywords.multipleOf, - "not": _keywords.not_, - "oneOf": _keywords.oneOf, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "properties": _keywords.properties, - "propertyNames": _keywords.propertyNames, - "required": _keywords.required, - "type": _keywords.type, - "unevaluatedItems": _legacy_keywords.unevaluatedItems_draft2019, - "unevaluatedProperties": ( - _legacy_keywords.unevaluatedProperties_draft2019 - ), - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft201909_type_checker, - format_checker=_format.draft201909_format_checker, - version="draft2019-09", -) - -Draft202012Validator = create( - meta_schema=SPECIFICATIONS.contents( - "https://json-schema.org/draft/2020-12/schema", - ), - validators={ - "$dynamicRef": _keywords.dynamicRef, - "$ref": _keywords.ref, - "additionalProperties": _keywords.additionalProperties, - "allOf": _keywords.allOf, - "anyOf": _keywords.anyOf, - "const": _keywords.const, - "contains": _keywords.contains, - "dependentRequired": _keywords.dependentRequired, - "dependentSchemas": _keywords.dependentSchemas, - "enum": _keywords.enum, - "exclusiveMaximum": _keywords.exclusiveMaximum, - "exclusiveMinimum": _keywords.exclusiveMinimum, - "format": _keywords.format, - "if": _keywords.if_, - "items": _keywords.items, - "maxItems": _keywords.maxItems, - "maxLength": _keywords.maxLength, - "maxProperties": _keywords.maxProperties, - "maximum": _keywords.maximum, - "minItems": _keywords.minItems, - "minLength": _keywords.minLength, - "minProperties": _keywords.minProperties, - "minimum": _keywords.minimum, - "multipleOf": _keywords.multipleOf, - "not": _keywords.not_, - "oneOf": _keywords.oneOf, - "pattern": _keywords.pattern, - "patternProperties": _keywords.patternProperties, - "prefixItems": _keywords.prefixItems, - "properties": _keywords.properties, - "propertyNames": _keywords.propertyNames, - "required": _keywords.required, - "type": _keywords.type, - "unevaluatedItems": _keywords.unevaluatedItems, - "unevaluatedProperties": _keywords.unevaluatedProperties, - "uniqueItems": _keywords.uniqueItems, - }, - type_checker=_types.draft202012_type_checker, - format_checker=_format.draft202012_format_checker, - version="draft2020-12", -) - -_LATEST_VERSION = Draft202012Validator - - -class _RefResolver: - """ - Resolve JSON References. - - Arguments: - - base_uri (str): - - The URI of the referring document - - referrer: - - The actual referring document - - store (dict): - - A mapping from URIs to documents to cache - - cache_remote (bool): - - Whether remote refs should be cached after first resolution - - handlers (dict): - - A mapping from URI schemes to functions that should be used - to retrieve them - - urljoin_cache (:func:`functools.lru_cache`): - - A cache that will be used for caching the results of joining - the resolution scope to subscopes. - - remote_cache (:func:`functools.lru_cache`): - - A cache that will be used for caching the results of - resolved remote URLs. - - Attributes: - - cache_remote (bool): - - Whether remote refs should be cached after first resolution - - .. deprecated:: v4.18.0 - - ``RefResolver`` has been deprecated in favor of `referencing`. - - """ - - _DEPRECATION_MESSAGE = ( - "jsonschema.RefResolver is deprecated as of v4.18.0, in favor of the " - "https://github.com/python-jsonschema/referencing library, which " - "provides more compliant referencing behavior as well as more " - "flexible APIs for customization. A future release will remove " - "RefResolver. Please file a feature request (on referencing) if you " - "are missing an API for the kind of customization you need." - ) - - def __init__( - self, - base_uri, - referrer, - store=HashTrieMap(), - cache_remote=True, - handlers=(), - urljoin_cache=None, - remote_cache=None, - ): - if urljoin_cache is None: - urljoin_cache = lru_cache(1024)(urljoin) - if remote_cache is None: - remote_cache = lru_cache(1024)(self.resolve_from_url) - - self.referrer = referrer - self.cache_remote = cache_remote - self.handlers = dict(handlers) - - self._scopes_stack = [base_uri] - - self.store = _utils.URIDict( - (uri, each.contents) for uri, each in SPECIFICATIONS.items() - ) - self.store.update( - (id, each.META_SCHEMA) for id, each in _META_SCHEMAS.items() - ) - self.store.update(store) - self.store.update( - (schema["$id"], schema) - for schema in store.values() - if isinstance(schema, Mapping) and "$id" in schema - ) - self.store[base_uri] = referrer - - self._urljoin_cache = urljoin_cache - self._remote_cache = remote_cache - - @classmethod - def from_schema( # noqa: D417 - cls, - schema, - id_of=referencing.jsonschema.DRAFT202012.id_of, - *args, - **kwargs, - ): - """ - Construct a resolver from a JSON schema object. - - Arguments: - - schema: - - the referring schema - - Returns: - - `_RefResolver` - - """ - return cls(base_uri=id_of(schema) or "", referrer=schema, *args, **kwargs) # noqa: B026, E501 - - def push_scope(self, scope): - """ - Enter a given sub-scope. - - Treats further dereferences as being performed underneath the - given scope. - """ - self._scopes_stack.append( - self._urljoin_cache(self.resolution_scope, scope), - ) - - def pop_scope(self): - """ - Exit the most recent entered scope. - - Treats further dereferences as being performed underneath the - original scope. - - Don't call this method more times than `push_scope` has been - called. - """ - try: - self._scopes_stack.pop() - except IndexError: - raise exceptions._RefResolutionError( - "Failed to pop the scope from an empty stack. " - "`pop_scope()` should only be called once for every " - "`push_scope()`", - ) from None - - @property - def resolution_scope(self): - """ - Retrieve the current resolution scope. - """ - return self._scopes_stack[-1] - - @property - def base_uri(self): - """ - Retrieve the current base URI, not including any fragment. - """ - uri, _ = urldefrag(self.resolution_scope) - return uri - - @contextlib.contextmanager - def in_scope(self, scope): - """ - Temporarily enter the given scope for the duration of the context. - - .. deprecated:: v4.0.0 - """ - warnings.warn( - "jsonschema.RefResolver.in_scope is deprecated and will be " - "removed in a future release.", - DeprecationWarning, - stacklevel=3, - ) - self.push_scope(scope) - try: - yield - finally: - self.pop_scope() - - @contextlib.contextmanager - def resolving(self, ref): - """ - Resolve the given ``ref`` and enter its resolution scope. - - Exits the scope on exit of this context manager. - - Arguments: - - ref (str): - - The reference to resolve - - """ - url, resolved = self.resolve(ref) - self.push_scope(url) - try: - yield resolved - finally: - self.pop_scope() - - def _find_in_referrer(self, key): - return self._get_subschemas_cache()[key] - - @lru_cache # noqa: B019 - def _get_subschemas_cache(self): - cache = {key: [] for key in _SUBSCHEMAS_KEYWORDS} - for keyword, subschema in _search_schema( - self.referrer, _match_subschema_keywords, - ): - cache[keyword].append(subschema) - return cache - - @lru_cache # noqa: B019 - def _find_in_subschemas(self, url): - subschemas = self._get_subschemas_cache()["$id"] - if not subschemas: - return None - uri, fragment = urldefrag(url) - for subschema in subschemas: - id = subschema["$id"] - if not isinstance(id, str): - continue - target_uri = self._urljoin_cache(self.resolution_scope, id) - if target_uri.rstrip("/") == uri.rstrip("/"): - if fragment: - subschema = self.resolve_fragment(subschema, fragment) - self.store[url] = subschema - return url, subschema - return None - - def resolve(self, ref): - """ - Resolve the given reference. - """ - url = self._urljoin_cache(self.resolution_scope, ref).rstrip("/") - - match = self._find_in_subschemas(url) - if match is not None: - return match - - return url, self._remote_cache(url) - - def resolve_from_url(self, url): - """ - Resolve the given URL. - """ - url, fragment = urldefrag(url) - if not url: - url = self.base_uri - - try: - document = self.store[url] - except KeyError: - try: - document = self.resolve_remote(url) - except Exception as exc: - raise exceptions._RefResolutionError(exc) from exc - - return self.resolve_fragment(document, fragment) - - def resolve_fragment(self, document, fragment): - """ - Resolve a ``fragment`` within the referenced ``document``. - - Arguments: - - document: - - The referent document - - fragment (str): - - a URI fragment to resolve within it - - """ - fragment = fragment.lstrip("/") - - if not fragment: - return document - - if document is self.referrer: - find = self._find_in_referrer - else: - - def find(key): - yield from _search_schema(document, _match_keyword(key)) - - for keyword in ["$anchor", "$dynamicAnchor"]: - for subschema in find(keyword): - if fragment == subschema[keyword]: - return subschema - for keyword in ["id", "$id"]: - for subschema in find(keyword): - if "#" + fragment == subschema[keyword]: - return subschema - - # Resolve via path - parts = unquote(fragment).split("/") if fragment else [] - for part in parts: - part = part.replace("~1", "/").replace("~0", "~") - - if isinstance(document, Sequence): - try: # noqa: SIM105 - part = int(part) - except ValueError: - pass - try: - document = document[part] - except (TypeError, LookupError) as err: - raise exceptions._RefResolutionError( - f"Unresolvable JSON pointer: {fragment!r}", - ) from err - - return document - - def resolve_remote(self, uri): - """ - Resolve a remote ``uri``. - - If called directly, does not check the store first, but after - retrieving the document at the specified URI it will be saved in - the store if :attr:`cache_remote` is True. - - .. note:: - - If the requests_ library is present, ``jsonschema`` will use it to - request the remote ``uri``, so that the correct encoding is - detected and used. - - If it isn't, or if the scheme of the ``uri`` is not ``http`` or - ``https``, UTF-8 is assumed. - - Arguments: - - uri (str): - - The URI to resolve - - Returns: - - The retrieved document - - .. _requests: https://pypi.org/project/requests/ - - """ - try: - import requests - except ImportError: - requests = None - - scheme = urlsplit(uri).scheme - - if scheme in self.handlers: - result = self.handlers[scheme](uri) - elif scheme in ["http", "https"] and requests: - # Requests has support for detecting the correct encoding of - # json over http - result = requests.get(uri).json() - else: - # Otherwise, pass off to urllib and assume utf-8 - with urlopen(uri) as url: # noqa: S310 - result = json.loads(url.read().decode("utf-8")) - - if self.cache_remote: - self.store[uri] = result - return result - - -_SUBSCHEMAS_KEYWORDS = ("$id", "id", "$anchor", "$dynamicAnchor") - - -def _match_keyword(keyword): - - def matcher(value): - if keyword in value: - yield value - - return matcher - - -def _match_subschema_keywords(value): - for keyword in _SUBSCHEMAS_KEYWORDS: - if keyword in value: - yield keyword, value - - -def _search_schema(schema, matcher): - """Breadth-first search routine.""" - values = deque([schema]) - while values: - value = values.pop() - if not isinstance(value, dict): - continue - yield from matcher(value) - values.extendleft(value.values()) - - -def validate(instance, schema, cls=None, *args, **kwargs): # noqa: D417 - """ - Validate an instance under the given schema. - - >>> validate([2, 3, 4], {"maxItems": 2}) - Traceback (most recent call last): - ... - ValidationError: [2, 3, 4] is too long - - :func:`~jsonschema.validators.validate` will first verify that the - provided schema is itself valid, since not doing so can lead to less - obvious error messages and fail in less obvious or consistent ways. - - If you know you have a valid schema already, especially - if you intend to validate multiple instances with - the same schema, you likely would prefer using the - `jsonschema.protocols.Validator.validate` method directly on a - specific validator (e.g. ``Draft202012Validator.validate``). - - - Arguments: - - instance: - - The instance to validate - - schema: - - The schema to validate with - - cls (jsonschema.protocols.Validator): - - The class that will be used to validate the instance. - - If the ``cls`` argument is not provided, two things will happen - in accordance with the specification. First, if the schema has a - :kw:`$schema` keyword containing a known meta-schema [#]_ then the - proper validator will be used. The specification recommends that - all schemas contain :kw:`$schema` properties for this reason. If no - :kw:`$schema` property is found, the default validator class is the - latest released draft. - - Any other provided positional and keyword arguments will be passed - on when instantiating the ``cls``. - - Raises: - - `jsonschema.exceptions.ValidationError`: - - if the instance is invalid - - `jsonschema.exceptions.SchemaError`: - - if the schema itself is invalid - - .. rubric:: Footnotes - .. [#] known by a validator registered with - `jsonschema.validators.validates` - - """ - if cls is None: - cls = validator_for(schema) - - cls.check_schema(schema) - validator = cls(schema, *args, **kwargs) - error = exceptions.best_match(validator.iter_errors(instance)) - if error is not None: - raise error - - -def validator_for( - schema, - default: Validator | _utils.Unset = _UNSET, -) -> type[Validator]: - """ - Retrieve the validator class appropriate for validating the given schema. - - Uses the :kw:`$schema` keyword that should be present in the given - schema to look up the appropriate validator class. - - Arguments: - - schema (collections.abc.Mapping or bool): - - the schema to look at - - default: - - the default to return if the appropriate validator class - cannot be determined. - - If unprovided, the default is to return the latest supported - draft. - - Examples: - - The :kw:`$schema` JSON Schema keyword will control which validator - class is returned: - - >>> schema = { - ... "$schema": "https://json-schema.org/draft/2020-12/schema", - ... "type": "integer", - ... } - >>> jsonschema.validators.validator_for(schema) - - - - Here, a draft 7 schema instead will return the draft 7 validator: - - >>> schema = { - ... "$schema": "http://json-schema.org/draft-07/schema#", - ... "type": "integer", - ... } - >>> jsonschema.validators.validator_for(schema) - - - - Schemas with no ``$schema`` keyword will fallback to the default - argument: - - >>> schema = {"type": "integer"} - >>> jsonschema.validators.validator_for( - ... schema, default=Draft7Validator, - ... ) - - - or if none is provided, to the latest version supported. - Always including the keyword when authoring schemas is highly - recommended. - - """ - DefaultValidator = _LATEST_VERSION if default is _UNSET else default - - if schema is True or schema is False or "$schema" not in schema: - return DefaultValidator - if schema["$schema"] not in _META_SCHEMAS and default is _UNSET: - warn( - ( - "The metaschema specified by $schema was not found. " - "Using the latest draft to validate, but this will raise " - "an error in the future." - ), - DeprecationWarning, - stacklevel=2, - ) - return _META_SCHEMAS.get(schema["$schema"], DefaultValidator) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/METADATA deleted file mode 100644 index b4ced65..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/METADATA +++ /dev/null @@ -1,55 +0,0 @@ -Metadata-Version: 2.3 -Name: jsonschema-specifications -Version: 2024.10.1 -Summary: The JSON Schema meta-schemas and vocabularies, exposed as a Registry -Project-URL: Documentation, https://jsonschema-specifications.readthedocs.io/ -Project-URL: Homepage, https://github.com/python-jsonschema/jsonschema-specifications -Project-URL: Issues, https://github.com/python-jsonschema/jsonschema-specifications/issues/ -Project-URL: Funding, https://github.com/sponsors/Julian -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema-specifications?utm_source=pypi-jsonschema-specifications&utm_medium=referral&utm_campaign=pypi-link -Project-URL: Source, https://github.com/python-jsonschema/jsonschema-specifications -Author-email: Julian Berman -License-File: COPYING -Keywords: data validation,json,json schema,jsonschema,validation -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: File Formats :: JSON -Classifier: Topic :: File Formats :: JSON :: JSON Schema -Requires-Python: >=3.9 -Requires-Dist: referencing>=0.31.0 -Description-Content-Type: text/x-rst - -============================= -``jsonschema-specifications`` -============================= - -|PyPI| |Pythons| |CI| |ReadTheDocs| - -JSON support files from the `JSON Schema Specifications `_ (metaschemas, vocabularies, etc.), packaged for runtime access from Python as a `referencing-based Schema Registry `_. - -.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema-specifications.svg - :alt: PyPI version - :target: https://pypi.org/project/jsonschema-specifications/ - -.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema-specifications.svg - :alt: Supported Python versions - :target: https://pypi.org/project/jsonschema-specifications/ - -.. |CI| image:: https://github.com/python-jsonschema/jsonschema-specifications/workflows/CI/badge.svg - :alt: Build status - :target: https://github.com/python-jsonschema/jsonschema-specifications/actions?query=workflow%3ACI - -.. |ReadTheDocs| image:: https://readthedocs.org/projects/jsonschema-specifications/badge/?version=stable&style=flat - :alt: ReadTheDocs status - :target: https://jsonschema-specifications.readthedocs.io/en/stable/ diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/RECORD deleted file mode 100644 index 7d84d3c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/RECORD +++ /dev/null @@ -1,28 +0,0 @@ -jsonschema_specifications/__init__.py,sha256=qoTB2DKY7qvNrGhMPH6gtmAJRLilmVQ-fFZwT6ryqw0,386 -jsonschema_specifications/_core.py,sha256=tFhc1CMleJ3AJOK_bjxOpFQTdrsUClFGfFxPBU_CebM,1140 -jsonschema_specifications/schemas/draft201909/metaschema.json,sha256=e3YbPhIfCgyh6ioLjizIVrz4AWBLgmjXG6yqICvAwTs,1785 -jsonschema_specifications/schemas/draft201909/vocabularies/applicator,sha256=aJUQDplyb7sQcFhRK77D7P1LJOj9L6zuPlBe5ysNTDE,1860 -jsonschema_specifications/schemas/draft201909/vocabularies/content,sha256=m31PVaTi_bAsQwBo_f-rxzKt3OI42j8d8mkCScM1MnQ,517 -jsonschema_specifications/schemas/draft201909/vocabularies/core,sha256=taLElX9kldClCB8ECevooU5BOayyA_x0hHH47eKvWyw,1531 -jsonschema_specifications/schemas/draft201909/vocabularies/meta-data,sha256=1H4kRd1qgicaKY2DzGxsuNSuHhXg3Fa-zTehY-zwEoY,892 -jsonschema_specifications/schemas/draft201909/vocabularies/validation,sha256=HlJsHTNac0gF_ILPV5jBK5YK19olF8Zs2lobCTWcPBw,2834 -jsonschema_specifications/schemas/draft202012/metaschema.json,sha256=Qdp29a-3zgYtJI92JGOpL3ykfk4PkFsiS6av7vkd7Q8,2452 -jsonschema_specifications/schemas/draft202012/vocabularies/applicator,sha256=xKbkFHuR_vf-ptwFjLG_k0AvdBS3ZXiosWqvHa1qrO8,1659 -jsonschema_specifications/schemas/draft202012/vocabularies/content,sha256=CDQ3R3ZOSlgUJieTz01lIFenkThjxZUNQyl-jh_axbY,519 -jsonschema_specifications/schemas/draft202012/vocabularies/core,sha256=wtEqjk3RHTNt_IOj9mOqTGnwtJs76wlP_rJbUxb0gD0,1564 -jsonschema_specifications/schemas/draft202012/vocabularies/format,sha256=UOu_55BhGoSbjMQAoJwdDg-2q1wNQ6DyIgH9NiUFa_Q,403 -jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation,sha256=q8d1rf79idIjWBcNm_k_Tr0jSVY7u-3WDwK-98gSvMA,448 -jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion,sha256=xSJCuaG7eGsmw-gset1CjDH5yW5XXc6Z5W6l_qptogw,445 -jsonschema_specifications/schemas/draft202012/vocabularies/meta-data,sha256=j3bW4U9Bubku-TO3CM3FFEyLUmhlGtEZGEhfsXVPHHY,892 -jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated,sha256=Lb-8tzmUtnCwl2SSre4f_7RsIWgnhNL1pMpWH54tDLQ,506 -jsonschema_specifications/schemas/draft202012/vocabularies/validation,sha256=cBCjHlQfMtK-ch4t40jfdcmzaHaj7TBId_wKvaHTelg,2834 -jsonschema_specifications/schemas/draft3/metaschema.json,sha256=LPdfZENvtb43Si6qJ6uLfh_WUcm0ba6mxnsC_WTiRYs,2600 -jsonschema_specifications/schemas/draft4/metaschema.json,sha256=4UidC0dV8CeTMCWR0_y48Htok6gqlPJIlfjk7fEbguI,4357 -jsonschema_specifications/schemas/draft6/metaschema.json,sha256=wp386fVINcOgbAOzxdXsDtp3cGVo-cTffPvHVmpRAG0,4437 -jsonschema_specifications/schemas/draft7/metaschema.json,sha256=PVOSCIJhYGxVm2A_OFMpyfGrRbXWZ-uZBodFOwVdQF4,4819 -jsonschema_specifications/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -jsonschema_specifications/tests/test_jsonschema_specifications.py,sha256=WkbYRW6A6FoZ0rivShfqVLSCsAiHJ2x8TxqECJTXPTY,1106 -jsonschema_specifications-2024.10.1.dist-info/METADATA,sha256=-jCfClPka5D4aDTtJ683zNiEcSHXhPBLuk9r9XWwyHI,2985 -jsonschema_specifications-2024.10.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87 -jsonschema_specifications-2024.10.1.dist-info/licenses/COPYING,sha256=QtzWNJX4e063x3V6-jebtVpT-Ur9el9lfZrfVyNuUVw,1057 -jsonschema_specifications-2024.10.1.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/WHEEL deleted file mode 100644 index cdd68a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.25.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/licenses/COPYING b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/licenses/COPYING deleted file mode 100644 index a9f853e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications-2024.10.1.dist-info/licenses/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2022 Julian Berman - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/__init__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/__init__.py deleted file mode 100644 index a423574..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -The JSON Schema meta-schemas and vocabularies, exposed as a Registry. -""" - -from referencing.jsonschema import EMPTY_REGISTRY as _EMPTY_REGISTRY - -from jsonschema_specifications._core import _schemas - -#: A `referencing.jsonschema.SchemaRegistry` containing all of the official -#: meta-schemas and vocabularies. -REGISTRY = (_schemas() @ _EMPTY_REGISTRY).crawl() -__all__ = ["REGISTRY"] diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/_core.py b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/_core.py deleted file mode 100644 index e67bd71..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/_core.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Load all the JSON Schema specification's official schemas. -""" - -import json - -try: - from importlib.resources import files -except ImportError: - from importlib_resources import ( # type: ignore[import-not-found, no-redef] - files, - ) - -from referencing import Resource - - -def _schemas(): - """ - All schemas we ship. - """ - # importlib.resources.abc.Traversal doesn't have nice ways to do this that - # I'm aware of... - # - # It can't recurse arbitrarily, e.g. no ``.glob()``. - # - # So this takes some liberties given the real layout of what we ship - # (only 2 levels of nesting, no directories within the second level). - - for version in files(__package__).joinpath("schemas").iterdir(): - if version.name.startswith("."): - continue - for child in version.iterdir(): - children = [child] if child.is_file() else child.iterdir() - for path in children: - if path.name.startswith("."): - continue - contents = json.loads(path.read_text(encoding="utf-8")) - yield Resource.from_contents(contents) diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/metaschema.json deleted file mode 100644 index 2248a0c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/metaschema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/schema", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/core": true, - "https://json-schema.org/draft/2019-09/vocab/applicator": true, - "https://json-schema.org/draft/2019-09/vocab/validation": true, - "https://json-schema.org/draft/2019-09/vocab/meta-data": true, - "https://json-schema.org/draft/2019-09/vocab/format": false, - "https://json-schema.org/draft/2019-09/vocab/content": true - }, - "$recursiveAnchor": true, - - "title": "Core and Validation specifications meta-schema", - "allOf": [ - {"$ref": "meta/core"}, - {"$ref": "meta/applicator"}, - {"$ref": "meta/validation"}, - {"$ref": "meta/meta-data"}, - {"$ref": "meta/format"}, - {"$ref": "meta/content"} - ], - "type": ["object", "boolean"], - "properties": { - "definitions": { - "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", - "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, - "default": {} - }, - "dependencies": { - "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"", - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$recursiveRef": "#" }, - { "$ref": "meta/validation#/$defs/stringArray" } - ] - } - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/applicator b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/applicator deleted file mode 100644 index 24a1cc4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/applicator +++ /dev/null @@ -1,56 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/applicator", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/applicator": true - }, - "$recursiveAnchor": true, - - "title": "Applicator vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "additionalItems": { "$recursiveRef": "#" }, - "unevaluatedItems": { "$recursiveRef": "#" }, - "items": { - "anyOf": [ - { "$recursiveRef": "#" }, - { "$ref": "#/$defs/schemaArray" } - ] - }, - "contains": { "$recursiveRef": "#" }, - "additionalProperties": { "$recursiveRef": "#" }, - "unevaluatedProperties": { "$recursiveRef": "#" }, - "properties": { - "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, - "propertyNames": { "format": "regex" }, - "default": {} - }, - "dependentSchemas": { - "type": "object", - "additionalProperties": { - "$recursiveRef": "#" - } - }, - "propertyNames": { "$recursiveRef": "#" }, - "if": { "$recursiveRef": "#" }, - "then": { "$recursiveRef": "#" }, - "else": { "$recursiveRef": "#" }, - "allOf": { "$ref": "#/$defs/schemaArray" }, - "anyOf": { "$ref": "#/$defs/schemaArray" }, - "oneOf": { "$ref": "#/$defs/schemaArray" }, - "not": { "$recursiveRef": "#" } - }, - "$defs": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$recursiveRef": "#" } - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/content b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/content deleted file mode 100644 index f6752a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/content +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/content", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/content": true - }, - "$recursiveAnchor": true, - - "title": "Content vocabulary meta-schema", - - "type": ["object", "boolean"], - "properties": { - "contentMediaType": { "type": "string" }, - "contentEncoding": { "type": "string" }, - "contentSchema": { "$recursiveRef": "#" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/core b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/core deleted file mode 100644 index eb708a5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/core +++ /dev/null @@ -1,57 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/core", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/core": true - }, - "$recursiveAnchor": true, - - "title": "Core vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "$id": { - "type": "string", - "format": "uri-reference", - "$comment": "Non-empty fragments not allowed.", - "pattern": "^[^#]*#?$" - }, - "$schema": { - "type": "string", - "format": "uri" - }, - "$anchor": { - "type": "string", - "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" - }, - "$ref": { - "type": "string", - "format": "uri-reference" - }, - "$recursiveRef": { - "type": "string", - "format": "uri-reference" - }, - "$recursiveAnchor": { - "type": "boolean", - "default": false - }, - "$vocabulary": { - "type": "object", - "propertyNames": { - "type": "string", - "format": "uri" - }, - "additionalProperties": { - "type": "boolean" - } - }, - "$comment": { - "type": "string" - }, - "$defs": { - "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, - "default": {} - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data deleted file mode 100644 index da04cff..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/meta-data", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/meta-data": true - }, - "$recursiveAnchor": true, - - "title": "Meta-data vocabulary meta-schema", - - "type": ["object", "boolean"], - "properties": { - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": true, - "deprecated": { - "type": "boolean", - "default": false - }, - "readOnly": { - "type": "boolean", - "default": false - }, - "writeOnly": { - "type": "boolean", - "default": false - }, - "examples": { - "type": "array", - "items": true - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/validation b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/validation deleted file mode 100644 index 9f59677..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/validation +++ /dev/null @@ -1,98 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/validation", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/validation": true - }, - "$recursiveAnchor": true, - - "title": "Validation vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "multipleOf": { - "type": "number", - "exclusiveMinimum": 0 - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "number" - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "number" - }, - "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, - "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, - "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, - "minContains": { - "$ref": "#/$defs/nonNegativeInteger", - "default": 1 - }, - "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, - "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "required": { "$ref": "#/$defs/stringArray" }, - "dependentRequired": { - "type": "object", - "additionalProperties": { - "$ref": "#/$defs/stringArray" - } - }, - "const": true, - "enum": { - "type": "array", - "items": true - }, - "type": { - "anyOf": [ - { "$ref": "#/$defs/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/$defs/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - } - }, - "$defs": { - "nonNegativeInteger": { - "type": "integer", - "minimum": 0 - }, - "nonNegativeIntegerDefault0": { - "$ref": "#/$defs/nonNegativeInteger", - "default": 0 - }, - "simpleTypes": { - "enum": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true, - "default": [] - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/metaschema.json deleted file mode 100644 index d5e2d31..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/metaschema.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/schema", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/core": true, - "https://json-schema.org/draft/2020-12/vocab/applicator": true, - "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, - "https://json-schema.org/draft/2020-12/vocab/validation": true, - "https://json-schema.org/draft/2020-12/vocab/meta-data": true, - "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, - "https://json-schema.org/draft/2020-12/vocab/content": true - }, - "$dynamicAnchor": "meta", - - "title": "Core and Validation specifications meta-schema", - "allOf": [ - {"$ref": "meta/core"}, - {"$ref": "meta/applicator"}, - {"$ref": "meta/unevaluated"}, - {"$ref": "meta/validation"}, - {"$ref": "meta/meta-data"}, - {"$ref": "meta/format-annotation"}, - {"$ref": "meta/content"} - ], - "type": ["object", "boolean"], - "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", - "properties": { - "definitions": { - "$comment": "\"definitions\" has been replaced by \"$defs\".", - "type": "object", - "additionalProperties": { "$dynamicRef": "#meta" }, - "deprecated": true, - "default": {} - }, - "dependencies": { - "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$dynamicRef": "#meta" }, - { "$ref": "meta/validation#/$defs/stringArray" } - ] - }, - "deprecated": true, - "default": {} - }, - "$recursiveAnchor": { - "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", - "$ref": "meta/core#/$defs/anchorString", - "deprecated": true - }, - "$recursiveRef": { - "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", - "$ref": "meta/core#/$defs/uriReferenceString", - "deprecated": true - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/applicator b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/applicator deleted file mode 100644 index ca69923..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/applicator +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/applicator", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/applicator": true - }, - "$dynamicAnchor": "meta", - - "title": "Applicator vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "prefixItems": { "$ref": "#/$defs/schemaArray" }, - "items": { "$dynamicRef": "#meta" }, - "contains": { "$dynamicRef": "#meta" }, - "additionalProperties": { "$dynamicRef": "#meta" }, - "properties": { - "type": "object", - "additionalProperties": { "$dynamicRef": "#meta" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$dynamicRef": "#meta" }, - "propertyNames": { "format": "regex" }, - "default": {} - }, - "dependentSchemas": { - "type": "object", - "additionalProperties": { "$dynamicRef": "#meta" }, - "default": {} - }, - "propertyNames": { "$dynamicRef": "#meta" }, - "if": { "$dynamicRef": "#meta" }, - "then": { "$dynamicRef": "#meta" }, - "else": { "$dynamicRef": "#meta" }, - "allOf": { "$ref": "#/$defs/schemaArray" }, - "anyOf": { "$ref": "#/$defs/schemaArray" }, - "oneOf": { "$ref": "#/$defs/schemaArray" }, - "not": { "$dynamicRef": "#meta" } - }, - "$defs": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$dynamicRef": "#meta" } - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/content b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/content deleted file mode 100644 index 2f6e056..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/content +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/content", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/content": true - }, - "$dynamicAnchor": "meta", - - "title": "Content vocabulary meta-schema", - - "type": ["object", "boolean"], - "properties": { - "contentEncoding": { "type": "string" }, - "contentMediaType": { "type": "string" }, - "contentSchema": { "$dynamicRef": "#meta" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/core b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/core deleted file mode 100644 index dfc092d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/core +++ /dev/null @@ -1,51 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/core", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/core": true - }, - "$dynamicAnchor": "meta", - - "title": "Core vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "$id": { - "$ref": "#/$defs/uriReferenceString", - "$comment": "Non-empty fragments not allowed.", - "pattern": "^[^#]*#?$" - }, - "$schema": { "$ref": "#/$defs/uriString" }, - "$ref": { "$ref": "#/$defs/uriReferenceString" }, - "$anchor": { "$ref": "#/$defs/anchorString" }, - "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, - "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, - "$vocabulary": { - "type": "object", - "propertyNames": { "$ref": "#/$defs/uriString" }, - "additionalProperties": { - "type": "boolean" - } - }, - "$comment": { - "type": "string" - }, - "$defs": { - "type": "object", - "additionalProperties": { "$dynamicRef": "#meta" } - } - }, - "$defs": { - "anchorString": { - "type": "string", - "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" - }, - "uriString": { - "type": "string", - "format": "uri" - }, - "uriReferenceString": { - "type": "string", - "format": "uri-reference" - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format deleted file mode 100644 index 09bbfdd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://json-schema.org/draft/2019-09/meta/format", - "$vocabulary": { - "https://json-schema.org/draft/2019-09/vocab/format": true - }, - "$recursiveAnchor": true, - - "title": "Format vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "format": { "type": "string" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation deleted file mode 100644 index 51ef7ea..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/format-annotation": true - }, - "$dynamicAnchor": "meta", - - "title": "Format vocabulary meta-schema for annotation results", - "type": ["object", "boolean"], - "properties": { - "format": { "type": "string" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion deleted file mode 100644 index 5e73fd7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/format-assertion", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/format-assertion": true - }, - "$dynamicAnchor": "meta", - - "title": "Format vocabulary meta-schema for assertion results", - "type": ["object", "boolean"], - "properties": { - "format": { "type": "string" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data deleted file mode 100644 index 05cbc22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/meta-data": true - }, - "$dynamicAnchor": "meta", - - "title": "Meta-data vocabulary meta-schema", - - "type": ["object", "boolean"], - "properties": { - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": true, - "deprecated": { - "type": "boolean", - "default": false - }, - "readOnly": { - "type": "boolean", - "default": false - }, - "writeOnly": { - "type": "boolean", - "default": false - }, - "examples": { - "type": "array", - "items": true - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated deleted file mode 100644 index 5f62a3f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/unevaluated": true - }, - "$dynamicAnchor": "meta", - - "title": "Unevaluated applicator vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "unevaluatedItems": { "$dynamicRef": "#meta" }, - "unevaluatedProperties": { "$dynamicRef": "#meta" } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/validation b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/validation deleted file mode 100644 index 606b87b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/validation +++ /dev/null @@ -1,98 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://json-schema.org/draft/2020-12/meta/validation", - "$vocabulary": { - "https://json-schema.org/draft/2020-12/vocab/validation": true - }, - "$dynamicAnchor": "meta", - - "title": "Validation vocabulary meta-schema", - "type": ["object", "boolean"], - "properties": { - "type": { - "anyOf": [ - { "$ref": "#/$defs/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/$defs/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "const": true, - "enum": { - "type": "array", - "items": true - }, - "multipleOf": { - "type": "number", - "exclusiveMinimum": 0 - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "number" - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "number" - }, - "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, - "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, - "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, - "minContains": { - "$ref": "#/$defs/nonNegativeInteger", - "default": 1 - }, - "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, - "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, - "required": { "$ref": "#/$defs/stringArray" }, - "dependentRequired": { - "type": "object", - "additionalProperties": { - "$ref": "#/$defs/stringArray" - } - } - }, - "$defs": { - "nonNegativeInteger": { - "type": "integer", - "minimum": 0 - }, - "nonNegativeIntegerDefault0": { - "$ref": "#/$defs/nonNegativeInteger", - "default": 0 - }, - "simpleTypes": { - "enum": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true, - "default": [] - } - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft3/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft3/metaschema.json deleted file mode 100644 index 8b26b1f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft3/metaschema.json +++ /dev/null @@ -1,172 +0,0 @@ -{ - "$schema" : "http://json-schema.org/draft-03/schema#", - "id" : "http://json-schema.org/draft-03/schema#", - "type" : "object", - - "properties" : { - "type" : { - "type" : ["string", "array"], - "items" : { - "type" : ["string", {"$ref" : "#"}] - }, - "uniqueItems" : true, - "default" : "any" - }, - - "properties" : { - "type" : "object", - "additionalProperties" : {"$ref" : "#"}, - "default" : {} - }, - - "patternProperties" : { - "type" : "object", - "additionalProperties" : {"$ref" : "#"}, - "default" : {} - }, - - "additionalProperties" : { - "type" : [{"$ref" : "#"}, "boolean"], - "default" : {} - }, - - "items" : { - "type" : [{"$ref" : "#"}, "array"], - "items" : {"$ref" : "#"}, - "default" : {} - }, - - "additionalItems" : { - "type" : [{"$ref" : "#"}, "boolean"], - "default" : {} - }, - - "required" : { - "type" : "boolean", - "default" : false - }, - - "dependencies" : { - "type" : "object", - "additionalProperties" : { - "type" : ["string", "array", {"$ref" : "#"}], - "items" : { - "type" : "string" - } - }, - "default" : {} - }, - - "minimum" : { - "type" : "number" - }, - - "maximum" : { - "type" : "number" - }, - - "exclusiveMinimum" : { - "type" : "boolean", - "default" : false - }, - - "exclusiveMaximum" : { - "type" : "boolean", - "default" : false - }, - - "minItems" : { - "type" : "integer", - "minimum" : 0, - "default" : 0 - }, - - "maxItems" : { - "type" : "integer", - "minimum" : 0 - }, - - "uniqueItems" : { - "type" : "boolean", - "default" : false - }, - - "pattern" : { - "type" : "string", - "format" : "regex" - }, - - "minLength" : { - "type" : "integer", - "minimum" : 0, - "default" : 0 - }, - - "maxLength" : { - "type" : "integer" - }, - - "enum" : { - "type" : "array", - "minItems" : 1, - "uniqueItems" : true - }, - - "default" : { - "type" : "any" - }, - - "title" : { - "type" : "string" - }, - - "description" : { - "type" : "string" - }, - - "format" : { - "type" : "string" - }, - - "divisibleBy" : { - "type" : "number", - "minimum" : 0, - "exclusiveMinimum" : true, - "default" : 1 - }, - - "disallow" : { - "type" : ["string", "array"], - "items" : { - "type" : ["string", {"$ref" : "#"}] - }, - "uniqueItems" : true - }, - - "extends" : { - "type" : [{"$ref" : "#"}, "array"], - "items" : {"$ref" : "#"}, - "default" : {} - }, - - "id" : { - "type" : "string" - }, - - "$ref" : { - "type" : "string" - }, - - "$schema" : { - "type" : "string", - "format" : "uri" - } - }, - - "dependencies" : { - "exclusiveMinimum" : "minimum", - "exclusiveMaximum" : "maximum" - }, - - "default" : {} -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft4/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft4/metaschema.json deleted file mode 100644 index bcbb847..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft4/metaschema.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "id": "http://json-schema.org/draft-04/schema#", - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Core schema meta-schema", - "definitions": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#" } - }, - "positiveInteger": { - "type": "integer", - "minimum": 0 - }, - "positiveIntegerDefault0": { - "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] - }, - "simpleTypes": { - "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "minItems": 1, - "uniqueItems": true - } - }, - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "$schema": { - "type": "string" - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": {}, - "multipleOf": { - "type": "number", - "minimum": 0, - "exclusiveMinimum": true - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "boolean", - "default": false - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "boolean", - "default": false - }, - "maxLength": { "$ref": "#/definitions/positiveInteger" }, - "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "additionalItems": { - "anyOf": [ - { "type": "boolean" }, - { "$ref": "#" } - ], - "default": {} - }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/schemaArray" } - ], - "default": {} - }, - "maxItems": { "$ref": "#/definitions/positiveInteger" }, - "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxProperties": { "$ref": "#/definitions/positiveInteger" }, - "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "required": { "$ref": "#/definitions/stringArray" }, - "additionalProperties": { - "anyOf": [ - { "type": "boolean" }, - { "$ref": "#" } - ], - "default": {} - }, - "definitions": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "properties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "dependencies": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/stringArray" } - ] - } - }, - "enum": { - "type": "array", - "minItems": 1, - "uniqueItems": true - }, - "type": { - "anyOf": [ - { "$ref": "#/definitions/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/definitions/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "format": { "type": "string" }, - "allOf": { "$ref": "#/definitions/schemaArray" }, - "anyOf": { "$ref": "#/definitions/schemaArray" }, - "oneOf": { "$ref": "#/definitions/schemaArray" }, - "not": { "$ref": "#" } - }, - "dependencies": { - "exclusiveMaximum": [ "maximum" ], - "exclusiveMinimum": [ "minimum" ] - }, - "default": {} -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft6/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft6/metaschema.json deleted file mode 100644 index a0d2bf7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft6/metaschema.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-06/schema#", - "$id": "http://json-schema.org/draft-06/schema#", - "title": "Core schema meta-schema", - "definitions": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#" } - }, - "nonNegativeInteger": { - "type": "integer", - "minimum": 0 - }, - "nonNegativeIntegerDefault0": { - "allOf": [ - { "$ref": "#/definitions/nonNegativeInteger" }, - { "default": 0 } - ] - }, - "simpleTypes": { - "enum": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true, - "default": [] - } - }, - "type": ["object", "boolean"], - "properties": { - "$id": { - "type": "string", - "format": "uri-reference" - }, - "$schema": { - "type": "string", - "format": "uri" - }, - "$ref": { - "type": "string", - "format": "uri-reference" - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": {}, - "examples": { - "type": "array", - "items": {} - }, - "multipleOf": { - "type": "number", - "exclusiveMinimum": 0 - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "number" - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "number" - }, - "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, - "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "additionalItems": { "$ref": "#" }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/schemaArray" } - ], - "default": {} - }, - "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, - "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "contains": { "$ref": "#" }, - "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, - "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "required": { "$ref": "#/definitions/stringArray" }, - "additionalProperties": { "$ref": "#" }, - "definitions": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "properties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "propertyNames": { "format": "regex" }, - "default": {} - }, - "dependencies": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/stringArray" } - ] - } - }, - "propertyNames": { "$ref": "#" }, - "const": {}, - "enum": { - "type": "array" - }, - "type": { - "anyOf": [ - { "$ref": "#/definitions/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/definitions/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "format": { "type": "string" }, - "allOf": { "$ref": "#/definitions/schemaArray" }, - "anyOf": { "$ref": "#/definitions/schemaArray" }, - "oneOf": { "$ref": "#/definitions/schemaArray" }, - "not": { "$ref": "#" } - }, - "default": {} -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft7/metaschema.json b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft7/metaschema.json deleted file mode 100644 index 746cde9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/schemas/draft7/metaschema.json +++ /dev/null @@ -1,166 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "http://json-schema.org/draft-07/schema#", - "title": "Core schema meta-schema", - "definitions": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#" } - }, - "nonNegativeInteger": { - "type": "integer", - "minimum": 0 - }, - "nonNegativeIntegerDefault0": { - "allOf": [ - { "$ref": "#/definitions/nonNegativeInteger" }, - { "default": 0 } - ] - }, - "simpleTypes": { - "enum": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true, - "default": [] - } - }, - "type": ["object", "boolean"], - "properties": { - "$id": { - "type": "string", - "format": "uri-reference" - }, - "$schema": { - "type": "string", - "format": "uri" - }, - "$ref": { - "type": "string", - "format": "uri-reference" - }, - "$comment": { - "type": "string" - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": true, - "readOnly": { - "type": "boolean", - "default": false - }, - "examples": { - "type": "array", - "items": true - }, - "multipleOf": { - "type": "number", - "exclusiveMinimum": 0 - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "number" - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "number" - }, - "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, - "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "additionalItems": { "$ref": "#" }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/schemaArray" } - ], - "default": true - }, - "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, - "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "contains": { "$ref": "#" }, - "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, - "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, - "required": { "$ref": "#/definitions/stringArray" }, - "additionalProperties": { "$ref": "#" }, - "definitions": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "properties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "propertyNames": { "format": "regex" }, - "default": {} - }, - "dependencies": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/stringArray" } - ] - } - }, - "propertyNames": { "$ref": "#" }, - "const": true, - "enum": { - "type": "array", - "items": true - }, - "type": { - "anyOf": [ - { "$ref": "#/definitions/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/definitions/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "format": { "type": "string" }, - "contentMediaType": { "type": "string" }, - "contentEncoding": { "type": "string" }, - "if": {"$ref": "#"}, - "then": {"$ref": "#"}, - "else": {"$ref": "#"}, - "allOf": { "$ref": "#/definitions/schemaArray" }, - "anyOf": { "$ref": "#/definitions/schemaArray" }, - "oneOf": { "$ref": "#/definitions/schemaArray" }, - "not": { "$ref": "#" } - }, - "default": true -} diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/tests/test_jsonschema_specifications.py b/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/tests/test_jsonschema_specifications.py deleted file mode 100644 index fd2927e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/jsonschema_specifications/tests/test_jsonschema_specifications.py +++ /dev/null @@ -1,41 +0,0 @@ -from collections.abc import Mapping -from pathlib import Path - -import pytest - -from jsonschema_specifications import REGISTRY - - -def test_it_contains_metaschemas(): - schema = REGISTRY.contents("http://json-schema.org/draft-07/schema#") - assert isinstance(schema, Mapping) - assert schema["$id"] == "http://json-schema.org/draft-07/schema#" - assert schema["title"] == "Core schema meta-schema" - - -def test_it_is_crawled(): - assert REGISTRY.crawl() == REGISTRY - - -@pytest.mark.parametrize( - "ignored_relative_path", - ["schemas/.DS_Store", "schemas/draft7/.DS_Store"], -) -def test_it_copes_with_dotfiles(ignored_relative_path): - """ - Ignore files like .DS_Store if someone has actually caused one to exist. - - We test here through the private interface as of course the global has - already loaded our schemas. - """ - - import jsonschema_specifications - - package = Path(jsonschema_specifications.__file__).parent - - ignored = package / ignored_relative_path - ignored.touch() - try: - list(jsonschema_specifications._schemas()) - finally: - ignored.unlink() diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/LICENSE deleted file mode 100644 index afb9a05..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2023 Onroerend Erfgoed - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/METADATA deleted file mode 100644 index 431e856..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/METADATA +++ /dev/null @@ -1,52 +0,0 @@ -Metadata-Version: 2.1 -Name: language-tags -Version: 1.2.0 -Summary: This project is a Python version of the language-tags Javascript project. -Home-page: https://github.com/OnroerendErfgoed/language-tags -Author: Flanders Heritage Agency -Author-email: ict@onroerenderfgoed.be -License: MIT -Platform: any -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: License :: OSI Approved :: MIT License -Description-Content-Type: text/x-rst -License-File: LICENSE - -IANA Language Tags for Python -============================= - -.. image:: https://badge.fury.io/py/language-tags.png - :target: http://badge.fury.io/py/language-tags -.. image:: https://app.travis-ci.com/OnroerendErfgoed/language-tags.png?branch=develop - :target: https://app.travis-ci.com/OnroerendErfgoed/language-tags -.. image:: https://coveralls.io/repos/OnroerendErfgoed/language-tags/badge.png - :target: https://coveralls.io/r/OnroerendErfgoed/language-tags -.. image:: https://readthedocs.org/projects/language-tags/badge/?version=latest - :target: https://readthedocs.org/projects/language-tags/?badge=latest - -This Python API offers a way to validate and lookup languages tags. - -Standard --------- - -It is based on `BCP 47 `_ (`RFC 5646 `_) and the latest `IANA language subtag registry `_. - -This project will be updated as the standards change. - -Language-tags 1.0.0 only supports Python 3, for Python 2 support, please use language-tags 0.5.0. - -JSON data ---------- - -See the `language-subtag-registry `_ project for the underlying JSON data. - -Javascript version ------------------- - -This project is a Python version of the `language-tags `_ Javascript project. - - diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/RECORD deleted file mode 100644 index 3091b77..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/RECORD +++ /dev/null @@ -1,24 +0,0 @@ -language_tags/Subtag.py,sha256=Wpqr8GZqrd9ozFxbArKPzGSw-mfcZ3dfFU1vlGzNDRc,4402 -language_tags/Tag.py,sha256=8DjrLIAKSdADHanXvu-lcLZhhK6dpI6AraPBbZN8T4I,15306 -language_tags/__init__.py,sha256=VNffJGXM5dGZCKXHmipviJMGJiNlVlBxW9miD15DJ84,35 -language_tags/tags.py,sha256=5N5_zPJFCTUxnYRuKYgc-cHnl5KJ3LLwzXlMoEvBd1c,6868 -language_tags/data/__init__.py,sha256=90y_YWPh0l8glnCTmXZFs3YhFsqB_myZekX4BlVP9yc,334 -language_tags/data/json/collection.json,sha256=eAGVRFiAwbzJOi1DnhNbsGJ2vXZPui8jGC1RvvJmpr8,1607 -language_tags/data/json/extlang.json,sha256=810fhxE332uD58SvmQnuXaUkQ5266_rwa_RXlxlg3ww,3531 -language_tags/data/json/grandfathered.json,sha256=eOOi2R_yszTf20F10zgRia490bSlQ6MLsntLPaBHKFo,481 -language_tags/data/json/index.json,sha256=tMX4h2y_d9MtIKU0e-GnDKvKQtgg_P_NvlQJXSn3m2A,297503 -language_tags/data/json/language.json,sha256=J5ytxpH_ao1L4jwvT6iVH8fg1OwhkOESElGq92TIKbk,114068 -language_tags/data/json/macrolanguage.json,sha256=dUNN5W-acKzkBScC3CW2JUjSyaK2CNJmNRd2naNjLes,784 -language_tags/data/json/meta.json,sha256=RrsEGnklYFSnWi-1s_5qivhKhGUxX5beNbpUrnppUWk,31 -language_tags/data/json/private-use.json,sha256=J5LQjfv6upD9waU75Q8Tv16xNY8ihUd0uuPvzyuNCpU,22 -language_tags/data/json/redundant.json,sha256=-lPhzqzYQ0wplT5g_IbZDhu3gj02F1fgfW7_JE-ch2w,1246 -language_tags/data/json/region.json,sha256=s4qB8DRt9J44466vVp1uVgXYd7UPGty2_SyGxWrCYdU,3994 -language_tags/data/json/registry.json,sha256=PcZQlXXQdqCpTEFhqvob_Pb-6nQlqU3FfeZvYtzQKqE,1103463 -language_tags/data/json/script.json,sha256=qT2pGEr83NhUg0YuyVyTX9omxLg9mNkcjCsGar5Z3yw,3189 -language_tags/data/json/special.json,sha256=7B16SUUugtpS46wCkkPE9HG1obO8b1LcpOsPoLlevqY,59 -language_tags/data/json/variant.json,sha256=vNJItGOdFih4oJTg5N8CAcJZB94nGTe7kXJBfcQWKOQ,1922 -language_tags-1.2.0.dist-info/LICENSE,sha256=nge5mlDunQs7ujhCNqNHY9u4W1VZGb8NILTEs3zHFao,1089 -language_tags-1.2.0.dist-info/METADATA,sha256=7m9_E1Z-tJwQz0l4-QiZ7s18aqL7VO4w5DL8VEGEtYI,2088 -language_tags-1.2.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 -language_tags-1.2.0.dist-info/top_level.txt,sha256=zsp-1Zd2UDhzSILmHcM4cfLtAmhlS6Z3IXrb_3oLxF4,14 -language_tags-1.2.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/WHEEL deleted file mode 100644 index becc9a6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.37.1) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/top_level.txt deleted file mode 100644 index 25d3202..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags-1.2.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -language_tags diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/Subtag.py b/extensions/.local/lib/python3.11/site-packages/language_tags/Subtag.py deleted file mode 100644 index d39e613..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/Subtag.py +++ /dev/null @@ -1,152 +0,0 @@ -# -*- coding: utf-8 -*- -import json -from language_tags import data - - -index = data.get('index') -registry = data.get('registry') - - -class Subtag: - def __init__(self, subtag, type): - - """ - A subtag is a part of the hyphen-separated :class:`language_tags.Tag.Tag`. - - :param str subtag: subtage. - :param str type: can be 'language', 'extlang', 'script', 'region' or 'variant'. - :return: :raise Error: Checks for ``Subtag.ERR_NONEXISTENT`` and ``Subtag.ERR_TAG``. - """ - # Lowercase for consistency (case is only a formatting convention, not a standard requirement). - subtag = str(subtag).lower() - type = str(type).lower() - - # Include errror codes - self.ERR_NONEXISTENT = 1 - self.ERR_TAG = 2 - - class Error(Exception): - def __init__(self, code, message): - self.code = code - self.message = message - - def __str__(self): - return repr("%s: %s" % (self.code, self.message)) - - if subtag not in index: - raise Error(self.ERR_NONEXISTENT, 'Non-existent subtag %s.' % subtag) - types = index[subtag] - - if type not in types: - raise Error(self.ERR_NONEXISTENT, 'Non-existent subtag %s of type %s.' % (subtag, type)) - i = types[type] - - record = registry[i] - if 'Subtag' not in record: - raise Error(self.ERR_TAG, '%s is a %s tag' % (subtag, type)) - - self.data = { - "subtag": subtag, - "record": record, - "type": type - } - - def __str__(self): - return self.format - - def __repr__(self): - return json.dumps(self.data, ensure_ascii=False) - - @property - def type(self): - """ - Get the subtag type. - - :return: string -- either 'language', 'extlang', 'script', 'region' or 'variant'. - """ - return self.data['type'] - - @property - def description(self): - """ - Get the subtag description. - - :return: list of description strings. - """ - return self.data['record']['Description'] - - @property - def preferred(self): - """ - Get the preferred subtag. - - :return: preferred :class:`language_tags.Subtag.Subtag` if exists, otherwise None. - """ - if 'Preferred-Value' in self.data['record']: - preferred = self.data['record']['Preferred-Value'] - type = self.data['type'] - if type == 'extlang': - type = 'language' - return Subtag(preferred, type) - return None - - @property - def format(self): - """ - Get the subtag code conventional format according to RFC 5646 section 2.1.1. - - :return: string -- subtag code conventional format. - """ - subtag = self.data['subtag'] - if self.data['type'] == 'region': - return subtag.upper() - if self.data['type'] == 'script': - return subtag.capitalize() - return subtag - - @property - def script(self): - """ - Get the language's default script of the subtag (RFC 5646 section 3.1.9) - - :return: string -- the language's default script. - """ - if 'Suppress-Script' in self.data['record']: - return Subtag(self.data['record']['Suppress-Script'], 'script') - return None - - @property - def scope(self): - """ - Get the subtag scope. - - :return: string subtag scope if exists, otherwise None. - """ - return self.data['record']['Scope'] if 'Scope' in self.data['record'] else None - - @property - def deprecated(self): - """ - Get the deprecation date. - - :return: deprecation date as string if subtag is deprecated, otherwise None. - """ - return self.data['record']['Deprecated'] if 'Deprecated' in self.data['record'] else None - - @property - def added(self): - """ - Get the date when the subtag was added to the registry. - - :return: date (as string) when the subtag was added to the registry. - """ - return self.data['record']['Added'] - - @property - def comments(self): - """ - Get the comments of the subtag. - - :return: list of comments. The return list can be empty. - """ - return self.data['record']['Comments'] if 'Comments' in self.data['record'] else [] diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/Tag.py b/extensions/.local/lib/python3.11/site-packages/language_tags/Tag.py deleted file mode 100644 index 09c3d44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/Tag.py +++ /dev/null @@ -1,424 +0,0 @@ -# -*- coding: utf-8 -*- -import json - - -from language_tags.Subtag import Subtag -from language_tags import data - - -index = data.get('index') -registry = data.get('registry') - - -class Tag: - def __init__(self, tag): - # Lowercase for consistency (case is only a formatting convention, not a standard requirement). - """ - Tags for Identifying Languages based on BCP 47 (RFC 5646) and the latest IANA language subtag registry. - - :param str tag: (hyphen-separated) tag. - """ - tag = str(tag).strip().lower() - - self.data = {'tag': tag} - - if tag in index: - types = index[tag] - # Check if the input tag is grandfathered or redundant. - if 'grandfathered' in types or 'redundant' in types: - self.data['record'] = registry[types['grandfathered']] if 'grandfathered' in types \ - else registry[types['redundant']] - - # Include errror codes - self.ERR_DEPRECATED = 1 - self.ERR_NO_LANGUAGE = 2 - self.ERR_UNKNOWN = 3 - self.ERR_TOO_LONG = 4 - self.ERR_EXTRA_REGION = 5 - self.ERR_EXTRA_EXTLANG = 6 - self.ERR_EXTRA_SCRIPT = 7 - self.ERR_DUPLICATE_VARIANT = 8 - self.ERR_WRONG_ORDER = 9 - self.ERR_SUPPRESS_SCRIPT = 10 - self.ERR_SUBTAG_DEPRECATED = 11 - self.ERR_EXTRA_LANGUAGE = 12 - - def __str__(self): - return self.format - - def __repr__(self): - return json.dumps(self.data, ensure_ascii=False) - - @property - def preferred(self): - """ - Get the preferred :class:`language_tags.Tag.Tag` of the deprecated or redundant tag. - - :return: preferred :class:`language_tags.Tag.Tag` if the deprecated or redundant tag has one, otherwise None. - """ - if 'record' in self.data: - return Tag(self.data['record']['Preferred-Value']) if 'Preferred-Value' in self.data['record'] else None - else: - return None - - @property - def type(self): - """ - Get the type of the tag (either grandfathered, redundant or tag see RFC 5646 section 2.2.8.). - - :return: string -- type of the tag. - """ - if 'record' in self.data: - return self.data['record']['Type'] - return 'tag' - - @property - def added(self): - """ - Get the date string of grandfathered or redundant tag when it was added to the registry. - - :return: added date string if the deprecated or redundant tag has one, otherwise None. - """ - if 'record' in self.data: - return self.data['record']['Added'] if 'Added' in self.data['record'] else None - else: - return None - - @property - def deprecated(self): - """ - Get the deprecation date of grandfathered or redundant tag if the tag is deprecated. - - :return: deprecation date string if the deprecated or redundant tag has one, otherwise None. - """ - if 'record' in self.data: - return self.data['record']['Deprecated'] if 'Deprecated' in self.data['record'] else None - else: - return None - - @property - def descriptions(self): - """ - Get the list of descriptions of the grandfathered or redundant tag. - - :return: list of descriptions. If no descriptions available, it returns an empty list. - """ - if 'record' in self.data: - return self.data['record']['Description'] if 'Description' in self.data['record'] else [] - else: - return [] - - @property - def format(self): - """ - Get format according to algorithm defined in RFC 5646 section 2.1.1. - - - :return: formatted tag string. - """ - tag = self.data['tag'] - subtags = tag.split('-') - if len(subtags) == 1: - return subtags[0] - - formatted_tag = subtags[0] - private_tag = False - for i, subtag in enumerate(subtags[1:]): - - if len(subtags[i]) == 1 or private_tag: - formatted_tag += '-' + subtag - private_tag = True - - elif len(subtag) == 2: - formatted_tag += '-' + subtag.upper() - - elif len(subtag) == 4: - formatted_tag += '-' + subtag.capitalize() - else: - formatted_tag += '-' + subtag - - return formatted_tag - - @property - def subtags(self): - """ - Get the :class:`language_tags.Subtag.Subtag` objects of the tag. - - :return: list of :class:`language_tags.Subtag.Subtag` objects that are part of the tag. - The return list can be empty. - """ - data = self.data - subtags = [] - - # if tag is grandfathered return no subtags - if 'record' in data and self.data['record']['Type'] == 'grandfathered': - return subtags - - codes = data['tag'].split('-') - # Try and find the language tag. - for i, code in enumerate(codes): - - # Singletons and anything after are unhandled. - if len(code) == 1: - #Stop the loop (stop processing after a singleton). - break - - # Check for non-existent tag. - if code not in index: - continue - types = index[code] - - # Language subtags may only appear at the beginning of the tag, otherwise the subtag type is indeterminate. - if 'language' in types and i == 0: - subtags.append(Subtag(code, 'language')) - continue - - if len(code) == 2: - # Should be a region - if 'region' in types: - subtags.append(Subtag(code, 'region')) - # Error case: language subtag in the wrong place. - elif 'language' in types: - subtags.append(Subtag(code, 'language')) - - elif len(code) == 3: - # Could be a numeric region code e.g. '001' for 'World'. - if 'region' in types: - subtags.append(Subtag(code, 'region')) - elif 'extlang' in types: - subtags.append(Subtag(code, 'extlang')) - # Error case: language subtag in the wrong place. - elif 'language' in types: - subtags.append(Subtag(code, 'language')) - - elif len(code) == 4: - # Could be a numeric variant - if 'variant' in types: - subtags.append(Subtag(code, 'variant')) - elif 'script' in types: - subtags.append(Subtag(code, 'script')) - - else: - # Should be a variant - if 'variant' in types: - subtags.append(Subtag(code, 'variant')) - - return subtags - - @property - def language(self): - """ - Get the language :class:`language_tags.Subtag.Subtag` of the tag. - - :return: language :class:`language_tags.Subtag.Subtag` that is part of the tag. - The return can be None. - """ - - language_item = [subtag for subtag in self.subtags if subtag.type == 'language'] - - return language_item[0] if len(language_item) > 0 else None - - @property - def region(self): - """ - Get the region :class:`language_tags.Subtag.Subtag` of the tag. - - :return: region :class:`language_tags.Subtag.Subtag` that is part of the tag. - The return can be None. - """ - - region_item = [subtag for subtag in self.subtags if subtag.type == 'region'] - - return region_item[0] if len(region_item) > 0 else None - - - @property - def script(self): - """ - Get the script :class:`language_tags.Subtag.Subtag` of the tag. - - :return: script :class:`language_tags.Subtag.Subtag` that is part of the tag. - The return can be None. - """ - script_item = [subtag for subtag in self.subtags if subtag.type == 'script'] - - return script_item[0] if len(script_item) > 0 else None - - @property - def valid(self): - """ - Checks whether the tag is valid. - - :return: Bool -- True if valid otherwise False. - """ - return len(self.errors) < 1 - - @property - def errors(self): - """ - Get the errors of the tag. - If invalid then the list will consist of errors containing each a code and message explaining the error. - Each error also refers to the respective (sub)tag(s). - - :return: list of errors of the tag. If the tag is valid, it returns an empty list. - """ - errors = [] - data = self.data - error = self.error - - # Check if the tag is grandfathered and if the grandfathered tag is deprecated (e.g. no-nyn). - if 'record' in data: - if 'Deprecated' in data['record']: - errors.append(error(self.ERR_DEPRECATED)) - # Only check every subtag if the tag is not explicitly listed as grandfathered or redundant. - return errors - - # Check that all subtag codes are meaningful. - codes = data['tag'].split('-') - for i, code in enumerate(codes): - # Ignore anything after a singleton (break) - if len(code) < 2: - # Check that each private-use subtag is within the maximum allowed length. - for code in codes[i + 1:]: - if len(code) > 8: - errors.append(error(self.ERR_TOO_LONG, code)) - break - - if code not in index: - errors.append(error(self.ERR_UNKNOWN, code)) - # Continue to the next item. - continue - - # Check that first tag is a language tag. - subtags = self.subtags - if not len(subtags): - errors.append(error(self.ERR_NO_LANGUAGE)) - return errors - elif subtags[0].type != 'language': - errors.append(error(self.ERR_NO_LANGUAGE)) - return errors - - # Check for more than one of some types and for deprecation. - found = dict(language=[], extlang=[], variant=[], script=[], region=[]) - for subtag in subtags: - type = subtag.type - - if subtag.deprecated: - errors.append(error(self.ERR_SUBTAG_DEPRECATED, subtag)) - - if type in found: - found[type].append(subtag) - - if 'language' == type: - if len(found['language']) > 1: - errors.append(error(self.ERR_EXTRA_LANGUAGE, subtag)) - elif 'region' == type: - if len(found['region']) > 1: - errors.append(error(self.ERR_EXTRA_REGION, subtag)) - elif 'extlang' == type: - if len(found['extlang']) > 1: - errors.append(error(self.ERR_EXTRA_EXTLANG, subtag)) - elif 'script' == type: - if len(found['script']) > 1: - errors.append(error(self.ERR_EXTRA_SCRIPT, subtag)) - # Check if script is same as language suppress-script. - else: - script = subtags[0].script - if script: - if script.format == subtag.format: - errors.append(error(self.ERR_SUPPRESS_SCRIPT, subtag)) - elif 'variant' == type: - if len(found['variant']) > 1: - for variant in found['variant']: - if variant.format == subtag.format: - errors.append(error(self.ERR_DUPLICATE_VARIANT, subtag)) - break - - # Check for correct order. - if len(subtags) > 1: - priority = dict(language=4, extlang=5, script=6, region=7, variant=8) - for i, subtag in enumerate(subtags[0:len(subtags)-1]): - next = subtags[i + 1] - if next: - if priority[subtag.type] > priority[next.type]: - errors.append(error(self.ERR_WRONG_ORDER, [subtag, next])) - - return errors - - def error(self, code, subtag=None): - """ - Get the :class:`language_tags.Tag.Tag.Error` of a specific Tag error code. - The error creates a message explaining the error. - It also refers to the respective (sub)tag(s). - - :param int code: a Tag error error: - - * 1 = Tag.ERR_DEPRECATED - * 2 = Tag.ERR_NO_LANGUAGE - * 3 = Tag.ERR_UNKNOWN, - * 4 = Tag.ERR_TOO_LONG - * 5 = Tag.ERR_EXTRA_REGION - * 6 = Tag.ERR_EXTRA_EXTLANG - * 7 = Tag.ERR_EXTRA_SCRIPT, - * 8 = Tag.ERR_DUPLICATE_VARIANT - * 9 = Tag.ERR_WRONG_ORDER - * 10 = Tag.ERR_SUPPRESS_SCRIPT, - * 11 = Tag.ERR_SUBTAG_DEPRECATED - * 12 = Tag.ERR_EXTRA_LANGUAGE - - :param subtag: string (sub)tag or list of string (sub)tags creating the error. - :return: An exception class containing: a Tag error input code, the derived message with the given (sub)tag(s). - input - """ - message = "" - data = self.data - - if code == self.ERR_DEPRECATED: - message = 'The tag %s is deprecated.' % data['tag'] - - # Note that a record that contains a 'Deprecated' field and no corresponding 'Preferred-Value' field - # has no replacement mapping (RFC 5646 section 3.1.6). - if 'Preferred-Value' in self.data['record']: - message += ' Use \'%s\' instead.' % data['record']['Preferred-Value'] - - elif code == self.ERR_SUBTAG_DEPRECATED: - message = 'The subtag \'%s\' is deprecated.' % subtag.format - - elif code == self.ERR_NO_LANGUAGE: - if not len(data['tag']): - message = 'Empty tag.' - else: - message = 'Missing language tag in \'%s\'.' % data['tag'] - - elif code == self.ERR_UNKNOWN: - message = 'Unknown code \'%s\'' % subtag - - elif code == self.ERR_TOO_LONG: - message = 'The private-use subtag \'%s\' is too long.' % subtag - - elif code in [self.ERR_EXTRA_LANGUAGE, - self.ERR_EXTRA_EXTLANG, - self.ERR_EXTRA_REGION, - self.ERR_EXTRA_SCRIPT]: - message = 'Extra %s subtag \'%s\' found.' % (subtag.type, subtag.format) - - elif code == self.ERR_DUPLICATE_VARIANT: - message = 'Duplicate variant subtag \'%s\' found.' % subtag.format - - elif code == self.ERR_WRONG_ORDER: - message = 'The subtag \'%s\' should not appear before \'%s\'.' % (subtag[0].format, subtag[1].format) - - elif code == self.ERR_SUPPRESS_SCRIPT: - message = 'The script subtag \'%s\' is the same as the language suppress-script.' % subtag.format - - class Error(Exception): - def __init__(self, code, message, tag, subtag): - self.code = code - self.message = message - self.tag = tag - self.subtag = subtag.format if isinstance(subtag, Subtag) else subtag - - def __str__(self): - return repr("%s: %s (Tag %s; Subtag %s)" % (self.code, self.message, self.tag, str(self.subtag))) - - return Error(code, message, data['tag'], subtag) diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/__init__.py b/extensions/.local/lib/python3.11/site-packages/language_tags/__init__.py deleted file mode 100644 index d3a906f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from language_tags.tags import tags \ No newline at end of file diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/__init__.py b/extensions/.local/lib/python3.11/site-packages/language_tags/data/__init__.py deleted file mode 100644 index b61553a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -import json -from io import open - -__all__ = ['get'] - -parent_dir = os.path.dirname(__file__) -data_dir = 'json/' - -cache = {} - - -def get(name): - if name not in cache: - with open(os.path.join(parent_dir, data_dir, "%s.json" % name), encoding='utf-8') as f: - cache[name] = json.load(f) - - return cache[name] diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/collection.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/collection.json deleted file mode 100644 index b32f597..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/collection.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "bh": 15, - "aav": 209, - "afa": 298, - "alg": 415, - "alv": 430, - "apa": 505, - "aqa": 531, - "aql": 536, - "art": 558, - "ath": 596, - "auf": 620, - "aus": 633, - "awd": 655, - "azc": 702, - "bad": 714, - "bai": 719, - "bat": 727, - "ber": 826, - "bnt": 1054, - "btk": 1193, - "cai": 1366, - "cau": 1377, - "cba": 1383, - "ccn": 1413, - "ccs": 1418, - "cdc": 1420, - "cdd": 1421, - "cel": 1439, - "cmc": 1529, - "cpe": 1584, - "cpf": 1585, - "cpp": 1590, - "crp": 1611, - "csu": 1641, - "cus": 1677, - "day": 1721, - "dmn": 1867, - "dra": 1913, - "egx": 2024, - "esx": 2110, - "euq": 2123, - "fiu": 2165, - "fox": 2187, - "gem": 2313, - "gme": 2399, - "gmq": 2405, - "gmw": 2409, - "grk": 2475, - "him": 2626, - "hmx": 2667, - "hok": 2689, - "hyx": 2760, - "iir": 2814, - "ijo": 2819, - "inc": 2858, - "ine": 2859, - "ira": 2878, - "iro": 2884, - "itc": 2904, - "jpx": 3043, - "kar": 3090, - "kdo": 3160, - "khi": 3256, - "kro": 3511, - "map": 4085, - "mkh": 4328, - "mno": 4409, - "mun": 4581, - "myn": 4681, - "nah": 4726, - "nai": 4727, - "ngf": 4848, - "nic": 4894, - "nub": 5131, - "omq": 5301, - "omv": 5305, - "oto": 5370, - "paa": 5394, - "phi": 5499, - "plf": 5554, - "poz": 5639, - "pqe": 5655, - "pqw": 5657, - "pra": 5658, - "qwe": 5793, - "roa": 5920, - "sai": 5984, - "sal": 5987, - "sdv": 6065, - "sem": 6080, - "sgn": 6110, - "sio": 6158, - "sit": 6163, - "sla": 6211, - "smi": 6240, - "son": 6291, - "sqj": 6325, - "ssa": 6359, - "syd": 6474, - "tai": 6506, - "tbq": 6538, - "trk": 6863, - "tup": 6942, - "tut": 6945, - "tuw": 6948, - "urj": 7122, - "wak": 7262, - "wen": 7311, - "xgn": 7563, - "xnd": 7653, - "ypk": 7975, - "zhx": 8104, - "zle": 8129, - "zls": 8134, - "zlw": 8135, - "znd": 8163 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/extlang.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/extlang.json deleted file mode 100644 index 3c76fce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/extlang.json +++ /dev/null @@ -1,254 +0,0 @@ -{ - "aao": 8240, - "abh": 8241, - "abv": 8242, - "acm": 8243, - "acq": 8244, - "acw": 8245, - "acx": 8246, - "acy": 8247, - "adf": 8248, - "ads": 8249, - "aeb": 8250, - "aec": 8251, - "aed": 8252, - "aen": 8253, - "afb": 8254, - "afg": 8255, - "ajp": 8256, - "ajs": 8257, - "apc": 8258, - "apd": 8259, - "arb": 8260, - "arq": 8261, - "ars": 8262, - "ary": 8263, - "arz": 8264, - "ase": 8265, - "asf": 8266, - "asp": 8267, - "asq": 8268, - "asw": 8269, - "auz": 8270, - "avl": 8271, - "ayh": 8272, - "ayl": 8273, - "ayn": 8274, - "ayp": 8275, - "bbz": 8276, - "bfi": 8277, - "bfk": 8278, - "bjn": 8279, - "bog": 8280, - "bqn": 8281, - "bqy": 8282, - "btj": 8283, - "bve": 8284, - "bvl": 8285, - "bvu": 8286, - "bzs": 8287, - "cdo": 8288, - "cds": 8289, - "cjy": 8290, - "cmn": 8291, - "cnp": 8292, - "coa": 8293, - "cpx": 8294, - "csc": 8295, - "csd": 8296, - "cse": 8297, - "csf": 8298, - "csg": 8299, - "csl": 8300, - "csn": 8301, - "csp": 8302, - "csq": 8303, - "csr": 8304, - "csx": 8305, - "czh": 8306, - "czo": 8307, - "doq": 8308, - "dse": 8309, - "dsl": 8310, - "dsz": 8311, - "dup": 8312, - "ecs": 8313, - "ehs": 8314, - "esl": 8315, - "esn": 8316, - "eso": 8317, - "eth": 8318, - "fcs": 8319, - "fse": 8320, - "fsl": 8321, - "fss": 8322, - "gan": 8323, - "gds": 8324, - "gom": 8325, - "gse": 8326, - "gsg": 8327, - "gsm": 8328, - "gss": 8329, - "gus": 8330, - "hab": 8331, - "haf": 8332, - "hak": 8333, - "hds": 8334, - "hji": 8335, - "hks": 8336, - "hos": 8337, - "hps": 8338, - "hsh": 8339, - "hsl": 8340, - "hsn": 8341, - "icl": 8342, - "iks": 8343, - "ils": 8344, - "inl": 8345, - "ins": 8346, - "ise": 8347, - "isg": 8348, - "isr": 8349, - "jak": 8350, - "jax": 8351, - "jcs": 8352, - "jhs": 8353, - "jks": 8354, - "jls": 8355, - "jos": 8356, - "jsl": 8357, - "jus": 8358, - "kgi": 8359, - "knn": 8360, - "kvb": 8361, - "kvk": 8362, - "kvr": 8363, - "kxd": 8364, - "lbs": 8365, - "lce": 8366, - "lcf": 8367, - "liw": 8368, - "lls": 8369, - "lsb": 8370, - "lsc": 8371, - "lsg": 8372, - "lsl": 8373, - "lsn": 8374, - "lso": 8375, - "lsp": 8376, - "lst": 8377, - "lsv": 8378, - "lsw": 8379, - "lsy": 8380, - "ltg": 8381, - "lvs": 8382, - "lws": 8383, - "lzh": 8384, - "max": 8385, - "mdl": 8386, - "meo": 8387, - "mfa": 8388, - "mfb": 8389, - "mfs": 8390, - "min": 8391, - "mnp": 8392, - "mqg": 8393, - "mre": 8394, - "msd": 8395, - "msi": 8396, - "msr": 8397, - "mui": 8398, - "mzc": 8399, - "mzg": 8400, - "mzy": 8401, - "nan": 8402, - "nbs": 8403, - "ncs": 8404, - "nsi": 8405, - "nsl": 8406, - "nsp": 8407, - "nsr": 8408, - "nzs": 8409, - "okl": 8410, - "orn": 8411, - "ors": 8412, - "pel": 8413, - "pga": 8414, - "pgz": 8415, - "pks": 8416, - "prl": 8417, - "prz": 8418, - "psc": 8419, - "psd": 8420, - "pse": 8421, - "psg": 8422, - "psl": 8423, - "pso": 8424, - "psp": 8425, - "psr": 8426, - "pys": 8427, - "rib": 8428, - "rms": 8429, - "rnb": 8430, - "rsi": 8431, - "rsl": 8432, - "rsm": 8433, - "rsn": 8434, - "sdl": 8435, - "sfb": 8436, - "sfs": 8437, - "sgg": 8438, - "sgx": 8439, - "shu": 8440, - "slf": 8441, - "sls": 8442, - "sqk": 8443, - "sqs": 8444, - "sqx": 8445, - "ssh": 8446, - "ssp": 8447, - "ssr": 8448, - "svk": 8449, - "swc": 8450, - "swh": 8451, - "swl": 8452, - "syy": 8453, - "szs": 8454, - "tmw": 8455, - "tse": 8456, - "tsm": 8457, - "tsq": 8458, - "tss": 8459, - "tsy": 8460, - "tza": 8461, - "ugn": 8462, - "ugy": 8463, - "ukl": 8464, - "uks": 8465, - "urk": 8466, - "uzn": 8467, - "uzs": 8468, - "vgt": 8469, - "vkk": 8470, - "vkt": 8471, - "vsi": 8472, - "vsl": 8473, - "vsv": 8474, - "wbs": 8475, - "wuu": 8476, - "xki": 8477, - "xml": 8478, - "xmm": 8479, - "xms": 8480, - "yds": 8481, - "ygs": 8482, - "yhs": 8483, - "ysl": 8484, - "ysm": 8485, - "yue": 8486, - "zib": 8487, - "zlm": 8488, - "zmi": 8489, - "zsl": 8490, - "zsm": 8491 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/grandfathered.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/grandfathered.json deleted file mode 100644 index 91c8c2d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/grandfathered.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "art-lojban": 9117, - "cel-gaulish": 9118, - "en-gb-oed": 9119, - "i-ami": 9120, - "i-bnn": 9121, - "i-default": 9122, - "i-enochian": 9123, - "i-hak": 9124, - "i-klingon": 9125, - "i-lux": 9126, - "i-mingo": 9127, - "i-navajo": 9128, - "i-pwn": 9129, - "i-tao": 9130, - "i-tay": 9131, - "i-tsu": 9132, - "no-bok": 9133, - "no-nyn": 9134, - "sgn-be-fr": 9135, - "sgn-be-nl": 9136, - "sgn-ch-de": 9137, - "zh-guoyu": 9138, - "zh-hakka": 9139, - "zh-min": 9140, - "zh-min-nan": 9141, - "zh-xiang": 9142 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/index.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/index.json deleted file mode 100644 index 614afa9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/index.json +++ /dev/null @@ -1,26890 +0,0 @@ -{ - "142": { - "region": 8999 - }, - "143": { - "region": 9000 - }, - "145": { - "region": 9001 - }, - "150": { - "region": 9002 - }, - "151": { - "region": 9003 - }, - "154": { - "region": 9004 - }, - "155": { - "region": 9005 - }, - "202": { - "region": 9006 - }, - "419": { - "region": 9007 - }, - "1901": { - "variant": 9010 - }, - "1994": { - "variant": 9012 - }, - "1996": { - "variant": 9013 - }, - "aa": { - "language": 0, - "region": 8704 - }, - "ab": { - "language": 1 - }, - "ae": { - "language": 2, - "region": 8707 - }, - "af": { - "language": 3, - "region": 8708 - }, - "ak": { - "language": 4 - }, - "am": { - "language": 5, - "region": 8712 - }, - "an": { - "language": 6, - "region": 8713 - }, - "ar": { - "language": 7, - "region": 8716 - }, - "as": { - "language": 8, - "region": 8717 - }, - "av": { - "language": 9 - }, - "ay": { - "language": 10 - }, - "az": { - "language": 11, - "region": 8722 - }, - "ba": { - "language": 12, - "region": 8723 - }, - "be": { - "language": 13, - "region": 8726 - }, - "bg": { - "language": 14, - "region": 8728 - }, - "bh": { - "language": 15, - "region": 8729 - }, - "bi": { - "language": 16, - "region": 8730 - }, - "bm": { - "language": 17, - "region": 8733 - }, - "bn": { - "language": 18, - "region": 8734 - }, - "bo": { - "language": 19, - "region": 8735 - }, - "br": { - "language": 20, - "region": 8737 - }, - "bs": { - "language": 21, - "region": 8738 - }, - "ca": { - "language": 22, - "region": 8745 - }, - "ce": { - "language": 23 - }, - "ch": { - "language": 24, - "region": 8750 - }, - "co": { - "language": 25, - "region": 8756 - }, - "cr": { - "language": 26, - "region": 8758 - }, - "cs": { - "language": 27, - "region": 8759 - }, - "cu": { - "language": 28, - "region": 8760 - }, - "cv": { - "language": 29, - "region": 8761 - }, - "cy": { - "language": 30, - "region": 8764 - }, - "da": { - "language": 31 - }, - "de": { - "language": 32, - "region": 8767 - }, - "dv": { - "language": 33 - }, - "dz": { - "language": 34, - "region": 8773 - }, - "ee": { - "language": 35, - "region": 8776 - }, - "el": { - "language": 36 - }, - "en": { - "language": 37 - }, - "eo": { - "language": 38 - }, - "es": { - "language": 39, - "region": 8780 - }, - "et": { - "language": 40, - "region": 8781 - }, - "eu": { - "language": 41, - "region": 8782 - }, - "fa": { - "language": 42 - }, - "ff": { - "language": 43 - }, - "fi": { - "language": 44, - "region": 8784 - }, - "fj": { - "language": 45, - "region": 8785 - }, - "fo": { - "language": 46, - "region": 8788 - }, - "fr": { - "language": 47, - "region": 8789 - }, - "fy": { - "language": 48 - }, - "ga": { - "language": 49, - "region": 8791 - }, - "gd": { - "language": 50, - "region": 8793 - }, - "gl": { - "language": 51, - "region": 8799 - }, - "gn": { - "language": 52, - "region": 8801 - }, - "gu": { - "language": 53, - "region": 8807 - }, - "gv": { - "language": 54 - }, - "ha": { - "language": 55 - }, - "he": { - "language": 56 - }, - "hi": { - "language": 57 - }, - "ho": { - "language": 58 - }, - "hr": { - "language": 59, - "region": 8813 - }, - "ht": { - "language": 60, - "region": 8814 - }, - "hu": { - "language": 61, - "region": 8815 - }, - "hy": { - "language": 62 - }, - "hz": { - "language": 63 - }, - "ia": { - "language": 64 - }, - "id": { - "language": 65, - "region": 8817 - }, - "ie": { - "language": 66, - "region": 8818 - }, - "ig": { - "language": 67 - }, - "ii": { - "language": 68 - }, - "ik": { - "language": 69 - }, - "in": { - "language": 70, - "region": 8821 - }, - "io": { - "language": 71, - "region": 8822 - }, - "is": { - "language": 72, - "region": 8825 - }, - "it": { - "language": 73, - "region": 8826 - }, - "iu": { - "language": 74 - }, - "iw": { - "language": 75 - }, - "ja": { - "language": 76 - }, - "ji": { - "language": 77 - }, - "jv": { - "language": 78 - }, - "jw": { - "language": 79 - }, - "ka": { - "language": 80 - }, - "kg": { - "language": 81, - "region": 8832 - }, - "ki": { - "language": 82, - "region": 8834 - }, - "kj": { - "language": 83 - }, - "kk": { - "language": 84 - }, - "kl": { - "language": 85 - }, - "km": { - "language": 86, - "region": 8835 - }, - "kn": { - "language": 87, - "region": 8836 - }, - "ko": { - "language": 88 - }, - "kr": { - "language": 89, - "region": 8838 - }, - "ks": { - "language": 90 - }, - "ku": { - "language": 91 - }, - "kv": { - "language": 92 - }, - "kw": { - "language": 93, - "region": 8839 - }, - "ky": { - "language": 94, - "region": 8840 - }, - "la": { - "language": 95, - "region": 8842 - }, - "lb": { - "language": 96, - "region": 8843 - }, - "lg": { - "language": 97 - }, - "li": { - "language": 98, - "region": 8845 - }, - "ln": { - "language": 99 - }, - "lo": { - "language": 100 - }, - "lt": { - "language": 101, - "region": 8849 - }, - "lu": { - "language": 102, - "region": 8850 - }, - "lv": { - "language": 103, - "region": 8851 - }, - "mg": { - "language": 104, - "region": 8858 - }, - "mh": { - "language": 105, - "region": 8859 - }, - "mi": { - "language": 106 - }, - "mk": { - "language": 107, - "region": 8860 - }, - "ml": { - "language": 108, - "region": 8861 - }, - "mn": { - "language": 109, - "region": 8863 - }, - "mo": { - "language": 110, - "region": 8864 - }, - "mr": { - "language": 111, - "region": 8867 - }, - "ms": { - "language": 112, - "region": 8868 - }, - "mt": { - "language": 113, - "region": 8869 - }, - "my": { - "language": 114, - "region": 8874 - }, - "na": { - "language": 115, - "region": 8876 - }, - "nb": { - "language": 116 - }, - "nd": { - "language": 117 - }, - "ne": { - "language": 118, - "region": 8878 - }, - "ng": { - "language": 119, - "region": 8880 - }, - "nl": { - "language": 120, - "region": 8882 - }, - "nn": { - "language": 121 - }, - "no": { - "language": 122, - "region": 8883 - }, - "nr": { - "language": 123, - "region": 8885 - }, - "nv": { - "language": 124 - }, - "ny": { - "language": 125 - }, - "oc": { - "language": 126 - }, - "oj": { - "language": 127 - }, - "om": { - "language": 128, - "region": 8889 - }, - "or": { - "language": 129 - }, - "os": { - "language": 130 - }, - "pa": { - "language": 131, - "region": 8890 - }, - "pi": { - "language": 132 - }, - "pl": { - "language": 133, - "region": 8896 - }, - "ps": { - "language": 134, - "region": 8900 - }, - "pt": { - "language": 135, - "region": 8901 - }, - "qu": { - "language": 136 - }, - "rm": { - "language": 137 - }, - "rn": { - "language": 138 - }, - "ro": { - "language": 139, - "region": 8907 - }, - "ru": { - "language": 140, - "region": 8909 - }, - "rw": { - "language": 141, - "region": 8910 - }, - "sa": { - "language": 142, - "region": 8911 - }, - "sc": { - "language": 143, - "region": 8913 - }, - "sd": { - "language": 144, - "region": 8914 - }, - "se": { - "language": 145, - "region": 8915 - }, - "sg": { - "language": 146, - "region": 8916 - }, - "sh": { - "language": 147, - "region": 8917 - }, - "si": { - "language": 148, - "region": 8918 - }, - "sk": { - "language": 149, - "region": 8920 - }, - "sl": { - "language": 150, - "region": 8921 - }, - "sm": { - "language": 151, - "region": 8922 - }, - "sn": { - "language": 152, - "region": 8923 - }, - "so": { - "language": 153, - "region": 8924 - }, - "sq": { - "language": 154 - }, - "sr": { - "language": 155, - "region": 8925 - }, - "ss": { - "language": 156, - "region": 8926 - }, - "st": { - "language": 157, - "region": 8927 - }, - "su": { - "language": 158, - "region": 8928 - }, - "sv": { - "language": 159, - "region": 8929 - }, - "sw": { - "language": 160 - }, - "ta": { - "language": 161, - "region": 8933 - }, - "te": { - "language": 162 - }, - "tg": { - "language": 163, - "region": 8937 - }, - "th": { - "language": 164, - "region": 8938 - }, - "ti": { - "language": 165 - }, - "tk": { - "language": 166, - "region": 8940 - }, - "tl": { - "language": 167, - "region": 8941 - }, - "tn": { - "language": 168, - "region": 8943 - }, - "to": { - "language": 169, - "region": 8944 - }, - "tr": { - "language": 170, - "region": 8946 - }, - "ts": { - "language": 171 - }, - "tt": { - "language": 172, - "region": 8947 - }, - "tw": { - "language": 173, - "region": 8949 - }, - "ty": { - "language": 174 - }, - "ug": { - "language": 175, - "region": 8952 - }, - "uk": { - "language": 176 - }, - "ur": { - "language": 177 - }, - "uz": { - "language": 178, - "region": 8957 - }, - "ve": { - "language": 179, - "region": 8960 - }, - "vi": { - "language": 180, - "region": 8962 - }, - "vo": { - "language": 181 - }, - "wa": { - "language": 182 - }, - "wo": { - "language": 183 - }, - "xh": { - "language": 184 - }, - "yi": { - "language": 185 - }, - "yo": { - "language": 186 - }, - "za": { - "language": 187, - "region": 8972 - }, - "zh": { - "language": 188 - }, - "zu": { - "language": 189 - }, - "aaa": { - "language": 190 - }, - "aab": { - "language": 191 - }, - "aac": { - "language": 192 - }, - "aad": { - "language": 193 - }, - "aae": { - "language": 194 - }, - "aaf": { - "language": 195 - }, - "aag": { - "language": 196 - }, - "aah": { - "language": 197 - }, - "aai": { - "language": 198 - }, - "aak": { - "language": 199 - }, - "aal": { - "language": 200 - }, - "aam": { - "language": 201 - }, - "aan": { - "language": 202 - }, - "aao": { - "language": 203, - "extlang": 8240 - }, - "aap": { - "language": 204 - }, - "aaq": { - "language": 205 - }, - "aas": { - "language": 206 - }, - "aat": { - "language": 207 - }, - "aau": { - "language": 208 - }, - "aav": { - "language": 209 - }, - "aaw": { - "language": 210 - }, - "aax": { - "language": 211 - }, - "aaz": { - "language": 212 - }, - "aba": { - "language": 213 - }, - "abb": { - "language": 214 - }, - "abc": { - "language": 215 - }, - "abd": { - "language": 216 - }, - "abe": { - "language": 217 - }, - "abf": { - "language": 218 - }, - "abg": { - "language": 219 - }, - "abh": { - "language": 220, - "extlang": 8241 - }, - "abi": { - "language": 221 - }, - "abj": { - "language": 222 - }, - "abl": { - "language": 223 - }, - "abm": { - "language": 224 - }, - "abn": { - "language": 225 - }, - "abo": { - "language": 226 - }, - "abp": { - "language": 227 - }, - "abq": { - "language": 228 - }, - "abr": { - "language": 229 - }, - "abs": { - "language": 230 - }, - "abt": { - "language": 231 - }, - "abu": { - "language": 232 - }, - "abv": { - "language": 233, - "extlang": 8242 - }, - "abw": { - "language": 234 - }, - "abx": { - "language": 235 - }, - "aby": { - "language": 236 - }, - "abz": { - "language": 237 - }, - "aca": { - "language": 238 - }, - "acb": { - "language": 239 - }, - "acd": { - "language": 240 - }, - "ace": { - "language": 241 - }, - "acf": { - "language": 242 - }, - "ach": { - "language": 243 - }, - "aci": { - "language": 244 - }, - "ack": { - "language": 245 - }, - "acl": { - "language": 246 - }, - "acm": { - "language": 247, - "extlang": 8243 - }, - "acn": { - "language": 248 - }, - "acp": { - "language": 249 - }, - "acq": { - "language": 250, - "extlang": 8244 - }, - "acr": { - "language": 251 - }, - "acs": { - "language": 252 - }, - "act": { - "language": 253 - }, - "acu": { - "language": 254 - }, - "acv": { - "language": 255 - }, - "acw": { - "language": 256, - "extlang": 8245 - }, - "acx": { - "language": 257, - "extlang": 8246 - }, - "acy": { - "language": 258, - "extlang": 8247 - }, - "acz": { - "language": 259 - }, - "ada": { - "language": 260 - }, - "adb": { - "language": 261 - }, - "add": { - "language": 262 - }, - "ade": { - "language": 263 - }, - "adf": { - "language": 264, - "extlang": 8248 - }, - "adg": { - "language": 265 - }, - "adh": { - "language": 266 - }, - "adi": { - "language": 267 - }, - "adj": { - "language": 268 - }, - "adl": { - "language": 269 - }, - "adn": { - "language": 270 - }, - "ado": { - "language": 271 - }, - "adp": { - "language": 272 - }, - "adq": { - "language": 273 - }, - "adr": { - "language": 274 - }, - "ads": { - "language": 275, - "extlang": 8249 - }, - "adt": { - "language": 276 - }, - "adu": { - "language": 277 - }, - "adw": { - "language": 278 - }, - "adx": { - "language": 279 - }, - "ady": { - "language": 280 - }, - "adz": { - "language": 281 - }, - "aea": { - "language": 282 - }, - "aeb": { - "language": 283, - "extlang": 8250 - }, - "aec": { - "language": 284, - "extlang": 8251 - }, - "aed": { - "language": 285, - "extlang": 8252 - }, - "aee": { - "language": 286 - }, - "aek": { - "language": 287 - }, - "ael": { - "language": 288 - }, - "aem": { - "language": 289 - }, - "aen": { - "language": 290, - "extlang": 8253 - }, - "aeq": { - "language": 291 - }, - "aer": { - "language": 292 - }, - "aes": { - "language": 293 - }, - "aeu": { - "language": 294 - }, - "aew": { - "language": 295 - }, - "aey": { - "language": 296 - }, - "aez": { - "language": 297 - }, - "afa": { - "language": 298 - }, - "afb": { - "language": 299, - "extlang": 8254 - }, - "afd": { - "language": 300 - }, - "afe": { - "language": 301 - }, - "afg": { - "language": 302, - "extlang": 8255 - }, - "afh": { - "language": 303 - }, - "afi": { - "language": 304 - }, - "afk": { - "language": 305 - }, - "afn": { - "language": 306 - }, - "afo": { - "language": 307 - }, - "afp": { - "language": 308 - }, - "afs": { - "language": 309 - }, - "aft": { - "language": 310 - }, - "afu": { - "language": 311 - }, - "afz": { - "language": 312 - }, - "aga": { - "language": 313 - }, - "agb": { - "language": 314 - }, - "agc": { - "language": 315 - }, - "agd": { - "language": 316 - }, - "age": { - "language": 317 - }, - "agf": { - "language": 318 - }, - "agg": { - "language": 319 - }, - "agh": { - "language": 320 - }, - "agi": { - "language": 321 - }, - "agj": { - "language": 322 - }, - "agk": { - "language": 323 - }, - "agl": { - "language": 324 - }, - "agm": { - "language": 325 - }, - "agn": { - "language": 326 - }, - "ago": { - "language": 327 - }, - "agp": { - "language": 328 - }, - "agq": { - "language": 329 - }, - "agr": { - "language": 330 - }, - "ags": { - "language": 331 - }, - "agt": { - "language": 332 - }, - "agu": { - "language": 333 - }, - "agv": { - "language": 334 - }, - "agw": { - "language": 335 - }, - "agx": { - "language": 336 - }, - "agy": { - "language": 337 - }, - "agz": { - "language": 338 - }, - "aha": { - "language": 339 - }, - "ahb": { - "language": 340 - }, - "ahg": { - "language": 341 - }, - "ahh": { - "language": 342 - }, - "ahi": { - "language": 343 - }, - "ahk": { - "language": 344 - }, - "ahl": { - "language": 345 - }, - "ahm": { - "language": 346 - }, - "ahn": { - "language": 347 - }, - "aho": { - "language": 348 - }, - "ahp": { - "language": 349 - }, - "ahr": { - "language": 350 - }, - "ahs": { - "language": 351 - }, - "aht": { - "language": 352 - }, - "aia": { - "language": 353 - }, - "aib": { - "language": 354 - }, - "aic": { - "language": 355 - }, - "aid": { - "language": 356 - }, - "aie": { - "language": 357 - }, - "aif": { - "language": 358 - }, - "aig": { - "language": 359 - }, - "aih": { - "language": 360 - }, - "aii": { - "language": 361 - }, - "aij": { - "language": 362 - }, - "aik": { - "language": 363 - }, - "ail": { - "language": 364 - }, - "aim": { - "language": 365 - }, - "ain": { - "language": 366 - }, - "aio": { - "language": 367 - }, - "aip": { - "language": 368 - }, - "aiq": { - "language": 369 - }, - "air": { - "language": 370 - }, - "ais": { - "language": 371 - }, - "ait": { - "language": 372 - }, - "aiw": { - "language": 373 - }, - "aix": { - "language": 374 - }, - "aiy": { - "language": 375 - }, - "aja": { - "language": 376 - }, - "ajg": { - "language": 377 - }, - "aji": { - "language": 378 - }, - "ajn": { - "language": 379 - }, - "ajp": { - "language": 380, - "extlang": 8256 - }, - "ajs": { - "language": 381, - "extlang": 8257 - }, - "ajt": { - "language": 382 - }, - "aju": { - "language": 383 - }, - "ajw": { - "language": 384 - }, - "ajz": { - "language": 385 - }, - "akb": { - "language": 386 - }, - "akc": { - "language": 387 - }, - "akd": { - "language": 388 - }, - "ake": { - "language": 389 - }, - "akf": { - "language": 390 - }, - "akg": { - "language": 391 - }, - "akh": { - "language": 392 - }, - "aki": { - "language": 393 - }, - "akj": { - "language": 394 - }, - "akk": { - "language": 395 - }, - "akl": { - "language": 396 - }, - "akm": { - "language": 397 - }, - "ako": { - "language": 398 - }, - "akp": { - "language": 399 - }, - "akq": { - "language": 400 - }, - "akr": { - "language": 401 - }, - "aks": { - "language": 402 - }, - "akt": { - "language": 403 - }, - "aku": { - "language": 404 - }, - "akv": { - "language": 405 - }, - "akw": { - "language": 406 - }, - "akx": { - "language": 407 - }, - "aky": { - "language": 408 - }, - "akz": { - "language": 409 - }, - "ala": { - "language": 410 - }, - "alc": { - "language": 411 - }, - "ald": { - "language": 412 - }, - "ale": { - "language": 413 - }, - "alf": { - "language": 414 - }, - "alg": { - "language": 415 - }, - "alh": { - "language": 416 - }, - "ali": { - "language": 417 - }, - "alj": { - "language": 418 - }, - "alk": { - "language": 419 - }, - "all": { - "language": 420 - }, - "alm": { - "language": 421 - }, - "aln": { - "language": 422 - }, - "alo": { - "language": 423 - }, - "alp": { - "language": 424 - }, - "alq": { - "language": 425 - }, - "alr": { - "language": 426 - }, - "als": { - "language": 427 - }, - "alt": { - "language": 428 - }, - "alu": { - "language": 429 - }, - "alv": { - "language": 430 - }, - "alw": { - "language": 431 - }, - "alx": { - "language": 432 - }, - "aly": { - "language": 433 - }, - "alz": { - "language": 434 - }, - "ama": { - "language": 435 - }, - "amb": { - "language": 436 - }, - "amc": { - "language": 437 - }, - "ame": { - "language": 438 - }, - "amf": { - "language": 439 - }, - "amg": { - "language": 440 - }, - "ami": { - "language": 441 - }, - "amj": { - "language": 442 - }, - "amk": { - "language": 443 - }, - "aml": { - "language": 444 - }, - "amm": { - "language": 445 - }, - "amn": { - "language": 446 - }, - "amo": { - "language": 447 - }, - "amp": { - "language": 448 - }, - "amq": { - "language": 449 - }, - "amr": { - "language": 450 - }, - "ams": { - "language": 451 - }, - "amt": { - "language": 452 - }, - "amu": { - "language": 453 - }, - "amv": { - "language": 454 - }, - "amw": { - "language": 455 - }, - "amx": { - "language": 456 - }, - "amy": { - "language": 457 - }, - "amz": { - "language": 458 - }, - "ana": { - "language": 459 - }, - "anb": { - "language": 460 - }, - "anc": { - "language": 461 - }, - "and": { - "language": 462 - }, - "ane": { - "language": 463 - }, - "anf": { - "language": 464 - }, - "ang": { - "language": 465 - }, - "anh": { - "language": 466 - }, - "ani": { - "language": 467 - }, - "anj": { - "language": 468 - }, - "ank": { - "language": 469 - }, - "anl": { - "language": 470 - }, - "anm": { - "language": 471 - }, - "ann": { - "language": 472 - }, - "ano": { - "language": 473 - }, - "anp": { - "language": 474 - }, - "anq": { - "language": 475 - }, - "anr": { - "language": 476 - }, - "ans": { - "language": 477 - }, - "ant": { - "language": 478 - }, - "anu": { - "language": 479 - }, - "anv": { - "language": 480 - }, - "anw": { - "language": 481 - }, - "anx": { - "language": 482 - }, - "any": { - "language": 483 - }, - "anz": { - "language": 484 - }, - "aoa": { - "language": 485 - }, - "aob": { - "language": 486 - }, - "aoc": { - "language": 487 - }, - "aod": { - "language": 488 - }, - "aoe": { - "language": 489 - }, - "aof": { - "language": 490 - }, - "aog": { - "language": 491 - }, - "aoh": { - "language": 492 - }, - "aoi": { - "language": 493 - }, - "aoj": { - "language": 494 - }, - "aok": { - "language": 495 - }, - "aol": { - "language": 496 - }, - "aom": { - "language": 497 - }, - "aon": { - "language": 498 - }, - "aor": { - "language": 499 - }, - "aos": { - "language": 500 - }, - "aot": { - "language": 501 - }, - "aou": { - "language": 502 - }, - "aox": { - "language": 503 - }, - "aoz": { - "language": 504 - }, - "apa": { - "language": 505 - }, - "apb": { - "language": 506 - }, - "apc": { - "language": 507, - "extlang": 8258 - }, - "apd": { - "language": 508, - "extlang": 8259 - }, - "ape": { - "language": 509 - }, - "apf": { - "language": 510 - }, - "apg": { - "language": 511 - }, - "aph": { - "language": 512 - }, - "api": { - "language": 513 - }, - "apj": { - "language": 514 - }, - "apk": { - "language": 515 - }, - "apl": { - "language": 516 - }, - "apm": { - "language": 517 - }, - "apn": { - "language": 518 - }, - "apo": { - "language": 519 - }, - "app": { - "language": 520 - }, - "apq": { - "language": 521 - }, - "apr": { - "language": 522 - }, - "aps": { - "language": 523 - }, - "apt": { - "language": 524 - }, - "apu": { - "language": 525 - }, - "apv": { - "language": 526 - }, - "apw": { - "language": 527 - }, - "apx": { - "language": 528 - }, - "apy": { - "language": 529 - }, - "apz": { - "language": 530 - }, - "aqa": { - "language": 531 - }, - "aqc": { - "language": 532 - }, - "aqd": { - "language": 533 - }, - "aqg": { - "language": 534 - }, - "aqk": { - "language": 535 - }, - "aql": { - "language": 536 - }, - "aqm": { - "language": 537 - }, - "aqn": { - "language": 538 - }, - "aqp": { - "language": 539 - }, - "aqr": { - "language": 540 - }, - "aqt": { - "language": 541 - }, - "aqz": { - "language": 542 - }, - "arb": { - "language": 543, - "extlang": 8260 - }, - "arc": { - "language": 544 - }, - "ard": { - "language": 545 - }, - "are": { - "language": 546 - }, - "arh": { - "language": 547 - }, - "ari": { - "language": 548 - }, - "arj": { - "language": 549 - }, - "ark": { - "language": 550 - }, - "arl": { - "language": 551 - }, - "arn": { - "language": 552 - }, - "aro": { - "language": 553 - }, - "arp": { - "language": 554 - }, - "arq": { - "language": 555, - "extlang": 8261 - }, - "arr": { - "language": 556 - }, - "ars": { - "language": 557, - "extlang": 8262 - }, - "art": { - "language": 558 - }, - "aru": { - "language": 559 - }, - "arv": { - "language": 560 - }, - "arw": { - "language": 561 - }, - "arx": { - "language": 562 - }, - "ary": { - "language": 563, - "extlang": 8263 - }, - "arz": { - "language": 564, - "extlang": 8264 - }, - "asa": { - "language": 565 - }, - "asb": { - "language": 566 - }, - "asc": { - "language": 567 - }, - "asd": { - "language": 568 - }, - "ase": { - "language": 569, - "extlang": 8265 - }, - "asf": { - "language": 570, - "extlang": 8266 - }, - "asg": { - "language": 571 - }, - "ash": { - "language": 572 - }, - "asi": { - "language": 573 - }, - "asj": { - "language": 574 - }, - "ask": { - "language": 575 - }, - "asl": { - "language": 576 - }, - "asn": { - "language": 577 - }, - "aso": { - "language": 578 - }, - "asp": { - "language": 579, - "extlang": 8267 - }, - "asq": { - "language": 580, - "extlang": 8268 - }, - "asr": { - "language": 581 - }, - "ass": { - "language": 582 - }, - "ast": { - "language": 583 - }, - "asu": { - "language": 584 - }, - "asv": { - "language": 585 - }, - "asw": { - "language": 586, - "extlang": 8269 - }, - "asx": { - "language": 587 - }, - "asy": { - "language": 588 - }, - "asz": { - "language": 589 - }, - "ata": { - "language": 590 - }, - "atb": { - "language": 591 - }, - "atc": { - "language": 592 - }, - "atd": { - "language": 593 - }, - "ate": { - "language": 594 - }, - "atg": { - "language": 595 - }, - "ath": { - "language": 596 - }, - "ati": { - "language": 597 - }, - "atj": { - "language": 598 - }, - "atk": { - "language": 599 - }, - "atl": { - "language": 600 - }, - "atm": { - "language": 601 - }, - "atn": { - "language": 602 - }, - "ato": { - "language": 603 - }, - "atp": { - "language": 604 - }, - "atq": { - "language": 605 - }, - "atr": { - "language": 606 - }, - "ats": { - "language": 607 - }, - "att": { - "language": 608 - }, - "atu": { - "language": 609 - }, - "atv": { - "language": 610 - }, - "atw": { - "language": 611 - }, - "atx": { - "language": 612 - }, - "aty": { - "language": 613 - }, - "atz": { - "language": 614 - }, - "aua": { - "language": 615 - }, - "aub": { - "language": 616 - }, - "auc": { - "language": 617 - }, - "aud": { - "language": 618 - }, - "aue": { - "language": 619 - }, - "auf": { - "language": 620 - }, - "aug": { - "language": 621 - }, - "auh": { - "language": 622 - }, - "aui": { - "language": 623 - }, - "auj": { - "language": 624 - }, - "auk": { - "language": 625 - }, - "aul": { - "language": 626 - }, - "aum": { - "language": 627 - }, - "aun": { - "language": 628 - }, - "auo": { - "language": 629 - }, - "aup": { - "language": 630 - }, - "auq": { - "language": 631 - }, - "aur": { - "language": 632 - }, - "aus": { - "language": 633 - }, - "aut": { - "language": 634 - }, - "auu": { - "language": 635 - }, - "auw": { - "language": 636 - }, - "aux": { - "language": 637 - }, - "auy": { - "language": 638 - }, - "auz": { - "language": 639, - "extlang": 8270 - }, - "avb": { - "language": 640 - }, - "avd": { - "language": 641 - }, - "avi": { - "language": 642 - }, - "avk": { - "language": 643 - }, - "avl": { - "language": 644, - "extlang": 8271 - }, - "avm": { - "language": 645 - }, - "avn": { - "language": 646 - }, - "avo": { - "language": 647 - }, - "avs": { - "language": 648 - }, - "avt": { - "language": 649 - }, - "avu": { - "language": 650 - }, - "avv": { - "language": 651 - }, - "awa": { - "language": 652 - }, - "awb": { - "language": 653 - }, - "awc": { - "language": 654 - }, - "awd": { - "language": 655 - }, - "awe": { - "language": 656 - }, - "awg": { - "language": 657 - }, - "awh": { - "language": 658 - }, - "awi": { - "language": 659 - }, - "awk": { - "language": 660 - }, - "awm": { - "language": 661 - }, - "awn": { - "language": 662 - }, - "awo": { - "language": 663 - }, - "awr": { - "language": 664 - }, - "aws": { - "language": 665 - }, - "awt": { - "language": 666 - }, - "awu": { - "language": 667 - }, - "awv": { - "language": 668 - }, - "aww": { - "language": 669 - }, - "awx": { - "language": 670 - }, - "awy": { - "language": 671 - }, - "axb": { - "language": 672 - }, - "axe": { - "language": 673 - }, - "axg": { - "language": 674 - }, - "axk": { - "language": 675 - }, - "axl": { - "language": 676 - }, - "axm": { - "language": 677 - }, - "axx": { - "language": 678 - }, - "aya": { - "language": 679 - }, - "ayb": { - "language": 680 - }, - "ayc": { - "language": 681 - }, - "ayd": { - "language": 682 - }, - "aye": { - "language": 683 - }, - "ayg": { - "language": 684 - }, - "ayh": { - "language": 685, - "extlang": 8272 - }, - "ayi": { - "language": 686 - }, - "ayk": { - "language": 687 - }, - "ayl": { - "language": 688, - "extlang": 8273 - }, - "ayn": { - "language": 689, - "extlang": 8274 - }, - "ayo": { - "language": 690 - }, - "ayp": { - "language": 691, - "extlang": 8275 - }, - "ayq": { - "language": 692 - }, - "ayr": { - "language": 693 - }, - "ays": { - "language": 694 - }, - "ayt": { - "language": 695 - }, - "ayu": { - "language": 696 - }, - "ayx": { - "language": 697 - }, - "ayy": { - "language": 698 - }, - "ayz": { - "language": 699 - }, - "aza": { - "language": 700 - }, - "azb": { - "language": 701 - }, - "azc": { - "language": 702 - }, - "azd": { - "language": 703 - }, - "azg": { - "language": 704 - }, - "azj": { - "language": 705 - }, - "azm": { - "language": 706 - }, - "azn": { - "language": 707 - }, - "azo": { - "language": 708 - }, - "azt": { - "language": 709 - }, - "azz": { - "language": 710 - }, - "baa": { - "language": 711 - }, - "bab": { - "language": 712 - }, - "bac": { - "language": 713 - }, - "bad": { - "language": 714 - }, - "bae": { - "language": 715 - }, - "baf": { - "language": 716 - }, - "bag": { - "language": 717 - }, - "bah": { - "language": 718 - }, - "bai": { - "language": 719 - }, - "baj": { - "language": 720 - }, - "bal": { - "language": 721 - }, - "ban": { - "language": 722 - }, - "bao": { - "language": 723 - }, - "bap": { - "language": 724 - }, - "bar": { - "language": 725 - }, - "bas": { - "language": 726 - }, - "bat": { - "language": 727 - }, - "bau": { - "language": 728 - }, - "bav": { - "language": 729 - }, - "baw": { - "language": 730 - }, - "bax": { - "language": 731 - }, - "bay": { - "language": 732 - }, - "baz": { - "language": 733 - }, - "bba": { - "language": 734 - }, - "bbb": { - "language": 735 - }, - "bbc": { - "language": 736 - }, - "bbd": { - "language": 737 - }, - "bbe": { - "language": 738 - }, - "bbf": { - "language": 739 - }, - "bbg": { - "language": 740 - }, - "bbh": { - "language": 741 - }, - "bbi": { - "language": 742 - }, - "bbj": { - "language": 743 - }, - "bbk": { - "language": 744 - }, - "bbl": { - "language": 745 - }, - "bbm": { - "language": 746 - }, - "bbn": { - "language": 747 - }, - "bbo": { - "language": 748 - }, - "bbp": { - "language": 749 - }, - "bbq": { - "language": 750 - }, - "bbr": { - "language": 751 - }, - "bbs": { - "language": 752 - }, - "bbt": { - "language": 753 - }, - "bbu": { - "language": 754 - }, - "bbv": { - "language": 755 - }, - "bbw": { - "language": 756 - }, - "bbx": { - "language": 757 - }, - "bby": { - "language": 758 - }, - "bbz": { - "language": 759, - "extlang": 8276 - }, - "bca": { - "language": 760 - }, - "bcb": { - "language": 761 - }, - "bcc": { - "language": 762 - }, - "bcd": { - "language": 763 - }, - "bce": { - "language": 764 - }, - "bcf": { - "language": 765 - }, - "bcg": { - "language": 766 - }, - "bch": { - "language": 767 - }, - "bci": { - "language": 768 - }, - "bcj": { - "language": 769 - }, - "bck": { - "language": 770 - }, - "bcl": { - "language": 771 - }, - "bcm": { - "language": 772 - }, - "bcn": { - "language": 773 - }, - "bco": { - "language": 774 - }, - "bcp": { - "language": 775 - }, - "bcq": { - "language": 776 - }, - "bcr": { - "language": 777 - }, - "bcs": { - "language": 778 - }, - "bct": { - "language": 779 - }, - "bcu": { - "language": 780 - }, - "bcv": { - "language": 781 - }, - "bcw": { - "language": 782 - }, - "bcy": { - "language": 783 - }, - "bcz": { - "language": 784 - }, - "bda": { - "language": 785 - }, - "bdb": { - "language": 786 - }, - "bdc": { - "language": 787 - }, - "bdd": { - "language": 788 - }, - "bde": { - "language": 789 - }, - "bdf": { - "language": 790 - }, - "bdg": { - "language": 791 - }, - "bdh": { - "language": 792 - }, - "bdi": { - "language": 793 - }, - "bdj": { - "language": 794 - }, - "bdk": { - "language": 795 - }, - "bdl": { - "language": 796 - }, - "bdm": { - "language": 797 - }, - "bdn": { - "language": 798 - }, - "bdo": { - "language": 799 - }, - "bdp": { - "language": 800 - }, - "bdq": { - "language": 801 - }, - "bdr": { - "language": 802 - }, - "bds": { - "language": 803 - }, - "bdt": { - "language": 804 - }, - "bdu": { - "language": 805 - }, - "bdv": { - "language": 806 - }, - "bdw": { - "language": 807 - }, - "bdx": { - "language": 808 - }, - "bdy": { - "language": 809 - }, - "bdz": { - "language": 810 - }, - "bea": { - "language": 811 - }, - "beb": { - "language": 812 - }, - "bec": { - "language": 813 - }, - "bed": { - "language": 814 - }, - "bee": { - "language": 815 - }, - "bef": { - "language": 816 - }, - "beg": { - "language": 817 - }, - "beh": { - "language": 818 - }, - "bei": { - "language": 819 - }, - "bej": { - "language": 820 - }, - "bek": { - "language": 821 - }, - "bem": { - "language": 822 - }, - "beo": { - "language": 823 - }, - "bep": { - "language": 824 - }, - "beq": { - "language": 825 - }, - "ber": { - "language": 826 - }, - "bes": { - "language": 827 - }, - "bet": { - "language": 828 - }, - "beu": { - "language": 829 - }, - "bev": { - "language": 830 - }, - "bew": { - "language": 831 - }, - "bex": { - "language": 832 - }, - "bey": { - "language": 833 - }, - "bez": { - "language": 834 - }, - "bfa": { - "language": 835 - }, - "bfb": { - "language": 836 - }, - "bfc": { - "language": 837 - }, - "bfd": { - "language": 838 - }, - "bfe": { - "language": 839 - }, - "bff": { - "language": 840 - }, - "bfg": { - "language": 841 - }, - "bfh": { - "language": 842 - }, - "bfi": { - "language": 843, - "extlang": 8277 - }, - "bfj": { - "language": 844 - }, - "bfk": { - "language": 845, - "extlang": 8278 - }, - "bfl": { - "language": 846 - }, - "bfm": { - "language": 847 - }, - "bfn": { - "language": 848 - }, - "bfo": { - "language": 849 - }, - "bfp": { - "language": 850 - }, - "bfq": { - "language": 851 - }, - "bfr": { - "language": 852 - }, - "bfs": { - "language": 853 - }, - "bft": { - "language": 854 - }, - "bfu": { - "language": 855 - }, - "bfw": { - "language": 856 - }, - "bfx": { - "language": 857 - }, - "bfy": { - "language": 858 - }, - "bfz": { - "language": 859 - }, - "bga": { - "language": 860 - }, - "bgb": { - "language": 861 - }, - "bgc": { - "language": 862 - }, - "bgd": { - "language": 863 - }, - "bge": { - "language": 864 - }, - "bgf": { - "language": 865 - }, - "bgg": { - "language": 866 - }, - "bgi": { - "language": 867 - }, - "bgj": { - "language": 868 - }, - "bgk": { - "language": 869 - }, - "bgl": { - "language": 870 - }, - "bgm": { - "language": 871 - }, - "bgn": { - "language": 872 - }, - "bgo": { - "language": 873 - }, - "bgp": { - "language": 874 - }, - "bgq": { - "language": 875 - }, - "bgr": { - "language": 876 - }, - "bgs": { - "language": 877 - }, - "bgt": { - "language": 878 - }, - "bgu": { - "language": 879 - }, - "bgv": { - "language": 880 - }, - "bgw": { - "language": 881 - }, - "bgx": { - "language": 882 - }, - "bgy": { - "language": 883 - }, - "bgz": { - "language": 884 - }, - "bha": { - "language": 885 - }, - "bhb": { - "language": 886 - }, - "bhc": { - "language": 887 - }, - "bhd": { - "language": 888 - }, - "bhe": { - "language": 889 - }, - "bhf": { - "language": 890 - }, - "bhg": { - "language": 891 - }, - "bhh": { - "language": 892 - }, - "bhi": { - "language": 893 - }, - "bhj": { - "language": 894 - }, - "bhk": { - "language": 895 - }, - "bhl": { - "language": 896 - }, - "bhm": { - "language": 897 - }, - "bhn": { - "language": 898 - }, - "bho": { - "language": 899 - }, - "bhp": { - "language": 900 - }, - "bhq": { - "language": 901 - }, - "bhr": { - "language": 902 - }, - "bhs": { - "language": 903 - }, - "bht": { - "language": 904 - }, - "bhu": { - "language": 905 - }, - "bhv": { - "language": 906 - }, - "bhw": { - "language": 907 - }, - "bhx": { - "language": 908 - }, - "bhy": { - "language": 909 - }, - "bhz": { - "language": 910 - }, - "bia": { - "language": 911 - }, - "bib": { - "language": 912 - }, - "bic": { - "language": 913 - }, - "bid": { - "language": 914 - }, - "bie": { - "language": 915 - }, - "bif": { - "language": 916 - }, - "big": { - "language": 917 - }, - "bij": { - "language": 918 - }, - "bik": { - "language": 919 - }, - "bil": { - "language": 920 - }, - "bim": { - "language": 921 - }, - "bin": { - "language": 922 - }, - "bio": { - "language": 923 - }, - "bip": { - "language": 924 - }, - "biq": { - "language": 925 - }, - "bir": { - "language": 926 - }, - "bit": { - "language": 927 - }, - "biu": { - "language": 928 - }, - "biv": { - "language": 929 - }, - "biw": { - "language": 930 - }, - "bix": { - "language": 931 - }, - "biy": { - "language": 932 - }, - "biz": { - "language": 933 - }, - "bja": { - "language": 934 - }, - "bjb": { - "language": 935 - }, - "bjc": { - "language": 936 - }, - "bjd": { - "language": 937 - }, - "bje": { - "language": 938 - }, - "bjf": { - "language": 939 - }, - "bjg": { - "language": 940 - }, - "bjh": { - "language": 941 - }, - "bji": { - "language": 942 - }, - "bjj": { - "language": 943 - }, - "bjk": { - "language": 944 - }, - "bjl": { - "language": 945 - }, - "bjm": { - "language": 946 - }, - "bjn": { - "language": 947, - "extlang": 8279 - }, - "bjo": { - "language": 948 - }, - "bjp": { - "language": 949 - }, - "bjq": { - "language": 950 - }, - "bjr": { - "language": 951 - }, - "bjs": { - "language": 952 - }, - "bjt": { - "language": 953 - }, - "bju": { - "language": 954 - }, - "bjv": { - "language": 955 - }, - "bjw": { - "language": 956 - }, - "bjx": { - "language": 957 - }, - "bjy": { - "language": 958 - }, - "bjz": { - "language": 959 - }, - "bka": { - "language": 960 - }, - "bkb": { - "language": 961 - }, - "bkc": { - "language": 962 - }, - "bkd": { - "language": 963 - }, - "bkf": { - "language": 964 - }, - "bkg": { - "language": 965 - }, - "bkh": { - "language": 966 - }, - "bki": { - "language": 967 - }, - "bkj": { - "language": 968 - }, - "bkk": { - "language": 969 - }, - "bkl": { - "language": 970 - }, - "bkm": { - "language": 971 - }, - "bkn": { - "language": 972 - }, - "bko": { - "language": 973 - }, - "bkp": { - "language": 974 - }, - "bkq": { - "language": 975 - }, - "bkr": { - "language": 976 - }, - "bks": { - "language": 977 - }, - "bkt": { - "language": 978 - }, - "bku": { - "language": 979 - }, - "bkv": { - "language": 980 - }, - "bkw": { - "language": 981 - }, - "bkx": { - "language": 982 - }, - "bky": { - "language": 983 - }, - "bkz": { - "language": 984 - }, - "bla": { - "language": 985 - }, - "blb": { - "language": 986 - }, - "blc": { - "language": 987 - }, - "bld": { - "language": 988 - }, - "ble": { - "language": 989 - }, - "blf": { - "language": 990 - }, - "blg": { - "language": 991 - }, - "blh": { - "language": 992 - }, - "bli": { - "language": 993 - }, - "blj": { - "language": 994 - }, - "blk": { - "language": 995 - }, - "bll": { - "language": 996 - }, - "blm": { - "language": 997 - }, - "bln": { - "language": 998 - }, - "blo": { - "language": 999 - }, - "blp": { - "language": 1000 - }, - "blq": { - "language": 1001 - }, - "blr": { - "language": 1002 - }, - "bls": { - "language": 1003 - }, - "blt": { - "language": 1004 - }, - "blv": { - "language": 1005 - }, - "blw": { - "language": 1006 - }, - "blx": { - "language": 1007 - }, - "bly": { - "language": 1008 - }, - "blz": { - "language": 1009 - }, - "bma": { - "language": 1010 - }, - "bmb": { - "language": 1011 - }, - "bmc": { - "language": 1012 - }, - "bmd": { - "language": 1013 - }, - "bme": { - "language": 1014 - }, - "bmf": { - "language": 1015 - }, - "bmg": { - "language": 1016 - }, - "bmh": { - "language": 1017 - }, - "bmi": { - "language": 1018 - }, - "bmj": { - "language": 1019 - }, - "bmk": { - "language": 1020 - }, - "bml": { - "language": 1021 - }, - "bmm": { - "language": 1022 - }, - "bmn": { - "language": 1023 - }, - "bmo": { - "language": 1024 - }, - "bmp": { - "language": 1025 - }, - "bmq": { - "language": 1026 - }, - "bmr": { - "language": 1027 - }, - "bms": { - "language": 1028 - }, - "bmt": { - "language": 1029 - }, - "bmu": { - "language": 1030 - }, - "bmv": { - "language": 1031 - }, - "bmw": { - "language": 1032 - }, - "bmx": { - "language": 1033 - }, - "bmy": { - "language": 1034 - }, - "bmz": { - "language": 1035 - }, - "bna": { - "language": 1036 - }, - "bnb": { - "language": 1037 - }, - "bnc": { - "language": 1038 - }, - "bnd": { - "language": 1039 - }, - "bne": { - "language": 1040 - }, - "bnf": { - "language": 1041 - }, - "bng": { - "language": 1042 - }, - "bni": { - "language": 1043 - }, - "bnj": { - "language": 1044 - }, - "bnk": { - "language": 1045 - }, - "bnl": { - "language": 1046 - }, - "bnm": { - "language": 1047 - }, - "bnn": { - "language": 1048 - }, - "bno": { - "language": 1049 - }, - "bnp": { - "language": 1050 - }, - "bnq": { - "language": 1051 - }, - "bnr": { - "language": 1052 - }, - "bns": { - "language": 1053 - }, - "bnt": { - "language": 1054 - }, - "bnu": { - "language": 1055 - }, - "bnv": { - "language": 1056 - }, - "bnw": { - "language": 1057 - }, - "bnx": { - "language": 1058 - }, - "bny": { - "language": 1059 - }, - "bnz": { - "language": 1060 - }, - "boa": { - "language": 1061 - }, - "bob": { - "language": 1062 - }, - "boe": { - "language": 1063 - }, - "bof": { - "language": 1064 - }, - "bog": { - "language": 1065, - "extlang": 8280 - }, - "boh": { - "language": 1066 - }, - "boi": { - "language": 1067 - }, - "boj": { - "language": 1068 - }, - "bok": { - "language": 1069 - }, - "bol": { - "language": 1070 - }, - "bom": { - "language": 1071 - }, - "bon": { - "language": 1072 - }, - "boo": { - "language": 1073 - }, - "bop": { - "language": 1074 - }, - "boq": { - "language": 1075 - }, - "bor": { - "language": 1076 - }, - "bot": { - "language": 1077 - }, - "bou": { - "language": 1078 - }, - "bov": { - "language": 1079 - }, - "bow": { - "language": 1080 - }, - "box": { - "language": 1081 - }, - "boy": { - "language": 1082 - }, - "boz": { - "language": 1083 - }, - "bpa": { - "language": 1084 - }, - "bpb": { - "language": 1085 - }, - "bpc": { - "language": 1086 - }, - "bpd": { - "language": 1087 - }, - "bpe": { - "language": 1088 - }, - "bpg": { - "language": 1089 - }, - "bph": { - "language": 1090 - }, - "bpi": { - "language": 1091 - }, - "bpj": { - "language": 1092 - }, - "bpk": { - "language": 1093 - }, - "bpl": { - "language": 1094 - }, - "bpm": { - "language": 1095 - }, - "bpn": { - "language": 1096 - }, - "bpo": { - "language": 1097 - }, - "bpp": { - "language": 1098 - }, - "bpq": { - "language": 1099 - }, - "bpr": { - "language": 1100 - }, - "bps": { - "language": 1101 - }, - "bpt": { - "language": 1102 - }, - "bpu": { - "language": 1103 - }, - "bpv": { - "language": 1104 - }, - "bpw": { - "language": 1105 - }, - "bpx": { - "language": 1106 - }, - "bpy": { - "language": 1107 - }, - "bpz": { - "language": 1108 - }, - "bqa": { - "language": 1109 - }, - "bqb": { - "language": 1110 - }, - "bqc": { - "language": 1111 - }, - "bqd": { - "language": 1112 - }, - "bqf": { - "language": 1113 - }, - "bqg": { - "language": 1114 - }, - "bqh": { - "language": 1115 - }, - "bqi": { - "language": 1116 - }, - "bqj": { - "language": 1117 - }, - "bqk": { - "language": 1118 - }, - "bql": { - "language": 1119 - }, - "bqm": { - "language": 1120 - }, - "bqn": { - "language": 1121, - "extlang": 8281 - }, - "bqo": { - "language": 1122 - }, - "bqp": { - "language": 1123 - }, - "bqq": { - "language": 1124 - }, - "bqr": { - "language": 1125 - }, - "bqs": { - "language": 1126 - }, - "bqt": { - "language": 1127 - }, - "bqu": { - "language": 1128 - }, - "bqv": { - "language": 1129 - }, - "bqw": { - "language": 1130 - }, - "bqx": { - "language": 1131 - }, - "bqy": { - "language": 1132, - "extlang": 8282 - }, - "bqz": { - "language": 1133 - }, - "bra": { - "language": 1134 - }, - "brb": { - "language": 1135 - }, - "brc": { - "language": 1136 - }, - "brd": { - "language": 1137 - }, - "brf": { - "language": 1138 - }, - "brg": { - "language": 1139 - }, - "brh": { - "language": 1140 - }, - "bri": { - "language": 1141 - }, - "brj": { - "language": 1142 - }, - "brk": { - "language": 1143 - }, - "brl": { - "language": 1144 - }, - "brm": { - "language": 1145 - }, - "brn": { - "language": 1146 - }, - "bro": { - "language": 1147 - }, - "brp": { - "language": 1148 - }, - "brq": { - "language": 1149 - }, - "brr": { - "language": 1150 - }, - "brs": { - "language": 1151 - }, - "brt": { - "language": 1152 - }, - "bru": { - "language": 1153 - }, - "brv": { - "language": 1154 - }, - "brw": { - "language": 1155 - }, - "brx": { - "language": 1156 - }, - "bry": { - "language": 1157 - }, - "brz": { - "language": 1158 - }, - "bsa": { - "language": 1159 - }, - "bsb": { - "language": 1160 - }, - "bsc": { - "language": 1161 - }, - "bse": { - "language": 1162 - }, - "bsf": { - "language": 1163 - }, - "bsg": { - "language": 1164 - }, - "bsh": { - "language": 1165 - }, - "bsi": { - "language": 1166 - }, - "bsj": { - "language": 1167 - }, - "bsk": { - "language": 1168 - }, - "bsl": { - "language": 1169 - }, - "bsm": { - "language": 1170 - }, - "bsn": { - "language": 1171 - }, - "bso": { - "language": 1172 - }, - "bsp": { - "language": 1173 - }, - "bsq": { - "language": 1174 - }, - "bsr": { - "language": 1175 - }, - "bss": { - "language": 1176 - }, - "bst": { - "language": 1177 - }, - "bsu": { - "language": 1178 - }, - "bsv": { - "language": 1179 - }, - "bsw": { - "language": 1180 - }, - "bsx": { - "language": 1181 - }, - "bsy": { - "language": 1182 - }, - "bta": { - "language": 1183 - }, - "btb": { - "language": 1184 - }, - "btc": { - "language": 1185 - }, - "btd": { - "language": 1186 - }, - "bte": { - "language": 1187 - }, - "btf": { - "language": 1188 - }, - "btg": { - "language": 1189 - }, - "bth": { - "language": 1190 - }, - "bti": { - "language": 1191 - }, - "btj": { - "language": 1192, - "extlang": 8283 - }, - "btk": { - "language": 1193 - }, - "btl": { - "language": 1194 - }, - "btm": { - "language": 1195 - }, - "btn": { - "language": 1196 - }, - "bto": { - "language": 1197 - }, - "btp": { - "language": 1198 - }, - "btq": { - "language": 1199 - }, - "btr": { - "language": 1200 - }, - "bts": { - "language": 1201 - }, - "btt": { - "language": 1202 - }, - "btu": { - "language": 1203 - }, - "btv": { - "language": 1204 - }, - "btw": { - "language": 1205 - }, - "btx": { - "language": 1206 - }, - "bty": { - "language": 1207 - }, - "btz": { - "language": 1208 - }, - "bua": { - "language": 1209 - }, - "bub": { - "language": 1210 - }, - "buc": { - "language": 1211 - }, - "bud": { - "language": 1212 - }, - "bue": { - "language": 1213 - }, - "buf": { - "language": 1214 - }, - "bug": { - "language": 1215 - }, - "buh": { - "language": 1216 - }, - "bui": { - "language": 1217 - }, - "buj": { - "language": 1218 - }, - "buk": { - "language": 1219 - }, - "bum": { - "language": 1220 - }, - "bun": { - "language": 1221 - }, - "buo": { - "language": 1222 - }, - "bup": { - "language": 1223 - }, - "buq": { - "language": 1224 - }, - "bus": { - "language": 1225 - }, - "but": { - "language": 1226 - }, - "buu": { - "language": 1227 - }, - "buv": { - "language": 1228 - }, - "buw": { - "language": 1229 - }, - "bux": { - "language": 1230 - }, - "buy": { - "language": 1231 - }, - "buz": { - "language": 1232 - }, - "bva": { - "language": 1233 - }, - "bvb": { - "language": 1234 - }, - "bvc": { - "language": 1235 - }, - "bvd": { - "language": 1236 - }, - "bve": { - "language": 1237, - "extlang": 8284 - }, - "bvf": { - "language": 1238 - }, - "bvg": { - "language": 1239 - }, - "bvh": { - "language": 1240 - }, - "bvi": { - "language": 1241 - }, - "bvj": { - "language": 1242 - }, - "bvk": { - "language": 1243 - }, - "bvl": { - "language": 1244, - "extlang": 8285 - }, - "bvm": { - "language": 1245 - }, - "bvn": { - "language": 1246 - }, - "bvo": { - "language": 1247 - }, - "bvp": { - "language": 1248 - }, - "bvq": { - "language": 1249 - }, - "bvr": { - "language": 1250 - }, - "bvt": { - "language": 1251 - }, - "bvu": { - "language": 1252, - "extlang": 8286 - }, - "bvv": { - "language": 1253 - }, - "bvw": { - "language": 1254 - }, - "bvx": { - "language": 1255 - }, - "bvy": { - "language": 1256 - }, - "bvz": { - "language": 1257 - }, - "bwa": { - "language": 1258 - }, - "bwb": { - "language": 1259 - }, - "bwc": { - "language": 1260 - }, - "bwd": { - "language": 1261 - }, - "bwe": { - "language": 1262 - }, - "bwf": { - "language": 1263 - }, - "bwg": { - "language": 1264 - }, - "bwh": { - "language": 1265 - }, - "bwi": { - "language": 1266 - }, - "bwj": { - "language": 1267 - }, - "bwk": { - "language": 1268 - }, - "bwl": { - "language": 1269 - }, - "bwm": { - "language": 1270 - }, - "bwn": { - "language": 1271 - }, - "bwo": { - "language": 1272 - }, - "bwp": { - "language": 1273 - }, - "bwq": { - "language": 1274 - }, - "bwr": { - "language": 1275 - }, - "bws": { - "language": 1276 - }, - "bwt": { - "language": 1277 - }, - "bwu": { - "language": 1278 - }, - "bww": { - "language": 1279 - }, - "bwx": { - "language": 1280 - }, - "bwy": { - "language": 1281 - }, - "bwz": { - "language": 1282 - }, - "bxa": { - "language": 1283 - }, - "bxb": { - "language": 1284 - }, - "bxc": { - "language": 1285 - }, - "bxd": { - "language": 1286 - }, - "bxe": { - "language": 1287 - }, - "bxf": { - "language": 1288 - }, - "bxg": { - "language": 1289 - }, - "bxh": { - "language": 1290 - }, - "bxi": { - "language": 1291 - }, - "bxj": { - "language": 1292 - }, - "bxk": { - "language": 1293 - }, - "bxl": { - "language": 1294 - }, - "bxm": { - "language": 1295 - }, - "bxn": { - "language": 1296 - }, - "bxo": { - "language": 1297 - }, - "bxp": { - "language": 1298 - }, - "bxq": { - "language": 1299 - }, - "bxr": { - "language": 1300 - }, - "bxs": { - "language": 1301 - }, - "bxu": { - "language": 1302 - }, - "bxv": { - "language": 1303 - }, - "bxw": { - "language": 1304 - }, - "bxx": { - "language": 1305 - }, - "bxz": { - "language": 1306 - }, - "bya": { - "language": 1307 - }, - "byb": { - "language": 1308 - }, - "byc": { - "language": 1309 - }, - "byd": { - "language": 1310 - }, - "bye": { - "language": 1311 - }, - "byf": { - "language": 1312 - }, - "byg": { - "language": 1313 - }, - "byh": { - "language": 1314 - }, - "byi": { - "language": 1315 - }, - "byj": { - "language": 1316 - }, - "byk": { - "language": 1317 - }, - "byl": { - "language": 1318 - }, - "bym": { - "language": 1319 - }, - "byn": { - "language": 1320 - }, - "byo": { - "language": 1321 - }, - "byp": { - "language": 1322 - }, - "byq": { - "language": 1323 - }, - "byr": { - "language": 1324 - }, - "bys": { - "language": 1325 - }, - "byt": { - "language": 1326 - }, - "byv": { - "language": 1327 - }, - "byw": { - "language": 1328 - }, - "byx": { - "language": 1329 - }, - "byy": { - "language": 1330 - }, - "byz": { - "language": 1331 - }, - "bza": { - "language": 1332 - }, - "bzb": { - "language": 1333 - }, - "bzc": { - "language": 1334 - }, - "bzd": { - "language": 1335 - }, - "bze": { - "language": 1336 - }, - "bzf": { - "language": 1337 - }, - "bzg": { - "language": 1338 - }, - "bzh": { - "language": 1339 - }, - "bzi": { - "language": 1340 - }, - "bzj": { - "language": 1341 - }, - "bzk": { - "language": 1342 - }, - "bzl": { - "language": 1343 - }, - "bzm": { - "language": 1344 - }, - "bzn": { - "language": 1345 - }, - "bzo": { - "language": 1346 - }, - "bzp": { - "language": 1347 - }, - "bzq": { - "language": 1348 - }, - "bzr": { - "language": 1349 - }, - "bzs": { - "language": 1350, - "extlang": 8287 - }, - "bzt": { - "language": 1351 - }, - "bzu": { - "language": 1352 - }, - "bzv": { - "language": 1353 - }, - "bzw": { - "language": 1354 - }, - "bzx": { - "language": 1355 - }, - "bzy": { - "language": 1356 - }, - "bzz": { - "language": 1357 - }, - "caa": { - "language": 1358 - }, - "cab": { - "language": 1359 - }, - "cac": { - "language": 1360 - }, - "cad": { - "language": 1361 - }, - "cae": { - "language": 1362 - }, - "caf": { - "language": 1363 - }, - "cag": { - "language": 1364 - }, - "cah": { - "language": 1365 - }, - "cai": { - "language": 1366 - }, - "caj": { - "language": 1367 - }, - "cak": { - "language": 1368 - }, - "cal": { - "language": 1369 - }, - "cam": { - "language": 1370 - }, - "can": { - "language": 1371 - }, - "cao": { - "language": 1372 - }, - "cap": { - "language": 1373 - }, - "caq": { - "language": 1374 - }, - "car": { - "language": 1375 - }, - "cas": { - "language": 1376 - }, - "cau": { - "language": 1377 - }, - "cav": { - "language": 1378 - }, - "caw": { - "language": 1379 - }, - "cax": { - "language": 1380 - }, - "cay": { - "language": 1381 - }, - "caz": { - "language": 1382 - }, - "cba": { - "language": 1383 - }, - "cbb": { - "language": 1384 - }, - "cbc": { - "language": 1385 - }, - "cbd": { - "language": 1386 - }, - "cbe": { - "language": 1387 - }, - "cbg": { - "language": 1388 - }, - "cbh": { - "language": 1389 - }, - "cbi": { - "language": 1390 - }, - "cbj": { - "language": 1391 - }, - "cbk": { - "language": 1392 - }, - "cbl": { - "language": 1393 - }, - "cbn": { - "language": 1394 - }, - "cbo": { - "language": 1395 - }, - "cbq": { - "language": 1396 - }, - "cbr": { - "language": 1397 - }, - "cbs": { - "language": 1398 - }, - "cbt": { - "language": 1399 - }, - "cbu": { - "language": 1400 - }, - "cbv": { - "language": 1401 - }, - "cbw": { - "language": 1402 - }, - "cby": { - "language": 1403 - }, - "cca": { - "language": 1404 - }, - "ccc": { - "language": 1405 - }, - "ccd": { - "language": 1406 - }, - "cce": { - "language": 1407 - }, - "ccg": { - "language": 1408 - }, - "cch": { - "language": 1409 - }, - "ccj": { - "language": 1410 - }, - "ccl": { - "language": 1411 - }, - "ccm": { - "language": 1412 - }, - "ccn": { - "language": 1413 - }, - "cco": { - "language": 1414 - }, - "ccp": { - "language": 1415 - }, - "ccq": { - "language": 1416 - }, - "ccr": { - "language": 1417 - }, - "ccs": { - "language": 1418 - }, - "cda": { - "language": 1419 - }, - "cdc": { - "language": 1420 - }, - "cdd": { - "language": 1421 - }, - "cde": { - "language": 1422 - }, - "cdf": { - "language": 1423 - }, - "cdg": { - "language": 1424 - }, - "cdh": { - "language": 1425 - }, - "cdi": { - "language": 1426 - }, - "cdj": { - "language": 1427 - }, - "cdm": { - "language": 1428 - }, - "cdn": { - "language": 1429 - }, - "cdo": { - "language": 1430, - "extlang": 8288 - }, - "cdr": { - "language": 1431 - }, - "cds": { - "language": 1432, - "extlang": 8289 - }, - "cdy": { - "language": 1433 - }, - "cdz": { - "language": 1434 - }, - "cea": { - "language": 1435 - }, - "ceb": { - "language": 1436 - }, - "ceg": { - "language": 1437 - }, - "cek": { - "language": 1438 - }, - "cel": { - "language": 1439 - }, - "cen": { - "language": 1440 - }, - "cet": { - "language": 1441 - }, - "cey": { - "language": 1442 - }, - "cfa": { - "language": 1443 - }, - "cfd": { - "language": 1444 - }, - "cfg": { - "language": 1445 - }, - "cfm": { - "language": 1446 - }, - "cga": { - "language": 1447 - }, - "cgc": { - "language": 1448 - }, - "cgg": { - "language": 1449 - }, - "cgk": { - "language": 1450 - }, - "chb": { - "language": 1451 - }, - "chc": { - "language": 1452 - }, - "chd": { - "language": 1453 - }, - "chf": { - "language": 1454 - }, - "chg": { - "language": 1455 - }, - "chh": { - "language": 1456 - }, - "chj": { - "language": 1457 - }, - "chk": { - "language": 1458 - }, - "chl": { - "language": 1459 - }, - "chm": { - "language": 1460 - }, - "chn": { - "language": 1461 - }, - "cho": { - "language": 1462 - }, - "chp": { - "language": 1463 - }, - "chq": { - "language": 1464 - }, - "chr": { - "language": 1465 - }, - "cht": { - "language": 1466 - }, - "chw": { - "language": 1467 - }, - "chx": { - "language": 1468 - }, - "chy": { - "language": 1469 - }, - "chz": { - "language": 1470 - }, - "cia": { - "language": 1471 - }, - "cib": { - "language": 1472 - }, - "cic": { - "language": 1473 - }, - "cid": { - "language": 1474 - }, - "cie": { - "language": 1475 - }, - "cih": { - "language": 1476 - }, - "cik": { - "language": 1477 - }, - "cim": { - "language": 1478 - }, - "cin": { - "language": 1479 - }, - "cip": { - "language": 1480 - }, - "cir": { - "language": 1481 - }, - "ciw": { - "language": 1482 - }, - "ciy": { - "language": 1483 - }, - "cja": { - "language": 1484 - }, - "cje": { - "language": 1485 - }, - "cjh": { - "language": 1486 - }, - "cji": { - "language": 1487 - }, - "cjk": { - "language": 1488 - }, - "cjm": { - "language": 1489 - }, - "cjn": { - "language": 1490 - }, - "cjo": { - "language": 1491 - }, - "cjp": { - "language": 1492 - }, - "cjr": { - "language": 1493 - }, - "cjs": { - "language": 1494 - }, - "cjv": { - "language": 1495 - }, - "cjy": { - "language": 1496, - "extlang": 8290 - }, - "cka": { - "language": 1497 - }, - "ckb": { - "language": 1498 - }, - "ckh": { - "language": 1499 - }, - "ckl": { - "language": 1500 - }, - "ckm": { - "language": 1501 - }, - "ckn": { - "language": 1502 - }, - "cko": { - "language": 1503 - }, - "ckq": { - "language": 1504 - }, - "ckr": { - "language": 1505 - }, - "cks": { - "language": 1506 - }, - "ckt": { - "language": 1507 - }, - "cku": { - "language": 1508 - }, - "ckv": { - "language": 1509 - }, - "ckx": { - "language": 1510 - }, - "cky": { - "language": 1511 - }, - "ckz": { - "language": 1512 - }, - "cla": { - "language": 1513 - }, - "clc": { - "language": 1514 - }, - "cld": { - "language": 1515 - }, - "cle": { - "language": 1516 - }, - "clh": { - "language": 1517 - }, - "cli": { - "language": 1518 - }, - "clj": { - "language": 1519 - }, - "clk": { - "language": 1520 - }, - "cll": { - "language": 1521 - }, - "clm": { - "language": 1522 - }, - "clo": { - "language": 1523 - }, - "clt": { - "language": 1524 - }, - "clu": { - "language": 1525 - }, - "clw": { - "language": 1526 - }, - "cly": { - "language": 1527 - }, - "cma": { - "language": 1528 - }, - "cmc": { - "language": 1529 - }, - "cme": { - "language": 1530 - }, - "cmg": { - "language": 1531 - }, - "cmi": { - "language": 1532 - }, - "cmk": { - "language": 1533 - }, - "cml": { - "language": 1534 - }, - "cmm": { - "language": 1535 - }, - "cmn": { - "language": 1536, - "extlang": 8291 - }, - "cmo": { - "language": 1537 - }, - "cmr": { - "language": 1538 - }, - "cms": { - "language": 1539 - }, - "cmt": { - "language": 1540 - }, - "cna": { - "language": 1541 - }, - "cnb": { - "language": 1542 - }, - "cnc": { - "language": 1543 - }, - "cng": { - "language": 1544 - }, - "cnh": { - "language": 1545 - }, - "cni": { - "language": 1546 - }, - "cnk": { - "language": 1547 - }, - "cnl": { - "language": 1548 - }, - "cno": { - "language": 1549 - }, - "cnp": { - "language": 1550, - "extlang": 8292 - }, - "cnq": { - "language": 1551 - }, - "cnr": { - "language": 1552 - }, - "cns": { - "language": 1553 - }, - "cnt": { - "language": 1554 - }, - "cnu": { - "language": 1555 - }, - "cnw": { - "language": 1556 - }, - "cnx": { - "language": 1557 - }, - "coa": { - "language": 1558, - "extlang": 8293 - }, - "cob": { - "language": 1559 - }, - "coc": { - "language": 1560 - }, - "cod": { - "language": 1561 - }, - "coe": { - "language": 1562 - }, - "cof": { - "language": 1563 - }, - "cog": { - "language": 1564 - }, - "coh": { - "language": 1565 - }, - "coj": { - "language": 1566 - }, - "cok": { - "language": 1567 - }, - "col": { - "language": 1568 - }, - "com": { - "language": 1569 - }, - "con": { - "language": 1570 - }, - "coo": { - "language": 1571 - }, - "cop": { - "language": 1572 - }, - "coq": { - "language": 1573 - }, - "cot": { - "language": 1574 - }, - "cou": { - "language": 1575 - }, - "cov": { - "language": 1576 - }, - "cow": { - "language": 1577 - }, - "cox": { - "language": 1578 - }, - "coy": { - "language": 1579 - }, - "coz": { - "language": 1580 - }, - "cpa": { - "language": 1581 - }, - "cpb": { - "language": 1582 - }, - "cpc": { - "language": 1583 - }, - "cpe": { - "language": 1584 - }, - "cpf": { - "language": 1585 - }, - "cpg": { - "language": 1586 - }, - "cpi": { - "language": 1587 - }, - "cpn": { - "language": 1588 - }, - "cpo": { - "language": 1589 - }, - "cpp": { - "language": 1590 - }, - "cps": { - "language": 1591 - }, - "cpu": { - "language": 1592 - }, - "cpx": { - "language": 1593, - "extlang": 8294 - }, - "cpy": { - "language": 1594 - }, - "cqd": { - "language": 1595 - }, - "cqu": { - "language": 1596 - }, - "cra": { - "language": 1597 - }, - "crb": { - "language": 1598 - }, - "crc": { - "language": 1599 - }, - "crd": { - "language": 1600 - }, - "crf": { - "language": 1601 - }, - "crg": { - "language": 1602 - }, - "crh": { - "language": 1603 - }, - "cri": { - "language": 1604 - }, - "crj": { - "language": 1605 - }, - "crk": { - "language": 1606 - }, - "crl": { - "language": 1607 - }, - "crm": { - "language": 1608 - }, - "crn": { - "language": 1609 - }, - "cro": { - "language": 1610 - }, - "crp": { - "language": 1611 - }, - "crq": { - "language": 1612 - }, - "crr": { - "language": 1613 - }, - "crs": { - "language": 1614 - }, - "crt": { - "language": 1615 - }, - "crv": { - "language": 1616 - }, - "crw": { - "language": 1617 - }, - "crx": { - "language": 1618 - }, - "cry": { - "language": 1619 - }, - "crz": { - "language": 1620 - }, - "csa": { - "language": 1621 - }, - "csb": { - "language": 1622 - }, - "csc": { - "language": 1623, - "extlang": 8295 - }, - "csd": { - "language": 1624, - "extlang": 8296 - }, - "cse": { - "language": 1625, - "extlang": 8297 - }, - "csf": { - "language": 1626, - "extlang": 8298 - }, - "csg": { - "language": 1627, - "extlang": 8299 - }, - "csh": { - "language": 1628 - }, - "csi": { - "language": 1629 - }, - "csj": { - "language": 1630 - }, - "csk": { - "language": 1631 - }, - "csl": { - "language": 1632, - "extlang": 8300 - }, - "csm": { - "language": 1633 - }, - "csn": { - "language": 1634, - "extlang": 8301 - }, - "cso": { - "language": 1635 - }, - "csp": { - "language": 1636, - "extlang": 8302 - }, - "csq": { - "language": 1637, - "extlang": 8303 - }, - "csr": { - "language": 1638, - "extlang": 8304 - }, - "css": { - "language": 1639 - }, - "cst": { - "language": 1640 - }, - "csu": { - "language": 1641 - }, - "csv": { - "language": 1642 - }, - "csw": { - "language": 1643 - }, - "csx": { - "language": 1644, - "extlang": 8305 - }, - "csy": { - "language": 1645 - }, - "csz": { - "language": 1646 - }, - "cta": { - "language": 1647 - }, - "ctc": { - "language": 1648 - }, - "ctd": { - "language": 1649 - }, - "cte": { - "language": 1650 - }, - "ctg": { - "language": 1651 - }, - "cth": { - "language": 1652 - }, - "ctl": { - "language": 1653 - }, - "ctm": { - "language": 1654 - }, - "ctn": { - "language": 1655 - }, - "cto": { - "language": 1656 - }, - "ctp": { - "language": 1657 - }, - "cts": { - "language": 1658 - }, - "ctt": { - "language": 1659 - }, - "ctu": { - "language": 1660 - }, - "cty": { - "language": 1661 - }, - "ctz": { - "language": 1662 - }, - "cua": { - "language": 1663 - }, - "cub": { - "language": 1664 - }, - "cuc": { - "language": 1665 - }, - "cug": { - "language": 1666 - }, - "cuh": { - "language": 1667 - }, - "cui": { - "language": 1668 - }, - "cuj": { - "language": 1669 - }, - "cuk": { - "language": 1670 - }, - "cul": { - "language": 1671 - }, - "cum": { - "language": 1672 - }, - "cuo": { - "language": 1673 - }, - "cup": { - "language": 1674 - }, - "cuq": { - "language": 1675 - }, - "cur": { - "language": 1676 - }, - "cus": { - "language": 1677 - }, - "cut": { - "language": 1678 - }, - "cuu": { - "language": 1679 - }, - "cuv": { - "language": 1680 - }, - "cuw": { - "language": 1681 - }, - "cux": { - "language": 1682 - }, - "cuy": { - "language": 1683 - }, - "cvg": { - "language": 1684 - }, - "cvn": { - "language": 1685 - }, - "cwa": { - "language": 1686 - }, - "cwb": { - "language": 1687 - }, - "cwd": { - "language": 1688 - }, - "cwe": { - "language": 1689 - }, - "cwg": { - "language": 1690 - }, - "cwt": { - "language": 1691 - }, - "cya": { - "language": 1692 - }, - "cyb": { - "language": 1693 - }, - "cyo": { - "language": 1694 - }, - "czh": { - "language": 1695, - "extlang": 8306 - }, - "czk": { - "language": 1696 - }, - "czn": { - "language": 1697 - }, - "czo": { - "language": 1698, - "extlang": 8307 - }, - "czt": { - "language": 1699 - }, - "daa": { - "language": 1700 - }, - "dac": { - "language": 1701 - }, - "dad": { - "language": 1702 - }, - "dae": { - "language": 1703 - }, - "daf": { - "language": 1704 - }, - "dag": { - "language": 1705 - }, - "dah": { - "language": 1706 - }, - "dai": { - "language": 1707 - }, - "daj": { - "language": 1708 - }, - "dak": { - "language": 1709 - }, - "dal": { - "language": 1710 - }, - "dam": { - "language": 1711 - }, - "dao": { - "language": 1712 - }, - "dap": { - "language": 1713 - }, - "daq": { - "language": 1714 - }, - "dar": { - "language": 1715 - }, - "das": { - "language": 1716 - }, - "dau": { - "language": 1717 - }, - "dav": { - "language": 1718 - }, - "daw": { - "language": 1719 - }, - "dax": { - "language": 1720 - }, - "day": { - "language": 1721 - }, - "daz": { - "language": 1722 - }, - "dba": { - "language": 1723 - }, - "dbb": { - "language": 1724 - }, - "dbd": { - "language": 1725 - }, - "dbe": { - "language": 1726 - }, - "dbf": { - "language": 1727 - }, - "dbg": { - "language": 1728 - }, - "dbi": { - "language": 1729 - }, - "dbj": { - "language": 1730 - }, - "dbl": { - "language": 1731 - }, - "dbm": { - "language": 1732 - }, - "dbn": { - "language": 1733 - }, - "dbo": { - "language": 1734 - }, - "dbp": { - "language": 1735 - }, - "dbq": { - "language": 1736 - }, - "dbr": { - "language": 1737 - }, - "dbt": { - "language": 1738 - }, - "dbu": { - "language": 1739 - }, - "dbv": { - "language": 1740 - }, - "dbw": { - "language": 1741 - }, - "dby": { - "language": 1742 - }, - "dcc": { - "language": 1743 - }, - "dcr": { - "language": 1744 - }, - "dda": { - "language": 1745 - }, - "ddd": { - "language": 1746 - }, - "dde": { - "language": 1747 - }, - "ddg": { - "language": 1748 - }, - "ddi": { - "language": 1749 - }, - "ddj": { - "language": 1750 - }, - "ddn": { - "language": 1751 - }, - "ddo": { - "language": 1752 - }, - "ddr": { - "language": 1753 - }, - "dds": { - "language": 1754 - }, - "ddw": { - "language": 1755 - }, - "dec": { - "language": 1756 - }, - "ded": { - "language": 1757 - }, - "dee": { - "language": 1758 - }, - "def": { - "language": 1759 - }, - "deg": { - "language": 1760 - }, - "deh": { - "language": 1761 - }, - "dei": { - "language": 1762 - }, - "dek": { - "language": 1763 - }, - "del": { - "language": 1764 - }, - "dem": { - "language": 1765 - }, - "den": { - "language": 1766 - }, - "dep": { - "language": 1767 - }, - "deq": { - "language": 1768 - }, - "der": { - "language": 1769 - }, - "des": { - "language": 1770 - }, - "dev": { - "language": 1771 - }, - "dez": { - "language": 1772 - }, - "dga": { - "language": 1773 - }, - "dgb": { - "language": 1774 - }, - "dgc": { - "language": 1775 - }, - "dgd": { - "language": 1776 - }, - "dge": { - "language": 1777 - }, - "dgg": { - "language": 1778 - }, - "dgh": { - "language": 1779 - }, - "dgi": { - "language": 1780 - }, - "dgk": { - "language": 1781 - }, - "dgl": { - "language": 1782 - }, - "dgn": { - "language": 1783 - }, - "dgo": { - "language": 1784 - }, - "dgr": { - "language": 1785 - }, - "dgs": { - "language": 1786 - }, - "dgt": { - "language": 1787 - }, - "dgu": { - "language": 1788 - }, - "dgw": { - "language": 1789 - }, - "dgx": { - "language": 1790 - }, - "dgz": { - "language": 1791 - }, - "dha": { - "language": 1792 - }, - "dhd": { - "language": 1793 - }, - "dhg": { - "language": 1794 - }, - "dhi": { - "language": 1795 - }, - "dhl": { - "language": 1796 - }, - "dhm": { - "language": 1797 - }, - "dhn": { - "language": 1798 - }, - "dho": { - "language": 1799 - }, - "dhr": { - "language": 1800 - }, - "dhs": { - "language": 1801 - }, - "dhu": { - "language": 1802 - }, - "dhv": { - "language": 1803 - }, - "dhw": { - "language": 1804 - }, - "dhx": { - "language": 1805 - }, - "dia": { - "language": 1806 - }, - "dib": { - "language": 1807 - }, - "dic": { - "language": 1808 - }, - "did": { - "language": 1809 - }, - "dif": { - "language": 1810 - }, - "dig": { - "language": 1811 - }, - "dih": { - "language": 1812 - }, - "dii": { - "language": 1813 - }, - "dij": { - "language": 1814 - }, - "dik": { - "language": 1815 - }, - "dil": { - "language": 1816 - }, - "dim": { - "language": 1817 - }, - "din": { - "language": 1818 - }, - "dio": { - "language": 1819 - }, - "dip": { - "language": 1820 - }, - "diq": { - "language": 1821 - }, - "dir": { - "language": 1822 - }, - "dis": { - "language": 1823 - }, - "dit": { - "language": 1824 - }, - "diu": { - "language": 1825 - }, - "diw": { - "language": 1826 - }, - "dix": { - "language": 1827 - }, - "diy": { - "language": 1828 - }, - "diz": { - "language": 1829 - }, - "dja": { - "language": 1830 - }, - "djb": { - "language": 1831 - }, - "djc": { - "language": 1832 - }, - "djd": { - "language": 1833 - }, - "dje": { - "language": 1834 - }, - "djf": { - "language": 1835 - }, - "dji": { - "language": 1836 - }, - "djj": { - "language": 1837 - }, - "djk": { - "language": 1838 - }, - "djl": { - "language": 1839 - }, - "djm": { - "language": 1840 - }, - "djn": { - "language": 1841 - }, - "djo": { - "language": 1842 - }, - "djr": { - "language": 1843 - }, - "dju": { - "language": 1844 - }, - "djw": { - "language": 1845 - }, - "dka": { - "language": 1846 - }, - "dkg": { - "language": 1847 - }, - "dkk": { - "language": 1848 - }, - "dkl": { - "language": 1849 - }, - "dkr": { - "language": 1850 - }, - "dks": { - "language": 1851 - }, - "dkx": { - "language": 1852 - }, - "dlg": { - "language": 1853 - }, - "dlk": { - "language": 1854 - }, - "dlm": { - "language": 1855 - }, - "dln": { - "language": 1856 - }, - "dma": { - "language": 1857 - }, - "dmb": { - "language": 1858 - }, - "dmc": { - "language": 1859 - }, - "dmd": { - "language": 1860 - }, - "dme": { - "language": 1861 - }, - "dmf": { - "language": 1862 - }, - "dmg": { - "language": 1863 - }, - "dmk": { - "language": 1864 - }, - "dml": { - "language": 1865 - }, - "dmm": { - "language": 1866 - }, - "dmn": { - "language": 1867 - }, - "dmo": { - "language": 1868 - }, - "dmr": { - "language": 1869 - }, - "dms": { - "language": 1870 - }, - "dmu": { - "language": 1871 - }, - "dmv": { - "language": 1872 - }, - "dmw": { - "language": 1873 - }, - "dmx": { - "language": 1874 - }, - "dmy": { - "language": 1875 - }, - "dna": { - "language": 1876 - }, - "dnd": { - "language": 1877 - }, - "dne": { - "language": 1878 - }, - "dng": { - "language": 1879 - }, - "dni": { - "language": 1880 - }, - "dnj": { - "language": 1881 - }, - "dnk": { - "language": 1882 - }, - "dnn": { - "language": 1883 - }, - "dno": { - "language": 1884 - }, - "dnr": { - "language": 1885 - }, - "dnt": { - "language": 1886 - }, - "dnu": { - "language": 1887 - }, - "dnv": { - "language": 1888 - }, - "dnw": { - "language": 1889 - }, - "dny": { - "language": 1890 - }, - "doa": { - "language": 1891 - }, - "dob": { - "language": 1892 - }, - "doc": { - "language": 1893 - }, - "doe": { - "language": 1894 - }, - "dof": { - "language": 1895 - }, - "doh": { - "language": 1896 - }, - "doi": { - "language": 1897 - }, - "dok": { - "language": 1898 - }, - "dol": { - "language": 1899 - }, - "don": { - "language": 1900 - }, - "doo": { - "language": 1901 - }, - "dop": { - "language": 1902 - }, - "doq": { - "language": 1903, - "extlang": 8308 - }, - "dor": { - "language": 1904 - }, - "dos": { - "language": 1905 - }, - "dot": { - "language": 1906 - }, - "dov": { - "language": 1907 - }, - "dow": { - "language": 1908 - }, - "dox": { - "language": 1909 - }, - "doy": { - "language": 1910 - }, - "doz": { - "language": 1911 - }, - "dpp": { - "language": 1912 - }, - "dra": { - "language": 1913 - }, - "drb": { - "language": 1914 - }, - "drc": { - "language": 1915 - }, - "drd": { - "language": 1916 - }, - "dre": { - "language": 1917 - }, - "drg": { - "language": 1918 - }, - "drh": { - "language": 1919 - }, - "dri": { - "language": 1920 - }, - "drl": { - "language": 1921 - }, - "drn": { - "language": 1922 - }, - "dro": { - "language": 1923 - }, - "drq": { - "language": 1924 - }, - "drr": { - "language": 1925 - }, - "drs": { - "language": 1926 - }, - "drt": { - "language": 1927 - }, - "dru": { - "language": 1928 - }, - "drw": { - "language": 1929 - }, - "dry": { - "language": 1930 - }, - "dsb": { - "language": 1931 - }, - "dse": { - "language": 1932, - "extlang": 8309 - }, - "dsh": { - "language": 1933 - }, - "dsi": { - "language": 1934 - }, - "dsl": { - "language": 1935, - "extlang": 8310 - }, - "dsn": { - "language": 1936 - }, - "dso": { - "language": 1937 - }, - "dsq": { - "language": 1938 - }, - "dsz": { - "language": 1939, - "extlang": 8311 - }, - "dta": { - "language": 1940 - }, - "dtb": { - "language": 1941 - }, - "dtd": { - "language": 1942 - }, - "dth": { - "language": 1943 - }, - "dti": { - "language": 1944 - }, - "dtk": { - "language": 1945 - }, - "dtm": { - "language": 1946 - }, - "dtn": { - "language": 1947 - }, - "dto": { - "language": 1948 - }, - "dtp": { - "language": 1949 - }, - "dtr": { - "language": 1950 - }, - "dts": { - "language": 1951 - }, - "dtt": { - "language": 1952 - }, - "dtu": { - "language": 1953 - }, - "dty": { - "language": 1954 - }, - "dua": { - "language": 1955 - }, - "dub": { - "language": 1956 - }, - "duc": { - "language": 1957 - }, - "dud": { - "language": 1958 - }, - "due": { - "language": 1959 - }, - "duf": { - "language": 1960 - }, - "dug": { - "language": 1961 - }, - "duh": { - "language": 1962 - }, - "dui": { - "language": 1963 - }, - "duj": { - "language": 1964 - }, - "duk": { - "language": 1965 - }, - "dul": { - "language": 1966 - }, - "dum": { - "language": 1967 - }, - "dun": { - "language": 1968 - }, - "duo": { - "language": 1969 - }, - "dup": { - "language": 1970, - "extlang": 8312 - }, - "duq": { - "language": 1971 - }, - "dur": { - "language": 1972 - }, - "dus": { - "language": 1973 - }, - "duu": { - "language": 1974 - }, - "duv": { - "language": 1975 - }, - "duw": { - "language": 1976 - }, - "dux": { - "language": 1977 - }, - "duy": { - "language": 1978 - }, - "duz": { - "language": 1979 - }, - "dva": { - "language": 1980 - }, - "dwa": { - "language": 1981 - }, - "dwk": { - "language": 1982 - }, - "dwl": { - "language": 1983 - }, - "dwr": { - "language": 1984 - }, - "dws": { - "language": 1985 - }, - "dwu": { - "language": 1986 - }, - "dww": { - "language": 1987 - }, - "dwy": { - "language": 1988 - }, - "dwz": { - "language": 1989 - }, - "dya": { - "language": 1990 - }, - "dyb": { - "language": 1991 - }, - "dyd": { - "language": 1992 - }, - "dyg": { - "language": 1993 - }, - "dyi": { - "language": 1994 - }, - "dym": { - "language": 1995 - }, - "dyn": { - "language": 1996 - }, - "dyo": { - "language": 1997 - }, - "dyu": { - "language": 1998 - }, - "dyy": { - "language": 1999 - }, - "dza": { - "language": 2000 - }, - "dzd": { - "language": 2001 - }, - "dze": { - "language": 2002 - }, - "dzg": { - "language": 2003 - }, - "dzl": { - "language": 2004 - }, - "dzn": { - "language": 2005 - }, - "eaa": { - "language": 2006 - }, - "ebc": { - "language": 2007 - }, - "ebg": { - "language": 2008 - }, - "ebk": { - "language": 2009 - }, - "ebo": { - "language": 2010 - }, - "ebr": { - "language": 2011 - }, - "ebu": { - "language": 2012 - }, - "ecr": { - "language": 2013 - }, - "ecs": { - "language": 2014, - "extlang": 8313 - }, - "ecy": { - "language": 2015 - }, - "eee": { - "language": 2016 - }, - "efa": { - "language": 2017 - }, - "efe": { - "language": 2018 - }, - "efi": { - "language": 2019 - }, - "ega": { - "language": 2020 - }, - "egl": { - "language": 2021 - }, - "egm": { - "language": 2022 - }, - "ego": { - "language": 2023 - }, - "egx": { - "language": 2024 - }, - "egy": { - "language": 2025 - }, - "ehs": { - "language": 2026, - "extlang": 8314 - }, - "ehu": { - "language": 2027 - }, - "eip": { - "language": 2028 - }, - "eit": { - "language": 2029 - }, - "eiv": { - "language": 2030 - }, - "eja": { - "language": 2031 - }, - "eka": { - "language": 2032 - }, - "ekc": { - "language": 2033 - }, - "eke": { - "language": 2034 - }, - "ekg": { - "language": 2035 - }, - "eki": { - "language": 2036 - }, - "ekk": { - "language": 2037 - }, - "ekl": { - "language": 2038 - }, - "ekm": { - "language": 2039 - }, - "eko": { - "language": 2040 - }, - "ekp": { - "language": 2041 - }, - "ekr": { - "language": 2042 - }, - "eky": { - "language": 2043 - }, - "ele": { - "language": 2044 - }, - "elh": { - "language": 2045 - }, - "eli": { - "language": 2046 - }, - "elk": { - "language": 2047 - }, - "elm": { - "language": 2048 - }, - "elo": { - "language": 2049 - }, - "elp": { - "language": 2050 - }, - "elu": { - "language": 2051 - }, - "elx": { - "language": 2052 - }, - "ema": { - "language": 2053 - }, - "emb": { - "language": 2054 - }, - "eme": { - "language": 2055 - }, - "emg": { - "language": 2056 - }, - "emi": { - "language": 2057 - }, - "emk": { - "language": 2058 - }, - "emm": { - "language": 2059 - }, - "emn": { - "language": 2060 - }, - "emo": { - "language": 2061 - }, - "emp": { - "language": 2062 - }, - "emq": { - "language": 2063 - }, - "ems": { - "language": 2064 - }, - "emu": { - "language": 2065 - }, - "emw": { - "language": 2066 - }, - "emx": { - "language": 2067 - }, - "emy": { - "language": 2068 - }, - "emz": { - "language": 2069 - }, - "ena": { - "language": 2070 - }, - "enb": { - "language": 2071 - }, - "enc": { - "language": 2072 - }, - "end": { - "language": 2073 - }, - "enf": { - "language": 2074 - }, - "enh": { - "language": 2075 - }, - "enl": { - "language": 2076 - }, - "enm": { - "language": 2077 - }, - "enn": { - "language": 2078 - }, - "eno": { - "language": 2079 - }, - "enq": { - "language": 2080 - }, - "enr": { - "language": 2081 - }, - "enu": { - "language": 2082 - }, - "env": { - "language": 2083 - }, - "enw": { - "language": 2084 - }, - "enx": { - "language": 2085 - }, - "eot": { - "language": 2086 - }, - "epi": { - "language": 2087 - }, - "era": { - "language": 2088 - }, - "erg": { - "language": 2089 - }, - "erh": { - "language": 2090 - }, - "eri": { - "language": 2091 - }, - "erk": { - "language": 2092 - }, - "ero": { - "language": 2093 - }, - "err": { - "language": 2094 - }, - "ers": { - "language": 2095 - }, - "ert": { - "language": 2096 - }, - "erw": { - "language": 2097 - }, - "ese": { - "language": 2098 - }, - "esg": { - "language": 2099 - }, - "esh": { - "language": 2100 - }, - "esi": { - "language": 2101 - }, - "esk": { - "language": 2102 - }, - "esl": { - "language": 2103, - "extlang": 8315 - }, - "esm": { - "language": 2104 - }, - "esn": { - "language": 2105, - "extlang": 8316 - }, - "eso": { - "language": 2106, - "extlang": 8317 - }, - "esq": { - "language": 2107 - }, - "ess": { - "language": 2108 - }, - "esu": { - "language": 2109 - }, - "esx": { - "language": 2110 - }, - "esy": { - "language": 2111 - }, - "etb": { - "language": 2112 - }, - "etc": { - "language": 2113 - }, - "eth": { - "language": 2114, - "extlang": 8318 - }, - "etn": { - "language": 2115 - }, - "eto": { - "language": 2116 - }, - "etr": { - "language": 2117 - }, - "ets": { - "language": 2118 - }, - "ett": { - "language": 2119 - }, - "etu": { - "language": 2120 - }, - "etx": { - "language": 2121 - }, - "etz": { - "language": 2122 - }, - "euq": { - "language": 2123 - }, - "eve": { - "language": 2124 - }, - "evh": { - "language": 2125 - }, - "evn": { - "language": 2126 - }, - "ewo": { - "language": 2127 - }, - "ext": { - "language": 2128 - }, - "eya": { - "language": 2129 - }, - "eyo": { - "language": 2130 - }, - "eza": { - "language": 2131 - }, - "eze": { - "language": 2132 - }, - "faa": { - "language": 2133 - }, - "fab": { - "language": 2134 - }, - "fad": { - "language": 2135 - }, - "faf": { - "language": 2136 - }, - "fag": { - "language": 2137 - }, - "fah": { - "language": 2138 - }, - "fai": { - "language": 2139 - }, - "faj": { - "language": 2140 - }, - "fak": { - "language": 2141 - }, - "fal": { - "language": 2142 - }, - "fam": { - "language": 2143 - }, - "fan": { - "language": 2144 - }, - "fap": { - "language": 2145 - }, - "far": { - "language": 2146 - }, - "fat": { - "language": 2147 - }, - "fau": { - "language": 2148 - }, - "fax": { - "language": 2149 - }, - "fay": { - "language": 2150 - }, - "faz": { - "language": 2151 - }, - "fbl": { - "language": 2152 - }, - "fcs": { - "language": 2153, - "extlang": 8319 - }, - "fer": { - "language": 2154 - }, - "ffi": { - "language": 2155 - }, - "ffm": { - "language": 2156 - }, - "fgr": { - "language": 2157 - }, - "fia": { - "language": 2158 - }, - "fie": { - "language": 2159 - }, - "fif": { - "language": 2160 - }, - "fil": { - "language": 2161 - }, - "fip": { - "language": 2162 - }, - "fir": { - "language": 2163 - }, - "fit": { - "language": 2164 - }, - "fiu": { - "language": 2165 - }, - "fiw": { - "language": 2166 - }, - "fkk": { - "language": 2167 - }, - "fkv": { - "language": 2168 - }, - "fla": { - "language": 2169 - }, - "flh": { - "language": 2170 - }, - "fli": { - "language": 2171 - }, - "fll": { - "language": 2172 - }, - "fln": { - "language": 2173 - }, - "flr": { - "language": 2174 - }, - "fly": { - "language": 2175 - }, - "fmp": { - "language": 2176 - }, - "fmu": { - "language": 2177 - }, - "fnb": { - "language": 2178 - }, - "fng": { - "language": 2179 - }, - "fni": { - "language": 2180 - }, - "fod": { - "language": 2181 - }, - "foi": { - "language": 2182 - }, - "fom": { - "language": 2183 - }, - "fon": { - "language": 2184 - }, - "for": { - "language": 2185 - }, - "fos": { - "language": 2186 - }, - "fox": { - "language": 2187 - }, - "fpe": { - "language": 2188 - }, - "fqs": { - "language": 2189 - }, - "frc": { - "language": 2190 - }, - "frd": { - "language": 2191 - }, - "frk": { - "language": 2192 - }, - "frm": { - "language": 2193 - }, - "fro": { - "language": 2194 - }, - "frp": { - "language": 2195 - }, - "frq": { - "language": 2196 - }, - "frr": { - "language": 2197 - }, - "frs": { - "language": 2198 - }, - "frt": { - "language": 2199 - }, - "fse": { - "language": 2200, - "extlang": 8320 - }, - "fsl": { - "language": 2201, - "extlang": 8321 - }, - "fss": { - "language": 2202, - "extlang": 8322 - }, - "fub": { - "language": 2203 - }, - "fuc": { - "language": 2204 - }, - "fud": { - "language": 2205 - }, - "fue": { - "language": 2206 - }, - "fuf": { - "language": 2207 - }, - "fuh": { - "language": 2208 - }, - "fui": { - "language": 2209 - }, - "fuj": { - "language": 2210 - }, - "fum": { - "language": 2211 - }, - "fun": { - "language": 2212 - }, - "fuq": { - "language": 2213 - }, - "fur": { - "language": 2214 - }, - "fut": { - "language": 2215 - }, - "fuu": { - "language": 2216 - }, - "fuv": { - "language": 2217 - }, - "fuy": { - "language": 2218 - }, - "fvr": { - "language": 2219 - }, - "fwa": { - "language": 2220 - }, - "fwe": { - "language": 2221 - }, - "gaa": { - "language": 2222 - }, - "gab": { - "language": 2223 - }, - "gac": { - "language": 2224 - }, - "gad": { - "language": 2225 - }, - "gae": { - "language": 2226 - }, - "gaf": { - "language": 2227 - }, - "gag": { - "language": 2228 - }, - "gah": { - "language": 2229 - }, - "gai": { - "language": 2230 - }, - "gaj": { - "language": 2231 - }, - "gak": { - "language": 2232 - }, - "gal": { - "language": 2233 - }, - "gam": { - "language": 2234 - }, - "gan": { - "language": 2235, - "extlang": 8323 - }, - "gao": { - "language": 2236 - }, - "gap": { - "language": 2237 - }, - "gaq": { - "language": 2238 - }, - "gar": { - "language": 2239 - }, - "gas": { - "language": 2240 - }, - "gat": { - "language": 2241 - }, - "gau": { - "language": 2242 - }, - "gav": { - "language": 2243 - }, - "gaw": { - "language": 2244 - }, - "gax": { - "language": 2245 - }, - "gay": { - "language": 2246 - }, - "gaz": { - "language": 2247 - }, - "gba": { - "language": 2248 - }, - "gbb": { - "language": 2249 - }, - "gbc": { - "language": 2250 - }, - "gbd": { - "language": 2251 - }, - "gbe": { - "language": 2252 - }, - "gbf": { - "language": 2253 - }, - "gbg": { - "language": 2254 - }, - "gbh": { - "language": 2255 - }, - "gbi": { - "language": 2256 - }, - "gbj": { - "language": 2257 - }, - "gbk": { - "language": 2258 - }, - "gbl": { - "language": 2259 - }, - "gbm": { - "language": 2260 - }, - "gbn": { - "language": 2261 - }, - "gbo": { - "language": 2262 - }, - "gbp": { - "language": 2263 - }, - "gbq": { - "language": 2264 - }, - "gbr": { - "language": 2265 - }, - "gbs": { - "language": 2266 - }, - "gbu": { - "language": 2267 - }, - "gbv": { - "language": 2268 - }, - "gbw": { - "language": 2269 - }, - "gbx": { - "language": 2270 - }, - "gby": { - "language": 2271 - }, - "gbz": { - "language": 2272 - }, - "gcc": { - "language": 2273 - }, - "gcd": { - "language": 2274 - }, - "gce": { - "language": 2275 - }, - "gcf": { - "language": 2276 - }, - "gcl": { - "language": 2277 - }, - "gcn": { - "language": 2278 - }, - "gcr": { - "language": 2279 - }, - "gct": { - "language": 2280 - }, - "gda": { - "language": 2281 - }, - "gdb": { - "language": 2282 - }, - "gdc": { - "language": 2283 - }, - "gdd": { - "language": 2284 - }, - "gde": { - "language": 2285 - }, - "gdf": { - "language": 2286 - }, - "gdg": { - "language": 2287 - }, - "gdh": { - "language": 2288 - }, - "gdi": { - "language": 2289 - }, - "gdj": { - "language": 2290 - }, - "gdk": { - "language": 2291 - }, - "gdl": { - "language": 2292 - }, - "gdm": { - "language": 2293 - }, - "gdn": { - "language": 2294 - }, - "gdo": { - "language": 2295 - }, - "gdq": { - "language": 2296 - }, - "gdr": { - "language": 2297 - }, - "gds": { - "language": 2298, - "extlang": 8324 - }, - "gdt": { - "language": 2299 - }, - "gdu": { - "language": 2300 - }, - "gdx": { - "language": 2301 - }, - "gea": { - "language": 2302 - }, - "geb": { - "language": 2303 - }, - "gec": { - "language": 2304 - }, - "ged": { - "language": 2305 - }, - "gef": { - "language": 2306 - }, - "geg": { - "language": 2307 - }, - "geh": { - "language": 2308 - }, - "gei": { - "language": 2309 - }, - "gej": { - "language": 2310 - }, - "gek": { - "language": 2311 - }, - "gel": { - "language": 2312 - }, - "gem": { - "language": 2313 - }, - "geq": { - "language": 2314 - }, - "ges": { - "language": 2315 - }, - "gev": { - "language": 2316 - }, - "gew": { - "language": 2317 - }, - "gex": { - "language": 2318 - }, - "gey": { - "language": 2319 - }, - "gez": { - "language": 2320 - }, - "gfk": { - "language": 2321 - }, - "gft": { - "language": 2322 - }, - "gfx": { - "language": 2323 - }, - "gga": { - "language": 2324 - }, - "ggb": { - "language": 2325 - }, - "ggd": { - "language": 2326 - }, - "gge": { - "language": 2327 - }, - "ggg": { - "language": 2328 - }, - "ggk": { - "language": 2329 - }, - "ggl": { - "language": 2330 - }, - "ggn": { - "language": 2331 - }, - "ggo": { - "language": 2332 - }, - "ggr": { - "language": 2333 - }, - "ggt": { - "language": 2334 - }, - "ggu": { - "language": 2335 - }, - "ggw": { - "language": 2336 - }, - "gha": { - "language": 2337 - }, - "ghc": { - "language": 2338 - }, - "ghe": { - "language": 2339 - }, - "ghh": { - "language": 2340 - }, - "ghk": { - "language": 2341 - }, - "ghl": { - "language": 2342 - }, - "ghn": { - "language": 2343 - }, - "gho": { - "language": 2344 - }, - "ghr": { - "language": 2345 - }, - "ghs": { - "language": 2346 - }, - "ght": { - "language": 2347 - }, - "gia": { - "language": 2348 - }, - "gib": { - "language": 2349 - }, - "gic": { - "language": 2350 - }, - "gid": { - "language": 2351 - }, - "gie": { - "language": 2352 - }, - "gig": { - "language": 2353 - }, - "gih": { - "language": 2354 - }, - "gii": { - "language": 2355 - }, - "gil": { - "language": 2356 - }, - "gim": { - "language": 2357 - }, - "gin": { - "language": 2358 - }, - "gio": { - "language": 2359 - }, - "gip": { - "language": 2360 - }, - "giq": { - "language": 2361 - }, - "gir": { - "language": 2362 - }, - "gis": { - "language": 2363 - }, - "git": { - "language": 2364 - }, - "giu": { - "language": 2365 - }, - "giw": { - "language": 2366 - }, - "gix": { - "language": 2367 - }, - "giy": { - "language": 2368 - }, - "giz": { - "language": 2369 - }, - "gji": { - "language": 2370 - }, - "gjk": { - "language": 2371 - }, - "gjm": { - "language": 2372 - }, - "gjn": { - "language": 2373 - }, - "gjr": { - "language": 2374 - }, - "gju": { - "language": 2375 - }, - "gka": { - "language": 2376 - }, - "gkd": { - "language": 2377 - }, - "gke": { - "language": 2378 - }, - "gkn": { - "language": 2379 - }, - "gko": { - "language": 2380 - }, - "gkp": { - "language": 2381 - }, - "gku": { - "language": 2382 - }, - "glb": { - "language": 2383 - }, - "glc": { - "language": 2384 - }, - "gld": { - "language": 2385 - }, - "glh": { - "language": 2386 - }, - "gli": { - "language": 2387 - }, - "glj": { - "language": 2388 - }, - "glk": { - "language": 2389 - }, - "gll": { - "language": 2390 - }, - "glo": { - "language": 2391 - }, - "glr": { - "language": 2392 - }, - "glu": { - "language": 2393 - }, - "glw": { - "language": 2394 - }, - "gly": { - "language": 2395 - }, - "gma": { - "language": 2396 - }, - "gmb": { - "language": 2397 - }, - "gmd": { - "language": 2398 - }, - "gme": { - "language": 2399 - }, - "gmg": { - "language": 2400 - }, - "gmh": { - "language": 2401 - }, - "gml": { - "language": 2402 - }, - "gmm": { - "language": 2403 - }, - "gmn": { - "language": 2404 - }, - "gmq": { - "language": 2405 - }, - "gmr": { - "language": 2406 - }, - "gmu": { - "language": 2407 - }, - "gmv": { - "language": 2408 - }, - "gmw": { - "language": 2409 - }, - "gmx": { - "language": 2410 - }, - "gmy": { - "language": 2411 - }, - "gmz": { - "language": 2412 - }, - "gna": { - "language": 2413 - }, - "gnb": { - "language": 2414 - }, - "gnc": { - "language": 2415 - }, - "gnd": { - "language": 2416 - }, - "gne": { - "language": 2417 - }, - "gng": { - "language": 2418 - }, - "gnh": { - "language": 2419 - }, - "gni": { - "language": 2420 - }, - "gnj": { - "language": 2421 - }, - "gnk": { - "language": 2422 - }, - "gnl": { - "language": 2423 - }, - "gnm": { - "language": 2424 - }, - "gnn": { - "language": 2425 - }, - "gno": { - "language": 2426 - }, - "gnq": { - "language": 2427 - }, - "gnr": { - "language": 2428 - }, - "gnt": { - "language": 2429 - }, - "gnu": { - "language": 2430 - }, - "gnw": { - "language": 2431 - }, - "gnz": { - "language": 2432 - }, - "goa": { - "language": 2433 - }, - "gob": { - "language": 2434 - }, - "goc": { - "language": 2435 - }, - "god": { - "language": 2436 - }, - "goe": { - "language": 2437 - }, - "gof": { - "language": 2438 - }, - "gog": { - "language": 2439 - }, - "goh": { - "language": 2440 - }, - "goi": { - "language": 2441 - }, - "goj": { - "language": 2442 - }, - "gok": { - "language": 2443 - }, - "gol": { - "language": 2444 - }, - "gom": { - "language": 2445, - "extlang": 8325 - }, - "gon": { - "language": 2446 - }, - "goo": { - "language": 2447 - }, - "gop": { - "language": 2448 - }, - "goq": { - "language": 2449 - }, - "gor": { - "language": 2450 - }, - "gos": { - "language": 2451 - }, - "got": { - "language": 2452 - }, - "gou": { - "language": 2453 - }, - "gov": { - "language": 2454 - }, - "gow": { - "language": 2455 - }, - "gox": { - "language": 2456 - }, - "goy": { - "language": 2457 - }, - "goz": { - "language": 2458 - }, - "gpa": { - "language": 2459 - }, - "gpe": { - "language": 2460 - }, - "gpn": { - "language": 2461 - }, - "gqa": { - "language": 2462 - }, - "gqi": { - "language": 2463 - }, - "gqn": { - "language": 2464 - }, - "gqr": { - "language": 2465 - }, - "gqu": { - "language": 2466 - }, - "gra": { - "language": 2467 - }, - "grb": { - "language": 2468 - }, - "grc": { - "language": 2469 - }, - "grd": { - "language": 2470 - }, - "grg": { - "language": 2471 - }, - "grh": { - "language": 2472 - }, - "gri": { - "language": 2473 - }, - "grj": { - "language": 2474 - }, - "grk": { - "language": 2475 - }, - "grm": { - "language": 2476 - }, - "gro": { - "language": 2477 - }, - "grq": { - "language": 2478 - }, - "grr": { - "language": 2479 - }, - "grs": { - "language": 2480 - }, - "grt": { - "language": 2481 - }, - "gru": { - "language": 2482 - }, - "grv": { - "language": 2483 - }, - "grw": { - "language": 2484 - }, - "grx": { - "language": 2485 - }, - "gry": { - "language": 2486 - }, - "grz": { - "language": 2487 - }, - "gse": { - "language": 2488, - "extlang": 8326 - }, - "gsg": { - "language": 2489, - "extlang": 8327 - }, - "gsl": { - "language": 2490 - }, - "gsm": { - "language": 2491, - "extlang": 8328 - }, - "gsn": { - "language": 2492 - }, - "gso": { - "language": 2493 - }, - "gsp": { - "language": 2494 - }, - "gss": { - "language": 2495, - "extlang": 8329 - }, - "gsw": { - "language": 2496 - }, - "gta": { - "language": 2497 - }, - "gti": { - "language": 2498 - }, - "gtu": { - "language": 2499 - }, - "gua": { - "language": 2500 - }, - "gub": { - "language": 2501 - }, - "guc": { - "language": 2502 - }, - "gud": { - "language": 2503 - }, - "gue": { - "language": 2504 - }, - "guf": { - "language": 2505 - }, - "gug": { - "language": 2506 - }, - "guh": { - "language": 2507 - }, - "gui": { - "language": 2508 - }, - "guk": { - "language": 2509 - }, - "gul": { - "language": 2510 - }, - "gum": { - "language": 2511 - }, - "gun": { - "language": 2512 - }, - "guo": { - "language": 2513 - }, - "gup": { - "language": 2514 - }, - "guq": { - "language": 2515 - }, - "gur": { - "language": 2516 - }, - "gus": { - "language": 2517, - "extlang": 8330 - }, - "gut": { - "language": 2518 - }, - "guu": { - "language": 2519 - }, - "guv": { - "language": 2520 - }, - "guw": { - "language": 2521 - }, - "gux": { - "language": 2522 - }, - "guz": { - "language": 2523 - }, - "gva": { - "language": 2524 - }, - "gvc": { - "language": 2525 - }, - "gve": { - "language": 2526 - }, - "gvf": { - "language": 2527 - }, - "gvj": { - "language": 2528 - }, - "gvl": { - "language": 2529 - }, - "gvm": { - "language": 2530 - }, - "gvn": { - "language": 2531 - }, - "gvo": { - "language": 2532 - }, - "gvp": { - "language": 2533 - }, - "gvr": { - "language": 2534 - }, - "gvs": { - "language": 2535 - }, - "gvy": { - "language": 2536 - }, - "gwa": { - "language": 2537 - }, - "gwb": { - "language": 2538 - }, - "gwc": { - "language": 2539 - }, - "gwd": { - "language": 2540 - }, - "gwe": { - "language": 2541 - }, - "gwf": { - "language": 2542 - }, - "gwg": { - "language": 2543 - }, - "gwi": { - "language": 2544 - }, - "gwj": { - "language": 2545 - }, - "gwm": { - "language": 2546 - }, - "gwn": { - "language": 2547 - }, - "gwr": { - "language": 2548 - }, - "gwt": { - "language": 2549 - }, - "gwu": { - "language": 2550 - }, - "gww": { - "language": 2551 - }, - "gwx": { - "language": 2552 - }, - "gxx": { - "language": 2553 - }, - "gya": { - "language": 2554 - }, - "gyb": { - "language": 2555 - }, - "gyd": { - "language": 2556 - }, - "gye": { - "language": 2557 - }, - "gyf": { - "language": 2558 - }, - "gyg": { - "language": 2559 - }, - "gyi": { - "language": 2560 - }, - "gyl": { - "language": 2561 - }, - "gym": { - "language": 2562 - }, - "gyn": { - "language": 2563 - }, - "gyo": { - "language": 2564 - }, - "gyr": { - "language": 2565 - }, - "gyy": { - "language": 2566 - }, - "gyz": { - "language": 2567 - }, - "gza": { - "language": 2568 - }, - "gzi": { - "language": 2569 - }, - "gzn": { - "language": 2570 - }, - "haa": { - "language": 2571 - }, - "hab": { - "language": 2572, - "extlang": 8331 - }, - "hac": { - "language": 2573 - }, - "had": { - "language": 2574 - }, - "hae": { - "language": 2575 - }, - "haf": { - "language": 2576, - "extlang": 8332 - }, - "hag": { - "language": 2577 - }, - "hah": { - "language": 2578 - }, - "hai": { - "language": 2579 - }, - "haj": { - "language": 2580 - }, - "hak": { - "language": 2581, - "extlang": 8333 - }, - "hal": { - "language": 2582 - }, - "ham": { - "language": 2583 - }, - "han": { - "language": 2584 - }, - "hao": { - "language": 2585 - }, - "hap": { - "language": 2586 - }, - "haq": { - "language": 2587 - }, - "har": { - "language": 2588 - }, - "has": { - "language": 2589 - }, - "hav": { - "language": 2590 - }, - "haw": { - "language": 2591 - }, - "hax": { - "language": 2592 - }, - "hay": { - "language": 2593 - }, - "haz": { - "language": 2594 - }, - "hba": { - "language": 2595 - }, - "hbb": { - "language": 2596 - }, - "hbn": { - "language": 2597 - }, - "hbo": { - "language": 2598 - }, - "hbu": { - "language": 2599 - }, - "hca": { - "language": 2600 - }, - "hch": { - "language": 2601 - }, - "hdn": { - "language": 2602 - }, - "hds": { - "language": 2603, - "extlang": 8334 - }, - "hdy": { - "language": 2604 - }, - "hea": { - "language": 2605 - }, - "hed": { - "language": 2606 - }, - "heg": { - "language": 2607 - }, - "heh": { - "language": 2608 - }, - "hei": { - "language": 2609 - }, - "hem": { - "language": 2610 - }, - "hgm": { - "language": 2611 - }, - "hgw": { - "language": 2612 - }, - "hhi": { - "language": 2613 - }, - "hhr": { - "language": 2614 - }, - "hhy": { - "language": 2615 - }, - "hia": { - "language": 2616 - }, - "hib": { - "language": 2617 - }, - "hid": { - "language": 2618 - }, - "hif": { - "language": 2619 - }, - "hig": { - "language": 2620 - }, - "hih": { - "language": 2621 - }, - "hii": { - "language": 2622 - }, - "hij": { - "language": 2623 - }, - "hik": { - "language": 2624 - }, - "hil": { - "language": 2625 - }, - "him": { - "language": 2626 - }, - "hio": { - "language": 2627 - }, - "hir": { - "language": 2628 - }, - "hit": { - "language": 2629 - }, - "hiw": { - "language": 2630 - }, - "hix": { - "language": 2631 - }, - "hji": { - "language": 2632, - "extlang": 8335 - }, - "hka": { - "language": 2633 - }, - "hke": { - "language": 2634 - }, - "hkh": { - "language": 2635 - }, - "hkk": { - "language": 2636 - }, - "hkn": { - "language": 2637 - }, - "hks": { - "language": 2638, - "extlang": 8336 - }, - "hla": { - "language": 2639 - }, - "hlb": { - "language": 2640 - }, - "hld": { - "language": 2641 - }, - "hle": { - "language": 2642 - }, - "hlt": { - "language": 2643 - }, - "hlu": { - "language": 2644 - }, - "hma": { - "language": 2645 - }, - "hmb": { - "language": 2646 - }, - "hmc": { - "language": 2647 - }, - "hmd": { - "language": 2648 - }, - "hme": { - "language": 2649 - }, - "hmf": { - "language": 2650 - }, - "hmg": { - "language": 2651 - }, - "hmh": { - "language": 2652 - }, - "hmi": { - "language": 2653 - }, - "hmj": { - "language": 2654 - }, - "hmk": { - "language": 2655 - }, - "hml": { - "language": 2656 - }, - "hmm": { - "language": 2657 - }, - "hmn": { - "language": 2658 - }, - "hmp": { - "language": 2659 - }, - "hmq": { - "language": 2660 - }, - "hmr": { - "language": 2661 - }, - "hms": { - "language": 2662 - }, - "hmt": { - "language": 2663 - }, - "hmu": { - "language": 2664 - }, - "hmv": { - "language": 2665 - }, - "hmw": { - "language": 2666 - }, - "hmx": { - "language": 2667 - }, - "hmy": { - "language": 2668 - }, - "hmz": { - "language": 2669 - }, - "hna": { - "language": 2670 - }, - "hnd": { - "language": 2671 - }, - "hne": { - "language": 2672 - }, - "hng": { - "language": 2673 - }, - "hnh": { - "language": 2674 - }, - "hni": { - "language": 2675 - }, - "hnj": { - "language": 2676 - }, - "hnn": { - "language": 2677 - }, - "hno": { - "language": 2678 - }, - "hns": { - "language": 2679 - }, - "hnu": { - "language": 2680 - }, - "hoa": { - "language": 2681 - }, - "hob": { - "language": 2682 - }, - "hoc": { - "language": 2683 - }, - "hod": { - "language": 2684 - }, - "hoe": { - "language": 2685 - }, - "hoh": { - "language": 2686 - }, - "hoi": { - "language": 2687 - }, - "hoj": { - "language": 2688 - }, - "hok": { - "language": 2689 - }, - "hol": { - "language": 2690 - }, - "hom": { - "language": 2691 - }, - "hoo": { - "language": 2692 - }, - "hop": { - "language": 2693 - }, - "hor": { - "language": 2694 - }, - "hos": { - "language": 2695, - "extlang": 8337 - }, - "hot": { - "language": 2696 - }, - "hov": { - "language": 2697 - }, - "how": { - "language": 2698 - }, - "hoy": { - "language": 2699 - }, - "hoz": { - "language": 2700 - }, - "hpo": { - "language": 2701 - }, - "hps": { - "language": 2702, - "extlang": 8338 - }, - "hra": { - "language": 2703 - }, - "hrc": { - "language": 2704 - }, - "hre": { - "language": 2705 - }, - "hrk": { - "language": 2706 - }, - "hrm": { - "language": 2707 - }, - "hro": { - "language": 2708 - }, - "hrp": { - "language": 2709 - }, - "hrr": { - "language": 2710 - }, - "hrt": { - "language": 2711 - }, - "hru": { - "language": 2712 - }, - "hrw": { - "language": 2713 - }, - "hrx": { - "language": 2714 - }, - "hrz": { - "language": 2715 - }, - "hsb": { - "language": 2716 - }, - "hsh": { - "language": 2717, - "extlang": 8339 - }, - "hsl": { - "language": 2718, - "extlang": 8340 - }, - "hsn": { - "language": 2719, - "extlang": 8341 - }, - "hss": { - "language": 2720 - }, - "hti": { - "language": 2721 - }, - "hto": { - "language": 2722 - }, - "hts": { - "language": 2723 - }, - "htu": { - "language": 2724 - }, - "htx": { - "language": 2725 - }, - "hub": { - "language": 2726 - }, - "huc": { - "language": 2727 - }, - "hud": { - "language": 2728 - }, - "hue": { - "language": 2729 - }, - "huf": { - "language": 2730 - }, - "hug": { - "language": 2731 - }, - "huh": { - "language": 2732 - }, - "hui": { - "language": 2733 - }, - "huj": { - "language": 2734 - }, - "huk": { - "language": 2735 - }, - "hul": { - "language": 2736 - }, - "hum": { - "language": 2737 - }, - "huo": { - "language": 2738 - }, - "hup": { - "language": 2739 - }, - "huq": { - "language": 2740 - }, - "hur": { - "language": 2741 - }, - "hus": { - "language": 2742 - }, - "hut": { - "language": 2743 - }, - "huu": { - "language": 2744 - }, - "huv": { - "language": 2745 - }, - "huw": { - "language": 2746 - }, - "hux": { - "language": 2747 - }, - "huy": { - "language": 2748 - }, - "huz": { - "language": 2749 - }, - "hvc": { - "language": 2750 - }, - "hve": { - "language": 2751 - }, - "hvk": { - "language": 2752 - }, - "hvn": { - "language": 2753 - }, - "hvv": { - "language": 2754 - }, - "hwa": { - "language": 2755 - }, - "hwc": { - "language": 2756 - }, - "hwo": { - "language": 2757 - }, - "hya": { - "language": 2758 - }, - "hyw": { - "language": 2759 - }, - "hyx": { - "language": 2760 - }, - "iai": { - "language": 2761 - }, - "ian": { - "language": 2762 - }, - "iap": { - "language": 2763 - }, - "iar": { - "language": 2764 - }, - "iba": { - "language": 2765 - }, - "ibb": { - "language": 2766 - }, - "ibd": { - "language": 2767 - }, - "ibe": { - "language": 2768 - }, - "ibg": { - "language": 2769 - }, - "ibh": { - "language": 2770 - }, - "ibi": { - "language": 2771 - }, - "ibl": { - "language": 2772 - }, - "ibm": { - "language": 2773 - }, - "ibn": { - "language": 2774 - }, - "ibr": { - "language": 2775 - }, - "ibu": { - "language": 2776 - }, - "iby": { - "language": 2777 - }, - "ica": { - "language": 2778 - }, - "ich": { - "language": 2779 - }, - "icl": { - "language": 2780, - "extlang": 8342 - }, - "icr": { - "language": 2781 - }, - "ida": { - "language": 2782 - }, - "idb": { - "language": 2783 - }, - "idc": { - "language": 2784 - }, - "idd": { - "language": 2785 - }, - "ide": { - "language": 2786 - }, - "idi": { - "language": 2787 - }, - "idr": { - "language": 2788 - }, - "ids": { - "language": 2789 - }, - "idt": { - "language": 2790 - }, - "idu": { - "language": 2791 - }, - "ifa": { - "language": 2792 - }, - "ifb": { - "language": 2793 - }, - "ife": { - "language": 2794 - }, - "iff": { - "language": 2795 - }, - "ifk": { - "language": 2796 - }, - "ifm": { - "language": 2797 - }, - "ifu": { - "language": 2798 - }, - "ify": { - "language": 2799 - }, - "igb": { - "language": 2800 - }, - "ige": { - "language": 2801 - }, - "igg": { - "language": 2802 - }, - "igl": { - "language": 2803 - }, - "igm": { - "language": 2804 - }, - "ign": { - "language": 2805 - }, - "igo": { - "language": 2806 - }, - "igs": { - "language": 2807 - }, - "igw": { - "language": 2808 - }, - "ihb": { - "language": 2809 - }, - "ihi": { - "language": 2810 - }, - "ihp": { - "language": 2811 - }, - "ihw": { - "language": 2812 - }, - "iin": { - "language": 2813 - }, - "iir": { - "language": 2814 - }, - "ijc": { - "language": 2815 - }, - "ije": { - "language": 2816 - }, - "ijj": { - "language": 2817 - }, - "ijn": { - "language": 2818 - }, - "ijo": { - "language": 2819 - }, - "ijs": { - "language": 2820 - }, - "ike": { - "language": 2821 - }, - "iki": { - "language": 2822 - }, - "ikk": { - "language": 2823 - }, - "ikl": { - "language": 2824 - }, - "iko": { - "language": 2825 - }, - "ikp": { - "language": 2826 - }, - "ikr": { - "language": 2827 - }, - "iks": { - "language": 2828, - "extlang": 8343 - }, - "ikt": { - "language": 2829 - }, - "ikv": { - "language": 2830 - }, - "ikw": { - "language": 2831 - }, - "ikx": { - "language": 2832 - }, - "ikz": { - "language": 2833 - }, - "ila": { - "language": 2834 - }, - "ilb": { - "language": 2835 - }, - "ilg": { - "language": 2836 - }, - "ili": { - "language": 2837 - }, - "ilk": { - "language": 2838 - }, - "ill": { - "language": 2839 - }, - "ilm": { - "language": 2840 - }, - "ilo": { - "language": 2841 - }, - "ilp": { - "language": 2842 - }, - "ils": { - "language": 2843, - "extlang": 8344 - }, - "ilu": { - "language": 2844 - }, - "ilv": { - "language": 2845 - }, - "ilw": { - "language": 2846 - }, - "ima": { - "language": 2847 - }, - "ime": { - "language": 2848 - }, - "imi": { - "language": 2849 - }, - "iml": { - "language": 2850 - }, - "imn": { - "language": 2851 - }, - "imo": { - "language": 2852 - }, - "imr": { - "language": 2853 - }, - "ims": { - "language": 2854 - }, - "imt": { - "language": 2855 - }, - "imy": { - "language": 2856 - }, - "inb": { - "language": 2857 - }, - "inc": { - "language": 2858 - }, - "ine": { - "language": 2859 - }, - "ing": { - "language": 2860 - }, - "inh": { - "language": 2861 - }, - "inj": { - "language": 2862 - }, - "inl": { - "language": 2863, - "extlang": 8345 - }, - "inm": { - "language": 2864 - }, - "inn": { - "language": 2865 - }, - "ino": { - "language": 2866 - }, - "inp": { - "language": 2867 - }, - "ins": { - "language": 2868, - "extlang": 8346 - }, - "int": { - "language": 2869 - }, - "inz": { - "language": 2870 - }, - "ior": { - "language": 2871 - }, - "iou": { - "language": 2872 - }, - "iow": { - "language": 2873 - }, - "ipi": { - "language": 2874 - }, - "ipo": { - "language": 2875 - }, - "iqu": { - "language": 2876 - }, - "iqw": { - "language": 2877 - }, - "ira": { - "language": 2878 - }, - "ire": { - "language": 2879 - }, - "irh": { - "language": 2880 - }, - "iri": { - "language": 2881 - }, - "irk": { - "language": 2882 - }, - "irn": { - "language": 2883 - }, - "iro": { - "language": 2884 - }, - "irr": { - "language": 2885 - }, - "iru": { - "language": 2886 - }, - "irx": { - "language": 2887 - }, - "iry": { - "language": 2888 - }, - "isa": { - "language": 2889 - }, - "isc": { - "language": 2890 - }, - "isd": { - "language": 2891 - }, - "ise": { - "language": 2892, - "extlang": 8347 - }, - "isg": { - "language": 2893, - "extlang": 8348 - }, - "ish": { - "language": 2894 - }, - "isi": { - "language": 2895 - }, - "isk": { - "language": 2896 - }, - "ism": { - "language": 2897 - }, - "isn": { - "language": 2898 - }, - "iso": { - "language": 2899 - }, - "isr": { - "language": 2900, - "extlang": 8349 - }, - "ist": { - "language": 2901 - }, - "isu": { - "language": 2902 - }, - "itb": { - "language": 2903 - }, - "itc": { - "language": 2904 - }, - "itd": { - "language": 2905 - }, - "ite": { - "language": 2906 - }, - "iti": { - "language": 2907 - }, - "itk": { - "language": 2908 - }, - "itl": { - "language": 2909 - }, - "itm": { - "language": 2910 - }, - "ito": { - "language": 2911 - }, - "itr": { - "language": 2912 - }, - "its": { - "language": 2913 - }, - "itt": { - "language": 2914 - }, - "itv": { - "language": 2915 - }, - "itw": { - "language": 2916 - }, - "itx": { - "language": 2917 - }, - "ity": { - "language": 2918 - }, - "itz": { - "language": 2919 - }, - "ium": { - "language": 2920 - }, - "ivb": { - "language": 2921 - }, - "ivv": { - "language": 2922 - }, - "iwk": { - "language": 2923 - }, - "iwm": { - "language": 2924 - }, - "iwo": { - "language": 2925 - }, - "iws": { - "language": 2926 - }, - "ixc": { - "language": 2927 - }, - "ixl": { - "language": 2928 - }, - "iya": { - "language": 2929 - }, - "iyo": { - "language": 2930 - }, - "iyx": { - "language": 2931 - }, - "izh": { - "language": 2932 - }, - "izi": { - "language": 2933 - }, - "izr": { - "language": 2934 - }, - "izz": { - "language": 2935 - }, - "jaa": { - "language": 2936 - }, - "jab": { - "language": 2937 - }, - "jac": { - "language": 2938 - }, - "jad": { - "language": 2939 - }, - "jae": { - "language": 2940 - }, - "jaf": { - "language": 2941 - }, - "jah": { - "language": 2942 - }, - "jaj": { - "language": 2943 - }, - "jak": { - "language": 2944, - "extlang": 8350 - }, - "jal": { - "language": 2945 - }, - "jam": { - "language": 2946 - }, - "jan": { - "language": 2947 - }, - "jao": { - "language": 2948 - }, - "jaq": { - "language": 2949 - }, - "jar": { - "language": 2950 - }, - "jas": { - "language": 2951 - }, - "jat": { - "language": 2952 - }, - "jau": { - "language": 2953 - }, - "jax": { - "language": 2954, - "extlang": 8351 - }, - "jay": { - "language": 2955 - }, - "jaz": { - "language": 2956 - }, - "jbe": { - "language": 2957 - }, - "jbi": { - "language": 2958 - }, - "jbj": { - "language": 2959 - }, - "jbk": { - "language": 2960 - }, - "jbm": { - "language": 2961 - }, - "jbn": { - "language": 2962 - }, - "jbo": { - "language": 2963 - }, - "jbr": { - "language": 2964 - }, - "jbt": { - "language": 2965 - }, - "jbu": { - "language": 2966 - }, - "jbw": { - "language": 2967 - }, - "jcs": { - "language": 2968, - "extlang": 8352 - }, - "jct": { - "language": 2969 - }, - "jda": { - "language": 2970 - }, - "jdg": { - "language": 2971 - }, - "jdt": { - "language": 2972 - }, - "jeb": { - "language": 2973 - }, - "jee": { - "language": 2974 - }, - "jeg": { - "language": 2975 - }, - "jeh": { - "language": 2976 - }, - "jei": { - "language": 2977 - }, - "jek": { - "language": 2978 - }, - "jel": { - "language": 2979 - }, - "jen": { - "language": 2980 - }, - "jer": { - "language": 2981 - }, - "jet": { - "language": 2982 - }, - "jeu": { - "language": 2983 - }, - "jgb": { - "language": 2984 - }, - "jge": { - "language": 2985 - }, - "jgk": { - "language": 2986 - }, - "jgo": { - "language": 2987 - }, - "jhi": { - "language": 2988 - }, - "jhs": { - "language": 2989, - "extlang": 8353 - }, - "jia": { - "language": 2990 - }, - "jib": { - "language": 2991 - }, - "jic": { - "language": 2992 - }, - "jid": { - "language": 2993 - }, - "jie": { - "language": 2994 - }, - "jig": { - "language": 2995 - }, - "jih": { - "language": 2996 - }, - "jii": { - "language": 2997 - }, - "jil": { - "language": 2998 - }, - "jim": { - "language": 2999 - }, - "jio": { - "language": 3000 - }, - "jiq": { - "language": 3001 - }, - "jit": { - "language": 3002 - }, - "jiu": { - "language": 3003 - }, - "jiv": { - "language": 3004 - }, - "jiy": { - "language": 3005 - }, - "jje": { - "language": 3006 - }, - "jjr": { - "language": 3007 - }, - "jka": { - "language": 3008 - }, - "jkm": { - "language": 3009 - }, - "jko": { - "language": 3010 - }, - "jkp": { - "language": 3011 - }, - "jkr": { - "language": 3012 - }, - "jks": { - "language": 3013, - "extlang": 8354 - }, - "jku": { - "language": 3014 - }, - "jle": { - "language": 3015 - }, - "jls": { - "language": 3016, - "extlang": 8355 - }, - "jma": { - "language": 3017 - }, - "jmb": { - "language": 3018 - }, - "jmc": { - "language": 3019 - }, - "jmd": { - "language": 3020 - }, - "jmi": { - "language": 3021 - }, - "jml": { - "language": 3022 - }, - "jmn": { - "language": 3023 - }, - "jmr": { - "language": 3024 - }, - "jms": { - "language": 3025 - }, - "jmw": { - "language": 3026 - }, - "jmx": { - "language": 3027 - }, - "jna": { - "language": 3028 - }, - "jnd": { - "language": 3029 - }, - "jng": { - "language": 3030 - }, - "jni": { - "language": 3031 - }, - "jnj": { - "language": 3032 - }, - "jnl": { - "language": 3033 - }, - "jns": { - "language": 3034 - }, - "job": { - "language": 3035 - }, - "jod": { - "language": 3036 - }, - "jog": { - "language": 3037 - }, - "jor": { - "language": 3038 - }, - "jos": { - "language": 3039, - "extlang": 8356 - }, - "jow": { - "language": 3040 - }, - "jpa": { - "language": 3041 - }, - "jpr": { - "language": 3042 - }, - "jpx": { - "language": 3043 - }, - "jqr": { - "language": 3044 - }, - "jra": { - "language": 3045 - }, - "jrb": { - "language": 3046 - }, - "jrr": { - "language": 3047 - }, - "jrt": { - "language": 3048 - }, - "jru": { - "language": 3049 - }, - "jsl": { - "language": 3050, - "extlang": 8357 - }, - "jua": { - "language": 3051 - }, - "jub": { - "language": 3052 - }, - "juc": { - "language": 3053 - }, - "jud": { - "language": 3054 - }, - "juh": { - "language": 3055 - }, - "jui": { - "language": 3056 - }, - "juk": { - "language": 3057 - }, - "jul": { - "language": 3058 - }, - "jum": { - "language": 3059 - }, - "jun": { - "language": 3060 - }, - "juo": { - "language": 3061 - }, - "jup": { - "language": 3062 - }, - "jur": { - "language": 3063 - }, - "jus": { - "language": 3064, - "extlang": 8358 - }, - "jut": { - "language": 3065 - }, - "juu": { - "language": 3066 - }, - "juw": { - "language": 3067 - }, - "juy": { - "language": 3068 - }, - "jvd": { - "language": 3069 - }, - "jvn": { - "language": 3070 - }, - "jwi": { - "language": 3071 - }, - "jya": { - "language": 3072 - }, - "jye": { - "language": 3073 - }, - "jyy": { - "language": 3074 - }, - "kaa": { - "language": 3075 - }, - "kab": { - "language": 3076 - }, - "kac": { - "language": 3077 - }, - "kad": { - "language": 3078 - }, - "kae": { - "language": 3079 - }, - "kaf": { - "language": 3080 - }, - "kag": { - "language": 3081 - }, - "kah": { - "language": 3082 - }, - "kai": { - "language": 3083 - }, - "kaj": { - "language": 3084 - }, - "kak": { - "language": 3085 - }, - "kam": { - "language": 3086 - }, - "kao": { - "language": 3087 - }, - "kap": { - "language": 3088 - }, - "kaq": { - "language": 3089 - }, - "kar": { - "language": 3090 - }, - "kav": { - "language": 3091 - }, - "kaw": { - "language": 3092 - }, - "kax": { - "language": 3093 - }, - "kay": { - "language": 3094 - }, - "kba": { - "language": 3095 - }, - "kbb": { - "language": 3096 - }, - "kbc": { - "language": 3097 - }, - "kbd": { - "language": 3098 - }, - "kbe": { - "language": 3099 - }, - "kbf": { - "language": 3100 - }, - "kbg": { - "language": 3101 - }, - "kbh": { - "language": 3102 - }, - "kbi": { - "language": 3103 - }, - "kbj": { - "language": 3104 - }, - "kbk": { - "language": 3105 - }, - "kbl": { - "language": 3106 - }, - "kbm": { - "language": 3107 - }, - "kbn": { - "language": 3108 - }, - "kbo": { - "language": 3109 - }, - "kbp": { - "language": 3110 - }, - "kbq": { - "language": 3111 - }, - "kbr": { - "language": 3112 - }, - "kbs": { - "language": 3113 - }, - "kbt": { - "language": 3114 - }, - "kbu": { - "language": 3115 - }, - "kbv": { - "language": 3116 - }, - "kbw": { - "language": 3117 - }, - "kbx": { - "language": 3118 - }, - "kby": { - "language": 3119 - }, - "kbz": { - "language": 3120 - }, - "kca": { - "language": 3121 - }, - "kcb": { - "language": 3122 - }, - "kcc": { - "language": 3123 - }, - "kcd": { - "language": 3124 - }, - "kce": { - "language": 3125 - }, - "kcf": { - "language": 3126 - }, - "kcg": { - "language": 3127 - }, - "kch": { - "language": 3128 - }, - "kci": { - "language": 3129 - }, - "kcj": { - "language": 3130 - }, - "kck": { - "language": 3131 - }, - "kcl": { - "language": 3132 - }, - "kcm": { - "language": 3133 - }, - "kcn": { - "language": 3134 - }, - "kco": { - "language": 3135 - }, - "kcp": { - "language": 3136 - }, - "kcq": { - "language": 3137 - }, - "kcr": { - "language": 3138 - }, - "kcs": { - "language": 3139 - }, - "kct": { - "language": 3140 - }, - "kcu": { - "language": 3141 - }, - "kcv": { - "language": 3142 - }, - "kcw": { - "language": 3143 - }, - "kcx": { - "language": 3144 - }, - "kcy": { - "language": 3145 - }, - "kcz": { - "language": 3146 - }, - "kda": { - "language": 3147 - }, - "kdc": { - "language": 3148 - }, - "kdd": { - "language": 3149 - }, - "kde": { - "language": 3150 - }, - "kdf": { - "language": 3151 - }, - "kdg": { - "language": 3152 - }, - "kdh": { - "language": 3153 - }, - "kdi": { - "language": 3154 - }, - "kdj": { - "language": 3155 - }, - "kdk": { - "language": 3156 - }, - "kdl": { - "language": 3157 - }, - "kdm": { - "language": 3158 - }, - "kdn": { - "language": 3159 - }, - "kdo": { - "language": 3160 - }, - "kdp": { - "language": 3161 - }, - "kdq": { - "language": 3162 - }, - "kdr": { - "language": 3163 - }, - "kdt": { - "language": 3164 - }, - "kdu": { - "language": 3165 - }, - "kdv": { - "language": 3166 - }, - "kdw": { - "language": 3167 - }, - "kdx": { - "language": 3168 - }, - "kdy": { - "language": 3169 - }, - "kdz": { - "language": 3170 - }, - "kea": { - "language": 3171 - }, - "keb": { - "language": 3172 - }, - "kec": { - "language": 3173 - }, - "ked": { - "language": 3174 - }, - "kee": { - "language": 3175 - }, - "kef": { - "language": 3176 - }, - "keg": { - "language": 3177 - }, - "keh": { - "language": 3178 - }, - "kei": { - "language": 3179 - }, - "kej": { - "language": 3180 - }, - "kek": { - "language": 3181 - }, - "kel": { - "language": 3182 - }, - "kem": { - "language": 3183 - }, - "ken": { - "language": 3184 - }, - "keo": { - "language": 3185 - }, - "kep": { - "language": 3186 - }, - "keq": { - "language": 3187 - }, - "ker": { - "language": 3188 - }, - "kes": { - "language": 3189 - }, - "ket": { - "language": 3190 - }, - "keu": { - "language": 3191 - }, - "kev": { - "language": 3192 - }, - "kew": { - "language": 3193 - }, - "kex": { - "language": 3194 - }, - "key": { - "language": 3195 - }, - "kez": { - "language": 3196 - }, - "kfa": { - "language": 3197 - }, - "kfb": { - "language": 3198 - }, - "kfc": { - "language": 3199 - }, - "kfd": { - "language": 3200 - }, - "kfe": { - "language": 3201 - }, - "kff": { - "language": 3202 - }, - "kfg": { - "language": 3203 - }, - "kfh": { - "language": 3204 - }, - "kfi": { - "language": 3205 - }, - "kfj": { - "language": 3206 - }, - "kfk": { - "language": 3207 - }, - "kfl": { - "language": 3208 - }, - "kfm": { - "language": 3209 - }, - "kfn": { - "language": 3210 - }, - "kfo": { - "language": 3211 - }, - "kfp": { - "language": 3212 - }, - "kfq": { - "language": 3213 - }, - "kfr": { - "language": 3214 - }, - "kfs": { - "language": 3215 - }, - "kft": { - "language": 3216 - }, - "kfu": { - "language": 3217 - }, - "kfv": { - "language": 3218 - }, - "kfw": { - "language": 3219 - }, - "kfx": { - "language": 3220 - }, - "kfy": { - "language": 3221 - }, - "kfz": { - "language": 3222 - }, - "kga": { - "language": 3223 - }, - "kgb": { - "language": 3224 - }, - "kgc": { - "language": 3225 - }, - "kgd": { - "language": 3226 - }, - "kge": { - "language": 3227 - }, - "kgf": { - "language": 3228 - }, - "kgg": { - "language": 3229 - }, - "kgh": { - "language": 3230 - }, - "kgi": { - "language": 3231, - "extlang": 8359 - }, - "kgj": { - "language": 3232 - }, - "kgk": { - "language": 3233 - }, - "kgl": { - "language": 3234 - }, - "kgm": { - "language": 3235 - }, - "kgn": { - "language": 3236 - }, - "kgo": { - "language": 3237 - }, - "kgp": { - "language": 3238 - }, - "kgq": { - "language": 3239 - }, - "kgr": { - "language": 3240 - }, - "kgs": { - "language": 3241 - }, - "kgt": { - "language": 3242 - }, - "kgu": { - "language": 3243 - }, - "kgv": { - "language": 3244 - }, - "kgw": { - "language": 3245 - }, - "kgx": { - "language": 3246 - }, - "kgy": { - "language": 3247 - }, - "kha": { - "language": 3248 - }, - "khb": { - "language": 3249 - }, - "khc": { - "language": 3250 - }, - "khd": { - "language": 3251 - }, - "khe": { - "language": 3252 - }, - "khf": { - "language": 3253 - }, - "khg": { - "language": 3254 - }, - "khh": { - "language": 3255 - }, - "khi": { - "language": 3256 - }, - "khj": { - "language": 3257 - }, - "khk": { - "language": 3258 - }, - "khl": { - "language": 3259 - }, - "khn": { - "language": 3260 - }, - "kho": { - "language": 3261 - }, - "khp": { - "language": 3262 - }, - "khq": { - "language": 3263 - }, - "khr": { - "language": 3264 - }, - "khs": { - "language": 3265 - }, - "kht": { - "language": 3266 - }, - "khu": { - "language": 3267 - }, - "khv": { - "language": 3268 - }, - "khw": { - "language": 3269 - }, - "khx": { - "language": 3270 - }, - "khy": { - "language": 3271 - }, - "khz": { - "language": 3272 - }, - "kia": { - "language": 3273 - }, - "kib": { - "language": 3274 - }, - "kic": { - "language": 3275 - }, - "kid": { - "language": 3276 - }, - "kie": { - "language": 3277 - }, - "kif": { - "language": 3278 - }, - "kig": { - "language": 3279 - }, - "kih": { - "language": 3280 - }, - "kii": { - "language": 3281 - }, - "kij": { - "language": 3282 - }, - "kil": { - "language": 3283 - }, - "kim": { - "language": 3284 - }, - "kio": { - "language": 3285 - }, - "kip": { - "language": 3286 - }, - "kiq": { - "language": 3287 - }, - "kis": { - "language": 3288 - }, - "kit": { - "language": 3289 - }, - "kiu": { - "language": 3290 - }, - "kiv": { - "language": 3291 - }, - "kiw": { - "language": 3292 - }, - "kix": { - "language": 3293 - }, - "kiy": { - "language": 3294 - }, - "kiz": { - "language": 3295 - }, - "kja": { - "language": 3296 - }, - "kjb": { - "language": 3297 - }, - "kjc": { - "language": 3298 - }, - "kjd": { - "language": 3299 - }, - "kje": { - "language": 3300 - }, - "kjf": { - "language": 3301 - }, - "kjg": { - "language": 3302 - }, - "kjh": { - "language": 3303 - }, - "kji": { - "language": 3304 - }, - "kjj": { - "language": 3305 - }, - "kjk": { - "language": 3306 - }, - "kjl": { - "language": 3307 - }, - "kjm": { - "language": 3308 - }, - "kjn": { - "language": 3309 - }, - "kjo": { - "language": 3310 - }, - "kjp": { - "language": 3311 - }, - "kjq": { - "language": 3312 - }, - "kjr": { - "language": 3313 - }, - "kjs": { - "language": 3314 - }, - "kjt": { - "language": 3315 - }, - "kju": { - "language": 3316 - }, - "kjv": { - "language": 3317 - }, - "kjx": { - "language": 3318 - }, - "kjy": { - "language": 3319 - }, - "kjz": { - "language": 3320 - }, - "kka": { - "language": 3321 - }, - "kkb": { - "language": 3322 - }, - "kkc": { - "language": 3323 - }, - "kkd": { - "language": 3324 - }, - "kke": { - "language": 3325 - }, - "kkf": { - "language": 3326 - }, - "kkg": { - "language": 3327 - }, - "kkh": { - "language": 3328 - }, - "kki": { - "language": 3329 - }, - "kkj": { - "language": 3330 - }, - "kkk": { - "language": 3331 - }, - "kkl": { - "language": 3332 - }, - "kkm": { - "language": 3333 - }, - "kkn": { - "language": 3334 - }, - "kko": { - "language": 3335 - }, - "kkp": { - "language": 3336 - }, - "kkq": { - "language": 3337 - }, - "kkr": { - "language": 3338 - }, - "kks": { - "language": 3339 - }, - "kkt": { - "language": 3340 - }, - "kku": { - "language": 3341 - }, - "kkv": { - "language": 3342 - }, - "kkw": { - "language": 3343 - }, - "kkx": { - "language": 3344 - }, - "kky": { - "language": 3345 - }, - "kkz": { - "language": 3346 - }, - "kla": { - "language": 3347 - }, - "klb": { - "language": 3348 - }, - "klc": { - "language": 3349 - }, - "kld": { - "language": 3350 - }, - "kle": { - "language": 3351 - }, - "klf": { - "language": 3352 - }, - "klg": { - "language": 3353 - }, - "klh": { - "language": 3354 - }, - "kli": { - "language": 3355 - }, - "klj": { - "language": 3356 - }, - "klk": { - "language": 3357 - }, - "kll": { - "language": 3358 - }, - "klm": { - "language": 3359 - }, - "kln": { - "language": 3360 - }, - "klo": { - "language": 3361 - }, - "klp": { - "language": 3362 - }, - "klq": { - "language": 3363 - }, - "klr": { - "language": 3364 - }, - "kls": { - "language": 3365 - }, - "klt": { - "language": 3366 - }, - "klu": { - "language": 3367 - }, - "klv": { - "language": 3368 - }, - "klw": { - "language": 3369 - }, - "klx": { - "language": 3370 - }, - "kly": { - "language": 3371 - }, - "klz": { - "language": 3372 - }, - "kma": { - "language": 3373 - }, - "kmb": { - "language": 3374 - }, - "kmc": { - "language": 3375 - }, - "kmd": { - "language": 3376 - }, - "kme": { - "language": 3377 - }, - "kmf": { - "language": 3378 - }, - "kmg": { - "language": 3379 - }, - "kmh": { - "language": 3380 - }, - "kmi": { - "language": 3381 - }, - "kmj": { - "language": 3382 - }, - "kmk": { - "language": 3383 - }, - "kml": { - "language": 3384 - }, - "kmm": { - "language": 3385 - }, - "kmn": { - "language": 3386 - }, - "kmo": { - "language": 3387 - }, - "kmp": { - "language": 3388 - }, - "kmq": { - "language": 3389 - }, - "kmr": { - "language": 3390 - }, - "kms": { - "language": 3391 - }, - "kmt": { - "language": 3392 - }, - "kmu": { - "language": 3393 - }, - "kmv": { - "language": 3394 - }, - "kmw": { - "language": 3395 - }, - "kmx": { - "language": 3396 - }, - "kmy": { - "language": 3397 - }, - "kmz": { - "language": 3398 - }, - "kna": { - "language": 3399 - }, - "knb": { - "language": 3400 - }, - "knc": { - "language": 3401 - }, - "knd": { - "language": 3402 - }, - "kne": { - "language": 3403 - }, - "knf": { - "language": 3404 - }, - "kng": { - "language": 3405 - }, - "kni": { - "language": 3406 - }, - "knj": { - "language": 3407 - }, - "knk": { - "language": 3408 - }, - "knl": { - "language": 3409 - }, - "knm": { - "language": 3410 - }, - "knn": { - "language": 3411, - "extlang": 8360 - }, - "kno": { - "language": 3412 - }, - "knp": { - "language": 3413 - }, - "knq": { - "language": 3414 - }, - "knr": { - "language": 3415 - }, - "kns": { - "language": 3416 - }, - "knt": { - "language": 3417 - }, - "knu": { - "language": 3418 - }, - "knv": { - "language": 3419 - }, - "knw": { - "language": 3420 - }, - "knx": { - "language": 3421 - }, - "kny": { - "language": 3422 - }, - "knz": { - "language": 3423 - }, - "koa": { - "language": 3424 - }, - "koc": { - "language": 3425 - }, - "kod": { - "language": 3426 - }, - "koe": { - "language": 3427 - }, - "kof": { - "language": 3428 - }, - "kog": { - "language": 3429 - }, - "koh": { - "language": 3430 - }, - "koi": { - "language": 3431 - }, - "koj": { - "language": 3432 - }, - "kok": { - "language": 3433 - }, - "kol": { - "language": 3434 - }, - "koo": { - "language": 3435 - }, - "kop": { - "language": 3436 - }, - "koq": { - "language": 3437 - }, - "kos": { - "language": 3438 - }, - "kot": { - "language": 3439 - }, - "kou": { - "language": 3440 - }, - "kov": { - "language": 3441 - }, - "kow": { - "language": 3442 - }, - "kox": { - "language": 3443 - }, - "koy": { - "language": 3444 - }, - "koz": { - "language": 3445 - }, - "kpa": { - "language": 3446 - }, - "kpb": { - "language": 3447 - }, - "kpc": { - "language": 3448 - }, - "kpd": { - "language": 3449 - }, - "kpe": { - "language": 3450 - }, - "kpf": { - "language": 3451 - }, - "kpg": { - "language": 3452 - }, - "kph": { - "language": 3453 - }, - "kpi": { - "language": 3454 - }, - "kpj": { - "language": 3455 - }, - "kpk": { - "language": 3456 - }, - "kpl": { - "language": 3457 - }, - "kpm": { - "language": 3458 - }, - "kpn": { - "language": 3459 - }, - "kpo": { - "language": 3460 - }, - "kpp": { - "language": 3461 - }, - "kpq": { - "language": 3462 - }, - "kpr": { - "language": 3463 - }, - "kps": { - "language": 3464 - }, - "kpt": { - "language": 3465 - }, - "kpu": { - "language": 3466 - }, - "kpv": { - "language": 3467 - }, - "kpw": { - "language": 3468 - }, - "kpx": { - "language": 3469 - }, - "kpy": { - "language": 3470 - }, - "kpz": { - "language": 3471 - }, - "kqa": { - "language": 3472 - }, - "kqb": { - "language": 3473 - }, - "kqc": { - "language": 3474 - }, - "kqd": { - "language": 3475 - }, - "kqe": { - "language": 3476 - }, - "kqf": { - "language": 3477 - }, - "kqg": { - "language": 3478 - }, - "kqh": { - "language": 3479 - }, - "kqi": { - "language": 3480 - }, - "kqj": { - "language": 3481 - }, - "kqk": { - "language": 3482 - }, - "kql": { - "language": 3483 - }, - "kqm": { - "language": 3484 - }, - "kqn": { - "language": 3485 - }, - "kqo": { - "language": 3486 - }, - "kqp": { - "language": 3487 - }, - "kqq": { - "language": 3488 - }, - "kqr": { - "language": 3489 - }, - "kqs": { - "language": 3490 - }, - "kqt": { - "language": 3491 - }, - "kqu": { - "language": 3492 - }, - "kqv": { - "language": 3493 - }, - "kqw": { - "language": 3494 - }, - "kqx": { - "language": 3495 - }, - "kqy": { - "language": 3496 - }, - "kqz": { - "language": 3497 - }, - "kra": { - "language": 3498 - }, - "krb": { - "language": 3499 - }, - "krc": { - "language": 3500 - }, - "krd": { - "language": 3501 - }, - "kre": { - "language": 3502 - }, - "krf": { - "language": 3503 - }, - "krh": { - "language": 3504 - }, - "kri": { - "language": 3505 - }, - "krj": { - "language": 3506 - }, - "krk": { - "language": 3507 - }, - "krl": { - "language": 3508 - }, - "krm": { - "language": 3509 - }, - "krn": { - "language": 3510 - }, - "kro": { - "language": 3511 - }, - "krp": { - "language": 3512 - }, - "krr": { - "language": 3513 - }, - "krs": { - "language": 3514 - }, - "krt": { - "language": 3515 - }, - "kru": { - "language": 3516 - }, - "krv": { - "language": 3517 - }, - "krw": { - "language": 3518 - }, - "krx": { - "language": 3519 - }, - "kry": { - "language": 3520 - }, - "krz": { - "language": 3521 - }, - "ksa": { - "language": 3522 - }, - "ksb": { - "language": 3523 - }, - "ksc": { - "language": 3524 - }, - "ksd": { - "language": 3525 - }, - "kse": { - "language": 3526 - }, - "ksf": { - "language": 3527 - }, - "ksg": { - "language": 3528 - }, - "ksh": { - "language": 3529 - }, - "ksi": { - "language": 3530 - }, - "ksj": { - "language": 3531 - }, - "ksk": { - "language": 3532 - }, - "ksl": { - "language": 3533 - }, - "ksm": { - "language": 3534 - }, - "ksn": { - "language": 3535 - }, - "kso": { - "language": 3536 - }, - "ksp": { - "language": 3537 - }, - "ksq": { - "language": 3538 - }, - "ksr": { - "language": 3539 - }, - "kss": { - "language": 3540 - }, - "kst": { - "language": 3541 - }, - "ksu": { - "language": 3542 - }, - "ksv": { - "language": 3543 - }, - "ksw": { - "language": 3544 - }, - "ksx": { - "language": 3545 - }, - "ksy": { - "language": 3546 - }, - "ksz": { - "language": 3547 - }, - "kta": { - "language": 3548 - }, - "ktb": { - "language": 3549 - }, - "ktc": { - "language": 3550 - }, - "ktd": { - "language": 3551 - }, - "kte": { - "language": 3552 - }, - "ktf": { - "language": 3553 - }, - "ktg": { - "language": 3554 - }, - "kth": { - "language": 3555 - }, - "kti": { - "language": 3556 - }, - "ktj": { - "language": 3557 - }, - "ktk": { - "language": 3558 - }, - "ktl": { - "language": 3559 - }, - "ktm": { - "language": 3560 - }, - "ktn": { - "language": 3561 - }, - "kto": { - "language": 3562 - }, - "ktp": { - "language": 3563 - }, - "ktq": { - "language": 3564 - }, - "ktr": { - "language": 3565 - }, - "kts": { - "language": 3566 - }, - "ktt": { - "language": 3567 - }, - "ktu": { - "language": 3568 - }, - "ktv": { - "language": 3569 - }, - "ktw": { - "language": 3570 - }, - "ktx": { - "language": 3571 - }, - "kty": { - "language": 3572 - }, - "ktz": { - "language": 3573 - }, - "kub": { - "language": 3574 - }, - "kuc": { - "language": 3575 - }, - "kud": { - "language": 3576 - }, - "kue": { - "language": 3577 - }, - "kuf": { - "language": 3578 - }, - "kug": { - "language": 3579 - }, - "kuh": { - "language": 3580 - }, - "kui": { - "language": 3581 - }, - "kuj": { - "language": 3582 - }, - "kuk": { - "language": 3583 - }, - "kul": { - "language": 3584 - }, - "kum": { - "language": 3585 - }, - "kun": { - "language": 3586 - }, - "kuo": { - "language": 3587 - }, - "kup": { - "language": 3588 - }, - "kuq": { - "language": 3589 - }, - "kus": { - "language": 3590 - }, - "kut": { - "language": 3591 - }, - "kuu": { - "language": 3592 - }, - "kuv": { - "language": 3593 - }, - "kuw": { - "language": 3594 - }, - "kux": { - "language": 3595 - }, - "kuy": { - "language": 3596 - }, - "kuz": { - "language": 3597 - }, - "kva": { - "language": 3598 - }, - "kvb": { - "language": 3599, - "extlang": 8361 - }, - "kvc": { - "language": 3600 - }, - "kvd": { - "language": 3601 - }, - "kve": { - "language": 3602 - }, - "kvf": { - "language": 3603 - }, - "kvg": { - "language": 3604 - }, - "kvh": { - "language": 3605 - }, - "kvi": { - "language": 3606 - }, - "kvj": { - "language": 3607 - }, - "kvk": { - "language": 3608, - "extlang": 8362 - }, - "kvl": { - "language": 3609 - }, - "kvm": { - "language": 3610 - }, - "kvn": { - "language": 3611 - }, - "kvo": { - "language": 3612 - }, - "kvp": { - "language": 3613 - }, - "kvq": { - "language": 3614 - }, - "kvr": { - "language": 3615, - "extlang": 8363 - }, - "kvs": { - "language": 3616 - }, - "kvt": { - "language": 3617 - }, - "kvu": { - "language": 3618 - }, - "kvv": { - "language": 3619 - }, - "kvw": { - "language": 3620 - }, - "kvx": { - "language": 3621 - }, - "kvy": { - "language": 3622 - }, - "kvz": { - "language": 3623 - }, - "kwa": { - "language": 3624 - }, - "kwb": { - "language": 3625 - }, - "kwc": { - "language": 3626 - }, - "kwd": { - "language": 3627 - }, - "kwe": { - "language": 3628 - }, - "kwf": { - "language": 3629 - }, - "kwg": { - "language": 3630 - }, - "kwh": { - "language": 3631 - }, - "kwi": { - "language": 3632 - }, - "kwj": { - "language": 3633 - }, - "kwk": { - "language": 3634 - }, - "kwl": { - "language": 3635 - }, - "kwm": { - "language": 3636 - }, - "kwn": { - "language": 3637 - }, - "kwo": { - "language": 3638 - }, - "kwp": { - "language": 3639 - }, - "kwq": { - "language": 3640 - }, - "kwr": { - "language": 3641 - }, - "kws": { - "language": 3642 - }, - "kwt": { - "language": 3643 - }, - "kwu": { - "language": 3644 - }, - "kwv": { - "language": 3645 - }, - "kww": { - "language": 3646 - }, - "kwx": { - "language": 3647 - }, - "kwy": { - "language": 3648 - }, - "kwz": { - "language": 3649 - }, - "kxa": { - "language": 3650 - }, - "kxb": { - "language": 3651 - }, - "kxc": { - "language": 3652 - }, - "kxd": { - "language": 3653, - "extlang": 8364 - }, - "kxe": { - "language": 3654 - }, - "kxf": { - "language": 3655 - }, - "kxh": { - "language": 3656 - }, - "kxi": { - "language": 3657 - }, - "kxj": { - "language": 3658 - }, - "kxk": { - "language": 3659 - }, - "kxl": { - "language": 3660 - }, - "kxm": { - "language": 3661 - }, - "kxn": { - "language": 3662 - }, - "kxo": { - "language": 3663 - }, - "kxp": { - "language": 3664 - }, - "kxq": { - "language": 3665 - }, - "kxr": { - "language": 3666 - }, - "kxs": { - "language": 3667 - }, - "kxt": { - "language": 3668 - }, - "kxu": { - "language": 3669 - }, - "kxv": { - "language": 3670 - }, - "kxw": { - "language": 3671 - }, - "kxx": { - "language": 3672 - }, - "kxy": { - "language": 3673 - }, - "kxz": { - "language": 3674 - }, - "kya": { - "language": 3675 - }, - "kyb": { - "language": 3676 - }, - "kyc": { - "language": 3677 - }, - "kyd": { - "language": 3678 - }, - "kye": { - "language": 3679 - }, - "kyf": { - "language": 3680 - }, - "kyg": { - "language": 3681 - }, - "kyh": { - "language": 3682 - }, - "kyi": { - "language": 3683 - }, - "kyj": { - "language": 3684 - }, - "kyk": { - "language": 3685 - }, - "kyl": { - "language": 3686 - }, - "kym": { - "language": 3687 - }, - "kyn": { - "language": 3688 - }, - "kyo": { - "language": 3689 - }, - "kyp": { - "language": 3690 - }, - "kyq": { - "language": 3691 - }, - "kyr": { - "language": 3692 - }, - "kys": { - "language": 3693 - }, - "kyt": { - "language": 3694 - }, - "kyu": { - "language": 3695 - }, - "kyv": { - "language": 3696 - }, - "kyw": { - "language": 3697 - }, - "kyx": { - "language": 3698 - }, - "kyy": { - "language": 3699 - }, - "kyz": { - "language": 3700 - }, - "kza": { - "language": 3701 - }, - "kzb": { - "language": 3702 - }, - "kzc": { - "language": 3703 - }, - "kzd": { - "language": 3704 - }, - "kze": { - "language": 3705 - }, - "kzf": { - "language": 3706 - }, - "kzg": { - "language": 3707 - }, - "kzh": { - "language": 3708 - }, - "kzi": { - "language": 3709 - }, - "kzj": { - "language": 3710 - }, - "kzk": { - "language": 3711 - }, - "kzl": { - "language": 3712 - }, - "kzm": { - "language": 3713 - }, - "kzn": { - "language": 3714 - }, - "kzo": { - "language": 3715 - }, - "kzp": { - "language": 3716 - }, - "kzq": { - "language": 3717 - }, - "kzr": { - "language": 3718 - }, - "kzs": { - "language": 3719 - }, - "kzt": { - "language": 3720 - }, - "kzu": { - "language": 3721 - }, - "kzv": { - "language": 3722 - }, - "kzw": { - "language": 3723 - }, - "kzx": { - "language": 3724 - }, - "kzy": { - "language": 3725 - }, - "kzz": { - "language": 3726 - }, - "laa": { - "language": 3727 - }, - "lab": { - "language": 3728 - }, - "lac": { - "language": 3729 - }, - "lad": { - "language": 3730 - }, - "lae": { - "language": 3731 - }, - "laf": { - "language": 3732 - }, - "lag": { - "language": 3733 - }, - "lah": { - "language": 3734 - }, - "lai": { - "language": 3735 - }, - "laj": { - "language": 3736 - }, - "lak": { - "language": 3737 - }, - "lal": { - "language": 3738 - }, - "lam": { - "language": 3739 - }, - "lan": { - "language": 3740 - }, - "lap": { - "language": 3741 - }, - "laq": { - "language": 3742 - }, - "lar": { - "language": 3743 - }, - "las": { - "language": 3744 - }, - "lau": { - "language": 3745 - }, - "law": { - "language": 3746 - }, - "lax": { - "language": 3747 - }, - "lay": { - "language": 3748 - }, - "laz": { - "language": 3749 - }, - "lba": { - "language": 3750 - }, - "lbb": { - "language": 3751 - }, - "lbc": { - "language": 3752 - }, - "lbe": { - "language": 3753 - }, - "lbf": { - "language": 3754 - }, - "lbg": { - "language": 3755 - }, - "lbi": { - "language": 3756 - }, - "lbj": { - "language": 3757 - }, - "lbk": { - "language": 3758 - }, - "lbl": { - "language": 3759 - }, - "lbm": { - "language": 3760 - }, - "lbn": { - "language": 3761 - }, - "lbo": { - "language": 3762 - }, - "lbq": { - "language": 3763 - }, - "lbr": { - "language": 3764 - }, - "lbs": { - "language": 3765, - "extlang": 8365 - }, - "lbt": { - "language": 3766 - }, - "lbu": { - "language": 3767 - }, - "lbv": { - "language": 3768 - }, - "lbw": { - "language": 3769 - }, - "lbx": { - "language": 3770 - }, - "lby": { - "language": 3771 - }, - "lbz": { - "language": 3772 - }, - "lcc": { - "language": 3773 - }, - "lcd": { - "language": 3774 - }, - "lce": { - "language": 3775, - "extlang": 8366 - }, - "lcf": { - "language": 3776, - "extlang": 8367 - }, - "lch": { - "language": 3777 - }, - "lcl": { - "language": 3778 - }, - "lcm": { - "language": 3779 - }, - "lcp": { - "language": 3780 - }, - "lcq": { - "language": 3781 - }, - "lcs": { - "language": 3782 - }, - "lda": { - "language": 3783 - }, - "ldb": { - "language": 3784 - }, - "ldd": { - "language": 3785 - }, - "ldg": { - "language": 3786 - }, - "ldh": { - "language": 3787 - }, - "ldi": { - "language": 3788 - }, - "ldj": { - "language": 3789 - }, - "ldk": { - "language": 3790 - }, - "ldl": { - "language": 3791 - }, - "ldm": { - "language": 3792 - }, - "ldn": { - "language": 3793 - }, - "ldo": { - "language": 3794 - }, - "ldp": { - "language": 3795 - }, - "ldq": { - "language": 3796 - }, - "lea": { - "language": 3797 - }, - "leb": { - "language": 3798 - }, - "lec": { - "language": 3799 - }, - "led": { - "language": 3800 - }, - "lee": { - "language": 3801 - }, - "lef": { - "language": 3802 - }, - "leg": { - "language": 3803 - }, - "leh": { - "language": 3804 - }, - "lei": { - "language": 3805 - }, - "lej": { - "language": 3806 - }, - "lek": { - "language": 3807 - }, - "lel": { - "language": 3808 - }, - "lem": { - "language": 3809 - }, - "len": { - "language": 3810 - }, - "leo": { - "language": 3811 - }, - "lep": { - "language": 3812 - }, - "leq": { - "language": 3813 - }, - "ler": { - "language": 3814 - }, - "les": { - "language": 3815 - }, - "let": { - "language": 3816 - }, - "leu": { - "language": 3817 - }, - "lev": { - "language": 3818 - }, - "lew": { - "language": 3819 - }, - "lex": { - "language": 3820 - }, - "ley": { - "language": 3821 - }, - "lez": { - "language": 3822 - }, - "lfa": { - "language": 3823 - }, - "lfn": { - "language": 3824 - }, - "lga": { - "language": 3825 - }, - "lgb": { - "language": 3826 - }, - "lgg": { - "language": 3827 - }, - "lgh": { - "language": 3828 - }, - "lgi": { - "language": 3829 - }, - "lgk": { - "language": 3830 - }, - "lgl": { - "language": 3831 - }, - "lgm": { - "language": 3832 - }, - "lgn": { - "language": 3833 - }, - "lgo": { - "language": 3834 - }, - "lgq": { - "language": 3835 - }, - "lgr": { - "language": 3836 - }, - "lgt": { - "language": 3837 - }, - "lgu": { - "language": 3838 - }, - "lgz": { - "language": 3839 - }, - "lha": { - "language": 3840 - }, - "lhh": { - "language": 3841 - }, - "lhi": { - "language": 3842 - }, - "lhl": { - "language": 3843 - }, - "lhm": { - "language": 3844 - }, - "lhn": { - "language": 3845 - }, - "lhp": { - "language": 3846 - }, - "lhs": { - "language": 3847 - }, - "lht": { - "language": 3848 - }, - "lhu": { - "language": 3849 - }, - "lia": { - "language": 3850 - }, - "lib": { - "language": 3851 - }, - "lic": { - "language": 3852 - }, - "lid": { - "language": 3853 - }, - "lie": { - "language": 3854 - }, - "lif": { - "language": 3855 - }, - "lig": { - "language": 3856 - }, - "lih": { - "language": 3857 - }, - "lii": { - "language": 3858 - }, - "lij": { - "language": 3859 - }, - "lik": { - "language": 3860 - }, - "lil": { - "language": 3861 - }, - "lio": { - "language": 3862 - }, - "lip": { - "language": 3863 - }, - "liq": { - "language": 3864 - }, - "lir": { - "language": 3865 - }, - "lis": { - "language": 3866 - }, - "liu": { - "language": 3867 - }, - "liv": { - "language": 3868 - }, - "liw": { - "language": 3869, - "extlang": 8368 - }, - "lix": { - "language": 3870 - }, - "liy": { - "language": 3871 - }, - "liz": { - "language": 3872 - }, - "lja": { - "language": 3873 - }, - "lje": { - "language": 3874 - }, - "lji": { - "language": 3875 - }, - "ljl": { - "language": 3876 - }, - "ljp": { - "language": 3877 - }, - "ljw": { - "language": 3878 - }, - "ljx": { - "language": 3879 - }, - "lka": { - "language": 3880 - }, - "lkb": { - "language": 3881 - }, - "lkc": { - "language": 3882 - }, - "lkd": { - "language": 3883 - }, - "lke": { - "language": 3884 - }, - "lkh": { - "language": 3885 - }, - "lki": { - "language": 3886 - }, - "lkj": { - "language": 3887 - }, - "lkl": { - "language": 3888 - }, - "lkm": { - "language": 3889 - }, - "lkn": { - "language": 3890 - }, - "lko": { - "language": 3891 - }, - "lkr": { - "language": 3892 - }, - "lks": { - "language": 3893 - }, - "lkt": { - "language": 3894 - }, - "lku": { - "language": 3895 - }, - "lky": { - "language": 3896 - }, - "lla": { - "language": 3897 - }, - "llb": { - "language": 3898 - }, - "llc": { - "language": 3899 - }, - "lld": { - "language": 3900 - }, - "lle": { - "language": 3901 - }, - "llf": { - "language": 3902 - }, - "llg": { - "language": 3903 - }, - "llh": { - "language": 3904 - }, - "lli": { - "language": 3905 - }, - "llj": { - "language": 3906 - }, - "llk": { - "language": 3907 - }, - "lll": { - "language": 3908 - }, - "llm": { - "language": 3909 - }, - "lln": { - "language": 3910 - }, - "llo": { - "language": 3911 - }, - "llp": { - "language": 3912 - }, - "llq": { - "language": 3913 - }, - "lls": { - "language": 3914, - "extlang": 8369 - }, - "llu": { - "language": 3915 - }, - "llx": { - "language": 3916 - }, - "lma": { - "language": 3917 - }, - "lmb": { - "language": 3918 - }, - "lmc": { - "language": 3919 - }, - "lmd": { - "language": 3920 - }, - "lme": { - "language": 3921 - }, - "lmf": { - "language": 3922 - }, - "lmg": { - "language": 3923 - }, - "lmh": { - "language": 3924 - }, - "lmi": { - "language": 3925 - }, - "lmj": { - "language": 3926 - }, - "lmk": { - "language": 3927 - }, - "lml": { - "language": 3928 - }, - "lmm": { - "language": 3929 - }, - "lmn": { - "language": 3930 - }, - "lmo": { - "language": 3931 - }, - "lmp": { - "language": 3932 - }, - "lmq": { - "language": 3933 - }, - "lmr": { - "language": 3934 - }, - "lmu": { - "language": 3935 - }, - "lmv": { - "language": 3936 - }, - "lmw": { - "language": 3937 - }, - "lmx": { - "language": 3938 - }, - "lmy": { - "language": 3939 - }, - "lmz": { - "language": 3940 - }, - "lna": { - "language": 3941 - }, - "lnb": { - "language": 3942 - }, - "lnd": { - "language": 3943 - }, - "lng": { - "language": 3944 - }, - "lnh": { - "language": 3945 - }, - "lni": { - "language": 3946 - }, - "lnj": { - "language": 3947 - }, - "lnl": { - "language": 3948 - }, - "lnm": { - "language": 3949 - }, - "lnn": { - "language": 3950 - }, - "lno": { - "language": 3951 - }, - "lns": { - "language": 3952 - }, - "lnu": { - "language": 3953 - }, - "lnw": { - "language": 3954 - }, - "lnz": { - "language": 3955 - }, - "loa": { - "language": 3956 - }, - "lob": { - "language": 3957 - }, - "loc": { - "language": 3958 - }, - "loe": { - "language": 3959 - }, - "lof": { - "language": 3960 - }, - "log": { - "language": 3961 - }, - "loh": { - "language": 3962 - }, - "loi": { - "language": 3963 - }, - "loj": { - "language": 3964 - }, - "lok": { - "language": 3965 - }, - "lol": { - "language": 3966 - }, - "lom": { - "language": 3967 - }, - "lon": { - "language": 3968 - }, - "loo": { - "language": 3969 - }, - "lop": { - "language": 3970 - }, - "loq": { - "language": 3971 - }, - "lor": { - "language": 3972 - }, - "los": { - "language": 3973 - }, - "lot": { - "language": 3974 - }, - "lou": { - "language": 3975 - }, - "lov": { - "language": 3976 - }, - "low": { - "language": 3977 - }, - "lox": { - "language": 3978 - }, - "loy": { - "language": 3979 - }, - "loz": { - "language": 3980 - }, - "lpa": { - "language": 3981 - }, - "lpe": { - "language": 3982 - }, - "lpn": { - "language": 3983 - }, - "lpo": { - "language": 3984 - }, - "lpx": { - "language": 3985 - }, - "lqr": { - "language": 3986 - }, - "lra": { - "language": 3987 - }, - "lrc": { - "language": 3988 - }, - "lre": { - "language": 3989 - }, - "lrg": { - "language": 3990 - }, - "lri": { - "language": 3991 - }, - "lrk": { - "language": 3992 - }, - "lrl": { - "language": 3993 - }, - "lrm": { - "language": 3994 - }, - "lrn": { - "language": 3995 - }, - "lro": { - "language": 3996 - }, - "lrr": { - "language": 3997 - }, - "lrt": { - "language": 3998 - }, - "lrv": { - "language": 3999 - }, - "lrz": { - "language": 4000 - }, - "lsa": { - "language": 4001 - }, - "lsb": { - "language": 4002, - "extlang": 8370 - }, - "lsc": { - "language": 4003, - "extlang": 8371 - }, - "lsd": { - "language": 4004 - }, - "lse": { - "language": 4005 - }, - "lsg": { - "language": 4006, - "extlang": 8372 - }, - "lsh": { - "language": 4007 - }, - "lsi": { - "language": 4008 - }, - "lsl": { - "language": 4009, - "extlang": 8373 - }, - "lsm": { - "language": 4010 - }, - "lsn": { - "language": 4011, - "extlang": 8374 - }, - "lso": { - "language": 4012, - "extlang": 8375 - }, - "lsp": { - "language": 4013, - "extlang": 8376 - }, - "lsr": { - "language": 4014 - }, - "lss": { - "language": 4015 - }, - "lst": { - "language": 4016, - "extlang": 8377 - }, - "lsv": { - "language": 4017, - "extlang": 8378 - }, - "lsw": { - "language": 4018, - "extlang": 8379 - }, - "lsy": { - "language": 4019, - "extlang": 8380 - }, - "ltc": { - "language": 4020 - }, - "ltg": { - "language": 4021, - "extlang": 8381 - }, - "lth": { - "language": 4022 - }, - "lti": { - "language": 4023 - }, - "ltn": { - "language": 4024 - }, - "lto": { - "language": 4025 - }, - "lts": { - "language": 4026 - }, - "ltu": { - "language": 4027 - }, - "lua": { - "language": 4028 - }, - "luc": { - "language": 4029 - }, - "lud": { - "language": 4030 - }, - "lue": { - "language": 4031 - }, - "luf": { - "language": 4032 - }, - "lui": { - "language": 4033 - }, - "luj": { - "language": 4034 - }, - "luk": { - "language": 4035 - }, - "lul": { - "language": 4036 - }, - "lum": { - "language": 4037 - }, - "lun": { - "language": 4038 - }, - "luo": { - "language": 4039 - }, - "lup": { - "language": 4040 - }, - "luq": { - "language": 4041 - }, - "lur": { - "language": 4042 - }, - "lus": { - "language": 4043 - }, - "lut": { - "language": 4044 - }, - "luu": { - "language": 4045 - }, - "luv": { - "language": 4046 - }, - "luw": { - "language": 4047 - }, - "luy": { - "language": 4048 - }, - "luz": { - "language": 4049 - }, - "lva": { - "language": 4050 - }, - "lvi": { - "language": 4051 - }, - "lvk": { - "language": 4052 - }, - "lvs": { - "language": 4053, - "extlang": 8382 - }, - "lvu": { - "language": 4054 - }, - "lwa": { - "language": 4055 - }, - "lwe": { - "language": 4056 - }, - "lwg": { - "language": 4057 - }, - "lwh": { - "language": 4058 - }, - "lwl": { - "language": 4059 - }, - "lwm": { - "language": 4060 - }, - "lwo": { - "language": 4061 - }, - "lws": { - "language": 4062, - "extlang": 8383 - }, - "lwt": { - "language": 4063 - }, - "lwu": { - "language": 4064 - }, - "lww": { - "language": 4065 - }, - "lxm": { - "language": 4066 - }, - "lya": { - "language": 4067 - }, - "lyg": { - "language": 4068 - }, - "lyn": { - "language": 4069 - }, - "lzh": { - "language": 4070, - "extlang": 8384 - }, - "lzl": { - "language": 4071 - }, - "lzn": { - "language": 4072 - }, - "lzz": { - "language": 4073 - }, - "maa": { - "language": 4074 - }, - "mab": { - "language": 4075 - }, - "mad": { - "language": 4076 - }, - "mae": { - "language": 4077 - }, - "maf": { - "language": 4078 - }, - "mag": { - "language": 4079 - }, - "mai": { - "language": 4080 - }, - "maj": { - "language": 4081 - }, - "mak": { - "language": 4082 - }, - "mam": { - "language": 4083 - }, - "man": { - "language": 4084 - }, - "map": { - "language": 4085 - }, - "maq": { - "language": 4086 - }, - "mas": { - "language": 4087 - }, - "mat": { - "language": 4088 - }, - "mau": { - "language": 4089 - }, - "mav": { - "language": 4090 - }, - "maw": { - "language": 4091 - }, - "max": { - "language": 4092, - "extlang": 8385 - }, - "maz": { - "language": 4093 - }, - "mba": { - "language": 4094 - }, - "mbb": { - "language": 4095 - }, - "mbc": { - "language": 4096 - }, - "mbd": { - "language": 4097 - }, - "mbe": { - "language": 4098 - }, - "mbf": { - "language": 4099 - }, - "mbh": { - "language": 4100 - }, - "mbi": { - "language": 4101 - }, - "mbj": { - "language": 4102 - }, - "mbk": { - "language": 4103 - }, - "mbl": { - "language": 4104 - }, - "mbm": { - "language": 4105 - }, - "mbn": { - "language": 4106 - }, - "mbo": { - "language": 4107 - }, - "mbp": { - "language": 4108 - }, - "mbq": { - "language": 4109 - }, - "mbr": { - "language": 4110 - }, - "mbs": { - "language": 4111 - }, - "mbt": { - "language": 4112 - }, - "mbu": { - "language": 4113 - }, - "mbv": { - "language": 4114 - }, - "mbw": { - "language": 4115 - }, - "mbx": { - "language": 4116 - }, - "mby": { - "language": 4117 - }, - "mbz": { - "language": 4118 - }, - "mca": { - "language": 4119 - }, - "mcb": { - "language": 4120 - }, - "mcc": { - "language": 4121 - }, - "mcd": { - "language": 4122 - }, - "mce": { - "language": 4123 - }, - "mcf": { - "language": 4124 - }, - "mcg": { - "language": 4125 - }, - "mch": { - "language": 4126 - }, - "mci": { - "language": 4127 - }, - "mcj": { - "language": 4128 - }, - "mck": { - "language": 4129 - }, - "mcl": { - "language": 4130 - }, - "mcm": { - "language": 4131 - }, - "mcn": { - "language": 4132 - }, - "mco": { - "language": 4133 - }, - "mcp": { - "language": 4134 - }, - "mcq": { - "language": 4135 - }, - "mcr": { - "language": 4136 - }, - "mcs": { - "language": 4137 - }, - "mct": { - "language": 4138 - }, - "mcu": { - "language": 4139 - }, - "mcv": { - "language": 4140 - }, - "mcw": { - "language": 4141 - }, - "mcx": { - "language": 4142 - }, - "mcy": { - "language": 4143 - }, - "mcz": { - "language": 4144 - }, - "mda": { - "language": 4145 - }, - "mdb": { - "language": 4146 - }, - "mdc": { - "language": 4147 - }, - "mdd": { - "language": 4148 - }, - "mde": { - "language": 4149 - }, - "mdf": { - "language": 4150 - }, - "mdg": { - "language": 4151 - }, - "mdh": { - "language": 4152 - }, - "mdi": { - "language": 4153 - }, - "mdj": { - "language": 4154 - }, - "mdk": { - "language": 4155 - }, - "mdl": { - "language": 4156, - "extlang": 8386 - }, - "mdm": { - "language": 4157 - }, - "mdn": { - "language": 4158 - }, - "mdp": { - "language": 4159 - }, - "mdq": { - "language": 4160 - }, - "mdr": { - "language": 4161 - }, - "mds": { - "language": 4162 - }, - "mdt": { - "language": 4163 - }, - "mdu": { - "language": 4164 - }, - "mdv": { - "language": 4165 - }, - "mdw": { - "language": 4166 - }, - "mdx": { - "language": 4167 - }, - "mdy": { - "language": 4168 - }, - "mdz": { - "language": 4169 - }, - "mea": { - "language": 4170 - }, - "meb": { - "language": 4171 - }, - "mec": { - "language": 4172 - }, - "med": { - "language": 4173 - }, - "mee": { - "language": 4174 - }, - "mef": { - "language": 4175 - }, - "meg": { - "language": 4176 - }, - "meh": { - "language": 4177 - }, - "mei": { - "language": 4178 - }, - "mej": { - "language": 4179 - }, - "mek": { - "language": 4180 - }, - "mel": { - "language": 4181 - }, - "mem": { - "language": 4182 - }, - "men": { - "language": 4183 - }, - "meo": { - "language": 4184, - "extlang": 8387 - }, - "mep": { - "language": 4185 - }, - "meq": { - "language": 4186 - }, - "mer": { - "language": 4187 - }, - "mes": { - "language": 4188 - }, - "met": { - "language": 4189 - }, - "meu": { - "language": 4190 - }, - "mev": { - "language": 4191 - }, - "mew": { - "language": 4192 - }, - "mey": { - "language": 4193 - }, - "mez": { - "language": 4194 - }, - "mfa": { - "language": 4195, - "extlang": 8388 - }, - "mfb": { - "language": 4196, - "extlang": 8389 - }, - "mfc": { - "language": 4197 - }, - "mfd": { - "language": 4198 - }, - "mfe": { - "language": 4199 - }, - "mff": { - "language": 4200 - }, - "mfg": { - "language": 4201 - }, - "mfh": { - "language": 4202 - }, - "mfi": { - "language": 4203 - }, - "mfj": { - "language": 4204 - }, - "mfk": { - "language": 4205 - }, - "mfl": { - "language": 4206 - }, - "mfm": { - "language": 4207 - }, - "mfn": { - "language": 4208 - }, - "mfo": { - "language": 4209 - }, - "mfp": { - "language": 4210 - }, - "mfq": { - "language": 4211 - }, - "mfr": { - "language": 4212 - }, - "mfs": { - "language": 4213, - "extlang": 8390 - }, - "mft": { - "language": 4214 - }, - "mfu": { - "language": 4215 - }, - "mfv": { - "language": 4216 - }, - "mfw": { - "language": 4217 - }, - "mfx": { - "language": 4218 - }, - "mfy": { - "language": 4219 - }, - "mfz": { - "language": 4220 - }, - "mga": { - "language": 4221 - }, - "mgb": { - "language": 4222 - }, - "mgc": { - "language": 4223 - }, - "mgd": { - "language": 4224 - }, - "mge": { - "language": 4225 - }, - "mgf": { - "language": 4226 - }, - "mgg": { - "language": 4227 - }, - "mgh": { - "language": 4228 - }, - "mgi": { - "language": 4229 - }, - "mgj": { - "language": 4230 - }, - "mgk": { - "language": 4231 - }, - "mgl": { - "language": 4232 - }, - "mgm": { - "language": 4233 - }, - "mgn": { - "language": 4234 - }, - "mgo": { - "language": 4235 - }, - "mgp": { - "language": 4236 - }, - "mgq": { - "language": 4237 - }, - "mgr": { - "language": 4238 - }, - "mgs": { - "language": 4239 - }, - "mgt": { - "language": 4240 - }, - "mgu": { - "language": 4241 - }, - "mgv": { - "language": 4242 - }, - "mgw": { - "language": 4243 - }, - "mgx": { - "language": 4244 - }, - "mgy": { - "language": 4245 - }, - "mgz": { - "language": 4246 - }, - "mha": { - "language": 4247 - }, - "mhb": { - "language": 4248 - }, - "mhc": { - "language": 4249 - }, - "mhd": { - "language": 4250 - }, - "mhe": { - "language": 4251 - }, - "mhf": { - "language": 4252 - }, - "mhg": { - "language": 4253 - }, - "mhh": { - "language": 4254 - }, - "mhi": { - "language": 4255 - }, - "mhj": { - "language": 4256 - }, - "mhk": { - "language": 4257 - }, - "mhl": { - "language": 4258 - }, - "mhm": { - "language": 4259 - }, - "mhn": { - "language": 4260 - }, - "mho": { - "language": 4261 - }, - "mhp": { - "language": 4262 - }, - "mhq": { - "language": 4263 - }, - "mhr": { - "language": 4264 - }, - "mhs": { - "language": 4265 - }, - "mht": { - "language": 4266 - }, - "mhu": { - "language": 4267 - }, - "mhw": { - "language": 4268 - }, - "mhx": { - "language": 4269 - }, - "mhy": { - "language": 4270 - }, - "mhz": { - "language": 4271 - }, - "mia": { - "language": 4272 - }, - "mib": { - "language": 4273 - }, - "mic": { - "language": 4274 - }, - "mid": { - "language": 4275 - }, - "mie": { - "language": 4276 - }, - "mif": { - "language": 4277 - }, - "mig": { - "language": 4278 - }, - "mih": { - "language": 4279 - }, - "mii": { - "language": 4280 - }, - "mij": { - "language": 4281 - }, - "mik": { - "language": 4282 - }, - "mil": { - "language": 4283 - }, - "mim": { - "language": 4284 - }, - "min": { - "language": 4285, - "extlang": 8391 - }, - "mio": { - "language": 4286 - }, - "mip": { - "language": 4287 - }, - "miq": { - "language": 4288 - }, - "mir": { - "language": 4289 - }, - "mis": { - "language": 4290 - }, - "mit": { - "language": 4291 - }, - "miu": { - "language": 4292 - }, - "miw": { - "language": 4293 - }, - "mix": { - "language": 4294 - }, - "miy": { - "language": 4295 - }, - "miz": { - "language": 4296 - }, - "mja": { - "language": 4297 - }, - "mjb": { - "language": 4298 - }, - "mjc": { - "language": 4299 - }, - "mjd": { - "language": 4300 - }, - "mje": { - "language": 4301 - }, - "mjg": { - "language": 4302 - }, - "mjh": { - "language": 4303 - }, - "mji": { - "language": 4304 - }, - "mjj": { - "language": 4305 - }, - "mjk": { - "language": 4306 - }, - "mjl": { - "language": 4307 - }, - "mjm": { - "language": 4308 - }, - "mjn": { - "language": 4309 - }, - "mjo": { - "language": 4310 - }, - "mjp": { - "language": 4311 - }, - "mjq": { - "language": 4312 - }, - "mjr": { - "language": 4313 - }, - "mjs": { - "language": 4314 - }, - "mjt": { - "language": 4315 - }, - "mju": { - "language": 4316 - }, - "mjv": { - "language": 4317 - }, - "mjw": { - "language": 4318 - }, - "mjx": { - "language": 4319 - }, - "mjy": { - "language": 4320 - }, - "mjz": { - "language": 4321 - }, - "mka": { - "language": 4322 - }, - "mkb": { - "language": 4323 - }, - "mkc": { - "language": 4324 - }, - "mke": { - "language": 4325 - }, - "mkf": { - "language": 4326 - }, - "mkg": { - "language": 4327 - }, - "mkh": { - "language": 4328 - }, - "mki": { - "language": 4329 - }, - "mkj": { - "language": 4330 - }, - "mkk": { - "language": 4331 - }, - "mkl": { - "language": 4332 - }, - "mkm": { - "language": 4333 - }, - "mkn": { - "language": 4334 - }, - "mko": { - "language": 4335 - }, - "mkp": { - "language": 4336 - }, - "mkq": { - "language": 4337 - }, - "mkr": { - "language": 4338 - }, - "mks": { - "language": 4339 - }, - "mkt": { - "language": 4340 - }, - "mku": { - "language": 4341 - }, - "mkv": { - "language": 4342 - }, - "mkw": { - "language": 4343 - }, - "mkx": { - "language": 4344 - }, - "mky": { - "language": 4345 - }, - "mkz": { - "language": 4346 - }, - "mla": { - "language": 4347 - }, - "mlb": { - "language": 4348 - }, - "mlc": { - "language": 4349 - }, - "mld": { - "language": 4350 - }, - "mle": { - "language": 4351 - }, - "mlf": { - "language": 4352 - }, - "mlh": { - "language": 4353 - }, - "mli": { - "language": 4354 - }, - "mlj": { - "language": 4355 - }, - "mlk": { - "language": 4356 - }, - "mll": { - "language": 4357 - }, - "mlm": { - "language": 4358 - }, - "mln": { - "language": 4359 - }, - "mlo": { - "language": 4360 - }, - "mlp": { - "language": 4361 - }, - "mlq": { - "language": 4362 - }, - "mlr": { - "language": 4363 - }, - "mls": { - "language": 4364 - }, - "mlu": { - "language": 4365 - }, - "mlv": { - "language": 4366 - }, - "mlw": { - "language": 4367 - }, - "mlx": { - "language": 4368 - }, - "mlz": { - "language": 4369 - }, - "mma": { - "language": 4370 - }, - "mmb": { - "language": 4371 - }, - "mmc": { - "language": 4372 - }, - "mmd": { - "language": 4373 - }, - "mme": { - "language": 4374 - }, - "mmf": { - "language": 4375 - }, - "mmg": { - "language": 4376 - }, - "mmh": { - "language": 4377 - }, - "mmi": { - "language": 4378 - }, - "mmj": { - "language": 4379 - }, - "mmk": { - "language": 4380 - }, - "mml": { - "language": 4381 - }, - "mmm": { - "language": 4382 - }, - "mmn": { - "language": 4383 - }, - "mmo": { - "language": 4384 - }, - "mmp": { - "language": 4385 - }, - "mmq": { - "language": 4386 - }, - "mmr": { - "language": 4387 - }, - "mmt": { - "language": 4388 - }, - "mmu": { - "language": 4389 - }, - "mmv": { - "language": 4390 - }, - "mmw": { - "language": 4391 - }, - "mmx": { - "language": 4392 - }, - "mmy": { - "language": 4393 - }, - "mmz": { - "language": 4394 - }, - "mna": { - "language": 4395 - }, - "mnb": { - "language": 4396 - }, - "mnc": { - "language": 4397 - }, - "mnd": { - "language": 4398 - }, - "mne": { - "language": 4399 - }, - "mnf": { - "language": 4400 - }, - "mng": { - "language": 4401 - }, - "mnh": { - "language": 4402 - }, - "mni": { - "language": 4403 - }, - "mnj": { - "language": 4404 - }, - "mnk": { - "language": 4405 - }, - "mnl": { - "language": 4406 - }, - "mnm": { - "language": 4407 - }, - "mnn": { - "language": 4408 - }, - "mno": { - "language": 4409 - }, - "mnp": { - "language": 4410, - "extlang": 8392 - }, - "mnq": { - "language": 4411 - }, - "mnr": { - "language": 4412 - }, - "mns": { - "language": 4413 - }, - "mnt": { - "language": 4414 - }, - "mnu": { - "language": 4415 - }, - "mnv": { - "language": 4416 - }, - "mnw": { - "language": 4417 - }, - "mnx": { - "language": 4418 - }, - "mny": { - "language": 4419 - }, - "mnz": { - "language": 4420 - }, - "moa": { - "language": 4421 - }, - "moc": { - "language": 4422 - }, - "mod": { - "language": 4423 - }, - "moe": { - "language": 4424 - }, - "mof": { - "language": 4425 - }, - "mog": { - "language": 4426 - }, - "moh": { - "language": 4427 - }, - "moi": { - "language": 4428 - }, - "moj": { - "language": 4429 - }, - "mok": { - "language": 4430 - }, - "mom": { - "language": 4431 - }, - "moo": { - "language": 4432 - }, - "mop": { - "language": 4433 - }, - "moq": { - "language": 4434 - }, - "mor": { - "language": 4435 - }, - "mos": { - "language": 4436 - }, - "mot": { - "language": 4437 - }, - "mou": { - "language": 4438 - }, - "mov": { - "language": 4439 - }, - "mow": { - "language": 4440 - }, - "mox": { - "language": 4441 - }, - "moy": { - "language": 4442 - }, - "moz": { - "language": 4443 - }, - "mpa": { - "language": 4444 - }, - "mpb": { - "language": 4445 - }, - "mpc": { - "language": 4446 - }, - "mpd": { - "language": 4447 - }, - "mpe": { - "language": 4448 - }, - "mpg": { - "language": 4449 - }, - "mph": { - "language": 4450 - }, - "mpi": { - "language": 4451 - }, - "mpj": { - "language": 4452 - }, - "mpk": { - "language": 4453 - }, - "mpl": { - "language": 4454 - }, - "mpm": { - "language": 4455 - }, - "mpn": { - "language": 4456 - }, - "mpo": { - "language": 4457 - }, - "mpp": { - "language": 4458 - }, - "mpq": { - "language": 4459 - }, - "mpr": { - "language": 4460 - }, - "mps": { - "language": 4461 - }, - "mpt": { - "language": 4462 - }, - "mpu": { - "language": 4463 - }, - "mpv": { - "language": 4464 - }, - "mpw": { - "language": 4465 - }, - "mpx": { - "language": 4466 - }, - "mpy": { - "language": 4467 - }, - "mpz": { - "language": 4468 - }, - "mqa": { - "language": 4469 - }, - "mqb": { - "language": 4470 - }, - "mqc": { - "language": 4471 - }, - "mqe": { - "language": 4472 - }, - "mqf": { - "language": 4473 - }, - "mqg": { - "language": 4474, - "extlang": 8393 - }, - "mqh": { - "language": 4475 - }, - "mqi": { - "language": 4476 - }, - "mqj": { - "language": 4477 - }, - "mqk": { - "language": 4478 - }, - "mql": { - "language": 4479 - }, - "mqm": { - "language": 4480 - }, - "mqn": { - "language": 4481 - }, - "mqo": { - "language": 4482 - }, - "mqp": { - "language": 4483 - }, - "mqq": { - "language": 4484 - }, - "mqr": { - "language": 4485 - }, - "mqs": { - "language": 4486 - }, - "mqt": { - "language": 4487 - }, - "mqu": { - "language": 4488 - }, - "mqv": { - "language": 4489 - }, - "mqw": { - "language": 4490 - }, - "mqx": { - "language": 4491 - }, - "mqy": { - "language": 4492 - }, - "mqz": { - "language": 4493 - }, - "mra": { - "language": 4494 - }, - "mrb": { - "language": 4495 - }, - "mrc": { - "language": 4496 - }, - "mrd": { - "language": 4497 - }, - "mre": { - "language": 4498, - "extlang": 8394 - }, - "mrf": { - "language": 4499 - }, - "mrg": { - "language": 4500 - }, - "mrh": { - "language": 4501 - }, - "mrj": { - "language": 4502 - }, - "mrk": { - "language": 4503 - }, - "mrl": { - "language": 4504 - }, - "mrm": { - "language": 4505 - }, - "mrn": { - "language": 4506 - }, - "mro": { - "language": 4507 - }, - "mrp": { - "language": 4508 - }, - "mrq": { - "language": 4509 - }, - "mrr": { - "language": 4510 - }, - "mrs": { - "language": 4511 - }, - "mrt": { - "language": 4512 - }, - "mru": { - "language": 4513 - }, - "mrv": { - "language": 4514 - }, - "mrw": { - "language": 4515 - }, - "mrx": { - "language": 4516 - }, - "mry": { - "language": 4517 - }, - "mrz": { - "language": 4518 - }, - "msb": { - "language": 4519 - }, - "msc": { - "language": 4520 - }, - "msd": { - "language": 4521, - "extlang": 8395 - }, - "mse": { - "language": 4522 - }, - "msf": { - "language": 4523 - }, - "msg": { - "language": 4524 - }, - "msh": { - "language": 4525 - }, - "msi": { - "language": 4526, - "extlang": 8396 - }, - "msj": { - "language": 4527 - }, - "msk": { - "language": 4528 - }, - "msl": { - "language": 4529 - }, - "msm": { - "language": 4530 - }, - "msn": { - "language": 4531 - }, - "mso": { - "language": 4532 - }, - "msp": { - "language": 4533 - }, - "msq": { - "language": 4534 - }, - "msr": { - "language": 4535, - "extlang": 8397 - }, - "mss": { - "language": 4536 - }, - "mst": { - "language": 4537 - }, - "msu": { - "language": 4538 - }, - "msv": { - "language": 4539 - }, - "msw": { - "language": 4540 - }, - "msx": { - "language": 4541 - }, - "msy": { - "language": 4542 - }, - "msz": { - "language": 4543 - }, - "mta": { - "language": 4544 - }, - "mtb": { - "language": 4545 - }, - "mtc": { - "language": 4546 - }, - "mtd": { - "language": 4547 - }, - "mte": { - "language": 4548 - }, - "mtf": { - "language": 4549 - }, - "mtg": { - "language": 4550 - }, - "mth": { - "language": 4551 - }, - "mti": { - "language": 4552 - }, - "mtj": { - "language": 4553 - }, - "mtk": { - "language": 4554 - }, - "mtl": { - "language": 4555 - }, - "mtm": { - "language": 4556 - }, - "mtn": { - "language": 4557 - }, - "mto": { - "language": 4558 - }, - "mtp": { - "language": 4559 - }, - "mtq": { - "language": 4560 - }, - "mtr": { - "language": 4561 - }, - "mts": { - "language": 4562 - }, - "mtt": { - "language": 4563 - }, - "mtu": { - "language": 4564 - }, - "mtv": { - "language": 4565 - }, - "mtw": { - "language": 4566 - }, - "mtx": { - "language": 4567 - }, - "mty": { - "language": 4568 - }, - "mua": { - "language": 4569 - }, - "mub": { - "language": 4570 - }, - "muc": { - "language": 4571 - }, - "mud": { - "language": 4572 - }, - "mue": { - "language": 4573 - }, - "mug": { - "language": 4574 - }, - "muh": { - "language": 4575 - }, - "mui": { - "language": 4576, - "extlang": 8398 - }, - "muj": { - "language": 4577 - }, - "muk": { - "language": 4578 - }, - "mul": { - "language": 4579 - }, - "mum": { - "language": 4580 - }, - "mun": { - "language": 4581 - }, - "muo": { - "language": 4582 - }, - "mup": { - "language": 4583 - }, - "muq": { - "language": 4584 - }, - "mur": { - "language": 4585 - }, - "mus": { - "language": 4586 - }, - "mut": { - "language": 4587 - }, - "muu": { - "language": 4588 - }, - "muv": { - "language": 4589 - }, - "mux": { - "language": 4590 - }, - "muy": { - "language": 4591 - }, - "muz": { - "language": 4592 - }, - "mva": { - "language": 4593 - }, - "mvb": { - "language": 4594 - }, - "mvd": { - "language": 4595 - }, - "mve": { - "language": 4596 - }, - "mvf": { - "language": 4597 - }, - "mvg": { - "language": 4598 - }, - "mvh": { - "language": 4599 - }, - "mvi": { - "language": 4600 - }, - "mvk": { - "language": 4601 - }, - "mvl": { - "language": 4602 - }, - "mvm": { - "language": 4603 - }, - "mvn": { - "language": 4604 - }, - "mvo": { - "language": 4605 - }, - "mvp": { - "language": 4606 - }, - "mvq": { - "language": 4607 - }, - "mvr": { - "language": 4608 - }, - "mvs": { - "language": 4609 - }, - "mvt": { - "language": 4610 - }, - "mvu": { - "language": 4611 - }, - "mvv": { - "language": 4612 - }, - "mvw": { - "language": 4613 - }, - "mvx": { - "language": 4614 - }, - "mvy": { - "language": 4615 - }, - "mvz": { - "language": 4616 - }, - "mwa": { - "language": 4617 - }, - "mwb": { - "language": 4618 - }, - "mwc": { - "language": 4619 - }, - "mwd": { - "language": 4620 - }, - "mwe": { - "language": 4621 - }, - "mwf": { - "language": 4622 - }, - "mwg": { - "language": 4623 - }, - "mwh": { - "language": 4624 - }, - "mwi": { - "language": 4625 - }, - "mwj": { - "language": 4626 - }, - "mwk": { - "language": 4627 - }, - "mwl": { - "language": 4628 - }, - "mwm": { - "language": 4629 - }, - "mwn": { - "language": 4630 - }, - "mwo": { - "language": 4631 - }, - "mwp": { - "language": 4632 - }, - "mwq": { - "language": 4633 - }, - "mwr": { - "language": 4634 - }, - "mws": { - "language": 4635 - }, - "mwt": { - "language": 4636 - }, - "mwu": { - "language": 4637 - }, - "mwv": { - "language": 4638 - }, - "mww": { - "language": 4639 - }, - "mwx": { - "language": 4640 - }, - "mwy": { - "language": 4641 - }, - "mwz": { - "language": 4642 - }, - "mxa": { - "language": 4643 - }, - "mxb": { - "language": 4644 - }, - "mxc": { - "language": 4645 - }, - "mxd": { - "language": 4646 - }, - "mxe": { - "language": 4647 - }, - "mxf": { - "language": 4648 - }, - "mxg": { - "language": 4649 - }, - "mxh": { - "language": 4650 - }, - "mxi": { - "language": 4651 - }, - "mxj": { - "language": 4652 - }, - "mxk": { - "language": 4653 - }, - "mxl": { - "language": 4654 - }, - "mxm": { - "language": 4655 - }, - "mxn": { - "language": 4656 - }, - "mxo": { - "language": 4657 - }, - "mxp": { - "language": 4658 - }, - "mxq": { - "language": 4659 - }, - "mxr": { - "language": 4660 - }, - "mxs": { - "language": 4661 - }, - "mxt": { - "language": 4662 - }, - "mxu": { - "language": 4663 - }, - "mxv": { - "language": 4664 - }, - "mxw": { - "language": 4665 - }, - "mxx": { - "language": 4666 - }, - "mxy": { - "language": 4667 - }, - "mxz": { - "language": 4668 - }, - "myb": { - "language": 4669 - }, - "myc": { - "language": 4670 - }, - "myd": { - "language": 4671 - }, - "mye": { - "language": 4672 - }, - "myf": { - "language": 4673 - }, - "myg": { - "language": 4674 - }, - "myh": { - "language": 4675 - }, - "myi": { - "language": 4676 - }, - "myj": { - "language": 4677 - }, - "myk": { - "language": 4678 - }, - "myl": { - "language": 4679 - }, - "mym": { - "language": 4680 - }, - "myn": { - "language": 4681 - }, - "myo": { - "language": 4682 - }, - "myp": { - "language": 4683 - }, - "myq": { - "language": 4684 - }, - "myr": { - "language": 4685 - }, - "mys": { - "language": 4686 - }, - "myt": { - "language": 4687 - }, - "myu": { - "language": 4688 - }, - "myv": { - "language": 4689 - }, - "myw": { - "language": 4690 - }, - "myx": { - "language": 4691 - }, - "myy": { - "language": 4692 - }, - "myz": { - "language": 4693 - }, - "mza": { - "language": 4694 - }, - "mzb": { - "language": 4695 - }, - "mzc": { - "language": 4696, - "extlang": 8399 - }, - "mzd": { - "language": 4697 - }, - "mze": { - "language": 4698 - }, - "mzg": { - "language": 4699, - "extlang": 8400 - }, - "mzh": { - "language": 4700 - }, - "mzi": { - "language": 4701 - }, - "mzj": { - "language": 4702 - }, - "mzk": { - "language": 4703 - }, - "mzl": { - "language": 4704 - }, - "mzm": { - "language": 4705 - }, - "mzn": { - "language": 4706 - }, - "mzo": { - "language": 4707 - }, - "mzp": { - "language": 4708 - }, - "mzq": { - "language": 4709 - }, - "mzr": { - "language": 4710 - }, - "mzs": { - "language": 4711 - }, - "mzt": { - "language": 4712 - }, - "mzu": { - "language": 4713 - }, - "mzv": { - "language": 4714 - }, - "mzw": { - "language": 4715 - }, - "mzx": { - "language": 4716 - }, - "mzy": { - "language": 4717, - "extlang": 8401 - }, - "mzz": { - "language": 4718 - }, - "naa": { - "language": 4719 - }, - "nab": { - "language": 4720 - }, - "nac": { - "language": 4721 - }, - "nad": { - "language": 4722 - }, - "nae": { - "language": 4723 - }, - "naf": { - "language": 4724 - }, - "nag": { - "language": 4725 - }, - "nah": { - "language": 4726 - }, - "nai": { - "language": 4727 - }, - "naj": { - "language": 4728 - }, - "nak": { - "language": 4729 - }, - "nal": { - "language": 4730 - }, - "nam": { - "language": 4731 - }, - "nan": { - "language": 4732, - "extlang": 8402 - }, - "nao": { - "language": 4733 - }, - "nap": { - "language": 4734 - }, - "naq": { - "language": 4735 - }, - "nar": { - "language": 4736 - }, - "nas": { - "language": 4737 - }, - "nat": { - "language": 4738 - }, - "naw": { - "language": 4739 - }, - "nax": { - "language": 4740 - }, - "nay": { - "language": 4741 - }, - "naz": { - "language": 4742 - }, - "nba": { - "language": 4743 - }, - "nbb": { - "language": 4744 - }, - "nbc": { - "language": 4745 - }, - "nbd": { - "language": 4746 - }, - "nbe": { - "language": 4747 - }, - "nbf": { - "language": 4748 - }, - "nbg": { - "language": 4749 - }, - "nbh": { - "language": 4750 - }, - "nbi": { - "language": 4751 - }, - "nbj": { - "language": 4752 - }, - "nbk": { - "language": 4753 - }, - "nbm": { - "language": 4754 - }, - "nbn": { - "language": 4755 - }, - "nbo": { - "language": 4756 - }, - "nbp": { - "language": 4757 - }, - "nbq": { - "language": 4758 - }, - "nbr": { - "language": 4759 - }, - "nbs": { - "language": 4760, - "extlang": 8403 - }, - "nbt": { - "language": 4761 - }, - "nbu": { - "language": 4762 - }, - "nbv": { - "language": 4763 - }, - "nbw": { - "language": 4764 - }, - "nbx": { - "language": 4765 - }, - "nby": { - "language": 4766 - }, - "nca": { - "language": 4767 - }, - "ncb": { - "language": 4768 - }, - "ncc": { - "language": 4769 - }, - "ncd": { - "language": 4770 - }, - "nce": { - "language": 4771 - }, - "ncf": { - "language": 4772 - }, - "ncg": { - "language": 4773 - }, - "nch": { - "language": 4774 - }, - "nci": { - "language": 4775 - }, - "ncj": { - "language": 4776 - }, - "nck": { - "language": 4777 - }, - "ncl": { - "language": 4778 - }, - "ncm": { - "language": 4779 - }, - "ncn": { - "language": 4780 - }, - "nco": { - "language": 4781 - }, - "ncp": { - "language": 4782 - }, - "ncq": { - "language": 4783 - }, - "ncr": { - "language": 4784 - }, - "ncs": { - "language": 4785, - "extlang": 8404 - }, - "nct": { - "language": 4786 - }, - "ncu": { - "language": 4787 - }, - "ncx": { - "language": 4788 - }, - "ncz": { - "language": 4789 - }, - "nda": { - "language": 4790 - }, - "ndb": { - "language": 4791 - }, - "ndc": { - "language": 4792 - }, - "ndd": { - "language": 4793 - }, - "ndf": { - "language": 4794 - }, - "ndg": { - "language": 4795 - }, - "ndh": { - "language": 4796 - }, - "ndi": { - "language": 4797 - }, - "ndj": { - "language": 4798 - }, - "ndk": { - "language": 4799 - }, - "ndl": { - "language": 4800 - }, - "ndm": { - "language": 4801 - }, - "ndn": { - "language": 4802 - }, - "ndp": { - "language": 4803 - }, - "ndq": { - "language": 4804 - }, - "ndr": { - "language": 4805 - }, - "nds": { - "language": 4806 - }, - "ndt": { - "language": 4807 - }, - "ndu": { - "language": 4808 - }, - "ndv": { - "language": 4809 - }, - "ndw": { - "language": 4810 - }, - "ndx": { - "language": 4811 - }, - "ndy": { - "language": 4812 - }, - "ndz": { - "language": 4813 - }, - "nea": { - "language": 4814 - }, - "neb": { - "language": 4815 - }, - "nec": { - "language": 4816 - }, - "ned": { - "language": 4817 - }, - "nee": { - "language": 4818 - }, - "nef": { - "language": 4819 - }, - "neg": { - "language": 4820 - }, - "neh": { - "language": 4821 - }, - "nei": { - "language": 4822 - }, - "nej": { - "language": 4823 - }, - "nek": { - "language": 4824 - }, - "nem": { - "language": 4825 - }, - "nen": { - "language": 4826 - }, - "neo": { - "language": 4827 - }, - "neq": { - "language": 4828 - }, - "ner": { - "language": 4829 - }, - "nes": { - "language": 4830 - }, - "net": { - "language": 4831 - }, - "neu": { - "language": 4832 - }, - "nev": { - "language": 4833 - }, - "new": { - "language": 4834 - }, - "nex": { - "language": 4835 - }, - "ney": { - "language": 4836 - }, - "nez": { - "language": 4837 - }, - "nfa": { - "language": 4838 - }, - "nfd": { - "language": 4839 - }, - "nfl": { - "language": 4840 - }, - "nfr": { - "language": 4841 - }, - "nfu": { - "language": 4842 - }, - "nga": { - "language": 4843 - }, - "ngb": { - "language": 4844 - }, - "ngc": { - "language": 4845 - }, - "ngd": { - "language": 4846 - }, - "nge": { - "language": 4847 - }, - "ngf": { - "language": 4848 - }, - "ngg": { - "language": 4849 - }, - "ngh": { - "language": 4850 - }, - "ngi": { - "language": 4851 - }, - "ngj": { - "language": 4852 - }, - "ngk": { - "language": 4853 - }, - "ngl": { - "language": 4854 - }, - "ngm": { - "language": 4855 - }, - "ngn": { - "language": 4856 - }, - "ngo": { - "language": 4857 - }, - "ngp": { - "language": 4858 - }, - "ngq": { - "language": 4859 - }, - "ngr": { - "language": 4860 - }, - "ngs": { - "language": 4861 - }, - "ngt": { - "language": 4862 - }, - "ngu": { - "language": 4863 - }, - "ngv": { - "language": 4864 - }, - "ngw": { - "language": 4865 - }, - "ngx": { - "language": 4866 - }, - "ngy": { - "language": 4867 - }, - "ngz": { - "language": 4868 - }, - "nha": { - "language": 4869 - }, - "nhb": { - "language": 4870 - }, - "nhc": { - "language": 4871 - }, - "nhd": { - "language": 4872 - }, - "nhe": { - "language": 4873 - }, - "nhf": { - "language": 4874 - }, - "nhg": { - "language": 4875 - }, - "nhh": { - "language": 4876 - }, - "nhi": { - "language": 4877 - }, - "nhk": { - "language": 4878 - }, - "nhm": { - "language": 4879 - }, - "nhn": { - "language": 4880 - }, - "nho": { - "language": 4881 - }, - "nhp": { - "language": 4882 - }, - "nhq": { - "language": 4883 - }, - "nhr": { - "language": 4884 - }, - "nht": { - "language": 4885 - }, - "nhu": { - "language": 4886 - }, - "nhv": { - "language": 4887 - }, - "nhw": { - "language": 4888 - }, - "nhx": { - "language": 4889 - }, - "nhy": { - "language": 4890 - }, - "nhz": { - "language": 4891 - }, - "nia": { - "language": 4892 - }, - "nib": { - "language": 4893 - }, - "nic": { - "language": 4894 - }, - "nid": { - "language": 4895 - }, - "nie": { - "language": 4896 - }, - "nif": { - "language": 4897 - }, - "nig": { - "language": 4898 - }, - "nih": { - "language": 4899 - }, - "nii": { - "language": 4900 - }, - "nij": { - "language": 4901 - }, - "nik": { - "language": 4902 - }, - "nil": { - "language": 4903 - }, - "nim": { - "language": 4904 - }, - "nin": { - "language": 4905 - }, - "nio": { - "language": 4906 - }, - "niq": { - "language": 4907 - }, - "nir": { - "language": 4908 - }, - "nis": { - "language": 4909 - }, - "nit": { - "language": 4910 - }, - "niu": { - "language": 4911 - }, - "niv": { - "language": 4912 - }, - "niw": { - "language": 4913 - }, - "nix": { - "language": 4914 - }, - "niy": { - "language": 4915 - }, - "niz": { - "language": 4916 - }, - "nja": { - "language": 4917 - }, - "njb": { - "language": 4918 - }, - "njd": { - "language": 4919 - }, - "njh": { - "language": 4920 - }, - "nji": { - "language": 4921 - }, - "njj": { - "language": 4922 - }, - "njl": { - "language": 4923 - }, - "njm": { - "language": 4924 - }, - "njn": { - "language": 4925 - }, - "njo": { - "language": 4926 - }, - "njr": { - "language": 4927 - }, - "njs": { - "language": 4928 - }, - "njt": { - "language": 4929 - }, - "nju": { - "language": 4930 - }, - "njx": { - "language": 4931 - }, - "njy": { - "language": 4932 - }, - "njz": { - "language": 4933 - }, - "nka": { - "language": 4934 - }, - "nkb": { - "language": 4935 - }, - "nkc": { - "language": 4936 - }, - "nkd": { - "language": 4937 - }, - "nke": { - "language": 4938 - }, - "nkf": { - "language": 4939 - }, - "nkg": { - "language": 4940 - }, - "nkh": { - "language": 4941 - }, - "nki": { - "language": 4942 - }, - "nkj": { - "language": 4943 - }, - "nkk": { - "language": 4944 - }, - "nkm": { - "language": 4945 - }, - "nkn": { - "language": 4946 - }, - "nko": { - "language": 4947 - }, - "nkp": { - "language": 4948 - }, - "nkq": { - "language": 4949 - }, - "nkr": { - "language": 4950 - }, - "nks": { - "language": 4951 - }, - "nkt": { - "language": 4952 - }, - "nku": { - "language": 4953 - }, - "nkv": { - "language": 4954 - }, - "nkw": { - "language": 4955 - }, - "nkx": { - "language": 4956 - }, - "nkz": { - "language": 4957 - }, - "nla": { - "language": 4958 - }, - "nlc": { - "language": 4959 - }, - "nle": { - "language": 4960 - }, - "nlg": { - "language": 4961 - }, - "nli": { - "language": 4962 - }, - "nlj": { - "language": 4963 - }, - "nlk": { - "language": 4964 - }, - "nll": { - "language": 4965 - }, - "nlm": { - "language": 4966 - }, - "nln": { - "language": 4967 - }, - "nlo": { - "language": 4968 - }, - "nlq": { - "language": 4969 - }, - "nlr": { - "language": 4970 - }, - "nlu": { - "language": 4971 - }, - "nlv": { - "language": 4972 - }, - "nlw": { - "language": 4973 - }, - "nlx": { - "language": 4974 - }, - "nly": { - "language": 4975 - }, - "nlz": { - "language": 4976 - }, - "nma": { - "language": 4977 - }, - "nmb": { - "language": 4978 - }, - "nmc": { - "language": 4979 - }, - "nmd": { - "language": 4980 - }, - "nme": { - "language": 4981 - }, - "nmf": { - "language": 4982 - }, - "nmg": { - "language": 4983 - }, - "nmh": { - "language": 4984 - }, - "nmi": { - "language": 4985 - }, - "nmj": { - "language": 4986 - }, - "nmk": { - "language": 4987 - }, - "nml": { - "language": 4988 - }, - "nmm": { - "language": 4989 - }, - "nmn": { - "language": 4990 - }, - "nmo": { - "language": 4991 - }, - "nmp": { - "language": 4992 - }, - "nmq": { - "language": 4993 - }, - "nmr": { - "language": 4994 - }, - "nms": { - "language": 4995 - }, - "nmt": { - "language": 4996 - }, - "nmu": { - "language": 4997 - }, - "nmv": { - "language": 4998 - }, - "nmw": { - "language": 4999 - }, - "nmx": { - "language": 5000 - }, - "nmy": { - "language": 5001 - }, - "nmz": { - "language": 5002 - }, - "nna": { - "language": 5003 - }, - "nnb": { - "language": 5004 - }, - "nnc": { - "language": 5005 - }, - "nnd": { - "language": 5006 - }, - "nne": { - "language": 5007 - }, - "nnf": { - "language": 5008 - }, - "nng": { - "language": 5009 - }, - "nnh": { - "language": 5010 - }, - "nni": { - "language": 5011 - }, - "nnj": { - "language": 5012 - }, - "nnk": { - "language": 5013 - }, - "nnl": { - "language": 5014 - }, - "nnm": { - "language": 5015 - }, - "nnn": { - "language": 5016 - }, - "nnp": { - "language": 5017 - }, - "nnq": { - "language": 5018 - }, - "nnr": { - "language": 5019 - }, - "nns": { - "language": 5020 - }, - "nnt": { - "language": 5021 - }, - "nnu": { - "language": 5022 - }, - "nnv": { - "language": 5023 - }, - "nnw": { - "language": 5024 - }, - "nnx": { - "language": 5025 - }, - "nny": { - "language": 5026 - }, - "nnz": { - "language": 5027 - }, - "noa": { - "language": 5028 - }, - "noc": { - "language": 5029 - }, - "nod": { - "language": 5030 - }, - "noe": { - "language": 5031 - }, - "nof": { - "language": 5032 - }, - "nog": { - "language": 5033 - }, - "noh": { - "language": 5034 - }, - "noi": { - "language": 5035 - }, - "noj": { - "language": 5036 - }, - "nok": { - "language": 5037 - }, - "nol": { - "language": 5038 - }, - "nom": { - "language": 5039 - }, - "non": { - "language": 5040 - }, - "noo": { - "language": 5041 - }, - "nop": { - "language": 5042 - }, - "noq": { - "language": 5043 - }, - "nos": { - "language": 5044 - }, - "not": { - "language": 5045 - }, - "nou": { - "language": 5046 - }, - "nov": { - "language": 5047 - }, - "now": { - "language": 5048 - }, - "noy": { - "language": 5049 - }, - "noz": { - "language": 5050 - }, - "npa": { - "language": 5051 - }, - "npb": { - "language": 5052 - }, - "npg": { - "language": 5053 - }, - "nph": { - "language": 5054 - }, - "npi": { - "language": 5055 - }, - "npl": { - "language": 5056 - }, - "npn": { - "language": 5057 - }, - "npo": { - "language": 5058 - }, - "nps": { - "language": 5059 - }, - "npu": { - "language": 5060 - }, - "npx": { - "language": 5061 - }, - "npy": { - "language": 5062 - }, - "nqg": { - "language": 5063 - }, - "nqk": { - "language": 5064 - }, - "nql": { - "language": 5065 - }, - "nqm": { - "language": 5066 - }, - "nqn": { - "language": 5067 - }, - "nqo": { - "language": 5068 - }, - "nqq": { - "language": 5069 - }, - "nqt": { - "language": 5070 - }, - "nqy": { - "language": 5071 - }, - "nra": { - "language": 5072 - }, - "nrb": { - "language": 5073 - }, - "nrc": { - "language": 5074 - }, - "nre": { - "language": 5075 - }, - "nrf": { - "language": 5076 - }, - "nrg": { - "language": 5077 - }, - "nri": { - "language": 5078 - }, - "nrk": { - "language": 5079 - }, - "nrl": { - "language": 5080 - }, - "nrm": { - "language": 5081 - }, - "nrn": { - "language": 5082 - }, - "nrp": { - "language": 5083 - }, - "nrr": { - "language": 5084 - }, - "nrt": { - "language": 5085 - }, - "nru": { - "language": 5086 - }, - "nrx": { - "language": 5087 - }, - "nrz": { - "language": 5088 - }, - "nsa": { - "language": 5089 - }, - "nsb": { - "language": 5090 - }, - "nsc": { - "language": 5091 - }, - "nsd": { - "language": 5092 - }, - "nse": { - "language": 5093 - }, - "nsf": { - "language": 5094 - }, - "nsg": { - "language": 5095 - }, - "nsh": { - "language": 5096 - }, - "nsi": { - "language": 5097, - "extlang": 8405 - }, - "nsk": { - "language": 5098 - }, - "nsl": { - "language": 5099, - "extlang": 8406 - }, - "nsm": { - "language": 5100 - }, - "nsn": { - "language": 5101 - }, - "nso": { - "language": 5102 - }, - "nsp": { - "language": 5103, - "extlang": 8407 - }, - "nsq": { - "language": 5104 - }, - "nsr": { - "language": 5105, - "extlang": 8408 - }, - "nss": { - "language": 5106 - }, - "nst": { - "language": 5107 - }, - "nsu": { - "language": 5108 - }, - "nsv": { - "language": 5109 - }, - "nsw": { - "language": 5110 - }, - "nsx": { - "language": 5111 - }, - "nsy": { - "language": 5112 - }, - "nsz": { - "language": 5113 - }, - "ntd": { - "language": 5114 - }, - "nte": { - "language": 5115 - }, - "ntg": { - "language": 5116 - }, - "nti": { - "language": 5117 - }, - "ntj": { - "language": 5118 - }, - "ntk": { - "language": 5119 - }, - "ntm": { - "language": 5120 - }, - "nto": { - "language": 5121 - }, - "ntp": { - "language": 5122 - }, - "ntr": { - "language": 5123 - }, - "nts": { - "language": 5124 - }, - "ntu": { - "language": 5125 - }, - "ntw": { - "language": 5126 - }, - "ntx": { - "language": 5127 - }, - "nty": { - "language": 5128 - }, - "ntz": { - "language": 5129 - }, - "nua": { - "language": 5130 - }, - "nub": { - "language": 5131 - }, - "nuc": { - "language": 5132 - }, - "nud": { - "language": 5133 - }, - "nue": { - "language": 5134 - }, - "nuf": { - "language": 5135 - }, - "nug": { - "language": 5136 - }, - "nuh": { - "language": 5137 - }, - "nui": { - "language": 5138 - }, - "nuj": { - "language": 5139 - }, - "nuk": { - "language": 5140 - }, - "nul": { - "language": 5141 - }, - "num": { - "language": 5142 - }, - "nun": { - "language": 5143 - }, - "nuo": { - "language": 5144 - }, - "nup": { - "language": 5145 - }, - "nuq": { - "language": 5146 - }, - "nur": { - "language": 5147 - }, - "nus": { - "language": 5148 - }, - "nut": { - "language": 5149 - }, - "nuu": { - "language": 5150 - }, - "nuv": { - "language": 5151 - }, - "nuw": { - "language": 5152 - }, - "nux": { - "language": 5153 - }, - "nuy": { - "language": 5154 - }, - "nuz": { - "language": 5155 - }, - "nvh": { - "language": 5156 - }, - "nvm": { - "language": 5157 - }, - "nvo": { - "language": 5158 - }, - "nwa": { - "language": 5159 - }, - "nwb": { - "language": 5160 - }, - "nwc": { - "language": 5161 - }, - "nwe": { - "language": 5162 - }, - "nwg": { - "language": 5163 - }, - "nwi": { - "language": 5164 - }, - "nwm": { - "language": 5165 - }, - "nwo": { - "language": 5166 - }, - "nwr": { - "language": 5167 - }, - "nww": { - "language": 5168 - }, - "nwx": { - "language": 5169 - }, - "nwy": { - "language": 5170 - }, - "nxa": { - "language": 5171 - }, - "nxd": { - "language": 5172 - }, - "nxe": { - "language": 5173 - }, - "nxg": { - "language": 5174 - }, - "nxi": { - "language": 5175 - }, - "nxk": { - "language": 5176 - }, - "nxl": { - "language": 5177 - }, - "nxm": { - "language": 5178 - }, - "nxn": { - "language": 5179 - }, - "nxo": { - "language": 5180 - }, - "nxq": { - "language": 5181 - }, - "nxr": { - "language": 5182 - }, - "nxu": { - "language": 5183 - }, - "nxx": { - "language": 5184 - }, - "nyb": { - "language": 5185 - }, - "nyc": { - "language": 5186 - }, - "nyd": { - "language": 5187 - }, - "nye": { - "language": 5188 - }, - "nyf": { - "language": 5189 - }, - "nyg": { - "language": 5190 - }, - "nyh": { - "language": 5191 - }, - "nyi": { - "language": 5192 - }, - "nyj": { - "language": 5193 - }, - "nyk": { - "language": 5194 - }, - "nyl": { - "language": 5195 - }, - "nym": { - "language": 5196 - }, - "nyn": { - "language": 5197 - }, - "nyo": { - "language": 5198 - }, - "nyp": { - "language": 5199 - }, - "nyq": { - "language": 5200 - }, - "nyr": { - "language": 5201 - }, - "nys": { - "language": 5202 - }, - "nyt": { - "language": 5203 - }, - "nyu": { - "language": 5204 - }, - "nyv": { - "language": 5205 - }, - "nyw": { - "language": 5206 - }, - "nyx": { - "language": 5207 - }, - "nyy": { - "language": 5208 - }, - "nza": { - "language": 5209 - }, - "nzb": { - "language": 5210 - }, - "nzd": { - "language": 5211 - }, - "nzi": { - "language": 5212 - }, - "nzk": { - "language": 5213 - }, - "nzm": { - "language": 5214 - }, - "nzs": { - "language": 5215, - "extlang": 8409 - }, - "nzu": { - "language": 5216 - }, - "nzy": { - "language": 5217 - }, - "nzz": { - "language": 5218 - }, - "oaa": { - "language": 5219 - }, - "oac": { - "language": 5220 - }, - "oar": { - "language": 5221 - }, - "oav": { - "language": 5222 - }, - "obi": { - "language": 5223 - }, - "obk": { - "language": 5224 - }, - "obl": { - "language": 5225 - }, - "obm": { - "language": 5226 - }, - "obo": { - "language": 5227 - }, - "obr": { - "language": 5228 - }, - "obt": { - "language": 5229 - }, - "obu": { - "language": 5230 - }, - "oca": { - "language": 5231 - }, - "och": { - "language": 5232 - }, - "ocm": { - "language": 5233 - }, - "oco": { - "language": 5234 - }, - "ocu": { - "language": 5235 - }, - "oda": { - "language": 5236 - }, - "odk": { - "language": 5237 - }, - "odt": { - "language": 5238 - }, - "odu": { - "language": 5239 - }, - "ofo": { - "language": 5240 - }, - "ofs": { - "language": 5241 - }, - "ofu": { - "language": 5242 - }, - "ogb": { - "language": 5243 - }, - "ogc": { - "language": 5244 - }, - "oge": { - "language": 5245 - }, - "ogg": { - "language": 5246 - }, - "ogo": { - "language": 5247 - }, - "ogu": { - "language": 5248 - }, - "oht": { - "language": 5249 - }, - "ohu": { - "language": 5250 - }, - "oia": { - "language": 5251 - }, - "oie": { - "language": 5252 - }, - "oin": { - "language": 5253 - }, - "ojb": { - "language": 5254 - }, - "ojc": { - "language": 5255 - }, - "ojg": { - "language": 5256 - }, - "ojp": { - "language": 5257 - }, - "ojs": { - "language": 5258 - }, - "ojv": { - "language": 5259 - }, - "ojw": { - "language": 5260 - }, - "oka": { - "language": 5261 - }, - "okb": { - "language": 5262 - }, - "okc": { - "language": 5263 - }, - "okd": { - "language": 5264 - }, - "oke": { - "language": 5265 - }, - "okg": { - "language": 5266 - }, - "okh": { - "language": 5267 - }, - "oki": { - "language": 5268 - }, - "okj": { - "language": 5269 - }, - "okk": { - "language": 5270 - }, - "okl": { - "language": 5271, - "extlang": 8410 - }, - "okm": { - "language": 5272 - }, - "okn": { - "language": 5273 - }, - "oko": { - "language": 5274 - }, - "okr": { - "language": 5275 - }, - "oks": { - "language": 5276 - }, - "oku": { - "language": 5277 - }, - "okv": { - "language": 5278 - }, - "okx": { - "language": 5279 - }, - "okz": { - "language": 5280 - }, - "ola": { - "language": 5281 - }, - "old": { - "language": 5282 - }, - "ole": { - "language": 5283 - }, - "olk": { - "language": 5284 - }, - "olm": { - "language": 5285 - }, - "olo": { - "language": 5286 - }, - "olr": { - "language": 5287 - }, - "olt": { - "language": 5288 - }, - "olu": { - "language": 5289 - }, - "oma": { - "language": 5290 - }, - "omb": { - "language": 5291 - }, - "omc": { - "language": 5292 - }, - "ome": { - "language": 5293 - }, - "omg": { - "language": 5294 - }, - "omi": { - "language": 5295 - }, - "omk": { - "language": 5296 - }, - "oml": { - "language": 5297 - }, - "omn": { - "language": 5298 - }, - "omo": { - "language": 5299 - }, - "omp": { - "language": 5300 - }, - "omq": { - "language": 5301 - }, - "omr": { - "language": 5302 - }, - "omt": { - "language": 5303 - }, - "omu": { - "language": 5304 - }, - "omv": { - "language": 5305 - }, - "omw": { - "language": 5306 - }, - "omx": { - "language": 5307 - }, - "omy": { - "language": 5308 - }, - "ona": { - "language": 5309 - }, - "onb": { - "language": 5310 - }, - "one": { - "language": 5311 - }, - "ong": { - "language": 5312 - }, - "oni": { - "language": 5313 - }, - "onj": { - "language": 5314 - }, - "onk": { - "language": 5315 - }, - "onn": { - "language": 5316 - }, - "ono": { - "language": 5317 - }, - "onp": { - "language": 5318 - }, - "onr": { - "language": 5319 - }, - "ons": { - "language": 5320 - }, - "ont": { - "language": 5321 - }, - "onu": { - "language": 5322 - }, - "onw": { - "language": 5323 - }, - "onx": { - "language": 5324 - }, - "ood": { - "language": 5325 - }, - "oog": { - "language": 5326 - }, - "oon": { - "language": 5327 - }, - "oor": { - "language": 5328 - }, - "oos": { - "language": 5329 - }, - "opa": { - "language": 5330 - }, - "opk": { - "language": 5331 - }, - "opm": { - "language": 5332 - }, - "opo": { - "language": 5333 - }, - "opt": { - "language": 5334 - }, - "opy": { - "language": 5335 - }, - "ora": { - "language": 5336 - }, - "orc": { - "language": 5337 - }, - "ore": { - "language": 5338 - }, - "org": { - "language": 5339 - }, - "orh": { - "language": 5340 - }, - "orn": { - "language": 5341, - "extlang": 8411 - }, - "oro": { - "language": 5342 - }, - "orr": { - "language": 5343 - }, - "ors": { - "language": 5344, - "extlang": 8412 - }, - "ort": { - "language": 5345 - }, - "oru": { - "language": 5346 - }, - "orv": { - "language": 5347 - }, - "orw": { - "language": 5348 - }, - "orx": { - "language": 5349 - }, - "ory": { - "language": 5350 - }, - "orz": { - "language": 5351 - }, - "osa": { - "language": 5352 - }, - "osc": { - "language": 5353 - }, - "osi": { - "language": 5354 - }, - "osn": { - "language": 5355 - }, - "oso": { - "language": 5356 - }, - "osp": { - "language": 5357 - }, - "ost": { - "language": 5358 - }, - "osu": { - "language": 5359 - }, - "osx": { - "language": 5360 - }, - "ota": { - "language": 5361 - }, - "otb": { - "language": 5362 - }, - "otd": { - "language": 5363 - }, - "ote": { - "language": 5364 - }, - "oti": { - "language": 5365 - }, - "otk": { - "language": 5366 - }, - "otl": { - "language": 5367 - }, - "otm": { - "language": 5368 - }, - "otn": { - "language": 5369 - }, - "oto": { - "language": 5370 - }, - "otq": { - "language": 5371 - }, - "otr": { - "language": 5372 - }, - "ots": { - "language": 5373 - }, - "ott": { - "language": 5374 - }, - "otu": { - "language": 5375 - }, - "otw": { - "language": 5376 - }, - "otx": { - "language": 5377 - }, - "oty": { - "language": 5378 - }, - "otz": { - "language": 5379 - }, - "oua": { - "language": 5380 - }, - "oub": { - "language": 5381 - }, - "oue": { - "language": 5382 - }, - "oui": { - "language": 5383 - }, - "oum": { - "language": 5384 - }, - "oun": { - "language": 5385 - }, - "ovd": { - "language": 5386 - }, - "owi": { - "language": 5387 - }, - "owl": { - "language": 5388 - }, - "oyb": { - "language": 5389 - }, - "oyd": { - "language": 5390 - }, - "oym": { - "language": 5391 - }, - "oyy": { - "language": 5392 - }, - "ozm": { - "language": 5393 - }, - "paa": { - "language": 5394 - }, - "pab": { - "language": 5395 - }, - "pac": { - "language": 5396 - }, - "pad": { - "language": 5397 - }, - "pae": { - "language": 5398 - }, - "paf": { - "language": 5399 - }, - "pag": { - "language": 5400 - }, - "pah": { - "language": 5401 - }, - "pai": { - "language": 5402 - }, - "pak": { - "language": 5403 - }, - "pal": { - "language": 5404 - }, - "pam": { - "language": 5405 - }, - "pao": { - "language": 5406 - }, - "pap": { - "language": 5407 - }, - "paq": { - "language": 5408 - }, - "par": { - "language": 5409 - }, - "pas": { - "language": 5410 - }, - "pat": { - "language": 5411 - }, - "pau": { - "language": 5412 - }, - "pav": { - "language": 5413 - }, - "paw": { - "language": 5414 - }, - "pax": { - "language": 5415 - }, - "pay": { - "language": 5416 - }, - "paz": { - "language": 5417 - }, - "pbb": { - "language": 5418 - }, - "pbc": { - "language": 5419 - }, - "pbe": { - "language": 5420 - }, - "pbf": { - "language": 5421 - }, - "pbg": { - "language": 5422 - }, - "pbh": { - "language": 5423 - }, - "pbi": { - "language": 5424 - }, - "pbl": { - "language": 5425 - }, - "pbm": { - "language": 5426 - }, - "pbn": { - "language": 5427 - }, - "pbo": { - "language": 5428 - }, - "pbp": { - "language": 5429 - }, - "pbr": { - "language": 5430 - }, - "pbs": { - "language": 5431 - }, - "pbt": { - "language": 5432 - }, - "pbu": { - "language": 5433 - }, - "pbv": { - "language": 5434 - }, - "pby": { - "language": 5435 - }, - "pbz": { - "language": 5436 - }, - "pca": { - "language": 5437 - }, - "pcb": { - "language": 5438 - }, - "pcc": { - "language": 5439 - }, - "pcd": { - "language": 5440 - }, - "pce": { - "language": 5441 - }, - "pcf": { - "language": 5442 - }, - "pcg": { - "language": 5443 - }, - "pch": { - "language": 5444 - }, - "pci": { - "language": 5445 - }, - "pcj": { - "language": 5446 - }, - "pck": { - "language": 5447 - }, - "pcl": { - "language": 5448 - }, - "pcm": { - "language": 5449 - }, - "pcn": { - "language": 5450 - }, - "pcp": { - "language": 5451 - }, - "pcr": { - "language": 5452 - }, - "pcw": { - "language": 5453 - }, - "pda": { - "language": 5454 - }, - "pdc": { - "language": 5455 - }, - "pdi": { - "language": 5456 - }, - "pdn": { - "language": 5457 - }, - "pdo": { - "language": 5458 - }, - "pdt": { - "language": 5459 - }, - "pdu": { - "language": 5460 - }, - "pea": { - "language": 5461 - }, - "peb": { - "language": 5462 - }, - "ped": { - "language": 5463 - }, - "pee": { - "language": 5464 - }, - "pef": { - "language": 5465 - }, - "peg": { - "language": 5466 - }, - "peh": { - "language": 5467 - }, - "pei": { - "language": 5468 - }, - "pej": { - "language": 5469 - }, - "pek": { - "language": 5470 - }, - "pel": { - "language": 5471, - "extlang": 8413 - }, - "pem": { - "language": 5472 - }, - "peo": { - "language": 5473 - }, - "pep": { - "language": 5474 - }, - "peq": { - "language": 5475 - }, - "pes": { - "language": 5476 - }, - "pev": { - "language": 5477 - }, - "pex": { - "language": 5478 - }, - "pey": { - "language": 5479 - }, - "pez": { - "language": 5480 - }, - "pfa": { - "language": 5481 - }, - "pfe": { - "language": 5482 - }, - "pfl": { - "language": 5483 - }, - "pga": { - "language": 5484, - "extlang": 8414 - }, - "pgd": { - "language": 5485 - }, - "pgg": { - "language": 5486 - }, - "pgi": { - "language": 5487 - }, - "pgk": { - "language": 5488 - }, - "pgl": { - "language": 5489 - }, - "pgn": { - "language": 5490 - }, - "pgs": { - "language": 5491 - }, - "pgu": { - "language": 5492 - }, - "pgy": { - "language": 5493 - }, - "pgz": { - "language": 5494, - "extlang": 8415 - }, - "pha": { - "language": 5495 - }, - "phd": { - "language": 5496 - }, - "phg": { - "language": 5497 - }, - "phh": { - "language": 5498 - }, - "phi": { - "language": 5499 - }, - "phj": { - "language": 5500 - }, - "phk": { - "language": 5501 - }, - "phl": { - "language": 5502 - }, - "phm": { - "language": 5503 - }, - "phn": { - "language": 5504 - }, - "pho": { - "language": 5505 - }, - "phq": { - "language": 5506 - }, - "phr": { - "language": 5507 - }, - "pht": { - "language": 5508 - }, - "phu": { - "language": 5509 - }, - "phv": { - "language": 5510 - }, - "phw": { - "language": 5511 - }, - "pia": { - "language": 5512 - }, - "pib": { - "language": 5513 - }, - "pic": { - "language": 5514 - }, - "pid": { - "language": 5515 - }, - "pie": { - "language": 5516 - }, - "pif": { - "language": 5517 - }, - "pig": { - "language": 5518 - }, - "pih": { - "language": 5519 - }, - "pii": { - "language": 5520 - }, - "pij": { - "language": 5521 - }, - "pil": { - "language": 5522 - }, - "pim": { - "language": 5523 - }, - "pin": { - "language": 5524 - }, - "pio": { - "language": 5525 - }, - "pip": { - "language": 5526 - }, - "pir": { - "language": 5527 - }, - "pis": { - "language": 5528 - }, - "pit": { - "language": 5529 - }, - "piu": { - "language": 5530 - }, - "piv": { - "language": 5531 - }, - "piw": { - "language": 5532 - }, - "pix": { - "language": 5533 - }, - "piy": { - "language": 5534 - }, - "piz": { - "language": 5535 - }, - "pjt": { - "language": 5536 - }, - "pka": { - "language": 5537 - }, - "pkb": { - "language": 5538 - }, - "pkc": { - "language": 5539 - }, - "pkg": { - "language": 5540 - }, - "pkh": { - "language": 5541 - }, - "pkn": { - "language": 5542 - }, - "pko": { - "language": 5543 - }, - "pkp": { - "language": 5544 - }, - "pkr": { - "language": 5545 - }, - "pks": { - "language": 5546, - "extlang": 8416 - }, - "pkt": { - "language": 5547 - }, - "pku": { - "language": 5548 - }, - "pla": { - "language": 5549 - }, - "plb": { - "language": 5550 - }, - "plc": { - "language": 5551 - }, - "pld": { - "language": 5552 - }, - "ple": { - "language": 5553 - }, - "plf": { - "language": 5554 - }, - "plg": { - "language": 5555 - }, - "plh": { - "language": 5556 - }, - "plj": { - "language": 5557 - }, - "plk": { - "language": 5558 - }, - "pll": { - "language": 5559 - }, - "pln": { - "language": 5560 - }, - "plo": { - "language": 5561 - }, - "plp": { - "language": 5562 - }, - "plq": { - "language": 5563 - }, - "plr": { - "language": 5564 - }, - "pls": { - "language": 5565 - }, - "plt": { - "language": 5566 - }, - "plu": { - "language": 5567 - }, - "plv": { - "language": 5568 - }, - "plw": { - "language": 5569 - }, - "ply": { - "language": 5570 - }, - "plz": { - "language": 5571 - }, - "pma": { - "language": 5572 - }, - "pmb": { - "language": 5573 - }, - "pmc": { - "language": 5574 - }, - "pmd": { - "language": 5575 - }, - "pme": { - "language": 5576 - }, - "pmf": { - "language": 5577 - }, - "pmh": { - "language": 5578 - }, - "pmi": { - "language": 5579 - }, - "pmj": { - "language": 5580 - }, - "pmk": { - "language": 5581 - }, - "pml": { - "language": 5582 - }, - "pmm": { - "language": 5583 - }, - "pmn": { - "language": 5584 - }, - "pmo": { - "language": 5585 - }, - "pmq": { - "language": 5586 - }, - "pmr": { - "language": 5587 - }, - "pms": { - "language": 5588 - }, - "pmt": { - "language": 5589 - }, - "pmu": { - "language": 5590 - }, - "pmw": { - "language": 5591 - }, - "pmx": { - "language": 5592 - }, - "pmy": { - "language": 5593 - }, - "pmz": { - "language": 5594 - }, - "pna": { - "language": 5595 - }, - "pnb": { - "language": 5596 - }, - "pnc": { - "language": 5597 - }, - "pnd": { - "language": 5598 - }, - "pne": { - "language": 5599 - }, - "png": { - "language": 5600 - }, - "pnh": { - "language": 5601 - }, - "pni": { - "language": 5602 - }, - "pnj": { - "language": 5603 - }, - "pnk": { - "language": 5604 - }, - "pnl": { - "language": 5605 - }, - "pnm": { - "language": 5606 - }, - "pnn": { - "language": 5607 - }, - "pno": { - "language": 5608 - }, - "pnp": { - "language": 5609 - }, - "pnq": { - "language": 5610 - }, - "pnr": { - "language": 5611 - }, - "pns": { - "language": 5612 - }, - "pnt": { - "language": 5613 - }, - "pnu": { - "language": 5614 - }, - "pnv": { - "language": 5615 - }, - "pnw": { - "language": 5616 - }, - "pnx": { - "language": 5617 - }, - "pny": { - "language": 5618 - }, - "pnz": { - "language": 5619 - }, - "poc": { - "language": 5620 - }, - "pod": { - "language": 5621 - }, - "poe": { - "language": 5622 - }, - "pof": { - "language": 5623 - }, - "pog": { - "language": 5624 - }, - "poh": { - "language": 5625 - }, - "poi": { - "language": 5626 - }, - "pok": { - "language": 5627 - }, - "pom": { - "language": 5628 - }, - "pon": { - "language": 5629 - }, - "poo": { - "language": 5630 - }, - "pop": { - "language": 5631 - }, - "poq": { - "language": 5632 - }, - "pos": { - "language": 5633 - }, - "pot": { - "language": 5634 - }, - "pov": { - "language": 5635 - }, - "pow": { - "language": 5636 - }, - "pox": { - "language": 5637 - }, - "poy": { - "language": 5638 - }, - "poz": { - "language": 5639 - }, - "ppa": { - "language": 5640 - }, - "ppe": { - "language": 5641 - }, - "ppi": { - "language": 5642 - }, - "ppk": { - "language": 5643 - }, - "ppl": { - "language": 5644 - }, - "ppm": { - "language": 5645 - }, - "ppn": { - "language": 5646 - }, - "ppo": { - "language": 5647 - }, - "ppp": { - "language": 5648 - }, - "ppq": { - "language": 5649 - }, - "ppr": { - "language": 5650 - }, - "pps": { - "language": 5651 - }, - "ppt": { - "language": 5652 - }, - "ppu": { - "language": 5653 - }, - "pqa": { - "language": 5654 - }, - "pqe": { - "language": 5655 - }, - "pqm": { - "language": 5656 - }, - "pqw": { - "language": 5657 - }, - "pra": { - "language": 5658 - }, - "prb": { - "language": 5659 - }, - "prc": { - "language": 5660 - }, - "prd": { - "language": 5661 - }, - "pre": { - "language": 5662 - }, - "prf": { - "language": 5663 - }, - "prg": { - "language": 5664 - }, - "prh": { - "language": 5665 - }, - "pri": { - "language": 5666 - }, - "prk": { - "language": 5667 - }, - "prl": { - "language": 5668, - "extlang": 8417 - }, - "prm": { - "language": 5669 - }, - "prn": { - "language": 5670 - }, - "pro": { - "language": 5671 - }, - "prp": { - "language": 5672 - }, - "prq": { - "language": 5673 - }, - "prr": { - "language": 5674 - }, - "prs": { - "language": 5675 - }, - "prt": { - "language": 5676 - }, - "pru": { - "language": 5677 - }, - "prw": { - "language": 5678 - }, - "prx": { - "language": 5679 - }, - "pry": { - "language": 5680 - }, - "prz": { - "language": 5681, - "extlang": 8418 - }, - "psa": { - "language": 5682 - }, - "psc": { - "language": 5683, - "extlang": 8419 - }, - "psd": { - "language": 5684, - "extlang": 8420 - }, - "pse": { - "language": 5685, - "extlang": 8421 - }, - "psg": { - "language": 5686, - "extlang": 8422 - }, - "psh": { - "language": 5687 - }, - "psi": { - "language": 5688 - }, - "psl": { - "language": 5689, - "extlang": 8423 - }, - "psm": { - "language": 5690 - }, - "psn": { - "language": 5691 - }, - "pso": { - "language": 5692, - "extlang": 8424 - }, - "psp": { - "language": 5693, - "extlang": 8425 - }, - "psq": { - "language": 5694 - }, - "psr": { - "language": 5695, - "extlang": 8426 - }, - "pss": { - "language": 5696 - }, - "pst": { - "language": 5697 - }, - "psu": { - "language": 5698 - }, - "psw": { - "language": 5699 - }, - "psy": { - "language": 5700 - }, - "pta": { - "language": 5701 - }, - "pth": { - "language": 5702 - }, - "pti": { - "language": 5703 - }, - "ptn": { - "language": 5704 - }, - "pto": { - "language": 5705 - }, - "ptp": { - "language": 5706 - }, - "ptq": { - "language": 5707 - }, - "ptr": { - "language": 5708 - }, - "ptt": { - "language": 5709 - }, - "ptu": { - "language": 5710 - }, - "ptv": { - "language": 5711 - }, - "ptw": { - "language": 5712 - }, - "pty": { - "language": 5713 - }, - "pua": { - "language": 5714 - }, - "pub": { - "language": 5715 - }, - "puc": { - "language": 5716 - }, - "pud": { - "language": 5717 - }, - "pue": { - "language": 5718 - }, - "puf": { - "language": 5719 - }, - "pug": { - "language": 5720 - }, - "pui": { - "language": 5721 - }, - "puj": { - "language": 5722 - }, - "puk": { - "language": 5723 - }, - "pum": { - "language": 5724 - }, - "puo": { - "language": 5725 - }, - "pup": { - "language": 5726 - }, - "puq": { - "language": 5727 - }, - "pur": { - "language": 5728 - }, - "put": { - "language": 5729 - }, - "puu": { - "language": 5730 - }, - "puw": { - "language": 5731 - }, - "pux": { - "language": 5732 - }, - "puy": { - "language": 5733 - }, - "puz": { - "language": 5734 - }, - "pwa": { - "language": 5735 - }, - "pwb": { - "language": 5736 - }, - "pwg": { - "language": 5737 - }, - "pwi": { - "language": 5738 - }, - "pwm": { - "language": 5739 - }, - "pwn": { - "language": 5740 - }, - "pwo": { - "language": 5741 - }, - "pwr": { - "language": 5742 - }, - "pww": { - "language": 5743 - }, - "pxm": { - "language": 5744 - }, - "pye": { - "language": 5745 - }, - "pym": { - "language": 5746 - }, - "pyn": { - "language": 5747 - }, - "pys": { - "language": 5748, - "extlang": 8427 - }, - "pyu": { - "language": 5749 - }, - "pyx": { - "language": 5750 - }, - "pyy": { - "language": 5751 - }, - "pzh": { - "language": 5752 - }, - "pzn": { - "language": 5753 - }, - "qaa..qtz": { - "language": 5754 - }, - "qua": { - "language": 5755 - }, - "qub": { - "language": 5756 - }, - "quc": { - "language": 5757 - }, - "qud": { - "language": 5758 - }, - "quf": { - "language": 5759 - }, - "qug": { - "language": 5760 - }, - "quh": { - "language": 5761 - }, - "qui": { - "language": 5762 - }, - "quk": { - "language": 5763 - }, - "qul": { - "language": 5764 - }, - "qum": { - "language": 5765 - }, - "qun": { - "language": 5766 - }, - "qup": { - "language": 5767 - }, - "quq": { - "language": 5768 - }, - "qur": { - "language": 5769 - }, - "qus": { - "language": 5770 - }, - "quv": { - "language": 5771 - }, - "quw": { - "language": 5772 - }, - "qux": { - "language": 5773 - }, - "quy": { - "language": 5774 - }, - "quz": { - "language": 5775 - }, - "qva": { - "language": 5776 - }, - "qvc": { - "language": 5777 - }, - "qve": { - "language": 5778 - }, - "qvh": { - "language": 5779 - }, - "qvi": { - "language": 5780 - }, - "qvj": { - "language": 5781 - }, - "qvl": { - "language": 5782 - }, - "qvm": { - "language": 5783 - }, - "qvn": { - "language": 5784 - }, - "qvo": { - "language": 5785 - }, - "qvp": { - "language": 5786 - }, - "qvs": { - "language": 5787 - }, - "qvw": { - "language": 5788 - }, - "qvy": { - "language": 5789 - }, - "qvz": { - "language": 5790 - }, - "qwa": { - "language": 5791 - }, - "qwc": { - "language": 5792 - }, - "qwe": { - "language": 5793 - }, - "qwh": { - "language": 5794 - }, - "qwm": { - "language": 5795 - }, - "qws": { - "language": 5796 - }, - "qwt": { - "language": 5797 - }, - "qxa": { - "language": 5798 - }, - "qxc": { - "language": 5799 - }, - "qxh": { - "language": 5800 - }, - "qxl": { - "language": 5801 - }, - "qxn": { - "language": 5802 - }, - "qxo": { - "language": 5803 - }, - "qxp": { - "language": 5804 - }, - "qxq": { - "language": 5805 - }, - "qxr": { - "language": 5806 - }, - "qxs": { - "language": 5807 - }, - "qxt": { - "language": 5808 - }, - "qxu": { - "language": 5809 - }, - "qxw": { - "language": 5810 - }, - "qya": { - "language": 5811 - }, - "qyp": { - "language": 5812 - }, - "raa": { - "language": 5813 - }, - "rab": { - "language": 5814 - }, - "rac": { - "language": 5815 - }, - "rad": { - "language": 5816 - }, - "raf": { - "language": 5817 - }, - "rag": { - "language": 5818 - }, - "rah": { - "language": 5819 - }, - "rai": { - "language": 5820 - }, - "raj": { - "language": 5821 - }, - "rak": { - "language": 5822 - }, - "ral": { - "language": 5823 - }, - "ram": { - "language": 5824 - }, - "ran": { - "language": 5825 - }, - "rao": { - "language": 5826 - }, - "rap": { - "language": 5827 - }, - "raq": { - "language": 5828 - }, - "rar": { - "language": 5829 - }, - "ras": { - "language": 5830 - }, - "rat": { - "language": 5831 - }, - "rau": { - "language": 5832 - }, - "rav": { - "language": 5833 - }, - "raw": { - "language": 5834 - }, - "rax": { - "language": 5835 - }, - "ray": { - "language": 5836 - }, - "raz": { - "language": 5837 - }, - "rbb": { - "language": 5838 - }, - "rbk": { - "language": 5839 - }, - "rbl": { - "language": 5840 - }, - "rbp": { - "language": 5841 - }, - "rcf": { - "language": 5842 - }, - "rdb": { - "language": 5843 - }, - "rea": { - "language": 5844 - }, - "reb": { - "language": 5845 - }, - "ree": { - "language": 5846 - }, - "reg": { - "language": 5847 - }, - "rei": { - "language": 5848 - }, - "rej": { - "language": 5849 - }, - "rel": { - "language": 5850 - }, - "rem": { - "language": 5851 - }, - "ren": { - "language": 5852 - }, - "rer": { - "language": 5853 - }, - "res": { - "language": 5854 - }, - "ret": { - "language": 5855 - }, - "rey": { - "language": 5856 - }, - "rga": { - "language": 5857 - }, - "rge": { - "language": 5858 - }, - "rgk": { - "language": 5859 - }, - "rgn": { - "language": 5860 - }, - "rgr": { - "language": 5861 - }, - "rgs": { - "language": 5862 - }, - "rgu": { - "language": 5863 - }, - "rhg": { - "language": 5864 - }, - "rhp": { - "language": 5865 - }, - "ria": { - "language": 5866 - }, - "rib": { - "language": 5867, - "extlang": 8428 - }, - "rie": { - "language": 5868 - }, - "rif": { - "language": 5869 - }, - "ril": { - "language": 5870 - }, - "rim": { - "language": 5871 - }, - "rin": { - "language": 5872 - }, - "rir": { - "language": 5873 - }, - "rit": { - "language": 5874 - }, - "riu": { - "language": 5875 - }, - "rjg": { - "language": 5876 - }, - "rji": { - "language": 5877 - }, - "rjs": { - "language": 5878 - }, - "rka": { - "language": 5879 - }, - "rkb": { - "language": 5880 - }, - "rkh": { - "language": 5881 - }, - "rki": { - "language": 5882 - }, - "rkm": { - "language": 5883 - }, - "rkt": { - "language": 5884 - }, - "rkw": { - "language": 5885 - }, - "rma": { - "language": 5886 - }, - "rmb": { - "language": 5887 - }, - "rmc": { - "language": 5888 - }, - "rmd": { - "language": 5889 - }, - "rme": { - "language": 5890 - }, - "rmf": { - "language": 5891 - }, - "rmg": { - "language": 5892 - }, - "rmh": { - "language": 5893 - }, - "rmi": { - "language": 5894 - }, - "rmk": { - "language": 5895 - }, - "rml": { - "language": 5896 - }, - "rmm": { - "language": 5897 - }, - "rmn": { - "language": 5898 - }, - "rmo": { - "language": 5899 - }, - "rmp": { - "language": 5900 - }, - "rmq": { - "language": 5901 - }, - "rmr": { - "language": 5902 - }, - "rms": { - "language": 5903, - "extlang": 8429 - }, - "rmt": { - "language": 5904 - }, - "rmu": { - "language": 5905 - }, - "rmv": { - "language": 5906 - }, - "rmw": { - "language": 5907 - }, - "rmx": { - "language": 5908 - }, - "rmy": { - "language": 5909 - }, - "rmz": { - "language": 5910 - }, - "rna": { - "language": 5911 - }, - "rnb": { - "language": 5912, - "extlang": 8430 - }, - "rnd": { - "language": 5913 - }, - "rng": { - "language": 5914 - }, - "rnl": { - "language": 5915 - }, - "rnn": { - "language": 5916 - }, - "rnp": { - "language": 5917 - }, - "rnr": { - "language": 5918 - }, - "rnw": { - "language": 5919 - }, - "roa": { - "language": 5920 - }, - "rob": { - "language": 5921 - }, - "roc": { - "language": 5922 - }, - "rod": { - "language": 5923 - }, - "roe": { - "language": 5924 - }, - "rof": { - "language": 5925 - }, - "rog": { - "language": 5926 - }, - "rol": { - "language": 5927 - }, - "rom": { - "language": 5928 - }, - "roo": { - "language": 5929 - }, - "rop": { - "language": 5930 - }, - "ror": { - "language": 5931 - }, - "rou": { - "language": 5932 - }, - "row": { - "language": 5933 - }, - "rpn": { - "language": 5934 - }, - "rpt": { - "language": 5935 - }, - "rri": { - "language": 5936 - }, - "rro": { - "language": 5937 - }, - "rrt": { - "language": 5938 - }, - "rsb": { - "language": 5939 - }, - "rsi": { - "language": 5940, - "extlang": 8431 - }, - "rsk": { - "language": 5941 - }, - "rsl": { - "language": 5942, - "extlang": 8432 - }, - "rsm": { - "language": 5943, - "extlang": 8433 - }, - "rsn": { - "language": 5944, - "extlang": 8434 - }, - "rtc": { - "language": 5945 - }, - "rth": { - "language": 5946 - }, - "rtm": { - "language": 5947 - }, - "rts": { - "language": 5948 - }, - "rtw": { - "language": 5949 - }, - "rub": { - "language": 5950 - }, - "ruc": { - "language": 5951 - }, - "rue": { - "language": 5952 - }, - "ruf": { - "language": 5953 - }, - "rug": { - "language": 5954 - }, - "ruh": { - "language": 5955 - }, - "rui": { - "language": 5956 - }, - "ruk": { - "language": 5957 - }, - "ruo": { - "language": 5958 - }, - "rup": { - "language": 5959 - }, - "ruq": { - "language": 5960 - }, - "rut": { - "language": 5961 - }, - "ruu": { - "language": 5962 - }, - "ruy": { - "language": 5963 - }, - "ruz": { - "language": 5964 - }, - "rwa": { - "language": 5965 - }, - "rwk": { - "language": 5966 - }, - "rwl": { - "language": 5967 - }, - "rwm": { - "language": 5968 - }, - "rwo": { - "language": 5969 - }, - "rwr": { - "language": 5970 - }, - "rxd": { - "language": 5971 - }, - "rxw": { - "language": 5972 - }, - "ryn": { - "language": 5973 - }, - "rys": { - "language": 5974 - }, - "ryu": { - "language": 5975 - }, - "rzh": { - "language": 5976 - }, - "saa": { - "language": 5977 - }, - "sab": { - "language": 5978 - }, - "sac": { - "language": 5979 - }, - "sad": { - "language": 5980 - }, - "sae": { - "language": 5981 - }, - "saf": { - "language": 5982 - }, - "sah": { - "language": 5983 - }, - "sai": { - "language": 5984 - }, - "saj": { - "language": 5985 - }, - "sak": { - "language": 5986 - }, - "sal": { - "language": 5987 - }, - "sam": { - "language": 5988 - }, - "sao": { - "language": 5989 - }, - "sap": { - "language": 5990 - }, - "saq": { - "language": 5991 - }, - "sar": { - "language": 5992 - }, - "sas": { - "language": 5993 - }, - "sat": { - "language": 5994 - }, - "sau": { - "language": 5995 - }, - "sav": { - "language": 5996 - }, - "saw": { - "language": 5997 - }, - "sax": { - "language": 5998 - }, - "say": { - "language": 5999 - }, - "saz": { - "language": 6000 - }, - "sba": { - "language": 6001 - }, - "sbb": { - "language": 6002 - }, - "sbc": { - "language": 6003 - }, - "sbd": { - "language": 6004 - }, - "sbe": { - "language": 6005 - }, - "sbf": { - "language": 6006 - }, - "sbg": { - "language": 6007 - }, - "sbh": { - "language": 6008 - }, - "sbi": { - "language": 6009 - }, - "sbj": { - "language": 6010 - }, - "sbk": { - "language": 6011 - }, - "sbl": { - "language": 6012 - }, - "sbm": { - "language": 6013 - }, - "sbn": { - "language": 6014 - }, - "sbo": { - "language": 6015 - }, - "sbp": { - "language": 6016 - }, - "sbq": { - "language": 6017 - }, - "sbr": { - "language": 6018 - }, - "sbs": { - "language": 6019 - }, - "sbt": { - "language": 6020 - }, - "sbu": { - "language": 6021 - }, - "sbv": { - "language": 6022 - }, - "sbw": { - "language": 6023 - }, - "sbx": { - "language": 6024 - }, - "sby": { - "language": 6025 - }, - "sbz": { - "language": 6026 - }, - "sca": { - "language": 6027 - }, - "scb": { - "language": 6028 - }, - "sce": { - "language": 6029 - }, - "scf": { - "language": 6030 - }, - "scg": { - "language": 6031 - }, - "sch": { - "language": 6032 - }, - "sci": { - "language": 6033 - }, - "sck": { - "language": 6034 - }, - "scl": { - "language": 6035 - }, - "scn": { - "language": 6036 - }, - "sco": { - "language": 6037 - }, - "scp": { - "language": 6038 - }, - "scq": { - "language": 6039 - }, - "scs": { - "language": 6040 - }, - "sct": { - "language": 6041 - }, - "scu": { - "language": 6042 - }, - "scv": { - "language": 6043 - }, - "scw": { - "language": 6044 - }, - "scx": { - "language": 6045 - }, - "sda": { - "language": 6046 - }, - "sdb": { - "language": 6047 - }, - "sdc": { - "language": 6048 - }, - "sde": { - "language": 6049 - }, - "sdf": { - "language": 6050 - }, - "sdg": { - "language": 6051 - }, - "sdh": { - "language": 6052 - }, - "sdj": { - "language": 6053 - }, - "sdk": { - "language": 6054 - }, - "sdl": { - "language": 6055, - "extlang": 8435 - }, - "sdm": { - "language": 6056 - }, - "sdn": { - "language": 6057 - }, - "sdo": { - "language": 6058 - }, - "sdp": { - "language": 6059 - }, - "sdq": { - "language": 6060 - }, - "sdr": { - "language": 6061 - }, - "sds": { - "language": 6062 - }, - "sdt": { - "language": 6063 - }, - "sdu": { - "language": 6064 - }, - "sdv": { - "language": 6065 - }, - "sdx": { - "language": 6066 - }, - "sdz": { - "language": 6067 - }, - "sea": { - "language": 6068 - }, - "seb": { - "language": 6069 - }, - "sec": { - "language": 6070 - }, - "sed": { - "language": 6071 - }, - "see": { - "language": 6072 - }, - "sef": { - "language": 6073 - }, - "seg": { - "language": 6074 - }, - "seh": { - "language": 6075 - }, - "sei": { - "language": 6076 - }, - "sej": { - "language": 6077 - }, - "sek": { - "language": 6078 - }, - "sel": { - "language": 6079 - }, - "sem": { - "language": 6080 - }, - "sen": { - "language": 6081 - }, - "seo": { - "language": 6082 - }, - "sep": { - "language": 6083 - }, - "seq": { - "language": 6084 - }, - "ser": { - "language": 6085 - }, - "ses": { - "language": 6086 - }, - "set": { - "language": 6087 - }, - "seu": { - "language": 6088 - }, - "sev": { - "language": 6089 - }, - "sew": { - "language": 6090 - }, - "sey": { - "language": 6091 - }, - "sez": { - "language": 6092 - }, - "sfb": { - "language": 6093, - "extlang": 8436 - }, - "sfe": { - "language": 6094 - }, - "sfm": { - "language": 6095 - }, - "sfs": { - "language": 6096, - "extlang": 8437 - }, - "sfw": { - "language": 6097 - }, - "sga": { - "language": 6098 - }, - "sgb": { - "language": 6099 - }, - "sgc": { - "language": 6100 - }, - "sgd": { - "language": 6101 - }, - "sge": { - "language": 6102 - }, - "sgg": { - "language": 6103, - "extlang": 8438 - }, - "sgh": { - "language": 6104 - }, - "sgi": { - "language": 6105 - }, - "sgj": { - "language": 6106 - }, - "sgk": { - "language": 6107 - }, - "sgl": { - "language": 6108 - }, - "sgm": { - "language": 6109 - }, - "sgn": { - "language": 6110 - }, - "sgo": { - "language": 6111 - }, - "sgp": { - "language": 6112 - }, - "sgr": { - "language": 6113 - }, - "sgs": { - "language": 6114 - }, - "sgt": { - "language": 6115 - }, - "sgu": { - "language": 6116 - }, - "sgw": { - "language": 6117 - }, - "sgx": { - "language": 6118, - "extlang": 8439 - }, - "sgy": { - "language": 6119 - }, - "sgz": { - "language": 6120 - }, - "sha": { - "language": 6121 - }, - "shb": { - "language": 6122 - }, - "shc": { - "language": 6123 - }, - "shd": { - "language": 6124 - }, - "she": { - "language": 6125 - }, - "shg": { - "language": 6126 - }, - "shh": { - "language": 6127 - }, - "shi": { - "language": 6128 - }, - "shj": { - "language": 6129 - }, - "shk": { - "language": 6130 - }, - "shl": { - "language": 6131 - }, - "shm": { - "language": 6132 - }, - "shn": { - "language": 6133 - }, - "sho": { - "language": 6134 - }, - "shp": { - "language": 6135 - }, - "shq": { - "language": 6136 - }, - "shr": { - "language": 6137 - }, - "shs": { - "language": 6138 - }, - "sht": { - "language": 6139 - }, - "shu": { - "language": 6140, - "extlang": 8440 - }, - "shv": { - "language": 6141 - }, - "shw": { - "language": 6142 - }, - "shx": { - "language": 6143 - }, - "shy": { - "language": 6144 - }, - "shz": { - "language": 6145 - }, - "sia": { - "language": 6146 - }, - "sib": { - "language": 6147 - }, - "sid": { - "language": 6148 - }, - "sie": { - "language": 6149 - }, - "sif": { - "language": 6150 - }, - "sig": { - "language": 6151 - }, - "sih": { - "language": 6152 - }, - "sii": { - "language": 6153 - }, - "sij": { - "language": 6154 - }, - "sik": { - "language": 6155 - }, - "sil": { - "language": 6156 - }, - "sim": { - "language": 6157 - }, - "sio": { - "language": 6158 - }, - "sip": { - "language": 6159 - }, - "siq": { - "language": 6160 - }, - "sir": { - "language": 6161 - }, - "sis": { - "language": 6162 - }, - "sit": { - "language": 6163 - }, - "siu": { - "language": 6164 - }, - "siv": { - "language": 6165 - }, - "siw": { - "language": 6166 - }, - "six": { - "language": 6167 - }, - "siy": { - "language": 6168 - }, - "siz": { - "language": 6169 - }, - "sja": { - "language": 6170 - }, - "sjb": { - "language": 6171 - }, - "sjd": { - "language": 6172 - }, - "sje": { - "language": 6173 - }, - "sjg": { - "language": 6174 - }, - "sjk": { - "language": 6175 - }, - "sjl": { - "language": 6176 - }, - "sjm": { - "language": 6177 - }, - "sjn": { - "language": 6178 - }, - "sjo": { - "language": 6179 - }, - "sjp": { - "language": 6180 - }, - "sjr": { - "language": 6181 - }, - "sjs": { - "language": 6182 - }, - "sjt": { - "language": 6183 - }, - "sju": { - "language": 6184 - }, - "sjw": { - "language": 6185 - }, - "ska": { - "language": 6186 - }, - "skb": { - "language": 6187 - }, - "skc": { - "language": 6188 - }, - "skd": { - "language": 6189 - }, - "ske": { - "language": 6190 - }, - "skf": { - "language": 6191 - }, - "skg": { - "language": 6192 - }, - "skh": { - "language": 6193 - }, - "ski": { - "language": 6194 - }, - "skj": { - "language": 6195 - }, - "skk": { - "language": 6196 - }, - "skm": { - "language": 6197 - }, - "skn": { - "language": 6198 - }, - "sko": { - "language": 6199 - }, - "skp": { - "language": 6200 - }, - "skq": { - "language": 6201 - }, - "skr": { - "language": 6202 - }, - "sks": { - "language": 6203 - }, - "skt": { - "language": 6204 - }, - "sku": { - "language": 6205 - }, - "skv": { - "language": 6206 - }, - "skw": { - "language": 6207 - }, - "skx": { - "language": 6208 - }, - "sky": { - "language": 6209 - }, - "skz": { - "language": 6210 - }, - "sla": { - "language": 6211 - }, - "slc": { - "language": 6212 - }, - "sld": { - "language": 6213 - }, - "sle": { - "language": 6214 - }, - "slf": { - "language": 6215, - "extlang": 8441 - }, - "slg": { - "language": 6216 - }, - "slh": { - "language": 6217 - }, - "sli": { - "language": 6218 - }, - "slj": { - "language": 6219 - }, - "sll": { - "language": 6220 - }, - "slm": { - "language": 6221 - }, - "sln": { - "language": 6222 - }, - "slp": { - "language": 6223 - }, - "slq": { - "language": 6224 - }, - "slr": { - "language": 6225 - }, - "sls": { - "language": 6226, - "extlang": 8442 - }, - "slt": { - "language": 6227 - }, - "slu": { - "language": 6228 - }, - "slw": { - "language": 6229 - }, - "slx": { - "language": 6230 - }, - "sly": { - "language": 6231 - }, - "slz": { - "language": 6232 - }, - "sma": { - "language": 6233 - }, - "smb": { - "language": 6234 - }, - "smc": { - "language": 6235 - }, - "smd": { - "language": 6236 - }, - "smf": { - "language": 6237 - }, - "smg": { - "language": 6238 - }, - "smh": { - "language": 6239 - }, - "smi": { - "language": 6240 - }, - "smj": { - "language": 6241 - }, - "smk": { - "language": 6242 - }, - "sml": { - "language": 6243 - }, - "smm": { - "language": 6244 - }, - "smn": { - "language": 6245 - }, - "smp": { - "language": 6246 - }, - "smq": { - "language": 6247 - }, - "smr": { - "language": 6248 - }, - "sms": { - "language": 6249 - }, - "smt": { - "language": 6250 - }, - "smu": { - "language": 6251 - }, - "smv": { - "language": 6252 - }, - "smw": { - "language": 6253 - }, - "smx": { - "language": 6254 - }, - "smy": { - "language": 6255 - }, - "smz": { - "language": 6256 - }, - "snb": { - "language": 6257 - }, - "snc": { - "language": 6258 - }, - "sne": { - "language": 6259 - }, - "snf": { - "language": 6260 - }, - "sng": { - "language": 6261 - }, - "snh": { - "language": 6262 - }, - "sni": { - "language": 6263 - }, - "snj": { - "language": 6264 - }, - "snk": { - "language": 6265 - }, - "snl": { - "language": 6266 - }, - "snm": { - "language": 6267 - }, - "snn": { - "language": 6268 - }, - "sno": { - "language": 6269 - }, - "snp": { - "language": 6270 - }, - "snq": { - "language": 6271 - }, - "snr": { - "language": 6272 - }, - "sns": { - "language": 6273 - }, - "snu": { - "language": 6274 - }, - "snv": { - "language": 6275 - }, - "snw": { - "language": 6276 - }, - "snx": { - "language": 6277 - }, - "sny": { - "language": 6278 - }, - "snz": { - "language": 6279 - }, - "soa": { - "language": 6280 - }, - "sob": { - "language": 6281 - }, - "soc": { - "language": 6282 - }, - "sod": { - "language": 6283 - }, - "soe": { - "language": 6284 - }, - "sog": { - "language": 6285 - }, - "soh": { - "language": 6286 - }, - "soi": { - "language": 6287 - }, - "soj": { - "language": 6288 - }, - "sok": { - "language": 6289 - }, - "sol": { - "language": 6290 - }, - "son": { - "language": 6291 - }, - "soo": { - "language": 6292 - }, - "sop": { - "language": 6293 - }, - "soq": { - "language": 6294 - }, - "sor": { - "language": 6295 - }, - "sos": { - "language": 6296 - }, - "sou": { - "language": 6297 - }, - "sov": { - "language": 6298 - }, - "sow": { - "language": 6299 - }, - "sox": { - "language": 6300 - }, - "soy": { - "language": 6301 - }, - "soz": { - "language": 6302 - }, - "spb": { - "language": 6303 - }, - "spc": { - "language": 6304 - }, - "spd": { - "language": 6305 - }, - "spe": { - "language": 6306 - }, - "spg": { - "language": 6307 - }, - "spi": { - "language": 6308 - }, - "spk": { - "language": 6309 - }, - "spl": { - "language": 6310 - }, - "spm": { - "language": 6311 - }, - "spn": { - "language": 6312 - }, - "spo": { - "language": 6313 - }, - "spp": { - "language": 6314 - }, - "spq": { - "language": 6315 - }, - "spr": { - "language": 6316 - }, - "sps": { - "language": 6317 - }, - "spt": { - "language": 6318 - }, - "spu": { - "language": 6319 - }, - "spv": { - "language": 6320 - }, - "spx": { - "language": 6321 - }, - "spy": { - "language": 6322 - }, - "sqa": { - "language": 6323 - }, - "sqh": { - "language": 6324 - }, - "sqj": { - "language": 6325 - }, - "sqk": { - "language": 6326, - "extlang": 8443 - }, - "sqm": { - "language": 6327 - }, - "sqn": { - "language": 6328 - }, - "sqo": { - "language": 6329 - }, - "sqq": { - "language": 6330 - }, - "sqr": { - "language": 6331 - }, - "sqs": { - "language": 6332, - "extlang": 8444 - }, - "sqt": { - "language": 6333 - }, - "squ": { - "language": 6334 - }, - "sqx": { - "language": 6335, - "extlang": 8445 - }, - "sra": { - "language": 6336 - }, - "srb": { - "language": 6337 - }, - "src": { - "language": 6338 - }, - "sre": { - "language": 6339 - }, - "srf": { - "language": 6340 - }, - "srg": { - "language": 6341 - }, - "srh": { - "language": 6342 - }, - "sri": { - "language": 6343 - }, - "srk": { - "language": 6344 - }, - "srl": { - "language": 6345 - }, - "srm": { - "language": 6346 - }, - "srn": { - "language": 6347 - }, - "sro": { - "language": 6348 - }, - "srq": { - "language": 6349 - }, - "srr": { - "language": 6350 - }, - "srs": { - "language": 6351 - }, - "srt": { - "language": 6352 - }, - "sru": { - "language": 6353 - }, - "srv": { - "language": 6354 - }, - "srw": { - "language": 6355 - }, - "srx": { - "language": 6356 - }, - "sry": { - "language": 6357 - }, - "srz": { - "language": 6358 - }, - "ssa": { - "language": 6359 - }, - "ssb": { - "language": 6360 - }, - "ssc": { - "language": 6361 - }, - "ssd": { - "language": 6362 - }, - "sse": { - "language": 6363 - }, - "ssf": { - "language": 6364 - }, - "ssg": { - "language": 6365 - }, - "ssh": { - "language": 6366, - "extlang": 8446 - }, - "ssi": { - "language": 6367 - }, - "ssj": { - "language": 6368 - }, - "ssk": { - "language": 6369 - }, - "ssl": { - "language": 6370 - }, - "ssm": { - "language": 6371 - }, - "ssn": { - "language": 6372 - }, - "sso": { - "language": 6373 - }, - "ssp": { - "language": 6374, - "extlang": 8447 - }, - "ssq": { - "language": 6375 - }, - "ssr": { - "language": 6376, - "extlang": 8448 - }, - "sss": { - "language": 6377 - }, - "sst": { - "language": 6378 - }, - "ssu": { - "language": 6379 - }, - "ssv": { - "language": 6380 - }, - "ssx": { - "language": 6381 - }, - "ssy": { - "language": 6382 - }, - "ssz": { - "language": 6383 - }, - "sta": { - "language": 6384 - }, - "stb": { - "language": 6385 - }, - "std": { - "language": 6386 - }, - "ste": { - "language": 6387 - }, - "stf": { - "language": 6388 - }, - "stg": { - "language": 6389 - }, - "sth": { - "language": 6390 - }, - "sti": { - "language": 6391 - }, - "stj": { - "language": 6392 - }, - "stk": { - "language": 6393 - }, - "stl": { - "language": 6394 - }, - "stm": { - "language": 6395 - }, - "stn": { - "language": 6396 - }, - "sto": { - "language": 6397 - }, - "stp": { - "language": 6398 - }, - "stq": { - "language": 6399 - }, - "str": { - "language": 6400 - }, - "sts": { - "language": 6401 - }, - "stt": { - "language": 6402 - }, - "stu": { - "language": 6403 - }, - "stv": { - "language": 6404 - }, - "stw": { - "language": 6405 - }, - "sty": { - "language": 6406 - }, - "sua": { - "language": 6407 - }, - "sub": { - "language": 6408 - }, - "suc": { - "language": 6409 - }, - "sue": { - "language": 6410 - }, - "sug": { - "language": 6411 - }, - "sui": { - "language": 6412 - }, - "suj": { - "language": 6413 - }, - "suk": { - "language": 6414 - }, - "sul": { - "language": 6415 - }, - "sum": { - "language": 6416 - }, - "suo": { - "language": 6417 - }, - "suq": { - "language": 6418 - }, - "sur": { - "language": 6419 - }, - "sus": { - "language": 6420 - }, - "sut": { - "language": 6421 - }, - "suv": { - "language": 6422 - }, - "suw": { - "language": 6423 - }, - "sux": { - "language": 6424 - }, - "suy": { - "language": 6425 - }, - "suz": { - "language": 6426 - }, - "sva": { - "language": 6427 - }, - "svb": { - "language": 6428 - }, - "svc": { - "language": 6429 - }, - "sve": { - "language": 6430 - }, - "svk": { - "language": 6431, - "extlang": 8449 - }, - "svm": { - "language": 6432 - }, - "svr": { - "language": 6433 - }, - "svs": { - "language": 6434 - }, - "svx": { - "language": 6435 - }, - "swb": { - "language": 6436 - }, - "swc": { - "language": 6437, - "extlang": 8450 - }, - "swf": { - "language": 6438 - }, - "swg": { - "language": 6439 - }, - "swh": { - "language": 6440, - "extlang": 8451 - }, - "swi": { - "language": 6441 - }, - "swj": { - "language": 6442 - }, - "swk": { - "language": 6443 - }, - "swl": { - "language": 6444, - "extlang": 8452 - }, - "swm": { - "language": 6445 - }, - "swn": { - "language": 6446 - }, - "swo": { - "language": 6447 - }, - "swp": { - "language": 6448 - }, - "swq": { - "language": 6449 - }, - "swr": { - "language": 6450 - }, - "sws": { - "language": 6451 - }, - "swt": { - "language": 6452 - }, - "swu": { - "language": 6453 - }, - "swv": { - "language": 6454 - }, - "sww": { - "language": 6455 - }, - "swx": { - "language": 6456 - }, - "swy": { - "language": 6457 - }, - "sxb": { - "language": 6458 - }, - "sxc": { - "language": 6459 - }, - "sxe": { - "language": 6460 - }, - "sxg": { - "language": 6461 - }, - "sxk": { - "language": 6462 - }, - "sxl": { - "language": 6463 - }, - "sxm": { - "language": 6464 - }, - "sxn": { - "language": 6465 - }, - "sxo": { - "language": 6466 - }, - "sxr": { - "language": 6467 - }, - "sxs": { - "language": 6468 - }, - "sxu": { - "language": 6469 - }, - "sxw": { - "language": 6470 - }, - "sya": { - "language": 6471 - }, - "syb": { - "language": 6472 - }, - "syc": { - "language": 6473 - }, - "syd": { - "language": 6474 - }, - "syi": { - "language": 6475 - }, - "syk": { - "language": 6476 - }, - "syl": { - "language": 6477 - }, - "sym": { - "language": 6478 - }, - "syn": { - "language": 6479 - }, - "syo": { - "language": 6480 - }, - "syr": { - "language": 6481 - }, - "sys": { - "language": 6482 - }, - "syw": { - "language": 6483 - }, - "syx": { - "language": 6484 - }, - "syy": { - "language": 6485, - "extlang": 8453 - }, - "sza": { - "language": 6486 - }, - "szb": { - "language": 6487 - }, - "szc": { - "language": 6488 - }, - "szd": { - "language": 6489 - }, - "sze": { - "language": 6490 - }, - "szg": { - "language": 6491 - }, - "szl": { - "language": 6492 - }, - "szn": { - "language": 6493 - }, - "szp": { - "language": 6494 - }, - "szs": { - "language": 6495, - "extlang": 8454 - }, - "szv": { - "language": 6496 - }, - "szw": { - "language": 6497 - }, - "szy": { - "language": 6498 - }, - "taa": { - "language": 6499 - }, - "tab": { - "language": 6500 - }, - "tac": { - "language": 6501 - }, - "tad": { - "language": 6502 - }, - "tae": { - "language": 6503 - }, - "taf": { - "language": 6504 - }, - "tag": { - "language": 6505 - }, - "tai": { - "language": 6506 - }, - "taj": { - "language": 6507 - }, - "tak": { - "language": 6508 - }, - "tal": { - "language": 6509 - }, - "tan": { - "language": 6510 - }, - "tao": { - "language": 6511 - }, - "tap": { - "language": 6512 - }, - "taq": { - "language": 6513 - }, - "tar": { - "language": 6514 - }, - "tas": { - "language": 6515 - }, - "tau": { - "language": 6516 - }, - "tav": { - "language": 6517 - }, - "taw": { - "language": 6518 - }, - "tax": { - "language": 6519 - }, - "tay": { - "language": 6520 - }, - "taz": { - "language": 6521 - }, - "tba": { - "language": 6522 - }, - "tbb": { - "language": 6523 - }, - "tbc": { - "language": 6524 - }, - "tbd": { - "language": 6525 - }, - "tbe": { - "language": 6526 - }, - "tbf": { - "language": 6527 - }, - "tbg": { - "language": 6528 - }, - "tbh": { - "language": 6529 - }, - "tbi": { - "language": 6530 - }, - "tbj": { - "language": 6531 - }, - "tbk": { - "language": 6532 - }, - "tbl": { - "language": 6533 - }, - "tbm": { - "language": 6534 - }, - "tbn": { - "language": 6535 - }, - "tbo": { - "language": 6536 - }, - "tbp": { - "language": 6537 - }, - "tbq": { - "language": 6538 - }, - "tbr": { - "language": 6539 - }, - "tbs": { - "language": 6540 - }, - "tbt": { - "language": 6541 - }, - "tbu": { - "language": 6542 - }, - "tbv": { - "language": 6543 - }, - "tbw": { - "language": 6544 - }, - "tbx": { - "language": 6545 - }, - "tby": { - "language": 6546 - }, - "tbz": { - "language": 6547 - }, - "tca": { - "language": 6548 - }, - "tcb": { - "language": 6549 - }, - "tcc": { - "language": 6550 - }, - "tcd": { - "language": 6551 - }, - "tce": { - "language": 6552 - }, - "tcf": { - "language": 6553 - }, - "tcg": { - "language": 6554 - }, - "tch": { - "language": 6555 - }, - "tci": { - "language": 6556 - }, - "tck": { - "language": 6557 - }, - "tcl": { - "language": 6558 - }, - "tcm": { - "language": 6559 - }, - "tcn": { - "language": 6560 - }, - "tco": { - "language": 6561 - }, - "tcp": { - "language": 6562 - }, - "tcq": { - "language": 6563 - }, - "tcs": { - "language": 6564 - }, - "tct": { - "language": 6565 - }, - "tcu": { - "language": 6566 - }, - "tcw": { - "language": 6567 - }, - "tcx": { - "language": 6568 - }, - "tcy": { - "language": 6569 - }, - "tcz": { - "language": 6570 - }, - "tda": { - "language": 6571 - }, - "tdb": { - "language": 6572 - }, - "tdc": { - "language": 6573 - }, - "tdd": { - "language": 6574 - }, - "tde": { - "language": 6575 - }, - "tdf": { - "language": 6576 - }, - "tdg": { - "language": 6577 - }, - "tdh": { - "language": 6578 - }, - "tdi": { - "language": 6579 - }, - "tdj": { - "language": 6580 - }, - "tdk": { - "language": 6581 - }, - "tdl": { - "language": 6582 - }, - "tdm": { - "language": 6583 - }, - "tdn": { - "language": 6584 - }, - "tdo": { - "language": 6585 - }, - "tdq": { - "language": 6586 - }, - "tdr": { - "language": 6587 - }, - "tds": { - "language": 6588 - }, - "tdt": { - "language": 6589 - }, - "tdu": { - "language": 6590 - }, - "tdv": { - "language": 6591 - }, - "tdx": { - "language": 6592 - }, - "tdy": { - "language": 6593 - }, - "tea": { - "language": 6594 - }, - "teb": { - "language": 6595 - }, - "tec": { - "language": 6596 - }, - "ted": { - "language": 6597 - }, - "tee": { - "language": 6598 - }, - "tef": { - "language": 6599 - }, - "teg": { - "language": 6600 - }, - "teh": { - "language": 6601 - }, - "tei": { - "language": 6602 - }, - "tek": { - "language": 6603 - }, - "tem": { - "language": 6604 - }, - "ten": { - "language": 6605 - }, - "teo": { - "language": 6606 - }, - "tep": { - "language": 6607 - }, - "teq": { - "language": 6608 - }, - "ter": { - "language": 6609 - }, - "tes": { - "language": 6610 - }, - "tet": { - "language": 6611 - }, - "teu": { - "language": 6612 - }, - "tev": { - "language": 6613 - }, - "tew": { - "language": 6614 - }, - "tex": { - "language": 6615 - }, - "tey": { - "language": 6616 - }, - "tez": { - "language": 6617 - }, - "tfi": { - "language": 6618 - }, - "tfn": { - "language": 6619 - }, - "tfo": { - "language": 6620 - }, - "tfr": { - "language": 6621 - }, - "tft": { - "language": 6622 - }, - "tga": { - "language": 6623 - }, - "tgb": { - "language": 6624 - }, - "tgc": { - "language": 6625 - }, - "tgd": { - "language": 6626 - }, - "tge": { - "language": 6627 - }, - "tgf": { - "language": 6628 - }, - "tgg": { - "language": 6629 - }, - "tgh": { - "language": 6630 - }, - "tgi": { - "language": 6631 - }, - "tgj": { - "language": 6632 - }, - "tgn": { - "language": 6633 - }, - "tgo": { - "language": 6634 - }, - "tgp": { - "language": 6635 - }, - "tgq": { - "language": 6636 - }, - "tgr": { - "language": 6637 - }, - "tgs": { - "language": 6638 - }, - "tgt": { - "language": 6639 - }, - "tgu": { - "language": 6640 - }, - "tgv": { - "language": 6641 - }, - "tgw": { - "language": 6642 - }, - "tgx": { - "language": 6643 - }, - "tgy": { - "language": 6644 - }, - "tgz": { - "language": 6645 - }, - "thc": { - "language": 6646 - }, - "thd": { - "language": 6647 - }, - "the": { - "language": 6648 - }, - "thf": { - "language": 6649 - }, - "thh": { - "language": 6650 - }, - "thi": { - "language": 6651 - }, - "thk": { - "language": 6652 - }, - "thl": { - "language": 6653 - }, - "thm": { - "language": 6654 - }, - "thn": { - "language": 6655 - }, - "thp": { - "language": 6656 - }, - "thq": { - "language": 6657 - }, - "thr": { - "language": 6658 - }, - "ths": { - "language": 6659 - }, - "tht": { - "language": 6660 - }, - "thu": { - "language": 6661 - }, - "thv": { - "language": 6662 - }, - "thw": { - "language": 6663 - }, - "thx": { - "language": 6664 - }, - "thy": { - "language": 6665 - }, - "thz": { - "language": 6666 - }, - "tia": { - "language": 6667 - }, - "tic": { - "language": 6668 - }, - "tid": { - "language": 6669 - }, - "tie": { - "language": 6670 - }, - "tif": { - "language": 6671 - }, - "tig": { - "language": 6672 - }, - "tih": { - "language": 6673 - }, - "tii": { - "language": 6674 - }, - "tij": { - "language": 6675 - }, - "tik": { - "language": 6676 - }, - "til": { - "language": 6677 - }, - "tim": { - "language": 6678 - }, - "tin": { - "language": 6679 - }, - "tio": { - "language": 6680 - }, - "tip": { - "language": 6681 - }, - "tiq": { - "language": 6682 - }, - "tis": { - "language": 6683 - }, - "tit": { - "language": 6684 - }, - "tiu": { - "language": 6685 - }, - "tiv": { - "language": 6686 - }, - "tiw": { - "language": 6687 - }, - "tix": { - "language": 6688 - }, - "tiy": { - "language": 6689 - }, - "tiz": { - "language": 6690 - }, - "tja": { - "language": 6691 - }, - "tjg": { - "language": 6692 - }, - "tji": { - "language": 6693 - }, - "tjj": { - "language": 6694 - }, - "tjl": { - "language": 6695 - }, - "tjm": { - "language": 6696 - }, - "tjn": { - "language": 6697 - }, - "tjo": { - "language": 6698 - }, - "tjp": { - "language": 6699 - }, - "tjs": { - "language": 6700 - }, - "tju": { - "language": 6701 - }, - "tjw": { - "language": 6702 - }, - "tka": { - "language": 6703 - }, - "tkb": { - "language": 6704 - }, - "tkd": { - "language": 6705 - }, - "tke": { - "language": 6706 - }, - "tkf": { - "language": 6707 - }, - "tkg": { - "language": 6708 - }, - "tkk": { - "language": 6709 - }, - "tkl": { - "language": 6710 - }, - "tkm": { - "language": 6711 - }, - "tkn": { - "language": 6712 - }, - "tkp": { - "language": 6713 - }, - "tkq": { - "language": 6714 - }, - "tkr": { - "language": 6715 - }, - "tks": { - "language": 6716 - }, - "tkt": { - "language": 6717 - }, - "tku": { - "language": 6718 - }, - "tkv": { - "language": 6719 - }, - "tkw": { - "language": 6720 - }, - "tkx": { - "language": 6721 - }, - "tkz": { - "language": 6722 - }, - "tla": { - "language": 6723 - }, - "tlb": { - "language": 6724 - }, - "tlc": { - "language": 6725 - }, - "tld": { - "language": 6726 - }, - "tlf": { - "language": 6727 - }, - "tlg": { - "language": 6728 - }, - "tlh": { - "language": 6729 - }, - "tli": { - "language": 6730 - }, - "tlj": { - "language": 6731 - }, - "tlk": { - "language": 6732 - }, - "tll": { - "language": 6733 - }, - "tlm": { - "language": 6734 - }, - "tln": { - "language": 6735 - }, - "tlo": { - "language": 6736 - }, - "tlp": { - "language": 6737 - }, - "tlq": { - "language": 6738 - }, - "tlr": { - "language": 6739 - }, - "tls": { - "language": 6740 - }, - "tlt": { - "language": 6741 - }, - "tlu": { - "language": 6742 - }, - "tlv": { - "language": 6743 - }, - "tlw": { - "language": 6744 - }, - "tlx": { - "language": 6745 - }, - "tly": { - "language": 6746 - }, - "tma": { - "language": 6747 - }, - "tmb": { - "language": 6748 - }, - "tmc": { - "language": 6749 - }, - "tmd": { - "language": 6750 - }, - "tme": { - "language": 6751 - }, - "tmf": { - "language": 6752 - }, - "tmg": { - "language": 6753 - }, - "tmh": { - "language": 6754 - }, - "tmi": { - "language": 6755 - }, - "tmj": { - "language": 6756 - }, - "tmk": { - "language": 6757 - }, - "tml": { - "language": 6758 - }, - "tmm": { - "language": 6759 - }, - "tmn": { - "language": 6760 - }, - "tmo": { - "language": 6761 - }, - "tmp": { - "language": 6762 - }, - "tmq": { - "language": 6763 - }, - "tmr": { - "language": 6764 - }, - "tms": { - "language": 6765 - }, - "tmt": { - "language": 6766 - }, - "tmu": { - "language": 6767 - }, - "tmv": { - "language": 6768 - }, - "tmw": { - "language": 6769, - "extlang": 8455 - }, - "tmy": { - "language": 6770 - }, - "tmz": { - "language": 6771 - }, - "tna": { - "language": 6772 - }, - "tnb": { - "language": 6773 - }, - "tnc": { - "language": 6774 - }, - "tnd": { - "language": 6775 - }, - "tne": { - "language": 6776 - }, - "tnf": { - "language": 6777 - }, - "tng": { - "language": 6778 - }, - "tnh": { - "language": 6779 - }, - "tni": { - "language": 6780 - }, - "tnk": { - "language": 6781 - }, - "tnl": { - "language": 6782 - }, - "tnm": { - "language": 6783 - }, - "tnn": { - "language": 6784 - }, - "tno": { - "language": 6785 - }, - "tnp": { - "language": 6786 - }, - "tnq": { - "language": 6787 - }, - "tnr": { - "language": 6788 - }, - "tns": { - "language": 6789 - }, - "tnt": { - "language": 6790 - }, - "tnu": { - "language": 6791 - }, - "tnv": { - "language": 6792 - }, - "tnw": { - "language": 6793 - }, - "tnx": { - "language": 6794 - }, - "tny": { - "language": 6795 - }, - "tnz": { - "language": 6796 - }, - "tob": { - "language": 6797 - }, - "toc": { - "language": 6798 - }, - "tod": { - "language": 6799 - }, - "toe": { - "language": 6800 - }, - "tof": { - "language": 6801 - }, - "tog": { - "language": 6802 - }, - "toh": { - "language": 6803 - }, - "toi": { - "language": 6804 - }, - "toj": { - "language": 6805 - }, - "tok": { - "language": 6806 - }, - "tol": { - "language": 6807 - }, - "tom": { - "language": 6808 - }, - "too": { - "language": 6809 - }, - "top": { - "language": 6810 - }, - "toq": { - "language": 6811 - }, - "tor": { - "language": 6812 - }, - "tos": { - "language": 6813 - }, - "tou": { - "language": 6814 - }, - "tov": { - "language": 6815 - }, - "tow": { - "language": 6816 - }, - "tox": { - "language": 6817 - }, - "toy": { - "language": 6818 - }, - "toz": { - "language": 6819 - }, - "tpa": { - "language": 6820 - }, - "tpc": { - "language": 6821 - }, - "tpe": { - "language": 6822 - }, - "tpf": { - "language": 6823 - }, - "tpg": { - "language": 6824 - }, - "tpi": { - "language": 6825 - }, - "tpj": { - "language": 6826 - }, - "tpk": { - "language": 6827 - }, - "tpl": { - "language": 6828 - }, - "tpm": { - "language": 6829 - }, - "tpn": { - "language": 6830 - }, - "tpo": { - "language": 6831 - }, - "tpp": { - "language": 6832 - }, - "tpq": { - "language": 6833 - }, - "tpr": { - "language": 6834 - }, - "tpt": { - "language": 6835 - }, - "tpu": { - "language": 6836 - }, - "tpv": { - "language": 6837 - }, - "tpw": { - "language": 6838 - }, - "tpx": { - "language": 6839 - }, - "tpy": { - "language": 6840 - }, - "tpz": { - "language": 6841 - }, - "tqb": { - "language": 6842 - }, - "tql": { - "language": 6843 - }, - "tqm": { - "language": 6844 - }, - "tqn": { - "language": 6845 - }, - "tqo": { - "language": 6846 - }, - "tqp": { - "language": 6847 - }, - "tqq": { - "language": 6848 - }, - "tqr": { - "language": 6849 - }, - "tqt": { - "language": 6850 - }, - "tqu": { - "language": 6851 - }, - "tqw": { - "language": 6852 - }, - "tra": { - "language": 6853 - }, - "trb": { - "language": 6854 - }, - "trc": { - "language": 6855 - }, - "trd": { - "language": 6856 - }, - "tre": { - "language": 6857 - }, - "trf": { - "language": 6858 - }, - "trg": { - "language": 6859 - }, - "trh": { - "language": 6860 - }, - "tri": { - "language": 6861 - }, - "trj": { - "language": 6862 - }, - "trk": { - "language": 6863 - }, - "trl": { - "language": 6864 - }, - "trm": { - "language": 6865 - }, - "trn": { - "language": 6866 - }, - "tro": { - "language": 6867 - }, - "trp": { - "language": 6868 - }, - "trq": { - "language": 6869 - }, - "trr": { - "language": 6870 - }, - "trs": { - "language": 6871 - }, - "trt": { - "language": 6872 - }, - "tru": { - "language": 6873 - }, - "trv": { - "language": 6874 - }, - "trw": { - "language": 6875 - }, - "trx": { - "language": 6876 - }, - "try": { - "language": 6877 - }, - "trz": { - "language": 6878 - }, - "tsa": { - "language": 6879 - }, - "tsb": { - "language": 6880 - }, - "tsc": { - "language": 6881 - }, - "tsd": { - "language": 6882 - }, - "tse": { - "language": 6883, - "extlang": 8456 - }, - "tsf": { - "language": 6884 - }, - "tsg": { - "language": 6885 - }, - "tsh": { - "language": 6886 - }, - "tsi": { - "language": 6887 - }, - "tsj": { - "language": 6888 - }, - "tsk": { - "language": 6889 - }, - "tsl": { - "language": 6890 - }, - "tsm": { - "language": 6891, - "extlang": 8457 - }, - "tsp": { - "language": 6892 - }, - "tsq": { - "language": 6893, - "extlang": 8458 - }, - "tsr": { - "language": 6894 - }, - "tss": { - "language": 6895, - "extlang": 8459 - }, - "tst": { - "language": 6896 - }, - "tsu": { - "language": 6897 - }, - "tsv": { - "language": 6898 - }, - "tsw": { - "language": 6899 - }, - "tsx": { - "language": 6900 - }, - "tsy": { - "language": 6901, - "extlang": 8460 - }, - "tsz": { - "language": 6902 - }, - "tta": { - "language": 6903 - }, - "ttb": { - "language": 6904 - }, - "ttc": { - "language": 6905 - }, - "ttd": { - "language": 6906 - }, - "tte": { - "language": 6907 - }, - "ttf": { - "language": 6908 - }, - "ttg": { - "language": 6909 - }, - "tth": { - "language": 6910 - }, - "tti": { - "language": 6911 - }, - "ttj": { - "language": 6912 - }, - "ttk": { - "language": 6913 - }, - "ttl": { - "language": 6914 - }, - "ttm": { - "language": 6915 - }, - "ttn": { - "language": 6916 - }, - "tto": { - "language": 6917 - }, - "ttp": { - "language": 6918 - }, - "ttq": { - "language": 6919 - }, - "ttr": { - "language": 6920 - }, - "tts": { - "language": 6921 - }, - "ttt": { - "language": 6922 - }, - "ttu": { - "language": 6923 - }, - "ttv": { - "language": 6924 - }, - "ttw": { - "language": 6925 - }, - "tty": { - "language": 6926 - }, - "ttz": { - "language": 6927 - }, - "tua": { - "language": 6928 - }, - "tub": { - "language": 6929 - }, - "tuc": { - "language": 6930 - }, - "tud": { - "language": 6931 - }, - "tue": { - "language": 6932 - }, - "tuf": { - "language": 6933 - }, - "tug": { - "language": 6934 - }, - "tuh": { - "language": 6935 - }, - "tui": { - "language": 6936 - }, - "tuj": { - "language": 6937 - }, - "tul": { - "language": 6938 - }, - "tum": { - "language": 6939 - }, - "tun": { - "language": 6940 - }, - "tuo": { - "language": 6941 - }, - "tup": { - "language": 6942 - }, - "tuq": { - "language": 6943 - }, - "tus": { - "language": 6944 - }, - "tut": { - "language": 6945 - }, - "tuu": { - "language": 6946 - }, - "tuv": { - "language": 6947 - }, - "tuw": { - "language": 6948 - }, - "tux": { - "language": 6949 - }, - "tuy": { - "language": 6950 - }, - "tuz": { - "language": 6951 - }, - "tva": { - "language": 6952 - }, - "tvd": { - "language": 6953 - }, - "tve": { - "language": 6954 - }, - "tvk": { - "language": 6955 - }, - "tvl": { - "language": 6956 - }, - "tvm": { - "language": 6957 - }, - "tvn": { - "language": 6958 - }, - "tvo": { - "language": 6959 - }, - "tvs": { - "language": 6960 - }, - "tvt": { - "language": 6961 - }, - "tvu": { - "language": 6962 - }, - "tvw": { - "language": 6963 - }, - "tvx": { - "language": 6964 - }, - "tvy": { - "language": 6965 - }, - "twa": { - "language": 6966 - }, - "twb": { - "language": 6967 - }, - "twc": { - "language": 6968 - }, - "twd": { - "language": 6969 - }, - "twe": { - "language": 6970 - }, - "twf": { - "language": 6971 - }, - "twg": { - "language": 6972 - }, - "twh": { - "language": 6973 - }, - "twl": { - "language": 6974 - }, - "twm": { - "language": 6975 - }, - "twn": { - "language": 6976 - }, - "two": { - "language": 6977 - }, - "twp": { - "language": 6978 - }, - "twq": { - "language": 6979 - }, - "twr": { - "language": 6980 - }, - "twt": { - "language": 6981 - }, - "twu": { - "language": 6982 - }, - "tww": { - "language": 6983 - }, - "twx": { - "language": 6984 - }, - "twy": { - "language": 6985 - }, - "txa": { - "language": 6986 - }, - "txb": { - "language": 6987 - }, - "txc": { - "language": 6988 - }, - "txe": { - "language": 6989 - }, - "txg": { - "language": 6990 - }, - "txh": { - "language": 6991 - }, - "txi": { - "language": 6992 - }, - "txj": { - "language": 6993 - }, - "txm": { - "language": 6994 - }, - "txn": { - "language": 6995 - }, - "txo": { - "language": 6996 - }, - "txq": { - "language": 6997 - }, - "txr": { - "language": 6998 - }, - "txs": { - "language": 6999 - }, - "txt": { - "language": 7000 - }, - "txu": { - "language": 7001 - }, - "txx": { - "language": 7002 - }, - "txy": { - "language": 7003 - }, - "tya": { - "language": 7004 - }, - "tye": { - "language": 7005 - }, - "tyh": { - "language": 7006 - }, - "tyi": { - "language": 7007 - }, - "tyj": { - "language": 7008 - }, - "tyl": { - "language": 7009 - }, - "tyn": { - "language": 7010 - }, - "typ": { - "language": 7011 - }, - "tyr": { - "language": 7012 - }, - "tys": { - "language": 7013 - }, - "tyt": { - "language": 7014 - }, - "tyu": { - "language": 7015 - }, - "tyv": { - "language": 7016 - }, - "tyx": { - "language": 7017 - }, - "tyy": { - "language": 7018 - }, - "tyz": { - "language": 7019 - }, - "tza": { - "language": 7020, - "extlang": 8461 - }, - "tzh": { - "language": 7021 - }, - "tzj": { - "language": 7022 - }, - "tzl": { - "language": 7023 - }, - "tzm": { - "language": 7024 - }, - "tzn": { - "language": 7025 - }, - "tzo": { - "language": 7026 - }, - "tzx": { - "language": 7027 - }, - "uam": { - "language": 7028 - }, - "uan": { - "language": 7029 - }, - "uar": { - "language": 7030 - }, - "uba": { - "language": 7031 - }, - "ubi": { - "language": 7032 - }, - "ubl": { - "language": 7033 - }, - "ubr": { - "language": 7034 - }, - "ubu": { - "language": 7035 - }, - "uby": { - "language": 7036 - }, - "uda": { - "language": 7037 - }, - "ude": { - "language": 7038 - }, - "udg": { - "language": 7039 - }, - "udi": { - "language": 7040 - }, - "udj": { - "language": 7041 - }, - "udl": { - "language": 7042 - }, - "udm": { - "language": 7043 - }, - "udu": { - "language": 7044 - }, - "ues": { - "language": 7045 - }, - "ufi": { - "language": 7046 - }, - "uga": { - "language": 7047 - }, - "ugb": { - "language": 7048 - }, - "uge": { - "language": 7049 - }, - "ugh": { - "language": 7050 - }, - "ugn": { - "language": 7051, - "extlang": 8462 - }, - "ugo": { - "language": 7052 - }, - "ugy": { - "language": 7053, - "extlang": 8463 - }, - "uha": { - "language": 7054 - }, - "uhn": { - "language": 7055 - }, - "uis": { - "language": 7056 - }, - "uiv": { - "language": 7057 - }, - "uji": { - "language": 7058 - }, - "uka": { - "language": 7059 - }, - "ukg": { - "language": 7060 - }, - "ukh": { - "language": 7061 - }, - "uki": { - "language": 7062 - }, - "ukk": { - "language": 7063 - }, - "ukl": { - "language": 7064, - "extlang": 8464 - }, - "ukp": { - "language": 7065 - }, - "ukq": { - "language": 7066 - }, - "uks": { - "language": 7067, - "extlang": 8465 - }, - "uku": { - "language": 7068 - }, - "ukv": { - "language": 7069 - }, - "ukw": { - "language": 7070 - }, - "uky": { - "language": 7071 - }, - "ula": { - "language": 7072 - }, - "ulb": { - "language": 7073 - }, - "ulc": { - "language": 7074 - }, - "ule": { - "language": 7075 - }, - "ulf": { - "language": 7076 - }, - "uli": { - "language": 7077 - }, - "ulk": { - "language": 7078 - }, - "ull": { - "language": 7079 - }, - "ulm": { - "language": 7080 - }, - "uln": { - "language": 7081 - }, - "ulu": { - "language": 7082 - }, - "ulw": { - "language": 7083 - }, - "uma": { - "language": 7084 - }, - "umb": { - "language": 7085 - }, - "umc": { - "language": 7086 - }, - "umd": { - "language": 7087 - }, - "umg": { - "language": 7088 - }, - "umi": { - "language": 7089 - }, - "umm": { - "language": 7090 - }, - "umn": { - "language": 7091 - }, - "umo": { - "language": 7092 - }, - "ump": { - "language": 7093 - }, - "umr": { - "language": 7094 - }, - "ums": { - "language": 7095 - }, - "umu": { - "language": 7096 - }, - "una": { - "language": 7097 - }, - "und": { - "language": 7098 - }, - "une": { - "language": 7099 - }, - "ung": { - "language": 7100 - }, - "uni": { - "language": 7101 - }, - "unk": { - "language": 7102 - }, - "unm": { - "language": 7103 - }, - "unn": { - "language": 7104 - }, - "unp": { - "language": 7105 - }, - "unr": { - "language": 7106 - }, - "unu": { - "language": 7107 - }, - "unx": { - "language": 7108 - }, - "unz": { - "language": 7109 - }, - "uok": { - "language": 7110 - }, - "uon": { - "language": 7111 - }, - "upi": { - "language": 7112 - }, - "upv": { - "language": 7113 - }, - "ura": { - "language": 7114 - }, - "urb": { - "language": 7115 - }, - "urc": { - "language": 7116 - }, - "ure": { - "language": 7117 - }, - "urf": { - "language": 7118 - }, - "urg": { - "language": 7119 - }, - "urh": { - "language": 7120 - }, - "uri": { - "language": 7121 - }, - "urj": { - "language": 7122 - }, - "urk": { - "language": 7123, - "extlang": 8466 - }, - "url": { - "language": 7124 - }, - "urm": { - "language": 7125 - }, - "urn": { - "language": 7126 - }, - "uro": { - "language": 7127 - }, - "urp": { - "language": 7128 - }, - "urr": { - "language": 7129 - }, - "urt": { - "language": 7130 - }, - "uru": { - "language": 7131 - }, - "urv": { - "language": 7132 - }, - "urw": { - "language": 7133 - }, - "urx": { - "language": 7134 - }, - "ury": { - "language": 7135 - }, - "urz": { - "language": 7136 - }, - "usa": { - "language": 7137 - }, - "ush": { - "language": 7138 - }, - "usi": { - "language": 7139 - }, - "usk": { - "language": 7140 - }, - "usp": { - "language": 7141 - }, - "uss": { - "language": 7142 - }, - "usu": { - "language": 7143 - }, - "uta": { - "language": 7144 - }, - "ute": { - "language": 7145 - }, - "uth": { - "language": 7146 - }, - "utp": { - "language": 7147 - }, - "utr": { - "language": 7148 - }, - "utu": { - "language": 7149 - }, - "uum": { - "language": 7150 - }, - "uun": { - "language": 7151 - }, - "uur": { - "language": 7152 - }, - "uuu": { - "language": 7153 - }, - "uve": { - "language": 7154 - }, - "uvh": { - "language": 7155 - }, - "uvl": { - "language": 7156 - }, - "uwa": { - "language": 7157 - }, - "uya": { - "language": 7158 - }, - "uzn": { - "language": 7159, - "extlang": 8467 - }, - "uzs": { - "language": 7160, - "extlang": 8468 - }, - "vaa": { - "language": 7161 - }, - "vae": { - "language": 7162 - }, - "vaf": { - "language": 7163 - }, - "vag": { - "language": 7164 - }, - "vah": { - "language": 7165 - }, - "vai": { - "language": 7166 - }, - "vaj": { - "language": 7167 - }, - "val": { - "language": 7168 - }, - "vam": { - "language": 7169 - }, - "van": { - "language": 7170 - }, - "vao": { - "language": 7171 - }, - "vap": { - "language": 7172 - }, - "var": { - "language": 7173 - }, - "vas": { - "language": 7174 - }, - "vau": { - "language": 7175 - }, - "vav": { - "language": 7176 - }, - "vay": { - "language": 7177 - }, - "vbb": { - "language": 7178 - }, - "vbk": { - "language": 7179 - }, - "vec": { - "language": 7180 - }, - "ved": { - "language": 7181 - }, - "vel": { - "language": 7182 - }, - "vem": { - "language": 7183 - }, - "veo": { - "language": 7184 - }, - "vep": { - "language": 7185 - }, - "ver": { - "language": 7186 - }, - "vgr": { - "language": 7187 - }, - "vgt": { - "language": 7188, - "extlang": 8469 - }, - "vic": { - "language": 7189 - }, - "vid": { - "language": 7190 - }, - "vif": { - "language": 7191 - }, - "vig": { - "language": 7192 - }, - "vil": { - "language": 7193 - }, - "vin": { - "language": 7194 - }, - "vis": { - "language": 7195 - }, - "vit": { - "language": 7196 - }, - "viv": { - "language": 7197 - }, - "vka": { - "language": 7198 - }, - "vki": { - "language": 7199 - }, - "vkj": { - "language": 7200 - }, - "vkk": { - "language": 7201, - "extlang": 8470 - }, - "vkl": { - "language": 7202 - }, - "vkm": { - "language": 7203 - }, - "vkn": { - "language": 7204 - }, - "vko": { - "language": 7205 - }, - "vkp": { - "language": 7206 - }, - "vkt": { - "language": 7207, - "extlang": 8471 - }, - "vku": { - "language": 7208 - }, - "vkz": { - "language": 7209 - }, - "vlp": { - "language": 7210 - }, - "vls": { - "language": 7211 - }, - "vma": { - "language": 7212 - }, - "vmb": { - "language": 7213 - }, - "vmc": { - "language": 7214 - }, - "vmd": { - "language": 7215 - }, - "vme": { - "language": 7216 - }, - "vmf": { - "language": 7217 - }, - "vmg": { - "language": 7218 - }, - "vmh": { - "language": 7219 - }, - "vmi": { - "language": 7220 - }, - "vmj": { - "language": 7221 - }, - "vmk": { - "language": 7222 - }, - "vml": { - "language": 7223 - }, - "vmm": { - "language": 7224 - }, - "vmp": { - "language": 7225 - }, - "vmq": { - "language": 7226 - }, - "vmr": { - "language": 7227 - }, - "vms": { - "language": 7228 - }, - "vmu": { - "language": 7229 - }, - "vmv": { - "language": 7230 - }, - "vmw": { - "language": 7231 - }, - "vmx": { - "language": 7232 - }, - "vmy": { - "language": 7233 - }, - "vmz": { - "language": 7234 - }, - "vnk": { - "language": 7235 - }, - "vnm": { - "language": 7236 - }, - "vnp": { - "language": 7237 - }, - "vor": { - "language": 7238 - }, - "vot": { - "language": 7239 - }, - "vra": { - "language": 7240 - }, - "vro": { - "language": 7241 - }, - "vrs": { - "language": 7242 - }, - "vrt": { - "language": 7243 - }, - "vsi": { - "language": 7244, - "extlang": 8472 - }, - "vsl": { - "language": 7245, - "extlang": 8473 - }, - "vsv": { - "language": 7246, - "extlang": 8474 - }, - "vto": { - "language": 7247 - }, - "vum": { - "language": 7248 - }, - "vun": { - "language": 7249 - }, - "vut": { - "language": 7250 - }, - "vwa": { - "language": 7251 - }, - "waa": { - "language": 7252 - }, - "wab": { - "language": 7253 - }, - "wac": { - "language": 7254 - }, - "wad": { - "language": 7255 - }, - "wae": { - "language": 7256 - }, - "waf": { - "language": 7257 - }, - "wag": { - "language": 7258 - }, - "wah": { - "language": 7259 - }, - "wai": { - "language": 7260 - }, - "waj": { - "language": 7261 - }, - "wak": { - "language": 7262 - }, - "wal": { - "language": 7263 - }, - "wam": { - "language": 7264 - }, - "wan": { - "language": 7265 - }, - "wao": { - "language": 7266 - }, - "wap": { - "language": 7267 - }, - "waq": { - "language": 7268 - }, - "war": { - "language": 7269 - }, - "was": { - "language": 7270 - }, - "wat": { - "language": 7271 - }, - "wau": { - "language": 7272 - }, - "wav": { - "language": 7273 - }, - "waw": { - "language": 7274 - }, - "wax": { - "language": 7275 - }, - "way": { - "language": 7276 - }, - "waz": { - "language": 7277 - }, - "wba": { - "language": 7278 - }, - "wbb": { - "language": 7279 - }, - "wbe": { - "language": 7280 - }, - "wbf": { - "language": 7281 - }, - "wbh": { - "language": 7282 - }, - "wbi": { - "language": 7283 - }, - "wbj": { - "language": 7284 - }, - "wbk": { - "language": 7285 - }, - "wbl": { - "language": 7286 - }, - "wbm": { - "language": 7287 - }, - "wbp": { - "language": 7288 - }, - "wbq": { - "language": 7289 - }, - "wbr": { - "language": 7290 - }, - "wbs": { - "language": 7291, - "extlang": 8475 - }, - "wbt": { - "language": 7292 - }, - "wbv": { - "language": 7293 - }, - "wbw": { - "language": 7294 - }, - "wca": { - "language": 7295 - }, - "wci": { - "language": 7296 - }, - "wdd": { - "language": 7297 - }, - "wdg": { - "language": 7298 - }, - "wdj": { - "language": 7299 - }, - "wdk": { - "language": 7300 - }, - "wdt": { - "language": 7301 - }, - "wdu": { - "language": 7302 - }, - "wdy": { - "language": 7303 - }, - "wea": { - "language": 7304 - }, - "wec": { - "language": 7305 - }, - "wed": { - "language": 7306 - }, - "weg": { - "language": 7307 - }, - "weh": { - "language": 7308 - }, - "wei": { - "language": 7309 - }, - "wem": { - "language": 7310 - }, - "wen": { - "language": 7311 - }, - "weo": { - "language": 7312 - }, - "wep": { - "language": 7313 - }, - "wer": { - "language": 7314 - }, - "wes": { - "language": 7315 - }, - "wet": { - "language": 7316 - }, - "weu": { - "language": 7317 - }, - "wew": { - "language": 7318 - }, - "wfg": { - "language": 7319 - }, - "wga": { - "language": 7320 - }, - "wgb": { - "language": 7321 - }, - "wgg": { - "language": 7322 - }, - "wgi": { - "language": 7323 - }, - "wgo": { - "language": 7324 - }, - "wgu": { - "language": 7325 - }, - "wgw": { - "language": 7326 - }, - "wgy": { - "language": 7327 - }, - "wha": { - "language": 7328 - }, - "whg": { - "language": 7329 - }, - "whk": { - "language": 7330 - }, - "whu": { - "language": 7331 - }, - "wib": { - "language": 7332 - }, - "wic": { - "language": 7333 - }, - "wie": { - "language": 7334 - }, - "wif": { - "language": 7335 - }, - "wig": { - "language": 7336 - }, - "wih": { - "language": 7337 - }, - "wii": { - "language": 7338 - }, - "wij": { - "language": 7339 - }, - "wik": { - "language": 7340 - }, - "wil": { - "language": 7341 - }, - "wim": { - "language": 7342 - }, - "win": { - "language": 7343 - }, - "wir": { - "language": 7344 - }, - "wit": { - "language": 7345 - }, - "wiu": { - "language": 7346 - }, - "wiv": { - "language": 7347 - }, - "wiw": { - "language": 7348 - }, - "wiy": { - "language": 7349 - }, - "wja": { - "language": 7350 - }, - "wji": { - "language": 7351 - }, - "wka": { - "language": 7352 - }, - "wkb": { - "language": 7353 - }, - "wkd": { - "language": 7354 - }, - "wkl": { - "language": 7355 - }, - "wkr": { - "language": 7356 - }, - "wku": { - "language": 7357 - }, - "wkw": { - "language": 7358 - }, - "wky": { - "language": 7359 - }, - "wla": { - "language": 7360 - }, - "wlc": { - "language": 7361 - }, - "wle": { - "language": 7362 - }, - "wlg": { - "language": 7363 - }, - "wlh": { - "language": 7364 - }, - "wli": { - "language": 7365 - }, - "wlk": { - "language": 7366 - }, - "wll": { - "language": 7367 - }, - "wlm": { - "language": 7368 - }, - "wlo": { - "language": 7369 - }, - "wlr": { - "language": 7370 - }, - "wls": { - "language": 7371 - }, - "wlu": { - "language": 7372 - }, - "wlv": { - "language": 7373 - }, - "wlw": { - "language": 7374 - }, - "wlx": { - "language": 7375 - }, - "wly": { - "language": 7376 - }, - "wma": { - "language": 7377 - }, - "wmb": { - "language": 7378 - }, - "wmc": { - "language": 7379 - }, - "wmd": { - "language": 7380 - }, - "wme": { - "language": 7381 - }, - "wmg": { - "language": 7382 - }, - "wmh": { - "language": 7383 - }, - "wmi": { - "language": 7384 - }, - "wmm": { - "language": 7385 - }, - "wmn": { - "language": 7386 - }, - "wmo": { - "language": 7387 - }, - "wms": { - "language": 7388 - }, - "wmt": { - "language": 7389 - }, - "wmw": { - "language": 7390 - }, - "wmx": { - "language": 7391 - }, - "wnb": { - "language": 7392 - }, - "wnc": { - "language": 7393 - }, - "wnd": { - "language": 7394 - }, - "wne": { - "language": 7395 - }, - "wng": { - "language": 7396 - }, - "wni": { - "language": 7397 - }, - "wnk": { - "language": 7398 - }, - "wnm": { - "language": 7399 - }, - "wnn": { - "language": 7400 - }, - "wno": { - "language": 7401 - }, - "wnp": { - "language": 7402 - }, - "wnu": { - "language": 7403 - }, - "wnw": { - "language": 7404 - }, - "wny": { - "language": 7405 - }, - "woa": { - "language": 7406 - }, - "wob": { - "language": 7407 - }, - "woc": { - "language": 7408 - }, - "wod": { - "language": 7409 - }, - "woe": { - "language": 7410 - }, - "wof": { - "language": 7411 - }, - "wog": { - "language": 7412 - }, - "woi": { - "language": 7413 - }, - "wok": { - "language": 7414 - }, - "wom": { - "language": 7415 - }, - "won": { - "language": 7416 - }, - "woo": { - "language": 7417 - }, - "wor": { - "language": 7418 - }, - "wos": { - "language": 7419 - }, - "wow": { - "language": 7420 - }, - "woy": { - "language": 7421 - }, - "wpc": { - "language": 7422 - }, - "wra": { - "language": 7423 - }, - "wrb": { - "language": 7424 - }, - "wrd": { - "language": 7425 - }, - "wrg": { - "language": 7426 - }, - "wrh": { - "language": 7427 - }, - "wri": { - "language": 7428 - }, - "wrk": { - "language": 7429 - }, - "wrl": { - "language": 7430 - }, - "wrm": { - "language": 7431 - }, - "wrn": { - "language": 7432 - }, - "wro": { - "language": 7433 - }, - "wrp": { - "language": 7434 - }, - "wrr": { - "language": 7435 - }, - "wrs": { - "language": 7436 - }, - "wru": { - "language": 7437 - }, - "wrv": { - "language": 7438 - }, - "wrw": { - "language": 7439 - }, - "wrx": { - "language": 7440 - }, - "wry": { - "language": 7441 - }, - "wrz": { - "language": 7442 - }, - "wsa": { - "language": 7443 - }, - "wsg": { - "language": 7444 - }, - "wsi": { - "language": 7445 - }, - "wsk": { - "language": 7446 - }, - "wsr": { - "language": 7447 - }, - "wss": { - "language": 7448 - }, - "wsu": { - "language": 7449 - }, - "wsv": { - "language": 7450 - }, - "wtf": { - "language": 7451 - }, - "wth": { - "language": 7452 - }, - "wti": { - "language": 7453 - }, - "wtk": { - "language": 7454 - }, - "wtm": { - "language": 7455 - }, - "wtw": { - "language": 7456 - }, - "wua": { - "language": 7457 - }, - "wub": { - "language": 7458 - }, - "wud": { - "language": 7459 - }, - "wuh": { - "language": 7460 - }, - "wul": { - "language": 7461 - }, - "wum": { - "language": 7462 - }, - "wun": { - "language": 7463 - }, - "wur": { - "language": 7464 - }, - "wut": { - "language": 7465 - }, - "wuu": { - "language": 7466, - "extlang": 8476 - }, - "wuv": { - "language": 7467 - }, - "wux": { - "language": 7468 - }, - "wuy": { - "language": 7469 - }, - "wwa": { - "language": 7470 - }, - "wwb": { - "language": 7471 - }, - "wwo": { - "language": 7472 - }, - "wwr": { - "language": 7473 - }, - "www": { - "language": 7474 - }, - "wxa": { - "language": 7475 - }, - "wxw": { - "language": 7476 - }, - "wya": { - "language": 7477 - }, - "wyb": { - "language": 7478 - }, - "wyi": { - "language": 7479 - }, - "wym": { - "language": 7480 - }, - "wyn": { - "language": 7481 - }, - "wyr": { - "language": 7482 - }, - "wyy": { - "language": 7483 - }, - "xaa": { - "language": 7484 - }, - "xab": { - "language": 7485 - }, - "xac": { - "language": 7486 - }, - "xad": { - "language": 7487 - }, - "xae": { - "language": 7488 - }, - "xag": { - "language": 7489 - }, - "xai": { - "language": 7490 - }, - "xaj": { - "language": 7491 - }, - "xak": { - "language": 7492 - }, - "xal": { - "language": 7493 - }, - "xam": { - "language": 7494 - }, - "xan": { - "language": 7495 - }, - "xao": { - "language": 7496 - }, - "xap": { - "language": 7497 - }, - "xaq": { - "language": 7498 - }, - "xar": { - "language": 7499 - }, - "xas": { - "language": 7500 - }, - "xat": { - "language": 7501 - }, - "xau": { - "language": 7502 - }, - "xav": { - "language": 7503 - }, - "xaw": { - "language": 7504 - }, - "xay": { - "language": 7505 - }, - "xba": { - "language": 7506 - }, - "xbb": { - "language": 7507 - }, - "xbc": { - "language": 7508 - }, - "xbd": { - "language": 7509 - }, - "xbe": { - "language": 7510 - }, - "xbg": { - "language": 7511 - }, - "xbi": { - "language": 7512 - }, - "xbj": { - "language": 7513 - }, - "xbm": { - "language": 7514 - }, - "xbn": { - "language": 7515 - }, - "xbo": { - "language": 7516 - }, - "xbp": { - "language": 7517 - }, - "xbr": { - "language": 7518 - }, - "xbw": { - "language": 7519 - }, - "xbx": { - "language": 7520 - }, - "xby": { - "language": 7521 - }, - "xcb": { - "language": 7522 - }, - "xcc": { - "language": 7523 - }, - "xce": { - "language": 7524 - }, - "xcg": { - "language": 7525 - }, - "xch": { - "language": 7526 - }, - "xcl": { - "language": 7527 - }, - "xcm": { - "language": 7528 - }, - "xcn": { - "language": 7529 - }, - "xco": { - "language": 7530 - }, - "xcr": { - "language": 7531 - }, - "xct": { - "language": 7532 - }, - "xcu": { - "language": 7533 - }, - "xcv": { - "language": 7534 - }, - "xcw": { - "language": 7535 - }, - "xcy": { - "language": 7536 - }, - "xda": { - "language": 7537 - }, - "xdc": { - "language": 7538 - }, - "xdk": { - "language": 7539 - }, - "xdm": { - "language": 7540 - }, - "xdo": { - "language": 7541 - }, - "xdq": { - "language": 7542 - }, - "xdy": { - "language": 7543 - }, - "xeb": { - "language": 7544 - }, - "xed": { - "language": 7545 - }, - "xeg": { - "language": 7546 - }, - "xel": { - "language": 7547 - }, - "xem": { - "language": 7548 - }, - "xep": { - "language": 7549 - }, - "xer": { - "language": 7550 - }, - "xes": { - "language": 7551 - }, - "xet": { - "language": 7552 - }, - "xeu": { - "language": 7553 - }, - "xfa": { - "language": 7554 - }, - "xga": { - "language": 7555 - }, - "xgb": { - "language": 7556 - }, - "xgd": { - "language": 7557 - }, - "xgf": { - "language": 7558 - }, - "xgg": { - "language": 7559 - }, - "xgi": { - "language": 7560 - }, - "xgl": { - "language": 7561 - }, - "xgm": { - "language": 7562 - }, - "xgn": { - "language": 7563 - }, - "xgr": { - "language": 7564 - }, - "xgu": { - "language": 7565 - }, - "xgw": { - "language": 7566 - }, - "xha": { - "language": 7567 - }, - "xhc": { - "language": 7568 - }, - "xhd": { - "language": 7569 - }, - "xhe": { - "language": 7570 - }, - "xhm": { - "language": 7571 - }, - "xhr": { - "language": 7572 - }, - "xht": { - "language": 7573 - }, - "xhu": { - "language": 7574 - }, - "xhv": { - "language": 7575 - }, - "xia": { - "language": 7576 - }, - "xib": { - "language": 7577 - }, - "xii": { - "language": 7578 - }, - "xil": { - "language": 7579 - }, - "xin": { - "language": 7580 - }, - "xip": { - "language": 7581 - }, - "xir": { - "language": 7582 - }, - "xis": { - "language": 7583 - }, - "xiv": { - "language": 7584 - }, - "xiy": { - "language": 7585 - }, - "xjb": { - "language": 7586 - }, - "xjt": { - "language": 7587 - }, - "xka": { - "language": 7588 - }, - "xkb": { - "language": 7589 - }, - "xkc": { - "language": 7590 - }, - "xkd": { - "language": 7591 - }, - "xke": { - "language": 7592 - }, - "xkf": { - "language": 7593 - }, - "xkg": { - "language": 7594 - }, - "xkh": { - "language": 7595 - }, - "xki": { - "language": 7596, - "extlang": 8477 - }, - "xkj": { - "language": 7597 - }, - "xkk": { - "language": 7598 - }, - "xkl": { - "language": 7599 - }, - "xkn": { - "language": 7600 - }, - "xko": { - "language": 7601 - }, - "xkp": { - "language": 7602 - }, - "xkq": { - "language": 7603 - }, - "xkr": { - "language": 7604 - }, - "xks": { - "language": 7605 - }, - "xkt": { - "language": 7606 - }, - "xku": { - "language": 7607 - }, - "xkv": { - "language": 7608 - }, - "xkw": { - "language": 7609 - }, - "xkx": { - "language": 7610 - }, - "xky": { - "language": 7611 - }, - "xkz": { - "language": 7612 - }, - "xla": { - "language": 7613 - }, - "xlb": { - "language": 7614 - }, - "xlc": { - "language": 7615 - }, - "xld": { - "language": 7616 - }, - "xle": { - "language": 7617 - }, - "xlg": { - "language": 7618 - }, - "xli": { - "language": 7619 - }, - "xln": { - "language": 7620 - }, - "xlo": { - "language": 7621 - }, - "xlp": { - "language": 7622 - }, - "xls": { - "language": 7623 - }, - "xlu": { - "language": 7624 - }, - "xly": { - "language": 7625 - }, - "xma": { - "language": 7626 - }, - "xmb": { - "language": 7627 - }, - "xmc": { - "language": 7628 - }, - "xmd": { - "language": 7629 - }, - "xme": { - "language": 7630 - }, - "xmf": { - "language": 7631 - }, - "xmg": { - "language": 7632 - }, - "xmh": { - "language": 7633 - }, - "xmj": { - "language": 7634 - }, - "xmk": { - "language": 7635 - }, - "xml": { - "language": 7636, - "extlang": 8478 - }, - "xmm": { - "language": 7637, - "extlang": 8479 - }, - "xmn": { - "language": 7638 - }, - "xmo": { - "language": 7639 - }, - "xmp": { - "language": 7640 - }, - "xmq": { - "language": 7641 - }, - "xmr": { - "language": 7642 - }, - "xms": { - "language": 7643, - "extlang": 8480 - }, - "xmt": { - "language": 7644 - }, - "xmu": { - "language": 7645 - }, - "xmv": { - "language": 7646 - }, - "xmw": { - "language": 7647 - }, - "xmx": { - "language": 7648 - }, - "xmy": { - "language": 7649 - }, - "xmz": { - "language": 7650 - }, - "xna": { - "language": 7651 - }, - "xnb": { - "language": 7652 - }, - "xnd": { - "language": 7653 - }, - "xng": { - "language": 7654 - }, - "xnh": { - "language": 7655 - }, - "xni": { - "language": 7656 - }, - "xnj": { - "language": 7657 - }, - "xnk": { - "language": 7658 - }, - "xnm": { - "language": 7659 - }, - "xnn": { - "language": 7660 - }, - "xno": { - "language": 7661 - }, - "xnq": { - "language": 7662 - }, - "xnr": { - "language": 7663 - }, - "xns": { - "language": 7664 - }, - "xnt": { - "language": 7665 - }, - "xnu": { - "language": 7666 - }, - "xny": { - "language": 7667 - }, - "xnz": { - "language": 7668 - }, - "xoc": { - "language": 7669 - }, - "xod": { - "language": 7670 - }, - "xog": { - "language": 7671 - }, - "xoi": { - "language": 7672 - }, - "xok": { - "language": 7673 - }, - "xom": { - "language": 7674 - }, - "xon": { - "language": 7675 - }, - "xoo": { - "language": 7676 - }, - "xop": { - "language": 7677 - }, - "xor": { - "language": 7678 - }, - "xow": { - "language": 7679 - }, - "xpa": { - "language": 7680 - }, - "xpb": { - "language": 7681 - }, - "xpc": { - "language": 7682 - }, - "xpd": { - "language": 7683 - }, - "xpe": { - "language": 7684 - }, - "xpf": { - "language": 7685 - }, - "xpg": { - "language": 7686 - }, - "xph": { - "language": 7687 - }, - "xpi": { - "language": 7688 - }, - "xpj": { - "language": 7689 - }, - "xpk": { - "language": 7690 - }, - "xpl": { - "language": 7691 - }, - "xpm": { - "language": 7692 - }, - "xpn": { - "language": 7693 - }, - "xpo": { - "language": 7694 - }, - "xpp": { - "language": 7695 - }, - "xpq": { - "language": 7696 - }, - "xpr": { - "language": 7697 - }, - "xps": { - "language": 7698 - }, - "xpt": { - "language": 7699 - }, - "xpu": { - "language": 7700 - }, - "xpv": { - "language": 7701 - }, - "xpw": { - "language": 7702 - }, - "xpx": { - "language": 7703 - }, - "xpy": { - "language": 7704 - }, - "xpz": { - "language": 7705 - }, - "xqa": { - "language": 7706 - }, - "xqt": { - "language": 7707 - }, - "xra": { - "language": 7708 - }, - "xrb": { - "language": 7709 - }, - "xrd": { - "language": 7710 - }, - "xre": { - "language": 7711 - }, - "xrg": { - "language": 7712 - }, - "xri": { - "language": 7713 - }, - "xrm": { - "language": 7714 - }, - "xrn": { - "language": 7715 - }, - "xrq": { - "language": 7716 - }, - "xrr": { - "language": 7717 - }, - "xrt": { - "language": 7718 - }, - "xru": { - "language": 7719 - }, - "xrw": { - "language": 7720 - }, - "xsa": { - "language": 7721 - }, - "xsb": { - "language": 7722 - }, - "xsc": { - "language": 7723 - }, - "xsd": { - "language": 7724 - }, - "xse": { - "language": 7725 - }, - "xsh": { - "language": 7726 - }, - "xsi": { - "language": 7727 - }, - "xsj": { - "language": 7728 - }, - "xsl": { - "language": 7729 - }, - "xsm": { - "language": 7730 - }, - "xsn": { - "language": 7731 - }, - "xso": { - "language": 7732 - }, - "xsp": { - "language": 7733 - }, - "xsq": { - "language": 7734 - }, - "xsr": { - "language": 7735 - }, - "xss": { - "language": 7736 - }, - "xsu": { - "language": 7737 - }, - "xsv": { - "language": 7738 - }, - "xsy": { - "language": 7739 - }, - "xta": { - "language": 7740 - }, - "xtb": { - "language": 7741 - }, - "xtc": { - "language": 7742 - }, - "xtd": { - "language": 7743 - }, - "xte": { - "language": 7744 - }, - "xtg": { - "language": 7745 - }, - "xth": { - "language": 7746 - }, - "xti": { - "language": 7747 - }, - "xtj": { - "language": 7748 - }, - "xtl": { - "language": 7749 - }, - "xtm": { - "language": 7750 - }, - "xtn": { - "language": 7751 - }, - "xto": { - "language": 7752 - }, - "xtp": { - "language": 7753 - }, - "xtq": { - "language": 7754 - }, - "xtr": { - "language": 7755 - }, - "xts": { - "language": 7756 - }, - "xtt": { - "language": 7757 - }, - "xtu": { - "language": 7758 - }, - "xtv": { - "language": 7759 - }, - "xtw": { - "language": 7760 - }, - "xty": { - "language": 7761 - }, - "xtz": { - "language": 7762 - }, - "xua": { - "language": 7763 - }, - "xub": { - "language": 7764 - }, - "xud": { - "language": 7765 - }, - "xug": { - "language": 7766 - }, - "xuj": { - "language": 7767 - }, - "xul": { - "language": 7768 - }, - "xum": { - "language": 7769 - }, - "xun": { - "language": 7770 - }, - "xuo": { - "language": 7771 - }, - "xup": { - "language": 7772 - }, - "xur": { - "language": 7773 - }, - "xut": { - "language": 7774 - }, - "xuu": { - "language": 7775 - }, - "xve": { - "language": 7776 - }, - "xvi": { - "language": 7777 - }, - "xvn": { - "language": 7778 - }, - "xvo": { - "language": 7779 - }, - "xvs": { - "language": 7780 - }, - "xwa": { - "language": 7781 - }, - "xwc": { - "language": 7782 - }, - "xwd": { - "language": 7783 - }, - "xwe": { - "language": 7784 - }, - "xwg": { - "language": 7785 - }, - "xwj": { - "language": 7786 - }, - "xwk": { - "language": 7787 - }, - "xwl": { - "language": 7788 - }, - "xwo": { - "language": 7789 - }, - "xwr": { - "language": 7790 - }, - "xwt": { - "language": 7791 - }, - "xww": { - "language": 7792 - }, - "xxb": { - "language": 7793 - }, - "xxk": { - "language": 7794 - }, - "xxm": { - "language": 7795 - }, - "xxr": { - "language": 7796 - }, - "xxt": { - "language": 7797 - }, - "xya": { - "language": 7798 - }, - "xyb": { - "language": 7799 - }, - "xyj": { - "language": 7800 - }, - "xyk": { - "language": 7801 - }, - "xyl": { - "language": 7802 - }, - "xyt": { - "language": 7803 - }, - "xyy": { - "language": 7804 - }, - "xzh": { - "language": 7805 - }, - "xzm": { - "language": 7806 - }, - "xzp": { - "language": 7807 - }, - "yaa": { - "language": 7808 - }, - "yab": { - "language": 7809 - }, - "yac": { - "language": 7810 - }, - "yad": { - "language": 7811 - }, - "yae": { - "language": 7812 - }, - "yaf": { - "language": 7813 - }, - "yag": { - "language": 7814 - }, - "yah": { - "language": 7815 - }, - "yai": { - "language": 7816 - }, - "yaj": { - "language": 7817 - }, - "yak": { - "language": 7818 - }, - "yal": { - "language": 7819 - }, - "yam": { - "language": 7820 - }, - "yan": { - "language": 7821 - }, - "yao": { - "language": 7822 - }, - "yap": { - "language": 7823 - }, - "yaq": { - "language": 7824 - }, - "yar": { - "language": 7825 - }, - "yas": { - "language": 7826 - }, - "yat": { - "language": 7827 - }, - "yau": { - "language": 7828 - }, - "yav": { - "language": 7829 - }, - "yaw": { - "language": 7830 - }, - "yax": { - "language": 7831 - }, - "yay": { - "language": 7832 - }, - "yaz": { - "language": 7833 - }, - "yba": { - "language": 7834 - }, - "ybb": { - "language": 7835 - }, - "ybd": { - "language": 7836 - }, - "ybe": { - "language": 7837 - }, - "ybh": { - "language": 7838 - }, - "ybi": { - "language": 7839 - }, - "ybj": { - "language": 7840 - }, - "ybk": { - "language": 7841 - }, - "ybl": { - "language": 7842 - }, - "ybm": { - "language": 7843 - }, - "ybn": { - "language": 7844 - }, - "ybo": { - "language": 7845 - }, - "ybx": { - "language": 7846 - }, - "yby": { - "language": 7847 - }, - "ych": { - "language": 7848 - }, - "ycl": { - "language": 7849 - }, - "ycn": { - "language": 7850 - }, - "ycp": { - "language": 7851 - }, - "yda": { - "language": 7852 - }, - "ydd": { - "language": 7853 - }, - "yde": { - "language": 7854 - }, - "ydg": { - "language": 7855 - }, - "ydk": { - "language": 7856 - }, - "yds": { - "language": 7857, - "extlang": 8481 - }, - "yea": { - "language": 7858 - }, - "yec": { - "language": 7859 - }, - "yee": { - "language": 7860 - }, - "yei": { - "language": 7861 - }, - "yej": { - "language": 7862 - }, - "yel": { - "language": 7863 - }, - "yen": { - "language": 7864 - }, - "yer": { - "language": 7865 - }, - "yes": { - "language": 7866 - }, - "yet": { - "language": 7867 - }, - "yeu": { - "language": 7868 - }, - "yev": { - "language": 7869 - }, - "yey": { - "language": 7870 - }, - "yga": { - "language": 7871 - }, - "ygi": { - "language": 7872 - }, - "ygl": { - "language": 7873 - }, - "ygm": { - "language": 7874 - }, - "ygp": { - "language": 7875 - }, - "ygr": { - "language": 7876 - }, - "ygs": { - "language": 7877, - "extlang": 8482 - }, - "ygu": { - "language": 7878 - }, - "ygw": { - "language": 7879 - }, - "yha": { - "language": 7880 - }, - "yhd": { - "language": 7881 - }, - "yhl": { - "language": 7882 - }, - "yhs": { - "language": 7883, - "extlang": 8483 - }, - "yia": { - "language": 7884 - }, - "yif": { - "language": 7885 - }, - "yig": { - "language": 7886 - }, - "yih": { - "language": 7887 - }, - "yii": { - "language": 7888 - }, - "yij": { - "language": 7889 - }, - "yik": { - "language": 7890 - }, - "yil": { - "language": 7891 - }, - "yim": { - "language": 7892 - }, - "yin": { - "language": 7893 - }, - "yip": { - "language": 7894 - }, - "yiq": { - "language": 7895 - }, - "yir": { - "language": 7896 - }, - "yis": { - "language": 7897 - }, - "yit": { - "language": 7898 - }, - "yiu": { - "language": 7899 - }, - "yiv": { - "language": 7900 - }, - "yix": { - "language": 7901 - }, - "yiy": { - "language": 7902 - }, - "yiz": { - "language": 7903 - }, - "yka": { - "language": 7904 - }, - "ykg": { - "language": 7905 - }, - "yki": { - "language": 7906 - }, - "ykk": { - "language": 7907 - }, - "ykl": { - "language": 7908 - }, - "ykm": { - "language": 7909 - }, - "ykn": { - "language": 7910 - }, - "yko": { - "language": 7911 - }, - "ykr": { - "language": 7912 - }, - "ykt": { - "language": 7913 - }, - "yku": { - "language": 7914 - }, - "yky": { - "language": 7915 - }, - "yla": { - "language": 7916 - }, - "ylb": { - "language": 7917 - }, - "yle": { - "language": 7918 - }, - "ylg": { - "language": 7919 - }, - "yli": { - "language": 7920 - }, - "yll": { - "language": 7921 - }, - "ylm": { - "language": 7922 - }, - "yln": { - "language": 7923 - }, - "ylo": { - "language": 7924 - }, - "ylr": { - "language": 7925 - }, - "ylu": { - "language": 7926 - }, - "yly": { - "language": 7927 - }, - "yma": { - "language": 7928 - }, - "ymb": { - "language": 7929 - }, - "ymc": { - "language": 7930 - }, - "ymd": { - "language": 7931 - }, - "yme": { - "language": 7932 - }, - "ymg": { - "language": 7933 - }, - "ymh": { - "language": 7934 - }, - "ymi": { - "language": 7935 - }, - "ymk": { - "language": 7936 - }, - "yml": { - "language": 7937 - }, - "ymm": { - "language": 7938 - }, - "ymn": { - "language": 7939 - }, - "ymo": { - "language": 7940 - }, - "ymp": { - "language": 7941 - }, - "ymq": { - "language": 7942 - }, - "ymr": { - "language": 7943 - }, - "yms": { - "language": 7944 - }, - "ymt": { - "language": 7945 - }, - "ymx": { - "language": 7946 - }, - "ymz": { - "language": 7947 - }, - "yna": { - "language": 7948 - }, - "ynd": { - "language": 7949 - }, - "yne": { - "language": 7950 - }, - "yng": { - "language": 7951 - }, - "ynh": { - "language": 7952 - }, - "ynk": { - "language": 7953 - }, - "ynl": { - "language": 7954 - }, - "ynn": { - "language": 7955 - }, - "yno": { - "language": 7956 - }, - "ynq": { - "language": 7957 - }, - "yns": { - "language": 7958 - }, - "ynu": { - "language": 7959 - }, - "yob": { - "language": 7960 - }, - "yog": { - "language": 7961 - }, - "yoi": { - "language": 7962 - }, - "yok": { - "language": 7963 - }, - "yol": { - "language": 7964 - }, - "yom": { - "language": 7965 - }, - "yon": { - "language": 7966 - }, - "yos": { - "language": 7967 - }, - "yot": { - "language": 7968 - }, - "yox": { - "language": 7969 - }, - "yoy": { - "language": 7970 - }, - "ypa": { - "language": 7971 - }, - "ypb": { - "language": 7972 - }, - "ypg": { - "language": 7973 - }, - "yph": { - "language": 7974 - }, - "ypk": { - "language": 7975 - }, - "ypm": { - "language": 7976 - }, - "ypn": { - "language": 7977 - }, - "ypo": { - "language": 7978 - }, - "ypp": { - "language": 7979 - }, - "ypz": { - "language": 7980 - }, - "yra": { - "language": 7981 - }, - "yrb": { - "language": 7982 - }, - "yre": { - "language": 7983 - }, - "yri": { - "language": 7984 - }, - "yrk": { - "language": 7985 - }, - "yrl": { - "language": 7986 - }, - "yrm": { - "language": 7987 - }, - "yrn": { - "language": 7988 - }, - "yro": { - "language": 7989 - }, - "yrs": { - "language": 7990 - }, - "yrw": { - "language": 7991 - }, - "yry": { - "language": 7992 - }, - "ysc": { - "language": 7993 - }, - "ysd": { - "language": 7994 - }, - "ysg": { - "language": 7995 - }, - "ysl": { - "language": 7996, - "extlang": 8484 - }, - "ysm": { - "language": 7997, - "extlang": 8485 - }, - "ysn": { - "language": 7998 - }, - "yso": { - "language": 7999 - }, - "ysp": { - "language": 8000 - }, - "ysr": { - "language": 8001 - }, - "yss": { - "language": 8002 - }, - "ysy": { - "language": 8003 - }, - "yta": { - "language": 8004 - }, - "ytl": { - "language": 8005 - }, - "ytp": { - "language": 8006 - }, - "ytw": { - "language": 8007 - }, - "yty": { - "language": 8008 - }, - "yua": { - "language": 8009 - }, - "yub": { - "language": 8010 - }, - "yuc": { - "language": 8011 - }, - "yud": { - "language": 8012 - }, - "yue": { - "language": 8013, - "extlang": 8486 - }, - "yuf": { - "language": 8014 - }, - "yug": { - "language": 8015 - }, - "yui": { - "language": 8016 - }, - "yuj": { - "language": 8017 - }, - "yuk": { - "language": 8018 - }, - "yul": { - "language": 8019 - }, - "yum": { - "language": 8020 - }, - "yun": { - "language": 8021 - }, - "yup": { - "language": 8022 - }, - "yuq": { - "language": 8023 - }, - "yur": { - "language": 8024 - }, - "yut": { - "language": 8025 - }, - "yuu": { - "language": 8026 - }, - "yuw": { - "language": 8027 - }, - "yux": { - "language": 8028 - }, - "yuy": { - "language": 8029 - }, - "yuz": { - "language": 8030 - }, - "yva": { - "language": 8031 - }, - "yvt": { - "language": 8032 - }, - "ywa": { - "language": 8033 - }, - "ywg": { - "language": 8034 - }, - "ywl": { - "language": 8035 - }, - "ywn": { - "language": 8036 - }, - "ywq": { - "language": 8037 - }, - "ywr": { - "language": 8038 - }, - "ywt": { - "language": 8039 - }, - "ywu": { - "language": 8040 - }, - "yww": { - "language": 8041 - }, - "yxa": { - "language": 8042 - }, - "yxg": { - "language": 8043 - }, - "yxl": { - "language": 8044 - }, - "yxm": { - "language": 8045 - }, - "yxu": { - "language": 8046 - }, - "yxy": { - "language": 8047 - }, - "yyr": { - "language": 8048 - }, - "yyu": { - "language": 8049 - }, - "yyz": { - "language": 8050 - }, - "yzg": { - "language": 8051 - }, - "yzk": { - "language": 8052 - }, - "zaa": { - "language": 8053 - }, - "zab": { - "language": 8054 - }, - "zac": { - "language": 8055 - }, - "zad": { - "language": 8056 - }, - "zae": { - "language": 8057 - }, - "zaf": { - "language": 8058 - }, - "zag": { - "language": 8059 - }, - "zah": { - "language": 8060 - }, - "zai": { - "language": 8061 - }, - "zaj": { - "language": 8062 - }, - "zak": { - "language": 8063 - }, - "zal": { - "language": 8064 - }, - "zam": { - "language": 8065 - }, - "zao": { - "language": 8066 - }, - "zap": { - "language": 8067 - }, - "zaq": { - "language": 8068 - }, - "zar": { - "language": 8069 - }, - "zas": { - "language": 8070 - }, - "zat": { - "language": 8071 - }, - "zau": { - "language": 8072 - }, - "zav": { - "language": 8073 - }, - "zaw": { - "language": 8074 - }, - "zax": { - "language": 8075 - }, - "zay": { - "language": 8076 - }, - "zaz": { - "language": 8077 - }, - "zba": { - "language": 8078 - }, - "zbc": { - "language": 8079 - }, - "zbe": { - "language": 8080 - }, - "zbl": { - "language": 8081 - }, - "zbt": { - "language": 8082 - }, - "zbu": { - "language": 8083 - }, - "zbw": { - "language": 8084 - }, - "zca": { - "language": 8085 - }, - "zcd": { - "language": 8086 - }, - "zch": { - "language": 8087 - }, - "zdj": { - "language": 8088 - }, - "zea": { - "language": 8089 - }, - "zeg": { - "language": 8090 - }, - "zeh": { - "language": 8091 - }, - "zen": { - "language": 8092 - }, - "zga": { - "language": 8093 - }, - "zgb": { - "language": 8094 - }, - "zgh": { - "language": 8095 - }, - "zgm": { - "language": 8096 - }, - "zgn": { - "language": 8097 - }, - "zgr": { - "language": 8098 - }, - "zhb": { - "language": 8099 - }, - "zhd": { - "language": 8100 - }, - "zhi": { - "language": 8101 - }, - "zhn": { - "language": 8102 - }, - "zhw": { - "language": 8103 - }, - "zhx": { - "language": 8104 - }, - "zia": { - "language": 8105 - }, - "zib": { - "language": 8106, - "extlang": 8487 - }, - "zik": { - "language": 8107 - }, - "zil": { - "language": 8108 - }, - "zim": { - "language": 8109 - }, - "zin": { - "language": 8110 - }, - "zir": { - "language": 8111 - }, - "ziw": { - "language": 8112 - }, - "ziz": { - "language": 8113 - }, - "zka": { - "language": 8114 - }, - "zkb": { - "language": 8115 - }, - "zkd": { - "language": 8116 - }, - "zkg": { - "language": 8117 - }, - "zkh": { - "language": 8118 - }, - "zkk": { - "language": 8119 - }, - "zkn": { - "language": 8120 - }, - "zko": { - "language": 8121 - }, - "zkp": { - "language": 8122 - }, - "zkr": { - "language": 8123 - }, - "zkt": { - "language": 8124 - }, - "zku": { - "language": 8125 - }, - "zkv": { - "language": 8126 - }, - "zkz": { - "language": 8127 - }, - "zla": { - "language": 8128 - }, - "zle": { - "language": 8129 - }, - "zlj": { - "language": 8130 - }, - "zlm": { - "language": 8131, - "extlang": 8488 - }, - "zln": { - "language": 8132 - }, - "zlq": { - "language": 8133 - }, - "zls": { - "language": 8134 - }, - "zlw": { - "language": 8135 - }, - "zma": { - "language": 8136 - }, - "zmb": { - "language": 8137 - }, - "zmc": { - "language": 8138 - }, - "zmd": { - "language": 8139 - }, - "zme": { - "language": 8140 - }, - "zmf": { - "language": 8141 - }, - "zmg": { - "language": 8142 - }, - "zmh": { - "language": 8143 - }, - "zmi": { - "language": 8144, - "extlang": 8489 - }, - "zmj": { - "language": 8145 - }, - "zmk": { - "language": 8146 - }, - "zml": { - "language": 8147 - }, - "zmm": { - "language": 8148 - }, - "zmn": { - "language": 8149 - }, - "zmo": { - "language": 8150 - }, - "zmp": { - "language": 8151 - }, - "zmq": { - "language": 8152 - }, - "zmr": { - "language": 8153 - }, - "zms": { - "language": 8154 - }, - "zmt": { - "language": 8155 - }, - "zmu": { - "language": 8156 - }, - "zmv": { - "language": 8157 - }, - "zmw": { - "language": 8158 - }, - "zmx": { - "language": 8159 - }, - "zmy": { - "language": 8160 - }, - "zmz": { - "language": 8161 - }, - "zna": { - "language": 8162 - }, - "znd": { - "language": 8163 - }, - "zne": { - "language": 8164 - }, - "zng": { - "language": 8165 - }, - "znk": { - "language": 8166 - }, - "zns": { - "language": 8167 - }, - "zoc": { - "language": 8168 - }, - "zoh": { - "language": 8169 - }, - "zom": { - "language": 8170 - }, - "zoo": { - "language": 8171 - }, - "zoq": { - "language": 8172 - }, - "zor": { - "language": 8173 - }, - "zos": { - "language": 8174 - }, - "zpa": { - "language": 8175 - }, - "zpb": { - "language": 8176 - }, - "zpc": { - "language": 8177 - }, - "zpd": { - "language": 8178 - }, - "zpe": { - "language": 8179 - }, - "zpf": { - "language": 8180 - }, - "zpg": { - "language": 8181 - }, - "zph": { - "language": 8182 - }, - "zpi": { - "language": 8183 - }, - "zpj": { - "language": 8184 - }, - "zpk": { - "language": 8185 - }, - "zpl": { - "language": 8186 - }, - "zpm": { - "language": 8187 - }, - "zpn": { - "language": 8188 - }, - "zpo": { - "language": 8189 - }, - "zpp": { - "language": 8190 - }, - "zpq": { - "language": 8191 - }, - "zpr": { - "language": 8192 - }, - "zps": { - "language": 8193 - }, - "zpt": { - "language": 8194 - }, - "zpu": { - "language": 8195 - }, - "zpv": { - "language": 8196 - }, - "zpw": { - "language": 8197 - }, - "zpx": { - "language": 8198 - }, - "zpy": { - "language": 8199 - }, - "zpz": { - "language": 8200 - }, - "zqe": { - "language": 8201 - }, - "zra": { - "language": 8202 - }, - "zrg": { - "language": 8203 - }, - "zrn": { - "language": 8204 - }, - "zro": { - "language": 8205 - }, - "zrp": { - "language": 8206 - }, - "zrs": { - "language": 8207 - }, - "zsa": { - "language": 8208 - }, - "zsk": { - "language": 8209 - }, - "zsl": { - "language": 8210, - "extlang": 8490 - }, - "zsm": { - "language": 8211, - "extlang": 8491 - }, - "zsr": { - "language": 8212 - }, - "zsu": { - "language": 8213 - }, - "zte": { - "language": 8214 - }, - "ztg": { - "language": 8215 - }, - "ztl": { - "language": 8216 - }, - "ztm": { - "language": 8217 - }, - "ztn": { - "language": 8218 - }, - "ztp": { - "language": 8219 - }, - "ztq": { - "language": 8220 - }, - "zts": { - "language": 8221 - }, - "ztt": { - "language": 8222 - }, - "ztu": { - "language": 8223 - }, - "ztx": { - "language": 8224 - }, - "zty": { - "language": 8225 - }, - "zua": { - "language": 8226 - }, - "zuh": { - "language": 8227 - }, - "zum": { - "language": 8228 - }, - "zun": { - "language": 8229 - }, - "zuy": { - "language": 8230 - }, - "zwa": { - "language": 8231 - }, - "zxx": { - "language": 8232 - }, - "zyb": { - "language": 8233 - }, - "zyg": { - "language": 8234 - }, - "zyj": { - "language": 8235 - }, - "zyn": { - "language": 8236 - }, - "zyp": { - "language": 8237 - }, - "zza": { - "language": 8238 - }, - "zzj": { - "language": 8239 - }, - "adlm": { - "script": 8492 - }, - "afak": { - "script": 8493 - }, - "aghb": { - "script": 8494 - }, - "ahom": { - "script": 8495 - }, - "arab": { - "script": 8496 - }, - "aran": { - "script": 8497 - }, - "armi": { - "script": 8498 - }, - "armn": { - "script": 8499 - }, - "avst": { - "script": 8500 - }, - "bali": { - "script": 8501 - }, - "bamu": { - "script": 8502 - }, - "bass": { - "script": 8503 - }, - "batk": { - "script": 8504 - }, - "beng": { - "script": 8505 - }, - "bhks": { - "script": 8506 - }, - "blis": { - "script": 8507 - }, - "bopo": { - "script": 8508 - }, - "brah": { - "script": 8509 - }, - "brai": { - "script": 8510 - }, - "bugi": { - "script": 8511 - }, - "buhd": { - "script": 8512 - }, - "cakm": { - "script": 8513 - }, - "cans": { - "script": 8514 - }, - "cari": { - "script": 8515 - }, - "cham": { - "script": 8516 - }, - "cher": { - "script": 8517 - }, - "chrs": { - "script": 8518 - }, - "cirt": { - "script": 8519 - }, - "copt": { - "script": 8520 - }, - "cpmn": { - "script": 8521 - }, - "cprt": { - "script": 8522 - }, - "cyrl": { - "script": 8523 - }, - "cyrs": { - "script": 8524 - }, - "deva": { - "script": 8525 - }, - "diak": { - "script": 8526 - }, - "dogr": { - "script": 8527 - }, - "dsrt": { - "script": 8528 - }, - "dupl": { - "script": 8529 - }, - "egyd": { - "script": 8530 - }, - "egyh": { - "script": 8531 - }, - "egyp": { - "script": 8532 - }, - "elba": { - "script": 8533 - }, - "elym": { - "script": 8534 - }, - "ethi": { - "script": 8535 - }, - "geok": { - "script": 8536 - }, - "geor": { - "script": 8537 - }, - "glag": { - "script": 8538 - }, - "gong": { - "script": 8539 - }, - "gonm": { - "script": 8540 - }, - "goth": { - "script": 8541 - }, - "gran": { - "script": 8542 - }, - "grek": { - "script": 8543 - }, - "gujr": { - "script": 8544 - }, - "guru": { - "script": 8545 - }, - "hanb": { - "script": 8546 - }, - "hang": { - "script": 8547 - }, - "hani": { - "script": 8548 - }, - "hano": { - "script": 8549 - }, - "hans": { - "script": 8550 - }, - "hant": { - "script": 8551 - }, - "hatr": { - "script": 8552 - }, - "hebr": { - "script": 8553 - }, - "hira": { - "script": 8554 - }, - "hluw": { - "script": 8555 - }, - "hmng": { - "script": 8556 - }, - "hmnp": { - "script": 8557 - }, - "hrkt": { - "script": 8558 - }, - "hung": { - "script": 8559 - }, - "inds": { - "script": 8560 - }, - "ital": { - "script": 8561 - }, - "jamo": { - "script": 8562 - }, - "java": { - "script": 8563 - }, - "jpan": { - "script": 8564 - }, - "jurc": { - "script": 8565 - }, - "kali": { - "script": 8566 - }, - "kana": { - "script": 8567 - }, - "kawi": { - "script": 8568 - }, - "khar": { - "script": 8569 - }, - "khmr": { - "script": 8570 - }, - "khoj": { - "script": 8571 - }, - "kitl": { - "script": 8572 - }, - "kits": { - "script": 8573 - }, - "knda": { - "script": 8574 - }, - "kore": { - "script": 8575 - }, - "kpel": { - "script": 8576 - }, - "kthi": { - "script": 8577 - }, - "lana": { - "script": 8578 - }, - "laoo": { - "script": 8579 - }, - "latf": { - "script": 8580 - }, - "latg": { - "script": 8581 - }, - "latn": { - "script": 8582 - }, - "leke": { - "script": 8583 - }, - "lepc": { - "script": 8584 - }, - "limb": { - "script": 8585 - }, - "lina": { - "script": 8586 - }, - "linb": { - "script": 8587 - }, - "lisu": { - "script": 8588 - }, - "loma": { - "script": 8589 - }, - "lyci": { - "script": 8590 - }, - "lydi": { - "script": 8591 - }, - "mahj": { - "script": 8592 - }, - "maka": { - "script": 8593 - }, - "mand": { - "script": 8594 - }, - "mani": { - "script": 8595 - }, - "marc": { - "script": 8596 - }, - "maya": { - "script": 8597 - }, - "medf": { - "script": 8598 - }, - "mend": { - "script": 8599 - }, - "merc": { - "script": 8600 - }, - "mero": { - "script": 8601 - }, - "mlym": { - "script": 8602 - }, - "modi": { - "script": 8603 - }, - "mong": { - "script": 8604 - }, - "moon": { - "script": 8605 - }, - "mroo": { - "script": 8606 - }, - "mtei": { - "script": 8607 - }, - "mult": { - "script": 8608 - }, - "mymr": { - "script": 8609 - }, - "nagm": { - "script": 8610 - }, - "nand": { - "script": 8611 - }, - "narb": { - "script": 8612 - }, - "nbat": { - "script": 8613 - }, - "newa": { - "script": 8614 - }, - "nkdb": { - "script": 8615 - }, - "nkgb": { - "script": 8616 - }, - "nkoo": { - "script": 8617 - }, - "nshu": { - "script": 8618 - }, - "ogam": { - "script": 8619 - }, - "olck": { - "script": 8620 - }, - "orkh": { - "script": 8621 - }, - "orya": { - "script": 8622 - }, - "osge": { - "script": 8623 - }, - "osma": { - "script": 8624 - }, - "ougr": { - "script": 8625 - }, - "palm": { - "script": 8626 - }, - "pauc": { - "script": 8627 - }, - "pcun": { - "script": 8628 - }, - "pelm": { - "script": 8629 - }, - "perm": { - "script": 8630 - }, - "phag": { - "script": 8631 - }, - "phli": { - "script": 8632 - }, - "phlp": { - "script": 8633 - }, - "phlv": { - "script": 8634 - }, - "phnx": { - "script": 8635 - }, - "piqd": { - "script": 8636 - }, - "plrd": { - "script": 8637 - }, - "prti": { - "script": 8638 - }, - "psin": { - "script": 8639 - }, - "qaaa..qabx": { - "script": 8640 - }, - "ranj": { - "script": 8641 - }, - "rjng": { - "script": 8642 - }, - "rohg": { - "script": 8643 - }, - "roro": { - "script": 8644 - }, - "runr": { - "script": 8645 - }, - "samr": { - "script": 8646 - }, - "sara": { - "script": 8647 - }, - "sarb": { - "script": 8648 - }, - "saur": { - "script": 8649 - }, - "sgnw": { - "script": 8650 - }, - "shaw": { - "script": 8651 - }, - "shrd": { - "script": 8652 - }, - "shui": { - "script": 8653 - }, - "sidd": { - "script": 8654 - }, - "sind": { - "script": 8655 - }, - "sinh": { - "script": 8656 - }, - "sogd": { - "script": 8657 - }, - "sogo": { - "script": 8658 - }, - "sora": { - "script": 8659 - }, - "soyo": { - "script": 8660 - }, - "sund": { - "script": 8661 - }, - "sunu": { - "script": 8662 - }, - "sylo": { - "script": 8663 - }, - "syrc": { - "script": 8664 - }, - "syre": { - "script": 8665 - }, - "syrj": { - "script": 8666 - }, - "syrn": { - "script": 8667 - }, - "tagb": { - "script": 8668 - }, - "takr": { - "script": 8669 - }, - "tale": { - "script": 8670 - }, - "talu": { - "script": 8671 - }, - "taml": { - "script": 8672 - }, - "tang": { - "script": 8673 - }, - "tavt": { - "script": 8674 - }, - "telu": { - "script": 8675 - }, - "teng": { - "script": 8676 - }, - "tfng": { - "script": 8677 - }, - "tglg": { - "script": 8678 - }, - "thaa": { - "script": 8679 - }, - "thai": { - "script": 8680 - }, - "tibt": { - "script": 8681 - }, - "tirh": { - "script": 8682 - }, - "tnsa": { - "script": 8683 - }, - "toto": { - "script": 8684 - }, - "ugar": { - "script": 8685 - }, - "vaii": { - "script": 8686 - }, - "visp": { - "script": 8687 - }, - "vith": { - "script": 8688 - }, - "wara": { - "script": 8689 - }, - "wcho": { - "script": 8690 - }, - "wole": { - "script": 8691 - }, - "xpeo": { - "script": 8692 - }, - "xsux": { - "script": 8693 - }, - "yezi": { - "script": 8694 - }, - "yiii": { - "script": 8695 - }, - "zanb": { - "script": 8696 - }, - "zinh": { - "script": 8697 - }, - "zmth": { - "script": 8698 - }, - "zsye": { - "script": 8699 - }, - "zsym": { - "script": 8700 - }, - "zxxx": { - "script": 8701 - }, - "zyyy": { - "script": 8702 - }, - "zzzz": { - "script": 8703 - }, - "ac": { - "region": 8705 - }, - "ad": { - "region": 8706 - }, - "ag": { - "region": 8709 - }, - "ai": { - "region": 8710 - }, - "al": { - "region": 8711 - }, - "ao": { - "region": 8714 - }, - "aq": { - "region": 8715 - }, - "at": { - "region": 8718 - }, - "au": { - "region": 8719 - }, - "aw": { - "region": 8720 - }, - "ax": { - "region": 8721 - }, - "bb": { - "region": 8724 - }, - "bd": { - "region": 8725 - }, - "bf": { - "region": 8727 - }, - "bj": { - "region": 8731 - }, - "bl": { - "region": 8732 - }, - "bq": { - "region": 8736 - }, - "bt": { - "region": 8739 - }, - "bu": { - "region": 8740 - }, - "bv": { - "region": 8741 - }, - "bw": { - "region": 8742 - }, - "by": { - "region": 8743 - }, - "bz": { - "region": 8744 - }, - "cc": { - "region": 8746 - }, - "cd": { - "region": 8747 - }, - "cf": { - "region": 8748 - }, - "cg": { - "region": 8749 - }, - "ci": { - "region": 8751 - }, - "ck": { - "region": 8752 - }, - "cl": { - "region": 8753 - }, - "cm": { - "region": 8754 - }, - "cn": { - "region": 8755 - }, - "cp": { - "region": 8757 - }, - "cw": { - "region": 8762 - }, - "cx": { - "region": 8763 - }, - "cz": { - "region": 8765 - }, - "dd": { - "region": 8766 - }, - "dg": { - "region": 8768 - }, - "dj": { - "region": 8769 - }, - "dk": { - "region": 8770 - }, - "dm": { - "region": 8771 - }, - "do": { - "region": 8772 - }, - "ea": { - "region": 8774 - }, - "ec": { - "region": 8775 - }, - "eg": { - "region": 8777 - }, - "eh": { - "region": 8778 - }, - "er": { - "region": 8779 - }, - "ez": { - "region": 8783 - }, - "fk": { - "region": 8786 - }, - "fm": { - "region": 8787 - }, - "fx": { - "region": 8790 - }, - "gb": { - "region": 8792 - }, - "ge": { - "region": 8794 - }, - "gf": { - "region": 8795 - }, - "gg": { - "region": 8796 - }, - "gh": { - "region": 8797 - }, - "gi": { - "region": 8798 - }, - "gm": { - "region": 8800 - }, - "gp": { - "region": 8802 - }, - "gq": { - "region": 8803 - }, - "gr": { - "region": 8804 - }, - "gs": { - "region": 8805 - }, - "gt": { - "region": 8806 - }, - "gw": { - "region": 8808 - }, - "gy": { - "region": 8809 - }, - "hk": { - "region": 8810 - }, - "hm": { - "region": 8811 - }, - "hn": { - "region": 8812 - }, - "ic": { - "region": 8816 - }, - "il": { - "region": 8819 - }, - "im": { - "region": 8820 - }, - "iq": { - "region": 8823 - }, - "ir": { - "region": 8824 - }, - "je": { - "region": 8827 - }, - "jm": { - "region": 8828 - }, - "jo": { - "region": 8829 - }, - "jp": { - "region": 8830 - }, - "ke": { - "region": 8831 - }, - "kh": { - "region": 8833 - }, - "kp": { - "region": 8837 - }, - "kz": { - "region": 8841 - }, - "lc": { - "region": 8844 - }, - "lk": { - "region": 8846 - }, - "lr": { - "region": 8847 - }, - "ls": { - "region": 8848 - }, - "ly": { - "region": 8852 - }, - "ma": { - "region": 8853 - }, - "mc": { - "region": 8854 - }, - "md": { - "region": 8855 - }, - "me": { - "region": 8856 - }, - "mf": { - "region": 8857 - }, - "mm": { - "region": 8862 - }, - "mp": { - "region": 8865 - }, - "mq": { - "region": 8866 - }, - "mu": { - "region": 8870 - }, - "mv": { - "region": 8871 - }, - "mw": { - "region": 8872 - }, - "mx": { - "region": 8873 - }, - "mz": { - "region": 8875 - }, - "nc": { - "region": 8877 - }, - "nf": { - "region": 8879 - }, - "ni": { - "region": 8881 - }, - "np": { - "region": 8884 - }, - "nt": { - "region": 8886 - }, - "nu": { - "region": 8887 - }, - "nz": { - "region": 8888 - }, - "pe": { - "region": 8891 - }, - "pf": { - "region": 8892 - }, - "pg": { - "region": 8893 - }, - "ph": { - "region": 8894 - }, - "pk": { - "region": 8895 - }, - "pm": { - "region": 8897 - }, - "pn": { - "region": 8898 - }, - "pr": { - "region": 8899 - }, - "pw": { - "region": 8902 - }, - "py": { - "region": 8903 - }, - "qa": { - "region": 8904 - }, - "qm..qz": { - "region": 8905 - }, - "re": { - "region": 8906 - }, - "rs": { - "region": 8908 - }, - "sb": { - "region": 8912 - }, - "sj": { - "region": 8919 - }, - "sx": { - "region": 8930 - }, - "sy": { - "region": 8931 - }, - "sz": { - "region": 8932 - }, - "tc": { - "region": 8934 - }, - "td": { - "region": 8935 - }, - "tf": { - "region": 8936 - }, - "tj": { - "region": 8939 - }, - "tm": { - "region": 8942 - }, - "tp": { - "region": 8945 - }, - "tv": { - "region": 8948 - }, - "tz": { - "region": 8950 - }, - "ua": { - "region": 8951 - }, - "um": { - "region": 8953 - }, - "un": { - "region": 8954 - }, - "us": { - "region": 8955 - }, - "uy": { - "region": 8956 - }, - "va": { - "region": 8958 - }, - "vc": { - "region": 8959 - }, - "vg": { - "region": 8961 - }, - "vn": { - "region": 8963 - }, - "vu": { - "region": 8964 - }, - "wf": { - "region": 8965 - }, - "ws": { - "region": 8966 - }, - "xa..xz": { - "region": 8967 - }, - "yd": { - "region": 8968 - }, - "ye": { - "region": 8969 - }, - "yt": { - "region": 8970 - }, - "yu": { - "region": 8971 - }, - "zm": { - "region": 8973 - }, - "zr": { - "region": 8974 - }, - "zw": { - "region": 8975 - }, - "zz": { - "region": 8976 - }, - "001": { - "region": 8977 - }, - "002": { - "region": 8978 - }, - "003": { - "region": 8979 - }, - "005": { - "region": 8980 - }, - "009": { - "region": 8981 - }, - "011": { - "region": 8982 - }, - "013": { - "region": 8983 - }, - "014": { - "region": 8984 - }, - "015": { - "region": 8985 - }, - "017": { - "region": 8986 - }, - "018": { - "region": 8987 - }, - "019": { - "region": 8988 - }, - "021": { - "region": 8989 - }, - "029": { - "region": 8990 - }, - "030": { - "region": 8991 - }, - "034": { - "region": 8992 - }, - "035": { - "region": 8993 - }, - "039": { - "region": 8994 - }, - "053": { - "region": 8995 - }, - "054": { - "region": 8996 - }, - "057": { - "region": 8997 - }, - "061": { - "region": 8998 - }, - "1606nict": { - "variant": 9008 - }, - "1694acad": { - "variant": 9009 - }, - "1959acad": { - "variant": 9011 - }, - "abl1943": { - "variant": 9014 - }, - "akuapem": { - "variant": 9015 - }, - "alalc97": { - "variant": 9016 - }, - "aluku": { - "variant": 9017 - }, - "ao1990": { - "variant": 9018 - }, - "aranes": { - "variant": 9019 - }, - "arevela": { - "variant": 9020 - }, - "arevmda": { - "variant": 9021 - }, - "arkaika": { - "variant": 9022 - }, - "asante": { - "variant": 9023 - }, - "auvern": { - "variant": 9024 - }, - "baku1926": { - "variant": 9025 - }, - "balanka": { - "variant": 9026 - }, - "barla": { - "variant": 9027 - }, - "basiceng": { - "variant": 9028 - }, - "bauddha": { - "variant": 9029 - }, - "biscayan": { - "variant": 9030 - }, - "biske": { - "variant": 9031 - }, - "bohoric": { - "variant": 9032 - }, - "boont": { - "variant": 9033 - }, - "bornholm": { - "variant": 9034 - }, - "cisaup": { - "variant": 9035 - }, - "colb1945": { - "variant": 9036 - }, - "cornu": { - "variant": 9037 - }, - "creiss": { - "variant": 9038 - }, - "dajnko": { - "variant": 9039 - }, - "ekavsk": { - "variant": 9040 - }, - "emodeng": { - "variant": 9041 - }, - "fonipa": { - "variant": 9042 - }, - "fonkirsh": { - "variant": 9043 - }, - "fonnapa": { - "variant": 9044 - }, - "fonupa": { - "variant": 9045 - }, - "fonxsamp": { - "variant": 9046 - }, - "gallo": { - "variant": 9047 - }, - "gascon": { - "variant": 9048 - }, - "grclass": { - "variant": 9049 - }, - "grital": { - "variant": 9050 - }, - "grmistr": { - "variant": 9051 - }, - "hepburn": { - "variant": 9052 - }, - "heploc": { - "variant": 9053 - }, - "hognorsk": { - "variant": 9054 - }, - "hsistemo": { - "variant": 9055 - }, - "ijekavsk": { - "variant": 9056 - }, - "itihasa": { - "variant": 9057 - }, - "ivanchov": { - "variant": 9058 - }, - "jauer": { - "variant": 9059 - }, - "jyutping": { - "variant": 9060 - }, - "kkcor": { - "variant": 9061 - }, - "kociewie": { - "variant": 9062 - }, - "kscor": { - "variant": 9063 - }, - "laukika": { - "variant": 9064 - }, - "lemosin": { - "variant": 9065 - }, - "lengadoc": { - "variant": 9066 - }, - "lipaw": { - "variant": 9067 - }, - "ltg2007": { - "variant": 9068 - }, - "luna1918": { - "variant": 9069 - }, - "metelko": { - "variant": 9070 - }, - "monoton": { - "variant": 9071 - }, - "ndyuka": { - "variant": 9072 - }, - "nedis": { - "variant": 9073 - }, - "newfound": { - "variant": 9074 - }, - "nicard": { - "variant": 9075 - }, - "njiva": { - "variant": 9076 - }, - "nulik": { - "variant": 9077 - }, - "osojs": { - "variant": 9078 - }, - "oxendict": { - "variant": 9079 - }, - "pahawh2": { - "variant": 9080 - }, - "pahawh3": { - "variant": 9081 - }, - "pahawh4": { - "variant": 9082 - }, - "pamaka": { - "variant": 9083 - }, - "peano": { - "variant": 9084 - }, - "petr1708": { - "variant": 9085 - }, - "pinyin": { - "variant": 9086 - }, - "polyton": { - "variant": 9087 - }, - "provenc": { - "variant": 9088 - }, - "puter": { - "variant": 9089 - }, - "rigik": { - "variant": 9090 - }, - "rozaj": { - "variant": 9091 - }, - "rumgr": { - "variant": 9092 - }, - "scotland": { - "variant": 9093 - }, - "scouse": { - "variant": 9094 - }, - "simple": { - "variant": 9095 - }, - "solba": { - "variant": 9096 - }, - "sotav": { - "variant": 9097 - }, - "spanglis": { - "variant": 9098 - }, - "surmiran": { - "variant": 9099 - }, - "sursilv": { - "variant": 9100 - }, - "sutsilv": { - "variant": 9101 - }, - "synnejyl": { - "variant": 9102 - }, - "tarask": { - "variant": 9103 - }, - "tongyong": { - "variant": 9104 - }, - "tunumiit": { - "variant": 9105 - }, - "uccor": { - "variant": 9106 - }, - "ucrcor": { - "variant": 9107 - }, - "ulster": { - "variant": 9108 - }, - "unifon": { - "variant": 9109 - }, - "vaidika": { - "variant": 9110 - }, - "valencia": { - "variant": 9111 - }, - "vallader": { - "variant": 9112 - }, - "vecdruka": { - "variant": 9113 - }, - "vivaraup": { - "variant": 9114 - }, - "wadegile": { - "variant": 9115 - }, - "xsistemo": { - "variant": 9116 - }, - "art-lojban": { - "grandfathered": 9117 - }, - "cel-gaulish": { - "grandfathered": 9118 - }, - "en-gb-oed": { - "grandfathered": 9119 - }, - "i-ami": { - "grandfathered": 9120 - }, - "i-bnn": { - "grandfathered": 9121 - }, - "i-default": { - "grandfathered": 9122 - }, - "i-enochian": { - "grandfathered": 9123 - }, - "i-hak": { - "grandfathered": 9124 - }, - "i-klingon": { - "grandfathered": 9125 - }, - "i-lux": { - "grandfathered": 9126 - }, - "i-mingo": { - "grandfathered": 9127 - }, - "i-navajo": { - "grandfathered": 9128 - }, - "i-pwn": { - "grandfathered": 9129 - }, - "i-tao": { - "grandfathered": 9130 - }, - "i-tay": { - "grandfathered": 9131 - }, - "i-tsu": { - "grandfathered": 9132 - }, - "no-bok": { - "grandfathered": 9133 - }, - "no-nyn": { - "grandfathered": 9134 - }, - "sgn-be-fr": { - "grandfathered": 9135 - }, - "sgn-be-nl": { - "grandfathered": 9136 - }, - "sgn-ch-de": { - "grandfathered": 9137 - }, - "zh-guoyu": { - "grandfathered": 9138 - }, - "zh-hakka": { - "grandfathered": 9139 - }, - "zh-min": { - "grandfathered": 9140 - }, - "zh-min-nan": { - "grandfathered": 9141 - }, - "zh-xiang": { - "grandfathered": 9142 - }, - "az-arab": { - "redundant": 9143 - }, - "az-cyrl": { - "redundant": 9144 - }, - "az-latn": { - "redundant": 9145 - }, - "be-latn": { - "redundant": 9146 - }, - "bs-cyrl": { - "redundant": 9147 - }, - "bs-latn": { - "redundant": 9148 - }, - "de-1901": { - "redundant": 9149 - }, - "de-1996": { - "redundant": 9150 - }, - "de-at-1901": { - "redundant": 9151 - }, - "de-at-1996": { - "redundant": 9152 - }, - "de-ch-1901": { - "redundant": 9153 - }, - "de-ch-1996": { - "redundant": 9154 - }, - "de-de-1901": { - "redundant": 9155 - }, - "de-de-1996": { - "redundant": 9156 - }, - "en-boont": { - "redundant": 9157 - }, - "en-scouse": { - "redundant": 9158 - }, - "es-419": { - "redundant": 9159 - }, - "iu-cans": { - "redundant": 9160 - }, - "iu-latn": { - "redundant": 9161 - }, - "mn-cyrl": { - "redundant": 9162 - }, - "mn-mong": { - "redundant": 9163 - }, - "sgn-br": { - "redundant": 9164 - }, - "sgn-co": { - "redundant": 9165 - }, - "sgn-de": { - "redundant": 9166 - }, - "sgn-dk": { - "redundant": 9167 - }, - "sgn-es": { - "redundant": 9168 - }, - "sgn-fr": { - "redundant": 9169 - }, - "sgn-gb": { - "redundant": 9170 - }, - "sgn-gr": { - "redundant": 9171 - }, - "sgn-ie": { - "redundant": 9172 - }, - "sgn-it": { - "redundant": 9173 - }, - "sgn-jp": { - "redundant": 9174 - }, - "sgn-mx": { - "redundant": 9175 - }, - "sgn-ni": { - "redundant": 9176 - }, - "sgn-nl": { - "redundant": 9177 - }, - "sgn-no": { - "redundant": 9178 - }, - "sgn-pt": { - "redundant": 9179 - }, - "sgn-se": { - "redundant": 9180 - }, - "sgn-us": { - "redundant": 9181 - }, - "sgn-za": { - "redundant": 9182 - }, - "sl-nedis": { - "redundant": 9183 - }, - "sl-rozaj": { - "redundant": 9184 - }, - "sr-cyrl": { - "redundant": 9185 - }, - "sr-latn": { - "redundant": 9186 - }, - "tg-arab": { - "redundant": 9187 - }, - "tg-cyrl": { - "redundant": 9188 - }, - "uz-cyrl": { - "redundant": 9189 - }, - "uz-latn": { - "redundant": 9190 - }, - "yi-latn": { - "redundant": 9191 - }, - "zh-cmn": { - "redundant": 9192 - }, - "zh-cmn-hans": { - "redundant": 9193 - }, - "zh-cmn-hant": { - "redundant": 9194 - }, - "zh-gan": { - "redundant": 9195 - }, - "zh-hans": { - "redundant": 9196 - }, - "zh-hans-cn": { - "redundant": 9197 - }, - "zh-hans-hk": { - "redundant": 9198 - }, - "zh-hans-mo": { - "redundant": 9199 - }, - "zh-hans-sg": { - "redundant": 9200 - }, - "zh-hans-tw": { - "redundant": 9201 - }, - "zh-hant": { - "redundant": 9202 - }, - "zh-hant-cn": { - "redundant": 9203 - }, - "zh-hant-hk": { - "redundant": 9204 - }, - "zh-hant-mo": { - "redundant": 9205 - }, - "zh-hant-sg": { - "redundant": 9206 - }, - "zh-hant-tw": { - "redundant": 9207 - }, - "zh-wuu": { - "redundant": 9208 - }, - "zh-yue": { - "redundant": 9209 - } -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/language.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/language.json deleted file mode 100644 index 9cb4520..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/language.json +++ /dev/null @@ -1,8242 +0,0 @@ -{ - "aa": 0, - "ab": 1, - "ae": 2, - "af": 3, - "ak": 4, - "am": 5, - "an": 6, - "ar": 7, - "as": 8, - "av": 9, - "ay": 10, - "az": 11, - "ba": 12, - "be": 13, - "bg": 14, - "bh": 15, - "bi": 16, - "bm": 17, - "bn": 18, - "bo": 19, - "br": 20, - "bs": 21, - "ca": 22, - "ce": 23, - "ch": 24, - "co": 25, - "cr": 26, - "cs": 27, - "cu": 28, - "cv": 29, - "cy": 30, - "da": 31, - "de": 32, - "dv": 33, - "dz": 34, - "ee": 35, - "el": 36, - "en": 37, - "eo": 38, - "es": 39, - "et": 40, - "eu": 41, - "fa": 42, - "ff": 43, - "fi": 44, - "fj": 45, - "fo": 46, - "fr": 47, - "fy": 48, - "ga": 49, - "gd": 50, - "gl": 51, - "gn": 52, - "gu": 53, - "gv": 54, - "ha": 55, - "he": 56, - "hi": 57, - "ho": 58, - "hr": 59, - "ht": 60, - "hu": 61, - "hy": 62, - "hz": 63, - "ia": 64, - "id": 65, - "ie": 66, - "ig": 67, - "ii": 68, - "ik": 69, - "in": 70, - "io": 71, - "is": 72, - "it": 73, - "iu": 74, - "iw": 75, - "ja": 76, - "ji": 77, - "jv": 78, - "jw": 79, - "ka": 80, - "kg": 81, - "ki": 82, - "kj": 83, - "kk": 84, - "kl": 85, - "km": 86, - "kn": 87, - "ko": 88, - "kr": 89, - "ks": 90, - "ku": 91, - "kv": 92, - "kw": 93, - "ky": 94, - "la": 95, - "lb": 96, - "lg": 97, - "li": 98, - "ln": 99, - "lo": 100, - "lt": 101, - "lu": 102, - "lv": 103, - "mg": 104, - "mh": 105, - "mi": 106, - "mk": 107, - "ml": 108, - "mn": 109, - "mo": 110, - "mr": 111, - "ms": 112, - "mt": 113, - "my": 114, - "na": 115, - "nb": 116, - "nd": 117, - "ne": 118, - "ng": 119, - "nl": 120, - "nn": 121, - "no": 122, - "nr": 123, - "nv": 124, - "ny": 125, - "oc": 126, - "oj": 127, - "om": 128, - "or": 129, - "os": 130, - "pa": 131, - "pi": 132, - "pl": 133, - "ps": 134, - "pt": 135, - "qu": 136, - "rm": 137, - "rn": 138, - "ro": 139, - "ru": 140, - "rw": 141, - "sa": 142, - "sc": 143, - "sd": 144, - "se": 145, - "sg": 146, - "sh": 147, - "si": 148, - "sk": 149, - "sl": 150, - "sm": 151, - "sn": 152, - "so": 153, - "sq": 154, - "sr": 155, - "ss": 156, - "st": 157, - "su": 158, - "sv": 159, - "sw": 160, - "ta": 161, - "te": 162, - "tg": 163, - "th": 164, - "ti": 165, - "tk": 166, - "tl": 167, - "tn": 168, - "to": 169, - "tr": 170, - "ts": 171, - "tt": 172, - "tw": 173, - "ty": 174, - "ug": 175, - "uk": 176, - "ur": 177, - "uz": 178, - "ve": 179, - "vi": 180, - "vo": 181, - "wa": 182, - "wo": 183, - "xh": 184, - "yi": 185, - "yo": 186, - "za": 187, - "zh": 188, - "zu": 189, - "aaa": 190, - "aab": 191, - "aac": 192, - "aad": 193, - "aae": 194, - "aaf": 195, - "aag": 196, - "aah": 197, - "aai": 198, - "aak": 199, - "aal": 200, - "aam": 201, - "aan": 202, - "aao": 203, - "aap": 204, - "aaq": 205, - "aas": 206, - "aat": 207, - "aau": 208, - "aav": 209, - "aaw": 210, - "aax": 211, - "aaz": 212, - "aba": 213, - "abb": 214, - "abc": 215, - "abd": 216, - "abe": 217, - "abf": 218, - "abg": 219, - "abh": 220, - "abi": 221, - "abj": 222, - "abl": 223, - "abm": 224, - "abn": 225, - "abo": 226, - "abp": 227, - "abq": 228, - "abr": 229, - "abs": 230, - "abt": 231, - "abu": 232, - "abv": 233, - "abw": 234, - "abx": 235, - "aby": 236, - "abz": 237, - "aca": 238, - "acb": 239, - "acd": 240, - "ace": 241, - "acf": 242, - "ach": 243, - "aci": 244, - "ack": 245, - "acl": 246, - "acm": 247, - "acn": 248, - "acp": 249, - "acq": 250, - "acr": 251, - "acs": 252, - "act": 253, - "acu": 254, - "acv": 255, - "acw": 256, - "acx": 257, - "acy": 258, - "acz": 259, - "ada": 260, - "adb": 261, - "add": 262, - "ade": 263, - "adf": 264, - "adg": 265, - "adh": 266, - "adi": 267, - "adj": 268, - "adl": 269, - "adn": 270, - "ado": 271, - "adp": 272, - "adq": 273, - "adr": 274, - "ads": 275, - "adt": 276, - "adu": 277, - "adw": 278, - "adx": 279, - "ady": 280, - "adz": 281, - "aea": 282, - "aeb": 283, - "aec": 284, - "aed": 285, - "aee": 286, - "aek": 287, - "ael": 288, - "aem": 289, - "aen": 290, - "aeq": 291, - "aer": 292, - "aes": 293, - "aeu": 294, - "aew": 295, - "aey": 296, - "aez": 297, - "afa": 298, - "afb": 299, - "afd": 300, - "afe": 301, - "afg": 302, - "afh": 303, - "afi": 304, - "afk": 305, - "afn": 306, - "afo": 307, - "afp": 308, - "afs": 309, - "aft": 310, - "afu": 311, - "afz": 312, - "aga": 313, - "agb": 314, - "agc": 315, - "agd": 316, - "age": 317, - "agf": 318, - "agg": 319, - "agh": 320, - "agi": 321, - "agj": 322, - "agk": 323, - "agl": 324, - "agm": 325, - "agn": 326, - "ago": 327, - "agp": 328, - "agq": 329, - "agr": 330, - "ags": 331, - "agt": 332, - "agu": 333, - "agv": 334, - "agw": 335, - "agx": 336, - "agy": 337, - "agz": 338, - "aha": 339, - "ahb": 340, - "ahg": 341, - "ahh": 342, - "ahi": 343, - "ahk": 344, - "ahl": 345, - "ahm": 346, - "ahn": 347, - "aho": 348, - "ahp": 349, - "ahr": 350, - "ahs": 351, - "aht": 352, - "aia": 353, - "aib": 354, - "aic": 355, - "aid": 356, - "aie": 357, - "aif": 358, - "aig": 359, - "aih": 360, - "aii": 361, - "aij": 362, - "aik": 363, - "ail": 364, - "aim": 365, - "ain": 366, - "aio": 367, - "aip": 368, - "aiq": 369, - "air": 370, - "ais": 371, - "ait": 372, - "aiw": 373, - "aix": 374, - "aiy": 375, - "aja": 376, - "ajg": 377, - "aji": 378, - "ajn": 379, - "ajp": 380, - "ajs": 381, - "ajt": 382, - "aju": 383, - "ajw": 384, - "ajz": 385, - "akb": 386, - "akc": 387, - "akd": 388, - "ake": 389, - "akf": 390, - "akg": 391, - "akh": 392, - "aki": 393, - "akj": 394, - "akk": 395, - "akl": 396, - "akm": 397, - "ako": 398, - "akp": 399, - "akq": 400, - "akr": 401, - "aks": 402, - "akt": 403, - "aku": 404, - "akv": 405, - "akw": 406, - "akx": 407, - "aky": 408, - "akz": 409, - "ala": 410, - "alc": 411, - "ald": 412, - "ale": 413, - "alf": 414, - "alg": 415, - "alh": 416, - "ali": 417, - "alj": 418, - "alk": 419, - "all": 420, - "alm": 421, - "aln": 422, - "alo": 423, - "alp": 424, - "alq": 425, - "alr": 426, - "als": 427, - "alt": 428, - "alu": 429, - "alv": 430, - "alw": 431, - "alx": 432, - "aly": 433, - "alz": 434, - "ama": 435, - "amb": 436, - "amc": 437, - "ame": 438, - "amf": 439, - "amg": 440, - "ami": 441, - "amj": 442, - "amk": 443, - "aml": 444, - "amm": 445, - "amn": 446, - "amo": 447, - "amp": 448, - "amq": 449, - "amr": 450, - "ams": 451, - "amt": 452, - "amu": 453, - "amv": 454, - "amw": 455, - "amx": 456, - "amy": 457, - "amz": 458, - "ana": 459, - "anb": 460, - "anc": 461, - "and": 462, - "ane": 463, - "anf": 464, - "ang": 465, - "anh": 466, - "ani": 467, - "anj": 468, - "ank": 469, - "anl": 470, - "anm": 471, - "ann": 472, - "ano": 473, - "anp": 474, - "anq": 475, - "anr": 476, - "ans": 477, - "ant": 478, - "anu": 479, - "anv": 480, - "anw": 481, - "anx": 482, - "any": 483, - "anz": 484, - "aoa": 485, - "aob": 486, - "aoc": 487, - "aod": 488, - "aoe": 489, - "aof": 490, - "aog": 491, - "aoh": 492, - "aoi": 493, - "aoj": 494, - "aok": 495, - "aol": 496, - "aom": 497, - "aon": 498, - "aor": 499, - "aos": 500, - "aot": 501, - "aou": 502, - "aox": 503, - "aoz": 504, - "apa": 505, - "apb": 506, - "apc": 507, - "apd": 508, - "ape": 509, - "apf": 510, - "apg": 511, - "aph": 512, - "api": 513, - "apj": 514, - "apk": 515, - "apl": 516, - "apm": 517, - "apn": 518, - "apo": 519, - "app": 520, - "apq": 521, - "apr": 522, - "aps": 523, - "apt": 524, - "apu": 525, - "apv": 526, - "apw": 527, - "apx": 528, - "apy": 529, - "apz": 530, - "aqa": 531, - "aqc": 532, - "aqd": 533, - "aqg": 534, - "aqk": 535, - "aql": 536, - "aqm": 537, - "aqn": 538, - "aqp": 539, - "aqr": 540, - "aqt": 541, - "aqz": 542, - "arb": 543, - "arc": 544, - "ard": 545, - "are": 546, - "arh": 547, - "ari": 548, - "arj": 549, - "ark": 550, - "arl": 551, - "arn": 552, - "aro": 553, - "arp": 554, - "arq": 555, - "arr": 556, - "ars": 557, - "art": 558, - "aru": 559, - "arv": 560, - "arw": 561, - "arx": 562, - "ary": 563, - "arz": 564, - "asa": 565, - "asb": 566, - "asc": 567, - "asd": 568, - "ase": 569, - "asf": 570, - "asg": 571, - "ash": 572, - "asi": 573, - "asj": 574, - "ask": 575, - "asl": 576, - "asn": 577, - "aso": 578, - "asp": 579, - "asq": 580, - "asr": 581, - "ass": 582, - "ast": 583, - "asu": 584, - "asv": 585, - "asw": 586, - "asx": 587, - "asy": 588, - "asz": 589, - "ata": 590, - "atb": 591, - "atc": 592, - "atd": 593, - "ate": 594, - "atg": 595, - "ath": 596, - "ati": 597, - "atj": 598, - "atk": 599, - "atl": 600, - "atm": 601, - "atn": 602, - "ato": 603, - "atp": 604, - "atq": 605, - "atr": 606, - "ats": 607, - "att": 608, - "atu": 609, - "atv": 610, - "atw": 611, - "atx": 612, - "aty": 613, - "atz": 614, - "aua": 615, - "aub": 616, - "auc": 617, - "aud": 618, - "aue": 619, - "auf": 620, - "aug": 621, - "auh": 622, - "aui": 623, - "auj": 624, - "auk": 625, - "aul": 626, - "aum": 627, - "aun": 628, - "auo": 629, - "aup": 630, - "auq": 631, - "aur": 632, - "aus": 633, - "aut": 634, - "auu": 635, - "auw": 636, - "aux": 637, - "auy": 638, - "auz": 639, - "avb": 640, - "avd": 641, - "avi": 642, - "avk": 643, - "avl": 644, - "avm": 645, - "avn": 646, - "avo": 647, - "avs": 648, - "avt": 649, - "avu": 650, - "avv": 651, - "awa": 652, - "awb": 653, - "awc": 654, - "awd": 655, - "awe": 656, - "awg": 657, - "awh": 658, - "awi": 659, - "awk": 660, - "awm": 661, - "awn": 662, - "awo": 663, - "awr": 664, - "aws": 665, - "awt": 666, - "awu": 667, - "awv": 668, - "aww": 669, - "awx": 670, - "awy": 671, - "axb": 672, - "axe": 673, - "axg": 674, - "axk": 675, - "axl": 676, - "axm": 677, - "axx": 678, - "aya": 679, - "ayb": 680, - "ayc": 681, - "ayd": 682, - "aye": 683, - "ayg": 684, - "ayh": 685, - "ayi": 686, - "ayk": 687, - "ayl": 688, - "ayn": 689, - "ayo": 690, - "ayp": 691, - "ayq": 692, - "ayr": 693, - "ays": 694, - "ayt": 695, - "ayu": 696, - "ayx": 697, - "ayy": 698, - "ayz": 699, - "aza": 700, - "azb": 701, - "azc": 702, - "azd": 703, - "azg": 704, - "azj": 705, - "azm": 706, - "azn": 707, - "azo": 708, - "azt": 709, - "azz": 710, - "baa": 711, - "bab": 712, - "bac": 713, - "bad": 714, - "bae": 715, - "baf": 716, - "bag": 717, - "bah": 718, - "bai": 719, - "baj": 720, - "bal": 721, - "ban": 722, - "bao": 723, - "bap": 724, - "bar": 725, - "bas": 726, - "bat": 727, - "bau": 728, - "bav": 729, - "baw": 730, - "bax": 731, - "bay": 732, - "baz": 733, - "bba": 734, - "bbb": 735, - "bbc": 736, - "bbd": 737, - "bbe": 738, - "bbf": 739, - "bbg": 740, - "bbh": 741, - "bbi": 742, - "bbj": 743, - "bbk": 744, - "bbl": 745, - "bbm": 746, - "bbn": 747, - "bbo": 748, - "bbp": 749, - "bbq": 750, - "bbr": 751, - "bbs": 752, - "bbt": 753, - "bbu": 754, - "bbv": 755, - "bbw": 756, - "bbx": 757, - "bby": 758, - "bbz": 759, - "bca": 760, - "bcb": 761, - "bcc": 762, - "bcd": 763, - "bce": 764, - "bcf": 765, - "bcg": 766, - "bch": 767, - "bci": 768, - "bcj": 769, - "bck": 770, - "bcl": 771, - "bcm": 772, - "bcn": 773, - "bco": 774, - "bcp": 775, - "bcq": 776, - "bcr": 777, - "bcs": 778, - "bct": 779, - "bcu": 780, - "bcv": 781, - "bcw": 782, - "bcy": 783, - "bcz": 784, - "bda": 785, - "bdb": 786, - "bdc": 787, - "bdd": 788, - "bde": 789, - "bdf": 790, - "bdg": 791, - "bdh": 792, - "bdi": 793, - "bdj": 794, - "bdk": 795, - "bdl": 796, - "bdm": 797, - "bdn": 798, - "bdo": 799, - "bdp": 800, - "bdq": 801, - "bdr": 802, - "bds": 803, - "bdt": 804, - "bdu": 805, - "bdv": 806, - "bdw": 807, - "bdx": 808, - "bdy": 809, - "bdz": 810, - "bea": 811, - "beb": 812, - "bec": 813, - "bed": 814, - "bee": 815, - "bef": 816, - "beg": 817, - "beh": 818, - "bei": 819, - "bej": 820, - "bek": 821, - "bem": 822, - "beo": 823, - "bep": 824, - "beq": 825, - "ber": 826, - "bes": 827, - "bet": 828, - "beu": 829, - "bev": 830, - "bew": 831, - "bex": 832, - "bey": 833, - "bez": 834, - "bfa": 835, - "bfb": 836, - "bfc": 837, - "bfd": 838, - "bfe": 839, - "bff": 840, - "bfg": 841, - "bfh": 842, - "bfi": 843, - "bfj": 844, - "bfk": 845, - "bfl": 846, - "bfm": 847, - "bfn": 848, - "bfo": 849, - "bfp": 850, - "bfq": 851, - "bfr": 852, - "bfs": 853, - "bft": 854, - "bfu": 855, - "bfw": 856, - "bfx": 857, - "bfy": 858, - "bfz": 859, - "bga": 860, - "bgb": 861, - "bgc": 862, - "bgd": 863, - "bge": 864, - "bgf": 865, - "bgg": 866, - "bgi": 867, - "bgj": 868, - "bgk": 869, - "bgl": 870, - "bgm": 871, - "bgn": 872, - "bgo": 873, - "bgp": 874, - "bgq": 875, - "bgr": 876, - "bgs": 877, - "bgt": 878, - "bgu": 879, - "bgv": 880, - "bgw": 881, - "bgx": 882, - "bgy": 883, - "bgz": 884, - "bha": 885, - "bhb": 886, - "bhc": 887, - "bhd": 888, - "bhe": 889, - "bhf": 890, - "bhg": 891, - "bhh": 892, - "bhi": 893, - "bhj": 894, - "bhk": 895, - "bhl": 896, - "bhm": 897, - "bhn": 898, - "bho": 899, - "bhp": 900, - "bhq": 901, - "bhr": 902, - "bhs": 903, - "bht": 904, - "bhu": 905, - "bhv": 906, - "bhw": 907, - "bhx": 908, - "bhy": 909, - "bhz": 910, - "bia": 911, - "bib": 912, - "bic": 913, - "bid": 914, - "bie": 915, - "bif": 916, - "big": 917, - "bij": 918, - "bik": 919, - "bil": 920, - "bim": 921, - "bin": 922, - "bio": 923, - "bip": 924, - "biq": 925, - "bir": 926, - "bit": 927, - "biu": 928, - "biv": 929, - "biw": 930, - "bix": 931, - "biy": 932, - "biz": 933, - "bja": 934, - "bjb": 935, - "bjc": 936, - "bjd": 937, - "bje": 938, - "bjf": 939, - "bjg": 940, - "bjh": 941, - "bji": 942, - "bjj": 943, - "bjk": 944, - "bjl": 945, - "bjm": 946, - "bjn": 947, - "bjo": 948, - "bjp": 949, - "bjq": 950, - "bjr": 951, - "bjs": 952, - "bjt": 953, - "bju": 954, - "bjv": 955, - "bjw": 956, - "bjx": 957, - "bjy": 958, - "bjz": 959, - "bka": 960, - "bkb": 961, - "bkc": 962, - "bkd": 963, - "bkf": 964, - "bkg": 965, - "bkh": 966, - "bki": 967, - "bkj": 968, - "bkk": 969, - "bkl": 970, - "bkm": 971, - "bkn": 972, - "bko": 973, - "bkp": 974, - "bkq": 975, - "bkr": 976, - "bks": 977, - "bkt": 978, - "bku": 979, - "bkv": 980, - "bkw": 981, - "bkx": 982, - "bky": 983, - "bkz": 984, - "bla": 985, - "blb": 986, - "blc": 987, - "bld": 988, - "ble": 989, - "blf": 990, - "blg": 991, - "blh": 992, - "bli": 993, - "blj": 994, - "blk": 995, - "bll": 996, - "blm": 997, - "bln": 998, - "blo": 999, - "blp": 1000, - "blq": 1001, - "blr": 1002, - "bls": 1003, - "blt": 1004, - "blv": 1005, - "blw": 1006, - "blx": 1007, - "bly": 1008, - "blz": 1009, - "bma": 1010, - "bmb": 1011, - "bmc": 1012, - "bmd": 1013, - "bme": 1014, - "bmf": 1015, - "bmg": 1016, - "bmh": 1017, - "bmi": 1018, - "bmj": 1019, - "bmk": 1020, - "bml": 1021, - "bmm": 1022, - "bmn": 1023, - "bmo": 1024, - "bmp": 1025, - "bmq": 1026, - "bmr": 1027, - "bms": 1028, - "bmt": 1029, - "bmu": 1030, - "bmv": 1031, - "bmw": 1032, - "bmx": 1033, - "bmy": 1034, - "bmz": 1035, - "bna": 1036, - "bnb": 1037, - "bnc": 1038, - "bnd": 1039, - "bne": 1040, - "bnf": 1041, - "bng": 1042, - "bni": 1043, - "bnj": 1044, - "bnk": 1045, - "bnl": 1046, - "bnm": 1047, - "bnn": 1048, - "bno": 1049, - "bnp": 1050, - "bnq": 1051, - "bnr": 1052, - "bns": 1053, - "bnt": 1054, - "bnu": 1055, - "bnv": 1056, - "bnw": 1057, - "bnx": 1058, - "bny": 1059, - "bnz": 1060, - "boa": 1061, - "bob": 1062, - "boe": 1063, - "bof": 1064, - "bog": 1065, - "boh": 1066, - "boi": 1067, - "boj": 1068, - "bok": 1069, - "bol": 1070, - "bom": 1071, - "bon": 1072, - "boo": 1073, - "bop": 1074, - "boq": 1075, - "bor": 1076, - "bot": 1077, - "bou": 1078, - "bov": 1079, - "bow": 1080, - "box": 1081, - "boy": 1082, - "boz": 1083, - "bpa": 1084, - "bpb": 1085, - "bpc": 1086, - "bpd": 1087, - "bpe": 1088, - "bpg": 1089, - "bph": 1090, - "bpi": 1091, - "bpj": 1092, - "bpk": 1093, - "bpl": 1094, - "bpm": 1095, - "bpn": 1096, - "bpo": 1097, - "bpp": 1098, - "bpq": 1099, - "bpr": 1100, - "bps": 1101, - "bpt": 1102, - "bpu": 1103, - "bpv": 1104, - "bpw": 1105, - "bpx": 1106, - "bpy": 1107, - "bpz": 1108, - "bqa": 1109, - "bqb": 1110, - "bqc": 1111, - "bqd": 1112, - "bqf": 1113, - "bqg": 1114, - "bqh": 1115, - "bqi": 1116, - "bqj": 1117, - "bqk": 1118, - "bql": 1119, - "bqm": 1120, - "bqn": 1121, - "bqo": 1122, - "bqp": 1123, - "bqq": 1124, - "bqr": 1125, - "bqs": 1126, - "bqt": 1127, - "bqu": 1128, - "bqv": 1129, - "bqw": 1130, - "bqx": 1131, - "bqy": 1132, - "bqz": 1133, - "bra": 1134, - "brb": 1135, - "brc": 1136, - "brd": 1137, - "brf": 1138, - "brg": 1139, - "brh": 1140, - "bri": 1141, - "brj": 1142, - "brk": 1143, - "brl": 1144, - "brm": 1145, - "brn": 1146, - "bro": 1147, - "brp": 1148, - "brq": 1149, - "brr": 1150, - "brs": 1151, - "brt": 1152, - "bru": 1153, - "brv": 1154, - "brw": 1155, - "brx": 1156, - "bry": 1157, - "brz": 1158, - "bsa": 1159, - "bsb": 1160, - "bsc": 1161, - "bse": 1162, - "bsf": 1163, - "bsg": 1164, - "bsh": 1165, - "bsi": 1166, - "bsj": 1167, - "bsk": 1168, - "bsl": 1169, - "bsm": 1170, - "bsn": 1171, - "bso": 1172, - "bsp": 1173, - "bsq": 1174, - "bsr": 1175, - "bss": 1176, - "bst": 1177, - "bsu": 1178, - "bsv": 1179, - "bsw": 1180, - "bsx": 1181, - "bsy": 1182, - "bta": 1183, - "btb": 1184, - "btc": 1185, - "btd": 1186, - "bte": 1187, - "btf": 1188, - "btg": 1189, - "bth": 1190, - "bti": 1191, - "btj": 1192, - "btk": 1193, - "btl": 1194, - "btm": 1195, - "btn": 1196, - "bto": 1197, - "btp": 1198, - "btq": 1199, - "btr": 1200, - "bts": 1201, - "btt": 1202, - "btu": 1203, - "btv": 1204, - "btw": 1205, - "btx": 1206, - "bty": 1207, - "btz": 1208, - "bua": 1209, - "bub": 1210, - "buc": 1211, - "bud": 1212, - "bue": 1213, - "buf": 1214, - "bug": 1215, - "buh": 1216, - "bui": 1217, - "buj": 1218, - "buk": 1219, - "bum": 1220, - "bun": 1221, - "buo": 1222, - "bup": 1223, - "buq": 1224, - "bus": 1225, - "but": 1226, - "buu": 1227, - "buv": 1228, - "buw": 1229, - "bux": 1230, - "buy": 1231, - "buz": 1232, - "bva": 1233, - "bvb": 1234, - "bvc": 1235, - "bvd": 1236, - "bve": 1237, - "bvf": 1238, - "bvg": 1239, - "bvh": 1240, - "bvi": 1241, - "bvj": 1242, - "bvk": 1243, - "bvl": 1244, - "bvm": 1245, - "bvn": 1246, - "bvo": 1247, - "bvp": 1248, - "bvq": 1249, - "bvr": 1250, - "bvt": 1251, - "bvu": 1252, - "bvv": 1253, - "bvw": 1254, - "bvx": 1255, - "bvy": 1256, - "bvz": 1257, - "bwa": 1258, - "bwb": 1259, - "bwc": 1260, - "bwd": 1261, - "bwe": 1262, - "bwf": 1263, - "bwg": 1264, - "bwh": 1265, - "bwi": 1266, - "bwj": 1267, - "bwk": 1268, - "bwl": 1269, - "bwm": 1270, - "bwn": 1271, - "bwo": 1272, - "bwp": 1273, - "bwq": 1274, - "bwr": 1275, - "bws": 1276, - "bwt": 1277, - "bwu": 1278, - "bww": 1279, - "bwx": 1280, - "bwy": 1281, - "bwz": 1282, - "bxa": 1283, - "bxb": 1284, - "bxc": 1285, - "bxd": 1286, - "bxe": 1287, - "bxf": 1288, - "bxg": 1289, - "bxh": 1290, - "bxi": 1291, - "bxj": 1292, - "bxk": 1293, - "bxl": 1294, - "bxm": 1295, - "bxn": 1296, - "bxo": 1297, - "bxp": 1298, - "bxq": 1299, - "bxr": 1300, - "bxs": 1301, - "bxu": 1302, - "bxv": 1303, - "bxw": 1304, - "bxx": 1305, - "bxz": 1306, - "bya": 1307, - "byb": 1308, - "byc": 1309, - "byd": 1310, - "bye": 1311, - "byf": 1312, - "byg": 1313, - "byh": 1314, - "byi": 1315, - "byj": 1316, - "byk": 1317, - "byl": 1318, - "bym": 1319, - "byn": 1320, - "byo": 1321, - "byp": 1322, - "byq": 1323, - "byr": 1324, - "bys": 1325, - "byt": 1326, - "byv": 1327, - "byw": 1328, - "byx": 1329, - "byy": 1330, - "byz": 1331, - "bza": 1332, - "bzb": 1333, - "bzc": 1334, - "bzd": 1335, - "bze": 1336, - "bzf": 1337, - "bzg": 1338, - "bzh": 1339, - "bzi": 1340, - "bzj": 1341, - "bzk": 1342, - "bzl": 1343, - "bzm": 1344, - "bzn": 1345, - "bzo": 1346, - "bzp": 1347, - "bzq": 1348, - "bzr": 1349, - "bzs": 1350, - "bzt": 1351, - "bzu": 1352, - "bzv": 1353, - "bzw": 1354, - "bzx": 1355, - "bzy": 1356, - "bzz": 1357, - "caa": 1358, - "cab": 1359, - "cac": 1360, - "cad": 1361, - "cae": 1362, - "caf": 1363, - "cag": 1364, - "cah": 1365, - "cai": 1366, - "caj": 1367, - "cak": 1368, - "cal": 1369, - "cam": 1370, - "can": 1371, - "cao": 1372, - "cap": 1373, - "caq": 1374, - "car": 1375, - "cas": 1376, - "cau": 1377, - "cav": 1378, - "caw": 1379, - "cax": 1380, - "cay": 1381, - "caz": 1382, - "cba": 1383, - "cbb": 1384, - "cbc": 1385, - "cbd": 1386, - "cbe": 1387, - "cbg": 1388, - "cbh": 1389, - "cbi": 1390, - "cbj": 1391, - "cbk": 1392, - "cbl": 1393, - "cbn": 1394, - "cbo": 1395, - "cbq": 1396, - "cbr": 1397, - "cbs": 1398, - "cbt": 1399, - "cbu": 1400, - "cbv": 1401, - "cbw": 1402, - "cby": 1403, - "cca": 1404, - "ccc": 1405, - "ccd": 1406, - "cce": 1407, - "ccg": 1408, - "cch": 1409, - "ccj": 1410, - "ccl": 1411, - "ccm": 1412, - "ccn": 1413, - "cco": 1414, - "ccp": 1415, - "ccq": 1416, - "ccr": 1417, - "ccs": 1418, - "cda": 1419, - "cdc": 1420, - "cdd": 1421, - "cde": 1422, - "cdf": 1423, - "cdg": 1424, - "cdh": 1425, - "cdi": 1426, - "cdj": 1427, - "cdm": 1428, - "cdn": 1429, - "cdo": 1430, - "cdr": 1431, - "cds": 1432, - "cdy": 1433, - "cdz": 1434, - "cea": 1435, - "ceb": 1436, - "ceg": 1437, - "cek": 1438, - "cel": 1439, - "cen": 1440, - "cet": 1441, - "cey": 1442, - "cfa": 1443, - "cfd": 1444, - "cfg": 1445, - "cfm": 1446, - "cga": 1447, - "cgc": 1448, - "cgg": 1449, - "cgk": 1450, - "chb": 1451, - "chc": 1452, - "chd": 1453, - "chf": 1454, - "chg": 1455, - "chh": 1456, - "chj": 1457, - "chk": 1458, - "chl": 1459, - "chm": 1460, - "chn": 1461, - "cho": 1462, - "chp": 1463, - "chq": 1464, - "chr": 1465, - "cht": 1466, - "chw": 1467, - "chx": 1468, - "chy": 1469, - "chz": 1470, - "cia": 1471, - "cib": 1472, - "cic": 1473, - "cid": 1474, - "cie": 1475, - "cih": 1476, - "cik": 1477, - "cim": 1478, - "cin": 1479, - "cip": 1480, - "cir": 1481, - "ciw": 1482, - "ciy": 1483, - "cja": 1484, - "cje": 1485, - "cjh": 1486, - "cji": 1487, - "cjk": 1488, - "cjm": 1489, - "cjn": 1490, - "cjo": 1491, - "cjp": 1492, - "cjr": 1493, - "cjs": 1494, - "cjv": 1495, - "cjy": 1496, - "cka": 1497, - "ckb": 1498, - "ckh": 1499, - "ckl": 1500, - "ckm": 1501, - "ckn": 1502, - "cko": 1503, - "ckq": 1504, - "ckr": 1505, - "cks": 1506, - "ckt": 1507, - "cku": 1508, - "ckv": 1509, - "ckx": 1510, - "cky": 1511, - "ckz": 1512, - "cla": 1513, - "clc": 1514, - "cld": 1515, - "cle": 1516, - "clh": 1517, - "cli": 1518, - "clj": 1519, - "clk": 1520, - "cll": 1521, - "clm": 1522, - "clo": 1523, - "clt": 1524, - "clu": 1525, - "clw": 1526, - "cly": 1527, - "cma": 1528, - "cmc": 1529, - "cme": 1530, - "cmg": 1531, - "cmi": 1532, - "cmk": 1533, - "cml": 1534, - "cmm": 1535, - "cmn": 1536, - "cmo": 1537, - "cmr": 1538, - "cms": 1539, - "cmt": 1540, - "cna": 1541, - "cnb": 1542, - "cnc": 1543, - "cng": 1544, - "cnh": 1545, - "cni": 1546, - "cnk": 1547, - "cnl": 1548, - "cno": 1549, - "cnp": 1550, - "cnq": 1551, - "cnr": 1552, - "cns": 1553, - "cnt": 1554, - "cnu": 1555, - "cnw": 1556, - "cnx": 1557, - "coa": 1558, - "cob": 1559, - "coc": 1560, - "cod": 1561, - "coe": 1562, - "cof": 1563, - "cog": 1564, - "coh": 1565, - "coj": 1566, - "cok": 1567, - "col": 1568, - "com": 1569, - "con": 1570, - "coo": 1571, - "cop": 1572, - "coq": 1573, - "cot": 1574, - "cou": 1575, - "cov": 1576, - "cow": 1577, - "cox": 1578, - "coy": 1579, - "coz": 1580, - "cpa": 1581, - "cpb": 1582, - "cpc": 1583, - "cpe": 1584, - "cpf": 1585, - "cpg": 1586, - "cpi": 1587, - "cpn": 1588, - "cpo": 1589, - "cpp": 1590, - "cps": 1591, - "cpu": 1592, - "cpx": 1593, - "cpy": 1594, - "cqd": 1595, - "cqu": 1596, - "cra": 1597, - "crb": 1598, - "crc": 1599, - "crd": 1600, - "crf": 1601, - "crg": 1602, - "crh": 1603, - "cri": 1604, - "crj": 1605, - "crk": 1606, - "crl": 1607, - "crm": 1608, - "crn": 1609, - "cro": 1610, - "crp": 1611, - "crq": 1612, - "crr": 1613, - "crs": 1614, - "crt": 1615, - "crv": 1616, - "crw": 1617, - "crx": 1618, - "cry": 1619, - "crz": 1620, - "csa": 1621, - "csb": 1622, - "csc": 1623, - "csd": 1624, - "cse": 1625, - "csf": 1626, - "csg": 1627, - "csh": 1628, - "csi": 1629, - "csj": 1630, - "csk": 1631, - "csl": 1632, - "csm": 1633, - "csn": 1634, - "cso": 1635, - "csp": 1636, - "csq": 1637, - "csr": 1638, - "css": 1639, - "cst": 1640, - "csu": 1641, - "csv": 1642, - "csw": 1643, - "csx": 1644, - "csy": 1645, - "csz": 1646, - "cta": 1647, - "ctc": 1648, - "ctd": 1649, - "cte": 1650, - "ctg": 1651, - "cth": 1652, - "ctl": 1653, - "ctm": 1654, - "ctn": 1655, - "cto": 1656, - "ctp": 1657, - "cts": 1658, - "ctt": 1659, - "ctu": 1660, - "cty": 1661, - "ctz": 1662, - "cua": 1663, - "cub": 1664, - "cuc": 1665, - "cug": 1666, - "cuh": 1667, - "cui": 1668, - "cuj": 1669, - "cuk": 1670, - "cul": 1671, - "cum": 1672, - "cuo": 1673, - "cup": 1674, - "cuq": 1675, - "cur": 1676, - "cus": 1677, - "cut": 1678, - "cuu": 1679, - "cuv": 1680, - "cuw": 1681, - "cux": 1682, - "cuy": 1683, - "cvg": 1684, - "cvn": 1685, - "cwa": 1686, - "cwb": 1687, - "cwd": 1688, - "cwe": 1689, - "cwg": 1690, - "cwt": 1691, - "cya": 1692, - "cyb": 1693, - "cyo": 1694, - "czh": 1695, - "czk": 1696, - "czn": 1697, - "czo": 1698, - "czt": 1699, - "daa": 1700, - "dac": 1701, - "dad": 1702, - "dae": 1703, - "daf": 1704, - "dag": 1705, - "dah": 1706, - "dai": 1707, - "daj": 1708, - "dak": 1709, - "dal": 1710, - "dam": 1711, - "dao": 1712, - "dap": 1713, - "daq": 1714, - "dar": 1715, - "das": 1716, - "dau": 1717, - "dav": 1718, - "daw": 1719, - "dax": 1720, - "day": 1721, - "daz": 1722, - "dba": 1723, - "dbb": 1724, - "dbd": 1725, - "dbe": 1726, - "dbf": 1727, - "dbg": 1728, - "dbi": 1729, - "dbj": 1730, - "dbl": 1731, - "dbm": 1732, - "dbn": 1733, - "dbo": 1734, - "dbp": 1735, - "dbq": 1736, - "dbr": 1737, - "dbt": 1738, - "dbu": 1739, - "dbv": 1740, - "dbw": 1741, - "dby": 1742, - "dcc": 1743, - "dcr": 1744, - "dda": 1745, - "ddd": 1746, - "dde": 1747, - "ddg": 1748, - "ddi": 1749, - "ddj": 1750, - "ddn": 1751, - "ddo": 1752, - "ddr": 1753, - "dds": 1754, - "ddw": 1755, - "dec": 1756, - "ded": 1757, - "dee": 1758, - "def": 1759, - "deg": 1760, - "deh": 1761, - "dei": 1762, - "dek": 1763, - "del": 1764, - "dem": 1765, - "den": 1766, - "dep": 1767, - "deq": 1768, - "der": 1769, - "des": 1770, - "dev": 1771, - "dez": 1772, - "dga": 1773, - "dgb": 1774, - "dgc": 1775, - "dgd": 1776, - "dge": 1777, - "dgg": 1778, - "dgh": 1779, - "dgi": 1780, - "dgk": 1781, - "dgl": 1782, - "dgn": 1783, - "dgo": 1784, - "dgr": 1785, - "dgs": 1786, - "dgt": 1787, - "dgu": 1788, - "dgw": 1789, - "dgx": 1790, - "dgz": 1791, - "dha": 1792, - "dhd": 1793, - "dhg": 1794, - "dhi": 1795, - "dhl": 1796, - "dhm": 1797, - "dhn": 1798, - "dho": 1799, - "dhr": 1800, - "dhs": 1801, - "dhu": 1802, - "dhv": 1803, - "dhw": 1804, - "dhx": 1805, - "dia": 1806, - "dib": 1807, - "dic": 1808, - "did": 1809, - "dif": 1810, - "dig": 1811, - "dih": 1812, - "dii": 1813, - "dij": 1814, - "dik": 1815, - "dil": 1816, - "dim": 1817, - "din": 1818, - "dio": 1819, - "dip": 1820, - "diq": 1821, - "dir": 1822, - "dis": 1823, - "dit": 1824, - "diu": 1825, - "diw": 1826, - "dix": 1827, - "diy": 1828, - "diz": 1829, - "dja": 1830, - "djb": 1831, - "djc": 1832, - "djd": 1833, - "dje": 1834, - "djf": 1835, - "dji": 1836, - "djj": 1837, - "djk": 1838, - "djl": 1839, - "djm": 1840, - "djn": 1841, - "djo": 1842, - "djr": 1843, - "dju": 1844, - "djw": 1845, - "dka": 1846, - "dkg": 1847, - "dkk": 1848, - "dkl": 1849, - "dkr": 1850, - "dks": 1851, - "dkx": 1852, - "dlg": 1853, - "dlk": 1854, - "dlm": 1855, - "dln": 1856, - "dma": 1857, - "dmb": 1858, - "dmc": 1859, - "dmd": 1860, - "dme": 1861, - "dmf": 1862, - "dmg": 1863, - "dmk": 1864, - "dml": 1865, - "dmm": 1866, - "dmn": 1867, - "dmo": 1868, - "dmr": 1869, - "dms": 1870, - "dmu": 1871, - "dmv": 1872, - "dmw": 1873, - "dmx": 1874, - "dmy": 1875, - "dna": 1876, - "dnd": 1877, - "dne": 1878, - "dng": 1879, - "dni": 1880, - "dnj": 1881, - "dnk": 1882, - "dnn": 1883, - "dno": 1884, - "dnr": 1885, - "dnt": 1886, - "dnu": 1887, - "dnv": 1888, - "dnw": 1889, - "dny": 1890, - "doa": 1891, - "dob": 1892, - "doc": 1893, - "doe": 1894, - "dof": 1895, - "doh": 1896, - "doi": 1897, - "dok": 1898, - "dol": 1899, - "don": 1900, - "doo": 1901, - "dop": 1902, - "doq": 1903, - "dor": 1904, - "dos": 1905, - "dot": 1906, - "dov": 1907, - "dow": 1908, - "dox": 1909, - "doy": 1910, - "doz": 1911, - "dpp": 1912, - "dra": 1913, - "drb": 1914, - "drc": 1915, - "drd": 1916, - "dre": 1917, - "drg": 1918, - "drh": 1919, - "dri": 1920, - "drl": 1921, - "drn": 1922, - "dro": 1923, - "drq": 1924, - "drr": 1925, - "drs": 1926, - "drt": 1927, - "dru": 1928, - "drw": 1929, - "dry": 1930, - "dsb": 1931, - "dse": 1932, - "dsh": 1933, - "dsi": 1934, - "dsl": 1935, - "dsn": 1936, - "dso": 1937, - "dsq": 1938, - "dsz": 1939, - "dta": 1940, - "dtb": 1941, - "dtd": 1942, - "dth": 1943, - "dti": 1944, - "dtk": 1945, - "dtm": 1946, - "dtn": 1947, - "dto": 1948, - "dtp": 1949, - "dtr": 1950, - "dts": 1951, - "dtt": 1952, - "dtu": 1953, - "dty": 1954, - "dua": 1955, - "dub": 1956, - "duc": 1957, - "dud": 1958, - "due": 1959, - "duf": 1960, - "dug": 1961, - "duh": 1962, - "dui": 1963, - "duj": 1964, - "duk": 1965, - "dul": 1966, - "dum": 1967, - "dun": 1968, - "duo": 1969, - "dup": 1970, - "duq": 1971, - "dur": 1972, - "dus": 1973, - "duu": 1974, - "duv": 1975, - "duw": 1976, - "dux": 1977, - "duy": 1978, - "duz": 1979, - "dva": 1980, - "dwa": 1981, - "dwk": 1982, - "dwl": 1983, - "dwr": 1984, - "dws": 1985, - "dwu": 1986, - "dww": 1987, - "dwy": 1988, - "dwz": 1989, - "dya": 1990, - "dyb": 1991, - "dyd": 1992, - "dyg": 1993, - "dyi": 1994, - "dym": 1995, - "dyn": 1996, - "dyo": 1997, - "dyu": 1998, - "dyy": 1999, - "dza": 2000, - "dzd": 2001, - "dze": 2002, - "dzg": 2003, - "dzl": 2004, - "dzn": 2005, - "eaa": 2006, - "ebc": 2007, - "ebg": 2008, - "ebk": 2009, - "ebo": 2010, - "ebr": 2011, - "ebu": 2012, - "ecr": 2013, - "ecs": 2014, - "ecy": 2015, - "eee": 2016, - "efa": 2017, - "efe": 2018, - "efi": 2019, - "ega": 2020, - "egl": 2021, - "egm": 2022, - "ego": 2023, - "egx": 2024, - "egy": 2025, - "ehs": 2026, - "ehu": 2027, - "eip": 2028, - "eit": 2029, - "eiv": 2030, - "eja": 2031, - "eka": 2032, - "ekc": 2033, - "eke": 2034, - "ekg": 2035, - "eki": 2036, - "ekk": 2037, - "ekl": 2038, - "ekm": 2039, - "eko": 2040, - "ekp": 2041, - "ekr": 2042, - "eky": 2043, - "ele": 2044, - "elh": 2045, - "eli": 2046, - "elk": 2047, - "elm": 2048, - "elo": 2049, - "elp": 2050, - "elu": 2051, - "elx": 2052, - "ema": 2053, - "emb": 2054, - "eme": 2055, - "emg": 2056, - "emi": 2057, - "emk": 2058, - "emm": 2059, - "emn": 2060, - "emo": 2061, - "emp": 2062, - "emq": 2063, - "ems": 2064, - "emu": 2065, - "emw": 2066, - "emx": 2067, - "emy": 2068, - "emz": 2069, - "ena": 2070, - "enb": 2071, - "enc": 2072, - "end": 2073, - "enf": 2074, - "enh": 2075, - "enl": 2076, - "enm": 2077, - "enn": 2078, - "eno": 2079, - "enq": 2080, - "enr": 2081, - "enu": 2082, - "env": 2083, - "enw": 2084, - "enx": 2085, - "eot": 2086, - "epi": 2087, - "era": 2088, - "erg": 2089, - "erh": 2090, - "eri": 2091, - "erk": 2092, - "ero": 2093, - "err": 2094, - "ers": 2095, - "ert": 2096, - "erw": 2097, - "ese": 2098, - "esg": 2099, - "esh": 2100, - "esi": 2101, - "esk": 2102, - "esl": 2103, - "esm": 2104, - "esn": 2105, - "eso": 2106, - "esq": 2107, - "ess": 2108, - "esu": 2109, - "esx": 2110, - "esy": 2111, - "etb": 2112, - "etc": 2113, - "eth": 2114, - "etn": 2115, - "eto": 2116, - "etr": 2117, - "ets": 2118, - "ett": 2119, - "etu": 2120, - "etx": 2121, - "etz": 2122, - "euq": 2123, - "eve": 2124, - "evh": 2125, - "evn": 2126, - "ewo": 2127, - "ext": 2128, - "eya": 2129, - "eyo": 2130, - "eza": 2131, - "eze": 2132, - "faa": 2133, - "fab": 2134, - "fad": 2135, - "faf": 2136, - "fag": 2137, - "fah": 2138, - "fai": 2139, - "faj": 2140, - "fak": 2141, - "fal": 2142, - "fam": 2143, - "fan": 2144, - "fap": 2145, - "far": 2146, - "fat": 2147, - "fau": 2148, - "fax": 2149, - "fay": 2150, - "faz": 2151, - "fbl": 2152, - "fcs": 2153, - "fer": 2154, - "ffi": 2155, - "ffm": 2156, - "fgr": 2157, - "fia": 2158, - "fie": 2159, - "fif": 2160, - "fil": 2161, - "fip": 2162, - "fir": 2163, - "fit": 2164, - "fiu": 2165, - "fiw": 2166, - "fkk": 2167, - "fkv": 2168, - "fla": 2169, - "flh": 2170, - "fli": 2171, - "fll": 2172, - "fln": 2173, - "flr": 2174, - "fly": 2175, - "fmp": 2176, - "fmu": 2177, - "fnb": 2178, - "fng": 2179, - "fni": 2180, - "fod": 2181, - "foi": 2182, - "fom": 2183, - "fon": 2184, - "for": 2185, - "fos": 2186, - "fox": 2187, - "fpe": 2188, - "fqs": 2189, - "frc": 2190, - "frd": 2191, - "frk": 2192, - "frm": 2193, - "fro": 2194, - "frp": 2195, - "frq": 2196, - "frr": 2197, - "frs": 2198, - "frt": 2199, - "fse": 2200, - "fsl": 2201, - "fss": 2202, - "fub": 2203, - "fuc": 2204, - "fud": 2205, - "fue": 2206, - "fuf": 2207, - "fuh": 2208, - "fui": 2209, - "fuj": 2210, - "fum": 2211, - "fun": 2212, - "fuq": 2213, - "fur": 2214, - "fut": 2215, - "fuu": 2216, - "fuv": 2217, - "fuy": 2218, - "fvr": 2219, - "fwa": 2220, - "fwe": 2221, - "gaa": 2222, - "gab": 2223, - "gac": 2224, - "gad": 2225, - "gae": 2226, - "gaf": 2227, - "gag": 2228, - "gah": 2229, - "gai": 2230, - "gaj": 2231, - "gak": 2232, - "gal": 2233, - "gam": 2234, - "gan": 2235, - "gao": 2236, - "gap": 2237, - "gaq": 2238, - "gar": 2239, - "gas": 2240, - "gat": 2241, - "gau": 2242, - "gav": 2243, - "gaw": 2244, - "gax": 2245, - "gay": 2246, - "gaz": 2247, - "gba": 2248, - "gbb": 2249, - "gbc": 2250, - "gbd": 2251, - "gbe": 2252, - "gbf": 2253, - "gbg": 2254, - "gbh": 2255, - "gbi": 2256, - "gbj": 2257, - "gbk": 2258, - "gbl": 2259, - "gbm": 2260, - "gbn": 2261, - "gbo": 2262, - "gbp": 2263, - "gbq": 2264, - "gbr": 2265, - "gbs": 2266, - "gbu": 2267, - "gbv": 2268, - "gbw": 2269, - "gbx": 2270, - "gby": 2271, - "gbz": 2272, - "gcc": 2273, - "gcd": 2274, - "gce": 2275, - "gcf": 2276, - "gcl": 2277, - "gcn": 2278, - "gcr": 2279, - "gct": 2280, - "gda": 2281, - "gdb": 2282, - "gdc": 2283, - "gdd": 2284, - "gde": 2285, - "gdf": 2286, - "gdg": 2287, - "gdh": 2288, - "gdi": 2289, - "gdj": 2290, - "gdk": 2291, - "gdl": 2292, - "gdm": 2293, - "gdn": 2294, - "gdo": 2295, - "gdq": 2296, - "gdr": 2297, - "gds": 2298, - "gdt": 2299, - "gdu": 2300, - "gdx": 2301, - "gea": 2302, - "geb": 2303, - "gec": 2304, - "ged": 2305, - "gef": 2306, - "geg": 2307, - "geh": 2308, - "gei": 2309, - "gej": 2310, - "gek": 2311, - "gel": 2312, - "gem": 2313, - "geq": 2314, - "ges": 2315, - "gev": 2316, - "gew": 2317, - "gex": 2318, - "gey": 2319, - "gez": 2320, - "gfk": 2321, - "gft": 2322, - "gfx": 2323, - "gga": 2324, - "ggb": 2325, - "ggd": 2326, - "gge": 2327, - "ggg": 2328, - "ggk": 2329, - "ggl": 2330, - "ggn": 2331, - "ggo": 2332, - "ggr": 2333, - "ggt": 2334, - "ggu": 2335, - "ggw": 2336, - "gha": 2337, - "ghc": 2338, - "ghe": 2339, - "ghh": 2340, - "ghk": 2341, - "ghl": 2342, - "ghn": 2343, - "gho": 2344, - "ghr": 2345, - "ghs": 2346, - "ght": 2347, - "gia": 2348, - "gib": 2349, - "gic": 2350, - "gid": 2351, - "gie": 2352, - "gig": 2353, - "gih": 2354, - "gii": 2355, - "gil": 2356, - "gim": 2357, - "gin": 2358, - "gio": 2359, - "gip": 2360, - "giq": 2361, - "gir": 2362, - "gis": 2363, - "git": 2364, - "giu": 2365, - "giw": 2366, - "gix": 2367, - "giy": 2368, - "giz": 2369, - "gji": 2370, - "gjk": 2371, - "gjm": 2372, - "gjn": 2373, - "gjr": 2374, - "gju": 2375, - "gka": 2376, - "gkd": 2377, - "gke": 2378, - "gkn": 2379, - "gko": 2380, - "gkp": 2381, - "gku": 2382, - "glb": 2383, - "glc": 2384, - "gld": 2385, - "glh": 2386, - "gli": 2387, - "glj": 2388, - "glk": 2389, - "gll": 2390, - "glo": 2391, - "glr": 2392, - "glu": 2393, - "glw": 2394, - "gly": 2395, - "gma": 2396, - "gmb": 2397, - "gmd": 2398, - "gme": 2399, - "gmg": 2400, - "gmh": 2401, - "gml": 2402, - "gmm": 2403, - "gmn": 2404, - "gmq": 2405, - "gmr": 2406, - "gmu": 2407, - "gmv": 2408, - "gmw": 2409, - "gmx": 2410, - "gmy": 2411, - "gmz": 2412, - "gna": 2413, - "gnb": 2414, - "gnc": 2415, - "gnd": 2416, - "gne": 2417, - "gng": 2418, - "gnh": 2419, - "gni": 2420, - "gnj": 2421, - "gnk": 2422, - "gnl": 2423, - "gnm": 2424, - "gnn": 2425, - "gno": 2426, - "gnq": 2427, - "gnr": 2428, - "gnt": 2429, - "gnu": 2430, - "gnw": 2431, - "gnz": 2432, - "goa": 2433, - "gob": 2434, - "goc": 2435, - "god": 2436, - "goe": 2437, - "gof": 2438, - "gog": 2439, - "goh": 2440, - "goi": 2441, - "goj": 2442, - "gok": 2443, - "gol": 2444, - "gom": 2445, - "gon": 2446, - "goo": 2447, - "gop": 2448, - "goq": 2449, - "gor": 2450, - "gos": 2451, - "got": 2452, - "gou": 2453, - "gov": 2454, - "gow": 2455, - "gox": 2456, - "goy": 2457, - "goz": 2458, - "gpa": 2459, - "gpe": 2460, - "gpn": 2461, - "gqa": 2462, - "gqi": 2463, - "gqn": 2464, - "gqr": 2465, - "gqu": 2466, - "gra": 2467, - "grb": 2468, - "grc": 2469, - "grd": 2470, - "grg": 2471, - "grh": 2472, - "gri": 2473, - "grj": 2474, - "grk": 2475, - "grm": 2476, - "gro": 2477, - "grq": 2478, - "grr": 2479, - "grs": 2480, - "grt": 2481, - "gru": 2482, - "grv": 2483, - "grw": 2484, - "grx": 2485, - "gry": 2486, - "grz": 2487, - "gse": 2488, - "gsg": 2489, - "gsl": 2490, - "gsm": 2491, - "gsn": 2492, - "gso": 2493, - "gsp": 2494, - "gss": 2495, - "gsw": 2496, - "gta": 2497, - "gti": 2498, - "gtu": 2499, - "gua": 2500, - "gub": 2501, - "guc": 2502, - "gud": 2503, - "gue": 2504, - "guf": 2505, - "gug": 2506, - "guh": 2507, - "gui": 2508, - "guk": 2509, - "gul": 2510, - "gum": 2511, - "gun": 2512, - "guo": 2513, - "gup": 2514, - "guq": 2515, - "gur": 2516, - "gus": 2517, - "gut": 2518, - "guu": 2519, - "guv": 2520, - "guw": 2521, - "gux": 2522, - "guz": 2523, - "gva": 2524, - "gvc": 2525, - "gve": 2526, - "gvf": 2527, - "gvj": 2528, - "gvl": 2529, - "gvm": 2530, - "gvn": 2531, - "gvo": 2532, - "gvp": 2533, - "gvr": 2534, - "gvs": 2535, - "gvy": 2536, - "gwa": 2537, - "gwb": 2538, - "gwc": 2539, - "gwd": 2540, - "gwe": 2541, - "gwf": 2542, - "gwg": 2543, - "gwi": 2544, - "gwj": 2545, - "gwm": 2546, - "gwn": 2547, - "gwr": 2548, - "gwt": 2549, - "gwu": 2550, - "gww": 2551, - "gwx": 2552, - "gxx": 2553, - "gya": 2554, - "gyb": 2555, - "gyd": 2556, - "gye": 2557, - "gyf": 2558, - "gyg": 2559, - "gyi": 2560, - "gyl": 2561, - "gym": 2562, - "gyn": 2563, - "gyo": 2564, - "gyr": 2565, - "gyy": 2566, - "gyz": 2567, - "gza": 2568, - "gzi": 2569, - "gzn": 2570, - "haa": 2571, - "hab": 2572, - "hac": 2573, - "had": 2574, - "hae": 2575, - "haf": 2576, - "hag": 2577, - "hah": 2578, - "hai": 2579, - "haj": 2580, - "hak": 2581, - "hal": 2582, - "ham": 2583, - "han": 2584, - "hao": 2585, - "hap": 2586, - "haq": 2587, - "har": 2588, - "has": 2589, - "hav": 2590, - "haw": 2591, - "hax": 2592, - "hay": 2593, - "haz": 2594, - "hba": 2595, - "hbb": 2596, - "hbn": 2597, - "hbo": 2598, - "hbu": 2599, - "hca": 2600, - "hch": 2601, - "hdn": 2602, - "hds": 2603, - "hdy": 2604, - "hea": 2605, - "hed": 2606, - "heg": 2607, - "heh": 2608, - "hei": 2609, - "hem": 2610, - "hgm": 2611, - "hgw": 2612, - "hhi": 2613, - "hhr": 2614, - "hhy": 2615, - "hia": 2616, - "hib": 2617, - "hid": 2618, - "hif": 2619, - "hig": 2620, - "hih": 2621, - "hii": 2622, - "hij": 2623, - "hik": 2624, - "hil": 2625, - "him": 2626, - "hio": 2627, - "hir": 2628, - "hit": 2629, - "hiw": 2630, - "hix": 2631, - "hji": 2632, - "hka": 2633, - "hke": 2634, - "hkh": 2635, - "hkk": 2636, - "hkn": 2637, - "hks": 2638, - "hla": 2639, - "hlb": 2640, - "hld": 2641, - "hle": 2642, - "hlt": 2643, - "hlu": 2644, - "hma": 2645, - "hmb": 2646, - "hmc": 2647, - "hmd": 2648, - "hme": 2649, - "hmf": 2650, - "hmg": 2651, - "hmh": 2652, - "hmi": 2653, - "hmj": 2654, - "hmk": 2655, - "hml": 2656, - "hmm": 2657, - "hmn": 2658, - "hmp": 2659, - "hmq": 2660, - "hmr": 2661, - "hms": 2662, - "hmt": 2663, - "hmu": 2664, - "hmv": 2665, - "hmw": 2666, - "hmx": 2667, - "hmy": 2668, - "hmz": 2669, - "hna": 2670, - "hnd": 2671, - "hne": 2672, - "hng": 2673, - "hnh": 2674, - "hni": 2675, - "hnj": 2676, - "hnn": 2677, - "hno": 2678, - "hns": 2679, - "hnu": 2680, - "hoa": 2681, - "hob": 2682, - "hoc": 2683, - "hod": 2684, - "hoe": 2685, - "hoh": 2686, - "hoi": 2687, - "hoj": 2688, - "hok": 2689, - "hol": 2690, - "hom": 2691, - "hoo": 2692, - "hop": 2693, - "hor": 2694, - "hos": 2695, - "hot": 2696, - "hov": 2697, - "how": 2698, - "hoy": 2699, - "hoz": 2700, - "hpo": 2701, - "hps": 2702, - "hra": 2703, - "hrc": 2704, - "hre": 2705, - "hrk": 2706, - "hrm": 2707, - "hro": 2708, - "hrp": 2709, - "hrr": 2710, - "hrt": 2711, - "hru": 2712, - "hrw": 2713, - "hrx": 2714, - "hrz": 2715, - "hsb": 2716, - "hsh": 2717, - "hsl": 2718, - "hsn": 2719, - "hss": 2720, - "hti": 2721, - "hto": 2722, - "hts": 2723, - "htu": 2724, - "htx": 2725, - "hub": 2726, - "huc": 2727, - "hud": 2728, - "hue": 2729, - "huf": 2730, - "hug": 2731, - "huh": 2732, - "hui": 2733, - "huj": 2734, - "huk": 2735, - "hul": 2736, - "hum": 2737, - "huo": 2738, - "hup": 2739, - "huq": 2740, - "hur": 2741, - "hus": 2742, - "hut": 2743, - "huu": 2744, - "huv": 2745, - "huw": 2746, - "hux": 2747, - "huy": 2748, - "huz": 2749, - "hvc": 2750, - "hve": 2751, - "hvk": 2752, - "hvn": 2753, - "hvv": 2754, - "hwa": 2755, - "hwc": 2756, - "hwo": 2757, - "hya": 2758, - "hyw": 2759, - "hyx": 2760, - "iai": 2761, - "ian": 2762, - "iap": 2763, - "iar": 2764, - "iba": 2765, - "ibb": 2766, - "ibd": 2767, - "ibe": 2768, - "ibg": 2769, - "ibh": 2770, - "ibi": 2771, - "ibl": 2772, - "ibm": 2773, - "ibn": 2774, - "ibr": 2775, - "ibu": 2776, - "iby": 2777, - "ica": 2778, - "ich": 2779, - "icl": 2780, - "icr": 2781, - "ida": 2782, - "idb": 2783, - "idc": 2784, - "idd": 2785, - "ide": 2786, - "idi": 2787, - "idr": 2788, - "ids": 2789, - "idt": 2790, - "idu": 2791, - "ifa": 2792, - "ifb": 2793, - "ife": 2794, - "iff": 2795, - "ifk": 2796, - "ifm": 2797, - "ifu": 2798, - "ify": 2799, - "igb": 2800, - "ige": 2801, - "igg": 2802, - "igl": 2803, - "igm": 2804, - "ign": 2805, - "igo": 2806, - "igs": 2807, - "igw": 2808, - "ihb": 2809, - "ihi": 2810, - "ihp": 2811, - "ihw": 2812, - "iin": 2813, - "iir": 2814, - "ijc": 2815, - "ije": 2816, - "ijj": 2817, - "ijn": 2818, - "ijo": 2819, - "ijs": 2820, - "ike": 2821, - "iki": 2822, - "ikk": 2823, - "ikl": 2824, - "iko": 2825, - "ikp": 2826, - "ikr": 2827, - "iks": 2828, - "ikt": 2829, - "ikv": 2830, - "ikw": 2831, - "ikx": 2832, - "ikz": 2833, - "ila": 2834, - "ilb": 2835, - "ilg": 2836, - "ili": 2837, - "ilk": 2838, - "ill": 2839, - "ilm": 2840, - "ilo": 2841, - "ilp": 2842, - "ils": 2843, - "ilu": 2844, - "ilv": 2845, - "ilw": 2846, - "ima": 2847, - "ime": 2848, - "imi": 2849, - "iml": 2850, - "imn": 2851, - "imo": 2852, - "imr": 2853, - "ims": 2854, - "imt": 2855, - "imy": 2856, - "inb": 2857, - "inc": 2858, - "ine": 2859, - "ing": 2860, - "inh": 2861, - "inj": 2862, - "inl": 2863, - "inm": 2864, - "inn": 2865, - "ino": 2866, - "inp": 2867, - "ins": 2868, - "int": 2869, - "inz": 2870, - "ior": 2871, - "iou": 2872, - "iow": 2873, - "ipi": 2874, - "ipo": 2875, - "iqu": 2876, - "iqw": 2877, - "ira": 2878, - "ire": 2879, - "irh": 2880, - "iri": 2881, - "irk": 2882, - "irn": 2883, - "iro": 2884, - "irr": 2885, - "iru": 2886, - "irx": 2887, - "iry": 2888, - "isa": 2889, - "isc": 2890, - "isd": 2891, - "ise": 2892, - "isg": 2893, - "ish": 2894, - "isi": 2895, - "isk": 2896, - "ism": 2897, - "isn": 2898, - "iso": 2899, - "isr": 2900, - "ist": 2901, - "isu": 2902, - "itb": 2903, - "itc": 2904, - "itd": 2905, - "ite": 2906, - "iti": 2907, - "itk": 2908, - "itl": 2909, - "itm": 2910, - "ito": 2911, - "itr": 2912, - "its": 2913, - "itt": 2914, - "itv": 2915, - "itw": 2916, - "itx": 2917, - "ity": 2918, - "itz": 2919, - "ium": 2920, - "ivb": 2921, - "ivv": 2922, - "iwk": 2923, - "iwm": 2924, - "iwo": 2925, - "iws": 2926, - "ixc": 2927, - "ixl": 2928, - "iya": 2929, - "iyo": 2930, - "iyx": 2931, - "izh": 2932, - "izi": 2933, - "izr": 2934, - "izz": 2935, - "jaa": 2936, - "jab": 2937, - "jac": 2938, - "jad": 2939, - "jae": 2940, - "jaf": 2941, - "jah": 2942, - "jaj": 2943, - "jak": 2944, - "jal": 2945, - "jam": 2946, - "jan": 2947, - "jao": 2948, - "jaq": 2949, - "jar": 2950, - "jas": 2951, - "jat": 2952, - "jau": 2953, - "jax": 2954, - "jay": 2955, - "jaz": 2956, - "jbe": 2957, - "jbi": 2958, - "jbj": 2959, - "jbk": 2960, - "jbm": 2961, - "jbn": 2962, - "jbo": 2963, - "jbr": 2964, - "jbt": 2965, - "jbu": 2966, - "jbw": 2967, - "jcs": 2968, - "jct": 2969, - "jda": 2970, - "jdg": 2971, - "jdt": 2972, - "jeb": 2973, - "jee": 2974, - "jeg": 2975, - "jeh": 2976, - "jei": 2977, - "jek": 2978, - "jel": 2979, - "jen": 2980, - "jer": 2981, - "jet": 2982, - "jeu": 2983, - "jgb": 2984, - "jge": 2985, - "jgk": 2986, - "jgo": 2987, - "jhi": 2988, - "jhs": 2989, - "jia": 2990, - "jib": 2991, - "jic": 2992, - "jid": 2993, - "jie": 2994, - "jig": 2995, - "jih": 2996, - "jii": 2997, - "jil": 2998, - "jim": 2999, - "jio": 3000, - "jiq": 3001, - "jit": 3002, - "jiu": 3003, - "jiv": 3004, - "jiy": 3005, - "jje": 3006, - "jjr": 3007, - "jka": 3008, - "jkm": 3009, - "jko": 3010, - "jkp": 3011, - "jkr": 3012, - "jks": 3013, - "jku": 3014, - "jle": 3015, - "jls": 3016, - "jma": 3017, - "jmb": 3018, - "jmc": 3019, - "jmd": 3020, - "jmi": 3021, - "jml": 3022, - "jmn": 3023, - "jmr": 3024, - "jms": 3025, - "jmw": 3026, - "jmx": 3027, - "jna": 3028, - "jnd": 3029, - "jng": 3030, - "jni": 3031, - "jnj": 3032, - "jnl": 3033, - "jns": 3034, - "job": 3035, - "jod": 3036, - "jog": 3037, - "jor": 3038, - "jos": 3039, - "jow": 3040, - "jpa": 3041, - "jpr": 3042, - "jpx": 3043, - "jqr": 3044, - "jra": 3045, - "jrb": 3046, - "jrr": 3047, - "jrt": 3048, - "jru": 3049, - "jsl": 3050, - "jua": 3051, - "jub": 3052, - "juc": 3053, - "jud": 3054, - "juh": 3055, - "jui": 3056, - "juk": 3057, - "jul": 3058, - "jum": 3059, - "jun": 3060, - "juo": 3061, - "jup": 3062, - "jur": 3063, - "jus": 3064, - "jut": 3065, - "juu": 3066, - "juw": 3067, - "juy": 3068, - "jvd": 3069, - "jvn": 3070, - "jwi": 3071, - "jya": 3072, - "jye": 3073, - "jyy": 3074, - "kaa": 3075, - "kab": 3076, - "kac": 3077, - "kad": 3078, - "kae": 3079, - "kaf": 3080, - "kag": 3081, - "kah": 3082, - "kai": 3083, - "kaj": 3084, - "kak": 3085, - "kam": 3086, - "kao": 3087, - "kap": 3088, - "kaq": 3089, - "kar": 3090, - "kav": 3091, - "kaw": 3092, - "kax": 3093, - "kay": 3094, - "kba": 3095, - "kbb": 3096, - "kbc": 3097, - "kbd": 3098, - "kbe": 3099, - "kbf": 3100, - "kbg": 3101, - "kbh": 3102, - "kbi": 3103, - "kbj": 3104, - "kbk": 3105, - "kbl": 3106, - "kbm": 3107, - "kbn": 3108, - "kbo": 3109, - "kbp": 3110, - "kbq": 3111, - "kbr": 3112, - "kbs": 3113, - "kbt": 3114, - "kbu": 3115, - "kbv": 3116, - "kbw": 3117, - "kbx": 3118, - "kby": 3119, - "kbz": 3120, - "kca": 3121, - "kcb": 3122, - "kcc": 3123, - "kcd": 3124, - "kce": 3125, - "kcf": 3126, - "kcg": 3127, - "kch": 3128, - "kci": 3129, - "kcj": 3130, - "kck": 3131, - "kcl": 3132, - "kcm": 3133, - "kcn": 3134, - "kco": 3135, - "kcp": 3136, - "kcq": 3137, - "kcr": 3138, - "kcs": 3139, - "kct": 3140, - "kcu": 3141, - "kcv": 3142, - "kcw": 3143, - "kcx": 3144, - "kcy": 3145, - "kcz": 3146, - "kda": 3147, - "kdc": 3148, - "kdd": 3149, - "kde": 3150, - "kdf": 3151, - "kdg": 3152, - "kdh": 3153, - "kdi": 3154, - "kdj": 3155, - "kdk": 3156, - "kdl": 3157, - "kdm": 3158, - "kdn": 3159, - "kdo": 3160, - "kdp": 3161, - "kdq": 3162, - "kdr": 3163, - "kdt": 3164, - "kdu": 3165, - "kdv": 3166, - "kdw": 3167, - "kdx": 3168, - "kdy": 3169, - "kdz": 3170, - "kea": 3171, - "keb": 3172, - "kec": 3173, - "ked": 3174, - "kee": 3175, - "kef": 3176, - "keg": 3177, - "keh": 3178, - "kei": 3179, - "kej": 3180, - "kek": 3181, - "kel": 3182, - "kem": 3183, - "ken": 3184, - "keo": 3185, - "kep": 3186, - "keq": 3187, - "ker": 3188, - "kes": 3189, - "ket": 3190, - "keu": 3191, - "kev": 3192, - "kew": 3193, - "kex": 3194, - "key": 3195, - "kez": 3196, - "kfa": 3197, - "kfb": 3198, - "kfc": 3199, - "kfd": 3200, - "kfe": 3201, - "kff": 3202, - "kfg": 3203, - "kfh": 3204, - "kfi": 3205, - "kfj": 3206, - "kfk": 3207, - "kfl": 3208, - "kfm": 3209, - "kfn": 3210, - "kfo": 3211, - "kfp": 3212, - "kfq": 3213, - "kfr": 3214, - "kfs": 3215, - "kft": 3216, - "kfu": 3217, - "kfv": 3218, - "kfw": 3219, - "kfx": 3220, - "kfy": 3221, - "kfz": 3222, - "kga": 3223, - "kgb": 3224, - "kgc": 3225, - "kgd": 3226, - "kge": 3227, - "kgf": 3228, - "kgg": 3229, - "kgh": 3230, - "kgi": 3231, - "kgj": 3232, - "kgk": 3233, - "kgl": 3234, - "kgm": 3235, - "kgn": 3236, - "kgo": 3237, - "kgp": 3238, - "kgq": 3239, - "kgr": 3240, - "kgs": 3241, - "kgt": 3242, - "kgu": 3243, - "kgv": 3244, - "kgw": 3245, - "kgx": 3246, - "kgy": 3247, - "kha": 3248, - "khb": 3249, - "khc": 3250, - "khd": 3251, - "khe": 3252, - "khf": 3253, - "khg": 3254, - "khh": 3255, - "khi": 3256, - "khj": 3257, - "khk": 3258, - "khl": 3259, - "khn": 3260, - "kho": 3261, - "khp": 3262, - "khq": 3263, - "khr": 3264, - "khs": 3265, - "kht": 3266, - "khu": 3267, - "khv": 3268, - "khw": 3269, - "khx": 3270, - "khy": 3271, - "khz": 3272, - "kia": 3273, - "kib": 3274, - "kic": 3275, - "kid": 3276, - "kie": 3277, - "kif": 3278, - "kig": 3279, - "kih": 3280, - "kii": 3281, - "kij": 3282, - "kil": 3283, - "kim": 3284, - "kio": 3285, - "kip": 3286, - "kiq": 3287, - "kis": 3288, - "kit": 3289, - "kiu": 3290, - "kiv": 3291, - "kiw": 3292, - "kix": 3293, - "kiy": 3294, - "kiz": 3295, - "kja": 3296, - "kjb": 3297, - "kjc": 3298, - "kjd": 3299, - "kje": 3300, - "kjf": 3301, - "kjg": 3302, - "kjh": 3303, - "kji": 3304, - "kjj": 3305, - "kjk": 3306, - "kjl": 3307, - "kjm": 3308, - "kjn": 3309, - "kjo": 3310, - "kjp": 3311, - "kjq": 3312, - "kjr": 3313, - "kjs": 3314, - "kjt": 3315, - "kju": 3316, - "kjv": 3317, - "kjx": 3318, - "kjy": 3319, - "kjz": 3320, - "kka": 3321, - "kkb": 3322, - "kkc": 3323, - "kkd": 3324, - "kke": 3325, - "kkf": 3326, - "kkg": 3327, - "kkh": 3328, - "kki": 3329, - "kkj": 3330, - "kkk": 3331, - "kkl": 3332, - "kkm": 3333, - "kkn": 3334, - "kko": 3335, - "kkp": 3336, - "kkq": 3337, - "kkr": 3338, - "kks": 3339, - "kkt": 3340, - "kku": 3341, - "kkv": 3342, - "kkw": 3343, - "kkx": 3344, - "kky": 3345, - "kkz": 3346, - "kla": 3347, - "klb": 3348, - "klc": 3349, - "kld": 3350, - "kle": 3351, - "klf": 3352, - "klg": 3353, - "klh": 3354, - "kli": 3355, - "klj": 3356, - "klk": 3357, - "kll": 3358, - "klm": 3359, - "kln": 3360, - "klo": 3361, - "klp": 3362, - "klq": 3363, - "klr": 3364, - "kls": 3365, - "klt": 3366, - "klu": 3367, - "klv": 3368, - "klw": 3369, - "klx": 3370, - "kly": 3371, - "klz": 3372, - "kma": 3373, - "kmb": 3374, - "kmc": 3375, - "kmd": 3376, - "kme": 3377, - "kmf": 3378, - "kmg": 3379, - "kmh": 3380, - "kmi": 3381, - "kmj": 3382, - "kmk": 3383, - "kml": 3384, - "kmm": 3385, - "kmn": 3386, - "kmo": 3387, - "kmp": 3388, - "kmq": 3389, - "kmr": 3390, - "kms": 3391, - "kmt": 3392, - "kmu": 3393, - "kmv": 3394, - "kmw": 3395, - "kmx": 3396, - "kmy": 3397, - "kmz": 3398, - "kna": 3399, - "knb": 3400, - "knc": 3401, - "knd": 3402, - "kne": 3403, - "knf": 3404, - "kng": 3405, - "kni": 3406, - "knj": 3407, - "knk": 3408, - "knl": 3409, - "knm": 3410, - "knn": 3411, - "kno": 3412, - "knp": 3413, - "knq": 3414, - "knr": 3415, - "kns": 3416, - "knt": 3417, - "knu": 3418, - "knv": 3419, - "knw": 3420, - "knx": 3421, - "kny": 3422, - "knz": 3423, - "koa": 3424, - "koc": 3425, - "kod": 3426, - "koe": 3427, - "kof": 3428, - "kog": 3429, - "koh": 3430, - "koi": 3431, - "koj": 3432, - "kok": 3433, - "kol": 3434, - "koo": 3435, - "kop": 3436, - "koq": 3437, - "kos": 3438, - "kot": 3439, - "kou": 3440, - "kov": 3441, - "kow": 3442, - "kox": 3443, - "koy": 3444, - "koz": 3445, - "kpa": 3446, - "kpb": 3447, - "kpc": 3448, - "kpd": 3449, - "kpe": 3450, - "kpf": 3451, - "kpg": 3452, - "kph": 3453, - "kpi": 3454, - "kpj": 3455, - "kpk": 3456, - "kpl": 3457, - "kpm": 3458, - "kpn": 3459, - "kpo": 3460, - "kpp": 3461, - "kpq": 3462, - "kpr": 3463, - "kps": 3464, - "kpt": 3465, - "kpu": 3466, - "kpv": 3467, - "kpw": 3468, - "kpx": 3469, - "kpy": 3470, - "kpz": 3471, - "kqa": 3472, - "kqb": 3473, - "kqc": 3474, - "kqd": 3475, - "kqe": 3476, - "kqf": 3477, - "kqg": 3478, - "kqh": 3479, - "kqi": 3480, - "kqj": 3481, - "kqk": 3482, - "kql": 3483, - "kqm": 3484, - "kqn": 3485, - "kqo": 3486, - "kqp": 3487, - "kqq": 3488, - "kqr": 3489, - "kqs": 3490, - "kqt": 3491, - "kqu": 3492, - "kqv": 3493, - "kqw": 3494, - "kqx": 3495, - "kqy": 3496, - "kqz": 3497, - "kra": 3498, - "krb": 3499, - "krc": 3500, - "krd": 3501, - "kre": 3502, - "krf": 3503, - "krh": 3504, - "kri": 3505, - "krj": 3506, - "krk": 3507, - "krl": 3508, - "krm": 3509, - "krn": 3510, - "kro": 3511, - "krp": 3512, - "krr": 3513, - "krs": 3514, - "krt": 3515, - "kru": 3516, - "krv": 3517, - "krw": 3518, - "krx": 3519, - "kry": 3520, - "krz": 3521, - "ksa": 3522, - "ksb": 3523, - "ksc": 3524, - "ksd": 3525, - "kse": 3526, - "ksf": 3527, - "ksg": 3528, - "ksh": 3529, - "ksi": 3530, - "ksj": 3531, - "ksk": 3532, - "ksl": 3533, - "ksm": 3534, - "ksn": 3535, - "kso": 3536, - "ksp": 3537, - "ksq": 3538, - "ksr": 3539, - "kss": 3540, - "kst": 3541, - "ksu": 3542, - "ksv": 3543, - "ksw": 3544, - "ksx": 3545, - "ksy": 3546, - "ksz": 3547, - "kta": 3548, - "ktb": 3549, - "ktc": 3550, - "ktd": 3551, - "kte": 3552, - "ktf": 3553, - "ktg": 3554, - "kth": 3555, - "kti": 3556, - "ktj": 3557, - "ktk": 3558, - "ktl": 3559, - "ktm": 3560, - "ktn": 3561, - "kto": 3562, - "ktp": 3563, - "ktq": 3564, - "ktr": 3565, - "kts": 3566, - "ktt": 3567, - "ktu": 3568, - "ktv": 3569, - "ktw": 3570, - "ktx": 3571, - "kty": 3572, - "ktz": 3573, - "kub": 3574, - "kuc": 3575, - "kud": 3576, - "kue": 3577, - "kuf": 3578, - "kug": 3579, - "kuh": 3580, - "kui": 3581, - "kuj": 3582, - "kuk": 3583, - "kul": 3584, - "kum": 3585, - "kun": 3586, - "kuo": 3587, - "kup": 3588, - "kuq": 3589, - "kus": 3590, - "kut": 3591, - "kuu": 3592, - "kuv": 3593, - "kuw": 3594, - "kux": 3595, - "kuy": 3596, - "kuz": 3597, - "kva": 3598, - "kvb": 3599, - "kvc": 3600, - "kvd": 3601, - "kve": 3602, - "kvf": 3603, - "kvg": 3604, - "kvh": 3605, - "kvi": 3606, - "kvj": 3607, - "kvk": 3608, - "kvl": 3609, - "kvm": 3610, - "kvn": 3611, - "kvo": 3612, - "kvp": 3613, - "kvq": 3614, - "kvr": 3615, - "kvs": 3616, - "kvt": 3617, - "kvu": 3618, - "kvv": 3619, - "kvw": 3620, - "kvx": 3621, - "kvy": 3622, - "kvz": 3623, - "kwa": 3624, - "kwb": 3625, - "kwc": 3626, - "kwd": 3627, - "kwe": 3628, - "kwf": 3629, - "kwg": 3630, - "kwh": 3631, - "kwi": 3632, - "kwj": 3633, - "kwk": 3634, - "kwl": 3635, - "kwm": 3636, - "kwn": 3637, - "kwo": 3638, - "kwp": 3639, - "kwq": 3640, - "kwr": 3641, - "kws": 3642, - "kwt": 3643, - "kwu": 3644, - "kwv": 3645, - "kww": 3646, - "kwx": 3647, - "kwy": 3648, - "kwz": 3649, - "kxa": 3650, - "kxb": 3651, - "kxc": 3652, - "kxd": 3653, - "kxe": 3654, - "kxf": 3655, - "kxh": 3656, - "kxi": 3657, - "kxj": 3658, - "kxk": 3659, - "kxl": 3660, - "kxm": 3661, - "kxn": 3662, - "kxo": 3663, - "kxp": 3664, - "kxq": 3665, - "kxr": 3666, - "kxs": 3667, - "kxt": 3668, - "kxu": 3669, - "kxv": 3670, - "kxw": 3671, - "kxx": 3672, - "kxy": 3673, - "kxz": 3674, - "kya": 3675, - "kyb": 3676, - "kyc": 3677, - "kyd": 3678, - "kye": 3679, - "kyf": 3680, - "kyg": 3681, - "kyh": 3682, - "kyi": 3683, - "kyj": 3684, - "kyk": 3685, - "kyl": 3686, - "kym": 3687, - "kyn": 3688, - "kyo": 3689, - "kyp": 3690, - "kyq": 3691, - "kyr": 3692, - "kys": 3693, - "kyt": 3694, - "kyu": 3695, - "kyv": 3696, - "kyw": 3697, - "kyx": 3698, - "kyy": 3699, - "kyz": 3700, - "kza": 3701, - "kzb": 3702, - "kzc": 3703, - "kzd": 3704, - "kze": 3705, - "kzf": 3706, - "kzg": 3707, - "kzh": 3708, - "kzi": 3709, - "kzj": 3710, - "kzk": 3711, - "kzl": 3712, - "kzm": 3713, - "kzn": 3714, - "kzo": 3715, - "kzp": 3716, - "kzq": 3717, - "kzr": 3718, - "kzs": 3719, - "kzt": 3720, - "kzu": 3721, - "kzv": 3722, - "kzw": 3723, - "kzx": 3724, - "kzy": 3725, - "kzz": 3726, - "laa": 3727, - "lab": 3728, - "lac": 3729, - "lad": 3730, - "lae": 3731, - "laf": 3732, - "lag": 3733, - "lah": 3734, - "lai": 3735, - "laj": 3736, - "lak": 3737, - "lal": 3738, - "lam": 3739, - "lan": 3740, - "lap": 3741, - "laq": 3742, - "lar": 3743, - "las": 3744, - "lau": 3745, - "law": 3746, - "lax": 3747, - "lay": 3748, - "laz": 3749, - "lba": 3750, - "lbb": 3751, - "lbc": 3752, - "lbe": 3753, - "lbf": 3754, - "lbg": 3755, - "lbi": 3756, - "lbj": 3757, - "lbk": 3758, - "lbl": 3759, - "lbm": 3760, - "lbn": 3761, - "lbo": 3762, - "lbq": 3763, - "lbr": 3764, - "lbs": 3765, - "lbt": 3766, - "lbu": 3767, - "lbv": 3768, - "lbw": 3769, - "lbx": 3770, - "lby": 3771, - "lbz": 3772, - "lcc": 3773, - "lcd": 3774, - "lce": 3775, - "lcf": 3776, - "lch": 3777, - "lcl": 3778, - "lcm": 3779, - "lcp": 3780, - "lcq": 3781, - "lcs": 3782, - "lda": 3783, - "ldb": 3784, - "ldd": 3785, - "ldg": 3786, - "ldh": 3787, - "ldi": 3788, - "ldj": 3789, - "ldk": 3790, - "ldl": 3791, - "ldm": 3792, - "ldn": 3793, - "ldo": 3794, - "ldp": 3795, - "ldq": 3796, - "lea": 3797, - "leb": 3798, - "lec": 3799, - "led": 3800, - "lee": 3801, - "lef": 3802, - "leg": 3803, - "leh": 3804, - "lei": 3805, - "lej": 3806, - "lek": 3807, - "lel": 3808, - "lem": 3809, - "len": 3810, - "leo": 3811, - "lep": 3812, - "leq": 3813, - "ler": 3814, - "les": 3815, - "let": 3816, - "leu": 3817, - "lev": 3818, - "lew": 3819, - "lex": 3820, - "ley": 3821, - "lez": 3822, - "lfa": 3823, - "lfn": 3824, - "lga": 3825, - "lgb": 3826, - "lgg": 3827, - "lgh": 3828, - "lgi": 3829, - "lgk": 3830, - "lgl": 3831, - "lgm": 3832, - "lgn": 3833, - "lgo": 3834, - "lgq": 3835, - "lgr": 3836, - "lgt": 3837, - "lgu": 3838, - "lgz": 3839, - "lha": 3840, - "lhh": 3841, - "lhi": 3842, - "lhl": 3843, - "lhm": 3844, - "lhn": 3845, - "lhp": 3846, - "lhs": 3847, - "lht": 3848, - "lhu": 3849, - "lia": 3850, - "lib": 3851, - "lic": 3852, - "lid": 3853, - "lie": 3854, - "lif": 3855, - "lig": 3856, - "lih": 3857, - "lii": 3858, - "lij": 3859, - "lik": 3860, - "lil": 3861, - "lio": 3862, - "lip": 3863, - "liq": 3864, - "lir": 3865, - "lis": 3866, - "liu": 3867, - "liv": 3868, - "liw": 3869, - "lix": 3870, - "liy": 3871, - "liz": 3872, - "lja": 3873, - "lje": 3874, - "lji": 3875, - "ljl": 3876, - "ljp": 3877, - "ljw": 3878, - "ljx": 3879, - "lka": 3880, - "lkb": 3881, - "lkc": 3882, - "lkd": 3883, - "lke": 3884, - "lkh": 3885, - "lki": 3886, - "lkj": 3887, - "lkl": 3888, - "lkm": 3889, - "lkn": 3890, - "lko": 3891, - "lkr": 3892, - "lks": 3893, - "lkt": 3894, - "lku": 3895, - "lky": 3896, - "lla": 3897, - "llb": 3898, - "llc": 3899, - "lld": 3900, - "lle": 3901, - "llf": 3902, - "llg": 3903, - "llh": 3904, - "lli": 3905, - "llj": 3906, - "llk": 3907, - "lll": 3908, - "llm": 3909, - "lln": 3910, - "llo": 3911, - "llp": 3912, - "llq": 3913, - "lls": 3914, - "llu": 3915, - "llx": 3916, - "lma": 3917, - "lmb": 3918, - "lmc": 3919, - "lmd": 3920, - "lme": 3921, - "lmf": 3922, - "lmg": 3923, - "lmh": 3924, - "lmi": 3925, - "lmj": 3926, - "lmk": 3927, - "lml": 3928, - "lmm": 3929, - "lmn": 3930, - "lmo": 3931, - "lmp": 3932, - "lmq": 3933, - "lmr": 3934, - "lmu": 3935, - "lmv": 3936, - "lmw": 3937, - "lmx": 3938, - "lmy": 3939, - "lmz": 3940, - "lna": 3941, - "lnb": 3942, - "lnd": 3943, - "lng": 3944, - "lnh": 3945, - "lni": 3946, - "lnj": 3947, - "lnl": 3948, - "lnm": 3949, - "lnn": 3950, - "lno": 3951, - "lns": 3952, - "lnu": 3953, - "lnw": 3954, - "lnz": 3955, - "loa": 3956, - "lob": 3957, - "loc": 3958, - "loe": 3959, - "lof": 3960, - "log": 3961, - "loh": 3962, - "loi": 3963, - "loj": 3964, - "lok": 3965, - "lol": 3966, - "lom": 3967, - "lon": 3968, - "loo": 3969, - "lop": 3970, - "loq": 3971, - "lor": 3972, - "los": 3973, - "lot": 3974, - "lou": 3975, - "lov": 3976, - "low": 3977, - "lox": 3978, - "loy": 3979, - "loz": 3980, - "lpa": 3981, - "lpe": 3982, - "lpn": 3983, - "lpo": 3984, - "lpx": 3985, - "lqr": 3986, - "lra": 3987, - "lrc": 3988, - "lre": 3989, - "lrg": 3990, - "lri": 3991, - "lrk": 3992, - "lrl": 3993, - "lrm": 3994, - "lrn": 3995, - "lro": 3996, - "lrr": 3997, - "lrt": 3998, - "lrv": 3999, - "lrz": 4000, - "lsa": 4001, - "lsb": 4002, - "lsc": 4003, - "lsd": 4004, - "lse": 4005, - "lsg": 4006, - "lsh": 4007, - "lsi": 4008, - "lsl": 4009, - "lsm": 4010, - "lsn": 4011, - "lso": 4012, - "lsp": 4013, - "lsr": 4014, - "lss": 4015, - "lst": 4016, - "lsv": 4017, - "lsw": 4018, - "lsy": 4019, - "ltc": 4020, - "ltg": 4021, - "lth": 4022, - "lti": 4023, - "ltn": 4024, - "lto": 4025, - "lts": 4026, - "ltu": 4027, - "lua": 4028, - "luc": 4029, - "lud": 4030, - "lue": 4031, - "luf": 4032, - "lui": 4033, - "luj": 4034, - "luk": 4035, - "lul": 4036, - "lum": 4037, - "lun": 4038, - "luo": 4039, - "lup": 4040, - "luq": 4041, - "lur": 4042, - "lus": 4043, - "lut": 4044, - "luu": 4045, - "luv": 4046, - "luw": 4047, - "luy": 4048, - "luz": 4049, - "lva": 4050, - "lvi": 4051, - "lvk": 4052, - "lvs": 4053, - "lvu": 4054, - "lwa": 4055, - "lwe": 4056, - "lwg": 4057, - "lwh": 4058, - "lwl": 4059, - "lwm": 4060, - "lwo": 4061, - "lws": 4062, - "lwt": 4063, - "lwu": 4064, - "lww": 4065, - "lxm": 4066, - "lya": 4067, - "lyg": 4068, - "lyn": 4069, - "lzh": 4070, - "lzl": 4071, - "lzn": 4072, - "lzz": 4073, - "maa": 4074, - "mab": 4075, - "mad": 4076, - "mae": 4077, - "maf": 4078, - "mag": 4079, - "mai": 4080, - "maj": 4081, - "mak": 4082, - "mam": 4083, - "man": 4084, - "map": 4085, - "maq": 4086, - "mas": 4087, - "mat": 4088, - "mau": 4089, - "mav": 4090, - "maw": 4091, - "max": 4092, - "maz": 4093, - "mba": 4094, - "mbb": 4095, - "mbc": 4096, - "mbd": 4097, - "mbe": 4098, - "mbf": 4099, - "mbh": 4100, - "mbi": 4101, - "mbj": 4102, - "mbk": 4103, - "mbl": 4104, - "mbm": 4105, - "mbn": 4106, - "mbo": 4107, - "mbp": 4108, - "mbq": 4109, - "mbr": 4110, - "mbs": 4111, - "mbt": 4112, - "mbu": 4113, - "mbv": 4114, - "mbw": 4115, - "mbx": 4116, - "mby": 4117, - "mbz": 4118, - "mca": 4119, - "mcb": 4120, - "mcc": 4121, - "mcd": 4122, - "mce": 4123, - "mcf": 4124, - "mcg": 4125, - "mch": 4126, - "mci": 4127, - "mcj": 4128, - "mck": 4129, - "mcl": 4130, - "mcm": 4131, - "mcn": 4132, - "mco": 4133, - "mcp": 4134, - "mcq": 4135, - "mcr": 4136, - "mcs": 4137, - "mct": 4138, - "mcu": 4139, - "mcv": 4140, - "mcw": 4141, - "mcx": 4142, - "mcy": 4143, - "mcz": 4144, - "mda": 4145, - "mdb": 4146, - "mdc": 4147, - "mdd": 4148, - "mde": 4149, - "mdf": 4150, - "mdg": 4151, - "mdh": 4152, - "mdi": 4153, - "mdj": 4154, - "mdk": 4155, - "mdl": 4156, - "mdm": 4157, - "mdn": 4158, - "mdp": 4159, - "mdq": 4160, - "mdr": 4161, - "mds": 4162, - "mdt": 4163, - "mdu": 4164, - "mdv": 4165, - "mdw": 4166, - "mdx": 4167, - "mdy": 4168, - "mdz": 4169, - "mea": 4170, - "meb": 4171, - "mec": 4172, - "med": 4173, - "mee": 4174, - "mef": 4175, - "meg": 4176, - "meh": 4177, - "mei": 4178, - "mej": 4179, - "mek": 4180, - "mel": 4181, - "mem": 4182, - "men": 4183, - "meo": 4184, - "mep": 4185, - "meq": 4186, - "mer": 4187, - "mes": 4188, - "met": 4189, - "meu": 4190, - "mev": 4191, - "mew": 4192, - "mey": 4193, - "mez": 4194, - "mfa": 4195, - "mfb": 4196, - "mfc": 4197, - "mfd": 4198, - "mfe": 4199, - "mff": 4200, - "mfg": 4201, - "mfh": 4202, - "mfi": 4203, - "mfj": 4204, - "mfk": 4205, - "mfl": 4206, - "mfm": 4207, - "mfn": 4208, - "mfo": 4209, - "mfp": 4210, - "mfq": 4211, - "mfr": 4212, - "mfs": 4213, - "mft": 4214, - "mfu": 4215, - "mfv": 4216, - "mfw": 4217, - "mfx": 4218, - "mfy": 4219, - "mfz": 4220, - "mga": 4221, - "mgb": 4222, - "mgc": 4223, - "mgd": 4224, - "mge": 4225, - "mgf": 4226, - "mgg": 4227, - "mgh": 4228, - "mgi": 4229, - "mgj": 4230, - "mgk": 4231, - "mgl": 4232, - "mgm": 4233, - "mgn": 4234, - "mgo": 4235, - "mgp": 4236, - "mgq": 4237, - "mgr": 4238, - "mgs": 4239, - "mgt": 4240, - "mgu": 4241, - "mgv": 4242, - "mgw": 4243, - "mgx": 4244, - "mgy": 4245, - "mgz": 4246, - "mha": 4247, - "mhb": 4248, - "mhc": 4249, - "mhd": 4250, - "mhe": 4251, - "mhf": 4252, - "mhg": 4253, - "mhh": 4254, - "mhi": 4255, - "mhj": 4256, - "mhk": 4257, - "mhl": 4258, - "mhm": 4259, - "mhn": 4260, - "mho": 4261, - "mhp": 4262, - "mhq": 4263, - "mhr": 4264, - "mhs": 4265, - "mht": 4266, - "mhu": 4267, - "mhw": 4268, - "mhx": 4269, - "mhy": 4270, - "mhz": 4271, - "mia": 4272, - "mib": 4273, - "mic": 4274, - "mid": 4275, - "mie": 4276, - "mif": 4277, - "mig": 4278, - "mih": 4279, - "mii": 4280, - "mij": 4281, - "mik": 4282, - "mil": 4283, - "mim": 4284, - "min": 4285, - "mio": 4286, - "mip": 4287, - "miq": 4288, - "mir": 4289, - "mis": 4290, - "mit": 4291, - "miu": 4292, - "miw": 4293, - "mix": 4294, - "miy": 4295, - "miz": 4296, - "mja": 4297, - "mjb": 4298, - "mjc": 4299, - "mjd": 4300, - "mje": 4301, - "mjg": 4302, - "mjh": 4303, - "mji": 4304, - "mjj": 4305, - "mjk": 4306, - "mjl": 4307, - "mjm": 4308, - "mjn": 4309, - "mjo": 4310, - "mjp": 4311, - "mjq": 4312, - "mjr": 4313, - "mjs": 4314, - "mjt": 4315, - "mju": 4316, - "mjv": 4317, - "mjw": 4318, - "mjx": 4319, - "mjy": 4320, - "mjz": 4321, - "mka": 4322, - "mkb": 4323, - "mkc": 4324, - "mke": 4325, - "mkf": 4326, - "mkg": 4327, - "mkh": 4328, - "mki": 4329, - "mkj": 4330, - "mkk": 4331, - "mkl": 4332, - "mkm": 4333, - "mkn": 4334, - "mko": 4335, - "mkp": 4336, - "mkq": 4337, - "mkr": 4338, - "mks": 4339, - "mkt": 4340, - "mku": 4341, - "mkv": 4342, - "mkw": 4343, - "mkx": 4344, - "mky": 4345, - "mkz": 4346, - "mla": 4347, - "mlb": 4348, - "mlc": 4349, - "mld": 4350, - "mle": 4351, - "mlf": 4352, - "mlh": 4353, - "mli": 4354, - "mlj": 4355, - "mlk": 4356, - "mll": 4357, - "mlm": 4358, - "mln": 4359, - "mlo": 4360, - "mlp": 4361, - "mlq": 4362, - "mlr": 4363, - "mls": 4364, - "mlu": 4365, - "mlv": 4366, - "mlw": 4367, - "mlx": 4368, - "mlz": 4369, - "mma": 4370, - "mmb": 4371, - "mmc": 4372, - "mmd": 4373, - "mme": 4374, - "mmf": 4375, - "mmg": 4376, - "mmh": 4377, - "mmi": 4378, - "mmj": 4379, - "mmk": 4380, - "mml": 4381, - "mmm": 4382, - "mmn": 4383, - "mmo": 4384, - "mmp": 4385, - "mmq": 4386, - "mmr": 4387, - "mmt": 4388, - "mmu": 4389, - "mmv": 4390, - "mmw": 4391, - "mmx": 4392, - "mmy": 4393, - "mmz": 4394, - "mna": 4395, - "mnb": 4396, - "mnc": 4397, - "mnd": 4398, - "mne": 4399, - "mnf": 4400, - "mng": 4401, - "mnh": 4402, - "mni": 4403, - "mnj": 4404, - "mnk": 4405, - "mnl": 4406, - "mnm": 4407, - "mnn": 4408, - "mno": 4409, - "mnp": 4410, - "mnq": 4411, - "mnr": 4412, - "mns": 4413, - "mnt": 4414, - "mnu": 4415, - "mnv": 4416, - "mnw": 4417, - "mnx": 4418, - "mny": 4419, - "mnz": 4420, - "moa": 4421, - "moc": 4422, - "mod": 4423, - "moe": 4424, - "mof": 4425, - "mog": 4426, - "moh": 4427, - "moi": 4428, - "moj": 4429, - "mok": 4430, - "mom": 4431, - "moo": 4432, - "mop": 4433, - "moq": 4434, - "mor": 4435, - "mos": 4436, - "mot": 4437, - "mou": 4438, - "mov": 4439, - "mow": 4440, - "mox": 4441, - "moy": 4442, - "moz": 4443, - "mpa": 4444, - "mpb": 4445, - "mpc": 4446, - "mpd": 4447, - "mpe": 4448, - "mpg": 4449, - "mph": 4450, - "mpi": 4451, - "mpj": 4452, - "mpk": 4453, - "mpl": 4454, - "mpm": 4455, - "mpn": 4456, - "mpo": 4457, - "mpp": 4458, - "mpq": 4459, - "mpr": 4460, - "mps": 4461, - "mpt": 4462, - "mpu": 4463, - "mpv": 4464, - "mpw": 4465, - "mpx": 4466, - "mpy": 4467, - "mpz": 4468, - "mqa": 4469, - "mqb": 4470, - "mqc": 4471, - "mqe": 4472, - "mqf": 4473, - "mqg": 4474, - "mqh": 4475, - "mqi": 4476, - "mqj": 4477, - "mqk": 4478, - "mql": 4479, - "mqm": 4480, - "mqn": 4481, - "mqo": 4482, - "mqp": 4483, - "mqq": 4484, - "mqr": 4485, - "mqs": 4486, - "mqt": 4487, - "mqu": 4488, - "mqv": 4489, - "mqw": 4490, - "mqx": 4491, - "mqy": 4492, - "mqz": 4493, - "mra": 4494, - "mrb": 4495, - "mrc": 4496, - "mrd": 4497, - "mre": 4498, - "mrf": 4499, - "mrg": 4500, - "mrh": 4501, - "mrj": 4502, - "mrk": 4503, - "mrl": 4504, - "mrm": 4505, - "mrn": 4506, - "mro": 4507, - "mrp": 4508, - "mrq": 4509, - "mrr": 4510, - "mrs": 4511, - "mrt": 4512, - "mru": 4513, - "mrv": 4514, - "mrw": 4515, - "mrx": 4516, - "mry": 4517, - "mrz": 4518, - "msb": 4519, - "msc": 4520, - "msd": 4521, - "mse": 4522, - "msf": 4523, - "msg": 4524, - "msh": 4525, - "msi": 4526, - "msj": 4527, - "msk": 4528, - "msl": 4529, - "msm": 4530, - "msn": 4531, - "mso": 4532, - "msp": 4533, - "msq": 4534, - "msr": 4535, - "mss": 4536, - "mst": 4537, - "msu": 4538, - "msv": 4539, - "msw": 4540, - "msx": 4541, - "msy": 4542, - "msz": 4543, - "mta": 4544, - "mtb": 4545, - "mtc": 4546, - "mtd": 4547, - "mte": 4548, - "mtf": 4549, - "mtg": 4550, - "mth": 4551, - "mti": 4552, - "mtj": 4553, - "mtk": 4554, - "mtl": 4555, - "mtm": 4556, - "mtn": 4557, - "mto": 4558, - "mtp": 4559, - "mtq": 4560, - "mtr": 4561, - "mts": 4562, - "mtt": 4563, - "mtu": 4564, - "mtv": 4565, - "mtw": 4566, - "mtx": 4567, - "mty": 4568, - "mua": 4569, - "mub": 4570, - "muc": 4571, - "mud": 4572, - "mue": 4573, - "mug": 4574, - "muh": 4575, - "mui": 4576, - "muj": 4577, - "muk": 4578, - "mul": 4579, - "mum": 4580, - "mun": 4581, - "muo": 4582, - "mup": 4583, - "muq": 4584, - "mur": 4585, - "mus": 4586, - "mut": 4587, - "muu": 4588, - "muv": 4589, - "mux": 4590, - "muy": 4591, - "muz": 4592, - "mva": 4593, - "mvb": 4594, - "mvd": 4595, - "mve": 4596, - "mvf": 4597, - "mvg": 4598, - "mvh": 4599, - "mvi": 4600, - "mvk": 4601, - "mvl": 4602, - "mvm": 4603, - "mvn": 4604, - "mvo": 4605, - "mvp": 4606, - "mvq": 4607, - "mvr": 4608, - "mvs": 4609, - "mvt": 4610, - "mvu": 4611, - "mvv": 4612, - "mvw": 4613, - "mvx": 4614, - "mvy": 4615, - "mvz": 4616, - "mwa": 4617, - "mwb": 4618, - "mwc": 4619, - "mwd": 4620, - "mwe": 4621, - "mwf": 4622, - "mwg": 4623, - "mwh": 4624, - "mwi": 4625, - "mwj": 4626, - "mwk": 4627, - "mwl": 4628, - "mwm": 4629, - "mwn": 4630, - "mwo": 4631, - "mwp": 4632, - "mwq": 4633, - "mwr": 4634, - "mws": 4635, - "mwt": 4636, - "mwu": 4637, - "mwv": 4638, - "mww": 4639, - "mwx": 4640, - "mwy": 4641, - "mwz": 4642, - "mxa": 4643, - "mxb": 4644, - "mxc": 4645, - "mxd": 4646, - "mxe": 4647, - "mxf": 4648, - "mxg": 4649, - "mxh": 4650, - "mxi": 4651, - "mxj": 4652, - "mxk": 4653, - "mxl": 4654, - "mxm": 4655, - "mxn": 4656, - "mxo": 4657, - "mxp": 4658, - "mxq": 4659, - "mxr": 4660, - "mxs": 4661, - "mxt": 4662, - "mxu": 4663, - "mxv": 4664, - "mxw": 4665, - "mxx": 4666, - "mxy": 4667, - "mxz": 4668, - "myb": 4669, - "myc": 4670, - "myd": 4671, - "mye": 4672, - "myf": 4673, - "myg": 4674, - "myh": 4675, - "myi": 4676, - "myj": 4677, - "myk": 4678, - "myl": 4679, - "mym": 4680, - "myn": 4681, - "myo": 4682, - "myp": 4683, - "myq": 4684, - "myr": 4685, - "mys": 4686, - "myt": 4687, - "myu": 4688, - "myv": 4689, - "myw": 4690, - "myx": 4691, - "myy": 4692, - "myz": 4693, - "mza": 4694, - "mzb": 4695, - "mzc": 4696, - "mzd": 4697, - "mze": 4698, - "mzg": 4699, - "mzh": 4700, - "mzi": 4701, - "mzj": 4702, - "mzk": 4703, - "mzl": 4704, - "mzm": 4705, - "mzn": 4706, - "mzo": 4707, - "mzp": 4708, - "mzq": 4709, - "mzr": 4710, - "mzs": 4711, - "mzt": 4712, - "mzu": 4713, - "mzv": 4714, - "mzw": 4715, - "mzx": 4716, - "mzy": 4717, - "mzz": 4718, - "naa": 4719, - "nab": 4720, - "nac": 4721, - "nad": 4722, - "nae": 4723, - "naf": 4724, - "nag": 4725, - "nah": 4726, - "nai": 4727, - "naj": 4728, - "nak": 4729, - "nal": 4730, - "nam": 4731, - "nan": 4732, - "nao": 4733, - "nap": 4734, - "naq": 4735, - "nar": 4736, - "nas": 4737, - "nat": 4738, - "naw": 4739, - "nax": 4740, - "nay": 4741, - "naz": 4742, - "nba": 4743, - "nbb": 4744, - "nbc": 4745, - "nbd": 4746, - "nbe": 4747, - "nbf": 4748, - "nbg": 4749, - "nbh": 4750, - "nbi": 4751, - "nbj": 4752, - "nbk": 4753, - "nbm": 4754, - "nbn": 4755, - "nbo": 4756, - "nbp": 4757, - "nbq": 4758, - "nbr": 4759, - "nbs": 4760, - "nbt": 4761, - "nbu": 4762, - "nbv": 4763, - "nbw": 4764, - "nbx": 4765, - "nby": 4766, - "nca": 4767, - "ncb": 4768, - "ncc": 4769, - "ncd": 4770, - "nce": 4771, - "ncf": 4772, - "ncg": 4773, - "nch": 4774, - "nci": 4775, - "ncj": 4776, - "nck": 4777, - "ncl": 4778, - "ncm": 4779, - "ncn": 4780, - "nco": 4781, - "ncp": 4782, - "ncq": 4783, - "ncr": 4784, - "ncs": 4785, - "nct": 4786, - "ncu": 4787, - "ncx": 4788, - "ncz": 4789, - "nda": 4790, - "ndb": 4791, - "ndc": 4792, - "ndd": 4793, - "ndf": 4794, - "ndg": 4795, - "ndh": 4796, - "ndi": 4797, - "ndj": 4798, - "ndk": 4799, - "ndl": 4800, - "ndm": 4801, - "ndn": 4802, - "ndp": 4803, - "ndq": 4804, - "ndr": 4805, - "nds": 4806, - "ndt": 4807, - "ndu": 4808, - "ndv": 4809, - "ndw": 4810, - "ndx": 4811, - "ndy": 4812, - "ndz": 4813, - "nea": 4814, - "neb": 4815, - "nec": 4816, - "ned": 4817, - "nee": 4818, - "nef": 4819, - "neg": 4820, - "neh": 4821, - "nei": 4822, - "nej": 4823, - "nek": 4824, - "nem": 4825, - "nen": 4826, - "neo": 4827, - "neq": 4828, - "ner": 4829, - "nes": 4830, - "net": 4831, - "neu": 4832, - "nev": 4833, - "new": 4834, - "nex": 4835, - "ney": 4836, - "nez": 4837, - "nfa": 4838, - "nfd": 4839, - "nfl": 4840, - "nfr": 4841, - "nfu": 4842, - "nga": 4843, - "ngb": 4844, - "ngc": 4845, - "ngd": 4846, - "nge": 4847, - "ngf": 4848, - "ngg": 4849, - "ngh": 4850, - "ngi": 4851, - "ngj": 4852, - "ngk": 4853, - "ngl": 4854, - "ngm": 4855, - "ngn": 4856, - "ngo": 4857, - "ngp": 4858, - "ngq": 4859, - "ngr": 4860, - "ngs": 4861, - "ngt": 4862, - "ngu": 4863, - "ngv": 4864, - "ngw": 4865, - "ngx": 4866, - "ngy": 4867, - "ngz": 4868, - "nha": 4869, - "nhb": 4870, - "nhc": 4871, - "nhd": 4872, - "nhe": 4873, - "nhf": 4874, - "nhg": 4875, - "nhh": 4876, - "nhi": 4877, - "nhk": 4878, - "nhm": 4879, - "nhn": 4880, - "nho": 4881, - "nhp": 4882, - "nhq": 4883, - "nhr": 4884, - "nht": 4885, - "nhu": 4886, - "nhv": 4887, - "nhw": 4888, - "nhx": 4889, - "nhy": 4890, - "nhz": 4891, - "nia": 4892, - "nib": 4893, - "nic": 4894, - "nid": 4895, - "nie": 4896, - "nif": 4897, - "nig": 4898, - "nih": 4899, - "nii": 4900, - "nij": 4901, - "nik": 4902, - "nil": 4903, - "nim": 4904, - "nin": 4905, - "nio": 4906, - "niq": 4907, - "nir": 4908, - "nis": 4909, - "nit": 4910, - "niu": 4911, - "niv": 4912, - "niw": 4913, - "nix": 4914, - "niy": 4915, - "niz": 4916, - "nja": 4917, - "njb": 4918, - "njd": 4919, - "njh": 4920, - "nji": 4921, - "njj": 4922, - "njl": 4923, - "njm": 4924, - "njn": 4925, - "njo": 4926, - "njr": 4927, - "njs": 4928, - "njt": 4929, - "nju": 4930, - "njx": 4931, - "njy": 4932, - "njz": 4933, - "nka": 4934, - "nkb": 4935, - "nkc": 4936, - "nkd": 4937, - "nke": 4938, - "nkf": 4939, - "nkg": 4940, - "nkh": 4941, - "nki": 4942, - "nkj": 4943, - "nkk": 4944, - "nkm": 4945, - "nkn": 4946, - "nko": 4947, - "nkp": 4948, - "nkq": 4949, - "nkr": 4950, - "nks": 4951, - "nkt": 4952, - "nku": 4953, - "nkv": 4954, - "nkw": 4955, - "nkx": 4956, - "nkz": 4957, - "nla": 4958, - "nlc": 4959, - "nle": 4960, - "nlg": 4961, - "nli": 4962, - "nlj": 4963, - "nlk": 4964, - "nll": 4965, - "nlm": 4966, - "nln": 4967, - "nlo": 4968, - "nlq": 4969, - "nlr": 4970, - "nlu": 4971, - "nlv": 4972, - "nlw": 4973, - "nlx": 4974, - "nly": 4975, - "nlz": 4976, - "nma": 4977, - "nmb": 4978, - "nmc": 4979, - "nmd": 4980, - "nme": 4981, - "nmf": 4982, - "nmg": 4983, - "nmh": 4984, - "nmi": 4985, - "nmj": 4986, - "nmk": 4987, - "nml": 4988, - "nmm": 4989, - "nmn": 4990, - "nmo": 4991, - "nmp": 4992, - "nmq": 4993, - "nmr": 4994, - "nms": 4995, - "nmt": 4996, - "nmu": 4997, - "nmv": 4998, - "nmw": 4999, - "nmx": 5000, - "nmy": 5001, - "nmz": 5002, - "nna": 5003, - "nnb": 5004, - "nnc": 5005, - "nnd": 5006, - "nne": 5007, - "nnf": 5008, - "nng": 5009, - "nnh": 5010, - "nni": 5011, - "nnj": 5012, - "nnk": 5013, - "nnl": 5014, - "nnm": 5015, - "nnn": 5016, - "nnp": 5017, - "nnq": 5018, - "nnr": 5019, - "nns": 5020, - "nnt": 5021, - "nnu": 5022, - "nnv": 5023, - "nnw": 5024, - "nnx": 5025, - "nny": 5026, - "nnz": 5027, - "noa": 5028, - "noc": 5029, - "nod": 5030, - "noe": 5031, - "nof": 5032, - "nog": 5033, - "noh": 5034, - "noi": 5035, - "noj": 5036, - "nok": 5037, - "nol": 5038, - "nom": 5039, - "non": 5040, - "noo": 5041, - "nop": 5042, - "noq": 5043, - "nos": 5044, - "not": 5045, - "nou": 5046, - "nov": 5047, - "now": 5048, - "noy": 5049, - "noz": 5050, - "npa": 5051, - "npb": 5052, - "npg": 5053, - "nph": 5054, - "npi": 5055, - "npl": 5056, - "npn": 5057, - "npo": 5058, - "nps": 5059, - "npu": 5060, - "npx": 5061, - "npy": 5062, - "nqg": 5063, - "nqk": 5064, - "nql": 5065, - "nqm": 5066, - "nqn": 5067, - "nqo": 5068, - "nqq": 5069, - "nqt": 5070, - "nqy": 5071, - "nra": 5072, - "nrb": 5073, - "nrc": 5074, - "nre": 5075, - "nrf": 5076, - "nrg": 5077, - "nri": 5078, - "nrk": 5079, - "nrl": 5080, - "nrm": 5081, - "nrn": 5082, - "nrp": 5083, - "nrr": 5084, - "nrt": 5085, - "nru": 5086, - "nrx": 5087, - "nrz": 5088, - "nsa": 5089, - "nsb": 5090, - "nsc": 5091, - "nsd": 5092, - "nse": 5093, - "nsf": 5094, - "nsg": 5095, - "nsh": 5096, - "nsi": 5097, - "nsk": 5098, - "nsl": 5099, - "nsm": 5100, - "nsn": 5101, - "nso": 5102, - "nsp": 5103, - "nsq": 5104, - "nsr": 5105, - "nss": 5106, - "nst": 5107, - "nsu": 5108, - "nsv": 5109, - "nsw": 5110, - "nsx": 5111, - "nsy": 5112, - "nsz": 5113, - "ntd": 5114, - "nte": 5115, - "ntg": 5116, - "nti": 5117, - "ntj": 5118, - "ntk": 5119, - "ntm": 5120, - "nto": 5121, - "ntp": 5122, - "ntr": 5123, - "nts": 5124, - "ntu": 5125, - "ntw": 5126, - "ntx": 5127, - "nty": 5128, - "ntz": 5129, - "nua": 5130, - "nub": 5131, - "nuc": 5132, - "nud": 5133, - "nue": 5134, - "nuf": 5135, - "nug": 5136, - "nuh": 5137, - "nui": 5138, - "nuj": 5139, - "nuk": 5140, - "nul": 5141, - "num": 5142, - "nun": 5143, - "nuo": 5144, - "nup": 5145, - "nuq": 5146, - "nur": 5147, - "nus": 5148, - "nut": 5149, - "nuu": 5150, - "nuv": 5151, - "nuw": 5152, - "nux": 5153, - "nuy": 5154, - "nuz": 5155, - "nvh": 5156, - "nvm": 5157, - "nvo": 5158, - "nwa": 5159, - "nwb": 5160, - "nwc": 5161, - "nwe": 5162, - "nwg": 5163, - "nwi": 5164, - "nwm": 5165, - "nwo": 5166, - "nwr": 5167, - "nww": 5168, - "nwx": 5169, - "nwy": 5170, - "nxa": 5171, - "nxd": 5172, - "nxe": 5173, - "nxg": 5174, - "nxi": 5175, - "nxk": 5176, - "nxl": 5177, - "nxm": 5178, - "nxn": 5179, - "nxo": 5180, - "nxq": 5181, - "nxr": 5182, - "nxu": 5183, - "nxx": 5184, - "nyb": 5185, - "nyc": 5186, - "nyd": 5187, - "nye": 5188, - "nyf": 5189, - "nyg": 5190, - "nyh": 5191, - "nyi": 5192, - "nyj": 5193, - "nyk": 5194, - "nyl": 5195, - "nym": 5196, - "nyn": 5197, - "nyo": 5198, - "nyp": 5199, - "nyq": 5200, - "nyr": 5201, - "nys": 5202, - "nyt": 5203, - "nyu": 5204, - "nyv": 5205, - "nyw": 5206, - "nyx": 5207, - "nyy": 5208, - "nza": 5209, - "nzb": 5210, - "nzd": 5211, - "nzi": 5212, - "nzk": 5213, - "nzm": 5214, - "nzs": 5215, - "nzu": 5216, - "nzy": 5217, - "nzz": 5218, - "oaa": 5219, - "oac": 5220, - "oar": 5221, - "oav": 5222, - "obi": 5223, - "obk": 5224, - "obl": 5225, - "obm": 5226, - "obo": 5227, - "obr": 5228, - "obt": 5229, - "obu": 5230, - "oca": 5231, - "och": 5232, - "ocm": 5233, - "oco": 5234, - "ocu": 5235, - "oda": 5236, - "odk": 5237, - "odt": 5238, - "odu": 5239, - "ofo": 5240, - "ofs": 5241, - "ofu": 5242, - "ogb": 5243, - "ogc": 5244, - "oge": 5245, - "ogg": 5246, - "ogo": 5247, - "ogu": 5248, - "oht": 5249, - "ohu": 5250, - "oia": 5251, - "oie": 5252, - "oin": 5253, - "ojb": 5254, - "ojc": 5255, - "ojg": 5256, - "ojp": 5257, - "ojs": 5258, - "ojv": 5259, - "ojw": 5260, - "oka": 5261, - "okb": 5262, - "okc": 5263, - "okd": 5264, - "oke": 5265, - "okg": 5266, - "okh": 5267, - "oki": 5268, - "okj": 5269, - "okk": 5270, - "okl": 5271, - "okm": 5272, - "okn": 5273, - "oko": 5274, - "okr": 5275, - "oks": 5276, - "oku": 5277, - "okv": 5278, - "okx": 5279, - "okz": 5280, - "ola": 5281, - "old": 5282, - "ole": 5283, - "olk": 5284, - "olm": 5285, - "olo": 5286, - "olr": 5287, - "olt": 5288, - "olu": 5289, - "oma": 5290, - "omb": 5291, - "omc": 5292, - "ome": 5293, - "omg": 5294, - "omi": 5295, - "omk": 5296, - "oml": 5297, - "omn": 5298, - "omo": 5299, - "omp": 5300, - "omq": 5301, - "omr": 5302, - "omt": 5303, - "omu": 5304, - "omv": 5305, - "omw": 5306, - "omx": 5307, - "omy": 5308, - "ona": 5309, - "onb": 5310, - "one": 5311, - "ong": 5312, - "oni": 5313, - "onj": 5314, - "onk": 5315, - "onn": 5316, - "ono": 5317, - "onp": 5318, - "onr": 5319, - "ons": 5320, - "ont": 5321, - "onu": 5322, - "onw": 5323, - "onx": 5324, - "ood": 5325, - "oog": 5326, - "oon": 5327, - "oor": 5328, - "oos": 5329, - "opa": 5330, - "opk": 5331, - "opm": 5332, - "opo": 5333, - "opt": 5334, - "opy": 5335, - "ora": 5336, - "orc": 5337, - "ore": 5338, - "org": 5339, - "orh": 5340, - "orn": 5341, - "oro": 5342, - "orr": 5343, - "ors": 5344, - "ort": 5345, - "oru": 5346, - "orv": 5347, - "orw": 5348, - "orx": 5349, - "ory": 5350, - "orz": 5351, - "osa": 5352, - "osc": 5353, - "osi": 5354, - "osn": 5355, - "oso": 5356, - "osp": 5357, - "ost": 5358, - "osu": 5359, - "osx": 5360, - "ota": 5361, - "otb": 5362, - "otd": 5363, - "ote": 5364, - "oti": 5365, - "otk": 5366, - "otl": 5367, - "otm": 5368, - "otn": 5369, - "oto": 5370, - "otq": 5371, - "otr": 5372, - "ots": 5373, - "ott": 5374, - "otu": 5375, - "otw": 5376, - "otx": 5377, - "oty": 5378, - "otz": 5379, - "oua": 5380, - "oub": 5381, - "oue": 5382, - "oui": 5383, - "oum": 5384, - "oun": 5385, - "ovd": 5386, - "owi": 5387, - "owl": 5388, - "oyb": 5389, - "oyd": 5390, - "oym": 5391, - "oyy": 5392, - "ozm": 5393, - "paa": 5394, - "pab": 5395, - "pac": 5396, - "pad": 5397, - "pae": 5398, - "paf": 5399, - "pag": 5400, - "pah": 5401, - "pai": 5402, - "pak": 5403, - "pal": 5404, - "pam": 5405, - "pao": 5406, - "pap": 5407, - "paq": 5408, - "par": 5409, - "pas": 5410, - "pat": 5411, - "pau": 5412, - "pav": 5413, - "paw": 5414, - "pax": 5415, - "pay": 5416, - "paz": 5417, - "pbb": 5418, - "pbc": 5419, - "pbe": 5420, - "pbf": 5421, - "pbg": 5422, - "pbh": 5423, - "pbi": 5424, - "pbl": 5425, - "pbm": 5426, - "pbn": 5427, - "pbo": 5428, - "pbp": 5429, - "pbr": 5430, - "pbs": 5431, - "pbt": 5432, - "pbu": 5433, - "pbv": 5434, - "pby": 5435, - "pbz": 5436, - "pca": 5437, - "pcb": 5438, - "pcc": 5439, - "pcd": 5440, - "pce": 5441, - "pcf": 5442, - "pcg": 5443, - "pch": 5444, - "pci": 5445, - "pcj": 5446, - "pck": 5447, - "pcl": 5448, - "pcm": 5449, - "pcn": 5450, - "pcp": 5451, - "pcr": 5452, - "pcw": 5453, - "pda": 5454, - "pdc": 5455, - "pdi": 5456, - "pdn": 5457, - "pdo": 5458, - "pdt": 5459, - "pdu": 5460, - "pea": 5461, - "peb": 5462, - "ped": 5463, - "pee": 5464, - "pef": 5465, - "peg": 5466, - "peh": 5467, - "pei": 5468, - "pej": 5469, - "pek": 5470, - "pel": 5471, - "pem": 5472, - "peo": 5473, - "pep": 5474, - "peq": 5475, - "pes": 5476, - "pev": 5477, - "pex": 5478, - "pey": 5479, - "pez": 5480, - "pfa": 5481, - "pfe": 5482, - "pfl": 5483, - "pga": 5484, - "pgd": 5485, - "pgg": 5486, - "pgi": 5487, - "pgk": 5488, - "pgl": 5489, - "pgn": 5490, - "pgs": 5491, - "pgu": 5492, - "pgy": 5493, - "pgz": 5494, - "pha": 5495, - "phd": 5496, - "phg": 5497, - "phh": 5498, - "phi": 5499, - "phj": 5500, - "phk": 5501, - "phl": 5502, - "phm": 5503, - "phn": 5504, - "pho": 5505, - "phq": 5506, - "phr": 5507, - "pht": 5508, - "phu": 5509, - "phv": 5510, - "phw": 5511, - "pia": 5512, - "pib": 5513, - "pic": 5514, - "pid": 5515, - "pie": 5516, - "pif": 5517, - "pig": 5518, - "pih": 5519, - "pii": 5520, - "pij": 5521, - "pil": 5522, - "pim": 5523, - "pin": 5524, - "pio": 5525, - "pip": 5526, - "pir": 5527, - "pis": 5528, - "pit": 5529, - "piu": 5530, - "piv": 5531, - "piw": 5532, - "pix": 5533, - "piy": 5534, - "piz": 5535, - "pjt": 5536, - "pka": 5537, - "pkb": 5538, - "pkc": 5539, - "pkg": 5540, - "pkh": 5541, - "pkn": 5542, - "pko": 5543, - "pkp": 5544, - "pkr": 5545, - "pks": 5546, - "pkt": 5547, - "pku": 5548, - "pla": 5549, - "plb": 5550, - "plc": 5551, - "pld": 5552, - "ple": 5553, - "plf": 5554, - "plg": 5555, - "plh": 5556, - "plj": 5557, - "plk": 5558, - "pll": 5559, - "pln": 5560, - "plo": 5561, - "plp": 5562, - "plq": 5563, - "plr": 5564, - "pls": 5565, - "plt": 5566, - "plu": 5567, - "plv": 5568, - "plw": 5569, - "ply": 5570, - "plz": 5571, - "pma": 5572, - "pmb": 5573, - "pmc": 5574, - "pmd": 5575, - "pme": 5576, - "pmf": 5577, - "pmh": 5578, - "pmi": 5579, - "pmj": 5580, - "pmk": 5581, - "pml": 5582, - "pmm": 5583, - "pmn": 5584, - "pmo": 5585, - "pmq": 5586, - "pmr": 5587, - "pms": 5588, - "pmt": 5589, - "pmu": 5590, - "pmw": 5591, - "pmx": 5592, - "pmy": 5593, - "pmz": 5594, - "pna": 5595, - "pnb": 5596, - "pnc": 5597, - "pnd": 5598, - "pne": 5599, - "png": 5600, - "pnh": 5601, - "pni": 5602, - "pnj": 5603, - "pnk": 5604, - "pnl": 5605, - "pnm": 5606, - "pnn": 5607, - "pno": 5608, - "pnp": 5609, - "pnq": 5610, - "pnr": 5611, - "pns": 5612, - "pnt": 5613, - "pnu": 5614, - "pnv": 5615, - "pnw": 5616, - "pnx": 5617, - "pny": 5618, - "pnz": 5619, - "poc": 5620, - "pod": 5621, - "poe": 5622, - "pof": 5623, - "pog": 5624, - "poh": 5625, - "poi": 5626, - "pok": 5627, - "pom": 5628, - "pon": 5629, - "poo": 5630, - "pop": 5631, - "poq": 5632, - "pos": 5633, - "pot": 5634, - "pov": 5635, - "pow": 5636, - "pox": 5637, - "poy": 5638, - "poz": 5639, - "ppa": 5640, - "ppe": 5641, - "ppi": 5642, - "ppk": 5643, - "ppl": 5644, - "ppm": 5645, - "ppn": 5646, - "ppo": 5647, - "ppp": 5648, - "ppq": 5649, - "ppr": 5650, - "pps": 5651, - "ppt": 5652, - "ppu": 5653, - "pqa": 5654, - "pqe": 5655, - "pqm": 5656, - "pqw": 5657, - "pra": 5658, - "prb": 5659, - "prc": 5660, - "prd": 5661, - "pre": 5662, - "prf": 5663, - "prg": 5664, - "prh": 5665, - "pri": 5666, - "prk": 5667, - "prl": 5668, - "prm": 5669, - "prn": 5670, - "pro": 5671, - "prp": 5672, - "prq": 5673, - "prr": 5674, - "prs": 5675, - "prt": 5676, - "pru": 5677, - "prw": 5678, - "prx": 5679, - "pry": 5680, - "prz": 5681, - "psa": 5682, - "psc": 5683, - "psd": 5684, - "pse": 5685, - "psg": 5686, - "psh": 5687, - "psi": 5688, - "psl": 5689, - "psm": 5690, - "psn": 5691, - "pso": 5692, - "psp": 5693, - "psq": 5694, - "psr": 5695, - "pss": 5696, - "pst": 5697, - "psu": 5698, - "psw": 5699, - "psy": 5700, - "pta": 5701, - "pth": 5702, - "pti": 5703, - "ptn": 5704, - "pto": 5705, - "ptp": 5706, - "ptq": 5707, - "ptr": 5708, - "ptt": 5709, - "ptu": 5710, - "ptv": 5711, - "ptw": 5712, - "pty": 5713, - "pua": 5714, - "pub": 5715, - "puc": 5716, - "pud": 5717, - "pue": 5718, - "puf": 5719, - "pug": 5720, - "pui": 5721, - "puj": 5722, - "puk": 5723, - "pum": 5724, - "puo": 5725, - "pup": 5726, - "puq": 5727, - "pur": 5728, - "put": 5729, - "puu": 5730, - "puw": 5731, - "pux": 5732, - "puy": 5733, - "puz": 5734, - "pwa": 5735, - "pwb": 5736, - "pwg": 5737, - "pwi": 5738, - "pwm": 5739, - "pwn": 5740, - "pwo": 5741, - "pwr": 5742, - "pww": 5743, - "pxm": 5744, - "pye": 5745, - "pym": 5746, - "pyn": 5747, - "pys": 5748, - "pyu": 5749, - "pyx": 5750, - "pyy": 5751, - "pzh": 5752, - "pzn": 5753, - "qaa..qtz": 5754, - "qua": 5755, - "qub": 5756, - "quc": 5757, - "qud": 5758, - "quf": 5759, - "qug": 5760, - "quh": 5761, - "qui": 5762, - "quk": 5763, - "qul": 5764, - "qum": 5765, - "qun": 5766, - "qup": 5767, - "quq": 5768, - "qur": 5769, - "qus": 5770, - "quv": 5771, - "quw": 5772, - "qux": 5773, - "quy": 5774, - "quz": 5775, - "qva": 5776, - "qvc": 5777, - "qve": 5778, - "qvh": 5779, - "qvi": 5780, - "qvj": 5781, - "qvl": 5782, - "qvm": 5783, - "qvn": 5784, - "qvo": 5785, - "qvp": 5786, - "qvs": 5787, - "qvw": 5788, - "qvy": 5789, - "qvz": 5790, - "qwa": 5791, - "qwc": 5792, - "qwe": 5793, - "qwh": 5794, - "qwm": 5795, - "qws": 5796, - "qwt": 5797, - "qxa": 5798, - "qxc": 5799, - "qxh": 5800, - "qxl": 5801, - "qxn": 5802, - "qxo": 5803, - "qxp": 5804, - "qxq": 5805, - "qxr": 5806, - "qxs": 5807, - "qxt": 5808, - "qxu": 5809, - "qxw": 5810, - "qya": 5811, - "qyp": 5812, - "raa": 5813, - "rab": 5814, - "rac": 5815, - "rad": 5816, - "raf": 5817, - "rag": 5818, - "rah": 5819, - "rai": 5820, - "raj": 5821, - "rak": 5822, - "ral": 5823, - "ram": 5824, - "ran": 5825, - "rao": 5826, - "rap": 5827, - "raq": 5828, - "rar": 5829, - "ras": 5830, - "rat": 5831, - "rau": 5832, - "rav": 5833, - "raw": 5834, - "rax": 5835, - "ray": 5836, - "raz": 5837, - "rbb": 5838, - "rbk": 5839, - "rbl": 5840, - "rbp": 5841, - "rcf": 5842, - "rdb": 5843, - "rea": 5844, - "reb": 5845, - "ree": 5846, - "reg": 5847, - "rei": 5848, - "rej": 5849, - "rel": 5850, - "rem": 5851, - "ren": 5852, - "rer": 5853, - "res": 5854, - "ret": 5855, - "rey": 5856, - "rga": 5857, - "rge": 5858, - "rgk": 5859, - "rgn": 5860, - "rgr": 5861, - "rgs": 5862, - "rgu": 5863, - "rhg": 5864, - "rhp": 5865, - "ria": 5866, - "rib": 5867, - "rie": 5868, - "rif": 5869, - "ril": 5870, - "rim": 5871, - "rin": 5872, - "rir": 5873, - "rit": 5874, - "riu": 5875, - "rjg": 5876, - "rji": 5877, - "rjs": 5878, - "rka": 5879, - "rkb": 5880, - "rkh": 5881, - "rki": 5882, - "rkm": 5883, - "rkt": 5884, - "rkw": 5885, - "rma": 5886, - "rmb": 5887, - "rmc": 5888, - "rmd": 5889, - "rme": 5890, - "rmf": 5891, - "rmg": 5892, - "rmh": 5893, - "rmi": 5894, - "rmk": 5895, - "rml": 5896, - "rmm": 5897, - "rmn": 5898, - "rmo": 5899, - "rmp": 5900, - "rmq": 5901, - "rmr": 5902, - "rms": 5903, - "rmt": 5904, - "rmu": 5905, - "rmv": 5906, - "rmw": 5907, - "rmx": 5908, - "rmy": 5909, - "rmz": 5910, - "rna": 5911, - "rnb": 5912, - "rnd": 5913, - "rng": 5914, - "rnl": 5915, - "rnn": 5916, - "rnp": 5917, - "rnr": 5918, - "rnw": 5919, - "roa": 5920, - "rob": 5921, - "roc": 5922, - "rod": 5923, - "roe": 5924, - "rof": 5925, - "rog": 5926, - "rol": 5927, - "rom": 5928, - "roo": 5929, - "rop": 5930, - "ror": 5931, - "rou": 5932, - "row": 5933, - "rpn": 5934, - "rpt": 5935, - "rri": 5936, - "rro": 5937, - "rrt": 5938, - "rsb": 5939, - "rsi": 5940, - "rsk": 5941, - "rsl": 5942, - "rsm": 5943, - "rsn": 5944, - "rtc": 5945, - "rth": 5946, - "rtm": 5947, - "rts": 5948, - "rtw": 5949, - "rub": 5950, - "ruc": 5951, - "rue": 5952, - "ruf": 5953, - "rug": 5954, - "ruh": 5955, - "rui": 5956, - "ruk": 5957, - "ruo": 5958, - "rup": 5959, - "ruq": 5960, - "rut": 5961, - "ruu": 5962, - "ruy": 5963, - "ruz": 5964, - "rwa": 5965, - "rwk": 5966, - "rwl": 5967, - "rwm": 5968, - "rwo": 5969, - "rwr": 5970, - "rxd": 5971, - "rxw": 5972, - "ryn": 5973, - "rys": 5974, - "ryu": 5975, - "rzh": 5976, - "saa": 5977, - "sab": 5978, - "sac": 5979, - "sad": 5980, - "sae": 5981, - "saf": 5982, - "sah": 5983, - "sai": 5984, - "saj": 5985, - "sak": 5986, - "sal": 5987, - "sam": 5988, - "sao": 5989, - "sap": 5990, - "saq": 5991, - "sar": 5992, - "sas": 5993, - "sat": 5994, - "sau": 5995, - "sav": 5996, - "saw": 5997, - "sax": 5998, - "say": 5999, - "saz": 6000, - "sba": 6001, - "sbb": 6002, - "sbc": 6003, - "sbd": 6004, - "sbe": 6005, - "sbf": 6006, - "sbg": 6007, - "sbh": 6008, - "sbi": 6009, - "sbj": 6010, - "sbk": 6011, - "sbl": 6012, - "sbm": 6013, - "sbn": 6014, - "sbo": 6015, - "sbp": 6016, - "sbq": 6017, - "sbr": 6018, - "sbs": 6019, - "sbt": 6020, - "sbu": 6021, - "sbv": 6022, - "sbw": 6023, - "sbx": 6024, - "sby": 6025, - "sbz": 6026, - "sca": 6027, - "scb": 6028, - "sce": 6029, - "scf": 6030, - "scg": 6031, - "sch": 6032, - "sci": 6033, - "sck": 6034, - "scl": 6035, - "scn": 6036, - "sco": 6037, - "scp": 6038, - "scq": 6039, - "scs": 6040, - "sct": 6041, - "scu": 6042, - "scv": 6043, - "scw": 6044, - "scx": 6045, - "sda": 6046, - "sdb": 6047, - "sdc": 6048, - "sde": 6049, - "sdf": 6050, - "sdg": 6051, - "sdh": 6052, - "sdj": 6053, - "sdk": 6054, - "sdl": 6055, - "sdm": 6056, - "sdn": 6057, - "sdo": 6058, - "sdp": 6059, - "sdq": 6060, - "sdr": 6061, - "sds": 6062, - "sdt": 6063, - "sdu": 6064, - "sdv": 6065, - "sdx": 6066, - "sdz": 6067, - "sea": 6068, - "seb": 6069, - "sec": 6070, - "sed": 6071, - "see": 6072, - "sef": 6073, - "seg": 6074, - "seh": 6075, - "sei": 6076, - "sej": 6077, - "sek": 6078, - "sel": 6079, - "sem": 6080, - "sen": 6081, - "seo": 6082, - "sep": 6083, - "seq": 6084, - "ser": 6085, - "ses": 6086, - "set": 6087, - "seu": 6088, - "sev": 6089, - "sew": 6090, - "sey": 6091, - "sez": 6092, - "sfb": 6093, - "sfe": 6094, - "sfm": 6095, - "sfs": 6096, - "sfw": 6097, - "sga": 6098, - "sgb": 6099, - "sgc": 6100, - "sgd": 6101, - "sge": 6102, - "sgg": 6103, - "sgh": 6104, - "sgi": 6105, - "sgj": 6106, - "sgk": 6107, - "sgl": 6108, - "sgm": 6109, - "sgn": 6110, - "sgo": 6111, - "sgp": 6112, - "sgr": 6113, - "sgs": 6114, - "sgt": 6115, - "sgu": 6116, - "sgw": 6117, - "sgx": 6118, - "sgy": 6119, - "sgz": 6120, - "sha": 6121, - "shb": 6122, - "shc": 6123, - "shd": 6124, - "she": 6125, - "shg": 6126, - "shh": 6127, - "shi": 6128, - "shj": 6129, - "shk": 6130, - "shl": 6131, - "shm": 6132, - "shn": 6133, - "sho": 6134, - "shp": 6135, - "shq": 6136, - "shr": 6137, - "shs": 6138, - "sht": 6139, - "shu": 6140, - "shv": 6141, - "shw": 6142, - "shx": 6143, - "shy": 6144, - "shz": 6145, - "sia": 6146, - "sib": 6147, - "sid": 6148, - "sie": 6149, - "sif": 6150, - "sig": 6151, - "sih": 6152, - "sii": 6153, - "sij": 6154, - "sik": 6155, - "sil": 6156, - "sim": 6157, - "sio": 6158, - "sip": 6159, - "siq": 6160, - "sir": 6161, - "sis": 6162, - "sit": 6163, - "siu": 6164, - "siv": 6165, - "siw": 6166, - "six": 6167, - "siy": 6168, - "siz": 6169, - "sja": 6170, - "sjb": 6171, - "sjd": 6172, - "sje": 6173, - "sjg": 6174, - "sjk": 6175, - "sjl": 6176, - "sjm": 6177, - "sjn": 6178, - "sjo": 6179, - "sjp": 6180, - "sjr": 6181, - "sjs": 6182, - "sjt": 6183, - "sju": 6184, - "sjw": 6185, - "ska": 6186, - "skb": 6187, - "skc": 6188, - "skd": 6189, - "ske": 6190, - "skf": 6191, - "skg": 6192, - "skh": 6193, - "ski": 6194, - "skj": 6195, - "skk": 6196, - "skm": 6197, - "skn": 6198, - "sko": 6199, - "skp": 6200, - "skq": 6201, - "skr": 6202, - "sks": 6203, - "skt": 6204, - "sku": 6205, - "skv": 6206, - "skw": 6207, - "skx": 6208, - "sky": 6209, - "skz": 6210, - "sla": 6211, - "slc": 6212, - "sld": 6213, - "sle": 6214, - "slf": 6215, - "slg": 6216, - "slh": 6217, - "sli": 6218, - "slj": 6219, - "sll": 6220, - "slm": 6221, - "sln": 6222, - "slp": 6223, - "slq": 6224, - "slr": 6225, - "sls": 6226, - "slt": 6227, - "slu": 6228, - "slw": 6229, - "slx": 6230, - "sly": 6231, - "slz": 6232, - "sma": 6233, - "smb": 6234, - "smc": 6235, - "smd": 6236, - "smf": 6237, - "smg": 6238, - "smh": 6239, - "smi": 6240, - "smj": 6241, - "smk": 6242, - "sml": 6243, - "smm": 6244, - "smn": 6245, - "smp": 6246, - "smq": 6247, - "smr": 6248, - "sms": 6249, - "smt": 6250, - "smu": 6251, - "smv": 6252, - "smw": 6253, - "smx": 6254, - "smy": 6255, - "smz": 6256, - "snb": 6257, - "snc": 6258, - "sne": 6259, - "snf": 6260, - "sng": 6261, - "snh": 6262, - "sni": 6263, - "snj": 6264, - "snk": 6265, - "snl": 6266, - "snm": 6267, - "snn": 6268, - "sno": 6269, - "snp": 6270, - "snq": 6271, - "snr": 6272, - "sns": 6273, - "snu": 6274, - "snv": 6275, - "snw": 6276, - "snx": 6277, - "sny": 6278, - "snz": 6279, - "soa": 6280, - "sob": 6281, - "soc": 6282, - "sod": 6283, - "soe": 6284, - "sog": 6285, - "soh": 6286, - "soi": 6287, - "soj": 6288, - "sok": 6289, - "sol": 6290, - "son": 6291, - "soo": 6292, - "sop": 6293, - "soq": 6294, - "sor": 6295, - "sos": 6296, - "sou": 6297, - "sov": 6298, - "sow": 6299, - "sox": 6300, - "soy": 6301, - "soz": 6302, - "spb": 6303, - "spc": 6304, - "spd": 6305, - "spe": 6306, - "spg": 6307, - "spi": 6308, - "spk": 6309, - "spl": 6310, - "spm": 6311, - "spn": 6312, - "spo": 6313, - "spp": 6314, - "spq": 6315, - "spr": 6316, - "sps": 6317, - "spt": 6318, - "spu": 6319, - "spv": 6320, - "spx": 6321, - "spy": 6322, - "sqa": 6323, - "sqh": 6324, - "sqj": 6325, - "sqk": 6326, - "sqm": 6327, - "sqn": 6328, - "sqo": 6329, - "sqq": 6330, - "sqr": 6331, - "sqs": 6332, - "sqt": 6333, - "squ": 6334, - "sqx": 6335, - "sra": 6336, - "srb": 6337, - "src": 6338, - "sre": 6339, - "srf": 6340, - "srg": 6341, - "srh": 6342, - "sri": 6343, - "srk": 6344, - "srl": 6345, - "srm": 6346, - "srn": 6347, - "sro": 6348, - "srq": 6349, - "srr": 6350, - "srs": 6351, - "srt": 6352, - "sru": 6353, - "srv": 6354, - "srw": 6355, - "srx": 6356, - "sry": 6357, - "srz": 6358, - "ssa": 6359, - "ssb": 6360, - "ssc": 6361, - "ssd": 6362, - "sse": 6363, - "ssf": 6364, - "ssg": 6365, - "ssh": 6366, - "ssi": 6367, - "ssj": 6368, - "ssk": 6369, - "ssl": 6370, - "ssm": 6371, - "ssn": 6372, - "sso": 6373, - "ssp": 6374, - "ssq": 6375, - "ssr": 6376, - "sss": 6377, - "sst": 6378, - "ssu": 6379, - "ssv": 6380, - "ssx": 6381, - "ssy": 6382, - "ssz": 6383, - "sta": 6384, - "stb": 6385, - "std": 6386, - "ste": 6387, - "stf": 6388, - "stg": 6389, - "sth": 6390, - "sti": 6391, - "stj": 6392, - "stk": 6393, - "stl": 6394, - "stm": 6395, - "stn": 6396, - "sto": 6397, - "stp": 6398, - "stq": 6399, - "str": 6400, - "sts": 6401, - "stt": 6402, - "stu": 6403, - "stv": 6404, - "stw": 6405, - "sty": 6406, - "sua": 6407, - "sub": 6408, - "suc": 6409, - "sue": 6410, - "sug": 6411, - "sui": 6412, - "suj": 6413, - "suk": 6414, - "sul": 6415, - "sum": 6416, - "suo": 6417, - "suq": 6418, - "sur": 6419, - "sus": 6420, - "sut": 6421, - "suv": 6422, - "suw": 6423, - "sux": 6424, - "suy": 6425, - "suz": 6426, - "sva": 6427, - "svb": 6428, - "svc": 6429, - "sve": 6430, - "svk": 6431, - "svm": 6432, - "svr": 6433, - "svs": 6434, - "svx": 6435, - "swb": 6436, - "swc": 6437, - "swf": 6438, - "swg": 6439, - "swh": 6440, - "swi": 6441, - "swj": 6442, - "swk": 6443, - "swl": 6444, - "swm": 6445, - "swn": 6446, - "swo": 6447, - "swp": 6448, - "swq": 6449, - "swr": 6450, - "sws": 6451, - "swt": 6452, - "swu": 6453, - "swv": 6454, - "sww": 6455, - "swx": 6456, - "swy": 6457, - "sxb": 6458, - "sxc": 6459, - "sxe": 6460, - "sxg": 6461, - "sxk": 6462, - "sxl": 6463, - "sxm": 6464, - "sxn": 6465, - "sxo": 6466, - "sxr": 6467, - "sxs": 6468, - "sxu": 6469, - "sxw": 6470, - "sya": 6471, - "syb": 6472, - "syc": 6473, - "syd": 6474, - "syi": 6475, - "syk": 6476, - "syl": 6477, - "sym": 6478, - "syn": 6479, - "syo": 6480, - "syr": 6481, - "sys": 6482, - "syw": 6483, - "syx": 6484, - "syy": 6485, - "sza": 6486, - "szb": 6487, - "szc": 6488, - "szd": 6489, - "sze": 6490, - "szg": 6491, - "szl": 6492, - "szn": 6493, - "szp": 6494, - "szs": 6495, - "szv": 6496, - "szw": 6497, - "szy": 6498, - "taa": 6499, - "tab": 6500, - "tac": 6501, - "tad": 6502, - "tae": 6503, - "taf": 6504, - "tag": 6505, - "tai": 6506, - "taj": 6507, - "tak": 6508, - "tal": 6509, - "tan": 6510, - "tao": 6511, - "tap": 6512, - "taq": 6513, - "tar": 6514, - "tas": 6515, - "tau": 6516, - "tav": 6517, - "taw": 6518, - "tax": 6519, - "tay": 6520, - "taz": 6521, - "tba": 6522, - "tbb": 6523, - "tbc": 6524, - "tbd": 6525, - "tbe": 6526, - "tbf": 6527, - "tbg": 6528, - "tbh": 6529, - "tbi": 6530, - "tbj": 6531, - "tbk": 6532, - "tbl": 6533, - "tbm": 6534, - "tbn": 6535, - "tbo": 6536, - "tbp": 6537, - "tbq": 6538, - "tbr": 6539, - "tbs": 6540, - "tbt": 6541, - "tbu": 6542, - "tbv": 6543, - "tbw": 6544, - "tbx": 6545, - "tby": 6546, - "tbz": 6547, - "tca": 6548, - "tcb": 6549, - "tcc": 6550, - "tcd": 6551, - "tce": 6552, - "tcf": 6553, - "tcg": 6554, - "tch": 6555, - "tci": 6556, - "tck": 6557, - "tcl": 6558, - "tcm": 6559, - "tcn": 6560, - "tco": 6561, - "tcp": 6562, - "tcq": 6563, - "tcs": 6564, - "tct": 6565, - "tcu": 6566, - "tcw": 6567, - "tcx": 6568, - "tcy": 6569, - "tcz": 6570, - "tda": 6571, - "tdb": 6572, - "tdc": 6573, - "tdd": 6574, - "tde": 6575, - "tdf": 6576, - "tdg": 6577, - "tdh": 6578, - "tdi": 6579, - "tdj": 6580, - "tdk": 6581, - "tdl": 6582, - "tdm": 6583, - "tdn": 6584, - "tdo": 6585, - "tdq": 6586, - "tdr": 6587, - "tds": 6588, - "tdt": 6589, - "tdu": 6590, - "tdv": 6591, - "tdx": 6592, - "tdy": 6593, - "tea": 6594, - "teb": 6595, - "tec": 6596, - "ted": 6597, - "tee": 6598, - "tef": 6599, - "teg": 6600, - "teh": 6601, - "tei": 6602, - "tek": 6603, - "tem": 6604, - "ten": 6605, - "teo": 6606, - "tep": 6607, - "teq": 6608, - "ter": 6609, - "tes": 6610, - "tet": 6611, - "teu": 6612, - "tev": 6613, - "tew": 6614, - "tex": 6615, - "tey": 6616, - "tez": 6617, - "tfi": 6618, - "tfn": 6619, - "tfo": 6620, - "tfr": 6621, - "tft": 6622, - "tga": 6623, - "tgb": 6624, - "tgc": 6625, - "tgd": 6626, - "tge": 6627, - "tgf": 6628, - "tgg": 6629, - "tgh": 6630, - "tgi": 6631, - "tgj": 6632, - "tgn": 6633, - "tgo": 6634, - "tgp": 6635, - "tgq": 6636, - "tgr": 6637, - "tgs": 6638, - "tgt": 6639, - "tgu": 6640, - "tgv": 6641, - "tgw": 6642, - "tgx": 6643, - "tgy": 6644, - "tgz": 6645, - "thc": 6646, - "thd": 6647, - "the": 6648, - "thf": 6649, - "thh": 6650, - "thi": 6651, - "thk": 6652, - "thl": 6653, - "thm": 6654, - "thn": 6655, - "thp": 6656, - "thq": 6657, - "thr": 6658, - "ths": 6659, - "tht": 6660, - "thu": 6661, - "thv": 6662, - "thw": 6663, - "thx": 6664, - "thy": 6665, - "thz": 6666, - "tia": 6667, - "tic": 6668, - "tid": 6669, - "tie": 6670, - "tif": 6671, - "tig": 6672, - "tih": 6673, - "tii": 6674, - "tij": 6675, - "tik": 6676, - "til": 6677, - "tim": 6678, - "tin": 6679, - "tio": 6680, - "tip": 6681, - "tiq": 6682, - "tis": 6683, - "tit": 6684, - "tiu": 6685, - "tiv": 6686, - "tiw": 6687, - "tix": 6688, - "tiy": 6689, - "tiz": 6690, - "tja": 6691, - "tjg": 6692, - "tji": 6693, - "tjj": 6694, - "tjl": 6695, - "tjm": 6696, - "tjn": 6697, - "tjo": 6698, - "tjp": 6699, - "tjs": 6700, - "tju": 6701, - "tjw": 6702, - "tka": 6703, - "tkb": 6704, - "tkd": 6705, - "tke": 6706, - "tkf": 6707, - "tkg": 6708, - "tkk": 6709, - "tkl": 6710, - "tkm": 6711, - "tkn": 6712, - "tkp": 6713, - "tkq": 6714, - "tkr": 6715, - "tks": 6716, - "tkt": 6717, - "tku": 6718, - "tkv": 6719, - "tkw": 6720, - "tkx": 6721, - "tkz": 6722, - "tla": 6723, - "tlb": 6724, - "tlc": 6725, - "tld": 6726, - "tlf": 6727, - "tlg": 6728, - "tlh": 6729, - "tli": 6730, - "tlj": 6731, - "tlk": 6732, - "tll": 6733, - "tlm": 6734, - "tln": 6735, - "tlo": 6736, - "tlp": 6737, - "tlq": 6738, - "tlr": 6739, - "tls": 6740, - "tlt": 6741, - "tlu": 6742, - "tlv": 6743, - "tlw": 6744, - "tlx": 6745, - "tly": 6746, - "tma": 6747, - "tmb": 6748, - "tmc": 6749, - "tmd": 6750, - "tme": 6751, - "tmf": 6752, - "tmg": 6753, - "tmh": 6754, - "tmi": 6755, - "tmj": 6756, - "tmk": 6757, - "tml": 6758, - "tmm": 6759, - "tmn": 6760, - "tmo": 6761, - "tmp": 6762, - "tmq": 6763, - "tmr": 6764, - "tms": 6765, - "tmt": 6766, - "tmu": 6767, - "tmv": 6768, - "tmw": 6769, - "tmy": 6770, - "tmz": 6771, - "tna": 6772, - "tnb": 6773, - "tnc": 6774, - "tnd": 6775, - "tne": 6776, - "tnf": 6777, - "tng": 6778, - "tnh": 6779, - "tni": 6780, - "tnk": 6781, - "tnl": 6782, - "tnm": 6783, - "tnn": 6784, - "tno": 6785, - "tnp": 6786, - "tnq": 6787, - "tnr": 6788, - "tns": 6789, - "tnt": 6790, - "tnu": 6791, - "tnv": 6792, - "tnw": 6793, - "tnx": 6794, - "tny": 6795, - "tnz": 6796, - "tob": 6797, - "toc": 6798, - "tod": 6799, - "toe": 6800, - "tof": 6801, - "tog": 6802, - "toh": 6803, - "toi": 6804, - "toj": 6805, - "tok": 6806, - "tol": 6807, - "tom": 6808, - "too": 6809, - "top": 6810, - "toq": 6811, - "tor": 6812, - "tos": 6813, - "tou": 6814, - "tov": 6815, - "tow": 6816, - "tox": 6817, - "toy": 6818, - "toz": 6819, - "tpa": 6820, - "tpc": 6821, - "tpe": 6822, - "tpf": 6823, - "tpg": 6824, - "tpi": 6825, - "tpj": 6826, - "tpk": 6827, - "tpl": 6828, - "tpm": 6829, - "tpn": 6830, - "tpo": 6831, - "tpp": 6832, - "tpq": 6833, - "tpr": 6834, - "tpt": 6835, - "tpu": 6836, - "tpv": 6837, - "tpw": 6838, - "tpx": 6839, - "tpy": 6840, - "tpz": 6841, - "tqb": 6842, - "tql": 6843, - "tqm": 6844, - "tqn": 6845, - "tqo": 6846, - "tqp": 6847, - "tqq": 6848, - "tqr": 6849, - "tqt": 6850, - "tqu": 6851, - "tqw": 6852, - "tra": 6853, - "trb": 6854, - "trc": 6855, - "trd": 6856, - "tre": 6857, - "trf": 6858, - "trg": 6859, - "trh": 6860, - "tri": 6861, - "trj": 6862, - "trk": 6863, - "trl": 6864, - "trm": 6865, - "trn": 6866, - "tro": 6867, - "trp": 6868, - "trq": 6869, - "trr": 6870, - "trs": 6871, - "trt": 6872, - "tru": 6873, - "trv": 6874, - "trw": 6875, - "trx": 6876, - "try": 6877, - "trz": 6878, - "tsa": 6879, - "tsb": 6880, - "tsc": 6881, - "tsd": 6882, - "tse": 6883, - "tsf": 6884, - "tsg": 6885, - "tsh": 6886, - "tsi": 6887, - "tsj": 6888, - "tsk": 6889, - "tsl": 6890, - "tsm": 6891, - "tsp": 6892, - "tsq": 6893, - "tsr": 6894, - "tss": 6895, - "tst": 6896, - "tsu": 6897, - "tsv": 6898, - "tsw": 6899, - "tsx": 6900, - "tsy": 6901, - "tsz": 6902, - "tta": 6903, - "ttb": 6904, - "ttc": 6905, - "ttd": 6906, - "tte": 6907, - "ttf": 6908, - "ttg": 6909, - "tth": 6910, - "tti": 6911, - "ttj": 6912, - "ttk": 6913, - "ttl": 6914, - "ttm": 6915, - "ttn": 6916, - "tto": 6917, - "ttp": 6918, - "ttq": 6919, - "ttr": 6920, - "tts": 6921, - "ttt": 6922, - "ttu": 6923, - "ttv": 6924, - "ttw": 6925, - "tty": 6926, - "ttz": 6927, - "tua": 6928, - "tub": 6929, - "tuc": 6930, - "tud": 6931, - "tue": 6932, - "tuf": 6933, - "tug": 6934, - "tuh": 6935, - "tui": 6936, - "tuj": 6937, - "tul": 6938, - "tum": 6939, - "tun": 6940, - "tuo": 6941, - "tup": 6942, - "tuq": 6943, - "tus": 6944, - "tut": 6945, - "tuu": 6946, - "tuv": 6947, - "tuw": 6948, - "tux": 6949, - "tuy": 6950, - "tuz": 6951, - "tva": 6952, - "tvd": 6953, - "tve": 6954, - "tvk": 6955, - "tvl": 6956, - "tvm": 6957, - "tvn": 6958, - "tvo": 6959, - "tvs": 6960, - "tvt": 6961, - "tvu": 6962, - "tvw": 6963, - "tvx": 6964, - "tvy": 6965, - "twa": 6966, - "twb": 6967, - "twc": 6968, - "twd": 6969, - "twe": 6970, - "twf": 6971, - "twg": 6972, - "twh": 6973, - "twl": 6974, - "twm": 6975, - "twn": 6976, - "two": 6977, - "twp": 6978, - "twq": 6979, - "twr": 6980, - "twt": 6981, - "twu": 6982, - "tww": 6983, - "twx": 6984, - "twy": 6985, - "txa": 6986, - "txb": 6987, - "txc": 6988, - "txe": 6989, - "txg": 6990, - "txh": 6991, - "txi": 6992, - "txj": 6993, - "txm": 6994, - "txn": 6995, - "txo": 6996, - "txq": 6997, - "txr": 6998, - "txs": 6999, - "txt": 7000, - "txu": 7001, - "txx": 7002, - "txy": 7003, - "tya": 7004, - "tye": 7005, - "tyh": 7006, - "tyi": 7007, - "tyj": 7008, - "tyl": 7009, - "tyn": 7010, - "typ": 7011, - "tyr": 7012, - "tys": 7013, - "tyt": 7014, - "tyu": 7015, - "tyv": 7016, - "tyx": 7017, - "tyy": 7018, - "tyz": 7019, - "tza": 7020, - "tzh": 7021, - "tzj": 7022, - "tzl": 7023, - "tzm": 7024, - "tzn": 7025, - "tzo": 7026, - "tzx": 7027, - "uam": 7028, - "uan": 7029, - "uar": 7030, - "uba": 7031, - "ubi": 7032, - "ubl": 7033, - "ubr": 7034, - "ubu": 7035, - "uby": 7036, - "uda": 7037, - "ude": 7038, - "udg": 7039, - "udi": 7040, - "udj": 7041, - "udl": 7042, - "udm": 7043, - "udu": 7044, - "ues": 7045, - "ufi": 7046, - "uga": 7047, - "ugb": 7048, - "uge": 7049, - "ugh": 7050, - "ugn": 7051, - "ugo": 7052, - "ugy": 7053, - "uha": 7054, - "uhn": 7055, - "uis": 7056, - "uiv": 7057, - "uji": 7058, - "uka": 7059, - "ukg": 7060, - "ukh": 7061, - "uki": 7062, - "ukk": 7063, - "ukl": 7064, - "ukp": 7065, - "ukq": 7066, - "uks": 7067, - "uku": 7068, - "ukv": 7069, - "ukw": 7070, - "uky": 7071, - "ula": 7072, - "ulb": 7073, - "ulc": 7074, - "ule": 7075, - "ulf": 7076, - "uli": 7077, - "ulk": 7078, - "ull": 7079, - "ulm": 7080, - "uln": 7081, - "ulu": 7082, - "ulw": 7083, - "uma": 7084, - "umb": 7085, - "umc": 7086, - "umd": 7087, - "umg": 7088, - "umi": 7089, - "umm": 7090, - "umn": 7091, - "umo": 7092, - "ump": 7093, - "umr": 7094, - "ums": 7095, - "umu": 7096, - "una": 7097, - "und": 7098, - "une": 7099, - "ung": 7100, - "uni": 7101, - "unk": 7102, - "unm": 7103, - "unn": 7104, - "unp": 7105, - "unr": 7106, - "unu": 7107, - "unx": 7108, - "unz": 7109, - "uok": 7110, - "uon": 7111, - "upi": 7112, - "upv": 7113, - "ura": 7114, - "urb": 7115, - "urc": 7116, - "ure": 7117, - "urf": 7118, - "urg": 7119, - "urh": 7120, - "uri": 7121, - "urj": 7122, - "urk": 7123, - "url": 7124, - "urm": 7125, - "urn": 7126, - "uro": 7127, - "urp": 7128, - "urr": 7129, - "urt": 7130, - "uru": 7131, - "urv": 7132, - "urw": 7133, - "urx": 7134, - "ury": 7135, - "urz": 7136, - "usa": 7137, - "ush": 7138, - "usi": 7139, - "usk": 7140, - "usp": 7141, - "uss": 7142, - "usu": 7143, - "uta": 7144, - "ute": 7145, - "uth": 7146, - "utp": 7147, - "utr": 7148, - "utu": 7149, - "uum": 7150, - "uun": 7151, - "uur": 7152, - "uuu": 7153, - "uve": 7154, - "uvh": 7155, - "uvl": 7156, - "uwa": 7157, - "uya": 7158, - "uzn": 7159, - "uzs": 7160, - "vaa": 7161, - "vae": 7162, - "vaf": 7163, - "vag": 7164, - "vah": 7165, - "vai": 7166, - "vaj": 7167, - "val": 7168, - "vam": 7169, - "van": 7170, - "vao": 7171, - "vap": 7172, - "var": 7173, - "vas": 7174, - "vau": 7175, - "vav": 7176, - "vay": 7177, - "vbb": 7178, - "vbk": 7179, - "vec": 7180, - "ved": 7181, - "vel": 7182, - "vem": 7183, - "veo": 7184, - "vep": 7185, - "ver": 7186, - "vgr": 7187, - "vgt": 7188, - "vic": 7189, - "vid": 7190, - "vif": 7191, - "vig": 7192, - "vil": 7193, - "vin": 7194, - "vis": 7195, - "vit": 7196, - "viv": 7197, - "vka": 7198, - "vki": 7199, - "vkj": 7200, - "vkk": 7201, - "vkl": 7202, - "vkm": 7203, - "vkn": 7204, - "vko": 7205, - "vkp": 7206, - "vkt": 7207, - "vku": 7208, - "vkz": 7209, - "vlp": 7210, - "vls": 7211, - "vma": 7212, - "vmb": 7213, - "vmc": 7214, - "vmd": 7215, - "vme": 7216, - "vmf": 7217, - "vmg": 7218, - "vmh": 7219, - "vmi": 7220, - "vmj": 7221, - "vmk": 7222, - "vml": 7223, - "vmm": 7224, - "vmp": 7225, - "vmq": 7226, - "vmr": 7227, - "vms": 7228, - "vmu": 7229, - "vmv": 7230, - "vmw": 7231, - "vmx": 7232, - "vmy": 7233, - "vmz": 7234, - "vnk": 7235, - "vnm": 7236, - "vnp": 7237, - "vor": 7238, - "vot": 7239, - "vra": 7240, - "vro": 7241, - "vrs": 7242, - "vrt": 7243, - "vsi": 7244, - "vsl": 7245, - "vsv": 7246, - "vto": 7247, - "vum": 7248, - "vun": 7249, - "vut": 7250, - "vwa": 7251, - "waa": 7252, - "wab": 7253, - "wac": 7254, - "wad": 7255, - "wae": 7256, - "waf": 7257, - "wag": 7258, - "wah": 7259, - "wai": 7260, - "waj": 7261, - "wak": 7262, - "wal": 7263, - "wam": 7264, - "wan": 7265, - "wao": 7266, - "wap": 7267, - "waq": 7268, - "war": 7269, - "was": 7270, - "wat": 7271, - "wau": 7272, - "wav": 7273, - "waw": 7274, - "wax": 7275, - "way": 7276, - "waz": 7277, - "wba": 7278, - "wbb": 7279, - "wbe": 7280, - "wbf": 7281, - "wbh": 7282, - "wbi": 7283, - "wbj": 7284, - "wbk": 7285, - "wbl": 7286, - "wbm": 7287, - "wbp": 7288, - "wbq": 7289, - "wbr": 7290, - "wbs": 7291, - "wbt": 7292, - "wbv": 7293, - "wbw": 7294, - "wca": 7295, - "wci": 7296, - "wdd": 7297, - "wdg": 7298, - "wdj": 7299, - "wdk": 7300, - "wdt": 7301, - "wdu": 7302, - "wdy": 7303, - "wea": 7304, - "wec": 7305, - "wed": 7306, - "weg": 7307, - "weh": 7308, - "wei": 7309, - "wem": 7310, - "wen": 7311, - "weo": 7312, - "wep": 7313, - "wer": 7314, - "wes": 7315, - "wet": 7316, - "weu": 7317, - "wew": 7318, - "wfg": 7319, - "wga": 7320, - "wgb": 7321, - "wgg": 7322, - "wgi": 7323, - "wgo": 7324, - "wgu": 7325, - "wgw": 7326, - "wgy": 7327, - "wha": 7328, - "whg": 7329, - "whk": 7330, - "whu": 7331, - "wib": 7332, - "wic": 7333, - "wie": 7334, - "wif": 7335, - "wig": 7336, - "wih": 7337, - "wii": 7338, - "wij": 7339, - "wik": 7340, - "wil": 7341, - "wim": 7342, - "win": 7343, - "wir": 7344, - "wit": 7345, - "wiu": 7346, - "wiv": 7347, - "wiw": 7348, - "wiy": 7349, - "wja": 7350, - "wji": 7351, - "wka": 7352, - "wkb": 7353, - "wkd": 7354, - "wkl": 7355, - "wkr": 7356, - "wku": 7357, - "wkw": 7358, - "wky": 7359, - "wla": 7360, - "wlc": 7361, - "wle": 7362, - "wlg": 7363, - "wlh": 7364, - "wli": 7365, - "wlk": 7366, - "wll": 7367, - "wlm": 7368, - "wlo": 7369, - "wlr": 7370, - "wls": 7371, - "wlu": 7372, - "wlv": 7373, - "wlw": 7374, - "wlx": 7375, - "wly": 7376, - "wma": 7377, - "wmb": 7378, - "wmc": 7379, - "wmd": 7380, - "wme": 7381, - "wmg": 7382, - "wmh": 7383, - "wmi": 7384, - "wmm": 7385, - "wmn": 7386, - "wmo": 7387, - "wms": 7388, - "wmt": 7389, - "wmw": 7390, - "wmx": 7391, - "wnb": 7392, - "wnc": 7393, - "wnd": 7394, - "wne": 7395, - "wng": 7396, - "wni": 7397, - "wnk": 7398, - "wnm": 7399, - "wnn": 7400, - "wno": 7401, - "wnp": 7402, - "wnu": 7403, - "wnw": 7404, - "wny": 7405, - "woa": 7406, - "wob": 7407, - "woc": 7408, - "wod": 7409, - "woe": 7410, - "wof": 7411, - "wog": 7412, - "woi": 7413, - "wok": 7414, - "wom": 7415, - "won": 7416, - "woo": 7417, - "wor": 7418, - "wos": 7419, - "wow": 7420, - "woy": 7421, - "wpc": 7422, - "wra": 7423, - "wrb": 7424, - "wrd": 7425, - "wrg": 7426, - "wrh": 7427, - "wri": 7428, - "wrk": 7429, - "wrl": 7430, - "wrm": 7431, - "wrn": 7432, - "wro": 7433, - "wrp": 7434, - "wrr": 7435, - "wrs": 7436, - "wru": 7437, - "wrv": 7438, - "wrw": 7439, - "wrx": 7440, - "wry": 7441, - "wrz": 7442, - "wsa": 7443, - "wsg": 7444, - "wsi": 7445, - "wsk": 7446, - "wsr": 7447, - "wss": 7448, - "wsu": 7449, - "wsv": 7450, - "wtf": 7451, - "wth": 7452, - "wti": 7453, - "wtk": 7454, - "wtm": 7455, - "wtw": 7456, - "wua": 7457, - "wub": 7458, - "wud": 7459, - "wuh": 7460, - "wul": 7461, - "wum": 7462, - "wun": 7463, - "wur": 7464, - "wut": 7465, - "wuu": 7466, - "wuv": 7467, - "wux": 7468, - "wuy": 7469, - "wwa": 7470, - "wwb": 7471, - "wwo": 7472, - "wwr": 7473, - "www": 7474, - "wxa": 7475, - "wxw": 7476, - "wya": 7477, - "wyb": 7478, - "wyi": 7479, - "wym": 7480, - "wyn": 7481, - "wyr": 7482, - "wyy": 7483, - "xaa": 7484, - "xab": 7485, - "xac": 7486, - "xad": 7487, - "xae": 7488, - "xag": 7489, - "xai": 7490, - "xaj": 7491, - "xak": 7492, - "xal": 7493, - "xam": 7494, - "xan": 7495, - "xao": 7496, - "xap": 7497, - "xaq": 7498, - "xar": 7499, - "xas": 7500, - "xat": 7501, - "xau": 7502, - "xav": 7503, - "xaw": 7504, - "xay": 7505, - "xba": 7506, - "xbb": 7507, - "xbc": 7508, - "xbd": 7509, - "xbe": 7510, - "xbg": 7511, - "xbi": 7512, - "xbj": 7513, - "xbm": 7514, - "xbn": 7515, - "xbo": 7516, - "xbp": 7517, - "xbr": 7518, - "xbw": 7519, - "xbx": 7520, - "xby": 7521, - "xcb": 7522, - "xcc": 7523, - "xce": 7524, - "xcg": 7525, - "xch": 7526, - "xcl": 7527, - "xcm": 7528, - "xcn": 7529, - "xco": 7530, - "xcr": 7531, - "xct": 7532, - "xcu": 7533, - "xcv": 7534, - "xcw": 7535, - "xcy": 7536, - "xda": 7537, - "xdc": 7538, - "xdk": 7539, - "xdm": 7540, - "xdo": 7541, - "xdq": 7542, - "xdy": 7543, - "xeb": 7544, - "xed": 7545, - "xeg": 7546, - "xel": 7547, - "xem": 7548, - "xep": 7549, - "xer": 7550, - "xes": 7551, - "xet": 7552, - "xeu": 7553, - "xfa": 7554, - "xga": 7555, - "xgb": 7556, - "xgd": 7557, - "xgf": 7558, - "xgg": 7559, - "xgi": 7560, - "xgl": 7561, - "xgm": 7562, - "xgn": 7563, - "xgr": 7564, - "xgu": 7565, - "xgw": 7566, - "xha": 7567, - "xhc": 7568, - "xhd": 7569, - "xhe": 7570, - "xhm": 7571, - "xhr": 7572, - "xht": 7573, - "xhu": 7574, - "xhv": 7575, - "xia": 7576, - "xib": 7577, - "xii": 7578, - "xil": 7579, - "xin": 7580, - "xip": 7581, - "xir": 7582, - "xis": 7583, - "xiv": 7584, - "xiy": 7585, - "xjb": 7586, - "xjt": 7587, - "xka": 7588, - "xkb": 7589, - "xkc": 7590, - "xkd": 7591, - "xke": 7592, - "xkf": 7593, - "xkg": 7594, - "xkh": 7595, - "xki": 7596, - "xkj": 7597, - "xkk": 7598, - "xkl": 7599, - "xkn": 7600, - "xko": 7601, - "xkp": 7602, - "xkq": 7603, - "xkr": 7604, - "xks": 7605, - "xkt": 7606, - "xku": 7607, - "xkv": 7608, - "xkw": 7609, - "xkx": 7610, - "xky": 7611, - "xkz": 7612, - "xla": 7613, - "xlb": 7614, - "xlc": 7615, - "xld": 7616, - "xle": 7617, - "xlg": 7618, - "xli": 7619, - "xln": 7620, - "xlo": 7621, - "xlp": 7622, - "xls": 7623, - "xlu": 7624, - "xly": 7625, - "xma": 7626, - "xmb": 7627, - "xmc": 7628, - "xmd": 7629, - "xme": 7630, - "xmf": 7631, - "xmg": 7632, - "xmh": 7633, - "xmj": 7634, - "xmk": 7635, - "xml": 7636, - "xmm": 7637, - "xmn": 7638, - "xmo": 7639, - "xmp": 7640, - "xmq": 7641, - "xmr": 7642, - "xms": 7643, - "xmt": 7644, - "xmu": 7645, - "xmv": 7646, - "xmw": 7647, - "xmx": 7648, - "xmy": 7649, - "xmz": 7650, - "xna": 7651, - "xnb": 7652, - "xnd": 7653, - "xng": 7654, - "xnh": 7655, - "xni": 7656, - "xnj": 7657, - "xnk": 7658, - "xnm": 7659, - "xnn": 7660, - "xno": 7661, - "xnq": 7662, - "xnr": 7663, - "xns": 7664, - "xnt": 7665, - "xnu": 7666, - "xny": 7667, - "xnz": 7668, - "xoc": 7669, - "xod": 7670, - "xog": 7671, - "xoi": 7672, - "xok": 7673, - "xom": 7674, - "xon": 7675, - "xoo": 7676, - "xop": 7677, - "xor": 7678, - "xow": 7679, - "xpa": 7680, - "xpb": 7681, - "xpc": 7682, - "xpd": 7683, - "xpe": 7684, - "xpf": 7685, - "xpg": 7686, - "xph": 7687, - "xpi": 7688, - "xpj": 7689, - "xpk": 7690, - "xpl": 7691, - "xpm": 7692, - "xpn": 7693, - "xpo": 7694, - "xpp": 7695, - "xpq": 7696, - "xpr": 7697, - "xps": 7698, - "xpt": 7699, - "xpu": 7700, - "xpv": 7701, - "xpw": 7702, - "xpx": 7703, - "xpy": 7704, - "xpz": 7705, - "xqa": 7706, - "xqt": 7707, - "xra": 7708, - "xrb": 7709, - "xrd": 7710, - "xre": 7711, - "xrg": 7712, - "xri": 7713, - "xrm": 7714, - "xrn": 7715, - "xrq": 7716, - "xrr": 7717, - "xrt": 7718, - "xru": 7719, - "xrw": 7720, - "xsa": 7721, - "xsb": 7722, - "xsc": 7723, - "xsd": 7724, - "xse": 7725, - "xsh": 7726, - "xsi": 7727, - "xsj": 7728, - "xsl": 7729, - "xsm": 7730, - "xsn": 7731, - "xso": 7732, - "xsp": 7733, - "xsq": 7734, - "xsr": 7735, - "xss": 7736, - "xsu": 7737, - "xsv": 7738, - "xsy": 7739, - "xta": 7740, - "xtb": 7741, - "xtc": 7742, - "xtd": 7743, - "xte": 7744, - "xtg": 7745, - "xth": 7746, - "xti": 7747, - "xtj": 7748, - "xtl": 7749, - "xtm": 7750, - "xtn": 7751, - "xto": 7752, - "xtp": 7753, - "xtq": 7754, - "xtr": 7755, - "xts": 7756, - "xtt": 7757, - "xtu": 7758, - "xtv": 7759, - "xtw": 7760, - "xty": 7761, - "xtz": 7762, - "xua": 7763, - "xub": 7764, - "xud": 7765, - "xug": 7766, - "xuj": 7767, - "xul": 7768, - "xum": 7769, - "xun": 7770, - "xuo": 7771, - "xup": 7772, - "xur": 7773, - "xut": 7774, - "xuu": 7775, - "xve": 7776, - "xvi": 7777, - "xvn": 7778, - "xvo": 7779, - "xvs": 7780, - "xwa": 7781, - "xwc": 7782, - "xwd": 7783, - "xwe": 7784, - "xwg": 7785, - "xwj": 7786, - "xwk": 7787, - "xwl": 7788, - "xwo": 7789, - "xwr": 7790, - "xwt": 7791, - "xww": 7792, - "xxb": 7793, - "xxk": 7794, - "xxm": 7795, - "xxr": 7796, - "xxt": 7797, - "xya": 7798, - "xyb": 7799, - "xyj": 7800, - "xyk": 7801, - "xyl": 7802, - "xyt": 7803, - "xyy": 7804, - "xzh": 7805, - "xzm": 7806, - "xzp": 7807, - "yaa": 7808, - "yab": 7809, - "yac": 7810, - "yad": 7811, - "yae": 7812, - "yaf": 7813, - "yag": 7814, - "yah": 7815, - "yai": 7816, - "yaj": 7817, - "yak": 7818, - "yal": 7819, - "yam": 7820, - "yan": 7821, - "yao": 7822, - "yap": 7823, - "yaq": 7824, - "yar": 7825, - "yas": 7826, - "yat": 7827, - "yau": 7828, - "yav": 7829, - "yaw": 7830, - "yax": 7831, - "yay": 7832, - "yaz": 7833, - "yba": 7834, - "ybb": 7835, - "ybd": 7836, - "ybe": 7837, - "ybh": 7838, - "ybi": 7839, - "ybj": 7840, - "ybk": 7841, - "ybl": 7842, - "ybm": 7843, - "ybn": 7844, - "ybo": 7845, - "ybx": 7846, - "yby": 7847, - "ych": 7848, - "ycl": 7849, - "ycn": 7850, - "ycp": 7851, - "yda": 7852, - "ydd": 7853, - "yde": 7854, - "ydg": 7855, - "ydk": 7856, - "yds": 7857, - "yea": 7858, - "yec": 7859, - "yee": 7860, - "yei": 7861, - "yej": 7862, - "yel": 7863, - "yen": 7864, - "yer": 7865, - "yes": 7866, - "yet": 7867, - "yeu": 7868, - "yev": 7869, - "yey": 7870, - "yga": 7871, - "ygi": 7872, - "ygl": 7873, - "ygm": 7874, - "ygp": 7875, - "ygr": 7876, - "ygs": 7877, - "ygu": 7878, - "ygw": 7879, - "yha": 7880, - "yhd": 7881, - "yhl": 7882, - "yhs": 7883, - "yia": 7884, - "yif": 7885, - "yig": 7886, - "yih": 7887, - "yii": 7888, - "yij": 7889, - "yik": 7890, - "yil": 7891, - "yim": 7892, - "yin": 7893, - "yip": 7894, - "yiq": 7895, - "yir": 7896, - "yis": 7897, - "yit": 7898, - "yiu": 7899, - "yiv": 7900, - "yix": 7901, - "yiy": 7902, - "yiz": 7903, - "yka": 7904, - "ykg": 7905, - "yki": 7906, - "ykk": 7907, - "ykl": 7908, - "ykm": 7909, - "ykn": 7910, - "yko": 7911, - "ykr": 7912, - "ykt": 7913, - "yku": 7914, - "yky": 7915, - "yla": 7916, - "ylb": 7917, - "yle": 7918, - "ylg": 7919, - "yli": 7920, - "yll": 7921, - "ylm": 7922, - "yln": 7923, - "ylo": 7924, - "ylr": 7925, - "ylu": 7926, - "yly": 7927, - "yma": 7928, - "ymb": 7929, - "ymc": 7930, - "ymd": 7931, - "yme": 7932, - "ymg": 7933, - "ymh": 7934, - "ymi": 7935, - "ymk": 7936, - "yml": 7937, - "ymm": 7938, - "ymn": 7939, - "ymo": 7940, - "ymp": 7941, - "ymq": 7942, - "ymr": 7943, - "yms": 7944, - "ymt": 7945, - "ymx": 7946, - "ymz": 7947, - "yna": 7948, - "ynd": 7949, - "yne": 7950, - "yng": 7951, - "ynh": 7952, - "ynk": 7953, - "ynl": 7954, - "ynn": 7955, - "yno": 7956, - "ynq": 7957, - "yns": 7958, - "ynu": 7959, - "yob": 7960, - "yog": 7961, - "yoi": 7962, - "yok": 7963, - "yol": 7964, - "yom": 7965, - "yon": 7966, - "yos": 7967, - "yot": 7968, - "yox": 7969, - "yoy": 7970, - "ypa": 7971, - "ypb": 7972, - "ypg": 7973, - "yph": 7974, - "ypk": 7975, - "ypm": 7976, - "ypn": 7977, - "ypo": 7978, - "ypp": 7979, - "ypz": 7980, - "yra": 7981, - "yrb": 7982, - "yre": 7983, - "yri": 7984, - "yrk": 7985, - "yrl": 7986, - "yrm": 7987, - "yrn": 7988, - "yro": 7989, - "yrs": 7990, - "yrw": 7991, - "yry": 7992, - "ysc": 7993, - "ysd": 7994, - "ysg": 7995, - "ysl": 7996, - "ysm": 7997, - "ysn": 7998, - "yso": 7999, - "ysp": 8000, - "ysr": 8001, - "yss": 8002, - "ysy": 8003, - "yta": 8004, - "ytl": 8005, - "ytp": 8006, - "ytw": 8007, - "yty": 8008, - "yua": 8009, - "yub": 8010, - "yuc": 8011, - "yud": 8012, - "yue": 8013, - "yuf": 8014, - "yug": 8015, - "yui": 8016, - "yuj": 8017, - "yuk": 8018, - "yul": 8019, - "yum": 8020, - "yun": 8021, - "yup": 8022, - "yuq": 8023, - "yur": 8024, - "yut": 8025, - "yuu": 8026, - "yuw": 8027, - "yux": 8028, - "yuy": 8029, - "yuz": 8030, - "yva": 8031, - "yvt": 8032, - "ywa": 8033, - "ywg": 8034, - "ywl": 8035, - "ywn": 8036, - "ywq": 8037, - "ywr": 8038, - "ywt": 8039, - "ywu": 8040, - "yww": 8041, - "yxa": 8042, - "yxg": 8043, - "yxl": 8044, - "yxm": 8045, - "yxu": 8046, - "yxy": 8047, - "yyr": 8048, - "yyu": 8049, - "yyz": 8050, - "yzg": 8051, - "yzk": 8052, - "zaa": 8053, - "zab": 8054, - "zac": 8055, - "zad": 8056, - "zae": 8057, - "zaf": 8058, - "zag": 8059, - "zah": 8060, - "zai": 8061, - "zaj": 8062, - "zak": 8063, - "zal": 8064, - "zam": 8065, - "zao": 8066, - "zap": 8067, - "zaq": 8068, - "zar": 8069, - "zas": 8070, - "zat": 8071, - "zau": 8072, - "zav": 8073, - "zaw": 8074, - "zax": 8075, - "zay": 8076, - "zaz": 8077, - "zba": 8078, - "zbc": 8079, - "zbe": 8080, - "zbl": 8081, - "zbt": 8082, - "zbu": 8083, - "zbw": 8084, - "zca": 8085, - "zcd": 8086, - "zch": 8087, - "zdj": 8088, - "zea": 8089, - "zeg": 8090, - "zeh": 8091, - "zen": 8092, - "zga": 8093, - "zgb": 8094, - "zgh": 8095, - "zgm": 8096, - "zgn": 8097, - "zgr": 8098, - "zhb": 8099, - "zhd": 8100, - "zhi": 8101, - "zhn": 8102, - "zhw": 8103, - "zhx": 8104, - "zia": 8105, - "zib": 8106, - "zik": 8107, - "zil": 8108, - "zim": 8109, - "zin": 8110, - "zir": 8111, - "ziw": 8112, - "ziz": 8113, - "zka": 8114, - "zkb": 8115, - "zkd": 8116, - "zkg": 8117, - "zkh": 8118, - "zkk": 8119, - "zkn": 8120, - "zko": 8121, - "zkp": 8122, - "zkr": 8123, - "zkt": 8124, - "zku": 8125, - "zkv": 8126, - "zkz": 8127, - "zla": 8128, - "zle": 8129, - "zlj": 8130, - "zlm": 8131, - "zln": 8132, - "zlq": 8133, - "zls": 8134, - "zlw": 8135, - "zma": 8136, - "zmb": 8137, - "zmc": 8138, - "zmd": 8139, - "zme": 8140, - "zmf": 8141, - "zmg": 8142, - "zmh": 8143, - "zmi": 8144, - "zmj": 8145, - "zmk": 8146, - "zml": 8147, - "zmm": 8148, - "zmn": 8149, - "zmo": 8150, - "zmp": 8151, - "zmq": 8152, - "zmr": 8153, - "zms": 8154, - "zmt": 8155, - "zmu": 8156, - "zmv": 8157, - "zmw": 8158, - "zmx": 8159, - "zmy": 8160, - "zmz": 8161, - "zna": 8162, - "znd": 8163, - "zne": 8164, - "zng": 8165, - "znk": 8166, - "zns": 8167, - "zoc": 8168, - "zoh": 8169, - "zom": 8170, - "zoo": 8171, - "zoq": 8172, - "zor": 8173, - "zos": 8174, - "zpa": 8175, - "zpb": 8176, - "zpc": 8177, - "zpd": 8178, - "zpe": 8179, - "zpf": 8180, - "zpg": 8181, - "zph": 8182, - "zpi": 8183, - "zpj": 8184, - "zpk": 8185, - "zpl": 8186, - "zpm": 8187, - "zpn": 8188, - "zpo": 8189, - "zpp": 8190, - "zpq": 8191, - "zpr": 8192, - "zps": 8193, - "zpt": 8194, - "zpu": 8195, - "zpv": 8196, - "zpw": 8197, - "zpx": 8198, - "zpy": 8199, - "zpz": 8200, - "zqe": 8201, - "zra": 8202, - "zrg": 8203, - "zrn": 8204, - "zro": 8205, - "zrp": 8206, - "zrs": 8207, - "zsa": 8208, - "zsk": 8209, - "zsl": 8210, - "zsm": 8211, - "zsr": 8212, - "zsu": 8213, - "zte": 8214, - "ztg": 8215, - "ztl": 8216, - "ztm": 8217, - "ztn": 8218, - "ztp": 8219, - "ztq": 8220, - "zts": 8221, - "ztt": 8222, - "ztu": 8223, - "ztx": 8224, - "zty": 8225, - "zua": 8226, - "zuh": 8227, - "zum": 8228, - "zun": 8229, - "zuy": 8230, - "zwa": 8231, - "zxx": 8232, - "zyb": 8233, - "zyg": 8234, - "zyj": 8235, - "zyn": 8236, - "zyp": 8237, - "zza": 8238, - "zzj": 8239 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/macrolanguage.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/macrolanguage.json deleted file mode 100644 index ee02241..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/macrolanguage.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "ak": 4, - "ar": 7, - "ay": 10, - "az": 11, - "cr": 26, - "et": 40, - "fa": 42, - "ff": 43, - "gn": 52, - "ik": 69, - "iu": 74, - "kg": 81, - "kr": 89, - "ku": 91, - "kv": 92, - "lv": 103, - "mg": 104, - "mn": 109, - "ms": 112, - "ne": 118, - "no": 122, - "oj": 127, - "om": 128, - "or": 129, - "ps": 134, - "qu": 136, - "sc": 143, - "sh": 147, - "sq": 154, - "sw": 160, - "uz": 178, - "yi": 185, - "za": 187, - "zh": 188, - "bal": 721, - "bik": 919, - "bnc": 1038, - "bua": 1209, - "chm": 1460, - "del": 1764, - "den": 1766, - "din": 1818, - "doi": 1897, - "gba": 2248, - "gon": 2446, - "grb": 2468, - "hai": 2579, - "hmn": 2658, - "jrb": 3046, - "kln": 3360, - "kok": 3433, - "kpe": 3450, - "lah": 3734, - "luy": 4048, - "man": 4084, - "mwr": 4634, - "raj": 5821, - "rom": 5928, - "syr": 6481, - "tmh": 6754, - "zap": 8067, - "zza": 8238 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/meta.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/meta.json deleted file mode 100644 index aff7361..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/meta.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "File-Date": "2022-06-28" -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/private-use.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/private-use.json deleted file mode 100644 index 7c14712..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/private-use.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "qaa..qtz": 5754 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/redundant.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/redundant.json deleted file mode 100644 index 23202d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/redundant.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "az-arab": 9143, - "az-cyrl": 9144, - "az-latn": 9145, - "be-latn": 9146, - "bs-cyrl": 9147, - "bs-latn": 9148, - "de-1901": 9149, - "de-1996": 9150, - "de-at-1901": 9151, - "de-at-1996": 9152, - "de-ch-1901": 9153, - "de-ch-1996": 9154, - "de-de-1901": 9155, - "de-de-1996": 9156, - "en-boont": 9157, - "en-scouse": 9158, - "es-419": 9159, - "iu-cans": 9160, - "iu-latn": 9161, - "mn-cyrl": 9162, - "mn-mong": 9163, - "sgn-br": 9164, - "sgn-co": 9165, - "sgn-de": 9166, - "sgn-dk": 9167, - "sgn-es": 9168, - "sgn-fr": 9169, - "sgn-gb": 9170, - "sgn-gr": 9171, - "sgn-ie": 9172, - "sgn-it": 9173, - "sgn-jp": 9174, - "sgn-mx": 9175, - "sgn-ni": 9176, - "sgn-nl": 9177, - "sgn-no": 9178, - "sgn-pt": 9179, - "sgn-se": 9180, - "sgn-us": 9181, - "sgn-za": 9182, - "sl-nedis": 9183, - "sl-rozaj": 9184, - "sr-cyrl": 9185, - "sr-latn": 9186, - "tg-arab": 9187, - "tg-cyrl": 9188, - "uz-cyrl": 9189, - "uz-latn": 9190, - "yi-latn": 9191, - "zh-cmn": 9192, - "zh-cmn-hans": 9193, - "zh-cmn-hant": 9194, - "zh-gan": 9195, - "zh-hans": 9196, - "zh-hans-cn": 9197, - "zh-hans-hk": 9198, - "zh-hans-mo": 9199, - "zh-hans-sg": 9200, - "zh-hans-tw": 9201, - "zh-hant": 9202, - "zh-hant-cn": 9203, - "zh-hant-hk": 9204, - "zh-hant-mo": 9205, - "zh-hant-sg": 9206, - "zh-hant-tw": 9207, - "zh-wuu": 9208, - "zh-yue": 9209 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/region.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/region.json deleted file mode 100644 index cd24023..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/region.json +++ /dev/null @@ -1,306 +0,0 @@ -{ - "142": 8999, - "143": 9000, - "145": 9001, - "150": 9002, - "151": 9003, - "154": 9004, - "155": 9005, - "202": 9006, - "419": 9007, - "aa": 8704, - "ac": 8705, - "ad": 8706, - "ae": 8707, - "af": 8708, - "ag": 8709, - "ai": 8710, - "al": 8711, - "am": 8712, - "an": 8713, - "ao": 8714, - "aq": 8715, - "ar": 8716, - "as": 8717, - "at": 8718, - "au": 8719, - "aw": 8720, - "ax": 8721, - "az": 8722, - "ba": 8723, - "bb": 8724, - "bd": 8725, - "be": 8726, - "bf": 8727, - "bg": 8728, - "bh": 8729, - "bi": 8730, - "bj": 8731, - "bl": 8732, - "bm": 8733, - "bn": 8734, - "bo": 8735, - "bq": 8736, - "br": 8737, - "bs": 8738, - "bt": 8739, - "bu": 8740, - "bv": 8741, - "bw": 8742, - "by": 8743, - "bz": 8744, - "ca": 8745, - "cc": 8746, - "cd": 8747, - "cf": 8748, - "cg": 8749, - "ch": 8750, - "ci": 8751, - "ck": 8752, - "cl": 8753, - "cm": 8754, - "cn": 8755, - "co": 8756, - "cp": 8757, - "cr": 8758, - "cs": 8759, - "cu": 8760, - "cv": 8761, - "cw": 8762, - "cx": 8763, - "cy": 8764, - "cz": 8765, - "dd": 8766, - "de": 8767, - "dg": 8768, - "dj": 8769, - "dk": 8770, - "dm": 8771, - "do": 8772, - "dz": 8773, - "ea": 8774, - "ec": 8775, - "ee": 8776, - "eg": 8777, - "eh": 8778, - "er": 8779, - "es": 8780, - "et": 8781, - "eu": 8782, - "ez": 8783, - "fi": 8784, - "fj": 8785, - "fk": 8786, - "fm": 8787, - "fo": 8788, - "fr": 8789, - "fx": 8790, - "ga": 8791, - "gb": 8792, - "gd": 8793, - "ge": 8794, - "gf": 8795, - "gg": 8796, - "gh": 8797, - "gi": 8798, - "gl": 8799, - "gm": 8800, - "gn": 8801, - "gp": 8802, - "gq": 8803, - "gr": 8804, - "gs": 8805, - "gt": 8806, - "gu": 8807, - "gw": 8808, - "gy": 8809, - "hk": 8810, - "hm": 8811, - "hn": 8812, - "hr": 8813, - "ht": 8814, - "hu": 8815, - "ic": 8816, - "id": 8817, - "ie": 8818, - "il": 8819, - "im": 8820, - "in": 8821, - "io": 8822, - "iq": 8823, - "ir": 8824, - "is": 8825, - "it": 8826, - "je": 8827, - "jm": 8828, - "jo": 8829, - "jp": 8830, - "ke": 8831, - "kg": 8832, - "kh": 8833, - "ki": 8834, - "km": 8835, - "kn": 8836, - "kp": 8837, - "kr": 8838, - "kw": 8839, - "ky": 8840, - "kz": 8841, - "la": 8842, - "lb": 8843, - "lc": 8844, - "li": 8845, - "lk": 8846, - "lr": 8847, - "ls": 8848, - "lt": 8849, - "lu": 8850, - "lv": 8851, - "ly": 8852, - "ma": 8853, - "mc": 8854, - "md": 8855, - "me": 8856, - "mf": 8857, - "mg": 8858, - "mh": 8859, - "mk": 8860, - "ml": 8861, - "mm": 8862, - "mn": 8863, - "mo": 8864, - "mp": 8865, - "mq": 8866, - "mr": 8867, - "ms": 8868, - "mt": 8869, - "mu": 8870, - "mv": 8871, - "mw": 8872, - "mx": 8873, - "my": 8874, - "mz": 8875, - "na": 8876, - "nc": 8877, - "ne": 8878, - "nf": 8879, - "ng": 8880, - "ni": 8881, - "nl": 8882, - "no": 8883, - "np": 8884, - "nr": 8885, - "nt": 8886, - "nu": 8887, - "nz": 8888, - "om": 8889, - "pa": 8890, - "pe": 8891, - "pf": 8892, - "pg": 8893, - "ph": 8894, - "pk": 8895, - "pl": 8896, - "pm": 8897, - "pn": 8898, - "pr": 8899, - "ps": 8900, - "pt": 8901, - "pw": 8902, - "py": 8903, - "qa": 8904, - "qm..qz": 8905, - "re": 8906, - "ro": 8907, - "rs": 8908, - "ru": 8909, - "rw": 8910, - "sa": 8911, - "sb": 8912, - "sc": 8913, - "sd": 8914, - "se": 8915, - "sg": 8916, - "sh": 8917, - "si": 8918, - "sj": 8919, - "sk": 8920, - "sl": 8921, - "sm": 8922, - "sn": 8923, - "so": 8924, - "sr": 8925, - "ss": 8926, - "st": 8927, - "su": 8928, - "sv": 8929, - "sx": 8930, - "sy": 8931, - "sz": 8932, - "ta": 8933, - "tc": 8934, - "td": 8935, - "tf": 8936, - "tg": 8937, - "th": 8938, - "tj": 8939, - "tk": 8940, - "tl": 8941, - "tm": 8942, - "tn": 8943, - "to": 8944, - "tp": 8945, - "tr": 8946, - "tt": 8947, - "tv": 8948, - "tw": 8949, - "tz": 8950, - "ua": 8951, - "ug": 8952, - "um": 8953, - "un": 8954, - "us": 8955, - "uy": 8956, - "uz": 8957, - "va": 8958, - "vc": 8959, - "ve": 8960, - "vg": 8961, - "vi": 8962, - "vn": 8963, - "vu": 8964, - "wf": 8965, - "ws": 8966, - "xa..xz": 8967, - "yd": 8968, - "ye": 8969, - "yt": 8970, - "yu": 8971, - "za": 8972, - "zm": 8973, - "zr": 8974, - "zw": 8975, - "zz": 8976, - "001": 8977, - "002": 8978, - "003": 8979, - "005": 8980, - "009": 8981, - "011": 8982, - "013": 8983, - "014": 8984, - "015": 8985, - "017": 8986, - "018": 8987, - "019": 8988, - "021": 8989, - "029": 8990, - "030": 8991, - "034": 8992, - "035": 8993, - "039": 8994, - "053": 8995, - "054": 8996, - "057": 8997, - "061": 8998 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/registry.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/registry.json deleted file mode 100644 index 5ed1a85..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/registry.json +++ /dev/null @@ -1,77276 +0,0 @@ -[ - { - "Type": "language", - "Subtag": "aa", - "Description": [ - "Afar" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ab", - "Description": [ - "Abkhazian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "ae", - "Description": [ - "Avestan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "af", - "Description": [ - "Afrikaans" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ak", - "Description": [ - "Akan" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "am", - "Description": [ - "Amharic" - ], - "Added": "2005-10-16", - "Suppress-Script": "Ethi" - }, - { - "Type": "language", - "Subtag": "an", - "Description": [ - "Aragonese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ar", - "Description": [ - "Arabic" - ], - "Added": "2005-10-16", - "Suppress-Script": "Arab", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "as", - "Description": [ - "Assamese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Beng" - }, - { - "Type": "language", - "Subtag": "av", - "Description": [ - "Avaric" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ay", - "Description": [ - "Aymara" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "az", - "Description": [ - "Azerbaijani" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ba", - "Description": [ - "Bashkir" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "be", - "Description": [ - "Belarusian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "bg", - "Description": [ - "Bulgarian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "bh", - "Description": [ - "Bihari languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "bi", - "Description": [ - "Bislama" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bm", - "Description": [ - "Bambara" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bn", - "Description": [ - "Bengali", - "Bangla" - ], - "Added": "2005-10-16", - "Suppress-Script": "Beng" - }, - { - "Type": "language", - "Subtag": "bo", - "Description": [ - "Tibetan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "br", - "Description": [ - "Breton" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bs", - "Description": [ - "Bosnian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Macrolanguage": "sh" - }, - { - "Type": "language", - "Subtag": "ca", - "Description": [ - "Catalan", - "Valencian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ce", - "Description": [ - "Chechen" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ch", - "Description": [ - "Chamorro" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "co", - "Description": [ - "Corsican" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cr", - "Description": [ - "Cree" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "cs", - "Description": [ - "Czech" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "cu", - "Description": [ - "Church Slavic", - "Church Slavonic", - "Old Bulgarian", - "Old Church Slavonic", - "Old Slavonic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cv", - "Description": [ - "Chuvash" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cy", - "Description": [ - "Welsh" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "da", - "Description": [ - "Danish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "de", - "Description": [ - "German" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "dv", - "Description": [ - "Dhivehi", - "Divehi", - "Maldivian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Thaa" - }, - { - "Type": "language", - "Subtag": "dz", - "Description": [ - "Dzongkha" - ], - "Added": "2005-10-16", - "Suppress-Script": "Tibt" - }, - { - "Type": "language", - "Subtag": "ee", - "Description": [ - "Ewe" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "el", - "Description": [ - "Modern Greek (1453-)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Grek" - }, - { - "Type": "language", - "Subtag": "en", - "Description": [ - "English" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "eo", - "Description": [ - "Esperanto" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "es", - "Description": [ - "Spanish", - "Castilian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "et", - "Description": [ - "Estonian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "eu", - "Description": [ - "Basque" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "fa", - "Description": [ - "Persian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Arab", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ff", - "Description": [ - "Fulah" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "fi", - "Description": [ - "Finnish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "fj", - "Description": [ - "Fijian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "fo", - "Description": [ - "Faroese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "fr", - "Description": [ - "French" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "fy", - "Description": [ - "Western Frisian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ga", - "Description": [ - "Irish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "gd", - "Description": [ - "Scottish Gaelic", - "Gaelic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gl", - "Description": [ - "Galician" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "gn", - "Description": [ - "Guarani" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "gu", - "Description": [ - "Gujarati" - ], - "Added": "2005-10-16", - "Suppress-Script": "Gujr" - }, - { - "Type": "language", - "Subtag": "gv", - "Description": [ - "Manx" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ha", - "Description": [ - "Hausa" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "he", - "Description": [ - "Hebrew" - ], - "Added": "2005-10-16", - "Suppress-Script": "Hebr" - }, - { - "Type": "language", - "Subtag": "hi", - "Description": [ - "Hindi" - ], - "Added": "2005-10-16", - "Suppress-Script": "Deva" - }, - { - "Type": "language", - "Subtag": "ho", - "Description": [ - "Hiri Motu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "hr", - "Description": [ - "Croatian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Macrolanguage": "sh" - }, - { - "Type": "language", - "Subtag": "ht", - "Description": [ - "Haitian", - "Haitian Creole" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "hu", - "Description": [ - "Hungarian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "hy", - "Description": [ - "Armenian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Armn", - "Comments": [ - "see also hyw" - ] - }, - { - "Type": "language", - "Subtag": "hz", - "Description": [ - "Herero" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ia", - "Description": [ - "Interlingua (International Auxiliary Language Association)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "id", - "Description": [ - "Indonesian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "ie", - "Description": [ - "Interlingue", - "Occidental" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ig", - "Description": [ - "Igbo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ii", - "Description": [ - "Sichuan Yi", - "Nuosu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ik", - "Description": [ - "Inupiaq" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "in", - "Description": [ - "Indonesian" - ], - "Added": "2005-10-16", - "Deprecated": "1989-01-01", - "Preferred-Value": "id", - "Suppress-Script": "Latn", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "io", - "Description": [ - "Ido" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "is", - "Description": [ - "Icelandic" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "it", - "Description": [ - "Italian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "iu", - "Description": [ - "Inuktitut" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "iw", - "Description": [ - "Hebrew" - ], - "Added": "2005-10-16", - "Deprecated": "1989-01-01", - "Preferred-Value": "he", - "Suppress-Script": "Hebr" - }, - { - "Type": "language", - "Subtag": "ja", - "Description": [ - "Japanese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Jpan" - }, - { - "Type": "language", - "Subtag": "ji", - "Description": [ - "Yiddish" - ], - "Added": "2005-10-16", - "Deprecated": "1989-01-01", - "Preferred-Value": "yi" - }, - { - "Type": "language", - "Subtag": "jv", - "Description": [ - "Javanese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "jw", - "Description": [ - "Javanese" - ], - "Added": "2005-10-16", - "Deprecated": "2001-08-13", - "Preferred-Value": "jv", - "Comments": [ - "published by error in Table 1 of ISO 639:1988" - ] - }, - { - "Type": "language", - "Subtag": "ka", - "Description": [ - "Georgian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Geor" - }, - { - "Type": "language", - "Subtag": "kg", - "Description": [ - "Kongo" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ki", - "Description": [ - "Kikuyu", - "Gikuyu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kj", - "Description": [ - "Kuanyama", - "Kwanyama" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kk", - "Description": [ - "Kazakh" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "kl", - "Description": [ - "Kalaallisut", - "Greenlandic" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "km", - "Description": [ - "Khmer", - "Central Khmer" - ], - "Added": "2005-10-16", - "Suppress-Script": "Khmr" - }, - { - "Type": "language", - "Subtag": "kn", - "Description": [ - "Kannada" - ], - "Added": "2005-10-16", - "Suppress-Script": "Knda" - }, - { - "Type": "language", - "Subtag": "ko", - "Description": [ - "Korean" - ], - "Added": "2005-10-16", - "Suppress-Script": "Kore" - }, - { - "Type": "language", - "Subtag": "kr", - "Description": [ - "Kanuri" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ks", - "Description": [ - "Kashmiri" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ku", - "Description": [ - "Kurdish" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "kv", - "Description": [ - "Komi" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "kw", - "Description": [ - "Cornish" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ky", - "Description": [ - "Kirghiz", - "Kyrgyz" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "la", - "Description": [ - "Latin" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "lb", - "Description": [ - "Luxembourgish", - "Letzeburgesch" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "lg", - "Description": [ - "Ganda", - "Luganda" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "li", - "Description": [ - "Limburgan", - "Limburger", - "Limburgish" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ln", - "Description": [ - "Lingala" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "lo", - "Description": [ - "Lao" - ], - "Added": "2005-10-16", - "Suppress-Script": "Laoo" - }, - { - "Type": "language", - "Subtag": "lt", - "Description": [ - "Lithuanian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "lu", - "Description": [ - "Luba-Katanga" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lv", - "Description": [ - "Latvian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "mg", - "Description": [ - "Malagasy" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "mh", - "Description": [ - "Marshallese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "mi", - "Description": [ - "Maori" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mk", - "Description": [ - "Macedonian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "ml", - "Description": [ - "Malayalam" - ], - "Added": "2005-10-16", - "Suppress-Script": "Mlym" - }, - { - "Type": "language", - "Subtag": "mn", - "Description": [ - "Mongolian" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "mo", - "Description": [ - "Moldavian", - "Moldovan" - ], - "Added": "2005-10-16", - "Deprecated": "2008-11-22", - "Preferred-Value": "ro", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "mr", - "Description": [ - "Marathi" - ], - "Added": "2005-10-16", - "Suppress-Script": "Deva" - }, - { - "Type": "language", - "Subtag": "ms", - "Description": [ - "Malay (macrolanguage)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "mt", - "Description": [ - "Maltese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "my", - "Description": [ - "Burmese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Mymr" - }, - { - "Type": "language", - "Subtag": "na", - "Description": [ - "Nauru" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "nb", - "Description": [ - "Norwegian BokmÃ¥l" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Macrolanguage": "no" - }, - { - "Type": "language", - "Subtag": "nd", - "Description": [ - "North Ndebele" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ne", - "Description": [ - "Nepali (macrolanguage)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Deva", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ng", - "Description": [ - "Ndonga" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nl", - "Description": [ - "Dutch", - "Flemish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "nn", - "Description": [ - "Norwegian Nynorsk" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Macrolanguage": "no" - }, - { - "Type": "language", - "Subtag": "no", - "Description": [ - "Norwegian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "nr", - "Description": [ - "South Ndebele" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "nv", - "Description": [ - "Navajo", - "Navaho" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ny", - "Description": [ - "Nyanja", - "Chewa", - "Chichewa" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "oc", - "Description": [ - "Occitan (post 1500)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "oj", - "Description": [ - "Ojibwa" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "om", - "Description": [ - "Oromo" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "or", - "Description": [ - "Oriya (macrolanguage)", - "Odia (macrolanguage)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Orya", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "os", - "Description": [ - "Ossetian", - "Ossetic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pa", - "Description": [ - "Panjabi", - "Punjabi" - ], - "Added": "2005-10-16", - "Suppress-Script": "Guru" - }, - { - "Type": "language", - "Subtag": "pi", - "Description": [ - "Pali" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pl", - "Description": [ - "Polish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ps", - "Description": [ - "Pushto", - "Pashto" - ], - "Added": "2005-10-16", - "Suppress-Script": "Arab", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "pt", - "Description": [ - "Portuguese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "qu", - "Description": [ - "Quechua" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "rm", - "Description": [ - "Romansh" - ], - "Suppress-Script": "Latn", - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "rn", - "Description": [ - "Rundi" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ro", - "Description": [ - "Romanian", - "Moldavian", - "Moldovan" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ru", - "Description": [ - "Russian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "rw", - "Description": [ - "Kinyarwanda" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sa", - "Description": [ - "Sanskrit" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sc", - "Description": [ - "Sardinian" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "sd", - "Description": [ - "Sindhi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "se", - "Description": [ - "Northern Sami" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sg", - "Description": [ - "Sango" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sh", - "Description": [ - "Serbo-Croatian" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage", - "Comments": [ - "sr, hr, bs are preferred for most modern uses" - ] - }, - { - "Type": "language", - "Subtag": "si", - "Description": [ - "Sinhala", - "Sinhalese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Sinh" - }, - { - "Type": "language", - "Subtag": "sk", - "Description": [ - "Slovak" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sl", - "Description": [ - "Slovenian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sm", - "Description": [ - "Samoan" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sn", - "Description": [ - "Shona" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "so", - "Description": [ - "Somali" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sq", - "Description": [ - "Albanian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "sr", - "Description": [ - "Serbian" - ], - "Added": "2005-10-16", - "Macrolanguage": "sh", - "Comments": [ - "see cnr for Montenegrin" - ] - }, - { - "Type": "language", - "Subtag": "ss", - "Description": [ - "Swati" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "st", - "Description": [ - "Southern Sotho" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "su", - "Description": [ - "Sundanese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sv", - "Description": [ - "Swedish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "sw", - "Description": [ - "Swahili (macrolanguage)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ta", - "Description": [ - "Tamil" - ], - "Added": "2005-10-16", - "Suppress-Script": "Taml" - }, - { - "Type": "language", - "Subtag": "te", - "Description": [ - "Telugu" - ], - "Added": "2005-10-16", - "Suppress-Script": "Telu" - }, - { - "Type": "language", - "Subtag": "tg", - "Description": [ - "Tajik" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "th", - "Description": [ - "Thai" - ], - "Added": "2005-10-16", - "Suppress-Script": "Thai" - }, - { - "Type": "language", - "Subtag": "ti", - "Description": [ - "Tigrinya" - ], - "Added": "2005-10-16", - "Suppress-Script": "Ethi" - }, - { - "Type": "language", - "Subtag": "tk", - "Description": [ - "Turkmen" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tl", - "Description": [ - "Tagalog" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tn", - "Description": [ - "Tswana" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "to", - "Description": [ - "Tonga (Tonga Islands)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tr", - "Description": [ - "Turkish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ts", - "Description": [ - "Tsonga" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tt", - "Description": [ - "Tatar" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tw", - "Description": [ - "Twi" - ], - "Added": "2005-10-16", - "Macrolanguage": "ak" - }, - { - "Type": "language", - "Subtag": "ty", - "Description": [ - "Tahitian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ug", - "Description": [ - "Uighur", - "Uyghur" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "uk", - "Description": [ - "Ukrainian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Cyrl" - }, - { - "Type": "language", - "Subtag": "ur", - "Description": [ - "Urdu" - ], - "Added": "2005-10-16", - "Suppress-Script": "Arab" - }, - { - "Type": "language", - "Subtag": "uz", - "Description": [ - "Uzbek" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ve", - "Description": [ - "Venda" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "vi", - "Description": [ - "Vietnamese" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "vo", - "Description": [ - "Volapük" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "wa", - "Description": [ - "Walloon" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "wo", - "Description": [ - "Wolof" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "xh", - "Description": [ - "Xhosa" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "yi", - "Description": [ - "Yiddish" - ], - "Added": "2005-10-16", - "Suppress-Script": "Hebr", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "yo", - "Description": [ - "Yoruba" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "za", - "Description": [ - "Zhuang", - "Chuang" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "zh", - "Description": [ - "Chinese" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "zu", - "Description": [ - "Zulu" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "aaa", - "Description": [ - "Ghotuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aab", - "Description": [ - "Alumu-Tesu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aac", - "Description": [ - "Ari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aad", - "Description": [ - "Amal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aae", - "Description": [ - "Arbëreshë Albanian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sq" - }, - { - "Type": "language", - "Subtag": "aaf", - "Description": [ - "Aranadan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aag", - "Description": [ - "Ambrak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aah", - "Description": [ - "Abu' Arapesh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aai", - "Description": [ - "Arifama-Miniafia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aak", - "Description": [ - "Ankave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aal", - "Description": [ - "Afade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aam", - "Description": [ - "Aramanik" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "aas" - }, - { - "Type": "language", - "Subtag": "aan", - "Description": [ - "Anambé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aao", - "Description": [ - "Algerian Saharan Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "aap", - "Description": [ - "Pará Arára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aaq", - "Description": [ - "Eastern Abnaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aas", - "Description": [ - "Aasáx" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aat", - "Description": [ - "Arvanitika Albanian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sq" - }, - { - "Type": "language", - "Subtag": "aau", - "Description": [ - "Abau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aav", - "Description": [ - "Austro-Asiatic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aaw", - "Description": [ - "Solong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aax", - "Description": [ - "Mandobo Atas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aaz", - "Description": [ - "Amarasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aba", - "Description": [ - "Abé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abb", - "Description": [ - "Bankon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abc", - "Description": [ - "Ambala Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abd", - "Description": [ - "Manide" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abe", - "Description": [ - "Western Abnaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abf", - "Description": [ - "Abai Sungai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abg", - "Description": [ - "Abaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abh", - "Description": [ - "Tajiki Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "abi", - "Description": [ - "Abidji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abj", - "Description": [ - "Aka-Bea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abl", - "Description": [ - "Lampung Nyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abm", - "Description": [ - "Abanyom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abn", - "Description": [ - "Abua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abo", - "Description": [ - "Abon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abp", - "Description": [ - "Abellen Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abq", - "Description": [ - "Abaza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abr", - "Description": [ - "Abron" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abs", - "Description": [ - "Ambonese Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abt", - "Description": [ - "Ambulas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abu", - "Description": [ - "Abure" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abv", - "Description": [ - "Baharna Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "abw", - "Description": [ - "Pal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abx", - "Description": [ - "Inabaknon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aby", - "Description": [ - "Aneme Wake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "abz", - "Description": [ - "Abui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aca", - "Description": [ - "Achagua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acb", - "Description": [ - "Ãncá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acd", - "Description": [ - "Gikyode" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ace", - "Description": [ - "Achinese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "acf", - "Description": [ - "Saint Lucian Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ach", - "Description": [ - "Acoli" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "aci", - "Description": [ - "Aka-Cari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ack", - "Description": [ - "Aka-Kora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acl", - "Description": [ - "Akar-Bale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acm", - "Description": [ - "Mesopotamian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "acn", - "Description": [ - "Achang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acp", - "Description": [ - "Eastern Acipa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acq", - "Description": [ - "Ta'izzi-Adeni Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "acr", - "Description": [ - "Achi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acs", - "Description": [ - "Acroá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "act", - "Description": [ - "Achterhoeks" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acu", - "Description": [ - "Achuar-Shiwiar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acv", - "Description": [ - "Achumawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "acw", - "Description": [ - "Hijazi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "acx", - "Description": [ - "Omani Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "acy", - "Description": [ - "Cypriot Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "acz", - "Description": [ - "Acheron" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ada", - "Description": [ - "Adangme" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "adb", - "Description": [ - "Atauran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "add", - "Description": [ - "Lidzonka", - "Dzodinka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ade", - "Description": [ - "Adele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adf", - "Description": [ - "Dhofari Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "adg", - "Description": [ - "Andegerebinha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adh", - "Description": [ - "Adhola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adi", - "Description": [ - "Adi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adj", - "Description": [ - "Adioukrou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adl", - "Description": [ - "Galo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adn", - "Description": [ - "Adang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ado", - "Description": [ - "Abu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adp", - "Description": [ - "Adap" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "dz" - }, - { - "Type": "language", - "Subtag": "adq", - "Description": [ - "Adangbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adr", - "Description": [ - "Adonara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ads", - "Description": [ - "Adamorobe Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adt", - "Description": [ - "Adnyamathanha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adu", - "Description": [ - "Aduge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adw", - "Description": [ - "Amundava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "adx", - "Description": [ - "Amdo Tibetan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ady", - "Description": [ - "Adyghe", - "Adygei" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "adz", - "Description": [ - "Adzera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aea", - "Description": [ - "Areba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aeb", - "Description": [ - "Tunisian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "aec", - "Description": [ - "Saidi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "aed", - "Description": [ - "Argentine Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aee", - "Description": [ - "Northeast Pashai", - "Northeast Pashayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aek", - "Description": [ - "Haeke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ael", - "Description": [ - "Ambele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aem", - "Description": [ - "Arem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aen", - "Description": [ - "Armenian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aeq", - "Description": [ - "Aer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aer", - "Description": [ - "Eastern Arrernte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aes", - "Description": [ - "Alsea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aeu", - "Description": [ - "Akeu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aew", - "Description": [ - "Ambakich" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aey", - "Description": [ - "Amele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aez", - "Description": [ - "Aeka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afa", - "Description": [ - "Afro-Asiatic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "afb", - "Description": [ - "Gulf Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "afd", - "Description": [ - "Andai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afe", - "Description": [ - "Putukwam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afg", - "Description": [ - "Afghan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afh", - "Description": [ - "Afrihili" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "afi", - "Description": [ - "Akrukay", - "Chini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afk", - "Description": [ - "Nanubae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afn", - "Description": [ - "Defaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afo", - "Description": [ - "Eloyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afp", - "Description": [ - "Tapei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afs", - "Description": [ - "Afro-Seminole Creole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aft", - "Description": [ - "Afitti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afu", - "Description": [ - "Awutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "afz", - "Description": [ - "Obokuitai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aga", - "Description": [ - "Aguano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agb", - "Description": [ - "Legbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agc", - "Description": [ - "Agatu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agd", - "Description": [ - "Agarabi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "age", - "Description": [ - "Angal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agf", - "Description": [ - "Arguni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agg", - "Description": [ - "Angor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agh", - "Description": [ - "Ngelima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agi", - "Description": [ - "Agariya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agj", - "Description": [ - "Argobba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agk", - "Description": [ - "Isarog Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agl", - "Description": [ - "Fembe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agm", - "Description": [ - "Angaataha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agn", - "Description": [ - "Agutaynen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ago", - "Description": [ - "Tainae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agp", - "Description": [ - "Paranan" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see apf, prf" - ] - }, - { - "Type": "language", - "Subtag": "agq", - "Description": [ - "Aghem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agr", - "Description": [ - "Aguaruna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ags", - "Description": [ - "Esimbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agt", - "Description": [ - "Central Cagayan Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agu", - "Description": [ - "Aguacateco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agv", - "Description": [ - "Remontado Dumagat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agw", - "Description": [ - "Kahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agx", - "Description": [ - "Aghul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agy", - "Description": [ - "Southern Alta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "agz", - "Description": [ - "Mt. Iriga Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aha", - "Description": [ - "Ahanta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahb", - "Description": [ - "Axamb" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahg", - "Description": [ - "Qimant" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahh", - "Description": [ - "Aghu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahi", - "Description": [ - "Tiagbamrin Aizi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahk", - "Description": [ - "Akha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahl", - "Description": [ - "Igo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahm", - "Description": [ - "Mobumrin Aizi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahn", - "Description": [ - "Àhàn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aho", - "Description": [ - "Ahom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahp", - "Description": [ - "Aproumu Aizi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahr", - "Description": [ - "Ahirani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ahs", - "Description": [ - "Ashe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aht", - "Description": [ - "Ahtena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aia", - "Description": [ - "Arosi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aib", - "Description": [ - "Ainu (China)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aic", - "Description": [ - "Ainbai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aid", - "Description": [ - "Alngith" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aie", - "Description": [ - "Amara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aif", - "Description": [ - "Agi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aig", - "Description": [ - "Antigua and Barbuda Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aih", - "Description": [ - "Ai-Cham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aii", - "Description": [ - "Assyrian Neo-Aramaic" - ], - "Added": "2009-07-29", - "Macrolanguage": "syr" - }, - { - "Type": "language", - "Subtag": "aij", - "Description": [ - "Lishanid Noshan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aik", - "Description": [ - "Ake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ail", - "Description": [ - "Aimele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aim", - "Description": [ - "Aimol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ain", - "Description": [ - "Ainu (Japan)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "aio", - "Description": [ - "Aiton" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aip", - "Description": [ - "Burumakok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aiq", - "Description": [ - "Aimaq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "air", - "Description": [ - "Airoran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ais", - "Description": [ - "Nataoran Amis" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Comments": [ - "see ami, szy" - ] - }, - { - "Type": "language", - "Subtag": "ait", - "Description": [ - "Arikem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aiw", - "Description": [ - "Aari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aix", - "Description": [ - "Aighon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aiy", - "Description": [ - "Ali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aja", - "Description": [ - "Aja (South Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ajg", - "Description": [ - "Aja (Benin)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aji", - "Description": [ - "Ajië" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ajn", - "Description": [ - "Andajin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ajp", - "Description": [ - "South Levantine Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ajs", - "Description": [ - "Algerian Jewish Sign Language" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "ajt", - "Description": [ - "Judeo-Tunisian Arabic" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Preferred-Value": "aeb", - "Macrolanguage": "jrb" - }, - { - "Type": "language", - "Subtag": "aju", - "Description": [ - "Judeo-Moroccan Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "jrb" - }, - { - "Type": "language", - "Subtag": "ajw", - "Description": [ - "Ajawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ajz", - "Description": [ - "Amri Karbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akb", - "Description": [ - "Batak Angkola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akc", - "Description": [ - "Mpur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akd", - "Description": [ - "Ukpet-Ehom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ake", - "Description": [ - "Akawaio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akf", - "Description": [ - "Akpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akg", - "Description": [ - "Anakalangu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akh", - "Description": [ - "Angal Heneng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aki", - "Description": [ - "Aiome" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akj", - "Description": [ - "Aka-Jeru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akk", - "Description": [ - "Akkadian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "akl", - "Description": [ - "Aklanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akm", - "Description": [ - "Aka-Bo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ako", - "Description": [ - "Akurio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akp", - "Description": [ - "Siwu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akq", - "Description": [ - "Ak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akr", - "Description": [ - "Araki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aks", - "Description": [ - "Akaselem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akt", - "Description": [ - "Akolet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aku", - "Description": [ - "Akum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akv", - "Description": [ - "Akhvakh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akw", - "Description": [ - "Akwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akx", - "Description": [ - "Aka-Kede" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aky", - "Description": [ - "Aka-Kol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "akz", - "Description": [ - "Alabama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ala", - "Description": [ - "Alago" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alc", - "Description": [ - "Qawasqar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ald", - "Description": [ - "Alladian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ale", - "Description": [ - "Aleut" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "alf", - "Description": [ - "Alege" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alg", - "Description": [ - "Algonquian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "alh", - "Description": [ - "Alawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ali", - "Description": [ - "Amaimon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alj", - "Description": [ - "Alangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alk", - "Description": [ - "Alak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "all", - "Description": [ - "Allar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alm", - "Description": [ - "Amblong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aln", - "Description": [ - "Gheg Albanian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sq" - }, - { - "Type": "language", - "Subtag": "alo", - "Description": [ - "Larike-Wakasihu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alp", - "Description": [ - "Alune" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alq", - "Description": [ - "Algonquin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alr", - "Description": [ - "Alutor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "als", - "Description": [ - "Tosk Albanian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sq" - }, - { - "Type": "language", - "Subtag": "alt", - "Description": [ - "Southern Altai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "alu", - "Description": [ - "'Are'are" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alv", - "Description": [ - "Atlantic-Congo languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "alw", - "Description": [ - "Alaba-K’abeena", - "Wanbasana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alx", - "Description": [ - "Amol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aly", - "Description": [ - "Alyawarr" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "alz", - "Description": [ - "Alur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ama", - "Description": [ - "Amanayé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amb", - "Description": [ - "Ambo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amc", - "Description": [ - "Amahuaca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ame", - "Description": [ - "Yanesha'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amf", - "Description": [ - "Hamer-Banna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amg", - "Description": [ - "Amurdak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ami", - "Description": [ - "Amis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amj", - "Description": [ - "Amdang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amk", - "Description": [ - "Ambai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aml", - "Description": [ - "War-Jaintia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amm", - "Description": [ - "Ama (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amn", - "Description": [ - "Amanab" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amo", - "Description": [ - "Amo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amp", - "Description": [ - "Alamblak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amq", - "Description": [ - "Amahai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amr", - "Description": [ - "Amarakaeri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ams", - "Description": [ - "Southern Amami-Oshima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amt", - "Description": [ - "Amto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amu", - "Description": [ - "Guerrero Amuzgo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amv", - "Description": [ - "Ambelau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amw", - "Description": [ - "Western Neo-Aramaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amx", - "Description": [ - "Anmatyerre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amy", - "Description": [ - "Ami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "amz", - "Description": [ - "Atampaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ana", - "Description": [ - "Andaqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anb", - "Description": [ - "Andoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anc", - "Description": [ - "Ngas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "and", - "Description": [ - "Ansus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ane", - "Description": [ - "Xârâcùù" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anf", - "Description": [ - "Animere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ang", - "Description": [ - "Old English (ca. 450-1100)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "anh", - "Description": [ - "Nend" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ani", - "Description": [ - "Andi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anj", - "Description": [ - "Anor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ank", - "Description": [ - "Goemai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anl", - "Description": [ - "Anu-Hkongso Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anm", - "Description": [ - "Anal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ann", - "Description": [ - "Obolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ano", - "Description": [ - "Andoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anp", - "Description": [ - "Angika" - ], - "Added": "2006-03-08" - }, - { - "Type": "language", - "Subtag": "anq", - "Description": [ - "Jarawa (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anr", - "Description": [ - "Andh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ans", - "Description": [ - "Anserma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ant", - "Description": [ - "Antakarinya", - "Antikarinya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anu", - "Description": [ - "Anuak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anv", - "Description": [ - "Denya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anw", - "Description": [ - "Anaang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anx", - "Description": [ - "Andra-Hus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "any", - "Description": [ - "Anyin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "anz", - "Description": [ - "Anem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoa", - "Description": [ - "Angolar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aob", - "Description": [ - "Abom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoc", - "Description": [ - "Pemon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aod", - "Description": [ - "Andarum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoe", - "Description": [ - "Angal Enen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aof", - "Description": [ - "Bragat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aog", - "Description": [ - "Angoram" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoh", - "Description": [ - "Arma" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "aoi", - "Description": [ - "Anindilyakwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoj", - "Description": [ - "Mufian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aok", - "Description": [ - "Arhö" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aol", - "Description": [ - "Alor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aom", - "Description": [ - "Ömie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aon", - "Description": [ - "Bumbita Arapesh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aor", - "Description": [ - "Aore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aos", - "Description": [ - "Taikat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aot", - "Description": [ - "Atong (India)", - "A'tong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aou", - "Description": [ - "A'ou" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "aox", - "Description": [ - "Atorada" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aoz", - "Description": [ - "Uab Meto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apa", - "Description": [ - "Apache languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "apb", - "Description": [ - "Sa'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apc", - "Description": [ - "North Levantine Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "apd", - "Description": [ - "Sudanese Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ape", - "Description": [ - "Bukiyip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apf", - "Description": [ - "Pahanan Agta" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "apg", - "Description": [ - "Ampanang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aph", - "Description": [ - "Athpariya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "api", - "Description": [ - "Apiaká" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apj", - "Description": [ - "Jicarilla Apache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apk", - "Description": [ - "Kiowa Apache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apl", - "Description": [ - "Lipan Apache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apm", - "Description": [ - "Mescalero-Chiricahua Apache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apn", - "Description": [ - "Apinayé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apo", - "Description": [ - "Ambul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "app", - "Description": [ - "Apma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apq", - "Description": [ - "A-Pucikwar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apr", - "Description": [ - "Arop-Lokep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aps", - "Description": [ - "Arop-Sissano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apt", - "Description": [ - "Apatani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apu", - "Description": [ - "Apurinã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apv", - "Description": [ - "Alapmunte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apw", - "Description": [ - "Western Apache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apx", - "Description": [ - "Aputai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apy", - "Description": [ - "Apalaí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "apz", - "Description": [ - "Safeyoka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqa", - "Description": [ - "Alacalufan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aqc", - "Description": [ - "Archi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqd", - "Description": [ - "Ampari Dogon" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "aqg", - "Description": [ - "Arigidi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqk", - "Description": [ - "Aninka" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "aql", - "Description": [ - "Algic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aqm", - "Description": [ - "Atohwaim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqn", - "Description": [ - "Northern Alta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqp", - "Description": [ - "Atakapa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqr", - "Description": [ - "Arhâ" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aqt", - "Description": [ - "Angaité" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "aqz", - "Description": [ - "Akuntsu" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "arb", - "Description": [ - "Standard Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "arc", - "Description": [ - "Official Aramaic (700-300 BCE)", - "Imperial Aramaic (700-300 BCE)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ard", - "Description": [ - "Arabana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "are", - "Description": [ - "Western Arrarnta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arh", - "Description": [ - "Arhuaco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ari", - "Description": [ - "Arikara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arj", - "Description": [ - "Arapaso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ark", - "Description": [ - "Arikapú" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arl", - "Description": [ - "Arabela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arn", - "Description": [ - "Mapudungun", - "Mapuche" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "aro", - "Description": [ - "Araona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arp", - "Description": [ - "Arapaho" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "arq", - "Description": [ - "Algerian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "arr", - "Description": [ - "Karo (Brazil)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ars", - "Description": [ - "Najdi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "art", - "Description": [ - "Artificial languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aru", - "Description": [ - "Aruá (Amazonas State)", - "Arawá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arv", - "Description": [ - "Arbore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "arw", - "Description": [ - "Arawak" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "arx", - "Description": [ - "Aruá (Rodonia State)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ary", - "Description": [ - "Moroccan Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "arz", - "Description": [ - "Egyptian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "asa", - "Description": [ - "Asu (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asb", - "Description": [ - "Assiniboine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asc", - "Description": [ - "Casuarina Coast Asmat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asd", - "Description": [ - "Asas" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Preferred-Value": "snz" - }, - { - "Type": "language", - "Subtag": "ase", - "Description": [ - "American Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asf", - "Description": [ - "Auslan", - "Australian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asg", - "Description": [ - "Cishingini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ash", - "Description": [ - "Abishira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asi", - "Description": [ - "Buruwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asj", - "Description": [ - "Sari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ask", - "Description": [ - "Ashkun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asl", - "Description": [ - "Asilulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asn", - "Description": [ - "Xingú Asuriní" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aso", - "Description": [ - "Dano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asp", - "Description": [ - "Algerian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asq", - "Description": [ - "Austrian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asr", - "Description": [ - "Asuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ass", - "Description": [ - "Ipulo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ast", - "Description": [ - "Asturian", - "Asturleonese", - "Bable", - "Leonese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "asu", - "Description": [ - "Tocantins Asurini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asv", - "Description": [ - "Asoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asw", - "Description": [ - "Australian Aborigines Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asx", - "Description": [ - "Muratayak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asy", - "Description": [ - "Yaosakor Asmat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "asz", - "Description": [ - "As" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ata", - "Description": [ - "Pele-Ata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atb", - "Description": [ - "Zaiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atc", - "Description": [ - "Atsahuaca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atd", - "Description": [ - "Ata Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ate", - "Description": [ - "Atemble" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atg", - "Description": [ - "Ivbie North-Okpela-Arhe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ath", - "Description": [ - "Athapascan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ati", - "Description": [ - "Attié" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atj", - "Description": [ - "Atikamekw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atk", - "Description": [ - "Ati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atl", - "Description": [ - "Mt. Iraya Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atm", - "Description": [ - "Ata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atn", - "Description": [ - "Ashtiani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ato", - "Description": [ - "Atong (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atp", - "Description": [ - "Pudtol Atta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atq", - "Description": [ - "Aralle-Tabulahan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atr", - "Description": [ - "Waimiri-Atroari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ats", - "Description": [ - "Gros Ventre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "att", - "Description": [ - "Pamplona Atta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atu", - "Description": [ - "Reel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atv", - "Description": [ - "Northern Altai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atw", - "Description": [ - "Atsugewi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atx", - "Description": [ - "Arutani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aty", - "Description": [ - "Aneityum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "atz", - "Description": [ - "Arta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aua", - "Description": [ - "Asumboa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aub", - "Description": [ - "Alugu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auc", - "Description": [ - "Waorani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aud", - "Description": [ - "Anuta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aue", - "Description": [ - "Ç‚KxʼauÇʼein" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "ktz" - }, - { - "Type": "language", - "Subtag": "auf", - "Description": [ - "Arauan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aug", - "Description": [ - "Aguna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auh", - "Description": [ - "Aushi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aui", - "Description": [ - "Anuki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auj", - "Description": [ - "Awjilah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auk", - "Description": [ - "Heyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aul", - "Description": [ - "Aulua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aum", - "Description": [ - "Asu (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aun", - "Description": [ - "Molmo One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auo", - "Description": [ - "Auyokawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aup", - "Description": [ - "Makayam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auq", - "Description": [ - "Anus", - "Korur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aur", - "Description": [ - "Aruek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aus", - "Description": [ - "Australian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "aut", - "Description": [ - "Austral" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auu", - "Description": [ - "Auye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auw", - "Description": [ - "Awyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aux", - "Description": [ - "Aurá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auy", - "Description": [ - "Awiyaana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "auz", - "Description": [ - "Uzbeki Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "avb", - "Description": [ - "Avau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avd", - "Description": [ - "Alviri-Vidari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avi", - "Description": [ - "Avikam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avk", - "Description": [ - "Kotava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avl", - "Description": [ - "Eastern Egyptian Bedawi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "avm", - "Description": [ - "Angkamuthi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "avn", - "Description": [ - "Avatime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avo", - "Description": [ - "Agavotaguerra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avs", - "Description": [ - "Aushiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avt", - "Description": [ - "Au" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avu", - "Description": [ - "Avokaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "avv", - "Description": [ - "Avá-Canoeiro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awa", - "Description": [ - "Awadhi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "awb", - "Description": [ - "Awa (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awc", - "Description": [ - "Cicipu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awd", - "Description": [ - "Arawakan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "awe", - "Description": [ - "Awetí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awg", - "Description": [ - "Anguthimri" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "awh", - "Description": [ - "Awbono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awi", - "Description": [ - "Aekyom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awk", - "Description": [ - "Awabakal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awm", - "Description": [ - "Arawum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awn", - "Description": [ - "Awngi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awo", - "Description": [ - "Awak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awr", - "Description": [ - "Awera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aws", - "Description": [ - "South Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awt", - "Description": [ - "Araweté" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awu", - "Description": [ - "Central Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awv", - "Description": [ - "Jair Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aww", - "Description": [ - "Awun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awx", - "Description": [ - "Awara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "awy", - "Description": [ - "Edera Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "axb", - "Description": [ - "Abipon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "axe", - "Description": [ - "Ayerrerenge" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "axg", - "Description": [ - "Mato Grosso Arára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "axk", - "Description": [ - "Yaka (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "axl", - "Description": [ - "Lower Southern Aranda" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "axm", - "Description": [ - "Middle Armenian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "axx", - "Description": [ - "Xârâgurè" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aya", - "Description": [ - "Awar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayb", - "Description": [ - "Ayizo Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayc", - "Description": [ - "Southern Aymara" - ], - "Added": "2009-07-29", - "Macrolanguage": "ay" - }, - { - "Type": "language", - "Subtag": "ayd", - "Description": [ - "Ayabadhu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aye", - "Description": [ - "Ayere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayg", - "Description": [ - "Ginyanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayh", - "Description": [ - "Hadrami Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ayi", - "Description": [ - "Leyigha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayk", - "Description": [ - "Akuku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayl", - "Description": [ - "Libyan Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ayn", - "Description": [ - "Sanaani Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ayo", - "Description": [ - "Ayoreo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayp", - "Description": [ - "North Mesopotamian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ayq", - "Description": [ - "Ayi (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayr", - "Description": [ - "Central Aymara" - ], - "Added": "2009-07-29", - "Macrolanguage": "ay" - }, - { - "Type": "language", - "Subtag": "ays", - "Description": [ - "Sorsogon Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayt", - "Description": [ - "Magbukun Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayu", - "Description": [ - "Ayu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ayx", - "Description": [ - "Ayi (China)" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Preferred-Value": "nun" - }, - { - "Type": "language", - "Subtag": "ayy", - "Description": [ - "Tayabas Ayta" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ayz", - "Description": [ - "Mai Brat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "aza", - "Description": [ - "Azha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "azb", - "Description": [ - "South Azerbaijani" - ], - "Added": "2009-07-29", - "Macrolanguage": "az" - }, - { - "Type": "language", - "Subtag": "azc", - "Description": [ - "Uto-Aztecan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "azd", - "Description": [ - "Eastern Durango Nahuatl" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "azg", - "Description": [ - "San Pedro Amuzgos Amuzgo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "azj", - "Description": [ - "North Azerbaijani" - ], - "Added": "2009-07-29", - "Macrolanguage": "az" - }, - { - "Type": "language", - "Subtag": "azm", - "Description": [ - "Ipalapa Amuzgo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "azn", - "Description": [ - "Western Durango Nahuatl" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "azo", - "Description": [ - "Awing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "azt", - "Description": [ - "Faire Atta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "azz", - "Description": [ - "Highland Puebla Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "baa", - "Description": [ - "Babatana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bab", - "Description": [ - "Bainouk-Gunyuño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bac", - "Description": [ - "Badui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bad", - "Description": [ - "Banda languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "bae", - "Description": [ - "Baré" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "baf", - "Description": [ - "Nubaca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bag", - "Description": [ - "Tuki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bah", - "Description": [ - "Bahamas Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bai", - "Description": [ - "Bamileke languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "baj", - "Description": [ - "Barakai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bal", - "Description": [ - "Baluchi" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "ban", - "Description": [ - "Balinese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bao", - "Description": [ - "Waimaha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bap", - "Description": [ - "Bantawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bar", - "Description": [ - "Bavarian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bas", - "Description": [ - "Basa (Cameroon)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bat", - "Description": [ - "Baltic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "bau", - "Description": [ - "Bada (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bav", - "Description": [ - "Vengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "baw", - "Description": [ - "Bambili-Bambui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bax", - "Description": [ - "Bamun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bay", - "Description": [ - "Batuley" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "baz", - "Description": [ - "Tunen" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see nvo, tvu" - ] - }, - { - "Type": "language", - "Subtag": "bba", - "Description": [ - "Baatonum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbb", - "Description": [ - "Barai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbc", - "Description": [ - "Batak Toba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbd", - "Description": [ - "Bau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbe", - "Description": [ - "Bangba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbf", - "Description": [ - "Baibai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbg", - "Description": [ - "Barama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbh", - "Description": [ - "Bugan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbi", - "Description": [ - "Barombi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbj", - "Description": [ - "Ghomálá'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbk", - "Description": [ - "Babanki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbl", - "Description": [ - "Bats" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbm", - "Description": [ - "Babango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbn", - "Description": [ - "Uneapa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbo", - "Description": [ - "Northern Bobo Madaré", - "Konabéré" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbp", - "Description": [ - "West Central Banda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbq", - "Description": [ - "Bamali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbr", - "Description": [ - "Girawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbs", - "Description": [ - "Bakpinka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbt", - "Description": [ - "Mburku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbu", - "Description": [ - "Kulung (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbv", - "Description": [ - "Karnai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbw", - "Description": [ - "Baba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbx", - "Description": [ - "Bubia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bby", - "Description": [ - "Befang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bbz", - "Description": [ - "Babalia Creole Arabic" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "bca", - "Description": [ - "Central Bai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcb", - "Description": [ - "Bainouk-Samik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcc", - "Description": [ - "Southern Balochi" - ], - "Added": "2009-07-29", - "Macrolanguage": "bal" - }, - { - "Type": "language", - "Subtag": "bcd", - "Description": [ - "North Babar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bce", - "Description": [ - "Bamenyam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcf", - "Description": [ - "Bamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcg", - "Description": [ - "Baga Pokur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bch", - "Description": [ - "Bariai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bci", - "Description": [ - "Baoulé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcj", - "Description": [ - "Bardi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bck", - "Description": [ - "Bunuba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcl", - "Description": [ - "Central Bikol" - ], - "Added": "2009-07-29", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "bcm", - "Description": [ - "Bannoni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcn", - "Description": [ - "Bali (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bco", - "Description": [ - "Kaluli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcp", - "Description": [ - "Bali (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcq", - "Description": [ - "Bench" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcr", - "Description": [ - "Babine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcs", - "Description": [ - "Kohumono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bct", - "Description": [ - "Bendi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcu", - "Description": [ - "Awad Bing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcv", - "Description": [ - "Shoo-Minda-Nye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcw", - "Description": [ - "Bana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcy", - "Description": [ - "Bacama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bcz", - "Description": [ - "Bainouk-Gunyaamolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bda", - "Description": [ - "Bayot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdb", - "Description": [ - "Basap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdc", - "Description": [ - "Emberá-Baudó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdd", - "Description": [ - "Bunama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bde", - "Description": [ - "Bade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdf", - "Description": [ - "Biage" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "bdg", - "Description": [ - "Bonggi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdh", - "Description": [ - "Baka (South Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdi", - "Description": [ - "Burun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdj", - "Description": [ - "Bai (South Sudan)", - "Bai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdk", - "Description": [ - "Budukh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdl", - "Description": [ - "Indonesian Bajau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdm", - "Description": [ - "Buduma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdn", - "Description": [ - "Baldemu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdo", - "Description": [ - "Morom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdp", - "Description": [ - "Bende" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdq", - "Description": [ - "Bahnar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdr", - "Description": [ - "West Coast Bajau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bds", - "Description": [ - "Burunge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdt", - "Description": [ - "Bokoto" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "bdu", - "Description": [ - "Oroko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdv", - "Description": [ - "Bodo Parja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdw", - "Description": [ - "Baham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdx", - "Description": [ - "Budong-Budong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdy", - "Description": [ - "Bandjalang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bdz", - "Description": [ - "Badeshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bea", - "Description": [ - "Beaver" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "beb", - "Description": [ - "Bebele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bec", - "Description": [ - "Iceve-Maci" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bed", - "Description": [ - "Bedoanas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bee", - "Description": [ - "Byangsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bef", - "Description": [ - "Benabena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "beg", - "Description": [ - "Belait" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "beh", - "Description": [ - "Biali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bei", - "Description": [ - "Bekati'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bej", - "Description": [ - "Beja", - "Bedawiyet" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bek", - "Description": [ - "Bebeli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bem", - "Description": [ - "Bemba (Zambia)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "beo", - "Description": [ - "Beami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bep", - "Description": [ - "Besoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "beq", - "Description": [ - "Beembe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ber", - "Description": [ - "Berber languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "bes", - "Description": [ - "Besme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bet", - "Description": [ - "Guiberoua Béte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "beu", - "Description": [ - "Blagar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bev", - "Description": [ - "Daloa Bété" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bew", - "Description": [ - "Betawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bex", - "Description": [ - "Jur Modo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bey", - "Description": [ - "Beli (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bez", - "Description": [ - "Bena (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfa", - "Description": [ - "Bari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfb", - "Description": [ - "Pauri Bareli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfc", - "Description": [ - "Panyi Bai", - "Northern Bai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfd", - "Description": [ - "Bafut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfe", - "Description": [ - "Betaf", - "Tena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bff", - "Description": [ - "Bofi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfg", - "Description": [ - "Busang Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfh", - "Description": [ - "Blafe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfi", - "Description": [ - "British Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfj", - "Description": [ - "Bafanji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfk", - "Description": [ - "Ban Khor Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfl", - "Description": [ - "Banda-Ndélé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfm", - "Description": [ - "Mmen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfn", - "Description": [ - "Bunak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfo", - "Description": [ - "Malba Birifor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfp", - "Description": [ - "Beba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfq", - "Description": [ - "Badaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfr", - "Description": [ - "Bazigar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfs", - "Description": [ - "Southern Bai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bft", - "Description": [ - "Balti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfu", - "Description": [ - "Gahri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfw", - "Description": [ - "Bondo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfx", - "Description": [ - "Bantayanon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "bfy", - "Description": [ - "Bagheli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bfz", - "Description": [ - "Mahasu Pahari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bga", - "Description": [ - "Gwamhi-Wuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgb", - "Description": [ - "Bobongko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgc", - "Description": [ - "Haryanvi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgd", - "Description": [ - "Rathwi Bareli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bge", - "Description": [ - "Bauria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgf", - "Description": [ - "Bangandu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgg", - "Description": [ - "Bugun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgi", - "Description": [ - "Giangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgj", - "Description": [ - "Bangolan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgk", - "Description": [ - "Bit", - "Buxinhua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgl", - "Description": [ - "Bo (Laos)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgm", - "Description": [ - "Baga Mboteni" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "bcg" - }, - { - "Type": "language", - "Subtag": "bgn", - "Description": [ - "Western Balochi" - ], - "Added": "2009-07-29", - "Macrolanguage": "bal" - }, - { - "Type": "language", - "Subtag": "bgo", - "Description": [ - "Baga Koga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgp", - "Description": [ - "Eastern Balochi" - ], - "Added": "2009-07-29", - "Macrolanguage": "bal" - }, - { - "Type": "language", - "Subtag": "bgq", - "Description": [ - "Bagri" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "bgr", - "Description": [ - "Bawm Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgs", - "Description": [ - "Tagabawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgt", - "Description": [ - "Bughotu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgu", - "Description": [ - "Mbongno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgv", - "Description": [ - "Warkay-Bipim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgw", - "Description": [ - "Bhatri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgx", - "Description": [ - "Balkan Gagauz Turkish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgy", - "Description": [ - "Benggoi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bgz", - "Description": [ - "Banggai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bha", - "Description": [ - "Bharia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhb", - "Description": [ - "Bhili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhc", - "Description": [ - "Biga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhd", - "Description": [ - "Bhadrawahi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhe", - "Description": [ - "Bhaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhf", - "Description": [ - "Odiai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhg", - "Description": [ - "Binandere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhh", - "Description": [ - "Bukharic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhi", - "Description": [ - "Bhilali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhj", - "Description": [ - "Bahing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhk", - "Description": [ - "Albay Bicolano" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Macrolanguage": "bik", - "Comments": [ - "see fbl, lbl, rbl, ubl" - ] - }, - { - "Type": "language", - "Subtag": "bhl", - "Description": [ - "Bimin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhm", - "Description": [ - "Bathari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhn", - "Description": [ - "Bohtan Neo-Aramaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bho", - "Description": [ - "Bhojpuri" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bhp", - "Description": [ - "Bima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhq", - "Description": [ - "Tukang Besi South" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhr", - "Description": [ - "Bara Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "bhs", - "Description": [ - "Buwal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bht", - "Description": [ - "Bhattiyali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhu", - "Description": [ - "Bhunjia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhv", - "Description": [ - "Bahau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhw", - "Description": [ - "Biak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhx", - "Description": [ - "Bhalay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhy", - "Description": [ - "Bhele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bhz", - "Description": [ - "Bada (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bia", - "Description": [ - "Badimaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bib", - "Description": [ - "Bissa", - "Bisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bic", - "Description": [ - "Bikaru" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Preferred-Value": "bir" - }, - { - "Type": "language", - "Subtag": "bid", - "Description": [ - "Bidiyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bie", - "Description": [ - "Bepour" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bif", - "Description": [ - "Biafada" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "big", - "Description": [ - "Biangai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bij", - "Description": [ - "Vaghat-Ya-Bijim-Legeri" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see dkg, jbm, tyy" - ] - }, - { - "Type": "language", - "Subtag": "bik", - "Description": [ - "Bikol" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "bil", - "Description": [ - "Bile" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bim", - "Description": [ - "Bimoba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bin", - "Description": [ - "Bini", - "Edo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "bio", - "Description": [ - "Nai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bip", - "Description": [ - "Bila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biq", - "Description": [ - "Bipi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bir", - "Description": [ - "Bisorio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bit", - "Description": [ - "Berinomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biu", - "Description": [ - "Biete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biv", - "Description": [ - "Southern Birifor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biw", - "Description": [ - "Kol (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bix", - "Description": [ - "Bijori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biy", - "Description": [ - "Birhor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "biz", - "Description": [ - "Baloi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bja", - "Description": [ - "Budza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjb", - "Description": [ - "Banggarla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjc", - "Description": [ - "Bariji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjd", - "Description": [ - "Bandjigali" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "drl" - }, - { - "Type": "language", - "Subtag": "bje", - "Description": [ - "Biao-Jiao Mien" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjf", - "Description": [ - "Barzani Jewish Neo-Aramaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjg", - "Description": [ - "Bidyogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjh", - "Description": [ - "Bahinemo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bji", - "Description": [ - "Burji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjj", - "Description": [ - "Kanauji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjk", - "Description": [ - "Barok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjl", - "Description": [ - "Bulu (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjm", - "Description": [ - "Bajelani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjn", - "Description": [ - "Banjar" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "bjo", - "Description": [ - "Mid-Southern Banda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjp", - "Description": [ - "Fanamaket" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "bjq", - "Description": [ - "Southern Betsimisaraka Malagasy" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Macrolanguage": "mg", - "Comments": [ - "see bzc, tkg" - ] - }, - { - "Type": "language", - "Subtag": "bjr", - "Description": [ - "Binumarien" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjs", - "Description": [ - "Bajan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjt", - "Description": [ - "Balanta-Ganja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bju", - "Description": [ - "Busuu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjv", - "Description": [ - "Bedjond" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjw", - "Description": [ - "Bakwé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjx", - "Description": [ - "Banao Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjy", - "Description": [ - "Bayali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bjz", - "Description": [ - "Baruga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bka", - "Description": [ - "Kyak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkb", - "Description": [ - "Finallig" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see ebk, obk" - ] - }, - { - "Type": "language", - "Subtag": "bkc", - "Description": [ - "Baka (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkd", - "Description": [ - "Binukid", - "Talaandig" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkf", - "Description": [ - "Beeke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkg", - "Description": [ - "Buraka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkh", - "Description": [ - "Bakoko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bki", - "Description": [ - "Baki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkj", - "Description": [ - "Pande" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkk", - "Description": [ - "Brokskat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkl", - "Description": [ - "Berik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkm", - "Description": [ - "Kom (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkn", - "Description": [ - "Bukitan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bko", - "Description": [ - "Kwa'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkp", - "Description": [ - "Boko (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkq", - "Description": [ - "Bakairí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkr", - "Description": [ - "Bakumpai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bks", - "Description": [ - "Northern Sorsoganon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkt", - "Description": [ - "Boloki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bku", - "Description": [ - "Buhid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkv", - "Description": [ - "Bekwarra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkw", - "Description": [ - "Bekwel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkx", - "Description": [ - "Baikeno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bky", - "Description": [ - "Bokyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bkz", - "Description": [ - "Bungku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bla", - "Description": [ - "Siksika" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "blb", - "Description": [ - "Bilua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blc", - "Description": [ - "Bella Coola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bld", - "Description": [ - "Bolango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ble", - "Description": [ - "Balanta-Kentohe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blf", - "Description": [ - "Buol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blg", - "Description": [ - "Balau" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Preferred-Value": "iba" - }, - { - "Type": "language", - "Subtag": "blh", - "Description": [ - "Kuwaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bli", - "Description": [ - "Bolia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blj", - "Description": [ - "Bolongan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blk", - "Description": [ - "Pa'o Karen", - "Pa'O" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bll", - "Description": [ - "Biloxi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blm", - "Description": [ - "Beli (South Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bln", - "Description": [ - "Southern Catanduanes Bikol" - ], - "Added": "2009-07-29", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "blo", - "Description": [ - "Anii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blp", - "Description": [ - "Blablanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blq", - "Description": [ - "Baluan-Pam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blr", - "Description": [ - "Blang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bls", - "Description": [ - "Balaesang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blt", - "Description": [ - "Tai Dam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blv", - "Description": [ - "Kibala", - "Bolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blw", - "Description": [ - "Balangao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blx", - "Description": [ - "Mag-Indi Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bly", - "Description": [ - "Notre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "blz", - "Description": [ - "Balantak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bma", - "Description": [ - "Lame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmb", - "Description": [ - "Bembe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmc", - "Description": [ - "Biem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmd", - "Description": [ - "Baga Manduri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bme", - "Description": [ - "Limassa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmf", - "Description": [ - "Bom-Kim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmg", - "Description": [ - "Bamwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmh", - "Description": [ - "Kein" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmi", - "Description": [ - "Bagirmi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmj", - "Description": [ - "Bote-Majhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmk", - "Description": [ - "Ghayavi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bml", - "Description": [ - "Bomboli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmm", - "Description": [ - "Northern Betsimisaraka Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "bmn", - "Description": [ - "Bina (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmo", - "Description": [ - "Bambalang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmp", - "Description": [ - "Bulgebi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmq", - "Description": [ - "Bomu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmr", - "Description": [ - "Muinane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bms", - "Description": [ - "Bilma Kanuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmt", - "Description": [ - "Biao Mon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmu", - "Description": [ - "Somba-Siawari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmv", - "Description": [ - "Bum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmw", - "Description": [ - "Bomwali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmx", - "Description": [ - "Baimak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bmy", - "Description": [ - "Bemba (Democratic Republic of Congo)" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "bmz", - "Description": [ - "Baramu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bna", - "Description": [ - "Bonerate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnb", - "Description": [ - "Bookan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnc", - "Description": [ - "Bontok" - ], - "Added": "2009-07-29", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "bnd", - "Description": [ - "Banda (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bne", - "Description": [ - "Bintauna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnf", - "Description": [ - "Masiwang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bng", - "Description": [ - "Benga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bni", - "Description": [ - "Bangi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnj", - "Description": [ - "Eastern Tawbuid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnk", - "Description": [ - "Bierebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnl", - "Description": [ - "Boon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnm", - "Description": [ - "Batanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnn", - "Description": [ - "Bunun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bno", - "Description": [ - "Bantoanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnp", - "Description": [ - "Bola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnq", - "Description": [ - "Bantik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnr", - "Description": [ - "Butmas-Tur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bns", - "Description": [ - "Bundeli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnt", - "Description": [ - "Bantu languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "bnu", - "Description": [ - "Bentong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnv", - "Description": [ - "Bonerif", - "Beneraf", - "Edwas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnw", - "Description": [ - "Bisis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnx", - "Description": [ - "Bangubangu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bny", - "Description": [ - "Bintulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bnz", - "Description": [ - "Beezen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boa", - "Description": [ - "Bora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bob", - "Description": [ - "Aweer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boe", - "Description": [ - "Mundabli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bof", - "Description": [ - "Bolon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bog", - "Description": [ - "Bamako Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boh", - "Description": [ - "Boma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boi", - "Description": [ - "Barbareño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boj", - "Description": [ - "Anjam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bok", - "Description": [ - "Bonjo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bol", - "Description": [ - "Bole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bom", - "Description": [ - "Berom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bon", - "Description": [ - "Bine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boo", - "Description": [ - "Tiemacèwè Bozo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bop", - "Description": [ - "Bonkiman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boq", - "Description": [ - "Bogaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bor", - "Description": [ - "Borôro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bot", - "Description": [ - "Bongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bou", - "Description": [ - "Bondei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bov", - "Description": [ - "Tuwuli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bow", - "Description": [ - "Rema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "box", - "Description": [ - "Buamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boy", - "Description": [ - "Bodo (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "boz", - "Description": [ - "Tiéyaxo Bozo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpa", - "Description": [ - "Daakaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpb", - "Description": [ - "Barbacoas" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "bpc", - "Description": [ - "Mbuk" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "bpd", - "Description": [ - "Banda-Banda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpe", - "Description": [ - "Bauni" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "bpg", - "Description": [ - "Bonggo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bph", - "Description": [ - "Botlikh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpi", - "Description": [ - "Bagupi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpj", - "Description": [ - "Binji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpk", - "Description": [ - "Orowe", - "'Ôrôê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpl", - "Description": [ - "Broome Pearling Lugger Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpm", - "Description": [ - "Biyom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpn", - "Description": [ - "Dzao Min" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpo", - "Description": [ - "Anasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpp", - "Description": [ - "Kaure" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpq", - "Description": [ - "Banda Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpr", - "Description": [ - "Koronadal Blaan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bps", - "Description": [ - "Sarangani Blaan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpt", - "Description": [ - "Barrow Point" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpu", - "Description": [ - "Bongu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpv", - "Description": [ - "Bian Marind" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpw", - "Description": [ - "Bo (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpx", - "Description": [ - "Palya Bareli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpy", - "Description": [ - "Bishnupriya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bpz", - "Description": [ - "Bilba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqa", - "Description": [ - "Tchumbuli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqb", - "Description": [ - "Bagusa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqc", - "Description": [ - "Boko (Benin)", - "Boo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqd", - "Description": [ - "Bung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqf", - "Description": [ - "Baga Kaloum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqg", - "Description": [ - "Bago-Kusuntu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqh", - "Description": [ - "Baima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqi", - "Description": [ - "Bakhtiari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqj", - "Description": [ - "Bandial" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqk", - "Description": [ - "Banda-Mbrès" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bql", - "Description": [ - "Bilakura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqm", - "Description": [ - "Wumboko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqn", - "Description": [ - "Bulgarian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqo", - "Description": [ - "Balo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqp", - "Description": [ - "Busa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqq", - "Description": [ - "Biritai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqr", - "Description": [ - "Burusu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqs", - "Description": [ - "Bosngun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqt", - "Description": [ - "Bamukumbit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqu", - "Description": [ - "Boguru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqv", - "Description": [ - "Koro Wachi", - "Begbere-Ejar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqw", - "Description": [ - "Buru (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqx", - "Description": [ - "Baangi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqy", - "Description": [ - "Bengkala Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bqz", - "Description": [ - "Bakaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bra", - "Description": [ - "Braj" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "brb", - "Description": [ - "Brao", - "Lave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brc", - "Description": [ - "Berbice Creole Dutch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brd", - "Description": [ - "Baraamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brf", - "Description": [ - "Bira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brg", - "Description": [ - "Baure" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brh", - "Description": [ - "Brahui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bri", - "Description": [ - "Mokpwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brj", - "Description": [ - "Bieria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brk", - "Description": [ - "Birked" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brl", - "Description": [ - "Birwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brm", - "Description": [ - "Barambu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brn", - "Description": [ - "Boruca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bro", - "Description": [ - "Brokkat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brp", - "Description": [ - "Barapasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brq", - "Description": [ - "Breri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brr", - "Description": [ - "Birao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brs", - "Description": [ - "Baras" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brt", - "Description": [ - "Bitare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bru", - "Description": [ - "Eastern Bru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brv", - "Description": [ - "Western Bru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brw", - "Description": [ - "Bellari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brx", - "Description": [ - "Bodo (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bry", - "Description": [ - "Burui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "brz", - "Description": [ - "Bilbil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsa", - "Description": [ - "Abinomn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsb", - "Description": [ - "Brunei Bisaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsc", - "Description": [ - "Bassari", - "Oniyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bse", - "Description": [ - "Wushi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsf", - "Description": [ - "Bauchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsg", - "Description": [ - "Bashkardi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsh", - "Description": [ - "Kati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsi", - "Description": [ - "Bassossi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsj", - "Description": [ - "Bangwinji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsk", - "Description": [ - "Burushaski" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsl", - "Description": [ - "Basa-Gumna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsm", - "Description": [ - "Busami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsn", - "Description": [ - "Barasana-Eduria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bso", - "Description": [ - "Buso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsp", - "Description": [ - "Baga Sitemu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsq", - "Description": [ - "Bassa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsr", - "Description": [ - "Bassa-Kontagora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bss", - "Description": [ - "Akoose" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bst", - "Description": [ - "Basketo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsu", - "Description": [ - "Bahonsuai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsv", - "Description": [ - "Baga Sobané" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsw", - "Description": [ - "Baiso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsx", - "Description": [ - "Yangkam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bsy", - "Description": [ - "Sabah Bisaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bta", - "Description": [ - "Bata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btb", - "Description": [ - "Beti (Cameroon)" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see beb, bum, bxp, eto, ewo, fan, mct" - ] - }, - { - "Type": "language", - "Subtag": "btc", - "Description": [ - "Bati (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btd", - "Description": [ - "Batak Dairi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bte", - "Description": [ - "Gamo-Ningi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btf", - "Description": [ - "Birgit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btg", - "Description": [ - "Gagnoa Bété" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bth", - "Description": [ - "Biatah Bidayuh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bti", - "Description": [ - "Burate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btj", - "Description": [ - "Bacanese Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "btk", - "Description": [ - "Batak languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "btl", - "Description": [ - "Bhatola" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "btm", - "Description": [ - "Batak Mandailing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btn", - "Description": [ - "Ratagnon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bto", - "Description": [ - "Rinconada Bikol" - ], - "Added": "2009-07-29", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "btp", - "Description": [ - "Budibud" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btq", - "Description": [ - "Batek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btr", - "Description": [ - "Baetora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bts", - "Description": [ - "Batak Simalungun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btt", - "Description": [ - "Bete-Bendi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btu", - "Description": [ - "Batu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btv", - "Description": [ - "Bateri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btw", - "Description": [ - "Butuanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btx", - "Description": [ - "Batak Karo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bty", - "Description": [ - "Bobot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "btz", - "Description": [ - "Batak Alas-Kluet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bua", - "Description": [ - "Buriat" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "bub", - "Description": [ - "Bua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buc", - "Description": [ - "Bushi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bud", - "Description": [ - "Ntcham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bue", - "Description": [ - "Beothuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buf", - "Description": [ - "Bushoong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bug", - "Description": [ - "Buginese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "buh", - "Description": [ - "Younuo Bunu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bui", - "Description": [ - "Bongili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buj", - "Description": [ - "Basa-Gurmana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buk", - "Description": [ - "Bugawac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bum", - "Description": [ - "Bulu (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bun", - "Description": [ - "Sherbro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buo", - "Description": [ - "Terei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bup", - "Description": [ - "Busoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buq", - "Description": [ - "Brem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bus", - "Description": [ - "Bokobaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "but", - "Description": [ - "Bungain" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buu", - "Description": [ - "Budu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buv", - "Description": [ - "Bun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buw", - "Description": [ - "Bubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bux", - "Description": [ - "Boghom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buy", - "Description": [ - "Bullom So" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "buz", - "Description": [ - "Bukwen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bva", - "Description": [ - "Barein" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvb", - "Description": [ - "Bube" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvc", - "Description": [ - "Baelelea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvd", - "Description": [ - "Baeggu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bve", - "Description": [ - "Berau Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "bvf", - "Description": [ - "Boor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvg", - "Description": [ - "Bonkeng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvh", - "Description": [ - "Bure" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvi", - "Description": [ - "Belanda Viri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvj", - "Description": [ - "Baan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvk", - "Description": [ - "Bukat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvl", - "Description": [ - "Bolivian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvm", - "Description": [ - "Bamunka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvn", - "Description": [ - "Buna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvo", - "Description": [ - "Bolgo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvp", - "Description": [ - "Bumang" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "bvq", - "Description": [ - "Birri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvr", - "Description": [ - "Burarra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvt", - "Description": [ - "Bati (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvu", - "Description": [ - "Bukit Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "bvv", - "Description": [ - "Baniva" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvw", - "Description": [ - "Boga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvx", - "Description": [ - "Dibole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bvy", - "Description": [ - "Baybayanon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "bvz", - "Description": [ - "Bauzi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwa", - "Description": [ - "Bwatoo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwb", - "Description": [ - "Namosi-Naitasiri-Serua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwc", - "Description": [ - "Bwile" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwd", - "Description": [ - "Bwaidoka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwe", - "Description": [ - "Bwe Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwf", - "Description": [ - "Boselewa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwg", - "Description": [ - "Barwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwh", - "Description": [ - "Bishuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwi", - "Description": [ - "Baniwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwj", - "Description": [ - "Láá Láá Bwamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwk", - "Description": [ - "Bauwaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwl", - "Description": [ - "Bwela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwm", - "Description": [ - "Biwat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwn", - "Description": [ - "Wunai Bunu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwo", - "Description": [ - "Boro (Ethiopia)", - "Borna (Ethiopia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwp", - "Description": [ - "Mandobo Bawah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwq", - "Description": [ - "Southern Bobo Madaré" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwr", - "Description": [ - "Bura-Pabir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bws", - "Description": [ - "Bomboma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwt", - "Description": [ - "Bafaw-Balong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwu", - "Description": [ - "Buli (Ghana)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bww", - "Description": [ - "Bwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwx", - "Description": [ - "Bu-Nao Bunu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwy", - "Description": [ - "Cwi Bwamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bwz", - "Description": [ - "Bwisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxa", - "Description": [ - "Tairaha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxb", - "Description": [ - "Belanda Bor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxc", - "Description": [ - "Molengue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxd", - "Description": [ - "Pela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxe", - "Description": [ - "Birale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxf", - "Description": [ - "Bilur", - "Minigir" - ], - "Added": "2009-07-29", - "Comments": [ - "see also vmg" - ] - }, - { - "Type": "language", - "Subtag": "bxg", - "Description": [ - "Bangala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxh", - "Description": [ - "Buhutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxi", - "Description": [ - "Pirlatapa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxj", - "Description": [ - "Bayungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxk", - "Description": [ - "Bukusu", - "Lubukusu" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "bxl", - "Description": [ - "Jalkunan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxm", - "Description": [ - "Mongolia Buriat" - ], - "Added": "2009-07-29", - "Macrolanguage": "bua" - }, - { - "Type": "language", - "Subtag": "bxn", - "Description": [ - "Burduna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxo", - "Description": [ - "Barikanchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxp", - "Description": [ - "Bebil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxq", - "Description": [ - "Beele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxr", - "Description": [ - "Russia Buriat" - ], - "Added": "2009-07-29", - "Macrolanguage": "bua" - }, - { - "Type": "language", - "Subtag": "bxs", - "Description": [ - "Busam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxu", - "Description": [ - "China Buriat" - ], - "Added": "2009-07-29", - "Macrolanguage": "bua" - }, - { - "Type": "language", - "Subtag": "bxv", - "Description": [ - "Berakou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxw", - "Description": [ - "Bankagooma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bxx", - "Description": [ - "Borna (Democratic Republic of Congo)" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "bxz", - "Description": [ - "Binahari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bya", - "Description": [ - "Batak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byb", - "Description": [ - "Bikya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byc", - "Description": [ - "Ubaghara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byd", - "Description": [ - "Benyadu'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bye", - "Description": [ - "Pouye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byf", - "Description": [ - "Bete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byg", - "Description": [ - "Baygo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byh", - "Description": [ - "Bhujel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byi", - "Description": [ - "Buyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byj", - "Description": [ - "Bina (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byk", - "Description": [ - "Biao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byl", - "Description": [ - "Bayono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bym", - "Description": [ - "Bidjara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byn", - "Description": [ - "Bilin", - "Blin" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "byo", - "Description": [ - "Biyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byp", - "Description": [ - "Bumaji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byq", - "Description": [ - "Basay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byr", - "Description": [ - "Baruya", - "Yipma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bys", - "Description": [ - "Burak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byt", - "Description": [ - "Berti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byv", - "Description": [ - "Medumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byw", - "Description": [ - "Belhariya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byx", - "Description": [ - "Qaqet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "byy", - "Description": [ - "Buya" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "byz", - "Description": [ - "Banaro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bza", - "Description": [ - "Bandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzb", - "Description": [ - "Andio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzc", - "Description": [ - "Southern Betsimisaraka Malagasy" - ], - "Added": "2011-08-16", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "bzd", - "Description": [ - "Bribri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bze", - "Description": [ - "Jenaama Bozo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzf", - "Description": [ - "Boikin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzg", - "Description": [ - "Babuza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzh", - "Description": [ - "Mapos Buang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzi", - "Description": [ - "Bisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzj", - "Description": [ - "Belize Kriol English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzk", - "Description": [ - "Nicaragua Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzl", - "Description": [ - "Boano (Sulawesi)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzm", - "Description": [ - "Bolondo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzn", - "Description": [ - "Boano (Maluku)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzo", - "Description": [ - "Bozaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzp", - "Description": [ - "Kemberano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzq", - "Description": [ - "Buli (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzr", - "Description": [ - "Biri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzs", - "Description": [ - "Brazilian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzt", - "Description": [ - "Brithenig" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzu", - "Description": [ - "Burmeso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzv", - "Description": [ - "Naami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzw", - "Description": [ - "Basa (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzx", - "Description": [ - "KÉ›lÉ›ngaxo Bozo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzy", - "Description": [ - "Obanliku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "bzz", - "Description": [ - "Evant" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "caa", - "Description": [ - "Chortí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cab", - "Description": [ - "Garifuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cac", - "Description": [ - "Chuj" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cad", - "Description": [ - "Caddo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cae", - "Description": [ - "Lehar", - "Laalaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "caf", - "Description": [ - "Southern Carrier" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cag", - "Description": [ - "Nivaclé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cah", - "Description": [ - "Cahuarano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cai", - "Description": [ - "Central American Indian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "caj", - "Description": [ - "Chané" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cak", - "Description": [ - "Kaqchikel", - "Cakchiquel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cal", - "Description": [ - "Carolinian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cam", - "Description": [ - "Cemuhî" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "can", - "Description": [ - "Chambri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cao", - "Description": [ - "Chácobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cap", - "Description": [ - "Chipaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "caq", - "Description": [ - "Car Nicobarese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "car", - "Description": [ - "Galibi Carib" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cas", - "Description": [ - "Tsimané" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cau", - "Description": [ - "Caucasian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cav", - "Description": [ - "Cavineña" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "caw", - "Description": [ - "Callawalla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cax", - "Description": [ - "Chiquitano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cay", - "Description": [ - "Cayuga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "caz", - "Description": [ - "Canichana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cba", - "Description": [ - "Chibchan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cbb", - "Description": [ - "Cabiyarí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbc", - "Description": [ - "Carapana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbd", - "Description": [ - "Carijona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbe", - "Description": [ - "Chipiajes" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "cbg", - "Description": [ - "Chimila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbh", - "Description": [ - "Cagua" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "cbi", - "Description": [ - "Chachi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbj", - "Description": [ - "Ede Cabe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbk", - "Description": [ - "Chavacano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbl", - "Description": [ - "Bualkhaw Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbn", - "Description": [ - "Nyahkur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbo", - "Description": [ - "Izora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbq", - "Description": [ - "Tsucuba", - "Cuba" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "cbr", - "Description": [ - "Cashibo-Cacataibo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbs", - "Description": [ - "Cashinahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbt", - "Description": [ - "Chayahuita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbu", - "Description": [ - "Candoshi-Shapra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbv", - "Description": [ - "Cacua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cbw", - "Description": [ - "Kinabalian" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "cby", - "Description": [ - "Carabayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cca", - "Description": [ - "Cauca" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ccc", - "Description": [ - "Chamicuro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccd", - "Description": [ - "Cafundo Creole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cce", - "Description": [ - "Chopi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccg", - "Description": [ - "Samba Daka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cch", - "Description": [ - "Atsam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccj", - "Description": [ - "Kasanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccl", - "Description": [ - "Cutchi-Swahili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccm", - "Description": [ - "Malaccan Creole Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccn", - "Description": [ - "North Caucasian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cco", - "Description": [ - "Comaltepec Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccp", - "Description": [ - "Chakma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccq", - "Description": [ - "Chaungtha" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "rki" - }, - { - "Type": "language", - "Subtag": "ccr", - "Description": [ - "Cacaopera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ccs", - "Description": [ - "South Caucasian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cda", - "Description": [ - "Choni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdc", - "Description": [ - "Chadic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cdd", - "Description": [ - "Caddoan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cde", - "Description": [ - "Chenchu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdf", - "Description": [ - "Chiru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdg", - "Description": [ - "Chamari" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "cdh", - "Description": [ - "Chambeali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdi", - "Description": [ - "Chodri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdj", - "Description": [ - "Churahi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdm", - "Description": [ - "Chepang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdn", - "Description": [ - "Chaudangsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdo", - "Description": [ - "Min Dong Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "cdr", - "Description": [ - "Cinda-Regi-Tiyal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cds", - "Description": [ - "Chadian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdy", - "Description": [ - "Chadong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cdz", - "Description": [ - "Koda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cea", - "Description": [ - "Lower Chehalis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ceb", - "Description": [ - "Cebuano" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ceg", - "Description": [ - "Chamacoco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cek", - "Description": [ - "Eastern Khumi Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "cel", - "Description": [ - "Celtic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cen", - "Description": [ - "Cen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cet", - "Description": [ - "Centúúm" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cey", - "Description": [ - "Ekai Chin" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "cfa", - "Description": [ - "Dijim-Bwilim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cfd", - "Description": [ - "Cara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cfg", - "Description": [ - "Como Karim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cfm", - "Description": [ - "Falam Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cga", - "Description": [ - "Changriwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cgc", - "Description": [ - "Kagayanen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cgg", - "Description": [ - "Chiga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cgk", - "Description": [ - "Chocangacakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chb", - "Description": [ - "Chibcha" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chc", - "Description": [ - "Catawba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chd", - "Description": [ - "Highland Oaxaca Chontal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chf", - "Description": [ - "Tabasco Chontal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chg", - "Description": [ - "Chagatai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chh", - "Description": [ - "Chinook" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chj", - "Description": [ - "Ojitlán Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chk", - "Description": [ - "Chuukese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chl", - "Description": [ - "Cahuilla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chm", - "Description": [ - "Mari (Russia)" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "chn", - "Description": [ - "Chinook jargon" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cho", - "Description": [ - "Choctaw" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chp", - "Description": [ - "Chipewyan", - "Dene Suline" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chq", - "Description": [ - "Quiotepec Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chr", - "Description": [ - "Cherokee" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cht", - "Description": [ - "Cholón" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chw", - "Description": [ - "Chuwabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chx", - "Description": [ - "Chantyal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "chy", - "Description": [ - "Cheyenne" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "chz", - "Description": [ - "Ozumacín Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cia", - "Description": [ - "Cia-Cia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cib", - "Description": [ - "Ci Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cic", - "Description": [ - "Chickasaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cid", - "Description": [ - "Chimariko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cie", - "Description": [ - "Cineni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cih", - "Description": [ - "Chinali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cik", - "Description": [ - "Chitkuli Kinnauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cim", - "Description": [ - "Cimbrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cin", - "Description": [ - "Cinta Larga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cip", - "Description": [ - "Chiapanec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cir", - "Description": [ - "Tiri", - "Haméa", - "Méa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ciw", - "Description": [ - "Chippewa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "ciy", - "Description": [ - "Chaima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cja", - "Description": [ - "Western Cham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cje", - "Description": [ - "Chru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjh", - "Description": [ - "Upper Chehalis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cji", - "Description": [ - "Chamalal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjk", - "Description": [ - "Chokwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjm", - "Description": [ - "Eastern Cham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjn", - "Description": [ - "Chenapian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjo", - "Description": [ - "Ashéninka Pajonal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjp", - "Description": [ - "Cabécar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjr", - "Description": [ - "Chorotega" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "mom" - }, - { - "Type": "language", - "Subtag": "cjs", - "Description": [ - "Shor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjv", - "Description": [ - "Chuave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cjy", - "Description": [ - "Jinyu Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "cka", - "Description": [ - "Khumi Awa Chin" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "cmr" - }, - { - "Type": "language", - "Subtag": "ckb", - "Description": [ - "Central Kurdish" - ], - "Added": "2009-07-29", - "Macrolanguage": "ku" - }, - { - "Type": "language", - "Subtag": "ckh", - "Description": [ - "Chak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckl", - "Description": [ - "Cibak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckm", - "Description": [ - "Chakavian" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ckn", - "Description": [ - "Kaang Chin" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "cko", - "Description": [ - "Anufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckq", - "Description": [ - "Kajakse" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckr", - "Description": [ - "Kairak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cks", - "Description": [ - "Tayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckt", - "Description": [ - "Chukot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cku", - "Description": [ - "Koasati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckv", - "Description": [ - "Kavalan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckx", - "Description": [ - "Caka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cky", - "Description": [ - "Cakfem-Mushere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ckz", - "Description": [ - "Cakchiquel-Quiché Mixed Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cla", - "Description": [ - "Ron" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clc", - "Description": [ - "Chilcotin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cld", - "Description": [ - "Chaldean Neo-Aramaic" - ], - "Added": "2009-07-29", - "Macrolanguage": "syr" - }, - { - "Type": "language", - "Subtag": "cle", - "Description": [ - "Lealao Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clh", - "Description": [ - "Chilisso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cli", - "Description": [ - "Chakali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clj", - "Description": [ - "Laitu Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "clk", - "Description": [ - "Idu-Mishmi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cll", - "Description": [ - "Chala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clm", - "Description": [ - "Clallam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clo", - "Description": [ - "Lowland Oaxaca Chontal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clt", - "Description": [ - "Lautu Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "clu", - "Description": [ - "Caluyanun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "clw", - "Description": [ - "Chulym" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cly", - "Description": [ - "Eastern Highland Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cma", - "Description": [ - "Maa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmc", - "Description": [ - "Chamic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cme", - "Description": [ - "Cerma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmg", - "Description": [ - "Classical Mongolian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmi", - "Description": [ - "Emberá-Chamí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmk", - "Description": [ - "Chimakum" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "xch" - }, - { - "Type": "language", - "Subtag": "cml", - "Description": [ - "Campalagian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmm", - "Description": [ - "Michigamea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmn", - "Description": [ - "Mandarin Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "cmo", - "Description": [ - "Central Mnong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmr", - "Description": [ - "Mro-Khimi Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cms", - "Description": [ - "Messapic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cmt", - "Description": [ - "Camtho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cna", - "Description": [ - "Changthang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnb", - "Description": [ - "Chinbon Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnc", - "Description": [ - "Côông" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cng", - "Description": [ - "Northern Qiang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnh", - "Description": [ - "Hakha Chin", - "Haka Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cni", - "Description": [ - "Asháninka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnk", - "Description": [ - "Khumi Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnl", - "Description": [ - "Lalana Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cno", - "Description": [ - "Con" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnp", - "Description": [ - "Northern Ping Chinese", - "Northern Pinghua" - ], - "Added": "2020-03-28", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "cnq", - "Description": [ - "Chung" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "cnr", - "Description": [ - "Montenegrin" - ], - "Added": "2018-01-23", - "Macrolanguage": "sh", - "Comments": [ - "see sr for Serbian" - ] - }, - { - "Type": "language", - "Subtag": "cns", - "Description": [ - "Central Asmat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnt", - "Description": [ - "Tepetotutla Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnu", - "Description": [ - "Chenoua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnw", - "Description": [ - "Ngawn Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cnx", - "Description": [ - "Middle Cornish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coa", - "Description": [ - "Cocos Islands Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "cob", - "Description": [ - "Chicomuceltec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coc", - "Description": [ - "Cocopa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cod", - "Description": [ - "Cocama-Cocamilla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coe", - "Description": [ - "Koreguaje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cof", - "Description": [ - "Colorado" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cog", - "Description": [ - "Chong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coh", - "Description": [ - "Chonyi-Dzihana-Kauma", - "Chichonyi-Chidzihana-Chikauma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coj", - "Description": [ - "Cochimi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cok", - "Description": [ - "Santa Teresa Cora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "col", - "Description": [ - "Columbia-Wenatchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "com", - "Description": [ - "Comanche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "con", - "Description": [ - "Cofán" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coo", - "Description": [ - "Comox" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cop", - "Description": [ - "Coptic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "coq", - "Description": [ - "Coquille" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cot", - "Description": [ - "Caquinte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cou", - "Description": [ - "Wamey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cov", - "Description": [ - "Cao Miao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cow", - "Description": [ - "Cowlitz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cox", - "Description": [ - "Nanti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "coy", - "Description": [ - "Coyaima" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "pij" - }, - { - "Type": "language", - "Subtag": "coz", - "Description": [ - "Chochotec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpa", - "Description": [ - "Palantla Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpb", - "Description": [ - "Ucayali-Yurúa Ashéninka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpc", - "Description": [ - "Ajyíninka Apurucayali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpe", - "Description": [ - "English-based creoles and pidgins" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cpf", - "Description": [ - "French-based creoles and pidgins" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cpg", - "Description": [ - "Cappadocian Greek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpi", - "Description": [ - "Chinese Pidgin English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpn", - "Description": [ - "Cherepon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpo", - "Description": [ - "Kpeego" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "cpp", - "Description": [ - "Portuguese-based creoles and pidgins" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cps", - "Description": [ - "Capiznon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpu", - "Description": [ - "Pichis Ashéninka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cpx", - "Description": [ - "Pu-Xian Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "cpy", - "Description": [ - "South Ucayali Ashéninka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cqd", - "Description": [ - "Chuanqiandian Cluster Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "cqu", - "Description": [ - "Chilean Quechua" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "quh", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "cra", - "Description": [ - "Chara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crb", - "Description": [ - "Island Carib" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crc", - "Description": [ - "Lonwolwol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crd", - "Description": [ - "Coeur d'Alene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crf", - "Description": [ - "Caramanta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crg", - "Description": [ - "Michif" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crh", - "Description": [ - "Crimean Tatar", - "Crimean Turkish" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "cri", - "Description": [ - "Sãotomense" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crj", - "Description": [ - "Southern East Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "crk", - "Description": [ - "Plains Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "crl", - "Description": [ - "Northern East Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "crm", - "Description": [ - "Moose Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "crn", - "Description": [ - "El Nayar Cora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cro", - "Description": [ - "Crow" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crp", - "Description": [ - "Creoles and pidgins" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "crq", - "Description": [ - "Iyo'wujwa Chorote" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crr", - "Description": [ - "Carolina Algonquian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crs", - "Description": [ - "Seselwa Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crt", - "Description": [ - "Iyojwa'ja Chorote" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crv", - "Description": [ - "Chaura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crw", - "Description": [ - "Chrau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crx", - "Description": [ - "Carrier" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cry", - "Description": [ - "Cori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "crz", - "Description": [ - "Cruzeño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csa", - "Description": [ - "Chiltepec Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csb", - "Description": [ - "Kashubian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "csc", - "Description": [ - "Catalan Sign Language", - "Lengua de señas catalana", - "Llengua de Signes Catalana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csd", - "Description": [ - "Chiangmai Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cse", - "Description": [ - "Czech Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csf", - "Description": [ - "Cuba Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csg", - "Description": [ - "Chilean Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csh", - "Description": [ - "Asho Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csi", - "Description": [ - "Coast Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csj", - "Description": [ - "Songlai Chin" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "csk", - "Description": [ - "Jola-Kasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csl", - "Description": [ - "Chinese Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csm", - "Description": [ - "Central Sierra Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csn", - "Description": [ - "Colombian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cso", - "Description": [ - "Sochiapam Chinantec", - "Sochiapan Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csp", - "Description": [ - "Southern Ping Chinese", - "Southern Pinghua" - ], - "Added": "2020-03-28", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "csq", - "Description": [ - "Croatia Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csr", - "Description": [ - "Costa Rican Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "css", - "Description": [ - "Southern Ohlone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cst", - "Description": [ - "Northern Ohlone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csu", - "Description": [ - "Central Sudanic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "csv", - "Description": [ - "Sumtu Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "csw", - "Description": [ - "Swampy Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "csx", - "Description": [ - "Cambodian Sign Language" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "csy", - "Description": [ - "Siyin Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "csz", - "Description": [ - "Coos" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cta", - "Description": [ - "Tataltepec Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctc", - "Description": [ - "Chetco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctd", - "Description": [ - "Tedim Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cte", - "Description": [ - "Tepinapa Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctg", - "Description": [ - "Chittagonian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cth", - "Description": [ - "Thaiphum Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ctl", - "Description": [ - "Tlacoatzintepec Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctm", - "Description": [ - "Chitimacha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctn", - "Description": [ - "Chhintange" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cto", - "Description": [ - "Emberá-Catío" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctp", - "Description": [ - "Western Highland Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cts", - "Description": [ - "Northern Catanduanes Bikol" - ], - "Added": "2009-07-29", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "ctt", - "Description": [ - "Wayanad Chetti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ctu", - "Description": [ - "Chol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cty", - "Description": [ - "Moundadan Chetty" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ctz", - "Description": [ - "Zacatepec Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cua", - "Description": [ - "Cua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cub", - "Description": [ - "Cubeo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuc", - "Description": [ - "Usila Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cug", - "Description": [ - "Chungmboko", - "Cung" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Comments": [ - "see bpc, cnq" - ] - }, - { - "Type": "language", - "Subtag": "cuh", - "Description": [ - "Chuka", - "Gichuka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cui", - "Description": [ - "Cuiba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuj", - "Description": [ - "Mashco Piro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuk", - "Description": [ - "San Blas Kuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cul", - "Description": [ - "Culina", - "Kulina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cum", - "Description": [ - "Cumeral" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "cuo", - "Description": [ - "Cumanagoto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cup", - "Description": [ - "Cupeño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuq", - "Description": [ - "Cun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cur", - "Description": [ - "Chhulung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cus", - "Description": [ - "Cushitic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "cut", - "Description": [ - "Teutila Cuicatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuu", - "Description": [ - "Tai Ya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuv", - "Description": [ - "Cuvok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuw", - "Description": [ - "Chukwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cux", - "Description": [ - "Tepeuxila Cuicatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cuy", - "Description": [ - "Cuitlatec" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "cvg", - "Description": [ - "Chug" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cvn", - "Description": [ - "Valle Nacional Chinantec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cwa", - "Description": [ - "Kabwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cwb", - "Description": [ - "Maindo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cwd", - "Description": [ - "Woods Cree" - ], - "Added": "2009-07-29", - "Macrolanguage": "cr" - }, - { - "Type": "language", - "Subtag": "cwe", - "Description": [ - "Kwere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cwg", - "Description": [ - "Chewong", - "Cheq Wong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cwt", - "Description": [ - "Kuwaataay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cya", - "Description": [ - "Nopala Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cyb", - "Description": [ - "Cayubaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "cyo", - "Description": [ - "Cuyonon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "czh", - "Description": [ - "Huizhou Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "czk", - "Description": [ - "Knaanic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "czn", - "Description": [ - "Zenzontepec Chatino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "czo", - "Description": [ - "Min Zhong Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "czt", - "Description": [ - "Zotung Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "daa", - "Description": [ - "Dangaléat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dac", - "Description": [ - "Dambi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dad", - "Description": [ - "Marik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dae", - "Description": [ - "Duupa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "daf", - "Description": [ - "Dan" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see dnj, lda" - ] - }, - { - "Type": "language", - "Subtag": "dag", - "Description": [ - "Dagbani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dah", - "Description": [ - "Gwahatike" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dai", - "Description": [ - "Day" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "daj", - "Description": [ - "Dar Fur Daju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dak", - "Description": [ - "Dakota" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "dal", - "Description": [ - "Dahalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dam", - "Description": [ - "Damakawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dao", - "Description": [ - "Daai Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dap", - "Description": [ - "Nisi (India)" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see njz, tgj" - ] - }, - { - "Type": "language", - "Subtag": "daq", - "Description": [ - "Dandami Maria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dar", - "Description": [ - "Dargwa" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "das", - "Description": [ - "Daho-Doo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dau", - "Description": [ - "Dar Sila Daju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dav", - "Description": [ - "Taita", - "Dawida" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "daw", - "Description": [ - "Davawenyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dax", - "Description": [ - "Dayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "day", - "Description": [ - "Land Dayak languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "daz", - "Description": [ - "Dao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dba", - "Description": [ - "Bangime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbb", - "Description": [ - "Deno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbd", - "Description": [ - "Dadiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbe", - "Description": [ - "Dabe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbf", - "Description": [ - "Edopi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbg", - "Description": [ - "Dogul Dom Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbi", - "Description": [ - "Doka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbj", - "Description": [ - "Ida'an" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbl", - "Description": [ - "Dyirbal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbm", - "Description": [ - "Duguri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbn", - "Description": [ - "Duriankere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbo", - "Description": [ - "Dulbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbp", - "Description": [ - "Duwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbq", - "Description": [ - "Daba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbr", - "Description": [ - "Dabarre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbt", - "Description": [ - "Ben Tey Dogon" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dbu", - "Description": [ - "Bondum Dom Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbv", - "Description": [ - "Dungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dbw", - "Description": [ - "Bankan Tey Dogon" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dby", - "Description": [ - "Dibiyaso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dcc", - "Description": [ - "Deccan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dcr", - "Description": [ - "Negerhollands" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dda", - "Description": [ - "Dadi Dadi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ddd", - "Description": [ - "Dongotono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dde", - "Description": [ - "Doondo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddg", - "Description": [ - "Fataluku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddi", - "Description": [ - "West Goodenough" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddj", - "Description": [ - "Jaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddn", - "Description": [ - "Dendi (Benin)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddo", - "Description": [ - "Dido" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddr", - "Description": [ - "Dhudhuroa" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dds", - "Description": [ - "Donno So Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ddw", - "Description": [ - "Dawera-Daweloor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dec", - "Description": [ - "Dagik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ded", - "Description": [ - "Dedua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dee", - "Description": [ - "Dewoin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "def", - "Description": [ - "Dezfuli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "deg", - "Description": [ - "Degema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "deh", - "Description": [ - "Dehwari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dei", - "Description": [ - "Demisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dek", - "Description": [ - "Dek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "del", - "Description": [ - "Delaware" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "dem", - "Description": [ - "Dem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "den", - "Description": [ - "Slave (Athapascan)" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "dep", - "Description": [ - "Pidgin Delaware" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "deq", - "Description": [ - "Dendi (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "der", - "Description": [ - "Deori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "des", - "Description": [ - "Desano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dev", - "Description": [ - "Domung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dez", - "Description": [ - "Dengese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dga", - "Description": [ - "Southern Dagaare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgb", - "Description": [ - "Bunoge Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgc", - "Description": [ - "Casiguran Dumagat Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgd", - "Description": [ - "Dagaari Dioula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dge", - "Description": [ - "Degenan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgg", - "Description": [ - "Doga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgh", - "Description": [ - "Dghwede" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgi", - "Description": [ - "Northern Dagara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgk", - "Description": [ - "Dagba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgl", - "Description": [ - "Andaandi", - "Dongolawi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dgn", - "Description": [ - "Dagoman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgo", - "Description": [ - "Dogri (individual language)" - ], - "Added": "2009-07-29", - "Macrolanguage": "doi" - }, - { - "Type": "language", - "Subtag": "dgr", - "Description": [ - "Dogrib", - "Tłı̨chÇ«" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "dgs", - "Description": [ - "Dogoso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgt", - "Description": [ - "Ndra'ngith" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dgu", - "Description": [ - "Degaru" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "dgw", - "Description": [ - "Daungwurrung" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dgx", - "Description": [ - "Doghoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dgz", - "Description": [ - "Daga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dha", - "Description": [ - "Dhanwar (India)" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "dhd", - "Description": [ - "Dhundari" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "dhg", - "Description": [ - "Dhangu-Djangu", - "Dhangu", - "Djangu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhi", - "Description": [ - "Dhimal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhl", - "Description": [ - "Dhalandji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhm", - "Description": [ - "Zemba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhn", - "Description": [ - "Dhanki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dho", - "Description": [ - "Dhodia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhr", - "Description": [ - "Dhargari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhs", - "Description": [ - "Dhaiso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhu", - "Description": [ - "Dhurga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhv", - "Description": [ - "Dehu", - "Drehu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhw", - "Description": [ - "Dhanwar (Nepal)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dhx", - "Description": [ - "Dhungaloo" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "dia", - "Description": [ - "Dia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dib", - "Description": [ - "South Central Dinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "din" - }, - { - "Type": "language", - "Subtag": "dic", - "Description": [ - "Lakota Dida" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "did", - "Description": [ - "Didinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dif", - "Description": [ - "Dieri", - "Diyari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dig", - "Description": [ - "Digo", - "Chidigo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dih", - "Description": [ - "Kumiai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dii", - "Description": [ - "Dimbong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dij", - "Description": [ - "Dai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dik", - "Description": [ - "Southwestern Dinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "din" - }, - { - "Type": "language", - "Subtag": "dil", - "Description": [ - "Dilling" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dim", - "Description": [ - "Dime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "din", - "Description": [ - "Dinka" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "dio", - "Description": [ - "Dibo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dip", - "Description": [ - "Northeastern Dinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "din" - }, - { - "Type": "language", - "Subtag": "diq", - "Description": [ - "Dimli (individual language)" - ], - "Added": "2009-07-29", - "Macrolanguage": "zza" - }, - { - "Type": "language", - "Subtag": "dir", - "Description": [ - "Dirim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dis", - "Description": [ - "Dimasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dit", - "Description": [ - "Dirari" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-29", - "Preferred-Value": "dif" - }, - { - "Type": "language", - "Subtag": "diu", - "Description": [ - "Diriku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "diw", - "Description": [ - "Northwestern Dinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "din" - }, - { - "Type": "language", - "Subtag": "dix", - "Description": [ - "Dixon Reef" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "diy", - "Description": [ - "Diuwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "diz", - "Description": [ - "Ding" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dja", - "Description": [ - "Djadjawurrung" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "djb", - "Description": [ - "Djinba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djc", - "Description": [ - "Dar Daju Daju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djd", - "Description": [ - "Djamindjung", - "Ngaliwurru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dje", - "Description": [ - "Zarma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djf", - "Description": [ - "Djangun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dji", - "Description": [ - "Djinang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djj", - "Description": [ - "Djeebbana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djk", - "Description": [ - "Eastern Maroon Creole", - "Businenge Tongo", - "Nenge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djl", - "Description": [ - "Djiwarli" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see dze, iin" - ] - }, - { - "Type": "language", - "Subtag": "djm", - "Description": [ - "Jamsay Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djn", - "Description": [ - "Jawoyn", - "Djauan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djo", - "Description": [ - "Jangkang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djr", - "Description": [ - "Djambarrpuyngu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dju", - "Description": [ - "Kapriman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "djw", - "Description": [ - "Djawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dka", - "Description": [ - "Dakpakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dkg", - "Description": [ - "Kadung" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "dkk", - "Description": [ - "Dakka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dkl", - "Description": [ - "Kolum So Dogon" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Comments": [ - "see aqd, dmb" - ] - }, - { - "Type": "language", - "Subtag": "dkr", - "Description": [ - "Kuijau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dks", - "Description": [ - "Southeastern Dinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "din" - }, - { - "Type": "language", - "Subtag": "dkx", - "Description": [ - "Mazagway" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dlg", - "Description": [ - "Dolgan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dlk", - "Description": [ - "Dahalik" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "dlm", - "Description": [ - "Dalmatian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dln", - "Description": [ - "Darlong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dma", - "Description": [ - "Duma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmb", - "Description": [ - "Mombo Dogon" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "dmc", - "Description": [ - "Gavak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmd", - "Description": [ - "Madhi Madhi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dme", - "Description": [ - "Dugwor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmf", - "Description": [ - "Medefaidrin" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "dmg", - "Description": [ - "Upper Kinabatangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmk", - "Description": [ - "Domaaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dml", - "Description": [ - "Dameli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmm", - "Description": [ - "Dama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmn", - "Description": [ - "Mande languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "dmo", - "Description": [ - "Kemedzung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmr", - "Description": [ - "East Damar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dms", - "Description": [ - "Dampelas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmu", - "Description": [ - "Dubu", - "Tebi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmv", - "Description": [ - "Dumpas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmw", - "Description": [ - "Mudburra" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "dmx", - "Description": [ - "Dema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dmy", - "Description": [ - "Demta", - "Sowari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dna", - "Description": [ - "Upper Grand Valley Dani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnd", - "Description": [ - "Daonda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dne", - "Description": [ - "Ndendeule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dng", - "Description": [ - "Dungan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dni", - "Description": [ - "Lower Grand Valley Dani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnj", - "Description": [ - "Dan" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "dnk", - "Description": [ - "Dengka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnn", - "Description": [ - "Dzùùngoo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dno", - "Description": [ - "Ndrulo", - "Northern Lendu" - ], - "Added": "2018-10-28" - }, - { - "Type": "language", - "Subtag": "dnr", - "Description": [ - "Danaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnt", - "Description": [ - "Mid Grand Valley Dani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnu", - "Description": [ - "Danau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dnv", - "Description": [ - "Danu" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dnw", - "Description": [ - "Western Dani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dny", - "Description": [ - "Dení" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doa", - "Description": [ - "Dom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dob", - "Description": [ - "Dobu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doc", - "Description": [ - "Northern Dong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doe", - "Description": [ - "Doe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dof", - "Description": [ - "Domu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doh", - "Description": [ - "Dong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doi", - "Description": [ - "Dogri (macrolanguage)" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "dok", - "Description": [ - "Dondo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dol", - "Description": [ - "Doso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "don", - "Description": [ - "Toura (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doo", - "Description": [ - "Dongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dop", - "Description": [ - "Lukpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doq", - "Description": [ - "Dominican Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dor", - "Description": [ - "Dori'o" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dos", - "Description": [ - "Dogosé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dot", - "Description": [ - "Dass" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dov", - "Description": [ - "Dombe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dow", - "Description": [ - "Doyayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dox", - "Description": [ - "Bussa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doy", - "Description": [ - "Dompo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "doz", - "Description": [ - "Dorze" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dpp", - "Description": [ - "Papar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dra", - "Description": [ - "Dravidian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "drb", - "Description": [ - "Dair" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drc", - "Description": [ - "Minderico" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "drd", - "Description": [ - "Darmiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dre", - "Description": [ - "Dolpo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drg", - "Description": [ - "Rungus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drh", - "Description": [ - "Darkhat" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "khk" - }, - { - "Type": "language", - "Subtag": "dri", - "Description": [ - "C'Lela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drl", - "Description": [ - "Paakantyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drn", - "Description": [ - "West Damar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dro", - "Description": [ - "Daro-Matu Melanau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drq", - "Description": [ - "Dura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drr", - "Description": [ - "Dororo" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "kzk" - }, - { - "Type": "language", - "Subtag": "drs", - "Description": [ - "Gedeo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drt", - "Description": [ - "Drents" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dru", - "Description": [ - "Rukai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "drw", - "Description": [ - "Darwazi" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "prs" - }, - { - "Type": "language", - "Subtag": "dry", - "Description": [ - "Darai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsb", - "Description": [ - "Lower Sorbian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "dse", - "Description": [ - "Dutch Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsh", - "Description": [ - "Daasanach" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsi", - "Description": [ - "Disa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsl", - "Description": [ - "Danish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsn", - "Description": [ - "Dusner" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dso", - "Description": [ - "Desiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsq", - "Description": [ - "Tadaksahak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dsz", - "Description": [ - "Mardin Sign Language" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "dta", - "Description": [ - "Daur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtb", - "Description": [ - "Labuk-Kinabatangan Kadazan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtd", - "Description": [ - "Ditidaht" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "dth", - "Description": [ - "Adithinngithigh" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dti", - "Description": [ - "Ana Tinga Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtk", - "Description": [ - "Tene Kan Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtm", - "Description": [ - "Tomo Kan Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtn", - "Description": [ - "Daatsʼíin" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "dto", - "Description": [ - "Tommo So Dogon" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "dtp", - "Description": [ - "Kadazan Dusun", - "Central Dusun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtr", - "Description": [ - "Lotud" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dts", - "Description": [ - "Toro So Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtt", - "Description": [ - "Toro Tegu Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dtu", - "Description": [ - "Tebul Ure Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dty", - "Description": [ - "Dotyali" - ], - "Added": "2012-08-12", - "Macrolanguage": "ne" - }, - { - "Type": "language", - "Subtag": "dua", - "Description": [ - "Duala" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "dub", - "Description": [ - "Dubli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duc", - "Description": [ - "Duna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dud", - "Description": [ - "Hun-Saare" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Comments": [ - "see uth, uss" - ] - }, - { - "Type": "language", - "Subtag": "due", - "Description": [ - "Umiray Dumaget Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duf", - "Description": [ - "Dumbea", - "Drubea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dug", - "Description": [ - "Duruma", - "Chiduruma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duh", - "Description": [ - "Dungra Bhil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dui", - "Description": [ - "Dumun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duj", - "Description": [ - "Dhuwal" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Comments": [ - "see dwu, dwy" - ] - }, - { - "Type": "language", - "Subtag": "duk", - "Description": [ - "Uyajitaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dul", - "Description": [ - "Alabat Island Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dum", - "Description": [ - "Middle Dutch (ca. 1050-1350)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "dun", - "Description": [ - "Dusun Deyah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duo", - "Description": [ - "Dupaninan Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dup", - "Description": [ - "Duano" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "duq", - "Description": [ - "Dusun Malang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dur", - "Description": [ - "Dii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dus", - "Description": [ - "Dumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duu", - "Description": [ - "Drung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duv", - "Description": [ - "Duvle" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duw", - "Description": [ - "Dusun Witu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dux", - "Description": [ - "Duungooma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duy", - "Description": [ - "Dicamay Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "duz", - "Description": [ - "Duli-Gey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dva", - "Description": [ - "Duau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dwa", - "Description": [ - "Diri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dwk", - "Description": [ - "Dawik Kui" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "dwl", - "Description": [ - "Walo Kumbe Dogon" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see dbt, dbw" - ] - }, - { - "Type": "language", - "Subtag": "dwr", - "Description": [ - "Dawro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dws", - "Description": [ - "Dutton World Speedwords" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dwu", - "Description": [ - "Dhuwal" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "dww", - "Description": [ - "Dawawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dwy", - "Description": [ - "Dhuwaya" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "dwz", - "Description": [ - "Dewas Rai" - ], - "Added": "2018-10-28" - }, - { - "Type": "language", - "Subtag": "dya", - "Description": [ - "Dyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyb", - "Description": [ - "Dyaberdyaber" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyd", - "Description": [ - "Dyugun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyg", - "Description": [ - "Villa Viciosa Agta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyi", - "Description": [ - "Djimini Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dym", - "Description": [ - "Yanda Dom Dogon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyn", - "Description": [ - "Dyangadi", - "Dhanggatti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyo", - "Description": [ - "Jola-Fonyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dyu", - "Description": [ - "Dyula" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "dyy", - "Description": [ - "Djabugay", - "Dyaabugay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dza", - "Description": [ - "Tunzu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dzd", - "Description": [ - "Daza" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "dze", - "Description": [ - "Djiwarli" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "dzg", - "Description": [ - "Dazaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dzl", - "Description": [ - "Dzalakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "dzn", - "Description": [ - "Dzando" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eaa", - "Description": [ - "Karenggapa" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ebc", - "Description": [ - "Beginci" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ebg", - "Description": [ - "Ebughu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ebk", - "Description": [ - "Eastern Bontok" - ], - "Added": "2010-03-11", - "Macrolanguage": "bnc" - }, - { - "Type": "language", - "Subtag": "ebo", - "Description": [ - "Teke-Ebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ebr", - "Description": [ - "Ebrié" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ebu", - "Description": [ - "Embu", - "Kiembu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ecr", - "Description": [ - "Eteocretan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ecs", - "Description": [ - "Ecuadorian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ecy", - "Description": [ - "Eteocypriot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eee", - "Description": [ - "E" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "efa", - "Description": [ - "Efai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "efe", - "Description": [ - "Efe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "efi", - "Description": [ - "Efik" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ega", - "Description": [ - "Ega" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "egl", - "Description": [ - "Emilian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "egm", - "Description": [ - "Benamanga" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "ego", - "Description": [ - "Eggon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "egx", - "Description": [ - "Egyptian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "egy", - "Description": [ - "Egyptian (Ancient)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ehs", - "Description": [ - "Miyakubo Sign Language" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ehu", - "Description": [ - "Ehueun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eip", - "Description": [ - "Eipomek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eit", - "Description": [ - "Eitiep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eiv", - "Description": [ - "Askopan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eja", - "Description": [ - "Ejamat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eka", - "Description": [ - "Ekajuk" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ekc", - "Description": [ - "Eastern Karnic" - ], - "Added": "2013-09-10", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "eke", - "Description": [ - "Ekit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ekg", - "Description": [ - "Ekari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eki", - "Description": [ - "Eki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ekk", - "Description": [ - "Standard Estonian" - ], - "Added": "2009-07-29", - "Macrolanguage": "et" - }, - { - "Type": "language", - "Subtag": "ekl", - "Description": [ - "Kol (Bangladesh)", - "Kol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ekm", - "Description": [ - "Elip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eko", - "Description": [ - "Koti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ekp", - "Description": [ - "Ekpeye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ekr", - "Description": [ - "Yace" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eky", - "Description": [ - "Eastern Kayah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ele", - "Description": [ - "Elepi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elh", - "Description": [ - "El Hugeirat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eli", - "Description": [ - "Nding" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elk", - "Description": [ - "Elkei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elm", - "Description": [ - "Eleme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elo", - "Description": [ - "El Molo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elp", - "Description": [ - "Elpaputih" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see amq, plh" - ] - }, - { - "Type": "language", - "Subtag": "elu", - "Description": [ - "Elu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "elx", - "Description": [ - "Elamite" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ema", - "Description": [ - "Emai-Iuleha-Ora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emb", - "Description": [ - "Embaloh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eme", - "Description": [ - "Emerillon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emg", - "Description": [ - "Eastern Meohang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emi", - "Description": [ - "Mussau-Emira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emk", - "Description": [ - "Eastern Maninkakan" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "emm", - "Description": [ - "Mamulique" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emn", - "Description": [ - "Eman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emo", - "Description": [ - "Emok" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "emp", - "Description": [ - "Northern Emberá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emq", - "Description": [ - "Eastern Minyag" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ems", - "Description": [ - "Pacific Gulf Yupik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emu", - "Description": [ - "Eastern Muria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emw", - "Description": [ - "Emplawas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emx", - "Description": [ - "Erromintxela" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "emy", - "Description": [ - "Epigraphic Mayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "emz", - "Description": [ - "Mbessa" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ena", - "Description": [ - "Apali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enb", - "Description": [ - "Markweeta" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "enc", - "Description": [ - "En" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "end", - "Description": [ - "Ende" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enf", - "Description": [ - "Forest Enets" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enh", - "Description": [ - "Tundra Enets" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enl", - "Description": [ - "Enlhet" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "enm", - "Description": [ - "Middle English (1100-1500)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "enn", - "Description": [ - "Engenni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eno", - "Description": [ - "Enggano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enq", - "Description": [ - "Enga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enr", - "Description": [ - "Emumu", - "Emem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enu", - "Description": [ - "Enu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "env", - "Description": [ - "Enwan (Edo State)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enw", - "Description": [ - "Enwan (Akwa Ibom State)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "enx", - "Description": [ - "Enxet" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "eot", - "Description": [ - "Beti (Côte d'Ivoire)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "epi", - "Description": [ - "Epie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "era", - "Description": [ - "Eravallan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "erg", - "Description": [ - "Sie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "erh", - "Description": [ - "Eruwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eri", - "Description": [ - "Ogea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "erk", - "Description": [ - "South Efate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ero", - "Description": [ - "Horpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "err", - "Description": [ - "Erre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ers", - "Description": [ - "Ersu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ert", - "Description": [ - "Eritai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "erw", - "Description": [ - "Erokwanas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ese", - "Description": [ - "Ese Ejja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esg", - "Description": [ - "Aheri Gondi" - ], - "Added": "2016-05-30", - "Macrolanguage": "gon" - }, - { - "Type": "language", - "Subtag": "esh", - "Description": [ - "Eshtehardi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esi", - "Description": [ - "North Alaskan Inupiatun" - ], - "Added": "2009-07-29", - "Macrolanguage": "ik" - }, - { - "Type": "language", - "Subtag": "esk", - "Description": [ - "Northwest Alaska Inupiatun" - ], - "Added": "2009-07-29", - "Macrolanguage": "ik" - }, - { - "Type": "language", - "Subtag": "esl", - "Description": [ - "Egypt Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esm", - "Description": [ - "Esuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esn", - "Description": [ - "Salvadoran Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eso", - "Description": [ - "Estonian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esq", - "Description": [ - "Esselen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ess", - "Description": [ - "Central Siberian Yupik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esu", - "Description": [ - "Central Yupik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "esx", - "Description": [ - "Eskimo-Aleut languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "esy", - "Description": [ - "Eskayan" - ], - "Added": "2014-04-06" - }, - { - "Type": "language", - "Subtag": "etb", - "Description": [ - "Etebi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etc", - "Description": [ - "Etchemin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eth", - "Description": [ - "Ethiopian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etn", - "Description": [ - "Eton (Vanuatu)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eto", - "Description": [ - "Eton (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etr", - "Description": [ - "Edolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ets", - "Description": [ - "Yekhee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ett", - "Description": [ - "Etruscan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etu", - "Description": [ - "Ejagham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etx", - "Description": [ - "Eten" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "etz", - "Description": [ - "Semimi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "euq", - "Description": [ - "Basque (family)" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "eve", - "Description": [ - "Even" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "evh", - "Description": [ - "Uvbie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "evn", - "Description": [ - "Evenki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ewo", - "Description": [ - "Ewondo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ext", - "Description": [ - "Extremaduran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eya", - "Description": [ - "Eyak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "eyo", - "Description": [ - "Keiyo" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "eza", - "Description": [ - "Ezaa" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "eze", - "Description": [ - "Uzekwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "faa", - "Description": [ - "Fasu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fab", - "Description": [ - "Fa d'Ambu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fad", - "Description": [ - "Wagi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "faf", - "Description": [ - "Fagani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fag", - "Description": [ - "Finongan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fah", - "Description": [ - "Baissa Fali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fai", - "Description": [ - "Faiwol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "faj", - "Description": [ - "Faita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fak", - "Description": [ - "Fang (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fal", - "Description": [ - "South Fali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fam", - "Description": [ - "Fam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fan", - "Description": [ - "Fang (Equatorial Guinea)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "fap", - "Description": [ - "Paloor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "far", - "Description": [ - "Fataleka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fat", - "Description": [ - "Fanti" - ], - "Added": "2005-10-16", - "Macrolanguage": "ak" - }, - { - "Type": "language", - "Subtag": "fau", - "Description": [ - "Fayu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fax", - "Description": [ - "Fala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fay", - "Description": [ - "Southwestern Fars" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "faz", - "Description": [ - "Northwestern Fars" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fbl", - "Description": [ - "West Albay Bikol" - ], - "Added": "2010-03-11", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "fcs", - "Description": [ - "Quebec Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fer", - "Description": [ - "Feroge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ffi", - "Description": [ - "Foia Foia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ffm", - "Description": [ - "Maasina Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fgr", - "Description": [ - "Fongoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fia", - "Description": [ - "Nobiin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fie", - "Description": [ - "Fyer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fif", - "Description": [ - "Faifi" - ], - "Added": "2020-06-08" - }, - { - "Type": "language", - "Subtag": "fil", - "Description": [ - "Filipino", - "Pilipino" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "fip", - "Description": [ - "Fipa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fir", - "Description": [ - "Firan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fit", - "Description": [ - "Tornedalen Finnish", - "Meänkieli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fiu", - "Description": [ - "Finno-Ugrian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "fiw", - "Description": [ - "Fiwaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fkk", - "Description": [ - "Kirya-KonzÉ™l" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "fkv", - "Description": [ - "Kven Finnish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fla", - "Description": [ - "Kalispel-Pend d'Oreille" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "flh", - "Description": [ - "Foau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fli", - "Description": [ - "Fali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fll", - "Description": [ - "North Fali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fln", - "Description": [ - "Flinders Island" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "flr", - "Description": [ - "Fuliiru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fly", - "Description": [ - "Flaaitaal", - "Tsotsitaal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fmp", - "Description": [ - "Fe'fe'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fmu", - "Description": [ - "Far Western Muria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fnb", - "Description": [ - "Fanbak" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "fng", - "Description": [ - "Fanagalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fni", - "Description": [ - "Fania" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fod", - "Description": [ - "Foodo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "foi", - "Description": [ - "Foi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fom", - "Description": [ - "Foma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fon", - "Description": [ - "Fon" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "for", - "Description": [ - "Fore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fos", - "Description": [ - "Siraya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fox", - "Description": [ - "Formosan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "fpe", - "Description": [ - "Fernando Po Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fqs", - "Description": [ - "Fas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frc", - "Description": [ - "Cajun French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frd", - "Description": [ - "Fordata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frk", - "Description": [ - "Frankish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frm", - "Description": [ - "Middle French (ca. 1400-1600)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "fro", - "Description": [ - "Old French (842-ca. 1400)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "frp", - "Description": [ - "Arpitan", - "Francoprovençal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frq", - "Description": [ - "Forak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "frr", - "Description": [ - "Northern Frisian" - ], - "Added": "2006-03-08", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "frs", - "Description": [ - "Eastern Frisian" - ], - "Added": "2006-03-08", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "frt", - "Description": [ - "Fortsenal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fse", - "Description": [ - "Finnish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fsl", - "Description": [ - "French Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fss", - "Description": [ - "Finland-Swedish Sign Language", - "finlandssvenskt teckensprÃ¥k", - "suomenruotsalainen viittomakieli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fub", - "Description": [ - "Adamawa Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fuc", - "Description": [ - "Pulaar" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fud", - "Description": [ - "East Futuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fue", - "Description": [ - "Borgu Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fuf", - "Description": [ - "Pular" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fuh", - "Description": [ - "Western Niger Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fui", - "Description": [ - "Bagirmi Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fuj", - "Description": [ - "Ko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fum", - "Description": [ - "Fum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fun", - "Description": [ - "Fulniô" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fuq", - "Description": [ - "Central-Eastern Niger Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fur", - "Description": [ - "Friulian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "fut", - "Description": [ - "Futuna-Aniwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fuu", - "Description": [ - "Furu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fuv", - "Description": [ - "Nigerian Fulfulde" - ], - "Added": "2009-07-29", - "Macrolanguage": "ff" - }, - { - "Type": "language", - "Subtag": "fuy", - "Description": [ - "Fuyug" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fvr", - "Description": [ - "Fur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fwa", - "Description": [ - "Fwâi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "fwe", - "Description": [ - "Fwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gaa", - "Description": [ - "Ga" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gab", - "Description": [ - "Gabri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gac", - "Description": [ - "Mixed Great Andamanese" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "gad", - "Description": [ - "Gaddang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gae", - "Description": [ - "Guarequena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gaf", - "Description": [ - "Gende" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gag", - "Description": [ - "Gagauz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gah", - "Description": [ - "Alekano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gai", - "Description": [ - "Borei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gaj", - "Description": [ - "Gadsup" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gak", - "Description": [ - "Gamkonora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gal", - "Description": [ - "Galolen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gam", - "Description": [ - "Kandawo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gan", - "Description": [ - "Gan Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "gao", - "Description": [ - "Gants" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gap", - "Description": [ - "Gal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gaq", - "Description": [ - "Gata'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gar", - "Description": [ - "Galeya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gas", - "Description": [ - "Adiwasi Garasia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gat", - "Description": [ - "Kenati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gau", - "Description": [ - "Mudhili Gadaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gav", - "Description": [ - "Gabutamon" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "dev" - }, - { - "Type": "language", - "Subtag": "gaw", - "Description": [ - "Nobonob" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gax", - "Description": [ - "Borana-Arsi-Guji Oromo" - ], - "Added": "2009-07-29", - "Macrolanguage": "om" - }, - { - "Type": "language", - "Subtag": "gay", - "Description": [ - "Gayo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gaz", - "Description": [ - "West Central Oromo" - ], - "Added": "2009-07-29", - "Macrolanguage": "om" - }, - { - "Type": "language", - "Subtag": "gba", - "Description": [ - "Gbaya (Central African Republic)" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "gbb", - "Description": [ - "Kaytetye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbc", - "Description": [ - "Garawa" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see wny, wrk" - ] - }, - { - "Type": "language", - "Subtag": "gbd", - "Description": [ - "Karajarri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbe", - "Description": [ - "Niksek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbf", - "Description": [ - "Gaikundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbg", - "Description": [ - "Gbanziri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbh", - "Description": [ - "Defi Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbi", - "Description": [ - "Galela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbj", - "Description": [ - "Bodo Gadaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbk", - "Description": [ - "Gaddi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbl", - "Description": [ - "Gamit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbm", - "Description": [ - "Garhwali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbn", - "Description": [ - "Mo'da" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbo", - "Description": [ - "Northern Grebo" - ], - "Added": "2009-07-29", - "Macrolanguage": "grb" - }, - { - "Type": "language", - "Subtag": "gbp", - "Description": [ - "Gbaya-Bossangoa" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "gbq", - "Description": [ - "Gbaya-Bozoum" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "gbr", - "Description": [ - "Gbagyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbs", - "Description": [ - "Gbesi Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbu", - "Description": [ - "Gagadu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbv", - "Description": [ - "Gbanu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbw", - "Description": [ - "Gabi-Gabi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gbx", - "Description": [ - "Eastern Xwla Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gby", - "Description": [ - "Gbari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gbz", - "Description": [ - "Zoroastrian Dari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcc", - "Description": [ - "Mali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcd", - "Description": [ - "Ganggalida" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gce", - "Description": [ - "Galice" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcf", - "Description": [ - "Guadeloupean Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcl", - "Description": [ - "Grenadian Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcn", - "Description": [ - "Gaina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gcr", - "Description": [ - "Guianese Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gct", - "Description": [ - "Colonia Tovar German" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gda", - "Description": [ - "Gade Lohar" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "gdb", - "Description": [ - "Pottangi Ollar Gadaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdc", - "Description": [ - "Gugu Badhun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdd", - "Description": [ - "Gedaged" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gde", - "Description": [ - "Gude" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdf", - "Description": [ - "Guduf-Gava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdg", - "Description": [ - "Ga'dang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdh", - "Description": [ - "Gadjerawang", - "Gajirrabeng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdi", - "Description": [ - "Gundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdj", - "Description": [ - "Gurdjar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdk", - "Description": [ - "Gadang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdl", - "Description": [ - "Dirasha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdm", - "Description": [ - "Laal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdn", - "Description": [ - "Umanakaina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdo", - "Description": [ - "Ghodoberi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdq", - "Description": [ - "Mehri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdr", - "Description": [ - "Wipi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gds", - "Description": [ - "Ghandruk Sign Language" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "gdt", - "Description": [ - "Kungardutyi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gdu", - "Description": [ - "Gudu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gdx", - "Description": [ - "Godwari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gea", - "Description": [ - "Geruma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "geb", - "Description": [ - "Kire" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gec", - "Description": [ - "Gboloo Grebo" - ], - "Added": "2009-07-29", - "Macrolanguage": "grb" - }, - { - "Type": "language", - "Subtag": "ged", - "Description": [ - "Gade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gef", - "Description": [ - "Gerai" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "geg", - "Description": [ - "Gengle" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "geh", - "Description": [ - "Hutterite German", - "Hutterisch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gei", - "Description": [ - "Gebe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gej", - "Description": [ - "Gen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gek", - "Description": [ - "Ywom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gel", - "Description": [ - "ut-Ma'in" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gem", - "Description": [ - "Germanic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "geq", - "Description": [ - "Geme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ges", - "Description": [ - "Geser-Gorom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gev", - "Description": [ - "Eviya" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "gew", - "Description": [ - "Gera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gex", - "Description": [ - "Garre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gey", - "Description": [ - "Enya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gez", - "Description": [ - "Geez" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gfk", - "Description": [ - "Patpatar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gft", - "Description": [ - "Gafat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gfx", - "Description": [ - "Mangetti Dune ǃXung" - ], - "Added": "2012-08-12", - "Deprecated": "2015-02-12", - "Preferred-Value": "vaj" - }, - { - "Type": "language", - "Subtag": "gga", - "Description": [ - "Gao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggb", - "Description": [ - "Gbii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggd", - "Description": [ - "Gugadj" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gge", - "Description": [ - "Gurr-goni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggg", - "Description": [ - "Gurgula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggk", - "Description": [ - "Kungarakany" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggl", - "Description": [ - "Ganglau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggn", - "Description": [ - "Eastern Gurung" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "gvr" - }, - { - "Type": "language", - "Subtag": "ggo", - "Description": [ - "Southern Gondi" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Comments": [ - "see esg, wsg" - ] - }, - { - "Type": "language", - "Subtag": "ggr", - "Description": [ - "Aghu Tharnggalu" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see gtu, ikr" - ] - }, - { - "Type": "language", - "Subtag": "ggt", - "Description": [ - "Gitua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggu", - "Description": [ - "Gagu", - "Gban" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ggw", - "Description": [ - "Gogodala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gha", - "Description": [ - "Ghadamès" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghc", - "Description": [ - "Hiberno-Scottish Gaelic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghe", - "Description": [ - "Southern Ghale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghh", - "Description": [ - "Northern Ghale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghk", - "Description": [ - "Geko Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghl", - "Description": [ - "Ghulfan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghn", - "Description": [ - "Ghanongga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gho", - "Description": [ - "Ghomara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghr", - "Description": [ - "Ghera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ghs", - "Description": [ - "Guhu-Samane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ght", - "Description": [ - "Kuke", - "Kutang Ghale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gia", - "Description": [ - "Kija" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gib", - "Description": [ - "Gibanawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gic", - "Description": [ - "Gail" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gid", - "Description": [ - "Gidar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gie", - "Description": [ - "GaÉ“ogbo", - "Guébie" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "gig", - "Description": [ - "Goaria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gih", - "Description": [ - "Githabul" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gii", - "Description": [ - "Girirra" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "gil", - "Description": [ - "Gilbertese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gim", - "Description": [ - "Gimi (Eastern Highlands)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gin", - "Description": [ - "Hinukh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gio", - "Description": [ - "Gelao" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see aou, gqu" - ] - }, - { - "Type": "language", - "Subtag": "gip", - "Description": [ - "Gimi (West New Britain)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "giq", - "Description": [ - "Green Gelao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gir", - "Description": [ - "Red Gelao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gis", - "Description": [ - "North Giziga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "git", - "Description": [ - "Gitxsan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "giu", - "Description": [ - "Mulao" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "giw", - "Description": [ - "White Gelao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gix", - "Description": [ - "Gilima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "giy", - "Description": [ - "Giyug" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "giz", - "Description": [ - "South Giziga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gji", - "Description": [ - "Geji" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see gyz, zbu" - ] - }, - { - "Type": "language", - "Subtag": "gjk", - "Description": [ - "Kachi Koli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gjm", - "Description": [ - "Gunditjmara" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gjn", - "Description": [ - "Gonja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gjr", - "Description": [ - "Gurindji Kriol" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "gju", - "Description": [ - "Gujari" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "gka", - "Description": [ - "Guya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gkd", - "Description": [ - "Magɨ (Madang Province)" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "gke", - "Description": [ - "Ndai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gkn", - "Description": [ - "Gokana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gko", - "Description": [ - "Kok-Nar" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "gkp", - "Description": [ - "Guinea Kpelle" - ], - "Added": "2009-07-29", - "Macrolanguage": "kpe" - }, - { - "Type": "language", - "Subtag": "gku", - "Description": [ - "Ç‚Ungkue" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "glb", - "Description": [ - "Belning" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "glc", - "Description": [ - "Bon Gula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gld", - "Description": [ - "Nanai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "glh", - "Description": [ - "Northwest Pashai", - "Northwest Pashayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gli", - "Description": [ - "Guliguli" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "kzk" - }, - { - "Type": "language", - "Subtag": "glj", - "Description": [ - "Gula Iro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "glk", - "Description": [ - "Gilaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gll", - "Description": [ - "Garlali" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "glo", - "Description": [ - "Galambu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "glr", - "Description": [ - "Glaro-Twabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "glu", - "Description": [ - "Gula (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "glw", - "Description": [ - "Glavda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gly", - "Description": [ - "Gule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gma", - "Description": [ - "Gambera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmb", - "Description": [ - "Gula'alaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmd", - "Description": [ - "Mághdì" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gme", - "Description": [ - "East Germanic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "gmg", - "Description": [ - "Magɨyi" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "gmh", - "Description": [ - "Middle High German (ca. 1050-1500)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gml", - "Description": [ - "Middle Low German" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmm", - "Description": [ - "Gbaya-Mbodomo" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "gmn", - "Description": [ - "Gimnime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmq", - "Description": [ - "North Germanic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "gmr", - "Description": [ - "Mirning", - "Mirniny" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "gmu", - "Description": [ - "Gumalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmv", - "Description": [ - "Gamo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmw", - "Description": [ - "West Germanic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "gmx", - "Description": [ - "Magoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmy", - "Description": [ - "Mycenaean Greek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gmz", - "Description": [ - "Mgbolizhia" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gna", - "Description": [ - "Kaansa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnb", - "Description": [ - "Gangte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnc", - "Description": [ - "Guanche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnd", - "Description": [ - "Zulgo-Gemzek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gne", - "Description": [ - "Ganang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gng", - "Description": [ - "Ngangam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnh", - "Description": [ - "Lere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gni", - "Description": [ - "Gooniyandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnj", - "Description": [ - "Ngen" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "gnk", - "Description": [ - "ÇGana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnl", - "Description": [ - "Gangulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnm", - "Description": [ - "Ginuman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnn", - "Description": [ - "Gumatj" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gno", - "Description": [ - "Northern Gondi" - ], - "Added": "2009-07-29", - "Macrolanguage": "gon" - }, - { - "Type": "language", - "Subtag": "gnq", - "Description": [ - "Gana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnr", - "Description": [ - "Gureng Gureng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnt", - "Description": [ - "Guntai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnu", - "Description": [ - "Gnau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gnw", - "Description": [ - "Western Bolivian Guaraní" - ], - "Added": "2009-07-29", - "Macrolanguage": "gn" - }, - { - "Type": "language", - "Subtag": "gnz", - "Description": [ - "Ganzi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goa", - "Description": [ - "Guro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gob", - "Description": [ - "Playero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goc", - "Description": [ - "Gorakor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "god", - "Description": [ - "Godié" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goe", - "Description": [ - "Gongduk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gof", - "Description": [ - "Gofa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gog", - "Description": [ - "Gogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goh", - "Description": [ - "Old High German (ca. 750-1050)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "goi", - "Description": [ - "Gobasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goj", - "Description": [ - "Gowlan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gok", - "Description": [ - "Gowli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gol", - "Description": [ - "Gola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gom", - "Description": [ - "Goan Konkani" - ], - "Added": "2009-07-29", - "Macrolanguage": "kok" - }, - { - "Type": "language", - "Subtag": "gon", - "Description": [ - "Gondi" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "goo", - "Description": [ - "Gone Dau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gop", - "Description": [ - "Yeretuar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goq", - "Description": [ - "Gorap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gor", - "Description": [ - "Gorontalo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gos", - "Description": [ - "Gronings" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "got", - "Description": [ - "Gothic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gou", - "Description": [ - "Gavar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gov", - "Description": [ - "Goo" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "gow", - "Description": [ - "Gorowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gox", - "Description": [ - "Gobu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goy", - "Description": [ - "Goundo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "goz", - "Description": [ - "Gozarkhani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gpa", - "Description": [ - "Gupa-Abawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gpe", - "Description": [ - "Ghanaian Pidgin English" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "gpn", - "Description": [ - "Taiap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gqa", - "Description": [ - "Ga'anda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gqi", - "Description": [ - "Guiqiong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gqn", - "Description": [ - "Guana (Brazil)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gqr", - "Description": [ - "Gor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gqu", - "Description": [ - "Qau" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "gra", - "Description": [ - "Rajput Garasia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grb", - "Description": [ - "Grebo" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "grc", - "Description": [ - "Ancient Greek (to 1453)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "grd", - "Description": [ - "Guruntum-Mbaaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grg", - "Description": [ - "Madi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grh", - "Description": [ - "Gbiri-Niragu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gri", - "Description": [ - "Ghari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grj", - "Description": [ - "Southern Grebo" - ], - "Added": "2009-07-29", - "Macrolanguage": "grb" - }, - { - "Type": "language", - "Subtag": "grk", - "Description": [ - "Greek languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "grm", - "Description": [ - "Kota Marudu Talantang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gro", - "Description": [ - "Groma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grq", - "Description": [ - "Gorovu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grr", - "Description": [ - "Taznatit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grs", - "Description": [ - "Gresi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grt", - "Description": [ - "Garo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gru", - "Description": [ - "Kistane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grv", - "Description": [ - "Central Grebo" - ], - "Added": "2009-07-29", - "Macrolanguage": "grb" - }, - { - "Type": "language", - "Subtag": "grw", - "Description": [ - "Gweda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "grx", - "Description": [ - "Guriaso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gry", - "Description": [ - "Barclayville Grebo" - ], - "Added": "2009-07-29", - "Macrolanguage": "grb" - }, - { - "Type": "language", - "Subtag": "grz", - "Description": [ - "Guramalum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gse", - "Description": [ - "Ghanaian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gsg", - "Description": [ - "German Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gsl", - "Description": [ - "Gusilay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gsm", - "Description": [ - "Guatemalan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gsn", - "Description": [ - "Nema", - "Gusan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gso", - "Description": [ - "Southwest Gbaya" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "gsp", - "Description": [ - "Wasembo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gss", - "Description": [ - "Greek Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gsw", - "Description": [ - "Swiss German", - "Alemannic", - "Alsatian" - ], - "Added": "2006-03-08", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "gta", - "Description": [ - "Guató" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gti", - "Description": [ - "Gbati-ri" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "nyc" - }, - { - "Type": "language", - "Subtag": "gtu", - "Description": [ - "Aghu-Tharnggala" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "gua", - "Description": [ - "Shiki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gub", - "Description": [ - "Guajajára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guc", - "Description": [ - "Wayuu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gud", - "Description": [ - "Yocoboué Dida" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gue", - "Description": [ - "Gurindji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guf", - "Description": [ - "Gupapuyngu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gug", - "Description": [ - "Paraguayan Guaraní" - ], - "Added": "2009-07-29", - "Macrolanguage": "gn" - }, - { - "Type": "language", - "Subtag": "guh", - "Description": [ - "Guahibo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gui", - "Description": [ - "Eastern Bolivian Guaraní" - ], - "Added": "2009-07-29", - "Macrolanguage": "gn" - }, - { - "Type": "language", - "Subtag": "guk", - "Description": [ - "Gumuz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gul", - "Description": [ - "Sea Island Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gum", - "Description": [ - "Guambiano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gun", - "Description": [ - "Mbyá Guaraní" - ], - "Added": "2009-07-29", - "Macrolanguage": "gn" - }, - { - "Type": "language", - "Subtag": "guo", - "Description": [ - "Guayabero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gup", - "Description": [ - "Gunwinggu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guq", - "Description": [ - "Aché" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gur", - "Description": [ - "Farefare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gus", - "Description": [ - "Guinean Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gut", - "Description": [ - "Maléku Jaíka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guu", - "Description": [ - "Yanomamö" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guv", - "Description": [ - "Gey" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "duz" - }, - { - "Type": "language", - "Subtag": "guw", - "Description": [ - "Gun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gux", - "Description": [ - "Gourmanchéma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "guz", - "Description": [ - "Gusii", - "Ekegusii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gva", - "Description": [ - "Guana (Paraguay)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvc", - "Description": [ - "Guanano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gve", - "Description": [ - "Duwet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvf", - "Description": [ - "Golin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvj", - "Description": [ - "Guajá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvl", - "Description": [ - "Gulay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvm", - "Description": [ - "Gurmana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvn", - "Description": [ - "Kuku-Yalanji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvo", - "Description": [ - "Gavião Do Jiparaná" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvp", - "Description": [ - "Pará Gavião" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvr", - "Description": [ - "Gurung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvs", - "Description": [ - "Gumawana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gvy", - "Description": [ - "Guyani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwa", - "Description": [ - "Mbato" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwb", - "Description": [ - "Gwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwc", - "Description": [ - "Gawri", - "Kalami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwd", - "Description": [ - "Gawwada" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwe", - "Description": [ - "Gweno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwf", - "Description": [ - "Gowro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwg", - "Description": [ - "Moo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwi", - "Description": [ - "Gwichʼin" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "gwj", - "Description": [ - "Ç€Gwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwm", - "Description": [ - "Awngthim" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "gwn", - "Description": [ - "Gwandara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwr", - "Description": [ - "Gwere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwt", - "Description": [ - "Gawar-Bati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwu", - "Description": [ - "Guwamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gww", - "Description": [ - "Kwini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gwx", - "Description": [ - "Gua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gxx", - "Description": [ - "Wè Southern" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gya", - "Description": [ - "Northwest Gbaya" - ], - "Added": "2009-07-29", - "Macrolanguage": "gba" - }, - { - "Type": "language", - "Subtag": "gyb", - "Description": [ - "Garus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyd", - "Description": [ - "Kayardild" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gye", - "Description": [ - "Gyem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyf", - "Description": [ - "Gungabula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyg", - "Description": [ - "Gbayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyi", - "Description": [ - "Gyele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyl", - "Description": [ - "Gayil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gym", - "Description": [ - "Ngäbere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyn", - "Description": [ - "Guyanese Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyo", - "Description": [ - "Gyalsumdo" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "gyr", - "Description": [ - "Guarayu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyy", - "Description": [ - "Gunya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gyz", - "Description": [ - "Geji", - "Gyaazi" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "gza", - "Description": [ - "Ganza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gzi", - "Description": [ - "Gazi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "gzn", - "Description": [ - "Gane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "haa", - "Description": [ - "Han" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hab", - "Description": [ - "Hanoi Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hac", - "Description": [ - "Gurani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "had", - "Description": [ - "Hatam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hae", - "Description": [ - "Eastern Oromo" - ], - "Added": "2009-07-29", - "Macrolanguage": "om" - }, - { - "Type": "language", - "Subtag": "haf", - "Description": [ - "Haiphong Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hag", - "Description": [ - "Hanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hah", - "Description": [ - "Hahon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hai", - "Description": [ - "Haida" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "haj", - "Description": [ - "Hajong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hak", - "Description": [ - "Hakka Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "hal", - "Description": [ - "Halang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ham", - "Description": [ - "Hewa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "han", - "Description": [ - "Hangaza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hao", - "Description": [ - "Hakö" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hap", - "Description": [ - "Hupla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "haq", - "Description": [ - "Ha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "har", - "Description": [ - "Harari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "has", - "Description": [ - "Haisla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hav", - "Description": [ - "Havu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "haw", - "Description": [ - "Hawaiian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "hax", - "Description": [ - "Southern Haida" - ], - "Added": "2009-07-29", - "Macrolanguage": "hai" - }, - { - "Type": "language", - "Subtag": "hay", - "Description": [ - "Haya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "haz", - "Description": [ - "Hazaragi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hba", - "Description": [ - "Hamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hbb", - "Description": [ - "Huba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hbn", - "Description": [ - "Heiban" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hbo", - "Description": [ - "Ancient Hebrew" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hbu", - "Description": [ - "Habu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hca", - "Description": [ - "Andaman Creole Hindi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hch", - "Description": [ - "Huichol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hdn", - "Description": [ - "Northern Haida" - ], - "Added": "2009-07-29", - "Macrolanguage": "hai" - }, - { - "Type": "language", - "Subtag": "hds", - "Description": [ - "Honduras Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hdy", - "Description": [ - "Hadiyya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hea", - "Description": [ - "Northern Qiandong Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hed", - "Description": [ - "Herdé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "heg", - "Description": [ - "Helong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "heh", - "Description": [ - "Hehe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hei", - "Description": [ - "Heiltsuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hem", - "Description": [ - "Hemba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hgm", - "Description": [ - "HaiÇom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hgw", - "Description": [ - "Haigwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hhi", - "Description": [ - "Hoia Hoia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hhr", - "Description": [ - "Kerak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hhy", - "Description": [ - "Hoyahoya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hia", - "Description": [ - "Lamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hib", - "Description": [ - "Hibito" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hid", - "Description": [ - "Hidatsa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hif", - "Description": [ - "Fiji Hindi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hig", - "Description": [ - "Kamwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hih", - "Description": [ - "Pamosu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hii", - "Description": [ - "Hinduri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hij", - "Description": [ - "Hijuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hik", - "Description": [ - "Seit-Kaitetu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hil", - "Description": [ - "Hiligaynon" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "him", - "Description": [ - "Himachali languages", - "Western Pahari languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "hio", - "Description": [ - "Tsoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hir", - "Description": [ - "Himarimã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hit", - "Description": [ - "Hittite" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "hiw", - "Description": [ - "Hiw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hix", - "Description": [ - "Hixkaryána" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hji", - "Description": [ - "Haji" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "hka", - "Description": [ - "Kahe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hke", - "Description": [ - "Hunde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hkh", - "Description": [ - "Khah", - "Poguli" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "hkk", - "Description": [ - "Hunjara-Kaina Ke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hkn", - "Description": [ - "Mel-Khaonh" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "hks", - "Description": [ - "Hong Kong Sign Language", - "Heung Kong Sau Yue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hla", - "Description": [ - "Halia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hlb", - "Description": [ - "Halbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hld", - "Description": [ - "Halang Doan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hle", - "Description": [ - "Hlersu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hlt", - "Description": [ - "Matu Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hlu", - "Description": [ - "Hieroglyphic Luwian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hma", - "Description": [ - "Southern Mashan Hmong", - "Southern Mashan Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmb", - "Description": [ - "Humburi Senni Songhay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hmc", - "Description": [ - "Central Huishui Hmong", - "Central Huishui Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmd", - "Description": [ - "Large Flowery Miao", - "A-hmaos", - "Da-Hua Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hme", - "Description": [ - "Eastern Huishui Hmong", - "Eastern Huishui Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmf", - "Description": [ - "Hmong Don" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hmg", - "Description": [ - "Southwestern Guiyang Hmong" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmh", - "Description": [ - "Southwestern Huishui Hmong", - "Southwestern Huishui Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmi", - "Description": [ - "Northern Huishui Hmong", - "Northern Huishui Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmj", - "Description": [ - "Ge", - "Gejia" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmk", - "Description": [ - "Maek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hml", - "Description": [ - "Luopohe Hmong", - "Luopohe Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmm", - "Description": [ - "Central Mashan Hmong", - "Central Mashan Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmn", - "Description": [ - "Hmong", - "Mong" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "hmp", - "Description": [ - "Northern Mashan Hmong", - "Northern Mashan Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmq", - "Description": [ - "Eastern Qiandong Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmr", - "Description": [ - "Hmar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hms", - "Description": [ - "Southern Qiandong Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmt", - "Description": [ - "Hamtai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hmu", - "Description": [ - "Hamap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hmv", - "Description": [ - "Hmong Dô" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hmw", - "Description": [ - "Western Mashan Hmong", - "Western Mashan Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmx", - "Description": [ - "Hmong-Mien languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "hmy", - "Description": [ - "Southern Guiyang Hmong", - "Southern Guiyang Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hmz", - "Description": [ - "Hmong Shua", - "Sinicized Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hna", - "Description": [ - "Mina (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hnd", - "Description": [ - "Southern Hindko" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "hne", - "Description": [ - "Chhattisgarhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hng", - "Description": [ - "Hungu" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "hnh", - "Description": [ - "ÇAni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hni", - "Description": [ - "Hani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hnj", - "Description": [ - "Hmong Njua", - "Mong Leng", - "Mong Njua" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hnn", - "Description": [ - "Hanunoo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hno", - "Description": [ - "Northern Hindko" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "hns", - "Description": [ - "Caribbean Hindustani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hnu", - "Description": [ - "Hung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoa", - "Description": [ - "Hoava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hob", - "Description": [ - "Mari (Madang Province)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoc", - "Description": [ - "Ho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hod", - "Description": [ - "Holma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoe", - "Description": [ - "Horom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoh", - "Description": [ - "Hobyót" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoi", - "Description": [ - "Holikachuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoj", - "Description": [ - "Hadothi", - "Haroti" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "hok", - "Description": [ - "Hokan languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "hol", - "Description": [ - "Holu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hom", - "Description": [ - "Homa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoo", - "Description": [ - "Holoholo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hop", - "Description": [ - "Hopi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hor", - "Description": [ - "Horo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hos", - "Description": [ - "Ho Chi Minh City Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hot", - "Description": [ - "Hote", - "Malê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hov", - "Description": [ - "Hovongan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "how", - "Description": [ - "Honi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoy", - "Description": [ - "Holiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hoz", - "Description": [ - "Hozo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hpo", - "Description": [ - "Hpon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hps", - "Description": [ - "Hawai'i Sign Language (HSL)", - "Hawai'i Pidgin Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hra", - "Description": [ - "Hrangkhol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrc", - "Description": [ - "Niwer Mil" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "hre", - "Description": [ - "Hre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrk", - "Description": [ - "Haruku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrm", - "Description": [ - "Horned Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "hro", - "Description": [ - "Haroi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrp", - "Description": [ - "Nhirrpi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "hrr", - "Description": [ - "Horuru" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "jal" - }, - { - "Type": "language", - "Subtag": "hrt", - "Description": [ - "Hértevin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hru", - "Description": [ - "Hruso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrw", - "Description": [ - "Warwar Feni" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "hrx", - "Description": [ - "Hunsrik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hrz", - "Description": [ - "Harzani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hsb", - "Description": [ - "Upper Sorbian" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "hsh", - "Description": [ - "Hungarian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hsl", - "Description": [ - "Hausa Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hsn", - "Description": [ - "Xiang Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "hss", - "Description": [ - "Harsusi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hti", - "Description": [ - "Hoti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hto", - "Description": [ - "Minica Huitoto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hts", - "Description": [ - "Hadza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "htu", - "Description": [ - "Hitu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "htx", - "Description": [ - "Middle Hittite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hub", - "Description": [ - "Huambisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huc", - "Description": [ - "Ç‚Hua", - "ǂʼAmkhoe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hud", - "Description": [ - "Huaulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hue", - "Description": [ - "San Francisco Del Mar Huave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huf", - "Description": [ - "Humene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hug", - "Description": [ - "Huachipaeri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huh", - "Description": [ - "Huilliche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hui", - "Description": [ - "Huli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huj", - "Description": [ - "Northern Guiyang Hmong", - "Northern Guiyang Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "huk", - "Description": [ - "Hulung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hul", - "Description": [ - "Hula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hum", - "Description": [ - "Hungana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huo", - "Description": [ - "Hu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hup", - "Description": [ - "Hupa" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "huq", - "Description": [ - "Tsat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hur", - "Description": [ - "Halkomelem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hus", - "Description": [ - "Huastec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hut", - "Description": [ - "Humla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huu", - "Description": [ - "Murui Huitoto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huv", - "Description": [ - "San Mateo Del Mar Huave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huw", - "Description": [ - "Hukumina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hux", - "Description": [ - "Nüpode Huitoto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huy", - "Description": [ - "Hulaulá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "huz", - "Description": [ - "Hunzib" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hvc", - "Description": [ - "Haitian Vodoun Culture Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hve", - "Description": [ - "San Dionisio Del Mar Huave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hvk", - "Description": [ - "Haveke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hvn", - "Description": [ - "Sabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hvv", - "Description": [ - "Santa María Del Mar Huave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hwa", - "Description": [ - "Wané" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hwc", - "Description": [ - "Hawai'i Creole English", - "Hawai'i Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hwo", - "Description": [ - "Hwana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hya", - "Description": [ - "Hya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "hyw", - "Description": [ - "Western Armenian" - ], - "Added": "2018-03-08", - "Comments": [ - "see also hy" - ] - }, - { - "Type": "language", - "Subtag": "hyx", - "Description": [ - "Armenian (family)" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "iai", - "Description": [ - "Iaai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ian", - "Description": [ - "Iatmul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iap", - "Description": [ - "Iapama" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "iar", - "Description": [ - "Purari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iba", - "Description": [ - "Iban" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ibb", - "Description": [ - "Ibibio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibd", - "Description": [ - "Iwaidja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibe", - "Description": [ - "Akpes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibg", - "Description": [ - "Ibanag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibh", - "Description": [ - "Bih" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "ibi", - "Description": [ - "Ibilo" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "opa" - }, - { - "Type": "language", - "Subtag": "ibl", - "Description": [ - "Ibaloi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibm", - "Description": [ - "Agoi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibn", - "Description": [ - "Ibino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibr", - "Description": [ - "Ibuoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ibu", - "Description": [ - "Ibu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iby", - "Description": [ - "Ibani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ica", - "Description": [ - "Ede Ica" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ich", - "Description": [ - "Etkywan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "icl", - "Description": [ - "Icelandic Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "icr", - "Description": [ - "Islander Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ida", - "Description": [ - "Idakho-Isukha-Tiriki", - "Luidakho-Luisukha-Lutirichi" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "idb", - "Description": [ - "Indo-Portuguese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idc", - "Description": [ - "Idon", - "Ajiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idd", - "Description": [ - "Ede Idaca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ide", - "Description": [ - "Idere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idi", - "Description": [ - "Idi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idr", - "Description": [ - "Indri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ids", - "Description": [ - "Idesa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idt", - "Description": [ - "Idaté" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "idu", - "Description": [ - "Idoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ifa", - "Description": [ - "Amganad Ifugao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ifb", - "Description": [ - "Batad Ifugao", - "Ayangan Ifugao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ife", - "Description": [ - "Ifè" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iff", - "Description": [ - "Ifo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ifk", - "Description": [ - "Tuwali Ifugao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ifm", - "Description": [ - "Teke-Fuumu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ifu", - "Description": [ - "Mayoyao Ifugao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ify", - "Description": [ - "Keley-I Kallahan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igb", - "Description": [ - "Ebira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ige", - "Description": [ - "Igede" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igg", - "Description": [ - "Igana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igl", - "Description": [ - "Igala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igm", - "Description": [ - "Kanggape" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ign", - "Description": [ - "Ignaciano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igo", - "Description": [ - "Isebe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igs", - "Description": [ - "Interglossa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "igw", - "Description": [ - "Igwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ihb", - "Description": [ - "Iha Based Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ihi", - "Description": [ - "Ihievbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ihp", - "Description": [ - "Iha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ihw", - "Description": [ - "Bidhawal" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "iin", - "Description": [ - "Thiin" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "iir", - "Description": [ - "Indo-Iranian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ijc", - "Description": [ - "Izon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ije", - "Description": [ - "Biseni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ijj", - "Description": [ - "Ede Ije" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ijn", - "Description": [ - "Kalabari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ijo", - "Description": [ - "Ijo languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ijs", - "Description": [ - "Southeast Ijo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ike", - "Description": [ - "Eastern Canadian Inuktitut" - ], - "Added": "2009-07-29", - "Macrolanguage": "iu" - }, - { - "Type": "language", - "Subtag": "iki", - "Description": [ - "Iko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikk", - "Description": [ - "Ika" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikl", - "Description": [ - "Ikulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iko", - "Description": [ - "Olulumo-Ikom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikp", - "Description": [ - "Ikpeshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikr", - "Description": [ - "Ikaranggal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "iks", - "Description": [ - "Inuit Sign Language" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "ikt", - "Description": [ - "Inuinnaqtun", - "Western Canadian Inuktitut" - ], - "Added": "2009-07-29", - "Macrolanguage": "iu" - }, - { - "Type": "language", - "Subtag": "ikv", - "Description": [ - "Iku-Gora-Ankwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikw", - "Description": [ - "Ikwere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikx", - "Description": [ - "Ik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ikz", - "Description": [ - "Ikizu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ila", - "Description": [ - "Ile Ape" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilb", - "Description": [ - "Ila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilg", - "Description": [ - "Garig-Ilgar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ili", - "Description": [ - "Ili Turki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilk", - "Description": [ - "Ilongot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ill", - "Description": [ - "Iranun" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Comments": [ - "see ilm, ilp" - ] - }, - { - "Type": "language", - "Subtag": "ilm", - "Description": [ - "Iranun (Malaysia)" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "ilo", - "Description": [ - "Iloko" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ilp", - "Description": [ - "Iranun (Philippines)" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "ils", - "Description": [ - "International Sign" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilu", - "Description": [ - "Ili'uun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilv", - "Description": [ - "Ilue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ilw", - "Description": [ - "Talur" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "gal" - }, - { - "Type": "language", - "Subtag": "ima", - "Description": [ - "Mala Malasar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ime", - "Description": [ - "Imeraguen" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "imi", - "Description": [ - "Anamgura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iml", - "Description": [ - "Miluk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "imn", - "Description": [ - "Imonda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "imo", - "Description": [ - "Imbongu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "imr", - "Description": [ - "Imroing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ims", - "Description": [ - "Marsian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "imt", - "Description": [ - "Imotong" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "imy", - "Description": [ - "Milyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inb", - "Description": [ - "Inga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inc", - "Description": [ - "Indic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ine", - "Description": [ - "Indo-European languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ing", - "Description": [ - "Degexit'an" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inh", - "Description": [ - "Ingush" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "inj", - "Description": [ - "Jungle Inga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inl", - "Description": [ - "Indonesian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inm", - "Description": [ - "Minaean" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inn", - "Description": [ - "Isinai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ino", - "Description": [ - "Inoke-Yate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inp", - "Description": [ - "Iñapari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ins", - "Description": [ - "Indian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "int", - "Description": [ - "Intha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "inz", - "Description": [ - "Ineseño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ior", - "Description": [ - "Inor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iou", - "Description": [ - "Tuma-Irumu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iow", - "Description": [ - "Iowa-Oto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ipi", - "Description": [ - "Ipili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ipo", - "Description": [ - "Ipiko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iqu", - "Description": [ - "Iquito" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iqw", - "Description": [ - "Ikwo" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ira", - "Description": [ - "Iranian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ire", - "Description": [ - "Iresim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "irh", - "Description": [ - "Irarutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iri", - "Description": [ - "Rigwe", - "Irigwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "irk", - "Description": [ - "Iraqw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "irn", - "Description": [ - "Irántxe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iro", - "Description": [ - "Iroquoian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "irr", - "Description": [ - "Ir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iru", - "Description": [ - "Irula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "irx", - "Description": [ - "Kamberau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iry", - "Description": [ - "Iraya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isa", - "Description": [ - "Isabi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isc", - "Description": [ - "Isconahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isd", - "Description": [ - "Isnag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ise", - "Description": [ - "Italian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isg", - "Description": [ - "Irish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ish", - "Description": [ - "Esan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isi", - "Description": [ - "Nkem-Nkum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isk", - "Description": [ - "Ishkashimi" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "ism", - "Description": [ - "Masimasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isn", - "Description": [ - "Isanzu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iso", - "Description": [ - "Isoko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isr", - "Description": [ - "Israeli Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ist", - "Description": [ - "Istriot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "isu", - "Description": [ - "Isu (Menchum Division)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itb", - "Description": [ - "Binongan Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itc", - "Description": [ - "Italic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "itd", - "Description": [ - "Southern Tidung" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "ite", - "Description": [ - "Itene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iti", - "Description": [ - "Inlaod Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itk", - "Description": [ - "Judeo-Italian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itl", - "Description": [ - "Itelmen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itm", - "Description": [ - "Itu Mbon Uzo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ito", - "Description": [ - "Itonama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itr", - "Description": [ - "Iteri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "its", - "Description": [ - "Isekiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itt", - "Description": [ - "Maeng Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itv", - "Description": [ - "Itawit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itw", - "Description": [ - "Ito" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itx", - "Description": [ - "Itik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ity", - "Description": [ - "Moyadan Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "itz", - "Description": [ - "Itzá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ium", - "Description": [ - "Iu Mien" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ivb", - "Description": [ - "Ibatan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ivv", - "Description": [ - "Ivatan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iwk", - "Description": [ - "I-Wak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iwm", - "Description": [ - "Iwam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iwo", - "Description": [ - "Iwur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iws", - "Description": [ - "Sepik Iwam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ixc", - "Description": [ - "Ixcatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ixl", - "Description": [ - "Ixil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iya", - "Description": [ - "Iyayu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iyo", - "Description": [ - "Mesaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "iyx", - "Description": [ - "Yaka (Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "izh", - "Description": [ - "Ingrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "izi", - "Description": [ - "Izi-Ezaa-Ikwo-Mgbo" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see eza, gmz, iqw, izz" - ] - }, - { - "Type": "language", - "Subtag": "izr", - "Description": [ - "Izere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "izz", - "Description": [ - "Izii" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "jaa", - "Description": [ - "Jamamadí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jab", - "Description": [ - "Hyam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jac", - "Description": [ - "Popti'", - "Jakalteko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jad", - "Description": [ - "Jahanka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jae", - "Description": [ - "Yabem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jaf", - "Description": [ - "Jara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jah", - "Description": [ - "Jah Hut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jaj", - "Description": [ - "Zazao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jak", - "Description": [ - "Jakun" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "jal", - "Description": [ - "Yalahatan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jam", - "Description": [ - "Jamaican Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jan", - "Description": [ - "Jandai" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jao", - "Description": [ - "Yanyuwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jaq", - "Description": [ - "Yaqay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jar", - "Description": [ - "Jarawa (Nigeria)" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see jgk, jjr" - ] - }, - { - "Type": "language", - "Subtag": "jas", - "Description": [ - "New Caledonian Javanese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jat", - "Description": [ - "Jakati" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "jau", - "Description": [ - "Yaur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jax", - "Description": [ - "Jambi Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "jay", - "Description": [ - "Yan-nhangu", - "Nhangu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jaz", - "Description": [ - "Jawe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbe", - "Description": [ - "Judeo-Berber" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbi", - "Description": [ - "Badjiri" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "jbj", - "Description": [ - "Arandai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbk", - "Description": [ - "Barikewa" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jbm", - "Description": [ - "Bijim" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "jbn", - "Description": [ - "Nafusi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbo", - "Description": [ - "Lojban" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "jbr", - "Description": [ - "Jofotek-Bromnya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbt", - "Description": [ - "Jabutí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbu", - "Description": [ - "Jukun Takum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jbw", - "Description": [ - "Yawijibaya" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jcs", - "Description": [ - "Jamaican Country Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jct", - "Description": [ - "Krymchak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jda", - "Description": [ - "Jad" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jdg", - "Description": [ - "Jadgali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jdt", - "Description": [ - "Judeo-Tat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jeb", - "Description": [ - "Jebero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jee", - "Description": [ - "Jerung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jeg", - "Description": [ - "Jeng" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23", - "Preferred-Value": "oyb" - }, - { - "Type": "language", - "Subtag": "jeh", - "Description": [ - "Jeh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jei", - "Description": [ - "Yei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jek", - "Description": [ - "Jeri Kuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jel", - "Description": [ - "Yelmek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jen", - "Description": [ - "Dza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jer", - "Description": [ - "Jere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jet", - "Description": [ - "Manem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jeu", - "Description": [ - "Jonkor Bourmataguil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jgb", - "Description": [ - "Ngbee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jge", - "Description": [ - "Judeo-Georgian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jgk", - "Description": [ - "Gwak" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jgo", - "Description": [ - "Ngomba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jhi", - "Description": [ - "Jehai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jhs", - "Description": [ - "Jhankot Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jia", - "Description": [ - "Jina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jib", - "Description": [ - "Jibu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jic", - "Description": [ - "Tol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jid", - "Description": [ - "Bu (Kaduna State)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jie", - "Description": [ - "Jilbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jig", - "Description": [ - "Jingulu", - "Djingili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jih", - "Description": [ - "sTodsde", - "Shangzhai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jii", - "Description": [ - "Jiiddu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jil", - "Description": [ - "Jilim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jim", - "Description": [ - "Jimi (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jio", - "Description": [ - "Jiamao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jiq", - "Description": [ - "Guanyinqiao", - "Lavrung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jit", - "Description": [ - "Jita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jiu", - "Description": [ - "Youle Jinuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jiv", - "Description": [ - "Shuar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jiy", - "Description": [ - "Buyuan Jinuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jje", - "Description": [ - "Jejueo" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "jjr", - "Description": [ - "Bankal" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jka", - "Description": [ - "Kaera" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "jkm", - "Description": [ - "Mobwa Karen" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jko", - "Description": [ - "Kubo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jkp", - "Description": [ - "Paku Karen" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jkr", - "Description": [ - "Koro (India)" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jks", - "Description": [ - "Amami Koniya Sign Language" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "jku", - "Description": [ - "Labir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jle", - "Description": [ - "Ngile" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jls", - "Description": [ - "Jamaican Sign Language" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "jma", - "Description": [ - "Dima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmb", - "Description": [ - "Zumbun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmc", - "Description": [ - "Machame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmd", - "Description": [ - "Yamdena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmi", - "Description": [ - "Jimi (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jml", - "Description": [ - "Jumli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmn", - "Description": [ - "Makuri Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmr", - "Description": [ - "Kamara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jms", - "Description": [ - "Mashi (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jmw", - "Description": [ - "Mouwase" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "jmx", - "Description": [ - "Western Juxtlahuaca Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jna", - "Description": [ - "Jangshung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jnd", - "Description": [ - "Jandavra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jng", - "Description": [ - "Yangman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jni", - "Description": [ - "Janji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jnj", - "Description": [ - "Yemsa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jnl", - "Description": [ - "Rawat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jns", - "Description": [ - "Jaunsari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "job", - "Description": [ - "Joba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jod", - "Description": [ - "Wojenaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jog", - "Description": [ - "Jogi" - ], - "Added": "2015-05-27" - }, - { - "Type": "language", - "Subtag": "jor", - "Description": [ - "Jorá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jos", - "Description": [ - "Jordanian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jow", - "Description": [ - "Jowulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jpa", - "Description": [ - "Jewish Palestinian Aramaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jpr", - "Description": [ - "Judeo-Persian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "jpx", - "Description": [ - "Japanese (family)" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "jqr", - "Description": [ - "Jaqaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jra", - "Description": [ - "Jarai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jrb", - "Description": [ - "Judeo-Arabic" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "jrr", - "Description": [ - "Jiru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jrt", - "Description": [ - "Jakattoe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jru", - "Description": [ - "Japrería" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jsl", - "Description": [ - "Japanese Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jua", - "Description": [ - "Júma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jub", - "Description": [ - "Wannu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juc", - "Description": [ - "Jurchen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jud", - "Description": [ - "Worodougou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juh", - "Description": [ - "Hõne" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jui", - "Description": [ - "Ngadjuri" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "juk", - "Description": [ - "Wapan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jul", - "Description": [ - "Jirel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jum", - "Description": [ - "Jumjum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jun", - "Description": [ - "Juang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juo", - "Description": [ - "Jiba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jup", - "Description": [ - "Hupdë" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jur", - "Description": [ - "Jurúna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jus", - "Description": [ - "Jumla Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jut", - "Description": [ - "Jutish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juu", - "Description": [ - "Ju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juw", - "Description": [ - "Wãpha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "juy", - "Description": [ - "Juray" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jvd", - "Description": [ - "Javindo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jvn", - "Description": [ - "Caribbean Javanese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jwi", - "Description": [ - "Jwira-Pepesa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jya", - "Description": [ - "Jiarong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "jye", - "Description": [ - "Judeo-Yemeni Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "jrb" - }, - { - "Type": "language", - "Subtag": "jyy", - "Description": [ - "Jaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kaa", - "Description": [ - "Kara-Kalpak", - "Karakalpak" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kab", - "Description": [ - "Kabyle" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kac", - "Description": [ - "Kachin", - "Jingpho" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kad", - "Description": [ - "Adara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kae", - "Description": [ - "Ketangalan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kaf", - "Description": [ - "Katso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kag", - "Description": [ - "Kajaman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kah", - "Description": [ - "Kara (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kai", - "Description": [ - "Karekare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kaj", - "Description": [ - "Jju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kak", - "Description": [ - "Kalanguya", - "Kayapa Kallahan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kam", - "Description": [ - "Kamba (Kenya)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kao", - "Description": [ - "Xaasongaxango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kap", - "Description": [ - "Bezhta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kaq", - "Description": [ - "Capanahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kar", - "Description": [ - "Karen languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "kav", - "Description": [ - "Katukína" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kaw", - "Description": [ - "Kawi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kax", - "Description": [ - "Kao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kay", - "Description": [ - "Kamayurá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kba", - "Description": [ - "Kalarko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbb", - "Description": [ - "Kaxuiâna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbc", - "Description": [ - "Kadiwéu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbd", - "Description": [ - "Kabardian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kbe", - "Description": [ - "Kanju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbf", - "Description": [ - "Kakauhua" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "kbg", - "Description": [ - "Khamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbh", - "Description": [ - "Camsá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbi", - "Description": [ - "Kaptiau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbj", - "Description": [ - "Kari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbk", - "Description": [ - "Grass Koiari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbl", - "Description": [ - "Kanembu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbm", - "Description": [ - "Iwal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbn", - "Description": [ - "Kare (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbo", - "Description": [ - "Keliko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbp", - "Description": [ - "Kabiyè" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbq", - "Description": [ - "Kamano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbr", - "Description": [ - "Kafa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbs", - "Description": [ - "Kande" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbt", - "Description": [ - "Abadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbu", - "Description": [ - "Kabutra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbv", - "Description": [ - "Dera (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbw", - "Description": [ - "Kaiep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kbx", - "Description": [ - "Ap Ma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kby", - "Description": [ - "Manga Kanuri" - ], - "Added": "2009-07-29", - "Macrolanguage": "kr" - }, - { - "Type": "language", - "Subtag": "kbz", - "Description": [ - "Duhwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kca", - "Description": [ - "Khanty" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcb", - "Description": [ - "Kawacha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcc", - "Description": [ - "Lubila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcd", - "Description": [ - "Ngkâlmpw Kanum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kce", - "Description": [ - "Kaivi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcf", - "Description": [ - "Ukaan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcg", - "Description": [ - "Tyap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kch", - "Description": [ - "Vono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kci", - "Description": [ - "Kamantan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcj", - "Description": [ - "Kobiana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kck", - "Description": [ - "Kalanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcl", - "Description": [ - "Kela (Papua New Guinea)", - "Kala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcm", - "Description": [ - "Gula (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcn", - "Description": [ - "Nubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kco", - "Description": [ - "Kinalakna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcp", - "Description": [ - "Kanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcq", - "Description": [ - "Kamo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcr", - "Description": [ - "Katla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcs", - "Description": [ - "Koenoem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kct", - "Description": [ - "Kaian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcu", - "Description": [ - "Kami (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcv", - "Description": [ - "Kete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcw", - "Description": [ - "Kabwari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcx", - "Description": [ - "Kachama-Ganjule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcy", - "Description": [ - "Korandje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kcz", - "Description": [ - "Konongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kda", - "Description": [ - "Worimi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdc", - "Description": [ - "Kutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdd", - "Description": [ - "Yankunytjatjara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kde", - "Description": [ - "Makonde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdf", - "Description": [ - "Mamusi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdg", - "Description": [ - "Seba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdh", - "Description": [ - "Tem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdi", - "Description": [ - "Kumam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdj", - "Description": [ - "Karamojong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdk", - "Description": [ - "Numèè", - "Kwényi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdl", - "Description": [ - "Tsikimba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdm", - "Description": [ - "Kagoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdn", - "Description": [ - "Kunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdo", - "Description": [ - "Kordofanian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "kdp", - "Description": [ - "Kaningdon-Nindem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdq", - "Description": [ - "Koch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdr", - "Description": [ - "Karaim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdt", - "Description": [ - "Kuy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdu", - "Description": [ - "Kadaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdv", - "Description": [ - "Kado" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see zkd, zkn" - ] - }, - { - "Type": "language", - "Subtag": "kdw", - "Description": [ - "Koneraw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdx", - "Description": [ - "Kam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdy", - "Description": [ - "Keder", - "Keijar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kdz", - "Description": [ - "Kwaja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kea", - "Description": [ - "Kabuverdianu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keb", - "Description": [ - "Kélé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kec", - "Description": [ - "Keiga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ked", - "Description": [ - "Kerewe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kee", - "Description": [ - "Eastern Keres" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kef", - "Description": [ - "Kpessi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keg", - "Description": [ - "Tese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keh", - "Description": [ - "Keak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kei", - "Description": [ - "Kei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kej", - "Description": [ - "Kadar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kek", - "Description": [ - "Kekchí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kel", - "Description": [ - "Kela (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kem", - "Description": [ - "Kemak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ken", - "Description": [ - "Kenyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keo", - "Description": [ - "Kakwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kep", - "Description": [ - "Kaikadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keq", - "Description": [ - "Kamar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ker", - "Description": [ - "Kera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kes", - "Description": [ - "Kugbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ket", - "Description": [ - "Ket" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "keu", - "Description": [ - "Akebu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kev", - "Description": [ - "Kanikkaran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kew", - "Description": [ - "West Kewa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kex", - "Description": [ - "Kukna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "key", - "Description": [ - "Kupia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kez", - "Description": [ - "Kukele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfa", - "Description": [ - "Kodava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfb", - "Description": [ - "Northwestern Kolami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfc", - "Description": [ - "Konda-Dora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfd", - "Description": [ - "Korra Koraga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfe", - "Description": [ - "Kota (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kff", - "Description": [ - "Koya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfg", - "Description": [ - "Kudiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfh", - "Description": [ - "Kurichiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfi", - "Description": [ - "Kannada Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfj", - "Description": [ - "Kemiehua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfk", - "Description": [ - "Kinnauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfl", - "Description": [ - "Kung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfm", - "Description": [ - "Khunsari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfn", - "Description": [ - "Kuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfo", - "Description": [ - "Koro (Côte d'Ivoire)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfp", - "Description": [ - "Korwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfq", - "Description": [ - "Korku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfr", - "Description": [ - "Kachhi", - "Kutchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfs", - "Description": [ - "Bilaspuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kft", - "Description": [ - "Kanjari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfu", - "Description": [ - "Katkari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfv", - "Description": [ - "Kurmukar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfw", - "Description": [ - "Kharam Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfx", - "Description": [ - "Kullu Pahari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfy", - "Description": [ - "Kumaoni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kfz", - "Description": [ - "Koromfé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kga", - "Description": [ - "Koyaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgb", - "Description": [ - "Kawe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgc", - "Description": [ - "Kasseng" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "tdf" - }, - { - "Type": "language", - "Subtag": "kgd", - "Description": [ - "Kataang" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23", - "Comments": [ - "see ncq, sct" - ] - }, - { - "Type": "language", - "Subtag": "kge", - "Description": [ - "Komering" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgf", - "Description": [ - "Kube" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgg", - "Description": [ - "Kusunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgh", - "Description": [ - "Upper Tanudan Kalinga" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "kml" - }, - { - "Type": "language", - "Subtag": "kgi", - "Description": [ - "Selangor Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgj", - "Description": [ - "Gamale Kham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgk", - "Description": [ - "Kaiwá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgl", - "Description": [ - "Kunggari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgm", - "Description": [ - "Karipúna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgn", - "Description": [ - "Karingani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgo", - "Description": [ - "Krongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgp", - "Description": [ - "Kaingang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgq", - "Description": [ - "Kamoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgr", - "Description": [ - "Abun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgs", - "Description": [ - "Kumbainggar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgt", - "Description": [ - "Somyev" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgu", - "Description": [ - "Kobol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgv", - "Description": [ - "Karas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgw", - "Description": [ - "Karon Dori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgx", - "Description": [ - "Kamaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kgy", - "Description": [ - "Kyerung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kha", - "Description": [ - "Khasi" - ], - "Added": "2005-10-16", - "Comments": [ - "as of 2008-04-21 this subtag does not include Lyngngam; see lyg" - ] - }, - { - "Type": "language", - "Subtag": "khb", - "Description": [ - "Lü" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khc", - "Description": [ - "Tukang Besi North" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khd", - "Description": [ - "Bädi Kanum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khe", - "Description": [ - "Korowai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khf", - "Description": [ - "Khuen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khg", - "Description": [ - "Khams Tibetan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khh", - "Description": [ - "Kehu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khi", - "Description": [ - "Khoisan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "khj", - "Description": [ - "Kuturmi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khk", - "Description": [ - "Halh Mongolian" - ], - "Added": "2009-07-29", - "Macrolanguage": "mn" - }, - { - "Type": "language", - "Subtag": "khl", - "Description": [ - "Lusi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khn", - "Description": [ - "Khandesi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kho", - "Description": [ - "Khotanese", - "Sakan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "khp", - "Description": [ - "Kapori", - "Kapauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khq", - "Description": [ - "Koyra Chiini Songhay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khr", - "Description": [ - "Kharia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khs", - "Description": [ - "Kasua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kht", - "Description": [ - "Khamti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khu", - "Description": [ - "Nkhumbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khv", - "Description": [ - "Khvarshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khw", - "Description": [ - "Khowar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khx", - "Description": [ - "Kanu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khy", - "Description": [ - "Kele (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "khz", - "Description": [ - "Keapara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kia", - "Description": [ - "Kim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kib", - "Description": [ - "Koalib" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kic", - "Description": [ - "Kickapoo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kid", - "Description": [ - "Koshin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kie", - "Description": [ - "Kibet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kif", - "Description": [ - "Eastern Parbate Kham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kig", - "Description": [ - "Kimaama", - "Kimaghima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kih", - "Description": [ - "Kilmeri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kii", - "Description": [ - "Kitsai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kij", - "Description": [ - "Kilivila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kil", - "Description": [ - "Kariya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kim", - "Description": [ - "Karagas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kio", - "Description": [ - "Kiowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kip", - "Description": [ - "Sheshi Kham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kiq", - "Description": [ - "Kosadle", - "Kosare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kis", - "Description": [ - "Kis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kit", - "Description": [ - "Agob" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kiu", - "Description": [ - "Kirmanjki (individual language)" - ], - "Added": "2009-07-29", - "Macrolanguage": "zza" - }, - { - "Type": "language", - "Subtag": "kiv", - "Description": [ - "Kimbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kiw", - "Description": [ - "Northeast Kiwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kix", - "Description": [ - "Khiamniungan Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kiy", - "Description": [ - "Kirikiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kiz", - "Description": [ - "Kisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kja", - "Description": [ - "Mlap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjb", - "Description": [ - "Q'anjob'al", - "Kanjobal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjc", - "Description": [ - "Coastal Konjo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjd", - "Description": [ - "Southern Kiwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kje", - "Description": [ - "Kisar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjf", - "Description": [ - "Khalaj [Indo-Iranian]" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "kjg", - "Description": [ - "Khmu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjh", - "Description": [ - "Khakas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kji", - "Description": [ - "Zabana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjj", - "Description": [ - "Khinalugh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjk", - "Description": [ - "Highland Konjo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjl", - "Description": [ - "Western Parbate Kham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjm", - "Description": [ - "Kháng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjn", - "Description": [ - "Kunjen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjo", - "Description": [ - "Harijan Kinnauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjp", - "Description": [ - "Pwo Eastern Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjq", - "Description": [ - "Western Keres" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjr", - "Description": [ - "Kurudu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjs", - "Description": [ - "East Kewa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjt", - "Description": [ - "Phrae Pwo Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kju", - "Description": [ - "Kashaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjv", - "Description": [ - "Kaikavian Literary Language" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "kjx", - "Description": [ - "Ramopa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjy", - "Description": [ - "Erave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kjz", - "Description": [ - "Bumthangkha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kka", - "Description": [ - "Kakanda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkb", - "Description": [ - "Kwerisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkc", - "Description": [ - "Odoodee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkd", - "Description": [ - "Kinuku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kke", - "Description": [ - "Kakabe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkf", - "Description": [ - "Kalaktang Monpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkg", - "Description": [ - "Mabaka Valley Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkh", - "Description": [ - "Khün" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kki", - "Description": [ - "Kagulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkj", - "Description": [ - "Kako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkk", - "Description": [ - "Kokota" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkl", - "Description": [ - "Kosarek Yale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkm", - "Description": [ - "Kiong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkn", - "Description": [ - "Kon Keu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kko", - "Description": [ - "Karko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkp", - "Description": [ - "Gugubera", - "Koko-Bera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkq", - "Description": [ - "Kaeku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkr", - "Description": [ - "Kir-Balar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kks", - "Description": [ - "Giiwo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkt", - "Description": [ - "Koi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kku", - "Description": [ - "Tumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkv", - "Description": [ - "Kangean" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkw", - "Description": [ - "Teke-Kukuya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkx", - "Description": [ - "Kohin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kky", - "Description": [ - "Guugu Yimidhirr", - "Guguyimidjir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kkz", - "Description": [ - "Kaska" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kla", - "Description": [ - "Klamath-Modoc" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klb", - "Description": [ - "Kiliwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klc", - "Description": [ - "Kolbila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kld", - "Description": [ - "Gamilaraay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kle", - "Description": [ - "Kulung (Nepal)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klf", - "Description": [ - "Kendeje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klg", - "Description": [ - "Tagakaulo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klh", - "Description": [ - "Weliki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kli", - "Description": [ - "Kalumpang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klj", - "Description": [ - "Khalaj" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klk", - "Description": [ - "Kono (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kll", - "Description": [ - "Kagan Kalagan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klm", - "Description": [ - "Migum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kln", - "Description": [ - "Kalenjin" - ], - "Added": "2009-07-29", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "klo", - "Description": [ - "Kapya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klp", - "Description": [ - "Kamasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klq", - "Description": [ - "Rumu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klr", - "Description": [ - "Khaling" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kls", - "Description": [ - "Kalasha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klt", - "Description": [ - "Nukna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klu", - "Description": [ - "Klao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klv", - "Description": [ - "Maskelynes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klw", - "Description": [ - "Tado", - "Lindu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klx", - "Description": [ - "Koluwawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kly", - "Description": [ - "Kalao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "klz", - "Description": [ - "Kabola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kma", - "Description": [ - "Konni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmb", - "Description": [ - "Kimbundu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kmc", - "Description": [ - "Southern Dong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmd", - "Description": [ - "Majukayang Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kme", - "Description": [ - "Bakole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmf", - "Description": [ - "Kare (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmg", - "Description": [ - "Kâte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmh", - "Description": [ - "Kalam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmi", - "Description": [ - "Kami (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmj", - "Description": [ - "Kumarbhag Paharia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmk", - "Description": [ - "Limos Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kml", - "Description": [ - "Tanudan Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmm", - "Description": [ - "Kom (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmn", - "Description": [ - "Awtuw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmo", - "Description": [ - "Kwoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmp", - "Description": [ - "Gimme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmq", - "Description": [ - "Kwama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmr", - "Description": [ - "Northern Kurdish" - ], - "Added": "2009-07-29", - "Macrolanguage": "ku" - }, - { - "Type": "language", - "Subtag": "kms", - "Description": [ - "Kamasau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmt", - "Description": [ - "Kemtuik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmu", - "Description": [ - "Kanite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmv", - "Description": [ - "Karipúna Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmw", - "Description": [ - "Komo (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmx", - "Description": [ - "Waboda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmy", - "Description": [ - "Koma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kmz", - "Description": [ - "Khorasani Turkish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kna", - "Description": [ - "Dera (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knb", - "Description": [ - "Lubuagan Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knc", - "Description": [ - "Central Kanuri" - ], - "Added": "2009-07-29", - "Macrolanguage": "kr" - }, - { - "Type": "language", - "Subtag": "knd", - "Description": [ - "Konda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kne", - "Description": [ - "Kankanaey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knf", - "Description": [ - "Mankanya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kng", - "Description": [ - "Koongo" - ], - "Added": "2009-07-29", - "Macrolanguage": "kg" - }, - { - "Type": "language", - "Subtag": "kni", - "Description": [ - "Kanufi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knj", - "Description": [ - "Western Kanjobal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knk", - "Description": [ - "Kuranko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knl", - "Description": [ - "Keninjal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knm", - "Description": [ - "Kanamarí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knn", - "Description": [ - "Konkani (individual language)" - ], - "Added": "2009-07-29", - "Macrolanguage": "kok" - }, - { - "Type": "language", - "Subtag": "kno", - "Description": [ - "Kono (Sierra Leone)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knp", - "Description": [ - "Kwanja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knq", - "Description": [ - "Kintaq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knr", - "Description": [ - "Kaningra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kns", - "Description": [ - "Kensiu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knt", - "Description": [ - "Panoan Katukína" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knu", - "Description": [ - "Kono (Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knv", - "Description": [ - "Tabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knw", - "Description": [ - "Kung-Ekoka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knx", - "Description": [ - "Kendayan", - "Salako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kny", - "Description": [ - "Kanyok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "knz", - "Description": [ - "Kalamsé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koa", - "Description": [ - "Konomala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koc", - "Description": [ - "Kpati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kod", - "Description": [ - "Kodi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koe", - "Description": [ - "Kacipo-Bale Suri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kof", - "Description": [ - "Kubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kog", - "Description": [ - "Cogui", - "Kogi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koh", - "Description": [ - "Koyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koi", - "Description": [ - "Komi-Permyak" - ], - "Added": "2009-07-29", - "Macrolanguage": "kv" - }, - { - "Type": "language", - "Subtag": "koj", - "Description": [ - "Sara Dunjo" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "kwv" - }, - { - "Type": "language", - "Subtag": "kok", - "Description": [ - "Konkani (macrolanguage)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Deva", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "kol", - "Description": [ - "Kol (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koo", - "Description": [ - "Konzo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kop", - "Description": [ - "Waube" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koq", - "Description": [ - "Kota (Gabon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kos", - "Description": [ - "Kosraean" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kot", - "Description": [ - "Lagwan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kou", - "Description": [ - "Koke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kov", - "Description": [ - "Kudu-Camo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kow", - "Description": [ - "Kugama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kox", - "Description": [ - "Coxima" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "koy", - "Description": [ - "Koyukon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "koz", - "Description": [ - "Korak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpa", - "Description": [ - "Kutto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpb", - "Description": [ - "Mullu Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpc", - "Description": [ - "Curripaco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpd", - "Description": [ - "Koba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpe", - "Description": [ - "Kpelle" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "kpf", - "Description": [ - "Komba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpg", - "Description": [ - "Kapingamarangi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kph", - "Description": [ - "Kplang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpi", - "Description": [ - "Kofei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpj", - "Description": [ - "Karajá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpk", - "Description": [ - "Kpan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpl", - "Description": [ - "Kpala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpm", - "Description": [ - "Koho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpn", - "Description": [ - "Kepkiriwát" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpo", - "Description": [ - "Ikposo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpp", - "Description": [ - "Paku Karen" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see jkm, jkp" - ] - }, - { - "Type": "language", - "Subtag": "kpq", - "Description": [ - "Korupun-Sela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpr", - "Description": [ - "Korafe-Yegha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kps", - "Description": [ - "Tehit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpt", - "Description": [ - "Karata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpu", - "Description": [ - "Kafoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpv", - "Description": [ - "Komi-Zyrian" - ], - "Added": "2009-07-29", - "Macrolanguage": "kv" - }, - { - "Type": "language", - "Subtag": "kpw", - "Description": [ - "Kobon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpx", - "Description": [ - "Mountain Koiali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpy", - "Description": [ - "Koryak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kpz", - "Description": [ - "Kupsabiny" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqa", - "Description": [ - "Mum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqb", - "Description": [ - "Kovai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqc", - "Description": [ - "Doromu-Koki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqd", - "Description": [ - "Koy Sanjaq Surat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqe", - "Description": [ - "Kalagan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqf", - "Description": [ - "Kakabai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqg", - "Description": [ - "Khe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqh", - "Description": [ - "Kisankasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqi", - "Description": [ - "Koitabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqj", - "Description": [ - "Koromira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqk", - "Description": [ - "Kotafon Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kql", - "Description": [ - "Kyenele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqm", - "Description": [ - "Khisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqn", - "Description": [ - "Kaonde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqo", - "Description": [ - "Eastern Krahn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqp", - "Description": [ - "Kimré" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqq", - "Description": [ - "Krenak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqr", - "Description": [ - "Kimaragang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqs", - "Description": [ - "Northern Kissi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqt", - "Description": [ - "Klias River Kadazan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqu", - "Description": [ - "Seroa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqv", - "Description": [ - "Okolod" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqw", - "Description": [ - "Kandas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqx", - "Description": [ - "Mser" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqy", - "Description": [ - "Koorete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kqz", - "Description": [ - "Korana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kra", - "Description": [ - "Kumhali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krb", - "Description": [ - "Karkin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krc", - "Description": [ - "Karachay-Balkar" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "krd", - "Description": [ - "Kairui-Midiki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kre", - "Description": [ - "Panará" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krf", - "Description": [ - "Koro (Vanuatu)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krh", - "Description": [ - "Kurama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kri", - "Description": [ - "Krio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krj", - "Description": [ - "Kinaray-A" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krk", - "Description": [ - "Kerek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krl", - "Description": [ - "Karelian" - ], - "Added": "2006-03-08" - }, - { - "Type": "language", - "Subtag": "krm", - "Description": [ - "Krim" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23", - "Preferred-Value": "bmf" - }, - { - "Type": "language", - "Subtag": "krn", - "Description": [ - "Sapo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kro", - "Description": [ - "Kru languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "krp", - "Description": [ - "Korop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krr", - "Description": [ - "Krung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krs", - "Description": [ - "Gbaya (Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krt", - "Description": [ - "Tumari Kanuri" - ], - "Added": "2009-07-29", - "Macrolanguage": "kr" - }, - { - "Type": "language", - "Subtag": "kru", - "Description": [ - "Kurukh" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "krv", - "Description": [ - "Kavet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krw", - "Description": [ - "Western Krahn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krx", - "Description": [ - "Karon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kry", - "Description": [ - "Kryts" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "krz", - "Description": [ - "Sota Kanum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksa", - "Description": [ - "Shuwa-Zamani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksb", - "Description": [ - "Shambala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksc", - "Description": [ - "Southern Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksd", - "Description": [ - "Kuanua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kse", - "Description": [ - "Kuni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksf", - "Description": [ - "Bafia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksg", - "Description": [ - "Kusaghe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksh", - "Description": [ - "Kölsch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksi", - "Description": [ - "Krisa", - "I'saka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksj", - "Description": [ - "Uare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksk", - "Description": [ - "Kansa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksl", - "Description": [ - "Kumalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksm", - "Description": [ - "Kumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksn", - "Description": [ - "Kasiguranin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kso", - "Description": [ - "Kofa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksp", - "Description": [ - "Kaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksq", - "Description": [ - "Kwaami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksr", - "Description": [ - "Borong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kss", - "Description": [ - "Southern Kisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kst", - "Description": [ - "Winyé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksu", - "Description": [ - "Khamyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksv", - "Description": [ - "Kusu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksw", - "Description": [ - "S'gaw Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksx", - "Description": [ - "Kedang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksy", - "Description": [ - "Kharia Thar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ksz", - "Description": [ - "Kodaku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kta", - "Description": [ - "Katua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktb", - "Description": [ - "Kambaata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktc", - "Description": [ - "Kholok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktd", - "Description": [ - "Kokata", - "Kukatha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kte", - "Description": [ - "Nubri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktf", - "Description": [ - "Kwami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktg", - "Description": [ - "Kalkutung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kth", - "Description": [ - "Karanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kti", - "Description": [ - "North Muyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktj", - "Description": [ - "Plapo Krumen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktk", - "Description": [ - "Kaniet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktl", - "Description": [ - "Koroshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktm", - "Description": [ - "Kurti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktn", - "Description": [ - "Karitiâna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kto", - "Description": [ - "Kuot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktp", - "Description": [ - "Kaduo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktq", - "Description": [ - "Katabaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktr", - "Description": [ - "Kota Marudu Tinagas" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "dtp" - }, - { - "Type": "language", - "Subtag": "kts", - "Description": [ - "South Muyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktt", - "Description": [ - "Ketum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktu", - "Description": [ - "Kituba (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktv", - "Description": [ - "Eastern Katu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktw", - "Description": [ - "Kato" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktx", - "Description": [ - "Kaxararí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kty", - "Description": [ - "Kango (Bas-Uélé District)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ktz", - "Description": [ - "Juǀʼhoan", - "Juǀʼhoansi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kub", - "Description": [ - "Kutep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuc", - "Description": [ - "Kwinsu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kud", - "Description": [ - "'Auhelawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kue", - "Description": [ - "Kuman (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuf", - "Description": [ - "Western Katu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kug", - "Description": [ - "Kupa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuh", - "Description": [ - "Kushi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kui", - "Description": [ - "Kuikúro-Kalapálo", - "Kalapalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuj", - "Description": [ - "Kuria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuk", - "Description": [ - "Kepo'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kul", - "Description": [ - "Kulere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kum", - "Description": [ - "Kumyk" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kun", - "Description": [ - "Kunama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuo", - "Description": [ - "Kumukio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kup", - "Description": [ - "Kunimaipa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuq", - "Description": [ - "Karipuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kus", - "Description": [ - "Kusaal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kut", - "Description": [ - "Kutenai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "kuu", - "Description": [ - "Upper Kuskokwim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuv", - "Description": [ - "Kur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuw", - "Description": [ - "Kpagua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kux", - "Description": [ - "Kukatja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuy", - "Description": [ - "Kuuku-Ya'u" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kuz", - "Description": [ - "Kunza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kva", - "Description": [ - "Bagvalal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvb", - "Description": [ - "Kubu" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "kvc", - "Description": [ - "Kove" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvd", - "Description": [ - "Kui (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kve", - "Description": [ - "Kalabakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvf", - "Description": [ - "Kabalai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvg", - "Description": [ - "Kuni-Boazi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvh", - "Description": [ - "Komodo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvi", - "Description": [ - "Kwang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvj", - "Description": [ - "Psikye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvk", - "Description": [ - "Korean Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvl", - "Description": [ - "Kayaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvm", - "Description": [ - "Kendem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvn", - "Description": [ - "Border Kuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvo", - "Description": [ - "Dobel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvp", - "Description": [ - "Kompane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvq", - "Description": [ - "Geba Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvr", - "Description": [ - "Kerinci" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "kvs", - "Description": [ - "Kunggara" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "gdj" - }, - { - "Type": "language", - "Subtag": "kvt", - "Description": [ - "Lahta Karen", - "Lahta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvu", - "Description": [ - "Yinbaw Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvv", - "Description": [ - "Kola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvw", - "Description": [ - "Wersing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvx", - "Description": [ - "Parkari Koli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvy", - "Description": [ - "Yintale Karen", - "Yintale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kvz", - "Description": [ - "Tsakwambo", - "Tsaukambo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwa", - "Description": [ - "Dâw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwb", - "Description": [ - "Kwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwc", - "Description": [ - "Likwala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwd", - "Description": [ - "Kwaio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwe", - "Description": [ - "Kwerba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwf", - "Description": [ - "Kwara'ae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwg", - "Description": [ - "Sara Kaba Deme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwh", - "Description": [ - "Kowiai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwi", - "Description": [ - "Awa-Cuaiquer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwj", - "Description": [ - "Kwanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwk", - "Description": [ - "Kwakiutl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwl", - "Description": [ - "Kofyar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwm", - "Description": [ - "Kwambi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwn", - "Description": [ - "Kwangali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwo", - "Description": [ - "Kwomtari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwp", - "Description": [ - "Kodia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwq", - "Description": [ - "Kwak" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "yam" - }, - { - "Type": "language", - "Subtag": "kwr", - "Description": [ - "Kwer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kws", - "Description": [ - "Kwese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwt", - "Description": [ - "Kwesten" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwu", - "Description": [ - "Kwakum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwv", - "Description": [ - "Sara Kaba Náà" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kww", - "Description": [ - "Kwinti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwx", - "Description": [ - "Khirwar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kwy", - "Description": [ - "San Salvador Kongo" - ], - "Added": "2009-07-29", - "Macrolanguage": "kg" - }, - { - "Type": "language", - "Subtag": "kwz", - "Description": [ - "Kwadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxa", - "Description": [ - "Kairiru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxb", - "Description": [ - "Krobu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxc", - "Description": [ - "Konso", - "Khonso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxd", - "Description": [ - "Brunei" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "kxe", - "Description": [ - "Kakihum" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "tvd" - }, - { - "Type": "language", - "Subtag": "kxf", - "Description": [ - "Manumanaw Karen", - "Manumanaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxh", - "Description": [ - "Karo (Ethiopia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxi", - "Description": [ - "Keningau Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxj", - "Description": [ - "Kulfa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxk", - "Description": [ - "Zayein Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxl", - "Description": [ - "Nepali Kurux" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "kru" - }, - { - "Type": "language", - "Subtag": "kxm", - "Description": [ - "Northern Khmer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxn", - "Description": [ - "Kanowit-Tanjong Melanau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxo", - "Description": [ - "Kanoé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxp", - "Description": [ - "Wadiyara Koli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxq", - "Description": [ - "Smärky Kanum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxr", - "Description": [ - "Koro (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxs", - "Description": [ - "Kangjia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxt", - "Description": [ - "Koiwat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxu", - "Description": [ - "Kui (India)" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Comments": [ - "see dwk, uki" - ] - }, - { - "Type": "language", - "Subtag": "kxv", - "Description": [ - "Kuvi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxw", - "Description": [ - "Konai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxx", - "Description": [ - "Likuba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxy", - "Description": [ - "Kayong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kxz", - "Description": [ - "Kerewo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kya", - "Description": [ - "Kwaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyb", - "Description": [ - "Butbut Kalinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyc", - "Description": [ - "Kyaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyd", - "Description": [ - "Karey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kye", - "Description": [ - "Krache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyf", - "Description": [ - "Kouya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyg", - "Description": [ - "Keyagana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyh", - "Description": [ - "Karok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyi", - "Description": [ - "Kiput" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyj", - "Description": [ - "Karao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyk", - "Description": [ - "Kamayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyl", - "Description": [ - "Kalapuya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kym", - "Description": [ - "Kpatili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyn", - "Description": [ - "Northern Binukidnon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyo", - "Description": [ - "Kelon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyp", - "Description": [ - "Kang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyq", - "Description": [ - "Kenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyr", - "Description": [ - "Kuruáya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kys", - "Description": [ - "Baram Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyt", - "Description": [ - "Kayagar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyu", - "Description": [ - "Western Kayah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyv", - "Description": [ - "Kayort" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyw", - "Description": [ - "Kudmali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyx", - "Description": [ - "Rapoisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyy", - "Description": [ - "Kambaira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kyz", - "Description": [ - "Kayabí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kza", - "Description": [ - "Western Karaboro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzb", - "Description": [ - "Kaibobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzc", - "Description": [ - "Bondoukou Kulango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzd", - "Description": [ - "Kadai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kze", - "Description": [ - "Kosena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzf", - "Description": [ - "Da'a Kaili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzg", - "Description": [ - "Kikai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzh", - "Description": [ - "Kenuzi-Dongola" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see dgl, xnz" - ] - }, - { - "Type": "language", - "Subtag": "kzi", - "Description": [ - "Kelabit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzj", - "Description": [ - "Coastal Kadazan" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "dtp" - }, - { - "Type": "language", - "Subtag": "kzk", - "Description": [ - "Kazukuru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzl", - "Description": [ - "Kayeli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzm", - "Description": [ - "Kais" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzn", - "Description": [ - "Kokola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzo", - "Description": [ - "Kaningi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzp", - "Description": [ - "Kaidipang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzq", - "Description": [ - "Kaike" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzr", - "Description": [ - "Karang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzs", - "Description": [ - "Sugut Dusun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzt", - "Description": [ - "Tambunan Dusun" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "dtp" - }, - { - "Type": "language", - "Subtag": "kzu", - "Description": [ - "Kayupulau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzv", - "Description": [ - "Komyandaret" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzw", - "Description": [ - "Karirí-Xocó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzx", - "Description": [ - "Kamarian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzy", - "Description": [ - "Kango (Tshopo District)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "kzz", - "Description": [ - "Kalabra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "laa", - "Description": [ - "Southern Subanen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lab", - "Description": [ - "Linear A" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lac", - "Description": [ - "Lacandon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lad", - "Description": [ - "Ladino" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lae", - "Description": [ - "Pattani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "laf", - "Description": [ - "Lafofa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lag", - "Description": [ - "Langi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lah", - "Description": [ - "Lahnda" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "lai", - "Description": [ - "Lambya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "laj", - "Description": [ - "Lango (Uganda)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lak", - "Description": [ - "Laka (Nigeria)" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Preferred-Value": "ksp" - }, - { - "Type": "language", - "Subtag": "lal", - "Description": [ - "Lalia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lam", - "Description": [ - "Lamba" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lan", - "Description": [ - "Laru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lap", - "Description": [ - "Laka (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "laq", - "Description": [ - "Qabiao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lar", - "Description": [ - "Larteh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "las", - "Description": [ - "Lama (Togo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lau", - "Description": [ - "Laba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "law", - "Description": [ - "Lauje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lax", - "Description": [ - "Tiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lay", - "Description": [ - "Lama Bai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "laz", - "Description": [ - "Aribwatsa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lba", - "Description": [ - "Lui" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "lbb", - "Description": [ - "Label" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbc", - "Description": [ - "Lakkia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbe", - "Description": [ - "Lak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbf", - "Description": [ - "Tinani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbg", - "Description": [ - "Laopang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbi", - "Description": [ - "La'bi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbj", - "Description": [ - "Ladakhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbk", - "Description": [ - "Central Bontok" - ], - "Added": "2010-03-11", - "Macrolanguage": "bnc" - }, - { - "Type": "language", - "Subtag": "lbl", - "Description": [ - "Libon Bikol" - ], - "Added": "2010-03-11", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "lbm", - "Description": [ - "Lodhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbn", - "Description": [ - "Rmeet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbo", - "Description": [ - "Laven" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbq", - "Description": [ - "Wampar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbr", - "Description": [ - "Lohorung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbs", - "Description": [ - "Libyan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbt", - "Description": [ - "Lachi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbu", - "Description": [ - "Labu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbv", - "Description": [ - "Lavatbura-Lamusong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbw", - "Description": [ - "Tolaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbx", - "Description": [ - "Lawangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lby", - "Description": [ - "Lamalama", - "Lamu-Lamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lbz", - "Description": [ - "Lardil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcc", - "Description": [ - "Legenyem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcd", - "Description": [ - "Lola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lce", - "Description": [ - "Loncong", - "Sekak" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "lcf", - "Description": [ - "Lubu" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "lch", - "Description": [ - "Luchazi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcl", - "Description": [ - "Lisela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcm", - "Description": [ - "Tungag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcp", - "Description": [ - "Western Lawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcq", - "Description": [ - "Luhu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lcs", - "Description": [ - "Lisabata-Nuniali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lda", - "Description": [ - "Kla-Dan" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ldb", - "Description": [ - "DÅ©ya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldd", - "Description": [ - "Luri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldg", - "Description": [ - "Lenyima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldh", - "Description": [ - "Lamja-Dengsa-Tola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldi", - "Description": [ - "Laari" - ], - "Added": "2009-07-29", - "Macrolanguage": "kg" - }, - { - "Type": "language", - "Subtag": "ldj", - "Description": [ - "Lemoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldk", - "Description": [ - "Leelau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldl", - "Description": [ - "Kaan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldm", - "Description": [ - "Landoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldn", - "Description": [ - "Láadan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldo", - "Description": [ - "Loo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldp", - "Description": [ - "Tso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ldq", - "Description": [ - "Lufu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lea", - "Description": [ - "Lega-Shabunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "leb", - "Description": [ - "Lala-Bisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lec", - "Description": [ - "Leco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "led", - "Description": [ - "Lendu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lee", - "Description": [ - "Lyélé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lef", - "Description": [ - "Lelemi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "leg", - "Description": [ - "Lengua" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28", - "Comments": [ - "see enl, enx" - ] - }, - { - "Type": "language", - "Subtag": "leh", - "Description": [ - "Lenje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lei", - "Description": [ - "Lemio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lej", - "Description": [ - "Lengola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lek", - "Description": [ - "Leipon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lel", - "Description": [ - "Lele (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lem", - "Description": [ - "Nomaande" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "len", - "Description": [ - "Lenca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "leo", - "Description": [ - "Leti (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lep", - "Description": [ - "Lepcha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "leq", - "Description": [ - "Lembena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ler", - "Description": [ - "Lenkau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "les", - "Description": [ - "Lese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "let", - "Description": [ - "Lesing-Gelimi", - "Amio-Gelimi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "leu", - "Description": [ - "Kara (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lev", - "Description": [ - "Lamma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lew", - "Description": [ - "Ledo Kaili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lex", - "Description": [ - "Luang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ley", - "Description": [ - "Lemolang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lez", - "Description": [ - "Lezghian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lfa", - "Description": [ - "Lefa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lfn", - "Description": [ - "Lingua Franca Nova" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lga", - "Description": [ - "Lungga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgb", - "Description": [ - "Laghu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgg", - "Description": [ - "Lugbara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgh", - "Description": [ - "Laghuu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgi", - "Description": [ - "Lengilu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgk", - "Description": [ - "Lingarak", - "Neverver" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgl", - "Description": [ - "Wala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgm", - "Description": [ - "Lega-Mwenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgn", - "Description": [ - "T'apo", - "Opuuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgo", - "Description": [ - "Lango (South Sudan)" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "lgq", - "Description": [ - "Logba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgr", - "Description": [ - "Lengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgt", - "Description": [ - "Pahi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgu", - "Description": [ - "Longgu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lgz", - "Description": [ - "Ligenza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lha", - "Description": [ - "Laha (Viet Nam)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhh", - "Description": [ - "Laha (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhi", - "Description": [ - "Lahu Shi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhl", - "Description": [ - "Lahul Lohar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhm", - "Description": [ - "Lhomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhn", - "Description": [ - "Lahanan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhp", - "Description": [ - "Lhokpu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhs", - "Description": [ - "Mlahsö" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lht", - "Description": [ - "Lo-Toga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lhu", - "Description": [ - "Lahu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lia", - "Description": [ - "West-Central Limba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lib", - "Description": [ - "Likum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lic", - "Description": [ - "Hlai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lid", - "Description": [ - "Nyindrou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lie", - "Description": [ - "Likila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lif", - "Description": [ - "Limbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lig", - "Description": [ - "Ligbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lih", - "Description": [ - "Lihir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lii", - "Description": [ - "Lingkhim" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "raq" - }, - { - "Type": "language", - "Subtag": "lij", - "Description": [ - "Ligurian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lik", - "Description": [ - "Lika" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lil", - "Description": [ - "Lillooet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lio", - "Description": [ - "Liki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lip", - "Description": [ - "Sekpele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liq", - "Description": [ - "Libido" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lir", - "Description": [ - "Liberian English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lis", - "Description": [ - "Lisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liu", - "Description": [ - "Logorik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liv", - "Description": [ - "Liv" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liw", - "Description": [ - "Col" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "lix", - "Description": [ - "Liabuku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liy", - "Description": [ - "Banda-Bambari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "liz", - "Description": [ - "Libinza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lja", - "Description": [ - "Golpa" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lje", - "Description": [ - "Rampi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lji", - "Description": [ - "Laiyolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ljl", - "Description": [ - "Li'o" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ljp", - "Description": [ - "Lampung Api" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ljw", - "Description": [ - "Yirandali" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ljx", - "Description": [ - "Yuru" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lka", - "Description": [ - "Lakalei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkb", - "Description": [ - "Kabras", - "Lukabaras" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lkc", - "Description": [ - "Kucong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkd", - "Description": [ - "Lakondê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lke", - "Description": [ - "Kenyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkh", - "Description": [ - "Lakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lki", - "Description": [ - "Laki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkj", - "Description": [ - "Remun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkl", - "Description": [ - "Laeko-Libuat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lkm", - "Description": [ - "Kalaamaya" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lkn", - "Description": [ - "Lakon", - "Vure" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lko", - "Description": [ - "Khayo", - "Olukhayo" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lkr", - "Description": [ - "Päri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lks", - "Description": [ - "Kisa", - "Olushisa" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lkt", - "Description": [ - "Lakota" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lku", - "Description": [ - "Kungkari" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lky", - "Description": [ - "Lokoya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lla", - "Description": [ - "Lala-Roba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llb", - "Description": [ - "Lolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llc", - "Description": [ - "Lele (Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lld", - "Description": [ - "Ladin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lle", - "Description": [ - "Lele (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llf", - "Description": [ - "Hermit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llg", - "Description": [ - "Lole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llh", - "Description": [ - "Lamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lli", - "Description": [ - "Teke-Laali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llj", - "Description": [ - "Ladji Ladji" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "llk", - "Description": [ - "Lelak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lll", - "Description": [ - "Lilau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llm", - "Description": [ - "Lasalimu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lln", - "Description": [ - "Lele (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llo", - "Description": [ - "Khlor" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Preferred-Value": "ngt" - }, - { - "Type": "language", - "Subtag": "llp", - "Description": [ - "North Efate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llq", - "Description": [ - "Lolak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lls", - "Description": [ - "Lithuanian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llu", - "Description": [ - "Lau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "llx", - "Description": [ - "Lauan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lma", - "Description": [ - "East Limba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmb", - "Description": [ - "Merei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmc", - "Description": [ - "Limilngan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmd", - "Description": [ - "Lumun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lme", - "Description": [ - "Pévé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmf", - "Description": [ - "South Lembata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmg", - "Description": [ - "Lamogai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmh", - "Description": [ - "Lambichhong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmi", - "Description": [ - "Lombi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmj", - "Description": [ - "West Lembata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmk", - "Description": [ - "Lamkang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lml", - "Description": [ - "Hano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmm", - "Description": [ - "Lamam" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28", - "Preferred-Value": "rmx" - }, - { - "Type": "language", - "Subtag": "lmn", - "Description": [ - "Lambadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmo", - "Description": [ - "Lombard" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmp", - "Description": [ - "Limbum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmq", - "Description": [ - "Lamatuka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmr", - "Description": [ - "Lamalera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmu", - "Description": [ - "Lamenu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmv", - "Description": [ - "Lomaiviti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmw", - "Description": [ - "Lake Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmx", - "Description": [ - "Laimbue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmy", - "Description": [ - "Lamboya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lmz", - "Description": [ - "Lumbee" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "lna", - "Description": [ - "Langbashe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnb", - "Description": [ - "Mbalanhu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnd", - "Description": [ - "Lundayeh", - "Lun Bawang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lng", - "Description": [ - "Langobardic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnh", - "Description": [ - "Lanoh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lni", - "Description": [ - "Daantanai'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnj", - "Description": [ - "Leningitij" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnl", - "Description": [ - "South Central Banda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnm", - "Description": [ - "Langam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnn", - "Description": [ - "Lorediakarkar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lno", - "Description": [ - "Lango (South Sudan)" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Comments": [ - "see imt, lgo, lqr, oie" - ] - }, - { - "Type": "language", - "Subtag": "lns", - "Description": [ - "Lamnso'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnu", - "Description": [ - "Longuda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lnw", - "Description": [ - "Lanima" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lnz", - "Description": [ - "Lonzo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loa", - "Description": [ - "Loloda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lob", - "Description": [ - "Lobi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loc", - "Description": [ - "Inonhan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loe", - "Description": [ - "Saluan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lof", - "Description": [ - "Logol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "log", - "Description": [ - "Logo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loh", - "Description": [ - "Narim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loi", - "Description": [ - "Loma (Côte d'Ivoire)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loj", - "Description": [ - "Lou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lok", - "Description": [ - "Loko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lol", - "Description": [ - "Mongo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lom", - "Description": [ - "Loma (Liberia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lon", - "Description": [ - "Malawi Lomwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loo", - "Description": [ - "Lombo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lop", - "Description": [ - "Lopa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loq", - "Description": [ - "Lobala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lor", - "Description": [ - "Téén" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "los", - "Description": [ - "Loniu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lot", - "Description": [ - "Otuho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lou", - "Description": [ - "Louisiana Creole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lov", - "Description": [ - "Lopi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "low", - "Description": [ - "Tampias Lobu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lox", - "Description": [ - "Loun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loy", - "Description": [ - "Loke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "loz", - "Description": [ - "Lozi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lpa", - "Description": [ - "Lelepa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lpe", - "Description": [ - "Lepki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lpn", - "Description": [ - "Long Phuri Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lpo", - "Description": [ - "Lipo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lpx", - "Description": [ - "Lopit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lqr", - "Description": [ - "Logir" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "lra", - "Description": [ - "Rara Bakati'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrc", - "Description": [ - "Northern Luri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lre", - "Description": [ - "Laurentian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrg", - "Description": [ - "Laragia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lri", - "Description": [ - "Marachi", - "Olumarachi" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lrk", - "Description": [ - "Loarki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrl", - "Description": [ - "Lari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrm", - "Description": [ - "Marama", - "Olumarama" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lrn", - "Description": [ - "Lorang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lro", - "Description": [ - "Laro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrr", - "Description": [ - "Southern Yamphu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrt", - "Description": [ - "Larantuka Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrv", - "Description": [ - "Larevat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lrz", - "Description": [ - "Lemerig" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsa", - "Description": [ - "Lasgerdi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsb", - "Description": [ - "Burundian Sign Language", - "Langue des Signes Burundaise" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "lsc", - "Description": [ - "Albarradas Sign Language", - "Lengua de señas Albarradas" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "lsd", - "Description": [ - "Lishana Deni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lse", - "Description": [ - "Lusengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsg", - "Description": [ - "Lyons Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "lsh", - "Description": [ - "Lish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsi", - "Description": [ - "Lashi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsl", - "Description": [ - "Latvian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsm", - "Description": [ - "Saamia", - "Olusamia" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lsn", - "Description": [ - "Tibetan Sign Language" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "lso", - "Description": [ - "Laos Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsp", - "Description": [ - "Panamanian Sign Language", - "Lengua de Señas Panameñas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsr", - "Description": [ - "Aruop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lss", - "Description": [ - "Lasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lst", - "Description": [ - "Trinidad and Tobago Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lsv", - "Description": [ - "Sivia Sign Language" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "lsw", - "Description": [ - "Seychelles Sign Language", - "Lalang Siny Seselwa", - "Langue des Signes Seychelloise" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "lsy", - "Description": [ - "Mauritian Sign Language" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "ltc", - "Description": [ - "Late Middle Chinese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ltg", - "Description": [ - "Latgalian" - ], - "Added": "2010-03-11", - "Macrolanguage": "lv" - }, - { - "Type": "language", - "Subtag": "lth", - "Description": [ - "Thur" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "lti", - "Description": [ - "Leti (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ltn", - "Description": [ - "Latundê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lto", - "Description": [ - "Tsotso", - "Olutsotso" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lts", - "Description": [ - "Tachoni", - "Lutachoni" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "ltu", - "Description": [ - "Latu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lua", - "Description": [ - "Luba-Lulua" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "luc", - "Description": [ - "Aringa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lud", - "Description": [ - "Ludian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lue", - "Description": [ - "Luvale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luf", - "Description": [ - "Laua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lui", - "Description": [ - "Luiseno" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "luj", - "Description": [ - "Luna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luk", - "Description": [ - "Lunanakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lul", - "Description": [ - "Olu'bo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lum", - "Description": [ - "Luimbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lun", - "Description": [ - "Lunda" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "luo", - "Description": [ - "Luo (Kenya and Tanzania)", - "Dholuo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lup", - "Description": [ - "Lumbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luq", - "Description": [ - "Lucumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lur", - "Description": [ - "Laura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lus", - "Description": [ - "Lushai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "lut", - "Description": [ - "Lushootseed" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luu", - "Description": [ - "Lumba-Yakkha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luv", - "Description": [ - "Luwati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luw", - "Description": [ - "Luo (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "luy", - "Description": [ - "Luyia", - "Oluluyia" - ], - "Added": "2009-07-29", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "luz", - "Description": [ - "Southern Luri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lva", - "Description": [ - "Maku'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lvi", - "Description": [ - "Lavi" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "lvk", - "Description": [ - "Lavukaleve" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lvs", - "Description": [ - "Standard Latvian" - ], - "Added": "2010-03-11", - "Macrolanguage": "lv" - }, - { - "Type": "language", - "Subtag": "lvu", - "Description": [ - "Levuka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwa", - "Description": [ - "Lwalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwe", - "Description": [ - "Lewo Eleng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwg", - "Description": [ - "Wanga", - "Oluwanga" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "lwh", - "Description": [ - "White Lachi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwl", - "Description": [ - "Eastern Lawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwm", - "Description": [ - "Laomian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwo", - "Description": [ - "Luwo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lws", - "Description": [ - "Malawian Sign Language" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "lwt", - "Description": [ - "Lewotobi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lwu", - "Description": [ - "Lawu" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "lww", - "Description": [ - "Lewo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lxm", - "Description": [ - "Lakurumau" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "lya", - "Description": [ - "Layakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lyg", - "Description": [ - "Lyngngam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lyn", - "Description": [ - "Luyana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lzh", - "Description": [ - "Literary Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "lzl", - "Description": [ - "Litzlitz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lzn", - "Description": [ - "Leinong Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "lzz", - "Description": [ - "Laz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "maa", - "Description": [ - "San Jerónimo Tecóatl Mazatec" - ], - "Added": "2009-07-29", - "Comments": [ - "see also pbm" - ] - }, - { - "Type": "language", - "Subtag": "mab", - "Description": [ - "Yutanduchi Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mad", - "Description": [ - "Madurese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mae", - "Description": [ - "Bo-Rukul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "maf", - "Description": [ - "Mafa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mag", - "Description": [ - "Magahi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mai", - "Description": [ - "Maithili" - ], - "Added": "2005-10-16", - "Suppress-Script": "Deva" - }, - { - "Type": "language", - "Subtag": "maj", - "Description": [ - "Jalapa De Díaz Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mak", - "Description": [ - "Makasar" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mam", - "Description": [ - "Mam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "man", - "Description": [ - "Mandingo", - "Manding" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "map", - "Description": [ - "Austronesian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "maq", - "Description": [ - "Chiquihuitlán Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mas", - "Description": [ - "Masai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mat", - "Description": [ - "San Francisco Matlatzinca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mau", - "Description": [ - "Huautla Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mav", - "Description": [ - "Sateré-Mawé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "maw", - "Description": [ - "Mampruli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "max", - "Description": [ - "North Moluccan Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "maz", - "Description": [ - "Central Mazahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mba", - "Description": [ - "Higaonon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbb", - "Description": [ - "Western Bukidnon Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbc", - "Description": [ - "Macushi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbd", - "Description": [ - "Dibabawon Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbe", - "Description": [ - "Molale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbf", - "Description": [ - "Baba Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbh", - "Description": [ - "Mangseng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbi", - "Description": [ - "Ilianen Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbj", - "Description": [ - "Nadëb" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbk", - "Description": [ - "Malol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbl", - "Description": [ - "Maxakalí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbm", - "Description": [ - "Ombamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbn", - "Description": [ - "Macaguán" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbo", - "Description": [ - "Mbo (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbp", - "Description": [ - "Malayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbq", - "Description": [ - "Maisin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbr", - "Description": [ - "Nukak Makú" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbs", - "Description": [ - "Sarangani Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbt", - "Description": [ - "Matigsalug Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbu", - "Description": [ - "Mbula-Bwazza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbv", - "Description": [ - "Mbulungish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbw", - "Description": [ - "Maring" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbx", - "Description": [ - "Mari (East Sepik Province)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mby", - "Description": [ - "Memoni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mbz", - "Description": [ - "Amoltepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mca", - "Description": [ - "Maca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcb", - "Description": [ - "Machiguenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcc", - "Description": [ - "Bitur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcd", - "Description": [ - "Sharanahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mce", - "Description": [ - "Itundujia Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcf", - "Description": [ - "Matsés" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcg", - "Description": [ - "Mapoyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mch", - "Description": [ - "Maquiritari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mci", - "Description": [ - "Mese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcj", - "Description": [ - "Mvanip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mck", - "Description": [ - "Mbunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcl", - "Description": [ - "Macaguaje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcm", - "Description": [ - "Malaccan Creole Portuguese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcn", - "Description": [ - "Masana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mco", - "Description": [ - "Coatlán Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcp", - "Description": [ - "Makaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcq", - "Description": [ - "Ese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcr", - "Description": [ - "Menya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcs", - "Description": [ - "Mambai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mct", - "Description": [ - "Mengisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcu", - "Description": [ - "Cameroon Mambila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcv", - "Description": [ - "Minanibai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcw", - "Description": [ - "Mawa (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcx", - "Description": [ - "Mpiemo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcy", - "Description": [ - "South Watut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mcz", - "Description": [ - "Mawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mda", - "Description": [ - "Mada (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdb", - "Description": [ - "Morigi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdc", - "Description": [ - "Male (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdd", - "Description": [ - "Mbum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mde", - "Description": [ - "Maba (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdf", - "Description": [ - "Moksha" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mdg", - "Description": [ - "Massalat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdh", - "Description": [ - "Maguindanaon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdi", - "Description": [ - "Mamvu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdj", - "Description": [ - "Mangbetu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdk", - "Description": [ - "Mangbutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdl", - "Description": [ - "Maltese Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdm", - "Description": [ - "Mayogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdn", - "Description": [ - "Mbati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdp", - "Description": [ - "Mbala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdq", - "Description": [ - "Mbole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdr", - "Description": [ - "Mandar" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mds", - "Description": [ - "Maria (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdt", - "Description": [ - "Mbere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdu", - "Description": [ - "Mboko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdv", - "Description": [ - "Santa Lucía Monteverde Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdw", - "Description": [ - "Mbosi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdx", - "Description": [ - "Dizin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdy", - "Description": [ - "Male (Ethiopia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mdz", - "Description": [ - "Suruí Do Pará" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mea", - "Description": [ - "Menka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "meb", - "Description": [ - "Ikobi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mec", - "Description": [ - "Marra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "med", - "Description": [ - "Melpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mee", - "Description": [ - "Mengen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mef", - "Description": [ - "Megam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "meg", - "Description": [ - "Mea" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "cir" - }, - { - "Type": "language", - "Subtag": "meh", - "Description": [ - "Southwestern Tlaxiaco Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mei", - "Description": [ - "Midob" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mej", - "Description": [ - "Meyah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mek", - "Description": [ - "Mekeo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mel", - "Description": [ - "Central Melanau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mem", - "Description": [ - "Mangala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "men", - "Description": [ - "Mende (Sierra Leone)" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "meo", - "Description": [ - "Kedah Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "mep", - "Description": [ - "Miriwoong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "meq", - "Description": [ - "Merey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mer", - "Description": [ - "Meru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mes", - "Description": [ - "Masmaje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "met", - "Description": [ - "Mato" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "meu", - "Description": [ - "Motu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mev", - "Description": [ - "Mano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mew", - "Description": [ - "Maaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mey", - "Description": [ - "Hassaniyya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mez", - "Description": [ - "Menominee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfa", - "Description": [ - "Pattani Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "mfb", - "Description": [ - "Bangka" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "mfc", - "Description": [ - "Mba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfd", - "Description": [ - "Mendankwe-Nkwen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfe", - "Description": [ - "Morisyen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mff", - "Description": [ - "Naki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfg", - "Description": [ - "Mogofin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfh", - "Description": [ - "Matal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfi", - "Description": [ - "Wandala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfj", - "Description": [ - "Mefele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfk", - "Description": [ - "North Mofu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfl", - "Description": [ - "Putai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfm", - "Description": [ - "Marghi South" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfn", - "Description": [ - "Cross River Mbembe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfo", - "Description": [ - "Mbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfp", - "Description": [ - "Makassar Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfq", - "Description": [ - "Moba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfr", - "Description": [ - "Marrithiyel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfs", - "Description": [ - "Mexican Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mft", - "Description": [ - "Mokerang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfu", - "Description": [ - "Mbwela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfv", - "Description": [ - "Mandjak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfw", - "Description": [ - "Mulaha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfx", - "Description": [ - "Melo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfy", - "Description": [ - "Mayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mfz", - "Description": [ - "Mabaan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mga", - "Description": [ - "Middle Irish (900-1200)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mgb", - "Description": [ - "Mararit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgc", - "Description": [ - "Morokodo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgd", - "Description": [ - "Moru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mge", - "Description": [ - "Mango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgf", - "Description": [ - "Maklew" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgg", - "Description": [ - "Mpumpong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgh", - "Description": [ - "Makhuwa-Meetto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgi", - "Description": [ - "Lijili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgj", - "Description": [ - "Abureni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgk", - "Description": [ - "Mawes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgl", - "Description": [ - "Maleu-Kilenge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgm", - "Description": [ - "Mambae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgn", - "Description": [ - "Mbangi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgo", - "Description": [ - "Meta'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgp", - "Description": [ - "Eastern Magar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgq", - "Description": [ - "Malila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgr", - "Description": [ - "Mambwe-Lungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgs", - "Description": [ - "Manda (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgt", - "Description": [ - "Mongol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgu", - "Description": [ - "Mailu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgv", - "Description": [ - "Matengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgw", - "Description": [ - "Matumbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgx", - "Description": [ - "Omati" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see jbk, jmw" - ] - }, - { - "Type": "language", - "Subtag": "mgy", - "Description": [ - "Mbunga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mgz", - "Description": [ - "Mbugwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mha", - "Description": [ - "Manda (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhb", - "Description": [ - "Mahongwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhc", - "Description": [ - "Mocho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhd", - "Description": [ - "Mbugu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhe", - "Description": [ - "Besisi", - "Mah Meri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhf", - "Description": [ - "Mamaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhg", - "Description": [ - "Margu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhh", - "Description": [ - "Maskoy Pidgin" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "mhi", - "Description": [ - "Ma'di" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhj", - "Description": [ - "Mogholi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhk", - "Description": [ - "Mungaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhl", - "Description": [ - "Mauwake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhm", - "Description": [ - "Makhuwa-Moniga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhn", - "Description": [ - "Mócheno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mho", - "Description": [ - "Mashi (Zambia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhp", - "Description": [ - "Balinese Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhq", - "Description": [ - "Mandan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhr", - "Description": [ - "Eastern Mari" - ], - "Added": "2009-07-29", - "Macrolanguage": "chm" - }, - { - "Type": "language", - "Subtag": "mhs", - "Description": [ - "Buru (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mht", - "Description": [ - "Mandahuaca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhu", - "Description": [ - "Digaro-Mishmi", - "Darang Deng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhw", - "Description": [ - "Mbukushu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhx", - "Description": [ - "Maru", - "Lhaovo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhy", - "Description": [ - "Ma'anyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mhz", - "Description": [ - "Mor (Mor Islands)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mia", - "Description": [ - "Miami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mib", - "Description": [ - "Atatláhuca Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mic", - "Description": [ - "Mi'kmaq", - "Micmac" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mid", - "Description": [ - "Mandaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mie", - "Description": [ - "Ocotepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mif", - "Description": [ - "Mofu-Gudur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mig", - "Description": [ - "San Miguel El Grande Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mih", - "Description": [ - "Chayuco Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mii", - "Description": [ - "Chigmecatitlán Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mij", - "Description": [ - "Abar", - "Mungbam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mik", - "Description": [ - "Mikasuki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mil", - "Description": [ - "Peñoles Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mim", - "Description": [ - "Alacatlatzala Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "min", - "Description": [ - "Minangkabau" - ], - "Added": "2005-10-16", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "mio", - "Description": [ - "Pinotepa Nacional Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mip", - "Description": [ - "Apasco-Apoala Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "miq", - "Description": [ - "Mískito" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mir", - "Description": [ - "Isthmus Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mis", - "Description": [ - "Uncoded languages" - ], - "Added": "2005-10-16", - "Scope": "special" - }, - { - "Type": "language", - "Subtag": "mit", - "Description": [ - "Southern Puebla Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "miu", - "Description": [ - "Cacaloxtepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "miw", - "Description": [ - "Akoye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mix", - "Description": [ - "Mixtepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "miy", - "Description": [ - "Ayutla Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "miz", - "Description": [ - "Coatzospan Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mja", - "Description": [ - "Mahei" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "mjb", - "Description": [ - "Makalero" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "mjc", - "Description": [ - "San Juan Colorado Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjd", - "Description": [ - "Northwest Maidu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mje", - "Description": [ - "Muskum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjg", - "Description": [ - "Tu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjh", - "Description": [ - "Mwera (Nyasa)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mji", - "Description": [ - "Kim Mun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjj", - "Description": [ - "Mawak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjk", - "Description": [ - "Matukar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjl", - "Description": [ - "Mandeali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjm", - "Description": [ - "Medebur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjn", - "Description": [ - "Ma (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjo", - "Description": [ - "Malankuravan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjp", - "Description": [ - "Malapandaram" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjq", - "Description": [ - "Malaryan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjr", - "Description": [ - "Malavedan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjs", - "Description": [ - "Miship" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjt", - "Description": [ - "Sauria Paharia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mju", - "Description": [ - "Manna-Dora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjv", - "Description": [ - "Mannan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjw", - "Description": [ - "Karbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjx", - "Description": [ - "Mahali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjy", - "Description": [ - "Mahican" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mjz", - "Description": [ - "Majhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mka", - "Description": [ - "Mbre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkb", - "Description": [ - "Mal Paharia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkc", - "Description": [ - "Siliput" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mke", - "Description": [ - "Mawchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkf", - "Description": [ - "Miya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkg", - "Description": [ - "Mak (China)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkh", - "Description": [ - "Mon-Khmer languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "mki", - "Description": [ - "Dhatki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkj", - "Description": [ - "Mokilese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkk", - "Description": [ - "Byep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkl", - "Description": [ - "Mokole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkm", - "Description": [ - "Moklen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkn", - "Description": [ - "Kupang Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mko", - "Description": [ - "Mingang Doso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkp", - "Description": [ - "Moikodi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkq", - "Description": [ - "Bay Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkr", - "Description": [ - "Malas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mks", - "Description": [ - "Silacayoapan Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkt", - "Description": [ - "Vamale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mku", - "Description": [ - "Konyanka Maninka" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "mkv", - "Description": [ - "Mafea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkw", - "Description": [ - "Kituba (Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkx", - "Description": [ - "Kinamiging Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mky", - "Description": [ - "East Makian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mkz", - "Description": [ - "Makasae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mla", - "Description": [ - "Malo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlb", - "Description": [ - "Mbule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlc", - "Description": [ - "Cao Lan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mld", - "Description": [ - "Malakhel" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "mle", - "Description": [ - "Manambu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlf", - "Description": [ - "Mal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlh", - "Description": [ - "Mape" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mli", - "Description": [ - "Malimpung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlj", - "Description": [ - "Miltu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlk", - "Description": [ - "Ilwana", - "Kiwilwana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mll", - "Description": [ - "Malua Bay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlm", - "Description": [ - "Mulam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mln", - "Description": [ - "Malango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlo", - "Description": [ - "Mlomp" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlp", - "Description": [ - "Bargam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlq", - "Description": [ - "Western Maninkakan" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "mlr", - "Description": [ - "Vame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mls", - "Description": [ - "Masalit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlu", - "Description": [ - "To'abaita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlv", - "Description": [ - "Motlav", - "Mwotlap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlw", - "Description": [ - "Moloko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlx", - "Description": [ - "Malfaxal", - "Naha'ai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mlz", - "Description": [ - "Malaynon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mma", - "Description": [ - "Mama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmb", - "Description": [ - "Momina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmc", - "Description": [ - "Michoacán Mazahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmd", - "Description": [ - "Maonan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mme", - "Description": [ - "Mae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmf", - "Description": [ - "Mundat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmg", - "Description": [ - "North Ambrym" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmh", - "Description": [ - "Mehináku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmi", - "Description": [ - "Musar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmj", - "Description": [ - "Majhwar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmk", - "Description": [ - "Mukha-Dora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mml", - "Description": [ - "Man Met" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmm", - "Description": [ - "Maii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmn", - "Description": [ - "Mamanwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmo", - "Description": [ - "Mangga Buang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmp", - "Description": [ - "Siawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmq", - "Description": [ - "Musak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmr", - "Description": [ - "Western Xiangxi Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "mmt", - "Description": [ - "Malalamai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmu", - "Description": [ - "Mmaala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmv", - "Description": [ - "Miriti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmw", - "Description": [ - "Emae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmx", - "Description": [ - "Madak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmy", - "Description": [ - "Migaama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mmz", - "Description": [ - "Mabaale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mna", - "Description": [ - "Mbula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnb", - "Description": [ - "Muna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnc", - "Description": [ - "Manchu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mnd", - "Description": [ - "Mondé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mne", - "Description": [ - "Naba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnf", - "Description": [ - "Mundani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mng", - "Description": [ - "Eastern Mnong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnh", - "Description": [ - "Mono (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mni", - "Description": [ - "Manipuri" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mnj", - "Description": [ - "Munji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnk", - "Description": [ - "Mandinka" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "mnl", - "Description": [ - "Tiale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnm", - "Description": [ - "Mapena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnn", - "Description": [ - "Southern Mnong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mno", - "Description": [ - "Manobo languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "mnp", - "Description": [ - "Min Bei Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "mnq", - "Description": [ - "Minriq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnr", - "Description": [ - "Mono (USA)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mns", - "Description": [ - "Mansi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnt", - "Description": [ - "Maykulan" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see wnn, xyj, xyk, xyt" - ] - }, - { - "Type": "language", - "Subtag": "mnu", - "Description": [ - "Mer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnv", - "Description": [ - "Rennell-Bellona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnw", - "Description": [ - "Mon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnx", - "Description": [ - "Manikion" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mny", - "Description": [ - "Manyawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mnz", - "Description": [ - "Moni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moa", - "Description": [ - "Mwan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moc", - "Description": [ - "Mocoví" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mod", - "Description": [ - "Mobilian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moe", - "Description": [ - "Innu", - "Montagnais" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mof", - "Description": [ - "Mohegan-Montauk-Narragansett" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see xnt, xpq" - ] - }, - { - "Type": "language", - "Subtag": "mog", - "Description": [ - "Mongondow" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moh", - "Description": [ - "Mohawk" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "moi", - "Description": [ - "Mboi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moj", - "Description": [ - "Monzombo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mok", - "Description": [ - "Morori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mom", - "Description": [ - "Mangue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moo", - "Description": [ - "Monom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mop", - "Description": [ - "Mopán Maya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moq", - "Description": [ - "Mor (Bomberai Peninsula)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mor", - "Description": [ - "Moro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mos", - "Description": [ - "Mossi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mot", - "Description": [ - "Barí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mou", - "Description": [ - "Mogum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mov", - "Description": [ - "Mohave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mow", - "Description": [ - "Moi (Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mox", - "Description": [ - "Molima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moy", - "Description": [ - "Shekkacho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "moz", - "Description": [ - "Mukulu", - "Gergiko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpa", - "Description": [ - "Mpoto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpb", - "Description": [ - "Malak Malak", - "Mullukmulluk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpc", - "Description": [ - "Mangarrayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpd", - "Description": [ - "Machinere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpe", - "Description": [ - "Majang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpg", - "Description": [ - "Marba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mph", - "Description": [ - "Maung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpi", - "Description": [ - "Mpade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpj", - "Description": [ - "Martu Wangka", - "Wangkajunga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpk", - "Description": [ - "Mbara (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpl", - "Description": [ - "Middle Watut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpm", - "Description": [ - "Yosondúa Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpn", - "Description": [ - "Mindiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpo", - "Description": [ - "Miu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpp", - "Description": [ - "Migabac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpq", - "Description": [ - "Matís" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpr", - "Description": [ - "Vangunu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mps", - "Description": [ - "Dadibi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpt", - "Description": [ - "Mian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpu", - "Description": [ - "Makuráp" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpv", - "Description": [ - "Mungkip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpw", - "Description": [ - "Mapidian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpx", - "Description": [ - "Misima-Panaeati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpy", - "Description": [ - "Mapia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mpz", - "Description": [ - "Mpi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqa", - "Description": [ - "Maba (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqb", - "Description": [ - "Mbuko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqc", - "Description": [ - "Mangole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqe", - "Description": [ - "Matepi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqf", - "Description": [ - "Momuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqg", - "Description": [ - "Kota Bangun Kutai Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "mqh", - "Description": [ - "Tlazoyaltepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqi", - "Description": [ - "Mariri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqj", - "Description": [ - "Mamasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqk", - "Description": [ - "Rajah Kabunsuwan Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mql", - "Description": [ - "Mbelime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqm", - "Description": [ - "South Marquesan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqn", - "Description": [ - "Moronene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqo", - "Description": [ - "Modole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqp", - "Description": [ - "Manipa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqq", - "Description": [ - "Minokok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqr", - "Description": [ - "Mander" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqs", - "Description": [ - "West Makian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqt", - "Description": [ - "Mok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqu", - "Description": [ - "Mandari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqv", - "Description": [ - "Mosimo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqw", - "Description": [ - "Murupi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqx", - "Description": [ - "Mamuju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqy", - "Description": [ - "Manggarai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mqz", - "Description": [ - "Pano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mra", - "Description": [ - "Mlabri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrb", - "Description": [ - "Marino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrc", - "Description": [ - "Maricopa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrd", - "Description": [ - "Western Magar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mre", - "Description": [ - "Martha's Vineyard Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrf", - "Description": [ - "Elseng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrg", - "Description": [ - "Mising" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrh", - "Description": [ - "Mara Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrj", - "Description": [ - "Western Mari" - ], - "Added": "2009-07-29", - "Macrolanguage": "chm" - }, - { - "Type": "language", - "Subtag": "mrk", - "Description": [ - "Hmwaveke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrl", - "Description": [ - "Mortlockese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrm", - "Description": [ - "Merlav", - "Mwerlap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrn", - "Description": [ - "Cheke Holo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mro", - "Description": [ - "Mru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrp", - "Description": [ - "Morouas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrq", - "Description": [ - "North Marquesan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrr", - "Description": [ - "Maria (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrs", - "Description": [ - "Maragus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrt", - "Description": [ - "Marghi Central" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mru", - "Description": [ - "Mono (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrv", - "Description": [ - "Mangareva" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrw", - "Description": [ - "Maranao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrx", - "Description": [ - "Maremgi", - "Dineor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mry", - "Description": [ - "Mandaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mrz", - "Description": [ - "Marind" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msb", - "Description": [ - "Masbatenyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msc", - "Description": [ - "Sankaran Maninka" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "msd", - "Description": [ - "Yucatec Maya Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mse", - "Description": [ - "Musey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msf", - "Description": [ - "Mekwei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msg", - "Description": [ - "Moraid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msh", - "Description": [ - "Masikoro Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "msi", - "Description": [ - "Sabah Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "msj", - "Description": [ - "Ma (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msk", - "Description": [ - "Mansaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msl", - "Description": [ - "Molof", - "Poule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msm", - "Description": [ - "Agusan Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msn", - "Description": [ - "Vurës" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mso", - "Description": [ - "Mombum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msp", - "Description": [ - "Maritsauá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msq", - "Description": [ - "Caac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msr", - "Description": [ - "Mongolian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mss", - "Description": [ - "West Masela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mst", - "Description": [ - "Cataelano Mandaya" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "mry" - }, - { - "Type": "language", - "Subtag": "msu", - "Description": [ - "Musom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msv", - "Description": [ - "Maslam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msw", - "Description": [ - "Mansoanka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msx", - "Description": [ - "Moresada" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msy", - "Description": [ - "Aruamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "msz", - "Description": [ - "Momare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mta", - "Description": [ - "Cotabato Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtb", - "Description": [ - "Anyin Morofo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtc", - "Description": [ - "Munit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtd", - "Description": [ - "Mualang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mte", - "Description": [ - "Mono (Solomon Islands)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtf", - "Description": [ - "Murik (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtg", - "Description": [ - "Una" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mth", - "Description": [ - "Munggui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mti", - "Description": [ - "Maiwa (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtj", - "Description": [ - "Moskona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtk", - "Description": [ - "Mbe'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtl", - "Description": [ - "Montol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtm", - "Description": [ - "Mator" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtn", - "Description": [ - "Matagalpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mto", - "Description": [ - "Totontepec Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtp", - "Description": [ - "Wichí Lhamtés Nocten" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtq", - "Description": [ - "Muong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtr", - "Description": [ - "Mewari" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "mts", - "Description": [ - "Yora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtt", - "Description": [ - "Mota" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtu", - "Description": [ - "Tututepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtv", - "Description": [ - "Asaro'o" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtw", - "Description": [ - "Southern Binukidnon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mtx", - "Description": [ - "Tidaá Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mty", - "Description": [ - "Nabi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mua", - "Description": [ - "Mundang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mub", - "Description": [ - "Mubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muc", - "Description": [ - "Ajumbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mud", - "Description": [ - "Mednyj Aleut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mue", - "Description": [ - "Media Lengua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mug", - "Description": [ - "Musgu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muh", - "Description": [ - "Mündü" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mui", - "Description": [ - "Musi" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "muj", - "Description": [ - "Mabire" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muk", - "Description": [ - "Mugom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mul", - "Description": [ - "Multiple languages" - ], - "Added": "2005-10-16", - "Scope": "special" - }, - { - "Type": "language", - "Subtag": "mum", - "Description": [ - "Maiwala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mun", - "Description": [ - "Munda languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "muo", - "Description": [ - "Nyong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mup", - "Description": [ - "Malvi" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "muq", - "Description": [ - "Eastern Xiangxi Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "mur", - "Description": [ - "Murle" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mus", - "Description": [ - "Creek" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mut", - "Description": [ - "Western Muria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muu", - "Description": [ - "Yaaku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muv", - "Description": [ - "Muthuvan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mux", - "Description": [ - "Bo-Ung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muy", - "Description": [ - "Muyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "muz", - "Description": [ - "Mursi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mva", - "Description": [ - "Manam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvb", - "Description": [ - "Mattole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvd", - "Description": [ - "Mamboru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mve", - "Description": [ - "Marwari (Pakistan)" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "mvf", - "Description": [ - "Peripheral Mongolian" - ], - "Added": "2009-07-29", - "Macrolanguage": "mn" - }, - { - "Type": "language", - "Subtag": "mvg", - "Description": [ - "Yucuañe Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvh", - "Description": [ - "Mulgi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvi", - "Description": [ - "Miyako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvk", - "Description": [ - "Mekmek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvl", - "Description": [ - "Mbara (Australia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvm", - "Description": [ - "Muya" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see emq, wmg" - ] - }, - { - "Type": "language", - "Subtag": "mvn", - "Description": [ - "Minaveha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvo", - "Description": [ - "Marovo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvp", - "Description": [ - "Duri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvq", - "Description": [ - "Moere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvr", - "Description": [ - "Marau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvs", - "Description": [ - "Massep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvt", - "Description": [ - "Mpotovoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvu", - "Description": [ - "Marfa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvv", - "Description": [ - "Tagal Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvw", - "Description": [ - "Machinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvx", - "Description": [ - "Meoswar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvy", - "Description": [ - "Indus Kohistani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mvz", - "Description": [ - "Mesqan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwa", - "Description": [ - "Mwatebu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwb", - "Description": [ - "Juwal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwc", - "Description": [ - "Are" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwd", - "Description": [ - "Mudbura" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see dmw, xrq" - ] - }, - { - "Type": "language", - "Subtag": "mwe", - "Description": [ - "Mwera (Chimwera)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwf", - "Description": [ - "Murrinh-Patha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwg", - "Description": [ - "Aiklep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwh", - "Description": [ - "Mouk-Aria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwi", - "Description": [ - "Labo", - "Ninde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwj", - "Description": [ - "Maligo" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "vaj" - }, - { - "Type": "language", - "Subtag": "mwk", - "Description": [ - "Kita Maninkakan" - ], - "Added": "2009-07-29", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "mwl", - "Description": [ - "Mirandese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "mwm", - "Description": [ - "Sar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwn", - "Description": [ - "Nyamwanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwo", - "Description": [ - "Central Maewo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwp", - "Description": [ - "Kala Lagaw Ya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwq", - "Description": [ - "Mün Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwr", - "Description": [ - "Marwari" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "mws", - "Description": [ - "Mwimbi-Muthambi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwt", - "Description": [ - "Moken" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwu", - "Description": [ - "Mittu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mwv", - "Description": [ - "Mentawai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mww", - "Description": [ - "Hmong Daw" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "mwx", - "Description": [ - "Mediak" - ], - "Added": "2009-07-29", - "Deprecated": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "mwy", - "Description": [ - "Mosiro" - ], - "Added": "2009-07-29", - "Deprecated": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "mwz", - "Description": [ - "Moingi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxa", - "Description": [ - "Northwest Oaxaca Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxb", - "Description": [ - "Tezoatlán Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxc", - "Description": [ - "Manyika" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxd", - "Description": [ - "Modang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxe", - "Description": [ - "Mele-Fila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxf", - "Description": [ - "Malgbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxg", - "Description": [ - "Mbangala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxh", - "Description": [ - "Mvuba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxi", - "Description": [ - "Mozarabic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxj", - "Description": [ - "Miju-Mishmi", - "Geman Deng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxk", - "Description": [ - "Monumbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxl", - "Description": [ - "Maxi Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxm", - "Description": [ - "Meramera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxn", - "Description": [ - "Moi (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxo", - "Description": [ - "Mbowe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxp", - "Description": [ - "Tlahuitoltepec Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxq", - "Description": [ - "Juquila Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxr", - "Description": [ - "Murik (Malaysia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxs", - "Description": [ - "Huitepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxt", - "Description": [ - "Jamiltepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxu", - "Description": [ - "Mada (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxv", - "Description": [ - "Metlatónoc Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxw", - "Description": [ - "Namo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxx", - "Description": [ - "Mahou", - "Mawukakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxy", - "Description": [ - "Southeastern Nochixtlán Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mxz", - "Description": [ - "Central Masela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myb", - "Description": [ - "Mbay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myc", - "Description": [ - "Mayeka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myd", - "Description": [ - "Maramba" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Preferred-Value": "aog" - }, - { - "Type": "language", - "Subtag": "mye", - "Description": [ - "Myene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myf", - "Description": [ - "Bambassi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myg", - "Description": [ - "Manta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myh", - "Description": [ - "Makah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myi", - "Description": [ - "Mina (India)" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "myj", - "Description": [ - "Mangayat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myk", - "Description": [ - "Mamara Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myl", - "Description": [ - "Moma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mym", - "Description": [ - "Me'en" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myn", - "Description": [ - "Mayan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "myo", - "Description": [ - "Anfillo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myp", - "Description": [ - "Pirahã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myq", - "Description": [ - "Forest Maninka" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Macrolanguage": "man" - }, - { - "Type": "language", - "Subtag": "myr", - "Description": [ - "Muniche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mys", - "Description": [ - "Mesmes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myt", - "Description": [ - "Sangab Mandaya" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "mry" - }, - { - "Type": "language", - "Subtag": "myu", - "Description": [ - "Mundurukú" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myv", - "Description": [ - "Erzya" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "myw", - "Description": [ - "Muyuw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myx", - "Description": [ - "Masaaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myy", - "Description": [ - "Macuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "myz", - "Description": [ - "Classical Mandaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mza", - "Description": [ - "Santa María Zacatepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzb", - "Description": [ - "Tumzabt" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzc", - "Description": [ - "Madagascar Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzd", - "Description": [ - "Malimba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mze", - "Description": [ - "Morawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzg", - "Description": [ - "Monastic Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzh", - "Description": [ - "Wichí Lhamtés Güisnay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzi", - "Description": [ - "Ixcatlán Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzj", - "Description": [ - "Manya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzk", - "Description": [ - "Nigeria Mambila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzl", - "Description": [ - "Mazatlán Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzm", - "Description": [ - "Mumuye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzn", - "Description": [ - "Mazanderani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzo", - "Description": [ - "Matipuhy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzp", - "Description": [ - "Movima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzq", - "Description": [ - "Mori Atas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzr", - "Description": [ - "Marúbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzs", - "Description": [ - "Macanese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzt", - "Description": [ - "Mintil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzu", - "Description": [ - "Inapang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzv", - "Description": [ - "Manza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzw", - "Description": [ - "Deg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzx", - "Description": [ - "Mawayana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzy", - "Description": [ - "Mozambican Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "mzz", - "Description": [ - "Maiadomu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "naa", - "Description": [ - "Namla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nab", - "Description": [ - "Southern Nambikuára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nac", - "Description": [ - "Narak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nad", - "Description": [ - "Nijadali" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "xny" - }, - { - "Type": "language", - "Subtag": "nae", - "Description": [ - "Naka'ela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "naf", - "Description": [ - "Nabak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nag", - "Description": [ - "Naga Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nah", - "Description": [ - "Nahuatl languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "nai", - "Description": [ - "North American Indian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "naj", - "Description": [ - "Nalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nak", - "Description": [ - "Nakanai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nal", - "Description": [ - "Nalik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nam", - "Description": [ - "Ngan'gityemerri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nan", - "Description": [ - "Min Nan Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "nao", - "Description": [ - "Naaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nap", - "Description": [ - "Neapolitan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "naq", - "Description": [ - "Khoekhoe", - "Nama (Namibia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nar", - "Description": [ - "Iguta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nas", - "Description": [ - "Naasioi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nat", - "Description": [ - "Ca̱hungwa̱rya̱", - "Hungworo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "naw", - "Description": [ - "Nawuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nax", - "Description": [ - "Nakwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nay", - "Description": [ - "Ngarrindjeri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "naz", - "Description": [ - "Coatepec Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nba", - "Description": [ - "Nyemba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbb", - "Description": [ - "Ndoe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbc", - "Description": [ - "Chang Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbd", - "Description": [ - "Ngbinda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbe", - "Description": [ - "Konyak Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbf", - "Description": [ - "Naxi" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Comments": [ - "see nru, nxq" - ] - }, - { - "Type": "language", - "Subtag": "nbg", - "Description": [ - "Nagarchal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbh", - "Description": [ - "Ngamo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbi", - "Description": [ - "Mao Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbj", - "Description": [ - "Ngarinyman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbk", - "Description": [ - "Nake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbm", - "Description": [ - "Ngbaka Ma'bo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbn", - "Description": [ - "Kuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbo", - "Description": [ - "Nkukoli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbp", - "Description": [ - "Nnam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbq", - "Description": [ - "Nggem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbr", - "Description": [ - "Numana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbs", - "Description": [ - "Namibian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbt", - "Description": [ - "Na" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbu", - "Description": [ - "Rongmei Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbv", - "Description": [ - "Ngamambo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbw", - "Description": [ - "Southern Ngbandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nbx", - "Description": [ - "Ngura" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see ekc, gll, jbi, xpt, xwk" - ] - }, - { - "Type": "language", - "Subtag": "nby", - "Description": [ - "Ningera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nca", - "Description": [ - "Iyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncb", - "Description": [ - "Central Nicobarese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncc", - "Description": [ - "Ponam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncd", - "Description": [ - "Nachering" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nce", - "Description": [ - "Yale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncf", - "Description": [ - "Notsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncg", - "Description": [ - "Nisga'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nch", - "Description": [ - "Central Huasteca Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nci", - "Description": [ - "Classical Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncj", - "Description": [ - "Northern Puebla Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nck", - "Description": [ - "Na-kara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncl", - "Description": [ - "Michoacán Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncm", - "Description": [ - "Nambo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncn", - "Description": [ - "Nauna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nco", - "Description": [ - "Sibe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncp", - "Description": [ - "Ndaktup" - ], - "Added": "2009-07-29", - "Deprecated": "2018-03-08", - "Preferred-Value": "kdz" - }, - { - "Type": "language", - "Subtag": "ncq", - "Description": [ - "Northern Katang" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "ncr", - "Description": [ - "Ncane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncs", - "Description": [ - "Nicaraguan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nct", - "Description": [ - "Chothe Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncu", - "Description": [ - "Chumburung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncx", - "Description": [ - "Central Puebla Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ncz", - "Description": [ - "Natchez" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nda", - "Description": [ - "Ndasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndb", - "Description": [ - "Kenswei Nsei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndc", - "Description": [ - "Ndau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndd", - "Description": [ - "Nde-Nsele-Nta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndf", - "Description": [ - "Nadruvian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndg", - "Description": [ - "Ndengereko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndh", - "Description": [ - "Ndali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndi", - "Description": [ - "Samba Leko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndj", - "Description": [ - "Ndamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndk", - "Description": [ - "Ndaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndl", - "Description": [ - "Ndolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndm", - "Description": [ - "Ndam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndn", - "Description": [ - "Ngundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndp", - "Description": [ - "Ndo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndq", - "Description": [ - "Ndombe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndr", - "Description": [ - "Ndoola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nds", - "Description": [ - "Low German", - "Low Saxon" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ndt", - "Description": [ - "Ndunga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndu", - "Description": [ - "Dugun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndv", - "Description": [ - "Ndut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndw", - "Description": [ - "Ndobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndx", - "Description": [ - "Nduga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndy", - "Description": [ - "Lutos" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ndz", - "Description": [ - "Ndogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nea", - "Description": [ - "Eastern Ngad'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neb", - "Description": [ - "Toura (Côte d'Ivoire)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nec", - "Description": [ - "Nedebang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ned", - "Description": [ - "Nde-Gbite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nee", - "Description": [ - "Nêlêmwa-Nixumwak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nef", - "Description": [ - "Nefamese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neg", - "Description": [ - "Negidal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neh", - "Description": [ - "Nyenkha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nei", - "Description": [ - "Neo-Hittite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nej", - "Description": [ - "Neko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nek", - "Description": [ - "Neku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nem", - "Description": [ - "Nemi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nen", - "Description": [ - "Nengone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neo", - "Description": [ - "Ná-Meo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neq", - "Description": [ - "North Central Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ner", - "Description": [ - "Yahadian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nes", - "Description": [ - "Bhoti Kinnauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "net", - "Description": [ - "Nete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "neu", - "Description": [ - "Neo" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nev", - "Description": [ - "Nyaheun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "new", - "Description": [ - "Newari", - "Nepal Bhasa" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nex", - "Description": [ - "Neme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ney", - "Description": [ - "Neyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nez", - "Description": [ - "Nez Perce" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nfa", - "Description": [ - "Dhao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nfd", - "Description": [ - "Ahwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nfl", - "Description": [ - "Ayiwo", - "Äiwoo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nfr", - "Description": [ - "Nafaanra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nfu", - "Description": [ - "Mfumte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nga", - "Description": [ - "Ngbaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngb", - "Description": [ - "Northern Ngbandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngc", - "Description": [ - "Ngombe (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngd", - "Description": [ - "Ngando (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nge", - "Description": [ - "Ngemba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngf", - "Description": [ - "Trans-New Guinea languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ngg", - "Description": [ - "Ngbaka Manza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngh", - "Description": [ - "NÇng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngi", - "Description": [ - "Ngizim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngj", - "Description": [ - "Ngie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngk", - "Description": [ - "Dalabon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngl", - "Description": [ - "Lomwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngm", - "Description": [ - "Ngatik Men's Creole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngn", - "Description": [ - "Ngwo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngo", - "Description": [ - "Ngoni" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see xnj, xnq" - ] - }, - { - "Type": "language", - "Subtag": "ngp", - "Description": [ - "Ngulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngq", - "Description": [ - "Ngurimi", - "Ngoreme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngr", - "Description": [ - "Engdewu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngs", - "Description": [ - "Gvoko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngt", - "Description": [ - "Kriang", - "Ngeq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngu", - "Description": [ - "Guerrero Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngv", - "Description": [ - "Nagumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngw", - "Description": [ - "Ngwaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngx", - "Description": [ - "Nggwahyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngy", - "Description": [ - "Tibea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ngz", - "Description": [ - "Ngungwel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nha", - "Description": [ - "Nhanda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhb", - "Description": [ - "Beng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhc", - "Description": [ - "Tabasco Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhd", - "Description": [ - "Chiripá", - "Ava Guaraní" - ], - "Added": "2009-07-29", - "Macrolanguage": "gn" - }, - { - "Type": "language", - "Subtag": "nhe", - "Description": [ - "Eastern Huasteca Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhf", - "Description": [ - "Nhuwala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhg", - "Description": [ - "Tetelcingo Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhh", - "Description": [ - "Nahari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhi", - "Description": [ - "Zacatlán-Ahuacatlán-Tepetzintla Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhk", - "Description": [ - "Isthmus-Cosoleacaque Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhm", - "Description": [ - "Morelos Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhn", - "Description": [ - "Central Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nho", - "Description": [ - "Takuu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhp", - "Description": [ - "Isthmus-Pajapan Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhq", - "Description": [ - "Huaxcaleca Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhr", - "Description": [ - "Naro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nht", - "Description": [ - "Ometepec Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhu", - "Description": [ - "Noone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhv", - "Description": [ - "Temascaltepec Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhw", - "Description": [ - "Western Huasteca Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhx", - "Description": [ - "Isthmus-Mecayapan Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhy", - "Description": [ - "Northern Oaxaca Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nhz", - "Description": [ - "Santa María La Alta Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nia", - "Description": [ - "Nias" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nib", - "Description": [ - "Nakame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nic", - "Description": [ - "Niger-Kordofanian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "nid", - "Description": [ - "Ngandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nie", - "Description": [ - "Niellim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nif", - "Description": [ - "Nek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nig", - "Description": [ - "Ngalakgan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nih", - "Description": [ - "Nyiha (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nii", - "Description": [ - "Nii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nij", - "Description": [ - "Ngaju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nik", - "Description": [ - "Southern Nicobarese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nil", - "Description": [ - "Nila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nim", - "Description": [ - "Nilamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nin", - "Description": [ - "Ninzo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nio", - "Description": [ - "Nganasan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "niq", - "Description": [ - "Nandi" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "nir", - "Description": [ - "Nimboran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nis", - "Description": [ - "Nimi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nit", - "Description": [ - "Southeastern Kolami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "niu", - "Description": [ - "Niuean" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "niv", - "Description": [ - "Gilyak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "niw", - "Description": [ - "Nimo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nix", - "Description": [ - "Hema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "niy", - "Description": [ - "Ngiti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "niz", - "Description": [ - "Ningil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nja", - "Description": [ - "Nzanyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njb", - "Description": [ - "Nocte Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njd", - "Description": [ - "Ndonde Hamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njh", - "Description": [ - "Lotha Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nji", - "Description": [ - "Gudanji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njj", - "Description": [ - "Njen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njl", - "Description": [ - "Njalgulgule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njm", - "Description": [ - "Angami Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njn", - "Description": [ - "Liangmai Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njo", - "Description": [ - "Ao Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njr", - "Description": [ - "Njerep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njs", - "Description": [ - "Nisa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njt", - "Description": [ - "Ndyuka-Trio Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nju", - "Description": [ - "Ngadjunmaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njx", - "Description": [ - "Kunyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njy", - "Description": [ - "Njyem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "njz", - "Description": [ - "Nyishi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nka", - "Description": [ - "Nkoya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkb", - "Description": [ - "Khoibu Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkc", - "Description": [ - "Nkongho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkd", - "Description": [ - "Koireng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nke", - "Description": [ - "Duke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkf", - "Description": [ - "Inpui Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkg", - "Description": [ - "Nekgini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkh", - "Description": [ - "Khezha Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nki", - "Description": [ - "Thangal Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkj", - "Description": [ - "Nakai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkk", - "Description": [ - "Nokuku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkm", - "Description": [ - "Namat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkn", - "Description": [ - "Nkangala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nko", - "Description": [ - "Nkonya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkp", - "Description": [ - "Niuatoputapu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkq", - "Description": [ - "Nkami" - ], - "Added": "2010-04-16" - }, - { - "Type": "language", - "Subtag": "nkr", - "Description": [ - "Nukuoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nks", - "Description": [ - "North Asmat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkt", - "Description": [ - "Nyika (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nku", - "Description": [ - "Bouna Kulango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkv", - "Description": [ - "Nyika (Malawi and Zambia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkw", - "Description": [ - "Nkutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkx", - "Description": [ - "Nkoroo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nkz", - "Description": [ - "Nkari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nla", - "Description": [ - "Ngombale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlc", - "Description": [ - "Nalca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nle", - "Description": [ - "East Nyala" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "nlg", - "Description": [ - "Gela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nli", - "Description": [ - "Grangali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlj", - "Description": [ - "Nyali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlk", - "Description": [ - "Ninia Yali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nll", - "Description": [ - "Nihali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlm", - "Description": [ - "Mankiyali" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "nln", - "Description": [ - "Durango Nahuatl" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see azd, azn" - ] - }, - { - "Type": "language", - "Subtag": "nlo", - "Description": [ - "Ngul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlq", - "Description": [ - "Lao Naga" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nlr", - "Description": [ - "Ngarla" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see nrk, ywg" - ] - }, - { - "Type": "language", - "Subtag": "nlu", - "Description": [ - "Nchumbulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlv", - "Description": [ - "Orizaba Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlw", - "Description": [ - "Walangama" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nlx", - "Description": [ - "Nahali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nly", - "Description": [ - "Nyamal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nlz", - "Description": [ - "Nalögo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nma", - "Description": [ - "Maram Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmb", - "Description": [ - "Big Nambas", - "V'ënen Taut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmc", - "Description": [ - "Ngam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmd", - "Description": [ - "Ndumu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nme", - "Description": [ - "Mzieme Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmf", - "Description": [ - "Tangkhul Naga (India)" - ], - "Added": "2009-07-29", - "Comments": [ - "see ntx" - ] - }, - { - "Type": "language", - "Subtag": "nmg", - "Description": [ - "Kwasio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmh", - "Description": [ - "Monsang Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmi", - "Description": [ - "Nyam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmj", - "Description": [ - "Ngombe (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmk", - "Description": [ - "Namakura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nml", - "Description": [ - "Ndemli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmm", - "Description": [ - "Manangba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmn", - "Description": [ - "ǃXóõ" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmo", - "Description": [ - "Moyon Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmp", - "Description": [ - "Nimanbur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmq", - "Description": [ - "Nambya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmr", - "Description": [ - "Nimbari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nms", - "Description": [ - "Letemboi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmt", - "Description": [ - "Namonuito" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmu", - "Description": [ - "Northeast Maidu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmv", - "Description": [ - "Ngamini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmw", - "Description": [ - "Nimoa", - "Rifao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmx", - "Description": [ - "Nama (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmy", - "Description": [ - "Namuyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nmz", - "Description": [ - "Nawdm" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nna", - "Description": [ - "Nyangumarta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnb", - "Description": [ - "Nande" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnc", - "Description": [ - "Nancere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnd", - "Description": [ - "West Ambae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nne", - "Description": [ - "Ngandyera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnf", - "Description": [ - "Ngaing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nng", - "Description": [ - "Maring Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnh", - "Description": [ - "Ngiemboon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nni", - "Description": [ - "North Nuaulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnj", - "Description": [ - "Nyangatom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnk", - "Description": [ - "Nankina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnl", - "Description": [ - "Northern Rengma Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnm", - "Description": [ - "Namia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnn", - "Description": [ - "Ngete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnp", - "Description": [ - "Wancho Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnq", - "Description": [ - "Ngindo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnr", - "Description": [ - "Narungga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nns", - "Description": [ - "Ningye" - ], - "Added": "2009-07-29", - "Deprecated": "2019-04-16", - "Preferred-Value": "nbr" - }, - { - "Type": "language", - "Subtag": "nnt", - "Description": [ - "Nanticoke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnu", - "Description": [ - "Dwang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnv", - "Description": [ - "Nugunu (Australia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnw", - "Description": [ - "Southern Nuni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnx", - "Description": [ - "Ngong" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "ngv" - }, - { - "Type": "language", - "Subtag": "nny", - "Description": [ - "Nyangga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nnz", - "Description": [ - "Nda'nda'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noa", - "Description": [ - "Woun Meu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noc", - "Description": [ - "Nuk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nod", - "Description": [ - "Northern Thai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noe", - "Description": [ - "Nimadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nof", - "Description": [ - "Nomane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nog", - "Description": [ - "Nogai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "noh", - "Description": [ - "Nomu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noi", - "Description": [ - "Noiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noj", - "Description": [ - "Nonuya" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "nok", - "Description": [ - "Nooksack" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nol", - "Description": [ - "Nomlaki" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nom", - "Description": [ - "Nocamán" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "non", - "Description": [ - "Old Norse" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "noo", - "Description": [ - "Nootka" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Comments": [ - "see dtd, nuk" - ] - }, - { - "Type": "language", - "Subtag": "nop", - "Description": [ - "Numanggang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noq", - "Description": [ - "Ngongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nos", - "Description": [ - "Eastern Nisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "not", - "Description": [ - "Nomatsiguenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nou", - "Description": [ - "Ewage-Notu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nov", - "Description": [ - "Novial" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "now", - "Description": [ - "Nyambo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noy", - "Description": [ - "Noy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "noz", - "Description": [ - "Nayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npa", - "Description": [ - "Nar Phu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npb", - "Description": [ - "Nupbikha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npg", - "Description": [ - "Ponyo-Gongwang Naga" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nph", - "Description": [ - "Phom Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npi", - "Description": [ - "Nepali (individual language)" - ], - "Added": "2012-08-12", - "Macrolanguage": "ne" - }, - { - "Type": "language", - "Subtag": "npl", - "Description": [ - "Southeastern Puebla Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npn", - "Description": [ - "Mondropolon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npo", - "Description": [ - "Pochuri Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nps", - "Description": [ - "Nipsan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npu", - "Description": [ - "Puimei Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "npx", - "Description": [ - "Noipx" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "npy", - "Description": [ - "Napu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nqg", - "Description": [ - "Southern Nago" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nqk", - "Description": [ - "Kura Ede Nago" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nql", - "Description": [ - "Ngendelengo" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "nqm", - "Description": [ - "Ndom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nqn", - "Description": [ - "Nen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nqo", - "Description": [ - "N'Ko", - "N’Ko" - ], - "Added": "2006-06-05", - "Suppress-Script": "Nkoo" - }, - { - "Type": "language", - "Subtag": "nqq", - "Description": [ - "Kyan-Karyaw Naga" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nqt", - "Description": [ - "Nteng" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "nqy", - "Description": [ - "Akyaung Ari Naga" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nra", - "Description": [ - "Ngom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrb", - "Description": [ - "Nara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrc", - "Description": [ - "Noric" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nre", - "Description": [ - "Southern Rengma Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrf", - "Description": [ - "Jèrriais", - "Guernésiais" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "nrg", - "Description": [ - "Narango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nri", - "Description": [ - "Chokri Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrk", - "Description": [ - "Ngarla" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nrl", - "Description": [ - "Ngarluma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrm", - "Description": [ - "Narom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrn", - "Description": [ - "Norn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrp", - "Description": [ - "North Picene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrr", - "Description": [ - "Norra", - "Nora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrt", - "Description": [ - "Northern Kalapuya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nru", - "Description": [ - "Narua" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "nrx", - "Description": [ - "Ngurmbur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nrz", - "Description": [ - "Lala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsa", - "Description": [ - "Sangtam Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsb", - "Description": [ - "Lower Nossob" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "nsc", - "Description": [ - "Nshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsd", - "Description": [ - "Southern Nisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nse", - "Description": [ - "Nsenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsf", - "Description": [ - "Northwestern Nisu" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nsg", - "Description": [ - "Ngasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsh", - "Description": [ - "Ngoshie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsi", - "Description": [ - "Nigerian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsk", - "Description": [ - "Naskapi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsl", - "Description": [ - "Norwegian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsm", - "Description": [ - "Sumi Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsn", - "Description": [ - "Nehan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nso", - "Description": [ - "Pedi", - "Northern Sotho", - "Sepedi" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "nsp", - "Description": [ - "Nepalese Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsq", - "Description": [ - "Northern Sierra Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsr", - "Description": [ - "Maritime Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nss", - "Description": [ - "Nali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nst", - "Description": [ - "Tase Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsu", - "Description": [ - "Sierra Negra Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsv", - "Description": [ - "Southwestern Nisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsw", - "Description": [ - "Navut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsx", - "Description": [ - "Nsongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsy", - "Description": [ - "Nasal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nsz", - "Description": [ - "Nisenan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntd", - "Description": [ - "Northern Tidung" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "nte", - "Description": [ - "Nathembo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntg", - "Description": [ - "Ngantangarra" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "nti", - "Description": [ - "Natioro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntj", - "Description": [ - "Ngaanyatjarra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntk", - "Description": [ - "Ikoma-Nata-Isenye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntm", - "Description": [ - "Nateni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nto", - "Description": [ - "Ntomba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntp", - "Description": [ - "Northern Tepehuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntr", - "Description": [ - "Delo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nts", - "Description": [ - "Natagaimas" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "pij" - }, - { - "Type": "language", - "Subtag": "ntu", - "Description": [ - "Natügu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntw", - "Description": [ - "Nottoway" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntx", - "Description": [ - "Tangkhul Naga (Myanmar)" - ], - "Added": "2012-08-12", - "Comments": [ - "see nmf" - ] - }, - { - "Type": "language", - "Subtag": "nty", - "Description": [ - "Mantsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ntz", - "Description": [ - "Natanzi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nua", - "Description": [ - "Yuanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nub", - "Description": [ - "Nubian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "nuc", - "Description": [ - "Nukuini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nud", - "Description": [ - "Ngala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nue", - "Description": [ - "Ngundu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuf", - "Description": [ - "Nusu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nug", - "Description": [ - "Nungali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuh", - "Description": [ - "Ndunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nui", - "Description": [ - "Ngumbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuj", - "Description": [ - "Nyole" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuk", - "Description": [ - "Nuu-chah-nulth", - "Nuuchahnulth" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "nul", - "Description": [ - "Nusa Laut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "num", - "Description": [ - "Niuafo'ou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nun", - "Description": [ - "Anong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuo", - "Description": [ - "Nguôn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nup", - "Description": [ - "Nupe-Nupe-Tako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuq", - "Description": [ - "Nukumanu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nur", - "Description": [ - "Nukuria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nus", - "Description": [ - "Nuer" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nut", - "Description": [ - "Nung (Viet Nam)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuu", - "Description": [ - "Ngbundu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuv", - "Description": [ - "Northern Nuni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuw", - "Description": [ - "Nguluwan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nux", - "Description": [ - "Mehek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuy", - "Description": [ - "Nunggubuyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nuz", - "Description": [ - "Tlamacazapa Nahuatl" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nvh", - "Description": [ - "Nasarian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nvm", - "Description": [ - "Namiae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nvo", - "Description": [ - "Nyokon" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nwa", - "Description": [ - "Nawathinehena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwb", - "Description": [ - "Nyabwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwc", - "Description": [ - "Classical Newari", - "Classical Nepal Bhasa", - "Old Newari" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nwe", - "Description": [ - "Ngwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwg", - "Description": [ - "Ngayawung" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nwi", - "Description": [ - "Southwest Tanna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwm", - "Description": [ - "Nyamusa-Molo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwo", - "Description": [ - "Nauo" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nwr", - "Description": [ - "Nawaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nww", - "Description": [ - "Ndwewe" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "nwx", - "Description": [ - "Middle Newar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nwy", - "Description": [ - "Nottoway-Meherrin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxa", - "Description": [ - "Nauete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxd", - "Description": [ - "Ngando (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxe", - "Description": [ - "Nage" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxg", - "Description": [ - "Ngad'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxi", - "Description": [ - "Nindi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxk", - "Description": [ - "Koki Naga" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "nxl", - "Description": [ - "South Nuaulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxm", - "Description": [ - "Numidian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxn", - "Description": [ - "Ngawun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxo", - "Description": [ - "Ndambomo" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "nxq", - "Description": [ - "Naxi" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "nxr", - "Description": [ - "Ninggerum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nxu", - "Description": [ - "Narau" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "bpp" - }, - { - "Type": "language", - "Subtag": "nxx", - "Description": [ - "Nafri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyb", - "Description": [ - "Nyangbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyc", - "Description": [ - "Nyanga-li" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyd", - "Description": [ - "Nyore", - "Olunyole" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "nye", - "Description": [ - "Nyengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyf", - "Description": [ - "Giryama", - "Kigiryama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyg", - "Description": [ - "Nyindu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyh", - "Description": [ - "Nyikina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyi", - "Description": [ - "Ama (Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyj", - "Description": [ - "Nyanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyk", - "Description": [ - "Nyaneka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyl", - "Description": [ - "Nyeu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nym", - "Description": [ - "Nyamwezi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nyn", - "Description": [ - "Nyankole" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nyo", - "Description": [ - "Nyoro" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nyp", - "Description": [ - "Nyang'i" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyq", - "Description": [ - "Nayini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyr", - "Description": [ - "Nyiha (Malawi)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nys", - "Description": [ - "Nyungar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyt", - "Description": [ - "Nyawaygi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyu", - "Description": [ - "Nyungwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyv", - "Description": [ - "Nyulnyul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyw", - "Description": [ - "Nyaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyx", - "Description": [ - "Nganyaywana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nyy", - "Description": [ - "Nyakyusa-Ngonde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nza", - "Description": [ - "Tigon Mbembe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzb", - "Description": [ - "Njebi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzd", - "Description": [ - "Nzadi" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "nzi", - "Description": [ - "Nzima" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "nzk", - "Description": [ - "Nzakara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzm", - "Description": [ - "Zeme Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzs", - "Description": [ - "New Zealand Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzu", - "Description": [ - "Teke-Nzikou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzy", - "Description": [ - "Nzakambay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "nzz", - "Description": [ - "Nanga Dama Dogon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "oaa", - "Description": [ - "Orok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oac", - "Description": [ - "Oroch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oar", - "Description": [ - "Old Aramaic (up to 700 BCE)", - "Ancient Aramaic (up to 700 BCE)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oav", - "Description": [ - "Old Avar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obi", - "Description": [ - "Obispeño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obk", - "Description": [ - "Southern Bontok" - ], - "Added": "2010-03-11", - "Macrolanguage": "bnc" - }, - { - "Type": "language", - "Subtag": "obl", - "Description": [ - "Oblo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obm", - "Description": [ - "Moabite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obo", - "Description": [ - "Obo Manobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obr", - "Description": [ - "Old Burmese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obt", - "Description": [ - "Old Breton" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "obu", - "Description": [ - "Obulom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oca", - "Description": [ - "Ocaina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "och", - "Description": [ - "Old Chinese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ocm", - "Description": [ - "Old Cham" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "oco", - "Description": [ - "Old Cornish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ocu", - "Description": [ - "Atzingo Matlatzinca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oda", - "Description": [ - "Odut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "odk", - "Description": [ - "Od" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "odt", - "Description": [ - "Old Dutch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "odu", - "Description": [ - "Odual" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ofo", - "Description": [ - "Ofo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ofs", - "Description": [ - "Old Frisian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ofu", - "Description": [ - "Efutop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ogb", - "Description": [ - "Ogbia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ogc", - "Description": [ - "Ogbah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oge", - "Description": [ - "Old Georgian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ogg", - "Description": [ - "Ogbogolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ogo", - "Description": [ - "Khana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ogu", - "Description": [ - "Ogbronuagum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oht", - "Description": [ - "Old Hittite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ohu", - "Description": [ - "Old Hungarian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oia", - "Description": [ - "Oirata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oie", - "Description": [ - "Okolie" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "oin", - "Description": [ - "Inebu One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ojb", - "Description": [ - "Northwestern Ojibwa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "ojc", - "Description": [ - "Central Ojibwa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "ojg", - "Description": [ - "Eastern Ojibwa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "ojp", - "Description": [ - "Old Japanese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ojs", - "Description": [ - "Severn Ojibwa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "ojv", - "Description": [ - "Ontong Java" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ojw", - "Description": [ - "Western Ojibwa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "oka", - "Description": [ - "Okanagan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okb", - "Description": [ - "Okobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okc", - "Description": [ - "Kobo" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "okd", - "Description": [ - "Okodia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oke", - "Description": [ - "Okpe (Southwestern Edo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okg", - "Description": [ - "Koko Babangk" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "okh", - "Description": [ - "Koresh-e Rostam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oki", - "Description": [ - "Okiek" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "okj", - "Description": [ - "Oko-Juwoi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okk", - "Description": [ - "Kwamtim One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okl", - "Description": [ - "Old Kentish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okm", - "Description": [ - "Middle Korean (10th-16th cent.)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okn", - "Description": [ - "Oki-No-Erabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oko", - "Description": [ - "Old Korean (3rd-9th cent.)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okr", - "Description": [ - "Kirike" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oks", - "Description": [ - "Oko-Eni-Osayen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oku", - "Description": [ - "Oku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okv", - "Description": [ - "Orokaiva" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okx", - "Description": [ - "Okpe (Northwestern Edo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "okz", - "Description": [ - "Old Khmer" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ola", - "Description": [ - "Walungge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "old", - "Description": [ - "Mochi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ole", - "Description": [ - "Olekha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "olk", - "Description": [ - "Olkol" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "olm", - "Description": [ - "Oloma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "olo", - "Description": [ - "Livvi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "olr", - "Description": [ - "Olrat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "olt", - "Description": [ - "Old Lithuanian" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "olu", - "Description": [ - "Kuvale" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "oma", - "Description": [ - "Omaha-Ponca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omb", - "Description": [ - "East Ambae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omc", - "Description": [ - "Mochica" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ome", - "Description": [ - "Omejes" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "omg", - "Description": [ - "Omagua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omi", - "Description": [ - "Omi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omk", - "Description": [ - "Omok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oml", - "Description": [ - "Ombo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omn", - "Description": [ - "Minoan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omo", - "Description": [ - "Utarmbung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omp", - "Description": [ - "Old Manipuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omq", - "Description": [ - "Oto-Manguean languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "omr", - "Description": [ - "Old Marathi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omt", - "Description": [ - "Omotik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omu", - "Description": [ - "Omurano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omv", - "Description": [ - "Omotic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "omw", - "Description": [ - "South Tairora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omx", - "Description": [ - "Old Mon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "omy", - "Description": [ - "Old Malay" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ona", - "Description": [ - "Ona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onb", - "Description": [ - "Lingao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "one", - "Description": [ - "Oneida" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ong", - "Description": [ - "Olo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oni", - "Description": [ - "Onin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onj", - "Description": [ - "Onjob" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onk", - "Description": [ - "Kabore One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onn", - "Description": [ - "Onobasulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ono", - "Description": [ - "Onondaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onp", - "Description": [ - "Sartang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onr", - "Description": [ - "Northern One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ons", - "Description": [ - "Ono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ont", - "Description": [ - "Ontenu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onu", - "Description": [ - "Unua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onw", - "Description": [ - "Old Nubian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "onx", - "Description": [ - "Onin Based Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ood", - "Description": [ - "Tohono O'odham" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oog", - "Description": [ - "Ong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oon", - "Description": [ - "Önge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oor", - "Description": [ - "Oorlams" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oos", - "Description": [ - "Old Ossetic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opa", - "Description": [ - "Okpamheri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opk", - "Description": [ - "Kopkaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opm", - "Description": [ - "Oksapmin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opo", - "Description": [ - "Opao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opt", - "Description": [ - "Opata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "opy", - "Description": [ - "Ofayé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ora", - "Description": [ - "Oroha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orc", - "Description": [ - "Orma" - ], - "Added": "2009-07-29", - "Macrolanguage": "om" - }, - { - "Type": "language", - "Subtag": "ore", - "Description": [ - "Orejón" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "org", - "Description": [ - "Oring" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orh", - "Description": [ - "Oroqen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orn", - "Description": [ - "Orang Kanaq" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "oro", - "Description": [ - "Orokolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orr", - "Description": [ - "Oruma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ors", - "Description": [ - "Orang Seletar" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "ort", - "Description": [ - "Adivasi Oriya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oru", - "Description": [ - "Ormuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orv", - "Description": [ - "Old Russian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orw", - "Description": [ - "Oro Win" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "orx", - "Description": [ - "Oro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ory", - "Description": [ - "Odia (individual language)", - "Oriya (individual language)" - ], - "Added": "2012-08-12", - "Macrolanguage": "or" - }, - { - "Type": "language", - "Subtag": "orz", - "Description": [ - "Ormu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osa", - "Description": [ - "Osage" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "osc", - "Description": [ - "Oscan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osi", - "Description": [ - "Osing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osn", - "Description": [ - "Old Sundanese" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "oso", - "Description": [ - "Ososo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osp", - "Description": [ - "Old Spanish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ost", - "Description": [ - "Osatu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osu", - "Description": [ - "Southern One" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "osx", - "Description": [ - "Old Saxon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ota", - "Description": [ - "Ottoman Turkish (1500-1928)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "otb", - "Description": [ - "Old Tibetan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otd", - "Description": [ - "Ot Danum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ote", - "Description": [ - "Mezquital Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oti", - "Description": [ - "Oti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otk", - "Description": [ - "Old Turkish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otl", - "Description": [ - "Tilapa Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otm", - "Description": [ - "Eastern Highland Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otn", - "Description": [ - "Tenango Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oto", - "Description": [ - "Otomian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "otq", - "Description": [ - "Querétaro Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otr", - "Description": [ - "Otoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ots", - "Description": [ - "Estado de México Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ott", - "Description": [ - "Temoaya Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otu", - "Description": [ - "Otuke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otw", - "Description": [ - "Ottawa" - ], - "Added": "2009-07-29", - "Macrolanguage": "oj" - }, - { - "Type": "language", - "Subtag": "otx", - "Description": [ - "Texcatepec Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oty", - "Description": [ - "Old Tamil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "otz", - "Description": [ - "Ixtenco Otomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oua", - "Description": [ - "Tagargrent" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oub", - "Description": [ - "Glio-Oubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oue", - "Description": [ - "Oune" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oui", - "Description": [ - "Old Uighur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oum", - "Description": [ - "Ouma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oun", - "Description": [ - "ǃOǃung" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "vaj" - }, - { - "Type": "language", - "Subtag": "ovd", - "Description": [ - "Elfdalian", - "Övdalian" - ], - "Added": "2016-06-16" - }, - { - "Type": "language", - "Subtag": "owi", - "Description": [ - "Owiniga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "owl", - "Description": [ - "Old Welsh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oyb", - "Description": [ - "Oy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oyd", - "Description": [ - "Oyda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oym", - "Description": [ - "Wayampi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "oyy", - "Description": [ - "Oya'oya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ozm", - "Description": [ - "Koonzime" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "paa", - "Description": [ - "Papuan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "pab", - "Description": [ - "Parecís" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pac", - "Description": [ - "Pacoh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pad", - "Description": [ - "Paumarí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pae", - "Description": [ - "Pagibete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "paf", - "Description": [ - "Paranawát" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pag", - "Description": [ - "Pangasinan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pah", - "Description": [ - "Tenharim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pai", - "Description": [ - "Pe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pak", - "Description": [ - "Parakanã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pal", - "Description": [ - "Pahlavi" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pam", - "Description": [ - "Pampanga", - "Kapampangan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pao", - "Description": [ - "Northern Paiute" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pap", - "Description": [ - "Papiamento" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "paq", - "Description": [ - "Parya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "par", - "Description": [ - "Panamint", - "Timbisha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pas", - "Description": [ - "Papasena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pat", - "Description": [ - "Papitalai" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Preferred-Value": "kxr" - }, - { - "Type": "language", - "Subtag": "pau", - "Description": [ - "Palauan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pav", - "Description": [ - "Pakaásnovos" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "paw", - "Description": [ - "Pawnee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pax", - "Description": [ - "Pankararé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pay", - "Description": [ - "Pech" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "paz", - "Description": [ - "Pankararú" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbb", - "Description": [ - "Páez" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbc", - "Description": [ - "Patamona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbe", - "Description": [ - "Mezontla Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbf", - "Description": [ - "Coyotepec Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbg", - "Description": [ - "Paraujano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbh", - "Description": [ - "E'ñapa Woromaipu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbi", - "Description": [ - "Parkwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbl", - "Description": [ - "Mak (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbm", - "Description": [ - "Puebla Mazatec" - ], - "Added": "2018-03-08", - "Comments": [ - "see also maa" - ] - }, - { - "Type": "language", - "Subtag": "pbn", - "Description": [ - "Kpasam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbo", - "Description": [ - "Papel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbp", - "Description": [ - "Badyara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbr", - "Description": [ - "Pangwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbs", - "Description": [ - "Central Pame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbt", - "Description": [ - "Southern Pashto" - ], - "Added": "2009-07-29", - "Macrolanguage": "ps" - }, - { - "Type": "language", - "Subtag": "pbu", - "Description": [ - "Northern Pashto" - ], - "Added": "2009-07-29", - "Macrolanguage": "ps" - }, - { - "Type": "language", - "Subtag": "pbv", - "Description": [ - "Pnar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pby", - "Description": [ - "Pyu (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pbz", - "Description": [ - "Palu" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "pca", - "Description": [ - "Santa Inés Ahuatempan Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcb", - "Description": [ - "Pear" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcc", - "Description": [ - "Bouyei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcd", - "Description": [ - "Picard" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pce", - "Description": [ - "Ruching Palaung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcf", - "Description": [ - "Paliyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcg", - "Description": [ - "Paniya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pch", - "Description": [ - "Pardhan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pci", - "Description": [ - "Duruwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcj", - "Description": [ - "Parenga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pck", - "Description": [ - "Paite Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcl", - "Description": [ - "Pardhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcm", - "Description": [ - "Nigerian Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcn", - "Description": [ - "Piti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcp", - "Description": [ - "Pacahuara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pcr", - "Description": [ - "Panang" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "adx" - }, - { - "Type": "language", - "Subtag": "pcw", - "Description": [ - "Pyapun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pda", - "Description": [ - "Anam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdc", - "Description": [ - "Pennsylvania German" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdi", - "Description": [ - "Pa Di" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdn", - "Description": [ - "Podena", - "Fedan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdo", - "Description": [ - "Padoe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdt", - "Description": [ - "Plautdietsch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pdu", - "Description": [ - "Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pea", - "Description": [ - "Peranakan Indonesian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "peb", - "Description": [ - "Eastern Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ped", - "Description": [ - "Mala (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pee", - "Description": [ - "Taje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pef", - "Description": [ - "Northeastern Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "peg", - "Description": [ - "Pengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "peh", - "Description": [ - "Bonan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pei", - "Description": [ - "Chichimeca-Jonaz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pej", - "Description": [ - "Northern Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pek", - "Description": [ - "Penchal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pel", - "Description": [ - "Pekal" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "pem", - "Description": [ - "Phende" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "peo", - "Description": [ - "Old Persian (ca. 600-400 B.C.)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pep", - "Description": [ - "Kunja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "peq", - "Description": [ - "Southern Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pes", - "Description": [ - "Iranian Persian" - ], - "Added": "2009-07-29", - "Macrolanguage": "fa" - }, - { - "Type": "language", - "Subtag": "pev", - "Description": [ - "Pémono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pex", - "Description": [ - "Petats" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pey", - "Description": [ - "Petjo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pez", - "Description": [ - "Eastern Penan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pfa", - "Description": [ - "Pááfang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pfe", - "Description": [ - "Pere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pfl", - "Description": [ - "Pfaelzisch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pga", - "Description": [ - "Sudanese Creole Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "pgd", - "Description": [ - "GÄndhÄrÄ«" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "pgg", - "Description": [ - "Pangwali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgi", - "Description": [ - "Pagi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgk", - "Description": [ - "Rerep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgl", - "Description": [ - "Primitive Irish" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "pgn", - "Description": [ - "Paelignian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgs", - "Description": [ - "Pangseng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgu", - "Description": [ - "Pagu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pgy", - "Description": [ - "Pongyong" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "pgz", - "Description": [ - "Papua New Guinean Sign Language" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "pha", - "Description": [ - "Pa-Hng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phd", - "Description": [ - "Phudagi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phg", - "Description": [ - "Phuong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phh", - "Description": [ - "Phukha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phi", - "Description": [ - "Philippine languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "phj", - "Description": [ - "Pahari" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "phk", - "Description": [ - "Phake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phl", - "Description": [ - "Phalura", - "Palula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phm", - "Description": [ - "Phimbi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phn", - "Description": [ - "Phoenician" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "pho", - "Description": [ - "Phunoi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phq", - "Description": [ - "Phana'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phr", - "Description": [ - "Pahari-Potwari" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "pht", - "Description": [ - "Phu Thai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phu", - "Description": [ - "Phuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phv", - "Description": [ - "Pahlavani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "phw", - "Description": [ - "Phangduwali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pia", - "Description": [ - "Pima Bajo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pib", - "Description": [ - "Yine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pic", - "Description": [ - "Pinji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pid", - "Description": [ - "Piaroa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pie", - "Description": [ - "Piro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pif", - "Description": [ - "Pingelapese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pig", - "Description": [ - "Pisabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pih", - "Description": [ - "Pitcairn-Norfolk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pii", - "Description": [ - "Pini" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "pij", - "Description": [ - "Pijao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pil", - "Description": [ - "Yom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pim", - "Description": [ - "Powhatan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pin", - "Description": [ - "Piame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pio", - "Description": [ - "Piapoco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pip", - "Description": [ - "Pero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pir", - "Description": [ - "Piratapuyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pis", - "Description": [ - "Pijin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pit", - "Description": [ - "Pitta Pitta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "piu", - "Description": [ - "Pintupi-Luritja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "piv", - "Description": [ - "Pileni", - "Vaeakau-Taumako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "piw", - "Description": [ - "Pimbwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pix", - "Description": [ - "Piu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "piy", - "Description": [ - "Piya-Kwonci" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "piz", - "Description": [ - "Pije" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pjt", - "Description": [ - "Pitjantjatjara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pka", - "Description": [ - "ArdhamÄgadhÄ« PrÄkrit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkb", - "Description": [ - "Pokomo", - "Kipfokomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkc", - "Description": [ - "Paekche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkg", - "Description": [ - "Pak-Tong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkh", - "Description": [ - "Pankhu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkn", - "Description": [ - "Pakanha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pko", - "Description": [ - "Pökoot" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "pkp", - "Description": [ - "Pukapuka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkr", - "Description": [ - "Attapady Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pks", - "Description": [ - "Pakistan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pkt", - "Description": [ - "Maleng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pku", - "Description": [ - "Paku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pla", - "Description": [ - "Miani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plb", - "Description": [ - "Polonombauk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plc", - "Description": [ - "Central Palawano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pld", - "Description": [ - "Polari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ple", - "Description": [ - "Palu'e" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plf", - "Description": [ - "Central Malayo-Polynesian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "plg", - "Description": [ - "Pilagá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plh", - "Description": [ - "Paulohi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plj", - "Description": [ - "Polci" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plk", - "Description": [ - "Kohistani Shina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pll", - "Description": [ - "Shwe Palaung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pln", - "Description": [ - "Palenquero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plo", - "Description": [ - "Oluta Popoluca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plp", - "Description": [ - "Palpa" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "plq", - "Description": [ - "Palaic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plr", - "Description": [ - "Palaka Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pls", - "Description": [ - "San Marcos Tlacoyalco Popoloca", - "San Marcos Tlalcoyalco Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plt", - "Description": [ - "Plateau Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "plu", - "Description": [ - "Palikúr" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plv", - "Description": [ - "Southwest Palawano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plw", - "Description": [ - "Brooke's Point Palawano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ply", - "Description": [ - "Bolyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "plz", - "Description": [ - "Paluan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pma", - "Description": [ - "Paama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmb", - "Description": [ - "Pambia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmc", - "Description": [ - "Palumata" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "huw" - }, - { - "Type": "language", - "Subtag": "pmd", - "Description": [ - "Pallanganmiddang" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "pme", - "Description": [ - "Pwaamei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmf", - "Description": [ - "Pamona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmh", - "Description": [ - "MÄhÄrÄṣṭri PrÄkrit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmi", - "Description": [ - "Northern Pumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmj", - "Description": [ - "Southern Pumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmk", - "Description": [ - "Pamlico" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pml", - "Description": [ - "Lingua Franca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmm", - "Description": [ - "Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmn", - "Description": [ - "Pam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmo", - "Description": [ - "Pom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmq", - "Description": [ - "Northern Pame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmr", - "Description": [ - "Paynamar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pms", - "Description": [ - "Piemontese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmt", - "Description": [ - "Tuamotuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmu", - "Description": [ - "Mirpur Panjabi" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "phr", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "pmw", - "Description": [ - "Plains Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmx", - "Description": [ - "Poumei Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmy", - "Description": [ - "Papuan Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pmz", - "Description": [ - "Southern Pame" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pna", - "Description": [ - "Punan Bah-Biau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnb", - "Description": [ - "Western Panjabi" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "pnc", - "Description": [ - "Pannei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnd", - "Description": [ - "Mpinda" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "pne", - "Description": [ - "Western Penan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "png", - "Description": [ - "Pangu", - "Pongu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnh", - "Description": [ - "Penrhyn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pni", - "Description": [ - "Aoheng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnj", - "Description": [ - "Pinjarup" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "pnk", - "Description": [ - "Paunaka" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "pnl", - "Description": [ - "Paleni" - ], - "Added": "2013-09-10", - "Comments": [ - "see also wbf" - ] - }, - { - "Type": "language", - "Subtag": "pnm", - "Description": [ - "Punan Batu 1" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnn", - "Description": [ - "Pinai-Hagahai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pno", - "Description": [ - "Panobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnp", - "Description": [ - "Pancana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnq", - "Description": [ - "Pana (Burkina Faso)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnr", - "Description": [ - "Panim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pns", - "Description": [ - "Ponosakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnt", - "Description": [ - "Pontic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnu", - "Description": [ - "Jiongnai Bunu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnv", - "Description": [ - "Pinigura" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnw", - "Description": [ - "Banyjima", - "Panytyima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pnx", - "Description": [ - "Phong-Kniang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pny", - "Description": [ - "Pinyin" - ], - "Added": "2009-07-29", - "Comments": [ - "a Niger-Congo language spoken in Cameroon; not to be confused with the Pinyin romanization systems used for Chinese and Tibetan" - ] - }, - { - "Type": "language", - "Subtag": "pnz", - "Description": [ - "Pana (Central African Republic)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poc", - "Description": [ - "Poqomam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pod", - "Description": [ - "Ponares" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "poe", - "Description": [ - "San Juan Atzingo Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pof", - "Description": [ - "Poke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pog", - "Description": [ - "Potiguára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poh", - "Description": [ - "Poqomchi'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poi", - "Description": [ - "Highland Popoluca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pok", - "Description": [ - "Pokangá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pom", - "Description": [ - "Southeastern Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pon", - "Description": [ - "Pohnpeian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "poo", - "Description": [ - "Central Pomo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pop", - "Description": [ - "Pwapwâ" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poq", - "Description": [ - "Texistepec Popoluca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pos", - "Description": [ - "Sayula Popoluca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pot", - "Description": [ - "Potawatomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pov", - "Description": [ - "Upper Guinea Crioulo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pow", - "Description": [ - "San Felipe Otlaltepec Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pox", - "Description": [ - "Polabian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poy", - "Description": [ - "Pogolo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "poz", - "Description": [ - "Malayo-Polynesian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ppa", - "Description": [ - "Pao" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "bfy" - }, - { - "Type": "language", - "Subtag": "ppe", - "Description": [ - "Papi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppi", - "Description": [ - "Paipai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppk", - "Description": [ - "Uma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppl", - "Description": [ - "Pipil", - "Nicarao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppm", - "Description": [ - "Papuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppn", - "Description": [ - "Papapana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppo", - "Description": [ - "Folopa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppp", - "Description": [ - "Pelende" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppq", - "Description": [ - "Pei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppr", - "Description": [ - "Piru" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "lcq" - }, - { - "Type": "language", - "Subtag": "pps", - "Description": [ - "San Luís Temalacayuca Popoloca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppt", - "Description": [ - "Pare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ppu", - "Description": [ - "Papora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pqa", - "Description": [ - "Pa'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pqe", - "Description": [ - "Eastern Malayo-Polynesian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "pqm", - "Description": [ - "Malecite-Passamaquoddy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pqw", - "Description": [ - "Western Malayo-Polynesian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "pra", - "Description": [ - "Prakrit languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "prb", - "Description": [ - "Lua'" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "prc", - "Description": [ - "Parachi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prd", - "Description": [ - "Parsi-Dari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pre", - "Description": [ - "Principense" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prf", - "Description": [ - "Paranan" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "prg", - "Description": [ - "Prussian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prh", - "Description": [ - "Porohanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pri", - "Description": [ - "Paicî" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prk", - "Description": [ - "Parauk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prl", - "Description": [ - "Peruvian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prm", - "Description": [ - "Kibiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prn", - "Description": [ - "Prasuni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pro", - "Description": [ - "Old Provençal (to 1500)", - "Old Occitan (to 1500)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "prp", - "Description": [ - "Parsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prq", - "Description": [ - "Ashéninka Perené" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prr", - "Description": [ - "Puri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prs", - "Description": [ - "Dari", - "Afghan Persian" - ], - "Added": "2009-07-29", - "Macrolanguage": "fa" - }, - { - "Type": "language", - "Subtag": "prt", - "Description": [ - "Phai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pru", - "Description": [ - "Puragi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prw", - "Description": [ - "Parawen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "prx", - "Description": [ - "Purik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pry", - "Description": [ - "Pray 3" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "prt" - }, - { - "Type": "language", - "Subtag": "prz", - "Description": [ - "Providencia Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psa", - "Description": [ - "Asue Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psc", - "Description": [ - "Iranian Sign Language", - "Persian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psd", - "Description": [ - "Plains Indian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pse", - "Description": [ - "Central Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "psg", - "Description": [ - "Penang Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psh", - "Description": [ - "Southwest Pashai", - "Southwest Pashayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psi", - "Description": [ - "Southeast Pashai", - "Southeast Pashayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psl", - "Description": [ - "Puerto Rican Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psm", - "Description": [ - "Pauserna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psn", - "Description": [ - "Panasuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pso", - "Description": [ - "Polish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psp", - "Description": [ - "Philippine Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psq", - "Description": [ - "Pasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psr", - "Description": [ - "Portuguese Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pss", - "Description": [ - "Kaulong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pst", - "Description": [ - "Central Pashto" - ], - "Added": "2009-07-29", - "Macrolanguage": "ps" - }, - { - "Type": "language", - "Subtag": "psu", - "Description": [ - "Sauraseni PrÄkrit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psw", - "Description": [ - "Port Sandwich" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "psy", - "Description": [ - "Piscataway" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pta", - "Description": [ - "Pai Tavytera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pth", - "Description": [ - "Pataxó Hã-Ha-Hãe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pti", - "Description": [ - "Pindiini", - "Wangkatha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptn", - "Description": [ - "Patani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pto", - "Description": [ - "Zo'é" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptp", - "Description": [ - "Patep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptq", - "Description": [ - "Pattapu" - ], - "Added": "2014-04-06" - }, - { - "Type": "language", - "Subtag": "ptr", - "Description": [ - "Piamatsina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptt", - "Description": [ - "Enrekang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptu", - "Description": [ - "Bambam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptv", - "Description": [ - "Port Vato" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ptw", - "Description": [ - "Pentlatch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pty", - "Description": [ - "Pathiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pua", - "Description": [ - "Western Highland Purepecha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pub", - "Description": [ - "Purum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puc", - "Description": [ - "Punan Merap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pud", - "Description": [ - "Punan Aput" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pue", - "Description": [ - "Puelche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puf", - "Description": [ - "Punan Merah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pug", - "Description": [ - "Phuie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pui", - "Description": [ - "Puinave" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puj", - "Description": [ - "Punan Tubu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puk", - "Description": [ - "Pu Ko" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "pum", - "Description": [ - "Puma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puo", - "Description": [ - "Puoc" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pup", - "Description": [ - "Pulabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puq", - "Description": [ - "Puquina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pur", - "Description": [ - "Puruborá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "put", - "Description": [ - "Putoh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puu", - "Description": [ - "Punu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puw", - "Description": [ - "Puluwatese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pux", - "Description": [ - "Puare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puy", - "Description": [ - "Purisimeño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "puz", - "Description": [ - "Purum Naga" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28", - "Preferred-Value": "pub" - }, - { - "Type": "language", - "Subtag": "pwa", - "Description": [ - "Pawaia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwb", - "Description": [ - "Panawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwg", - "Description": [ - "Gapapaiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwi", - "Description": [ - "Patwin" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "pwm", - "Description": [ - "Molbog" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwn", - "Description": [ - "Paiwan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwo", - "Description": [ - "Pwo Western Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pwr", - "Description": [ - "Powari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pww", - "Description": [ - "Pwo Northern Karen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pxm", - "Description": [ - "Quetzaltepec Mixe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pye", - "Description": [ - "Pye Krumen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pym", - "Description": [ - "Fyam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pyn", - "Description": [ - "Poyanáwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pys", - "Description": [ - "Paraguayan Sign Language", - "Lengua de Señas del Paraguay" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "pyu", - "Description": [ - "Puyuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pyx", - "Description": [ - "Pyu (Myanmar)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pyy", - "Description": [ - "Pyen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "pzh", - "Description": [ - "Pazeh" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "pzn", - "Description": [ - "Jejara Naga", - "Para Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qaa..qtz", - "Description": [ - "Private use" - ], - "Added": "2005-10-16", - "Scope": "private-use" - }, - { - "Type": "language", - "Subtag": "qua", - "Description": [ - "Quapaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qub", - "Description": [ - "Huallaga Huánuco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quc", - "Description": [ - "K'iche'", - "Quiché" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qud", - "Description": [ - "Calderón Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quf", - "Description": [ - "Lambayeque Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qug", - "Description": [ - "Chimborazo Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quh", - "Description": [ - "South Bolivian Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qui", - "Description": [ - "Quileute" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "quk", - "Description": [ - "Chachapoyas Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qul", - "Description": [ - "North Bolivian Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qum", - "Description": [ - "Sipacapense" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qun", - "Description": [ - "Quinault" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qup", - "Description": [ - "Southern Pastaza Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quq", - "Description": [ - "Quinqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qur", - "Description": [ - "Yanahuanca Pasco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qus", - "Description": [ - "Santiago del Estero Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quv", - "Description": [ - "Sacapulteco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "quw", - "Description": [ - "Tena Lowland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qux", - "Description": [ - "Yauyos Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quy", - "Description": [ - "Ayacucho Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "quz", - "Description": [ - "Cusco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qva", - "Description": [ - "Ambo-Pasco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvc", - "Description": [ - "Cajamarca Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qve", - "Description": [ - "Eastern Apurímac Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvh", - "Description": [ - "Huamalíes-Dos de Mayo Huánuco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvi", - "Description": [ - "Imbabura Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvj", - "Description": [ - "Loja Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvl", - "Description": [ - "Cajatambo North Lima Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvm", - "Description": [ - "Margos-Yarowilca-Lauricocha Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvn", - "Description": [ - "North Junín Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvo", - "Description": [ - "Napo Lowland Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvp", - "Description": [ - "Pacaraos Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvs", - "Description": [ - "San Martín Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvw", - "Description": [ - "Huaylla Wanca Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qvy", - "Description": [ - "Queyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qvz", - "Description": [ - "Northern Pastaza Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qwa", - "Description": [ - "Corongo Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qwc", - "Description": [ - "Classical Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qwe", - "Description": [ - "Quechuan (family)" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "qwh", - "Description": [ - "Huaylas Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qwm", - "Description": [ - "Kuman (Russia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qws", - "Description": [ - "Sihuas Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qwt", - "Description": [ - "Kwalhioqua-Tlatskanai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qxa", - "Description": [ - "Chiquián Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxc", - "Description": [ - "Chincha Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxh", - "Description": [ - "Panao Huánuco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxl", - "Description": [ - "Salasaca Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxn", - "Description": [ - "Northern Conchucos Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxo", - "Description": [ - "Southern Conchucos Ancash Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxp", - "Description": [ - "Puno Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxq", - "Description": [ - "Qashqa'i" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qxr", - "Description": [ - "Cañar Highland Quichua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxs", - "Description": [ - "Southern Qiang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qxt", - "Description": [ - "Santa Ana de Tusi Pasco Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxu", - "Description": [ - "Arequipa-La Unión Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qxw", - "Description": [ - "Jauja Wanca Quechua" - ], - "Added": "2009-07-29", - "Macrolanguage": "qu" - }, - { - "Type": "language", - "Subtag": "qya", - "Description": [ - "Quenya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "qyp", - "Description": [ - "Quiripi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "raa", - "Description": [ - "Dungmali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rab", - "Description": [ - "Camling" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rac", - "Description": [ - "Rasawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rad", - "Description": [ - "Rade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "raf", - "Description": [ - "Western Meohang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rag", - "Description": [ - "Logooli", - "Lulogooli" - ], - "Added": "2009-07-29", - "Macrolanguage": "luy" - }, - { - "Type": "language", - "Subtag": "rah", - "Description": [ - "Rabha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rai", - "Description": [ - "Ramoaaina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "raj", - "Description": [ - "Rajasthani" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "rak", - "Description": [ - "Tulu-Bohuai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ral", - "Description": [ - "Ralte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ram", - "Description": [ - "Canela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ran", - "Description": [ - "Riantana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rao", - "Description": [ - "Rao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rap", - "Description": [ - "Rapanui" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "raq", - "Description": [ - "Saam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rar", - "Description": [ - "Rarotongan", - "Cook Islands Maori" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ras", - "Description": [ - "Tegali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rat", - "Description": [ - "Razajerdi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rau", - "Description": [ - "Raute" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rav", - "Description": [ - "Sampang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "raw", - "Description": [ - "Rawang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rax", - "Description": [ - "Rang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ray", - "Description": [ - "Rapa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "raz", - "Description": [ - "Rahambuu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rbb", - "Description": [ - "Rumai Palaung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rbk", - "Description": [ - "Northern Bontok" - ], - "Added": "2010-03-11", - "Macrolanguage": "bnc" - }, - { - "Type": "language", - "Subtag": "rbl", - "Description": [ - "Miraya Bikol" - ], - "Added": "2010-03-11", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "rbp", - "Description": [ - "Barababaraba" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "rcf", - "Description": [ - "Réunion Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rdb", - "Description": [ - "Rudbari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rea", - "Description": [ - "Rerau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "reb", - "Description": [ - "Rembong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ree", - "Description": [ - "Rejang Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "reg", - "Description": [ - "Kara (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rei", - "Description": [ - "Reli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rej", - "Description": [ - "Rejang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rel", - "Description": [ - "Rendille" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rem", - "Description": [ - "Remo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ren", - "Description": [ - "Rengao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rer", - "Description": [ - "Rer Bare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "res", - "Description": [ - "Reshe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ret", - "Description": [ - "Retta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rey", - "Description": [ - "Reyesano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rga", - "Description": [ - "Roria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rge", - "Description": [ - "Romano-Greek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rgk", - "Description": [ - "Rangkas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rgn", - "Description": [ - "Romagnol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rgr", - "Description": [ - "Resígaro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rgs", - "Description": [ - "Southern Roglai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rgu", - "Description": [ - "Ringgou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rhg", - "Description": [ - "Rohingya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rhp", - "Description": [ - "Yahang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ria", - "Description": [ - "Riang (India)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rib", - "Description": [ - "Bribri Sign Language" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "rie", - "Description": [ - "Rien" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "rif", - "Description": [ - "Tarifit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ril", - "Description": [ - "Riang Lang", - "Riang (Myanmar)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rim", - "Description": [ - "Nyaturu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rin", - "Description": [ - "Nungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rir", - "Description": [ - "Ribun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rit", - "Description": [ - "Ritharrngu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "riu", - "Description": [ - "Riung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rjg", - "Description": [ - "Rajong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rji", - "Description": [ - "Raji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rjs", - "Description": [ - "Rajbanshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rka", - "Description": [ - "Kraol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rkb", - "Description": [ - "Rikbaktsa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rkh", - "Description": [ - "Rakahanga-Manihiki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rki", - "Description": [ - "Rakhine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rkm", - "Description": [ - "Marka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rkt", - "Description": [ - "Rangpuri", - "Kamta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rkw", - "Description": [ - "Arakwal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "rma", - "Description": [ - "Rama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmb", - "Description": [ - "Rembarrnga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmc", - "Description": [ - "Carpathian Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmd", - "Description": [ - "Traveller Danish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rme", - "Description": [ - "Angloromani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmf", - "Description": [ - "Kalo Finnish Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmg", - "Description": [ - "Traveller Norwegian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmh", - "Description": [ - "Murkim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmi", - "Description": [ - "Lomavren" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmk", - "Description": [ - "Romkun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rml", - "Description": [ - "Baltic Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmm", - "Description": [ - "Roma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmn", - "Description": [ - "Balkan Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmo", - "Description": [ - "Sinte Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmp", - "Description": [ - "Rempi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmq", - "Description": [ - "Caló" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "rmr", - "Description": [ - "Caló" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see emx, rmq" - ] - }, - { - "Type": "language", - "Subtag": "rms", - "Description": [ - "Romanian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmt", - "Description": [ - "Domari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmu", - "Description": [ - "Tavringer Romani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmv", - "Description": [ - "Romanova" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmw", - "Description": [ - "Welsh Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmx", - "Description": [ - "Romam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rmy", - "Description": [ - "Vlax Romani" - ], - "Added": "2009-07-29", - "Macrolanguage": "rom" - }, - { - "Type": "language", - "Subtag": "rmz", - "Description": [ - "Marma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rna", - "Description": [ - "Runa" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "rnb", - "Description": [ - "Brunca Sign Language" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "rnd", - "Description": [ - "Ruund" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rng", - "Description": [ - "Ronga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rnl", - "Description": [ - "Ranglong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rnn", - "Description": [ - "Roon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rnp", - "Description": [ - "Rongpo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rnr", - "Description": [ - "Nari Nari" - ], - "Added": "2012-08-20" - }, - { - "Type": "language", - "Subtag": "rnw", - "Description": [ - "Rungwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "roa", - "Description": [ - "Romance languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "rob", - "Description": [ - "Tae'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "roc", - "Description": [ - "Cacgia Roglai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rod", - "Description": [ - "Rogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "roe", - "Description": [ - "Ronji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rof", - "Description": [ - "Rombo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rog", - "Description": [ - "Northern Roglai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rol", - "Description": [ - "Romblomanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rom", - "Description": [ - "Romany" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "roo", - "Description": [ - "Rotokas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rop", - "Description": [ - "Kriol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ror", - "Description": [ - "Rongga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rou", - "Description": [ - "Runga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "row", - "Description": [ - "Dela-Oenale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rpn", - "Description": [ - "Repanbitip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rpt", - "Description": [ - "Rapting" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rri", - "Description": [ - "Ririo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rro", - "Description": [ - "Waima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rrt", - "Description": [ - "Arritinngithigh" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "rsb", - "Description": [ - "Romano-Serbian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rsi", - "Description": [ - "Rennellese Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "rsk", - "Description": [ - "Ruthenian", - "Rusyn" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "rsl", - "Description": [ - "Russian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rsm", - "Description": [ - "Miriwoong Sign Language" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "rsn", - "Description": [ - "Rwandan Sign Language" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "rtc", - "Description": [ - "Rungtu Chin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "rth", - "Description": [ - "Ratahan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rtm", - "Description": [ - "Rotuman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rts", - "Description": [ - "Yurats" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "rtw", - "Description": [ - "Rathawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rub", - "Description": [ - "Gungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruc", - "Description": [ - "Ruuli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rue", - "Description": [ - "Rusyn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruf", - "Description": [ - "Luguru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rug", - "Description": [ - "Roviana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruh", - "Description": [ - "Ruga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rui", - "Description": [ - "Rufiji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruk", - "Description": [ - "Che" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruo", - "Description": [ - "Istro Romanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rup", - "Description": [ - "Macedo-Romanian", - "Aromanian", - "Arumanian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ruq", - "Description": [ - "Megleno Romanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rut", - "Description": [ - "Rutul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruu", - "Description": [ - "Lanas Lobu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruy", - "Description": [ - "Mala (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ruz", - "Description": [ - "Ruma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rwa", - "Description": [ - "Rawo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rwk", - "Description": [ - "Rwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rwl", - "Description": [ - "Ruwila" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "rwm", - "Description": [ - "Amba (Uganda)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rwo", - "Description": [ - "Rawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rwr", - "Description": [ - "Marwari (India)" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "rxd", - "Description": [ - "Ngardi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "rxw", - "Description": [ - "Karuwali", - "Garuwali" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ryn", - "Description": [ - "Northern Amami-Oshima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rys", - "Description": [ - "Yaeyama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ryu", - "Description": [ - "Central Okinawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "rzh", - "Description": [ - "RÄziḥī" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "saa", - "Description": [ - "Saba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sab", - "Description": [ - "Buglere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sac", - "Description": [ - "Meskwaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sad", - "Description": [ - "Sandawe" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sae", - "Description": [ - "Sabanê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "saf", - "Description": [ - "Safaliba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sah", - "Description": [ - "Yakut" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sai", - "Description": [ - "South American Indian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "saj", - "Description": [ - "Sahu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sak", - "Description": [ - "Sake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sal", - "Description": [ - "Salishan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sam", - "Description": [ - "Samaritan Aramaic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sao", - "Description": [ - "Sause" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sap", - "Description": [ - "Sanapaná" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28", - "Comments": [ - "see aqt, spn" - ] - }, - { - "Type": "language", - "Subtag": "saq", - "Description": [ - "Samburu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sar", - "Description": [ - "Saraveca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sas", - "Description": [ - "Sasak" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sat", - "Description": [ - "Santali" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sau", - "Description": [ - "Saleman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sav", - "Description": [ - "Saafi-Saafi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "saw", - "Description": [ - "Sawi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sax", - "Description": [ - "Sa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "say", - "Description": [ - "Saya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "saz", - "Description": [ - "Saurashtra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sba", - "Description": [ - "Ngambay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbb", - "Description": [ - "Simbo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbc", - "Description": [ - "Kele (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbd", - "Description": [ - "Southern Samo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbe", - "Description": [ - "Saliba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbf", - "Description": [ - "Chabu", - "Shabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbg", - "Description": [ - "Seget" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbh", - "Description": [ - "Sori-Harengan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbi", - "Description": [ - "Seti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbj", - "Description": [ - "Surbakhal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbk", - "Description": [ - "Safwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbl", - "Description": [ - "Botolan Sambal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbm", - "Description": [ - "Sagala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbn", - "Description": [ - "Sindhi Bhil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbo", - "Description": [ - "Sabüm" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbp", - "Description": [ - "Sangu (Tanzania)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbq", - "Description": [ - "Sileibi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbr", - "Description": [ - "Sembakung Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbs", - "Description": [ - "Subiya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbt", - "Description": [ - "Kimki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbu", - "Description": [ - "Stod Bhoti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbv", - "Description": [ - "Sabine" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbw", - "Description": [ - "Simba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbx", - "Description": [ - "Seberuang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sby", - "Description": [ - "Soli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sbz", - "Description": [ - "Sara Kaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sca", - "Description": [ - "Sansu" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "hle" - }, - { - "Type": "language", - "Subtag": "scb", - "Description": [ - "Chut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sce", - "Description": [ - "Dongxiang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scf", - "Description": [ - "San Miguel Creole French" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scg", - "Description": [ - "Sanggau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sch", - "Description": [ - "Sakachep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sci", - "Description": [ - "Sri Lankan Creole Malay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sck", - "Description": [ - "Sadri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scl", - "Description": [ - "Shina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scn", - "Description": [ - "Sicilian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sco", - "Description": [ - "Scots" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "scp", - "Description": [ - "Hyolmo", - "Helambu Sherpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scq", - "Description": [ - "Sa'och" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scs", - "Description": [ - "North Slavey" - ], - "Added": "2009-07-29", - "Macrolanguage": "den" - }, - { - "Type": "language", - "Subtag": "sct", - "Description": [ - "Southern Katang" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "scu", - "Description": [ - "Shumcho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scv", - "Description": [ - "Sheni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scw", - "Description": [ - "Sha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "scx", - "Description": [ - "Sicel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sda", - "Description": [ - "Toraja-Sa'dan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdb", - "Description": [ - "Shabak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdc", - "Description": [ - "Sassarese Sardinian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sc" - }, - { - "Type": "language", - "Subtag": "sde", - "Description": [ - "Surubu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdf", - "Description": [ - "Sarli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdg", - "Description": [ - "Savi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdh", - "Description": [ - "Southern Kurdish" - ], - "Added": "2009-07-29", - "Macrolanguage": "ku" - }, - { - "Type": "language", - "Subtag": "sdj", - "Description": [ - "Suundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdk", - "Description": [ - "Sos Kundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdl", - "Description": [ - "Saudi Arabian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdm", - "Description": [ - "Semandang" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Comments": [ - "see ebc, gef, sdq" - ] - }, - { - "Type": "language", - "Subtag": "sdn", - "Description": [ - "Gallurese Sardinian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sc" - }, - { - "Type": "language", - "Subtag": "sdo", - "Description": [ - "Bukar-Sadung Bidayuh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdp", - "Description": [ - "Sherdukpen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdq", - "Description": [ - "Semandang" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "sdr", - "Description": [ - "Oraon Sadri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sds", - "Description": [ - "Sened" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdt", - "Description": [ - "Shuadit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdu", - "Description": [ - "Sarudu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdv", - "Description": [ - "Eastern Sudanic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sdx", - "Description": [ - "Sibu Melanau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sdz", - "Description": [ - "Sallands" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sea", - "Description": [ - "Semai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seb", - "Description": [ - "Shempire Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sec", - "Description": [ - "Sechelt" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sed", - "Description": [ - "Sedang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "see", - "Description": [ - "Seneca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sef", - "Description": [ - "Cebaara Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seg", - "Description": [ - "Segeju" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seh", - "Description": [ - "Sena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sei", - "Description": [ - "Seri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sej", - "Description": [ - "Sene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sek", - "Description": [ - "Sekani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sel", - "Description": [ - "Selkup" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sem", - "Description": [ - "Semitic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sen", - "Description": [ - "Nanerigé Sénoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seo", - "Description": [ - "Suarmin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sep", - "Description": [ - "Sìcìté Sénoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seq", - "Description": [ - "Senara Sénoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ser", - "Description": [ - "Serrano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ses", - "Description": [ - "Koyraboro Senni Songhai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "set", - "Description": [ - "Sentani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "seu", - "Description": [ - "Serui-Laut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sev", - "Description": [ - "Nyarafolo Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sew", - "Description": [ - "Sewa Bay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sey", - "Description": [ - "Secoya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sez", - "Description": [ - "Senthang Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sfb", - "Description": [ - "Langue des signes de Belgique Francophone", - "French Belgian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sfe", - "Description": [ - "Eastern Subanen" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "sfm", - "Description": [ - "Small Flowery Miao" - ], - "Added": "2009-07-29", - "Macrolanguage": "hmn" - }, - { - "Type": "language", - "Subtag": "sfs", - "Description": [ - "South African Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sfw", - "Description": [ - "Sehwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sga", - "Description": [ - "Old Irish (to 900)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sgb", - "Description": [ - "Mag-antsi Ayta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgc", - "Description": [ - "Kipsigis" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "sgd", - "Description": [ - "Surigaonon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "sge", - "Description": [ - "Segai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgg", - "Description": [ - "Swiss-German Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgh", - "Description": [ - "Shughni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgi", - "Description": [ - "Suga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgj", - "Description": [ - "Surgujia" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "sgk", - "Description": [ - "Sangkong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgl", - "Description": [ - "Sanglechi-Ishkashimi" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see isk, sgy" - ] - }, - { - "Type": "language", - "Subtag": "sgm", - "Description": [ - "Singa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgn", - "Description": [ - "Sign languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sgo", - "Description": [ - "Songa" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "sgp", - "Description": [ - "Singpho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgr", - "Description": [ - "Sangisari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgs", - "Description": [ - "Samogitian" - ], - "Added": "2010-07-26" - }, - { - "Type": "language", - "Subtag": "sgt", - "Description": [ - "Brokpake" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgu", - "Description": [ - "Salas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgw", - "Description": [ - "Sebat Bet Gurage" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgx", - "Description": [ - "Sierra Leone Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sgy", - "Description": [ - "Sanglechi" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "sgz", - "Description": [ - "Sursurunga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sha", - "Description": [ - "Shall-Zwall" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shb", - "Description": [ - "Ninam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shc", - "Description": [ - "Sonde" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shd", - "Description": [ - "Kundal Shahi" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "she", - "Description": [ - "Sheko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shg", - "Description": [ - "Shua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shh", - "Description": [ - "Shoshoni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shi", - "Description": [ - "Tachelhit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shj", - "Description": [ - "Shatt" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shk", - "Description": [ - "Shilluk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shl", - "Description": [ - "Shendu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shm", - "Description": [ - "Shahrudi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shn", - "Description": [ - "Shan" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sho", - "Description": [ - "Shanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shp", - "Description": [ - "Shipibo-Conibo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shq", - "Description": [ - "Sala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shr", - "Description": [ - "Shi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shs", - "Description": [ - "Shuswap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sht", - "Description": [ - "Shasta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shu", - "Description": [ - "Chadian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "shv", - "Description": [ - "Shehri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shw", - "Description": [ - "Shwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shx", - "Description": [ - "She" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shy", - "Description": [ - "Tachawit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "shz", - "Description": [ - "Syenara Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sia", - "Description": [ - "Akkala Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sib", - "Description": [ - "Sebop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sid", - "Description": [ - "Sidamo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sie", - "Description": [ - "Simaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sif", - "Description": [ - "Siamou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sig", - "Description": [ - "Paasaal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sih", - "Description": [ - "Zire", - "Sîshëë" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sii", - "Description": [ - "Shom Peng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sij", - "Description": [ - "Numbami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sik", - "Description": [ - "Sikiana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sil", - "Description": [ - "Tumulung Sisaala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sim", - "Description": [ - "Mende (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sio", - "Description": [ - "Siouan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sip", - "Description": [ - "Sikkimese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "siq", - "Description": [ - "Sonia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sir", - "Description": [ - "Siri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sis", - "Description": [ - "Siuslaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sit", - "Description": [ - "Sino-Tibetan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "siu", - "Description": [ - "Sinagen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "siv", - "Description": [ - "Sumariup" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "siw", - "Description": [ - "Siwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "six", - "Description": [ - "Sumau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "siy", - "Description": [ - "Sivandi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "siz", - "Description": [ - "Siwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sja", - "Description": [ - "Epena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjb", - "Description": [ - "Sajau Basap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjd", - "Description": [ - "Kildin Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sje", - "Description": [ - "Pite Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjg", - "Description": [ - "Assangori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjk", - "Description": [ - "Kemi Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjl", - "Description": [ - "Sajalong", - "Miji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjm", - "Description": [ - "Mapun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjn", - "Description": [ - "Sindarin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjo", - "Description": [ - "Xibe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjp", - "Description": [ - "Surjapuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjr", - "Description": [ - "Siar-Lak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjs", - "Description": [ - "Senhaja De Srair" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjt", - "Description": [ - "Ter Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sju", - "Description": [ - "Ume Sami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sjw", - "Description": [ - "Shawnee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ska", - "Description": [ - "Skagit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skb", - "Description": [ - "Saek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skc", - "Description": [ - "Ma Manda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skd", - "Description": [ - "Southern Sierra Miwok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ske", - "Description": [ - "Seke (Vanuatu)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skf", - "Description": [ - "Sakirabiá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skg", - "Description": [ - "Sakalava Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "skh", - "Description": [ - "Sikule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ski", - "Description": [ - "Sika" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skj", - "Description": [ - "Seke (Nepal)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skk", - "Description": [ - "Sok" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23", - "Preferred-Value": "oyb" - }, - { - "Type": "language", - "Subtag": "skm", - "Description": [ - "Kutong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skn", - "Description": [ - "Kolibugan Subanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sko", - "Description": [ - "Seko Tengah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skp", - "Description": [ - "Sekapan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skq", - "Description": [ - "Sininkere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skr", - "Description": [ - "Saraiki", - "Seraiki" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "sks", - "Description": [ - "Maia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skt", - "Description": [ - "Sakata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sku", - "Description": [ - "Sakao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skv", - "Description": [ - "Skou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skw", - "Description": [ - "Skepi Creole Dutch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skx", - "Description": [ - "Seko Padang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sky", - "Description": [ - "Sikaiana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "skz", - "Description": [ - "Sekar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sla", - "Description": [ - "Slavic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "slc", - "Description": [ - "Sáliba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sld", - "Description": [ - "Sissala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sle", - "Description": [ - "Sholaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slf", - "Description": [ - "Swiss-Italian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slg", - "Description": [ - "Selungai Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slh", - "Description": [ - "Southern Puget Sound Salish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sli", - "Description": [ - "Lower Silesian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slj", - "Description": [ - "Salumá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sll", - "Description": [ - "Salt-Yui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slm", - "Description": [ - "Pangutaran Sama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sln", - "Description": [ - "Salinan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slp", - "Description": [ - "Lamaholot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slq", - "Description": [ - "Salchuq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slr", - "Description": [ - "Salar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sls", - "Description": [ - "Singapore Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slt", - "Description": [ - "Sila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slu", - "Description": [ - "Selaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slw", - "Description": [ - "Sialum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slx", - "Description": [ - "Salampasu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sly", - "Description": [ - "Selayar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "slz", - "Description": [ - "Ma'ya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sma", - "Description": [ - "Southern Sami" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "smb", - "Description": [ - "Simbari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smc", - "Description": [ - "Som" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smd", - "Description": [ - "Sama" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Preferred-Value": "kmb" - }, - { - "Type": "language", - "Subtag": "smf", - "Description": [ - "Auwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smg", - "Description": [ - "Simbali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smh", - "Description": [ - "Samei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smi", - "Description": [ - "Sami languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "smj", - "Description": [ - "Lule Sami" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "smk", - "Description": [ - "Bolinao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sml", - "Description": [ - "Central Sama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smm", - "Description": [ - "Musasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smn", - "Description": [ - "Inari Sami" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "smp", - "Description": [ - "Samaritan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smq", - "Description": [ - "Samo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smr", - "Description": [ - "Simeulue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sms", - "Description": [ - "Skolt Sami" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "smt", - "Description": [ - "Simte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smu", - "Description": [ - "Somray" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smv", - "Description": [ - "Samvedi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smw", - "Description": [ - "Sumbawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smx", - "Description": [ - "Samba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smy", - "Description": [ - "Semnani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "smz", - "Description": [ - "Simeku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snb", - "Description": [ - "Sebuyau" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Preferred-Value": "iba" - }, - { - "Type": "language", - "Subtag": "snc", - "Description": [ - "Sinaugoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sne", - "Description": [ - "Bau Bidayuh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snf", - "Description": [ - "Noon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sng", - "Description": [ - "Sanga (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snh", - "Description": [ - "Shinabo" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "sni", - "Description": [ - "Sensi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snj", - "Description": [ - "Riverain Sango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snk", - "Description": [ - "Soninke" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "snl", - "Description": [ - "Sangil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snm", - "Description": [ - "Southern Ma'di" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snn", - "Description": [ - "Siona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sno", - "Description": [ - "Snohomish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snp", - "Description": [ - "Siane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snq", - "Description": [ - "Sangu (Gabon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snr", - "Description": [ - "Sihan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sns", - "Description": [ - "South West Bay", - "Nahavaq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snu", - "Description": [ - "Senggi", - "Viid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snv", - "Description": [ - "Sa'ban" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snw", - "Description": [ - "Selee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snx", - "Description": [ - "Sam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sny", - "Description": [ - "Saniyo-Hiyewe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "snz", - "Description": [ - "Kou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soa", - "Description": [ - "Thai Song" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sob", - "Description": [ - "Sobei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soc", - "Description": [ - "So (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sod", - "Description": [ - "Songoora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soe", - "Description": [ - "Songomeno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sog", - "Description": [ - "Sogdian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "soh", - "Description": [ - "Aka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soi", - "Description": [ - "Sonha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soj", - "Description": [ - "Soi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sok", - "Description": [ - "Sokoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sol", - "Description": [ - "Solos" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "son", - "Description": [ - "Songhai languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "soo", - "Description": [ - "Songo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sop", - "Description": [ - "Songe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soq", - "Description": [ - "Kanasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sor", - "Description": [ - "Somrai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sos", - "Description": [ - "Seeku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sou", - "Description": [ - "Southern Thai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sov", - "Description": [ - "Sonsorol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sow", - "Description": [ - "Sowanda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sox", - "Description": [ - "Swo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soy", - "Description": [ - "Miyobe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "soz", - "Description": [ - "Temi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spb", - "Description": [ - "Sepa (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spc", - "Description": [ - "Sapé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spd", - "Description": [ - "Saep" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spe", - "Description": [ - "Sepa (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spg", - "Description": [ - "Sian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spi", - "Description": [ - "Saponi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spk", - "Description": [ - "Sengo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spl", - "Description": [ - "Selepet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spm", - "Description": [ - "Akukem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spn", - "Description": [ - "Sanapaná" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "spo", - "Description": [ - "Spokane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spp", - "Description": [ - "Supyire Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spq", - "Description": [ - "Loreto-Ucayali Spanish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spr", - "Description": [ - "Saparua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sps", - "Description": [ - "Saposa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spt", - "Description": [ - "Spiti Bhoti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spu", - "Description": [ - "Sapuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spv", - "Description": [ - "Sambalpuri", - "Kosli" - ], - "Added": "2012-08-12", - "Macrolanguage": "or" - }, - { - "Type": "language", - "Subtag": "spx", - "Description": [ - "South Picene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "spy", - "Description": [ - "Sabaot" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "sqa", - "Description": [ - "Shama-Sambuga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqh", - "Description": [ - "Shau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqj", - "Description": [ - "Albanian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "sqk", - "Description": [ - "Albanian Sign Language" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "sqm", - "Description": [ - "Suma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqn", - "Description": [ - "Susquehannock" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqo", - "Description": [ - "Sorkhei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqq", - "Description": [ - "Sou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqr", - "Description": [ - "Siculo Arabic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqs", - "Description": [ - "Sri Lankan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqt", - "Description": [ - "Soqotri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "squ", - "Description": [ - "Squamish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sqx", - "Description": [ - "Kufr Qassem Sign Language (KQSL)" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "sra", - "Description": [ - "Saruga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srb", - "Description": [ - "Sora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "src", - "Description": [ - "Logudorese Sardinian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sc" - }, - { - "Type": "language", - "Subtag": "sre", - "Description": [ - "Sara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srf", - "Description": [ - "Nafi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srg", - "Description": [ - "Sulod" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srh", - "Description": [ - "Sarikoli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sri", - "Description": [ - "Siriano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srk", - "Description": [ - "Serudung Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srl", - "Description": [ - "Isirawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srm", - "Description": [ - "Saramaccan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srn", - "Description": [ - "Sranan Tongo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sro", - "Description": [ - "Campidanese Sardinian" - ], - "Added": "2009-07-29", - "Macrolanguage": "sc" - }, - { - "Type": "language", - "Subtag": "srq", - "Description": [ - "Sirionó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srr", - "Description": [ - "Serer" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "srs", - "Description": [ - "Sarsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srt", - "Description": [ - "Sauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sru", - "Description": [ - "Suruí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srv", - "Description": [ - "Southern Sorsoganon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srw", - "Description": [ - "Serua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srx", - "Description": [ - "Sirmauri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sry", - "Description": [ - "Sera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "srz", - "Description": [ - "Shahmirzadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssa", - "Description": [ - "Nilo-Saharan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ssb", - "Description": [ - "Southern Sama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssc", - "Description": [ - "Suba-Simbiti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssd", - "Description": [ - "Siroi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sse", - "Description": [ - "Balangingi", - "Bangingih Sama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssf", - "Description": [ - "Thao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssg", - "Description": [ - "Seimat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssh", - "Description": [ - "Shihhi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "ar" - }, - { - "Type": "language", - "Subtag": "ssi", - "Description": [ - "Sansi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssj", - "Description": [ - "Sausi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssk", - "Description": [ - "Sunam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssl", - "Description": [ - "Western Sisaala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssm", - "Description": [ - "Semnam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssn", - "Description": [ - "Waata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sso", - "Description": [ - "Sissano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssp", - "Description": [ - "Spanish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssq", - "Description": [ - "So'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssr", - "Description": [ - "Swiss-French Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sss", - "Description": [ - "Sô" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sst", - "Description": [ - "Sinasina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssu", - "Description": [ - "Susuami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssv", - "Description": [ - "Shark Bay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssx", - "Description": [ - "Samberigi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssy", - "Description": [ - "Saho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ssz", - "Description": [ - "Sengseng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sta", - "Description": [ - "Settla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stb", - "Description": [ - "Northern Subanen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "std", - "Description": [ - "Sentinel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ste", - "Description": [ - "Liana-Seti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stf", - "Description": [ - "Seta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stg", - "Description": [ - "Trieng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sth", - "Description": [ - "Shelta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sti", - "Description": [ - "Bulo Stieng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stj", - "Description": [ - "Matya Samo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stk", - "Description": [ - "Arammba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stl", - "Description": [ - "Stellingwerfs" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stm", - "Description": [ - "Setaman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stn", - "Description": [ - "Owa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sto", - "Description": [ - "Stoney" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stp", - "Description": [ - "Southeastern Tepehuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stq", - "Description": [ - "Saterfriesisch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "str", - "Description": [ - "Straits Salish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sts", - "Description": [ - "Shumashti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stt", - "Description": [ - "Budeh Stieng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stu", - "Description": [ - "Samtao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stv", - "Description": [ - "Silt'e" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "stw", - "Description": [ - "Satawalese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sty", - "Description": [ - "Siberian Tatar" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "sua", - "Description": [ - "Sulka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sub", - "Description": [ - "Suku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "suc", - "Description": [ - "Western Subanon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sue", - "Description": [ - "Suena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sug", - "Description": [ - "Suganga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sui", - "Description": [ - "Suki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "suj", - "Description": [ - "Shubi" - ], - "Added": "2009-07-29", - "Comments": [ - "see also xsj" - ] - }, - { - "Type": "language", - "Subtag": "suk", - "Description": [ - "Sukuma" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sul", - "Description": [ - "Surigaonon" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see sgd, tgn" - ] - }, - { - "Type": "language", - "Subtag": "sum", - "Description": [ - "Sumo-Mayangna" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see ulw, yan" - ] - }, - { - "Type": "language", - "Subtag": "suo", - "Description": [ - "Bouni" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "suq", - "Description": [ - "Tirmaga-Chai Suri", - "Suri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sur", - "Description": [ - "Mwaghavul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sus", - "Description": [ - "Susu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "sut", - "Description": [ - "Subtiaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "suv", - "Description": [ - "Puroik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "suw", - "Description": [ - "Sumbwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sux", - "Description": [ - "Sumerian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "suy", - "Description": [ - "Suyá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "suz", - "Description": [ - "Sunwar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sva", - "Description": [ - "Svan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "svb", - "Description": [ - "Ulau-Suain" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "svc", - "Description": [ - "Vincentian Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sve", - "Description": [ - "Serili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "svk", - "Description": [ - "Slovakian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "svm", - "Description": [ - "Slavomolisano" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "svr", - "Description": [ - "Savara" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "svs", - "Description": [ - "Savosavo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "svx", - "Description": [ - "Skalvian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swb", - "Description": [ - "Maore Comorian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swc", - "Description": [ - "Congo Swahili" - ], - "Added": "2009-07-29", - "Macrolanguage": "sw" - }, - { - "Type": "language", - "Subtag": "swf", - "Description": [ - "Sere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swg", - "Description": [ - "Swabian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swh", - "Description": [ - "Swahili (individual language)", - "Kiswahili" - ], - "Added": "2009-07-29", - "Macrolanguage": "sw" - }, - { - "Type": "language", - "Subtag": "swi", - "Description": [ - "Sui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swj", - "Description": [ - "Sira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swk", - "Description": [ - "Malawi Sena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swl", - "Description": [ - "Swedish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swm", - "Description": [ - "Samosa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swn", - "Description": [ - "Sawknah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swo", - "Description": [ - "Shanenawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swp", - "Description": [ - "Suau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swq", - "Description": [ - "Sharwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swr", - "Description": [ - "Saweru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sws", - "Description": [ - "Seluwasan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swt", - "Description": [ - "Sawila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swu", - "Description": [ - "Suwawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swv", - "Description": [ - "Shekhawati" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "sww", - "Description": [ - "Sowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swx", - "Description": [ - "Suruahá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "swy", - "Description": [ - "Sarua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxb", - "Description": [ - "Suba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxc", - "Description": [ - "Sicanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxe", - "Description": [ - "Sighu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxg", - "Description": [ - "Shuhi", - "Shixing" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxk", - "Description": [ - "Southern Kalapuya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxl", - "Description": [ - "Selian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxm", - "Description": [ - "Samre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxn", - "Description": [ - "Sangir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxo", - "Description": [ - "Sorothaptic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxr", - "Description": [ - "Saaroa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxs", - "Description": [ - "Sasaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxu", - "Description": [ - "Upper Saxon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sxw", - "Description": [ - "Saxwe Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sya", - "Description": [ - "Siang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syb", - "Description": [ - "Central Subanen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syc", - "Description": [ - "Classical Syriac" - ], - "Added": "2007-04-03" - }, - { - "Type": "language", - "Subtag": "syd", - "Description": [ - "Samoyedic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "syi", - "Description": [ - "Seki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syk", - "Description": [ - "Sukur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syl", - "Description": [ - "Sylheti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sym", - "Description": [ - "Maya Samo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syn", - "Description": [ - "Senaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syo", - "Description": [ - "Suoy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syr", - "Description": [ - "Syriac" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "sys", - "Description": [ - "Sinyar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syw", - "Description": [ - "Kagate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "syx", - "Description": [ - "Samay" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "syy", - "Description": [ - "Al-Sayyid Bedouin Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sza", - "Description": [ - "Semelai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szb", - "Description": [ - "Ngalum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szc", - "Description": [ - "Semaq Beri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szd", - "Description": [ - "Seru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "sze", - "Description": [ - "Seze" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szg", - "Description": [ - "Sengele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szl", - "Description": [ - "Silesian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szn", - "Description": [ - "Sula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szp", - "Description": [ - "Suabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szs", - "Description": [ - "Solomon Islands Sign Language" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "szv", - "Description": [ - "Isu (Fako Division)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szw", - "Description": [ - "Sawai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "szy", - "Description": [ - "Sakizaya" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "taa", - "Description": [ - "Lower Tanana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tab", - "Description": [ - "Tabassaran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tac", - "Description": [ - "Lowland Tarahumara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tad", - "Description": [ - "Tause" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tae", - "Description": [ - "Tariana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "taf", - "Description": [ - "Tapirapé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tag", - "Description": [ - "Tagoi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tai", - "Description": [ - "Tai languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "taj", - "Description": [ - "Eastern Tamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tak", - "Description": [ - "Tala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tal", - "Description": [ - "Tal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tan", - "Description": [ - "Tangale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tao", - "Description": [ - "Yami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tap", - "Description": [ - "Taabwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "taq", - "Description": [ - "Tamasheq" - ], - "Added": "2009-07-29", - "Macrolanguage": "tmh" - }, - { - "Type": "language", - "Subtag": "tar", - "Description": [ - "Central Tarahumara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tas", - "Description": [ - "Tay Boi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tau", - "Description": [ - "Upper Tanana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tav", - "Description": [ - "Tatuyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "taw", - "Description": [ - "Tai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tax", - "Description": [ - "Tamki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tay", - "Description": [ - "Atayal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "taz", - "Description": [ - "Tocho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tba", - "Description": [ - "Aikanã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbb", - "Description": [ - "Tapeba" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "tbc", - "Description": [ - "Takia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbd", - "Description": [ - "Kaki Ae" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbe", - "Description": [ - "Tanimbili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbf", - "Description": [ - "Mandara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbg", - "Description": [ - "North Tairora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbh", - "Description": [ - "Dharawal", - "Thurawal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbi", - "Description": [ - "Gaam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbj", - "Description": [ - "Tiang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbk", - "Description": [ - "Calamian Tagbanwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbl", - "Description": [ - "Tboli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbm", - "Description": [ - "Tagbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbn", - "Description": [ - "Barro Negro Tunebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbo", - "Description": [ - "Tawala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbp", - "Description": [ - "Taworta", - "Diebroud" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbq", - "Description": [ - "Tibeto-Burman languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "tbr", - "Description": [ - "Tumtum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbs", - "Description": [ - "Tanguat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbt", - "Description": [ - "Tembo (Kitembo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbu", - "Description": [ - "Tubar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbv", - "Description": [ - "Tobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbw", - "Description": [ - "Tagbanwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbx", - "Description": [ - "Kapin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tby", - "Description": [ - "Tabaru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tbz", - "Description": [ - "Ditammari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tca", - "Description": [ - "Ticuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcb", - "Description": [ - "Tanacross" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcc", - "Description": [ - "Datooga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcd", - "Description": [ - "Tafi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tce", - "Description": [ - "Southern Tutchone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcf", - "Description": [ - "Malinaltepec Me'phaa", - "Malinaltepec Tlapanec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcg", - "Description": [ - "Tamagario" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tch", - "Description": [ - "Turks And Caicos Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tci", - "Description": [ - "Wára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tck", - "Description": [ - "Tchitchege" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcl", - "Description": [ - "Taman (Myanmar)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcm", - "Description": [ - "Tanahmerah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcn", - "Description": [ - "Tichurong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tco", - "Description": [ - "Taungyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcp", - "Description": [ - "Tawr Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcq", - "Description": [ - "Kaiy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcs", - "Description": [ - "Torres Strait Creole", - "Yumplatok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tct", - "Description": [ - "T'en" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcu", - "Description": [ - "Southeastern Tarahumara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcw", - "Description": [ - "Tecpatlán Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcx", - "Description": [ - "Toda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcy", - "Description": [ - "Tulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tcz", - "Description": [ - "Thado Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tda", - "Description": [ - "Tagdal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdb", - "Description": [ - "Panchpargania" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdc", - "Description": [ - "Emberá-Tadó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdd", - "Description": [ - "Tai Nüa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tde", - "Description": [ - "Tiranige Diga Dogon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "tdf", - "Description": [ - "Talieng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdg", - "Description": [ - "Western Tamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdh", - "Description": [ - "Thulung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdi", - "Description": [ - "Tomadino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdj", - "Description": [ - "Tajio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdk", - "Description": [ - "Tambas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdl", - "Description": [ - "Sur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdm", - "Description": [ - "Taruma" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "tdn", - "Description": [ - "Tondano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdo", - "Description": [ - "Teme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdq", - "Description": [ - "Tita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdr", - "Description": [ - "Todrah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tds", - "Description": [ - "Doutai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdt", - "Description": [ - "Tetun Dili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdu", - "Description": [ - "Tempasuk Dusun" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "dtp" - }, - { - "Type": "language", - "Subtag": "tdv", - "Description": [ - "Toro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tdx", - "Description": [ - "Tandroy-Mahafaly Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "tdy", - "Description": [ - "Tadyawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tea", - "Description": [ - "Temiar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "teb", - "Description": [ - "Tetete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tec", - "Description": [ - "Terik" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "ted", - "Description": [ - "Tepo Krumen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tee", - "Description": [ - "Huehuetla Tepehua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tef", - "Description": [ - "Teressa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "teg", - "Description": [ - "Teke-Tege" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "teh", - "Description": [ - "Tehuelche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tei", - "Description": [ - "Torricelli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tek", - "Description": [ - "Ibali Teke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tem", - "Description": [ - "Timne" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "ten", - "Description": [ - "Tama (Colombia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "teo", - "Description": [ - "Teso" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tep", - "Description": [ - "Tepecano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "teq", - "Description": [ - "Temein" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ter", - "Description": [ - "Tereno" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tes", - "Description": [ - "Tengger" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tet", - "Description": [ - "Tetum" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "teu", - "Description": [ - "Soo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tev", - "Description": [ - "Teor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tew", - "Description": [ - "Tewa (USA)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tex", - "Description": [ - "Tennet" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tey", - "Description": [ - "Tulishi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tez", - "Description": [ - "Tetserret" - ], - "Added": "2018-03-08" - }, - { - "Type": "language", - "Subtag": "tfi", - "Description": [ - "Tofin Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tfn", - "Description": [ - "Tanaina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tfo", - "Description": [ - "Tefaro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tfr", - "Description": [ - "Teribe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tft", - "Description": [ - "Ternate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tga", - "Description": [ - "Sagalla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgb", - "Description": [ - "Tobilung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgc", - "Description": [ - "Tigak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgd", - "Description": [ - "Ciwogai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tge", - "Description": [ - "Eastern Gorkha Tamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgf", - "Description": [ - "Chalikha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgg", - "Description": [ - "Tangga" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see bjp, hrc, hrw" - ] - }, - { - "Type": "language", - "Subtag": "tgh", - "Description": [ - "Tobagonian Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgi", - "Description": [ - "Lawunuia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgj", - "Description": [ - "Tagin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "tgn", - "Description": [ - "Tandaganon" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "tgo", - "Description": [ - "Sudest" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgp", - "Description": [ - "Tangoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgq", - "Description": [ - "Tring" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgr", - "Description": [ - "Tareng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgs", - "Description": [ - "Nume" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgt", - "Description": [ - "Central Tagbanwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgu", - "Description": [ - "Tanggu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgv", - "Description": [ - "Tingui-Boto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgw", - "Description": [ - "Tagwana Senoufo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgx", - "Description": [ - "Tagish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgy", - "Description": [ - "Togoyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tgz", - "Description": [ - "Tagalaka" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "thc", - "Description": [ - "Tai Hang Tong" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "tpo" - }, - { - "Type": "language", - "Subtag": "thd", - "Description": [ - "Kuuk Thaayorre", - "Thayore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "the", - "Description": [ - "Chitwania Tharu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thf", - "Description": [ - "Thangmi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thh", - "Description": [ - "Northern Tarahumara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thi", - "Description": [ - "Tai Long" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thk", - "Description": [ - "Tharaka", - "Kitharaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thl", - "Description": [ - "Dangaura Tharu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thm", - "Description": [ - "Aheu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thn", - "Description": [ - "Thachanadan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thp", - "Description": [ - "Thompson" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thq", - "Description": [ - "Kochila Tharu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thr", - "Description": [ - "Rana Tharu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ths", - "Description": [ - "Thakali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tht", - "Description": [ - "Tahltan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thu", - "Description": [ - "Thuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thv", - "Description": [ - "Tahaggart Tamahaq" - ], - "Added": "2009-07-29", - "Macrolanguage": "tmh" - }, - { - "Type": "language", - "Subtag": "thw", - "Description": [ - "Thudam" - ], - "Added": "2009-07-29", - "Deprecated": "2020-06-08", - "Preferred-Value": "ola" - }, - { - "Type": "language", - "Subtag": "thx", - "Description": [ - "The" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "oyb" - }, - { - "Type": "language", - "Subtag": "thy", - "Description": [ - "Tha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "thz", - "Description": [ - "Tayart Tamajeq" - ], - "Added": "2009-07-29", - "Macrolanguage": "tmh" - }, - { - "Type": "language", - "Subtag": "tia", - "Description": [ - "Tidikelt Tamazight" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tic", - "Description": [ - "Tira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tid", - "Description": [ - "Tidong" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Comments": [ - "see itd, ntd" - ] - }, - { - "Type": "language", - "Subtag": "tie", - "Description": [ - "Tingal" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Preferred-Value": "ras" - }, - { - "Type": "language", - "Subtag": "tif", - "Description": [ - "Tifal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tig", - "Description": [ - "Tigre" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tih", - "Description": [ - "Timugon Murut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tii", - "Description": [ - "Tiene" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tij", - "Description": [ - "Tilung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tik", - "Description": [ - "Tikar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "til", - "Description": [ - "Tillamook" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tim", - "Description": [ - "Timbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tin", - "Description": [ - "Tindi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tio", - "Description": [ - "Teop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tip", - "Description": [ - "Trimuris" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tiq", - "Description": [ - "Tiéfo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tis", - "Description": [ - "Masadiit Itneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tit", - "Description": [ - "Tinigua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tiu", - "Description": [ - "Adasen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tiv", - "Description": [ - "Tiv" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tiw", - "Description": [ - "Tiwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tix", - "Description": [ - "Southern Tiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tiy", - "Description": [ - "Tiruray" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tiz", - "Description": [ - "Tai Hongjin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tja", - "Description": [ - "Tajuasohn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjg", - "Description": [ - "Tunjung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tji", - "Description": [ - "Northern Tujia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjj", - "Description": [ - "Tjungundji" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "tjl", - "Description": [ - "Tai Laing" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "tjm", - "Description": [ - "Timucua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjn", - "Description": [ - "Tonjon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjo", - "Description": [ - "Temacine Tamazight" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjp", - "Description": [ - "Tjupany" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "tjs", - "Description": [ - "Southern Tujia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tju", - "Description": [ - "Tjurruru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tjw", - "Description": [ - "Djabwurrung" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "tka", - "Description": [ - "Truká" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkb", - "Description": [ - "Buksa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkd", - "Description": [ - "Tukudede" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tke", - "Description": [ - "Takwane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkf", - "Description": [ - "Tukumanféd" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkg", - "Description": [ - "Tesaka Malagasy" - ], - "Added": "2011-08-16", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "tkk", - "Description": [ - "Takpa" - ], - "Added": "2009-07-29", - "Deprecated": "2011-08-16", - "Preferred-Value": "twm" - }, - { - "Type": "language", - "Subtag": "tkl", - "Description": [ - "Tokelau" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tkm", - "Description": [ - "Takelma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkn", - "Description": [ - "Toku-No-Shima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkp", - "Description": [ - "Tikopia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkq", - "Description": [ - "Tee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkr", - "Description": [ - "Tsakhur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tks", - "Description": [ - "Takestani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkt", - "Description": [ - "Kathoriya Tharu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tku", - "Description": [ - "Upper Necaxa Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkv", - "Description": [ - "Mur Pano" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "tkw", - "Description": [ - "Teanu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkx", - "Description": [ - "Tangko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tkz", - "Description": [ - "Takua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tla", - "Description": [ - "Southwestern Tepehuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlb", - "Description": [ - "Tobelo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlc", - "Description": [ - "Yecuatla Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tld", - "Description": [ - "Talaud" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlf", - "Description": [ - "Telefol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlg", - "Description": [ - "Tofanma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlh", - "Description": [ - "Klingon", - "tlhIngan Hol" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tli", - "Description": [ - "Tlingit" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tlj", - "Description": [ - "Talinga-Bwisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlk", - "Description": [ - "Taloki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tll", - "Description": [ - "Tetela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlm", - "Description": [ - "Tolomako" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tln", - "Description": [ - "Talondo'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlo", - "Description": [ - "Talodi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlp", - "Description": [ - "Filomena Mata-Coahuitlán Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlq", - "Description": [ - "Tai Loi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlr", - "Description": [ - "Talise" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tls", - "Description": [ - "Tambotalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlt", - "Description": [ - "Sou Nama", - "Teluti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlu", - "Description": [ - "Tulehu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlv", - "Description": [ - "Taliabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tlw", - "Description": [ - "South Wemale" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "weo" - }, - { - "Type": "language", - "Subtag": "tlx", - "Description": [ - "Khehek" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tly", - "Description": [ - "Talysh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tma", - "Description": [ - "Tama (Chad)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmb", - "Description": [ - "Katbol", - "Avava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmc", - "Description": [ - "Tumak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmd", - "Description": [ - "Haruai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tme", - "Description": [ - "Tremembé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmf", - "Description": [ - "Toba-Maskoy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmg", - "Description": [ - "Ternateño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmh", - "Description": [ - "Tamashek" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "tmi", - "Description": [ - "Tutuba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmj", - "Description": [ - "Samarokena" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmk", - "Description": [ - "Northwestern Tamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tml", - "Description": [ - "Tamnim Citak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmm", - "Description": [ - "Tai Thanh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmn", - "Description": [ - "Taman (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmo", - "Description": [ - "Temoq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmp", - "Description": [ - "Tai Mène" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "tyj" - }, - { - "Type": "language", - "Subtag": "tmq", - "Description": [ - "Tumleo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmr", - "Description": [ - "Jewish Babylonian Aramaic (ca. 200-1200 CE)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tms", - "Description": [ - "Tima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmt", - "Description": [ - "Tasmate" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmu", - "Description": [ - "Iau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmv", - "Description": [ - "Tembo (Motembo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmw", - "Description": [ - "Temuan" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "tmy", - "Description": [ - "Tami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tmz", - "Description": [ - "Tamanaku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tna", - "Description": [ - "Tacana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnb", - "Description": [ - "Western Tunebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnc", - "Description": [ - "Tanimuca-Retuarã" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnd", - "Description": [ - "Angosturas Tunebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tne", - "Description": [ - "Tinoc Kallahan" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "kak" - }, - { - "Type": "language", - "Subtag": "tnf", - "Description": [ - "Tangshewi" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Preferred-Value": "prs" - }, - { - "Type": "language", - "Subtag": "tng", - "Description": [ - "Tobanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnh", - "Description": [ - "Maiani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tni", - "Description": [ - "Tandia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnk", - "Description": [ - "Kwamera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnl", - "Description": [ - "Lenakel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnm", - "Description": [ - "Tabla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnn", - "Description": [ - "North Tanna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tno", - "Description": [ - "Toromono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnp", - "Description": [ - "Whitesands" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnq", - "Description": [ - "Taino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnr", - "Description": [ - "Ménik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tns", - "Description": [ - "Tenis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnt", - "Description": [ - "Tontemboan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnu", - "Description": [ - "Tay Khang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnv", - "Description": [ - "Tangchangya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnw", - "Description": [ - "Tonsawang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnx", - "Description": [ - "Tanema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tny", - "Description": [ - "Tongwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tnz", - "Description": [ - "Ten'edn" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tob", - "Description": [ - "Toba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toc", - "Description": [ - "Coyutla Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tod", - "Description": [ - "Toma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toe", - "Description": [ - "Tomedes" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "tof", - "Description": [ - "Gizrra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tog", - "Description": [ - "Tonga (Nyasa)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "toh", - "Description": [ - "Gitonga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toi", - "Description": [ - "Tonga (Zambia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toj", - "Description": [ - "Tojolabal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tok", - "Description": [ - "Toki Pona" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "tol", - "Description": [ - "Tolowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tom", - "Description": [ - "Tombulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "too", - "Description": [ - "Xicotepec De Juárez Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "top", - "Description": [ - "Papantla Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toq", - "Description": [ - "Toposa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tor", - "Description": [ - "Togbo-Vara Banda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tos", - "Description": [ - "Highland Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tou", - "Description": [ - "Tho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tov", - "Description": [ - "Upper Taromi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tow", - "Description": [ - "Jemez" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tox", - "Description": [ - "Tobian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toy", - "Description": [ - "Topoiyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "toz", - "Description": [ - "To" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpa", - "Description": [ - "Taupota" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpc", - "Description": [ - "Azoyú Me'phaa", - "Azoyú Tlapanec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpe", - "Description": [ - "Tippera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpf", - "Description": [ - "Tarpia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpg", - "Description": [ - "Kula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpi", - "Description": [ - "Tok Pisin" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tpj", - "Description": [ - "Tapieté" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpk", - "Description": [ - "Tupinikin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpl", - "Description": [ - "Tlacoapa Me'phaa", - "Tlacoapa Tlapanec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpm", - "Description": [ - "Tampulma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpn", - "Description": [ - "Tupinambá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpo", - "Description": [ - "Tai Pao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpp", - "Description": [ - "Pisaflores Tepehua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpq", - "Description": [ - "Tukpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpr", - "Description": [ - "Tuparí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpt", - "Description": [ - "Tlachichilco Tepehua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpu", - "Description": [ - "Tampuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpv", - "Description": [ - "Tanapag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpw", - "Description": [ - "Tupí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpx", - "Description": [ - "Acatepec Me'phaa", - "Acatepec Tlapanec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpy", - "Description": [ - "Trumai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tpz", - "Description": [ - "Tinputz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqb", - "Description": [ - "Tembé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tql", - "Description": [ - "Lehali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqm", - "Description": [ - "Turumsa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqn", - "Description": [ - "Tenino" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqo", - "Description": [ - "Toaripi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqp", - "Description": [ - "Tomoip" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqq", - "Description": [ - "Tunni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqr", - "Description": [ - "Torona" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqt", - "Description": [ - "Western Totonac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqu", - "Description": [ - "Touo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tqw", - "Description": [ - "Tonkawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tra", - "Description": [ - "Tirahi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trb", - "Description": [ - "Terebu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trc", - "Description": [ - "Copala Triqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trd", - "Description": [ - "Turi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tre", - "Description": [ - "East Tarangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trf", - "Description": [ - "Trinidadian Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trg", - "Description": [ - "Lishán Didán" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trh", - "Description": [ - "Turaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tri", - "Description": [ - "Trió" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trj", - "Description": [ - "Toram" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trk", - "Description": [ - "Turkic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "trl", - "Description": [ - "Traveller Scottish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trm", - "Description": [ - "Tregami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trn", - "Description": [ - "Trinitario" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tro", - "Description": [ - "Tarao Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trp", - "Description": [ - "Kok Borok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trq", - "Description": [ - "San Martín Itunyoso Triqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trr", - "Description": [ - "Taushiro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trs", - "Description": [ - "Chicahuaxtla Triqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trt", - "Description": [ - "Tunggare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tru", - "Description": [ - "Turoyo", - "Surayt" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trv", - "Description": [ - "Sediq", - "Seediq", - "Taroko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trw", - "Description": [ - "Torwali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trx", - "Description": [ - "Tringgus-Sembaan Bidayuh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "try", - "Description": [ - "Turung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "trz", - "Description": [ - "Torá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsa", - "Description": [ - "Tsaangi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsb", - "Description": [ - "Tsamai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsc", - "Description": [ - "Tswa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsd", - "Description": [ - "Tsakonian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tse", - "Description": [ - "Tunisian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsf", - "Description": [ - "Southwestern Tamang" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "taj" - }, - { - "Type": "language", - "Subtag": "tsg", - "Description": [ - "Tausug" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsh", - "Description": [ - "Tsuvan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsi", - "Description": [ - "Tsimshian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tsj", - "Description": [ - "Tshangla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsk", - "Description": [ - "Tseku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsl", - "Description": [ - "Ts'ün-Lao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsm", - "Description": [ - "Turkish Sign Language", - "Türk İşaret Dili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsp", - "Description": [ - "Northern Toussian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsq", - "Description": [ - "Thai Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsr", - "Description": [ - "Akei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tss", - "Description": [ - "Taiwan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tst", - "Description": [ - "Tondi Songway Kiini" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "tsu", - "Description": [ - "Tsou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsv", - "Description": [ - "Tsogo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsw", - "Description": [ - "Tsishingini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsx", - "Description": [ - "Mubami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsy", - "Description": [ - "Tebul Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tsz", - "Description": [ - "Purepecha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tta", - "Description": [ - "Tutelo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttb", - "Description": [ - "Gaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttc", - "Description": [ - "Tektiteko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttd", - "Description": [ - "Tauade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tte", - "Description": [ - "Bwanabwana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttf", - "Description": [ - "Tuotomb" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttg", - "Description": [ - "Tutong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tth", - "Description": [ - "Upper Ta'oih" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tti", - "Description": [ - "Tobati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttj", - "Description": [ - "Tooro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttk", - "Description": [ - "Totoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttl", - "Description": [ - "Totela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttm", - "Description": [ - "Northern Tutchone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttn", - "Description": [ - "Towei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tto", - "Description": [ - "Lower Ta'oih" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttp", - "Description": [ - "Tombelala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttq", - "Description": [ - "Tawallammat Tamajaq" - ], - "Added": "2009-07-29", - "Macrolanguage": "tmh" - }, - { - "Type": "language", - "Subtag": "ttr", - "Description": [ - "Tera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tts", - "Description": [ - "Northeastern Thai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttt", - "Description": [ - "Muslim Tat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttu", - "Description": [ - "Torau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttv", - "Description": [ - "Titan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttw", - "Description": [ - "Long Wat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tty", - "Description": [ - "Sikaritai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ttz", - "Description": [ - "Tsum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tua", - "Description": [ - "Wiarumus" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tub", - "Description": [ - "Tübatulabal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuc", - "Description": [ - "Mutu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tud", - "Description": [ - "Tuxá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tue", - "Description": [ - "Tuyuca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuf", - "Description": [ - "Central Tunebo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tug", - "Description": [ - "Tunia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuh", - "Description": [ - "Taulil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tui", - "Description": [ - "Tupuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuj", - "Description": [ - "Tugutil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tul", - "Description": [ - "Tula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tum", - "Description": [ - "Tumbuka" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tun", - "Description": [ - "Tunica" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuo", - "Description": [ - "Tucano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tup", - "Description": [ - "Tupi languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "tuq", - "Description": [ - "Tedaga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tus", - "Description": [ - "Tuscarora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tut", - "Description": [ - "Altaic languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "tuu", - "Description": [ - "Tututni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuv", - "Description": [ - "Turkana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuw", - "Description": [ - "Tungus languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "tux", - "Description": [ - "Tuxináwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tuy", - "Description": [ - "Tugen" - ], - "Added": "2009-07-29", - "Macrolanguage": "kln" - }, - { - "Type": "language", - "Subtag": "tuz", - "Description": [ - "Turka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tva", - "Description": [ - "Vaghua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvd", - "Description": [ - "Tsuvadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tve", - "Description": [ - "Te'un" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvk", - "Description": [ - "Southeast Ambrym" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvl", - "Description": [ - "Tuvalu" - ], - "Added": "2005-10-16", - "Suppress-Script": "Latn" - }, - { - "Type": "language", - "Subtag": "tvm", - "Description": [ - "Tela-Masbuar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvn", - "Description": [ - "Tavoyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvo", - "Description": [ - "Tidore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvs", - "Description": [ - "Taveta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvt", - "Description": [ - "Tutsa Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvu", - "Description": [ - "Tunen" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "tvw", - "Description": [ - "Sedoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tvx", - "Description": [ - "Taivoan" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "tvy", - "Description": [ - "Timor Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twa", - "Description": [ - "Twana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twb", - "Description": [ - "Western Tawbuid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twc", - "Description": [ - "Teshenawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twd", - "Description": [ - "Twents" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twe", - "Description": [ - "Tewa (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twf", - "Description": [ - "Northern Tiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twg", - "Description": [ - "Tereweng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twh", - "Description": [ - "Tai Dón" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twl", - "Description": [ - "Tawara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twm", - "Description": [ - "Tawang Monpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twn", - "Description": [ - "Twendi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "two", - "Description": [ - "Tswapong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twp", - "Description": [ - "Ere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twq", - "Description": [ - "Tasawaq" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twr", - "Description": [ - "Southwestern Tarahumara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twt", - "Description": [ - "Turiwára" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twu", - "Description": [ - "Termanu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tww", - "Description": [ - "Tuwari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twx", - "Description": [ - "Tewe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "twy", - "Description": [ - "Tawoyan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txa", - "Description": [ - "Tombonuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txb", - "Description": [ - "Tokharian B" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txc", - "Description": [ - "Tsetsaut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txe", - "Description": [ - "Totoli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txg", - "Description": [ - "Tangut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txh", - "Description": [ - "Thracian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txi", - "Description": [ - "Ikpeng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txj", - "Description": [ - "Tarjumo" - ], - "Added": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "txm", - "Description": [ - "Tomini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txn", - "Description": [ - "West Tarangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txo", - "Description": [ - "Toto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txq", - "Description": [ - "Tii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txr", - "Description": [ - "Tartessian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txs", - "Description": [ - "Tonsea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txt", - "Description": [ - "Citak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txu", - "Description": [ - "Kayapó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txx", - "Description": [ - "Tatana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "txy", - "Description": [ - "Tanosy Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "tya", - "Description": [ - "Tauya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tye", - "Description": [ - "Kyanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyh", - "Description": [ - "O'du" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyi", - "Description": [ - "Teke-Tsaayi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyj", - "Description": [ - "Tai Do", - "Tai Yo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyl", - "Description": [ - "Thu Lao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyn", - "Description": [ - "Kombai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "typ", - "Description": [ - "Thaypan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyr", - "Description": [ - "Tai Daeng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tys", - "Description": [ - "Tày Sa Pa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyt", - "Description": [ - "Tày Tac" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyu", - "Description": [ - "Kua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyv", - "Description": [ - "Tuvinian" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "tyx", - "Description": [ - "Teke-Tyee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tyy", - "Description": [ - "Tiyaa" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "tyz", - "Description": [ - "Tày" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tza", - "Description": [ - "Tanzanian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzh", - "Description": [ - "Tzeltal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzj", - "Description": [ - "Tz'utujil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzl", - "Description": [ - "Talossan" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "tzm", - "Description": [ - "Central Atlas Tamazight" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzn", - "Description": [ - "Tugun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzo", - "Description": [ - "Tzotzil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "tzx", - "Description": [ - "Tabriak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uam", - "Description": [ - "Uamué" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uan", - "Description": [ - "Kuan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uar", - "Description": [ - "Tairuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uba", - "Description": [ - "Ubang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ubi", - "Description": [ - "Ubi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ubl", - "Description": [ - "Buhi'non Bikol" - ], - "Added": "2010-03-11", - "Macrolanguage": "bik" - }, - { - "Type": "language", - "Subtag": "ubr", - "Description": [ - "Ubir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ubu", - "Description": [ - "Umbu-Ungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uby", - "Description": [ - "Ubykh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uda", - "Description": [ - "Uda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ude", - "Description": [ - "Udihe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "udg", - "Description": [ - "Muduga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "udi", - "Description": [ - "Udi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "udj", - "Description": [ - "Ujir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "udl", - "Description": [ - "Wuzlam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "udm", - "Description": [ - "Udmurt" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "udu", - "Description": [ - "Uduk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ues", - "Description": [ - "Kioko" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ufi", - "Description": [ - "Ufim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uga", - "Description": [ - "Ugaritic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "ugb", - "Description": [ - "Kuku-Ugbanh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uge", - "Description": [ - "Ughele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ugh", - "Description": [ - "Kubachi" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "ugn", - "Description": [ - "Ugandan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ugo", - "Description": [ - "Ugong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ugy", - "Description": [ - "Uruguayan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uha", - "Description": [ - "Uhami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uhn", - "Description": [ - "Damal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uis", - "Description": [ - "Uisai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uiv", - "Description": [ - "Iyive" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uji", - "Description": [ - "Tanjijili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uka", - "Description": [ - "Kaburi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ukg", - "Description": [ - "Ukuriguma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ukh", - "Description": [ - "Ukhwejo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uki", - "Description": [ - "Kui (India)" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ukk", - "Description": [ - "Muak Sa-aak" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "ukl", - "Description": [ - "Ukrainian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ukp", - "Description": [ - "Ukpe-Bayobiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ukq", - "Description": [ - "Ukwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uks", - "Description": [ - "Urubú-Kaapor Sign Language", - "Kaapor Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uku", - "Description": [ - "Ukue" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ukv", - "Description": [ - "Kuku" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "ukw", - "Description": [ - "Ukwuani-Aboh-Ndoni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uky", - "Description": [ - "Kuuk-Yak" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ula", - "Description": [ - "Fungwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulb", - "Description": [ - "Ulukwumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulc", - "Description": [ - "Ulch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ule", - "Description": [ - "Lule" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ulf", - "Description": [ - "Usku", - "Afra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uli", - "Description": [ - "Ulithian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulk", - "Description": [ - "Meriam Mir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ull", - "Description": [ - "Ullatan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulm", - "Description": [ - "Ulumanda'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uln", - "Description": [ - "Unserdeutsch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulu", - "Description": [ - "Uma' Lung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ulw", - "Description": [ - "Ulwa" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "uma", - "Description": [ - "Umatilla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umb", - "Description": [ - "Umbundu" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "umc", - "Description": [ - "Marrucinian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umd", - "Description": [ - "Umbindhamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umg", - "Description": [ - "Morrobalama", - "Umbuygamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umi", - "Description": [ - "Ukit" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umm", - "Description": [ - "Umon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umn", - "Description": [ - "Makyan Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umo", - "Description": [ - "Umotína" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ump", - "Description": [ - "Umpila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umr", - "Description": [ - "Umbugarla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ums", - "Description": [ - "Pendau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "umu", - "Description": [ - "Munsee" - ], - "Added": "2009-07-29", - "Macrolanguage": "del" - }, - { - "Type": "language", - "Subtag": "una", - "Description": [ - "North Watut" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "und", - "Description": [ - "Undetermined" - ], - "Added": "2005-10-16", - "Scope": "special" - }, - { - "Type": "language", - "Subtag": "une", - "Description": [ - "Uneme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ung", - "Description": [ - "Ngarinyin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uni", - "Description": [ - "Uni" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "unk", - "Description": [ - "Enawené-Nawé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "unm", - "Description": [ - "Unami" - ], - "Added": "2009-07-29", - "Macrolanguage": "del" - }, - { - "Type": "language", - "Subtag": "unn", - "Description": [ - "Kurnai" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "unp", - "Description": [ - "Worora" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see wro, xgu" - ] - }, - { - "Type": "language", - "Subtag": "unr", - "Description": [ - "Mundari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "unu", - "Description": [ - "Unubahe" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "unx", - "Description": [ - "Munda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "unz", - "Description": [ - "Unde Kaili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uok", - "Description": [ - "Uokha" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "ema" - }, - { - "Type": "language", - "Subtag": "uon", - "Description": [ - "Kulon" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "upi", - "Description": [ - "Umeda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "upv", - "Description": [ - "Uripiv-Wala-Rano-Atchin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ura", - "Description": [ - "Urarina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urb", - "Description": [ - "Urubú-Kaapor", - "Kaapor" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urc", - "Description": [ - "Urningangg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ure", - "Description": [ - "Uru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urf", - "Description": [ - "Uradhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urg", - "Description": [ - "Urigina" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urh", - "Description": [ - "Urhobo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uri", - "Description": [ - "Urim" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urj", - "Description": [ - "Uralic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "urk", - "Description": [ - "Urak Lawoi'" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "url", - "Description": [ - "Urali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urm", - "Description": [ - "Urapmin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urn", - "Description": [ - "Uruangnirin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uro", - "Description": [ - "Ura (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urp", - "Description": [ - "Uru-Pa-In" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urr", - "Description": [ - "Lehalurup", - "Löyöp" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urt", - "Description": [ - "Urat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uru", - "Description": [ - "Urumi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urv", - "Description": [ - "Uruava" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urw", - "Description": [ - "Sop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urx", - "Description": [ - "Urimo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ury", - "Description": [ - "Orya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "urz", - "Description": [ - "Uru-Eu-Wau-Wau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "usa", - "Description": [ - "Usarufa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ush", - "Description": [ - "Ushojo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "usi", - "Description": [ - "Usui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "usk", - "Description": [ - "Usaghade" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "usp", - "Description": [ - "Uspanteco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uss", - "Description": [ - "us-Saare" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "usu", - "Description": [ - "Uya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uta", - "Description": [ - "Otank" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ute", - "Description": [ - "Ute-Southern Paiute" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uth", - "Description": [ - "ut-Hun" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "utp", - "Description": [ - "Amba (Solomon Islands)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "utr", - "Description": [ - "Etulo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "utu", - "Description": [ - "Utu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uum", - "Description": [ - "Urum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uun", - "Description": [ - "Kulon-Pazeh" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Comments": [ - "see pzh, uon" - ] - }, - { - "Type": "language", - "Subtag": "uur", - "Description": [ - "Ura (Vanuatu)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uuu", - "Description": [ - "U" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uve", - "Description": [ - "West Uvean", - "Fagauvea" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uvh", - "Description": [ - "Uri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uvl", - "Description": [ - "Lote" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uwa", - "Description": [ - "Kuku-Uwanh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uya", - "Description": [ - "Doko-Uyanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "uzn", - "Description": [ - "Northern Uzbek" - ], - "Added": "2009-07-29", - "Macrolanguage": "uz" - }, - { - "Type": "language", - "Subtag": "uzs", - "Description": [ - "Southern Uzbek" - ], - "Added": "2009-07-29", - "Macrolanguage": "uz" - }, - { - "Type": "language", - "Subtag": "vaa", - "Description": [ - "Vaagri Booli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vae", - "Description": [ - "Vale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vaf", - "Description": [ - "Vafsi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vag", - "Description": [ - "Vagla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vah", - "Description": [ - "Varhadi-Nagpuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vai", - "Description": [ - "Vai" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "vaj", - "Description": [ - "Sekele", - "Northwestern ǃKung", - "Vasekele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "val", - "Description": [ - "Vehes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vam", - "Description": [ - "Vanimo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "van", - "Description": [ - "Valman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vao", - "Description": [ - "Vao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vap", - "Description": [ - "Vaiphei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "var", - "Description": [ - "Huarijio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vas", - "Description": [ - "Vasavi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vau", - "Description": [ - "Vanuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vav", - "Description": [ - "Varli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vay", - "Description": [ - "Wayu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vbb", - "Description": [ - "Southeast Babar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vbk", - "Description": [ - "Southwestern Bontok" - ], - "Added": "2010-03-11", - "Macrolanguage": "bnc" - }, - { - "Type": "language", - "Subtag": "vec", - "Description": [ - "Venetian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ved", - "Description": [ - "Veddah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vel", - "Description": [ - "Veluws" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vem", - "Description": [ - "Vemgo-Mabas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "veo", - "Description": [ - "Ventureño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vep", - "Description": [ - "Veps" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ver", - "Description": [ - "Mom Jango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vgr", - "Description": [ - "Vaghri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vgt", - "Description": [ - "Vlaamse Gebarentaal", - "Flemish Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vic", - "Description": [ - "Virgin Islands Creole English" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vid", - "Description": [ - "Vidunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vif", - "Description": [ - "Vili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vig", - "Description": [ - "Viemo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vil", - "Description": [ - "Vilela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vin", - "Description": [ - "Vinza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vis", - "Description": [ - "Vishavan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vit", - "Description": [ - "Viti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "viv", - "Description": [ - "Iduna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vka", - "Description": [ - "Kariyarra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vki", - "Description": [ - "Ija-Zuba" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see vkn, vkz" - ] - }, - { - "Type": "language", - "Subtag": "vkj", - "Description": [ - "Kujarge" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkk", - "Description": [ - "Kaur" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "vkl", - "Description": [ - "Kulisusu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkm", - "Description": [ - "Kamakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkn", - "Description": [ - "Koro Nulu" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "vko", - "Description": [ - "Kodeoha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkp", - "Description": [ - "Korlai Creole Portuguese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkt", - "Description": [ - "Tenggarong Kutai Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "vku", - "Description": [ - "Kurrama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vkz", - "Description": [ - "Koro Zuba" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "vlp", - "Description": [ - "Valpei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vls", - "Description": [ - "Vlaams" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vma", - "Description": [ - "Martuyhunira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmb", - "Description": [ - "Barbaram" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmc", - "Description": [ - "Juxtlahuaca Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmd", - "Description": [ - "Mudu Koraga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vme", - "Description": [ - "East Masela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmf", - "Description": [ - "Mainfränkisch" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmg", - "Description": [ - "Lungalunga" - ], - "Added": "2009-07-29", - "Comments": [ - "see also bxf" - ] - }, - { - "Type": "language", - "Subtag": "vmh", - "Description": [ - "Maraghei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmi", - "Description": [ - "Miwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmj", - "Description": [ - "Ixtayutla Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmk", - "Description": [ - "Makhuwa-Shirima" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vml", - "Description": [ - "Malgana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmm", - "Description": [ - "Mitlatongo Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmp", - "Description": [ - "Soyaltepec Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmq", - "Description": [ - "Soyaltepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmr", - "Description": [ - "Marenje" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vms", - "Description": [ - "Moksela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmu", - "Description": [ - "Muluridyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmv", - "Description": [ - "Valley Maidu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmw", - "Description": [ - "Makhuwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmx", - "Description": [ - "Tamazola Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmy", - "Description": [ - "Ayautla Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vmz", - "Description": [ - "Mazatlán Mazatec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vnk", - "Description": [ - "Vano", - "Lovono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vnm", - "Description": [ - "Vinmavis", - "Neve'ei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vnp", - "Description": [ - "Vunapu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vor", - "Description": [ - "Voro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vot", - "Description": [ - "Votic" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "vra", - "Description": [ - "Vera'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vro", - "Description": [ - "Võro" - ], - "Added": "2009-07-29", - "Macrolanguage": "et" - }, - { - "Type": "language", - "Subtag": "vrs", - "Description": [ - "Varisi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vrt", - "Description": [ - "Burmbar", - "Banam Bay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vsi", - "Description": [ - "Moldova Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vsl", - "Description": [ - "Venezuelan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vsv", - "Description": [ - "Valencian Sign Language", - "Llengua de signes valenciana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vto", - "Description": [ - "Vitou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vum", - "Description": [ - "Vumbu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vun", - "Description": [ - "Vunjo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vut", - "Description": [ - "Vute" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "vwa", - "Description": [ - "Awa (China)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waa", - "Description": [ - "Walla Walla" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wab", - "Description": [ - "Wab" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wac", - "Description": [ - "Wasco-Wishram" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wad", - "Description": [ - "Wamesa", - "Wondama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wae", - "Description": [ - "Walser" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waf", - "Description": [ - "Wakoná" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wag", - "Description": [ - "Wa'ema" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wah", - "Description": [ - "Watubela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wai", - "Description": [ - "Wares" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waj", - "Description": [ - "Waffa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wak", - "Description": [ - "Wakashan languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "wal", - "Description": [ - "Wolaytta", - "Wolaitta" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "wam", - "Description": [ - "Wampanoag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wan", - "Description": [ - "Wan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wao", - "Description": [ - "Wappo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wap", - "Description": [ - "Wapishana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waq", - "Description": [ - "Wagiman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "war", - "Description": [ - "Waray (Philippines)" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "was", - "Description": [ - "Washo" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "wat", - "Description": [ - "Kaninuwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wau", - "Description": [ - "Waurá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wav", - "Description": [ - "Waka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waw", - "Description": [ - "Waiwai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wax", - "Description": [ - "Watam", - "Marangis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "way", - "Description": [ - "Wayana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "waz", - "Description": [ - "Wampur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wba", - "Description": [ - "Warao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbb", - "Description": [ - "Wabo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbe", - "Description": [ - "Waritai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbf", - "Description": [ - "Wara" - ], - "Added": "2009-07-29", - "Comments": [ - "see also pnl" - ] - }, - { - "Type": "language", - "Subtag": "wbh", - "Description": [ - "Wanda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbi", - "Description": [ - "Vwanji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbj", - "Description": [ - "Alagwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbk", - "Description": [ - "Waigali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbl", - "Description": [ - "Wakhi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbm", - "Description": [ - "Wa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbp", - "Description": [ - "Warlpiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbq", - "Description": [ - "Waddar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbr", - "Description": [ - "Wagdi" - ], - "Added": "2009-07-29", - "Macrolanguage": "raj" - }, - { - "Type": "language", - "Subtag": "wbs", - "Description": [ - "West Bengal Sign Language" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "wbt", - "Description": [ - "Warnman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbv", - "Description": [ - "Wajarri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wbw", - "Description": [ - "Woi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wca", - "Description": [ - "Yanomámi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wci", - "Description": [ - "Waci Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wdd", - "Description": [ - "Wandji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wdg", - "Description": [ - "Wadaginam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wdj", - "Description": [ - "Wadjiginy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wdk", - "Description": [ - "Wadikali" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wdt", - "Description": [ - "Wendat" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "wdu", - "Description": [ - "Wadjigu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wdy", - "Description": [ - "Wadjabangayi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wea", - "Description": [ - "Wewaw" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wec", - "Description": [ - "Wè Western" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wed", - "Description": [ - "Wedau" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "weg", - "Description": [ - "Wergaia" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "weh", - "Description": [ - "Weh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wei", - "Description": [ - "Kiunum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wem", - "Description": [ - "Weme Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wen", - "Description": [ - "Sorbian languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "weo", - "Description": [ - "Wemale" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wep", - "Description": [ - "Westphalien" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wer", - "Description": [ - "Weri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wes", - "Description": [ - "Cameroon Pidgin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wet", - "Description": [ - "Perai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "weu", - "Description": [ - "Rawngtu Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wew", - "Description": [ - "Wejewa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wfg", - "Description": [ - "Yafi", - "Zorop" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wga", - "Description": [ - "Wagaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wgb", - "Description": [ - "Wagawaga" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "wgg", - "Description": [ - "Wangkangurru", - "Wangganguru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wgi", - "Description": [ - "Wahgi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wgo", - "Description": [ - "Waigeo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wgu", - "Description": [ - "Wirangu" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "wgw", - "Description": [ - "Wagawaga" - ], - "Added": "2009-07-29", - "Deprecated": "2010-03-11", - "Comments": [ - "see wgb, ylb" - ] - }, - { - "Type": "language", - "Subtag": "wgy", - "Description": [ - "Warrgamay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wha", - "Description": [ - "Sou Upaa", - "Manusela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "whg", - "Description": [ - "North Wahgi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "whk", - "Description": [ - "Wahau Kenyah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "whu", - "Description": [ - "Wahau Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wib", - "Description": [ - "Southern Toussian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wic", - "Description": [ - "Wichita" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wie", - "Description": [ - "Wik-Epa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wif", - "Description": [ - "Wik-Keyangan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wig", - "Description": [ - "Wik Ngathan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wih", - "Description": [ - "Wik-Me'anha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wii", - "Description": [ - "Minidien" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wij", - "Description": [ - "Wik-Iiyanh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wik", - "Description": [ - "Wikalkan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wil", - "Description": [ - "Wilawila" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wim", - "Description": [ - "Wik-Mungkan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "win", - "Description": [ - "Ho-Chunk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wir", - "Description": [ - "Wiraféd" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wit", - "Description": [ - "Wintu" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see nol, pwi, wnw" - ] - }, - { - "Type": "language", - "Subtag": "wiu", - "Description": [ - "Wiru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wiv", - "Description": [ - "Vitu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wiw", - "Description": [ - "Wirangu" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see nwo, wgu" - ] - }, - { - "Type": "language", - "Subtag": "wiy", - "Description": [ - "Wiyot" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wja", - "Description": [ - "Waja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wji", - "Description": [ - "Warji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wka", - "Description": [ - "Kw'adza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wkb", - "Description": [ - "Kumbaran" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wkd", - "Description": [ - "Wakde", - "Mo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wkl", - "Description": [ - "Kalanadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wkr", - "Description": [ - "Keerray-Woorroong" - ], - "Added": "2019-04-16" - }, - { - "Type": "language", - "Subtag": "wku", - "Description": [ - "Kunduvadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wkw", - "Description": [ - "Wakawaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wky", - "Description": [ - "Wangkayutyuru" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wla", - "Description": [ - "Walio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlc", - "Description": [ - "Mwali Comorian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wle", - "Description": [ - "Wolane" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlg", - "Description": [ - "Kunbarlang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlh", - "Description": [ - "Welaun" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "wli", - "Description": [ - "Waioli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlk", - "Description": [ - "Wailaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wll", - "Description": [ - "Wali (Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlm", - "Description": [ - "Middle Welsh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlo", - "Description": [ - "Wolio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlr", - "Description": [ - "Wailapa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wls", - "Description": [ - "Wallisian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlu", - "Description": [ - "Wuliwuli" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlv", - "Description": [ - "Wichí Lhamtés Vejoz" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlw", - "Description": [ - "Walak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wlx", - "Description": [ - "Wali (Ghana)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wly", - "Description": [ - "Waling" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wma", - "Description": [ - "Mawa (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmb", - "Description": [ - "Wambaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmc", - "Description": [ - "Wamas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmd", - "Description": [ - "Mamaindé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wme", - "Description": [ - "Wambule" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmg", - "Description": [ - "Western Minyag" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "wmh", - "Description": [ - "Waima'a" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmi", - "Description": [ - "Wamin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmm", - "Description": [ - "Maiwa (Indonesia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmn", - "Description": [ - "Waamwang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmo", - "Description": [ - "Wom (Papua New Guinea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wms", - "Description": [ - "Wambon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmt", - "Description": [ - "Walmajarri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmw", - "Description": [ - "Mwani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wmx", - "Description": [ - "Womo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnb", - "Description": [ - "Wanambre" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnc", - "Description": [ - "Wantoat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnd", - "Description": [ - "Wandarang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wne", - "Description": [ - "Waneci" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wng", - "Description": [ - "Wanggom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wni", - "Description": [ - "Ndzwani Comorian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnk", - "Description": [ - "Wanukaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnm", - "Description": [ - "Wanggamala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnn", - "Description": [ - "Wunumara" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wno", - "Description": [ - "Wano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnp", - "Description": [ - "Wanap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnu", - "Description": [ - "Usan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wnw", - "Description": [ - "Wintu" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wny", - "Description": [ - "Wanyi", - "Waanyi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "woa", - "Description": [ - "Kuwema", - "Tyaraity" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wob", - "Description": [ - "Wè Northern" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "woc", - "Description": [ - "Wogeo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wod", - "Description": [ - "Wolani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "woe", - "Description": [ - "Woleaian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wof", - "Description": [ - "Gambian Wolof" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wog", - "Description": [ - "Wogamusin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "woi", - "Description": [ - "Kamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wok", - "Description": [ - "Longto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wom", - "Description": [ - "Wom (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "won", - "Description": [ - "Wongo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "woo", - "Description": [ - "Manombai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wor", - "Description": [ - "Woria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wos", - "Description": [ - "Hanga Hundi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wow", - "Description": [ - "Wawonii" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "woy", - "Description": [ - "Weyto" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wpc", - "Description": [ - "Maco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wra", - "Description": [ - "Warapu" - ], - "Added": "2009-07-29", - "Deprecated": "2021-02-20", - "Comments": [ - "see bpe, suo, uni" - ] - }, - { - "Type": "language", - "Subtag": "wrb", - "Description": [ - "Waluwarra", - "Warluwara" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrd", - "Description": [ - "Warduji" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "wrg", - "Description": [ - "Warungu", - "Gudjal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrh", - "Description": [ - "Wiradjuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wri", - "Description": [ - "Wariyangga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrk", - "Description": [ - "Garrwa" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "wrl", - "Description": [ - "Warlmanpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrm", - "Description": [ - "Warumungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrn", - "Description": [ - "Warnang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wro", - "Description": [ - "Worrorra" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "wrp", - "Description": [ - "Waropen" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrr", - "Description": [ - "Wardaman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrs", - "Description": [ - "Waris" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wru", - "Description": [ - "Waru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrv", - "Description": [ - "Waruna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrw", - "Description": [ - "Gugu Warra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wrx", - "Description": [ - "Wae Rana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wry", - "Description": [ - "Merwari" - ], - "Added": "2009-07-29", - "Macrolanguage": "mwr" - }, - { - "Type": "language", - "Subtag": "wrz", - "Description": [ - "Waray (Australia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsa", - "Description": [ - "Warembori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsg", - "Description": [ - "Adilabad Gondi" - ], - "Added": "2016-05-30", - "Macrolanguage": "gon" - }, - { - "Type": "language", - "Subtag": "wsi", - "Description": [ - "Wusi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsk", - "Description": [ - "Waskia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsr", - "Description": [ - "Owenia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wss", - "Description": [ - "Wasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsu", - "Description": [ - "Wasu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wsv", - "Description": [ - "Wotapuri-Katarqalai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wtf", - "Description": [ - "Watiwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wth", - "Description": [ - "Wathawurrung" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wti", - "Description": [ - "Berta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wtk", - "Description": [ - "Watakataui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wtm", - "Description": [ - "Mewati" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wtw", - "Description": [ - "Wotu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wua", - "Description": [ - "Wikngenchera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wub", - "Description": [ - "Wunambal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wud", - "Description": [ - "Wudu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wuh", - "Description": [ - "Wutunhua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wul", - "Description": [ - "Silimo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wum", - "Description": [ - "Wumbvu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wun", - "Description": [ - "Bungu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wur", - "Description": [ - "Wurrugu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wut", - "Description": [ - "Wutung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wuu", - "Description": [ - "Wu Chinese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "wuv", - "Description": [ - "Wuvulu-Aua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wux", - "Description": [ - "Wulna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wuy", - "Description": [ - "Wauyai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wwa", - "Description": [ - "Waama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wwb", - "Description": [ - "Wakabunga" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "wwo", - "Description": [ - "Wetamut", - "Dorig" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wwr", - "Description": [ - "Warrwa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "www", - "Description": [ - "Wawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wxa", - "Description": [ - "Waxianghua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wxw", - "Description": [ - "Wardandi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wya", - "Description": [ - "Wyandot" - ], - "Added": "2009-07-29", - "Deprecated": "2022-02-25", - "Comments": [ - "see wdt, wyn" - ] - }, - { - "Type": "language", - "Subtag": "wyb", - "Description": [ - "Wangaaybuwan-Ngiyambaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wyi", - "Description": [ - "Woiwurrung" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "wym", - "Description": [ - "Wymysorys" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wyn", - "Description": [ - "Wyandot" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "wyr", - "Description": [ - "Wayoró" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "wyy", - "Description": [ - "Western Fijian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xaa", - "Description": [ - "Andalusian Arabic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xab", - "Description": [ - "Sambe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xac", - "Description": [ - "Kachari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xad", - "Description": [ - "Adai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xae", - "Description": [ - "Aequian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xag", - "Description": [ - "Aghwan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xai", - "Description": [ - "Kaimbé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xaj", - "Description": [ - "Ararandewára" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "xak", - "Description": [ - "Máku" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "xal", - "Description": [ - "Kalmyk", - "Oirat" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "xam", - "Description": [ - "Ç€Xam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xan", - "Description": [ - "Xamtanga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xao", - "Description": [ - "Khao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xap", - "Description": [ - "Apalachee" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xaq", - "Description": [ - "Aquitanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xar", - "Description": [ - "Karami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xas", - "Description": [ - "Kamas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xat", - "Description": [ - "Katawixi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xau", - "Description": [ - "Kauwera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xav", - "Description": [ - "Xavánte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xaw", - "Description": [ - "Kawaiisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xay", - "Description": [ - "Kayan Mahakam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xba", - "Description": [ - "Kamba (Brazil)" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "cax" - }, - { - "Type": "language", - "Subtag": "xbb", - "Description": [ - "Lower Burdekin" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "xbc", - "Description": [ - "Bactrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbd", - "Description": [ - "Bindal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xbe", - "Description": [ - "Bigambal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xbg", - "Description": [ - "Bunganditj" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xbi", - "Description": [ - "Kombio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbj", - "Description": [ - "Birrpayi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xbm", - "Description": [ - "Middle Breton" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbn", - "Description": [ - "Kenaboi" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "xbo", - "Description": [ - "Bolgarian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbp", - "Description": [ - "Bibbulman" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xbr", - "Description": [ - "Kambera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbw", - "Description": [ - "Kambiwá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xbx", - "Description": [ - "Kabixí" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "xby", - "Description": [ - "Batjala", - "Batyala" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xcb", - "Description": [ - "Cumbric" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcc", - "Description": [ - "Camunic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xce", - "Description": [ - "Celtiberian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcg", - "Description": [ - "Cisalpine Gaulish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xch", - "Description": [ - "Chemakum", - "Chimakum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcl", - "Description": [ - "Classical Armenian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcm", - "Description": [ - "Comecrudo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcn", - "Description": [ - "Cotoname" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xco", - "Description": [ - "Chorasmian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcr", - "Description": [ - "Carian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xct", - "Description": [ - "Classical Tibetan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcu", - "Description": [ - "Curonian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcv", - "Description": [ - "Chuvantsy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcw", - "Description": [ - "Coahuilteco" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xcy", - "Description": [ - "Cayuse" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xda", - "Description": [ - "Darkinyung" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xdc", - "Description": [ - "Dacian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xdk", - "Description": [ - "Dharuk" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xdm", - "Description": [ - "Edomite" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xdo", - "Description": [ - "Kwandu" - ], - "Added": "2017-02-23" - }, - { - "Type": "language", - "Subtag": "xdq", - "Description": [ - "Kaitag" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "xdy", - "Description": [ - "Malayic Dayak" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xeb", - "Description": [ - "Eblan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xed", - "Description": [ - "Hdi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xeg", - "Description": [ - "ÇXegwi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xel", - "Description": [ - "Kelo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xem", - "Description": [ - "Kembayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xep", - "Description": [ - "Epi-Olmec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xer", - "Description": [ - "Xerénte" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xes", - "Description": [ - "Kesawai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xet", - "Description": [ - "Xetá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xeu", - "Description": [ - "Keoru-Ahia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xfa", - "Description": [ - "Faliscan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xga", - "Description": [ - "Galatian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xgb", - "Description": [ - "Gbin" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xgd", - "Description": [ - "Gudang" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xgf", - "Description": [ - "Gabrielino-Fernandeño" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xgg", - "Description": [ - "Goreng" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xgi", - "Description": [ - "Garingbal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xgl", - "Description": [ - "Galindan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xgm", - "Description": [ - "Dharumbal", - "Guwinmal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xgn", - "Description": [ - "Mongolian languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "xgr", - "Description": [ - "Garza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xgu", - "Description": [ - "Unggumi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xgw", - "Description": [ - "Guwa" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xha", - "Description": [ - "Harami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xhc", - "Description": [ - "Hunnic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xhd", - "Description": [ - "Hadrami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xhe", - "Description": [ - "Khetrani" - ], - "Added": "2009-07-29", - "Macrolanguage": "lah" - }, - { - "Type": "language", - "Subtag": "xhm", - "Description": [ - "Middle Khmer (1400 to 1850 CE)" - ], - "Added": "2022-02-25" - }, - { - "Type": "language", - "Subtag": "xhr", - "Description": [ - "Hernican" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xht", - "Description": [ - "Hattic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xhu", - "Description": [ - "Hurrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xhv", - "Description": [ - "Khua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xia", - "Description": [ - "Xiandao" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "acn" - }, - { - "Type": "language", - "Subtag": "xib", - "Description": [ - "Iberian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xii", - "Description": [ - "Xiri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xil", - "Description": [ - "Illyrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xin", - "Description": [ - "Xinca" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xip", - "Description": [ - "Xipináwa" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "xir", - "Description": [ - "Xiriâna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xis", - "Description": [ - "Kisan" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "xiv", - "Description": [ - "Indus Valley Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xiy", - "Description": [ - "Xipaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xjb", - "Description": [ - "Minjungbal" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xjt", - "Description": [ - "Jaitmatang" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xka", - "Description": [ - "Kalkoti" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkb", - "Description": [ - "Northern Nago" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkc", - "Description": [ - "Kho'ini" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkd", - "Description": [ - "Mendalam Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xke", - "Description": [ - "Kereho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkf", - "Description": [ - "Khengkha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkg", - "Description": [ - "Kagoro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkh", - "Description": [ - "Karahawyana" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30", - "Preferred-Value": "waw" - }, - { - "Type": "language", - "Subtag": "xki", - "Description": [ - "Kenyan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkj", - "Description": [ - "Kajali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkk", - "Description": [ - "Kachok", - "Kaco'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkl", - "Description": [ - "Mainstream Kenyah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkn", - "Description": [ - "Kayan River Kayan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xko", - "Description": [ - "Kiorr" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkp", - "Description": [ - "Kabatei" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkq", - "Description": [ - "Koroni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkr", - "Description": [ - "Xakriabá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xks", - "Description": [ - "Kumbewaha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkt", - "Description": [ - "Kantosi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xku", - "Description": [ - "Kaamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkv", - "Description": [ - "Kgalagadi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkw", - "Description": [ - "Kembra" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkx", - "Description": [ - "Karore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xky", - "Description": [ - "Uma' Lasan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xkz", - "Description": [ - "Kurtokha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xla", - "Description": [ - "Kamula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlb", - "Description": [ - "Loup B" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlc", - "Description": [ - "Lycian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xld", - "Description": [ - "Lydian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xle", - "Description": [ - "Lemnian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlg", - "Description": [ - "Ligurian (Ancient)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xli", - "Description": [ - "Liburnian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xln", - "Description": [ - "Alanic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlo", - "Description": [ - "Loup A" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlp", - "Description": [ - "Lepontic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xls", - "Description": [ - "Lusitanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xlu", - "Description": [ - "Cuneiform Luwian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xly", - "Description": [ - "Elymian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xma", - "Description": [ - "Mushungulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmb", - "Description": [ - "Mbonga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmc", - "Description": [ - "Makhuwa-Marrevone" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmd", - "Description": [ - "Mbudum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xme", - "Description": [ - "Median" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmf", - "Description": [ - "Mingrelian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmg", - "Description": [ - "Mengaka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmh", - "Description": [ - "Kugu-Muminh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmj", - "Description": [ - "Majera" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmk", - "Description": [ - "Ancient Macedonian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xml", - "Description": [ - "Malaysian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmm", - "Description": [ - "Manado Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "xmn", - "Description": [ - "Manichaean Middle Persian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmo", - "Description": [ - "Morerebi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmp", - "Description": [ - "Kuku-Mu'inh" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmq", - "Description": [ - "Kuku-Mangk" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmr", - "Description": [ - "Meroitic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xms", - "Description": [ - "Moroccan Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmt", - "Description": [ - "Matbat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmu", - "Description": [ - "Kamu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmv", - "Description": [ - "Antankarana Malagasy", - "Tankarana Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "xmw", - "Description": [ - "Tsimihety Malagasy" - ], - "Added": "2009-07-29", - "Macrolanguage": "mg" - }, - { - "Type": "language", - "Subtag": "xmx", - "Description": [ - "Salawati", - "Maden" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmy", - "Description": [ - "Mayaguduna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xmz", - "Description": [ - "Mori Bawah" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xna", - "Description": [ - "Ancient North Arabian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xnb", - "Description": [ - "Kanakanabu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xnd", - "Description": [ - "Na-Dene languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "xng", - "Description": [ - "Middle Mongolian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xnh", - "Description": [ - "Kuanhua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xni", - "Description": [ - "Ngarigu" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xnj", - "Description": [ - "Ngoni (Tanzania)" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "xnk", - "Description": [ - "Nganakarti" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xnm", - "Description": [ - "Ngumbarl" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xnn", - "Description": [ - "Northern Kankanay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xno", - "Description": [ - "Anglo-Norman" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xnq", - "Description": [ - "Ngoni (Mozambique)" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "xnr", - "Description": [ - "Kangri" - ], - "Added": "2009-07-29", - "Macrolanguage": "doi" - }, - { - "Type": "language", - "Subtag": "xns", - "Description": [ - "Kanashi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xnt", - "Description": [ - "Narragansett" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "xnu", - "Description": [ - "Nukunul" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xny", - "Description": [ - "Nyiyaparli" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xnz", - "Description": [ - "Kenzi", - "Mattoki" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xoc", - "Description": [ - "O'chi'chi'" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xod", - "Description": [ - "Kokoda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xog", - "Description": [ - "Soga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xoi", - "Description": [ - "Kominimung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xok", - "Description": [ - "Xokleng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xom", - "Description": [ - "Komo (Sudan)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xon", - "Description": [ - "Konkomba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xoo", - "Description": [ - "Xukurú" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xop", - "Description": [ - "Kopar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xor", - "Description": [ - "Korubo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xow", - "Description": [ - "Kowaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpa", - "Description": [ - "Pirriya" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xpb", - "Description": [ - "Northeastern Tasmanian", - "Pyemmairrener" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpc", - "Description": [ - "Pecheneg" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpd", - "Description": [ - "Oyster Bay Tasmanian" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpe", - "Description": [ - "Liberia Kpelle" - ], - "Added": "2009-07-29", - "Macrolanguage": "kpe" - }, - { - "Type": "language", - "Subtag": "xpf", - "Description": [ - "Southeast Tasmanian", - "Nuenonne" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpg", - "Description": [ - "Phrygian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xph", - "Description": [ - "North Midlands Tasmanian", - "Tyerrenoterpanner" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpi", - "Description": [ - "Pictish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpj", - "Description": [ - "Mpalitjanh" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xpk", - "Description": [ - "Kulina Pano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpl", - "Description": [ - "Port Sorell Tasmanian" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpm", - "Description": [ - "Pumpokol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpn", - "Description": [ - "Kapinawá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpo", - "Description": [ - "Pochutec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpp", - "Description": [ - "Puyo-Paekche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpq", - "Description": [ - "Mohegan-Pequot" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "xpr", - "Description": [ - "Parthian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xps", - "Description": [ - "Pisidian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpt", - "Description": [ - "Punthamara" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xpu", - "Description": [ - "Punic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpv", - "Description": [ - "Northern Tasmanian", - "Tommeginne" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpw", - "Description": [ - "Northwestern Tasmanian", - "Peerapper" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpx", - "Description": [ - "Southwestern Tasmanian", - "Toogee" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xpy", - "Description": [ - "Puyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xpz", - "Description": [ - "Bruny Island Tasmanian" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "xqa", - "Description": [ - "Karakhanid" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xqt", - "Description": [ - "Qatabanian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xra", - "Description": [ - "Krahô" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrb", - "Description": [ - "Eastern Karaboro" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrd", - "Description": [ - "Gundungurra" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xre", - "Description": [ - "Kreye" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrg", - "Description": [ - "Minang" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xri", - "Description": [ - "Krikati-Timbira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrm", - "Description": [ - "Armazic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrn", - "Description": [ - "Arin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrq", - "Description": [ - "Karranga" - ], - "Added": "2013-09-10", - "Deprecated": "2020-03-28", - "Preferred-Value": "dmw" - }, - { - "Type": "language", - "Subtag": "xrr", - "Description": [ - "Raetic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrt", - "Description": [ - "Aranama-Tamique" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xru", - "Description": [ - "Marriammu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xrw", - "Description": [ - "Karawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsa", - "Description": [ - "Sabaean" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsb", - "Description": [ - "Sambal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsc", - "Description": [ - "Scythian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsd", - "Description": [ - "Sidetic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xse", - "Description": [ - "Sempan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsh", - "Description": [ - "Shamang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsi", - "Description": [ - "Sio" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsj", - "Description": [ - "Subi" - ], - "Added": "2009-07-29", - "Comments": [ - "see also suj" - ] - }, - { - "Type": "language", - "Subtag": "xsl", - "Description": [ - "South Slavey" - ], - "Added": "2009-07-29", - "Macrolanguage": "den" - }, - { - "Type": "language", - "Subtag": "xsm", - "Description": [ - "Kasem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsn", - "Description": [ - "Sanga (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xso", - "Description": [ - "Solano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsp", - "Description": [ - "Silopi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsq", - "Description": [ - "Makhuwa-Saka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsr", - "Description": [ - "Sherpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xss", - "Description": [ - "Assan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsu", - "Description": [ - "Sanumá" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsv", - "Description": [ - "Sudovian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xsy", - "Description": [ - "Saisiyat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xta", - "Description": [ - "Alcozauca Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtb", - "Description": [ - "Chazumba Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtc", - "Description": [ - "Katcha-Kadugli-Miri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtd", - "Description": [ - "Diuxi-Tilantongo Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xte", - "Description": [ - "Ketengban" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtg", - "Description": [ - "Transalpine Gaulish" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xth", - "Description": [ - "Yitha Yitha" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xti", - "Description": [ - "Sinicahua Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtj", - "Description": [ - "San Juan Teita Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtl", - "Description": [ - "Tijaltepec Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtm", - "Description": [ - "Magdalena Peñasco Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtn", - "Description": [ - "Northern Tlaxiaco Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xto", - "Description": [ - "Tokharian A" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtp", - "Description": [ - "San Miguel Piedras Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtq", - "Description": [ - "Tumshuqese" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtr", - "Description": [ - "Early Tripuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xts", - "Description": [ - "Sindihui Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtt", - "Description": [ - "Tacahua Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtu", - "Description": [ - "Cuyamecalco Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtv", - "Description": [ - "Thawa" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xtw", - "Description": [ - "Tawandê" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xty", - "Description": [ - "Yoloxochitl Mixtec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xtz", - "Description": [ - "Tasmanian" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Comments": [ - "see xpb, xpd, xpf, xph, xpl, xpv, xpw, xpx, xpz" - ] - }, - { - "Type": "language", - "Subtag": "xua", - "Description": [ - "Alu Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xub", - "Description": [ - "Betta Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xud", - "Description": [ - "Umiida" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xug", - "Description": [ - "Kunigami" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xuj", - "Description": [ - "Jennu Kurumba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xul", - "Description": [ - "Ngunawal", - "Nunukul" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xum", - "Description": [ - "Umbrian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xun", - "Description": [ - "Unggaranggu" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xuo", - "Description": [ - "Kuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xup", - "Description": [ - "Upper Umpqua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xur", - "Description": [ - "Urartian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xut", - "Description": [ - "Kuthant" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xuu", - "Description": [ - "Kxoe", - "Khwedam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xve", - "Description": [ - "Venetic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xvi", - "Description": [ - "Kamviri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xvn", - "Description": [ - "Vandalic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xvo", - "Description": [ - "Volscian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xvs", - "Description": [ - "Vestinian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwa", - "Description": [ - "Kwaza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwc", - "Description": [ - "Woccon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwd", - "Description": [ - "Wadi Wadi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xwe", - "Description": [ - "Xwela Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwg", - "Description": [ - "Kwegu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwj", - "Description": [ - "Wajuk" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xwk", - "Description": [ - "Wangkumara" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xwl", - "Description": [ - "Western Xwla Gbe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwo", - "Description": [ - "Written Oirat" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwr", - "Description": [ - "Kwerba Mamberamo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xwt", - "Description": [ - "Wotjobaluk" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xww", - "Description": [ - "Wemba Wemba" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xxb", - "Description": [ - "Boro (Ghana)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xxk", - "Description": [ - "Ke'o" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xxm", - "Description": [ - "Minkin" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xxr", - "Description": [ - "Koropó" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xxt", - "Description": [ - "Tambora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xya", - "Description": [ - "Yaygir" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xyb", - "Description": [ - "Yandjibara" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xyj", - "Description": [ - "Mayi-Yapi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xyk", - "Description": [ - "Mayi-Kulan" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xyl", - "Description": [ - "Yalakalore" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xyt", - "Description": [ - "Mayi-Thakurti" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "xyy", - "Description": [ - "Yorta Yorta" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "xzh", - "Description": [ - "Zhang-Zhung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xzm", - "Description": [ - "Zemgalian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "xzp", - "Description": [ - "Ancient Zapotec" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yaa", - "Description": [ - "Yaminahua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yab", - "Description": [ - "Yuhup" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yac", - "Description": [ - "Pass Valley Yali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yad", - "Description": [ - "Yagua" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yae", - "Description": [ - "Pumé" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yaf", - "Description": [ - "Yaka (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yag", - "Description": [ - "Yámana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yah", - "Description": [ - "Yazgulyam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yai", - "Description": [ - "Yagnobi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yaj", - "Description": [ - "Banda-Yangere" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yak", - "Description": [ - "Yakama" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yal", - "Description": [ - "Yalunka" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yam", - "Description": [ - "Yamba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yan", - "Description": [ - "Mayangna" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "yao", - "Description": [ - "Yao" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "yap", - "Description": [ - "Yapese" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "yaq", - "Description": [ - "Yaqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yar", - "Description": [ - "Yabarana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yas", - "Description": [ - "Nugunu (Cameroon)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yat", - "Description": [ - "Yambeta" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yau", - "Description": [ - "Yuwana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yav", - "Description": [ - "Yangben" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yaw", - "Description": [ - "Yawalapití" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yax", - "Description": [ - "Yauma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yay", - "Description": [ - "Agwagwune" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yaz", - "Description": [ - "Lokaa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yba", - "Description": [ - "Yala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybb", - "Description": [ - "Yemba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybd", - "Description": [ - "Yangbye" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "rki" - }, - { - "Type": "language", - "Subtag": "ybe", - "Description": [ - "West Yugur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybh", - "Description": [ - "Yakha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybi", - "Description": [ - "Yamphu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybj", - "Description": [ - "Hasha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybk", - "Description": [ - "Bokha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybl", - "Description": [ - "Yukuben" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybm", - "Description": [ - "Yaben" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybn", - "Description": [ - "Yabaâna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybo", - "Description": [ - "Yabong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ybx", - "Description": [ - "Yawiyo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yby", - "Description": [ - "Yaweyuha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ych", - "Description": [ - "Chesu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ycl", - "Description": [ - "Lolopo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ycn", - "Description": [ - "Yucuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ycp", - "Description": [ - "Chepya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yda", - "Description": [ - "Yanda" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ydd", - "Description": [ - "Eastern Yiddish" - ], - "Added": "2009-07-29", - "Macrolanguage": "yi" - }, - { - "Type": "language", - "Subtag": "yde", - "Description": [ - "Yangum Dey" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ydg", - "Description": [ - "Yidgha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ydk", - "Description": [ - "Yoidik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yds", - "Description": [ - "Yiddish Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "yea", - "Description": [ - "Ravula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yec", - "Description": [ - "Yeniche" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yee", - "Description": [ - "Yimas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yei", - "Description": [ - "Yeni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yej", - "Description": [ - "Yevanic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yel", - "Description": [ - "Yela" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yen", - "Description": [ - "Yendang" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Comments": [ - "see ynq, yot" - ] - }, - { - "Type": "language", - "Subtag": "yer", - "Description": [ - "Tarok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yes", - "Description": [ - "Nyankpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yet", - "Description": [ - "Yetfa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yeu", - "Description": [ - "Yerukula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yev", - "Description": [ - "Yapunda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yey", - "Description": [ - "Yeyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yga", - "Description": [ - "Malyangapa" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ygi", - "Description": [ - "Yiningayi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ygl", - "Description": [ - "Yangum Gel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ygm", - "Description": [ - "Yagomi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ygp", - "Description": [ - "Gepo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ygr", - "Description": [ - "Yagaria" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ygs", - "Description": [ - "YolÅ‹u Sign Language" - ], - "Added": "2014-02-28" - }, - { - "Type": "language", - "Subtag": "ygu", - "Description": [ - "Yugul" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ygw", - "Description": [ - "Yagwoia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yha", - "Description": [ - "Baha Buyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yhd", - "Description": [ - "Judeo-Iraqi Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "jrb" - }, - { - "Type": "language", - "Subtag": "yhl", - "Description": [ - "Hlepho Phowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yhs", - "Description": [ - "Yan-nhaÅ‹u Sign Language" - ], - "Added": "2015-04-17" - }, - { - "Type": "language", - "Subtag": "yia", - "Description": [ - "Yinggarda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yif", - "Description": [ - "Ache" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yig", - "Description": [ - "Wusa Nasu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yih", - "Description": [ - "Western Yiddish" - ], - "Added": "2009-07-29", - "Macrolanguage": "yi" - }, - { - "Type": "language", - "Subtag": "yii", - "Description": [ - "Yidiny" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yij", - "Description": [ - "Yindjibarndi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yik", - "Description": [ - "Dongshanba Lalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yil", - "Description": [ - "Yindjilandji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yim", - "Description": [ - "Yimchungru Naga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yin", - "Description": [ - "Riang Lai", - "Yinchia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yip", - "Description": [ - "Pholo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yiq", - "Description": [ - "Miqie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yir", - "Description": [ - "North Awyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yis", - "Description": [ - "Yis" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yit", - "Description": [ - "Eastern Lalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yiu", - "Description": [ - "Awu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yiv", - "Description": [ - "Northern Nisu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yix", - "Description": [ - "Axi Yi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yiy", - "Description": [ - "Yir Yoront" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Comments": [ - "see yrm, yyr" - ] - }, - { - "Type": "language", - "Subtag": "yiz", - "Description": [ - "Azhe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yka", - "Description": [ - "Yakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykg", - "Description": [ - "Northern Yukaghir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yki", - "Description": [ - "Yoke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykk", - "Description": [ - "Yakaikeke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykl", - "Description": [ - "Khlula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykm", - "Description": [ - "Kap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykn", - "Description": [ - "Kua-nsi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yko", - "Description": [ - "Yasa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykr", - "Description": [ - "Yekora" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ykt", - "Description": [ - "Kathu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yku", - "Description": [ - "Kuamasi" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yky", - "Description": [ - "Yakoma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yla", - "Description": [ - "Yaul" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylb", - "Description": [ - "Yaleba" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "yle", - "Description": [ - "Yele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylg", - "Description": [ - "Yelogu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yli", - "Description": [ - "Angguruk Yali" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yll", - "Description": [ - "Yil" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylm", - "Description": [ - "Limi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yln", - "Description": [ - "Langnian Buyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylo", - "Description": [ - "Naluo Yi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylr", - "Description": [ - "Yalarnnga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ylu", - "Description": [ - "Aribwaung" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yly", - "Description": [ - "Nyâlayu", - "Nyelâyu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yma", - "Description": [ - "Yamphe" - ], - "Added": "2009-07-29", - "Deprecated": "2012-08-12", - "Preferred-Value": "lrr" - }, - { - "Type": "language", - "Subtag": "ymb", - "Description": [ - "Yambes" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymc", - "Description": [ - "Southern Muji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymd", - "Description": [ - "Muda" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yme", - "Description": [ - "Yameo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymg", - "Description": [ - "Yamongeri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymh", - "Description": [ - "Mili" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymi", - "Description": [ - "Moji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymk", - "Description": [ - "Makwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yml", - "Description": [ - "Iamalele" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymm", - "Description": [ - "Maay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymn", - "Description": [ - "Yamna", - "Sunum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymo", - "Description": [ - "Yangum Mon" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymp", - "Description": [ - "Yamap" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymq", - "Description": [ - "Qila Muji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymr", - "Description": [ - "Malasar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yms", - "Description": [ - "Mysian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymt", - "Description": [ - "Mator-Taygi-Karagas" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "mtm" - }, - { - "Type": "language", - "Subtag": "ymx", - "Description": [ - "Northern Muji" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ymz", - "Description": [ - "Muzi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yna", - "Description": [ - "Aluo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynd", - "Description": [ - "Yandruwandha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yne", - "Description": [ - "Lang'e" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yng", - "Description": [ - "Yango" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynh", - "Description": [ - "Yangho" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12" - }, - { - "Type": "language", - "Subtag": "ynk", - "Description": [ - "Naukan Yupik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynl", - "Description": [ - "Yangulam" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynn", - "Description": [ - "Yana" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yno", - "Description": [ - "Yong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynq", - "Description": [ - "Yendang" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yns", - "Description": [ - "Yansi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ynu", - "Description": [ - "Yahuna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yob", - "Description": [ - "Yoba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yog", - "Description": [ - "Yogad" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yoi", - "Description": [ - "Yonaguni" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yok", - "Description": [ - "Yokuts" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yol", - "Description": [ - "Yola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yom", - "Description": [ - "Yombe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yon", - "Description": [ - "Yongkom" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yos", - "Description": [ - "Yos" - ], - "Added": "2009-07-29", - "Deprecated": "2013-09-10", - "Preferred-Value": "zom" - }, - { - "Type": "language", - "Subtag": "yot", - "Description": [ - "Yotti" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yox", - "Description": [ - "Yoron" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yoy", - "Description": [ - "Yoy" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypa", - "Description": [ - "Phala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypb", - "Description": [ - "Labo Phowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypg", - "Description": [ - "Phola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yph", - "Description": [ - "Phupha" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypk", - "Description": [ - "Yupik languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "ypm", - "Description": [ - "Phuma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypn", - "Description": [ - "Ani Phowa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypo", - "Description": [ - "Alo Phola" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypp", - "Description": [ - "Phupa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ypz", - "Description": [ - "Phuza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yra", - "Description": [ - "Yerakai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yrb", - "Description": [ - "Yareba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yre", - "Description": [ - "Yaouré" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yri", - "Description": [ - "Yarí" - ], - "Added": "2009-07-29", - "Deprecated": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "yrk", - "Description": [ - "Nenets" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yrl", - "Description": [ - "Nhengatu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yrm", - "Description": [ - "Yirrk-Mel" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yrn", - "Description": [ - "Yerong" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yro", - "Description": [ - "Yaroamë" - ], - "Added": "2016-05-30" - }, - { - "Type": "language", - "Subtag": "yrs", - "Description": [ - "Yarsun" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yrw", - "Description": [ - "Yarawata" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yry", - "Description": [ - "Yarluyandi" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ysc", - "Description": [ - "Yassic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysd", - "Description": [ - "Samatao" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysg", - "Description": [ - "Sonaga" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "ysl", - "Description": [ - "Yugoslavian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysm", - "Description": [ - "Myanmar Sign Language" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "ysn", - "Description": [ - "Sani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yso", - "Description": [ - "Nisi (China)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysp", - "Description": [ - "Southern Lolopo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysr", - "Description": [ - "Sirenik Yupik" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yss", - "Description": [ - "Yessan-Mayo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ysy", - "Description": [ - "Sanie" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yta", - "Description": [ - "Talu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ytl", - "Description": [ - "Tanglang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ytp", - "Description": [ - "Thopho" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ytw", - "Description": [ - "Yout Wam" - ], - "Added": "2010-03-11" - }, - { - "Type": "language", - "Subtag": "yty", - "Description": [ - "Yatay" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yua", - "Description": [ - "Yucateco", - "Yucatec Maya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yub", - "Description": [ - "Yugambal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuc", - "Description": [ - "Yuchi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yud", - "Description": [ - "Judeo-Tripolitanian Arabic" - ], - "Added": "2009-07-29", - "Macrolanguage": "jrb" - }, - { - "Type": "language", - "Subtag": "yue", - "Description": [ - "Yue Chinese", - "Cantonese" - ], - "Added": "2009-07-29", - "Macrolanguage": "zh" - }, - { - "Type": "language", - "Subtag": "yuf", - "Description": [ - "Havasupai-Walapai-Yavapai" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yug", - "Description": [ - "Yug" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yui", - "Description": [ - "Yurutí" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuj", - "Description": [ - "Karkar-Yuri" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuk", - "Description": [ - "Yuki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yul", - "Description": [ - "Yulu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yum", - "Description": [ - "Quechan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yun", - "Description": [ - "Bena (Nigeria)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yup", - "Description": [ - "Yukpa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuq", - "Description": [ - "Yuqui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yur", - "Description": [ - "Yurok" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yut", - "Description": [ - "Yopno" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuu", - "Description": [ - "Yugh" - ], - "Added": "2009-07-29", - "Deprecated": "2014-02-28", - "Preferred-Value": "yug" - }, - { - "Type": "language", - "Subtag": "yuw", - "Description": [ - "Yau (Morobe Province)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yux", - "Description": [ - "Southern Yukaghir" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuy", - "Description": [ - "East Yugur" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yuz", - "Description": [ - "Yuracare" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yva", - "Description": [ - "Yawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yvt", - "Description": [ - "Yavitero" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywa", - "Description": [ - "Kalou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywg", - "Description": [ - "Yinhawangka" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "ywl", - "Description": [ - "Western Lalu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywn", - "Description": [ - "Yawanawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywq", - "Description": [ - "Wuding-Luquan Yi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywr", - "Description": [ - "Yawuru" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywt", - "Description": [ - "Xishanba Lalo", - "Central Lalo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ywu", - "Description": [ - "Wumeng Nasu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yww", - "Description": [ - "Yawarawarga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yxa", - "Description": [ - "Mayawali" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yxg", - "Description": [ - "Yagara" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yxl", - "Description": [ - "Yardliyawarra" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yxm", - "Description": [ - "Yinwum" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yxu", - "Description": [ - "Yuyu" - ], - "Added": "2013-09-10" - }, - { - "Type": "language", - "Subtag": "yxy", - "Description": [ - "Yabula Yabula" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "yyr", - "Description": [ - "Yir Yoront" - ], - "Added": "2013-09-03" - }, - { - "Type": "language", - "Subtag": "yyu", - "Description": [ - "Yau (Sandaun Province)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yyz", - "Description": [ - "Ayizi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yzg", - "Description": [ - "E'ma Buyang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "yzk", - "Description": [ - "Zokhuo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zaa", - "Description": [ - "Sierra de Juárez Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zab", - "Description": [ - "Western Tlacolula Valley Zapotec", - "San Juan Guelavía Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zac", - "Description": [ - "Ocotlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zad", - "Description": [ - "Cajonos Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zae", - "Description": [ - "Yareni Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zaf", - "Description": [ - "Ayoquesco Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zag", - "Description": [ - "Zaghawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zah", - "Description": [ - "Zangwal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zai", - "Description": [ - "Isthmus Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zaj", - "Description": [ - "Zaramo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zak", - "Description": [ - "Zanaki" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zal", - "Description": [ - "Zauzou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zam", - "Description": [ - "Miahuatlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zao", - "Description": [ - "Ozolotepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zap", - "Description": [ - "Zapotec" - ], - "Added": "2005-10-16", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "zaq", - "Description": [ - "Aloápam Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zar", - "Description": [ - "Rincón Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zas", - "Description": [ - "Santo Domingo Albarradas Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zat", - "Description": [ - "Tabaa Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zau", - "Description": [ - "Zangskari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zav", - "Description": [ - "Yatzachi Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zaw", - "Description": [ - "Mitla Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zax", - "Description": [ - "Xadani Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zay", - "Description": [ - "Zayse-Zergulla", - "Zaysete" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zaz", - "Description": [ - "Zari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zba", - "Description": [ - "Balaibalan" - ], - "Added": "2020-03-28" - }, - { - "Type": "language", - "Subtag": "zbc", - "Description": [ - "Central Berawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zbe", - "Description": [ - "East Berawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zbl", - "Description": [ - "Blissymbols", - "Bliss", - "Blissymbolics" - ], - "Added": "2007-08-21", - "Suppress-Script": "Blis" - }, - { - "Type": "language", - "Subtag": "zbt", - "Description": [ - "Batui" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zbu", - "Description": [ - "Bu (Bauchi State)" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "zbw", - "Description": [ - "West Berawan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zca", - "Description": [ - "Coatecas Altas Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zcd", - "Description": [ - "Las Delicias Zapotec" - ], - "Added": "2022-02-25", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zch", - "Description": [ - "Central Hongshuihe Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zdj", - "Description": [ - "Ngazidja Comorian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zea", - "Description": [ - "Zeeuws" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zeg", - "Description": [ - "Zenag" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zeh", - "Description": [ - "Eastern Hongshuihe Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zen", - "Description": [ - "Zenaga" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "zga", - "Description": [ - "Kinga" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zgb", - "Description": [ - "Guibei Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zgh", - "Description": [ - "Standard Moroccan Tamazight" - ], - "Added": "2013-01-25" - }, - { - "Type": "language", - "Subtag": "zgm", - "Description": [ - "Minz Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zgn", - "Description": [ - "Guibian Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zgr", - "Description": [ - "Magori" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zhb", - "Description": [ - "Zhaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zhd", - "Description": [ - "Dai Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zhi", - "Description": [ - "Zhire" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zhn", - "Description": [ - "Nong Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zhw", - "Description": [ - "Zhoa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zhx", - "Description": [ - "Chinese (family)" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "zia", - "Description": [ - "Zia" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zib", - "Description": [ - "Zimbabwe Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zik", - "Description": [ - "Zimakani" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zil", - "Description": [ - "Zialo" - ], - "Added": "2011-08-16" - }, - { - "Type": "language", - "Subtag": "zim", - "Description": [ - "Mesme" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zin", - "Description": [ - "Zinza" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zir", - "Description": [ - "Ziriya" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "scv" - }, - { - "Type": "language", - "Subtag": "ziw", - "Description": [ - "Zigula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "ziz", - "Description": [ - "Zizilivakan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zka", - "Description": [ - "Kaimbulawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkb", - "Description": [ - "Koibal" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkd", - "Description": [ - "Kadu" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "zkg", - "Description": [ - "Koguryo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkh", - "Description": [ - "Khorezmian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkk", - "Description": [ - "Karankawa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkn", - "Description": [ - "Kanan" - ], - "Added": "2012-08-12" - }, - { - "Type": "language", - "Subtag": "zko", - "Description": [ - "Kott" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkp", - "Description": [ - "São Paulo Kaingáng" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkr", - "Description": [ - "Zakhring" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkt", - "Description": [ - "Kitan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zku", - "Description": [ - "Kaurna" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkv", - "Description": [ - "Krevinian" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zkz", - "Description": [ - "Khazar" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zla", - "Description": [ - "Zula" - ], - "Added": "2021-02-20" - }, - { - "Type": "language", - "Subtag": "zle", - "Description": [ - "East Slavic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "zlj", - "Description": [ - "Liujiang Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zlm", - "Description": [ - "Malay (individual language)" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "zln", - "Description": [ - "Lianshan Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zlq", - "Description": [ - "Liuqian Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zls", - "Description": [ - "South Slavic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "zlw", - "Description": [ - "West Slavic languages" - ], - "Added": "2009-07-29", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "zma", - "Description": [ - "Manda (Australia)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmb", - "Description": [ - "Zimba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmc", - "Description": [ - "Margany" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmd", - "Description": [ - "Maridan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zme", - "Description": [ - "Mangerr" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmf", - "Description": [ - "Mfinu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmg", - "Description": [ - "Marti Ke" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmh", - "Description": [ - "Makolkol" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmi", - "Description": [ - "Negeri Sembilan Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "zmj", - "Description": [ - "Maridjabin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmk", - "Description": [ - "Mandandanyi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zml", - "Description": [ - "Matngala" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmm", - "Description": [ - "Marimanindji", - "Marramaninyshi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmn", - "Description": [ - "Mbangwe" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmo", - "Description": [ - "Molo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmp", - "Description": [ - "Mpuono" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmq", - "Description": [ - "Mituku" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmr", - "Description": [ - "Maranunggu" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zms", - "Description": [ - "Mbesa" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmt", - "Description": [ - "Maringarr" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmu", - "Description": [ - "Muruwari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmv", - "Description": [ - "Mbariman-Gudhinma" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmw", - "Description": [ - "Mbo (Democratic Republic of Congo)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmx", - "Description": [ - "Bomitaba" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmy", - "Description": [ - "Mariyedi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zmz", - "Description": [ - "Mbandja" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zna", - "Description": [ - "Zan Gula" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "znd", - "Description": [ - "Zande languages" - ], - "Added": "2005-10-16", - "Scope": "collection" - }, - { - "Type": "language", - "Subtag": "zne", - "Description": [ - "Zande (individual language)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zng", - "Description": [ - "Mang" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "znk", - "Description": [ - "Manangkari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zns", - "Description": [ - "Mangas" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zoc", - "Description": [ - "Copainalá Zoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zoh", - "Description": [ - "Chimalapa Zoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zom", - "Description": [ - "Zou" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zoo", - "Description": [ - "Asunción Mixtepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zoq", - "Description": [ - "Tabasco Zoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zor", - "Description": [ - "Rayón Zoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zos", - "Description": [ - "Francisco León Zoque" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zpa", - "Description": [ - "Lachiguiri Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpb", - "Description": [ - "Yautepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpc", - "Description": [ - "Choapan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpd", - "Description": [ - "Southeastern Ixtlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpe", - "Description": [ - "Petapa Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpf", - "Description": [ - "San Pedro Quiatoni Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpg", - "Description": [ - "Guevea De Humboldt Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zph", - "Description": [ - "Totomachapan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpi", - "Description": [ - "Santa María Quiegolani Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpj", - "Description": [ - "Quiavicuzas Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpk", - "Description": [ - "Tlacolulita Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpl", - "Description": [ - "Lachixío Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpm", - "Description": [ - "Mixtepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpn", - "Description": [ - "Santa Inés Yatzechi Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpo", - "Description": [ - "Amatlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpp", - "Description": [ - "El Alto Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpq", - "Description": [ - "Zoogocho Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpr", - "Description": [ - "Santiago Xanica Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zps", - "Description": [ - "Coatlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpt", - "Description": [ - "San Vicente Coatlán Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpu", - "Description": [ - "Yalálag Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpv", - "Description": [ - "Chichicapan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpw", - "Description": [ - "Zaniza Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpx", - "Description": [ - "San Baltazar Loxicha Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpy", - "Description": [ - "Mazaltepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zpz", - "Description": [ - "Texmelucan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zqe", - "Description": [ - "Qiubei Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zra", - "Description": [ - "Kara (Korea)" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zrg", - "Description": [ - "Mirgan" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zrn", - "Description": [ - "Zerenkel" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zro", - "Description": [ - "Záparo" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zrp", - "Description": [ - "Zarphatic" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zrs", - "Description": [ - "Mairasi" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zsa", - "Description": [ - "Sarasira" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zsk", - "Description": [ - "Kaskean" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zsl", - "Description": [ - "Zambian Sign Language" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zsm", - "Description": [ - "Standard Malay" - ], - "Added": "2009-07-29", - "Macrolanguage": "ms" - }, - { - "Type": "language", - "Subtag": "zsr", - "Description": [ - "Southern Rincon Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zsu", - "Description": [ - "Sukurum" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zte", - "Description": [ - "Elotepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztg", - "Description": [ - "Xanaguía Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztl", - "Description": [ - "Lapaguía-Guivini Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztm", - "Description": [ - "San Agustín Mixtepec Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztn", - "Description": [ - "Santa Catarina Albarradas Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztp", - "Description": [ - "Loxicha Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztq", - "Description": [ - "Quioquitani-Quierí Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zts", - "Description": [ - "Tilquiapan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztt", - "Description": [ - "Tejalapan Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztu", - "Description": [ - "Güilá Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "ztx", - "Description": [ - "Zaachila Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zty", - "Description": [ - "Yatee Zapotec" - ], - "Added": "2009-07-29", - "Macrolanguage": "zap" - }, - { - "Type": "language", - "Subtag": "zua", - "Description": [ - "Zeem" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zuh", - "Description": [ - "Tokano" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zum", - "Description": [ - "Kumzari" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zun", - "Description": [ - "Zuni" - ], - "Added": "2005-10-16" - }, - { - "Type": "language", - "Subtag": "zuy", - "Description": [ - "Zumaya" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zwa", - "Description": [ - "Zay" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zxx", - "Description": [ - "No linguistic content", - "Not applicable" - ], - "Added": "2006-03-08", - "Scope": "special" - }, - { - "Type": "language", - "Subtag": "zyb", - "Description": [ - "Yongbei Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zyg", - "Description": [ - "Yang Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zyj", - "Description": [ - "Youjiang Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zyn", - "Description": [ - "Yongnan Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "language", - "Subtag": "zyp", - "Description": [ - "Zyphe Chin" - ], - "Added": "2009-07-29" - }, - { - "Type": "language", - "Subtag": "zza", - "Description": [ - "Zaza", - "Dimili", - "Dimli (macrolanguage)", - "Kirdki", - "Kirmanjki (macrolanguage)", - "Zazaki" - ], - "Added": "2006-08-24", - "Scope": "macrolanguage" - }, - { - "Type": "language", - "Subtag": "zzj", - "Description": [ - "Zuojiang Zhuang" - ], - "Added": "2009-07-29", - "Macrolanguage": "za" - }, - { - "Type": "extlang", - "Subtag": "aao", - "Description": [ - "Algerian Saharan Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "aao", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "abh", - "Description": [ - "Tajiki Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "abh", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "abv", - "Description": [ - "Baharna Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "abv", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "acm", - "Description": [ - "Mesopotamian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "acm", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "acq", - "Description": [ - "Ta'izzi-Adeni Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "acq", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "acw", - "Description": [ - "Hijazi Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "acw", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "acx", - "Description": [ - "Omani Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "acx", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "acy", - "Description": [ - "Cypriot Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "acy", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "adf", - "Description": [ - "Dhofari Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "adf", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ads", - "Description": [ - "Adamorobe Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ads", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "aeb", - "Description": [ - "Tunisian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "aeb", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "aec", - "Description": [ - "Saidi Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "aec", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "aed", - "Description": [ - "Argentine Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "aed", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "aen", - "Description": [ - "Armenian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "aen", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "afb", - "Description": [ - "Gulf Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "afb", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "afg", - "Description": [ - "Afghan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "afg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ajp", - "Description": [ - "South Levantine Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ajp", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ajs", - "Description": [ - "Algerian Jewish Sign Language" - ], - "Added": "2022-02-25", - "Preferred-Value": "ajs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "apc", - "Description": [ - "North Levantine Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "apc", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "apd", - "Description": [ - "Sudanese Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "apd", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "arb", - "Description": [ - "Standard Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "arb", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "arq", - "Description": [ - "Algerian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "arq", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ars", - "Description": [ - "Najdi Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ars", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ary", - "Description": [ - "Moroccan Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ary", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "arz", - "Description": [ - "Egyptian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "arz", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ase", - "Description": [ - "American Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ase", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "asf", - "Description": [ - "Auslan", - "Australian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "asf", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "asp", - "Description": [ - "Algerian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "asp", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "asq", - "Description": [ - "Austrian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "asq", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "asw", - "Description": [ - "Australian Aborigines Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "asw", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "auz", - "Description": [ - "Uzbeki Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "auz", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "avl", - "Description": [ - "Eastern Egyptian Bedawi Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "avl", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ayh", - "Description": [ - "Hadrami Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ayh", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ayl", - "Description": [ - "Libyan Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ayl", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ayn", - "Description": [ - "Sanaani Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ayn", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ayp", - "Description": [ - "North Mesopotamian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ayp", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "bbz", - "Description": [ - "Babalia Creole Arabic" - ], - "Added": "2009-07-29", - "Deprecated": "2020-03-28", - "Preferred-Value": "bbz", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "bfi", - "Description": [ - "British Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bfi", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "bfk", - "Description": [ - "Ban Khor Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bfk", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "bjn", - "Description": [ - "Banjar" - ], - "Added": "2009-07-29", - "Preferred-Value": "bjn", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "bog", - "Description": [ - "Bamako Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bog", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "bqn", - "Description": [ - "Bulgarian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bqn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "bqy", - "Description": [ - "Bengkala Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bqy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "btj", - "Description": [ - "Bacanese Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "btj", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "bve", - "Description": [ - "Berau Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "bve", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "bvl", - "Description": [ - "Bolivian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bvl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "bvu", - "Description": [ - "Bukit Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "bvu", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "bzs", - "Description": [ - "Brazilian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "bzs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "cdo", - "Description": [ - "Min Dong Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "cdo", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "cds", - "Description": [ - "Chadian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "cds", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "cjy", - "Description": [ - "Jinyu Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "cjy", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "cmn", - "Description": [ - "Mandarin Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "cmn", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "cnp", - "Description": [ - "Northern Ping Chinese", - "Northern Pinghua" - ], - "Added": "2020-03-28", - "Preferred-Value": "cnp", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "coa", - "Description": [ - "Cocos Islands Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "coa", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "cpx", - "Description": [ - "Pu-Xian Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "cpx", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "csc", - "Description": [ - "Catalan Sign Language", - "Lengua de señas catalana", - "Llengua de Signes Catalana" - ], - "Added": "2009-07-29", - "Preferred-Value": "csc", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csd", - "Description": [ - "Chiangmai Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csd", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "cse", - "Description": [ - "Czech Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "cse", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csf", - "Description": [ - "Cuba Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csf", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csg", - "Description": [ - "Chilean Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csl", - "Description": [ - "Chinese Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csn", - "Description": [ - "Colombian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csp", - "Description": [ - "Southern Ping Chinese", - "Southern Pinghua" - ], - "Added": "2020-03-28", - "Preferred-Value": "csp", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "csq", - "Description": [ - "Croatia Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csq", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csr", - "Description": [ - "Costa Rican Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "csr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "csx", - "Description": [ - "Cambodian Sign Language" - ], - "Added": "2021-02-20", - "Preferred-Value": "csx", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "czh", - "Description": [ - "Huizhou Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "czh", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "czo", - "Description": [ - "Min Zhong Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "czo", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "doq", - "Description": [ - "Dominican Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "doq", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "dse", - "Description": [ - "Dutch Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "dse", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "dsl", - "Description": [ - "Danish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "dsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "dsz", - "Description": [ - "Mardin Sign Language" - ], - "Added": "2022-02-25", - "Preferred-Value": "dsz", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "dup", - "Description": [ - "Duano" - ], - "Added": "2009-07-29", - "Preferred-Value": "dup", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "ecs", - "Description": [ - "Ecuadorian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ecs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ehs", - "Description": [ - "Miyakubo Sign Language" - ], - "Added": "2021-02-20", - "Preferred-Value": "ehs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "esl", - "Description": [ - "Egypt Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "esl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "esn", - "Description": [ - "Salvadoran Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "esn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "eso", - "Description": [ - "Estonian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "eso", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "eth", - "Description": [ - "Ethiopian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "eth", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "fcs", - "Description": [ - "Quebec Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "fcs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "fse", - "Description": [ - "Finnish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "fse", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "fsl", - "Description": [ - "French Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "fsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "fss", - "Description": [ - "Finland-Swedish Sign Language", - "finlandssvenskt teckensprÃ¥k", - "suomenruotsalainen viittomakieli" - ], - "Added": "2009-07-29", - "Preferred-Value": "fss", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gan", - "Description": [ - "Gan Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "gan", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "gds", - "Description": [ - "Ghandruk Sign Language" - ], - "Added": "2012-08-12", - "Preferred-Value": "gds", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gom", - "Description": [ - "Goan Konkani" - ], - "Added": "2009-07-29", - "Preferred-Value": "gom", - "Prefix": [ - "kok" - ], - "Macrolanguage": "kok" - }, - { - "Type": "extlang", - "Subtag": "gse", - "Description": [ - "Ghanaian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "gse", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gsg", - "Description": [ - "German Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "gsg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gsm", - "Description": [ - "Guatemalan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "gsm", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gss", - "Description": [ - "Greek Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "gss", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "gus", - "Description": [ - "Guinean Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "gus", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hab", - "Description": [ - "Hanoi Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hab", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "haf", - "Description": [ - "Haiphong Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "haf", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hak", - "Description": [ - "Hakka Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "hak", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "hds", - "Description": [ - "Honduras Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hds", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hji", - "Description": [ - "Haji" - ], - "Added": "2009-07-29", - "Preferred-Value": "hji", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "hks", - "Description": [ - "Hong Kong Sign Language", - "Heung Kong Sau Yue" - ], - "Added": "2009-07-29", - "Preferred-Value": "hks", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hos", - "Description": [ - "Ho Chi Minh City Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hos", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hps", - "Description": [ - "Hawai'i Sign Language (HSL)", - "Hawai'i Pidgin Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hps", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hsh", - "Description": [ - "Hungarian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hsh", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hsl", - "Description": [ - "Hausa Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "hsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "hsn", - "Description": [ - "Xiang Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "hsn", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "icl", - "Description": [ - "Icelandic Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "icl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "iks", - "Description": [ - "Inuit Sign Language" - ], - "Added": "2015-02-12", - "Preferred-Value": "iks", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ils", - "Description": [ - "International Sign" - ], - "Added": "2009-07-29", - "Preferred-Value": "ils", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "inl", - "Description": [ - "Indonesian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "inl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ins", - "Description": [ - "Indian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ins", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ise", - "Description": [ - "Italian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ise", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "isg", - "Description": [ - "Irish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "isg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "isr", - "Description": [ - "Israeli Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "isr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jak", - "Description": [ - "Jakun" - ], - "Added": "2009-07-29", - "Preferred-Value": "jak", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "jax", - "Description": [ - "Jambi Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "jax", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "jcs", - "Description": [ - "Jamaican Country Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "jcs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jhs", - "Description": [ - "Jhankot Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "jhs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jks", - "Description": [ - "Amami Koniya Sign Language" - ], - "Added": "2021-02-20", - "Preferred-Value": "jks", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jls", - "Description": [ - "Jamaican Sign Language" - ], - "Added": "2010-03-11", - "Preferred-Value": "jls", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jos", - "Description": [ - "Jordanian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "jos", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jsl", - "Description": [ - "Japanese Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "jsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "jus", - "Description": [ - "Jumla Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "jus", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "kgi", - "Description": [ - "Selangor Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "kgi", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "knn", - "Description": [ - "Konkani (individual language)" - ], - "Added": "2009-07-29", - "Preferred-Value": "knn", - "Prefix": [ - "kok" - ], - "Macrolanguage": "kok" - }, - { - "Type": "extlang", - "Subtag": "kvb", - "Description": [ - "Kubu" - ], - "Added": "2009-07-29", - "Preferred-Value": "kvb", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "kvk", - "Description": [ - "Korean Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "kvk", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "kvr", - "Description": [ - "Kerinci" - ], - "Added": "2009-07-29", - "Preferred-Value": "kvr", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "kxd", - "Description": [ - "Brunei" - ], - "Added": "2009-07-29", - "Preferred-Value": "kxd", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "lbs", - "Description": [ - "Libyan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "lbs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lce", - "Description": [ - "Loncong", - "Sekak" - ], - "Added": "2009-07-29", - "Preferred-Value": "lce", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "lcf", - "Description": [ - "Lubu" - ], - "Added": "2009-07-29", - "Preferred-Value": "lcf", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "liw", - "Description": [ - "Col" - ], - "Added": "2009-07-29", - "Preferred-Value": "liw", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "lls", - "Description": [ - "Lithuanian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "lls", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsb", - "Description": [ - "Burundian Sign Language", - "Langue des Signes Burundaise" - ], - "Added": "2021-02-20", - "Preferred-Value": "lsb", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsc", - "Description": [ - "Albarradas Sign Language", - "Lengua de señas Albarradas" - ], - "Added": "2022-02-25", - "Preferred-Value": "lsc", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsg", - "Description": [ - "Lyons Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2018-03-08", - "Preferred-Value": "lsg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsl", - "Description": [ - "Latvian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "lsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsn", - "Description": [ - "Tibetan Sign Language" - ], - "Added": "2019-04-16", - "Preferred-Value": "lsn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lso", - "Description": [ - "Laos Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "lso", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsp", - "Description": [ - "Panamanian Sign Language", - "Lengua de Señas Panameñas" - ], - "Added": "2009-07-29", - "Preferred-Value": "lsp", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lst", - "Description": [ - "Trinidad and Tobago Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "lst", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsv", - "Description": [ - "Sivia Sign Language" - ], - "Added": "2019-04-16", - "Preferred-Value": "lsv", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsw", - "Description": [ - "Seychelles Sign Language", - "Lalang Siny Seselwa", - "Langue des Signes Seychelloise" - ], - "Added": "2022-02-25", - "Preferred-Value": "lsw", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lsy", - "Description": [ - "Mauritian Sign Language" - ], - "Added": "2010-03-11", - "Preferred-Value": "lsy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ltg", - "Description": [ - "Latgalian" - ], - "Added": "2010-03-11", - "Preferred-Value": "ltg", - "Prefix": [ - "lv" - ], - "Macrolanguage": "lv" - }, - { - "Type": "extlang", - "Subtag": "lvs", - "Description": [ - "Standard Latvian" - ], - "Added": "2010-03-11", - "Preferred-Value": "lvs", - "Prefix": [ - "lv" - ], - "Macrolanguage": "lv" - }, - { - "Type": "extlang", - "Subtag": "lws", - "Description": [ - "Malawian Sign Language" - ], - "Added": "2018-03-08", - "Preferred-Value": "lws", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "lzh", - "Description": [ - "Literary Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "lzh", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "max", - "Description": [ - "North Moluccan Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "max", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mdl", - "Description": [ - "Maltese Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mdl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "meo", - "Description": [ - "Kedah Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "meo", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mfa", - "Description": [ - "Pattani Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "mfa", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mfb", - "Description": [ - "Bangka" - ], - "Added": "2009-07-29", - "Preferred-Value": "mfb", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mfs", - "Description": [ - "Mexican Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mfs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "min", - "Description": [ - "Minangkabau" - ], - "Added": "2009-07-29", - "Preferred-Value": "min", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mnp", - "Description": [ - "Min Bei Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "mnp", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "mqg", - "Description": [ - "Kota Bangun Kutai Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "mqg", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mre", - "Description": [ - "Martha's Vineyard Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mre", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "msd", - "Description": [ - "Yucatec Maya Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "msd", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "msi", - "Description": [ - "Sabah Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "msi", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "msr", - "Description": [ - "Mongolian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "msr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "mui", - "Description": [ - "Musi" - ], - "Added": "2009-07-29", - "Preferred-Value": "mui", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "mzc", - "Description": [ - "Madagascar Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mzc", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "mzg", - "Description": [ - "Monastic Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mzg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "mzy", - "Description": [ - "Mozambican Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "mzy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nan", - "Description": [ - "Min Nan Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "nan", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "nbs", - "Description": [ - "Namibian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nbs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ncs", - "Description": [ - "Nicaraguan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ncs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nsi", - "Description": [ - "Nigerian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nsi", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nsl", - "Description": [ - "Norwegian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nsp", - "Description": [ - "Nepalese Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nsp", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nsr", - "Description": [ - "Maritime Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nsr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "nzs", - "Description": [ - "New Zealand Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "nzs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "okl", - "Description": [ - "Old Kentish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "okl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "orn", - "Description": [ - "Orang Kanaq" - ], - "Added": "2009-07-29", - "Preferred-Value": "orn", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "ors", - "Description": [ - "Orang Seletar" - ], - "Added": "2009-07-29", - "Preferred-Value": "ors", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "pel", - "Description": [ - "Pekal" - ], - "Added": "2009-07-29", - "Preferred-Value": "pel", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "pga", - "Description": [ - "Sudanese Creole Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "pga", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "pgz", - "Description": [ - "Papua New Guinean Sign Language" - ], - "Added": "2016-05-30", - "Preferred-Value": "pgz", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "pks", - "Description": [ - "Pakistan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "pks", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "prl", - "Description": [ - "Peruvian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "prl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "prz", - "Description": [ - "Providencia Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "prz", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "psc", - "Description": [ - "Iranian Sign Language", - "Persian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psc", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "psd", - "Description": [ - "Plains Indian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psd", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "pse", - "Description": [ - "Central Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "pse", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "psg", - "Description": [ - "Penang Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "psl", - "Description": [ - "Puerto Rican Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "pso", - "Description": [ - "Polish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "pso", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "psp", - "Description": [ - "Philippine Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psp", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "psr", - "Description": [ - "Portuguese Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "psr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "pys", - "Description": [ - "Paraguayan Sign Language", - "Lengua de Señas del Paraguay" - ], - "Added": "2010-03-11", - "Preferred-Value": "pys", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rib", - "Description": [ - "Bribri Sign Language" - ], - "Added": "2022-02-25", - "Preferred-Value": "rib", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rms", - "Description": [ - "Romanian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "rms", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rnb", - "Description": [ - "Brunca Sign Language" - ], - "Added": "2022-02-25", - "Preferred-Value": "rnb", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rsi", - "Description": [ - "Rennellese Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2017-02-23", - "Preferred-Value": "rsi", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rsl", - "Description": [ - "Russian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "rsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rsm", - "Description": [ - "Miriwoong Sign Language" - ], - "Added": "2016-05-30", - "Preferred-Value": "rsm", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "rsn", - "Description": [ - "Rwandan Sign Language" - ], - "Added": "2022-02-25", - "Preferred-Value": "rsn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sdl", - "Description": [ - "Saudi Arabian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sdl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sfb", - "Description": [ - "Langue des signes de Belgique Francophone", - "French Belgian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sfb", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sfs", - "Description": [ - "South African Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sfs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sgg", - "Description": [ - "Swiss-German Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sgg", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sgx", - "Description": [ - "Sierra Leone Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sgx", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "shu", - "Description": [ - "Chadian Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "shu", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "slf", - "Description": [ - "Swiss-Italian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "slf", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sls", - "Description": [ - "Singapore Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sls", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sqk", - "Description": [ - "Albanian Sign Language" - ], - "Added": "2012-08-12", - "Preferred-Value": "sqk", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sqs", - "Description": [ - "Sri Lankan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "sqs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "sqx", - "Description": [ - "Kufr Qassem Sign Language (KQSL)" - ], - "Added": "2021-02-20", - "Preferred-Value": "sqx", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ssh", - "Description": [ - "Shihhi Arabic" - ], - "Added": "2009-07-29", - "Preferred-Value": "ssh", - "Prefix": [ - "ar" - ], - "Macrolanguage": "ar" - }, - { - "Type": "extlang", - "Subtag": "ssp", - "Description": [ - "Spanish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ssp", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ssr", - "Description": [ - "Swiss-French Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ssr", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "svk", - "Description": [ - "Slovakian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "svk", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "swc", - "Description": [ - "Congo Swahili" - ], - "Added": "2009-07-29", - "Preferred-Value": "swc", - "Prefix": [ - "sw" - ], - "Macrolanguage": "sw" - }, - { - "Type": "extlang", - "Subtag": "swh", - "Description": [ - "Swahili (individual language)", - "Kiswahili" - ], - "Added": "2009-07-29", - "Preferred-Value": "swh", - "Prefix": [ - "sw" - ], - "Macrolanguage": "sw" - }, - { - "Type": "extlang", - "Subtag": "swl", - "Description": [ - "Swedish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "swl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "syy", - "Description": [ - "Al-Sayyid Bedouin Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "syy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "szs", - "Description": [ - "Solomon Islands Sign Language" - ], - "Added": "2017-02-23", - "Preferred-Value": "szs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tmw", - "Description": [ - "Temuan" - ], - "Added": "2009-07-29", - "Preferred-Value": "tmw", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "tse", - "Description": [ - "Tunisian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "tse", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tsm", - "Description": [ - "Turkish Sign Language", - "Türk İşaret Dili" - ], - "Added": "2009-07-29", - "Preferred-Value": "tsm", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tsq", - "Description": [ - "Thai Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "tsq", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tss", - "Description": [ - "Taiwan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "tss", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tsy", - "Description": [ - "Tebul Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "tsy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "tza", - "Description": [ - "Tanzanian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "tza", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ugn", - "Description": [ - "Ugandan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ugn", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ugy", - "Description": [ - "Uruguayan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ugy", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ukl", - "Description": [ - "Ukrainian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ukl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "uks", - "Description": [ - "Urubú-Kaapor Sign Language", - "Kaapor Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "uks", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "urk", - "Description": [ - "Urak Lawoi'" - ], - "Added": "2009-07-29", - "Preferred-Value": "urk", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "uzn", - "Description": [ - "Northern Uzbek" - ], - "Added": "2009-07-29", - "Preferred-Value": "uzn", - "Prefix": [ - "uz" - ], - "Macrolanguage": "uz" - }, - { - "Type": "extlang", - "Subtag": "uzs", - "Description": [ - "Southern Uzbek" - ], - "Added": "2009-07-29", - "Preferred-Value": "uzs", - "Prefix": [ - "uz" - ], - "Macrolanguage": "uz" - }, - { - "Type": "extlang", - "Subtag": "vgt", - "Description": [ - "Vlaamse Gebarentaal", - "Flemish Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "vgt", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "vkk", - "Description": [ - "Kaur" - ], - "Added": "2009-07-29", - "Preferred-Value": "vkk", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "vkt", - "Description": [ - "Tenggarong Kutai Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "vkt", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "vsi", - "Description": [ - "Moldova Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "vsi", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "vsl", - "Description": [ - "Venezuelan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "vsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "vsv", - "Description": [ - "Valencian Sign Language", - "Llengua de signes valenciana" - ], - "Added": "2009-07-29", - "Preferred-Value": "vsv", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "wbs", - "Description": [ - "West Bengal Sign Language" - ], - "Added": "2017-02-23", - "Preferred-Value": "wbs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "wuu", - "Description": [ - "Wu Chinese" - ], - "Added": "2009-07-29", - "Preferred-Value": "wuu", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "xki", - "Description": [ - "Kenyan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "xki", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "xml", - "Description": [ - "Malaysian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "xml", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "xmm", - "Description": [ - "Manado Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "xmm", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "xms", - "Description": [ - "Moroccan Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "xms", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "yds", - "Description": [ - "Yiddish Sign Language" - ], - "Added": "2009-07-29", - "Deprecated": "2015-02-12", - "Preferred-Value": "yds", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ygs", - "Description": [ - "YolÅ‹u Sign Language" - ], - "Added": "2014-02-28", - "Preferred-Value": "ygs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "yhs", - "Description": [ - "Yan-nhaÅ‹u Sign Language" - ], - "Added": "2015-04-17", - "Preferred-Value": "yhs", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ysl", - "Description": [ - "Yugoslavian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "ysl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "ysm", - "Description": [ - "Myanmar Sign Language" - ], - "Added": "2021-02-20", - "Preferred-Value": "ysm", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "yue", - "Description": [ - "Yue Chinese", - "Cantonese" - ], - "Added": "2009-07-29", - "Preferred-Value": "yue", - "Prefix": [ - "zh" - ], - "Macrolanguage": "zh" - }, - { - "Type": "extlang", - "Subtag": "zib", - "Description": [ - "Zimbabwe Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "zib", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "zlm", - "Description": [ - "Malay (individual language)" - ], - "Added": "2009-07-29", - "Preferred-Value": "zlm", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "zmi", - "Description": [ - "Negeri Sembilan Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "zmi", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "extlang", - "Subtag": "zsl", - "Description": [ - "Zambian Sign Language" - ], - "Added": "2009-07-29", - "Preferred-Value": "zsl", - "Prefix": [ - "sgn" - ] - }, - { - "Type": "extlang", - "Subtag": "zsm", - "Description": [ - "Standard Malay" - ], - "Added": "2009-07-29", - "Preferred-Value": "zsm", - "Prefix": [ - "ms" - ], - "Macrolanguage": "ms" - }, - { - "Type": "script", - "Subtag": "Adlm", - "Description": [ - "Adlam" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Afak", - "Description": [ - "Afaka" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Aghb", - "Description": [ - "Caucasian Albanian" - ], - "Added": "2012-11-01" - }, - { - "Type": "script", - "Subtag": "Ahom", - "Description": [ - "Ahom", - "Tai Ahom" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Arab", - "Description": [ - "Arabic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Aran", - "Description": [ - "Arabic (Nastaliq variant)" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Armi", - "Description": [ - "Imperial Aramaic" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Armn", - "Description": [ - "Armenian" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Avst", - "Description": [ - "Avestan" - ], - "Added": "2007-07-28" - }, - { - "Type": "script", - "Subtag": "Bali", - "Description": [ - "Balinese" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Bamu", - "Description": [ - "Bamum" - ], - "Added": "2009-07-30" - }, - { - "Type": "script", - "Subtag": "Bass", - "Description": [ - "Bassa Vah" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Batk", - "Description": [ - "Batak" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Beng", - "Description": [ - "Bengali", - "Bangla" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Bhks", - "Description": [ - "Bhaiksuki" - ], - "Added": "2015-07-24" - }, - { - "Type": "script", - "Subtag": "Blis", - "Description": [ - "Blissymbols" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Bopo", - "Description": [ - "Bopomofo" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Brah", - "Description": [ - "Brahmi" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Brai", - "Description": [ - "Braille" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Bugi", - "Description": [ - "Buginese" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Buhd", - "Description": [ - "Buhid" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cakm", - "Description": [ - "Chakma" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Cans", - "Description": [ - "Unified Canadian Aboriginal Syllabics" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cari", - "Description": [ - "Carian" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Cham", - "Description": [ - "Cham" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cher", - "Description": [ - "Cherokee" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Chrs", - "Description": [ - "Chorasmian" - ], - "Added": "2019-09-11" - }, - { - "Type": "script", - "Subtag": "Cirt", - "Description": [ - "Cirth" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Copt", - "Description": [ - "Coptic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cpmn", - "Description": [ - "Cypro-Minoan" - ], - "Added": "2017-08-13" - }, - { - "Type": "script", - "Subtag": "Cprt", - "Description": [ - "Cypriot syllabary" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cyrl", - "Description": [ - "Cyrillic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Cyrs", - "Description": [ - "Cyrillic (Old Church Slavonic variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Deva", - "Description": [ - "Devanagari", - "Nagari" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Diak", - "Description": [ - "Dives Akuru" - ], - "Added": "2019-09-11" - }, - { - "Type": "script", - "Subtag": "Dogr", - "Description": [ - "Dogra" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Dsrt", - "Description": [ - "Deseret", - "Mormon" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Dupl", - "Description": [ - "Duployan shorthand", - "Duployan stenography" - ], - "Added": "2010-08-16" - }, - { - "Type": "script", - "Subtag": "Egyd", - "Description": [ - "Egyptian demotic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Egyh", - "Description": [ - "Egyptian hieratic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Egyp", - "Description": [ - "Egyptian hieroglyphs" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Elba", - "Description": [ - "Elbasan" - ], - "Added": "2010-08-16" - }, - { - "Type": "script", - "Subtag": "Elym", - "Description": [ - "Elymaic" - ], - "Added": "2018-10-28" - }, - { - "Type": "script", - "Subtag": "Ethi", - "Description": [ - "Ethiopic", - "GeÊ»ez", - "Ge'ez" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Geok", - "Description": [ - "Khutsuri (Asomtavruli and Nuskhuri)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Geor", - "Description": [ - "Georgian (Mkhedruli and Mtavruli)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Glag", - "Description": [ - "Glagolitic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Gong", - "Description": [ - "Gunjala Gondi" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Gonm", - "Description": [ - "Masaram Gondi" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Goth", - "Description": [ - "Gothic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Gran", - "Description": [ - "Grantha" - ], - "Added": "2009-12-09" - }, - { - "Type": "script", - "Subtag": "Grek", - "Description": [ - "Greek" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Gujr", - "Description": [ - "Gujarati" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Guru", - "Description": [ - "Gurmukhi" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hanb", - "Description": [ - "Han with Bopomofo (alias for Han + Bopomofo)" - ], - "Added": "2016-02-08" - }, - { - "Type": "script", - "Subtag": "Hang", - "Description": [ - "Hangul", - "HangÅ­l", - "Hangeul" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hani", - "Description": [ - "Han", - "Hanzi", - "Kanji", - "Hanja" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hano", - "Description": [ - "Hanunoo", - "Hanunóo" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hans", - "Description": [ - "Han (Simplified variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hant", - "Description": [ - "Han (Traditional variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hatr", - "Description": [ - "Hatran" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Hebr", - "Description": [ - "Hebrew" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hira", - "Description": [ - "Hiragana" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hluw", - "Description": [ - "Anatolian Hieroglyphs", - "Luwian Hieroglyphs", - "Hittite Hieroglyphs" - ], - "Added": "2011-12-28" - }, - { - "Type": "script", - "Subtag": "Hmng", - "Description": [ - "Pahawh Hmong" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hmnp", - "Description": [ - "Nyiakeng Puachue Hmong" - ], - "Added": "2017-08-13" - }, - { - "Type": "script", - "Subtag": "Hrkt", - "Description": [ - "Japanese syllabaries (alias for Hiragana + Katakana)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Hung", - "Description": [ - "Old Hungarian", - "Hungarian Runic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Inds", - "Description": [ - "Indus", - "Harappan" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Ital", - "Description": [ - "Old Italic (Etruscan, Oscan, etc.)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Jamo", - "Description": [ - "Jamo (alias for Jamo subset of Hangul)" - ], - "Added": "2016-02-08" - }, - { - "Type": "script", - "Subtag": "Java", - "Description": [ - "Javanese" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Jpan", - "Description": [ - "Japanese (alias for Han + Hiragana + Katakana)" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Jurc", - "Description": [ - "Jurchen" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Kali", - "Description": [ - "Kayah Li" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Kana", - "Description": [ - "Katakana" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Kawi", - "Description": [ - "Kawi" - ], - "Added": "2021-12-24" - }, - { - "Type": "script", - "Subtag": "Khar", - "Description": [ - "Kharoshthi" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Khmr", - "Description": [ - "Khmer" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Khoj", - "Description": [ - "Khojki" - ], - "Added": "2011-08-16" - }, - { - "Type": "script", - "Subtag": "Kitl", - "Description": [ - "Khitan large script" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Kits", - "Description": [ - "Khitan small script" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Knda", - "Description": [ - "Kannada" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Kore", - "Description": [ - "Korean (alias for Hangul + Han)" - ], - "Added": "2007-07-05" - }, - { - "Type": "script", - "Subtag": "Kpel", - "Description": [ - "Kpelle" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Kthi", - "Description": [ - "Kaithi" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Lana", - "Description": [ - "Tai Tham", - "Lanna" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Laoo", - "Description": [ - "Lao" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Latf", - "Description": [ - "Latin (Fraktur variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Latg", - "Description": [ - "Latin (Gaelic variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Latn", - "Description": [ - "Latin" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Leke", - "Description": [ - "Leke" - ], - "Added": "2015-07-24" - }, - { - "Type": "script", - "Subtag": "Lepc", - "Description": [ - "Lepcha", - "Róng" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Limb", - "Description": [ - "Limbu" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Lina", - "Description": [ - "Linear A" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Linb", - "Description": [ - "Linear B" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Lisu", - "Description": [ - "Lisu", - "Fraser" - ], - "Added": "2009-03-13" - }, - { - "Type": "script", - "Subtag": "Loma", - "Description": [ - "Loma" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Lyci", - "Description": [ - "Lycian" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Lydi", - "Description": [ - "Lydian" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Mahj", - "Description": [ - "Mahajani" - ], - "Added": "2012-11-01" - }, - { - "Type": "script", - "Subtag": "Maka", - "Description": [ - "Makasar" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Mand", - "Description": [ - "Mandaic", - "Mandaean" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Mani", - "Description": [ - "Manichaean" - ], - "Added": "2007-07-28" - }, - { - "Type": "script", - "Subtag": "Marc", - "Description": [ - "Marchen" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Maya", - "Description": [ - "Mayan hieroglyphs" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Medf", - "Description": [ - "Medefaidrin", - "Oberi Okaime", - "Oberi ƆkaimÉ›" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Mend", - "Description": [ - "Mende Kikakui" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Merc", - "Description": [ - "Meroitic Cursive" - ], - "Added": "2009-12-09" - }, - { - "Type": "script", - "Subtag": "Mero", - "Description": [ - "Meroitic Hieroglyphs" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Mlym", - "Description": [ - "Malayalam" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Modi", - "Description": [ - "Modi", - "Moá¸Ä«" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Mong", - "Description": [ - "Mongolian" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Moon", - "Description": [ - "Moon", - "Moon code", - "Moon script", - "Moon type" - ], - "Added": "2007-01-26" - }, - { - "Type": "script", - "Subtag": "Mroo", - "Description": [ - "Mro", - "Mru" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Mtei", - "Description": [ - "Meitei Mayek", - "Meithei", - "Meetei" - ], - "Added": "2007-01-26" - }, - { - "Type": "script", - "Subtag": "Mult", - "Description": [ - "Multani" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Mymr", - "Description": [ - "Myanmar", - "Burmese" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Nagm", - "Description": [ - "Nag Mundari" - ], - "Added": "2021-12-24" - }, - { - "Type": "script", - "Subtag": "Nand", - "Description": [ - "Nandinagari" - ], - "Added": "2018-10-28" - }, - { - "Type": "script", - "Subtag": "Narb", - "Description": [ - "Old North Arabian", - "Ancient North Arabian" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Nbat", - "Description": [ - "Nabataean" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Newa", - "Description": [ - "Newa", - "Newar", - "Newari", - "NepÄla lipi" - ], - "Added": "2016-01-04" - }, - { - "Type": "script", - "Subtag": "Nkdb", - "Description": [ - "Naxi Dongba", - "na²¹ɕi³³ to³³ba²¹", - "Nakhi Tomba" - ], - "Added": "2017-08-13" - }, - { - "Type": "script", - "Subtag": "Nkgb", - "Description": [ - "Naxi Geba", - "na²¹ɕi³³ gʌ²¹ba²¹", - "'Na-'Khi ²GgÅ-¹baw", - "Nakhi Geba" - ], - "Added": "2009-03-13" - }, - { - "Type": "script", - "Subtag": "Nkoo", - "Description": [ - "N’Ko", - "N'Ko" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Nshu", - "Description": [ - "Nüshu" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Ogam", - "Description": [ - "Ogham" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Olck", - "Description": [ - "Ol Chiki", - "Ol Cemet'", - "Ol", - "Santali" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Orkh", - "Description": [ - "Old Turkic", - "Orkhon Runic" - ], - "Added": "2009-07-30" - }, - { - "Type": "script", - "Subtag": "Orya", - "Description": [ - "Oriya", - "Odia" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Osge", - "Description": [ - "Osage" - ], - "Added": "2014-12-11" - }, - { - "Type": "script", - "Subtag": "Osma", - "Description": [ - "Osmanya" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Ougr", - "Description": [ - "Old Uyghur" - ], - "Added": "2021-02-12" - }, - { - "Type": "script", - "Subtag": "Palm", - "Description": [ - "Palmyrene" - ], - "Added": "2010-04-10" - }, - { - "Type": "script", - "Subtag": "Pauc", - "Description": [ - "Pau Cin Hau" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Pcun", - "Description": [ - "Proto-Cuneiform" - ], - "Added": "2021-02-12" - }, - { - "Type": "script", - "Subtag": "Pelm", - "Description": [ - "Proto-Elamite" - ], - "Added": "2021-02-12" - }, - { - "Type": "script", - "Subtag": "Perm", - "Description": [ - "Old Permic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Phag", - "Description": [ - "Phags-pa" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Phli", - "Description": [ - "Inscriptional Pahlavi" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Phlp", - "Description": [ - "Psalter Pahlavi" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Phlv", - "Description": [ - "Book Pahlavi" - ], - "Added": "2007-07-28" - }, - { - "Type": "script", - "Subtag": "Phnx", - "Description": [ - "Phoenician" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Piqd", - "Description": [ - "Klingon (KLI pIqaD)" - ], - "Added": "2016-01-04" - }, - { - "Type": "script", - "Subtag": "Plrd", - "Description": [ - "Miao", - "Pollard" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Prti", - "Description": [ - "Inscriptional Parthian" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Psin", - "Description": [ - "Proto-Sinaitic" - ], - "Added": "2021-02-12" - }, - { - "Type": "script", - "Subtag": "Qaaa..Qabx", - "Description": [ - "Private use" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Ranj", - "Description": [ - "Ranjana" - ], - "Added": "2021-02-12" - }, - { - "Type": "script", - "Subtag": "Rjng", - "Description": [ - "Rejang", - "Redjang", - "Kaganga" - ], - "Added": "2006-10-17" - }, - { - "Type": "script", - "Subtag": "Rohg", - "Description": [ - "Hanifi Rohingya" - ], - "Added": "2017-12-13" - }, - { - "Type": "script", - "Subtag": "Roro", - "Description": [ - "Rongorongo" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Runr", - "Description": [ - "Runic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Samr", - "Description": [ - "Samaritan" - ], - "Added": "2007-07-28" - }, - { - "Type": "script", - "Subtag": "Sara", - "Description": [ - "Sarati" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Sarb", - "Description": [ - "Old South Arabian" - ], - "Added": "2009-07-30" - }, - { - "Type": "script", - "Subtag": "Saur", - "Description": [ - "Saurashtra" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Sgnw", - "Description": [ - "SignWriting" - ], - "Added": "2006-10-17" - }, - { - "Type": "script", - "Subtag": "Shaw", - "Description": [ - "Shavian", - "Shaw" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Shrd", - "Description": [ - "Sharada", - "ÅšÄradÄ" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Shui", - "Description": [ - "Shuishu" - ], - "Added": "2017-08-13" - }, - { - "Type": "script", - "Subtag": "Sidd", - "Description": [ - "Siddham", - "Siddhaṃ", - "SiddhamÄtá¹›kÄ" - ], - "Added": "2013-12-02" - }, - { - "Type": "script", - "Subtag": "Sind", - "Description": [ - "Khudawadi", - "Sindhi" - ], - "Added": "2010-08-16" - }, - { - "Type": "script", - "Subtag": "Sinh", - "Description": [ - "Sinhala" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Sogd", - "Description": [ - "Sogdian" - ], - "Added": "2017-12-13" - }, - { - "Type": "script", - "Subtag": "Sogo", - "Description": [ - "Old Sogdian" - ], - "Added": "2017-12-13" - }, - { - "Type": "script", - "Subtag": "Sora", - "Description": [ - "Sora Sompeng" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Soyo", - "Description": [ - "Soyombo" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Sund", - "Description": [ - "Sundanese" - ], - "Added": "2006-07-21" - }, - { - "Type": "script", - "Subtag": "Sunu", - "Description": [ - "Sunuwar" - ], - "Added": "2021-12-24" - }, - { - "Type": "script", - "Subtag": "Sylo", - "Description": [ - "Syloti Nagri" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Syrc", - "Description": [ - "Syriac" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Syre", - "Description": [ - "Syriac (Estrangelo variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Syrj", - "Description": [ - "Syriac (Western variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Syrn", - "Description": [ - "Syriac (Eastern variant)" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tagb", - "Description": [ - "Tagbanwa" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Takr", - "Description": [ - "Takri", - "ṬÄkrÄ«", - "ṬÄá¹…krÄ«" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Tale", - "Description": [ - "Tai Le" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Talu", - "Description": [ - "New Tai Lue" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Taml", - "Description": [ - "Tamil" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tang", - "Description": [ - "Tangut" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Tavt", - "Description": [ - "Tai Viet" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Telu", - "Description": [ - "Telugu" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Teng", - "Description": [ - "Tengwar" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tfng", - "Description": [ - "Tifinagh", - "Berber" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tglg", - "Description": [ - "Tagalog", - "Baybayin", - "Alibata" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Thaa", - "Description": [ - "Thaana" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Thai", - "Description": [ - "Thai" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tibt", - "Description": [ - "Tibetan" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Tirh", - "Description": [ - "Tirhuta" - ], - "Added": "2011-08-16" - }, - { - "Type": "script", - "Subtag": "Tnsa", - "Description": [ - "Tangsa" - ], - "Added": "2021-03-05" - }, - { - "Type": "script", - "Subtag": "Toto", - "Description": [ - "Toto" - ], - "Added": "2020-05-12" - }, - { - "Type": "script", - "Subtag": "Ugar", - "Description": [ - "Ugaritic" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Vaii", - "Description": [ - "Vai" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Visp", - "Description": [ - "Visible Speech" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Vith", - "Description": [ - "Vithkuqi" - ], - "Added": "2021-03-05" - }, - { - "Type": "script", - "Subtag": "Wara", - "Description": [ - "Warang Citi", - "Varang Kshiti" - ], - "Added": "2009-12-09" - }, - { - "Type": "script", - "Subtag": "Wcho", - "Description": [ - "Wancho" - ], - "Added": "2017-08-13" - }, - { - "Type": "script", - "Subtag": "Wole", - "Description": [ - "Woleai" - ], - "Added": "2011-01-07" - }, - { - "Type": "script", - "Subtag": "Xpeo", - "Description": [ - "Old Persian" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Xsux", - "Description": [ - "Sumero-Akkadian cuneiform" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Yezi", - "Description": [ - "Yezidi" - ], - "Added": "2019-09-11" - }, - { - "Type": "script", - "Subtag": "Yiii", - "Description": [ - "Yi" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Zanb", - "Description": [ - "Zanabazar Square", - "Zanabazarin Dörböljin Useg", - "Xewtee Dörböljin Bicig", - "Horizontal Square Script" - ], - "Added": "2017-01-13" - }, - { - "Type": "script", - "Subtag": "Zinh", - "Description": [ - "Code for inherited script" - ], - "Added": "2009-04-03", - "Comments": [ - "Not intended for use as a language subtag" - ] - }, - { - "Type": "script", - "Subtag": "Zmth", - "Description": [ - "Mathematical notation" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Zsye", - "Description": [ - "Symbols (Emoji variant)" - ], - "Added": "2016-01-04" - }, - { - "Type": "script", - "Subtag": "Zsym", - "Description": [ - "Symbols" - ], - "Added": "2007-12-05" - }, - { - "Type": "script", - "Subtag": "Zxxx", - "Description": [ - "Code for unwritten documents" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Zyyy", - "Description": [ - "Code for undetermined script" - ], - "Added": "2005-10-16" - }, - { - "Type": "script", - "Subtag": "Zzzz", - "Description": [ - "Code for uncoded script" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AA", - "Description": [ - "Private use" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AC", - "Description": [ - "Ascension Island" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "AD", - "Description": [ - "Andorra" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AE", - "Description": [ - "United Arab Emirates" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AF", - "Description": [ - "Afghanistan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AG", - "Description": [ - "Antigua and Barbuda" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AI", - "Description": [ - "Anguilla" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AL", - "Description": [ - "Albania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AM", - "Description": [ - "Armenia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AN", - "Description": [ - "Netherlands Antilles" - ], - "Added": "2005-10-16", - "Deprecated": "2011-01-07", - "Comments": [ - "see BQ, CW, and SX" - ] - }, - { - "Type": "region", - "Subtag": "AO", - "Description": [ - "Angola" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AQ", - "Description": [ - "Antarctica" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AR", - "Description": [ - "Argentina" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AS", - "Description": [ - "American Samoa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AT", - "Description": [ - "Austria" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AU", - "Description": [ - "Australia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AW", - "Description": [ - "Aruba" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AX", - "Description": [ - "Ã…land Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "AZ", - "Description": [ - "Azerbaijan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BA", - "Description": [ - "Bosnia and Herzegovina" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BB", - "Description": [ - "Barbados" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BD", - "Description": [ - "Bangladesh" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BE", - "Description": [ - "Belgium" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BF", - "Description": [ - "Burkina Faso" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BG", - "Description": [ - "Bulgaria" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BH", - "Description": [ - "Bahrain" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BI", - "Description": [ - "Burundi" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BJ", - "Description": [ - "Benin" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BL", - "Description": [ - "Saint Barthélemy" - ], - "Added": "2007-11-02" - }, - { - "Type": "region", - "Subtag": "BM", - "Description": [ - "Bermuda" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BN", - "Description": [ - "Brunei Darussalam" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BO", - "Description": [ - "Bolivia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BQ", - "Description": [ - "Bonaire, Sint Eustatius and Saba" - ], - "Added": "2011-01-07" - }, - { - "Type": "region", - "Subtag": "BR", - "Description": [ - "Brazil" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BS", - "Description": [ - "Bahamas" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BT", - "Description": [ - "Bhutan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BU", - "Description": [ - "Burma" - ], - "Added": "2005-10-16", - "Deprecated": "1989-12-05", - "Preferred-Value": "MM" - }, - { - "Type": "region", - "Subtag": "BV", - "Description": [ - "Bouvet Island" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BW", - "Description": [ - "Botswana" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BY", - "Description": [ - "Belarus" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "BZ", - "Description": [ - "Belize" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CA", - "Description": [ - "Canada" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CC", - "Description": [ - "Cocos (Keeling) Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CD", - "Description": [ - "The Democratic Republic of the Congo" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CF", - "Description": [ - "Central African Republic" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CG", - "Description": [ - "Congo" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CH", - "Description": [ - "Switzerland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CI", - "Description": [ - "Côte d'Ivoire" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CK", - "Description": [ - "Cook Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CL", - "Description": [ - "Chile" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CM", - "Description": [ - "Cameroon" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CN", - "Description": [ - "China" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CO", - "Description": [ - "Colombia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CP", - "Description": [ - "Clipperton Island" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "CR", - "Description": [ - "Costa Rica" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CS", - "Description": [ - "Serbia and Montenegro" - ], - "Added": "2005-10-16", - "Deprecated": "2006-10-05", - "Comments": [ - "see RS for Serbia or ME for Montenegro" - ] - }, - { - "Type": "region", - "Subtag": "CU", - "Description": [ - "Cuba" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CV", - "Description": [ - "Cabo Verde", - "Cape Verde" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CW", - "Description": [ - "Curaçao" - ], - "Added": "2011-01-07" - }, - { - "Type": "region", - "Subtag": "CX", - "Description": [ - "Christmas Island" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CY", - "Description": [ - "Cyprus" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "CZ", - "Description": [ - "Czechia", - "Czech Republic" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DD", - "Description": [ - "German Democratic Republic" - ], - "Added": "2005-10-16", - "Deprecated": "1990-10-30", - "Preferred-Value": "DE" - }, - { - "Type": "region", - "Subtag": "DE", - "Description": [ - "Germany" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DG", - "Description": [ - "Diego Garcia" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "DJ", - "Description": [ - "Djibouti" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DK", - "Description": [ - "Denmark" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DM", - "Description": [ - "Dominica" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DO", - "Description": [ - "Dominican Republic" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "DZ", - "Description": [ - "Algeria" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "EA", - "Description": [ - "Ceuta, Melilla" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "EC", - "Description": [ - "Ecuador" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "EE", - "Description": [ - "Estonia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "EG", - "Description": [ - "Egypt" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "EH", - "Description": [ - "Western Sahara" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ER", - "Description": [ - "Eritrea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ES", - "Description": [ - "Spain" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ET", - "Description": [ - "Ethiopia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "EU", - "Description": [ - "European Union" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "EZ", - "Description": [ - "Eurozone" - ], - "Added": "2016-07-14" - }, - { - "Type": "region", - "Subtag": "FI", - "Description": [ - "Finland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FJ", - "Description": [ - "Fiji" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FK", - "Description": [ - "Falkland Islands (Malvinas)" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FM", - "Description": [ - "Federated States of Micronesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FO", - "Description": [ - "Faroe Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FR", - "Description": [ - "France" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "FX", - "Description": [ - "Metropolitan France" - ], - "Added": "2005-10-16", - "Deprecated": "1997-07-14", - "Preferred-Value": "FR" - }, - { - "Type": "region", - "Subtag": "GA", - "Description": [ - "Gabon" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GB", - "Description": [ - "United Kingdom" - ], - "Added": "2005-10-16", - "Comments": [ - "as of 2006-03-29 GB no longer includes the Channel Islands and Isle of Man; see GG, JE, IM" - ] - }, - { - "Type": "region", - "Subtag": "GD", - "Description": [ - "Grenada" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GE", - "Description": [ - "Georgia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GF", - "Description": [ - "French Guiana" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GG", - "Description": [ - "Guernsey" - ], - "Added": "2006-03-29" - }, - { - "Type": "region", - "Subtag": "GH", - "Description": [ - "Ghana" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GI", - "Description": [ - "Gibraltar" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GL", - "Description": [ - "Greenland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GM", - "Description": [ - "Gambia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GN", - "Description": [ - "Guinea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GP", - "Description": [ - "Guadeloupe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GQ", - "Description": [ - "Equatorial Guinea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GR", - "Description": [ - "Greece" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GS", - "Description": [ - "South Georgia and the South Sandwich Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GT", - "Description": [ - "Guatemala" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GU", - "Description": [ - "Guam" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GW", - "Description": [ - "Guinea-Bissau" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "GY", - "Description": [ - "Guyana" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HK", - "Description": [ - "Hong Kong" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HM", - "Description": [ - "Heard Island and McDonald Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HN", - "Description": [ - "Honduras" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HR", - "Description": [ - "Croatia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HT", - "Description": [ - "Haiti" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "HU", - "Description": [ - "Hungary" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IC", - "Description": [ - "Canary Islands" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "ID", - "Description": [ - "Indonesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IE", - "Description": [ - "Ireland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IL", - "Description": [ - "Israel" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IM", - "Description": [ - "Isle of Man" - ], - "Added": "2006-03-29" - }, - { - "Type": "region", - "Subtag": "IN", - "Description": [ - "India" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IO", - "Description": [ - "British Indian Ocean Territory" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IQ", - "Description": [ - "Iraq" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IR", - "Description": [ - "Islamic Republic of Iran" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IS", - "Description": [ - "Iceland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "IT", - "Description": [ - "Italy" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "JE", - "Description": [ - "Jersey" - ], - "Added": "2006-03-29" - }, - { - "Type": "region", - "Subtag": "JM", - "Description": [ - "Jamaica" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "JO", - "Description": [ - "Jordan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "JP", - "Description": [ - "Japan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KE", - "Description": [ - "Kenya" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KG", - "Description": [ - "Kyrgyzstan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KH", - "Description": [ - "Cambodia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KI", - "Description": [ - "Kiribati" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KM", - "Description": [ - "Comoros" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KN", - "Description": [ - "Saint Kitts and Nevis" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KP", - "Description": [ - "Democratic People's Republic of Korea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KR", - "Description": [ - "Republic of Korea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KW", - "Description": [ - "Kuwait" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KY", - "Description": [ - "Cayman Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "KZ", - "Description": [ - "Kazakhstan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LA", - "Description": [ - "Lao People's Democratic Republic" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LB", - "Description": [ - "Lebanon" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LC", - "Description": [ - "Saint Lucia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LI", - "Description": [ - "Liechtenstein" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LK", - "Description": [ - "Sri Lanka" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LR", - "Description": [ - "Liberia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LS", - "Description": [ - "Lesotho" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LT", - "Description": [ - "Lithuania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LU", - "Description": [ - "Luxembourg" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LV", - "Description": [ - "Latvia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "LY", - "Description": [ - "Libya" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MA", - "Description": [ - "Morocco" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MC", - "Description": [ - "Monaco" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MD", - "Description": [ - "Moldova" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ME", - "Description": [ - "Montenegro" - ], - "Added": "2006-10-05" - }, - { - "Type": "region", - "Subtag": "MF", - "Description": [ - "Saint Martin (French part)" - ], - "Added": "2007-11-02" - }, - { - "Type": "region", - "Subtag": "MG", - "Description": [ - "Madagascar" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MH", - "Description": [ - "Marshall Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MK", - "Description": [ - "North Macedonia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ML", - "Description": [ - "Mali" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MM", - "Description": [ - "Myanmar" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MN", - "Description": [ - "Mongolia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MO", - "Description": [ - "Macao" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MP", - "Description": [ - "Northern Mariana Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MQ", - "Description": [ - "Martinique" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MR", - "Description": [ - "Mauritania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MS", - "Description": [ - "Montserrat" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MT", - "Description": [ - "Malta" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MU", - "Description": [ - "Mauritius" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MV", - "Description": [ - "Maldives" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MW", - "Description": [ - "Malawi" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MX", - "Description": [ - "Mexico" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MY", - "Description": [ - "Malaysia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "MZ", - "Description": [ - "Mozambique" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NA", - "Description": [ - "Namibia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NC", - "Description": [ - "New Caledonia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NE", - "Description": [ - "Niger" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NF", - "Description": [ - "Norfolk Island" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NG", - "Description": [ - "Nigeria" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NI", - "Description": [ - "Nicaragua" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NL", - "Description": [ - "Netherlands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NO", - "Description": [ - "Norway" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NP", - "Description": [ - "Nepal" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NR", - "Description": [ - "Nauru" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NT", - "Description": [ - "Neutral Zone" - ], - "Added": "2005-10-16", - "Deprecated": "1993-07-12" - }, - { - "Type": "region", - "Subtag": "NU", - "Description": [ - "Niue" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "NZ", - "Description": [ - "New Zealand" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "OM", - "Description": [ - "Oman" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PA", - "Description": [ - "Panama" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PE", - "Description": [ - "Peru" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PF", - "Description": [ - "French Polynesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PG", - "Description": [ - "Papua New Guinea" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PH", - "Description": [ - "Philippines" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PK", - "Description": [ - "Pakistan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PL", - "Description": [ - "Poland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PM", - "Description": [ - "Saint Pierre and Miquelon" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PN", - "Description": [ - "Pitcairn" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PR", - "Description": [ - "Puerto Rico" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PS", - "Description": [ - "State of Palestine" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PT", - "Description": [ - "Portugal" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PW", - "Description": [ - "Palau" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "PY", - "Description": [ - "Paraguay" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "QA", - "Description": [ - "Qatar" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "QM..QZ", - "Description": [ - "Private use" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "RE", - "Description": [ - "Réunion" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "RO", - "Description": [ - "Romania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "RS", - "Description": [ - "Serbia" - ], - "Added": "2006-10-05" - }, - { - "Type": "region", - "Subtag": "RU", - "Description": [ - "Russian Federation" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "RW", - "Description": [ - "Rwanda" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SA", - "Description": [ - "Saudi Arabia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SB", - "Description": [ - "Solomon Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SC", - "Description": [ - "Seychelles" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SD", - "Description": [ - "Sudan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SE", - "Description": [ - "Sweden" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SG", - "Description": [ - "Singapore" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SH", - "Description": [ - "Saint Helena, Ascension and Tristan da Cunha" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SI", - "Description": [ - "Slovenia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SJ", - "Description": [ - "Svalbard and Jan Mayen" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SK", - "Description": [ - "Slovakia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SL", - "Description": [ - "Sierra Leone" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SM", - "Description": [ - "San Marino" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SN", - "Description": [ - "Senegal" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SO", - "Description": [ - "Somalia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SR", - "Description": [ - "Suriname" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SS", - "Description": [ - "South Sudan" - ], - "Added": "2011-08-25" - }, - { - "Type": "region", - "Subtag": "ST", - "Description": [ - "Sao Tome and Principe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SU", - "Description": [ - "Union of Soviet Socialist Republics" - ], - "Added": "2005-10-16", - "Deprecated": "1992-08-30" - }, - { - "Type": "region", - "Subtag": "SV", - "Description": [ - "El Salvador" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SX", - "Description": [ - "Sint Maarten (Dutch part)" - ], - "Added": "2011-01-07" - }, - { - "Type": "region", - "Subtag": "SY", - "Description": [ - "Syrian Arab Republic" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "SZ", - "Description": [ - "Eswatini", - "eSwatini", - "Swaziland" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TA", - "Description": [ - "Tristan da Cunha" - ], - "Added": "2009-07-29" - }, - { - "Type": "region", - "Subtag": "TC", - "Description": [ - "Turks and Caicos Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TD", - "Description": [ - "Chad" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TF", - "Description": [ - "French Southern Territories" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TG", - "Description": [ - "Togo" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TH", - "Description": [ - "Thailand" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TJ", - "Description": [ - "Tajikistan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TK", - "Description": [ - "Tokelau" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TL", - "Description": [ - "Timor-Leste" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TM", - "Description": [ - "Turkmenistan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TN", - "Description": [ - "Tunisia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TO", - "Description": [ - "Tonga" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TP", - "Description": [ - "East Timor" - ], - "Added": "2005-10-16", - "Deprecated": "2002-05-20", - "Preferred-Value": "TL" - }, - { - "Type": "region", - "Subtag": "TR", - "Description": [ - "Turkey" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TT", - "Description": [ - "Trinidad and Tobago" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TV", - "Description": [ - "Tuvalu" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TW", - "Description": [ - "Taiwan, Province of China" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "TZ", - "Description": [ - "United Republic of Tanzania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UA", - "Description": [ - "Ukraine" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UG", - "Description": [ - "Uganda" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UM", - "Description": [ - "United States Minor Outlying Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UN", - "Description": [ - "United Nations" - ], - "Added": "2016-07-14" - }, - { - "Type": "region", - "Subtag": "US", - "Description": [ - "United States" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UY", - "Description": [ - "Uruguay" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "UZ", - "Description": [ - "Uzbekistan" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VA", - "Description": [ - "Holy See (Vatican City State)" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VC", - "Description": [ - "Saint Vincent and the Grenadines" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VE", - "Description": [ - "Venezuela" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VG", - "Description": [ - "British Virgin Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VI", - "Description": [ - "U.S. Virgin Islands" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VN", - "Description": [ - "Viet Nam" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "VU", - "Description": [ - "Vanuatu" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "WF", - "Description": [ - "Wallis and Futuna" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "WS", - "Description": [ - "Samoa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "XA..XZ", - "Description": [ - "Private use" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "YD", - "Description": [ - "Democratic Yemen" - ], - "Added": "2005-10-16", - "Deprecated": "1990-08-14", - "Preferred-Value": "YE" - }, - { - "Type": "region", - "Subtag": "YE", - "Description": [ - "Yemen" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "YT", - "Description": [ - "Mayotte" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "YU", - "Description": [ - "Yugoslavia" - ], - "Added": "2005-10-16", - "Deprecated": "2003-07-23", - "Comments": [ - "see BA, HR, ME, MK, RS, or SI" - ] - }, - { - "Type": "region", - "Subtag": "ZA", - "Description": [ - "South Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ZM", - "Description": [ - "Zambia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ZR", - "Description": [ - "Zaire" - ], - "Added": "2005-10-16", - "Deprecated": "1997-07-14", - "Preferred-Value": "CD" - }, - { - "Type": "region", - "Subtag": "ZW", - "Description": [ - "Zimbabwe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "ZZ", - "Description": [ - "Private use" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "001", - "Description": [ - "World" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "002", - "Description": [ - "Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "003", - "Description": [ - "North America" - ], - "Added": "2010-08-16", - "Comments": [ - "Includes Northern America (021), Caribbean (029), and Central America (013); see also 021" - ] - }, - { - "Type": "region", - "Subtag": "005", - "Description": [ - "South America" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "009", - "Description": [ - "Oceania" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "011", - "Description": [ - "Western Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "013", - "Description": [ - "Central America" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "014", - "Description": [ - "Eastern Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "015", - "Description": [ - "Northern Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "017", - "Description": [ - "Middle Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "018", - "Description": [ - "Southern Africa" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "019", - "Description": [ - "Americas" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "021", - "Description": [ - "Northern America" - ], - "Added": "2005-10-16", - "Comments": [ - "Does not include Caribbean (029) or Central America (013); see also 003" - ] - }, - { - "Type": "region", - "Subtag": "029", - "Description": [ - "Caribbean" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "030", - "Description": [ - "Eastern Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "034", - "Description": [ - "Southern Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "035", - "Description": [ - "South-Eastern Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "039", - "Description": [ - "Southern Europe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "053", - "Description": [ - "Australia and New Zealand" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "054", - "Description": [ - "Melanesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "057", - "Description": [ - "Micronesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "061", - "Description": [ - "Polynesia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "142", - "Description": [ - "Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "143", - "Description": [ - "Central Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "145", - "Description": [ - "Western Asia" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "150", - "Description": [ - "Europe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "151", - "Description": [ - "Eastern Europe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "154", - "Description": [ - "Northern Europe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "155", - "Description": [ - "Western Europe" - ], - "Added": "2005-10-16" - }, - { - "Type": "region", - "Subtag": "202", - "Description": [ - "Sub-Saharan Africa" - ], - "Added": "2017-04-18" - }, - { - "Type": "region", - "Subtag": "419", - "Description": [ - "Latin America and the Caribbean" - ], - "Added": "2005-10-16" - }, - { - "Type": "variant", - "Subtag": "1606nict", - "Description": [ - "Late Middle French (to 1606)" - ], - "Added": "2007-03-20", - "Prefix": [ - "frm" - ], - "Comments": [ - "16th century French as in Jean Nicot, \"Thresor de la langue francoyse\", 1606, but also including some French similar to that of Rabelais" - ] - }, - { - "Type": "variant", - "Subtag": "1694acad", - "Description": [ - "Early Modern French" - ], - "Added": "2007-03-20", - "Prefix": [ - "fr" - ], - "Comments": [ - "17th century French, as catalogued in the \"Dictionnaire de l'académie françoise\", 4eme ed. 1694; frequently includes elements of Middle French, as this is a transitional period" - ] - }, - { - "Type": "variant", - "Subtag": "1901", - "Description": [ - "Traditional German orthography" - ], - "Added": "2005-10-16", - "Prefix": [ - "de" - ] - }, - { - "Type": "variant", - "Subtag": "1959acad", - "Description": [ - "\"Academic\" (\"governmental\") variant of Belarusian as codified in 1959" - ], - "Added": "2008-09-30", - "Prefix": [ - "be" - ] - }, - { - "Type": "variant", - "Subtag": "1994", - "Description": [ - "Standardized Resian orthography" - ], - "Added": "2007-07-28", - "Prefix": [ - "sl-rozaj", - "sl-rozaj-biske", - "sl-rozaj-njiva", - "sl-rozaj-osojs", - "sl-rozaj-solba" - ], - "Comments": [ - "For standardized Resian an orthography was published in 1994." - ] - }, - { - "Type": "variant", - "Subtag": "1996", - "Description": [ - "German orthography of 1996" - ], - "Added": "2005-10-16", - "Prefix": [ - "de" - ] - }, - { - "Type": "variant", - "Subtag": "abl1943", - "Description": [ - "Orthographic formulation of 1943 - Official in Brazil (Formulário Ortográfico de 1943 - Oficial no Brasil)" - ], - "Added": "2015-05-06", - "Prefix": [ - "pt-BR" - ], - "Comments": [ - "Denotes conventions established by the Academia Brasileira de Letras in 1943 and generally used in Brazil until 2009" - ] - }, - { - "Type": "variant", - "Subtag": "akuapem", - "Description": [ - "Akuapem Twi" - ], - "Added": "2017-06-05", - "Prefix": [ - "tw" - ] - }, - { - "Type": "variant", - "Subtag": "alalc97", - "Description": [ - "ALA-LC Romanization, 1997 edition" - ], - "Added": "2009-12-09", - "Comments": [ - "Romanizations recommended by the American Library Association and the Library of Congress, in \"ALA-LC Romanization Tables: Transliteration Schemes for Non-Roman Scripts\" (1997), ISBN 978-0-8444-0940-5." - ] - }, - { - "Type": "variant", - "Subtag": "aluku", - "Description": [ - "Aluku dialect", - "Boni dialect" - ], - "Added": "2009-09-05", - "Prefix": [ - "djk" - ], - "Comments": [ - "Aluku dialect of the \"Busi Nenge Tongo\" English-based Creole continuum in Eastern Suriname and Western French Guiana" - ] - }, - { - "Type": "variant", - "Subtag": "ao1990", - "Description": [ - "Portuguese Language Orthographic Agreement of 1990 (Acordo Ortográfico da Língua Portuguesa de 1990)" - ], - "Added": "2015-05-06", - "Prefix": [ - "pt", - "gl" - ], - "Comments": [ - "Portuguese orthography conventions established in 1990 but not brought into effect until 2009" - ] - }, - { - "Type": "variant", - "Subtag": "aranes", - "Description": [ - "Aranese" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in the Val d'Aran" - ] - }, - { - "Type": "variant", - "Subtag": "arevela", - "Description": [ - "Eastern Armenian" - ], - "Added": "2006-09-18", - "Deprecated": "2018-03-24", - "Prefix": [ - "hy" - ], - "Comments": [ - "Preferred tag is hy" - ] - }, - { - "Type": "variant", - "Subtag": "arevmda", - "Description": [ - "Western Armenian" - ], - "Added": "2006-09-18", - "Deprecated": "2018-03-24", - "Prefix": [ - "hy" - ], - "Comments": [ - "Preferred tag is hyw" - ] - }, - { - "Type": "variant", - "Subtag": "arkaika", - "Description": [ - "Arcaicam Esperantom", - "Arkaika Esperanto" - ], - "Added": "2020-12-17", - "Prefix": [ - "eo" - ], - "Comments": [ - "Archaic Esperanto variant devised by Manuel Halvelik" - ] - }, - { - "Type": "variant", - "Subtag": "asante", - "Description": [ - "Asante Twi", - "Ashanti Twi" - ], - "Added": "2017-06-05", - "Prefix": [ - "tw" - ] - }, - { - "Type": "variant", - "Subtag": "auvern", - "Description": [ - "Auvergnat" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Auvergne" - ] - }, - { - "Type": "variant", - "Subtag": "baku1926", - "Description": [ - "Unified Turkic Latin Alphabet (Historical)" - ], - "Added": "2007-04-18", - "Prefix": [ - "az", - "ba", - "crh", - "kk", - "krc", - "ky", - "sah", - "tk", - "tt", - "uz" - ], - "Comments": [ - "Denotes alphabet used in Turkic republics/regions of the former USSR in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. Also known as: New Turkic Alphabet; BirlәşdirilmiÅŸ Jeni Tyrk Ó˜lifbasÑŒ (Birlesdirilmis Jeni Tyrk Elifbasi); JaÅ‹alif (Janalif)." - ] - }, - { - "Type": "variant", - "Subtag": "balanka", - "Description": [ - "The Balanka dialect of Anii" - ], - "Added": "2014-02-15", - "Prefix": [ - "blo" - ], - "Comments": [ - "Balanka is one of 19 Anii dialects." - ] - }, - { - "Type": "variant", - "Subtag": "barla", - "Description": [ - "The Barlavento dialect group of Kabuverdianu" - ], - "Prefix": [ - "kea" - ], - "Comments": [ - "Barlavento is one of the two main dialect groups of Kabuverdianu." - ], - "Added": "2013-12-10" - }, - { - "Type": "variant", - "Subtag": "basiceng", - "Description": [ - "Basic English" - ], - "Added": "2015-12-29", - "Prefix": [ - "en" - ] - }, - { - "Type": "variant", - "Subtag": "bauddha", - "Description": [ - "Buddhist Hybrid Sanskrit" - ], - "Added": "2010-07-28", - "Prefix": [ - "sa" - ] - }, - { - "Type": "variant", - "Subtag": "biscayan", - "Description": [ - "Biscayan dialect of Basque" - ], - "Added": "2010-04-13", - "Prefix": [ - "eu" - ] - }, - { - "Type": "variant", - "Subtag": "biske", - "Description": [ - "The San Giorgio dialect of Resian", - "The Bila dialect of Resian" - ], - "Added": "2007-07-05", - "Prefix": [ - "sl-rozaj" - ], - "Comments": [ - "The dialect of San Giorgio/Bila is one of the four major local dialects of Resian" - ] - }, - { - "Type": "variant", - "Subtag": "bohoric", - "Description": [ - "Slovene in BohoriÄ alphabet" - ], - "Added": "2012-06-27", - "Prefix": [ - "sl" - ], - "Comments": [ - "The subtag represents the alphabet codified by Adam BohoriÄ in 1584 and used from the first printed Slovene book and up to the mid-19th century." - ] - }, - { - "Type": "variant", - "Subtag": "boont", - "Description": [ - "Boontling" - ], - "Added": "2006-09-18", - "Prefix": [ - "en" - ], - "Comments": [ - "Jargon embedded in American English" - ] - }, - { - "Type": "variant", - "Subtag": "bornholm", - "Description": [ - "Bornholmsk" - ], - "Added": "2019-03-27", - "Prefix": [ - "da" - ] - }, - { - "Type": "variant", - "Subtag": "cisaup", - "Description": [ - "Cisalpine" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in northwestern Italy" - ] - }, - { - "Type": "variant", - "Subtag": "colb1945", - "Description": [ - "Portuguese-Brazilian Orthographic Convention of 1945 (Convenção Ortográfica Luso-Brasileira de 1945)" - ], - "Added": "2015-05-06", - "Prefix": [ - "pt" - ], - "Comments": [ - "Portuguese orthography conventions established in 1945, generally in effect until 2009. This reform was not ratified in Brazil." - ] - }, - { - "Type": "variant", - "Subtag": "cornu", - "Description": [ - "Cornu-English", - "Cornish English", - "Anglo-Cornish" - ], - "Added": "2015-12-07", - "Prefix": [ - "en" - ] - }, - { - "Type": "variant", - "Subtag": "creiss", - "Description": [ - "Occitan variants of the Croissant area" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ] - }, - { - "Type": "variant", - "Subtag": "dajnko", - "Description": [ - "Slovene in Dajnko alphabet" - ], - "Added": "2012-06-27", - "Prefix": [ - "sl" - ], - "Comments": [ - "The subtag represents the alphabet codified by Peter Dajnko and used from 1824 to 1839 mostly in Styria (in what is now Eastern Slovenia)." - ] - }, - { - "Type": "variant", - "Subtag": "ekavsk", - "Description": [ - "Serbian with Ekavian pronunciation" - ], - "Prefix": [ - "sr", - "sr-Latn", - "sr-Cyrl" - ], - "Added": "2013-12-02" - }, - { - "Type": "variant", - "Subtag": "emodeng", - "Description": [ - "Early Modern English (1500-1700)" - ], - "Added": "2012-02-05", - "Prefix": [ - "en" - ] - }, - { - "Type": "variant", - "Subtag": "fonipa", - "Description": [ - "International Phonetic Alphabet" - ], - "Added": "2006-12-11" - }, - { - "Type": "variant", - "Subtag": "fonkirsh", - "Description": [ - "Kirshenbaum Phonetic Alphabet" - ], - "Added": "2018-04-22" - }, - { - "Type": "variant", - "Subtag": "fonnapa", - "Description": [ - "North American Phonetic Alphabet", - "Americanist Phonetic Notation" - ], - "Added": "2016-06-24" - }, - { - "Type": "variant", - "Subtag": "fonupa", - "Description": [ - "Uralic Phonetic Alphabet" - ], - "Added": "2006-12-11" - }, - { - "Type": "variant", - "Subtag": "fonxsamp", - "Description": [ - "X-SAMPA transcription" - ], - "Added": "2010-10-23", - "Comments": [ - "Indicates that the content is transcribed according to X-SAMPA" - ] - }, - { - "Type": "variant", - "Subtag": "gallo", - "Description": [ - "Gallo" - ], - "Added": "2021-08-05", - "Prefix": [ - "fr" - ] - }, - { - "Type": "variant", - "Subtag": "gascon", - "Description": [ - "Gascon" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Gascony" - ] - }, - { - "Type": "variant", - "Subtag": "grclass", - "Description": [ - "Classical Occitan orthography" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc", - "oc-aranes", - "oc-auvern", - "oc-cisaup", - "oc-creiss", - "oc-gascon", - "oc-lemosin", - "oc-lengadoc", - "oc-nicard", - "oc-provenc", - "oc-vivaraup" - ], - "Comments": [ - "Classical written standard for Occitan developed in 1935 by Alibèrt" - ] - }, - { - "Type": "variant", - "Subtag": "grital", - "Description": [ - "Italian-inspired Occitan orthography" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc", - "oc-cisaup", - "oc-nicard", - "oc-provenc" - ] - }, - { - "Type": "variant", - "Subtag": "grmistr", - "Description": [ - "Mistralian or Mistralian-inspired Occitan orthography" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc", - "oc-aranes", - "oc-auvern", - "oc-cisaup", - "oc-creiss", - "oc-gascon", - "oc-lemosin", - "oc-lengadoc", - "oc-nicard", - "oc-provenc", - "oc-vivaraup" - ], - "Comments": [ - "Written standard developed by Romanilha in 1853 and used by Mistral and the Félibres, including derived standards such as Escolo dóu Po, Escolo Gaston Febus, and others" - ] - }, - { - "Type": "variant", - "Subtag": "hepburn", - "Description": [ - "Hepburn romanization" - ], - "Added": "2009-10-01", - "Prefix": [ - "ja-Latn" - ] - }, - { - "Type": "variant", - "Subtag": "heploc", - "Description": [ - "Hepburn romanization, Library of Congress method" - ], - "Added": "2009-10-01", - "Deprecated": "2010-02-07", - "Preferred-Value": "alalc97", - "Prefix": [ - "ja-Latn-hepburn" - ], - "Comments": [ - "Preferred tag is ja-Latn-alalc97" - ] - }, - { - "Type": "variant", - "Subtag": "hognorsk", - "Description": [ - "Norwegian in Høgnorsk (High Norwegian) orthography" - ], - "Added": "2010-01-02", - "Prefix": [ - "nn" - ], - "Comments": [ - "Norwegian following Ivar Aasen's orthographical principles, including modern usage." - ] - }, - { - "Type": "variant", - "Subtag": "hsistemo", - "Description": [ - "Standard H-system orthographic fallback for spelling Esperanto" - ], - "Added": "2017-03-14", - "Prefix": [ - "eo" - ] - }, - { - "Type": "variant", - "Subtag": "ijekavsk", - "Description": [ - "Serbian with Ijekavian pronunciation" - ], - "Prefix": [ - "sr", - "sr-Latn", - "sr-Cyrl" - ], - "Added": "2013-12-02" - }, - { - "Type": "variant", - "Subtag": "itihasa", - "Description": [ - "Epic Sanskrit" - ], - "Added": "2010-07-28", - "Prefix": [ - "sa" - ] - }, - { - "Type": "variant", - "Subtag": "ivanchov", - "Description": [ - "Bulgarian in 1899 orthography" - ], - "Added": "2017-12-13", - "Prefix": [ - "bg" - ], - "Comments": [ - "Bulgarian orthography introduced by Todor Ivanchov in 1899" - ] - }, - { - "Type": "variant", - "Subtag": "jauer", - "Description": [ - "Jauer dialect of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "The spoken dialect of the Val Müstair, which has no written standard." - ] - }, - { - "Type": "variant", - "Subtag": "jyutping", - "Description": [ - "Jyutping Cantonese Romanization" - ], - "Added": "2010-10-23", - "Prefix": [ - "yue" - ], - "Comments": [ - "Jyutping romanization of Cantonese" - ] - }, - { - "Type": "variant", - "Subtag": "kkcor", - "Description": [ - "Common Cornish orthography of Revived Cornish" - ], - "Added": "2008-10-14", - "Prefix": [ - "kw" - ] - }, - { - "Type": "variant", - "Subtag": "kociewie", - "Description": [ - "The Kociewie dialect of Polish" - ], - "Added": "2014-11-27", - "Prefix": [ - "pl" - ], - "Comments": [ - "The dialect of Kociewie is spoken in the region around Starogard GdaÅ„ski, Tczew and Åšwiecie in northern Poland." - ] - }, - { - "Type": "variant", - "Subtag": "kscor", - "Description": [ - "Standard Cornish orthography of Revived Cornish", - "Kernowek Standard" - ], - "Added": "2012-06-27", - "Prefix": [ - "kw" - ] - }, - { - "Type": "variant", - "Subtag": "laukika", - "Description": [ - "Classical Sanskrit" - ], - "Added": "2010-07-28", - "Prefix": [ - "sa" - ] - }, - { - "Type": "variant", - "Subtag": "lemosin", - "Description": [ - "Limousin" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Limousin" - ] - }, - { - "Type": "variant", - "Subtag": "lengadoc", - "Description": [ - "Languedocien" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Languedoc" - ] - }, - { - "Type": "variant", - "Subtag": "lipaw", - "Description": [ - "The Lipovaz dialect of Resian", - "The Lipovec dialect of Resian" - ], - "Added": "2007-08-11", - "Prefix": [ - "sl-rozaj" - ], - "Comments": [ - "The dialect of Lipovaz/Lipovec is one of the minor local dialects of Resian" - ] - }, - { - "Type": "variant", - "Subtag": "ltg2007", - "Description": [ - "The Latgalian language orthography codified in the language law in 2007" - ], - "Added": "2022-06-23", - "Prefix": [ - "ltg" - ] - }, - { - "Type": "variant", - "Subtag": "luna1918", - "Description": [ - "Post-1917 Russian orthography" - ], - "Added": "2010-10-10", - "Prefix": [ - "ru" - ], - "Comments": [ - "Russian orthography as established by the 1917/1918 orthographic reforms" - ] - }, - { - "Type": "variant", - "Subtag": "metelko", - "Description": [ - "Slovene in Metelko alphabet" - ], - "Added": "2012-06-27", - "Prefix": [ - "sl" - ], - "Comments": [ - "The subtag represents the alphabet codified by Franc Serafin Metelko and used from 1825 to 1833." - ] - }, - { - "Type": "variant", - "Subtag": "monoton", - "Description": [ - "Monotonic Greek" - ], - "Added": "2006-12-11", - "Prefix": [ - "el" - ] - }, - { - "Type": "variant", - "Subtag": "ndyuka", - "Description": [ - "Ndyuka dialect", - "Aukan dialect" - ], - "Added": "2009-09-05", - "Prefix": [ - "djk" - ], - "Comments": [ - "Ndyuka dialect of the \"Busi Nenge Tongo\" English-based Creole continuum in Eastern Suriname and Western French Guiana" - ] - }, - { - "Type": "variant", - "Subtag": "nedis", - "Description": [ - "Natisone dialect", - "Nadiza dialect" - ], - "Added": "2005-10-16", - "Prefix": [ - "sl" - ] - }, - { - "Type": "variant", - "Subtag": "newfound", - "Description": [ - "Newfoundland English" - ], - "Added": "2015-11-25", - "Prefix": [ - "en-CA" - ] - }, - { - "Type": "variant", - "Subtag": "nicard", - "Description": [ - "Niçard" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Nice" - ] - }, - { - "Type": "variant", - "Subtag": "njiva", - "Description": [ - "The Gniva dialect of Resian", - "The Njiva dialect of Resian" - ], - "Added": "2007-07-05", - "Prefix": [ - "sl-rozaj" - ], - "Comments": [ - "The dialect of Gniva/Njiva is one of the four major local dialects of Resian" - ] - }, - { - "Type": "variant", - "Subtag": "nulik", - "Description": [ - "Volapük nulik", - "Volapük perevidöl", - "Volapük nulädik", - "de Jong's Volapük", - "New Volapük", - "Revised Volapük", - "Modern Volapük" - ], - "Added": "2012-01-28", - "Prefix": [ - "vo" - ] - }, - { - "Type": "variant", - "Subtag": "osojs", - "Description": [ - "The Oseacco dialect of Resian", - "The Osojane dialect of Resian" - ], - "Added": "2007-07-05", - "Prefix": [ - "sl-rozaj" - ], - "Comments": [ - "The dialect of Oseacco/Osojane is one of the four major local dialects of Resian" - ] - }, - { - "Type": "variant", - "Subtag": "oxendict", - "Description": [ - "Oxford English Dictionary spelling" - ], - "Added": "2015-04-17", - "Prefix": [ - "en" - ] - }, - { - "Type": "variant", - "Subtag": "pahawh2", - "Description": [ - "Pahawh Hmong Second Stage Reduced orthography" - ], - "Added": "2017-01-13", - "Prefix": [ - "mww", - "hnj" - ] - }, - { - "Type": "variant", - "Subtag": "pahawh3", - "Description": [ - "Pahawh Hmong Third Stage Reduced orthography" - ], - "Added": "2017-01-13", - "Prefix": [ - "mww", - "hnj" - ] - }, - { - "Type": "variant", - "Subtag": "pahawh4", - "Description": [ - "Pahawh Hmong Final Version orthography" - ], - "Added": "2017-01-13", - "Prefix": [ - "mww", - "hnj" - ] - }, - { - "Type": "variant", - "Subtag": "pamaka", - "Description": [ - "Pamaka dialect" - ], - "Added": "2009-09-05", - "Prefix": [ - "djk" - ], - "Comments": [ - "Pamaka dialect of the \"Busi Nenge Tongo\" English-based Creole continuum in Eastern Suriname and Western French Guiana" - ] - }, - { - "Type": "variant", - "Subtag": "peano", - "Description": [ - "Latino Sine Flexione", - "Interlingua de API", - "Interlingua de Peano" - ], - "Prefix": [ - "la" - ], - "Comments": [ - "Peano’s Interlingua, created in 1903 by Giuseppe Peano as an international auxiliary language" - ], - "Added": "2020-03-12" - }, - { - "Type": "variant", - "Subtag": "petr1708", - "Description": [ - "Petrine orthography" - ], - "Added": "2010-10-10", - "Prefix": [ - "ru" - ], - "Comments": [ - "Russian orthography from the Petrine orthographic reforms of 1708 to the 1917 orthographic reform" - ] - }, - { - "Type": "variant", - "Subtag": "pinyin", - "Description": [ - "Pinyin romanization" - ], - "Added": "2008-10-14", - "Prefix": [ - "zh-Latn", - "bo-Latn" - ] - }, - { - "Type": "variant", - "Subtag": "polyton", - "Description": [ - "Polytonic Greek" - ], - "Added": "2006-12-11", - "Prefix": [ - "el" - ] - }, - { - "Type": "variant", - "Subtag": "provenc", - "Description": [ - "Provençal" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in Provence" - ] - }, - { - "Type": "variant", - "Subtag": "puter", - "Description": [ - "Puter idiom of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Puter is one of the five traditional written standards or \"idioms\" of the Romansh language." - ] - }, - { - "Type": "variant", - "Subtag": "rigik", - "Description": [ - "Volapük rigik", - "Schleyer's Volapük", - "Original Volapük", - "Classic Volapük" - ], - "Added": "2012-01-28", - "Prefix": [ - "vo" - ] - }, - { - "Type": "variant", - "Subtag": "rozaj", - "Description": [ - "Resian", - "Resianic", - "Rezijan" - ], - "Added": "2005-10-16", - "Prefix": [ - "sl" - ] - }, - { - "Type": "variant", - "Subtag": "rumgr", - "Description": [ - "Rumantsch Grischun" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Supraregional Romansh written standard" - ] - }, - { - "Type": "variant", - "Subtag": "scotland", - "Description": [ - "Scottish Standard English" - ], - "Added": "2007-08-31", - "Prefix": [ - "en" - ] - }, - { - "Type": "variant", - "Subtag": "scouse", - "Description": [ - "Scouse" - ], - "Added": "2006-09-18", - "Prefix": [ - "en" - ], - "Comments": [ - "English Liverpudlian dialect known as 'Scouse'" - ] - }, - { - "Type": "variant", - "Subtag": "simple", - "Description": [ - "Simplified form" - ], - "Added": "2015-12-29" - }, - { - "Type": "variant", - "Subtag": "solba", - "Description": [ - "The Stolvizza dialect of Resian", - "The Solbica dialect of Resian" - ], - "Added": "2007-07-05", - "Prefix": [ - "sl-rozaj" - ], - "Comments": [ - "The dialect of Stolvizza/Solbica is one of the four major local dialects of Resian" - ] - }, - { - "Type": "variant", - "Subtag": "sotav", - "Description": [ - "The Sotavento dialect group of Kabuverdianu" - ], - "Prefix": [ - "kea" - ], - "Comments": [ - "Sotavento is one of the two main dialect groups of Kabuverdianu." - ], - "Added": "2013-12-10" - }, - { - "Type": "variant", - "Subtag": "spanglis", - "Description": [ - "Spanglish" - ], - "Added": "2017-02-23", - "Prefix": [ - "en", - "es" - ], - "Comments": [ - "A variety of contact dialects of English and Spanish" - ] - }, - { - "Type": "variant", - "Subtag": "surmiran", - "Description": [ - "Surmiran idiom of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Surmiran is one of the five traditional written standards or \"idioms\" of the Romansh language." - ] - }, - { - "Type": "variant", - "Subtag": "sursilv", - "Description": [ - "Sursilvan idiom of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Sursilvan is one of the five traditional written standards or \"idioms\" of the Romansh language." - ] - }, - { - "Type": "variant", - "Subtag": "sutsilv", - "Description": [ - "Sutsilvan idiom of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Sutsilvan is one of the five traditional written standards or \"idioms\" of the Romansh language." - ] - }, - { - "Type": "variant", - "Subtag": "synnejyl", - "Description": [ - "Synnejysk", - "South Jutish" - ], - "Added": "2021-07-17", - "Prefix": [ - "da" - ] - }, - { - "Type": "variant", - "Subtag": "tarask", - "Description": [ - "Belarusian in Taraskievica orthography" - ], - "Added": "2007-04-27", - "Prefix": [ - "be" - ], - "Comments": [ - "The subtag represents Branislau Taraskievic's Belarusian orthography as published in \"Bielaruski klasycny pravapis\" by Juras Buslakou, Vincuk Viacorka, Zmicier Sanko, and Zmicier Sauka (Vilnia- Miensk 2005)." - ] - }, - { - "Type": "variant", - "Subtag": "tongyong", - "Description": [ - "Tongyong Pinyin romanization" - ], - "Added": "2020-06-08", - "Prefix": [ - "zh-Latn" - ], - "Comments": [ - "Former official transcription standard for Mandarin Chinese in Taiwan." - ] - }, - { - "Type": "variant", - "Subtag": "tunumiit", - "Description": [ - "Tunumiisiut", - "East Greenlandic", - "Østgrønlandsk" - ], - "Added": "2020-07-16", - "Prefix": [ - "kl" - ], - "Comments": [ - "Also known as Tunumiit oraasiat" - ] - }, - { - "Type": "variant", - "Subtag": "uccor", - "Description": [ - "Unified Cornish orthography of Revived Cornish" - ], - "Added": "2008-10-14", - "Prefix": [ - "kw" - ] - }, - { - "Type": "variant", - "Subtag": "ucrcor", - "Description": [ - "Unified Cornish Revised orthography of Revived Cornish" - ], - "Added": "2008-10-14", - "Prefix": [ - "kw" - ] - }, - { - "Type": "variant", - "Subtag": "ulster", - "Description": [ - "Ulster dialect of Scots" - ], - "Added": "2010-04-10", - "Prefix": [ - "sco" - ] - }, - { - "Type": "variant", - "Subtag": "unifon", - "Description": [ - "Unifon phonetic alphabet" - ], - "Added": "2013-10-02", - "Prefix": [ - "en", - "hup", - "kyh", - "tol", - "yur" - ] - }, - { - "Type": "variant", - "Subtag": "vaidika", - "Description": [ - "Vedic Sanskrit" - ], - "Added": "2010-07-28", - "Prefix": [ - "sa" - ], - "Comments": [ - "The most ancient dialect of Sanskrit used in verse and prose composed until about the 4th century B.C.E." - ] - }, - { - "Type": "variant", - "Subtag": "valencia", - "Description": [ - "Valencian" - ], - "Added": "2007-03-06", - "Prefix": [ - "ca" - ], - "Comments": [ - "Variety spoken in the \"Comunidad Valenciana\" region of Spain, where it is co-official with Spanish." - ] - }, - { - "Type": "variant", - "Subtag": "vallader", - "Description": [ - "Vallader idiom of Romansh" - ], - "Added": "2010-06-29", - "Prefix": [ - "rm" - ], - "Comments": [ - "Vallader is one of the five traditional written standards or \"idioms\" of the Romansh language." - ] - }, - { - "Type": "variant", - "Subtag": "vecdruka", - "Description": [ - "Latvian orthography used before 1920s (\"vecÄ druka\")" - ], - "Added": "2020-09-26", - "Prefix": [ - "lv" - ], - "Comments": [ - "The subtag represents the old orthography of the Latvian language used during c. 1600s–1920s." - ] - }, - { - "Type": "variant", - "Subtag": "vivaraup", - "Description": [ - "Vivaro-Alpine" - ], - "Added": "2018-04-22", - "Prefix": [ - "oc" - ], - "Comments": [ - "Occitan variant spoken in northeastern Occitania" - ] - }, - { - "Type": "variant", - "Subtag": "wadegile", - "Description": [ - "Wade-Giles romanization" - ], - "Added": "2008-10-03", - "Prefix": [ - "zh-Latn" - ] - }, - { - "Type": "variant", - "Subtag": "xsistemo", - "Description": [ - "Standard X-system orthographic fallback for spelling Esperanto" - ], - "Added": "2017-03-14", - "Prefix": [ - "eo" - ] - }, - { - "Type": "grandfathered", - "Tag": "art-lojban", - "Description": [ - "Lojban" - ], - "Added": "2001-11-11", - "Deprecated": "2003-09-02", - "Preferred-Value": "jbo" - }, - { - "Type": "grandfathered", - "Tag": "cel-gaulish", - "Description": [ - "Gaulish" - ], - "Added": "2001-05-25", - "Deprecated": "2015-03-29", - "Comments": [ - "see xcg, xga, xtg" - ] - }, - { - "Type": "grandfathered", - "Tag": "en-GB-oed", - "Description": [ - "English, Oxford English Dictionary spelling" - ], - "Added": "2003-07-09", - "Deprecated": "2015-04-17", - "Preferred-Value": "en-GB-oxendict" - }, - { - "Type": "grandfathered", - "Tag": "i-ami", - "Description": [ - "Amis" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "ami" - }, - { - "Type": "grandfathered", - "Tag": "i-bnn", - "Description": [ - "Bunun" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "bnn" - }, - { - "Type": "grandfathered", - "Tag": "i-default", - "Description": [ - "Default Language" - ], - "Added": "1998-03-10" - }, - { - "Type": "grandfathered", - "Tag": "i-enochian", - "Description": [ - "Enochian" - ], - "Added": "2002-07-03", - "Deprecated": "2015-03-29" - }, - { - "Type": "grandfathered", - "Tag": "i-hak", - "Description": [ - "Hakka" - ], - "Added": "1999-01-31", - "Deprecated": "2000-01-10", - "Preferred-Value": "hak" - }, - { - "Type": "grandfathered", - "Tag": "i-klingon", - "Description": [ - "Klingon" - ], - "Added": "1999-05-26", - "Deprecated": "2004-02-24", - "Preferred-Value": "tlh" - }, - { - "Type": "grandfathered", - "Tag": "i-lux", - "Description": [ - "Luxembourgish" - ], - "Added": "1997-09-19", - "Deprecated": "1998-09-09", - "Preferred-Value": "lb" - }, - { - "Type": "grandfathered", - "Tag": "i-mingo", - "Description": [ - "Mingo" - ], - "Added": "1997-09-19" - }, - { - "Type": "grandfathered", - "Tag": "i-navajo", - "Description": [ - "Navajo" - ], - "Added": "1997-09-19", - "Deprecated": "2000-02-18", - "Preferred-Value": "nv" - }, - { - "Type": "grandfathered", - "Tag": "i-pwn", - "Description": [ - "Paiwan" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "pwn" - }, - { - "Type": "grandfathered", - "Tag": "i-tao", - "Description": [ - "Tao" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "tao" - }, - { - "Type": "grandfathered", - "Tag": "i-tay", - "Description": [ - "Tayal" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "tay" - }, - { - "Type": "grandfathered", - "Tag": "i-tsu", - "Description": [ - "Tsou" - ], - "Added": "1999-05-25", - "Deprecated": "2009-07-29", - "Preferred-Value": "tsu" - }, - { - "Type": "grandfathered", - "Tag": "no-bok", - "Description": [ - "Norwegian Bokmal" - ], - "Added": "1995-08-23", - "Deprecated": "2000-02-18", - "Preferred-Value": "nb" - }, - { - "Type": "grandfathered", - "Tag": "no-nyn", - "Description": [ - "Norwegian Nynorsk" - ], - "Added": "1995-08-23", - "Deprecated": "2000-02-18", - "Preferred-Value": "nn" - }, - { - "Type": "grandfathered", - "Tag": "sgn-BE-FR", - "Description": [ - "Belgian-French Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "sfb" - }, - { - "Type": "grandfathered", - "Tag": "sgn-BE-NL", - "Description": [ - "Belgian-Flemish Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "vgt" - }, - { - "Type": "grandfathered", - "Tag": "sgn-CH-DE", - "Description": [ - "Swiss German Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "sgg" - }, - { - "Type": "grandfathered", - "Tag": "zh-guoyu", - "Description": [ - "Mandarin or Standard Chinese" - ], - "Added": "1999-12-18", - "Deprecated": "2005-07-15", - "Preferred-Value": "cmn" - }, - { - "Type": "grandfathered", - "Tag": "zh-hakka", - "Description": [ - "Hakka" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Preferred-Value": "hak" - }, - { - "Type": "grandfathered", - "Tag": "zh-min", - "Description": [ - "Min, Fuzhou, Hokkien, Amoy, or Taiwanese" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Comments": [ - "see cdo, cpx, czo, mnp, nan" - ] - }, - { - "Type": "grandfathered", - "Tag": "zh-min-nan", - "Description": [ - "Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo" - ], - "Added": "2001-03-26", - "Deprecated": "2009-07-29", - "Preferred-Value": "nan" - }, - { - "Type": "grandfathered", - "Tag": "zh-xiang", - "Description": [ - "Xiang or Hunanese" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Preferred-Value": "hsn" - }, - { - "Type": "redundant", - "Tag": "az-Arab", - "Description": [ - "Azerbaijani in Arabic script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "az-Cyrl", - "Description": [ - "Azerbaijani in Cyrillic script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "az-Latn", - "Description": [ - "Azerbaijani in Latin script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "be-Latn", - "Description": [ - "Belarusian in Latin script" - ], - "Added": "2005-01-06" - }, - { - "Type": "redundant", - "Tag": "bs-Cyrl", - "Description": [ - "Bosnian in Cyrillic script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "bs-Latn", - "Description": [ - "Bosnian in Latin script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "de-1901", - "Description": [ - "German, traditional orthography" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-1996", - "Description": [ - "German, orthography of 1996" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-AT-1901", - "Description": [ - "German, Austrian variant, traditional orthography" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-AT-1996", - "Description": [ - "German, Austrian variant, orthography of 1996" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-CH-1901", - "Description": [ - "German, Swiss variant, traditional orthography" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-CH-1996", - "Description": [ - "German, Swiss variant, orthography of 1996" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-DE-1901", - "Description": [ - "German, German variant, traditional orthography" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "de-DE-1996", - "Description": [ - "German, German variant, orthography of 1996" - ], - "Added": "2001-07-17" - }, - { - "Type": "redundant", - "Tag": "en-boont", - "Description": [ - "Boontling" - ], - "Added": "2003-02-14" - }, - { - "Type": "redundant", - "Tag": "en-scouse", - "Description": [ - "Scouse" - ], - "Added": "2000-05-25" - }, - { - "Type": "redundant", - "Tag": "es-419", - "Description": [ - "Latin American Spanish" - ], - "Added": "2005-07-15" - }, - { - "Type": "redundant", - "Tag": "iu-Cans", - "Description": [ - "Inuktitut in Canadian Aboriginal Syllabic script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "iu-Latn", - "Description": [ - "Inuktitut in Latin script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "mn-Cyrl", - "Description": [ - "Mongolian in Cyrillic script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "mn-Mong", - "Description": [ - "Mongolian in Mongolian script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "sgn-BR", - "Description": [ - "Brazilian Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "bzs" - }, - { - "Type": "redundant", - "Tag": "sgn-CO", - "Description": [ - "Colombian Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "csn" - }, - { - "Type": "redundant", - "Tag": "sgn-DE", - "Description": [ - "German Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "gsg" - }, - { - "Type": "redundant", - "Tag": "sgn-DK", - "Description": [ - "Danish Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "dsl" - }, - { - "Type": "redundant", - "Tag": "sgn-ES", - "Description": [ - "Spanish Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "ssp" - }, - { - "Type": "redundant", - "Tag": "sgn-FR", - "Description": [ - "French Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "fsl" - }, - { - "Type": "redundant", - "Tag": "sgn-GB", - "Description": [ - "British Sign Language" - ], - "Added": "2001-03-02", - "Deprecated": "2009-07-29", - "Preferred-Value": "bfi" - }, - { - "Type": "redundant", - "Tag": "sgn-GR", - "Description": [ - "Greek Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "gss" - }, - { - "Type": "redundant", - "Tag": "sgn-IE", - "Description": [ - "Irish Sign Language" - ], - "Added": "2001-03-02", - "Deprecated": "2009-07-29", - "Preferred-Value": "isg" - }, - { - "Type": "redundant", - "Tag": "sgn-IT", - "Description": [ - "Italian Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "ise" - }, - { - "Type": "redundant", - "Tag": "sgn-JP", - "Description": [ - "Japanese Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "jsl" - }, - { - "Type": "redundant", - "Tag": "sgn-MX", - "Description": [ - "Mexican Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "mfs" - }, - { - "Type": "redundant", - "Tag": "sgn-NI", - "Description": [ - "Nicaraguan Sign Language" - ], - "Added": "2001-03-02", - "Deprecated": "2009-07-29", - "Preferred-Value": "ncs" - }, - { - "Type": "redundant", - "Tag": "sgn-NL", - "Description": [ - "Dutch Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "dse" - }, - { - "Type": "redundant", - "Tag": "sgn-NO", - "Description": [ - "Norwegian Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "nsl" - }, - { - "Type": "redundant", - "Tag": "sgn-PT", - "Description": [ - "Portuguese Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "psr" - }, - { - "Type": "redundant", - "Tag": "sgn-SE", - "Description": [ - "Swedish Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "swl" - }, - { - "Type": "redundant", - "Tag": "sgn-US", - "Description": [ - "American Sign Language" - ], - "Added": "2001-03-02", - "Deprecated": "2009-07-29", - "Preferred-Value": "ase" - }, - { - "Type": "redundant", - "Tag": "sgn-ZA", - "Description": [ - "South African Sign Language" - ], - "Added": "2001-11-11", - "Deprecated": "2009-07-29", - "Preferred-Value": "sfs" - }, - { - "Type": "redundant", - "Tag": "sl-nedis", - "Description": [ - "Natisone dialect, Nadiza dialect" - ], - "Added": "2004-06-01" - }, - { - "Type": "redundant", - "Tag": "sl-rozaj", - "Description": [ - "Resian, Resianic, Rezijan" - ], - "Added": "2003-10-09" - }, - { - "Type": "redundant", - "Tag": "sr-Cyrl", - "Description": [ - "Serbian in Cyrillic script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "sr-Latn", - "Description": [ - "Serbian in Latin script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "tg-Arab", - "Description": [ - "Tajik in Arabic script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "tg-Cyrl", - "Description": [ - "Tajik in Cyrillic script" - ], - "Added": "2005-02-17" - }, - { - "Type": "redundant", - "Tag": "uz-Cyrl", - "Description": [ - "Uzbek in Cyrillic script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "uz-Latn", - "Description": [ - "Uzbek in Latin script" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "yi-Latn", - "Description": [ - "Yiddish, in Latin script" - ], - "Added": "2003-01-07" - }, - { - "Type": "redundant", - "Tag": "zh-cmn", - "Description": [ - "Mandarin Chinese" - ], - "Added": "2005-07-15", - "Deprecated": "2009-07-29", - "Preferred-Value": "cmn" - }, - { - "Type": "redundant", - "Tag": "zh-cmn-Hans", - "Description": [ - "Mandarin Chinese (Simplified)" - ], - "Added": "2005-07-15", - "Deprecated": "2009-07-29", - "Preferred-Value": "cmn-Hans" - }, - { - "Type": "redundant", - "Tag": "zh-cmn-Hant", - "Description": [ - "Mandarin Chinese (Traditional)" - ], - "Added": "2005-07-15", - "Deprecated": "2009-07-29", - "Preferred-Value": "cmn-Hant" - }, - { - "Type": "redundant", - "Tag": "zh-gan", - "Description": [ - "Kan or Gan" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Preferred-Value": "gan" - }, - { - "Type": "redundant", - "Tag": "zh-Hans", - "Description": [ - "simplified Chinese" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "zh-Hans-CN", - "Description": [ - "PRC Mainland Chinese in simplified script" - ], - "Added": "2005-04-13" - }, - { - "Type": "redundant", - "Tag": "zh-Hans-HK", - "Description": [ - "Hong Kong Chinese in simplified script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hans-MO", - "Description": [ - "Macao Chinese in simplified script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hans-SG", - "Description": [ - "Singapore Chinese in simplified script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hans-TW", - "Description": [ - "Taiwan Chinese in simplified script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hant", - "Description": [ - "traditional Chinese" - ], - "Added": "2003-05-30" - }, - { - "Type": "redundant", - "Tag": "zh-Hant-CN", - "Description": [ - "PRC Mainland Chinese in traditional script" - ], - "Added": "2005-04-13" - }, - { - "Type": "redundant", - "Tag": "zh-Hant-HK", - "Description": [ - "Hong Kong Chinese in traditional script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hant-MO", - "Description": [ - "Macao Chinese in traditional script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hant-SG", - "Description": [ - "Singapore Chinese in traditional script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-Hant-TW", - "Description": [ - "Taiwan Chinese in traditional script" - ], - "Added": "2005-04-11" - }, - { - "Type": "redundant", - "Tag": "zh-wuu", - "Description": [ - "Shanghaiese or Wu" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Preferred-Value": "wuu" - }, - { - "Type": "redundant", - "Tag": "zh-yue", - "Description": [ - "Cantonese" - ], - "Added": "1999-12-18", - "Deprecated": "2009-07-29", - "Preferred-Value": "yue" - } -] diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/script.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/script.json deleted file mode 100644 index 6e622d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/script.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "adlm": 8492, - "afak": 8493, - "aghb": 8494, - "ahom": 8495, - "arab": 8496, - "aran": 8497, - "armi": 8498, - "armn": 8499, - "avst": 8500, - "bali": 8501, - "bamu": 8502, - "bass": 8503, - "batk": 8504, - "beng": 8505, - "bhks": 8506, - "blis": 8507, - "bopo": 8508, - "brah": 8509, - "brai": 8510, - "bugi": 8511, - "buhd": 8512, - "cakm": 8513, - "cans": 8514, - "cari": 8515, - "cham": 8516, - "cher": 8517, - "chrs": 8518, - "cirt": 8519, - "copt": 8520, - "cpmn": 8521, - "cprt": 8522, - "cyrl": 8523, - "cyrs": 8524, - "deva": 8525, - "diak": 8526, - "dogr": 8527, - "dsrt": 8528, - "dupl": 8529, - "egyd": 8530, - "egyh": 8531, - "egyp": 8532, - "elba": 8533, - "elym": 8534, - "ethi": 8535, - "geok": 8536, - "geor": 8537, - "glag": 8538, - "gong": 8539, - "gonm": 8540, - "goth": 8541, - "gran": 8542, - "grek": 8543, - "gujr": 8544, - "guru": 8545, - "hanb": 8546, - "hang": 8547, - "hani": 8548, - "hano": 8549, - "hans": 8550, - "hant": 8551, - "hatr": 8552, - "hebr": 8553, - "hira": 8554, - "hluw": 8555, - "hmng": 8556, - "hmnp": 8557, - "hrkt": 8558, - "hung": 8559, - "inds": 8560, - "ital": 8561, - "jamo": 8562, - "java": 8563, - "jpan": 8564, - "jurc": 8565, - "kali": 8566, - "kana": 8567, - "kawi": 8568, - "khar": 8569, - "khmr": 8570, - "khoj": 8571, - "kitl": 8572, - "kits": 8573, - "knda": 8574, - "kore": 8575, - "kpel": 8576, - "kthi": 8577, - "lana": 8578, - "laoo": 8579, - "latf": 8580, - "latg": 8581, - "latn": 8582, - "leke": 8583, - "lepc": 8584, - "limb": 8585, - "lina": 8586, - "linb": 8587, - "lisu": 8588, - "loma": 8589, - "lyci": 8590, - "lydi": 8591, - "mahj": 8592, - "maka": 8593, - "mand": 8594, - "mani": 8595, - "marc": 8596, - "maya": 8597, - "medf": 8598, - "mend": 8599, - "merc": 8600, - "mero": 8601, - "mlym": 8602, - "modi": 8603, - "mong": 8604, - "moon": 8605, - "mroo": 8606, - "mtei": 8607, - "mult": 8608, - "mymr": 8609, - "nagm": 8610, - "nand": 8611, - "narb": 8612, - "nbat": 8613, - "newa": 8614, - "nkdb": 8615, - "nkgb": 8616, - "nkoo": 8617, - "nshu": 8618, - "ogam": 8619, - "olck": 8620, - "orkh": 8621, - "orya": 8622, - "osge": 8623, - "osma": 8624, - "ougr": 8625, - "palm": 8626, - "pauc": 8627, - "pcun": 8628, - "pelm": 8629, - "perm": 8630, - "phag": 8631, - "phli": 8632, - "phlp": 8633, - "phlv": 8634, - "phnx": 8635, - "piqd": 8636, - "plrd": 8637, - "prti": 8638, - "psin": 8639, - "qaaa..qabx": 8640, - "ranj": 8641, - "rjng": 8642, - "rohg": 8643, - "roro": 8644, - "runr": 8645, - "samr": 8646, - "sara": 8647, - "sarb": 8648, - "saur": 8649, - "sgnw": 8650, - "shaw": 8651, - "shrd": 8652, - "shui": 8653, - "sidd": 8654, - "sind": 8655, - "sinh": 8656, - "sogd": 8657, - "sogo": 8658, - "sora": 8659, - "soyo": 8660, - "sund": 8661, - "sunu": 8662, - "sylo": 8663, - "syrc": 8664, - "syre": 8665, - "syrj": 8666, - "syrn": 8667, - "tagb": 8668, - "takr": 8669, - "tale": 8670, - "talu": 8671, - "taml": 8672, - "tang": 8673, - "tavt": 8674, - "telu": 8675, - "teng": 8676, - "tfng": 8677, - "tglg": 8678, - "thaa": 8679, - "thai": 8680, - "tibt": 8681, - "tirh": 8682, - "tnsa": 8683, - "toto": 8684, - "ugar": 8685, - "vaii": 8686, - "visp": 8687, - "vith": 8688, - "wara": 8689, - "wcho": 8690, - "wole": 8691, - "xpeo": 8692, - "xsux": 8693, - "yezi": 8694, - "yiii": 8695, - "zanb": 8696, - "zinh": 8697, - "zmth": 8698, - "zsye": 8699, - "zsym": 8700, - "zxxx": 8701, - "zyyy": 8702, - "zzzz": 8703 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/special.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/special.json deleted file mode 100644 index 327790c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/special.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "mis": 4290, - "mul": 4579, - "und": 7098, - "zxx": 8232 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/variant.json b/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/variant.json deleted file mode 100644 index 36c9f56..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/data/json/variant.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "1901": 9010, - "1994": 9012, - "1996": 9013, - "1606nict": 9008, - "1694acad": 9009, - "1959acad": 9011, - "abl1943": 9014, - "akuapem": 9015, - "alalc97": 9016, - "aluku": 9017, - "ao1990": 9018, - "aranes": 9019, - "arevela": 9020, - "arevmda": 9021, - "arkaika": 9022, - "asante": 9023, - "auvern": 9024, - "baku1926": 9025, - "balanka": 9026, - "barla": 9027, - "basiceng": 9028, - "bauddha": 9029, - "biscayan": 9030, - "biske": 9031, - "bohoric": 9032, - "boont": 9033, - "bornholm": 9034, - "cisaup": 9035, - "colb1945": 9036, - "cornu": 9037, - "creiss": 9038, - "dajnko": 9039, - "ekavsk": 9040, - "emodeng": 9041, - "fonipa": 9042, - "fonkirsh": 9043, - "fonnapa": 9044, - "fonupa": 9045, - "fonxsamp": 9046, - "gallo": 9047, - "gascon": 9048, - "grclass": 9049, - "grital": 9050, - "grmistr": 9051, - "hepburn": 9052, - "heploc": 9053, - "hognorsk": 9054, - "hsistemo": 9055, - "ijekavsk": 9056, - "itihasa": 9057, - "ivanchov": 9058, - "jauer": 9059, - "jyutping": 9060, - "kkcor": 9061, - "kociewie": 9062, - "kscor": 9063, - "laukika": 9064, - "lemosin": 9065, - "lengadoc": 9066, - "lipaw": 9067, - "ltg2007": 9068, - "luna1918": 9069, - "metelko": 9070, - "monoton": 9071, - "ndyuka": 9072, - "nedis": 9073, - "newfound": 9074, - "nicard": 9075, - "njiva": 9076, - "nulik": 9077, - "osojs": 9078, - "oxendict": 9079, - "pahawh2": 9080, - "pahawh3": 9081, - "pahawh4": 9082, - "pamaka": 9083, - "peano": 9084, - "petr1708": 9085, - "pinyin": 9086, - "polyton": 9087, - "provenc": 9088, - "puter": 9089, - "rigik": 9090, - "rozaj": 9091, - "rumgr": 9092, - "scotland": 9093, - "scouse": 9094, - "simple": 9095, - "solba": 9096, - "sotav": 9097, - "spanglis": 9098, - "surmiran": 9099, - "sursilv": 9100, - "sutsilv": 9101, - "synnejyl": 9102, - "tarask": 9103, - "tongyong": 9104, - "tunumiit": 9105, - "uccor": 9106, - "ucrcor": 9107, - "ulster": 9108, - "unifon": 9109, - "vaidika": 9110, - "valencia": 9111, - "vallader": 9112, - "vecdruka": 9113, - "vivaraup": 9114, - "wadegile": 9115, - "xsistemo": 9116 -} diff --git a/extensions/.local/lib/python3.11/site-packages/language_tags/tags.py b/extensions/.local/lib/python3.11/site-packages/language_tags/tags.py deleted file mode 100644 index afeafca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/language_tags/tags.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- coding: utf-8 -*- -from language_tags.Subtag import Subtag -from language_tags.Tag import Tag -from language_tags import data - - -index = data.get('index') -registry = data.get('registry') - - -class tags(): - - @staticmethod - def tag(tag): - """ - Get a :class:`language_tags.Tag.Tag` of a string (hyphen-separated) tag. - - :param str tag: (hyphen-separated) tag. - :return: :class:`language_tags.Tag.Tag`. - """ - return Tag(tag) - - @staticmethod - def check(tag): - """ - Check if a string (hyphen-separated) tag is valid. - - :param str tag: (hyphen-separated) tag. - :return: bool -- True if valid. - """ - return Tag(tag).valid - - @staticmethod - def types(subtag): - """ - Get the types of a subtag string (excludes redundant and grandfathered). - - - :param str subtag: subtag. - :return: list of types. The return list can be empty. - """ - if subtag in index: - types = index[subtag] - return [type for type in types.keys() if type != 'redundant' or type != 'grandfathered'] - else: - return [] - - @staticmethod - def subtags(subtags): - """ - Get a list of existing :class:`language_tags.Subtag.Subtag` objects given the input subtag(s). - - :param subtags: string subtag or list of string subtags. - :return: a list of existing :class:`language_tags.Subtag.Subtag` objects. The return list can be empty. - """ - result = [] - - if not isinstance(subtags, list): - subtags = [subtags] - - for subtag in subtags: - for type in tags.types(subtag): - result.append(Subtag(subtag, type)) - - return result - - @staticmethod - def filter(subtags): - """ - Get a list of non-existing string subtag(s) given the input string subtag(s). - - :param subtags: string subtag or a list of string subtags. - :return: list of non-existing string subtags. The return list can be empty. - """ - if not isinstance(subtags, list): - subtags = [subtags] - return [subtag for subtag in subtags if len(tags.types(subtag)) == 0] - - @staticmethod - def search(description, all=False): - """ - Gets a list of :class:`language_tags.Subtag.Subtag` objects where the description matches. - - :param description: a string or compiled regular expression. For - example: ``search(re.compile(r'[0-9]{4}'))`` if the - description of the returned subtag must contain four contiguous numerical digits. - :type description: str or RegExp - :param all: If set on True grandfathered and redundant tags will be included in the return - list. - :type all: bool, optional - :return: list of :class:`language_tags.Subtag.Subtag` objects each including the description. - The return list can be empty. - """ - - # If the input query is all lowercase, make a case-insensitive match. - if isinstance(description, str): - list_to_string = lambda l: ', '.join(l).lower() if description.lower() == description else ', '.join(l) - - def test(record): - return description in list_to_string(record['Description']) - - elif hasattr(description.search, '__call__'): - def test(record): - return description.search(', '.join(record['Description'])) is not None - - records = filter(lambda r: False if ('Subtag' not in r and not all) else test(r), registry) - records = list(records) - # Sort by matched description string length. This is a quick way to push precise matches towards the top. - results = sorted(records, key=lambda r: min([abs(len(r_description) - len(description)) - for r_description in r['Description']])) \ - if isinstance(description, str) else records - return [Subtag(r['Subtag'], r['Type']) if 'Subtag' in r else Tag(['Tag']) for r in results] - - @staticmethod - def description(tag): - """ - Gets a list of descriptions given the tag. - - :param str tag: (hyphen-separated) tag. - :return: list of string descriptions. The return list can be empty. - """ - tag_object = Tag(tag) - results = [] - results.extend(tag_object.descriptions) - subtags = tag_object.subtags - for subtag in subtags: - results += subtag.description - - return results - - @staticmethod - def languages(macrolanguage): - """ - Get a list of :class:`language_tags.Subtag.Subtag` objects given the string macrolanguage. - - :param string macrolanguage: subtag macrolanguage. - :return: a list of the macrolanguage :class:`language_tags.Subtag.Subtag` objects. - :raise Exception: if the macrolanguage does not exists. - """ - results = [] - - macrolanguage = macrolanguage.lower() - macrolanguage_data = data.get('macrolanguage') - if macrolanguage not in macrolanguage_data: - raise Exception('\'' + macrolanguage + '\' is not a macrolanguage.') - for registry_item in registry: - record = registry_item - if 'Macrolanguage' in record: - if record['Macrolanguage'] == macrolanguage: - results.append(Subtag(record['Subtag'], record['Type'])) - - return results - - @staticmethod - def type(subtag, type): - """ - Get a :class:`language_tags.Subtag.Subtag` by subtag and type. Can be None if not exists. - - :param str subtag: subtag. - :param str type: type of the subtag. - :return: :class:`language_tags.Subtag.Subtag` if exists, otherwise None. - """ - subtag = subtag.lower() - if subtag in index: - types = index[subtag] - if type in types: - return Subtag(subtag, type) - return None - - @staticmethod - def language(subtag): - """ - Get a language :class:`language_tags.Subtag.Subtag` of the subtag string. - - :param str subtag: subtag. - :return: language :class:`language_tags.Subtag.Subtag` if exists, otherwise None. - """ - return tags.type(subtag, 'language') - - @staticmethod - def region(subtag): - """ - Get a region :class:`language_tags.Subtag.Subtag` of the subtag string. - - :param str subtag: subtag. - :return: region :class:`language_tags.Subtag.Subtag` if exists, otherwise None. - """ - return tags.type(subtag, 'region') - - @staticmethod - def date(): - """ - Get the file date of the underlying data as a string. - - :return: date as string (for example: '2014-03-27'). - """ - meta = data.get('meta') - return meta['File-Date'] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/LICENSE.txt b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/LICENSE.txt deleted file mode 100644 index 100b4bf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/LICENSE.txt +++ /dev/null @@ -1,37 +0,0 @@ -NetworkX is distributed with the 3-clause BSD license. - -:: - - Copyright (C) 2004-2024, NetworkX Developers - Aric Hagberg - Dan Schult - Pieter Swart - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the NetworkX Developers nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/METADATA deleted file mode 100644 index d58e657..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/METADATA +++ /dev/null @@ -1,165 +0,0 @@ -Metadata-Version: 2.1 -Name: networkx -Version: 3.4.2 -Summary: Python package for creating and manipulating graphs and networks -Author-email: Aric Hagberg -Maintainer-email: NetworkX Developers -Project-URL: Homepage, https://networkx.org/ -Project-URL: Bug Tracker, https://github.com/networkx/networkx/issues -Project-URL: Documentation, https://networkx.org/documentation/stable/ -Project-URL: Source Code, https://github.com/networkx/networkx -Keywords: Networks,Graph Theory,Mathematics,network,graph,discrete mathematics,math -Platform: Linux -Platform: Mac OSX -Platform: Windows -Platform: Unix -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Science/Research -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Scientific/Engineering :: Bio-Informatics -Classifier: Topic :: Scientific/Engineering :: Information Analysis -Classifier: Topic :: Scientific/Engineering :: Mathematics -Classifier: Topic :: Scientific/Engineering :: Physics -Requires-Python: >=3.10 -Description-Content-Type: text/x-rst -License-File: LICENSE.txt -Provides-Extra: default -Requires-Dist: numpy >=1.24 ; extra == 'default' -Requires-Dist: scipy !=1.11.0,!=1.11.1,>=1.10 ; extra == 'default' -Requires-Dist: matplotlib >=3.7 ; extra == 'default' -Requires-Dist: pandas >=2.0 ; extra == 'default' -Provides-Extra: developer -Requires-Dist: changelist ==0.5 ; extra == 'developer' -Requires-Dist: pre-commit >=3.2 ; extra == 'developer' -Requires-Dist: mypy >=1.1 ; extra == 'developer' -Requires-Dist: rtoml ; extra == 'developer' -Provides-Extra: doc -Requires-Dist: sphinx >=7.3 ; extra == 'doc' -Requires-Dist: pydata-sphinx-theme >=0.15 ; extra == 'doc' -Requires-Dist: sphinx-gallery >=0.16 ; extra == 'doc' -Requires-Dist: numpydoc >=1.8.0 ; extra == 'doc' -Requires-Dist: pillow >=9.4 ; extra == 'doc' -Requires-Dist: texext >=0.6.7 ; extra == 'doc' -Requires-Dist: myst-nb >=1.1 ; extra == 'doc' -Requires-Dist: intersphinx-registry ; extra == 'doc' -Provides-Extra: example -Requires-Dist: osmnx >=1.9 ; extra == 'example' -Requires-Dist: momepy >=0.7.2 ; extra == 'example' -Requires-Dist: contextily >=1.6 ; extra == 'example' -Requires-Dist: seaborn >=0.13 ; extra == 'example' -Requires-Dist: cairocffi >=1.7 ; extra == 'example' -Requires-Dist: igraph >=0.11 ; extra == 'example' -Requires-Dist: scikit-learn >=1.5 ; extra == 'example' -Provides-Extra: extra -Requires-Dist: lxml >=4.6 ; extra == 'extra' -Requires-Dist: pygraphviz >=1.14 ; extra == 'extra' -Requires-Dist: pydot >=3.0.1 ; extra == 'extra' -Requires-Dist: sympy >=1.10 ; extra == 'extra' -Provides-Extra: test -Requires-Dist: pytest >=7.2 ; extra == 'test' -Requires-Dist: pytest-cov >=4.0 ; extra == 'test' - -NetworkX -======== - - -.. image:: - https://github.com/networkx/networkx/workflows/test/badge.svg?branch=main - :target: https://github.com/networkx/networkx/actions?query=workflow%3Atest - -.. image:: - https://codecov.io/gh/networkx/networkx/branch/main/graph/badge.svg? - :target: https://app.codecov.io/gh/networkx/networkx/branch/main - -.. image:: - https://img.shields.io/pypi/v/networkx.svg? - :target: https://pypi.python.org/pypi/networkx - -.. image:: - https://img.shields.io/pypi/l/networkx.svg? - :target: https://github.com/networkx/networkx/blob/main/LICENSE.txt - -.. image:: - https://img.shields.io/pypi/pyversions/networkx.svg? - :target: https://pypi.python.org/pypi/networkx - -.. image:: - https://img.shields.io/github/labels/networkx/networkx/good%20first%20issue?color=green&label=contribute - :target: https://github.com/networkx/networkx/contribute - - -NetworkX is a Python package for the creation, manipulation, -and study of the structure, dynamics, and functions -of complex networks. - -- **Website (including documentation):** https://networkx.org -- **Mailing list:** https://groups.google.com/forum/#!forum/networkx-discuss -- **Source:** https://github.com/networkx/networkx -- **Bug reports:** https://github.com/networkx/networkx/issues -- **Report a security vulnerability:** https://tidelift.com/security -- **Tutorial:** https://networkx.org/documentation/latest/tutorial.html -- **GitHub Discussions:** https://github.com/networkx/networkx/discussions -- **Discord (Scientific Python) invite link:** https://discord.com/invite/vur45CbwMz -- **NetworkX meetings calendar (open to all):** https://scientific-python.org/calendars/networkx.ics - -Simple example --------------- - -Find the shortest path between two nodes in an undirected graph: - -.. code:: pycon - - >>> import networkx as nx - >>> G = nx.Graph() - >>> G.add_edge("A", "B", weight=4) - >>> G.add_edge("B", "D", weight=2) - >>> G.add_edge("A", "C", weight=3) - >>> G.add_edge("C", "D", weight=4) - >>> nx.shortest_path(G, "A", "D", weight="weight") - ['A', 'B', 'D'] - -Install -------- - -Install the latest released version of NetworkX: - -.. code:: shell - - $ pip install networkx - -Install with all optional dependencies: - -.. code:: shell - - $ pip install networkx[default] - -For additional details, -please see the `installation guide `_. - -Bugs ----- - -Please report any bugs that you find `here `_. -Or, even better, fork the repository on `GitHub `_ -and create a pull request (PR). We welcome all changes, big or small, and we -will help you make the PR if you are new to `git` (just ask on the issue and/or -see the `contributor guide `_). - -License -------- - -Released under the `3-Clause BSD license `_:: - - Copyright (C) 2004-2024 NetworkX Developers - Aric Hagberg - Dan Schult - Pieter Swart diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/RECORD deleted file mode 100644 index 4597e91..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/RECORD +++ /dev/null @@ -1,582 +0,0 @@ -networkx/__init__.py,sha256=vV-bYyml9JK5OV8Ic_dctL5ZGR5NqwF4fzd4msR2b9U,1274 -networkx/conftest.py,sha256=0wpXc9prGYLSw5gG-VvummltLxH5RtKeGwrxFsChe4E,8883 -networkx/convert.py,sha256=yB_MTl3GEvNb3CgDcBiCrhIN4LlV5N_BN9A0ykhBr7E,16025 -networkx/convert_matrix.py,sha256=7kc66-0XFGQUox3fVZuapUV4qCprg92ECe9BMjfSpCE,45383 -networkx/exception.py,sha256=hC8efPfIzOFo0jiWiQbTPaNKuNTuUwhp9RPw--pdv4U,3787 -networkx/lazy_imports.py,sha256=tYxP13tZ3p8-Qh--Mey4ZXZqQhWgQAbI7xYBZRrBzw0,5764 -networkx/relabel.py,sha256=0HptAQOBToKhLZzxscd6FQpzVCNMlYmiHjHul69ct8o,10300 -networkx/algorithms/__init__.py,sha256=oij1HDNcE7GhTPAtuHYT8eGZdH4K_vYaha51X5XoUCY,6559 -networkx/algorithms/asteroidal.py,sha256=jbN_MmETkCGpSvUWW6W8_Qqa3Syay2BwkX9odcyQFfk,5865 -networkx/algorithms/boundary.py,sha256=q3JtWssmn9yCB2mBdkjKZjkaxmBhkG9_dJOzmuJiQos,5339 -networkx/algorithms/bridges.py,sha256=CsxueHDOB9aFM5D8GP83u1ZKGzxF193XBpvmMReAcQk,6066 -networkx/algorithms/broadcasting.py,sha256=eqqZJ7oDQVCl7P3-PLm-gthzSc-kWnF2D1Yv42GXoGk,4890 -networkx/algorithms/chains.py,sha256=PPiSq5-GsT1Lsf8fwtGwGDVf1hhv5ZLariWtfzkBbAw,6968 -networkx/algorithms/chordal.py,sha256=L-ILWdVLWE44OkWmEO_4bSo4z6Ro-_zLglfLfTrwdqQ,13411 -networkx/algorithms/clique.py,sha256=LrmXvK6KVcjDyUrF5S6JTC2PQ1kTf26Yeb0TjqNy_WA,25872 -networkx/algorithms/cluster.py,sha256=x7dIotmBaBU3yaIzphjAyA2B-FHS_iiQ5nF-FeinQlU,20359 -networkx/algorithms/communicability_alg.py,sha256=0tZvZKY-_GUUB7GsRILxabS2jEpI51Udg5ADI9ADGZw,4545 -networkx/algorithms/core.py,sha256=2QQYUPoMs9F1rgGUlYgIAj6ETy4VefQWG1rl0RMkf9o,19184 -networkx/algorithms/covering.py,sha256=abt1bRBmiPi1J950uUYfTk4YS4pVhz1zanY01vxqNLg,5294 -networkx/algorithms/cuts.py,sha256=-J5j6Yi2CrlFsrX4bK-5kFztD6i4X6gihXwxmFC1zYQ,9990 -networkx/algorithms/cycles.py,sha256=erkLvKZkYfGDwya6Pn_o8cR5CnEnYeJ30Yi4kGr5xvk,43237 -networkx/algorithms/d_separation.py,sha256=3O_5RIWziPQ5xwRn-yAjH28xrkSaVIVbCFpw7K2Pa2A,27283 -networkx/algorithms/dag.py,sha256=y2HhZm0-olRZabgo9xczjsWf8ObSeG--VJl3PIEh9cE,45070 -networkx/algorithms/distance_measures.py,sha256=eauckS80lzTT_0CpZZh1JR7tLCzeiGCviaARDK1MN8k,34195 -networkx/algorithms/distance_regular.py,sha256=-1QCGLy7OPoNuV2bYJDY4jVot-0LGMobBQ0DubjbhGI,7053 -networkx/algorithms/dominance.py,sha256=T_z37jx_WSbY_HMfYgqZL6fT-p6PMAlZjSwEVsaLfLE,3450 -networkx/algorithms/dominating.py,sha256=d4CkSt_hmcwldF5FaOiazZpThYhxAuasRhJgGdExGjc,2669 -networkx/algorithms/efficiency_measures.py,sha256=VKbLKJgdIbno-YnJaLaCZt7TNXXnQPdz8N99uJCo748,4741 -networkx/algorithms/euler.py,sha256=yCqKaGchFSRPTRDXq7u1fH2IXZF94wWf9S10K9-Cd6U,14205 -networkx/algorithms/graph_hashing.py,sha256=0jcfhXY7tChFBV4N0ga4oJCJCHRwawrsDDyNy11uJlk,12556 -networkx/algorithms/graphical.py,sha256=1NdlhXuGEgUkHPo47EoNTWUMfdeTpiv7BBVM9ty2ivw,15831 -networkx/algorithms/hierarchy.py,sha256=_KFhCF1Afr2TrkPhqx-1PXUXEtfYLhbRShC58ZKbDGE,1786 -networkx/algorithms/hybrid.py,sha256=z3sIFMOpja1wlj-lI8YI6OIbSLZWHr66uSqyVESZWXY,6209 -networkx/algorithms/isolate.py,sha256=4rDH_iGY2WM5igJS-lBcIVb11MrKdoaFhJLieLZ4BAE,2301 -networkx/algorithms/link_prediction.py,sha256=UYo_LJgoVXcM1iLMXswM2g4jvUJmvxln3e5bVfXxQ10,22253 -networkx/algorithms/lowest_common_ancestors.py,sha256=xP0hkaJzwrj4evzahYvIjtUhaodj4FYv4JB51PWwVpc,9198 -networkx/algorithms/matching.py,sha256=bEvhXTFcRa-ZMNugIyM14rJ5QAcQkcZ2j-YJ-PTGQ3w,44550 -networkx/algorithms/mis.py,sha256=BEMv_dW8R6CjMMXJQGIhS4HpS8A8AkLJJWnz3GstuS4,2344 -networkx/algorithms/moral.py,sha256=z5lp42k4kqYk7t_FfszVj5KAC7BxXe6Adik3T2qvA6o,1535 -networkx/algorithms/node_classification.py,sha256=a2mVO7NI2IQF4Cd2Mx7TMLoTEu5HNG9RB5sEHQ19Wdw,6469 -networkx/algorithms/non_randomness.py,sha256=Uag54gFi5DR5uAQNFXyKKyORQuowTPuhq_QsjZaVMJ4,3068 -networkx/algorithms/planar_drawing.py,sha256=AXuoT3aFgEtCeMnAaUsRqjxCABdNYZ8Oo9sGOKBQto0,16254 -networkx/algorithms/planarity.py,sha256=PhIhnecPna-J_v7taoj-Ie175XWayVfcuMDHkj2bWLc,47249 -networkx/algorithms/polynomials.py,sha256=iP30_mcOlj81Vrzt4iB_ZZxYiRokubs-O1i9RW4pgTw,11278 -networkx/algorithms/reciprocity.py,sha256=1WMhLbSMkVPxRPlfUvbgO5FgVvJHn1doXQF4WuqSLQk,2855 -networkx/algorithms/regular.py,sha256=lEhYCP4Yysz8oTdxY8m40oqZcdhjKJuDsEj-P310loI,6794 -networkx/algorithms/richclub.py,sha256=kARzso3M6wnUcAJo2g8ga_ZtigL2czDNzeUDzBtRfqo,4892 -networkx/algorithms/similarity.py,sha256=My2MeE7AsIrCfXEkX-IYfbpbcNL3O7ZUkFtlzzF-j_8,61093 -networkx/algorithms/simple_paths.py,sha256=LFdFNltpt-rRI94x7HVDQooNbgm-urkzGQCxVHfIR5Q,30320 -networkx/algorithms/smallworld.py,sha256=3xT-z2_CVdp5-Ap8vF6fsd3DiavDYtspFNZrcwcpXG0,13565 -networkx/algorithms/smetric.py,sha256=_Aj4BIMnafiXbJtLkvAfAnIEMdI9OcVvMy6kk9KKTns,770 -networkx/algorithms/sparsifiers.py,sha256=4T8pMlh-usEHA2-rZFh-CmZbBY9dcXIHjoqR-oJ2hSw,10048 -networkx/algorithms/structuralholes.py,sha256=CS89P45_m1JGFGnSGA-FlC2xnt0BYq3O5ky1zkjYEDI,9342 -networkx/algorithms/summarization.py,sha256=CygTsSthyCKHs0ZTZsCgWnyaT8annQbLpUtahmfY9Sw,23251 -networkx/algorithms/swap.py,sha256=NVZMmlnkdxgwwNw5GDrc8waNERcdCu52ydHcBdOA_hw,14744 -networkx/algorithms/threshold.py,sha256=1HBOrQTyEaEp2uoIHsAlTEMpYAYXoRnR-6PaOKIjdZE,31150 -networkx/algorithms/time_dependent.py,sha256=PAeJ7Yt8kUqbDgvBaz_ZfUFZg-w-vf1gPC0HO6go_TI,5762 -networkx/algorithms/tournament.py,sha256=nx-PSefooyyYAwhFa9a7SRZSRL_ky5Rq19lYP79-0E8,11579 -networkx/algorithms/triads.py,sha256=Gf0f6liwgARszL-R4yQle-ogGH4mJkF-gureeUTxGyY,16853 -networkx/algorithms/vitality.py,sha256=8M1cubIydO49El2kwVCURHZ2UwCtfGVFeGS8-JYt1ko,2289 -networkx/algorithms/voronoi.py,sha256=07SnSpxLDz4k6K59Jo-VTNA-Qy5knaHfBC-y_5vAOLQ,3183 -networkx/algorithms/walks.py,sha256=0JOLhpAyeNzmF8EtlVlYOWEPJJvCIltt7tbk1Vx52dI,2427 -networkx/algorithms/wiener.py,sha256=WOUG0L5xDKpY4uspyI-oDo1hWuHxbUnTFZEe_-IAx5M,7639 -networkx/algorithms/approximation/__init__.py,sha256=CydjSsAU3qlxRwDTvgLyjQRgIuhL1e1STrjPdfqtfSE,1178 -networkx/algorithms/approximation/clique.py,sha256=b4cnWMJXmmgCyjMI8A_doHZeKS_RQbGqm2L01OpT_Jg,7691 -networkx/algorithms/approximation/clustering_coefficient.py,sha256=SWpSLEhW3DJc1n2fHlSbJSGg3wdoJkN5Y4_tnntn0Ws,2164 -networkx/algorithms/approximation/connectivity.py,sha256=aVXSfUiWEG4gUL0R1u6WZ-h-wheuLP1_suO_pRFB8M4,13118 -networkx/algorithms/approximation/distance_measures.py,sha256=UEkmKagNw9sj8kiUDdbAeYuzvZ31pgLMXqzliqMkG84,5805 -networkx/algorithms/approximation/dominating_set.py,sha256=5fC90w1CgYR4Xkpqact8iukKY0i57bMmyJW-A9CToUQ,4710 -networkx/algorithms/approximation/kcomponents.py,sha256=MDkoyQbk0gSAm3ZZK35VOsiLJDv7wiDsxfzH5O-ObFs,13285 -networkx/algorithms/approximation/matching.py,sha256=PFof5m9AIq9Xr5Kaa_-mYxI1IBBP7HEkjf-R9wVE3bo,1175 -networkx/algorithms/approximation/maxcut.py,sha256=eTQZqsDQAAUaufni-aDJAY2UzIcajDhRMdj-AcqVkPs,4333 -networkx/algorithms/approximation/ramsey.py,sha256=W5tX7BOQJIM_qNsBeUhCXVWMD8DFdeTycYyk08k4Sqk,1358 -networkx/algorithms/approximation/steinertree.py,sha256=dbPciMrLHmb1XWa0v7-v3qNFJ3Z7pZD0n4RAGF8eob4,8048 -networkx/algorithms/approximation/traveling_salesman.py,sha256=af4HEUYtuoulBpAQZJT2zqoUu8x08NtL1cQL5uGqe9E,55943 -networkx/algorithms/approximation/treewidth.py,sha256=Yu944jTE9MODBo1QiZjxbAGmHiC5MXZZTNV1YrLfz9o,8216 -networkx/algorithms/approximation/vertex_cover.py,sha256=oIi_yg5O-IisnfmrSof1P4HD-fsZpW69RpvkR_SM5Og,2803 -networkx/algorithms/approximation/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/approximation/tests/test_approx_clust_coeff.py,sha256=PGOVEKf2BcJu1vvjZrgTlBBpwM8V6t7yCANjyS9nWF0,1171 -networkx/algorithms/approximation/tests/test_clique.py,sha256=s6HQB-lK3RAu_ftpe2NvIiMu0Ol8tpAdbGvWzucNL6k,3021 -networkx/algorithms/approximation/tests/test_connectivity.py,sha256=gDG6tsgP3ux7Dgu0x7r0nso7_yknIxicV42Gq0It5pc,5952 -networkx/algorithms/approximation/tests/test_distance_measures.py,sha256=axgOojplJIgXdopgkjxjAgvzGTQ1FV1oJ5NG-7ICalo,2023 -networkx/algorithms/approximation/tests/test_dominating_set.py,sha256=l4pBDY7pK7Fxw-S4tOlNcxf-j2j5GpHPJ9f4TrMs1sI,2686 -networkx/algorithms/approximation/tests/test_kcomponents.py,sha256=tTljP1FHzXrUwi-oBz5AQcibRw1NgR4N5UE0a2OrOUA,9346 -networkx/algorithms/approximation/tests/test_matching.py,sha256=nitZncaM0605kaIu1NO6_5TFV2--nohUCO46XTD_lnM,186 -networkx/algorithms/approximation/tests/test_maxcut.py,sha256=U6CDZFSLfYDII-1nX9XB7avSz10kTx88vNazJFoLQ1k,2804 -networkx/algorithms/approximation/tests/test_ramsey.py,sha256=h36Ol39csHbIoTDBxbxMgn4371iVUGZ3a2N6l7d56lI,1143 -networkx/algorithms/approximation/tests/test_steinertree.py,sha256=rxkj8OWDWFqSE5MI3XC4NSOgyNUzYVfxKSskutOPtbQ,9671 -networkx/algorithms/approximation/tests/test_traveling_salesman.py,sha256=lLnnWvs88JBkhkf4Cg8qBipSvRnjn9W9WvOKZ-Gew6Q,30842 -networkx/algorithms/approximation/tests/test_treewidth.py,sha256=MWFFcmjO0QxM8FS8iXSCtfGnk6eqG2kFyv1u2qnSeUo,9096 -networkx/algorithms/approximation/tests/test_vertex_cover.py,sha256=FobHNhG9CAMeB_AOEprUs-7XQdPoc1YvfmXhozDZ8pM,1942 -networkx/algorithms/assortativity/__init__.py,sha256=ov3HRRbeYB_6Qezvxp1OTl77GBpw-EWkWGUzgfT8G9c,294 -networkx/algorithms/assortativity/connectivity.py,sha256=-V0C5MTqtErl86N-gyrZ487MUyiG5x1QFEZKurOpIJA,4220 -networkx/algorithms/assortativity/correlation.py,sha256=0rc4FDi-e8eQRia7gpFrTqjIy-J7V2GtSwOb4QN6WZk,8689 -networkx/algorithms/assortativity/mixing.py,sha256=RRqqkuVwo71LosJLDbeVCVBikqC7I_XZORdsonQsf9Y,7586 -networkx/algorithms/assortativity/neighbor_degree.py,sha256=UMaQWKBkOZ0ZgC8xGt5fXEz8OL1rgwYjt2zKbKEqofI,5282 -networkx/algorithms/assortativity/pairs.py,sha256=w7xnaWxDDteluHoCsqunLlcM6nlcBenO_5Nz87oOEnE,3841 -networkx/algorithms/assortativity/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/assortativity/tests/base_test.py,sha256=MNeQMLA3oBUCM8TSyNbBQ_uW0nDc1GEZYdNdUwePAm4,2651 -networkx/algorithms/assortativity/tests/test_connectivity.py,sha256=Js841GQLYTLWvc6xZhnyqj-JtyrnS0ska1TFYntxyXA,4978 -networkx/algorithms/assortativity/tests/test_correlation.py,sha256=1_D9GjLDnlT8Uy28lUn2fS1AHp2XBwiMpIl2OhRNDXk,5069 -networkx/algorithms/assortativity/tests/test_mixing.py,sha256=u-LIccNn-TeIAM766UtzUJQlY7NAbxF4EsUoKINzmlo,6820 -networkx/algorithms/assortativity/tests/test_neighbor_degree.py,sha256=ODP2M8jCaFr_l3ODwpwaz20-KqU2IFaEfJRBK53mpE8,3968 -networkx/algorithms/assortativity/tests/test_pairs.py,sha256=t05qP_-gfkbiR6aTLtE1owYl9otBSsuJcRkuZsa63UQ,3008 -networkx/algorithms/bipartite/__init__.py,sha256=811Xu3D1Qx8ncqRshHoN3gWZ_A04Hb2qxzoGuc5vBa4,3825 -networkx/algorithms/bipartite/basic.py,sha256=JPC2gGuPvFA6q2CuI5mqLX_9QUGxrsQ8cIwcS0e9P4U,8375 -networkx/algorithms/bipartite/centrality.py,sha256=G280bAqeyXyCmes5NpRqUv2Tc-EHWrMshJ3_f4uqV9U,9156 -networkx/algorithms/bipartite/cluster.py,sha256=ZDAo7NM69woVY8fNwRjbAz6Wwb99CE650lMmv1v0Omc,6935 -networkx/algorithms/bipartite/covering.py,sha256=B3ITc016Kk70NBv-1lb30emXnfjlMIQJ7M-FIPCZip0,2163 -networkx/algorithms/bipartite/edgelist.py,sha256=l6JqWqedRGde0sOz7oLK-xe9azq_VEYec0-GPlFUIbg,11364 -networkx/algorithms/bipartite/extendability.py,sha256=OrYHlS4ruQST-dlQOuleiqHFKpVVNOvrG5aDNFgfckg,3989 -networkx/algorithms/bipartite/generators.py,sha256=PfnR6S9gKw5OK_JuGMChltWxyd_i8_KYFq1WpRlsL-A,20439 -networkx/algorithms/bipartite/matching.py,sha256=xsT048Ok_uM0Zhpdc34qswV1zaCGOlJQnsbGTDsm5oo,21637 -networkx/algorithms/bipartite/matrix.py,sha256=RuoILyPHjORW0Y_Bcf-vSH_K6-bSUjiTN9JTjnik5HE,6156 -networkx/algorithms/bipartite/projection.py,sha256=YIUlreqQQ6IPE37OXF32zNIdzEGeyR8aY-7iUENZYVA,17252 -networkx/algorithms/bipartite/redundancy.py,sha256=Mnkz0LbNXS0haxtLQ5naorR6C2tNLUbkNS_3PANFxbg,3402 -networkx/algorithms/bipartite/spectral.py,sha256=fu2grV1the_e_G-e_lUdhk8Y9XFe6_p2tPmx3RKntFw,1902 -networkx/algorithms/bipartite/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/bipartite/tests/test_basic.py,sha256=gzbtsQqPi85BznX5REdGBBJVyr9aH4nO06c3eEI4634,4291 -networkx/algorithms/bipartite/tests/test_centrality.py,sha256=PABPbrIyoAziEEQKXsZLl2jT36N8DZpNRzEO-jeu89Y,6362 -networkx/algorithms/bipartite/tests/test_cluster.py,sha256=O0VsPVt8vcY_E1FjjLJX2xaUbhVViI5MP6_gLTbEpos,2801 -networkx/algorithms/bipartite/tests/test_covering.py,sha256=EGVxYQsyLXE5yY5N5u6D4wZq2NcZe9OwlYpEuY6DF3o,1221 -networkx/algorithms/bipartite/tests/test_edgelist.py,sha256=fK35tSekG_-9Ewr5Bhl1bRdwAy247Z9zZ4dQFFDQ9xw,8471 -networkx/algorithms/bipartite/tests/test_extendability.py,sha256=XgPmg6bWiHAF1iQ75_r2NqUxExOQNZRUeYUPzlCa5-E,7043 -networkx/algorithms/bipartite/tests/test_generators.py,sha256=DB9NEapShvX9L5Dpj1OF8bs8LOu5n3zvew60WZhYChQ,13241 -networkx/algorithms/bipartite/tests/test_matching.py,sha256=3-2DMl3tF-g4_xNHvEuY4fZW7S5cqMTO_GUpcz1gkeQ,11973 -networkx/algorithms/bipartite/tests/test_matrix.py,sha256=1MymSi1dCUqAhTt82O2nBzjriNQtFRk6TxWGJ2FBW4k,3094 -networkx/algorithms/bipartite/tests/test_project.py,sha256=FBjkys3JYYzEG4aq_CsQrtm41edZibWI_uDAQ0b4wqM,15134 -networkx/algorithms/bipartite/tests/test_redundancy.py,sha256=utxcrQaTrkcEN3kqtObgKNpLZai8B5sMAqLyXatOuUo,917 -networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py,sha256=1jGDgrIx3-TWOCNMSC4zxmZa7LHyMU69DXh3h12Bjag,2358 -networkx/algorithms/centrality/__init__.py,sha256=Er3YoYoj76UfY4P6I0L-0fCQkO7mMU0b3NLsTT2RGWI,558 -networkx/algorithms/centrality/betweenness.py,sha256=9kXlMR9T1IHDJ55x2fSMfjuLBy402AREJfQKUW1LfFo,14383 -networkx/algorithms/centrality/betweenness_subset.py,sha256=mkVJdEmR1G8kFoS-KN-jwhUyR_CUiB8DXneGqsqyB6U,9336 -networkx/algorithms/centrality/closeness.py,sha256=ehkntG-gApT9uhWJjGaEZQ-tEQ-hdxDT7luf-uVPNAE,10281 -networkx/algorithms/centrality/current_flow_betweenness.py,sha256=zZRqgrB06uDzgwWJ_FLUF3DSrgkER1tvakYZHX8DbSY,11848 -networkx/algorithms/centrality/current_flow_betweenness_subset.py,sha256=2qtLgf_3ft5qdDvHFrfYUt6zeQi42Nw7XBpSZRboJIA,8107 -networkx/algorithms/centrality/current_flow_closeness.py,sha256=IvecI8BZE4SgKayEXhKowIJw7S2fD_dN__N-f9TW-ME,3327 -networkx/algorithms/centrality/degree_alg.py,sha256=EFTA1b_GWUbmBy5R9beRQp7yh1X_NwZtk5L6is-mFGk,3894 -networkx/algorithms/centrality/dispersion.py,sha256=M12L2KiVPrC2-SyCXMF0kvxLelgcmvXJkLT_cBHoCTw,3631 -networkx/algorithms/centrality/eigenvector.py,sha256=LAxVqaT3LmuQw20__t1KrgLKPF1Cz-PkTaiSrgPC1FU,13623 -networkx/algorithms/centrality/flow_matrix.py,sha256=Y65m6VbWyYjNK0CInE_lufyEkKy9-TyPmBeXb-Gkz70,3834 -networkx/algorithms/centrality/group.py,sha256=-YaVfnJ6HKT6b1P-IhyUKtJvXk0ZSnC2Jz4XP6hjkyE,27960 -networkx/algorithms/centrality/harmonic.py,sha256=ZPp8FYFgSUZS0QBxUbzhi39qiv_EN7COirxZEYiTCIM,2847 -networkx/algorithms/centrality/katz.py,sha256=uVGHAyjqndSd4y4idHjkv0mUhmKmHU5vaEfNWfiKlzc,11042 -networkx/algorithms/centrality/laplacian.py,sha256=8-qloyxvFc33xlfpj7Xol8qeOvPAg_Z0BHVZGSxjnmc,5640 -networkx/algorithms/centrality/load.py,sha256=M2EdPX4gJEYGjMBIJMFKRWGI9uYHbFOWYxsILeaJuOE,6859 -networkx/algorithms/centrality/percolation.py,sha256=YJB8iYgbpjJ3EYK8pl26iSnjgfFsK31ufytRHnUTYYE,4419 -networkx/algorithms/centrality/reaching.py,sha256=OFWHlDUtCaQXHWxAfEgPpinej-0anLJQZsCvh3D8gME,7243 -networkx/algorithms/centrality/second_order.py,sha256=4CTboP95B6gUtAtSKLfeeE4s9oq0_3hXsXczxL6c_g8,5012 -networkx/algorithms/centrality/subgraph_alg.py,sha256=HtwSPYMRUxhaAuvMA90Qu2i1smXSpVpLRtHlBohnpSc,9513 -networkx/algorithms/centrality/trophic.py,sha256=q--TsLcfGNCSet_A6oLVf7CGWQBvDxDOlkjozduZfxY,4679 -networkx/algorithms/centrality/voterank_alg.py,sha256=z_1eq8rSDadEO5W5BbAg1zuOJj2di4FUCkmOwiuK12I,3231 -networkx/algorithms/centrality/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/centrality/tests/test_betweenness_centrality.py,sha256=pKoPAP1hnQSgrOxYeW5-LdUiFDANiwTn_NdOdgccbo8,26795 -networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py,sha256=HrHMcgOL69Z6y679SbqZIjkQOnqrYSz24gt17AJ9q-o,12554 -networkx/algorithms/centrality/tests/test_closeness_centrality.py,sha256=Ziz_LMgRJHT1pz_sgT4oCZPmOeWJL7OmfUSI8UCC1dI,10210 -networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py,sha256=VOxx1A7iSGtdEbzJYea_sW_Hv0S71-oo1CVX7Rqd5RY,7870 -networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py,sha256=JfRGgPuiF-vJu5fc2_pcJYREEboxcK_dmy-np39c4Aw,5839 -networkx/algorithms/centrality/tests/test_current_flow_closeness.py,sha256=vflQeoNKngrGUiRb3XNlm2X9wR4vKgMSW_sCyMUCQi8,1379 -networkx/algorithms/centrality/tests/test_degree_centrality.py,sha256=Jn_p5lThA3__ZBTDAORwo_EchjXKKkK1NwU_73HHI6M,4101 -networkx/algorithms/centrality/tests/test_dispersion.py,sha256=ROgl_5bGhcNXonNW3ylsvUcA0NCwynsQu_scic371Gw,1959 -networkx/algorithms/centrality/tests/test_eigenvector_centrality.py,sha256=A6REmarGOuDmq3GcSYemyadlFLv24sErIGLtDcL9GO4,5255 -networkx/algorithms/centrality/tests/test_group.py,sha256=833ME4tGlOGQZz8YANw4MSyeVPpjbyCdYh5X88GOprw,8685 -networkx/algorithms/centrality/tests/test_harmonic_centrality.py,sha256=wI7nStX_kIFJoZQY_i8DXXlZBOJzVnQfOP8yidX0PAU,3867 -networkx/algorithms/centrality/tests/test_katz_centrality.py,sha256=JL0bZZsJe2MQFL6urXgY82wCAwucUvhjaShYZPxpL6U,11240 -networkx/algorithms/centrality/tests/test_laplacian_centrality.py,sha256=vY-NULtr_U_GxUMwfAZB-iccxIRTiqqUN4Q8HRNpzSo,5916 -networkx/algorithms/centrality/tests/test_load_centrality.py,sha256=Vv3zSW89iELN-8KNbUclmkhOe1LzKdF7U_w34nYovIo,11343 -networkx/algorithms/centrality/tests/test_percolation_centrality.py,sha256=ycQ1fvEZZcWAfqL11urT7yHiEP77usJDSG25OQiDM2s,2591 -networkx/algorithms/centrality/tests/test_reaching.py,sha256=_JVeO1Ri-KybdnGCJ_yNPtJQmT_g77z0DAkU0JYFVGQ,5090 -networkx/algorithms/centrality/tests/test_second_order_centrality.py,sha256=ce0wQ4T33lu23wskzGUnBS7X4BSODlvAX1S5KxlLzOA,1999 -networkx/algorithms/centrality/tests/test_subgraph.py,sha256=vhE9Uh-_Hlk49k-ny6ORHCgqk7LWH8OHIYOEYM96uz0,3729 -networkx/algorithms/centrality/tests/test_trophic.py,sha256=_lmwb0_78iX_cxgUKHjCRCSxohVMkRrkKqSaB5QV3ys,8705 -networkx/algorithms/centrality/tests/test_voterank.py,sha256=tN5u7pKAnJ_4AiwhPW6EuJZz7FLIG2jYqLKcXFi2urk,1687 -networkx/algorithms/coloring/__init__.py,sha256=P1cmqrAjcaCdObkNZ1e6Hp__ZpxBAhQx0iIipOVW8jg,182 -networkx/algorithms/coloring/equitable_coloring.py,sha256=uDcza6PD9qbvwVPUX1MBZbopQdrAEKNk6DpCFkc02tU,16315 -networkx/algorithms/coloring/greedy_coloring.py,sha256=6Jzcc4iW5KuRVFEEr15v8rBvik3g4maa7_wcjWyyRDI,20046 -networkx/algorithms/coloring/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/coloring/tests/test_coloring.py,sha256=7v_d1xanjYMZCa3dq2hE2hCcyexwWBTEFV5SoLgQDv4,23697 -networkx/algorithms/community/__init__.py,sha256=0YrcAVLTxJt3u-htlaSPZ-XSRn0Jg-EQKCMRPmWuw-g,1179 -networkx/algorithms/community/asyn_fluid.py,sha256=0ktsoOa4JKBKiuE3wmGDcBSUgPlFdGvzNheqINtWKbk,5935 -networkx/algorithms/community/centrality.py,sha256=Yyv5kyf1hf_L7iQ_ZbG8_FAkP638Sc_3N4tCSoB6J1w,6635 -networkx/algorithms/community/community_utils.py,sha256=sUi-AcPYyGrYhnjI9ztt-vrSHLl28lKXxTJPfi5N0c8,908 -networkx/algorithms/community/divisive.py,sha256=yFcKfKkiI6FqEVlBVxLa1fbqI1Yeiqe_A5fpPnYvlAE,6655 -networkx/algorithms/community/kclique.py,sha256=DTr9iUT_XWv0S3Y79KQl6OXefjztNMc9SAHWhdFOxcU,2460 -networkx/algorithms/community/kernighan_lin.py,sha256=vPU8Mbpk7_NscMC-gorNoXhsQjkOhgK2YiKOo-u6DvY,4349 -networkx/algorithms/community/label_propagation.py,sha256=LhzAXSHFCPQ2kG_rPgXb06YKdppO7buApksCC4GI4w8,11878 -networkx/algorithms/community/louvain.py,sha256=zh5h16hRWzgTv9IUqWiiJKFntZhQbB_EHNYIGViwPas,15365 -networkx/algorithms/community/lukes.py,sha256=gzqnup95RR2UzUiPpIt8qkepzZ9dCWqHGQSVPIJDMx8,8115 -networkx/algorithms/community/modularity_max.py,sha256=gzyZrGHNMtTZyqpLFcJHxgzzIsar1m5DktScODoUngk,18082 -networkx/algorithms/community/quality.py,sha256=dVIkV-CFKdAou0WjgIDmfhnpIIqReRaeL4odg39XAYk,11939 -networkx/algorithms/community/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/community/tests/test_asyn_fluid.py,sha256=UzAMxJzhN74qUinehR7B1rhU_vsigJ7-cRvcE6jdKyc,3332 -networkx/algorithms/community/tests/test_centrality.py,sha256=s8q4k5aThR0OgO9CDQk_PXMxfllmf5uC1GlvyUc_8EY,2932 -networkx/algorithms/community/tests/test_divisive.py,sha256=-Ee40OR-mPDReTngTEhbpx4_uLtNI7cqFkt8cZT9t5Y,3441 -networkx/algorithms/community/tests/test_kclique.py,sha256=iA0SBqwbDfaD2u7KM6ccs6LfgAQY_xxrnW05UIT_tFA,2413 -networkx/algorithms/community/tests/test_kernighan_lin.py,sha256=rcFDI9mTq1Nwsi251PwDgi1UoxTMPXAeSy2Cp6GtUQg,2710 -networkx/algorithms/community/tests/test_label_propagation.py,sha256=IHidFEv7MI781zsdk7XT848rLvLwDk2wBK1FjL-CRv4,7985 -networkx/algorithms/community/tests/test_louvain.py,sha256=TwW1nlSKWGJeIKr9QOJ8xGehSY6R0Nz01xsnFqzt0Oo,8071 -networkx/algorithms/community/tests/test_lukes.py,sha256=f_JU-EzY6PwXEkPN8kk5_3NVg6phlX0nrj1f57M49lk,3961 -networkx/algorithms/community/tests/test_modularity_max.py,sha256=XYyPuDkxL4CYFwnpTdU_qD4GydpqgiRAIJO3CHQN_m4,10617 -networkx/algorithms/community/tests/test_quality.py,sha256=sZEy10hh3zlelUmww5r2pk5LxpZAht06PC5zCHxV1bs,5275 -networkx/algorithms/community/tests/test_utils.py,sha256=gomD6rFgAaywxT1Yjdi4ozY-1rC0ina4jgfvWeCvwGE,704 -networkx/algorithms/components/__init__.py,sha256=Dt74KZWp_cJ_j0lL5hd_S50_hia5DKcC2SjuRnubr6M,173 -networkx/algorithms/components/attracting.py,sha256=6az3lgqWhHTXaWUUuOPZfW9t7okliAhooFRotQY5JoM,2712 -networkx/algorithms/components/biconnected.py,sha256=_9GJdPZgqusGKZLzqT9tUSj1XZr2DgohiT6hcHVyil4,12782 -networkx/algorithms/components/connected.py,sha256=r-jNJJkxoDtFcYiuoteyZb3a2oEHh0j0WBddwsXj_a4,4459 -networkx/algorithms/components/semiconnected.py,sha256=BaBMFlQ208vuHOo5y1xeV0PDEI3yDUfH6zFb_jkcVhQ,2030 -networkx/algorithms/components/strongly_connected.py,sha256=i41vDeazdNGqG4weufAKd6axaN2nBKmMzURZBs7WsLI,9542 -networkx/algorithms/components/weakly_connected.py,sha256=jFHHr0qTZH57IyFIQ8iD5gekgczQXTPRHrtYoXVYYPM,4455 -networkx/algorithms/components/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/components/tests/test_attracting.py,sha256=b3N3ZR9E5gLSQWGgaqhcRfRs4KBW6GnnkVYeAjdxC_o,2243 -networkx/algorithms/components/tests/test_biconnected.py,sha256=N-J-dgBgI77ytYUUrXjduLxtDydH7jS-af98fyPBkYc,6036 -networkx/algorithms/components/tests/test_connected.py,sha256=KMYm55BpbFdGXk_B2WozS9rIagQROd7_k0LT3HFQmr4,4815 -networkx/algorithms/components/tests/test_semiconnected.py,sha256=q860lIxZF5M2JmDwwdzy-SGSXnrillOefMx23GcJpw0,1792 -networkx/algorithms/components/tests/test_strongly_connected.py,sha256=Zm7MgUIZbuPPJu66xZH1zfMZQ_3X1YBl2fLCOjph7NQ,6021 -networkx/algorithms/components/tests/test_weakly_connected.py,sha256=_eUx7226dxme_K2WNmvSIwZXQlKNoCuglWOOC3kFUW4,3083 -networkx/algorithms/connectivity/__init__.py,sha256=EvYKw8LJn7wyZECHAsuEkIaSl-cV-LhymR6tqcn90p8,281 -networkx/algorithms/connectivity/connectivity.py,sha256=KuvVbJ0dAmG2h51uFo9IdBIK1G1PYaTZ-XFT78ksZEo,29367 -networkx/algorithms/connectivity/cuts.py,sha256=d9O6G3fuhjg0GEuDSm6QyYhm3OTBKFZeHC7Tz6IZ0Mg,23015 -networkx/algorithms/connectivity/disjoint_paths.py,sha256=R0HDHrrhdI1E_do3U6t6oseXsrGJlG7PC89kXCPC1v8,14649 -networkx/algorithms/connectivity/edge_augmentation.py,sha256=SE7CkLjtxG-q6DZPZH33g6MJcYA1KsJgHm-Pm575gkA,44061 -networkx/algorithms/connectivity/edge_kcomponents.py,sha256=hqABcfCqZ-rb45I0qYE-X4NtstsKJbxl37FZzzmoXA4,20894 -networkx/algorithms/connectivity/kcomponents.py,sha256=TtiEvpaKflkdxJ3r37Qsj1qrSzB2rtHzDcxCDO_Aq2Q,8171 -networkx/algorithms/connectivity/kcutsets.py,sha256=zYohzgkR2FODi_Ew2M9uMLb_a9ZP5fNqcXJwMYy6P7o,9371 -networkx/algorithms/connectivity/stoerwagner.py,sha256=WodsJEqKgsmTTcyUBk2u3wV_CXeon-cAzveWgIGgFmA,5431 -networkx/algorithms/connectivity/utils.py,sha256=gL8LmZnK4GKAZQcIPEhVNYmVi18Mqsqwg4O4j_et56s,3217 -networkx/algorithms/connectivity/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/connectivity/tests/test_connectivity.py,sha256=eSmsi8uQk6MI591JgtSu2elIusb08bmSZS0h9gxb76I,15027 -networkx/algorithms/connectivity/tests/test_cuts.py,sha256=4F8seWb-sPDDjjVMkh14gst5UQa5f-zDkCsZIdJjVzo,10353 -networkx/algorithms/connectivity/tests/test_disjoint_paths.py,sha256=NLHReLoXSKoA6KPBNRbjF84ktg5PEaaktIj2AII3SDY,8392 -networkx/algorithms/connectivity/tests/test_edge_augmentation.py,sha256=d3ymFHyY2G4cpy1Y6wu4ze339qfF2LRp2HmGAIVjnMM,15731 -networkx/algorithms/connectivity/tests/test_edge_kcomponents.py,sha256=CZ26Dy91WOUqhw1X73mqLGX-WHWzBBIeBCgrp6KK4Zo,16453 -networkx/algorithms/connectivity/tests/test_kcomponents.py,sha256=ohoSX8GACeszRZdzTiNuWXSFitfU9DzP0hqllS2gvMU,8554 -networkx/algorithms/connectivity/tests/test_kcutsets.py,sha256=sVKjwQt3FUqtnlY2xuHn6VGY9rvUkYoVp7v5fK-6aJw,8610 -networkx/algorithms/connectivity/tests/test_stoer_wagner.py,sha256=A291C30_t2CI1erPCqN1W0DoAj3zqNA8fThPIj4Rku0,3011 -networkx/algorithms/flow/__init__.py,sha256=rVtMUy6dViPLewjDRntmn15QF0bQwiDdQbZZx9j7Drc,341 -networkx/algorithms/flow/boykovkolmogorov.py,sha256=qFcppmiXz4VKKFd4RbDsiWOqJODtDTHbNr9_UFTjQaU,13334 -networkx/algorithms/flow/capacityscaling.py,sha256=8rng2qO5kawNSxq2S8BNlUMmdvNSoC6R8ekiBGU8LxU,14469 -networkx/algorithms/flow/dinitz_alg.py,sha256=I5nnZVsj0aU8-9Cje0umey407epFzpd7BDJpkI6ESK4,8341 -networkx/algorithms/flow/edmondskarp.py,sha256=PEIwLftevS2VYHaTzzZMSOLPy7QSBPsWPedjx1lR6Cs,8056 -networkx/algorithms/flow/gomory_hu.py,sha256=EuibaxPl65shGM9Jxvaa9WMwMmoczDvXXc2b0E81cqM,6345 -networkx/algorithms/flow/maxflow.py,sha256=3_v0FUEHulFrOeSDM1FMcmOF3yTYvxUbLGv3MNTNp1Q,22795 -networkx/algorithms/flow/mincost.py,sha256=GzMYInS4QcNe0yImGrVXJ0bRd7t5TSSMa9jSeenIoOk,12853 -networkx/algorithms/flow/networksimplex.py,sha256=32uetoZWj-_7KPO2OJputP0FpTrsQ_qJxntC8XxIVr0,25185 -networkx/algorithms/flow/preflowpush.py,sha256=CUKZ0-7X9l7P7qH_2n2Immbf8mFm8vocH2SY0tIwjGo,15721 -networkx/algorithms/flow/shortestaugmentingpath.py,sha256=gXXdkY3nH4d0hXVn0P2-kzfC3DHcuCdrudFdxetflKI,10372 -networkx/algorithms/flow/utils.py,sha256=bCeiFAiyFe4-ptkCopo_PnQKF9xY5M8Br87hJT3fRWQ,6084 -networkx/algorithms/flow/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/flow/tests/gl1.gpickle.bz2,sha256=z4-BzrXqruFiGqYLiS2D5ZamFz9vZRc1m2ef89qhsPg,44623 -networkx/algorithms/flow/tests/gw1.gpickle.bz2,sha256=b3nw6Q-kxR7HkWXxWWPh7YlHdXbga8qmeuYiwmBBGTE,42248 -networkx/algorithms/flow/tests/netgen-2.gpickle.bz2,sha256=OxfmbN7ajtuNHexyYmx38fZd1GdeP3bcL8T9hKoDjjA,18972 -networkx/algorithms/flow/tests/test_gomory_hu.py,sha256=aWtbI3AHofIK6LDJnmj9UH1QOfulXsi5NyB7bNyV2Vw,4471 -networkx/algorithms/flow/tests/test_maxflow.py,sha256=4CtGOqeyloAxFSajaxPfGuyVhE0R3IdJf2SuIg4kHKQ,18940 -networkx/algorithms/flow/tests/test_maxflow_large_graph.py,sha256=1a7pS0i5sj_kowLelETcHdrf7RmPEhAJnmCT03JZ0K8,4622 -networkx/algorithms/flow/tests/test_mincost.py,sha256=n4fFLDwDLy7Tau-_ey1CoxZwKhFjk28GLGJjCyxhClk,17816 -networkx/algorithms/flow/tests/test_networksimplex.py,sha256=bsVxlvHAD0K7aDevCcVaa9uRNNsWAevw6yUKlj2T8No,12103 -networkx/algorithms/flow/tests/wlm3.gpickle.bz2,sha256=zKy6Hg-_swvsNh8OSOyIyZnTR0_Npd35O9RErOF8-g4,88132 -networkx/algorithms/isomorphism/__init__.py,sha256=gPRQ-_X6xN2lJZPQNw86IVj4NemGmbQYTejf5yJ32N4,406 -networkx/algorithms/isomorphism/ismags.py,sha256=TpZP5xDxLITCGOk8DT4EBVaWDbbjzEUT5ZOCDNGAho0,43239 -networkx/algorithms/isomorphism/isomorph.py,sha256=Yg2Aukv0tVZIQ66jxzDS4DPBjX6DMKwT0_WNH12fsgk,7114 -networkx/algorithms/isomorphism/isomorphvf2.py,sha256=_IdR1YRm8N9z-HaX2XtzPRq-2j3_jqlcJ8WSrvAyE5g,46785 -networkx/algorithms/isomorphism/matchhelpers.py,sha256=PaZ7PjmNNsJO9KoeRrf9JgcDHIcFr1tZckQc_ol4e9I,10884 -networkx/algorithms/isomorphism/temporalisomorphvf2.py,sha256=-1NW81l8kM9orQ2ni9tcNizQzEhOUE9BaBJXjUWqhiI,10948 -networkx/algorithms/isomorphism/tree_isomorphism.py,sha256=fj1cUspSojUVwmAdWKGzXEHqOawUNJgzfO9QjCEnPLs,9454 -networkx/algorithms/isomorphism/vf2pp.py,sha256=WNXf7g0u3c8R3IsX2YuP3gWU5sjb0uqjuDSvmtob_QE,36421 -networkx/algorithms/isomorphism/vf2userfunc.py,sha256=HiPwyr7nJF1QS9w69MzKf6wGvO8cgjvdS5vW59iwCew,7371 -networkx/algorithms/isomorphism/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/isomorphism/tests/iso_r01_s80.A99,sha256=hKzMtYLUR8Oqp9pmJR6RwG7qo31aNPZcnXy4KHDGhqU,1442 -networkx/algorithms/isomorphism/tests/iso_r01_s80.B99,sha256=AHx_W2xG4JEcz1xKoN5TwCHVE6-UO2PiMByynkd4TPE,1442 -networkx/algorithms/isomorphism/tests/si2_b06_m200.A99,sha256=NVnPFA52amNl3qM55G1V9eL9ZlP9NwugBlPf-zekTFU,310 -networkx/algorithms/isomorphism/tests/si2_b06_m200.B99,sha256=-clIDp05LFNRHA2BghhGTeyuXDqBBqA9XpEzpB7Ku7M,1602 -networkx/algorithms/isomorphism/tests/test_ismags.py,sha256=8D1jWosarNJ0ZzCYgfwy0mB62YVZAMvG-UF9Q0peRa0,10581 -networkx/algorithms/isomorphism/tests/test_isomorphism.py,sha256=kF-o4dTjB7Ad0NOHnUGoiOCCNr3MWSmJm_YBc-Wvhgk,2022 -networkx/algorithms/isomorphism/tests/test_isomorphvf2.py,sha256=qisgeaCLO8ytf09DP7zANsnWdAHPu1lvJl4Gmg2zD6M,11747 -networkx/algorithms/isomorphism/tests/test_match_helpers.py,sha256=uuTcvjgf2LPqSQzzECPIh0dezw8-a1IN0u42u8TxwAw,2483 -networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py,sha256=k8032J4ItZ4aFHeOraOpiF8y4aPm2O1g44UvUfrQJgg,7343 -networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py,sha256=0-7waJjupg8AWfQDqrcsJVOgTXk7HePr5kt87MgnPtM,7412 -networkx/algorithms/isomorphism/tests/test_vf2pp.py,sha256=65RkN1mPWLoxirE7SlIvfaKMJk80b_ZwWG6HTJtlkPg,49924 -networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py,sha256=HnXcdy2LTBFX423nIdJ8CbwmfkHFmzf1XNa8-xld5jk,90125 -networkx/algorithms/isomorphism/tests/test_vf2userfunc.py,sha256=KMRPb-m3fmvRF0vt9laKIzOfwnrkxN2SueLv7JWUuXs,6625 -networkx/algorithms/link_analysis/__init__.py,sha256=UkcgTDdzsIu-jsJ4jBwP8sF2CsRPC1YcZZT-q5Wlj3I,118 -networkx/algorithms/link_analysis/hits_alg.py,sha256=OJ2DPKn_qGDBiW7Tln8_vLtJGvBkzWbOxylbHn95ne4,10421 -networkx/algorithms/link_analysis/pagerank_alg.py,sha256=BlJr6dsDfUNdU0mH8BmqWLt8Hzra-wBwWmQFHArTJc8,17191 -networkx/algorithms/link_analysis/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/link_analysis/tests/test_hits.py,sha256=QjSZZmrj3rBLNVpKOIHUvJNYM7OJ1b-yjiaglyVzNyw,2547 -networkx/algorithms/link_analysis/tests/test_pagerank.py,sha256=szFqJoRJrDojANbuAaw7kfX-cLjEne6tOyek3-Cax_4,7283 -networkx/algorithms/minors/__init__.py,sha256=ceeKdsZ6U1H40ED-KmtVGkbADxeWMTVG07Ja8P7N_Pg,587 -networkx/algorithms/minors/contraction.py,sha256=EviSuRlx5EsGiWNbGrSSfAYfPV19jzIN8H_l596YHbI,22870 -networkx/algorithms/minors/tests/test_contraction.py,sha256=YjBXi-byijqbh_OxLpLK7_au5A5YCoVTlta7hnnK4Gg,14213 -networkx/algorithms/operators/__init__.py,sha256=dJ3xOXvHxSzzM3-YcfvjGTJ_ndxULF1TybkIRzUS87Y,201 -networkx/algorithms/operators/all.py,sha256=pNIKjEiSBBiUa6zcYZHQIiiHq3C9hnazSyaIpasvBxw,9652 -networkx/algorithms/operators/binary.py,sha256=mRgkFsPoAw2PuqMIwRmS59vYC2KFJ47dB_lct5HRAh4,12948 -networkx/algorithms/operators/product.py,sha256=FQkSIduOv-z1ktVzid2T40759S-BmAfTlya88VytuZc,19632 -networkx/algorithms/operators/unary.py,sha256=Eo2yeTg-F5uODGWSWR_im5VaKZQ97LyATIuKZcAFQR8,1795 -networkx/algorithms/operators/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/operators/tests/test_all.py,sha256=Pqjv9QiA0875Yl9D5o6c5Ml0t4KHpH2a5jbpAoZQXFc,8250 -networkx/algorithms/operators/tests/test_binary.py,sha256=QzQTfnkHf1ulVvvNsclfkQgzRGc9hGQdZDyf4F9O5n8,12171 -networkx/algorithms/operators/tests/test_product.py,sha256=i4pBb5A4NmaCsllR1XizyhUToaQFMuLZ-JrywkQFdbU,15155 -networkx/algorithms/operators/tests/test_unary.py,sha256=UZdzbt5GI9hnflEizUWXihGqBWmSFJDkzjwVv6wziQE,1415 -networkx/algorithms/shortest_paths/__init__.py,sha256=Rmxtsje-mPdQyeYhE8TP2NId-iZEOu4eAsWhVRm2Xqk,285 -networkx/algorithms/shortest_paths/astar.py,sha256=EhUUKwQ6kGBPVXVA7inJN3tb5nr45M99kEDygVcLPf8,8967 -networkx/algorithms/shortest_paths/dense.py,sha256=rdMTlAwrboZMaA8Hj0RmbEpqNNU9zmBxk5Ljswsg37U,8211 -networkx/algorithms/shortest_paths/generic.py,sha256=6N22Kf1t-7HFPn2-QoLqbm1kJSKk5dWCimNi8UuYzM4,25738 -networkx/algorithms/shortest_paths/unweighted.py,sha256=3Up0AF835pSSgSQjzmTK8fw42o0CGc-tsrjenTRfjQc,15642 -networkx/algorithms/shortest_paths/weighted.py,sha256=AGX34ATlzEi1_cyayRzxeUnEPjauQmbc-nKBng6wAL0,82465 -networkx/algorithms/shortest_paths/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/shortest_paths/tests/test_astar.py,sha256=G9hrEo2U9c_kzaRTAXYbS1TpcJgF_uqj9249K2qbjAY,8941 -networkx/algorithms/shortest_paths/tests/test_dense.py,sha256=ievl4gu3Exl_31hp4OKcsAGPb3g3_xFUM4t3NnvrG_A,6747 -networkx/algorithms/shortest_paths/tests/test_dense_numpy.py,sha256=BNwXCe2wgNPE8o35-shPsFj8l19c_QG6Ye8tkIGphf8,2300 -networkx/algorithms/shortest_paths/tests/test_generic.py,sha256=oJBKCLIsMA1KTo8q-oG9JQmaxysc7_QSgbBqMImh23c,18456 -networkx/algorithms/shortest_paths/tests/test_unweighted.py,sha256=kMDgx5JP2QHyOST41zhyUiSc3qajKalAJP6W0Mt3oeg,5891 -networkx/algorithms/shortest_paths/tests/test_weighted.py,sha256=dmzFBYN3QEDZoun7RAtSe_spsGSbvkDiJSgUf9e-1K8,35038 -networkx/algorithms/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/tests/test_asteroidal.py,sha256=DnWI5_jnaaZMxtG44XD0K690HZs8ez7HU_9dSR-p6eA,502 -networkx/algorithms/tests/test_boundary.py,sha256=1OSJh32FYFhAVYB5zqxhZGEXZLS0HPp9kvfHZvWmD3o,6227 -networkx/algorithms/tests/test_bridges.py,sha256=jSCguECho0GNHnu0vpRh1twyfGP6tWFcaYL1rgvc8mU,4026 -networkx/algorithms/tests/test_broadcasting.py,sha256=2LIMrKmSGSSWRLy5TR_NzDQD1annA2JohpsbEbVJKfE,2021 -networkx/algorithms/tests/test_chains.py,sha256=Vhpf0maR3OUaa6aUxC6FNYLeUvBKPZyFimM4_WsLQKo,4364 -networkx/algorithms/tests/test_chordal.py,sha256=DPdNPY7KtqCsCwYVb4xQfnIm-z35dUJIWxNHtAiQLAQ,4438 -networkx/algorithms/tests/test_clique.py,sha256=FPIF2f8NLODsz-k_qrHt7DolClV_VdNWSh68oe8-ygI,9413 -networkx/algorithms/tests/test_cluster.py,sha256=CzYPJm4QY5SL-amMNh2ItPgQ-FjePPG9EBfIKOZHp6s,15883 -networkx/algorithms/tests/test_communicability.py,sha256=4KK9wU9gAUqHAAAyHwAKpq2dV9g415s_X0qd7Tt83gU,2938 -networkx/algorithms/tests/test_core.py,sha256=CF7YPX3F2pUtBu2sp4ZEAGRldaBkdgr1ufk6UkrETuA,9555 -networkx/algorithms/tests/test_covering.py,sha256=EeBjQ5mxcVctgavqXZ255T8ryFocuxjxdVpIxVUNFvw,2718 -networkx/algorithms/tests/test_cuts.py,sha256=gKm9VDtnmwFli6kgwV1ktEFI_rw84p2Sg02Em6SoW5Q,5376 -networkx/algorithms/tests/test_cycles.py,sha256=Sp7PSNB8iy_iST90uNDv8mXwiSOXWRYLkUFJz9pwHWU,34424 -networkx/algorithms/tests/test_d_separation.py,sha256=ZypzMVDpBZo_4qBlieFlj3RVU6vh7tejEZGlu7qcQbc,10929 -networkx/algorithms/tests/test_dag.py,sha256=aEUvVl7Ht3XC2XdBanoCDNM7vpPb8YELvMQDawLZbhQ,29385 -networkx/algorithms/tests/test_distance_measures.py,sha256=WHsOxV9mI-PqJa08C65Gd3myv5G7fzDehX_atJLql7Q,26154 -networkx/algorithms/tests/test_distance_regular.py,sha256=w27OTUtAI0VQv7cikkOdJg4bo4q7xTNIVE8nbU_x7b8,2915 -networkx/algorithms/tests/test_dominance.py,sha256=QVBj3SarZNm57YKavOLFtwU43xn4fxcEU6chn2Gfuaw,9194 -networkx/algorithms/tests/test_dominating.py,sha256=hyta7ln6BbHaGlpEUla6jVzh2PRuSjvujLSGXrmwZbc,1228 -networkx/algorithms/tests/test_efficiency.py,sha256=QKWMvyjCG1Byt-oNp7Rz_qxnVeT77Zk27lrzI1qH0mA,1894 -networkx/algorithms/tests/test_euler.py,sha256=L4L1ljHVxQxjQQludO2r6k3UZU7WAY_N6WYUjFx1fEk,11209 -networkx/algorithms/tests/test_graph_hashing.py,sha256=MqRwsNbyRWUy94V7UuDqEREuHxFTSn7-d0HzwSDI2As,24534 -networkx/algorithms/tests/test_graphical.py,sha256=uhFjvs04odxABToY4IRig_CaUTpAC3SfZRu1p1T7FwY,5366 -networkx/algorithms/tests/test_hierarchy.py,sha256=uW8DqCdXiAeypkNPKcAYX7aW86CawYH84Q0bW4cDTXo,1184 -networkx/algorithms/tests/test_hybrid.py,sha256=kQLzaMoqZcKFaJ3D7PKbY2O-FX59XDZ1pN5un8My-tk,720 -networkx/algorithms/tests/test_isolate.py,sha256=LyR0YYHJDH5vppQzGzGiJK-aaIV17_Jmla8dMf93olg,555 -networkx/algorithms/tests/test_link_prediction.py,sha256=Jah4vOGDYcWaPSl_iG-0fOXnhu5o8f6wcfakRmWuX7I,20004 -networkx/algorithms/tests/test_lowest_common_ancestors.py,sha256=GvhYCQMnVYD9LHPCNFgWMAUmOV8V5gko0fe05zi1JwU,13153 -networkx/algorithms/tests/test_matching.py,sha256=jhehNkApE5RuMPtbjWNeHn0tPqhVz65mL7QakfRA3Vw,20174 -networkx/algorithms/tests/test_max_weight_clique.py,sha256=M1eoy8OtuQVZkEvNMauV9vqR6hHtOCrtq6INv2qzMyA,6739 -networkx/algorithms/tests/test_mis.py,sha256=Z2tKoqbs-AFPzEBDYO7S8U-F7usLfZJ2l6j2DpZUts4,1865 -networkx/algorithms/tests/test_moral.py,sha256=15PZgkx7O9aXQB1npQ2JNqBBkEqPPP2RfeZzKqY-GNU,452 -networkx/algorithms/tests/test_node_classification.py,sha256=NgJJKUHH1GoD1GE3F4QRYBLM3fUo_En3RNtZvhqCjlg,4663 -networkx/algorithms/tests/test_non_randomness.py,sha256=xMkJp0F91Qn45EUuMottk1WSDfOQ90TDQfZFDSJ8tkE,1000 -networkx/algorithms/tests/test_planar_drawing.py,sha256=NN55y2cs9IdZYwUsG-RbI07aGSMx5gp5vnmGLC2vopo,8765 -networkx/algorithms/tests/test_planarity.py,sha256=rrIGX28JoG_DqINsuY4TSdDloxnz4dkCd3xeRo9Svqs,16386 -networkx/algorithms/tests/test_polynomials.py,sha256=baI0Kua1pRngRC6Scm5gRRwi1bl0iET5_Xxo3AZTP3A,1983 -networkx/algorithms/tests/test_reciprocity.py,sha256=X_PXWFOTzuEcyMWpRdwEJfm8lJOfNE_1rb9AAybf4is,1296 -networkx/algorithms/tests/test_regular.py,sha256=5KGvwhixanEigI0KgeUJ1hWPw7YRGZgNbrMkKcndd5M,2626 -networkx/algorithms/tests/test_richclub.py,sha256=ql_j69gIoph8d6oD2tzDqu3b-uW884nmEJZQmWANR6k,3965 -networkx/algorithms/tests/test_similarity.py,sha256=BV5f4DiSQHPsXkSosf29idxGQ_wLiTwEsiHtgDOLLw4,33189 -networkx/algorithms/tests/test_simple_paths.py,sha256=7U9wCXz4SHK0XeYrs1k2KjYgrYVQDnts2ggQLzU18p0,25181 -networkx/algorithms/tests/test_smallworld.py,sha256=rfgNCRU6YF55f8sCuA5WmX6MmhDci89Tb4jaz4ALjcQ,2405 -networkx/algorithms/tests/test_smetric.py,sha256=VM14L4X1AABvINDL9qKXzlech_Q2g4Aee-ozWM2Qrr4,144 -networkx/algorithms/tests/test_sparsifiers.py,sha256=1GRbQy1vfmwv6eUhP4Io0aykH2VyTJfFWmncrXmTqi4,4044 -networkx/algorithms/tests/test_structuralholes.py,sha256=NsQfW85GquVUndyHBVo5OMku_C8i8bfE-4WXJr5dILw,5290 -networkx/algorithms/tests/test_summarization.py,sha256=uNyaUstobIEu6M_Hexik-3YiYTRSy_XO6LUqoE4wazw,21312 -networkx/algorithms/tests/test_swap.py,sha256=WJtGMkSbAd1Cv06VaUeDVHosNOtdigsqEspyux0ExCs,6144 -networkx/algorithms/tests/test_threshold.py,sha256=RF_SM5tdMGJfEHETO19mFicnt69UIlvVeuCwI7rxb0M,9751 -networkx/algorithms/tests/test_time_dependent.py,sha256=NmuV2kDo4nh2MeN0hwcJf0QSDtqMD0dfSeeKSsYBtQ8,13342 -networkx/algorithms/tests/test_tournament.py,sha256=XF6TwqPwJ7bKKuD7vM1Q7a9NnKerk38lWghvqTekQfk,4159 -networkx/algorithms/tests/test_triads.py,sha256=anSuYt1ZmV0_aGtSPLl5YxEQZHOuo0QndNADUdZKqdY,9383 -networkx/algorithms/tests/test_vitality.py,sha256=p5lPWCtVMtbvxDw6TJUaf8vpb0zKPoz5pND722xiypQ,1380 -networkx/algorithms/tests/test_voronoi.py,sha256=M4B6JtkJUw56ULEWRs1kyVEUsroNrnb5FBq9OioAyHM,3477 -networkx/algorithms/tests/test_walks.py,sha256=X8cb-YvGHiiqbMEXuKMSdTAb9WtVtbHjIESNSqpJTmU,1499 -networkx/algorithms/tests/test_wiener.py,sha256=k9ld7wdPq5knS6cjo0hja8aWL-cdxYKGRpDU0z3cvNI,3209 -networkx/algorithms/traversal/__init__.py,sha256=YtFrfNjciqTOI6jGePQaJ01tRSEQXTHqTGGNhDEDb_8,142 -networkx/algorithms/traversal/beamsearch.py,sha256=Vn0U4Wck8ICShIAGggv3tVtQWVW0ABEz_hcBsGrql6o,3473 -networkx/algorithms/traversal/breadth_first_search.py,sha256=iFE-rskYn-oOOEI8ocCbCD3QMH5PX41RP8Xb2Krb2H8,18288 -networkx/algorithms/traversal/depth_first_search.py,sha256=2V4T3tGujcAtV3W6WcTQUjGAAe3b1rqinONowUhLsa8,16795 -networkx/algorithms/traversal/edgebfs.py,sha256=s8lugT0l6J8HRmB8dCs3D1UxZa95SGHGyP2WCfaABOc,6244 -networkx/algorithms/traversal/edgedfs.py,sha256=_s9N4UKaEi8sRtJ604qPHl_NIM92rOLkgec9ZPwZYp0,5957 -networkx/algorithms/traversal/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/traversal/tests/test_beamsearch.py,sha256=bzUcswZ1qo0ecDZYSER_4enbsW6SjTpb_3Nb3fqmkAo,900 -networkx/algorithms/traversal/tests/test_bfs.py,sha256=mOMBIo1SEplTa0zQI3XN__UovQgd573t8q2_rxu7e90,6465 -networkx/algorithms/traversal/tests/test_dfs.py,sha256=EqLV_C-3frQ89C-SD0jtHvWEankNfPXm6M76JDdenq0,10604 -networkx/algorithms/traversal/tests/test_edgebfs.py,sha256=8oplCu0fct3QipT0JB0-292EA2aOm8zWlMkPedfe6iY,4702 -networkx/algorithms/traversal/tests/test_edgedfs.py,sha256=HGmC3GUYSn9XLMHQpdefdE6g-Uh3KqbmgEEXBcckdYc,4775 -networkx/algorithms/tree/__init__.py,sha256=wm_FjX3G7hqJfyNmeEaJsRjZI-8Kkv0Nb5jAmQNXzSc,149 -networkx/algorithms/tree/branchings.py,sha256=B0c_uKpcnV2SwJMZJRK0BMEz8LkvIcOhv1y0AI0gTnY,34339 -networkx/algorithms/tree/coding.py,sha256=uFqGL6g1QWjGC4F9MCrsz_8rjWeuMJr5HUumGNsqXV4,13464 -networkx/algorithms/tree/decomposition.py,sha256=lY_rqx9JxnLEkp1wiAv0mX62PGPwGQ6SW4Jp48o8aiw,3071 -networkx/algorithms/tree/mst.py,sha256=nvaqotj00pnqAMY6_mOr8YLAAd2u-ApefXzzWU_4JVo,46140 -networkx/algorithms/tree/operations.py,sha256=1N6AH0vfY2QyyYBH_OOE0b7dS7dx9-pT3cOTQVmE1A0,4042 -networkx/algorithms/tree/recognition.py,sha256=bYnaDN0ZaIWTgq0tbPEHAcdxQBWZpDvWypZarBbA334,7569 -networkx/algorithms/tree/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/algorithms/tree/tests/test_branchings.py,sha256=uSMc57nLXLBRgm_ERqUSNSrTfq9R3ZWDFkyrG3KR8Vs,17727 -networkx/algorithms/tree/tests/test_coding.py,sha256=XC6SbfA2zVGH4FyJJyv6o8eOnBu7FNzNot3SKs7QmEo,3955 -networkx/algorithms/tree/tests/test_decomposition.py,sha256=vnl_xoQzi1LnlZL25vXOZWwvaWmon3-x222OKt4eDqE,1871 -networkx/algorithms/tree/tests/test_mst.py,sha256=ad6kAEpAF9PH1FyD_jHa2xnAtgBGs75sYGTY0s530BQ,31631 -networkx/algorithms/tree/tests/test_operations.py,sha256=ybU96kROTVJRTyjLG7JSJjYlPxaWmYjUVJqbXV5VGGI,1961 -networkx/algorithms/tree/tests/test_recognition.py,sha256=qeMEIvg-j2MqaU-TNIQhCcXxao8vTBy0wjpU7jr2iw8,4521 -networkx/classes/__init__.py,sha256=Q9oONJrnTFs874SGpwcbV_kyJTDcrLI69GFt99MiE6I,364 -networkx/classes/coreviews.py,sha256=9koRKORoAkI0spB-yMCkqXvry7mMd6hmSPhBab3SzcE,13143 -networkx/classes/digraph.py,sha256=Fup1GbADCpXKLA12M67RbhA0cm6BGi_4cIxBLsjHEtc,48101 -networkx/classes/filters.py,sha256=PCy7BsoIby8VcamqDjZQiNAe_5egI0WKUq-y5nc9unQ,2817 -networkx/classes/function.py,sha256=H6ho_EtU8zRTNv4VCaLb_BY_56PplSiftktk-OkqdcU,38898 -networkx/classes/graph.py,sha256=bc5yHCeDu0XyfBOR0nRx9rEMOpry9FdezxqiCIYPH1E,71102 -networkx/classes/graphviews.py,sha256=ulUTLozEK_hj_4TGHdgvxveR2-rb92Q14jjxH4oH4Go,8520 -networkx/classes/multidigraph.py,sha256=aOqjfSJ6Lx9l-1zwCIMNYRW0mW1wPDniEcRWQ8gKmYY,36351 -networkx/classes/multigraph.py,sha256=PSZR7QgyszlO5PqzhxI954LySqLHq-589OQrCOtC9pw,47248 -networkx/classes/reportviews.py,sha256=u0hNZqaWXCfLMP_lq835XCIVStkZQJ9HaQPeDPPoo88,46132 -networkx/classes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/classes/tests/dispatch_interface.py,sha256=OA4t1XQX7Qqm3pGhTZYKno4c_zbIcvpSWstO_LXIVRo,6479 -networkx/classes/tests/historical_tests.py,sha256=nrv0ccvUMtp714VEV1I9UTwWz8ohgujbC-Xnxpc7kU8,16174 -networkx/classes/tests/test_coreviews.py,sha256=qzdozzWK8vLag-CAUqrXAM2CZZwMFN5vMu6Tdrwdf-E,12128 -networkx/classes/tests/test_digraph.py,sha256=uw0FuEu3y_YI-PSGuQCRytFpXLF7Eye2fqLJaKbXkBc,12283 -networkx/classes/tests/test_digraph_historical.py,sha256=Q8DGba1o0xRZfdsQxreq9naREFSgVhbaZOvTT7W8mdc,3684 -networkx/classes/tests/test_filters.py,sha256=fBLig8z548gsBBlQw6VJdGZb4IcqJj7_0mi2Fd2ncEM,5851 -networkx/classes/tests/test_function.py,sha256=a7fsmmdOSX-OYTEP0RV27vh4e_jyZh9w6SX1iABMVq0,34997 -networkx/classes/tests/test_graph.py,sha256=77t7pk1Pmz-txewyD2Dv19Vva6vWpWCtJSPtFx-EY_Y,30913 -networkx/classes/tests/test_graph_historical.py,sha256=Jl3aCS1BtwoCRdajMKDZcMQRypkOis0J_XU2LHEmYUE,274 -networkx/classes/tests/test_graphviews.py,sha256=i4x3ii8--PPg_pK4YA8aMR1axUQCdXZYpzmB05iEAOg,11466 -networkx/classes/tests/test_multidigraph.py,sha256=ryTKegCoYixXbAqOn3mIt9vSMb5666Dv-pfMkXEjoUE,16342 -networkx/classes/tests/test_multigraph.py,sha256=0vFQO3RCJaBpzXvnQzdWa_qYLHNo_I9DICYhPZJNUMk,18777 -networkx/classes/tests/test_reportviews.py,sha256=dNL6fMMsumYKU4Q_kx-vsXB3GU9xTQxrQn45qoa8e8I,41919 -networkx/classes/tests/test_special.py,sha256=IJsmqCS9LrTDoZ11KPmo-UOI7xEskL7NyduEJNPMNqs,4103 -networkx/classes/tests/test_subgraphviews.py,sha256=1dcJHq3F00LyoFSu6CTFPqS7DFIkWK1PyQu4QvJh5ko,13223 -networkx/drawing/__init__.py,sha256=rnTFNzLc4fis1hTAEpnWTC80neAR88-llVQ-LObN-i4,160 -networkx/drawing/layout.py,sha256=eA5YJ2xA-AYDL1WFICETTqfnl7amjRYfkgOJEJbigvw,50243 -networkx/drawing/nx_agraph.py,sha256=bbtLuusDb4vNu6EPF9rgBdJsP-DaIFyzPgxBn5KEA1I,13937 -networkx/drawing/nx_latex.py,sha256=zSGYPpn3wewWaEBCJerq6gRb5RmKP9SY0sLWhyqD8Xo,24805 -networkx/drawing/nx_pydot.py,sha256=b_USURmDffy1KWh2ue1vMf99-zCJiETldIDS7HGHitc,9591 -networkx/drawing/nx_pylab.py,sha256=WTqktY5niRF56x4bsotbGrastccRtgUcsxjqYt8Oe_s,66369 -networkx/drawing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/drawing/tests/test_agraph.py,sha256=BzrfyQYEtaUbxOzhROLE6njzpG6ZxW7QkRdpVholLAY,8789 -networkx/drawing/tests/test_latex.py,sha256=_Wng73kMltC-_sUoxdo2uBL2bkEc7HMqkKhwo9ZDJGA,8710 -networkx/drawing/tests/test_layout.py,sha256=IWl7cCFb_eGowjACF5tki9voThOzHNpPgjkonzH-pzQ,20611 -networkx/drawing/tests/test_pydot.py,sha256=X9b66gWqMgdTEyRJ7Zmy5kL9cr22waI688K9BJUf4Bk,4973 -networkx/drawing/tests/test_pylab.py,sha256=KgWiNwgkdSn-A36-DP68ZFibbb6JWV4SOJA7O433Y5U,35921 -networkx/drawing/tests/baseline/test_house_with_colors.png,sha256=FQi9pIRFwjq4gvgB8cDdBHL5euQUJFw6sQlABf2kRVo,21918 -networkx/generators/__init__.py,sha256=EoYB5c5ZE4rsNKZvl1TRQy2Vo2D3T2H-YunyD2i6sa0,1366 -networkx/generators/atlas.dat.gz,sha256=c_xBbfAWSSNgd1HLdZ9K6B3rX2VQvyW-Wcht47dH5B0,8887 -networkx/generators/atlas.py,sha256=07Xegzj5j_SiApgzgve2rSTXp0nmWwCw7-1keUjbvRo,5606 -networkx/generators/classic.py,sha256=68lCnSeo50uV1yoc6ZvjnckR7lAbrhUdniyEogczvB4,32000 -networkx/generators/cographs.py,sha256=-WR4_yrNk_X5nj7egb7A22eKPVymOdIYM-IftSRH4WA,1891 -networkx/generators/community.py,sha256=_p_4OfItbg8nS0b3EvojCXZ8cESdC-0Gj67V5w2veuM,34911 -networkx/generators/degree_seq.py,sha256=97XUApgQZrpSxyXODgVLP9drX5rEF-Xb40bYqaBGSj0,30173 -networkx/generators/directed.py,sha256=Vcg0zeWFS2-F99bFmhXj4mzlCy_yoBuuqjnSx5I-Dco,15696 -networkx/generators/duplication.py,sha256=hmYAHJBez7WlfdVGGa288JFUBHoIUdVqEGCodApKOr4,5831 -networkx/generators/ego.py,sha256=TZ-o05FpvVPAdXFBLjjfa2FnAcZwlgqr_1jMdLTzFSg,1900 -networkx/generators/expanders.py,sha256=nJMys4kHNHZzC5jkyCFftw1W_6cF_r82eGTqn7cNrDo,14455 -networkx/generators/geometric.py,sha256=cCrx1HdlLc08klO6bBzb-g0GUfF2AaktCrJOmhDSWUo,39610 -networkx/generators/harary_graph.py,sha256=N6vzXKrW-ZU-xDc2ZTF_Gf7kb0LRQVRfK2oLBQvyVO8,6159 -networkx/generators/internet_as_graphs.py,sha256=Y_pQaGhe183X6dXH4ocqIK3DzXRz0oXE-AKwsL1yCHk,14172 -networkx/generators/intersection.py,sha256=EFm0AOjnqyp8KcT7kGWqANq-_vq9kQ0d_0DzVyQyP-o,4101 -networkx/generators/interval_graph.py,sha256=ZTmdgQbBx3M6sysGWXbGyngYYOC1TAXD3Ozkw4deQFw,2204 -networkx/generators/joint_degree_seq.py,sha256=nyp86NC_4XvzvwpwwzKrrCSz1i_4bESSDtVjWvpkWFg,24773 -networkx/generators/lattice.py,sha256=kVCvTahWPQGNbok6maXfaqGzm88UuxhP7D9BkKhGW1o,13500 -networkx/generators/line.py,sha256=4mFH60EsHvb4wW34E45Byl_rXjDPICD59caoAtOE8VI,17531 -networkx/generators/mycielski.py,sha256=xBX2m77sCzumoH5cAGitksvEEW-ocbCnbdaN7fKUtVk,3314 -networkx/generators/nonisomorphic_trees.py,sha256=gE7uPB-uaE6rEfaimmR9bqobso5yclcCG6u8zwZlS48,6453 -networkx/generators/random_clustered.py,sha256=i_NdvvchHvsvbwgQtoWSY_pLwvhO9Lh02MSZXzgGb7c,4183 -networkx/generators/random_graphs.py,sha256=qi_AjT9Hx5M6ujgTe-DBVIsY9LwqPPZjuAHFMIaQOOc,51346 -networkx/generators/small.py,sha256=Xs9JNTtoLiShg7fF7_VRJ-G18JGSt4JEMmhhtpS51r8,28171 -networkx/generators/social.py,sha256=IUVgWVMUmRaUG28U0KzB--0DtKLdCFDz54tkJ69W4ms,23437 -networkx/generators/spectral_graph_forge.py,sha256=kF4SCE3dcgwBA9bMys5O-mCf529dFhraw3Zmy9GRnQ4,4240 -networkx/generators/stochastic.py,sha256=Qg9vWm9EOug2OQVIHL_dZ5HrXc16lxnWyzX52KWNEPI,1981 -networkx/generators/sudoku.py,sha256=kLM2AP0H4966uYiNO1oAFEmv5qBftU_bOfYucRxexM0,4288 -networkx/generators/time_series.py,sha256=_DMiY9X95O_9sK2BSeeTb2yMWfStBwKFWwn6FUOXN4Q,2439 -networkx/generators/trees.py,sha256=2a8MsKTzQfFLBESG5oocbTaMv0cYX0vtedFD29eiOFA,36533 -networkx/generators/triads.py,sha256=7kScTf3ITDi3qsSa-IvGMpa9diEaFwQnRuIf3Tv4UBI,2452 -networkx/generators/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/generators/tests/test_atlas.py,sha256=nwXJL4O5jUqhTwqhkPxHY8s3KXHQTDEdsfbg4MsSzVQ,2530 -networkx/generators/tests/test_classic.py,sha256=PlEZOxT8XADzyDL-GIItEx66hW4bvVl4UCo4ojX4m80,24021 -networkx/generators/tests/test_cographs.py,sha256=Khqvx15VNWHjNkMeEpsio3oJAi8KoiYqfTqKVbQWT9U,458 -networkx/generators/tests/test_community.py,sha256=FGcDo3Ajb-yYc5kUkFbVfOJVMG-YppbAtjgBPcVzjLc,11311 -networkx/generators/tests/test_degree_seq.py,sha256=in6lg1pwcAg1N08MA3lQdr3lnm2-aoUy3BRm6Yj_OBQ,7093 -networkx/generators/tests/test_directed.py,sha256=A01l9R-VBauEN7UEtLkkp9SubjjrnC_QWR2w0Q5GHq0,5259 -networkx/generators/tests/test_duplication.py,sha256=UdIGDF_fishanWid1xO_aH4NDfie8xpIqd26qndhOqI,3155 -networkx/generators/tests/test_ego.py,sha256=8v1Qjmkli9wIhhUuqzgqCzysr0C1Z2C3oJMCUoNvgY4,1327 -networkx/generators/tests/test_expanders.py,sha256=0X78pbB1PnW4pxa7UvlA5lzq6u0ZCfnvMBMYJvLHYH0,5602 -networkx/generators/tests/test_geometric.py,sha256=gnVm4dam_Er88YwaNpNZC6mjJjfgwMYhyLOtU9oPn1o,18087 -networkx/generators/tests/test_harary_graph.py,sha256=GiX5LXXJaNxzjvd-Nyw_QuARzbFGkA6zE1R1eX8mclw,4936 -networkx/generators/tests/test_internet_as_graphs.py,sha256=QmzkOnWg9bcSrv31UcaD6Cko55AV-GPLLY5Aqb_Dmvs,6795 -networkx/generators/tests/test_intersection.py,sha256=hcIit5fKfOn3VjMhz9KqovZK9tzxZfmC6ezvA7gZAvM,819 -networkx/generators/tests/test_interval_graph.py,sha256=JYMi-QMkJQdBU9uOdfm0Xr6MEYqIbhU5oSDa6D3tSb0,4277 -networkx/generators/tests/test_joint_degree_seq.py,sha256=8TXTZI3Um2gBXtP-4yhGKf9vCi78-NVmWZw9r9WG3F8,4270 -networkx/generators/tests/test_lattice.py,sha256=q4Ri-dH9mKhfq0PNX9xMeYRUiP0JlPBr7piSruZlFlg,9290 -networkx/generators/tests/test_line.py,sha256=vXncJuny2j5ulCJyT01Rt1tTwPib4XelS3dJDdJXjx0,10378 -networkx/generators/tests/test_mycielski.py,sha256=fwZLO1ybcltRy6TzCel8tPBil1oZWv9QSXs779H6Xt0,946 -networkx/generators/tests/test_nonisomorphic_trees.py,sha256=g5zkb0T7mkb2AdT-GkIGPXvahh9lv-f-XddJ80Y0Zfg,2454 -networkx/generators/tests/test_random_clustered.py,sha256=SalHqWvpnXA3QrDRMjLx15dk2c4Us8Ck52clUERoUI8,1297 -networkx/generators/tests/test_random_graphs.py,sha256=RTrKahiDHdXIb2ScFzQk3vrxncnMOE3W5LyJfIPvuKc,18925 -networkx/generators/tests/test_small.py,sha256=K4-sSBZca3UMP1deUOWlkSzpanJBAT-vQdr11PMI_QY,7060 -networkx/generators/tests/test_spectral_graph_forge.py,sha256=x4jyTiQiydaUPWYaGsNFsIB47PAzSSwQYCNXGa2B4SU,1594 -networkx/generators/tests/test_stochastic.py,sha256=f-5KD3RpoQf369gXHH7KGebE19g5lCkXR_alcwmFm_s,2179 -networkx/generators/tests/test_sudoku.py,sha256=dgOmk-B7MxCVkbHdZzsLZppQ61FAArVy4McSVL8Afzo,1968 -networkx/generators/tests/test_time_series.py,sha256=rgmFcitlKa_kF6TzJ2ze91lSmNJlqjhvgrYet0AUZx8,2230 -networkx/generators/tests/test_trees.py,sha256=Pvh0MvTKaRuZuwWL-wpJIC0zlBAcnTirpSLJi-9c7qc,7006 -networkx/generators/tests/test_triads.py,sha256=K8anVEP8R90Y172IrKIOrYRWRJBGeqxNqU9isX7Ybxs,333 -networkx/linalg/__init__.py,sha256=7iyNZ_YYBnlsW8zSfhUgvEkywOrUWfpIuyS86ZOKlG8,568 -networkx/linalg/algebraicconnectivity.py,sha256=3nOW8g21_8B_J_cCj6UYMVqGUHEI_T3827LcyoSxJvI,21149 -networkx/linalg/attrmatrix.py,sha256=Mwiw5dvIvjDY7Bwlb4sy85KzfoP02EF64CfG_GvJsro,15509 -networkx/linalg/bethehessianmatrix.py,sha256=Ii4NX6mo90W3MppCRcYn9dRW_MsEkVdA9TH6x7JhX8o,2697 -networkx/linalg/graphmatrix.py,sha256=NIs2uWGS_8lJJ5IQ8Og9aIWHawghtlCDWifqOIKV2-c,5623 -networkx/linalg/laplacianmatrix.py,sha256=iRHHabmb9S4ChDPx3Yn2-WIEQFd_flFD3AZkA4k-oyY,20536 -networkx/linalg/modularitymatrix.py,sha256=R_VITtgIkGenxlsCLN4u6CYxj3_HiPXfeU29yarntRo,4706 -networkx/linalg/spectrum.py,sha256=aRY7ApYv5HxrO_4O8brxpZRw3SJU3fYzlgMwhEIXcrc,4215 -networkx/linalg/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/linalg/tests/test_algebraic_connectivity.py,sha256=Kj2ct6gQ71xXFP7usAbFLJxD7ZdtTzneHiFJQOoVCUQ,13737 -networkx/linalg/tests/test_attrmatrix.py,sha256=XD3YuPc5yXKWbhwVSI8YiV_wABWM-rLtwf1uwwWlnI0,2833 -networkx/linalg/tests/test_bethehessian.py,sha256=0r-Do902ywV10TyqTlIJ2Ls3iMqM6sSs2PZbod7kWBM,1327 -networkx/linalg/tests/test_graphmatrix.py,sha256=e5YSH9ih1VL64nnYgZFDvLyKbP3BFqpp0jY6t-8b2eY,8708 -networkx/linalg/tests/test_laplacian.py,sha256=0AGJwezqohoQtrmTZ94Gvg5vISMCB7_G2QdJl7JFTXg,14081 -networkx/linalg/tests/test_modularity.py,sha256=mfKUvwc3bj6Rud1aG4oK3Eu1qg12o6cB8-pv5ZFicYY,3115 -networkx/linalg/tests/test_spectrum.py,sha256=agP2DsiEIvtkNUkT94mdPtJjwnobnjMTUOwjIQa4giA,2828 -networkx/readwrite/__init__.py,sha256=TvSbnGEHQ5F9CY2tkpjWYOyrUj6BeW3sc6P4_IczbKA,561 -networkx/readwrite/adjlist.py,sha256=FjVdLlrWLi7mVuKHzO16AO6CVFqA6TCJu3GxLxSOXbU,8435 -networkx/readwrite/edgelist.py,sha256=pjnG_o3_usmgthIpscQRJWHZZ8b3-39Uqgj0OF9qE_g,14237 -networkx/readwrite/gexf.py,sha256=wq50Twz2o9XuoeR6awNYcftZDP-MRSztnsukmKiE3cQ,39693 -networkx/readwrite/gml.py,sha256=5TWaEGaQv33f8F5i5IciQp8YbK0MKNxb1E5GQcKC02M,31150 -networkx/readwrite/graph6.py,sha256=q1CmarzZ_jW_A15fU3YyKFl5OhtN-qWUrVcfc0ZTv6w,11401 -networkx/readwrite/graphml.py,sha256=12KKKXLDyMIif-KB4ZWdvMpgnuRqQ2EEqwY9TX3jkj8,39318 -networkx/readwrite/leda.py,sha256=VjpyUYeAWPD4TQSyvcC-ftcTeg6Pow9zJJqNuiGZ0zU,2797 -networkx/readwrite/multiline_adjlist.py,sha256=_3SB2719ceBdJjYPkyAZUPuCebcHX_Zwk6mQDs4OcTQ,11301 -networkx/readwrite/p2g.py,sha256=0Mi8yvV0Hy6Bo4cbCKYjNp0_0ALYmNNCUMer4w1bkrY,3092 -networkx/readwrite/pajek.py,sha256=9j3sRjLzPQxqQFdEoTCOwICpdAf7G39cdls04dhErns,8738 -networkx/readwrite/sparse6.py,sha256=MFih4PCNJSY4UFuJxBNxYjBT9_11UpIbPQrySSiE9bg,10315 -networkx/readwrite/text.py,sha256=9u43d_m2xcoJKl5rKQ-3N0kIdr3m4xzX2i1y05xDDbM,29163 -networkx/readwrite/json_graph/__init__.py,sha256=37XJPMmilcwwo8KqouLWUly7Yv5tZ7IKraMHbBRx3fI,677 -networkx/readwrite/json_graph/adjacency.py,sha256=WM6fdncV87WDLPOfF-IbOlOOBMX0utUjJ09UsxtwRAo,4716 -networkx/readwrite/json_graph/cytoscape.py,sha256=kX6_p24F4CnDdT0D5lYrD0-jypyMdmqnGQEXKR1_kH4,5338 -networkx/readwrite/json_graph/node_link.py,sha256=QUre2tj2j6PXdwz6J3ExxyoLsfX-Vs5lDwjcYQjSDcM,10792 -networkx/readwrite/json_graph/tree.py,sha256=K4rF4Kds4g0JhgcPTrrR_I3Pswpze8yCVH4M-WF9nn0,3851 -networkx/readwrite/json_graph/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/readwrite/json_graph/tests/test_adjacency.py,sha256=jueQE3Z_W5BZuCjr0hEsOWSfoQ2fP51p0o0m7IcXUuE,2456 -networkx/readwrite/json_graph/tests/test_cytoscape.py,sha256=vFoDzcSRI9THlmp4Fu2HHhIF9AUmECWs5mftVWjaWWs,2044 -networkx/readwrite/json_graph/tests/test_node_link.py,sha256=q0mqy5fqZFxxHQb18tmFXUOOp_oTP1Ye5bEWzTnXEFo,6468 -networkx/readwrite/json_graph/tests/test_tree.py,sha256=zBXv3_db2XGxFs3XQ35btNf_ku52aLXXiHZmmX4ixAs,1352 -networkx/readwrite/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/readwrite/tests/test_adjlist.py,sha256=t5RL85eDQFPUIdh8W4kozY_P7PMJU2LwSXjWZGE-4Aw,10134 -networkx/readwrite/tests/test_edgelist.py,sha256=cmOqVSpVO-FTdFRUAz40_e2sSmmB9xV6uYmfvw5cNhQ,10113 -networkx/readwrite/tests/test_gexf.py,sha256=Tbqueeh0XRQ8vtmGwXcyy9K3tWPlnLu6Gop0Hy4cZcc,19405 -networkx/readwrite/tests/test_gml.py,sha256=8_2nBU6n8zLHkApiuKkZNH-xMRSdA1G8ZH3Lvjspizg,21391 -networkx/readwrite/tests/test_graph6.py,sha256=DAi58D_G3j2UGk6VpfGkLGzfSAl318TIbuXSKKZ102U,6067 -networkx/readwrite/tests/test_graphml.py,sha256=MrU3AkdqNQ6gVLtOQrZUx39pV7PjS_ETu5uuT5Ce6BI,67573 -networkx/readwrite/tests/test_leda.py,sha256=_5F4nLLQ1oAZQMZtTQoFncZL0Oc-IsztFBglEdQeH3k,1392 -networkx/readwrite/tests/test_p2g.py,sha256=drsdod5amV9TGCk-qE2RwsvAop78IKEI1WguVFfd9rs,1320 -networkx/readwrite/tests/test_pajek.py,sha256=-bT-y26OmWgpLcvk-qvVfOEa-DTcQPwV2qKB99roOrk,4629 -networkx/readwrite/tests/test_sparse6.py,sha256=cqFHWz4G_kMawaRqceofN4K-JlkmPx3BEaDXkU8DD0o,5284 -networkx/readwrite/tests/test_text.py,sha256=x1N97hD31HPkj9Wn2PYti5-gcwaFNnStkaN_38HKnIg,55319 -networkx/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/tests/test_all_random_functions.py,sha256=VWBH5Uov3DswxuRDzlMPuDlcryPyWVaCvt2_OMw-dIQ,8673 -networkx/tests/test_convert.py,sha256=SoIVrqJFF9Gu9Jff_apfbpqg8QhkfC6QW4qzoSM-ukM,12731 -networkx/tests/test_convert_numpy.py,sha256=jw-iEj7wVAVXd5rlOxTBMHQD63m90q5RBQxv1ee9dNw,19065 -networkx/tests/test_convert_pandas.py,sha256=2LrQrGkxdlvEZxKmMvyptUvOsTsAcbo8u6siSVbnV3M,13346 -networkx/tests/test_convert_scipy.py,sha256=C2cY_8dgBksO0uttkhyCnjACXtC6KHjxqHUk47P5wH8,10436 -networkx/tests/test_exceptions.py,sha256=XYkpPzqMepSw3MPRUJN5LcFsUsy3YT_fiRDhm0OeAeQ,927 -networkx/tests/test_import.py,sha256=Gm4ujfH9JkQtDrSjOlwXXXUuubI057wskKLCkF6Z92k,220 -networkx/tests/test_lazy_imports.py,sha256=nKykNQPt_ZV8JxCH_EkwwcPNayAgZGQVf89e8I7uIlI,2680 -networkx/tests/test_relabel.py,sha256=dffbjiW_VUAQe7iD8knFS_KepUITt0F6xuwf7daWwKw,14517 -networkx/utils/__init__.py,sha256=7pxleRNpBWuL3FEQz3CzKLn17b6_eSwkM7dqnL1okDk,302 -networkx/utils/backends.py,sha256=pXioKWl33QJEcL9_FDufk2xv12_8bpgYniJYouJEq4M,113169 -networkx/utils/configs.py,sha256=v3p9eXPPllCcMqX33VhVQUVeXOm7eAn9xdASDEqMmP8,15023 -networkx/utils/decorators.py,sha256=aj07nVz7CW1TaYMBpSiHdRuw_U3_o0XdGoRyLMrJeXg,44836 -networkx/utils/heaps.py,sha256=HUZuETHfELEqiXdMBPmD9fA2KiACVhp6iEahcrjFxYM,10391 -networkx/utils/mapped_queue.py,sha256=WdIRk27D_ArmPs9tdpvQLQCV4Tmus212BQhxsFIMYgk,10184 -networkx/utils/misc.py,sha256=BN_VscZjoishxgbjwxm1PVG_J_jHqpuMd9bffwK6Q5M,21293 -networkx/utils/random_sequence.py,sha256=KzKh0BRMri0MBZlzxHNMl3qRTy2DnBexW3eDzmxKab4,4237 -networkx/utils/rcm.py,sha256=9tpXSK-wwLXFcq3ypXilYNAaJAKrmMiMwp4R78OLvuI,4624 -networkx/utils/union_find.py,sha256=NxKlBlyS71A1Wlnt28L-wyZoI9ExZvJth_0e2XSVris,3338 -networkx/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -networkx/utils/tests/test__init.py,sha256=QE0i-lNE4pG2eYjB2mZ0uw7jPD-7TdL7Y9p73JoWQmo,363 -networkx/utils/tests/test_backends.py,sha256=5fwka8bdEBtvPhjN49dMcgKsUBIVHEmMag6uckBAAd8,6108 -networkx/utils/tests/test_config.py,sha256=nImFv-UMS3uo9DFgYejSCNRm2mOUVHldKFFAY4t_2mQ,7414 -networkx/utils/tests/test_decorators.py,sha256=dm3b5yiQPlnlT_4pSm0FwK-xBGV9dcnhv14Vh9Jiz1o,14050 -networkx/utils/tests/test_heaps.py,sha256=qCuWMzpcMH1Gwu014CAams78o151QD5YL0mB1fz16Yw,3711 -networkx/utils/tests/test_mapped_queue.py,sha256=l1Nguzz68Fv91FnAT7y7B0GXSoje9uoWiObHo7TliGM,7354 -networkx/utils/tests/test_misc.py,sha256=zkD1pYO4xBuBxlGe-nU8okcX6hfDMgu0OJZGu4TMrN0,8671 -networkx/utils/tests/test_random_sequence.py,sha256=Ou-IeCFybibZuycoin5gUQzzC-iy5yanZFmrqvdGt6Q,925 -networkx/utils/tests/test_rcm.py,sha256=UvUAkgmQMGk_Nn94TJyQsle4A5SLQFqMQWld1tiQ2lk,1421 -networkx/utils/tests/test_unionfind.py,sha256=j-DF5XyeJzq1hoeAgN5Nye2Au7EPD040t8oS4Aw2IwU,1579 -networkx-3.4.2.dist-info/LICENSE.txt,sha256=W0M7kPdV65u9Bv7_HRpPXyMsUgihhWlBmeRfqV12J5I,1763 -networkx-3.4.2.dist-info/METADATA,sha256=LlJl3ah27zxE_vqelVNJm8VkyJoWyV44va-bq8VW0dc,6349 -networkx-3.4.2.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91 -networkx-3.4.2.dist-info/entry_points.txt,sha256=H2jZaDsDJ_i9H2SwWpwuFel8BrZ9xHKuvh-DQAWW9lQ,94 -networkx-3.4.2.dist-info/top_level.txt,sha256=s3Mk-7KOlu-kD39w8Xg_KXoP5Z_MVvgB-upkyuOE4Hk,9 -networkx-3.4.2.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/WHEEL deleted file mode 100644 index da25d7b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.2.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/entry_points.txt deleted file mode 100644 index 377282a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[networkx.backends] -nx_loopback = networkx.classes.tests.dispatch_interface:backend_interface diff --git a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/top_level.txt deleted file mode 100644 index 4d07dfe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx-3.4.2.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -networkx diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/__init__.py deleted file mode 100644 index 5710827..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -NetworkX -======== - -NetworkX is a Python package for the creation, manipulation, and study of the -structure, dynamics, and functions of complex networks. - -See https://networkx.org for complete documentation. -""" - -__version__ = "3.4.2" - - -# These are imported in order as listed -from networkx.lazy_imports import _lazy_import - -from networkx.exception import * - -from networkx import utils -from networkx.utils import _clear_cache, _dispatchable - -# load_and_call entry_points, set configs -config = utils.backends._set_configs_from_environment() -utils.config = utils.configs.config = config # type: ignore[attr-defined] - -from networkx import classes -from networkx.classes import filters -from networkx.classes import * - -from networkx import convert -from networkx.convert import * - -from networkx import convert_matrix -from networkx.convert_matrix import * - -from networkx import relabel -from networkx.relabel import * - -from networkx import generators -from networkx.generators import * - -from networkx import readwrite -from networkx.readwrite import * - -# Need to test with SciPy, when available -from networkx import algorithms -from networkx.algorithms import * - -from networkx import linalg -from networkx.linalg import * - -from networkx import drawing -from networkx.drawing import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/__init__.py deleted file mode 100644 index 56bfb14..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/__init__.py +++ /dev/null @@ -1,133 +0,0 @@ -from networkx.algorithms.assortativity import * -from networkx.algorithms.asteroidal import * -from networkx.algorithms.boundary import * -from networkx.algorithms.broadcasting import * -from networkx.algorithms.bridges import * -from networkx.algorithms.chains import * -from networkx.algorithms.centrality import * -from networkx.algorithms.chordal import * -from networkx.algorithms.cluster import * -from networkx.algorithms.clique import * -from networkx.algorithms.communicability_alg import * -from networkx.algorithms.components import * -from networkx.algorithms.coloring import * -from networkx.algorithms.core import * -from networkx.algorithms.covering import * -from networkx.algorithms.cycles import * -from networkx.algorithms.cuts import * -from networkx.algorithms.d_separation import * -from networkx.algorithms.dag import * -from networkx.algorithms.distance_measures import * -from networkx.algorithms.distance_regular import * -from networkx.algorithms.dominance import * -from networkx.algorithms.dominating import * -from networkx.algorithms.efficiency_measures import * -from networkx.algorithms.euler import * -from networkx.algorithms.graphical import * -from networkx.algorithms.hierarchy import * -from networkx.algorithms.hybrid import * -from networkx.algorithms.link_analysis import * -from networkx.algorithms.link_prediction import * -from networkx.algorithms.lowest_common_ancestors import * -from networkx.algorithms.isolate import * -from networkx.algorithms.matching import * -from networkx.algorithms.minors import * -from networkx.algorithms.mis import * -from networkx.algorithms.moral import * -from networkx.algorithms.non_randomness import * -from networkx.algorithms.operators import * -from networkx.algorithms.planarity import * -from networkx.algorithms.planar_drawing import * -from networkx.algorithms.polynomials import * -from networkx.algorithms.reciprocity import * -from networkx.algorithms.regular import * -from networkx.algorithms.richclub import * -from networkx.algorithms.shortest_paths import * -from networkx.algorithms.similarity import * -from networkx.algorithms.graph_hashing import * -from networkx.algorithms.simple_paths import * -from networkx.algorithms.smallworld import * -from networkx.algorithms.smetric import * -from networkx.algorithms.structuralholes import * -from networkx.algorithms.sparsifiers import * -from networkx.algorithms.summarization import * -from networkx.algorithms.swap import * -from networkx.algorithms.time_dependent import * -from networkx.algorithms.traversal import * -from networkx.algorithms.triads import * -from networkx.algorithms.vitality import * -from networkx.algorithms.voronoi import * -from networkx.algorithms.walks import * -from networkx.algorithms.wiener import * - -# Make certain subpackages available to the user as direct imports from -# the `networkx` namespace. -from networkx.algorithms import approximation -from networkx.algorithms import assortativity -from networkx.algorithms import bipartite -from networkx.algorithms import node_classification -from networkx.algorithms import centrality -from networkx.algorithms import chordal -from networkx.algorithms import cluster -from networkx.algorithms import clique -from networkx.algorithms import components -from networkx.algorithms import connectivity -from networkx.algorithms import community -from networkx.algorithms import coloring -from networkx.algorithms import flow -from networkx.algorithms import isomorphism -from networkx.algorithms import link_analysis -from networkx.algorithms import lowest_common_ancestors -from networkx.algorithms import operators -from networkx.algorithms import shortest_paths -from networkx.algorithms import tournament -from networkx.algorithms import traversal -from networkx.algorithms import tree - -# Make certain functions from some of the previous subpackages available -# to the user as direct imports from the `networkx` namespace. -from networkx.algorithms.bipartite import complete_bipartite_graph -from networkx.algorithms.bipartite import is_bipartite -from networkx.algorithms.bipartite import projected_graph -from networkx.algorithms.connectivity import all_pairs_node_connectivity -from networkx.algorithms.connectivity import all_node_cuts -from networkx.algorithms.connectivity import average_node_connectivity -from networkx.algorithms.connectivity import edge_connectivity -from networkx.algorithms.connectivity import edge_disjoint_paths -from networkx.algorithms.connectivity import k_components -from networkx.algorithms.connectivity import k_edge_components -from networkx.algorithms.connectivity import k_edge_subgraphs -from networkx.algorithms.connectivity import k_edge_augmentation -from networkx.algorithms.connectivity import is_k_edge_connected -from networkx.algorithms.connectivity import minimum_edge_cut -from networkx.algorithms.connectivity import minimum_node_cut -from networkx.algorithms.connectivity import node_connectivity -from networkx.algorithms.connectivity import node_disjoint_paths -from networkx.algorithms.connectivity import stoer_wagner -from networkx.algorithms.flow import capacity_scaling -from networkx.algorithms.flow import cost_of_flow -from networkx.algorithms.flow import gomory_hu_tree -from networkx.algorithms.flow import max_flow_min_cost -from networkx.algorithms.flow import maximum_flow -from networkx.algorithms.flow import maximum_flow_value -from networkx.algorithms.flow import min_cost_flow -from networkx.algorithms.flow import min_cost_flow_cost -from networkx.algorithms.flow import minimum_cut -from networkx.algorithms.flow import minimum_cut_value -from networkx.algorithms.flow import network_simplex -from networkx.algorithms.isomorphism import could_be_isomorphic -from networkx.algorithms.isomorphism import fast_could_be_isomorphic -from networkx.algorithms.isomorphism import faster_could_be_isomorphic -from networkx.algorithms.isomorphism import is_isomorphic -from networkx.algorithms.isomorphism.vf2pp import * -from networkx.algorithms.tree.branchings import maximum_branching -from networkx.algorithms.tree.branchings import maximum_spanning_arborescence -from networkx.algorithms.tree.branchings import minimum_branching -from networkx.algorithms.tree.branchings import minimum_spanning_arborescence -from networkx.algorithms.tree.branchings import ArborescenceIterator -from networkx.algorithms.tree.coding import * -from networkx.algorithms.tree.decomposition import * -from networkx.algorithms.tree.mst import * -from networkx.algorithms.tree.operations import * -from networkx.algorithms.tree.recognition import * -from networkx.algorithms.tournament import is_tournament diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/__init__.py deleted file mode 100644 index d12a8f8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Approximations of graph properties and Heuristic methods for optimization. - -The functions in this class are not imported into the top-level ``networkx`` -namespace so the easiest way to use them is with:: - - >>> from networkx.algorithms import approximation - -Another option is to import the specific function with -``from networkx.algorithms.approximation import function_name``. - -""" - -from networkx.algorithms.approximation.clustering_coefficient import * -from networkx.algorithms.approximation.clique import * -from networkx.algorithms.approximation.connectivity import * -from networkx.algorithms.approximation.distance_measures import * -from networkx.algorithms.approximation.dominating_set import * -from networkx.algorithms.approximation.kcomponents import * -from networkx.algorithms.approximation.matching import * -from networkx.algorithms.approximation.ramsey import * -from networkx.algorithms.approximation.steinertree import * -from networkx.algorithms.approximation.traveling_salesman import * -from networkx.algorithms.approximation.treewidth import * -from networkx.algorithms.approximation.vertex_cover import * -from networkx.algorithms.approximation.maxcut import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clique.py deleted file mode 100644 index ed0f350..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clique.py +++ /dev/null @@ -1,259 +0,0 @@ -"""Functions for computing large cliques and maximum independent sets.""" - -import networkx as nx -from networkx.algorithms.approximation import ramsey -from networkx.utils import not_implemented_for - -__all__ = [ - "clique_removal", - "max_clique", - "large_clique_size", - "maximum_independent_set", -] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def maximum_independent_set(G): - """Returns an approximate maximum independent set. - - Independent set or stable set is a set of vertices in a graph, no two of - which are adjacent. That is, it is a set I of vertices such that for every - two vertices in I, there is no edge connecting the two. Equivalently, each - edge in the graph has at most one endpoint in I. The size of an independent - set is the number of vertices it contains [1]_. - - A maximum independent set is a largest independent set for a given graph G - and its size is denoted $\\alpha(G)$. The problem of finding such a set is called - the maximum independent set problem and is an NP-hard optimization problem. - As such, it is unlikely that there exists an efficient algorithm for finding - a maximum independent set of a graph. - - The Independent Set algorithm is based on [2]_. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - iset : Set - The apx-maximum independent set - - Examples - -------- - >>> G = nx.path_graph(10) - >>> nx.approximation.maximum_independent_set(G) - {0, 2, 4, 6, 9} - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - Notes - ----- - Finds the $O(|V|/(log|V|)^2)$ apx of independent set in the worst case. - - References - ---------- - .. [1] `Wikipedia: Independent set - `_ - .. [2] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - """ - iset, _ = clique_removal(G) - return iset - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def max_clique(G): - r"""Find the Maximum Clique - - Finds the $O(|V|/(log|V|)^2)$ apx of maximum clique/independent set - in the worst case. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - clique : set - The apx-maximum clique of the graph - - Examples - -------- - >>> G = nx.path_graph(10) - >>> nx.approximation.max_clique(G) - {8, 9} - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - Notes - ----- - A clique in an undirected graph G = (V, E) is a subset of the vertex set - `C \subseteq V` such that for every two vertices in C there exists an edge - connecting the two. This is equivalent to saying that the subgraph - induced by C is complete (in some cases, the term clique may also refer - to the subgraph). - - A maximum clique is a clique of the largest possible size in a given graph. - The clique number `\omega(G)` of a graph G is the number of - vertices in a maximum clique in G. The intersection number of - G is the smallest number of cliques that together cover all edges of G. - - https://en.wikipedia.org/wiki/Maximum_clique - - References - ---------- - .. [1] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - doi:10.1007/BF01994876 - """ - # finding the maximum clique in a graph is equivalent to finding - # the independent set in the complementary graph - cgraph = nx.complement(G) - iset, _ = clique_removal(cgraph) - return iset - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def clique_removal(G): - r"""Repeatedly remove cliques from the graph. - - Results in a $O(|V|/(\log |V|)^2)$ approximation of maximum clique - and independent set. Returns the largest independent set found, along - with found maximal cliques. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - max_ind_cliques : (set, list) tuple - 2-tuple of Maximal Independent Set and list of maximal cliques (sets). - - Examples - -------- - >>> G = nx.path_graph(10) - >>> nx.approximation.clique_removal(G) - ({0, 2, 4, 6, 9}, [{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}]) - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - References - ---------- - .. [1] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - """ - graph = G.copy() - c_i, i_i = ramsey.ramsey_R2(graph) - cliques = [c_i] - isets = [i_i] - while graph: - graph.remove_nodes_from(c_i) - c_i, i_i = ramsey.ramsey_R2(graph) - if c_i: - cliques.append(c_i) - if i_i: - isets.append(i_i) - # Determine the largest independent set as measured by cardinality. - maxiset = max(isets, key=len) - return maxiset, cliques - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def large_clique_size(G): - """Find the size of a large clique in a graph. - - A *clique* is a subset of nodes in which each pair of nodes is - adjacent. This function is a heuristic for finding the size of a - large clique in the graph. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - k: integer - The size of a large clique in the graph. - - Examples - -------- - >>> G = nx.path_graph(10) - >>> nx.approximation.large_clique_size(G) - 2 - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - Notes - ----- - This implementation is from [1]_. Its worst case time complexity is - :math:`O(n d^2)`, where *n* is the number of nodes in the graph and - *d* is the maximum degree. - - This function is a heuristic, which means it may work well in - practice, but there is no rigorous mathematical guarantee on the - ratio between the returned number and the actual largest clique size - in the graph. - - References - ---------- - .. [1] Pattabiraman, Bharath, et al. - "Fast Algorithms for the Maximum Clique Problem on Massive Graphs - with Applications to Overlapping Community Detection." - *Internet Mathematics* 11.4-5 (2015): 421--448. - - - See also - -------- - - :func:`networkx.algorithms.approximation.clique.max_clique` - A function that returns an approximate maximum clique with a - guarantee on the approximation ratio. - - :mod:`networkx.algorithms.clique` - Functions for finding the exact maximum clique in a graph. - - """ - degrees = G.degree - - def _clique_heuristic(G, U, size, best_size): - if not U: - return max(best_size, size) - u = max(U, key=degrees) - U.remove(u) - N_prime = {v for v in G[u] if degrees[v] >= best_size} - return _clique_heuristic(G, U & N_prime, size + 1, best_size) - - best_size = 0 - nodes = (u for u in G if degrees[u] >= best_size) - for u in nodes: - neighbors = {v for v in G[u] if degrees[v] >= best_size} - best_size = _clique_heuristic(G, neighbors, 1, best_size) - return best_size diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clustering_coefficient.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clustering_coefficient.py deleted file mode 100644 index 545fc65..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/clustering_coefficient.py +++ /dev/null @@ -1,71 +0,0 @@ -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ["average_clustering"] - - -@not_implemented_for("directed") -@py_random_state(2) -@nx._dispatchable(name="approximate_average_clustering") -def average_clustering(G, trials=1000, seed=None): - r"""Estimates the average clustering coefficient of G. - - The local clustering of each node in `G` is the fraction of triangles - that actually exist over all possible triangles in its neighborhood. - The average clustering coefficient of a graph `G` is the mean of - local clusterings. - - This function finds an approximate average clustering coefficient - for G by repeating `n` times (defined in `trials`) the following - experiment: choose a node at random, choose two of its neighbors - at random, and check if they are connected. The approximate - coefficient is the fraction of triangles found over the number - of trials [1]_. - - Parameters - ---------- - G : NetworkX graph - - trials : integer - Number of trials to perform (default 1000). - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - c : float - Approximated average clustering coefficient. - - Examples - -------- - >>> from networkx.algorithms import approximation - >>> G = nx.erdos_renyi_graph(10, 0.2, seed=10) - >>> approximation.average_clustering(G, trials=1000, seed=10) - 0.214 - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - References - ---------- - .. [1] Schank, Thomas, and Dorothea Wagner. Approximating clustering - coefficient and transitivity. Universität Karlsruhe, Fakultät für - Informatik, 2004. - https://doi.org/10.5445/IR/1000001239 - - """ - n = len(G) - triangles = 0 - nodes = list(G) - for i in [int(seed.random() * n) for i in range(trials)]: - nbrs = list(G[nodes[i]]) - if len(nbrs) < 2: - continue - u, v = seed.sample(nbrs, 2) - if u in G[v]: - triangles += 1 - return triangles / trials diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/connectivity.py deleted file mode 100644 index 0b596fd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/connectivity.py +++ /dev/null @@ -1,412 +0,0 @@ -"""Fast approximation for node connectivity""" - -import itertools -from operator import itemgetter - -import networkx as nx - -__all__ = [ - "local_node_connectivity", - "node_connectivity", - "all_pairs_node_connectivity", -] - - -@nx._dispatchable(name="approximate_local_node_connectivity") -def local_node_connectivity(G, source, target, cutoff=None): - """Compute node connectivity between source and target. - - Pairwise or local node connectivity between two distinct and nonadjacent - nodes is the minimum number of nodes that must be removed (minimum - separating cutset) to disconnect them. By Menger's theorem, this is equal - to the number of node independent paths (paths that share no nodes other - than source and target). Which is what we compute in this function. - - This algorithm is a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - Parameters - ---------- - - G : NetworkX graph - - source : node - Starting node for node connectivity - - target : node - Ending node for node connectivity - - cutoff : integer - Maximum node connectivity to consider. If None, the minimum degree - of source or target is used as a cutoff. Default value None. - - Returns - ------- - k: integer - pairwise node connectivity - - Examples - -------- - >>> # Platonic octahedral graph has node connectivity 4 - >>> # for each non adjacent node pair - >>> from networkx.algorithms import approximation as approx - >>> G = nx.octahedral_graph() - >>> approx.local_node_connectivity(G, 0, 5) - 4 - - Notes - ----- - This algorithm [1]_ finds node independents paths between two nodes by - computing their shortest path using BFS, marking the nodes of the path - found as 'used' and then searching other shortest paths excluding the - nodes marked as used until no more paths exist. It is not exact because - a shortest path could use nodes that, if the path were longer, may belong - to two different node independent paths. Thus it only guarantees an - strict lower bound on node connectivity. - - Note that the authors propose a further refinement, losing accuracy and - gaining speed, which is not implemented yet. - - See also - -------- - all_pairs_node_connectivity - node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - if target == source: - raise nx.NetworkXError("source and target have to be different nodes.") - - # Maximum possible node independent paths - if G.is_directed(): - possible = min(G.out_degree(source), G.in_degree(target)) - else: - possible = min(G.degree(source), G.degree(target)) - - K = 0 - if not possible: - return K - - if cutoff is None: - cutoff = float("inf") - - exclude = set() - for i in range(min(possible, cutoff)): - try: - path = _bidirectional_shortest_path(G, source, target, exclude) - exclude.update(set(path)) - K += 1 - except nx.NetworkXNoPath: - break - - return K - - -@nx._dispatchable(name="approximate_node_connectivity") -def node_connectivity(G, s=None, t=None): - r"""Returns an approximation for node connectivity for a graph or digraph G. - - Node connectivity is equal to the minimum number of nodes that - must be removed to disconnect G or render it trivial. By Menger's theorem, - this is equal to the number of node independent paths (paths that - share no nodes other than source and target). - - If source and target nodes are provided, this function returns the - local node connectivity: the minimum number of nodes that must be - removed to break all paths from source to target in G. - - This algorithm is based on a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - Returns - ------- - K : integer - Node connectivity of G, or local node connectivity if source - and target are provided. - - Examples - -------- - >>> # Platonic octahedral graph is 4-node-connected - >>> from networkx.algorithms import approximation as approx - >>> G = nx.octahedral_graph() - >>> approx.node_connectivity(G) - 4 - - Notes - ----- - This algorithm [1]_ finds node independents paths between two nodes by - computing their shortest path using BFS, marking the nodes of the path - found as 'used' and then searching other shortest paths excluding the - nodes marked as used until no more paths exist. It is not exact because - a shortest path could use nodes that, if the path were longer, may belong - to two different node independent paths. Thus it only guarantees an - strict lower bound on node connectivity. - - See also - -------- - all_pairs_node_connectivity - local_node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError("Both source and target must be specified.") - - # Local node connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - return local_node_connectivity(G, s, t) - - # Global node connectivity - if G.is_directed(): - connected_func = nx.is_weakly_connected - iter_func = itertools.permutations - - def neighbors(v): - return itertools.chain(G.predecessors(v), G.successors(v)) - - else: - connected_func = nx.is_connected - iter_func = itertools.combinations - neighbors = G.neighbors - - if not connected_func(G): - return 0 - - # Choose a node with minimum degree - v, minimum_degree = min(G.degree(), key=itemgetter(1)) - # Node connectivity is bounded by minimum degree - K = minimum_degree - # compute local node connectivity with all non-neighbors nodes - # and store the minimum - for w in set(G) - set(neighbors(v)) - {v}: - K = min(K, local_node_connectivity(G, v, w, cutoff=K)) - # Same for non adjacent pairs of neighbors of v - for x, y in iter_func(neighbors(v), 2): - if y not in G[x] and x != y: - K = min(K, local_node_connectivity(G, x, y, cutoff=K)) - return K - - -@nx._dispatchable(name="approximate_all_pairs_node_connectivity") -def all_pairs_node_connectivity(G, nbunch=None, cutoff=None): - """Compute node connectivity between all pairs of nodes. - - Pairwise or local node connectivity between two distinct and nonadjacent - nodes is the minimum number of nodes that must be removed (minimum - separating cutset) to disconnect them. By Menger's theorem, this is equal - to the number of node independent paths (paths that share no nodes other - than source and target). Which is what we compute in this function. - - This algorithm is a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - - Parameters - ---------- - G : NetworkX graph - - nbunch: container - Container of nodes. If provided node connectivity will be computed - only over pairs of nodes in nbunch. - - cutoff : integer - Maximum node connectivity to consider. If None, the minimum degree - of source or target is used as a cutoff in each pair of nodes. - Default value None. - - Returns - ------- - K : dictionary - Dictionary, keyed by source and target, of pairwise node connectivity - - Examples - -------- - A 3 node cycle with one extra node attached has connectivity 2 between all - nodes in the cycle and connectivity 1 between the extra node and the rest: - - >>> G = nx.cycle_graph(3) - >>> G.add_edge(2, 3) - >>> import pprint # for nice dictionary formatting - >>> pprint.pprint(nx.all_pairs_node_connectivity(G)) - {0: {1: 2, 2: 2, 3: 1}, - 1: {0: 2, 2: 2, 3: 1}, - 2: {0: 2, 1: 2, 3: 1}, - 3: {0: 1, 1: 1, 2: 1}} - - See Also - -------- - local_node_connectivity - node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - """ - if nbunch is None: - nbunch = G - else: - nbunch = set(nbunch) - - directed = G.is_directed() - if directed: - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - all_pairs = {n: {} for n in nbunch} - - for u, v in iter_func(nbunch, 2): - k = local_node_connectivity(G, u, v, cutoff=cutoff) - all_pairs[u][v] = k - if not directed: - all_pairs[v][u] = k - - return all_pairs - - -def _bidirectional_shortest_path(G, source, target, exclude): - """Returns shortest path between source and target ignoring nodes in the - container 'exclude'. - - Parameters - ---------- - - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - exclude: container - Container for nodes to exclude from the search for shortest paths - - Returns - ------- - path: list - Shortest path between source and target ignoring nodes in 'exclude' - - Raises - ------ - NetworkXNoPath - If there is no path or if nodes are adjacent and have only one path - between them - - Notes - ----- - This function and its helper are originally from - networkx.algorithms.shortest_paths.unweighted and are modified to - accept the extra parameter 'exclude', which is a container for nodes - already used in other paths that should be ignored. - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target, exclude) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from source to w - while w is not None: - path.append(w) - w = pred[w] - path.reverse() - # from w to target - w = succ[path[-1]] - while w is not None: - path.append(w) - w = succ[w] - - return path - - -def _bidirectional_pred_succ(G, source, target, exclude): - # does BFS from both source and target and meets in the middle - # excludes nodes in the container "exclude" from the search - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # predecessor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - level = 0 - - while forward_fringe and reverse_fringe: - # Make sure that we iterate one step forward and one step backwards - # thus source and target will only trigger "found path" when they are - # adjacent and then they can be safely included in the container 'exclude' - level += 1 - if level % 2 != 0: - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc(v): - if w in exclude: - continue - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: - return pred, succ, w # found path - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred(v): - if w in exclude: - continue - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: - return pred, succ, w # found path - - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/distance_measures.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/distance_measures.py deleted file mode 100644 index d5847e6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/distance_measures.py +++ /dev/null @@ -1,150 +0,0 @@ -"""Distance measures approximated metrics.""" - -import networkx as nx -from networkx.utils.decorators import py_random_state - -__all__ = ["diameter"] - - -@py_random_state(1) -@nx._dispatchable(name="approximate_diameter") -def diameter(G, seed=None): - """Returns a lower bound on the diameter of the graph G. - - The function computes a lower bound on the diameter (i.e., the maximum eccentricity) - of a directed or undirected graph G. The procedure used varies depending on the graph - being directed or not. - - If G is an `undirected` graph, then the function uses the `2-sweep` algorithm [1]_. - The main idea is to pick the farthest node from a random node and return its eccentricity. - - Otherwise, if G is a `directed` graph, the function uses the `2-dSweep` algorithm [2]_, - The procedure starts by selecting a random source node $s$ from which it performs a - forward and a backward BFS. Let $a_1$ and $a_2$ be the farthest nodes in the forward and - backward cases, respectively. Then, it computes the backward eccentricity of $a_1$ using - a backward BFS and the forward eccentricity of $a_2$ using a forward BFS. - Finally, it returns the best lower bound between the two. - - In both cases, the time complexity is linear with respect to the size of G. - - Parameters - ---------- - G : NetworkX graph - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - d : integer - Lower Bound on the Diameter of G - - Examples - -------- - >>> G = nx.path_graph(10) # undirected graph - >>> nx.diameter(G) - 9 - >>> G = nx.cycle_graph(3, create_using=nx.DiGraph) # directed graph - >>> nx.diameter(G) - 2 - - Raises - ------ - NetworkXError - If the graph is empty or - If the graph is undirected and not connected or - If the graph is directed and not strongly connected. - - See Also - -------- - networkx.algorithms.distance_measures.diameter - - References - ---------- - .. [1] Magnien, Clémence, Matthieu Latapy, and Michel Habib. - *Fast computation of empirically tight bounds for the diameter of massive graphs.* - Journal of Experimental Algorithmics (JEA), 2009. - https://arxiv.org/pdf/0904.2728.pdf - .. [2] Crescenzi, Pierluigi, Roberto Grossi, Leonardo Lanzi, and Andrea Marino. - *On computing the diameter of real-world directed (weighted) graphs.* - International Symposium on Experimental Algorithms. Springer, Berlin, Heidelberg, 2012. - https://courses.cs.ut.ee/MTAT.03.238/2014_fall/uploads/Main/diameter.pdf - """ - # if G is empty - if not G: - raise nx.NetworkXError("Expected non-empty NetworkX graph!") - # if there's only a node - if G.number_of_nodes() == 1: - return 0 - # if G is directed - if G.is_directed(): - return _two_sweep_directed(G, seed) - # else if G is undirected - return _two_sweep_undirected(G, seed) - - -def _two_sweep_undirected(G, seed): - """Helper function for finding a lower bound on the diameter - for undirected Graphs. - - The idea is to pick the farthest node from a random node - and return its eccentricity. - - ``G`` is a NetworkX undirected graph. - - .. note:: - - ``seed`` is a random.Random or numpy.random.RandomState instance - """ - # select a random source node - source = seed.choice(list(G)) - # get the distances to the other nodes - distances = nx.shortest_path_length(G, source) - # if some nodes have not been visited, then the graph is not connected - if len(distances) != len(G): - raise nx.NetworkXError("Graph not connected.") - # take a node that is (one of) the farthest nodes from the source - *_, node = distances - # return the eccentricity of the node - return nx.eccentricity(G, node) - - -def _two_sweep_directed(G, seed): - """Helper function for finding a lower bound on the diameter - for directed Graphs. - - It implements 2-dSweep, the directed version of the 2-sweep algorithm. - The algorithm follows the following steps. - 1. Select a source node $s$ at random. - 2. Perform a forward BFS from $s$ to select a node $a_1$ at the maximum - distance from the source, and compute $LB_1$, the backward eccentricity of $a_1$. - 3. Perform a backward BFS from $s$ to select a node $a_2$ at the maximum - distance from the source, and compute $LB_2$, the forward eccentricity of $a_2$. - 4. Return the maximum between $LB_1$ and $LB_2$. - - ``G`` is a NetworkX directed graph. - - .. note:: - - ``seed`` is a random.Random or numpy.random.RandomState instance - """ - # get a new digraph G' with the edges reversed in the opposite direction - G_reversed = G.reverse() - # select a random source node - source = seed.choice(list(G)) - # compute forward distances from source - forward_distances = nx.shortest_path_length(G, source) - # compute backward distances from source - backward_distances = nx.shortest_path_length(G_reversed, source) - # if either the source can't reach every node or not every node - # can reach the source, then the graph is not strongly connected - n = len(G) - if len(forward_distances) != n or len(backward_distances) != n: - raise nx.NetworkXError("DiGraph not strongly connected.") - # take a node a_1 at the maximum distance from the source in G - *_, a_1 = forward_distances - # take a node a_2 at the maximum distance from the source in G_reversed - *_, a_2 = backward_distances - # return the max between the backward eccentricity of a_1 and the forward eccentricity of a_2 - return max(nx.eccentricity(G_reversed, a_1), nx.eccentricity(G, a_2)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/dominating_set.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/dominating_set.py deleted file mode 100644 index e568a82..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/dominating_set.py +++ /dev/null @@ -1,149 +0,0 @@ -"""Functions for finding node and edge dominating sets. - -A `dominating set`_ for an undirected graph *G* with vertex set *V* -and edge set *E* is a subset *D* of *V* such that every vertex not in -*D* is adjacent to at least one member of *D*. An `edge dominating set`_ -is a subset *F* of *E* such that every edge not in *F* is -incident to an endpoint of at least one edge in *F*. - -.. _dominating set: https://en.wikipedia.org/wiki/Dominating_set -.. _edge dominating set: https://en.wikipedia.org/wiki/Edge_dominating_set - -""" - -import networkx as nx - -from ...utils import not_implemented_for -from ..matching import maximal_matching - -__all__ = ["min_weighted_dominating_set", "min_edge_dominating_set"] - - -# TODO Why doesn't this algorithm work for directed graphs? -@not_implemented_for("directed") -@nx._dispatchable(node_attrs="weight") -def min_weighted_dominating_set(G, weight=None): - r"""Returns a dominating set that approximates the minimum weight node - dominating set. - - Parameters - ---------- - G : NetworkX graph - Undirected graph. - - weight : string - The node attribute storing the weight of an node. If provided, - the node attribute with this key must be a number for each - node. If not provided, each node is assumed to have weight one. - - Returns - ------- - min_weight_dominating_set : set - A set of nodes, the sum of whose weights is no more than `(\log - w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of - each node in the graph and `w(V^*)` denotes the sum of the - weights of each node in the minimum weight dominating set. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 4), (1, 4), (1, 2), (2, 3), (3, 4), (2, 5)]) - >>> nx.approximation.min_weighted_dominating_set(G) - {1, 2, 4} - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Notes - ----- - This algorithm computes an approximate minimum weighted dominating - set for the graph `G`. The returned solution has weight `(\log - w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of each - node in the graph and `w(V^*)` denotes the sum of the weights of - each node in the minimum weight dominating set for the graph. - - This implementation of the algorithm runs in $O(m)$ time, where $m$ - is the number of edges in the graph. - - References - ---------- - .. [1] Vazirani, Vijay V. - *Approximation Algorithms*. - Springer Science & Business Media, 2001. - - """ - # The unique dominating set for the null graph is the empty set. - if len(G) == 0: - return set() - - # This is the dominating set that will eventually be returned. - dom_set = set() - - def _cost(node_and_neighborhood): - """Returns the cost-effectiveness of greedily choosing the given - node. - - `node_and_neighborhood` is a two-tuple comprising a node and its - closed neighborhood. - - """ - v, neighborhood = node_and_neighborhood - return G.nodes[v].get(weight, 1) / len(neighborhood - dom_set) - - # This is a set of all vertices not already covered by the - # dominating set. - vertices = set(G) - # This is a dictionary mapping each node to the closed neighborhood - # of that node. - neighborhoods = {v: {v} | set(G[v]) for v in G} - - # Continue until all vertices are adjacent to some node in the - # dominating set. - while vertices: - # Find the most cost-effective node to add, along with its - # closed neighborhood. - dom_node, min_set = min(neighborhoods.items(), key=_cost) - # Add the node to the dominating set and reduce the remaining - # set of nodes to cover. - dom_set.add(dom_node) - del neighborhoods[dom_node] - vertices -= min_set - - return dom_set - - -@nx._dispatchable -def min_edge_dominating_set(G): - r"""Returns minimum cardinality edge dominating set. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - min_edge_dominating_set : set - Returns a set of dominating edges whose size is no more than 2 * OPT. - - Examples - -------- - >>> G = nx.petersen_graph() - >>> nx.approximation.min_edge_dominating_set(G) - {(0, 1), (4, 9), (6, 8), (5, 7), (2, 3)} - - Raises - ------ - ValueError - If the input graph `G` is empty. - - Notes - ----- - The algorithm computes an approximate solution to the edge dominating set - problem. The result is no more than 2 * OPT in terms of size of the set. - Runtime of the algorithm is $O(|E|)$. - """ - if not G: - raise ValueError("Expected non-empty NetworkX graph!") - return maximal_matching(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/kcomponents.py deleted file mode 100644 index f726a4e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/kcomponents.py +++ /dev/null @@ -1,369 +0,0 @@ -"""Fast approximation for k-component structure""" - -import itertools -from collections import defaultdict -from collections.abc import Mapping -from functools import cached_property - -import networkx as nx -from networkx.algorithms.approximation import local_node_connectivity -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for - -__all__ = ["k_components"] - - -@not_implemented_for("directed") -@nx._dispatchable(name="approximate_k_components") -def k_components(G, min_density=0.95): - r"""Returns the approximate k-component structure of a graph G. - - A `k`-component is a maximal subgraph of a graph G that has, at least, - node connectivity `k`: we need to remove at least `k` nodes to break it - into more components. `k`-components have an inherent hierarchical - structure because they are nested in terms of connectivity: a connected - graph can contain several 2-components, each of which can contain - one or more 3-components, and so forth. - - This implementation is based on the fast heuristics to approximate - the `k`-component structure of a graph [1]_. Which, in turn, it is based on - a fast approximation algorithm for finding good lower bounds of the number - of node independent paths between two nodes [2]_. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - min_density : Float - Density relaxation threshold. Default value 0.95 - - Returns - ------- - k_components : dict - Dictionary with connectivity level `k` as key and a list of - sets of nodes that form a k-component of level `k` as values. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Examples - -------- - >>> # Petersen graph has 10 nodes and it is triconnected, thus all - >>> # nodes are in a single component on all three connectivity levels - >>> from networkx.algorithms import approximation as apxa - >>> G = nx.petersen_graph() - >>> k_components = apxa.k_components(G) - - Notes - ----- - The logic of the approximation algorithm for computing the `k`-component - structure [1]_ is based on repeatedly applying simple and fast algorithms - for `k`-cores and biconnected components in order to narrow down the - number of pairs of nodes over which we have to compute White and Newman's - approximation algorithm for finding node independent paths [2]_. More - formally, this algorithm is based on Whitney's theorem, which states - an inclusion relation among node connectivity, edge connectivity, and - minimum degree for any graph G. This theorem implies that every - `k`-component is nested inside a `k`-edge-component, which in turn, - is contained in a `k`-core. Thus, this algorithm computes node independent - paths among pairs of nodes in each biconnected part of each `k`-core, - and repeats this procedure for each `k` from 3 to the maximal core number - of a node in the input graph. - - Because, in practice, many nodes of the core of level `k` inside a - bicomponent actually are part of a component of level k, the auxiliary - graph needed for the algorithm is likely to be very dense. Thus, we use - a complement graph data structure (see `AntiGraph`) to save memory. - AntiGraph only stores information of the edges that are *not* present - in the actual auxiliary graph. When applying algorithms to this - complement graph data structure, it behaves as if it were the dense - version. - - See also - -------- - k_components - - References - ---------- - .. [1] Torrents, J. and F. Ferraro (2015) Structural Cohesion: - Visualization and Heuristics for Fast Computation. - https://arxiv.org/pdf/1503.04476v1 - - .. [2] White, Douglas R., and Mark Newman (2001) A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - https://www.santafe.edu/research/results/working-papers/fast-approximation-algorithms-for-finding-node-ind - - .. [3] Moody, J. and D. White (2003). Social cohesion and embeddedness: - A hierarchical conception of social groups. - American Sociological Review 68(1), 103--28. - https://doi.org/10.2307/3088904 - - """ - # Dictionary with connectivity level (k) as keys and a list of - # sets of nodes that form a k-component as values - k_components = defaultdict(list) - # make a few functions local for speed - node_connectivity = local_node_connectivity - k_core = nx.k_core - core_number = nx.core_number - biconnected_components = nx.biconnected_components - combinations = itertools.combinations - # Exact solution for k = {1,2} - # There is a linear time algorithm for triconnectivity, if we had an - # implementation available we could start from k = 4. - for component in nx.connected_components(G): - # isolated nodes have connectivity 0 - comp = set(component) - if len(comp) > 1: - k_components[1].append(comp) - for bicomponent in nx.biconnected_components(G): - # avoid considering dyads as bicomponents - bicomp = set(bicomponent) - if len(bicomp) > 2: - k_components[2].append(bicomp) - # There is no k-component of k > maximum core number - # \kappa(G) <= \lambda(G) <= \delta(G) - g_cnumber = core_number(G) - max_core = max(g_cnumber.values()) - for k in range(3, max_core + 1): - C = k_core(G, k, core_number=g_cnumber) - for nodes in biconnected_components(C): - # Build a subgraph SG induced by the nodes that are part of - # each biconnected component of the k-core subgraph C. - if len(nodes) < k: - continue - SG = G.subgraph(nodes) - # Build auxiliary graph - H = _AntiGraph() - H.add_nodes_from(SG.nodes()) - for u, v in combinations(SG, 2): - K = node_connectivity(SG, u, v, cutoff=k) - if k > K: - H.add_edge(u, v) - for h_nodes in biconnected_components(H): - if len(h_nodes) <= k: - continue - SH = H.subgraph(h_nodes) - for Gc in _cliques_heuristic(SG, SH, k, min_density): - for k_nodes in biconnected_components(Gc): - Gk = nx.k_core(SG.subgraph(k_nodes), k) - if len(Gk) <= k: - continue - k_components[k].append(set(Gk)) - return k_components - - -def _cliques_heuristic(G, H, k, min_density): - h_cnumber = nx.core_number(H) - for i, c_value in enumerate(sorted(set(h_cnumber.values()), reverse=True)): - cands = {n for n, c in h_cnumber.items() if c == c_value} - # Skip checking for overlap for the highest core value - if i == 0: - overlap = False - else: - overlap = set.intersection( - *[{x for x in H[n] if x not in cands} for n in cands] - ) - if overlap and len(overlap) < k: - SH = H.subgraph(cands | overlap) - else: - SH = H.subgraph(cands) - sh_cnumber = nx.core_number(SH) - SG = nx.k_core(G.subgraph(SH), k) - while not (_same(sh_cnumber) and nx.density(SH) >= min_density): - # This subgraph must be writable => .copy() - SH = H.subgraph(SG).copy() - if len(SH) <= k: - break - sh_cnumber = nx.core_number(SH) - sh_deg = dict(SH.degree()) - min_deg = min(sh_deg.values()) - SH.remove_nodes_from(n for n, d in sh_deg.items() if d == min_deg) - SG = nx.k_core(G.subgraph(SH), k) - else: - yield SG - - -def _same(measure, tol=0): - vals = set(measure.values()) - if (max(vals) - min(vals)) <= tol: - return True - return False - - -class _AntiGraph(nx.Graph): - """ - Class for complement graphs. - - The main goal is to be able to work with big and dense graphs with - a low memory footprint. - - In this class you add the edges that *do not exist* in the dense graph, - the report methods of the class return the neighbors, the edges and - the degree as if it was the dense graph. Thus it's possible to use - an instance of this class with some of NetworkX functions. In this - case we only use k-core, connected_components, and biconnected_components. - """ - - all_edge_dict = {"weight": 1} - - def single_edge_dict(self): - return self.all_edge_dict - - edge_attr_dict_factory = single_edge_dict # type: ignore[assignment] - - def __getitem__(self, n): - """Returns a dict of neighbors of node n in the dense graph. - - Parameters - ---------- - n : node - A node in the graph. - - Returns - ------- - adj_dict : dictionary - The adjacency dictionary for nodes connected to n. - - """ - all_edge_dict = self.all_edge_dict - return { - node: all_edge_dict for node in set(self._adj) - set(self._adj[n]) - {n} - } - - def neighbors(self, n): - """Returns an iterator over all neighbors of node n in the - dense graph. - """ - try: - return iter(set(self._adj) - set(self._adj[n]) - {n}) - except KeyError as err: - raise NetworkXError(f"The node {n} is not in the graph.") from err - - class AntiAtlasView(Mapping): - """An adjacency inner dict for AntiGraph""" - - def __init__(self, graph, node): - self._graph = graph - self._atlas = graph._adj[node] - self._node = node - - def __len__(self): - return len(self._graph) - len(self._atlas) - 1 - - def __iter__(self): - return (n for n in self._graph if n not in self._atlas and n != self._node) - - def __getitem__(self, nbr): - nbrs = set(self._graph._adj) - set(self._atlas) - {self._node} - if nbr in nbrs: - return self._graph.all_edge_dict - raise KeyError(nbr) - - class AntiAdjacencyView(AntiAtlasView): - """An adjacency outer dict for AntiGraph""" - - def __init__(self, graph): - self._graph = graph - self._atlas = graph._adj - - def __len__(self): - return len(self._atlas) - - def __iter__(self): - return iter(self._graph) - - def __getitem__(self, node): - if node not in self._graph: - raise KeyError(node) - return self._graph.AntiAtlasView(self._graph, node) - - @cached_property - def adj(self): - return self.AntiAdjacencyView(self) - - def subgraph(self, nodes): - """This subgraph method returns a full AntiGraph. Not a View""" - nodes = set(nodes) - G = _AntiGraph() - G.add_nodes_from(nodes) - for n in G: - Gnbrs = G.adjlist_inner_dict_factory() - G._adj[n] = Gnbrs - for nbr, d in self._adj[n].items(): - if nbr in G._adj: - Gnbrs[nbr] = d - G._adj[nbr][n] = d - G.graph = self.graph - return G - - class AntiDegreeView(nx.reportviews.DegreeView): - def __iter__(self): - all_nodes = set(self._succ) - for n in self._nodes: - nbrs = all_nodes - set(self._succ[n]) - {n} - yield (n, len(nbrs)) - - def __getitem__(self, n): - nbrs = set(self._succ) - set(self._succ[n]) - {n} - # AntiGraph is a ThinGraph so all edges have weight 1 - return len(nbrs) + (n in nbrs) - - @cached_property - def degree(self): - """Returns an iterator for (node, degree) and degree for single node. - - The node degree is the number of edges adjacent to the node. - - Parameters - ---------- - nbunch : iterable container, optional (default=all nodes) - A container of nodes. The container will be iterated - through once. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - deg: - Degree of the node, if a single node is passed as argument. - nd_iter : an iterator - The iterator returns two-tuples of (node, degree). - - See Also - -------- - degree - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1])) - [(0, 1), (1, 2)] - - """ - return self.AntiDegreeView(self) - - def adjacency(self): - """Returns an iterator of (node, adjacency set) tuples for all nodes - in the dense graph. - - This is the fastest way to look at every edge. - For directed graphs, only outgoing adjacencies are included. - - Returns - ------- - adj_iter : iterator - An iterator of (node, adjacency set) for all nodes in - the graph. - - """ - for n in self._adj: - yield (n, set(self._adj) - set(self._adj[n]) - {n}) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/matching.py deleted file mode 100644 index dc08919..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/matching.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -************** -Graph Matching -************** - -Given a graph G = (V,E), a matching M in G is a set of pairwise non-adjacent -edges; that is, no two edges share a common vertex. - -`Wikipedia: Matching `_ -""" - -import networkx as nx - -__all__ = ["min_maximal_matching"] - - -@nx._dispatchable -def min_maximal_matching(G): - r"""Returns the minimum maximal matching of G. That is, out of all maximal - matchings of the graph G, the smallest is returned. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - min_maximal_matching : set - Returns a set of edges such that no two edges share a common endpoint - and every edge not in the set shares some common endpoint in the set. - Cardinality will be 2*OPT in the worst case. - - Notes - ----- - The algorithm computes an approximate solution for the minimum maximal - cardinality matching problem. The solution is no more than 2 * OPT in size. - Runtime is $O(|E|)$. - - References - ---------- - .. [1] Vazirani, Vijay Approximation Algorithms (2001) - """ - return nx.maximal_matching(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/maxcut.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/maxcut.py deleted file mode 100644 index f4e1da8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/maxcut.py +++ /dev/null @@ -1,143 +0,0 @@ -import networkx as nx -from networkx.utils.decorators import not_implemented_for, py_random_state - -__all__ = ["randomized_partitioning", "one_exchange"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(1) -@nx._dispatchable(edge_attrs="weight") -def randomized_partitioning(G, seed=None, p=0.5, weight=None): - """Compute a random partitioning of the graph nodes and its cut value. - - A partitioning is calculated by observing each node - and deciding to add it to the partition with probability `p`, - returning a random cut and its corresponding value (the - sum of weights of edges connecting different partitions). - - Parameters - ---------- - G : NetworkX graph - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - p : scalar - Probability for each node to be part of the first partition. - Should be in [0,1] - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - cut_size : scalar - Value of the minimum cut. - - partition : pair of node sets - A partitioning of the nodes that defines a minimum cut. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> cut_size, partition = nx.approximation.randomized_partitioning(G, seed=1) - >>> cut_size - 6 - >>> partition - ({0, 3, 4}, {1, 2}) - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - """ - cut = {node for node in G.nodes() if seed.random() < p} - cut_size = nx.algorithms.cut_size(G, cut, weight=weight) - partition = (cut, G.nodes - cut) - return cut_size, partition - - -def _swap_node_partition(cut, node): - return cut - {node} if node in cut else cut.union({node}) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(2) -@nx._dispatchable(edge_attrs="weight") -def one_exchange(G, initial_cut=None, seed=None, weight=None): - """Compute a partitioning of the graphs nodes and the corresponding cut value. - - Use a greedy one exchange strategy to find a locally maximal cut - and its value, it works by finding the best node (one that gives - the highest gain to the cut value) to add to the current cut - and repeats this process until no improvement can be made. - - Parameters - ---------- - G : networkx Graph - Graph to find a maximum cut for. - - initial_cut : set - Cut to use as a starting point. If not supplied the algorithm - starts with an empty cut. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - cut_value : scalar - Value of the maximum cut. - - partition : pair of node sets - A partitioning of the nodes that defines a maximum cut. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> curr_cut_size, partition = nx.approximation.one_exchange(G, seed=1) - >>> curr_cut_size - 6 - >>> partition - ({0, 2}, {1, 3, 4}) - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - """ - if initial_cut is None: - initial_cut = set() - cut = set(initial_cut) - current_cut_size = nx.algorithms.cut_size(G, cut, weight=weight) - while True: - nodes = list(G.nodes()) - # Shuffling the nodes ensures random tie-breaks in the following call to max - seed.shuffle(nodes) - best_node_to_swap = max( - nodes, - key=lambda v: nx.algorithms.cut_size( - G, _swap_node_partition(cut, v), weight=weight - ), - default=None, - ) - potential_cut = _swap_node_partition(cut, best_node_to_swap) - potential_cut_size = nx.algorithms.cut_size(G, potential_cut, weight=weight) - - if potential_cut_size > current_cut_size: - cut = potential_cut - current_cut_size = potential_cut_size - else: - break - - partition = (cut, G.nodes - cut) - return current_cut_size, partition diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/ramsey.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/ramsey.py deleted file mode 100644 index 0552e4a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/ramsey.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Ramsey numbers. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -from ...utils import arbitrary_element - -__all__ = ["ramsey_R2"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def ramsey_R2(G): - r"""Compute the largest clique and largest independent set in `G`. - - This can be used to estimate bounds for the 2-color - Ramsey number `R(2;s,t)` for `G`. - - This is a recursive implementation which could run into trouble - for large recursions. Note that self-loop edges are ignored. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - max_pair : (set, set) tuple - Maximum clique, Maximum independent set. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - """ - if not G: - return set(), set() - - node = arbitrary_element(G) - nbrs = (nbr for nbr in nx.all_neighbors(G, node) if nbr != node) - nnbrs = nx.non_neighbors(G, node) - c_1, i_1 = ramsey_R2(G.subgraph(nbrs).copy()) - c_2, i_2 = ramsey_R2(G.subgraph(nnbrs).copy()) - - c_1.add(node) - i_2.add(node) - # Choose the larger of the two cliques and the larger of the two - # independent sets, according to cardinality. - return max(c_1, c_2, key=len), max(i_1, i_2, key=len) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/steinertree.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/steinertree.py deleted file mode 100644 index f4840ef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/steinertree.py +++ /dev/null @@ -1,231 +0,0 @@ -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = ["metric_closure", "steiner_tree"] - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight", returns_graph=True) -def metric_closure(G, weight="weight"): - """Return the metric closure of a graph. - - The metric closure of a graph *G* is the complete graph in which each edge - is weighted by the shortest path distance between the nodes in *G* . - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - NetworkX graph - Metric closure of the graph `G`. - - """ - M = nx.Graph() - - Gnodes = set(G) - - # check for connected graph while processing first node - all_paths_iter = nx.all_pairs_dijkstra(G, weight=weight) - u, (distance, path) = next(all_paths_iter) - if Gnodes - set(distance): - msg = "G is not a connected graph. metric_closure is not defined." - raise nx.NetworkXError(msg) - Gnodes.remove(u) - for v in Gnodes: - M.add_edge(u, v, distance=distance[v], path=path[v]) - - # first node done -- now process the rest - for u, (distance, path) in all_paths_iter: - Gnodes.remove(u) - for v in Gnodes: - M.add_edge(u, v, distance=distance[v], path=path[v]) - - return M - - -def _mehlhorn_steiner_tree(G, terminal_nodes, weight): - paths = nx.multi_source_dijkstra_path(G, terminal_nodes) - - d_1 = {} - s = {} - for v in G.nodes(): - s[v] = paths[v][0] - d_1[(v, s[v])] = len(paths[v]) - 1 - - # G1-G4 names match those from the Mehlhorn 1988 paper. - G_1_prime = nx.Graph() - for u, v, data in G.edges(data=True): - su, sv = s[u], s[v] - weight_here = d_1[(u, su)] + data.get(weight, 1) + d_1[(v, sv)] - if not G_1_prime.has_edge(su, sv): - G_1_prime.add_edge(su, sv, weight=weight_here) - else: - new_weight = min(weight_here, G_1_prime[su][sv]["weight"]) - G_1_prime.add_edge(su, sv, weight=new_weight) - - G_2 = nx.minimum_spanning_edges(G_1_prime, data=True) - - G_3 = nx.Graph() - for u, v, d in G_2: - path = nx.shortest_path(G, u, v, weight) - for n1, n2 in pairwise(path): - G_3.add_edge(n1, n2) - - G_3_mst = list(nx.minimum_spanning_edges(G_3, data=False)) - if G.is_multigraph(): - G_3_mst = ( - (u, v, min(G[u][v], key=lambda k: G[u][v][k][weight])) for u, v in G_3_mst - ) - G_4 = G.edge_subgraph(G_3_mst).copy() - _remove_nonterminal_leaves(G_4, terminal_nodes) - return G_4.edges() - - -def _kou_steiner_tree(G, terminal_nodes, weight): - # H is the subgraph induced by terminal_nodes in the metric closure M of G. - M = metric_closure(G, weight=weight) - H = M.subgraph(terminal_nodes) - - # Use the 'distance' attribute of each edge provided by M. - mst_edges = nx.minimum_spanning_edges(H, weight="distance", data=True) - - # Create an iterator over each edge in each shortest path; repeats are okay - mst_all_edges = chain.from_iterable(pairwise(d["path"]) for u, v, d in mst_edges) - if G.is_multigraph(): - mst_all_edges = ( - (u, v, min(G[u][v], key=lambda k: G[u][v][k][weight])) - for u, v in mst_all_edges - ) - - # Find the MST again, over this new set of edges - G_S = G.edge_subgraph(mst_all_edges) - T_S = nx.minimum_spanning_edges(G_S, weight="weight", data=False) - - # Leaf nodes that are not terminal might still remain; remove them here - T_H = G.edge_subgraph(T_S).copy() - _remove_nonterminal_leaves(T_H, terminal_nodes) - - return T_H.edges() - - -def _remove_nonterminal_leaves(G, terminals): - terminal_set = set(terminals) - leaves = {n for n in G if len(set(G[n]) - {n}) == 1} - nonterminal_leaves = leaves - terminal_set - - while nonterminal_leaves: - # Removing a node may create new non-terminal leaves, so we limit - # search for candidate non-terminal nodes to neighbors of current - # non-terminal nodes - candidate_leaves = set.union(*(set(G[n]) for n in nonterminal_leaves)) - candidate_leaves -= nonterminal_leaves | terminal_set - # Remove current set of non-terminal nodes - G.remove_nodes_from(nonterminal_leaves) - # Find any new non-terminal nodes from the set of candidates - leaves = {n for n in candidate_leaves if len(set(G[n]) - {n}) == 1} - nonterminal_leaves = leaves - terminal_set - - -ALGORITHMS = { - "kou": _kou_steiner_tree, - "mehlhorn": _mehlhorn_steiner_tree, -} - - -@not_implemented_for("directed") -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def steiner_tree(G, terminal_nodes, weight="weight", method=None): - r"""Return an approximation to the minimum Steiner tree of a graph. - - The minimum Steiner tree of `G` w.r.t a set of `terminal_nodes` (also *S*) - is a tree within `G` that spans those nodes and has minimum size (sum of - edge weights) among all such trees. - - The approximation algorithm is specified with the `method` keyword - argument. All three available algorithms produce a tree whose weight is - within a ``(2 - (2 / l))`` factor of the weight of the optimal Steiner tree, - where ``l`` is the minimum number of leaf nodes across all possible Steiner - trees. - - * ``"kou"`` [2]_ (runtime $O(|S| |V|^2)$) computes the minimum spanning tree of - the subgraph of the metric closure of *G* induced by the terminal nodes, - where the metric closure of *G* is the complete graph in which each edge is - weighted by the shortest path distance between the nodes in *G*. - - * ``"mehlhorn"`` [3]_ (runtime $O(|E|+|V|\log|V|)$) modifies Kou et al.'s - algorithm, beginning by finding the closest terminal node for each - non-terminal. This data is used to create a complete graph containing only - the terminal nodes, in which edge is weighted with the shortest path - distance between them. The algorithm then proceeds in the same way as Kou - et al.. - - Parameters - ---------- - G : NetworkX graph - - terminal_nodes : list - A list of terminal nodes for which minimum steiner tree is - to be found. - - weight : string (default = 'weight') - Use the edge attribute specified by this string as the edge weight. - Any edge attribute not present defaults to 1. - - method : string, optional (default = 'mehlhorn') - The algorithm to use to approximate the Steiner tree. - Supported options: 'kou', 'mehlhorn'. - Other inputs produce a ValueError. - - Returns - ------- - NetworkX graph - Approximation to the minimum steiner tree of `G` induced by - `terminal_nodes` . - - Raises - ------ - NetworkXNotImplemented - If `G` is directed. - - ValueError - If the specified `method` is not supported. - - Notes - ----- - For multigraphs, the edge between two nodes with minimum weight is the - edge put into the Steiner tree. - - - References - ---------- - .. [1] Steiner_tree_problem on Wikipedia. - https://en.wikipedia.org/wiki/Steiner_tree_problem - .. [2] Kou, L., G. Markowsky, and L. Berman. 1981. - ‘A Fast Algorithm for Steiner Trees’. - Acta Informatica 15 (2): 141–45. - https://doi.org/10.1007/BF00288961. - .. [3] Mehlhorn, Kurt. 1988. - ‘A Faster Approximation Algorithm for the Steiner Problem in Graphs’. - Information Processing Letters 27 (3): 125–28. - https://doi.org/10.1016/0020-0190(88)90066-X. - """ - if method is None: - method = "mehlhorn" - - try: - algo = ALGORITHMS[method] - except KeyError as e: - raise ValueError(f"{method} is not a valid choice for an algorithm.") from e - - edges = algo(G, terminal_nodes, weight) - # For multigraph we should add the minimal weight edge keys - if G.is_multigraph(): - edges = ( - (u, v, min(G[u][v], key=lambda k: G[u][v][k][weight])) for u, v in edges - ) - T = G.edge_subgraph(edges) - return T diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py deleted file mode 100644 index 5eab5c1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +++ /dev/null @@ -1,41 +0,0 @@ -import networkx as nx -from networkx.algorithms.approximation import average_clustering - -# This approximation has to be exact in regular graphs -# with no triangles or with all possible triangles. - - -def test_petersen(): - # Actual coefficient is 0 - G = nx.petersen_graph() - assert average_clustering(G, trials=len(G) // 2) == nx.average_clustering(G) - - -def test_petersen_seed(): - # Actual coefficient is 0 - G = nx.petersen_graph() - assert average_clustering(G, trials=len(G) // 2, seed=1) == nx.average_clustering(G) - - -def test_tetrahedral(): - # Actual coefficient is 1 - G = nx.tetrahedral_graph() - assert average_clustering(G, trials=len(G) // 2) == nx.average_clustering(G) - - -def test_dodecahedral(): - # Actual coefficient is 0 - G = nx.dodecahedral_graph() - assert average_clustering(G, trials=len(G) // 2) == nx.average_clustering(G) - - -def test_empty(): - G = nx.empty_graph(5) - assert average_clustering(G, trials=len(G) // 2) == 0 - - -def test_complete(): - G = nx.complete_graph(5) - assert average_clustering(G, trials=len(G) // 2) == 1 - G = nx.complete_graph(7) - assert average_clustering(G, trials=len(G) // 2) == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_clique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_clique.py deleted file mode 100644 index b40dcb9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_clique.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.approximation.clique` module.""" - -import networkx as nx -from networkx.algorithms.approximation import ( - clique_removal, - large_clique_size, - max_clique, - maximum_independent_set, -) - - -def is_independent_set(G, nodes): - """Returns True if and only if `nodes` is a clique in `G`. - - `G` is a NetworkX graph. `nodes` is an iterable of nodes in - `G`. - - """ - return G.subgraph(nodes).number_of_edges() == 0 - - -def is_clique(G, nodes): - """Returns True if and only if `nodes` is an independent set - in `G`. - - `G` is an undirected simple graph. `nodes` is an iterable of - nodes in `G`. - - """ - H = G.subgraph(nodes) - n = len(H) - return H.number_of_edges() == n * (n - 1) // 2 - - -class TestCliqueRemoval: - """Unit tests for the - :func:`~networkx.algorithms.approximation.clique_removal` function. - - """ - - def test_trivial_graph(self): - G = nx.trivial_graph() - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - # In fact, we should only have 1-cliques, that is, singleton nodes. - assert all(len(clique) == 1 for clique in cliques) - - def test_complete_graph(self): - G = nx.complete_graph(10) - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - - def test_barbell_graph(self): - G = nx.barbell_graph(10, 5) - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - - -class TestMaxClique: - """Unit tests for the :func:`networkx.algorithms.approximation.max_clique` - function. - - """ - - def test_null_graph(self): - G = nx.null_graph() - assert len(max_clique(G)) == 0 - - def test_complete_graph(self): - graph = nx.complete_graph(30) - # this should return the entire graph - mc = max_clique(graph) - assert 30 == len(mc) - - def test_maximal_by_cardinality(self): - """Tests that the maximal clique is computed according to maximum - cardinality of the sets. - - For more information, see pull request #1531. - - """ - G = nx.complete_graph(5) - G.add_edge(4, 5) - clique = max_clique(G) - assert len(clique) > 1 - - G = nx.lollipop_graph(30, 2) - clique = max_clique(G) - assert len(clique) > 2 - - -def test_large_clique_size(): - G = nx.complete_graph(9) - nx.add_cycle(G, [9, 10, 11]) - G.add_edge(8, 9) - G.add_edge(1, 12) - G.add_node(13) - - assert large_clique_size(G) == 9 - G.remove_node(5) - assert large_clique_size(G) == 8 - G.remove_edge(2, 3) - assert large_clique_size(G) == 7 - - -def test_independent_set(): - # smoke test - G = nx.Graph() - assert len(maximum_independent_set(G)) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_connectivity.py deleted file mode 100644 index 887db20..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_connectivity.py +++ /dev/null @@ -1,199 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import approximation as approx - - -def test_global_node_connectivity(): - # Figure 1 chapter on Connectivity - G = nx.Graph() - G.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 6), - (3, 4), - (3, 6), - (4, 6), - (4, 7), - (5, 7), - (6, 8), - (6, 9), - (7, 8), - (7, 10), - (8, 11), - (9, 10), - (9, 11), - (10, 11), - ] - ) - assert 2 == approx.local_node_connectivity(G, 1, 11) - assert 2 == approx.node_connectivity(G) - assert 2 == approx.node_connectivity(G, 1, 11) - - -def test_white_harary1(): - # Figure 1b white and harary (2001) - # A graph with high adhesion (edge connectivity) and low cohesion - # (node connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - assert 1 == approx.node_connectivity(G) - - -def test_complete_graphs(): - for n in range(5, 25, 5): - G = nx.complete_graph(n) - assert n - 1 == approx.node_connectivity(G) - assert n - 1 == approx.node_connectivity(G, 0, 3) - - -def test_empty_graphs(): - for k in range(5, 25, 5): - G = nx.empty_graph(k) - assert 0 == approx.node_connectivity(G) - assert 0 == approx.node_connectivity(G, 0, 3) - - -def test_petersen(): - G = nx.petersen_graph() - assert 3 == approx.node_connectivity(G) - assert 3 == approx.node_connectivity(G, 0, 5) - - -# Approximation fails with tutte graph -# def test_tutte(): -# G = nx.tutte_graph() -# assert_equal(3, approx.node_connectivity(G)) - - -def test_dodecahedral(): - G = nx.dodecahedral_graph() - assert 3 == approx.node_connectivity(G) - assert 3 == approx.node_connectivity(G, 0, 5) - - -def test_octahedral(): - G = nx.octahedral_graph() - assert 4 == approx.node_connectivity(G) - assert 4 == approx.node_connectivity(G, 0, 5) - - -# Approximation can fail with icosahedral graph depending -# on iteration order. -# def test_icosahedral(): -# G=nx.icosahedral_graph() -# assert_equal(5, approx.node_connectivity(G)) -# assert_equal(5, approx.node_connectivity(G, 0, 5)) - - -def test_only_source(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, s=0) - - -def test_only_target(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, t=0) - - -def test_missing_source(): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 10, 1) - - -def test_missing_target(): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 1, 10) - - -def test_source_equals_target(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.local_node_connectivity, G, 0, 0) - - -def test_directed_node_connectivity(): - G = nx.cycle_graph(10, create_using=nx.DiGraph()) # only one direction - D = nx.cycle_graph(10).to_directed() # 2 reciprocal edges - assert 1 == approx.node_connectivity(G) - assert 1 == approx.node_connectivity(G, 1, 4) - assert 2 == approx.node_connectivity(D) - assert 2 == approx.node_connectivity(D, 1, 4) - - -class TestAllPairsNodeConnectivityApprox: - @classmethod - def setup_class(cls): - cls.path = nx.path_graph(7) - cls.directed_path = nx.path_graph(7, create_using=nx.DiGraph()) - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.gnp = nx.gnp_random_graph(30, 0.1) - cls.directed_gnp = nx.gnp_random_graph(30, 0.1, directed=True) - cls.K20 = nx.complete_graph(20) - cls.K10 = nx.complete_graph(10) - cls.K5 = nx.complete_graph(5) - cls.G_list = [ - cls.path, - cls.directed_path, - cls.cycle, - cls.directed_cycle, - cls.gnp, - cls.directed_gnp, - cls.K10, - cls.K5, - cls.K20, - ] - - def test_cycles(self): - K_undir = approx.all_pairs_node_connectivity(self.cycle) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 2 - K_dir = approx.all_pairs_node_connectivity(self.directed_cycle) - for source in K_dir: - for target, k in K_dir[source].items(): - assert k == 1 - - def test_complete(self): - for G in [self.K10, self.K5, self.K20]: - K = approx.all_pairs_node_connectivity(G) - for source in K: - for target, k in K[source].items(): - assert k == len(G) - 1 - - def test_paths(self): - K_undir = approx.all_pairs_node_connectivity(self.path) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 1 - K_dir = approx.all_pairs_node_connectivity(self.directed_path) - for source in K_dir: - for target, k in K_dir[source].items(): - if source < target: - assert k == 1 - else: - assert k == 0 - - def test_cutoff(self): - for G in [self.K10, self.K5, self.K20]: - for mp in [2, 3, 4]: - paths = approx.all_pairs_node_connectivity(G, cutoff=mp) - for source in paths: - for target, K in paths[source].items(): - assert K == mp - - def test_all_pairs_connectivity_nbunch(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - C = approx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert len(C) == len(nbunch) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_distance_measures.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_distance_measures.py deleted file mode 100644 index 3809a8f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_distance_measures.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.approximation.distance_measures` module.""" - -import pytest - -import networkx as nx -from networkx.algorithms.approximation import diameter - - -class TestDiameter: - """Unit tests for the approximate diameter function - :func:`~networkx.algorithms.approximation.distance_measures.diameter`. - """ - - def test_null_graph(self): - """Test empty graph.""" - G = nx.null_graph() - with pytest.raises( - nx.NetworkXError, match="Expected non-empty NetworkX graph!" - ): - diameter(G) - - def test_undirected_non_connected(self): - """Test an undirected disconnected graph.""" - graph = nx.path_graph(10) - graph.remove_edge(3, 4) - with pytest.raises(nx.NetworkXError, match="Graph not connected."): - diameter(graph) - - def test_directed_non_strongly_connected(self): - """Test a directed non strongly connected graph.""" - graph = nx.path_graph(10, create_using=nx.DiGraph()) - with pytest.raises(nx.NetworkXError, match="DiGraph not strongly connected."): - diameter(graph) - - def test_complete_undirected_graph(self): - """Test a complete undirected graph.""" - graph = nx.complete_graph(10) - assert diameter(graph) == 1 - - def test_complete_directed_graph(self): - """Test a complete directed graph.""" - graph = nx.complete_graph(10, create_using=nx.DiGraph()) - assert diameter(graph) == 1 - - def test_undirected_path_graph(self): - """Test an undirected path graph with 10 nodes.""" - graph = nx.path_graph(10) - assert diameter(graph) == 9 - - def test_directed_path_graph(self): - """Test a directed path graph with 10 nodes.""" - graph = nx.path_graph(10).to_directed() - assert diameter(graph) == 9 - - def test_single_node(self): - """Test a graph which contains just a node.""" - graph = nx.Graph() - graph.add_node(1) - assert diameter(graph) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_dominating_set.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_dominating_set.py deleted file mode 100644 index 6b90d85..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_dominating_set.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.approximation import ( - min_edge_dominating_set, - min_weighted_dominating_set, -) - - -class TestMinWeightDominatingSet: - def test_min_weighted_dominating_set(self): - graph = nx.Graph() - graph.add_edge(1, 2) - graph.add_edge(1, 5) - graph.add_edge(2, 3) - graph.add_edge(2, 5) - graph.add_edge(3, 4) - graph.add_edge(3, 6) - graph.add_edge(5, 6) - - vertices = {1, 2, 3, 4, 5, 6} - # due to ties, this might be hard to test tight bounds - dom_set = min_weighted_dominating_set(graph) - for vertex in vertices - dom_set: - neighbors = set(graph.neighbors(vertex)) - assert len(neighbors & dom_set) > 0, "Non dominating set found!" - - def test_star_graph(self): - """Tests that an approximate dominating set for the star graph, - even when the center node does not have the smallest integer - label, gives just the center node. - - For more information, see #1527. - - """ - # Create a star graph in which the center node has the highest - # label instead of the lowest. - G = nx.star_graph(10) - G = nx.relabel_nodes(G, {0: 9, 9: 0}) - assert min_weighted_dominating_set(G) == {9} - - def test_null_graph(self): - """Tests that the unique dominating set for the null graph is an empty set""" - G = nx.Graph() - assert min_weighted_dominating_set(G) == set() - - def test_min_edge_dominating_set(self): - graph = nx.path_graph(5) - dom_set = min_edge_dominating_set(graph) - - # this is a crappy way to test, but good enough for now. - for edge in graph.edges(): - if edge in dom_set: - continue - else: - u, v = edge - found = False - for dom_edge in dom_set: - found |= u == dom_edge[0] or u == dom_edge[1] - assert found, "Non adjacent edge found!" - - graph = nx.complete_graph(10) - dom_set = min_edge_dominating_set(graph) - - # this is a crappy way to test, but good enough for now. - for edge in graph.edges(): - if edge in dom_set: - continue - else: - u, v = edge - found = False - for dom_edge in dom_set: - found |= u == dom_edge[0] or u == dom_edge[1] - assert found, "Non adjacent edge found!" - - graph = nx.Graph() # empty Networkx graph - with pytest.raises(ValueError, match="Expected non-empty NetworkX graph!"): - min_edge_dominating_set(graph) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_kcomponents.py deleted file mode 100644 index 65ba802..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_kcomponents.py +++ /dev/null @@ -1,303 +0,0 @@ -# Test for approximation to k-components algorithm -import pytest - -import networkx as nx -from networkx.algorithms.approximation import k_components -from networkx.algorithms.approximation.kcomponents import _AntiGraph, _same - - -def build_k_number_dict(k_components): - k_num = {} - for k, comps in sorted(k_components.items()): - for comp in comps: - for node in comp: - k_num[node] = k - return k_num - - -## -# Some nice synthetic graphs -## - - -def graph_example_1(): - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), label_attribute="labels" - ) - rlabels = nx.get_node_attributes(G, "labels") - labels = {v: k for k, v in rlabels.items()} - - for nodes in [ - (labels[(0, 0)], labels[(1, 0)]), - (labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 0)], labels[(4, 0)]), - (labels[(3, 4)], labels[(4, 4)]), - ]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - G.add_edge(new_node + 16, new_node + 5) - return G - - -def torrents_and_ferraro_graph(): - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), label_attribute="labels" - ) - rlabels = nx.get_node_attributes(G, "labels") - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # Commenting this makes the graph not biconnected !! - # This stupid mistake make one reviewer very angry :P - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - - -# Helper function - - -def _check_connectivity(G): - result = k_components(G) - for k, components in result.items(): - if k < 3: - continue - for component in components: - C = G.subgraph(component) - K = nx.node_connectivity(C) - assert K >= k - - -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - _check_connectivity(G) - - -def test_example_1(): - G = graph_example_1() - _check_connectivity(G) - - -def test_karate_0(): - G = nx.karate_club_graph() - _check_connectivity(G) - - -def test_karate_1(): - karate_k_num = { - 0: 4, - 1: 4, - 2: 4, - 3: 4, - 4: 3, - 5: 3, - 6: 3, - 7: 4, - 8: 4, - 9: 2, - 10: 3, - 11: 1, - 12: 2, - 13: 4, - 14: 2, - 15: 2, - 16: 2, - 17: 2, - 18: 2, - 19: 3, - 20: 2, - 21: 2, - 22: 2, - 23: 3, - 24: 3, - 25: 3, - 26: 2, - 27: 3, - 28: 3, - 29: 3, - 30: 4, - 31: 3, - 32: 4, - 33: 4, - } - approx_karate_k_num = karate_k_num.copy() - approx_karate_k_num[24] = 2 - approx_karate_k_num[25] = 2 - G = nx.karate_club_graph() - k_comps = k_components(G) - k_num = build_k_number_dict(k_comps) - assert k_num in (karate_k_num, approx_karate_k_num) - - -def test_example_1_detail_3_and_4(): - G = graph_example_1() - result = k_components(G) - # In this example graph there are 8 3-components, 4 with 15 nodes - # and 4 with 5 nodes. - assert len(result[3]) == 8 - assert len([c for c in result[3] if len(c) == 15]) == 4 - assert len([c for c in result[3] if len(c) == 5]) == 4 - # There are also 8 4-components all with 5 nodes. - assert len(result[4]) == 8 - assert all(len(c) == 5 for c in result[4]) - # Finally check that the k-components detected have actually node - # connectivity >= k. - for k, components in result.items(): - if k < 3: - continue - for component in components: - K = nx.node_connectivity(G.subgraph(component)) - assert K >= k - - -def test_directed(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.gnp_random_graph(10, 0.4, directed=True) - kc = k_components(G) - - -def test_same(): - equal = {"A": 2, "B": 2, "C": 2} - slightly_different = {"A": 2, "B": 1, "C": 2} - different = {"A": 2, "B": 8, "C": 18} - assert _same(equal) - assert not _same(slightly_different) - assert _same(slightly_different, tol=1) - assert not _same(different) - assert not _same(different, tol=4) - - -class TestAntiGraph: - @classmethod - def setup_class(cls): - cls.Gnp = nx.gnp_random_graph(20, 0.8, seed=42) - cls.Anp = _AntiGraph(nx.complement(cls.Gnp)) - cls.Gd = nx.davis_southern_women_graph() - cls.Ad = _AntiGraph(nx.complement(cls.Gd)) - cls.Gk = nx.karate_club_graph() - cls.Ak = _AntiGraph(nx.complement(cls.Gk)) - cls.GA = [(cls.Gnp, cls.Anp), (cls.Gd, cls.Ad), (cls.Gk, cls.Ak)] - - def test_size(self): - for G, A in self.GA: - n = G.order() - s = len(list(G.edges())) + len(list(A.edges())) - assert s == (n * (n - 1)) / 2 - - def test_degree(self): - for G, A in self.GA: - assert sorted(G.degree()) == sorted(A.degree()) - - def test_core_number(self): - for G, A in self.GA: - assert nx.core_number(G) == nx.core_number(A) - - def test_connected_components(self): - # ccs are same unless isolated nodes or any node has degree=len(G)-1 - # graphs in self.GA avoid this problem - for G, A in self.GA: - gc = [set(c) for c in nx.connected_components(G)] - ac = [set(c) for c in nx.connected_components(A)] - for comp in ac: - assert comp in gc - - def test_adj(self): - for G, A in self.GA: - for n, nbrs in G.adj.items(): - a_adj = sorted((n, sorted(ad)) for n, ad in A.adj.items()) - g_adj = sorted((n, sorted(ad)) for n, ad in G.adj.items()) - assert a_adj == g_adj - - def test_adjacency(self): - for G, A in self.GA: - a_adj = list(A.adjacency()) - for n, nbrs in G.adjacency(): - assert (n, set(nbrs)) in a_adj - - def test_neighbors(self): - for G, A in self.GA: - node = list(G.nodes())[0] - assert set(G.neighbors(node)) == set(A.neighbors(node)) - - def test_node_not_in_graph(self): - for G, A in self.GA: - node = "non_existent_node" - pytest.raises(nx.NetworkXError, A.neighbors, node) - pytest.raises(nx.NetworkXError, G.neighbors, node) - - def test_degree_thingraph(self): - for G, A in self.GA: - node = list(G.nodes())[0] - nodes = list(G.nodes())[1:4] - assert G.degree(node) == A.degree(node) - assert sum(d for n, d in G.degree()) == sum(d for n, d in A.degree()) - # AntiGraph is a ThinGraph, so all the weights are 1 - assert sum(d for n, d in A.degree()) == sum( - d for n, d in A.degree(weight="weight") - ) - assert sum(d for n, d in G.degree(nodes)) == sum( - d for n, d in A.degree(nodes) - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_matching.py deleted file mode 100644 index f50da3d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_matching.py +++ /dev/null @@ -1,8 +0,0 @@ -import networkx as nx -import networkx.algorithms.approximation as a - - -def test_min_maximal_matching(): - # smoke test - G = nx.Graph() - assert len(a.min_maximal_matching(G)) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_maxcut.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_maxcut.py deleted file mode 100644 index ef04244..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_maxcut.py +++ /dev/null @@ -1,94 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx.algorithms.approximation import maxcut - - -@pytest.mark.parametrize( - "f", (nx.approximation.randomized_partitioning, nx.approximation.one_exchange) -) -@pytest.mark.parametrize("graph_constructor", (nx.DiGraph, nx.MultiGraph)) -def test_raises_on_directed_and_multigraphs(f, graph_constructor): - G = graph_constructor([(0, 1), (1, 2)]) - with pytest.raises(nx.NetworkXNotImplemented): - f(G) - - -def _is_valid_cut(G, set1, set2): - union = set1.union(set2) - assert union == set(G.nodes) - assert len(set1) + len(set2) == G.number_of_nodes() - - -def _cut_is_locally_optimal(G, cut_size, set1): - # test if cut can be locally improved - for i, node in enumerate(set1): - cut_size_without_node = nx.algorithms.cut_size( - G, set1 - {node}, weight="weight" - ) - assert cut_size_without_node <= cut_size - - -def test_random_partitioning(): - G = nx.complete_graph(5) - _, (set1, set2) = maxcut.randomized_partitioning(G, seed=5) - _is_valid_cut(G, set1, set2) - - -def test_random_partitioning_all_to_one(): - G = nx.complete_graph(5) - _, (set1, set2) = maxcut.randomized_partitioning(G, p=1) - _is_valid_cut(G, set1, set2) - assert len(set1) == G.number_of_nodes() - assert len(set2) == 0 - - -def test_one_exchange_basic(): - G = nx.complete_graph(5) - random.seed(5) - for u, v, w in G.edges(data=True): - w["weight"] = random.randrange(-100, 100, 1) / 10 - - initial_cut = set(random.sample(sorted(G.nodes()), k=5)) - cut_size, (set1, set2) = maxcut.one_exchange( - G, initial_cut, weight="weight", seed=5 - ) - - _is_valid_cut(G, set1, set2) - _cut_is_locally_optimal(G, cut_size, set1) - - -def test_one_exchange_optimal(): - # Greedy one exchange should find the optimal solution for this graph (14) - G = nx.Graph() - G.add_edge(1, 2, weight=3) - G.add_edge(1, 3, weight=3) - G.add_edge(1, 4, weight=3) - G.add_edge(1, 5, weight=3) - G.add_edge(2, 3, weight=5) - - cut_size, (set1, set2) = maxcut.one_exchange(G, weight="weight", seed=5) - - _is_valid_cut(G, set1, set2) - _cut_is_locally_optimal(G, cut_size, set1) - # check global optimality - assert cut_size == 14 - - -def test_negative_weights(): - G = nx.complete_graph(5) - random.seed(5) - for u, v, w in G.edges(data=True): - w["weight"] = -1 * random.random() - - initial_cut = set(random.sample(sorted(G.nodes()), k=5)) - cut_size, (set1, set2) = maxcut.one_exchange(G, initial_cut, weight="weight") - - # make sure it is a valid cut - _is_valid_cut(G, set1, set2) - # check local optimality - _cut_is_locally_optimal(G, cut_size, set1) - # test that all nodes are in the same partition - assert len(set1) == len(G.nodes) or len(set2) == len(G.nodes) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_ramsey.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_ramsey.py deleted file mode 100644 index 32fe1fb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_ramsey.py +++ /dev/null @@ -1,31 +0,0 @@ -import networkx as nx -import networkx.algorithms.approximation as apxa - - -def test_ramsey(): - # this should only find the complete graph - graph = nx.complete_graph(10) - c, i = apxa.ramsey_R2(graph) - cdens = nx.density(graph.subgraph(c)) - assert cdens == 1.0, "clique not correctly found by ramsey!" - idens = nx.density(graph.subgraph(i)) - assert idens == 0.0, "i-set not correctly found by ramsey!" - - # this trivial graph has no cliques. should just find i-sets - graph = nx.trivial_graph() - c, i = apxa.ramsey_R2(graph) - assert c == {0}, "clique not correctly found by ramsey!" - assert i == {0}, "i-set not correctly found by ramsey!" - - graph = nx.barbell_graph(10, 5, nx.Graph()) - c, i = apxa.ramsey_R2(graph) - cdens = nx.density(graph.subgraph(c)) - assert cdens == 1.0, "clique not correctly found by ramsey!" - idens = nx.density(graph.subgraph(i)) - assert idens == 0.0, "i-set not correctly found by ramsey!" - - # add self-loops and test again - graph.add_edges_from([(n, n) for n in range(0, len(graph), 2)]) - cc, ii = apxa.ramsey_R2(graph) - assert cc == c - assert ii == i diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_steinertree.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_steinertree.py deleted file mode 100644 index 1b07475..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_steinertree.py +++ /dev/null @@ -1,265 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.approximation.steinertree import ( - _remove_nonterminal_leaves, - metric_closure, - steiner_tree, -) -from networkx.utils import edges_equal - - -class TestSteinerTree: - @classmethod - def setup_class(cls): - G1 = nx.Graph() - G1.add_edge(1, 2, weight=10) - G1.add_edge(2, 3, weight=10) - G1.add_edge(3, 4, weight=10) - G1.add_edge(4, 5, weight=10) - G1.add_edge(5, 6, weight=10) - G1.add_edge(2, 7, weight=1) - G1.add_edge(7, 5, weight=1) - - G2 = nx.Graph() - G2.add_edge(0, 5, weight=6) - G2.add_edge(1, 2, weight=2) - G2.add_edge(1, 5, weight=3) - G2.add_edge(2, 4, weight=4) - G2.add_edge(3, 5, weight=5) - G2.add_edge(4, 5, weight=1) - - G3 = nx.Graph() - G3.add_edge(1, 2, weight=8) - G3.add_edge(1, 9, weight=3) - G3.add_edge(1, 8, weight=6) - G3.add_edge(1, 10, weight=2) - G3.add_edge(1, 14, weight=3) - G3.add_edge(2, 3, weight=6) - G3.add_edge(3, 4, weight=3) - G3.add_edge(3, 10, weight=2) - G3.add_edge(3, 11, weight=1) - G3.add_edge(4, 5, weight=1) - G3.add_edge(4, 11, weight=1) - G3.add_edge(5, 6, weight=4) - G3.add_edge(5, 11, weight=2) - G3.add_edge(5, 12, weight=1) - G3.add_edge(5, 13, weight=3) - G3.add_edge(6, 7, weight=2) - G3.add_edge(6, 12, weight=3) - G3.add_edge(6, 13, weight=1) - G3.add_edge(7, 8, weight=3) - G3.add_edge(7, 9, weight=3) - G3.add_edge(7, 11, weight=5) - G3.add_edge(7, 13, weight=2) - G3.add_edge(7, 14, weight=4) - G3.add_edge(8, 9, weight=2) - G3.add_edge(9, 14, weight=1) - G3.add_edge(10, 11, weight=2) - G3.add_edge(10, 14, weight=1) - G3.add_edge(11, 12, weight=1) - G3.add_edge(11, 14, weight=7) - G3.add_edge(12, 14, weight=3) - G3.add_edge(12, 15, weight=1) - G3.add_edge(13, 14, weight=4) - G3.add_edge(13, 15, weight=1) - G3.add_edge(14, 15, weight=2) - - cls.G1 = G1 - cls.G2 = G2 - cls.G3 = G3 - cls.G1_term_nodes = [1, 2, 3, 4, 5] - cls.G2_term_nodes = [0, 2, 3] - cls.G3_term_nodes = [1, 3, 5, 6, 8, 10, 11, 12, 13] - - cls.methods = ["kou", "mehlhorn"] - - def test_connected_metric_closure(self): - G = self.G1.copy() - G.add_node(100) - pytest.raises(nx.NetworkXError, metric_closure, G) - - def test_metric_closure(self): - M = metric_closure(self.G1) - mc = [ - (1, 2, {"distance": 10, "path": [1, 2]}), - (1, 3, {"distance": 20, "path": [1, 2, 3]}), - (1, 4, {"distance": 22, "path": [1, 2, 7, 5, 4]}), - (1, 5, {"distance": 12, "path": [1, 2, 7, 5]}), - (1, 6, {"distance": 22, "path": [1, 2, 7, 5, 6]}), - (1, 7, {"distance": 11, "path": [1, 2, 7]}), - (2, 3, {"distance": 10, "path": [2, 3]}), - (2, 4, {"distance": 12, "path": [2, 7, 5, 4]}), - (2, 5, {"distance": 2, "path": [2, 7, 5]}), - (2, 6, {"distance": 12, "path": [2, 7, 5, 6]}), - (2, 7, {"distance": 1, "path": [2, 7]}), - (3, 4, {"distance": 10, "path": [3, 4]}), - (3, 5, {"distance": 12, "path": [3, 2, 7, 5]}), - (3, 6, {"distance": 22, "path": [3, 2, 7, 5, 6]}), - (3, 7, {"distance": 11, "path": [3, 2, 7]}), - (4, 5, {"distance": 10, "path": [4, 5]}), - (4, 6, {"distance": 20, "path": [4, 5, 6]}), - (4, 7, {"distance": 11, "path": [4, 5, 7]}), - (5, 6, {"distance": 10, "path": [5, 6]}), - (5, 7, {"distance": 1, "path": [5, 7]}), - (6, 7, {"distance": 11, "path": [6, 5, 7]}), - ] - assert edges_equal(list(M.edges(data=True)), mc) - - def test_steiner_tree(self): - valid_steiner_trees = [ - [ - [ - (1, 2, {"weight": 10}), - (2, 3, {"weight": 10}), - (2, 7, {"weight": 1}), - (3, 4, {"weight": 10}), - (5, 7, {"weight": 1}), - ], - [ - (1, 2, {"weight": 10}), - (2, 7, {"weight": 1}), - (3, 4, {"weight": 10}), - (4, 5, {"weight": 10}), - (5, 7, {"weight": 1}), - ], - [ - (1, 2, {"weight": 10}), - (2, 3, {"weight": 10}), - (2, 7, {"weight": 1}), - (4, 5, {"weight": 10}), - (5, 7, {"weight": 1}), - ], - ], - [ - [ - (0, 5, {"weight": 6}), - (1, 2, {"weight": 2}), - (1, 5, {"weight": 3}), - (3, 5, {"weight": 5}), - ], - [ - (0, 5, {"weight": 6}), - (4, 2, {"weight": 4}), - (4, 5, {"weight": 1}), - (3, 5, {"weight": 5}), - ], - ], - [ - [ - (1, 10, {"weight": 2}), - (3, 10, {"weight": 2}), - (3, 11, {"weight": 1}), - (5, 12, {"weight": 1}), - (6, 13, {"weight": 1}), - (8, 9, {"weight": 2}), - (9, 14, {"weight": 1}), - (10, 14, {"weight": 1}), - (11, 12, {"weight": 1}), - (12, 15, {"weight": 1}), - (13, 15, {"weight": 1}), - ] - ], - ] - for method in self.methods: - for G, term_nodes, valid_trees in zip( - [self.G1, self.G2, self.G3], - [self.G1_term_nodes, self.G2_term_nodes, self.G3_term_nodes], - valid_steiner_trees, - ): - S = steiner_tree(G, term_nodes, method=method) - assert any( - edges_equal(list(S.edges(data=True)), valid_tree) - for valid_tree in valid_trees - ) - - def test_multigraph_steiner_tree(self): - G = nx.MultiGraph() - G.add_edges_from( - [ - (1, 2, 0, {"weight": 1}), - (2, 3, 0, {"weight": 999}), - (2, 3, 1, {"weight": 1}), - (3, 4, 0, {"weight": 1}), - (3, 5, 0, {"weight": 1}), - ] - ) - terminal_nodes = [2, 4, 5] - expected_edges = [ - (2, 3, 1, {"weight": 1}), # edge with key 1 has lower weight - (3, 4, 0, {"weight": 1}), - (3, 5, 0, {"weight": 1}), - ] - for method in self.methods: - S = steiner_tree(G, terminal_nodes, method=method) - assert edges_equal(S.edges(data=True, keys=True), expected_edges) - - def test_remove_nonterminal_leaves(self): - G = nx.path_graph(10) - _remove_nonterminal_leaves(G, [4, 5, 6]) - - assert list(G) == [4, 5, 6] # only the terminal nodes are left - - -@pytest.mark.parametrize("method", ("kou", "mehlhorn")) -def test_steiner_tree_weight_attribute(method): - G = nx.star_graph(4) - # Add an edge attribute that is named something other than "weight" - nx.set_edge_attributes(G, {e: 10 for e in G.edges}, name="distance") - H = nx.approximation.steiner_tree(G, [1, 3], method=method, weight="distance") - assert nx.utils.edges_equal(H.edges, [(0, 1), (0, 3)]) - - -@pytest.mark.parametrize("method", ("kou", "mehlhorn")) -def test_steiner_tree_multigraph_weight_attribute(method): - G = nx.cycle_graph(3, create_using=nx.MultiGraph) - nx.set_edge_attributes(G, {e: 10 for e in G.edges}, name="distance") - G.add_edge(2, 0, distance=5) - H = nx.approximation.steiner_tree(G, list(G), method=method, weight="distance") - assert len(H.edges) == 2 and H.has_edge(2, 0, key=1) - assert sum(dist for *_, dist in H.edges(data="distance")) == 15 - - -@pytest.mark.parametrize("method", (None, "mehlhorn", "kou")) -def test_steiner_tree_methods(method): - G = nx.star_graph(4) - expected = nx.Graph([(0, 1), (0, 3)]) - st = nx.approximation.steiner_tree(G, [1, 3], method=method) - assert nx.utils.edges_equal(st.edges, expected.edges) - - -def test_steiner_tree_method_invalid(): - G = nx.star_graph(4) - with pytest.raises( - ValueError, match="invalid_method is not a valid choice for an algorithm." - ): - nx.approximation.steiner_tree(G, terminal_nodes=[1, 3], method="invalid_method") - - -def test_steiner_tree_remove_non_terminal_leaves_self_loop_edges(): - # To verify that the last step of the steiner tree approximation - # behaves in the case where a non-terminal leaf has a self loop edge - G = nx.path_graph(10) - - # Add self loops to the terminal nodes - G.add_edges_from([(2, 2), (3, 3), (4, 4), (7, 7), (8, 8)]) - - # Remove non-terminal leaves - _remove_nonterminal_leaves(G, [4, 5, 6, 7]) - - # The terminal nodes should be left - assert list(G) == [4, 5, 6, 7] # only the terminal nodes are left - - -def test_steiner_tree_non_terminal_leaves_multigraph_self_loop_edges(): - # To verify that the last step of the steiner tree approximation - # behaves in the case where a non-terminal leaf has a self loop edge - G = nx.MultiGraph() - G.add_edges_from([(i, i + 1) for i in range(10)]) - G.add_edges_from([(2, 2), (3, 3), (4, 4), (4, 4), (7, 7)]) - - # Remove non-terminal leaves - _remove_nonterminal_leaves(G, [4, 5, 6, 7]) - - # Only the terminal nodes should be left - assert list(G) == [4, 5, 6, 7] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_traveling_salesman.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_traveling_salesman.py deleted file mode 100644 index 2084c19..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_traveling_salesman.py +++ /dev/null @@ -1,977 +0,0 @@ -"""Unit tests for the traveling_salesman module.""" - -import random - -import pytest - -import networkx as nx -import networkx.algorithms.approximation as nx_app - -pairwise = nx.utils.pairwise - - -def test_christofides_hamiltonian(): - random.seed(42) - G = nx.complete_graph(20) - for u, v in G.edges(): - G[u][v]["weight"] = random.randint(0, 10) - - H = nx.Graph() - H.add_edges_from(pairwise(nx_app.christofides(G))) - H.remove_edges_from(nx.find_cycle(H)) - assert len(H.edges) == 0 - - tree = nx.minimum_spanning_tree(G, weight="weight") - H = nx.Graph() - H.add_edges_from(pairwise(nx_app.christofides(G, tree))) - H.remove_edges_from(nx.find_cycle(H)) - assert len(H.edges) == 0 - - -def test_christofides_incomplete_graph(): - G = nx.complete_graph(10) - G.remove_edge(0, 1) - pytest.raises(nx.NetworkXError, nx_app.christofides, G) - - -def test_christofides_ignore_selfloops(): - G = nx.complete_graph(5) - G.add_edge(3, 3) - cycle = nx_app.christofides(G) - assert len(cycle) - 1 == len(G) == len(set(cycle)) - - -# set up graphs for other tests -class TestBase: - @classmethod - def setup_class(cls): - cls.DG = nx.DiGraph() - cls.DG.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "A", 3), - ("B", "C", 12), - ("B", "D", 16), - ("C", "A", 13), - ("C", "B", 12), - ("C", "D", 4), - ("D", "A", 14), - ("D", "B", 15), - ("D", "C", 2), - } - ) - cls.DG_cycle = ["D", "C", "B", "A", "D"] - cls.DG_cost = 31.0 - - cls.DG2 = nx.DiGraph() - cls.DG2.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "A", 30), - ("B", "C", 2), - ("B", "D", 16), - ("C", "A", 33), - ("C", "B", 32), - ("C", "D", 34), - ("D", "A", 14), - ("D", "B", 15), - ("D", "C", 2), - } - ) - cls.DG2_cycle = ["D", "A", "B", "C", "D"] - cls.DG2_cost = 53.0 - - cls.unweightedUG = nx.complete_graph(5, nx.Graph()) - cls.unweightedDG = nx.complete_graph(5, nx.DiGraph()) - - cls.incompleteUG = nx.Graph() - cls.incompleteUG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) - cls.incompleteDG = nx.DiGraph() - cls.incompleteDG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) - - cls.UG = nx.Graph() - cls.UG.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "C", 12), - ("B", "D", 16), - ("C", "D", 4), - } - ) - cls.UG_cycle = ["D", "C", "B", "A", "D"] - cls.UG_cost = 33.0 - - cls.UG2 = nx.Graph() - cls.UG2.add_weighted_edges_from( - { - ("A", "B", 1), - ("A", "C", 15), - ("A", "D", 5), - ("B", "C", 16), - ("B", "D", 8), - ("C", "D", 3), - } - ) - cls.UG2_cycle = ["D", "C", "B", "A", "D"] - cls.UG2_cost = 25.0 - - -def validate_solution(soln, cost, exp_soln, exp_cost): - assert soln == exp_soln - assert cost == exp_cost - - -def validate_symmetric_solution(soln, cost, exp_soln, exp_cost): - assert soln == exp_soln or soln == exp_soln[::-1] - assert cost == exp_cost - - -class TestGreedyTSP(TestBase): - def test_greedy(self): - cycle = nx_app.greedy_tsp(self.DG, source="D") - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, ["D", "C", "B", "A", "D"], 31.0) - - cycle = nx_app.greedy_tsp(self.DG2, source="D") - cost = sum(self.DG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, ["D", "C", "B", "A", "D"], 78.0) - - cycle = nx_app.greedy_tsp(self.UG, source="D") - cost = sum(self.UG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, ["D", "C", "B", "A", "D"], 33.0) - - cycle = nx_app.greedy_tsp(self.UG2, source="D") - cost = sum(self.UG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, ["D", "C", "A", "B", "D"], 27.0) - - def test_not_complete_graph(self): - pytest.raises(nx.NetworkXError, nx_app.greedy_tsp, self.incompleteUG) - pytest.raises(nx.NetworkXError, nx_app.greedy_tsp, self.incompleteDG) - - def test_not_weighted_graph(self): - nx_app.greedy_tsp(self.unweightedUG) - nx_app.greedy_tsp(self.unweightedDG) - - def test_two_nodes(self): - G = nx.Graph() - G.add_weighted_edges_from({(1, 2, 1)}) - cycle = nx_app.greedy_tsp(G) - cost = sum(G[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, [1, 2, 1], 2) - - def test_ignore_selfloops(self): - G = nx.complete_graph(5) - G.add_edge(3, 3) - cycle = nx_app.greedy_tsp(G) - assert len(cycle) - 1 == len(G) == len(set(cycle)) - - -class TestSimulatedAnnealingTSP(TestBase): - tsp = staticmethod(nx_app.simulated_annealing_tsp) - - def test_simulated_annealing_directed(self): - cycle = self.tsp(self.DG, "greedy", source="D", seed=42) - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.DG_cycle, self.DG_cost) - - initial_sol = ["D", "B", "A", "C", "D"] - cycle = self.tsp(self.DG, initial_sol, source="D", seed=42) - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.DG_cycle, self.DG_cost) - - initial_sol = ["D", "A", "C", "B", "D"] - cycle = self.tsp(self.DG, initial_sol, move="1-0", source="D", seed=42) - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.DG_cycle, self.DG_cost) - - cycle = self.tsp(self.DG2, "greedy", source="D", seed=42) - cost = sum(self.DG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.DG2_cycle, self.DG2_cost) - - cycle = self.tsp(self.DG2, "greedy", move="1-0", source="D", seed=42) - cost = sum(self.DG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.DG2_cycle, self.DG2_cost) - - def test_simulated_annealing_undirected(self): - cycle = self.tsp(self.UG, "greedy", source="D", seed=42) - cost = sum(self.UG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, self.UG_cycle, self.UG_cost) - - cycle = self.tsp(self.UG2, "greedy", source="D", seed=42) - cost = sum(self.UG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_symmetric_solution(cycle, cost, self.UG2_cycle, self.UG2_cost) - - cycle = self.tsp(self.UG2, "greedy", move="1-0", source="D", seed=42) - cost = sum(self.UG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_symmetric_solution(cycle, cost, self.UG2_cycle, self.UG2_cost) - - def test_error_on_input_order_mistake(self): - # see issue #4846 https://github.com/networkx/networkx/issues/4846 - pytest.raises(TypeError, self.tsp, self.UG, weight="weight") - pytest.raises(nx.NetworkXError, self.tsp, self.UG, "weight") - - def test_not_complete_graph(self): - pytest.raises(nx.NetworkXError, self.tsp, self.incompleteUG, "greedy", source=0) - pytest.raises(nx.NetworkXError, self.tsp, self.incompleteDG, "greedy", source=0) - - def test_ignore_selfloops(self): - G = nx.complete_graph(5) - G.add_edge(3, 3) - cycle = self.tsp(G, "greedy") - assert len(cycle) - 1 == len(G) == len(set(cycle)) - - def test_not_weighted_graph(self): - self.tsp(self.unweightedUG, "greedy") - self.tsp(self.unweightedDG, "greedy") - - def test_two_nodes(self): - G = nx.Graph() - G.add_weighted_edges_from({(1, 2, 1)}) - - cycle = self.tsp(G, "greedy", source=1, seed=42) - cost = sum(G[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, [1, 2, 1], 2) - - cycle = self.tsp(G, [1, 2, 1], source=1, seed=42) - cost = sum(G[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - validate_solution(cycle, cost, [1, 2, 1], 2) - - def test_failure_of_costs_too_high_when_iterations_low(self): - # Simulated Annealing Version: - # set number of moves low and alpha high - cycle = self.tsp( - self.DG2, "greedy", source="D", move="1-0", alpha=1, N_inner=1, seed=42 - ) - cost = sum(self.DG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - print(cycle, cost) - assert cost > self.DG2_cost - - # Try with an incorrect initial guess - initial_sol = ["D", "A", "B", "C", "D"] - cycle = self.tsp( - self.DG, - initial_sol, - source="D", - move="1-0", - alpha=0.1, - N_inner=1, - max_iterations=1, - seed=42, - ) - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - print(cycle, cost) - assert cost > self.DG_cost - - -class TestThresholdAcceptingTSP(TestSimulatedAnnealingTSP): - tsp = staticmethod(nx_app.threshold_accepting_tsp) - - def test_failure_of_costs_too_high_when_iterations_low(self): - # Threshold Version: - # set number of moves low and number of iterations low - cycle = self.tsp( - self.DG2, - "greedy", - source="D", - move="1-0", - N_inner=1, - max_iterations=1, - seed=4, - ) - cost = sum(self.DG2[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - assert cost > self.DG2_cost - - # set threshold too low - initial_sol = ["D", "A", "B", "C", "D"] - cycle = self.tsp( - self.DG, initial_sol, source="D", move="1-0", threshold=-3, seed=42 - ) - cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) - assert cost > self.DG_cost - - -# Tests for function traveling_salesman_problem -def test_TSP_method(): - G = nx.cycle_graph(9) - G[4][5]["weight"] = 10 - - # Test using the old currying method - sa_tsp = lambda G, weight: nx_app.simulated_annealing_tsp( - G, "greedy", weight, source=4, seed=1 - ) - - path = nx_app.traveling_salesman_problem( - G, - method=sa_tsp, - cycle=False, - ) - print(path) - assert path == [4, 3, 2, 1, 0, 8, 7, 6, 5] - - -def test_TSP_unweighted(): - G = nx.cycle_graph(9) - path = nx_app.traveling_salesman_problem(G, nodes=[3, 6], cycle=False) - assert path in ([3, 4, 5, 6], [6, 5, 4, 3]) - - cycle = nx_app.traveling_salesman_problem(G, nodes=[3, 6]) - assert cycle in ([3, 4, 5, 6, 5, 4, 3], [6, 5, 4, 3, 4, 5, 6]) - - -def test_TSP_weighted(): - G = nx.cycle_graph(9) - G[0][1]["weight"] = 2 - G[1][2]["weight"] = 2 - G[2][3]["weight"] = 2 - G[3][4]["weight"] = 4 - G[4][5]["weight"] = 5 - G[5][6]["weight"] = 4 - G[6][7]["weight"] = 2 - G[7][8]["weight"] = 2 - G[8][0]["weight"] = 2 - tsp = nx_app.traveling_salesman_problem - - # path between 3 and 6 - expected_paths = ([3, 2, 1, 0, 8, 7, 6], [6, 7, 8, 0, 1, 2, 3]) - # cycle between 3 and 6 - expected_cycles = ( - [3, 2, 1, 0, 8, 7, 6, 7, 8, 0, 1, 2, 3], - [6, 7, 8, 0, 1, 2, 3, 2, 1, 0, 8, 7, 6], - ) - # path through all nodes - expected_tourpaths = ([5, 6, 7, 8, 0, 1, 2, 3, 4], [4, 3, 2, 1, 0, 8, 7, 6, 5]) - - # Check default method - cycle = tsp(G, nodes=[3, 6], weight="weight") - assert cycle in expected_cycles - - path = tsp(G, nodes=[3, 6], weight="weight", cycle=False) - assert path in expected_paths - - tourpath = tsp(G, weight="weight", cycle=False) - assert tourpath in expected_tourpaths - - # Check all methods - methods = [ - (nx_app.christofides, {}), - (nx_app.greedy_tsp, {}), - ( - nx_app.simulated_annealing_tsp, - {"init_cycle": "greedy"}, - ), - ( - nx_app.threshold_accepting_tsp, - {"init_cycle": "greedy"}, - ), - ] - for method, kwargs in methods: - cycle = tsp(G, nodes=[3, 6], weight="weight", method=method, **kwargs) - assert cycle in expected_cycles - - path = tsp( - G, nodes=[3, 6], weight="weight", method=method, cycle=False, **kwargs - ) - assert path in expected_paths - - tourpath = tsp(G, weight="weight", method=method, cycle=False, **kwargs) - assert tourpath in expected_tourpaths - - -def test_TSP_incomplete_graph_short_path(): - G = nx.cycle_graph(9) - G.add_edges_from([(4, 9), (9, 10), (10, 11), (11, 0)]) - G[4][5]["weight"] = 5 - - cycle = nx_app.traveling_salesman_problem(G) - print(cycle) - assert len(cycle) == 17 and len(set(cycle)) == 12 - - # make sure that cutting one edge out of complete graph formulation - # cuts out many edges out of the path of the TSP - path = nx_app.traveling_salesman_problem(G, cycle=False) - print(path) - assert len(path) == 13 and len(set(path)) == 12 - - -def test_held_karp_ascent(): - """ - Test the Held-Karp relaxation with the ascent method - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - # Adjacency matrix from page 1153 of the 1970 Held and Karp paper - # which have been edited to be directional, but also symmetric - G_array = np.array( - [ - [0, 97, 60, 73, 17, 52], - [97, 0, 41, 52, 90, 30], - [60, 41, 0, 21, 35, 41], - [73, 52, 21, 0, 95, 46], - [17, 90, 35, 95, 0, 81], - [52, 30, 41, 46, 81, 0], - ] - ) - - solution_edges = [(1, 3), (2, 4), (3, 2), (4, 0), (5, 1), (0, 5)] - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - # Check that the optimal weights are the same - assert round(opt_hk, 2) == 207.00 - # Check that the z_stars are the same - solution = nx.DiGraph() - solution.add_edges_from(solution_edges) - assert nx.utils.edges_equal(z_star.edges, solution.edges) - - -def test_ascent_fractional_solution(): - """ - Test the ascent method using a modified version of Figure 2 on page 1140 - in 'The Traveling Salesman Problem and Minimum Spanning Trees' by Held and - Karp - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - # This version of Figure 2 has all of the edge weights multiplied by 100 - # and is a complete directed graph with infinite edge weights for the - # edges not listed in the original graph - G_array = np.array( - [ - [0, 100, 100, 100000, 100000, 1], - [100, 0, 100, 100000, 1, 100000], - [100, 100, 0, 1, 100000, 100000], - [100000, 100000, 1, 0, 100, 100], - [100000, 1, 100000, 100, 0, 100], - [1, 100000, 100000, 100, 100, 0], - ] - ) - - solution_z_star = { - (0, 1): 5 / 12, - (0, 2): 5 / 12, - (0, 5): 5 / 6, - (1, 0): 5 / 12, - (1, 2): 1 / 3, - (1, 4): 5 / 6, - (2, 0): 5 / 12, - (2, 1): 1 / 3, - (2, 3): 5 / 6, - (3, 2): 5 / 6, - (3, 4): 1 / 3, - (3, 5): 1 / 2, - (4, 1): 5 / 6, - (4, 3): 1 / 3, - (4, 5): 1 / 2, - (5, 0): 5 / 6, - (5, 3): 1 / 2, - (5, 4): 1 / 2, - } - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - # Check that the optimal weights are the same - assert round(opt_hk, 2) == 303.00 - # Check that the z_stars are the same - assert {key: round(z_star[key], 4) for key in z_star} == { - key: round(solution_z_star[key], 4) for key in solution_z_star - } - - -def test_ascent_method_asymmetric(): - """ - Tests the ascent method using a truly asymmetric graph for which the - solution has been brute forced - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - [0, 26, 63, 59, 69, 31, 41], - [62, 0, 91, 53, 75, 87, 47], - [47, 82, 0, 90, 15, 9, 18], - [68, 19, 5, 0, 58, 34, 93], - [11, 58, 53, 55, 0, 61, 79], - [88, 75, 13, 76, 98, 0, 40], - [41, 61, 55, 88, 46, 45, 0], - ] - ) - - solution_edges = [(0, 1), (1, 3), (3, 2), (2, 5), (5, 6), (4, 0), (6, 4)] - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - # Check that the optimal weights are the same - assert round(opt_hk, 2) == 190.00 - # Check that the z_stars match. - solution = nx.DiGraph() - solution.add_edges_from(solution_edges) - assert nx.utils.edges_equal(z_star.edges, solution.edges) - - -def test_ascent_method_asymmetric_2(): - """ - Tests the ascent method using a truly asymmetric graph for which the - solution has been brute forced - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - [0, 45, 39, 92, 29, 31], - [72, 0, 4, 12, 21, 60], - [81, 6, 0, 98, 70, 53], - [49, 71, 59, 0, 98, 94], - [74, 95, 24, 43, 0, 47], - [56, 43, 3, 65, 22, 0], - ] - ) - - solution_edges = [(0, 5), (5, 4), (1, 3), (3, 0), (2, 1), (4, 2)] - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - # Check that the optimal weights are the same - assert round(opt_hk, 2) == 144.00 - # Check that the z_stars match. - solution = nx.DiGraph() - solution.add_edges_from(solution_edges) - assert nx.utils.edges_equal(z_star.edges, solution.edges) - - -def test_held_karp_ascent_asymmetric_3(): - """ - Tests the ascent method using a truly asymmetric graph with a fractional - solution for which the solution has been brute forced. - - In this graph their are two different optimal, integral solutions (which - are also the overall atsp solutions) to the Held Karp relaxation. However, - this particular graph has two different tours of optimal value and the - possible solutions in the held_karp_ascent function are not stored in an - ordered data structure. - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - [0, 1, 5, 2, 7, 4], - [7, 0, 7, 7, 1, 4], - [4, 7, 0, 9, 2, 1], - [7, 2, 7, 0, 4, 4], - [5, 5, 4, 4, 0, 3], - [3, 9, 1, 3, 4, 0], - ] - ) - - solution1_edges = [(0, 3), (1, 4), (2, 5), (3, 1), (4, 2), (5, 0)] - - solution2_edges = [(0, 3), (3, 1), (1, 4), (4, 5), (2, 0), (5, 2)] - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - assert round(opt_hk, 2) == 13.00 - # Check that the z_stars are the same - solution1 = nx.DiGraph() - solution1.add_edges_from(solution1_edges) - solution2 = nx.DiGraph() - solution2.add_edges_from(solution2_edges) - assert nx.utils.edges_equal(z_star.edges, solution1.edges) or nx.utils.edges_equal( - z_star.edges, solution2.edges - ) - - -def test_held_karp_ascent_fractional_asymmetric(): - """ - Tests the ascent method using a truly asymmetric graph with a fractional - solution for which the solution has been brute forced - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - [0, 100, 150, 100000, 100000, 1], - [150, 0, 100, 100000, 1, 100000], - [100, 150, 0, 1, 100000, 100000], - [100000, 100000, 1, 0, 150, 100], - [100000, 2, 100000, 100, 0, 150], - [2, 100000, 100000, 150, 100, 0], - ] - ) - - solution_z_star = { - (0, 1): 5 / 12, - (0, 2): 5 / 12, - (0, 5): 5 / 6, - (1, 0): 5 / 12, - (1, 2): 5 / 12, - (1, 4): 5 / 6, - (2, 0): 5 / 12, - (2, 1): 5 / 12, - (2, 3): 5 / 6, - (3, 2): 5 / 6, - (3, 4): 5 / 12, - (3, 5): 5 / 12, - (4, 1): 5 / 6, - (4, 3): 5 / 12, - (4, 5): 5 / 12, - (5, 0): 5 / 6, - (5, 3): 5 / 12, - (5, 4): 5 / 12, - } - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - opt_hk, z_star = tsp.held_karp_ascent(G) - - # Check that the optimal weights are the same - assert round(opt_hk, 2) == 304.00 - # Check that the z_stars are the same - assert {key: round(z_star[key], 4) for key in z_star} == { - key: round(solution_z_star[key], 4) for key in solution_z_star - } - - -def test_spanning_tree_distribution(): - """ - Test that we can create an exponential distribution of spanning trees such - that the probability of each tree is proportional to the product of edge - weights. - - Results of this test have been confirmed with hypothesis testing from the - created distribution. - - This test uses the symmetric, fractional Held Karp solution. - """ - import networkx.algorithms.approximation.traveling_salesman as tsp - - pytest.importorskip("numpy") - pytest.importorskip("scipy") - - z_star = { - (0, 1): 5 / 12, - (0, 2): 5 / 12, - (0, 5): 5 / 6, - (1, 0): 5 / 12, - (1, 2): 1 / 3, - (1, 4): 5 / 6, - (2, 0): 5 / 12, - (2, 1): 1 / 3, - (2, 3): 5 / 6, - (3, 2): 5 / 6, - (3, 4): 1 / 3, - (3, 5): 1 / 2, - (4, 1): 5 / 6, - (4, 3): 1 / 3, - (4, 5): 1 / 2, - (5, 0): 5 / 6, - (5, 3): 1 / 2, - (5, 4): 1 / 2, - } - - solution_gamma = { - (0, 1): -0.6383, - (0, 2): -0.6827, - (0, 5): 0, - (1, 2): -1.0781, - (1, 4): 0, - (2, 3): 0, - (5, 3): -0.2820, - (5, 4): -0.3327, - (4, 3): -0.9927, - } - - # The undirected support of z_star - G = nx.MultiGraph() - for u, v in z_star: - if (u, v) in G.edges or (v, u) in G.edges: - continue - G.add_edge(u, v) - - gamma = tsp.spanning_tree_distribution(G, z_star) - - assert {key: round(gamma[key], 4) for key in gamma} == solution_gamma - - -def test_asadpour_tsp(): - """ - Test the complete asadpour tsp algorithm with the fractional, symmetric - Held Karp solution. This test also uses an incomplete graph as input. - """ - # This version of Figure 2 has all of the edge weights multiplied by 100 - # and the 0 weight edges have a weight of 1. - pytest.importorskip("numpy") - pytest.importorskip("scipy") - - edge_list = [ - (0, 1, 100), - (0, 2, 100), - (0, 5, 1), - (1, 2, 100), - (1, 4, 1), - (2, 3, 1), - (3, 4, 100), - (3, 5, 100), - (4, 5, 100), - (1, 0, 100), - (2, 0, 100), - (5, 0, 1), - (2, 1, 100), - (4, 1, 1), - (3, 2, 1), - (4, 3, 100), - (5, 3, 100), - (5, 4, 100), - ] - - G = nx.DiGraph() - G.add_weighted_edges_from(edge_list) - - tour = nx_app.traveling_salesman_problem( - G, weight="weight", method=nx_app.asadpour_atsp, seed=19 - ) - - # Check that the returned list is a valid tour. Because this is an - # incomplete graph, the conditions are not as strict. We need the tour to - # - # Start and end at the same node - # Pass through every vertex at least once - # Have a total cost at most ln(6) / ln(ln(6)) = 3.0723 times the optimal - # - # For the second condition it is possible to have the tour pass through the - # same vertex more then. Imagine that the tour on the complete version takes - # an edge not in the original graph. In the output this is substituted with - # the shortest path between those vertices, allowing vertices to appear more - # than once. - # - # Even though we are using a fixed seed, multiple tours have been known to - # be returned. The first two are from the original development of this test, - # and the third one from issue #5913 on GitHub. If other tours are returned, - # add it on the list of expected tours. - expected_tours = [ - [1, 4, 5, 0, 2, 3, 2, 1], - [3, 2, 0, 1, 4, 5, 3], - [3, 2, 1, 0, 5, 4, 3], - ] - - assert tour in expected_tours - - -def test_asadpour_real_world(): - """ - This test uses airline prices between the six largest cities in the US. - - * New York City -> JFK - * Los Angeles -> LAX - * Chicago -> ORD - * Houston -> IAH - * Phoenix -> PHX - * Philadelphia -> PHL - - Flight prices from August 2021 using Delta or American airlines to get - nonstop flight. The brute force solution found the optimal tour to cost $872 - - This test also uses the `source` keyword argument to ensure that the tour - always starts at city 0. - """ - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - # JFK LAX ORD IAH PHX PHL - [0, 243, 199, 208, 169, 183], # JFK - [277, 0, 217, 123, 127, 252], # LAX - [297, 197, 0, 197, 123, 177], # ORD - [303, 169, 197, 0, 117, 117], # IAH - [257, 127, 160, 117, 0, 319], # PHX - [183, 332, 217, 117, 319, 0], # PHL - ] - ) - - node_list = ["JFK", "LAX", "ORD", "IAH", "PHX", "PHL"] - - expected_tours = [ - ["JFK", "LAX", "PHX", "ORD", "IAH", "PHL", "JFK"], - ["JFK", "ORD", "PHX", "LAX", "IAH", "PHL", "JFK"], - ] - - G = nx.from_numpy_array(G_array, nodelist=node_list, create_using=nx.DiGraph) - - tour = nx_app.traveling_salesman_problem( - G, weight="weight", method=nx_app.asadpour_atsp, seed=37, source="JFK" - ) - - assert tour in expected_tours - - -def test_asadpour_real_world_path(): - """ - This test uses airline prices between the six largest cities in the US. This - time using a path, not a cycle. - - * New York City -> JFK - * Los Angeles -> LAX - * Chicago -> ORD - * Houston -> IAH - * Phoenix -> PHX - * Philadelphia -> PHL - - Flight prices from August 2021 using Delta or American airlines to get - nonstop flight. The brute force solution found the optimal tour to cost $872 - """ - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - G_array = np.array( - [ - # JFK LAX ORD IAH PHX PHL - [0, 243, 199, 208, 169, 183], # JFK - [277, 0, 217, 123, 127, 252], # LAX - [297, 197, 0, 197, 123, 177], # ORD - [303, 169, 197, 0, 117, 117], # IAH - [257, 127, 160, 117, 0, 319], # PHX - [183, 332, 217, 117, 319, 0], # PHL - ] - ) - - node_list = ["JFK", "LAX", "ORD", "IAH", "PHX", "PHL"] - - expected_paths = [ - ["ORD", "PHX", "LAX", "IAH", "PHL", "JFK"], - ["JFK", "PHL", "IAH", "ORD", "PHX", "LAX"], - ] - - G = nx.from_numpy_array(G_array, nodelist=node_list, create_using=nx.DiGraph) - - path = nx_app.traveling_salesman_problem( - G, weight="weight", cycle=False, method=nx_app.asadpour_atsp, seed=56 - ) - - assert path in expected_paths - - -def test_asadpour_disconnected_graph(): - """ - Test that the proper exception is raised when asadpour_atsp is given an - disconnected graph. - """ - - G = nx.complete_graph(4, create_using=nx.DiGraph) - # have to set edge weights so that if the exception is not raised, the - # function will complete and we will fail the test - nx.set_edge_attributes(G, 1, "weight") - G.add_node(5) - - pytest.raises(nx.NetworkXError, nx_app.asadpour_atsp, G) - - -def test_asadpour_incomplete_graph(): - """ - Test that the proper exception is raised when asadpour_atsp is given an - incomplete graph - """ - - G = nx.complete_graph(4, create_using=nx.DiGraph) - # have to set edge weights so that if the exception is not raised, the - # function will complete and we will fail the test - nx.set_edge_attributes(G, 1, "weight") - G.remove_edge(0, 1) - - pytest.raises(nx.NetworkXError, nx_app.asadpour_atsp, G) - - -def test_asadpour_empty_graph(): - """ - Test the asadpour_atsp function with an empty graph - """ - G = nx.DiGraph() - - pytest.raises(nx.NetworkXError, nx_app.asadpour_atsp, G) - - -@pytest.mark.slow -def test_asadpour_integral_held_karp(): - """ - This test uses an integral held karp solution and the held karp function - will return a graph rather than a dict, bypassing most of the asadpour - algorithm. - - At first glance, this test probably doesn't look like it ensures that we - skip the rest of the asadpour algorithm, but it does. We are not fixing a - see for the random number generator, so if we sample any spanning trees - the approximation would be different basically every time this test is - executed but it is not since held karp is deterministic and we do not - reach the portion of the code with the dependence on random numbers. - """ - np = pytest.importorskip("numpy") - - G_array = np.array( - [ - [0, 26, 63, 59, 69, 31, 41], - [62, 0, 91, 53, 75, 87, 47], - [47, 82, 0, 90, 15, 9, 18], - [68, 19, 5, 0, 58, 34, 93], - [11, 58, 53, 55, 0, 61, 79], - [88, 75, 13, 76, 98, 0, 40], - [41, 61, 55, 88, 46, 45, 0], - ] - ) - - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - - for _ in range(2): - tour = nx_app.traveling_salesman_problem(G, method=nx_app.asadpour_atsp) - - assert [1, 3, 2, 5, 2, 6, 4, 0, 1] == tour - - -def test_directed_tsp_impossible(): - """ - Test the asadpour algorithm with a graph without a hamiltonian circuit - """ - pytest.importorskip("numpy") - - # In this graph, once we leave node 0 we cannot return - edges = [ - (0, 1, 10), - (0, 2, 11), - (0, 3, 12), - (1, 2, 4), - (1, 3, 6), - (2, 1, 3), - (2, 3, 2), - (3, 1, 5), - (3, 2, 1), - ] - - G = nx.DiGraph() - G.add_weighted_edges_from(edges) - - pytest.raises(nx.NetworkXError, nx_app.traveling_salesman_problem, G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_treewidth.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_treewidth.py deleted file mode 100644 index 461b0f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_treewidth.py +++ /dev/null @@ -1,280 +0,0 @@ -import itertools - -import networkx as nx -from networkx.algorithms.approximation import ( - treewidth_min_degree, - treewidth_min_fill_in, -) -from networkx.algorithms.approximation.treewidth import ( - MinDegreeHeuristic, - min_fill_in_heuristic, -) - - -def is_tree_decomp(graph, decomp): - """Check if the given tree decomposition is valid.""" - for x in graph.nodes(): - appear_once = False - for bag in decomp.nodes(): - if x in bag: - appear_once = True - break - assert appear_once - - # Check if each connected pair of nodes are at least once together in a bag - for x, y in graph.edges(): - appear_together = False - for bag in decomp.nodes(): - if x in bag and y in bag: - appear_together = True - break - assert appear_together - - # Check if the nodes associated with vertex v form a connected subset of T - for v in graph.nodes(): - subset = [] - for bag in decomp.nodes(): - if v in bag: - subset.append(bag) - sub_graph = decomp.subgraph(subset) - assert nx.is_connected(sub_graph) - - -class TestTreewidthMinDegree: - """Unit tests for the min_degree function""" - - @classmethod - def setup_class(cls): - """Setup for different kinds of trees""" - cls.complete = nx.Graph() - cls.complete.add_edge(1, 2) - cls.complete.add_edge(2, 3) - cls.complete.add_edge(1, 3) - - cls.small_tree = nx.Graph() - cls.small_tree.add_edge(1, 3) - cls.small_tree.add_edge(4, 3) - cls.small_tree.add_edge(2, 3) - cls.small_tree.add_edge(3, 5) - cls.small_tree.add_edge(5, 6) - cls.small_tree.add_edge(5, 7) - cls.small_tree.add_edge(6, 7) - - cls.deterministic_graph = nx.Graph() - cls.deterministic_graph.add_edge(0, 1) # deg(0) = 1 - - cls.deterministic_graph.add_edge(1, 2) # deg(1) = 2 - - cls.deterministic_graph.add_edge(2, 3) - cls.deterministic_graph.add_edge(2, 4) # deg(2) = 3 - - cls.deterministic_graph.add_edge(3, 4) - cls.deterministic_graph.add_edge(3, 5) - cls.deterministic_graph.add_edge(3, 6) # deg(3) = 4 - - cls.deterministic_graph.add_edge(4, 5) - cls.deterministic_graph.add_edge(4, 6) - cls.deterministic_graph.add_edge(4, 7) # deg(4) = 5 - - cls.deterministic_graph.add_edge(5, 6) - cls.deterministic_graph.add_edge(5, 7) - cls.deterministic_graph.add_edge(5, 8) - cls.deterministic_graph.add_edge(5, 9) # deg(5) = 6 - - cls.deterministic_graph.add_edge(6, 7) - cls.deterministic_graph.add_edge(6, 8) - cls.deterministic_graph.add_edge(6, 9) # deg(6) = 6 - - cls.deterministic_graph.add_edge(7, 8) - cls.deterministic_graph.add_edge(7, 9) # deg(7) = 5 - - cls.deterministic_graph.add_edge(8, 9) # deg(8) = 4 - - def test_petersen_graph(self): - """Test Petersen graph tree decomposition result""" - G = nx.petersen_graph() - _, decomp = treewidth_min_degree(G) - is_tree_decomp(G, decomp) - - def test_small_tree_treewidth(self): - """Test small tree - - Test if the computed treewidth of the known self.small_tree is 2. - As we know which value we can expect from our heuristic, values other - than two are regressions - """ - G = self.small_tree - # the order of removal should be [1,2,4]3[5,6,7] - # (with [] denoting any order of the containing nodes) - # resulting in treewidth 2 for the heuristic - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 2 - - def test_heuristic_abort(self): - """Test heuristic abort condition for fully connected graph""" - graph = {} - for u in self.complete: - graph[u] = set() - for v in self.complete[u]: - if u != v: # ignore self-loop - graph[u].add(v) - - deg_heuristic = MinDegreeHeuristic(graph) - node = deg_heuristic.best_node(graph) - if node is None: - pass - else: - assert False - - def test_empty_graph(self): - """Test empty graph""" - G = nx.Graph() - _, _ = treewidth_min_degree(G) - - def test_two_component_graph(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - treewidth, _ = treewidth_min_degree(G) - assert treewidth == 0 - - def test_not_sortable_nodes(self): - G = nx.Graph([(0, "a")]) - treewidth_min_degree(G) - - def test_heuristic_first_steps(self): - """Test first steps of min_degree heuristic""" - graph = { - n: set(self.deterministic_graph[n]) - {n} for n in self.deterministic_graph - } - deg_heuristic = MinDegreeHeuristic(graph) - elim_node = deg_heuristic.best_node(graph) - print(f"Graph {graph}:") - steps = [] - - while elim_node is not None: - print(f"Removing {elim_node}:") - steps.append(elim_node) - nbrs = graph[elim_node] - - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - for u in graph: - if elim_node in graph[u]: - graph[u].remove(elim_node) - - del graph[elim_node] - print(f"Graph {graph}:") - elim_node = deg_heuristic.best_node(graph) - - # check only the first 5 elements for equality - assert steps[:5] == [0, 1, 2, 3, 4] - - -class TestTreewidthMinFillIn: - """Unit tests for the treewidth_min_fill_in function.""" - - @classmethod - def setup_class(cls): - """Setup for different kinds of trees""" - cls.complete = nx.Graph() - cls.complete.add_edge(1, 2) - cls.complete.add_edge(2, 3) - cls.complete.add_edge(1, 3) - - cls.small_tree = nx.Graph() - cls.small_tree.add_edge(1, 2) - cls.small_tree.add_edge(2, 3) - cls.small_tree.add_edge(3, 4) - cls.small_tree.add_edge(1, 4) - cls.small_tree.add_edge(2, 4) - cls.small_tree.add_edge(4, 5) - cls.small_tree.add_edge(5, 6) - cls.small_tree.add_edge(5, 7) - cls.small_tree.add_edge(6, 7) - - cls.deterministic_graph = nx.Graph() - cls.deterministic_graph.add_edge(1, 2) - cls.deterministic_graph.add_edge(1, 3) - cls.deterministic_graph.add_edge(3, 4) - cls.deterministic_graph.add_edge(2, 4) - cls.deterministic_graph.add_edge(3, 5) - cls.deterministic_graph.add_edge(4, 5) - cls.deterministic_graph.add_edge(3, 6) - cls.deterministic_graph.add_edge(5, 6) - - def test_petersen_graph(self): - """Test Petersen graph tree decomposition result""" - G = nx.petersen_graph() - _, decomp = treewidth_min_fill_in(G) - is_tree_decomp(G, decomp) - - def test_small_tree_treewidth(self): - """Test if the computed treewidth of the known self.small_tree is 2""" - G = self.small_tree - # the order of removal should be [1,2,4]3[5,6,7] - # (with [] denoting any order of the containing nodes) - # resulting in treewidth 2 for the heuristic - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 2 - - def test_heuristic_abort(self): - """Test if min_fill_in returns None for fully connected graph""" - graph = {} - for u in self.complete: - graph[u] = set() - for v in self.complete[u]: - if u != v: # ignore self-loop - graph[u].add(v) - next_node = min_fill_in_heuristic(graph) - if next_node is None: - pass - else: - assert False - - def test_empty_graph(self): - """Test empty graph""" - G = nx.Graph() - _, _ = treewidth_min_fill_in(G) - - def test_two_component_graph(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 0 - - def test_not_sortable_nodes(self): - G = nx.Graph([(0, "a")]) - treewidth_min_fill_in(G) - - def test_heuristic_first_steps(self): - """Test first steps of min_fill_in heuristic""" - graph = { - n: set(self.deterministic_graph[n]) - {n} for n in self.deterministic_graph - } - print(f"Graph {graph}:") - elim_node = min_fill_in_heuristic(graph) - steps = [] - - while elim_node is not None: - print(f"Removing {elim_node}:") - steps.append(elim_node) - nbrs = graph[elim_node] - - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - for u in graph: - if elim_node in graph[u]: - graph[u].remove(elim_node) - - del graph[elim_node] - print(f"Graph {graph}:") - elim_node = min_fill_in_heuristic(graph) - - # check only the first 2 elements for equality - assert steps[:2] == [6, 5] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_vertex_cover.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_vertex_cover.py deleted file mode 100644 index 5cc5a38..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/tests/test_vertex_cover.py +++ /dev/null @@ -1,68 +0,0 @@ -import networkx as nx -from networkx.algorithms.approximation import min_weighted_vertex_cover - - -def is_cover(G, node_cover): - return all({u, v} & node_cover for u, v in G.edges()) - - -class TestMWVC: - """Unit tests for the approximate minimum weighted vertex cover - function, - :func:`~networkx.algorithms.approximation.vertex_cover.min_weighted_vertex_cover`. - - """ - - def test_unweighted_directed(self): - # Create a star graph in which half the nodes are directed in - # and half are directed out. - G = nx.DiGraph() - G.add_edges_from((0, v) for v in range(1, 26)) - G.add_edges_from((v, 0) for v in range(26, 51)) - cover = min_weighted_vertex_cover(G) - assert 1 == len(cover) - assert is_cover(G, cover) - - def test_unweighted_undirected(self): - # create a simple star graph - size = 50 - sg = nx.star_graph(size) - cover = min_weighted_vertex_cover(sg) - assert 1 == len(cover) - assert is_cover(sg, cover) - - def test_weighted(self): - wg = nx.Graph() - wg.add_node(0, weight=10) - wg.add_node(1, weight=1) - wg.add_node(2, weight=1) - wg.add_node(3, weight=1) - wg.add_node(4, weight=1) - - wg.add_edge(0, 1) - wg.add_edge(0, 2) - wg.add_edge(0, 3) - wg.add_edge(0, 4) - - wg.add_edge(1, 2) - wg.add_edge(2, 3) - wg.add_edge(3, 4) - wg.add_edge(4, 1) - - cover = min_weighted_vertex_cover(wg, weight="weight") - csum = sum(wg.nodes[node]["weight"] for node in cover) - assert 4 == csum - assert is_cover(wg, cover) - - def test_unweighted_self_loop(self): - slg = nx.Graph() - slg.add_node(0) - slg.add_node(1) - slg.add_node(2) - - slg.add_edge(0, 1) - slg.add_edge(2, 2) - - cover = min_weighted_vertex_cover(slg) - assert 2 == len(cover) - assert is_cover(slg, cover) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/traveling_salesman.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/traveling_salesman.py deleted file mode 100644 index 2080c99..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/traveling_salesman.py +++ /dev/null @@ -1,1501 +0,0 @@ -""" -================================= -Travelling Salesman Problem (TSP) -================================= - -Implementation of approximate algorithms -for solving and approximating the TSP problem. - -Categories of algorithms which are implemented: - -- Christofides (provides a 3/2-approximation of TSP) -- Greedy -- Simulated Annealing (SA) -- Threshold Accepting (TA) -- Asadpour Asymmetric Traveling Salesman Algorithm - -The Travelling Salesman Problem tries to find, given the weight -(distance) between all points where a salesman has to visit, the -route so that: - -- The total distance (cost) which the salesman travels is minimized. -- The salesman returns to the starting point. -- Note that for a complete graph, the salesman visits each point once. - -The function `travelling_salesman_problem` allows for incomplete -graphs by finding all-pairs shortest paths, effectively converting -the problem to a complete graph problem. It calls one of the -approximate methods on that problem and then converts the result -back to the original graph using the previously found shortest paths. - -TSP is an NP-hard problem in combinatorial optimization, -important in operations research and theoretical computer science. - -http://en.wikipedia.org/wiki/Travelling_salesman_problem -""" - -import math - -import networkx as nx -from networkx.algorithms.tree.mst import random_spanning_tree -from networkx.utils import not_implemented_for, pairwise, py_random_state - -__all__ = [ - "traveling_salesman_problem", - "christofides", - "asadpour_atsp", - "greedy_tsp", - "simulated_annealing_tsp", - "threshold_accepting_tsp", -] - - -def swap_two_nodes(soln, seed): - """Swap two nodes in `soln` to give a neighbor solution. - - Parameters - ---------- - soln : list of nodes - Current cycle of nodes - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - list - The solution after move is applied. (A neighbor solution.) - - Notes - ----- - This function assumes that the incoming list `soln` is a cycle - (that the first and last element are the same) and also that - we don't want any move to change the first node in the list - (and thus not the last node either). - - The input list is changed as well as returned. Make a copy if needed. - - See Also - -------- - move_one_node - """ - a, b = seed.sample(range(1, len(soln) - 1), k=2) - soln[a], soln[b] = soln[b], soln[a] - return soln - - -def move_one_node(soln, seed): - """Move one node to another position to give a neighbor solution. - - The node to move and the position to move to are chosen randomly. - The first and last nodes are left untouched as soln must be a cycle - starting at that node. - - Parameters - ---------- - soln : list of nodes - Current cycle of nodes - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - list - The solution after move is applied. (A neighbor solution.) - - Notes - ----- - This function assumes that the incoming list `soln` is a cycle - (that the first and last element are the same) and also that - we don't want any move to change the first node in the list - (and thus not the last node either). - - The input list is changed as well as returned. Make a copy if needed. - - See Also - -------- - swap_two_nodes - """ - a, b = seed.sample(range(1, len(soln) - 1), k=2) - soln.insert(b, soln.pop(a)) - return soln - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def christofides(G, weight="weight", tree=None): - """Approximate a solution of the traveling salesman problem - - Compute a 3/2-approximation of the traveling salesman problem - in a complete undirected graph using Christofides [1]_ algorithm. - - Parameters - ---------- - G : Graph - `G` should be a complete weighted undirected graph. - The distance between all pairs of nodes should be included. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - tree : NetworkX graph or None (default: None) - A minimum spanning tree of G. Or, if None, the minimum spanning - tree is computed using :func:`networkx.minimum_spanning_tree` - - Returns - ------- - list - List of nodes in `G` along a cycle with a 3/2-approximation of - the minimal Hamiltonian cycle. - - References - ---------- - .. [1] Christofides, Nicos. "Worst-case analysis of a new heuristic for - the travelling salesman problem." No. RR-388. Carnegie-Mellon Univ - Pittsburgh Pa Management Sciences Research Group, 1976. - """ - # Remove selfloops if necessary - loop_nodes = nx.nodes_with_selfloops(G) - try: - node = next(loop_nodes) - except StopIteration: - pass - else: - G = G.copy() - G.remove_edge(node, node) - G.remove_edges_from((n, n) for n in loop_nodes) - # Check that G is a complete graph - N = len(G) - 1 - # This check ignores selfloops which is what we want here. - if any(len(nbrdict) != N for n, nbrdict in G.adj.items()): - raise nx.NetworkXError("G must be a complete graph.") - - if tree is None: - tree = nx.minimum_spanning_tree(G, weight=weight) - L = G.copy() - L.remove_nodes_from([v for v, degree in tree.degree if not (degree % 2)]) - MG = nx.MultiGraph() - MG.add_edges_from(tree.edges) - edges = nx.min_weight_matching(L, weight=weight) - MG.add_edges_from(edges) - return _shortcutting(nx.eulerian_circuit(MG)) - - -def _shortcutting(circuit): - """Remove duplicate nodes in the path""" - nodes = [] - for u, v in circuit: - if v in nodes: - continue - if not nodes: - nodes.append(u) - nodes.append(v) - nodes.append(nodes[0]) - return nodes - - -@nx._dispatchable(edge_attrs="weight") -def traveling_salesman_problem( - G, weight="weight", nodes=None, cycle=True, method=None, **kwargs -): - """Find the shortest path in `G` connecting specified nodes - - This function allows approximate solution to the traveling salesman - problem on networks that are not complete graphs and/or where the - salesman does not need to visit all nodes. - - This function proceeds in two steps. First, it creates a complete - graph using the all-pairs shortest_paths between nodes in `nodes`. - Edge weights in the new graph are the lengths of the paths - between each pair of nodes in the original graph. - Second, an algorithm (default: `christofides` for undirected and - `asadpour_atsp` for directed) is used to approximate the minimal Hamiltonian - cycle on this new graph. The available algorithms are: - - - christofides - - greedy_tsp - - simulated_annealing_tsp - - threshold_accepting_tsp - - asadpour_atsp - - Once the Hamiltonian Cycle is found, this function post-processes to - accommodate the structure of the original graph. If `cycle` is ``False``, - the biggest weight edge is removed to make a Hamiltonian path. - Then each edge on the new complete graph used for that analysis is - replaced by the shortest_path between those nodes on the original graph. - If the input graph `G` includes edges with weights that do not adhere to - the triangle inequality, such as when `G` is not a complete graph (i.e - length of non-existent edges is infinity), then the returned path may - contain some repeating nodes (other than the starting node). - - Parameters - ---------- - G : NetworkX graph - A possibly weighted graph - - nodes : collection of nodes (default=G.nodes) - collection (list, set, etc.) of nodes to visit - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - cycle : bool (default: True) - Indicates whether a cycle should be returned, or a path. - Note: the cycle is the approximate minimal cycle. - The path simply removes the biggest edge in that cycle. - - method : function (default: None) - A function that returns a cycle on all nodes and approximates - the solution to the traveling salesman problem on a complete - graph. The returned cycle is then used to find a corresponding - solution on `G`. `method` should be callable; take inputs - `G`, and `weight`; and return a list of nodes along the cycle. - - Provided options include :func:`christofides`, :func:`greedy_tsp`, - :func:`simulated_annealing_tsp` and :func:`threshold_accepting_tsp`. - - If `method is None`: use :func:`christofides` for undirected `G` and - :func:`asadpour_atsp` for directed `G`. - - **kwargs : dict - Other keyword arguments to be passed to the `method` function passed in. - - Returns - ------- - list - List of nodes in `G` along a path with an approximation of the minimal - path through `nodes`. - - Raises - ------ - NetworkXError - If `G` is a directed graph it has to be strongly connected or the - complete version cannot be generated. - - Examples - -------- - >>> tsp = nx.approximation.traveling_salesman_problem - >>> G = nx.cycle_graph(9) - >>> G[4][5]["weight"] = 5 # all other weights are 1 - >>> tsp(G, nodes=[3, 6]) - [3, 2, 1, 0, 8, 7, 6, 7, 8, 0, 1, 2, 3] - >>> path = tsp(G, cycle=False) - >>> path in ([4, 3, 2, 1, 0, 8, 7, 6, 5], [5, 6, 7, 8, 0, 1, 2, 3, 4]) - True - - While no longer required, you can still build (curry) your own function - to provide parameter values to the methods. - - >>> SA_tsp = nx.approximation.simulated_annealing_tsp - >>> method = lambda G, weight: SA_tsp(G, "greedy", weight=weight, temp=500) - >>> path = tsp(G, cycle=False, method=method) - >>> path in ([4, 3, 2, 1, 0, 8, 7, 6, 5], [5, 6, 7, 8, 0, 1, 2, 3, 4]) - True - - Otherwise, pass other keyword arguments directly into the tsp function. - - >>> path = tsp( - ... G, - ... cycle=False, - ... method=nx.approximation.simulated_annealing_tsp, - ... init_cycle="greedy", - ... temp=500, - ... ) - >>> path in ([4, 3, 2, 1, 0, 8, 7, 6, 5], [5, 6, 7, 8, 0, 1, 2, 3, 4]) - True - """ - if method is None: - if G.is_directed(): - method = asadpour_atsp - else: - method = christofides - if nodes is None: - nodes = list(G.nodes) - - dist = {} - path = {} - for n, (d, p) in nx.all_pairs_dijkstra(G, weight=weight): - dist[n] = d - path[n] = p - - if G.is_directed(): - # If the graph is not strongly connected, raise an exception - if not nx.is_strongly_connected(G): - raise nx.NetworkXError("G is not strongly connected") - GG = nx.DiGraph() - else: - GG = nx.Graph() - for u in nodes: - for v in nodes: - if u == v: - continue - GG.add_edge(u, v, weight=dist[u][v]) - - best_GG = method(GG, weight=weight, **kwargs) - - if not cycle: - # find and remove the biggest edge - (u, v) = max(pairwise(best_GG), key=lambda x: dist[x[0]][x[1]]) - pos = best_GG.index(u) + 1 - while best_GG[pos] != v: - pos = best_GG[pos:].index(u) + 1 - best_GG = best_GG[pos:-1] + best_GG[:pos] - - best_path = [] - for u, v in pairwise(best_GG): - best_path.extend(path[u][v][:-1]) - best_path.append(v) - return best_path - - -@not_implemented_for("undirected") -@py_random_state(2) -@nx._dispatchable(edge_attrs="weight", mutates_input=True) -def asadpour_atsp(G, weight="weight", seed=None, source=None): - """ - Returns an approximate solution to the traveling salesman problem. - - This approximate solution is one of the best known approximations for the - asymmetric traveling salesman problem developed by Asadpour et al, - [1]_. The algorithm first solves the Held-Karp relaxation to find a lower - bound for the weight of the cycle. Next, it constructs an exponential - distribution of undirected spanning trees where the probability of an - edge being in the tree corresponds to the weight of that edge using a - maximum entropy rounding scheme. Next we sample that distribution - $2 \\lceil \\ln n \\rceil$ times and save the minimum sampled tree once the - direction of the arcs is added back to the edges. Finally, we augment - then short circuit that graph to find the approximate tour for the - salesman. - - Parameters - ---------- - G : nx.DiGraph - The graph should be a complete weighted directed graph. The - distance between all paris of nodes should be included and the triangle - inequality should hold. That is, the direct edge between any two nodes - should be the path of least cost. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - source : node label (default=`None`) - If given, return the cycle starting and ending at the given node. - - Returns - ------- - cycle : list of nodes - Returns the cycle (list of nodes) that a salesman can follow to minimize - the total weight of the trip. - - Raises - ------ - NetworkXError - If `G` is not complete or has less than two nodes, the algorithm raises - an exception. - - NetworkXError - If `source` is not `None` and is not a node in `G`, the algorithm raises - an exception. - - NetworkXNotImplemented - If `G` is an undirected graph. - - References - ---------- - .. [1] A. Asadpour, M. X. Goemans, A. Madry, S. O. Gharan, and A. Saberi, - An o(log n/log log n)-approximation algorithm for the asymmetric - traveling salesman problem, Operations research, 65 (2017), - pp. 1043–1061 - - Examples - -------- - >>> import networkx as nx - >>> import networkx.algorithms.approximation as approx - >>> G = nx.complete_graph(3, create_using=nx.DiGraph) - >>> nx.set_edge_attributes( - ... G, - ... {(0, 1): 2, (1, 2): 2, (2, 0): 2, (0, 2): 1, (2, 1): 1, (1, 0): 1}, - ... "weight", - ... ) - >>> tour = approx.asadpour_atsp(G, source=0) - >>> tour - [0, 2, 1, 0] - """ - from math import ceil, exp - from math import log as ln - - # Check that G is a complete graph - N = len(G) - 1 - if N < 2: - raise nx.NetworkXError("G must have at least two nodes") - # This check ignores selfloops which is what we want here. - if any(len(nbrdict) - (n in nbrdict) != N for n, nbrdict in G.adj.items()): - raise nx.NetworkXError("G is not a complete DiGraph") - # Check that the source vertex, if given, is in the graph - if source is not None and source not in G.nodes: - raise nx.NetworkXError("Given source node not in G.") - - opt_hk, z_star = held_karp_ascent(G, weight) - - # Test to see if the ascent method found an integer solution or a fractional - # solution. If it is integral then z_star is a nx.Graph, otherwise it is - # a dict - if not isinstance(z_star, dict): - # Here we are using the shortcutting method to go from the list of edges - # returned from eulerian_circuit to a list of nodes - return _shortcutting(nx.eulerian_circuit(z_star, source=source)) - - # Create the undirected support of z_star - z_support = nx.MultiGraph() - for u, v in z_star: - if (u, v) not in z_support.edges: - edge_weight = min(G[u][v][weight], G[v][u][weight]) - z_support.add_edge(u, v, **{weight: edge_weight}) - - # Create the exponential distribution of spanning trees - gamma = spanning_tree_distribution(z_support, z_star) - - # Write the lambda values to the edges of z_support - z_support = nx.Graph(z_support) - lambda_dict = {(u, v): exp(gamma[(u, v)]) for u, v in z_support.edges()} - nx.set_edge_attributes(z_support, lambda_dict, "weight") - del gamma, lambda_dict - - # Sample 2 * ceil( ln(n) ) spanning trees and record the minimum one - minimum_sampled_tree = None - minimum_sampled_tree_weight = math.inf - for _ in range(2 * ceil(ln(G.number_of_nodes()))): - sampled_tree = random_spanning_tree(z_support, "weight", seed=seed) - sampled_tree_weight = sampled_tree.size(weight) - if sampled_tree_weight < minimum_sampled_tree_weight: - minimum_sampled_tree = sampled_tree.copy() - minimum_sampled_tree_weight = sampled_tree_weight - - # Orient the edges in that tree to keep the cost of the tree the same. - t_star = nx.MultiDiGraph() - for u, v, d in minimum_sampled_tree.edges(data=weight): - if d == G[u][v][weight]: - t_star.add_edge(u, v, **{weight: d}) - else: - t_star.add_edge(v, u, **{weight: d}) - - # Find the node demands needed to neutralize the flow of t_star in G - node_demands = {n: t_star.out_degree(n) - t_star.in_degree(n) for n in t_star} - nx.set_node_attributes(G, node_demands, "demand") - - # Find the min_cost_flow - flow_dict = nx.min_cost_flow(G, "demand") - - # Build the flow into t_star - for source, values in flow_dict.items(): - for target in values: - if (source, target) not in t_star.edges and values[target] > 0: - # IF values[target] > 0 we have to add that many edges - for _ in range(values[target]): - t_star.add_edge(source, target) - - # Return the shortcut eulerian circuit - circuit = nx.eulerian_circuit(t_star, source=source) - return _shortcutting(circuit) - - -@nx._dispatchable(edge_attrs="weight", mutates_input=True, returns_graph=True) -def held_karp_ascent(G, weight="weight"): - """ - Minimizes the Held-Karp relaxation of the TSP for `G` - - Solves the Held-Karp relaxation of the input complete digraph and scales - the output solution for use in the Asadpour [1]_ ASTP algorithm. - - The Held-Karp relaxation defines the lower bound for solutions to the - ATSP, although it does return a fractional solution. This is used in the - Asadpour algorithm as an initial solution which is later rounded to a - integral tree within the spanning tree polytopes. This function solves - the relaxation with the branch and bound method in [2]_. - - Parameters - ---------- - G : nx.DiGraph - The graph should be a complete weighted directed graph. - The distance between all paris of nodes should be included. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - Returns - ------- - OPT : float - The cost for the optimal solution to the Held-Karp relaxation - z : dict or nx.Graph - A symmetrized and scaled version of the optimal solution to the - Held-Karp relaxation for use in the Asadpour algorithm. - - If an integral solution is found, then that is an optimal solution for - the ATSP problem and that is returned instead. - - References - ---------- - .. [1] A. Asadpour, M. X. Goemans, A. Madry, S. O. Gharan, and A. Saberi, - An o(log n/log log n)-approximation algorithm for the asymmetric - traveling salesman problem, Operations research, 65 (2017), - pp. 1043–1061 - - .. [2] M. Held, R. M. Karp, The traveling-salesman problem and minimum - spanning trees, Operations Research, 1970-11-01, Vol. 18 (6), - pp.1138-1162 - """ - import numpy as np - from scipy import optimize - - def k_pi(): - """ - Find the set of minimum 1-Arborescences for G at point pi. - - Returns - ------- - Set - The set of minimum 1-Arborescences - """ - # Create a copy of G without vertex 1. - G_1 = G.copy() - minimum_1_arborescences = set() - minimum_1_arborescence_weight = math.inf - - # node is node '1' in the Held and Karp paper - n = next(G.__iter__()) - G_1.remove_node(n) - - # Iterate over the spanning arborescences of the graph until we know - # that we have found the minimum 1-arborescences. My proposed strategy - # is to find the most extensive root to connect to from 'node 1' and - # the least expensive one. We then iterate over arborescences until - # the cost of the basic arborescence is the cost of the minimum one - # plus the difference between the most and least expensive roots, - # that way the cost of connecting 'node 1' will by definition not by - # minimum - min_root = {"node": None, weight: math.inf} - max_root = {"node": None, weight: -math.inf} - for u, v, d in G.edges(n, data=True): - if d[weight] < min_root[weight]: - min_root = {"node": v, weight: d[weight]} - if d[weight] > max_root[weight]: - max_root = {"node": v, weight: d[weight]} - - min_in_edge = min(G.in_edges(n, data=True), key=lambda x: x[2][weight]) - min_root[weight] = min_root[weight] + min_in_edge[2][weight] - max_root[weight] = max_root[weight] + min_in_edge[2][weight] - - min_arb_weight = math.inf - for arb in nx.ArborescenceIterator(G_1): - arb_weight = arb.size(weight) - if min_arb_weight == math.inf: - min_arb_weight = arb_weight - elif arb_weight > min_arb_weight + max_root[weight] - min_root[weight]: - break - # We have to pick the root node of the arborescence for the out - # edge of the first vertex as that is the only node without an - # edge directed into it. - for N, deg in arb.in_degree: - if deg == 0: - # root found - arb.add_edge(n, N, **{weight: G[n][N][weight]}) - arb_weight += G[n][N][weight] - break - - # We can pick the minimum weight in-edge for the vertex with - # a cycle. If there are multiple edges with the same, minimum - # weight, We need to add all of them. - # - # Delete the edge (N, v) so that we cannot pick it. - edge_data = G[N][n] - G.remove_edge(N, n) - min_weight = min(G.in_edges(n, data=weight), key=lambda x: x[2])[2] - min_edges = [ - (u, v, d) for u, v, d in G.in_edges(n, data=weight) if d == min_weight - ] - for u, v, d in min_edges: - new_arb = arb.copy() - new_arb.add_edge(u, v, **{weight: d}) - new_arb_weight = arb_weight + d - # Check to see the weight of the arborescence, if it is a - # new minimum, clear all of the old potential minimum - # 1-arborescences and add this is the only one. If its - # weight is above the known minimum, do not add it. - if new_arb_weight < minimum_1_arborescence_weight: - minimum_1_arborescences.clear() - minimum_1_arborescence_weight = new_arb_weight - # We have a 1-arborescence, add it to the set - if new_arb_weight == minimum_1_arborescence_weight: - minimum_1_arborescences.add(new_arb) - G.add_edge(N, n, **edge_data) - - return minimum_1_arborescences - - def direction_of_ascent(): - """ - Find the direction of ascent at point pi. - - See [1]_ for more information. - - Returns - ------- - dict - A mapping from the nodes of the graph which represents the direction - of ascent. - - References - ---------- - .. [1] M. Held, R. M. Karp, The traveling-salesman problem and minimum - spanning trees, Operations Research, 1970-11-01, Vol. 18 (6), - pp.1138-1162 - """ - # 1. Set d equal to the zero n-vector. - d = {} - for n in G: - d[n] = 0 - del n - # 2. Find a 1-Arborescence T^k such that k is in K(pi, d). - minimum_1_arborescences = k_pi() - while True: - # Reduce K(pi) to K(pi, d) - # Find the arborescence in K(pi) which increases the lest in - # direction d - min_k_d_weight = math.inf - min_k_d = None - for arborescence in minimum_1_arborescences: - weighted_cost = 0 - for n, deg in arborescence.degree: - weighted_cost += d[n] * (deg - 2) - if weighted_cost < min_k_d_weight: - min_k_d_weight = weighted_cost - min_k_d = arborescence - - # 3. If sum of d_i * v_{i, k} is greater than zero, terminate - if min_k_d_weight > 0: - return d, min_k_d - # 4. d_i = d_i + v_{i, k} - for n, deg in min_k_d.degree: - d[n] += deg - 2 - # Check that we do not need to terminate because the direction - # of ascent does not exist. This is done with linear - # programming. - c = np.full(len(minimum_1_arborescences), -1, dtype=int) - a_eq = np.empty((len(G) + 1, len(minimum_1_arborescences)), dtype=int) - b_eq = np.zeros(len(G) + 1, dtype=int) - b_eq[len(G)] = 1 - for arb_count, arborescence in enumerate(minimum_1_arborescences): - n_count = len(G) - 1 - for n, deg in arborescence.degree: - a_eq[n_count][arb_count] = deg - 2 - n_count -= 1 - a_eq[len(G)][arb_count] = 1 - program_result = optimize.linprog( - c, A_eq=a_eq, b_eq=b_eq, method="highs-ipm" - ) - # If the constants exist, then the direction of ascent doesn't - if program_result.success: - # There is no direction of ascent - return None, minimum_1_arborescences - - # 5. GO TO 2 - - def find_epsilon(k, d): - """ - Given the direction of ascent at pi, find the maximum distance we can go - in that direction. - - Parameters - ---------- - k_xy : set - The set of 1-arborescences which have the minimum rate of increase - in the direction of ascent - - d : dict - The direction of ascent - - Returns - ------- - float - The distance we can travel in direction `d` - """ - min_epsilon = math.inf - for e_u, e_v, e_w in G.edges(data=weight): - if (e_u, e_v) in k.edges: - continue - # Now, I have found a condition which MUST be true for the edges to - # be a valid substitute. The edge in the graph which is the - # substitute is the one with the same terminated end. This can be - # checked rather simply. - # - # Find the edge within k which is the substitute. Because k is a - # 1-arborescence, we know that they is only one such edges - # leading into every vertex. - if len(k.in_edges(e_v, data=weight)) > 1: - raise Exception - sub_u, sub_v, sub_w = next(k.in_edges(e_v, data=weight).__iter__()) - k.add_edge(e_u, e_v, **{weight: e_w}) - k.remove_edge(sub_u, sub_v) - if ( - max(d for n, d in k.in_degree()) <= 1 - and len(G) == k.number_of_edges() - and nx.is_weakly_connected(k) - ): - # Ascent method calculation - if d[sub_u] == d[e_u] or sub_w == e_w: - # Revert to the original graph - k.remove_edge(e_u, e_v) - k.add_edge(sub_u, sub_v, **{weight: sub_w}) - continue - epsilon = (sub_w - e_w) / (d[e_u] - d[sub_u]) - if 0 < epsilon < min_epsilon: - min_epsilon = epsilon - # Revert to the original graph - k.remove_edge(e_u, e_v) - k.add_edge(sub_u, sub_v, **{weight: sub_w}) - - return min_epsilon - - # I have to know that the elements in pi correspond to the correct elements - # in the direction of ascent, even if the node labels are not integers. - # Thus, I will use dictionaries to made that mapping. - pi_dict = {} - for n in G: - pi_dict[n] = 0 - del n - original_edge_weights = {} - for u, v, d in G.edges(data=True): - original_edge_weights[(u, v)] = d[weight] - dir_ascent, k_d = direction_of_ascent() - while dir_ascent is not None: - max_distance = find_epsilon(k_d, dir_ascent) - for n, v in dir_ascent.items(): - pi_dict[n] += max_distance * v - for u, v, d in G.edges(data=True): - d[weight] = original_edge_weights[(u, v)] + pi_dict[u] - dir_ascent, k_d = direction_of_ascent() - nx._clear_cache(G) - # k_d is no longer an individual 1-arborescence but rather a set of - # minimal 1-arborescences at the maximum point of the polytope and should - # be reflected as such - k_max = k_d - - # Search for a cycle within k_max. If a cycle exists, return it as the - # solution - for k in k_max: - if len([n for n in k if k.degree(n) == 2]) == G.order(): - # Tour found - # TODO: this branch does not restore original_edge_weights of G! - return k.size(weight), k - - # Write the original edge weights back to G and every member of k_max at - # the maximum point. Also average the number of times that edge appears in - # the set of minimal 1-arborescences. - x_star = {} - size_k_max = len(k_max) - for u, v, d in G.edges(data=True): - edge_count = 0 - d[weight] = original_edge_weights[(u, v)] - for k in k_max: - if (u, v) in k.edges(): - edge_count += 1 - k[u][v][weight] = original_edge_weights[(u, v)] - x_star[(u, v)] = edge_count / size_k_max - # Now symmetrize the edges in x_star and scale them according to (5) in - # reference [1] - z_star = {} - scale_factor = (G.order() - 1) / G.order() - for u, v in x_star: - frequency = x_star[(u, v)] + x_star[(v, u)] - if frequency > 0: - z_star[(u, v)] = scale_factor * frequency - del x_star - # Return the optimal weight and the z dict - return next(k_max.__iter__()).size(weight), z_star - - -@nx._dispatchable -def spanning_tree_distribution(G, z): - """ - Find the asadpour exponential distribution of spanning trees. - - Solves the Maximum Entropy Convex Program in the Asadpour algorithm [1]_ - using the approach in section 7 to build an exponential distribution of - undirected spanning trees. - - This algorithm ensures that the probability of any edge in a spanning - tree is proportional to the sum of the probabilities of the tress - containing that edge over the sum of the probabilities of all spanning - trees of the graph. - - Parameters - ---------- - G : nx.MultiGraph - The undirected support graph for the Held Karp relaxation - - z : dict - The output of `held_karp_ascent()`, a scaled version of the Held-Karp - solution. - - Returns - ------- - gamma : dict - The probability distribution which approximately preserves the marginal - probabilities of `z`. - """ - from math import exp - from math import log as ln - - def q(e): - """ - The value of q(e) is described in the Asadpour paper is "the - probability that edge e will be included in a spanning tree T that is - chosen with probability proportional to exp(gamma(T))" which - basically means that it is the total probability of the edge appearing - across the whole distribution. - - Parameters - ---------- - e : tuple - The `(u, v)` tuple describing the edge we are interested in - - Returns - ------- - float - The probability that a spanning tree chosen according to the - current values of gamma will include edge `e`. - """ - # Create the laplacian matrices - for u, v, d in G.edges(data=True): - d[lambda_key] = exp(gamma[(u, v)]) - G_Kirchhoff = nx.total_spanning_tree_weight(G, lambda_key) - G_e = nx.contracted_edge(G, e, self_loops=False) - G_e_Kirchhoff = nx.total_spanning_tree_weight(G_e, lambda_key) - - # Multiply by the weight of the contracted edge since it is not included - # in the total weight of the contracted graph. - return exp(gamma[(e[0], e[1])]) * G_e_Kirchhoff / G_Kirchhoff - - # initialize gamma to the zero dict - gamma = {} - for u, v, _ in G.edges: - gamma[(u, v)] = 0 - - # set epsilon - EPSILON = 0.2 - - # pick an edge attribute name that is unlikely to be in the graph - lambda_key = "spanning_tree_distribution's secret attribute name for lambda" - - while True: - # We need to know that know that no values of q_e are greater than - # (1 + epsilon) * z_e, however changing one gamma value can increase the - # value of a different q_e, so we have to complete the for loop without - # changing anything for the condition to be meet - in_range_count = 0 - # Search for an edge with q_e > (1 + epsilon) * z_e - for u, v in gamma: - e = (u, v) - q_e = q(e) - z_e = z[e] - if q_e > (1 + EPSILON) * z_e: - delta = ln( - (q_e * (1 - (1 + EPSILON / 2) * z_e)) - / ((1 - q_e) * (1 + EPSILON / 2) * z_e) - ) - gamma[e] -= delta - # Check that delta had the desired effect - new_q_e = q(e) - desired_q_e = (1 + EPSILON / 2) * z_e - if round(new_q_e, 8) != round(desired_q_e, 8): - raise nx.NetworkXError( - f"Unable to modify probability for edge ({u}, {v})" - ) - else: - in_range_count += 1 - # Check if the for loop terminated without changing any gamma - if in_range_count == len(gamma): - break - - # Remove the new edge attributes - for _, _, d in G.edges(data=True): - if lambda_key in d: - del d[lambda_key] - - return gamma - - -@nx._dispatchable(edge_attrs="weight") -def greedy_tsp(G, weight="weight", source=None): - """Return a low cost cycle starting at `source` and its cost. - - This approximates a solution to the traveling salesman problem. - It finds a cycle of all the nodes that a salesman can visit in order - to visit many nodes while minimizing total distance. - It uses a simple greedy algorithm. - In essence, this function returns a large cycle given a source point - for which the total cost of the cycle is minimized. - - Parameters - ---------- - G : Graph - The Graph should be a complete weighted undirected graph. - The distance between all pairs of nodes should be included. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - source : node, optional (default: first node in list(G)) - Starting node. If None, defaults to ``next(iter(G))`` - - Returns - ------- - cycle : list of nodes - Returns the cycle (list of nodes) that a salesman - can follow to minimize total weight of the trip. - - Raises - ------ - NetworkXError - If `G` is not complete, the algorithm raises an exception. - - Examples - -------- - >>> from networkx.algorithms import approximation as approx - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... { - ... ("A", "B", 3), - ... ("A", "C", 17), - ... ("A", "D", 14), - ... ("B", "A", 3), - ... ("B", "C", 12), - ... ("B", "D", 16), - ... ("C", "A", 13), - ... ("C", "B", 12), - ... ("C", "D", 4), - ... ("D", "A", 14), - ... ("D", "B", 15), - ... ("D", "C", 2), - ... } - ... ) - >>> cycle = approx.greedy_tsp(G, source="D") - >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) - >>> cycle - ['D', 'C', 'B', 'A', 'D'] - >>> cost - 31 - - Notes - ----- - This implementation of a greedy algorithm is based on the following: - - - The algorithm adds a node to the solution at every iteration. - - The algorithm selects a node not already in the cycle whose connection - to the previous node adds the least cost to the cycle. - - A greedy algorithm does not always give the best solution. - However, it can construct a first feasible solution which can - be passed as a parameter to an iterative improvement algorithm such - as Simulated Annealing, or Threshold Accepting. - - Time complexity: It has a running time $O(|V|^2)$ - """ - # Check that G is a complete graph - N = len(G) - 1 - # This check ignores selfloops which is what we want here. - if any(len(nbrdict) - (n in nbrdict) != N for n, nbrdict in G.adj.items()): - raise nx.NetworkXError("G must be a complete graph.") - - if source is None: - source = nx.utils.arbitrary_element(G) - - if G.number_of_nodes() == 2: - neighbor = next(G.neighbors(source)) - return [source, neighbor, source] - - nodeset = set(G) - nodeset.remove(source) - cycle = [source] - next_node = source - while nodeset: - nbrdict = G[next_node] - next_node = min(nodeset, key=lambda n: nbrdict[n].get(weight, 1)) - cycle.append(next_node) - nodeset.remove(next_node) - cycle.append(cycle[0]) - return cycle - - -@py_random_state(9) -@nx._dispatchable(edge_attrs="weight") -def simulated_annealing_tsp( - G, - init_cycle, - weight="weight", - source=None, - temp=100, - move="1-1", - max_iterations=10, - N_inner=100, - alpha=0.01, - seed=None, -): - """Returns an approximate solution to the traveling salesman problem. - - This function uses simulated annealing to approximate the minimal cost - cycle through the nodes. Starting from a suboptimal solution, simulated - annealing perturbs that solution, occasionally accepting changes that make - the solution worse to escape from a locally optimal solution. The chance - of accepting such changes decreases over the iterations to encourage - an optimal result. In summary, the function returns a cycle starting - at `source` for which the total cost is minimized. It also returns the cost. - - The chance of accepting a proposed change is related to a parameter called - the temperature (annealing has a physical analogue of steel hardening - as it cools). As the temperature is reduced, the chance of moves that - increase cost goes down. - - Parameters - ---------- - G : Graph - `G` should be a complete weighted graph. - The distance between all pairs of nodes should be included. - - init_cycle : list of all nodes or "greedy" - The initial solution (a cycle through all nodes returning to the start). - This argument has no default to make you think about it. - If "greedy", use `greedy_tsp(G, weight)`. - Other common starting cycles are `list(G) + [next(iter(G))]` or the final - result of `simulated_annealing_tsp` when doing `threshold_accepting_tsp`. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - source : node, optional (default: first node in list(G)) - Starting node. If None, defaults to ``next(iter(G))`` - - temp : int, optional (default=100) - The algorithm's temperature parameter. It represents the initial - value of temperature - - move : "1-1" or "1-0" or function, optional (default="1-1") - Indicator of what move to use when finding new trial solutions. - Strings indicate two special built-in moves: - - - "1-1": 1-1 exchange which transposes the position - of two elements of the current solution. - The function called is :func:`swap_two_nodes`. - For example if we apply 1-1 exchange in the solution - ``A = [3, 2, 1, 4, 3]`` - we can get the following by the transposition of 1 and 4 elements: - ``A' = [3, 2, 4, 1, 3]`` - - "1-0": 1-0 exchange which moves an node in the solution - to a new position. - The function called is :func:`move_one_node`. - For example if we apply 1-0 exchange in the solution - ``A = [3, 2, 1, 4, 3]`` - we can transfer the fourth element to the second position: - ``A' = [3, 4, 2, 1, 3]`` - - You may provide your own functions to enact a move from - one solution to a neighbor solution. The function must take - the solution as input along with a `seed` input to control - random number generation (see the `seed` input here). - Your function should maintain the solution as a cycle with - equal first and last node and all others appearing once. - Your function should return the new solution. - - max_iterations : int, optional (default=10) - Declared done when this number of consecutive iterations of - the outer loop occurs without any change in the best cost solution. - - N_inner : int, optional (default=100) - The number of iterations of the inner loop. - - alpha : float between (0, 1), optional (default=0.01) - Percentage of temperature decrease in each iteration - of outer loop - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - cycle : list of nodes - Returns the cycle (list of nodes) that a salesman - can follow to minimize total weight of the trip. - - Raises - ------ - NetworkXError - If `G` is not complete the algorithm raises an exception. - - Examples - -------- - >>> from networkx.algorithms import approximation as approx - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... { - ... ("A", "B", 3), - ... ("A", "C", 17), - ... ("A", "D", 14), - ... ("B", "A", 3), - ... ("B", "C", 12), - ... ("B", "D", 16), - ... ("C", "A", 13), - ... ("C", "B", 12), - ... ("C", "D", 4), - ... ("D", "A", 14), - ... ("D", "B", 15), - ... ("D", "C", 2), - ... } - ... ) - >>> cycle = approx.simulated_annealing_tsp(G, "greedy", source="D") - >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) - >>> cycle - ['D', 'C', 'B', 'A', 'D'] - >>> cost - 31 - >>> incycle = ["D", "B", "A", "C", "D"] - >>> cycle = approx.simulated_annealing_tsp(G, incycle, source="D") - >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) - >>> cycle - ['D', 'C', 'B', 'A', 'D'] - >>> cost - 31 - - Notes - ----- - Simulated Annealing is a metaheuristic local search algorithm. - The main characteristic of this algorithm is that it accepts - even solutions which lead to the increase of the cost in order - to escape from low quality local optimal solutions. - - This algorithm needs an initial solution. If not provided, it is - constructed by a simple greedy algorithm. At every iteration, the - algorithm selects thoughtfully a neighbor solution. - Consider $c(x)$ cost of current solution and $c(x')$ cost of a - neighbor solution. - If $c(x') - c(x) <= 0$ then the neighbor solution becomes the current - solution for the next iteration. Otherwise, the algorithm accepts - the neighbor solution with probability $p = exp - ([c(x') - c(x)] / temp)$. - Otherwise the current solution is retained. - - `temp` is a parameter of the algorithm and represents temperature. - - Time complexity: - For $N_i$ iterations of the inner loop and $N_o$ iterations of the - outer loop, this algorithm has running time $O(N_i * N_o * |V|)$. - - For more information and how the algorithm is inspired see: - http://en.wikipedia.org/wiki/Simulated_annealing - """ - if move == "1-1": - move = swap_two_nodes - elif move == "1-0": - move = move_one_node - if init_cycle == "greedy": - # Construct an initial solution using a greedy algorithm. - cycle = greedy_tsp(G, weight=weight, source=source) - if G.number_of_nodes() == 2: - return cycle - - else: - cycle = list(init_cycle) - if source is None: - source = cycle[0] - elif source != cycle[0]: - raise nx.NetworkXError("source must be first node in init_cycle") - if cycle[0] != cycle[-1]: - raise nx.NetworkXError("init_cycle must be a cycle. (return to start)") - - if len(cycle) - 1 != len(G) or len(set(G.nbunch_iter(cycle))) != len(G): - raise nx.NetworkXError("init_cycle should be a cycle over all nodes in G.") - - # Check that G is a complete graph - N = len(G) - 1 - # This check ignores selfloops which is what we want here. - if any(len(nbrdict) - (n in nbrdict) != N for n, nbrdict in G.adj.items()): - raise nx.NetworkXError("G must be a complete graph.") - - if G.number_of_nodes() == 2: - neighbor = next(G.neighbors(source)) - return [source, neighbor, source] - - # Find the cost of initial solution - cost = sum(G[u][v].get(weight, 1) for u, v in pairwise(cycle)) - - count = 0 - best_cycle = cycle.copy() - best_cost = cost - while count <= max_iterations and temp > 0: - count += 1 - for i in range(N_inner): - adj_sol = move(cycle, seed) - adj_cost = sum(G[u][v].get(weight, 1) for u, v in pairwise(adj_sol)) - delta = adj_cost - cost - if delta <= 0: - # Set current solution the adjacent solution. - cycle = adj_sol - cost = adj_cost - - if cost < best_cost: - count = 0 - best_cycle = cycle.copy() - best_cost = cost - else: - # Accept even a worse solution with probability p. - p = math.exp(-delta / temp) - if p >= seed.random(): - cycle = adj_sol - cost = adj_cost - temp -= temp * alpha - - return best_cycle - - -@py_random_state(9) -@nx._dispatchable(edge_attrs="weight") -def threshold_accepting_tsp( - G, - init_cycle, - weight="weight", - source=None, - threshold=1, - move="1-1", - max_iterations=10, - N_inner=100, - alpha=0.1, - seed=None, -): - """Returns an approximate solution to the traveling salesman problem. - - This function uses threshold accepting methods to approximate the minimal cost - cycle through the nodes. Starting from a suboptimal solution, threshold - accepting methods perturb that solution, accepting any changes that make - the solution no worse than increasing by a threshold amount. Improvements - in cost are accepted, but so are changes leading to small increases in cost. - This allows the solution to leave suboptimal local minima in solution space. - The threshold is decreased slowly as iterations proceed helping to ensure - an optimum. In summary, the function returns a cycle starting at `source` - for which the total cost is minimized. - - Parameters - ---------- - G : Graph - `G` should be a complete weighted graph. - The distance between all pairs of nodes should be included. - - init_cycle : list or "greedy" - The initial solution (a cycle through all nodes returning to the start). - This argument has no default to make you think about it. - If "greedy", use `greedy_tsp(G, weight)`. - Other common starting cycles are `list(G) + [next(iter(G))]` or the final - result of `simulated_annealing_tsp` when doing `threshold_accepting_tsp`. - - weight : string, optional (default="weight") - Edge data key corresponding to the edge weight. - If any edge does not have this attribute the weight is set to 1. - - source : node, optional (default: first node in list(G)) - Starting node. If None, defaults to ``next(iter(G))`` - - threshold : int, optional (default=1) - The algorithm's threshold parameter. It represents the initial - threshold's value - - move : "1-1" or "1-0" or function, optional (default="1-1") - Indicator of what move to use when finding new trial solutions. - Strings indicate two special built-in moves: - - - "1-1": 1-1 exchange which transposes the position - of two elements of the current solution. - The function called is :func:`swap_two_nodes`. - For example if we apply 1-1 exchange in the solution - ``A = [3, 2, 1, 4, 3]`` - we can get the following by the transposition of 1 and 4 elements: - ``A' = [3, 2, 4, 1, 3]`` - - "1-0": 1-0 exchange which moves an node in the solution - to a new position. - The function called is :func:`move_one_node`. - For example if we apply 1-0 exchange in the solution - ``A = [3, 2, 1, 4, 3]`` - we can transfer the fourth element to the second position: - ``A' = [3, 4, 2, 1, 3]`` - - You may provide your own functions to enact a move from - one solution to a neighbor solution. The function must take - the solution as input along with a `seed` input to control - random number generation (see the `seed` input here). - Your function should maintain the solution as a cycle with - equal first and last node and all others appearing once. - Your function should return the new solution. - - max_iterations : int, optional (default=10) - Declared done when this number of consecutive iterations of - the outer loop occurs without any change in the best cost solution. - - N_inner : int, optional (default=100) - The number of iterations of the inner loop. - - alpha : float between (0, 1), optional (default=0.1) - Percentage of threshold decrease when there is at - least one acceptance of a neighbor solution. - If no inner loop moves are accepted the threshold remains unchanged. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - cycle : list of nodes - Returns the cycle (list of nodes) that a salesman - can follow to minimize total weight of the trip. - - Raises - ------ - NetworkXError - If `G` is not complete the algorithm raises an exception. - - Examples - -------- - >>> from networkx.algorithms import approximation as approx - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... { - ... ("A", "B", 3), - ... ("A", "C", 17), - ... ("A", "D", 14), - ... ("B", "A", 3), - ... ("B", "C", 12), - ... ("B", "D", 16), - ... ("C", "A", 13), - ... ("C", "B", 12), - ... ("C", "D", 4), - ... ("D", "A", 14), - ... ("D", "B", 15), - ... ("D", "C", 2), - ... } - ... ) - >>> cycle = approx.threshold_accepting_tsp(G, "greedy", source="D") - >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) - >>> cycle - ['D', 'C', 'B', 'A', 'D'] - >>> cost - 31 - >>> incycle = ["D", "B", "A", "C", "D"] - >>> cycle = approx.threshold_accepting_tsp(G, incycle, source="D") - >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) - >>> cycle - ['D', 'C', 'B', 'A', 'D'] - >>> cost - 31 - - Notes - ----- - Threshold Accepting is a metaheuristic local search algorithm. - The main characteristic of this algorithm is that it accepts - even solutions which lead to the increase of the cost in order - to escape from low quality local optimal solutions. - - This algorithm needs an initial solution. This solution can be - constructed by a simple greedy algorithm. At every iteration, it - selects thoughtfully a neighbor solution. - Consider $c(x)$ cost of current solution and $c(x')$ cost of - neighbor solution. - If $c(x') - c(x) <= threshold$ then the neighbor solution becomes the current - solution for the next iteration, where the threshold is named threshold. - - In comparison to the Simulated Annealing algorithm, the Threshold - Accepting algorithm does not accept very low quality solutions - (due to the presence of the threshold value). In the case of - Simulated Annealing, even a very low quality solution can - be accepted with probability $p$. - - Time complexity: - It has a running time $O(m * n * |V|)$ where $m$ and $n$ are the number - of times the outer and inner loop run respectively. - - For more information and how algorithm is inspired see: - https://doi.org/10.1016/0021-9991(90)90201-B - - See Also - -------- - simulated_annealing_tsp - - """ - if move == "1-1": - move = swap_two_nodes - elif move == "1-0": - move = move_one_node - if init_cycle == "greedy": - # Construct an initial solution using a greedy algorithm. - cycle = greedy_tsp(G, weight=weight, source=source) - if G.number_of_nodes() == 2: - return cycle - - else: - cycle = list(init_cycle) - if source is None: - source = cycle[0] - elif source != cycle[0]: - raise nx.NetworkXError("source must be first node in init_cycle") - if cycle[0] != cycle[-1]: - raise nx.NetworkXError("init_cycle must be a cycle. (return to start)") - - if len(cycle) - 1 != len(G) or len(set(G.nbunch_iter(cycle))) != len(G): - raise nx.NetworkXError("init_cycle is not all and only nodes.") - - # Check that G is a complete graph - N = len(G) - 1 - # This check ignores selfloops which is what we want here. - if any(len(nbrdict) - (n in nbrdict) != N for n, nbrdict in G.adj.items()): - raise nx.NetworkXError("G must be a complete graph.") - - if G.number_of_nodes() == 2: - neighbor = list(G.neighbors(source))[0] - return [source, neighbor, source] - - # Find the cost of initial solution - cost = sum(G[u][v].get(weight, 1) for u, v in pairwise(cycle)) - - count = 0 - best_cycle = cycle.copy() - best_cost = cost - while count <= max_iterations: - count += 1 - accepted = False - for i in range(N_inner): - adj_sol = move(cycle, seed) - adj_cost = sum(G[u][v].get(weight, 1) for u, v in pairwise(adj_sol)) - delta = adj_cost - cost - if delta <= threshold: - accepted = True - - # Set current solution the adjacent solution. - cycle = adj_sol - cost = adj_cost - - if cost < best_cost: - count = 0 - best_cycle = cycle.copy() - best_cost = cost - if accepted: - threshold -= threshold * alpha - - return best_cycle diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/treewidth.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/treewidth.py deleted file mode 100644 index 31d73f6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/treewidth.py +++ /dev/null @@ -1,252 +0,0 @@ -"""Functions for computing treewidth decomposition. - -Treewidth of an undirected graph is a number associated with the graph. -It can be defined as the size of the largest vertex set (bag) in a tree -decomposition of the graph minus one. - -`Wikipedia: Treewidth `_ - -The notions of treewidth and tree decomposition have gained their -attractiveness partly because many graph and network problems that are -intractable (e.g., NP-hard) on arbitrary graphs become efficiently -solvable (e.g., with a linear time algorithm) when the treewidth of the -input graphs is bounded by a constant [1]_ [2]_. - -There are two different functions for computing a tree decomposition: -:func:`treewidth_min_degree` and :func:`treewidth_min_fill_in`. - -.. [1] Hans L. Bodlaender and Arie M. C. A. Koster. 2010. "Treewidth - computations I.Upper bounds". Inf. Comput. 208, 3 (March 2010),259-275. - http://dx.doi.org/10.1016/j.ic.2009.03.008 - -.. [2] Hans L. Bodlaender. "Discovering Treewidth". Institute of Information - and Computing Sciences, Utrecht University. - Technical Report UU-CS-2005-018. - http://www.cs.uu.nl - -.. [3] K. Wang, Z. Lu, and J. Hicks *Treewidth*. - https://web.archive.org/web/20210507025929/http://web.eecs.utk.edu/~cphill25/cs594_spring2015_projects/treewidth.pdf - -""" - -import itertools -import sys -from heapq import heapify, heappop, heappush - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["treewidth_min_degree", "treewidth_min_fill_in"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def treewidth_min_degree(G): - """Returns a treewidth decomposition using the Minimum Degree heuristic. - - The heuristic chooses the nodes according to their degree, i.e., first - the node with the lowest degree is chosen, then the graph is updated - and the corresponding node is removed. Next, a new node with the lowest - degree is chosen, and so on. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - deg_heuristic = MinDegreeHeuristic(G) - return treewidth_decomp(G, lambda graph: deg_heuristic.best_node(graph)) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def treewidth_min_fill_in(G): - """Returns a treewidth decomposition using the Minimum Fill-in heuristic. - - The heuristic chooses a node from the graph, where the number of edges - added turning the neighborhood of the chosen node into clique is as - small as possible. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - return treewidth_decomp(G, min_fill_in_heuristic) - - -class MinDegreeHeuristic: - """Implements the Minimum Degree heuristic. - - The heuristic chooses the nodes according to their degree - (number of neighbors), i.e., first the node with the lowest degree is - chosen, then the graph is updated and the corresponding node is - removed. Next, a new node with the lowest degree is chosen, and so on. - """ - - def __init__(self, graph): - self._graph = graph - - # nodes that have to be updated in the heap before each iteration - self._update_nodes = [] - - self._degreeq = [] # a heapq with 3-tuples (degree,unique_id,node) - self.count = itertools.count() - - # build heap with initial degrees - for n in graph: - self._degreeq.append((len(graph[n]), next(self.count), n)) - heapify(self._degreeq) - - def best_node(self, graph): - # update nodes in self._update_nodes - for n in self._update_nodes: - # insert changed degrees into degreeq - heappush(self._degreeq, (len(graph[n]), next(self.count), n)) - - # get the next valid (minimum degree) node - while self._degreeq: - (min_degree, _, elim_node) = heappop(self._degreeq) - if elim_node not in graph or len(graph[elim_node]) != min_degree: - # outdated entry in degreeq - continue - elif min_degree == len(graph) - 1: - # fully connected: abort condition - return None - - # remember to update nodes in the heap before getting the next node - self._update_nodes = graph[elim_node] - return elim_node - - # the heap is empty: abort - return None - - -def min_fill_in_heuristic(graph): - """Implements the Minimum Degree heuristic. - - Returns the node from the graph, where the number of edges added when - turning the neighborhood of the chosen node into clique is as small as - possible. This algorithm chooses the nodes using the Minimum Fill-In - heuristic. The running time of the algorithm is :math:`O(V^3)` and it uses - additional constant memory.""" - - if len(graph) == 0: - return None - - min_fill_in_node = None - - min_fill_in = sys.maxsize - - # sort nodes by degree - nodes_by_degree = sorted(graph, key=lambda x: len(graph[x])) - min_degree = len(graph[nodes_by_degree[0]]) - - # abort condition (handle complete graph) - if min_degree == len(graph) - 1: - return None - - for node in nodes_by_degree: - num_fill_in = 0 - nbrs = graph[node] - for nbr in nbrs: - # count how many nodes in nbrs current nbr is not connected to - # subtract 1 for the node itself - num_fill_in += len(nbrs - graph[nbr]) - 1 - if num_fill_in >= 2 * min_fill_in: - break - - num_fill_in /= 2 # divide by 2 because of double counting - - if num_fill_in < min_fill_in: # update min-fill-in node - if num_fill_in == 0: - return node - min_fill_in = num_fill_in - min_fill_in_node = node - - return min_fill_in_node - - -@nx._dispatchable(returns_graph=True) -def treewidth_decomp(G, heuristic=min_fill_in_heuristic): - """Returns a treewidth decomposition using the passed heuristic. - - Parameters - ---------- - G : NetworkX graph - heuristic : heuristic function - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - - # make dict-of-sets structure - graph = {n: set(G[n]) - {n} for n in G} - - # stack containing nodes and neighbors in the order from the heuristic - node_stack = [] - - # get first node from heuristic - elim_node = heuristic(graph) - while elim_node is not None: - # connect all neighbors with each other - nbrs = graph[elim_node] - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - # push node and its current neighbors on stack - node_stack.append((elim_node, nbrs)) - - # remove node from graph - for u in graph[elim_node]: - graph[u].remove(elim_node) - - del graph[elim_node] - elim_node = heuristic(graph) - - # the abort condition is met; put all remaining nodes into one bag - decomp = nx.Graph() - first_bag = frozenset(graph.keys()) - decomp.add_node(first_bag) - - treewidth = len(first_bag) - 1 - - while node_stack: - # get node and its neighbors from the stack - (curr_node, nbrs) = node_stack.pop() - - # find a bag all neighbors are in - old_bag = None - for bag in decomp.nodes: - if nbrs <= bag: - old_bag = bag - break - - if old_bag is None: - # no old_bag was found: just connect to the first_bag - old_bag = first_bag - - # create new node for decomposition - nbrs.add(curr_node) - new_bag = frozenset(nbrs) - - # update treewidth - treewidth = max(treewidth, len(new_bag) - 1) - - # add edge to decomposition (implicitly also adds the new node) - decomp.add_edge(old_bag, new_bag) - - return treewidth, decomp diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/vertex_cover.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/vertex_cover.py deleted file mode 100644 index 13d7167..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/approximation/vertex_cover.py +++ /dev/null @@ -1,83 +0,0 @@ -"""Functions for computing an approximate minimum weight vertex cover. - -A |vertex cover|_ is a subset of nodes such that each edge in the graph -is incident to at least one node in the subset. - -.. _vertex cover: https://en.wikipedia.org/wiki/Vertex_cover -.. |vertex cover| replace:: *vertex cover* - -""" - -import networkx as nx - -__all__ = ["min_weighted_vertex_cover"] - - -@nx._dispatchable(node_attrs="weight") -def min_weighted_vertex_cover(G, weight=None): - r"""Returns an approximate minimum weighted vertex cover. - - The set of nodes returned by this function is guaranteed to be a - vertex cover, and the total weight of the set is guaranteed to be at - most twice the total weight of the minimum weight vertex cover. In - other words, - - .. math:: - - w(S) \leq 2 * w(S^*), - - where $S$ is the vertex cover returned by this function, - $S^*$ is the vertex cover of minimum weight out of all vertex - covers of the graph, and $w$ is the function that computes the - sum of the weights of each node in that given set. - - Parameters - ---------- - G : NetworkX graph - - weight : string, optional (default = None) - If None, every node has weight 1. If a string, use this node - attribute as the node weight. A node without this attribute is - assumed to have weight 1. - - Returns - ------- - min_weighted_cover : set - Returns a set of nodes whose weight sum is no more than twice - the weight sum of the minimum weight vertex cover. - - Notes - ----- - For a directed graph, a vertex cover has the same definition: a set - of nodes such that each edge in the graph is incident to at least - one node in the set. Whether the node is the head or tail of the - directed edge is ignored. - - This is the local-ratio algorithm for computing an approximate - vertex cover. The algorithm greedily reduces the costs over edges, - iteratively building a cover. The worst-case runtime of this - implementation is $O(m \log n)$, where $n$ is the number - of nodes and $m$ the number of edges in the graph. - - References - ---------- - .. [1] Bar-Yehuda, R., and Even, S. (1985). "A local-ratio theorem for - approximating the weighted vertex cover problem." - *Annals of Discrete Mathematics*, 25, 27–46 - - - """ - cost = dict(G.nodes(data=weight, default=1)) - # While there are uncovered edges, choose an uncovered and update - # the cost of the remaining edges. - cover = set() - for u, v in G.edges(): - if u in cover or v in cover: - continue - if cost[u] <= cost[v]: - cover.add(u) - cost[v] -= cost[u] - else: - cover.add(v) - cost[u] -= cost[v] - return cover diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/__init__.py deleted file mode 100644 index 4d98886..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from networkx.algorithms.assortativity.connectivity import * -from networkx.algorithms.assortativity.correlation import * -from networkx.algorithms.assortativity.mixing import * -from networkx.algorithms.assortativity.neighbor_degree import * -from networkx.algorithms.assortativity.pairs import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/connectivity.py deleted file mode 100644 index c3fde0d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/connectivity.py +++ /dev/null @@ -1,122 +0,0 @@ -from collections import defaultdict - -import networkx as nx - -__all__ = ["average_degree_connectivity"] - - -@nx._dispatchable(edge_attrs="weight") -def average_degree_connectivity( - G, source="in+out", target="in+out", nodes=None, weight=None -): - r"""Compute the average degree connectivity of graph. - - The average degree connectivity is the average nearest neighbor degree of - nodes with degree k. For weighted graphs, an analogous measure can - be computed using the weighted average neighbors degree defined in - [1]_, for a node `i`, as - - .. math:: - - k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j - - where `s_i` is the weighted degree of node `i`, - `w_{ij}` is the weight of the edge that links `i` and `j`, - and `N(i)` are the neighbors of node `i`. - - Parameters - ---------- - G : NetworkX graph - - source : "in"|"out"|"in+out" (default:"in+out") - Directed graphs only. Use "in"- or "out"-degree for source node. - - target : "in"|"out"|"in+out" (default:"in+out" - Directed graphs only. Use "in"- or "out"-degree for target node. - - nodes : list or iterable (optional) - Compute neighbor connectivity for these nodes. The default is all - nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - d : dict - A dictionary keyed by degree k with the value of average connectivity. - - Raises - ------ - NetworkXError - If either `source` or `target` are not one of 'in', - 'out', or 'in+out'. - If either `source` or `target` is passed for an undirected graph. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G.edges[1, 2]["weight"] = 3 - >>> nx.average_degree_connectivity(G) - {1: 2.0, 2: 1.5} - >>> nx.average_degree_connectivity(G, weight="weight") - {1: 2.0, 2: 1.75} - - See Also - -------- - average_neighbor_degree - - References - ---------- - .. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani, - "The architecture of complex weighted networks". - PNAS 101 (11): 3747–3752 (2004). - """ - # First, determine the type of neighbors and the type of degree to use. - if G.is_directed(): - if source not in ("in", "out", "in+out"): - raise nx.NetworkXError('source must be one of "in", "out", or "in+out"') - if target not in ("in", "out", "in+out"): - raise nx.NetworkXError('target must be one of "in", "out", or "in+out"') - direction = {"out": G.out_degree, "in": G.in_degree, "in+out": G.degree} - neighbor_funcs = { - "out": G.successors, - "in": G.predecessors, - "in+out": G.neighbors, - } - source_degree = direction[source] - target_degree = direction[target] - neighbors = neighbor_funcs[source] - # `reverse` indicates whether to look at the in-edge when - # computing the weight of an edge. - reverse = source == "in" - else: - if source != "in+out" or target != "in+out": - raise nx.NetworkXError( - f"source and target arguments are only supported for directed graphs" - ) - source_degree = G.degree - target_degree = G.degree - neighbors = G.neighbors - reverse = False - dsum = defaultdict(int) - dnorm = defaultdict(int) - # Check if `source_nodes` is actually a single node in the graph. - source_nodes = source_degree(nodes) - if nodes in G: - source_nodes = [(nodes, source_degree(nodes))] - for n, k in source_nodes: - nbrdeg = target_degree(neighbors(n)) - if weight is None: - s = sum(d for n, d in nbrdeg) - else: # weight nbr degree by weight of (n,nbr) edge - if reverse: - s = sum(G[nbr][n].get(weight, 1) * d for nbr, d in nbrdeg) - else: - s = sum(G[n][nbr].get(weight, 1) * d for nbr, d in nbrdeg) - dnorm[k] += source_degree(n, weight=weight) - dsum[k] += s - - # normalize - return {k: avg if dnorm[k] == 0 else avg / dnorm[k] for k, avg in dsum.items()} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/correlation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/correlation.py deleted file mode 100644 index 52ae7a1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/correlation.py +++ /dev/null @@ -1,302 +0,0 @@ -"""Node assortativity coefficients and correlation measures.""" - -import networkx as nx -from networkx.algorithms.assortativity.mixing import ( - attribute_mixing_matrix, - degree_mixing_matrix, -) -from networkx.algorithms.assortativity.pairs import node_degree_xy - -__all__ = [ - "degree_pearson_correlation_coefficient", - "degree_assortativity_coefficient", - "attribute_assortativity_coefficient", - "numeric_assortativity_coefficient", -] - - -@nx._dispatchable(edge_attrs="weight") -def degree_assortativity_coefficient(G, x="out", y="in", weight=None, nodes=None): - """Compute degree assortativity of graph. - - Assortativity measures the similarity of connections - in the graph with respect to the node degree. - - Parameters - ---------- - G : NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Compute degree assortativity only for nodes in container. - The default is all nodes. - - Returns - ------- - r : float - Assortativity of graph by degree. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> r = nx.degree_assortativity_coefficient(G) - >>> print(f"{r:3.1f}") - -0.5 - - See Also - -------- - attribute_assortativity_coefficient - numeric_assortativity_coefficient - degree_mixing_dict - degree_mixing_matrix - - Notes - ----- - This computes Eq. (21) in Ref. [1]_ , where e is the joint - probability distribution (mixing matrix) of the degrees. If G is - directed than the matrix e is the joint probability of the - user-specified degree type for the source and target. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - .. [2] Foster, J.G., Foster, D.V., Grassberger, P. & Paczuski, M. - Edge direction and the structure of networks, PNAS 107, 10815-20 (2010). - """ - if nodes is None: - nodes = G.nodes - - degrees = None - - if G.is_directed(): - indeg = ( - {d for _, d in G.in_degree(nodes, weight=weight)} - if "in" in (x, y) - else set() - ) - outdeg = ( - {d for _, d in G.out_degree(nodes, weight=weight)} - if "out" in (x, y) - else set() - ) - degrees = set.union(indeg, outdeg) - else: - degrees = {d for _, d in G.degree(nodes, weight=weight)} - - mapping = {d: i for i, d in enumerate(degrees)} - M = degree_mixing_matrix(G, x=x, y=y, nodes=nodes, weight=weight, mapping=mapping) - - return _numeric_ac(M, mapping=mapping) - - -@nx._dispatchable(edge_attrs="weight") -def degree_pearson_correlation_coefficient(G, x="out", y="in", weight=None, nodes=None): - """Compute degree assortativity of graph. - - Assortativity measures the similarity of connections - in the graph with respect to the node degree. - - This is the same as degree_assortativity_coefficient but uses the - potentially faster scipy.stats.pearsonr function. - - Parameters - ---------- - G : NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Compute pearson correlation of degrees only for specified nodes. - The default is all nodes. - - Returns - ------- - r : float - Assortativity of graph by degree. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> r = nx.degree_pearson_correlation_coefficient(G) - >>> print(f"{r:3.1f}") - -0.5 - - Notes - ----- - This calls scipy.stats.pearsonr. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks - Physical Review E, 67 026126, 2003 - .. [2] Foster, J.G., Foster, D.V., Grassberger, P. & Paczuski, M. - Edge direction and the structure of networks, PNAS 107, 10815-20 (2010). - """ - import scipy as sp - - xy = node_degree_xy(G, x=x, y=y, nodes=nodes, weight=weight) - x, y = zip(*xy) - return float(sp.stats.pearsonr(x, y)[0]) - - -@nx._dispatchable(node_attrs="attribute") -def attribute_assortativity_coefficient(G, attribute, nodes=None): - """Compute assortativity for node attributes. - - Assortativity measures the similarity of connections - in the graph with respect to the given attribute. - - Parameters - ---------- - G : NetworkX graph - - attribute : string - Node attribute key - - nodes: list or iterable (optional) - Compute attribute assortativity for nodes in container. - The default is all nodes. - - Returns - ------- - r: float - Assortativity of graph for given attribute - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([0, 1], color="red") - >>> G.add_nodes_from([2, 3], color="blue") - >>> G.add_edges_from([(0, 1), (2, 3)]) - >>> print(nx.attribute_assortativity_coefficient(G, "color")) - 1.0 - - Notes - ----- - This computes Eq. (2) in Ref. [1]_ , (trace(M)-sum(M^2))/(1-sum(M^2)), - where M is the joint probability distribution (mixing matrix) - of the specified attribute. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - """ - M = attribute_mixing_matrix(G, attribute, nodes) - return attribute_ac(M) - - -@nx._dispatchable(node_attrs="attribute") -def numeric_assortativity_coefficient(G, attribute, nodes=None): - """Compute assortativity for numerical node attributes. - - Assortativity measures the similarity of connections - in the graph with respect to the given numeric attribute. - - Parameters - ---------- - G : NetworkX graph - - attribute : string - Node attribute key. - - nodes: list or iterable (optional) - Compute numeric assortativity only for attributes of nodes in - container. The default is all nodes. - - Returns - ------- - r: float - Assortativity of graph for given attribute - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([0, 1], size=2) - >>> G.add_nodes_from([2, 3], size=3) - >>> G.add_edges_from([(0, 1), (2, 3)]) - >>> print(nx.numeric_assortativity_coefficient(G, "size")) - 1.0 - - Notes - ----- - This computes Eq. (21) in Ref. [1]_ , which is the Pearson correlation - coefficient of the specified (scalar valued) attribute across edges. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks - Physical Review E, 67 026126, 2003 - """ - if nodes is None: - nodes = G.nodes - vals = {G.nodes[n][attribute] for n in nodes} - mapping = {d: i for i, d in enumerate(vals)} - M = attribute_mixing_matrix(G, attribute, nodes, mapping) - return _numeric_ac(M, mapping) - - -def attribute_ac(M): - """Compute assortativity for attribute matrix M. - - Parameters - ---------- - M : numpy.ndarray - 2D ndarray representing the attribute mixing matrix. - - Notes - ----- - This computes Eq. (2) in Ref. [1]_ , (trace(e)-sum(e^2))/(1-sum(e^2)), - where e is the joint probability distribution (mixing matrix) - of the specified attribute. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - """ - if M.sum() != 1.0: - M = M / M.sum() - s = (M @ M).sum() - t = M.trace() - r = (t - s) / (1 - s) - return float(r) - - -def _numeric_ac(M, mapping): - # M is a 2D numpy array - # numeric assortativity coefficient, pearsonr - import numpy as np - - if M.sum() != 1.0: - M = M / M.sum() - x = np.array(list(mapping.keys())) - y = x # x and y have the same support - idx = list(mapping.values()) - a = M.sum(axis=0) - b = M.sum(axis=1) - vara = (a[idx] * x**2).sum() - ((a[idx] * x).sum()) ** 2 - varb = (b[idx] * y**2).sum() - ((b[idx] * y).sum()) ** 2 - xy = np.outer(x, y) - ab = np.outer(a[idx], b[idx]) - return float((xy * (M - ab)).sum() / np.sqrt(vara * varb)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/mixing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/mixing.py deleted file mode 100644 index 1762d4e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/mixing.py +++ /dev/null @@ -1,255 +0,0 @@ -""" -Mixing matrices for node attributes and degree. -""" - -import networkx as nx -from networkx.algorithms.assortativity.pairs import node_attribute_xy, node_degree_xy -from networkx.utils import dict_to_numpy_array - -__all__ = [ - "attribute_mixing_matrix", - "attribute_mixing_dict", - "degree_mixing_matrix", - "degree_mixing_dict", - "mixing_dict", -] - - -@nx._dispatchable(node_attrs="attribute") -def attribute_mixing_dict(G, attribute, nodes=None, normalized=False): - """Returns dictionary representation of mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - attribute : string - Node attribute key. - - nodes: list or iterable (optional) - Unse nodes in container to build the dict. The default is all nodes. - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([0, 1], color="red") - >>> G.add_nodes_from([2, 3], color="blue") - >>> G.add_edge(1, 3) - >>> d = nx.attribute_mixing_dict(G, "color") - >>> print(d["red"]["blue"]) - 1 - >>> print(d["blue"]["red"]) # d symmetric for undirected graphs - 1 - - Returns - ------- - d : dictionary - Counts or joint probability of occurrence of attribute pairs. - """ - xy_iter = node_attribute_xy(G, attribute, nodes) - return mixing_dict(xy_iter, normalized=normalized) - - -@nx._dispatchable(node_attrs="attribute") -def attribute_mixing_matrix(G, attribute, nodes=None, mapping=None, normalized=True): - """Returns mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - attribute : string - Node attribute key. - - nodes: list or iterable (optional) - Use only nodes in container to build the matrix. The default is - all nodes. - - mapping : dictionary, optional - Mapping from node attribute to integer index in matrix. - If not specified, an arbitrary ordering will be used. - - normalized : bool (default=True) - Return counts if False or probabilities if True. - - Returns - ------- - m: numpy array - Counts or joint probability of occurrence of attribute pairs. - - Notes - ----- - If each node has a unique attribute value, the unnormalized mixing matrix - will be equal to the adjacency matrix. To get a denser mixing matrix, - the rounding can be performed to form groups of nodes with equal values. - For example, the exact height of persons in cm (180.79155222, 163.9080892, - 163.30095355, 167.99016217, 168.21590163, ...) can be rounded to (180, 163, - 163, 168, 168, ...). - - Definitions of attribute mixing matrix vary on whether the matrix - should include rows for attribute values that don't arise. Here we - do not include such empty-rows. But you can force them to appear - by inputting a `mapping` that includes those values. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> gender = {0: "male", 1: "female", 2: "female"} - >>> nx.set_node_attributes(G, gender, "gender") - >>> mapping = {"male": 0, "female": 1} - >>> mix_mat = nx.attribute_mixing_matrix(G, "gender", mapping=mapping) - >>> mix_mat - array([[0. , 0.25], - [0.25, 0.5 ]]) - """ - d = attribute_mixing_dict(G, attribute, nodes) - a = dict_to_numpy_array(d, mapping=mapping) - if normalized: - a = a / a.sum() - return a - - -@nx._dispatchable(edge_attrs="weight") -def degree_mixing_dict(G, x="out", y="in", weight=None, nodes=None, normalized=False): - """Returns dictionary representation of mixing matrix for degree. - - Parameters - ---------- - G : graph - NetworkX graph object. - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Returns - ------- - d: dictionary - Counts or joint probability of occurrence of degree pairs. - """ - xy_iter = node_degree_xy(G, x=x, y=y, nodes=nodes, weight=weight) - return mixing_dict(xy_iter, normalized=normalized) - - -@nx._dispatchable(edge_attrs="weight") -def degree_mixing_matrix( - G, x="out", y="in", weight=None, nodes=None, normalized=True, mapping=None -): - """Returns mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - nodes: list or iterable (optional) - Build the matrix using only nodes in container. - The default is all nodes. - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - normalized : bool (default=True) - Return counts if False or probabilities if True. - - mapping : dictionary, optional - Mapping from node degree to integer index in matrix. - If not specified, an arbitrary ordering will be used. - - Returns - ------- - m: numpy array - Counts, or joint probability, of occurrence of node degree. - - Notes - ----- - Definitions of degree mixing matrix vary on whether the matrix - should include rows for degree values that don't arise. Here we - do not include such empty-rows. But you can force them to appear - by inputting a `mapping` that includes those values. See examples. - - Examples - -------- - >>> G = nx.star_graph(3) - >>> mix_mat = nx.degree_mixing_matrix(G) - >>> mix_mat - array([[0. , 0.5], - [0.5, 0. ]]) - - If you want every possible degree to appear as a row, even if no nodes - have that degree, use `mapping` as follows, - - >>> max_degree = max(deg for n, deg in G.degree) - >>> mapping = {x: x for x in range(max_degree + 1)} # identity mapping - >>> mix_mat = nx.degree_mixing_matrix(G, mapping=mapping) - >>> mix_mat - array([[0. , 0. , 0. , 0. ], - [0. , 0. , 0. , 0.5], - [0. , 0. , 0. , 0. ], - [0. , 0.5, 0. , 0. ]]) - """ - d = degree_mixing_dict(G, x=x, y=y, nodes=nodes, weight=weight) - a = dict_to_numpy_array(d, mapping=mapping) - if normalized: - a = a / a.sum() - return a - - -def mixing_dict(xy, normalized=False): - """Returns a dictionary representation of mixing matrix. - - Parameters - ---------- - xy : list or container of two-tuples - Pairs of (x,y) items. - - attribute : string - Node attribute key - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Returns - ------- - d: dictionary - Counts or Joint probability of occurrence of values in xy. - """ - d = {} - psum = 0.0 - for x, y in xy: - if x not in d: - d[x] = {} - if y not in d: - d[y] = {} - v = d[x].get(y, 0) - d[x][y] = v + 1 - psum += 1 - - if normalized: - for _, jdict in d.items(): - for j in jdict: - jdict[j] /= psum - return d diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/neighbor_degree.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/neighbor_degree.py deleted file mode 100644 index 6488d04..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/neighbor_degree.py +++ /dev/null @@ -1,160 +0,0 @@ -import networkx as nx - -__all__ = ["average_neighbor_degree"] - - -@nx._dispatchable(edge_attrs="weight") -def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=None): - r"""Returns the average degree of the neighborhood of each node. - - In an undirected graph, the neighborhood `N(i)` of node `i` contains the - nodes that are connected to `i` by an edge. - - For directed graphs, `N(i)` is defined according to the parameter `source`: - - - if source is 'in', then `N(i)` consists of predecessors of node `i`. - - if source is 'out', then `N(i)` consists of successors of node `i`. - - if source is 'in+out', then `N(i)` is both predecessors and successors. - - The average neighborhood degree of a node `i` is - - .. math:: - - k_{nn,i} = \frac{1}{|N(i)|} \sum_{j \in N(i)} k_j - - where `N(i)` are the neighbors of node `i` and `k_j` is - the degree of node `j` which belongs to `N(i)`. For weighted - graphs, an analogous measure can be defined [1]_, - - .. math:: - - k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j - - where `s_i` is the weighted degree of node `i`, `w_{ij}` - is the weight of the edge that links `i` and `j` and - `N(i)` are the neighbors of node `i`. - - - Parameters - ---------- - G : NetworkX graph - - source : string ("in"|"out"|"in+out"), optional (default="out") - Directed graphs only. - Use "in"- or "out"-neighbors of source node. - - target : string ("in"|"out"|"in+out"), optional (default="out") - Directed graphs only. - Use "in"- or "out"-degree for target node. - - nodes : list or iterable, optional (default=G.nodes) - Compute neighbor degree only for specified nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - d: dict - A dictionary keyed by node to the average degree of its neighbors. - - Raises - ------ - NetworkXError - If either `source` or `target` are not one of 'in', 'out', or 'in+out'. - If either `source` or `target` is passed for an undirected graph. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G.edges[0, 1]["weight"] = 5 - >>> G.edges[2, 3]["weight"] = 3 - - >>> nx.average_neighbor_degree(G) - {0: 2.0, 1: 1.5, 2: 1.5, 3: 2.0} - >>> nx.average_neighbor_degree(G, weight="weight") - {0: 2.0, 1: 1.1666666666666667, 2: 1.25, 3: 2.0} - - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> nx.average_neighbor_degree(G, source="in", target="in") - {0: 0.0, 1: 0.0, 2: 1.0, 3: 1.0} - - >>> nx.average_neighbor_degree(G, source="out", target="out") - {0: 1.0, 1: 1.0, 2: 0.0, 3: 0.0} - - See Also - -------- - average_degree_connectivity - - References - ---------- - .. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani, - "The architecture of complex weighted networks". - PNAS 101 (11): 3747–3752 (2004). - """ - if G.is_directed(): - if source == "in": - source_degree = G.in_degree - elif source == "out": - source_degree = G.out_degree - elif source == "in+out": - source_degree = G.degree - else: - raise nx.NetworkXError( - f"source argument {source} must be 'in', 'out' or 'in+out'" - ) - - if target == "in": - target_degree = G.in_degree - elif target == "out": - target_degree = G.out_degree - elif target == "in+out": - target_degree = G.degree - else: - raise nx.NetworkXError( - f"target argument {target} must be 'in', 'out' or 'in+out'" - ) - else: - if source != "out" or target != "out": - raise nx.NetworkXError( - f"source and target arguments are only supported for directed graphs" - ) - source_degree = target_degree = G.degree - - # precompute target degrees -- should *not* be weighted degree - t_deg = dict(target_degree()) - - # Set up both predecessor and successor neighbor dicts leaving empty if not needed - G_P = G_S = {n: {} for n in G} - if G.is_directed(): - # "in" or "in+out" cases: G_P contains predecessors - if "in" in source: - G_P = G.pred - # "out" or "in+out" cases: G_S contains successors - if "out" in source: - G_S = G.succ - else: - # undirected leave G_P empty but G_S is the adjacency - G_S = G.adj - - # Main loop: Compute average degree of neighbors - avg = {} - for n, deg in source_degree(nodes, weight=weight): - # handle degree zero average - if deg == 0: - avg[n] = 0.0 - continue - - # we sum over both G_P and G_S, but one of the two is usually empty. - if weight is None: - avg[n] = ( - sum(t_deg[nbr] for nbr in G_S[n]) + sum(t_deg[nbr] for nbr in G_P[n]) - ) / deg - else: - avg[n] = ( - sum(dd.get(weight, 1) * t_deg[nbr] for nbr, dd in G_S[n].items()) - + sum(dd.get(weight, 1) * t_deg[nbr] for nbr, dd in G_P[n].items()) - ) / deg - return avg diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/pairs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/pairs.py deleted file mode 100644 index ea5fd28..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/pairs.py +++ /dev/null @@ -1,127 +0,0 @@ -"""Generators of x-y pairs of node data.""" - -import networkx as nx - -__all__ = ["node_attribute_xy", "node_degree_xy"] - - -@nx._dispatchable(node_attrs="attribute") -def node_attribute_xy(G, attribute, nodes=None): - """Yields 2-tuples of node attribute values for all edges in `G`. - - This generator yields, for each edge in `G` incident to a node in `nodes`, - a 2-tuple of form ``(attribute value, attribute value)`` for the parameter - specified node-attribute. - - Parameters - ---------- - G: NetworkX graph - - attribute: key - The node attribute key. - - nodes: list or iterable (optional) - Use only edges that are incident to specified nodes. - The default is all nodes. - - Yields - ------ - (x, y): 2-tuple - Generates 2-tuple of (attribute, attribute) values. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_node(1, color="red") - >>> G.add_node(2, color="blue") - >>> G.add_node(3, color="green") - >>> G.add_edge(1, 2) - >>> list(nx.node_attribute_xy(G, "color")) - [('red', 'blue')] - - Notes - ----- - For undirected graphs, each edge is produced twice, once for each edge - representation (u, v) and (v, u), with the exception of self-loop edges - which only appear once. - """ - if nodes is None: - nodes = set(G) - else: - nodes = set(nodes) - Gnodes = G.nodes - for u, nbrsdict in G.adjacency(): - if u not in nodes: - continue - uattr = Gnodes[u].get(attribute, None) - if G.is_multigraph(): - for v, keys in nbrsdict.items(): - vattr = Gnodes[v].get(attribute, None) - for _ in keys: - yield (uattr, vattr) - else: - for v in nbrsdict: - vattr = Gnodes[v].get(attribute, None) - yield (uattr, vattr) - - -@nx._dispatchable(edge_attrs="weight") -def node_degree_xy(G, x="out", y="in", weight=None, nodes=None): - """Yields 2-tuples of ``(degree, degree)`` values for edges in `G`. - - This generator yields, for each edge in `G` incident to a node in `nodes`, - a 2-tuple of form ``(degree, degree)``. The node degrees are weighted - when a `weight` attribute is specified. - - Parameters - ---------- - G: NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Use only edges that are adjacency to specified nodes. - The default is all nodes. - - Yields - ------ - (x, y): 2-tuple - Generates 2-tuple of (degree, degree) values. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2) - >>> list(nx.node_degree_xy(G, x="out", y="in")) - [(1, 1)] - >>> list(nx.node_degree_xy(G, x="in", y="out")) - [(0, 0)] - - Notes - ----- - For undirected graphs, each edge is produced twice, once for each edge - representation (u, v) and (v, u), with the exception of self-loop edges - which only appear once. - """ - nodes = set(G) if nodes is None else set(nodes) - if G.is_directed(): - direction = {"out": G.out_degree, "in": G.in_degree} - xdeg = direction[x] - ydeg = direction[y] - else: - xdeg = ydeg = G.degree - - for u, degu in xdeg(nodes, weight=weight): - # use G.edges to treat multigraphs correctly - neighbors = (nbr for _, nbr in G.edges(u) if nbr in nodes) - for _, degv in ydeg(neighbors, weight=weight): - yield degu, degv diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/base_test.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/base_test.py deleted file mode 100644 index 46d6300..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/base_test.py +++ /dev/null @@ -1,81 +0,0 @@ -import networkx as nx - - -class BaseTestAttributeMixing: - @classmethod - def setup_class(cls): - G = nx.Graph() - G.add_nodes_from([0, 1], fish="one") - G.add_nodes_from([2, 3], fish="two") - G.add_nodes_from([4], fish="red") - G.add_nodes_from([5], fish="blue") - G.add_edges_from([(0, 1), (2, 3), (0, 4), (2, 5)]) - cls.G = G - - D = nx.DiGraph() - D.add_nodes_from([0, 1], fish="one") - D.add_nodes_from([2, 3], fish="two") - D.add_nodes_from([4], fish="red") - D.add_nodes_from([5], fish="blue") - D.add_edges_from([(0, 1), (2, 3), (0, 4), (2, 5)]) - cls.D = D - - M = nx.MultiGraph() - M.add_nodes_from([0, 1], fish="one") - M.add_nodes_from([2, 3], fish="two") - M.add_nodes_from([4], fish="red") - M.add_nodes_from([5], fish="blue") - M.add_edges_from([(0, 1), (0, 1), (2, 3)]) - cls.M = M - - S = nx.Graph() - S.add_nodes_from([0, 1], fish="one") - S.add_nodes_from([2, 3], fish="two") - S.add_nodes_from([4], fish="red") - S.add_nodes_from([5], fish="blue") - S.add_edge(0, 0) - S.add_edge(2, 2) - cls.S = S - - N = nx.Graph() - N.add_nodes_from([0, 1], margin=-2) - N.add_nodes_from([2, 3], margin=-2) - N.add_nodes_from([4], margin=-3) - N.add_nodes_from([5], margin=-4) - N.add_edges_from([(0, 1), (2, 3), (0, 4), (2, 5)]) - cls.N = N - - F = nx.Graph() - F.add_edges_from([(0, 3), (1, 3), (2, 3)], weight=0.5) - F.add_edge(0, 2, weight=1) - nx.set_node_attributes(F, dict(F.degree(weight="weight")), "margin") - cls.F = F - - K = nx.Graph() - K.add_nodes_from([1, 2], margin=-1) - K.add_nodes_from([3], margin=1) - K.add_nodes_from([4], margin=2) - K.add_edges_from([(3, 4), (1, 2), (1, 3)]) - cls.K = K - - -class BaseTestDegreeMixing: - @classmethod - def setup_class(cls): - cls.P4 = nx.path_graph(4) - cls.D = nx.DiGraph() - cls.D.add_edges_from([(0, 2), (0, 3), (1, 3), (2, 3)]) - cls.D2 = nx.DiGraph() - cls.D2.add_edges_from([(0, 3), (1, 0), (1, 2), (2, 4), (4, 1), (4, 3), (4, 2)]) - cls.M = nx.MultiGraph() - nx.add_path(cls.M, range(4)) - cls.M.add_edge(0, 1) - cls.S = nx.Graph() - cls.S.add_edges_from([(0, 0), (1, 1)]) - cls.W = nx.Graph() - cls.W.add_edges_from([(0, 3), (1, 3), (2, 3)], weight=0.5) - cls.W.add_edge(0, 2, weight=1) - S1 = nx.star_graph(4) - S2 = nx.star_graph(4) - cls.DS = nx.disjoint_union(S1, S2) - cls.DS.add_edge(4, 5) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_connectivity.py deleted file mode 100644 index 21c6287..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_connectivity.py +++ /dev/null @@ -1,143 +0,0 @@ -from itertools import permutations - -import pytest - -import networkx as nx - - -class TestNeighborConnectivity: - def test_degree_p4(self): - G = nx.path_graph(4) - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.5} - nd = nx.average_degree_connectivity(D) - assert nd == answer - - answer = {1: 2.0, 2: 1.5} - D = G.to_directed() - nd = nx.average_degree_connectivity(D, source="in", target="in") - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity(D, source="in", target="in") - assert nd == answer - - def test_degree_p4_weighted(self): - G = nx.path_graph(4) - G[1][2]["weight"] = 4 - answer = {1: 2.0, 2: 1.8} - nd = nx.average_degree_connectivity(G, weight="weight") - assert nd == answer - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.8} - nd = nx.average_degree_connectivity(D, weight="weight") - assert nd == answer - - answer = {1: 2.0, 2: 1.8} - D = G.to_directed() - nd = nx.average_degree_connectivity( - D, weight="weight", source="in", target="in" - ) - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity( - D, source="in", target="out", weight="weight" - ) - assert nd == answer - - def test_weight_keyword(self): - G = nx.path_graph(4) - G[1][2]["other"] = 4 - answer = {1: 2.0, 2: 1.8} - nd = nx.average_degree_connectivity(G, weight="other") - assert nd == answer - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G, weight=None) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.8} - nd = nx.average_degree_connectivity(D, weight="other") - assert nd == answer - - answer = {1: 2.0, 2: 1.8} - D = G.to_directed() - nd = nx.average_degree_connectivity(D, weight="other", source="in", target="in") - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity(D, weight="other", source="in", target="in") - assert nd == answer - - def test_degree_barrat(self): - G = nx.star_graph(5) - G.add_edges_from([(5, 6), (5, 7), (5, 8), (5, 9)]) - G[0][5]["weight"] = 5 - nd = nx.average_degree_connectivity(G)[5] - assert nd == 1.8 - nd = nx.average_degree_connectivity(G, weight="weight")[5] - assert nd == pytest.approx(3.222222, abs=1e-5) - - def test_zero_deg(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(1, 4) - c = nx.average_degree_connectivity(G) - assert c == {1: 0, 3: 1} - c = nx.average_degree_connectivity(G, source="in", target="in") - assert c == {0: 0, 1: 0} - c = nx.average_degree_connectivity(G, source="in", target="out") - assert c == {0: 0, 1: 3} - c = nx.average_degree_connectivity(G, source="in", target="in+out") - assert c == {0: 0, 1: 3} - c = nx.average_degree_connectivity(G, source="out", target="out") - assert c == {0: 0, 3: 0} - c = nx.average_degree_connectivity(G, source="out", target="in") - assert c == {0: 0, 3: 1} - c = nx.average_degree_connectivity(G, source="out", target="in+out") - assert c == {0: 0, 3: 1} - - def test_in_out_weight(self): - G = nx.DiGraph() - G.add_edge(1, 2, weight=1) - G.add_edge(1, 3, weight=1) - G.add_edge(3, 1, weight=1) - for s, t in permutations(["in", "out", "in+out"], 2): - c = nx.average_degree_connectivity(G, source=s, target=t) - cw = nx.average_degree_connectivity(G, source=s, target=t, weight="weight") - assert c == cw - - def test_invalid_source(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - nx.average_degree_connectivity(G, source="bogus") - - def test_invalid_target(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - nx.average_degree_connectivity(G, target="bogus") - - def test_invalid_undirected_graph(self): - G = nx.Graph() - with pytest.raises(nx.NetworkXError): - nx.average_degree_connectivity(G, target="bogus") - with pytest.raises(nx.NetworkXError): - nx.average_degree_connectivity(G, source="bogus") - - def test_single_node(self): - # TODO Is this really the intended behavior for providing a - # single node as the argument `nodes`? Shouldn't the function - # just return the connectivity value itself? - G = nx.trivial_graph() - conn = nx.average_degree_connectivity(G, nodes=0) - assert conn == {0: 0} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_correlation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_correlation.py deleted file mode 100644 index 5203f94..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_correlation.py +++ /dev/null @@ -1,123 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -import networkx as nx -from networkx.algorithms.assortativity.correlation import attribute_ac - -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing - - -class TestDegreeMixingCorrelation(BaseTestDegreeMixing): - def test_degree_assortativity_undirected(self): - r = nx.degree_assortativity_coefficient(self.P4) - np.testing.assert_almost_equal(r, -1.0 / 2, decimal=4) - - def test_degree_assortativity_node_kwargs(self): - G = nx.Graph() - edges = [(0, 1), (0, 3), (1, 2), (1, 3), (1, 4), (5, 9), (9, 0)] - G.add_edges_from(edges) - r = nx.degree_assortativity_coefficient(G, nodes=[1, 2, 4]) - np.testing.assert_almost_equal(r, -1.0, decimal=4) - - def test_degree_assortativity_directed(self): - r = nx.degree_assortativity_coefficient(self.D) - np.testing.assert_almost_equal(r, -0.57735, decimal=4) - - def test_degree_assortativity_directed2(self): - """Test degree assortativity for a directed graph where the set of - in/out degree does not equal the total degree.""" - r = nx.degree_assortativity_coefficient(self.D2) - np.testing.assert_almost_equal(r, 0.14852, decimal=4) - - def test_degree_assortativity_multigraph(self): - r = nx.degree_assortativity_coefficient(self.M) - np.testing.assert_almost_equal(r, -1.0 / 7.0, decimal=4) - - def test_degree_pearson_assortativity_undirected(self): - r = nx.degree_pearson_correlation_coefficient(self.P4) - np.testing.assert_almost_equal(r, -1.0 / 2, decimal=4) - - def test_degree_pearson_assortativity_directed(self): - r = nx.degree_pearson_correlation_coefficient(self.D) - np.testing.assert_almost_equal(r, -0.57735, decimal=4) - - def test_degree_pearson_assortativity_directed2(self): - """Test degree assortativity with Pearson for a directed graph where - the set of in/out degree does not equal the total degree.""" - r = nx.degree_pearson_correlation_coefficient(self.D2) - np.testing.assert_almost_equal(r, 0.14852, decimal=4) - - def test_degree_pearson_assortativity_multigraph(self): - r = nx.degree_pearson_correlation_coefficient(self.M) - np.testing.assert_almost_equal(r, -1.0 / 7.0, decimal=4) - - def test_degree_assortativity_weighted(self): - r = nx.degree_assortativity_coefficient(self.W, weight="weight") - np.testing.assert_almost_equal(r, -0.1429, decimal=4) - - def test_degree_assortativity_double_star(self): - r = nx.degree_assortativity_coefficient(self.DS) - np.testing.assert_almost_equal(r, -0.9339, decimal=4) - - -class TestAttributeMixingCorrelation(BaseTestAttributeMixing): - def test_attribute_assortativity_undirected(self): - r = nx.attribute_assortativity_coefficient(self.G, "fish") - assert r == 6.0 / 22.0 - - def test_attribute_assortativity_directed(self): - r = nx.attribute_assortativity_coefficient(self.D, "fish") - assert r == 1.0 / 3.0 - - def test_attribute_assortativity_multigraph(self): - r = nx.attribute_assortativity_coefficient(self.M, "fish") - assert r == 1.0 - - def test_attribute_assortativity_coefficient(self): - # from "Mixing patterns in networks" - # fmt: off - a = np.array([[0.258, 0.016, 0.035, 0.013], - [0.012, 0.157, 0.058, 0.019], - [0.013, 0.023, 0.306, 0.035], - [0.005, 0.007, 0.024, 0.016]]) - # fmt: on - r = attribute_ac(a) - np.testing.assert_almost_equal(r, 0.623, decimal=3) - - def test_attribute_assortativity_coefficient2(self): - # fmt: off - a = np.array([[0.18, 0.02, 0.01, 0.03], - [0.02, 0.20, 0.03, 0.02], - [0.01, 0.03, 0.16, 0.01], - [0.03, 0.02, 0.01, 0.22]]) - # fmt: on - r = attribute_ac(a) - np.testing.assert_almost_equal(r, 0.68, decimal=2) - - def test_attribute_assortativity(self): - a = np.array([[50, 50, 0], [50, 50, 0], [0, 0, 2]]) - r = attribute_ac(a) - np.testing.assert_almost_equal(r, 0.029, decimal=3) - - def test_attribute_assortativity_negative(self): - r = nx.numeric_assortativity_coefficient(self.N, "margin") - np.testing.assert_almost_equal(r, -0.2903, decimal=4) - - def test_assortativity_node_kwargs(self): - G = nx.Graph() - G.add_nodes_from([0, 1], size=2) - G.add_nodes_from([2, 3], size=3) - G.add_edges_from([(0, 1), (2, 3)]) - r = nx.numeric_assortativity_coefficient(G, "size", nodes=[0, 3]) - np.testing.assert_almost_equal(r, 1.0, decimal=4) - - def test_attribute_assortativity_float(self): - r = nx.numeric_assortativity_coefficient(self.F, "margin") - np.testing.assert_almost_equal(r, -0.1429, decimal=4) - - def test_attribute_assortativity_mixed(self): - r = nx.numeric_assortativity_coefficient(self.K, "margin") - np.testing.assert_almost_equal(r, 0.4340, decimal=4) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_mixing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_mixing.py deleted file mode 100644 index 9af0986..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_mixing.py +++ /dev/null @@ -1,176 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") - - -import networkx as nx - -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing - - -class TestDegreeMixingDict(BaseTestDegreeMixing): - def test_degree_mixing_dict_undirected(self): - d = nx.degree_mixing_dict(self.P4) - d_result = {1: {2: 2}, 2: {1: 2, 2: 2}} - assert d == d_result - - def test_degree_mixing_dict_undirected_normalized(self): - d = nx.degree_mixing_dict(self.P4, normalized=True) - d_result = {1: {2: 1.0 / 3}, 2: {1: 1.0 / 3, 2: 1.0 / 3}} - assert d == d_result - - def test_degree_mixing_dict_directed(self): - d = nx.degree_mixing_dict(self.D) - print(d) - d_result = {1: {3: 2}, 2: {1: 1, 3: 1}, 3: {}} - assert d == d_result - - def test_degree_mixing_dict_multigraph(self): - d = nx.degree_mixing_dict(self.M) - d_result = {1: {2: 1}, 2: {1: 1, 3: 3}, 3: {2: 3}} - assert d == d_result - - def test_degree_mixing_dict_weighted(self): - d = nx.degree_mixing_dict(self.W, weight="weight") - d_result = {0.5: {1.5: 1}, 1.5: {1.5: 6, 0.5: 1}} - assert d == d_result - - -class TestDegreeMixingMatrix(BaseTestDegreeMixing): - def test_degree_mixing_matrix_undirected(self): - # fmt: off - a_result = np.array([[0, 2], - [2, 2]] - ) - # fmt: on - a = nx.degree_mixing_matrix(self.P4, normalized=False) - np.testing.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.P4) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_degree_mixing_matrix_directed(self): - # fmt: off - a_result = np.array([[0, 0, 2], - [1, 0, 1], - [0, 0, 0]] - ) - # fmt: on - a = nx.degree_mixing_matrix(self.D, normalized=False) - np.testing.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.D) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_degree_mixing_matrix_multigraph(self): - # fmt: off - a_result = np.array([[0, 1, 0], - [1, 0, 3], - [0, 3, 0]] - ) - # fmt: on - a = nx.degree_mixing_matrix(self.M, normalized=False) - np.testing.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.M) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_degree_mixing_matrix_selfloop(self): - # fmt: off - a_result = np.array([[2]]) - # fmt: on - a = nx.degree_mixing_matrix(self.S, normalized=False) - np.testing.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.S) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_degree_mixing_matrix_weighted(self): - a_result = np.array([[0.0, 1.0], [1.0, 6.0]]) - a = nx.degree_mixing_matrix(self.W, weight="weight", normalized=False) - np.testing.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.W, weight="weight") - np.testing.assert_equal(a, a_result / float(a_result.sum())) - - def test_degree_mixing_matrix_mapping(self): - a_result = np.array([[6.0, 1.0], [1.0, 0.0]]) - mapping = {0.5: 1, 1.5: 0} - a = nx.degree_mixing_matrix( - self.W, weight="weight", normalized=False, mapping=mapping - ) - np.testing.assert_equal(a, a_result) - - -class TestAttributeMixingDict(BaseTestAttributeMixing): - def test_attribute_mixing_dict_undirected(self): - d = nx.attribute_mixing_dict(self.G, "fish") - d_result = { - "one": {"one": 2, "red": 1}, - "two": {"two": 2, "blue": 1}, - "red": {"one": 1}, - "blue": {"two": 1}, - } - assert d == d_result - - def test_attribute_mixing_dict_directed(self): - d = nx.attribute_mixing_dict(self.D, "fish") - d_result = { - "one": {"one": 1, "red": 1}, - "two": {"two": 1, "blue": 1}, - "red": {}, - "blue": {}, - } - assert d == d_result - - def test_attribute_mixing_dict_multigraph(self): - d = nx.attribute_mixing_dict(self.M, "fish") - d_result = {"one": {"one": 4}, "two": {"two": 2}} - assert d == d_result - - -class TestAttributeMixingMatrix(BaseTestAttributeMixing): - def test_attribute_mixing_matrix_undirected(self): - mapping = {"one": 0, "two": 1, "red": 2, "blue": 3} - a_result = np.array([[2, 0, 1, 0], [0, 2, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0]]) - a = nx.attribute_mixing_matrix( - self.G, "fish", mapping=mapping, normalized=False - ) - np.testing.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.G, "fish", mapping=mapping) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_attribute_mixing_matrix_directed(self): - mapping = {"one": 0, "two": 1, "red": 2, "blue": 3} - a_result = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]]) - a = nx.attribute_mixing_matrix( - self.D, "fish", mapping=mapping, normalized=False - ) - np.testing.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.D, "fish", mapping=mapping) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_attribute_mixing_matrix_multigraph(self): - mapping = {"one": 0, "two": 1, "red": 2, "blue": 3} - a_result = np.array([[4, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) - a = nx.attribute_mixing_matrix( - self.M, "fish", mapping=mapping, normalized=False - ) - np.testing.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.M, "fish", mapping=mapping) - np.testing.assert_equal(a, a_result / a_result.sum()) - - def test_attribute_mixing_matrix_negative(self): - mapping = {-2: 0, -3: 1, -4: 2} - a_result = np.array([[4.0, 1.0, 1.0], [1.0, 0.0, 0.0], [1.0, 0.0, 0.0]]) - a = nx.attribute_mixing_matrix( - self.N, "margin", mapping=mapping, normalized=False - ) - np.testing.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.N, "margin", mapping=mapping) - np.testing.assert_equal(a, a_result / float(a_result.sum())) - - def test_attribute_mixing_matrix_float(self): - mapping = {0.5: 1, 1.5: 0} - a_result = np.array([[6.0, 1.0], [1.0, 0.0]]) - a = nx.attribute_mixing_matrix( - self.F, "margin", mapping=mapping, normalized=False - ) - np.testing.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.F, "margin", mapping=mapping) - np.testing.assert_equal(a, a_result / a_result.sum()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_neighbor_degree.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_neighbor_degree.py deleted file mode 100644 index bf1252d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +++ /dev/null @@ -1,108 +0,0 @@ -import pytest - -import networkx as nx - - -class TestAverageNeighbor: - def test_degree_p4(self): - G = nx.path_graph(4) - answer = {0: 2, 1: 1.5, 2: 1.5, 3: 2} - nd = nx.average_neighbor_degree(G) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = nx.DiGraph(G.edges(data=True)) - nd = nx.average_neighbor_degree(D) - assert nd == {0: 1, 1: 1, 2: 0, 3: 0} - nd = nx.average_neighbor_degree(D, "in", "out") - assert nd == {0: 0, 1: 1, 2: 1, 3: 1} - nd = nx.average_neighbor_degree(D, "out", "in") - assert nd == {0: 1, 1: 1, 2: 1, 3: 0} - nd = nx.average_neighbor_degree(D, "in", "in") - assert nd == {0: 0, 1: 0, 2: 1, 3: 1} - - def test_degree_p4_weighted(self): - G = nx.path_graph(4) - G[1][2]["weight"] = 4 - answer = {0: 2, 1: 1.8, 2: 1.8, 3: 2} - nd = nx.average_neighbor_degree(G, weight="weight") - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, weight="weight") - assert nd == answer - - D = nx.DiGraph(G.edges(data=True)) - print(D.edges(data=True)) - nd = nx.average_neighbor_degree(D, weight="weight") - assert nd == {0: 1, 1: 1, 2: 0, 3: 0} - nd = nx.average_neighbor_degree(D, "out", "out", weight="weight") - assert nd == {0: 1, 1: 1, 2: 0, 3: 0} - nd = nx.average_neighbor_degree(D, "in", "in", weight="weight") - assert nd == {0: 0, 1: 0, 2: 1, 3: 1} - nd = nx.average_neighbor_degree(D, "in", "out", weight="weight") - assert nd == {0: 0, 1: 1, 2: 1, 3: 1} - nd = nx.average_neighbor_degree(D, "out", "in", weight="weight") - assert nd == {0: 1, 1: 1, 2: 1, 3: 0} - nd = nx.average_neighbor_degree(D, source="in+out", weight="weight") - assert nd == {0: 1.0, 1: 1.0, 2: 0.8, 3: 1.0} - nd = nx.average_neighbor_degree(D, target="in+out", weight="weight") - assert nd == {0: 2.0, 1: 2.0, 2: 1.0, 3: 0.0} - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, weight="weight") - assert nd == answer - nd = nx.average_neighbor_degree(D, source="out", target="out", weight="weight") - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source="in", target="in", weight="weight") - assert nd == answer - - def test_degree_k4(self): - G = nx.complete_graph(4) - answer = {0: 3, 1: 3, 2: 3, 3: 3} - nd = nx.average_neighbor_degree(G) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source="in", target="in") - assert nd == answer - - def test_degree_k4_nodes(self): - G = nx.complete_graph(4) - answer = {1: 3.0, 2: 3.0} - nd = nx.average_neighbor_degree(G, nodes=[1, 2]) - assert nd == answer - - def test_degree_barrat(self): - G = nx.star_graph(5) - G.add_edges_from([(5, 6), (5, 7), (5, 8), (5, 9)]) - G[0][5]["weight"] = 5 - nd = nx.average_neighbor_degree(G)[5] - assert nd == 1.8 - nd = nx.average_neighbor_degree(G, weight="weight")[5] - assert nd == pytest.approx(3.222222, abs=1e-5) - - def test_error_invalid_source_target(self): - G = nx.path_graph(4) - with pytest.raises(nx.NetworkXError): - nx.average_neighbor_degree(G, "error") - with pytest.raises(nx.NetworkXError): - nx.average_neighbor_degree(G, "in", "error") - G = G.to_directed() - with pytest.raises(nx.NetworkXError): - nx.average_neighbor_degree(G, "error") - with pytest.raises(nx.NetworkXError): - nx.average_neighbor_degree(G, "in", "error") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_pairs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_pairs.py deleted file mode 100644 index 3984292..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/assortativity/tests/test_pairs.py +++ /dev/null @@ -1,87 +0,0 @@ -import networkx as nx - -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing - - -class TestAttributeMixingXY(BaseTestAttributeMixing): - def test_node_attribute_xy_undirected(self): - attrxy = sorted(nx.node_attribute_xy(self.G, "fish")) - attrxy_result = sorted( - [ - ("one", "one"), - ("one", "one"), - ("two", "two"), - ("two", "two"), - ("one", "red"), - ("red", "one"), - ("blue", "two"), - ("two", "blue"), - ] - ) - assert attrxy == attrxy_result - - def test_node_attribute_xy_undirected_nodes(self): - attrxy = sorted(nx.node_attribute_xy(self.G, "fish", nodes=["one", "yellow"])) - attrxy_result = sorted([]) - assert attrxy == attrxy_result - - def test_node_attribute_xy_directed(self): - attrxy = sorted(nx.node_attribute_xy(self.D, "fish")) - attrxy_result = sorted( - [("one", "one"), ("two", "two"), ("one", "red"), ("two", "blue")] - ) - assert attrxy == attrxy_result - - def test_node_attribute_xy_multigraph(self): - attrxy = sorted(nx.node_attribute_xy(self.M, "fish")) - attrxy_result = [ - ("one", "one"), - ("one", "one"), - ("one", "one"), - ("one", "one"), - ("two", "two"), - ("two", "two"), - ] - assert attrxy == attrxy_result - - def test_node_attribute_xy_selfloop(self): - attrxy = sorted(nx.node_attribute_xy(self.S, "fish")) - attrxy_result = [("one", "one"), ("two", "two")] - assert attrxy == attrxy_result - - -class TestDegreeMixingXY(BaseTestDegreeMixing): - def test_node_degree_xy_undirected(self): - xy = sorted(nx.node_degree_xy(self.P4)) - xy_result = sorted([(1, 2), (2, 1), (2, 2), (2, 2), (1, 2), (2, 1)]) - assert xy == xy_result - - def test_node_degree_xy_undirected_nodes(self): - xy = sorted(nx.node_degree_xy(self.P4, nodes=[0, 1, -1])) - xy_result = sorted([(1, 2), (2, 1)]) - assert xy == xy_result - - def test_node_degree_xy_directed(self): - xy = sorted(nx.node_degree_xy(self.D)) - xy_result = sorted([(2, 1), (2, 3), (1, 3), (1, 3)]) - assert xy == xy_result - - def test_node_degree_xy_multigraph(self): - xy = sorted(nx.node_degree_xy(self.M)) - xy_result = sorted( - [(2, 3), (2, 3), (3, 2), (3, 2), (2, 3), (3, 2), (1, 2), (2, 1)] - ) - assert xy == xy_result - - def test_node_degree_xy_selfloop(self): - xy = sorted(nx.node_degree_xy(self.S)) - xy_result = sorted([(2, 2), (2, 2)]) - assert xy == xy_result - - def test_node_degree_xy_weighted(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7) - G.add_edge(2, 3, weight=10) - xy = sorted(nx.node_degree_xy(G, weight="weight")) - xy_result = sorted([(7, 17), (17, 10), (17, 7), (10, 17)]) - assert xy == xy_result diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/asteroidal.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/asteroidal.py deleted file mode 100644 index 3f9b2ab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/asteroidal.py +++ /dev/null @@ -1,171 +0,0 @@ -""" -Algorithms for asteroidal triples and asteroidal numbers in graphs. - -An asteroidal triple in a graph G is a set of three non-adjacent vertices -u, v and w such that there exist a path between any two of them that avoids -closed neighborhood of the third. More formally, v_j, v_k belongs to the same -connected component of G - N[v_i], where N[v_i] denotes the closed neighborhood -of v_i. A graph which does not contain any asteroidal triples is called -an AT-free graph. The class of AT-free graphs is a graph class for which -many NP-complete problems are solvable in polynomial time. Amongst them, -independent set and coloring. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["is_at_free", "find_asteroidal_triple"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def find_asteroidal_triple(G): - r"""Find an asteroidal triple in the given graph. - - An asteroidal triple is a triple of non-adjacent vertices such that - there exists a path between any two of them which avoids the closed - neighborhood of the third. It checks all independent triples of vertices - and whether they are an asteroidal triple or not. This is done with the - help of a data structure called a component structure. - A component structure encodes information about which vertices belongs to - the same connected component when the closed neighborhood of a given vertex - is removed from the graph. The algorithm used to check is the trivial - one, outlined in [1]_, which has a runtime of - :math:`O(|V||\overline{E} + |V||E|)`, where the second term is the - creation of the component structure. - - Parameters - ---------- - G : NetworkX Graph - The graph to check whether is AT-free or not - - Returns - ------- - list or None - An asteroidal triple is returned as a list of nodes. If no asteroidal - triple exists, i.e. the graph is AT-free, then None is returned. - The returned value depends on the certificate parameter. The default - option is a bool which is True if the graph is AT-free, i.e. the - given graph contains no asteroidal triples, and False otherwise, i.e. - if the graph contains at least one asteroidal triple. - - Notes - ----- - The component structure and the algorithm is described in [1]_. The current - implementation implements the trivial algorithm for simple graphs. - - References - ---------- - .. [1] Ekkehard Köhler, - "Recognizing Graphs without asteroidal triples", - Journal of Discrete Algorithms 2, pages 439-452, 2004. - https://www.sciencedirect.com/science/article/pii/S157086670400019X - """ - V = set(G.nodes) - - if len(V) < 6: - # An asteroidal triple cannot exist in a graph with 5 or less vertices. - return None - - component_structure = create_component_structure(G) - E_complement = set(nx.complement(G).edges) - - for e in E_complement: - u = e[0] - v = e[1] - u_neighborhood = set(G[u]).union([u]) - v_neighborhood = set(G[v]).union([v]) - union_of_neighborhoods = u_neighborhood.union(v_neighborhood) - for w in V - union_of_neighborhoods: - # Check for each pair of vertices whether they belong to the - # same connected component when the closed neighborhood of the - # third is removed. - if ( - component_structure[u][v] == component_structure[u][w] - and component_structure[v][u] == component_structure[v][w] - and component_structure[w][u] == component_structure[w][v] - ): - return [u, v, w] - return None - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_at_free(G): - """Check if a graph is AT-free. - - The method uses the `find_asteroidal_triple` method to recognize - an AT-free graph. If no asteroidal triple is found the graph is - AT-free and True is returned. If at least one asteroidal triple is - found the graph is not AT-free and False is returned. - - Parameters - ---------- - G : NetworkX Graph - The graph to check whether is AT-free or not. - - Returns - ------- - bool - True if G is AT-free and False otherwise. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - >>> nx.is_at_free(G) - True - - >>> G = nx.cycle_graph(6) - >>> nx.is_at_free(G) - False - """ - return find_asteroidal_triple(G) is None - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def create_component_structure(G): - r"""Create component structure for G. - - A *component structure* is an `nxn` array, denoted `c`, where `n` is - the number of vertices, where each row and column corresponds to a vertex. - - .. math:: - c_{uv} = \begin{cases} 0, if v \in N[u] \\ - k, if v \in component k of G \setminus N[u] \end{cases} - - Where `k` is an arbitrary label for each component. The structure is used - to simplify the detection of asteroidal triples. - - Parameters - ---------- - G : NetworkX Graph - Undirected, simple graph. - - Returns - ------- - component_structure : dictionary - A dictionary of dictionaries, keyed by pairs of vertices. - - """ - V = set(G.nodes) - component_structure = {} - for v in V: - label = 0 - closed_neighborhood = set(G[v]).union({v}) - row_dict = {} - for u in closed_neighborhood: - row_dict[u] = 0 - - G_reduced = G.subgraph(set(G.nodes) - closed_neighborhood) - for cc in nx.connected_components(G_reduced): - label += 1 - for u in cc: - row_dict[u] = label - - component_structure[v] = row_dict - - return component_structure diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/__init__.py deleted file mode 100644 index 7839db9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -r"""This module provides functions and operations for bipartite -graphs. Bipartite graphs `B = (U, V, E)` have two node sets `U,V` and edges in -`E` that only connect nodes from opposite sets. It is common in the literature -to use an spatial analogy referring to the two node sets as top and bottom nodes. - -The bipartite algorithms are not imported into the networkx namespace -at the top level so the easiest way to use them is with: - ->>> from networkx.algorithms import bipartite - -NetworkX does not have a custom bipartite graph class but the Graph() -or DiGraph() classes can be used to represent bipartite graphs. However, -you have to keep track of which set each node belongs to, and make -sure that there is no edge between nodes of the same set. The convention used -in NetworkX is to use a node attribute named `bipartite` with values 0 or 1 to -identify the sets each node belongs to. This convention is not enforced in -the source code of bipartite functions, it's only a recommendation. - -For example: - ->>> B = nx.Graph() ->>> # Add nodes with the node attribute "bipartite" ->>> B.add_nodes_from([1, 2, 3, 4], bipartite=0) ->>> B.add_nodes_from(["a", "b", "c"], bipartite=1) ->>> # Add edges only between nodes of opposite node sets ->>> B.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")]) - -Many algorithms of the bipartite module of NetworkX require, as an argument, a -container with all the nodes that belong to one set, in addition to the bipartite -graph `B`. The functions in the bipartite package do not check that the node set -is actually correct nor that the input graph is actually bipartite. -If `B` is connected, you can find the two node sets using a two-coloring -algorithm: - ->>> nx.is_connected(B) -True ->>> bottom_nodes, top_nodes = bipartite.sets(B) - -However, if the input graph is not connected, there are more than one possible -colorations. This is the reason why we require the user to pass a container -with all nodes of one bipartite node set as an argument to most bipartite -functions. In the face of ambiguity, we refuse the temptation to guess and -raise an :exc:`AmbiguousSolution ` -Exception if the input graph for -:func:`bipartite.sets ` -is disconnected. - -Using the `bipartite` node attribute, you can easily get the two node sets: - ->>> top_nodes = {n for n, d in B.nodes(data=True) if d["bipartite"] == 0} ->>> bottom_nodes = set(B) - top_nodes - -So you can easily use the bipartite algorithms that require, as an argument, a -container with all nodes that belong to one node set: - ->>> print(round(bipartite.density(B, bottom_nodes), 2)) -0.5 ->>> G = bipartite.projected_graph(B, top_nodes) - -All bipartite graph generators in NetworkX build bipartite graphs with the -`bipartite` node attribute. Thus, you can use the same approach: - ->>> RB = bipartite.random_graph(5, 7, 0.2) ->>> RB_top = {n for n, d in RB.nodes(data=True) if d["bipartite"] == 0} ->>> RB_bottom = set(RB) - RB_top ->>> list(RB_top) -[0, 1, 2, 3, 4] ->>> list(RB_bottom) -[5, 6, 7, 8, 9, 10, 11] - -For other bipartite graph generators see -:mod:`Generators `. - -""" - -from networkx.algorithms.bipartite.basic import * -from networkx.algorithms.bipartite.centrality import * -from networkx.algorithms.bipartite.cluster import * -from networkx.algorithms.bipartite.covering import * -from networkx.algorithms.bipartite.edgelist import * -from networkx.algorithms.bipartite.matching import * -from networkx.algorithms.bipartite.matrix import * -from networkx.algorithms.bipartite.projection import * -from networkx.algorithms.bipartite.redundancy import * -from networkx.algorithms.bipartite.spectral import * -from networkx.algorithms.bipartite.generators import * -from networkx.algorithms.bipartite.extendability import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/basic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/basic.py deleted file mode 100644 index 8d9a4d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/basic.py +++ /dev/null @@ -1,322 +0,0 @@ -""" -========================== -Bipartite Graph Algorithms -========================== -""" - -import networkx as nx -from networkx.algorithms.components import connected_components -from networkx.exception import AmbiguousSolution - -__all__ = [ - "is_bipartite", - "is_bipartite_node_set", - "color", - "sets", - "density", - "degrees", -] - - -@nx._dispatchable -def color(G): - """Returns a two-coloring of the graph. - - Raises an exception if the graph is not bipartite. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - color : dictionary - A dictionary keyed by node with a 1 or 0 as data for each node color. - - Raises - ------ - NetworkXError - If the graph is not two-colorable. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> c = bipartite.color(G) - >>> print(c) - {0: 1, 1: 0, 2: 1, 3: 0} - - You can use this to set a node attribute indicating the bipartite set: - - >>> nx.set_node_attributes(G, c, "bipartite") - >>> print(G.nodes[0]["bipartite"]) - 1 - >>> print(G.nodes[1]["bipartite"]) - 0 - """ - if G.is_directed(): - import itertools - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)]) - - else: - neighbors = G.neighbors - - color = {} - for n in G: # handle disconnected graphs - if n in color or len(G[n]) == 0: # skip isolates - continue - queue = [n] - color[n] = 1 # nodes seen with color (1 or 0) - while queue: - v = queue.pop() - c = 1 - color[v] # opposite color of node v - for w in neighbors(v): - if w in color: - if color[w] == color[v]: - raise nx.NetworkXError("Graph is not bipartite.") - else: - color[w] = c - queue.append(w) - # color isolates with 0 - color.update(dict.fromkeys(nx.isolates(G), 0)) - return color - - -@nx._dispatchable -def is_bipartite(G): - """Returns True if graph G is bipartite, False if not. - - Parameters - ---------- - G : NetworkX graph - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> print(bipartite.is_bipartite(G)) - True - - See Also - -------- - color, is_bipartite_node_set - """ - try: - color(G) - return True - except nx.NetworkXError: - return False - - -@nx._dispatchable -def is_bipartite_node_set(G, nodes): - """Returns True if nodes and G/nodes are a bipartition of G. - - Parameters - ---------- - G : NetworkX graph - - nodes: list or container - Check if nodes are a one of a bipartite set. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> X = set([1, 3]) - >>> bipartite.is_bipartite_node_set(G, X) - True - - Notes - ----- - An exception is raised if the input nodes are not distinct, because in this - case some bipartite algorithms will yield incorrect results. - For connected graphs the bipartite sets are unique. This function handles - disconnected graphs. - """ - S = set(nodes) - - if len(S) < len(nodes): - # this should maybe just return False? - raise AmbiguousSolution( - "The input node set contains duplicates.\n" - "This may lead to incorrect results when using it in bipartite algorithms.\n" - "Consider using set(nodes) as the input" - ) - - for CC in (G.subgraph(c).copy() for c in connected_components(G)): - X, Y = sets(CC) - if not ( - (X.issubset(S) and Y.isdisjoint(S)) or (Y.issubset(S) and X.isdisjoint(S)) - ): - return False - return True - - -@nx._dispatchable -def sets(G, top_nodes=None): - """Returns bipartite node sets of graph G. - - Raises an exception if the graph is not bipartite or if the input - graph is disconnected and thus more than one valid solution exists. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - Parameters - ---------- - G : NetworkX graph - - top_nodes : container, optional - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - X : set - Nodes from one side of the bipartite graph. - Y : set - Nodes from the other side. - - Raises - ------ - AmbiguousSolution - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - NetworkXError - Raised if the input graph is not bipartite. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> X, Y = bipartite.sets(G) - >>> list(X) - [0, 2] - >>> list(Y) - [1, 3] - - See Also - -------- - color - - """ - if G.is_directed(): - is_connected = nx.is_weakly_connected - else: - is_connected = nx.is_connected - if top_nodes is not None: - X = set(top_nodes) - Y = set(G) - X - else: - if not is_connected(G): - msg = "Disconnected graph: Ambiguous solution for bipartite sets." - raise nx.AmbiguousSolution(msg) - c = color(G) - X = {n for n, is_top in c.items() if is_top} - Y = {n for n, is_top in c.items() if not is_top} - return (X, Y) - - -@nx._dispatchable(graphs="B") -def density(B, nodes): - """Returns density of bipartite graph B. - - Parameters - ---------- - B : NetworkX graph - - nodes: list or container - Nodes in one node set of the bipartite graph. - - Returns - ------- - d : float - The bipartite density - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.complete_bipartite_graph(3, 2) - >>> X = set([0, 1, 2]) - >>> bipartite.density(G, X) - 1.0 - >>> Y = set([3, 4]) - >>> bipartite.density(G, Y) - 1.0 - - Notes - ----- - The container of nodes passed as argument must contain all nodes - in one of the two bipartite node sets to avoid ambiguity in the - case of disconnected graphs. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - color - """ - n = len(B) - m = nx.number_of_edges(B) - nb = len(nodes) - nt = n - nb - if m == 0: # includes cases n==0 and n==1 - d = 0.0 - else: - if B.is_directed(): - d = m / (2 * nb * nt) - else: - d = m / (nb * nt) - return d - - -@nx._dispatchable(graphs="B", edge_attrs="weight") -def degrees(B, nodes, weight=None): - """Returns the degrees of the two node sets in the bipartite graph B. - - Parameters - ---------- - B : NetworkX graph - - nodes: list or container - Nodes in one node set of the bipartite graph. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - (degX,degY) : tuple of dictionaries - The degrees of the two bipartite sets as dictionaries keyed by node. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.complete_bipartite_graph(3, 2) - >>> Y = set([3, 4]) - >>> degX, degY = bipartite.degrees(G, Y) - >>> dict(degX) - {0: 2, 1: 2, 2: 2} - - Notes - ----- - The container of nodes passed as argument must contain all nodes - in one of the two bipartite node sets to avoid ambiguity in the - case of disconnected graphs. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - color, density - """ - bottom = set(nodes) - top = set(B) - bottom - return (B.degree(top, weight), B.degree(bottom, weight)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/centrality.py deleted file mode 100644 index 42d7270..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/centrality.py +++ /dev/null @@ -1,290 +0,0 @@ -import networkx as nx - -__all__ = ["degree_centrality", "betweenness_centrality", "closeness_centrality"] - - -@nx._dispatchable(name="bipartite_degree_centrality") -def degree_centrality(G, nodes): - r"""Compute the degree centrality for nodes in a bipartite network. - - The degree centrality for a node `v` is the fraction of nodes - connected to it. - - Parameters - ---------- - G : graph - A bipartite network - - nodes : list or container - Container with all nodes in one bipartite node set. - - Returns - ------- - centrality : dictionary - Dictionary keyed by node with bipartite degree centrality as the value. - - Examples - -------- - >>> G = nx.wheel_graph(5) - >>> top_nodes = {0, 1, 2} - >>> nx.bipartite.degree_centrality(G, nodes=top_nodes) - {0: 2.0, 1: 1.5, 2: 1.5, 3: 1.0, 4: 1.0} - - See Also - -------- - betweenness_centrality - closeness_centrality - :func:`~networkx.algorithms.bipartite.basic.sets` - :func:`~networkx.algorithms.bipartite.basic.is_bipartite` - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both bipartite node - sets. See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - For unipartite networks, the degree centrality values are - normalized by dividing by the maximum possible degree (which is - `n-1` where `n` is the number of nodes in G). - - In the bipartite case, the maximum possible degree of a node in a - bipartite node set is the number of nodes in the opposite node set - [1]_. The degree centrality for a node `v` in the bipartite - sets `U` with `n` nodes and `V` with `m` nodes is - - .. math:: - - d_{v} = \frac{deg(v)}{m}, \mbox{for} v \in U , - - d_{v} = \frac{deg(v)}{n}, \mbox{for} v \in V , - - - where `deg(v)` is the degree of node `v`. - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - https://dx.doi.org/10.4135/9781446294413.n28 - """ - top = set(nodes) - bottom = set(G) - top - s = 1.0 / len(bottom) - centrality = {n: d * s for n, d in G.degree(top)} - s = 1.0 / len(top) - centrality.update({n: d * s for n, d in G.degree(bottom)}) - return centrality - - -@nx._dispatchable(name="bipartite_betweenness_centrality") -def betweenness_centrality(G, nodes): - r"""Compute betweenness centrality for nodes in a bipartite network. - - Betweenness centrality of a node `v` is the sum of the - fraction of all-pairs shortest paths that pass through `v`. - - Values of betweenness are normalized by the maximum possible - value which for bipartite graphs is limited by the relative size - of the two node sets [1]_. - - Let `n` be the number of nodes in the node set `U` and - `m` be the number of nodes in the node set `V`, then - nodes in `U` are normalized by dividing by - - .. math:: - - \frac{1}{2} [m^2 (s + 1)^2 + m (s + 1)(2t - s - 1) - t (2s - t + 3)] , - - where - - .. math:: - - s = (n - 1) \div m , t = (n - 1) \mod m , - - and nodes in `V` are normalized by dividing by - - .. math:: - - \frac{1}{2} [n^2 (p + 1)^2 + n (p + 1)(2r - p - 1) - r (2p - r + 3)] , - - where, - - .. math:: - - p = (m - 1) \div n , r = (m - 1) \mod n . - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or container - Container with all nodes in one bipartite node set. - - Returns - ------- - betweenness : dictionary - Dictionary keyed by node with bipartite betweenness centrality - as the value. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> top_nodes = {1, 2} - >>> nx.bipartite.betweenness_centrality(G, nodes=top_nodes) - {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - - See Also - -------- - degree_centrality - closeness_centrality - :func:`~networkx.algorithms.bipartite.basic.sets` - :func:`~networkx.algorithms.bipartite.basic.is_bipartite` - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both node sets. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - https://dx.doi.org/10.4135/9781446294413.n28 - """ - top = set(nodes) - bottom = set(G) - top - n = len(top) - m = len(bottom) - s, t = divmod(n - 1, m) - bet_max_top = ( - ((m**2) * ((s + 1) ** 2)) - + (m * (s + 1) * (2 * t - s - 1)) - - (t * ((2 * s) - t + 3)) - ) / 2.0 - p, r = divmod(m - 1, n) - bet_max_bot = ( - ((n**2) * ((p + 1) ** 2)) - + (n * (p + 1) * (2 * r - p - 1)) - - (r * ((2 * p) - r + 3)) - ) / 2.0 - betweenness = nx.betweenness_centrality(G, normalized=False, weight=None) - for node in top: - betweenness[node] /= bet_max_top - for node in bottom: - betweenness[node] /= bet_max_bot - return betweenness - - -@nx._dispatchable(name="bipartite_closeness_centrality") -def closeness_centrality(G, nodes, normalized=True): - r"""Compute the closeness centrality for nodes in a bipartite network. - - The closeness of a node is the distance to all other nodes in the - graph or in the case that the graph is not connected to all other nodes - in the connected component containing that node. - - Parameters - ---------- - G : graph - A bipartite network - - nodes : list or container - Container with all nodes in one bipartite node set. - - normalized : bool, optional - If True (default) normalize by connected component size. - - Returns - ------- - closeness : dictionary - Dictionary keyed by node with bipartite closeness centrality - as the value. - - Examples - -------- - >>> G = nx.wheel_graph(5) - >>> top_nodes = {0, 1, 2} - >>> nx.bipartite.closeness_centrality(G, nodes=top_nodes) - {0: 1.5, 1: 1.2, 2: 1.2, 3: 1.0, 4: 1.0} - - See Also - -------- - betweenness_centrality - degree_centrality - :func:`~networkx.algorithms.bipartite.basic.sets` - :func:`~networkx.algorithms.bipartite.basic.is_bipartite` - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both node sets. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - Closeness centrality is normalized by the minimum distance possible. - In the bipartite case the minimum distance for a node in one bipartite - node set is 1 from all nodes in the other node set and 2 from all - other nodes in its own set [1]_. Thus the closeness centrality - for node `v` in the two bipartite sets `U` with - `n` nodes and `V` with `m` nodes is - - .. math:: - - c_{v} = \frac{m + 2(n - 1)}{d}, \mbox{for} v \in U, - - c_{v} = \frac{n + 2(m - 1)}{d}, \mbox{for} v \in V, - - where `d` is the sum of the distances from `v` to all - other nodes. - - Higher values of closeness indicate higher centrality. - - As in the unipartite case, setting normalized=True causes the - values to normalized further to n-1 / size(G)-1 where n is the - number of nodes in the connected part of graph containing the - node. If the graph is not completely connected, this algorithm - computes the closeness centrality for each connected part - separately. - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - https://dx.doi.org/10.4135/9781446294413.n28 - """ - closeness = {} - path_length = nx.single_source_shortest_path_length - top = set(nodes) - bottom = set(G) - top - n = len(top) - m = len(bottom) - for node in top: - sp = dict(path_length(G, node)) - totsp = sum(sp.values()) - if totsp > 0.0 and len(G) > 1: - closeness[node] = (m + 2 * (n - 1)) / totsp - if normalized: - s = (len(sp) - 1) / (len(G) - 1) - closeness[node] *= s - else: - closeness[node] = 0.0 - for node in bottom: - sp = dict(path_length(G, node)) - totsp = sum(sp.values()) - if totsp > 0.0 and len(G) > 1: - closeness[node] = (n + 2 * (m - 1)) / totsp - if normalized: - s = (len(sp) - 1) / (len(G) - 1) - closeness[node] *= s - else: - closeness[node] = 0.0 - return closeness diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/cluster.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/cluster.py deleted file mode 100644 index 5b66b28..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/cluster.py +++ /dev/null @@ -1,278 +0,0 @@ -"""Functions for computing clustering of pairs""" - -import itertools - -import networkx as nx - -__all__ = [ - "clustering", - "average_clustering", - "latapy_clustering", - "robins_alexander_clustering", -] - - -def cc_dot(nu, nv): - return len(nu & nv) / len(nu | nv) - - -def cc_max(nu, nv): - return len(nu & nv) / max(len(nu), len(nv)) - - -def cc_min(nu, nv): - return len(nu & nv) / min(len(nu), len(nv)) - - -modes = {"dot": cc_dot, "min": cc_min, "max": cc_max} - - -@nx._dispatchable -def latapy_clustering(G, nodes=None, mode="dot"): - r"""Compute a bipartite clustering coefficient for nodes. - - The bipartite clustering coefficient is a measure of local density - of connections defined as [1]_: - - .. math:: - - c_u = \frac{\sum_{v \in N(N(u))} c_{uv} }{|N(N(u))|} - - where `N(N(u))` are the second order neighbors of `u` in `G` excluding `u`, - and `c_{uv}` is the pairwise clustering coefficient between nodes - `u` and `v`. - - The mode selects the function for `c_{uv}` which can be: - - `dot`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{|N(u) \cup N(v)|} - - `min`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{min(|N(u)|,|N(v)|)} - - `max`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{max(|N(u)|,|N(v)|)} - - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or iterable (optional) - Compute bipartite clustering for these nodes. The default - is all nodes in G. - - mode : string - The pairwise bipartite clustering method to be used in the computation. - It must be "dot", "max", or "min". - - Returns - ------- - clustering : dictionary - A dictionary keyed by node with the clustering coefficient value. - - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) # path graphs are bipartite - >>> c = bipartite.clustering(G) - >>> c[0] - 0.5 - >>> c = bipartite.clustering(G, mode="min") - >>> c[0] - 1.0 - - See Also - -------- - robins_alexander_clustering - average_clustering - networkx.algorithms.cluster.square_clustering - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - """ - if not nx.algorithms.bipartite.is_bipartite(G): - raise nx.NetworkXError("Graph is not bipartite") - - try: - cc_func = modes[mode] - except KeyError as err: - raise nx.NetworkXError( - "Mode for bipartite clustering must be: dot, min or max" - ) from err - - if nodes is None: - nodes = G - ccs = {} - for v in nodes: - cc = 0.0 - nbrs2 = {u for nbr in G[v] for u in G[nbr]} - {v} - for u in nbrs2: - cc += cc_func(set(G[u]), set(G[v])) - if cc > 0.0: # len(nbrs2)>0 - cc /= len(nbrs2) - ccs[v] = cc - return ccs - - -clustering = latapy_clustering - - -@nx._dispatchable(name="bipartite_average_clustering") -def average_clustering(G, nodes=None, mode="dot"): - r"""Compute the average bipartite clustering coefficient. - - A clustering coefficient for the whole graph is the average, - - .. math:: - - C = \frac{1}{n}\sum_{v \in G} c_v, - - where `n` is the number of nodes in `G`. - - Similar measures for the two bipartite sets can be defined [1]_ - - .. math:: - - C_X = \frac{1}{|X|}\sum_{v \in X} c_v, - - where `X` is a bipartite set of `G`. - - Parameters - ---------- - G : graph - a bipartite graph - - nodes : list or iterable, optional - A container of nodes to use in computing the average. - The nodes should be either the entire graph (the default) or one of the - bipartite sets. - - mode : string - The pairwise bipartite clustering method. - It must be "dot", "max", or "min" - - Returns - ------- - clustering : float - The average bipartite clustering for the given set of nodes or the - entire graph if no nodes are specified. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.star_graph(3) # star graphs are bipartite - >>> bipartite.average_clustering(G) - 0.75 - >>> X, Y = bipartite.sets(G) - >>> bipartite.average_clustering(G, X) - 0.0 - >>> bipartite.average_clustering(G, Y) - 1.0 - - See Also - -------- - clustering - - Notes - ----- - The container of nodes passed to this function must contain all of the nodes - in one of the bipartite sets ("top" or "bottom") in order to compute - the correct average bipartite clustering coefficients. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - """ - if nodes is None: - nodes = G - ccs = latapy_clustering(G, nodes=nodes, mode=mode) - return sum(ccs[v] for v in nodes) / len(nodes) - - -@nx._dispatchable -def robins_alexander_clustering(G): - r"""Compute the bipartite clustering of G. - - Robins and Alexander [1]_ defined bipartite clustering coefficient as - four times the number of four cycles `C_4` divided by the number of - three paths `L_3` in a bipartite graph: - - .. math:: - - CC_4 = \frac{4 * C_4}{L_3} - - Parameters - ---------- - G : graph - a bipartite graph - - Returns - ------- - clustering : float - The Robins and Alexander bipartite clustering for the input graph. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.davis_southern_women_graph() - >>> print(round(bipartite.robins_alexander_clustering(G), 3)) - 0.468 - - See Also - -------- - latapy_clustering - networkx.algorithms.cluster.square_clustering - - References - ---------- - .. [1] Robins, G. and M. Alexander (2004). Small worlds among interlocking - directors: Network structure and distance in bipartite graphs. - Computational & Mathematical Organization Theory 10(1), 69–94. - - """ - if G.order() < 4 or G.size() < 3: - return 0 - L_3 = _threepaths(G) - if L_3 == 0: - return 0 - C_4 = _four_cycles(G) - return (4.0 * C_4) / L_3 - - -def _four_cycles(G): - cycles = 0 - for v in G: - for u, w in itertools.combinations(G[v], 2): - cycles += len((set(G[u]) & set(G[w])) - {v}) - return cycles / 4 - - -def _threepaths(G): - paths = 0 - for v in G: - for u in G[v]: - for w in set(G[u]) - {v}: - paths += len(set(G[w]) - {v, u}) - # Divide by two because we count each three path twice - # one for each possible starting point - return paths / 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/covering.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/covering.py deleted file mode 100644 index f937903..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/covering.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Functions related to graph covers.""" - -import networkx as nx -from networkx.algorithms.bipartite.matching import hopcroft_karp_matching -from networkx.algorithms.covering import min_edge_cover as _min_edge_cover -from networkx.utils import not_implemented_for - -__all__ = ["min_edge_cover"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(name="bipartite_min_edge_cover") -def min_edge_cover(G, matching_algorithm=None): - """Returns a set of edges which constitutes - the minimum edge cover of the graph. - - The smallest edge cover can be found in polynomial time by finding - a maximum matching and extending it greedily so that all nodes - are covered. - - Parameters - ---------- - G : NetworkX graph - An undirected bipartite graph. - - matching_algorithm : function - A function that returns a maximum cardinality matching in a - given bipartite graph. The function must take one input, the - graph ``G``, and return a dictionary mapping each node to its - mate. If not specified, - :func:`~networkx.algorithms.bipartite.matching.hopcroft_karp_matching` - will be used. Other possibilities include - :func:`~networkx.algorithms.bipartite.matching.eppstein_matching`, - - Returns - ------- - set - A set of the edges in a minimum edge cover of the graph, given as - pairs of nodes. It contains both the edges `(u, v)` and `(v, u)` - for given nodes `u` and `v` among the edges of minimum edge cover. - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - A minimum edge cover is an edge covering of smallest cardinality. - - Due to its implementation, the worst-case running time of this algorithm - is bounded by the worst-case running time of the function - ``matching_algorithm``. - """ - if G.order() == 0: # Special case for the empty graph - return set() - if matching_algorithm is None: - matching_algorithm = hopcroft_karp_matching - return _min_edge_cover(G, matching_algorithm=matching_algorithm) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/edgelist.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/edgelist.py deleted file mode 100644 index db6ef9d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/edgelist.py +++ /dev/null @@ -1,360 +0,0 @@ -""" -******************** -Bipartite Edge Lists -******************** -Read and write NetworkX graphs as bipartite edge lists. - -Format ------- -You can read or write three formats of edge lists with these functions. - -Node pairs with no data:: - - 1 2 - -Python dictionary as data:: - - 1 2 {'weight':7, 'color':'green'} - -Arbitrary data:: - - 1 2 7 green - -For each edge (u, v) the node u is assigned to part 0 and the node v to part 1. -""" - -__all__ = ["generate_edgelist", "write_edgelist", "parse_edgelist", "read_edgelist"] - -import networkx as nx -from networkx.utils import not_implemented_for, open_file - - -@open_file(1, mode="wb") -def write_edgelist(G, path, comments="#", delimiter=" ", data=True, encoding="utf-8"): - """Write a bipartite graph as a list of edges. - - Parameters - ---------- - G : Graph - A NetworkX bipartite graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - data : bool or list, optional - If False write no edge data. - If True write a string representation of the edge data dictionary.. - If a list (or other iterable) is provided, write the keys specified - in the list. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G.add_nodes_from([0, 2], bipartite=0) - >>> G.add_nodes_from([1, 3], bipartite=1) - >>> nx.write_edgelist(G, "test.edgelist") - >>> fh = open("test.edgelist", "wb") - >>> nx.write_edgelist(G, fh) - >>> nx.write_edgelist(G, "test.edgelist.gz") - >>> nx.write_edgelist(G, "test.edgelist.gz", data=False) - - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=7, color="red") - >>> nx.write_edgelist(G, "test.edgelist", data=False) - >>> nx.write_edgelist(G, "test.edgelist", data=["color"]) - >>> nx.write_edgelist(G, "test.edgelist", data=["color", "weight"]) - - See Also - -------- - write_edgelist - generate_edgelist - """ - for line in generate_edgelist(G, delimiter, data): - line += "\n" - path.write(line.encode(encoding)) - - -@not_implemented_for("directed") -def generate_edgelist(G, delimiter=" ", data=True): - """Generate a single line of the bipartite graph G in edge list format. - - Parameters - ---------- - G : NetworkX graph - The graph is assumed to have node attribute `part` set to 0,1 representing - the two graph parts - - delimiter : string, optional - Separator for node labels - - data : bool or list of keys - If False generate no edge data. If True use a dictionary - representation of edge data. If a list of keys use a list of data - values corresponding to the keys. - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> G.add_nodes_from([0, 2], bipartite=0) - >>> G.add_nodes_from([1, 3], bipartite=1) - >>> G[1][2]["weight"] = 3 - >>> G[2][3]["capacity"] = 12 - >>> for line in bipartite.generate_edgelist(G, data=False): - ... print(line) - 0 1 - 2 1 - 2 3 - - >>> for line in bipartite.generate_edgelist(G): - ... print(line) - 0 1 {} - 2 1 {'weight': 3} - 2 3 {'capacity': 12} - - >>> for line in bipartite.generate_edgelist(G, data=["weight"]): - ... print(line) - 0 1 - 2 1 3 - 2 3 - """ - try: - part0 = [n for n, d in G.nodes.items() if d["bipartite"] == 0] - except BaseException as err: - raise AttributeError("Missing node attribute `bipartite`") from err - if data is True or data is False: - for n in part0: - for edge in G.edges(n, data=data): - yield delimiter.join(map(str, edge)) - else: - for n in part0: - for u, v, d in G.edges(n, data=True): - edge = [u, v] - try: - edge.extend(d[k] for k in data) - except KeyError: - pass # missing data for this edge, should warn? - yield delimiter.join(map(str, edge)) - - -@nx._dispatchable(name="bipartite_parse_edgelist", graphs=None, returns_graph=True) -def parse_edgelist( - lines, comments="#", delimiter=None, create_using=None, nodetype=None, data=True -): - """Parse lines of an edge list representation of a bipartite graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in edgelist format - comments : string, optional - Marker for comment lines - delimiter : string, optional - Separator for node labels - create_using: NetworkX graph container, optional - Use given NetworkX graph for holding nodes or edges. - nodetype : Python type, optional - Convert nodes to this type. - data : bool or list of (label,type) tuples - If False generate no edge data or if True use a dictionary - representation of edge data or a list tuples specifying dictionary - key names and types for edge data. - - Returns - ------- - G: NetworkX Graph - The bipartite graph corresponding to lines - - Examples - -------- - Edgelist with no data: - - >>> from networkx.algorithms import bipartite - >>> lines = ["1 2", "2 3", "3 4"] - >>> G = bipartite.parse_edgelist(lines, nodetype=int) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.nodes(data=True)) - [(1, {'bipartite': 0}), (2, {'bipartite': 0}), (3, {'bipartite': 0}), (4, {'bipartite': 1})] - >>> sorted(G.edges()) - [(1, 2), (2, 3), (3, 4)] - - Edgelist with data in Python dictionary representation: - - >>> lines = ["1 2 {'weight':3}", "2 3 {'weight':27}", "3 4 {'weight':3.0}"] - >>> G = bipartite.parse_edgelist(lines, nodetype=int) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.edges(data=True)) - [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] - - Edgelist with data in a list: - - >>> lines = ["1 2 3", "2 3 27", "3 4 3.0"] - >>> G = bipartite.parse_edgelist(lines, nodetype=int, data=(("weight", float),)) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.edges(data=True)) - [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] - - See Also - -------- - """ - from ast import literal_eval - - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not len(line): - continue - # split line, should have 2 or more - s = line.rstrip("\n").split(delimiter) - if len(s) < 2: - continue - u = s.pop(0) - v = s.pop(0) - d = s - if nodetype is not None: - try: - u = nodetype(u) - v = nodetype(v) - except BaseException as err: - raise TypeError( - f"Failed to convert nodes {u},{v} to type {nodetype}." - ) from err - - if len(d) == 0 or data is False: - # no data or data type specified - edgedata = {} - elif data is True: - # no edge types specified - try: # try to evaluate as dictionary - edgedata = dict(literal_eval(" ".join(d))) - except BaseException as err: - raise TypeError( - f"Failed to convert edge data ({d}) to dictionary." - ) from err - else: - # convert edge data to dictionary with specified keys and type - if len(d) != len(data): - raise IndexError( - f"Edge data {d} and data_keys {data} are not the same length" - ) - edgedata = {} - for (edge_key, edge_type), edge_value in zip(data, d): - try: - edge_value = edge_type(edge_value) - except BaseException as err: - raise TypeError( - f"Failed to convert {edge_key} data " - f"{edge_value} to type {edge_type}." - ) from err - edgedata.update({edge_key: edge_value}) - G.add_node(u, bipartite=0) - G.add_node(v, bipartite=1) - G.add_edge(u, v, **edgedata) - return G - - -@open_file(0, mode="rb") -@nx._dispatchable(name="bipartite_read_edgelist", graphs=None, returns_graph=True) -def read_edgelist( - path, - comments="#", - delimiter=None, - create_using=None, - nodetype=None, - data=True, - edgetype=None, - encoding="utf-8", -): - """Read a bipartite graph from a list of edges. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : Graph container, optional, - Use specified container to build graph. The default is networkx.Graph, - an undirected graph. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - data : bool or list of (label,type) tuples - Tuples specifying dictionary key names and types for edge data - edgetype : int, float, str, Python type, optional OBSOLETE - Convert edge data from strings to specified type and use as 'weight' - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> G.add_nodes_from([0, 2], bipartite=0) - >>> G.add_nodes_from([1, 3], bipartite=1) - >>> bipartite.write_edgelist(G, "test.edgelist") - >>> G = bipartite.read_edgelist("test.edgelist") - - >>> fh = open("test.edgelist", "rb") - >>> G = bipartite.read_edgelist(fh) - >>> fh.close() - - >>> G = bipartite.read_edgelist("test.edgelist", nodetype=int) - - Edgelist with data in a list: - - >>> textline = "1 2 3" - >>> fh = open("test.edgelist", "w") - >>> d = fh.write(textline) - >>> fh.close() - >>> G = bipartite.read_edgelist( - ... "test.edgelist", nodetype=int, data=(("weight", float),) - ... ) - >>> list(G) - [1, 2] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0})] - - See parse_edgelist() for more examples of formatting. - - See Also - -------- - parse_edgelist - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - """ - lines = (line.decode(encoding) for line in path) - return parse_edgelist( - lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - data=data, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/extendability.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/extendability.py deleted file mode 100644 index 61d8d06..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/extendability.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Provides a function for computing the extendability of a graph which is -undirected, simple, connected and bipartite and contains at least one perfect matching.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["maximal_extendability"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def maximal_extendability(G): - """Computes the extendability of a graph. - - The extendability of a graph is defined as the maximum $k$ for which `G` - is $k$-extendable. Graph `G` is $k$-extendable if and only if `G` has a - perfect matching and every set of $k$ independent edges can be extended - to a perfect matching in `G`. - - Parameters - ---------- - G : NetworkX Graph - A fully-connected bipartite graph without self-loops - - Returns - ------- - extendability : int - - Raises - ------ - NetworkXError - If the graph `G` is disconnected. - If the graph `G` is not bipartite. - If the graph `G` does not contain a perfect matching. - If the residual graph of `G` is not strongly connected. - - Notes - ----- - Definition: - Let `G` be a simple, connected, undirected and bipartite graph with a perfect - matching M and bipartition (U,V). The residual graph of `G`, denoted by $G_M$, - is the graph obtained from G by directing the edges of M from V to U and the - edges that do not belong to M from U to V. - - Lemma [1]_ : - Let M be a perfect matching of `G`. `G` is $k$-extendable if and only if its residual - graph $G_M$ is strongly connected and there are $k$ vertex-disjoint directed - paths between every vertex of U and every vertex of V. - - Assuming that input graph `G` is undirected, simple, connected, bipartite and contains - a perfect matching M, this function constructs the residual graph $G_M$ of G and - returns the minimum value among the maximum vertex-disjoint directed paths between - every vertex of U and every vertex of V in $G_M$. By combining the definitions - and the lemma, this value represents the extendability of the graph `G`. - - Time complexity O($n^3$ $m^2$)) where $n$ is the number of vertices - and $m$ is the number of edges. - - References - ---------- - .. [1] "A polynomial algorithm for the extendability problem in bipartite graphs", - J. Lakhal, L. Litzler, Information Processing Letters, 1998. - .. [2] "On n-extendible graphs", M. D. Plummer, Discrete Mathematics, 31:201–210, 1980 - https://doi.org/10.1016/0012-365X(80)90037-0 - - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph G is not connected") - - if not nx.bipartite.is_bipartite(G): - raise nx.NetworkXError("Graph G is not bipartite") - - U, V = nx.bipartite.sets(G) - - maximum_matching = nx.bipartite.hopcroft_karp_matching(G) - - if not nx.is_perfect_matching(G, maximum_matching): - raise nx.NetworkXError("Graph G does not contain a perfect matching") - - # list of edges in perfect matching, directed from V to U - pm = [(node, maximum_matching[node]) for node in V & maximum_matching.keys()] - - # Direct all the edges of G, from V to U if in matching, else from U to V - directed_edges = [ - (x, y) if (x in V and (x, y) in pm) or (x in U and (y, x) not in pm) else (y, x) - for x, y in G.edges - ] - - # Construct the residual graph of G - residual_G = nx.DiGraph() - residual_G.add_nodes_from(G) - residual_G.add_edges_from(directed_edges) - - if not nx.is_strongly_connected(residual_G): - raise nx.NetworkXError("The residual graph of G is not strongly connected") - - # For node-pairs between V & U, keep min of max number of node-disjoint paths - # Variable $k$ stands for the extendability of graph G - k = float("inf") - for u in U: - for v in V: - num_paths = sum(1 for _ in nx.node_disjoint_paths(residual_G, u, v)) - k = k if k < num_paths else num_paths - return k diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/generators.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/generators.py deleted file mode 100644 index e8428f6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/generators.py +++ /dev/null @@ -1,604 +0,0 @@ -""" -Generators and functions for bipartite graphs. -""" - -import math -import numbers -from functools import reduce - -import networkx as nx -from networkx.utils import nodes_or_number, py_random_state - -__all__ = [ - "configuration_model", - "havel_hakimi_graph", - "reverse_havel_hakimi_graph", - "alternating_havel_hakimi_graph", - "preferential_attachment_graph", - "random_graph", - "gnmk_random_graph", - "complete_bipartite_graph", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number([0, 1]) -def complete_bipartite_graph(n1, n2, create_using=None): - """Returns the complete bipartite graph `K_{n_1,n_2}`. - - The graph is composed of two partitions with nodes 0 to (n1 - 1) - in the first and nodes n1 to (n1 + n2 - 1) in the second. - Each node in the first is connected to each node in the second. - - Parameters - ---------- - n1, n2 : integer or iterable container of nodes - If integers, nodes are from `range(n1)` and `range(n1, n1 + n2)`. - If a container, the elements are the nodes. - create_using : NetworkX graph instance, (default: nx.Graph) - Return graph of this type. - - Notes - ----- - Nodes are the integers 0 to `n1 + n2 - 1` unless either n1 or n2 are - containers of nodes. If only one of n1 or n2 are integers, that - integer is replaced by `range` of that integer. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.complete_bipartite_graph - """ - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - n1, top = n1 - n2, bottom = n2 - if isinstance(n1, numbers.Integral) and isinstance(n2, numbers.Integral): - bottom = [n1 + i for i in bottom] - G.add_nodes_from(top, bipartite=0) - G.add_nodes_from(bottom, bipartite=1) - if len(G) != len(top) + len(bottom): - raise nx.NetworkXError("Inputs n1 and n2 must contain distinct nodes") - G.add_edges_from((u, v) for u in top for v in bottom) - G.graph["name"] = f"complete_bipartite_graph({len(top)}, {len(bottom)})" - return G - - -@py_random_state(3) -@nx._dispatchable(name="bipartite_configuration_model", graphs=None, returns_graph=True) -def configuration_model(aseq, bseq, create_using=None, seed=None): - """Returns a random bipartite graph from two given degree sequences. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from set A are connected to nodes in set B by choosing - randomly from the possible free stubs, one in A and one in B. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.configuration_model - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length and sum of each sequence - lena = len(aseq) - lenb = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - f"invalid degree sequences, sum(aseq)!=sum(bseq),{suma},{sumb}" - ) - - G = _add_nodes_with_bipartite_label(G, lena, lenb) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build lists of degree-repeated vertex numbers - stubs = [[v] * aseq[v] for v in range(lena)] - astubs = [x for subseq in stubs for x in subseq] - - stubs = [[v] * bseq[v - lena] for v in range(lena, lena + lenb)] - bstubs = [x for subseq in stubs for x in subseq] - - # shuffle lists - seed.shuffle(astubs) - seed.shuffle(bstubs) - - G.add_edges_from([astubs[i], bstubs[i]] for i in range(suma)) - - G.name = "bipartite_configuration_model" - return G - - -@nx._dispatchable(name="bipartite_havel_hakimi_graph", graphs=None, returns_graph=True) -def havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using a - Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from the set A are connected to nodes in the set B by - connecting the highest degree nodes in set A to the highest degree - nodes in set B until all stubs are connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - naseq = len(aseq) - nbseq = len(bseq) - - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - f"invalid degree sequences, sum(aseq)!=sum(bseq),{suma},{sumb}" - ) - - G = _add_nodes_with_bipartite_label(G, naseq, nbseq) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(naseq)] - bstubs = [[bseq[v - naseq], v] for v in range(naseq, naseq + nbseq)] - astubs.sort() - while astubs: - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - # connect the source to largest degree nodes in the b set - bstubs.sort() - for target in bstubs[-degree:]: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_havel_hakimi_graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def reverse_havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using a - Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from set A are connected to nodes in the set B by connecting - the highest degree nodes in set A to the lowest degree nodes in - set B until all stubs are connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.reverse_havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - lena = len(aseq) - lenb = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - f"invalid degree sequences, sum(aseq)!=sum(bseq),{suma},{sumb}" - ) - - G = _add_nodes_with_bipartite_label(G, lena, lenb) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(lena)] - bstubs = [[bseq[v - lena], v] for v in range(lena, lena + lenb)] - astubs.sort() - bstubs.sort() - while astubs: - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - # connect the source to the smallest degree nodes in the b set - for target in bstubs[0:degree]: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_reverse_havel_hakimi_graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def alternating_havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using - an alternating Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from the set A are connected to nodes in the set B by - connecting the highest degree nodes in set A to alternatively the - highest and the lowest degree nodes in set B until all stubs are - connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.alternating_havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - naseq = len(aseq) - nbseq = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - f"invalid degree sequences, sum(aseq)!=sum(bseq),{suma},{sumb}" - ) - - G = _add_nodes_with_bipartite_label(G, naseq, nbseq) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(naseq)] - bstubs = [[bseq[v - naseq], v] for v in range(naseq, naseq + nbseq)] - while astubs: - astubs.sort() - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - bstubs.sort() - small = bstubs[0 : degree // 2] # add these low degree targets - large = bstubs[(-degree + degree // 2) :] # now high degree targets - stubs = [x for z in zip(large, small) for x in z] # combine, sorry - if len(stubs) < len(small) + len(large): # check for zip truncation - stubs.append(large.pop()) - for target in stubs: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_alternating_havel_hakimi_graph" - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def preferential_attachment_graph(aseq, p, create_using=None, seed=None): - """Create a bipartite graph with a preferential attachment model from - a given single degree sequence. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes starting with node len(aseq). - The number of nodes in set B is random. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - p : float - Probability that a new bottom node is added. - create_using : NetworkX graph instance, optional - Return graph of this type. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] Guillaume, J.L. and Latapy, M., - Bipartite graphs as models of complex networks. - Physica A: Statistical Mechanics and its Applications, - 2006, 371(2), pp.795-813. - .. [2] Jean-Loup Guillaume and Matthieu Latapy, - Bipartite structure of all complex networks, - Inf. Process. Lett. 90, 2004, pg. 215-221 - https://doi.org/10.1016/j.ipl.2004.03.007 - - Notes - ----- - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.preferential_attachment_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - if p > 1: - raise nx.NetworkXError(f"probability {p} > 1") - - naseq = len(aseq) - G = _add_nodes_with_bipartite_label(G, naseq, 0) - vv = [[v] * aseq[v] for v in range(naseq)] - while vv: - while vv[0]: - source = vv[0][0] - vv[0].remove(source) - if seed.random() < p or len(G) == naseq: - target = len(G) - G.add_node(target, bipartite=1) - G.add_edge(source, target) - else: - bb = [[b] * G.degree(b) for b in range(naseq, len(G))] - # flatten the list of lists into a list. - bbstubs = reduce(lambda x, y: x + y, bb) - # choose preferentially a bottom node. - target = seed.choice(bbstubs) - G.add_node(target, bipartite=1) - G.add_edge(source, target) - vv.remove(vv[0]) - G.name = "bipartite_preferential_attachment_model" - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_graph(n, m, p, seed=None, directed=False): - """Returns a bipartite random graph. - - This is a bipartite version of the binomial (ErdÅ‘s-Rényi) graph. - The graph is composed of two partitions. Set A has nodes 0 to - (n - 1) and set B has nodes n to (n + m - 1). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set. - m : int - The number of nodes in the second bipartite set. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - - Notes - ----- - The bipartite random graph algorithm chooses each of the n*m (undirected) - or 2*nm (directed) possible edges with probability p. - - This algorithm is $O(n+m)$ where $m$ is the expected number of edges. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.random_graph - - See Also - -------- - gnp_random_graph, configuration_model - - References - ---------- - .. [1] Vladimir Batagelj and Ulrik Brandes, - "Efficient generation of large random networks", - Phys. Rev. E, 71, 036113, 2005. - """ - G = nx.Graph() - G = _add_nodes_with_bipartite_label(G, n, m) - if directed: - G = nx.DiGraph(G) - G.name = f"fast_gnp_random_graph({n},{m},{p})" - - if p <= 0: - return G - if p >= 1: - return nx.complete_bipartite_graph(n, m) - - lp = math.log(1.0 - p) - - v = 0 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= m and v < n: - w = w - m - v = v + 1 - if v < n: - G.add_edge(v, n + w) - - if directed: - # use the same algorithm to - # add edges from the "m" to "n" set - v = 0 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= m and v < n: - w = w - m - v = v + 1 - if v < n: - G.add_edge(n + w, v) - - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def gnmk_random_graph(n, m, k, seed=None, directed=False): - """Returns a random bipartite graph G_{n,m,k}. - - Produces a bipartite graph chosen randomly out of the set of all graphs - with n top nodes, m bottom nodes, and k edges. - The graph is composed of two sets of nodes. - Set A has nodes 0 to (n - 1) and set B has nodes n to (n + m - 1). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set. - m : int - The number of nodes in the second bipartite set. - k : int - The number of edges - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - - Examples - -------- - from nx.algorithms import bipartite - G = bipartite.gnmk_random_graph(10,20,50) - - See Also - -------- - gnm_random_graph - - Notes - ----- - If k > m * n then a complete bipartite graph is returned. - - This graph is a bipartite version of the `G_{nm}` random graph model. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.gnmk_random_graph - """ - G = nx.Graph() - G = _add_nodes_with_bipartite_label(G, n, m) - if directed: - G = nx.DiGraph(G) - G.name = f"bipartite_gnm_random_graph({n},{m},{k})" - if n == 1 or m == 1: - return G - max_edges = n * m # max_edges for bipartite networks - if k >= max_edges: # Maybe we should raise an exception here - return nx.complete_bipartite_graph(n, m, create_using=G) - - top = [n for n, d in G.nodes(data=True) if d["bipartite"] == 0] - bottom = list(set(G) - set(top)) - edge_count = 0 - while edge_count < k: - # generate random edge,u,v - u = seed.choice(top) - v = seed.choice(bottom) - if v in G[u]: - continue - else: - G.add_edge(u, v) - edge_count += 1 - return G - - -def _add_nodes_with_bipartite_label(G, lena, lenb): - G.add_nodes_from(range(lena + lenb)) - b = dict(zip(range(lena), [0] * lena)) - b.update(dict(zip(range(lena, lena + lenb), [1] * lenb))) - nx.set_node_attributes(G, b, "bipartite") - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matching.py deleted file mode 100644 index 38a1747..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matching.py +++ /dev/null @@ -1,590 +0,0 @@ -# This module uses material from the Wikipedia article Hopcroft--Karp algorithm -# , accessed on -# January 3, 2015, which is released under the Creative Commons -# Attribution-Share-Alike License 3.0 -# . That article includes -# pseudocode, which has been translated into the corresponding Python code. -# -# Portions of this module use code from David Eppstein's Python Algorithms and -# Data Structures (PADS) library, which is dedicated to the public domain (for -# proof, see ). -"""Provides functions for computing maximum cardinality matchings and minimum -weight full matchings in a bipartite graph. - -If you don't care about the particular implementation of the maximum matching -algorithm, simply use the :func:`maximum_matching`. If you do care, you can -import one of the named maximum matching algorithms directly. - -For example, to find a maximum matching in the complete bipartite graph with -two vertices on the left and three vertices on the right: - ->>> G = nx.complete_bipartite_graph(2, 3) ->>> left, right = nx.bipartite.sets(G) ->>> list(left) -[0, 1] ->>> list(right) -[2, 3, 4] ->>> nx.bipartite.maximum_matching(G) -{0: 2, 1: 3, 2: 0, 3: 1} - -The dictionary returned by :func:`maximum_matching` includes a mapping for -vertices in both the left and right vertex sets. - -Similarly, :func:`minimum_weight_full_matching` produces, for a complete -weighted bipartite graph, a matching whose cardinality is the cardinality of -the smaller of the two partitions, and for which the sum of the weights of the -edges included in the matching is minimal. - -""" - -import collections -import itertools - -import networkx as nx -from networkx.algorithms.bipartite import sets as bipartite_sets -from networkx.algorithms.bipartite.matrix import biadjacency_matrix - -__all__ = [ - "maximum_matching", - "hopcroft_karp_matching", - "eppstein_matching", - "to_vertex_cover", - "minimum_weight_full_matching", -] - -INFINITY = float("inf") - - -@nx._dispatchable -def hopcroft_karp_matching(G, top_nodes=None): - """Returns the maximum cardinality matching of the bipartite graph `G`. - - A matching is a set of edges that do not share any nodes. A maximum - cardinality matching is a matching with the most edges possible. It - is not always unique. Finding a matching in a bipartite graph can be - treated as a networkx flow problem. - - The functions ``hopcroft_karp_matching`` and ``maximum_matching`` - are aliases of the same function. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container of nodes - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matches`, such that - ``matches[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in `matches`. - - Raises - ------ - AmbiguousSolution - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented with the `Hopcroft--Karp matching algorithm - `_ for - bipartite graphs. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - maximum_matching - hopcroft_karp_matching - eppstein_matching - - References - ---------- - .. [1] John E. Hopcroft and Richard M. Karp. "An n^{5 / 2} Algorithm for - Maximum Matchings in Bipartite Graphs" In: **SIAM Journal of Computing** - 2.4 (1973), pp. 225--231. . - - """ - - # First we define some auxiliary search functions. - # - # If you are a human reading these auxiliary search functions, the "global" - # variables `leftmatches`, `rightmatches`, `distances`, etc. are defined - # below the functions, so that they are initialized close to the initial - # invocation of the search functions. - def breadth_first_search(): - for v in left: - if leftmatches[v] is None: - distances[v] = 0 - queue.append(v) - else: - distances[v] = INFINITY - distances[None] = INFINITY - while queue: - v = queue.popleft() - if distances[v] < distances[None]: - for u in G[v]: - if distances[rightmatches[u]] is INFINITY: - distances[rightmatches[u]] = distances[v] + 1 - queue.append(rightmatches[u]) - return distances[None] is not INFINITY - - def depth_first_search(v): - if v is not None: - for u in G[v]: - if distances[rightmatches[u]] == distances[v] + 1: - if depth_first_search(rightmatches[u]): - rightmatches[u] = v - leftmatches[v] = u - return True - distances[v] = INFINITY - return False - return True - - # Initialize the "global" variables that maintain state during the search. - left, right = bipartite_sets(G, top_nodes) - leftmatches = {v: None for v in left} - rightmatches = {v: None for v in right} - distances = {} - queue = collections.deque() - - # Implementation note: this counter is incremented as pairs are matched but - # it is currently not used elsewhere in the computation. - num_matched_pairs = 0 - while breadth_first_search(): - for v in left: - if leftmatches[v] is None: - if depth_first_search(v): - num_matched_pairs += 1 - - # Strip the entries matched to `None`. - leftmatches = {k: v for k, v in leftmatches.items() if v is not None} - rightmatches = {k: v for k, v in rightmatches.items() if v is not None} - - # At this point, the left matches and the right matches are inverses of one - # another. In other words, - # - # leftmatches == {v, k for k, v in rightmatches.items()} - # - # Finally, we combine both the left matches and right matches. - return dict(itertools.chain(leftmatches.items(), rightmatches.items())) - - -@nx._dispatchable -def eppstein_matching(G, top_nodes=None): - """Returns the maximum cardinality matching of the bipartite graph `G`. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matching`, such that - ``matching[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in `matching`. - - Raises - ------ - AmbiguousSolution - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented with David Eppstein's version of the algorithm - Hopcroft--Karp algorithm (see :func:`hopcroft_karp_matching`), which - originally appeared in the `Python Algorithms and Data Structures library - (PADS) `_. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - - hopcroft_karp_matching - - """ - # Due to its original implementation, a directed graph is needed - # so that the two sets of bipartite nodes can be distinguished - left, right = bipartite_sets(G, top_nodes) - G = nx.DiGraph(G.edges(left)) - # initialize greedy matching (redundant, but faster than full search) - matching = {} - for u in G: - for v in G[u]: - if v not in matching: - matching[v] = u - break - while True: - # structure residual graph into layers - # pred[u] gives the neighbor in the previous layer for u in U - # preds[v] gives a list of neighbors in the previous layer for v in V - # unmatched gives a list of unmatched vertices in final layer of V, - # and is also used as a flag value for pred[u] when u is in the first - # layer - preds = {} - unmatched = [] - pred = {u: unmatched for u in G} - for v in matching: - del pred[matching[v]] - layer = list(pred) - - # repeatedly extend layering structure by another pair of layers - while layer and not unmatched: - newLayer = {} - for u in layer: - for v in G[u]: - if v not in preds: - newLayer.setdefault(v, []).append(u) - layer = [] - for v in newLayer: - preds[v] = newLayer[v] - if v in matching: - layer.append(matching[v]) - pred[matching[v]] = v - else: - unmatched.append(v) - - # did we finish layering without finding any alternating paths? - if not unmatched: - # TODO - The lines between --- were unused and were thus commented - # out. This whole commented chunk should be reviewed to determine - # whether it should be built upon or completely removed. - # --- - # unlayered = {} - # for u in G: - # # TODO Why is extra inner loop necessary? - # for v in G[u]: - # if v not in preds: - # unlayered[v] = None - # --- - # TODO Originally, this function returned a three-tuple: - # - # return (matching, list(pred), list(unlayered)) - # - # For some reason, the documentation for this function - # indicated that the second and third elements of the returned - # three-tuple would be the vertices in the left and right vertex - # sets, respectively, that are also in the maximum independent set. - # However, what I think the author meant was that the second - # element is the list of vertices that were unmatched and the third - # element was the list of vertices that were matched. Since that - # seems to be the case, they don't really need to be returned, - # since that information can be inferred from the matching - # dictionary. - - # All the matched nodes must be a key in the dictionary - for key in matching.copy(): - matching[matching[key]] = key - return matching - - # recursively search backward through layers to find alternating paths - # recursion returns true if found path, false otherwise - def recurse(v): - if v in preds: - L = preds.pop(v) - for u in L: - if u in pred: - pu = pred.pop(u) - if pu is unmatched or recurse(pu): - matching[v] = u - return True - return False - - for v in unmatched: - recurse(v) - - -def _is_connected_by_alternating_path(G, v, matched_edges, unmatched_edges, targets): - """Returns True if and only if the vertex `v` is connected to one of - the target vertices by an alternating path in `G`. - - An *alternating path* is a path in which every other edge is in the - specified maximum matching (and the remaining edges in the path are not in - the matching). An alternating path may have matched edges in the even - positions or in the odd positions, as long as the edges alternate between - 'matched' and 'unmatched'. - - `G` is an undirected bipartite NetworkX graph. - - `v` is a vertex in `G`. - - `matched_edges` is a set of edges present in a maximum matching in `G`. - - `unmatched_edges` is a set of edges not present in a maximum - matching in `G`. - - `targets` is a set of vertices. - - """ - - def _alternating_dfs(u, along_matched=True): - """Returns True if and only if `u` is connected to one of the - targets by an alternating path. - - `u` is a vertex in the graph `G`. - - If `along_matched` is True, this step of the depth-first search - will continue only through edges in the given matching. Otherwise, it - will continue only through edges *not* in the given matching. - - """ - visited = set() - # Follow matched edges when depth is even, - # and follow unmatched edges when depth is odd. - initial_depth = 0 if along_matched else 1 - stack = [(u, iter(G[u]), initial_depth)] - while stack: - parent, children, depth = stack[-1] - valid_edges = matched_edges if depth % 2 else unmatched_edges - try: - child = next(children) - if child not in visited: - if (parent, child) in valid_edges or (child, parent) in valid_edges: - if child in targets: - return True - visited.add(child) - stack.append((child, iter(G[child]), depth + 1)) - except StopIteration: - stack.pop() - return False - - # Check for alternating paths starting with edges in the matching, then - # check for alternating paths starting with edges not in the - # matching. - return _alternating_dfs(v, along_matched=True) or _alternating_dfs( - v, along_matched=False - ) - - -def _connected_by_alternating_paths(G, matching, targets): - """Returns the set of vertices that are connected to one of the target - vertices by an alternating path in `G` or are themselves a target. - - An *alternating path* is a path in which every other edge is in the - specified maximum matching (and the remaining edges in the path are not in - the matching). An alternating path may have matched edges in the even - positions or in the odd positions, as long as the edges alternate between - 'matched' and 'unmatched'. - - `G` is an undirected bipartite NetworkX graph. - - `matching` is a dictionary representing a maximum matching in `G`, as - returned by, for example, :func:`maximum_matching`. - - `targets` is a set of vertices. - - """ - # Get the set of matched edges and the set of unmatched edges. Only include - # one version of each undirected edge (for example, include edge (1, 2) but - # not edge (2, 1)). Using frozensets as an intermediary step we do not - # require nodes to be orderable. - edge_sets = {frozenset((u, v)) for u, v in matching.items()} - matched_edges = {tuple(edge) for edge in edge_sets} - unmatched_edges = { - (u, v) for (u, v) in G.edges() if frozenset((u, v)) not in edge_sets - } - - return { - v - for v in G - if v in targets - or _is_connected_by_alternating_path( - G, v, matched_edges, unmatched_edges, targets - ) - } - - -@nx._dispatchable -def to_vertex_cover(G, matching, top_nodes=None): - """Returns the minimum vertex cover corresponding to the given maximum - matching of the bipartite graph `G`. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - matching : dictionary - - A dictionary whose keys are vertices in `G` and whose values are the - distinct neighbors comprising the maximum matching for `G`, as returned - by, for example, :func:`maximum_matching`. The dictionary *must* - represent the maximum matching. - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - vertex_cover : :class:`set` - - The minimum vertex cover in `G`. - - Raises - ------ - AmbiguousSolution - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented using the procedure guaranteed by `Konig's - theorem - `_, - which proves an equivalence between a maximum matching and a minimum vertex - cover in bipartite graphs. - - Since a minimum vertex cover is the complement of a maximum independent set - for any graph, one can compute the maximum independent set of a bipartite - graph this way: - - >>> G = nx.complete_bipartite_graph(2, 3) - >>> matching = nx.bipartite.maximum_matching(G) - >>> vertex_cover = nx.bipartite.to_vertex_cover(G, matching) - >>> independent_set = set(G) - vertex_cover - >>> print(list(independent_set)) - [2, 3, 4] - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - """ - # This is a Python implementation of the algorithm described at - # . - L, R = bipartite_sets(G, top_nodes) - # Let U be the set of unmatched vertices in the left vertex set. - unmatched_vertices = set(G) - set(matching) - U = unmatched_vertices & L - # Let Z be the set of vertices that are either in U or are connected to U - # by alternating paths. - Z = _connected_by_alternating_paths(G, matching, U) - # At this point, every edge either has a right endpoint in Z or a left - # endpoint not in Z. This gives us the vertex cover. - return (L - Z) | (R & Z) - - -#: Returns the maximum cardinality matching in the given bipartite graph. -#: -#: This function is simply an alias for :func:`hopcroft_karp_matching`. -maximum_matching = hopcroft_karp_matching - - -@nx._dispatchable(edge_attrs="weight") -def minimum_weight_full_matching(G, top_nodes=None, weight="weight"): - r"""Returns a minimum weight full matching of the bipartite graph `G`. - - Let :math:`G = ((U, V), E)` be a weighted bipartite graph with real weights - :math:`w : E \to \mathbb{R}`. This function then produces a matching - :math:`M \subseteq E` with cardinality - - .. math:: - \lvert M \rvert = \min(\lvert U \rvert, \lvert V \rvert), - - which minimizes the sum of the weights of the edges included in the - matching, :math:`\sum_{e \in M} w(e)`, or raises an error if no such - matching exists. - - When :math:`\lvert U \rvert = \lvert V \rvert`, this is commonly - referred to as a perfect matching; here, since we allow - :math:`\lvert U \rvert` and :math:`\lvert V \rvert` to differ, we - follow Karp [1]_ and refer to the matching as *full*. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. - - weight : string, optional (default='weight') - - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matches`, such that - ``matches[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in `matches`. - - Raises - ------ - ValueError - Raised if no full matching exists. - - ImportError - Raised if SciPy is not available. - - Notes - ----- - The problem of determining a minimum weight full matching is also known as - the rectangular linear assignment problem. This implementation defers the - calculation of the assignment to SciPy. - - References - ---------- - .. [1] Richard Manning Karp: - An algorithm to Solve the m x n Assignment Problem in Expected Time - O(mn log n). - Networks, 10(2):143–152, 1980. - - """ - import numpy as np - import scipy as sp - - left, right = nx.bipartite.sets(G, top_nodes) - U = list(left) - V = list(right) - # We explicitly create the biadjacency matrix having infinities - # where edges are missing (as opposed to zeros, which is what one would - # get by using toarray on the sparse matrix). - weights_sparse = biadjacency_matrix( - G, row_order=U, column_order=V, weight=weight, format="coo" - ) - weights = np.full(weights_sparse.shape, np.inf) - weights[weights_sparse.row, weights_sparse.col] = weights_sparse.data - left_matches = sp.optimize.linear_sum_assignment(weights) - d = {U[u]: V[v] for u, v in zip(*left_matches)} - # d will contain the matching from edges in left to right; we need to - # add the ones from right to left as well. - d.update({v: u for u, v in d.items()}) - return d diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matrix.py deleted file mode 100644 index bbfa47c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/matrix.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -==================== -Biadjacency matrices -==================== -""" - -import itertools - -import networkx as nx -from networkx.convert_matrix import _generate_weighted_edges - -__all__ = ["biadjacency_matrix", "from_biadjacency_matrix"] - - -@nx._dispatchable(edge_attrs="weight") -def biadjacency_matrix( - G, row_order, column_order=None, dtype=None, weight="weight", format="csr" -): - r"""Returns the biadjacency matrix of the bipartite graph G. - - Let `G = (U, V, E)` be a bipartite graph with node sets - `U = u_{1},...,u_{r}` and `V = v_{1},...,v_{s}`. The biadjacency - matrix [1]_ is the `r` x `s` matrix `B` in which `b_{i,j} = 1` - if, and only if, `(u_i, v_j) \in E`. If the parameter `weight` is - not `None` and matches the name of an edge attribute, its value is - used instead of 1. - - Parameters - ---------- - G : graph - A NetworkX graph - - row_order : list of nodes - The rows of the matrix are ordered according to the list of nodes. - - column_order : list, optional - The columns of the matrix are ordered according to the list of nodes. - If column_order is None, then the ordering of columns is arbitrary. - - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. If None, then the - NumPy default is used. - - weight : string or None, optional (default='weight') - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. - - format : str in {'bsr', 'csr', 'csc', 'coo', 'lil', 'dia', 'dok'} - The type of the matrix to be returned (default 'csr'). For - some algorithms different implementations of sparse matrices - can perform better. See [2]_ for details. - - Returns - ------- - M : SciPy sparse array - Biadjacency matrix representation of the bipartite graph G. - - Notes - ----- - No attempt is made to check that the input graph is bipartite. - - For directed bipartite graphs only successors are considered as neighbors. - To obtain an adjacency matrix with ones (or weight values) for both - predecessors and successors you have to generate two biadjacency matrices - where the rows of one of them are the columns of the other, and then add - one to the transpose of the other. - - See Also - -------- - adjacency_matrix - from_biadjacency_matrix - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph - .. [2] Scipy Dev. References, "Sparse Matrices", - https://docs.scipy.org/doc/scipy/reference/sparse.html - """ - import scipy as sp - - nlen = len(row_order) - if nlen == 0: - raise nx.NetworkXError("row_order is empty list") - if len(row_order) != len(set(row_order)): - msg = "Ambiguous ordering: `row_order` contained duplicates." - raise nx.NetworkXError(msg) - if column_order is None: - column_order = list(set(G) - set(row_order)) - mlen = len(column_order) - if len(column_order) != len(set(column_order)): - msg = "Ambiguous ordering: `column_order` contained duplicates." - raise nx.NetworkXError(msg) - - row_index = dict(zip(row_order, itertools.count())) - col_index = dict(zip(column_order, itertools.count())) - - if G.number_of_edges() == 0: - row, col, data = [], [], [] - else: - row, col, data = zip( - *( - (row_index[u], col_index[v], d.get(weight, 1)) - for u, v, d in G.edges(row_order, data=True) - if u in row_index and v in col_index - ) - ) - A = sp.sparse.coo_array((data, (row, col)), shape=(nlen, mlen), dtype=dtype) - try: - return A.asformat(format) - except ValueError as err: - raise nx.NetworkXError(f"Unknown sparse array format: {format}") from err - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_biadjacency_matrix(A, create_using=None, edge_attribute="weight"): - r"""Creates a new bipartite graph from a biadjacency matrix given as a - SciPy sparse array. - - Parameters - ---------- - A: scipy sparse array - A biadjacency matrix representation of a graph - - create_using: NetworkX graph - Use specified graph for result. The default is Graph() - - edge_attribute: string - Name of edge attribute to store matrix numeric value. The data will - have the same type as the matrix entry (int, float, (real,imag)). - - Notes - ----- - The nodes are labeled with the attribute `bipartite` set to an integer - 0 or 1 representing membership in part 0 or part 1 of the bipartite graph. - - If `create_using` is an instance of :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph` and the entries of `A` are of - type :class:`int`, then this function returns a multigraph (of the same - type as `create_using`) with parallel edges. In this case, `edge_attribute` - will be ignored. - - See Also - -------- - biadjacency_matrix - from_numpy_array - - References - ---------- - [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph - """ - G = nx.empty_graph(0, create_using) - n, m = A.shape - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(range(n), bipartite=0) - G.add_nodes_from(range(n, n + m), bipartite=1) - # Create an iterable over (u, v, w) triples and for each triple, add an - # edge from u to v with weight w. - triples = ((u, n + v, d) for (u, v, d) in _generate_weighted_edges(A)) - # If the entries in the adjacency matrix are integers and the graph is a - # multigraph, then create parallel edges, each with weight 1, for each - # entry in the adjacency matrix. Otherwise, create one edge for each - # positive entry in the adjacency matrix and set the weight of that edge to - # be the entry in the matrix. - if A.dtype.kind in ("i", "u") and G.is_multigraph(): - chain = itertools.chain.from_iterable - triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) - G.add_weighted_edges_from(triples, weight=edge_attribute) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/projection.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/projection.py deleted file mode 100644 index 7c2a26c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/projection.py +++ /dev/null @@ -1,526 +0,0 @@ -"""One-mode (unipartite) projections of bipartite graphs.""" - -import networkx as nx -from networkx.exception import NetworkXAlgorithmError -from networkx.utils import not_implemented_for - -__all__ = [ - "projected_graph", - "weighted_projected_graph", - "collaboration_weighted_projected_graph", - "overlap_weighted_projected_graph", - "generic_weighted_projected_graph", -] - - -@nx._dispatchable( - graphs="B", preserve_node_attrs=True, preserve_graph_attrs=True, returns_graph=True -) -def projected_graph(B, nodes, multigraph=False): - r"""Returns the projection of B onto one of its node sets. - - Returns the graph G that is the projection of the bipartite graph B - onto the specified nodes. They retain their attributes and are connected - in G if they have a common neighbor in B. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - multigraph: bool (default=False) - If True return a multigraph where the multiple edges represent multiple - shared neighbors. They edge key in the multigraph is assigned to the - label of the neighbor. - - Returns - ------- - Graph : NetworkX graph or multigraph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(4) - >>> G = bipartite.projected_graph(B, [1, 3]) - >>> list(G) - [1, 3] - >>> list(G.edges()) - [(1, 3)] - - If nodes `a`, and `b` are connected through both nodes 1 and 2 then - building a multigraph results in two edges in the projection onto - [`a`, `b`]: - - >>> B = nx.Graph() - >>> B.add_edges_from([("a", 1), ("b", 1), ("a", 2), ("b", 2)]) - >>> G = bipartite.projected_graph(B, ["a", "b"], multigraph=True) - >>> print([sorted((u, v)) for u, v in G.edges()]) - [['a', 'b'], ['a', 'b']] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - Returns a simple graph that is the projection of the bipartite graph B - onto the set of nodes given in list nodes. If multigraph=True then - a multigraph is returned with an edge for every shared neighbor. - - Directed graphs are allowed as input. The output will also then - be a directed graph with edges if there is a directed path between - the nodes. - - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph - """ - if B.is_multigraph(): - raise nx.NetworkXError("not defined for multigraphs") - if B.is_directed(): - directed = True - if multigraph: - G = nx.MultiDiGraph() - else: - G = nx.DiGraph() - else: - directed = False - if multigraph: - G = nx.MultiGraph() - else: - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - nbrs2 = {v for nbr in B[u] for v in B[nbr] if v != u} - if multigraph: - for n in nbrs2: - if directed: - links = set(B[u]) & set(B.pred[n]) - else: - links = set(B[u]) & set(B[n]) - for l in links: - if not G.has_edge(u, n, l): - G.add_edge(u, n, key=l) - else: - G.add_edges_from((u, n) for n in nbrs2) - return G - - -@not_implemented_for("multigraph") -@nx._dispatchable(graphs="B", returns_graph=True) -def weighted_projected_graph(B, nodes, ratio=False): - r"""Returns a weighted projection of B onto one of its node sets. - - The weighted projected graph is the projection of the bipartite - network B onto the specified nodes with weights representing the - number of shared neighbors or the ratio between actual shared - neighbors and possible shared neighbors if ``ratio is True`` [1]_. - The nodes retain their attributes and are connected in the resulting - graph if they have an edge to a common node in the original graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Distinct nodes to project onto (the "bottom" nodes). - - ratio: Bool (default=False) - If True, edge weight is the ratio between actual shared neighbors - and maximum possible shared neighbors (i.e., the size of the other - node set). If False, edges weight is the number of shared neighbors. - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(4) - >>> G = bipartite.weighted_projected_graph(B, [1, 3]) - >>> list(G) - [1, 3] - >>> list(G.edges(data=True)) - [(1, 3, {'weight': 1})] - >>> G = bipartite.weighted_projected_graph(B, [1, 3], ratio=True) - >>> list(G.edges(data=True)) - [(1, 3, {'weight': 0.5})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite, or that - the input nodes are distinct. However, if the length of the input nodes is - greater than or equal to the nodes in the graph B, an exception is raised. - If the nodes are not distinct but don't raise this error, the output weights - will be incorrect. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph - projected_graph - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - n_top = len(B) - len(nodes) - - if n_top < 1: - raise NetworkXAlgorithmError( - f"the size of the nodes to project onto ({len(nodes)}) is >= the graph size ({len(B)}).\n" - "They are either not a valid bipartite partition or contain duplicates" - ) - - for u in nodes: - unbrs = set(B[u]) - nbrs2 = {n for nbr in unbrs for n in B[nbr]} - {u} - for v in nbrs2: - vnbrs = set(pred[v]) - common = unbrs & vnbrs - if not ratio: - weight = len(common) - else: - weight = len(common) / n_top - G.add_edge(u, v, weight=weight) - return G - - -@not_implemented_for("multigraph") -@nx._dispatchable(graphs="B", returns_graph=True) -def collaboration_weighted_projected_graph(B, nodes): - r"""Newman's weighted projection of B onto one of its node sets. - - The collaboration weighted projection is the projection of the - bipartite network B onto the specified nodes with weights assigned - using Newman's collaboration model [1]_: - - .. math:: - - w_{u, v} = \sum_k \frac{\delta_{u}^{k} \delta_{v}^{k}}{d_k - 1} - - where `u` and `v` are nodes from the bottom bipartite node set, - and `k` is a node of the top node set. - The value `d_k` is the degree of node `k` in the bipartite - network and `\delta_{u}^{k}` is 1 if node `u` is - linked to node `k` in the original bipartite graph or 0 otherwise. - - The nodes retain their attributes and are connected in the resulting - graph if have an edge to a common node in the original bipartite - graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(5) - >>> B.add_edge(1, 5) - >>> G = bipartite.collaboration_weighted_projected_graph(B, [0, 2, 4, 5]) - >>> list(G) - [0, 2, 4, 5] - >>> for edge in sorted(G.edges(data=True)): - ... print(edge) - (0, 2, {'weight': 0.5}) - (0, 5, {'weight': 0.5}) - (2, 4, {'weight': 1.0}) - (2, 5, {'weight': 0.5}) - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph, - projected_graph - - References - ---------- - .. [1] Scientific collaboration networks: II. - Shortest paths, weighted networks, and centrality, - M. E. J. Newman, Phys. Rev. E 64, 016132 (2001). - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - unbrs = set(B[u]) - nbrs2 = {n for nbr in unbrs for n in B[nbr] if n != u} - for v in nbrs2: - vnbrs = set(pred[v]) - common_degree = (len(B[n]) for n in unbrs & vnbrs) - weight = sum(1.0 / (deg - 1) for deg in common_degree if deg > 1) - G.add_edge(u, v, weight=weight) - return G - - -@not_implemented_for("multigraph") -@nx._dispatchable(graphs="B", returns_graph=True) -def overlap_weighted_projected_graph(B, nodes, jaccard=True): - r"""Overlap weighted projection of B onto one of its node sets. - - The overlap weighted projection is the projection of the bipartite - network B onto the specified nodes with weights representing - the Jaccard index between the neighborhoods of the two nodes in the - original bipartite network [1]_: - - .. math:: - - w_{v, u} = \frac{|N(u) \cap N(v)|}{|N(u) \cup N(v)|} - - or if the parameter 'jaccard' is False, the fraction of common - neighbors by minimum of both nodes degree in the original - bipartite graph [1]_: - - .. math:: - - w_{v, u} = \frac{|N(u) \cap N(v)|}{min(|N(u)|, |N(v)|)} - - The nodes retain their attributes and are connected in the resulting - graph if have an edge to a common node in the original bipartite graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - jaccard: Bool (default=True) - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(5) - >>> nodes = [0, 2, 4] - >>> G = bipartite.overlap_weighted_projected_graph(B, nodes) - >>> list(G) - [0, 2, 4] - >>> list(G.edges(data=True)) - [(0, 2, {'weight': 0.5}), (2, 4, {'weight': 0.5})] - >>> G = bipartite.overlap_weighted_projected_graph(B, nodes, jaccard=False) - >>> list(G.edges(data=True)) - [(0, 2, {'weight': 1.0}), (2, 4, {'weight': 1.0})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - generic_weighted_projected_graph, - projected_graph - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. Analyzing Affiliation - Networks. In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - unbrs = set(B[u]) - nbrs2 = {n for nbr in unbrs for n in B[nbr]} - {u} - for v in nbrs2: - vnbrs = set(pred[v]) - if jaccard: - wt = len(unbrs & vnbrs) / len(unbrs | vnbrs) - else: - wt = len(unbrs & vnbrs) / min(len(unbrs), len(vnbrs)) - G.add_edge(u, v, weight=wt) - return G - - -@not_implemented_for("multigraph") -@nx._dispatchable(graphs="B", preserve_all_attrs=True, returns_graph=True) -def generic_weighted_projected_graph(B, nodes, weight_function=None): - r"""Weighted projection of B with a user-specified weight function. - - The bipartite network B is projected on to the specified nodes - with weights computed by a user-specified function. This function - must accept as a parameter the neighborhood sets of two nodes and - return an integer or a float. - - The nodes retain their attributes and are connected in the resulting graph - if they have an edge to a common node in the original graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - weight_function : function - This function must accept as parameters the same input graph - that this function, and two nodes; and return an integer or a float. - The default function computes the number of shared neighbors. - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> # Define some custom weight functions - >>> def jaccard(G, u, v): - ... unbrs = set(G[u]) - ... vnbrs = set(G[v]) - ... return float(len(unbrs & vnbrs)) / len(unbrs | vnbrs) - >>> def my_weight(G, u, v, weight="weight"): - ... w = 0 - ... for nbr in set(G[u]) & set(G[v]): - ... w += G[u][nbr].get(weight, 1) + G[v][nbr].get(weight, 1) - ... return w - >>> # A complete bipartite graph with 4 nodes and 4 edges - >>> B = nx.complete_bipartite_graph(2, 2) - >>> # Add some arbitrary weight to the edges - >>> for i, (u, v) in enumerate(B.edges()): - ... B.edges[u, v]["weight"] = i + 1 - >>> for edge in B.edges(data=True): - ... print(edge) - (0, 2, {'weight': 1}) - (0, 3, {'weight': 2}) - (1, 2, {'weight': 3}) - (1, 3, {'weight': 4}) - >>> # By default, the weight is the number of shared neighbors - >>> G = bipartite.generic_weighted_projected_graph(B, [0, 1]) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 2})] - >>> # To specify a custom weight function use the weight_function parameter - >>> G = bipartite.generic_weighted_projected_graph( - ... B, [0, 1], weight_function=jaccard - ... ) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 1.0})] - >>> G = bipartite.generic_weighted_projected_graph( - ... B, [0, 1], weight_function=my_weight - ... ) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 10})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - projected_graph - - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - if weight_function is None: - - def weight_function(G, u, v): - # Notice that we use set(pred[v]) for handling the directed case. - return len(set(G[u]) & set(pred[v])) - - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - nbrs2 = {n for nbr in set(B[u]) for n in B[nbr]} - {u} - for v in nbrs2: - weight = weight_function(B, u, v) - G.add_edge(u, v, weight=weight) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/redundancy.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/redundancy.py deleted file mode 100644 index b622b97..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/redundancy.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Node redundancy for bipartite graphs.""" - -from itertools import combinations - -import networkx as nx -from networkx import NetworkXError - -__all__ = ["node_redundancy"] - - -@nx._dispatchable -def node_redundancy(G, nodes=None): - r"""Computes the node redundancy coefficients for the nodes in the bipartite - graph `G`. - - The redundancy coefficient of a node `v` is the fraction of pairs of - neighbors of `v` that are both linked to other nodes. In a one-mode - projection these nodes would be linked together even if `v` were - not there. - - More formally, for any vertex `v`, the *redundancy coefficient of `v`* is - defined by - - .. math:: - - rc(v) = \frac{|\{\{u, w\} \subseteq N(v), - \: \exists v' \neq v,\: (v',u) \in E\: - \mathrm{and}\: (v',w) \in E\}|}{ \frac{|N(v)|(|N(v)|-1)}{2}}, - - where `N(v)` is the set of neighbors of `v` in `G`. - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or iterable (optional) - Compute redundancy for these nodes. The default is all nodes in G. - - Returns - ------- - redundancy : dictionary - A dictionary keyed by node with the node redundancy value. - - Examples - -------- - Compute the redundancy coefficient of each node in a graph:: - - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> rc[0] - 1.0 - - Compute the average redundancy for the graph:: - - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> sum(rc.values()) / len(G) - 1.0 - - Compute the average redundancy for a set of nodes:: - - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> nodes = [0, 2] - >>> sum(rc[n] for n in nodes) / len(nodes) - 1.0 - - Raises - ------ - NetworkXError - If any of the nodes in the graph (or in `nodes`, if specified) has - (out-)degree less than two (which would result in division by zero, - according to the definition of the redundancy coefficient). - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - - """ - if nodes is None: - nodes = G - if any(len(G[v]) < 2 for v in nodes): - raise NetworkXError( - "Cannot compute redundancy coefficient for a node" - " that has fewer than two neighbors." - ) - # TODO This can be trivially parallelized. - return {v: _node_redundancy(G, v) for v in nodes} - - -def _node_redundancy(G, v): - """Returns the redundancy of the node `v` in the bipartite graph `G`. - - If `G` is a graph with `n` nodes, the redundancy of a node is the ratio - of the "overlap" of `v` to the maximum possible overlap of `v` - according to its degree. The overlap of `v` is the number of pairs of - neighbors that have mutual neighbors themselves, other than `v`. - - `v` must have at least two neighbors in `G`. - - """ - n = len(G[v]) - overlap = sum( - 1 for (u, w) in combinations(G[v], 2) if (set(G[u]) & set(G[w])) - {v} - ) - return (2 * overlap) / (n * (n - 1)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/spectral.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/spectral.py deleted file mode 100644 index cb9388f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/spectral.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Spectral bipartivity measure. -""" - -import networkx as nx - -__all__ = ["spectral_bipartivity"] - - -@nx._dispatchable(edge_attrs="weight") -def spectral_bipartivity(G, nodes=None, weight="weight"): - """Returns the spectral bipartivity. - - Parameters - ---------- - G : NetworkX graph - - nodes : list or container optional(default is all nodes) - Nodes to return value of spectral bipartivity contribution. - - weight : string or None optional (default = 'weight') - Edge data key to use for edge weights. If None, weights set to 1. - - Returns - ------- - sb : float or dict - A single number if the keyword nodes is not specified, or - a dictionary keyed by node with the spectral bipartivity contribution - of that node as the value. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> bipartite.spectral_bipartivity(G) - 1.0 - - Notes - ----- - This implementation uses Numpy (dense) matrices which are not efficient - for storing large sparse graphs. - - See Also - -------- - color - - References - ---------- - .. [1] E. Estrada and J. A. Rodríguez-Velázquez, "Spectral measures of - bipartivity in complex networks", PhysRev E 72, 046105 (2005) - """ - import scipy as sp - - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist, weight=weight) - expA = sp.linalg.expm(A) - expmA = sp.linalg.expm(-A) - coshA = 0.5 * (expA + expmA) - if nodes is None: - # return single number for entire graph - return float(coshA.diagonal().sum() / expA.diagonal().sum()) - else: - # contribution for individual nodes - index = dict(zip(nodelist, range(len(nodelist)))) - sb = {} - for n in nodes: - i = index[n] - sb[n] = coshA.item(i, i) / expA.item(i, i) - return sb diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_basic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_basic.py deleted file mode 100644 index 655506b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_basic.py +++ /dev/null @@ -1,125 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import bipartite - - -class TestBipartiteBasic: - def test_is_bipartite(self): - assert bipartite.is_bipartite(nx.path_graph(4)) - assert bipartite.is_bipartite(nx.DiGraph([(1, 0)])) - assert not bipartite.is_bipartite(nx.complete_graph(3)) - - def test_bipartite_color(self): - G = nx.path_graph(4) - c = bipartite.color(G) - assert c == {0: 1, 1: 0, 2: 1, 3: 0} - - def test_not_bipartite_color(self): - with pytest.raises(nx.NetworkXError): - c = bipartite.color(nx.complete_graph(4)) - - def test_bipartite_directed(self): - G = bipartite.random_graph(10, 10, 0.1, directed=True) - assert bipartite.is_bipartite(G) - - def test_bipartite_sets(self): - G = nx.path_graph(4) - X, Y = bipartite.sets(G) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_directed(self): - G = nx.path_graph(4) - D = G.to_directed() - X, Y = bipartite.sets(D) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_given_top_nodes(self): - G = nx.path_graph(4) - top_nodes = [0, 2] - X, Y = bipartite.sets(G, top_nodes) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - G = nx.path_graph(4) - G.add_edges_from([(5, 6), (6, 7)]) - X, Y = bipartite.sets(G) - - def test_is_bipartite_node_set(self): - G = nx.path_graph(4) - - with pytest.raises(nx.AmbiguousSolution): - bipartite.is_bipartite_node_set(G, [1, 1, 2, 3]) - - assert bipartite.is_bipartite_node_set(G, [0, 2]) - assert bipartite.is_bipartite_node_set(G, [1, 3]) - assert not bipartite.is_bipartite_node_set(G, [1, 2]) - G.add_edge(10, 20) - assert bipartite.is_bipartite_node_set(G, [0, 2, 10]) - assert bipartite.is_bipartite_node_set(G, [0, 2, 20]) - assert bipartite.is_bipartite_node_set(G, [1, 3, 10]) - assert bipartite.is_bipartite_node_set(G, [1, 3, 20]) - - def test_bipartite_density(self): - G = nx.path_graph(5) - X, Y = bipartite.sets(G) - density = len(list(G.edges())) / (len(X) * len(Y)) - assert bipartite.density(G, X) == density - D = nx.DiGraph(G.edges()) - assert bipartite.density(D, X) == density / 2.0 - assert bipartite.density(nx.Graph(), {}) == 0.0 - - def test_bipartite_degrees(self): - G = nx.path_graph(5) - X = {1, 3} - Y = {0, 2, 4} - u, d = bipartite.degrees(G, Y) - assert dict(u) == {1: 2, 3: 2} - assert dict(d) == {0: 1, 2: 2, 4: 1} - - def test_bipartite_weighted_degrees(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=0.1, other=0.2) - X = {1, 3} - Y = {0, 2, 4} - u, d = bipartite.degrees(G, Y, weight="weight") - assert dict(u) == {1: 1.1, 3: 2} - assert dict(d) == {0: 0.1, 2: 2, 4: 1} - u, d = bipartite.degrees(G, Y, weight="other") - assert dict(u) == {1: 1.2, 3: 2} - assert dict(d) == {0: 0.2, 2: 2, 4: 1} - - def test_biadjacency_matrix_weight(self): - pytest.importorskip("scipy") - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2, other=4) - X = [1, 3] - Y = [0, 2, 4] - M = bipartite.biadjacency_matrix(G, X, weight="weight") - assert M[0, 0] == 2 - M = bipartite.biadjacency_matrix(G, X, weight="other") - assert M[0, 0] == 4 - - def test_biadjacency_matrix(self): - pytest.importorskip("scipy") - tops = [2, 5, 10] - bots = [5, 10, 15] - for i in range(len(tops)): - G = bipartite.random_graph(tops[i], bots[i], 0.2) - top = [n for n, d in G.nodes(data=True) if d["bipartite"] == 0] - M = bipartite.biadjacency_matrix(G, top) - assert M.shape[0] == tops[i] - assert M.shape[1] == bots[i] - - def test_biadjacency_matrix_order(self): - pytest.importorskip("scipy") - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2) - X = [3, 1] - Y = [4, 2, 0] - M = bipartite.biadjacency_matrix(G, X, Y, weight="weight") - assert M[1, 2] == 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_centrality.py deleted file mode 100644 index 19fb5d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_centrality.py +++ /dev/null @@ -1,192 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import bipartite - - -class TestBipartiteCentrality: - @classmethod - def setup_class(cls): - cls.P4 = nx.path_graph(4) - cls.K3 = nx.complete_bipartite_graph(3, 3) - cls.C4 = nx.cycle_graph(4) - cls.davis = nx.davis_southern_women_graph() - cls.top_nodes = [ - n for n, d in cls.davis.nodes(data=True) if d["bipartite"] == 0 - ] - - def test_degree_centrality(self): - d = bipartite.degree_centrality(self.P4, [1, 3]) - answer = {0: 0.5, 1: 1.0, 2: 1.0, 3: 0.5} - assert d == answer - d = bipartite.degree_centrality(self.K3, [0, 1, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0} - assert d == answer - d = bipartite.degree_centrality(self.C4, [0, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0} - assert d == answer - - def test_betweenness_centrality(self): - c = bipartite.betweenness_centrality(self.P4, [1, 3]) - answer = {0: 0.0, 1: 1.0, 2: 1.0, 3: 0.0} - assert c == answer - c = bipartite.betweenness_centrality(self.K3, [0, 1, 2]) - answer = {0: 0.125, 1: 0.125, 2: 0.125, 3: 0.125, 4: 0.125, 5: 0.125} - assert c == answer - c = bipartite.betweenness_centrality(self.C4, [0, 2]) - answer = {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - assert c == answer - - def test_closeness_centrality(self): - c = bipartite.closeness_centrality(self.P4, [1, 3]) - answer = {0: 2.0 / 3, 1: 1.0, 2: 1.0, 3: 2.0 / 3} - assert c == answer - c = bipartite.closeness_centrality(self.K3, [0, 1, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0} - assert c == answer - c = bipartite.closeness_centrality(self.C4, [0, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0} - assert c == answer - G = nx.Graph() - G.add_node(0) - G.add_node(1) - c = bipartite.closeness_centrality(G, [0]) - assert c == {0: 0.0, 1: 0.0} - c = bipartite.closeness_centrality(G, [1]) - assert c == {0: 0.0, 1: 0.0} - - def test_bipartite_closeness_centrality_unconnected(self): - G = nx.complete_bipartite_graph(3, 3) - G.add_edge(6, 7) - c = bipartite.closeness_centrality(G, [0, 2, 4, 6], normalized=False) - answer = { - 0: 10.0 / 7, - 2: 10.0 / 7, - 4: 10.0 / 7, - 6: 10.0, - 1: 10.0 / 7, - 3: 10.0 / 7, - 5: 10.0 / 7, - 7: 10.0, - } - assert c == answer - - def test_davis_degree_centrality(self): - G = self.davis - deg = bipartite.degree_centrality(G, self.top_nodes) - answer = { - "E8": 0.78, - "E9": 0.67, - "E7": 0.56, - "Nora Fayette": 0.57, - "Evelyn Jefferson": 0.57, - "Theresa Anderson": 0.57, - "E6": 0.44, - "Sylvia Avondale": 0.50, - "Laura Mandeville": 0.50, - "Brenda Rogers": 0.50, - "Katherina Rogers": 0.43, - "E5": 0.44, - "Helen Lloyd": 0.36, - "E3": 0.33, - "Ruth DeSand": 0.29, - "Verne Sanderson": 0.29, - "E12": 0.33, - "Myra Liddel": 0.29, - "E11": 0.22, - "Eleanor Nye": 0.29, - "Frances Anderson": 0.29, - "Pearl Oglethorpe": 0.21, - "E4": 0.22, - "Charlotte McDowd": 0.29, - "E10": 0.28, - "Olivia Carleton": 0.14, - "Flora Price": 0.14, - "E2": 0.17, - "E1": 0.17, - "Dorothy Murchison": 0.14, - "E13": 0.17, - "E14": 0.17, - } - for node, value in answer.items(): - assert value == pytest.approx(deg[node], abs=1e-2) - - def test_davis_betweenness_centrality(self): - G = self.davis - bet = bipartite.betweenness_centrality(G, self.top_nodes) - answer = { - "E8": 0.24, - "E9": 0.23, - "E7": 0.13, - "Nora Fayette": 0.11, - "Evelyn Jefferson": 0.10, - "Theresa Anderson": 0.09, - "E6": 0.07, - "Sylvia Avondale": 0.07, - "Laura Mandeville": 0.05, - "Brenda Rogers": 0.05, - "Katherina Rogers": 0.05, - "E5": 0.04, - "Helen Lloyd": 0.04, - "E3": 0.02, - "Ruth DeSand": 0.02, - "Verne Sanderson": 0.02, - "E12": 0.02, - "Myra Liddel": 0.02, - "E11": 0.02, - "Eleanor Nye": 0.01, - "Frances Anderson": 0.01, - "Pearl Oglethorpe": 0.01, - "E4": 0.01, - "Charlotte McDowd": 0.01, - "E10": 0.01, - "Olivia Carleton": 0.01, - "Flora Price": 0.01, - "E2": 0.00, - "E1": 0.00, - "Dorothy Murchison": 0.00, - "E13": 0.00, - "E14": 0.00, - } - for node, value in answer.items(): - assert value == pytest.approx(bet[node], abs=1e-2) - - def test_davis_closeness_centrality(self): - G = self.davis - clos = bipartite.closeness_centrality(G, self.top_nodes) - answer = { - "E8": 0.85, - "E9": 0.79, - "E7": 0.73, - "Nora Fayette": 0.80, - "Evelyn Jefferson": 0.80, - "Theresa Anderson": 0.80, - "E6": 0.69, - "Sylvia Avondale": 0.77, - "Laura Mandeville": 0.73, - "Brenda Rogers": 0.73, - "Katherina Rogers": 0.73, - "E5": 0.59, - "Helen Lloyd": 0.73, - "E3": 0.56, - "Ruth DeSand": 0.71, - "Verne Sanderson": 0.71, - "E12": 0.56, - "Myra Liddel": 0.69, - "E11": 0.54, - "Eleanor Nye": 0.67, - "Frances Anderson": 0.67, - "Pearl Oglethorpe": 0.67, - "E4": 0.54, - "Charlotte McDowd": 0.60, - "E10": 0.55, - "Olivia Carleton": 0.59, - "Flora Price": 0.59, - "E2": 0.52, - "E1": 0.52, - "Dorothy Murchison": 0.65, - "E13": 0.52, - "E14": 0.52, - } - for node, value in answer.items(): - assert value == pytest.approx(clos[node], abs=1e-2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_cluster.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_cluster.py deleted file mode 100644 index 72e2dba..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_cluster.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import bipartite -from networkx.algorithms.bipartite.cluster import cc_dot, cc_max, cc_min - - -def test_pairwise_bipartite_cc_functions(): - # Test functions for different kinds of bipartite clustering coefficients - # between pairs of nodes using 3 example graphs from figure 5 p. 40 - # Latapy et al (2008) - G1 = nx.Graph([(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7)]) - G2 = nx.Graph([(0, 2), (0, 3), (0, 4), (1, 3), (1, 4), (1, 5)]) - G3 = nx.Graph( - [(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9)] - ) - result = { - 0: [1 / 3.0, 2 / 3.0, 2 / 5.0], - 1: [1 / 2.0, 2 / 3.0, 2 / 3.0], - 2: [2 / 8.0, 2 / 5.0, 2 / 5.0], - } - for i, G in enumerate([G1, G2, G3]): - assert bipartite.is_bipartite(G) - assert cc_dot(set(G[0]), set(G[1])) == result[i][0] - assert cc_min(set(G[0]), set(G[1])) == result[i][1] - assert cc_max(set(G[0]), set(G[1])) == result[i][2] - - -def test_star_graph(): - G = nx.star_graph(3) - # all modes are the same - answer = {0: 0, 1: 1, 2: 1, 3: 1} - assert bipartite.clustering(G, mode="dot") == answer - assert bipartite.clustering(G, mode="min") == answer - assert bipartite.clustering(G, mode="max") == answer - - -def test_not_bipartite(): - with pytest.raises(nx.NetworkXError): - bipartite.clustering(nx.complete_graph(4)) - - -def test_bad_mode(): - with pytest.raises(nx.NetworkXError): - bipartite.clustering(nx.path_graph(4), mode="foo") - - -def test_path_graph(): - G = nx.path_graph(4) - answer = {0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5} - assert bipartite.clustering(G, mode="dot") == answer - assert bipartite.clustering(G, mode="max") == answer - answer = {0: 1, 1: 1, 2: 1, 3: 1} - assert bipartite.clustering(G, mode="min") == answer - - -def test_average_path_graph(): - G = nx.path_graph(4) - assert bipartite.average_clustering(G, mode="dot") == 0.5 - assert bipartite.average_clustering(G, mode="max") == 0.5 - assert bipartite.average_clustering(G, mode="min") == 1 - - -def test_ra_clustering_davis(): - G = nx.davis_southern_women_graph() - cc4 = round(bipartite.robins_alexander_clustering(G), 3) - assert cc4 == 0.468 - - -def test_ra_clustering_square(): - G = nx.path_graph(4) - G.add_edge(0, 3) - assert bipartite.robins_alexander_clustering(G) == 1.0 - - -def test_ra_clustering_zero(): - G = nx.Graph() - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_nodes_from(range(4)) - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_edges_from([(0, 1), (2, 3), (3, 4)]) - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_edge(1, 2) - assert bipartite.robins_alexander_clustering(G) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_covering.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_covering.py deleted file mode 100644 index 9507e13..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_covering.py +++ /dev/null @@ -1,33 +0,0 @@ -import networkx as nx -from networkx.algorithms import bipartite - - -class TestMinEdgeCover: - """Tests for :func:`networkx.algorithms.bipartite.min_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert bipartite.min_edge_cover(G) == set() - - def test_graph_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert bipartite.min_edge_cover(G) == {(0, 1), (1, 0)} - - def test_bipartite_default(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(["a", "b", "c"], bipartite=1) - G.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")]) - min_cover = bipartite.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 - - def test_bipartite_explicit(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(["a", "b", "c"], bipartite=1) - G.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")]) - min_cover = bipartite.min_edge_cover(G, bipartite.eppstein_matching) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_edgelist.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_edgelist.py deleted file mode 100644 index 66be8a2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_edgelist.py +++ /dev/null @@ -1,240 +0,0 @@ -""" -Unit tests for bipartite edgelists. -""" - -import io - -import pytest - -import networkx as nx -from networkx.algorithms import bipartite -from networkx.utils import edges_equal, graphs_equal, nodes_equal - - -class TestEdgelist: - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")] - cls.G.add_edges_from(e) - cls.G.add_nodes_from(["a", "c", "e"], bipartite=0) - cls.G.add_nodes_from(["b", "d", "f"], bipartite=1) - cls.G.add_node("g", bipartite=0) - cls.DG = nx.DiGraph(cls.G) - cls.MG = nx.MultiGraph() - cls.MG.add_edges_from([(1, 2), (1, 2), (1, 2)]) - cls.MG.add_node(1, bipartite=0) - cls.MG.add_node(2, bipartite=1) - - def test_read_edgelist_1(self): - s = b"""\ -# comment line -1 2 -# comment line -2 3 -""" - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int) - assert edges_equal(G.edges(), [(1, 2), (2, 3)]) - - def test_read_edgelist_3(self): - s = b"""\ -# comment line -1 2 {'weight':2.0} -# comment line -2 3 {'weight':3.0} -""" - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int, data=False) - assert edges_equal(G.edges(), [(1, 2), (2, 3)]) - - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int, data=True) - assert edges_equal( - G.edges(data=True), [(1, 2, {"weight": 2.0}), (2, 3, {"weight": 3.0})] - ) - - def test_write_edgelist_1(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=False) - fh.seek(0) - assert fh.read() == b"1 2\n3 2\n" - - def test_write_edgelist_2(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {}\n3 2 {}\n" - - def test_write_edgelist_3(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {'weight': 2.0}\n3 2 {'weight': 3.0}\n" - - def test_write_edgelist_4(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=[("weight")]) - fh.seek(0) - assert fh.read() == b"1 2 2.0\n3 2 3.0\n" - - def test_unicode(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node("Radiohead", bipartite=1) - - fname = tmp_path / "edgelist.txt" - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname) - assert graphs_equal(G, H) - - def test_latin1_issue(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node("Radiohead", bipartite=1) - - fname = tmp_path / "edgelist.txt" - with pytest.raises(UnicodeEncodeError): - bipartite.write_edgelist(G, fname, encoding="latin-1") - - def test_latin1(self, tmp_path): - G = nx.Graph() - name1 = "Bj" + chr(246) + "rk" - name2 = chr(220) + "ber" - G.add_edge(name1, "Radiohead", **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node("Radiohead", bipartite=1) - - fname = tmp_path / "edgelist.txt" - bipartite.write_edgelist(G, fname, encoding="latin-1") - H = bipartite.read_edgelist(fname, encoding="latin-1") - assert graphs_equal(G, H) - - def test_edgelist_graph(self, tmp_path): - G = self.G - fname = tmp_path / "edgelist.txt" - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname) - H2 = bipartite.read_edgelist(fname) - assert H is not H2 # they should be different graphs - G.remove_node("g") # isolated nodes are not written in edgelist - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_integers(self, tmp_path): - G = nx.convert_node_labels_to_integers(self.G) - fname = tmp_path / "edgelist.txt" - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname, nodetype=int) - # isolated nodes are not written in edgelist - G.remove_nodes_from(list(nx.isolates(G))) - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_multigraph(self, tmp_path): - G = self.MG - fname = tmp_path / "edgelist.txt" - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_empty_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - bytesIO = io.BytesIO() - bipartite.write_edgelist(nx.DiGraph(), bytesIO) - - def test_raise_attribute(self): - with pytest.raises(AttributeError): - G = nx.path_graph(4) - bytesIO = io.BytesIO() - bipartite.write_edgelist(G, bytesIO) - - def test_parse_edgelist(self): - """Tests for conditions specific to - parse_edge_list method""" - - # ignore strings of length less than 2 - lines = ["1 2", "2 3", "3 1", "4", " "] - G = bipartite.parse_edgelist(lines, nodetype=int) - assert list(G.nodes) == [1, 2, 3] - - # Exception raised when node is not convertible - # to specified data type - with pytest.raises(TypeError, match=".*Failed to convert nodes"): - lines = ["a b", "b c", "c a"] - G = bipartite.parse_edgelist(lines, nodetype=int) - - # Exception raised when format of data is not - # convertible to dictionary object - with pytest.raises(TypeError, match=".*Failed to convert edge data"): - lines = ["1 2 3", "2 3 4", "3 1 2"] - G = bipartite.parse_edgelist(lines, nodetype=int) - - # Exception raised when edge data and data - # keys are not of same length - with pytest.raises(IndexError): - lines = ["1 2 3 4", "2 3 4"] - G = bipartite.parse_edgelist( - lines, nodetype=int, data=[("weight", int), ("key", int)] - ) - - # Exception raised when edge data is not - # convertible to specified data type - with pytest.raises(TypeError, match=".*Failed to convert key data"): - lines = ["1 2 3 a", "2 3 4 b"] - G = bipartite.parse_edgelist( - lines, nodetype=int, data=[("weight", int), ("key", int)] - ) - - -def test_bipartite_edgelist_consistent_strip_handling(): - """See gh-7462 - - Input when printed looks like: - - A B interaction 2 - B C interaction 4 - C A interaction - - Note the trailing \\t in the last line, which indicates the existence of - an empty data field. - """ - lines = io.StringIO( - "A\tB\tinteraction\t2\nB\tC\tinteraction\t4\nC\tA\tinteraction\t" - ) - descr = [("type", str), ("weight", str)] - # Should not raise - G = nx.bipartite.parse_edgelist(lines, delimiter="\t", data=descr) - expected = [("A", "B", "2"), ("A", "C", ""), ("B", "C", "4")] - assert sorted(G.edges(data="weight")) == expected diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_extendability.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_extendability.py deleted file mode 100644 index 17b7124..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_extendability.py +++ /dev/null @@ -1,334 +0,0 @@ -import pytest - -import networkx as nx - - -def test_selfloops_raises(): - G = nx.ladder_graph(3) - G.add_edge(0, 0) - with pytest.raises(nx.NetworkXError, match=".*not bipartite"): - nx.bipartite.maximal_extendability(G) - - -def test_disconnected_raises(): - G = nx.ladder_graph(3) - G.add_node("a") - with pytest.raises(nx.NetworkXError, match=".*not connected"): - nx.bipartite.maximal_extendability(G) - - -def test_not_bipartite_raises(): - G = nx.complete_graph(5) - with pytest.raises(nx.NetworkXError, match=".*not bipartite"): - nx.bipartite.maximal_extendability(G) - - -def test_no_perfect_matching_raises(): - G = nx.Graph([(0, 1), (0, 2)]) - with pytest.raises(nx.NetworkXError, match=".*not contain a perfect matching"): - nx.bipartite.maximal_extendability(G) - - -def test_residual_graph_not_strongly_connected_raises(): - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - with pytest.raises( - nx.NetworkXError, match="The residual graph of G is not strongly connected" - ): - nx.bipartite.maximal_extendability(G) - - -def test_ladder_graph_is_1(): - G = nx.ladder_graph(3) - assert nx.bipartite.maximal_extendability(G) == 1 - - -def test_cubical_graph_is_2(): - G = nx.cubical_graph() - assert nx.bipartite.maximal_extendability(G) == 2 - - -def test_k_is_3(): - G = nx.Graph( - [ - (1, 6), - (1, 7), - (1, 8), - (1, 9), - (2, 6), - (2, 7), - (2, 8), - (2, 10), - (3, 6), - (3, 8), - (3, 9), - (3, 10), - (4, 7), - (4, 8), - (4, 9), - (4, 10), - (5, 6), - (5, 7), - (5, 9), - (5, 10), - ] - ) - assert nx.bipartite.maximal_extendability(G) == 3 - - -def test_k_is_4(): - G = nx.Graph( - [ - (8, 1), - (8, 2), - (8, 3), - (8, 4), - (8, 5), - (9, 1), - (9, 2), - (9, 3), - (9, 4), - (9, 7), - (10, 1), - (10, 2), - (10, 3), - (10, 4), - (10, 6), - (11, 1), - (11, 2), - (11, 5), - (11, 6), - (11, 7), - (12, 1), - (12, 3), - (12, 5), - (12, 6), - (12, 7), - (13, 2), - (13, 4), - (13, 5), - (13, 6), - (13, 7), - (14, 3), - (14, 4), - (14, 5), - (14, 6), - (14, 7), - ] - ) - assert nx.bipartite.maximal_extendability(G) == 4 - - -def test_k_is_5(): - G = nx.Graph( - [ - (8, 1), - (8, 2), - (8, 3), - (8, 4), - (8, 5), - (8, 6), - (9, 1), - (9, 2), - (9, 3), - (9, 4), - (9, 5), - (9, 7), - (10, 1), - (10, 2), - (10, 3), - (10, 4), - (10, 6), - (10, 7), - (11, 1), - (11, 2), - (11, 3), - (11, 5), - (11, 6), - (11, 7), - (12, 1), - (12, 2), - (12, 4), - (12, 5), - (12, 6), - (12, 7), - (13, 1), - (13, 3), - (13, 4), - (13, 5), - (13, 6), - (13, 7), - (14, 2), - (14, 3), - (14, 4), - (14, 5), - (14, 6), - (14, 7), - ] - ) - assert nx.bipartite.maximal_extendability(G) == 5 - - -def test_k_is_6(): - G = nx.Graph( - [ - (9, 1), - (9, 2), - (9, 3), - (9, 4), - (9, 5), - (9, 6), - (9, 7), - (10, 1), - (10, 2), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (10, 8), - (11, 1), - (11, 2), - (11, 3), - (11, 4), - (11, 5), - (11, 7), - (11, 8), - (12, 1), - (12, 2), - (12, 3), - (12, 4), - (12, 6), - (12, 7), - (12, 8), - (13, 1), - (13, 2), - (13, 3), - (13, 5), - (13, 6), - (13, 7), - (13, 8), - (14, 1), - (14, 2), - (14, 4), - (14, 5), - (14, 6), - (14, 7), - (14, 8), - (15, 1), - (15, 3), - (15, 4), - (15, 5), - (15, 6), - (15, 7), - (15, 8), - (16, 2), - (16, 3), - (16, 4), - (16, 5), - (16, 6), - (16, 7), - (16, 8), - ] - ) - assert nx.bipartite.maximal_extendability(G) == 6 - - -def test_k_is_7(): - G = nx.Graph( - [ - (1, 11), - (1, 12), - (1, 13), - (1, 14), - (1, 15), - (1, 16), - (1, 17), - (1, 18), - (2, 11), - (2, 12), - (2, 13), - (2, 14), - (2, 15), - (2, 16), - (2, 17), - (2, 19), - (3, 11), - (3, 12), - (3, 13), - (3, 14), - (3, 15), - (3, 16), - (3, 17), - (3, 20), - (4, 11), - (4, 12), - (4, 13), - (4, 14), - (4, 15), - (4, 16), - (4, 17), - (4, 18), - (4, 19), - (4, 20), - (5, 11), - (5, 12), - (5, 13), - (5, 14), - (5, 15), - (5, 16), - (5, 17), - (5, 18), - (5, 19), - (5, 20), - (6, 11), - (6, 12), - (6, 13), - (6, 14), - (6, 15), - (6, 16), - (6, 17), - (6, 18), - (6, 19), - (6, 20), - (7, 11), - (7, 12), - (7, 13), - (7, 14), - (7, 15), - (7, 16), - (7, 17), - (7, 18), - (7, 19), - (7, 20), - (8, 11), - (8, 12), - (8, 13), - (8, 14), - (8, 15), - (8, 16), - (8, 17), - (8, 18), - (8, 19), - (8, 20), - (9, 11), - (9, 12), - (9, 13), - (9, 14), - (9, 15), - (9, 16), - (9, 17), - (9, 18), - (9, 19), - (9, 20), - (10, 11), - (10, 12), - (10, 13), - (10, 14), - (10, 15), - (10, 16), - (10, 17), - (10, 18), - (10, 19), - (10, 20), - ] - ) - assert nx.bipartite.maximal_extendability(G) == 7 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_generators.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_generators.py deleted file mode 100644 index 8b1e779..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_generators.py +++ /dev/null @@ -1,409 +0,0 @@ -import numbers - -import pytest - -import networkx as nx - -from ..generators import ( - alternating_havel_hakimi_graph, - complete_bipartite_graph, - configuration_model, - gnmk_random_graph, - havel_hakimi_graph, - preferential_attachment_graph, - random_graph, - reverse_havel_hakimi_graph, -) - -""" -Generators - Bipartite ----------------------- -""" - - -class TestGeneratorsBipartite: - def test_complete_bipartite_graph(self): - G = complete_bipartite_graph(0, 0) - assert nx.is_isomorphic(G, nx.null_graph()) - - for i in [1, 5]: - G = complete_bipartite_graph(i, 0) - assert nx.is_isomorphic(G, nx.empty_graph(i)) - G = complete_bipartite_graph(0, i) - assert nx.is_isomorphic(G, nx.empty_graph(i)) - - G = complete_bipartite_graph(2, 2) - assert nx.is_isomorphic(G, nx.cycle_graph(4)) - - G = complete_bipartite_graph(1, 5) - assert nx.is_isomorphic(G, nx.star_graph(5)) - - G = complete_bipartite_graph(5, 1) - assert nx.is_isomorphic(G, nx.star_graph(5)) - - # complete_bipartite_graph(m1,m2) is a connected graph with - # m1+m2 nodes and m1*m2 edges - for m1, m2 in [(5, 11), (7, 3)]: - G = complete_bipartite_graph(m1, m2) - assert nx.number_of_nodes(G) == m1 + m2 - assert nx.number_of_edges(G) == m1 * m2 - - with pytest.raises(nx.NetworkXError): - complete_bipartite_graph(7, 3, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError): - complete_bipartite_graph(7, 3, create_using=nx.MultiDiGraph) - - mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph) - assert mG.is_multigraph() - assert sorted(mG.edges()) == sorted(G.edges()) - - mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph) - assert mG.is_multigraph() - assert sorted(mG.edges()) == sorted(G.edges()) - - mG = complete_bipartite_graph(7, 3) # default to Graph - assert sorted(mG.edges()) == sorted(G.edges()) - assert not mG.is_multigraph() - assert not mG.is_directed() - - # specify nodes rather than number of nodes - for n1, n2 in [([1, 2], "ab"), (3, 2), (3, "ab"), ("ab", 3)]: - G = complete_bipartite_graph(n1, n2) - if isinstance(n1, numbers.Integral): - if isinstance(n2, numbers.Integral): - n2 = range(n1, n1 + n2) - n1 = range(n1) - elif isinstance(n2, numbers.Integral): - n2 = range(n2) - edges = {(u, v) for u in n1 for v in n2} - assert edges == set(G.edges) - assert G.size() == len(edges) - - # raise when node sets are not distinct - for n1, n2 in [([1, 2], 3), (3, [1, 2]), ("abc", "bcd")]: - pytest.raises(nx.NetworkXError, complete_bipartite_graph, n1, n2) - - def test_configuration_model(self): - aseq = [] - bseq = [] - G = configuration_model(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = configuration_model(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, configuration_model, aseq, bseq) - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2, 2] - G = configuration_model(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = configuration_model(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = configuration_model(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3] - - GU = nx.projected_graph(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.projected_graph(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises( - nx.NetworkXError, configuration_model, aseq, bseq, create_using=nx.DiGraph() - ) - pytest.raises( - nx.NetworkXError, configuration_model, aseq, bseq, create_using=nx.DiGraph - ) - pytest.raises( - nx.NetworkXError, - configuration_model, - aseq, - bseq, - create_using=nx.MultiDiGraph, - ) - - def test_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = havel_hakimi_graph(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - GU = nx.projected_graph(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.projected_graph(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 4 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises( - nx.NetworkXError, havel_hakimi_graph, aseq, bseq, create_using=nx.DiGraph - ) - pytest.raises( - nx.NetworkXError, havel_hakimi_graph, aseq, bseq, create_using=nx.DiGraph - ) - pytest.raises( - nx.NetworkXError, - havel_hakimi_graph, - aseq, - bseq, - create_using=nx.MultiDiGraph, - ) - - def test_reverse_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, reverse_havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3] - - GU = nx.projected_graph(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.projected_graph(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises( - nx.NetworkXError, - reverse_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.DiGraph, - ) - pytest.raises( - nx.NetworkXError, - reverse_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.DiGraph, - ) - pytest.raises( - nx.NetworkXError, - reverse_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.MultiDiGraph, - ) - - def test_alternating_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, alternating_havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3] - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3] - - GU = nx.projected_graph(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.projected_graph(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises( - nx.NetworkXError, - alternating_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.DiGraph, - ) - pytest.raises( - nx.NetworkXError, - alternating_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.DiGraph, - ) - pytest.raises( - nx.NetworkXError, - alternating_havel_hakimi_graph, - aseq, - bseq, - create_using=nx.MultiDiGraph, - ) - - def test_preferential_attachment(self): - aseq = [3, 2, 1, 1] - G = preferential_attachment_graph(aseq, 0.5) - assert G.is_multigraph() - assert not G.is_directed() - - G = preferential_attachment_graph(aseq, 0.5, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises( - nx.NetworkXError, - preferential_attachment_graph, - aseq, - 0.5, - create_using=nx.DiGraph(), - ) - pytest.raises( - nx.NetworkXError, - preferential_attachment_graph, - aseq, - 0.5, - create_using=nx.DiGraph(), - ) - pytest.raises( - nx.NetworkXError, - preferential_attachment_graph, - aseq, - 0.5, - create_using=nx.DiGraph(), - ) - - def test_random_graph(self): - n = 10 - m = 20 - G = random_graph(n, m, 0.9) - assert len(G) == 30 - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - - def test_random_digraph(self): - n = 10 - m = 20 - G = random_graph(n, m, 0.9, directed=True) - assert len(G) == 30 - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - - def test_gnmk_random_graph(self): - n = 10 - m = 20 - edges = 100 - # set seed because sometimes it is not connected - # which raises an error in bipartite.sets(G) below. - G = gnmk_random_graph(n, m, edges, seed=1234) - assert len(G) == n + m - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - # print(X) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - assert edges == len(list(G.edges())) - - def test_gnmk_random_graph_complete(self): - n = 10 - m = 20 - edges = 200 - G = gnmk_random_graph(n, m, edges) - assert len(G) == n + m - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - # print(X) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - assert edges == len(list(G.edges())) - - @pytest.mark.parametrize("n", (4, range(4), {0, 1, 2, 3})) - @pytest.mark.parametrize("m", (range(4, 7), {4, 5, 6})) - def test_complete_bipartite_graph_str(self, n, m): - """Ensure G.name is consistent for all inputs accepted by nodes_or_number. - See gh-7396""" - G = nx.complete_bipartite_graph(n, m) - ans = "Graph named 'complete_bipartite_graph(4, 3)' with 7 nodes and 12 edges" - assert str(G) == ans diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matching.py deleted file mode 100644 index c24659e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matching.py +++ /dev/null @@ -1,327 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.bipartite.matching` module.""" - -import itertools - -import pytest - -import networkx as nx -from networkx.algorithms.bipartite.matching import ( - eppstein_matching, - hopcroft_karp_matching, - maximum_matching, - minimum_weight_full_matching, - to_vertex_cover, -) - - -class TestMatching: - """Tests for bipartite matching algorithms.""" - - def setup_method(self): - """Creates a bipartite graph for use in testing matching algorithms. - - The bipartite graph has a maximum cardinality matching that leaves - vertex 1 and vertex 10 unmatched. The first six numbers are the left - vertices and the next six numbers are the right vertices. - - """ - self.simple_graph = nx.complete_bipartite_graph(2, 3) - self.simple_solution = {0: 2, 1: 3, 2: 0, 3: 1} - - edges = [(0, 7), (0, 8), (2, 6), (2, 9), (3, 8), (4, 8), (4, 9), (5, 11)] - self.top_nodes = set(range(6)) - self.graph = nx.Graph() - self.graph.add_nodes_from(range(12)) - self.graph.add_edges_from(edges) - - # Example bipartite graph from issue 2127 - G = nx.Graph() - G.add_nodes_from( - [ - (1, "C"), - (1, "B"), - (0, "G"), - (1, "F"), - (1, "E"), - (0, "C"), - (1, "D"), - (1, "I"), - (0, "A"), - (0, "D"), - (0, "F"), - (0, "E"), - (0, "H"), - (1, "G"), - (1, "A"), - (0, "I"), - (0, "B"), - (1, "H"), - ] - ) - G.add_edge((1, "C"), (0, "A")) - G.add_edge((1, "B"), (0, "A")) - G.add_edge((0, "G"), (1, "I")) - G.add_edge((0, "G"), (1, "H")) - G.add_edge((1, "F"), (0, "A")) - G.add_edge((1, "F"), (0, "C")) - G.add_edge((1, "F"), (0, "E")) - G.add_edge((1, "E"), (0, "A")) - G.add_edge((1, "E"), (0, "C")) - G.add_edge((0, "C"), (1, "D")) - G.add_edge((0, "C"), (1, "I")) - G.add_edge((0, "C"), (1, "G")) - G.add_edge((0, "C"), (1, "H")) - G.add_edge((1, "D"), (0, "A")) - G.add_edge((1, "I"), (0, "A")) - G.add_edge((1, "I"), (0, "E")) - G.add_edge((0, "A"), (1, "G")) - G.add_edge((0, "A"), (1, "H")) - G.add_edge((0, "E"), (1, "G")) - G.add_edge((0, "E"), (1, "H")) - self.disconnected_graph = G - - def check_match(self, matching): - """Asserts that the matching is what we expect from the bipartite graph - constructed in the :meth:`setup` fixture. - - """ - # For the sake of brevity, rename `matching` to `M`. - M = matching - matched_vertices = frozenset(itertools.chain(*M.items())) - # Assert that the maximum number of vertices (10) is matched. - assert matched_vertices == frozenset(range(12)) - {1, 10} - # Assert that no vertex appears in two edges, or in other words, that - # the matching (u, v) and (v, u) both appear in the matching - # dictionary. - assert all(u == M[M[u]] for u in range(12) if u in M) - - def check_vertex_cover(self, vertices): - """Asserts that the given set of vertices is the vertex cover we - expected from the bipartite graph constructed in the :meth:`setup` - fixture. - - """ - # By Konig's theorem, the number of edges in a maximum matching equals - # the number of vertices in a minimum vertex cover. - assert len(vertices) == 5 - # Assert that the set is truly a vertex cover. - for u, v in self.graph.edges(): - assert u in vertices or v in vertices - # TODO Assert that the vertices are the correct ones. - - def test_eppstein_matching(self): - """Tests that David Eppstein's implementation of the Hopcroft--Karp - algorithm produces a maximum cardinality matching. - - """ - self.check_match(eppstein_matching(self.graph, self.top_nodes)) - - def test_hopcroft_karp_matching(self): - """Tests that the Hopcroft--Karp algorithm produces a maximum - cardinality matching in a bipartite graph. - - """ - self.check_match(hopcroft_karp_matching(self.graph, self.top_nodes)) - - def test_to_vertex_cover(self): - """Test for converting a maximum matching to a minimum vertex cover.""" - matching = maximum_matching(self.graph, self.top_nodes) - vertex_cover = to_vertex_cover(self.graph, matching, self.top_nodes) - self.check_vertex_cover(vertex_cover) - - def test_eppstein_matching_simple(self): - match = eppstein_matching(self.simple_graph) - assert match == self.simple_solution - - def test_hopcroft_karp_matching_simple(self): - match = hopcroft_karp_matching(self.simple_graph) - assert match == self.simple_solution - - def test_eppstein_matching_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - match = eppstein_matching(self.disconnected_graph) - - def test_hopcroft_karp_matching_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - match = hopcroft_karp_matching(self.disconnected_graph) - - def test_issue_2127(self): - """Test from issue 2127""" - # Build the example DAG - G = nx.DiGraph() - G.add_edge("A", "C") - G.add_edge("A", "B") - G.add_edge("C", "E") - G.add_edge("C", "D") - G.add_edge("E", "G") - G.add_edge("E", "F") - G.add_edge("G", "I") - G.add_edge("G", "H") - - tc = nx.transitive_closure(G) - btc = nx.Graph() - - # Create a bipartite graph based on the transitive closure of G - for v in tc.nodes(): - btc.add_node((0, v)) - btc.add_node((1, v)) - - for u, v in tc.edges(): - btc.add_edge((0, u), (1, v)) - - top_nodes = {n for n in btc if n[0] == 0} - matching = hopcroft_karp_matching(btc, top_nodes) - vertex_cover = to_vertex_cover(btc, matching, top_nodes) - independent_set = set(G) - {v for _, v in vertex_cover} - assert {"B", "D", "F", "I", "H"} == independent_set - - def test_vertex_cover_issue_2384(self): - G = nx.Graph([(0, 3), (1, 3), (1, 4), (2, 3)]) - matching = maximum_matching(G) - vertex_cover = to_vertex_cover(G, matching) - for u, v in G.edges(): - assert u in vertex_cover or v in vertex_cover - - def test_vertex_cover_issue_3306(self): - G = nx.Graph() - edges = [(0, 2), (1, 0), (1, 1), (1, 2), (2, 2)] - G.add_edges_from([((i, "L"), (j, "R")) for i, j in edges]) - - matching = maximum_matching(G) - vertex_cover = to_vertex_cover(G, matching) - for u, v in G.edges(): - assert u in vertex_cover or v in vertex_cover - - def test_unorderable_nodes(self): - a = object() - b = object() - c = object() - d = object() - e = object() - G = nx.Graph([(a, d), (b, d), (b, e), (c, d)]) - matching = maximum_matching(G) - vertex_cover = to_vertex_cover(G, matching) - for u, v in G.edges(): - assert u in vertex_cover or v in vertex_cover - - -def test_eppstein_matching(): - """Test in accordance to issue #1927""" - G = nx.Graph() - G.add_nodes_from(["a", 2, 3, 4], bipartite=0) - G.add_nodes_from([1, "b", "c"], bipartite=1) - G.add_edges_from([("a", 1), ("a", "b"), (2, "b"), (2, "c"), (3, "c"), (4, 1)]) - matching = eppstein_matching(G) - assert len(matching) == len(maximum_matching(G)) - assert all(x in set(matching.keys()) for x in set(matching.values())) - - -class TestMinimumWeightFullMatching: - @classmethod - def setup_class(cls): - pytest.importorskip("scipy") - - def test_minimum_weight_full_matching_incomplete_graph(self): - B = nx.Graph() - B.add_nodes_from([1, 2], bipartite=0) - B.add_nodes_from([3, 4], bipartite=1) - B.add_edge(1, 4, weight=100) - B.add_edge(2, 3, weight=100) - B.add_edge(2, 4, weight=50) - matching = minimum_weight_full_matching(B) - assert matching == {1: 4, 2: 3, 4: 1, 3: 2} - - def test_minimum_weight_full_matching_with_no_full_matching(self): - B = nx.Graph() - B.add_nodes_from([1, 2, 3], bipartite=0) - B.add_nodes_from([4, 5, 6], bipartite=1) - B.add_edge(1, 4, weight=100) - B.add_edge(2, 4, weight=100) - B.add_edge(3, 4, weight=50) - B.add_edge(3, 5, weight=50) - B.add_edge(3, 6, weight=50) - with pytest.raises(ValueError): - minimum_weight_full_matching(B) - - def test_minimum_weight_full_matching_square(self): - G = nx.complete_bipartite_graph(3, 3) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=300) - matching = minimum_weight_full_matching(G) - assert matching == {0: 4, 1: 3, 2: 5, 4: 0, 3: 1, 5: 2} - - def test_minimum_weight_full_matching_smaller_left(self): - G = nx.complete_bipartite_graph(3, 4) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=1) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(1, 6, weight=2) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=290) - G.add_edge(2, 6, weight=3) - matching = minimum_weight_full_matching(G) - assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1} - - def test_minimum_weight_full_matching_smaller_top_nodes_right(self): - G = nx.complete_bipartite_graph(3, 4) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=1) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(1, 6, weight=2) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=290) - G.add_edge(2, 6, weight=3) - matching = minimum_weight_full_matching(G, top_nodes=[3, 4, 5, 6]) - assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1} - - def test_minimum_weight_full_matching_smaller_right(self): - G = nx.complete_bipartite_graph(4, 3) - G.add_edge(0, 4, weight=400) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=300) - G.add_edge(1, 4, weight=150) - G.add_edge(1, 5, weight=450) - G.add_edge(1, 6, weight=225) - G.add_edge(2, 4, weight=400) - G.add_edge(2, 5, weight=600) - G.add_edge(2, 6, weight=290) - G.add_edge(3, 4, weight=1) - G.add_edge(3, 5, weight=2) - G.add_edge(3, 6, weight=3) - matching = minimum_weight_full_matching(G) - assert matching == {1: 4, 2: 6, 3: 5, 4: 1, 5: 3, 6: 2} - - def test_minimum_weight_full_matching_negative_weights(self): - G = nx.complete_bipartite_graph(2, 2) - G.add_edge(0, 2, weight=-2) - G.add_edge(0, 3, weight=0.2) - G.add_edge(1, 2, weight=-2) - G.add_edge(1, 3, weight=0.3) - matching = minimum_weight_full_matching(G) - assert matching == {0: 3, 1: 2, 2: 1, 3: 0} - - def test_minimum_weight_full_matching_different_weight_key(self): - G = nx.complete_bipartite_graph(2, 2) - G.add_edge(0, 2, mass=2) - G.add_edge(0, 3, mass=0.2) - G.add_edge(1, 2, mass=1) - G.add_edge(1, 3, mass=2) - matching = minimum_weight_full_matching(G, weight="mass") - assert matching == {0: 3, 1: 2, 2: 1, 3: 0} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matrix.py deleted file mode 100644 index 53d8311..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_matrix.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -sp = pytest.importorskip("scipy") -sparse = pytest.importorskip("scipy.sparse") - - -import networkx as nx -from networkx.algorithms import bipartite -from networkx.utils import edges_equal - - -class TestBiadjacencyMatrix: - def test_biadjacency_matrix_weight(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2, other=4) - X = [1, 3] - Y = [0, 2, 4] - M = bipartite.biadjacency_matrix(G, X, weight="weight") - assert M[0, 0] == 2 - M = bipartite.biadjacency_matrix(G, X, weight="other") - assert M[0, 0] == 4 - - def test_biadjacency_matrix(self): - tops = [2, 5, 10] - bots = [5, 10, 15] - for i in range(len(tops)): - G = bipartite.random_graph(tops[i], bots[i], 0.2) - top = [n for n, d in G.nodes(data=True) if d["bipartite"] == 0] - M = bipartite.biadjacency_matrix(G, top) - assert M.shape[0] == tops[i] - assert M.shape[1] == bots[i] - - def test_biadjacency_matrix_order(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2) - X = [3, 1] - Y = [4, 2, 0] - M = bipartite.biadjacency_matrix(G, X, Y, weight="weight") - assert M[1, 2] == 2 - - def test_biadjacency_matrix_empty_graph(self): - G = nx.empty_graph(2) - M = nx.bipartite.biadjacency_matrix(G, [0]) - assert np.array_equal(M.toarray(), np.array([[0]])) - - def test_null_graph(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph(), []) - - def test_empty_graph(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), []) - - def test_duplicate_row(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [1, 1]) - - def test_duplicate_col(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], [1, 1]) - - def test_format_keyword(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], format="foo") - - def test_from_biadjacency_roundtrip(self): - B1 = nx.path_graph(5) - M = bipartite.biadjacency_matrix(B1, [0, 2, 4]) - B2 = bipartite.from_biadjacency_matrix(M) - assert nx.is_isomorphic(B1, B2) - - def test_from_biadjacency_weight(self): - M = sparse.csc_matrix([[1, 2], [0, 3]]) - B = bipartite.from_biadjacency_matrix(M) - assert edges_equal(B.edges(), [(0, 2), (0, 3), (1, 3)]) - B = bipartite.from_biadjacency_matrix(M, edge_attribute="weight") - e = [(0, 2, {"weight": 1}), (0, 3, {"weight": 2}), (1, 3, {"weight": 3})] - assert edges_equal(B.edges(data=True), e) - - def test_from_biadjacency_multigraph(self): - M = sparse.csc_matrix([[1, 2], [0, 3]]) - B = bipartite.from_biadjacency_matrix(M, create_using=nx.MultiGraph()) - assert edges_equal(B.edges(), [(0, 2), (0, 3), (0, 3), (1, 3), (1, 3), (1, 3)]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_project.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_project.py deleted file mode 100644 index 076bb42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_project.py +++ /dev/null @@ -1,407 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import bipartite -from networkx.utils import edges_equal, nodes_equal - - -class TestBipartiteProject: - def test_path_projected_graph(self): - G = nx.path_graph(4) - P = bipartite.projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - P = bipartite.projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - G = nx.MultiGraph([(0, 1)]) - with pytest.raises(nx.NetworkXError, match="not defined for multigraphs"): - bipartite.projected_graph(G, [0]) - - def test_path_projected_properties_graph(self): - G = nx.path_graph(4) - G.add_node(1, name="one") - G.add_node(2, name="two") - P = bipartite.projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - assert P.nodes[1]["name"] == G.nodes[1]["name"] - P = bipartite.projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - assert P.nodes[2]["name"] == G.nodes[2]["name"] - - def test_path_collaboration_projected_graph(self): - G = nx.path_graph(4) - P = bipartite.collaboration_weighted_projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]["weight"] = 1 - P = bipartite.collaboration_weighted_projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]["weight"] = 1 - - def test_directed_path_collaboration_projected_graph(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - P = bipartite.collaboration_weighted_projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]["weight"] = 1 - P = bipartite.collaboration_weighted_projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]["weight"] = 1 - - def test_path_weighted_projected_graph(self): - G = nx.path_graph(4) - - with pytest.raises(nx.NetworkXAlgorithmError): - bipartite.weighted_projected_graph(G, [1, 2, 3, 3]) - - P = bipartite.weighted_projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]["weight"] = 1 - P = bipartite.weighted_projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]["weight"] = 1 - - def test_digraph_weighted_projection(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 4)]) - P = bipartite.overlap_weighted_projected_graph(G, [1, 3]) - assert nx.get_edge_attributes(P, "weight") == {(1, 3): 1.0} - assert len(P) == 2 - - def test_path_weighted_projected_directed_graph(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - P = bipartite.weighted_projected_graph(G, [1, 3]) - assert nodes_equal(list(P), [1, 3]) - assert edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]["weight"] = 1 - P = bipartite.weighted_projected_graph(G, [0, 2]) - assert nodes_equal(list(P), [0, 2]) - assert edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]["weight"] = 1 - - def test_star_projected_graph(self): - G = nx.star_graph(3) - P = bipartite.projected_graph(G, [1, 2, 3]) - assert nodes_equal(list(P), [1, 2, 3]) - assert edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)]) - P = bipartite.weighted_projected_graph(G, [1, 2, 3]) - assert nodes_equal(list(P), [1, 2, 3]) - assert edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)]) - - P = bipartite.projected_graph(G, [0]) - assert nodes_equal(list(P), [0]) - assert edges_equal(list(P.edges()), []) - - def test_project_multigraph(self): - G = nx.Graph() - G.add_edge("a", 1) - G.add_edge("b", 1) - G.add_edge("a", 2) - G.add_edge("b", 2) - P = bipartite.projected_graph(G, "ab") - assert edges_equal(list(P.edges()), [("a", "b")]) - P = bipartite.weighted_projected_graph(G, "ab") - assert edges_equal(list(P.edges()), [("a", "b")]) - P = bipartite.projected_graph(G, "ab", multigraph=True) - assert edges_equal(list(P.edges()), [("a", "b"), ("a", "b")]) - - def test_project_collaboration(self): - G = nx.Graph() - G.add_edge("a", 1) - G.add_edge("b", 1) - G.add_edge("b", 2) - G.add_edge("c", 2) - G.add_edge("c", 3) - G.add_edge("c", 4) - G.add_edge("b", 4) - P = bipartite.collaboration_weighted_projected_graph(G, "abc") - assert P["a"]["b"]["weight"] == 1 - assert P["b"]["c"]["weight"] == 2 - - def test_directed_projection(self): - G = nx.DiGraph() - G.add_edge("A", 1) - G.add_edge(1, "B") - G.add_edge("A", 2) - G.add_edge("B", 2) - P = bipartite.projected_graph(G, "AB") - assert edges_equal(list(P.edges()), [("A", "B")]) - P = bipartite.weighted_projected_graph(G, "AB") - assert edges_equal(list(P.edges()), [("A", "B")]) - assert P["A"]["B"]["weight"] == 1 - - P = bipartite.projected_graph(G, "AB", multigraph=True) - assert edges_equal(list(P.edges()), [("A", "B")]) - - G = nx.DiGraph() - G.add_edge("A", 1) - G.add_edge(1, "B") - G.add_edge("A", 2) - G.add_edge(2, "B") - P = bipartite.projected_graph(G, "AB") - assert edges_equal(list(P.edges()), [("A", "B")]) - P = bipartite.weighted_projected_graph(G, "AB") - assert edges_equal(list(P.edges()), [("A", "B")]) - assert P["A"]["B"]["weight"] == 2 - - P = bipartite.projected_graph(G, "AB", multigraph=True) - assert edges_equal(list(P.edges()), [("A", "B"), ("A", "B")]) - - -class TestBipartiteWeightedProjection: - @classmethod - def setup_class(cls): - # Tore Opsahl's example - # http://toreopsahl.com/2009/05/01/projecting-two-mode-networks-onto-weighted-one-mode-networks/ - cls.G = nx.Graph() - cls.G.add_edge("A", 1) - cls.G.add_edge("A", 2) - cls.G.add_edge("B", 1) - cls.G.add_edge("B", 2) - cls.G.add_edge("B", 3) - cls.G.add_edge("B", 4) - cls.G.add_edge("B", 5) - cls.G.add_edge("C", 1) - cls.G.add_edge("D", 3) - cls.G.add_edge("E", 4) - cls.G.add_edge("E", 5) - cls.G.add_edge("E", 6) - cls.G.add_edge("F", 6) - # Graph based on figure 6 from Newman (2001) - cls.N = nx.Graph() - cls.N.add_edge("A", 1) - cls.N.add_edge("A", 2) - cls.N.add_edge("A", 3) - cls.N.add_edge("B", 1) - cls.N.add_edge("B", 2) - cls.N.add_edge("B", 3) - cls.N.add_edge("C", 1) - cls.N.add_edge("D", 1) - cls.N.add_edge("E", 3) - - def test_project_weighted_shared(self): - edges = [ - ("A", "B", 2), - ("A", "C", 1), - ("B", "C", 1), - ("B", "D", 1), - ("B", "E", 2), - ("E", "F", 1), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.G, "ABCDEF") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - edges = [ - ("A", "B", 3), - ("A", "E", 1), - ("A", "C", 1), - ("A", "D", 1), - ("B", "E", 1), - ("B", "C", 1), - ("B", "D", 1), - ("C", "D", 1), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.N, "ABCDE") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - def test_project_weighted_newman(self): - edges = [ - ("A", "B", 1.5), - ("A", "C", 0.5), - ("B", "C", 0.5), - ("B", "D", 1), - ("B", "E", 2), - ("E", "F", 1), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.collaboration_weighted_projected_graph(self.G, "ABCDEF") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - edges = [ - ("A", "B", 11 / 6.0), - ("A", "E", 1 / 2.0), - ("A", "C", 1 / 3.0), - ("A", "D", 1 / 3.0), - ("B", "E", 1 / 2.0), - ("B", "C", 1 / 3.0), - ("B", "D", 1 / 3.0), - ("C", "D", 1 / 3.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.collaboration_weighted_projected_graph(self.N, "ABCDE") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - def test_project_weighted_ratio(self): - edges = [ - ("A", "B", 2 / 6.0), - ("A", "C", 1 / 6.0), - ("B", "C", 1 / 6.0), - ("B", "D", 1 / 6.0), - ("B", "E", 2 / 6.0), - ("E", "F", 1 / 6.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.G, "ABCDEF", ratio=True) - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - edges = [ - ("A", "B", 3 / 3.0), - ("A", "E", 1 / 3.0), - ("A", "C", 1 / 3.0), - ("A", "D", 1 / 3.0), - ("B", "E", 1 / 3.0), - ("B", "C", 1 / 3.0), - ("B", "D", 1 / 3.0), - ("C", "D", 1 / 3.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.N, "ABCDE", ratio=True) - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - def test_project_weighted_overlap(self): - edges = [ - ("A", "B", 2 / 2.0), - ("A", "C", 1 / 1.0), - ("B", "C", 1 / 1.0), - ("B", "D", 1 / 1.0), - ("B", "E", 2 / 3.0), - ("E", "F", 1 / 1.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.G, "ABCDEF", jaccard=False) - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - edges = [ - ("A", "B", 3 / 3.0), - ("A", "E", 1 / 1.0), - ("A", "C", 1 / 1.0), - ("A", "D", 1 / 1.0), - ("B", "E", 1 / 1.0), - ("B", "C", 1 / 1.0), - ("B", "D", 1 / 1.0), - ("C", "D", 1 / 1.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.N, "ABCDE", jaccard=False) - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - def test_project_weighted_jaccard(self): - edges = [ - ("A", "B", 2 / 5.0), - ("A", "C", 1 / 2.0), - ("B", "C", 1 / 5.0), - ("B", "D", 1 / 5.0), - ("B", "E", 2 / 6.0), - ("E", "F", 1 / 3.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.G, "ABCDEF") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - edges = [ - ("A", "B", 3 / 3.0), - ("A", "E", 1 / 3.0), - ("A", "C", 1 / 3.0), - ("A", "D", 1 / 3.0), - ("B", "E", 1 / 3.0), - ("B", "C", 1 / 3.0), - ("B", "D", 1 / 3.0), - ("C", "D", 1 / 1.0), - ] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.N, "ABCDE") - assert edges_equal(list(P.edges()), Panswer.edges()) - for u, v in P.edges(): - assert P[u][v]["weight"] == Panswer[u][v]["weight"] - - def test_generic_weighted_projected_graph_simple(self): - def shared(G, u, v): - return len(set(G[u]) & set(G[v])) - - B = nx.path_graph(5) - G = bipartite.generic_weighted_projected_graph( - B, [0, 2, 4], weight_function=shared - ) - assert nodes_equal(list(G), [0, 2, 4]) - assert edges_equal( - list(G.edges(data=True)), - [(0, 2, {"weight": 1}), (2, 4, {"weight": 1})], - ) - - G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4]) - assert nodes_equal(list(G), [0, 2, 4]) - assert edges_equal( - list(G.edges(data=True)), - [(0, 2, {"weight": 1}), (2, 4, {"weight": 1})], - ) - B = nx.DiGraph() - nx.add_path(B, range(5)) - G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4]) - assert nodes_equal(list(G), [0, 2, 4]) - assert edges_equal( - list(G.edges(data=True)), [(0, 2, {"weight": 1}), (2, 4, {"weight": 1})] - ) - - def test_generic_weighted_projected_graph_custom(self): - def jaccard(G, u, v): - unbrs = set(G[u]) - vnbrs = set(G[v]) - return len(unbrs & vnbrs) / len(unbrs | vnbrs) - - def my_weight(G, u, v, weight="weight"): - w = 0 - for nbr in set(G[u]) & set(G[v]): - w += G.edges[u, nbr].get(weight, 1) + G.edges[v, nbr].get(weight, 1) - return w - - B = nx.bipartite.complete_bipartite_graph(2, 2) - for i, (u, v) in enumerate(B.edges()): - B.edges[u, v]["weight"] = i + 1 - G = bipartite.generic_weighted_projected_graph( - B, [0, 1], weight_function=jaccard - ) - assert edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 1.0})]) - G = bipartite.generic_weighted_projected_graph( - B, [0, 1], weight_function=my_weight - ) - assert edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 10})]) - G = bipartite.generic_weighted_projected_graph(B, [0, 1]) - assert edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 2})]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_redundancy.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_redundancy.py deleted file mode 100644 index 8d979db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_redundancy.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.bipartite.redundancy` module.""" - -import pytest - -from networkx import NetworkXError, cycle_graph -from networkx.algorithms.bipartite import complete_bipartite_graph, node_redundancy - - -def test_no_redundant_nodes(): - G = complete_bipartite_graph(2, 2) - - # when nodes is None - rc = node_redundancy(G) - assert all(redundancy == 1 for redundancy in rc.values()) - - # when set of nodes is specified - rc = node_redundancy(G, (2, 3)) - assert rc == {2: 1.0, 3: 1.0} - - -def test_redundant_nodes(): - G = cycle_graph(6) - edge = {0, 3} - G.add_edge(*edge) - redundancy = node_redundancy(G) - for v in edge: - assert redundancy[v] == 2 / 3 - for v in set(G) - edge: - assert redundancy[v] == 1 - - -def test_not_enough_neighbors(): - with pytest.raises(NetworkXError): - G = complete_bipartite_graph(1, 2) - node_redundancy(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py deleted file mode 100644 index b940649..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +++ /dev/null @@ -1,80 +0,0 @@ -import pytest - -pytest.importorskip("scipy") - -import networkx as nx -from networkx.algorithms.bipartite import spectral_bipartivity as sb - -# Examples from Figure 1 -# E. Estrada and J. A. Rodríguez-Velázquez, "Spectral measures of -# bipartivity in complex networks", PhysRev E 72, 046105 (2005) - - -class TestSpectralBipartivity: - def test_star_like(self): - # star-like - - G = nx.star_graph(2) - G.add_edge(1, 2) - assert sb(G) == pytest.approx(0.843, abs=1e-3) - - G = nx.star_graph(3) - G.add_edge(1, 2) - assert sb(G) == pytest.approx(0.871, abs=1e-3) - - G = nx.star_graph(4) - G.add_edge(1, 2) - assert sb(G) == pytest.approx(0.890, abs=1e-3) - - def test_k23_like(self): - # K2,3-like - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - assert sb(G) == pytest.approx(0.769, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - assert sb(G) == pytest.approx(0.829, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - assert sb(G) == pytest.approx(0.731, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - G.add_edge(2, 4) - assert sb(G) == pytest.approx(0.692, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(0, 1) - assert sb(G) == pytest.approx(0.645, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(2, 3) - assert sb(G) == pytest.approx(0.645, abs=1e-3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(2, 3) - G.add_edge(0, 1) - assert sb(G) == pytest.approx(0.597, abs=1e-3) - - def test_single_nodes(self): - # single nodes - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - sbn = sb(G, nodes=[1, 2]) - assert sbn[1] == pytest.approx(0.85, abs=1e-2) - assert sbn[2] == pytest.approx(0.77, abs=1e-2) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - sbn = sb(G, nodes=[1, 2]) - assert sbn[1] == pytest.approx(0.73, abs=1e-2) - assert sbn[2] == pytest.approx(0.82, abs=1e-2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/boundary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/boundary.py deleted file mode 100644 index ba05d80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/boundary.py +++ /dev/null @@ -1,168 +0,0 @@ -"""Routines to find the boundary of a set of nodes. - -An edge boundary is a set of edges, each of which has exactly one -endpoint in a given set of nodes (or, in the case of directed graphs, -the set of edges whose source node is in the set). - -A node boundary of a set *S* of nodes is the set of (out-)neighbors of -nodes in *S* that are outside *S*. - -""" - -from itertools import chain - -import networkx as nx - -__all__ = ["edge_boundary", "node_boundary"] - - -@nx._dispatchable(edge_attrs={"data": "default"}, preserve_edge_attrs="data") -def edge_boundary(G, nbunch1, nbunch2=None, data=False, keys=False, default=None): - """Returns the edge boundary of `nbunch1`. - - The *edge boundary* of a set *S* with respect to a set *T* is the - set of edges (*u*, *v*) such that *u* is in *S* and *v* is in *T*. - If *T* is not specified, it is assumed to be the set of all nodes - not in *S*. - - Parameters - ---------- - G : NetworkX graph - - nbunch1 : iterable - Iterable of nodes in the graph representing the set of nodes - whose edge boundary will be returned. (This is the set *S* from - the definition above.) - - nbunch2 : iterable - Iterable of nodes representing the target (or "exterior") set of - nodes. (This is the set *T* from the definition above.) If not - specified, this is assumed to be the set of all nodes in `G` - not in `nbunch1`. - - keys : bool - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - data : bool or object - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - default : object - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - Returns - ------- - iterator - An iterator over the edges in the boundary of `nbunch1` with - respect to `nbunch2`. If `keys`, `data`, or `default` - are specified and `G` is a multigraph, then edges are returned - with keys and/or data, as in :meth:`MultiGraph.edges`. - - Examples - -------- - >>> G = nx.wheel_graph(6) - - When nbunch2=None: - - >>> list(nx.edge_boundary(G, (1, 3))) - [(1, 0), (1, 2), (1, 5), (3, 0), (3, 2), (3, 4)] - - When nbunch2 is given: - - >>> list(nx.edge_boundary(G, (1, 3), (2, 0))) - [(1, 0), (1, 2), (3, 0), (3, 2)] - - Notes - ----- - Any element of `nbunch` that is not in the graph `G` will be - ignored. - - `nbunch1` and `nbunch2` are usually meant to be disjoint, but in - the interest of speed and generality, that is not required here. - - """ - nset1 = {n for n in nbunch1 if n in G} - # Here we create an iterator over edges incident to nodes in the set - # `nset1`. The `Graph.edges()` method does not provide a guarantee - # on the orientation of the edges, so our algorithm below must - # handle the case in which exactly one orientation, either (u, v) or - # (v, u), appears in this iterable. - if G.is_multigraph(): - edges = G.edges(nset1, data=data, keys=keys, default=default) - else: - edges = G.edges(nset1, data=data, default=default) - # If `nbunch2` is not provided, then it is assumed to be the set - # complement of `nbunch1`. For the sake of efficiency, this is - # implemented by using the `not in` operator, instead of by creating - # an additional set and using the `in` operator. - if nbunch2 is None: - return (e for e in edges if (e[0] in nset1) ^ (e[1] in nset1)) - nset2 = set(nbunch2) - return ( - e - for e in edges - if (e[0] in nset1 and e[1] in nset2) or (e[1] in nset1 and e[0] in nset2) - ) - - -@nx._dispatchable -def node_boundary(G, nbunch1, nbunch2=None): - """Returns the node boundary of `nbunch1`. - - The *node boundary* of a set *S* with respect to a set *T* is the - set of nodes *v* in *T* such that for some *u* in *S*, there is an - edge joining *u* to *v*. If *T* is not specified, it is assumed to - be the set of all nodes not in *S*. - - Parameters - ---------- - G : NetworkX graph - - nbunch1 : iterable - Iterable of nodes in the graph representing the set of nodes - whose node boundary will be returned. (This is the set *S* from - the definition above.) - - nbunch2 : iterable - Iterable of nodes representing the target (or "exterior") set of - nodes. (This is the set *T* from the definition above.) If not - specified, this is assumed to be the set of all nodes in `G` - not in `nbunch1`. - - Returns - ------- - set - The node boundary of `nbunch1` with respect to `nbunch2`. - - Examples - -------- - >>> G = nx.wheel_graph(6) - - When nbunch2=None: - - >>> list(nx.node_boundary(G, (3, 4))) - [0, 2, 5] - - When nbunch2 is given: - - >>> list(nx.node_boundary(G, (3, 4), (0, 1, 5))) - [0, 5] - - Notes - ----- - Any element of `nbunch` that is not in the graph `G` will be - ignored. - - `nbunch1` and `nbunch2` are usually meant to be disjoint, but in - the interest of speed and generality, that is not required here. - - """ - nset1 = {n for n in nbunch1 if n in G} - bdy = set(chain.from_iterable(G[v] for v in nset1)) - nset1 - # If `nbunch2` is not specified, it is assumed to be the set - # complement of `nbunch1`. - if nbunch2 is not None: - bdy &= set(nbunch2) - return bdy diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bridges.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bridges.py deleted file mode 100644 index eaa6fd3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/bridges.py +++ /dev/null @@ -1,205 +0,0 @@ -"""Bridge-finding algorithms.""" - -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["bridges", "has_bridges", "local_bridges"] - - -@not_implemented_for("directed") -@nx._dispatchable -def bridges(G, root=None): - """Generate all bridges in a graph. - - A *bridge* in a graph is an edge whose removal causes the number of - connected components of the graph to increase. Equivalently, a bridge is an - edge that does not belong to any cycle. Bridges are also known as cut-edges, - isthmuses, or cut arcs. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the bridges in the - connected component containing this node will be returned. - - Yields - ------ - e : edge - An edge in the graph whose removal disconnects the graph (or - causes the number of connected components to increase). - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - NetworkXNotImplemented - If `G` is a directed graph. - - Examples - -------- - The barbell graph with parameter zero has a single bridge: - - >>> G = nx.barbell_graph(10, 0) - >>> list(nx.bridges(G)) - [(9, 10)] - - Notes - ----- - This is an implementation of the algorithm described in [1]_. An edge is a - bridge if and only if it is not contained in any chain. Chains are found - using the :func:`networkx.chain_decomposition` function. - - The algorithm described in [1]_ requires a simple graph. If the provided - graph is a multigraph, we convert it to a simple graph and verify that any - bridges discovered by the chain decomposition algorithm are not multi-edges. - - Ignoring polylogarithmic factors, the worst-case time complexity is the - same as the :func:`networkx.chain_decomposition` function, - $O(m + n)$, where $n$ is the number of nodes in the graph and $m$ is - the number of edges. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29#Bridge-Finding_with_Chain_Decompositions - """ - multigraph = G.is_multigraph() - H = nx.Graph(G) if multigraph else G - chains = nx.chain_decomposition(H, root=root) - chain_edges = set(chain.from_iterable(chains)) - if root is not None: - H = H.subgraph(nx.node_connected_component(H, root)).copy() - for u, v in H.edges(): - if (u, v) not in chain_edges and (v, u) not in chain_edges: - if multigraph and len(G[u][v]) > 1: - continue - yield u, v - - -@not_implemented_for("directed") -@nx._dispatchable -def has_bridges(G, root=None): - """Decide whether a graph has any bridges. - - A *bridge* in a graph is an edge whose removal causes the number of - connected components of the graph to increase. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the bridges in the - connected component containing this node will be considered. - - Returns - ------- - bool - Whether the graph (or the connected component containing `root`) - has any bridges. - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - NetworkXNotImplemented - If `G` is a directed graph. - - Examples - -------- - The barbell graph with parameter zero has a single bridge:: - - >>> G = nx.barbell_graph(10, 0) - >>> nx.has_bridges(G) - True - - On the other hand, the cycle graph has no bridges:: - - >>> G = nx.cycle_graph(5) - >>> nx.has_bridges(G) - False - - Notes - ----- - This implementation uses the :func:`networkx.bridges` function, so - it shares its worst-case time complexity, $O(m + n)$, ignoring - polylogarithmic factors, where $n$ is the number of nodes in the - graph and $m$ is the number of edges. - - """ - try: - next(bridges(G, root=root)) - except StopIteration: - return False - else: - return True - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def local_bridges(G, with_span=True, weight=None): - """Iterate over local bridges of `G` optionally computing the span - - A *local bridge* is an edge whose endpoints have no common neighbors. - That is, the edge is not part of a triangle in the graph. - - The *span* of a *local bridge* is the shortest path length between - the endpoints if the local bridge is removed. - - Parameters - ---------- - G : undirected graph - - with_span : bool - If True, yield a 3-tuple `(u, v, span)` - - weight : function, string or None (default: None) - If function, used to compute edge weights for the span. - If string, the edge data attribute used in calculating span. - If None, all edges have weight 1. - - Yields - ------ - e : edge - The local bridges as an edge 2-tuple of nodes `(u, v)` or - as a 3-tuple `(u, v, span)` when `with_span is True`. - - Raises - ------ - NetworkXNotImplemented - If `G` is a directed graph or multigraph. - - Examples - -------- - A cycle graph has every edge a local bridge with span N-1. - - >>> G = nx.cycle_graph(9) - >>> (0, 8, 8) in set(nx.local_bridges(G)) - True - """ - if with_span is not True: - for u, v in G.edges: - if not (set(G[u]) & set(G[v])): - yield u, v - else: - wt = nx.weighted._weight_function(G, weight) - for u, v in G.edges: - if not (set(G[u]) & set(G[v])): - enodes = {u, v} - - def hide_edge(n, nbr, d): - if n not in enodes or nbr not in enodes: - return wt(n, nbr, d) - return None - - try: - span = nx.shortest_path_length(G, u, v, weight=hide_edge) - yield u, v, span - except nx.NetworkXNoPath: - yield u, v, float("inf") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/broadcasting.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/broadcasting.py deleted file mode 100644 index 9b362a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/broadcasting.py +++ /dev/null @@ -1,155 +0,0 @@ -"""Routines to calculate the broadcast time of certain graphs. - -Broadcasting is an information dissemination problem in which a node in a graph, -called the originator, must distribute a message to all other nodes by placing -a series of calls along the edges of the graph. Once informed, other nodes aid -the originator in distributing the message. - -The broadcasting must be completed as quickly as possible subject to the -following constraints: -- Each call requires one unit of time. -- A node can only participate in one call per unit of time. -- Each call only involves two adjacent nodes: a sender and a receiver. -""" - -import networkx as nx -from networkx import NetworkXError -from networkx.utils import not_implemented_for - -__all__ = [ - "tree_broadcast_center", - "tree_broadcast_time", -] - - -def _get_max_broadcast_value(G, U, v, values): - adj = sorted(set(G.neighbors(v)) & U, key=values.get, reverse=True) - return max(values[u] + i for i, u in enumerate(adj, start=1)) - - -def _get_broadcast_centers(G, v, values, target): - adj = sorted(G.neighbors(v), key=values.get, reverse=True) - j = next(i for i, u in enumerate(adj, start=1) if values[u] + i == target) - return set([v] + adj[:j]) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def tree_broadcast_center(G): - """Return the Broadcast Center of the tree `G`. - - The broadcast center of a graph G denotes the set of nodes having - minimum broadcast time [1]_. This is a linear algorithm for determining - the broadcast center of a tree with ``N`` nodes, as a by-product it also - determines the broadcast time from the broadcast center. - - Parameters - ---------- - G : undirected graph - The graph should be an undirected tree - - Returns - ------- - BC : (int, set) tuple - minimum broadcast number of the tree, set of broadcast centers - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - References - ---------- - .. [1] Slater, P.J., Cockayne, E.J., Hedetniemi, S.T, - Information dissemination in trees. SIAM J.Comput. 10(4), 692–701 (1981) - """ - # Assert that the graph G is a tree - if not nx.is_tree(G): - NetworkXError("Input graph is not a tree") - # step 0 - if G.number_of_nodes() == 2: - return 1, set(G.nodes()) - if G.number_of_nodes() == 1: - return 0, set(G.nodes()) - - # step 1 - U = {node for node, deg in G.degree if deg == 1} - values = {n: 0 for n in U} - T = G.copy() - T.remove_nodes_from(U) - - # step 2 - W = {node for node, deg in T.degree if deg == 1} - values.update((w, G.degree[w] - 1) for w in W) - - # step 3 - while T.number_of_nodes() >= 2: - # step 4 - w = min(W, key=lambda n: values[n]) - v = next(T.neighbors(w)) - - # step 5 - U.add(w) - W.remove(w) - T.remove_node(w) - - # step 6 - if T.degree(v) == 1: - # update t(v) - values.update({v: _get_max_broadcast_value(G, U, v, values)}) - W.add(v) - - # step 7 - v = nx.utils.arbitrary_element(T) - b_T = _get_max_broadcast_value(G, U, v, values) - return b_T, _get_broadcast_centers(G, v, values, b_T) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def tree_broadcast_time(G, node=None): - """Return the Broadcast Time of the tree `G`. - - The minimum broadcast time of a node is defined as the minimum amount - of time required to complete broadcasting starting from the - originator. The broadcast time of a graph is the maximum over - all nodes of the minimum broadcast time from that node [1]_. - This function returns the minimum broadcast time of `node`. - If `node` is None the broadcast time for the graph is returned. - - Parameters - ---------- - G : undirected graph - The graph should be an undirected tree - node: int, optional - index of starting node. If `None`, the algorithm returns the broadcast - time of the tree. - - Returns - ------- - BT : int - Broadcast Time of a node in a tree - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - References - ---------- - .. [1] Harutyunyan, H. A. and Li, Z. - "A Simple Construction of Broadcast Graphs." - In Computing and Combinatorics. COCOON 2019 - (Ed. D. Z. Du and C. Tian.) Springer, pp. 240-253, 2019. - """ - b_T, b_C = tree_broadcast_center(G) - if node is not None: - return b_T + min(nx.shortest_path_length(G, node, u) for u in b_C) - dist_from_center = dict.fromkeys(G, len(G)) - for u in b_C: - for v, dist in nx.shortest_path_length(G, u).items(): - if dist < dist_from_center[v]: - dist_from_center[v] = dist - return b_T + max(dist_from_center.values()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/__init__.py deleted file mode 100644 index c91a904..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from .betweenness import * -from .betweenness_subset import * -from .closeness import * -from .current_flow_betweenness import * -from .current_flow_betweenness_subset import * -from .current_flow_closeness import * -from .degree_alg import * -from .dispersion import * -from .eigenvector import * -from .group import * -from .harmonic import * -from .katz import * -from .load import * -from .percolation import * -from .reaching import * -from .second_order import * -from .subgraph_alg import * -from .trophic import * -from .voterank_alg import * -from .laplacian import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness.py deleted file mode 100644 index 42e0977..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness.py +++ /dev/null @@ -1,436 +0,0 @@ -"""Betweenness centrality measures.""" - -from collections import deque -from heapq import heappop, heappush -from itertools import count - -import networkx as nx -from networkx.algorithms.shortest_paths.weighted import _weight_function -from networkx.utils import py_random_state -from networkx.utils.decorators import not_implemented_for - -__all__ = ["betweenness_centrality", "edge_betweenness_centrality"] - - -@py_random_state(5) -@nx._dispatchable(edge_attrs="weight") -def betweenness_centrality( - G, k=None, normalized=True, weight=None, endpoints=False, seed=None -): - r"""Compute the shortest-path betweenness centrality for nodes. - - Betweenness centrality of a node $v$ is the sum of the - fraction of all-pairs shortest paths that pass through $v$ - - .. math:: - - c_B(v) =\sum_{s,t \in V} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|v)$ is the number of - those paths passing through some node $v$ other than $s, t$. - If $s = t$, $\sigma(s, t) = 1$, and if $v \in {s, t}$, - $\sigma(s, t|v) = 0$ [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - k : int, optional (default=None) - If k is not None use k node samples to estimate betweenness. - The value of k <= n where n is the number of nodes in the graph. - Higher values give better approximation. - - normalized : bool, optional - If True the betweenness values are normalized by `2/((n-1)(n-2))` - for graphs, and `1/((n-1)(n-2))` for directed graphs where `n` - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - Weights are used to calculate weighted shortest paths, so they are - interpreted as distances. - - endpoints : bool, optional - If True include the endpoints in the shortest path counts. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Note that this is only used if k is not None. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - edge_betweenness_centrality - load_centrality - - Notes - ----- - The algorithm is from Ulrik Brandes [1]_. - See [4]_ for the original first published version and [2]_ for details on - algorithms for variations and related metrics. - - For approximate betweenness calculations set k=#samples to use - k nodes ("pivots") to estimate the betweenness values. For an estimate - of the number of pivots needed see [3]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - are easy to count. Undirected paths are tricky: should a path - from "u" to "v" count as 1 undirected path or as 2 directed paths? - - For betweenness_centrality we report the number of undirected - paths when G is undirected. - - For betweenness_centrality_subset the reporting is different. - If the source and target subsets are the same, then we want - to count undirected paths. But if the source and target subsets - differ -- for example, if sources is {0} and targets is {1}, - then we are only counting the paths in one direction. They are - undirected paths but we are counting them in a directed way. - To count them as undirected paths, each should count as half a path. - - This algorithm is not guaranteed to be correct if edge weights - are floating point numbers. As a workaround you can use integer - numbers by multiplying the relevant edge attributes by a convenient - constant factor (eg 100) and converting to integers. - - References - ---------- - .. [1] Ulrik Brandes: - A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - https://doi.org/10.1080/0022250X.2001.9990249 - .. [2] Ulrik Brandes: - On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - https://doi.org/10.1016/j.socnet.2007.11.001 - .. [3] Ulrik Brandes and Christian Pich: - Centrality Estimation in Large Networks. - International Journal of Bifurcation and Chaos 17(7):2303-2318, 2007. - https://dx.doi.org/10.1142/S0218127407018403 - .. [4] Linton C. Freeman: - A set of measures of centrality based on betweenness. - Sociometry 40: 35–41, 1977 - https://doi.org/10.2307/3033543 - """ - betweenness = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - if k is None: - nodes = G - else: - nodes = seed.sample(list(G.nodes()), k) - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma, _ = _single_source_shortest_path_basic(G, s) - else: # use Dijkstra's algorithm - S, P, sigma, _ = _single_source_dijkstra_path_basic(G, s, weight) - # accumulation - if endpoints: - betweenness, _ = _accumulate_endpoints(betweenness, S, P, sigma, s) - else: - betweenness, _ = _accumulate_basic(betweenness, S, P, sigma, s) - # rescaling - betweenness = _rescale( - betweenness, - len(G), - normalized=normalized, - directed=G.is_directed(), - k=k, - endpoints=endpoints, - ) - return betweenness - - -@py_random_state(4) -@nx._dispatchable(edge_attrs="weight") -def edge_betweenness_centrality(G, k=None, normalized=True, weight=None, seed=None): - r"""Compute betweenness centrality for edges. - - Betweenness centrality of an edge $e$ is the sum of the - fraction of all-pairs shortest paths that pass through $e$ - - .. math:: - - c_B(e) =\sum_{s,t \in V} \frac{\sigma(s, t|e)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|e)$ is the number of - those paths passing through edge $e$ [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - k : int, optional (default=None) - If k is not None use k node samples to estimate betweenness. - The value of k <= n where n is the number of nodes in the graph. - Higher values give better approximation. - - normalized : bool, optional - If True the betweenness values are normalized by $2/(n(n-1))$ - for graphs, and $1/(n(n-1))$ for directed graphs where $n$ - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - Weights are used to calculate weighted shortest paths, so they are - interpreted as distances. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Note that this is only used if k is not None. - - Returns - ------- - edges : dictionary - Dictionary of edges with betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_load - - Notes - ----- - The algorithm is from Ulrik Brandes [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - References - ---------- - .. [1] A Faster Algorithm for Betweenness Centrality. Ulrik Brandes, - Journal of Mathematical Sociology 25(2):163-177, 2001. - https://doi.org/10.1080/0022250X.2001.9990249 - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - https://doi.org/10.1016/j.socnet.2007.11.001 - """ - betweenness = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - # b[e]=0 for e in G.edges() - betweenness.update(dict.fromkeys(G.edges(), 0.0)) - if k is None: - nodes = G - else: - nodes = seed.sample(list(G.nodes()), k) - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma, _ = _single_source_shortest_path_basic(G, s) - else: # use Dijkstra's algorithm - S, P, sigma, _ = _single_source_dijkstra_path_basic(G, s, weight) - # accumulation - betweenness = _accumulate_edges(betweenness, S, P, sigma, s) - # rescaling - for n in G: # remove nodes to only return edges - del betweenness[n] - betweenness = _rescale_e( - betweenness, len(G), normalized=normalized, directed=G.is_directed() - ) - if G.is_multigraph(): - betweenness = _add_edge_keys(G, betweenness, weight=weight) - return betweenness - - -# helpers for betweenness centrality - - -def _single_source_shortest_path_basic(G, s): - S = [] - P = {} - for v in G: - P[v] = [] - sigma = dict.fromkeys(G, 0.0) # sigma[v]=0 for v in G - D = {} - sigma[s] = 1.0 - D[s] = 0 - Q = deque([s]) - while Q: # use BFS to find shortest paths - v = Q.popleft() - S.append(v) - Dv = D[v] - sigmav = sigma[v] - for w in G[v]: - if w not in D: - Q.append(w) - D[w] = Dv + 1 - if D[w] == Dv + 1: # this is a shortest path, count paths - sigma[w] += sigmav - P[w].append(v) # predecessors - return S, P, sigma, D - - -def _single_source_dijkstra_path_basic(G, s, weight): - weight = _weight_function(G, weight) - # modified from Eppstein - S = [] - P = {} - for v in G: - P[v] = [] - sigma = dict.fromkeys(G, 0.0) # sigma[v]=0 for v in G - D = {} - sigma[s] = 1.0 - push = heappush - pop = heappop - seen = {s: 0} - c = count() - Q = [] # use Q as heap with (distance,node id) tuples - push(Q, (0, next(c), s, s)) - while Q: - (dist, _, pred, v) = pop(Q) - if v in D: - continue # already searched this node. - sigma[v] += sigma[pred] # count paths - S.append(v) - D[v] = dist - for w, edgedata in G[v].items(): - vw_dist = dist + weight(v, w, edgedata) - if w not in D and (w not in seen or vw_dist < seen[w]): - seen[w] = vw_dist - push(Q, (vw_dist, next(c), v, w)) - sigma[w] = 0.0 - P[w] = [v] - elif vw_dist == seen[w]: # handle equal paths - sigma[w] += sigma[v] - P[w].append(v) - return S, P, sigma, D - - -def _accumulate_basic(betweenness, S, P, sigma, s): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] - return betweenness, delta - - -def _accumulate_endpoints(betweenness, S, P, sigma, s): - betweenness[s] += len(S) - 1 - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] + 1 - return betweenness, delta - - -def _accumulate_edges(betweenness, S, P, sigma, s): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - c = sigma[v] * coeff - if (v, w) not in betweenness: - betweenness[(w, v)] += c - else: - betweenness[(v, w)] += c - delta[v] += c - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _rescale(betweenness, n, normalized, directed=False, k=None, endpoints=False): - if normalized: - if endpoints: - if n < 2: - scale = None # no normalization - else: - # Scale factor should include endpoint nodes - scale = 1 / (n * (n - 1)) - elif n <= 2: - scale = None # no normalization b=0 for all nodes - else: - scale = 1 / ((n - 1) * (n - 2)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - if k is not None: - scale = scale * n / k - for v in betweenness: - betweenness[v] *= scale - return betweenness - - -def _rescale_e(betweenness, n, normalized, directed=False, k=None): - if normalized: - if n <= 1: - scale = None # no normalization b=0 for all nodes - else: - scale = 1 / (n * (n - 1)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - if k is not None: - scale = scale * n / k - for v in betweenness: - betweenness[v] *= scale - return betweenness - - -@not_implemented_for("graph") -def _add_edge_keys(G, betweenness, weight=None): - r"""Adds the corrected betweenness centrality (BC) values for multigraphs. - - Parameters - ---------- - G : NetworkX graph. - - betweenness : dictionary - Dictionary mapping adjacent node tuples to betweenness centrality values. - - weight : string or function - See `_weight_function` for details. Defaults to `None`. - - Returns - ------- - edges : dictionary - The parameter `betweenness` including edges with keys and their - betweenness centrality values. - - The BC value is divided among edges of equal weight. - """ - _weight = _weight_function(G, weight) - - edge_bc = dict.fromkeys(G.edges, 0.0) - for u, v in betweenness: - d = G[u][v] - wt = _weight(u, v, d) - keys = [k for k in d if _weight(u, v, {k: d[k]}) == wt] - bc = betweenness[(u, v)] / len(keys) - for k in keys: - edge_bc[(u, v, k)] = bc - - return edge_bc diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness_subset.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness_subset.py deleted file mode 100644 index b9e9936..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/betweenness_subset.py +++ /dev/null @@ -1,275 +0,0 @@ -"""Betweenness centrality measures for subsets of nodes.""" - -import networkx as nx -from networkx.algorithms.centrality.betweenness import ( - _add_edge_keys, -) -from networkx.algorithms.centrality.betweenness import ( - _single_source_dijkstra_path_basic as dijkstra, -) -from networkx.algorithms.centrality.betweenness import ( - _single_source_shortest_path_basic as shortest_path, -) - -__all__ = [ - "betweenness_centrality_subset", - "edge_betweenness_centrality_subset", -] - - -@nx._dispatchable(edge_attrs="weight") -def betweenness_centrality_subset(G, sources, targets, normalized=False, weight=None): - r"""Compute betweenness centrality for a subset of nodes. - - .. math:: - - c_B(v) =\sum_{s\in S, t \in T} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $S$ is the set of sources, $T$ is the set of targets, - $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, - and $\sigma(s, t|v)$ is the number of those paths - passing through some node $v$ other than $s, t$. - If $s = t$, $\sigma(s, t) = 1$, - and if $v \in {s, t}$, $\sigma(s, t|v) = 0$ [2]_. - - - Parameters - ---------- - G : graph - A NetworkX graph. - - sources: list of nodes - Nodes to use as sources for shortest paths in betweenness - - targets: list of nodes - Nodes to use as targets for shortest paths in betweenness - - normalized : bool, optional - If True the betweenness values are normalized by $2/((n-1)(n-2))$ - for graphs, and $1/((n-1)(n-2))$ for directed graphs where $n$ - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - Weights are used to calculate weighted shortest paths, so they are - interpreted as distances. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - edge_betweenness_centrality - load_centrality - - Notes - ----- - The basic algorithm is from [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The normalization might seem a little strange but it is - designed to make betweenness_centrality(G) be the same as - betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - are easy to count. Undirected paths are tricky: should a path - from "u" to "v" count as 1 undirected path or as 2 directed paths? - - For betweenness_centrality we report the number of undirected - paths when G is undirected. - - For betweenness_centrality_subset the reporting is different. - If the source and target subsets are the same, then we want - to count undirected paths. But if the source and target subsets - differ -- for example, if sources is {0} and targets is {1}, - then we are only counting the paths in one direction. They are - undirected paths but we are counting them in a directed way. - To count them as undirected paths, each should count as half a path. - - References - ---------- - .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - https://doi.org/10.1080/0022250X.2001.9990249 - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - https://doi.org/10.1016/j.socnet.2007.11.001 - """ - b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - for s in sources: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma, _ = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma, _ = dijkstra(G, s, weight) - b = _accumulate_subset(b, S, P, sigma, s, targets) - b = _rescale(b, len(G), normalized=normalized, directed=G.is_directed()) - return b - - -@nx._dispatchable(edge_attrs="weight") -def edge_betweenness_centrality_subset( - G, sources, targets, normalized=False, weight=None -): - r"""Compute betweenness centrality for edges for a subset of nodes. - - .. math:: - - c_B(v) =\sum_{s\in S,t \in T} \frac{\sigma(s, t|e)}{\sigma(s, t)} - - where $S$ is the set of sources, $T$ is the set of targets, - $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, - and $\sigma(s, t|e)$ is the number of those paths - passing through edge $e$ [2]_. - - Parameters - ---------- - G : graph - A networkx graph. - - sources: list of nodes - Nodes to use as sources for shortest paths in betweenness - - targets: list of nodes - Nodes to use as targets for shortest paths in betweenness - - normalized : bool, optional - If True the betweenness values are normalized by `2/(n(n-1))` - for graphs, and `1/(n(n-1))` for directed graphs where `n` - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - Weights are used to calculate weighted shortest paths, so they are - interpreted as distances. - - Returns - ------- - edges : dictionary - Dictionary of edges with Betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_load - - Notes - ----- - The basic algorithm is from [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The normalization might seem a little strange but it is the same - as in edge_betweenness_centrality() and is designed to make - edge_betweenness_centrality(G) be the same as - edge_betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). - - References - ---------- - .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - https://doi.org/10.1080/0022250X.2001.9990249 - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - https://doi.org/10.1016/j.socnet.2007.11.001 - """ - b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - b.update(dict.fromkeys(G.edges(), 0.0)) # b[e] for e in G.edges() - for s in sources: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma, _ = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma, _ = dijkstra(G, s, weight) - b = _accumulate_edges_subset(b, S, P, sigma, s, targets) - for n in G: # remove nodes to only return edges - del b[n] - b = _rescale_e(b, len(G), normalized=normalized, directed=G.is_directed()) - if G.is_multigraph(): - b = _add_edge_keys(G, b, weight=weight) - return b - - -def _accumulate_subset(betweenness, S, P, sigma, s, targets): - delta = dict.fromkeys(S, 0.0) - target_set = set(targets) - {s} - while S: - w = S.pop() - if w in target_set: - coeff = (delta[w] + 1.0) / sigma[w] - else: - coeff = delta[w] / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _accumulate_edges_subset(betweenness, S, P, sigma, s, targets): - """edge_betweenness_centrality_subset helper.""" - delta = dict.fromkeys(S, 0) - target_set = set(targets) - while S: - w = S.pop() - for v in P[w]: - if w in target_set: - c = (sigma[v] / sigma[w]) * (1.0 + delta[w]) - else: - c = delta[w] / len(P[w]) - if (v, w) not in betweenness: - betweenness[(w, v)] += c - else: - betweenness[(v, w)] += c - delta[v] += c - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _rescale(betweenness, n, normalized, directed=False): - """betweenness_centrality_subset helper.""" - if normalized: - if n <= 2: - scale = None # no normalization b=0 for all nodes - else: - scale = 1.0 / ((n - 1) * (n - 2)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - for v in betweenness: - betweenness[v] *= scale - return betweenness - - -def _rescale_e(betweenness, n, normalized, directed=False): - """edge_betweenness_centrality_subset helper.""" - if normalized: - if n <= 1: - scale = None # no normalization b=0 for all nodes - else: - scale = 1.0 / (n * (n - 1)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - for v in betweenness: - betweenness[v] *= scale - return betweenness diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/closeness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/closeness.py deleted file mode 100644 index 1cc2f95..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/closeness.py +++ /dev/null @@ -1,282 +0,0 @@ -""" -Closeness centrality measures. -""" - -import functools - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils.decorators import not_implemented_for - -__all__ = ["closeness_centrality", "incremental_closeness_centrality"] - - -@nx._dispatchable(edge_attrs="distance") -def closeness_centrality(G, u=None, distance=None, wf_improved=True): - r"""Compute closeness centrality for nodes. - - Closeness centrality [1]_ of a node `u` is the reciprocal of the - average shortest path distance to `u` over all `n-1` reachable nodes. - - .. math:: - - C(u) = \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - where `d(v, u)` is the shortest-path distance between `v` and `u`, - and `n-1` is the number of nodes reachable from `u`. Notice that the - closeness distance function computes the incoming distance to `u` - for directed graphs. To use outward distance, act on `G.reverse()`. - - Notice that higher values of closeness indicate higher centrality. - - Wasserman and Faust propose an improved formula for graphs with - more than one connected component. The result is "a ratio of the - fraction of actors in the group who are reachable, to the average - distance" from the reachable actors [2]_. You might think this - scale factor is inverted but it is not. As is, nodes from small - components receive a smaller closeness value. Letting `N` denote - the number of nodes in the graph, - - .. math:: - - C_{WF}(u) = \frac{n-1}{N-1} \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - Parameters - ---------- - G : graph - A NetworkX graph - - u : node, optional - Return only the value for node u - - distance : edge attribute key, optional (default=None) - Use the specified edge attribute as the edge distance in shortest - path calculations. If `None` (the default) all edges have a distance of 1. - Absent edge attributes are assigned a distance of 1. Note that no check - is performed to ensure that edges have the provided attribute. - - wf_improved : bool, optional (default=True) - If True, scale by the fraction of nodes reachable. This gives the - Wasserman and Faust improved formula. For single component graphs - it is the same as the original formula. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with closeness centrality as the value. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.closeness_centrality(G) - {0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75} - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, incremental_closeness_centrality - - Notes - ----- - The closeness centrality is normalized to `(n-1)/(|G|-1)` where - `n` is the number of nodes in the connected part of graph - containing the node. If the graph is not completely connected, - this algorithm computes the closeness centrality for each - connected part separately scaled by that parts size. - - If the 'distance' keyword is set to an edge attribute key then the - shortest-path length will be computed using Dijkstra's algorithm with - that edge attribute as the edge weight. - - The closeness centrality uses *inward* distance to a node, not outward. - If you want to use outword distances apply the function to `G.reverse()` - - In NetworkX 2.2 and earlier a bug caused Dijkstra's algorithm to use the - outward distance rather than the inward distance. If you use a 'distance' - keyword and a DiGraph, your results will change between v2.2 and v2.3. - - References - ---------- - .. [1] Linton C. Freeman: Centrality in networks: I. - Conceptual clarification. Social Networks 1:215-239, 1979. - https://doi.org/10.1016/0378-8733(78)90021-7 - .. [2] pg. 201 of Wasserman, S. and Faust, K., - Social Network Analysis: Methods and Applications, 1994, - Cambridge University Press. - """ - if G.is_directed(): - G = G.reverse() # create a reversed graph view - - if distance is not None: - # use Dijkstra's algorithm with specified attribute as edge weight - path_length = functools.partial( - nx.single_source_dijkstra_path_length, weight=distance - ) - else: - path_length = nx.single_source_shortest_path_length - - if u is None: - nodes = G.nodes - else: - nodes = [u] - closeness_dict = {} - for n in nodes: - sp = path_length(G, n) - totsp = sum(sp.values()) - len_G = len(G) - _closeness_centrality = 0.0 - if totsp > 0.0 and len_G > 1: - _closeness_centrality = (len(sp) - 1.0) / totsp - # normalize to number of nodes-1 in connected part - if wf_improved: - s = (len(sp) - 1.0) / (len_G - 1) - _closeness_centrality *= s - closeness_dict[n] = _closeness_centrality - if u is not None: - return closeness_dict[u] - return closeness_dict - - -@not_implemented_for("directed") -@nx._dispatchable(mutates_input=True) -def incremental_closeness_centrality( - G, edge, prev_cc=None, insertion=True, wf_improved=True -): - r"""Incremental closeness centrality for nodes. - - Compute closeness centrality for nodes using level-based work filtering - as described in Incremental Algorithms for Closeness Centrality by Sariyuce et al. - - Level-based work filtering detects unnecessary updates to the closeness - centrality and filters them out. - - --- - From "Incremental Algorithms for Closeness Centrality": - - Theorem 1: Let :math:`G = (V, E)` be a graph and u and v be two vertices in V - such that there is no edge (u, v) in E. Let :math:`G' = (V, E \cup uv)` - Then :math:`cc[s] = cc'[s]` if and only if :math:`\left|dG(s, u) - dG(s, v)\right| \leq 1`. - - Where :math:`dG(u, v)` denotes the length of the shortest path between - two vertices u, v in a graph G, cc[s] is the closeness centrality for a - vertex s in V, and cc'[s] is the closeness centrality for a - vertex s in V, with the (u, v) edge added. - --- - - We use Theorem 1 to filter out updates when adding or removing an edge. - When adding an edge (u, v), we compute the shortest path lengths from all - other nodes to u and to v before the node is added. When removing an edge, - we compute the shortest path lengths after the edge is removed. Then we - apply Theorem 1 to use previously computed closeness centrality for nodes - where :math:`\left|dG(s, u) - dG(s, v)\right| \leq 1`. This works only for - undirected, unweighted graphs; the distance argument is not supported. - - Closeness centrality [1]_ of a node `u` is the reciprocal of the - sum of the shortest path distances from `u` to all `n-1` other nodes. - Since the sum of distances depends on the number of nodes in the - graph, closeness is normalized by the sum of minimum possible - distances `n-1`. - - .. math:: - - C(u) = \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - where `d(v, u)` is the shortest-path distance between `v` and `u`, - and `n` is the number of nodes in the graph. - - Notice that higher values of closeness indicate higher centrality. - - Parameters - ---------- - G : graph - A NetworkX graph - - edge : tuple - The modified edge (u, v) in the graph. - - prev_cc : dictionary - The previous closeness centrality for all nodes in the graph. - - insertion : bool, optional - If True (default) the edge was inserted, otherwise it was deleted from the graph. - - wf_improved : bool, optional (default=True) - If True, scale by the fraction of nodes reachable. This gives the - Wasserman and Faust improved formula. For single component graphs - it is the same as the original formula. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with closeness centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, closeness_centrality - - Notes - ----- - The closeness centrality is normalized to `(n-1)/(|G|-1)` where - `n` is the number of nodes in the connected part of graph - containing the node. If the graph is not completely connected, - this algorithm computes the closeness centrality for each - connected part separately. - - References - ---------- - .. [1] Freeman, L.C., 1979. Centrality in networks: I. - Conceptual clarification. Social Networks 1, 215--239. - https://doi.org/10.1016/0378-8733(78)90021-7 - .. [2] Sariyuce, A.E. ; Kaya, K. ; Saule, E. ; Catalyiirek, U.V. Incremental - Algorithms for Closeness Centrality. 2013 IEEE International Conference on Big Data - http://sariyuce.com/papers/bigdata13.pdf - """ - if prev_cc is not None and set(prev_cc.keys()) != set(G.nodes()): - raise NetworkXError("prev_cc and G do not have the same nodes") - - # Unpack edge - (u, v) = edge - path_length = nx.single_source_shortest_path_length - - if insertion: - # For edge insertion, we want shortest paths before the edge is inserted - du = path_length(G, u) - dv = path_length(G, v) - - G.add_edge(u, v) - else: - G.remove_edge(u, v) - - # For edge removal, we want shortest paths after the edge is removed - du = path_length(G, u) - dv = path_length(G, v) - - if prev_cc is None: - return nx.closeness_centrality(G) - - nodes = G.nodes() - closeness_dict = {} - for n in nodes: - if n in du and n in dv and abs(du[n] - dv[n]) <= 1: - closeness_dict[n] = prev_cc[n] - else: - sp = path_length(G, n) - totsp = sum(sp.values()) - len_G = len(G) - _closeness_centrality = 0.0 - if totsp > 0.0 and len_G > 1: - _closeness_centrality = (len(sp) - 1.0) / totsp - # normalize to number of nodes-1 in connected part - if wf_improved: - s = (len(sp) - 1.0) / (len_G - 1) - _closeness_centrality *= s - closeness_dict[n] = _closeness_centrality - - # Leave the graph as we found it - if insertion: - G.remove_edge(u, v) - else: - G.add_edge(u, v) - - return closeness_dict diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness.py deleted file mode 100644 index bfde279..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness.py +++ /dev/null @@ -1,342 +0,0 @@ -"""Current-flow betweenness centrality measures.""" - -import networkx as nx -from networkx.algorithms.centrality.flow_matrix import ( - CGInverseLaplacian, - FullInverseLaplacian, - SuperLUInverseLaplacian, - flow_matrix_row, -) -from networkx.utils import ( - not_implemented_for, - py_random_state, - reverse_cuthill_mckee_ordering, -) - -__all__ = [ - "current_flow_betweenness_centrality", - "approximate_current_flow_betweenness_centrality", - "edge_current_flow_betweenness_centrality", -] - - -@not_implemented_for("directed") -@py_random_state(7) -@nx._dispatchable(edge_attrs="weight") -def approximate_current_flow_betweenness_centrality( - G, - normalized=True, - weight=None, - dtype=float, - solver="full", - epsilon=0.5, - kmax=10000, - seed=None, -): - r"""Compute the approximate current-flow betweenness centrality for nodes. - - Approximates the current-flow betweenness centrality within absolute - error of epsilon with high probability [1]_. - - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - The weight reflects the capacity or the strength of the - edge. - - dtype : data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='full') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - epsilon: float - Absolute error tolerance. - - kmax: int - Maximum number of sample node pairs to use for approximation. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - current_flow_betweenness_centrality - - Notes - ----- - The running time is $O((1/\epsilon^2)m{\sqrt k} \log n)$ - and the space required is $O(m)$ for $n$ nodes and $m$ edges. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Ulrik Brandes and Daniel Fleischer: - Centrality Measures Based on Current Flow. - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - """ - import numpy as np - - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - solvername = { - "full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian, - } - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(n)))) - L = nx.laplacian_matrix(H, nodelist=range(n), weight=weight).asformat("csc") - L = L.astype(dtype) - C = solvername[solver](L, dtype=dtype) # initialize solver - betweenness = dict.fromkeys(H, 0.0) - nb = (n - 1.0) * (n - 2.0) # normalization factor - cstar = n * (n - 1) / nb - l = 1 # parameter in approximation, adjustable - k = l * int(np.ceil((cstar / epsilon) ** 2 * np.log(n))) - if k > kmax: - msg = f"Number random pairs k>kmax ({k}>{kmax}) " - raise nx.NetworkXError(msg, "Increase kmax or epsilon") - cstar2k = cstar / (2 * k) - for _ in range(k): - s, t = pair = seed.sample(range(n), 2) - b = np.zeros(n, dtype=dtype) - b[s] = 1 - b[t] = -1 - p = C.solve(b) - for v in H: - if v in pair: - continue - for nbr in H[v]: - w = H[v][nbr].get(weight, 1.0) - betweenness[v] += float(w * np.abs(p[v] - p[nbr]) * cstar2k) - if normalized: - factor = 1.0 - else: - factor = nb / 2.0 - # remap to original node names and "unnormalize" if required - return {ordering[k]: v * factor for k, v in betweenness.items()} - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def current_flow_betweenness_centrality( - G, normalized=True, weight=None, dtype=float, solver="full" -): - r"""Compute current-flow betweenness centrality for nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - The weight reflects the capacity or the strength of the - edge. - - dtype : data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='full') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - approximate_current_flow_betweenness_centrality - betweenness_centrality - edge_betweenness_centrality - edge_current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - N = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(N)))) - betweenness = dict.fromkeys(H, 0.0) # b[n]=0 for n in H - for row, (s, t) in flow_matrix_row(H, weight=weight, dtype=dtype, solver=solver): - pos = dict(zip(row.argsort()[::-1], range(N))) - for i in range(N): - betweenness[s] += (i - pos[i]) * row.item(i) - betweenness[t] += (N - i - 1 - pos[i]) * row.item(i) - if normalized: - nb = (N - 1.0) * (N - 2.0) # normalization factor - else: - nb = 2.0 - return {ordering[n]: (b - n) * 2.0 / nb for n, b in betweenness.items()} - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def edge_current_flow_betweenness_centrality( - G, normalized=True, weight=None, dtype=float, solver="full" -): - r"""Compute current-flow betweenness centrality for edges. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - The weight reflects the capacity or the strength of the - edge. - - dtype : data type (default=float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='full') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of edge tuples with betweenness centrality as the value. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraphs. - If the input graph is an instance of DiGraph class, NetworkXError - is raised. - - See Also - -------- - betweenness_centrality - edge_betweenness_centrality - current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - N = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(N)))) - edges = (tuple(sorted((u, v))) for u, v in H.edges()) - betweenness = dict.fromkeys(edges, 0.0) - if normalized: - nb = (N - 1.0) * (N - 2.0) # normalization factor - else: - nb = 2.0 - for row, (e) in flow_matrix_row(H, weight=weight, dtype=dtype, solver=solver): - pos = dict(zip(row.argsort()[::-1], range(1, N + 1))) - for i in range(N): - betweenness[e] += (i + 1 - pos[i]) * row.item(i) - betweenness[e] += (N - i - pos[i]) * row.item(i) - betweenness[e] /= nb - return {(ordering[s], ordering[t]): b for (s, t), b in betweenness.items()} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness_subset.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness_subset.py deleted file mode 100644 index 911718c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_betweenness_subset.py +++ /dev/null @@ -1,227 +0,0 @@ -"""Current-flow betweenness centrality measures for subsets of nodes.""" - -import networkx as nx -from networkx.algorithms.centrality.flow_matrix import flow_matrix_row -from networkx.utils import not_implemented_for, reverse_cuthill_mckee_ordering - -__all__ = [ - "current_flow_betweenness_centrality_subset", - "edge_current_flow_betweenness_centrality_subset", -] - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def current_flow_betweenness_centrality_subset( - G, sources, targets, normalized=True, weight=None, dtype=float, solver="lu" -): - r"""Compute current-flow betweenness centrality for subsets of nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - sources: list of nodes - Nodes to use as sources for current - - targets: list of nodes - Nodes to use as sinks for current - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - The weight reflects the capacity or the strength of the - edge. - - dtype: data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - approximate_current_flow_betweenness_centrality - betweenness_centrality - edge_betweenness_centrality - edge_current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - import numpy as np - - from networkx.utils import reverse_cuthill_mckee_ordering - - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - N = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - mapping = dict(zip(ordering, range(N))) - H = nx.relabel_nodes(G, mapping) - betweenness = dict.fromkeys(H, 0.0) # b[n]=0 for n in H - for row, (s, t) in flow_matrix_row(H, weight=weight, dtype=dtype, solver=solver): - for ss in sources: - i = mapping[ss] - for tt in targets: - j = mapping[tt] - betweenness[s] += 0.5 * abs(row.item(i) - row.item(j)) - betweenness[t] += 0.5 * abs(row.item(i) - row.item(j)) - if normalized: - nb = (N - 1.0) * (N - 2.0) # normalization factor - else: - nb = 2.0 - for node in H: - betweenness[node] = betweenness[node] / nb + 1.0 / (2 - N) - return {ordering[node]: value for node, value in betweenness.items()} - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def edge_current_flow_betweenness_centrality_subset( - G, sources, targets, normalized=True, weight=None, dtype=float, solver="lu" -): - r"""Compute current-flow betweenness centrality for edges using subsets - of nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - sources: list of nodes - Nodes to use as sources for current - - targets: list of nodes - Nodes to use as sinks for current - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - The weight reflects the capacity or the strength of the - edge. - - dtype: data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dict - Dictionary of edge tuples with betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_betweenness_centrality - current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - import numpy as np - - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - N = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - mapping = dict(zip(ordering, range(N))) - H = nx.relabel_nodes(G, mapping) - edges = (tuple(sorted((u, v))) for u, v in H.edges()) - betweenness = dict.fromkeys(edges, 0.0) - if normalized: - nb = (N - 1.0) * (N - 2.0) # normalization factor - else: - nb = 2.0 - for row, (e) in flow_matrix_row(H, weight=weight, dtype=dtype, solver=solver): - for ss in sources: - i = mapping[ss] - for tt in targets: - j = mapping[tt] - betweenness[e] += 0.5 * abs(row.item(i) - row.item(j)) - betweenness[e] /= nb - return {(ordering[s], ordering[t]): value for (s, t), value in betweenness.items()} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_closeness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_closeness.py deleted file mode 100644 index 67f8639..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/current_flow_closeness.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Current-flow closeness centrality measures.""" - -import networkx as nx -from networkx.algorithms.centrality.flow_matrix import ( - CGInverseLaplacian, - FullInverseLaplacian, - SuperLUInverseLaplacian, -) -from networkx.utils import not_implemented_for, reverse_cuthill_mckee_ordering - -__all__ = ["current_flow_closeness_centrality", "information_centrality"] - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def current_flow_closeness_centrality(G, weight=None, dtype=float, solver="lu"): - """Compute current-flow closeness centrality for nodes. - - Current-flow closeness centrality is variant of closeness - centrality based on effective resistance between nodes in - a network. This metric is also known as information centrality. - - Parameters - ---------- - G : graph - A NetworkX graph. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - The weight reflects the capacity or the strength of the - edge. - - dtype: data type (default=float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with current flow closeness centrality as the value. - - See Also - -------- - closeness_centrality - - Notes - ----- - The algorithm is from Brandes [1]_. - - See also [2]_ for the original definition of information centrality. - - References - ---------- - .. [1] Ulrik Brandes and Daniel Fleischer, - Centrality Measures Based on Current Flow. - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31856-9_44 - - .. [2] Karen Stephenson and Marvin Zelen: - Rethinking centrality: Methods and examples. - Social Networks 11(1):1-37, 1989. - https://doi.org/10.1016/0378-8733(89)90016-6 - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - solvername = { - "full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian, - } - N = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(N)))) - betweenness = dict.fromkeys(H, 0.0) # b[n]=0 for n in H - N = H.number_of_nodes() - L = nx.laplacian_matrix(H, nodelist=range(N), weight=weight).asformat("csc") - L = L.astype(dtype) - C2 = solvername[solver](L, width=1, dtype=dtype) # initialize solver - for v in H: - col = C2.get_row(v) - for w in H: - betweenness[v] += col.item(v) - 2 * col.item(w) - betweenness[w] += col.item(v) - return {ordering[node]: 1 / value for node, value in betweenness.items()} - - -information_centrality = current_flow_closeness_centrality diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/degree_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/degree_alg.py deleted file mode 100644 index b3c1e32..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/degree_alg.py +++ /dev/null @@ -1,150 +0,0 @@ -"""Degree centrality measures.""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ["degree_centrality", "in_degree_centrality", "out_degree_centrality"] - - -@nx._dispatchable -def degree_centrality(G): - """Compute the degree centrality for nodes. - - The degree centrality for a node v is the fraction of nodes it - is connected to. - - Parameters - ---------- - G : graph - A networkx graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with degree centrality as the value. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.degree_centrality(G) - {0: 1.0, 1: 1.0, 2: 0.6666666666666666, 3: 0.6666666666666666} - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.degree()} - return centrality - - -@not_implemented_for("undirected") -@nx._dispatchable -def in_degree_centrality(G): - """Compute the in-degree centrality for nodes. - - The in-degree centrality for a node v is the fraction of nodes its - incoming edges are connected to. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with in-degree centrality as values. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.in_degree_centrality(G) - {0: 0.0, 1: 0.3333333333333333, 2: 0.6666666666666666, 3: 0.6666666666666666} - - See Also - -------- - degree_centrality, out_degree_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.in_degree()} - return centrality - - -@not_implemented_for("undirected") -@nx._dispatchable -def out_degree_centrality(G): - """Compute the out-degree centrality for nodes. - - The out-degree centrality for a node v is the fraction of nodes its - outgoing edges are connected to. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with out-degree centrality as values. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.out_degree_centrality(G) - {0: 1.0, 1: 0.6666666666666666, 2: 0.0, 3: 0.0} - - See Also - -------- - degree_centrality, in_degree_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.out_degree()} - return centrality diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/dispersion.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/dispersion.py deleted file mode 100644 index a3fa685..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/dispersion.py +++ /dev/null @@ -1,107 +0,0 @@ -from itertools import combinations - -import networkx as nx - -__all__ = ["dispersion"] - - -@nx._dispatchable -def dispersion(G, u=None, v=None, normalized=True, alpha=1.0, b=0.0, c=0.0): - r"""Calculate dispersion between `u` and `v` in `G`. - - A link between two actors (`u` and `v`) has a high dispersion when their - mutual ties (`s` and `t`) are not well connected with each other. - - Parameters - ---------- - G : graph - A NetworkX graph. - u : node, optional - The source for the dispersion score (e.g. ego node of the network). - v : node, optional - The target of the dispersion score if specified. - normalized : bool - If True (default) normalize by the embeddedness of the nodes (u and v). - alpha, b, c : float - Parameters for the normalization procedure. When `normalized` is True, - the dispersion value is normalized by:: - - result = ((dispersion + b) ** alpha) / (embeddedness + c) - - as long as the denominator is nonzero. - - Returns - ------- - nodes : dictionary - If u (v) is specified, returns a dictionary of nodes with dispersion - score for all "target" ("source") nodes. If neither u nor v is - specified, returns a dictionary of dictionaries for all nodes 'u' in the - graph with a dispersion score for each node 'v'. - - Notes - ----- - This implementation follows Lars Backstrom and Jon Kleinberg [1]_. Typical - usage would be to run dispersion on the ego network $G_u$ if $u$ were - specified. Running :func:`dispersion` with neither $u$ nor $v$ specified - can take some time to complete. - - References - ---------- - .. [1] Romantic Partnerships and the Dispersion of Social Ties: - A Network Analysis of Relationship Status on Facebook. - Lars Backstrom, Jon Kleinberg. - https://arxiv.org/pdf/1310.6753v1.pdf - - """ - - def _dispersion(G_u, u, v): - """dispersion for all nodes 'v' in a ego network G_u of node 'u'""" - u_nbrs = set(G_u[u]) - ST = {n for n in G_u[v] if n in u_nbrs} - set_uv = {u, v} - # all possible ties of connections that u and b share - possib = combinations(ST, 2) - total = 0 - for s, t in possib: - # neighbors of s that are in G_u, not including u and v - nbrs_s = u_nbrs.intersection(G_u[s]) - set_uv - # s and t are not directly connected - if t not in nbrs_s: - # s and t do not share a connection - if nbrs_s.isdisjoint(G_u[t]): - # tick for disp(u, v) - total += 1 - # neighbors that u and v share - embeddedness = len(ST) - - dispersion_val = total - if normalized: - dispersion_val = (total + b) ** alpha - if embeddedness + c != 0: - dispersion_val /= embeddedness + c - - return dispersion_val - - if u is None: - # v and u are not specified - if v is None: - results = {n: {} for n in G} - for u in G: - for v in G[u]: - results[u][v] = _dispersion(G, u, v) - # u is not specified, but v is - else: - results = dict.fromkeys(G[v], {}) - for u in G[v]: - results[u] = _dispersion(G, v, u) - else: - # u is specified with no target v - if v is None: - results = dict.fromkeys(G[u], {}) - for v in G[u]: - results[v] = _dispersion(G, u, v) - # both u and v are specified - else: - results = _dispersion(G, u, v) - - return results diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/eigenvector.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/eigenvector.py deleted file mode 100644 index b8cf63e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/eigenvector.py +++ /dev/null @@ -1,357 +0,0 @@ -"""Functions for computing eigenvector centrality.""" - -import math - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["eigenvector_centrality", "eigenvector_centrality_numpy"] - - -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def eigenvector_centrality(G, max_iter=100, tol=1.0e-6, nstart=None, weight=None): - r"""Compute the eigenvector centrality for the graph G. - - Eigenvector centrality computes the centrality for a node by adding - the centrality of its predecessors. The centrality for node $i$ is the - $i$-th element of a left eigenvector associated with the eigenvalue $\lambda$ - of maximum modulus that is positive. Such an eigenvector $x$ is - defined up to a multiplicative constant by the equation - - .. math:: - - \lambda x^T = x^T A, - - where $A$ is the adjacency matrix of the graph G. By definition of - row-column product, the equation above is equivalent to - - .. math:: - - \lambda x_i = \sum_{j\to i}x_j. - - That is, adding the eigenvector centralities of the predecessors of - $i$ one obtains the eigenvector centrality of $i$ multiplied by - $\lambda$. In the case of undirected graphs, $x$ also solves the familiar - right-eigenvector equation $Ax = \lambda x$. - - By virtue of the Perron–Frobenius theorem [1]_, if G is strongly - connected there is a unique eigenvector $x$, and all its entries - are strictly positive. - - If G is not strongly connected there might be several left - eigenvectors associated with $\lambda$, and some of their elements - might be zero. - - Parameters - ---------- - G : graph - A networkx graph. - - max_iter : integer, optional (default=100) - Maximum number of power iterations. - - tol : float, optional (default=1.0e-6) - Error tolerance (in Euclidean norm) used to check convergence in - power iteration. - - nstart : dictionary, optional (default=None) - Starting value of power iteration for each node. Must have a nonzero - projection on the desired eigenvector for the power method to converge. - If None, this implementation uses an all-ones vector, which is a safe - choice. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. Otherwise holds the - name of the edge attribute used as weight. In this measure the - weight is interpreted as the connection strength. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with eigenvector centrality as the value. The - associated vector has unit Euclidean norm and the values are - nonegative. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> centrality = nx.eigenvector_centrality(G) - >>> sorted((v, f"{c:0.2f}") for v, c in centrality.items()) - [(0, '0.37'), (1, '0.60'), (2, '0.60'), (3, '0.37')] - - Raises - ------ - NetworkXPointlessConcept - If the graph G is the null graph. - - NetworkXError - If each value in `nstart` is zero. - - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - See Also - -------- - eigenvector_centrality_numpy - :func:`~networkx.algorithms.link_analysis.pagerank_alg.pagerank` - :func:`~networkx.algorithms.link_analysis.hits_alg.hits` - - Notes - ----- - Eigenvector centrality was introduced by Landau [2]_ for chess - tournaments. It was later rediscovered by Wei [3]_ and then - popularized by Kendall [4]_ in the context of sport ranking. Berge - introduced a general definition for graphs based on social connections - [5]_. Bonacich [6]_ reintroduced again eigenvector centrality and made - it popular in link analysis. - - This function computes the left dominant eigenvector, which corresponds - to adding the centrality of predecessors: this is the usual approach. - To add the centrality of successors first reverse the graph with - ``G.reverse()``. - - The implementation uses power iteration [7]_ to compute a dominant - eigenvector starting from the provided vector `nstart`. Convergence is - guaranteed as long as `nstart` has a nonzero projection on a dominant - eigenvector, which certainly happens using the default value. - - The method stops when the change in the computed vector between two - iterations is smaller than an error tolerance of ``G.number_of_nodes() - * tol`` or after ``max_iter`` iterations, but in the second case it - raises an exception. - - This implementation uses $(A + I)$ rather than the adjacency matrix - $A$ because the change preserves eigenvectors, but it shifts the - spectrum, thus guaranteeing convergence even for networks with - negative eigenvalues of maximum modulus. - - References - ---------- - .. [1] Abraham Berman and Robert J. Plemmons. - "Nonnegative Matrices in the Mathematical Sciences." - Classics in Applied Mathematics. SIAM, 1994. - - .. [2] Edmund Landau. - "Zur relativen Wertbemessung der Turnierresultate." - Deutsches Wochenschach, 11:366–369, 1895. - - .. [3] Teh-Hsing Wei. - "The Algebraic Foundations of Ranking Theory." - PhD thesis, University of Cambridge, 1952. - - .. [4] Maurice G. Kendall. - "Further contributions to the theory of paired comparisons." - Biometrics, 11(1):43–62, 1955. - https://www.jstor.org/stable/3001479 - - .. [5] Claude Berge - "Théorie des graphes et ses applications." - Dunod, Paris, France, 1958. - - .. [6] Phillip Bonacich. - "Technique for analyzing overlapping memberships." - Sociological Methodology, 4:176–185, 1972. - https://www.jstor.org/stable/270732 - - .. [7] Power iteration:: https://en.wikipedia.org/wiki/Power_iteration - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - "cannot compute centrality for the null graph" - ) - # If no initial vector is provided, start with the all-ones vector. - if nstart is None: - nstart = {v: 1 for v in G} - if all(v == 0 for v in nstart.values()): - raise nx.NetworkXError("initial vector cannot have all zero values") - # Normalize the initial vector so that each entry is in [0, 1]. This is - # guaranteed to never have a divide-by-zero error by the previous line. - nstart_sum = sum(nstart.values()) - x = {k: v / nstart_sum for k, v in nstart.items()} - nnodes = G.number_of_nodes() - # make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = xlast.copy() # Start with xlast times I to iterate with (A+I) - # do the multiplication y^T = x^T A (left eigenvector) - for n in x: - for nbr in G[n]: - w = G[n][nbr].get(weight, 1) if weight else 1 - x[nbr] += xlast[n] * w - # Normalize the vector. The normalization denominator `norm` - # should never be zero by the Perron--Frobenius - # theorem. However, in case it is due to numerical error, we - # assume the norm to be one instead. - norm = math.hypot(*x.values()) or 1 - x = {k: v / norm for k, v in x.items()} - # Check for convergence (in the L_1 norm). - if sum(abs(x[n] - xlast[n]) for n in x) < nnodes * tol: - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -@nx._dispatchable(edge_attrs="weight") -def eigenvector_centrality_numpy(G, weight=None, max_iter=50, tol=0): - r"""Compute the eigenvector centrality for the graph `G`. - - Eigenvector centrality computes the centrality for a node by adding - the centrality of its predecessors. The centrality for node $i$ is the - $i$-th element of a left eigenvector associated with the eigenvalue $\lambda$ - of maximum modulus that is positive. Such an eigenvector $x$ is - defined up to a multiplicative constant by the equation - - .. math:: - - \lambda x^T = x^T A, - - where $A$ is the adjacency matrix of the graph `G`. By definition of - row-column product, the equation above is equivalent to - - .. math:: - - \lambda x_i = \sum_{j\to i}x_j. - - That is, adding the eigenvector centralities of the predecessors of - $i$ one obtains the eigenvector centrality of $i$ multiplied by - $\lambda$. In the case of undirected graphs, $x$ also solves the familiar - right-eigenvector equation $Ax = \lambda x$. - - By virtue of the Perron--Frobenius theorem [1]_, if `G` is (strongly) - connected, there is a unique eigenvector $x$, and all its entries - are strictly positive. - - However, if `G` is not (strongly) connected, there might be several left - eigenvectors associated with $\lambda$, and some of their elements - might be zero. - Depending on the method used to choose eigenvectors, round-off error can affect - which of the infinitely many eigenvectors is reported. - This can lead to inconsistent results for the same graph, - which the underlying implementation is not robust to. - For this reason, only (strongly) connected graphs are accepted. - - Parameters - ---------- - G : graph - A connected NetworkX graph. - - weight : None or string, optional (default=None) - If ``None``, all edge weights are considered equal. Otherwise holds the - name of the edge attribute used as weight. In this measure the - weight is interpreted as the connection strength. - - max_iter : integer, optional (default=50) - Maximum number of Arnoldi update iterations allowed. - - tol : float, optional (default=0) - Relative accuracy for eigenvalues (stopping criterion). - The default value of 0 implies machine precision. - - Returns - ------- - nodes : dict of nodes - Dictionary of nodes with eigenvector centrality as the value. The - associated vector has unit Euclidean norm and the values are - nonnegative. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> centrality = nx.eigenvector_centrality_numpy(G) - >>> print([f"{node} {centrality[node]:0.2f}" for node in centrality]) - ['0 0.37', '1 0.60', '2 0.60', '3 0.37'] - - Raises - ------ - NetworkXPointlessConcept - If the graph `G` is the null graph. - - ArpackNoConvergence - When the requested convergence is not obtained. The currently - converged eigenvalues and eigenvectors can be found as - eigenvalues and eigenvectors attributes of the exception object. - - AmbiguousSolution - If `G` is not connected. - - See Also - -------- - :func:`scipy.sparse.linalg.eigs` - eigenvector_centrality - :func:`~networkx.algorithms.link_analysis.pagerank_alg.pagerank` - :func:`~networkx.algorithms.link_analysis.hits_alg.hits` - - Notes - ----- - Eigenvector centrality was introduced by Landau [2]_ for chess - tournaments. It was later rediscovered by Wei [3]_ and then - popularized by Kendall [4]_ in the context of sport ranking. Berge - introduced a general definition for graphs based on social connections - [5]_. Bonacich [6]_ reintroduced again eigenvector centrality and made - it popular in link analysis. - - This function computes the left dominant eigenvector, which corresponds - to adding the centrality of predecessors: this is the usual approach. - To add the centrality of successors first reverse the graph with - ``G.reverse()``. - - This implementation uses the - :func:`SciPy sparse eigenvalue solver` (ARPACK) - to find the largest eigenvalue/eigenvector pair using Arnoldi iterations - [7]_. - - References - ---------- - .. [1] Abraham Berman and Robert J. Plemmons. - "Nonnegative Matrices in the Mathematical Sciences". - Classics in Applied Mathematics. SIAM, 1994. - - .. [2] Edmund Landau. - "Zur relativen Wertbemessung der Turnierresultate". - Deutsches Wochenschach, 11:366--369, 1895. - - .. [3] Teh-Hsing Wei. - "The Algebraic Foundations of Ranking Theory". - PhD thesis, University of Cambridge, 1952. - - .. [4] Maurice G. Kendall. - "Further contributions to the theory of paired comparisons". - Biometrics, 11(1):43--62, 1955. - https://www.jstor.org/stable/3001479 - - .. [5] Claude Berge. - "Théorie des graphes et ses applications". - Dunod, Paris, France, 1958. - - .. [6] Phillip Bonacich. - "Technique for analyzing overlapping memberships". - Sociological Methodology, 4:176--185, 1972. - https://www.jstor.org/stable/270732 - - .. [7] Arnoldi, W. E. (1951). - "The principle of minimized iterations in the solution of the matrix eigenvalue problem". - Quarterly of Applied Mathematics. 9 (1): 17--29. - https://doi.org/10.1090/qam/42792 - """ - import numpy as np - import scipy as sp - - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - "cannot compute centrality for the null graph" - ) - connected = nx.is_strongly_connected(G) if G.is_directed() else nx.is_connected(G) - if not connected: # See gh-6888. - raise nx.AmbiguousSolution( - "`eigenvector_centrality_numpy` does not give consistent results for disconnected graphs" - ) - M = nx.to_scipy_sparse_array(G, nodelist=list(G), weight=weight, dtype=float) - _, eigenvector = sp.sparse.linalg.eigs( - M.T, k=1, which="LR", maxiter=max_iter, tol=tol - ) - largest = eigenvector.flatten().real - norm = np.sign(largest.sum()) * sp.linalg.norm(largest) - return dict(zip(G, (largest / norm).tolist())) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/flow_matrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/flow_matrix.py deleted file mode 100644 index e72b5e9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/flow_matrix.py +++ /dev/null @@ -1,130 +0,0 @@ -# Helpers for current-flow betweenness and current-flow closeness -# Lazy computations for inverse Laplacian and flow-matrix rows. -import networkx as nx - - -@nx._dispatchable(edge_attrs="weight") -def flow_matrix_row(G, weight=None, dtype=float, solver="lu"): - # Generate a row of the current-flow matrix - import numpy as np - - solvername = { - "full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian, - } - n = G.number_of_nodes() - L = nx.laplacian_matrix(G, nodelist=range(n), weight=weight).asformat("csc") - L = L.astype(dtype) - C = solvername[solver](L, dtype=dtype) # initialize solver - w = C.w # w is the Laplacian matrix width - # row-by-row flow matrix - for u, v in sorted(sorted((u, v)) for u, v in G.edges()): - B = np.zeros(w, dtype=dtype) - c = G[u][v].get(weight, 1.0) - B[u % w] = c - B[v % w] = -c - # get only the rows needed in the inverse laplacian - # and multiply to get the flow matrix row - row = B @ C.get_rows(u, v) - yield row, (u, v) - - -# Class to compute the inverse laplacian only for specified rows -# Allows computation of the current-flow matrix without storing entire -# inverse laplacian matrix -class InverseLaplacian: - def __init__(self, L, width=None, dtype=None): - global np - import numpy as np - - (n, n) = L.shape - self.dtype = dtype - self.n = n - if width is None: - self.w = self.width(L) - else: - self.w = width - self.C = np.zeros((self.w, n), dtype=dtype) - self.L1 = L[1:, 1:] - self.init_solver(L) - - def init_solver(self, L): - pass - - def solve(self, r): - raise nx.NetworkXError("Implement solver") - - def solve_inverse(self, r): - raise nx.NetworkXError("Implement solver") - - def get_rows(self, r1, r2): - for r in range(r1, r2 + 1): - self.C[r % self.w, 1:] = self.solve_inverse(r) - return self.C - - def get_row(self, r): - self.C[r % self.w, 1:] = self.solve_inverse(r) - return self.C[r % self.w] - - def width(self, L): - m = 0 - for i, row in enumerate(L): - w = 0 - y = np.nonzero(row)[-1] - if len(y) > 0: - v = y - i - w = v.max() - v.min() + 1 - m = max(w, m) - return m - - -class FullInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - self.IL = np.zeros(L.shape, dtype=self.dtype) - self.IL[1:, 1:] = np.linalg.inv(self.L1.todense()) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s = self.IL @ rhs - return s - - def solve_inverse(self, r): - return self.IL[r, 1:] - - -class SuperLUInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - import scipy as sp - - self.lusolve = sp.sparse.linalg.factorized(self.L1.tocsc()) - - def solve_inverse(self, r): - rhs = np.zeros(self.n, dtype=self.dtype) - rhs[r] = 1 - return self.lusolve(rhs[1:]) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s[1:] = self.lusolve(rhs[1:]) - return s - - -class CGInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - global sp - import scipy as sp - - ilu = sp.sparse.linalg.spilu(self.L1.tocsc()) - n = self.n - 1 - self.M = sp.sparse.linalg.LinearOperator(shape=(n, n), matvec=ilu.solve) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s[1:] = sp.sparse.linalg.cg(self.L1, rhs[1:], M=self.M, atol=0)[0] - return s - - def solve_inverse(self, r): - rhs = np.zeros(self.n, self.dtype) - rhs[r] = 1 - return sp.sparse.linalg.cg(self.L1, rhs[1:], M=self.M, atol=0)[0] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/group.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/group.py deleted file mode 100644 index 7c48742..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/group.py +++ /dev/null @@ -1,787 +0,0 @@ -"""Group centrality measures.""" - -from copy import deepcopy - -import networkx as nx -from networkx.algorithms.centrality.betweenness import ( - _accumulate_endpoints, - _single_source_dijkstra_path_basic, - _single_source_shortest_path_basic, -) -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - "group_betweenness_centrality", - "group_closeness_centrality", - "group_degree_centrality", - "group_in_degree_centrality", - "group_out_degree_centrality", - "prominent_group", -] - - -@nx._dispatchable(edge_attrs="weight") -def group_betweenness_centrality(G, C, normalized=True, weight=None, endpoints=False): - r"""Compute the group betweenness centrality for a group of nodes. - - Group betweenness centrality of a group of nodes $C$ is the sum of the - fraction of all-pairs shortest paths that pass through any vertex in $C$ - - .. math:: - - c_B(v) =\sum_{s,t \in V} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|C)$ is the number of - those paths passing through some node in group $C$. Note that - $(s, t)$ are not members of the group ($V-C$ is the set of nodes - in $V$ that are not in $C$). - - Parameters - ---------- - G : graph - A NetworkX graph. - - C : list or set or list of lists or list of sets - A group or a list of groups containing nodes which belong to G, for which group betweenness - centrality is to be calculated. - - normalized : bool, optional (default=True) - If True, group betweenness is normalized by `1/((|V|-|C|)(|V|-|C|-1))` - where `|V|` is the number of nodes in G and `|C|` is the number of nodes in C. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - The weight of an edge is treated as the length or distance between the two sides. - - endpoints : bool, optional (default=False) - If True include the endpoints in the shortest path counts. - - Raises - ------ - NodeNotFound - If node(s) in C are not present in G. - - Returns - ------- - betweenness : list of floats or float - If C is a single group then return a float. If C is a list with - several groups then return a list of group betweenness centralities. - - See Also - -------- - betweenness_centrality - - Notes - ----- - Group betweenness centrality is described in [1]_ and its importance discussed in [3]_. - The initial implementation of the algorithm is mentioned in [2]_. This function uses - an improved algorithm presented in [4]_. - - The number of nodes in the group must be a maximum of n - 2 where `n` - is the total number of nodes in the graph. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - between "u" and "v" are counted as two possible paths (one each - direction) while undirected paths between "u" and "v" are counted - as one path. Said another way, the sum in the expression above is - over all ``s != t`` for directed graphs and for ``s < t`` for undirected graphs. - - - References - ---------- - .. [1] M G Everett and S P Borgatti: - The Centrality of Groups and Classes. - Journal of Mathematical Sociology. 23(3): 181-201. 1999. - http://www.analytictech.com/borgatti/group_centrality.htm - .. [2] Ulrik Brandes: - On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.9610&rep=rep1&type=pdf - .. [3] Sourav Medya et. al.: - Group Centrality Maximization via Network Design. - SIAM International Conference on Data Mining, SDM 2018, 126–134. - https://sites.cs.ucsb.edu/~arlei/pubs/sdm18.pdf - .. [4] Rami Puzis, Yuval Elovici, and Shlomi Dolev. - "Fast algorithm for successive computation of group betweenness centrality." - https://journals.aps.org/pre/pdf/10.1103/PhysRevE.76.056709 - - """ - GBC = [] # initialize betweenness - list_of_groups = True - # check weather C contains one or many groups - if any(el in G for el in C): - C = [C] - list_of_groups = False - set_v = {node for group in C for node in group} - if set_v - G.nodes: # element(s) of C not in G - raise nx.NodeNotFound(f"The node(s) {set_v - G.nodes} are in C but not in G.") - - # pre-processing - PB, sigma, D = _group_preprocessing(G, set_v, weight) - - # the algorithm for each group - for group in C: - group = set(group) # set of nodes in group - # initialize the matrices of the sigma and the PB - GBC_group = 0 - sigma_m = deepcopy(sigma) - PB_m = deepcopy(PB) - sigma_m_v = deepcopy(sigma_m) - PB_m_v = deepcopy(PB_m) - for v in group: - GBC_group += PB_m[v][v] - for x in group: - for y in group: - dxvy = 0 - dxyv = 0 - dvxy = 0 - if not ( - sigma_m[x][y] == 0 or sigma_m[x][v] == 0 or sigma_m[v][y] == 0 - ): - if D[x][v] == D[x][y] + D[y][v]: - dxyv = sigma_m[x][y] * sigma_m[y][v] / sigma_m[x][v] - if D[x][y] == D[x][v] + D[v][y]: - dxvy = sigma_m[x][v] * sigma_m[v][y] / sigma_m[x][y] - if D[v][y] == D[v][x] + D[x][y]: - dvxy = sigma_m[v][x] * sigma[x][y] / sigma[v][y] - sigma_m_v[x][y] = sigma_m[x][y] * (1 - dxvy) - PB_m_v[x][y] = PB_m[x][y] - PB_m[x][y] * dxvy - if y != v: - PB_m_v[x][y] -= PB_m[x][v] * dxyv - if x != v: - PB_m_v[x][y] -= PB_m[v][y] * dvxy - sigma_m, sigma_m_v = sigma_m_v, sigma_m - PB_m, PB_m_v = PB_m_v, PB_m - - # endpoints - v, c = len(G), len(group) - if not endpoints: - scale = 0 - # if the graph is connected then subtract the endpoints from - # the count for all the nodes in the graph. else count how many - # nodes are connected to the group's nodes and subtract that. - if nx.is_directed(G): - if nx.is_strongly_connected(G): - scale = c * (2 * v - c - 1) - elif nx.is_connected(G): - scale = c * (2 * v - c - 1) - if scale == 0: - for group_node1 in group: - for node in D[group_node1]: - if node != group_node1: - if node in group: - scale += 1 - else: - scale += 2 - GBC_group -= scale - - # normalized - if normalized: - scale = 1 / ((v - c) * (v - c - 1)) - GBC_group *= scale - - # If undirected than count only the undirected edges - elif not G.is_directed(): - GBC_group /= 2 - - GBC.append(GBC_group) - if list_of_groups: - return GBC - return GBC[0] - - -def _group_preprocessing(G, set_v, weight): - sigma = {} - delta = {} - D = {} - betweenness = dict.fromkeys(G, 0) - for s in G: - if weight is None: # use BFS - S, P, sigma[s], D[s] = _single_source_shortest_path_basic(G, s) - else: # use Dijkstra's algorithm - S, P, sigma[s], D[s] = _single_source_dijkstra_path_basic(G, s, weight) - betweenness, delta[s] = _accumulate_endpoints(betweenness, S, P, sigma[s], s) - for i in delta[s]: # add the paths from s to i and rescale sigma - if s != i: - delta[s][i] += 1 - if weight is not None: - sigma[s][i] = sigma[s][i] / 2 - # building the path betweenness matrix only for nodes that appear in the group - PB = dict.fromkeys(G) - for group_node1 in set_v: - PB[group_node1] = dict.fromkeys(G, 0.0) - for group_node2 in set_v: - if group_node2 not in D[group_node1]: - continue - for node in G: - # if node is connected to the two group nodes than continue - if group_node2 in D[node] and group_node1 in D[node]: - if ( - D[node][group_node2] - == D[node][group_node1] + D[group_node1][group_node2] - ): - PB[group_node1][group_node2] += ( - delta[node][group_node2] - * sigma[node][group_node1] - * sigma[group_node1][group_node2] - / sigma[node][group_node2] - ) - return PB, sigma, D - - -@nx._dispatchable(edge_attrs="weight") -def prominent_group( - G, k, weight=None, C=None, endpoints=False, normalized=True, greedy=False -): - r"""Find the prominent group of size $k$ in graph $G$. The prominence of the - group is evaluated by the group betweenness centrality. - - Group betweenness centrality of a group of nodes $C$ is the sum of the - fraction of all-pairs shortest paths that pass through any vertex in $C$ - - .. math:: - - c_B(v) =\sum_{s,t \in V} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|C)$ is the number of - those paths passing through some node in group $C$. Note that - $(s, t)$ are not members of the group ($V-C$ is the set of nodes - in $V$ that are not in $C$). - - Parameters - ---------- - G : graph - A NetworkX graph. - - k : int - The number of nodes in the group. - - normalized : bool, optional (default=True) - If True, group betweenness is normalized by ``1/((|V|-|C|)(|V|-|C|-1))`` - where ``|V|`` is the number of nodes in G and ``|C|`` is the number of - nodes in C. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - The weight of an edge is treated as the length or distance between the two sides. - - endpoints : bool, optional (default=False) - If True include the endpoints in the shortest path counts. - - C : list or set, optional (default=None) - list of nodes which won't be candidates of the prominent group. - - greedy : bool, optional (default=False) - Using a naive greedy algorithm in order to find non-optimal prominent - group. For scale free networks the results are negligibly below the optimal - results. - - Raises - ------ - NodeNotFound - If node(s) in C are not present in G. - - Returns - ------- - max_GBC : float - The group betweenness centrality of the prominent group. - - max_group : list - The list of nodes in the prominent group. - - See Also - -------- - betweenness_centrality, group_betweenness_centrality - - Notes - ----- - Group betweenness centrality is described in [1]_ and its importance discussed in [3]_. - The algorithm is described in [2]_ and is based on techniques mentioned in [4]_. - - The number of nodes in the group must be a maximum of ``n - 2`` where ``n`` - is the total number of nodes in the graph. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - between "u" and "v" are counted as two possible paths (one each - direction) while undirected paths between "u" and "v" are counted - as one path. Said another way, the sum in the expression above is - over all ``s != t`` for directed graphs and for ``s < t`` for undirected graphs. - - References - ---------- - .. [1] M G Everett and S P Borgatti: - The Centrality of Groups and Classes. - Journal of Mathematical Sociology. 23(3): 181-201. 1999. - http://www.analytictech.com/borgatti/group_centrality.htm - .. [2] Rami Puzis, Yuval Elovici, and Shlomi Dolev: - "Finding the Most Prominent Group in Complex Networks" - AI communications 20(4): 287-296, 2007. - https://www.researchgate.net/profile/Rami_Puzis2/publication/220308855 - .. [3] Sourav Medya et. al.: - Group Centrality Maximization via Network Design. - SIAM International Conference on Data Mining, SDM 2018, 126–134. - https://sites.cs.ucsb.edu/~arlei/pubs/sdm18.pdf - .. [4] Rami Puzis, Yuval Elovici, and Shlomi Dolev. - "Fast algorithm for successive computation of group betweenness centrality." - https://journals.aps.org/pre/pdf/10.1103/PhysRevE.76.056709 - """ - import numpy as np - import pandas as pd - - if C is not None: - C = set(C) - if C - G.nodes: # element(s) of C not in G - raise nx.NodeNotFound(f"The node(s) {C - G.nodes} are in C but not in G.") - nodes = list(G.nodes - C) - else: - nodes = list(G.nodes) - DF_tree = nx.Graph() - DF_tree.__networkx_cache__ = None # Disable caching - PB, sigma, D = _group_preprocessing(G, nodes, weight) - betweenness = pd.DataFrame.from_dict(PB) - if C is not None: - for node in C: - # remove from the betweenness all the nodes not part of the group - betweenness.drop(index=node, inplace=True) - betweenness.drop(columns=node, inplace=True) - CL = [node for _, node in sorted(zip(np.diag(betweenness), nodes), reverse=True)] - max_GBC = 0 - max_group = [] - DF_tree.add_node( - 1, - CL=CL, - betweenness=betweenness, - GBC=0, - GM=[], - sigma=sigma, - cont=dict(zip(nodes, np.diag(betweenness))), - ) - - # the algorithm - DF_tree.nodes[1]["heu"] = 0 - for i in range(k): - DF_tree.nodes[1]["heu"] += DF_tree.nodes[1]["cont"][DF_tree.nodes[1]["CL"][i]] - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, 1, D, max_group, nodes, greedy - ) - - v = len(G) - if not endpoints: - scale = 0 - # if the graph is connected then subtract the endpoints from - # the count for all the nodes in the graph. else count how many - # nodes are connected to the group's nodes and subtract that. - if nx.is_directed(G): - if nx.is_strongly_connected(G): - scale = k * (2 * v - k - 1) - elif nx.is_connected(G): - scale = k * (2 * v - k - 1) - if scale == 0: - for group_node1 in max_group: - for node in D[group_node1]: - if node != group_node1: - if node in max_group: - scale += 1 - else: - scale += 2 - max_GBC -= scale - - # normalized - if normalized: - scale = 1 / ((v - k) * (v - k - 1)) - max_GBC *= scale - - # If undirected then count only the undirected edges - elif not G.is_directed(): - max_GBC /= 2 - max_GBC = float(f"{max_GBC:.2f}") - return max_GBC, max_group - - -def _dfbnb(G, k, DF_tree, max_GBC, root, D, max_group, nodes, greedy): - # stopping condition - if we found a group of size k and with higher GBC then prune - if len(DF_tree.nodes[root]["GM"]) == k and DF_tree.nodes[root]["GBC"] > max_GBC: - return DF_tree.nodes[root]["GBC"], DF_tree, DF_tree.nodes[root]["GM"] - # stopping condition - if the size of group members equal to k or there are less than - # k - |GM| in the candidate list or the heuristic function plus the GBC is below the - # maximal GBC found then prune - if ( - len(DF_tree.nodes[root]["GM"]) == k - or len(DF_tree.nodes[root]["CL"]) <= k - len(DF_tree.nodes[root]["GM"]) - or DF_tree.nodes[root]["GBC"] + DF_tree.nodes[root]["heu"] <= max_GBC - ): - return max_GBC, DF_tree, max_group - - # finding the heuristic of both children - node_p, node_m, DF_tree = _heuristic(k, root, DF_tree, D, nodes, greedy) - - # finding the child with the bigger heuristic + GBC and expand - # that node first if greedy then only expand the plus node - if greedy: - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, node_p, D, max_group, nodes, greedy - ) - - elif ( - DF_tree.nodes[node_p]["GBC"] + DF_tree.nodes[node_p]["heu"] - > DF_tree.nodes[node_m]["GBC"] + DF_tree.nodes[node_m]["heu"] - ): - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, node_p, D, max_group, nodes, greedy - ) - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, node_m, D, max_group, nodes, greedy - ) - else: - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, node_m, D, max_group, nodes, greedy - ) - max_GBC, DF_tree, max_group = _dfbnb( - G, k, DF_tree, max_GBC, node_p, D, max_group, nodes, greedy - ) - return max_GBC, DF_tree, max_group - - -def _heuristic(k, root, DF_tree, D, nodes, greedy): - import numpy as np - - # This helper function add two nodes to DF_tree - one left son and the - # other right son, finds their heuristic, CL, GBC, and GM - node_p = DF_tree.number_of_nodes() + 1 - node_m = DF_tree.number_of_nodes() + 2 - added_node = DF_tree.nodes[root]["CL"][0] - - # adding the plus node - DF_tree.add_nodes_from([(node_p, deepcopy(DF_tree.nodes[root]))]) - DF_tree.nodes[node_p]["GM"].append(added_node) - DF_tree.nodes[node_p]["GBC"] += DF_tree.nodes[node_p]["cont"][added_node] - root_node = DF_tree.nodes[root] - for x in nodes: - for y in nodes: - dxvy = 0 - dxyv = 0 - dvxy = 0 - if not ( - root_node["sigma"][x][y] == 0 - or root_node["sigma"][x][added_node] == 0 - or root_node["sigma"][added_node][y] == 0 - ): - if D[x][added_node] == D[x][y] + D[y][added_node]: - dxyv = ( - root_node["sigma"][x][y] - * root_node["sigma"][y][added_node] - / root_node["sigma"][x][added_node] - ) - if D[x][y] == D[x][added_node] + D[added_node][y]: - dxvy = ( - root_node["sigma"][x][added_node] - * root_node["sigma"][added_node][y] - / root_node["sigma"][x][y] - ) - if D[added_node][y] == D[added_node][x] + D[x][y]: - dvxy = ( - root_node["sigma"][added_node][x] - * root_node["sigma"][x][y] - / root_node["sigma"][added_node][y] - ) - DF_tree.nodes[node_p]["sigma"][x][y] = root_node["sigma"][x][y] * (1 - dxvy) - DF_tree.nodes[node_p]["betweenness"].loc[y, x] = ( - root_node["betweenness"][x][y] - root_node["betweenness"][x][y] * dxvy - ) - if y != added_node: - DF_tree.nodes[node_p]["betweenness"].loc[y, x] -= ( - root_node["betweenness"][x][added_node] * dxyv - ) - if x != added_node: - DF_tree.nodes[node_p]["betweenness"].loc[y, x] -= ( - root_node["betweenness"][added_node][y] * dvxy - ) - - DF_tree.nodes[node_p]["CL"] = [ - node - for _, node in sorted( - zip(np.diag(DF_tree.nodes[node_p]["betweenness"]), nodes), reverse=True - ) - if node not in DF_tree.nodes[node_p]["GM"] - ] - DF_tree.nodes[node_p]["cont"] = dict( - zip(nodes, np.diag(DF_tree.nodes[node_p]["betweenness"])) - ) - DF_tree.nodes[node_p]["heu"] = 0 - for i in range(k - len(DF_tree.nodes[node_p]["GM"])): - DF_tree.nodes[node_p]["heu"] += DF_tree.nodes[node_p]["cont"][ - DF_tree.nodes[node_p]["CL"][i] - ] - - # adding the minus node - don't insert the first node in the CL to GM - # Insert minus node only if isn't greedy type algorithm - if not greedy: - DF_tree.add_nodes_from([(node_m, deepcopy(DF_tree.nodes[root]))]) - DF_tree.nodes[node_m]["CL"].pop(0) - DF_tree.nodes[node_m]["cont"].pop(added_node) - DF_tree.nodes[node_m]["heu"] = 0 - for i in range(k - len(DF_tree.nodes[node_m]["GM"])): - DF_tree.nodes[node_m]["heu"] += DF_tree.nodes[node_m]["cont"][ - DF_tree.nodes[node_m]["CL"][i] - ] - else: - node_m = None - - return node_p, node_m, DF_tree - - -@nx._dispatchable(edge_attrs="weight") -def group_closeness_centrality(G, S, weight=None): - r"""Compute the group closeness centrality for a group of nodes. - - Group closeness centrality of a group of nodes $S$ is a measure - of how close the group is to the other nodes in the graph. - - .. math:: - - c_{close}(S) = \frac{|V-S|}{\sum_{v \in V-S} d_{S, v}} - - d_{S, v} = min_{u \in S} (d_{u, v}) - - where $V$ is the set of nodes, $d_{S, v}$ is the distance of - the group $S$ from $v$ defined as above. ($V-S$ is the set of nodes - in $V$ that are not in $S$). - - Parameters - ---------- - G : graph - A NetworkX graph. - - S : list or set - S is a group of nodes which belong to G, for which group closeness - centrality is to be calculated. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - The weight of an edge is treated as the length or distance between the two sides. - - Raises - ------ - NodeNotFound - If node(s) in S are not present in G. - - Returns - ------- - closeness : float - Group closeness centrality of the group S. - - See Also - -------- - closeness_centrality - - Notes - ----- - The measure was introduced in [1]_. - The formula implemented here is described in [2]_. - - Higher values of closeness indicate greater centrality. - - It is assumed that 1 / 0 is 0 (required in the case of directed graphs, - or when a shortest path length is 0). - - The number of nodes in the group must be a maximum of n - 1 where `n` - is the total number of nodes in the graph. - - For directed graphs, the incoming distance is utilized here. To use the - outward distance, act on `G.reverse()`. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - References - ---------- - .. [1] M G Everett and S P Borgatti: - The Centrality of Groups and Classes. - Journal of Mathematical Sociology. 23(3): 181-201. 1999. - http://www.analytictech.com/borgatti/group_centrality.htm - .. [2] J. Zhao et. al.: - Measuring and Maximizing Group Closeness Centrality over - Disk Resident Graphs. - WWWConference Proceedings, 2014. 689-694. - https://doi.org/10.1145/2567948.2579356 - """ - if G.is_directed(): - G = G.reverse() # reverse view - closeness = 0 # initialize to 0 - V = set(G) # set of nodes in G - S = set(S) # set of nodes in group S - V_S = V - S # set of nodes in V but not S - shortest_path_lengths = nx.multi_source_dijkstra_path_length(G, S, weight=weight) - # accumulation - for v in V_S: - try: - closeness += shortest_path_lengths[v] - except KeyError: # no path exists - closeness += 0 - try: - closeness = len(V_S) / closeness - except ZeroDivisionError: # 1 / 0 assumed as 0 - closeness = 0 - return closeness - - -@nx._dispatchable -def group_degree_centrality(G, S): - """Compute the group degree centrality for a group of nodes. - - Group degree centrality of a group of nodes $S$ is the fraction - of non-group members connected to group members. - - Parameters - ---------- - G : graph - A NetworkX graph. - - S : list or set - S is a group of nodes which belong to G, for which group degree - centrality is to be calculated. - - Raises - ------ - NetworkXError - If node(s) in S are not in G. - - Returns - ------- - centrality : float - Group degree centrality of the group S. - - See Also - -------- - degree_centrality - group_in_degree_centrality - group_out_degree_centrality - - Notes - ----- - The measure was introduced in [1]_. - - The number of nodes in the group must be a maximum of n - 1 where `n` - is the total number of nodes in the graph. - - References - ---------- - .. [1] M G Everett and S P Borgatti: - The Centrality of Groups and Classes. - Journal of Mathematical Sociology. 23(3): 181-201. 1999. - http://www.analytictech.com/borgatti/group_centrality.htm - """ - centrality = len(set().union(*[set(G.neighbors(i)) for i in S]) - set(S)) - centrality /= len(G.nodes()) - len(S) - return centrality - - -@not_implemented_for("undirected") -@nx._dispatchable -def group_in_degree_centrality(G, S): - """Compute the group in-degree centrality for a group of nodes. - - Group in-degree centrality of a group of nodes $S$ is the fraction - of non-group members connected to group members by incoming edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - S : list or set - S is a group of nodes which belong to G, for which group in-degree - centrality is to be calculated. - - Returns - ------- - centrality : float - Group in-degree centrality of the group S. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - NodeNotFound - If node(s) in S are not in G. - - See Also - -------- - degree_centrality - group_degree_centrality - group_out_degree_centrality - - Notes - ----- - The number of nodes in the group must be a maximum of n - 1 where `n` - is the total number of nodes in the graph. - - `G.neighbors(i)` gives nodes with an outward edge from i, in a DiGraph, - so for group in-degree centrality, the reverse graph is used. - """ - return group_degree_centrality(G.reverse(), S) - - -@not_implemented_for("undirected") -@nx._dispatchable -def group_out_degree_centrality(G, S): - """Compute the group out-degree centrality for a group of nodes. - - Group out-degree centrality of a group of nodes $S$ is the fraction - of non-group members connected to group members by outgoing edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - S : list or set - S is a group of nodes which belong to G, for which group in-degree - centrality is to be calculated. - - Returns - ------- - centrality : float - Group out-degree centrality of the group S. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - NodeNotFound - If node(s) in S are not in G. - - See Also - -------- - degree_centrality - group_degree_centrality - group_in_degree_centrality - - Notes - ----- - The number of nodes in the group must be a maximum of n - 1 where `n` - is the total number of nodes in the graph. - - `G.neighbors(i)` gives nodes with an outward edge from i, in a DiGraph, - so for group out-degree centrality, the graph itself is used. - """ - return group_degree_centrality(G, S) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/harmonic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/harmonic.py deleted file mode 100644 index 236e149..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/harmonic.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Functions for computing the harmonic centrality of a graph.""" - -from functools import partial - -import networkx as nx - -__all__ = ["harmonic_centrality"] - - -@nx._dispatchable(edge_attrs="distance") -def harmonic_centrality(G, nbunch=None, distance=None, sources=None): - r"""Compute harmonic centrality for nodes. - - Harmonic centrality [1]_ of a node `u` is the sum of the reciprocal - of the shortest path distances from all other nodes to `u` - - .. math:: - - C(u) = \sum_{v \neq u} \frac{1}{d(v, u)} - - where `d(v, u)` is the shortest-path distance between `v` and `u`. - - If `sources` is given as an argument, the returned harmonic centrality - values are calculated as the sum of the reciprocals of the shortest - path distances from the nodes specified in `sources` to `u` instead - of from all nodes to `u`. - - Notice that higher values indicate higher centrality. - - Parameters - ---------- - G : graph - A NetworkX graph - - nbunch : container (default: all nodes in G) - Container of nodes for which harmonic centrality values are calculated. - - sources : container (default: all nodes in G) - Container of nodes `v` over which reciprocal distances are computed. - Nodes not in `G` are silently ignored. - - distance : edge attribute key, optional (default=None) - Use the specified edge attribute as the edge distance in shortest - path calculations. If `None`, then each edge will have distance equal to 1. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with harmonic centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, closeness_centrality - - Notes - ----- - If the 'distance' keyword is set to an edge attribute key then the - shortest-path length will be computed using Dijkstra's algorithm with - that edge attribute as the edge weight. - - References - ---------- - .. [1] Boldi, Paolo, and Sebastiano Vigna. "Axioms for centrality." - Internet Mathematics 10.3-4 (2014): 222-262. - """ - - nbunch = set(G.nbunch_iter(nbunch) if nbunch is not None else G.nodes) - sources = set(G.nbunch_iter(sources) if sources is not None else G.nodes) - - centrality = {u: 0 for u in nbunch} - - transposed = False - if len(nbunch) < len(sources): - transposed = True - nbunch, sources = sources, nbunch - if nx.is_directed(G): - G = nx.reverse(G, copy=False) - - spl = partial(nx.shortest_path_length, G, weight=distance) - for v in sources: - dist = spl(v) - for u in nbunch.intersection(dist): - d = dist[u] - if d == 0: # handle u == v and edges with 0 weight - continue - centrality[v if transposed else u] += 1 / d - - return centrality diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/katz.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/katz.py deleted file mode 100644 index 4bd087b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/katz.py +++ /dev/null @@ -1,331 +0,0 @@ -"""Katz centrality.""" - -import math - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["katz_centrality", "katz_centrality_numpy"] - - -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def katz_centrality( - G, - alpha=0.1, - beta=1.0, - max_iter=1000, - tol=1.0e-6, - nstart=None, - normalized=True, - weight=None, -): - r"""Compute the Katz centrality for the nodes of the graph G. - - Katz centrality computes the centrality for a node based on the centrality - of its neighbors. It is a generalization of the eigenvector centrality. The - Katz centrality for node $i$ is - - .. math:: - - x_i = \alpha \sum_{j} A_{ij} x_j + \beta, - - where $A$ is the adjacency matrix of graph G with eigenvalues $\lambda$. - - The parameter $\beta$ controls the initial centrality and - - .. math:: - - \alpha < \frac{1}{\lambda_{\max}}. - - Katz centrality computes the relative influence of a node within a - network by measuring the number of the immediate neighbors (first - degree nodes) and also all other nodes in the network that connect - to the node under consideration through these immediate neighbors. - - Extra weight can be provided to immediate neighbors through the - parameter $\beta$. Connections made with distant neighbors - are, however, penalized by an attenuation factor $\alpha$ which - should be strictly less than the inverse largest eigenvalue of the - adjacency matrix in order for the Katz centrality to be computed - correctly. More information is provided in [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - alpha : float, optional (default=0.1) - Attenuation factor - - beta : scalar or dictionary, optional (default=1.0) - Weight attributed to the immediate neighborhood. If not a scalar, the - dictionary must have a value for every node. - - max_iter : integer, optional (default=1000) - Maximum number of iterations in power method. - - tol : float, optional (default=1.0e-6) - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of Katz iteration for each node. - - normalized : bool, optional (default=True) - If True normalize the resulting values. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - In this measure the weight is interpreted as the connection strength. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with Katz centrality as the value. - - Raises - ------ - NetworkXError - If the parameter `beta` is not a scalar but lacks a value for at least - one node - - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - Examples - -------- - >>> import math - >>> G = nx.path_graph(4) - >>> phi = (1 + math.sqrt(5)) / 2.0 # largest eigenvalue of adj matrix - >>> centrality = nx.katz_centrality(G, 1 / phi - 0.01) - >>> for n, c in sorted(centrality.items()): - ... print(f"{n} {c:.2f}") - 0 0.37 - 1 0.60 - 2 0.60 - 3 0.37 - - See Also - -------- - katz_centrality_numpy - eigenvector_centrality - eigenvector_centrality_numpy - :func:`~networkx.algorithms.link_analysis.pagerank_alg.pagerank` - :func:`~networkx.algorithms.link_analysis.hits_alg.hits` - - Notes - ----- - Katz centrality was introduced by [2]_. - - This algorithm it uses the power method to find the eigenvector - corresponding to the largest eigenvalue of the adjacency matrix of ``G``. - The parameter ``alpha`` should be strictly less than the inverse of largest - eigenvalue of the adjacency matrix for the algorithm to converge. - You can use ``max(nx.adjacency_spectrum(G))`` to get $\lambda_{\max}$ the largest - eigenvalue of the adjacency matrix. - The iteration will stop after ``max_iter`` iterations or an error tolerance of - ``number_of_nodes(G) * tol`` has been reached. - - For strongly connected graphs, as $\alpha \to 1/\lambda_{\max}$, and $\beta > 0$, - Katz centrality approaches the results for eigenvector centrality. - - For directed graphs this finds "left" eigenvectors which corresponds - to the in-edges in the graph. For out-edges Katz centrality, - first reverse the graph with ``G.reverse()``. - - References - ---------- - .. [1] Mark E. J. Newman: - Networks: An Introduction. - Oxford University Press, USA, 2010, p. 720. - .. [2] Leo Katz: - A New Status Index Derived from Sociometric Index. - Psychometrika 18(1):39–43, 1953 - https://link.springer.com/content/pdf/10.1007/BF02289026.pdf - """ - if len(G) == 0: - return {} - - nnodes = G.number_of_nodes() - - if nstart is None: - # choose starting vector with entries of 0 - x = {n: 0 for n in G} - else: - x = nstart - - try: - b = dict.fromkeys(G, float(beta)) - except (TypeError, ValueError, AttributeError) as err: - b = beta - if set(beta) != set(G): - raise nx.NetworkXError( - "beta dictionary must have a value for every node" - ) from err - - # make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = dict.fromkeys(xlast, 0) - # do the multiplication y^T = Alpha * x^T A + Beta - for n in x: - for nbr in G[n]: - x[nbr] += xlast[n] * G[n][nbr].get(weight, 1) - for n in x: - x[n] = alpha * x[n] + b[n] - - # check convergence - error = sum(abs(x[n] - xlast[n]) for n in x) - if error < nnodes * tol: - if normalized: - # normalize vector - try: - s = 1.0 / math.hypot(*x.values()) - except ZeroDivisionError: - s = 1.0 - else: - s = 1 - for n in x: - x[n] *= s - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def katz_centrality_numpy(G, alpha=0.1, beta=1.0, normalized=True, weight=None): - r"""Compute the Katz centrality for the graph G. - - Katz centrality computes the centrality for a node based on the centrality - of its neighbors. It is a generalization of the eigenvector centrality. The - Katz centrality for node $i$ is - - .. math:: - - x_i = \alpha \sum_{j} A_{ij} x_j + \beta, - - where $A$ is the adjacency matrix of graph G with eigenvalues $\lambda$. - - The parameter $\beta$ controls the initial centrality and - - .. math:: - - \alpha < \frac{1}{\lambda_{\max}}. - - Katz centrality computes the relative influence of a node within a - network by measuring the number of the immediate neighbors (first - degree nodes) and also all other nodes in the network that connect - to the node under consideration through these immediate neighbors. - - Extra weight can be provided to immediate neighbors through the - parameter $\beta$. Connections made with distant neighbors - are, however, penalized by an attenuation factor $\alpha$ which - should be strictly less than the inverse largest eigenvalue of the - adjacency matrix in order for the Katz centrality to be computed - correctly. More information is provided in [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - alpha : float - Attenuation factor - - beta : scalar or dictionary, optional (default=1.0) - Weight attributed to the immediate neighborhood. If not a scalar the - dictionary must have an value for every node. - - normalized : bool - If True normalize the resulting values. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - In this measure the weight is interpreted as the connection strength. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with Katz centrality as the value. - - Raises - ------ - NetworkXError - If the parameter `beta` is not a scalar but lacks a value for at least - one node - - Examples - -------- - >>> import math - >>> G = nx.path_graph(4) - >>> phi = (1 + math.sqrt(5)) / 2.0 # largest eigenvalue of adj matrix - >>> centrality = nx.katz_centrality_numpy(G, 1 / phi) - >>> for n, c in sorted(centrality.items()): - ... print(f"{n} {c:.2f}") - 0 0.37 - 1 0.60 - 2 0.60 - 3 0.37 - - See Also - -------- - katz_centrality - eigenvector_centrality_numpy - eigenvector_centrality - :func:`~networkx.algorithms.link_analysis.pagerank_alg.pagerank` - :func:`~networkx.algorithms.link_analysis.hits_alg.hits` - - Notes - ----- - Katz centrality was introduced by [2]_. - - This algorithm uses a direct linear solver to solve the above equation. - The parameter ``alpha`` should be strictly less than the inverse of largest - eigenvalue of the adjacency matrix for there to be a solution. - You can use ``max(nx.adjacency_spectrum(G))`` to get $\lambda_{\max}$ the largest - eigenvalue of the adjacency matrix. - - For strongly connected graphs, as $\alpha \to 1/\lambda_{\max}$, and $\beta > 0$, - Katz centrality approaches the results for eigenvector centrality. - - For directed graphs this finds "left" eigenvectors which corresponds - to the in-edges in the graph. For out-edges Katz centrality, - first reverse the graph with ``G.reverse()``. - - References - ---------- - .. [1] Mark E. J. Newman: - Networks: An Introduction. - Oxford University Press, USA, 2010, p. 173. - .. [2] Leo Katz: - A New Status Index Derived from Sociometric Index. - Psychometrika 18(1):39–43, 1953 - https://link.springer.com/content/pdf/10.1007/BF02289026.pdf - """ - import numpy as np - - if len(G) == 0: - return {} - try: - nodelist = beta.keys() - if set(nodelist) != set(G): - raise nx.NetworkXError("beta dictionary must have a value for every node") - b = np.array(list(beta.values()), dtype=float) - except AttributeError: - nodelist = list(G) - try: - b = np.ones((len(nodelist), 1)) * beta - except (TypeError, ValueError, AttributeError) as err: - raise nx.NetworkXError("beta must be a number") from err - - A = nx.adjacency_matrix(G, nodelist=nodelist, weight=weight).todense().T - n = A.shape[0] - centrality = np.linalg.solve(np.eye(n, n) - (alpha * A), b).squeeze() - - # Normalize: rely on truediv to cast to float, then tolist to make Python numbers - norm = np.sign(sum(centrality)) * np.linalg.norm(centrality) if normalized else 1 - return dict(zip(nodelist, (centrality / norm).tolist())) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/laplacian.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/laplacian.py deleted file mode 100644 index efb6e8f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/laplacian.py +++ /dev/null @@ -1,150 +0,0 @@ -""" -Laplacian centrality measures. -""" - -import networkx as nx - -__all__ = ["laplacian_centrality"] - - -@nx._dispatchable(edge_attrs="weight") -def laplacian_centrality( - G, normalized=True, nodelist=None, weight="weight", walk_type=None, alpha=0.95 -): - r"""Compute the Laplacian centrality for nodes in the graph `G`. - - The Laplacian Centrality of a node ``i`` is measured by the drop in the - Laplacian Energy after deleting node ``i`` from the graph. The Laplacian Energy - is the sum of the squared eigenvalues of a graph's Laplacian matrix. - - .. math:: - - C_L(u_i,G) = \frac{(\Delta E)_i}{E_L (G)} = \frac{E_L (G)-E_L (G_i)}{E_L (G)} - - E_L (G) = \sum_{i=0}^n \lambda_i^2 - - Where $E_L (G)$ is the Laplacian energy of graph `G`, - E_L (G_i) is the Laplacian energy of graph `G` after deleting node ``i`` - and $\lambda_i$ are the eigenvalues of `G`'s Laplacian matrix. - This formula shows the normalized value. Without normalization, - the numerator on the right side is returned. - - Parameters - ---------- - G : graph - A networkx graph - - normalized : bool (default = True) - If True the centrality score is scaled so the sum over all nodes is 1. - If False the centrality score for each node is the drop in Laplacian - energy when that node is removed. - - nodelist : list, optional (default = None) - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight: string or None, optional (default=`weight`) - Optional parameter `weight` to compute the Laplacian matrix. - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - Optional parameter `walk_type` used when calling - :func:`directed_laplacian_matrix `. - One of ``"random"``, ``"lazy"``, or ``"pagerank"``. If ``walk_type=None`` - (the default), then a value is selected according to the properties of `G`: - - ``walk_type="random"`` if `G` is strongly connected and aperiodic - - ``walk_type="lazy"`` if `G` is strongly connected but not aperiodic - - ``walk_type="pagerank"`` for all other cases. - - alpha : real (default = 0.95) - Optional parameter `alpha` used when calling - :func:`directed_laplacian_matrix `. - (1 - alpha) is the teleportation probability used with pagerank. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with Laplacian centrality as the value. - - Examples - -------- - >>> G = nx.Graph() - >>> edges = [(0, 1, 4), (0, 2, 2), (2, 1, 1), (1, 3, 2), (1, 4, 2), (4, 5, 1)] - >>> G.add_weighted_edges_from(edges) - >>> sorted((v, f"{c:0.2f}") for v, c in laplacian_centrality(G).items()) - [(0, '0.70'), (1, '0.90'), (2, '0.28'), (3, '0.22'), (4, '0.26'), (5, '0.04')] - - Notes - ----- - The algorithm is implemented based on [1]_ with an extension to directed graphs - using the ``directed_laplacian_matrix`` function. - - Raises - ------ - NetworkXPointlessConcept - If the graph `G` is the null graph. - ZeroDivisionError - If the graph `G` has no edges (is empty) and normalization is requested. - - References - ---------- - .. [1] Qi, X., Fuller, E., Wu, Q., Wu, Y., and Zhang, C.-Q. (2012). - Laplacian centrality: A new centrality measure for weighted networks. - Information Sciences, 194:240-253. - https://math.wvu.edu/~cqzhang/Publication-files/my-paper/INS-2012-Laplacian-W.pdf - - See Also - -------- - :func:`~networkx.linalg.laplacianmatrix.directed_laplacian_matrix` - :func:`~networkx.linalg.laplacianmatrix.laplacian_matrix` - """ - import numpy as np - import scipy as sp - - if len(G) == 0: - raise nx.NetworkXPointlessConcept("null graph has no centrality defined") - if G.size(weight=weight) == 0: - if normalized: - raise ZeroDivisionError("graph with no edges has zero full energy") - return {n: 0 for n in G} - - if nodelist is not None: - nodeset = set(G.nbunch_iter(nodelist)) - if len(nodeset) != len(nodelist): - raise nx.NetworkXError("nodelist has duplicate nodes or nodes not in G") - nodes = nodelist + [n for n in G if n not in nodeset] - else: - nodelist = nodes = list(G) - - if G.is_directed(): - lap_matrix = nx.directed_laplacian_matrix(G, nodes, weight, walk_type, alpha) - else: - lap_matrix = nx.laplacian_matrix(G, nodes, weight).toarray() - - full_energy = np.power(sp.linalg.eigh(lap_matrix, eigvals_only=True), 2).sum() - - # calculate laplacian centrality - laplace_centralities_dict = {} - for i, node in enumerate(nodelist): - # remove row and col i from lap_matrix - all_but_i = list(np.arange(lap_matrix.shape[0])) - all_but_i.remove(i) - A_2 = lap_matrix[all_but_i, :][:, all_but_i] - - # Adjust diagonal for removed row - new_diag = lap_matrix.diagonal() - abs(lap_matrix[:, i]) - np.fill_diagonal(A_2, new_diag[all_but_i]) - - if len(all_but_i) > 0: # catches degenerate case of single node - new_energy = np.power(sp.linalg.eigh(A_2, eigvals_only=True), 2).sum() - else: - new_energy = 0.0 - - lapl_cent = full_energy - new_energy - if normalized: - lapl_cent = lapl_cent / full_energy - - laplace_centralities_dict[node] = float(lapl_cent) - - return laplace_centralities_dict diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/load.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/load.py deleted file mode 100644 index fc46edd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/load.py +++ /dev/null @@ -1,200 +0,0 @@ -"""Load centrality.""" - -from operator import itemgetter - -import networkx as nx - -__all__ = ["load_centrality", "edge_load_centrality"] - - -@nx._dispatchable(edge_attrs="weight") -def newman_betweenness_centrality(G, v=None, cutoff=None, normalized=True, weight=None): - """Compute load centrality for nodes. - - The load centrality of a node is the fraction of all shortest - paths that pass through that node. - - Parameters - ---------- - G : graph - A networkx graph. - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, edge weights are ignored. - Otherwise holds the name of the edge attribute used as weight. - The weight of an edge is treated as the length or distance between the two sides. - - cutoff : bool, optional (default=None) - If specified, only consider paths of length <= cutoff. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with centrality as the value. - - See Also - -------- - betweenness_centrality - - Notes - ----- - Load centrality is slightly different than betweenness. It was originally - introduced by [2]_. For this load algorithm see [1]_. - - References - ---------- - .. [1] Mark E. J. Newman: - Scientific collaboration networks. II. - Shortest paths, weighted networks, and centrality. - Physical Review E 64, 016132, 2001. - http://journals.aps.org/pre/abstract/10.1103/PhysRevE.64.016132 - .. [2] Kwang-Il Goh, Byungnam Kahng and Doochul Kim - Universal behavior of Load Distribution in Scale-Free Networks. - Physical Review Letters 87(27):1–4, 2001. - https://doi.org/10.1103/PhysRevLett.87.278701 - """ - if v is not None: # only one node - betweenness = 0.0 - for source in G: - ubetween = _node_betweenness(G, source, cutoff, False, weight) - betweenness += ubetween[v] if v in ubetween else 0 - if normalized: - order = G.order() - if order <= 2: - return betweenness # no normalization b=0 for all nodes - betweenness *= 1.0 / ((order - 1) * (order - 2)) - else: - betweenness = {}.fromkeys(G, 0.0) - for source in betweenness: - ubetween = _node_betweenness(G, source, cutoff, False, weight) - for vk in ubetween: - betweenness[vk] += ubetween[vk] - if normalized: - order = G.order() - if order <= 2: - return betweenness # no normalization b=0 for all nodes - scale = 1.0 / ((order - 1) * (order - 2)) - for v in betweenness: - betweenness[v] *= scale - return betweenness # all nodes - - -def _node_betweenness(G, source, cutoff=False, normalized=True, weight=None): - """Node betweenness_centrality helper: - - See betweenness_centrality for what you probably want. - This actually computes "load" and not betweenness. - See https://networkx.lanl.gov/ticket/103 - - This calculates the load of each node for paths from a single source. - (The fraction of number of shortests paths from source that go - through each node.) - - To get the load for a node you need to do all-pairs shortest paths. - - If weight is not None then use Dijkstra for finding shortest paths. - """ - # get the predecessor and path length data - if weight is None: - (pred, length) = nx.predecessor(G, source, cutoff=cutoff, return_seen=True) - else: - (pred, length) = nx.dijkstra_predecessor_and_distance(G, source, cutoff, weight) - - # order the nodes by path length - onodes = [(l, vert) for (vert, l) in length.items()] - onodes.sort() - onodes[:] = [vert for (l, vert) in onodes if l > 0] - - # initialize betweenness - between = {}.fromkeys(length, 1.0) - - while onodes: - v = onodes.pop() - if v in pred: - num_paths = len(pred[v]) # Discount betweenness if more than - for x in pred[v]: # one shortest path. - if x == source: # stop if hit source because all remaining v - break # also have pred[v]==[source] - between[x] += between[v] / num_paths - # remove source - for v in between: - between[v] -= 1 - # rescale to be between 0 and 1 - if normalized: - l = len(between) - if l > 2: - # scale by 1/the number of possible paths - scale = 1 / ((l - 1) * (l - 2)) - for v in between: - between[v] *= scale - return between - - -load_centrality = newman_betweenness_centrality - - -@nx._dispatchable -def edge_load_centrality(G, cutoff=False): - """Compute edge load. - - WARNING: This concept of edge load has not been analysed - or discussed outside of NetworkX that we know of. - It is based loosely on load_centrality in the sense that - it counts the number of shortest paths which cross each edge. - This function is for demonstration and testing purposes. - - Parameters - ---------- - G : graph - A networkx graph - - cutoff : bool, optional (default=False) - If specified, only consider paths of length <= cutoff. - - Returns - ------- - A dict keyed by edge 2-tuple to the number of shortest paths - which use that edge. Where more than one path is shortest - the count is divided equally among paths. - """ - betweenness = {} - for u, v in G.edges(): - betweenness[(u, v)] = 0.0 - betweenness[(v, u)] = 0.0 - - for source in G: - ubetween = _edge_betweenness(G, source, cutoff=cutoff) - for e, ubetweenv in ubetween.items(): - betweenness[e] += ubetweenv # cumulative total - return betweenness - - -def _edge_betweenness(G, source, nodes=None, cutoff=False): - """Edge betweenness helper.""" - # get the predecessor data - (pred, length) = nx.predecessor(G, source, cutoff=cutoff, return_seen=True) - # order the nodes by path length - onodes = [n for n, d in sorted(length.items(), key=itemgetter(1))] - # initialize betweenness, doesn't account for any edge weights - between = {} - for u, v in G.edges(nodes): - between[(u, v)] = 1.0 - between[(v, u)] = 1.0 - - while onodes: # work through all paths - v = onodes.pop() - if v in pred: - # Discount betweenness if more than one shortest path. - num_paths = len(pred[v]) - for w in pred[v]: - if w in pred: - # Discount betweenness, mult path - num_paths = len(pred[w]) - for x in pred[w]: - between[(w, x)] += between[(v, w)] / num_paths - between[(x, w)] += between[(w, v)] / num_paths - return between diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/percolation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/percolation.py deleted file mode 100644 index 0d4c871..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/percolation.py +++ /dev/null @@ -1,128 +0,0 @@ -"""Percolation centrality measures.""" - -import networkx as nx -from networkx.algorithms.centrality.betweenness import ( - _single_source_dijkstra_path_basic as dijkstra, -) -from networkx.algorithms.centrality.betweenness import ( - _single_source_shortest_path_basic as shortest_path, -) - -__all__ = ["percolation_centrality"] - - -@nx._dispatchable(node_attrs="attribute", edge_attrs="weight") -def percolation_centrality(G, attribute="percolation", states=None, weight=None): - r"""Compute the percolation centrality for nodes. - - Percolation centrality of a node $v$, at a given time, is defined - as the proportion of ‘percolated paths’ that go through that node. - - This measure quantifies relative impact of nodes based on their - topological connectivity, as well as their percolation states. - - Percolation states of nodes are used to depict network percolation - scenarios (such as during infection transmission in a social network - of individuals, spreading of computer viruses on computer networks, or - transmission of disease over a network of towns) over time. In this - measure usually the percolation state is expressed as a decimal - between 0.0 and 1.0. - - When all nodes are in the same percolated state this measure is - equivalent to betweenness centrality. - - Parameters - ---------- - G : graph - A NetworkX graph. - - attribute : None or string, optional (default='percolation') - Name of the node attribute to use for percolation state, used - if `states` is None. If a node does not set the attribute the - state of that node will be set to the default value of 1. - If all nodes do not have the attribute all nodes will be set to - 1 and the centrality measure will be equivalent to betweenness centrality. - - states : None or dict, optional (default=None) - Specify percolation states for the nodes, nodes as keys states - as values. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - The weight of an edge is treated as the length or distance between the two sides. - - - Returns - ------- - nodes : dictionary - Dictionary of nodes with percolation centrality as the value. - - See Also - -------- - betweenness_centrality - - Notes - ----- - The algorithm is from Mahendra Piraveenan, Mikhail Prokopenko, and - Liaquat Hossain [1]_ - Pair dependencies are calculated and accumulated using [2]_ - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - References - ---------- - .. [1] Mahendra Piraveenan, Mikhail Prokopenko, Liaquat Hossain - Percolation Centrality: Quantifying Graph-Theoretic Impact of Nodes - during Percolation in Networks - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0053095 - .. [2] Ulrik Brandes: - A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - https://doi.org/10.1080/0022250X.2001.9990249 - """ - percolation = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - - nodes = G - - if states is None: - states = nx.get_node_attributes(nodes, attribute, default=1) - - # sum of all percolation states - p_sigma_x_t = 0.0 - for v in states.values(): - p_sigma_x_t += v - - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma, _ = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma, _ = dijkstra(G, s, weight) - # accumulation - percolation = _accumulate_percolation( - percolation, S, P, sigma, s, states, p_sigma_x_t - ) - - n = len(G) - - for v in percolation: - percolation[v] *= 1 / (n - 2) - - return percolation - - -def _accumulate_percolation(percolation, S, P, sigma, s, states, p_sigma_x_t): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - # percolation weight - pw_s_w = states[s] / (p_sigma_x_t - states[w]) - percolation[w] += delta[w] * pw_s_w - return percolation diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/reaching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/reaching.py deleted file mode 100644 index 378e8a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/reaching.py +++ /dev/null @@ -1,209 +0,0 @@ -"""Functions for computing reaching centrality of a node or a graph.""" - -import networkx as nx -from networkx.utils import pairwise - -__all__ = ["global_reaching_centrality", "local_reaching_centrality"] - - -def _average_weight(G, path, weight=None): - """Returns the average weight of an edge in a weighted path. - - Parameters - ---------- - G : graph - A networkx graph. - - path: list - A list of vertices that define the path. - - weight : None or string, optional (default=None) - If None, edge weights are ignored. Then the average weight of an edge - is assumed to be the multiplicative inverse of the length of the path. - Otherwise holds the name of the edge attribute used as weight. - """ - path_length = len(path) - 1 - if path_length <= 0: - return 0 - if weight is None: - return 1 / path_length - total_weight = sum(G.edges[i, j][weight] for i, j in pairwise(path)) - return total_weight / path_length - - -@nx._dispatchable(edge_attrs="weight") -def global_reaching_centrality(G, weight=None, normalized=True): - """Returns the global reaching centrality of a directed graph. - - The *global reaching centrality* of a weighted directed graph is the - average over all nodes of the difference between the local reaching - centrality of the node and the greatest local reaching centrality of - any node in the graph [1]_. For more information on the local - reaching centrality, see :func:`local_reaching_centrality`. - Informally, the local reaching centrality is the proportion of the - graph that is reachable from the neighbors of the node. - - Parameters - ---------- - G : DiGraph - A networkx DiGraph. - - weight : None or string, optional (default=None) - Attribute to use for edge weights. If ``None``, each edge weight - is assumed to be one. A higher weight implies a stronger - connection between nodes and a *shorter* path length. - - normalized : bool, optional (default=True) - Whether to normalize the edge weights by the total sum of edge - weights. - - Returns - ------- - h : float - The global reaching centrality of the graph. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2) - >>> G.add_edge(1, 3) - >>> nx.global_reaching_centrality(G) - 1.0 - >>> G.add_edge(3, 2) - >>> nx.global_reaching_centrality(G) - 0.75 - - See also - -------- - local_reaching_centrality - - References - ---------- - .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. - "Hierarchy Measure for Complex Networks." - *PLoS ONE* 7.3 (2012): e33799. - https://doi.org/10.1371/journal.pone.0033799 - """ - if nx.is_negatively_weighted(G, weight=weight): - raise nx.NetworkXError("edge weights must be positive") - total_weight = G.size(weight=weight) - if total_weight <= 0: - raise nx.NetworkXError("Size of G must be positive") - # If provided, weights must be interpreted as connection strength - # (so higher weights are more likely to be chosen). However, the - # shortest path algorithms in NetworkX assume the provided "weight" - # is actually a distance (so edges with higher weight are less - # likely to be chosen). Therefore we need to invert the weights when - # computing shortest paths. - # - # If weight is None, we leave it as-is so that the shortest path - # algorithm can use a faster, unweighted algorithm. - if weight is not None: - - def as_distance(u, v, d): - return total_weight / d.get(weight, 1) - - shortest_paths = nx.shortest_path(G, weight=as_distance) - else: - shortest_paths = nx.shortest_path(G) - - centrality = local_reaching_centrality - # TODO This can be trivially parallelized. - lrc = [ - centrality(G, node, paths=paths, weight=weight, normalized=normalized) - for node, paths in shortest_paths.items() - ] - - max_lrc = max(lrc) - return sum(max_lrc - c for c in lrc) / (len(G) - 1) - - -@nx._dispatchable(edge_attrs="weight") -def local_reaching_centrality(G, v, paths=None, weight=None, normalized=True): - """Returns the local reaching centrality of a node in a directed - graph. - - The *local reaching centrality* of a node in a directed graph is the - proportion of other nodes reachable from that node [1]_. - - Parameters - ---------- - G : DiGraph - A NetworkX DiGraph. - - v : node - A node in the directed graph `G`. - - paths : dictionary (default=None) - If this is not `None` it must be a dictionary representation - of single-source shortest paths, as computed by, for example, - :func:`networkx.shortest_path` with source node `v`. Use this - keyword argument if you intend to invoke this function many - times but don't want the paths to be recomputed each time. - - weight : None or string, optional (default=None) - Attribute to use for edge weights. If `None`, each edge weight - is assumed to be one. A higher weight implies a stronger - connection between nodes and a *shorter* path length. - - normalized : bool, optional (default=True) - Whether to normalize the edge weights by the total sum of edge - weights. - - Returns - ------- - h : float - The local reaching centrality of the node ``v`` in the graph - ``G``. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2), (1, 3)]) - >>> nx.local_reaching_centrality(G, 3) - 0.0 - >>> G.add_edge(3, 2) - >>> nx.local_reaching_centrality(G, 3) - 0.5 - - See also - -------- - global_reaching_centrality - - References - ---------- - .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. - "Hierarchy Measure for Complex Networks." - *PLoS ONE* 7.3 (2012): e33799. - https://doi.org/10.1371/journal.pone.0033799 - """ - # Corner case: graph with single node containing a self-loop - if (total_weight := G.size(weight=weight)) > 0 and len(G) == 1: - raise nx.NetworkXError( - "local_reaching_centrality of a single node with self-loop not well-defined" - ) - if paths is None: - if nx.is_negatively_weighted(G, weight=weight): - raise nx.NetworkXError("edge weights must be positive") - if total_weight <= 0: - raise nx.NetworkXError("Size of G must be positive") - if weight is not None: - # Interpret weights as lengths. - def as_distance(u, v, d): - return total_weight / d.get(weight, 1) - - paths = nx.shortest_path(G, source=v, weight=as_distance) - else: - paths = nx.shortest_path(G, source=v) - # If the graph is unweighted, simply return the proportion of nodes - # reachable from the source node ``v``. - if weight is None and G.is_directed(): - return (len(paths) - 1) / (len(G) - 1) - if normalized and weight is not None: - norm = G.size(weight=weight) / G.size() - else: - norm = 1 - # TODO This can be trivially parallelized. - avgw = (_average_weight(G, path, weight=weight) for path in paths.values()) - sum_avg_weight = sum(avgw) / norm - return sum_avg_weight / (len(G) - 1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/second_order.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/second_order.py deleted file mode 100644 index 35583cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/second_order.py +++ /dev/null @@ -1,141 +0,0 @@ -"""Copyright (c) 2015 – Thomson Licensing, SAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted (subject to the limitations in the -disclaimer below) provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of Thomson Licensing, or Technicolor, nor the names -of its contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE -GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT -HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -# Authors: Erwan Le Merrer (erwan.lemerrer@technicolor.com) - -__all__ = ["second_order_centrality"] - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def second_order_centrality(G, weight="weight"): - """Compute the second order centrality for nodes of G. - - The second order centrality of a given node is the standard deviation of - the return times to that node of a perpetual random walk on G: - - Parameters - ---------- - G : graph - A NetworkX connected and undirected graph. - - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - - Returns - ------- - nodes : dictionary - Dictionary keyed by node with second order centrality as the value. - - Examples - -------- - >>> G = nx.star_graph(10) - >>> soc = nx.second_order_centrality(G) - >>> print(sorted(soc.items(), key=lambda x: x[1])[0][0]) # pick first id - 0 - - Raises - ------ - NetworkXException - If the graph G is empty, non connected or has negative weights. - - See Also - -------- - betweenness_centrality - - Notes - ----- - Lower values of second order centrality indicate higher centrality. - - The algorithm is from Kermarrec, Le Merrer, Sericola and Trédan [1]_. - - This code implements the analytical version of the algorithm, i.e., - there is no simulation of a random walk process involved. The random walk - is here unbiased (corresponding to eq 6 of the paper [1]_), thus the - centrality values are the standard deviations for random walk return times - on the transformed input graph G (equal in-degree at each nodes by adding - self-loops). - - Complexity of this implementation, made to run locally on a single machine, - is O(n^3), with n the size of G, which makes it viable only for small - graphs. - - References - ---------- - .. [1] Anne-Marie Kermarrec, Erwan Le Merrer, Bruno Sericola, Gilles Trédan - "Second order centrality: Distributed assessment of nodes criticity in - complex networks", Elsevier Computer Communications 34(5):619-628, 2011. - """ - import numpy as np - - n = len(G) - - if n == 0: - raise nx.NetworkXException("Empty graph.") - if not nx.is_connected(G): - raise nx.NetworkXException("Non connected graph.") - if any(d.get(weight, 0) < 0 for u, v, d in G.edges(data=True)): - raise nx.NetworkXException("Graph has negative edge weights.") - - # balancing G for Metropolis-Hastings random walks - G = nx.DiGraph(G) - in_deg = dict(G.in_degree(weight=weight)) - d_max = max(in_deg.values()) - for i, deg in in_deg.items(): - if deg < d_max: - G.add_edge(i, i, weight=d_max - deg) - - P = nx.to_numpy_array(G) - P /= P.sum(axis=1)[:, np.newaxis] # to transition probability matrix - - def _Qj(P, j): - P = P.copy() - P[:, j] = 0 - return P - - M = np.empty([n, n]) - - for i in range(n): - M[:, i] = np.linalg.solve( - np.identity(n) - _Qj(P, i), np.ones([n, 1])[:, 0] - ) # eq 3 - - return dict( - zip( - G.nodes, - (float(np.sqrt(2 * np.sum(M[:, i]) - n * (n + 1))) for i in range(n)), - ) - ) # eq 6 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/subgraph_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/subgraph_alg.py deleted file mode 100644 index 0a49e6f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/subgraph_alg.py +++ /dev/null @@ -1,340 +0,0 @@ -""" -Subraph centrality and communicability betweenness. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "subgraph_centrality_exp", - "subgraph_centrality", - "communicability_betweenness_centrality", - "estrada_index", -] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def subgraph_centrality_exp(G): - r"""Returns the subgraph centrality for each node of G. - - Subgraph centrality of a node `n` is the sum of weighted closed - walks of all lengths starting and ending at node `n`. The weights - decrease with path length. Each closed walk is associated with a - connected subgraph ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - nodes:dictionary - Dictionary of nodes with subgraph centrality as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - subgraph_centrality: - Alternative algorithm of the subgraph centrality for each node of G. - - Notes - ----- - This version of the algorithm exponentiates the adjacency matrix. - - The subgraph centrality of a node `u` in G can be found using - the matrix exponential of the adjacency matrix of G [1]_, - - .. math:: - - SC(u)=(e^A)_{uu} . - - References - ---------- - .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, - "Subgraph centrality in complex networks", - Physical Review E 71, 056103 (2005). - https://arxiv.org/abs/cond-mat/0504730 - - Examples - -------- - (Example from [1]_) - >>> G = nx.Graph( - ... [ - ... (1, 2), - ... (1, 5), - ... (1, 8), - ... (2, 3), - ... (2, 8), - ... (3, 4), - ... (3, 6), - ... (4, 5), - ... (4, 7), - ... (5, 6), - ... (6, 7), - ... (7, 8), - ... ] - ... ) - >>> sc = nx.subgraph_centrality_exp(G) - >>> print([f"{node} {sc[node]:0.2f}" for node in sorted(sc)]) - ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] - """ - # alternative implementation that calculates the matrix exponential - import scipy as sp - - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - expA = sp.linalg.expm(A) - # convert diagonal to dictionary keyed by node - sc = dict(zip(nodelist, map(float, expA.diagonal()))) - return sc - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def subgraph_centrality(G): - r"""Returns subgraph centrality for each node in G. - - Subgraph centrality of a node `n` is the sum of weighted closed - walks of all lengths starting and ending at node `n`. The weights - decrease with path length. Each closed walk is associated with a - connected subgraph ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with subgraph centrality as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - subgraph_centrality_exp: - Alternative algorithm of the subgraph centrality for each node of G. - - Notes - ----- - This version of the algorithm computes eigenvalues and eigenvectors - of the adjacency matrix. - - Subgraph centrality of a node `u` in G can be found using - a spectral decomposition of the adjacency matrix [1]_, - - .. math:: - - SC(u)=\sum_{j=1}^{N}(v_{j}^{u})^2 e^{\lambda_{j}}, - - where `v_j` is an eigenvector of the adjacency matrix `A` of G - corresponding to the eigenvalue `\lambda_j`. - - Examples - -------- - (Example from [1]_) - >>> G = nx.Graph( - ... [ - ... (1, 2), - ... (1, 5), - ... (1, 8), - ... (2, 3), - ... (2, 8), - ... (3, 4), - ... (3, 6), - ... (4, 5), - ... (4, 7), - ... (5, 6), - ... (6, 7), - ... (7, 8), - ... ] - ... ) - >>> sc = nx.subgraph_centrality(G) - >>> print([f"{node} {sc[node]:0.2f}" for node in sorted(sc)]) - ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] - - References - ---------- - .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, - "Subgraph centrality in complex networks", - Physical Review E 71, 056103 (2005). - https://arxiv.org/abs/cond-mat/0504730 - - """ - import numpy as np - - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[np.nonzero(A)] = 1 - w, v = np.linalg.eigh(A) - vsquare = np.array(v) ** 2 - expw = np.exp(w) - xg = vsquare @ expw - # convert vector dictionary keyed by node - sc = dict(zip(nodelist, map(float, xg))) - return sc - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def communicability_betweenness_centrality(G): - r"""Returns subgraph communicability for all pairs of nodes in G. - - Communicability betweenness measure makes use of the number of walks - connecting every pair of nodes as the basis of a betweenness centrality - measure. - - Parameters - ---------- - G: graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with communicability betweenness as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - Notes - ----- - Let `G=(V,E)` be a simple undirected graph with `n` nodes and `m` edges, - and `A` denote the adjacency matrix of `G`. - - Let `G(r)=(V,E(r))` be the graph resulting from - removing all edges connected to node `r` but not the node itself. - - The adjacency matrix for `G(r)` is `A+E(r)`, where `E(r)` has nonzeros - only in row and column `r`. - - The subraph betweenness of a node `r` is [1]_ - - .. math:: - - \omega_{r} = \frac{1}{C}\sum_{p}\sum_{q}\frac{G_{prq}}{G_{pq}}, - p\neq q, q\neq r, - - where - `G_{prq}=(e^{A}_{pq} - (e^{A+E(r)})_{pq}` is the number of walks - involving node r, - `G_{pq}=(e^{A})_{pq}` is the number of closed walks starting - at node `p` and ending at node `q`, - and `C=(n-1)^{2}-(n-1)` is a normalization factor equal to the - number of terms in the sum. - - The resulting `\omega_{r}` takes values between zero and one. - The lower bound cannot be attained for a connected - graph, and the upper bound is attained in the star graph. - - References - ---------- - .. [1] Ernesto Estrada, Desmond J. Higham, Naomichi Hatano, - "Communicability Betweenness in Complex Networks" - Physica A 388 (2009) 764-774. - https://arxiv.org/abs/0905.4102 - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) - >>> cbc = nx.communicability_betweenness_centrality(G) - >>> print([f"{node} {cbc[node]:0.2f}" for node in sorted(cbc)]) - ['0 0.03', '1 0.45', '2 0.51', '3 0.45', '4 0.40', '5 0.19', '6 0.03'] - """ - import numpy as np - import scipy as sp - - nodelist = list(G) # ordering of nodes in matrix - n = len(nodelist) - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[np.nonzero(A)] = 1 - expA = sp.linalg.expm(A) - mapping = dict(zip(nodelist, range(n))) - cbc = {} - for v in G: - # remove row and col of node v - i = mapping[v] - row = A[i, :].copy() - col = A[:, i].copy() - A[i, :] = 0 - A[:, i] = 0 - B = (expA - sp.linalg.expm(A)) / expA - # sum with row/col of node v and diag set to zero - B[i, :] = 0 - B[:, i] = 0 - B -= np.diag(np.diag(B)) - cbc[v] = float(B.sum()) - # put row and col back - A[i, :] = row - A[:, i] = col - # rescale when more than two nodes - order = len(cbc) - if order > 2: - scale = 1.0 / ((order - 1.0) ** 2 - (order - 1.0)) - cbc = {node: value * scale for node, value in cbc.items()} - return cbc - - -@nx._dispatchable -def estrada_index(G): - r"""Returns the Estrada index of a the graph G. - - The Estrada Index is a topological index of folding or 3D "compactness" ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - estrada index: float - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - Notes - ----- - Let `G=(V,E)` be a simple undirected graph with `n` nodes and let - `\lambda_{1}\leq\lambda_{2}\leq\cdots\lambda_{n}` - be a non-increasing ordering of the eigenvalues of its adjacency - matrix `A`. The Estrada index is ([1]_, [2]_) - - .. math:: - EE(G)=\sum_{j=1}^n e^{\lambda _j}. - - References - ---------- - .. [1] E. Estrada, "Characterization of 3D molecular structure", - Chem. Phys. Lett. 319, 713 (2000). - https://doi.org/10.1016/S0009-2614(00)00158-5 - .. [2] José Antonio de la Peñaa, Ivan Gutman, Juan Rada, - "Estimating the Estrada index", - Linear Algebra and its Applications. 427, 1 (2007). - https://doi.org/10.1016/j.laa.2007.06.020 - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) - >>> ei = nx.estrada_index(G) - >>> print(f"{ei:0.5}") - 20.55 - """ - return sum(subgraph_centrality(G).values()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality.py deleted file mode 100644 index 4c059cf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +++ /dev/null @@ -1,780 +0,0 @@ -import pytest - -import networkx as nx - - -def weighted_G(): - G = nx.Graph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - return G - - -class TestBetweennessCentrality: - def test_K5(self): - """Betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, weight=None, normalized=False) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_K5_endpoints(self): - """Betweenness centrality: K5 endpoints""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, weight=None, normalized=False, endpoints=True) - b_answer = {0: 4.0, 1: 4.0, 2: 4.0, 3: 4.0, 4: 4.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - # normalized = True case - b = nx.betweenness_centrality(G, weight=None, normalized=True, endpoints=True) - b_answer = {0: 0.4, 1: 0.4, 2: 0.4, 3: 0.4, 4: 0.4} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P3_normalized(self): - """Betweenness centrality: P3 normalized""" - G = nx.path_graph(3) - b = nx.betweenness_centrality(G, weight=None, normalized=True) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P3(self): - """Betweenness centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, weight=None, normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_sample_from_P3(self): - """Betweenness centrality: P3 sample""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, k=3, weight=None, normalized=False, seed=1) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - b = nx.betweenness_centrality(G, k=2, weight=None, normalized=False, seed=1) - # python versions give different results with same seed - b_approx1 = {0: 0.0, 1: 1.5, 2: 0.0} - b_approx2 = {0: 0.0, 1: 0.75, 2: 0.0} - for n in sorted(G): - assert b[n] in (b_approx1[n], b_approx2[n]) - - def test_P3_endpoints(self): - """Betweenness centrality: P3 endpoints""" - G = nx.path_graph(3) - b_answer = {0: 2.0, 1: 3.0, 2: 2.0} - b = nx.betweenness_centrality(G, weight=None, normalized=False, endpoints=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - # normalized = True case - b_answer = {0: 2 / 3, 1: 1.0, 2: 2 / 3} - b = nx.betweenness_centrality(G, weight=None, normalized=True, endpoints=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_krackhardt_kite_graph(self): - """Betweenness centrality: Krackhardt kite graph""" - G = nx.krackhardt_kite_graph() - b_answer = { - 0: 1.667, - 1: 1.667, - 2: 0.000, - 3: 7.333, - 4: 0.000, - 5: 16.667, - 6: 16.667, - 7: 28.000, - 8: 16.000, - 9: 0.000, - } - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, weight=None, normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_krackhardt_kite_graph_normalized(self): - """Betweenness centrality: Krackhardt kite graph normalized""" - G = nx.krackhardt_kite_graph() - b_answer = { - 0: 0.023, - 1: 0.023, - 2: 0.000, - 3: 0.102, - 4: 0.000, - 5: 0.231, - 6: 0.231, - 7: 0.389, - 8: 0.222, - 9: 0.000, - } - b = nx.betweenness_centrality(G, weight=None, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_florentine_families_graph(self): - """Betweenness centrality: Florentine families graph""" - G = nx.florentine_families_graph() - b_answer = { - "Acciaiuoli": 0.000, - "Albizzi": 0.212, - "Barbadori": 0.093, - "Bischeri": 0.104, - "Castellani": 0.055, - "Ginori": 0.000, - "Guadagni": 0.255, - "Lamberteschi": 0.000, - "Medici": 0.522, - "Pazzi": 0.000, - "Peruzzi": 0.022, - "Ridolfi": 0.114, - "Salviati": 0.143, - "Strozzi": 0.103, - "Tornabuoni": 0.092, - } - - b = nx.betweenness_centrality(G, weight=None, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_les_miserables_graph(self): - """Betweenness centrality: Les Miserables graph""" - G = nx.les_miserables_graph() - b_answer = { - "Napoleon": 0.000, - "Myriel": 0.177, - "MlleBaptistine": 0.000, - "MmeMagloire": 0.000, - "CountessDeLo": 0.000, - "Geborand": 0.000, - "Champtercier": 0.000, - "Cravatte": 0.000, - "Count": 0.000, - "OldMan": 0.000, - "Valjean": 0.570, - "Labarre": 0.000, - "Marguerite": 0.000, - "MmeDeR": 0.000, - "Isabeau": 0.000, - "Gervais": 0.000, - "Listolier": 0.000, - "Tholomyes": 0.041, - "Fameuil": 0.000, - "Blacheville": 0.000, - "Favourite": 0.000, - "Dahlia": 0.000, - "Zephine": 0.000, - "Fantine": 0.130, - "MmeThenardier": 0.029, - "Thenardier": 0.075, - "Cosette": 0.024, - "Javert": 0.054, - "Fauchelevent": 0.026, - "Bamatabois": 0.008, - "Perpetue": 0.000, - "Simplice": 0.009, - "Scaufflaire": 0.000, - "Woman1": 0.000, - "Judge": 0.000, - "Champmathieu": 0.000, - "Brevet": 0.000, - "Chenildieu": 0.000, - "Cochepaille": 0.000, - "Pontmercy": 0.007, - "Boulatruelle": 0.000, - "Eponine": 0.011, - "Anzelma": 0.000, - "Woman2": 0.000, - "MotherInnocent": 0.000, - "Gribier": 0.000, - "MmeBurgon": 0.026, - "Jondrette": 0.000, - "Gavroche": 0.165, - "Gillenormand": 0.020, - "Magnon": 0.000, - "MlleGillenormand": 0.048, - "MmePontmercy": 0.000, - "MlleVaubois": 0.000, - "LtGillenormand": 0.000, - "Marius": 0.132, - "BaronessT": 0.000, - "Mabeuf": 0.028, - "Enjolras": 0.043, - "Combeferre": 0.001, - "Prouvaire": 0.000, - "Feuilly": 0.001, - "Courfeyrac": 0.005, - "Bahorel": 0.002, - "Bossuet": 0.031, - "Joly": 0.002, - "Grantaire": 0.000, - "MotherPlutarch": 0.000, - "Gueulemer": 0.005, - "Babet": 0.005, - "Claquesous": 0.005, - "Montparnasse": 0.004, - "Toussaint": 0.000, - "Child1": 0.000, - "Child2": 0.000, - "Brujon": 0.000, - "MmeHucheloup": 0.000, - } - - b = nx.betweenness_centrality(G, weight=None, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_ladder_graph(self): - """Betweenness centrality: Ladder graph""" - G = nx.Graph() # ladder_graph(3) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - b_answer = {0: 1.667, 1: 1.667, 2: 6.667, 3: 6.667, 4: 1.667, 5: 1.667} - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, weight=None, normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_disconnected_path(self): - """Betweenness centrality: disconnected path""" - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5, 6]) - b_answer = {0: 0, 1: 1, 2: 0, 3: 0, 4: 2, 5: 2, 6: 0} - b = nx.betweenness_centrality(G, weight=None, normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_disconnected_path_endpoints(self): - """Betweenness centrality: disconnected path endpoints""" - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5, 6]) - b_answer = {0: 2, 1: 3, 2: 2, 3: 3, 4: 5, 5: 5, 6: 3} - b = nx.betweenness_centrality(G, weight=None, normalized=False, endpoints=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - # normalized = True case - b = nx.betweenness_centrality(G, weight=None, normalized=True, endpoints=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n] / 21, abs=1e-7) - - def test_directed_path(self): - """Betweenness centrality: directed path""" - G = nx.DiGraph() - nx.add_path(G, [0, 1, 2]) - b = nx.betweenness_centrality(G, weight=None, normalized=False) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_directed_path_normalized(self): - """Betweenness centrality: directed path normalized""" - G = nx.DiGraph() - nx.add_path(G, [0, 1, 2]) - b = nx.betweenness_centrality(G, weight=None, normalized=True) - b_answer = {0: 0.0, 1: 0.5, 2: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -class TestWeightedBetweennessCentrality: - def test_K5(self): - """Weighted betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P3_normalized(self): - """Weighted betweenness centrality: P3 normalized""" - G = nx.path_graph(3) - b = nx.betweenness_centrality(G, weight="weight", normalized=True) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P3(self): - """Weighted betweenness centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_krackhardt_kite_graph(self): - """Weighted betweenness centrality: Krackhardt kite graph""" - G = nx.krackhardt_kite_graph() - b_answer = { - 0: 1.667, - 1: 1.667, - 2: 0.000, - 3: 7.333, - 4: 0.000, - 5: 16.667, - 6: 16.667, - 7: 28.000, - 8: 16.000, - 9: 0.000, - } - for b in b_answer: - b_answer[b] /= 2 - - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_krackhardt_kite_graph_normalized(self): - """Weighted betweenness centrality: - Krackhardt kite graph normalized - """ - G = nx.krackhardt_kite_graph() - b_answer = { - 0: 0.023, - 1: 0.023, - 2: 0.000, - 3: 0.102, - 4: 0.000, - 5: 0.231, - 6: 0.231, - 7: 0.389, - 8: 0.222, - 9: 0.000, - } - b = nx.betweenness_centrality(G, weight="weight", normalized=True) - - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_florentine_families_graph(self): - """Weighted betweenness centrality: - Florentine families graph""" - G = nx.florentine_families_graph() - b_answer = { - "Acciaiuoli": 0.000, - "Albizzi": 0.212, - "Barbadori": 0.093, - "Bischeri": 0.104, - "Castellani": 0.055, - "Ginori": 0.000, - "Guadagni": 0.255, - "Lamberteschi": 0.000, - "Medici": 0.522, - "Pazzi": 0.000, - "Peruzzi": 0.022, - "Ridolfi": 0.114, - "Salviati": 0.143, - "Strozzi": 0.103, - "Tornabuoni": 0.092, - } - - b = nx.betweenness_centrality(G, weight="weight", normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_les_miserables_graph(self): - """Weighted betweenness centrality: Les Miserables graph""" - G = nx.les_miserables_graph() - b_answer = { - "Napoleon": 0.000, - "Myriel": 0.177, - "MlleBaptistine": 0.000, - "MmeMagloire": 0.000, - "CountessDeLo": 0.000, - "Geborand": 0.000, - "Champtercier": 0.000, - "Cravatte": 0.000, - "Count": 0.000, - "OldMan": 0.000, - "Valjean": 0.454, - "Labarre": 0.000, - "Marguerite": 0.009, - "MmeDeR": 0.000, - "Isabeau": 0.000, - "Gervais": 0.000, - "Listolier": 0.000, - "Tholomyes": 0.066, - "Fameuil": 0.000, - "Blacheville": 0.000, - "Favourite": 0.000, - "Dahlia": 0.000, - "Zephine": 0.000, - "Fantine": 0.114, - "MmeThenardier": 0.046, - "Thenardier": 0.129, - "Cosette": 0.075, - "Javert": 0.193, - "Fauchelevent": 0.026, - "Bamatabois": 0.080, - "Perpetue": 0.000, - "Simplice": 0.001, - "Scaufflaire": 0.000, - "Woman1": 0.000, - "Judge": 0.000, - "Champmathieu": 0.000, - "Brevet": 0.000, - "Chenildieu": 0.000, - "Cochepaille": 0.000, - "Pontmercy": 0.023, - "Boulatruelle": 0.000, - "Eponine": 0.023, - "Anzelma": 0.000, - "Woman2": 0.000, - "MotherInnocent": 0.000, - "Gribier": 0.000, - "MmeBurgon": 0.026, - "Jondrette": 0.000, - "Gavroche": 0.285, - "Gillenormand": 0.024, - "Magnon": 0.005, - "MlleGillenormand": 0.036, - "MmePontmercy": 0.005, - "MlleVaubois": 0.000, - "LtGillenormand": 0.015, - "Marius": 0.072, - "BaronessT": 0.004, - "Mabeuf": 0.089, - "Enjolras": 0.003, - "Combeferre": 0.000, - "Prouvaire": 0.000, - "Feuilly": 0.004, - "Courfeyrac": 0.001, - "Bahorel": 0.007, - "Bossuet": 0.028, - "Joly": 0.000, - "Grantaire": 0.036, - "MotherPlutarch": 0.000, - "Gueulemer": 0.025, - "Babet": 0.015, - "Claquesous": 0.042, - "Montparnasse": 0.050, - "Toussaint": 0.011, - "Child1": 0.000, - "Child2": 0.000, - "Brujon": 0.002, - "MmeHucheloup": 0.034, - } - - b = nx.betweenness_centrality(G, weight="weight", normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_ladder_graph(self): - """Weighted betweenness centrality: Ladder graph""" - G = nx.Graph() # ladder_graph(3) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - b_answer = {0: 1.667, 1: 1.667, 2: 6.667, 3: 6.667, 4: 1.667, 5: 1.667} - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_G(self): - """Weighted betweenness centrality: G""" - G = weighted_G() - b_answer = {0: 2.0, 1: 0.0, 2: 4.0, 3: 3.0, 4: 4.0, 5: 0.0} - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_G2(self): - """Weighted betweenness centrality: G2""" - G = nx.DiGraph() - G.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - - b_answer = {"y": 5.0, "x": 5.0, "s": 4.0, "u": 2.0, "v": 2.0} - - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_G3(self): - """Weighted betweenness centrality: G3""" - G = nx.MultiGraph(weighted_G()) - es = list(G.edges(data=True))[::2] # duplicate every other edge - G.add_edges_from(es) - b_answer = {0: 2.0, 1: 0.0, 2: 4.0, 3: 3.0, 4: 4.0, 5: 0.0} - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_G4(self): - """Weighted betweenness centrality: G4""" - G = nx.MultiDiGraph() - G.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("s", "x", 6), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("x", "y", 3), - ("y", "s", 7), - ("y", "v", 6), - ("y", "v", 6), - ] - ) - - b_answer = {"y": 5.0, "x": 5.0, "s": 4.0, "u": 2.0, "v": 2.0} - - b = nx.betweenness_centrality(G, weight="weight", normalized=False) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -class TestEdgeBetweennessCentrality: - def test_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = dict.fromkeys(G.edges(), 1) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = dict.fromkeys(G.edges(), 1 / 10) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = {(0, 1): 2, (0, 3): 2, (1, 2): 2, (2, 3): 2} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n] / 6, abs=1e-7) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n] / 6, abs=1e-7) - - def test_balanced_tree(self): - """Edge betweenness centrality: balanced tree""" - G = nx.balanced_tree(r=2, h=2) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = {(0, 1): 12, (0, 2): 12, (1, 3): 6, (1, 4): 6, (2, 5): 6, (2, 6): 6} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -class TestWeightedEdgeBetweennessCentrality: - def test_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = dict.fromkeys(G.edges(), 1) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = {(0, 1): 2, (0, 3): 2, (1, 2): 2, (2, 3): 2} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_balanced_tree(self): - """Edge betweenness centrality: balanced tree""" - G = nx.balanced_tree(r=2, h=2) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = {(0, 1): 12, (0, 2): 12, (1, 3): 6, (1, 4): 6, (2, 5): 6, (2, 6): 6} - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_weighted_graph(self): - """Edge betweenness centrality: weighted""" - eList = [ - (0, 1, 5), - (0, 2, 4), - (0, 3, 3), - (0, 4, 2), - (1, 2, 4), - (1, 3, 1), - (1, 4, 3), - (2, 4, 5), - (3, 4, 4), - ] - G = nx.Graph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = { - (0, 1): 0.0, - (0, 2): 1.0, - (0, 3): 2.0, - (0, 4): 1.0, - (1, 2): 2.0, - (1, 3): 3.5, - (1, 4): 1.5, - (2, 4): 1.0, - (3, 4): 0.5, - } - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_weighted_graph(self): - """Edge betweenness centrality: normalized weighted""" - eList = [ - (0, 1, 5), - (0, 2, 4), - (0, 3, 3), - (0, 4, 2), - (1, 2, 4), - (1, 3, 1), - (1, 4, 3), - (2, 4, 5), - (3, 4, 4), - ] - G = nx.Graph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=True) - b_answer = { - (0, 1): 0.0, - (0, 2): 1.0, - (0, 3): 2.0, - (0, 4): 1.0, - (1, 2): 2.0, - (1, 3): 3.5, - (1, 4): 1.5, - (2, 4): 1.0, - (3, 4): 0.5, - } - norm = len(G) * (len(G) - 1) / 2 - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n] / norm, abs=1e-7) - - def test_weighted_multigraph(self): - """Edge betweenness centrality: weighted multigraph""" - eList = [ - (0, 1, 5), - (0, 1, 4), - (0, 2, 4), - (0, 3, 3), - (0, 3, 3), - (0, 4, 2), - (1, 2, 4), - (1, 3, 1), - (1, 3, 2), - (1, 4, 3), - (1, 4, 4), - (2, 4, 5), - (3, 4, 4), - (3, 4, 4), - ] - G = nx.MultiGraph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=False) - b_answer = { - (0, 1, 0): 0.0, - (0, 1, 1): 0.5, - (0, 2, 0): 1.0, - (0, 3, 0): 0.75, - (0, 3, 1): 0.75, - (0, 4, 0): 1.0, - (1, 2, 0): 2.0, - (1, 3, 0): 3.0, - (1, 3, 1): 0.0, - (1, 4, 0): 1.5, - (1, 4, 1): 0.0, - (2, 4, 0): 1.0, - (3, 4, 0): 0.25, - (3, 4, 1): 0.25, - } - for n in sorted(G.edges(keys=True)): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_weighted_multigraph(self): - """Edge betweenness centrality: normalized weighted multigraph""" - eList = [ - (0, 1, 5), - (0, 1, 4), - (0, 2, 4), - (0, 3, 3), - (0, 3, 3), - (0, 4, 2), - (1, 2, 4), - (1, 3, 1), - (1, 3, 2), - (1, 4, 3), - (1, 4, 4), - (2, 4, 5), - (3, 4, 4), - (3, 4, 4), - ] - G = nx.MultiGraph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight="weight", normalized=True) - b_answer = { - (0, 1, 0): 0.0, - (0, 1, 1): 0.5, - (0, 2, 0): 1.0, - (0, 3, 0): 0.75, - (0, 3, 1): 0.75, - (0, 4, 0): 1.0, - (1, 2, 0): 2.0, - (1, 3, 0): 3.0, - (1, 3, 1): 0.0, - (1, 4, 0): 1.5, - (1, 4, 1): 0.0, - (2, 4, 0): 1.0, - (3, 4, 0): 0.25, - (3, 4, 1): 0.25, - } - norm = len(G) * (len(G) - 1) / 2 - for n in sorted(G.edges(keys=True)): - assert b[n] == pytest.approx(b_answer[n] / norm, abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py deleted file mode 100644 index a35a401..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +++ /dev/null @@ -1,340 +0,0 @@ -import pytest - -import networkx as nx - - -class TestSubsetBetweennessCentrality: - def test_K5(self): - """Betweenness Centrality Subset: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[1, 3], weight=None - ) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5_directed(self): - """Betweenness Centrality Subset: P5 directed""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 1, 2: 1, 3: 0, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5(self): - """Betweenness Centrality Subset: P5""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 0.5, 2: 0.5, 3: 0, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5_multiple_target(self): - """Betweenness Centrality Subset: P5 multiple target""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 1, 2: 1, 3: 0.5, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box(self): - """Betweenness Centrality Subset: box""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - b_answer = {0: 0, 1: 0.25, 2: 0.25, 3: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box_and_path(self): - """Betweenness Centrality Subset: box and path""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (3, 4), (4, 5)]) - b_answer = {0: 0, 1: 0.5, 2: 0.5, 3: 0.5, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box_and_path2(self): - """Betweenness Centrality Subset: box and path multiple target""" - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (1, 20), (20, 3), (3, 4)]) - b_answer = {0: 0, 1: 1.0, 2: 0.5, 20: 0.5, 3: 0.5, 4: 0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_diamond_multi_path(self): - """Betweenness Centrality Subset: Diamond Multi Path""" - G = nx.Graph() - G.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (1, 10), - (10, 11), - (11, 12), - (12, 9), - (2, 6), - (3, 6), - (4, 6), - (5, 7), - (7, 8), - (6, 8), - (8, 9), - ] - ) - b = nx.betweenness_centrality_subset(G, sources=[1], targets=[9], weight=None) - - expected_b = { - 1: 0, - 2: 1.0 / 10, - 3: 1.0 / 10, - 4: 1.0 / 10, - 5: 1.0 / 10, - 6: 3.0 / 10, - 7: 1.0 / 10, - 8: 4.0 / 10, - 9: 0, - 10: 1.0 / 10, - 11: 1.0 / 10, - 12: 1.0 / 10, - } - - for n in sorted(G): - assert b[n] == pytest.approx(expected_b[n], abs=1e-7) - - def test_normalized_p2(self): - """ - Betweenness Centrality Subset: Normalized P2 - if n <= 2: no normalization, betweenness centrality should be 0 for all nodes. - """ - G = nx.Graph() - nx.add_path(G, range(2)) - b_answer = {0: 0, 1: 0.0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[1], normalized=True, weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_P5_directed(self): - """Betweenness Centrality Subset: Normalized Directed P5""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 1.0 / 12.0, 2: 1.0 / 12.0, 3: 0, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[3], normalized=True, weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_weighted_graph(self): - """Betweenness Centrality Subset: Weighted Graph""" - G = nx.DiGraph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - b_answer = {0: 0.0, 1: 0.0, 2: 0.5, 3: 0.5, 4: 0.5, 5: 0.0} - b = nx.betweenness_centrality_subset( - G, sources=[0], targets=[5], normalized=False, weight="weight" - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -class TestEdgeSubsetBetweennessCentrality: - def test_K5(self): - """Edge betweenness subset centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[1, 3], weight=None - ) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 3)] = b_answer[(0, 1)] = 0.5 - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5_directed(self): - """Edge betweenness subset centrality: P5 directed""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 1 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5(self): - """Edge betweenness subset centrality: P5""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 0.5 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P5_multiple_target(self): - """Edge betweenness subset centrality: P5 multiple target""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 1 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box(self): - """Edge betweenness subset centrality: box""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(0, 2)] = 0.25 - b_answer[(1, 3)] = b_answer[(2, 3)] = 0.25 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box_and_path(self): - """Edge betweenness subset centrality: box and path""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (3, 4), (4, 5)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(0, 2)] = 0.5 - b_answer[(1, 3)] = b_answer[(2, 3)] = 0.5 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_box_and_path2(self): - """Edge betweenness subset centrality: box and path multiple target""" - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (1, 20), (20, 3), (3, 4)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = 1.0 - b_answer[(1, 20)] = b_answer[(3, 20)] = 0.5 - b_answer[(1, 2)] = b_answer[(2, 3)] = 0.5 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3, 4], weight=None - ) - for n in sorted(G.edges()): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_diamond_multi_path(self): - """Edge betweenness subset centrality: Diamond Multi Path""" - G = nx.Graph() - G.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (1, 10), - (10, 11), - (11, 12), - (12, 9), - (2, 6), - (3, 6), - (4, 6), - (5, 7), - (7, 8), - (6, 8), - (8, 9), - ] - ) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(8, 9)] = 0.4 - b_answer[(6, 8)] = b_answer[(7, 8)] = 0.2 - b_answer[(2, 6)] = b_answer[(3, 6)] = b_answer[(4, 6)] = 0.2 / 3.0 - b_answer[(1, 2)] = b_answer[(1, 3)] = b_answer[(1, 4)] = 0.2 / 3.0 - b_answer[(5, 7)] = 0.2 - b_answer[(1, 5)] = 0.2 - b_answer[(9, 12)] = 0.1 - b_answer[(11, 12)] = b_answer[(10, 11)] = b_answer[(1, 10)] = 0.1 - b = nx.edge_betweenness_centrality_subset( - G, sources=[1], targets=[9], weight=None - ) - for n in G.edges(): - sort_n = tuple(sorted(n)) - assert b[n] == pytest.approx(b_answer[sort_n], abs=1e-7) - - def test_normalized_p1(self): - """ - Edge betweenness subset centrality: P1 - if n <= 1: no normalization b=0 for all nodes - """ - G = nx.Graph() - nx.add_path(G, range(1)) - b_answer = dict.fromkeys(G.edges(), 0) - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[0], normalized=True, weight=None - ) - for n in G.edges(): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_normalized_P5_directed(self): - """Edge betweenness subset centrality: Normalized Directed P5""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 0.05 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[3], normalized=True, weight=None - ) - for n in G.edges(): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_weighted_graph(self): - """Edge betweenness subset centrality: Weighted Graph""" - G = nx.DiGraph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 2)] = b_answer[(2, 4)] = b_answer[(4, 5)] = 0.5 - b_answer[(0, 3)] = b_answer[(3, 5)] = 0.5 - b = nx.edge_betweenness_centrality_subset( - G, sources=[0], targets=[5], normalized=False, weight="weight" - ) - for n in G.edges(): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_closeness_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_closeness_centrality.py deleted file mode 100644 index 7bdb7e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_closeness_centrality.py +++ /dev/null @@ -1,307 +0,0 @@ -""" -Tests for closeness centrality. -""" - -import pytest - -import networkx as nx - - -class TestClosenessCentrality: - @classmethod - def setup_class(cls): - cls.K = nx.krackhardt_kite_graph() - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - - cls.C4 = nx.cycle_graph(4) - cls.T = nx.balanced_tree(r=2, h=2) - cls.Gb = nx.Graph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - - F = nx.florentine_families_graph() - cls.F = F - - cls.LM = nx.les_miserables_graph() - - # Create random undirected, unweighted graph for testing incremental version - cls.undirected_G = nx.fast_gnp_random_graph(n=100, p=0.6, seed=123) - cls.undirected_G_cc = nx.closeness_centrality(cls.undirected_G) - - def test_wf_improved(self): - G = nx.union(self.P4, nx.path_graph([4, 5, 6])) - c = nx.closeness_centrality(G) - cwf = nx.closeness_centrality(G, wf_improved=False) - res = {0: 0.25, 1: 0.375, 2: 0.375, 3: 0.25, 4: 0.222, 5: 0.333, 6: 0.222} - wf_res = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5, 4: 0.667, 5: 1.0, 6: 0.667} - for n in G: - assert c[n] == pytest.approx(res[n], abs=1e-3) - assert cwf[n] == pytest.approx(wf_res[n], abs=1e-3) - - def test_digraph(self): - G = nx.path_graph(3, create_using=nx.DiGraph()) - c = nx.closeness_centrality(G) - cr = nx.closeness_centrality(G.reverse()) - d = {0: 0.0, 1: 0.500, 2: 0.667} - dr = {0: 0.667, 1: 0.500, 2: 0.0} - for n in sorted(self.P3): - assert c[n] == pytest.approx(d[n], abs=1e-3) - assert cr[n] == pytest.approx(dr[n], abs=1e-3) - - def test_k5_closeness(self): - c = nx.closeness_centrality(self.K5) - d = {0: 1.000, 1: 1.000, 2: 1.000, 3: 1.000, 4: 1.000} - for n in sorted(self.K5): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_p3_closeness(self): - c = nx.closeness_centrality(self.P3) - d = {0: 0.667, 1: 1.000, 2: 0.667} - for n in sorted(self.P3): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_krackhardt_closeness(self): - c = nx.closeness_centrality(self.K) - d = { - 0: 0.529, - 1: 0.529, - 2: 0.500, - 3: 0.600, - 4: 0.500, - 5: 0.643, - 6: 0.643, - 7: 0.600, - 8: 0.429, - 9: 0.310, - } - for n in sorted(self.K): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_florentine_families_closeness(self): - c = nx.closeness_centrality(self.F) - d = { - "Acciaiuoli": 0.368, - "Albizzi": 0.483, - "Barbadori": 0.4375, - "Bischeri": 0.400, - "Castellani": 0.389, - "Ginori": 0.333, - "Guadagni": 0.467, - "Lamberteschi": 0.326, - "Medici": 0.560, - "Pazzi": 0.286, - "Peruzzi": 0.368, - "Ridolfi": 0.500, - "Salviati": 0.389, - "Strozzi": 0.4375, - "Tornabuoni": 0.483, - } - for n in sorted(self.F): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_les_miserables_closeness(self): - c = nx.closeness_centrality(self.LM) - d = { - "Napoleon": 0.302, - "Myriel": 0.429, - "MlleBaptistine": 0.413, - "MmeMagloire": 0.413, - "CountessDeLo": 0.302, - "Geborand": 0.302, - "Champtercier": 0.302, - "Cravatte": 0.302, - "Count": 0.302, - "OldMan": 0.302, - "Valjean": 0.644, - "Labarre": 0.394, - "Marguerite": 0.413, - "MmeDeR": 0.394, - "Isabeau": 0.394, - "Gervais": 0.394, - "Listolier": 0.341, - "Tholomyes": 0.392, - "Fameuil": 0.341, - "Blacheville": 0.341, - "Favourite": 0.341, - "Dahlia": 0.341, - "Zephine": 0.341, - "Fantine": 0.461, - "MmeThenardier": 0.461, - "Thenardier": 0.517, - "Cosette": 0.478, - "Javert": 0.517, - "Fauchelevent": 0.402, - "Bamatabois": 0.427, - "Perpetue": 0.318, - "Simplice": 0.418, - "Scaufflaire": 0.394, - "Woman1": 0.396, - "Judge": 0.404, - "Champmathieu": 0.404, - "Brevet": 0.404, - "Chenildieu": 0.404, - "Cochepaille": 0.404, - "Pontmercy": 0.373, - "Boulatruelle": 0.342, - "Eponine": 0.396, - "Anzelma": 0.352, - "Woman2": 0.402, - "MotherInnocent": 0.398, - "Gribier": 0.288, - "MmeBurgon": 0.344, - "Jondrette": 0.257, - "Gavroche": 0.514, - "Gillenormand": 0.442, - "Magnon": 0.335, - "MlleGillenormand": 0.442, - "MmePontmercy": 0.315, - "MlleVaubois": 0.308, - "LtGillenormand": 0.365, - "Marius": 0.531, - "BaronessT": 0.352, - "Mabeuf": 0.396, - "Enjolras": 0.481, - "Combeferre": 0.392, - "Prouvaire": 0.357, - "Feuilly": 0.392, - "Courfeyrac": 0.400, - "Bahorel": 0.394, - "Bossuet": 0.475, - "Joly": 0.394, - "Grantaire": 0.358, - "MotherPlutarch": 0.285, - "Gueulemer": 0.463, - "Babet": 0.463, - "Claquesous": 0.452, - "Montparnasse": 0.458, - "Toussaint": 0.402, - "Child1": 0.342, - "Child2": 0.342, - "Brujon": 0.380, - "MmeHucheloup": 0.353, - } - for n in sorted(self.LM): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_weighted_closeness(self): - edges = [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - XG = nx.Graph() - XG.add_weighted_edges_from(edges) - c = nx.closeness_centrality(XG, distance="weight") - d = {"y": 0.200, "x": 0.286, "s": 0.138, "u": 0.235, "v": 0.200} - for n in sorted(XG): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - # - # Tests for incremental closeness centrality. - # - @staticmethod - def pick_add_edge(g): - u = nx.utils.arbitrary_element(g) - possible_nodes = set(g.nodes()) - neighbors = list(g.neighbors(u)) + [u] - possible_nodes.difference_update(neighbors) - v = nx.utils.arbitrary_element(possible_nodes) - return (u, v) - - @staticmethod - def pick_remove_edge(g): - u = nx.utils.arbitrary_element(g) - possible_nodes = list(g.neighbors(u)) - v = nx.utils.arbitrary_element(possible_nodes) - return (u, v) - - def test_directed_raises(self): - with pytest.raises(nx.NetworkXNotImplemented): - dir_G = nx.gn_graph(n=5) - prev_cc = None - edge = self.pick_add_edge(dir_G) - insert = True - nx.incremental_closeness_centrality(dir_G, edge, prev_cc, insert) - - def test_wrong_size_prev_cc_raises(self): - with pytest.raises(nx.NetworkXError): - G = self.undirected_G.copy() - edge = self.pick_add_edge(G) - insert = True - prev_cc = self.undirected_G_cc.copy() - prev_cc.pop(0) - nx.incremental_closeness_centrality(G, edge, prev_cc, insert) - - def test_wrong_nodes_prev_cc_raises(self): - with pytest.raises(nx.NetworkXError): - G = self.undirected_G.copy() - edge = self.pick_add_edge(G) - insert = True - prev_cc = self.undirected_G_cc.copy() - num_nodes = len(prev_cc) - prev_cc.pop(0) - prev_cc[num_nodes] = 0.5 - nx.incremental_closeness_centrality(G, edge, prev_cc, insert) - - def test_zero_centrality(self): - G = nx.path_graph(3) - prev_cc = nx.closeness_centrality(G) - edge = self.pick_remove_edge(G) - test_cc = nx.incremental_closeness_centrality(G, edge, prev_cc, insertion=False) - G.remove_edges_from([edge]) - real_cc = nx.closeness_centrality(G) - shared_items = set(test_cc.items()) & set(real_cc.items()) - assert len(shared_items) == len(real_cc) - assert 0 in test_cc.values() - - def test_incremental(self): - # Check that incremental and regular give same output - G = self.undirected_G.copy() - prev_cc = None - for i in range(5): - if i % 2 == 0: - # Remove an edge - insert = False - edge = self.pick_remove_edge(G) - else: - # Add an edge - insert = True - edge = self.pick_add_edge(G) - - # start = timeit.default_timer() - test_cc = nx.incremental_closeness_centrality(G, edge, prev_cc, insert) - # inc_elapsed = (timeit.default_timer() - start) - # print(f"incremental time: {inc_elapsed}") - - if insert: - G.add_edges_from([edge]) - else: - G.remove_edges_from([edge]) - - # start = timeit.default_timer() - real_cc = nx.closeness_centrality(G) - # reg_elapsed = (timeit.default_timer() - start) - # print(f"regular time: {reg_elapsed}") - # Example output: - # incremental time: 0.208 - # regular time: 0.276 - # incremental time: 0.00683 - # regular time: 0.260 - # incremental time: 0.0224 - # regular time: 0.278 - # incremental time: 0.00804 - # regular time: 0.208 - # incremental time: 0.00947 - # regular time: 0.188 - - assert set(test_cc.items()) == set(real_cc.items()) - - prev_cc = test_cc diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py deleted file mode 100644 index 4e3d438..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +++ /dev/null @@ -1,197 +0,0 @@ -import pytest - -import networkx as nx -from networkx import approximate_current_flow_betweenness_centrality as approximate_cfbc -from networkx import edge_current_flow_betweenness_centrality as edge_current_flow - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -class TestFlowBetweennessCentrality: - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - G.add_edge(0, 1, weight=0.5, other=0.3) - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - wb_answer = {0: 0.2222222, 1: 0.2222222, 2: 0.30555555, 3: 0.30555555} - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight="weight") - for n in sorted(G): - assert b[n] == pytest.approx(wb_answer[n], abs=1e-7) - wb_answer = {0: 0.2051282, 1: 0.2051282, 2: 0.33974358, 3: 0.33974358} - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight="other") - for n in sorted(G): - assert b[n] == pytest.approx(wb_answer[n], abs=1e-7) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - for solver in ["full", "lu", "cg"]: - b = nx.current_flow_betweenness_centrality( - G, normalized=False, solver=solver - ) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4_normalized(self): - """Betweenness centrality: P4 normalized""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {0: 0, 1: 2.0 / 3, 2: 2.0 / 3, 3: 0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4(self): - """Betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=False) - b_answer = {0: 0, 1: 2, 2: 2, 3: 0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_star(self): - """Betweenness centrality: star""" - G = nx.Graph() - nx.add_star(G, ["a", "b", "c", "d"]) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {"a": 1.0, "b": 0.0, "c": 0.0, "d": 0.0} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_solvers2(self): - """Betweenness centrality: alternate solvers""" - G = nx.complete_graph(4) - for solver in ["full", "lu", "cg"]: - b = nx.current_flow_betweenness_centrality( - G, normalized=False, solver=solver - ) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -class TestApproximateFlowBetweennessCentrality: - def test_K4_normalized(self): - "Approximate current-flow betweenness centrality: K4 normalized" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - np.testing.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_K4(self): - "Approximate current-flow betweenness centrality: K4" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=False) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=False, epsilon=0.5 * epsilon) - for n in sorted(G): - np.testing.assert_allclose(b[n], ba[n], atol=epsilon * len(G) ** 2) - - def test_star(self): - "Approximate current-flow betweenness centrality: star" - G = nx.Graph() - nx.add_star(G, ["a", "b", "c", "d"]) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - np.testing.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_grid(self): - "Approximate current-flow betweenness centrality: 2d grid" - G = nx.grid_2d_graph(4, 4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - np.testing.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_seed(self): - G = nx.complete_graph(4) - b = approximate_cfbc(G, normalized=False, epsilon=0.05, seed=1) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - np.testing.assert_allclose(b[n], b_answer[n], atol=0.1) - - def test_solvers(self): - "Approximate current-flow betweenness centrality: solvers" - G = nx.complete_graph(4) - epsilon = 0.1 - for solver in ["full", "lu", "cg"]: - b = approximate_cfbc( - G, normalized=False, solver=solver, epsilon=0.5 * epsilon - ) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - np.testing.assert_allclose(b[n], b_answer[n], atol=epsilon) - - def test_lower_kmax(self): - G = nx.complete_graph(4) - with pytest.raises(nx.NetworkXError, match="Increase kmax or epsilon"): - nx.approximate_current_flow_betweenness_centrality(G, kmax=4) - - -class TestWeightedFlowBetweennessCentrality: - pass - - -class TestEdgeFlowBetweennessCentrality: - def test_K4(self): - """Edge flow betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow(G, normalized=True) - b_answer = dict.fromkeys(G.edges(), 0.25) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_K4_normalized(self): - """Edge flow betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = dict.fromkeys(G.edges(), 0.75) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_C4(self): - """Edge flow betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = {(0, 1): 1.25, (0, 3): 1.25, (1, 2): 1.25, (2, 3): 1.25} - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = {(0, 1): 1.5, (1, 2): 2.0, (2, 3): 1.5} - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - -@pytest.mark.parametrize( - "centrality_func", - ( - nx.current_flow_betweenness_centrality, - nx.edge_current_flow_betweenness_centrality, - nx.approximate_current_flow_betweenness_centrality, - ), -) -def test_unconnected_graphs_betweenness_centrality(centrality_func): - G = nx.Graph([(1, 2), (3, 4)]) - G.add_node(5) - with pytest.raises(nx.NetworkXError, match="Graph not connected"): - centrality_func(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py deleted file mode 100644 index 7b1611b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +++ /dev/null @@ -1,147 +0,0 @@ -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx import edge_current_flow_betweenness_centrality as edge_current_flow -from networkx import ( - edge_current_flow_betweenness_centrality_subset as edge_current_flow_subset, -) - - -class TestFlowBetweennessCentrality: - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - # test weighted network - G.add_edge(0, 1, weight=0.5, other=0.3) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True, weight=None - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True, weight="other" - ) - b_answer = nx.current_flow_betweenness_centrality( - G, normalized=True, weight="other" - ) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4_normalized(self): - """Betweenness centrality: P4 normalized""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4(self): - """Betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_star(self): - """Betweenness centrality: star""" - G = nx.Graph() - nx.add_star(G, ["a", "b", "c", "d"]) - b = nx.current_flow_betweenness_centrality_subset( - G, list(G), list(G), normalized=True - ) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - -# class TestWeightedFlowBetweennessCentrality(): -# pass - - -class TestEdgeFlowBetweennessCentrality: - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=False) - b_answer = edge_current_flow(G, normalized=False) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - # test weighted network - G.add_edge(0, 1, weight=0.5, other=0.3) - b = edge_current_flow_subset(G, list(G), list(G), normalized=False, weight=None) - # weight is None => same as unweighted network - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - b = edge_current_flow_subset(G, list(G), list(G), normalized=False) - b_answer = edge_current_flow(G, normalized=False) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - b = edge_current_flow_subset( - G, list(G), list(G), normalized=False, weight="other" - ) - b_answer = edge_current_flow(G, normalized=False, weight="other") - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert v1 == pytest.approx(v2, abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_closeness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_closeness.py deleted file mode 100644 index 2528d62..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx - - -class TestFlowClosenessCentrality: - def test_K4(self): - """Closeness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_closeness_centrality(G) - b_answer = {0: 2.0 / 3, 1: 2.0 / 3, 2: 2.0 / 3, 3: 2.0 / 3} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P4(self): - """Closeness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_closeness_centrality(G) - b_answer = {0: 1.0 / 6, 1: 1.0 / 4, 2: 1.0 / 4, 3: 1.0 / 6} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_star(self): - """Closeness centrality: star""" - G = nx.Graph() - nx.add_star(G, ["a", "b", "c", "d"]) - b = nx.current_flow_closeness_centrality(G) - b_answer = {"a": 1.0 / 3, "b": 0.6 / 3, "c": 0.6 / 3, "d": 0.6 / 3} - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_current_flow_closeness_centrality_not_connected(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - with pytest.raises(nx.NetworkXError): - nx.current_flow_closeness_centrality(G) - - -class TestWeightedFlowClosenessCentrality: - pass diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_degree_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_degree_centrality.py deleted file mode 100644 index e39aa3b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_degree_centrality.py +++ /dev/null @@ -1,144 +0,0 @@ -""" -Unit tests for degree centrality. -""" - -import pytest - -import networkx as nx - - -class TestDegreeCentrality: - def setup_method(self): - self.K = nx.krackhardt_kite_graph() - self.P3 = nx.path_graph(3) - self.K5 = nx.complete_graph(5) - - F = nx.Graph() # Florentine families - F.add_edge("Acciaiuoli", "Medici") - F.add_edge("Castellani", "Peruzzi") - F.add_edge("Castellani", "Strozzi") - F.add_edge("Castellani", "Barbadori") - F.add_edge("Medici", "Barbadori") - F.add_edge("Medici", "Ridolfi") - F.add_edge("Medici", "Tornabuoni") - F.add_edge("Medici", "Albizzi") - F.add_edge("Medici", "Salviati") - F.add_edge("Salviati", "Pazzi") - F.add_edge("Peruzzi", "Strozzi") - F.add_edge("Peruzzi", "Bischeri") - F.add_edge("Strozzi", "Ridolfi") - F.add_edge("Strozzi", "Bischeri") - F.add_edge("Ridolfi", "Tornabuoni") - F.add_edge("Tornabuoni", "Guadagni") - F.add_edge("Albizzi", "Ginori") - F.add_edge("Albizzi", "Guadagni") - F.add_edge("Bischeri", "Guadagni") - F.add_edge("Guadagni", "Lamberteschi") - self.F = F - - G = nx.DiGraph() - G.add_edge(0, 5) - G.add_edge(1, 5) - G.add_edge(2, 5) - G.add_edge(3, 5) - G.add_edge(4, 5) - G.add_edge(5, 6) - G.add_edge(5, 7) - G.add_edge(5, 8) - self.G = G - - def test_degree_centrality_1(self): - d = nx.degree_centrality(self.K5) - exact = dict(zip(range(5), [1] * 5)) - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - def test_degree_centrality_2(self): - d = nx.degree_centrality(self.P3) - exact = {0: 0.5, 1: 1, 2: 0.5} - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - def test_degree_centrality_3(self): - d = nx.degree_centrality(self.K) - exact = { - 0: 0.444, - 1: 0.444, - 2: 0.333, - 3: 0.667, - 4: 0.333, - 5: 0.556, - 6: 0.556, - 7: 0.333, - 8: 0.222, - 9: 0.111, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(float(f"{dc:.3f}"), abs=1e-7) - - def test_degree_centrality_4(self): - d = nx.degree_centrality(self.F) - names = sorted(self.F.nodes()) - dcs = [ - 0.071, - 0.214, - 0.143, - 0.214, - 0.214, - 0.071, - 0.286, - 0.071, - 0.429, - 0.071, - 0.214, - 0.214, - 0.143, - 0.286, - 0.214, - ] - exact = dict(zip(names, dcs)) - for n, dc in d.items(): - assert exact[n] == pytest.approx(float(f"{dc:.3f}"), abs=1e-7) - - def test_indegree_centrality(self): - d = nx.in_degree_centrality(self.G) - exact = { - 0: 0.0, - 1: 0.0, - 2: 0.0, - 3: 0.0, - 4: 0.0, - 5: 0.625, - 6: 0.125, - 7: 0.125, - 8: 0.125, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - def test_outdegree_centrality(self): - d = nx.out_degree_centrality(self.G) - exact = { - 0: 0.125, - 1: 0.125, - 2: 0.125, - 3: 0.125, - 4: 0.125, - 5: 0.375, - 6: 0.0, - 7: 0.0, - 8: 0.0, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - def test_small_graph_centrality(self): - G = nx.empty_graph(create_using=nx.DiGraph) - assert {} == nx.degree_centrality(G) - assert {} == nx.out_degree_centrality(G) - assert {} == nx.in_degree_centrality(G) - - G = nx.empty_graph(1, create_using=nx.DiGraph) - assert {0: 1} == nx.degree_centrality(G) - assert {0: 1} == nx.out_degree_centrality(G) - assert {0: 1} == nx.in_degree_centrality(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_dispersion.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_dispersion.py deleted file mode 100644 index 05de1c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_dispersion.py +++ /dev/null @@ -1,73 +0,0 @@ -import networkx as nx - - -def small_ego_G(): - """The sample network from https://arxiv.org/pdf/1310.6753v1.pdf""" - edges = [ - ("a", "b"), - ("a", "c"), - ("b", "c"), - ("b", "d"), - ("b", "e"), - ("b", "f"), - ("c", "d"), - ("c", "f"), - ("c", "h"), - ("d", "f"), - ("e", "f"), - ("f", "h"), - ("h", "j"), - ("h", "k"), - ("i", "j"), - ("i", "k"), - ("j", "k"), - ("u", "a"), - ("u", "b"), - ("u", "c"), - ("u", "d"), - ("u", "e"), - ("u", "f"), - ("u", "g"), - ("u", "h"), - ("u", "i"), - ("u", "j"), - ("u", "k"), - ] - G = nx.Graph() - G.add_edges_from(edges) - - return G - - -class TestDispersion: - def test_article(self): - """our algorithm matches article's""" - G = small_ego_G() - disp_uh = nx.dispersion(G, "u", "h", normalized=False) - disp_ub = nx.dispersion(G, "u", "b", normalized=False) - assert disp_uh == 4 - assert disp_ub == 1 - - def test_results_length(self): - """there is a result for every node""" - G = small_ego_G() - disp = nx.dispersion(G) - disp_Gu = nx.dispersion(G, "u") - disp_uv = nx.dispersion(G, "u", "h") - assert len(disp) == len(G) - assert len(disp_Gu) == len(G) - 1 - assert isinstance(disp_uv, float) - - def test_dispersion_v_only(self): - G = small_ego_G() - disp_G_h = nx.dispersion(G, v="h", normalized=False) - disp_G_h_normalized = nx.dispersion(G, v="h", normalized=True) - assert disp_G_h == {"c": 0, "f": 0, "j": 0, "k": 0, "u": 4} - assert disp_G_h_normalized == {"c": 0.0, "f": 0.0, "j": 0.0, "k": 0.0, "u": 1.0} - - def test_impossible_things(self): - G = nx.karate_club_graph() - disp = nx.dispersion(G) - for u in disp: - for v in disp[u]: - assert disp[u][v] >= 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py deleted file mode 100644 index cfc9ee7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +++ /dev/null @@ -1,187 +0,0 @@ -import math - -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -import networkx as nx - - -class TestEigenvectorCentrality: - def test_K5(self): - """Eigenvector centrality: K5""" - G = nx.complete_graph(5) - b = nx.eigenvector_centrality(G) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - nstart = {n: 1 for n in G} - b = nx.eigenvector_centrality(G, nstart=nstart) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_P3(self): - """Eigenvector centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.5, 1: 0.7071, 2: 0.5} - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - b = nx.eigenvector_centrality(G) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_P3_unweighted(self): - """Eigenvector centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.5, 1: 0.7071, 2: 0.5} - b = nx.eigenvector_centrality_numpy(G, weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_maxiter(self): - with pytest.raises(nx.PowerIterationFailedConvergence): - G = nx.path_graph(3) - nx.eigenvector_centrality(G, max_iter=0) - - -class TestEigenvectorCentralityDirected: - @classmethod - def setup_class(cls): - G = nx.DiGraph() - - edges = [ - (1, 2), - (1, 3), - (2, 4), - (3, 2), - (3, 5), - (4, 2), - (4, 5), - (4, 6), - (5, 6), - (5, 7), - (5, 8), - (6, 8), - (7, 1), - (7, 5), - (7, 8), - (8, 6), - (8, 7), - ] - - G.add_edges_from(edges, weight=2.0) - cls.G = G.reverse() - cls.G.evc = [ - 0.25368793, - 0.19576478, - 0.32817092, - 0.40430835, - 0.48199885, - 0.15724483, - 0.51346196, - 0.32475403, - ] - - H = nx.DiGraph() - - edges = [ - (1, 2), - (1, 3), - (2, 4), - (3, 2), - (3, 5), - (4, 2), - (4, 5), - (4, 6), - (5, 6), - (5, 7), - (5, 8), - (6, 8), - (7, 1), - (7, 5), - (7, 8), - (8, 6), - (8, 7), - ] - - G.add_edges_from(edges) - cls.H = G.reverse() - cls.H.evc = [ - 0.25368793, - 0.19576478, - 0.32817092, - 0.40430835, - 0.48199885, - 0.15724483, - 0.51346196, - 0.32475403, - ] - - def test_eigenvector_centrality_weighted(self): - G = self.G - p = nx.eigenvector_centrality(G) - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-4) - - def test_eigenvector_centrality_weighted_numpy(self): - G = self.G - p = nx.eigenvector_centrality_numpy(G) - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-7) - - def test_eigenvector_centrality_unweighted(self): - G = self.H - p = nx.eigenvector_centrality(G) - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-4) - - def test_eigenvector_centrality_unweighted_numpy(self): - G = self.H - p = nx.eigenvector_centrality_numpy(G) - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-7) - - -class TestEigenvectorCentralityExceptions: - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - nx.eigenvector_centrality(nx.MultiGraph()) - - def test_multigraph_numpy(self): - with pytest.raises(nx.NetworkXException): - nx.eigenvector_centrality_numpy(nx.MultiGraph()) - - def test_null(self): - with pytest.raises(nx.NetworkXException): - nx.eigenvector_centrality(nx.Graph()) - - def test_null_numpy(self): - with pytest.raises(nx.NetworkXException): - nx.eigenvector_centrality_numpy(nx.Graph()) - - @pytest.mark.parametrize( - "G", - [ - nx.empty_graph(3), - nx.DiGraph([(0, 1), (1, 2)]), - ], - ) - def test_disconnected_numpy(self, G): - msg = "does not give consistent results for disconnected" - with pytest.raises(nx.AmbiguousSolution, match=msg): - nx.eigenvector_centrality_numpy(G) - - def test_zero_nstart(self): - G = nx.Graph([(1, 2), (1, 3), (2, 3)]) - with pytest.raises( - nx.NetworkXException, match="initial vector cannot have all zero values" - ): - nx.eigenvector_centrality(G, nstart={v: 0 for v in G}) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_group.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_group.py deleted file mode 100644 index 82343f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_group.py +++ /dev/null @@ -1,277 +0,0 @@ -""" -Tests for Group Centrality Measures -""" - -import pytest - -import networkx as nx - - -class TestGroupBetweennessCentrality: - def test_group_betweenness_single_node(self): - """ - Group betweenness centrality for single node group - """ - G = nx.path_graph(5) - C = [1] - b = nx.group_betweenness_centrality( - G, C, weight=None, normalized=False, endpoints=False - ) - b_answer = 3.0 - assert b == b_answer - - def test_group_betweenness_with_endpoints(self): - """ - Group betweenness centrality for single node group - """ - G = nx.path_graph(5) - C = [1] - b = nx.group_betweenness_centrality( - G, C, weight=None, normalized=False, endpoints=True - ) - b_answer = 7.0 - assert b == b_answer - - def test_group_betweenness_normalized(self): - """ - Group betweenness centrality for group with more than - 1 node and normalized - """ - G = nx.path_graph(5) - C = [1, 3] - b = nx.group_betweenness_centrality( - G, C, weight=None, normalized=True, endpoints=False - ) - b_answer = 1.0 - assert b == b_answer - - def test_two_group_betweenness_value_zero(self): - """ - Group betweenness centrality value of 0 - """ - G = nx.cycle_graph(7) - C = [[0, 1, 6], [0, 1, 5]] - b = nx.group_betweenness_centrality(G, C, weight=None, normalized=False) - b_answer = [0.0, 3.0] - assert b == b_answer - - def test_group_betweenness_value_zero(self): - """ - Group betweenness centrality value of 0 - """ - G = nx.cycle_graph(6) - C = [0, 1, 5] - b = nx.group_betweenness_centrality(G, C, weight=None, normalized=False) - b_answer = 0.0 - assert b == b_answer - - def test_group_betweenness_disconnected_graph(self): - """ - Group betweenness centrality in a disconnected graph - """ - G = nx.path_graph(5) - G.remove_edge(0, 1) - C = [1] - b = nx.group_betweenness_centrality(G, C, weight=None, normalized=False) - b_answer = 0.0 - assert b == b_answer - - def test_group_betweenness_node_not_in_graph(self): - """ - Node(s) in C not in graph, raises NodeNotFound exception - """ - with pytest.raises(nx.NodeNotFound): - nx.group_betweenness_centrality(nx.path_graph(5), [4, 7, 8]) - - def test_group_betweenness_directed_weighted(self): - """ - Group betweenness centrality in a directed and weighted graph - """ - G = nx.DiGraph() - G.add_edge(1, 0, weight=1) - G.add_edge(0, 2, weight=2) - G.add_edge(1, 2, weight=3) - G.add_edge(3, 1, weight=4) - G.add_edge(2, 3, weight=1) - G.add_edge(4, 3, weight=6) - G.add_edge(2, 4, weight=7) - C = [1, 2] - b = nx.group_betweenness_centrality(G, C, weight="weight", normalized=False) - b_answer = 5.0 - assert b == b_answer - - -class TestProminentGroup: - np = pytest.importorskip("numpy") - pd = pytest.importorskip("pandas") - - def test_prominent_group_single_node(self): - """ - Prominent group for single node - """ - G = nx.path_graph(5) - k = 1 - b, g = nx.prominent_group(G, k, normalized=False, endpoints=False) - b_answer, g_answer = 4.0, [2] - assert b == b_answer and g == g_answer - - def test_prominent_group_with_c(self): - """ - Prominent group without some nodes - """ - G = nx.path_graph(5) - k = 1 - b, g = nx.prominent_group(G, k, normalized=False, C=[2]) - b_answer, g_answer = 3.0, [1] - assert b == b_answer and g == g_answer - - def test_prominent_group_normalized_endpoints(self): - """ - Prominent group with normalized result, with endpoints - """ - G = nx.cycle_graph(7) - k = 2 - b, g = nx.prominent_group(G, k, normalized=True, endpoints=True) - b_answer, g_answer = 1.7, [2, 5] - assert b == b_answer and g == g_answer - - def test_prominent_group_disconnected_graph(self): - """ - Prominent group of disconnected graph - """ - G = nx.path_graph(6) - G.remove_edge(0, 1) - k = 1 - b, g = nx.prominent_group(G, k, weight=None, normalized=False) - b_answer, g_answer = 4.0, [3] - assert b == b_answer and g == g_answer - - def test_prominent_group_node_not_in_graph(self): - """ - Node(s) in C not in graph, raises NodeNotFound exception - """ - with pytest.raises(nx.NodeNotFound): - nx.prominent_group(nx.path_graph(5), 1, C=[10]) - - def test_group_betweenness_directed_weighted(self): - """ - Group betweenness centrality in a directed and weighted graph - """ - G = nx.DiGraph() - G.add_edge(1, 0, weight=1) - G.add_edge(0, 2, weight=2) - G.add_edge(1, 2, weight=3) - G.add_edge(3, 1, weight=4) - G.add_edge(2, 3, weight=1) - G.add_edge(4, 3, weight=6) - G.add_edge(2, 4, weight=7) - k = 2 - b, g = nx.prominent_group(G, k, weight="weight", normalized=False) - b_answer, g_answer = 5.0, [1, 2] - assert b == b_answer and g == g_answer - - def test_prominent_group_greedy_algorithm(self): - """ - Group betweenness centrality in a greedy algorithm - """ - G = nx.cycle_graph(7) - k = 2 - b, g = nx.prominent_group(G, k, normalized=True, endpoints=True, greedy=True) - b_answer, g_answer = 1.7, [6, 3] - assert b == b_answer and g == g_answer - - -class TestGroupClosenessCentrality: - def test_group_closeness_single_node(self): - """ - Group closeness centrality for a single node group - """ - G = nx.path_graph(5) - c = nx.group_closeness_centrality(G, [1]) - c_answer = nx.closeness_centrality(G, 1) - assert c == c_answer - - def test_group_closeness_disconnected(self): - """ - Group closeness centrality for a disconnected graph - """ - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - c = nx.group_closeness_centrality(G, [1, 2]) - c_answer = 0 - assert c == c_answer - - def test_group_closeness_multiple_node(self): - """ - Group closeness centrality for a group with more than - 1 node - """ - G = nx.path_graph(4) - c = nx.group_closeness_centrality(G, [1, 2]) - c_answer = 1 - assert c == c_answer - - def test_group_closeness_node_not_in_graph(self): - """ - Node(s) in S not in graph, raises NodeNotFound exception - """ - with pytest.raises(nx.NodeNotFound): - nx.group_closeness_centrality(nx.path_graph(5), [6, 7, 8]) - - -class TestGroupDegreeCentrality: - def test_group_degree_centrality_single_node(self): - """ - Group degree centrality for a single node group - """ - G = nx.path_graph(4) - d = nx.group_degree_centrality(G, [1]) - d_answer = nx.degree_centrality(G)[1] - assert d == d_answer - - def test_group_degree_centrality_multiple_node(self): - """ - Group degree centrality for group with more than - 1 node - """ - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from( - [(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), (2, 3), (2, 4), (2, 5)] - ) - d = nx.group_degree_centrality(G, [1, 2]) - d_answer = 1 - assert d == d_answer - - def test_group_in_degree_centrality(self): - """ - Group in-degree centrality in a DiGraph - """ - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from( - [(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), (2, 3), (2, 4), (2, 5)] - ) - d = nx.group_in_degree_centrality(G, [1, 2]) - d_answer = 0 - assert d == d_answer - - def test_group_out_degree_centrality(self): - """ - Group out-degree centrality in a DiGraph - """ - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from( - [(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), (2, 3), (2, 4), (2, 5)] - ) - d = nx.group_out_degree_centrality(G, [1, 2]) - d_answer = 1 - assert d == d_answer - - def test_group_degree_centrality_node_not_in_graph(self): - """ - Node(s) in S not in graph, raises NetworkXError - """ - with pytest.raises(nx.NetworkXError): - nx.group_degree_centrality(nx.path_graph(5), [6, 7, 8]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_harmonic_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_harmonic_centrality.py deleted file mode 100644 index 4b3dc4a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Tests for degree centrality. -""" - -import pytest - -import networkx as nx -from networkx.algorithms.centrality import harmonic_centrality - - -class TestClosenessCentrality: - @classmethod - def setup_class(cls): - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - - cls.C4 = nx.cycle_graph(4) - cls.C4_directed = nx.cycle_graph(4, create_using=nx.DiGraph) - - cls.C5 = nx.cycle_graph(5) - - cls.T = nx.balanced_tree(r=2, h=2) - - cls.Gb = nx.DiGraph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (0, 4), (2, 1), (2, 3), (4, 3)]) - - def test_p3_harmonic(self): - c = harmonic_centrality(self.P3) - d = {0: 1.5, 1: 2, 2: 1.5} - for n in sorted(self.P3): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_p4_harmonic(self): - c = harmonic_centrality(self.P4) - d = {0: 1.8333333, 1: 2.5, 2: 2.5, 3: 1.8333333} - for n in sorted(self.P4): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_clique_complete(self): - c = harmonic_centrality(self.K5) - d = {0: 4, 1: 4, 2: 4, 3: 4, 4: 4} - for n in sorted(self.P3): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_cycle_C4(self): - c = harmonic_centrality(self.C4) - d = {0: 2.5, 1: 2.5, 2: 2.5, 3: 2.5} - for n in sorted(self.C4): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_cycle_C5(self): - c = harmonic_centrality(self.C5) - d = {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 4} - for n in sorted(self.C5): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_bal_tree(self): - c = harmonic_centrality(self.T) - d = {0: 4.0, 1: 4.1666, 2: 4.1666, 3: 2.8333, 4: 2.8333, 5: 2.8333, 6: 2.8333} - for n in sorted(self.T): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_exampleGraph(self): - c = harmonic_centrality(self.Gb) - d = {0: 0, 1: 2, 2: 1, 3: 2.5, 4: 1} - for n in sorted(self.Gb): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_weighted_harmonic(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("a", "b", 10), - ("d", "c", 5), - ("a", "c", 1), - ("e", "f", 2), - ("f", "c", 1), - ("a", "f", 3), - ] - ) - c = harmonic_centrality(XG, distance="weight") - d = {"a": 0, "b": 0.1, "c": 2.533, "d": 0, "e": 0, "f": 0.83333} - for n in sorted(XG): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_empty(self): - G = nx.DiGraph() - c = harmonic_centrality(G, distance="weight") - d = {} - assert c == d - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - c = harmonic_centrality(G, distance="weight") - d = {0: 0} - assert c == d - - def test_cycle_c4_directed(self): - c = harmonic_centrality(self.C4_directed, nbunch=[0, 1], sources=[1, 2]) - d = {0: 0.833, 1: 0.333} - for n in [0, 1]: - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_cycle_c4_directed_subset(self): - c = harmonic_centrality(self.C4_directed, nbunch=[0, 1]) - d = 1.833 - for n in [0, 1]: - assert c[n] == pytest.approx(d, abs=1e-3) - - def test_p3_harmonic_subset(self): - c = harmonic_centrality(self.P3, sources=[0, 1]) - d = {0: 1, 1: 1, 2: 1.5} - for n in self.P3: - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_p4_harmonic_subset(self): - c = harmonic_centrality(self.P4, nbunch=[2, 3], sources=[0, 1]) - d = {2: 1.5, 3: 0.8333333} - for n in [2, 3]: - assert c[n] == pytest.approx(d[n], abs=1e-3) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_katz_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_katz_centrality.py deleted file mode 100644 index 0927f00..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_katz_centrality.py +++ /dev/null @@ -1,345 +0,0 @@ -import math - -import pytest - -import networkx as nx - - -class TestKatzCentrality: - def test_K5(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - nstart = {n: 1 for n in G} - b = nx.katz_centrality(G, alpha, nstart=nstart) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - - def test_P3(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - b = nx.katz_centrality(G, alpha) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_maxiter(self): - with pytest.raises(nx.PowerIterationFailedConvergence): - nx.katz_centrality(nx.path_graph(3), 0.1, max_iter=0) - - def test_beta_as_scalar(self): - alpha = 0.1 - beta = 0.1 - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha, beta) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_beta_as_dict(self): - alpha = 0.1 - beta = {0: 1.0, 1: 1.0, 2: 1.0} - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha, beta) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_multiple_alpha(self): - alpha_list = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6] - for alpha in alpha_list: - b_answer = { - 0.1: { - 0: 0.5598852584152165, - 1: 0.6107839182711449, - 2: 0.5598852584152162, - }, - 0.2: { - 0: 0.5454545454545454, - 1: 0.6363636363636365, - 2: 0.5454545454545454, - }, - 0.3: { - 0: 0.5333964609104419, - 1: 0.6564879518897746, - 2: 0.5333964609104419, - }, - 0.4: { - 0: 0.5232045649263551, - 1: 0.6726915834767423, - 2: 0.5232045649263551, - }, - 0.5: { - 0: 0.5144957746691622, - 1: 0.6859943117075809, - 2: 0.5144957746691622, - }, - 0.6: { - 0: 0.5069794004195823, - 1: 0.6970966755769258, - 2: 0.5069794004195823, - }, - } - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[alpha][n], abs=1e-4) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - nx.katz_centrality(nx.MultiGraph(), 0.1) - - def test_empty(self): - e = nx.katz_centrality(nx.Graph(), 0.1) - assert e == {} - - def test_bad_beta(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - beta = {0: 77} - nx.katz_centrality(G, 0.1, beta=beta) - - def test_bad_beta_number(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - nx.katz_centrality(G, 0.1, beta="foo") - - -class TestKatzCentralityNumpy: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - def test_K5(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_P3(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - b = nx.katz_centrality_numpy(G, alpha) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_beta_as_scalar(self): - alpha = 0.1 - beta = 0.1 - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha, beta) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_beta_as_dict(self): - alpha = 0.1 - beta = {0: 1.0, 1: 1.0, 2: 1.0} - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha, beta) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - def test_multiple_alpha(self): - alpha_list = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6] - for alpha in alpha_list: - b_answer = { - 0.1: { - 0: 0.5598852584152165, - 1: 0.6107839182711449, - 2: 0.5598852584152162, - }, - 0.2: { - 0: 0.5454545454545454, - 1: 0.6363636363636365, - 2: 0.5454545454545454, - }, - 0.3: { - 0: 0.5333964609104419, - 1: 0.6564879518897746, - 2: 0.5333964609104419, - }, - 0.4: { - 0: 0.5232045649263551, - 1: 0.6726915834767423, - 2: 0.5232045649263551, - }, - 0.5: { - 0: 0.5144957746691622, - 1: 0.6859943117075809, - 2: 0.5144957746691622, - }, - 0.6: { - 0: 0.5069794004195823, - 1: 0.6970966755769258, - 2: 0.5069794004195823, - }, - } - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[alpha][n], abs=1e-4) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - nx.katz_centrality(nx.MultiGraph(), 0.1) - - def test_empty(self): - e = nx.katz_centrality(nx.Graph(), 0.1) - assert e == {} - - def test_bad_beta(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - beta = {0: 77} - nx.katz_centrality_numpy(G, 0.1, beta=beta) - - def test_bad_beta_numbe(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - nx.katz_centrality_numpy(G, 0.1, beta="foo") - - def test_K5_unweighted(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha, weight=None) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-7) - b = nx.eigenvector_centrality_numpy(G, weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-3) - - def test_P3_unweighted(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, 2: 0.5598852584152162} - b = nx.katz_centrality_numpy(G, alpha, weight=None) - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-4) - - -class TestKatzCentralityDirected: - @classmethod - def setup_class(cls): - G = nx.DiGraph() - edges = [ - (1, 2), - (1, 3), - (2, 4), - (3, 2), - (3, 5), - (4, 2), - (4, 5), - (4, 6), - (5, 6), - (5, 7), - (5, 8), - (6, 8), - (7, 1), - (7, 5), - (7, 8), - (8, 6), - (8, 7), - ] - G.add_edges_from(edges, weight=2.0) - cls.G = G.reverse() - cls.G.alpha = 0.1 - cls.G.evc = [ - 0.3289589783189635, - 0.2832077296243516, - 0.3425906003685471, - 0.3970420865198392, - 0.41074871061646284, - 0.272257430756461, - 0.4201989685435462, - 0.34229059218038554, - ] - - H = nx.DiGraph(edges) - cls.H = G.reverse() - cls.H.alpha = 0.1 - cls.H.evc = [ - 0.3289589783189635, - 0.2832077296243516, - 0.3425906003685471, - 0.3970420865198392, - 0.41074871061646284, - 0.272257430756461, - 0.4201989685435462, - 0.34229059218038554, - ] - - def test_katz_centrality_weighted(self): - G = self.G - alpha = self.G.alpha - p = nx.katz_centrality(G, alpha, weight="weight") - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-7) - - def test_katz_centrality_unweighted(self): - H = self.H - alpha = self.H.alpha - p = nx.katz_centrality(H, alpha, weight="weight") - for a, b in zip(list(p.values()), self.H.evc): - assert a == pytest.approx(b, abs=1e-7) - - -class TestKatzCentralityDirectedNumpy(TestKatzCentralityDirected): - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - super().setup_class() - - def test_katz_centrality_weighted(self): - G = self.G - alpha = self.G.alpha - p = nx.katz_centrality_numpy(G, alpha, weight="weight") - for a, b in zip(list(p.values()), self.G.evc): - assert a == pytest.approx(b, abs=1e-7) - - def test_katz_centrality_unweighted(self): - H = self.H - alpha = self.H.alpha - p = nx.katz_centrality_numpy(H, alpha, weight="weight") - for a, b in zip(list(p.values()), self.H.evc): - assert a == pytest.approx(b, abs=1e-7) - - -class TestKatzEigenvectorVKatz: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - def test_eigenvector_v_katz_random(self): - G = nx.gnp_random_graph(10, 0.5, seed=1234) - l = max(np.linalg.eigvals(nx.adjacency_matrix(G).todense())) - e = nx.eigenvector_centrality_numpy(G) - k = nx.katz_centrality_numpy(G, 1.0 / l) - for n in G: - assert e[n] == pytest.approx(k[n], abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_laplacian_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_laplacian_centrality.py deleted file mode 100644 index 21aa28b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +++ /dev/null @@ -1,221 +0,0 @@ -import pytest - -import networkx as nx - -np = pytest.importorskip("numpy") -sp = pytest.importorskip("scipy") - - -def test_laplacian_centrality_null_graph(): - G = nx.Graph() - with pytest.raises(nx.NetworkXPointlessConcept): - d = nx.laplacian_centrality(G, normalized=False) - - -def test_laplacian_centrality_single_node(): - """See gh-6571""" - G = nx.empty_graph(1) - assert nx.laplacian_centrality(G, normalized=False) == {0: 0} - with pytest.raises(ZeroDivisionError): - nx.laplacian_centrality(G, normalized=True) - - -def test_laplacian_centrality_unconnected_nodes(): - """laplacian_centrality on a unconnected node graph should return 0 - - For graphs without edges, the Laplacian energy is 0 and is unchanged with - node removal, so:: - - LC(v) = LE(G) - LE(G - v) = 0 - 0 = 0 - """ - G = nx.empty_graph(3) - assert nx.laplacian_centrality(G, normalized=False) == {0: 0, 1: 0, 2: 0} - - -def test_laplacian_centrality_empty_graph(): - G = nx.empty_graph(3) - with pytest.raises(ZeroDivisionError): - d = nx.laplacian_centrality(G, normalized=True) - - -def test_laplacian_centrality_E(): - E = nx.Graph() - E.add_weighted_edges_from( - [(0, 1, 4), (4, 5, 1), (0, 2, 2), (2, 1, 1), (1, 3, 2), (1, 4, 2)] - ) - d = nx.laplacian_centrality(E) - exact = { - 0: 0.700000, - 1: 0.900000, - 2: 0.280000, - 3: 0.220000, - 4: 0.260000, - 5: 0.040000, - } - - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - # Check not normalized - full_energy = 200 - dnn = nx.laplacian_centrality(E, normalized=False) - for n, dc in dnn.items(): - assert exact[n] * full_energy == pytest.approx(dc, abs=1e-7) - - # Check unweighted not-normalized version - duw_nn = nx.laplacian_centrality(E, normalized=False, weight=None) - print(duw_nn) - exact_uw_nn = { - 0: 18, - 1: 34, - 2: 18, - 3: 10, - 4: 16, - 5: 6, - } - for n, dc in duw_nn.items(): - assert exact_uw_nn[n] == pytest.approx(dc, abs=1e-7) - - # Check unweighted version - duw = nx.laplacian_centrality(E, weight=None) - full_energy = 42 - for n, dc in duw.items(): - assert exact_uw_nn[n] / full_energy == pytest.approx(dc, abs=1e-7) - - -def test_laplacian_centrality_KC(): - KC = nx.karate_club_graph() - d = nx.laplacian_centrality(KC) - exact = { - 0: 0.2543593, - 1: 0.1724524, - 2: 0.2166053, - 3: 0.0964646, - 4: 0.0350344, - 5: 0.0571109, - 6: 0.0540713, - 7: 0.0788674, - 8: 0.1222204, - 9: 0.0217565, - 10: 0.0308751, - 11: 0.0215965, - 12: 0.0174372, - 13: 0.118861, - 14: 0.0366341, - 15: 0.0548712, - 16: 0.0172772, - 17: 0.0191969, - 18: 0.0225564, - 19: 0.0331147, - 20: 0.0279955, - 21: 0.0246361, - 22: 0.0382339, - 23: 0.1294193, - 24: 0.0227164, - 25: 0.0644697, - 26: 0.0281555, - 27: 0.075188, - 28: 0.0364742, - 29: 0.0707087, - 30: 0.0708687, - 31: 0.131019, - 32: 0.2370821, - 33: 0.3066709, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - # Check not normalized - full_energy = 12502 - dnn = nx.laplacian_centrality(KC, normalized=False) - for n, dc in dnn.items(): - assert exact[n] * full_energy == pytest.approx(dc, abs=1e-3) - - -def test_laplacian_centrality_K(): - K = nx.krackhardt_kite_graph() - d = nx.laplacian_centrality(K) - exact = { - 0: 0.3010753, - 1: 0.3010753, - 2: 0.2258065, - 3: 0.483871, - 4: 0.2258065, - 5: 0.3870968, - 6: 0.3870968, - 7: 0.1935484, - 8: 0.0752688, - 9: 0.0322581, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - # Check not normalized - full_energy = 186 - dnn = nx.laplacian_centrality(K, normalized=False) - for n, dc in dnn.items(): - assert exact[n] * full_energy == pytest.approx(dc, abs=1e-3) - - -def test_laplacian_centrality_P3(): - P3 = nx.path_graph(3) - d = nx.laplacian_centrality(P3) - exact = {0: 0.6, 1: 1.0, 2: 0.6} - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - -def test_laplacian_centrality_K5(): - K5 = nx.complete_graph(5) - d = nx.laplacian_centrality(K5) - exact = {0: 0.52, 1: 0.52, 2: 0.52, 3: 0.52, 4: 0.52} - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - -def test_laplacian_centrality_FF(): - FF = nx.florentine_families_graph() - d = nx.laplacian_centrality(FF) - exact = { - "Acciaiuoli": 0.0804598, - "Medici": 0.4022989, - "Castellani": 0.1724138, - "Peruzzi": 0.183908, - "Strozzi": 0.2528736, - "Barbadori": 0.137931, - "Ridolfi": 0.2183908, - "Tornabuoni": 0.2183908, - "Albizzi": 0.1954023, - "Salviati": 0.1149425, - "Pazzi": 0.0344828, - "Bischeri": 0.1954023, - "Guadagni": 0.2298851, - "Ginori": 0.045977, - "Lamberteschi": 0.0574713, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - -def test_laplacian_centrality_DG(): - DG = nx.DiGraph([(0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 6), (5, 7), (5, 8)]) - d = nx.laplacian_centrality(DG) - exact = { - 0: 0.2123352, - 5: 0.515391, - 1: 0.2123352, - 2: 0.2123352, - 3: 0.2123352, - 4: 0.2123352, - 6: 0.2952031, - 7: 0.2952031, - 8: 0.2952031, - } - for n, dc in d.items(): - assert exact[n] == pytest.approx(dc, abs=1e-7) - - # Check not normalized - full_energy = 9.50704 - dnn = nx.laplacian_centrality(DG, normalized=False) - for n, dc in dnn.items(): - assert exact[n] * full_energy == pytest.approx(dc, abs=1e-4) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_load_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_load_centrality.py deleted file mode 100644 index bf09603..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_load_centrality.py +++ /dev/null @@ -1,344 +0,0 @@ -import pytest - -import networkx as nx - - -class TestLoadCentrality: - @classmethod - def setup_class(cls): - G = nx.Graph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - cls.G = G - cls.exact_weighted = {0: 4.0, 1: 0.0, 2: 8.0, 3: 6.0, 4: 8.0, 5: 0.0} - cls.K = nx.krackhardt_kite_graph() - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - cls.P2 = nx.path_graph(2) - - cls.C4 = nx.cycle_graph(4) - cls.T = nx.balanced_tree(r=2, h=2) - cls.Gb = nx.Graph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - cls.F = nx.florentine_families_graph() - cls.LM = nx.les_miserables_graph() - cls.D = nx.cycle_graph(3, create_using=nx.DiGraph()) - cls.D.add_edges_from([(3, 0), (4, 3)]) - - def test_not_strongly_connected(self): - b = nx.load_centrality(self.D) - result = {0: 5.0 / 12, 1: 1.0 / 4, 2: 1.0 / 12, 3: 1.0 / 4, 4: 0.000} - for n in sorted(self.D): - assert result[n] == pytest.approx(b[n], abs=1e-3) - assert result[n] == pytest.approx(nx.load_centrality(self.D, n), abs=1e-3) - - def test_P2_normalized_load(self): - G = self.P2 - c = nx.load_centrality(G, normalized=True) - d = {0: 0.000, 1: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_weighted_load(self): - b = nx.load_centrality(self.G, weight="weight", normalized=False) - for n in sorted(self.G): - assert b[n] == self.exact_weighted[n] - - def test_k5_load(self): - G = self.K5 - c = nx.load_centrality(G) - d = {0: 0.000, 1: 0.000, 2: 0.000, 3: 0.000, 4: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_p3_load(self): - G = self.P3 - c = nx.load_centrality(G) - d = {0: 0.000, 1: 1.000, 2: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - c = nx.load_centrality(G, v=1) - assert c == pytest.approx(1.0, abs=1e-7) - c = nx.load_centrality(G, v=1, normalized=True) - assert c == pytest.approx(1.0, abs=1e-7) - - def test_p2_load(self): - G = nx.path_graph(2) - c = nx.load_centrality(G) - d = {0: 0.000, 1: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_krackhardt_load(self): - G = self.K - c = nx.load_centrality(G) - d = { - 0: 0.023, - 1: 0.023, - 2: 0.000, - 3: 0.102, - 4: 0.000, - 5: 0.231, - 6: 0.231, - 7: 0.389, - 8: 0.222, - 9: 0.000, - } - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_florentine_families_load(self): - G = self.F - c = nx.load_centrality(G) - d = { - "Acciaiuoli": 0.000, - "Albizzi": 0.211, - "Barbadori": 0.093, - "Bischeri": 0.104, - "Castellani": 0.055, - "Ginori": 0.000, - "Guadagni": 0.251, - "Lamberteschi": 0.000, - "Medici": 0.522, - "Pazzi": 0.000, - "Peruzzi": 0.022, - "Ridolfi": 0.117, - "Salviati": 0.143, - "Strozzi": 0.106, - "Tornabuoni": 0.090, - } - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_les_miserables_load(self): - G = self.LM - c = nx.load_centrality(G) - d = { - "Napoleon": 0.000, - "Myriel": 0.177, - "MlleBaptistine": 0.000, - "MmeMagloire": 0.000, - "CountessDeLo": 0.000, - "Geborand": 0.000, - "Champtercier": 0.000, - "Cravatte": 0.000, - "Count": 0.000, - "OldMan": 0.000, - "Valjean": 0.567, - "Labarre": 0.000, - "Marguerite": 0.000, - "MmeDeR": 0.000, - "Isabeau": 0.000, - "Gervais": 0.000, - "Listolier": 0.000, - "Tholomyes": 0.043, - "Fameuil": 0.000, - "Blacheville": 0.000, - "Favourite": 0.000, - "Dahlia": 0.000, - "Zephine": 0.000, - "Fantine": 0.128, - "MmeThenardier": 0.029, - "Thenardier": 0.075, - "Cosette": 0.024, - "Javert": 0.054, - "Fauchelevent": 0.026, - "Bamatabois": 0.008, - "Perpetue": 0.000, - "Simplice": 0.009, - "Scaufflaire": 0.000, - "Woman1": 0.000, - "Judge": 0.000, - "Champmathieu": 0.000, - "Brevet": 0.000, - "Chenildieu": 0.000, - "Cochepaille": 0.000, - "Pontmercy": 0.007, - "Boulatruelle": 0.000, - "Eponine": 0.012, - "Anzelma": 0.000, - "Woman2": 0.000, - "MotherInnocent": 0.000, - "Gribier": 0.000, - "MmeBurgon": 0.026, - "Jondrette": 0.000, - "Gavroche": 0.164, - "Gillenormand": 0.021, - "Magnon": 0.000, - "MlleGillenormand": 0.047, - "MmePontmercy": 0.000, - "MlleVaubois": 0.000, - "LtGillenormand": 0.000, - "Marius": 0.133, - "BaronessT": 0.000, - "Mabeuf": 0.028, - "Enjolras": 0.041, - "Combeferre": 0.001, - "Prouvaire": 0.000, - "Feuilly": 0.001, - "Courfeyrac": 0.006, - "Bahorel": 0.002, - "Bossuet": 0.032, - "Joly": 0.002, - "Grantaire": 0.000, - "MotherPlutarch": 0.000, - "Gueulemer": 0.005, - "Babet": 0.005, - "Claquesous": 0.005, - "Montparnasse": 0.004, - "Toussaint": 0.000, - "Child1": 0.000, - "Child2": 0.000, - "Brujon": 0.000, - "MmeHucheloup": 0.000, - } - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_unnormalized_k5_load(self): - G = self.K5 - c = nx.load_centrality(G, normalized=False) - d = {0: 0.000, 1: 0.000, 2: 0.000, 3: 0.000, 4: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_unnormalized_p3_load(self): - G = self.P3 - c = nx.load_centrality(G, normalized=False) - d = {0: 0.000, 1: 2.000, 2: 0.000} - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_unnormalized_krackhardt_load(self): - G = self.K - c = nx.load_centrality(G, normalized=False) - d = { - 0: 1.667, - 1: 1.667, - 2: 0.000, - 3: 7.333, - 4: 0.000, - 5: 16.667, - 6: 16.667, - 7: 28.000, - 8: 16.000, - 9: 0.000, - } - - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_unnormalized_florentine_families_load(self): - G = self.F - c = nx.load_centrality(G, normalized=False) - - d = { - "Acciaiuoli": 0.000, - "Albizzi": 38.333, - "Barbadori": 17.000, - "Bischeri": 19.000, - "Castellani": 10.000, - "Ginori": 0.000, - "Guadagni": 45.667, - "Lamberteschi": 0.000, - "Medici": 95.000, - "Pazzi": 0.000, - "Peruzzi": 4.000, - "Ridolfi": 21.333, - "Salviati": 26.000, - "Strozzi": 19.333, - "Tornabuoni": 16.333, - } - for n in sorted(G): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_load_betweenness_difference(self): - # Difference Between Load and Betweenness - # --------------------------------------- The smallest graph - # that shows the difference between load and betweenness is - # G=ladder_graph(3) (Graph B below) - - # Graph A and B are from Tao Zhou, Jian-Guo Liu, Bing-Hong - # Wang: Comment on "Scientific collaboration - # networks. II. Shortest paths, weighted networks, and - # centrality". https://arxiv.org/pdf/physics/0511084 - - # Notice that unlike here, their calculation adds to 1 to the - # betweenness of every node i for every path from i to every - # other node. This is exactly what it should be, based on - # Eqn. (1) in their paper: the eqn is B(v) = \sum_{s\neq t, - # s\neq v}{\frac{\sigma_{st}(v)}{\sigma_{st}}}, therefore, - # they allow v to be the target node. - - # We follow Brandes 2001, who follows Freeman 1977 that make - # the sum for betweenness of v exclude paths where v is either - # the source or target node. To agree with their numbers, we - # must additionally, remove edge (4,8) from the graph, see AC - # example following (there is a mistake in the figure in their - # paper - personal communication). - - # A = nx.Graph() - # A.add_edges_from([(0,1), (1,2), (1,3), (2,4), - # (3,5), (4,6), (4,7), (4,8), - # (5,8), (6,9), (7,9), (8,9)]) - B = nx.Graph() # ladder_graph(3) - B.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - c = nx.load_centrality(B, normalized=False) - d = {0: 1.750, 1: 1.750, 2: 6.500, 3: 6.500, 4: 1.750, 5: 1.750} - for n in sorted(B): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_c4_edge_load(self): - G = self.C4 - c = nx.edge_load_centrality(G) - d = {(0, 1): 6.000, (0, 3): 6.000, (1, 2): 6.000, (2, 3): 6.000} - for n in G.edges(): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_p4_edge_load(self): - G = self.P4 - c = nx.edge_load_centrality(G) - d = {(0, 1): 6.000, (1, 2): 8.000, (2, 3): 6.000} - for n in G.edges(): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_k5_edge_load(self): - G = self.K5 - c = nx.edge_load_centrality(G) - d = { - (0, 1): 5.000, - (0, 2): 5.000, - (0, 3): 5.000, - (0, 4): 5.000, - (1, 2): 5.000, - (1, 3): 5.000, - (1, 4): 5.000, - (2, 3): 5.000, - (2, 4): 5.000, - (3, 4): 5.000, - } - for n in G.edges(): - assert c[n] == pytest.approx(d[n], abs=1e-3) - - def test_tree_edge_load(self): - G = self.T - c = nx.edge_load_centrality(G) - d = { - (0, 1): 24.000, - (0, 2): 24.000, - (1, 3): 12.000, - (1, 4): 12.000, - (2, 5): 12.000, - (2, 6): 12.000, - } - for n in G.edges(): - assert c[n] == pytest.approx(d[n], abs=1e-3) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_percolation_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_percolation_centrality.py deleted file mode 100644 index 0cb8f52..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_percolation_centrality.py +++ /dev/null @@ -1,87 +0,0 @@ -import pytest - -import networkx as nx - - -def example1a_G(): - G = nx.Graph() - G.add_node(1, percolation=0.1) - G.add_node(2, percolation=0.2) - G.add_node(3, percolation=0.2) - G.add_node(4, percolation=0.2) - G.add_node(5, percolation=0.3) - G.add_node(6, percolation=0.2) - G.add_node(7, percolation=0.5) - G.add_node(8, percolation=0.5) - G.add_edges_from([(1, 4), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8)]) - return G - - -def example1b_G(): - G = nx.Graph() - G.add_node(1, percolation=0.3) - G.add_node(2, percolation=0.5) - G.add_node(3, percolation=0.5) - G.add_node(4, percolation=0.2) - G.add_node(5, percolation=0.3) - G.add_node(6, percolation=0.2) - G.add_node(7, percolation=0.1) - G.add_node(8, percolation=0.1) - G.add_edges_from([(1, 4), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8)]) - return G - - -def test_percolation_example1a(): - """percolation centrality: example 1a""" - G = example1a_G() - p = nx.percolation_centrality(G) - p_answer = {4: 0.625, 6: 0.667} - for n, k in p_answer.items(): - assert p[n] == pytest.approx(k, abs=1e-3) - - -def test_percolation_example1b(): - """percolation centrality: example 1a""" - G = example1b_G() - p = nx.percolation_centrality(G) - p_answer = {4: 0.825, 6: 0.4} - for n, k in p_answer.items(): - assert p[n] == pytest.approx(k, abs=1e-3) - - -def test_converge_to_betweenness(): - """percolation centrality: should converge to betweenness - centrality when all nodes are percolated the same""" - # taken from betweenness test test_florentine_families_graph - G = nx.florentine_families_graph() - b_answer = { - "Acciaiuoli": 0.000, - "Albizzi": 0.212, - "Barbadori": 0.093, - "Bischeri": 0.104, - "Castellani": 0.055, - "Ginori": 0.000, - "Guadagni": 0.255, - "Lamberteschi": 0.000, - "Medici": 0.522, - "Pazzi": 0.000, - "Peruzzi": 0.022, - "Ridolfi": 0.114, - "Salviati": 0.143, - "Strozzi": 0.103, - "Tornabuoni": 0.092, - } - - # If no initial state is provided, state for - # every node defaults to 1 - p_answer = nx.percolation_centrality(G) - assert p_answer == pytest.approx(b_answer, abs=1e-3) - - p_states = {k: 0.3 for k, v in b_answer.items()} - p_answer = nx.percolation_centrality(G, states=p_states) - assert p_answer == pytest.approx(b_answer, abs=1e-3) - - -def test_default_percolation(): - G = nx.erdos_renyi_graph(42, 0.42, seed=42) - assert nx.percolation_centrality(G) == pytest.approx(nx.betweenness_centrality(G)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_reaching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_reaching.py deleted file mode 100644 index 35d50e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_reaching.py +++ /dev/null @@ -1,140 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.centrality.reaching` module.""" - -import pytest - -import networkx as nx - - -class TestGlobalReachingCentrality: - """Unit tests for the global reaching centrality function.""" - - def test_non_positive_weights(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - nx.global_reaching_centrality(G, weight="weight") - - def test_negatively_weighted(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, -2), (1, 2, +1)]) - nx.global_reaching_centrality(G, weight="weight") - - def test_directed_star(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 2, 0.5), (1, 3, 0.5)]) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight="weight") == 0.5 - assert grc(G) == 1 - - def test_undirected_unweighted_star(self): - G = nx.star_graph(2) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight=None) == 0.25 - - def test_undirected_weighted_star(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2)]) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight="weight") == 0.375 - - def test_cycle_directed_unweighted(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - assert nx.global_reaching_centrality(G, weight=None) == 0 - - def test_cycle_undirected_unweighted(self): - G = nx.Graph() - G.add_edge(1, 2) - assert nx.global_reaching_centrality(G, weight=None) == 0 - - def test_cycle_directed_weighted(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 2, 1), (2, 1, 1)]) - assert nx.global_reaching_centrality(G) == 0 - - def test_cycle_undirected_weighted(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False) == 0 - - def test_directed_weighted(self): - G = nx.DiGraph() - G.add_edge("A", "B", weight=5) - G.add_edge("B", "C", weight=1) - G.add_edge("B", "D", weight=0.25) - G.add_edge("D", "E", weight=1) - - denom = len(G) - 1 - A_local = sum([5, 3, 2.625, 2.0833333333333]) / denom - B_local = sum([1, 0.25, 0.625]) / denom - C_local = 0 - D_local = sum([1]) / denom - E_local = 0 - - local_reach_ctrs = [A_local, C_local, B_local, D_local, E_local] - max_local = max(local_reach_ctrs) - expected = sum(max_local - lrc for lrc in local_reach_ctrs) / denom - grc = nx.global_reaching_centrality - actual = grc(G, normalized=False, weight="weight") - assert expected == pytest.approx(actual, abs=1e-7) - - def test_single_node_with_cycle(self): - G = nx.DiGraph([(1, 1)]) - with pytest.raises(nx.NetworkXError, match="local_reaching_centrality"): - nx.global_reaching_centrality(G) - - def test_single_node_with_weighted_cycle(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 1, 2)]) - with pytest.raises(nx.NetworkXError, match="local_reaching_centrality"): - nx.global_reaching_centrality(G, weight="weight") - - -class TestLocalReachingCentrality: - """Unit tests for the local reaching centrality function.""" - - def test_non_positive_weights(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - G.add_weighted_edges_from([(0, 1, 0)]) - nx.local_reaching_centrality(G, 0, weight="weight") - - def test_negatively_weighted(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, -2), (1, 2, +1)]) - nx.local_reaching_centrality(G, 0, weight="weight") - - def test_undirected_unweighted_star(self): - G = nx.star_graph(2) - grc = nx.local_reaching_centrality - assert grc(G, 1, weight=None, normalized=False) == 0.75 - - def test_undirected_weighted_star(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2)]) - centrality = nx.local_reaching_centrality( - G, 1, normalized=False, weight="weight" - ) - assert centrality == 1.5 - - def test_undirected_weighted_normalized(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2)]) - centrality = nx.local_reaching_centrality( - G, 1, normalized=True, weight="weight" - ) - assert centrality == 1.0 - - def test_single_node_with_cycle(self): - G = nx.DiGraph([(1, 1)]) - with pytest.raises(nx.NetworkXError, match="local_reaching_centrality"): - nx.local_reaching_centrality(G, 1) - - def test_single_node_with_weighted_cycle(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 1, 2)]) - with pytest.raises(nx.NetworkXError, match="local_reaching_centrality"): - nx.local_reaching_centrality(G, 1, weight="weight") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_second_order_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_second_order_centrality.py deleted file mode 100644 index cc30478..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_second_order_centrality.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Tests for second order centrality. -""" - -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx - - -def test_empty(): - with pytest.raises(nx.NetworkXException): - G = nx.empty_graph() - nx.second_order_centrality(G) - - -def test_non_connected(): - with pytest.raises(nx.NetworkXException): - G = nx.Graph() - G.add_node(0) - G.add_node(1) - nx.second_order_centrality(G) - - -def test_non_negative_edge_weights(): - with pytest.raises(nx.NetworkXException): - G = nx.path_graph(2) - G.add_edge(0, 1, weight=-1) - nx.second_order_centrality(G) - - -def test_weight_attribute(): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1.0), (1, 2, 3.5)], weight="w") - expected = {0: 3.431, 1: 3.082, 2: 5.612} - b = nx.second_order_centrality(G, weight="w") - - for n in sorted(G): - assert b[n] == pytest.approx(expected[n], abs=1e-2) - - -def test_one_node_graph(): - """Second order centrality: single node""" - G = nx.Graph() - G.add_node(0) - G.add_edge(0, 0) - assert nx.second_order_centrality(G)[0] == 0 - - -def test_P3(): - """Second order centrality: line graph, as defined in paper""" - G = nx.path_graph(3) - b_answer = {0: 3.741, 1: 1.414, 2: 3.741} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-2) - - -def test_K3(): - """Second order centrality: complete graph, as defined in paper""" - G = nx.complete_graph(3) - b_answer = {0: 1.414, 1: 1.414, 2: 1.414} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-2) - - -def test_ring_graph(): - """Second order centrality: ring graph, as defined in paper""" - G = nx.cycle_graph(5) - b_answer = {0: 4.472, 1: 4.472, 2: 4.472, 3: 4.472, 4: 4.472} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert b[n] == pytest.approx(b_answer[n], abs=1e-2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_subgraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_subgraph.py deleted file mode 100644 index 7109275..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_subgraph.py +++ /dev/null @@ -1,110 +0,0 @@ -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.algorithms.centrality.subgraph_alg import ( - communicability_betweenness_centrality, - estrada_index, - subgraph_centrality, - subgraph_centrality_exp, -) - - -class TestSubgraph: - def test_subgraph_centrality(self): - answer = {0: 1.5430806348152433, 1: 1.5430806348152433} - result = subgraph_centrality(nx.path_graph(2)) - for k, v in result.items(): - assert answer[k] == pytest.approx(v, abs=1e-7) - - answer1 = { - "1": 1.6445956054135658, - "Albert": 2.4368257358712189, - "Aric": 2.4368257358712193, - "Dan": 3.1306328496328168, - "Franck": 2.3876142275231915, - } - G1 = nx.Graph( - [ - ("Franck", "Aric"), - ("Aric", "Dan"), - ("Dan", "Albert"), - ("Albert", "Franck"), - ("Dan", "1"), - ("Franck", "Albert"), - ] - ) - result1 = subgraph_centrality(G1) - for k, v in result1.items(): - assert answer1[k] == pytest.approx(v, abs=1e-7) - result1 = subgraph_centrality_exp(G1) - for k, v in result1.items(): - assert answer1[k] == pytest.approx(v, abs=1e-7) - - def test_subgraph_centrality_big_graph(self): - g199 = nx.complete_graph(199) - g200 = nx.complete_graph(200) - - comm199 = nx.subgraph_centrality(g199) - comm199_exp = nx.subgraph_centrality_exp(g199) - - comm200 = nx.subgraph_centrality(g200) - comm200_exp = nx.subgraph_centrality_exp(g200) - - def test_communicability_betweenness_centrality_small(self): - result = communicability_betweenness_centrality(nx.path_graph(2)) - assert result == {0: 0, 1: 0} - - result = communicability_betweenness_centrality(nx.path_graph(1)) - assert result == {0: 0} - - result = communicability_betweenness_centrality(nx.path_graph(0)) - assert result == {} - - answer = {0: 0.1411224421177313, 1: 1.0, 2: 0.1411224421177313} - result = communicability_betweenness_centrality(nx.path_graph(3)) - for k, v in result.items(): - assert answer[k] == pytest.approx(v, abs=1e-7) - - result = communicability_betweenness_centrality(nx.complete_graph(3)) - for k, v in result.items(): - assert 0.49786143366223296 == pytest.approx(v, abs=1e-7) - - def test_communicability_betweenness_centrality(self): - answer = { - 0: 0.07017447951484615, - 1: 0.71565598701107991, - 2: 0.71565598701107991, - 3: 0.07017447951484615, - } - result = communicability_betweenness_centrality(nx.path_graph(4)) - for k, v in result.items(): - assert answer[k] == pytest.approx(v, abs=1e-7) - - answer1 = { - "1": 0.060039074193949521, - "Albert": 0.315470761661372, - "Aric": 0.31547076166137211, - "Dan": 0.68297778678316201, - "Franck": 0.21977926617449497, - } - G1 = nx.Graph( - [ - ("Franck", "Aric"), - ("Aric", "Dan"), - ("Dan", "Albert"), - ("Albert", "Franck"), - ("Dan", "1"), - ("Franck", "Albert"), - ] - ) - result1 = communicability_betweenness_centrality(G1) - for k, v in result1.items(): - assert answer1[k] == pytest.approx(v, abs=1e-7) - - def test_estrada_index(self): - answer = 1041.2470334195475 - result = estrada_index(nx.karate_club_graph()) - assert answer == pytest.approx(result, abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_trophic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_trophic.py deleted file mode 100644 index e6880d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_trophic.py +++ /dev/null @@ -1,302 +0,0 @@ -"""Test trophic levels, trophic differences and trophic coherence""" - -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx - - -def test_trophic_levels(): - """Trivial example""" - G = nx.DiGraph() - G.add_edge("a", "b") - G.add_edge("b", "c") - - d = nx.trophic_levels(G) - assert d == {"a": 1, "b": 2, "c": 3} - - -def test_trophic_levels_levine(): - """Example from Figure 5 in Stephen Levine (1980) J. theor. Biol. 83, - 195-207 - """ - S = nx.DiGraph() - S.add_edge(1, 2, weight=1.0) - S.add_edge(1, 3, weight=0.2) - S.add_edge(1, 4, weight=0.8) - S.add_edge(2, 3, weight=0.2) - S.add_edge(2, 5, weight=0.3) - S.add_edge(4, 3, weight=0.6) - S.add_edge(4, 5, weight=0.7) - S.add_edge(5, 4, weight=0.2) - - # save copy for later, test intermediate implementation details first - S2 = S.copy() - - # drop nodes of in-degree zero - z = [nid for nid, d in S.in_degree if d == 0] - for nid in z: - S.remove_node(nid) - - # find adjacency matrix - q = nx.linalg.graphmatrix.adjacency_matrix(S).T - - # fmt: off - expected_q = np.array([ - [0, 0, 0., 0], - [0.2, 0, 0.6, 0], - [0, 0, 0, 0.2], - [0.3, 0, 0.7, 0] - ]) - # fmt: on - assert np.array_equal(q.todense(), expected_q) - - # must be square, size of number of nodes - assert len(q.shape) == 2 - assert q.shape[0] == q.shape[1] - assert q.shape[0] == len(S) - - nn = q.shape[0] - - i = np.eye(nn) - n = np.linalg.inv(i - q) - y = np.asarray(n) @ np.ones(nn) - - expected_y = np.array([1, 2.07906977, 1.46511628, 2.3255814]) - assert np.allclose(y, expected_y) - - expected_d = {1: 1, 2: 2, 3: 3.07906977, 4: 2.46511628, 5: 3.3255814} - - d = nx.trophic_levels(S2) - - for nid, level in d.items(): - expected_level = expected_d[nid] - assert expected_level == pytest.approx(level, abs=1e-7) - - -def test_trophic_levels_simple(): - matrix_a = np.array([[0, 0], [1, 0]]) - G = nx.from_numpy_array(matrix_a, create_using=nx.DiGraph) - d = nx.trophic_levels(G) - assert d[0] == pytest.approx(2, abs=1e-7) - assert d[1] == pytest.approx(1, abs=1e-7) - - -def test_trophic_levels_more_complex(): - # fmt: off - matrix = np.array([ - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix, create_using=nx.DiGraph) - d = nx.trophic_levels(G) - expected_result = [1, 2, 3, 4] - for ind in range(4): - assert d[ind] == pytest.approx(expected_result[ind], abs=1e-7) - - # fmt: off - matrix = np.array([ - [0, 1, 1, 0], - [0, 0, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix, create_using=nx.DiGraph) - d = nx.trophic_levels(G) - - expected_result = [1, 2, 2.5, 3.25] - print("Calculated result: ", d) - print("Expected Result: ", expected_result) - - for ind in range(4): - assert d[ind] == pytest.approx(expected_result[ind], abs=1e-7) - - -def test_trophic_levels_even_more_complex(): - # fmt: off - # Another, bigger matrix - matrix = np.array([ - [0, 0, 0, 0, 0], - [0, 1, 0, 1, 0], - [1, 0, 0, 0, 0], - [0, 1, 0, 0, 0], - [0, 0, 0, 1, 0] - ]) - # Generated this linear system using pen and paper: - K = np.array([ - [1, 0, -1, 0, 0], - [0, 0.5, 0, -0.5, 0], - [0, 0, 1, 0, 0], - [0, -0.5, 0, 1, -0.5], - [0, 0, 0, 0, 1], - ]) - # fmt: on - result_1 = np.ravel(np.linalg.inv(K) @ np.ones(5)) - G = nx.from_numpy_array(matrix, create_using=nx.DiGraph) - result_2 = nx.trophic_levels(G) - - for ind in range(5): - assert result_1[ind] == pytest.approx(result_2[ind], abs=1e-7) - - -def test_trophic_levels_singular_matrix(): - """Should raise an error with graphs with only non-basal nodes""" - matrix = np.identity(4) - G = nx.from_numpy_array(matrix, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError) as e: - nx.trophic_levels(G) - msg = ( - "Trophic levels are only defined for graphs where every node " - + "has a path from a basal node (basal nodes are nodes with no " - + "incoming edges)." - ) - assert msg in str(e.value) - - -def test_trophic_levels_singular_with_basal(): - """Should fail to compute if there are any parts of the graph which are not - reachable from any basal node (with in-degree zero). - """ - G = nx.DiGraph() - # a has in-degree zero - G.add_edge("a", "b") - - # b is one level above a, c and d - G.add_edge("c", "b") - G.add_edge("d", "b") - - # c and d form a loop, neither are reachable from a - G.add_edge("c", "d") - G.add_edge("d", "c") - - with pytest.raises(nx.NetworkXError) as e: - nx.trophic_levels(G) - msg = ( - "Trophic levels are only defined for graphs where every node " - + "has a path from a basal node (basal nodes are nodes with no " - + "incoming edges)." - ) - assert msg in str(e.value) - - # if self-loops are allowed, smaller example: - G = nx.DiGraph() - G.add_edge("a", "b") # a has in-degree zero - G.add_edge("c", "b") # b is one level above a and c - G.add_edge("c", "c") # c has a self-loop - with pytest.raises(nx.NetworkXError) as e: - nx.trophic_levels(G) - msg = ( - "Trophic levels are only defined for graphs where every node " - + "has a path from a basal node (basal nodes are nodes with no " - + "incoming edges)." - ) - assert msg in str(e.value) - - -def test_trophic_differences(): - matrix_a = np.array([[0, 1], [0, 0]]) - G = nx.from_numpy_array(matrix_a, create_using=nx.DiGraph) - diffs = nx.trophic_differences(G) - assert diffs[(0, 1)] == pytest.approx(1, abs=1e-7) - - # fmt: off - matrix_b = np.array([ - [0, 1, 1, 0], - [0, 0, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_b, create_using=nx.DiGraph) - diffs = nx.trophic_differences(G) - - assert diffs[(0, 1)] == pytest.approx(1, abs=1e-7) - assert diffs[(0, 2)] == pytest.approx(1.5, abs=1e-7) - assert diffs[(1, 2)] == pytest.approx(0.5, abs=1e-7) - assert diffs[(1, 3)] == pytest.approx(1.25, abs=1e-7) - assert diffs[(2, 3)] == pytest.approx(0.75, abs=1e-7) - - -def test_trophic_incoherence_parameter_no_cannibalism(): - matrix_a = np.array([[0, 1], [0, 0]]) - G = nx.from_numpy_array(matrix_a, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=False) - assert q == pytest.approx(0, abs=1e-7) - - # fmt: off - matrix_b = np.array([ - [0, 1, 1, 0], - [0, 0, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_b, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=False) - assert q == pytest.approx(np.std([1, 1.5, 0.5, 0.75, 1.25]), abs=1e-7) - - # fmt: off - matrix_c = np.array([ - [0, 1, 1, 0], - [0, 1, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 1] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_c, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=False) - # Ignore the -link - assert q == pytest.approx(np.std([1, 1.5, 0.5, 0.75, 1.25]), abs=1e-7) - - # no self-loops case - # fmt: off - matrix_d = np.array([ - [0, 1, 1, 0], - [0, 0, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_d, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=False) - # Ignore the -link - assert q == pytest.approx(np.std([1, 1.5, 0.5, 0.75, 1.25]), abs=1e-7) - - -def test_trophic_incoherence_parameter_cannibalism(): - matrix_a = np.array([[0, 1], [0, 0]]) - G = nx.from_numpy_array(matrix_a, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=True) - assert q == pytest.approx(0, abs=1e-7) - - # fmt: off - matrix_b = np.array([ - [0, 0, 0, 0, 0], - [0, 1, 0, 1, 0], - [1, 0, 0, 0, 0], - [0, 1, 0, 0, 0], - [0, 0, 0, 1, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_b, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=True) - assert q == pytest.approx(2, abs=1e-7) - - # fmt: off - matrix_c = np.array([ - [0, 1, 1, 0], - [0, 0, 1, 1], - [0, 0, 0, 1], - [0, 0, 0, 0] - ]) - # fmt: on - G = nx.from_numpy_array(matrix_c, create_using=nx.DiGraph) - q = nx.trophic_incoherence_parameter(G, cannibalism=True) - # Ignore the -link - assert q == pytest.approx(np.std([1, 1.5, 0.5, 0.75, 1.25]), abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_voterank.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_voterank.py deleted file mode 100644 index a5cfb61..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/tests/test_voterank.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Unit tests for VoteRank. -""" - -import networkx as nx - - -class TestVoteRankCentrality: - # Example Graph present in reference paper - def test_voterank_centrality_1(self): - G = nx.Graph() - G.add_edges_from( - [ - (7, 8), - (7, 5), - (7, 9), - (5, 0), - (0, 1), - (0, 2), - (0, 3), - (0, 4), - (1, 6), - (2, 6), - (3, 6), - (4, 6), - ] - ) - assert [0, 7, 6] == nx.voterank(G) - - def test_voterank_emptygraph(self): - G = nx.Graph() - assert [] == nx.voterank(G) - - # Graph unit test - def test_voterank_centrality_2(self): - G = nx.florentine_families_graph() - d = nx.voterank(G, 4) - exact = ["Medici", "Strozzi", "Guadagni", "Castellani"] - assert exact == d - - # DiGraph unit test - def test_voterank_centrality_3(self): - G = nx.gnc_graph(10, seed=7) - d = nx.voterank(G, 4) - exact = [3, 6, 8] - assert exact == d - - # MultiGraph unit test - def test_voterank_centrality_4(self): - G = nx.MultiGraph() - G.add_edges_from( - [(0, 1), (0, 1), (1, 2), (2, 5), (2, 5), (5, 6), (5, 6), (2, 4), (4, 3)] - ) - exact = [2, 1, 5, 4] - assert exact == nx.voterank(G) - - # MultiDiGraph unit test - def test_voterank_centrality_5(self): - G = nx.MultiDiGraph() - G.add_edges_from( - [(0, 1), (0, 1), (1, 2), (2, 5), (2, 5), (5, 6), (5, 6), (2, 4), (4, 3)] - ) - exact = [2, 0, 5, 4] - assert exact == nx.voterank(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/trophic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/trophic.py deleted file mode 100644 index 9e461ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/trophic.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Trophic levels""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["trophic_levels", "trophic_differences", "trophic_incoherence_parameter"] - - -@not_implemented_for("undirected") -@nx._dispatchable(edge_attrs="weight") -def trophic_levels(G, weight="weight"): - r"""Compute the trophic levels of nodes. - - The trophic level of a node $i$ is - - .. math:: - - s_i = 1 + \frac{1}{k^{in}_i} \sum_{j} a_{ij} s_j - - where $k^{in}_i$ is the in-degree of i - - .. math:: - - k^{in}_i = \sum_{j} a_{ij} - - and nodes with $k^{in}_i = 0$ have $s_i = 1$ by convention. - - These are calculated using the method outlined in Levine [1]_. - - Parameters - ---------- - G : DiGraph - A directed networkx graph - - Returns - ------- - nodes : dict - Dictionary of nodes with trophic level as the value. - - References - ---------- - .. [1] Stephen Levine (1980) J. theor. Biol. 83, 195-207 - """ - import numpy as np - - # find adjacency matrix - a = nx.adjacency_matrix(G, weight=weight).T.toarray() - - # drop rows/columns where in-degree is zero - rowsum = np.sum(a, axis=1) - p = a[rowsum != 0][:, rowsum != 0] - # normalise so sum of in-degree weights is 1 along each row - p = p / rowsum[rowsum != 0][:, np.newaxis] - - # calculate trophic levels - nn = p.shape[0] - i = np.eye(nn) - try: - n = np.linalg.inv(i - p) - except np.linalg.LinAlgError as err: - # LinAlgError is raised when there is a non-basal node - msg = ( - "Trophic levels are only defined for graphs where every " - + "node has a path from a basal node (basal nodes are nodes " - + "with no incoming edges)." - ) - raise nx.NetworkXError(msg) from err - y = n.sum(axis=1) + 1 - - levels = {} - - # all nodes with in-degree zero have trophic level == 1 - zero_node_ids = (node_id for node_id, degree in G.in_degree if degree == 0) - for node_id in zero_node_ids: - levels[node_id] = 1 - - # all other nodes have levels as calculated - nonzero_node_ids = (node_id for node_id, degree in G.in_degree if degree != 0) - for i, node_id in enumerate(nonzero_node_ids): - levels[node_id] = y.item(i) - - return levels - - -@not_implemented_for("undirected") -@nx._dispatchable(edge_attrs="weight") -def trophic_differences(G, weight="weight"): - r"""Compute the trophic differences of the edges of a directed graph. - - The trophic difference $x_ij$ for each edge is defined in Johnson et al. - [1]_ as: - - .. math:: - x_ij = s_j - s_i - - Where $s_i$ is the trophic level of node $i$. - - Parameters - ---------- - G : DiGraph - A directed networkx graph - - Returns - ------- - diffs : dict - Dictionary of edges with trophic differences as the value. - - References - ---------- - .. [1] Samuel Johnson, Virginia Dominguez-Garcia, Luca Donetti, Miguel A. - Munoz (2014) PNAS "Trophic coherence determines food-web stability" - """ - levels = trophic_levels(G, weight=weight) - diffs = {} - for u, v in G.edges: - diffs[(u, v)] = levels[v] - levels[u] - return diffs - - -@not_implemented_for("undirected") -@nx._dispatchable(edge_attrs="weight") -def trophic_incoherence_parameter(G, weight="weight", cannibalism=False): - r"""Compute the trophic incoherence parameter of a graph. - - Trophic coherence is defined as the homogeneity of the distribution of - trophic distances: the more similar, the more coherent. This is measured by - the standard deviation of the trophic differences and referred to as the - trophic incoherence parameter $q$ by [1]. - - Parameters - ---------- - G : DiGraph - A directed networkx graph - - cannibalism: Boolean - If set to False, self edges are not considered in the calculation - - Returns - ------- - trophic_incoherence_parameter : float - The trophic coherence of a graph - - References - ---------- - .. [1] Samuel Johnson, Virginia Dominguez-Garcia, Luca Donetti, Miguel A. - Munoz (2014) PNAS "Trophic coherence determines food-web stability" - """ - import numpy as np - - if cannibalism: - diffs = trophic_differences(G, weight=weight) - else: - # If no cannibalism, remove self-edges - self_loops = list(nx.selfloop_edges(G)) - if self_loops: - # Make a copy so we do not change G's edges in memory - G_2 = G.copy() - G_2.remove_edges_from(self_loops) - else: - # Avoid copy otherwise - G_2 = G - diffs = trophic_differences(G_2, weight=weight) - return float(np.std(list(diffs.values()))) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/voterank_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/voterank_alg.py deleted file mode 100644 index 9b510b2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/centrality/voterank_alg.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Algorithm to select influential nodes in a graph using VoteRank.""" - -import networkx as nx - -__all__ = ["voterank"] - - -@nx._dispatchable -def voterank(G, number_of_nodes=None): - """Select a list of influential nodes in a graph using VoteRank algorithm - - VoteRank [1]_ computes a ranking of the nodes in a graph G based on a - voting scheme. With VoteRank, all nodes vote for each of its in-neighbors - and the node with the highest votes is elected iteratively. The voting - ability of out-neighbors of elected nodes is decreased in subsequent turns. - - Parameters - ---------- - G : graph - A NetworkX graph. - - number_of_nodes : integer, optional - Number of ranked nodes to extract (default all nodes). - - Returns - ------- - voterank : list - Ordered list of computed seeds. - Only nodes with positive number of votes are returned. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 4)]) - >>> nx.voterank(G) - [0, 1] - - The algorithm can be used both for undirected and directed graphs. - However, the directed version is different in two ways: - (i) nodes only vote for their in-neighbors and - (ii) only the voting ability of elected node and its out-neighbors are updated: - - >>> G = nx.DiGraph([(0, 1), (2, 1), (2, 3), (3, 4)]) - >>> nx.voterank(G) - [2, 3] - - Notes - ----- - Each edge is treated independently in case of multigraphs. - - References - ---------- - .. [1] Zhang, J.-X. et al. (2016). - Identifying a set of influential spreaders in complex networks. - Sci. Rep. 6, 27823; doi: 10.1038/srep27823. - """ - influential_nodes = [] - vote_rank = {} - if len(G) == 0: - return influential_nodes - if number_of_nodes is None or number_of_nodes > len(G): - number_of_nodes = len(G) - if G.is_directed(): - # For directed graphs compute average out-degree - avgDegree = sum(deg for _, deg in G.out_degree()) / len(G) - else: - # For undirected graphs compute average degree - avgDegree = sum(deg for _, deg in G.degree()) / len(G) - # step 1 - initiate all nodes to (0,1) (score, voting ability) - for n in G.nodes(): - vote_rank[n] = [0, 1] - # Repeat steps 1b to 4 until num_seeds are elected. - for _ in range(number_of_nodes): - # step 1b - reset rank - for n in G.nodes(): - vote_rank[n][0] = 0 - # step 2 - vote - for n, nbr in G.edges(): - # In directed graphs nodes only vote for their in-neighbors - vote_rank[n][0] += vote_rank[nbr][1] - if not G.is_directed(): - vote_rank[nbr][0] += vote_rank[n][1] - for n in influential_nodes: - vote_rank[n][0] = 0 - # step 3 - select top node - n = max(G.nodes, key=lambda x: vote_rank[x][0]) - if vote_rank[n][0] == 0: - return influential_nodes - influential_nodes.append(n) - # weaken the selected node - vote_rank[n] = [0, 0] - # step 4 - update voterank properties - for _, nbr in G.edges(n): - vote_rank[nbr][1] -= 1 / avgDegree - vote_rank[nbr][1] = max(vote_rank[nbr][1], 0) - return influential_nodes diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chains.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chains.py deleted file mode 100644 index ae342d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chains.py +++ /dev/null @@ -1,172 +0,0 @@ -"""Functions for finding chains in a graph.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["chain_decomposition"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def chain_decomposition(G, root=None): - """Returns the chain decomposition of a graph. - - The *chain decomposition* of a graph with respect a depth-first - search tree is a set of cycles or paths derived from the set of - fundamental cycles of the tree in the following manner. Consider - each fundamental cycle with respect to the given tree, represented - as a list of edges beginning with the nontree edge oriented away - from the root of the tree. For each fundamental cycle, if it - overlaps with any previous fundamental cycle, just take the initial - non-overlapping segment, which is a path instead of a cycle. Each - cycle or path is called a *chain*. For more information, see [1]_. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the chain - decomposition for the connected component containing this node - will be returned. This node indicates the root of the depth-first - search tree. - - Yields - ------ - chain : list - A list of edges representing a chain. There is no guarantee on - the orientation of the edges in each chain (for example, if a - chain includes the edge joining nodes 1 and 2, the chain may - include either (1, 2) or (2, 1)). - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> list(nx.chain_decomposition(G)) - [[(4, 5), (5, 3), (3, 4)]] - - Notes - ----- - The worst-case running time of this implementation is linear in the - number of nodes and number of edges [1]_. - - References - ---------- - .. [1] Jens M. Schmidt (2013). "A simple test on 2-vertex- - and 2-edge-connectivity." *Information Processing Letters*, - 113, 241–244. Elsevier. - - """ - - def _dfs_cycle_forest(G, root=None): - """Builds a directed graph composed of cycles from the given graph. - - `G` is an undirected simple graph. `root` is a node in the graph - from which the depth-first search is started. - - This function returns both the depth-first search cycle graph - (as a :class:`~networkx.DiGraph`) and the list of nodes in - depth-first preorder. The depth-first search cycle graph is a - directed graph whose edges are the edges of `G` oriented toward - the root if the edge is a tree edge and away from the root if - the edge is a non-tree edge. If `root` is not specified, this - performs a depth-first search on each connected component of `G` - and returns a directed forest instead. - - If `root` is not in the graph, this raises :exc:`KeyError`. - - """ - # Create a directed graph from the depth-first search tree with - # root node `root` in which tree edges are directed toward the - # root and nontree edges are directed away from the root. For - # each node with an incident nontree edge, this creates a - # directed cycle starting with the nontree edge and returning to - # that node. - # - # The `parent` node attribute stores the parent of each node in - # the DFS tree. The `nontree` edge attribute indicates whether - # the edge is a tree edge or a nontree edge. - # - # We also store the order of the nodes found in the depth-first - # search in the `nodes` list. - H = nx.DiGraph() - nodes = [] - for u, v, d in nx.dfs_labeled_edges(G, source=root): - if d == "forward": - # `dfs_labeled_edges()` yields (root, root, 'forward') - # if it is beginning the search on a new connected - # component. - if u == v: - H.add_node(v, parent=None) - nodes.append(v) - else: - H.add_node(v, parent=u) - H.add_edge(v, u, nontree=False) - nodes.append(v) - # `dfs_labeled_edges` considers nontree edges in both - # orientations, so we need to not add the edge if it its - # other orientation has been added. - elif d == "nontree" and v not in H[u]: - H.add_edge(v, u, nontree=True) - else: - # Do nothing on 'reverse' edges; we only care about - # forward and nontree edges. - pass - return H, nodes - - def _build_chain(G, u, v, visited): - """Generate the chain starting from the given nontree edge. - - `G` is a DFS cycle graph as constructed by - :func:`_dfs_cycle_graph`. The edge (`u`, `v`) is a nontree edge - that begins a chain. `visited` is a set representing the nodes - in `G` that have already been visited. - - This function yields the edges in an initial segment of the - fundamental cycle of `G` starting with the nontree edge (`u`, - `v`) that includes all the edges up until the first node that - appears in `visited`. The tree edges are given by the 'parent' - node attribute. The `visited` set is updated to add each node in - an edge yielded by this function. - - """ - while v not in visited: - yield u, v - visited.add(v) - u, v = v, G.nodes[v]["parent"] - yield u, v - - # Check if the root is in the graph G. If not, raise NodeNotFound - if root is not None and root not in G: - raise nx.NodeNotFound(f"Root node {root} is not in graph") - - # Create a directed version of H that has the DFS edges directed - # toward the root and the nontree edges directed away from the root - # (in each connected component). - H, nodes = _dfs_cycle_forest(G, root) - - # Visit the nodes again in DFS order. For each node, and for each - # nontree edge leaving that node, compute the fundamental cycle for - # that nontree edge starting with that edge. If the fundamental - # cycle overlaps with any visited nodes, just take the prefix of the - # cycle up to the point of visited nodes. - # - # We repeat this process for each connected component (implicitly, - # since `nodes` already has a list of the nodes grouped by connected - # component). - visited = set() - for u in nodes: - visited.add(u) - # For each nontree edge going out of node u... - edges = ((u, v) for u, v, d in H.out_edges(u, data="nontree") if d) - for u, v in edges: - # Create the cycle or cycle prefix starting with the - # nontree edge. - chain = list(_build_chain(H, u, v, visited)) - yield chain diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chordal.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chordal.py deleted file mode 100644 index ab71c24..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/chordal.py +++ /dev/null @@ -1,443 +0,0 @@ -""" -Algorithms for chordal graphs. - -A graph is chordal if every cycle of length at least 4 has a chord -(an edge joining two nodes not adjacent in the cycle). -https://en.wikipedia.org/wiki/Chordal_graph -""" - -import sys - -import networkx as nx -from networkx.algorithms.components import connected_components -from networkx.utils import arbitrary_element, not_implemented_for - -__all__ = [ - "is_chordal", - "find_induced_nodes", - "chordal_graph_cliques", - "chordal_graph_treewidth", - "NetworkXTreewidthBoundExceeded", - "complete_to_chordal_graph", -] - - -class NetworkXTreewidthBoundExceeded(nx.NetworkXException): - """Exception raised when a treewidth bound has been provided and it has - been exceeded""" - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_chordal(G): - """Checks whether G is a chordal graph. - - A graph is chordal if every cycle of length at least 4 has a chord - (an edge joining two nodes not adjacent in the cycle). - - Parameters - ---------- - G : graph - A NetworkX graph. - - Returns - ------- - chordal : bool - True if G is a chordal graph and False otherwise. - - Raises - ------ - NetworkXNotImplemented - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - - Examples - -------- - >>> e = [ - ... (1, 2), - ... (1, 3), - ... (2, 3), - ... (2, 4), - ... (3, 4), - ... (3, 5), - ... (3, 6), - ... (4, 5), - ... (4, 6), - ... (5, 6), - ... ] - >>> G = nx.Graph(e) - >>> nx.is_chordal(G) - True - - Notes - ----- - The routine tries to go through every node following maximum cardinality - search. It returns False when it finds that the separator for any node - is not a clique. Based on the algorithms in [1]_. - - Self loops are ignored. - - References - ---------- - .. [1] R. E. Tarjan and M. Yannakakis, Simple linear-time algorithms - to test chordality of graphs, test acyclicity of hypergraphs, and - selectively reduce acyclic hypergraphs, SIAM J. Comput., 13 (1984), - pp. 566–579. - """ - if len(G.nodes) <= 3: - return True - return len(_find_chordality_breaker(G)) == 0 - - -@nx._dispatchable -def find_induced_nodes(G, s, t, treewidth_bound=sys.maxsize): - """Returns the set of induced nodes in the path from s to t. - - Parameters - ---------- - G : graph - A chordal NetworkX graph - s : node - Source node to look for induced nodes - t : node - Destination node to look for induced nodes - treewidth_bound: float - Maximum treewidth acceptable for the graph H. The search - for induced nodes will end as soon as the treewidth_bound is exceeded. - - Returns - ------- - induced_nodes : Set of nodes - The set of induced nodes in the path from s to t in G - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - If the input graph is an instance of one of these classes, a - :exc:`NetworkXError` is raised. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> G = nx.Graph() - >>> G = nx.generators.classic.path_graph(10) - >>> induced_nodes = nx.find_induced_nodes(G, 1, 9, 2) - >>> sorted(induced_nodes) - [1, 2, 3, 4, 5, 6, 7, 8, 9] - - Notes - ----- - G must be a chordal graph and (s,t) an edge that is not in G. - - If a treewidth_bound is provided, the search for induced nodes will end - as soon as the treewidth_bound is exceeded. - - The algorithm is inspired by Algorithm 4 in [1]_. - A formal definition of induced node can also be found on that reference. - - Self Loops are ignored - - References - ---------- - .. [1] Learning Bounded Treewidth Bayesian Networks. - Gal Elidan, Stephen Gould; JMLR, 9(Dec):2699--2731, 2008. - http://jmlr.csail.mit.edu/papers/volume9/elidan08a/elidan08a.pdf - """ - if not is_chordal(G): - raise nx.NetworkXError("Input graph is not chordal.") - - H = nx.Graph(G) - H.add_edge(s, t) - induced_nodes = set() - triplet = _find_chordality_breaker(H, s, treewidth_bound) - while triplet: - (u, v, w) = triplet - induced_nodes.update(triplet) - for n in triplet: - if n != s: - H.add_edge(s, n) - triplet = _find_chordality_breaker(H, s, treewidth_bound) - if induced_nodes: - # Add t and the second node in the induced path from s to t. - induced_nodes.add(t) - for u in G[s]: - if len(induced_nodes & set(G[u])) == 2: - induced_nodes.add(u) - break - return induced_nodes - - -@nx._dispatchable -def chordal_graph_cliques(G): - """Returns all maximal cliques of a chordal graph. - - The algorithm breaks the graph in connected components and performs a - maximum cardinality search in each component to get the cliques. - - Parameters - ---------- - G : graph - A NetworkX graph - - Yields - ------ - frozenset of nodes - Maximal cliques, each of which is a frozenset of - nodes in `G`. The order of cliques is arbitrary. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> e = [ - ... (1, 2), - ... (1, 3), - ... (2, 3), - ... (2, 4), - ... (3, 4), - ... (3, 5), - ... (3, 6), - ... (4, 5), - ... (4, 6), - ... (5, 6), - ... (7, 8), - ... ] - >>> G = nx.Graph(e) - >>> G.add_node(9) - >>> cliques = [c for c in chordal_graph_cliques(G)] - >>> cliques[0] - frozenset({1, 2, 3}) - """ - for C in (G.subgraph(c).copy() for c in connected_components(G)): - if C.number_of_nodes() == 1: - if nx.number_of_selfloops(C) > 0: - raise nx.NetworkXError("Input graph is not chordal.") - yield frozenset(C.nodes()) - else: - unnumbered = set(C.nodes()) - v = arbitrary_element(C) - unnumbered.remove(v) - numbered = {v} - clique_wanna_be = {v} - while unnumbered: - v = _max_cardinality_node(C, unnumbered, numbered) - unnumbered.remove(v) - numbered.add(v) - new_clique_wanna_be = set(C.neighbors(v)) & numbered - sg = C.subgraph(clique_wanna_be) - if _is_complete_graph(sg): - new_clique_wanna_be.add(v) - if not new_clique_wanna_be >= clique_wanna_be: - yield frozenset(clique_wanna_be) - clique_wanna_be = new_clique_wanna_be - else: - raise nx.NetworkXError("Input graph is not chordal.") - yield frozenset(clique_wanna_be) - - -@nx._dispatchable -def chordal_graph_treewidth(G): - """Returns the treewidth of the chordal graph G. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - treewidth : int - The size of the largest clique in the graph minus one. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> e = [ - ... (1, 2), - ... (1, 3), - ... (2, 3), - ... (2, 4), - ... (3, 4), - ... (3, 5), - ... (3, 6), - ... (4, 5), - ... (4, 6), - ... (5, 6), - ... (7, 8), - ... ] - >>> G = nx.Graph(e) - >>> G.add_node(9) - >>> nx.chordal_graph_treewidth(G) - 3 - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Tree_decomposition#Treewidth - """ - if not is_chordal(G): - raise nx.NetworkXError("Input graph is not chordal.") - - max_clique = -1 - for clique in nx.chordal_graph_cliques(G): - max_clique = max(max_clique, len(clique)) - return max_clique - 1 - - -def _is_complete_graph(G): - """Returns True if G is a complete graph.""" - if nx.number_of_selfloops(G) > 0: - raise nx.NetworkXError("Self loop found in _is_complete_graph()") - n = G.number_of_nodes() - if n < 2: - return True - e = G.number_of_edges() - max_edges = (n * (n - 1)) / 2 - return e == max_edges - - -def _find_missing_edge(G): - """Given a non-complete graph G, returns a missing edge.""" - nodes = set(G) - for u in G: - missing = nodes - set(list(G[u].keys()) + [u]) - if missing: - return (u, missing.pop()) - - -def _max_cardinality_node(G, choices, wanna_connect): - """Returns a the node in choices that has more connections in G - to nodes in wanna_connect. - """ - max_number = -1 - for x in choices: - number = len([y for y in G[x] if y in wanna_connect]) - if number > max_number: - max_number = number - max_cardinality_node = x - return max_cardinality_node - - -def _find_chordality_breaker(G, s=None, treewidth_bound=sys.maxsize): - """Given a graph G, starts a max cardinality search - (starting from s if s is given and from an arbitrary node otherwise) - trying to find a non-chordal cycle. - - If it does find one, it returns (u,v,w) where u,v,w are the three - nodes that together with s are involved in the cycle. - - It ignores any self loops. - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept("Graph has no nodes.") - unnumbered = set(G) - if s is None: - s = arbitrary_element(G) - unnumbered.remove(s) - numbered = {s} - current_treewidth = -1 - while unnumbered: # and current_treewidth <= treewidth_bound: - v = _max_cardinality_node(G, unnumbered, numbered) - unnumbered.remove(v) - numbered.add(v) - clique_wanna_be = set(G[v]) & numbered - sg = G.subgraph(clique_wanna_be) - if _is_complete_graph(sg): - # The graph seems to be chordal by now. We update the treewidth - current_treewidth = max(current_treewidth, len(clique_wanna_be)) - if current_treewidth > treewidth_bound: - raise nx.NetworkXTreewidthBoundExceeded( - f"treewidth_bound exceeded: {current_treewidth}" - ) - else: - # sg is not a clique, - # look for an edge that is not included in sg - (u, w) = _find_missing_edge(sg) - return (u, v, w) - return () - - -@not_implemented_for("directed") -@nx._dispatchable(returns_graph=True) -def complete_to_chordal_graph(G): - """Return a copy of G completed to a chordal graph - - Adds edges to a copy of G to create a chordal graph. A graph G=(V,E) is - called chordal if for each cycle with length bigger than 3, there exist - two non-adjacent nodes connected by an edge (called a chord). - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - H : NetworkX graph - The chordal enhancement of G - alpha : Dictionary - The elimination ordering of nodes of G - - Notes - ----- - There are different approaches to calculate the chordal - enhancement of a graph. The algorithm used here is called - MCS-M and gives at least minimal (local) triangulation of graph. Note - that this triangulation is not necessarily a global minimum. - - https://en.wikipedia.org/wiki/Chordal_graph - - References - ---------- - .. [1] Berry, Anne & Blair, Jean & Heggernes, Pinar & Peyton, Barry. (2004) - Maximum Cardinality Search for Computing Minimal Triangulations of - Graphs. Algorithmica. 39. 287-298. 10.1007/s00453-004-1084-3. - - Examples - -------- - >>> from networkx.algorithms.chordal import complete_to_chordal_graph - >>> G = nx.wheel_graph(10) - >>> H, alpha = complete_to_chordal_graph(G) - """ - H = G.copy() - alpha = {node: 0 for node in H} - if nx.is_chordal(H): - return H, alpha - chords = set() - weight = {node: 0 for node in H.nodes()} - unnumbered_nodes = list(H.nodes()) - for i in range(len(H.nodes()), 0, -1): - # get the node in unnumbered_nodes with the maximum weight - z = max(unnumbered_nodes, key=lambda node: weight[node]) - unnumbered_nodes.remove(z) - alpha[z] = i - update_nodes = [] - for y in unnumbered_nodes: - if G.has_edge(y, z): - update_nodes.append(y) - else: - # y_weight will be bigger than node weights between y and z - y_weight = weight[y] - lower_nodes = [ - node for node in unnumbered_nodes if weight[node] < y_weight - ] - if nx.has_path(H.subgraph(lower_nodes + [z, y]), y, z): - update_nodes.append(y) - chords.add((z, y)) - # during calculation of paths the weights should not be updated - for node in update_nodes: - weight[node] += 1 - H.add_edges_from(chords) - return H, alpha diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/clique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/clique.py deleted file mode 100644 index 57b588a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/clique.py +++ /dev/null @@ -1,755 +0,0 @@ -"""Functions for finding and manipulating cliques. - -Finding the largest clique in a graph is NP-complete problem, so most of -these algorithms have an exponential running time; for more information, -see the Wikipedia article on the clique problem [1]_. - -.. [1] clique problem:: https://en.wikipedia.org/wiki/Clique_problem - -""" - -from collections import defaultdict, deque -from itertools import chain, combinations, islice - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "find_cliques", - "find_cliques_recursive", - "make_max_clique_graph", - "make_clique_bipartite", - "node_clique_number", - "number_of_cliques", - "enumerate_all_cliques", - "max_weight_clique", -] - - -@not_implemented_for("directed") -@nx._dispatchable -def enumerate_all_cliques(G): - """Returns all cliques in an undirected graph. - - This function returns an iterator over cliques, each of which is a - list of nodes. The iteration is ordered by cardinality of the - cliques: first all cliques of size one, then all cliques of size - two, etc. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - iterator - An iterator over cliques, each of which is a list of nodes in - `G`. The cliques are ordered according to size. - - Notes - ----- - To obtain a list of all cliques, use - `list(enumerate_all_cliques(G))`. However, be aware that in the - worst-case, the length of this list can be exponential in the number - of nodes in the graph (for example, when the graph is the complete - graph). This function avoids storing all cliques in memory by only - keeping current candidate node lists in memory during its search. - - The implementation is adapted from the algorithm by Zhang, et - al. (2005) [1]_ to output all cliques discovered. - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Yun Zhang, Abu-Khzam, F.N., Baldwin, N.E., Chesler, E.J., - Langston, M.A., Samatova, N.F., - "Genome-Scale Computational Approaches to Memory-Intensive - Applications in Systems Biology". - *Supercomputing*, 2005. Proceedings of the ACM/IEEE SC 2005 - Conference, pp. 12, 12--18 Nov. 2005. - . - - """ - index = {} - nbrs = {} - for u in G: - index[u] = len(index) - # Neighbors of u that appear after u in the iteration order of G. - nbrs[u] = {v for v in G[u] if v not in index} - - queue = deque(([u], sorted(nbrs[u], key=index.__getitem__)) for u in G) - # Loop invariants: - # 1. len(base) is nondecreasing. - # 2. (base + cnbrs) is sorted with respect to the iteration order of G. - # 3. cnbrs is a set of common neighbors of nodes in base. - while queue: - base, cnbrs = map(list, queue.popleft()) - yield base - for i, u in enumerate(cnbrs): - # Use generators to reduce memory consumption. - queue.append( - ( - chain(base, [u]), - filter(nbrs[u].__contains__, islice(cnbrs, i + 1, None)), - ) - ) - - -@not_implemented_for("directed") -@nx._dispatchable -def find_cliques(G, nodes=None): - """Returns all maximal cliques in an undirected graph. - - For each node *n*, a *maximal clique for n* is a largest complete - subgraph containing *n*. The largest maximal clique is sometimes - called the *maximum clique*. - - This function returns an iterator over cliques, each of which is a - list of nodes. It is an iterative implementation, so should not - suffer from recursion depth issues. - - This function accepts a list of `nodes` and only the maximal cliques - containing all of these `nodes` are returned. It can considerably speed up - the running time if some specific cliques are desired. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - nodes : list, optional (default=None) - If provided, only yield *maximal cliques* containing all nodes in `nodes`. - If `nodes` isn't a clique itself, a ValueError is raised. - - Returns - ------- - iterator - An iterator over maximal cliques, each of which is a list of - nodes in `G`. If `nodes` is provided, only the maximal cliques - containing all the nodes in `nodes` are returned. The order of - cliques is arbitrary. - - Raises - ------ - ValueError - If `nodes` is not a clique. - - Examples - -------- - >>> from pprint import pprint # For nice dict formatting - >>> G = nx.karate_club_graph() - >>> sum(1 for c in nx.find_cliques(G)) # The number of maximal cliques in G - 36 - >>> max(nx.find_cliques(G), key=len) # The largest maximal clique in G - [0, 1, 2, 3, 13] - - The size of the largest maximal clique is known as the *clique number* of - the graph, which can be found directly with: - - >>> max(len(c) for c in nx.find_cliques(G)) - 5 - - One can also compute the number of maximal cliques in `G` that contain a given - node. The following produces a dictionary keyed by node whose - values are the number of maximal cliques in `G` that contain the node: - - >>> pprint({n: sum(1 for c in nx.find_cliques(G) if n in c) for n in G}) - {0: 13, - 1: 6, - 2: 7, - 3: 3, - 4: 2, - 5: 3, - 6: 3, - 7: 1, - 8: 3, - 9: 2, - 10: 2, - 11: 1, - 12: 1, - 13: 2, - 14: 1, - 15: 1, - 16: 1, - 17: 1, - 18: 1, - 19: 2, - 20: 1, - 21: 1, - 22: 1, - 23: 3, - 24: 2, - 25: 2, - 26: 1, - 27: 3, - 28: 2, - 29: 2, - 30: 2, - 31: 4, - 32: 9, - 33: 14} - - Or, similarly, the maximal cliques in `G` that contain a given node. - For example, the 4 maximal cliques that contain node 31: - - >>> [c for c in nx.find_cliques(G) if 31 in c] - [[0, 31], [33, 32, 31], [33, 28, 31], [24, 25, 31]] - - See Also - -------- - find_cliques_recursive - A recursive version of the same algorithm. - - Notes - ----- - To obtain a list of all maximal cliques, use - `list(find_cliques(G))`. However, be aware that in the worst-case, - the length of this list can be exponential in the number of nodes in - the graph. This function avoids storing all cliques in memory by - only keeping current candidate node lists in memory during its search. - - This implementation is based on the algorithm published by Bron and - Kerbosch (1973) [1]_, as adapted by Tomita, Tanaka and Takahashi - (2006) [2]_ and discussed in Cazals and Karande (2008) [3]_. It - essentially unrolls the recursion used in the references to avoid - issues of recursion stack depth (for a recursive implementation, see - :func:`find_cliques_recursive`). - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Bron, C. and Kerbosch, J. - "Algorithm 457: finding all cliques of an undirected graph". - *Communications of the ACM* 16, 9 (Sep. 1973), 575--577. - - - .. [2] Etsuji Tomita, Akira Tanaka, Haruhisa Takahashi, - "The worst-case time complexity for generating all maximal - cliques and computational experiments", - *Theoretical Computer Science*, Volume 363, Issue 1, - Computing and Combinatorics, - 10th Annual International Conference on - Computing and Combinatorics (COCOON 2004), 25 October 2006, Pages 28--42 - - - .. [3] F. Cazals, C. Karande, - "A note on the problem of reporting maximal cliques", - *Theoretical Computer Science*, - Volume 407, Issues 1--3, 6 November 2008, Pages 564--568, - - - """ - if len(G) == 0: - return - - adj = {u: {v for v in G[u] if v != u} for u in G} - - # Initialize Q with the given nodes and subg, cand with their nbrs - Q = nodes[:] if nodes is not None else [] - cand = set(G) - for node in Q: - if node not in cand: - raise ValueError(f"The given `nodes` {nodes} do not form a clique") - cand &= adj[node] - - if not cand: - yield Q[:] - return - - subg = cand.copy() - stack = [] - Q.append(None) - - u = max(subg, key=lambda u: len(cand & adj[u])) - ext_u = cand - adj[u] - - try: - while True: - if ext_u: - q = ext_u.pop() - cand.remove(q) - Q[-1] = q - adj_q = adj[q] - subg_q = subg & adj_q - if not subg_q: - yield Q[:] - else: - cand_q = cand & adj_q - if cand_q: - stack.append((subg, cand, ext_u)) - Q.append(None) - subg = subg_q - cand = cand_q - u = max(subg, key=lambda u: len(cand & adj[u])) - ext_u = cand - adj[u] - else: - Q.pop() - subg, cand, ext_u = stack.pop() - except IndexError: - pass - - -# TODO Should this also be not implemented for directed graphs? -@nx._dispatchable -def find_cliques_recursive(G, nodes=None): - """Returns all maximal cliques in a graph. - - For each node *v*, a *maximal clique for v* is a largest complete - subgraph containing *v*. The largest maximal clique is sometimes - called the *maximum clique*. - - This function returns an iterator over cliques, each of which is a - list of nodes. It is a recursive implementation, so may suffer from - recursion depth issues, but is included for pedagogical reasons. - For a non-recursive implementation, see :func:`find_cliques`. - - This function accepts a list of `nodes` and only the maximal cliques - containing all of these `nodes` are returned. It can considerably speed up - the running time if some specific cliques are desired. - - Parameters - ---------- - G : NetworkX graph - - nodes : list, optional (default=None) - If provided, only yield *maximal cliques* containing all nodes in `nodes`. - If `nodes` isn't a clique itself, a ValueError is raised. - - Returns - ------- - iterator - An iterator over maximal cliques, each of which is a list of - nodes in `G`. If `nodes` is provided, only the maximal cliques - containing all the nodes in `nodes` are yielded. The order of - cliques is arbitrary. - - Raises - ------ - ValueError - If `nodes` is not a clique. - - See Also - -------- - find_cliques - An iterative version of the same algorithm. See docstring for examples. - - Notes - ----- - To obtain a list of all maximal cliques, use - `list(find_cliques_recursive(G))`. However, be aware that in the - worst-case, the length of this list can be exponential in the number - of nodes in the graph. This function avoids storing all cliques in memory - by only keeping current candidate node lists in memory during its search. - - This implementation is based on the algorithm published by Bron and - Kerbosch (1973) [1]_, as adapted by Tomita, Tanaka and Takahashi - (2006) [2]_ and discussed in Cazals and Karande (2008) [3]_. For a - non-recursive implementation, see :func:`find_cliques`. - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Bron, C. and Kerbosch, J. - "Algorithm 457: finding all cliques of an undirected graph". - *Communications of the ACM* 16, 9 (Sep. 1973), 575--577. - - - .. [2] Etsuji Tomita, Akira Tanaka, Haruhisa Takahashi, - "The worst-case time complexity for generating all maximal - cliques and computational experiments", - *Theoretical Computer Science*, Volume 363, Issue 1, - Computing and Combinatorics, - 10th Annual International Conference on - Computing and Combinatorics (COCOON 2004), 25 October 2006, Pages 28--42 - - - .. [3] F. Cazals, C. Karande, - "A note on the problem of reporting maximal cliques", - *Theoretical Computer Science*, - Volume 407, Issues 1--3, 6 November 2008, Pages 564--568, - - - """ - if len(G) == 0: - return iter([]) - - adj = {u: {v for v in G[u] if v != u} for u in G} - - # Initialize Q with the given nodes and subg, cand with their nbrs - Q = nodes[:] if nodes is not None else [] - cand_init = set(G) - for node in Q: - if node not in cand_init: - raise ValueError(f"The given `nodes` {nodes} do not form a clique") - cand_init &= adj[node] - - if not cand_init: - return iter([Q]) - - subg_init = cand_init.copy() - - def expand(subg, cand): - u = max(subg, key=lambda u: len(cand & adj[u])) - for q in cand - adj[u]: - cand.remove(q) - Q.append(q) - adj_q = adj[q] - subg_q = subg & adj_q - if not subg_q: - yield Q[:] - else: - cand_q = cand & adj_q - if cand_q: - yield from expand(subg_q, cand_q) - Q.pop() - - return expand(subg_init, cand_init) - - -@nx._dispatchable(returns_graph=True) -def make_max_clique_graph(G, create_using=None): - """Returns the maximal clique graph of the given graph. - - The nodes of the maximal clique graph of `G` are the cliques of - `G` and an edge joins two cliques if the cliques are not disjoint. - - Parameters - ---------- - G : NetworkX graph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - A graph whose nodes are the cliques of `G` and whose edges - join two cliques if they are not disjoint. - - Notes - ----- - This function behaves like the following code:: - - import networkx as nx - - G = nx.make_clique_bipartite(G) - cliques = [v for v in G.nodes() if G.nodes[v]["bipartite"] == 0] - G = nx.bipartite.projected_graph(G, cliques) - G = nx.relabel_nodes(G, {-v: v - 1 for v in G}) - - It should be faster, though, since it skips all the intermediate - steps. - - """ - if create_using is None: - B = G.__class__() - else: - B = nx.empty_graph(0, create_using) - cliques = list(enumerate(set(c) for c in find_cliques(G))) - # Add a numbered node for each clique. - B.add_nodes_from(i for i, c in cliques) - # Join cliques by an edge if they share a node. - clique_pairs = combinations(cliques, 2) - B.add_edges_from((i, j) for (i, c1), (j, c2) in clique_pairs if c1 & c2) - return B - - -@nx._dispatchable(returns_graph=True) -def make_clique_bipartite(G, fpos=None, create_using=None, name=None): - """Returns the bipartite clique graph corresponding to `G`. - - In the returned bipartite graph, the "bottom" nodes are the nodes of - `G` and the "top" nodes represent the maximal cliques of `G`. - There is an edge from node *v* to clique *C* in the returned graph - if and only if *v* is an element of *C*. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - fpos : bool - If True or not None, the returned graph will have an - additional attribute, `pos`, a dictionary mapping node to - position in the Euclidean plane. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - A bipartite graph whose "bottom" set is the nodes of the graph - `G`, whose "top" set is the cliques of `G`, and whose edges - join nodes of `G` to the cliques that contain them. - - The nodes of the graph `G` have the node attribute - 'bipartite' set to 1 and the nodes representing cliques - have the node attribute 'bipartite' set to 0, as is the - convention for bipartite graphs in NetworkX. - - """ - B = nx.empty_graph(0, create_using) - B.clear() - # The "bottom" nodes in the bipartite graph are the nodes of the - # original graph, G. - B.add_nodes_from(G, bipartite=1) - for i, cl in enumerate(find_cliques(G)): - # The "top" nodes in the bipartite graph are the cliques. These - # nodes get negative numbers as labels. - name = -i - 1 - B.add_node(name, bipartite=0) - B.add_edges_from((v, name) for v in cl) - return B - - -@nx._dispatchable -def node_clique_number(G, nodes=None, cliques=None, separate_nodes=False): - """Returns the size of the largest maximal clique containing each given node. - - Returns a single or list depending on input nodes. - An optional list of cliques can be input if already computed. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - cliques : list, optional (default=None) - A list of cliques, each of which is itself a list of nodes. - If not specified, the list of all cliques will be computed - using :func:`find_cliques`. - - Returns - ------- - int or dict - If `nodes` is a single node, returns the size of the - largest maximal clique in `G` containing that node. - Otherwise return a dict keyed by node to the size - of the largest maximal clique containing that node. - - See Also - -------- - find_cliques - find_cliques yields the maximal cliques of G. - It accepts a `nodes` argument which restricts consideration to - maximal cliques containing all the given `nodes`. - The search for the cliques is optimized for `nodes`. - """ - if cliques is None: - if nodes is not None: - # Use ego_graph to decrease size of graph - # check for single node - if nodes in G: - return max(len(c) for c in find_cliques(nx.ego_graph(G, nodes))) - # handle multiple nodes - return { - n: max(len(c) for c in find_cliques(nx.ego_graph(G, n))) for n in nodes - } - - # nodes is None--find all cliques - cliques = list(find_cliques(G)) - - # single node requested - if nodes in G: - return max(len(c) for c in cliques if nodes in c) - - # multiple nodes requested - # preprocess all nodes (faster than one at a time for even 2 nodes) - size_for_n = defaultdict(int) - for c in cliques: - size_of_c = len(c) - for n in c: - if size_for_n[n] < size_of_c: - size_for_n[n] = size_of_c - if nodes is None: - return size_for_n - return {n: size_for_n[n] for n in nodes} - - -def number_of_cliques(G, nodes=None, cliques=None): - """Returns the number of maximal cliques for each node. - - Returns a single or list depending on input nodes. - Optional list of cliques can be input if already computed. - """ - if cliques is None: - cliques = list(find_cliques(G)) - - if nodes is None: - nodes = list(G.nodes()) # none, get entire graph - - if not isinstance(nodes, list): # check for a list - v = nodes - # assume it is a single value - numcliq = len([1 for c in cliques if v in c]) - else: - numcliq = {} - for v in nodes: - numcliq[v] = len([1 for c in cliques if v in c]) - return numcliq - - -class MaxWeightClique: - """A class for the maximum weight clique algorithm. - - This class is a helper for the `max_weight_clique` function. The class - should not normally be used directly. - - Parameters - ---------- - G : NetworkX graph - The undirected graph for which a maximum weight clique is sought - weight : string or None, optional (default='weight') - The node attribute that holds the integer value used as a weight. - If None, then each node has weight 1. - - Attributes - ---------- - G : NetworkX graph - The undirected graph for which a maximum weight clique is sought - node_weights: dict - The weight of each node - incumbent_nodes : list - The nodes of the incumbent clique (the best clique found so far) - incumbent_weight: int - The weight of the incumbent clique - """ - - def __init__(self, G, weight): - self.G = G - self.incumbent_nodes = [] - self.incumbent_weight = 0 - - if weight is None: - self.node_weights = {v: 1 for v in G.nodes()} - else: - for v in G.nodes(): - if weight not in G.nodes[v]: - errmsg = f"Node {v!r} does not have the requested weight field." - raise KeyError(errmsg) - if not isinstance(G.nodes[v][weight], int): - errmsg = f"The {weight!r} field of node {v!r} is not an integer." - raise ValueError(errmsg) - self.node_weights = {v: G.nodes[v][weight] for v in G.nodes()} - - def update_incumbent_if_improved(self, C, C_weight): - """Update the incumbent if the node set C has greater weight. - - C is assumed to be a clique. - """ - if C_weight > self.incumbent_weight: - self.incumbent_nodes = C[:] - self.incumbent_weight = C_weight - - def greedily_find_independent_set(self, P): - """Greedily find an independent set of nodes from a set of - nodes P.""" - independent_set = [] - P = P[:] - while P: - v = P[0] - independent_set.append(v) - P = [w for w in P if v != w and not self.G.has_edge(v, w)] - return independent_set - - def find_branching_nodes(self, P, target): - """Find a set of nodes to branch on.""" - residual_wt = {v: self.node_weights[v] for v in P} - total_wt = 0 - P = P[:] - while P: - independent_set = self.greedily_find_independent_set(P) - min_wt_in_class = min(residual_wt[v] for v in independent_set) - total_wt += min_wt_in_class - if total_wt > target: - break - for v in independent_set: - residual_wt[v] -= min_wt_in_class - P = [v for v in P if residual_wt[v] != 0] - return P - - def expand(self, C, C_weight, P): - """Look for the best clique that contains all the nodes in C and zero or - more of the nodes in P, backtracking if it can be shown that no such - clique has greater weight than the incumbent. - """ - self.update_incumbent_if_improved(C, C_weight) - branching_nodes = self.find_branching_nodes(P, self.incumbent_weight - C_weight) - while branching_nodes: - v = branching_nodes.pop() - P.remove(v) - new_C = C + [v] - new_C_weight = C_weight + self.node_weights[v] - new_P = [w for w in P if self.G.has_edge(v, w)] - self.expand(new_C, new_C_weight, new_P) - - def find_max_weight_clique(self): - """Find a maximum weight clique.""" - # Sort nodes in reverse order of degree for speed - nodes = sorted(self.G.nodes(), key=lambda v: self.G.degree(v), reverse=True) - nodes = [v for v in nodes if self.node_weights[v] > 0] - self.expand([], 0, nodes) - - -@not_implemented_for("directed") -@nx._dispatchable(node_attrs="weight") -def max_weight_clique(G, weight="weight"): - """Find a maximum weight clique in G. - - A *clique* in a graph is a set of nodes such that every two distinct nodes - are adjacent. The *weight* of a clique is the sum of the weights of its - nodes. A *maximum weight clique* of graph G is a clique C in G such that - no clique in G has weight greater than the weight of C. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - weight : string or None, optional (default='weight') - The node attribute that holds the integer value used as a weight. - If None, then each node has weight 1. - - Returns - ------- - clique : list - the nodes of a maximum weight clique - weight : int - the weight of a maximum weight clique - - Notes - ----- - The implementation is recursive, and therefore it may run into recursion - depth issues if G contains a clique whose number of nodes is close to the - recursion depth limit. - - At each search node, the algorithm greedily constructs a weighted - independent set cover of part of the graph in order to find a small set of - nodes on which to branch. The algorithm is very similar to the algorithm - of Tavares et al. [1]_, other than the fact that the NetworkX version does - not use bitsets. This style of algorithm for maximum weight clique (and - maximum weight independent set, which is the same problem but on the - complement graph) has a decades-long history. See Algorithm B of Warren - and Hicks [2]_ and the references in that paper. - - References - ---------- - .. [1] Tavares, W.A., Neto, M.B.C., Rodrigues, C.D., Michelon, P.: Um - algoritmo de branch and bound para o problema da clique máxima - ponderada. Proceedings of XLVII SBPO 1 (2015). - - .. [2] Warren, Jeffrey S, Hicks, Illya V.: Combinatorial Branch-and-Bound - for the Maximum Weight Independent Set Problem. Technical Report, - Texas A&M University (2016). - """ - - mwc = MaxWeightClique(G, weight) - mwc.find_max_weight_clique() - return mwc.incumbent_nodes, mwc.incumbent_weight diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cluster.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cluster.py deleted file mode 100644 index 6c91ad2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cluster.py +++ /dev/null @@ -1,609 +0,0 @@ -"""Algorithms to characterize the number of triangles in a graph.""" - -from collections import Counter -from itertools import chain, combinations - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "triangles", - "average_clustering", - "clustering", - "transitivity", - "square_clustering", - "generalized_degree", -] - - -@not_implemented_for("directed") -@nx._dispatchable -def triangles(G, nodes=None): - """Compute the number of triangles. - - Finds the number of triangles that include a node as one vertex. - - Parameters - ---------- - G : graph - A networkx graph - - nodes : node, iterable of nodes, or None (default=None) - If a singleton node, return the number of triangles for that node. - If an iterable, compute the number of triangles for each of those nodes. - If `None` (the default) compute the number of triangles for all nodes in `G`. - - Returns - ------- - out : dict or int - If `nodes` is a container of nodes, returns number of triangles keyed by node (dict). - If `nodes` is a specific node, returns number of triangles for the node (int). - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.triangles(G, 0)) - 6 - >>> print(nx.triangles(G)) - {0: 6, 1: 6, 2: 6, 3: 6, 4: 6} - >>> print(list(nx.triangles(G, [0, 1]).values())) - [6, 6] - - Notes - ----- - Self loops are ignored. - - """ - if nodes is not None: - # If `nodes` represents a single node, return only its number of triangles - if nodes in G: - return next(_triangles_and_degree_iter(G, nodes))[2] // 2 - - # if `nodes` is a container of nodes, then return a - # dictionary mapping node to number of triangles. - return {v: t // 2 for v, d, t, _ in _triangles_and_degree_iter(G, nodes)} - - # if nodes is None, then compute triangles for the complete graph - - # dict used to avoid visiting the same nodes twice - # this allows calculating/counting each triangle only once - later_nbrs = {} - - # iterate over the nodes in a graph - for node, neighbors in G.adjacency(): - later_nbrs[node] = {n for n in neighbors if n not in later_nbrs and n != node} - - # instantiate Counter for each node to include isolated nodes - # add 1 to the count if a nodes neighbor's neighbor is also a neighbor - triangle_counts = Counter(dict.fromkeys(G, 0)) - for node1, neighbors in later_nbrs.items(): - for node2 in neighbors: - third_nodes = neighbors & later_nbrs[node2] - m = len(third_nodes) - triangle_counts[node1] += m - triangle_counts[node2] += m - triangle_counts.update(third_nodes) - - return dict(triangle_counts) - - -@not_implemented_for("multigraph") -def _triangles_and_degree_iter(G, nodes=None): - """Return an iterator of (node, degree, triangles, generalized degree). - - This double counts triangles so you may want to divide by 2. - See degree(), triangles() and generalized_degree() for definitions - and details. - - """ - if nodes is None: - nodes_nbrs = G.adj.items() - else: - nodes_nbrs = ((n, G[n]) for n in G.nbunch_iter(nodes)) - - for v, v_nbrs in nodes_nbrs: - vs = set(v_nbrs) - {v} - gen_degree = Counter(len(vs & (set(G[w]) - {w})) for w in vs) - ntriangles = sum(k * val for k, val in gen_degree.items()) - yield (v, len(vs), ntriangles, gen_degree) - - -@not_implemented_for("multigraph") -def _weighted_triangles_and_degree_iter(G, nodes=None, weight="weight"): - """Return an iterator of (node, degree, weighted_triangles). - - Used for weighted clustering. - Note: this returns the geometric average weight of edges in the triangle. - Also, each triangle is counted twice (each direction). - So you may want to divide by 2. - - """ - import numpy as np - - if weight is None or G.number_of_edges() == 0: - max_weight = 1 - else: - max_weight = max(d.get(weight, 1) for u, v, d in G.edges(data=True)) - if nodes is None: - nodes_nbrs = G.adj.items() - else: - nodes_nbrs = ((n, G[n]) for n in G.nbunch_iter(nodes)) - - def wt(u, v): - return G[u][v].get(weight, 1) / max_weight - - for i, nbrs in nodes_nbrs: - inbrs = set(nbrs) - {i} - weighted_triangles = 0 - seen = set() - for j in inbrs: - seen.add(j) - # This avoids counting twice -- we double at the end. - jnbrs = set(G[j]) - seen - # Only compute the edge weight once, before the inner inner - # loop. - wij = wt(i, j) - weighted_triangles += np.cbrt( - [(wij * wt(j, k) * wt(k, i)) for k in inbrs & jnbrs] - ).sum() - yield (i, len(inbrs), 2 * float(weighted_triangles)) - - -@not_implemented_for("multigraph") -def _directed_triangles_and_degree_iter(G, nodes=None): - """Return an iterator of - (node, total_degree, reciprocal_degree, directed_triangles). - - Used for directed clustering. - Note that unlike `_triangles_and_degree_iter()`, this function counts - directed triangles so does not count triangles twice. - - """ - nodes_nbrs = ((n, G._pred[n], G._succ[n]) for n in G.nbunch_iter(nodes)) - - for i, preds, succs in nodes_nbrs: - ipreds = set(preds) - {i} - isuccs = set(succs) - {i} - - directed_triangles = 0 - for j in chain(ipreds, isuccs): - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += sum( - 1 - for k in chain( - (ipreds & jpreds), - (ipreds & jsuccs), - (isuccs & jpreds), - (isuccs & jsuccs), - ) - ) - dtotal = len(ipreds) + len(isuccs) - dbidirectional = len(ipreds & isuccs) - yield (i, dtotal, dbidirectional, directed_triangles) - - -@not_implemented_for("multigraph") -def _directed_weighted_triangles_and_degree_iter(G, nodes=None, weight="weight"): - """Return an iterator of - (node, total_degree, reciprocal_degree, directed_weighted_triangles). - - Used for directed weighted clustering. - Note that unlike `_weighted_triangles_and_degree_iter()`, this function counts - directed triangles so does not count triangles twice. - - """ - import numpy as np - - if weight is None or G.number_of_edges() == 0: - max_weight = 1 - else: - max_weight = max(d.get(weight, 1) for u, v, d in G.edges(data=True)) - - nodes_nbrs = ((n, G._pred[n], G._succ[n]) for n in G.nbunch_iter(nodes)) - - def wt(u, v): - return G[u][v].get(weight, 1) / max_weight - - for i, preds, succs in nodes_nbrs: - ipreds = set(preds) - {i} - isuccs = set(succs) - {i} - - directed_triangles = 0 - for j in ipreds: - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += np.cbrt( - [(wt(j, i) * wt(k, i) * wt(k, j)) for k in ipreds & jpreds] - ).sum() - directed_triangles += np.cbrt( - [(wt(j, i) * wt(k, i) * wt(j, k)) for k in ipreds & jsuccs] - ).sum() - directed_triangles += np.cbrt( - [(wt(j, i) * wt(i, k) * wt(k, j)) for k in isuccs & jpreds] - ).sum() - directed_triangles += np.cbrt( - [(wt(j, i) * wt(i, k) * wt(j, k)) for k in isuccs & jsuccs] - ).sum() - - for j in isuccs: - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += np.cbrt( - [(wt(i, j) * wt(k, i) * wt(k, j)) for k in ipreds & jpreds] - ).sum() - directed_triangles += np.cbrt( - [(wt(i, j) * wt(k, i) * wt(j, k)) for k in ipreds & jsuccs] - ).sum() - directed_triangles += np.cbrt( - [(wt(i, j) * wt(i, k) * wt(k, j)) for k in isuccs & jpreds] - ).sum() - directed_triangles += np.cbrt( - [(wt(i, j) * wt(i, k) * wt(j, k)) for k in isuccs & jsuccs] - ).sum() - - dtotal = len(ipreds) + len(isuccs) - dbidirectional = len(ipreds & isuccs) - yield (i, dtotal, dbidirectional, float(directed_triangles)) - - -@nx._dispatchable(edge_attrs="weight") -def average_clustering(G, nodes=None, weight=None, count_zeros=True): - r"""Compute the average clustering coefficient for the graph G. - - The clustering coefficient for the graph is the average, - - .. math:: - - C = \frac{1}{n}\sum_{v \in G} c_v, - - where :math:`n` is the number of nodes in `G`. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute average clustering for nodes in this container. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - count_zeros : bool - If False include only the nodes with nonzero clustering in the average. - - Returns - ------- - avg : float - Average clustering - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.average_clustering(G)) - 1.0 - - Notes - ----- - This is a space saving routine; it might be faster - to use the clustering function to get a list and then take the average. - - Self loops are ignored. - - References - ---------- - .. [1] Generalizations of the clustering coefficient to weighted - complex networks by J. Saramäki, M. Kivelä, J.-P. Onnela, - K. Kaski, and J. Kertész, Physical Review E, 75 027105 (2007). - http://jponnela.com/web_documents/a9.pdf - .. [2] Marcus Kaiser, Mean clustering coefficients: the role of isolated - nodes and leafs on clustering measures for small-world networks. - https://arxiv.org/abs/0802.2512 - """ - c = clustering(G, nodes, weight=weight).values() - if not count_zeros: - c = [v for v in c if abs(v) > 0] - return sum(c) / len(c) - - -@nx._dispatchable(edge_attrs="weight") -def clustering(G, nodes=None, weight=None): - r"""Compute the clustering coefficient for nodes. - - For unweighted graphs, the clustering of a node :math:`u` - is the fraction of possible triangles through that node that exist, - - .. math:: - - c_u = \frac{2 T(u)}{deg(u)(deg(u)-1)}, - - where :math:`T(u)` is the number of triangles through node :math:`u` and - :math:`deg(u)` is the degree of :math:`u`. - - For weighted graphs, there are several ways to define clustering [1]_. - the one used here is defined - as the geometric average of the subgraph edge weights [2]_, - - .. math:: - - c_u = \frac{1}{deg(u)(deg(u)-1))} - \sum_{vw} (\hat{w}_{uv} \hat{w}_{uw} \hat{w}_{vw})^{1/3}. - - The edge weights :math:`\hat{w}_{uv}` are normalized by the maximum weight - in the network :math:`\hat{w}_{uv} = w_{uv}/\max(w)`. - - The value of :math:`c_u` is assigned to 0 if :math:`deg(u) < 2`. - - Additionally, this weighted definition has been generalized to support negative edge weights [3]_. - - For directed graphs, the clustering is similarly defined as the fraction - of all possible directed triangles or geometric average of the subgraph - edge weights for unweighted and weighted directed graph respectively [4]_. - - .. math:: - - c_u = \frac{T(u)}{2(deg^{tot}(u)(deg^{tot}(u)-1) - 2deg^{\leftrightarrow}(u))}, - - where :math:`T(u)` is the number of directed triangles through node - :math:`u`, :math:`deg^{tot}(u)` is the sum of in degree and out degree of - :math:`u` and :math:`deg^{\leftrightarrow}(u)` is the reciprocal degree of - :math:`u`. - - - Parameters - ---------- - G : graph - - nodes : node, iterable of nodes, or None (default=None) - If a singleton node, return the number of triangles for that node. - If an iterable, compute the number of triangles for each of those nodes. - If `None` (the default) compute the number of triangles for all nodes in `G`. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - out : float, or dictionary - Clustering coefficient at specified nodes - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.clustering(G, 0)) - 1.0 - >>> print(nx.clustering(G)) - {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0} - - Notes - ----- - Self loops are ignored. - - References - ---------- - .. [1] Generalizations of the clustering coefficient to weighted - complex networks by J. Saramäki, M. Kivelä, J.-P. Onnela, - K. Kaski, and J. Kertész, Physical Review E, 75 027105 (2007). - http://jponnela.com/web_documents/a9.pdf - .. [2] Intensity and coherence of motifs in weighted complex - networks by J. P. Onnela, J. Saramäki, J. Kertész, and K. Kaski, - Physical Review E, 71(6), 065103 (2005). - .. [3] Generalization of Clustering Coefficients to Signed Correlation Networks - by G. Costantini and M. Perugini, PloS one, 9(2), e88669 (2014). - .. [4] Clustering in complex directed networks by G. Fagiolo, - Physical Review E, 76(2), 026107 (2007). - """ - if G.is_directed(): - if weight is not None: - td_iter = _directed_weighted_triangles_and_degree_iter(G, nodes, weight) - clusterc = { - v: 0 if t == 0 else t / ((dt * (dt - 1) - 2 * db) * 2) - for v, dt, db, t in td_iter - } - else: - td_iter = _directed_triangles_and_degree_iter(G, nodes) - clusterc = { - v: 0 if t == 0 else t / ((dt * (dt - 1) - 2 * db) * 2) - for v, dt, db, t in td_iter - } - else: - # The formula 2*T/(d*(d-1)) from docs is t/(d*(d-1)) here b/c t==2*T - if weight is not None: - td_iter = _weighted_triangles_and_degree_iter(G, nodes, weight) - clusterc = {v: 0 if t == 0 else t / (d * (d - 1)) for v, d, t in td_iter} - else: - td_iter = _triangles_and_degree_iter(G, nodes) - clusterc = {v: 0 if t == 0 else t / (d * (d - 1)) for v, d, t, _ in td_iter} - if nodes in G: - # Return the value of the sole entry in the dictionary. - return clusterc[nodes] - return clusterc - - -@nx._dispatchable -def transitivity(G): - r"""Compute graph transitivity, the fraction of all possible triangles - present in G. - - Possible triangles are identified by the number of "triads" - (two edges with a shared vertex). - - The transitivity is - - .. math:: - - T = 3\frac{\#triangles}{\#triads}. - - Parameters - ---------- - G : graph - - Returns - ------- - out : float - Transitivity - - Notes - ----- - Self loops are ignored. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.transitivity(G)) - 1.0 - """ - triangles_contri = [ - (t, d * (d - 1)) for v, d, t, _ in _triangles_and_degree_iter(G) - ] - # If the graph is empty - if len(triangles_contri) == 0: - return 0 - triangles, contri = map(sum, zip(*triangles_contri)) - return 0 if triangles == 0 else triangles / contri - - -@nx._dispatchable -def square_clustering(G, nodes=None): - r"""Compute the squares clustering coefficient for nodes. - - For each node return the fraction of possible squares that exist at - the node [1]_ - - .. math:: - C_4(v) = \frac{ \sum_{u=1}^{k_v} - \sum_{w=u+1}^{k_v} q_v(u,w) }{ \sum_{u=1}^{k_v} - \sum_{w=u+1}^{k_v} [a_v(u,w) + q_v(u,w)]}, - - where :math:`q_v(u,w)` are the number of common neighbors of :math:`u` and - :math:`w` other than :math:`v` (ie squares), and :math:`a_v(u,w) = (k_u - - (1+q_v(u,w)+\theta_{uv})) + (k_w - (1+q_v(u,w)+\theta_{uw}))`, where - :math:`\theta_{uw} = 1` if :math:`u` and :math:`w` are connected and 0 - otherwise. [2]_ - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute clustering for nodes in this container. - - Returns - ------- - c4 : dictionary - A dictionary keyed by node with the square clustering coefficient value. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.square_clustering(G, 0)) - 1.0 - >>> print(nx.square_clustering(G)) - {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0} - - Notes - ----- - While :math:`C_3(v)` (triangle clustering) gives the probability that - two neighbors of node v are connected with each other, :math:`C_4(v)` is - the probability that two neighbors of node v share a common - neighbor different from v. This algorithm can be applied to both - bipartite and unipartite networks. - - References - ---------- - .. [1] Pedro G. Lind, Marta C. González, and Hans J. Herrmann. 2005 - Cycles and clustering in bipartite networks. - Physical Review E (72) 056127. - .. [2] Zhang, Peng et al. Clustering Coefficient and Community Structure of - Bipartite Networks. Physica A: Statistical Mechanics and its Applications 387.27 (2008): 6869–6875. - https://arxiv.org/abs/0710.0117v1 - """ - if nodes is None: - node_iter = G - else: - node_iter = G.nbunch_iter(nodes) - clustering = {} - for v in node_iter: - clustering[v] = 0 - potential = 0 - for u, w in combinations(G[v], 2): - squares = len((set(G[u]) & set(G[w])) - {v}) - clustering[v] += squares - degm = squares + 1 - if w in G[u]: - degm += 1 - potential += (len(G[u]) - degm) + (len(G[w]) - degm) + squares - if potential > 0: - clustering[v] /= potential - if nodes in G: - # Return the value of the sole entry in the dictionary. - return clustering[nodes] - return clustering - - -@not_implemented_for("directed") -@nx._dispatchable -def generalized_degree(G, nodes=None): - r"""Compute the generalized degree for nodes. - - For each node, the generalized degree shows how many edges of given - triangle multiplicity the node is connected to. The triangle multiplicity - of an edge is the number of triangles an edge participates in. The - generalized degree of node :math:`i` can be written as a vector - :math:`\mathbf{k}_i=(k_i^{(0)}, \dotsc, k_i^{(N-2)})` where - :math:`k_i^{(j)}` is the number of edges attached to node :math:`i` that - participate in :math:`j` triangles. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute the generalized degree for nodes in this container. - - Returns - ------- - out : Counter, or dictionary of Counters - Generalized degree of specified nodes. The Counter is keyed by edge - triangle multiplicity. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.generalized_degree(G, 0)) - Counter({3: 4}) - >>> print(nx.generalized_degree(G)) - {0: Counter({3: 4}), 1: Counter({3: 4}), 2: Counter({3: 4}), 3: Counter({3: 4}), 4: Counter({3: 4})} - - To recover the number of triangles attached to a node: - - >>> k1 = nx.generalized_degree(G, 0) - >>> sum([k * v for k, v in k1.items()]) / 2 == nx.triangles(G, 0) - True - - Notes - ----- - Self loops are ignored. - - In a network of N nodes, the highest triangle multiplicity an edge can have - is N-2. - - The return value does not include a `zero` entry if no edges of a - particular triangle multiplicity are present. - - The number of triangles node :math:`i` is attached to can be recovered from - the generalized degree :math:`\mathbf{k}_i=(k_i^{(0)}, \dotsc, - k_i^{(N-2)})` by :math:`(k_i^{(1)}+2k_i^{(2)}+\dotsc +(N-2)k_i^{(N-2)})/2`. - - References - ---------- - .. [1] Networks with arbitrary edge multiplicities by V. Zlatić, - D. Garlaschelli and G. Caldarelli, EPL (Europhysics Letters), - Volume 97, Number 2 (2012). - https://iopscience.iop.org/article/10.1209/0295-5075/97/28005 - """ - if nodes in G: - return next(_triangles_and_degree_iter(G, nodes))[3] - return {v: gd for v, d, t, gd in _triangles_and_degree_iter(G, nodes)} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/__init__.py deleted file mode 100644 index 39381d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from networkx.algorithms.coloring.greedy_coloring import * -from networkx.algorithms.coloring.equitable_coloring import equitable_color - -__all__ = ["greedy_color", "equitable_color"] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/equitable_coloring.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/equitable_coloring.py deleted file mode 100644 index e464a07..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/equitable_coloring.py +++ /dev/null @@ -1,505 +0,0 @@ -""" -Equitable coloring of graphs with bounded degree. -""" - -from collections import defaultdict - -import networkx as nx - -__all__ = ["equitable_color"] - - -@nx._dispatchable -def is_coloring(G, coloring): - """Determine if the coloring is a valid coloring for the graph G.""" - # Verify that the coloring is valid. - return all(coloring[s] != coloring[d] for s, d in G.edges) - - -@nx._dispatchable -def is_equitable(G, coloring, num_colors=None): - """Determines if the coloring is valid and equitable for the graph G.""" - - if not is_coloring(G, coloring): - return False - - # Verify whether it is equitable. - color_set_size = defaultdict(int) - for color in coloring.values(): - color_set_size[color] += 1 - - if num_colors is not None: - for color in range(num_colors): - if color not in color_set_size: - # These colors do not have any vertices attached to them. - color_set_size[color] = 0 - - # If there are more than 2 distinct values, the coloring cannot be equitable - all_set_sizes = set(color_set_size.values()) - if len(all_set_sizes) == 0 and num_colors is None: # Was an empty graph - return True - elif len(all_set_sizes) == 1: - return True - elif len(all_set_sizes) == 2: - a, b = list(all_set_sizes) - return abs(a - b) <= 1 - else: # len(all_set_sizes) > 2: - return False - - -def make_C_from_F(F): - C = defaultdict(list) - for node, color in F.items(): - C[color].append(node) - - return C - - -def make_N_from_L_C(L, C): - nodes = L.keys() - colors = C.keys() - return { - (node, color): sum(1 for v in L[node] if v in C[color]) - for node in nodes - for color in colors - } - - -def make_H_from_C_N(C, N): - return { - (c1, c2): sum(1 for node in C[c1] if N[(node, c2)] == 0) for c1 in C for c2 in C - } - - -def change_color(u, X, Y, N, H, F, C, L): - """Change the color of 'u' from X to Y and update N, H, F, C.""" - assert F[u] == X and X != Y - - # Change the class of 'u' from X to Y - F[u] = Y - - for k in C: - # 'u' witnesses an edge from k -> Y instead of from k -> X now. - if N[u, k] == 0: - H[(X, k)] -= 1 - H[(Y, k)] += 1 - - for v in L[u]: - # 'v' has lost a neighbor in X and gained one in Y - N[(v, X)] -= 1 - N[(v, Y)] += 1 - - if N[(v, X)] == 0: - # 'v' witnesses F[v] -> X - H[(F[v], X)] += 1 - - if N[(v, Y)] == 1: - # 'v' no longer witnesses F[v] -> Y - H[(F[v], Y)] -= 1 - - C[X].remove(u) - C[Y].append(u) - - -def move_witnesses(src_color, dst_color, N, H, F, C, T_cal, L): - """Move witness along a path from src_color to dst_color.""" - X = src_color - while X != dst_color: - Y = T_cal[X] - # Move _any_ witness from X to Y = T_cal[X] - w = next(x for x in C[X] if N[(x, Y)] == 0) - change_color(w, X, Y, N=N, H=H, F=F, C=C, L=L) - X = Y - - -@nx._dispatchable(mutates_input=True) -def pad_graph(G, num_colors): - """Add a disconnected complete clique K_p such that the number of nodes in - the graph becomes a multiple of `num_colors`. - - Assumes that the graph's nodes are labelled using integers. - - Returns the number of nodes with each color. - """ - - n_ = len(G) - r = num_colors - 1 - - # Ensure that the number of nodes in G is a multiple of (r + 1) - s = n_ // (r + 1) - if n_ != s * (r + 1): - p = (r + 1) - n_ % (r + 1) - s += 1 - - # Complete graph K_p between (imaginary) nodes [n_, ... , n_ + p] - K = nx.relabel_nodes(nx.complete_graph(p), {idx: idx + n_ for idx in range(p)}) - G.add_edges_from(K.edges) - - return s - - -def procedure_P(V_minus, V_plus, N, H, F, C, L, excluded_colors=None): - """Procedure P as described in the paper.""" - - if excluded_colors is None: - excluded_colors = set() - - A_cal = set() - T_cal = {} - R_cal = [] - - # BFS to determine A_cal, i.e. colors reachable from V- - reachable = [V_minus] - marked = set(reachable) - idx = 0 - - while idx < len(reachable): - pop = reachable[idx] - idx += 1 - - A_cal.add(pop) - R_cal.append(pop) - - # TODO: Checking whether a color has been visited can be made faster by - # using a look-up table instead of testing for membership in a set by a - # logarithmic factor. - next_layer = [] - for k in C: - if ( - H[(k, pop)] > 0 - and k not in A_cal - and k not in excluded_colors - and k not in marked - ): - next_layer.append(k) - - for dst in next_layer: - # Record that `dst` can reach `pop` - T_cal[dst] = pop - - marked.update(next_layer) - reachable.extend(next_layer) - - # Variables for the algorithm - b = len(C) - len(A_cal) - - if V_plus in A_cal: - # Easy case: V+ is in A_cal - # Move one node from V+ to V- using T_cal to find the parents. - move_witnesses(V_plus, V_minus, N=N, H=H, F=F, C=C, T_cal=T_cal, L=L) - else: - # If there is a solo edge, we can resolve the situation by - # moving witnesses from B to A, making G[A] equitable and then - # recursively balancing G[B - w] with a different V_minus and - # but the same V_plus. - - A_0 = set() - A_cal_0 = set() - num_terminal_sets_found = 0 - made_equitable = False - - for W_1 in R_cal[::-1]: - for v in C[W_1]: - X = None - - for U in C: - if N[(v, U)] == 0 and U in A_cal and U != W_1: - X = U - - # v does not witness an edge in H[A_cal] - if X is None: - continue - - for U in C: - # Note: Departing from the paper here. - if N[(v, U)] >= 1 and U not in A_cal: - X_prime = U - w = v - - try: - # Finding the solo neighbor of w in X_prime - y = next( - node - for node in L[w] - if F[node] == X_prime and N[(node, W_1)] == 1 - ) - except StopIteration: - pass - else: - W = W_1 - - # Move w from W to X, now X has one extra node. - change_color(w, W, X, N=N, H=H, F=F, C=C, L=L) - - # Move witness from X to V_minus, making the coloring - # equitable. - move_witnesses( - src_color=X, - dst_color=V_minus, - N=N, - H=H, - F=F, - C=C, - T_cal=T_cal, - L=L, - ) - - # Move y from X_prime to W, making W the correct size. - change_color(y, X_prime, W, N=N, H=H, F=F, C=C, L=L) - - # Then call the procedure on G[B - y] - procedure_P( - V_minus=X_prime, - V_plus=V_plus, - N=N, - H=H, - C=C, - F=F, - L=L, - excluded_colors=excluded_colors.union(A_cal), - ) - made_equitable = True - break - - if made_equitable: - break - else: - # No node in W_1 was found such that - # it had a solo-neighbor. - A_cal_0.add(W_1) - A_0.update(C[W_1]) - num_terminal_sets_found += 1 - - if num_terminal_sets_found == b: - # Otherwise, construct the maximal independent set and find - # a pair of z_1, z_2 as in Case II. - - # BFS to determine B_cal': the set of colors reachable from V+ - B_cal_prime = set() - T_cal_prime = {} - - reachable = [V_plus] - marked = set(reachable) - idx = 0 - while idx < len(reachable): - pop = reachable[idx] - idx += 1 - - B_cal_prime.add(pop) - - # No need to check for excluded_colors here because - # they only exclude colors from A_cal - next_layer = [ - k - for k in C - if H[(pop, k)] > 0 and k not in B_cal_prime and k not in marked - ] - - for dst in next_layer: - T_cal_prime[pop] = dst - - marked.update(next_layer) - reachable.extend(next_layer) - - # Construct the independent set of G[B'] - I_set = set() - I_covered = set() - W_covering = {} - - B_prime = [node for k in B_cal_prime for node in C[k]] - - # Add the nodes in V_plus to I first. - for z in C[V_plus] + B_prime: - if z in I_covered or F[z] not in B_cal_prime: - continue - - I_set.add(z) - I_covered.add(z) - I_covered.update(list(L[z])) - - for w in L[z]: - if F[w] in A_cal_0 and N[(z, F[w])] == 1: - if w not in W_covering: - W_covering[w] = z - else: - # Found z1, z2 which have the same solo - # neighbor in some W - z_1 = W_covering[w] - # z_2 = z - - Z = F[z_1] - W = F[w] - - # shift nodes along W, V- - move_witnesses( - W, V_minus, N=N, H=H, F=F, C=C, T_cal=T_cal, L=L - ) - - # shift nodes along V+ to Z - move_witnesses( - V_plus, - Z, - N=N, - H=H, - F=F, - C=C, - T_cal=T_cal_prime, - L=L, - ) - - # change color of z_1 to W - change_color(z_1, Z, W, N=N, H=H, F=F, C=C, L=L) - - # change color of w to some color in B_cal - W_plus = next( - k for k in C if N[(w, k)] == 0 and k not in A_cal - ) - change_color(w, W, W_plus, N=N, H=H, F=F, C=C, L=L) - - # recurse with G[B \cup W*] - excluded_colors.update( - [k for k in C if k != W and k not in B_cal_prime] - ) - procedure_P( - V_minus=W, - V_plus=W_plus, - N=N, - H=H, - C=C, - F=F, - L=L, - excluded_colors=excluded_colors, - ) - - made_equitable = True - break - - if made_equitable: - break - else: - assert False, ( - "Must find a w which is the solo neighbor " - "of two vertices in B_cal_prime." - ) - - if made_equitable: - break - - -@nx._dispatchable -def equitable_color(G, num_colors): - """Provides an equitable coloring for nodes of `G`. - - Attempts to color a graph using `num_colors` colors, where no neighbors of - a node can have same color as the node itself and the number of nodes with - each color differ by at most 1. `num_colors` must be greater than the - maximum degree of `G`. The algorithm is described in [1]_ and has - complexity O(num_colors * n**2). - - Parameters - ---------- - G : networkX graph - The nodes of this graph will be colored. - - num_colors : number of colors to use - This number must be at least one more than the maximum degree of nodes - in the graph. - - Returns - ------- - A dictionary with keys representing nodes and values representing - corresponding coloring. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> nx.coloring.equitable_color(G, num_colors=3) # doctest: +SKIP - {0: 2, 1: 1, 2: 2, 3: 0} - - Raises - ------ - NetworkXAlgorithmError - If `num_colors` is not at least the maximum degree of the graph `G` - - References - ---------- - .. [1] Kierstead, H. A., Kostochka, A. V., Mydlarz, M., & Szemerédi, E. - (2010). A fast algorithm for equitable coloring. Combinatorica, 30(2), - 217-224. - """ - - # Map nodes to integers for simplicity later. - nodes_to_int = {} - int_to_nodes = {} - - for idx, node in enumerate(G.nodes): - nodes_to_int[node] = idx - int_to_nodes[idx] = node - - G = nx.relabel_nodes(G, nodes_to_int, copy=True) - - # Basic graph statistics and sanity check. - if len(G.nodes) > 0: - r_ = max(G.degree(node) for node in G.nodes) - else: - r_ = 0 - - if r_ >= num_colors: - raise nx.NetworkXAlgorithmError( - f"Graph has maximum degree {r_}, needs " - f"{r_ + 1} (> {num_colors}) colors for guaranteed coloring." - ) - - # Ensure that the number of nodes in G is a multiple of (r + 1) - pad_graph(G, num_colors) - - # Starting the algorithm. - # L = {node: list(G.neighbors(node)) for node in G.nodes} - L_ = {node: [] for node in G.nodes} - - # Arbitrary equitable allocation of colors to nodes. - F = {node: idx % num_colors for idx, node in enumerate(G.nodes)} - - C = make_C_from_F(F) - - # The neighborhood is empty initially. - N = make_N_from_L_C(L_, C) - - # Currently all nodes witness all edges. - H = make_H_from_C_N(C, N) - - # Start of algorithm. - edges_seen = set() - - for u in sorted(G.nodes): - for v in sorted(G.neighbors(u)): - # Do not double count edges if (v, u) has already been seen. - if (v, u) in edges_seen: - continue - - edges_seen.add((u, v)) - - L_[u].append(v) - L_[v].append(u) - - N[(u, F[v])] += 1 - N[(v, F[u])] += 1 - - if F[u] != F[v]: - # Were 'u' and 'v' witnesses for F[u] -> F[v] or F[v] -> F[u]? - if N[(u, F[v])] == 1: - H[F[u], F[v]] -= 1 # u cannot witness an edge between F[u], F[v] - - if N[(v, F[u])] == 1: - H[F[v], F[u]] -= 1 # v cannot witness an edge between F[v], F[u] - - if N[(u, F[u])] != 0: - # Find the first color where 'u' does not have any neighbors. - Y = next(k for k in C if N[(u, k)] == 0) - X = F[u] - change_color(u, X, Y, N=N, H=H, F=F, C=C, L=L_) - - # Procedure P - procedure_P(V_minus=X, V_plus=Y, N=N, H=H, F=F, C=C, L=L_) - - return {int_to_nodes[x]: F[x] for x in int_to_nodes} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/greedy_coloring.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/greedy_coloring.py deleted file mode 100644 index 9be0780..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/greedy_coloring.py +++ /dev/null @@ -1,565 +0,0 @@ -""" -Greedy graph coloring using various strategies. -""" - -import itertools -from collections import defaultdict, deque - -import networkx as nx -from networkx.utils import arbitrary_element, py_random_state - -__all__ = [ - "greedy_color", - "strategy_connected_sequential", - "strategy_connected_sequential_bfs", - "strategy_connected_sequential_dfs", - "strategy_independent_set", - "strategy_largest_first", - "strategy_random_sequential", - "strategy_saturation_largest_first", - "strategy_smallest_last", -] - - -def strategy_largest_first(G, colors): - """Returns a list of the nodes of ``G`` in decreasing order by - degree. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return sorted(G, key=G.degree, reverse=True) - - -@py_random_state(2) -def strategy_random_sequential(G, colors, seed=None): - """Returns a random permutation of the nodes of ``G`` as a list. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - nodes = list(G) - seed.shuffle(nodes) - return nodes - - -def strategy_smallest_last(G, colors): - """Returns a deque of the nodes of ``G``, "smallest" last. - - Specifically, the degrees of each node are tracked in a bucket queue. - From this, the node of minimum degree is repeatedly popped from the - graph, updating its neighbors' degrees. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - This implementation of the strategy runs in $O(n + m)$ time - (ignoring polylogarithmic factors), where $n$ is the number of nodes - and $m$ is the number of edges. - - This strategy is related to :func:`strategy_independent_set`: if we - interpret each node removed as an independent set of size one, then - this strategy chooses an independent set of size one instead of a - maximal independent set. - - """ - H = G.copy() - result = deque() - - # Build initial degree list (i.e. the bucket queue data structure) - degrees = defaultdict(set) # set(), for fast random-access removals - lbound = float("inf") - for node, d in H.degree(): - degrees[d].add(node) - lbound = min(lbound, d) # Lower bound on min-degree. - - def find_min_degree(): - # Save time by starting the iterator at `lbound`, not 0. - # The value that we find will be our new `lbound`, which we set later. - return next(d for d in itertools.count(lbound) if d in degrees) - - for _ in G: - # Pop a min-degree node and add it to the list. - min_degree = find_min_degree() - u = degrees[min_degree].pop() - if not degrees[min_degree]: # Clean up the degree list. - del degrees[min_degree] - result.appendleft(u) - - # Update degrees of removed node's neighbors. - for v in H[u]: - degree = H.degree(v) - degrees[degree].remove(v) - if not degrees[degree]: # Clean up the degree list. - del degrees[degree] - degrees[degree - 1].add(v) - - # Finally, remove the node. - H.remove_node(u) - lbound = min_degree - 1 # Subtract 1 in case of tied neighbors. - - return result - - -def _maximal_independent_set(G): - """Returns a maximal independent set of nodes in ``G`` by repeatedly - choosing an independent node of minimum degree (with respect to the - subgraph of unchosen nodes). - - """ - result = set() - remaining = set(G) - while remaining: - G = G.subgraph(remaining) - v = min(remaining, key=G.degree) - result.add(v) - remaining -= set(G[v]) | {v} - return result - - -def strategy_independent_set(G, colors): - """Uses a greedy independent set removal strategy to determine the - colors. - - This function updates ``colors`` **in-place** and return ``None``, - unlike the other strategy functions in this module. - - This algorithm repeatedly finds and removes a maximal independent - set, assigning each node in the set an unused color. - - ``G`` is a NetworkX graph. - - This strategy is related to :func:`strategy_smallest_last`: in that - strategy, an independent set of size one is chosen at each step - instead of a maximal independent set. - - """ - remaining_nodes = set(G) - while len(remaining_nodes) > 0: - nodes = _maximal_independent_set(G.subgraph(remaining_nodes)) - remaining_nodes -= nodes - yield from nodes - - -def strategy_connected_sequential_bfs(G, colors): - """Returns an iterable over nodes in ``G`` in the order given by a - breadth-first traversal. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return strategy_connected_sequential(G, colors, "bfs") - - -def strategy_connected_sequential_dfs(G, colors): - """Returns an iterable over nodes in ``G`` in the order given by a - depth-first traversal. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return strategy_connected_sequential(G, colors, "dfs") - - -def strategy_connected_sequential(G, colors, traversal="bfs"): - """Returns an iterable over nodes in ``G`` in the order given by a - breadth-first or depth-first traversal. - - ``traversal`` must be one of the strings ``'dfs'`` or ``'bfs'``, - representing depth-first traversal or breadth-first traversal, - respectively. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - if traversal == "bfs": - traverse = nx.bfs_edges - elif traversal == "dfs": - traverse = nx.dfs_edges - else: - raise nx.NetworkXError( - "Please specify one of the strings 'bfs' or" - " 'dfs' for connected sequential ordering" - ) - for component in nx.connected_components(G): - source = arbitrary_element(component) - # Yield the source node, then all the nodes in the specified - # traversal order. - yield source - for _, end in traverse(G.subgraph(component), source): - yield end - - -def strategy_saturation_largest_first(G, colors): - """Iterates over all the nodes of ``G`` in "saturation order" (also - known as "DSATUR"). - - ``G`` is a NetworkX graph. ``colors`` is a dictionary mapping nodes of - ``G`` to colors, for those nodes that have already been colored. - - """ - distinct_colors = {v: set() for v in G} - - # Add the node color assignments given in colors to the - # distinct colors set for each neighbor of that node - for node, color in colors.items(): - for neighbor in G[node]: - distinct_colors[neighbor].add(color) - - # Check that the color assignments in colors are valid - # i.e. no neighboring nodes have the same color - if len(colors) >= 2: - for node, color in colors.items(): - if color in distinct_colors[node]: - raise nx.NetworkXError("Neighboring nodes must have different colors") - - # If 0 nodes have been colored, simply choose the node of highest degree. - if not colors: - node = max(G, key=G.degree) - yield node - # Add the color 0 to the distinct colors set for each - # neighbor of that node. - for v in G[node]: - distinct_colors[v].add(0) - - while len(G) != len(colors): - # Update the distinct color sets for the neighbors. - for node, color in colors.items(): - for neighbor in G[node]: - distinct_colors[neighbor].add(color) - - # Compute the maximum saturation and the set of nodes that - # achieve that saturation. - saturation = {v: len(c) for v, c in distinct_colors.items() if v not in colors} - # Yield the node with the highest saturation, and break ties by - # degree. - node = max(saturation, key=lambda v: (saturation[v], G.degree(v))) - yield node - - -#: Dictionary mapping name of a strategy as a string to the strategy function. -STRATEGIES = { - "largest_first": strategy_largest_first, - "random_sequential": strategy_random_sequential, - "smallest_last": strategy_smallest_last, - "independent_set": strategy_independent_set, - "connected_sequential_bfs": strategy_connected_sequential_bfs, - "connected_sequential_dfs": strategy_connected_sequential_dfs, - "connected_sequential": strategy_connected_sequential, - "saturation_largest_first": strategy_saturation_largest_first, - "DSATUR": strategy_saturation_largest_first, -} - - -@nx._dispatchable -def greedy_color(G, strategy="largest_first", interchange=False): - """Color a graph using various strategies of greedy graph coloring. - - Attempts to color a graph using as few colors as possible, where no - neighbors of a node can have same color as the node itself. The - given strategy determines the order in which nodes are colored. - - The strategies are described in [1]_, and smallest-last is based on - [2]_. - - Parameters - ---------- - G : NetworkX graph - - strategy : string or function(G, colors) - A function (or a string representing a function) that provides - the coloring strategy, by returning nodes in the ordering they - should be colored. ``G`` is the graph, and ``colors`` is a - dictionary of the currently assigned colors, keyed by nodes. The - function must return an iterable over all the nodes in ``G``. - - If the strategy function is an iterator generator (that is, a - function with ``yield`` statements), keep in mind that the - ``colors`` dictionary will be updated after each ``yield``, since - this function chooses colors greedily. - - If ``strategy`` is a string, it must be one of the following, - each of which represents one of the built-in strategy functions. - - * ``'largest_first'`` - * ``'random_sequential'`` - * ``'smallest_last'`` - * ``'independent_set'`` - * ``'connected_sequential_bfs'`` - * ``'connected_sequential_dfs'`` - * ``'connected_sequential'`` (alias for the previous strategy) - * ``'saturation_largest_first'`` - * ``'DSATUR'`` (alias for the previous strategy) - - interchange: bool - Will use the color interchange algorithm described by [3]_ if set - to ``True``. - - Note that ``saturation_largest_first`` and ``independent_set`` - do not work with interchange. Furthermore, if you use - interchange with your own strategy function, you cannot rely - on the values in the ``colors`` argument. - - Returns - ------- - A dictionary with keys representing nodes and values representing - corresponding coloring. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> d = nx.coloring.greedy_color(G, strategy="largest_first") - >>> d in [{0: 0, 1: 1, 2: 0, 3: 1}, {0: 1, 1: 0, 2: 1, 3: 0}] - True - - Raises - ------ - NetworkXPointlessConcept - If ``strategy`` is ``saturation_largest_first`` or - ``independent_set`` and ``interchange`` is ``True``. - - References - ---------- - .. [1] Adrian Kosowski, and Krzysztof Manuszewski, - Classical Coloring of Graphs, Graph Colorings, 2-19, 2004. - ISBN 0-8218-3458-4. - .. [2] David W. Matula, and Leland L. Beck, "Smallest-last - ordering and clustering and graph coloring algorithms." *J. ACM* 30, - 3 (July 1983), 417–427. - .. [3] Maciej M. Sysło, Narsingh Deo, Janusz S. Kowalik, - Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983. - ISBN 0-486-45353-7. - - """ - if len(G) == 0: - return {} - # Determine the strategy provided by the caller. - strategy = STRATEGIES.get(strategy, strategy) - if not callable(strategy): - raise nx.NetworkXError( - f"strategy must be callable or a valid string. {strategy} not valid." - ) - # Perform some validation on the arguments before executing any - # strategy functions. - if interchange: - if strategy is strategy_independent_set: - msg = "interchange cannot be used with independent_set" - raise nx.NetworkXPointlessConcept(msg) - if strategy is strategy_saturation_largest_first: - msg = "interchange cannot be used with" " saturation_largest_first" - raise nx.NetworkXPointlessConcept(msg) - colors = {} - nodes = strategy(G, colors) - if interchange: - return _greedy_coloring_with_interchange(G, nodes) - for u in nodes: - # Set to keep track of colors of neighbors - nbr_colors = {colors[v] for v in G[u] if v in colors} - # Find the first unused color. - for color in itertools.count(): - if color not in nbr_colors: - break - # Assign the new color to the current node. - colors[u] = color - return colors - - -# Tools for coloring with interchanges -class _Node: - __slots__ = ["node_id", "color", "adj_list", "adj_color"] - - def __init__(self, node_id, n): - self.node_id = node_id - self.color = -1 - self.adj_list = None - self.adj_color = [None for _ in range(n)] - - def __repr__(self): - return ( - f"Node_id: {self.node_id}, Color: {self.color}, " - f"Adj_list: ({self.adj_list}), adj_color: ({self.adj_color})" - ) - - def assign_color(self, adj_entry, color): - adj_entry.col_prev = None - adj_entry.col_next = self.adj_color[color] - self.adj_color[color] = adj_entry - if adj_entry.col_next is not None: - adj_entry.col_next.col_prev = adj_entry - - def clear_color(self, adj_entry, color): - if adj_entry.col_prev is None: - self.adj_color[color] = adj_entry.col_next - else: - adj_entry.col_prev.col_next = adj_entry.col_next - if adj_entry.col_next is not None: - adj_entry.col_next.col_prev = adj_entry.col_prev - - def iter_neighbors(self): - adj_node = self.adj_list - while adj_node is not None: - yield adj_node - adj_node = adj_node.next - - def iter_neighbors_color(self, color): - adj_color_node = self.adj_color[color] - while adj_color_node is not None: - yield adj_color_node.node_id - adj_color_node = adj_color_node.col_next - - -class _AdjEntry: - __slots__ = ["node_id", "next", "mate", "col_next", "col_prev"] - - def __init__(self, node_id): - self.node_id = node_id - self.next = None - self.mate = None - self.col_next = None - self.col_prev = None - - def __repr__(self): - col_next = None if self.col_next is None else self.col_next.node_id - col_prev = None if self.col_prev is None else self.col_prev.node_id - return ( - f"Node_id: {self.node_id}, Next: ({self.next}), " - f"Mate: ({self.mate.node_id}), " - f"col_next: ({col_next}), col_prev: ({col_prev})" - ) - - -def _greedy_coloring_with_interchange(G, nodes): - """Return a coloring for `original_graph` using interchange approach - - This procedure is an adaption of the algorithm described by [1]_, - and is an implementation of coloring with interchange. Please be - advised, that the datastructures used are rather complex because - they are optimized to minimize the time spent identifying - subcomponents of the graph, which are possible candidates for color - interchange. - - Parameters - ---------- - G : NetworkX graph - The graph to be colored - - nodes : list - nodes ordered using the strategy of choice - - Returns - ------- - dict : - A dictionary keyed by node to a color value - - References - ---------- - .. [1] Maciej M. Syslo, Narsingh Deo, Janusz S. Kowalik, - Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983. - ISBN 0-486-45353-7. - """ - n = len(G) - - graph = {node: _Node(node, n) for node in G} - - for node1, node2 in G.edges(): - adj_entry1 = _AdjEntry(node2) - adj_entry2 = _AdjEntry(node1) - adj_entry1.mate = adj_entry2 - adj_entry2.mate = adj_entry1 - node1_head = graph[node1].adj_list - adj_entry1.next = node1_head - graph[node1].adj_list = adj_entry1 - node2_head = graph[node2].adj_list - adj_entry2.next = node2_head - graph[node2].adj_list = adj_entry2 - - k = 0 - for node in nodes: - # Find the smallest possible, unused color - neighbors = graph[node].iter_neighbors() - col_used = {graph[adj_node.node_id].color for adj_node in neighbors} - col_used.discard(-1) - k1 = next(itertools.dropwhile(lambda x: x in col_used, itertools.count())) - - # k1 is now the lowest available color - if k1 > k: - connected = True - visited = set() - col1 = -1 - col2 = -1 - while connected and col1 < k: - col1 += 1 - neighbor_cols = graph[node].iter_neighbors_color(col1) - col1_adj = list(neighbor_cols) - - col2 = col1 - while connected and col2 < k: - col2 += 1 - visited = set(col1_adj) - frontier = list(col1_adj) - i = 0 - while i < len(frontier): - search_node = frontier[i] - i += 1 - col_opp = col2 if graph[search_node].color == col1 else col1 - neighbor_cols = graph[search_node].iter_neighbors_color(col_opp) - - for neighbor in neighbor_cols: - if neighbor not in visited: - visited.add(neighbor) - frontier.append(neighbor) - - # Search if node is not adj to any col2 vertex - connected = ( - len( - visited.intersection(graph[node].iter_neighbors_color(col2)) - ) - > 0 - ) - - # If connected is false then we can swap !!! - if not connected: - # Update all the nodes in the component - for search_node in visited: - graph[search_node].color = ( - col2 if graph[search_node].color == col1 else col1 - ) - col2_adj = graph[search_node].adj_color[col2] - graph[search_node].adj_color[col2] = graph[search_node].adj_color[ - col1 - ] - graph[search_node].adj_color[col1] = col2_adj - - # Update all the neighboring nodes - for search_node in visited: - col = graph[search_node].color - col_opp = col1 if col == col2 else col2 - for adj_node in graph[search_node].iter_neighbors(): - if graph[adj_node.node_id].color != col_opp: - # Direct reference to entry - adj_mate = adj_node.mate - graph[adj_node.node_id].clear_color(adj_mate, col_opp) - graph[adj_node.node_id].assign_color(adj_mate, col) - k1 = col1 - - # We can color this node color k1 - graph[node].color = k1 - k = max(k1, k) - - # Update the neighbors of this node - for adj_node in graph[node].iter_neighbors(): - adj_mate = adj_node.mate - graph[adj_node.node_id].assign_color(adj_mate, k1) - - return {node.node_id: node.color for node in graph.values()} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/tests/test_coloring.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/tests/test_coloring.py deleted file mode 100644 index 1e5a913..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/coloring/tests/test_coloring.py +++ /dev/null @@ -1,863 +0,0 @@ -"""Greedy coloring test suite.""" - -import itertools - -import pytest - -import networkx as nx - -is_coloring = nx.algorithms.coloring.equitable_coloring.is_coloring -is_equitable = nx.algorithms.coloring.equitable_coloring.is_equitable - - -ALL_STRATEGIES = [ - "largest_first", - "random_sequential", - "smallest_last", - "independent_set", - "connected_sequential_bfs", - "connected_sequential_dfs", - "connected_sequential", - "saturation_largest_first", - "DSATUR", -] - -# List of strategies where interchange=True results in an error -INTERCHANGE_INVALID = ["independent_set", "saturation_largest_first", "DSATUR"] - - -class TestColoring: - def test_basic_cases(self): - def check_basic_case(graph_func, n_nodes, strategy, interchange): - graph = graph_func() - coloring = nx.coloring.greedy_color( - graph, strategy=strategy, interchange=interchange - ) - assert verify_length(coloring, n_nodes) - assert verify_coloring(graph, coloring) - - for graph_func, n_nodes in BASIC_TEST_CASES.items(): - for interchange in [True, False]: - for strategy in ALL_STRATEGIES: - check_basic_case(graph_func, n_nodes, strategy, False) - if strategy not in INTERCHANGE_INVALID: - check_basic_case(graph_func, n_nodes, strategy, True) - - def test_special_cases(self): - def check_special_case(strategy, graph_func, interchange, colors): - graph = graph_func() - coloring = nx.coloring.greedy_color( - graph, strategy=strategy, interchange=interchange - ) - if not hasattr(colors, "__len__"): - colors = [colors] - assert any(verify_length(coloring, n_colors) for n_colors in colors) - assert verify_coloring(graph, coloring) - - for strategy, arglist in SPECIAL_TEST_CASES.items(): - for args in arglist: - check_special_case(strategy, args[0], args[1], args[2]) - - def test_interchange_invalid(self): - graph = one_node_graph() - for strategy in INTERCHANGE_INVALID: - pytest.raises( - nx.NetworkXPointlessConcept, - nx.coloring.greedy_color, - graph, - strategy=strategy, - interchange=True, - ) - - def test_bad_inputs(self): - graph = one_node_graph() - pytest.raises( - nx.NetworkXError, - nx.coloring.greedy_color, - graph, - strategy="invalid strategy", - ) - - def test_strategy_as_function(self): - graph = lf_shc() - colors_1 = nx.coloring.greedy_color(graph, "largest_first") - colors_2 = nx.coloring.greedy_color(graph, nx.coloring.strategy_largest_first) - assert colors_1 == colors_2 - - def test_seed_argument(self): - graph = lf_shc() - rs = nx.coloring.strategy_random_sequential - c1 = nx.coloring.greedy_color(graph, lambda g, c: rs(g, c, seed=1)) - for u, v in graph.edges: - assert c1[u] != c1[v] - - def test_is_coloring(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2)]) - coloring = {0: 0, 1: 1, 2: 0} - assert is_coloring(G, coloring) - - coloring[0] = 1 - assert not is_coloring(G, coloring) - assert not is_equitable(G, coloring) - - def test_is_equitable(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2)]) - coloring = {0: 0, 1: 1, 2: 0} - assert is_equitable(G, coloring) - - G.add_edges_from([(2, 3), (2, 4), (2, 5)]) - coloring[3] = 1 - coloring[4] = 1 - coloring[5] = 1 - assert is_coloring(G, coloring) - assert not is_equitable(G, coloring) - - def test_num_colors(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (0, 3)]) - pytest.raises(nx.NetworkXAlgorithmError, nx.coloring.equitable_color, G, 2) - - def test_equitable_color(self): - G = nx.fast_gnp_random_graph(n=10, p=0.2, seed=42) - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring) - - def test_equitable_color_empty(self): - G = nx.empty_graph() - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring) - - def test_equitable_color_large(self): - G = nx.fast_gnp_random_graph(100, 0.1, seed=42) - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring, num_colors=max_degree(G) + 1) - - def test_case_V_plus_not_in_A_cal(self): - # Hand crafted case to avoid the easy case. - L = { - 0: [2, 5], - 1: [3, 4], - 2: [0, 8], - 3: [1, 7], - 4: [1, 6], - 5: [0, 6], - 6: [4, 5], - 7: [3], - 8: [2], - } - - F = { - # Color 0 - 0: 0, - 1: 0, - # Color 1 - 2: 1, - 3: 1, - 4: 1, - 5: 1, - # Color 2 - 6: 2, - 7: 2, - 8: 2, - } - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=1, N=N, H=H, F=F, C=C, L=L - ) - check_state(L=L, N=N, H=H, F=F, C=C) - - def test_cast_no_solo(self): - L = { - 0: [8, 9], - 1: [10, 11], - 2: [8], - 3: [9], - 4: [10, 11], - 5: [8], - 6: [9], - 7: [10, 11], - 8: [0, 2, 5], - 9: [0, 3, 6], - 10: [1, 4, 7], - 11: [1, 4, 7], - } - - F = {0: 0, 1: 0, 2: 2, 3: 2, 4: 2, 5: 3, 6: 3, 7: 3, 8: 1, 9: 1, 10: 1, 11: 1} - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=1, N=N, H=H, F=F, C=C, L=L - ) - check_state(L=L, N=N, H=H, F=F, C=C) - - def test_hard_prob(self): - # Tests for two levels of recursion. - num_colors, s = 5, 5 - - G = nx.Graph() - G.add_edges_from( - [ - (0, 10), - (0, 11), - (0, 12), - (0, 23), - (10, 4), - (10, 9), - (10, 20), - (11, 4), - (11, 8), - (11, 16), - (12, 9), - (12, 22), - (12, 23), - (23, 7), - (1, 17), - (1, 18), - (1, 19), - (1, 24), - (17, 5), - (17, 13), - (17, 22), - (18, 5), - (19, 5), - (19, 6), - (19, 8), - (24, 7), - (24, 16), - (2, 4), - (2, 13), - (2, 14), - (2, 15), - (4, 6), - (13, 5), - (13, 21), - (14, 6), - (14, 15), - (15, 6), - (15, 21), - (3, 16), - (3, 20), - (3, 21), - (3, 22), - (16, 8), - (20, 8), - (21, 9), - (22, 7), - ] - ) - F = {node: node // s for node in range(num_colors * s)} - F[s - 1] = num_colors - 1 - - params = make_params_from_graph(G=G, F=F) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=num_colors - 1, **params - ) - check_state(**params) - - def test_hardest_prob(self): - # Tests for two levels of recursion. - num_colors, s = 10, 4 - - G = nx.Graph() - G.add_edges_from( - [ - (0, 19), - (0, 24), - (0, 29), - (0, 30), - (0, 35), - (19, 3), - (19, 7), - (19, 9), - (19, 15), - (19, 21), - (19, 24), - (19, 30), - (19, 38), - (24, 5), - (24, 11), - (24, 13), - (24, 20), - (24, 30), - (24, 37), - (24, 38), - (29, 6), - (29, 10), - (29, 13), - (29, 15), - (29, 16), - (29, 17), - (29, 20), - (29, 26), - (30, 6), - (30, 10), - (30, 15), - (30, 22), - (30, 23), - (30, 39), - (35, 6), - (35, 9), - (35, 14), - (35, 18), - (35, 22), - (35, 23), - (35, 25), - (35, 27), - (1, 20), - (1, 26), - (1, 31), - (1, 34), - (1, 38), - (20, 4), - (20, 8), - (20, 14), - (20, 18), - (20, 28), - (20, 33), - (26, 7), - (26, 10), - (26, 14), - (26, 18), - (26, 21), - (26, 32), - (26, 39), - (31, 5), - (31, 8), - (31, 13), - (31, 16), - (31, 17), - (31, 21), - (31, 25), - (31, 27), - (34, 7), - (34, 8), - (34, 13), - (34, 18), - (34, 22), - (34, 23), - (34, 25), - (34, 27), - (38, 4), - (38, 9), - (38, 12), - (38, 14), - (38, 21), - (38, 27), - (2, 3), - (2, 18), - (2, 21), - (2, 28), - (2, 32), - (2, 33), - (2, 36), - (2, 37), - (2, 39), - (3, 5), - (3, 9), - (3, 13), - (3, 22), - (3, 23), - (3, 25), - (3, 27), - (18, 6), - (18, 11), - (18, 15), - (18, 39), - (21, 4), - (21, 10), - (21, 14), - (21, 36), - (28, 6), - (28, 10), - (28, 14), - (28, 16), - (28, 17), - (28, 25), - (28, 27), - (32, 5), - (32, 10), - (32, 12), - (32, 16), - (32, 17), - (32, 22), - (32, 23), - (33, 7), - (33, 10), - (33, 12), - (33, 16), - (33, 17), - (33, 25), - (33, 27), - (36, 5), - (36, 8), - (36, 15), - (36, 16), - (36, 17), - (36, 25), - (36, 27), - (37, 5), - (37, 11), - (37, 15), - (37, 16), - (37, 17), - (37, 22), - (37, 23), - (39, 7), - (39, 8), - (39, 15), - (39, 22), - (39, 23), - ] - ) - F = {node: node // s for node in range(num_colors * s)} - F[s - 1] = num_colors - 1 # V- = 0, V+ = num_colors - 1 - - params = make_params_from_graph(G=G, F=F) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=num_colors - 1, **params - ) - check_state(**params) - - def test_strategy_saturation_largest_first(self): - def color_remaining_nodes( - G, - colored_nodes, - full_color_assignment=None, - nodes_to_add_between_calls=1, - ): - color_assignments = [] - aux_colored_nodes = colored_nodes.copy() - - node_iterator = nx.algorithms.coloring.greedy_coloring.strategy_saturation_largest_first( - G, aux_colored_nodes - ) - - for u in node_iterator: - # Set to keep track of colors of neighbors - nbr_colors = { - aux_colored_nodes[v] for v in G[u] if v in aux_colored_nodes - } - # Find the first unused color. - for color in itertools.count(): - if color not in nbr_colors: - break - aux_colored_nodes[u] = color - color_assignments.append((u, color)) - - # Color nodes between iterations - for i in range(nodes_to_add_between_calls - 1): - if not len(color_assignments) + len(colored_nodes) >= len( - full_color_assignment - ): - full_color_assignment_node, color = full_color_assignment[ - len(color_assignments) + len(colored_nodes) - ] - - # Assign the new color to the current node. - aux_colored_nodes[full_color_assignment_node] = color - color_assignments.append((full_color_assignment_node, color)) - - return color_assignments, aux_colored_nodes - - for G, _, _ in SPECIAL_TEST_CASES["saturation_largest_first"]: - G = G() - - # Check that function still works when nodes are colored between iterations - for nodes_to_add_between_calls in range(1, 5): - # Get a full color assignment, (including the order in which nodes were colored) - colored_nodes = {} - full_color_assignment, full_colored_nodes = color_remaining_nodes( - G, colored_nodes - ) - - # For each node in the color assignment, add it to colored_nodes and re-run the function - for ind, (node, color) in enumerate(full_color_assignment): - colored_nodes[node] = color - - ( - partial_color_assignment, - partial_colored_nodes, - ) = color_remaining_nodes( - G, - colored_nodes, - full_color_assignment=full_color_assignment, - nodes_to_add_between_calls=nodes_to_add_between_calls, - ) - - # Check that the color assignment and order of remaining nodes are the same - assert full_color_assignment[ind + 1 :] == partial_color_assignment - assert full_colored_nodes == partial_colored_nodes - - -# ############################ Utility functions ############################ -def verify_coloring(graph, coloring): - for node in graph.nodes(): - if node not in coloring: - return False - - color = coloring[node] - for neighbor in graph.neighbors(node): - if coloring[neighbor] == color: - return False - - return True - - -def verify_length(coloring, expected): - coloring = dict_to_sets(coloring) - return len(coloring) == expected - - -def dict_to_sets(colors): - if len(colors) == 0: - return [] - - k = max(colors.values()) + 1 - sets = [set() for _ in range(k)] - - for node, color in colors.items(): - sets[color].add(node) - - return sets - - -# ############################ Graph Generation ############################ - - -def empty_graph(): - return nx.Graph() - - -def one_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1]) - return graph - - -def two_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1, 2]) - graph.add_edges_from([(1, 2)]) - return graph - - -def three_node_clique(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.add_edges_from([(1, 2), (1, 3), (2, 3)]) - return graph - - -def disconnected(): - graph = nx.Graph() - graph.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6)]) - return graph - - -def rs_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4]) - graph.add_edges_from([(1, 2), (2, 3), (3, 4)]) - return graph - - -def slf_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from( - [(1, 2), (1, 5), (1, 6), (2, 3), (2, 7), (3, 4), (3, 7), (4, 5), (4, 6), (5, 6)] - ) - return graph - - -def slf_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - graph.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 4), - (2, 6), - (5, 7), - (5, 8), - (6, 7), - (6, 8), - (7, 8), - ] - ) - return graph - - -def lf_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([(6, 1), (1, 4), (4, 3), (3, 2), (2, 5)]) - return graph - - -def lf_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from( - [ - (1, 7), - (1, 6), - (1, 3), - (1, 4), - (7, 2), - (2, 6), - (2, 3), - (2, 5), - (5, 3), - (5, 4), - (4, 3), - ] - ) - return graph - - -def sl_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from( - [(1, 2), (1, 3), (2, 3), (1, 4), (2, 5), (3, 6), (4, 5), (4, 6), (5, 6)] - ) - return graph - - -def sl_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - graph.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 5), - (1, 7), - (2, 3), - (2, 4), - (2, 8), - (8, 4), - (8, 6), - (8, 7), - (7, 5), - (7, 6), - (3, 4), - (4, 6), - (6, 5), - (5, 3), - ] - ) - return graph - - -def gis_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4]) - graph.add_edges_from([(1, 2), (2, 3), (3, 4)]) - return graph - - -def gis_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([(1, 5), (2, 5), (3, 6), (4, 6), (5, 6)]) - return graph - - -def cs_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5]) - graph.add_edges_from([(1, 2), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (4, 5)]) - return graph - - -def rsi_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from( - [(1, 2), (1, 5), (1, 6), (2, 3), (3, 4), (4, 5), (4, 6), (5, 6)] - ) - return graph - - -def lfi_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from( - [(1, 2), (1, 5), (1, 6), (2, 3), (2, 7), (3, 4), (3, 7), (4, 5), (4, 6), (5, 6)] - ) - return graph - - -def lfi_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9]) - graph.add_edges_from( - [ - (1, 2), - (1, 5), - (1, 6), - (1, 7), - (2, 3), - (2, 8), - (2, 9), - (3, 4), - (3, 8), - (3, 9), - (4, 5), - (4, 6), - (4, 7), - (5, 6), - ] - ) - return graph - - -def sli_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 5), - (1, 7), - (2, 3), - (2, 6), - (3, 4), - (4, 5), - (4, 6), - (5, 7), - (6, 7), - ] - ) - return graph - - -def sli_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9]) - graph.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 7), - (2, 8), - (2, 9), - (3, 6), - (3, 7), - (3, 9), - (4, 5), - (4, 6), - (4, 8), - (4, 9), - (5, 6), - (5, 7), - (5, 8), - (6, 7), - (6, 9), - (7, 8), - (8, 9), - ] - ) - return graph - - -# -------------------------------------------------------------------------- -# Basic tests for all strategies -# For each basic graph function, specify the number of expected colors. -BASIC_TEST_CASES = { - empty_graph: 0, - one_node_graph: 1, - two_node_graph: 2, - disconnected: 2, - three_node_clique: 3, -} - - -# -------------------------------------------------------------------------- -# Special test cases. Each strategy has a list of tuples of the form -# (graph function, interchange, valid # of colors) -SPECIAL_TEST_CASES = { - "random_sequential": [ - (rs_shc, False, (2, 3)), - (rs_shc, True, 2), - (rsi_shc, True, (3, 4)), - ], - "saturation_largest_first": [(slf_shc, False, (3, 4)), (slf_hc, False, 4)], - "largest_first": [ - (lf_shc, False, (2, 3)), - (lf_hc, False, 4), - (lf_shc, True, 2), - (lf_hc, True, 3), - (lfi_shc, True, (3, 4)), - (lfi_hc, True, 4), - ], - "smallest_last": [ - (sl_shc, False, (3, 4)), - (sl_hc, False, 5), - (sl_shc, True, 3), - (sl_hc, True, 4), - (sli_shc, True, (3, 4)), - (sli_hc, True, 5), - ], - "independent_set": [(gis_shc, False, (2, 3)), (gis_hc, False, 3)], - "connected_sequential": [(cs_shc, False, (3, 4)), (cs_shc, True, 3)], - "connected_sequential_dfs": [(cs_shc, False, (3, 4))], -} - - -# -------------------------------------------------------------------------- -# Helper functions to test -# (graph function, interchange, valid # of colors) - - -def check_state(L, N, H, F, C): - s = len(C[0]) - num_colors = len(C.keys()) - - assert all(u in L[v] for u in L for v in L[u]) - assert all(F[u] != F[v] for u in L for v in L[u]) - assert all(len(L[u]) < num_colors for u in L) - assert all(len(C[x]) == s for x in C) - assert all(H[(c1, c2)] >= 0 for c1 in C for c2 in C) - assert all(N[(u, F[u])] == 0 for u in F) - - -def max_degree(G): - """Get the maximum degree of any node in G.""" - return max(G.degree(node) for node in G.nodes) if len(G.nodes) > 0 else 0 - - -def make_params_from_graph(G, F): - """Returns {N, L, H, C} from the given graph.""" - num_nodes = len(G) - L = {u: [] for u in range(num_nodes)} - for u, v in G.edges: - L[u].append(v) - L[v].append(u) - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - return {"N": N, "F": F, "C": C, "H": H, "L": L} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/communicability_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/communicability_alg.py deleted file mode 100644 index dea156b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/communicability_alg.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -Communicability. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["communicability", "communicability_exp"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def communicability(G): - r"""Returns communicability between all pairs of nodes in G. - - The communicability between pairs of nodes in G is the sum of - walks of different lengths starting at node u and ending at node v. - - Parameters - ---------- - G: graph - - Returns - ------- - comm: dictionary of dictionaries - Dictionary of dictionaries keyed by nodes with communicability - as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - communicability_exp: - Communicability between all pairs of nodes in G using spectral - decomposition. - communicability_betweenness_centrality: - Communicability betweenness centrality for each node in G. - - Notes - ----- - This algorithm uses a spectral decomposition of the adjacency matrix. - Let G=(V,E) be a simple undirected graph. Using the connection between - the powers of the adjacency matrix and the number of walks in the graph, - the communicability between nodes `u` and `v` based on the graph spectrum - is [1]_ - - .. math:: - C(u,v)=\sum_{j=1}^{n}\phi_{j}(u)\phi_{j}(v)e^{\lambda_{j}}, - - where `\phi_{j}(u)` is the `u\rm{th}` element of the `j\rm{th}` orthonormal - eigenvector of the adjacency matrix associated with the eigenvalue - `\lambda_{j}`. - - References - ---------- - .. [1] Ernesto Estrada, Naomichi Hatano, - "Communicability in complex networks", - Phys. Rev. E 77, 036111 (2008). - https://arxiv.org/abs/0707.0756 - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) - >>> c = nx.communicability(G) - """ - import numpy as np - - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - w, vec = np.linalg.eigh(A) - expw = np.exp(w) - mapping = dict(zip(nodelist, range(len(nodelist)))) - c = {} - # computing communicabilities - for u in G: - c[u] = {} - for v in G: - s = 0 - p = mapping[u] - q = mapping[v] - for j in range(len(nodelist)): - s += vec[:, j][p] * vec[:, j][q] * expw[j] - c[u][v] = float(s) - return c - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def communicability_exp(G): - r"""Returns communicability between all pairs of nodes in G. - - Communicability between pair of node (u,v) of node in G is the sum of - walks of different lengths starting at node u and ending at node v. - - Parameters - ---------- - G: graph - - Returns - ------- - comm: dictionary of dictionaries - Dictionary of dictionaries keyed by nodes with communicability - as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - communicability: - Communicability between pairs of nodes in G. - communicability_betweenness_centrality: - Communicability betweenness centrality for each node in G. - - Notes - ----- - This algorithm uses matrix exponentiation of the adjacency matrix. - - Let G=(V,E) be a simple undirected graph. Using the connection between - the powers of the adjacency matrix and the number of walks in the graph, - the communicability between nodes u and v is [1]_, - - .. math:: - C(u,v) = (e^A)_{uv}, - - where `A` is the adjacency matrix of G. - - References - ---------- - .. [1] Ernesto Estrada, Naomichi Hatano, - "Communicability in complex networks", - Phys. Rev. E 77, 036111 (2008). - https://arxiv.org/abs/0707.0756 - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) - >>> c = nx.communicability_exp(G) - """ - import scipy as sp - - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - # communicability matrix - expA = sp.linalg.expm(A) - mapping = dict(zip(nodelist, range(len(nodelist)))) - c = {} - for u in G: - c[u] = {} - for v in G: - c[u][v] = float(expA[mapping[u], mapping[v]]) - return c diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/__init__.py deleted file mode 100644 index 4dfa848..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Functions for computing and measuring community structure. - -The ``community`` subpackage can be accessed by using :mod:`networkx.community`, then accessing the -functions as attributes of ``community``. For example:: - - >>> import networkx as nx - >>> G = nx.barbell_graph(5, 1) - >>> communities_generator = nx.community.girvan_newman(G) - >>> top_level_communities = next(communities_generator) - >>> next_level_communities = next(communities_generator) - >>> sorted(map(sorted, next_level_communities)) - [[0, 1, 2, 3, 4], [5], [6, 7, 8, 9, 10]] - -""" - -from networkx.algorithms.community.asyn_fluid import * -from networkx.algorithms.community.centrality import * -from networkx.algorithms.community.divisive import * -from networkx.algorithms.community.kclique import * -from networkx.algorithms.community.kernighan_lin import * -from networkx.algorithms.community.label_propagation import * -from networkx.algorithms.community.lukes import * -from networkx.algorithms.community.modularity_max import * -from networkx.algorithms.community.quality import * -from networkx.algorithms.community.community_utils import * -from networkx.algorithms.community.louvain import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/asyn_fluid.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/asyn_fluid.py deleted file mode 100644 index fea72c1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/asyn_fluid.py +++ /dev/null @@ -1,151 +0,0 @@ -"""Asynchronous Fluid Communities algorithm for community detection.""" - -from collections import Counter - -import networkx as nx -from networkx.algorithms.components import is_connected -from networkx.exception import NetworkXError -from networkx.utils import groups, not_implemented_for, py_random_state - -__all__ = ["asyn_fluidc"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(3) -@nx._dispatchable -def asyn_fluidc(G, k, max_iter=100, seed=None): - """Returns communities in `G` as detected by Fluid Communities algorithm. - - The asynchronous fluid communities algorithm is described in - [1]_. The algorithm is based on the simple idea of fluids interacting - in an environment, expanding and pushing each other. Its initialization is - random, so found communities may vary on different executions. - - The algorithm proceeds as follows. First each of the initial k communities - is initialized in a random vertex in the graph. Then the algorithm iterates - over all vertices in a random order, updating the community of each vertex - based on its own community and the communities of its neighbors. This - process is performed several times until convergence. - At all times, each community has a total density of 1, which is equally - distributed among the vertices it contains. If a vertex changes of - community, vertex densities of affected communities are adjusted - immediately. When a complete iteration over all vertices is done, such that - no vertex changes the community it belongs to, the algorithm has converged - and returns. - - This is the original version of the algorithm described in [1]_. - Unfortunately, it does not support weighted graphs yet. - - Parameters - ---------- - G : NetworkX graph - Graph must be simple and undirected. - - k : integer - The number of communities to be found. - - max_iter : integer - The number of maximum iterations allowed. By default 100. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - communities : iterable - Iterable of communities given as sets of nodes. - - Notes - ----- - k variable is not an optional argument. - - References - ---------- - .. [1] Parés F., Garcia-Gasulla D. et al. "Fluid Communities: A - Competitive and Highly Scalable Community Detection Algorithm". - [https://arxiv.org/pdf/1703.09307.pdf]. - """ - # Initial checks - if not isinstance(k, int): - raise NetworkXError("k must be an integer.") - if not k > 0: - raise NetworkXError("k must be greater than 0.") - if not is_connected(G): - raise NetworkXError("Fluid Communities require connected Graphs.") - if len(G) < k: - raise NetworkXError("k cannot be bigger than the number of nodes.") - # Initialization - max_density = 1.0 - vertices = list(G) - seed.shuffle(vertices) - communities = {n: i for i, n in enumerate(vertices[:k])} - density = {} - com_to_numvertices = {} - for vertex in communities: - com_to_numvertices[communities[vertex]] = 1 - density[communities[vertex]] = max_density - # Set up control variables and start iterating - iter_count = 0 - cont = True - while cont: - cont = False - iter_count += 1 - # Loop over all vertices in graph in a random order - vertices = list(G) - seed.shuffle(vertices) - for vertex in vertices: - # Updating rule - com_counter = Counter() - # Take into account self vertex community - try: - com_counter.update({communities[vertex]: density[communities[vertex]]}) - except KeyError: - pass - # Gather neighbor vertex communities - for v in G[vertex]: - try: - com_counter.update({communities[v]: density[communities[v]]}) - except KeyError: - continue - # Check which is the community with highest density - new_com = -1 - if len(com_counter.keys()) > 0: - max_freq = max(com_counter.values()) - best_communities = [ - com - for com, freq in com_counter.items() - if (max_freq - freq) < 0.0001 - ] - # If actual vertex com in best communities, it is preserved - try: - if communities[vertex] in best_communities: - new_com = communities[vertex] - except KeyError: - pass - # If vertex community changes... - if new_com == -1: - # Set flag of non-convergence - cont = True - # Randomly chose a new community from candidates - new_com = seed.choice(best_communities) - # Update previous community status - try: - com_to_numvertices[communities[vertex]] -= 1 - density[communities[vertex]] = ( - max_density / com_to_numvertices[communities[vertex]] - ) - except KeyError: - pass - # Update new community status - communities[vertex] = new_com - com_to_numvertices[communities[vertex]] += 1 - density[communities[vertex]] = ( - max_density / com_to_numvertices[communities[vertex]] - ) - # If maximum iterations reached --> output actual results - if iter_count > max_iter: - break - # Return results by grouping communities as list of vertices - return iter(groups(communities).values()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/centrality.py deleted file mode 100644 index 4328170..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/centrality.py +++ /dev/null @@ -1,171 +0,0 @@ -"""Functions for computing communities based on centrality notions.""" - -import networkx as nx - -__all__ = ["girvan_newman"] - - -@nx._dispatchable(preserve_edge_attrs="most_valuable_edge") -def girvan_newman(G, most_valuable_edge=None): - """Finds communities in a graph using the Girvan–Newman method. - - Parameters - ---------- - G : NetworkX graph - - most_valuable_edge : function - Function that takes a graph as input and outputs an edge. The - edge returned by this function will be recomputed and removed at - each iteration of the algorithm. - - If not specified, the edge with the highest - :func:`networkx.edge_betweenness_centrality` will be used. - - Returns - ------- - iterator - Iterator over tuples of sets of nodes in `G`. Each set of node - is a community, each tuple is a sequence of communities at a - particular level of the algorithm. - - Examples - -------- - To get the first pair of communities:: - - >>> G = nx.path_graph(10) - >>> comp = nx.community.girvan_newman(G) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]) - - To get only the first *k* tuples of communities, use - :func:`itertools.islice`:: - - >>> import itertools - >>> G = nx.path_graph(8) - >>> k = 2 - >>> comp = nx.community.girvan_newman(G) - >>> for communities in itertools.islice(comp, k): - ... print(tuple(sorted(c) for c in communities)) - ... - ([0, 1, 2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5, 6, 7]) - - To stop getting tuples of communities once the number of communities - is greater than *k*, use :func:`itertools.takewhile`:: - - >>> import itertools - >>> G = nx.path_graph(8) - >>> k = 4 - >>> comp = nx.community.girvan_newman(G) - >>> limited = itertools.takewhile(lambda c: len(c) <= k, comp) - >>> for communities in limited: - ... print(tuple(sorted(c) for c in communities)) - ... - ([0, 1, 2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5], [6, 7]) - - To just choose an edge to remove based on the weight:: - - >>> from operator import itemgetter - >>> G = nx.path_graph(10) - >>> edges = G.edges() - >>> nx.set_edge_attributes(G, {(u, v): v for u, v in edges}, "weight") - >>> def heaviest(G): - ... u, v, w = max(G.edges(data="weight"), key=itemgetter(2)) - ... return (u, v) - ... - >>> comp = nx.community.girvan_newman(G, most_valuable_edge=heaviest) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4, 5, 6, 7, 8], [9]) - - To utilize edge weights when choosing an edge with, for example, the - highest betweenness centrality:: - - >>> from networkx import edge_betweenness_centrality as betweenness - >>> def most_central_edge(G): - ... centrality = betweenness(G, weight="weight") - ... return max(centrality, key=centrality.get) - ... - >>> G = nx.path_graph(10) - >>> comp = nx.community.girvan_newman(G, most_valuable_edge=most_central_edge) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]) - - To specify a different ranking algorithm for edges, use the - `most_valuable_edge` keyword argument:: - - >>> from networkx import edge_betweenness_centrality - >>> from random import random - >>> def most_central_edge(G): - ... centrality = edge_betweenness_centrality(G) - ... max_cent = max(centrality.values()) - ... # Scale the centrality values so they are between 0 and 1, - ... # and add some random noise. - ... centrality = {e: c / max_cent for e, c in centrality.items()} - ... # Add some random noise. - ... centrality = {e: c + random() for e, c in centrality.items()} - ... return max(centrality, key=centrality.get) - ... - >>> G = nx.path_graph(10) - >>> comp = nx.community.girvan_newman(G, most_valuable_edge=most_central_edge) - - Notes - ----- - The Girvan–Newman algorithm detects communities by progressively - removing edges from the original graph. The algorithm removes the - "most valuable" edge, traditionally the edge with the highest - betweenness centrality, at each step. As the graph breaks down into - pieces, the tightly knit community structure is exposed and the - result can be depicted as a dendrogram. - - """ - # If the graph is already empty, simply return its connected - # components. - if G.number_of_edges() == 0: - yield tuple(nx.connected_components(G)) - return - # If no function is provided for computing the most valuable edge, - # use the edge betweenness centrality. - if most_valuable_edge is None: - - def most_valuable_edge(G): - """Returns the edge with the highest betweenness centrality - in the graph `G`. - - """ - # We have guaranteed that the graph is non-empty, so this - # dictionary will never be empty. - betweenness = nx.edge_betweenness_centrality(G) - return max(betweenness, key=betweenness.get) - - # The copy of G here must include the edge weight data. - g = G.copy().to_undirected() - # Self-loops must be removed because their removal has no effect on - # the connected components of the graph. - g.remove_edges_from(nx.selfloop_edges(g)) - while g.number_of_edges() > 0: - yield _without_most_central_edges(g, most_valuable_edge) - - -def _without_most_central_edges(G, most_valuable_edge): - """Returns the connected components of the graph that results from - repeatedly removing the most "valuable" edge in the graph. - - `G` must be a non-empty graph. This function modifies the graph `G` - in-place; that is, it removes edges on the graph `G`. - - `most_valuable_edge` is a function that takes the graph `G` as input - (or a subgraph with one or more edges of `G` removed) and returns an - edge. That edge will be removed and this process will be repeated - until the number of connected components in the graph increases. - - """ - original_num_components = nx.number_connected_components(G) - num_new_components = original_num_components - while num_new_components <= original_num_components: - edge = most_valuable_edge(G) - G.remove_edge(*edge) - new_components = tuple(nx.connected_components(G)) - num_new_components = len(new_components) - return new_components diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/community_utils.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/community_utils.py deleted file mode 100644 index ba73a6b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/community_utils.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Helper functions for community-finding algorithms.""" - -import networkx as nx - -__all__ = ["is_partition"] - - -@nx._dispatchable -def is_partition(G, communities): - """Returns *True* if `communities` is a partition of the nodes of `G`. - - A partition of a universe set is a family of pairwise disjoint sets - whose union is the entire universe set. - - Parameters - ---------- - G : NetworkX graph. - - communities : list or iterable of sets of nodes - If not a list, the iterable is converted internally to a list. - If it is an iterator it is exhausted. - - """ - # Alternate implementation: - # return all(sum(1 if v in c else 0 for c in communities) == 1 for v in G) - if not isinstance(communities, list): - communities = list(communities) - nodes = {n for c in communities for n in c if n in G} - - return len(G) == len(nodes) == sum(len(c) for c in communities) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/divisive.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/divisive.py deleted file mode 100644 index be3c7d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/divisive.py +++ /dev/null @@ -1,216 +0,0 @@ -import functools - -import networkx as nx - -__all__ = [ - "edge_betweenness_partition", - "edge_current_flow_betweenness_partition", -] - - -@nx._dispatchable(edge_attrs="weight") -def edge_betweenness_partition(G, number_of_sets, *, weight=None): - """Partition created by iteratively removing the highest edge betweenness edge. - - This algorithm works by calculating the edge betweenness for all - edges and removing the edge with the highest value. It is then - determined whether the graph has been broken into at least - `number_of_sets` connected components. - If not the process is repeated. - - Parameters - ---------- - G : NetworkX Graph, DiGraph or MultiGraph - Graph to be partitioned - - number_of_sets : int - Number of sets in the desired partition of the graph - - weight : key, optional, default=None - The key to use if using weights for edge betweenness calculation - - Returns - ------- - C : list of sets - Partition of the nodes of G - - Raises - ------ - NetworkXError - If number_of_sets is <= 0 or if number_of_sets > len(G) - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> part = nx.community.edge_betweenness_partition(G, 2) - >>> {0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21} in part - True - >>> { - ... 2, - ... 8, - ... 9, - ... 14, - ... 15, - ... 18, - ... 20, - ... 22, - ... 23, - ... 24, - ... 25, - ... 26, - ... 27, - ... 28, - ... 29, - ... 30, - ... 31, - ... 32, - ... 33, - ... } in part - True - - See Also - -------- - edge_current_flow_betweenness_partition - - Notes - ----- - This algorithm is fairly slow, as both the calculation of connected - components and edge betweenness relies on all pairs shortest - path algorithms. They could potentially be combined to cut down - on overall computation time. - - References - ---------- - .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174 - http://arxiv.org/abs/0906.0612 - """ - if number_of_sets <= 0: - raise nx.NetworkXError("number_of_sets must be >0") - if number_of_sets == 1: - return [set(G)] - if number_of_sets == len(G): - return [{n} for n in G] - if number_of_sets > len(G): - raise nx.NetworkXError("number_of_sets must be <= len(G)") - - H = G.copy() - partition = list(nx.connected_components(H)) - while len(partition) < number_of_sets: - ranking = nx.edge_betweenness_centrality(H, weight=weight) - edge = max(ranking, key=ranking.get) - H.remove_edge(*edge) - partition = list(nx.connected_components(H)) - return partition - - -@nx._dispatchable(edge_attrs="weight") -def edge_current_flow_betweenness_partition(G, number_of_sets, *, weight=None): - """Partition created by removing the highest edge current flow betweenness edge. - - This algorithm works by calculating the edge current flow - betweenness for all edges and removing the edge with the - highest value. It is then determined whether the graph has - been broken into at least `number_of_sets` connected - components. If not the process is repeated. - - Parameters - ---------- - G : NetworkX Graph, DiGraph or MultiGraph - Graph to be partitioned - - number_of_sets : int - Number of sets in the desired partition of the graph - - weight : key, optional (default=None) - The edge attribute key to use as weights for - edge current flow betweenness calculations - - Returns - ------- - C : list of sets - Partition of G - - Raises - ------ - NetworkXError - If number_of_sets is <= 0 or number_of_sets > len(G) - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> part = nx.community.edge_current_flow_betweenness_partition(G, 2) - >>> {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 16, 17, 19, 21} in part - True - >>> {8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33} in part - True - - - See Also - -------- - edge_betweenness_partition - - Notes - ----- - This algorithm is extremely slow, as the recalculation of the edge - current flow betweenness is extremely slow. - - References - ---------- - .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174 - http://arxiv.org/abs/0906.0612 - """ - if number_of_sets <= 0: - raise nx.NetworkXError("number_of_sets must be >0") - elif number_of_sets == 1: - return [set(G)] - elif number_of_sets == len(G): - return [{n} for n in G] - elif number_of_sets > len(G): - raise nx.NetworkXError("number_of_sets must be <= len(G)") - - rank = functools.partial( - nx.edge_current_flow_betweenness_centrality, normalized=False, weight=weight - ) - - # current flow requires a connected network so we track the components explicitly - H = G.copy() - partition = list(nx.connected_components(H)) - if len(partition) > 1: - Hcc_subgraphs = [H.subgraph(cc).copy() for cc in partition] - else: - Hcc_subgraphs = [H] - - ranking = {} - for Hcc in Hcc_subgraphs: - ranking.update(rank(Hcc)) - - while len(partition) < number_of_sets: - edge = max(ranking, key=ranking.get) - for cc, Hcc in zip(partition, Hcc_subgraphs): - if edge[0] in cc: - Hcc.remove_edge(*edge) - del ranking[edge] - splitcc_list = list(nx.connected_components(Hcc)) - if len(splitcc_list) > 1: - # there are 2 connected components. split off smaller one - cc_new = min(splitcc_list, key=len) - Hcc_new = Hcc.subgraph(cc_new).copy() - # update edge rankings for Hcc_new - newranks = rank(Hcc_new) - for e, r in newranks.items(): - ranking[e if e in ranking else e[::-1]] = r - # append new cc and Hcc to their lists. - partition.append(cc_new) - Hcc_subgraphs.append(Hcc_new) - - # leave existing cc and Hcc in their lists, but shrink them - Hcc.remove_nodes_from(cc_new) - cc.difference_update(cc_new) - # update edge rankings for Hcc whether it was split or not - newranks = rank(Hcc) - for e, r in newranks.items(): - ranking[e if e in ranking else e[::-1]] = r - break - return partition diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kclique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kclique.py deleted file mode 100644 index c724910..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kclique.py +++ /dev/null @@ -1,79 +0,0 @@ -from collections import defaultdict - -import networkx as nx - -__all__ = ["k_clique_communities"] - - -@nx._dispatchable -def k_clique_communities(G, k, cliques=None): - """Find k-clique communities in graph using the percolation method. - - A k-clique community is the union of all cliques of size k that - can be reached through adjacent (sharing k-1 nodes) k-cliques. - - Parameters - ---------- - G : NetworkX graph - - k : int - Size of smallest clique - - cliques: list or generator - Precomputed cliques (use networkx.find_cliques(G)) - - Returns - ------- - Yields sets of nodes, one for each k-clique community. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> K5 = nx.convert_node_labels_to_integers(G, first_label=2) - >>> G.add_edges_from(K5.edges()) - >>> c = list(nx.community.k_clique_communities(G, 4)) - >>> sorted(list(c[0])) - [0, 1, 2, 3, 4, 5, 6] - >>> list(nx.community.k_clique_communities(G, 6)) - [] - - References - ---------- - .. [1] Gergely Palla, Imre Derényi, Illés Farkas1, and Tamás Vicsek, - Uncovering the overlapping community structure of complex networks - in nature and society Nature 435, 814-818, 2005, - doi:10.1038/nature03607 - """ - if k < 2: - raise nx.NetworkXError(f"k={k}, k must be greater than 1.") - if cliques is None: - cliques = nx.find_cliques(G) - cliques = [frozenset(c) for c in cliques if len(c) >= k] - - # First index which nodes are in which cliques - membership_dict = defaultdict(list) - for clique in cliques: - for node in clique: - membership_dict[node].append(clique) - - # For each clique, see which adjacent cliques percolate - perc_graph = nx.Graph() - perc_graph.add_nodes_from(cliques) - for clique in cliques: - for adj_clique in _get_adjacent_cliques(clique, membership_dict): - if len(clique.intersection(adj_clique)) >= (k - 1): - perc_graph.add_edge(clique, adj_clique) - - # Connected components of clique graph with perc edges - # are the percolated cliques - for component in nx.connected_components(perc_graph): - yield (frozenset.union(*component)) - - -def _get_adjacent_cliques(clique, membership_dict): - adjacent_cliques = set() - for n in clique: - for adj_clique in membership_dict[n]: - if clique != adj_clique: - adjacent_cliques.add(adj_clique) - return adjacent_cliques diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kernighan_lin.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kernighan_lin.py deleted file mode 100644 index f6397d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/kernighan_lin.py +++ /dev/null @@ -1,139 +0,0 @@ -"""Functions for computing the Kernighan–Lin bipartition algorithm.""" - -from itertools import count - -import networkx as nx -from networkx.algorithms.community.community_utils import is_partition -from networkx.utils import BinaryHeap, not_implemented_for, py_random_state - -__all__ = ["kernighan_lin_bisection"] - - -def _kernighan_lin_sweep(edges, side): - """ - This is a modified form of Kernighan-Lin, which moves single nodes at a - time, alternating between sides to keep the bisection balanced. We keep - two min-heaps of swap costs to make optimal-next-move selection fast. - """ - costs0, costs1 = costs = BinaryHeap(), BinaryHeap() - for u, side_u, edges_u in zip(count(), side, edges): - cost_u = sum(w if side[v] else -w for v, w in edges_u) - costs[side_u].insert(u, cost_u if side_u else -cost_u) - - def _update_costs(costs_x, x): - for y, w in edges[x]: - costs_y = costs[side[y]] - cost_y = costs_y.get(y) - if cost_y is not None: - cost_y += 2 * (-w if costs_x is costs_y else w) - costs_y.insert(y, cost_y, True) - - i = 0 - totcost = 0 - while costs0 and costs1: - u, cost_u = costs0.pop() - _update_costs(costs0, u) - v, cost_v = costs1.pop() - _update_costs(costs1, v) - totcost += cost_u + cost_v - i += 1 - yield totcost, i, (u, v) - - -@not_implemented_for("directed") -@py_random_state(4) -@nx._dispatchable(edge_attrs="weight") -def kernighan_lin_bisection(G, partition=None, max_iter=10, weight="weight", seed=None): - """Partition a graph into two blocks using the Kernighan–Lin - algorithm. - - This algorithm partitions a network into two sets by iteratively - swapping pairs of nodes to reduce the edge cut between the two sets. The - pairs are chosen according to a modified form of Kernighan-Lin [1]_, which - moves node individually, alternating between sides to keep the bisection - balanced. - - Parameters - ---------- - G : NetworkX graph - Graph must be undirected. - - partition : tuple - Pair of iterables containing an initial partition. If not - specified, a random balanced partition is used. - - max_iter : int - Maximum number of times to attempt swaps to find an - improvement before giving up. - - weight : key - Edge data key to use as weight. If None, the weights are all - set to one. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Only used if partition is None - - Returns - ------- - partition : tuple - A pair of sets of nodes representing the bipartition. - - Raises - ------ - NetworkXError - If partition is not a valid partition of the nodes of the graph. - - References - ---------- - .. [1] Kernighan, B. W.; Lin, Shen (1970). - "An efficient heuristic procedure for partitioning graphs." - *Bell Systems Technical Journal* 49: 291--307. - Oxford University Press 2011. - - """ - n = len(G) - labels = list(G) - seed.shuffle(labels) - index = {v: i for i, v in enumerate(labels)} - - if partition is None: - side = [0] * (n // 2) + [1] * ((n + 1) // 2) - else: - try: - A, B = partition - except (TypeError, ValueError) as err: - raise nx.NetworkXError("partition must be two sets") from err - if not is_partition(G, (A, B)): - raise nx.NetworkXError("partition invalid") - side = [0] * n - for a in A: - side[index[a]] = 1 - - if G.is_multigraph(): - edges = [ - [ - (index[u], sum(e.get(weight, 1) for e in d.values())) - for u, d in G[v].items() - ] - for v in labels - ] - else: - edges = [ - [(index[u], e.get(weight, 1)) for u, e in G[v].items()] for v in labels - ] - - for i in range(max_iter): - costs = list(_kernighan_lin_sweep(edges, side)) - min_cost, min_i, _ = min(costs) - if min_cost >= 0: - break - - for _, _, (u, v) in costs[:min_i]: - side[u] = 1 - side[v] = 0 - - A = {u for u, s in zip(labels, side) if s == 0} - B = {u for u, s in zip(labels, side) if s == 1} - return A, B diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/label_propagation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/label_propagation.py deleted file mode 100644 index 7488028..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/label_propagation.py +++ /dev/null @@ -1,338 +0,0 @@ -""" -Label propagation community detection algorithms. -""" - -from collections import Counter, defaultdict, deque - -import networkx as nx -from networkx.utils import groups, not_implemented_for, py_random_state - -__all__ = [ - "label_propagation_communities", - "asyn_lpa_communities", - "fast_label_propagation_communities", -] - - -@py_random_state("seed") -@nx._dispatchable(edge_attrs="weight") -def fast_label_propagation_communities(G, *, weight=None, seed=None): - """Returns communities in `G` as detected by fast label propagation. - - The fast label propagation algorithm is described in [1]_. The algorithm is - probabilistic and the found communities may vary in different executions. - - The algorithm operates as follows. First, the community label of each node is - set to a unique label. The algorithm then repeatedly updates the labels of - the nodes to the most frequent label in their neighborhood. In case of ties, - a random label is chosen from the most frequent labels. - - The algorithm maintains a queue of nodes that still need to be processed. - Initially, all nodes are added to the queue in a random order. Then the nodes - are removed from the queue one by one and processed. If a node updates its label, - all its neighbors that have a different label are added to the queue (if not - already in the queue). The algorithm stops when the queue is empty. - - Parameters - ---------- - G : Graph, DiGraph, MultiGraph, or MultiDiGraph - Any NetworkX graph. - - weight : string, or None (default) - The edge attribute representing a non-negative weight of an edge. If None, - each edge is assumed to have weight one. The weight of an edge is used in - determining the frequency with which a label appears among the neighbors of - a node (edge with weight `w` is equivalent to `w` unweighted edges). - - seed : integer, random_state, or None (default) - Indicator of random number generation state. See :ref:`Randomness`. - - Returns - ------- - communities : iterable - Iterable of communities given as sets of nodes. - - Notes - ----- - Edge directions are ignored for directed graphs. - Edge weights must be non-negative numbers. - - References - ---------- - .. [1] Vincent A. Traag & Lovro Šubelj. "Large network community detection by - fast label propagation." Scientific Reports 13 (2023): 2701. - https://doi.org/10.1038/s41598-023-29610-z - """ - - # Queue of nodes to be processed. - nodes_queue = deque(G) - seed.shuffle(nodes_queue) - - # Set of nodes in the queue. - nodes_set = set(G) - - # Assign unique label to each node. - comms = {node: i for i, node in enumerate(G)} - - while nodes_queue: - # Remove next node from the queue to process. - node = nodes_queue.popleft() - nodes_set.remove(node) - - # Isolated nodes retain their initial label. - if G.degree(node) > 0: - # Compute frequency of labels in node's neighborhood. - label_freqs = _fast_label_count(G, comms, node, weight) - max_freq = max(label_freqs.values()) - - # Always sample new label from most frequent labels. - comm = seed.choice( - [comm for comm in label_freqs if label_freqs[comm] == max_freq] - ) - - if comms[node] != comm: - comms[node] = comm - - # Add neighbors that have different label to the queue. - for nbr in nx.all_neighbors(G, node): - if comms[nbr] != comm and nbr not in nodes_set: - nodes_queue.append(nbr) - nodes_set.add(nbr) - - yield from groups(comms).values() - - -def _fast_label_count(G, comms, node, weight=None): - """Computes the frequency of labels in the neighborhood of a node. - - Returns a dictionary keyed by label to the frequency of that label. - """ - - if weight is None: - # Unweighted (un)directed simple graph. - if not G.is_multigraph(): - label_freqs = Counter(map(comms.get, nx.all_neighbors(G, node))) - - # Unweighted (un)directed multigraph. - else: - label_freqs = defaultdict(int) - for nbr in G[node]: - label_freqs[comms[nbr]] += len(G[node][nbr]) - - if G.is_directed(): - for nbr in G.pred[node]: - label_freqs[comms[nbr]] += len(G.pred[node][nbr]) - - else: - # Weighted undirected simple/multigraph. - label_freqs = defaultdict(float) - for _, nbr, w in G.edges(node, data=weight, default=1): - label_freqs[comms[nbr]] += w - - # Weighted directed simple/multigraph. - if G.is_directed(): - for nbr, _, w in G.in_edges(node, data=weight, default=1): - label_freqs[comms[nbr]] += w - - return label_freqs - - -@py_random_state(2) -@nx._dispatchable(edge_attrs="weight") -def asyn_lpa_communities(G, weight=None, seed=None): - """Returns communities in `G` as detected by asynchronous label - propagation. - - The asynchronous label propagation algorithm is described in - [1]_. The algorithm is probabilistic and the found communities may - vary on different executions. - - The algorithm proceeds as follows. After initializing each node with - a unique label, the algorithm repeatedly sets the label of a node to - be the label that appears most frequently among that nodes - neighbors. The algorithm halts when each node has the label that - appears most frequently among its neighbors. The algorithm is - asynchronous because each node is updated without waiting for - updates on the remaining nodes. - - This generalized version of the algorithm in [1]_ accepts edge - weights. - - Parameters - ---------- - G : Graph - - weight : string - The edge attribute representing the weight of an edge. - If None, each edge is assumed to have weight one. In this - algorithm, the weight of an edge is used in determining the - frequency with which a label appears among the neighbors of a - node: a higher weight means the label appears more often. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - communities : iterable - Iterable of communities given as sets of nodes. - - Notes - ----- - Edge weight attributes must be numerical. - - References - ---------- - .. [1] Raghavan, Usha Nandini, Réka Albert, and Soundar Kumara. "Near - linear time algorithm to detect community structures in large-scale - networks." Physical Review E 76.3 (2007): 036106. - """ - - labels = {n: i for i, n in enumerate(G)} - cont = True - - while cont: - cont = False - nodes = list(G) - seed.shuffle(nodes) - - for node in nodes: - if not G[node]: - continue - - # Get label frequencies among adjacent nodes. - # Depending on the order they are processed in, - # some nodes will be in iteration t and others in t-1, - # making the algorithm asynchronous. - if weight is None: - # initialising a Counter from an iterator of labels is - # faster for getting unweighted label frequencies - label_freq = Counter(map(labels.get, G[node])) - else: - # updating a defaultdict is substantially faster - # for getting weighted label frequencies - label_freq = defaultdict(float) - for _, v, wt in G.edges(node, data=weight, default=1): - label_freq[labels[v]] += wt - - # Get the labels that appear with maximum frequency. - max_freq = max(label_freq.values()) - best_labels = [ - label for label, freq in label_freq.items() if freq == max_freq - ] - - # If the node does not have one of the maximum frequency labels, - # randomly choose one of them and update the node's label. - # Continue the iteration as long as at least one node - # doesn't have a maximum frequency label. - if labels[node] not in best_labels: - labels[node] = seed.choice(best_labels) - cont = True - - yield from groups(labels).values() - - -@not_implemented_for("directed") -@nx._dispatchable -def label_propagation_communities(G): - """Generates community sets determined by label propagation - - Finds communities in `G` using a semi-synchronous label propagation - method [1]_. This method combines the advantages of both the synchronous - and asynchronous models. Not implemented for directed graphs. - - Parameters - ---------- - G : graph - An undirected NetworkX graph. - - Returns - ------- - communities : iterable - A dict_values object that contains a set of nodes for each community. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed - - References - ---------- - .. [1] Cordasco, G., & Gargano, L. (2010, December). Community detection - via semi-synchronous label propagation algorithms. In Business - Applications of Social Network Analysis (BASNA), 2010 IEEE International - Workshop on (pp. 1-8). IEEE. - """ - coloring = _color_network(G) - # Create a unique label for each node in the graph - labeling = {v: k for k, v in enumerate(G)} - while not _labeling_complete(labeling, G): - # Update the labels of every node with the same color. - for color, nodes in coloring.items(): - for n in nodes: - _update_label(n, labeling, G) - - clusters = defaultdict(set) - for node, label in labeling.items(): - clusters[label].add(node) - return clusters.values() - - -def _color_network(G): - """Colors the network so that neighboring nodes all have distinct colors. - - Returns a dict keyed by color to a set of nodes with that color. - """ - coloring = {} # color => set(node) - colors = nx.coloring.greedy_color(G) - for node, color in colors.items(): - if color in coloring: - coloring[color].add(node) - else: - coloring[color] = {node} - return coloring - - -def _labeling_complete(labeling, G): - """Determines whether or not LPA is done. - - Label propagation is complete when all nodes have a label that is - in the set of highest frequency labels amongst its neighbors. - - Nodes with no neighbors are considered complete. - """ - return all( - labeling[v] in _most_frequent_labels(v, labeling, G) for v in G if len(G[v]) > 0 - ) - - -def _most_frequent_labels(node, labeling, G): - """Returns a set of all labels with maximum frequency in `labeling`. - - Input `labeling` should be a dict keyed by node to labels. - """ - if not G[node]: - # Nodes with no neighbors are themselves a community and are labeled - # accordingly, hence the immediate if statement. - return {labeling[node]} - - # Compute the frequencies of all neighbors of node - freqs = Counter(labeling[q] for q in G[node]) - max_freq = max(freqs.values()) - return {label for label, freq in freqs.items() if freq == max_freq} - - -def _update_label(node, labeling, G): - """Updates the label of a node using the Prec-Max tie breaking algorithm - - The algorithm is explained in: 'Community Detection via Semi-Synchronous - Label Propagation Algorithms' Cordasco and Gargano, 2011 - """ - high_labels = _most_frequent_labels(node, labeling, G) - if len(high_labels) == 1: - labeling[node] = high_labels.pop() - elif len(high_labels) > 1: - # Prec-Max - if labeling[node] not in high_labels: - labeling[node] = max(high_labels) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/louvain.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/louvain.py deleted file mode 100644 index 959c93a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/louvain.py +++ /dev/null @@ -1,382 +0,0 @@ -"""Function for detecting communities based on Louvain Community Detection -Algorithm""" - -import itertools -from collections import defaultdict, deque - -import networkx as nx -from networkx.algorithms.community import modularity -from networkx.utils import py_random_state - -__all__ = ["louvain_communities", "louvain_partitions"] - - -@py_random_state("seed") -@nx._dispatchable(edge_attrs="weight") -def louvain_communities( - G, weight="weight", resolution=1, threshold=0.0000001, max_level=None, seed=None -): - r"""Find the best partition of a graph using the Louvain Community Detection - Algorithm. - - Louvain Community Detection Algorithm is a simple method to extract the community - structure of a network. This is a heuristic method based on modularity optimization. [1]_ - - The algorithm works in 2 steps. On the first step it assigns every node to be - in its own community and then for each node it tries to find the maximum positive - modularity gain by moving each node to all of its neighbor communities. If no positive - gain is achieved the node remains in its original community. - - The modularity gain obtained by moving an isolated node $i$ into a community $C$ can - easily be calculated by the following formula (combining [1]_ [2]_ and some algebra): - - .. math:: - \Delta Q = \frac{k_{i,in}}{2m} - \gamma\frac{ \Sigma_{tot} \cdot k_i}{2m^2} - - where $m$ is the size of the graph, $k_{i,in}$ is the sum of the weights of the links - from $i$ to nodes in $C$, $k_i$ is the sum of the weights of the links incident to node $i$, - $\Sigma_{tot}$ is the sum of the weights of the links incident to nodes in $C$ and $\gamma$ - is the resolution parameter. - - For the directed case the modularity gain can be computed using this formula according to [3]_ - - .. math:: - \Delta Q = \frac{k_{i,in}}{m} - - \gamma\frac{k_i^{out} \cdot\Sigma_{tot}^{in} + k_i^{in} \cdot \Sigma_{tot}^{out}}{m^2} - - where $k_i^{out}$, $k_i^{in}$ are the outer and inner weighted degrees of node $i$ and - $\Sigma_{tot}^{in}$, $\Sigma_{tot}^{out}$ are the sum of in-going and out-going links incident - to nodes in $C$. - - The first phase continues until no individual move can improve the modularity. - - The second phase consists in building a new network whose nodes are now the communities - found in the first phase. To do so, the weights of the links between the new nodes are given by - the sum of the weight of the links between nodes in the corresponding two communities. Once this - phase is complete it is possible to reapply the first phase creating bigger communities with - increased modularity. - - The above two phases are executed until no modularity gain is achieved (or is less than - the `threshold`, or until `max_levels` is reached). - - Be careful with self-loops in the input graph. These are treated as - previously reduced communities -- as if the process had been started - in the middle of the algorithm. Large self-loop edge weights thus - represent strong communities and in practice may be hard to add - other nodes to. If your input graph edge weights for self-loops - do not represent already reduced communities you may want to remove - the self-loops before inputting that graph. - - Parameters - ---------- - G : NetworkX graph - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - resolution : float, optional (default=1) - If resolution is less than 1, the algorithm favors larger communities. - Greater than 1 favors smaller communities - threshold : float, optional (default=0.0000001) - Modularity gain threshold for each level. If the gain of modularity - between 2 levels of the algorithm is less than the given threshold - then the algorithm stops and returns the resulting communities. - max_level : int or None, optional (default=None) - The maximum number of levels (steps of the algorithm) to compute. - Must be a positive integer or None. If None, then there is no max - level and the threshold parameter determines the stopping condition. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - list - A list of sets (partition of `G`). Each set represents one community and contains - all the nodes that constitute it. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.petersen_graph() - >>> nx.community.louvain_communities(G, seed=123) - [{0, 4, 5, 7, 9}, {1, 2, 3, 6, 8}] - - Notes - ----- - The order in which the nodes are considered can affect the final output. In the algorithm - the ordering happens using a random shuffle. - - References - ---------- - .. [1] Blondel, V.D. et al. Fast unfolding of communities in - large networks. J. Stat. Mech 10008, 1-12(2008). https://doi.org/10.1088/1742-5468/2008/10/P10008 - .. [2] Traag, V.A., Waltman, L. & van Eck, N.J. From Louvain to Leiden: guaranteeing - well-connected communities. Sci Rep 9, 5233 (2019). https://doi.org/10.1038/s41598-019-41695-z - .. [3] Nicolas Dugué, Anthony Perez. Directed Louvain : maximizing modularity in directed networks. - [Research Report] Université d’Orléans. 2015. hal-01231784. https://hal.archives-ouvertes.fr/hal-01231784 - - See Also - -------- - louvain_partitions - """ - - partitions = louvain_partitions(G, weight, resolution, threshold, seed) - if max_level is not None: - if max_level <= 0: - raise ValueError("max_level argument must be a positive integer or None") - partitions = itertools.islice(partitions, max_level) - final_partition = deque(partitions, maxlen=1) - return final_partition.pop() - - -@py_random_state("seed") -@nx._dispatchable(edge_attrs="weight") -def louvain_partitions( - G, weight="weight", resolution=1, threshold=0.0000001, seed=None -): - """Yields partitions for each level of the Louvain Community Detection Algorithm - - Louvain Community Detection Algorithm is a simple method to extract the community - structure of a network. This is a heuristic method based on modularity optimization. [1]_ - - The partitions at each level (step of the algorithm) form a dendrogram of communities. - A dendrogram is a diagram representing a tree and each level represents - a partition of the G graph. The top level contains the smallest communities - and as you traverse to the bottom of the tree the communities get bigger - and the overall modularity increases making the partition better. - - Each level is generated by executing the two phases of the Louvain Community - Detection Algorithm. - - Be careful with self-loops in the input graph. These are treated as - previously reduced communities -- as if the process had been started - in the middle of the algorithm. Large self-loop edge weights thus - represent strong communities and in practice may be hard to add - other nodes to. If your input graph edge weights for self-loops - do not represent already reduced communities you may want to remove - the self-loops before inputting that graph. - - Parameters - ---------- - G : NetworkX graph - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - resolution : float, optional (default=1) - If resolution is less than 1, the algorithm favors larger communities. - Greater than 1 favors smaller communities - threshold : float, optional (default=0.0000001) - Modularity gain threshold for each level. If the gain of modularity - between 2 levels of the algorithm is less than the given threshold - then the algorithm stops and returns the resulting communities. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Yields - ------ - list - A list of sets (partition of `G`). Each set represents one community and contains - all the nodes that constitute it. - - References - ---------- - .. [1] Blondel, V.D. et al. Fast unfolding of communities in - large networks. J. Stat. Mech 10008, 1-12(2008) - - See Also - -------- - louvain_communities - """ - - partition = [{u} for u in G.nodes()] - if nx.is_empty(G): - yield partition - return - mod = modularity(G, partition, resolution=resolution, weight=weight) - is_directed = G.is_directed() - if G.is_multigraph(): - graph = _convert_multigraph(G, weight, is_directed) - else: - graph = G.__class__() - graph.add_nodes_from(G) - graph.add_weighted_edges_from(G.edges(data=weight, default=1)) - - m = graph.size(weight="weight") - partition, inner_partition, improvement = _one_level( - graph, m, partition, resolution, is_directed, seed - ) - improvement = True - while improvement: - # gh-5901 protect the sets in the yielded list from further manipulation here - yield [s.copy() for s in partition] - new_mod = modularity( - graph, inner_partition, resolution=resolution, weight="weight" - ) - if new_mod - mod <= threshold: - return - mod = new_mod - graph = _gen_graph(graph, inner_partition) - partition, inner_partition, improvement = _one_level( - graph, m, partition, resolution, is_directed, seed - ) - - -def _one_level(G, m, partition, resolution=1, is_directed=False, seed=None): - """Calculate one level of the Louvain partitions tree - - Parameters - ---------- - G : NetworkX Graph/DiGraph - The graph from which to detect communities - m : number - The size of the graph `G`. - partition : list of sets of nodes - A valid partition of the graph `G` - resolution : positive number - The resolution parameter for computing the modularity of a partition - is_directed : bool - True if `G` is a directed graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - """ - node2com = {u: i for i, u in enumerate(G.nodes())} - inner_partition = [{u} for u in G.nodes()] - if is_directed: - in_degrees = dict(G.in_degree(weight="weight")) - out_degrees = dict(G.out_degree(weight="weight")) - Stot_in = list(in_degrees.values()) - Stot_out = list(out_degrees.values()) - # Calculate weights for both in and out neighbors without considering self-loops - nbrs = {} - for u in G: - nbrs[u] = defaultdict(float) - for _, n, wt in G.out_edges(u, data="weight"): - if u != n: - nbrs[u][n] += wt - for n, _, wt in G.in_edges(u, data="weight"): - if u != n: - nbrs[u][n] += wt - else: - degrees = dict(G.degree(weight="weight")) - Stot = list(degrees.values()) - nbrs = {u: {v: data["weight"] for v, data in G[u].items() if v != u} for u in G} - rand_nodes = list(G.nodes) - seed.shuffle(rand_nodes) - nb_moves = 1 - improvement = False - while nb_moves > 0: - nb_moves = 0 - for u in rand_nodes: - best_mod = 0 - best_com = node2com[u] - weights2com = _neighbor_weights(nbrs[u], node2com) - if is_directed: - in_degree = in_degrees[u] - out_degree = out_degrees[u] - Stot_in[best_com] -= in_degree - Stot_out[best_com] -= out_degree - remove_cost = ( - -weights2com[best_com] / m - + resolution - * (out_degree * Stot_in[best_com] + in_degree * Stot_out[best_com]) - / m**2 - ) - else: - degree = degrees[u] - Stot[best_com] -= degree - remove_cost = -weights2com[best_com] / m + resolution * ( - Stot[best_com] * degree - ) / (2 * m**2) - for nbr_com, wt in weights2com.items(): - if is_directed: - gain = ( - remove_cost - + wt / m - - resolution - * ( - out_degree * Stot_in[nbr_com] - + in_degree * Stot_out[nbr_com] - ) - / m**2 - ) - else: - gain = ( - remove_cost - + wt / m - - resolution * (Stot[nbr_com] * degree) / (2 * m**2) - ) - if gain > best_mod: - best_mod = gain - best_com = nbr_com - if is_directed: - Stot_in[best_com] += in_degree - Stot_out[best_com] += out_degree - else: - Stot[best_com] += degree - if best_com != node2com[u]: - com = G.nodes[u].get("nodes", {u}) - partition[node2com[u]].difference_update(com) - inner_partition[node2com[u]].remove(u) - partition[best_com].update(com) - inner_partition[best_com].add(u) - improvement = True - nb_moves += 1 - node2com[u] = best_com - partition = list(filter(len, partition)) - inner_partition = list(filter(len, inner_partition)) - return partition, inner_partition, improvement - - -def _neighbor_weights(nbrs, node2com): - """Calculate weights between node and its neighbor communities. - - Parameters - ---------- - nbrs : dictionary - Dictionary with nodes' neighbors as keys and their edge weight as value. - node2com : dictionary - Dictionary with all graph's nodes as keys and their community index as value. - - """ - weights = defaultdict(float) - for nbr, wt in nbrs.items(): - weights[node2com[nbr]] += wt - return weights - - -def _gen_graph(G, partition): - """Generate a new graph based on the partitions of a given graph""" - H = G.__class__() - node2com = {} - for i, part in enumerate(partition): - nodes = set() - for node in part: - node2com[node] = i - nodes.update(G.nodes[node].get("nodes", {node})) - H.add_node(i, nodes=nodes) - - for node1, node2, wt in G.edges(data=True): - wt = wt["weight"] - com1 = node2com[node1] - com2 = node2com[node2] - temp = H.get_edge_data(com1, com2, {"weight": 0})["weight"] - H.add_edge(com1, com2, weight=wt + temp) - return H - - -def _convert_multigraph(G, weight, is_directed): - """Convert a Multigraph to normal Graph""" - if is_directed: - H = nx.DiGraph() - else: - H = nx.Graph() - H.add_nodes_from(G) - for u, v, wt in G.edges(data=weight, default=1): - if H.has_edge(u, v): - H[u][v]["weight"] += wt - else: - H.add_edge(u, v, weight=wt) - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/lukes.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/lukes.py deleted file mode 100644 index 08dd7cd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/lukes.py +++ /dev/null @@ -1,227 +0,0 @@ -"""Lukes Algorithm for exact optimal weighted tree partitioning.""" - -from copy import deepcopy -from functools import lru_cache -from random import choice - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["lukes_partitioning"] - -D_EDGE_W = "weight" -D_EDGE_VALUE = 1.0 -D_NODE_W = "weight" -D_NODE_VALUE = 1 -PKEY = "partitions" -CLUSTER_EVAL_CACHE_SIZE = 2048 - - -def _split_n_from(n, min_size_of_first_part): - # splits j in two parts of which the first is at least - # the second argument - assert n >= min_size_of_first_part - for p1 in range(min_size_of_first_part, n + 1): - yield p1, n - p1 - - -@nx._dispatchable(node_attrs="node_weight", edge_attrs="edge_weight") -def lukes_partitioning(G, max_size, node_weight=None, edge_weight=None): - """Optimal partitioning of a weighted tree using the Lukes algorithm. - - This algorithm partitions a connected, acyclic graph featuring integer - node weights and float edge weights. The resulting clusters are such - that the total weight of the nodes in each cluster does not exceed - max_size and that the weight of the edges that are cut by the partition - is minimum. The algorithm is based on [1]_. - - Parameters - ---------- - G : NetworkX graph - - max_size : int - Maximum weight a partition can have in terms of sum of - node_weight for all nodes in the partition - - edge_weight : key - Edge data key to use as weight. If None, the weights are all - set to one. - - node_weight : key - Node data key to use as weight. If None, the weights are all - set to one. The data must be int. - - Returns - ------- - partition : list - A list of sets of nodes representing the clusters of the - partition. - - Raises - ------ - NotATree - If G is not a tree. - TypeError - If any of the values of node_weight is not int. - - References - ---------- - .. [1] Lukes, J. A. (1974). - "Efficient Algorithm for the Partitioning of Trees." - IBM Journal of Research and Development, 18(3), 217–224. - - """ - # First sanity check and tree preparation - if not nx.is_tree(G): - raise nx.NotATree("lukes_partitioning works only on trees") - else: - if nx.is_directed(G): - root = [n for n, d in G.in_degree() if d == 0] - assert len(root) == 1 - root = root[0] - t_G = deepcopy(G) - else: - root = choice(list(G.nodes)) - # this has the desirable side effect of not inheriting attributes - t_G = nx.dfs_tree(G, root) - - # Since we do not want to screw up the original graph, - # if we have a blank attribute, we make a deepcopy - if edge_weight is None or node_weight is None: - safe_G = deepcopy(G) - if edge_weight is None: - nx.set_edge_attributes(safe_G, D_EDGE_VALUE, D_EDGE_W) - edge_weight = D_EDGE_W - if node_weight is None: - nx.set_node_attributes(safe_G, D_NODE_VALUE, D_NODE_W) - node_weight = D_NODE_W - else: - safe_G = G - - # Second sanity check - # The values of node_weight MUST BE int. - # I cannot see any room for duck typing without incurring serious - # danger of subtle bugs. - all_n_attr = nx.get_node_attributes(safe_G, node_weight).values() - for x in all_n_attr: - if not isinstance(x, int): - raise TypeError( - "lukes_partitioning needs integer " - f"values for node_weight ({node_weight})" - ) - - # SUBROUTINES ----------------------- - # these functions are defined here for two reasons: - # - brevity: we can leverage global "safe_G" - # - caching: signatures are hashable - - @not_implemented_for("undirected") - # this is intended to be called only on t_G - def _leaves(gr): - for x in gr.nodes: - if not nx.descendants(gr, x): - yield x - - @not_implemented_for("undirected") - def _a_parent_of_leaves_only(gr): - tleaves = set(_leaves(gr)) - for n in set(gr.nodes) - tleaves: - if all(x in tleaves for x in nx.descendants(gr, n)): - return n - - @lru_cache(CLUSTER_EVAL_CACHE_SIZE) - def _value_of_cluster(cluster): - valid_edges = [e for e in safe_G.edges if e[0] in cluster and e[1] in cluster] - return sum(safe_G.edges[e][edge_weight] for e in valid_edges) - - def _value_of_partition(partition): - return sum(_value_of_cluster(frozenset(c)) for c in partition) - - @lru_cache(CLUSTER_EVAL_CACHE_SIZE) - def _weight_of_cluster(cluster): - return sum(safe_G.nodes[n][node_weight] for n in cluster) - - def _pivot(partition, node): - ccx = [c for c in partition if node in c] - assert len(ccx) == 1 - return ccx[0] - - def _concatenate_or_merge(partition_1, partition_2, x, i, ref_weight): - ccx = _pivot(partition_1, x) - cci = _pivot(partition_2, i) - merged_xi = ccx.union(cci) - - # We first check if we can do the merge. - # If so, we do the actual calculations, otherwise we concatenate - if _weight_of_cluster(frozenset(merged_xi)) <= ref_weight: - cp1 = list(filter(lambda x: x != ccx, partition_1)) - cp2 = list(filter(lambda x: x != cci, partition_2)) - - option_2 = [merged_xi] + cp1 + cp2 - return option_2, _value_of_partition(option_2) - else: - option_1 = partition_1 + partition_2 - return option_1, _value_of_partition(option_1) - - # INITIALIZATION ----------------------- - leaves = set(_leaves(t_G)) - for lv in leaves: - t_G.nodes[lv][PKEY] = {} - slot = safe_G.nodes[lv][node_weight] - t_G.nodes[lv][PKEY][slot] = [{lv}] - t_G.nodes[lv][PKEY][0] = [{lv}] - - for inner in [x for x in t_G.nodes if x not in leaves]: - t_G.nodes[inner][PKEY] = {} - slot = safe_G.nodes[inner][node_weight] - t_G.nodes[inner][PKEY][slot] = [{inner}] - nx._clear_cache(t_G) - - # CORE ALGORITHM ----------------------- - while True: - x_node = _a_parent_of_leaves_only(t_G) - weight_of_x = safe_G.nodes[x_node][node_weight] - best_value = 0 - best_partition = None - bp_buffer = {} - x_descendants = nx.descendants(t_G, x_node) - for i_node in x_descendants: - for j in range(weight_of_x, max_size + 1): - for a, b in _split_n_from(j, weight_of_x): - if ( - a not in t_G.nodes[x_node][PKEY] - or b not in t_G.nodes[i_node][PKEY] - ): - # it's not possible to form this particular weight sum - continue - - part1 = t_G.nodes[x_node][PKEY][a] - part2 = t_G.nodes[i_node][PKEY][b] - part, value = _concatenate_or_merge(part1, part2, x_node, i_node, j) - - if j not in bp_buffer or bp_buffer[j][1] < value: - # we annotate in the buffer the best partition for j - bp_buffer[j] = part, value - - # we also keep track of the overall best partition - if best_value <= value: - best_value = value - best_partition = part - - # as illustrated in Lukes, once we finished a child, we can - # discharge the partitions we found into the graph - # (the key phrase is make all x == x') - # so that they are used by the subsequent children - for w, (best_part_for_vl, vl) in bp_buffer.items(): - t_G.nodes[x_node][PKEY][w] = best_part_for_vl - bp_buffer.clear() - - # the absolute best partition for this node - # across all weights has to be stored at 0 - t_G.nodes[x_node][PKEY][0] = best_partition - t_G.remove_nodes_from(x_descendants) - - if x_node == root: - # the 0-labeled partition of root - # is the optimal one for the whole tree - return t_G.nodes[root][PKEY][0] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/modularity_max.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/modularity_max.py deleted file mode 100644 index f465e01..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/modularity_max.py +++ /dev/null @@ -1,451 +0,0 @@ -"""Functions for detecting communities based on modularity.""" - -from collections import defaultdict - -import networkx as nx -from networkx.algorithms.community.quality import modularity -from networkx.utils import not_implemented_for -from networkx.utils.mapped_queue import MappedQueue - -__all__ = [ - "greedy_modularity_communities", - "naive_greedy_modularity_communities", -] - - -def _greedy_modularity_communities_generator(G, weight=None, resolution=1): - r"""Yield community partitions of G and the modularity change at each step. - - This function performs Clauset-Newman-Moore greedy modularity maximization [2]_ - At each step of the process it yields the change in modularity that will occur in - the next step followed by yielding the new community partition after that step. - - Greedy modularity maximization begins with each node in its own community - and repeatedly joins the pair of communities that lead to the largest - modularity until one community contains all nodes (the partition has one set). - - This function maximizes the generalized modularity, where `resolution` - is the resolution parameter, often expressed as $\gamma$. - See :func:`~networkx.algorithms.community.quality.modularity`. - - Parameters - ---------- - G : NetworkX graph - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - resolution : float (default=1) - If resolution is less than 1, modularity favors larger communities. - Greater than 1 favors smaller communities. - - Yields - ------ - Alternating yield statements produce the following two objects: - - communities: dict_values - A dict_values of frozensets of nodes, one for each community. - This represents a partition of the nodes of the graph into communities. - The first yield is the partition with each node in its own community. - - dq: float - The change in modularity when merging the next two communities - that leads to the largest modularity. - - See Also - -------- - modularity - - References - ---------- - .. [1] Newman, M. E. J. "Networks: An Introduction", page 224 - Oxford University Press 2011. - .. [2] Clauset, A., Newman, M. E., & Moore, C. - "Finding community structure in very large networks." - Physical Review E 70(6), 2004. - .. [3] Reichardt and Bornholdt "Statistical Mechanics of Community - Detection" Phys. Rev. E74, 2006. - .. [4] Newman, M. E. J."Analysis of weighted networks" - Physical Review E 70(5 Pt 2):056131, 2004. - """ - directed = G.is_directed() - N = G.number_of_nodes() - - # Count edges (or the sum of edge-weights for weighted graphs) - m = G.size(weight) - q0 = 1 / m - - # Calculate degrees (notation from the papers) - # a : the fraction of (weighted) out-degree for each node - # b : the fraction of (weighted) in-degree for each node - if directed: - a = {node: deg_out * q0 for node, deg_out in G.out_degree(weight=weight)} - b = {node: deg_in * q0 for node, deg_in in G.in_degree(weight=weight)} - else: - a = b = {node: deg * q0 * 0.5 for node, deg in G.degree(weight=weight)} - - # this preliminary step collects the edge weights for each node pair - # It handles multigraph and digraph and works fine for graph. - dq_dict = defaultdict(lambda: defaultdict(float)) - for u, v, wt in G.edges(data=weight, default=1): - if u == v: - continue - dq_dict[u][v] += wt - dq_dict[v][u] += wt - - # now scale and subtract the expected edge-weights term - for u, nbrdict in dq_dict.items(): - for v, wt in nbrdict.items(): - dq_dict[u][v] = q0 * wt - resolution * (a[u] * b[v] + b[u] * a[v]) - - # Use -dq to get a max_heap instead of a min_heap - # dq_heap holds a heap for each node's neighbors - dq_heap = {u: MappedQueue({(u, v): -dq for v, dq in dq_dict[u].items()}) for u in G} - # H -> all_dq_heap holds a heap with the best items for each node - H = MappedQueue([dq_heap[n].heap[0] for n in G if len(dq_heap[n]) > 0]) - - # Initialize single-node communities - communities = {n: frozenset([n]) for n in G} - yield communities.values() - - # Merge the two communities that lead to the largest modularity - while len(H) > 1: - # Find best merge - # Remove from heap of row maxes - # Ties will be broken by choosing the pair with lowest min community id - try: - negdq, u, v = H.pop() - except IndexError: - break - dq = -negdq - yield dq - # Remove best merge from row u heap - dq_heap[u].pop() - # Push new row max onto H - if len(dq_heap[u]) > 0: - H.push(dq_heap[u].heap[0]) - # If this element was also at the root of row v, we need to remove the - # duplicate entry from H - if dq_heap[v].heap[0] == (v, u): - H.remove((v, u)) - # Remove best merge from row v heap - dq_heap[v].remove((v, u)) - # Push new row max onto H - if len(dq_heap[v]) > 0: - H.push(dq_heap[v].heap[0]) - else: - # Duplicate wasn't in H, just remove from row v heap - dq_heap[v].remove((v, u)) - - # Perform merge - communities[v] = frozenset(communities[u] | communities[v]) - del communities[u] - - # Get neighbor communities connected to the merged communities - u_nbrs = set(dq_dict[u]) - v_nbrs = set(dq_dict[v]) - all_nbrs = (u_nbrs | v_nbrs) - {u, v} - both_nbrs = u_nbrs & v_nbrs - # Update dq for merge of u into v - for w in all_nbrs: - # Calculate new dq value - if w in both_nbrs: - dq_vw = dq_dict[v][w] + dq_dict[u][w] - elif w in v_nbrs: - dq_vw = dq_dict[v][w] - resolution * (a[u] * b[w] + a[w] * b[u]) - else: # w in u_nbrs - dq_vw = dq_dict[u][w] - resolution * (a[v] * b[w] + a[w] * b[v]) - # Update rows v and w - for row, col in [(v, w), (w, v)]: - dq_heap_row = dq_heap[row] - # Update dict for v,w only (u is removed below) - dq_dict[row][col] = dq_vw - # Save old max of per-row heap - if len(dq_heap_row) > 0: - d_oldmax = dq_heap_row.heap[0] - else: - d_oldmax = None - # Add/update heaps - d = (row, col) - d_negdq = -dq_vw - # Save old value for finding heap index - if w in v_nbrs: - # Update existing element in per-row heap - dq_heap_row.update(d, d, priority=d_negdq) - else: - # We're creating a new nonzero element, add to heap - dq_heap_row.push(d, priority=d_negdq) - # Update heap of row maxes if necessary - if d_oldmax is None: - # No entries previously in this row, push new max - H.push(d, priority=d_negdq) - else: - # We've updated an entry in this row, has the max changed? - row_max = dq_heap_row.heap[0] - if d_oldmax != row_max or d_oldmax.priority != row_max.priority: - H.update(d_oldmax, row_max) - - # Remove row/col u from dq_dict matrix - for w in dq_dict[u]: - # Remove from dict - dq_old = dq_dict[w][u] - del dq_dict[w][u] - # Remove from heaps if we haven't already - if w != v: - # Remove both row and column - for row, col in [(w, u), (u, w)]: - dq_heap_row = dq_heap[row] - # Check if replaced dq is row max - d_old = (row, col) - if dq_heap_row.heap[0] == d_old: - # Update per-row heap and heap of row maxes - dq_heap_row.remove(d_old) - H.remove(d_old) - # Update row max - if len(dq_heap_row) > 0: - H.push(dq_heap_row.heap[0]) - else: - # Only update per-row heap - dq_heap_row.remove(d_old) - - del dq_dict[u] - # Mark row u as deleted, but keep placeholder - dq_heap[u] = MappedQueue() - # Merge u into v and update a - a[v] += a[u] - a[u] = 0 - if directed: - b[v] += b[u] - b[u] = 0 - - yield communities.values() - - -@nx._dispatchable(edge_attrs="weight") -def greedy_modularity_communities( - G, - weight=None, - resolution=1, - cutoff=1, - best_n=None, -): - r"""Find communities in G using greedy modularity maximization. - - This function uses Clauset-Newman-Moore greedy modularity maximization [2]_ - to find the community partition with the largest modularity. - - Greedy modularity maximization begins with each node in its own community - and repeatedly joins the pair of communities that lead to the largest - modularity until no further increase in modularity is possible (a maximum). - Two keyword arguments adjust the stopping condition. `cutoff` is a lower - limit on the number of communities so you can stop the process before - reaching a maximum (used to save computation time). `best_n` is an upper - limit on the number of communities so you can make the process continue - until at most n communities remain even if the maximum modularity occurs - for more. To obtain exactly n communities, set both `cutoff` and `best_n` to n. - - This function maximizes the generalized modularity, where `resolution` - is the resolution parameter, often expressed as $\gamma$. - See :func:`~networkx.algorithms.community.quality.modularity`. - - Parameters - ---------- - G : NetworkX graph - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - resolution : float, optional (default=1) - If resolution is less than 1, modularity favors larger communities. - Greater than 1 favors smaller communities. - - cutoff : int, optional (default=1) - A minimum number of communities below which the merging process stops. - The process stops at this number of communities even if modularity - is not maximized. The goal is to let the user stop the process early. - The process stops before the cutoff if it finds a maximum of modularity. - - best_n : int or None, optional (default=None) - A maximum number of communities above which the merging process will - not stop. This forces community merging to continue after modularity - starts to decrease until `best_n` communities remain. - If ``None``, don't force it to continue beyond a maximum. - - Raises - ------ - ValueError : If the `cutoff` or `best_n` value is not in the range - ``[1, G.number_of_nodes()]``, or if `best_n` < `cutoff`. - - Returns - ------- - communities: list - A list of frozensets of nodes, one for each community. - Sorted by length with largest communities first. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> c = nx.community.greedy_modularity_communities(G) - >>> sorted(c[0]) - [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] - - See Also - -------- - modularity - - References - ---------- - .. [1] Newman, M. E. J. "Networks: An Introduction", page 224 - Oxford University Press 2011. - .. [2] Clauset, A., Newman, M. E., & Moore, C. - "Finding community structure in very large networks." - Physical Review E 70(6), 2004. - .. [3] Reichardt and Bornholdt "Statistical Mechanics of Community - Detection" Phys. Rev. E74, 2006. - .. [4] Newman, M. E. J."Analysis of weighted networks" - Physical Review E 70(5 Pt 2):056131, 2004. - """ - if not G.size(): - return [{n} for n in G] - - if (cutoff < 1) or (cutoff > G.number_of_nodes()): - raise ValueError(f"cutoff must be between 1 and {len(G)}. Got {cutoff}.") - if best_n is not None: - if (best_n < 1) or (best_n > G.number_of_nodes()): - raise ValueError(f"best_n must be between 1 and {len(G)}. Got {best_n}.") - if best_n < cutoff: - raise ValueError(f"Must have best_n >= cutoff. Got {best_n} < {cutoff}") - if best_n == 1: - return [set(G)] - else: - best_n = G.number_of_nodes() - - # retrieve generator object to construct output - community_gen = _greedy_modularity_communities_generator( - G, weight=weight, resolution=resolution - ) - - # construct the first best community - communities = next(community_gen) - - # continue merging communities until one of the breaking criteria is satisfied - while len(communities) > cutoff: - try: - dq = next(community_gen) - # StopIteration occurs when communities are the connected components - except StopIteration: - communities = sorted(communities, key=len, reverse=True) - # if best_n requires more merging, merge big sets for highest modularity - while len(communities) > best_n: - comm1, comm2, *rest = communities - communities = [comm1 ^ comm2] - communities.extend(rest) - return communities - - # keep going unless max_mod is reached or best_n says to merge more - if dq < 0 and len(communities) <= best_n: - break - communities = next(community_gen) - - return sorted(communities, key=len, reverse=True) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def naive_greedy_modularity_communities(G, resolution=1, weight=None): - r"""Find communities in G using greedy modularity maximization. - - This implementation is O(n^4), much slower than alternatives, but it is - provided as an easy-to-understand reference implementation. - - Greedy modularity maximization begins with each node in its own community - and joins the pair of communities that most increases modularity until no - such pair exists. - - This function maximizes the generalized modularity, where `resolution` - is the resolution parameter, often expressed as $\gamma$. - See :func:`~networkx.algorithms.community.quality.modularity`. - - Parameters - ---------- - G : NetworkX graph - Graph must be simple and undirected. - - resolution : float (default=1) - If resolution is less than 1, modularity favors larger communities. - Greater than 1 favors smaller communities. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - list - A list of sets of nodes, one for each community. - Sorted by length with largest communities first. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> c = nx.community.naive_greedy_modularity_communities(G) - >>> sorted(c[0]) - [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] - - See Also - -------- - greedy_modularity_communities - modularity - """ - # First create one community for each node - communities = [frozenset([u]) for u in G.nodes()] - # Track merges - merges = [] - # Greedily merge communities until no improvement is possible - old_modularity = None - new_modularity = modularity(G, communities, resolution=resolution, weight=weight) - while old_modularity is None or new_modularity > old_modularity: - # Save modularity for comparison - old_modularity = new_modularity - # Find best pair to merge - trial_communities = list(communities) - to_merge = None - for i, u in enumerate(communities): - for j, v in enumerate(communities): - # Skip i==j and empty communities - if j <= i or len(u) == 0 or len(v) == 0: - continue - # Merge communities u and v - trial_communities[j] = u | v - trial_communities[i] = frozenset([]) - trial_modularity = modularity( - G, trial_communities, resolution=resolution, weight=weight - ) - if trial_modularity >= new_modularity: - # Check if strictly better or tie - if trial_modularity > new_modularity: - # Found new best, save modularity and group indexes - new_modularity = trial_modularity - to_merge = (i, j, new_modularity - old_modularity) - elif to_merge and min(i, j) < min(to_merge[0], to_merge[1]): - # Break ties by choosing pair with lowest min id - new_modularity = trial_modularity - to_merge = (i, j, new_modularity - old_modularity) - # Un-merge - trial_communities[i] = u - trial_communities[j] = v - if to_merge is not None: - # If the best merge improves modularity, use it - merges.append(to_merge) - i, j, dq = to_merge - u, v = communities[i], communities[j] - communities[j] = u | v - communities[i] = frozenset([]) - # Remove empty communities and sort - return sorted((c for c in communities if len(c) > 0), key=len, reverse=True) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/quality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/quality.py deleted file mode 100644 index f09a6d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/quality.py +++ /dev/null @@ -1,346 +0,0 @@ -"""Functions for measuring the quality of a partition (into -communities). - -""" - -from itertools import combinations - -import networkx as nx -from networkx import NetworkXError -from networkx.algorithms.community.community_utils import is_partition -from networkx.utils.decorators import argmap - -__all__ = ["modularity", "partition_quality"] - - -class NotAPartition(NetworkXError): - """Raised if a given collection is not a partition.""" - - def __init__(self, G, collection): - msg = f"{collection} is not a valid partition of the graph {G}" - super().__init__(msg) - - -def _require_partition(G, partition): - """Decorator to check that a valid partition is input to a function - - Raises :exc:`networkx.NetworkXError` if the partition is not valid. - - This decorator should be used on functions whose first two arguments - are a graph and a partition of the nodes of that graph (in that - order):: - - >>> @require_partition - ... def foo(G, partition): - ... print("partition is valid!") - ... - >>> G = nx.complete_graph(5) - >>> partition = [{0, 1}, {2, 3}, {4}] - >>> foo(G, partition) - partition is valid! - >>> partition = [{0}, {2, 3}, {4}] - >>> foo(G, partition) - Traceback (most recent call last): - ... - networkx.exception.NetworkXError: `partition` is not a valid partition of the nodes of G - >>> partition = [{0, 1}, {1, 2, 3}, {4}] - >>> foo(G, partition) - Traceback (most recent call last): - ... - networkx.exception.NetworkXError: `partition` is not a valid partition of the nodes of G - - """ - if is_partition(G, partition): - return G, partition - raise nx.NetworkXError("`partition` is not a valid partition of the nodes of G") - - -require_partition = argmap(_require_partition, (0, 1)) - - -@nx._dispatchable -def intra_community_edges(G, partition): - """Returns the number of intra-community edges for a partition of `G`. - - Parameters - ---------- - G : NetworkX graph. - - partition : iterable of sets of nodes - This must be a partition of the nodes of `G`. - - The "intra-community edges" are those edges joining a pair of nodes - in the same block of the partition. - - """ - return sum(G.subgraph(block).size() for block in partition) - - -@nx._dispatchable -def inter_community_edges(G, partition): - """Returns the number of inter-community edges for a partition of `G`. - according to the given - partition of the nodes of `G`. - - Parameters - ---------- - G : NetworkX graph. - - partition : iterable of sets of nodes - This must be a partition of the nodes of `G`. - - The *inter-community edges* are those edges joining a pair of nodes - in different blocks of the partition. - - Implementation note: this function creates an intermediate graph - that may require the same amount of memory as that of `G`. - - """ - # Alternate implementation that does not require constructing a new - # graph object (but does require constructing an affiliation - # dictionary): - # - # aff = dict(chain.from_iterable(((v, block) for v in block) - # for block in partition)) - # return sum(1 for u, v in G.edges() if aff[u] != aff[v]) - # - MG = nx.MultiDiGraph if G.is_directed() else nx.MultiGraph - return nx.quotient_graph(G, partition, create_using=MG).size() - - -@nx._dispatchable -def inter_community_non_edges(G, partition): - """Returns the number of inter-community non-edges according to the - given partition of the nodes of `G`. - - Parameters - ---------- - G : NetworkX graph. - - partition : iterable of sets of nodes - This must be a partition of the nodes of `G`. - - A *non-edge* is a pair of nodes (undirected if `G` is undirected) - that are not adjacent in `G`. The *inter-community non-edges* are - those non-edges on a pair of nodes in different blocks of the - partition. - - Implementation note: this function creates two intermediate graphs, - which may require up to twice the amount of memory as required to - store `G`. - - """ - # Alternate implementation that does not require constructing two - # new graph objects (but does require constructing an affiliation - # dictionary): - # - # aff = dict(chain.from_iterable(((v, block) for v in block) - # for block in partition)) - # return sum(1 for u, v in nx.non_edges(G) if aff[u] != aff[v]) - # - return inter_community_edges(nx.complement(G), partition) - - -@nx._dispatchable(edge_attrs="weight") -def modularity(G, communities, weight="weight", resolution=1): - r"""Returns the modularity of the given partition of the graph. - - Modularity is defined in [1]_ as - - .. math:: - Q = \frac{1}{2m} \sum_{ij} \left( A_{ij} - \gamma\frac{k_ik_j}{2m}\right) - \delta(c_i,c_j) - - where $m$ is the number of edges (or sum of all edge weights as in [5]_), - $A$ is the adjacency matrix of `G`, $k_i$ is the (weighted) degree of $i$, - $\gamma$ is the resolution parameter, and $\delta(c_i, c_j)$ is 1 if $i$ and - $j$ are in the same community else 0. - - According to [2]_ (and verified by some algebra) this can be reduced to - - .. math:: - Q = \sum_{c=1}^{n} - \left[ \frac{L_c}{m} - \gamma\left( \frac{k_c}{2m} \right) ^2 \right] - - where the sum iterates over all communities $c$, $m$ is the number of edges, - $L_c$ is the number of intra-community links for community $c$, - $k_c$ is the sum of degrees of the nodes in community $c$, - and $\gamma$ is the resolution parameter. - - The resolution parameter sets an arbitrary tradeoff between intra-group - edges and inter-group edges. More complex grouping patterns can be - discovered by analyzing the same network with multiple values of gamma - and then combining the results [3]_. That said, it is very common to - simply use gamma=1. More on the choice of gamma is in [4]_. - - The second formula is the one actually used in calculation of the modularity. - For directed graphs the second formula replaces $k_c$ with $k^{in}_c k^{out}_c$. - - Parameters - ---------- - G : NetworkX Graph - - communities : list or iterable of set of nodes - These node sets must represent a partition of G's nodes. - - weight : string or None, optional (default="weight") - The edge attribute that holds the numerical value used - as a weight. If None or an edge does not have that attribute, - then that edge has weight 1. - - resolution : float (default=1) - If resolution is less than 1, modularity favors larger communities. - Greater than 1 favors smaller communities. - - Returns - ------- - Q : float - The modularity of the partition. - - Raises - ------ - NotAPartition - If `communities` is not a partition of the nodes of `G`. - - Examples - -------- - >>> G = nx.barbell_graph(3, 0) - >>> nx.community.modularity(G, [{0, 1, 2}, {3, 4, 5}]) - 0.35714285714285715 - >>> nx.community.modularity(G, nx.community.label_propagation_communities(G)) - 0.35714285714285715 - - References - ---------- - .. [1] M. E. J. Newman "Networks: An Introduction", page 224. - Oxford University Press, 2011. - .. [2] Clauset, Aaron, Mark EJ Newman, and Cristopher Moore. - "Finding community structure in very large networks." - Phys. Rev. E 70.6 (2004). - .. [3] Reichardt and Bornholdt "Statistical Mechanics of Community Detection" - Phys. Rev. E 74, 016110, 2006. https://doi.org/10.1103/PhysRevE.74.016110 - .. [4] M. E. J. Newman, "Equivalence between modularity optimization and - maximum likelihood methods for community detection" - Phys. Rev. E 94, 052315, 2016. https://doi.org/10.1103/PhysRevE.94.052315 - .. [5] Blondel, V.D. et al. "Fast unfolding of communities in large - networks" J. Stat. Mech 10008, 1-12 (2008). - https://doi.org/10.1088/1742-5468/2008/10/P10008 - """ - if not isinstance(communities, list): - communities = list(communities) - if not is_partition(G, communities): - raise NotAPartition(G, communities) - - directed = G.is_directed() - if directed: - out_degree = dict(G.out_degree(weight=weight)) - in_degree = dict(G.in_degree(weight=weight)) - m = sum(out_degree.values()) - norm = 1 / m**2 - else: - out_degree = in_degree = dict(G.degree(weight=weight)) - deg_sum = sum(out_degree.values()) - m = deg_sum / 2 - norm = 1 / deg_sum**2 - - def community_contribution(community): - comm = set(community) - L_c = sum(wt for u, v, wt in G.edges(comm, data=weight, default=1) if v in comm) - - out_degree_sum = sum(out_degree[u] for u in comm) - in_degree_sum = sum(in_degree[u] for u in comm) if directed else out_degree_sum - - return L_c / m - resolution * out_degree_sum * in_degree_sum * norm - - return sum(map(community_contribution, communities)) - - -@require_partition -@nx._dispatchable -def partition_quality(G, partition): - """Returns the coverage and performance of a partition of G. - - The *coverage* of a partition is the ratio of the number of - intra-community edges to the total number of edges in the graph. - - The *performance* of a partition is the number of - intra-community edges plus inter-community non-edges divided by the total - number of potential edges. - - This algorithm has complexity $O(C^2 + L)$ where C is the number of communities and L is the number of links. - - Parameters - ---------- - G : NetworkX graph - - partition : sequence - Partition of the nodes of `G`, represented as a sequence of - sets of nodes (blocks). Each block of the partition represents a - community. - - Returns - ------- - (float, float) - The (coverage, performance) tuple of the partition, as defined above. - - Raises - ------ - NetworkXError - If `partition` is not a valid partition of the nodes of `G`. - - Notes - ----- - If `G` is a multigraph; - - for coverage, the multiplicity of edges is counted - - for performance, the result is -1 (total number of possible edges is not defined) - - References - ---------- - .. [1] Santo Fortunato. - "Community Detection in Graphs". - *Physical Reports*, Volume 486, Issue 3--5 pp. 75--174 - - """ - - node_community = {} - for i, community in enumerate(partition): - for node in community: - node_community[node] = i - - # `performance` is not defined for multigraphs - if not G.is_multigraph(): - # Iterate over the communities, quadratic, to calculate `possible_inter_community_edges` - possible_inter_community_edges = sum( - len(p1) * len(p2) for p1, p2 in combinations(partition, 2) - ) - - if G.is_directed(): - possible_inter_community_edges *= 2 - else: - possible_inter_community_edges = 0 - - # Compute the number of edges in the complete graph -- `n` nodes, - # directed or undirected, depending on `G` - n = len(G) - total_pairs = n * (n - 1) - if not G.is_directed(): - total_pairs //= 2 - - intra_community_edges = 0 - inter_community_non_edges = possible_inter_community_edges - - # Iterate over the links to count `intra_community_edges` and `inter_community_non_edges` - for e in G.edges(): - if node_community[e[0]] == node_community[e[1]]: - intra_community_edges += 1 - else: - inter_community_non_edges -= 1 - - coverage = intra_community_edges / len(G.edges) - - if G.is_multigraph(): - performance = -1.0 - else: - performance = (intra_community_edges + inter_community_non_edges) / total_pairs - - return coverage, performance diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_asyn_fluid.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_asyn_fluid.py deleted file mode 100644 index 6c023be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_asyn_fluid.py +++ /dev/null @@ -1,136 +0,0 @@ -import pytest - -import networkx as nx -from networkx import Graph, NetworkXError -from networkx.algorithms.community import asyn_fluidc - - -@pytest.mark.parametrize("graph_constructor", (nx.DiGraph, nx.MultiGraph)) -def test_raises_on_directed_and_multigraphs(graph_constructor): - G = graph_constructor([(0, 1), (1, 2)]) - with pytest.raises(nx.NetworkXNotImplemented): - nx.community.asyn_fluidc(G, 1) - - -def test_exceptions(): - test = Graph() - test.add_node("a") - pytest.raises(NetworkXError, asyn_fluidc, test, "hi") - pytest.raises(NetworkXError, asyn_fluidc, test, -1) - pytest.raises(NetworkXError, asyn_fluidc, test, 3) - test.add_node("b") - pytest.raises(NetworkXError, asyn_fluidc, test, 1) - - -def test_single_node(): - test = Graph() - - test.add_node("a") - - # ground truth - ground_truth = {frozenset(["a"])} - - communities = asyn_fluidc(test, 1) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_two_nodes(): - test = Graph() - - test.add_edge("a", "b") - - # ground truth - ground_truth = {frozenset(["a"]), frozenset(["b"])} - - communities = asyn_fluidc(test, 2) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_two_clique_communities(): - test = Graph() - - # c1 - test.add_edge("a", "b") - test.add_edge("a", "c") - test.add_edge("b", "c") - - # connection - test.add_edge("c", "d") - - # c2 - test.add_edge("d", "e") - test.add_edge("d", "f") - test.add_edge("f", "e") - - # ground truth - ground_truth = {frozenset(["a", "c", "b"]), frozenset(["e", "d", "f"])} - - communities = asyn_fluidc(test, 2, seed=7) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_five_clique_ring(): - test = Graph() - - # c1 - test.add_edge("1a", "1b") - test.add_edge("1a", "1c") - test.add_edge("1a", "1d") - test.add_edge("1b", "1c") - test.add_edge("1b", "1d") - test.add_edge("1c", "1d") - - # c2 - test.add_edge("2a", "2b") - test.add_edge("2a", "2c") - test.add_edge("2a", "2d") - test.add_edge("2b", "2c") - test.add_edge("2b", "2d") - test.add_edge("2c", "2d") - - # c3 - test.add_edge("3a", "3b") - test.add_edge("3a", "3c") - test.add_edge("3a", "3d") - test.add_edge("3b", "3c") - test.add_edge("3b", "3d") - test.add_edge("3c", "3d") - - # c4 - test.add_edge("4a", "4b") - test.add_edge("4a", "4c") - test.add_edge("4a", "4d") - test.add_edge("4b", "4c") - test.add_edge("4b", "4d") - test.add_edge("4c", "4d") - - # c5 - test.add_edge("5a", "5b") - test.add_edge("5a", "5c") - test.add_edge("5a", "5d") - test.add_edge("5b", "5c") - test.add_edge("5b", "5d") - test.add_edge("5c", "5d") - - # connections - test.add_edge("1a", "2c") - test.add_edge("2a", "3c") - test.add_edge("3a", "4c") - test.add_edge("4a", "5c") - test.add_edge("5a", "1c") - - # ground truth - ground_truth = { - frozenset(["1a", "1b", "1c", "1d"]), - frozenset(["2a", "2b", "2c", "2d"]), - frozenset(["3a", "3b", "3c", "3d"]), - frozenset(["4a", "4b", "4c", "4d"]), - frozenset(["5a", "5b", "5c", "5d"]), - } - - communities = asyn_fluidc(test, 5, seed=9) - result = {frozenset(c) for c in communities} - assert result == ground_truth diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_centrality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_centrality.py deleted file mode 100644 index 1a8982f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_centrality.py +++ /dev/null @@ -1,85 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.community.centrality` -module. - -""" - -from operator import itemgetter - -import networkx as nx - - -def set_of_sets(iterable): - return set(map(frozenset, iterable)) - - -def validate_communities(result, expected): - assert set_of_sets(result) == set_of_sets(expected) - - -def validate_possible_communities(result, *expected): - assert any(set_of_sets(result) == set_of_sets(p) for p in expected) - - -class TestGirvanNewman: - """Unit tests for the - :func:`networkx.algorithms.community.centrality.girvan_newman` - function. - - """ - - def test_no_edges(self): - G = nx.empty_graph(3) - communities = list(nx.community.girvan_newman(G)) - assert len(communities) == 1 - validate_communities(communities[0], [{0}, {1}, {2}]) - - def test_undirected(self): - # Start with the graph .-.-.-. - G = nx.path_graph(4) - communities = list(nx.community.girvan_newman(G)) - assert len(communities) == 3 - # After one removal, we get the graph .-. .-. - validate_communities(communities[0], [{0, 1}, {2, 3}]) - # After the next, we get the graph .-. . ., but there are two - # symmetric possible versions. - validate_possible_communities( - communities[1], [{0}, {1}, {2, 3}], [{0, 1}, {2}, {3}] - ) - # After the last removal, we always get the empty graph. - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_directed(self): - G = nx.DiGraph(nx.path_graph(4)) - communities = list(nx.community.girvan_newman(G)) - assert len(communities) == 3 - validate_communities(communities[0], [{0, 1}, {2, 3}]) - validate_possible_communities( - communities[1], [{0}, {1}, {2, 3}], [{0, 1}, {2}, {3}] - ) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_selfloops(self): - G = nx.path_graph(4) - G.add_edge(0, 0) - G.add_edge(2, 2) - communities = list(nx.community.girvan_newman(G)) - assert len(communities) == 3 - validate_communities(communities[0], [{0, 1}, {2, 3}]) - validate_possible_communities( - communities[1], [{0}, {1}, {2, 3}], [{0, 1}, {2}, {3}] - ) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_most_valuable_edge(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 3), (1, 2, 2), (2, 3, 1)]) - # Let the most valuable edge be the one with the highest weight. - - def heaviest(G): - return max(G.edges(data="weight"), key=itemgetter(2))[:2] - - communities = list(nx.community.girvan_newman(G, heaviest)) - assert len(communities) == 3 - validate_communities(communities[0], [{0}, {1, 2, 3}]) - validate_communities(communities[1], [{0}, {1}, {2, 3}]) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_divisive.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_divisive.py deleted file mode 100644 index 6331503..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_divisive.py +++ /dev/null @@ -1,106 +0,0 @@ -import pytest - -import networkx as nx - - -def test_edge_betweenness_partition(): - G = nx.barbell_graph(3, 0) - C = nx.community.edge_betweenness_partition(G, 2) - answer = [{0, 1, 2}, {3, 4, 5}] - assert len(C) == len(answer) - for s in answer: - assert s in C - - G = nx.barbell_graph(3, 1) - C = nx.community.edge_betweenness_partition(G, 3) - answer = [{0, 1, 2}, {4, 5, 6}, {3}] - assert len(C) == len(answer) - for s in answer: - assert s in C - - C = nx.community.edge_betweenness_partition(G, 7) - answer = [{n} for n in G] - assert len(C) == len(answer) - for s in answer: - assert s in C - - C = nx.community.edge_betweenness_partition(G, 1) - assert C == [set(G)] - - C = nx.community.edge_betweenness_partition(G, 1, weight="weight") - assert C == [set(G)] - - with pytest.raises(nx.NetworkXError): - nx.community.edge_betweenness_partition(G, 0) - - with pytest.raises(nx.NetworkXError): - nx.community.edge_betweenness_partition(G, -1) - - with pytest.raises(nx.NetworkXError): - nx.community.edge_betweenness_partition(G, 10) - - -def test_edge_current_flow_betweenness_partition(): - pytest.importorskip("scipy") - - G = nx.barbell_graph(3, 0) - C = nx.community.edge_current_flow_betweenness_partition(G, 2) - answer = [{0, 1, 2}, {3, 4, 5}] - assert len(C) == len(answer) - for s in answer: - assert s in C - - G = nx.barbell_graph(3, 1) - C = nx.community.edge_current_flow_betweenness_partition(G, 2) - answers = [[{0, 1, 2, 3}, {4, 5, 6}], [{0, 1, 2}, {3, 4, 5, 6}]] - assert len(C) == len(answers[0]) - assert any(all(s in answer for s in C) for answer in answers) - - C = nx.community.edge_current_flow_betweenness_partition(G, 3) - answer = [{0, 1, 2}, {4, 5, 6}, {3}] - assert len(C) == len(answer) - for s in answer: - assert s in C - - C = nx.community.edge_current_flow_betweenness_partition(G, 4) - answers = [[{1, 2}, {4, 5, 6}, {3}, {0}], [{0, 1, 2}, {5, 6}, {3}, {4}]] - assert len(C) == len(answers[0]) - assert any(all(s in answer for s in C) for answer in answers) - - C = nx.community.edge_current_flow_betweenness_partition(G, 5) - answer = [{1, 2}, {5, 6}, {3}, {0}, {4}] - assert len(C) == len(answer) - for s in answer: - assert s in C - - C = nx.community.edge_current_flow_betweenness_partition(G, 6) - answers = [[{2}, {5, 6}, {3}, {0}, {4}, {1}], [{1, 2}, {6}, {3}, {0}, {4}, {5}]] - assert len(C) == len(answers[0]) - assert any(all(s in answer for s in C) for answer in answers) - - C = nx.community.edge_current_flow_betweenness_partition(G, 7) - answer = [{n} for n in G] - assert len(C) == len(answer) - for s in answer: - assert s in C - - C = nx.community.edge_current_flow_betweenness_partition(G, 1) - assert C == [set(G)] - - C = nx.community.edge_current_flow_betweenness_partition(G, 1, weight="weight") - assert C == [set(G)] - - with pytest.raises(nx.NetworkXError): - nx.community.edge_current_flow_betweenness_partition(G, 0) - - with pytest.raises(nx.NetworkXError): - nx.community.edge_current_flow_betweenness_partition(G, -1) - - with pytest.raises(nx.NetworkXError): - nx.community.edge_current_flow_betweenness_partition(G, 10) - - N = 10 - G = nx.empty_graph(N) - for i in range(2, N - 1): - C = nx.community.edge_current_flow_betweenness_partition(G, i) - assert C == [{n} for n in G] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kclique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kclique.py deleted file mode 100644 index aa0b7e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kclique.py +++ /dev/null @@ -1,91 +0,0 @@ -from itertools import combinations - -import pytest - -import networkx as nx - - -def test_overlapping_K5(): - G = nx.Graph() - G.add_edges_from(combinations(range(5), 2)) # Add a five clique - G.add_edges_from(combinations(range(2, 7), 2)) # Add another five clique - c = list(nx.community.k_clique_communities(G, 4)) - assert c == [frozenset(range(7))] - c = set(nx.community.k_clique_communities(G, 5)) - assert c == {frozenset(range(5)), frozenset(range(2, 7))} - - -def test_isolated_K5(): - G = nx.Graph() - G.add_edges_from(combinations(range(5), 2)) # Add a five clique - G.add_edges_from(combinations(range(5, 10), 2)) # Add another five clique - c = set(nx.community.k_clique_communities(G, 5)) - assert c == {frozenset(range(5)), frozenset(range(5, 10))} - - -class TestZacharyKarateClub: - def setup_method(self): - self.G = nx.karate_club_graph() - - def _check_communities(self, k, expected): - communities = set(nx.community.k_clique_communities(self.G, k)) - assert communities == expected - - def test_k2(self): - # clique percolation with k=2 is just connected components - expected = {frozenset(self.G)} - self._check_communities(2, expected) - - def test_k3(self): - comm1 = [ - 0, - 1, - 2, - 3, - 7, - 8, - 12, - 13, - 14, - 15, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - ] - comm2 = [0, 4, 5, 6, 10, 16] - comm3 = [24, 25, 31] - expected = {frozenset(comm1), frozenset(comm2), frozenset(comm3)} - self._check_communities(3, expected) - - def test_k4(self): - expected = { - frozenset([0, 1, 2, 3, 7, 13]), - frozenset([8, 32, 30, 33]), - frozenset([32, 33, 29, 23]), - } - self._check_communities(4, expected) - - def test_k5(self): - expected = {frozenset([0, 1, 2, 3, 7, 13])} - self._check_communities(5, expected) - - def test_k6(self): - expected = set() - self._check_communities(6, expected) - - -def test_bad_k(): - with pytest.raises(nx.NetworkXError): - list(nx.community.k_clique_communities(nx.Graph(), 1)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kernighan_lin.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kernighan_lin.py deleted file mode 100644 index 25d53d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_kernighan_lin.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.community.kernighan_lin` -module. -""" - -from itertools import permutations - -import pytest - -import networkx as nx -from networkx.algorithms.community import kernighan_lin_bisection - - -def assert_partition_equal(x, y): - assert set(map(frozenset, x)) == set(map(frozenset, y)) - - -def test_partition(): - G = nx.barbell_graph(3, 0) - C = kernighan_lin_bisection(G) - assert_partition_equal(C, [{0, 1, 2}, {3, 4, 5}]) - - -def test_partition_argument(): - G = nx.barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - C = kernighan_lin_bisection(G, partition) - assert_partition_equal(C, partition) - - -def test_partition_argument_non_integer_nodes(): - G = nx.Graph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - partition = ({"A", "B"}, {"C", "D"}) - C = kernighan_lin_bisection(G, partition) - assert_partition_equal(C, partition) - - -def test_seed_argument(): - G = nx.barbell_graph(3, 0) - C = kernighan_lin_bisection(G, seed=1) - assert_partition_equal(C, [{0, 1, 2}, {3, 4, 5}]) - - -def test_non_disjoint_partition(): - with pytest.raises(nx.NetworkXError): - G = nx.barbell_graph(3, 0) - partition = ({0, 1, 2}, {2, 3, 4, 5}) - kernighan_lin_bisection(G, partition) - - -def test_too_many_blocks(): - with pytest.raises(nx.NetworkXError): - G = nx.barbell_graph(3, 0) - partition = ({0, 1}, {2}, {3, 4, 5}) - kernighan_lin_bisection(G, partition) - - -def test_multigraph(): - G = nx.cycle_graph(4) - M = nx.MultiGraph(G.edges()) - M.add_edges_from(G.edges()) - M.remove_edge(1, 2) - for labels in permutations(range(4)): - mapping = dict(zip(M, labels)) - A, B = kernighan_lin_bisection(nx.relabel_nodes(M, mapping), seed=0) - assert_partition_equal( - [A, B], [{mapping[0], mapping[1]}, {mapping[2], mapping[3]}] - ) - - -def test_max_iter_argument(): - G = nx.Graph( - [ - ("A", "B", {"weight": 1}), - ("A", "C", {"weight": 2}), - ("A", "D", {"weight": 3}), - ("A", "E", {"weight": 2}), - ("A", "F", {"weight": 4}), - ("B", "C", {"weight": 1}), - ("B", "D", {"weight": 4}), - ("B", "E", {"weight": 2}), - ("B", "F", {"weight": 1}), - ("C", "D", {"weight": 3}), - ("C", "E", {"weight": 2}), - ("C", "F", {"weight": 1}), - ("D", "E", {"weight": 4}), - ("D", "F", {"weight": 3}), - ("E", "F", {"weight": 2}), - ] - ) - partition = ({"A", "B", "C"}, {"D", "E", "F"}) - C = kernighan_lin_bisection(G, partition, max_iter=1) - assert_partition_equal(C, ({"A", "F", "C"}, {"D", "E", "B"})) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_label_propagation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_label_propagation.py deleted file mode 100644 index 4be72db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_label_propagation.py +++ /dev/null @@ -1,241 +0,0 @@ -from itertools import chain, combinations - -import pytest - -import networkx as nx - - -def test_directed_not_supported(): - with pytest.raises(nx.NetworkXNotImplemented): - # not supported for directed graphs - test = nx.DiGraph() - test.add_edge("a", "b") - test.add_edge("a", "c") - test.add_edge("b", "d") - result = nx.community.label_propagation_communities(test) - - -def test_iterator_vs_iterable(): - G = nx.empty_graph("a") - assert list(nx.community.label_propagation_communities(G)) == [{"a"}] - for community in nx.community.label_propagation_communities(G): - assert community == {"a"} - pytest.raises(TypeError, next, nx.community.label_propagation_communities(G)) - - -def test_one_node(): - test = nx.Graph() - test.add_node("a") - - # The expected communities are: - ground_truth = {frozenset(["a"])} - - communities = nx.community.label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_unconnected_communities(): - test = nx.Graph() - # community 1 - test.add_edge("a", "c") - test.add_edge("a", "d") - test.add_edge("d", "c") - # community 2 - test.add_edge("b", "e") - test.add_edge("e", "f") - test.add_edge("f", "b") - - # The expected communities are: - ground_truth = {frozenset(["a", "c", "d"]), frozenset(["b", "e", "f"])} - - communities = nx.community.label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_connected_communities(): - test = nx.Graph() - # community 1 - test.add_edge("a", "b") - test.add_edge("c", "a") - test.add_edge("c", "b") - test.add_edge("d", "a") - test.add_edge("d", "b") - test.add_edge("d", "c") - test.add_edge("e", "a") - test.add_edge("e", "b") - test.add_edge("e", "c") - test.add_edge("e", "d") - # community 2 - test.add_edge("1", "2") - test.add_edge("3", "1") - test.add_edge("3", "2") - test.add_edge("4", "1") - test.add_edge("4", "2") - test.add_edge("4", "3") - test.add_edge("5", "1") - test.add_edge("5", "2") - test.add_edge("5", "3") - test.add_edge("5", "4") - # edge between community 1 and 2 - test.add_edge("a", "1") - # community 3 - test.add_edge("x", "y") - # community 4 with only a single node - test.add_node("z") - - # The expected communities are: - ground_truth1 = { - frozenset(["a", "b", "c", "d", "e"]), - frozenset(["1", "2", "3", "4", "5"]), - frozenset(["x", "y"]), - frozenset(["z"]), - } - ground_truth2 = { - frozenset(["a", "b", "c", "d", "e", "1", "2", "3", "4", "5"]), - frozenset(["x", "y"]), - frozenset(["z"]), - } - ground_truth = (ground_truth1, ground_truth2) - - communities = nx.community.label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result in ground_truth - - -def test_termination(): - # ensure termination of asyn_lpa_communities in two cases - # that led to an endless loop in a previous version - test1 = nx.karate_club_graph() - test2 = nx.caveman_graph(2, 10) - test2.add_edges_from([(0, 20), (20, 10)]) - nx.community.asyn_lpa_communities(test1) - nx.community.asyn_lpa_communities(test2) - - -class TestAsynLpaCommunities: - def _check_communities(self, G, expected): - """Checks that the communities computed from the given graph ``G`` - using the :func:`~networkx.asyn_lpa_communities` function match - the set of nodes given in ``expected``. - - ``expected`` must be a :class:`set` of :class:`frozenset` - instances, each element of which is a node in the graph. - - """ - communities = nx.community.asyn_lpa_communities(G) - result = {frozenset(c) for c in communities} - assert result == expected - - def test_null_graph(self): - G = nx.null_graph() - ground_truth = set() - self._check_communities(G, ground_truth) - - def test_single_node(self): - G = nx.empty_graph(1) - ground_truth = {frozenset([0])} - self._check_communities(G, ground_truth) - - def test_simple_communities(self): - # This graph is the disjoint union of two triangles. - G = nx.Graph(["ab", "ac", "bc", "de", "df", "fe"]) - ground_truth = {frozenset("abc"), frozenset("def")} - self._check_communities(G, ground_truth) - - def test_seed_argument(self): - G = nx.Graph(["ab", "ac", "bc", "de", "df", "fe"]) - ground_truth = {frozenset("abc"), frozenset("def")} - communities = nx.community.asyn_lpa_communities(G, seed=1) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - def test_several_communities(self): - # This graph is the disjoint union of five triangles. - ground_truth = {frozenset(range(3 * i, 3 * (i + 1))) for i in range(5)} - edges = chain.from_iterable(combinations(c, 2) for c in ground_truth) - G = nx.Graph(edges) - self._check_communities(G, ground_truth) - - -class TestFastLabelPropagationCommunities: - N = 100 # number of nodes - K = 15 # average node degree - - def _check_communities(self, G, truth, weight=None, seed=42): - C = nx.community.fast_label_propagation_communities(G, weight=weight, seed=seed) - assert {frozenset(c) for c in C} == truth - - def test_null_graph(self): - G = nx.null_graph() - truth = set() - self._check_communities(G, truth) - - def test_empty_graph(self): - G = nx.empty_graph(self.N) - truth = {frozenset([i]) for i in G} - self._check_communities(G, truth) - - def test_star_graph(self): - G = nx.star_graph(self.N) - truth = {frozenset(G)} - self._check_communities(G, truth) - - def test_complete_graph(self): - G = nx.complete_graph(self.N) - truth = {frozenset(G)} - self._check_communities(G, truth) - - def test_bipartite_graph(self): - G = nx.complete_bipartite_graph(self.N // 2, self.N // 2) - truth = {frozenset(G)} - self._check_communities(G, truth) - - def test_random_graph(self): - G = nx.gnm_random_graph(self.N, self.N * self.K // 2, seed=42) - truth = {frozenset(G)} - self._check_communities(G, truth) - - def test_disjoin_cliques(self): - G = nx.Graph(["ab", "AB", "AC", "BC", "12", "13", "14", "23", "24", "34"]) - truth = {frozenset("ab"), frozenset("ABC"), frozenset("1234")} - self._check_communities(G, truth) - - def test_ring_of_cliques(self): - N, K = self.N, self.K - G = nx.ring_of_cliques(N, K) - truth = {frozenset([K * i + k for k in range(K)]) for i in range(N)} - self._check_communities(G, truth) - - def test_larger_graph(self): - G = nx.gnm_random_graph(100 * self.N, 50 * self.N * self.K, seed=42) - nx.community.fast_label_propagation_communities(G) - - def test_graph_type(self): - G1 = nx.complete_graph(self.N, nx.MultiDiGraph()) - G2 = nx.MultiGraph(G1) - G3 = nx.DiGraph(G1) - G4 = nx.Graph(G1) - truth = {frozenset(G1)} - self._check_communities(G1, truth) - self._check_communities(G2, truth) - self._check_communities(G3, truth) - self._check_communities(G4, truth) - - def test_weight_argument(self): - G = nx.MultiDiGraph() - G.add_edge(1, 2, weight=1.41) - G.add_edge(2, 1, weight=1.41) - G.add_edge(2, 3) - G.add_edge(3, 4, weight=3.14) - truth = {frozenset({1, 2}), frozenset({3, 4})} - self._check_communities(G, truth, weight="weight") - - def test_seed_argument(self): - G = nx.karate_club_graph() - C = nx.community.fast_label_propagation_communities(G, seed=2023) - truth = {frozenset(c) for c in C} - self._check_communities(G, truth, seed=2023) - # smoke test that seed=None works - C = nx.community.fast_label_propagation_communities(G, seed=None) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_louvain.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_louvain.py deleted file mode 100644 index 816e6f1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_louvain.py +++ /dev/null @@ -1,264 +0,0 @@ -import pytest - -import networkx as nx - - -def test_modularity_increase(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - partition = [{u} for u in G.nodes()] - mod = nx.community.modularity(G, partition) - partition = nx.community.louvain_communities(G) - - assert nx.community.modularity(G, partition) > mod - - -def test_valid_partition(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - H = G.to_directed() - partition = nx.community.louvain_communities(G) - partition2 = nx.community.louvain_communities(H) - - assert nx.community.is_partition(G, partition) - assert nx.community.is_partition(H, partition2) - - -def test_karate_club_partition(): - G = nx.karate_club_graph() - part = [ - {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, - {16, 4, 5, 6, 10}, - {23, 25, 27, 28, 24, 31}, - {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, - ] - partition = nx.community.louvain_communities(G, seed=2, weight=None) - - assert part == partition - - -def test_partition_iterator(): - G = nx.path_graph(15) - parts_iter = nx.community.louvain_partitions(G, seed=42) - first_part = next(parts_iter) - first_copy = [s.copy() for s in first_part] - - # gh-5901 reports sets changing after next partition is yielded - assert first_copy[0] == first_part[0] - second_part = next(parts_iter) - assert first_copy[0] == first_part[0] - - -def test_undirected_selfloops(): - G = nx.karate_club_graph() - expected_partition = nx.community.louvain_communities(G, seed=2, weight=None) - part = [ - {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, - {16, 4, 5, 6, 10}, - {23, 25, 27, 28, 24, 31}, - {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, - ] - assert expected_partition == part - - G.add_weighted_edges_from([(i, i, i * 1000) for i in range(9)]) - # large self-loop weight impacts partition - partition = nx.community.louvain_communities(G, seed=2, weight="weight") - assert part != partition - - # small self-loop weights aren't enough to impact partition in this graph - partition = nx.community.louvain_communities(G, seed=2, weight=None) - assert part == partition - - -def test_directed_selfloops(): - G = nx.DiGraph() - G.add_nodes_from(range(11)) - G_edges = [ - (0, 2), - (0, 1), - (1, 0), - (2, 1), - (2, 0), - (3, 4), - (4, 3), - (7, 8), - (8, 7), - (9, 10), - (10, 9), - ] - G.add_edges_from(G_edges) - G_expected_partition = nx.community.louvain_communities(G, seed=123, weight=None) - - G.add_weighted_edges_from([(i, i, i * 1000) for i in range(3)]) - # large self-loop weight impacts partition - G_partition = nx.community.louvain_communities(G, seed=123, weight="weight") - assert G_partition != G_expected_partition - - # small self-loop weights aren't enough to impact partition in this graph - G_partition = nx.community.louvain_communities(G, seed=123, weight=None) - assert G_partition == G_expected_partition - - -def test_directed_partition(): - """ - Test 2 cases that were looping infinitely - from issues #5175 and #5704 - """ - G = nx.DiGraph() - H = nx.DiGraph() - G.add_nodes_from(range(10)) - H.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) - G_edges = [ - (0, 2), - (0, 1), - (1, 0), - (2, 1), - (2, 0), - (3, 4), - (4, 3), - (7, 8), - (8, 7), - (9, 10), - (10, 9), - ] - H_edges = [ - (1, 2), - (1, 6), - (1, 9), - (2, 3), - (2, 4), - (2, 5), - (3, 4), - (4, 3), - (4, 5), - (5, 4), - (6, 7), - (6, 8), - (9, 10), - (9, 11), - (10, 11), - (11, 10), - ] - G.add_edges_from(G_edges) - H.add_edges_from(H_edges) - - G_expected_partition = [{0, 1, 2}, {3, 4}, {5}, {6}, {8, 7}, {9, 10}] - G_partition = nx.community.louvain_communities(G, seed=123, weight=None) - - H_expected_partition = [{2, 3, 4, 5}, {8, 1, 6, 7}, {9, 10, 11}] - H_partition = nx.community.louvain_communities(H, seed=123, weight=None) - - assert G_partition == G_expected_partition - assert H_partition == H_expected_partition - - -def test_none_weight_param(): - G = nx.karate_club_graph() - nx.set_edge_attributes( - G, {edge: i * i for i, edge in enumerate(G.edges)}, name="foo" - ) - - part = [ - {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, - {16, 4, 5, 6, 10}, - {23, 25, 27, 28, 24, 31}, - {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, - ] - partition1 = nx.community.louvain_communities(G, weight=None, seed=2) - partition2 = nx.community.louvain_communities(G, weight="foo", seed=2) - partition3 = nx.community.louvain_communities(G, weight="weight", seed=2) - - assert part == partition1 - assert part != partition2 - assert part != partition3 - assert partition2 != partition3 - - -def test_quality(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - H = nx.gn_graph(200, seed=1234) - I = nx.MultiGraph(G) - J = nx.MultiDiGraph(H) - - partition = nx.community.louvain_communities(G) - partition2 = nx.community.louvain_communities(H) - partition3 = nx.community.louvain_communities(I) - partition4 = nx.community.louvain_communities(J) - - quality = nx.community.partition_quality(G, partition)[0] - quality2 = nx.community.partition_quality(H, partition2)[0] - quality3 = nx.community.partition_quality(I, partition3)[0] - quality4 = nx.community.partition_quality(J, partition4)[0] - - assert quality >= 0.65 - assert quality2 >= 0.65 - assert quality3 >= 0.65 - assert quality4 >= 0.65 - - -def test_multigraph(): - G = nx.karate_club_graph() - H = nx.MultiGraph(G) - G.add_edge(0, 1, weight=10) - H.add_edge(0, 1, weight=9) - G.add_edge(0, 9, foo=20) - H.add_edge(0, 9, foo=20) - - partition1 = nx.community.louvain_communities(G, seed=1234) - partition2 = nx.community.louvain_communities(H, seed=1234) - partition3 = nx.community.louvain_communities(H, weight="foo", seed=1234) - - assert partition1 == partition2 != partition3 - - -def test_resolution(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - - partition1 = nx.community.louvain_communities(G, resolution=0.5, seed=12) - partition2 = nx.community.louvain_communities(G, seed=12) - partition3 = nx.community.louvain_communities(G, resolution=2, seed=12) - - assert len(partition1) <= len(partition2) <= len(partition3) - - -def test_threshold(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - partition1 = nx.community.louvain_communities(G, threshold=0.3, seed=2) - partition2 = nx.community.louvain_communities(G, seed=2) - mod1 = nx.community.modularity(G, partition1) - mod2 = nx.community.modularity(G, partition2) - - assert mod1 <= mod2 - - -def test_empty_graph(): - G = nx.Graph() - G.add_nodes_from(range(5)) - expected = [{0}, {1}, {2}, {3}, {4}] - assert nx.community.louvain_communities(G) == expected - - -def test_max_level(): - G = nx.LFR_benchmark_graph( - 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 - ) - parts_iter = nx.community.louvain_partitions(G, seed=42) - for max_level, expected in enumerate(parts_iter, 1): - partition = nx.community.louvain_communities(G, max_level=max_level, seed=42) - assert partition == expected - assert max_level > 1 # Ensure we are actually testing max_level - # max_level is an upper limit; it's okay if we stop before it's hit. - partition = nx.community.louvain_communities(G, max_level=max_level + 1, seed=42) - assert partition == expected - with pytest.raises( - ValueError, match="max_level argument must be a positive integer" - ): - nx.community.louvain_communities(G, max_level=0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_lukes.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_lukes.py deleted file mode 100644 index cfa48f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_lukes.py +++ /dev/null @@ -1,152 +0,0 @@ -from itertools import product - -import pytest - -import networkx as nx - -EWL = "e_weight" -NWL = "n_weight" - - -# first test from the Lukes original paper -def paper_1_case(float_edge_wt=False, explicit_node_wt=True, directed=False): - # problem-specific constants - limit = 3 - - # configuration - if float_edge_wt: - shift = 0.001 - else: - shift = 0 - - if directed: - example_1 = nx.DiGraph() - else: - example_1 = nx.Graph() - - # graph creation - example_1.add_edge(1, 2, **{EWL: 3 + shift}) - example_1.add_edge(1, 4, **{EWL: 2 + shift}) - example_1.add_edge(2, 3, **{EWL: 4 + shift}) - example_1.add_edge(2, 5, **{EWL: 6 + shift}) - - # node weights - if explicit_node_wt: - nx.set_node_attributes(example_1, 1, NWL) - wtu = NWL - else: - wtu = None - - # partitioning - clusters_1 = { - frozenset(x) - for x in nx.community.lukes_partitioning( - example_1, limit, node_weight=wtu, edge_weight=EWL - ) - } - - return clusters_1 - - -# second test from the Lukes original paper -def paper_2_case(explicit_edge_wt=True, directed=False): - # problem specific constants - byte_block_size = 32 - - # configuration - if directed: - example_2 = nx.DiGraph() - else: - example_2 = nx.Graph() - - if explicit_edge_wt: - edic = {EWL: 1} - wtu = EWL - else: - edic = {} - wtu = None - - # graph creation - example_2.add_edge("name", "home_address", **edic) - example_2.add_edge("name", "education", **edic) - example_2.add_edge("education", "bs", **edic) - example_2.add_edge("education", "ms", **edic) - example_2.add_edge("education", "phd", **edic) - example_2.add_edge("name", "telephone", **edic) - example_2.add_edge("telephone", "home", **edic) - example_2.add_edge("telephone", "office", **edic) - example_2.add_edge("office", "no1", **edic) - example_2.add_edge("office", "no2", **edic) - - example_2.nodes["name"][NWL] = 20 - example_2.nodes["education"][NWL] = 10 - example_2.nodes["bs"][NWL] = 1 - example_2.nodes["ms"][NWL] = 1 - example_2.nodes["phd"][NWL] = 1 - example_2.nodes["home_address"][NWL] = 8 - example_2.nodes["telephone"][NWL] = 8 - example_2.nodes["home"][NWL] = 8 - example_2.nodes["office"][NWL] = 4 - example_2.nodes["no1"][NWL] = 1 - example_2.nodes["no2"][NWL] = 1 - - # partitioning - clusters_2 = { - frozenset(x) - for x in nx.community.lukes_partitioning( - example_2, byte_block_size, node_weight=NWL, edge_weight=wtu - ) - } - - return clusters_2 - - -def test_paper_1_case(): - ground_truth = {frozenset([1, 4]), frozenset([2, 3, 5])} - - tf = (True, False) - for flt, nwt, drc in product(tf, tf, tf): - part = paper_1_case(flt, nwt, drc) - assert part == ground_truth - - -def test_paper_2_case(): - ground_truth = { - frozenset(["education", "bs", "ms", "phd"]), - frozenset(["name", "home_address"]), - frozenset(["telephone", "home", "office", "no1", "no2"]), - } - - tf = (True, False) - for ewt, drc in product(tf, tf): - part = paper_2_case(ewt, drc) - assert part == ground_truth - - -def test_mandatory_tree(): - not_a_tree = nx.complete_graph(4) - - with pytest.raises(nx.NotATree): - nx.community.lukes_partitioning(not_a_tree, 5) - - -def test_mandatory_integrality(): - byte_block_size = 32 - - ex_1_broken = nx.DiGraph() - - ex_1_broken.add_edge(1, 2, **{EWL: 3.2}) - ex_1_broken.add_edge(1, 4, **{EWL: 2.4}) - ex_1_broken.add_edge(2, 3, **{EWL: 4.0}) - ex_1_broken.add_edge(2, 5, **{EWL: 6.3}) - - ex_1_broken.nodes[1][NWL] = 1.2 # ! - ex_1_broken.nodes[2][NWL] = 1 - ex_1_broken.nodes[3][NWL] = 1 - ex_1_broken.nodes[4][NWL] = 1 - ex_1_broken.nodes[5][NWL] = 2 - - with pytest.raises(TypeError): - nx.community.lukes_partitioning( - ex_1_broken, byte_block_size, node_weight=NWL, edge_weight=EWL - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_modularity_max.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_modularity_max.py deleted file mode 100644 index 0121367..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_modularity_max.py +++ /dev/null @@ -1,340 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.community import ( - greedy_modularity_communities, - naive_greedy_modularity_communities, -) - - -@pytest.mark.parametrize( - "func", (greedy_modularity_communities, naive_greedy_modularity_communities) -) -def test_modularity_communities(func): - G = nx.karate_club_graph() - john_a = frozenset( - [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] - ) - mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19]) - overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21]) - expected = {john_a, overlap, mr_hi} - assert set(func(G, weight=None)) == expected - - -@pytest.mark.parametrize( - "func", (greedy_modularity_communities, naive_greedy_modularity_communities) -) -def test_modularity_communities_categorical_labels(func): - # Using other than 0-starting contiguous integers as node-labels. - G = nx.Graph( - [ - ("a", "b"), - ("a", "c"), - ("b", "c"), - ("b", "d"), # inter-community edge - ("d", "e"), - ("d", "f"), - ("d", "g"), - ("f", "g"), - ("d", "e"), - ("f", "e"), - ] - ) - expected = {frozenset({"f", "g", "e", "d"}), frozenset({"a", "b", "c"})} - assert set(func(G)) == expected - - -def test_greedy_modularity_communities_components(): - # Test for gh-5530 - G = nx.Graph([(0, 1), (2, 3), (4, 5), (5, 6)]) - # usual case with 3 components - assert greedy_modularity_communities(G) == [{4, 5, 6}, {0, 1}, {2, 3}] - # best_n can make the algorithm continue even when modularity goes down - assert greedy_modularity_communities(G, best_n=3) == [{4, 5, 6}, {0, 1}, {2, 3}] - assert greedy_modularity_communities(G, best_n=2) == [{0, 1, 4, 5, 6}, {2, 3}] - assert greedy_modularity_communities(G, best_n=1) == [{0, 1, 2, 3, 4, 5, 6}] - - -def test_greedy_modularity_communities_relabeled(): - # Test for gh-4966 - G = nx.balanced_tree(2, 2) - mapping = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h"} - G = nx.relabel_nodes(G, mapping) - expected = [frozenset({"e", "d", "a", "b"}), frozenset({"c", "f", "g"})] - assert greedy_modularity_communities(G) == expected - - -def test_greedy_modularity_communities_directed(): - G = nx.DiGraph( - [ - ("a", "b"), - ("a", "c"), - ("b", "c"), - ("b", "d"), # inter-community edge - ("d", "e"), - ("d", "f"), - ("d", "g"), - ("f", "g"), - ("d", "e"), - ("f", "e"), - ] - ) - expected = [frozenset({"f", "g", "e", "d"}), frozenset({"a", "b", "c"})] - assert greedy_modularity_communities(G) == expected - - # with loops - G = nx.DiGraph() - G.add_edges_from( - [(1, 1), (1, 2), (1, 3), (2, 3), (1, 4), (4, 4), (5, 5), (4, 5), (4, 6), (5, 6)] - ) - expected = [frozenset({1, 2, 3}), frozenset({4, 5, 6})] - assert greedy_modularity_communities(G) == expected - - -@pytest.mark.parametrize( - "func", (greedy_modularity_communities, naive_greedy_modularity_communities) -) -def test_modularity_communities_weighted(func): - G = nx.balanced_tree(2, 3) - for a, b in G.edges: - if ((a == 1) or (a == 2)) and (b != 0): - G[a][b]["weight"] = 10.0 - else: - G[a][b]["weight"] = 1.0 - - expected = [{0, 1, 3, 4, 7, 8, 9, 10}, {2, 5, 6, 11, 12, 13, 14}] - - assert func(G, weight="weight") == expected - assert func(G, weight="weight", resolution=0.9) == expected - assert func(G, weight="weight", resolution=0.3) == expected - assert func(G, weight="weight", resolution=1.1) != expected - - -def test_modularity_communities_floating_point(): - # check for floating point error when used as key in the mapped_queue dict. - # Test for gh-4992 and gh-5000 - G = nx.Graph() - G.add_weighted_edges_from( - [(0, 1, 12), (1, 4, 71), (2, 3, 15), (2, 4, 10), (3, 6, 13)] - ) - expected = [{0, 1, 4}, {2, 3, 6}] - assert greedy_modularity_communities(G, weight="weight") == expected - assert ( - greedy_modularity_communities(G, weight="weight", resolution=0.99) == expected - ) - - -def test_modularity_communities_directed_weighted(): - G = nx.DiGraph() - G.add_weighted_edges_from( - [ - (1, 2, 5), - (1, 3, 3), - (2, 3, 6), - (2, 6, 1), - (1, 4, 1), - (4, 5, 3), - (4, 6, 7), - (5, 6, 2), - (5, 7, 5), - (5, 8, 4), - (6, 8, 3), - ] - ) - expected = [frozenset({4, 5, 6, 7, 8}), frozenset({1, 2, 3})] - assert greedy_modularity_communities(G, weight="weight") == expected - - # A large weight of the edge (2, 6) causes 6 to change group, even if it shares - # only one connection with the new group and 3 with the old one. - G[2][6]["weight"] = 20 - expected = [frozenset({1, 2, 3, 6}), frozenset({4, 5, 7, 8})] - assert greedy_modularity_communities(G, weight="weight") == expected - - -def test_greedy_modularity_communities_multigraph(): - G = nx.MultiGraph() - G.add_edges_from( - [ - (1, 2), - (1, 2), - (1, 3), - (2, 3), - (1, 4), - (2, 4), - (4, 5), - (5, 6), - (5, 7), - (5, 7), - (6, 7), - (7, 8), - (5, 8), - ] - ) - expected = [frozenset({1, 2, 3, 4}), frozenset({5, 6, 7, 8})] - assert greedy_modularity_communities(G) == expected - - # Converting (4, 5) into a multi-edge causes node 4 to change group. - G.add_edge(4, 5) - expected = [frozenset({4, 5, 6, 7, 8}), frozenset({1, 2, 3})] - assert greedy_modularity_communities(G) == expected - - -def test_greedy_modularity_communities_multigraph_weighted(): - G = nx.MultiGraph() - G.add_weighted_edges_from( - [ - (1, 2, 5), - (1, 2, 3), - (1, 3, 6), - (1, 3, 6), - (2, 3, 4), - (1, 4, 1), - (1, 4, 1), - (2, 4, 3), - (2, 4, 3), - (4, 5, 1), - (5, 6, 3), - (5, 6, 7), - (5, 6, 4), - (5, 7, 9), - (5, 7, 9), - (6, 7, 8), - (7, 8, 2), - (7, 8, 2), - (5, 8, 6), - (5, 8, 6), - ] - ) - expected = [frozenset({1, 2, 3, 4}), frozenset({5, 6, 7, 8})] - assert greedy_modularity_communities(G, weight="weight") == expected - - # Adding multi-edge (4, 5, 16) causes node 4 to change group. - G.add_edge(4, 5, weight=16) - expected = [frozenset({4, 5, 6, 7, 8}), frozenset({1, 2, 3})] - assert greedy_modularity_communities(G, weight="weight") == expected - - # Increasing the weight of edge (1, 4) causes node 4 to return to the former group. - G[1][4][1]["weight"] = 3 - expected = [frozenset({1, 2, 3, 4}), frozenset({5, 6, 7, 8})] - assert greedy_modularity_communities(G, weight="weight") == expected - - -def test_greed_modularity_communities_multidigraph(): - G = nx.MultiDiGraph() - G.add_edges_from( - [ - (1, 2), - (1, 2), - (3, 1), - (2, 3), - (2, 3), - (3, 2), - (1, 4), - (2, 4), - (4, 2), - (4, 5), - (5, 6), - (5, 6), - (6, 5), - (5, 7), - (6, 7), - (7, 8), - (5, 8), - (8, 4), - ] - ) - expected = [frozenset({1, 2, 3, 4}), frozenset({5, 6, 7, 8})] - assert greedy_modularity_communities(G, weight="weight") == expected - - -def test_greed_modularity_communities_multidigraph_weighted(): - G = nx.MultiDiGraph() - G.add_weighted_edges_from( - [ - (1, 2, 5), - (1, 2, 3), - (3, 1, 6), - (1, 3, 6), - (3, 2, 4), - (1, 4, 2), - (1, 4, 5), - (2, 4, 3), - (3, 2, 8), - (4, 2, 3), - (4, 3, 5), - (4, 5, 2), - (5, 6, 3), - (5, 6, 7), - (6, 5, 4), - (5, 7, 9), - (5, 7, 9), - (7, 6, 8), - (7, 8, 2), - (8, 7, 2), - (5, 8, 6), - (5, 8, 6), - ] - ) - expected = [frozenset({1, 2, 3, 4}), frozenset({5, 6, 7, 8})] - assert greedy_modularity_communities(G, weight="weight") == expected - - -def test_resolution_parameter_impact(): - G = nx.barbell_graph(5, 3) - - gamma = 1 - expected = [frozenset(range(5)), frozenset(range(8, 13)), frozenset(range(5, 8))] - assert greedy_modularity_communities(G, resolution=gamma) == expected - assert naive_greedy_modularity_communities(G, resolution=gamma) == expected - - gamma = 2.5 - expected = [{0, 1, 2, 3}, {9, 10, 11, 12}, {5, 6, 7}, {4}, {8}] - assert greedy_modularity_communities(G, resolution=gamma) == expected - assert naive_greedy_modularity_communities(G, resolution=gamma) == expected - - gamma = 0.3 - expected = [frozenset(range(8)), frozenset(range(8, 13))] - assert greedy_modularity_communities(G, resolution=gamma) == expected - assert naive_greedy_modularity_communities(G, resolution=gamma) == expected - - -def test_cutoff_parameter(): - G = nx.circular_ladder_graph(4) - - # No aggregation: - expected = [{k} for k in range(8)] - assert greedy_modularity_communities(G, cutoff=8) == expected - - # Aggregation to half order (number of nodes) - expected = [{k, k + 1} for k in range(0, 8, 2)] - assert greedy_modularity_communities(G, cutoff=4) == expected - - # Default aggregation case (here, 2 communities emerge) - expected = [frozenset(range(4)), frozenset(range(4, 8))] - assert greedy_modularity_communities(G, cutoff=1) == expected - - -def test_best_n(): - G = nx.barbell_graph(5, 3) - - # Same result as without enforcing cutoff: - best_n = 3 - expected = [frozenset(range(5)), frozenset(range(8, 13)), frozenset(range(5, 8))] - assert greedy_modularity_communities(G, best_n=best_n) == expected - - # One additional merging step: - best_n = 2 - expected = [frozenset(range(8)), frozenset(range(8, 13))] - assert greedy_modularity_communities(G, best_n=best_n) == expected - - # Two additional merging steps: - best_n = 1 - expected = [frozenset(range(13))] - assert greedy_modularity_communities(G, best_n=best_n) == expected - - -def test_greedy_modularity_communities_corner_cases(): - G = nx.empty_graph() - assert nx.community.greedy_modularity_communities(G) == [] - G.add_nodes_from(range(3)) - assert nx.community.greedy_modularity_communities(G) == [{0}, {1}, {2}] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_quality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_quality.py deleted file mode 100644 index c502c7e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_quality.py +++ /dev/null @@ -1,139 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.community.quality` -module. - -""" - -import pytest - -import networkx as nx -from networkx import barbell_graph -from networkx.algorithms.community import modularity, partition_quality -from networkx.algorithms.community.quality import inter_community_edges - - -class TestPerformance: - """Unit tests for the :func:`performance` function.""" - - def test_bad_partition(self): - """Tests that a poor partition has a low performance measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 4}, {2, 3, 5}] - assert 8 / 15 == pytest.approx(partition_quality(G, partition)[1], abs=1e-7) - - def test_good_partition(self): - """Tests that a good partition has a high performance measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - assert 14 / 15 == pytest.approx(partition_quality(G, partition)[1], abs=1e-7) - - -class TestCoverage: - """Unit tests for the :func:`coverage` function.""" - - def test_bad_partition(self): - """Tests that a poor partition has a low coverage measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 4}, {2, 3, 5}] - assert 3 / 7 == pytest.approx(partition_quality(G, partition)[0], abs=1e-7) - - def test_good_partition(self): - """Tests that a good partition has a high coverage measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - assert 6 / 7 == pytest.approx(partition_quality(G, partition)[0], abs=1e-7) - - -def test_modularity(): - G = nx.barbell_graph(3, 0) - C = [{0, 1, 4}, {2, 3, 5}] - assert (-16 / (14**2)) == pytest.approx(modularity(G, C), abs=1e-7) - C = [{0, 1, 2}, {3, 4, 5}] - assert (35 * 2) / (14**2) == pytest.approx(modularity(G, C), abs=1e-7) - - n = 1000 - G = nx.erdos_renyi_graph(n, 0.09, seed=42, directed=True) - C = [set(range(n // 2)), set(range(n // 2, n))] - assert 0.00017154251389292754 == pytest.approx(modularity(G, C), abs=1e-7) - - G = nx.margulis_gabber_galil_graph(10) - mid_value = G.number_of_nodes() // 2 - nodes = list(G.nodes) - C = [set(nodes[:mid_value]), set(nodes[mid_value:])] - assert 0.13 == pytest.approx(modularity(G, C), abs=1e-7) - - G = nx.DiGraph() - G.add_edges_from([(2, 1), (2, 3), (3, 4)]) - C = [{1, 2}, {3, 4}] - assert 2 / 9 == pytest.approx(modularity(G, C), abs=1e-7) - - -def test_modularity_resolution(): - G = nx.barbell_graph(3, 0) - C = [{0, 1, 4}, {2, 3, 5}] - assert modularity(G, C) == pytest.approx(3 / 7 - 100 / 14**2) - gamma = 2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx(3 / 7 - gamma * 100 / 14**2) - gamma = 0.2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx(3 / 7 - gamma * 100 / 14**2) - - C = [{0, 1, 2}, {3, 4, 5}] - assert modularity(G, C) == pytest.approx(6 / 7 - 98 / 14**2) - gamma = 2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx(6 / 7 - gamma * 98 / 14**2) - gamma = 0.2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx(6 / 7 - gamma * 98 / 14**2) - - G = nx.barbell_graph(5, 3) - C = [frozenset(range(5)), frozenset(range(8, 13)), frozenset(range(5, 8))] - gamma = 1 - result = modularity(G, C, resolution=gamma) - # This C is maximal for gamma=1: modularity = 0.518229 - assert result == pytest.approx((22 / 24) - gamma * (918 / (48**2))) - gamma = 2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((22 / 24) - gamma * (918 / (48**2))) - gamma = 0.2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((22 / 24) - gamma * (918 / (48**2))) - - C = [{0, 1, 2, 3}, {9, 10, 11, 12}, {5, 6, 7}, {4}, {8}] - gamma = 1 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((14 / 24) - gamma * (598 / (48**2))) - gamma = 2.5 - result = modularity(G, C, resolution=gamma) - # This C is maximal for gamma=2.5: modularity = -0.06553819 - assert result == pytest.approx((14 / 24) - gamma * (598 / (48**2))) - gamma = 0.2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((14 / 24) - gamma * (598 / (48**2))) - - C = [frozenset(range(8)), frozenset(range(8, 13))] - gamma = 1 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((23 / 24) - gamma * (1170 / (48**2))) - gamma = 2 - result = modularity(G, C, resolution=gamma) - assert result == pytest.approx((23 / 24) - gamma * (1170 / (48**2))) - gamma = 0.3 - result = modularity(G, C, resolution=gamma) - # This C is maximal for gamma=0.3: modularity = 0.805990 - assert result == pytest.approx((23 / 24) - gamma * (1170 / (48**2))) - - -def test_inter_community_edges_with_digraphs(): - G = nx.complete_graph(2, create_using=nx.DiGraph()) - partition = [{0}, {1}] - assert inter_community_edges(G, partition) == 2 - - G = nx.complete_graph(10, create_using=nx.DiGraph()) - partition = [{0}, {1, 2}, {3, 4, 5}, {6, 7, 8, 9}] - assert inter_community_edges(G, partition) == 70 - - G = nx.cycle_graph(4, create_using=nx.DiGraph()) - partition = [{0, 1}, {2, 3}] - assert inter_community_edges(G, partition) == 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_utils.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_utils.py deleted file mode 100644 index ea019db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/community/tests/test_utils.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.community.utils` module.""" - -import networkx as nx - - -def test_is_partition(): - G = nx.empty_graph(3) - assert nx.community.is_partition(G, [{0, 1}, {2}]) - assert nx.community.is_partition(G, ({0, 1}, {2})) - assert nx.community.is_partition(G, ([0, 1], [2])) - assert nx.community.is_partition(G, [[0, 1], [2]]) - - -def test_not_covering(): - G = nx.empty_graph(3) - assert not nx.community.is_partition(G, [{0}, {1}]) - - -def test_not_disjoint(): - G = nx.empty_graph(3) - assert not nx.community.is_partition(G, [{0, 1}, {1, 2}]) - - -def test_not_node(): - G = nx.empty_graph(3) - assert not nx.community.is_partition(G, [{0, 1}, {3}]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/__init__.py deleted file mode 100644 index f9ae2ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .connected import * -from .strongly_connected import * -from .weakly_connected import * -from .attracting import * -from .biconnected import * -from .semiconnected import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/attracting.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/attracting.py deleted file mode 100644 index 3d77cd9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/attracting.py +++ /dev/null @@ -1,115 +0,0 @@ -"""Attracting components.""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - "number_attracting_components", - "attracting_components", - "is_attracting_component", -] - - -@not_implemented_for("undirected") -@nx._dispatchable -def attracting_components(G): - """Generates the attracting components in `G`. - - An attracting component in a directed graph `G` is a strongly connected - component with the property that a random walker on the graph will never - leave the component, once it enters the component. - - The nodes in attracting components can also be thought of as recurrent - nodes. If a random walker enters the attractor containing the node, then - the node will be visited infinitely often. - - To obtain induced subgraphs on each component use: - ``(G.subgraph(c).copy() for c in attracting_components(G))`` - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - attractors : generator of sets - A generator of sets of nodes, one for each attracting component of G. - - Raises - ------ - NetworkXNotImplemented - If the input graph is undirected. - - See Also - -------- - number_attracting_components - is_attracting_component - - """ - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - for n in cG: - if cG.out_degree(n) == 0: - yield scc[n] - - -@not_implemented_for("undirected") -@nx._dispatchable -def number_attracting_components(G): - """Returns the number of attracting components in `G`. - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - n : int - The number of attracting components in G. - - Raises - ------ - NetworkXNotImplemented - If the input graph is undirected. - - See Also - -------- - attracting_components - is_attracting_component - - """ - return sum(1 for ac in attracting_components(G)) - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_attracting_component(G): - """Returns True if `G` consists of a single attracting component. - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - attracting : bool - True if `G` has a single attracting component. Otherwise, False. - - Raises - ------ - NetworkXNotImplemented - If the input graph is undirected. - - See Also - -------- - attracting_components - number_attracting_components - - """ - ac = list(attracting_components(G)) - if len(ac) == 1: - return len(ac[0]) == len(G) - return False diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/biconnected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/biconnected.py deleted file mode 100644 index fd0f386..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/biconnected.py +++ /dev/null @@ -1,394 +0,0 @@ -"""Biconnected components and articulation points.""" - -from itertools import chain - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - "biconnected_components", - "biconnected_component_edges", - "is_biconnected", - "articulation_points", -] - - -@not_implemented_for("directed") -@nx._dispatchable -def is_biconnected(G): - """Returns True if the graph is biconnected, False otherwise. - - A graph is biconnected if, and only if, it cannot be disconnected by - removing only one node (and all edges incident on that node). If - removing a node increases the number of disconnected components - in the graph, that node is called an articulation point, or cut - vertex. A biconnected graph has no articulation points. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - biconnected : bool - True if the graph is biconnected, False otherwise. - - Raises - ------ - NetworkXNotImplemented - If the input graph is not undirected. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> print(nx.is_biconnected(G)) - False - >>> G.add_edge(0, 3) - >>> print(nx.is_biconnected(G)) - True - - See Also - -------- - biconnected_components - articulation_points - biconnected_component_edges - is_strongly_connected - is_weakly_connected - is_connected - is_semiconnected - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - bccs = biconnected_components(G) - try: - bcc = next(bccs) - except StopIteration: - # No bicomponents (empty graph?) - return False - try: - next(bccs) - except StopIteration: - # Only one bicomponent - return len(bcc) == len(G) - else: - # Multiple bicomponents - return False - - -@not_implemented_for("directed") -@nx._dispatchable -def biconnected_component_edges(G): - """Returns a generator of lists of edges, one list for each biconnected - component of the input graph. - - Biconnected components are maximal subgraphs such that the removal of a - node (and all edges incident on that node) will not disconnect the - subgraph. Note that nodes may be part of more than one biconnected - component. Those nodes are articulation points, or cut vertices. - However, each edge belongs to one, and only one, biconnected component. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - edges : generator of lists - Generator of lists of edges, one list for each bicomponent. - - Raises - ------ - NetworkXNotImplemented - If the input graph is not undirected. - - Examples - -------- - >>> G = nx.barbell_graph(4, 2) - >>> print(nx.is_biconnected(G)) - False - >>> bicomponents_edges = list(nx.biconnected_component_edges(G)) - >>> len(bicomponents_edges) - 5 - >>> G.add_edge(2, 8) - >>> print(nx.is_biconnected(G)) - True - >>> bicomponents_edges = list(nx.biconnected_component_edges(G)) - >>> len(bicomponents_edges) - 1 - - See Also - -------- - is_biconnected, - biconnected_components, - articulation_points, - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - yield from _biconnected_dfs(G, components=True) - - -@not_implemented_for("directed") -@nx._dispatchable -def biconnected_components(G): - """Returns a generator of sets of nodes, one set for each biconnected - component of the graph - - Biconnected components are maximal subgraphs such that the removal of a - node (and all edges incident on that node) will not disconnect the - subgraph. Note that nodes may be part of more than one biconnected - component. Those nodes are articulation points, or cut vertices. The - removal of articulation points will increase the number of connected - components of the graph. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - nodes : generator - Generator of sets of nodes, one set for each biconnected component. - - Raises - ------ - NetworkXNotImplemented - If the input graph is not undirected. - - Examples - -------- - >>> G = nx.lollipop_graph(5, 1) - >>> print(nx.is_biconnected(G)) - False - >>> bicomponents = list(nx.biconnected_components(G)) - >>> len(bicomponents) - 2 - >>> G.add_edge(0, 5) - >>> print(nx.is_biconnected(G)) - True - >>> bicomponents = list(nx.biconnected_components(G)) - >>> len(bicomponents) - 1 - - You can generate a sorted list of biconnected components, largest - first, using sort. - - >>> G.remove_edge(0, 5) - >>> [len(c) for c in sorted(nx.biconnected_components(G), key=len, reverse=True)] - [5, 2] - - If you only want the largest connected component, it's more - efficient to use max instead of sort. - - >>> Gc = max(nx.biconnected_components(G), key=len) - - To create the components as subgraphs use: - ``(G.subgraph(c).copy() for c in biconnected_components(G))`` - - See Also - -------- - is_biconnected - articulation_points - biconnected_component_edges - k_components : this function is a special case where k=2 - bridge_components : similar to this function, but is defined using - 2-edge-connectivity instead of 2-node-connectivity. - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - for comp in _biconnected_dfs(G, components=True): - yield set(chain.from_iterable(comp)) - - -@not_implemented_for("directed") -@nx._dispatchable -def articulation_points(G): - """Yield the articulation points, or cut vertices, of a graph. - - An articulation point or cut vertex is any node whose removal (along with - all its incident edges) increases the number of connected components of - a graph. An undirected connected graph without articulation points is - biconnected. Articulation points belong to more than one biconnected - component of a graph. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Yields - ------ - node - An articulation point in the graph. - - Raises - ------ - NetworkXNotImplemented - If the input graph is not undirected. - - Examples - -------- - - >>> G = nx.barbell_graph(4, 2) - >>> print(nx.is_biconnected(G)) - False - >>> len(list(nx.articulation_points(G))) - 4 - >>> G.add_edge(2, 8) - >>> print(nx.is_biconnected(G)) - True - >>> len(list(nx.articulation_points(G))) - 0 - - See Also - -------- - is_biconnected - biconnected_components - biconnected_component_edges - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - seen = set() - for articulation in _biconnected_dfs(G, components=False): - if articulation not in seen: - seen.add(articulation) - yield articulation - - -@not_implemented_for("directed") -def _biconnected_dfs(G, components=True): - # depth-first search algorithm to generate articulation points - # and biconnected components - visited = set() - for start in G: - if start in visited: - continue - discovery = {start: 0} # time of first discovery of node during search - low = {start: 0} - root_children = 0 - visited.add(start) - edge_stack = [] - stack = [(start, start, iter(G[start]))] - edge_index = {} - while stack: - grandparent, parent, children = stack[-1] - try: - child = next(children) - if grandparent == child: - continue - if child in visited: - if discovery[child] <= discovery[parent]: # back edge - low[parent] = min(low[parent], discovery[child]) - if components: - edge_index[parent, child] = len(edge_stack) - edge_stack.append((parent, child)) - else: - low[child] = discovery[child] = len(discovery) - visited.add(child) - stack.append((parent, child, iter(G[child]))) - if components: - edge_index[parent, child] = len(edge_stack) - edge_stack.append((parent, child)) - - except StopIteration: - stack.pop() - if len(stack) > 1: - if low[parent] >= discovery[grandparent]: - if components: - ind = edge_index[grandparent, parent] - yield edge_stack[ind:] - del edge_stack[ind:] - - else: - yield grandparent - low[grandparent] = min(low[parent], low[grandparent]) - elif stack: # length 1 so grandparent is root - root_children += 1 - if components: - ind = edge_index[grandparent, parent] - yield edge_stack[ind:] - del edge_stack[ind:] - if not components: - # root node is articulation point if it has more than 1 child - if root_children > 1: - yield start diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/connected.py deleted file mode 100644 index ebe0d8c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/connected.py +++ /dev/null @@ -1,216 +0,0 @@ -"""Connected components.""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -from ...utils import arbitrary_element - -__all__ = [ - "number_connected_components", - "connected_components", - "is_connected", - "node_connected_component", -] - - -@not_implemented_for("directed") -@nx._dispatchable -def connected_components(G): - """Generate connected components. - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each component of G. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Examples - -------- - Generate a sorted list of connected components, largest first. - - >>> G = nx.path_graph(4) - >>> nx.add_path(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)] - [4, 3] - - If you only want the largest connected component, it's more - efficient to use max instead of sort. - - >>> largest_cc = max(nx.connected_components(G), key=len) - - To create the induced subgraph of each component use: - - >>> S = [G.subgraph(c).copy() for c in nx.connected_components(G)] - - See Also - -------- - strongly_connected_components - weakly_connected_components - - Notes - ----- - For undirected graphs only. - - """ - seen = set() - n = len(G) - for v in G: - if v not in seen: - c = _plain_bfs(G, n, v) - seen.update(c) - yield c - - -@not_implemented_for("directed") -@nx._dispatchable -def number_connected_components(G): - """Returns the number of connected components. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - n : integer - Number of connected components - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)]) - >>> nx.number_connected_components(G) - 3 - - See Also - -------- - connected_components - number_weakly_connected_components - number_strongly_connected_components - - Notes - ----- - For undirected graphs only. - - """ - return sum(1 for cc in connected_components(G)) - - -@not_implemented_for("directed") -@nx._dispatchable -def is_connected(G): - """Returns True if the graph is connected, False otherwise. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - connected : bool - True if the graph is connected, false otherwise. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> print(nx.is_connected(G)) - True - - See Also - -------- - is_strongly_connected - is_weakly_connected - is_semiconnected - is_biconnected - connected_components - - Notes - ----- - For undirected graphs only. - - """ - n = len(G) - if n == 0: - raise nx.NetworkXPointlessConcept( - "Connectivity is undefined for the null graph." - ) - return sum(1 for node in _plain_bfs(G, n, arbitrary_element(G))) == len(G) - - -@not_implemented_for("directed") -@nx._dispatchable -def node_connected_component(G, n): - """Returns the set of nodes in the component of graph containing node n. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - n : node label - A node in G - - Returns - ------- - comp : set - A set of nodes in the component of G containing node n. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)]) - >>> nx.node_connected_component(G, 0) # nodes of component that contains node 0 - {0, 1, 2} - - See Also - -------- - connected_components - - Notes - ----- - For undirected graphs only. - - """ - return _plain_bfs(G, len(G), n) - - -def _plain_bfs(G, n, source): - """A fast BFS node generator""" - adj = G._adj - seen = {source} - nextlevel = [source] - while nextlevel: - thislevel = nextlevel - nextlevel = [] - for v in thislevel: - for w in adj[v]: - if w not in seen: - seen.add(w) - nextlevel.append(w) - if len(seen) == n: - return seen - return seen diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/semiconnected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/semiconnected.py deleted file mode 100644 index 9ca5d76..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/semiconnected.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Semiconnectedness.""" - -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = ["is_semiconnected"] - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_semiconnected(G): - r"""Returns True if the graph is semiconnected, False otherwise. - - A graph is semiconnected if and only if for any pair of nodes, either one - is reachable from the other, or they are mutually reachable. - - This function uses a theorem that states that a DAG is semiconnected - if for any topological sort, for node $v_n$ in that sort, there is an - edge $(v_i, v_{i+1})$. That allows us to check if a non-DAG `G` is - semiconnected by condensing the graph: i.e. constructing a new graph `H` - with nodes being the strongly connected components of `G`, and edges - (scc_1, scc_2) if there is a edge $(v_1, v_2)$ in `G` for some - $v_1 \in scc_1$ and $v_2 \in scc_2$. That results in a DAG, so we compute - the topological sort of `H` and check if for every $n$ there is an edge - $(scc_n, scc_{n+1})$. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - Returns - ------- - semiconnected : bool - True if the graph is semiconnected, False otherwise. - - Raises - ------ - NetworkXNotImplemented - If the input graph is undirected. - - NetworkXPointlessConcept - If the graph is empty. - - Examples - -------- - >>> G = nx.path_graph(4, create_using=nx.DiGraph()) - >>> print(nx.is_semiconnected(G)) - True - >>> G = nx.DiGraph([(1, 2), (3, 2)]) - >>> print(nx.is_semiconnected(G)) - False - - See Also - -------- - is_strongly_connected - is_weakly_connected - is_connected - is_biconnected - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - "Connectivity is undefined for the null graph." - ) - - if not nx.is_weakly_connected(G): - return False - - H = nx.condensation(G) - - return all(H.has_edge(u, v) for u, v in pairwise(nx.topological_sort(H))) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/strongly_connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/strongly_connected.py deleted file mode 100644 index 393728f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/strongly_connected.py +++ /dev/null @@ -1,351 +0,0 @@ -"""Strongly connected components.""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - "number_strongly_connected_components", - "strongly_connected_components", - "is_strongly_connected", - "kosaraju_strongly_connected_components", - "condensation", -] - - -@not_implemented_for("undirected") -@nx._dispatchable -def strongly_connected_components(G): - """Generate nodes in strongly connected components of graph. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each strongly connected - component of G. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - Generate a sorted list of strongly connected components, largest first. - - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph()) - >>> nx.add_cycle(G, [10, 11, 12]) - >>> [ - ... len(c) - ... for c in sorted(nx.strongly_connected_components(G), key=len, reverse=True) - ... ] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort. - - >>> largest = max(nx.strongly_connected_components(G), key=len) - - See Also - -------- - connected_components - weakly_connected_components - kosaraju_strongly_connected_components - - Notes - ----- - Uses Tarjan's algorithm[1]_ with Nuutila's modifications[2]_. - Nonrecursive version of algorithm. - - References - ---------- - .. [1] Depth-first search and linear graph algorithms, R. Tarjan - SIAM Journal of Computing 1(2):146-160, (1972). - - .. [2] On finding the strongly connected components in a directed graph. - E. Nuutila and E. Soisalon-Soinen - Information Processing Letters 49(1): 9-14, (1994).. - - """ - preorder = {} - lowlink = {} - scc_found = set() - scc_queue = [] - i = 0 # Preorder counter - neighbors = {v: iter(G[v]) for v in G} - for source in G: - if source not in scc_found: - queue = [source] - while queue: - v = queue[-1] - if v not in preorder: - i = i + 1 - preorder[v] = i - done = True - for w in neighbors[v]: - if w not in preorder: - queue.append(w) - done = False - break - if done: - lowlink[v] = preorder[v] - for w in G[v]: - if w not in scc_found: - if preorder[w] > preorder[v]: - lowlink[v] = min([lowlink[v], lowlink[w]]) - else: - lowlink[v] = min([lowlink[v], preorder[w]]) - queue.pop() - if lowlink[v] == preorder[v]: - scc = {v} - while scc_queue and preorder[scc_queue[-1]] > preorder[v]: - k = scc_queue.pop() - scc.add(k) - scc_found.update(scc) - yield scc - else: - scc_queue.append(v) - - -@not_implemented_for("undirected") -@nx._dispatchable -def kosaraju_strongly_connected_components(G, source=None): - """Generate nodes in strongly connected components of graph. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each strongly connected - component of G. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - Generate a sorted list of strongly connected components, largest first. - - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph()) - >>> nx.add_cycle(G, [10, 11, 12]) - >>> [ - ... len(c) - ... for c in sorted( - ... nx.kosaraju_strongly_connected_components(G), key=len, reverse=True - ... ) - ... ] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort. - - >>> largest = max(nx.kosaraju_strongly_connected_components(G), key=len) - - See Also - -------- - strongly_connected_components - - Notes - ----- - Uses Kosaraju's algorithm. - - """ - post = list(nx.dfs_postorder_nodes(G.reverse(copy=False), source=source)) - - seen = set() - while post: - r = post.pop() - if r in seen: - continue - c = nx.dfs_preorder_nodes(G, r) - new = {v for v in c if v not in seen} - seen.update(new) - yield new - - -@not_implemented_for("undirected") -@nx._dispatchable -def number_strongly_connected_components(G): - """Returns number of strongly connected components in graph. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - Returns - ------- - n : integer - Number of strongly connected components - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - >>> G = nx.DiGraph( - ... [(0, 1), (1, 2), (2, 0), (2, 3), (4, 5), (3, 4), (5, 6), (6, 3), (6, 7)] - ... ) - >>> nx.number_strongly_connected_components(G) - 3 - - See Also - -------- - strongly_connected_components - number_connected_components - number_weakly_connected_components - - Notes - ----- - For directed graphs only. - """ - return sum(1 for scc in strongly_connected_components(G)) - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_strongly_connected(G): - """Test directed graph for strong connectivity. - - A directed graph is strongly connected if and only if every vertex in - the graph is reachable from every other vertex. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - connected : bool - True if the graph is strongly connected, False otherwise. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4), (4, 2)]) - >>> nx.is_strongly_connected(G) - True - >>> G.remove_edge(2, 3) - >>> nx.is_strongly_connected(G) - False - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - See Also - -------- - is_weakly_connected - is_semiconnected - is_connected - is_biconnected - strongly_connected_components - - Notes - ----- - For directed graphs only. - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - """Connectivity is undefined for the null graph.""" - ) - - return len(next(strongly_connected_components(G))) == len(G) - - -@not_implemented_for("undirected") -@nx._dispatchable(returns_graph=True) -def condensation(G, scc=None): - """Returns the condensation of G. - - The condensation of G is the graph with each of the strongly connected - components contracted into a single node. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph. - - scc: list or generator (optional, default=None) - Strongly connected components. If provided, the elements in - `scc` must partition the nodes in `G`. If not provided, it will be - calculated as scc=nx.strongly_connected_components(G). - - Returns - ------- - C : NetworkX DiGraph - The condensation graph C of G. The node labels are integers - corresponding to the index of the component in the list of - strongly connected components of G. C has a graph attribute named - 'mapping' with a dictionary mapping the original nodes to the - nodes in C to which they belong. Each node in C also has a node - attribute 'members' with the set of original nodes in G that - form the SCC that the node in C represents. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - Contracting two sets of strongly connected nodes into two distinct SCC - using the barbell graph. - - >>> G = nx.barbell_graph(4, 0) - >>> G.remove_edge(3, 4) - >>> G = nx.DiGraph(G) - >>> H = nx.condensation(G) - >>> H.nodes.data() - NodeDataView({0: {'members': {0, 1, 2, 3}}, 1: {'members': {4, 5, 6, 7}}}) - >>> H.graph["mapping"] - {0: 0, 1: 0, 2: 0, 3: 0, 4: 1, 5: 1, 6: 1, 7: 1} - - Contracting a complete graph into one single SCC. - - >>> G = nx.complete_graph(7, create_using=nx.DiGraph) - >>> H = nx.condensation(G) - >>> H.nodes - NodeView((0,)) - >>> H.nodes.data() - NodeDataView({0: {'members': {0, 1, 2, 3, 4, 5, 6}}}) - - Notes - ----- - After contracting all strongly connected components to a single node, - the resulting graph is a directed acyclic graph. - - """ - if scc is None: - scc = nx.strongly_connected_components(G) - mapping = {} - members = {} - C = nx.DiGraph() - # Add mapping dict as graph attribute - C.graph["mapping"] = mapping - if len(G) == 0: - return C - for i, component in enumerate(scc): - members[i] = component - mapping.update((n, i) for n in component) - number_of_components = i + 1 - C.add_nodes_from(range(number_of_components)) - C.add_edges_from( - (mapping[u], mapping[v]) for u, v in G.edges() if mapping[u] != mapping[v] - ) - # Add a list of members (ie original nodes) to each node (ie scc) in C. - nx.set_node_attributes(C, members, "members") - return C diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_attracting.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_attracting.py deleted file mode 100644 index 336c40d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_attracting.py +++ /dev/null @@ -1,70 +0,0 @@ -import pytest - -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestAttractingComponents: - @classmethod - def setup_class(cls): - cls.G1 = nx.DiGraph() - cls.G1.add_edges_from( - [ - (5, 11), - (11, 2), - (11, 9), - (11, 10), - (7, 11), - (7, 8), - (8, 9), - (3, 8), - (3, 10), - ] - ) - cls.G2 = nx.DiGraph() - cls.G2.add_edges_from([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1)]) - - cls.G3 = nx.DiGraph() - cls.G3.add_edges_from([(0, 1), (1, 2), (2, 1), (0, 3), (3, 4), (4, 3)]) - - cls.G4 = nx.DiGraph() - - def test_attracting_components(self): - ac = list(nx.attracting_components(self.G1)) - assert {2} in ac - assert {9} in ac - assert {10} in ac - - ac = list(nx.attracting_components(self.G2)) - ac = [tuple(sorted(x)) for x in ac] - assert ac == [(1, 2)] - - ac = list(nx.attracting_components(self.G3)) - ac = [tuple(sorted(x)) for x in ac] - assert (1, 2) in ac - assert (3, 4) in ac - assert len(ac) == 2 - - ac = list(nx.attracting_components(self.G4)) - assert ac == [] - - def test_number_attacting_components(self): - assert nx.number_attracting_components(self.G1) == 3 - assert nx.number_attracting_components(self.G2) == 1 - assert nx.number_attracting_components(self.G3) == 2 - assert nx.number_attracting_components(self.G4) == 0 - - def test_is_attracting_component(self): - assert not nx.is_attracting_component(self.G1) - assert not nx.is_attracting_component(self.G2) - assert not nx.is_attracting_component(self.G3) - g2 = self.G3.subgraph([1, 2]) - assert nx.is_attracting_component(g2) - assert not nx.is_attracting_component(self.G4) - - def test_connected_raise(self): - G = nx.Graph() - with pytest.raises(NetworkXNotImplemented): - next(nx.attracting_components(G)) - pytest.raises(NetworkXNotImplemented, nx.number_attracting_components, G) - pytest.raises(NetworkXNotImplemented, nx.is_attracting_component, G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_biconnected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_biconnected.py deleted file mode 100644 index 19d2d88..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_biconnected.py +++ /dev/null @@ -1,248 +0,0 @@ -import pytest - -import networkx as nx -from networkx import NetworkXNotImplemented - - -def assert_components_edges_equal(x, y): - sx = {frozenset(frozenset(e) for e in c) for c in x} - sy = {frozenset(frozenset(e) for e in c) for c in y} - assert sx == sy - - -def assert_components_equal(x, y): - sx = {frozenset(c) for c in x} - sy = {frozenset(c) for c in y} - assert sx == sy - - -def test_barbell(): - G = nx.barbell_graph(8, 4) - nx.add_path(G, [7, 20, 21, 22]) - nx.add_cycle(G, [22, 23, 24, 25]) - pts = set(nx.articulation_points(G)) - assert pts == {7, 8, 9, 10, 11, 12, 20, 21, 22} - - answer = [ - {12, 13, 14, 15, 16, 17, 18, 19}, - {0, 1, 2, 3, 4, 5, 6, 7}, - {22, 23, 24, 25}, - {11, 12}, - {10, 11}, - {9, 10}, - {8, 9}, - {7, 8}, - {21, 22}, - {20, 21}, - {7, 20}, - ] - assert_components_equal(list(nx.biconnected_components(G)), answer) - - G.add_edge(2, 17) - pts = set(nx.articulation_points(G)) - assert pts == {7, 20, 21, 22} - - -def test_articulation_points_repetitions(): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3)]) - assert list(nx.articulation_points(G)) == [1] - - -def test_articulation_points_cycle(): - G = nx.cycle_graph(3) - nx.add_cycle(G, [1, 3, 4]) - pts = set(nx.articulation_points(G)) - assert pts == {1} - - -def test_is_biconnected(): - G = nx.cycle_graph(3) - assert nx.is_biconnected(G) - nx.add_cycle(G, [1, 3, 4]) - assert not nx.is_biconnected(G) - - -def test_empty_is_biconnected(): - G = nx.empty_graph(5) - assert not nx.is_biconnected(G) - G.add_edge(0, 1) - assert not nx.is_biconnected(G) - - -def test_biconnected_components_cycle(): - G = nx.cycle_graph(3) - nx.add_cycle(G, [1, 3, 4]) - answer = [{0, 1, 2}, {1, 3, 4}] - assert_components_equal(list(nx.biconnected_components(G)), answer) - - -def test_biconnected_components1(): - # graph example from - # https://web.archive.org/web/20121229123447/http://www.ibluemojo.com/school/articul_algorithm.html - edges = [ - (0, 1), - (0, 5), - (0, 6), - (0, 14), - (1, 5), - (1, 6), - (1, 14), - (2, 4), - (2, 10), - (3, 4), - (3, 15), - (4, 6), - (4, 7), - (4, 10), - (5, 14), - (6, 14), - (7, 9), - (8, 9), - (8, 12), - (8, 13), - (10, 15), - (11, 12), - (11, 13), - (12, 13), - ] - G = nx.Graph(edges) - pts = set(nx.articulation_points(G)) - assert pts == {4, 6, 7, 8, 9} - comps = list(nx.biconnected_component_edges(G)) - answer = [ - [(3, 4), (15, 3), (10, 15), (10, 4), (2, 10), (4, 2)], - [(13, 12), (13, 8), (11, 13), (12, 11), (8, 12)], - [(9, 8)], - [(7, 9)], - [(4, 7)], - [(6, 4)], - [(14, 0), (5, 1), (5, 0), (14, 5), (14, 1), (6, 14), (6, 0), (1, 6), (0, 1)], - ] - assert_components_edges_equal(comps, answer) - - -def test_biconnected_components2(): - G = nx.Graph() - nx.add_cycle(G, "ABC") - nx.add_cycle(G, "CDE") - nx.add_cycle(G, "FIJHG") - nx.add_cycle(G, "GIJ") - G.add_edge("E", "G") - comps = list(nx.biconnected_component_edges(G)) - answer = [ - [ - tuple("GF"), - tuple("FI"), - tuple("IG"), - tuple("IJ"), - tuple("JG"), - tuple("JH"), - tuple("HG"), - ], - [tuple("EG")], - [tuple("CD"), tuple("DE"), tuple("CE")], - [tuple("AB"), tuple("BC"), tuple("AC")], - ] - assert_components_edges_equal(comps, answer) - - -def test_biconnected_davis(): - D = nx.davis_southern_women_graph() - bcc = list(nx.biconnected_components(D))[0] - assert set(D) == bcc # All nodes in a giant bicomponent - # So no articulation points - assert len(list(nx.articulation_points(D))) == 0 - - -def test_biconnected_karate(): - K = nx.karate_club_graph() - answer = [ - { - 0, - 1, - 2, - 3, - 7, - 8, - 9, - 12, - 13, - 14, - 15, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - }, - {0, 4, 5, 6, 10, 16}, - {0, 11}, - ] - bcc = list(nx.biconnected_components(K)) - assert_components_equal(bcc, answer) - assert set(nx.articulation_points(K)) == {0} - - -def test_biconnected_eppstein(): - # tests from http://www.ics.uci.edu/~eppstein/PADS/Biconnectivity.py - G1 = nx.Graph( - { - 0: [1, 2, 5], - 1: [0, 5], - 2: [0, 3, 4], - 3: [2, 4, 5, 6], - 4: [2, 3, 5, 6], - 5: [0, 1, 3, 4], - 6: [3, 4], - } - ) - G2 = nx.Graph( - { - 0: [2, 5], - 1: [3, 8], - 2: [0, 3, 5], - 3: [1, 2, 6, 8], - 4: [7], - 5: [0, 2], - 6: [3, 8], - 7: [4], - 8: [1, 3, 6], - } - ) - assert nx.is_biconnected(G1) - assert not nx.is_biconnected(G2) - answer_G2 = [{1, 3, 6, 8}, {0, 2, 5}, {2, 3}, {4, 7}] - bcc = list(nx.biconnected_components(G2)) - assert_components_equal(bcc, answer_G2) - - -def test_null_graph(): - G = nx.Graph() - assert not nx.is_biconnected(G) - assert list(nx.biconnected_components(G)) == [] - assert list(nx.biconnected_component_edges(G)) == [] - assert list(nx.articulation_points(G)) == [] - - -def test_connected_raise(): - DG = nx.DiGraph() - with pytest.raises(NetworkXNotImplemented): - next(nx.biconnected_components(DG)) - with pytest.raises(NetworkXNotImplemented): - next(nx.biconnected_component_edges(DG)) - with pytest.raises(NetworkXNotImplemented): - next(nx.articulation_points(DG)) - pytest.raises(NetworkXNotImplemented, nx.is_biconnected, DG) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_connected.py deleted file mode 100644 index 207214c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_connected.py +++ /dev/null @@ -1,138 +0,0 @@ -import pytest - -import networkx as nx -from networkx import NetworkXNotImplemented -from networkx import convert_node_labels_to_integers as cnlti -from networkx.classes.tests import dispatch_interface - - -class TestConnected: - @classmethod - def setup_class(cls): - G1 = cnlti(nx.grid_2d_graph(2, 2), first_label=0, ordering="sorted") - G2 = cnlti(nx.lollipop_graph(3, 3), first_label=4, ordering="sorted") - G3 = cnlti(nx.house_graph(), first_label=10, ordering="sorted") - cls.G = nx.union(G1, G2) - cls.G = nx.union(cls.G, G3) - cls.DG = nx.DiGraph([(1, 2), (1, 3), (2, 3)]) - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1) - - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2), - (2, 3), - (2, 8), - (3, 4), - (3, 7), - (4, 5), - (5, 3), - (5, 6), - (7, 4), - (7, 6), - (8, 1), - (8, 7), - ] - ) - C = [[3, 4, 5, 7], [1, 2, 8], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = [[2, 3, 4], [1]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = [[1, 2, 3]] - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = [[0], [1], [2], [3], [4], [5], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = [[0, 1, 2], [3, 4]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - C = [] - cls.gc.append((G, C)) - - def test_connected_components(self): - # Test duplicated below - cc = nx.connected_components - G = self.G - C = { - frozenset([0, 1, 2, 3]), - frozenset([4, 5, 6, 7, 8, 9]), - frozenset([10, 11, 12, 13, 14]), - } - assert {frozenset(g) for g in cc(G)} == C - - def test_connected_components_nx_loopback(self): - # This tests the @nx._dispatchable mechanism, treating nx.connected_components - # as if it were a re-implementation from another package. - # Test duplicated from above - cc = nx.connected_components - G = dispatch_interface.convert(self.G) - C = { - frozenset([0, 1, 2, 3]), - frozenset([4, 5, 6, 7, 8, 9]), - frozenset([10, 11, 12, 13, 14]), - } - if "nx_loopback" in nx.config.backends or not nx.config.backends: - # If `nx.config.backends` is empty, then `_dispatchable.__call__` takes a - # "fast path" and does not check graph inputs, so using an unknown backend - # here will still work. - assert {frozenset(g) for g in cc(G)} == C - else: - # This raises, because "nx_loopback" is not registered as a backend. - with pytest.raises( - ImportError, match="'nx_loopback' backend is not installed" - ): - cc(G) - - def test_number_connected_components(self): - ncc = nx.number_connected_components - assert ncc(self.G) == 3 - - def test_number_connected_components2(self): - ncc = nx.number_connected_components - assert ncc(self.grid) == 1 - - def test_connected_components2(self): - cc = nx.connected_components - G = self.grid - C = {frozenset([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])} - assert {frozenset(g) for g in cc(G)} == C - - def test_node_connected_components(self): - ncc = nx.node_connected_component - G = self.grid - C = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - assert ncc(G, 1) == C - - def test_is_connected(self): - assert nx.is_connected(self.grid) - G = nx.Graph() - G.add_nodes_from([1, 2]) - assert not nx.is_connected(G) - - def test_connected_raise(self): - with pytest.raises(NetworkXNotImplemented): - next(nx.connected_components(self.DG)) - pytest.raises(NetworkXNotImplemented, nx.number_connected_components, self.DG) - pytest.raises(NetworkXNotImplemented, nx.node_connected_component, self.DG, 1) - pytest.raises(NetworkXNotImplemented, nx.is_connected, self.DG) - pytest.raises(nx.NetworkXPointlessConcept, nx.is_connected, nx.Graph()) - - def test_connected_mutability(self): - G = self.grid - seen = set() - for component in nx.connected_components(G): - assert len(seen & component) == 0 - seen.update(component) - component.clear() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_semiconnected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_semiconnected.py deleted file mode 100644 index 6376bbf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_semiconnected.py +++ /dev/null @@ -1,55 +0,0 @@ -from itertools import chain - -import pytest - -import networkx as nx - - -class TestIsSemiconnected: - def test_undirected(self): - pytest.raises(nx.NetworkXNotImplemented, nx.is_semiconnected, nx.Graph()) - pytest.raises(nx.NetworkXNotImplemented, nx.is_semiconnected, nx.MultiGraph()) - - def test_empty(self): - pytest.raises(nx.NetworkXPointlessConcept, nx.is_semiconnected, nx.DiGraph()) - pytest.raises( - nx.NetworkXPointlessConcept, nx.is_semiconnected, nx.MultiDiGraph() - ) - - def test_single_node_graph(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.is_semiconnected(G) - - def test_path(self): - G = nx.path_graph(100, create_using=nx.DiGraph()) - assert nx.is_semiconnected(G) - G.add_edge(100, 99) - assert not nx.is_semiconnected(G) - - def test_cycle(self): - G = nx.cycle_graph(100, create_using=nx.DiGraph()) - assert nx.is_semiconnected(G) - G = nx.path_graph(100, create_using=nx.DiGraph()) - G.add_edge(0, 99) - assert nx.is_semiconnected(G) - - def test_tree(self): - G = nx.DiGraph() - G.add_edges_from( - chain.from_iterable([(i, 2 * i + 1), (i, 2 * i + 2)] for i in range(100)) - ) - assert not nx.is_semiconnected(G) - - def test_dumbbell(self): - G = nx.cycle_graph(100, create_using=nx.DiGraph()) - G.add_edges_from((i + 100, (i + 1) % 100 + 100) for i in range(100)) - assert not nx.is_semiconnected(G) # G is disconnected. - G.add_edge(100, 99) - assert nx.is_semiconnected(G) - - def test_alternating_path(self): - G = nx.DiGraph( - chain.from_iterable([(i, i - 1), (i, i + 1)] for i in range(0, 100, 2)) - ) - assert not nx.is_semiconnected(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_strongly_connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_strongly_connected.py deleted file mode 100644 index 27f4098..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_strongly_connected.py +++ /dev/null @@ -1,193 +0,0 @@ -import pytest - -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestStronglyConnected: - @classmethod - def setup_class(cls): - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2), - (2, 3), - (2, 8), - (3, 4), - (3, 7), - (4, 5), - (5, 3), - (5, 6), - (7, 4), - (7, 6), - (8, 1), - (8, 7), - ] - ) - C = {frozenset([3, 4, 5, 7]), frozenset([1, 2, 8]), frozenset([6])} - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = {frozenset([2, 3, 4]), frozenset([1])} - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = {frozenset([1, 2, 3])} - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = { - frozenset([0]), - frozenset([1]), - frozenset([2]), - frozenset([3]), - frozenset([4]), - frozenset([5]), - frozenset([6]), - } - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = {frozenset([0, 1, 2]), frozenset([3, 4])} - cls.gc.append((G, C)) - - def test_tarjan(self): - scc = nx.strongly_connected_components - for G, C in self.gc: - assert {frozenset(g) for g in scc(G)} == C - - def test_kosaraju(self): - scc = nx.kosaraju_strongly_connected_components - for G, C in self.gc: - assert {frozenset(g) for g in scc(G)} == C - - def test_number_strongly_connected_components(self): - ncc = nx.number_strongly_connected_components - for G, C in self.gc: - assert ncc(G) == len(C) - - def test_is_strongly_connected(self): - for G, C in self.gc: - if len(C) == 1: - assert nx.is_strongly_connected(G) - else: - assert not nx.is_strongly_connected(G) - - def test_contract_scc1(self): - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2), - (2, 3), - (2, 11), - (2, 12), - (3, 4), - (4, 3), - (4, 5), - (5, 6), - (6, 5), - (6, 7), - (7, 8), - (7, 9), - (7, 10), - (8, 9), - (9, 7), - (10, 6), - (11, 2), - (11, 4), - (11, 6), - (12, 6), - (12, 11), - ] - ) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - # DAG - assert nx.is_directed_acyclic_graph(cG) - # nodes - assert sorted(cG.nodes()) == [0, 1, 2, 3] - # edges - mapping = {} - for i, component in enumerate(scc): - for n in component: - mapping[n] = i - edge = (mapping[2], mapping[3]) - assert cG.has_edge(*edge) - edge = (mapping[2], mapping[5]) - assert cG.has_edge(*edge) - edge = (mapping[3], mapping[5]) - assert cG.has_edge(*edge) - - def test_contract_scc_isolate(self): - # Bug found and fixed in [1687]. - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - assert list(cG.nodes()) == [0] - assert list(cG.edges()) == [] - - def test_contract_scc_edge(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - G.add_edge(2, 3) - G.add_edge(3, 4) - G.add_edge(4, 3) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - assert sorted(cG.nodes()) == [0, 1] - if 1 in scc[0]: - edge = (0, 1) - else: - edge = (1, 0) - assert list(cG.edges()) == [edge] - - def test_condensation_mapping_and_members(self): - G, C = self.gc[1] - C = sorted(C, key=len, reverse=True) - cG = nx.condensation(G) - mapping = cG.graph["mapping"] - assert all(n in G for n in mapping) - assert all(0 == cN for n, cN in mapping.items() if n in C[0]) - assert all(1 == cN for n, cN in mapping.items() if n in C[1]) - for n, d in cG.nodes(data=True): - assert set(C[n]) == cG.nodes[n]["members"] - - def test_null_graph(self): - G = nx.DiGraph() - assert list(nx.strongly_connected_components(G)) == [] - assert list(nx.kosaraju_strongly_connected_components(G)) == [] - assert len(nx.condensation(G)) == 0 - pytest.raises( - nx.NetworkXPointlessConcept, nx.is_strongly_connected, nx.DiGraph() - ) - - def test_connected_raise(self): - G = nx.Graph() - with pytest.raises(NetworkXNotImplemented): - next(nx.strongly_connected_components(G)) - with pytest.raises(NetworkXNotImplemented): - next(nx.kosaraju_strongly_connected_components(G)) - pytest.raises(NetworkXNotImplemented, nx.is_strongly_connected, G) - pytest.raises(NetworkXNotImplemented, nx.condensation, G) - - strong_cc_methods = ( - nx.strongly_connected_components, - nx.kosaraju_strongly_connected_components, - ) - - @pytest.mark.parametrize("get_components", strong_cc_methods) - def test_connected_mutability(self, get_components): - DG = nx.path_graph(5, create_using=nx.DiGraph) - G = nx.disjoint_union(DG, DG) - seen = set() - for component in get_components(G): - assert len(seen & component) == 0 - seen.update(component) - component.clear() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_weakly_connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_weakly_connected.py deleted file mode 100644 index f014478..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/tests/test_weakly_connected.py +++ /dev/null @@ -1,96 +0,0 @@ -import pytest - -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestWeaklyConnected: - @classmethod - def setup_class(cls): - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2), - (2, 3), - (2, 8), - (3, 4), - (3, 7), - (4, 5), - (5, 3), - (5, 6), - (7, 4), - (7, 6), - (8, 1), - (8, 7), - ] - ) - C = [[3, 4, 5, 7], [1, 2, 8], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = [[2, 3, 4], [1]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = [[1, 2, 3]] - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = [[0], [1], [2], [3], [4], [5], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = [[0, 1, 2], [3, 4]] - cls.gc.append((G, C)) - - def test_weakly_connected_components(self): - for G, C in self.gc: - U = G.to_undirected() - w = {frozenset(g) for g in nx.weakly_connected_components(G)} - c = {frozenset(g) for g in nx.connected_components(U)} - assert w == c - - def test_number_weakly_connected_components(self): - for G, C in self.gc: - U = G.to_undirected() - w = nx.number_weakly_connected_components(G) - c = nx.number_connected_components(U) - assert w == c - - def test_is_weakly_connected(self): - for G, C in self.gc: - U = G.to_undirected() - assert nx.is_weakly_connected(G) == nx.is_connected(U) - - def test_null_graph(self): - G = nx.DiGraph() - assert list(nx.weakly_connected_components(G)) == [] - assert nx.number_weakly_connected_components(G) == 0 - with pytest.raises(nx.NetworkXPointlessConcept): - next(nx.is_weakly_connected(G)) - - def test_connected_raise(self): - G = nx.Graph() - with pytest.raises(NetworkXNotImplemented): - next(nx.weakly_connected_components(G)) - pytest.raises(NetworkXNotImplemented, nx.number_weakly_connected_components, G) - pytest.raises(NetworkXNotImplemented, nx.is_weakly_connected, G) - - def test_connected_mutability(self): - DG = nx.path_graph(5, create_using=nx.DiGraph) - G = nx.disjoint_union(DG, DG) - seen = set() - for component in nx.weakly_connected_components(G): - assert len(seen & component) == 0 - seen.update(component) - component.clear() - - -def test_is_weakly_connected_empty_graph_raises(): - G = nx.DiGraph() - with pytest.raises(nx.NetworkXPointlessConcept, match="Connectivity is undefined"): - nx.is_weakly_connected(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/weakly_connected.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/weakly_connected.py deleted file mode 100644 index ecfac50..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/components/weakly_connected.py +++ /dev/null @@ -1,197 +0,0 @@ -"""Weakly connected components.""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - "number_weakly_connected_components", - "weakly_connected_components", - "is_weakly_connected", -] - - -@not_implemented_for("undirected") -@nx._dispatchable -def weakly_connected_components(G): - """Generate weakly connected components of G. - - Parameters - ---------- - G : NetworkX graph - A directed graph - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each weakly connected - component of G. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - Generate a sorted list of weakly connected components, largest first. - - >>> G = nx.path_graph(4, create_using=nx.DiGraph()) - >>> nx.add_path(G, [10, 11, 12]) - >>> [ - ... len(c) - ... for c in sorted(nx.weakly_connected_components(G), key=len, reverse=True) - ... ] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort: - - >>> largest_cc = max(nx.weakly_connected_components(G), key=len) - - See Also - -------- - connected_components - strongly_connected_components - - Notes - ----- - For directed graphs only. - - """ - seen = set() - n = len(G) # must be outside the loop to avoid performance hit with graph views - for v in G: - if v not in seen: - c = set(_plain_bfs(G, n, v)) - seen.update(c) - yield c - - -@not_implemented_for("undirected") -@nx._dispatchable -def number_weakly_connected_components(G): - """Returns the number of weakly connected components in G. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - Returns - ------- - n : integer - Number of weakly connected components - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (2, 1), (3, 4)]) - >>> nx.number_weakly_connected_components(G) - 2 - - See Also - -------- - weakly_connected_components - number_connected_components - number_strongly_connected_components - - Notes - ----- - For directed graphs only. - - """ - return sum(1 for wcc in weakly_connected_components(G)) - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_weakly_connected(G): - """Test directed graph for weak connectivity. - - A directed graph is weakly connected if and only if the graph - is connected when the direction of the edge between nodes is ignored. - - Note that if a graph is strongly connected (i.e. the graph is connected - even when we account for directionality), it is by definition weakly - connected as well. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - connected : bool - True if the graph is weakly connected, False otherwise. - - Raises - ------ - NetworkXNotImplemented - If G is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (2, 1)]) - >>> G.add_node(3) - >>> nx.is_weakly_connected(G) # node 3 is not connected to the graph - False - >>> G.add_edge(2, 3) - >>> nx.is_weakly_connected(G) - True - - See Also - -------- - is_strongly_connected - is_semiconnected - is_connected - is_biconnected - weakly_connected_components - - Notes - ----- - For directed graphs only. - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - """Connectivity is undefined for the null graph.""" - ) - - return len(next(weakly_connected_components(G))) == len(G) - - -def _plain_bfs(G, n, source): - """A fast BFS node generator - - The direction of the edge between nodes is ignored. - - For directed graphs only. - - """ - Gsucc = G._succ - Gpred = G._pred - seen = {source} - nextlevel = [source] - - yield source - while nextlevel: - thislevel = nextlevel - nextlevel = [] - for v in thislevel: - for w in Gsucc[v]: - if w not in seen: - seen.add(w) - nextlevel.append(w) - yield w - for w in Gpred[v]: - if w not in seen: - seen.add(w) - nextlevel.append(w) - yield w - if len(seen) == n: - return diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/__init__.py deleted file mode 100644 index d08a360..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Connectivity and cut algorithms""" - -from .connectivity import * -from .cuts import * -from .edge_augmentation import * -from .edge_kcomponents import * -from .disjoint_paths import * -from .kcomponents import * -from .kcutsets import * -from .stoerwagner import * -from .utils import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/connectivity.py deleted file mode 100644 index 2f85c86..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/connectivity.py +++ /dev/null @@ -1,811 +0,0 @@ -""" -Flow based connectivity algorithms -""" - -import itertools -from operator import itemgetter - -import networkx as nx - -# Define the default maximum flow function to use in all flow based -# connectivity algorithms. -from networkx.algorithms.flow import ( - boykov_kolmogorov, - build_residual_network, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -) - -default_flow_func = edmonds_karp - -from .utils import build_auxiliary_edge_connectivity, build_auxiliary_node_connectivity - -__all__ = [ - "average_node_connectivity", - "local_node_connectivity", - "node_connectivity", - "local_edge_connectivity", - "edge_connectivity", - "all_pairs_node_connectivity", -] - - -@nx._dispatchable(graphs={"G": 0, "auxiliary?": 4}, preserve_graph_attrs={"auxiliary"}) -def local_node_connectivity( - G, s, t, flow_func=None, auxiliary=None, residual=None, cutoff=None -): - r"""Computes local node connectivity for nodes s and t. - - Local node connectivity for two non adjacent nodes s and t is the - minimum number of nodes that must be removed (along with their incident - edges) to disconnect them. - - This is a flow based implementation of node connectivity. We compute the - maximum flow on an auxiliary digraph build from the original input - graph (see below for details). - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node - - t : node - Target node - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - cutoff : integer, float, or None (default: None) - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This only works for flows - that support the cutoff parameter (most do) and is ignored otherwise. - - Returns - ------- - K : integer - local node connectivity for nodes s and t - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import local_node_connectivity - - We use in this example the platonic icosahedral graph, which has node - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> local_node_connectivity(G, 0, 6) - 5 - - If you need to compute local connectivity on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local node connectivity among - all pairs of nodes of the platonic icosahedral graph reusing - the data structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_node_connectivity - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = local_node_connectivity(G, u, v, auxiliary=H, residual=R) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing node - connectivity. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> local_node_connectivity(G, 0, 6, flow_func=shortest_augmenting_path) - 5 - - Notes - ----- - This is a flow based implementation of node connectivity. We compute the - maximum flow using, by default, the :meth:`edmonds_karp` algorithm (see: - :meth:`maximum_flow`) on an auxiliary digraph build from the original - input graph: - - For an undirected graph G having `n` nodes and `m` edges we derive a - directed graph H with `2n` nodes and `2m+n` arcs by replacing each - original node `v` with two nodes `v_A`, `v_B` linked by an (internal) - arc in H. Then for each edge (`u`, `v`) in G we add two arcs - (`u_B`, `v_A`) and (`v_B`, `u_A`) in H. Finally we set the attribute - capacity = 1 for each arc in H [1]_ . - - For a directed graph G having `n` nodes and `m` arcs we derive a - directed graph H with `2n` nodes and `m+n` arcs by replacing each - original node `v` with two nodes `v_A`, `v_B` linked by an (internal) - arc (`v_A`, `v_B`) in H. Then for each arc (`u`, `v`) in G we add one arc - (`u_B`, `v_A`) in H. Finally we set the attribute capacity = 1 for - each arc in H. - - This is equal to the local node connectivity because the value of - a maximum s-t-flow is equal to the capacity of a minimum s-t-cut. - - See also - -------- - :meth:`local_edge_connectivity` - :meth:`node_connectivity` - :meth:`minimum_node_cut` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and - Erlebach, 'Network Analysis: Methodological Foundations', Lecture - Notes in Computer Science, Volume 3418, Springer-Verlag, 2005. - http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get("mapping", None) - if mapping is None: - raise nx.NetworkXError("Invalid auxiliary digraph.") - - kwargs = {"flow_func": flow_func, "residual": residual} - - if flow_func is not preflow_push: - kwargs["cutoff"] = cutoff - - if flow_func is shortest_augmenting_path: - kwargs["two_phase"] = True - - return nx.maximum_flow_value(H, f"{mapping[s]}B", f"{mapping[t]}A", **kwargs) - - -@nx._dispatchable -def node_connectivity(G, s=None, t=None, flow_func=None): - r"""Returns node connectivity for a graph or digraph G. - - Node connectivity is equal to the minimum number of nodes that - must be removed to disconnect G or render it trivial. If source - and target nodes are provided, this function returns the local node - connectivity: the minimum number of nodes that must be removed to break - all paths from source to target in G. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - K : integer - Node connectivity of G, or local node connectivity if source - and target are provided. - - Examples - -------- - >>> # Platonic icosahedral graph is 5-node-connected - >>> G = nx.icosahedral_graph() - >>> nx.node_connectivity(G) - 5 - - You can use alternative flow algorithms for the underlying maximum - flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. Alternative - flow functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> nx.node_connectivity(G, flow_func=shortest_augmenting_path) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local node connectivity. - - >>> nx.node_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_node_connectivity` for details. - - Notes - ----- - This is a flow based implementation of node connectivity. The - algorithm works by solving $O((n-\delta-1+\delta(\delta-1)/2))$ - maximum flow problems on an auxiliary digraph. Where $\delta$ - is the minimum degree of G. For details about the auxiliary - digraph and the computation of local node connectivity see - :meth:`local_node_connectivity`. This implementation is based - on algorithm 11 in [1]_. - - See also - -------- - :meth:`local_node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError("Both source and target must be specified.") - - # Local node connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - return local_node_connectivity(G, s, t, flow_func=flow_func) - - # Global node connectivity - if G.is_directed(): - if not nx.is_weakly_connected(G): - return 0 - iter_func = itertools.permutations - # It is necessary to consider both predecessors - # and successors for directed graphs - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)]) - - else: - if not nx.is_connected(G): - return 0 - iter_func = itertools.combinations - neighbors = G.neighbors - - # Reuse the auxiliary digraph and the residual network - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R} - - # Pick a node with minimum degree - # Node connectivity is bounded by degree. - v, K = min(G.degree(), key=itemgetter(1)) - # compute local node connectivity with all its non-neighbors nodes - for w in set(G) - set(neighbors(v)) - {v}: - kwargs["cutoff"] = K - K = min(K, local_node_connectivity(G, v, w, **kwargs)) - # Also for non adjacent pairs of neighbors of v - for x, y in iter_func(neighbors(v), 2): - if y in G[x]: - continue - kwargs["cutoff"] = K - K = min(K, local_node_connectivity(G, x, y, **kwargs)) - - return K - - -@nx._dispatchable -def average_node_connectivity(G, flow_func=None): - r"""Returns the average connectivity of a graph G. - - The average connectivity `\bar{\kappa}` of a graph G is the average - of local node connectivity over all pairs of nodes of G [1]_ . - - .. math:: - - \bar{\kappa}(G) = \frac{\sum_{u,v} \kappa_{G}(u,v)}{{n \choose 2}} - - Parameters - ---------- - - G : NetworkX graph - Undirected graph - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See :meth:`local_node_connectivity` - for details. The choice of the default function may change from - version to version and should not be relied on. Default value: None. - - Returns - ------- - K : float - Average node connectivity - - See also - -------- - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Beineke, L., O. Oellermann, and R. Pippert (2002). The average - connectivity of a graph. Discrete mathematics 252(1-3), 31-45. - http://www.sciencedirect.com/science/article/pii/S0012365X01001807 - - """ - if G.is_directed(): - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - # Reuse the auxiliary digraph and the residual network - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R} - - num, den = 0, 0 - for u, v in iter_func(G, 2): - num += local_node_connectivity(G, u, v, **kwargs) - den += 1 - - if den == 0: # Null Graph - return 0 - return num / den - - -@nx._dispatchable -def all_pairs_node_connectivity(G, nbunch=None, flow_func=None): - """Compute node connectivity between all pairs of nodes of G. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - nbunch: container - Container of nodes. If provided node connectivity will be computed - only over pairs of nodes in nbunch. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - all_pairs : dict - A dictionary with node connectivity between all pairs of nodes - in G, or in nbunch if provided. - - See also - -------- - :meth:`local_node_connectivity` - :meth:`edge_connectivity` - :meth:`local_edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - """ - if nbunch is None: - nbunch = G - else: - nbunch = set(nbunch) - - directed = G.is_directed() - if directed: - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - all_pairs = {n: {} for n in nbunch} - - # Reuse auxiliary digraph and residual network - H = build_auxiliary_node_connectivity(G) - mapping = H.graph["mapping"] - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R} - - for u, v in iter_func(nbunch, 2): - K = local_node_connectivity(G, u, v, **kwargs) - all_pairs[u][v] = K - if not directed: - all_pairs[v][u] = K - - return all_pairs - - -@nx._dispatchable(graphs={"G": 0, "auxiliary?": 4}) -def local_edge_connectivity( - G, s, t, flow_func=None, auxiliary=None, residual=None, cutoff=None -): - r"""Returns local edge connectivity for nodes s and t in G. - - Local edge connectivity for two nodes s and t is the minimum number - of edges that must be removed to disconnect them. - - This is a flow based implementation of edge connectivity. We compute the - maximum flow on an auxiliary digraph build from the original - network (see below for details). This is equal to the local edge - connectivity because the value of a maximum s-t-flow is equal to the - capacity of a minimum s-t-cut (Ford and Fulkerson theorem) [1]_ . - - Parameters - ---------- - G : NetworkX graph - Undirected or directed graph - - s : node - Source node - - t : node - Target node - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph for computing flow based edge connectivity. If - provided it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - cutoff : integer, float, or None (default: None) - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This only works for flows - that support the cutoff parameter (most do) and is ignored otherwise. - - Returns - ------- - K : integer - local edge connectivity for nodes s and t. - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import local_edge_connectivity - - We use in this example the platonic icosahedral graph, which has edge - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> local_edge_connectivity(G, 0, 6) - 5 - - If you need to compute local connectivity on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local edge connectivity among - all pairs of nodes of the platonic icosahedral graph reusing - the data structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_edge_connectivity - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = local_edge_connectivity(G, u, v, auxiliary=H, residual=R) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge - connectivity. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> local_edge_connectivity(G, 0, 6, flow_func=shortest_augmenting_path) - 5 - - Notes - ----- - This is a flow based implementation of edge connectivity. We compute the - maximum flow using, by default, the :meth:`edmonds_karp` algorithm on an - auxiliary digraph build from the original input graph: - - If the input graph is undirected, we replace each edge (`u`,`v`) with - two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute - 'capacity' for each arc to 1. If the input graph is directed we simply - add the 'capacity' attribute. This is an implementation of algorithm 1 - in [1]_. - - The maximum flow in the auxiliary network is equal to the local edge - connectivity because the value of a maximum s-t-flow is equal to the - capacity of a minimum s-t-cut (Ford and Fulkerson theorem). - - See also - -------- - :meth:`edge_connectivity` - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - kwargs = {"flow_func": flow_func, "residual": residual} - - if flow_func is not preflow_push: - kwargs["cutoff"] = cutoff - - if flow_func is shortest_augmenting_path: - kwargs["two_phase"] = True - - return nx.maximum_flow_value(H, s, t, **kwargs) - - -@nx._dispatchable -def edge_connectivity(G, s=None, t=None, flow_func=None, cutoff=None): - r"""Returns the edge connectivity of the graph or digraph G. - - The edge connectivity is equal to the minimum number of edges that - must be removed to disconnect G or render it trivial. If source - and target nodes are provided, this function returns the local edge - connectivity: the minimum number of edges that must be removed to - break all paths from source to target in G. - - Parameters - ---------- - G : NetworkX graph - Undirected or directed graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - cutoff : integer, float, or None (default: None) - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This only works for flows - that support the cutoff parameter (most do) and is ignored otherwise. - - Returns - ------- - K : integer - Edge connectivity for G, or local edge connectivity if source - and target were provided - - Examples - -------- - >>> # Platonic icosahedral graph is 5-edge-connected - >>> G = nx.icosahedral_graph() - >>> nx.edge_connectivity(G) - 5 - - You can use alternative flow algorithms for the underlying - maximum flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. - Alternative flow functions have to be explicitly imported - from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> nx.edge_connectivity(G, flow_func=shortest_augmenting_path) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local edge connectivity. - - >>> nx.edge_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_edge_connectivity` for details. - - Notes - ----- - This is a flow based implementation of global edge connectivity. - For undirected graphs the algorithm works by finding a 'small' - dominating set of nodes of G (see algorithm 7 in [1]_ ) and - computing local maximum flow (see :meth:`local_edge_connectivity`) - between an arbitrary node in the dominating set and the rest of - nodes in it. This is an implementation of algorithm 6 in [1]_ . - For directed graphs, the algorithm does n calls to the maximum - flow function. This is an implementation of algorithm 8 in [1]_ . - - See also - -------- - :meth:`local_edge_connectivity` - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - :meth:`k_edge_components` - :meth:`k_edge_subgraphs` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError("Both source and target must be specified.") - - # Local edge connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - return local_edge_connectivity(G, s, t, flow_func=flow_func, cutoff=cutoff) - - # Global edge connectivity - # reuse auxiliary digraph and residual network - H = build_auxiliary_edge_connectivity(G) - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R} - - if G.is_directed(): - # Algorithm 8 in [1] - if not nx.is_weakly_connected(G): - return 0 - - # initial value for \lambda is minimum degree - L = min(d for n, d in G.degree()) - nodes = list(G) - n = len(nodes) - - if cutoff is not None: - L = min(cutoff, L) - - for i in range(n): - kwargs["cutoff"] = L - try: - L = min(L, local_edge_connectivity(G, nodes[i], nodes[i + 1], **kwargs)) - except IndexError: # last node! - L = min(L, local_edge_connectivity(G, nodes[i], nodes[0], **kwargs)) - return L - else: # undirected - # Algorithm 6 in [1] - if not nx.is_connected(G): - return 0 - - # initial value for \lambda is minimum degree - L = min(d for n, d in G.degree()) - - if cutoff is not None: - L = min(cutoff, L) - - # A dominating set is \lambda-covering - # We need a dominating set with at least two nodes - for node in G: - D = nx.dominating_set(G, start_with=node) - v = D.pop() - if D: - break - else: - # in complete graphs the dominating sets will always be of one node - # thus we return min degree - return L - - for w in D: - kwargs["cutoff"] = L - L = min(L, local_edge_connectivity(G, v, w, **kwargs)) - - return L diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/cuts.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/cuts.py deleted file mode 100644 index 27124e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/cuts.py +++ /dev/null @@ -1,612 +0,0 @@ -""" -Flow based cut algorithms -""" - -import itertools - -import networkx as nx - -# Define the default maximum flow function to use in all flow based -# cut algorithms. -from networkx.algorithms.flow import build_residual_network, edmonds_karp - -default_flow_func = edmonds_karp - -from .utils import build_auxiliary_edge_connectivity, build_auxiliary_node_connectivity - -__all__ = [ - "minimum_st_node_cut", - "minimum_node_cut", - "minimum_st_edge_cut", - "minimum_edge_cut", -] - - -@nx._dispatchable( - graphs={"G": 0, "auxiliary?": 4}, - preserve_edge_attrs={"auxiliary": {"capacity": float("inf")}}, - preserve_graph_attrs={"auxiliary"}, -) -def minimum_st_edge_cut(G, s, t, flow_func=None, auxiliary=None, residual=None): - """Returns the edges of the cut-set of a minimum (s, t)-cut. - - This function returns the set of edges of minimum cardinality that, - if removed, would destroy all paths among source and target in G. - Edge weights are not considered. See :meth:`minimum_cut` for - computing minimum cuts considering edge weights. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See :meth:`node_connectivity` for - details. The choice of the default function may change from version - to version and should not be relied on. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - cutset : set - Set of edges that, if removed from the graph, will disconnect it. - - See also - -------- - :meth:`minimum_cut` - :meth:`minimum_node_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import minimum_st_edge_cut - - We use in this example the platonic icosahedral graph, which has edge - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> len(minimum_st_edge_cut(G, 0, 6)) - 5 - - If you need to compute local edge cuts on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local edge cuts among all pairs of - nodes of the platonic icosahedral graph reusing the data - structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_edge_connectivity - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = len(minimum_st_edge_cut(G, u, v, auxiliary=H, residual=R)) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge - cuts. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(minimum_st_edge_cut(G, 0, 6, flow_func=shortest_augmenting_path)) - 5 - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - kwargs = {"capacity": "capacity", "flow_func": flow_func, "residual": residual} - - cut_value, partition = nx.minimum_cut(H, s, t, **kwargs) - reachable, non_reachable = partition - # Any edge in the original graph linking the two sets in the - # partition is part of the edge cutset - cutset = set() - for u, nbrs in ((n, G[n]) for n in reachable): - cutset.update((u, v) for v in nbrs if v in non_reachable) - - return cutset - - -@nx._dispatchable( - graphs={"G": 0, "auxiliary?": 4}, - preserve_node_attrs={"auxiliary": {"id": None}}, - preserve_graph_attrs={"auxiliary"}, -) -def minimum_st_node_cut(G, s, t, flow_func=None, auxiliary=None, residual=None): - r"""Returns a set of nodes of minimum cardinality that disconnect source - from target in G. - - This function returns the set of nodes of minimum cardinality that, - if removed, would destroy all paths among source and target in G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. - - t : node - Target node. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - cutset : set - Set of nodes that, if removed, would destroy all paths between - source and target in G. - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import minimum_st_node_cut - - We use in this example the platonic icosahedral graph, which has node - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> len(minimum_st_node_cut(G, 0, 6)) - 5 - - If you need to compute local st cuts between several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity and node cuts, and the - residual network for the underlying maximum flow computation. - - Example of how to compute local st node cuts reusing the data - structures: - - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_node_connectivity - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> len(minimum_st_node_cut(G, 0, 6, auxiliary=H, residual=R)) - 5 - - You can also use alternative flow algorithms for computing minimum st - node cuts. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(minimum_st_node_cut(G, 0, 6, flow_func=shortest_augmenting_path)) - 5 - - Notes - ----- - This is a flow based implementation of minimum node cut. The algorithm - is based in solving a number of maximum flow computations to determine - the capacity of the minimum cut on an auxiliary directed network that - corresponds to the minimum node cut of G. It handles both directed - and undirected graphs. This implementation is based on algorithm 11 - in [1]_. - - See also - -------- - :meth:`minimum_node_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get("mapping", None) - if mapping is None: - raise nx.NetworkXError("Invalid auxiliary digraph.") - if G.has_edge(s, t) or G.has_edge(t, s): - return {} - kwargs = {"flow_func": flow_func, "residual": residual, "auxiliary": H} - - # The edge cut in the auxiliary digraph corresponds to the node cut in the - # original graph. - edge_cut = minimum_st_edge_cut(H, f"{mapping[s]}B", f"{mapping[t]}A", **kwargs) - # Each node in the original graph maps to two nodes of the auxiliary graph - node_cut = {H.nodes[node]["id"] for edge in edge_cut for node in edge} - return node_cut - {s, t} - - -@nx._dispatchable -def minimum_node_cut(G, s=None, t=None, flow_func=None): - r"""Returns a set of nodes of minimum cardinality that disconnects G. - - If source and target nodes are provided, this function returns the - set of nodes of minimum cardinality that, if removed, would destroy - all paths among source and target in G. If not, it returns a set - of nodes of minimum cardinality that disconnects G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - cutset : set - Set of nodes that, if removed, would disconnect G. If source - and target nodes are provided, the set contains the nodes that - if removed, would destroy all paths between source and target. - - Examples - -------- - >>> # Platonic icosahedral graph has node connectivity 5 - >>> G = nx.icosahedral_graph() - >>> node_cut = nx.minimum_node_cut(G) - >>> len(node_cut) - 5 - - You can use alternative flow algorithms for the underlying maximum - flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. Alternative - flow functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> node_cut == nx.minimum_node_cut(G, flow_func=shortest_augmenting_path) - True - - If you specify a pair of nodes (source and target) as parameters, - this function returns a local st node cut. - - >>> len(nx.minimum_node_cut(G, 3, 7)) - 5 - - If you need to perform several local st cuts among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`minimum_st_node_cut` for details. - - Notes - ----- - This is a flow based implementation of minimum node cut. The algorithm - is based in solving a number of maximum flow computations to determine - the capacity of the minimum cut on an auxiliary directed network that - corresponds to the minimum node cut of G. It handles both directed - and undirected graphs. This implementation is based on algorithm 11 - in [1]_. - - See also - -------- - :meth:`minimum_st_node_cut` - :meth:`minimum_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError("Both source and target must be specified.") - - # Local minimum node cut. - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - return minimum_st_node_cut(G, s, t, flow_func=flow_func) - - # Global minimum node cut. - # Analog to the algorithm 11 for global node connectivity in [1]. - if G.is_directed(): - if not nx.is_weakly_connected(G): - raise nx.NetworkXError("Input graph is not connected") - iter_func = itertools.permutations - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)]) - - else: - if not nx.is_connected(G): - raise nx.NetworkXError("Input graph is not connected") - iter_func = itertools.combinations - neighbors = G.neighbors - - # Reuse the auxiliary digraph and the residual network. - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R} - - # Choose a node with minimum degree. - v = min(G, key=G.degree) - # Initial node cutset is all neighbors of the node with minimum degree. - min_cut = set(G[v]) - # Compute st node cuts between v and all its non-neighbors nodes in G. - for w in set(G) - set(neighbors(v)) - {v}: - this_cut = minimum_st_node_cut(G, v, w, **kwargs) - if len(min_cut) >= len(this_cut): - min_cut = this_cut - # Also for non adjacent pairs of neighbors of v. - for x, y in iter_func(neighbors(v), 2): - if y in G[x]: - continue - this_cut = minimum_st_node_cut(G, x, y, **kwargs) - if len(min_cut) >= len(this_cut): - min_cut = this_cut - - return min_cut - - -@nx._dispatchable -def minimum_edge_cut(G, s=None, t=None, flow_func=None): - r"""Returns a set of edges of minimum cardinality that disconnects G. - - If source and target nodes are provided, this function returns the - set of edges of minimum cardinality that, if removed, would break - all paths among source and target in G. If not, it returns a set of - edges of minimum cardinality that disconnects G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - cutset : set - Set of edges that, if removed, would disconnect G. If source - and target nodes are provided, the set contains the edges that - if removed, would destroy all paths between source and target. - - Examples - -------- - >>> # Platonic icosahedral graph has edge connectivity 5 - >>> G = nx.icosahedral_graph() - >>> len(nx.minimum_edge_cut(G)) - 5 - - You can use alternative flow algorithms for the underlying - maximum flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. - Alternative flow functions have to be explicitly imported - from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(nx.minimum_edge_cut(G, flow_func=shortest_augmenting_path)) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local edge connectivity. - - >>> nx.edge_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_edge_connectivity` for details. - - Notes - ----- - This is a flow based implementation of minimum edge cut. For - undirected graphs the algorithm works by finding a 'small' dominating - set of nodes of G (see algorithm 7 in [1]_) and computing the maximum - flow between an arbitrary node in the dominating set and the rest of - nodes in it. This is an implementation of algorithm 6 in [1]_. For - directed graphs, the algorithm does n calls to the max flow function. - The function raises an error if the directed graph is not weakly - connected and returns an empty set if it is weakly connected. - It is an implementation of algorithm 8 in [1]_. - - See also - -------- - :meth:`minimum_st_edge_cut` - :meth:`minimum_node_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError("Both source and target must be specified.") - - # reuse auxiliary digraph and residual network - H = build_auxiliary_edge_connectivity(G) - R = build_residual_network(H, "capacity") - kwargs = {"flow_func": flow_func, "residual": R, "auxiliary": H} - - # Local minimum edge cut if s and t are not None - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - return minimum_st_edge_cut(H, s, t, **kwargs) - - # Global minimum edge cut - # Analog to the algorithm for global edge connectivity - if G.is_directed(): - # Based on algorithm 8 in [1] - if not nx.is_weakly_connected(G): - raise nx.NetworkXError("Input graph is not connected") - - # Initial cutset is all edges of a node with minimum degree - node = min(G, key=G.degree) - min_cut = set(G.edges(node)) - nodes = list(G) - n = len(nodes) - for i in range(n): - try: - this_cut = minimum_st_edge_cut(H, nodes[i], nodes[i + 1], **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - except IndexError: # Last node! - this_cut = minimum_st_edge_cut(H, nodes[i], nodes[0], **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - - return min_cut - - else: # undirected - # Based on algorithm 6 in [1] - if not nx.is_connected(G): - raise nx.NetworkXError("Input graph is not connected") - - # Initial cutset is all edges of a node with minimum degree - node = min(G, key=G.degree) - min_cut = set(G.edges(node)) - # A dominating set is \lambda-covering - # We need a dominating set with at least two nodes - for node in G: - D = nx.dominating_set(G, start_with=node) - v = D.pop() - if D: - break - else: - # in complete graphs the dominating set will always be of one node - # thus we return min_cut, which now contains the edges of a node - # with minimum degree - return min_cut - for w in D: - this_cut = minimum_st_edge_cut(H, v, w, **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - - return min_cut diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/disjoint_paths.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/disjoint_paths.py deleted file mode 100644 index 0061649..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/disjoint_paths.py +++ /dev/null @@ -1,408 +0,0 @@ -"""Flow based node and edge disjoint paths.""" - -import networkx as nx - -# Define the default maximum flow function to use for the underlying -# maximum flow computations -from networkx.algorithms.flow import ( - edmonds_karp, - preflow_push, - shortest_augmenting_path, -) -from networkx.exception import NetworkXNoPath - -default_flow_func = edmonds_karp -from itertools import filterfalse as _filterfalse - -# Functions to build auxiliary data structures. -from .utils import build_auxiliary_edge_connectivity, build_auxiliary_node_connectivity - -__all__ = ["edge_disjoint_paths", "node_disjoint_paths"] - - -@nx._dispatchable( - graphs={"G": 0, "auxiliary?": 5}, - preserve_edge_attrs={"auxiliary": {"capacity": float("inf")}}, -) -def edge_disjoint_paths( - G, s, t, flow_func=None, cutoff=None, auxiliary=None, residual=None -): - """Returns the edges disjoint paths between source and target. - - Edge disjoint paths are paths that do not share any edge. The - number of edge disjoint paths between source and target is equal - to their edge connectivity. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. The choice of the default function - may change from version to version and should not be relied on. - Default value: None. - - cutoff : integer or None (default: None) - Maximum number of paths to yield. If specified, the maximum flow - algorithm will terminate when the flow value reaches or exceeds the - cutoff. This only works for flows that support the cutoff parameter - (most do) and is ignored otherwise. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based edge connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - paths : generator - A generator of edge independent paths. - - Raises - ------ - NetworkXNoPath - If there is no path between source and target. - - NetworkXError - If source or target are not in the graph G. - - See also - -------- - :meth:`node_disjoint_paths` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Examples - -------- - We use in this example the platonic icosahedral graph, which has node - edge connectivity 5, thus there are 5 edge disjoint paths between any - pair of nodes. - - >>> G = nx.icosahedral_graph() - >>> len(list(nx.edge_disjoint_paths(G, 0, 6))) - 5 - - - If you need to compute edge disjoint paths on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute edge disjoint paths among all pairs of - nodes of the platonic icosahedral graph reusing the data - structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_edge_connectivity - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> result = {n: {} for n in G} - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as arguments - >>> for u, v in itertools.combinations(G, 2): - ... k = len(list(nx.edge_disjoint_paths(G, u, v, auxiliary=H, residual=R))) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge disjoint - paths. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(list(nx.edge_disjoint_paths(G, 0, 6, flow_func=shortest_augmenting_path))) - 5 - - Notes - ----- - This is a flow based implementation of edge disjoint paths. We compute - the maximum flow between source and target on an auxiliary directed - network. The saturated edges in the residual network after running the - maximum flow algorithm correspond to edge disjoint paths between source - and target in the original network. This function handles both directed - and undirected graphs, and can use all flow algorithms from NetworkX flow - package. - - """ - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - # Maximum possible edge disjoint paths - possible = min(H.out_degree(s), H.in_degree(t)) - if not possible: - raise NetworkXNoPath - - if cutoff is None: - cutoff = possible - else: - cutoff = min(cutoff, possible) - - # Compute maximum flow between source and target. Flow functions in - # NetworkX return a residual network. - kwargs = { - "capacity": "capacity", - "residual": residual, - "cutoff": cutoff, - "value_only": True, - } - if flow_func is preflow_push: - del kwargs["cutoff"] - if flow_func is shortest_augmenting_path: - kwargs["two_phase"] = True - R = flow_func(H, s, t, **kwargs) - - if R.graph["flow_value"] == 0: - raise NetworkXNoPath - - # Saturated edges in the residual network form the edge disjoint paths - # between source and target - cutset = [ - (u, v) - for u, v, d in R.edges(data=True) - if d["capacity"] == d["flow"] and d["flow"] > 0 - ] - # This is equivalent of what flow.utils.build_flow_dict returns, but - # only for the nodes with saturated edges and without reporting 0 flows. - flow_dict = {n: {} for edge in cutset for n in edge} - for u, v in cutset: - flow_dict[u][v] = 1 - - # Rebuild the edge disjoint paths from the flow dictionary. - paths_found = 0 - for v in list(flow_dict[s]): - if paths_found >= cutoff: - # preflow_push does not support cutoff: we have to - # keep track of the paths founds and stop at cutoff. - break - path = [s] - if v == t: - path.append(v) - yield path - continue - u = v - while u != t: - path.append(u) - try: - u, _ = flow_dict[u].popitem() - except KeyError: - break - else: - path.append(t) - yield path - paths_found += 1 - - -@nx._dispatchable( - graphs={"G": 0, "auxiliary?": 5}, - preserve_node_attrs={"auxiliary": {"id": None}}, - preserve_graph_attrs={"auxiliary"}, -) -def node_disjoint_paths( - G, s, t, flow_func=None, cutoff=None, auxiliary=None, residual=None -): - r"""Computes node disjoint paths between source and target. - - Node disjoint paths are paths that only share their first and last - nodes. The number of node independent paths between two nodes is - equal to their local node connectivity. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. - - t : node - Target node. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - cutoff : integer or None (default: None) - Maximum number of paths to yield. If specified, the maximum flow - algorithm will terminate when the flow value reaches or exceeds the - cutoff. This only works for flows that support the cutoff parameter - (most do) and is ignored otherwise. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - paths : generator - Generator of node disjoint paths. - - Raises - ------ - NetworkXNoPath - If there is no path between source and target. - - NetworkXError - If source or target are not in the graph G. - - Examples - -------- - We use in this example the platonic icosahedral graph, which has node - connectivity 5, thus there are 5 node disjoint paths between any pair - of non neighbor nodes. - - >>> G = nx.icosahedral_graph() - >>> len(list(nx.node_disjoint_paths(G, 0, 6))) - 5 - - If you need to compute node disjoint paths between several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity and node cuts, and the - residual network for the underlying maximum flow computation. - - Example of how to compute node disjoint paths reusing the data - structures: - - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import build_auxiliary_node_connectivity - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, "capacity") - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as arguments - >>> len(list(nx.node_disjoint_paths(G, 0, 6, auxiliary=H, residual=R))) - 5 - - You can also use alternative flow algorithms for computing node disjoint - paths. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(list(nx.node_disjoint_paths(G, 0, 6, flow_func=shortest_augmenting_path))) - 5 - - Notes - ----- - This is a flow based implementation of node disjoint paths. We compute - the maximum flow between source and target on an auxiliary directed - network. The saturated edges in the residual network after running the - maximum flow algorithm correspond to node disjoint paths between source - and target in the original network. This function handles both directed - and undirected graphs, and can use all flow algorithms from NetworkX flow - package. - - See also - -------- - :meth:`edge_disjoint_paths` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - """ - if s not in G: - raise nx.NetworkXError(f"node {s} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {t} not in graph") - - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get("mapping", None) - if mapping is None: - raise nx.NetworkXError("Invalid auxiliary digraph.") - - # Maximum possible edge disjoint paths - possible = min(H.out_degree(f"{mapping[s]}B"), H.in_degree(f"{mapping[t]}A")) - if not possible: - raise NetworkXNoPath - - if cutoff is None: - cutoff = possible - else: - cutoff = min(cutoff, possible) - - kwargs = { - "flow_func": flow_func, - "residual": residual, - "auxiliary": H, - "cutoff": cutoff, - } - - # The edge disjoint paths in the auxiliary digraph correspond to the node - # disjoint paths in the original graph. - paths_edges = edge_disjoint_paths(H, f"{mapping[s]}B", f"{mapping[t]}A", **kwargs) - for path in paths_edges: - # Each node in the original graph maps to two nodes in auxiliary graph - yield list(_unique_everseen(H.nodes[node]["id"] for node in path)) - - -def _unique_everseen(iterable): - # Adapted from https://docs.python.org/3/library/itertools.html examples - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - seen = set() - seen_add = seen.add - for element in _filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_augmentation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_augmentation.py deleted file mode 100644 index 278a8e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_augmentation.py +++ /dev/null @@ -1,1270 +0,0 @@ -""" -Algorithms for finding k-edge-augmentations - -A k-edge-augmentation is a set of edges, that once added to a graph, ensures -that the graph is k-edge-connected; i.e. the graph cannot be disconnected -unless k or more edges are removed. Typically, the goal is to find the -augmentation with minimum weight. In general, it is not guaranteed that a -k-edge-augmentation exists. - -See Also --------- -:mod:`edge_kcomponents` : algorithms for finding k-edge-connected components -:mod:`connectivity` : algorithms for determining edge connectivity. -""" - -import itertools as it -import math -from collections import defaultdict, namedtuple - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ["k_edge_augmentation", "is_k_edge_connected", "is_locally_k_edge_connected"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_k_edge_connected(G, k): - """Tests to see if a graph is k-edge-connected. - - Is it impossible to disconnect the graph by removing fewer than k edges? - If so, then G is k-edge-connected. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - edge connectivity to test for - - Returns - ------- - boolean - True if G is k-edge-connected. - - See Also - -------- - :func:`is_locally_k_edge_connected` - - Examples - -------- - >>> G = nx.barbell_graph(10, 0) - >>> nx.is_k_edge_connected(G, k=1) - True - >>> nx.is_k_edge_connected(G, k=2) - False - """ - if k < 1: - raise ValueError(f"k must be positive, not {k}") - # First try to quickly determine if G is not k-edge-connected - if G.number_of_nodes() < k + 1: - return False - elif any(d < k for n, d in G.degree()): - return False - else: - # Otherwise perform the full check - if k == 1: - return nx.is_connected(G) - elif k == 2: - return nx.is_connected(G) and not nx.has_bridges(G) - else: - return nx.edge_connectivity(G, cutoff=k) >= k - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_locally_k_edge_connected(G, s, t, k): - """Tests to see if an edge in a graph is locally k-edge-connected. - - Is it impossible to disconnect s and t by removing fewer than k edges? - If so, then s and t are locally k-edge-connected in G. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - s : node - Source node - - t : node - Target node - - k : integer - local edge connectivity for nodes s and t - - Returns - ------- - boolean - True if s and t are locally k-edge-connected in G. - - See Also - -------- - :func:`is_k_edge_connected` - - Examples - -------- - >>> from networkx.algorithms.connectivity import is_locally_k_edge_connected - >>> G = nx.barbell_graph(10, 0) - >>> is_locally_k_edge_connected(G, 5, 15, k=1) - True - >>> is_locally_k_edge_connected(G, 5, 15, k=2) - False - >>> is_locally_k_edge_connected(G, 1, 5, k=2) - True - """ - if k < 1: - raise ValueError(f"k must be positive, not {k}") - - # First try to quickly determine s, t is not k-locally-edge-connected in G - if G.degree(s) < k or G.degree(t) < k: - return False - else: - # Otherwise perform the full check - if k == 1: - return nx.has_path(G, s, t) - else: - localk = nx.connectivity.local_edge_connectivity(G, s, t, cutoff=k) - return localk >= k - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def k_edge_augmentation(G, k, avail=None, weight=None, partial=False): - """Finds set of edges to k-edge-connect G. - - Adding edges from the augmentation to G make it impossible to disconnect G - unless k or more edges are removed. This function uses the most efficient - function available (depending on the value of k and if the problem is - weighted or unweighted) to search for a minimum weight subset of available - edges that k-edge-connects G. In general, finding a k-edge-augmentation is - NP-hard, so solutions are not guaranteed to be minimal. Furthermore, a - k-edge-augmentation may not exist. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - The available edges that can be used in the augmentation. - - If unspecified, then all edges in the complement of G are available. - Otherwise, each item is an available edge (with an optional weight). - - In the unweighted case, each item is an edge ``(u, v)``. - - In the weighted case, each item is a 3-tuple ``(u, v, d)`` or a dict - with items ``(u, v): d``. The third item, ``d``, can be a dictionary - or a real number. If ``d`` is a dictionary ``d[weight]`` - correspondings to the weight. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples where the - third item in each tuple is a dictionary. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then all - a partial k-edge-augmentation is generated. Adding the edges in a - partial augmentation to G, minimizes the number of k-edge-connected - components and maximizes the edge connectivity between those - components. For details, see :func:`partial_k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges that, once added to G, would cause G to become k-edge-connected. - If partial is False, an error is raised if this is not possible. - Otherwise, generated edges form a partial augmentation, which - k-edge-connects any part of G where it is possible, and maximally - connects the remaining parts. - - Raises - ------ - NetworkXUnfeasible - If partial is False and no k-edge-augmentation exists. - - NetworkXNotImplemented - If the input graph is directed or a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - When k=1 this returns an optimal solution. - - When k=2 and ``avail`` is None, this returns an optimal solution. - Otherwise when k=2, this returns a 2-approximation of the optimal solution. - - For k>3, this problem is NP-hard and this uses a randomized algorithm that - produces a feasible solution, but provides no guarantees on the - solution weight. - - Examples - -------- - >>> # Unweighted cases - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> sorted(nx.k_edge_augmentation(G, k=1)) - [(1, 5)] - >>> sorted(nx.k_edge_augmentation(G, k=2)) - [(1, 5), (5, 4)] - >>> sorted(nx.k_edge_augmentation(G, k=3)) - [(1, 4), (1, 5), (2, 5), (3, 5), (4, 5)] - >>> complement = list(nx.k_edge_augmentation(G, k=5, partial=True)) - >>> G.add_edges_from(complement) - >>> nx.edge_connectivity(G) - 4 - - >>> # Weighted cases - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> # avail can be a tuple with a dict - >>> avail = [(1, 5, {"weight": 11}), (2, 5, {"weight": 10})] - >>> sorted(nx.k_edge_augmentation(G, k=1, avail=avail, weight="weight")) - [(2, 5)] - >>> # or avail can be a 3-tuple with a real number - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)] - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - >>> # or avail can be a dict - >>> avail = {(1, 5): 11, (2, 5): 10, (4, 3): 1, (4, 5): 51} - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - >>> # If augmentation is infeasible, then a partial solution can be found - >>> avail = {(1, 5): 11} - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail, partial=True)) - [(1, 5)] - """ - try: - if k <= 0: - raise ValueError(f"k must be a positive integer, not {k}") - elif G.number_of_nodes() < k + 1: - msg = f"impossible to {k} connect in graph with less than {k + 1} nodes" - raise nx.NetworkXUnfeasible(msg) - elif avail is not None and len(avail) == 0: - if not nx.is_k_edge_connected(G, k): - raise nx.NetworkXUnfeasible("no available edges") - aug_edges = [] - elif k == 1: - aug_edges = one_edge_augmentation( - G, avail=avail, weight=weight, partial=partial - ) - elif k == 2: - aug_edges = bridge_augmentation(G, avail=avail, weight=weight) - else: - # raise NotImplementedError(f'not implemented for k>2. k={k}') - aug_edges = greedy_k_edge_augmentation( - G, k=k, avail=avail, weight=weight, seed=0 - ) - # Do eager evaluation so we can catch any exceptions - # Before executing partial code. - yield from list(aug_edges) - except nx.NetworkXUnfeasible: - if partial: - # Return all available edges - if avail is None: - aug_edges = complement_edges(G) - else: - # If we can't k-edge-connect the entire graph, try to - # k-edge-connect as much as possible - aug_edges = partial_k_edge_augmentation( - G, k=k, avail=avail, weight=weight - ) - yield from aug_edges - else: - raise - - -@nx._dispatchable -def partial_k_edge_augmentation(G, k, avail, weight=None): - """Finds augmentation that k-edge-connects as much of the graph as possible. - - When a k-edge-augmentation is not possible, we can still try to find a - small set of edges that partially k-edge-connects as much of the graph as - possible. All possible edges are generated between remaining parts. - This minimizes the number of k-edge-connected subgraphs in the resulting - graph and maximizes the edge connectivity between those subgraphs. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges in the partial augmentation of G. These edges k-edge-connect any - part of G where it is possible, and maximally connects the remaining - parts. In other words, all edges from avail are generated except for - those within subgraphs that have already become k-edge-connected. - - Notes - ----- - Construct H that augments G with all edges in avail. - Find the k-edge-subgraphs of H. - For each k-edge-subgraph, if the number of nodes is more than k, then find - the k-edge-augmentation of that graph and add it to the solution. Then add - all edges in avail between k-edge subgraphs to the solution. - - See Also - -------- - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> G.add_node(8) - >>> avail = [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5), (1, 8)] - >>> sorted(partial_k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (1, 8)] - """ - - def _edges_between_disjoint(H, only1, only2): - """finds edges between disjoint nodes""" - only1_adj = {u: set(H.adj[u]) for u in only1} - for u, neighbs in only1_adj.items(): - # Find the neighbors of u in only1 that are also in only2 - neighbs12 = neighbs.intersection(only2) - for v in neighbs12: - yield (u, v) - - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - - # Find which parts of the graph can be k-edge-connected - H = G.copy() - H.add_edges_from( - ( - (u, v, {"weight": w, "generator": (u, v)}) - for (u, v), w in zip(avail, avail_w) - ) - ) - k_edge_subgraphs = list(nx.k_edge_subgraphs(H, k=k)) - - # Generate edges to k-edge-connect internal subgraphs - for nodes in k_edge_subgraphs: - if len(nodes) > 1: - # Get the k-edge-connected subgraph - C = H.subgraph(nodes).copy() - # Find the internal edges that were available - sub_avail = { - d["generator"]: d["weight"] - for (u, v, d) in C.edges(data=True) - if "generator" in d - } - # Remove potential augmenting edges - C.remove_edges_from(sub_avail.keys()) - # Find a subset of these edges that makes the component - # k-edge-connected and ignore the rest - yield from nx.k_edge_augmentation(C, k=k, avail=sub_avail) - - # Generate all edges between CCs that could not be k-edge-connected - for cc1, cc2 in it.combinations(k_edge_subgraphs, 2): - for u, v in _edges_between_disjoint(H, cc1, cc2): - d = H.get_edge_data(u, v) - edge = d.get("generator", None) - if edge is not None: - yield edge - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable -def one_edge_augmentation(G, avail=None, weight=None, partial=False): - """Finds minimum weight set of edges to connect G. - - Equivalent to :func:`k_edge_augmentation` when k=1. Adding the resulting - edges to G will make it 1-edge-connected. The solution is optimal for both - weighted and non-weighted variants. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then the - augmenting edges minimize the number of connected components. - - Yields - ------ - edge : tuple - Edges in the one-augmentation of G - - Raises - ------ - NetworkXUnfeasible - If partial is False and no one-edge-augmentation exists. - - Notes - ----- - Uses either :func:`unconstrained_one_edge_augmentation` or - :func:`weighted_one_edge_augmentation` depending on whether ``avail`` is - specified. Both algorithms are based on finding a minimum spanning tree. - As such both algorithms find optimal solutions and run in linear time. - - See Also - -------- - :func:`k_edge_augmentation` - """ - if avail is None: - return unconstrained_one_edge_augmentation(G) - else: - return weighted_one_edge_augmentation( - G, avail=avail, weight=weight, partial=partial - ) - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable -def bridge_augmentation(G, avail=None, weight=None): - """Finds the a set of edges that bridge connects G. - - Equivalent to :func:`k_edge_augmentation` when k=2, and partial=False. - Adding the resulting edges to G will make it 2-edge-connected. If no - constraints are specified the returned set of edges is minimum an optimal, - otherwise the solution is approximated. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges in the bridge-augmentation of G - - Raises - ------ - NetworkXUnfeasible - If no bridge-augmentation exists. - - Notes - ----- - If there are no constraints the solution can be computed in linear time - using :func:`unconstrained_bridge_augmentation`. Otherwise, the problem - becomes NP-hard and is the solution is approximated by - :func:`weighted_bridge_augmentation`. - - See Also - -------- - :func:`k_edge_augmentation` - """ - if G.number_of_nodes() < 3: - raise nx.NetworkXUnfeasible("impossible to bridge connect less than 3 nodes") - if avail is None: - return unconstrained_bridge_augmentation(G) - else: - return weighted_bridge_augmentation(G, avail, weight=weight) - - -# --- Algorithms and Helpers --- - - -def _ordered(u, v): - """Returns the nodes in an undirected edge in lower-triangular order""" - return (u, v) if u < v else (v, u) - - -def _unpack_available_edges(avail, weight=None, G=None): - """Helper to separate avail into edges and corresponding weights""" - if weight is None: - weight = "weight" - if isinstance(avail, dict): - avail_uv = list(avail.keys()) - avail_w = list(avail.values()) - else: - - def _try_getitem(d): - try: - return d[weight] - except TypeError: - return d - - avail_uv = [tup[0:2] for tup in avail] - avail_w = [1 if len(tup) == 2 else _try_getitem(tup[-1]) for tup in avail] - - if G is not None: - # Edges already in the graph are filtered - flags = [not G.has_edge(u, v) for u, v in avail_uv] - avail_uv = list(it.compress(avail_uv, flags)) - avail_w = list(it.compress(avail_w, flags)) - return avail_uv, avail_w - - -MetaEdge = namedtuple("MetaEdge", ("meta_uv", "uv", "w")) - - -def _lightest_meta_edges(mapping, avail_uv, avail_w): - """Maps available edges in the original graph to edges in the metagraph. - - Parameters - ---------- - mapping : dict - mapping produced by :func:`collapse`, that maps each node in the - original graph to a node in the meta graph - - avail_uv : list - list of edges - - avail_w : list - list of edge weights - - Notes - ----- - Each node in the metagraph is a k-edge-connected component in the original - graph. We don't care about any edge within the same k-edge-connected - component, so we ignore self edges. We also are only interested in the - minimum weight edge bridging each k-edge-connected component so, we group - the edges by meta-edge and take the lightest in each group. - - Examples - -------- - >>> # Each group represents a meta-node - >>> groups = ([1, 2, 3], [4, 5], [6]) - >>> mapping = {n: meta_n for meta_n, ns in enumerate(groups) for n in ns} - >>> avail_uv = [(1, 2), (3, 6), (1, 4), (5, 2), (6, 1), (2, 6), (3, 1)] - >>> avail_w = [20, 99, 20, 15, 50, 99, 20] - >>> sorted(_lightest_meta_edges(mapping, avail_uv, avail_w)) - [MetaEdge(meta_uv=(0, 1), uv=(5, 2), w=15), MetaEdge(meta_uv=(0, 2), uv=(6, 1), w=50)] - """ - grouped_wuv = defaultdict(list) - for w, (u, v) in zip(avail_w, avail_uv): - # Order the meta-edge so it can be used as a dict key - meta_uv = _ordered(mapping[u], mapping[v]) - # Group each available edge using the meta-edge as a key - grouped_wuv[meta_uv].append((w, u, v)) - - # Now that all available edges are grouped, choose one per group - for (mu, mv), choices_wuv in grouped_wuv.items(): - # Ignore available edges within the same meta-node - if mu != mv: - # Choose the lightest available edge belonging to each meta-edge - w, u, v = min(choices_wuv) - yield MetaEdge((mu, mv), (u, v), w) - - -@nx._dispatchable -def unconstrained_one_edge_augmentation(G): - """Finds the smallest set of edges to connect G. - - This is a variant of the unweighted MST problem. - If G is not empty, a feasible solution always exists. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Yields - ------ - edge : tuple - Edges in the one-edge-augmentation of G - - See Also - -------- - :func:`one_edge_augmentation` - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)]) - >>> G.add_nodes_from([6, 7, 8]) - >>> sorted(unconstrained_one_edge_augmentation(G)) - [(1, 4), (4, 6), (6, 7), (7, 8)] - """ - ccs1 = list(nx.connected_components(G)) - C = collapse(G, ccs1) - # When we are not constrained, we can just make a meta graph tree. - meta_nodes = list(C.nodes()) - # build a path in the metagraph - meta_aug = list(zip(meta_nodes, meta_nodes[1:])) - # map that path to the original graph - inverse = defaultdict(list) - for k, v in C.graph["mapping"].items(): - inverse[v].append(k) - for mu, mv in meta_aug: - yield (inverse[mu][0], inverse[mv][0]) - - -@nx._dispatchable -def weighted_one_edge_augmentation(G, avail, weight=None, partial=False): - """Finds the minimum weight set of edges to connect G if one exists. - - This is a variant of the weighted MST problem. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then the - augmenting edges minimize the number of connected components. - - Yields - ------ - edge : tuple - Edges in the subset of avail chosen to connect G. - - See Also - -------- - :func:`one_edge_augmentation` - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)]) - >>> G.add_nodes_from([6, 7, 8]) - >>> # any edge not in avail has an implicit weight of infinity - >>> avail = [(1, 3), (1, 5), (4, 7), (4, 8), (6, 1), (8, 1), (8, 2)] - >>> sorted(weighted_one_edge_augmentation(G, avail)) - [(1, 5), (4, 7), (6, 1), (8, 1)] - >>> # find another solution by giving large weights to edges in the - >>> # previous solution (note some of the old edges must be used) - >>> avail = [(1, 3), (1, 5, 99), (4, 7, 9), (6, 1, 99), (8, 1, 99), (8, 2)] - >>> sorted(weighted_one_edge_augmentation(G, avail)) - [(1, 5), (4, 7), (6, 1), (8, 2)] - """ - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - # Collapse CCs in the original graph into nodes in a metagraph - # Then find an MST of the metagraph instead of the original graph - C = collapse(G, nx.connected_components(G)) - mapping = C.graph["mapping"] - # Assign each available edge to an edge in the metagraph - candidate_mapping = _lightest_meta_edges(mapping, avail_uv, avail_w) - # nx.set_edge_attributes(C, name='weight', values=0) - C.add_edges_from( - (mu, mv, {"weight": w, "generator": uv}) - for (mu, mv), uv, w in candidate_mapping - ) - # Find MST of the meta graph - meta_mst = nx.minimum_spanning_tree(C) - if not partial and not nx.is_connected(meta_mst): - raise nx.NetworkXUnfeasible("Not possible to connect G with available edges") - # Yield the edge that generated the meta-edge - for mu, mv, d in meta_mst.edges(data=True): - if "generator" in d: - edge = d["generator"] - yield edge - - -@nx._dispatchable -def unconstrained_bridge_augmentation(G): - """Finds an optimal 2-edge-augmentation of G using the fewest edges. - - This is an implementation of the algorithm detailed in [1]_. - The basic idea is to construct a meta-graph of bridge-ccs, connect leaf - nodes of the trees to connect the entire graph, and finally connect the - leafs of the tree in dfs-preorder to bridge connect the entire graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Yields - ------ - edge : tuple - Edges in the bridge augmentation of G - - Notes - ----- - Input: a graph G. - First find the bridge components of G and collapse each bridge-cc into a - node of a metagraph graph C, which is guaranteed to be a forest of trees. - - C contains p "leafs" --- nodes with exactly one incident edge. - C contains q "isolated nodes" --- nodes with no incident edges. - - Theorem: If p + q > 1, then at least :math:`ceil(p / 2) + q` edges are - needed to bridge connect C. This algorithm achieves this min number. - - The method first adds enough edges to make G into a tree and then pairs - leafs in a simple fashion. - - Let n be the number of trees in C. Let v(i) be an isolated vertex in the - i-th tree if one exists, otherwise it is a pair of distinct leafs nodes - in the i-th tree. Alternating edges from these sets (i.e. adding edges - A1 = [(v(i)[0], v(i + 1)[1]), v(i + 1)[0], v(i + 2)[1])...]) connects C - into a tree T. This tree has p' = p + 2q - 2(n -1) leafs and no isolated - vertices. A1 has n - 1 edges. The next step finds ceil(p' / 2) edges to - biconnect any tree with p' leafs. - - Convert T into an arborescence T' by picking an arbitrary root node with - degree >= 2 and directing all edges away from the root. Note the - implementation implicitly constructs T'. - - The leafs of T are the nodes with no existing edges in T'. - Order the leafs of T' by DFS preorder. Then break this list in half - and add the zipped pairs to A2. - - The set A = A1 + A2 is the minimum augmentation in the metagraph. - - To convert this to edges in the original graph - - References - ---------- - .. [1] Eswaran, Kapali P., and R. Endre Tarjan. (1975) Augmentation problems. - http://epubs.siam.org/doi/abs/10.1137/0205044 - - See Also - -------- - :func:`bridge_augmentation` - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 7)] - >>> G = nx.path_graph((1, 2, 3, 2, 4, 5, 6, 7)) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 3), (3, 7)] - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)]) - >>> G.add_node(4) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 4), (4, 0)] - """ - # ----- - # Mapping of terms from (Eswaran and Tarjan): - # G = G_0 - the input graph - # C = G_0' - the bridge condensation of G. (This is a forest of trees) - # A1 = A_1 - the edges to connect the forest into a tree - # leaf = pendant - a node with degree of 1 - - # alpha(v) = maps the node v in G to its meta-node in C - # beta(x) = maps the meta-node x in C to any node in the bridge - # component of G corresponding to x. - - # find the 2-edge-connected components of G - bridge_ccs = list(nx.connectivity.bridge_components(G)) - # condense G into an forest C - C = collapse(G, bridge_ccs) - - # Choose pairs of distinct leaf nodes in each tree. If this is not - # possible then make a pair using the single isolated node in the tree. - vset1 = [ - tuple(cc) * 2 # case1: an isolated node - if len(cc) == 1 - else sorted(cc, key=C.degree)[0:2] # case2: pair of leaf nodes - for cc in nx.connected_components(C) - ] - if len(vset1) > 1: - # Use this set to construct edges that connect C into a tree. - nodes1 = [vs[0] for vs in vset1] - nodes2 = [vs[1] for vs in vset1] - A1 = list(zip(nodes1[1:], nodes2)) - else: - A1 = [] - # Connect each tree in the forest to construct an arborescence - T = C.copy() - T.add_edges_from(A1) - - # If there are only two leaf nodes, we simply connect them. - leafs = [n for n, d in T.degree() if d == 1] - if len(leafs) == 1: - A2 = [] - if len(leafs) == 2: - A2 = [tuple(leafs)] - else: - # Choose an arbitrary non-leaf root - try: - root = next(n for n, d in T.degree() if d > 1) - except StopIteration: # no nodes found with degree > 1 - return - # order the leaves of C by (induced directed) preorder - v2 = [n for n in nx.dfs_preorder_nodes(T, root) if T.degree(n) == 1] - # connecting first half of the leafs in pre-order to the second - # half will bridge connect the tree with the fewest edges. - half = math.ceil(len(v2) / 2) - A2 = list(zip(v2[:half], v2[-half:])) - - # collect the edges used to augment the original forest - aug_tree_edges = A1 + A2 - - # Construct the mapping (beta) from meta-nodes to regular nodes - inverse = defaultdict(list) - for k, v in C.graph["mapping"].items(): - inverse[v].append(k) - # sort so we choose minimum degree nodes first - inverse = { - mu: sorted(mapped, key=lambda u: (G.degree(u), u)) - for mu, mapped in inverse.items() - } - - # For each meta-edge, map back to an arbitrary pair in the original graph - G2 = G.copy() - for mu, mv in aug_tree_edges: - # Find the first available edge that doesn't exist and return it - for u, v in it.product(inverse[mu], inverse[mv]): - if not G2.has_edge(u, v): - G2.add_edge(u, v) - yield u, v - break - - -@nx._dispatchable -def weighted_bridge_augmentation(G, avail, weight=None): - """Finds an approximate min-weight 2-edge-augmentation of G. - - This is an implementation of the approximation algorithm detailed in [1]_. - It chooses a set of edges from avail to add to G that renders it - 2-edge-connected if such a subset exists. This is done by finding a - minimum spanning arborescence of a specially constructed metagraph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : set of 2 or 3 tuples. - candidate edges (with optional weights) to choose from - - weight : string - key to use to find weights if avail is a set of 3-tuples where the - third item in each tuple is a dictionary. - - Yields - ------ - edge : tuple - Edges in the subset of avail chosen to bridge augment G. - - Notes - ----- - Finding a weighted 2-edge-augmentation is NP-hard. - Any edge not in ``avail`` is considered to have a weight of infinity. - The approximation factor is 2 if ``G`` is connected and 3 if it is not. - Runs in :math:`O(m + n log(n))` time - - References - ---------- - .. [1] Khuller, Samir, and Ramakrishna Thurimella. (1993) Approximation - algorithms for graph augmentation. - http://www.sciencedirect.com/science/article/pii/S0196677483710102 - - See Also - -------- - :func:`bridge_augmentation` - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> # When the weights are equal, (1, 4) is the best - >>> avail = [(1, 4, 1), (1, 3, 1), (2, 4, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail)) - [(1, 4)] - >>> # Giving (1, 4) a high weight makes the two edge solution the best. - >>> avail = [(1, 4, 1000), (1, 3, 1), (2, 4, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail)) - [(1, 3), (2, 4)] - >>> # ------ - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail=avail)) - [(1, 5), (4, 5)] - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)] - >>> sorted(weighted_bridge_augmentation(G, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - """ - - if weight is None: - weight = "weight" - - # If input G is not connected the approximation factor increases to 3 - if not nx.is_connected(G): - H = G.copy() - connectors = list(one_edge_augmentation(H, avail=avail, weight=weight)) - H.add_edges_from(connectors) - - yield from connectors - else: - connectors = [] - H = G - - if len(avail) == 0: - if nx.has_bridges(H): - raise nx.NetworkXUnfeasible("no augmentation possible") - - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=H) - - # Collapse input into a metagraph. Meta nodes are bridge-ccs - bridge_ccs = nx.connectivity.bridge_components(H) - C = collapse(H, bridge_ccs) - - # Use the meta graph to shrink avail to a small feasible subset - mapping = C.graph["mapping"] - # Choose the minimum weight feasible edge in each group - meta_to_wuv = { - (mu, mv): (w, uv) - for (mu, mv), uv, w in _lightest_meta_edges(mapping, avail_uv, avail_w) - } - - # Mapping of terms from (Khuller and Thurimella): - # C : G_0 = (V, E^0) - # This is the metagraph where each node is a 2-edge-cc in G. - # The edges in C represent bridges in the original graph. - # (mu, mv) : E - E^0 # they group both avail and given edges in E - # T : \Gamma - # D : G^D = (V, E_D) - - # The paper uses ancestor because children point to parents, which is - # contrary to networkx standards. So, we actually need to run - # nx.least_common_ancestor on the reversed Tree. - - # Pick an arbitrary leaf from C as the root - try: - root = next(n for n, d in C.degree() if d == 1) - except StopIteration: # no nodes found with degree == 1 - return - # Root C into a tree TR by directing all edges away from the root - # Note in their paper T directs edges towards the root - TR = nx.dfs_tree(C, root) - - # Add to D the directed edges of T and set their weight to zero - # This indicates that it costs nothing to use edges that were given. - D = nx.reverse(TR).copy() - - nx.set_edge_attributes(D, name="weight", values=0) - - # The LCA of mu and mv in T is the shared ancestor of mu and mv that is - # located farthest from the root. - lca_gen = nx.tree_all_pairs_lowest_common_ancestor( - TR, root=root, pairs=meta_to_wuv.keys() - ) - - for (mu, mv), lca in lca_gen: - w, uv = meta_to_wuv[(mu, mv)] - if lca == mu: - # If u is an ancestor of v in TR, then add edge u->v to D - D.add_edge(lca, mv, weight=w, generator=uv) - elif lca == mv: - # If v is an ancestor of u in TR, then add edge v->u to D - D.add_edge(lca, mu, weight=w, generator=uv) - else: - # If neither u nor v is a ancestor of the other in TR - # let t = lca(TR, u, v) and add edges t->u and t->v - # Track the original edge that GENERATED these edges. - D.add_edge(lca, mu, weight=w, generator=uv) - D.add_edge(lca, mv, weight=w, generator=uv) - - # Then compute a minimum rooted branching - try: - # Note the original edges must be directed towards to root for the - # branching to give us a bridge-augmentation. - A = _minimum_rooted_branching(D, root) - except nx.NetworkXException as err: - # If there is no branching then augmentation is not possible - raise nx.NetworkXUnfeasible("no 2-edge-augmentation possible") from err - - # For each edge e, in the branching that did not belong to the directed - # tree T, add the corresponding edge that **GENERATED** it (this is not - # necessarily e itself!) - - # ensure the third case does not generate edges twice - bridge_connectors = set() - for mu, mv in A.edges(): - data = D.get_edge_data(mu, mv) - if "generator" in data: - # Add the avail edge that generated the branching edge. - edge = data["generator"] - bridge_connectors.add(edge) - - yield from bridge_connectors - - -def _minimum_rooted_branching(D, root): - """Helper function to compute a minimum rooted branching (aka rooted - arborescence) - - Before the branching can be computed, the directed graph must be rooted by - removing the predecessors of root. - - A branching / arborescence of rooted graph G is a subgraph that contains a - directed path from the root to every other vertex. It is the directed - analog of the minimum spanning tree problem. - - References - ---------- - [1] Khuller, Samir (2002) Advanced Algorithms Lecture 24 Notes. - https://web.archive.org/web/20121030033722/https://www.cs.umd.edu/class/spring2011/cmsc651/lec07.pdf - """ - rooted = D.copy() - # root the graph by removing all predecessors to `root`. - rooted.remove_edges_from([(u, root) for u in D.predecessors(root)]) - # Then compute the branching / arborescence. - A = nx.minimum_spanning_arborescence(rooted) - return A - - -@nx._dispatchable(returns_graph=True) -def collapse(G, grouped_nodes): - """Collapses each group of nodes into a single node. - - This is similar to condensation, but works on undirected graphs. - - Parameters - ---------- - G : NetworkX Graph - - grouped_nodes: list or generator - Grouping of nodes to collapse. The grouping must be disjoint. - If grouped_nodes are strongly_connected_components then this is - equivalent to :func:`condensation`. - - Returns - ------- - C : NetworkX Graph - The collapsed graph C of G with respect to the node grouping. The node - labels are integers corresponding to the index of the component in the - list of grouped_nodes. C has a graph attribute named 'mapping' with a - dictionary mapping the original nodes to the nodes in C to which they - belong. Each node in C also has a node attribute 'members' with the set - of original nodes in G that form the group that the node in C - represents. - - Examples - -------- - >>> # Collapses a graph using disjoint groups, but not necessarily connected - >>> G = nx.Graph([(1, 0), (2, 3), (3, 1), (3, 4), (4, 5), (5, 6), (5, 7)]) - >>> G.add_node("A") - >>> grouped_nodes = [{0, 1, 2, 3}, {5, 6, 7}] - >>> C = collapse(G, grouped_nodes) - >>> members = nx.get_node_attributes(C, "members") - >>> sorted(members.keys()) - [0, 1, 2, 3] - >>> member_values = set(map(frozenset, members.values())) - >>> assert {0, 1, 2, 3} in member_values - >>> assert {4} in member_values - >>> assert {5, 6, 7} in member_values - >>> assert {"A"} in member_values - """ - mapping = {} - members = {} - C = G.__class__() - i = 0 # required if G is empty - remaining = set(G.nodes()) - for i, group in enumerate(grouped_nodes): - group = set(group) - assert remaining.issuperset( - group - ), "grouped nodes must exist in G and be disjoint" - remaining.difference_update(group) - members[i] = group - mapping.update((n, i) for n in group) - # remaining nodes are in their own group - for i, node in enumerate(remaining, start=i + 1): - group = {node} - members[i] = group - mapping.update((n, i) for n in group) - number_of_groups = i + 1 - C.add_nodes_from(range(number_of_groups)) - C.add_edges_from( - (mapping[u], mapping[v]) for u, v in G.edges() if mapping[u] != mapping[v] - ) - # Add a list of members (ie original nodes) to each node (ie scc) in C. - nx.set_node_attributes(C, name="members", values=members) - # Add mapping dict as graph attribute - C.graph["mapping"] = mapping - return C - - -@nx._dispatchable -def complement_edges(G): - """Returns only the edges in the complement of G - - Parameters - ---------- - G : NetworkX Graph - - Yields - ------ - edge : tuple - Edges in the complement of G - - Examples - -------- - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> sorted(complement_edges(G)) - [(1, 3), (1, 4), (2, 4)] - >>> G = nx.path_graph((1, 2, 3, 4), nx.DiGraph()) - >>> sorted(complement_edges(G)) - [(1, 3), (1, 4), (2, 1), (2, 4), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3)] - >>> G = nx.complete_graph(1000) - >>> sorted(complement_edges(G)) - [] - """ - G_adj = G._adj # Store as a variable to eliminate attribute lookup - if G.is_directed(): - for u, v in it.combinations(G.nodes(), 2): - if v not in G_adj[u]: - yield (u, v) - if u not in G_adj[v]: - yield (v, u) - else: - for u, v in it.combinations(G.nodes(), 2): - if v not in G_adj[u]: - yield (u, v) - - -def _compat_shuffle(rng, input): - """wrapper around rng.shuffle for python 2 compatibility reasons""" - rng.shuffle(input) - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@py_random_state(4) -@nx._dispatchable -def greedy_k_edge_augmentation(G, k, avail=None, weight=None, seed=None): - """Greedy algorithm for finding a k-edge-augmentation - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Yields - ------ - edge : tuple - Edges in the greedy augmentation of G - - Notes - ----- - The algorithm is simple. Edges are incrementally added between parts of the - graph that are not yet locally k-edge-connected. Then edges are from the - augmenting set are pruned as long as local-edge-connectivity is not broken. - - This algorithm is greedy and does not provide optimality guarantees. It - exists only to provide :func:`k_edge_augmentation` with the ability to - generate a feasible solution for arbitrary k. - - See Also - -------- - :func:`k_edge_augmentation` - - Examples - -------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> sorted(greedy_k_edge_augmentation(G, k=2)) - [(1, 7)] - >>> sorted(greedy_k_edge_augmentation(G, k=1, avail=[])) - [] - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> avail = {(u, v): 1 for (u, v) in complement_edges(G)} - >>> # randomized pruning process can produce different solutions - >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=2)) - [(1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 4), (2, 6), (3, 7), (5, 7)] - >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=3)) - [(1, 3), (1, 5), (1, 6), (2, 4), (2, 6), (3, 7), (4, 7), (5, 7)] - """ - # Result set - aug_edges = [] - - done = is_k_edge_connected(G, k) - if done: - return - if avail is None: - # all edges are available - avail_uv = list(complement_edges(G)) - avail_w = [1] * len(avail_uv) - else: - # Get the unique set of unweighted edges - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - - # Greedy: order lightest edges. Use degree sum to tie-break - tiebreaker = [sum(map(G.degree, uv)) for uv in avail_uv] - avail_wduv = sorted(zip(avail_w, tiebreaker, avail_uv)) - avail_uv = [uv for w, d, uv in avail_wduv] - - # Incrementally add edges in until we are k-connected - H = G.copy() - for u, v in avail_uv: - done = False - if not is_locally_k_edge_connected(H, u, v, k=k): - # Only add edges in parts that are not yet locally k-edge-connected - aug_edges.append((u, v)) - H.add_edge(u, v) - # Did adding this edge help? - if H.degree(u) >= k and H.degree(v) >= k: - done = is_k_edge_connected(H, k) - if done: - break - - # Check for feasibility - if not done: - raise nx.NetworkXUnfeasible("not able to k-edge-connect with available edges") - - # Randomized attempt to reduce the size of the solution - _compat_shuffle(seed, aug_edges) - for u, v in list(aug_edges): - # Don't remove if we know it would break connectivity - if H.degree(u) <= k or H.degree(v) <= k: - continue - H.remove_edge(u, v) - aug_edges.remove((u, v)) - if not is_k_edge_connected(H, k=k): - # If removing this edge breaks feasibility, undo - H.add_edge(u, v) - aug_edges.append((u, v)) - - # Generate results - yield from aug_edges diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_kcomponents.py deleted file mode 100644 index 96886f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/edge_kcomponents.py +++ /dev/null @@ -1,592 +0,0 @@ -""" -Algorithms for finding k-edge-connected components and subgraphs. - -A k-edge-connected component (k-edge-cc) is a maximal set of nodes in G, such -that all pairs of node have an edge-connectivity of at least k. - -A k-edge-connected subgraph (k-edge-subgraph) is a maximal set of nodes in G, -such that the subgraph of G defined by the nodes has an edge-connectivity at -least k. -""" - -import itertools as it -from functools import partial - -import networkx as nx -from networkx.utils import arbitrary_element, not_implemented_for - -__all__ = [ - "k_edge_components", - "k_edge_subgraphs", - "bridge_components", - "EdgeComponentAuxGraph", -] - - -@not_implemented_for("multigraph") -@nx._dispatchable -def k_edge_components(G, k): - """Generates nodes in each maximal k-edge-connected component in G. - - Parameters - ---------- - G : NetworkX graph - - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_components : a generator of k-edge-ccs. Each set of returned nodes - will have k-edge-connectivity in the graph G. - - See Also - -------- - :func:`local_edge_connectivity` - :func:`k_edge_subgraphs` : similar to this function, but the subgraph - defined by the nodes must also have k-edge-connectivity. - :func:`k_components` : similar to this function, but uses node-connectivity - instead of edge-connectivity - - Raises - ------ - NetworkXNotImplemented - If the input graph is a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - Attempts to use the most efficient implementation available based on k. - If k=1, this is simply connected components for directed graphs and - connected components for undirected graphs. - If k=2 on an efficient bridge connected component algorithm from _[1] is - run based on the chain decomposition. - Otherwise, the algorithm from _[2] is used. - - Examples - -------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... (5, 6, 7, 8, 5, 7, 8, 6), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # note this returns {1, 4} unlike k_edge_subgraphs - >>> sorted(map(sorted, nx.k_edge_components(G, k=3))) - [[1, 4], [2], [3], [5, 6, 7, 8]] - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29 - .. [2] Wang, Tianhao, et al. (2015) A simple algorithm for finding all - k-edge-connected components. - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - """ - # Compute k-edge-ccs using the most efficient algorithms available. - if k < 1: - raise ValueError("k cannot be less than 1") - if G.is_directed(): - if k == 1: - return nx.strongly_connected_components(G) - else: - # TODO: investigate https://arxiv.org/abs/1412.6466 for k=2 - aux_graph = EdgeComponentAuxGraph.construct(G) - return aux_graph.k_edge_components(k) - else: - if k == 1: - return nx.connected_components(G) - elif k == 2: - return bridge_components(G) - else: - aux_graph = EdgeComponentAuxGraph.construct(G) - return aux_graph.k_edge_components(k) - - -@not_implemented_for("multigraph") -@nx._dispatchable -def k_edge_subgraphs(G, k): - """Generates nodes in each maximal k-edge-connected subgraph in G. - - Parameters - ---------- - G : NetworkX graph - - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_subgraphs : a generator of k-edge-subgraphs - Each k-edge-subgraph is a maximal set of nodes that defines a subgraph - of G that is k-edge-connected. - - See Also - -------- - :func:`edge_connectivity` - :func:`k_edge_components` : similar to this function, but nodes only - need to have k-edge-connectivity within the graph G and the subgraphs - might not be k-edge-connected. - - Raises - ------ - NetworkXNotImplemented - If the input graph is a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - Attempts to use the most efficient implementation available based on k. - If k=1, or k=2 and the graph is undirected, then this simply calls - `k_edge_components`. Otherwise the algorithm from _[1] is used. - - Examples - -------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... (5, 6, 7, 8, 5, 7, 8, 6), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # note this does not return {1, 4} unlike k_edge_components - >>> sorted(map(sorted, nx.k_edge_subgraphs(G, k=3))) - [[1], [2], [3], [4], [5, 6, 7, 8]] - - References - ---------- - .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs - from a large graph. ACM International Conference on Extending Database - Technology 2012 480-–491. - https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf - """ - if k < 1: - raise ValueError("k cannot be less than 1") - if G.is_directed(): - if k <= 1: - # For directed graphs , - # When k == 1, k-edge-ccs and k-edge-subgraphs are the same - return k_edge_components(G, k) - else: - return _k_edge_subgraphs_nodes(G, k) - else: - if k <= 2: - # For undirected graphs, - # when k <= 2, k-edge-ccs and k-edge-subgraphs are the same - return k_edge_components(G, k) - else: - return _k_edge_subgraphs_nodes(G, k) - - -def _k_edge_subgraphs_nodes(G, k): - """Helper to get the nodes from the subgraphs. - - This allows k_edge_subgraphs to return a generator. - """ - for C in general_k_edge_subgraphs(G, k): - yield set(C.nodes()) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def bridge_components(G): - """Finds all bridge-connected components G. - - Parameters - ---------- - G : NetworkX undirected graph - - Returns - ------- - bridge_components : a generator of 2-edge-connected components - - - See Also - -------- - :func:`k_edge_subgraphs` : this function is a special case for an - undirected graph where k=2. - :func:`biconnected_components` : similar to this function, but is defined - using 2-node-connectivity instead of 2-edge-connectivity. - - Raises - ------ - NetworkXNotImplemented - If the input graph is directed or a multigraph. - - Notes - ----- - Bridge-connected components are also known as 2-edge-connected components. - - Examples - -------- - >>> # The barbell graph with parameter zero has a single bridge - >>> G = nx.barbell_graph(5, 0) - >>> from networkx.algorithms.connectivity.edge_kcomponents import bridge_components - >>> sorted(map(sorted, bridge_components(G))) - [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] - """ - H = G.copy() - H.remove_edges_from(nx.bridges(G)) - yield from nx.connected_components(H) - - -class EdgeComponentAuxGraph: - r"""A simple algorithm to find all k-edge-connected components in a graph. - - Constructing the auxiliary graph (which may take some time) allows for the - k-edge-ccs to be found in linear time for arbitrary k. - - Notes - ----- - This implementation is based on [1]_. The idea is to construct an auxiliary - graph from which the k-edge-ccs can be extracted in linear time. The - auxiliary graph is constructed in $O(|V|\cdot F)$ operations, where F is the - complexity of max flow. Querying the components takes an additional $O(|V|)$ - operations. This algorithm can be slow for large graphs, but it handles an - arbitrary k and works for both directed and undirected inputs. - - The undirected case for k=1 is exactly connected components. - The undirected case for k=2 is exactly bridge connected components. - The directed case for k=1 is exactly strongly connected components. - - References - ---------- - .. [1] Wang, Tianhao, et al. (2015) A simple algorithm for finding all - k-edge-connected components. - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - - Examples - -------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph - >>> # Build an interesting graph with multiple levels of k-edge-ccs - >>> paths = [ - ... (1, 2, 3, 4, 1, 3, 4, 2), # a 3-edge-cc (a 4 clique) - ... (5, 6, 7, 5), # a 2-edge-cc (a 3 clique) - ... (1, 5), # combine first two ccs into a 1-edge-cc - ... (0,), # add an additional disconnected 1-edge-cc - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # Constructing the AuxGraph takes about O(n ** 4) - >>> aux_graph = EdgeComponentAuxGraph.construct(G) - >>> # Once constructed, querying takes O(n) - >>> sorted(map(sorted, aux_graph.k_edge_components(k=1))) - [[0], [1, 2, 3, 4, 5, 6, 7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=2))) - [[0], [1, 2, 3, 4], [5, 6, 7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=3))) - [[0], [1, 2, 3, 4], [5], [6], [7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=4))) - [[0], [1], [2], [3], [4], [5], [6], [7]] - - The auxiliary graph is primarily used for k-edge-ccs but it - can also speed up the queries of k-edge-subgraphs by refining the - search space. - - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> aux_graph = EdgeComponentAuxGraph.construct(G) - >>> sorted(map(sorted, aux_graph.k_edge_subgraphs(k=3))) - [[1], [2], [3], [4]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=3))) - [[1, 4], [2], [3]] - """ - - # @not_implemented_for('multigraph') # TODO: fix decor for classmethods - @classmethod - def construct(EdgeComponentAuxGraph, G): - """Builds an auxiliary graph encoding edge-connectivity between nodes. - - Notes - ----- - Given G=(V, E), initialize an empty auxiliary graph A. - Choose an arbitrary source node s. Initialize a set N of available - nodes (that can be used as the sink). The algorithm picks an - arbitrary node t from N - {s}, and then computes the minimum st-cut - (S, T) with value w. If G is directed the minimum of the st-cut or - the ts-cut is used instead. Then, the edge (s, t) is added to the - auxiliary graph with weight w. The algorithm is called recursively - first using S as the available nodes and s as the source, and then - using T and t. Recursion stops when the source is the only available - node. - - Parameters - ---------- - G : NetworkX graph - """ - # workaround for classmethod decorator - not_implemented_for("multigraph")(lambda G: G)(G) - - def _recursive_build(H, A, source, avail): - # Terminate once the flow has been compute to every node. - if {source} == avail: - return - # pick an arbitrary node as the sink - sink = arbitrary_element(avail - {source}) - # find the minimum cut and its weight - value, (S, T) = nx.minimum_cut(H, source, sink) - if H.is_directed(): - # check if the reverse direction has a smaller cut - value_, (T_, S_) = nx.minimum_cut(H, sink, source) - if value_ < value: - value, S, T = value_, S_, T_ - # add edge with weight of cut to the aux graph - A.add_edge(source, sink, weight=value) - # recursively call until all but one node is used - _recursive_build(H, A, source, avail.intersection(S)) - _recursive_build(H, A, sink, avail.intersection(T)) - - # Copy input to ensure all edges have unit capacity - H = G.__class__() - H.add_nodes_from(G.nodes()) - H.add_edges_from(G.edges(), capacity=1) - - # A is the auxiliary graph to be constructed - # It is a weighted undirected tree - A = nx.Graph() - - # Pick an arbitrary node as the source - if H.number_of_nodes() > 0: - source = arbitrary_element(H.nodes()) - # Initialize a set of elements that can be chosen as the sink - avail = set(H.nodes()) - - # This constructs A - _recursive_build(H, A, source, avail) - - # This class is a container the holds the auxiliary graph A and - # provides access the k_edge_components function. - self = EdgeComponentAuxGraph() - self.A = A - self.H = H - return self - - def k_edge_components(self, k): - """Queries the auxiliary graph for k-edge-connected components. - - Parameters - ---------- - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_components : a generator of k-edge-ccs - - Notes - ----- - Given the auxiliary graph, the k-edge-connected components can be - determined in linear time by removing all edges with weights less than - k from the auxiliary graph. The resulting connected components are the - k-edge-ccs in the original graph. - """ - if k < 1: - raise ValueError("k cannot be less than 1") - A = self.A - # "traverse the auxiliary graph A and delete all edges with weights less - # than k" - aux_weights = nx.get_edge_attributes(A, "weight") - # Create a relevant graph with the auxiliary edges with weights >= k - R = nx.Graph() - R.add_nodes_from(A.nodes()) - R.add_edges_from(e for e, w in aux_weights.items() if w >= k) - - # Return the nodes that are k-edge-connected in the original graph - yield from nx.connected_components(R) - - def k_edge_subgraphs(self, k): - """Queries the auxiliary graph for k-edge-connected subgraphs. - - Parameters - ---------- - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_subgraphs : a generator of k-edge-subgraphs - - Notes - ----- - Refines the k-edge-ccs into k-edge-subgraphs. The running time is more - than $O(|V|)$. - - For single values of k it is faster to use `nx.k_edge_subgraphs`. - But for multiple values of k, it can be faster to build AuxGraph and - then use this method. - """ - if k < 1: - raise ValueError("k cannot be less than 1") - H = self.H - A = self.A - # "traverse the auxiliary graph A and delete all edges with weights less - # than k" - aux_weights = nx.get_edge_attributes(A, "weight") - # Create a relevant graph with the auxiliary edges with weights >= k - R = nx.Graph() - R.add_nodes_from(A.nodes()) - R.add_edges_from(e for e, w in aux_weights.items() if w >= k) - - # Return the components whose subgraphs are k-edge-connected - for cc in nx.connected_components(R): - if len(cc) < k: - # Early return optimization - for node in cc: - yield {node} - else: - # Call subgraph solution to refine the results - C = H.subgraph(cc) - yield from k_edge_subgraphs(C, k) - - -def _low_degree_nodes(G, k, nbunch=None): - """Helper for finding nodes with degree less than k.""" - # Nodes with degree less than k cannot be k-edge-connected. - if G.is_directed(): - # Consider both in and out degree in the directed case - seen = set() - for node, degree in G.out_degree(nbunch): - if degree < k: - seen.add(node) - yield node - for node, degree in G.in_degree(nbunch): - if node not in seen and degree < k: - seen.add(node) - yield node - else: - # Only the degree matters in the undirected case - for node, degree in G.degree(nbunch): - if degree < k: - yield node - - -def _high_degree_components(G, k): - """Helper for filtering components that can't be k-edge-connected. - - Removes and generates each node with degree less than k. Then generates - remaining components where all nodes have degree at least k. - """ - # Iteratively remove parts of the graph that are not k-edge-connected - H = G.copy() - singletons = set(_low_degree_nodes(H, k)) - while singletons: - # Only search neighbors of removed nodes - nbunch = set(it.chain.from_iterable(map(H.neighbors, singletons))) - nbunch.difference_update(singletons) - H.remove_nodes_from(singletons) - for node in singletons: - yield {node} - singletons = set(_low_degree_nodes(H, k, nbunch)) - - # Note: remaining connected components may not be k-edge-connected - if G.is_directed(): - yield from nx.strongly_connected_components(H) - else: - yield from nx.connected_components(H) - - -@nx._dispatchable(returns_graph=True) -def general_k_edge_subgraphs(G, k): - """General algorithm to find all maximal k-edge-connected subgraphs in `G`. - - Parameters - ---------- - G : nx.Graph - Graph in which all maximal k-edge-connected subgraphs will be found. - - k : int - - Yields - ------ - k_edge_subgraphs : Graph instances that are k-edge-subgraphs - Each k-edge-subgraph contains a maximal set of nodes that defines a - subgraph of `G` that is k-edge-connected. - - Notes - ----- - Implementation of the basic algorithm from [1]_. The basic idea is to find - a global minimum cut of the graph. If the cut value is at least k, then the - graph is a k-edge-connected subgraph and can be added to the results. - Otherwise, the cut is used to split the graph in two and the procedure is - applied recursively. If the graph is just a single node, then it is also - added to the results. At the end, each result is either guaranteed to be - a single node or a subgraph of G that is k-edge-connected. - - This implementation contains optimizations for reducing the number of calls - to max-flow, but there are other optimizations in [1]_ that could be - implemented. - - References - ---------- - .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs - from a large graph. ACM International Conference on Extending Database - Technology 2012 480-–491. - https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf - - Examples - -------- - >>> from networkx.utils import pairwise - >>> paths = [ - ... (11, 12, 13, 14, 11, 13, 14, 12), # a 4-clique - ... (21, 22, 23, 24, 21, 23, 24, 22), # another 4-clique - ... # connect the cliques with high degree but low connectivity - ... (50, 13), - ... (12, 50, 22), - ... (13, 102, 23), - ... (14, 101, 24), - ... ] - >>> G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - >>> sorted(len(k_sg) for k_sg in k_edge_subgraphs(G, k=3)) - [1, 1, 1, 4, 4] - """ - if k < 1: - raise ValueError("k cannot be less than 1") - - # Node pruning optimization (incorporates early return) - # find_ccs is either connected_components/strongly_connected_components - find_ccs = partial(_high_degree_components, k=k) - - # Quick return optimization - if G.number_of_nodes() < k: - for node in G.nodes(): - yield G.subgraph([node]).copy() - return - - # Intermediate results - R0 = {G.subgraph(cc).copy() for cc in find_ccs(G)} - # Subdivide CCs in the intermediate results until they are k-conn - while R0: - G1 = R0.pop() - if G1.number_of_nodes() == 1: - yield G1 - else: - # Find a global minimum cut - cut_edges = nx.minimum_edge_cut(G1) - cut_value = len(cut_edges) - if cut_value < k: - # G1 is not k-edge-connected, so subdivide it - G1.remove_edges_from(cut_edges) - for cc in find_ccs(G1): - R0.add(G1.subgraph(cc).copy()) - else: - # Otherwise we found a k-edge-connected subgraph - yield G1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcomponents.py deleted file mode 100644 index e2f1ba2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcomponents.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -Moody and White algorithm for k-components -""" - -from collections import defaultdict -from itertools import combinations -from operator import itemgetter - -import networkx as nx - -# Define the default maximum flow function. -from networkx.algorithms.flow import edmonds_karp -from networkx.utils import not_implemented_for - -default_flow_func = edmonds_karp - -__all__ = ["k_components"] - - -@not_implemented_for("directed") -@nx._dispatchable -def k_components(G, flow_func=None): - r"""Returns the k-component structure of a graph G. - - A `k`-component is a maximal subgraph of a graph G that has, at least, - node connectivity `k`: we need to remove at least `k` nodes to break it - into more components. `k`-components have an inherent hierarchical - structure because they are nested in terms of connectivity: a connected - graph can contain several 2-components, each of which can contain - one or more 3-components, and so forth. - - Parameters - ---------- - G : NetworkX graph - - flow_func : function - Function to perform the underlying flow computations. Default value - :meth:`edmonds_karp`. This function performs better in sparse graphs with - right tailed degree distributions. :meth:`shortest_augmenting_path` will - perform better in denser graphs. - - Returns - ------- - k_components : dict - Dictionary with all connectivity levels `k` in the input Graph as keys - and a list of sets of nodes that form a k-component of level `k` as - values. - - Raises - ------ - NetworkXNotImplemented - If the input graph is directed. - - Examples - -------- - >>> # Petersen graph has 10 nodes and it is triconnected, thus all - >>> # nodes are in a single component on all three connectivity levels - >>> G = nx.petersen_graph() - >>> k_components = nx.k_components(G) - - Notes - ----- - Moody and White [1]_ (appendix A) provide an algorithm for identifying - k-components in a graph, which is based on Kanevsky's algorithm [2]_ - for finding all minimum-size node cut-sets of a graph (implemented in - :meth:`all_node_cuts` function): - - 1. Compute node connectivity, k, of the input graph G. - - 2. Identify all k-cutsets at the current level of connectivity using - Kanevsky's algorithm. - - 3. Generate new graph components based on the removal of - these cutsets. Nodes in a cutset belong to both sides - of the induced cut. - - 4. If the graph is neither complete nor trivial, return to 1; - else end. - - This implementation also uses some heuristics (see [3]_ for details) - to speed up the computation. - - See also - -------- - node_connectivity - all_node_cuts - biconnected_components : special case of this function when k=2 - k_edge_components : similar to this function, but uses edge-connectivity - instead of node-connectivity - - References - ---------- - .. [1] Moody, J. and D. White (2003). Social cohesion and embeddedness: - A hierarchical conception of social groups. - American Sociological Review 68(1), 103--28. - http://www2.asanet.org/journals/ASRFeb03MoodyWhite.pdf - - .. [2] Kanevsky, A. (1993). Finding all minimum-size separating vertex - sets in a graph. Networks 23(6), 533--541. - http://onlinelibrary.wiley.com/doi/10.1002/net.3230230604/abstract - - .. [3] Torrents, J. and F. Ferraro (2015). Structural Cohesion: - Visualization and Heuristics for Fast Computation. - https://arxiv.org/pdf/1503.04476v1 - - """ - # Dictionary with connectivity level (k) as keys and a list of - # sets of nodes that form a k-component as values. Note that - # k-components can overlap (but only k - 1 nodes). - k_components = defaultdict(list) - # Define default flow function - if flow_func is None: - flow_func = default_flow_func - # Bicomponents as a base to check for higher order k-components - for component in nx.connected_components(G): - # isolated nodes have connectivity 0 - comp = set(component) - if len(comp) > 1: - k_components[1].append(comp) - bicomponents = [G.subgraph(c) for c in nx.biconnected_components(G)] - for bicomponent in bicomponents: - bicomp = set(bicomponent) - # avoid considering dyads as bicomponents - if len(bicomp) > 2: - k_components[2].append(bicomp) - for B in bicomponents: - if len(B) <= 2: - continue - k = nx.node_connectivity(B, flow_func=flow_func) - if k > 2: - k_components[k].append(set(B)) - # Perform cuts in a DFS like order. - cuts = list(nx.all_node_cuts(B, k=k, flow_func=flow_func)) - stack = [(k, _generate_partition(B, cuts, k))] - while stack: - (parent_k, partition) = stack[-1] - try: - nodes = next(partition) - C = B.subgraph(nodes) - this_k = nx.node_connectivity(C, flow_func=flow_func) - if this_k > parent_k and this_k > 2: - k_components[this_k].append(set(C)) - cuts = list(nx.all_node_cuts(C, k=this_k, flow_func=flow_func)) - if cuts: - stack.append((this_k, _generate_partition(C, cuts, this_k))) - except StopIteration: - stack.pop() - - # This is necessary because k-components may only be reported at their - # maximum k level. But we want to return a dictionary in which keys are - # connectivity levels and values list of sets of components, without - # skipping any connectivity level. Also, it's possible that subsets of - # an already detected k-component appear at a level k. Checking for this - # in the while loop above penalizes the common case. Thus we also have to - # _consolidate all connectivity levels in _reconstruct_k_components. - return _reconstruct_k_components(k_components) - - -def _consolidate(sets, k): - """Merge sets that share k or more elements. - - See: http://rosettacode.org/wiki/Set_consolidation - - The iterative python implementation posted there is - faster than this because of the overhead of building a - Graph and calling nx.connected_components, but it's not - clear for us if we can use it in NetworkX because there - is no licence for the code. - - """ - G = nx.Graph() - nodes = dict(enumerate(sets)) - G.add_nodes_from(nodes) - G.add_edges_from( - (u, v) for u, v in combinations(nodes, 2) if len(nodes[u] & nodes[v]) >= k - ) - for component in nx.connected_components(G): - yield set.union(*[nodes[n] for n in component]) - - -def _generate_partition(G, cuts, k): - def has_nbrs_in_partition(G, node, partition): - return any(n in partition for n in G[node]) - - components = [] - nodes = {n for n, d in G.degree() if d > k} - {n for cut in cuts for n in cut} - H = G.subgraph(nodes) - for cc in nx.connected_components(H): - component = set(cc) - for cut in cuts: - for node in cut: - if has_nbrs_in_partition(G, node, cc): - component.add(node) - if len(component) < G.order(): - components.append(component) - yield from _consolidate(components, k + 1) - - -def _reconstruct_k_components(k_comps): - result = {} - max_k = max(k_comps) - for k in reversed(range(1, max_k + 1)): - if k == max_k: - result[k] = list(_consolidate(k_comps[k], k)) - elif k not in k_comps: - result[k] = list(_consolidate(result[k + 1], k)) - else: - nodes_at_k = set.union(*k_comps[k]) - to_add = [c for c in result[k + 1] if any(n not in nodes_at_k for n in c)] - if to_add: - result[k] = list(_consolidate(k_comps[k] + to_add, k)) - else: - result[k] = list(_consolidate(k_comps[k], k)) - return result - - -def build_k_number_dict(kcomps): - result = {} - for k, comps in sorted(kcomps.items(), key=itemgetter(0)): - for comp in comps: - for node in comp: - result[node] = k - return result diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcutsets.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcutsets.py deleted file mode 100644 index de26f4c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/kcutsets.py +++ /dev/null @@ -1,235 +0,0 @@ -""" -Kanevsky all minimum node k cutsets algorithm. -""" - -import copy -from collections import defaultdict -from itertools import combinations -from operator import itemgetter - -import networkx as nx -from networkx.algorithms.flow import ( - build_residual_network, - edmonds_karp, - shortest_augmenting_path, -) - -from .utils import build_auxiliary_node_connectivity - -default_flow_func = edmonds_karp - - -__all__ = ["all_node_cuts"] - - -@nx._dispatchable -def all_node_cuts(G, k=None, flow_func=None): - r"""Returns all minimum k cutsets of an undirected graph G. - - This implementation is based on Kanevsky's algorithm [1]_ for finding all - minimum-size node cut-sets of an undirected graph G; ie the set (or sets) - of nodes of cardinality equal to the node connectivity of G. Thus if - removed, would break G into two or more connected components. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - k : Integer - Node connectivity of the input graph. If k is None, then it is - computed. Default value: None. - - flow_func : function - Function to perform the underlying flow computations. Default value is - :func:`~networkx.algorithms.flow.edmonds_karp`. This function performs - better in sparse graphs with right tailed degree distributions. - :func:`~networkx.algorithms.flow.shortest_augmenting_path` will - perform better in denser graphs. - - - Returns - ------- - cuts : a generator of node cutsets - Each node cutset has cardinality equal to the node connectivity of - the input graph. - - Examples - -------- - >>> # A two-dimensional grid graph has 4 cutsets of cardinality 2 - >>> G = nx.grid_2d_graph(5, 5) - >>> cutsets = list(nx.all_node_cuts(G)) - >>> len(cutsets) - 4 - >>> all(2 == len(cutset) for cutset in cutsets) - True - >>> nx.node_connectivity(G) - 2 - - Notes - ----- - This implementation is based on the sequential algorithm for finding all - minimum-size separating vertex sets in a graph [1]_. The main idea is to - compute minimum cuts using local maximum flow computations among a set - of nodes of highest degree and all other non-adjacent nodes in the Graph. - Once we find a minimum cut, we add an edge between the high degree - node and the target node of the local maximum flow computation to make - sure that we will not find that minimum cut again. - - See also - -------- - node_connectivity - edmonds_karp - shortest_augmenting_path - - References - ---------- - .. [1] Kanevsky, A. (1993). Finding all minimum-size separating vertex - sets in a graph. Networks 23(6), 533--541. - http://onlinelibrary.wiley.com/doi/10.1002/net.3230230604/abstract - - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Input graph is disconnected.") - - # Address some corner cases first. - # For complete Graphs - - if nx.density(G) == 1: - yield from () - return - - # Initialize data structures. - # Keep track of the cuts already computed so we do not repeat them. - seen = [] - # Even-Tarjan reduction is what we call auxiliary digraph - # for node connectivity. - H = build_auxiliary_node_connectivity(G) - H_nodes = H.nodes # for speed - mapping = H.graph["mapping"] - # Keep a copy of original predecessors, H will be modified later. - # Shallow copy is enough. - original_H_pred = copy.copy(H._pred) - R = build_residual_network(H, "capacity") - kwargs = {"capacity": "capacity", "residual": R} - # Define default flow function - if flow_func is None: - flow_func = default_flow_func - if flow_func is shortest_augmenting_path: - kwargs["two_phase"] = True - # Begin the actual algorithm - # step 1: Find node connectivity k of G - if k is None: - k = nx.node_connectivity(G, flow_func=flow_func) - # step 2: - # Find k nodes with top degree, call it X: - X = {n for n, d in sorted(G.degree(), key=itemgetter(1), reverse=True)[:k]} - # Check if X is a k-node-cutset - if _is_separating_set(G, X): - seen.append(X) - yield X - - for x in X: - # step 3: Compute local connectivity flow of x with all other - # non adjacent nodes in G - non_adjacent = set(G) - {x} - set(G[x]) - for v in non_adjacent: - # step 4: compute maximum flow in an Even-Tarjan reduction H of G - # and step 5: build the associated residual network R - R = flow_func(H, f"{mapping[x]}B", f"{mapping[v]}A", **kwargs) - flow_value = R.graph["flow_value"] - - if flow_value == k: - # Find the nodes incident to the flow. - E1 = flowed_edges = [ - (u, w) for (u, w, d) in R.edges(data=True) if d["flow"] != 0 - ] - VE1 = incident_nodes = {n for edge in E1 for n in edge} - # Remove saturated edges form the residual network. - # Note that reversed edges are introduced with capacity 0 - # in the residual graph and they need to be removed too. - saturated_edges = [ - (u, w, d) - for (u, w, d) in R.edges(data=True) - if d["capacity"] == d["flow"] or d["capacity"] == 0 - ] - R.remove_edges_from(saturated_edges) - R_closure = nx.transitive_closure(R) - # step 6: shrink the strongly connected components of - # residual flow network R and call it L. - L = nx.condensation(R) - cmap = L.graph["mapping"] - inv_cmap = defaultdict(list) - for n, scc in cmap.items(): - inv_cmap[scc].append(n) - # Find the incident nodes in the condensed graph. - VE1 = {cmap[n] for n in VE1} - # step 7: Compute all antichains of L; - # they map to closed sets in H. - # Any edge in H that links a closed set is part of a cutset. - for antichain in nx.antichains(L): - # Only antichains that are subsets of incident nodes counts. - # Lemma 8 in reference. - if not set(antichain).issubset(VE1): - continue - # Nodes in an antichain of the condensation graph of - # the residual network map to a closed set of nodes that - # define a node partition of the auxiliary digraph H - # through taking all of antichain's predecessors in the - # transitive closure. - S = set() - for scc in antichain: - S.update(inv_cmap[scc]) - S_ancestors = set() - for n in S: - S_ancestors.update(R_closure._pred[n]) - S.update(S_ancestors) - if f"{mapping[x]}B" not in S or f"{mapping[v]}A" in S: - continue - # Find the cutset that links the node partition (S,~S) in H - cutset = set() - for u in S: - cutset.update((u, w) for w in original_H_pred[u] if w not in S) - # The edges in H that form the cutset are internal edges - # (ie edges that represent a node of the original graph G) - if any(H_nodes[u]["id"] != H_nodes[w]["id"] for u, w in cutset): - continue - node_cut = {H_nodes[u]["id"] for u, _ in cutset} - - if len(node_cut) == k: - # The cut is invalid if it includes internal edges of - # end nodes. The other half of Lemma 8 in ref. - if x in node_cut or v in node_cut: - continue - if node_cut not in seen: - yield node_cut - seen.append(node_cut) - - # Add an edge (x, v) to make sure that we do not - # find this cutset again. This is equivalent - # of adding the edge in the input graph - # G.add_edge(x, v) and then regenerate H and R: - # Add edges to the auxiliary digraph. - # See build_residual_network for convention we used - # in residual graphs. - H.add_edge(f"{mapping[x]}B", f"{mapping[v]}A", capacity=1) - H.add_edge(f"{mapping[v]}B", f"{mapping[x]}A", capacity=1) - # Add edges to the residual network. - R.add_edge(f"{mapping[x]}B", f"{mapping[v]}A", capacity=1) - R.add_edge(f"{mapping[v]}A", f"{mapping[x]}B", capacity=0) - R.add_edge(f"{mapping[v]}B", f"{mapping[x]}A", capacity=1) - R.add_edge(f"{mapping[x]}A", f"{mapping[v]}B", capacity=0) - - # Add again the saturated edges to reuse the residual network - R.add_edges_from(saturated_edges) - - -def _is_separating_set(G, cut): - """Assumes that the input graph is connected""" - if len(cut) == len(G) - 1: - return True - - H = nx.restricted_view(G, cut, []) - if nx.is_connected(H): - return False - return True diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/stoerwagner.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/stoerwagner.py deleted file mode 100644 index 29604b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/stoerwagner.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -Stoer-Wagner minimum cut algorithm. -""" - -from itertools import islice - -import networkx as nx - -from ...utils import BinaryHeap, arbitrary_element, not_implemented_for - -__all__ = ["stoer_wagner"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def stoer_wagner(G, weight="weight", heap=BinaryHeap): - r"""Returns the weighted minimum edge cut using the Stoer-Wagner algorithm. - - Determine the minimum edge cut of a connected graph using the - Stoer-Wagner algorithm. In weighted cases, all weights must be - nonnegative. - - The running time of the algorithm depends on the type of heaps used: - - ============== ============================================= - Type of heap Running time - ============== ============================================= - Binary heap $O(n (m + n) \log n)$ - Fibonacci heap $O(nm + n^2 \log n)$ - Pairing heap $O(2^{2 \sqrt{\log \log n}} nm + n^2 \log n)$ - ============== ============================================= - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute named by the - weight parameter below. If this attribute is not present, the edge is - considered to have unit weight. - - weight : string - Name of the weight attribute of the edges. If the attribute is not - present, unit weight is assumed. Default value: 'weight'. - - heap : class - Type of heap to be used in the algorithm. It should be a subclass of - :class:`MinHeap` or implement a compatible interface. - - If a stock heap implementation is to be used, :class:`BinaryHeap` is - recommended over :class:`PairingHeap` for Python implementations without - optimized attribute accesses (e.g., CPython) despite a slower - asymptotic running time. For Python implementations with optimized - attribute accesses (e.g., PyPy), :class:`PairingHeap` provides better - performance. Default value: :class:`BinaryHeap`. - - Returns - ------- - cut_value : integer or float - The sum of weights of edges in a minimum cut. - - partition : pair of node lists - A partitioning of the nodes that defines a minimum cut. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or a multigraph. - - NetworkXError - If the graph has less than two nodes, is not connected or has a - negative-weighted edge. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge("x", "a", weight=3) - >>> G.add_edge("x", "b", weight=1) - >>> G.add_edge("a", "c", weight=3) - >>> G.add_edge("b", "c", weight=5) - >>> G.add_edge("b", "d", weight=4) - >>> G.add_edge("d", "e", weight=2) - >>> G.add_edge("c", "y", weight=2) - >>> G.add_edge("e", "y", weight=3) - >>> cut_value, partition = nx.stoer_wagner(G) - >>> cut_value - 4 - """ - n = len(G) - if n < 2: - raise nx.NetworkXError("graph has less than two nodes.") - if not nx.is_connected(G): - raise nx.NetworkXError("graph is not connected.") - - # Make a copy of the graph for internal use. - G = nx.Graph( - (u, v, {"weight": e.get(weight, 1)}) for u, v, e in G.edges(data=True) if u != v - ) - G.__networkx_cache__ = None # Disable caching - - for u, v, e in G.edges(data=True): - if e["weight"] < 0: - raise nx.NetworkXError("graph has a negative-weighted edge.") - - cut_value = float("inf") - nodes = set(G) - contractions = [] # contracted node pairs - - # Repeatedly pick a pair of nodes to contract until only one node is left. - for i in range(n - 1): - # Pick an arbitrary node u and create a set A = {u}. - u = arbitrary_element(G) - A = {u} - # Repeatedly pick the node "most tightly connected" to A and add it to - # A. The tightness of connectivity of a node not in A is defined by the - # of edges connecting it to nodes in A. - h = heap() # min-heap emulating a max-heap - for v, e in G[u].items(): - h.insert(v, -e["weight"]) - # Repeat until all but one node has been added to A. - for j in range(n - i - 2): - u = h.pop()[0] - A.add(u) - for v, e in G[u].items(): - if v not in A: - h.insert(v, h.get(v, 0) - e["weight"]) - # A and the remaining node v define a "cut of the phase". There is a - # minimum cut of the original graph that is also a cut of the phase. - # Due to contractions in earlier phases, v may in fact represent - # multiple nodes in the original graph. - v, w = h.min() - w = -w - if w < cut_value: - cut_value = w - best_phase = i - # Contract v and the last node added to A. - contractions.append((u, v)) - for w, e in G[v].items(): - if w != u: - if w not in G[u]: - G.add_edge(u, w, weight=e["weight"]) - else: - G[u][w]["weight"] += e["weight"] - G.remove_node(v) - - # Recover the optimal partitioning from the contractions. - G = nx.Graph(islice(contractions, best_phase)) - v = contractions[best_phase][1] - G.add_node(v) - reachable = set(nx.single_source_shortest_path_length(G, v)) - partition = (list(reachable), list(nodes - reachable)) - - return cut_value, partition diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_connectivity.py deleted file mode 100644 index 7aef247..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_connectivity.py +++ /dev/null @@ -1,421 +0,0 @@ -import itertools - -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity import ( - local_edge_connectivity, - local_node_connectivity, -) - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - - -# helper functions for tests - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = f"Tried {max_attempts} times: no suitable Graph." - raise Exception(msg) - else: - attempts += 1 - - -def test_average_connectivity(): - # figure 1 from: - # Beineke, L., O. Oellermann, and R. Pippert (2002). The average - # connectivity of a graph. Discrete mathematics 252(1-3), 31-45 - # http://www.sciencedirect.com/science/article/pii/S0012365X01001807 - G1 = nx.path_graph(3) - G1.add_edges_from([(1, 3), (1, 4)]) - G2 = nx.path_graph(3) - G2.add_edges_from([(1, 3), (1, 4), (0, 3), (0, 4), (3, 4)]) - G3 = nx.Graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert nx.average_node_connectivity(G1, **kwargs) == 1, errmsg - assert nx.average_node_connectivity(G2, **kwargs) == 2.2, errmsg - assert nx.average_node_connectivity(G3, **kwargs) == 0, errmsg - - -def test_average_connectivity_directed(): - G = nx.DiGraph([(1, 3), (1, 4), (1, 5)]) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert nx.average_node_connectivity(G) == 0.25, errmsg - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for flow_func in flow_funcs: - for i in range(3): - G = next(Ggen) - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert nx.node_connectivity(G, flow_func=flow_func) == 1, errmsg - - -def test_brandes_erlebach(): - # Figure 1 chapter 7: Connectivity - # http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - G = nx.Graph() - G.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 6), - (3, 4), - (3, 6), - (4, 6), - (4, 7), - (5, 7), - (6, 8), - (6, 9), - (7, 8), - (7, 10), - (8, 11), - (9, 10), - (9, 11), - (10, 11), - ] - ) - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 3 == local_edge_connectivity(G, 1, 11, **kwargs), errmsg - assert 3 == nx.edge_connectivity(G, 1, 11, **kwargs), errmsg - assert 2 == local_node_connectivity(G, 1, 11, **kwargs), errmsg - assert 2 == nx.node_connectivity(G, 1, 11, **kwargs), errmsg - assert 2 == nx.edge_connectivity(G, **kwargs), errmsg - assert 2 == nx.node_connectivity(G, **kwargs), errmsg - if flow_func is flow.preflow_push: - assert 3 == nx.edge_connectivity(G, 1, 11, cutoff=2, **kwargs), errmsg - else: - assert 2 == nx.edge_connectivity(G, 1, 11, cutoff=2, **kwargs), errmsg - - -def test_white_harary_1(): - # Figure 1b white and harary (2001) - # https://doi.org/10.1111/0081-1750.00098 - # A graph with high adhesion (edge connectivity) and low cohesion - # (vertex connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 1 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_white_harary_2(): - # Figure 8 white and harary (2001) - # https://doi.org/10.1111/0081-1750.00098 - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.add_edge(0, 4) - # kappa <= lambda <= delta - assert 3 == min(nx.core_number(G).values()) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 1 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 1 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_complete_graphs(): - for n in range(5, 20, 5): - for flow_func in flow_funcs: - G = nx.complete_graph(n) - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert n - 1 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert n - 1 == nx.node_connectivity( - G.to_directed(), flow_func=flow_func - ), errmsg - assert n - 1 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - assert n - 1 == nx.edge_connectivity( - G.to_directed(), flow_func=flow_func - ), errmsg - - -def test_empty_graphs(): - for k in range(5, 25, 5): - G = nx.empty_graph(k) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 0 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 0 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_petersen(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 3 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_tutte(): - G = nx.tutte_graph() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 3 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_dodecahedral(): - G = nx.dodecahedral_graph() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 3 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_octahedral(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 4 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 4 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_icosahedral(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 5 == nx.node_connectivity(G, flow_func=flow_func), errmsg - assert 5 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - - -def test_missing_source(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, nx.node_connectivity, G, 10, 1, flow_func=flow_func - ) - - -def test_missing_target(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, nx.node_connectivity, G, 1, 10, flow_func=flow_func - ) - - -def test_edge_missing_source(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, nx.edge_connectivity, G, 10, 1, flow_func=flow_func - ) - - -def test_edge_missing_target(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, nx.edge_connectivity, G, 1, 10, flow_func=flow_func - ) - - -def test_not_weakly_connected(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert nx.node_connectivity(G) == 0, errmsg - assert nx.edge_connectivity(G) == 0, errmsg - - -def test_not_connected(): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert nx.node_connectivity(G) == 0, errmsg - assert nx.edge_connectivity(G) == 0, errmsg - - -def test_directed_edge_connectivity(): - G = nx.cycle_graph(10, create_using=nx.DiGraph()) # only one direction - D = nx.cycle_graph(10).to_directed() # 2 reciprocal edges - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert 1 == nx.edge_connectivity(G, flow_func=flow_func), errmsg - assert 1 == local_edge_connectivity(G, 1, 4, flow_func=flow_func), errmsg - assert 1 == nx.edge_connectivity(G, 1, 4, flow_func=flow_func), errmsg - assert 2 == nx.edge_connectivity(D, flow_func=flow_func), errmsg - assert 2 == local_edge_connectivity(D, 1, 4, flow_func=flow_func), errmsg - assert 2 == nx.edge_connectivity(D, 1, 4, flow_func=flow_func), errmsg - - -def test_cutoff(): - G = nx.complete_graph(5) - for local_func in [local_edge_connectivity, local_node_connectivity]: - for flow_func in flow_funcs: - if flow_func is flow.preflow_push: - # cutoff is not supported by preflow_push - continue - for cutoff in [3, 2, 1]: - result = local_func(G, 0, 4, flow_func=flow_func, cutoff=cutoff) - assert cutoff == result, f"cutoff error in {flow_func.__name__}" - - -def test_invalid_auxiliary(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, local_node_connectivity, G, 0, 3, auxiliary=G) - - -def test_interface_only_source(): - G = nx.complete_graph(5) - for interface_func in [nx.node_connectivity, nx.edge_connectivity]: - pytest.raises(nx.NetworkXError, interface_func, G, s=0) - - -def test_interface_only_target(): - G = nx.complete_graph(5) - for interface_func in [nx.node_connectivity, nx.edge_connectivity]: - pytest.raises(nx.NetworkXError, interface_func, G, t=3) - - -def test_edge_connectivity_flow_vs_stoer_wagner(): - graph_funcs = [nx.icosahedral_graph, nx.octahedral_graph, nx.dodecahedral_graph] - for graph_func in graph_funcs: - G = graph_func() - assert nx.stoer_wagner(G)[0] == nx.edge_connectivity(G) - - -class TestAllPairsNodeConnectivity: - @classmethod - def setup_class(cls): - cls.path = nx.path_graph(7) - cls.directed_path = nx.path_graph(7, create_using=nx.DiGraph()) - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.gnp = nx.gnp_random_graph(30, 0.1, seed=42) - cls.directed_gnp = nx.gnp_random_graph(30, 0.1, directed=True, seed=42) - cls.K20 = nx.complete_graph(20) - cls.K10 = nx.complete_graph(10) - cls.K5 = nx.complete_graph(5) - cls.G_list = [ - cls.path, - cls.directed_path, - cls.cycle, - cls.directed_cycle, - cls.gnp, - cls.directed_gnp, - cls.K10, - cls.K5, - cls.K20, - ] - - def test_cycles(self): - K_undir = nx.all_pairs_node_connectivity(self.cycle) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 2 - K_dir = nx.all_pairs_node_connectivity(self.directed_cycle) - for source in K_dir: - for target, k in K_dir[source].items(): - assert k == 1 - - def test_complete(self): - for G in [self.K10, self.K5, self.K20]: - K = nx.all_pairs_node_connectivity(G) - for source in K: - for target, k in K[source].items(): - assert k == len(G) - 1 - - def test_paths(self): - K_undir = nx.all_pairs_node_connectivity(self.path) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 1 - K_dir = nx.all_pairs_node_connectivity(self.directed_path) - for source in K_dir: - for target, k in K_dir[source].items(): - if source < target: - assert k == 1 - else: - assert k == 0 - - def test_all_pairs_connectivity_nbunch(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - C = nx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert len(C) == len(nbunch) - - def test_all_pairs_connectivity_icosahedral(self): - G = nx.icosahedral_graph() - C = nx.all_pairs_node_connectivity(G) - assert all(5 == C[u][v] for u, v in itertools.combinations(G, 2)) - - def test_all_pairs_connectivity(self): - G = nx.Graph() - nodes = [0, 1, 2, 3] - nx.add_path(G, nodes) - A = {n: {} for n in G} - for u, v in itertools.combinations(nodes, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G) - assert sorted((k, sorted(v)) for k, v in A.items()) == sorted( - (k, sorted(v)) for k, v in C.items() - ) - - def test_all_pairs_connectivity_directed(self): - G = nx.DiGraph() - nodes = [0, 1, 2, 3] - nx.add_path(G, nodes) - A = {n: {} for n in G} - for u, v in itertools.permutations(nodes, 2): - A[u][v] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G) - assert sorted((k, sorted(v)) for k, v in A.items()) == sorted( - (k, sorted(v)) for k, v in C.items() - ) - - def test_all_pairs_connectivity_nbunch_combinations(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - A = {n: {} for n in nbunch} - for u, v in itertools.combinations(nbunch, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert sorted((k, sorted(v)) for k, v in A.items()) == sorted( - (k, sorted(v)) for k, v in C.items() - ) - - def test_all_pairs_connectivity_nbunch_iter(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - A = {n: {} for n in nbunch} - for u, v in itertools.combinations(nbunch, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G, nbunch=iter(nbunch)) - assert sorted((k, sorted(v)) for k, v in A.items()) == sorted( - (k, sorted(v)) for k, v in C.items() - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_cuts.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_cuts.py deleted file mode 100644 index 7a485be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_cuts.py +++ /dev/null @@ -1,309 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity import minimum_st_edge_cut, minimum_st_node_cut -from networkx.utils import arbitrary_element - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - -# Tests for node and edge cutsets - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = f"Tried {attempts} times: no suitable Graph." - raise Exception(msg) - else: - attempts += 1 - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - for i in range(1): # change 1 to 3 or more for more realizations. - G = next(Ggen) - cut = nx.minimum_node_cut(G, flow_func=flow_func) - assert len(cut) == 1, errmsg - assert cut.pop() in set(nx.articulation_points(G)), errmsg - - -def test_brandes_erlebach_book(): - # Figure 1 chapter 7: Connectivity - # http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - G = nx.Graph() - G.add_edges_from( - [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 6), - (3, 4), - (3, 6), - (4, 6), - (4, 7), - (5, 7), - (6, 8), - (6, 9), - (7, 8), - (7, 10), - (8, 11), - (9, 10), - (9, 11), - (10, 11), - ] - ) - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge cutsets - assert 3 == len(nx.minimum_edge_cut(G, 1, 11, **kwargs)), errmsg - edge_cut = nx.minimum_edge_cut(G, **kwargs) - # Node 5 has only two edges - assert 2 == len(edge_cut), errmsg - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), errmsg - # node cuts - assert {6, 7} == minimum_st_node_cut(G, 1, 11, **kwargs), errmsg - assert {6, 7} == nx.minimum_node_cut(G, 1, 11, **kwargs), errmsg - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 2 == len(node_cut), errmsg - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), errmsg - - -def test_white_harary_paper(): - # Figure 1b white and harary (2001) - # https://doi.org/10.1111/0081-1750.00098 - # A graph with high adhesion (edge connectivity) and low cohesion - # (node connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 3 == len(edge_cut), errmsg - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), errmsg - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert {0} == node_cut, errmsg - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), errmsg - - -def test_petersen_cutset(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 3 == len(edge_cut), errmsg - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), errmsg - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 3 == len(node_cut), errmsg - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), errmsg - - -def test_octahedral_cutset(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 4 == len(edge_cut), errmsg - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), errmsg - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 4 == len(node_cut), errmsg - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), errmsg - - -def test_icosahedral_cutset(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 5 == len(edge_cut), errmsg - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), errmsg - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 5 == len(node_cut), errmsg - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), errmsg - - -def test_node_cutset_exception(): - G = nx.Graph() - G.add_edges_from([(1, 2), (3, 4)]) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.minimum_node_cut, G, flow_func=flow_func) - - -def test_node_cutset_random_graphs(): - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - for i in range(3): - G = nx.fast_gnp_random_graph(50, 0.25, seed=42) - if not nx.is_connected(G): - ccs = iter(nx.connected_components(G)) - start = arbitrary_element(next(ccs)) - G.add_edges_from((start, arbitrary_element(c)) for c in ccs) - cutset = nx.minimum_node_cut(G, flow_func=flow_func) - assert nx.node_connectivity(G) == len(cutset), errmsg - G.remove_nodes_from(cutset) - assert not nx.is_connected(G), errmsg - - -def test_edge_cutset_random_graphs(): - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - for i in range(3): - G = nx.fast_gnp_random_graph(50, 0.25, seed=42) - if not nx.is_connected(G): - ccs = iter(nx.connected_components(G)) - start = arbitrary_element(next(ccs)) - G.add_edges_from((start, arbitrary_element(c)) for c in ccs) - cutset = nx.minimum_edge_cut(G, flow_func=flow_func) - assert nx.edge_connectivity(G) == len(cutset), errmsg - G.remove_edges_from(cutset) - assert not nx.is_connected(G), errmsg - - -def test_empty_graphs(): - G = nx.Graph() - D = nx.DiGraph() - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXPointlessConcept, interface_func, G, flow_func=flow_func - ) - pytest.raises( - nx.NetworkXPointlessConcept, interface_func, D, flow_func=flow_func - ) - - -def test_unbounded(): - G = nx.complete_graph(5) - for flow_func in flow_funcs: - assert 4 == len(minimum_st_edge_cut(G, 1, 4, flow_func=flow_func)) - - -def test_missing_source(): - G = nx.path_graph(4) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, interface_func, G, 10, 1, flow_func=flow_func - ) - - -def test_missing_target(): - G = nx.path_graph(4) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises( - nx.NetworkXError, interface_func, G, 1, 10, flow_func=flow_func - ) - - -def test_not_weakly_connected(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, flow_func=flow_func) - - -def test_not_connected(): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, flow_func=flow_func) - - -def tests_min_cut_complete(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - assert 4 == len(interface_func(G, flow_func=flow_func)) - - -def tests_min_cut_complete_directed(): - G = nx.complete_graph(5) - G = G.to_directed() - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - assert 4 == len(interface_func(G, flow_func=flow_func)) - - -def tests_minimum_st_node_cut(): - G = nx.Graph() - G.add_nodes_from([0, 1, 2, 3, 7, 8, 11, 12]) - G.add_edges_from([(7, 11), (1, 11), (1, 12), (12, 8), (0, 1)]) - nodelist = minimum_st_node_cut(G, 7, 11) - assert nodelist == {} - - -def test_invalid_auxiliary(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, minimum_st_node_cut, G, 0, 3, auxiliary=G) - - -def test_interface_only_source(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - pytest.raises(nx.NetworkXError, interface_func, G, s=0) - - -def test_interface_only_target(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - pytest.raises(nx.NetworkXError, interface_func, G, t=3) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_disjoint_paths.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_disjoint_paths.py deleted file mode 100644 index 0c0fad9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +++ /dev/null @@ -1,249 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.utils import pairwise - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.edmonds_karp, - flow.dinitz, - flow.preflow_push, - flow.shortest_augmenting_path, -] - - -def is_path(G, path): - return all(v in G[u] for u, v in pairwise(path)) - - -def are_edge_disjoint_paths(G, paths): - if not paths: - return False - for path in paths: - assert is_path(G, path) - paths_edges = [list(pairwise(p)) for p in paths] - num_of_edges = sum(len(e) for e in paths_edges) - num_unique_edges = len(set.union(*[set(es) for es in paths_edges])) - if num_of_edges == num_unique_edges: - return True - return False - - -def are_node_disjoint_paths(G, paths): - if not paths: - return False - for path in paths: - assert is_path(G, path) - # first and last nodes are source and target - st = {paths[0][0], paths[0][-1]} - num_of_nodes = len([n for path in paths for n in path if n not in st]) - num_unique_nodes = len({n for path in paths for n in path if n not in st}) - if num_of_nodes == num_unique_nodes: - return True - return False - - -def test_graph_from_pr_2053(): - G = nx.Graph() - G.add_edges_from( - [ - ("A", "B"), - ("A", "D"), - ("A", "F"), - ("A", "G"), - ("B", "C"), - ("B", "D"), - ("B", "G"), - ("C", "D"), - ("C", "E"), - ("C", "Z"), - ("D", "E"), - ("D", "F"), - ("E", "F"), - ("E", "Z"), - ("F", "Z"), - ("G", "Z"), - ] - ) - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_paths = list(nx.edge_disjoint_paths(G, "A", "Z", **kwargs)) - assert are_edge_disjoint_paths(G, edge_paths), errmsg - assert nx.edge_connectivity(G, "A", "Z") == len(edge_paths), errmsg - # node disjoint paths - node_paths = list(nx.node_disjoint_paths(G, "A", "Z", **kwargs)) - assert are_node_disjoint_paths(G, node_paths), errmsg - assert nx.node_connectivity(G, "A", "Z") == len(node_paths), errmsg - - -def test_florentine_families(): - G = nx.florentine_families_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, "Medici", "Strozzi", **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert nx.edge_connectivity(G, "Medici", "Strozzi") == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, "Medici", "Strozzi", **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert nx.node_connectivity(G, "Medici", "Strozzi") == len(node_dpaths), errmsg - - -def test_karate(): - G = nx.karate_club_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 33, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert nx.edge_connectivity(G, 0, 33) == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 33, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert nx.node_connectivity(G, 0, 33) == len(node_dpaths), errmsg - - -def test_petersen_disjoint_paths(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert 3 == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert 3 == len(node_dpaths), errmsg - - -def test_octahedral_disjoint_paths(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 5, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert 4 == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 5, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert 4 == len(node_dpaths), errmsg - - -def test_icosahedral_disjoint_paths(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert 5 == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert 5 == len(node_dpaths), errmsg - - -def test_cutoff_disjoint_paths(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = {"flow_func": flow_func} - errmsg = f"Assertion failed in function: {flow_func.__name__}" - for cutoff in [2, 4]: - kwargs["cutoff"] = cutoff - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), errmsg - assert cutoff == len(edge_dpaths), errmsg - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), errmsg - assert cutoff == len(node_dpaths), errmsg - - -def test_missing_source_edge_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.edge_disjoint_paths(G, 10, 1)) - - -def test_missing_source_node_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.node_disjoint_paths(G, 10, 1)) - - -def test_missing_target_edge_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.edge_disjoint_paths(G, 1, 10)) - - -def test_missing_target_node_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.node_disjoint_paths(G, 1, 10)) - - -def test_not_weakly_connected_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_not_weakly_connected_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_not_connected_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_not_connected_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_isolated_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - G.add_node(1) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_isolated_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - G.add_node(1) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_invalid_auxiliary(): - with pytest.raises(nx.NetworkXError): - G = nx.complete_graph(5) - list(nx.node_disjoint_paths(G, 0, 3, auxiliary=G)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_augmentation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_augmentation.py deleted file mode 100644 index e1d92d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +++ /dev/null @@ -1,502 +0,0 @@ -import itertools as it -import random - -import pytest - -import networkx as nx -from networkx.algorithms.connectivity import k_edge_augmentation -from networkx.algorithms.connectivity.edge_augmentation import ( - _unpack_available_edges, - collapse, - complement_edges, - is_k_edge_connected, - is_locally_k_edge_connected, -) -from networkx.utils import pairwise - -# This should be set to the largest k for which an efficient algorithm is -# explicitly defined. -MAX_EFFICIENT_K = 2 - - -def tarjan_bridge_graph(): - # graph from tarjan paper - # RE Tarjan - "A note on finding the bridges of a graph" - # Information Processing Letters, 1974 - Elsevier - # doi:10.1016/0020-0190(74)90003-9. - # define 2-connected components and bridges - ccs = [ - (1, 2, 4, 3, 1, 4), - (5, 6, 7, 5), - (8, 9, 10, 8), - (17, 18, 16, 15, 17), - (11, 12, 14, 13, 11, 14), - ] - bridges = [(4, 8), (3, 5), (3, 17)] - G = nx.Graph(it.chain(*(pairwise(path) for path in ccs + bridges))) - return G - - -def test_weight_key(): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9]) - G.add_edges_from([(3, 8), (1, 2), (2, 3)]) - impossible = {(3, 6), (3, 9)} - rng = random.Random(0) - avail_uv = list(set(complement_edges(G)) - impossible) - avail = [(u, v, {"cost": rng.random()}) for u, v in avail_uv] - - _augment_and_check(G, k=1) - _augment_and_check(G, k=1, avail=avail_uv) - _augment_and_check(G, k=1, avail=avail, weight="cost") - - _check_augmentations(G, avail, weight="cost") - - -def test_is_locally_k_edge_connected_exceptions(): - pytest.raises(nx.NetworkXNotImplemented, is_k_edge_connected, nx.DiGraph(), k=0) - pytest.raises(nx.NetworkXNotImplemented, is_k_edge_connected, nx.MultiGraph(), k=0) - pytest.raises(ValueError, is_k_edge_connected, nx.Graph(), k=0) - - -def test_is_k_edge_connected(): - G = nx.barbell_graph(10, 0) - assert is_k_edge_connected(G, k=1) - assert not is_k_edge_connected(G, k=2) - - G = nx.Graph() - G.add_nodes_from([5, 15]) - assert not is_k_edge_connected(G, k=1) - assert not is_k_edge_connected(G, k=2) - - G = nx.complete_graph(5) - assert is_k_edge_connected(G, k=1) - assert is_k_edge_connected(G, k=2) - assert is_k_edge_connected(G, k=3) - assert is_k_edge_connected(G, k=4) - - G = nx.compose(nx.complete_graph([0, 1, 2]), nx.complete_graph([3, 4, 5])) - assert not is_k_edge_connected(G, k=1) - assert not is_k_edge_connected(G, k=2) - assert not is_k_edge_connected(G, k=3) - - -def test_is_k_edge_connected_exceptions(): - pytest.raises( - nx.NetworkXNotImplemented, is_locally_k_edge_connected, nx.DiGraph(), 1, 2, k=0 - ) - pytest.raises( - nx.NetworkXNotImplemented, - is_locally_k_edge_connected, - nx.MultiGraph(), - 1, - 2, - k=0, - ) - pytest.raises(ValueError, is_locally_k_edge_connected, nx.Graph(), 1, 2, k=0) - - -def test_is_locally_k_edge_connected(): - G = nx.barbell_graph(10, 0) - assert is_locally_k_edge_connected(G, 5, 15, k=1) - assert not is_locally_k_edge_connected(G, 5, 15, k=2) - - G = nx.Graph() - G.add_nodes_from([5, 15]) - assert not is_locally_k_edge_connected(G, 5, 15, k=2) - - -def test_null_graph(): - G = nx.Graph() - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_cliques(): - for n in range(1, 10): - G = nx.complete_graph(n) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_clique_and_node(): - for n in range(1, 10): - G = nx.complete_graph(n) - G.add_node(n + 1) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_point_graph(): - G = nx.Graph() - G.add_node(1) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_edgeless_graph(): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - _check_augmentations(G) - - -def test_invalid_k(): - G = nx.Graph() - pytest.raises(ValueError, list, k_edge_augmentation(G, k=-1)) - pytest.raises(ValueError, list, k_edge_augmentation(G, k=0)) - - -def test_unfeasible(): - G = tarjan_bridge_graph() - pytest.raises(nx.NetworkXUnfeasible, list, k_edge_augmentation(G, k=1, avail=[])) - - pytest.raises(nx.NetworkXUnfeasible, list, k_edge_augmentation(G, k=2, avail=[])) - - pytest.raises( - nx.NetworkXUnfeasible, list, k_edge_augmentation(G, k=2, avail=[(7, 9)]) - ) - - # partial solutions should not error if real solutions are infeasible - aug_edges = list(k_edge_augmentation(G, k=2, avail=[(7, 9)], partial=True)) - assert aug_edges == [(7, 9)] - - _check_augmentations(G, avail=[], max_k=MAX_EFFICIENT_K + 2) - - _check_augmentations(G, avail=[(7, 9)], max_k=MAX_EFFICIENT_K + 2) - - -def test_tarjan(): - G = tarjan_bridge_graph() - - aug_edges = set(_augment_and_check(G, k=2)[0]) - print(f"aug_edges = {aug_edges!r}") - # can't assert edge exactly equality due to non-determinant edge order - # but we do know the size of the solution must be 3 - assert len(aug_edges) == 3 - - avail = [ - (9, 7), - (8, 5), - (2, 10), - (6, 13), - (11, 18), - (1, 17), - (2, 3), - (16, 17), - (18, 14), - (15, 14), - ] - aug_edges = set(_augment_and_check(G, avail=avail, k=2)[0]) - - # Can't assert exact length since approximation depends on the order of a - # dict traversal. - assert len(aug_edges) <= 3 * 2 - - _check_augmentations(G, avail) - - -def test_configuration(): - # seeds = [2718183590, 2470619828, 1694705158, 3001036531, 2401251497] - seeds = [1001, 1002, 1003, 1004] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.Graph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_augmentations(G) - - -def test_shell(): - # seeds = [2057382236, 3331169846, 1840105863, 476020778, 2247498425] - seeds = [18] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed) - _check_augmentations(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_augmentations(G) - - -def test_star(): - G = nx.star_graph(3) - _check_augmentations(G) - - G = nx.star_graph(5) - _check_augmentations(G) - - G = nx.star_graph(10) - _check_augmentations(G) - - -def test_barbell(): - G = nx.barbell_graph(5, 0) - _check_augmentations(G) - - G = nx.barbell_graph(5, 2) - _check_augmentations(G) - - G = nx.barbell_graph(5, 3) - _check_augmentations(G) - - G = nx.barbell_graph(5, 4) - _check_augmentations(G) - - -def test_bridge(): - G = nx.Graph([(2393, 2257), (2393, 2685), (2685, 2257), (1758, 2257)]) - _check_augmentations(G) - - -def test_gnp_augmentation(): - rng = random.Random(0) - G = nx.gnp_random_graph(30, 0.005, seed=0) - # Randomly make edges available - avail = { - (u, v): 1 + rng.random() for u, v in complement_edges(G) if rng.random() < 0.25 - } - _check_augmentations(G, avail) - - -def _assert_solution_properties(G, aug_edges, avail_dict=None): - """Checks that aug_edges are consistently formatted""" - if avail_dict is not None: - assert all( - e in avail_dict for e in aug_edges - ), "when avail is specified aug-edges should be in avail" - - unique_aug = set(map(tuple, map(sorted, aug_edges))) - unique_aug = list(map(tuple, map(sorted, aug_edges))) - assert len(aug_edges) == len(unique_aug), "edges should be unique" - - assert not any(u == v for u, v in unique_aug), "should be no self-edges" - - assert not any( - G.has_edge(u, v) for u, v in unique_aug - ), "aug edges and G.edges should be disjoint" - - -def _augment_and_check( - G, k, avail=None, weight=None, verbose=False, orig_k=None, max_aug_k=None -): - """ - Does one specific augmentation and checks for properties of the result - """ - if orig_k is None: - try: - orig_k = nx.edge_connectivity(G) - except nx.NetworkXPointlessConcept: - orig_k = 0 - info = {} - try: - if avail is not None: - # ensure avail is in dict form - avail_dict = dict(zip(*_unpack_available_edges(avail, weight=weight))) - else: - avail_dict = None - try: - # Find the augmentation if possible - generator = nx.k_edge_augmentation(G, k=k, weight=weight, avail=avail) - assert not isinstance(generator, list), "should always return an iter" - aug_edges = [] - for edge in generator: - aug_edges.append(edge) - except nx.NetworkXUnfeasible: - infeasible = True - info["infeasible"] = True - assert len(aug_edges) == 0, "should not generate anything if unfeasible" - - if avail is None: - n_nodes = G.number_of_nodes() - assert n_nodes <= k, ( - "unconstrained cases are only unfeasible if |V| <= k. " - f"Got |V|={n_nodes} and k={k}" - ) - else: - if max_aug_k is None: - G_aug_all = G.copy() - G_aug_all.add_edges_from(avail_dict.keys()) - try: - max_aug_k = nx.edge_connectivity(G_aug_all) - except nx.NetworkXPointlessConcept: - max_aug_k = 0 - - assert max_aug_k < k, ( - "avail should only be unfeasible if using all edges " - "does not achieve k-edge-connectivity" - ) - - # Test for a partial solution - partial_edges = list( - nx.k_edge_augmentation(G, k=k, weight=weight, partial=True, avail=avail) - ) - - info["n_partial_edges"] = len(partial_edges) - - if avail_dict is None: - assert set(partial_edges) == set( - complement_edges(G) - ), "unweighted partial solutions should be the complement" - elif len(avail_dict) > 0: - H = G.copy() - - # Find the partial / full augmented connectivity - H.add_edges_from(partial_edges) - partial_conn = nx.edge_connectivity(H) - - H.add_edges_from(set(avail_dict.keys())) - full_conn = nx.edge_connectivity(H) - - # Full connectivity should be no better than our partial - # solution. - assert ( - partial_conn == full_conn - ), "adding more edges should not increase k-conn" - - # Find the new edge-connectivity after adding the augmenting edges - aug_edges = partial_edges - else: - infeasible = False - - # Find the weight of the augmentation - num_edges = len(aug_edges) - if avail is not None: - total_weight = sum(avail_dict[e] for e in aug_edges) - else: - total_weight = num_edges - - info["total_weight"] = total_weight - info["num_edges"] = num_edges - - # Find the new edge-connectivity after adding the augmenting edges - G_aug = G.copy() - G_aug.add_edges_from(aug_edges) - try: - aug_k = nx.edge_connectivity(G_aug) - except nx.NetworkXPointlessConcept: - aug_k = 0 - info["aug_k"] = aug_k - - # Do checks - if not infeasible and orig_k < k: - assert info["aug_k"] >= k, f"connectivity should increase to k={k} or more" - - assert info["aug_k"] >= orig_k, "augmenting should never reduce connectivity" - - _assert_solution_properties(G, aug_edges, avail_dict) - - except Exception: - info["failed"] = True - print(f"edges = {list(G.edges())}") - print(f"nodes = {list(G.nodes())}") - print(f"aug_edges = {list(aug_edges)}") - print(f"info = {info}") - raise - else: - if verbose: - print(f"info = {info}") - - if infeasible: - aug_edges = None - return aug_edges, info - - -def _check_augmentations(G, avail=None, max_k=None, weight=None, verbose=False): - """Helper to check weighted/unweighted cases with multiple values of k""" - # Using all available edges, find the maximum edge-connectivity - try: - orig_k = nx.edge_connectivity(G) - except nx.NetworkXPointlessConcept: - orig_k = 0 - - if avail is not None: - all_aug_edges = _unpack_available_edges(avail, weight=weight)[0] - G_aug_all = G.copy() - G_aug_all.add_edges_from(all_aug_edges) - try: - max_aug_k = nx.edge_connectivity(G_aug_all) - except nx.NetworkXPointlessConcept: - max_aug_k = 0 - else: - max_aug_k = G.number_of_nodes() - 1 - - if max_k is None: - max_k = min(4, max_aug_k) - - avail_uniform = {e: 1 for e in complement_edges(G)} - - if verbose: - print("\n=== CHECK_AUGMENTATION ===") - print(f"G.number_of_nodes = {G.number_of_nodes()!r}") - print(f"G.number_of_edges = {G.number_of_edges()!r}") - print(f"max_k = {max_k!r}") - print(f"max_aug_k = {max_aug_k!r}") - print(f"orig_k = {orig_k!r}") - - # check augmentation for multiple values of k - for k in range(1, max_k + 1): - if verbose: - print("---------------") - print(f"Checking k = {k}") - - # Check the unweighted version - if verbose: - print("unweighted case") - aug_edges1, info1 = _augment_and_check(G, k=k, verbose=verbose, orig_k=orig_k) - - # Check that the weighted version with all available edges and uniform - # weights gives a similar solution to the unweighted case. - if verbose: - print("weighted uniform case") - aug_edges2, info2 = _augment_and_check( - G, - k=k, - avail=avail_uniform, - verbose=verbose, - orig_k=orig_k, - max_aug_k=G.number_of_nodes() - 1, - ) - - # Check the weighted version - if avail is not None: - if verbose: - print("weighted case") - aug_edges3, info3 = _augment_and_check( - G, - k=k, - avail=avail, - weight=weight, - verbose=verbose, - max_aug_k=max_aug_k, - orig_k=orig_k, - ) - - if aug_edges1 is not None: - # Check approximation ratios - if k == 1: - # when k=1, both solutions should be optimal - assert info2["total_weight"] == info1["total_weight"] - if k == 2: - # when k=2, the weighted version is an approximation - if orig_k == 0: - # the approximation ratio is 3 if G is not connected - assert info2["total_weight"] <= info1["total_weight"] * 3 - else: - # the approximation ratio is 2 if G is was connected - assert info2["total_weight"] <= info1["total_weight"] * 2 - _check_unconstrained_bridge_property(G, info1) - - -def _check_unconstrained_bridge_property(G, info1): - # Check Theorem 5 from Eswaran and Tarjan. (1975) Augmentation problems - import math - - bridge_ccs = list(nx.connectivity.bridge_components(G)) - # condense G into an forest C - C = collapse(G, bridge_ccs) - - p = len([n for n, d in C.degree() if d == 1]) # leafs - q = len([n for n, d in C.degree() if d == 0]) # isolated - if p + q > 1: - size_target = math.ceil(p / 2) + q - size_aug = info1["num_edges"] - assert ( - size_aug == size_target - ), "augmentation size is different from what theory predicts" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py deleted file mode 100644 index 4a1f681..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +++ /dev/null @@ -1,488 +0,0 @@ -import itertools as it - -import pytest - -import networkx as nx -from networkx.algorithms.connectivity import EdgeComponentAuxGraph, bridge_components -from networkx.algorithms.connectivity.edge_kcomponents import general_k_edge_subgraphs -from networkx.utils import pairwise - -# ---------------- -# Helper functions -# ---------------- - - -def fset(list_of_sets): - """allows == to be used for list of sets""" - return set(map(frozenset, list_of_sets)) - - -def _assert_subgraph_edge_connectivity(G, ccs_subgraph, k): - """ - tests properties of k-edge-connected subgraphs - - the actual edge connectivity should be no less than k unless the cc is a - single node. - """ - for cc in ccs_subgraph: - C = G.subgraph(cc) - if len(cc) > 1: - connectivity = nx.edge_connectivity(C) - assert connectivity >= k - - -def _memo_connectivity(G, u, v, memo): - edge = (u, v) - if edge in memo: - return memo[edge] - if not G.is_directed(): - redge = (v, u) - if redge in memo: - return memo[redge] - memo[edge] = nx.edge_connectivity(G, *edge) - return memo[edge] - - -def _all_pairs_connectivity(G, cc, k, memo): - # Brute force check - for u, v in it.combinations(cc, 2): - # Use a memoization dict to save on computation - connectivity = _memo_connectivity(G, u, v, memo) - if G.is_directed(): - connectivity = min(connectivity, _memo_connectivity(G, v, u, memo)) - assert connectivity >= k - - -def _assert_local_cc_edge_connectivity(G, ccs_local, k, memo): - """ - tests properties of k-edge-connected components - - the local edge connectivity between each pair of nodes in the original - graph should be no less than k unless the cc is a single node. - """ - for cc in ccs_local: - if len(cc) > 1: - # Strategy for testing a bit faster: If the subgraph has high edge - # connectivity then it must have local connectivity - C = G.subgraph(cc) - connectivity = nx.edge_connectivity(C) - if connectivity < k: - # Otherwise do the brute force (with memoization) check - _all_pairs_connectivity(G, cc, k, memo) - - -# Helper function -def _check_edge_connectivity(G): - """ - Helper - generates all k-edge-components using the aux graph. Checks the - both local and subgraph edge connectivity of each cc. Also checks that - alternate methods of computing the k-edge-ccs generate the same result. - """ - # Construct the auxiliary graph that can be used to make each k-cc or k-sub - aux_graph = EdgeComponentAuxGraph.construct(G) - - # memoize the local connectivity in this graph - memo = {} - - for k in it.count(1): - # Test "local" k-edge-components and k-edge-subgraphs - ccs_local = fset(aux_graph.k_edge_components(k)) - ccs_subgraph = fset(aux_graph.k_edge_subgraphs(k)) - - # Check connectivity properties that should be guaranteed by the - # algorithms. - _assert_local_cc_edge_connectivity(G, ccs_local, k, memo) - _assert_subgraph_edge_connectivity(G, ccs_subgraph, k) - - if k == 1 or k == 2 and not G.is_directed(): - assert ( - ccs_local == ccs_subgraph - ), "Subgraphs and components should be the same when k == 1 or (k == 2 and not G.directed())" - - if G.is_directed(): - # Test special case methods are the same as the aux graph - if k == 1: - alt_sccs = fset(nx.strongly_connected_components(G)) - assert alt_sccs == ccs_local, "k=1 failed alt" - assert alt_sccs == ccs_subgraph, "k=1 failed alt" - else: - # Test special case methods are the same as the aux graph - if k == 1: - alt_ccs = fset(nx.connected_components(G)) - assert alt_ccs == ccs_local, "k=1 failed alt" - assert alt_ccs == ccs_subgraph, "k=1 failed alt" - elif k == 2: - alt_bridge_ccs = fset(bridge_components(G)) - assert alt_bridge_ccs == ccs_local, "k=2 failed alt" - assert alt_bridge_ccs == ccs_subgraph, "k=2 failed alt" - # if new methods for k == 3 or k == 4 are implemented add them here - - # Check the general subgraph method works by itself - alt_subgraph_ccs = fset( - [set(C.nodes()) for C in general_k_edge_subgraphs(G, k=k)] - ) - assert alt_subgraph_ccs == ccs_subgraph, "alt subgraph method failed" - - # Stop once k is larger than all special case methods - # and we cannot break down ccs any further. - if k > 2 and all(len(cc) == 1 for cc in ccs_local): - break - - -# ---------------- -# Misc tests -# ---------------- - - -def test_zero_k_exception(): - G = nx.Graph() - # functions that return generators error immediately - pytest.raises(ValueError, nx.k_edge_components, G, k=0) - pytest.raises(ValueError, nx.k_edge_subgraphs, G, k=0) - - # actual generators only error when you get the first item - aux_graph = EdgeComponentAuxGraph.construct(G) - pytest.raises(ValueError, list, aux_graph.k_edge_components(k=0)) - pytest.raises(ValueError, list, aux_graph.k_edge_subgraphs(k=0)) - - pytest.raises(ValueError, list, general_k_edge_subgraphs(G, k=0)) - - -def test_empty_input(): - G = nx.Graph() - assert [] == list(nx.k_edge_components(G, k=5)) - assert [] == list(nx.k_edge_subgraphs(G, k=5)) - - G = nx.DiGraph() - assert [] == list(nx.k_edge_components(G, k=5)) - assert [] == list(nx.k_edge_subgraphs(G, k=5)) - - -def test_not_implemented(): - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, EdgeComponentAuxGraph.construct, G) - pytest.raises(nx.NetworkXNotImplemented, nx.k_edge_components, G, k=2) - pytest.raises(nx.NetworkXNotImplemented, nx.k_edge_subgraphs, G, k=2) - with pytest.raises(nx.NetworkXNotImplemented): - next(bridge_components(G)) - with pytest.raises(nx.NetworkXNotImplemented): - next(bridge_components(nx.DiGraph())) - - -def test_general_k_edge_subgraph_quick_return(): - # tests quick return optimization - G = nx.Graph() - G.add_node(0) - subgraphs = list(general_k_edge_subgraphs(G, k=1)) - assert len(subgraphs) == 1 - for subgraph in subgraphs: - assert subgraph.number_of_nodes() == 1 - - G.add_node(1) - subgraphs = list(general_k_edge_subgraphs(G, k=1)) - assert len(subgraphs) == 2 - for subgraph in subgraphs: - assert subgraph.number_of_nodes() == 1 - - -# ---------------- -# Undirected tests -# ---------------- - - -def test_random_gnp(): - # seeds = [1550709854, 1309423156, 4208992358, 2785630813, 1915069929] - seeds = [12, 13] - - for seed in seeds: - G = nx.gnp_random_graph(20, 0.2, seed=seed) - _check_edge_connectivity(G) - - -def test_configuration(): - # seeds = [2718183590, 2470619828, 1694705158, 3001036531, 2401251497] - seeds = [14, 15] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.Graph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_edge_connectivity(G) - - -def test_shell(): - # seeds = [2057382236, 3331169846, 1840105863, 476020778, 2247498425] - seeds = [20] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed) - _check_edge_connectivity(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_edge_connectivity(G) - - -def test_tarjan_bridge(): - # graph from tarjan paper - # RE Tarjan - "A note on finding the bridges of a graph" - # Information Processing Letters, 1974 - Elsevier - # doi:10.1016/0020-0190(74)90003-9. - # define 2-connected components and bridges - ccs = [ - (1, 2, 4, 3, 1, 4), - (5, 6, 7, 5), - (8, 9, 10, 8), - (17, 18, 16, 15, 17), - (11, 12, 14, 13, 11, 14), - ] - bridges = [(4, 8), (3, 5), (3, 17)] - G = nx.Graph(it.chain(*(pairwise(path) for path in ccs + bridges))) - _check_edge_connectivity(G) - - -def test_bridge_cc(): - # define 2-connected components and bridges - cc2 = [(1, 2, 4, 3, 1, 4), (8, 9, 10, 8), (11, 12, 13, 11)] - bridges = [(4, 8), (3, 5), (20, 21), (22, 23, 24)] - G = nx.Graph(it.chain(*(pairwise(path) for path in cc2 + bridges))) - bridge_ccs = fset(bridge_components(G)) - target_ccs = fset( - [{1, 2, 3, 4}, {5}, {8, 9, 10}, {11, 12, 13}, {20}, {21}, {22}, {23}, {24}] - ) - assert bridge_ccs == target_ccs - _check_edge_connectivity(G) - - -def test_undirected_aux_graph(): - # Graph similar to the one in - # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - a, b, c, d, e, f, g, h, i = "abcdefghi" - paths = [ - (a, d, b, f, c), - (a, e, b), - (a, e, b, c, g, b, a), - (c, b), - (f, g, f), - (h, i), - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) - target_1 = fset([{a, b, c, d, e, f, g}, {h, i}]) - assert target_1 == components_1 - - # Check that the undirected case for k=1 agrees with CCs - alt_1 = fset(nx.k_edge_subgraphs(G, k=1)) - assert alt_1 == components_1 - - components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) - target_2 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) - assert target_2 == components_2 - - # Check that the undirected case for k=2 agrees with bridge components - alt_2 = fset(nx.k_edge_subgraphs(G, k=2)) - assert alt_2 == components_2 - - components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) - target_3 = fset([{a}, {b, c, f, g}, {d}, {e}, {h}, {i}]) - assert target_3 == components_3 - - components_4 = fset(aux_graph.k_edge_subgraphs(k=4)) - target_4 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) - assert target_4 == components_4 - - _check_edge_connectivity(G) - - -def test_local_subgraph_difference(): - paths = [ - (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique - (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique - # paths connecting each node of the 4 cliques - (11, 101, 21), - (12, 102, 22), - (13, 103, 23), - (14, 104, 24), - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - # Each clique is returned separately in k-edge-subgraphs - subgraph_ccs = fset(aux_graph.k_edge_subgraphs(3)) - subgraph_target = fset( - [{101}, {102}, {103}, {104}, {21, 22, 23, 24}, {11, 12, 13, 14}] - ) - assert subgraph_ccs == subgraph_target - - # But in k-edge-ccs they are returned together - # because they are locally 3-edge-connected - local_ccs = fset(aux_graph.k_edge_components(3)) - local_target = fset([{101}, {102}, {103}, {104}, {11, 12, 13, 14, 21, 22, 23, 24}]) - assert local_ccs == local_target - - -def test_local_subgraph_difference_directed(): - dipaths = [(1, 2, 3, 4, 1), (1, 3, 1)] - G = nx.DiGraph(it.chain(*[pairwise(path) for path in dipaths])) - - assert fset(nx.k_edge_components(G, k=1)) == fset(nx.k_edge_subgraphs(G, k=1)) - - # Unlike undirected graphs, when k=2, for directed graphs there is a case - # where the k-edge-ccs are not the same as the k-edge-subgraphs. - # (in directed graphs ccs and subgraphs are the same when k=2) - assert fset(nx.k_edge_components(G, k=2)) != fset(nx.k_edge_subgraphs(G, k=2)) - - assert fset(nx.k_edge_components(G, k=3)) == fset(nx.k_edge_subgraphs(G, k=3)) - - _check_edge_connectivity(G) - - -def test_triangles(): - paths = [ - (11, 12, 13, 11), # first 3-clique - (21, 22, 23, 21), # second 3-clique - (11, 21), # connected by an edge - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - - # subgraph and ccs are the same in all cases here - assert fset(nx.k_edge_components(G, k=1)) == fset(nx.k_edge_subgraphs(G, k=1)) - - assert fset(nx.k_edge_components(G, k=2)) == fset(nx.k_edge_subgraphs(G, k=2)) - - assert fset(nx.k_edge_components(G, k=3)) == fset(nx.k_edge_subgraphs(G, k=3)) - - _check_edge_connectivity(G) - - -def test_four_clique(): - paths = [ - (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique - (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique - # paths connecting the 4 cliques such that they are - # 3-connected in G, but not in the subgraph. - # Case where the nodes bridging them do not have degree less than 3. - (100, 13), - (12, 100, 22), - (13, 200, 23), - (14, 300, 24), - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - - # The subgraphs and ccs are different for k=3 - local_ccs = fset(nx.k_edge_components(G, k=3)) - subgraphs = fset(nx.k_edge_subgraphs(G, k=3)) - assert local_ccs != subgraphs - - # The cliques ares in the same cc - clique1 = frozenset(paths[0]) - clique2 = frozenset(paths[1]) - assert clique1.union(clique2).union({100}) in local_ccs - - # but different subgraphs - assert clique1 in subgraphs - assert clique2 in subgraphs - - assert G.degree(100) == 3 - - _check_edge_connectivity(G) - - -def test_five_clique(): - # Make a graph that can be disconnected less than 4 edges, but no node has - # degree less than 4. - G = nx.disjoint_union(nx.complete_graph(5), nx.complete_graph(5)) - paths = [ - # add aux-connections - (1, 100, 6), - (2, 100, 7), - (3, 200, 8), - (4, 200, 100), - ] - G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - assert min(dict(nx.degree(G)).values()) == 4 - - # For k=3 they are the same - assert fset(nx.k_edge_components(G, k=3)) == fset(nx.k_edge_subgraphs(G, k=3)) - - # For k=4 they are the different - # the aux nodes are in the same CC as clique 1 but no the same subgraph - assert fset(nx.k_edge_components(G, k=4)) != fset(nx.k_edge_subgraphs(G, k=4)) - - # For k=5 they are not the same - assert fset(nx.k_edge_components(G, k=5)) != fset(nx.k_edge_subgraphs(G, k=5)) - - # For k=6 they are the same - assert fset(nx.k_edge_components(G, k=6)) == fset(nx.k_edge_subgraphs(G, k=6)) - _check_edge_connectivity(G) - - -# ---------------- -# Undirected tests -# ---------------- - - -def test_directed_aux_graph(): - # Graph similar to the one in - # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - a, b, c, d, e, f, g, h, i = "abcdefghi" - dipaths = [ - (a, d, b, f, c), - (a, e, b), - (a, e, b, c, g, b, a), - (c, b), - (f, g, f), - (h, i), - ] - G = nx.DiGraph(it.chain(*[pairwise(path) for path in dipaths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) - target_1 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) - assert target_1 == components_1 - - # Check that the directed case for k=1 agrees with SCCs - alt_1 = fset(nx.strongly_connected_components(G)) - assert alt_1 == components_1 - - components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) - target_2 = fset([{i}, {e}, {d}, {b, c, f, g}, {h}, {a}]) - assert target_2 == components_2 - - components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) - target_3 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) - assert target_3 == components_3 - - -def test_random_gnp_directed(): - # seeds = [3894723670, 500186844, 267231174, 2181982262, 1116750056] - seeds = [21] - for seed in seeds: - G = nx.gnp_random_graph(20, 0.2, directed=True, seed=seed) - _check_edge_connectivity(G) - - -def test_configuration_directed(): - # seeds = [671221681, 2403749451, 124433910, 672335939, 1193127215] - seeds = [67] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.DiGraph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_edge_connectivity(G) - - -def test_shell_directed(): - # seeds = [3134027055, 4079264063, 1350769518, 1405643020, 530038094] - seeds = [31] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed).to_directed() - _check_edge_connectivity(G) - - -def test_karate_directed(): - G = nx.karate_club_graph().to_directed() - _check_edge_connectivity(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcomponents.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcomponents.py deleted file mode 100644 index f4436ac..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcomponents.py +++ /dev/null @@ -1,296 +0,0 @@ -# Test for Moody and White k-components algorithm -import pytest - -import networkx as nx -from networkx.algorithms.connectivity.kcomponents import ( - _consolidate, - build_k_number_dict, -) - -## -# A nice synthetic graph -## - - -def torrents_and_ferraro_graph(): - # Graph from https://arxiv.org/pdf/1503.04476v1 p.26 - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), label_attribute="labels" - ) - rlabels = nx.get_node_attributes(G, "labels") - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # This edge makes the graph biconnected; it's - # needed because K5s share only one node. - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - - -def test_directed(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.gnp_random_graph(10, 0.2, directed=True, seed=42) - nx.k_components(G) - - -# Helper function -def _check_connectivity(G, k_components): - for k, components in k_components.items(): - if k < 3: - continue - # check that k-components have node connectivity >= k. - for component in components: - C = G.subgraph(component) - K = nx.node_connectivity(C) - assert K >= k - - -@pytest.mark.slow -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - # In this example graph there are 8 3-components, 4 with 15 nodes - # and 4 with 5 nodes. - assert len(result[3]) == 8 - assert len([c for c in result[3] if len(c) == 15]) == 4 - assert len([c for c in result[3] if len(c) == 5]) == 4 - # There are also 8 4-components all with 5 nodes. - assert len(result[4]) == 8 - assert all(len(c) == 5 for c in result[4]) - - -@pytest.mark.slow -def test_random_gnp(): - G = nx.gnp_random_graph(50, 0.2, seed=42) - result = nx.k_components(G) - _check_connectivity(G, result) - - -@pytest.mark.slow -def test_shell(): - constructor = [(20, 80, 0.8), (80, 180, 0.6)] - G = nx.random_shell_graph(constructor, seed=42) - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_configuration(): - deg_seq = nx.random_powerlaw_tree_sequence(100, tries=5, seed=72) - G = nx.Graph(nx.configuration_model(deg_seq)) - G.remove_edges_from(nx.selfloop_edges(G)) - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_karate(): - G = nx.karate_club_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_karate_component_number(): - karate_k_num = { - 0: 4, - 1: 4, - 2: 4, - 3: 4, - 4: 3, - 5: 3, - 6: 3, - 7: 4, - 8: 4, - 9: 2, - 10: 3, - 11: 1, - 12: 2, - 13: 4, - 14: 2, - 15: 2, - 16: 2, - 17: 2, - 18: 2, - 19: 3, - 20: 2, - 21: 2, - 22: 2, - 23: 3, - 24: 3, - 25: 3, - 26: 2, - 27: 3, - 28: 3, - 29: 3, - 30: 4, - 31: 3, - 32: 4, - 33: 4, - } - G = nx.karate_club_graph() - k_components = nx.k_components(G) - k_num = build_k_number_dict(k_components) - assert karate_k_num == k_num - - -def test_davis_southern_women(): - G = nx.davis_southern_women_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_davis_southern_women_detail_3_and_4(): - solution = { - 3: [ - { - "Nora Fayette", - "E10", - "Myra Liddel", - "E12", - "E14", - "Frances Anderson", - "Evelyn Jefferson", - "Ruth DeSand", - "Helen Lloyd", - "Eleanor Nye", - "E9", - "E8", - "E5", - "E4", - "E7", - "E6", - "E1", - "Verne Sanderson", - "E3", - "E2", - "Theresa Anderson", - "Pearl Oglethorpe", - "Katherina Rogers", - "Brenda Rogers", - "E13", - "Charlotte McDowd", - "Sylvia Avondale", - "Laura Mandeville", - } - ], - 4: [ - { - "Nora Fayette", - "E10", - "Verne Sanderson", - "E12", - "Frances Anderson", - "Evelyn Jefferson", - "Ruth DeSand", - "Helen Lloyd", - "Eleanor Nye", - "E9", - "E8", - "E5", - "E4", - "E7", - "E6", - "Myra Liddel", - "E3", - "Theresa Anderson", - "Katherina Rogers", - "Brenda Rogers", - "Charlotte McDowd", - "Sylvia Avondale", - "Laura Mandeville", - } - ], - } - G = nx.davis_southern_women_graph() - result = nx.k_components(G) - for k, components in result.items(): - if k < 3: - continue - assert len(components) == len(solution[k]) - for component in components: - assert component in solution[k] - - -def test_set_consolidation_rosettacode(): - # Tests from http://rosettacode.org/wiki/Set_consolidation - def list_of_sets_equal(result, solution): - assert {frozenset(s) for s in result} == {frozenset(s) for s in solution} - - question = [{"A", "B"}, {"C", "D"}] - solution = [{"A", "B"}, {"C", "D"}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{"A", "B"}, {"B", "C"}] - solution = [{"A", "B", "C"}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{"A", "B"}, {"C", "D"}, {"D", "B"}] - solution = [{"A", "C", "B", "D"}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{"H", "I", "K"}, {"A", "B"}, {"C", "D"}, {"D", "B"}, {"F", "G", "H"}] - solution = [{"A", "C", "B", "D"}, {"G", "F", "I", "H", "K"}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [ - {"A", "H"}, - {"H", "I", "K"}, - {"A", "B"}, - {"C", "D"}, - {"D", "B"}, - {"F", "G", "H"}, - ] - solution = [{"A", "C", "B", "D", "G", "F", "I", "H", "K"}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [ - {"H", "I", "K"}, - {"A", "B"}, - {"C", "D"}, - {"D", "B"}, - {"F", "G", "H"}, - {"A", "H"}, - ] - solution = [{"A", "C", "B", "D", "G", "F", "I", "H", "K"}] - list_of_sets_equal(_consolidate(question, 1), solution) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcutsets.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcutsets.py deleted file mode 100644 index 4b4b549..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_kcutsets.py +++ /dev/null @@ -1,273 +0,0 @@ -# Jordi Torrents -# Test for k-cutsets -import itertools - -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity.kcutsets import _is_separating_set - -MAX_CUTSETS_TO_TEST = 4 # originally 100. cut to decrease testing time - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - - -## -# Some nice synthetic graphs -## -def graph_example_1(): - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), label_attribute="labels" - ) - rlabels = nx.get_node_attributes(G, "labels") - labels = {v: k for k, v in rlabels.items()} - - for nodes in [ - (labels[(0, 0)], labels[(1, 0)]), - (labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 0)], labels[(4, 0)]), - (labels[(3, 4)], labels[(4, 4)]), - ]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - G.add_edge(new_node + 16, new_node + 5) - return G - - -def torrents_and_ferraro_graph(): - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), label_attribute="labels" - ) - rlabels = nx.get_node_attributes(G, "labels") - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # Commenting this makes the graph not biconnected !! - # This stupid mistake make one reviewer very angry :P - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - - -# Helper function -def _check_separating_sets(G): - for cc in nx.connected_components(G): - if len(cc) < 3: - continue - Gc = G.subgraph(cc) - node_conn = nx.node_connectivity(Gc) - all_cuts = nx.all_node_cuts(Gc) - # Only test a limited number of cut sets to reduce test time. - for cut in itertools.islice(all_cuts, MAX_CUTSETS_TO_TEST): - assert node_conn == len(cut) - assert not nx.is_connected(nx.restricted_view(G, cut, [])) - - -@pytest.mark.slow -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - _check_separating_sets(G) - - -def test_example_1(): - G = graph_example_1() - _check_separating_sets(G) - - -def test_random_gnp(): - G = nx.gnp_random_graph(100, 0.1, seed=42) - _check_separating_sets(G) - - -def test_shell(): - constructor = [(20, 80, 0.8), (80, 180, 0.6)] - G = nx.random_shell_graph(constructor, seed=42) - _check_separating_sets(G) - - -def test_configuration(): - deg_seq = nx.random_powerlaw_tree_sequence(100, tries=5, seed=72) - G = nx.Graph(nx.configuration_model(deg_seq)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_separating_sets(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_separating_sets(G) - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = f"Tried {attempts} times: no suitable Graph." - raise Exception(msg) - else: - attempts += 1 - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for i in range(1): # change 1 to 3 or more for more realizations. - G = next(Ggen) - articulation_points = [{a} for a in nx.articulation_points(G)] - for cut in nx.all_node_cuts(G): - assert cut in articulation_points - - -def test_grid_2d_graph(): - # All minimum node cuts of a 2d grid - # are the four pairs of nodes that are - # neighbors of the four corner nodes. - G = nx.grid_2d_graph(5, 5) - solution = [{(0, 1), (1, 0)}, {(3, 0), (4, 1)}, {(3, 4), (4, 3)}, {(0, 3), (1, 4)}] - for cut in nx.all_node_cuts(G): - assert cut in solution - - -def test_disconnected_graph(): - G = nx.fast_gnp_random_graph(100, 0.01, seed=42) - cuts = nx.all_node_cuts(G) - pytest.raises(nx.NetworkXError, next, cuts) - - -@pytest.mark.slow -def test_alternative_flow_functions(): - graphs = [nx.grid_2d_graph(4, 4), nx.cycle_graph(5)] - for G in graphs: - node_conn = nx.node_connectivity(G) - for flow_func in flow_funcs: - all_cuts = nx.all_node_cuts(G, flow_func=flow_func) - # Only test a limited number of cut sets to reduce test time. - for cut in itertools.islice(all_cuts, MAX_CUTSETS_TO_TEST): - assert node_conn == len(cut) - assert not nx.is_connected(nx.restricted_view(G, cut, [])) - - -def test_is_separating_set_complete_graph(): - G = nx.complete_graph(5) - assert _is_separating_set(G, {0, 1, 2, 3}) - - -def test_is_separating_set(): - for i in [5, 10, 15]: - G = nx.star_graph(i) - max_degree_node = max(G, key=G.degree) - assert _is_separating_set(G, {max_degree_node}) - - -def test_non_repeated_cuts(): - # The algorithm was repeating the cut {0, 1} for the giant biconnected - # component of the Karate club graph. - K = nx.karate_club_graph() - bcc = max(list(nx.biconnected_components(K)), key=len) - G = K.subgraph(bcc) - solution = [{32, 33}, {2, 33}, {0, 3}, {0, 1}, {29, 33}] - cuts = list(nx.all_node_cuts(G)) - if len(solution) != len(cuts): - print(f"Solution: {solution}") - print(f"Result: {cuts}") - assert len(solution) == len(cuts) - for cut in cuts: - assert cut in solution - - -def test_cycle_graph(): - G = nx.cycle_graph(5) - solution = [{0, 2}, {0, 3}, {1, 3}, {1, 4}, {2, 4}] - cuts = list(nx.all_node_cuts(G)) - assert len(solution) == len(cuts) - for cut in cuts: - assert cut in solution - - -def test_complete_graph(): - G = nx.complete_graph(5) - assert nx.node_connectivity(G) == 4 - assert list(nx.all_node_cuts(G)) == [] - - -def test_all_node_cuts_simple_case(): - G = nx.complete_graph(5) - G.remove_edges_from([(0, 1), (3, 4)]) - expected = [{0, 1, 2}, {2, 3, 4}] - actual = list(nx.all_node_cuts(G)) - assert len(actual) == len(expected) - for cut in actual: - assert cut in expected diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_stoer_wagner.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_stoer_wagner.py deleted file mode 100644 index 2b9e2ba..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +++ /dev/null @@ -1,102 +0,0 @@ -from itertools import chain - -import pytest - -import networkx as nx - - -def _check_partition(G, cut_value, partition, weight): - assert isinstance(partition, tuple) - assert len(partition) == 2 - assert isinstance(partition[0], list) - assert isinstance(partition[1], list) - assert len(partition[0]) > 0 - assert len(partition[1]) > 0 - assert sum(map(len, partition)) == len(G) - assert set(chain.from_iterable(partition)) == set(G) - partition = tuple(map(set, partition)) - w = 0 - for u, v, e in G.edges(data=True): - if (u in partition[0]) == (v in partition[1]): - w += e.get(weight, 1) - assert w == cut_value - - -def _test_stoer_wagner(G, answer, weight="weight"): - cut_value, partition = nx.stoer_wagner(G, weight, heap=nx.utils.PairingHeap) - assert cut_value == answer - _check_partition(G, cut_value, partition, weight) - cut_value, partition = nx.stoer_wagner(G, weight, heap=nx.utils.BinaryHeap) - assert cut_value == answer - _check_partition(G, cut_value, partition, weight) - - -def test_graph1(): - G = nx.Graph() - G.add_edge("x", "a", weight=3) - G.add_edge("x", "b", weight=1) - G.add_edge("a", "c", weight=3) - G.add_edge("b", "c", weight=5) - G.add_edge("b", "d", weight=4) - G.add_edge("d", "e", weight=2) - G.add_edge("c", "y", weight=2) - G.add_edge("e", "y", weight=3) - _test_stoer_wagner(G, 4) - - -def test_graph2(): - G = nx.Graph() - G.add_edge("x", "a") - G.add_edge("x", "b") - G.add_edge("a", "c") - G.add_edge("b", "c") - G.add_edge("b", "d") - G.add_edge("d", "e") - G.add_edge("c", "y") - G.add_edge("e", "y") - _test_stoer_wagner(G, 2) - - -def test_graph3(): - # Source: - # Stoer, M. and Wagner, F. (1997). "A simple min-cut algorithm". Journal of - # the ACM 44 (4), 585-591. - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 5, weight=3) - G.add_edge(2, 3, weight=3) - G.add_edge(2, 5, weight=2) - G.add_edge(2, 6, weight=2) - G.add_edge(3, 4, weight=4) - G.add_edge(3, 7, weight=2) - G.add_edge(4, 7, weight=2) - G.add_edge(4, 8, weight=2) - G.add_edge(5, 6, weight=3) - G.add_edge(6, 7, weight=1) - G.add_edge(7, 8, weight=3) - _test_stoer_wagner(G, 4) - - -def test_weight_name(): - G = nx.Graph() - G.add_edge(1, 2, weight=1, cost=8) - G.add_edge(1, 3, cost=2) - G.add_edge(2, 3, cost=4) - _test_stoer_wagner(G, 6, weight="cost") - - -def test_exceptions(): - G = nx.Graph() - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_node(1) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_node(2) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_edge(1, 2, weight=-2) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G = nx.DiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) - G = nx.MultiDiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/utils.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/utils.py deleted file mode 100644 index 7bf9994..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/connectivity/utils.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -Utilities for connectivity package -""" - -import networkx as nx - -__all__ = ["build_auxiliary_node_connectivity", "build_auxiliary_edge_connectivity"] - - -@nx._dispatchable(returns_graph=True) -def build_auxiliary_node_connectivity(G): - r"""Creates a directed graph D from an undirected graph G to compute flow - based node connectivity. - - For an undirected graph G having `n` nodes and `m` edges we derive a - directed graph D with `2n` nodes and `2m+n` arcs by replacing each - original node `v` with two nodes `vA`, `vB` linked by an (internal) - arc in D. Then for each edge (`u`, `v`) in G we add two arcs (`uB`, `vA`) - and (`vB`, `uA`) in D. Finally we set the attribute capacity = 1 for each - arc in D [1]_. - - For a directed graph having `n` nodes and `m` arcs we derive a - directed graph D with `2n` nodes and `m+n` arcs by replacing each - original node `v` with two nodes `vA`, `vB` linked by an (internal) - arc (`vA`, `vB`) in D. Then for each arc (`u`, `v`) in G we add one - arc (`uB`, `vA`) in D. Finally we set the attribute capacity = 1 for - each arc in D. - - A dictionary with a mapping between nodes in the original graph and the - auxiliary digraph is stored as a graph attribute: D.graph['mapping']. - - References - ---------- - .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and - Erlebach, 'Network Analysis: Methodological Foundations', Lecture - Notes in Computer Science, Volume 3418, Springer-Verlag, 2005. - https://doi.org/10.1007/978-3-540-31955-9_7 - - """ - directed = G.is_directed() - - mapping = {} - H = nx.DiGraph() - - for i, node in enumerate(G): - mapping[node] = i - H.add_node(f"{i}A", id=node) - H.add_node(f"{i}B", id=node) - H.add_edge(f"{i}A", f"{i}B", capacity=1) - - edges = [] - for source, target in G.edges(): - edges.append((f"{mapping[source]}B", f"{mapping[target]}A")) - if not directed: - edges.append((f"{mapping[target]}B", f"{mapping[source]}A")) - H.add_edges_from(edges, capacity=1) - - # Store mapping as graph attribute - H.graph["mapping"] = mapping - return H - - -@nx._dispatchable(returns_graph=True) -def build_auxiliary_edge_connectivity(G): - """Auxiliary digraph for computing flow based edge connectivity - - If the input graph is undirected, we replace each edge (`u`,`v`) with - two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute - 'capacity' for each arc to 1. If the input graph is directed we simply - add the 'capacity' attribute. Part of algorithm 1 in [1]_ . - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. (this is a - chapter, look for the reference of the book). - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - """ - if G.is_directed(): - H = nx.DiGraph() - H.add_nodes_from(G.nodes()) - H.add_edges_from(G.edges(), capacity=1) - return H - else: - H = nx.DiGraph() - H.add_nodes_from(G.nodes()) - for source, target in G.edges(): - H.add_edges_from([(source, target), (target, source)], capacity=1) - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/core.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/core.py deleted file mode 100644 index 6acfb49..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/core.py +++ /dev/null @@ -1,649 +0,0 @@ -""" -Find the k-cores of a graph. - -The k-core is found by recursively pruning nodes with degrees less than k. - -See the following references for details: - -An O(m) Algorithm for Cores Decomposition of Networks -Vladimir Batagelj and Matjaz Zaversnik, 2003. -https://arxiv.org/abs/cs.DS/0310049 - -Generalized Cores -Vladimir Batagelj and Matjaz Zaversnik, 2002. -https://arxiv.org/pdf/cs/0202039 - -For directed graphs a more general notion is that of D-cores which -looks at (k, l) restrictions on (in, out) degree. The (k, k) D-core -is the k-core. - -D-cores: Measuring Collaboration of Directed Graphs Based on Degeneracy -Christos Giatsidis, Dimitrios M. Thilikos, Michalis Vazirgiannis, ICDM 2011. -http://www.graphdegeneracy.org/dcores_ICDM_2011.pdf - -Multi-scale structure and topological anomaly detection via a new network \ -statistic: The onion decomposition -L. Hébert-Dufresne, J. A. Grochow, and A. Allard -Scientific Reports 6, 31708 (2016) -http://doi.org/10.1038/srep31708 - -""" - -import networkx as nx - -__all__ = [ - "core_number", - "k_core", - "k_shell", - "k_crust", - "k_corona", - "k_truss", - "onion_layers", -] - - -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable -def core_number(G): - """Returns the core number for each node. - - A k-core is a maximal subgraph that contains nodes of degree k or more. - - The core number of a node is the largest value k of a k-core containing - that node. - - Parameters - ---------- - G : NetworkX graph - An undirected or directed graph - - Returns - ------- - core_number : dictionary - A dictionary keyed by node to the core number. - - Raises - ------ - NetworkXNotImplemented - If `G` is a multigraph or contains self loops. - - Notes - ----- - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> nx.core_number(H) - {0: 1, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 0} - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2), (2, 1), (2, 3), (2, 4), (3, 4), (4, 3)]) - >>> nx.core_number(G) - {1: 2, 2: 2, 3: 2, 4: 2} - - References - ---------- - .. [1] An O(m) Algorithm for Cores Decomposition of Networks - Vladimir Batagelj and Matjaz Zaversnik, 2003. - https://arxiv.org/abs/cs.DS/0310049 - """ - if nx.number_of_selfloops(G) > 0: - msg = ( - "Input graph has self loops which is not permitted; " - "Consider using G.remove_edges_from(nx.selfloop_edges(G))." - ) - raise nx.NetworkXNotImplemented(msg) - degrees = dict(G.degree()) - # Sort nodes by degree. - nodes = sorted(degrees, key=degrees.get) - bin_boundaries = [0] - curr_degree = 0 - for i, v in enumerate(nodes): - if degrees[v] > curr_degree: - bin_boundaries.extend([i] * (degrees[v] - curr_degree)) - curr_degree = degrees[v] - node_pos = {v: pos for pos, v in enumerate(nodes)} - # The initial guess for the core number of a node is its degree. - core = degrees - nbrs = {v: list(nx.all_neighbors(G, v)) for v in G} - for v in nodes: - for u in nbrs[v]: - if core[u] > core[v]: - nbrs[u].remove(v) - pos = node_pos[u] - bin_start = bin_boundaries[core[u]] - node_pos[u] = bin_start - node_pos[nodes[bin_start]] = pos - nodes[bin_start], nodes[pos] = nodes[pos], nodes[bin_start] - bin_boundaries[core[u]] += 1 - core[u] -= 1 - return core - - -def _core_subgraph(G, k_filter, k=None, core=None): - """Returns the subgraph induced by nodes passing filter `k_filter`. - - Parameters - ---------- - G : NetworkX graph - The graph or directed graph to process - k_filter : filter function - This function filters the nodes chosen. It takes three inputs: - A node of G, the filter's cutoff, and the core dict of the graph. - The function should return a Boolean value. - k : int, optional - The order of the core. If not specified use the max core number. - This value is used as the cutoff for the filter. - core : dict, optional - Precomputed core numbers keyed by node for the graph `G`. - If not specified, the core numbers will be computed from `G`. - - """ - if core is None: - core = core_number(G) - if k is None: - k = max(core.values()) - nodes = (v for v in core if k_filter(v, k, core)) - return G.subgraph(nodes).copy() - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def k_core(G, k=None, core_number=None): - """Returns the k-core of G. - - A k-core is a maximal subgraph that contains nodes of degree `k` or more. - - .. deprecated:: 3.3 - `k_core` will not accept `MultiGraph` objects in version 3.5. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph - k : int, optional - The order of the core. If not specified return the main core. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-core subgraph - - Raises - ------ - NetworkXNotImplemented - The k-core is not defined for multigraphs or graphs with self loops. - - Notes - ----- - The main core is the core with `k` as the largest core_number. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.k_core(H).nodes - NodeView((1, 2, 3, 5)) - - See Also - -------- - core_number - - References - ---------- - .. [1] An O(m) Algorithm for Cores Decomposition of Networks - Vladimir Batagelj and Matjaz Zaversnik, 2003. - https://arxiv.org/abs/cs.DS/0310049 - """ - - import warnings - - if G.is_multigraph(): - warnings.warn( - ( - "\n\n`k_core` will not accept `MultiGraph` objects in version 3.5.\n" - "Convert it to an undirected graph instead, using::\n\n" - "\tG = nx.Graph(G)\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - - def k_filter(v, k, c): - return c[v] >= k - - return _core_subgraph(G, k_filter, k, core_number) - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def k_shell(G, k=None, core_number=None): - """Returns the k-shell of G. - - The k-shell is the subgraph induced by nodes with core number k. - That is, nodes in the k-core that are not in the (k+1)-core. - - .. deprecated:: 3.3 - `k_shell` will not accept `MultiGraph` objects in version 3.5. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph. - k : int, optional - The order of the shell. If not specified return the outer shell. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - - Returns - ------- - G : NetworkX graph - The k-shell subgraph - - Raises - ------ - NetworkXNotImplemented - The k-shell is not implemented for multigraphs or graphs with self loops. - - Notes - ----- - This is similar to k_corona but in that case only neighbors in the - k-core are considered. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.k_shell(H, k=1).nodes - NodeView((0, 4)) - - See Also - -------- - core_number - k_corona - - - References - ---------- - .. [1] A model of Internet topology using k-shell decomposition - Shai Carmi, Shlomo Havlin, Scott Kirkpatrick, Yuval Shavitt, - and Eran Shir, PNAS July 3, 2007 vol. 104 no. 27 11150-11154 - http://www.pnas.org/content/104/27/11150.full - """ - - import warnings - - if G.is_multigraph(): - warnings.warn( - ( - "\n\n`k_shell` will not accept `MultiGraph` objects in version 3.5.\n" - "Convert it to an undirected graph instead, using::\n\n" - "\tG = nx.Graph(G)\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - - def k_filter(v, k, c): - return c[v] == k - - return _core_subgraph(G, k_filter, k, core_number) - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def k_crust(G, k=None, core_number=None): - """Returns the k-crust of G. - - The k-crust is the graph G with the edges of the k-core removed - and isolated nodes found after the removal of edges are also removed. - - .. deprecated:: 3.3 - `k_crust` will not accept `MultiGraph` objects in version 3.5. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph. - k : int, optional - The order of the shell. If not specified return the main crust. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-crust subgraph - - Raises - ------ - NetworkXNotImplemented - The k-crust is not implemented for multigraphs or graphs with self loops. - - Notes - ----- - This definition of k-crust is different than the definition in [1]_. - The k-crust in [1]_ is equivalent to the k+1 crust of this algorithm. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.k_crust(H, k=1).nodes - NodeView((0, 4, 6)) - - See Also - -------- - core_number - - References - ---------- - .. [1] A model of Internet topology using k-shell decomposition - Shai Carmi, Shlomo Havlin, Scott Kirkpatrick, Yuval Shavitt, - and Eran Shir, PNAS July 3, 2007 vol. 104 no. 27 11150-11154 - http://www.pnas.org/content/104/27/11150.full - """ - - import warnings - - if G.is_multigraph(): - warnings.warn( - ( - "\n\n`k_crust` will not accept `MultiGraph` objects in version 3.5.\n" - "Convert it to an undirected graph instead, using::\n\n" - "\tG = nx.Graph(G)\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - - # Default for k is one less than in _core_subgraph, so just inline. - # Filter is c[v] <= k - if core_number is None: - core_number = nx.core_number(G) - if k is None: - k = max(core_number.values()) - 1 - nodes = (v for v in core_number if core_number[v] <= k) - return G.subgraph(nodes).copy() - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def k_corona(G, k, core_number=None): - """Returns the k-corona of G. - - The k-corona is the subgraph of nodes in the k-core which have - exactly k neighbors in the k-core. - - .. deprecated:: 3.3 - `k_corona` will not accept `MultiGraph` objects in version 3.5. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph - k : int - The order of the corona. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-corona subgraph - - Raises - ------ - NetworkXNotImplemented - The k-corona is not defined for multigraphs or graphs with self loops. - - Notes - ----- - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.k_corona(H, k=2).nodes - NodeView((1, 2, 3, 5)) - - See Also - -------- - core_number - - References - ---------- - .. [1] k -core (bootstrap) percolation on complex networks: - Critical phenomena and nonlocal effects, - A. V. Goltsev, S. N. Dorogovtsev, and J. F. F. Mendes, - Phys. Rev. E 73, 056101 (2006) - http://link.aps.org/doi/10.1103/PhysRevE.73.056101 - """ - - import warnings - - if G.is_multigraph(): - warnings.warn( - ( - "\n\n`k_corona` will not accept `MultiGraph` objects in version 3.5.\n" - "Convert it to an undirected graph instead, using::\n\n" - "\tG = nx.Graph(G)\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - - def func(v, k, c): - return c[v] == k and k == sum(1 for w in G[v] if c[w] >= k) - - return _core_subgraph(G, func, k, core_number) - - -@nx.utils.not_implemented_for("directed") -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def k_truss(G, k): - """Returns the k-truss of `G`. - - The k-truss is the maximal induced subgraph of `G` which contains at least - three vertices where every edge is incident to at least `k-2` triangles. - - Parameters - ---------- - G : NetworkX graph - An undirected graph - k : int - The order of the truss - - Returns - ------- - H : NetworkX graph - The k-truss subgraph - - Raises - ------ - NetworkXNotImplemented - If `G` is a multigraph or directed graph or if it contains self loops. - - Notes - ----- - A k-clique is a (k-2)-truss and a k-truss is a (k+1)-core. - - Graph, node, and edge attributes are copied to the subgraph. - - K-trusses were originally defined in [2] which states that the k-truss - is the maximal induced subgraph where each edge belongs to at least - `k-2` triangles. A more recent paper, [1], uses a slightly different - definition requiring that each edge belong to at least `k` triangles. - This implementation uses the original definition of `k-2` triangles. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.k_truss(H, k=2).nodes - NodeView((0, 1, 2, 3, 4, 5)) - - References - ---------- - .. [1] Bounds and Algorithms for k-truss. Paul Burkhardt, Vance Faber, - David G. Harris, 2018. https://arxiv.org/abs/1806.05523v2 - .. [2] Trusses: Cohesive Subgraphs for Social Network Analysis. Jonathan - Cohen, 2005. - """ - if nx.number_of_selfloops(G) > 0: - msg = ( - "Input graph has self loops which is not permitted; " - "Consider using G.remove_edges_from(nx.selfloop_edges(G))." - ) - raise nx.NetworkXNotImplemented(msg) - - H = G.copy() - - n_dropped = 1 - while n_dropped > 0: - n_dropped = 0 - to_drop = [] - seen = set() - for u in H: - nbrs_u = set(H[u]) - seen.add(u) - new_nbrs = [v for v in nbrs_u if v not in seen] - for v in new_nbrs: - if len(nbrs_u & set(H[v])) < (k - 2): - to_drop.append((u, v)) - H.remove_edges_from(to_drop) - n_dropped = len(to_drop) - H.remove_nodes_from(list(nx.isolates(H))) - - return H - - -@nx.utils.not_implemented_for("multigraph") -@nx.utils.not_implemented_for("directed") -@nx._dispatchable -def onion_layers(G): - """Returns the layer of each vertex in an onion decomposition of the graph. - - The onion decomposition refines the k-core decomposition by providing - information on the internal organization of each k-shell. It is usually - used alongside the `core numbers`. - - Parameters - ---------- - G : NetworkX graph - An undirected graph without self loops. - - Returns - ------- - od_layers : dictionary - A dictionary keyed by node to the onion layer. The layers are - contiguous integers starting at 1. - - Raises - ------ - NetworkXNotImplemented - If `G` is a multigraph or directed graph or if it contains self loops. - - Examples - -------- - >>> degrees = [0, 1, 2, 2, 2, 2, 3] - >>> H = nx.havel_hakimi_graph(degrees) - >>> H.degree - DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0}) - >>> nx.onion_layers(H) - {6: 1, 0: 2, 4: 3, 1: 4, 2: 4, 3: 4, 5: 4} - - See Also - -------- - core_number - - References - ---------- - .. [1] Multi-scale structure and topological anomaly detection via a new - network statistic: The onion decomposition - L. Hébert-Dufresne, J. A. Grochow, and A. Allard - Scientific Reports 6, 31708 (2016) - http://doi.org/10.1038/srep31708 - .. [2] Percolation and the effective structure of complex networks - A. Allard and L. Hébert-Dufresne - Physical Review X 9, 011023 (2019) - http://doi.org/10.1103/PhysRevX.9.011023 - """ - if nx.number_of_selfloops(G) > 0: - msg = ( - "Input graph contains self loops which is not permitted; " - "Consider using G.remove_edges_from(nx.selfloop_edges(G))." - ) - raise nx.NetworkXNotImplemented(msg) - # Dictionaries to register the k-core/onion decompositions. - od_layers = {} - # Adjacency list - neighbors = {v: list(nx.all_neighbors(G, v)) for v in G} - # Effective degree of nodes. - degrees = dict(G.degree()) - # Performs the onion decomposition. - current_core = 1 - current_layer = 1 - # Sets vertices of degree 0 to layer 1, if any. - isolated_nodes = list(nx.isolates(G)) - if len(isolated_nodes) > 0: - for v in isolated_nodes: - od_layers[v] = current_layer - degrees.pop(v) - current_layer = 2 - # Finds the layer for the remaining nodes. - while len(degrees) > 0: - # Sets the order for looking at nodes. - nodes = sorted(degrees, key=degrees.get) - # Sets properly the current core. - min_degree = degrees[nodes[0]] - if min_degree > current_core: - current_core = min_degree - # Identifies vertices in the current layer. - this_layer = [] - for n in nodes: - if degrees[n] > current_core: - break - this_layer.append(n) - # Identifies the core/layer of the vertices in the current layer. - for v in this_layer: - od_layers[v] = current_layer - for n in neighbors[v]: - neighbors[n].remove(v) - degrees[n] = degrees[n] - 1 - degrees.pop(v) - # Updates the layer count. - current_layer = current_layer + 1 - # Returns the dictionaries containing the onion layer of each vertices. - return od_layers diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/covering.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/covering.py deleted file mode 100644 index a0e15dd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/covering.py +++ /dev/null @@ -1,142 +0,0 @@ -"""Functions related to graph covers.""" - -from functools import partial -from itertools import chain - -import networkx as nx -from networkx.utils import arbitrary_element, not_implemented_for - -__all__ = ["min_edge_cover", "is_edge_cover"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def min_edge_cover(G, matching_algorithm=None): - """Returns the min cardinality edge cover of the graph as a set of edges. - - A smallest edge cover can be found in polynomial time by finding - a maximum matching and extending it greedily so that all nodes - are covered. This function follows that process. A maximum matching - algorithm can be specified for the first step of the algorithm. - The resulting set may return a set with one 2-tuple for each edge, - (the usual case) or with both 2-tuples `(u, v)` and `(v, u)` for - each edge. The latter is only done when a bipartite matching algorithm - is specified as `matching_algorithm`. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - matching_algorithm : function - A function that returns a maximum cardinality matching for `G`. - The function must take one input, the graph `G`, and return - either a set of edges (with only one direction for the pair of nodes) - or a dictionary mapping each node to its mate. If not specified, - :func:`~networkx.algorithms.matching.max_weight_matching` is used. - Common bipartite matching functions include - :func:`~networkx.algorithms.bipartite.matching.hopcroft_karp_matching` - or - :func:`~networkx.algorithms.bipartite.matching.eppstein_matching`. - - Returns - ------- - min_cover : set - - A set of the edges in a minimum edge cover in the form of tuples. - It contains only one of the equivalent 2-tuples `(u, v)` and `(v, u)` - for each edge. If a bipartite method is used to compute the matching, - the returned set contains both the 2-tuples `(u, v)` and `(v, u)` - for each edge of a minimum edge cover. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> sorted(nx.min_edge_cover(G)) - [(2, 1), (3, 0)] - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - The minimum edge cover is an edge covering of smallest cardinality. - - Due to its implementation, the worst-case running time of this algorithm - is bounded by the worst-case running time of the function - ``matching_algorithm``. - - Minimum edge cover for `G` can also be found using the `min_edge_covering` - function in :mod:`networkx.algorithms.bipartite.covering` which is - simply this function with a default matching algorithm of - :func:`~networkx.algorithms.bipartite.matching.hopcraft_karp_matching` - """ - if len(G) == 0: - return set() - if nx.number_of_isolates(G) > 0: - # ``min_cover`` does not exist as there is an isolated node - raise nx.NetworkXException( - "Graph has a node with no edge incident on it, so no edge cover exists." - ) - if matching_algorithm is None: - matching_algorithm = partial(nx.max_weight_matching, maxcardinality=True) - maximum_matching = matching_algorithm(G) - # ``min_cover`` is superset of ``maximum_matching`` - try: - # bipartite matching algs return dict so convert if needed - min_cover = set(maximum_matching.items()) - bipartite_cover = True - except AttributeError: - min_cover = maximum_matching - bipartite_cover = False - # iterate for uncovered nodes - uncovered_nodes = set(G) - {v for u, v in min_cover} - {u for u, v in min_cover} - for v in uncovered_nodes: - # Since `v` is uncovered, each edge incident to `v` will join it - # with a covered node (otherwise, if there were an edge joining - # uncovered nodes `u` and `v`, the maximum matching algorithm - # would have found it), so we can choose an arbitrary edge - # incident to `v`. (This applies only in a simple graph, not a - # multigraph.) - u = arbitrary_element(G[v]) - min_cover.add((u, v)) - if bipartite_cover: - min_cover.add((v, u)) - return min_cover - - -@not_implemented_for("directed") -@nx._dispatchable -def is_edge_cover(G, cover): - """Decides whether a set of edges is a valid edge cover of the graph. - - Given a set of edges, whether it is an edge covering can - be decided if we just check whether all nodes of the graph - has an edge from the set, incident on it. - - Parameters - ---------- - G : NetworkX graph - An undirected bipartite graph. - - cover : set - Set of edges to be checked. - - Returns - ------- - bool - Whether the set of edges is a valid edge cover of the graph. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> cover = {(2, 1), (3, 0)} - >>> nx.is_edge_cover(G, cover) - True - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - """ - return set(G) <= set(chain.from_iterable(cover)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cuts.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cuts.py deleted file mode 100644 index e951431..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cuts.py +++ /dev/null @@ -1,398 +0,0 @@ -"""Functions for finding and evaluating cuts in a graph.""" - -from itertools import chain - -import networkx as nx - -__all__ = [ - "boundary_expansion", - "conductance", - "cut_size", - "edge_expansion", - "mixing_expansion", - "node_expansion", - "normalized_cut_size", - "volume", -] - - -# TODO STILL NEED TO UPDATE ALL THE DOCUMENTATION! - - -@nx._dispatchable(edge_attrs="weight") -def cut_size(G, S, T=None, weight=None): - """Returns the size of the cut between two sets of nodes. - - A *cut* is a partition of the nodes of a graph into two sets. The - *cut size* is the sum of the weights of the edges "between" the two - sets of nodes. - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - T : collection - A collection of nodes in `G`. If not specified, this is taken to - be the set complement of `S`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - Total weight of all edges from nodes in set `S` to nodes in - set `T` (and, in the case of directed graphs, all edges from - nodes in `T` to nodes in `S`). - - Examples - -------- - In the graph with two cliques joined by a single edges, the natural - bipartition of the graph into two blocks, one for each clique, - yields a cut of weight one:: - - >>> G = nx.barbell_graph(3, 0) - >>> S = {0, 1, 2} - >>> T = {3, 4, 5} - >>> nx.cut_size(G, S, T) - 1 - - Each parallel edge in a multigraph is counted when determining the - cut size:: - - >>> G = nx.MultiGraph(["ab", "ab"]) - >>> S = {"a"} - >>> T = {"b"} - >>> nx.cut_size(G, S, T) - 2 - - Notes - ----- - In a multigraph, the cut size is the total weight of edges including - multiplicity. - - """ - edges = nx.edge_boundary(G, S, T, data=weight, default=1) - if G.is_directed(): - edges = chain(edges, nx.edge_boundary(G, T, S, data=weight, default=1)) - return sum(weight for u, v, weight in edges) - - -@nx._dispatchable(edge_attrs="weight") -def volume(G, S, weight=None): - """Returns the volume of a set of nodes. - - The *volume* of a set *S* is the sum of the (out-)degrees of nodes - in *S* (taking into account parallel edges in multigraphs). [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The volume of the set of nodes represented by `S` in the graph - `G`. - - See also - -------- - conductance - cut_size - edge_expansion - edge_boundary - normalized_cut_size - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - degree = G.out_degree if G.is_directed() else G.degree - return sum(d for v, d in degree(S, weight=weight)) - - -@nx._dispatchable(edge_attrs="weight") -def normalized_cut_size(G, S, T=None, weight=None): - """Returns the normalized size of the cut between two sets of nodes. - - The *normalized cut size* is the cut size times the sum of the - reciprocal sizes of the volumes of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - T : collection - A collection of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The normalized cut size between the two sets `S` and `T`. - - Notes - ----- - In a multigraph, the cut size is the total weight of edges including - multiplicity. - - See also - -------- - conductance - cut_size - edge_expansion - volume - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T=T, weight=weight) - volume_S = volume(G, S, weight=weight) - volume_T = volume(G, T, weight=weight) - return num_cut_edges * ((1 / volume_S) + (1 / volume_T)) - - -@nx._dispatchable(edge_attrs="weight") -def conductance(G, S, T=None, weight=None): - """Returns the conductance of two sets of nodes. - - The *conductance* is the quotient of the cut size and the smaller of - the volumes of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - T : collection - A collection of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The conductance between the two sets `S` and `T`. - - See also - -------- - cut_size - edge_expansion - normalized_cut_size - volume - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T, weight=weight) - volume_S = volume(G, S, weight=weight) - volume_T = volume(G, T, weight=weight) - return num_cut_edges / min(volume_S, volume_T) - - -@nx._dispatchable(edge_attrs="weight") -def edge_expansion(G, S, T=None, weight=None): - """Returns the edge expansion between two node sets. - - The *edge expansion* is the quotient of the cut size and the smaller - of the cardinalities of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - T : collection - A collection of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The edge expansion between the two sets `S` and `T`. - - See also - -------- - boundary_expansion - mixing_expansion - node_expansion - - References - ---------- - .. [1] Fan Chung. - *Spectral Graph Theory*. - (CBMS Regional Conference Series in Mathematics, No. 92), - American Mathematical Society, 1997, ISBN 0-8218-0315-8 - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T=T, weight=weight) - return num_cut_edges / min(len(S), len(T)) - - -@nx._dispatchable(edge_attrs="weight") -def mixing_expansion(G, S, T=None, weight=None): - """Returns the mixing expansion between two node sets. - - The *mixing expansion* is the quotient of the cut size and twice the - number of edges in the graph. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - T : collection - A collection of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The mixing expansion between the two sets `S` and `T`. - - See also - -------- - boundary_expansion - edge_expansion - node_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends - in Theoretical Computer Science* 7.1–3 (2011): 1–336. - - - """ - num_cut_edges = cut_size(G, S, T=T, weight=weight) - num_total_edges = G.number_of_edges() - return num_cut_edges / (2 * num_total_edges) - - -# TODO What is the generalization to two arguments, S and T? Does the -# denominator become `min(len(S), len(T))`? -@nx._dispatchable -def node_expansion(G, S): - """Returns the node expansion of the set `S`. - - The *node expansion* is the quotient of the size of the node - boundary of *S* and the cardinality of *S*. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - Returns - ------- - number - The node expansion of the set `S`. - - See also - -------- - boundary_expansion - edge_expansion - mixing_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends - in Theoretical Computer Science* 7.1–3 (2011): 1–336. - - - """ - neighborhood = set(chain.from_iterable(G.neighbors(v) for v in S)) - return len(neighborhood) / len(S) - - -# TODO What is the generalization to two arguments, S and T? Does the -# denominator become `min(len(S), len(T))`? -@nx._dispatchable -def boundary_expansion(G, S): - """Returns the boundary expansion of the set `S`. - - The *boundary expansion* is the quotient of the size - of the node boundary and the cardinality of *S*. [1] - - Parameters - ---------- - G : NetworkX graph - - S : collection - A collection of nodes in `G`. - - Returns - ------- - number - The boundary expansion of the set `S`. - - See also - -------- - edge_expansion - mixing_expansion - node_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends in Theoretical Computer Science* - 7.1–3 (2011): 1–336. - - - """ - return len(nx.node_boundary(G, S)) / len(S) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cycles.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cycles.py deleted file mode 100644 index 975462a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/cycles.py +++ /dev/null @@ -1,1230 +0,0 @@ -""" -======================== -Cycle finding algorithms -======================== -""" - -from collections import Counter, defaultdict -from itertools import combinations, product -from math import inf - -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = [ - "cycle_basis", - "simple_cycles", - "recursive_simple_cycles", - "find_cycle", - "minimum_cycle_basis", - "chordless_cycles", - "girth", -] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def cycle_basis(G, root=None): - """Returns a list of cycles which form a basis for cycles of G. - - A basis for cycles of a network is a minimal collection of - cycles such that any cycle in the network can be written - as a sum of cycles in the basis. Here summation of cycles - is defined as "exclusive or" of the edges. Cycle bases are - useful, e.g. when deriving equations for electric circuits - using Kirchhoff's Laws. - - Parameters - ---------- - G : NetworkX Graph - root : node, optional - Specify starting node for basis. - - Returns - ------- - A list of cycle lists. Each cycle list is a list of nodes - which forms a cycle (loop) in G. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_cycle(G, [0, 1, 2, 3]) - >>> nx.add_cycle(G, [0, 3, 4, 5]) - >>> nx.cycle_basis(G, 0) - [[3, 4, 5, 0], [1, 2, 3, 0]] - - Notes - ----- - This is adapted from algorithm CACM 491 [1]_. - - References - ---------- - .. [1] Paton, K. An algorithm for finding a fundamental set of - cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518. - - See Also - -------- - simple_cycles - minimum_cycle_basis - """ - gnodes = dict.fromkeys(G) # set-like object that maintains node order - cycles = [] - while gnodes: # loop over connected components - if root is None: - root = gnodes.popitem()[0] - stack = [root] - pred = {root: root} - used = {root: set()} - while stack: # walk the spanning tree finding cycles - z = stack.pop() # use last-in so cycles easier to find - zused = used[z] - for nbr in G[z]: - if nbr not in used: # new node - pred[nbr] = z - stack.append(nbr) - used[nbr] = {z} - elif nbr == z: # self loops - cycles.append([z]) - elif nbr not in zused: # found a cycle - pn = used[nbr] - cycle = [nbr, z] - p = pred[z] - while p not in pn: - cycle.append(p) - p = pred[p] - cycle.append(p) - cycles.append(cycle) - used[nbr].add(z) - for node in pred: - gnodes.pop(node, None) - root = None - return cycles - - -@nx._dispatchable -def simple_cycles(G, length_bound=None): - """Find simple cycles (elementary circuits) of a graph. - - A "simple cycle", or "elementary circuit", is a closed path where - no node appears twice. In a directed graph, two simple cycles are distinct - if they are not cyclic permutations of each other. In an undirected graph, - two simple cycles are distinct if they are not cyclic permutations of each - other nor of the other's reversal. - - Optionally, the cycles are bounded in length. In the unbounded case, we use - a nonrecursive, iterator/generator version of Johnson's algorithm [1]_. In - the bounded case, we use a version of the algorithm of Gupta and - Suzumura [2]_. There may be better algorithms for some cases [3]_ [4]_ [5]_. - - The algorithms of Johnson, and Gupta and Suzumura, are enhanced by some - well-known preprocessing techniques. When `G` is directed, we restrict our - attention to strongly connected components of `G`, generate all simple cycles - containing a certain node, remove that node, and further decompose the - remainder into strongly connected components. When `G` is undirected, we - restrict our attention to biconnected components, generate all simple cycles - containing a particular edge, remove that edge, and further decompose the - remainder into biconnected components. - - Note that multigraphs are supported by this function -- and in undirected - multigraphs, a pair of parallel edges is considered a cycle of length 2. - Likewise, self-loops are considered to be cycles of length 1. We define - cycles as sequences of nodes; so the presence of loops and parallel edges - does not change the number of simple cycles in a graph. - - Parameters - ---------- - G : NetworkX Graph - A networkx graph. Undirected, directed, and multigraphs are all supported. - - length_bound : int or None, optional (default=None) - If `length_bound` is an int, generate all simple cycles of `G` with length at - most `length_bound`. Otherwise, generate all simple cycles of `G`. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - - Examples - -------- - >>> G = nx.DiGraph([(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)]) - >>> sorted(nx.simple_cycles(G)) - [[0], [0, 1, 2], [0, 2], [1, 2], [2]] - - To filter the cycles so that they don't include certain nodes or edges, - copy your graph and eliminate those nodes or edges before calling. - For example, to exclude self-loops from the above example: - - >>> H = G.copy() - >>> H.remove_edges_from(nx.selfloop_edges(G)) - >>> sorted(nx.simple_cycles(H)) - [[0, 1, 2], [0, 2], [1, 2]] - - Notes - ----- - When `length_bound` is None, the time complexity is $O((n+e)(c+1))$ for $n$ - nodes, $e$ edges and $c$ simple circuits. Otherwise, when ``length_bound > 1``, - the time complexity is $O((c+n)(k-1)d^k)$ where $d$ is the average degree of - the nodes of `G` and $k$ = `length_bound`. - - Raises - ------ - ValueError - when ``length_bound < 0``. - - References - ---------- - .. [1] Finding all the elementary circuits of a directed graph. - D. B. Johnson, SIAM Journal on Computing 4, no. 1, 77-84, 1975. - https://doi.org/10.1137/0204007 - .. [2] Finding All Bounded-Length Simple Cycles in a Directed Graph - A. Gupta and T. Suzumura https://arxiv.org/abs/2105.10094 - .. [3] Enumerating the cycles of a digraph: a new preprocessing strategy. - G. Loizou and P. Thanish, Information Sciences, v. 27, 163-182, 1982. - .. [4] A search strategy for the elementary cycles of a directed graph. - J.L. Szwarcfiter and P.E. Lauer, BIT NUMERICAL MATHEMATICS, - v. 16, no. 2, 192-204, 1976. - .. [5] Optimal Listing of Cycles and st-Paths in Undirected Graphs - R. Ferreira and R. Grossi and A. Marino and N. Pisanti and R. Rizzi and - G. Sacomoto https://arxiv.org/abs/1205.2766 - - See Also - -------- - cycle_basis - chordless_cycles - """ - - if length_bound is not None: - if length_bound == 0: - return - elif length_bound < 0: - raise ValueError("length bound must be non-negative") - - directed = G.is_directed() - yield from ([v] for v, Gv in G.adj.items() if v in Gv) - - if length_bound is not None and length_bound == 1: - return - - if G.is_multigraph() and not directed: - visited = set() - for u, Gu in G.adj.items(): - multiplicity = ((v, len(Guv)) for v, Guv in Gu.items() if v in visited) - yield from ([u, v] for v, m in multiplicity if m > 1) - visited.add(u) - - # explicitly filter out loops; implicitly filter out parallel edges - if directed: - G = nx.DiGraph((u, v) for u, Gu in G.adj.items() for v in Gu if v != u) - else: - G = nx.Graph((u, v) for u, Gu in G.adj.items() for v in Gu if v != u) - - # this case is not strictly necessary but improves performance - if length_bound is not None and length_bound == 2: - if directed: - visited = set() - for u, Gu in G.adj.items(): - yield from ( - [v, u] for v in visited.intersection(Gu) if G.has_edge(v, u) - ) - visited.add(u) - return - - if directed: - yield from _directed_cycle_search(G, length_bound) - else: - yield from _undirected_cycle_search(G, length_bound) - - -def _directed_cycle_search(G, length_bound): - """A dispatch function for `simple_cycles` for directed graphs. - - We generate all cycles of G through binary partition. - - 1. Pick a node v in G which belongs to at least one cycle - a. Generate all cycles of G which contain the node v. - b. Recursively generate all cycles of G \\ v. - - This is accomplished through the following: - - 1. Compute the strongly connected components SCC of G. - 2. Select and remove a biconnected component C from BCC. Select a - non-tree edge (u, v) of a depth-first search of G[C]. - 3. For each simple cycle P containing v in G[C], yield P. - 4. Add the biconnected components of G[C \\ v] to BCC. - - If the parameter length_bound is not None, then step 3 will be limited to - simple cycles of length at most length_bound. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - length_bound : int or None - If length_bound is an int, generate all simple cycles of G with length at most length_bound. - Otherwise, generate all simple cycles of G. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - """ - - scc = nx.strongly_connected_components - components = [c for c in scc(G) if len(c) >= 2] - while components: - c = components.pop() - Gc = G.subgraph(c) - v = next(iter(c)) - if length_bound is None: - yield from _johnson_cycle_search(Gc, [v]) - else: - yield from _bounded_cycle_search(Gc, [v], length_bound) - # delete v after searching G, to make sure we can find v - G.remove_node(v) - components.extend(c for c in scc(Gc) if len(c) >= 2) - - -def _undirected_cycle_search(G, length_bound): - """A dispatch function for `simple_cycles` for undirected graphs. - - We generate all cycles of G through binary partition. - - 1. Pick an edge (u, v) in G which belongs to at least one cycle - a. Generate all cycles of G which contain the edge (u, v) - b. Recursively generate all cycles of G \\ (u, v) - - This is accomplished through the following: - - 1. Compute the biconnected components BCC of G. - 2. Select and remove a biconnected component C from BCC. Select a - non-tree edge (u, v) of a depth-first search of G[C]. - 3. For each (v -> u) path P remaining in G[C] \\ (u, v), yield P. - 4. Add the biconnected components of G[C] \\ (u, v) to BCC. - - If the parameter length_bound is not None, then step 3 will be limited to simple paths - of length at most length_bound. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph - - length_bound : int or None - If length_bound is an int, generate all simple cycles of G with length at most length_bound. - Otherwise, generate all simple cycles of G. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - """ - - bcc = nx.biconnected_components - components = [c for c in bcc(G) if len(c) >= 3] - while components: - c = components.pop() - Gc = G.subgraph(c) - uv = list(next(iter(Gc.edges))) - G.remove_edge(*uv) - # delete (u, v) before searching G, to avoid fake 3-cycles [u, v, u] - if length_bound is None: - yield from _johnson_cycle_search(Gc, uv) - else: - yield from _bounded_cycle_search(Gc, uv, length_bound) - components.extend(c for c in bcc(Gc) if len(c) >= 3) - - -class _NeighborhoodCache(dict): - """Very lightweight graph wrapper which caches neighborhoods as list. - - This dict subclass uses the __missing__ functionality to query graphs for - their neighborhoods, and store the result as a list. This is used to avoid - the performance penalty incurred by subgraph views. - """ - - def __init__(self, G): - self.G = G - - def __missing__(self, v): - Gv = self[v] = list(self.G[v]) - return Gv - - -def _johnson_cycle_search(G, path): - """The main loop of the cycle-enumeration algorithm of Johnson. - - Parameters - ---------- - G : NetworkX Graph or DiGraph - A graph - - path : list - A cycle prefix. All cycles generated will begin with this prefix. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - - References - ---------- - .. [1] Finding all the elementary circuits of a directed graph. - D. B. Johnson, SIAM Journal on Computing 4, no. 1, 77-84, 1975. - https://doi.org/10.1137/0204007 - - """ - - G = _NeighborhoodCache(G) - blocked = set(path) - B = defaultdict(set) # graph portions that yield no elementary circuit - start = path[0] - stack = [iter(G[path[-1]])] - closed = [False] - while stack: - nbrs = stack[-1] - for w in nbrs: - if w == start: - yield path[:] - closed[-1] = True - elif w not in blocked: - path.append(w) - closed.append(False) - stack.append(iter(G[w])) - blocked.add(w) - break - else: # no more nbrs - stack.pop() - v = path.pop() - if closed.pop(): - if closed: - closed[-1] = True - unblock_stack = {v} - while unblock_stack: - u = unblock_stack.pop() - if u in blocked: - blocked.remove(u) - unblock_stack.update(B[u]) - B[u].clear() - else: - for w in G[v]: - B[w].add(v) - - -def _bounded_cycle_search(G, path, length_bound): - """The main loop of the cycle-enumeration algorithm of Gupta and Suzumura. - - Parameters - ---------- - G : NetworkX Graph or DiGraph - A graph - - path : list - A cycle prefix. All cycles generated will begin with this prefix. - - length_bound: int - A length bound. All cycles generated will have length at most length_bound. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - - References - ---------- - .. [1] Finding All Bounded-Length Simple Cycles in a Directed Graph - A. Gupta and T. Suzumura https://arxiv.org/abs/2105.10094 - - """ - G = _NeighborhoodCache(G) - lock = {v: 0 for v in path} - B = defaultdict(set) - start = path[0] - stack = [iter(G[path[-1]])] - blen = [length_bound] - while stack: - nbrs = stack[-1] - for w in nbrs: - if w == start: - yield path[:] - blen[-1] = 1 - elif len(path) < lock.get(w, length_bound): - path.append(w) - blen.append(length_bound) - lock[w] = len(path) - stack.append(iter(G[w])) - break - else: - stack.pop() - v = path.pop() - bl = blen.pop() - if blen: - blen[-1] = min(blen[-1], bl) - if bl < length_bound: - relax_stack = [(bl, v)] - while relax_stack: - bl, u = relax_stack.pop() - if lock.get(u, length_bound) < length_bound - bl + 1: - lock[u] = length_bound - bl + 1 - relax_stack.extend((bl + 1, w) for w in B[u].difference(path)) - else: - for w in G[v]: - B[w].add(v) - - -@nx._dispatchable -def chordless_cycles(G, length_bound=None): - """Find simple chordless cycles of a graph. - - A `simple cycle` is a closed path where no node appears twice. In a simple - cycle, a `chord` is an additional edge between two nodes in the cycle. A - `chordless cycle` is a simple cycle without chords. Said differently, a - chordless cycle is a cycle C in a graph G where the number of edges in the - induced graph G[C] is equal to the length of `C`. - - Note that some care must be taken in the case that G is not a simple graph - nor a simple digraph. Some authors limit the definition of chordless cycles - to have a prescribed minimum length; we do not. - - 1. We interpret self-loops to be chordless cycles, except in multigraphs - with multiple loops in parallel. Likewise, in a chordless cycle of - length greater than 1, there can be no nodes with self-loops. - - 2. We interpret directed two-cycles to be chordless cycles, except in - multi-digraphs when any edge in a two-cycle has a parallel copy. - - 3. We interpret parallel pairs of undirected edges as two-cycles, except - when a third (or more) parallel edge exists between the two nodes. - - 4. Generalizing the above, edges with parallel clones may not occur in - chordless cycles. - - In a directed graph, two chordless cycles are distinct if they are not - cyclic permutations of each other. In an undirected graph, two chordless - cycles are distinct if they are not cyclic permutations of each other nor of - the other's reversal. - - Optionally, the cycles are bounded in length. - - We use an algorithm strongly inspired by that of Dias et al [1]_. It has - been modified in the following ways: - - 1. Recursion is avoided, per Python's limitations - - 2. The labeling function is not necessary, because the starting paths - are chosen (and deleted from the host graph) to prevent multiple - occurrences of the same path - - 3. The search is optionally bounded at a specified length - - 4. Support for directed graphs is provided by extending cycles along - forward edges, and blocking nodes along forward and reverse edges - - 5. Support for multigraphs is provided by omitting digons from the set - of forward edges - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - length_bound : int or None, optional (default=None) - If length_bound is an int, generate all simple cycles of G with length at - most length_bound. Otherwise, generate all simple cycles of G. - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - - Examples - -------- - >>> sorted(list(nx.chordless_cycles(nx.complete_graph(4)))) - [[1, 0, 2], [1, 0, 3], [2, 0, 3], [2, 1, 3]] - - Notes - ----- - When length_bound is None, and the graph is simple, the time complexity is - $O((n+e)(c+1))$ for $n$ nodes, $e$ edges and $c$ chordless cycles. - - Raises - ------ - ValueError - when length_bound < 0. - - References - ---------- - .. [1] Efficient enumeration of chordless cycles - E. Dias and D. Castonguay and H. Longo and W.A.R. Jradi - https://arxiv.org/abs/1309.1051 - - See Also - -------- - simple_cycles - """ - - if length_bound is not None: - if length_bound == 0: - return - elif length_bound < 0: - raise ValueError("length bound must be non-negative") - - directed = G.is_directed() - multigraph = G.is_multigraph() - - if multigraph: - yield from ([v] for v, Gv in G.adj.items() if len(Gv.get(v, ())) == 1) - else: - yield from ([v] for v, Gv in G.adj.items() if v in Gv) - - if length_bound is not None and length_bound == 1: - return - - # Nodes with loops cannot belong to longer cycles. Let's delete them here. - # also, we implicitly reduce the multiplicity of edges down to 1 in the case - # of multiedges. - if directed: - F = nx.DiGraph((u, v) for u, Gu in G.adj.items() if u not in Gu for v in Gu) - B = F.to_undirected(as_view=False) - else: - F = nx.Graph((u, v) for u, Gu in G.adj.items() if u not in Gu for v in Gu) - B = None - - # If we're given a multigraph, we have a few cases to consider with parallel - # edges. - # - # 1. If we have 2 or more edges in parallel between the nodes (u, v), we - # must not construct longer cycles along (u, v). - # 2. If G is not directed, then a pair of parallel edges between (u, v) is a - # chordless cycle unless there exists a third (or more) parallel edge. - # 3. If G is directed, then parallel edges do not form cycles, but do - # preclude back-edges from forming cycles (handled in the next section), - # Thus, if an edge (u, v) is duplicated and the reverse (v, u) is also - # present, then we remove both from F. - # - # In directed graphs, we need to consider both directions that edges can - # take, so iterate over all edges (u, v) and possibly (v, u). In undirected - # graphs, we need to be a little careful to only consider every edge once, - # so we use a "visited" set to emulate node-order comparisons. - - if multigraph: - if not directed: - B = F.copy() - visited = set() - for u, Gu in G.adj.items(): - if directed: - multiplicity = ((v, len(Guv)) for v, Guv in Gu.items()) - for v, m in multiplicity: - if m > 1: - F.remove_edges_from(((u, v), (v, u))) - else: - multiplicity = ((v, len(Guv)) for v, Guv in Gu.items() if v in visited) - for v, m in multiplicity: - if m == 2: - yield [u, v] - if m > 1: - F.remove_edge(u, v) - visited.add(u) - - # If we're given a directed graphs, we need to think about digons. If we - # have two edges (u, v) and (v, u), then that's a two-cycle. If either edge - # was duplicated above, then we removed both from F. So, any digons we find - # here are chordless. After finding digons, we remove their edges from F - # to avoid traversing them in the search for chordless cycles. - if directed: - for u, Fu in F.adj.items(): - digons = [[u, v] for v in Fu if F.has_edge(v, u)] - yield from digons - F.remove_edges_from(digons) - F.remove_edges_from(e[::-1] for e in digons) - - if length_bound is not None and length_bound == 2: - return - - # Now, we prepare to search for cycles. We have removed all cycles of - # lengths 1 and 2, so F is a simple graph or simple digraph. We repeatedly - # separate digraphs into their strongly connected components, and undirected - # graphs into their biconnected components. For each component, we pick a - # node v, search for chordless cycles based at each "stem" (u, v, w), and - # then remove v from that component before separating the graph again. - if directed: - separate = nx.strongly_connected_components - - # Directed stems look like (u -> v -> w), so we use the product of - # predecessors of v with successors of v. - def stems(C, v): - for u, w in product(C.pred[v], C.succ[v]): - if not G.has_edge(u, w): # omit stems with acyclic chords - yield [u, v, w], F.has_edge(w, u) - - else: - separate = nx.biconnected_components - - # Undirected stems look like (u ~ v ~ w), but we must not also search - # (w ~ v ~ u), so we use combinations of v's neighbors of length 2. - def stems(C, v): - yield from (([u, v, w], F.has_edge(w, u)) for u, w in combinations(C[v], 2)) - - components = [c for c in separate(F) if len(c) > 2] - while components: - c = components.pop() - v = next(iter(c)) - Fc = F.subgraph(c) - Fcc = Bcc = None - for S, is_triangle in stems(Fc, v): - if is_triangle: - yield S - else: - if Fcc is None: - Fcc = _NeighborhoodCache(Fc) - Bcc = Fcc if B is None else _NeighborhoodCache(B.subgraph(c)) - yield from _chordless_cycle_search(Fcc, Bcc, S, length_bound) - - components.extend(c for c in separate(F.subgraph(c - {v})) if len(c) > 2) - - -def _chordless_cycle_search(F, B, path, length_bound): - """The main loop for chordless cycle enumeration. - - This algorithm is strongly inspired by that of Dias et al [1]_. It has been - modified in the following ways: - - 1. Recursion is avoided, per Python's limitations - - 2. The labeling function is not necessary, because the starting paths - are chosen (and deleted from the host graph) to prevent multiple - occurrences of the same path - - 3. The search is optionally bounded at a specified length - - 4. Support for directed graphs is provided by extending cycles along - forward edges, and blocking nodes along forward and reverse edges - - 5. Support for multigraphs is provided by omitting digons from the set - of forward edges - - Parameters - ---------- - F : _NeighborhoodCache - A graph of forward edges to follow in constructing cycles - - B : _NeighborhoodCache - A graph of blocking edges to prevent the production of chordless cycles - - path : list - A cycle prefix. All cycles generated will begin with this prefix. - - length_bound : int - A length bound. All cycles generated will have length at most length_bound. - - - Yields - ------ - list of nodes - Each cycle is represented by a list of nodes along the cycle. - - References - ---------- - .. [1] Efficient enumeration of chordless cycles - E. Dias and D. Castonguay and H. Longo and W.A.R. Jradi - https://arxiv.org/abs/1309.1051 - - """ - blocked = defaultdict(int) - target = path[0] - blocked[path[1]] = 1 - for w in path[1:]: - for v in B[w]: - blocked[v] += 1 - - stack = [iter(F[path[2]])] - while stack: - nbrs = stack[-1] - for w in nbrs: - if blocked[w] == 1 and (length_bound is None or len(path) < length_bound): - Fw = F[w] - if target in Fw: - yield path + [w] - else: - Bw = B[w] - if target in Bw: - continue - for v in Bw: - blocked[v] += 1 - path.append(w) - stack.append(iter(Fw)) - break - else: - stack.pop() - for v in B[path.pop()]: - blocked[v] -= 1 - - -@not_implemented_for("undirected") -@nx._dispatchable(mutates_input=True) -def recursive_simple_cycles(G): - """Find simple cycles (elementary circuits) of a directed graph. - - A `simple cycle`, or `elementary circuit`, is a closed path where - no node appears twice. Two elementary circuits are distinct if they - are not cyclic permutations of each other. - - This version uses a recursive algorithm to build a list of cycles. - You should probably use the iterator version called simple_cycles(). - Warning: This recursive version uses lots of RAM! - It appears in NetworkX for pedagogical value. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - A list of cycles, where each cycle is represented by a list of nodes - along the cycle. - - Example: - - >>> edges = [(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)] - >>> G = nx.DiGraph(edges) - >>> nx.recursive_simple_cycles(G) - [[0], [2], [0, 1, 2], [0, 2], [1, 2]] - - Notes - ----- - The implementation follows pp. 79-80 in [1]_. - - The time complexity is $O((n+e)(c+1))$ for $n$ nodes, $e$ edges and $c$ - elementary circuits. - - References - ---------- - .. [1] Finding all the elementary circuits of a directed graph. - D. B. Johnson, SIAM Journal on Computing 4, no. 1, 77-84, 1975. - https://doi.org/10.1137/0204007 - - See Also - -------- - simple_cycles, cycle_basis - """ - - # Jon Olav Vik, 2010-08-09 - def _unblock(thisnode): - """Recursively unblock and remove nodes from B[thisnode].""" - if blocked[thisnode]: - blocked[thisnode] = False - while B[thisnode]: - _unblock(B[thisnode].pop()) - - def circuit(thisnode, startnode, component): - closed = False # set to True if elementary path is closed - path.append(thisnode) - blocked[thisnode] = True - for nextnode in component[thisnode]: # direct successors of thisnode - if nextnode == startnode: - result.append(path[:]) - closed = True - elif not blocked[nextnode]: - if circuit(nextnode, startnode, component): - closed = True - if closed: - _unblock(thisnode) - else: - for nextnode in component[thisnode]: - if thisnode not in B[nextnode]: # TODO: use set for speedup? - B[nextnode].append(thisnode) - path.pop() # remove thisnode from path - return closed - - path = [] # stack of nodes in current path - blocked = defaultdict(bool) # vertex: blocked from search? - B = defaultdict(list) # graph portions that yield no elementary circuit - result = [] # list to accumulate the circuits found - - # Johnson's algorithm exclude self cycle edges like (v, v) - # To be backward compatible, we record those cycles in advance - # and then remove from subG - for v in G: - if G.has_edge(v, v): - result.append([v]) - G.remove_edge(v, v) - - # Johnson's algorithm requires some ordering of the nodes. - # They might not be sortable so we assign an arbitrary ordering. - ordering = dict(zip(G, range(len(G)))) - for s in ordering: - # Build the subgraph induced by s and following nodes in the ordering - subgraph = G.subgraph(node for node in G if ordering[node] >= ordering[s]) - # Find the strongly connected component in the subgraph - # that contains the least node according to the ordering - strongcomp = nx.strongly_connected_components(subgraph) - mincomp = min(strongcomp, key=lambda ns: min(ordering[n] for n in ns)) - component = G.subgraph(mincomp) - if len(component) > 1: - # smallest node in the component according to the ordering - startnode = min(component, key=ordering.__getitem__) - for node in component: - blocked[node] = False - B[node][:] = [] - dummy = circuit(startnode, startnode, component) - return result - - -@nx._dispatchable -def find_cycle(G, source=None, orientation=None): - """Returns a cycle found via depth-first traversal. - - The cycle is a list of edges indicating the cyclic path. - Orientation of directed edges is controlled by `orientation`. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Returns - ------- - edges : directed edges - A list of directed edges indicating the path taken for the loop. - If no cycle is found, then an exception is raised. - For graphs, an edge is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, an edge is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Raises - ------ - NetworkXNoCycle - If no cycle was found. - - Examples - -------- - In this example, we construct a DAG and find, in the first call, that there - are no directed cycles, and so an exception is raised. In the second call, - we ignore edge orientations and find that there is an undirected cycle. - Note that the second call finds a directed cycle while effectively - traversing an undirected graph, and so, we found an "undirected cycle". - This means that this DAG structure does not form a directed tree (which - is also known as a polytree). - - >>> G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - >>> nx.find_cycle(G, orientation="original") - Traceback (most recent call last): - ... - networkx.exception.NetworkXNoCycle: No cycle found. - >>> list(nx.find_cycle(G, orientation="ignore")) - [(0, 1, 'forward'), (1, 2, 'forward'), (0, 2, 'reverse')] - - See Also - -------- - simple_cycles - """ - if not G.is_directed() or orientation in (None, "original"): - - def tailhead(edge): - return edge[:2] - - elif orientation == "reverse": - - def tailhead(edge): - return edge[1], edge[0] - - elif orientation == "ignore": - - def tailhead(edge): - if edge[-1] == "reverse": - return edge[1], edge[0] - return edge[:2] - - explored = set() - cycle = [] - final_node = None - for start_node in G.nbunch_iter(source): - if start_node in explored: - # No loop is possible. - continue - - edges = [] - # All nodes seen in this iteration of edge_dfs - seen = {start_node} - # Nodes in active path. - active_nodes = {start_node} - previous_head = None - - for edge in nx.edge_dfs(G, start_node, orientation): - # Determine if this edge is a continuation of the active path. - tail, head = tailhead(edge) - if head in explored: - # Then we've already explored it. No loop is possible. - continue - if previous_head is not None and tail != previous_head: - # This edge results from backtracking. - # Pop until we get a node whose head equals the current tail. - # So for example, we might have: - # (0, 1), (1, 2), (2, 3), (1, 4) - # which must become: - # (0, 1), (1, 4) - while True: - try: - popped_edge = edges.pop() - except IndexError: - edges = [] - active_nodes = {tail} - break - else: - popped_head = tailhead(popped_edge)[1] - active_nodes.remove(popped_head) - - if edges: - last_head = tailhead(edges[-1])[1] - if tail == last_head: - break - edges.append(edge) - - if head in active_nodes: - # We have a loop! - cycle.extend(edges) - final_node = head - break - else: - seen.add(head) - active_nodes.add(head) - previous_head = head - - if cycle: - break - else: - explored.update(seen) - - else: - assert len(cycle) == 0 - raise nx.exception.NetworkXNoCycle("No cycle found.") - - # We now have a list of edges which ends on a cycle. - # So we need to remove from the beginning edges that are not relevant. - - for i, edge in enumerate(cycle): - tail, head = tailhead(edge) - if tail == final_node: - break - - return cycle[i:] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def minimum_cycle_basis(G, weight=None): - """Returns a minimum weight cycle basis for G - - Minimum weight means a cycle basis for which the total weight - (length for unweighted graphs) of all the cycles is minimum. - - Parameters - ---------- - G : NetworkX Graph - weight: string - name of the edge attribute to use for edge weights - - Returns - ------- - A list of cycle lists. Each cycle list is a list of nodes - which forms a cycle (loop) in G. Note that the nodes are not - necessarily returned in a order by which they appear in the cycle - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_cycle(G, [0, 1, 2, 3]) - >>> nx.add_cycle(G, [0, 3, 4, 5]) - >>> nx.minimum_cycle_basis(G) - [[5, 4, 3, 0], [3, 2, 1, 0]] - - References: - [1] Kavitha, Telikepalli, et al. "An O(m^2n) Algorithm for - Minimum Cycle Basis of Graphs." - http://link.springer.com/article/10.1007/s00453-007-9064-z - [2] de Pina, J. 1995. Applications of shortest path methods. - Ph.D. thesis, University of Amsterdam, Netherlands - - See Also - -------- - simple_cycles, cycle_basis - """ - # We first split the graph in connected subgraphs - return sum( - (_min_cycle_basis(G.subgraph(c), weight) for c in nx.connected_components(G)), - [], - ) - - -def _min_cycle_basis(G, weight): - cb = [] - # We extract the edges not in a spanning tree. We do not really need a - # *minimum* spanning tree. That is why we call the next function with - # weight=None. Depending on implementation, it may be faster as well - tree_edges = list(nx.minimum_spanning_edges(G, weight=None, data=False)) - chords = G.edges - tree_edges - {(v, u) for u, v in tree_edges} - - # We maintain a set of vectors orthogonal to sofar found cycles - set_orth = [{edge} for edge in chords] - while set_orth: - base = set_orth.pop() - # kth cycle is "parallel" to kth vector in set_orth - cycle_edges = _min_cycle(G, base, weight) - cb.append([v for u, v in cycle_edges]) - - # now update set_orth so that k+1,k+2... th elements are - # orthogonal to the newly found cycle, as per [p. 336, 1] - set_orth = [ - ( - {e for e in orth if e not in base if e[::-1] not in base} - | {e for e in base if e not in orth if e[::-1] not in orth} - ) - if sum((e in orth or e[::-1] in orth) for e in cycle_edges) % 2 - else orth - for orth in set_orth - ] - return cb - - -def _min_cycle(G, orth, weight): - """ - Computes the minimum weight cycle in G, - orthogonal to the vector orth as per [p. 338, 1] - Use (u, 1) to indicate the lifted copy of u (denoted u' in paper). - """ - Gi = nx.Graph() - - # Add 2 copies of each edge in G to Gi. - # If edge is in orth, add cross edge; otherwise in-plane edge - for u, v, wt in G.edges(data=weight, default=1): - if (u, v) in orth or (v, u) in orth: - Gi.add_edges_from([(u, (v, 1)), ((u, 1), v)], Gi_weight=wt) - else: - Gi.add_edges_from([(u, v), ((u, 1), (v, 1))], Gi_weight=wt) - - # find the shortest length in Gi between n and (n, 1) for each n - # Note: Use "Gi_weight" for name of weight attribute - spl = nx.shortest_path_length - lift = {n: spl(Gi, source=n, target=(n, 1), weight="Gi_weight") for n in G} - - # Now compute that short path in Gi, which translates to a cycle in G - start = min(lift, key=lift.get) - end = (start, 1) - min_path_i = nx.shortest_path(Gi, source=start, target=end, weight="Gi_weight") - - # Now we obtain the actual path, re-map nodes in Gi to those in G - min_path = [n if n in G else n[0] for n in min_path_i] - - # Now remove the edges that occur two times - # two passes: flag which edges get kept, then build it - edgelist = list(pairwise(min_path)) - edgeset = set() - for e in edgelist: - if e in edgeset: - edgeset.remove(e) - elif e[::-1] in edgeset: - edgeset.remove(e[::-1]) - else: - edgeset.add(e) - - min_edgelist = [] - for e in edgelist: - if e in edgeset: - min_edgelist.append(e) - edgeset.remove(e) - elif e[::-1] in edgeset: - min_edgelist.append(e[::-1]) - edgeset.remove(e[::-1]) - - return min_edgelist - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def girth(G): - """Returns the girth of the graph. - - The girth of a graph is the length of its shortest cycle, or infinity if - the graph is acyclic. The algorithm follows the description given on the - Wikipedia page [1]_, and runs in time O(mn) on a graph with m edges and n - nodes. - - Parameters - ---------- - G : NetworkX Graph - - Returns - ------- - int or math.inf - - Examples - -------- - All examples below (except P_5) can easily be checked using Wikipedia, - which has a page for each of these famous graphs. - - >>> nx.girth(nx.chvatal_graph()) - 4 - >>> nx.girth(nx.tutte_graph()) - 4 - >>> nx.girth(nx.petersen_graph()) - 5 - >>> nx.girth(nx.heawood_graph()) - 6 - >>> nx.girth(nx.pappus_graph()) - 6 - >>> nx.girth(nx.path_graph(5)) - inf - - References - ---------- - .. [1] `Wikipedia: Girth `_ - - """ - girth = depth_limit = inf - tree_edge = nx.algorithms.traversal.breadth_first_search.TREE_EDGE - level_edge = nx.algorithms.traversal.breadth_first_search.LEVEL_EDGE - for n in G: - # run a BFS from source n, keeping track of distances; since we want - # the shortest cycle, no need to explore beyond the current minimum length - depth = {n: 0} - for u, v, label in nx.bfs_labeled_edges(G, n): - du = depth[u] - if du > depth_limit: - break - if label is tree_edge: - depth[v] = du + 1 - else: - # if (u, v) is a level edge, the length is du + du + 1 (odd) - # otherwise, it's a forward edge; length is du + (du + 1) + 1 (even) - delta = label is level_edge - length = du + du + 2 - delta - if length < girth: - girth = length - depth_limit = du - delta - - return girth diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/d_separation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/d_separation.py deleted file mode 100644 index a688eca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/d_separation.py +++ /dev/null @@ -1,722 +0,0 @@ -""" -Algorithm for testing d-separation in DAGs. - -*d-separation* is a test for conditional independence in probability -distributions that can be factorized using DAGs. It is a purely -graphical test that uses the underlying graph and makes no reference -to the actual distribution parameters. See [1]_ for a formal -definition. - -The implementation is based on the conceptually simple linear time -algorithm presented in [2]_. Refer to [3]_, [4]_ for a couple of -alternative algorithms. - -The functional interface in NetworkX consists of three functions: - -- `find_minimal_d_separator` returns a minimal d-separator set ``z``. - That is, removing any node or nodes from it makes it no longer a d-separator. -- `is_d_separator` checks if a given set is a d-separator. -- `is_minimal_d_separator` checks if a given set is a minimal d-separator. - -D-separators ------------- - -Here, we provide a brief overview of d-separation and related concepts that -are relevant for understanding it: - -The ideas of d-separation and d-connection relate to paths being open or blocked. - -- A "path" is a sequence of nodes connected in order by edges. Unlike for most - graph theory analysis, the direction of the edges is ignored. Thus the path - can be thought of as a traditional path on the undirected version of the graph. -- A "candidate d-separator" ``z`` is a set of nodes being considered as - possibly blocking all paths between two prescribed sets ``x`` and ``y`` of nodes. - We refer to each node in the candidate d-separator as "known". -- A "collider" node on a path is a node that is a successor of its two neighbor - nodes on the path. That is, ``c`` is a collider if the edge directions - along the path look like ``... u -> c <- v ...``. -- If a collider node or any of its descendants are "known", the collider - is called an "open collider". Otherwise it is a "blocking collider". -- Any path can be "blocked" in two ways. If the path contains a "known" node - that is not a collider, the path is blocked. Also, if the path contains a - collider that is not a "known" node, the path is blocked. -- A path is "open" if it is not blocked. That is, it is open if every node is - either an open collider or not a "known". Said another way, every - "known" in the path is a collider and every collider is open (has a - "known" as a inclusive descendant). The concept of "open path" is meant to - demonstrate a probabilistic conditional dependence between two nodes given - prescribed knowledge ("known" nodes). -- Two sets ``x`` and ``y`` of nodes are "d-separated" by a set of nodes ``z`` - if all paths between nodes in ``x`` and nodes in ``y`` are blocked. That is, - if there are no open paths from any node in ``x`` to any node in ``y``. - Such a set ``z`` is a "d-separator" of ``x`` and ``y``. -- A "minimal d-separator" is a d-separator ``z`` for which no node or subset - of nodes can be removed with it still being a d-separator. - -The d-separator blocks some paths between ``x`` and ``y`` but opens others. -Nodes in the d-separator block paths if the nodes are not colliders. -But if a collider or its descendant nodes are in the d-separation set, the -colliders are open, allowing a path through that collider. - -Illustration of D-separation with examples ------------------------------------------- - -A pair of two nodes, ``u`` and ``v``, are d-connected if there is a path -from ``u`` to ``v`` that is not blocked. That means, there is an open -path from ``u`` to ``v``. - -For example, if the d-separating set is the empty set, then the following paths are -open between ``u`` and ``v``: - -- u <- n -> v -- u -> w -> ... -> n -> v - -If on the other hand, ``n`` is in the d-separating set, then ``n`` blocks -those paths between ``u`` and ``v``. - -Colliders block a path if they and their descendants are not included -in the d-separating set. An example of a path that is blocked when the -d-separating set is empty is: - -- u -> w -> ... -> n <- v - -The node ``n`` is a collider in this path and is not in the d-separating set. -So ``n`` blocks this path. However, if ``n`` or a descendant of ``n`` is -included in the d-separating set, then the path through the collider -at ``n`` (... -> n <- ...) is "open". - -D-separation is concerned with blocking all paths between nodes from ``x`` to ``y``. -A d-separating set between ``x`` and ``y`` is one where all paths are blocked. - -D-separation and its applications in probability ------------------------------------------------- - -D-separation is commonly used in probabilistic causal-graph models. D-separation -connects the idea of probabilistic "dependence" with separation in a graph. If -one assumes the causal Markov condition [5]_, (every node is conditionally -independent of its non-descendants, given its parents) then d-separation implies -conditional independence in probability distributions. -Symmetrically, d-connection implies dependence. - -The intuition is as follows. The edges on a causal graph indicate which nodes -influence the outcome of other nodes directly. An edge from u to v -implies that the outcome of event ``u`` influences the probabilities for -the outcome of event ``v``. Certainly knowing ``u`` changes predictions for ``v``. -But also knowing ``v`` changes predictions for ``u``. The outcomes are dependent. -Furthermore, an edge from ``v`` to ``w`` would mean that ``w`` and ``v`` are dependent -and thus that ``u`` could indirectly influence ``w``. - -Without any knowledge about the system (candidate d-separating set is empty) -a causal graph ``u -> v -> w`` allows all three nodes to be dependent. But -if we know the outcome of ``v``, the conditional probabilities of outcomes for -``u`` and ``w`` are independent of each other. That is, once we know the outcome -for ```v`, the probabilities for ``w`` do not depend on the outcome for ``u``. -This is the idea behind ``v`` blocking the path if it is "known" (in the candidate -d-separating set). - -The same argument works whether the direction of the edges are both -left-going and when both arrows head out from the middle. Having a "known" -node on a path blocks the collider-free path because those relationships -make the conditional probabilities independent. - -The direction of the causal edges does impact dependence precisely in the -case of a collider e.g. ``u -> v <- w``. In that situation, both ``u`` and ``w`` -influence ``v```. But they do not directly influence each other. So without any -knowledge of any outcomes, ``u`` and ``w`` are independent. That is the idea behind -colliders blocking the path. But, if ``v`` is known, the conditional probabilities -of ``u`` and ``w`` can be dependent. This is the heart of Berkson's Paradox [6]_. -For example, suppose ``u`` and ``w`` are boolean events (they either happen or do not) -and ``v`` represents the outcome "at least one of ``u`` and ``w`` occur". Then knowing -``v`` is true makes the conditional probabilities of ``u`` and ``w`` dependent. -Essentially, knowing that at least one of them is true raises the probability of -each. But further knowledge that ``w`` is true (or false) change the conditional -probability of ``u`` to either the original value or 1. So the conditional -probability of ``u`` depends on the outcome of ``w`` even though there is no -causal relationship between them. When a collider is known, dependence can -occur across paths through that collider. This is the reason open colliders -do not block paths. - -Furthermore, even if ``v`` is not "known", if one of its descendants is "known" -we can use that information to know more about ``v`` which again makes -``u`` and ``w`` potentially dependent. Suppose the chance of ``n`` occurring -is much higher when ``v`` occurs ("at least one of ``u`` and ``w`` occur"). -Then if we know ``n`` occurred, it is more likely that ``v`` occurred and that -makes the chance of ``u`` and ``w`` dependent. This is the idea behind why -a collider does no block a path if any descendant of the collider is "known". - -When two sets of nodes ``x`` and ``y`` are d-separated by a set ``z``, -it means that given the outcomes of the nodes in ``z``, the probabilities -of outcomes of the nodes in ``x`` are independent of the outcomes of the -nodes in ``y`` and vice versa. - -Examples --------- -A Hidden Markov Model with 5 observed states and 5 hidden states -where the hidden states have causal relationships resulting in -a path results in the following causal network. We check that -early states along the path are separated from late state in -the path by the d-separator of the middle hidden state. -Thus if we condition on the middle hidden state, the early -state probabilities are independent of the late state outcomes. - ->>> G = nx.DiGraph() ->>> G.add_edges_from( -... [ -... ("H1", "H2"), -... ("H2", "H3"), -... ("H3", "H4"), -... ("H4", "H5"), -... ("H1", "O1"), -... ("H2", "O2"), -... ("H3", "O3"), -... ("H4", "O4"), -... ("H5", "O5"), -... ] -... ) ->>> x, y, z = ({"H1", "O1"}, {"H5", "O5"}, {"H3"}) ->>> nx.is_d_separator(G, x, y, z) -True ->>> nx.is_minimal_d_separator(G, x, y, z) -True ->>> nx.is_minimal_d_separator(G, x, y, z | {"O3"}) -False ->>> z = nx.find_minimal_d_separator(G, x | y, {"O2", "O3", "O4"}) ->>> z == {"H2", "H4"} -True - -If no minimal_d_separator exists, `None` is returned - ->>> other_z = nx.find_minimal_d_separator(G, x | y, {"H2", "H3"}) ->>> other_z is None -True - - -References ----------- - -.. [1] Pearl, J. (2009). Causality. Cambridge: Cambridge University Press. - -.. [2] Darwiche, A. (2009). Modeling and reasoning with Bayesian networks. - Cambridge: Cambridge University Press. - -.. [3] Shachter, Ross D. "Bayes-ball: The rational pastime (for - determining irrelevance and requisite information in belief networks - and influence diagrams)." In Proceedings of the Fourteenth Conference - on Uncertainty in Artificial Intelligence (UAI), (pp. 480–487). 1998. - -.. [4] Koller, D., & Friedman, N. (2009). - Probabilistic graphical models: principles and techniques. The MIT Press. - -.. [5] https://en.wikipedia.org/wiki/Causal_Markov_condition - -.. [6] https://en.wikipedia.org/wiki/Berkson%27s_paradox - -""" - -from collections import deque -from itertools import chain - -import networkx as nx -from networkx.utils import UnionFind, not_implemented_for - -__all__ = [ - "is_d_separator", - "is_minimal_d_separator", - "find_minimal_d_separator", - "d_separated", - "minimal_d_separator", -] - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_d_separator(G, x, y, z): - """Return whether node sets `x` and `y` are d-separated by `z`. - - Parameters - ---------- - G : nx.DiGraph - A NetworkX DAG. - - x : node or set of nodes - First node or set of nodes in `G`. - - y : node or set of nodes - Second node or set of nodes in `G`. - - z : node or set of nodes - Potential separator (set of conditioning nodes in `G`). Can be empty set. - - Returns - ------- - b : bool - A boolean that is true if `x` is d-separated from `y` given `z` in `G`. - - Raises - ------ - NetworkXError - The *d-separation* test is commonly used on disjoint sets of - nodes in acyclic directed graphs. Accordingly, the algorithm - raises a :exc:`NetworkXError` if the node sets are not - disjoint or if the input graph is not a DAG. - - NodeNotFound - If any of the input nodes are not found in the graph, - a :exc:`NodeNotFound` exception is raised - - Notes - ----- - A d-separating set in a DAG is a set of nodes that - blocks all paths between the two sets. Nodes in `z` - block a path if they are part of the path and are not a collider, - or a descendant of a collider. Also colliders that are not in `z` - block a path. A collider structure along a path - is ``... -> c <- ...`` where ``c`` is the collider node. - - https://en.wikipedia.org/wiki/Bayesian_network#d-separation - """ - try: - x = {x} if x in G else x - y = {y} if y in G else y - z = {z} if z in G else z - - intersection = x & y or x & z or y & z - if intersection: - raise nx.NetworkXError( - f"The sets are not disjoint, with intersection {intersection}" - ) - - set_v = x | y | z - if set_v - G.nodes: - raise nx.NodeNotFound(f"The node(s) {set_v - G.nodes} are not found in G") - except TypeError: - raise nx.NodeNotFound("One of x, y, or z is not a node or a set of nodes in G") - - if not nx.is_directed_acyclic_graph(G): - raise nx.NetworkXError("graph should be directed acyclic") - - # contains -> and <-> edges from starting node T - forward_deque = deque([]) - forward_visited = set() - - # contains <- and - edges from starting node T - backward_deque = deque(x) - backward_visited = set() - - ancestors_or_z = set().union(*[nx.ancestors(G, node) for node in x]) | z | x - - while forward_deque or backward_deque: - if backward_deque: - node = backward_deque.popleft() - backward_visited.add(node) - if node in y: - return False - if node in z: - continue - - # add <- edges to backward deque - backward_deque.extend(G.pred[node].keys() - backward_visited) - # add -> edges to forward deque - forward_deque.extend(G.succ[node].keys() - forward_visited) - - if forward_deque: - node = forward_deque.popleft() - forward_visited.add(node) - if node in y: - return False - - # Consider if -> node <- is opened due to ancestor of node in z - if node in ancestors_or_z: - # add <- edges to backward deque - backward_deque.extend(G.pred[node].keys() - backward_visited) - if node not in z: - # add -> edges to forward deque - forward_deque.extend(G.succ[node].keys() - forward_visited) - - return True - - -@not_implemented_for("undirected") -@nx._dispatchable -def find_minimal_d_separator(G, x, y, *, included=None, restricted=None): - """Returns a minimal d-separating set between `x` and `y` if possible - - A d-separating set in a DAG is a set of nodes that blocks all - paths between the two sets of nodes, `x` and `y`. This function - constructs a d-separating set that is "minimal", meaning no nodes can - be removed without it losing the d-separating property for `x` and `y`. - If no d-separating sets exist for `x` and `y`, this returns `None`. - - In a DAG there may be more than one minimal d-separator between two - sets of nodes. Minimal d-separators are not always unique. This function - returns one minimal d-separator, or `None` if no d-separator exists. - - Uses the algorithm presented in [1]_. The complexity of the algorithm - is :math:`O(m)`, where :math:`m` stands for the number of edges in - the subgraph of G consisting of only the ancestors of `x` and `y`. - For full details, see [1]_. - - Parameters - ---------- - G : graph - A networkx DAG. - x : set | node - A node or set of nodes in the graph. - y : set | node - A node or set of nodes in the graph. - included : set | node | None - A node or set of nodes which must be included in the found separating set, - default is None, which means the empty set. - restricted : set | node | None - Restricted node or set of nodes to consider. Only these nodes can be in - the found separating set, default is None meaning all nodes in ``G``. - - Returns - ------- - z : set | None - The minimal d-separating set, if at least one d-separating set exists, - otherwise None. - - Raises - ------ - NetworkXError - Raises a :exc:`NetworkXError` if the input graph is not a DAG - or if node sets `x`, `y`, and `included` are not disjoint. - - NodeNotFound - If any of the input nodes are not found in the graph, - a :exc:`NodeNotFound` exception is raised. - - References - ---------- - .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding - minimal d-separators in linear time and applications." In - Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020. - """ - if not nx.is_directed_acyclic_graph(G): - raise nx.NetworkXError("graph should be directed acyclic") - - try: - x = {x} if x in G else x - y = {y} if y in G else y - - if included is None: - included = set() - elif included in G: - included = {included} - - if restricted is None: - restricted = set(G) - elif restricted in G: - restricted = {restricted} - - set_y = x | y | included | restricted - if set_y - G.nodes: - raise nx.NodeNotFound(f"The node(s) {set_y - G.nodes} are not found in G") - except TypeError: - raise nx.NodeNotFound( - "One of x, y, included or restricted is not a node or set of nodes in G" - ) - - if not included <= restricted: - raise nx.NetworkXError( - f"Included nodes {included} must be in restricted nodes {restricted}" - ) - - intersection = x & y or x & included or y & included - if intersection: - raise nx.NetworkXError( - f"The sets x, y, included are not disjoint. Overlap: {intersection}" - ) - - nodeset = x | y | included - ancestors_x_y_included = nodeset.union(*[nx.ancestors(G, node) for node in nodeset]) - - z_init = restricted & (ancestors_x_y_included - (x | y)) - - x_closure = _reachable(G, x, ancestors_x_y_included, z_init) - if x_closure & y: - return None - - z_updated = z_init & (x_closure | included) - y_closure = _reachable(G, y, ancestors_x_y_included, z_updated) - return z_updated & (y_closure | included) - - -@not_implemented_for("undirected") -@nx._dispatchable -def is_minimal_d_separator(G, x, y, z, *, included=None, restricted=None): - """Determine if `z` is a minimal d-separator for `x` and `y`. - - A d-separator, `z`, in a DAG is a set of nodes that blocks - all paths from nodes in set `x` to nodes in set `y`. - A minimal d-separator is a d-separator `z` such that removing - any subset of nodes makes it no longer a d-separator. - - Note: This function checks whether `z` is a d-separator AND is - minimal. One can use the function `is_d_separator` to only check if - `z` is a d-separator. See examples below. - - Parameters - ---------- - G : nx.DiGraph - A NetworkX DAG. - x : node | set - A node or set of nodes in the graph. - y : node | set - A node or set of nodes in the graph. - z : node | set - The node or set of nodes to check if it is a minimal d-separating set. - The function :func:`is_d_separator` is called inside this function - to verify that `z` is in fact a d-separator. - included : set | node | None - A node or set of nodes which must be included in the found separating set, - default is ``None``, which means the empty set. - restricted : set | node | None - Restricted node or set of nodes to consider. Only these nodes can be in - the found separating set, default is ``None`` meaning all nodes in ``G``. - - Returns - ------- - bool - Whether or not the set `z` is a minimal d-separator subject to - `restricted` nodes and `included` node constraints. - - Examples - -------- - >>> G = nx.path_graph([0, 1, 2, 3], create_using=nx.DiGraph) - >>> G.add_node(4) - >>> nx.is_minimal_d_separator(G, 0, 2, {1}) - True - >>> # since {1} is the minimal d-separator, {1, 3, 4} is not minimal - >>> nx.is_minimal_d_separator(G, 0, 2, {1, 3, 4}) - False - >>> # alternatively, if we only want to check that {1, 3, 4} is a d-separator - >>> nx.is_d_separator(G, 0, 2, {1, 3, 4}) - True - - Raises - ------ - NetworkXError - Raises a :exc:`NetworkXError` if the input graph is not a DAG. - - NodeNotFound - If any of the input nodes are not found in the graph, - a :exc:`NodeNotFound` exception is raised. - - References - ---------- - .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding - minimal d-separators in linear time and applications." In - Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020. - - Notes - ----- - This function works on verifying that a set is minimal and - d-separating between two nodes. Uses criterion (a), (b), (c) on - page 4 of [1]_. a) closure(`x`) and `y` are disjoint. b) `z` contains - all nodes from `included` and is contained in the `restricted` - nodes and in the union of ancestors of `x`, `y`, and `included`. - c) the nodes in `z` not in `included` are contained in both - closure(x) and closure(y). The closure of a set is the set of nodes - connected to the set by a directed path in G. - - The complexity is :math:`O(m)`, where :math:`m` stands for the - number of edges in the subgraph of G consisting of only the - ancestors of `x` and `y`. - - For full details, see [1]_. - """ - if not nx.is_directed_acyclic_graph(G): - raise nx.NetworkXError("graph should be directed acyclic") - - try: - x = {x} if x in G else x - y = {y} if y in G else y - z = {z} if z in G else z - - if included is None: - included = set() - elif included in G: - included = {included} - - if restricted is None: - restricted = set(G) - elif restricted in G: - restricted = {restricted} - - set_y = x | y | included | restricted - if set_y - G.nodes: - raise nx.NodeNotFound(f"The node(s) {set_y - G.nodes} are not found in G") - except TypeError: - raise nx.NodeNotFound( - "One of x, y, z, included or restricted is not a node or set of nodes in G" - ) - - if not included <= z: - raise nx.NetworkXError( - f"Included nodes {included} must be in proposed separating set z {x}" - ) - if not z <= restricted: - raise nx.NetworkXError( - f"Separating set {z} must be contained in restricted set {restricted}" - ) - - intersection = x.intersection(y) or x.intersection(z) or y.intersection(z) - if intersection: - raise nx.NetworkXError( - f"The sets are not disjoint, with intersection {intersection}" - ) - - nodeset = x | y | included - ancestors_x_y_included = nodeset.union(*[nx.ancestors(G, n) for n in nodeset]) - - # criterion (a) -- check that z is actually a separator - x_closure = _reachable(G, x, ancestors_x_y_included, z) - if x_closure & y: - return False - - # criterion (b) -- basic constraint; included and restricted already checked above - if not (z <= ancestors_x_y_included): - return False - - # criterion (c) -- check that z is minimal - y_closure = _reachable(G, y, ancestors_x_y_included, z) - if not ((z - included) <= (x_closure & y_closure)): - return False - return True - - -@not_implemented_for("undirected") -def _reachable(G, x, a, z): - """Modified Bayes-Ball algorithm for finding d-connected nodes. - - Find all nodes in `a` that are d-connected to those in `x` by - those in `z`. This is an implementation of the function - `REACHABLE` in [1]_ (which is itself a modification of the - Bayes-Ball algorithm [2]_) when restricted to DAGs. - - Parameters - ---------- - G : nx.DiGraph - A NetworkX DAG. - x : node | set - A node in the DAG, or a set of nodes. - a : node | set - A (set of) node(s) in the DAG containing the ancestors of `x`. - z : node | set - The node or set of nodes conditioned on when checking d-connectedness. - - Returns - ------- - w : set - The closure of `x` in `a` with respect to d-connectedness - given `z`. - - References - ---------- - .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding - minimal d-separators in linear time and applications." In - Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020. - - .. [2] Shachter, Ross D. "Bayes-ball: The rational pastime - (for determining irrelevance and requisite information in - belief networks and influence diagrams)." In Proceedings of the - Fourteenth Conference on Uncertainty in Artificial Intelligence - (UAI), (pp. 480–487). 1998. - """ - - def _pass(e, v, f, n): - """Whether a ball entering node `v` along edge `e` passes to `n` along `f`. - - Boolean function defined on page 6 of [1]_. - - Parameters - ---------- - e : bool - Directed edge by which the ball got to node `v`; `True` iff directed into `v`. - v : node - Node where the ball is. - f : bool - Directed edge connecting nodes `v` and `n`; `True` iff directed `n`. - n : node - Checking whether the ball passes to this node. - - Returns - ------- - b : bool - Whether the ball passes or not. - - References - ---------- - .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding - minimal d-separators in linear time and applications." In - Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020. - """ - is_element_of_A = n in a - # almost_definite_status = True # always true for DAGs; not so for RCGs - collider_if_in_Z = v not in z or (e and not f) - return is_element_of_A and collider_if_in_Z # and almost_definite_status - - queue = deque([]) - for node in x: - if bool(G.pred[node]): - queue.append((True, node)) - if bool(G.succ[node]): - queue.append((False, node)) - processed = queue.copy() - - while any(queue): - e, v = queue.popleft() - preds = ((False, n) for n in G.pred[v]) - succs = ((True, n) for n in G.succ[v]) - f_n_pairs = chain(preds, succs) - for f, n in f_n_pairs: - if (f, n) not in processed and _pass(e, v, f, n): - queue.append((f, n)) - processed.append((f, n)) - - return {w for (_, w) in processed} - - -# Deprecated functions: -def d_separated(G, x, y, z): - """Return whether nodes sets ``x`` and ``y`` are d-separated by ``z``. - - .. deprecated:: 3.3 - - This function is deprecated and will be removed in NetworkX v3.5. - Please use `is_d_separator(G, x, y, z)`. - - """ - import warnings - - warnings.warn( - "d_separated is deprecated and will be removed in NetworkX v3.5." - "Please use `is_d_separator(G, x, y, z)`.", - category=DeprecationWarning, - stacklevel=2, - ) - return nx.is_d_separator(G, x, y, z) - - -def minimal_d_separator(G, u, v): - """Returns a minimal_d-separating set between `x` and `y` if possible - - .. deprecated:: 3.3 - - minimal_d_separator is deprecated and will be removed in NetworkX v3.5. - Please use `find_minimal_d_separator(G, x, y)`. - - """ - import warnings - - warnings.warn( - ( - "This function is deprecated and will be removed in NetworkX v3.5." - "Please use `is_d_separator(G, x, y)`." - ), - category=DeprecationWarning, - stacklevel=2, - ) - return nx.find_minimal_d_separator(G, u, v) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dag.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dag.py deleted file mode 100644 index c757afb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dag.py +++ /dev/null @@ -1,1418 +0,0 @@ -"""Algorithms for directed acyclic graphs (DAGs). - -Note that most of these functions are only guaranteed to work for DAGs. -In general, these functions do not check for acyclic-ness, so it is up -to the user to check for that. -""" - -import heapq -from collections import deque -from functools import partial -from itertools import chain, combinations, product, starmap -from math import gcd - -import networkx as nx -from networkx.utils import arbitrary_element, not_implemented_for, pairwise - -__all__ = [ - "descendants", - "ancestors", - "topological_sort", - "lexicographical_topological_sort", - "all_topological_sorts", - "topological_generations", - "is_directed_acyclic_graph", - "is_aperiodic", - "transitive_closure", - "transitive_closure_dag", - "transitive_reduction", - "antichains", - "dag_longest_path", - "dag_longest_path_length", - "dag_to_branching", - "compute_v_structures", -] - -chaini = chain.from_iterable - - -@nx._dispatchable -def descendants(G, source): - """Returns all nodes reachable from `source` in `G`. - - Parameters - ---------- - G : NetworkX Graph - source : node in `G` - - Returns - ------- - set() - The descendants of `source` in `G` - - Raises - ------ - NetworkXError - If node `source` is not in `G`. - - Examples - -------- - >>> DG = nx.path_graph(5, create_using=nx.DiGraph) - >>> sorted(nx.descendants(DG, 2)) - [3, 4] - - The `source` node is not a descendant of itself, but can be included manually: - - >>> sorted(nx.descendants(DG, 2) | {2}) - [2, 3, 4] - - See also - -------- - ancestors - """ - return {child for parent, child in nx.bfs_edges(G, source)} - - -@nx._dispatchable -def ancestors(G, source): - """Returns all nodes having a path to `source` in `G`. - - Parameters - ---------- - G : NetworkX Graph - source : node in `G` - - Returns - ------- - set() - The ancestors of `source` in `G` - - Raises - ------ - NetworkXError - If node `source` is not in `G`. - - Examples - -------- - >>> DG = nx.path_graph(5, create_using=nx.DiGraph) - >>> sorted(nx.ancestors(DG, 2)) - [0, 1] - - The `source` node is not an ancestor of itself, but can be included manually: - - >>> sorted(nx.ancestors(DG, 2) | {2}) - [0, 1, 2] - - See also - -------- - descendants - """ - return {child for parent, child in nx.bfs_edges(G, source, reverse=True)} - - -@nx._dispatchable -def has_cycle(G): - """Decides whether the directed graph has a cycle.""" - try: - # Feed the entire iterator into a zero-length deque. - deque(topological_sort(G), maxlen=0) - except nx.NetworkXUnfeasible: - return True - else: - return False - - -@nx._dispatchable -def is_directed_acyclic_graph(G): - """Returns True if the graph `G` is a directed acyclic graph (DAG) or - False if not. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - bool - True if `G` is a DAG, False otherwise - - Examples - -------- - Undirected graph:: - - >>> G = nx.Graph([(1, 2), (2, 3)]) - >>> nx.is_directed_acyclic_graph(G) - False - - Directed graph with cycle:: - - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - >>> nx.is_directed_acyclic_graph(G) - False - - Directed acyclic graph:: - - >>> G = nx.DiGraph([(1, 2), (2, 3)]) - >>> nx.is_directed_acyclic_graph(G) - True - - See also - -------- - topological_sort - """ - return G.is_directed() and not has_cycle(G) - - -@nx._dispatchable -def topological_generations(G): - """Stratifies a DAG into generations. - - A topological generation is node collection in which ancestors of a node in each - generation are guaranteed to be in a previous generation, and any descendants of - a node are guaranteed to be in a following generation. Nodes are guaranteed to - be in the earliest possible generation that they can belong to. - - Parameters - ---------- - G : NetworkX digraph - A directed acyclic graph (DAG) - - Yields - ------ - sets of nodes - Yields sets of nodes representing each generation. - - Raises - ------ - NetworkXError - Generations are defined for directed graphs only. If the graph - `G` is undirected, a :exc:`NetworkXError` is raised. - - NetworkXUnfeasible - If `G` is not a directed acyclic graph (DAG) no topological generations - exist and a :exc:`NetworkXUnfeasible` exception is raised. This can also - be raised if `G` is changed while the returned iterator is being processed - - RuntimeError - If `G` is changed while the returned iterator is being processed. - - Examples - -------- - >>> DG = nx.DiGraph([(2, 1), (3, 1)]) - >>> [sorted(generation) for generation in nx.topological_generations(DG)] - [[2, 3], [1]] - - Notes - ----- - The generation in which a node resides can also be determined by taking the - max-path-distance from the node to the farthest leaf node. That value can - be obtained with this function using `enumerate(topological_generations(G))`. - - See also - -------- - topological_sort - """ - if not G.is_directed(): - raise nx.NetworkXError("Topological sort not defined on undirected graphs.") - - multigraph = G.is_multigraph() - indegree_map = {v: d for v, d in G.in_degree() if d > 0} - zero_indegree = [v for v, d in G.in_degree() if d == 0] - - while zero_indegree: - this_generation = zero_indegree - zero_indegree = [] - for node in this_generation: - if node not in G: - raise RuntimeError("Graph changed during iteration") - for child in G.neighbors(node): - try: - indegree_map[child] -= len(G[node][child]) if multigraph else 1 - except KeyError as err: - raise RuntimeError("Graph changed during iteration") from err - if indegree_map[child] == 0: - zero_indegree.append(child) - del indegree_map[child] - yield this_generation - - if indegree_map: - raise nx.NetworkXUnfeasible( - "Graph contains a cycle or graph changed during iteration" - ) - - -@nx._dispatchable -def topological_sort(G): - """Returns a generator of nodes in topologically sorted order. - - A topological sort is a nonunique permutation of the nodes of a - directed graph such that an edge from u to v implies that u - appears before v in the topological sort order. This ordering is - valid only if the graph has no directed cycles. - - Parameters - ---------- - G : NetworkX digraph - A directed acyclic graph (DAG) - - Yields - ------ - nodes - Yields the nodes in topological sorted order. - - Raises - ------ - NetworkXError - Topological sort is defined for directed graphs only. If the graph `G` - is undirected, a :exc:`NetworkXError` is raised. - - NetworkXUnfeasible - If `G` is not a directed acyclic graph (DAG) no topological sort exists - and a :exc:`NetworkXUnfeasible` exception is raised. This can also be - raised if `G` is changed while the returned iterator is being processed - - RuntimeError - If `G` is changed while the returned iterator is being processed. - - Examples - -------- - To get the reverse order of the topological sort: - - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> list(reversed(list(nx.topological_sort(DG)))) - [3, 2, 1] - - If your DiGraph naturally has the edges representing tasks/inputs - and nodes representing people/processes that initiate tasks, then - topological_sort is not quite what you need. You will have to change - the tasks to nodes with dependence reflected by edges. The result is - a kind of topological sort of the edges. This can be done - with :func:`networkx.line_graph` as follows: - - >>> list(nx.topological_sort(nx.line_graph(DG))) - [(1, 2), (2, 3)] - - Notes - ----- - This algorithm is based on a description and proof in - "Introduction to Algorithms: A Creative Approach" [1]_ . - - See also - -------- - is_directed_acyclic_graph, lexicographical_topological_sort - - References - ---------- - .. [1] Manber, U. (1989). - *Introduction to Algorithms - A Creative Approach.* Addison-Wesley. - """ - for generation in nx.topological_generations(G): - yield from generation - - -@nx._dispatchable -def lexicographical_topological_sort(G, key=None): - """Generate the nodes in the unique lexicographical topological sort order. - - Generates a unique ordering of nodes by first sorting topologically (for which there are often - multiple valid orderings) and then additionally by sorting lexicographically. - - A topological sort arranges the nodes of a directed graph so that the - upstream node of each directed edge precedes the downstream node. - It is always possible to find a solution for directed graphs that have no cycles. - There may be more than one valid solution. - - Lexicographical sorting is just sorting alphabetically. It is used here to break ties in the - topological sort and to determine a single, unique ordering. This can be useful in comparing - sort results. - - The lexicographical order can be customized by providing a function to the `key=` parameter. - The definition of the key function is the same as used in python's built-in `sort()`. - The function takes a single argument and returns a key to use for sorting purposes. - - Lexicographical sorting can fail if the node names are un-sortable. See the example below. - The solution is to provide a function to the `key=` argument that returns sortable keys. - - - Parameters - ---------- - G : NetworkX digraph - A directed acyclic graph (DAG) - - key : function, optional - A function of one argument that converts a node name to a comparison key. - It defines and resolves ambiguities in the sort order. Defaults to the identity function. - - Yields - ------ - nodes - Yields the nodes of G in lexicographical topological sort order. - - Raises - ------ - NetworkXError - Topological sort is defined for directed graphs only. If the graph `G` - is undirected, a :exc:`NetworkXError` is raised. - - NetworkXUnfeasible - If `G` is not a directed acyclic graph (DAG) no topological sort exists - and a :exc:`NetworkXUnfeasible` exception is raised. This can also be - raised if `G` is changed while the returned iterator is being processed - - RuntimeError - If `G` is changed while the returned iterator is being processed. - - TypeError - Results from un-sortable node names. - Consider using `key=` parameter to resolve ambiguities in the sort order. - - Examples - -------- - >>> DG = nx.DiGraph([(2, 1), (2, 5), (1, 3), (1, 4), (5, 4)]) - >>> list(nx.lexicographical_topological_sort(DG)) - [2, 1, 3, 5, 4] - >>> list(nx.lexicographical_topological_sort(DG, key=lambda x: -x)) - [2, 5, 1, 4, 3] - - The sort will fail for any graph with integer and string nodes. Comparison of integer to strings - is not defined in python. Is 3 greater or less than 'red'? - - >>> DG = nx.DiGraph([(1, "red"), (3, "red"), (1, "green"), (2, "blue")]) - >>> list(nx.lexicographical_topological_sort(DG)) - Traceback (most recent call last): - ... - TypeError: '<' not supported between instances of 'str' and 'int' - ... - - Incomparable nodes can be resolved using a `key` function. This example function - allows comparison of integers and strings by returning a tuple where the first - element is True for `str`, False otherwise. The second element is the node name. - This groups the strings and integers separately so they can be compared only among themselves. - - >>> key = lambda node: (isinstance(node, str), node) - >>> list(nx.lexicographical_topological_sort(DG, key=key)) - [1, 2, 3, 'blue', 'green', 'red'] - - Notes - ----- - This algorithm is based on a description and proof in - "Introduction to Algorithms: A Creative Approach" [1]_ . - - See also - -------- - topological_sort - - References - ---------- - .. [1] Manber, U. (1989). - *Introduction to Algorithms - A Creative Approach.* Addison-Wesley. - """ - if not G.is_directed(): - msg = "Topological sort not defined on undirected graphs." - raise nx.NetworkXError(msg) - - if key is None: - - def key(node): - return node - - nodeid_map = {n: i for i, n in enumerate(G)} - - def create_tuple(node): - return key(node), nodeid_map[node], node - - indegree_map = {v: d for v, d in G.in_degree() if d > 0} - # These nodes have zero indegree and ready to be returned. - zero_indegree = [create_tuple(v) for v, d in G.in_degree() if d == 0] - heapq.heapify(zero_indegree) - - while zero_indegree: - _, _, node = heapq.heappop(zero_indegree) - - if node not in G: - raise RuntimeError("Graph changed during iteration") - for _, child in G.edges(node): - try: - indegree_map[child] -= 1 - except KeyError as err: - raise RuntimeError("Graph changed during iteration") from err - if indegree_map[child] == 0: - try: - heapq.heappush(zero_indegree, create_tuple(child)) - except TypeError as err: - raise TypeError( - f"{err}\nConsider using `key=` parameter to resolve ambiguities in the sort order." - ) - del indegree_map[child] - - yield node - - if indegree_map: - msg = "Graph contains a cycle or graph changed during iteration" - raise nx.NetworkXUnfeasible(msg) - - -@not_implemented_for("undirected") -@nx._dispatchable -def all_topological_sorts(G): - """Returns a generator of _all_ topological sorts of the directed graph G. - - A topological sort is a nonunique permutation of the nodes such that an - edge from u to v implies that u appears before v in the topological sort - order. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Yields - ------ - topological_sort_order : list - a list of nodes in `G`, representing one of the topological sort orders - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - NetworkXUnfeasible - If `G` is not acyclic - - Examples - -------- - To enumerate all topological sorts of directed graph: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - >>> list(nx.all_topological_sorts(DG)) - [[1, 2, 4, 3], [1, 2, 3, 4]] - - Notes - ----- - Implements an iterative version of the algorithm given in [1]. - - References - ---------- - .. [1] Knuth, Donald E., Szwarcfiter, Jayme L. (1974). - "A Structured Program to Generate All Topological Sorting Arrangements" - Information Processing Letters, Volume 2, Issue 6, 1974, Pages 153-157, - ISSN 0020-0190, - https://doi.org/10.1016/0020-0190(74)90001-5. - Elsevier (North-Holland), Amsterdam - """ - if not G.is_directed(): - raise nx.NetworkXError("Topological sort not defined on undirected graphs.") - - # the names of count and D are chosen to match the global variables in [1] - # number of edges originating in a vertex v - count = dict(G.in_degree()) - # vertices with indegree 0 - D = deque([v for v, d in G.in_degree() if d == 0]) - # stack of first value chosen at a position k in the topological sort - bases = [] - current_sort = [] - - # do-while construct - while True: - assert all(count[v] == 0 for v in D) - - if len(current_sort) == len(G): - yield list(current_sort) - - # clean-up stack - while len(current_sort) > 0: - assert len(bases) == len(current_sort) - q = current_sort.pop() - - # "restores" all edges (q, x) - # NOTE: it is important to iterate over edges instead - # of successors, so count is updated correctly in multigraphs - for _, j in G.out_edges(q): - count[j] += 1 - assert count[j] >= 0 - # remove entries from D - while len(D) > 0 and count[D[-1]] > 0: - D.pop() - - # corresponds to a circular shift of the values in D - # if the first value chosen (the base) is in the first - # position of D again, we are done and need to consider the - # previous condition - D.appendleft(q) - if D[-1] == bases[-1]: - # all possible values have been chosen at current position - # remove corresponding marker - bases.pop() - else: - # there are still elements that have not been fixed - # at the current position in the topological sort - # stop removing elements, escape inner loop - break - - else: - if len(D) == 0: - raise nx.NetworkXUnfeasible("Graph contains a cycle.") - - # choose next node - q = D.pop() - # "erase" all edges (q, x) - # NOTE: it is important to iterate over edges instead - # of successors, so count is updated correctly in multigraphs - for _, j in G.out_edges(q): - count[j] -= 1 - assert count[j] >= 0 - if count[j] == 0: - D.append(j) - current_sort.append(q) - - # base for current position might _not_ be fixed yet - if len(bases) < len(current_sort): - bases.append(q) - - if len(bases) == 0: - break - - -@nx._dispatchable -def is_aperiodic(G): - """Returns True if `G` is aperiodic. - - A directed graph is aperiodic if there is no integer k > 1 that - divides the length of every cycle in the graph. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - bool - True if the graph is aperiodic False otherwise - - Raises - ------ - NetworkXError - If `G` is not directed - - Examples - -------- - A graph consisting of one cycle, the length of which is 2. Therefore ``k = 2`` - divides the length of every cycle in the graph and thus the graph - is *not aperiodic*:: - - >>> DG = nx.DiGraph([(1, 2), (2, 1)]) - >>> nx.is_aperiodic(DG) - False - - A graph consisting of two cycles: one of length 2 and the other of length 3. - The cycle lengths are coprime, so there is no single value of k where ``k > 1`` - that divides each cycle length and therefore the graph is *aperiodic*:: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (3, 1), (1, 4), (4, 1)]) - >>> nx.is_aperiodic(DG) - True - - A graph consisting of two cycles: one of length 2 and the other of length 4. - The lengths of the cycles share a common factor ``k = 2``, and therefore - the graph is *not aperiodic*:: - - >>> DG = nx.DiGraph([(1, 2), (2, 1), (3, 4), (4, 5), (5, 6), (6, 3)]) - >>> nx.is_aperiodic(DG) - False - - An acyclic graph, therefore the graph is *not aperiodic*:: - - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> nx.is_aperiodic(DG) - False - - Notes - ----- - This uses the method outlined in [1]_, which runs in $O(m)$ time - given $m$ edges in `G`. Note that a graph is not aperiodic if it is - acyclic as every integer trivial divides length 0 cycles. - - References - ---------- - .. [1] Jarvis, J. P.; Shier, D. R. (1996), - "Graph-theoretic analysis of finite Markov chains," - in Shier, D. R.; Wallenius, K. T., Applied Mathematical Modeling: - A Multidisciplinary Approach, CRC Press. - """ - if not G.is_directed(): - raise nx.NetworkXError("is_aperiodic not defined for undirected graphs") - if len(G) == 0: - raise nx.NetworkXPointlessConcept("Graph has no nodes.") - s = arbitrary_element(G) - levels = {s: 0} - this_level = [s] - g = 0 - lev = 1 - while this_level: - next_level = [] - for u in this_level: - for v in G[u]: - if v in levels: # Non-Tree Edge - g = gcd(g, levels[u] - levels[v] + 1) - else: # Tree Edge - next_level.append(v) - levels[v] = lev - this_level = next_level - lev += 1 - if len(levels) == len(G): # All nodes in tree - return g == 1 - else: - return g == 1 and nx.is_aperiodic(G.subgraph(set(G) - set(levels))) - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def transitive_closure(G, reflexive=False): - """Returns transitive closure of a graph - - The transitive closure of G = (V,E) is a graph G+ = (V,E+) such that - for all v, w in V there is an edge (v, w) in E+ if and only if there - is a path from v to w in G. - - Handling of paths from v to v has some flexibility within this definition. - A reflexive transitive closure creates a self-loop for the path - from v to v of length 0. The usual transitive closure creates a - self-loop only if a cycle exists (a path from v to v with length > 0). - We also allow an option for no self-loops. - - Parameters - ---------- - G : NetworkX Graph - A directed/undirected graph/multigraph. - reflexive : Bool or None, optional (default: False) - Determines when cycles create self-loops in the Transitive Closure. - If True, trivial cycles (length 0) create self-loops. The result - is a reflexive transitive closure of G. - If False (the default) non-trivial cycles create self-loops. - If None, self-loops are not created. - - Returns - ------- - NetworkX graph - The transitive closure of `G` - - Raises - ------ - NetworkXError - If `reflexive` not in `{None, True, False}` - - Examples - -------- - The treatment of trivial (i.e. length 0) cycles is controlled by the - `reflexive` parameter. - - Trivial (i.e. length 0) cycles do not create self-loops when - ``reflexive=False`` (the default):: - - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> TC = nx.transitive_closure(DG, reflexive=False) - >>> TC.edges() - OutEdgeView([(1, 2), (1, 3), (2, 3)]) - - However, nontrivial (i.e. length greater than 0) cycles create self-loops - when ``reflexive=False`` (the default):: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - >>> TC = nx.transitive_closure(DG, reflexive=False) - >>> TC.edges() - OutEdgeView([(1, 2), (1, 3), (1, 1), (2, 3), (2, 1), (2, 2), (3, 1), (3, 2), (3, 3)]) - - Trivial cycles (length 0) create self-loops when ``reflexive=True``:: - - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> TC = nx.transitive_closure(DG, reflexive=True) - >>> TC.edges() - OutEdgeView([(1, 2), (1, 1), (1, 3), (2, 3), (2, 2), (3, 3)]) - - And the third option is not to create self-loops at all when ``reflexive=None``:: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - >>> TC = nx.transitive_closure(DG, reflexive=None) - >>> TC.edges() - OutEdgeView([(1, 2), (1, 3), (2, 3), (2, 1), (3, 1), (3, 2)]) - - References - ---------- - .. [1] https://www.ics.uci.edu/~eppstein/PADS/PartialOrder.py - """ - TC = G.copy() - - if reflexive not in {None, True, False}: - raise nx.NetworkXError("Incorrect value for the parameter `reflexive`") - - for v in G: - if reflexive is None: - TC.add_edges_from((v, u) for u in nx.descendants(G, v) if u not in TC[v]) - elif reflexive is True: - TC.add_edges_from( - (v, u) for u in nx.descendants(G, v) | {v} if u not in TC[v] - ) - elif reflexive is False: - TC.add_edges_from((v, e[1]) for e in nx.edge_bfs(G, v) if e[1] not in TC[v]) - - return TC - - -@not_implemented_for("undirected") -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def transitive_closure_dag(G, topo_order=None): - """Returns the transitive closure of a directed acyclic graph. - - This function is faster than the function `transitive_closure`, but fails - if the graph has a cycle. - - The transitive closure of G = (V,E) is a graph G+ = (V,E+) such that - for all v, w in V there is an edge (v, w) in E+ if and only if there - is a non-null path from v to w in G. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Returns - ------- - NetworkX DiGraph - The transitive closure of `G` - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - NetworkXUnfeasible - If `G` has a cycle - - Examples - -------- - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> TC = nx.transitive_closure_dag(DG) - >>> TC.edges() - OutEdgeView([(1, 2), (1, 3), (2, 3)]) - - Notes - ----- - This algorithm is probably simple enough to be well-known but I didn't find - a mention in the literature. - """ - if topo_order is None: - topo_order = list(topological_sort(G)) - - TC = G.copy() - - # idea: traverse vertices following a reverse topological order, connecting - # each vertex to its descendants at distance 2 as we go - for v in reversed(topo_order): - TC.add_edges_from((v, u) for u in nx.descendants_at_distance(TC, v, 2)) - - return TC - - -@not_implemented_for("undirected") -@nx._dispatchable(returns_graph=True) -def transitive_reduction(G): - """Returns transitive reduction of a directed graph - - The transitive reduction of G = (V,E) is a graph G- = (V,E-) such that - for all v,w in V there is an edge (v,w) in E- if and only if (v,w) is - in E and there is no path from v to w in G with length greater than 1. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - Returns - ------- - NetworkX DiGraph - The transitive reduction of `G` - - Raises - ------ - NetworkXError - If `G` is not a directed acyclic graph (DAG) transitive reduction is - not uniquely defined and a :exc:`NetworkXError` exception is raised. - - Examples - -------- - To perform transitive reduction on a DiGraph: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (1, 3)]) - >>> TR = nx.transitive_reduction(DG) - >>> list(TR.edges) - [(1, 2), (2, 3)] - - To avoid unnecessary data copies, this implementation does not return a - DiGraph with node/edge data. - To perform transitive reduction on a DiGraph and transfer node/edge data: - - >>> DG = nx.DiGraph() - >>> DG.add_edges_from([(1, 2), (2, 3), (1, 3)], color="red") - >>> TR = nx.transitive_reduction(DG) - >>> TR.add_nodes_from(DG.nodes(data=True)) - >>> TR.add_edges_from((u, v, DG.edges[u, v]) for u, v in TR.edges) - >>> list(TR.edges(data=True)) - [(1, 2, {'color': 'red'}), (2, 3, {'color': 'red'})] - - References - ---------- - https://en.wikipedia.org/wiki/Transitive_reduction - - """ - if not is_directed_acyclic_graph(G): - msg = "Directed Acyclic Graph required for transitive_reduction" - raise nx.NetworkXError(msg) - TR = nx.DiGraph() - TR.add_nodes_from(G.nodes()) - descendants = {} - # count before removing set stored in descendants - check_count = dict(G.in_degree) - for u in G: - u_nbrs = set(G[u]) - for v in G[u]: - if v in u_nbrs: - if v not in descendants: - descendants[v] = {y for x, y in nx.dfs_edges(G, v)} - u_nbrs -= descendants[v] - check_count[v] -= 1 - if check_count[v] == 0: - del descendants[v] - TR.add_edges_from((u, v) for v in u_nbrs) - return TR - - -@not_implemented_for("undirected") -@nx._dispatchable -def antichains(G, topo_order=None): - """Generates antichains from a directed acyclic graph (DAG). - - An antichain is a subset of a partially ordered set such that any - two elements in the subset are incomparable. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Yields - ------ - antichain : list - a list of nodes in `G` representing an antichain - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - NetworkXUnfeasible - If `G` contains a cycle - - Examples - -------- - >>> DG = nx.DiGraph([(1, 2), (1, 3)]) - >>> list(nx.antichains(DG)) - [[], [3], [2], [2, 3], [1]] - - Notes - ----- - This function was originally developed by Peter Jipsen and Franco Saliola - for the SAGE project. It's included in NetworkX with permission from the - authors. Original SAGE code at: - - https://github.com/sagemath/sage/blob/master/src/sage/combinat/posets/hasse_diagram.py - - References - ---------- - .. [1] Free Lattices, by R. Freese, J. Jezek and J. B. Nation, - AMS, Vol 42, 1995, p. 226. - """ - if topo_order is None: - topo_order = list(nx.topological_sort(G)) - - TC = nx.transitive_closure_dag(G, topo_order) - antichains_stacks = [([], list(reversed(topo_order)))] - - while antichains_stacks: - (antichain, stack) = antichains_stacks.pop() - # Invariant: - # - the elements of antichain are independent - # - the elements of stack are independent from those of antichain - yield antichain - while stack: - x = stack.pop() - new_antichain = antichain + [x] - new_stack = [t for t in stack if not ((t in TC[x]) or (x in TC[t]))] - antichains_stacks.append((new_antichain, new_stack)) - - -@not_implemented_for("undirected") -@nx._dispatchable(edge_attrs={"weight": "default_weight"}) -def dag_longest_path(G, weight="weight", default_weight=1, topo_order=None): - """Returns the longest path in a directed acyclic graph (DAG). - - If `G` has edges with `weight` attribute the edge data are used as - weight values. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - weight : str, optional - Edge data key to use for weight - - default_weight : int, optional - The weight of edges that do not have a weight attribute - - topo_order: list or tuple, optional - A topological order for `G` (if None, the function will compute one) - - Returns - ------- - list - Longest path - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - Examples - -------- - >>> DG = nx.DiGraph( - ... [(0, 1, {"cost": 1}), (1, 2, {"cost": 1}), (0, 2, {"cost": 42})] - ... ) - >>> list(nx.all_simple_paths(DG, 0, 2)) - [[0, 1, 2], [0, 2]] - >>> nx.dag_longest_path(DG) - [0, 1, 2] - >>> nx.dag_longest_path(DG, weight="cost") - [0, 2] - - In the case where multiple valid topological orderings exist, `topo_order` - can be used to specify a specific ordering: - - >>> DG = nx.DiGraph([(0, 1), (0, 2)]) - >>> sorted(nx.all_topological_sorts(DG)) # Valid topological orderings - [[0, 1, 2], [0, 2, 1]] - >>> nx.dag_longest_path(DG, topo_order=[0, 1, 2]) - [0, 1] - >>> nx.dag_longest_path(DG, topo_order=[0, 2, 1]) - [0, 2] - - See also - -------- - dag_longest_path_length - - """ - if not G: - return [] - - if topo_order is None: - topo_order = nx.topological_sort(G) - - dist = {} # stores {v : (length, u)} - for v in topo_order: - us = [ - ( - dist[u][0] - + ( - max(data.values(), key=lambda x: x.get(weight, default_weight)) - if G.is_multigraph() - else data - ).get(weight, default_weight), - u, - ) - for u, data in G.pred[v].items() - ] - - # Use the best predecessor if there is one and its distance is - # non-negative, otherwise terminate. - maxu = max(us, key=lambda x: x[0]) if us else (0, v) - dist[v] = maxu if maxu[0] >= 0 else (0, v) - - u = None - v = max(dist, key=lambda x: dist[x][0]) - path = [] - while u != v: - path.append(v) - u = v - v = dist[v][1] - - path.reverse() - return path - - -@not_implemented_for("undirected") -@nx._dispatchable(edge_attrs={"weight": "default_weight"}) -def dag_longest_path_length(G, weight="weight", default_weight=1): - """Returns the longest path length in a DAG - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - weight : string, optional - Edge data key to use for weight - - default_weight : int, optional - The weight of edges that do not have a weight attribute - - Returns - ------- - int - Longest path length - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - Examples - -------- - >>> DG = nx.DiGraph( - ... [(0, 1, {"cost": 1}), (1, 2, {"cost": 1}), (0, 2, {"cost": 42})] - ... ) - >>> list(nx.all_simple_paths(DG, 0, 2)) - [[0, 1, 2], [0, 2]] - >>> nx.dag_longest_path_length(DG) - 2 - >>> nx.dag_longest_path_length(DG, weight="cost") - 42 - - See also - -------- - dag_longest_path - """ - path = nx.dag_longest_path(G, weight, default_weight) - path_length = 0 - if G.is_multigraph(): - for u, v in pairwise(path): - i = max(G[u][v], key=lambda x: G[u][v][x].get(weight, default_weight)) - path_length += G[u][v][i].get(weight, default_weight) - else: - for u, v in pairwise(path): - path_length += G[u][v].get(weight, default_weight) - - return path_length - - -@nx._dispatchable -def root_to_leaf_paths(G): - """Yields root-to-leaf paths in a directed acyclic graph. - - `G` must be a directed acyclic graph. If not, the behavior of this - function is undefined. A "root" in this graph is a node of in-degree - zero and a "leaf" a node of out-degree zero. - - When invoked, this function iterates over each path from any root to - any leaf. A path is a list of nodes. - - """ - roots = (v for v, d in G.in_degree() if d == 0) - leaves = (v for v, d in G.out_degree() if d == 0) - all_paths = partial(nx.all_simple_paths, G) - # TODO In Python 3, this would be better as `yield from ...`. - return chaini(starmap(all_paths, product(roots, leaves))) - - -@not_implemented_for("multigraph") -@not_implemented_for("undirected") -@nx._dispatchable(returns_graph=True) -def dag_to_branching(G): - """Returns a branching representing all (overlapping) paths from - root nodes to leaf nodes in the given directed acyclic graph. - - As described in :mod:`networkx.algorithms.tree.recognition`, a - *branching* is a directed forest in which each node has at most one - parent. In other words, a branching is a disjoint union of - *arborescences*. For this function, each node of in-degree zero in - `G` becomes a root of one of the arborescences, and there will be - one leaf node for each distinct path from that root to a leaf node - in `G`. - - Each node `v` in `G` with *k* parents becomes *k* distinct nodes in - the returned branching, one for each parent, and the sub-DAG rooted - at `v` is duplicated for each copy. The algorithm then recurses on - the children of each copy of `v`. - - Parameters - ---------- - G : NetworkX graph - A directed acyclic graph. - - Returns - ------- - DiGraph - The branching in which there is a bijection between root-to-leaf - paths in `G` (in which multiple paths may share the same leaf) - and root-to-leaf paths in the branching (in which there is a - unique path from a root to a leaf). - - Each node has an attribute 'source' whose value is the original - node to which this node corresponds. No other graph, node, or - edge attributes are copied into this new graph. - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed, or if `G` is a multigraph. - - HasACycle - If `G` is not acyclic. - - Examples - -------- - To examine which nodes in the returned branching were produced by - which original node in the directed acyclic graph, we can collect - the mapping from source node to new nodes into a dictionary. For - example, consider the directed diamond graph:: - - >>> from collections import defaultdict - >>> from operator import itemgetter - >>> - >>> G = nx.DiGraph(nx.utils.pairwise("abd")) - >>> G.add_edges_from(nx.utils.pairwise("acd")) - >>> B = nx.dag_to_branching(G) - >>> - >>> sources = defaultdict(set) - >>> for v, source in B.nodes(data="source"): - ... sources[source].add(v) - >>> len(sources["a"]) - 1 - >>> len(sources["d"]) - 2 - - To copy node attributes from the original graph to the new graph, - you can use a dictionary like the one constructed in the above - example:: - - >>> for source, nodes in sources.items(): - ... for v in nodes: - ... B.nodes[v].update(G.nodes[source]) - - Notes - ----- - This function is not idempotent in the sense that the node labels in - the returned branching may be uniquely generated each time the - function is invoked. In fact, the node labels may not be integers; - in order to relabel the nodes to be more readable, you can use the - :func:`networkx.convert_node_labels_to_integers` function. - - The current implementation of this function uses - :func:`networkx.prefix_tree`, so it is subject to the limitations of - that function. - - """ - if has_cycle(G): - msg = "dag_to_branching is only defined for acyclic graphs" - raise nx.HasACycle(msg) - paths = root_to_leaf_paths(G) - B = nx.prefix_tree(paths) - # Remove the synthetic `root`(0) and `NIL`(-1) nodes from the tree - B.remove_node(0) - B.remove_node(-1) - return B - - -@not_implemented_for("undirected") -@nx._dispatchable -def compute_v_structures(G): - """Yields 3-node tuples that represent the v-structures in `G`. - - .. deprecated:: 3.4 - - `compute_v_structures` actually yields colliders. It will be removed in - version 3.6. Use `nx.dag.v_structures` or `nx.dag.colliders` instead. - - Colliders are triples in the directed acyclic graph (DAG) where two parent nodes - point to the same child node. V-structures are colliders where the two parent - nodes are not adjacent. In a causal graph setting, the parents do not directly - depend on each other, but conditioning on the child node provides an association. - - Parameters - ---------- - G : graph - A networkx `~networkx.DiGraph`. - - Yields - ------ - A 3-tuple representation of a v-structure - Each v-structure is a 3-tuple with the parent, collider, and other parent. - - Raises - ------ - NetworkXNotImplemented - If `G` is an undirected graph. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (0, 4), (3, 1), (2, 4), (0, 5), (4, 5), (1, 5)]) - >>> nx.is_directed_acyclic_graph(G) - True - >>> list(nx.compute_v_structures(G)) - [(0, 4, 2), (0, 5, 4), (0, 5, 1), (4, 5, 1)] - - See Also - -------- - v_structures - colliders - - Notes - ----- - This function was written to be used on DAGs, however it works on cyclic graphs - too. Since colliders are referred to in the cyclic causal graph literature - [2]_ we allow cyclic graphs in this function. It is suggested that you test if - your input graph is acyclic as in the example if you want that property. - - References - ---------- - .. [1] `Pearl's PRIMER `_ - Ch-2 page 50: v-structures def. - .. [2] A Hyttinen, P.O. Hoyer, F. Eberhardt, M J ̈arvisalo, (2013) - "Discovering cyclic causal models with latent variables: - a general SAT-based procedure", UAI'13: Proceedings of the Twenty-Ninth - Conference on Uncertainty in Artificial Intelligence, pg 301–310, - `doi:10.5555/3023638.3023669 `_ - """ - import warnings - - warnings.warn( - ( - "\n\n`compute_v_structures` actually yields colliders. It will be\n" - "removed in version 3.6. Use `nx.dag.v_structures` or `nx.dag.colliders`\n" - "instead.\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - - return colliders(G) - - -@not_implemented_for("undirected") -@nx._dispatchable -def v_structures(G): - """Yields 3-node tuples that represent the v-structures in `G`. - - Colliders are triples in the directed acyclic graph (DAG) where two parent nodes - point to the same child node. V-structures are colliders where the two parent - nodes are not adjacent. In a causal graph setting, the parents do not directly - depend on each other, but conditioning on the child node provides an association. - - Parameters - ---------- - G : graph - A networkx `~networkx.DiGraph`. - - Yields - ------ - A 3-tuple representation of a v-structure - Each v-structure is a 3-tuple with the parent, collider, and other parent. - - Raises - ------ - NetworkXNotImplemented - If `G` is an undirected graph. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (0, 4), (3, 1), (2, 4), (0, 5), (4, 5), (1, 5)]) - >>> nx.is_directed_acyclic_graph(G) - True - >>> list(nx.dag.v_structures(G)) - [(0, 4, 2), (0, 5, 1), (4, 5, 1)] - - See Also - -------- - colliders - - Notes - ----- - This function was written to be used on DAGs, however it works on cyclic graphs - too. Since colliders are referred to in the cyclic causal graph literature - [2]_ we allow cyclic graphs in this function. It is suggested that you test if - your input graph is acyclic as in the example if you want that property. - - References - ---------- - .. [1] `Pearl's PRIMER `_ - Ch-2 page 50: v-structures def. - .. [2] A Hyttinen, P.O. Hoyer, F. Eberhardt, M J ̈arvisalo, (2013) - "Discovering cyclic causal models with latent variables: - a general SAT-based procedure", UAI'13: Proceedings of the Twenty-Ninth - Conference on Uncertainty in Artificial Intelligence, pg 301–310, - `doi:10.5555/3023638.3023669 `_ - """ - for p1, c, p2 in colliders(G): - if not (G.has_edge(p1, p2) or G.has_edge(p2, p1)): - yield (p1, c, p2) - - -@not_implemented_for("undirected") -@nx._dispatchable -def colliders(G): - """Yields 3-node tuples that represent the colliders in `G`. - - In a Directed Acyclic Graph (DAG), if you have three nodes A, B, and C, and - there are edges from A to C and from B to C, then C is a collider [1]_ . In - a causal graph setting, this means that both events A and B are "causing" C, - and conditioning on C provide an association between A and B even if - no direct causal relationship exists between A and B. - - Parameters - ---------- - G : graph - A networkx `~networkx.DiGraph`. - - Yields - ------ - A 3-tuple representation of a collider - Each collider is a 3-tuple with the parent, collider, and other parent. - - Raises - ------ - NetworkXNotImplemented - If `G` is an undirected graph. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (0, 4), (3, 1), (2, 4), (0, 5), (4, 5), (1, 5)]) - >>> nx.is_directed_acyclic_graph(G) - True - >>> list(nx.dag.colliders(G)) - [(0, 4, 2), (0, 5, 4), (0, 5, 1), (4, 5, 1)] - - See Also - -------- - v_structures - - Notes - ----- - This function was written to be used on DAGs, however it works on cyclic graphs - too. Since colliders are referred to in the cyclic causal graph literature - [2]_ we allow cyclic graphs in this function. It is suggested that you test if - your input graph is acyclic as in the example if you want that property. - - References - ---------- - .. [1] `Wikipedia: Collider in causal graphs `_ - .. [2] A Hyttinen, P.O. Hoyer, F. Eberhardt, M J ̈arvisalo, (2013) - "Discovering cyclic causal models with latent variables: - a general SAT-based procedure", UAI'13: Proceedings of the Twenty-Ninth - Conference on Uncertainty in Artificial Intelligence, pg 301–310, - `doi:10.5555/3023638.3023669 `_ - """ - for node in G.nodes: - for p1, p2 in combinations(G.predecessors(node), 2): - yield (p1, node, p2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_measures.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_measures.py deleted file mode 100644 index 8e15bf8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_measures.py +++ /dev/null @@ -1,1022 +0,0 @@ -"""Graph diameter, radius, eccentricity and other properties.""" - -import math - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "eccentricity", - "diameter", - "harmonic_diameter", - "radius", - "periphery", - "center", - "barycenter", - "resistance_distance", - "kemeny_constant", - "effective_graph_resistance", -] - - -def _extrema_bounding(G, compute="diameter", weight=None): - """Compute requested extreme distance metric of undirected graph G - - Computation is based on smart lower and upper bounds, and in practice - linear in the number of nodes, rather than quadratic (except for some - border cases such as complete graphs or circle shaped graphs). - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - compute : string denoting the requesting metric - "diameter" for the maximal eccentricity value, - "radius" for the minimal eccentricity value, - "periphery" for the set of nodes with eccentricity equal to the diameter, - "center" for the set of nodes with eccentricity equal to the radius, - "eccentricities" for the maximum distance from each node to all other nodes in G - - weight : string, function, or None - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - value : value of the requested metric - int for "diameter" and "radius" or - list of nodes for "center" and "periphery" or - dictionary of eccentricity values keyed by node for "eccentricities" - - Raises - ------ - NetworkXError - If the graph consists of multiple components - ValueError - If `compute` is not one of "diameter", "radius", "periphery", "center", or "eccentricities". - - Notes - ----- - This algorithm was proposed in [1]_ and discussed further in [2]_ and [3]_. - - References - ---------- - .. [1] F. W. Takes, W. A. Kosters, - "Determining the diameter of small world networks." - Proceedings of the 20th ACM international conference on Information and knowledge management, 2011 - https://dl.acm.org/doi/abs/10.1145/2063576.2063748 - .. [2] F. W. Takes, W. A. Kosters, - "Computing the Eccentricity Distribution of Large Graphs." - Algorithms, 2013 - https://www.mdpi.com/1999-4893/6/1/100 - .. [3] M. Borassi, P. Crescenzi, M. Habib, W. A. Kosters, A. Marino, F. W. Takes, - "Fast diameter and radius BFS-based computation in (weakly connected) real-world graphs: With an application to the six degrees of separation games. " - Theoretical Computer Science, 2015 - https://www.sciencedirect.com/science/article/pii/S0304397515001644 - """ - # init variables - degrees = dict(G.degree()) # start with the highest degree node - minlowernode = max(degrees, key=degrees.get) - N = len(degrees) # number of nodes - # alternate between smallest lower and largest upper bound - high = False - # status variables - ecc_lower = dict.fromkeys(G, 0) - ecc_upper = dict.fromkeys(G, N) - candidates = set(G) - - # (re)set bound extremes - minlower = N - maxlower = 0 - minupper = N - maxupper = 0 - - # repeat the following until there are no more candidates - while candidates: - if high: - current = maxuppernode # select node with largest upper bound - else: - current = minlowernode # select node with smallest lower bound - high = not high - - # get distances from/to current node and derive eccentricity - dist = nx.shortest_path_length(G, source=current, weight=weight) - - if len(dist) != N: - msg = "Cannot compute metric because graph is not connected." - raise nx.NetworkXError(msg) - current_ecc = max(dist.values()) - - # print status update - # print ("ecc of " + str(current) + " (" + str(ecc_lower[current]) + "/" - # + str(ecc_upper[current]) + ", deg: " + str(dist[current]) + ") is " - # + str(current_ecc)) - # print(ecc_upper) - - # (re)set bound extremes - maxuppernode = None - minlowernode = None - - # update node bounds - for i in candidates: - # update eccentricity bounds - d = dist[i] - ecc_lower[i] = low = max(ecc_lower[i], max(d, (current_ecc - d))) - ecc_upper[i] = upp = min(ecc_upper[i], current_ecc + d) - - # update min/max values of lower and upper bounds - minlower = min(ecc_lower[i], minlower) - maxlower = max(ecc_lower[i], maxlower) - minupper = min(ecc_upper[i], minupper) - maxupper = max(ecc_upper[i], maxupper) - - # update candidate set - if compute == "diameter": - ruled_out = { - i - for i in candidates - if ecc_upper[i] <= maxlower and 2 * ecc_lower[i] >= maxupper - } - elif compute == "radius": - ruled_out = { - i - for i in candidates - if ecc_lower[i] >= minupper and ecc_upper[i] + 1 <= 2 * minlower - } - elif compute == "periphery": - ruled_out = { - i - for i in candidates - if ecc_upper[i] < maxlower - and (maxlower == maxupper or ecc_lower[i] > maxupper) - } - elif compute == "center": - ruled_out = { - i - for i in candidates - if ecc_lower[i] > minupper - and (minlower == minupper or ecc_upper[i] + 1 < 2 * minlower) - } - elif compute == "eccentricities": - ruled_out = set() - else: - msg = "compute must be one of 'diameter', 'radius', 'periphery', 'center', 'eccentricities'" - raise ValueError(msg) - - ruled_out.update(i for i in candidates if ecc_lower[i] == ecc_upper[i]) - candidates -= ruled_out - - # for i in ruled_out: - # print("removing %g: ecc_u: %g maxl: %g ecc_l: %g maxu: %g"% - # (i,ecc_upper[i],maxlower,ecc_lower[i],maxupper)) - # print("node %g: ecc_u: %g maxl: %g ecc_l: %g maxu: %g"% - # (4,ecc_upper[4],maxlower,ecc_lower[4],maxupper)) - # print("NODE 4: %g"%(ecc_upper[4] <= maxlower)) - # print("NODE 4: %g"%(2 * ecc_lower[4] >= maxupper)) - # print("NODE 4: %g"%(ecc_upper[4] <= maxlower - # and 2 * ecc_lower[4] >= maxupper)) - - # updating maxuppernode and minlowernode for selection in next round - for i in candidates: - if ( - minlowernode is None - or ( - ecc_lower[i] == ecc_lower[minlowernode] - and degrees[i] > degrees[minlowernode] - ) - or (ecc_lower[i] < ecc_lower[minlowernode]) - ): - minlowernode = i - - if ( - maxuppernode is None - or ( - ecc_upper[i] == ecc_upper[maxuppernode] - and degrees[i] > degrees[maxuppernode] - ) - or (ecc_upper[i] > ecc_upper[maxuppernode]) - ): - maxuppernode = i - - # print status update - # print (" min=" + str(minlower) + "/" + str(minupper) + - # " max=" + str(maxlower) + "/" + str(maxupper) + - # " candidates: " + str(len(candidates))) - # print("cand:",candidates) - # print("ecc_l",ecc_lower) - # print("ecc_u",ecc_upper) - # wait = input("press Enter to continue") - - # return the correct value of the requested metric - if compute == "diameter": - return maxlower - if compute == "radius": - return minupper - if compute == "periphery": - p = [v for v in G if ecc_lower[v] == maxlower] - return p - if compute == "center": - c = [v for v in G if ecc_upper[v] == minupper] - return c - if compute == "eccentricities": - return ecc_lower - return None - - -@nx._dispatchable(edge_attrs="weight") -def eccentricity(G, v=None, sp=None, weight=None): - """Returns the eccentricity of nodes in G. - - The eccentricity of a node v is the maximum distance from v to - all other nodes in G. - - Parameters - ---------- - G : NetworkX graph - A graph - - v : node, optional - Return value of specified node - - sp : dict of dicts, optional - All pairs shortest path lengths as a dictionary of dictionaries - - weight : string, function, or None (default=None) - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - ecc : dictionary - A dictionary of eccentricity values keyed by node. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> dict(nx.eccentricity(G)) - {1: 2, 2: 3, 3: 2, 4: 2, 5: 3} - - >>> dict( - ... nx.eccentricity(G, v=[1, 5]) - ... ) # This returns the eccentricity of node 1 & 5 - {1: 2, 5: 3} - - """ - # if v is None: # none, use entire graph - # nodes=G.nodes() - # elif v in G: # is v a single node - # nodes=[v] - # else: # assume v is a container of nodes - # nodes=v - order = G.order() - e = {} - for n in G.nbunch_iter(v): - if sp is None: - length = nx.shortest_path_length(G, source=n, weight=weight) - - L = len(length) - else: - try: - length = sp[n] - L = len(length) - except TypeError as err: - raise nx.NetworkXError('Format of "sp" is invalid.') from err - if L != order: - if G.is_directed(): - msg = ( - "Found infinite path length because the digraph is not" - " strongly connected" - ) - else: - msg = "Found infinite path length because the graph is not" " connected" - raise nx.NetworkXError(msg) - - e[n] = max(length.values()) - - if v in G: - return e[v] # return single value - return e - - -@nx._dispatchable(edge_attrs="weight") -def diameter(G, e=None, usebounds=False, weight=None): - """Returns the diameter of the graph G. - - The diameter is the maximum eccentricity. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - weight : string, function, or None - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - d : integer - Diameter of graph - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> nx.diameter(G) - 3 - - See Also - -------- - eccentricity - """ - if usebounds is True and e is None and not G.is_directed(): - return _extrema_bounding(G, compute="diameter", weight=weight) - if e is None: - e = eccentricity(G, weight=weight) - return max(e.values()) - - -@nx._dispatchable -def harmonic_diameter(G, sp=None): - """Returns the harmonic diameter of the graph G. - - The harmonic diameter of a graph is the harmonic mean of the distances - between all pairs of distinct vertices. Graphs that are not strongly - connected have infinite diameter and mean distance, making such - measures not useful. Restricting the diameter or mean distance to - finite distances yields paradoxical values (e.g., a perfect match - would have diameter one). The harmonic mean handles gracefully - infinite distances (e.g., a perfect match has harmonic diameter equal - to the number of vertices minus one), making it possible to assign a - meaningful value to all graphs. - - Note that in [1] the harmonic diameter is called "connectivity length": - however, "harmonic diameter" is a more standard name from the - theory of metric spaces. The name "harmonic mean distance" is perhaps - a more descriptive name, but is not used in the literature, so we use the - name "harmonic diameter" here. - - Parameters - ---------- - G : NetworkX graph - A graph - - sp : dict of dicts, optional - All-pairs shortest path lengths as a dictionary of dictionaries - - Returns - ------- - hd : float - Harmonic diameter of graph - - References - ---------- - .. [1] Massimo Marchiori and Vito Latora, "Harmony in the small-world". - *Physica A: Statistical Mechanics and Its Applications* - 285(3-4), pages 539-546, 2000. - - """ - order = G.order() - - sum_invd = 0 - for n in G: - if sp is None: - length = nx.single_source_shortest_path_length(G, n) - else: - try: - length = sp[n] - L = len(length) - except TypeError as err: - raise nx.NetworkXError('Format of "sp" is invalid.') from err - - for d in length.values(): - # Note that this will skip the zero distance from n to itself, - # as it should be, but also zero-weight paths in weighted graphs. - if d != 0: - sum_invd += 1 / d - - if sum_invd != 0: - return order * (order - 1) / sum_invd - if order > 1: - return math.inf - return math.nan - - -@nx._dispatchable(edge_attrs="weight") -def periphery(G, e=None, usebounds=False, weight=None): - """Returns the periphery of the graph G. - - The periphery is the set of nodes with eccentricity equal to the diameter. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - weight : string, function, or None - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - p : list - List of nodes in periphery - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> nx.periphery(G) - [2, 5] - - See Also - -------- - barycenter - center - """ - if usebounds is True and e is None and not G.is_directed(): - return _extrema_bounding(G, compute="periphery", weight=weight) - if e is None: - e = eccentricity(G, weight=weight) - diameter = max(e.values()) - p = [v for v in e if e[v] == diameter] - return p - - -@nx._dispatchable(edge_attrs="weight") -def radius(G, e=None, usebounds=False, weight=None): - """Returns the radius of the graph G. - - The radius is the minimum eccentricity. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - weight : string, function, or None - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - r : integer - Radius of graph - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> nx.radius(G) - 2 - - """ - if usebounds is True and e is None and not G.is_directed(): - return _extrema_bounding(G, compute="radius", weight=weight) - if e is None: - e = eccentricity(G, weight=weight) - return min(e.values()) - - -@nx._dispatchable(edge_attrs="weight") -def center(G, e=None, usebounds=False, weight=None): - """Returns the center of the graph G. - - The center is the set of nodes with eccentricity equal to radius. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - weight : string, function, or None - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - If this is None, every edge has weight/distance/cost 1. - - Weights stored as floating point values can lead to small round-off - errors in distances. Use integer weights to avoid this. - - Weights should be positive, since they are distances. - - Returns - ------- - c : list - List of nodes in center - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> list(nx.center(G)) - [1, 3, 4] - - See Also - -------- - barycenter - periphery - """ - if usebounds is True and e is None and not G.is_directed(): - return _extrema_bounding(G, compute="center", weight=weight) - if e is None: - e = eccentricity(G, weight=weight) - radius = min(e.values()) - p = [v for v in e if e[v] == radius] - return p - - -@nx._dispatchable(edge_attrs="weight", mutates_input={"attr": 2}) -def barycenter(G, weight=None, attr=None, sp=None): - r"""Calculate barycenter of a connected graph, optionally with edge weights. - - The :dfn:`barycenter` a - :func:`connected ` graph - :math:`G` is the subgraph induced by the set of its nodes :math:`v` - minimizing the objective function - - .. math:: - - \sum_{u \in V(G)} d_G(u, v), - - where :math:`d_G` is the (possibly weighted) :func:`path length - `. - The barycenter is also called the :dfn:`median`. See [West01]_, p. 78. - - Parameters - ---------- - G : :class:`networkx.Graph` - The connected graph :math:`G`. - weight : :class:`str`, optional - Passed through to - :func:`~networkx.algorithms.shortest_paths.generic.shortest_path_length`. - attr : :class:`str`, optional - If given, write the value of the objective function to each node's - `attr` attribute. Otherwise do not store the value. - sp : dict of dicts, optional - All pairs shortest path lengths as a dictionary of dictionaries - - Returns - ------- - list - Nodes of `G` that induce the barycenter of `G`. - - Raises - ------ - NetworkXNoPath - If `G` is disconnected. `G` may appear disconnected to - :func:`barycenter` if `sp` is given but is missing shortest path - lengths for any pairs. - ValueError - If `sp` and `weight` are both given. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> nx.barycenter(G) - [1, 3, 4] - - See Also - -------- - center - periphery - """ - if sp is None: - sp = nx.shortest_path_length(G, weight=weight) - else: - sp = sp.items() - if weight is not None: - raise ValueError("Cannot use both sp, weight arguments together") - smallest, barycenter_vertices, n = float("inf"), [], len(G) - for v, dists in sp: - if len(dists) < n: - raise nx.NetworkXNoPath( - f"Input graph {G} is disconnected, so every induced subgraph " - "has infinite barycentricity." - ) - barycentricity = sum(dists.values()) - if attr is not None: - G.nodes[v][attr] = barycentricity - if barycentricity < smallest: - smallest = barycentricity - barycenter_vertices = [v] - elif barycentricity == smallest: - barycenter_vertices.append(v) - if attr is not None: - nx._clear_cache(G) - return barycenter_vertices - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def resistance_distance(G, nodeA=None, nodeB=None, weight=None, invert_weight=True): - """Returns the resistance distance between pairs of nodes in graph G. - - The resistance distance between two nodes of a graph is akin to treating - the graph as a grid of resistors with a resistance equal to the provided - weight [1]_, [2]_. - - If weight is not provided, then a weight of 1 is used for all edges. - - If two nodes are the same, the resistance distance is zero. - - Parameters - ---------- - G : NetworkX graph - A graph - - nodeA : node or None, optional (default=None) - A node within graph G. - If None, compute resistance distance using all nodes as source nodes. - - nodeB : node or None, optional (default=None) - A node within graph G. - If None, compute resistance distance using all nodes as target nodes. - - weight : string or None, optional (default=None) - The edge data key used to compute the resistance distance. - If None, then each edge has weight 1. - - invert_weight : boolean (default=True) - Proper calculation of resistance distance requires building the - Laplacian matrix with the reciprocal of the weight. Not required - if the weight is already inverted. Weight cannot be zero. - - Returns - ------- - rd : dict or float - If `nodeA` and `nodeB` are given, resistance distance between `nodeA` - and `nodeB`. If `nodeA` or `nodeB` is unspecified (the default), a - dictionary of nodes with resistance distances as the value. - - Raises - ------ - NetworkXNotImplemented - If `G` is a directed graph. - - NetworkXError - If `G` is not connected, or contains no nodes, - or `nodeA` is not in `G` or `nodeB` is not in `G`. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> round(nx.resistance_distance(G, 1, 3), 10) - 0.625 - - Notes - ----- - The implementation is based on Theorem A in [2]_. Self-loops are ignored. - Multi-edges are contracted in one edge with weight equal to the harmonic sum of the weights. - - References - ---------- - .. [1] Wikipedia - "Resistance distance." - https://en.wikipedia.org/wiki/Resistance_distance - .. [2] D. J. Klein and M. Randic. - Resistance distance. - J. of Math. Chem. 12:81-95, 1993. - """ - import numpy as np - - if len(G) == 0: - raise nx.NetworkXError("Graph G must contain at least one node.") - if not nx.is_connected(G): - raise nx.NetworkXError("Graph G must be strongly connected.") - if nodeA is not None and nodeA not in G: - raise nx.NetworkXError("Node A is not in graph G.") - if nodeB is not None and nodeB not in G: - raise nx.NetworkXError("Node B is not in graph G.") - - G = G.copy() - node_list = list(G) - - # Invert weights - if invert_weight and weight is not None: - if G.is_multigraph(): - for u, v, k, d in G.edges(keys=True, data=True): - d[weight] = 1 / d[weight] - else: - for u, v, d in G.edges(data=True): - d[weight] = 1 / d[weight] - - # Compute resistance distance using the Pseudo-inverse of the Laplacian - # Self-loops are ignored - L = nx.laplacian_matrix(G, weight=weight).todense() - Linv = np.linalg.pinv(L, hermitian=True) - - # Return relevant distances - if nodeA is not None and nodeB is not None: - i = node_list.index(nodeA) - j = node_list.index(nodeB) - return Linv.item(i, i) + Linv.item(j, j) - Linv.item(i, j) - Linv.item(j, i) - - elif nodeA is not None: - i = node_list.index(nodeA) - d = {} - for n in G: - j = node_list.index(n) - d[n] = Linv.item(i, i) + Linv.item(j, j) - Linv.item(i, j) - Linv.item(j, i) - return d - - elif nodeB is not None: - j = node_list.index(nodeB) - d = {} - for n in G: - i = node_list.index(n) - d[n] = Linv.item(i, i) + Linv.item(j, j) - Linv.item(i, j) - Linv.item(j, i) - return d - - else: - d = {} - for n in G: - i = node_list.index(n) - d[n] = {} - for n2 in G: - j = node_list.index(n2) - d[n][n2] = ( - Linv.item(i, i) - + Linv.item(j, j) - - Linv.item(i, j) - - Linv.item(j, i) - ) - return d - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def effective_graph_resistance(G, weight=None, invert_weight=True): - """Returns the Effective graph resistance of G. - - Also known as the Kirchhoff index. - - The effective graph resistance is defined as the sum - of the resistance distance of every node pair in G [1]_. - - If weight is not provided, then a weight of 1 is used for all edges. - - The effective graph resistance of a disconnected graph is infinite. - - Parameters - ---------- - G : NetworkX graph - A graph - - weight : string or None, optional (default=None) - The edge data key used to compute the effective graph resistance. - If None, then each edge has weight 1. - - invert_weight : boolean (default=True) - Proper calculation of resistance distance requires building the - Laplacian matrix with the reciprocal of the weight. Not required - if the weight is already inverted. Weight cannot be zero. - - Returns - ------- - RG : float - The effective graph resistance of `G`. - - Raises - ------ - NetworkXNotImplemented - If `G` is a directed graph. - - NetworkXError - If `G` does not contain any nodes. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (1, 4), (3, 4), (3, 5), (4, 5)]) - >>> round(nx.effective_graph_resistance(G), 10) - 10.25 - - Notes - ----- - The implementation is based on Theorem 2.2 in [2]_. Self-loops are ignored. - Multi-edges are contracted in one edge with weight equal to the harmonic sum of the weights. - - References - ---------- - .. [1] Wolfram - "Kirchhoff Index." - https://mathworld.wolfram.com/KirchhoffIndex.html - .. [2] W. Ellens, F. M. Spieksma, P. Van Mieghem, A. Jamakovic, R. E. Kooij. - Effective graph resistance. - Lin. Alg. Appl. 435:2491-2506, 2011. - """ - import numpy as np - - if len(G) == 0: - raise nx.NetworkXError("Graph G must contain at least one node.") - - # Disconnected graphs have infinite Effective graph resistance - if not nx.is_connected(G): - return float("inf") - - # Invert weights - G = G.copy() - if invert_weight and weight is not None: - if G.is_multigraph(): - for u, v, k, d in G.edges(keys=True, data=True): - d[weight] = 1 / d[weight] - else: - for u, v, d in G.edges(data=True): - d[weight] = 1 / d[weight] - - # Get Laplacian eigenvalues - mu = np.sort(nx.laplacian_spectrum(G, weight=weight)) - - # Compute Effective graph resistance based on spectrum of the Laplacian - # Self-loops are ignored - return float(np.sum(1 / mu[1:]) * G.number_of_nodes()) - - -@nx.utils.not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def kemeny_constant(G, *, weight=None): - """Returns the Kemeny constant of the given graph. - - The *Kemeny constant* (or Kemeny's constant) of a graph `G` - can be computed by regarding the graph as a Markov chain. - The Kemeny constant is then the expected number of time steps - to transition from a starting state i to a random destination state - sampled from the Markov chain's stationary distribution. - The Kemeny constant is independent of the chosen initial state [1]_. - - The Kemeny constant measures the time needed for spreading - across a graph. Low values indicate a closely connected graph - whereas high values indicate a spread-out graph. - - If weight is not provided, then a weight of 1 is used for all edges. - - Since `G` represents a Markov chain, the weights must be positive. - - Parameters - ---------- - G : NetworkX graph - - weight : string or None, optional (default=None) - The edge data key used to compute the Kemeny constant. - If None, then each edge has weight 1. - - Returns - ------- - float - The Kemeny constant of the graph `G`. - - Raises - ------ - NetworkXNotImplemented - If the graph `G` is directed. - - NetworkXError - If the graph `G` is not connected, or contains no nodes, - or has edges with negative weights. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> round(nx.kemeny_constant(G), 10) - 3.2 - - Notes - ----- - The implementation is based on equation (3.3) in [2]_. - Self-loops are allowed and indicate a Markov chain where - the state can remain the same. Multi-edges are contracted - in one edge with weight equal to the sum of the weights. - - References - ---------- - .. [1] Wikipedia - "Kemeny's constant." - https://en.wikipedia.org/wiki/Kemeny%27s_constant - .. [2] Lovász L. - Random walks on graphs: A survey. - Paul Erdös is Eighty, vol. 2, Bolyai Society, - Mathematical Studies, Keszthely, Hungary (1993), pp. 1-46 - """ - import numpy as np - import scipy as sp - - if len(G) == 0: - raise nx.NetworkXError("Graph G must contain at least one node.") - if not nx.is_connected(G): - raise nx.NetworkXError("Graph G must be connected.") - if nx.is_negatively_weighted(G, weight=weight): - raise nx.NetworkXError("The weights of graph G must be nonnegative.") - - # Compute matrix H = D^-1/2 A D^-1/2 - A = nx.adjacency_matrix(G, weight=weight) - n, m = A.shape - diags = A.sum(axis=1) - with np.errstate(divide="ignore"): - diags_sqrt = 1.0 / np.sqrt(diags) - diags_sqrt[np.isinf(diags_sqrt)] = 0 - DH = sp.sparse.csr_array(sp.sparse.spdiags(diags_sqrt, 0, m, n, format="csr")) - H = DH @ (A @ DH) - - # Compute eigenvalues of H - eig = np.sort(sp.linalg.eigvalsh(H.todense())) - - # Compute the Kemeny constant - return float(np.sum(1 / (1 - eig[:-1]))) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_regular.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_regular.py deleted file mode 100644 index 27b4d02..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/distance_regular.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -======================= -Distance-regular graphs -======================= -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -from .distance_measures import diameter - -__all__ = [ - "is_distance_regular", - "is_strongly_regular", - "intersection_array", - "global_parameters", -] - - -@nx._dispatchable -def is_distance_regular(G): - """Returns True if the graph is distance regular, False otherwise. - - A connected graph G is distance-regular if for any nodes x,y - and any integers i,j=0,1,...,d (where d is the graph - diameter), the number of vertices at distance i from x and - distance j from y depends only on i,j and the graph distance - between x and y, independently of the choice of x and y. - - Parameters - ---------- - G: Networkx graph (undirected) - - Returns - ------- - bool - True if the graph is Distance Regular, False otherwise - - Examples - -------- - >>> G = nx.hypercube_graph(6) - >>> nx.is_distance_regular(G) - True - - See Also - -------- - intersection_array, global_parameters - - Notes - ----- - For undirected and simple graphs only - - References - ---------- - .. [1] Brouwer, A. E.; Cohen, A. M.; and Neumaier, A. - Distance-Regular Graphs. New York: Springer-Verlag, 1989. - .. [2] Weisstein, Eric W. "Distance-Regular Graph." - http://mathworld.wolfram.com/Distance-RegularGraph.html - - """ - try: - intersection_array(G) - return True - except nx.NetworkXError: - return False - - -def global_parameters(b, c): - """Returns global parameters for a given intersection array. - - Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d - such that for any 2 vertices x,y in G at a distance i=d(x,y), there - are exactly c_i neighbors of y at a distance of i-1 from x and b_i - neighbors of y at a distance of i+1 from x. - - Thus, a distance regular graph has the global parameters, - [[c_0,a_0,b_0],[c_1,a_1,b_1],......,[c_d,a_d,b_d]] for the - intersection array [b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d] - where a_i+b_i+c_i=k , k= degree of every vertex. - - Parameters - ---------- - b : list - - c : list - - Returns - ------- - iterable - An iterable over three tuples. - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> b, c = nx.intersection_array(G) - >>> list(nx.global_parameters(b, c)) - [(0, 0, 3), (1, 0, 2), (1, 1, 1), (1, 1, 1), (2, 0, 1), (3, 0, 0)] - - References - ---------- - .. [1] Weisstein, Eric W. "Global Parameters." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/GlobalParameters.html - - See Also - -------- - intersection_array - """ - return ((y, b[0] - x - y, x) for x, y in zip(b + [0], [0] + c)) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def intersection_array(G): - """Returns the intersection array of a distance-regular graph. - - Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d - such that for any 2 vertices x,y in G at a distance i=d(x,y), there - are exactly c_i neighbors of y at a distance of i-1 from x and b_i - neighbors of y at a distance of i+1 from x. - - A distance regular graph's intersection array is given by, - [b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d] - - Parameters - ---------- - G: Networkx graph (undirected) - - Returns - ------- - b,c: tuple of lists - - Examples - -------- - >>> G = nx.icosahedral_graph() - >>> nx.intersection_array(G) - ([5, 2, 1], [1, 2, 5]) - - References - ---------- - .. [1] Weisstein, Eric W. "Intersection Array." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/IntersectionArray.html - - See Also - -------- - global_parameters - """ - # test for regular graph (all degrees must be equal) - if len(G) == 0: - raise nx.NetworkXPointlessConcept("Graph has no nodes.") - degree = iter(G.degree()) - (_, k) = next(degree) - for _, knext in degree: - if knext != k: - raise nx.NetworkXError("Graph is not distance regular.") - k = knext - path_length = dict(nx.all_pairs_shortest_path_length(G)) - diameter = max(max(path_length[n].values()) for n in path_length) - bint = {} # 'b' intersection array - cint = {} # 'c' intersection array - for u in G: - for v in G: - try: - i = path_length[u][v] - except KeyError as err: # graph must be connected - raise nx.NetworkXError("Graph is not distance regular.") from err - # number of neighbors of v at a distance of i-1 from u - c = len([n for n in G[v] if path_length[n][u] == i - 1]) - # number of neighbors of v at a distance of i+1 from u - b = len([n for n in G[v] if path_length[n][u] == i + 1]) - # b,c are independent of u and v - if cint.get(i, c) != c or bint.get(i, b) != b: - raise nx.NetworkXError("Graph is not distance regular") - bint[i] = b - cint[i] = c - return ( - [bint.get(j, 0) for j in range(diameter)], - [cint.get(j + 1, 0) for j in range(diameter)], - ) - - -# TODO There is a definition for directed strongly regular graphs. -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_strongly_regular(G): - """Returns True if and only if the given graph is strongly - regular. - - An undirected graph is *strongly regular* if - - * it is regular, - * each pair of adjacent vertices has the same number of neighbors in - common, - * each pair of nonadjacent vertices has the same number of neighbors - in common. - - Each strongly regular graph is a distance-regular graph. - Conversely, if a distance-regular graph has diameter two, then it is - a strongly regular graph. For more information on distance-regular - graphs, see :func:`is_distance_regular`. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - bool - Whether `G` is strongly regular. - - Examples - -------- - - The cycle graph on five vertices is strongly regular. It is - two-regular, each pair of adjacent vertices has no shared neighbors, - and each pair of nonadjacent vertices has one shared neighbor:: - - >>> G = nx.cycle_graph(5) - >>> nx.is_strongly_regular(G) - True - - """ - # Here is an alternate implementation based directly on the - # definition of strongly regular graphs: - # - # return (all_equal(G.degree().values()) - # and all_equal(len(common_neighbors(G, u, v)) - # for u, v in G.edges()) - # and all_equal(len(common_neighbors(G, u, v)) - # for u, v in non_edges(G))) - # - # We instead use the fact that a distance-regular graph of diameter - # two is strongly regular. - return is_distance_regular(G) and diameter(G) == 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominance.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominance.py deleted file mode 100644 index 30cb811..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominance.py +++ /dev/null @@ -1,135 +0,0 @@ -""" -Dominance algorithms. -""" - -from functools import reduce - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["immediate_dominators", "dominance_frontiers"] - - -@not_implemented_for("undirected") -@nx._dispatchable -def immediate_dominators(G, start): - """Returns the immediate dominators of all nodes of a directed graph. - - Parameters - ---------- - G : a DiGraph or MultiDiGraph - The graph where dominance is to be computed. - - start : node - The start node of dominance computation. - - Returns - ------- - idom : dict keyed by nodes - A dict containing the immediate dominators of each node reachable from - `start`. - - Raises - ------ - NetworkXNotImplemented - If `G` is undirected. - - NetworkXError - If `start` is not in `G`. - - Notes - ----- - Except for `start`, the immediate dominators are the parents of their - corresponding nodes in the dominator tree. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)]) - >>> sorted(nx.immediate_dominators(G, 1).items()) - [(1, 1), (2, 1), (3, 1), (4, 3), (5, 1)] - - References - ---------- - .. [1] Cooper, Keith D., Harvey, Timothy J. and Kennedy, Ken. - "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - if start not in G: - raise nx.NetworkXError("start is not in G") - - idom = {start: start} - - order = list(nx.dfs_postorder_nodes(G, start)) - dfn = {u: i for i, u in enumerate(order)} - order.pop() - order.reverse() - - def intersect(u, v): - while u != v: - while dfn[u] < dfn[v]: - u = idom[u] - while dfn[u] > dfn[v]: - v = idom[v] - return u - - changed = True - while changed: - changed = False - for u in order: - new_idom = reduce(intersect, (v for v in G.pred[u] if v in idom)) - if u not in idom or idom[u] != new_idom: - idom[u] = new_idom - changed = True - - return idom - - -@nx._dispatchable -def dominance_frontiers(G, start): - """Returns the dominance frontiers of all nodes of a directed graph. - - Parameters - ---------- - G : a DiGraph or MultiDiGraph - The graph where dominance is to be computed. - - start : node - The start node of dominance computation. - - Returns - ------- - df : dict keyed by nodes - A dict containing the dominance frontiers of each node reachable from - `start` as lists. - - Raises - ------ - NetworkXNotImplemented - If `G` is undirected. - - NetworkXError - If `start` is not in `G`. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)]) - >>> sorted((u, sorted(df)) for u, df in nx.dominance_frontiers(G, 1).items()) - [(1, []), (2, [5]), (3, [5]), (4, [5]), (5, [])] - - References - ---------- - .. [1] Cooper, Keith D., Harvey, Timothy J. and Kennedy, Ken. - "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - idom = nx.immediate_dominators(G, start) - - df = {u: set() for u in idom} - for u in idom: - if len(G.pred[u]) >= 2: - for v in G.pred[u]: - if v in idom: - while v != idom[u]: - df[v].add(u) - v = idom[v] - return df diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominating.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominating.py deleted file mode 100644 index ff956f7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/dominating.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Functions for computing dominating sets in a graph.""" - -from itertools import chain - -import networkx as nx -from networkx.utils import arbitrary_element - -__all__ = ["dominating_set", "is_dominating_set"] - - -@nx._dispatchable -def dominating_set(G, start_with=None): - r"""Finds a dominating set for the graph G. - - A *dominating set* for a graph with node set *V* is a subset *D* of - *V* such that every node not in *D* is adjacent to at least one - member of *D* [1]_. - - Parameters - ---------- - G : NetworkX graph - - start_with : node (default=None) - Node to use as a starting point for the algorithm. - - Returns - ------- - D : set - A dominating set for G. - - Notes - ----- - This function is an implementation of algorithm 7 in [2]_ which - finds some dominating set, not necessarily the smallest one. - - See also - -------- - is_dominating_set - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Dominating_set - - .. [2] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - all_nodes = set(G) - if start_with is None: - start_with = arbitrary_element(all_nodes) - if start_with not in G: - raise nx.NetworkXError(f"node {start_with} is not in G") - dominating_set = {start_with} - dominated_nodes = set(G[start_with]) - remaining_nodes = all_nodes - dominated_nodes - dominating_set - while remaining_nodes: - # Choose an arbitrary node and determine its undominated neighbors. - v = remaining_nodes.pop() - undominated_nbrs = set(G[v]) - dominating_set - # Add the node to the dominating set and the neighbors to the - # dominated set. Finally, remove all of those nodes from the set - # of remaining nodes. - dominating_set.add(v) - dominated_nodes |= undominated_nbrs - remaining_nodes -= undominated_nbrs - return dominating_set - - -@nx._dispatchable -def is_dominating_set(G, nbunch): - """Checks if `nbunch` is a dominating set for `G`. - - A *dominating set* for a graph with node set *V* is a subset *D* of - *V* such that every node not in *D* is adjacent to at least one - member of *D* [1]_. - - Parameters - ---------- - G : NetworkX graph - - nbunch : iterable - An iterable of nodes in the graph `G`. - - See also - -------- - dominating_set - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Dominating_set - - """ - testset = {n for n in nbunch if n in G} - nbrs = set(chain.from_iterable(G[n] for n in testset)) - return len(set(G) - testset - nbrs) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/efficiency_measures.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/efficiency_measures.py deleted file mode 100644 index b8e9d7a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/efficiency_measures.py +++ /dev/null @@ -1,167 +0,0 @@ -"""Provides functions for computing the efficiency of nodes and graphs.""" - -import networkx as nx -from networkx.exception import NetworkXNoPath - -from ..utils import not_implemented_for - -__all__ = ["efficiency", "local_efficiency", "global_efficiency"] - - -@not_implemented_for("directed") -@nx._dispatchable -def efficiency(G, u, v): - """Returns the efficiency of a pair of nodes in a graph. - - The *efficiency* of a pair of nodes is the multiplicative inverse of the - shortest path distance between the nodes [1]_. Returns 0 if no path - between nodes. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average local efficiency. - u, v : node - Nodes in the graph ``G``. - - Returns - ------- - float - Multiplicative inverse of the shortest path distance between the nodes. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.efficiency(G, 2, 3) # this gives efficiency for node 2 and 3 - 0.5 - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - local_efficiency - global_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - try: - eff = 1 / nx.shortest_path_length(G, u, v) - except NetworkXNoPath: - eff = 0 - return eff - - -@not_implemented_for("directed") -@nx._dispatchable -def global_efficiency(G): - """Returns the average global efficiency of the graph. - - The *efficiency* of a pair of nodes in a graph is the multiplicative - inverse of the shortest path distance between the nodes. The *average - global efficiency* of a graph is the average efficiency of all pairs of - nodes [1]_. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average global efficiency. - - Returns - ------- - float - The average global efficiency of the graph. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> round(nx.global_efficiency(G), 12) - 0.916666666667 - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - local_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - n = len(G) - denom = n * (n - 1) - if denom != 0: - lengths = nx.all_pairs_shortest_path_length(G) - g_eff = 0 - for source, targets in lengths: - for target, distance in targets.items(): - if distance > 0: - g_eff += 1 / distance - g_eff /= denom - # g_eff = sum(1 / d for s, tgts in lengths - # for t, d in tgts.items() if d > 0) / denom - else: - g_eff = 0 - # TODO This can be made more efficient by computing all pairs shortest - # path lengths in parallel. - return g_eff - - -@not_implemented_for("directed") -@nx._dispatchable -def local_efficiency(G): - """Returns the average local efficiency of the graph. - - The *efficiency* of a pair of nodes in a graph is the multiplicative - inverse of the shortest path distance between the nodes. The *local - efficiency* of a node in the graph is the average global efficiency of the - subgraph induced by the neighbors of the node. The *average local - efficiency* is the average of the local efficiencies of each node [1]_. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average local efficiency. - - Returns - ------- - float - The average local efficiency of the graph. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) - >>> nx.local_efficiency(G) - 0.9166666666666667 - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - global_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - efficiency_list = (global_efficiency(G.subgraph(G[v])) for v in G) - return sum(efficiency_list) / len(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/euler.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/euler.py deleted file mode 100644 index 2c308e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/euler.py +++ /dev/null @@ -1,470 +0,0 @@ -""" -Eulerian circuits and graphs. -""" - -from itertools import combinations - -import networkx as nx - -from ..utils import arbitrary_element, not_implemented_for - -__all__ = [ - "is_eulerian", - "eulerian_circuit", - "eulerize", - "is_semieulerian", - "has_eulerian_path", - "eulerian_path", -] - - -@nx._dispatchable -def is_eulerian(G): - """Returns True if and only if `G` is Eulerian. - - A graph is *Eulerian* if it has an Eulerian circuit. An *Eulerian - circuit* is a closed walk that includes each edge of a graph exactly - once. - - Graphs with isolated vertices (i.e. vertices with zero degree) are not - considered to have Eulerian circuits. Therefore, if the graph is not - connected (or not strongly connected, for directed graphs), this function - returns False. - - Parameters - ---------- - G : NetworkX graph - A graph, either directed or undirected. - - Examples - -------- - >>> nx.is_eulerian(nx.DiGraph({0: [3], 1: [2], 2: [3], 3: [0, 1]})) - True - >>> nx.is_eulerian(nx.complete_graph(5)) - True - >>> nx.is_eulerian(nx.petersen_graph()) - False - - If you prefer to allow graphs with isolated vertices to have Eulerian circuits, - you can first remove such vertices and then call `is_eulerian` as below example shows. - - >>> G = nx.Graph([(0, 1), (1, 2), (0, 2)]) - >>> G.add_node(3) - >>> nx.is_eulerian(G) - False - - >>> G.remove_nodes_from(list(nx.isolates(G))) - >>> nx.is_eulerian(G) - True - - - """ - if G.is_directed(): - # Every node must have equal in degree and out degree and the - # graph must be strongly connected - return all( - G.in_degree(n) == G.out_degree(n) for n in G - ) and nx.is_strongly_connected(G) - # An undirected Eulerian graph has no vertices of odd degree and - # must be connected. - return all(d % 2 == 0 for v, d in G.degree()) and nx.is_connected(G) - - -@nx._dispatchable -def is_semieulerian(G): - """Return True iff `G` is semi-Eulerian. - - G is semi-Eulerian if it has an Eulerian path but no Eulerian circuit. - - See Also - -------- - has_eulerian_path - is_eulerian - """ - return has_eulerian_path(G) and not is_eulerian(G) - - -def _find_path_start(G): - """Return a suitable starting vertex for an Eulerian path. - - If no path exists, return None. - """ - if not has_eulerian_path(G): - return None - - if is_eulerian(G): - return arbitrary_element(G) - - if G.is_directed(): - v1, v2 = (v for v in G if G.in_degree(v) != G.out_degree(v)) - # Determines which is the 'start' node (as opposed to the 'end') - if G.out_degree(v1) > G.in_degree(v1): - return v1 - else: - return v2 - - else: - # In an undirected graph randomly choose one of the possibilities - start = [v for v in G if G.degree(v) % 2 != 0][0] - return start - - -def _simplegraph_eulerian_circuit(G, source): - if G.is_directed(): - degree = G.out_degree - edges = G.out_edges - else: - degree = G.degree - edges = G.edges - vertex_stack = [source] - last_vertex = None - while vertex_stack: - current_vertex = vertex_stack[-1] - if degree(current_vertex) == 0: - if last_vertex is not None: - yield (last_vertex, current_vertex) - last_vertex = current_vertex - vertex_stack.pop() - else: - _, next_vertex = arbitrary_element(edges(current_vertex)) - vertex_stack.append(next_vertex) - G.remove_edge(current_vertex, next_vertex) - - -def _multigraph_eulerian_circuit(G, source): - if G.is_directed(): - degree = G.out_degree - edges = G.out_edges - else: - degree = G.degree - edges = G.edges - vertex_stack = [(source, None)] - last_vertex = None - last_key = None - while vertex_stack: - current_vertex, current_key = vertex_stack[-1] - if degree(current_vertex) == 0: - if last_vertex is not None: - yield (last_vertex, current_vertex, last_key) - last_vertex, last_key = current_vertex, current_key - vertex_stack.pop() - else: - triple = arbitrary_element(edges(current_vertex, keys=True)) - _, next_vertex, next_key = triple - vertex_stack.append((next_vertex, next_key)) - G.remove_edge(current_vertex, next_vertex, next_key) - - -@nx._dispatchable -def eulerian_circuit(G, source=None, keys=False): - """Returns an iterator over the edges of an Eulerian circuit in `G`. - - An *Eulerian circuit* is a closed walk that includes each edge of a - graph exactly once. - - Parameters - ---------- - G : NetworkX graph - A graph, either directed or undirected. - - source : node, optional - Starting node for circuit. - - keys : bool - If False, edges generated by this function will be of the form - ``(u, v)``. Otherwise, edges will be of the form ``(u, v, k)``. - This option is ignored unless `G` is a multigraph. - - Returns - ------- - edges : iterator - An iterator over edges in the Eulerian circuit. - - Raises - ------ - NetworkXError - If the graph is not Eulerian. - - See Also - -------- - is_eulerian - - Notes - ----- - This is a linear time implementation of an algorithm adapted from [1]_. - - For general information about Euler tours, see [2]_. - - References - ---------- - .. [1] J. Edmonds, E. L. Johnson. - Matching, Euler tours and the Chinese postman. - Mathematical programming, Volume 5, Issue 1 (1973), 111-114. - .. [2] https://en.wikipedia.org/wiki/Eulerian_path - - Examples - -------- - To get an Eulerian circuit in an undirected graph:: - - >>> G = nx.complete_graph(3) - >>> list(nx.eulerian_circuit(G)) - [(0, 2), (2, 1), (1, 0)] - >>> list(nx.eulerian_circuit(G, source=1)) - [(1, 2), (2, 0), (0, 1)] - - To get the sequence of vertices in an Eulerian circuit:: - - >>> [u for u, v in nx.eulerian_circuit(G)] - [0, 2, 1] - - """ - if not is_eulerian(G): - raise nx.NetworkXError("G is not Eulerian.") - if G.is_directed(): - G = G.reverse() - else: - G = G.copy() - if source is None: - source = arbitrary_element(G) - if G.is_multigraph(): - for u, v, k in _multigraph_eulerian_circuit(G, source): - if keys: - yield u, v, k - else: - yield u, v - else: - yield from _simplegraph_eulerian_circuit(G, source) - - -@nx._dispatchable -def has_eulerian_path(G, source=None): - """Return True iff `G` has an Eulerian path. - - An Eulerian path is a path in a graph which uses each edge of a graph - exactly once. If `source` is specified, then this function checks - whether an Eulerian path that starts at node `source` exists. - - A directed graph has an Eulerian path iff: - - at most one vertex has out_degree - in_degree = 1, - - at most one vertex has in_degree - out_degree = 1, - - every other vertex has equal in_degree and out_degree, - - and all of its vertices belong to a single connected - component of the underlying undirected graph. - - If `source` is not None, an Eulerian path starting at `source` exists if no - other node has out_degree - in_degree = 1. This is equivalent to either - there exists an Eulerian circuit or `source` has out_degree - in_degree = 1 - and the conditions above hold. - - An undirected graph has an Eulerian path iff: - - exactly zero or two vertices have odd degree, - - and all of its vertices belong to a single connected component. - - If `source` is not None, an Eulerian path starting at `source` exists if - either there exists an Eulerian circuit or `source` has an odd degree and the - conditions above hold. - - Graphs with isolated vertices (i.e. vertices with zero degree) are not considered - to have an Eulerian path. Therefore, if the graph is not connected (or not strongly - connected, for directed graphs), this function returns False. - - Parameters - ---------- - G : NetworkX Graph - The graph to find an euler path in. - - source : node, optional - Starting node for path. - - Returns - ------- - Bool : True if G has an Eulerian path. - - Examples - -------- - If you prefer to allow graphs with isolated vertices to have Eulerian path, - you can first remove such vertices and then call `has_eulerian_path` as below example shows. - - >>> G = nx.Graph([(0, 1), (1, 2), (0, 2)]) - >>> G.add_node(3) - >>> nx.has_eulerian_path(G) - False - - >>> G.remove_nodes_from(list(nx.isolates(G))) - >>> nx.has_eulerian_path(G) - True - - See Also - -------- - is_eulerian - eulerian_path - """ - if nx.is_eulerian(G): - return True - - if G.is_directed(): - ins = G.in_degree - outs = G.out_degree - # Since we know it is not eulerian, outs - ins must be 1 for source - if source is not None and outs[source] - ins[source] != 1: - return False - - unbalanced_ins = 0 - unbalanced_outs = 0 - for v in G: - if ins[v] - outs[v] == 1: - unbalanced_ins += 1 - elif outs[v] - ins[v] == 1: - unbalanced_outs += 1 - elif ins[v] != outs[v]: - return False - - return ( - unbalanced_ins <= 1 and unbalanced_outs <= 1 and nx.is_weakly_connected(G) - ) - else: - # We know it is not eulerian, so degree of source must be odd. - if source is not None and G.degree[source] % 2 != 1: - return False - - # Sum is 2 since we know it is not eulerian (which implies sum is 0) - return sum(d % 2 == 1 for v, d in G.degree()) == 2 and nx.is_connected(G) - - -@nx._dispatchable -def eulerian_path(G, source=None, keys=False): - """Return an iterator over the edges of an Eulerian path in `G`. - - Parameters - ---------- - G : NetworkX Graph - The graph in which to look for an eulerian path. - source : node or None (default: None) - The node at which to start the search. None means search over all - starting nodes. - keys : Bool (default: False) - Indicates whether to yield edge 3-tuples (u, v, edge_key). - The default yields edge 2-tuples - - Yields - ------ - Edge tuples along the eulerian path. - - Warning: If `source` provided is not the start node of an Euler path - will raise error even if an Euler Path exists. - """ - if not has_eulerian_path(G, source): - raise nx.NetworkXError("Graph has no Eulerian paths.") - if G.is_directed(): - G = G.reverse() - if source is None or nx.is_eulerian(G) is False: - source = _find_path_start(G) - if G.is_multigraph(): - for u, v, k in _multigraph_eulerian_circuit(G, source): - if keys: - yield u, v, k - else: - yield u, v - else: - yield from _simplegraph_eulerian_circuit(G, source) - else: - G = G.copy() - if source is None: - source = _find_path_start(G) - if G.is_multigraph(): - if keys: - yield from reversed( - [(v, u, k) for u, v, k in _multigraph_eulerian_circuit(G, source)] - ) - else: - yield from reversed( - [(v, u) for u, v, k in _multigraph_eulerian_circuit(G, source)] - ) - else: - yield from reversed( - [(v, u) for u, v in _simplegraph_eulerian_circuit(G, source)] - ) - - -@not_implemented_for("directed") -@nx._dispatchable(returns_graph=True) -def eulerize(G): - """Transforms a graph into an Eulerian graph. - - If `G` is Eulerian the result is `G` as a MultiGraph, otherwise the result is a smallest - (in terms of the number of edges) multigraph whose underlying simple graph is `G`. - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - Returns - ------- - G : NetworkX multigraph - - Raises - ------ - NetworkXError - If the graph is not connected. - - See Also - -------- - is_eulerian - eulerian_circuit - - References - ---------- - .. [1] J. Edmonds, E. L. Johnson. - Matching, Euler tours and the Chinese postman. - Mathematical programming, Volume 5, Issue 1 (1973), 111-114. - .. [2] https://en.wikipedia.org/wiki/Eulerian_path - .. [3] http://web.math.princeton.edu/math_alive/5/Notes1.pdf - - Examples - -------- - >>> G = nx.complete_graph(10) - >>> H = nx.eulerize(G) - >>> nx.is_eulerian(H) - True - - """ - if G.order() == 0: - raise nx.NetworkXPointlessConcept("Cannot Eulerize null graph") - if not nx.is_connected(G): - raise nx.NetworkXError("G is not connected") - odd_degree_nodes = [n for n, d in G.degree() if d % 2 == 1] - G = nx.MultiGraph(G) - if len(odd_degree_nodes) == 0: - return G - - # get all shortest paths between vertices of odd degree - odd_deg_pairs_paths = [ - (m, {n: nx.shortest_path(G, source=m, target=n)}) - for m, n in combinations(odd_degree_nodes, 2) - ] - - # use the number of vertices in a graph + 1 as an upper bound on - # the maximum length of a path in G - upper_bound_on_max_path_length = len(G) + 1 - - # use "len(G) + 1 - len(P)", - # where P is a shortest path between vertices n and m, - # as edge-weights in a new graph - # store the paths in the graph for easy indexing later - Gp = nx.Graph() - for n, Ps in odd_deg_pairs_paths: - for m, P in Ps.items(): - if n != m: - Gp.add_edge( - m, n, weight=upper_bound_on_max_path_length - len(P), path=P - ) - - # find the minimum weight matching of edges in the weighted graph - best_matching = nx.Graph(list(nx.max_weight_matching(Gp))) - - # duplicate each edge along each path in the set of paths in Gp - for m, n in best_matching.edges(): - path = Gp[m][n]["path"] - G.add_edges_from(nx.utils.pairwise(path)) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/__init__.py deleted file mode 100644 index c5d19ab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .maxflow import * -from .mincost import * -from .boykovkolmogorov import * -from .dinitz_alg import * -from .edmondskarp import * -from .gomory_hu import * -from .preflowpush import * -from .shortestaugmentingpath import * -from .capacityscaling import * -from .networksimplex import * -from .utils import build_flow_dict, build_residual_network diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/boykovkolmogorov.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/boykovkolmogorov.py deleted file mode 100644 index 30899c6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/boykovkolmogorov.py +++ /dev/null @@ -1,370 +0,0 @@ -""" -Boykov-Kolmogorov algorithm for maximum flow problems. -""" - -from collections import deque -from operator import itemgetter - -import networkx as nx -from networkx.algorithms.flow.utils import build_residual_network - -__all__ = ["boykov_kolmogorov"] - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def boykov_kolmogorov( - G, s, t, capacity="capacity", residual=None, value_only=False, cutoff=None -): - r"""Find a maximum single-commodity flow using Boykov-Kolmogorov algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has worse case complexity $O(n^2 m |C|)$ for $n$ nodes, $m$ - edges, and $|C|$ the cost of the minimum cut [1]_. This implementation - uses the marking heuristic defined in [2]_ which improves its running - time in many practical problems. - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> from networkx.algorithms.flow import boykov_kolmogorov - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - >>> R = boykov_kolmogorov(G, "x", "y") - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value - 3.0 - >>> flow_value == R.graph["flow_value"] - True - - A nice feature of the Boykov-Kolmogorov algorithm is that a partition - of the nodes that defines a minimum cut can be easily computed based - on the search trees used during the algorithm. These trees are stored - in the graph attribute `trees` of the residual network. - - >>> source_tree, target_tree = R.graph["trees"] - >>> partition = (set(source_tree), set(G) - set(source_tree)) - - Or equivalently: - - >>> partition = (set(G) - set(target_tree), set(target_tree)) - - References - ---------- - .. [1] Boykov, Y., & Kolmogorov, V. (2004). An experimental comparison - of min-cut/max-flow algorithms for energy minimization in vision. - Pattern Analysis and Machine Intelligence, IEEE Transactions on, - 26(9), 1124-1137. - https://doi.org/10.1109/TPAMI.2004.60 - - .. [2] Vladimir Kolmogorov. Graph-based Algorithms for Multi-camera - Reconstruction Problem. PhD thesis, Cornell University, CS Department, - 2003. pp. 109-114. - https://web.archive.org/web/20170809091249/https://pub.ist.ac.at/~vnk/papers/thesis.pdf - - """ - R = boykov_kolmogorov_impl(G, s, t, capacity, residual, cutoff) - R.graph["algorithm"] = "boykov_kolmogorov" - nx._clear_cache(R) - return R - - -def boykov_kolmogorov_impl(G, s, t, capacity, residual, cutoff): - if s not in G: - raise nx.NetworkXError(f"node {str(s)} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {str(t)} not in graph") - if s == t: - raise nx.NetworkXError("source and sink are the same node") - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - # This is way too slow - # nx.set_edge_attributes(R, 0, 'flow') - for u in R: - for e in R[u].values(): - e["flow"] = 0 - - # Use an arbitrary high value as infinite. It is computed - # when building the residual network. - INF = R.graph["inf"] - - if cutoff is None: - cutoff = INF - - R_succ = R.succ - R_pred = R.pred - - def grow(): - """Bidirectional breadth-first search for the growth stage. - - Returns a connecting edge, that is and edge that connects - a node from the source search tree with a node from the - target search tree. - The first node in the connecting edge is always from the - source tree and the last node from the target tree. - """ - while active: - u = active[0] - if u in source_tree: - this_tree = source_tree - other_tree = target_tree - neighbors = R_succ - else: - this_tree = target_tree - other_tree = source_tree - neighbors = R_pred - for v, attr in neighbors[u].items(): - if attr["capacity"] - attr["flow"] > 0: - if v not in this_tree: - if v in other_tree: - return (u, v) if this_tree is source_tree else (v, u) - this_tree[v] = u - dist[v] = dist[u] + 1 - timestamp[v] = timestamp[u] - active.append(v) - elif v in this_tree and _is_closer(u, v): - this_tree[v] = u - dist[v] = dist[u] + 1 - timestamp[v] = timestamp[u] - _ = active.popleft() - return None, None - - def augment(u, v): - """Augmentation stage. - - Reconstruct path and determine its residual capacity. - We start from a connecting edge, which links a node - from the source tree to a node from the target tree. - The connecting edge is the output of the grow function - and the input of this function. - """ - attr = R_succ[u][v] - flow = min(INF, attr["capacity"] - attr["flow"]) - path = [u] - # Trace a path from u to s in source_tree. - w = u - while w != s: - n = w - w = source_tree[n] - attr = R_pred[n][w] - flow = min(flow, attr["capacity"] - attr["flow"]) - path.append(w) - path.reverse() - # Trace a path from v to t in target_tree. - path.append(v) - w = v - while w != t: - n = w - w = target_tree[n] - attr = R_succ[n][w] - flow = min(flow, attr["capacity"] - attr["flow"]) - path.append(w) - # Augment flow along the path and check for saturated edges. - it = iter(path) - u = next(it) - these_orphans = [] - for v in it: - R_succ[u][v]["flow"] += flow - R_succ[v][u]["flow"] -= flow - if R_succ[u][v]["flow"] == R_succ[u][v]["capacity"]: - if v in source_tree: - source_tree[v] = None - these_orphans.append(v) - if u in target_tree: - target_tree[u] = None - these_orphans.append(u) - u = v - orphans.extend(sorted(these_orphans, key=dist.get)) - return flow - - def adopt(): - """Adoption stage. - - Reconstruct search trees by adopting or discarding orphans. - During augmentation stage some edges got saturated and thus - the source and target search trees broke down to forests, with - orphans as roots of some of its trees. We have to reconstruct - the search trees rooted to source and target before we can grow - them again. - """ - while orphans: - u = orphans.popleft() - if u in source_tree: - tree = source_tree - neighbors = R_pred - else: - tree = target_tree - neighbors = R_succ - nbrs = ((n, attr, dist[n]) for n, attr in neighbors[u].items() if n in tree) - for v, attr, d in sorted(nbrs, key=itemgetter(2)): - if attr["capacity"] - attr["flow"] > 0: - if _has_valid_root(v, tree): - tree[u] = v - dist[u] = dist[v] + 1 - timestamp[u] = time - break - else: - nbrs = ( - (n, attr, dist[n]) for n, attr in neighbors[u].items() if n in tree - ) - for v, attr, d in sorted(nbrs, key=itemgetter(2)): - if attr["capacity"] - attr["flow"] > 0: - if v not in active: - active.append(v) - if tree[v] == u: - tree[v] = None - orphans.appendleft(v) - if u in active: - active.remove(u) - del tree[u] - - def _has_valid_root(n, tree): - path = [] - v = n - while v is not None: - path.append(v) - if v in (s, t): - base_dist = 0 - break - elif timestamp[v] == time: - base_dist = dist[v] - break - v = tree[v] - else: - return False - length = len(path) - for i, u in enumerate(path, 1): - dist[u] = base_dist + length - i - timestamp[u] = time - return True - - def _is_closer(u, v): - return timestamp[v] <= timestamp[u] and dist[v] > dist[u] + 1 - - source_tree = {s: None} - target_tree = {t: None} - active = deque([s, t]) - orphans = deque() - flow_value = 0 - # data structures for the marking heuristic - time = 1 - timestamp = {s: time, t: time} - dist = {s: 0, t: 0} - while flow_value < cutoff: - # Growth stage - u, v = grow() - if u is None: - break - time += 1 - # Augmentation stage - flow_value += augment(u, v) - # Adoption stage - adopt() - - if flow_value * 2 > INF: - raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.") - - # Add source and target tree in a graph attribute. - # A partition that defines a minimum cut can be directly - # computed from the search trees as explained in the docstrings. - R.graph["trees"] = (source_tree, target_tree) - # Add the standard flow_value graph attribute. - R.graph["flow_value"] = flow_value - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/capacityscaling.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/capacityscaling.py deleted file mode 100644 index bf68565..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/capacityscaling.py +++ /dev/null @@ -1,407 +0,0 @@ -""" -Capacity scaling minimum cost flow algorithm. -""" - -__all__ = ["capacity_scaling"] - -from itertools import chain -from math import log - -import networkx as nx - -from ...utils import BinaryHeap, arbitrary_element, not_implemented_for - - -def _detect_unboundedness(R): - """Detect infinite-capacity negative cycles.""" - G = nx.DiGraph() - G.add_nodes_from(R) - - # Value simulating infinity. - inf = R.graph["inf"] - # True infinity. - f_inf = float("inf") - for u in R: - for v, e in R[u].items(): - # Compute the minimum weight of infinite-capacity (u, v) edges. - w = f_inf - for k, e in e.items(): - if e["capacity"] == inf: - w = min(w, e["weight"]) - if w != f_inf: - G.add_edge(u, v, weight=w) - - if nx.negative_edge_cycle(G): - raise nx.NetworkXUnbounded( - "Negative cost cycle of infinite capacity found. " - "Min cost flow may be unbounded below." - ) - - -@not_implemented_for("undirected") -def _build_residual_network(G, demand, capacity, weight): - """Build a residual network and initialize a zero flow.""" - if sum(G.nodes[u].get(demand, 0) for u in G) != 0: - raise nx.NetworkXUnfeasible("Sum of the demands should be 0.") - - R = nx.MultiDiGraph() - R.add_nodes_from( - (u, {"excess": -G.nodes[u].get(demand, 0), "potential": 0}) for u in G - ) - - inf = float("inf") - # Detect selfloops with infinite capacities and negative weights. - for u, v, e in nx.selfloop_edges(G, data=True): - if e.get(weight, 0) < 0 and e.get(capacity, inf) == inf: - raise nx.NetworkXUnbounded( - "Negative cost cycle of infinite capacity found. " - "Min cost flow may be unbounded below." - ) - - # Extract edges with positive capacities. Self loops excluded. - if G.is_multigraph(): - edge_list = [ - (u, v, k, e) - for u, v, k, e in G.edges(data=True, keys=True) - if u != v and e.get(capacity, inf) > 0 - ] - else: - edge_list = [ - (u, v, 0, e) - for u, v, e in G.edges(data=True) - if u != v and e.get(capacity, inf) > 0 - ] - # Simulate infinity with the larger of the sum of absolute node imbalances - # the sum of finite edge capacities or any positive value if both sums are - # zero. This allows the infinite-capacity edges to be distinguished for - # unboundedness detection and directly participate in residual capacity - # calculation. - inf = ( - max( - sum(abs(R.nodes[u]["excess"]) for u in R), - 2 - * sum( - e[capacity] - for u, v, k, e in edge_list - if capacity in e and e[capacity] != inf - ), - ) - or 1 - ) - for u, v, k, e in edge_list: - r = min(e.get(capacity, inf), inf) - w = e.get(weight, 0) - # Add both (u, v) and (v, u) into the residual network marked with the - # original key. (key[1] == True) indicates the (u, v) is in the - # original network. - R.add_edge(u, v, key=(k, True), capacity=r, weight=w, flow=0) - R.add_edge(v, u, key=(k, False), capacity=0, weight=-w, flow=0) - - # Record the value simulating infinity. - R.graph["inf"] = inf - - _detect_unboundedness(R) - - return R - - -def _build_flow_dict(G, R, capacity, weight): - """Build a flow dictionary from a residual network.""" - inf = float("inf") - flow_dict = {} - if G.is_multigraph(): - for u in G: - flow_dict[u] = {} - for v, es in G[u].items(): - flow_dict[u][v] = { - # Always saturate negative selfloops. - k: ( - 0 - if ( - u != v or e.get(capacity, inf) <= 0 or e.get(weight, 0) >= 0 - ) - else e[capacity] - ) - for k, e in es.items() - } - for v, es in R[u].items(): - if v in flow_dict[u]: - flow_dict[u][v].update( - (k[0], e["flow"]) for k, e in es.items() if e["flow"] > 0 - ) - else: - for u in G: - flow_dict[u] = { - # Always saturate negative selfloops. - v: ( - 0 - if (u != v or e.get(capacity, inf) <= 0 or e.get(weight, 0) >= 0) - else e[capacity] - ) - for v, e in G[u].items() - } - flow_dict[u].update( - (v, e["flow"]) - for v, es in R[u].items() - for e in es.values() - if e["flow"] > 0 - ) - return flow_dict - - -@nx._dispatchable( - node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} -) -def capacity_scaling( - G, demand="demand", capacity="capacity", weight="weight", heap=BinaryHeap -): - r"""Find a minimum cost flow satisfying all demands in digraph G. - - This is a capacity scaling successive shortest augmenting path algorithm. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph or MultiDiGraph on which a minimum cost flow satisfying all - demands is to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - heap : class - Type of heap to be used in the algorithm. It should be a subclass of - :class:`MinHeap` or implement a compatible interface. - - If a stock heap implementation is to be used, :class:`BinaryHeap` is - recommended over :class:`PairingHeap` for Python implementations without - optimized attribute accesses (e.g., CPython) despite a slower - asymptotic running time. For Python implementations with optimized - attribute accesses (e.g., PyPy), :class:`PairingHeap` provides better - performance. Default value: :class:`BinaryHeap`. - - Returns - ------- - flowCost : integer - Cost of a minimum cost flow satisfying all demands. - - flowDict : dictionary - If G is a digraph, a dict-of-dicts keyed by nodes such that - flowDict[u][v] is the flow on edge (u, v). - If G is a MultiDiGraph, a dict-of-dicts-of-dicts keyed by nodes - so that flowDict[u][v][key] is the flow on edge (u, v, key). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed, - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - Notes - ----- - This algorithm does not work if edge weights are floating-point numbers. - - See also - -------- - :meth:`network_simplex` - - Examples - -------- - A simple example of a min cost flow problem. - - >>> G = nx.DiGraph() - >>> G.add_node("a", demand=-5) - >>> G.add_node("d", demand=5) - >>> G.add_edge("a", "b", weight=3, capacity=4) - >>> G.add_edge("a", "c", weight=6, capacity=10) - >>> G.add_edge("b", "d", weight=1, capacity=9) - >>> G.add_edge("c", "d", weight=2, capacity=5) - >>> flowCost, flowDict = nx.capacity_scaling(G) - >>> flowCost - 24 - >>> flowDict - {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} - - It is possible to change the name of the attributes used for the - algorithm. - - >>> G = nx.DiGraph() - >>> G.add_node("p", spam=-4) - >>> G.add_node("q", spam=2) - >>> G.add_node("a", spam=-2) - >>> G.add_node("d", spam=-1) - >>> G.add_node("t", spam=2) - >>> G.add_node("w", spam=3) - >>> G.add_edge("p", "q", cost=7, vacancies=5) - >>> G.add_edge("p", "a", cost=1, vacancies=4) - >>> G.add_edge("q", "d", cost=2, vacancies=3) - >>> G.add_edge("t", "q", cost=1, vacancies=2) - >>> G.add_edge("a", "t", cost=2, vacancies=4) - >>> G.add_edge("d", "w", cost=3, vacancies=4) - >>> G.add_edge("t", "w", cost=4, vacancies=1) - >>> flowCost, flowDict = nx.capacity_scaling( - ... G, demand="spam", capacity="vacancies", weight="cost" - ... ) - >>> flowCost - 37 - >>> flowDict - {'p': {'q': 2, 'a': 2}, 'q': {'d': 1}, 'a': {'t': 4}, 'd': {'w': 2}, 't': {'q': 1, 'w': 1}, 'w': {}} - """ - R = _build_residual_network(G, demand, capacity, weight) - - inf = float("inf") - # Account cost of negative selfloops. - flow_cost = sum( - 0 - if e.get(capacity, inf) <= 0 or e.get(weight, 0) >= 0 - else e[capacity] * e[weight] - for u, v, e in nx.selfloop_edges(G, data=True) - ) - - # Determine the maximum edge capacity. - wmax = max(chain([-inf], (e["capacity"] for u, v, e in R.edges(data=True)))) - if wmax == -inf: - # Residual network has no edges. - return flow_cost, _build_flow_dict(G, R, capacity, weight) - - R_nodes = R.nodes - R_succ = R.succ - - delta = 2 ** int(log(wmax, 2)) - while delta >= 1: - # Saturate Δ-residual edges with negative reduced costs to achieve - # Δ-optimality. - for u in R: - p_u = R_nodes[u]["potential"] - for v, es in R_succ[u].items(): - for k, e in es.items(): - flow = e["capacity"] - e["flow"] - if e["weight"] - p_u + R_nodes[v]["potential"] < 0: - flow = e["capacity"] - e["flow"] - if flow >= delta: - e["flow"] += flow - R_succ[v][u][(k[0], not k[1])]["flow"] -= flow - R_nodes[u]["excess"] -= flow - R_nodes[v]["excess"] += flow - # Determine the Δ-active nodes. - S = set() - T = set() - S_add = S.add - S_remove = S.remove - T_add = T.add - T_remove = T.remove - for u in R: - excess = R_nodes[u]["excess"] - if excess >= delta: - S_add(u) - elif excess <= -delta: - T_add(u) - # Repeatedly augment flow from S to T along shortest paths until - # Δ-feasibility is achieved. - while S and T: - s = arbitrary_element(S) - t = None - # Search for a shortest path in terms of reduce costs from s to - # any t in T in the Δ-residual network. - d = {} - pred = {s: None} - h = heap() - h_insert = h.insert - h_get = h.get - h_insert(s, 0) - while h: - u, d_u = h.pop() - d[u] = d_u - if u in T: - # Path found. - t = u - break - p_u = R_nodes[u]["potential"] - for v, es in R_succ[u].items(): - if v in d: - continue - wmin = inf - # Find the minimum-weighted (u, v) Δ-residual edge. - for k, e in es.items(): - if e["capacity"] - e["flow"] >= delta: - w = e["weight"] - if w < wmin: - wmin = w - kmin = k - emin = e - if wmin == inf: - continue - # Update the distance label of v. - d_v = d_u + wmin - p_u + R_nodes[v]["potential"] - if h_insert(v, d_v): - pred[v] = (u, kmin, emin) - if t is not None: - # Augment Δ units of flow from s to t. - while u != s: - v = u - u, k, e = pred[v] - e["flow"] += delta - R_succ[v][u][(k[0], not k[1])]["flow"] -= delta - # Account node excess and deficit. - R_nodes[s]["excess"] -= delta - R_nodes[t]["excess"] += delta - if R_nodes[s]["excess"] < delta: - S_remove(s) - if R_nodes[t]["excess"] > -delta: - T_remove(t) - # Update node potentials. - d_t = d[t] - for u, d_u in d.items(): - R_nodes[u]["potential"] -= d_u - d_t - else: - # Path not found. - S_remove(s) - delta //= 2 - - if any(R.nodes[u]["excess"] != 0 for u in R): - raise nx.NetworkXUnfeasible("No flow satisfying all demands.") - - # Calculate the flow cost. - for u in R: - for v, es in R_succ[u].items(): - for e in es.values(): - flow = e["flow"] - if flow > 0: - flow_cost += flow * e["weight"] - - return flow_cost, _build_flow_dict(G, R, capacity, weight) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/dinitz_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/dinitz_alg.py deleted file mode 100644 index f369642..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/dinitz_alg.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -Dinitz' algorithm for maximum flow problems. -""" - -from collections import deque - -import networkx as nx -from networkx.algorithms.flow.utils import build_residual_network -from networkx.utils import pairwise - -__all__ = ["dinitz"] - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def dinitz(G, s, t, capacity="capacity", residual=None, value_only=False, cutoff=None): - """Find a maximum single-commodity flow using Dinitz' algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 m)$ for $n$ nodes and $m$ - edges [1]_. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> from networkx.algorithms.flow import dinitz - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - >>> R = dinitz(G, "x", "y") - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value - 3.0 - >>> flow_value == R.graph["flow_value"] - True - - References - ---------- - .. [1] Dinitz' Algorithm: The Original Version and Even's Version. - 2006. Yefim Dinitz. In Theoretical Computer Science. Lecture - Notes in Computer Science. Volume 3895. pp 218-240. - https://doi.org/10.1007/11685654_10 - - """ - R = dinitz_impl(G, s, t, capacity, residual, cutoff) - R.graph["algorithm"] = "dinitz" - nx._clear_cache(R) - return R - - -def dinitz_impl(G, s, t, capacity, residual, cutoff): - if s not in G: - raise nx.NetworkXError(f"node {str(s)} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {str(t)} not in graph") - if s == t: - raise nx.NetworkXError("source and sink are the same node") - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - for u in R: - for e in R[u].values(): - e["flow"] = 0 - - # Use an arbitrary high value as infinite. It is computed - # when building the residual network. - INF = R.graph["inf"] - - if cutoff is None: - cutoff = INF - - R_succ = R.succ - R_pred = R.pred - - def breath_first_search(): - parents = {} - vertex_dist = {s: 0} - queue = deque([(s, 0)]) - # Record all the potential edges of shortest augmenting paths - while queue: - if t in parents: - break - u, dist = queue.popleft() - for v, attr in R_succ[u].items(): - if attr["capacity"] - attr["flow"] > 0: - if v in parents: - if vertex_dist[v] == dist + 1: - parents[v].append(u) - else: - parents[v] = deque([u]) - vertex_dist[v] = dist + 1 - queue.append((v, dist + 1)) - return parents - - def depth_first_search(parents): - # DFS to find all the shortest augmenting paths - """Build a path using DFS starting from the sink""" - total_flow = 0 - u = t - # path also functions as a stack - path = [u] - # The loop ends with no augmenting path left in the layered graph - while True: - if len(parents[u]) > 0: - v = parents[u][0] - path.append(v) - else: - path.pop() - if len(path) == 0: - break - v = path[-1] - parents[v].popleft() - # Augment the flow along the path found - if v == s: - flow = INF - for u, v in pairwise(path): - flow = min(flow, R_pred[u][v]["capacity"] - R_pred[u][v]["flow"]) - for u, v in pairwise(reversed(path)): - R_pred[v][u]["flow"] += flow - R_pred[u][v]["flow"] -= flow - # Find the proper node to continue the search - if R_pred[v][u]["capacity"] - R_pred[v][u]["flow"] == 0: - parents[v].popleft() - while path[-1] != v: - path.pop() - total_flow += flow - v = path[-1] - u = v - return total_flow - - flow_value = 0 - while flow_value < cutoff: - parents = breath_first_search() - if t not in parents: - break - this_flow = depth_first_search(parents) - if this_flow * 2 > INF: - raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.") - flow_value += this_flow - - R.graph["flow_value"] = flow_value - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/edmondskarp.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/edmondskarp.py deleted file mode 100644 index 5006326..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/edmondskarp.py +++ /dev/null @@ -1,241 +0,0 @@ -""" -Edmonds-Karp algorithm for maximum flow problems. -""" - -import networkx as nx -from networkx.algorithms.flow.utils import build_residual_network - -__all__ = ["edmonds_karp"] - - -def edmonds_karp_core(R, s, t, cutoff): - """Implementation of the Edmonds-Karp algorithm.""" - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - inf = R.graph["inf"] - - def augment(path): - """Augment flow along a path from s to t.""" - # Determine the path residual capacity. - flow = inf - it = iter(path) - u = next(it) - for v in it: - attr = R_succ[u][v] - flow = min(flow, attr["capacity"] - attr["flow"]) - u = v - if flow * 2 > inf: - raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.") - # Augment flow along the path. - it = iter(path) - u = next(it) - for v in it: - R_succ[u][v]["flow"] += flow - R_succ[v][u]["flow"] -= flow - u = v - return flow - - def bidirectional_bfs(): - """Bidirectional breadth-first search for an augmenting path.""" - pred = {s: None} - q_s = [s] - succ = {t: None} - q_t = [t] - while True: - q = [] - if len(q_s) <= len(q_t): - for u in q_s: - for v, attr in R_succ[u].items(): - if v not in pred and attr["flow"] < attr["capacity"]: - pred[v] = u - if v in succ: - return v, pred, succ - q.append(v) - if not q: - return None, None, None - q_s = q - else: - for u in q_t: - for v, attr in R_pred[u].items(): - if v not in succ and attr["flow"] < attr["capacity"]: - succ[v] = u - if v in pred: - return v, pred, succ - q.append(v) - if not q: - return None, None, None - q_t = q - - # Look for shortest augmenting paths using breadth-first search. - flow_value = 0 - while flow_value < cutoff: - v, pred, succ = bidirectional_bfs() - if pred is None: - break - path = [v] - # Trace a path from s to v. - u = v - while u != s: - u = pred[u] - path.append(u) - path.reverse() - # Trace a path from v to t. - u = v - while u != t: - u = succ[u] - path.append(u) - flow_value += augment(path) - - return flow_value - - -def edmonds_karp_impl(G, s, t, capacity, residual, cutoff): - """Implementation of the Edmonds-Karp algorithm.""" - if s not in G: - raise nx.NetworkXError(f"node {str(s)} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {str(t)} not in graph") - if s == t: - raise nx.NetworkXError("source and sink are the same node") - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - for u in R: - for e in R[u].values(): - e["flow"] = 0 - - if cutoff is None: - cutoff = float("inf") - R.graph["flow_value"] = edmonds_karp_core(R, s, t, cutoff) - - return R - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def edmonds_karp( - G, s, t, capacity="capacity", residual=None, value_only=False, cutoff=None -): - """Find a maximum single-commodity flow using the Edmonds-Karp algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n m^2)$ for $n$ nodes and $m$ - edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> from networkx.algorithms.flow import edmonds_karp - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - >>> R = edmonds_karp(G, "x", "y") - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value - 3.0 - >>> flow_value == R.graph["flow_value"] - True - - """ - R = edmonds_karp_impl(G, s, t, capacity, residual, cutoff) - R.graph["algorithm"] = "edmonds_karp" - nx._clear_cache(R) - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/gomory_hu.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/gomory_hu.py deleted file mode 100644 index 69913da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/gomory_hu.py +++ /dev/null @@ -1,178 +0,0 @@ -""" -Gomory-Hu tree of undirected Graphs. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -from .edmondskarp import edmonds_karp -from .utils import build_residual_network - -default_flow_func = edmonds_karp - -__all__ = ["gomory_hu_tree"] - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def gomory_hu_tree(G, capacity="capacity", flow_func=None): - r"""Returns the Gomory-Hu tree of an undirected graph G. - - A Gomory-Hu tree of an undirected graph with capacities is a - weighted tree that represents the minimum s-t cuts for all s-t - pairs in the graph. - - It only requires `n-1` minimum cut computations instead of the - obvious `n(n-1)/2`. The tree represents all s-t cuts as the - minimum cut value among any pair of nodes is the minimum edge - weight in the shortest path between the two nodes in the - Gomory-Hu tree. - - The Gomory-Hu tree also has the property that removing the - edge with the minimum weight in the shortest path between - any two nodes leaves two connected components that form - a partition of the nodes in G that defines the minimum s-t - cut. - - See Examples section below for details. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - Function to perform the underlying flow computations. Default value - :func:`edmonds_karp`. This function performs better in sparse graphs - with right tailed degree distributions. - :func:`shortest_augmenting_path` will perform better in denser - graphs. - - Returns - ------- - Tree : NetworkX graph - A NetworkX graph representing the Gomory-Hu tree of the input graph. - - Raises - ------ - NetworkXNotImplemented - Raised if the input graph is directed. - - NetworkXError - Raised if the input graph is an empty Graph. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> nx.set_edge_attributes(G, 1, "capacity") - >>> T = nx.gomory_hu_tree(G) - >>> # The value of the minimum cut between any pair - ... # of nodes in G is the minimum edge weight in the - ... # shortest path between the two nodes in the - ... # Gomory-Hu tree. - ... def minimum_edge_weight_in_shortest_path(T, u, v): - ... path = nx.shortest_path(T, u, v, weight="weight") - ... return min((T[u][v]["weight"], (u, v)) for (u, v) in zip(path, path[1:])) - >>> u, v = 0, 33 - >>> cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> cut_value - 10 - >>> nx.minimum_cut_value(G, u, v) - 10 - >>> # The Gomory-Hu tree also has the property that removing the - ... # edge with the minimum weight in the shortest path between - ... # any two nodes leaves two connected components that form - ... # a partition of the nodes in G that defines the minimum s-t - ... # cut. - ... cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> T.remove_edge(*edge) - >>> U, V = list(nx.connected_components(T)) - >>> # Thus U and V form a partition that defines a minimum cut - ... # between u and v in G. You can compute the edge cut set, - ... # that is, the set of edges that if removed from G will - ... # disconnect u from v in G, with this information: - ... cutset = set() - >>> for x, nbrs in ((n, G[n]) for n in U): - ... cutset.update((x, y) for y in nbrs if y in V) - >>> # Because we have set the capacities of all edges to 1 - ... # the cutset contains ten edges - ... len(cutset) - 10 - >>> # You can use any maximum flow algorithm for the underlying - ... # flow computations using the argument flow_func - ... from networkx.algorithms import flow - >>> T = nx.gomory_hu_tree(G, flow_func=flow.boykov_kolmogorov) - >>> cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> cut_value - 10 - >>> nx.minimum_cut_value(G, u, v, flow_func=flow.boykov_kolmogorov) - 10 - - Notes - ----- - This implementation is based on Gusfield approach [1]_ to compute - Gomory-Hu trees, which does not require node contractions and has - the same computational complexity than the original method. - - See also - -------- - :func:`minimum_cut` - :func:`maximum_flow` - - References - ---------- - .. [1] Gusfield D: Very simple methods for all pairs network flow analysis. - SIAM J Comput 19(1):143-155, 1990. - - """ - if flow_func is None: - flow_func = default_flow_func - - if len(G) == 0: # empty graph - msg = "Empty Graph does not have a Gomory-Hu tree representation" - raise nx.NetworkXError(msg) - - # Start the tree as a star graph with an arbitrary node at the center - tree = {} - labels = {} - iter_nodes = iter(G) - root = next(iter_nodes) - for n in iter_nodes: - tree[n] = root - - # Reuse residual network - R = build_residual_network(G, capacity) - - # For all the leaves in the star graph tree (that is n-1 nodes). - for source in tree: - # Find neighbor in the tree - target = tree[source] - # compute minimum cut - cut_value, partition = nx.minimum_cut( - G, source, target, capacity=capacity, flow_func=flow_func, residual=R - ) - labels[(source, target)] = cut_value - # Update the tree - # Source will always be in partition[0] and target in partition[1] - for node in partition[0]: - if node != source and node in tree and tree[node] == target: - tree[node] = source - labels[node, source] = labels.get((node, target), cut_value) - # - if target != root and tree[target] in partition[0]: - labels[source, tree[target]] = labels[target, tree[target]] - labels[target, source] = cut_value - tree[source] = tree[target] - tree[target] = source - - # Build the tree - T = nx.Graph() - T.add_nodes_from(G) - T.add_weighted_edges_from(((u, v, labels[u, v]) for u, v in tree.items())) - return T diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/maxflow.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/maxflow.py deleted file mode 100644 index 7993d87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/maxflow.py +++ /dev/null @@ -1,607 +0,0 @@ -""" -Maximum flow (and minimum cut) algorithms on capacitated graphs. -""" - -import networkx as nx - -from .boykovkolmogorov import boykov_kolmogorov -from .dinitz_alg import dinitz -from .edmondskarp import edmonds_karp -from .preflowpush import preflow_push -from .shortestaugmentingpath import shortest_augmenting_path -from .utils import build_flow_dict - -# Define the default flow function for computing maximum flow. -default_flow_func = preflow_push - -__all__ = ["maximum_flow", "maximum_flow_value", "minimum_cut", "minimum_cut_value"] - - -@nx._dispatchable(graphs="flowG", edge_attrs={"capacity": float("inf")}) -def maximum_flow(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): - """Find a maximum single-commodity flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - flow_value : integer, float - Value of the maximum flow, i.e., net outflow from the source. - - flow_dict : dict - A dictionary containing the value of the flow that went through - each edge. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow_value` - :meth:`minimum_cut` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - - maximum_flow returns both the value of the maximum flow and a - dictionary with all flows. - - >>> flow_value, flow_dict = nx.maximum_flow(G, "x", "y") - >>> flow_value - 3.0 - >>> print(flow_dict["x"]["b"]) - 1.0 - - You can also use alternative algorithms for computing the - maximum flow by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> flow_value == nx.maximum_flow(G, "x", "y", flow_func=shortest_augmenting_path)[ - ... 0 - ... ] - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError( - "You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs." - ) - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=False, **kwargs) - flow_dict = build_flow_dict(flowG, R) - - return (R.graph["flow_value"], flow_dict) - - -@nx._dispatchable(graphs="flowG", edge_attrs={"capacity": float("inf")}) -def maximum_flow_value(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): - """Find the value of maximum single-commodity flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - flow_value : integer, float - Value of the maximum flow, i.e., net outflow from the source. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - - maximum_flow_value computes only the value of the - maximum flow: - - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value - 3.0 - - You can also use alternative algorithms for computing the - maximum flow by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> flow_value == nx.maximum_flow_value( - ... G, "x", "y", flow_func=shortest_augmenting_path - ... ) - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError( - "You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs." - ) - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - - return R.graph["flow_value"] - - -@nx._dispatchable(graphs="flowG", edge_attrs={"capacity": float("inf")}) -def minimum_cut(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): - """Compute the value and the node partition of a minimum (s, t)-cut. - - Use the max-flow min-cut theorem, i.e., the capacity of a minimum - capacity cut is equal to the flow value of a maximum flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - cut_value : integer, float - Value of the minimum cut. - - partition : pair of node sets - A partitioning of the nodes that defines a minimum cut. - - Raises - ------ - NetworkXUnbounded - If the graph has a path of infinite capacity, all cuts have - infinite capacity and the function raises a NetworkXError. - - See also - -------- - :meth:`maximum_flow` - :meth:`maximum_flow_value` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - - minimum_cut computes both the value of the - minimum cut and the node partition: - - >>> cut_value, partition = nx.minimum_cut(G, "x", "y") - >>> reachable, non_reachable = partition - - 'partition' here is a tuple with the two sets of nodes that define - the minimum cut. You can compute the cut set of edges that induce - the minimum cut as follows: - - >>> cutset = set() - >>> for u, nbrs in ((n, G[n]) for n in reachable): - ... cutset.update((u, v) for v in nbrs if v in non_reachable) - >>> print(sorted(cutset)) - [('c', 'y'), ('x', 'b')] - >>> cut_value == sum(G.edges[u, v]["capacity"] for (u, v) in cutset) - True - - You can also use alternative algorithms for computing the - minimum cut by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> cut_value == nx.minimum_cut(G, "x", "y", flow_func=shortest_augmenting_path)[0] - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError( - "You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs." - ) - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - if kwargs.get("cutoff") is not None and flow_func is preflow_push: - raise nx.NetworkXError("cutoff should not be specified.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - # Remove saturated edges from the residual network - cutset = [(u, v, d) for u, v, d in R.edges(data=True) if d["flow"] == d["capacity"]] - R.remove_edges_from(cutset) - - # Then, reachable and non reachable nodes from source in the - # residual network form the node partition that defines - # the minimum cut. - non_reachable = set(dict(nx.shortest_path_length(R, target=_t))) - partition = (set(flowG) - non_reachable, non_reachable) - # Finally add again cutset edges to the residual network to make - # sure that it is reusable. - R.add_edges_from(cutset) - return (R.graph["flow_value"], partition) - - -@nx._dispatchable(graphs="flowG", edge_attrs={"capacity": float("inf")}) -def minimum_cut_value(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): - """Compute the value of a minimum (s, t)-cut. - - Use the max-flow min-cut theorem, i.e., the capacity of a minimum - capacity cut is equal to the flow value of a maximum flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - cut_value : integer, float - Value of the minimum cut. - - Raises - ------ - NetworkXUnbounded - If the graph has a path of infinite capacity, all cuts have - infinite capacity and the function raises a NetworkXError. - - See also - -------- - :meth:`maximum_flow` - :meth:`maximum_flow_value` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - - minimum_cut_value computes only the value of the - minimum cut: - - >>> cut_value = nx.minimum_cut_value(G, "x", "y") - >>> cut_value - 3.0 - - You can also use alternative algorithms for computing the - minimum cut by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> cut_value == nx.minimum_cut_value( - ... G, "x", "y", flow_func=shortest_augmenting_path - ... ) - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError( - "You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs." - ) - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - if kwargs.get("cutoff") is not None and flow_func is preflow_push: - raise nx.NetworkXError("cutoff should not be specified.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - - return R.graph["flow_value"] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/mincost.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/mincost.py deleted file mode 100644 index 2f9390d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/mincost.py +++ /dev/null @@ -1,356 +0,0 @@ -""" -Minimum cost flow algorithms on directed connected graphs. -""" - -__all__ = ["min_cost_flow_cost", "min_cost_flow", "cost_of_flow", "max_flow_min_cost"] - -import networkx as nx - - -@nx._dispatchable( - node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} -) -def min_cost_flow_cost(G, demand="demand", capacity="capacity", weight="weight"): - r"""Find the cost of a minimum cost flow satisfying all demands in digraph G. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowCost : integer, float - Cost of a minimum cost flow satisfying all demands. - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - A simple example of a min cost flow problem. - - >>> G = nx.DiGraph() - >>> G.add_node("a", demand=-5) - >>> G.add_node("d", demand=5) - >>> G.add_edge("a", "b", weight=3, capacity=4) - >>> G.add_edge("a", "c", weight=6, capacity=10) - >>> G.add_edge("b", "d", weight=1, capacity=9) - >>> G.add_edge("c", "d", weight=2, capacity=5) - >>> flowCost = nx.min_cost_flow_cost(G) - >>> flowCost - 24 - """ - return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[0] - - -@nx._dispatchable( - node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} -) -def min_cost_flow(G, demand="demand", capacity="capacity", weight="weight"): - r"""Returns a minimum cost flow satisfying all demands in digraph G. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - A simple example of a min cost flow problem. - - >>> G = nx.DiGraph() - >>> G.add_node("a", demand=-5) - >>> G.add_node("d", demand=5) - >>> G.add_edge("a", "b", weight=3, capacity=4) - >>> G.add_edge("a", "c", weight=6, capacity=10) - >>> G.add_edge("b", "d", weight=1, capacity=9) - >>> G.add_edge("c", "d", weight=2, capacity=5) - >>> flowDict = nx.min_cost_flow(G) - >>> flowDict - {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} - """ - return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[1] - - -@nx._dispatchable(edge_attrs={"weight": 0}) -def cost_of_flow(G, flowDict, weight="weight"): - """Compute the cost of the flow given by flowDict on graph G. - - Note that this function does not check for the validity of the - flow flowDict. This function will fail if the graph G and the - flow don't have the same edge set. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Returns - ------- - cost : Integer, float - The total cost of the flow. This is given by the sum over all - edges of the product of the edge's flow and the edge's weight. - - See also - -------- - max_flow_min_cost, min_cost_flow, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_node("a", demand=-5) - >>> G.add_node("d", demand=5) - >>> G.add_edge("a", "b", weight=3, capacity=4) - >>> G.add_edge("a", "c", weight=6, capacity=10) - >>> G.add_edge("b", "d", weight=1, capacity=9) - >>> G.add_edge("c", "d", weight=2, capacity=5) - >>> flowDict = nx.min_cost_flow(G) - >>> flowDict - {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} - >>> nx.cost_of_flow(G, flowDict) - 24 - """ - return sum((flowDict[u][v] * d.get(weight, 0) for u, v, d in G.edges(data=True))) - - -@nx._dispatchable(edge_attrs={"capacity": float("inf"), "weight": 0}) -def max_flow_min_cost(G, s, t, capacity="capacity", weight="weight"): - """Returns a maximum (s, t)-flow of minimum cost. - - G is a digraph with edge costs and capacities. There is a source - node s and a sink node t. This function finds a maximum flow from - s to t whose total cost is minimized. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - s: node label - Source of the flow. - - t: node label - Destination of the flow. - - capacity: string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight: string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowDict: dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnbounded - This exception is raised if there is an infinite capacity path - from s to t in G. In this case there is no maximum flow. This - exception is also raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - is unbounded below. - - See also - -------- - cost_of_flow, min_cost_flow, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edges_from( - ... [ - ... (1, 2, {"capacity": 12, "weight": 4}), - ... (1, 3, {"capacity": 20, "weight": 6}), - ... (2, 3, {"capacity": 6, "weight": -3}), - ... (2, 6, {"capacity": 14, "weight": 1}), - ... (3, 4, {"weight": 9}), - ... (3, 5, {"capacity": 10, "weight": 5}), - ... (4, 2, {"capacity": 19, "weight": 13}), - ... (4, 5, {"capacity": 4, "weight": 0}), - ... (5, 7, {"capacity": 28, "weight": 2}), - ... (6, 5, {"capacity": 11, "weight": 1}), - ... (6, 7, {"weight": 8}), - ... (7, 4, {"capacity": 6, "weight": 6}), - ... ] - ... ) - >>> mincostFlow = nx.max_flow_min_cost(G, 1, 7) - >>> mincost = nx.cost_of_flow(G, mincostFlow) - >>> mincost - 373 - >>> from networkx.algorithms.flow import maximum_flow - >>> maxFlow = maximum_flow(G, 1, 7)[1] - >>> nx.cost_of_flow(G, maxFlow) >= mincost - True - >>> mincostFlowValue = sum((mincostFlow[u][7] for u in G.predecessors(7))) - sum( - ... (mincostFlow[7][v] for v in G.successors(7)) - ... ) - >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7) - True - - """ - maxFlow = nx.maximum_flow_value(G, s, t, capacity=capacity) - H = nx.DiGraph(G) - H.add_node(s, demand=-maxFlow) - H.add_node(t, demand=maxFlow) - return min_cost_flow(H, capacity=capacity, weight=weight) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/networksimplex.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/networksimplex.py deleted file mode 100644 index a9822d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/networksimplex.py +++ /dev/null @@ -1,666 +0,0 @@ -""" -Minimum cost flow algorithms on directed connected graphs. -""" - -__all__ = ["network_simplex"] - -from itertools import chain, islice, repeat -from math import ceil, sqrt - -import networkx as nx -from networkx.utils import not_implemented_for - - -class _DataEssentialsAndFunctions: - def __init__( - self, G, multigraph, demand="demand", capacity="capacity", weight="weight" - ): - # Number all nodes and edges and hereafter reference them using ONLY their numbers - self.node_list = list(G) # nodes - self.node_indices = {u: i for i, u in enumerate(self.node_list)} # node indices - self.node_demands = [ - G.nodes[u].get(demand, 0) for u in self.node_list - ] # node demands - - self.edge_sources = [] # edge sources - self.edge_targets = [] # edge targets - if multigraph: - self.edge_keys = [] # edge keys - self.edge_indices = {} # edge indices - self.edge_capacities = [] # edge capacities - self.edge_weights = [] # edge weights - - if not multigraph: - edges = G.edges(data=True) - else: - edges = G.edges(data=True, keys=True) - - inf = float("inf") - edges = (e for e in edges if e[0] != e[1] and e[-1].get(capacity, inf) != 0) - for i, e in enumerate(edges): - self.edge_sources.append(self.node_indices[e[0]]) - self.edge_targets.append(self.node_indices[e[1]]) - if multigraph: - self.edge_keys.append(e[2]) - self.edge_indices[e[:-1]] = i - self.edge_capacities.append(e[-1].get(capacity, inf)) - self.edge_weights.append(e[-1].get(weight, 0)) - - # spanning tree specific data to be initialized - - self.edge_count = None # number of edges - self.edge_flow = None # edge flows - self.node_potentials = None # node potentials - self.parent = None # parent nodes - self.parent_edge = None # edges to parents - self.subtree_size = None # subtree sizes - self.next_node_dft = None # next nodes in depth-first thread - self.prev_node_dft = None # previous nodes in depth-first thread - self.last_descendent_dft = None # last descendants in depth-first thread - self._spanning_tree_initialized = ( - False # False until initialize_spanning_tree() is called - ) - - def initialize_spanning_tree(self, n, faux_inf): - self.edge_count = len(self.edge_indices) # number of edges - self.edge_flow = list( - chain(repeat(0, self.edge_count), (abs(d) for d in self.node_demands)) - ) # edge flows - self.node_potentials = [ - faux_inf if d <= 0 else -faux_inf for d in self.node_demands - ] # node potentials - self.parent = list(chain(repeat(-1, n), [None])) # parent nodes - self.parent_edge = list( - range(self.edge_count, self.edge_count + n) - ) # edges to parents - self.subtree_size = list(chain(repeat(1, n), [n + 1])) # subtree sizes - self.next_node_dft = list( - chain(range(1, n), [-1, 0]) - ) # next nodes in depth-first thread - self.prev_node_dft = list(range(-1, n)) # previous nodes in depth-first thread - self.last_descendent_dft = list( - chain(range(n), [n - 1]) - ) # last descendants in depth-first thread - self._spanning_tree_initialized = True # True only if all the assignments pass - - def find_apex(self, p, q): - """ - Find the lowest common ancestor of nodes p and q in the spanning tree. - """ - size_p = self.subtree_size[p] - size_q = self.subtree_size[q] - while True: - while size_p < size_q: - p = self.parent[p] - size_p = self.subtree_size[p] - while size_p > size_q: - q = self.parent[q] - size_q = self.subtree_size[q] - if size_p == size_q: - if p != q: - p = self.parent[p] - size_p = self.subtree_size[p] - q = self.parent[q] - size_q = self.subtree_size[q] - else: - return p - - def trace_path(self, p, w): - """ - Returns the nodes and edges on the path from node p to its ancestor w. - """ - Wn = [p] - We = [] - while p != w: - We.append(self.parent_edge[p]) - p = self.parent[p] - Wn.append(p) - return Wn, We - - def find_cycle(self, i, p, q): - """ - Returns the nodes and edges on the cycle containing edge i == (p, q) - when the latter is added to the spanning tree. - - The cycle is oriented in the direction from p to q. - """ - w = self.find_apex(p, q) - Wn, We = self.trace_path(p, w) - Wn.reverse() - We.reverse() - if We != [i]: - We.append(i) - WnR, WeR = self.trace_path(q, w) - del WnR[-1] - Wn += WnR - We += WeR - return Wn, We - - def augment_flow(self, Wn, We, f): - """ - Augment f units of flow along a cycle represented by Wn and We. - """ - for i, p in zip(We, Wn): - if self.edge_sources[i] == p: - self.edge_flow[i] += f - else: - self.edge_flow[i] -= f - - def trace_subtree(self, p): - """ - Yield the nodes in the subtree rooted at a node p. - """ - yield p - l = self.last_descendent_dft[p] - while p != l: - p = self.next_node_dft[p] - yield p - - def remove_edge(self, s, t): - """ - Remove an edge (s, t) where parent[t] == s from the spanning tree. - """ - size_t = self.subtree_size[t] - prev_t = self.prev_node_dft[t] - last_t = self.last_descendent_dft[t] - next_last_t = self.next_node_dft[last_t] - # Remove (s, t). - self.parent[t] = None - self.parent_edge[t] = None - # Remove the subtree rooted at t from the depth-first thread. - self.next_node_dft[prev_t] = next_last_t - self.prev_node_dft[next_last_t] = prev_t - self.next_node_dft[last_t] = t - self.prev_node_dft[t] = last_t - # Update the subtree sizes and last descendants of the (old) ancestors - # of t. - while s is not None: - self.subtree_size[s] -= size_t - if self.last_descendent_dft[s] == last_t: - self.last_descendent_dft[s] = prev_t - s = self.parent[s] - - def make_root(self, q): - """ - Make a node q the root of its containing subtree. - """ - ancestors = [] - while q is not None: - ancestors.append(q) - q = self.parent[q] - ancestors.reverse() - for p, q in zip(ancestors, islice(ancestors, 1, None)): - size_p = self.subtree_size[p] - last_p = self.last_descendent_dft[p] - prev_q = self.prev_node_dft[q] - last_q = self.last_descendent_dft[q] - next_last_q = self.next_node_dft[last_q] - # Make p a child of q. - self.parent[p] = q - self.parent[q] = None - self.parent_edge[p] = self.parent_edge[q] - self.parent_edge[q] = None - self.subtree_size[p] = size_p - self.subtree_size[q] - self.subtree_size[q] = size_p - # Remove the subtree rooted at q from the depth-first thread. - self.next_node_dft[prev_q] = next_last_q - self.prev_node_dft[next_last_q] = prev_q - self.next_node_dft[last_q] = q - self.prev_node_dft[q] = last_q - if last_p == last_q: - self.last_descendent_dft[p] = prev_q - last_p = prev_q - # Add the remaining parts of the subtree rooted at p as a subtree - # of q in the depth-first thread. - self.prev_node_dft[p] = last_q - self.next_node_dft[last_q] = p - self.next_node_dft[last_p] = q - self.prev_node_dft[q] = last_p - self.last_descendent_dft[q] = last_p - - def add_edge(self, i, p, q): - """ - Add an edge (p, q) to the spanning tree where q is the root of a subtree. - """ - last_p = self.last_descendent_dft[p] - next_last_p = self.next_node_dft[last_p] - size_q = self.subtree_size[q] - last_q = self.last_descendent_dft[q] - # Make q a child of p. - self.parent[q] = p - self.parent_edge[q] = i - # Insert the subtree rooted at q into the depth-first thread. - self.next_node_dft[last_p] = q - self.prev_node_dft[q] = last_p - self.prev_node_dft[next_last_p] = last_q - self.next_node_dft[last_q] = next_last_p - # Update the subtree sizes and last descendants of the (new) ancestors - # of q. - while p is not None: - self.subtree_size[p] += size_q - if self.last_descendent_dft[p] == last_p: - self.last_descendent_dft[p] = last_q - p = self.parent[p] - - def update_potentials(self, i, p, q): - """ - Update the potentials of the nodes in the subtree rooted at a node - q connected to its parent p by an edge i. - """ - if q == self.edge_targets[i]: - d = self.node_potentials[p] - self.edge_weights[i] - self.node_potentials[q] - else: - d = self.node_potentials[p] + self.edge_weights[i] - self.node_potentials[q] - for q in self.trace_subtree(q): - self.node_potentials[q] += d - - def reduced_cost(self, i): - """Returns the reduced cost of an edge i.""" - c = ( - self.edge_weights[i] - - self.node_potentials[self.edge_sources[i]] - + self.node_potentials[self.edge_targets[i]] - ) - return c if self.edge_flow[i] == 0 else -c - - def find_entering_edges(self): - """Yield entering edges until none can be found.""" - if self.edge_count == 0: - return - - # Entering edges are found by combining Dantzig's rule and Bland's - # rule. The edges are cyclically grouped into blocks of size B. Within - # each block, Dantzig's rule is applied to find an entering edge. The - # blocks to search is determined following Bland's rule. - B = int(ceil(sqrt(self.edge_count))) # pivot block size - M = (self.edge_count + B - 1) // B # number of blocks needed to cover all edges - m = 0 # number of consecutive blocks without eligible - # entering edges - f = 0 # first edge in block - while m < M: - # Determine the next block of edges. - l = f + B - if l <= self.edge_count: - edges = range(f, l) - else: - l -= self.edge_count - edges = chain(range(f, self.edge_count), range(l)) - f = l - # Find the first edge with the lowest reduced cost. - i = min(edges, key=self.reduced_cost) - c = self.reduced_cost(i) - if c >= 0: - # No entering edge found in the current block. - m += 1 - else: - # Entering edge found. - if self.edge_flow[i] == 0: - p = self.edge_sources[i] - q = self.edge_targets[i] - else: - p = self.edge_targets[i] - q = self.edge_sources[i] - yield i, p, q - m = 0 - # All edges have nonnegative reduced costs. The current flow is - # optimal. - - def residual_capacity(self, i, p): - """Returns the residual capacity of an edge i in the direction away - from its endpoint p. - """ - return ( - self.edge_capacities[i] - self.edge_flow[i] - if self.edge_sources[i] == p - else self.edge_flow[i] - ) - - def find_leaving_edge(self, Wn, We): - """Returns the leaving edge in a cycle represented by Wn and We.""" - j, s = min( - zip(reversed(We), reversed(Wn)), - key=lambda i_p: self.residual_capacity(*i_p), - ) - t = self.edge_targets[j] if self.edge_sources[j] == s else self.edge_sources[j] - return j, s, t - - -@not_implemented_for("undirected") -@nx._dispatchable( - node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} -) -def network_simplex(G, demand="demand", capacity="capacity", weight="weight"): - r"""Find a minimum cost flow satisfying all demands in digraph G. - - This is a primal network simplex algorithm that uses the leaving - arc rule to prevent cycling. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowCost : integer, float - Cost of a minimum cost flow satisfying all demands. - - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow, min_cost_flow_cost - - Examples - -------- - A simple example of a min cost flow problem. - - >>> G = nx.DiGraph() - >>> G.add_node("a", demand=-5) - >>> G.add_node("d", demand=5) - >>> G.add_edge("a", "b", weight=3, capacity=4) - >>> G.add_edge("a", "c", weight=6, capacity=10) - >>> G.add_edge("b", "d", weight=1, capacity=9) - >>> G.add_edge("c", "d", weight=2, capacity=5) - >>> flowCost, flowDict = nx.network_simplex(G) - >>> flowCost - 24 - >>> flowDict - {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} - - The mincost flow algorithm can also be used to solve shortest path - problems. To find the shortest path between two nodes u and v, - give all edges an infinite capacity, give node u a demand of -1 and - node v a demand a 1. Then run the network simplex. The value of a - min cost flow will be the distance between u and v and edges - carrying positive flow will indicate the path. - - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... [ - ... ("s", "u", 10), - ... ("s", "x", 5), - ... ("u", "v", 1), - ... ("u", "x", 2), - ... ("v", "y", 1), - ... ("x", "u", 3), - ... ("x", "v", 5), - ... ("x", "y", 2), - ... ("y", "s", 7), - ... ("y", "v", 6), - ... ] - ... ) - >>> G.add_node("s", demand=-1) - >>> G.add_node("v", demand=1) - >>> flowCost, flowDict = nx.network_simplex(G) - >>> flowCost == nx.shortest_path_length(G, "s", "v", weight="weight") - True - >>> sorted([(u, v) for u in flowDict for v in flowDict[u] if flowDict[u][v] > 0]) - [('s', 'x'), ('u', 'v'), ('x', 'u')] - >>> nx.shortest_path(G, "s", "v", weight="weight") - ['s', 'x', 'u', 'v'] - - It is possible to change the name of the attributes used for the - algorithm. - - >>> G = nx.DiGraph() - >>> G.add_node("p", spam=-4) - >>> G.add_node("q", spam=2) - >>> G.add_node("a", spam=-2) - >>> G.add_node("d", spam=-1) - >>> G.add_node("t", spam=2) - >>> G.add_node("w", spam=3) - >>> G.add_edge("p", "q", cost=7, vacancies=5) - >>> G.add_edge("p", "a", cost=1, vacancies=4) - >>> G.add_edge("q", "d", cost=2, vacancies=3) - >>> G.add_edge("t", "q", cost=1, vacancies=2) - >>> G.add_edge("a", "t", cost=2, vacancies=4) - >>> G.add_edge("d", "w", cost=3, vacancies=4) - >>> G.add_edge("t", "w", cost=4, vacancies=1) - >>> flowCost, flowDict = nx.network_simplex( - ... G, demand="spam", capacity="vacancies", weight="cost" - ... ) - >>> flowCost - 37 - >>> flowDict - {'p': {'q': 2, 'a': 2}, 'q': {'d': 1}, 'a': {'t': 4}, 'd': {'w': 2}, 't': {'q': 1, 'w': 1}, 'w': {}} - - References - ---------- - .. [1] Z. Kiraly, P. Kovacs. - Efficient implementation of minimum-cost flow algorithms. - Acta Universitatis Sapientiae, Informatica 4(1):67--118. 2012. - .. [2] R. Barr, F. Glover, D. Klingman. - Enhancement of spanning tree labeling procedures for network - optimization. - INFOR 17(1):16--34. 1979. - """ - ########################################################################### - # Problem essentials extraction and sanity check - ########################################################################### - - if len(G) == 0: - raise nx.NetworkXError("graph has no nodes") - - multigraph = G.is_multigraph() - - # extracting data essential to problem - DEAF = _DataEssentialsAndFunctions( - G, multigraph, demand=demand, capacity=capacity, weight=weight - ) - - ########################################################################### - # Quick Error Detection - ########################################################################### - - inf = float("inf") - for u, d in zip(DEAF.node_list, DEAF.node_demands): - if abs(d) == inf: - raise nx.NetworkXError(f"node {u!r} has infinite demand") - for e, w in zip(DEAF.edge_indices, DEAF.edge_weights): - if abs(w) == inf: - raise nx.NetworkXError(f"edge {e!r} has infinite weight") - if not multigraph: - edges = nx.selfloop_edges(G, data=True) - else: - edges = nx.selfloop_edges(G, data=True, keys=True) - for e in edges: - if abs(e[-1].get(weight, 0)) == inf: - raise nx.NetworkXError(f"edge {e[:-1]!r} has infinite weight") - - ########################################################################### - # Quick Infeasibility Detection - ########################################################################### - - if sum(DEAF.node_demands) != 0: - raise nx.NetworkXUnfeasible("total node demand is not zero") - for e, c in zip(DEAF.edge_indices, DEAF.edge_capacities): - if c < 0: - raise nx.NetworkXUnfeasible(f"edge {e!r} has negative capacity") - if not multigraph: - edges = nx.selfloop_edges(G, data=True) - else: - edges = nx.selfloop_edges(G, data=True, keys=True) - for e in edges: - if e[-1].get(capacity, inf) < 0: - raise nx.NetworkXUnfeasible(f"edge {e[:-1]!r} has negative capacity") - - ########################################################################### - # Initialization - ########################################################################### - - # Add a dummy node -1 and connect all existing nodes to it with infinite- - # capacity dummy edges. Node -1 will serve as the root of the - # spanning tree of the network simplex method. The new edges will used to - # trivially satisfy the node demands and create an initial strongly - # feasible spanning tree. - for i, d in enumerate(DEAF.node_demands): - # Must be greater-than here. Zero-demand nodes must have - # edges pointing towards the root to ensure strong feasibility. - if d > 0: - DEAF.edge_sources.append(-1) - DEAF.edge_targets.append(i) - else: - DEAF.edge_sources.append(i) - DEAF.edge_targets.append(-1) - faux_inf = ( - 3 - * max( - chain( - [ - sum(c for c in DEAF.edge_capacities if c < inf), - sum(abs(w) for w in DEAF.edge_weights), - ], - (abs(d) for d in DEAF.node_demands), - ) - ) - or 1 - ) - - n = len(DEAF.node_list) # number of nodes - DEAF.edge_weights.extend(repeat(faux_inf, n)) - DEAF.edge_capacities.extend(repeat(faux_inf, n)) - - # Construct the initial spanning tree. - DEAF.initialize_spanning_tree(n, faux_inf) - - ########################################################################### - # Pivot loop - ########################################################################### - - for i, p, q in DEAF.find_entering_edges(): - Wn, We = DEAF.find_cycle(i, p, q) - j, s, t = DEAF.find_leaving_edge(Wn, We) - DEAF.augment_flow(Wn, We, DEAF.residual_capacity(j, s)) - # Do nothing more if the entering edge is the same as the leaving edge. - if i != j: - if DEAF.parent[t] != s: - # Ensure that s is the parent of t. - s, t = t, s - if We.index(i) > We.index(j): - # Ensure that q is in the subtree rooted at t. - p, q = q, p - DEAF.remove_edge(s, t) - DEAF.make_root(q) - DEAF.add_edge(i, p, q) - DEAF.update_potentials(i, p, q) - - ########################################################################### - # Infeasibility and unboundedness detection - ########################################################################### - - if any(DEAF.edge_flow[i] != 0 for i in range(-n, 0)): - raise nx.NetworkXUnfeasible("no flow satisfies all node demands") - - if any(DEAF.edge_flow[i] * 2 >= faux_inf for i in range(DEAF.edge_count)) or any( - e[-1].get(capacity, inf) == inf and e[-1].get(weight, 0) < 0 - for e in nx.selfloop_edges(G, data=True) - ): - raise nx.NetworkXUnbounded("negative cycle with infinite capacity found") - - ########################################################################### - # Flow cost calculation and flow dict construction - ########################################################################### - - del DEAF.edge_flow[DEAF.edge_count :] - flow_cost = sum(w * x for w, x in zip(DEAF.edge_weights, DEAF.edge_flow)) - flow_dict = {n: {} for n in DEAF.node_list} - - def add_entry(e): - """Add a flow dict entry.""" - d = flow_dict[e[0]] - for k in e[1:-2]: - try: - d = d[k] - except KeyError: - t = {} - d[k] = t - d = t - d[e[-2]] = e[-1] - - DEAF.edge_sources = ( - DEAF.node_list[s] for s in DEAF.edge_sources - ) # Use original nodes. - DEAF.edge_targets = ( - DEAF.node_list[t] for t in DEAF.edge_targets - ) # Use original nodes. - if not multigraph: - for e in zip(DEAF.edge_sources, DEAF.edge_targets, DEAF.edge_flow): - add_entry(e) - edges = G.edges(data=True) - else: - for e in zip( - DEAF.edge_sources, DEAF.edge_targets, DEAF.edge_keys, DEAF.edge_flow - ): - add_entry(e) - edges = G.edges(data=True, keys=True) - for e in edges: - if e[0] != e[1]: - if e[-1].get(capacity, inf) == 0: - add_entry(e[:-1] + (0,)) - else: - w = e[-1].get(weight, 0) - if w >= 0: - add_entry(e[:-1] + (0,)) - else: - c = e[-1][capacity] - flow_cost += w * c - add_entry(e[:-1] + (c,)) - - return flow_cost, flow_dict diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/preflowpush.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/preflowpush.py deleted file mode 100644 index 42cadc2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/preflowpush.py +++ /dev/null @@ -1,425 +0,0 @@ -""" -Highest-label preflow-push algorithm for maximum flow problems. -""" - -from collections import deque -from itertools import islice - -import networkx as nx - -from ...utils import arbitrary_element -from .utils import ( - CurrentEdge, - GlobalRelabelThreshold, - Level, - build_residual_network, - detect_unboundedness, -) - -__all__ = ["preflow_push"] - - -def preflow_push_impl(G, s, t, capacity, residual, global_relabel_freq, value_only): - """Implementation of the highest-label preflow-push algorithm.""" - if s not in G: - raise nx.NetworkXError(f"node {str(s)} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {str(t)} not in graph") - if s == t: - raise nx.NetworkXError("source and sink are the same node") - - if global_relabel_freq is None: - global_relabel_freq = 0 - if global_relabel_freq < 0: - raise nx.NetworkXError("global_relabel_freq must be nonnegative.") - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - detect_unboundedness(R, s, t) - - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - # Initialize/reset the residual network. - for u in R: - R_nodes[u]["excess"] = 0 - for e in R_succ[u].values(): - e["flow"] = 0 - - def reverse_bfs(src): - """Perform a reverse breadth-first search from src in the residual - network. - """ - heights = {src: 0} - q = deque([(src, 0)]) - while q: - u, height = q.popleft() - height += 1 - for v, attr in R_pred[u].items(): - if v not in heights and attr["flow"] < attr["capacity"]: - heights[v] = height - q.append((v, height)) - return heights - - # Initialize heights of the nodes. - heights = reverse_bfs(t) - - if s not in heights: - # t is not reachable from s in the residual network. The maximum flow - # must be zero. - R.graph["flow_value"] = 0 - return R - - n = len(R) - # max_height represents the height of the highest level below level n with - # at least one active node. - max_height = max(heights[u] for u in heights if u != s) - heights[s] = n - - grt = GlobalRelabelThreshold(n, R.size(), global_relabel_freq) - - # Initialize heights and 'current edge' data structures of the nodes. - for u in R: - R_nodes[u]["height"] = heights[u] if u in heights else n + 1 - R_nodes[u]["curr_edge"] = CurrentEdge(R_succ[u]) - - def push(u, v, flow): - """Push flow units of flow from u to v.""" - R_succ[u][v]["flow"] += flow - R_succ[v][u]["flow"] -= flow - R_nodes[u]["excess"] -= flow - R_nodes[v]["excess"] += flow - - # The maximum flow must be nonzero now. Initialize the preflow by - # saturating all edges emanating from s. - for u, attr in R_succ[s].items(): - flow = attr["capacity"] - if flow > 0: - push(s, u, flow) - - # Partition nodes into levels. - levels = [Level() for i in range(2 * n)] - for u in R: - if u != s and u != t: - level = levels[R_nodes[u]["height"]] - if R_nodes[u]["excess"] > 0: - level.active.add(u) - else: - level.inactive.add(u) - - def activate(v): - """Move a node from the inactive set to the active set of its level.""" - if v != s and v != t: - level = levels[R_nodes[v]["height"]] - if v in level.inactive: - level.inactive.remove(v) - level.active.add(v) - - def relabel(u): - """Relabel a node to create an admissible edge.""" - grt.add_work(len(R_succ[u])) - return ( - min( - R_nodes[v]["height"] - for v, attr in R_succ[u].items() - if attr["flow"] < attr["capacity"] - ) - + 1 - ) - - def discharge(u, is_phase1): - """Discharge a node until it becomes inactive or, during phase 1 (see - below), its height reaches at least n. The node is known to have the - largest height among active nodes. - """ - height = R_nodes[u]["height"] - curr_edge = R_nodes[u]["curr_edge"] - # next_height represents the next height to examine after discharging - # the current node. During phase 1, it is capped to below n. - next_height = height - levels[height].active.remove(u) - while True: - v, attr = curr_edge.get() - if height == R_nodes[v]["height"] + 1 and attr["flow"] < attr["capacity"]: - flow = min(R_nodes[u]["excess"], attr["capacity"] - attr["flow"]) - push(u, v, flow) - activate(v) - if R_nodes[u]["excess"] == 0: - # The node has become inactive. - levels[height].inactive.add(u) - break - try: - curr_edge.move_to_next() - except StopIteration: - # We have run off the end of the adjacency list, and there can - # be no more admissible edges. Relabel the node to create one. - height = relabel(u) - if is_phase1 and height >= n - 1: - # Although the node is still active, with a height at least - # n - 1, it is now known to be on the s side of the minimum - # s-t cut. Stop processing it until phase 2. - levels[height].active.add(u) - break - # The first relabel operation after global relabeling may not - # increase the height of the node since the 'current edge' data - # structure is not rewound. Use height instead of (height - 1) - # in case other active nodes at the same level are missed. - next_height = height - R_nodes[u]["height"] = height - return next_height - - def gap_heuristic(height): - """Apply the gap heuristic.""" - # Move all nodes at levels (height + 1) to max_height to level n + 1. - for level in islice(levels, height + 1, max_height + 1): - for u in level.active: - R_nodes[u]["height"] = n + 1 - for u in level.inactive: - R_nodes[u]["height"] = n + 1 - levels[n + 1].active.update(level.active) - level.active.clear() - levels[n + 1].inactive.update(level.inactive) - level.inactive.clear() - - def global_relabel(from_sink): - """Apply the global relabeling heuristic.""" - src = t if from_sink else s - heights = reverse_bfs(src) - if not from_sink: - # s must be reachable from t. Remove t explicitly. - del heights[t] - max_height = max(heights.values()) - if from_sink: - # Also mark nodes from which t is unreachable for relabeling. This - # serves the same purpose as the gap heuristic. - for u in R: - if u not in heights and R_nodes[u]["height"] < n: - heights[u] = n + 1 - else: - # Shift the computed heights because the height of s is n. - for u in heights: - heights[u] += n - max_height += n - del heights[src] - for u, new_height in heights.items(): - old_height = R_nodes[u]["height"] - if new_height != old_height: - if u in levels[old_height].active: - levels[old_height].active.remove(u) - levels[new_height].active.add(u) - else: - levels[old_height].inactive.remove(u) - levels[new_height].inactive.add(u) - R_nodes[u]["height"] = new_height - return max_height - - # Phase 1: Find the maximum preflow by pushing as much flow as possible to - # t. - - height = max_height - while height > 0: - # Discharge active nodes in the current level. - while True: - level = levels[height] - if not level.active: - # All active nodes in the current level have been discharged. - # Move to the next lower level. - height -= 1 - break - # Record the old height and level for the gap heuristic. - old_height = height - old_level = level - u = arbitrary_element(level.active) - height = discharge(u, True) - if grt.is_reached(): - # Global relabeling heuristic: Recompute the exact heights of - # all nodes. - height = global_relabel(True) - max_height = height - grt.clear_work() - elif not old_level.active and not old_level.inactive: - # Gap heuristic: If the level at old_height is empty (a 'gap'), - # a minimum cut has been identified. All nodes with heights - # above old_height can have their heights set to n + 1 and not - # be further processed before a maximum preflow is found. - gap_heuristic(old_height) - height = old_height - 1 - max_height = height - else: - # Update the height of the highest level with at least one - # active node. - max_height = max(max_height, height) - - # A maximum preflow has been found. The excess at t is the maximum flow - # value. - if value_only: - R.graph["flow_value"] = R_nodes[t]["excess"] - return R - - # Phase 2: Convert the maximum preflow into a maximum flow by returning the - # excess to s. - - # Relabel all nodes so that they have accurate heights. - height = global_relabel(False) - grt.clear_work() - - # Continue to discharge the active nodes. - while height > n: - # Discharge active nodes in the current level. - while True: - level = levels[height] - if not level.active: - # All active nodes in the current level have been discharged. - # Move to the next lower level. - height -= 1 - break - u = arbitrary_element(level.active) - height = discharge(u, False) - if grt.is_reached(): - # Global relabeling heuristic. - height = global_relabel(False) - grt.clear_work() - - R.graph["flow_value"] = R_nodes[t]["excess"] - return R - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def preflow_push( - G, s, t, capacity="capacity", residual=None, global_relabel_freq=1, value_only=False -): - r"""Find a maximum single-commodity flow using the highest-label - preflow-push algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 \sqrt{m})$ for $n$ nodes and - $m$ edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - global_relabel_freq : integer, float - Relative frequency of applying the global relabeling heuristic to speed - up the algorithm. If it is None, the heuristic is disabled. Default - value: 1. - - value_only : bool - If False, compute a maximum flow; otherwise, compute a maximum preflow - which is enough for computing the maximum flow value. Default value: - False. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. For each node :samp:`u` in :samp:`R`, - :samp:`R.nodes[u]['excess']` represents the difference between flow into - :samp:`u` and flow out of :samp:`u`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> from networkx.algorithms.flow import preflow_push - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - >>> R = preflow_push(G, "x", "y") - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value == R.graph["flow_value"] - True - >>> # preflow_push also stores the maximum flow value - >>> # in the excess attribute of the sink node t - >>> flow_value == R.nodes["y"]["excess"] - True - >>> # For some problems, you might only want to compute a - >>> # maximum preflow. - >>> R = preflow_push(G, "x", "y", value_only=True) - >>> flow_value == R.graph["flow_value"] - True - >>> flow_value == R.nodes["y"]["excess"] - True - - """ - R = preflow_push_impl(G, s, t, capacity, residual, global_relabel_freq, value_only) - R.graph["algorithm"] = "preflow_push" - nx._clear_cache(R) - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/shortestaugmentingpath.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/shortestaugmentingpath.py deleted file mode 100644 index 9f1193f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/shortestaugmentingpath.py +++ /dev/null @@ -1,300 +0,0 @@ -""" -Shortest augmenting path algorithm for maximum flow problems. -""" - -from collections import deque - -import networkx as nx - -from .edmondskarp import edmonds_karp_core -from .utils import CurrentEdge, build_residual_network - -__all__ = ["shortest_augmenting_path"] - - -def shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, cutoff): - """Implementation of the shortest augmenting path algorithm.""" - if s not in G: - raise nx.NetworkXError(f"node {str(s)} not in graph") - if t not in G: - raise nx.NetworkXError(f"node {str(t)} not in graph") - if s == t: - raise nx.NetworkXError("source and sink are the same node") - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - # Initialize/reset the residual network. - for u in R: - for e in R_succ[u].values(): - e["flow"] = 0 - - # Initialize heights of the nodes. - heights = {t: 0} - q = deque([(t, 0)]) - while q: - u, height = q.popleft() - height += 1 - for v, attr in R_pred[u].items(): - if v not in heights and attr["flow"] < attr["capacity"]: - heights[v] = height - q.append((v, height)) - - if s not in heights: - # t is not reachable from s in the residual network. The maximum flow - # must be zero. - R.graph["flow_value"] = 0 - return R - - n = len(G) - m = R.size() / 2 - - # Initialize heights and 'current edge' data structures of the nodes. - for u in R: - R_nodes[u]["height"] = heights[u] if u in heights else n - R_nodes[u]["curr_edge"] = CurrentEdge(R_succ[u]) - - # Initialize counts of nodes in each level. - counts = [0] * (2 * n - 1) - for u in R: - counts[R_nodes[u]["height"]] += 1 - - inf = R.graph["inf"] - - def augment(path): - """Augment flow along a path from s to t.""" - # Determine the path residual capacity. - flow = inf - it = iter(path) - u = next(it) - for v in it: - attr = R_succ[u][v] - flow = min(flow, attr["capacity"] - attr["flow"]) - u = v - if flow * 2 > inf: - raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.") - # Augment flow along the path. - it = iter(path) - u = next(it) - for v in it: - R_succ[u][v]["flow"] += flow - R_succ[v][u]["flow"] -= flow - u = v - return flow - - def relabel(u): - """Relabel a node to create an admissible edge.""" - height = n - 1 - for v, attr in R_succ[u].items(): - if attr["flow"] < attr["capacity"]: - height = min(height, R_nodes[v]["height"]) - return height + 1 - - if cutoff is None: - cutoff = float("inf") - - # Phase 1: Look for shortest augmenting paths using depth-first search. - - flow_value = 0 - path = [s] - u = s - d = n if not two_phase else int(min(m**0.5, 2 * n ** (2.0 / 3))) - done = R_nodes[s]["height"] >= d - while not done: - height = R_nodes[u]["height"] - curr_edge = R_nodes[u]["curr_edge"] - # Depth-first search for the next node on the path to t. - while True: - v, attr = curr_edge.get() - if height == R_nodes[v]["height"] + 1 and attr["flow"] < attr["capacity"]: - # Advance to the next node following an admissible edge. - path.append(v) - u = v - break - try: - curr_edge.move_to_next() - except StopIteration: - counts[height] -= 1 - if counts[height] == 0: - # Gap heuristic: If relabeling causes a level to become - # empty, a minimum cut has been identified. The algorithm - # can now be terminated. - R.graph["flow_value"] = flow_value - return R - height = relabel(u) - if u == s and height >= d: - if not two_phase: - # t is disconnected from s in the residual network. No - # more augmenting paths exist. - R.graph["flow_value"] = flow_value - return R - else: - # t is at least d steps away from s. End of phase 1. - done = True - break - counts[height] += 1 - R_nodes[u]["height"] = height - if u != s: - # After relabeling, the last edge on the path is no longer - # admissible. Retreat one step to look for an alternative. - path.pop() - u = path[-1] - break - if u == t: - # t is reached. Augment flow along the path and reset it for a new - # depth-first search. - flow_value += augment(path) - if flow_value >= cutoff: - R.graph["flow_value"] = flow_value - return R - path = [s] - u = s - - # Phase 2: Look for shortest augmenting paths using breadth-first search. - flow_value += edmonds_karp_core(R, s, t, cutoff - flow_value) - - R.graph["flow_value"] = flow_value - return R - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def shortest_augmenting_path( - G, - s, - t, - capacity="capacity", - residual=None, - value_only=False, - two_phase=False, - cutoff=None, -): - r"""Find a maximum single-commodity flow using the shortest augmenting path - algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 m)$ for $n$ nodes and $m$ - edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - two_phase : bool - If True, a two-phase variant is used. The two-phase variant improves - the running time on unit-capacity networks from $O(nm)$ to - $O(\min(n^{2/3}, m^{1/2}) m)$. Default value: False. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`preflow_push` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> from networkx.algorithms.flow import shortest_augmenting_path - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge("x", "a", capacity=3.0) - >>> G.add_edge("x", "b", capacity=1.0) - >>> G.add_edge("a", "c", capacity=3.0) - >>> G.add_edge("b", "c", capacity=5.0) - >>> G.add_edge("b", "d", capacity=4.0) - >>> G.add_edge("d", "e", capacity=2.0) - >>> G.add_edge("c", "y", capacity=2.0) - >>> G.add_edge("e", "y", capacity=3.0) - >>> R = shortest_augmenting_path(G, "x", "y") - >>> flow_value = nx.maximum_flow_value(G, "x", "y") - >>> flow_value - 3.0 - >>> flow_value == R.graph["flow_value"] - True - - """ - R = shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, cutoff) - R.graph["algorithm"] = "shortest_augmenting_path" - nx._clear_cache(R) - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2 deleted file mode 100644 index 5e9291e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf8f81ceb5eaaee1621aa60b892d83e596a6173f6f6517359b679ff3daa1b0f8 -size 44623 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2 deleted file mode 100644 index 356e5de..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f79f0e90fa4c51ec79165f15963e1ed89477576e06bcaa67ae622c260411931 -size 42248 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 deleted file mode 100644 index 9351606..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b17e66cdeda8edb8d1dec72626c77f1f65dd4675e3f76dc2fc4fd84aa038e30 -size 18972 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py deleted file mode 100644 index 1649ec8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py +++ /dev/null @@ -1,128 +0,0 @@ -from itertools import combinations - -import pytest - -import networkx as nx -from networkx.algorithms.flow import ( - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -) - -flow_funcs = [ - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -] - - -class TestGomoryHuTree: - def minimum_edge_weight(self, T, u, v): - path = nx.shortest_path(T, u, v, weight="weight") - return min((T[u][v]["weight"], (u, v)) for (u, v) in zip(path, path[1:])) - - def compute_cutset(self, G, T_orig, edge): - T = T_orig.copy() - T.remove_edge(*edge) - U, V = list(nx.connected_components(T)) - cutset = set() - for x, nbrs in ((n, G[n]) for n in U): - cutset.update((x, y) for y in nbrs if y in V) - return cutset - - def test_default_flow_function_karate_club_graph(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, "capacity") - T = nx.gomory_hu_tree(G) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v) == cut_value - - def test_karate_club_graph(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, "capacity") - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v) == cut_value - - def test_davis_southern_women_graph(self): - G = nx.davis_southern_women_graph() - nx.set_edge_attributes(G, 1, "capacity") - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v) == cut_value - - def test_florentine_families_graph(self): - G = nx.florentine_families_graph() - nx.set_edge_attributes(G, 1, "capacity") - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v) == cut_value - - @pytest.mark.slow - def test_les_miserables_graph_cutset(self): - G = nx.les_miserables_graph() - nx.set_edge_attributes(G, 1, "capacity") - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v) == cut_value - - def test_karate_club_graph_cutset(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, "capacity") - T = nx.gomory_hu_tree(G) - assert nx.is_tree(T) - u, v = 0, 33 - cut_value, edge = self.minimum_edge_weight(T, u, v) - cutset = self.compute_cutset(G, T, edge) - assert cut_value == len(cutset) - - def test_wikipedia_example(self): - # Example from https://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree - G = nx.Graph() - G.add_weighted_edges_from( - ( - (0, 1, 1), - (0, 2, 7), - (1, 2, 1), - (1, 3, 3), - (1, 4, 2), - (2, 4, 4), - (3, 4, 1), - (3, 5, 6), - (4, 5, 2), - ) - ) - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, capacity="weight", flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert nx.minimum_cut_value(G, u, v, capacity="weight") == cut_value - - def test_directed_raises(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - T = nx.gomory_hu_tree(G) - - def test_empty_raises(self): - with pytest.raises(nx.NetworkXError): - G = nx.empty_graph() - T = nx.gomory_hu_tree(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow.py deleted file mode 100644 index d7305a7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow.py +++ /dev/null @@ -1,573 +0,0 @@ -"""Maximum flow algorithms test suite.""" - -import pytest - -import networkx as nx -from networkx.algorithms.flow import ( - boykov_kolmogorov, - build_flow_dict, - build_residual_network, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -) - -flow_funcs = { - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -} - -max_min_funcs = {nx.maximum_flow, nx.minimum_cut} -flow_value_funcs = {nx.maximum_flow_value, nx.minimum_cut_value} -interface_funcs = max_min_funcs | flow_value_funcs -all_funcs = flow_funcs | interface_funcs - - -def compute_cutset(G, partition): - reachable, non_reachable = partition - cutset = set() - for u, nbrs in ((n, G[n]) for n in reachable): - cutset.update((u, v) for v in nbrs if v in non_reachable) - return cutset - - -def validate_flows(G, s, t, flowDict, solnValue, capacity, flow_func): - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert set(G) == set(flowDict), errmsg - for u in G: - assert set(G[u]) == set(flowDict[u]), errmsg - excess = {u: 0 for u in flowDict} - for u in flowDict: - for v, flow in flowDict[u].items(): - if capacity in G[u][v]: - assert flow <= G[u][v][capacity] - assert flow >= 0, errmsg - excess[u] -= flow - excess[v] += flow - for u, exc in excess.items(): - if u == s: - assert exc == -solnValue, errmsg - elif u == t: - assert exc == solnValue, errmsg - else: - assert exc == 0, errmsg - - -def validate_cuts(G, s, t, solnValue, partition, capacity, flow_func): - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert all(n in G for n in partition[0]), errmsg - assert all(n in G for n in partition[1]), errmsg - cutset = compute_cutset(G, partition) - assert all(G.has_edge(u, v) for (u, v) in cutset), errmsg - assert solnValue == sum(G[u][v][capacity] for (u, v) in cutset), errmsg - H = G.copy() - H.remove_edges_from(cutset) - if not G.is_directed(): - assert not nx.is_connected(H), errmsg - else: - assert not nx.is_strongly_connected(H), errmsg - - -def compare_flows_and_cuts(G, s, t, solnValue, capacity="capacity"): - for flow_func in flow_funcs: - errmsg = f"Assertion failed in function: {flow_func.__name__}" - R = flow_func(G, s, t, capacity) - # Test both legacy and new implementations. - flow_value = R.graph["flow_value"] - flow_dict = build_flow_dict(G, R) - assert flow_value == solnValue, errmsg - validate_flows(G, s, t, flow_dict, solnValue, capacity, flow_func) - # Minimum cut - cut_value, partition = nx.minimum_cut( - G, s, t, capacity=capacity, flow_func=flow_func - ) - validate_cuts(G, s, t, solnValue, partition, capacity, flow_func) - - -class TestMaxflowMinCutCommon: - def test_graph1(self): - # Trivial undirected graph - G = nx.Graph() - G.add_edge(1, 2, capacity=1.0) - - # solution flows - # {1: {2: 1.0}, 2: {1: 1.0}} - - compare_flows_and_cuts(G, 1, 2, 1.0) - - def test_graph2(self): - # A more complex undirected graph - # adapted from https://web.archive.org/web/20220815055650/https://www.topcoder.com/thrive/articles/Maximum%20Flow:%20Part%20One - G = nx.Graph() - G.add_edge("x", "a", capacity=3.0) - G.add_edge("x", "b", capacity=1.0) - G.add_edge("a", "c", capacity=3.0) - G.add_edge("b", "c", capacity=5.0) - G.add_edge("b", "d", capacity=4.0) - G.add_edge("d", "e", capacity=2.0) - G.add_edge("c", "y", capacity=2.0) - G.add_edge("e", "y", capacity=3.0) - - # H - # { - # "x": {"a": 3, "b": 1}, - # "a": {"c": 3, "x": 3}, - # "b": {"c": 1, "d": 2, "x": 1}, - # "c": {"a": 3, "b": 1, "y": 2}, - # "d": {"b": 2, "e": 2}, - # "e": {"d": 2, "y": 2}, - # "y": {"c": 2, "e": 2}, - # } - - compare_flows_and_cuts(G, "x", "y", 4.0) - - def test_digraph1(self): - # The classic directed graph example - G = nx.DiGraph() - G.add_edge("a", "b", capacity=1000.0) - G.add_edge("a", "c", capacity=1000.0) - G.add_edge("b", "c", capacity=1.0) - G.add_edge("b", "d", capacity=1000.0) - G.add_edge("c", "d", capacity=1000.0) - - # H - # { - # "a": {"b": 1000.0, "c": 1000.0}, - # "b": {"c": 0, "d": 1000.0}, - # "c": {"d": 1000.0}, - # "d": {}, - # } - - compare_flows_and_cuts(G, "a", "d", 2000.0) - - def test_digraph2(self): - # An example in which some edges end up with zero flow. - G = nx.DiGraph() - G.add_edge("s", "b", capacity=2) - G.add_edge("s", "c", capacity=1) - G.add_edge("c", "d", capacity=1) - G.add_edge("d", "a", capacity=1) - G.add_edge("b", "a", capacity=2) - G.add_edge("a", "t", capacity=2) - - # H - # { - # "s": {"b": 2, "c": 0}, - # "c": {"d": 0}, - # "d": {"a": 0}, - # "b": {"a": 2}, - # "a": {"t": 2}, - # "t": {}, - # } - - compare_flows_and_cuts(G, "s", "t", 2) - - def test_digraph3(self): - # A directed graph example from Cormen et al. - G = nx.DiGraph() - G.add_edge("s", "v1", capacity=16.0) - G.add_edge("s", "v2", capacity=13.0) - G.add_edge("v1", "v2", capacity=10.0) - G.add_edge("v2", "v1", capacity=4.0) - G.add_edge("v1", "v3", capacity=12.0) - G.add_edge("v3", "v2", capacity=9.0) - G.add_edge("v2", "v4", capacity=14.0) - G.add_edge("v4", "v3", capacity=7.0) - G.add_edge("v3", "t", capacity=20.0) - G.add_edge("v4", "t", capacity=4.0) - - # H - # { - # "s": {"v1": 12.0, "v2": 11.0}, - # "v2": {"v1": 0, "v4": 11.0}, - # "v1": {"v2": 0, "v3": 12.0}, - # "v3": {"v2": 0, "t": 19.0}, - # "v4": {"v3": 7.0, "t": 4.0}, - # "t": {}, - # } - - compare_flows_and_cuts(G, "s", "t", 23.0) - - def test_digraph4(self): - # A more complex directed graph - # from https://web.archive.org/web/20220815055650/https://www.topcoder.com/thrive/articles/Maximum%20Flow:%20Part%20One - G = nx.DiGraph() - G.add_edge("x", "a", capacity=3.0) - G.add_edge("x", "b", capacity=1.0) - G.add_edge("a", "c", capacity=3.0) - G.add_edge("b", "c", capacity=5.0) - G.add_edge("b", "d", capacity=4.0) - G.add_edge("d", "e", capacity=2.0) - G.add_edge("c", "y", capacity=2.0) - G.add_edge("e", "y", capacity=3.0) - - # H - # { - # "x": {"a": 2.0, "b": 1.0}, - # "a": {"c": 2.0}, - # "b": {"c": 0, "d": 1.0}, - # "c": {"y": 2.0}, - # "d": {"e": 1.0}, - # "e": {"y": 1.0}, - # "y": {}, - # } - - compare_flows_and_cuts(G, "x", "y", 3.0) - - def test_wikipedia_dinitz_example(self): - # Nice example from https://en.wikipedia.org/wiki/Dinic's_algorithm - G = nx.DiGraph() - G.add_edge("s", 1, capacity=10) - G.add_edge("s", 2, capacity=10) - G.add_edge(1, 3, capacity=4) - G.add_edge(1, 4, capacity=8) - G.add_edge(1, 2, capacity=2) - G.add_edge(2, 4, capacity=9) - G.add_edge(3, "t", capacity=10) - G.add_edge(4, 3, capacity=6) - G.add_edge(4, "t", capacity=10) - - # solution flows - # { - # 1: {2: 0, 3: 4, 4: 6}, - # 2: {4: 9}, - # 3: {"t": 9}, - # 4: {3: 5, "t": 10}, - # "s": {1: 10, 2: 9}, - # "t": {}, - # } - - compare_flows_and_cuts(G, "s", "t", 19) - - def test_optional_capacity(self): - # Test optional capacity parameter. - G = nx.DiGraph() - G.add_edge("x", "a", spam=3.0) - G.add_edge("x", "b", spam=1.0) - G.add_edge("a", "c", spam=3.0) - G.add_edge("b", "c", spam=5.0) - G.add_edge("b", "d", spam=4.0) - G.add_edge("d", "e", spam=2.0) - G.add_edge("c", "y", spam=2.0) - G.add_edge("e", "y", spam=3.0) - - # solution flows - # { - # "x": {"a": 2.0, "b": 1.0}, - # "a": {"c": 2.0}, - # "b": {"c": 0, "d": 1.0}, - # "c": {"y": 2.0}, - # "d": {"e": 1.0}, - # "e": {"y": 1.0}, - # "y": {}, - # } - solnValue = 3.0 - s = "x" - t = "y" - - compare_flows_and_cuts(G, s, t, solnValue, capacity="spam") - - def test_digraph_infcap_edges(self): - # DiGraph with infinite capacity edges - G = nx.DiGraph() - G.add_edge("s", "a") - G.add_edge("s", "b", capacity=30) - G.add_edge("a", "c", capacity=25) - G.add_edge("b", "c", capacity=12) - G.add_edge("a", "t", capacity=60) - G.add_edge("c", "t") - - # H - # { - # "s": {"a": 85, "b": 12}, - # "a": {"c": 25, "t": 60}, - # "b": {"c": 12}, - # "c": {"t": 37}, - # "t": {}, - # } - - compare_flows_and_cuts(G, "s", "t", 97) - - # DiGraph with infinite capacity digon - G = nx.DiGraph() - G.add_edge("s", "a", capacity=85) - G.add_edge("s", "b", capacity=30) - G.add_edge("a", "c") - G.add_edge("c", "a") - G.add_edge("b", "c", capacity=12) - G.add_edge("a", "t", capacity=60) - G.add_edge("c", "t", capacity=37) - - # H - # { - # "s": {"a": 85, "b": 12}, - # "a": {"c": 25, "t": 60}, - # "c": {"a": 0, "t": 37}, - # "b": {"c": 12}, - # "t": {}, - # } - - compare_flows_and_cuts(G, "s", "t", 97) - - def test_digraph_infcap_path(self): - # Graph with infinite capacity (s, t)-path - G = nx.DiGraph() - G.add_edge("s", "a") - G.add_edge("s", "b", capacity=30) - G.add_edge("a", "c") - G.add_edge("b", "c", capacity=12) - G.add_edge("a", "t", capacity=60) - G.add_edge("c", "t") - - for flow_func in all_funcs: - pytest.raises(nx.NetworkXUnbounded, flow_func, G, "s", "t") - - def test_graph_infcap_edges(self): - # Undirected graph with infinite capacity edges - G = nx.Graph() - G.add_edge("s", "a") - G.add_edge("s", "b", capacity=30) - G.add_edge("a", "c", capacity=25) - G.add_edge("b", "c", capacity=12) - G.add_edge("a", "t", capacity=60) - G.add_edge("c", "t") - - # H - # { - # "s": {"a": 85, "b": 12}, - # "a": {"c": 25, "s": 85, "t": 60}, - # "b": {"c": 12, "s": 12}, - # "c": {"a": 25, "b": 12, "t": 37}, - # "t": {"a": 60, "c": 37}, - # } - - compare_flows_and_cuts(G, "s", "t", 97) - - def test_digraph5(self): - # From ticket #429 by mfrasca. - G = nx.DiGraph() - G.add_edge("s", "a", capacity=2) - G.add_edge("s", "b", capacity=2) - G.add_edge("a", "b", capacity=5) - G.add_edge("a", "t", capacity=1) - G.add_edge("b", "a", capacity=1) - G.add_edge("b", "t", capacity=3) - # flow solution - # { - # "a": {"b": 1, "t": 1}, - # "b": {"a": 0, "t": 3}, - # "s": {"a": 2, "b": 2}, - # "t": {}, - # } - compare_flows_and_cuts(G, "s", "t", 4) - - def test_disconnected(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity") - G.remove_node(1) - assert nx.maximum_flow_value(G, 0, 3) == 0 - # flow solution - # {0: {}, 2: {3: 0}, 3: {2: 0}} - compare_flows_and_cuts(G, 0, 3, 0) - - def test_source_target_not_in_graph(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity") - G.remove_node(0) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 3) - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity") - G.remove_node(3) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 3) - - def test_source_target_coincide(self): - G = nx.Graph() - G.add_node(0) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 0) - - def test_multigraphs_raise(self): - G = nx.MultiGraph() - M = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (1, 0)], capacity=True) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 0) - - -class TestMaxFlowMinCutInterface: - def setup_method(self): - G = nx.DiGraph() - G.add_edge("x", "a", capacity=3.0) - G.add_edge("x", "b", capacity=1.0) - G.add_edge("a", "c", capacity=3.0) - G.add_edge("b", "c", capacity=5.0) - G.add_edge("b", "d", capacity=4.0) - G.add_edge("d", "e", capacity=2.0) - G.add_edge("c", "y", capacity=2.0) - G.add_edge("e", "y", capacity=3.0) - self.G = G - H = nx.DiGraph() - H.add_edge(0, 1, capacity=1.0) - H.add_edge(1, 2, capacity=1.0) - self.H = H - - def test_flow_func_not_callable(self): - elements = ["this_should_be_callable", 10, {1, 2, 3}] - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity") - for flow_func in interface_funcs: - for element in elements: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 1, flow_func=element) - pytest.raises(nx.NetworkXError, flow_func, G, 0, 1, flow_func=element) - - def test_flow_func_parameters(self): - G = self.G - fv = 3.0 - for interface_func in interface_funcs: - for flow_func in flow_funcs: - errmsg = ( - f"Assertion failed in function: {flow_func.__name__} " - f"in interface {interface_func.__name__}" - ) - result = interface_func(G, "x", "y", flow_func=flow_func) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, errmsg - - def test_minimum_cut_no_cutoff(self): - G = self.G - pytest.raises( - nx.NetworkXError, - nx.minimum_cut, - G, - "x", - "y", - flow_func=preflow_push, - cutoff=1.0, - ) - pytest.raises( - nx.NetworkXError, - nx.minimum_cut_value, - G, - "x", - "y", - flow_func=preflow_push, - cutoff=1.0, - ) - - def test_kwargs(self): - G = self.H - fv = 1.0 - to_test = ( - (shortest_augmenting_path, {"two_phase": True}), - (preflow_push, {"global_relabel_freq": 5}), - ) - for interface_func in interface_funcs: - for flow_func, kwargs in to_test: - errmsg = ( - f"Assertion failed in function: {flow_func.__name__} " - f"in interface {interface_func.__name__}" - ) - result = interface_func(G, 0, 2, flow_func=flow_func, **kwargs) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, errmsg - - def test_kwargs_default_flow_func(self): - G = self.H - for interface_func in interface_funcs: - pytest.raises( - nx.NetworkXError, interface_func, G, 0, 1, global_relabel_freq=2 - ) - - def test_reusing_residual(self): - G = self.G - fv = 3.0 - s, t = "x", "y" - R = build_residual_network(G, "capacity") - for interface_func in interface_funcs: - for flow_func in flow_funcs: - errmsg = ( - f"Assertion failed in function: {flow_func.__name__} " - f"in interface {interface_func.__name__}" - ) - for i in range(3): - result = interface_func( - G, "x", "y", flow_func=flow_func, residual=R - ) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, errmsg - - -# Tests specific to one algorithm -def test_preflow_push_global_relabel_freq(): - G = nx.DiGraph() - G.add_edge(1, 2, capacity=1) - R = preflow_push(G, 1, 2, global_relabel_freq=None) - assert R.graph["flow_value"] == 1 - pytest.raises(nx.NetworkXError, preflow_push, G, 1, 2, global_relabel_freq=-1) - - -def test_preflow_push_makes_enough_space(): - # From ticket #1542 - G = nx.DiGraph() - nx.add_path(G, [0, 1, 3], capacity=1) - nx.add_path(G, [1, 2, 3], capacity=1) - R = preflow_push(G, 0, 3, value_only=False) - assert R.graph["flow_value"] == 1 - - -def test_shortest_augmenting_path_two_phase(): - k = 5 - p = 1000 - G = nx.DiGraph() - for i in range(k): - G.add_edge("s", (i, 0), capacity=1) - nx.add_path(G, ((i, j) for j in range(p)), capacity=1) - G.add_edge((i, p - 1), "t", capacity=1) - R = shortest_augmenting_path(G, "s", "t", two_phase=True) - assert R.graph["flow_value"] == k - R = shortest_augmenting_path(G, "s", "t", two_phase=False) - assert R.graph["flow_value"] == k - - -class TestCutoff: - def test_cutoff(self): - k = 5 - p = 1000 - G = nx.DiGraph() - for i in range(k): - G.add_edge("s", (i, 0), capacity=2) - nx.add_path(G, ((i, j) for j in range(p)), capacity=2) - G.add_edge((i, p - 1), "t", capacity=2) - R = shortest_augmenting_path(G, "s", "t", two_phase=True, cutoff=k) - assert k <= R.graph["flow_value"] <= (2 * k) - R = shortest_augmenting_path(G, "s", "t", two_phase=False, cutoff=k) - assert k <= R.graph["flow_value"] <= (2 * k) - R = edmonds_karp(G, "s", "t", cutoff=k) - assert k <= R.graph["flow_value"] <= (2 * k) - R = dinitz(G, "s", "t", cutoff=k) - assert k <= R.graph["flow_value"] <= (2 * k) - R = boykov_kolmogorov(G, "s", "t", cutoff=k) - assert k <= R.graph["flow_value"] <= (2 * k) - - def test_complete_graph_cutoff(self): - G = nx.complete_graph(5) - nx.set_edge_attributes(G, {(u, v): 1 for u, v in G.edges()}, "capacity") - for flow_func in [ - shortest_augmenting_path, - edmonds_karp, - dinitz, - boykov_kolmogorov, - ]: - for cutoff in [3, 2, 1]: - result = nx.maximum_flow_value( - G, 0, 4, flow_func=flow_func, cutoff=cutoff - ) - assert cutoff == result, f"cutoff error in {flow_func.__name__}" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py deleted file mode 100644 index b395cbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Maximum flow algorithms test suite on large graphs.""" - -import bz2 -import importlib.resources -import os -import pickle - -import pytest - -import networkx as nx -from networkx.algorithms.flow import ( - boykov_kolmogorov, - build_flow_dict, - build_residual_network, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -) - -flow_funcs = [ - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -] - - -def gen_pyramid(N): - # This graph admits a flow of value 1 for which every arc is at - # capacity (except the arcs incident to the sink which have - # infinite capacity). - G = nx.DiGraph() - - for i in range(N - 1): - cap = 1.0 / (i + 2) - for j in range(i + 1): - G.add_edge((i, j), (i + 1, j), capacity=cap) - cap = 1.0 / (i + 1) - cap - G.add_edge((i, j), (i + 1, j + 1), capacity=cap) - cap = 1.0 / (i + 2) - cap - - for j in range(N): - G.add_edge((N - 1, j), "t") - - return G - - -def read_graph(name): - fname = ( - importlib.resources.files("networkx.algorithms.flow.tests") - / f"{name}.gpickle.bz2" - ) - - with bz2.BZ2File(fname, "rb") as f: - G = pickle.load(f) - return G - - -def validate_flows(G, s, t, soln_value, R, flow_func): - flow_value = R.graph["flow_value"] - flow_dict = build_flow_dict(G, R) - errmsg = f"Assertion failed in function: {flow_func.__name__}" - assert soln_value == flow_value, errmsg - assert set(G) == set(flow_dict), errmsg - for u in G: - assert set(G[u]) == set(flow_dict[u]), errmsg - excess = {u: 0 for u in flow_dict} - for u in flow_dict: - for v, flow in flow_dict[u].items(): - assert flow <= G[u][v].get("capacity", float("inf")), errmsg - assert flow >= 0, errmsg - excess[u] -= flow - excess[v] += flow - for u, exc in excess.items(): - if u == s: - assert exc == -soln_value, errmsg - elif u == t: - assert exc == soln_value, errmsg - else: - assert exc == 0, errmsg - - -class TestMaxflowLargeGraph: - def test_complete_graph(self): - N = 50 - G = nx.complete_graph(N) - nx.set_edge_attributes(G, 5, "capacity") - R = build_residual_network(G, "capacity") - kwargs = {"residual": R} - - for flow_func in flow_funcs: - kwargs["flow_func"] = flow_func - errmsg = f"Assertion failed in function: {flow_func.__name__}" - flow_value = nx.maximum_flow_value(G, 1, 2, **kwargs) - assert flow_value == 5 * (N - 1), errmsg - - def test_pyramid(self): - N = 10 - # N = 100 # this gives a graph with 5051 nodes - G = gen_pyramid(N) - R = build_residual_network(G, "capacity") - kwargs = {"residual": R} - - for flow_func in flow_funcs: - kwargs["flow_func"] = flow_func - errmsg = f"Assertion failed in function: {flow_func.__name__}" - flow_value = nx.maximum_flow_value(G, (0, 0), "t", **kwargs) - assert flow_value == pytest.approx(1.0, abs=1e-7) - - def test_gl1(self): - G = read_graph("gl1") - s = 1 - t = len(G) - R = build_residual_network(G, "capacity") - kwargs = {"residual": R} - - # do one flow_func to save time - flow_func = flow_funcs[0] - validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), flow_func) - - # for flow_func in flow_funcs: - # validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), - # flow_func) - - @pytest.mark.slow - def test_gw1(self): - G = read_graph("gw1") - s = 1 - t = len(G) - R = build_residual_network(G, "capacity") - kwargs = {"residual": R} - - for flow_func in flow_funcs: - validate_flows(G, s, t, 1202018, flow_func(G, s, t, **kwargs), flow_func) - - def test_wlm3(self): - G = read_graph("wlm3") - s = 1 - t = len(G) - R = build_residual_network(G, "capacity") - kwargs = {"residual": R} - - # do one flow_func to save time - flow_func = flow_funcs[0] - validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), flow_func) - - # for flow_func in flow_funcs: - # validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), - # flow_func) - - def test_preflow_push_global_relabel(self): - G = read_graph("gw1") - R = preflow_push(G, 1, len(G), global_relabel_freq=50) - assert R.graph["flow_value"] == 1202018 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_mincost.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_mincost.py deleted file mode 100644 index 5b1794b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_mincost.py +++ /dev/null @@ -1,476 +0,0 @@ -import bz2 -import importlib.resources -import os -import pickle - -import pytest - -import networkx as nx - - -class TestMinCostFlow: - def test_simple_digraph(self): - G = nx.DiGraph() - G.add_node("a", demand=-5) - G.add_node("d", demand=5) - G.add_edge("a", "b", weight=3, capacity=4) - G.add_edge("a", "c", weight=6, capacity=10) - G.add_edge("b", "d", weight=1, capacity=9) - G.add_edge("c", "d", weight=2, capacity=5) - flowCost, H = nx.network_simplex(G) - soln = {"a": {"b": 4, "c": 1}, "b": {"d": 4}, "c": {"d": 1}, "d": {}} - assert flowCost == 24 - assert nx.min_cost_flow_cost(G) == 24 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 24 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 24 - assert nx.cost_of_flow(G, H) == 24 - assert H == soln - - def test_negcycle_infcap(self): - G = nx.DiGraph() - G.add_node("s", demand=-5) - G.add_node("t", demand=5) - G.add_edge("s", "a", weight=1, capacity=3) - G.add_edge("a", "b", weight=3) - G.add_edge("c", "a", weight=-6) - G.add_edge("b", "d", weight=1) - G.add_edge("d", "c", weight=-2) - G.add_edge("d", "t", weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - - def test_sum_demands_not_zero(self): - G = nx.DiGraph() - G.add_node("s", demand=-5) - G.add_node("t", demand=4) - G.add_edge("s", "a", weight=1, capacity=3) - G.add_edge("a", "b", weight=3) - G.add_edge("a", "c", weight=-6) - G.add_edge("b", "d", weight=1) - G.add_edge("c", "d", weight=-2) - G.add_edge("d", "t", weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_no_flow_satisfying_demands(self): - G = nx.DiGraph() - G.add_node("s", demand=-5) - G.add_node("t", demand=5) - G.add_edge("s", "a", weight=1, capacity=3) - G.add_edge("a", "b", weight=3) - G.add_edge("a", "c", weight=-6) - G.add_edge("b", "d", weight=1) - G.add_edge("c", "d", weight=-2) - G.add_edge("d", "t", weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_transshipment(self): - G = nx.DiGraph() - G.add_node("a", demand=1) - G.add_node("b", demand=-2) - G.add_node("c", demand=-2) - G.add_node("d", demand=3) - G.add_node("e", demand=-4) - G.add_node("f", demand=-4) - G.add_node("g", demand=3) - G.add_node("h", demand=2) - G.add_node("r", demand=3) - G.add_edge("a", "c", weight=3) - G.add_edge("r", "a", weight=2) - G.add_edge("b", "a", weight=9) - G.add_edge("r", "c", weight=0) - G.add_edge("b", "r", weight=-6) - G.add_edge("c", "d", weight=5) - G.add_edge("e", "r", weight=4) - G.add_edge("e", "f", weight=3) - G.add_edge("h", "b", weight=4) - G.add_edge("f", "d", weight=7) - G.add_edge("f", "h", weight=12) - G.add_edge("g", "d", weight=12) - G.add_edge("f", "g", weight=-1) - G.add_edge("h", "g", weight=-10) - flowCost, H = nx.network_simplex(G) - soln = { - "a": {"c": 0}, - "b": {"a": 0, "r": 2}, - "c": {"d": 3}, - "d": {}, - "e": {"r": 3, "f": 1}, - "f": {"d": 0, "g": 3, "h": 2}, - "g": {"d": 0}, - "h": {"b": 0, "g": 0}, - "r": {"a": 1, "c": 1}, - } - assert flowCost == 41 - assert nx.min_cost_flow_cost(G) == 41 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 41 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 41 - assert nx.cost_of_flow(G, H) == 41 - assert H == soln - - def test_max_flow_min_cost(self): - G = nx.DiGraph() - G.add_edge("s", "a", bandwidth=6) - G.add_edge("s", "c", bandwidth=10, cost=10) - G.add_edge("a", "b", cost=6) - G.add_edge("b", "d", bandwidth=8, cost=7) - G.add_edge("c", "d", cost=10) - G.add_edge("d", "t", bandwidth=5, cost=5) - soln = { - "s": {"a": 5, "c": 0}, - "a": {"b": 5}, - "b": {"d": 5}, - "c": {"d": 0}, - "d": {"t": 5}, - "t": {}, - } - flow = nx.max_flow_min_cost(G, "s", "t", capacity="bandwidth", weight="cost") - assert flow == soln - assert nx.cost_of_flow(G, flow, weight="cost") == 90 - - G.add_edge("t", "s", cost=-100) - flowCost, flow = nx.capacity_scaling(G, capacity="bandwidth", weight="cost") - G.remove_edge("t", "s") - assert flowCost == -410 - assert flow["t"]["s"] == 5 - del flow["t"]["s"] - assert flow == soln - assert nx.cost_of_flow(G, flow, weight="cost") == 90 - - def test_digraph1(self): - # From Bradley, S. P., Hax, A. C. and Magnanti, T. L. Applied - # Mathematical Programming. Addison-Wesley, 1977. - G = nx.DiGraph() - G.add_node(1, demand=-20) - G.add_node(4, demand=5) - G.add_node(5, demand=15) - G.add_edges_from( - [ - (1, 2, {"capacity": 15, "weight": 4}), - (1, 3, {"capacity": 8, "weight": 4}), - (2, 3, {"weight": 2}), - (2, 4, {"capacity": 4, "weight": 2}), - (2, 5, {"capacity": 10, "weight": 6}), - (3, 4, {"capacity": 15, "weight": 1}), - (3, 5, {"capacity": 5, "weight": 3}), - (4, 5, {"weight": 2}), - (5, 3, {"capacity": 4, "weight": 1}), - ] - ) - flowCost, H = nx.network_simplex(G) - soln = { - 1: {2: 12, 3: 8}, - 2: {3: 8, 4: 4, 5: 0}, - 3: {4: 11, 5: 5}, - 4: {5: 10}, - 5: {3: 0}, - } - assert flowCost == 150 - assert nx.min_cost_flow_cost(G) == 150 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 150 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 150 - assert H == soln - assert nx.cost_of_flow(G, H) == 150 - - def test_digraph2(self): - # Example from ticket #430 from mfrasca. Original source: - # http://www.cs.princeton.edu/courses/archive/spr03/cs226/lectures/mincost.4up.pdf, slide 11. - G = nx.DiGraph() - G.add_edge("s", 1, capacity=12) - G.add_edge("s", 2, capacity=6) - G.add_edge("s", 3, capacity=14) - G.add_edge(1, 2, capacity=11, weight=4) - G.add_edge(2, 3, capacity=9, weight=6) - G.add_edge(1, 4, capacity=5, weight=5) - G.add_edge(1, 5, capacity=2, weight=12) - G.add_edge(2, 5, capacity=4, weight=4) - G.add_edge(2, 6, capacity=2, weight=6) - G.add_edge(3, 6, capacity=31, weight=3) - G.add_edge(4, 5, capacity=18, weight=4) - G.add_edge(5, 6, capacity=9, weight=5) - G.add_edge(4, "t", capacity=3) - G.add_edge(5, "t", capacity=7) - G.add_edge(6, "t", capacity=22) - flow = nx.max_flow_min_cost(G, "s", "t") - soln = { - 1: {2: 6, 4: 5, 5: 1}, - 2: {3: 6, 5: 4, 6: 2}, - 3: {6: 20}, - 4: {5: 2, "t": 3}, - 5: {6: 0, "t": 7}, - 6: {"t": 22}, - "s": {1: 12, 2: 6, 3: 14}, - "t": {}, - } - assert flow == soln - - G.add_edge("t", "s", weight=-100) - flowCost, flow = nx.capacity_scaling(G) - G.remove_edge("t", "s") - assert flow["t"]["s"] == 32 - assert flowCost == -3007 - del flow["t"]["s"] - assert flow == soln - assert nx.cost_of_flow(G, flow) == 193 - - def test_digraph3(self): - """Combinatorial Optimization: Algorithms and Complexity, - Papadimitriou Steiglitz at page 140 has an example, 7.1, but that - admits multiple solutions, so I alter it a bit. From ticket #430 - by mfrasca.""" - - G = nx.DiGraph() - G.add_edge("s", "a") - G["s"]["a"].update({0: 2, 1: 4}) - G.add_edge("s", "b") - G["s"]["b"].update({0: 2, 1: 1}) - G.add_edge("a", "b") - G["a"]["b"].update({0: 5, 1: 2}) - G.add_edge("a", "t") - G["a"]["t"].update({0: 1, 1: 5}) - G.add_edge("b", "a") - G["b"]["a"].update({0: 1, 1: 3}) - G.add_edge("b", "t") - G["b"]["t"].update({0: 3, 1: 2}) - - "PS.ex.7.1: testing main function" - sol = nx.max_flow_min_cost(G, "s", "t", capacity=0, weight=1) - flow = sum(v for v in sol["s"].values()) - assert 4 == flow - assert 23 == nx.cost_of_flow(G, sol, weight=1) - assert sol["s"] == {"a": 2, "b": 2} - assert sol["a"] == {"b": 1, "t": 1} - assert sol["b"] == {"a": 0, "t": 3} - assert sol["t"] == {} - - G.add_edge("t", "s") - G["t"]["s"].update({1: -100}) - flowCost, sol = nx.capacity_scaling(G, capacity=0, weight=1) - G.remove_edge("t", "s") - flow = sum(v for v in sol["s"].values()) - assert 4 == flow - assert sol["t"]["s"] == 4 - assert flowCost == -377 - del sol["t"]["s"] - assert sol["s"] == {"a": 2, "b": 2} - assert sol["a"] == {"b": 1, "t": 1} - assert sol["b"] == {"a": 0, "t": 3} - assert sol["t"] == {} - assert nx.cost_of_flow(G, sol, weight=1) == 23 - - def test_zero_capacity_edges(self): - """Address issue raised in ticket #617 by arv.""" - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2, {"capacity": 1, "weight": 1}), - (1, 5, {"capacity": 1, "weight": 1}), - (2, 3, {"capacity": 0, "weight": 1}), - (2, 5, {"capacity": 1, "weight": 1}), - (5, 3, {"capacity": 2, "weight": 1}), - (5, 4, {"capacity": 0, "weight": 1}), - (3, 4, {"capacity": 2, "weight": 1}), - ] - ) - G.nodes[1]["demand"] = -1 - G.nodes[2]["demand"] = -1 - G.nodes[4]["demand"] = 2 - - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0, 5: 1}, 2: {3: 0, 5: 1}, 3: {4: 2}, 4: {}, 5: {3: 2, 4: 0}} - assert flowCost == 6 - assert nx.min_cost_flow_cost(G) == 6 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 6 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 6 - assert H == soln - assert nx.cost_of_flow(G, H) == 6 - - def test_digon(self): - """Check if digons are handled properly. Taken from ticket - #618 by arv.""" - nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})] - edges = [ - (1, 2, {"capacity": 3, "weight": 600000}), - (2, 1, {"capacity": 2, "weight": 0}), - (2, 3, {"capacity": 5, "weight": 714285}), - (3, 2, {"capacity": 2, "weight": 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0}, 2: {1: 0, 3: 4}, 3: {2: 0}} - assert flowCost == 2857140 - assert nx.min_cost_flow_cost(G) == 2857140 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 2857140 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 2857140 - assert H == soln - assert nx.cost_of_flow(G, H) == 2857140 - - def test_deadend(self): - """Check if one-node cycles are handled properly. Taken from ticket - #2906 from @sshraven.""" - G = nx.DiGraph() - - G.add_nodes_from(range(5), demand=0) - G.nodes[4]["demand"] = -13 - G.nodes[3]["demand"] = 13 - - G.add_edges_from([(0, 2), (0, 3), (2, 1)], capacity=20, weight=0.1) - pytest.raises(nx.NetworkXUnfeasible, nx.min_cost_flow, G) - - def test_infinite_capacity_neg_digon(self): - """An infinite capacity negative cost digon results in an unbounded - instance.""" - nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})] - edges = [ - (1, 2, {"weight": -600}), - (2, 1, {"weight": 0}), - (2, 3, {"capacity": 5, "weight": 714285}), - (3, 2, {"capacity": 2, "weight": 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - - def test_finite_capacity_neg_digon(self): - """The digon should receive the maximum amount of flow it can handle. - Taken from ticket #749 by @chuongdo.""" - G = nx.DiGraph() - G.add_edge("a", "b", capacity=1, weight=-1) - G.add_edge("b", "a", capacity=1, weight=-1) - min_cost = -2 - assert nx.min_cost_flow_cost(G) == min_cost - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {"a": {"b": 1}, "b": {"a": 1}} - assert nx.cost_of_flow(G, H) == -2 - - def test_multidigraph(self): - """Multidigraphs are acceptable.""" - G = nx.MultiDiGraph() - G.add_weighted_edges_from([(1, 2, 1), (2, 3, 2)], weight="capacity") - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}} - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 0 - assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}} - - def test_negative_selfloops(self): - """Negative selfloops should cause an exception if uncapacitated and - always be saturated otherwise. - """ - G = nx.DiGraph() - G.add_edge(1, 1, weight=-1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - G[1][1]["capacity"] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: 2}} - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {1: {1: 2}} - - G = nx.MultiDiGraph() - G.add_edge(1, 1, "x", weight=-1) - G.add_edge(1, 1, "y", weight=1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - G[1][1]["x"]["capacity"] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: {"x": 2, "y": 0}}} - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {1: {1: {"x": 2, "y": 0}}} - - def test_bone_shaped(self): - # From #1283 - G = nx.DiGraph() - G.add_node(0, demand=-4) - G.add_node(1, demand=2) - G.add_node(2, demand=2) - G.add_node(3, demand=4) - G.add_node(4, demand=-2) - G.add_node(5, demand=-2) - G.add_edge(0, 1, capacity=4) - G.add_edge(0, 2, capacity=4) - G.add_edge(4, 3, capacity=4) - G.add_edge(5, 3, capacity=4) - G.add_edge(0, 3, capacity=0) - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}} - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 0 - assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}} - - def test_exceptions(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G) - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G) - G = nx.DiGraph() - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - # pytest.raises(nx.NetworkXError, nx.capacity_scaling, G) - G.add_node(0, demand=float("inf")) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G.nodes[0]["demand"] = 0 - G.add_node(1, demand=0) - G.add_edge(0, 1, weight=-float("inf")) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G[0][1]["weight"] = 0 - G.add_edge(0, 0, weight=float("inf")) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - # pytest.raises(nx.NetworkXError, nx.capacity_scaling, G) - G[0][0]["weight"] = 0 - G[0][1]["capacity"] = -1 - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - # pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G[0][1]["capacity"] = 0 - G[0][0]["capacity"] = -1 - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - # pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_large(self): - fname = ( - importlib.resources.files("networkx.algorithms.flow.tests") - / "netgen-2.gpickle.bz2" - ) - with bz2.BZ2File(fname, "rb") as f: - G = pickle.load(f) - flowCost, flowDict = nx.network_simplex(G) - assert 6749969302 == flowCost - assert 6749969302 == nx.cost_of_flow(G, flowDict) - flowCost, flowDict = nx.capacity_scaling(G) - assert 6749969302 == flowCost - assert 6749969302 == nx.cost_of_flow(G, flowDict) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py deleted file mode 100644 index cc9230c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py +++ /dev/null @@ -1,387 +0,0 @@ -import bz2 -import importlib.resources -import os -import pickle - -import pytest - -import networkx as nx - - -@pytest.fixture -def simple_flow_graph(): - G = nx.DiGraph() - G.add_node("a", demand=0) - G.add_node("b", demand=-5) - G.add_node("c", demand=50000000) - G.add_node("d", demand=-49999995) - G.add_edge("a", "b", weight=3, capacity=4) - G.add_edge("a", "c", weight=6, capacity=10) - G.add_edge("b", "d", weight=1, capacity=9) - G.add_edge("c", "d", weight=2, capacity=5) - return G - - -@pytest.fixture -def simple_no_flow_graph(): - G = nx.DiGraph() - G.add_node("s", demand=-5) - G.add_node("t", demand=5) - G.add_edge("s", "a", weight=1, capacity=3) - G.add_edge("a", "b", weight=3) - G.add_edge("a", "c", weight=-6) - G.add_edge("b", "d", weight=1) - G.add_edge("c", "d", weight=-2) - G.add_edge("d", "t", weight=1, capacity=3) - return G - - -def get_flowcost_from_flowdict(G, flowDict): - """Returns flow cost calculated from flow dictionary""" - flowCost = 0 - for u in flowDict: - for v in flowDict[u]: - flowCost += flowDict[u][v] * G[u][v]["weight"] - return flowCost - - -def test_infinite_demand_raise(simple_flow_graph): - G = simple_flow_graph - inf = float("inf") - nx.set_node_attributes(G, {"a": {"demand": inf}}) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - - -def test_neg_infinite_demand_raise(simple_flow_graph): - G = simple_flow_graph - inf = float("inf") - nx.set_node_attributes(G, {"a": {"demand": -inf}}) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - - -def test_infinite_weight_raise(simple_flow_graph): - G = simple_flow_graph - inf = float("inf") - nx.set_edge_attributes( - G, {("a", "b"): {"weight": inf}, ("b", "d"): {"weight": inf}} - ) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - - -def test_nonzero_net_demand_raise(simple_flow_graph): - G = simple_flow_graph - nx.set_node_attributes(G, {"b": {"demand": -4}}) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_negative_capacity_raise(simple_flow_graph): - G = simple_flow_graph - nx.set_edge_attributes(G, {("a", "b"): {"weight": 1}, ("b", "d"): {"capacity": -9}}) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_no_flow_satisfying_demands(simple_no_flow_graph): - G = simple_no_flow_graph - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_sum_demands_not_zero(simple_no_flow_graph): - G = simple_no_flow_graph - nx.set_node_attributes(G, {"t": {"demand": 4}}) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_google_or_tools_example(): - """ - https://developers.google.com/optimization/flow/mincostflow - """ - G = nx.DiGraph() - start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4] - end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2] - capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5] - unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3] - supplies = [20, 0, 0, -5, -15] - answer = 150 - - for i in range(len(supplies)): - G.add_node(i, demand=(-1) * supplies[i]) # supplies are negative of demand - - for i in range(len(start_nodes)): - G.add_edge( - start_nodes[i], end_nodes[i], weight=unit_costs[i], capacity=capacities[i] - ) - - flowCost, flowDict = nx.network_simplex(G) - assert flowCost == answer - assert flowCost == get_flowcost_from_flowdict(G, flowDict) - - -def test_google_or_tools_example2(): - """ - https://developers.google.com/optimization/flow/mincostflow - """ - G = nx.DiGraph() - start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4, 3] - end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2, 5] - capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5, 10] - unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3, 4] - supplies = [23, 0, 0, -5, -15, -3] - answer = 183 - - for i in range(len(supplies)): - G.add_node(i, demand=(-1) * supplies[i]) # supplies are negative of demand - - for i in range(len(start_nodes)): - G.add_edge( - start_nodes[i], end_nodes[i], weight=unit_costs[i], capacity=capacities[i] - ) - - flowCost, flowDict = nx.network_simplex(G) - assert flowCost == answer - assert flowCost == get_flowcost_from_flowdict(G, flowDict) - - -def test_large(): - fname = ( - importlib.resources.files("networkx.algorithms.flow.tests") - / "netgen-2.gpickle.bz2" - ) - - with bz2.BZ2File(fname, "rb") as f: - G = pickle.load(f) - flowCost, flowDict = nx.network_simplex(G) - assert 6749969302 == flowCost - assert 6749969302 == nx.cost_of_flow(G, flowDict) - - -def test_simple_digraph(): - G = nx.DiGraph() - G.add_node("a", demand=-5) - G.add_node("d", demand=5) - G.add_edge("a", "b", weight=3, capacity=4) - G.add_edge("a", "c", weight=6, capacity=10) - G.add_edge("b", "d", weight=1, capacity=9) - G.add_edge("c", "d", weight=2, capacity=5) - flowCost, H = nx.network_simplex(G) - soln = {"a": {"b": 4, "c": 1}, "b": {"d": 4}, "c": {"d": 1}, "d": {}} - assert flowCost == 24 - assert nx.min_cost_flow_cost(G) == 24 - assert H == soln - - -def test_negcycle_infcap(): - G = nx.DiGraph() - G.add_node("s", demand=-5) - G.add_node("t", demand=5) - G.add_edge("s", "a", weight=1, capacity=3) - G.add_edge("a", "b", weight=3) - G.add_edge("c", "a", weight=-6) - G.add_edge("b", "d", weight=1) - G.add_edge("d", "c", weight=-2) - G.add_edge("d", "t", weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_transshipment(): - G = nx.DiGraph() - G.add_node("a", demand=1) - G.add_node("b", demand=-2) - G.add_node("c", demand=-2) - G.add_node("d", demand=3) - G.add_node("e", demand=-4) - G.add_node("f", demand=-4) - G.add_node("g", demand=3) - G.add_node("h", demand=2) - G.add_node("r", demand=3) - G.add_edge("a", "c", weight=3) - G.add_edge("r", "a", weight=2) - G.add_edge("b", "a", weight=9) - G.add_edge("r", "c", weight=0) - G.add_edge("b", "r", weight=-6) - G.add_edge("c", "d", weight=5) - G.add_edge("e", "r", weight=4) - G.add_edge("e", "f", weight=3) - G.add_edge("h", "b", weight=4) - G.add_edge("f", "d", weight=7) - G.add_edge("f", "h", weight=12) - G.add_edge("g", "d", weight=12) - G.add_edge("f", "g", weight=-1) - G.add_edge("h", "g", weight=-10) - flowCost, H = nx.network_simplex(G) - soln = { - "a": {"c": 0}, - "b": {"a": 0, "r": 2}, - "c": {"d": 3}, - "d": {}, - "e": {"r": 3, "f": 1}, - "f": {"d": 0, "g": 3, "h": 2}, - "g": {"d": 0}, - "h": {"b": 0, "g": 0}, - "r": {"a": 1, "c": 1}, - } - assert flowCost == 41 - assert H == soln - - -def test_digraph1(): - # From Bradley, S. P., Hax, A. C. and Magnanti, T. L. Applied - # Mathematical Programming. Addison-Wesley, 1977. - G = nx.DiGraph() - G.add_node(1, demand=-20) - G.add_node(4, demand=5) - G.add_node(5, demand=15) - G.add_edges_from( - [ - (1, 2, {"capacity": 15, "weight": 4}), - (1, 3, {"capacity": 8, "weight": 4}), - (2, 3, {"weight": 2}), - (2, 4, {"capacity": 4, "weight": 2}), - (2, 5, {"capacity": 10, "weight": 6}), - (3, 4, {"capacity": 15, "weight": 1}), - (3, 5, {"capacity": 5, "weight": 3}), - (4, 5, {"weight": 2}), - (5, 3, {"capacity": 4, "weight": 1}), - ] - ) - flowCost, H = nx.network_simplex(G) - soln = { - 1: {2: 12, 3: 8}, - 2: {3: 8, 4: 4, 5: 0}, - 3: {4: 11, 5: 5}, - 4: {5: 10}, - 5: {3: 0}, - } - assert flowCost == 150 - assert nx.min_cost_flow_cost(G) == 150 - assert H == soln - - -def test_zero_capacity_edges(): - """Address issue raised in ticket #617 by arv.""" - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2, {"capacity": 1, "weight": 1}), - (1, 5, {"capacity": 1, "weight": 1}), - (2, 3, {"capacity": 0, "weight": 1}), - (2, 5, {"capacity": 1, "weight": 1}), - (5, 3, {"capacity": 2, "weight": 1}), - (5, 4, {"capacity": 0, "weight": 1}), - (3, 4, {"capacity": 2, "weight": 1}), - ] - ) - G.nodes[1]["demand"] = -1 - G.nodes[2]["demand"] = -1 - G.nodes[4]["demand"] = 2 - - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0, 5: 1}, 2: {3: 0, 5: 1}, 3: {4: 2}, 4: {}, 5: {3: 2, 4: 0}} - assert flowCost == 6 - assert nx.min_cost_flow_cost(G) == 6 - assert H == soln - - -def test_digon(): - """Check if digons are handled properly. Taken from ticket - #618 by arv.""" - nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})] - edges = [ - (1, 2, {"capacity": 3, "weight": 600000}), - (2, 1, {"capacity": 2, "weight": 0}), - (2, 3, {"capacity": 5, "weight": 714285}), - (3, 2, {"capacity": 2, "weight": 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0}, 2: {1: 0, 3: 4}, 3: {2: 0}} - assert flowCost == 2857140 - - -def test_deadend(): - """Check if one-node cycles are handled properly. Taken from ticket - #2906 from @sshraven.""" - G = nx.DiGraph() - - G.add_nodes_from(range(5), demand=0) - G.nodes[4]["demand"] = -13 - G.nodes[3]["demand"] = 13 - - G.add_edges_from([(0, 2), (0, 3), (2, 1)], capacity=20, weight=0.1) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - - -def test_infinite_capacity_neg_digon(): - """An infinite capacity negative cost digon results in an unbounded - instance.""" - nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})] - edges = [ - (1, 2, {"weight": -600}), - (2, 1, {"weight": 0}), - (2, 3, {"capacity": 5, "weight": 714285}), - (3, 2, {"capacity": 2, "weight": 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - - -def test_multidigraph(): - """Multidigraphs are acceptable.""" - G = nx.MultiDiGraph() - G.add_weighted_edges_from([(1, 2, 1), (2, 3, 2)], weight="capacity") - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}} - - -def test_negative_selfloops(): - """Negative selfloops should cause an exception if uncapacitated and - always be saturated otherwise. - """ - G = nx.DiGraph() - G.add_edge(1, 1, weight=-1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - - G[1][1]["capacity"] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: 2}} - - G = nx.MultiDiGraph() - G.add_edge(1, 1, "x", weight=-1) - G.add_edge(1, 1, "y", weight=1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - - G[1][1]["x"]["capacity"] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: {"x": 2, "y": 0}}} - - -def test_bone_shaped(): - # From #1283 - G = nx.DiGraph() - G.add_node(0, demand=-4) - G.add_node(1, demand=2) - G.add_node(2, demand=2) - G.add_node(3, demand=4) - G.add_node(4, demand=-2) - G.add_node(5, demand=-2) - G.add_edge(0, 1, capacity=4) - G.add_edge(0, 2, capacity=4) - G.add_edge(4, 3, capacity=4) - G.add_edge(5, 3, capacity=4) - G.add_edge(0, 3, capacity=0) - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}} - - -def test_graphs_type_exceptions(): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - G = nx.DiGraph() - pytest.raises(nx.NetworkXError, nx.network_simplex, G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 deleted file mode 100644 index c95da5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccacba1e0fbfb30bec361f0e48ec88c999d3474fcda5ddf93bd444ace17cfa0e -size 88132 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/utils.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/utils.py deleted file mode 100644 index 03f1d10..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/flow/utils.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Utility classes and functions for network flow algorithms. -""" - -from collections import deque - -import networkx as nx - -__all__ = [ - "CurrentEdge", - "Level", - "GlobalRelabelThreshold", - "build_residual_network", - "detect_unboundedness", - "build_flow_dict", -] - - -class CurrentEdge: - """Mechanism for iterating over out-edges incident to a node in a circular - manner. StopIteration exception is raised when wraparound occurs. - """ - - __slots__ = ("_edges", "_it", "_curr") - - def __init__(self, edges): - self._edges = edges - if self._edges: - self._rewind() - - def get(self): - return self._curr - - def move_to_next(self): - try: - self._curr = next(self._it) - except StopIteration: - self._rewind() - raise - - def _rewind(self): - self._it = iter(self._edges.items()) - self._curr = next(self._it) - - -class Level: - """Active and inactive nodes in a level.""" - - __slots__ = ("active", "inactive") - - def __init__(self): - self.active = set() - self.inactive = set() - - -class GlobalRelabelThreshold: - """Measurement of work before the global relabeling heuristic should be - applied. - """ - - def __init__(self, n, m, freq): - self._threshold = (n + m) / freq if freq else float("inf") - self._work = 0 - - def add_work(self, work): - self._work += work - - def is_reached(self): - return self._work >= self._threshold - - def clear_work(self): - self._work = 0 - - -@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True) -def build_residual_network(G, capacity): - """Build a residual network and initialize a zero flow. - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - """ - if G.is_multigraph(): - raise nx.NetworkXError("MultiGraph and MultiDiGraph not supported (yet).") - - R = nx.DiGraph() - R.__networkx_cache__ = None # Disable caching - R.add_nodes_from(G) - - inf = float("inf") - # Extract edges with positive capacities. Self loops excluded. - edge_list = [ - (u, v, attr) - for u, v, attr in G.edges(data=True) - if u != v and attr.get(capacity, inf) > 0 - ] - # Simulate infinity with three times the sum of the finite edge capacities - # or any positive value if the sum is zero. This allows the - # infinite-capacity edges to be distinguished for unboundedness detection - # and directly participate in residual capacity calculation. If the maximum - # flow is finite, these edges cannot appear in the minimum cut and thus - # guarantee correctness. Since the residual capacity of an - # infinite-capacity edge is always at least 2/3 of inf, while that of an - # finite-capacity edge is at most 1/3 of inf, if an operation moves more - # than 1/3 of inf units of flow to t, there must be an infinite-capacity - # s-t path in G. - inf = ( - 3 - * sum( - attr[capacity] - for u, v, attr in edge_list - if capacity in attr and attr[capacity] != inf - ) - or 1 - ) - if G.is_directed(): - for u, v, attr in edge_list: - r = min(attr.get(capacity, inf), inf) - if not R.has_edge(u, v): - # Both (u, v) and (v, u) must be present in the residual - # network. - R.add_edge(u, v, capacity=r) - R.add_edge(v, u, capacity=0) - else: - # The edge (u, v) was added when (v, u) was visited. - R[u][v]["capacity"] = r - else: - for u, v, attr in edge_list: - # Add a pair of edges with equal residual capacities. - r = min(attr.get(capacity, inf), inf) - R.add_edge(u, v, capacity=r) - R.add_edge(v, u, capacity=r) - - # Record the value simulating infinity. - R.graph["inf"] = inf - - return R - - -@nx._dispatchable( - graphs="R", - preserve_edge_attrs={"R": {"capacity": float("inf")}}, - preserve_graph_attrs=True, -) -def detect_unboundedness(R, s, t): - """Detect an infinite-capacity s-t path in R.""" - q = deque([s]) - seen = {s} - inf = R.graph["inf"] - while q: - u = q.popleft() - for v, attr in R[u].items(): - if attr["capacity"] == inf and v not in seen: - if v == t: - raise nx.NetworkXUnbounded( - "Infinite capacity path, flow unbounded above." - ) - seen.add(v) - q.append(v) - - -@nx._dispatchable(graphs={"G": 0, "R": 1}, preserve_edge_attrs={"R": {"flow": None}}) -def build_flow_dict(G, R): - """Build a flow dictionary from a residual network.""" - flow_dict = {} - for u in G: - flow_dict[u] = {v: 0 for v in G[u]} - flow_dict[u].update( - (v, attr["flow"]) for v, attr in R[u].items() if attr["flow"] > 0 - ) - return flow_dict diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graph_hashing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graph_hashing.py deleted file mode 100644 index 7ded847..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graph_hashing.py +++ /dev/null @@ -1,328 +0,0 @@ -""" -Functions for hashing graphs to strings. -Isomorphic graphs should be assigned identical hashes. -For now, only Weisfeiler-Lehman hashing is implemented. -""" - -from collections import Counter, defaultdict -from hashlib import blake2b - -import networkx as nx - -__all__ = ["weisfeiler_lehman_graph_hash", "weisfeiler_lehman_subgraph_hashes"] - - -def _hash_label(label, digest_size): - return blake2b(label.encode("ascii"), digest_size=digest_size).hexdigest() - - -def _init_node_labels(G, edge_attr, node_attr): - if node_attr: - return {u: str(dd[node_attr]) for u, dd in G.nodes(data=True)} - elif edge_attr: - return {u: "" for u in G} - else: - return {u: str(deg) for u, deg in G.degree()} - - -def _neighborhood_aggregate(G, node, node_labels, edge_attr=None): - """ - Compute new labels for given node by aggregating - the labels of each node's neighbors. - """ - label_list = [] - for nbr in G.neighbors(node): - prefix = "" if edge_attr is None else str(G[node][nbr][edge_attr]) - label_list.append(prefix + node_labels[nbr]) - return node_labels[node] + "".join(sorted(label_list)) - - -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs={"edge_attr": None}, node_attrs="node_attr") -def weisfeiler_lehman_graph_hash( - G, edge_attr=None, node_attr=None, iterations=3, digest_size=16 -): - """Return Weisfeiler Lehman (WL) graph hash. - - The function iteratively aggregates and hashes neighborhoods of each node. - After each node's neighbors are hashed to obtain updated node labels, - a hashed histogram of resulting labels is returned as the final hash. - - Hashes are identical for isomorphic graphs and strong guarantees that - non-isomorphic graphs will get different hashes. See [1]_ for details. - - If no node or edge attributes are provided, the degree of each node - is used as its initial label. - Otherwise, node and/or edge labels are used to compute the hash. - - Parameters - ---------- - G : graph - The graph to be hashed. - Can have node and/or edge attributes. Can also have no attributes. - edge_attr : string, optional (default=None) - The key in edge attribute dictionary to be used for hashing. - If None, edge labels are ignored. - node_attr: string, optional (default=None) - The key in node attribute dictionary to be used for hashing. - If None, and no edge_attr given, use the degrees of the nodes as labels. - iterations: int, optional (default=3) - Number of neighbor aggregations to perform. - Should be larger for larger graphs. - digest_size: int, optional (default=16) - Size (in bits) of blake2b hash digest to use for hashing node labels. - - Returns - ------- - h : string - Hexadecimal string corresponding to hash of the input graph. - - Examples - -------- - Two graphs with edge attributes that are isomorphic, except for - differences in the edge labels. - - >>> G1 = nx.Graph() - >>> G1.add_edges_from( - ... [ - ... (1, 2, {"label": "A"}), - ... (2, 3, {"label": "A"}), - ... (3, 1, {"label": "A"}), - ... (1, 4, {"label": "B"}), - ... ] - ... ) - >>> G2 = nx.Graph() - >>> G2.add_edges_from( - ... [ - ... (5, 6, {"label": "B"}), - ... (6, 7, {"label": "A"}), - ... (7, 5, {"label": "A"}), - ... (7, 8, {"label": "A"}), - ... ] - ... ) - - Omitting the `edge_attr` option, results in identical hashes. - - >>> nx.weisfeiler_lehman_graph_hash(G1) - '7bc4dde9a09d0b94c5097b219891d81a' - >>> nx.weisfeiler_lehman_graph_hash(G2) - '7bc4dde9a09d0b94c5097b219891d81a' - - With edge labels, the graphs are no longer assigned - the same hash digest. - - >>> nx.weisfeiler_lehman_graph_hash(G1, edge_attr="label") - 'c653d85538bcf041d88c011f4f905f10' - >>> nx.weisfeiler_lehman_graph_hash(G2, edge_attr="label") - '3dcd84af1ca855d0eff3c978d88e7ec7' - - Notes - ----- - To return the WL hashes of each subgraph of a graph, use - `weisfeiler_lehman_subgraph_hashes` - - Similarity between hashes does not imply similarity between graphs. - - References - ---------- - .. [1] Shervashidze, Nino, Pascal Schweitzer, Erik Jan Van Leeuwen, - Kurt Mehlhorn, and Karsten M. Borgwardt. Weisfeiler Lehman - Graph Kernels. Journal of Machine Learning Research. 2011. - http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf - - See also - -------- - weisfeiler_lehman_subgraph_hashes - """ - - def weisfeiler_lehman_step(G, labels, edge_attr=None): - """ - Apply neighborhood aggregation to each node - in the graph. - Computes a dictionary with labels for each node. - """ - new_labels = {} - for node in G.nodes(): - label = _neighborhood_aggregate(G, node, labels, edge_attr=edge_attr) - new_labels[node] = _hash_label(label, digest_size) - return new_labels - - # set initial node labels - node_labels = _init_node_labels(G, edge_attr, node_attr) - - subgraph_hash_counts = [] - for _ in range(iterations): - node_labels = weisfeiler_lehman_step(G, node_labels, edge_attr=edge_attr) - counter = Counter(node_labels.values()) - # sort the counter, extend total counts - subgraph_hash_counts.extend(sorted(counter.items(), key=lambda x: x[0])) - - # hash the final counter - return _hash_label(str(tuple(subgraph_hash_counts)), digest_size) - - -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs={"edge_attr": None}, node_attrs="node_attr") -def weisfeiler_lehman_subgraph_hashes( - G, - edge_attr=None, - node_attr=None, - iterations=3, - digest_size=16, - include_initial_labels=False, -): - """ - Return a dictionary of subgraph hashes by node. - - Dictionary keys are nodes in `G`, and values are a list of hashes. - Each hash corresponds to a subgraph rooted at a given node u in `G`. - Lists of subgraph hashes are sorted in increasing order of depth from - their root node, with the hash at index i corresponding to a subgraph - of nodes at most i edges distance from u. Thus, each list will contain - `iterations` elements - a hash for a subgraph at each depth. If - `include_initial_labels` is set to `True`, each list will additionally - have contain a hash of the initial node label (or equivalently a - subgraph of depth 0) prepended, totalling ``iterations + 1`` elements. - - The function iteratively aggregates and hashes neighborhoods of each node. - This is achieved for each step by replacing for each node its label from - the previous iteration with its hashed 1-hop neighborhood aggregate. - The new node label is then appended to a list of node labels for each - node. - - To aggregate neighborhoods for a node $u$ at each step, all labels of - nodes adjacent to $u$ are concatenated. If the `edge_attr` parameter is set, - labels for each neighboring node are prefixed with the value of this attribute - along the connecting edge from this neighbor to node $u$. The resulting string - is then hashed to compress this information into a fixed digest size. - - Thus, at the $i$-th iteration, nodes within $i$ hops influence any given - hashed node label. We can therefore say that at depth $i$ for node $u$ - we have a hash for a subgraph induced by the $i$-hop neighborhood of $u$. - - The output can be used to create general Weisfeiler-Lehman graph kernels, - or generate features for graphs or nodes - for example to generate 'words' in - a graph as seen in the 'graph2vec' algorithm. - See [1]_ & [2]_ respectively for details. - - Hashes are identical for isomorphic subgraphs and there exist strong - guarantees that non-isomorphic graphs will get different hashes. - See [1]_ for details. - - If no node or edge attributes are provided, the degree of each node - is used as its initial label. - Otherwise, node and/or edge labels are used to compute the hash. - - Parameters - ---------- - G : graph - The graph to be hashed. - Can have node and/or edge attributes. Can also have no attributes. - edge_attr : string, optional (default=None) - The key in edge attribute dictionary to be used for hashing. - If None, edge labels are ignored. - node_attr : string, optional (default=None) - The key in node attribute dictionary to be used for hashing. - If None, and no edge_attr given, use the degrees of the nodes as labels. - If None, and edge_attr is given, each node starts with an identical label. - iterations : int, optional (default=3) - Number of neighbor aggregations to perform. - Should be larger for larger graphs. - digest_size : int, optional (default=16) - Size (in bits) of blake2b hash digest to use for hashing node labels. - The default size is 16 bits. - include_initial_labels : bool, optional (default=False) - If True, include the hashed initial node label as the first subgraph - hash for each node. - - Returns - ------- - node_subgraph_hashes : dict - A dictionary with each key given by a node in G, and each value given - by the subgraph hashes in order of depth from the key node. - - Examples - -------- - Finding similar nodes in different graphs: - - >>> G1 = nx.Graph() - >>> G1.add_edges_from([(1, 2), (2, 3), (2, 4), (3, 5), (4, 6), (5, 7), (6, 7)]) - >>> G2 = nx.Graph() - >>> G2.add_edges_from([(1, 3), (2, 3), (1, 6), (1, 5), (4, 6)]) - >>> g1_hashes = nx.weisfeiler_lehman_subgraph_hashes( - ... G1, iterations=3, digest_size=8 - ... ) - >>> g2_hashes = nx.weisfeiler_lehman_subgraph_hashes( - ... G2, iterations=3, digest_size=8 - ... ) - - Even though G1 and G2 are not isomorphic (they have different numbers of edges), - the hash sequence of depth 3 for node 1 in G1 and node 5 in G2 are similar: - - >>> g1_hashes[1] - ['a93b64973cfc8897', 'db1b43ae35a1878f', '57872a7d2059c1c0'] - >>> g2_hashes[5] - ['a93b64973cfc8897', 'db1b43ae35a1878f', '1716d2a4012fa4bc'] - - The first 2 WL subgraph hashes match. From this we can conclude that it's very - likely the neighborhood of 2 hops around these nodes are isomorphic. - - However the 3-hop neighborhoods of ``G1`` and ``G2`` are not isomorphic since the - 3rd hashes in the lists above are not equal. - - These nodes may be candidates to be classified together since their local topology - is similar. - - Notes - ----- - To hash the full graph when subgraph hashes are not needed, use - `weisfeiler_lehman_graph_hash` for efficiency. - - Similarity between hashes does not imply similarity between graphs. - - References - ---------- - .. [1] Shervashidze, Nino, Pascal Schweitzer, Erik Jan Van Leeuwen, - Kurt Mehlhorn, and Karsten M. Borgwardt. Weisfeiler Lehman - Graph Kernels. Journal of Machine Learning Research. 2011. - http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf - .. [2] Annamalai Narayanan, Mahinthan Chandramohan, Rajasekar Venkatesan, - Lihui Chen, Yang Liu and Shantanu Jaiswa. graph2vec: Learning - Distributed Representations of Graphs. arXiv. 2017 - https://arxiv.org/pdf/1707.05005.pdf - - See also - -------- - weisfeiler_lehman_graph_hash - """ - - def weisfeiler_lehman_step(G, labels, node_subgraph_hashes, edge_attr=None): - """ - Apply neighborhood aggregation to each node - in the graph. - Computes a dictionary with labels for each node. - Appends the new hashed label to the dictionary of subgraph hashes - originating from and indexed by each node in G - """ - new_labels = {} - for node in G.nodes(): - label = _neighborhood_aggregate(G, node, labels, edge_attr=edge_attr) - hashed_label = _hash_label(label, digest_size) - new_labels[node] = hashed_label - node_subgraph_hashes[node].append(hashed_label) - return new_labels - - node_labels = _init_node_labels(G, edge_attr, node_attr) - if include_initial_labels: - node_subgraph_hashes = { - k: [_hash_label(v, digest_size)] for k, v in node_labels.items() - } - else: - node_subgraph_hashes = defaultdict(list) - - for _ in range(iterations): - node_labels = weisfeiler_lehman_step( - G, node_labels, node_subgraph_hashes, edge_attr - ) - - return dict(node_subgraph_hashes) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graphical.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graphical.py deleted file mode 100644 index d5d82de..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/graphical.py +++ /dev/null @@ -1,483 +0,0 @@ -"""Test sequences for graphiness.""" - -import heapq - -import networkx as nx - -__all__ = [ - "is_graphical", - "is_multigraphical", - "is_pseudographical", - "is_digraphical", - "is_valid_degree_sequence_erdos_gallai", - "is_valid_degree_sequence_havel_hakimi", -] - - -@nx._dispatchable(graphs=None) -def is_graphical(sequence, method="eg"): - """Returns True if sequence is a valid degree sequence. - - A degree sequence is valid if some graph can realize it. - - Parameters - ---------- - sequence : list or iterable container - A sequence of integer node degrees - - method : "eg" | "hh" (default: 'eg') - The method used to validate the degree sequence. - "eg" corresponds to the Erdős-Gallai algorithm - [EG1960]_, [choudum1986]_, and - "hh" to the Havel-Hakimi algorithm - [havel1955]_, [hakimi1962]_, [CL1996]_. - - Returns - ------- - valid : bool - True if the sequence is a valid degree sequence and False if not. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> sequence = (d for n, d in G.degree()) - >>> nx.is_graphical(sequence) - True - - To test a non-graphical sequence: - >>> sequence_list = [d for n, d in G.degree()] - >>> sequence_list[-1] += 1 - >>> nx.is_graphical(sequence_list) - False - - References - ---------- - .. [EG1960] Erdős and Gallai, Mat. Lapok 11 264, 1960. - .. [choudum1986] S.A. Choudum. "A simple proof of the Erdős-Gallai theorem on - graph sequences." Bulletin of the Australian Mathematical Society, 33, - pp 67-70, 1986. https://doi.org/10.1017/S0004972700002872 - .. [havel1955] Havel, V. "A Remark on the Existence of Finite Graphs" - Casopis Pest. Mat. 80, 477-480, 1955. - .. [hakimi1962] Hakimi, S. "On the Realizability of a Set of Integers as - Degrees of the Vertices of a Graph." SIAM J. Appl. Math. 10, 496-506, 1962. - .. [CL1996] G. Chartrand and L. Lesniak, "Graphs and Digraphs", - Chapman and Hall/CRC, 1996. - """ - if method == "eg": - valid = is_valid_degree_sequence_erdos_gallai(list(sequence)) - elif method == "hh": - valid = is_valid_degree_sequence_havel_hakimi(list(sequence)) - else: - msg = "`method` must be 'eg' or 'hh'" - raise nx.NetworkXException(msg) - return valid - - -def _basic_graphical_tests(deg_sequence): - # Sort and perform some simple tests on the sequence - deg_sequence = nx.utils.make_list_of_ints(deg_sequence) - p = len(deg_sequence) - num_degs = [0] * p - dmax, dmin, dsum, n = 0, p, 0, 0 - for d in deg_sequence: - # Reject if degree is negative or larger than the sequence length - if d < 0 or d >= p: - raise nx.NetworkXUnfeasible - # Process only the non-zero integers - elif d > 0: - dmax, dmin, dsum, n = max(dmax, d), min(dmin, d), dsum + d, n + 1 - num_degs[d] += 1 - # Reject sequence if it has odd sum or is oversaturated - if dsum % 2 or dsum > n * (n - 1): - raise nx.NetworkXUnfeasible - return dmax, dmin, dsum, n, num_degs - - -@nx._dispatchable(graphs=None) -def is_valid_degree_sequence_havel_hakimi(deg_sequence): - r"""Returns True if deg_sequence can be realized by a simple graph. - - The validation proceeds using the Havel-Hakimi theorem - [havel1955]_, [hakimi1962]_, [CL1996]_. - Worst-case run time is $O(s)$ where $s$ is the sum of the sequence. - - Parameters - ---------- - deg_sequence : list - A list of integers where each element specifies the degree of a node - in a graph. - - Returns - ------- - valid : bool - True if deg_sequence is graphical and False if not. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (4, 2), (5, 1), (5, 4)]) - >>> sequence = (d for _, d in G.degree()) - >>> nx.is_valid_degree_sequence_havel_hakimi(sequence) - True - - To test a non-valid sequence: - >>> sequence_list = [d for _, d in G.degree()] - >>> sequence_list[-1] += 1 - >>> nx.is_valid_degree_sequence_havel_hakimi(sequence_list) - False - - Notes - ----- - The ZZ condition says that for the sequence d if - - .. math:: - |d| >= \frac{(\max(d) + \min(d) + 1)^2}{4*\min(d)} - - then d is graphical. This was shown in Theorem 6 in [1]_. - - References - ---------- - .. [1] I.E. Zverovich and V.E. Zverovich. "Contributions to the theory - of graphic sequences", Discrete Mathematics, 105, pp. 292-303 (1992). - .. [havel1955] Havel, V. "A Remark on the Existence of Finite Graphs" - Casopis Pest. Mat. 80, 477-480, 1955. - .. [hakimi1962] Hakimi, S. "On the Realizability of a Set of Integers as - Degrees of the Vertices of a Graph." SIAM J. Appl. Math. 10, 496-506, 1962. - .. [CL1996] G. Chartrand and L. Lesniak, "Graphs and Digraphs", - Chapman and Hall/CRC, 1996. - """ - try: - dmax, dmin, dsum, n, num_degs = _basic_graphical_tests(deg_sequence) - except nx.NetworkXUnfeasible: - return False - # Accept if sequence has no non-zero degrees or passes the ZZ condition - if n == 0 or 4 * dmin * n >= (dmax + dmin + 1) * (dmax + dmin + 1): - return True - - modstubs = [0] * (dmax + 1) - # Successively reduce degree sequence by removing the maximum degree - while n > 0: - # Retrieve the maximum degree in the sequence - while num_degs[dmax] == 0: - dmax -= 1 - # If there are not enough stubs to connect to, then the sequence is - # not graphical - if dmax > n - 1: - return False - - # Remove largest stub in list - num_degs[dmax], n = num_degs[dmax] - 1, n - 1 - # Reduce the next dmax largest stubs - mslen = 0 - k = dmax - for i in range(dmax): - while num_degs[k] == 0: - k -= 1 - num_degs[k], n = num_degs[k] - 1, n - 1 - if k > 1: - modstubs[mslen] = k - 1 - mslen += 1 - # Add back to the list any non-zero stubs that were removed - for i in range(mslen): - stub = modstubs[i] - num_degs[stub], n = num_degs[stub] + 1, n + 1 - return True - - -@nx._dispatchable(graphs=None) -def is_valid_degree_sequence_erdos_gallai(deg_sequence): - r"""Returns True if deg_sequence can be realized by a simple graph. - - The validation is done using the Erdős-Gallai theorem [EG1960]_. - - Parameters - ---------- - deg_sequence : list - A list of integers - - Returns - ------- - valid : bool - True if deg_sequence is graphical and False if not. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (4, 2), (5, 1), (5, 4)]) - >>> sequence = (d for _, d in G.degree()) - >>> nx.is_valid_degree_sequence_erdos_gallai(sequence) - True - - To test a non-valid sequence: - >>> sequence_list = [d for _, d in G.degree()] - >>> sequence_list[-1] += 1 - >>> nx.is_valid_degree_sequence_erdos_gallai(sequence_list) - False - - Notes - ----- - - This implementation uses an equivalent form of the Erdős-Gallai criterion. - Worst-case run time is $O(n)$ where $n$ is the length of the sequence. - - Specifically, a sequence d is graphical if and only if the - sum of the sequence is even and for all strong indices k in the sequence, - - .. math:: - - \sum_{i=1}^{k} d_i \leq k(k-1) + \sum_{j=k+1}^{n} \min(d_i,k) - = k(n-1) - ( k \sum_{j=0}^{k-1} n_j - \sum_{j=0}^{k-1} j n_j ) - - A strong index k is any index where d_k >= k and the value n_j is the - number of occurrences of j in d. The maximal strong index is called the - Durfee index. - - This particular rearrangement comes from the proof of Theorem 3 in [2]_. - - The ZZ condition says that for the sequence d if - - .. math:: - |d| >= \frac{(\max(d) + \min(d) + 1)^2}{4*\min(d)} - - then d is graphical. This was shown in Theorem 6 in [2]_. - - References - ---------- - .. [1] A. Tripathi and S. Vijay. "A note on a theorem of Erdős & Gallai", - Discrete Mathematics, 265, pp. 417-420 (2003). - .. [2] I.E. Zverovich and V.E. Zverovich. "Contributions to the theory - of graphic sequences", Discrete Mathematics, 105, pp. 292-303 (1992). - .. [EG1960] Erdős and Gallai, Mat. Lapok 11 264, 1960. - """ - try: - dmax, dmin, dsum, n, num_degs = _basic_graphical_tests(deg_sequence) - except nx.NetworkXUnfeasible: - return False - # Accept if sequence has no non-zero degrees or passes the ZZ condition - if n == 0 or 4 * dmin * n >= (dmax + dmin + 1) * (dmax + dmin + 1): - return True - - # Perform the EG checks using the reformulation of Zverovich and Zverovich - k, sum_deg, sum_nj, sum_jnj = 0, 0, 0, 0 - for dk in range(dmax, dmin - 1, -1): - if dk < k + 1: # Check if already past Durfee index - return True - if num_degs[dk] > 0: - run_size = num_degs[dk] # Process a run of identical-valued degrees - if dk < k + run_size: # Check if end of run is past Durfee index - run_size = dk - k # Adjust back to Durfee index - sum_deg += run_size * dk - for v in range(run_size): - sum_nj += num_degs[k + v] - sum_jnj += (k + v) * num_degs[k + v] - k += run_size - if sum_deg > k * (n - 1) - k * sum_nj + sum_jnj: - return False - return True - - -@nx._dispatchable(graphs=None) -def is_multigraphical(sequence): - """Returns True if some multigraph can realize the sequence. - - Parameters - ---------- - sequence : list - A list of integers - - Returns - ------- - valid : bool - True if deg_sequence is a multigraphic degree sequence and False if not. - - Examples - -------- - >>> G = nx.MultiGraph([(1, 2), (1, 3), (2, 3), (3, 4), (4, 2), (5, 1), (5, 4)]) - >>> sequence = (d for _, d in G.degree()) - >>> nx.is_multigraphical(sequence) - True - - To test a non-multigraphical sequence: - >>> sequence_list = [d for _, d in G.degree()] - >>> sequence_list[-1] += 1 - >>> nx.is_multigraphical(sequence_list) - False - - Notes - ----- - The worst-case run time is $O(n)$ where $n$ is the length of the sequence. - - References - ---------- - .. [1] S. L. Hakimi. "On the realizability of a set of integers as - degrees of the vertices of a linear graph", J. SIAM, 10, pp. 496-506 - (1962). - """ - try: - deg_sequence = nx.utils.make_list_of_ints(sequence) - except nx.NetworkXError: - return False - dsum, dmax = 0, 0 - for d in deg_sequence: - if d < 0: - return False - dsum, dmax = dsum + d, max(dmax, d) - if dsum % 2 or dsum < 2 * dmax: - return False - return True - - -@nx._dispatchable(graphs=None) -def is_pseudographical(sequence): - """Returns True if some pseudograph can realize the sequence. - - Every nonnegative integer sequence with an even sum is pseudographical - (see [1]_). - - Parameters - ---------- - sequence : list or iterable container - A sequence of integer node degrees - - Returns - ------- - valid : bool - True if the sequence is a pseudographic degree sequence and False if not. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (4, 2), (5, 1), (5, 4)]) - >>> sequence = (d for _, d in G.degree()) - >>> nx.is_pseudographical(sequence) - True - - To test a non-pseudographical sequence: - >>> sequence_list = [d for _, d in G.degree()] - >>> sequence_list[-1] += 1 - >>> nx.is_pseudographical(sequence_list) - False - - Notes - ----- - The worst-case run time is $O(n)$ where n is the length of the sequence. - - References - ---------- - .. [1] F. Boesch and F. Harary. "Line removal algorithms for graphs - and their degree lists", IEEE Trans. Circuits and Systems, CAS-23(12), - pp. 778-782 (1976). - """ - try: - deg_sequence = nx.utils.make_list_of_ints(sequence) - except nx.NetworkXError: - return False - return sum(deg_sequence) % 2 == 0 and min(deg_sequence) >= 0 - - -@nx._dispatchable(graphs=None) -def is_digraphical(in_sequence, out_sequence): - r"""Returns True if some directed graph can realize the in- and out-degree - sequences. - - Parameters - ---------- - in_sequence : list or iterable container - A sequence of integer node in-degrees - - out_sequence : list or iterable container - A sequence of integer node out-degrees - - Returns - ------- - valid : bool - True if in and out-sequences are digraphic False if not. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 4), (4, 2), (5, 1), (5, 4)]) - >>> in_seq = (d for n, d in G.in_degree()) - >>> out_seq = (d for n, d in G.out_degree()) - >>> nx.is_digraphical(in_seq, out_seq) - True - - To test a non-digraphical scenario: - >>> in_seq_list = [d for n, d in G.in_degree()] - >>> in_seq_list[-1] += 1 - >>> nx.is_digraphical(in_seq_list, out_seq) - False - - Notes - ----- - This algorithm is from Kleitman and Wang [1]_. - The worst case runtime is $O(s \times \log n)$ where $s$ and $n$ are the - sum and length of the sequences respectively. - - References - ---------- - .. [1] D.J. Kleitman and D.L. Wang - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors, Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - try: - in_deg_sequence = nx.utils.make_list_of_ints(in_sequence) - out_deg_sequence = nx.utils.make_list_of_ints(out_sequence) - except nx.NetworkXError: - return False - # Process the sequences and form two heaps to store degree pairs with - # either zero or non-zero out degrees - sumin, sumout, nin, nout = 0, 0, len(in_deg_sequence), len(out_deg_sequence) - maxn = max(nin, nout) - maxin = 0 - if maxn == 0: - return True - stubheap, zeroheap = [], [] - for n in range(maxn): - in_deg, out_deg = 0, 0 - if n < nout: - out_deg = out_deg_sequence[n] - if n < nin: - in_deg = in_deg_sequence[n] - if in_deg < 0 or out_deg < 0: - return False - sumin, sumout, maxin = sumin + in_deg, sumout + out_deg, max(maxin, in_deg) - if in_deg > 0: - stubheap.append((-1 * out_deg, -1 * in_deg)) - elif out_deg > 0: - zeroheap.append(-1 * out_deg) - if sumin != sumout: - return False - heapq.heapify(stubheap) - heapq.heapify(zeroheap) - - modstubs = [(0, 0)] * (maxin + 1) - # Successively reduce degree sequence by removing the maximum out degree - while stubheap: - # Take the first value in the sequence with non-zero in degree - (freeout, freein) = heapq.heappop(stubheap) - freein *= -1 - if freein > len(stubheap) + len(zeroheap): - return False - - # Attach out stubs to the nodes with the most in stubs - mslen = 0 - for i in range(freein): - if zeroheap and (not stubheap or stubheap[0][0] > zeroheap[0]): - stubout = heapq.heappop(zeroheap) - stubin = 0 - else: - (stubout, stubin) = heapq.heappop(stubheap) - if stubout == 0: - return False - # Check if target is now totally connected - if stubout + 1 < 0 or stubin < 0: - modstubs[mslen] = (stubout + 1, stubin) - mslen += 1 - - # Add back the nodes to the heap that still have available stubs - for i in range(mslen): - stub = modstubs[i] - if stub[1] < 0: - heapq.heappush(stubheap, stub) - else: - heapq.heappush(zeroheap, stub[0]) - if freeout < 0: - heapq.heappush(zeroheap, freeout) - return True diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hierarchy.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hierarchy.py deleted file mode 100644 index d5a0552..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hierarchy.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Flow Hierarchy. -""" - -import networkx as nx - -__all__ = ["flow_hierarchy"] - - -@nx._dispatchable(edge_attrs="weight") -def flow_hierarchy(G, weight=None): - """Returns the flow hierarchy of a directed network. - - Flow hierarchy is defined as the fraction of edges not participating - in cycles in a directed graph [1]_. - - Parameters - ---------- - G : DiGraph or MultiDiGraph - A directed graph - - weight : string, optional (default=None) - Attribute to use for edge weights. If None the weight defaults to 1. - - Returns - ------- - h : float - Flow hierarchy value - - Raises - ------ - NetworkXError - If `G` is not a directed graph or if `G` has no edges. - - Notes - ----- - The algorithm described in [1]_ computes the flow hierarchy through - exponentiation of the adjacency matrix. This function implements an - alternative approach that finds strongly connected components. - An edge is in a cycle if and only if it is in a strongly connected - component, which can be found in $O(m)$ time using Tarjan's algorithm. - - References - ---------- - .. [1] Luo, J.; Magee, C.L. (2011), - Detecting evolving patterns of self-organizing networks by flow - hierarchy measurement, Complexity, Volume 16 Issue 6 53-61. - DOI: 10.1002/cplx.20368 - http://web.mit.edu/~cmagee/www/documents/28-DetectingEvolvingPatterns_FlowHierarchy.pdf - """ - # corner case: G has no edges - if nx.is_empty(G): - raise nx.NetworkXError("flow_hierarchy not applicable to empty graphs") - if not G.is_directed(): - raise nx.NetworkXError("G must be a digraph in flow_hierarchy") - scc = nx.strongly_connected_components(G) - return 1 - sum(G.subgraph(c).size(weight) for c in scc) / G.size(weight) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hybrid.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hybrid.py deleted file mode 100644 index 9d3dd30..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/hybrid.py +++ /dev/null @@ -1,196 +0,0 @@ -""" -Provides functions for finding and testing for locally `(k, l)`-connected -graphs. - -""" - -import copy - -import networkx as nx - -__all__ = ["kl_connected_subgraph", "is_kl_connected"] - - -@nx._dispatchable(returns_graph=True) -def kl_connected_subgraph(G, k, l, low_memory=False, same_as_graph=False): - """Returns the maximum locally `(k, l)`-connected subgraph of `G`. - - A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the - graph there are at least `l` edge-disjoint paths of length at most `k` - joining `u` to `v`. - - Parameters - ---------- - G : NetworkX graph - The graph in which to find a maximum locally `(k, l)`-connected - subgraph. - - k : integer - The maximum length of paths to consider. A higher number means a looser - connectivity requirement. - - l : integer - The number of edge-disjoint paths. A higher number means a stricter - connectivity requirement. - - low_memory : bool - If this is True, this function uses an algorithm that uses slightly - more time but less memory. - - same_as_graph : bool - If True then return a tuple of the form `(H, is_same)`, - where `H` is the maximum locally `(k, l)`-connected subgraph and - `is_same` is a Boolean representing whether `G` is locally `(k, - l)`-connected (and hence, whether `H` is simply a copy of the input - graph `G`). - - Returns - ------- - NetworkX graph or two-tuple - If `same_as_graph` is True, then this function returns a - two-tuple as described above. Otherwise, it returns only the maximum - locally `(k, l)`-connected subgraph. - - See also - -------- - is_kl_connected - - References - ---------- - .. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid - Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, - 2004. 89--104. - - """ - H = copy.deepcopy(G) # subgraph we construct by removing from G - - graphOK = True - deleted_some = True # hack to start off the while loop - while deleted_some: - deleted_some = False - # We use `for edge in list(H.edges()):` instead of - # `for edge in H.edges():` because we edit the graph `H` in - # the loop. Hence using an iterator will result in - # `RuntimeError: dictionary changed size during iteration` - for edge in list(H.edges()): - (u, v) = edge - # Get copy of graph needed for this search - if low_memory: - verts = {u, v} - for i in range(k): - for w in verts.copy(): - verts.update(G[w]) - G2 = G.subgraph(verts).copy() - else: - G2 = copy.deepcopy(G) - ### - path = [u, v] - cnt = 0 - accept = 0 - while path: - cnt += 1 # Found a path - if cnt >= l: - accept = 1 - break - # record edges along this graph - prev = u - for w in path: - if prev != w: - G2.remove_edge(prev, w) - prev = w - # path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1? - try: - path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1? - except nx.NetworkXNoPath: - path = False - # No Other Paths - if accept == 0: - H.remove_edge(u, v) - deleted_some = True - if graphOK: - graphOK = False - # We looked through all edges and removed none of them. - # So, H is the maximal (k,l)-connected subgraph of G - if same_as_graph: - return (H, graphOK) - return H - - -@nx._dispatchable -def is_kl_connected(G, k, l, low_memory=False): - """Returns True if and only if `G` is locally `(k, l)`-connected. - - A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the - graph there are at least `l` edge-disjoint paths of length at most `k` - joining `u` to `v`. - - Parameters - ---------- - G : NetworkX graph - The graph to test for local `(k, l)`-connectedness. - - k : integer - The maximum length of paths to consider. A higher number means a looser - connectivity requirement. - - l : integer - The number of edge-disjoint paths. A higher number means a stricter - connectivity requirement. - - low_memory : bool - If this is True, this function uses an algorithm that uses slightly - more time but less memory. - - Returns - ------- - bool - Whether the graph is locally `(k, l)`-connected subgraph. - - See also - -------- - kl_connected_subgraph - - References - ---------- - .. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid - Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, - 2004. 89--104. - - """ - graphOK = True - for edge in G.edges(): - (u, v) = edge - # Get copy of graph needed for this search - if low_memory: - verts = {u, v} - for i in range(k): - [verts.update(G.neighbors(w)) for w in verts.copy()] - G2 = G.subgraph(verts) - else: - G2 = copy.deepcopy(G) - ### - path = [u, v] - cnt = 0 - accept = 0 - while path: - cnt += 1 # Found a path - if cnt >= l: - accept = 1 - break - # record edges along this graph - prev = u - for w in path: - if w != prev: - G2.remove_edge(prev, w) - prev = w - # path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1? - try: - path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1? - except nx.NetworkXNoPath: - path = False - # No Other Paths - if accept == 0: - graphOK = False - break - # return status - return graphOK diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isolate.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isolate.py deleted file mode 100644 index 1ea8abe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isolate.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Functions for identifying isolate (degree zero) nodes. -""" - -import networkx as nx - -__all__ = ["is_isolate", "isolates", "number_of_isolates"] - - -@nx._dispatchable -def is_isolate(G, n): - """Determines whether a node is an isolate. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - n : node - A node in `G`. - - Returns - ------- - is_isolate : bool - True if and only if `n` has no neighbors. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge(1, 2) - >>> G.add_node(3) - >>> nx.is_isolate(G, 2) - False - >>> nx.is_isolate(G, 3) - True - """ - return G.degree(n) == 0 - - -@nx._dispatchable -def isolates(G): - """Iterator over isolates in the graph. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - iterator - An iterator over the isolates of `G`. - - Examples - -------- - To get a list of all isolates of a graph, use the :class:`list` - constructor:: - - >>> G = nx.Graph() - >>> G.add_edge(1, 2) - >>> G.add_node(3) - >>> list(nx.isolates(G)) - [3] - - To remove all isolates in the graph, first create a list of the - isolates, then use :meth:`Graph.remove_nodes_from`:: - - >>> G.remove_nodes_from(list(nx.isolates(G))) - >>> list(G) - [1, 2] - - For digraphs, isolates have zero in-degree and zero out_degre:: - - >>> G = nx.DiGraph([(0, 1), (1, 2)]) - >>> G.add_node(3) - >>> list(nx.isolates(G)) - [3] - - """ - return (n for n, d in G.degree() if d == 0) - - -@nx._dispatchable -def number_of_isolates(G): - """Returns the number of isolates in the graph. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - int - The number of degree zero nodes in the graph `G`. - - """ - return sum(1 for v in isolates(G)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/__init__.py deleted file mode 100644 index 58c2268..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from networkx.algorithms.isomorphism.isomorph import * -from networkx.algorithms.isomorphism.vf2userfunc import * -from networkx.algorithms.isomorphism.matchhelpers import * -from networkx.algorithms.isomorphism.temporalisomorphvf2 import * -from networkx.algorithms.isomorphism.ismags import * -from networkx.algorithms.isomorphism.tree_isomorphism import * -from networkx.algorithms.isomorphism.vf2pp import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/ismags.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/ismags.py deleted file mode 100644 index 24819fa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/ismags.py +++ /dev/null @@ -1,1163 +0,0 @@ -""" -ISMAGS Algorithm -================ - -Provides a Python implementation of the ISMAGS algorithm. [1]_ - -It is capable of finding (subgraph) isomorphisms between two graphs, taking the -symmetry of the subgraph into account. In most cases the VF2 algorithm is -faster (at least on small graphs) than this implementation, but in some cases -there is an exponential number of isomorphisms that are symmetrically -equivalent. In that case, the ISMAGS algorithm will provide only one solution -per symmetry group. - ->>> petersen = nx.petersen_graph() ->>> ismags = nx.isomorphism.ISMAGS(petersen, petersen) ->>> isomorphisms = list(ismags.isomorphisms_iter(symmetry=False)) ->>> len(isomorphisms) -120 ->>> isomorphisms = list(ismags.isomorphisms_iter(symmetry=True)) ->>> answer = [{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}] ->>> answer == isomorphisms -True - -In addition, this implementation also provides an interface to find the -largest common induced subgraph [2]_ between any two graphs, again taking -symmetry into account. Given `graph` and `subgraph` the algorithm will remove -nodes from the `subgraph` until `subgraph` is isomorphic to a subgraph of -`graph`. Since only the symmetry of `subgraph` is taken into account it is -worth thinking about how you provide your graphs: - ->>> graph1 = nx.path_graph(4) ->>> graph2 = nx.star_graph(3) ->>> ismags = nx.isomorphism.ISMAGS(graph1, graph2) ->>> ismags.is_isomorphic() -False ->>> largest_common_subgraph = list(ismags.largest_common_subgraph()) ->>> answer = [{1: 0, 0: 1, 2: 2}, {2: 0, 1: 1, 3: 2}] ->>> answer == largest_common_subgraph -True ->>> ismags2 = nx.isomorphism.ISMAGS(graph2, graph1) ->>> largest_common_subgraph = list(ismags2.largest_common_subgraph()) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 0: 1, 3: 2}, -... {2: 0, 0: 1, 1: 2}, -... {2: 0, 0: 1, 3: 2}, -... {3: 0, 0: 1, 1: 2}, -... {3: 0, 0: 1, 2: 2}, -... ] ->>> answer == largest_common_subgraph -True - -However, when not taking symmetry into account, it doesn't matter: - ->>> largest_common_subgraph = list(ismags.largest_common_subgraph(symmetry=False)) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 2: 1, 0: 2}, -... {2: 0, 1: 1, 3: 2}, -... {2: 0, 3: 1, 1: 2}, -... {1: 0, 0: 1, 2: 3}, -... {1: 0, 2: 1, 0: 3}, -... {2: 0, 1: 1, 3: 3}, -... {2: 0, 3: 1, 1: 3}, -... {1: 0, 0: 2, 2: 3}, -... {1: 0, 2: 2, 0: 3}, -... {2: 0, 1: 2, 3: 3}, -... {2: 0, 3: 2, 1: 3}, -... ] ->>> answer == largest_common_subgraph -True ->>> largest_common_subgraph = list(ismags2.largest_common_subgraph(symmetry=False)) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 0: 1, 3: 2}, -... {2: 0, 0: 1, 1: 2}, -... {2: 0, 0: 1, 3: 2}, -... {3: 0, 0: 1, 1: 2}, -... {3: 0, 0: 1, 2: 2}, -... {1: 1, 0: 2, 2: 3}, -... {1: 1, 0: 2, 3: 3}, -... {2: 1, 0: 2, 1: 3}, -... {2: 1, 0: 2, 3: 3}, -... {3: 1, 0: 2, 1: 3}, -... {3: 1, 0: 2, 2: 3}, -... ] ->>> answer == largest_common_subgraph -True - -Notes ------ -- The current implementation works for undirected graphs only. The algorithm - in general should work for directed graphs as well though. -- Node keys for both provided graphs need to be fully orderable as well as - hashable. -- Node and edge equality is assumed to be transitive: if A is equal to B, and - B is equal to C, then A is equal to C. - -References ----------- -.. [1] M. Houbraken, S. Demeyer, T. Michoel, P. Audenaert, D. Colle, - M. Pickavet, "The Index-Based Subgraph Matching Algorithm with General - Symmetries (ISMAGS): Exploiting Symmetry for Faster Subgraph - Enumeration", PLoS One 9(5): e97896, 2014. - https://doi.org/10.1371/journal.pone.0097896 -.. [2] https://en.wikipedia.org/wiki/Maximum_common_induced_subgraph -""" - -__all__ = ["ISMAGS"] - -import itertools -from collections import Counter, defaultdict -from functools import reduce, wraps - - -def are_all_equal(iterable): - """ - Returns ``True`` if and only if all elements in `iterable` are equal; and - ``False`` otherwise. - - Parameters - ---------- - iterable: collections.abc.Iterable - The container whose elements will be checked. - - Returns - ------- - bool - ``True`` iff all elements in `iterable` compare equal, ``False`` - otherwise. - """ - try: - shape = iterable.shape - except AttributeError: - pass - else: - if len(shape) > 1: - message = "The function does not works on multidimensional arrays." - raise NotImplementedError(message) from None - - iterator = iter(iterable) - first = next(iterator, None) - return all(item == first for item in iterator) - - -def make_partitions(items, test): - """ - Partitions items into sets based on the outcome of ``test(item1, item2)``. - Pairs of items for which `test` returns `True` end up in the same set. - - Parameters - ---------- - items : collections.abc.Iterable[collections.abc.Hashable] - Items to partition - test : collections.abc.Callable[collections.abc.Hashable, collections.abc.Hashable] - A function that will be called with 2 arguments, taken from items. - Should return `True` if those 2 items need to end up in the same - partition, and `False` otherwise. - - Returns - ------- - list[set] - A list of sets, with each set containing part of the items in `items`, - such that ``all(test(*pair) for pair in itertools.combinations(set, 2)) - == True`` - - Notes - ----- - The function `test` is assumed to be transitive: if ``test(a, b)`` and - ``test(b, c)`` return ``True``, then ``test(a, c)`` must also be ``True``. - """ - partitions = [] - for item in items: - for partition in partitions: - p_item = next(iter(partition)) - if test(item, p_item): - partition.add(item) - break - else: # No break - partitions.append({item}) - return partitions - - -def partition_to_color(partitions): - """ - Creates a dictionary that maps each item in each partition to the index of - the partition to which it belongs. - - Parameters - ---------- - partitions: collections.abc.Sequence[collections.abc.Iterable] - As returned by :func:`make_partitions`. - - Returns - ------- - dict - """ - colors = {} - for color, keys in enumerate(partitions): - for key in keys: - colors[key] = color - return colors - - -def intersect(collection_of_sets): - """ - Given an collection of sets, returns the intersection of those sets. - - Parameters - ---------- - collection_of_sets: collections.abc.Collection[set] - A collection of sets. - - Returns - ------- - set - An intersection of all sets in `collection_of_sets`. Will have the same - type as the item initially taken from `collection_of_sets`. - """ - collection_of_sets = list(collection_of_sets) - first = collection_of_sets.pop() - out = reduce(set.intersection, collection_of_sets, set(first)) - return type(first)(out) - - -class ISMAGS: - """ - Implements the ISMAGS subgraph matching algorithm. [1]_ ISMAGS stands for - "Index-based Subgraph Matching Algorithm with General Symmetries". As the - name implies, it is symmetry aware and will only generate non-symmetric - isomorphisms. - - Notes - ----- - The implementation imposes additional conditions compared to the VF2 - algorithm on the graphs provided and the comparison functions - (:attr:`node_equality` and :attr:`edge_equality`): - - - Node keys in both graphs must be orderable as well as hashable. - - Equality must be transitive: if A is equal to B, and B is equal to C, - then A must be equal to C. - - Attributes - ---------- - graph: networkx.Graph - subgraph: networkx.Graph - node_equality: collections.abc.Callable - The function called to see if two nodes should be considered equal. - It's signature looks like this: - ``f(graph1: networkx.Graph, node1, graph2: networkx.Graph, node2) -> bool``. - `node1` is a node in `graph1`, and `node2` a node in `graph2`. - Constructed from the argument `node_match`. - edge_equality: collections.abc.Callable - The function called to see if two edges should be considered equal. - It's signature looks like this: - ``f(graph1: networkx.Graph, edge1, graph2: networkx.Graph, edge2) -> bool``. - `edge1` is an edge in `graph1`, and `edge2` an edge in `graph2`. - Constructed from the argument `edge_match`. - - References - ---------- - .. [1] M. Houbraken, S. Demeyer, T. Michoel, P. Audenaert, D. Colle, - M. Pickavet, "The Index-Based Subgraph Matching Algorithm with General - Symmetries (ISMAGS): Exploiting Symmetry for Faster Subgraph - Enumeration", PLoS One 9(5): e97896, 2014. - https://doi.org/10.1371/journal.pone.0097896 - """ - - def __init__(self, graph, subgraph, node_match=None, edge_match=None, cache=None): - """ - Parameters - ---------- - graph: networkx.Graph - subgraph: networkx.Graph - node_match: collections.abc.Callable or None - Function used to determine whether two nodes are equivalent. Its - signature should look like ``f(n1: dict, n2: dict) -> bool``, with - `n1` and `n2` node property dicts. See also - :func:`~networkx.algorithms.isomorphism.categorical_node_match` and - friends. - If `None`, all nodes are considered equal. - edge_match: collections.abc.Callable or None - Function used to determine whether two edges are equivalent. Its - signature should look like ``f(e1: dict, e2: dict) -> bool``, with - `e1` and `e2` edge property dicts. See also - :func:`~networkx.algorithms.isomorphism.categorical_edge_match` and - friends. - If `None`, all edges are considered equal. - cache: collections.abc.Mapping - A cache used for caching graph symmetries. - """ - # TODO: graph and subgraph setter methods that invalidate the caches. - # TODO: allow for precomputed partitions and colors - self.graph = graph - self.subgraph = subgraph - self._symmetry_cache = cache - # Naming conventions are taken from the original paper. For your - # sanity: - # sg: subgraph - # g: graph - # e: edge(s) - # n: node(s) - # So: sgn means "subgraph nodes". - self._sgn_partitions_ = None - self._sge_partitions_ = None - - self._sgn_colors_ = None - self._sge_colors_ = None - - self._gn_partitions_ = None - self._ge_partitions_ = None - - self._gn_colors_ = None - self._ge_colors_ = None - - self._node_compat_ = None - self._edge_compat_ = None - - if node_match is None: - self.node_equality = self._node_match_maker(lambda n1, n2: True) - self._sgn_partitions_ = [set(self.subgraph.nodes)] - self._gn_partitions_ = [set(self.graph.nodes)] - self._node_compat_ = {0: 0} - else: - self.node_equality = self._node_match_maker(node_match) - if edge_match is None: - self.edge_equality = self._edge_match_maker(lambda e1, e2: True) - self._sge_partitions_ = [set(self.subgraph.edges)] - self._ge_partitions_ = [set(self.graph.edges)] - self._edge_compat_ = {0: 0} - else: - self.edge_equality = self._edge_match_maker(edge_match) - - @property - def _sgn_partitions(self): - if self._sgn_partitions_ is None: - - def nodematch(node1, node2): - return self.node_equality(self.subgraph, node1, self.subgraph, node2) - - self._sgn_partitions_ = make_partitions(self.subgraph.nodes, nodematch) - return self._sgn_partitions_ - - @property - def _sge_partitions(self): - if self._sge_partitions_ is None: - - def edgematch(edge1, edge2): - return self.edge_equality(self.subgraph, edge1, self.subgraph, edge2) - - self._sge_partitions_ = make_partitions(self.subgraph.edges, edgematch) - return self._sge_partitions_ - - @property - def _gn_partitions(self): - if self._gn_partitions_ is None: - - def nodematch(node1, node2): - return self.node_equality(self.graph, node1, self.graph, node2) - - self._gn_partitions_ = make_partitions(self.graph.nodes, nodematch) - return self._gn_partitions_ - - @property - def _ge_partitions(self): - if self._ge_partitions_ is None: - - def edgematch(edge1, edge2): - return self.edge_equality(self.graph, edge1, self.graph, edge2) - - self._ge_partitions_ = make_partitions(self.graph.edges, edgematch) - return self._ge_partitions_ - - @property - def _sgn_colors(self): - if self._sgn_colors_ is None: - self._sgn_colors_ = partition_to_color(self._sgn_partitions) - return self._sgn_colors_ - - @property - def _sge_colors(self): - if self._sge_colors_ is None: - self._sge_colors_ = partition_to_color(self._sge_partitions) - return self._sge_colors_ - - @property - def _gn_colors(self): - if self._gn_colors_ is None: - self._gn_colors_ = partition_to_color(self._gn_partitions) - return self._gn_colors_ - - @property - def _ge_colors(self): - if self._ge_colors_ is None: - self._ge_colors_ = partition_to_color(self._ge_partitions) - return self._ge_colors_ - - @property - def _node_compatibility(self): - if self._node_compat_ is not None: - return self._node_compat_ - self._node_compat_ = {} - for sgn_part_color, gn_part_color in itertools.product( - range(len(self._sgn_partitions)), range(len(self._gn_partitions)) - ): - sgn = next(iter(self._sgn_partitions[sgn_part_color])) - gn = next(iter(self._gn_partitions[gn_part_color])) - if self.node_equality(self.subgraph, sgn, self.graph, gn): - self._node_compat_[sgn_part_color] = gn_part_color - return self._node_compat_ - - @property - def _edge_compatibility(self): - if self._edge_compat_ is not None: - return self._edge_compat_ - self._edge_compat_ = {} - for sge_part_color, ge_part_color in itertools.product( - range(len(self._sge_partitions)), range(len(self._ge_partitions)) - ): - sge = next(iter(self._sge_partitions[sge_part_color])) - ge = next(iter(self._ge_partitions[ge_part_color])) - if self.edge_equality(self.subgraph, sge, self.graph, ge): - self._edge_compat_[sge_part_color] = ge_part_color - return self._edge_compat_ - - @staticmethod - def _node_match_maker(cmp): - @wraps(cmp) - def comparer(graph1, node1, graph2, node2): - return cmp(graph1.nodes[node1], graph2.nodes[node2]) - - return comparer - - @staticmethod - def _edge_match_maker(cmp): - @wraps(cmp) - def comparer(graph1, edge1, graph2, edge2): - return cmp(graph1.edges[edge1], graph2.edges[edge2]) - - return comparer - - def find_isomorphisms(self, symmetry=True): - """Find all subgraph isomorphisms between subgraph and graph - - Finds isomorphisms where :attr:`subgraph` <= :attr:`graph`. - - Parameters - ---------- - symmetry: bool - Whether symmetry should be taken into account. If False, found - isomorphisms may be symmetrically equivalent. - - Yields - ------ - dict - The found isomorphism mappings of {graph_node: subgraph_node}. - """ - # The networkx VF2 algorithm is slightly funny in when it yields an - # empty dict and when not. - if not self.subgraph: - yield {} - return - elif not self.graph: - return - elif len(self.graph) < len(self.subgraph): - return - - if symmetry: - _, cosets = self.analyze_symmetry( - self.subgraph, self._sgn_partitions, self._sge_colors - ) - constraints = self._make_constraints(cosets) - else: - constraints = [] - - candidates = self._find_nodecolor_candidates() - la_candidates = self._get_lookahead_candidates() - for sgn in self.subgraph: - extra_candidates = la_candidates[sgn] - if extra_candidates: - candidates[sgn] = candidates[sgn] | {frozenset(extra_candidates)} - - if any(candidates.values()): - start_sgn = min(candidates, key=lambda n: min(candidates[n], key=len)) - candidates[start_sgn] = (intersect(candidates[start_sgn]),) - yield from self._map_nodes(start_sgn, candidates, constraints) - else: - return - - @staticmethod - def _find_neighbor_color_count(graph, node, node_color, edge_color): - """ - For `node` in `graph`, count the number of edges of a specific color - it has to nodes of a specific color. - """ - counts = Counter() - neighbors = graph[node] - for neighbor in neighbors: - n_color = node_color[neighbor] - if (node, neighbor) in edge_color: - e_color = edge_color[node, neighbor] - else: - e_color = edge_color[neighbor, node] - counts[e_color, n_color] += 1 - return counts - - def _get_lookahead_candidates(self): - """ - Returns a mapping of {subgraph node: collection of graph nodes} for - which the graph nodes are feasible candidates for the subgraph node, as - determined by looking ahead one edge. - """ - g_counts = {} - for gn in self.graph: - g_counts[gn] = self._find_neighbor_color_count( - self.graph, gn, self._gn_colors, self._ge_colors - ) - candidates = defaultdict(set) - for sgn in self.subgraph: - sg_count = self._find_neighbor_color_count( - self.subgraph, sgn, self._sgn_colors, self._sge_colors - ) - new_sg_count = Counter() - for (sge_color, sgn_color), count in sg_count.items(): - try: - ge_color = self._edge_compatibility[sge_color] - gn_color = self._node_compatibility[sgn_color] - except KeyError: - pass - else: - new_sg_count[ge_color, gn_color] = count - - for gn, g_count in g_counts.items(): - if all(new_sg_count[x] <= g_count[x] for x in new_sg_count): - # Valid candidate - candidates[sgn].add(gn) - return candidates - - def largest_common_subgraph(self, symmetry=True): - """ - Find the largest common induced subgraphs between :attr:`subgraph` and - :attr:`graph`. - - Parameters - ---------- - symmetry: bool - Whether symmetry should be taken into account. If False, found - largest common subgraphs may be symmetrically equivalent. - - Yields - ------ - dict - The found isomorphism mappings of {graph_node: subgraph_node}. - """ - # The networkx VF2 algorithm is slightly funny in when it yields an - # empty dict and when not. - if not self.subgraph: - yield {} - return - elif not self.graph: - return - - if symmetry: - _, cosets = self.analyze_symmetry( - self.subgraph, self._sgn_partitions, self._sge_colors - ) - constraints = self._make_constraints(cosets) - else: - constraints = [] - - candidates = self._find_nodecolor_candidates() - - if any(candidates.values()): - yield from self._largest_common_subgraph(candidates, constraints) - else: - return - - def analyze_symmetry(self, graph, node_partitions, edge_colors): - """ - Find a minimal set of permutations and corresponding co-sets that - describe the symmetry of `graph`, given the node and edge equalities - given by `node_partitions` and `edge_colors`, respectively. - - Parameters - ---------- - graph : networkx.Graph - The graph whose symmetry should be analyzed. - node_partitions : list of sets - A list of sets containing node keys. Node keys in the same set - are considered equivalent. Every node key in `graph` should be in - exactly one of the sets. If all nodes are equivalent, this should - be ``[set(graph.nodes)]``. - edge_colors : dict mapping edges to their colors - A dict mapping every edge in `graph` to its corresponding color. - Edges with the same color are considered equivalent. If all edges - are equivalent, this should be ``{e: 0 for e in graph.edges}``. - - - Returns - ------- - set[frozenset] - The found permutations. This is a set of frozensets of pairs of node - keys which can be exchanged without changing :attr:`subgraph`. - dict[collections.abc.Hashable, set[collections.abc.Hashable]] - The found co-sets. The co-sets is a dictionary of - ``{node key: set of node keys}``. - Every key-value pair describes which ``values`` can be interchanged - without changing nodes less than ``key``. - """ - if self._symmetry_cache is not None: - key = hash( - ( - tuple(graph.nodes), - tuple(graph.edges), - tuple(map(tuple, node_partitions)), - tuple(edge_colors.items()), - ) - ) - if key in self._symmetry_cache: - return self._symmetry_cache[key] - node_partitions = list( - self._refine_node_partitions(graph, node_partitions, edge_colors) - ) - assert len(node_partitions) == 1 - node_partitions = node_partitions[0] - permutations, cosets = self._process_ordered_pair_partitions( - graph, node_partitions, node_partitions, edge_colors - ) - if self._symmetry_cache is not None: - self._symmetry_cache[key] = permutations, cosets - return permutations, cosets - - def is_isomorphic(self, symmetry=False): - """ - Returns True if :attr:`graph` is isomorphic to :attr:`subgraph` and - False otherwise. - - Returns - ------- - bool - """ - return len(self.subgraph) == len(self.graph) and self.subgraph_is_isomorphic( - symmetry - ) - - def subgraph_is_isomorphic(self, symmetry=False): - """ - Returns True if a subgraph of :attr:`graph` is isomorphic to - :attr:`subgraph` and False otherwise. - - Returns - ------- - bool - """ - # symmetry=False, since we only need to know whether there is any - # example; figuring out all symmetry elements probably costs more time - # than it gains. - isom = next(self.subgraph_isomorphisms_iter(symmetry=symmetry), None) - return isom is not None - - def isomorphisms_iter(self, symmetry=True): - """ - Does the same as :meth:`find_isomorphisms` if :attr:`graph` and - :attr:`subgraph` have the same number of nodes. - """ - if len(self.graph) == len(self.subgraph): - yield from self.subgraph_isomorphisms_iter(symmetry=symmetry) - - def subgraph_isomorphisms_iter(self, symmetry=True): - """Alternative name for :meth:`find_isomorphisms`.""" - return self.find_isomorphisms(symmetry) - - def _find_nodecolor_candidates(self): - """ - Per node in subgraph find all nodes in graph that have the same color. - """ - candidates = defaultdict(set) - for sgn in self.subgraph.nodes: - sgn_color = self._sgn_colors[sgn] - if sgn_color in self._node_compatibility: - gn_color = self._node_compatibility[sgn_color] - candidates[sgn].add(frozenset(self._gn_partitions[gn_color])) - else: - candidates[sgn].add(frozenset()) - candidates = dict(candidates) - for sgn, options in candidates.items(): - candidates[sgn] = frozenset(options) - return candidates - - @staticmethod - def _make_constraints(cosets): - """ - Turn cosets into constraints. - """ - constraints = [] - for node_i, node_ts in cosets.items(): - for node_t in node_ts: - if node_i != node_t: - # Node i must be smaller than node t. - constraints.append((node_i, node_t)) - return constraints - - @staticmethod - def _find_node_edge_color(graph, node_colors, edge_colors): - """ - For every node in graph, come up with a color that combines 1) the - color of the node, and 2) the number of edges of a color to each type - of node. - """ - counts = defaultdict(lambda: defaultdict(int)) - for node1, node2 in graph.edges: - if (node1, node2) in edge_colors: - # FIXME directed graphs - ecolor = edge_colors[node1, node2] - else: - ecolor = edge_colors[node2, node1] - # Count per node how many edges it has of what color to nodes of - # what color - counts[node1][ecolor, node_colors[node2]] += 1 - counts[node2][ecolor, node_colors[node1]] += 1 - - node_edge_colors = {} - for node in graph.nodes: - node_edge_colors[node] = node_colors[node], set(counts[node].items()) - - return node_edge_colors - - @staticmethod - def _get_permutations_by_length(items): - """ - Get all permutations of items, but only permute items with the same - length. - - >>> found = list(ISMAGS._get_permutations_by_length([[1], [2], [3, 4], [4, 5]])) - >>> answer = [ - ... (([1], [2]), ([3, 4], [4, 5])), - ... (([1], [2]), ([4, 5], [3, 4])), - ... (([2], [1]), ([3, 4], [4, 5])), - ... (([2], [1]), ([4, 5], [3, 4])), - ... ] - >>> found == answer - True - """ - by_len = defaultdict(list) - for item in items: - by_len[len(item)].append(item) - - yield from itertools.product( - *(itertools.permutations(by_len[l]) for l in sorted(by_len)) - ) - - @classmethod - def _refine_node_partitions(cls, graph, node_partitions, edge_colors, branch=False): - """ - Given a partition of nodes in graph, make the partitions smaller such - that all nodes in a partition have 1) the same color, and 2) the same - number of edges to specific other partitions. - """ - - def equal_color(node1, node2): - return node_edge_colors[node1] == node_edge_colors[node2] - - node_partitions = list(node_partitions) - node_colors = partition_to_color(node_partitions) - node_edge_colors = cls._find_node_edge_color(graph, node_colors, edge_colors) - if all( - are_all_equal(node_edge_colors[node] for node in partition) - for partition in node_partitions - ): - yield node_partitions - return - - new_partitions = [] - output = [new_partitions] - for partition in node_partitions: - if not are_all_equal(node_edge_colors[node] for node in partition): - refined = make_partitions(partition, equal_color) - if ( - branch - and len(refined) != 1 - and len({len(r) for r in refined}) != len([len(r) for r in refined]) - ): - # This is where it breaks. There are multiple new cells - # in refined with the same length, and their order - # matters. - # So option 1) Hit it with a big hammer and simply make all - # orderings. - permutations = cls._get_permutations_by_length(refined) - new_output = [] - for n_p in output: - for permutation in permutations: - new_output.append(n_p + list(permutation[0])) - output = new_output - else: - for n_p in output: - n_p.extend(sorted(refined, key=len)) - else: - for n_p in output: - n_p.append(partition) - for n_p in output: - yield from cls._refine_node_partitions(graph, n_p, edge_colors, branch) - - def _edges_of_same_color(self, sgn1, sgn2): - """ - Returns all edges in :attr:`graph` that have the same colour as the - edge between sgn1 and sgn2 in :attr:`subgraph`. - """ - if (sgn1, sgn2) in self._sge_colors: - # FIXME directed graphs - sge_color = self._sge_colors[sgn1, sgn2] - else: - sge_color = self._sge_colors[sgn2, sgn1] - if sge_color in self._edge_compatibility: - ge_color = self._edge_compatibility[sge_color] - g_edges = self._ge_partitions[ge_color] - else: - g_edges = [] - return g_edges - - def _map_nodes(self, sgn, candidates, constraints, mapping=None, to_be_mapped=None): - """ - Find all subgraph isomorphisms honoring constraints. - """ - if mapping is None: - mapping = {} - else: - mapping = mapping.copy() - if to_be_mapped is None: - to_be_mapped = set(self.subgraph.nodes) - - # Note, we modify candidates here. Doesn't seem to affect results, but - # remember this. - # candidates = candidates.copy() - sgn_candidates = intersect(candidates[sgn]) - candidates[sgn] = frozenset([sgn_candidates]) - for gn in sgn_candidates: - # We're going to try to map sgn to gn. - if gn in mapping.values() or sgn not in to_be_mapped: - # gn is already mapped to something - continue # pragma: no cover - - # REDUCTION and COMBINATION - mapping[sgn] = gn - # BASECASE - if to_be_mapped == set(mapping.keys()): - yield {v: k for k, v in mapping.items()} - continue - left_to_map = to_be_mapped - set(mapping.keys()) - - new_candidates = candidates.copy() - sgn_nbrs = set(self.subgraph[sgn]) - not_gn_nbrs = set(self.graph.nodes) - set(self.graph[gn]) - for sgn2 in left_to_map: - if sgn2 not in sgn_nbrs: - gn2_options = not_gn_nbrs - else: - # Get all edges to gn of the right color: - g_edges = self._edges_of_same_color(sgn, sgn2) - # FIXME directed graphs - # And all nodes involved in those which are connected to gn - gn2_options = {n for e in g_edges for n in e if gn in e} - # Node color compatibility should be taken care of by the - # initial candidate lists made by find_subgraphs - - # Add gn2_options to the right collection. Since new_candidates - # is a dict of frozensets of frozensets of node indices it's - # a bit clunky. We can't do .add, and + also doesn't work. We - # could do |, but I deem union to be clearer. - new_candidates[sgn2] = new_candidates[sgn2].union( - [frozenset(gn2_options)] - ) - - if (sgn, sgn2) in constraints: - gn2_options = {gn2 for gn2 in self.graph if gn2 > gn} - elif (sgn2, sgn) in constraints: - gn2_options = {gn2 for gn2 in self.graph if gn2 < gn} - else: - continue # pragma: no cover - new_candidates[sgn2] = new_candidates[sgn2].union( - [frozenset(gn2_options)] - ) - - # The next node is the one that is unmapped and has fewest - # candidates - next_sgn = min(left_to_map, key=lambda n: min(new_candidates[n], key=len)) - yield from self._map_nodes( - next_sgn, - new_candidates, - constraints, - mapping=mapping, - to_be_mapped=to_be_mapped, - ) - # Unmap sgn-gn. Strictly not necessary since it'd get overwritten - # when making a new mapping for sgn. - # del mapping[sgn] - - def _largest_common_subgraph(self, candidates, constraints, to_be_mapped=None): - """ - Find all largest common subgraphs honoring constraints. - """ - if to_be_mapped is None: - to_be_mapped = {frozenset(self.subgraph.nodes)} - - # The LCS problem is basically a repeated subgraph isomorphism problem - # with smaller and smaller subgraphs. We store the nodes that are - # "part of" the subgraph in to_be_mapped, and we make it a little - # smaller every iteration. - - current_size = len(next(iter(to_be_mapped), [])) - - found_iso = False - if current_size <= len(self.graph): - # There's no point in trying to find isomorphisms of - # graph >= subgraph if subgraph has more nodes than graph. - - # Try the isomorphism first with the nodes with lowest ID. So sort - # them. Those are more likely to be part of the final - # correspondence. This makes finding the first answer(s) faster. In - # theory. - for nodes in sorted(to_be_mapped, key=sorted): - # Find the isomorphism between subgraph[to_be_mapped] <= graph - next_sgn = min(nodes, key=lambda n: min(candidates[n], key=len)) - isomorphs = self._map_nodes( - next_sgn, candidates, constraints, to_be_mapped=nodes - ) - - # This is effectively `yield from isomorphs`, except that we look - # whether an item was yielded. - try: - item = next(isomorphs) - except StopIteration: - pass - else: - yield item - yield from isomorphs - found_iso = True - - # BASECASE - if found_iso or current_size == 1: - # Shrinking has no point because either 1) we end up with a smaller - # common subgraph (and we want the largest), or 2) there'll be no - # more subgraph. - return - - left_to_be_mapped = set() - for nodes in to_be_mapped: - for sgn in nodes: - # We're going to remove sgn from to_be_mapped, but subject to - # symmetry constraints. We know that for every constraint we - # have those subgraph nodes are equal. So whenever we would - # remove the lower part of a constraint, remove the higher - # instead. This is all dealth with by _remove_node. And because - # left_to_be_mapped is a set, we don't do double work. - - # And finally, make the subgraph one node smaller. - # REDUCTION - new_nodes = self._remove_node(sgn, nodes, constraints) - left_to_be_mapped.add(new_nodes) - # COMBINATION - yield from self._largest_common_subgraph( - candidates, constraints, to_be_mapped=left_to_be_mapped - ) - - @staticmethod - def _remove_node(node, nodes, constraints): - """ - Returns a new set where node has been removed from nodes, subject to - symmetry constraints. We know, that for every constraint we have - those subgraph nodes are equal. So whenever we would remove the - lower part of a constraint, remove the higher instead. - """ - while True: - for low, high in constraints: - if low == node and high in nodes: - node = high - break - else: # no break, couldn't find node in constraints - break - return frozenset(nodes - {node}) - - @staticmethod - def _find_permutations(top_partitions, bottom_partitions): - """ - Return the pairs of top/bottom partitions where the partitions are - different. Ensures that all partitions in both top and bottom - partitions have size 1. - """ - # Find permutations - permutations = set() - for top, bot in zip(top_partitions, bottom_partitions): - # top and bot have only one element - if len(top) != 1 or len(bot) != 1: - raise IndexError( - "Not all nodes are coupled. This is" - f" impossible: {top_partitions}, {bottom_partitions}" - ) - if top != bot: - permutations.add(frozenset((next(iter(top)), next(iter(bot))))) - return permutations - - @staticmethod - def _update_orbits(orbits, permutations): - """ - Update orbits based on permutations. Orbits is modified in place. - For every pair of items in permutations their respective orbits are - merged. - """ - for permutation in permutations: - node, node2 = permutation - # Find the orbits that contain node and node2, and replace the - # orbit containing node with the union - first = second = None - for idx, orbit in enumerate(orbits): - if first is not None and second is not None: - break - if node in orbit: - first = idx - if node2 in orbit: - second = idx - if first != second: - orbits[first].update(orbits[second]) - del orbits[second] - - def _couple_nodes( - self, - top_partitions, - bottom_partitions, - pair_idx, - t_node, - b_node, - graph, - edge_colors, - ): - """ - Generate new partitions from top and bottom_partitions where t_node is - coupled to b_node. pair_idx is the index of the partitions where t_ and - b_node can be found. - """ - t_partition = top_partitions[pair_idx] - b_partition = bottom_partitions[pair_idx] - assert t_node in t_partition and b_node in b_partition - # Couple node to node2. This means they get their own partition - new_top_partitions = [top.copy() for top in top_partitions] - new_bottom_partitions = [bot.copy() for bot in bottom_partitions] - new_t_groups = {t_node}, t_partition - {t_node} - new_b_groups = {b_node}, b_partition - {b_node} - # Replace the old partitions with the coupled ones - del new_top_partitions[pair_idx] - del new_bottom_partitions[pair_idx] - new_top_partitions[pair_idx:pair_idx] = new_t_groups - new_bottom_partitions[pair_idx:pair_idx] = new_b_groups - - new_top_partitions = self._refine_node_partitions( - graph, new_top_partitions, edge_colors - ) - new_bottom_partitions = self._refine_node_partitions( - graph, new_bottom_partitions, edge_colors, branch=True - ) - new_top_partitions = list(new_top_partitions) - assert len(new_top_partitions) == 1 - new_top_partitions = new_top_partitions[0] - for bot in new_bottom_partitions: - yield list(new_top_partitions), bot - - def _process_ordered_pair_partitions( - self, - graph, - top_partitions, - bottom_partitions, - edge_colors, - orbits=None, - cosets=None, - ): - """ - Processes ordered pair partitions as per the reference paper. Finds and - returns all permutations and cosets that leave the graph unchanged. - """ - if orbits is None: - orbits = [{node} for node in graph.nodes] - else: - # Note that we don't copy orbits when we are given one. This means - # we leak information between the recursive branches. This is - # intentional! - orbits = orbits - if cosets is None: - cosets = {} - else: - cosets = cosets.copy() - - assert all( - len(t_p) == len(b_p) for t_p, b_p in zip(top_partitions, bottom_partitions) - ) - - # BASECASE - if all(len(top) == 1 for top in top_partitions): - # All nodes are mapped - permutations = self._find_permutations(top_partitions, bottom_partitions) - self._update_orbits(orbits, permutations) - if permutations: - return [permutations], cosets - else: - return [], cosets - - permutations = [] - unmapped_nodes = { - (node, idx) - for idx, t_partition in enumerate(top_partitions) - for node in t_partition - if len(t_partition) > 1 - } - node, pair_idx = min(unmapped_nodes) - b_partition = bottom_partitions[pair_idx] - - for node2 in sorted(b_partition): - if len(b_partition) == 1: - # Can never result in symmetry - continue - if node != node2 and any( - node in orbit and node2 in orbit for orbit in orbits - ): - # Orbit prune branch - continue - # REDUCTION - # Couple node to node2 - partitions = self._couple_nodes( - top_partitions, - bottom_partitions, - pair_idx, - node, - node2, - graph, - edge_colors, - ) - for opp in partitions: - new_top_partitions, new_bottom_partitions = opp - - new_perms, new_cosets = self._process_ordered_pair_partitions( - graph, - new_top_partitions, - new_bottom_partitions, - edge_colors, - orbits, - cosets, - ) - # COMBINATION - permutations += new_perms - cosets.update(new_cosets) - - mapped = { - k - for top, bottom in zip(top_partitions, bottom_partitions) - for k in top - if len(top) == 1 and top == bottom - } - ks = {k for k in graph.nodes if k < node} - # Have all nodes with ID < node been mapped? - find_coset = ks <= mapped and node not in cosets - if find_coset: - # Find the orbit that contains node - for orbit in orbits: - if node in orbit: - cosets[node] = orbit.copy() - return permutations, cosets diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorph.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorph.py deleted file mode 100644 index fc3a3fc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorph.py +++ /dev/null @@ -1,249 +0,0 @@ -""" -Graph isomorphism functions. -""" - -import networkx as nx -from networkx.exception import NetworkXError - -__all__ = [ - "could_be_isomorphic", - "fast_could_be_isomorphic", - "faster_could_be_isomorphic", - "is_isomorphic", -] - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}) -def could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree, triangle, and number of cliques sequences. - The triangle sequence contains the number of triangles each node is part of. - The clique sequence contains for each node the number of maximal cliques - involving that node. - - """ - - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = G1.degree() - t1 = nx.triangles(G1) - clqs_1 = list(nx.find_cliques(G1)) - c1 = {n: sum(1 for c in clqs_1 if n in c) for n in G1} # number of cliques - props1 = [[d, t1[v], c1[v]] for v, d in d1] - props1.sort() - - d2 = G2.degree() - t2 = nx.triangles(G2) - clqs_2 = list(nx.find_cliques(G2)) - c2 = {n: sum(1 for c in clqs_2 if n in c) for n in G2} # number of cliques - props2 = [[d, t2[v], c2[v]] for v, d in d2] - props2.sort() - - if props1 != props2: - return False - - # OK... - return True - - -graph_could_be_isomorphic = could_be_isomorphic - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}) -def fast_could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree and triangle sequences. The triangle - sequence contains the number of triangles each node is part of. - """ - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = G1.degree() - t1 = nx.triangles(G1) - props1 = [[d, t1[v]] for v, d in d1] - props1.sort() - - d2 = G2.degree() - t2 = nx.triangles(G2) - props2 = [[d, t2[v]] for v, d in d2] - props2.sort() - - if props1 != props2: - return False - - # OK... - return True - - -fast_graph_could_be_isomorphic = fast_could_be_isomorphic - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}) -def faster_could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree sequences. - """ - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = sorted(d for n, d in G1.degree()) - d2 = sorted(d for n, d in G2.degree()) - - if d1 != d2: - return False - - # OK... - return True - - -faster_graph_could_be_isomorphic = faster_could_be_isomorphic - - -@nx._dispatchable( - graphs={"G1": 0, "G2": 1}, - preserve_edge_attrs="edge_match", - preserve_node_attrs="node_match", -) -def is_isomorphic(G1, G2, node_match=None, edge_match=None): - """Returns True if the graphs G1 and G2 are isomorphic and False otherwise. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 should - be considered equal during the isomorphism test. - If node_match is not specified then node attributes are not considered. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute dictionaries - for n1 and n2 as inputs. - - edge_match : callable - A function that returns True if the edge attribute dictionary - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during the isomorphism test. If edge_match is - not specified then edge attributes are not considered. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute dictionaries - of the edges under consideration. - - Notes - ----- - Uses the vf2 algorithm [1]_. - - Examples - -------- - >>> import networkx.algorithms.isomorphism as iso - - For digraphs G1 and G2, using 'weight' edge attribute (default: 1) - - >>> G1 = nx.DiGraph() - >>> G2 = nx.DiGraph() - >>> nx.add_path(G1, [1, 2, 3, 4], weight=1) - >>> nx.add_path(G2, [10, 20, 30, 40], weight=2) - >>> em = iso.numerical_edge_match("weight", 1) - >>> nx.is_isomorphic(G1, G2) # no weights considered - True - >>> nx.is_isomorphic(G1, G2, edge_match=em) # match weights - False - - For multidigraphs G1 and G2, using 'fill' node attribute (default: '') - - >>> G1 = nx.MultiDiGraph() - >>> G2 = nx.MultiDiGraph() - >>> G1.add_nodes_from([1, 2, 3], fill="red") - >>> G2.add_nodes_from([10, 20, 30, 40], fill="red") - >>> nx.add_path(G1, [1, 2, 3, 4], weight=3, linewidth=2.5) - >>> nx.add_path(G2, [10, 20, 30, 40], weight=3) - >>> nm = iso.categorical_node_match("fill", "red") - >>> nx.is_isomorphic(G1, G2, node_match=nm) - True - - For multidigraphs G1 and G2, using 'weight' edge attribute (default: 7) - - >>> G1.add_edge(1, 2, weight=7) - 1 - >>> G2.add_edge(10, 20) - 1 - >>> em = iso.numerical_multiedge_match("weight", 7, rtol=1e-6) - >>> nx.is_isomorphic(G1, G2, edge_match=em) - True - - For multigraphs G1 and G2, using 'weight' and 'linewidth' edge attributes - with default values 7 and 2.5. Also using 'fill' node attribute with - default value 'red'. - - >>> em = iso.numerical_multiedge_match(["weight", "linewidth"], [7, 2.5]) - >>> nm = iso.categorical_node_match("fill", "red") - >>> nx.is_isomorphic(G1, G2, edge_match=em, node_match=nm) - True - - See Also - -------- - numerical_node_match, numerical_edge_match, numerical_multiedge_match - categorical_node_match, categorical_edge_match, categorical_multiedge_match - - References - ---------- - .. [1] L. P. Cordella, P. Foggia, C. Sansone, M. Vento, - "An Improved Algorithm for Matching Large Graphs", - 3rd IAPR-TC15 Workshop on Graph-based Representations in - Pattern Recognition, Cuen, pp. 149-159, 2001. - https://www.researchgate.net/publication/200034365_An_Improved_Algorithm_for_Matching_Large_Graphs - """ - if G1.is_directed() and G2.is_directed(): - GM = nx.algorithms.isomorphism.DiGraphMatcher - elif (not G1.is_directed()) and (not G2.is_directed()): - GM = nx.algorithms.isomorphism.GraphMatcher - else: - raise NetworkXError("Graphs G1 and G2 are not of the same type.") - - gm = GM(G1, G2, node_match=node_match, edge_match=edge_match) - - return gm.is_isomorphic() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorphvf2.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorphvf2.py deleted file mode 100644 index cb2f1e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/isomorphvf2.py +++ /dev/null @@ -1,1238 +0,0 @@ -""" -************* -VF2 Algorithm -************* - -An implementation of VF2 algorithm for graph isomorphism testing. - -The simplest interface to use this module is to call the -:func:`is_isomorphic ` -function. - -Introduction ------------- - -The GraphMatcher and DiGraphMatcher are responsible for matching -graphs or directed graphs in a predetermined manner. This -usually means a check for an isomorphism, though other checks -are also possible. For example, a subgraph of one graph -can be checked for isomorphism to a second graph. - -Matching is done via syntactic feasibility. It is also possible -to check for semantic feasibility. Feasibility, then, is defined -as the logical AND of the two functions. - -To include a semantic check, the (Di)GraphMatcher class should be -subclassed, and the -:meth:`semantic_feasibility ` -function should be redefined. By default, the semantic feasibility function always -returns ``True``. The effect of this is that semantics are not -considered in the matching of G1 and G2. - -Examples --------- - -Suppose G1 and G2 are isomorphic graphs. Verification is as follows: - ->>> from networkx.algorithms import isomorphism ->>> G1 = nx.path_graph(4) ->>> G2 = nx.path_graph(4) ->>> GM = isomorphism.GraphMatcher(G1, G2) ->>> GM.is_isomorphic() -True - -GM.mapping stores the isomorphism mapping from G1 to G2. - ->>> GM.mapping -{0: 0, 1: 1, 2: 2, 3: 3} - - -Suppose G1 and G2 are isomorphic directed graphs. -Verification is as follows: - ->>> G1 = nx.path_graph(4, create_using=nx.DiGraph) ->>> G2 = nx.path_graph(4, create_using=nx.DiGraph) ->>> DiGM = isomorphism.DiGraphMatcher(G1, G2) ->>> DiGM.is_isomorphic() -True - -DiGM.mapping stores the isomorphism mapping from G1 to G2. - ->>> DiGM.mapping -{0: 0, 1: 1, 2: 2, 3: 3} - - - -Subgraph Isomorphism --------------------- -Graph theory literature can be ambiguous about the meaning of the -above statement, and we seek to clarify it now. - -In the VF2 literature, a mapping ``M`` is said to be a graph-subgraph -isomorphism iff ``M`` is an isomorphism between ``G2`` and a subgraph of ``G1``. -Thus, to say that ``G1`` and ``G2`` are graph-subgraph isomorphic is to say -that a subgraph of ``G1`` is isomorphic to ``G2``. - -Other literature uses the phrase 'subgraph isomorphic' as in '``G1`` does -not have a subgraph isomorphic to ``G2``'. Another use is as an in adverb -for isomorphic. Thus, to say that ``G1`` and ``G2`` are subgraph isomorphic -is to say that a subgraph of ``G1`` is isomorphic to ``G2``. - -Finally, the term 'subgraph' can have multiple meanings. In this -context, 'subgraph' always means a 'node-induced subgraph'. Edge-induced -subgraph isomorphisms are not directly supported, but one should be -able to perform the check by making use of -:func:`line_graph `. For -subgraphs which are not induced, the term 'monomorphism' is preferred -over 'isomorphism'. - -Let ``G = (N, E)`` be a graph with a set of nodes ``N`` and set of edges ``E``. - -If ``G' = (N', E')`` is a subgraph, then: - ``N'`` is a subset of ``N`` and - ``E'`` is a subset of ``E``. - -If ``G' = (N', E')`` is a node-induced subgraph, then: - ``N'`` is a subset of ``N`` and - ``E'`` is the subset of edges in ``E`` relating nodes in ``N'``. - -If ``G' = (N', E')`` is an edge-induced subgraph, then: - ``N'`` is the subset of nodes in ``N`` related by edges in ``E'`` and - ``E'`` is a subset of ``E``. - -If ``G' = (N', E')`` is a monomorphism, then: - ``N'`` is a subset of ``N`` and - ``E'`` is a subset of the set of edges in ``E`` relating nodes in ``N'``. - -Note that if ``G'`` is a node-induced subgraph of ``G``, then it is always a -subgraph monomorphism of ``G``, but the opposite is not always true, as a -monomorphism can have fewer edges. - -References ----------- -[1] Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento, - "A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs", - IEEE Transactions on Pattern Analysis and Machine Intelligence, - vol. 26, no. 10, pp. 1367-1372, Oct., 2004. - http://ieeexplore.ieee.org/iel5/34/29305/01323804.pdf - -[2] L. P. Cordella, P. Foggia, C. Sansone, M. Vento, "An Improved - Algorithm for Matching Large Graphs", 3rd IAPR-TC15 Workshop - on Graph-based Representations in Pattern Recognition, Cuen, - pp. 149-159, 2001. - https://www.researchgate.net/publication/200034365_An_Improved_Algorithm_for_Matching_Large_Graphs - -See Also --------- -:meth:`semantic_feasibility ` -:meth:`syntactic_feasibility ` - -Notes ------ - -The implementation handles both directed and undirected graphs as well -as multigraphs. - -In general, the subgraph isomorphism problem is NP-complete whereas the -graph isomorphism problem is most likely not NP-complete (although no -polynomial-time algorithm is known to exist). - -""" - -# This work was originally coded by Christopher Ellison -# as part of the Computational Mechanics Python (CMPy) project. -# James P. Crutchfield, principal investigator. -# Complexity Sciences Center and Physics Department, UC Davis. - -import sys - -__all__ = ["GraphMatcher", "DiGraphMatcher"] - - -class GraphMatcher: - """Implementation of VF2 algorithm for matching undirected graphs. - - Suitable for Graph and MultiGraph instances. - """ - - def __init__(self, G1, G2): - """Initialize GraphMatcher. - - Parameters - ---------- - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism. - - Examples - -------- - To create a GraphMatcher which checks for syntactic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.path_graph(4) - >>> G2 = nx.path_graph(4) - >>> GM = isomorphism.GraphMatcher(G1, G2) - """ - self.G1 = G1 - self.G2 = G2 - self.G1_nodes = set(G1.nodes()) - self.G2_nodes = set(G2.nodes()) - self.G2_node_order = {n: i for i, n in enumerate(G2)} - - # Set recursion limit. - self.old_recursion_limit = sys.getrecursionlimit() - expected_max_recursion_level = len(self.G2) - if self.old_recursion_limit < 1.5 * expected_max_recursion_level: - # Give some breathing room. - sys.setrecursionlimit(int(1.5 * expected_max_recursion_level)) - - # Declare that we will be searching for a graph-graph isomorphism. - self.test = "graph" - - # Initialize state - self.initialize() - - def reset_recursion_limit(self): - """Restores the recursion limit.""" - # TODO: - # Currently, we use recursion and set the recursion level higher. - # It would be nice to restore the level, but because the - # (Di)GraphMatcher classes make use of cyclic references, garbage - # collection will never happen when we define __del__() to - # restore the recursion level. The result is a memory leak. - # So for now, we do not automatically restore the recursion level, - # and instead provide a method to do this manually. Eventually, - # we should turn this into a non-recursive implementation. - sys.setrecursionlimit(self.old_recursion_limit) - - def candidate_pairs_iter(self): - """Iterator over candidate pairs of nodes in G1 and G2.""" - - # All computations are done using the current state! - - G1_nodes = self.G1_nodes - G2_nodes = self.G2_nodes - min_key = self.G2_node_order.__getitem__ - - # First we compute the inout-terminal sets. - T1_inout = [node for node in self.inout_1 if node not in self.core_1] - T2_inout = [node for node in self.inout_2 if node not in self.core_2] - - # If T1_inout and T2_inout are both nonempty. - # P(s) = T1_inout x {min T2_inout} - if T1_inout and T2_inout: - node_2 = min(T2_inout, key=min_key) - for node_1 in T1_inout: - yield node_1, node_2 - - else: - # If T1_inout and T2_inout were both empty.... - # P(s) = (N_1 - M_1) x {min (N_2 - M_2)} - # if not (T1_inout or T2_inout): # as suggested by [2], incorrect - if 1: # as inferred from [1], correct - # First we determine the candidate node for G2 - other_node = min(G2_nodes - set(self.core_2), key=min_key) - for node in self.G1: - if node not in self.core_1: - yield node, other_node - - # For all other cases, we don't have any candidate pairs. - - def initialize(self): - """Reinitializes the state of the algorithm. - - This method should be redefined if using something other than GMState. - If only subclassing GraphMatcher, a redefinition is not necessary. - - """ - - # core_1[n] contains the index of the node paired with n, which is m, - # provided n is in the mapping. - # core_2[m] contains the index of the node paired with m, which is n, - # provided m is in the mapping. - self.core_1 = {} - self.core_2 = {} - - # See the paper for definitions of M_x and T_x^{y} - - # inout_1[n] is non-zero if n is in M_1 or in T_1^{inout} - # inout_2[m] is non-zero if m is in M_2 or in T_2^{inout} - # - # The value stored is the depth of the SSR tree when the node became - # part of the corresponding set. - self.inout_1 = {} - self.inout_2 = {} - # Practically, these sets simply store the nodes in the subgraph. - - self.state = GMState(self) - - # Provide a convenient way to access the isomorphism mapping. - self.mapping = self.core_1.copy() - - def is_isomorphic(self): - """Returns True if G1 and G2 are isomorphic graphs.""" - - # Let's do two very quick checks! - # QUESTION: Should we call faster_graph_could_be_isomorphic(G1,G2)? - # For now, I just copy the code. - - # Check global properties - if self.G1.order() != self.G2.order(): - return False - - # Check local properties - d1 = sorted(d for n, d in self.G1.degree()) - d2 = sorted(d for n, d in self.G2.degree()) - if d1 != d2: - return False - - try: - x = next(self.isomorphisms_iter()) - return True - except StopIteration: - return False - - def isomorphisms_iter(self): - """Generator over isomorphisms between G1 and G2.""" - # Declare that we are looking for a graph-graph isomorphism. - self.test = "graph" - self.initialize() - yield from self.match() - - def match(self): - """Extends the isomorphism mapping. - - This function is called recursively to determine if a complete - isomorphism can be found between G1 and G2. It cleans up the class - variables after each recursive call. If an isomorphism is found, - we yield the mapping. - - """ - if len(self.core_1) == len(self.G2): - # Save the final mapping, otherwise garbage collection deletes it. - self.mapping = self.core_1.copy() - # The mapping is complete. - yield self.mapping - else: - for G1_node, G2_node in self.candidate_pairs_iter(): - if self.syntactic_feasibility(G1_node, G2_node): - if self.semantic_feasibility(G1_node, G2_node): - # Recursive call, adding the feasible state. - newstate = self.state.__class__(self, G1_node, G2_node) - yield from self.match() - - # restore data structures - newstate.restore() - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is semantically feasible. - - The semantic feasibility function should return True if it is - acceptable to add the candidate pair (G1_node, G2_node) to the current - partial isomorphism mapping. The logic should focus on semantic - information contained in the edge data or a formalized node class. - - By acceptable, we mean that the subsequent mapping can still become a - complete isomorphism mapping. Thus, if adding the candidate pair - definitely makes it so that the subsequent mapping cannot become a - complete isomorphism mapping, then this function must return False. - - The default semantic feasibility function always returns True. The - effect is that semantics are not considered in the matching of G1 - and G2. - - The semantic checks might differ based on the what type of test is - being performed. A keyword description of the test is stored in - self.test. Here is a quick description of the currently implemented - tests:: - - test='graph' - Indicates that the graph matcher is looking for a graph-graph - isomorphism. - - test='subgraph' - Indicates that the graph matcher is looking for a subgraph-graph - isomorphism such that a subgraph of G1 is isomorphic to G2. - - test='mono' - Indicates that the graph matcher is looking for a subgraph-graph - monomorphism such that a subgraph of G1 is monomorphic to G2. - - Any subclass which redefines semantic_feasibility() must maintain - the above form to keep the match() method functional. Implementations - should consider multigraphs. - """ - return True - - def subgraph_is_isomorphic(self): - """Returns `True` if a subgraph of ``G1`` is isomorphic to ``G2``. - - Examples - -------- - When creating the `GraphMatcher`, the order of the arguments is important - - >>> G = nx.Graph([("A", "B"), ("B", "C"), ("A", "C")]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 2), (1, 3), (0, 4)]) - - Check whether a subgraph of G is isomorphic to H: - - >>> isomatcher = nx.isomorphism.GraphMatcher(G, H) - >>> isomatcher.subgraph_is_isomorphic() - False - - Check whether a subgraph of H is isomorphic to G: - - >>> isomatcher = nx.isomorphism.GraphMatcher(H, G) - >>> isomatcher.subgraph_is_isomorphic() - True - """ - try: - x = next(self.subgraph_isomorphisms_iter()) - return True - except StopIteration: - return False - - def subgraph_is_monomorphic(self): - """Returns `True` if a subgraph of ``G1`` is monomorphic to ``G2``. - - Examples - -------- - When creating the `GraphMatcher`, the order of the arguments is important. - - >>> G = nx.Graph([("A", "B"), ("B", "C")]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 2)]) - - Check whether a subgraph of G is monomorphic to H: - - >>> isomatcher = nx.isomorphism.GraphMatcher(G, H) - >>> isomatcher.subgraph_is_monomorphic() - False - - Check whether a subgraph of H is isomorphic to G: - - >>> isomatcher = nx.isomorphism.GraphMatcher(H, G) - >>> isomatcher.subgraph_is_monomorphic() - True - """ - try: - x = next(self.subgraph_monomorphisms_iter()) - return True - except StopIteration: - return False - - def subgraph_isomorphisms_iter(self): - """Generator over isomorphisms between a subgraph of ``G1`` and ``G2``. - - Examples - -------- - When creating the `GraphMatcher`, the order of the arguments is important - - >>> G = nx.Graph([("A", "B"), ("B", "C"), ("A", "C")]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 2), (1, 3), (0, 4)]) - - Yield isomorphic mappings between ``H`` and subgraphs of ``G``: - - >>> isomatcher = nx.isomorphism.GraphMatcher(G, H) - >>> list(isomatcher.subgraph_isomorphisms_iter()) - [] - - Yield isomorphic mappings between ``G`` and subgraphs of ``H``: - - >>> isomatcher = nx.isomorphism.GraphMatcher(H, G) - >>> next(isomatcher.subgraph_isomorphisms_iter()) - {0: 'A', 1: 'B', 2: 'C'} - - """ - # Declare that we are looking for graph-subgraph isomorphism. - self.test = "subgraph" - self.initialize() - yield from self.match() - - def subgraph_monomorphisms_iter(self): - """Generator over monomorphisms between a subgraph of ``G1`` and ``G2``. - - Examples - -------- - When creating the `GraphMatcher`, the order of the arguments is important. - - >>> G = nx.Graph([("A", "B"), ("B", "C")]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 2)]) - - Yield monomorphic mappings between ``H`` and subgraphs of ``G``: - - >>> isomatcher = nx.isomorphism.GraphMatcher(G, H) - >>> list(isomatcher.subgraph_monomorphisms_iter()) - [] - - Yield monomorphic mappings between ``G`` and subgraphs of ``H``: - - >>> isomatcher = nx.isomorphism.GraphMatcher(H, G) - >>> next(isomatcher.subgraph_monomorphisms_iter()) - {0: 'A', 1: 'B', 2: 'C'} - """ - # Declare that we are looking for graph-subgraph monomorphism. - self.test = "mono" - self.initialize() - yield from self.match() - - def syntactic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is syntactically feasible. - - This function returns True if it is adding the candidate pair - to the current partial isomorphism/monomorphism mapping is allowable. - The addition is allowable if the inclusion of the candidate pair does - not make it impossible for an isomorphism/monomorphism to be found. - """ - - # The VF2 algorithm was designed to work with graphs having, at most, - # one edge connecting any two nodes. This is not the case when - # dealing with an MultiGraphs. - # - # Basically, when we test the look-ahead rules R_neighbor, we will - # make sure that the number of edges are checked. We also add - # a R_self check to verify that the number of selfloops is acceptable. - # - # Users might be comparing Graph instances with MultiGraph instances. - # So the generic GraphMatcher class must work with MultiGraphs. - # Care must be taken since the value in the innermost dictionary is a - # singlet for Graph instances. For MultiGraphs, the value in the - # innermost dictionary is a list. - - ### - # Test at each step to get a return value as soon as possible. - ### - - # Look ahead 0 - - # R_self - - # The number of selfloops for G1_node must equal the number of - # self-loops for G2_node. Without this check, we would fail on - # R_neighbor at the next recursion level. But it is good to prune the - # search tree now. - - if self.test == "mono": - if self.G1.number_of_edges(G1_node, G1_node) < self.G2.number_of_edges( - G2_node, G2_node - ): - return False - else: - if self.G1.number_of_edges(G1_node, G1_node) != self.G2.number_of_edges( - G2_node, G2_node - ): - return False - - # R_neighbor - - # For each neighbor n' of n in the partial mapping, the corresponding - # node m' is a neighbor of m, and vice versa. Also, the number of - # edges must be equal. - if self.test != "mono": - for neighbor in self.G1[G1_node]: - if neighbor in self.core_1: - if self.core_1[neighbor] not in self.G2[G2_node]: - return False - elif self.G1.number_of_edges( - neighbor, G1_node - ) != self.G2.number_of_edges(self.core_1[neighbor], G2_node): - return False - - for neighbor in self.G2[G2_node]: - if neighbor in self.core_2: - if self.core_2[neighbor] not in self.G1[G1_node]: - return False - elif self.test == "mono": - if self.G1.number_of_edges( - self.core_2[neighbor], G1_node - ) < self.G2.number_of_edges(neighbor, G2_node): - return False - else: - if self.G1.number_of_edges( - self.core_2[neighbor], G1_node - ) != self.G2.number_of_edges(neighbor, G2_node): - return False - - if self.test != "mono": - # Look ahead 1 - - # R_terminout - # The number of neighbors of n in T_1^{inout} is equal to the - # number of neighbors of m that are in T_2^{inout}, and vice versa. - num1 = 0 - for neighbor in self.G1[G1_node]: - if (neighbor in self.inout_1) and (neighbor not in self.core_1): - num1 += 1 - num2 = 0 - for neighbor in self.G2[G2_node]: - if (neighbor in self.inout_2) and (neighbor not in self.core_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Look ahead 2 - - # R_new - - # The number of neighbors of n that are neither in the core_1 nor - # T_1^{inout} is equal to the number of neighbors of m - # that are neither in core_2 nor T_2^{inout}. - num1 = 0 - for neighbor in self.G1[G1_node]: - if neighbor not in self.inout_1: - num1 += 1 - num2 = 0 - for neighbor in self.G2[G2_node]: - if neighbor not in self.inout_2: - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Otherwise, this node pair is syntactically feasible! - return True - - -class DiGraphMatcher(GraphMatcher): - """Implementation of VF2 algorithm for matching directed graphs. - - Suitable for DiGraph and MultiDiGraph instances. - """ - - def __init__(self, G1, G2): - """Initialize DiGraphMatcher. - - G1 and G2 should be nx.Graph or nx.MultiGraph instances. - - Examples - -------- - To create a GraphMatcher which checks for syntactic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - >>> G2 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - >>> DiGM = isomorphism.DiGraphMatcher(G1, G2) - """ - super().__init__(G1, G2) - - def candidate_pairs_iter(self): - """Iterator over candidate pairs of nodes in G1 and G2.""" - - # All computations are done using the current state! - - G1_nodes = self.G1_nodes - G2_nodes = self.G2_nodes - min_key = self.G2_node_order.__getitem__ - - # First we compute the out-terminal sets. - T1_out = [node for node in self.out_1 if node not in self.core_1] - T2_out = [node for node in self.out_2 if node not in self.core_2] - - # If T1_out and T2_out are both nonempty. - # P(s) = T1_out x {min T2_out} - if T1_out and T2_out: - node_2 = min(T2_out, key=min_key) - for node_1 in T1_out: - yield node_1, node_2 - - # If T1_out and T2_out were both empty.... - # We compute the in-terminal sets. - - # elif not (T1_out or T2_out): # as suggested by [2], incorrect - else: # as suggested by [1], correct - T1_in = [node for node in self.in_1 if node not in self.core_1] - T2_in = [node for node in self.in_2 if node not in self.core_2] - - # If T1_in and T2_in are both nonempty. - # P(s) = T1_out x {min T2_out} - if T1_in and T2_in: - node_2 = min(T2_in, key=min_key) - for node_1 in T1_in: - yield node_1, node_2 - - # If all terminal sets are empty... - # P(s) = (N_1 - M_1) x {min (N_2 - M_2)} - - # elif not (T1_in or T2_in): # as suggested by [2], incorrect - else: # as inferred from [1], correct - node_2 = min(G2_nodes - set(self.core_2), key=min_key) - for node_1 in G1_nodes: - if node_1 not in self.core_1: - yield node_1, node_2 - - # For all other cases, we don't have any candidate pairs. - - def initialize(self): - """Reinitializes the state of the algorithm. - - This method should be redefined if using something other than DiGMState. - If only subclassing GraphMatcher, a redefinition is not necessary. - """ - - # core_1[n] contains the index of the node paired with n, which is m, - # provided n is in the mapping. - # core_2[m] contains the index of the node paired with m, which is n, - # provided m is in the mapping. - self.core_1 = {} - self.core_2 = {} - - # See the paper for definitions of M_x and T_x^{y} - - # in_1[n] is non-zero if n is in M_1 or in T_1^{in} - # out_1[n] is non-zero if n is in M_1 or in T_1^{out} - # - # in_2[m] is non-zero if m is in M_2 or in T_2^{in} - # out_2[m] is non-zero if m is in M_2 or in T_2^{out} - # - # The value stored is the depth of the search tree when the node became - # part of the corresponding set. - self.in_1 = {} - self.in_2 = {} - self.out_1 = {} - self.out_2 = {} - - self.state = DiGMState(self) - - # Provide a convenient way to access the isomorphism mapping. - self.mapping = self.core_1.copy() - - def syntactic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is syntactically feasible. - - This function returns True if it is adding the candidate pair - to the current partial isomorphism/monomorphism mapping is allowable. - The addition is allowable if the inclusion of the candidate pair does - not make it impossible for an isomorphism/monomorphism to be found. - """ - - # The VF2 algorithm was designed to work with graphs having, at most, - # one edge connecting any two nodes. This is not the case when - # dealing with an MultiGraphs. - # - # Basically, when we test the look-ahead rules R_pred and R_succ, we - # will make sure that the number of edges are checked. We also add - # a R_self check to verify that the number of selfloops is acceptable. - - # Users might be comparing DiGraph instances with MultiDiGraph - # instances. So the generic DiGraphMatcher class must work with - # MultiDiGraphs. Care must be taken since the value in the innermost - # dictionary is a singlet for DiGraph instances. For MultiDiGraphs, - # the value in the innermost dictionary is a list. - - ### - # Test at each step to get a return value as soon as possible. - ### - - # Look ahead 0 - - # R_self - - # The number of selfloops for G1_node must equal the number of - # self-loops for G2_node. Without this check, we would fail on R_pred - # at the next recursion level. This should prune the tree even further. - if self.test == "mono": - if self.G1.number_of_edges(G1_node, G1_node) < self.G2.number_of_edges( - G2_node, G2_node - ): - return False - else: - if self.G1.number_of_edges(G1_node, G1_node) != self.G2.number_of_edges( - G2_node, G2_node - ): - return False - - # R_pred - - # For each predecessor n' of n in the partial mapping, the - # corresponding node m' is a predecessor of m, and vice versa. Also, - # the number of edges must be equal - if self.test != "mono": - for predecessor in self.G1.pred[G1_node]: - if predecessor in self.core_1: - if self.core_1[predecessor] not in self.G2.pred[G2_node]: - return False - elif self.G1.number_of_edges( - predecessor, G1_node - ) != self.G2.number_of_edges(self.core_1[predecessor], G2_node): - return False - - for predecessor in self.G2.pred[G2_node]: - if predecessor in self.core_2: - if self.core_2[predecessor] not in self.G1.pred[G1_node]: - return False - elif self.test == "mono": - if self.G1.number_of_edges( - self.core_2[predecessor], G1_node - ) < self.G2.number_of_edges(predecessor, G2_node): - return False - else: - if self.G1.number_of_edges( - self.core_2[predecessor], G1_node - ) != self.G2.number_of_edges(predecessor, G2_node): - return False - - # R_succ - - # For each successor n' of n in the partial mapping, the corresponding - # node m' is a successor of m, and vice versa. Also, the number of - # edges must be equal. - if self.test != "mono": - for successor in self.G1[G1_node]: - if successor in self.core_1: - if self.core_1[successor] not in self.G2[G2_node]: - return False - elif self.G1.number_of_edges( - G1_node, successor - ) != self.G2.number_of_edges(G2_node, self.core_1[successor]): - return False - - for successor in self.G2[G2_node]: - if successor in self.core_2: - if self.core_2[successor] not in self.G1[G1_node]: - return False - elif self.test == "mono": - if self.G1.number_of_edges( - G1_node, self.core_2[successor] - ) < self.G2.number_of_edges(G2_node, successor): - return False - else: - if self.G1.number_of_edges( - G1_node, self.core_2[successor] - ) != self.G2.number_of_edges(G2_node, successor): - return False - - if self.test != "mono": - # Look ahead 1 - - # R_termin - # The number of predecessors of n that are in T_1^{in} is equal to the - # number of predecessors of m that are in T_2^{in}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor in self.in_1) and (predecessor not in self.core_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor in self.in_2) and (predecessor not in self.core_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are in T_1^{in} is equal to the - # number of successors of m that are in T_2^{in}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor in self.in_1) and (successor not in self.core_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor in self.in_2) and (successor not in self.core_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # R_termout - - # The number of predecessors of n that are in T_1^{out} is equal to the - # number of predecessors of m that are in T_2^{out}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor in self.out_1) and (predecessor not in self.core_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor in self.out_2) and (predecessor not in self.core_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are in T_1^{out} is equal to the - # number of successors of m that are in T_2^{out}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor in self.out_1) and (successor not in self.core_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor in self.out_2) and (successor not in self.core_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Look ahead 2 - - # R_new - - # The number of predecessors of n that are neither in the core_1 nor - # T_1^{in} nor T_1^{out} is equal to the number of predecessors of m - # that are neither in core_2 nor T_2^{in} nor T_2^{out}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor not in self.in_1) and (predecessor not in self.out_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor not in self.in_2) and (predecessor not in self.out_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are neither in the core_1 nor - # T_1^{in} nor T_1^{out} is equal to the number of successors of m - # that are neither in core_2 nor T_2^{in} nor T_2^{out}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor not in self.in_1) and (successor not in self.out_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor not in self.in_2) and (successor not in self.out_2): - num2 += 1 - if self.test == "graph": - if num1 != num2: - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Otherwise, this node pair is syntactically feasible! - return True - - def subgraph_is_isomorphic(self): - """Returns `True` if a subgraph of ``G1`` is isomorphic to ``G2``. - - Examples - -------- - When creating the `DiGraphMatcher`, the order of the arguments is important - - >>> G = nx.DiGraph([("A", "B"), ("B", "A"), ("B", "C"), ("C", "B")]) - >>> H = nx.DiGraph(nx.path_graph(5)) - - Check whether a subgraph of G is isomorphic to H: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(G, H) - >>> isomatcher.subgraph_is_isomorphic() - False - - Check whether a subgraph of H is isomorphic to G: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(H, G) - >>> isomatcher.subgraph_is_isomorphic() - True - """ - return super().subgraph_is_isomorphic() - - def subgraph_is_monomorphic(self): - """Returns `True` if a subgraph of ``G1`` is monomorphic to ``G2``. - - Examples - -------- - When creating the `DiGraphMatcher`, the order of the arguments is important. - - >>> G = nx.DiGraph([("A", "B"), ("C", "B"), ("D", "C")]) - >>> H = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 2)]) - - Check whether a subgraph of G is monomorphic to H: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(G, H) - >>> isomatcher.subgraph_is_monomorphic() - False - - Check whether a subgraph of H is isomorphic to G: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(H, G) - >>> isomatcher.subgraph_is_monomorphic() - True - """ - return super().subgraph_is_monomorphic() - - def subgraph_isomorphisms_iter(self): - """Generator over isomorphisms between a subgraph of ``G1`` and ``G2``. - - Examples - -------- - When creating the `DiGraphMatcher`, the order of the arguments is important - - >>> G = nx.DiGraph([("B", "C"), ("C", "B"), ("C", "D"), ("D", "C")]) - >>> H = nx.DiGraph(nx.path_graph(5)) - - Yield isomorphic mappings between ``H`` and subgraphs of ``G``: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(G, H) - >>> list(isomatcher.subgraph_isomorphisms_iter()) - [] - - Yield isomorphic mappings between ``G`` and subgraphs of ``H``: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(H, G) - >>> next(isomatcher.subgraph_isomorphisms_iter()) - {0: 'B', 1: 'C', 2: 'D'} - """ - return super().subgraph_isomorphisms_iter() - - def subgraph_monomorphisms_iter(self): - """Generator over monomorphisms between a subgraph of ``G1`` and ``G2``. - - Examples - -------- - When creating the `DiGraphMatcher`, the order of the arguments is important. - - >>> G = nx.DiGraph([("A", "B"), ("C", "B"), ("D", "C")]) - >>> H = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 2)]) - - Yield monomorphic mappings between ``H`` and subgraphs of ``G``: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(G, H) - >>> list(isomatcher.subgraph_monomorphisms_iter()) - [] - - Yield monomorphic mappings between ``G`` and subgraphs of ``H``: - - >>> isomatcher = nx.isomorphism.DiGraphMatcher(H, G) - >>> next(isomatcher.subgraph_monomorphisms_iter()) - {3: 'A', 2: 'B', 1: 'C', 0: 'D'} - """ - return super().subgraph_monomorphisms_iter() - - -class GMState: - """Internal representation of state for the GraphMatcher class. - - This class is used internally by the GraphMatcher class. It is used - only to store state specific data. There will be at most G2.order() of - these objects in memory at a time, due to the depth-first search - strategy employed by the VF2 algorithm. - """ - - def __init__(self, GM, G1_node=None, G2_node=None): - """Initializes GMState object. - - Pass in the GraphMatcher to which this GMState belongs and the - new node pair that will be added to the GraphMatcher's current - isomorphism mapping. - """ - self.GM = GM - - # Initialize the last stored node pair. - self.G1_node = None - self.G2_node = None - self.depth = len(GM.core_1) - - if G1_node is None or G2_node is None: - # Then we reset the class variables - GM.core_1 = {} - GM.core_2 = {} - GM.inout_1 = {} - GM.inout_2 = {} - - # Watch out! G1_node == 0 should evaluate to True. - if G1_node is not None and G2_node is not None: - # Add the node pair to the isomorphism mapping. - GM.core_1[G1_node] = G2_node - GM.core_2[G2_node] = G1_node - - # Store the node that was added last. - self.G1_node = G1_node - self.G2_node = G2_node - - # Now we must update the other two vectors. - # We will add only if it is not in there already! - self.depth = len(GM.core_1) - - # First we add the new nodes... - if G1_node not in GM.inout_1: - GM.inout_1[G1_node] = self.depth - if G2_node not in GM.inout_2: - GM.inout_2[G2_node] = self.depth - - # Now we add every other node... - - # Updates for T_1^{inout} - new_nodes = set() - for node in GM.core_1: - new_nodes.update( - [neighbor for neighbor in GM.G1[node] if neighbor not in GM.core_1] - ) - for node in new_nodes: - if node not in GM.inout_1: - GM.inout_1[node] = self.depth - - # Updates for T_2^{inout} - new_nodes = set() - for node in GM.core_2: - new_nodes.update( - [neighbor for neighbor in GM.G2[node] if neighbor not in GM.core_2] - ) - for node in new_nodes: - if node not in GM.inout_2: - GM.inout_2[node] = self.depth - - def restore(self): - """Deletes the GMState object and restores the class variables.""" - # First we remove the node that was added from the core vectors. - # Watch out! G1_node == 0 should evaluate to True. - if self.G1_node is not None and self.G2_node is not None: - del self.GM.core_1[self.G1_node] - del self.GM.core_2[self.G2_node] - - # Now we revert the other two vectors. - # Thus, we delete all entries which have this depth level. - for vector in (self.GM.inout_1, self.GM.inout_2): - for node in list(vector.keys()): - if vector[node] == self.depth: - del vector[node] - - -class DiGMState: - """Internal representation of state for the DiGraphMatcher class. - - This class is used internally by the DiGraphMatcher class. It is used - only to store state specific data. There will be at most G2.order() of - these objects in memory at a time, due to the depth-first search - strategy employed by the VF2 algorithm. - - """ - - def __init__(self, GM, G1_node=None, G2_node=None): - """Initializes DiGMState object. - - Pass in the DiGraphMatcher to which this DiGMState belongs and the - new node pair that will be added to the GraphMatcher's current - isomorphism mapping. - """ - self.GM = GM - - # Initialize the last stored node pair. - self.G1_node = None - self.G2_node = None - self.depth = len(GM.core_1) - - if G1_node is None or G2_node is None: - # Then we reset the class variables - GM.core_1 = {} - GM.core_2 = {} - GM.in_1 = {} - GM.in_2 = {} - GM.out_1 = {} - GM.out_2 = {} - - # Watch out! G1_node == 0 should evaluate to True. - if G1_node is not None and G2_node is not None: - # Add the node pair to the isomorphism mapping. - GM.core_1[G1_node] = G2_node - GM.core_2[G2_node] = G1_node - - # Store the node that was added last. - self.G1_node = G1_node - self.G2_node = G2_node - - # Now we must update the other four vectors. - # We will add only if it is not in there already! - self.depth = len(GM.core_1) - - # First we add the new nodes... - for vector in (GM.in_1, GM.out_1): - if G1_node not in vector: - vector[G1_node] = self.depth - for vector in (GM.in_2, GM.out_2): - if G2_node not in vector: - vector[G2_node] = self.depth - - # Now we add every other node... - - # Updates for T_1^{in} - new_nodes = set() - for node in GM.core_1: - new_nodes.update( - [ - predecessor - for predecessor in GM.G1.predecessors(node) - if predecessor not in GM.core_1 - ] - ) - for node in new_nodes: - if node not in GM.in_1: - GM.in_1[node] = self.depth - - # Updates for T_2^{in} - new_nodes = set() - for node in GM.core_2: - new_nodes.update( - [ - predecessor - for predecessor in GM.G2.predecessors(node) - if predecessor not in GM.core_2 - ] - ) - for node in new_nodes: - if node not in GM.in_2: - GM.in_2[node] = self.depth - - # Updates for T_1^{out} - new_nodes = set() - for node in GM.core_1: - new_nodes.update( - [ - successor - for successor in GM.G1.successors(node) - if successor not in GM.core_1 - ] - ) - for node in new_nodes: - if node not in GM.out_1: - GM.out_1[node] = self.depth - - # Updates for T_2^{out} - new_nodes = set() - for node in GM.core_2: - new_nodes.update( - [ - successor - for successor in GM.G2.successors(node) - if successor not in GM.core_2 - ] - ) - for node in new_nodes: - if node not in GM.out_2: - GM.out_2[node] = self.depth - - def restore(self): - """Deletes the DiGMState object and restores the class variables.""" - - # First we remove the node that was added from the core vectors. - # Watch out! G1_node == 0 should evaluate to True. - if self.G1_node is not None and self.G2_node is not None: - del self.GM.core_1[self.G1_node] - del self.GM.core_2[self.G2_node] - - # Now we revert the other four vectors. - # Thus, we delete all entries which have this depth level. - for vector in (self.GM.in_1, self.GM.in_2, self.GM.out_1, self.GM.out_2): - for node in list(vector.keys()): - if vector[node] == self.depth: - del vector[node] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/matchhelpers.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/matchhelpers.py deleted file mode 100644 index b48820d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/matchhelpers.py +++ /dev/null @@ -1,352 +0,0 @@ -"""Functions which help end users define customize node_match and -edge_match functions to use during isomorphism checks. -""" - -import math -import types -from itertools import permutations - -__all__ = [ - "categorical_node_match", - "categorical_edge_match", - "categorical_multiedge_match", - "numerical_node_match", - "numerical_edge_match", - "numerical_multiedge_match", - "generic_node_match", - "generic_edge_match", - "generic_multiedge_match", -] - - -def copyfunc(f, name=None): - """Returns a deepcopy of a function.""" - return types.FunctionType( - f.__code__, f.__globals__, name or f.__name__, f.__defaults__, f.__closure__ - ) - - -def allclose(x, y, rtol=1.0000000000000001e-05, atol=1e-08): - """Returns True if x and y are sufficiently close, elementwise. - - Parameters - ---------- - rtol : float - The relative error tolerance. - atol : float - The absolute error tolerance. - - """ - # assume finite weights, see numpy.allclose() for reference - return all(math.isclose(xi, yi, rel_tol=rtol, abs_tol=atol) for xi, yi in zip(x, y)) - - -categorical_doc = """ -Returns a comparison function for a categorical node attribute. - -The value(s) of the attr(s) must be hashable and comparable via the == -operator since they are placed into a set([]) object. If the sets from -G1 and G2 are the same, then the constructed function returns True. - -Parameters ----------- -attr : string | list - The categorical node attribute to compare, or a list of categorical - node attributes to compare. -default : value | list - The default value for the categorical node attribute, or a list of - default values for the categorical node attributes. - -Returns -------- -match : function - The customized, categorical `node_match` function. - -Examples --------- ->>> import networkx.algorithms.isomorphism as iso ->>> nm = iso.categorical_node_match("size", 1) ->>> nm = iso.categorical_node_match(["color", "size"], ["red", 2]) - -""" - - -def categorical_node_match(attr, default): - if isinstance(attr, str): - - def match(data1, data2): - return data1.get(attr, default) == data2.get(attr, default) - - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(data1, data2): - return all(data1.get(attr, d) == data2.get(attr, d) for attr, d in attrs) - - return match - - -categorical_edge_match = copyfunc(categorical_node_match, "categorical_edge_match") - - -def categorical_multiedge_match(attr, default): - if isinstance(attr, str): - - def match(datasets1, datasets2): - values1 = {data.get(attr, default) for data in datasets1.values()} - values2 = {data.get(attr, default) for data in datasets2.values()} - return values1 == values2 - - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = set() - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.add(x) - values2 = set() - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.add(x) - return values1 == values2 - - return match - - -# Docstrings for categorical functions. -categorical_node_match.__doc__ = categorical_doc -categorical_edge_match.__doc__ = categorical_doc.replace("node", "edge") -tmpdoc = categorical_doc.replace("node", "edge") -tmpdoc = tmpdoc.replace("categorical_edge_match", "categorical_multiedge_match") -categorical_multiedge_match.__doc__ = tmpdoc - - -numerical_doc = """ -Returns a comparison function for a numerical node attribute. - -The value(s) of the attr(s) must be numerical and sortable. If the -sorted list of values from G1 and G2 are the same within some -tolerance, then the constructed function returns True. - -Parameters ----------- -attr : string | list - The numerical node attribute to compare, or a list of numerical - node attributes to compare. -default : value | list - The default value for the numerical node attribute, or a list of - default values for the numerical node attributes. -rtol : float - The relative error tolerance. -atol : float - The absolute error tolerance. - -Returns -------- -match : function - The customized, numerical `node_match` function. - -Examples --------- ->>> import networkx.algorithms.isomorphism as iso ->>> nm = iso.numerical_node_match("weight", 1.0) ->>> nm = iso.numerical_node_match(["weight", "linewidth"], [0.25, 0.5]) - -""" - - -def numerical_node_match(attr, default, rtol=1.0000000000000001e-05, atol=1e-08): - if isinstance(attr, str): - - def match(data1, data2): - return math.isclose( - data1.get(attr, default), - data2.get(attr, default), - rel_tol=rtol, - abs_tol=atol, - ) - - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(data1, data2): - values1 = [data1.get(attr, d) for attr, d in attrs] - values2 = [data2.get(attr, d) for attr, d in attrs] - return allclose(values1, values2, rtol=rtol, atol=atol) - - return match - - -numerical_edge_match = copyfunc(numerical_node_match, "numerical_edge_match") - - -def numerical_multiedge_match(attr, default, rtol=1.0000000000000001e-05, atol=1e-08): - if isinstance(attr, str): - - def match(datasets1, datasets2): - values1 = sorted(data.get(attr, default) for data in datasets1.values()) - values2 = sorted(data.get(attr, default) for data in datasets2.values()) - return allclose(values1, values2, rtol=rtol, atol=atol) - - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = [] - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.append(x) - values2 = [] - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.append(x) - values1.sort() - values2.sort() - for xi, yi in zip(values1, values2): - if not allclose(xi, yi, rtol=rtol, atol=atol): - return False - else: - return True - - return match - - -# Docstrings for numerical functions. -numerical_node_match.__doc__ = numerical_doc -numerical_edge_match.__doc__ = numerical_doc.replace("node", "edge") -tmpdoc = numerical_doc.replace("node", "edge") -tmpdoc = tmpdoc.replace("numerical_edge_match", "numerical_multiedge_match") -numerical_multiedge_match.__doc__ = tmpdoc - - -generic_doc = """ -Returns a comparison function for a generic attribute. - -The value(s) of the attr(s) are compared using the specified -operators. If all the attributes are equal, then the constructed -function returns True. - -Parameters ----------- -attr : string | list - The node attribute to compare, or a list of node attributes - to compare. -default : value | list - The default value for the node attribute, or a list of - default values for the node attributes. -op : callable | list - The operator to use when comparing attribute values, or a list - of operators to use when comparing values for each attribute. - -Returns -------- -match : function - The customized, generic `node_match` function. - -Examples --------- ->>> from operator import eq ->>> from math import isclose ->>> from networkx.algorithms.isomorphism import generic_node_match ->>> nm = generic_node_match("weight", 1.0, isclose) ->>> nm = generic_node_match("color", "red", eq) ->>> nm = generic_node_match(["weight", "color"], [1.0, "red"], [isclose, eq]) - -""" - - -def generic_node_match(attr, default, op): - if isinstance(attr, str): - - def match(data1, data2): - return op(data1.get(attr, default), data2.get(attr, default)) - - else: - attrs = list(zip(attr, default, op)) # Python 3 - - def match(data1, data2): - for attr, d, operator in attrs: - if not operator(data1.get(attr, d), data2.get(attr, d)): - return False - else: - return True - - return match - - -generic_edge_match = copyfunc(generic_node_match, "generic_edge_match") - - -def generic_multiedge_match(attr, default, op): - """Returns a comparison function for a generic attribute. - - The value(s) of the attr(s) are compared using the specified - operators. If all the attributes are equal, then the constructed - function returns True. Potentially, the constructed edge_match - function can be slow since it must verify that no isomorphism - exists between the multiedges before it returns False. - - Parameters - ---------- - attr : string | list - The edge attribute to compare, or a list of node attributes - to compare. - default : value | list - The default value for the edge attribute, or a list of - default values for the edgeattributes. - op : callable | list - The operator to use when comparing attribute values, or a list - of operators to use when comparing values for each attribute. - - Returns - ------- - match : function - The customized, generic `edge_match` function. - - Examples - -------- - >>> from operator import eq - >>> from math import isclose - >>> from networkx.algorithms.isomorphism import generic_node_match - >>> nm = generic_node_match("weight", 1.0, isclose) - >>> nm = generic_node_match("color", "red", eq) - >>> nm = generic_node_match(["weight", "color"], [1.0, "red"], [isclose, eq]) - - """ - - # This is slow, but generic. - # We must test every possible isomorphism between the edges. - if isinstance(attr, str): - attr = [attr] - default = [default] - op = [op] - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = [] - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.append(x) - values2 = [] - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.append(x) - for vals2 in permutations(values2): - for xi, yi in zip(values1, vals2): - if not all(map(lambda x, y, z: z(x, y), xi, yi, op)): - # This is not an isomorphism, go to next permutation. - break - else: - # Then we found an isomorphism. - return True - else: - # Then there are no isomorphisms between the multiedges. - return False - - return match - - -# Docstrings for numerical functions. -generic_node_match.__doc__ = generic_doc -generic_edge_match.__doc__ = generic_doc.replace("node", "edge") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/temporalisomorphvf2.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/temporalisomorphvf2.py deleted file mode 100644 index 62cacc7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/temporalisomorphvf2.py +++ /dev/null @@ -1,308 +0,0 @@ -""" -***************************** -Time-respecting VF2 Algorithm -***************************** - -An extension of the VF2 algorithm for time-respecting graph isomorphism -testing in temporal graphs. - -A temporal graph is one in which edges contain a datetime attribute, -denoting when interaction occurred between the incident nodes. A -time-respecting subgraph of a temporal graph is a subgraph such that -all interactions incident to a node occurred within a time threshold, -delta, of each other. A directed time-respecting subgraph has the -added constraint that incoming interactions to a node must precede -outgoing interactions from the same node - this enforces a sense of -directed flow. - -Introduction ------------- - -The TimeRespectingGraphMatcher and TimeRespectingDiGraphMatcher -extend the GraphMatcher and DiGraphMatcher classes, respectively, -to include temporal constraints on matches. This is achieved through -a semantic check, via the semantic_feasibility() function. - -As well as including G1 (the graph in which to seek embeddings) and -G2 (the subgraph structure of interest), the name of the temporal -attribute on the edges and the time threshold, delta, must be supplied -as arguments to the matching constructors. - -A delta of zero is the strictest temporal constraint on the match - -only embeddings in which all interactions occur at the same time will -be returned. A delta of one day will allow embeddings in which -adjacent interactions occur up to a day apart. - -Examples --------- - -Examples will be provided when the datetime type has been incorporated. - - -Temporal Subgraph Isomorphism ------------------------------ - -A brief discussion of the somewhat diverse current literature will be -included here. - -References ----------- - -[1] Redmond, U. and Cunningham, P. Temporal subgraph isomorphism. In: -The 2013 IEEE/ACM International Conference on Advances in Social -Networks Analysis and Mining (ASONAM). Niagara Falls, Canada; 2013: -pages 1451 - 1452. [65] - -For a discussion of the literature on temporal networks: - -[3] P. Holme and J. Saramaki. Temporal networks. Physics Reports, -519(3):97–125, 2012. - -Notes ------ - -Handles directed and undirected graphs and graphs with parallel edges. - -""" - -import networkx as nx - -from .isomorphvf2 import DiGraphMatcher, GraphMatcher - -__all__ = ["TimeRespectingGraphMatcher", "TimeRespectingDiGraphMatcher"] - - -class TimeRespectingGraphMatcher(GraphMatcher): - def __init__(self, G1, G2, temporal_attribute_name, delta): - """Initialize TimeRespectingGraphMatcher. - - G1 and G2 should be nx.Graph or nx.MultiGraph instances. - - Examples - -------- - To create a TimeRespectingGraphMatcher which checks for - syntactic and semantic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> from datetime import timedelta - >>> G1 = nx.Graph(nx.path_graph(4, create_using=nx.Graph())) - - >>> G2 = nx.Graph(nx.path_graph(4, create_using=nx.Graph())) - - >>> GM = isomorphism.TimeRespectingGraphMatcher( - ... G1, G2, "date", timedelta(days=1) - ... ) - """ - self.temporal_attribute_name = temporal_attribute_name - self.delta = delta - super().__init__(G1, G2) - - def one_hop(self, Gx, Gx_node, neighbors): - """ - Edges one hop out from a node in the mapping should be - time-respecting with respect to each other. - """ - dates = [] - for n in neighbors: - if isinstance(Gx, nx.Graph): # Graph G[u][v] returns the data dictionary. - dates.append(Gx[Gx_node][n][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for edge in Gx[Gx_node][ - n - ].values(): # Iterates all edges between node pair. - dates.append(edge[self.temporal_attribute_name]) - if any(x is None for x in dates): - raise ValueError("Datetime not supplied for at least one edge.") - return not dates or max(dates) - min(dates) <= self.delta - - def two_hop(self, Gx, core_x, Gx_node, neighbors): - """ - Paths of length 2 from Gx_node should be time-respecting. - """ - return all( - self.one_hop(Gx, v, [n for n in Gx[v] if n in core_x] + [Gx_node]) - for v in neighbors - ) - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is semantically - feasible. - - Any subclass which redefines semantic_feasibility() must - maintain the self.tests if needed, to keep the match() method - functional. Implementations should consider multigraphs. - """ - neighbors = [n for n in self.G1[G1_node] if n in self.core_1] - if not self.one_hop(self.G1, G1_node, neighbors): # Fail fast on first node. - return False - if not self.two_hop(self.G1, self.core_1, G1_node, neighbors): - return False - # Otherwise, this node is semantically feasible! - return True - - -class TimeRespectingDiGraphMatcher(DiGraphMatcher): - def __init__(self, G1, G2, temporal_attribute_name, delta): - """Initialize TimeRespectingDiGraphMatcher. - - G1 and G2 should be nx.DiGraph or nx.MultiDiGraph instances. - - Examples - -------- - To create a TimeRespectingDiGraphMatcher which checks for - syntactic and semantic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> from datetime import timedelta - >>> G1 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - - >>> G2 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - - >>> GM = isomorphism.TimeRespectingDiGraphMatcher( - ... G1, G2, "date", timedelta(days=1) - ... ) - """ - self.temporal_attribute_name = temporal_attribute_name - self.delta = delta - super().__init__(G1, G2) - - def get_pred_dates(self, Gx, Gx_node, core_x, pred): - """ - Get the dates of edges from predecessors. - """ - pred_dates = [] - if isinstance(Gx, nx.DiGraph): # Graph G[u][v] returns the data dictionary. - for n in pred: - pred_dates.append(Gx[n][Gx_node][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for n in pred: - for edge in Gx[n][ - Gx_node - ].values(): # Iterates all edge data between node pair. - pred_dates.append(edge[self.temporal_attribute_name]) - return pred_dates - - def get_succ_dates(self, Gx, Gx_node, core_x, succ): - """ - Get the dates of edges to successors. - """ - succ_dates = [] - if isinstance(Gx, nx.DiGraph): # Graph G[u][v] returns the data dictionary. - for n in succ: - succ_dates.append(Gx[Gx_node][n][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for n in succ: - for edge in Gx[Gx_node][ - n - ].values(): # Iterates all edge data between node pair. - succ_dates.append(edge[self.temporal_attribute_name]) - return succ_dates - - def one_hop(self, Gx, Gx_node, core_x, pred, succ): - """ - The ego node. - """ - pred_dates = self.get_pred_dates(Gx, Gx_node, core_x, pred) - succ_dates = self.get_succ_dates(Gx, Gx_node, core_x, succ) - return self.test_one(pred_dates, succ_dates) and self.test_two( - pred_dates, succ_dates - ) - - def two_hop_pred(self, Gx, Gx_node, core_x, pred): - """ - The predecessors of the ego node. - """ - return all( - self.one_hop( - Gx, - p, - core_x, - self.preds(Gx, core_x, p), - self.succs(Gx, core_x, p, Gx_node), - ) - for p in pred - ) - - def two_hop_succ(self, Gx, Gx_node, core_x, succ): - """ - The successors of the ego node. - """ - return all( - self.one_hop( - Gx, - s, - core_x, - self.preds(Gx, core_x, s, Gx_node), - self.succs(Gx, core_x, s), - ) - for s in succ - ) - - def preds(self, Gx, core_x, v, Gx_node=None): - pred = [n for n in Gx.predecessors(v) if n in core_x] - if Gx_node: - pred.append(Gx_node) - return pred - - def succs(self, Gx, core_x, v, Gx_node=None): - succ = [n for n in Gx.successors(v) if n in core_x] - if Gx_node: - succ.append(Gx_node) - return succ - - def test_one(self, pred_dates, succ_dates): - """ - Edges one hop out from Gx_node in the mapping should be - time-respecting with respect to each other, regardless of - direction. - """ - time_respecting = True - dates = pred_dates + succ_dates - - if any(x is None for x in dates): - raise ValueError("Date or datetime not supplied for at least one edge.") - - dates.sort() # Small to large. - if 0 < len(dates) and not (dates[-1] - dates[0] <= self.delta): - time_respecting = False - return time_respecting - - def test_two(self, pred_dates, succ_dates): - """ - Edges from a dual Gx_node in the mapping should be ordered in - a time-respecting manner. - """ - time_respecting = True - pred_dates.sort() - succ_dates.sort() - # First out before last in; negative of the necessary condition for time-respect. - if ( - 0 < len(succ_dates) - and 0 < len(pred_dates) - and succ_dates[0] < pred_dates[-1] - ): - time_respecting = False - return time_respecting - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is semantically - feasible. - - Any subclass which redefines semantic_feasibility() must - maintain the self.tests if needed, to keep the match() method - functional. Implementations should consider multigraphs. - """ - pred, succ = ( - [n for n in self.G1.predecessors(G1_node) if n in self.core_1], - [n for n in self.G1.successors(G1_node) if n in self.core_1], - ) - if not self.one_hop( - self.G1, G1_node, self.core_1, pred, succ - ): # Fail fast on first node. - return False - if not self.two_hop_pred(self.G1, G1_node, self.core_1, pred): - return False - if not self.two_hop_succ(self.G1, G1_node, self.core_1, succ): - return False - # Otherwise, this node is semantically feasible! - return True diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 deleted file mode 100644 index dac54f0..0000000 Binary files a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 and /dev/null differ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 deleted file mode 100644 index 6c6af68..0000000 Binary files a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 and /dev/null differ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 deleted file mode 100644 index 60c3a3c..0000000 Binary files a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 and /dev/null differ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 deleted file mode 100644 index 0236872..0000000 Binary files a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 and /dev/null differ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_ismags.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_ismags.py deleted file mode 100644 index bc4070a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_ismags.py +++ /dev/null @@ -1,327 +0,0 @@ -""" -Tests for ISMAGS isomorphism algorithm. -""" - -import pytest - -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -def _matches_to_sets(matches): - """ - Helper function to facilitate comparing collections of dictionaries in - which order does not matter. - """ - return {frozenset(m.items()) for m in matches} - - -class TestSelfIsomorphism: - data = [ - ( - [ - (0, {"name": "a"}), - (1, {"name": "a"}), - (2, {"name": "b"}), - (3, {"name": "b"}), - (4, {"name": "a"}), - (5, {"name": "a"}), - ], - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)], - ), - (range(1, 5), [(1, 2), (2, 4), (4, 3), (3, 1)]), - ( - [], - [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 0), - (0, 6), - (6, 7), - (2, 8), - (8, 9), - (4, 10), - (10, 11), - ], - ), - ([], [(0, 1), (1, 2), (1, 4), (2, 3), (3, 5), (3, 6)]), - ] - - def test_self_isomorphism(self): - """ - For some small, symmetric graphs, make sure that 1) they are isomorphic - to themselves, and 2) that only the identity mapping is found. - """ - for node_data, edge_data in self.data: - graph = nx.Graph() - graph.add_nodes_from(node_data) - graph.add_edges_from(edge_data) - - ismags = iso.ISMAGS( - graph, graph, node_match=iso.categorical_node_match("name", None) - ) - assert ismags.is_isomorphic() - assert ismags.subgraph_is_isomorphic() - assert list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == [ - {n: n for n in graph.nodes} - ] - - def test_edgecase_self_isomorphism(self): - """ - This edgecase is one of the cases in which it is hard to find all - symmetry elements. - """ - graph = nx.Graph() - nx.add_path(graph, range(5)) - graph.add_edges_from([(2, 5), (5, 6)]) - - ismags = iso.ISMAGS(graph, graph) - ismags_answer = list(ismags.find_isomorphisms(True)) - assert ismags_answer == [{n: n for n in graph.nodes}] - - graph = nx.relabel_nodes(graph, {0: 0, 1: 1, 2: 2, 3: 3, 4: 6, 5: 4, 6: 5}) - ismags = iso.ISMAGS(graph, graph) - ismags_answer = list(ismags.find_isomorphisms(True)) - assert ismags_answer == [{n: n for n in graph.nodes}] - - def test_directed_self_isomorphism(self): - """ - For some small, directed, symmetric graphs, make sure that 1) they are - isomorphic to themselves, and 2) that only the identity mapping is - found. - """ - for node_data, edge_data in self.data: - graph = nx.Graph() - graph.add_nodes_from(node_data) - graph.add_edges_from(edge_data) - - ismags = iso.ISMAGS( - graph, graph, node_match=iso.categorical_node_match("name", None) - ) - assert ismags.is_isomorphic() - assert ismags.subgraph_is_isomorphic() - assert list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == [ - {n: n for n in graph.nodes} - ] - - -class TestSubgraphIsomorphism: - def test_isomorphism(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(4)) - - g2 = nx.Graph() - nx.add_cycle(g2, range(4)) - g2.add_edges_from(list(zip(g2, range(4, 8)))) - ismags = iso.ISMAGS(g2, g1) - assert list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == [ - {n: n for n in g1.nodes} - ] - - def test_isomorphism2(self): - g1 = nx.Graph() - nx.add_path(g1, range(3)) - - g2 = g1.copy() - g2.add_edge(1, 3) - - ismags = iso.ISMAGS(g2, g1) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [ - {0: 0, 1: 1, 2: 2}, - {0: 0, 1: 1, 3: 2}, - {2: 0, 1: 1, 3: 2}, - ] - assert _matches_to_sets(matches) == _matches_to_sets(expected_symmetric) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [ - {0: 2, 1: 1, 2: 0}, - {0: 2, 1: 1, 3: 0}, - {2: 2, 1: 1, 3: 0}, - ] - assert _matches_to_sets(matches) == _matches_to_sets( - expected_symmetric + expected_asymmetric - ) - - def test_labeled_nodes(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(3)) - g1.nodes[1]["attr"] = True - - g2 = g1.copy() - g2.add_edge(1, 3) - ismags = iso.ISMAGS(g2, g1, node_match=lambda x, y: x == y) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [{0: 0, 1: 1, 2: 2}] - assert _matches_to_sets(matches) == _matches_to_sets(expected_symmetric) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [{0: 2, 1: 1, 2: 0}] - assert _matches_to_sets(matches) == _matches_to_sets( - expected_symmetric + expected_asymmetric - ) - - def test_labeled_edges(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(3)) - g1.edges[1, 2]["attr"] = True - - g2 = g1.copy() - g2.add_edge(1, 3) - ismags = iso.ISMAGS(g2, g1, edge_match=lambda x, y: x == y) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [{0: 0, 1: 1, 2: 2}] - assert _matches_to_sets(matches) == _matches_to_sets(expected_symmetric) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [{1: 2, 0: 0, 2: 1}] - assert _matches_to_sets(matches) == _matches_to_sets( - expected_symmetric + expected_asymmetric - ) - - -class TestWikipediaExample: - # Nodes 'a', 'b', 'c' and 'd' form a column. - # Nodes 'g', 'h', 'i' and 'j' form a column. - g1edges = [ - ["a", "g"], - ["a", "h"], - ["a", "i"], - ["b", "g"], - ["b", "h"], - ["b", "j"], - ["c", "g"], - ["c", "i"], - ["c", "j"], - ["d", "h"], - ["d", "i"], - ["d", "j"], - ] - - # Nodes 1,2,3,4 form the clockwise corners of a large square. - # Nodes 5,6,7,8 form the clockwise corners of a small square - g2edges = [ - [1, 2], - [2, 3], - [3, 4], - [4, 1], - [5, 6], - [6, 7], - [7, 8], - [8, 5], - [1, 5], - [2, 6], - [3, 7], - [4, 8], - ] - - def test_graph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - gm = iso.ISMAGS(g1, g2) - assert gm.is_isomorphic() - - -class TestLargestCommonSubgraph: - def test_mcis(self): - # Example graphs from DOI: 10.1002/spe.588 - graph1 = nx.Graph() - graph1.add_edges_from([(1, 2), (2, 3), (2, 4), (3, 4), (4, 5)]) - graph1.nodes[1]["color"] = 0 - - graph2 = nx.Graph() - graph2.add_edges_from( - [(1, 2), (2, 3), (2, 4), (3, 4), (3, 5), (5, 6), (5, 7), (6, 7)] - ) - graph2.nodes[1]["color"] = 1 - graph2.nodes[6]["color"] = 2 - graph2.nodes[7]["color"] = 2 - - ismags = iso.ISMAGS( - graph1, graph2, node_match=iso.categorical_node_match("color", None) - ) - assert list(ismags.subgraph_isomorphisms_iter(True)) == [] - assert list(ismags.subgraph_isomorphisms_iter(False)) == [] - found_mcis = _matches_to_sets(ismags.largest_common_subgraph()) - expected = _matches_to_sets( - [{2: 2, 3: 4, 4: 3, 5: 5}, {2: 4, 3: 2, 4: 3, 5: 5}] - ) - assert expected == found_mcis - - ismags = iso.ISMAGS( - graph2, graph1, node_match=iso.categorical_node_match("color", None) - ) - assert list(ismags.subgraph_isomorphisms_iter(True)) == [] - assert list(ismags.subgraph_isomorphisms_iter(False)) == [] - found_mcis = _matches_to_sets(ismags.largest_common_subgraph()) - # Same answer, but reversed. - expected = _matches_to_sets( - [{2: 2, 3: 4, 4: 3, 5: 5}, {4: 2, 2: 3, 3: 4, 5: 5}] - ) - assert expected == found_mcis - - def test_symmetry_mcis(self): - graph1 = nx.Graph() - nx.add_path(graph1, range(4)) - - graph2 = nx.Graph() - nx.add_path(graph2, range(3)) - graph2.add_edge(1, 3) - - # Only the symmetry of graph2 is taken into account here. - ismags1 = iso.ISMAGS( - graph1, graph2, node_match=iso.categorical_node_match("color", None) - ) - assert list(ismags1.subgraph_isomorphisms_iter(True)) == [] - found_mcis = _matches_to_sets(ismags1.largest_common_subgraph()) - expected = _matches_to_sets([{0: 0, 1: 1, 2: 2}, {1: 0, 3: 2, 2: 1}]) - assert expected == found_mcis - - # Only the symmetry of graph1 is taken into account here. - ismags2 = iso.ISMAGS( - graph2, graph1, node_match=iso.categorical_node_match("color", None) - ) - assert list(ismags2.subgraph_isomorphisms_iter(True)) == [] - found_mcis = _matches_to_sets(ismags2.largest_common_subgraph()) - expected = _matches_to_sets( - [ - {3: 2, 0: 0, 1: 1}, - {2: 0, 0: 2, 1: 1}, - {3: 0, 0: 2, 1: 1}, - {3: 0, 1: 1, 2: 2}, - {0: 0, 1: 1, 2: 2}, - {2: 0, 3: 2, 1: 1}, - ] - ) - - assert expected == found_mcis - - found_mcis1 = _matches_to_sets(ismags1.largest_common_subgraph(False)) - found_mcis2 = ismags2.largest_common_subgraph(False) - found_mcis2 = [{v: k for k, v in d.items()} for d in found_mcis2] - found_mcis2 = _matches_to_sets(found_mcis2) - - expected = _matches_to_sets( - [ - {3: 2, 1: 3, 2: 1}, - {2: 0, 0: 2, 1: 1}, - {1: 2, 3: 3, 2: 1}, - {3: 0, 1: 3, 2: 1}, - {0: 2, 2: 3, 1: 1}, - {3: 0, 1: 2, 2: 1}, - {2: 0, 0: 3, 1: 1}, - {0: 0, 2: 3, 1: 1}, - {1: 0, 3: 3, 2: 1}, - {1: 0, 3: 2, 2: 1}, - {0: 3, 1: 1, 2: 2}, - {0: 0, 1: 1, 2: 2}, - ] - ) - assert expected == found_mcis1 - assert expected == found_mcis2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphism.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphism.py deleted file mode 100644 index 548af80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphism.py +++ /dev/null @@ -1,48 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -class TestIsomorph: - @classmethod - def setup_class(cls): - cls.G1 = nx.Graph() - cls.G2 = nx.Graph() - cls.G3 = nx.Graph() - cls.G4 = nx.Graph() - cls.G5 = nx.Graph() - cls.G6 = nx.Graph() - cls.G1.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 3]]) - cls.G2.add_edges_from([[10, 20], [20, 30], [10, 30], [10, 50]]) - cls.G3.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 5]]) - cls.G4.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 4]]) - cls.G5.add_edges_from([[1, 2], [1, 3]]) - cls.G6.add_edges_from([[10, 20], [20, 30], [10, 30], [10, 50], [20, 50]]) - - def test_could_be_isomorphic(self): - assert iso.could_be_isomorphic(self.G1, self.G2) - assert iso.could_be_isomorphic(self.G1, self.G3) - assert not iso.could_be_isomorphic(self.G1, self.G4) - assert iso.could_be_isomorphic(self.G3, self.G2) - assert not iso.could_be_isomorphic(self.G1, self.G6) - - def test_fast_could_be_isomorphic(self): - assert iso.fast_could_be_isomorphic(self.G3, self.G2) - assert not iso.fast_could_be_isomorphic(self.G3, self.G5) - assert not iso.fast_could_be_isomorphic(self.G1, self.G6) - - def test_faster_could_be_isomorphic(self): - assert iso.faster_could_be_isomorphic(self.G3, self.G2) - assert not iso.faster_could_be_isomorphic(self.G3, self.G5) - assert not iso.faster_could_be_isomorphic(self.G1, self.G6) - - def test_is_isomorphic(self): - assert iso.is_isomorphic(self.G1, self.G2) - assert not iso.is_isomorphic(self.G1, self.G4) - assert iso.is_isomorphic(self.G1.to_directed(), self.G2.to_directed()) - assert not iso.is_isomorphic(self.G1.to_directed(), self.G4.to_directed()) - with pytest.raises( - nx.NetworkXError, match="Graphs G1 and G2 are not of the same type." - ): - iso.is_isomorphic(self.G1.to_directed(), self.G1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py deleted file mode 100644 index 413dfaf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +++ /dev/null @@ -1,410 +0,0 @@ -""" -Tests for VF2 isomorphism algorithm. -""" - -import importlib.resources -import os -import random -import struct - -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -class TestWikipediaExample: - # Source: https://en.wikipedia.org/wiki/Graph_isomorphism - - # Nodes 'a', 'b', 'c' and 'd' form a column. - # Nodes 'g', 'h', 'i' and 'j' form a column. - g1edges = [ - ["a", "g"], - ["a", "h"], - ["a", "i"], - ["b", "g"], - ["b", "h"], - ["b", "j"], - ["c", "g"], - ["c", "i"], - ["c", "j"], - ["d", "h"], - ["d", "i"], - ["d", "j"], - ] - - # Nodes 1,2,3,4 form the clockwise corners of a large square. - # Nodes 5,6,7,8 form the clockwise corners of a small square - g2edges = [ - [1, 2], - [2, 3], - [3, 4], - [4, 1], - [5, 6], - [6, 7], - [7, 8], - [8, 5], - [1, 5], - [2, 6], - [3, 7], - [4, 8], - ] - - def test_graph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - gm = iso.GraphMatcher(g1, g2) - assert gm.is_isomorphic() - # Just testing some cases - assert gm.subgraph_is_monomorphic() - - mapping = sorted(gm.mapping.items()) - - # this mapping is only one of the possibilities - # so this test needs to be reconsidered - # isomap = [('a', 1), ('b', 6), ('c', 3), ('d', 8), - # ('g', 2), ('h', 5), ('i', 4), ('j', 7)] - # assert_equal(mapping, isomap) - - def test_subgraph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - g3 = g2.subgraph([1, 2, 3, 4]) - gm = iso.GraphMatcher(g1, g3) - assert gm.subgraph_is_isomorphic() - - def test_subgraph_mono(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from([[1, 2], [2, 3], [3, 4]]) - gm = iso.GraphMatcher(g1, g2) - assert gm.subgraph_is_monomorphic() - - -class TestVF2GraphDB: - # https://web.archive.org/web/20090303210205/http://amalfi.dis.unina.it/graph/db/ - - @staticmethod - def create_graph(filename): - """Creates a Graph instance from the filename.""" - - # The file is assumed to be in the format from the VF2 graph database. - # Each file is composed of 16-bit numbers (unsigned short int). - # So we will want to read 2 bytes at a time. - - # We can read the number as follows: - # number = struct.unpack(' 0 - assert check_isomorphism(t1, t2, isomorphism) - - -# run positive_single_tree over all the -# non-isomorphic trees for k from 4 to maxk -# k = 4 is the first level that has more than 1 non-isomorphic tree -# k = 13 takes about 2.86 seconds to run on my laptop -# larger values run slow down significantly -# as the number of trees grows rapidly -def test_positive(maxk=14): - print("positive test") - - for k in range(2, maxk + 1): - start_time = time.time() - trial = 0 - for t in nx.nonisomorphic_trees(k): - positive_single_tree(t) - trial += 1 - print(k, trial, time.time() - start_time) - - -# test the trivial case of a single node in each tree -# note that nonisomorphic_trees doesn't work for k = 1 -def test_trivial(): - print("trivial test") - - # back to an undirected graph - t1 = nx.Graph() - t1.add_node("a") - root1 = "a" - - t2 = nx.Graph() - t2.add_node("n") - root2 = "n" - - isomorphism = rooted_tree_isomorphism(t1, root1, t2, root2) - - assert isomorphism == [("a", "n")] - - assert check_isomorphism(t1, t2, isomorphism) - - -# test another trivial case where the two graphs have -# different numbers of nodes -def test_trivial_2(): - print("trivial test 2") - - edges_1 = [("a", "b"), ("a", "c")] - - edges_2 = [("v", "y")] - - t1 = nx.Graph() - t1.add_edges_from(edges_1) - - t2 = nx.Graph() - t2.add_edges_from(edges_2) - - isomorphism = tree_isomorphism(t1, t2) - - # they cannot be isomorphic, - # since they have different numbers of nodes - assert isomorphism == [] - - -# the function nonisomorphic_trees generates all the non-isomorphic -# trees of a given size. Take each pair of these and verify that -# they are not isomorphic -# k = 4 is the first level that has more than 1 non-isomorphic tree -# k = 11 takes about 4.76 seconds to run on my laptop -# larger values run slow down significantly -# as the number of trees grows rapidly -def test_negative(maxk=11): - print("negative test") - - for k in range(4, maxk + 1): - test_trees = list(nx.nonisomorphic_trees(k)) - start_time = time.time() - trial = 0 - for i in range(len(test_trees) - 1): - for j in range(i + 1, len(test_trees)): - trial += 1 - assert tree_isomorphism(test_trees[i], test_trees[j]) == [] - print(k, trial, time.time() - start_time) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp.py deleted file mode 100644 index 5f3fb90..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp.py +++ /dev/null @@ -1,1608 +0,0 @@ -import itertools as it - -import pytest - -import networkx as nx -from networkx import vf2pp_is_isomorphic, vf2pp_isomorphism - -labels_same = ["blue"] - -labels_many = [ - "white", - "red", - "blue", - "green", - "orange", - "black", - "purple", - "yellow", - "brown", - "cyan", - "solarized", - "pink", - "none", -] - - -class TestPreCheck: - def test_first_graph_empty(self): - G1 = nx.Graph() - G2 = nx.Graph([(0, 1), (1, 2)]) - assert not vf2pp_is_isomorphic(G1, G2) - - def test_second_graph_empty(self): - G1 = nx.Graph([(0, 1), (1, 2)]) - G2 = nx.Graph() - assert not vf2pp_is_isomorphic(G1, G2) - - def test_different_order1(self): - G1 = nx.path_graph(5) - G2 = nx.path_graph(6) - assert not vf2pp_is_isomorphic(G1, G2) - - def test_different_order2(self): - G1 = nx.barbell_graph(100, 20) - G2 = nx.barbell_graph(101, 20) - assert not vf2pp_is_isomorphic(G1, G2) - - def test_different_order3(self): - G1 = nx.complete_graph(7) - G2 = nx.complete_graph(8) - assert not vf2pp_is_isomorphic(G1, G2) - - def test_different_degree_sequences1(self): - G1 = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (0, 4)]) - G2 = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (0, 4), (2, 5)]) - assert not vf2pp_is_isomorphic(G1, G2) - - G2.remove_node(3) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(["a"]))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle("a"))), "label") - - assert vf2pp_is_isomorphic(G1, G2) - - def test_different_degree_sequences2(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (0, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (6, 3), - (4, 7), - (7, 8), - (8, 3), - ] - ) - G2 = G1.copy() - G2.add_edge(8, 0) - assert not vf2pp_is_isomorphic(G1, G2) - - G1.add_edge(6, 1) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(["a"]))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle("a"))), "label") - - assert vf2pp_is_isomorphic(G1, G2) - - def test_different_degree_sequences3(self): - G1 = nx.Graph([(0, 1), (0, 2), (1, 2), (2, 3), (2, 4), (3, 4), (2, 5), (2, 6)]) - G2 = nx.Graph( - [(0, 1), (0, 6), (0, 2), (1, 2), (2, 3), (2, 4), (3, 4), (2, 5), (2, 6)] - ) - assert not vf2pp_is_isomorphic(G1, G2) - - G1.add_edge(3, 5) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(["a"]))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle("a"))), "label") - - assert vf2pp_is_isomorphic(G1, G2) - - def test_label_distribution(self): - G1 = nx.Graph([(0, 1), (0, 2), (1, 2), (2, 3), (2, 4), (3, 4), (2, 5), (2, 6)]) - G2 = nx.Graph([(0, 1), (0, 2), (1, 2), (2, 3), (2, 4), (3, 4), (2, 5), (2, 6)]) - - colors1 = ["blue", "blue", "blue", "yellow", "black", "purple", "purple"] - colors2 = ["blue", "blue", "yellow", "yellow", "black", "purple", "purple"] - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(colors1[::-1]))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(colors2[::-1]))), "label") - - assert not vf2pp_is_isomorphic(G1, G2, node_label="label") - G2.nodes[3]["label"] = "blue" - assert vf2pp_is_isomorphic(G1, G2, node_label="label") - - -class TestAllGraphTypesEdgeCases: - @pytest.mark.parametrize("graph_type", (nx.Graph, nx.MultiGraph, nx.DiGraph)) - def test_both_graphs_empty(self, graph_type): - G = graph_type() - H = graph_type() - assert vf2pp_isomorphism(G, H) is None - - G.add_node(0) - - assert vf2pp_isomorphism(G, H) is None - assert vf2pp_isomorphism(H, G) is None - - H.add_node(0) - assert vf2pp_isomorphism(G, H) == {0: 0} - - @pytest.mark.parametrize("graph_type", (nx.Graph, nx.MultiGraph, nx.DiGraph)) - def test_first_graph_empty(self, graph_type): - G = graph_type() - H = graph_type([(0, 1)]) - assert vf2pp_isomorphism(G, H) is None - - @pytest.mark.parametrize("graph_type", (nx.Graph, nx.MultiGraph, nx.DiGraph)) - def test_second_graph_empty(self, graph_type): - G = graph_type([(0, 1)]) - H = graph_type() - assert vf2pp_isomorphism(G, H) is None - - -class TestGraphISOVF2pp: - def test_custom_graph1_same_labels(self): - G1 = nx.Graph() - - mapped = {1: "A", 2: "B", 3: "C", 4: "D", 5: "Z", 6: "E"} - edges1 = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 6), (3, 4), (5, 1), (5, 2)] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Add edge making G1 symmetrical - G1.add_edge(3, 7) - G1.nodes[7]["label"] = "blue" - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Make G2 isomorphic to G1 - G2.add_edges_from([(mapped[3], "X"), (mapped[6], mapped[5])]) - G1.add_edge(4, 7) - G2.nodes["X"]["label"] = "blue" - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Re-structure maintaining isomorphism - G1.remove_edges_from([(1, 4), (1, 3)]) - G2.remove_edges_from([(mapped[1], mapped[5]), (mapped[1], mapped[2])]) - assert vf2pp_isomorphism(G1, G2, node_label="label") - - def test_custom_graph1_different_labels(self): - G1 = nx.Graph() - - mapped = {1: "A", 2: "B", 3: "C", 4: "D", 5: "Z", 6: "E"} - edges1 = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 6), (3, 4), (5, 1), (5, 2)] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - def test_custom_graph2_same_labels(self): - G1 = nx.Graph() - - mapped = {1: "A", 2: "C", 3: "D", 4: "E", 5: "G", 7: "B", 6: "F"} - edges1 = [(1, 2), (1, 5), (5, 6), (2, 3), (2, 4), (3, 4), (4, 5), (2, 7)] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Obtain two isomorphic subgraphs from the graph - G2.remove_edge(mapped[1], mapped[2]) - G2.add_edge(mapped[1], mapped[4]) - H1 = nx.Graph(G1.subgraph([2, 3, 4, 7])) - H2 = nx.Graph(G2.subgraph([mapped[1], mapped[4], mapped[5], mapped[6]])) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - # Add edges maintaining isomorphism - H1.add_edges_from([(3, 7), (4, 7)]) - H2.add_edges_from([(mapped[1], mapped[6]), (mapped[4], mapped[6])]) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - def test_custom_graph2_different_labels(self): - G1 = nx.Graph() - - mapped = {1: "A", 2: "C", 3: "D", 4: "E", 5: "G", 7: "B", 6: "F"} - edges1 = [(1, 2), (1, 5), (5, 6), (2, 3), (2, 4), (3, 4), (4, 5), (2, 7)] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - - # Adding new nodes - G1.add_node(0) - G2.add_node("Z") - G1.nodes[0]["label"] = G1.nodes[1]["label"] - G2.nodes["Z"]["label"] = G1.nodes[1]["label"] - mapped.update({0: "Z"}) - - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - # Change the color of one of the nodes - G2.nodes["Z"]["label"] = G1.nodes[2]["label"] - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Add an extra edge - G1.nodes[0]["label"] = "blue" - G2.nodes["Z"]["label"] = "blue" - G1.add_edge(0, 1) - - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Add extra edge to both - G2.add_edge("Z", "A") - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - def test_custom_graph3_same_labels(self): - G1 = nx.Graph() - - mapped = {1: 9, 2: 8, 3: 7, 4: 6, 5: 3, 8: 5, 9: 4, 7: 1, 6: 2} - edges1 = [ - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (4, 7), - (4, 9), - (5, 8), - (8, 9), - (5, 6), - (6, 7), - (5, 2), - ] - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Connect nodes maintaining symmetry - G1.add_edges_from([(6, 9), (7, 8)]) - G2.add_edges_from([(mapped[6], mapped[8]), (mapped[7], mapped[9])]) - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Make isomorphic - G1.add_edges_from([(6, 8), (7, 9)]) - G2.add_edges_from([(mapped[6], mapped[9]), (mapped[7], mapped[8])]) - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Connect more nodes - G1.add_edges_from([(2, 7), (3, 6)]) - G2.add_edges_from([(mapped[2], mapped[7]), (mapped[3], mapped[6])]) - G1.add_node(10) - G2.add_node("Z") - G1.nodes[10]["label"] = "blue" - G2.nodes["Z"]["label"] = "blue" - - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Connect the newly added node, to opposite sides of the graph - G1.add_edges_from([(10, 1), (10, 5), (10, 8)]) - G2.add_edges_from([("Z", mapped[1]), ("Z", mapped[4]), ("Z", mapped[9])]) - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Get two subgraphs that are not isomorphic but are easy to make - H1 = nx.Graph(G1.subgraph([2, 3, 4, 5, 6, 7, 10])) - H2 = nx.Graph( - G2.subgraph( - [mapped[4], mapped[5], mapped[6], mapped[7], mapped[8], mapped[9], "Z"] - ) - ) - assert vf2pp_isomorphism(H1, H2, node_label="label") is None - - # Restructure both to make them isomorphic - H1.add_edges_from([(10, 2), (10, 6), (3, 6), (2, 7), (2, 6), (3, 7)]) - H2.add_edges_from( - [("Z", mapped[7]), (mapped[6], mapped[9]), (mapped[7], mapped[8])] - ) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - # Add edges with opposite direction in each Graph - H1.add_edge(3, 5) - H2.add_edge(mapped[5], mapped[7]) - assert vf2pp_isomorphism(H1, H2, node_label="label") is None - - def test_custom_graph3_different_labels(self): - G1 = nx.Graph() - - mapped = {1: 9, 2: 8, 3: 7, 4: 6, 5: 3, 8: 5, 9: 4, 7: 1, 6: 2} - edges1 = [ - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (4, 7), - (4, 9), - (5, 8), - (8, 9), - (5, 6), - (6, 7), - (5, 2), - ] - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - # Add extra edge to G1 - G1.add_edge(1, 7) - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Compensate in G2 - G2.add_edge(9, 1) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - # Add extra node - G1.add_node("A") - G2.add_node("K") - G1.nodes["A"]["label"] = "green" - G2.nodes["K"]["label"] = "green" - mapped.update({"A": "K"}) - - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - # Connect A to one side of G1 and K to the opposite - G1.add_edge("A", 6) - G2.add_edge("K", 5) - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Make the graphs symmetrical - G1.add_edge(1, 5) - G1.add_edge(2, 9) - G2.add_edge(9, 3) - G2.add_edge(8, 4) - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Assign same colors so the two opposite sides are identical - for node in G1.nodes(): - color = "red" - G1.nodes[node]["label"] = color - G2.nodes[mapped[node]]["label"] = color - - assert vf2pp_isomorphism(G1, G2, node_label="label") - - def test_custom_graph4_different_labels(self): - G1 = nx.Graph() - edges1 = [ - (1, 2), - (2, 3), - (3, 8), - (3, 4), - (4, 5), - (4, 6), - (3, 6), - (8, 7), - (8, 9), - (5, 9), - (10, 11), - (11, 12), - (12, 13), - (11, 13), - ] - - mapped = { - 1: "n", - 2: "m", - 3: "l", - 4: "j", - 5: "k", - 6: "i", - 7: "g", - 8: "h", - 9: "f", - 10: "b", - 11: "a", - 12: "d", - 13: "e", - } - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - def test_custom_graph4_same_labels(self): - G1 = nx.Graph() - edges1 = [ - (1, 2), - (2, 3), - (3, 8), - (3, 4), - (4, 5), - (4, 6), - (3, 6), - (8, 7), - (8, 9), - (5, 9), - (10, 11), - (11, 12), - (12, 13), - (11, 13), - ] - - mapped = { - 1: "n", - 2: "m", - 3: "l", - 4: "j", - 5: "k", - 6: "i", - 7: "g", - 8: "h", - 9: "f", - 10: "b", - 11: "a", - 12: "d", - 13: "e", - } - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Add nodes of different label - G1.add_node(0) - G2.add_node("z") - G1.nodes[0]["label"] = "green" - G2.nodes["z"]["label"] = "blue" - - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Make the labels identical - G2.nodes["z"]["label"] = "green" - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Change the structure of the graphs, keeping them isomorphic - G1.add_edge(2, 5) - G2.remove_edge("i", "l") - G2.add_edge("g", "l") - G2.add_edge("m", "f") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Change the structure of the disconnected sub-graph, keeping it isomorphic - G1.remove_node(13) - G2.remove_node("d") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Connect the newly added node to the disconnected graph, which now is just a path of size 3 - G1.add_edge(0, 10) - G2.add_edge("e", "z") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Connect the two disconnected sub-graphs, forming a single graph - G1.add_edge(11, 3) - G1.add_edge(0, 8) - G2.add_edge("a", "l") - G2.add_edge("z", "j") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - def test_custom_graph5_same_labels(self): - G1 = nx.Graph() - edges1 = [ - (1, 5), - (1, 2), - (1, 4), - (2, 3), - (2, 6), - (3, 4), - (3, 7), - (4, 8), - (5, 8), - (5, 6), - (6, 7), - (7, 8), - ] - mapped = {1: "a", 2: "h", 3: "d", 4: "i", 5: "g", 6: "b", 7: "j", 8: "c"} - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Add different edges in each graph, maintaining symmetry - G1.add_edges_from([(3, 6), (2, 7), (2, 5), (1, 3), (4, 7), (6, 8)]) - G2.add_edges_from( - [ - (mapped[6], mapped[3]), - (mapped[2], mapped[7]), - (mapped[1], mapped[6]), - (mapped[5], mapped[7]), - (mapped[3], mapped[8]), - (mapped[2], mapped[4]), - ] - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") - - # Obtain two different but isomorphic subgraphs from G1 and G2 - H1 = nx.Graph(G1.subgraph([1, 5, 8, 6, 7, 3])) - H2 = nx.Graph( - G2.subgraph( - [mapped[1], mapped[4], mapped[8], mapped[7], mapped[3], mapped[5]] - ) - ) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - # Delete corresponding node from the two graphs - H1.remove_node(8) - H2.remove_node(mapped[7]) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - # Re-orient, maintaining isomorphism - H1.add_edge(1, 6) - H1.remove_edge(3, 6) - assert vf2pp_isomorphism(H1, H2, node_label="label") - - def test_custom_graph5_different_labels(self): - G1 = nx.Graph() - edges1 = [ - (1, 5), - (1, 2), - (1, 4), - (2, 3), - (2, 6), - (3, 4), - (3, 7), - (4, 8), - (5, 8), - (5, 6), - (6, 7), - (7, 8), - ] - mapped = {1: "a", 2: "h", 3: "d", 4: "i", 5: "g", 6: "b", 7: "j", 8: "c"} - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - colors = ["red", "blue", "grey", "none", "brown", "solarized", "yellow", "pink"] - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - # Assign different colors to matching nodes - c = 0 - for node in G1.nodes(): - color1 = colors[c] - color2 = colors[(c + 3) % len(colors)] - G1.nodes[node]["label"] = color1 - G2.nodes[mapped[node]]["label"] = color2 - c += 1 - - assert vf2pp_isomorphism(G1, G2, node_label="label") is None - - # Get symmetrical sub-graphs of G1,G2 and compare them - H1 = G1.subgraph([1, 5]) - H2 = G2.subgraph(["i", "c"]) - c = 0 - for node1, node2 in zip(H1.nodes(), H2.nodes()): - H1.nodes[node1]["label"] = "red" - H2.nodes[node2]["label"] = "red" - c += 1 - - assert vf2pp_isomorphism(H1, H2, node_label="label") - - def test_disconnected_graph_all_same_labels(self): - G1 = nx.Graph() - G1.add_nodes_from(list(range(10))) - - mapped = {0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0} - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - assert vf2pp_isomorphism(G1, G2, node_label="label") - - def test_disconnected_graph_all_different_labels(self): - G1 = nx.Graph() - G1.add_nodes_from(list(range(10))) - - mapped = {0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0} - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - assert vf2pp_isomorphism(G1, G2, node_label="label") == mapped - - def test_disconnected_graph_some_same_labels(self): - G1 = nx.Graph() - G1.add_nodes_from(list(range(10))) - - mapped = {0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0} - G2 = nx.relabel_nodes(G1, mapped) - - colors = [ - "white", - "white", - "white", - "purple", - "purple", - "red", - "red", - "pink", - "pink", - "pink", - ] - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(colors))), "label") - nx.set_node_attributes( - G2, dict(zip([mapped[n] for n in G1], it.cycle(colors))), "label" - ) - - assert vf2pp_isomorphism(G1, G2, node_label="label") - - -class TestMultiGraphISOVF2pp: - def test_custom_multigraph1_same_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: "A", 2: "B", 3: "C", 4: "D", 5: "Z", 6: "E"} - edges1 = [ - (1, 2), - (1, 3), - (1, 4), - (1, 4), - (1, 4), - (2, 3), - (2, 6), - (2, 6), - (3, 4), - (3, 4), - (5, 1), - (5, 1), - (5, 2), - (5, 2), - ] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Transfer the 2-clique to the right side of G1 - G1.remove_edges_from([(2, 6), (2, 6)]) - G1.add_edges_from([(3, 6), (3, 6)]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Delete an edges, making them symmetrical, so the position of the 2-clique doesn't matter - G2.remove_edge(mapped[1], mapped[4]) - G1.remove_edge(1, 4) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Add self-loops - G1.add_edges_from([(5, 5), (5, 5), (1, 1)]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Compensate in G2 - G2.add_edges_from( - [(mapped[1], mapped[1]), (mapped[4], mapped[4]), (mapped[4], mapped[4])] - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - def test_custom_multigraph1_different_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: "A", 2: "B", 3: "C", 4: "D", 5: "Z", 6: "E"} - edges1 = [ - (1, 2), - (1, 3), - (1, 4), - (1, 4), - (1, 4), - (2, 3), - (2, 6), - (2, 6), - (3, 4), - (3, 4), - (5, 1), - (5, 1), - (5, 2), - (5, 2), - ] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Re-structure G1, maintaining the degree sequence - G1.remove_edge(1, 4) - G1.add_edge(1, 5) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Restructure G2, making it isomorphic to G1 - G2.remove_edge("A", "D") - G2.add_edge("A", "Z") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Add edge from node to itself - G1.add_edges_from([(6, 6), (6, 6), (6, 6)]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Same for G2 - G2.add_edges_from([("E", "E"), ("E", "E"), ("E", "E")]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - def test_custom_multigraph2_same_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: "A", 2: "C", 3: "D", 4: "E", 5: "G", 7: "B", 6: "F"} - edges1 = [ - (1, 2), - (1, 2), - (1, 5), - (1, 5), - (1, 5), - (5, 6), - (2, 3), - (2, 3), - (2, 4), - (3, 4), - (3, 4), - (4, 5), - (4, 5), - (4, 5), - (2, 7), - (2, 7), - (2, 7), - ] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Obtain two non-isomorphic subgraphs from the graph - G2.remove_edges_from([(mapped[1], mapped[2]), (mapped[1], mapped[2])]) - G2.add_edge(mapped[1], mapped[4]) - H1 = nx.MultiGraph(G1.subgraph([2, 3, 4, 7])) - H2 = nx.MultiGraph(G2.subgraph([mapped[1], mapped[4], mapped[5], mapped[6]])) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Make them isomorphic - H1.remove_edge(3, 4) - H1.add_edges_from([(2, 3), (2, 4), (2, 4)]) - H2.add_edges_from([(mapped[5], mapped[6]), (mapped[5], mapped[6])]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Remove triangle edge - H1.remove_edges_from([(2, 3), (2, 3), (2, 3)]) - H2.remove_edges_from([(mapped[5], mapped[4])] * 3) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Change the edge orientation such that H1 is rotated H2 - H1.remove_edges_from([(2, 7), (2, 7)]) - H1.add_edges_from([(3, 4), (3, 4)]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Add extra edges maintaining degree sequence, but in a non-symmetrical manner - H2.add_edge(mapped[5], mapped[1]) - H1.add_edge(3, 4) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - def test_custom_multigraph2_different_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: "A", 2: "C", 3: "D", 4: "E", 5: "G", 7: "B", 6: "F"} - edges1 = [ - (1, 2), - (1, 2), - (1, 5), - (1, 5), - (1, 5), - (5, 6), - (2, 3), - (2, 3), - (2, 4), - (3, 4), - (3, 4), - (4, 5), - (4, 5), - (4, 5), - (2, 7), - (2, 7), - (2, 7), - ] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Re-structure G1 - G1.remove_edge(2, 7) - G1.add_edge(5, 6) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Same for G2 - G2.remove_edge("B", "C") - G2.add_edge("G", "F") - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Delete node from G1 and G2, keeping them isomorphic - G1.remove_node(3) - G2.remove_node("D") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Change G1 edges - G1.remove_edge(1, 2) - G1.remove_edge(2, 7) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Make G2 identical to G1, but with different edge orientation and different labels - G2.add_edges_from([("A", "C"), ("C", "E"), ("C", "E")]) - G2.remove_edges_from( - [("A", "G"), ("A", "G"), ("F", "G"), ("E", "G"), ("E", "G")] - ) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Make all labels the same, so G1 and G2 are also isomorphic - for n1, n2 in zip(G1.nodes(), G2.nodes()): - G1.nodes[n1]["label"] = "blue" - G2.nodes[n2]["label"] = "blue" - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - def test_custom_multigraph3_same_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: 9, 2: 8, 3: 7, 4: 6, 5: 3, 8: 5, 9: 4, 7: 1, 6: 2} - edges1 = [ - (1, 2), - (1, 3), - (1, 3), - (2, 3), - (2, 3), - (3, 4), - (4, 5), - (4, 7), - (4, 9), - (4, 9), - (4, 9), - (5, 8), - (5, 8), - (8, 9), - (8, 9), - (5, 6), - (6, 7), - (6, 7), - (6, 7), - (5, 2), - ] - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Connect nodes maintaining symmetry - G1.add_edges_from([(6, 9), (7, 8), (5, 8), (4, 9), (4, 9)]) - G2.add_edges_from( - [ - (mapped[6], mapped[8]), - (mapped[7], mapped[9]), - (mapped[5], mapped[8]), - (mapped[4], mapped[9]), - (mapped[4], mapped[9]), - ] - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Make isomorphic - G1.add_edges_from([(6, 8), (6, 8), (7, 9), (7, 9), (7, 9)]) - G2.add_edges_from( - [ - (mapped[6], mapped[8]), - (mapped[6], mapped[9]), - (mapped[7], mapped[8]), - (mapped[7], mapped[9]), - (mapped[7], mapped[9]), - ] - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Connect more nodes - G1.add_edges_from([(2, 7), (2, 7), (3, 6), (3, 6)]) - G2.add_edges_from( - [ - (mapped[2], mapped[7]), - (mapped[2], mapped[7]), - (mapped[3], mapped[6]), - (mapped[3], mapped[6]), - ] - ) - G1.add_node(10) - G2.add_node("Z") - G1.nodes[10]["label"] = "blue" - G2.nodes["Z"]["label"] = "blue" - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Connect the newly added node, to opposite sides of the graph - G1.add_edges_from([(10, 1), (10, 5), (10, 8), (10, 10), (10, 10)]) - G2.add_edges_from( - [ - ("Z", mapped[1]), - ("Z", mapped[4]), - ("Z", mapped[9]), - ("Z", "Z"), - ("Z", "Z"), - ] - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # We connected the new node to opposite sides, so G1 must be symmetrical to G2. Re-structure them to be so - G1.remove_edges_from([(1, 3), (4, 9), (4, 9), (7, 9)]) - G2.remove_edges_from( - [ - (mapped[1], mapped[3]), - (mapped[4], mapped[9]), - (mapped[4], mapped[9]), - (mapped[7], mapped[9]), - ] - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Get two subgraphs that are not isomorphic but are easy to make - H1 = nx.Graph(G1.subgraph([2, 3, 4, 5, 6, 7, 10])) - H2 = nx.Graph( - G2.subgraph( - [mapped[4], mapped[5], mapped[6], mapped[7], mapped[8], mapped[9], "Z"] - ) - ) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Restructure both to make them isomorphic - H1.add_edges_from([(10, 2), (10, 6), (3, 6), (2, 7), (2, 6), (3, 7)]) - H2.add_edges_from( - [("Z", mapped[7]), (mapped[6], mapped[9]), (mapped[7], mapped[8])] - ) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Remove one self-loop in H2 - H2.remove_edge("Z", "Z") - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Compensate in H1 - H1.remove_edge(10, 10) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - def test_custom_multigraph3_different_labels(self): - G1 = nx.MultiGraph() - - mapped = {1: 9, 2: 8, 3: 7, 4: 6, 5: 3, 8: 5, 9: 4, 7: 1, 6: 2} - edges1 = [ - (1, 2), - (1, 3), - (1, 3), - (2, 3), - (2, 3), - (3, 4), - (4, 5), - (4, 7), - (4, 9), - (4, 9), - (4, 9), - (5, 8), - (5, 8), - (8, 9), - (8, 9), - (5, 6), - (6, 7), - (6, 7), - (6, 7), - (5, 2), - ] - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Delete edge maintaining isomorphism - G1.remove_edge(4, 9) - G2.remove_edge(4, 6) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Change edge orientation such that G1 mirrors G2 - G1.add_edges_from([(4, 9), (1, 2), (1, 2)]) - G1.remove_edges_from([(1, 3), (1, 3)]) - G2.add_edges_from([(3, 5), (7, 9)]) - G2.remove_edge(8, 9) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Make all labels the same, so G1 and G2 are also isomorphic - for n1, n2 in zip(G1.nodes(), G2.nodes()): - G1.nodes[n1]["label"] = "blue" - G2.nodes[n2]["label"] = "blue" - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - G1.add_node(10) - G2.add_node("Z") - G1.nodes[10]["label"] = "green" - G2.nodes["Z"]["label"] = "green" - - # Add different number of edges between the new nodes and themselves - G1.add_edges_from([(10, 10), (10, 10)]) - G2.add_edges_from([("Z", "Z")]) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Make the number of self-edges equal - G1.remove_edge(10, 10) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Connect the new node to the graph - G1.add_edges_from([(10, 3), (10, 4)]) - G2.add_edges_from([("Z", 8), ("Z", 3)]) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Remove central node - G1.remove_node(4) - G2.remove_node(3) - G1.add_edges_from([(5, 6), (5, 6), (5, 7)]) - G2.add_edges_from([(1, 6), (1, 6), (6, 2)]) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - def test_custom_multigraph4_same_labels(self): - G1 = nx.MultiGraph() - edges1 = [ - (1, 2), - (1, 2), - (2, 2), - (2, 3), - (3, 8), - (3, 8), - (3, 4), - (4, 5), - (4, 5), - (4, 5), - (4, 6), - (3, 6), - (3, 6), - (6, 6), - (8, 7), - (7, 7), - (8, 9), - (9, 9), - (8, 9), - (8, 9), - (5, 9), - (10, 11), - (11, 12), - (12, 13), - (11, 13), - (10, 10), - (10, 11), - (11, 13), - ] - - mapped = { - 1: "n", - 2: "m", - 3: "l", - 4: "j", - 5: "k", - 6: "i", - 7: "g", - 8: "h", - 9: "f", - 10: "b", - 11: "a", - 12: "d", - 13: "e", - } - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Add extra but corresponding edges to both graphs - G1.add_edges_from([(2, 2), (2, 3), (2, 8), (3, 4)]) - G2.add_edges_from([("m", "m"), ("m", "l"), ("m", "h"), ("l", "j")]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Obtain subgraphs - H1 = nx.MultiGraph(G1.subgraph([2, 3, 4, 6, 10, 11, 12, 13])) - H2 = nx.MultiGraph( - G2.subgraph( - [ - mapped[2], - mapped[3], - mapped[8], - mapped[9], - mapped[10], - mapped[11], - mapped[12], - mapped[13], - ] - ) - ) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Make them isomorphic - H2.remove_edges_from( - [(mapped[3], mapped[2]), (mapped[9], mapped[8]), (mapped[2], mapped[2])] - ) - H2.add_edges_from([(mapped[9], mapped[9]), (mapped[2], mapped[8])]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Re-structure the disconnected sub-graph - H1.remove_node(12) - H2.remove_node(mapped[12]) - H1.add_edge(13, 13) - H2.add_edge(mapped[13], mapped[13]) - - # Connect the two disconnected components, forming a single graph - H1.add_edges_from([(3, 13), (6, 11)]) - H2.add_edges_from([(mapped[8], mapped[10]), (mapped[2], mapped[11])]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Change orientation of self-loops in one graph, maintaining the degree sequence - H1.remove_edges_from([(2, 2), (3, 6)]) - H1.add_edges_from([(6, 6), (2, 3)]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - def test_custom_multigraph4_different_labels(self): - G1 = nx.MultiGraph() - edges1 = [ - (1, 2), - (1, 2), - (2, 2), - (2, 3), - (3, 8), - (3, 8), - (3, 4), - (4, 5), - (4, 5), - (4, 5), - (4, 6), - (3, 6), - (3, 6), - (6, 6), - (8, 7), - (7, 7), - (8, 9), - (9, 9), - (8, 9), - (8, 9), - (5, 9), - (10, 11), - (11, 12), - (12, 13), - (11, 13), - ] - - mapped = { - 1: "n", - 2: "m", - 3: "l", - 4: "j", - 5: "k", - 6: "i", - 7: "g", - 8: "h", - 9: "f", - 10: "b", - 11: "a", - 12: "d", - 13: "e", - } - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m == mapped - - # Add extra but corresponding edges to both graphs - G1.add_edges_from([(2, 2), (2, 3), (2, 8), (3, 4)]) - G2.add_edges_from([("m", "m"), ("m", "l"), ("m", "h"), ("l", "j")]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m == mapped - - # Obtain isomorphic subgraphs - H1 = nx.MultiGraph(G1.subgraph([2, 3, 4, 6])) - H2 = nx.MultiGraph(G2.subgraph(["m", "l", "j", "i"])) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Delete the 3-clique, keeping only the path-graph. Also, H1 mirrors H2 - H1.remove_node(4) - H2.remove_node("j") - H1.remove_edges_from([(2, 2), (2, 3), (6, 6)]) - H2.remove_edges_from([("l", "i"), ("m", "m"), ("m", "m")]) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Assign the same labels so that mirroring means isomorphic - for n1, n2 in zip(H1.nodes(), H2.nodes()): - H1.nodes[n1]["label"] = "red" - H2.nodes[n2]["label"] = "red" - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Leave only one node with self-loop - H1.remove_nodes_from([3, 6]) - H2.remove_nodes_from(["m", "l"]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Remove one self-loop from H1 - H1.remove_edge(2, 2) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert not m - - # Same for H2 - H2.remove_edge("i", "i") - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Compose H1 with the disconnected sub-graph of G1. Same for H2 - S1 = nx.compose(H1, nx.MultiGraph(G1.subgraph([10, 11, 12, 13]))) - S2 = nx.compose(H2, nx.MultiGraph(G2.subgraph(["a", "b", "d", "e"]))) - - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - # Connect the two components - S1.add_edges_from([(13, 13), (13, 13), (2, 13)]) - S2.add_edges_from([("a", "a"), ("a", "a"), ("i", "e")]) - m = vf2pp_isomorphism(H1, H2, node_label="label") - assert m - - def test_custom_multigraph5_same_labels(self): - G1 = nx.MultiGraph() - - edges1 = [ - (1, 5), - (1, 2), - (1, 4), - (2, 3), - (2, 6), - (3, 4), - (3, 7), - (4, 8), - (5, 8), - (5, 6), - (6, 7), - (7, 8), - ] - mapped = {1: "a", 2: "h", 3: "d", 4: "i", 5: "g", 6: "b", 7: "j", 8: "c"} - - G1.add_edges_from(edges1) - G2 = nx.relabel_nodes(G1, mapped) - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Add multiple edges and self-loops, maintaining isomorphism - G1.add_edges_from( - [(1, 2), (1, 2), (3, 7), (8, 8), (8, 8), (7, 8), (2, 3), (5, 6)] - ) - G2.add_edges_from( - [ - ("a", "h"), - ("a", "h"), - ("d", "j"), - ("c", "c"), - ("c", "c"), - ("j", "c"), - ("d", "h"), - ("g", "b"), - ] - ) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Make G2 to be the rotated G1 - G2.remove_edges_from( - [ - ("a", "h"), - ("a", "h"), - ("d", "j"), - ("c", "c"), - ("c", "c"), - ("j", "c"), - ("d", "h"), - ("g", "b"), - ] - ) - G2.add_edges_from( - [ - ("d", "i"), - ("a", "h"), - ("g", "b"), - ("g", "b"), - ("i", "i"), - ("i", "i"), - ("b", "j"), - ("d", "j"), - ] - ) - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - def test_disconnected_multigraph_all_same_labels(self): - G1 = nx.MultiGraph() - G1.add_nodes_from(list(range(10))) - G1.add_edges_from([(i, i) for i in range(10)]) - - mapped = {0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0} - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_same))), "label") - nx.set_node_attributes(G2, dict(zip(G2, it.cycle(labels_same))), "label") - - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Add self-loops to non-mapped nodes. Should be the same, as the graph is disconnected. - G1.add_edges_from([(i, i) for i in range(5, 8)] * 3) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Compensate in G2 - G2.add_edges_from([(i, i) for i in range(3)] * 3) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - # Add one more self-loop in G2 - G2.add_edges_from([(0, 0), (1, 1), (1, 1)]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Compensate in G1 - G1.add_edges_from([(5, 5), (7, 7), (7, 7)]) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - def test_disconnected_multigraph_all_different_labels(self): - G1 = nx.MultiGraph() - G1.add_nodes_from(list(range(10))) - G1.add_edges_from([(i, i) for i in range(10)]) - - mapped = {0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0} - G2 = nx.relabel_nodes(G1, mapped) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip([mapped[n] for n in G1], it.cycle(labels_many))), - "label", - ) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - assert m == mapped - - # Add self-loops to non-mapped nodes. Now it is not the same, as there are different labels - G1.add_edges_from([(i, i) for i in range(5, 8)] * 3) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Add self-loops to non mapped nodes in G2 as well - G2.add_edges_from([(mapped[i], mapped[i]) for i in range(3)] * 7) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Add self-loops to mapped nodes in G2 - G2.add_edges_from([(mapped[i], mapped[i]) for i in range(5, 8)] * 3) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert not m - - # Add self-loops to G1 so that they are even in both graphs - G1.add_edges_from([(i, i) for i in range(3)] * 7) - m = vf2pp_isomorphism(G1, G2, node_label="label") - assert m - - -class TestDiGraphISOVF2pp: - def test_wikipedia_graph(self): - edges1 = [ - (1, 5), - (1, 2), - (1, 4), - (3, 2), - (6, 2), - (3, 4), - (7, 3), - (4, 8), - (5, 8), - (6, 5), - (6, 7), - (7, 8), - ] - mapped = {1: "a", 2: "h", 3: "d", 4: "i", 5: "g", 6: "b", 7: "j", 8: "c"} - - G1 = nx.DiGraph(edges1) - G2 = nx.relabel_nodes(G1, mapped) - - assert vf2pp_isomorphism(G1, G2) == mapped - - # Change the direction of an edge - G1.remove_edge(1, 5) - G1.add_edge(5, 1) - assert vf2pp_isomorphism(G1, G2) is None - - def test_non_isomorphic_same_degree_sequence(self): - r""" - G1 G2 - x--------------x x--------------x - | \ | | \ | - | x-------x | | x-------x | - | | | | | | | | - | x-------x | | x-------x | - | / | | \ | - x--------------x x--------------x - """ - edges1 = [ - (1, 5), - (1, 2), - (4, 1), - (3, 2), - (3, 4), - (4, 8), - (5, 8), - (6, 5), - (6, 7), - (7, 8), - ] - edges2 = [ - (1, 5), - (1, 2), - (4, 1), - (3, 2), - (4, 3), - (5, 8), - (6, 5), - (6, 7), - (3, 7), - (8, 7), - ] - - G1 = nx.DiGraph(edges1) - G2 = nx.DiGraph(edges2) - assert vf2pp_isomorphism(G1, G2) is None diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py deleted file mode 100644 index 0e29b1b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +++ /dev/null @@ -1,3106 +0,0 @@ -import itertools as it - -import pytest - -import networkx as nx -from networkx import vf2pp_is_isomorphic, vf2pp_isomorphism -from networkx.algorithms.isomorphism.vf2pp import ( - _consistent_PT, - _cut_PT, - _feasibility, - _find_candidates, - _find_candidates_Di, - _GraphParameters, - _initialize_parameters, - _matching_order, - _restore_Tinout, - _restore_Tinout_Di, - _StateParameters, - _update_Tinout, -) - -labels_same = ["blue"] - -labels_many = [ - "white", - "red", - "blue", - "green", - "orange", - "black", - "purple", - "yellow", - "brown", - "cyan", - "solarized", - "pink", - "none", -] - - -class TestNodeOrdering: - def test_empty_graph(self): - G1 = nx.Graph() - G2 = nx.Graph() - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - assert len(set(_matching_order(gparams))) == 0 - - def test_single_node(self): - G1 = nx.Graph() - G2 = nx.Graph() - G1.add_node(1) - G2.add_node(1) - - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label") - nx.set_node_attributes( - G2, - dict(zip(G2, it.cycle(labels_many))), - "label", - ) - l1, l2 = ( - nx.get_node_attributes(G1, "label"), - nx.get_node_attributes(G2, "label"), - ) - - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - m = _matching_order(gparams) - assert m == [1] - - def test_matching_order(self): - labels = [ - "blue", - "blue", - "red", - "red", - "red", - "red", - "green", - "green", - "green", - "yellow", - "purple", - "purple", - "blue", - "blue", - ] - G1 = nx.Graph( - [ - (0, 1), - (0, 2), - (1, 2), - (2, 5), - (2, 4), - (1, 3), - (1, 4), - (3, 6), - (4, 6), - (6, 7), - (7, 8), - (9, 10), - (9, 11), - (11, 12), - (11, 13), - (12, 13), - (10, 13), - ] - ) - G2 = G1.copy() - nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels))), "label") - nx.set_node_attributes( - G2, - dict(zip(G2, it.cycle(labels))), - "label", - ) - l1, l2 = ( - nx.get_node_attributes(G1, "label"), - nx.get_node_attributes(G2, "label"), - ) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - expected = [9, 11, 10, 13, 12, 1, 2, 4, 0, 3, 6, 5, 7, 8] - assert _matching_order(gparams) == expected - - def test_matching_order_all_branches(self): - G1 = nx.Graph( - [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 4), (3, 4)] - ) - G1.add_node(5) - G2 = G1.copy() - - G1.nodes[0]["label"] = "black" - G1.nodes[1]["label"] = "blue" - G1.nodes[2]["label"] = "blue" - G1.nodes[3]["label"] = "red" - G1.nodes[4]["label"] = "red" - G1.nodes[5]["label"] = "blue" - - G2.nodes[0]["label"] = "black" - G2.nodes[1]["label"] = "blue" - G2.nodes[2]["label"] = "blue" - G2.nodes[3]["label"] = "red" - G2.nodes[4]["label"] = "red" - G2.nodes[5]["label"] = "blue" - - l1, l2 = ( - nx.get_node_attributes(G1, "label"), - nx.get_node_attributes(G2, "label"), - ) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - expected = [0, 4, 1, 3, 2, 5] - assert _matching_order(gparams) == expected - - -class TestGraphCandidateSelection: - G1_edges = [ - (1, 2), - (1, 4), - (1, 5), - (2, 3), - (2, 4), - (3, 4), - (4, 5), - (1, 6), - (6, 7), - (6, 8), - (8, 9), - (7, 9), - ] - mapped = { - 0: "x", - 1: "a", - 2: "b", - 3: "c", - 4: "d", - 5: "e", - 6: "f", - 7: "g", - 8: "h", - 9: "i", - } - - def test_no_covered_neighbors_no_labels(self): - G1 = nx.Graph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = dict(G1.degree) - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1 = {7, 8, 2, 4, 5} - T1_tilde = {0, 3, 6} - T2 = {"g", "h", "b", "d", "e"} - T2_tilde = {"x", "c", "f"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 3 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 0 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - m.pop(9) - m_rev.pop(self.mapped[9]) - - T1 = {2, 4, 5, 6} - T1_tilde = {0, 3, 7, 8, 9} - T2 = {"g", "h", "b", "d", "e", "f"} - T2_tilde = {"x", "c", "g", "h", "i"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 7 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == { - self.mapped[u], - self.mapped[8], - self.mapped[3], - self.mapped[9], - } - - def test_no_covered_neighbors_with_labels(self): - G1 = nx.Graph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = dict(G1.degree) - nx.set_node_attributes( - G1, - dict(zip(G1, it.cycle(labels_many))), - "label", - ) - nx.set_node_attributes( - G2, - dict( - zip( - [self.mapped[n] for n in G1], - it.cycle(labels_many), - ) - ), - "label", - ) - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1 = {7, 8, 2, 4, 5, 6} - T1_tilde = {0, 3} - T2 = {"g", "h", "b", "d", "e", "f"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 3 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 0 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - # Change label of disconnected node - G1.nodes[u]["label"] = "blue" - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - # No candidate - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == set() - - m.pop(9) - m_rev.pop(self.mapped[9]) - - T1 = {2, 4, 5, 6} - T1_tilde = {0, 3, 7, 8, 9} - T2 = {"b", "d", "e", "f"} - T2_tilde = {"x", "c", "g", "h", "i"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 7 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - G1.nodes[8]["label"] = G1.nodes[7]["label"] - G2.nodes[self.mapped[8]]["label"] = G1.nodes[7]["label"] - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[8]} - - def test_covered_neighbors_no_labels(self): - G1 = nx.Graph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = dict(G1.degree) - l1 = dict(G1.nodes(data=None, default=-1)) - l2 = dict(G2.nodes(data=None, default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1 = {7, 8, 2, 4, 5, 6} - T1_tilde = {0, 3} - T2 = {"g", "h", "b", "d", "e", "f"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 5 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 6 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[2]} - - def test_covered_neighbors_with_labels(self): - G1 = nx.Graph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = dict(G1.degree) - nx.set_node_attributes( - G1, - dict(zip(G1, it.cycle(labels_many))), - "label", - ) - nx.set_node_attributes( - G2, - dict( - zip( - [self.mapped[n] for n in G1], - it.cycle(labels_many), - ) - ), - "label", - ) - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1 = {7, 8, 2, 4, 5, 6} - T1_tilde = {0, 3} - T2 = {"g", "h", "b", "d", "e", "f"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - u = 5 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 6 - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - # Assign to 2, the same label as 6 - G1.nodes[2]["label"] = G1.nodes[u]["label"] - G2.nodes[self.mapped[2]]["label"] = G1.nodes[u]["label"] - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups(dict(G2.degree())), - ) - - candidates = _find_candidates(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[2]} - - -class TestDiGraphCandidateSelection: - G1_edges = [ - (1, 2), - (1, 4), - (5, 1), - (2, 3), - (4, 2), - (3, 4), - (4, 5), - (1, 6), - (6, 7), - (6, 8), - (8, 9), - (7, 9), - ] - mapped = { - 0: "x", - 1: "a", - 2: "b", - 3: "c", - 4: "d", - 5: "e", - 6: "f", - 7: "g", - 8: "h", - 9: "i", - } - - def test_no_covered_neighbors_no_labels(self): - G1 = nx.DiGraph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree) - } - - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1_out = {2, 4, 6} - T1_in = {5, 7, 8} - T1_tilde = {0, 3} - T2_out = {"b", "d", "f"} - T2_in = {"e", "g", "h"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 3 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 0 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - m.pop(9) - m_rev.pop(self.mapped[9]) - - T1_out = {2, 4, 6} - T1_in = {5} - T1_tilde = {0, 3, 7, 8, 9} - T2_out = {"b", "d", "f"} - T2_in = {"e"} - T2_tilde = {"x", "c", "g", "h", "i"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 7 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[8], self.mapped[3]} - - def test_no_covered_neighbors_with_labels(self): - G1 = nx.DiGraph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree) - } - nx.set_node_attributes( - G1, - dict(zip(G1, it.cycle(labels_many))), - "label", - ) - nx.set_node_attributes( - G2, - dict( - zip( - [self.mapped[n] for n in G1], - it.cycle(labels_many), - ) - ), - "label", - ) - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1_out = {2, 4, 6} - T1_in = {5, 7, 8} - T1_tilde = {0, 3} - T2_out = {"b", "d", "f"} - T2_in = {"e", "g", "h"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 3 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 0 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - # Change label of disconnected node - G1.nodes[u]["label"] = "blue" - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - # No candidate - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == set() - - m.pop(9) - m_rev.pop(self.mapped[9]) - - T1_out = {2, 4, 6} - T1_in = {5} - T1_tilde = {0, 3, 7, 8, 9} - T2_out = {"b", "d", "f"} - T2_in = {"e"} - T2_tilde = {"x", "c", "g", "h", "i"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 7 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - G1.nodes[8]["label"] = G1.nodes[7]["label"] - G2.nodes[self.mapped[8]]["label"] = G1.nodes[7]["label"] - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[8]} - - def test_covered_neighbors_no_labels(self): - G1 = nx.DiGraph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree) - } - - l1 = dict(G1.nodes(data=None, default=-1)) - l2 = dict(G2.nodes(data=None, default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1_out = {2, 4, 6} - T1_in = {5, 7, 8} - T1_tilde = {0, 3} - T2_out = {"b", "d", "f"} - T2_in = {"e", "g", "h"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 5 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 6 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - # Change the direction of an edge to make the degree orientation same as first candidate of u. - G1.remove_edge(4, 2) - G1.add_edge(2, 4) - G2.remove_edge("d", "b") - G2.add_edge("b", "d") - - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[2]} - - def test_covered_neighbors_with_labels(self): - G1 = nx.DiGraph() - G1.add_edges_from(self.G1_edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, self.mapped) - - G1.remove_edge(4, 2) - G1.add_edge(2, 4) - G2.remove_edge("d", "b") - G2.add_edge("b", "d") - - G1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree) - } - - nx.set_node_attributes( - G1, - dict(zip(G1, it.cycle(labels_many))), - "label", - ) - nx.set_node_attributes( - G2, - dict( - zip( - [self.mapped[n] for n in G1], - it.cycle(labels_many), - ) - ), - "label", - ) - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - m = {9: self.mapped[9], 1: self.mapped[1]} - m_rev = {self.mapped[9]: 9, self.mapped[1]: 1} - - T1_out = {2, 4, 6} - T1_in = {5, 7, 8} - T1_tilde = {0, 3} - T2_out = {"b", "d", "f"} - T2_in = {"e", "g", "h"} - T2_tilde = {"x", "c"} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 5 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - u = 6 - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - # Assign to 2, the same label as 6 - G1.nodes[2]["label"] = G1.nodes[u]["label"] - G2.nodes[self.mapped[2]]["label"] = G1.nodes[u]["label"] - l1 = dict(G1.nodes(data="label", default=-1)) - l2 = dict(G2.nodes(data="label", default=-1)) - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u], self.mapped[2]} - - # Change the direction of an edge to make the degree orientation same as first candidate of u. - G1.remove_edge(2, 4) - G1.add_edge(4, 2) - G2.remove_edge("b", "d") - G2.add_edge("d", "b") - - gparams = _GraphParameters( - G1, - G2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - G2.in_degree(), G2.out_degree() - ) - } - ), - ) - - candidates = _find_candidates_Di(u, gparams, sparams, G1_degree) - assert candidates == {self.mapped[u]} - - def test_same_in_out_degrees_no_candidate(self): - g1 = nx.DiGraph([(4, 1), (4, 2), (3, 4), (5, 4), (6, 4)]) - g2 = nx.DiGraph([(1, 4), (2, 4), (3, 4), (4, 5), (4, 6)]) - - l1 = dict(g1.nodes(data=None, default=-1)) - l2 = dict(g2.nodes(data=None, default=-1)) - gparams = _GraphParameters( - g1, - g2, - l1, - l2, - nx.utils.groups(l1), - nx.utils.groups(l2), - nx.utils.groups( - { - node: (in_degree, out_degree) - for (node, in_degree), (_, out_degree) in zip( - g2.in_degree(), g2.out_degree() - ) - } - ), - ) - - g1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(g1.in_degree, g1.out_degree) - } - - m = {1: 1, 2: 2, 3: 3} - m_rev = m.copy() - - T1_out = {4} - T1_in = {4} - T1_tilde = {5, 6} - T2_out = {4} - T2_in = {4} - T2_tilde = {5, 6} - - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - u = 4 - # despite the same in and out degree, there's no candidate for u=4 - candidates = _find_candidates_Di(u, gparams, sparams, g1_degree) - assert candidates == set() - # Notice how the regular candidate selection method returns wrong result. - assert _find_candidates(u, gparams, sparams, g1_degree) == {4} - - -class TestGraphISOFeasibility: - def test_const_covered_neighbors(self): - G1 = nx.Graph([(0, 1), (1, 2), (3, 0), (3, 2)]) - G2 = nx.Graph([("a", "b"), ("b", "c"), ("k", "a"), ("k", "c")]) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_no_covered_neighbors(self): - G1 = nx.Graph([(0, 1), (1, 2), (3, 4), (3, 5)]) - G2 = nx.Graph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "z")]) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_mixed_covered_uncovered_neighbors(self): - G1 = nx.Graph([(0, 1), (1, 2), (3, 0), (3, 2), (3, 4), (3, 5)]) - G2 = nx.Graph( - [("a", "b"), ("b", "c"), ("k", "a"), ("k", "c"), ("k", "w"), ("k", "z")] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_fail_cases(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (4, 1), - (5, 3), - ] - ) - G2 = nx.Graph( - [ - ("a", "b"), - ("b", "c"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("k", "f"), - ("k", "g"), - ("e", "b"), - ("f", "d"), - ] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 10, "k" - assert _consistent_PT(u, v, gparams, sparams) - - # Delete one uncovered neighbor of u. Notice how it still passes the test. - # Two reasons for this: - # 1. If u, v had different degrees from the beginning, they wouldn't - # be selected as candidates in the first place. - # 2. Even if they are selected, consistency is basically 1-look-ahead, - # meaning that we take into consideration the relation of the - # candidates with their mapped neighbors. The node we deleted is - # not a covered neighbor. - # Such nodes will be checked by the cut_PT function, which is - # basically the 2-look-ahead, checking the relation of the - # candidates with T1, T2 (in which belongs the node we just deleted). - G1.remove_node(6) - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of u in G1 - G1.add_edge(u, 2) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.add_edge(v, "c") - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of v in G2 - G2.add_edge(v, "x") - G1.add_node(7) - sparams.mapping.update({7: "x"}) - sparams.reverse_mapping.update({"x": 7}) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compendate in G1 - G1.add_edge(u, 7) - assert _consistent_PT(u, v, gparams, sparams) - - @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph)) - def test_cut_inconsistent_labels(self, graph_type): - G1 = graph_type( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (4, 1), - (5, 3), - ] - ) - G2 = graph_type( - [ - ("a", "b"), - ("b", "c"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("k", "f"), - ("k", "g"), - ("e", "b"), - ("f", "d"), - ] - ) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - l1.update({6: "green"}) # Change the label of one neighbor of u - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - - u, v = 10, "k" - assert _cut_PT(u, v, gparams, sparams) - - def test_cut_consistent_labels(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (4, 1), - (5, 3), - ] - ) - G2 = nx.Graph( - [ - ("a", "b"), - ("b", "c"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("k", "f"), - ("k", "g"), - ("e", "b"), - ("f", "d"), - ] - ) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5}, - None, - {6}, - None, - {"e", "f"}, - None, - {"g"}, - None, - ) - - u, v = 10, "k" - assert not _cut_PT(u, v, gparams, sparams) - - def test_cut_same_labels(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (4, 1), - (5, 3), - ] - ) - mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"} - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5}, - None, - {6}, - None, - {"e", "f"}, - None, - {"g"}, - None, - ) - - u, v = 10, "k" - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G1[u] and T1, so it's not the same as the one between G2[v] and T2 - G1.remove_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.remove_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G2[v] and T2_tilde, so it's not the same as the one between G1[u] and T1_tilde - G2.remove_edge(v, mapped[6]) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G1 - G1.remove_edge(u, 6) - assert not _cut_PT(u, v, gparams, sparams) - - # Add disconnected nodes, which will form the new Ti_out - G1.add_nodes_from([6, 7, 8]) - G2.add_nodes_from(["g", "y", "z"]) - sparams.T1_tilde.update({6, 7, 8}) - sparams.T2_tilde.update({"g", "y", "z"}) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - - assert not _cut_PT(u, v, gparams, sparams) - - # Add some new nodes to the mapping - sparams.mapping.update({6: "g", 7: "y"}) - sparams.reverse_mapping.update({"g": 6, "y": 7}) - - # Add more nodes to T1, T2. - G1.add_edges_from([(6, 20), (7, 20), (6, 21)]) - G2.add_edges_from([("g", "i"), ("g", "j"), ("y", "j")]) - - sparams.mapping.update({20: "j", 21: "i"}) - sparams.reverse_mapping.update({"j": 20, "i": 21}) - sparams.T1.update({20, 21}) - sparams.T2.update({"i", "j"}) - sparams.T1_tilde.difference_update({6, 7}) - sparams.T2_tilde.difference_update({"g", "y"}) - - assert not _cut_PT(u, v, gparams, sparams) - - # Add nodes from the new T1 and T2, as neighbors of u and v respectively - G1.add_edges_from([(u, 20), (u, 21)]) - G2.add_edges_from([(v, "i"), (v, "j")]) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - - assert not _cut_PT(u, v, gparams, sparams) - - # Change the edges, maintaining the G1[u]-T1 intersection - G1.remove_edge(u, 20) - G1.add_edge(u, 4) - assert not _cut_PT(u, v, gparams, sparams) - - # Connect u to 8 which is still in T1_tilde - G1.add_edge(u, 8) - assert _cut_PT(u, v, gparams, sparams) - - # Same for v and z, so that inters(G1[u], T1out) == inters(G2[v], T2out) - G2.add_edge(v, "z") - assert not _cut_PT(u, v, gparams, sparams) - - def test_cut_different_labels(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 15), - (20, 12), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 3), - (20, 5), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - - l1 = {n: "none" for n in G1.nodes()} - l2 = {} - - l1.update( - { - 9: "blue", - 15: "blue", - 12: "blue", - 11: "green", - 3: "green", - 8: "red", - 0: "red", - 5: "yellow", - } - ) - l2.update({mapped[n]: l for n, l in l1.items()}) - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change the orientation of the labels on neighbors of u compared to neighbors of v. Leave the structure intact - l1.update({9: "red"}) - assert _cut_PT(u, v, gparams, sparams) - - # compensate in G2 - l2.update({mapped[9]: "red"}) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G1[u] and T1 - G1.add_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G2[v] and T2 - G2.add_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G2[v] and T2_tilde - G2.remove_edge(v, mapped[8]) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G1[u] and T1_tilde - G1.remove_edge(u, 8) - assert not _cut_PT(u, v, gparams, sparams) - - # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes - G1.add_edge(8, 3) - G2.add_edge(mapped[8], mapped[3]) - sparams.T1.add(8) - sparams.T2.add(mapped[8]) - sparams.T1_tilde.remove(8) - sparams.T2_tilde.remove(mapped[8]) - - assert not _cut_PT(u, v, gparams, sparams) - - # Remove neighbor of u from T1 - G1.remove_node(5) - l1.pop(5) - sparams.T1.remove(5) - assert _cut_PT(u, v, gparams, sparams) - - # Same in G2 - G2.remove_node(mapped[5]) - l2.pop(mapped[5]) - sparams.T2.remove(mapped[5]) - assert not _cut_PT(u, v, gparams, sparams) - - def test_feasibility_same_labels(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 15), - (20, 12), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 2), - (20, 5), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {mapped[n]: "blue" for n in G1.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change structure in G2 such that, ONLY consistency is harmed - G2.remove_edge(mapped[20], mapped[2]) - G2.add_edge(mapped[20], mapped[3]) - - # Consistency check fails, while the cutting rules are satisfied! - assert not _cut_PT(u, v, gparams, sparams) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 and make it consistent - G1.remove_edge(20, 2) - G1.add_edge(20, 3) - assert not _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - # ONLY fail the cutting check - G2.add_edge(v, mapped[10]) - assert _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - def test_feasibility_different_labels(self): - G1 = nx.Graph( - [ - (0, 1), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 15), - (20, 12), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 2), - (20, 5), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - - l1 = {n: "none" for n in G1.nodes()} - l2 = {} - - l1.update( - { - 9: "blue", - 15: "blue", - 12: "blue", - 11: "green", - 2: "green", - 8: "red", - 0: "red", - 5: "yellow", - } - ) - l2.update({mapped[n]: l for n, l in l1.items()}) - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change structure in G2 such that, ONLY consistency is harmed - G2.remove_edge(mapped[20], mapped[2]) - G2.add_edge(mapped[20], mapped[3]) - l2.update({mapped[3]: "green"}) - - # Consistency check fails, while the cutting rules are satisfied! - assert not _cut_PT(u, v, gparams, sparams) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 and make it consistent - G1.remove_edge(20, 2) - G1.add_edge(20, 3) - l1.update({3: "green"}) - assert not _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - # ONLY fail the cutting check - l1.update({5: "red"}) - assert _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - -class TestMultiGraphISOFeasibility: - def test_const_covered_neighbors(self): - G1 = nx.MultiGraph( - [(0, 1), (0, 1), (1, 2), (3, 0), (3, 0), (3, 0), (3, 2), (3, 2)] - ) - G2 = nx.MultiGraph( - [ - ("a", "b"), - ("a", "b"), - ("b", "c"), - ("k", "a"), - ("k", "a"), - ("k", "a"), - ("k", "c"), - ("k", "c"), - ] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_no_covered_neighbors(self): - G1 = nx.MultiGraph([(0, 1), (0, 1), (1, 2), (3, 4), (3, 4), (3, 5)]) - G2 = nx.MultiGraph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "w"), ("k", "z")]) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_mixed_covered_uncovered_neighbors(self): - G1 = nx.MultiGraph( - [(0, 1), (1, 2), (3, 0), (3, 0), (3, 0), (3, 2), (3, 2), (3, 4), (3, 5)] - ) - G2 = nx.MultiGraph( - [ - ("a", "b"), - ("b", "c"), - ("k", "a"), - ("k", "a"), - ("k", "a"), - ("k", "c"), - ("k", "c"), - ("k", "w"), - ("k", "z"), - ] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_fail_cases(self): - G1 = nx.MultiGraph( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 0), - (10, 0), - (10, 3), - (10, 3), - (10, 4), - (10, 5), - (10, 6), - (10, 6), - (4, 1), - (5, 3), - ] - ) - mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"} - G2 = nx.relabel_nodes(G1, mapped) - - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 10, "k" - assert _consistent_PT(u, v, gparams, sparams) - - # Delete one uncovered neighbor of u. Notice how it still passes the test. Two reasons for this: - # 1. If u, v had different degrees from the beginning, they wouldn't be selected as candidates in the first - # place. - # 2. Even if they are selected, consistency is basically 1-look-ahead, meaning that we take into consideration - # the relation of the candidates with their mapped neighbors. The node we deleted is not a covered neighbor. - # Such nodes will be checked by the cut_PT function, which is basically the 2-look-ahead, checking the - # relation of the candidates with T1, T2 (in which belongs the node we just deleted). - G1.remove_node(6) - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of u in G1 - G1.add_edge(u, 2) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.add_edge(v, "c") - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of v in G2 - G2.add_edge(v, "x") - G1.add_node(7) - sparams.mapping.update({7: "x"}) - sparams.reverse_mapping.update({"x": 7}) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compendate in G1 - G1.add_edge(u, 7) - assert _consistent_PT(u, v, gparams, sparams) - - # Delete an edge between u and a covered neighbor - G1.remove_edges_from([(u, 0), (u, 0)]) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.remove_edges_from([(v, mapped[0]), (v, mapped[0])]) - assert _consistent_PT(u, v, gparams, sparams) - - # Remove an edge between v and a covered neighbor - G2.remove_edge(v, mapped[3]) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 - G1.remove_edge(u, 3) - assert _consistent_PT(u, v, gparams, sparams) - - def test_cut_same_labels(self): - G1 = nx.MultiGraph( - [ - (0, 1), - (1, 2), - (10, 0), - (10, 0), - (10, 0), - (10, 3), - (10, 3), - (10, 4), - (10, 4), - (10, 5), - (10, 5), - (10, 5), - (10, 5), - (10, 6), - (10, 6), - (4, 1), - (5, 3), - ] - ) - mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"} - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5}, - None, - {6}, - None, - {"e", "f"}, - None, - {"g"}, - None, - ) - - u, v = 10, "k" - assert not _cut_PT(u, v, gparams, sparams) - - # Remove one of the multiple edges between u and a neighbor - G1.remove_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G2 - G1.remove_edge(u, 4) - G2.remove_edges_from([(v, mapped[4]), (v, mapped[4])]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G2[v] and T2_tilde, so it's not the same as the one between G1[u] and T1_tilde - G2.remove_edge(v, mapped[6]) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G1 - G1.remove_edge(u, 6) - assert not _cut_PT(u, v, gparams, sparams) - - # Add more edges between u and neighbor which belongs in T1_tilde - G1.add_edges_from([(u, 5), (u, 5), (u, 5)]) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.add_edges_from([(v, mapped[5]), (v, mapped[5]), (v, mapped[5])]) - assert not _cut_PT(u, v, gparams, sparams) - - # Add disconnected nodes, which will form the new Ti_out - G1.add_nodes_from([6, 7, 8]) - G2.add_nodes_from(["g", "y", "z"]) - G1.add_edges_from([(u, 6), (u, 6), (u, 6), (u, 8)]) - G2.add_edges_from([(v, "g"), (v, "g"), (v, "g"), (v, "z")]) - - sparams.T1_tilde.update({6, 7, 8}) - sparams.T2_tilde.update({"g", "y", "z"}) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - - assert not _cut_PT(u, v, gparams, sparams) - - # Add some new nodes to the mapping - sparams.mapping.update({6: "g", 7: "y"}) - sparams.reverse_mapping.update({"g": 6, "y": 7}) - - # Add more nodes to T1, T2. - G1.add_edges_from([(6, 20), (7, 20), (6, 21)]) - G2.add_edges_from([("g", "i"), ("g", "j"), ("y", "j")]) - - sparams.T1.update({20, 21}) - sparams.T2.update({"i", "j"}) - sparams.T1_tilde.difference_update({6, 7}) - sparams.T2_tilde.difference_update({"g", "y"}) - - assert not _cut_PT(u, v, gparams, sparams) - - # Remove some edges - G2.remove_edge(v, "g") - assert _cut_PT(u, v, gparams, sparams) - - G1.remove_edge(u, 6) - G1.add_edge(u, 8) - G2.add_edge(v, "z") - assert not _cut_PT(u, v, gparams, sparams) - - # Add nodes from the new T1 and T2, as neighbors of u and v respectively - G1.add_edges_from([(u, 20), (u, 20), (u, 20), (u, 21)]) - G2.add_edges_from([(v, "i"), (v, "i"), (v, "i"), (v, "j")]) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - - assert not _cut_PT(u, v, gparams, sparams) - - # Change the edges - G1.remove_edge(u, 20) - G1.add_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - G2.remove_edge(v, "i") - G2.add_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - def test_cut_different_labels(self): - G1 = nx.MultiGraph( - [ - (0, 1), - (0, 1), - (1, 2), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 9), - (20, 9), - (20, 15), - (20, 15), - (20, 12), - (20, 11), - (20, 11), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 8), - (20, 3), - (20, 3), - (20, 5), - (20, 5), - (20, 5), - (20, 0), - (20, 0), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - - l1 = {n: "none" for n in G1.nodes()} - l2 = {} - - l1.update( - { - 9: "blue", - 15: "blue", - 12: "blue", - 11: "green", - 3: "green", - 8: "red", - 0: "red", - 5: "yellow", - } - ) - l2.update({mapped[n]: l for n, l in l1.items()}) - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change the orientation of the labels on neighbors of u compared to neighbors of v. Leave the structure intact - l1.update({9: "red"}) - assert _cut_PT(u, v, gparams, sparams) - - # compensate in G2 - l2.update({mapped[9]: "red"}) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G1[u] and T1 - G1.add_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G2[v] and T2 - G2.add_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - # Delete one from the multiple edges - G2.remove_edge(v, mapped[8]) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G1[u] and T1_tilde - G1.remove_edge(u, 8) - assert not _cut_PT(u, v, gparams, sparams) - - # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes - G1.add_edges_from([(8, 3), (8, 3), (8, u)]) - G2.add_edges_from([(mapped[8], mapped[3]), (mapped[8], mapped[3])]) - sparams.T1.add(8) - sparams.T2.add(mapped[8]) - sparams.T1_tilde.remove(8) - sparams.T2_tilde.remove(mapped[8]) - - assert _cut_PT(u, v, gparams, sparams) - - # Fix uneven edges - G1.remove_edge(8, u) - assert not _cut_PT(u, v, gparams, sparams) - - # Remove neighbor of u from T1 - G1.remove_node(5) - l1.pop(5) - sparams.T1.remove(5) - assert _cut_PT(u, v, gparams, sparams) - - # Same in G2 - G2.remove_node(mapped[5]) - l2.pop(mapped[5]) - sparams.T2.remove(mapped[5]) - assert not _cut_PT(u, v, gparams, sparams) - - def test_feasibility_same_labels(self): - G1 = nx.MultiGraph( - [ - (0, 1), - (0, 1), - (1, 2), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 9), - (20, 9), - (20, 15), - (20, 15), - (20, 12), - (20, 11), - (20, 11), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 8), - (20, 3), - (20, 3), - (20, 5), - (20, 5), - (20, 5), - (20, 0), - (20, 0), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {mapped[n]: "blue" for n in G1.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change structure in G2 such that, ONLY consistency is harmed - G2.remove_edges_from([(mapped[20], mapped[3]), (mapped[20], mapped[3])]) - G2.add_edges_from([(mapped[20], mapped[2]), (mapped[20], mapped[2])]) - - # Consistency check fails, while the cutting rules are satisfied! - assert not _cut_PT(u, v, gparams, sparams) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 and make it consistent - G1.remove_edges_from([(20, 3), (20, 3)]) - G1.add_edges_from([(20, 2), (20, 2)]) - assert not _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - # ONLY fail the cutting check - G2.add_edges_from([(v, mapped[10])] * 5) - assert _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - # Pass all tests - G1.add_edges_from([(u, 10)] * 5) - assert not _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - def test_feasibility_different_labels(self): - G1 = nx.MultiGraph( - [ - (0, 1), - (0, 1), - (1, 2), - (1, 2), - (1, 14), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (4, 10), - (4, 9), - (6, 10), - (20, 9), - (20, 9), - (20, 9), - (20, 15), - (20, 15), - (20, 12), - (20, 11), - (20, 11), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 8), - (20, 2), - (20, 2), - (20, 5), - (20, 5), - (20, 5), - (20, 0), - (20, 0), - (20, 0), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "none" for n in G1.nodes()} - l2 = {} - - l1.update( - { - 9: "blue", - 15: "blue", - 12: "blue", - 11: "green", - 2: "green", - 8: "red", - 0: "red", - 5: "yellow", - } - ) - l2.update({mapped[n]: l for n, l in l1.items()}) - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 14}, - None, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "h", "o"}, - None, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change structure in G2 such that, ONLY consistency is harmed - G2.remove_edges_from([(mapped[20], mapped[2]), (mapped[20], mapped[2])]) - G2.add_edges_from([(mapped[20], mapped[3]), (mapped[20], mapped[3])]) - l2.update({mapped[3]: "green"}) - - # Consistency check fails, while the cutting rules are satisfied! - assert not _cut_PT(u, v, gparams, sparams) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 and make it consistent - G1.remove_edges_from([(20, 2), (20, 2)]) - G1.add_edges_from([(20, 3), (20, 3)]) - l1.update({3: "green"}) - assert not _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - # ONLY fail the cutting check - l1.update({5: "red"}) - assert _cut_PT(u, v, gparams, sparams) - assert _consistent_PT(u, v, gparams, sparams) - - -class TestDiGraphISOFeasibility: - def test_const_covered_neighbors(self): - G1 = nx.DiGraph([(0, 1), (1, 2), (0, 3), (2, 3)]) - G2 = nx.DiGraph([("a", "b"), ("b", "c"), ("a", "k"), ("c", "k")]) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_no_covered_neighbors(self): - G1 = nx.DiGraph([(0, 1), (1, 2), (3, 4), (3, 5)]) - G2 = nx.DiGraph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "z")]) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_mixed_covered_uncovered_neighbors(self): - G1 = nx.DiGraph([(0, 1), (1, 2), (3, 0), (3, 2), (3, 4), (3, 5)]) - G2 = nx.DiGraph( - [("a", "b"), ("b", "c"), ("k", "a"), ("k", "c"), ("k", "w"), ("k", "z")] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 3, "k" - assert _consistent_PT(u, v, gparams, sparams) - - def test_const_fail_cases(self): - G1 = nx.DiGraph( - [ - (0, 1), - (2, 1), - (10, 0), - (10, 3), - (10, 4), - (5, 10), - (10, 6), - (1, 4), - (5, 3), - ] - ) - G2 = nx.DiGraph( - [ - ("a", "b"), - ("c", "b"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("f", "k"), - ("k", "g"), - ("b", "e"), - ("f", "d"), - ] - ) - gparams = _GraphParameters(G1, G2, None, None, None, None, None) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - u, v = 10, "k" - assert _consistent_PT(u, v, gparams, sparams) - - # Delete one uncovered neighbor of u. Notice how it still passes the - # test. Two reasons for this: - # 1. If u, v had different degrees from the beginning, they wouldn't - # be selected as candidates in the first place. - # 2. Even if they are selected, consistency is basically - # 1-look-ahead, meaning that we take into consideration the - # relation of the candidates with their mapped neighbors. - # The node we deleted is not a covered neighbor. - # Such nodes will be checked by the cut_PT function, which is - # basically the 2-look-ahead, checking the relation of the - # candidates with T1, T2 (in which belongs the node we just deleted). - G1.remove_node(6) - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of u in G1 - G1.add_edge(u, 2) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.add_edge(v, "c") - assert _consistent_PT(u, v, gparams, sparams) - - # Add one more covered neighbor of v in G2 - G2.add_edge(v, "x") - G1.add_node(7) - sparams.mapping.update({7: "x"}) - sparams.reverse_mapping.update({"x": 7}) - assert not _consistent_PT(u, v, gparams, sparams) - - # Compensate in G1 - G1.add_edge(u, 7) - assert _consistent_PT(u, v, gparams, sparams) - - def test_cut_inconsistent_labels(self): - G1 = nx.DiGraph( - [ - (0, 1), - (2, 1), - (10, 0), - (10, 3), - (10, 4), - (5, 10), - (10, 6), - (1, 4), - (5, 3), - ] - ) - G2 = nx.DiGraph( - [ - ("a", "b"), - ("c", "b"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("f", "k"), - ("k", "g"), - ("b", "e"), - ("f", "d"), - ] - ) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - l1.update({5: "green"}) # Change the label of one neighbor of u - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - None, - None, - None, - None, - None, - None, - None, - None, - ) - - u, v = 10, "k" - assert _cut_PT(u, v, gparams, sparams) - - def test_cut_consistent_labels(self): - G1 = nx.DiGraph( - [ - (0, 1), - (2, 1), - (10, 0), - (10, 3), - (10, 4), - (5, 10), - (10, 6), - (1, 4), - (5, 3), - ] - ) - G2 = nx.DiGraph( - [ - ("a", "b"), - ("c", "b"), - ("k", "a"), - ("k", "d"), - ("k", "e"), - ("f", "k"), - ("k", "g"), - ("b", "e"), - ("f", "d"), - ] - ) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4}, - {5, 10}, - {6}, - None, - {"e"}, - {"f", "k"}, - {"g"}, - None, - ) - - u, v = 10, "k" - assert not _cut_PT(u, v, gparams, sparams) - - def test_cut_same_labels(self): - G1 = nx.DiGraph( - [ - (0, 1), - (2, 1), - (10, 0), - (10, 3), - (10, 4), - (5, 10), - (10, 6), - (1, 4), - (5, 3), - ] - ) - mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"} - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4}, - {5, 10}, - {6}, - None, - {"e"}, - {"f", "k"}, - {"g"}, - None, - ) - - u, v = 10, "k" - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G1[u] and T1_out, so it's not the same as the one between G2[v] and T2_out - G1.remove_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.remove_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G1[u] and T1_in, so it's not the same as the one between G2[v] and T2_in - G1.remove_edge(5, u) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G2 - G2.remove_edge(mapped[5], v) - assert not _cut_PT(u, v, gparams, sparams) - - # Change intersection between G2[v] and T2_tilde, so it's not the same as the one between G1[u] and T1_tilde - G2.remove_edge(v, mapped[6]) - assert _cut_PT(u, v, gparams, sparams) - - # Compensate in G1 - G1.remove_edge(u, 6) - assert not _cut_PT(u, v, gparams, sparams) - - # Add disconnected nodes, which will form the new Ti_tilde - G1.add_nodes_from([6, 7, 8]) - G2.add_nodes_from(["g", "y", "z"]) - sparams.T1_tilde.update({6, 7, 8}) - sparams.T2_tilde.update({"g", "y", "z"}) - - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - - assert not _cut_PT(u, v, gparams, sparams) - - def test_cut_different_labels(self): - G1 = nx.DiGraph( - [ - (0, 1), - (1, 2), - (14, 1), - (0, 4), - (1, 5), - (2, 6), - (3, 7), - (3, 6), - (10, 4), - (4, 9), - (6, 10), - (20, 9), - (20, 15), - (20, 12), - (20, 11), - (12, 13), - (11, 13), - (20, 8), - (20, 3), - (20, 5), - (0, 20), - ] - ) - mapped = { - 0: "a", - 1: "b", - 2: "c", - 3: "d", - 4: "e", - 5: "f", - 6: "g", - 7: "h", - 8: "i", - 9: "j", - 10: "k", - 11: "l", - 12: "m", - 13: "n", - 14: "o", - 15: "p", - 20: "x", - } - G2 = nx.relabel_nodes(G1, mapped) - - l1 = {n: "none" for n in G1.nodes()} - l2 = {} - - l1.update( - { - 9: "blue", - 15: "blue", - 12: "blue", - 11: "green", - 3: "green", - 8: "red", - 0: "red", - 5: "yellow", - } - ) - l2.update({mapped[n]: l for n, l in l1.items()}) - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c", 3: "d"}, - {"a": 0, "b": 1, "c": 2, "d": 3}, - {4, 5, 6, 7, 20}, - {14, 20}, - {9, 10, 15, 12, 11, 13, 8}, - None, - {"e", "f", "g", "x"}, - {"o", "x"}, - {"j", "k", "l", "m", "n", "i", "p"}, - None, - ) - - u, v = 20, "x" - assert not _cut_PT(u, v, gparams, sparams) - - # Change the orientation of the labels on neighbors of u compared to neighbors of v. Leave the structure intact - l1.update({9: "red"}) - assert _cut_PT(u, v, gparams, sparams) - - # compensate in G2 - l2.update({mapped[9]: "red"}) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G1[u] and T1_out - G1.add_edge(u, 4) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G2[v] and T2_out - G2.add_edge(v, mapped[4]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G1[u] and T1_in - G1.add_edge(u, 14) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G2[v] and T2_in - G2.add_edge(v, mapped[14]) - assert not _cut_PT(u, v, gparams, sparams) - - # Change the intersection of G2[v] and T2_tilde - G2.remove_edge(v, mapped[8]) - assert _cut_PT(u, v, gparams, sparams) - - # Same for G1[u] and T1_tilde - G1.remove_edge(u, 8) - assert not _cut_PT(u, v, gparams, sparams) - - # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes - G1.add_edge(8, 3) - G2.add_edge(mapped[8], mapped[3]) - sparams.T1.add(8) - sparams.T2.add(mapped[8]) - sparams.T1_tilde.remove(8) - sparams.T2_tilde.remove(mapped[8]) - - assert not _cut_PT(u, v, gparams, sparams) - - # Remove neighbor of u from T1 - G1.remove_node(5) - l1.pop(5) - sparams.T1.remove(5) - assert _cut_PT(u, v, gparams, sparams) - - # Same in G2 - G2.remove_node(mapped[5]) - l2.pop(mapped[5]) - sparams.T2.remove(mapped[5]) - assert not _cut_PT(u, v, gparams, sparams) - - def test_predecessor_T1_in_fail(self): - G1 = nx.DiGraph( - [(0, 1), (0, 3), (4, 0), (1, 5), (5, 2), (3, 6), (4, 6), (6, 5)] - ) - mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g"} - G2 = nx.relabel_nodes(G1, mapped) - l1 = {n: "blue" for n in G1.nodes()} - l2 = {n: "blue" for n in G2.nodes()} - - gparams = _GraphParameters( - G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None - ) - sparams = _StateParameters( - {0: "a", 1: "b", 2: "c"}, - {"a": 0, "b": 1, "c": 2}, - {3, 5}, - {4, 5}, - {6}, - None, - {"d", "f"}, - {"f"}, # mapped[4] is missing from T2_in - {"g"}, - None, - ) - - u, v = 6, "g" - assert _cut_PT(u, v, gparams, sparams) - - sparams.T2_in.add("e") - assert not _cut_PT(u, v, gparams, sparams) - - -class TestGraphTinoutUpdating: - edges = [ - (1, 3), - (2, 3), - (3, 4), - (4, 9), - (4, 5), - (3, 9), - (5, 8), - (5, 7), - (8, 7), - (6, 7), - ] - mapped = { - 0: "x", - 1: "a", - 2: "b", - 3: "c", - 4: "d", - 5: "e", - 6: "f", - 7: "g", - 8: "h", - 9: "i", - } - G1 = nx.Graph() - G1.add_edges_from(edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, mapping=mapped) - - def test_updating(self): - G2_degree = dict(self.G2.degree) - gparams, sparams = _initialize_parameters(self.G1, self.G2, G2_degree) - m, m_rev, T1, _, T1_tilde, _, T2, _, T2_tilde, _ = sparams - - # Add node to the mapping - m[4] = self.mapped[4] - m_rev[self.mapped[4]] = 4 - _update_Tinout(4, self.mapped[4], gparams, sparams) - - assert T1 == {3, 5, 9} - assert T2 == {"c", "i", "e"} - assert T1_tilde == {0, 1, 2, 6, 7, 8} - assert T2_tilde == {"x", "a", "b", "f", "g", "h"} - - # Add node to the mapping - m[5] = self.mapped[5] - m_rev.update({self.mapped[5]: 5}) - _update_Tinout(5, self.mapped[5], gparams, sparams) - - assert T1 == {3, 9, 8, 7} - assert T2 == {"c", "i", "h", "g"} - assert T1_tilde == {0, 1, 2, 6} - assert T2_tilde == {"x", "a", "b", "f"} - - # Add node to the mapping - m[6] = self.mapped[6] - m_rev.update({self.mapped[6]: 6}) - _update_Tinout(6, self.mapped[6], gparams, sparams) - - assert T1 == {3, 9, 8, 7} - assert T2 == {"c", "i", "h", "g"} - assert T1_tilde == {0, 1, 2} - assert T2_tilde == {"x", "a", "b"} - - # Add node to the mapping - m[3] = self.mapped[3] - m_rev.update({self.mapped[3]: 3}) - _update_Tinout(3, self.mapped[3], gparams, sparams) - - assert T1 == {1, 2, 9, 8, 7} - assert T2 == {"a", "b", "i", "h", "g"} - assert T1_tilde == {0} - assert T2_tilde == {"x"} - - # Add node to the mapping - m[0] = self.mapped[0] - m_rev.update({self.mapped[0]: 0}) - _update_Tinout(0, self.mapped[0], gparams, sparams) - - assert T1 == {1, 2, 9, 8, 7} - assert T2 == {"a", "b", "i", "h", "g"} - assert T1_tilde == set() - assert T2_tilde == set() - - def test_restoring(self): - m = {0: "x", 3: "c", 4: "d", 5: "e", 6: "f"} - m_rev = {"x": 0, "c": 3, "d": 4, "e": 5, "f": 6} - - T1 = {1, 2, 7, 9, 8} - T2 = {"a", "b", "g", "i", "h"} - T1_tilde = set() - T2_tilde = set() - - gparams = _GraphParameters(self.G1, self.G2, {}, {}, {}, {}, {}) - sparams = _StateParameters( - m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None - ) - - # Remove a node from the mapping - m.pop(0) - m_rev.pop("x") - _restore_Tinout(0, self.mapped[0], gparams, sparams) - - assert T1 == {1, 2, 7, 9, 8} - assert T2 == {"a", "b", "g", "i", "h"} - assert T1_tilde == {0} - assert T2_tilde == {"x"} - - # Remove a node from the mapping - m.pop(6) - m_rev.pop("f") - _restore_Tinout(6, self.mapped[6], gparams, sparams) - - assert T1 == {1, 2, 7, 9, 8} - assert T2 == {"a", "b", "g", "i", "h"} - assert T1_tilde == {0, 6} - assert T2_tilde == {"x", "f"} - - # Remove a node from the mapping - m.pop(3) - m_rev.pop("c") - _restore_Tinout(3, self.mapped[3], gparams, sparams) - - assert T1 == {7, 9, 8, 3} - assert T2 == {"g", "i", "h", "c"} - assert T1_tilde == {0, 6, 1, 2} - assert T2_tilde == {"x", "f", "a", "b"} - - # Remove a node from the mapping - m.pop(5) - m_rev.pop("e") - _restore_Tinout(5, self.mapped[5], gparams, sparams) - - assert T1 == {9, 3, 5} - assert T2 == {"i", "c", "e"} - assert T1_tilde == {0, 6, 1, 2, 7, 8} - assert T2_tilde == {"x", "f", "a", "b", "g", "h"} - - # Remove a node from the mapping - m.pop(4) - m_rev.pop("d") - _restore_Tinout(4, self.mapped[4], gparams, sparams) - - assert T1 == set() - assert T2 == set() - assert T1_tilde == set(self.G1.nodes()) - assert T2_tilde == set(self.G2.nodes()) - - -class TestDiGraphTinoutUpdating: - edges = [ - (1, 3), - (3, 2), - (3, 4), - (4, 9), - (4, 5), - (3, 9), - (5, 8), - (5, 7), - (8, 7), - (7, 6), - ] - mapped = { - 0: "x", - 1: "a", - 2: "b", - 3: "c", - 4: "d", - 5: "e", - 6: "f", - 7: "g", - 8: "h", - 9: "i", - } - G1 = nx.DiGraph(edges) - G1.add_node(0) - G2 = nx.relabel_nodes(G1, mapping=mapped) - - def test_updating(self): - G2_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip( - self.G2.in_degree, self.G2.out_degree - ) - } - gparams, sparams = _initialize_parameters(self.G1, self.G2, G2_degree) - m, m_rev, T1_out, T1_in, T1_tilde, _, T2_out, T2_in, T2_tilde, _ = sparams - - # Add node to the mapping - m[4] = self.mapped[4] - m_rev[self.mapped[4]] = 4 - _update_Tinout(4, self.mapped[4], gparams, sparams) - - assert T1_out == {5, 9} - assert T1_in == {3} - assert T2_out == {"i", "e"} - assert T2_in == {"c"} - assert T1_tilde == {0, 1, 2, 6, 7, 8} - assert T2_tilde == {"x", "a", "b", "f", "g", "h"} - - # Add node to the mapping - m[5] = self.mapped[5] - m_rev[self.mapped[5]] = 5 - _update_Tinout(5, self.mapped[5], gparams, sparams) - - assert T1_out == {9, 8, 7} - assert T1_in == {3} - assert T2_out == {"i", "g", "h"} - assert T2_in == {"c"} - assert T1_tilde == {0, 1, 2, 6} - assert T2_tilde == {"x", "a", "b", "f"} - - # Add node to the mapping - m[6] = self.mapped[6] - m_rev[self.mapped[6]] = 6 - _update_Tinout(6, self.mapped[6], gparams, sparams) - - assert T1_out == {9, 8, 7} - assert T1_in == {3, 7} - assert T2_out == {"i", "g", "h"} - assert T2_in == {"c", "g"} - assert T1_tilde == {0, 1, 2} - assert T2_tilde == {"x", "a", "b"} - - # Add node to the mapping - m[3] = self.mapped[3] - m_rev[self.mapped[3]] = 3 - _update_Tinout(3, self.mapped[3], gparams, sparams) - - assert T1_out == {9, 8, 7, 2} - assert T1_in == {7, 1} - assert T2_out == {"i", "g", "h", "b"} - assert T2_in == {"g", "a"} - assert T1_tilde == {0} - assert T2_tilde == {"x"} - - # Add node to the mapping - m[0] = self.mapped[0] - m_rev[self.mapped[0]] = 0 - _update_Tinout(0, self.mapped[0], gparams, sparams) - - assert T1_out == {9, 8, 7, 2} - assert T1_in == {7, 1} - assert T2_out == {"i", "g", "h", "b"} - assert T2_in == {"g", "a"} - assert T1_tilde == set() - assert T2_tilde == set() - - def test_restoring(self): - m = {0: "x", 3: "c", 4: "d", 5: "e", 6: "f"} - m_rev = {"x": 0, "c": 3, "d": 4, "e": 5, "f": 6} - - T1_out = {2, 7, 9, 8} - T1_in = {1, 7} - T2_out = {"b", "g", "i", "h"} - T2_in = {"a", "g"} - T1_tilde = set() - T2_tilde = set() - - gparams = _GraphParameters(self.G1, self.G2, {}, {}, {}, {}, {}) - sparams = _StateParameters( - m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None - ) - - # Remove a node from the mapping - m.pop(0) - m_rev.pop("x") - _restore_Tinout_Di(0, self.mapped[0], gparams, sparams) - - assert T1_out == {2, 7, 9, 8} - assert T1_in == {1, 7} - assert T2_out == {"b", "g", "i", "h"} - assert T2_in == {"a", "g"} - assert T1_tilde == {0} - assert T2_tilde == {"x"} - - # Remove a node from the mapping - m.pop(6) - m_rev.pop("f") - _restore_Tinout_Di(6, self.mapped[6], gparams, sparams) - - assert T1_out == {2, 9, 8, 7} - assert T1_in == {1} - assert T2_out == {"b", "i", "h", "g"} - assert T2_in == {"a"} - assert T1_tilde == {0, 6} - assert T2_tilde == {"x", "f"} - - # Remove a node from the mapping - m.pop(3) - m_rev.pop("c") - _restore_Tinout_Di(3, self.mapped[3], gparams, sparams) - - assert T1_out == {9, 8, 7} - assert T1_in == {3} - assert T2_out == {"i", "h", "g"} - assert T2_in == {"c"} - assert T1_tilde == {0, 6, 1, 2} - assert T2_tilde == {"x", "f", "a", "b"} - - # Remove a node from the mapping - m.pop(5) - m_rev.pop("e") - _restore_Tinout_Di(5, self.mapped[5], gparams, sparams) - - assert T1_out == {9, 5} - assert T1_in == {3} - assert T2_out == {"i", "e"} - assert T2_in == {"c"} - assert T1_tilde == {0, 6, 1, 2, 8, 7} - assert T2_tilde == {"x", "f", "a", "b", "h", "g"} - - # Remove a node from the mapping - m.pop(4) - m_rev.pop("d") - _restore_Tinout_Di(4, self.mapped[4], gparams, sparams) - - assert T1_out == set() - assert T1_in == set() - assert T2_out == set() - assert T2_in == set() - assert T1_tilde == set(self.G1.nodes()) - assert T2_tilde == set(self.G2.nodes()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py deleted file mode 100644 index b44f458..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -Tests for VF2 isomorphism algorithm for weighted graphs. -""" - -import math -from operator import eq - -import networkx as nx -import networkx.algorithms.isomorphism as iso - - -def test_simple(): - # 16 simple tests - w = "weight" - edges = [(0, 0, 1), (0, 0, 1.5), (0, 1, 2), (1, 0, 3)] - for g1 in [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]: - g1.add_weighted_edges_from(edges) - g2 = g1.subgraph(g1.nodes()) - if g1.is_multigraph(): - em = iso.numerical_multiedge_match("weight", 1) - else: - em = iso.numerical_edge_match("weight", 1) - assert nx.is_isomorphic(g1, g2, edge_match=em) - - for mod1, mod2 in [(False, True), (True, False), (True, True)]: - # mod1 tests a regular edge - # mod2 tests a selfloop - if g2.is_multigraph(): - if mod1: - data1 = {0: {"weight": 10}} - if mod2: - data2 = {0: {"weight": 1}, 1: {"weight": 2.5}} - else: - if mod1: - data1 = {"weight": 10} - if mod2: - data2 = {"weight": 2.5} - - g2 = g1.subgraph(g1.nodes()).copy() - if mod1: - if not g1.is_directed(): - g2._adj[1][0] = data1 - g2._adj[0][1] = data1 - else: - g2._succ[1][0] = data1 - g2._pred[0][1] = data1 - if mod2: - if not g1.is_directed(): - g2._adj[0][0] = data2 - else: - g2._succ[0][0] = data2 - g2._pred[0][0] = data2 - - assert not nx.is_isomorphic(g1, g2, edge_match=em) - - -def test_weightkey(): - g1 = nx.DiGraph() - g2 = nx.DiGraph() - - g1.add_edge("A", "B", weight=1) - g2.add_edge("C", "D", weight=0) - - assert nx.is_isomorphic(g1, g2) - em = iso.numerical_edge_match("nonexistent attribute", 1) - assert nx.is_isomorphic(g1, g2, edge_match=em) - em = iso.numerical_edge_match("weight", 1) - assert not nx.is_isomorphic(g1, g2, edge_match=em) - - g2 = nx.DiGraph() - g2.add_edge("C", "D") - assert nx.is_isomorphic(g1, g2, edge_match=em) - - -class TestNodeMatch_Graph: - def setup_method(self): - self.g1 = nx.Graph() - self.g2 = nx.Graph() - self.build() - - def build(self): - self.nm = iso.categorical_node_match("color", "") - self.em = iso.numerical_edge_match("weight", 1) - - self.g1.add_node("A", color="red") - self.g2.add_node("C", color="blue") - - self.g1.add_edge("A", "B", weight=1) - self.g2.add_edge("C", "D", weight=1) - - def test_noweight_nocolor(self): - assert nx.is_isomorphic(self.g1, self.g2) - - def test_color1(self): - assert not nx.is_isomorphic(self.g1, self.g2, node_match=self.nm) - - def test_color2(self): - self.g1.nodes["A"]["color"] = "blue" - assert nx.is_isomorphic(self.g1, self.g2, node_match=self.nm) - - def test_weight1(self): - assert nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) - - def test_weight2(self): - self.g1.add_edge("A", "B", weight=2) - assert not nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) - - def test_colorsandweights1(self): - iso = nx.is_isomorphic(self.g1, self.g2, node_match=self.nm, edge_match=self.em) - assert not iso - - def test_colorsandweights2(self): - self.g1.nodes["A"]["color"] = "blue" - iso = nx.is_isomorphic(self.g1, self.g2, node_match=self.nm, edge_match=self.em) - assert iso - - def test_colorsandweights3(self): - # make the weights disagree - self.g1.add_edge("A", "B", weight=2) - assert not nx.is_isomorphic( - self.g1, self.g2, node_match=self.nm, edge_match=self.em - ) - - -class TestEdgeMatch_MultiGraph: - def setup_method(self): - self.g1 = nx.MultiGraph() - self.g2 = nx.MultiGraph() - self.GM = iso.MultiGraphMatcher - self.build() - - def build(self): - g1 = self.g1 - g2 = self.g2 - - # We will assume integer weights only. - g1.add_edge("A", "B", color="green", weight=0, size=0.5) - g1.add_edge("A", "B", color="red", weight=1, size=0.35) - g1.add_edge("A", "B", color="red", weight=2, size=0.65) - - g2.add_edge("C", "D", color="green", weight=1, size=0.5) - g2.add_edge("C", "D", color="red", weight=0, size=0.45) - g2.add_edge("C", "D", color="red", weight=2, size=0.65) - - if g1.is_multigraph(): - self.em = iso.numerical_multiedge_match("weight", 1) - self.emc = iso.categorical_multiedge_match("color", "") - self.emcm = iso.categorical_multiedge_match(["color", "weight"], ["", 1]) - self.emg1 = iso.generic_multiedge_match("color", "red", eq) - self.emg2 = iso.generic_multiedge_match( - ["color", "weight", "size"], - ["red", 1, 0.5], - [eq, eq, math.isclose], - ) - else: - self.em = iso.numerical_edge_match("weight", 1) - self.emc = iso.categorical_edge_match("color", "") - self.emcm = iso.categorical_edge_match(["color", "weight"], ["", 1]) - self.emg1 = iso.generic_multiedge_match("color", "red", eq) - self.emg2 = iso.generic_edge_match( - ["color", "weight", "size"], - ["red", 1, 0.5], - [eq, eq, math.isclose], - ) - - def test_weights_only(self): - assert nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) - - def test_colors_only(self): - gm = self.GM(self.g1, self.g2, edge_match=self.emc) - assert gm.is_isomorphic() - - def test_colorsandweights(self): - gm = self.GM(self.g1, self.g2, edge_match=self.emcm) - assert not gm.is_isomorphic() - - def test_generic1(self): - gm = self.GM(self.g1, self.g2, edge_match=self.emg1) - assert gm.is_isomorphic() - - def test_generic2(self): - gm = self.GM(self.g1, self.g2, edge_match=self.emg2) - assert not gm.is_isomorphic() - - -class TestEdgeMatch_DiGraph(TestNodeMatch_Graph): - def setup_method(self): - TestNodeMatch_Graph.setup_method(self) - self.g1 = nx.DiGraph() - self.g2 = nx.DiGraph() - self.build() - - -class TestEdgeMatch_MultiDiGraph(TestEdgeMatch_MultiGraph): - def setup_method(self): - TestEdgeMatch_MultiGraph.setup_method(self) - self.g1 = nx.MultiDiGraph() - self.g2 = nx.MultiDiGraph() - self.GM = iso.MultiDiGraphMatcher - self.build() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tree_isomorphism.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tree_isomorphism.py deleted file mode 100644 index e409d51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/tree_isomorphism.py +++ /dev/null @@ -1,284 +0,0 @@ -""" -An algorithm for finding if two undirected trees are isomorphic, -and if so returns an isomorphism between the two sets of nodes. - -This algorithm uses a routine to tell if two rooted trees (trees with a -specified root node) are isomorphic, which may be independently useful. - -This implements an algorithm from: -The Design and Analysis of Computer Algorithms -by Aho, Hopcroft, and Ullman -Addison-Wesley Publishing 1974 -Example 3.2 pp. 84-86. - -A more understandable version of this algorithm is described in: -Homework Assignment 5 -McGill University SOCS 308-250B, Winter 2002 -by Matthew Suderman -http://crypto.cs.mcgill.ca/~crepeau/CS250/2004/HW5+.pdf -""" - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ["rooted_tree_isomorphism", "tree_isomorphism"] - - -@nx._dispatchable(graphs={"t1": 0, "t2": 2}, returns_graph=True) -def root_trees(t1, root1, t2, root2): - """Create a single digraph dT of free trees t1 and t2 - # with roots root1 and root2 respectively - # rename the nodes with consecutive integers - # so that all nodes get a unique name between both trees - - # our new "fake" root node is 0 - # t1 is numbers from 1 ... n - # t2 is numbered from n+1 to 2n - """ - - dT = nx.DiGraph() - - newroot1 = 1 # left root will be 1 - newroot2 = nx.number_of_nodes(t1) + 1 # right will be n+1 - - # may be overlap in node names here so need separate maps - # given the old name, what is the new - namemap1 = {root1: newroot1} - namemap2 = {root2: newroot2} - - # add an edge from our new root to root1 and root2 - dT.add_edge(0, namemap1[root1]) - dT.add_edge(0, namemap2[root2]) - - for i, (v1, v2) in enumerate(nx.bfs_edges(t1, root1)): - namemap1[v2] = i + namemap1[root1] + 1 - dT.add_edge(namemap1[v1], namemap1[v2]) - - for i, (v1, v2) in enumerate(nx.bfs_edges(t2, root2)): - namemap2[v2] = i + namemap2[root2] + 1 - dT.add_edge(namemap2[v1], namemap2[v2]) - - # now we really want the inverse of namemap1 and namemap2 - # giving the old name given the new - # since the values of namemap1 and namemap2 are unique - # there won't be collisions - namemap = {} - for old, new in namemap1.items(): - namemap[new] = old - for old, new in namemap2.items(): - namemap[new] = old - - return (dT, namemap, newroot1, newroot2) - - -# figure out the level of each node, with 0 at root -@nx._dispatchable -def assign_levels(G, root): - level = {} - level[root] = 0 - for v1, v2 in nx.bfs_edges(G, root): - level[v2] = level[v1] + 1 - - return level - - -# now group the nodes at each level -def group_by_levels(levels): - L = {} - for n, lev in levels.items(): - if lev not in L: - L[lev] = [] - L[lev].append(n) - - return L - - -# now lets get the isomorphism by walking the ordered_children -def generate_isomorphism(v, w, M, ordered_children): - # make sure tree1 comes first - assert v < w - M.append((v, w)) - for i, (x, y) in enumerate(zip(ordered_children[v], ordered_children[w])): - generate_isomorphism(x, y, M, ordered_children) - - -@nx._dispatchable(graphs={"t1": 0, "t2": 2}) -def rooted_tree_isomorphism(t1, root1, t2, root2): - """ - Given two rooted trees `t1` and `t2`, - with roots `root1` and `root2` respectively - this routine will determine if they are isomorphic. - - These trees may be either directed or undirected, - but if they are directed, all edges should flow from the root. - - It returns the isomorphism, a mapping of the nodes of `t1` onto the nodes - of `t2`, such that two trees are then identical. - - Note that two trees may have more than one isomorphism, and this - routine just returns one valid mapping. - - Parameters - ---------- - `t1` : NetworkX graph - One of the trees being compared - - `root1` : a node of `t1` which is the root of the tree - - `t2` : undirected NetworkX graph - The other tree being compared - - `root2` : a node of `t2` which is the root of the tree - - This is a subroutine used to implement `tree_isomorphism`, but will - be somewhat faster if you already have rooted trees. - - Returns - ------- - isomorphism : list - A list of pairs in which the left element is a node in `t1` - and the right element is a node in `t2`. The pairs are in - arbitrary order. If the nodes in one tree is mapped to the names in - the other, then trees will be identical. Note that an isomorphism - will not necessarily be unique. - - If `t1` and `t2` are not isomorphic, then it returns the empty list. - """ - - assert nx.is_tree(t1) - assert nx.is_tree(t2) - - # get the rooted tree formed by combining them - # with unique names - (dT, namemap, newroot1, newroot2) = root_trees(t1, root1, t2, root2) - - # compute the distance from the root, with 0 for our - levels = assign_levels(dT, 0) - - # height - h = max(levels.values()) - - # collect nodes into a dict by level - L = group_by_levels(levels) - - # each node has a label, initially set to 0 - label = {v: 0 for v in dT} - # and also ordered_labels and ordered_children - # which will store ordered tuples - ordered_labels = {v: () for v in dT} - ordered_children = {v: () for v in dT} - - # nothing to do on last level so start on h-1 - # also nothing to do for our fake level 0, so skip that - for i in range(h - 1, 0, -1): - # update the ordered_labels and ordered_children - # for any children - for v in L[i]: - # nothing to do if no children - if dT.out_degree(v) > 0: - # get all the pairs of labels and nodes of children - # and sort by labels - s = sorted((label[u], u) for u in dT.successors(v)) - - # invert to give a list of two tuples - # the sorted labels, and the corresponding children - ordered_labels[v], ordered_children[v] = list(zip(*s)) - - # now collect and sort the sorted ordered_labels - # for all nodes in L[i], carrying along the node - forlabel = sorted((ordered_labels[v], v) for v in L[i]) - - # now assign labels to these nodes, according to the sorted order - # starting from 0, where identical ordered_labels get the same label - current = 0 - for i, (ol, v) in enumerate(forlabel): - # advance to next label if not 0, and different from previous - if (i != 0) and (ol != forlabel[i - 1][0]): - current += 1 - label[v] = current - - # they are isomorphic if the labels of newroot1 and newroot2 are 0 - isomorphism = [] - if label[newroot1] == 0 and label[newroot2] == 0: - generate_isomorphism(newroot1, newroot2, isomorphism, ordered_children) - - # get the mapping back in terms of the old names - # return in sorted order for neatness - isomorphism = [(namemap[u], namemap[v]) for (u, v) in isomorphism] - - return isomorphism - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(graphs={"t1": 0, "t2": 1}) -def tree_isomorphism(t1, t2): - """ - Given two undirected (or free) trees `t1` and `t2`, - this routine will determine if they are isomorphic. - It returns the isomorphism, a mapping of the nodes of `t1` onto the nodes - of `t2`, such that two trees are then identical. - - Note that two trees may have more than one isomorphism, and this - routine just returns one valid mapping. - - Parameters - ---------- - t1 : undirected NetworkX graph - One of the trees being compared - - t2 : undirected NetworkX graph - The other tree being compared - - Returns - ------- - isomorphism : list - A list of pairs in which the left element is a node in `t1` - and the right element is a node in `t2`. The pairs are in - arbitrary order. If the nodes in one tree is mapped to the names in - the other, then trees will be identical. Note that an isomorphism - will not necessarily be unique. - - If `t1` and `t2` are not isomorphic, then it returns the empty list. - - Notes - ----- - This runs in O(n*log(n)) time for trees with n nodes. - """ - - assert nx.is_tree(t1) - assert nx.is_tree(t2) - - # To be isomorphic, t1 and t2 must have the same number of nodes. - if nx.number_of_nodes(t1) != nx.number_of_nodes(t2): - return [] - - # Another shortcut is that the sorted degree sequences need to be the same. - degree_sequence1 = sorted(d for (n, d) in t1.degree()) - degree_sequence2 = sorted(d for (n, d) in t2.degree()) - - if degree_sequence1 != degree_sequence2: - return [] - - # A tree can have either 1 or 2 centers. - # If the number doesn't match then t1 and t2 are not isomorphic. - center1 = nx.center(t1) - center2 = nx.center(t2) - - if len(center1) != len(center2): - return [] - - # If there is only 1 center in each, then use it. - if len(center1) == 1: - return rooted_tree_isomorphism(t1, center1[0], t2, center2[0]) - - # If there both have 2 centers, then try the first for t1 - # with the first for t2. - attempts = rooted_tree_isomorphism(t1, center1[0], t2, center2[0]) - - # If that worked we're done. - if len(attempts) > 0: - return attempts - - # Otherwise, try center1[0] with the center2[1], and see if that works - return rooted_tree_isomorphism(t1, center1[0], t2, center2[1]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2pp.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2pp.py deleted file mode 100644 index 3093d9c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2pp.py +++ /dev/null @@ -1,1075 +0,0 @@ -""" -*************** -VF2++ Algorithm -*************** - -An implementation of the VF2++ algorithm [1]_ for Graph Isomorphism testing. - -The simplest interface to use this module is to call: - -`vf2pp_is_isomorphic`: to check whether two graphs are isomorphic. -`vf2pp_isomorphism`: to obtain the node mapping between two graphs, -in case they are isomorphic. -`vf2pp_all_isomorphisms`: to generate all possible mappings between two graphs, -if isomorphic. - -Introduction ------------- -The VF2++ algorithm, follows a similar logic to that of VF2, while also -introducing new easy-to-check cutting rules and determining the optimal access -order of nodes. It is also implemented in a non-recursive manner, which saves -both time and space, when compared to its previous counterpart. - -The optimal node ordering is obtained after taking into consideration both the -degree but also the label rarity of each node. -This way we place the nodes that are more likely to match, first in the order, -thus examining the most promising branches in the beginning. -The rules also consider node labels, making it easier to prune unfruitful -branches early in the process. - -Examples --------- - -Suppose G1 and G2 are Isomorphic Graphs. Verification is as follows: - -Without node labels: - ->>> import networkx as nx ->>> G1 = nx.path_graph(4) ->>> G2 = nx.path_graph(4) ->>> nx.vf2pp_is_isomorphic(G1, G2, node_label=None) -True ->>> nx.vf2pp_isomorphism(G1, G2, node_label=None) -{1: 1, 2: 2, 0: 0, 3: 3} - -With node labels: - ->>> G1 = nx.path_graph(4) ->>> G2 = nx.path_graph(4) ->>> mapped = {1: 1, 2: 2, 3: 3, 0: 0} ->>> nx.set_node_attributes( -... G1, dict(zip(G1, ["blue", "red", "green", "yellow"])), "label" -... ) ->>> nx.set_node_attributes( -... G2, -... dict(zip([mapped[u] for u in G1], ["blue", "red", "green", "yellow"])), -... "label", -... ) ->>> nx.vf2pp_is_isomorphic(G1, G2, node_label="label") -True ->>> nx.vf2pp_isomorphism(G1, G2, node_label="label") -{1: 1, 2: 2, 0: 0, 3: 3} - -References ----------- -.. [1] Jüttner, Alpár & Madarasi, Péter. (2018). "VF2++—An improved subgraph - isomorphism algorithm". Discrete Applied Mathematics. 242. - https://doi.org/10.1016/j.dam.2018.02.018 - -""" - -import collections - -import networkx as nx - -__all__ = ["vf2pp_isomorphism", "vf2pp_is_isomorphic", "vf2pp_all_isomorphisms"] - -_GraphParameters = collections.namedtuple( - "_GraphParameters", - [ - "G1", - "G2", - "G1_labels", - "G2_labels", - "nodes_of_G1Labels", - "nodes_of_G2Labels", - "G2_nodes_of_degree", - ], -) - -_StateParameters = collections.namedtuple( - "_StateParameters", - [ - "mapping", - "reverse_mapping", - "T1", - "T1_in", - "T1_tilde", - "T1_tilde_in", - "T2", - "T2_in", - "T2_tilde", - "T2_tilde_in", - ], -) - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}, node_attrs={"node_label": "default_label"}) -def vf2pp_isomorphism(G1, G2, node_label=None, default_label=None): - """Return an isomorphic mapping between `G1` and `G2` if it exists. - - Parameters - ---------- - G1, G2 : NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism. - - node_label : str, optional - The name of the node attribute to be used when comparing nodes. - The default is `None`, meaning node attributes are not considered - in the comparison. Any node that doesn't have the `node_label` - attribute uses `default_label` instead. - - default_label : scalar - Default value to use when a node doesn't have an attribute - named `node_label`. Default is `None`. - - Returns - ------- - dict or None - Node mapping if the two graphs are isomorphic. None otherwise. - """ - try: - mapping = next(vf2pp_all_isomorphisms(G1, G2, node_label, default_label)) - return mapping - except StopIteration: - return None - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}, node_attrs={"node_label": "default_label"}) -def vf2pp_is_isomorphic(G1, G2, node_label=None, default_label=None): - """Examines whether G1 and G2 are isomorphic. - - Parameters - ---------- - G1, G2 : NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism. - - node_label : str, optional - The name of the node attribute to be used when comparing nodes. - The default is `None`, meaning node attributes are not considered - in the comparison. Any node that doesn't have the `node_label` - attribute uses `default_label` instead. - - default_label : scalar - Default value to use when a node doesn't have an attribute - named `node_label`. Default is `None`. - - Returns - ------- - bool - True if the two graphs are isomorphic, False otherwise. - """ - if vf2pp_isomorphism(G1, G2, node_label, default_label) is not None: - return True - return False - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}, node_attrs={"node_label": "default_label"}) -def vf2pp_all_isomorphisms(G1, G2, node_label=None, default_label=None): - """Yields all the possible mappings between G1 and G2. - - Parameters - ---------- - G1, G2 : NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism. - - node_label : str, optional - The name of the node attribute to be used when comparing nodes. - The default is `None`, meaning node attributes are not considered - in the comparison. Any node that doesn't have the `node_label` - attribute uses `default_label` instead. - - default_label : scalar - Default value to use when a node doesn't have an attribute - named `node_label`. Default is `None`. - - Yields - ------ - dict - Isomorphic mapping between the nodes in `G1` and `G2`. - """ - if G1.number_of_nodes() == 0 or G2.number_of_nodes() == 0: - return False - - # Create the degree dicts based on graph type - if G1.is_directed(): - G1_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree) - } - G2_degree = { - n: (in_degree, out_degree) - for (n, in_degree), (_, out_degree) in zip(G2.in_degree, G2.out_degree) - } - else: - G1_degree = dict(G1.degree) - G2_degree = dict(G2.degree) - - if not G1.is_directed(): - find_candidates = _find_candidates - restore_Tinout = _restore_Tinout - else: - find_candidates = _find_candidates_Di - restore_Tinout = _restore_Tinout_Di - - # Check that both graphs have the same number of nodes and degree sequence - if G1.order() != G2.order(): - return False - if sorted(G1_degree.values()) != sorted(G2_degree.values()): - return False - - # Initialize parameters and cache necessary information about degree and labels - graph_params, state_params = _initialize_parameters( - G1, G2, G2_degree, node_label, default_label - ) - - # Check if G1 and G2 have the same labels, and that number of nodes per label is equal between the two graphs - if not _precheck_label_properties(graph_params): - return False - - # Calculate the optimal node ordering - node_order = _matching_order(graph_params) - - # Initialize the stack - stack = [] - candidates = iter( - find_candidates(node_order[0], graph_params, state_params, G1_degree) - ) - stack.append((node_order[0], candidates)) - - mapping = state_params.mapping - reverse_mapping = state_params.reverse_mapping - - # Index of the node from the order, currently being examined - matching_node = 1 - - while stack: - current_node, candidate_nodes = stack[-1] - - try: - candidate = next(candidate_nodes) - except StopIteration: - # If no remaining candidates, return to a previous state, and follow another branch - stack.pop() - matching_node -= 1 - if stack: - # Pop the previously added u-v pair, and look for a different candidate _v for u - popped_node1, _ = stack[-1] - popped_node2 = mapping[popped_node1] - mapping.pop(popped_node1) - reverse_mapping.pop(popped_node2) - restore_Tinout(popped_node1, popped_node2, graph_params, state_params) - continue - - if _feasibility(current_node, candidate, graph_params, state_params): - # Terminate if mapping is extended to its full - if len(mapping) == G2.number_of_nodes() - 1: - cp_mapping = mapping.copy() - cp_mapping[current_node] = candidate - yield cp_mapping - continue - - # Feasibility rules pass, so extend the mapping and update the parameters - mapping[current_node] = candidate - reverse_mapping[candidate] = current_node - _update_Tinout(current_node, candidate, graph_params, state_params) - # Append the next node and its candidates to the stack - candidates = iter( - find_candidates( - node_order[matching_node], graph_params, state_params, G1_degree - ) - ) - stack.append((node_order[matching_node], candidates)) - matching_node += 1 - - -def _precheck_label_properties(graph_params): - G1, G2, G1_labels, G2_labels, nodes_of_G1Labels, nodes_of_G2Labels, _ = graph_params - if any( - label not in nodes_of_G1Labels or len(nodes_of_G1Labels[label]) != len(nodes) - for label, nodes in nodes_of_G2Labels.items() - ): - return False - return True - - -def _initialize_parameters(G1, G2, G2_degree, node_label=None, default_label=-1): - """Initializes all the necessary parameters for VF2++ - - Parameters - ---------- - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - Returns - ------- - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2 - G1_labels,G2_labels: dict - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_out, T2_out: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - """ - G1_labels = dict(G1.nodes(data=node_label, default=default_label)) - G2_labels = dict(G2.nodes(data=node_label, default=default_label)) - - graph_params = _GraphParameters( - G1, - G2, - G1_labels, - G2_labels, - nx.utils.groups(G1_labels), - nx.utils.groups(G2_labels), - nx.utils.groups(G2_degree), - ) - - T1, T1_in = set(), set() - T2, T2_in = set(), set() - if G1.is_directed(): - T1_tilde, T1_tilde_in = ( - set(G1.nodes()), - set(), - ) # todo: do we need Ti_tilde_in? What nodes does it have? - T2_tilde, T2_tilde_in = set(G2.nodes()), set() - else: - T1_tilde, T1_tilde_in = set(G1.nodes()), set() - T2_tilde, T2_tilde_in = set(G2.nodes()), set() - - state_params = _StateParameters( - {}, - {}, - T1, - T1_in, - T1_tilde, - T1_tilde_in, - T2, - T2_in, - T2_tilde, - T2_tilde_in, - ) - - return graph_params, state_params - - -def _matching_order(graph_params): - """The node ordering as introduced in VF2++. - - Notes - ----- - Taking into account the structure of the Graph and the node labeling, the nodes are placed in an order such that, - most of the unfruitful/infeasible branches of the search space can be pruned on high levels, significantly - decreasing the number of visited states. The premise is that, the algorithm will be able to recognize - inconsistencies early, proceeding to go deep into the search tree only if it's needed. - - Parameters - ---------- - graph_params: namedtuple - Contains: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism. - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively. - - Returns - ------- - node_order: list - The ordering of the nodes. - """ - G1, G2, G1_labels, _, _, nodes_of_G2Labels, _ = graph_params - if not G1 and not G2: - return {} - - if G1.is_directed(): - G1 = G1.to_undirected(as_view=True) - - V1_unordered = set(G1.nodes()) - label_rarity = {label: len(nodes) for label, nodes in nodes_of_G2Labels.items()} - used_degrees = {node: 0 for node in G1} - node_order = [] - - while V1_unordered: - max_rarity = min(label_rarity[G1_labels[x]] for x in V1_unordered) - rarest_nodes = [ - n for n in V1_unordered if label_rarity[G1_labels[n]] == max_rarity - ] - max_node = max(rarest_nodes, key=G1.degree) - - for dlevel_nodes in nx.bfs_layers(G1, max_node): - nodes_to_add = dlevel_nodes.copy() - while nodes_to_add: - max_used_degree = max(used_degrees[n] for n in nodes_to_add) - max_used_degree_nodes = [ - n for n in nodes_to_add if used_degrees[n] == max_used_degree - ] - max_degree = max(G1.degree[n] for n in max_used_degree_nodes) - max_degree_nodes = [ - n for n in max_used_degree_nodes if G1.degree[n] == max_degree - ] - next_node = min( - max_degree_nodes, key=lambda x: label_rarity[G1_labels[x]] - ) - - node_order.append(next_node) - for node in G1.neighbors(next_node): - used_degrees[node] += 1 - - nodes_to_add.remove(next_node) - label_rarity[G1_labels[next_node]] -= 1 - V1_unordered.discard(next_node) - - return node_order - - -def _find_candidates( - u, graph_params, state_params, G1_degree -): # todo: make the 4th argument the degree of u - """Given node u of G1, finds the candidates of u from G2. - - Parameters - ---------- - u: Graph node - The node from G1 for which to find the candidates from G2. - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_tilde, T2_tilde: set - Ti_tilde contains all the nodes from Gi, that are neither in the mapping nor in Ti - - Returns - ------- - candidates: set - The nodes from G2 which are candidates for u. - """ - G1, G2, G1_labels, _, _, nodes_of_G2Labels, G2_nodes_of_degree = graph_params - mapping, reverse_mapping, _, _, _, _, _, _, T2_tilde, _ = state_params - - covered_nbrs = [nbr for nbr in G1[u] if nbr in mapping] - if not covered_nbrs: - candidates = set(nodes_of_G2Labels[G1_labels[u]]) - candidates.intersection_update(G2_nodes_of_degree[G1_degree[u]]) - candidates.intersection_update(T2_tilde) - candidates.difference_update(reverse_mapping) - if G1.is_multigraph(): - candidates.difference_update( - { - node - for node in candidates - if G1.number_of_edges(u, u) != G2.number_of_edges(node, node) - } - ) - return candidates - - nbr1 = covered_nbrs[0] - common_nodes = set(G2[mapping[nbr1]]) - - for nbr1 in covered_nbrs[1:]: - common_nodes.intersection_update(G2[mapping[nbr1]]) - - common_nodes.difference_update(reverse_mapping) - common_nodes.intersection_update(G2_nodes_of_degree[G1_degree[u]]) - common_nodes.intersection_update(nodes_of_G2Labels[G1_labels[u]]) - if G1.is_multigraph(): - common_nodes.difference_update( - { - node - for node in common_nodes - if G1.number_of_edges(u, u) != G2.number_of_edges(node, node) - } - ) - return common_nodes - - -def _find_candidates_Di(u, graph_params, state_params, G1_degree): - G1, G2, G1_labels, _, _, nodes_of_G2Labels, G2_nodes_of_degree = graph_params - mapping, reverse_mapping, _, _, _, _, _, _, T2_tilde, _ = state_params - - covered_successors = [succ for succ in G1[u] if succ in mapping] - covered_predecessors = [pred for pred in G1.pred[u] if pred in mapping] - - if not (covered_successors or covered_predecessors): - candidates = set(nodes_of_G2Labels[G1_labels[u]]) - candidates.intersection_update(G2_nodes_of_degree[G1_degree[u]]) - candidates.intersection_update(T2_tilde) - candidates.difference_update(reverse_mapping) - if G1.is_multigraph(): - candidates.difference_update( - { - node - for node in candidates - if G1.number_of_edges(u, u) != G2.number_of_edges(node, node) - } - ) - return candidates - - if covered_successors: - succ1 = covered_successors[0] - common_nodes = set(G2.pred[mapping[succ1]]) - - for succ1 in covered_successors[1:]: - common_nodes.intersection_update(G2.pred[mapping[succ1]]) - else: - pred1 = covered_predecessors.pop() - common_nodes = set(G2[mapping[pred1]]) - - for pred1 in covered_predecessors: - common_nodes.intersection_update(G2[mapping[pred1]]) - - common_nodes.difference_update(reverse_mapping) - common_nodes.intersection_update(G2_nodes_of_degree[G1_degree[u]]) - common_nodes.intersection_update(nodes_of_G2Labels[G1_labels[u]]) - if G1.is_multigraph(): - common_nodes.difference_update( - { - node - for node in common_nodes - if G1.number_of_edges(u, u) != G2.number_of_edges(node, node) - } - ) - return common_nodes - - -def _feasibility(node1, node2, graph_params, state_params): - """Given a candidate pair of nodes u and v from G1 and G2 respectively, checks if it's feasible to extend the - mapping, i.e. if u and v can be matched. - - Notes - ----- - This function performs all the necessary checking by applying both consistency and cutting rules. - - Parameters - ---------- - node1, node2: Graph node - The candidate pair of nodes being checked for matching - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_out, T2_out: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - - Returns - ------- - True if all checks are successful, False otherwise. - """ - G1 = graph_params.G1 - - if _cut_PT(node1, node2, graph_params, state_params): - return False - - if G1.is_multigraph(): - if not _consistent_PT(node1, node2, graph_params, state_params): - return False - - return True - - -def _cut_PT(u, v, graph_params, state_params): - """Implements the cutting rules for the ISO problem. - - Parameters - ---------- - u, v: Graph node - The two candidate nodes being examined. - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_tilde, T2_tilde: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - - Returns - ------- - True if we should prune this branch, i.e. the node pair failed the cutting checks. False otherwise. - """ - G1, G2, G1_labels, G2_labels, _, _, _ = graph_params - ( - _, - _, - T1, - T1_in, - T1_tilde, - _, - T2, - T2_in, - T2_tilde, - _, - ) = state_params - - u_labels_predecessors, v_labels_predecessors = {}, {} - if G1.is_directed(): - u_labels_predecessors = nx.utils.groups( - {n1: G1_labels[n1] for n1 in G1.pred[u]} - ) - v_labels_predecessors = nx.utils.groups( - {n2: G2_labels[n2] for n2 in G2.pred[v]} - ) - - if set(u_labels_predecessors.keys()) != set(v_labels_predecessors.keys()): - return True - - u_labels_successors = nx.utils.groups({n1: G1_labels[n1] for n1 in G1[u]}) - v_labels_successors = nx.utils.groups({n2: G2_labels[n2] for n2 in G2[v]}) - - # if the neighbors of u, do not have the same labels as those of v, NOT feasible. - if set(u_labels_successors.keys()) != set(v_labels_successors.keys()): - return True - - for label, G1_nbh in u_labels_successors.items(): - G2_nbh = v_labels_successors[label] - - if G1.is_multigraph(): - # Check for every neighbor in the neighborhood, if u-nbr1 has same edges as v-nbr2 - u_nbrs_edges = sorted(G1.number_of_edges(u, x) for x in G1_nbh) - v_nbrs_edges = sorted(G2.number_of_edges(v, x) for x in G2_nbh) - if any( - u_nbr_edges != v_nbr_edges - for u_nbr_edges, v_nbr_edges in zip(u_nbrs_edges, v_nbrs_edges) - ): - return True - - if len(T1.intersection(G1_nbh)) != len(T2.intersection(G2_nbh)): - return True - if len(T1_tilde.intersection(G1_nbh)) != len(T2_tilde.intersection(G2_nbh)): - return True - if G1.is_directed() and len(T1_in.intersection(G1_nbh)) != len( - T2_in.intersection(G2_nbh) - ): - return True - - if not G1.is_directed(): - return False - - for label, G1_pred in u_labels_predecessors.items(): - G2_pred = v_labels_predecessors[label] - - if G1.is_multigraph(): - # Check for every neighbor in the neighborhood, if u-nbr1 has same edges as v-nbr2 - u_pred_edges = sorted(G1.number_of_edges(u, x) for x in G1_pred) - v_pred_edges = sorted(G2.number_of_edges(v, x) for x in G2_pred) - if any( - u_nbr_edges != v_nbr_edges - for u_nbr_edges, v_nbr_edges in zip(u_pred_edges, v_pred_edges) - ): - return True - - if len(T1.intersection(G1_pred)) != len(T2.intersection(G2_pred)): - return True - if len(T1_tilde.intersection(G1_pred)) != len(T2_tilde.intersection(G2_pred)): - return True - if len(T1_in.intersection(G1_pred)) != len(T2_in.intersection(G2_pred)): - return True - - return False - - -def _consistent_PT(u, v, graph_params, state_params): - """Checks the consistency of extending the mapping using the current node pair. - - Parameters - ---------- - u, v: Graph node - The two candidate nodes being examined. - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_out, T2_out: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - - Returns - ------- - True if the pair passes all the consistency checks successfully. False otherwise. - """ - G1, G2 = graph_params.G1, graph_params.G2 - mapping, reverse_mapping = state_params.mapping, state_params.reverse_mapping - - for neighbor in G1[u]: - if neighbor in mapping: - if G1.number_of_edges(u, neighbor) != G2.number_of_edges( - v, mapping[neighbor] - ): - return False - - for neighbor in G2[v]: - if neighbor in reverse_mapping: - if G1.number_of_edges(u, reverse_mapping[neighbor]) != G2.number_of_edges( - v, neighbor - ): - return False - - if not G1.is_directed(): - return True - - for predecessor in G1.pred[u]: - if predecessor in mapping: - if G1.number_of_edges(predecessor, u) != G2.number_of_edges( - mapping[predecessor], v - ): - return False - - for predecessor in G2.pred[v]: - if predecessor in reverse_mapping: - if G1.number_of_edges( - reverse_mapping[predecessor], u - ) != G2.number_of_edges(predecessor, v): - return False - - return True - - -def _update_Tinout(new_node1, new_node2, graph_params, state_params): - """Updates the Ti/Ti_out (i=1,2) when a new node pair u-v is added to the mapping. - - Notes - ----- - This function should be called right after the feasibility checks are passed, and node1 is mapped to node2. The - purpose of this function is to avoid brute force computing of Ti/Ti_out by iterating over all nodes of the graph - and checking which nodes satisfy the necessary conditions. Instead, in every step of the algorithm we focus - exclusively on the two nodes that are being added to the mapping, incrementally updating Ti/Ti_out. - - Parameters - ---------- - new_node1, new_node2: Graph node - The two new nodes, added to the mapping. - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_tilde, T2_tilde: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - """ - G1, G2, _, _, _, _, _ = graph_params - ( - mapping, - reverse_mapping, - T1, - T1_in, - T1_tilde, - T1_tilde_in, - T2, - T2_in, - T2_tilde, - T2_tilde_in, - ) = state_params - - uncovered_successors_G1 = {succ for succ in G1[new_node1] if succ not in mapping} - uncovered_successors_G2 = { - succ for succ in G2[new_node2] if succ not in reverse_mapping - } - - # Add the uncovered neighbors of node1 and node2 in T1 and T2 respectively - T1.update(uncovered_successors_G1) - T2.update(uncovered_successors_G2) - T1.discard(new_node1) - T2.discard(new_node2) - - T1_tilde.difference_update(uncovered_successors_G1) - T2_tilde.difference_update(uncovered_successors_G2) - T1_tilde.discard(new_node1) - T2_tilde.discard(new_node2) - - if not G1.is_directed(): - return - - uncovered_predecessors_G1 = { - pred for pred in G1.pred[new_node1] if pred not in mapping - } - uncovered_predecessors_G2 = { - pred for pred in G2.pred[new_node2] if pred not in reverse_mapping - } - - T1_in.update(uncovered_predecessors_G1) - T2_in.update(uncovered_predecessors_G2) - T1_in.discard(new_node1) - T2_in.discard(new_node2) - - T1_tilde.difference_update(uncovered_predecessors_G1) - T2_tilde.difference_update(uncovered_predecessors_G2) - T1_tilde.discard(new_node1) - T2_tilde.discard(new_node2) - - -def _restore_Tinout(popped_node1, popped_node2, graph_params, state_params): - """Restores the previous version of Ti/Ti_out when a node pair is deleted from the mapping. - - Parameters - ---------- - popped_node1, popped_node2: Graph node - The two nodes deleted from the mapping. - - graph_params: namedtuple - Contains all the Graph-related parameters: - - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism - - G1_labels,G2_labels: dict - The label of every node in G1 and G2 respectively - - state_params: namedtuple - Contains all the State-related parameters: - - mapping: dict - The mapping as extended so far. Maps nodes of G1 to nodes of G2 - - reverse_mapping: dict - The reverse mapping as extended so far. Maps nodes from G2 to nodes of G1. It's basically "mapping" reversed - - T1, T2: set - Ti contains uncovered neighbors of covered nodes from Gi, i.e. nodes that are not in the mapping, but are - neighbors of nodes that are. - - T1_tilde, T2_tilde: set - Ti_out contains all the nodes from Gi, that are neither in the mapping nor in Ti - """ - # If the node we want to remove from the mapping, has at least one covered neighbor, add it to T1. - G1, G2, _, _, _, _, _ = graph_params - ( - mapping, - reverse_mapping, - T1, - T1_in, - T1_tilde, - T1_tilde_in, - T2, - T2_in, - T2_tilde, - T2_tilde_in, - ) = state_params - - is_added = False - for neighbor in G1[popped_node1]: - if neighbor in mapping: - # if a neighbor of the excluded node1 is in the mapping, keep node1 in T1 - is_added = True - T1.add(popped_node1) - else: - # check if its neighbor has another connection with a covered node. If not, only then exclude it from T1 - if any(nbr in mapping for nbr in G1[neighbor]): - continue - T1.discard(neighbor) - T1_tilde.add(neighbor) - - # Case where the node is not present in neither the mapping nor T1. By definition, it should belong to T1_tilde - if not is_added: - T1_tilde.add(popped_node1) - - is_added = False - for neighbor in G2[popped_node2]: - if neighbor in reverse_mapping: - is_added = True - T2.add(popped_node2) - else: - if any(nbr in reverse_mapping for nbr in G2[neighbor]): - continue - T2.discard(neighbor) - T2_tilde.add(neighbor) - - if not is_added: - T2_tilde.add(popped_node2) - - -def _restore_Tinout_Di(popped_node1, popped_node2, graph_params, state_params): - # If the node we want to remove from the mapping, has at least one covered neighbor, add it to T1. - G1, G2, _, _, _, _, _ = graph_params - ( - mapping, - reverse_mapping, - T1, - T1_in, - T1_tilde, - T1_tilde_in, - T2, - T2_in, - T2_tilde, - T2_tilde_in, - ) = state_params - - is_added = False - for successor in G1[popped_node1]: - if successor in mapping: - # if a neighbor of the excluded node1 is in the mapping, keep node1 in T1 - is_added = True - T1_in.add(popped_node1) - else: - # check if its neighbor has another connection with a covered node. If not, only then exclude it from T1 - if not any(pred in mapping for pred in G1.pred[successor]): - T1.discard(successor) - - if not any(succ in mapping for succ in G1[successor]): - T1_in.discard(successor) - - if successor not in T1: - if successor not in T1_in: - T1_tilde.add(successor) - - for predecessor in G1.pred[popped_node1]: - if predecessor in mapping: - # if a neighbor of the excluded node1 is in the mapping, keep node1 in T1 - is_added = True - T1.add(popped_node1) - else: - # check if its neighbor has another connection with a covered node. If not, only then exclude it from T1 - if not any(pred in mapping for pred in G1.pred[predecessor]): - T1.discard(predecessor) - - if not any(succ in mapping for succ in G1[predecessor]): - T1_in.discard(predecessor) - - if not (predecessor in T1 or predecessor in T1_in): - T1_tilde.add(predecessor) - - # Case where the node is not present in neither the mapping nor T1. By definition it should belong to T1_tilde - if not is_added: - T1_tilde.add(popped_node1) - - is_added = False - for successor in G2[popped_node2]: - if successor in reverse_mapping: - is_added = True - T2_in.add(popped_node2) - else: - if not any(pred in reverse_mapping for pred in G2.pred[successor]): - T2.discard(successor) - - if not any(succ in reverse_mapping for succ in G2[successor]): - T2_in.discard(successor) - - if successor not in T2: - if successor not in T2_in: - T2_tilde.add(successor) - - for predecessor in G2.pred[popped_node2]: - if predecessor in reverse_mapping: - # if a neighbor of the excluded node1 is in the mapping, keep node1 in T1 - is_added = True - T2.add(popped_node2) - else: - # check if its neighbor has another connection with a covered node. If not, only then exclude it from T1 - if not any(pred in reverse_mapping for pred in G2.pred[predecessor]): - T2.discard(predecessor) - - if not any(succ in reverse_mapping for succ in G2[predecessor]): - T2_in.discard(predecessor) - - if not (predecessor in T2 or predecessor in T2_in): - T2_tilde.add(predecessor) - - if not is_added: - T2_tilde.add(popped_node2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2userfunc.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2userfunc.py deleted file mode 100644 index 6fcf8a1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/isomorphism/vf2userfunc.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Module to simplify the specification of user-defined equality functions for -node and edge attributes during isomorphism checks. - -During the construction of an isomorphism, the algorithm considers two -candidate nodes n1 in G1 and n2 in G2. The graphs G1 and G2 are then -compared with respect to properties involving n1 and n2, and if the outcome -is good, then the candidate nodes are considered isomorphic. NetworkX -provides a simple mechanism for users to extend the comparisons to include -node and edge attributes. - -Node attributes are handled by the node_match keyword. When considering -n1 and n2, the algorithm passes their node attribute dictionaries to -node_match, and if it returns False, then n1 and n2 cannot be -considered to be isomorphic. - -Edge attributes are handled by the edge_match keyword. When considering -n1 and n2, the algorithm must verify that outgoing edges from n1 are -commensurate with the outgoing edges for n2. If the graph is directed, -then a similar check is also performed for incoming edges. - -Focusing only on outgoing edges, we consider pairs of nodes (n1, v1) from -G1 and (n2, v2) from G2. For graphs and digraphs, there is only one edge -between (n1, v1) and only one edge between (n2, v2). Those edge attribute -dictionaries are passed to edge_match, and if it returns False, then -n1 and n2 cannot be considered isomorphic. For multigraphs and -multidigraphs, there can be multiple edges between (n1, v1) and also -multiple edges between (n2, v2). Now, there must exist an isomorphism -from "all the edges between (n1, v1)" to "all the edges between (n2, v2)". -So, all of the edge attribute dictionaries are passed to edge_match, and -it must determine if there is an isomorphism between the two sets of edges. -""" - -from . import isomorphvf2 as vf2 - -__all__ = ["GraphMatcher", "DiGraphMatcher", "MultiGraphMatcher", "MultiDiGraphMatcher"] - - -def _semantic_feasibility(self, G1_node, G2_node): - """Returns True if mapping G1_node to G2_node is semantically feasible.""" - # Make sure the nodes match - if self.node_match is not None: - nm = self.node_match(self.G1.nodes[G1_node], self.G2.nodes[G2_node]) - if not nm: - return False - - # Make sure the edges match - if self.edge_match is not None: - # Cached lookups - G1nbrs = self.G1_adj[G1_node] - G2nbrs = self.G2_adj[G2_node] - core_1 = self.core_1 - edge_match = self.edge_match - - for neighbor in G1nbrs: - # G1_node is not in core_1, so we must handle R_self separately - if neighbor == G1_node: - if G2_node in G2nbrs and not edge_match( - G1nbrs[G1_node], G2nbrs[G2_node] - ): - return False - elif neighbor in core_1: - G2_nbr = core_1[neighbor] - if G2_nbr in G2nbrs and not edge_match( - G1nbrs[neighbor], G2nbrs[G2_nbr] - ): - return False - # syntactic check has already verified that neighbors are symmetric - - return True - - -class GraphMatcher(vf2.GraphMatcher): - """VF2 isomorphism checker for undirected graphs.""" - - def __init__(self, G1, G2, node_match=None, edge_match=None): - """Initialize graph matcher. - - Parameters - ---------- - G1, G2: graph - The graphs to be tested. - - node_match: callable - A function that returns True iff node n1 in G1 and n2 in G2 - should be considered equal during the isomorphism test. The - function will be called like:: - - node_match(G1.nodes[n1], G2.nodes[n2]) - - That is, the function will receive the node attribute dictionaries - of the nodes under consideration. If None, then no attributes are - considered when testing for an isomorphism. - - edge_match: callable - A function that returns True iff the edge attribute dictionary for - the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should be - considered equal during the isomorphism test. The function will be - called like:: - - edge_match(G1[u1][v1], G2[u2][v2]) - - That is, the function will receive the edge attribute dictionaries - of the edges under consideration. If None, then no attributes are - considered when testing for an isomorphism. - - """ - vf2.GraphMatcher.__init__(self, G1, G2) - - self.node_match = node_match - self.edge_match = edge_match - - # These will be modified during checks to minimize code repeat. - self.G1_adj = self.G1.adj - self.G2_adj = self.G2.adj - - semantic_feasibility = _semantic_feasibility - - -class DiGraphMatcher(vf2.DiGraphMatcher): - """VF2 isomorphism checker for directed graphs.""" - - def __init__(self, G1, G2, node_match=None, edge_match=None): - """Initialize graph matcher. - - Parameters - ---------- - G1, G2 : graph - The graphs to be tested. - - node_match : callable - A function that returns True iff node n1 in G1 and n2 in G2 - should be considered equal during the isomorphism test. The - function will be called like:: - - node_match(G1.nodes[n1], G2.nodes[n2]) - - That is, the function will receive the node attribute dictionaries - of the nodes under consideration. If None, then no attributes are - considered when testing for an isomorphism. - - edge_match : callable - A function that returns True iff the edge attribute dictionary for - the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should be - considered equal during the isomorphism test. The function will be - called like:: - - edge_match(G1[u1][v1], G2[u2][v2]) - - That is, the function will receive the edge attribute dictionaries - of the edges under consideration. If None, then no attributes are - considered when testing for an isomorphism. - - """ - vf2.DiGraphMatcher.__init__(self, G1, G2) - - self.node_match = node_match - self.edge_match = edge_match - - # These will be modified during checks to minimize code repeat. - self.G1_adj = self.G1.adj - self.G2_adj = self.G2.adj - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if mapping G1_node to G2_node is semantically feasible.""" - - # Test node_match and also test edge_match on successors - feasible = _semantic_feasibility(self, G1_node, G2_node) - if not feasible: - return False - - # Test edge_match on predecessors - self.G1_adj = self.G1.pred - self.G2_adj = self.G2.pred - feasible = _semantic_feasibility(self, G1_node, G2_node) - self.G1_adj = self.G1.adj - self.G2_adj = self.G2.adj - - return feasible - - -# The "semantics" of edge_match are different for multi(di)graphs, but -# the implementation is the same. So, technically we do not need to -# provide "multi" versions, but we do so to match NetworkX's base classes. - - -class MultiGraphMatcher(GraphMatcher): - """VF2 isomorphism checker for undirected multigraphs.""" - - -class MultiDiGraphMatcher(DiGraphMatcher): - """VF2 isomorphism checker for directed multigraphs.""" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/__init__.py deleted file mode 100644 index 6009f00..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from networkx.algorithms.link_analysis.hits_alg import * -from networkx.algorithms.link_analysis.pagerank_alg import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/hits_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/hits_alg.py deleted file mode 100644 index d9e3069..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/hits_alg.py +++ /dev/null @@ -1,337 +0,0 @@ -"""Hubs and authorities analysis of graph structure.""" - -import networkx as nx - -__all__ = ["hits"] - - -@nx._dispatchable(preserve_edge_attrs={"G": {"weight": 1}}) -def hits(G, max_iter=100, tol=1.0e-8, nstart=None, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - max_iter : integer, optional - Maximum number of iterations in power method. - - tol : float, optional - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of each node for power method iteration. - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> h, a = nx.hits(G) - - Notes - ----- - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop - after max_iter iterations or an error tolerance of - number_of_nodes(G)*tol has been reached. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-32, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - import numpy as np - import scipy as sp - - if len(G) == 0: - return {}, {} - A = nx.adjacency_matrix(G, nodelist=list(G), dtype=float) - - if nstart is not None: - nstart = np.array(list(nstart.values())) - if max_iter <= 0: - raise nx.PowerIterationFailedConvergence(max_iter) - try: - _, _, vt = sp.sparse.linalg.svds(A, k=1, v0=nstart, maxiter=max_iter, tol=tol) - except sp.sparse.linalg.ArpackNoConvergence as exc: - raise nx.PowerIterationFailedConvergence(max_iter) from exc - - a = vt.flatten().real - h = A @ a - if normalized: - h /= h.sum() - a /= a.sum() - hubs = dict(zip(G, map(float, h))) - authorities = dict(zip(G, map(float, a))) - return hubs, authorities - - -def _hits_python(G, max_iter=100, tol=1.0e-8, nstart=None, normalized=True): - if isinstance(G, nx.MultiGraph | nx.MultiDiGraph): - raise Exception("hits() not defined for graphs with multiedges.") - if len(G) == 0: - return {}, {} - # choose fixed starting vector if not given - if nstart is None: - h = dict.fromkeys(G, 1.0 / G.number_of_nodes()) - else: - h = nstart - # normalize starting vector - s = 1.0 / sum(h.values()) - for k in h: - h[k] *= s - for _ in range(max_iter): # power iteration: make up to max_iter iterations - hlast = h - h = dict.fromkeys(hlast.keys(), 0) - a = dict.fromkeys(hlast.keys(), 0) - # this "matrix multiply" looks odd because it is - # doing a left multiply a^T=hlast^T*G - for n in h: - for nbr in G[n]: - a[nbr] += hlast[n] * G[n][nbr].get("weight", 1) - # now multiply h=Ga - for n in h: - for nbr in G[n]: - h[n] += a[nbr] * G[n][nbr].get("weight", 1) - # normalize vector - s = 1.0 / max(h.values()) - for n in h: - h[n] *= s - # normalize vector - s = 1.0 / max(a.values()) - for n in a: - a[n] *= s - # check convergence, l1 norm - err = sum(abs(h[n] - hlast[n]) for n in h) - if err < tol: - break - else: - raise nx.PowerIterationFailedConvergence(max_iter) - if normalized: - s = 1.0 / sum(a.values()) - for n in a: - a[n] *= s - s = 1.0 / sum(h.values()) - for n in h: - h[n] *= s - return h, a - - -def _hits_numpy(G, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Examples - -------- - >>> G = nx.path_graph(4) - - The `hubs` and `authorities` are given by the eigenvectors corresponding to the - maximum eigenvalues of the hubs_matrix and the authority_matrix, respectively. - - The ``hubs`` and ``authority`` matrices are computed from the adjacency - matrix: - - >>> adj_ary = nx.to_numpy_array(G) - >>> hubs_matrix = adj_ary @ adj_ary.T - >>> authority_matrix = adj_ary.T @ adj_ary - - `_hits_numpy` maps the eigenvector corresponding to the maximum eigenvalue - of the respective matrices to the nodes in `G`: - - >>> from networkx.algorithms.link_analysis.hits_alg import _hits_numpy - >>> hubs, authority = _hits_numpy(G) - - Notes - ----- - The eigenvector calculation uses NumPy's interface to LAPACK. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-32, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - import numpy as np - - if len(G) == 0: - return {}, {} - adj_ary = nx.to_numpy_array(G) - # Hub matrix - H = adj_ary @ adj_ary.T - e, ev = np.linalg.eig(H) - h = ev[:, np.argmax(e)] # eigenvector corresponding to the maximum eigenvalue - # Authority matrix - A = adj_ary.T @ adj_ary - e, ev = np.linalg.eig(A) - a = ev[:, np.argmax(e)] # eigenvector corresponding to the maximum eigenvalue - if normalized: - h /= h.sum() - a /= a.sum() - else: - h /= h.max() - a /= a.max() - hubs = dict(zip(G, map(float, h))) - authorities = dict(zip(G, map(float, a))) - return hubs, authorities - - -def _hits_scipy(G, max_iter=100, tol=1.0e-6, nstart=None, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - max_iter : integer, optional - Maximum number of iterations in power method. - - tol : float, optional - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of each node for power method iteration. - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Examples - -------- - >>> from networkx.algorithms.link_analysis.hits_alg import _hits_scipy - >>> G = nx.path_graph(4) - >>> h, a = _hits_scipy(G) - - Notes - ----- - This implementation uses SciPy sparse matrices. - - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop - after max_iter iterations or an error tolerance of - number_of_nodes(G)*tol has been reached. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-632, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - import numpy as np - - if len(G) == 0: - return {}, {} - A = nx.to_scipy_sparse_array(G, nodelist=list(G)) - (n, _) = A.shape # should be square - ATA = A.T @ A # authority matrix - # choose fixed starting vector if not given - if nstart is None: - x = np.ones((n, 1)) / n - else: - x = np.array([nstart.get(n, 0) for n in list(G)], dtype=float) - x /= x.sum() - - # power iteration on authority matrix - i = 0 - while True: - xlast = x - x = ATA @ x - x /= x.max() - # check convergence, l1 norm - err = np.absolute(x - xlast).sum() - if err < tol: - break - if i > max_iter: - raise nx.PowerIterationFailedConvergence(max_iter) - i += 1 - - a = x.flatten() - h = A @ a - if normalized: - h /= h.sum() - a /= a.sum() - hubs = dict(zip(G, map(float, h))) - authorities = dict(zip(G, map(float, a))) - return hubs, authorities diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/pagerank_alg.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/pagerank_alg.py deleted file mode 100644 index de9f95b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/pagerank_alg.py +++ /dev/null @@ -1,500 +0,0 @@ -"""PageRank analysis of graph structure.""" - -from warnings import warn - -import networkx as nx - -__all__ = ["pagerank", "google_matrix"] - - -@nx._dispatchable(edge_attrs="weight") -def pagerank( - G, - alpha=0.85, - personalization=None, - max_iter=100, - tol=1.0e-6, - nstart=None, - weight="weight", - dangling=None, -): - """Returns the PageRank of the nodes in the graph. - - PageRank computes a ranking of the nodes in the graph G based on - the structure of the incoming links. It was originally designed as - an algorithm to rank web pages. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float, optional - Damping parameter for PageRank, default=0.85. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specified, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - max_iter : integer, optional - Maximum number of iterations in power method eigenvalue solver. - - tol : float, optional - Error tolerance used to check convergence in power method solver. - The iteration will stop after a tolerance of ``len(G) * tol`` is reached. - - nstart : dictionary, optional - Starting value of PageRank iteration for each node. - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified). This must be selected to result in an irreducible transition - matrix (see notes under google_matrix). It may be common to have the - dangling dict to be the same as the personalization dict. - - - Returns - ------- - pagerank : dictionary - Dictionary of nodes with PageRank as value - - Examples - -------- - >>> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = nx.pagerank(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop after - an error tolerance of ``len(G) * tol`` has been reached. If the - number of iterations exceed `max_iter`, a - :exc:`networkx.exception.PowerIterationFailedConvergence` exception - is raised. - - The PageRank algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs by converting each edge in the - directed graph to two edges. - - See Also - -------- - google_matrix - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - - """ - return _pagerank_scipy( - G, alpha, personalization, max_iter, tol, nstart, weight, dangling - ) - - -def _pagerank_python( - G, - alpha=0.85, - personalization=None, - max_iter=100, - tol=1.0e-6, - nstart=None, - weight="weight", - dangling=None, -): - if len(G) == 0: - return {} - - D = G.to_directed() - - # Create a copy in (right) stochastic form - W = nx.stochastic_graph(D, weight=weight) - N = W.number_of_nodes() - - # Choose fixed starting vector if not given - if nstart is None: - x = dict.fromkeys(W, 1.0 / N) - else: - # Normalized nstart vector - s = sum(nstart.values()) - x = {k: v / s for k, v in nstart.items()} - - if personalization is None: - # Assign uniform personalization vector if not given - p = dict.fromkeys(W, 1.0 / N) - else: - s = sum(personalization.values()) - p = {k: v / s for k, v in personalization.items()} - - if dangling is None: - # Use personalization vector if dangling vector not specified - dangling_weights = p - else: - s = sum(dangling.values()) - dangling_weights = {k: v / s for k, v in dangling.items()} - dangling_nodes = [n for n in W if W.out_degree(n, weight=weight) == 0.0] - - # power iteration: make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = dict.fromkeys(xlast.keys(), 0) - danglesum = alpha * sum(xlast[n] for n in dangling_nodes) - for n in x: - # this matrix multiply looks odd because it is - # doing a left multiply x^T=xlast^T*W - for _, nbr, wt in W.edges(n, data=weight): - x[nbr] += alpha * xlast[n] * wt - x[n] += danglesum * dangling_weights.get(n, 0) + (1.0 - alpha) * p.get(n, 0) - # check convergence, l1 norm - err = sum(abs(x[n] - xlast[n]) for n in x) - if err < N * tol: - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -@nx._dispatchable(edge_attrs="weight") -def google_matrix( - G, alpha=0.85, personalization=None, nodelist=None, weight="weight", dangling=None -): - """Returns the Google matrix of the graph. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float - The damping factor. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specified, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes below). It may be common to have the dangling dict to - be the same as the personalization dict. - - Returns - ------- - A : 2D NumPy ndarray - Google matrix of the graph - - Notes - ----- - The array returned represents the transition matrix that describes the - Markov chain used in PageRank. For PageRank to converge to a unique - solution (i.e., a unique stationary distribution in a Markov chain), the - transition matrix must be irreducible. In other words, it must be that - there exists a path between every pair of nodes in the graph, or else there - is the potential of "rank sinks." - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - - A = nx.to_numpy_array(G, nodelist=nodelist, weight=weight) - N = len(G) - if N == 0: - return A - - # Personalization vector - if personalization is None: - p = np.repeat(1.0 / N, N) - else: - p = np.array([personalization.get(n, 0) for n in nodelist], dtype=float) - if p.sum() == 0: - raise ZeroDivisionError - p /= p.sum() - - # Dangling nodes - if dangling is None: - dangling_weights = p - else: - # Convert the dangling dictionary into an array in nodelist order - dangling_weights = np.array([dangling.get(n, 0) for n in nodelist], dtype=float) - dangling_weights /= dangling_weights.sum() - dangling_nodes = np.where(A.sum(axis=1) == 0)[0] - - # Assign dangling_weights to any dangling nodes (nodes with no out links) - A[dangling_nodes] = dangling_weights - - A /= A.sum(axis=1)[:, np.newaxis] # Normalize rows to sum to 1 - - return alpha * A + (1 - alpha) * p - - -def _pagerank_numpy( - G, alpha=0.85, personalization=None, weight="weight", dangling=None -): - """Returns the PageRank of the nodes in the graph. - - PageRank computes a ranking of the nodes in the graph G based on - the structure of the incoming links. It was originally designed as - an algorithm to rank web pages. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float, optional - Damping parameter for PageRank, default=0.85. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specified, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes under google_matrix). It may be common to have the - dangling dict to be the same as the personalization dict. - - Returns - ------- - pagerank : dictionary - Dictionary of nodes with PageRank as value. - - Examples - -------- - >>> from networkx.algorithms.link_analysis.pagerank_alg import _pagerank_numpy - >>> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = _pagerank_numpy(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation uses NumPy's interface to the LAPACK - eigenvalue solvers. This will be the fastest and most accurate - for small graphs. - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank, google_matrix - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - """ - import numpy as np - - if len(G) == 0: - return {} - M = google_matrix( - G, alpha, personalization=personalization, weight=weight, dangling=dangling - ) - # use numpy LAPACK solver - eigenvalues, eigenvectors = np.linalg.eig(M.T) - ind = np.argmax(eigenvalues) - # eigenvector of largest eigenvalue is at ind, normalized - largest = np.array(eigenvectors[:, ind]).flatten().real - norm = largest.sum() - return dict(zip(G, map(float, largest / norm))) - - -def _pagerank_scipy( - G, - alpha=0.85, - personalization=None, - max_iter=100, - tol=1.0e-6, - nstart=None, - weight="weight", - dangling=None, -): - """Returns the PageRank of the nodes in the graph. - - PageRank computes a ranking of the nodes in the graph G based on - the structure of the incoming links. It was originally designed as - an algorithm to rank web pages. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float, optional - Damping parameter for PageRank, default=0.85. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specified, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - max_iter : integer, optional - Maximum number of iterations in power method eigenvalue solver. - - tol : float, optional - Error tolerance used to check convergence in power method solver. - The iteration will stop after a tolerance of ``len(G) * tol`` is reached. - - nstart : dictionary, optional - Starting value of PageRank iteration for each node. - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes under google_matrix). It may be common to have the - dangling dict to be the same as the personalization dict. - - Returns - ------- - pagerank : dictionary - Dictionary of nodes with PageRank as value - - Examples - -------- - >>> from networkx.algorithms.link_analysis.pagerank_alg import _pagerank_scipy - >>> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = _pagerank_scipy(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation uses power iteration with a SciPy - sparse matrix representation. - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - """ - import numpy as np - import scipy as sp - - N = len(G) - if N == 0: - return {} - - nodelist = list(G) - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, dtype=float) - S = A.sum(axis=1) - S[S != 0] = 1.0 / S[S != 0] - # TODO: csr_array - Q = sp.sparse.csr_array(sp.sparse.spdiags(S.T, 0, *A.shape)) - A = Q @ A - - # initial vector - if nstart is None: - x = np.repeat(1.0 / N, N) - else: - x = np.array([nstart.get(n, 0) for n in nodelist], dtype=float) - x /= x.sum() - - # Personalization vector - if personalization is None: - p = np.repeat(1.0 / N, N) - else: - p = np.array([personalization.get(n, 0) for n in nodelist], dtype=float) - if p.sum() == 0: - raise ZeroDivisionError - p /= p.sum() - # Dangling nodes - if dangling is None: - dangling_weights = p - else: - # Convert the dangling dictionary into an array in nodelist order - dangling_weights = np.array([dangling.get(n, 0) for n in nodelist], dtype=float) - dangling_weights /= dangling_weights.sum() - is_dangling = np.where(S == 0)[0] - - # power iteration: make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = alpha * (x @ A + sum(x[is_dangling]) * dangling_weights) + (1 - alpha) * p - # check convergence, l1 norm - err = np.absolute(x - xlast).sum() - if err < N * tol: - return dict(zip(nodelist, map(float, x))) - raise nx.PowerIterationFailedConvergence(max_iter) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_hits.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_hits.py deleted file mode 100644 index 54713eb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_hits.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest - -import networkx as nx - -np = pytest.importorskip("numpy") -sp = pytest.importorskip("scipy") - -from networkx.algorithms.link_analysis.hits_alg import ( - _hits_numpy, - _hits_python, - _hits_scipy, -) - -# Example from -# A. Langville and C. Meyer, "A survey of eigenvector methods of web -# information retrieval." http://citeseer.ist.psu.edu/713792.html - - -class TestHITS: - @classmethod - def setup_class(cls): - G = nx.DiGraph() - - edges = [(1, 3), (1, 5), (2, 1), (3, 5), (5, 4), (5, 3), (6, 5)] - - G.add_edges_from(edges, weight=1) - cls.G = G - cls.G.a = dict( - zip(sorted(G), [0.000000, 0.000000, 0.366025, 0.133975, 0.500000, 0.000000]) - ) - cls.G.h = dict( - zip(sorted(G), [0.366025, 0.000000, 0.211325, 0.000000, 0.211325, 0.211325]) - ) - - def test_hits_numpy(self): - G = self.G - h, a = _hits_numpy(G) - for n in G: - assert h[n] == pytest.approx(G.h[n], abs=1e-4) - for n in G: - assert a[n] == pytest.approx(G.a[n], abs=1e-4) - - @pytest.mark.parametrize("hits_alg", (nx.hits, _hits_python, _hits_scipy)) - def test_hits(self, hits_alg): - G = self.G - h, a = hits_alg(G, tol=1.0e-08) - for n in G: - assert h[n] == pytest.approx(G.h[n], abs=1e-4) - for n in G: - assert a[n] == pytest.approx(G.a[n], abs=1e-4) - nstart = {i: 1.0 / 2 for i in G} - h, a = hits_alg(G, nstart=nstart) - for n in G: - assert h[n] == pytest.approx(G.h[n], abs=1e-4) - for n in G: - assert a[n] == pytest.approx(G.a[n], abs=1e-4) - - def test_empty(self): - G = nx.Graph() - assert nx.hits(G) == ({}, {}) - assert _hits_numpy(G) == ({}, {}) - assert _hits_python(G) == ({}, {}) - assert _hits_scipy(G) == ({}, {}) - - def test_hits_not_convergent(self): - G = nx.path_graph(50) - with pytest.raises(nx.PowerIterationFailedConvergence): - _hits_scipy(G, max_iter=1) - with pytest.raises(nx.PowerIterationFailedConvergence): - _hits_python(G, max_iter=1) - with pytest.raises(nx.PowerIterationFailedConvergence): - _hits_scipy(G, max_iter=0) - with pytest.raises(nx.PowerIterationFailedConvergence): - _hits_python(G, max_iter=0) - with pytest.raises(nx.PowerIterationFailedConvergence): - nx.hits(G, max_iter=0) - with pytest.raises(nx.PowerIterationFailedConvergence): - nx.hits(G, max_iter=1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_pagerank.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_pagerank.py deleted file mode 100644 index 44038fd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_analysis/tests/test_pagerank.py +++ /dev/null @@ -1,214 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx.classes.tests import dispatch_interface - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -from networkx.algorithms.link_analysis.pagerank_alg import ( - _pagerank_numpy, - _pagerank_python, - _pagerank_scipy, -) - -# Example from -# A. Langville and C. Meyer, "A survey of eigenvector methods of web -# information retrieval." http://citeseer.ist.psu.edu/713792.html - - -class TestPageRank: - @classmethod - def setup_class(cls): - G = nx.DiGraph() - edges = [ - (1, 2), - (1, 3), - # 2 is a dangling node - (3, 1), - (3, 2), - (3, 5), - (4, 5), - (4, 6), - (5, 4), - (5, 6), - (6, 4), - ] - G.add_edges_from(edges) - cls.G = G - cls.G.pagerank = dict( - zip( - sorted(G), - [ - 0.03721197, - 0.05395735, - 0.04150565, - 0.37508082, - 0.20599833, - 0.28624589, - ], - ) - ) - cls.dangling_node_index = 1 - cls.dangling_edges = {1: 2, 2: 3, 3: 0, 4: 0, 5: 0, 6: 0} - cls.G.dangling_pagerank = dict( - zip( - sorted(G), - [0.10844518, 0.18618601, 0.0710892, 0.2683668, 0.15919783, 0.20671497], - ) - ) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python)) - def test_pagerank(self, alg): - G = self.G - p = alg(G, alpha=0.9, tol=1.0e-08) - for n in G: - assert p[n] == pytest.approx(G.pagerank[n], abs=1e-4) - - nstart = {n: random.random() for n in G} - p = alg(G, alpha=0.9, tol=1.0e-08, nstart=nstart) - for n in G: - assert p[n] == pytest.approx(G.pagerank[n], abs=1e-4) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python)) - def test_pagerank_max_iter(self, alg): - with pytest.raises(nx.PowerIterationFailedConvergence): - alg(self.G, max_iter=0) - - def test_numpy_pagerank(self): - G = self.G - p = _pagerank_numpy(G, alpha=0.9) - for n in G: - assert p[n] == pytest.approx(G.pagerank[n], abs=1e-4) - - def test_google_matrix(self): - G = self.G - M = nx.google_matrix(G, alpha=0.9, nodelist=sorted(G)) - _, ev = np.linalg.eig(M.T) - p = ev[:, 0] / ev[:, 0].sum() - for a, b in zip(p, self.G.pagerank.values()): - assert a == pytest.approx(b, abs=1e-7) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python, _pagerank_numpy)) - def test_personalization(self, alg): - G = nx.complete_graph(4) - personalize = {0: 1, 1: 1, 2: 4, 3: 4} - answer = { - 0: 0.23246732615667579, - 1: 0.23246732615667579, - 2: 0.267532673843324, - 3: 0.2675326738433241, - } - p = alg(G, alpha=0.85, personalization=personalize) - for n in G: - assert p[n] == pytest.approx(answer[n], abs=1e-4) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python, nx.google_matrix)) - def test_zero_personalization_vector(self, alg): - G = nx.complete_graph(4) - personalize = {0: 0, 1: 0, 2: 0, 3: 0} - pytest.raises(ZeroDivisionError, alg, G, personalization=personalize) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python)) - def test_one_nonzero_personalization_value(self, alg): - G = nx.complete_graph(4) - personalize = {0: 0, 1: 0, 2: 0, 3: 1} - answer = { - 0: 0.22077931820379187, - 1: 0.22077931820379187, - 2: 0.22077931820379187, - 3: 0.3376620453886241, - } - p = alg(G, alpha=0.85, personalization=personalize) - for n in G: - assert p[n] == pytest.approx(answer[n], abs=1e-4) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python)) - def test_incomplete_personalization(self, alg): - G = nx.complete_graph(4) - personalize = {3: 1} - answer = { - 0: 0.22077931820379187, - 1: 0.22077931820379187, - 2: 0.22077931820379187, - 3: 0.3376620453886241, - } - p = alg(G, alpha=0.85, personalization=personalize) - for n in G: - assert p[n] == pytest.approx(answer[n], abs=1e-4) - - def test_dangling_matrix(self): - """ - Tests that the google_matrix doesn't change except for the dangling - nodes. - """ - G = self.G - dangling = self.dangling_edges - dangling_sum = sum(dangling.values()) - M1 = nx.google_matrix(G, personalization=dangling) - M2 = nx.google_matrix(G, personalization=dangling, dangling=dangling) - for i in range(len(G)): - for j in range(len(G)): - if i == self.dangling_node_index and (j + 1) in dangling: - assert M2[i, j] == pytest.approx( - dangling[j + 1] / dangling_sum, abs=1e-4 - ) - else: - assert M2[i, j] == pytest.approx(M1[i, j], abs=1e-4) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python, _pagerank_numpy)) - def test_dangling_pagerank(self, alg): - pr = alg(self.G, dangling=self.dangling_edges) - for n in self.G: - assert pr[n] == pytest.approx(self.G.dangling_pagerank[n], abs=1e-4) - - def test_empty(self): - G = nx.Graph() - assert nx.pagerank(G) == {} - assert _pagerank_python(G) == {} - assert _pagerank_numpy(G) == {} - assert nx.google_matrix(G).shape == (0, 0) - - @pytest.mark.parametrize("alg", (nx.pagerank, _pagerank_python)) - def test_multigraph(self, alg): - G = nx.MultiGraph() - G.add_edges_from([(1, 2), (1, 2), (1, 2), (2, 3), (2, 3), ("3", 3), ("3", 3)]) - answer = { - 1: 0.21066048614468322, - 2: 0.3395308825985378, - 3: 0.28933951385531687, - "3": 0.16046911740146227, - } - p = alg(G) - for n in G: - assert p[n] == pytest.approx(answer[n], abs=1e-4) - - -class TestPageRankScipy(TestPageRank): - def test_scipy_pagerank(self): - G = self.G - p = _pagerank_scipy(G, alpha=0.9, tol=1.0e-08) - for n in G: - assert p[n] == pytest.approx(G.pagerank[n], abs=1e-4) - personalize = {n: random.random() for n in G} - p = _pagerank_scipy(G, alpha=0.9, tol=1.0e-08, personalization=personalize) - - nstart = {n: random.random() for n in G} - p = _pagerank_scipy(G, alpha=0.9, tol=1.0e-08, nstart=nstart) - for n in G: - assert p[n] == pytest.approx(G.pagerank[n], abs=1e-4) - - def test_scipy_pagerank_max_iter(self): - with pytest.raises(nx.PowerIterationFailedConvergence): - _pagerank_scipy(self.G, max_iter=0) - - def test_dangling_scipy_pagerank(self): - pr = _pagerank_scipy(self.G, dangling=self.dangling_edges) - for n in self.G: - assert pr[n] == pytest.approx(self.G.dangling_pagerank[n], abs=1e-4) - - def test_empty_scipy(self): - G = nx.Graph() - assert _pagerank_scipy(G) == {} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_prediction.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_prediction.py deleted file mode 100644 index 3615f26..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/link_prediction.py +++ /dev/null @@ -1,687 +0,0 @@ -""" -Link prediction algorithms. -""" - -from math import log - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "resource_allocation_index", - "jaccard_coefficient", - "adamic_adar_index", - "preferential_attachment", - "cn_soundarajan_hopcroft", - "ra_index_soundarajan_hopcroft", - "within_inter_cluster", - "common_neighbor_centrality", -] - - -def _apply_prediction(G, func, ebunch=None): - """Applies the given function to each edge in the specified iterable - of edges. - - `G` is an instance of :class:`networkx.Graph`. - - `func` is a function on two inputs, each of which is a node in the - graph. The function can return anything, but it should return a - value representing a prediction of the likelihood of a "link" - joining the two nodes. - - `ebunch` is an iterable of pairs of nodes. If not specified, all - non-edges in the graph `G` will be used. - - """ - if ebunch is None: - ebunch = nx.non_edges(G) - else: - for u, v in ebunch: - if u not in G: - raise nx.NodeNotFound(f"Node {u} not in G.") - if v not in G: - raise nx.NodeNotFound(f"Node {v} not in G.") - return ((u, v, func(u, v)) for u, v in ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def resource_allocation_index(G, ebunch=None): - r"""Compute the resource allocation index of all node pairs in ebunch. - - Resource allocation index of `u` and `v` is defined as - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{1}{|\Gamma(w)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Resource allocation index will be computed for each pair of - nodes given in the iterable. The pairs must be given as - 2-tuples (u, v) where u and v are nodes in the graph. If ebunch - is None then all nonexistent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their resource allocation index. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> preds = nx.resource_allocation_index(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 1) -> 0.75000000 - (2, 3) -> 0.75000000 - - References - ---------- - .. [1] T. Zhou, L. Lu, Y.-C. Zhang. - Predicting missing links via local information. - Eur. Phys. J. B 71 (2009) 623. - https://arxiv.org/pdf/0901.0553.pdf - """ - - def predict(u, v): - return sum(1 / G.degree(w) for w in nx.common_neighbors(G, u, v)) - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def jaccard_coefficient(G, ebunch=None): - r"""Compute the Jaccard coefficient of all node pairs in ebunch. - - Jaccard coefficient of nodes `u` and `v` is defined as - - .. math:: - - \frac{|\Gamma(u) \cap \Gamma(v)|}{|\Gamma(u) \cup \Gamma(v)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Jaccard coefficient will be computed for each pair of nodes - given in the iterable. The pairs must be given as 2-tuples - (u, v) where u and v are nodes in the graph. If ebunch is None - then all nonexistent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their Jaccard coefficient. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> preds = nx.jaccard_coefficient(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 1) -> 0.60000000 - (2, 3) -> 0.60000000 - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - - def predict(u, v): - union_size = len(set(G[u]) | set(G[v])) - if union_size == 0: - return 0 - return len(nx.common_neighbors(G, u, v)) / union_size - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def adamic_adar_index(G, ebunch=None): - r"""Compute the Adamic-Adar index of all node pairs in ebunch. - - Adamic-Adar index of `u` and `v` is defined as - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{1}{\log |\Gamma(w)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - This index leads to zero-division for nodes only connected via self-loops. - It is intended to be used when no self-loops are present. - - Parameters - ---------- - G : graph - NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Adamic-Adar index will be computed for each pair of nodes given - in the iterable. The pairs must be given as 2-tuples (u, v) - where u and v are nodes in the graph. If ebunch is None then all - nonexistent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their Adamic-Adar index. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> preds = nx.adamic_adar_index(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 1) -> 2.16404256 - (2, 3) -> 2.16404256 - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - - def predict(u, v): - return sum(1 / log(G.degree(w)) for w in nx.common_neighbors(G, u, v)) - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def common_neighbor_centrality(G, ebunch=None, alpha=0.8): - r"""Return the CCPA score for each pair of nodes. - - Compute the Common Neighbor and Centrality based Parameterized Algorithm(CCPA) - score of all node pairs in ebunch. - - CCPA score of `u` and `v` is defined as - - .. math:: - - \alpha \cdot (|\Gamma (u){\cap }^{}\Gamma (v)|)+(1-\alpha )\cdot \frac{N}{{d}_{uv}} - - where $\Gamma(u)$ denotes the set of neighbors of $u$, $\Gamma(v)$ denotes the - set of neighbors of $v$, $\alpha$ is parameter varies between [0,1], $N$ denotes - total number of nodes in the Graph and ${d}_{uv}$ denotes shortest distance - between $u$ and $v$. - - This algorithm is based on two vital properties of nodes, namely the number - of common neighbors and their centrality. Common neighbor refers to the common - nodes between two nodes. Centrality refers to the prestige that a node enjoys - in a network. - - .. seealso:: - - :func:`common_neighbors` - - Parameters - ---------- - G : graph - NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Preferential attachment score will be computed for each pair of - nodes given in the iterable. The pairs must be given as - 2-tuples (u, v) where u and v are nodes in the graph. If ebunch - is None then all nonexistent edges in the graph will be used. - Default value: None. - - alpha : Parameter defined for participation of Common Neighbor - and Centrality Algorithm share. Values for alpha should - normally be between 0 and 1. Default value set to 0.8 - because author found better performance at 0.8 for all the - dataset. - Default value: 0.8 - - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their Common Neighbor and Centrality based - Parameterized Algorithm(CCPA) score. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NetworkXAlgorithmError - If self loops exist in `ebunch` or in `G` (if `ebunch` is `None`). - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> preds = nx.common_neighbor_centrality(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p}") - (0, 1) -> 3.4000000000000004 - (2, 3) -> 3.4000000000000004 - - References - ---------- - .. [1] Ahmad, I., Akhtar, M.U., Noor, S. et al. - Missing Link Prediction using Common Neighbor and Centrality based Parameterized Algorithm. - Sci Rep 10, 364 (2020). - https://doi.org/10.1038/s41598-019-57304-y - """ - - # When alpha == 1, the CCPA score simplifies to the number of common neighbors. - if alpha == 1: - - def predict(u, v): - if u == v: - raise nx.NetworkXAlgorithmError("Self loops are not supported") - - return len(nx.common_neighbors(G, u, v)) - - else: - spl = dict(nx.shortest_path_length(G)) - inf = float("inf") - - def predict(u, v): - if u == v: - raise nx.NetworkXAlgorithmError("Self loops are not supported") - path_len = spl[u].get(v, inf) - - n_nbrs = len(nx.common_neighbors(G, u, v)) - return alpha * n_nbrs + (1 - alpha) * len(G) / path_len - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def preferential_attachment(G, ebunch=None): - r"""Compute the preferential attachment score of all node pairs in ebunch. - - Preferential attachment score of `u` and `v` is defined as - - .. math:: - - |\Gamma(u)| |\Gamma(v)| - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Preferential attachment score will be computed for each pair of - nodes given in the iterable. The pairs must be given as - 2-tuples (u, v) where u and v are nodes in the graph. If ebunch - is None then all nonexistent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their preferential attachment score. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> preds = nx.preferential_attachment(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p}") - (0, 1) -> 16 - (2, 3) -> 16 - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - - def predict(u, v): - return G.degree(u) * G.degree(v) - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(node_attrs="community") -def cn_soundarajan_hopcroft(G, ebunch=None, community="community"): - r"""Count the number of common neighbors of all node pairs in ebunch - using community information. - - For two nodes $u$ and $v$, this function computes the number of - common neighbors and bonus one for each common neighbor belonging to - the same community as $u$ and $v$. Mathematically, - - .. math:: - - |\Gamma(u) \cap \Gamma(v)| + \sum_{w \in \Gamma(u) \cap \Gamma(v)} f(w) - - where $f(w)$ equals 1 if $w$ belongs to the same community as $u$ - and $v$ or 0 otherwise and $\Gamma(u)$ denotes the set of - neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The score will be computed for each pair of nodes given in the - iterable. The pairs must be given as 2-tuples (u, v) where u - and v are nodes in the graph. If ebunch is None then all - nonexistent edges in the graph will be used. - Default value: None. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their score. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NetworkXAlgorithmError - If no community information is available for a node in `ebunch` or in `G` (if `ebunch` is `None`). - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> G.nodes[0]["community"] = 0 - >>> G.nodes[1]["community"] = 0 - >>> G.nodes[2]["community"] = 0 - >>> preds = nx.cn_soundarajan_hopcroft(G, [(0, 2)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p}") - (0, 2) -> 2 - - References - ---------- - .. [1] Sucheta Soundarajan and John Hopcroft. - Using community information to improve the precision of link - prediction methods. - In Proceedings of the 21st international conference companion on - World Wide Web (WWW '12 Companion). ACM, New York, NY, USA, 607-608. - http://doi.acm.org/10.1145/2187980.2188150 - """ - - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - cnbors = nx.common_neighbors(G, u, v) - neighbors = ( - sum(_community(G, w, community) == Cu for w in cnbors) if Cu == Cv else 0 - ) - return len(cnbors) + neighbors - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(node_attrs="community") -def ra_index_soundarajan_hopcroft(G, ebunch=None, community="community"): - r"""Compute the resource allocation index of all node pairs in - ebunch using community information. - - For two nodes $u$ and $v$, this function computes the resource - allocation index considering only common neighbors belonging to the - same community as $u$ and $v$. Mathematically, - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{f(w)}{|\Gamma(w)|} - - where $f(w)$ equals 1 if $w$ belongs to the same community as $u$ - and $v$ or 0 otherwise and $\Gamma(u)$ denotes the set of - neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The score will be computed for each pair of nodes given in the - iterable. The pairs must be given as 2-tuples (u, v) where u - and v are nodes in the graph. If ebunch is None then all - nonexistent edges in the graph will be used. - Default value: None. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their score. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NetworkXAlgorithmError - If no community information is available for a node in `ebunch` or in `G` (if `ebunch` is `None`). - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - >>> G.nodes[0]["community"] = 0 - >>> G.nodes[1]["community"] = 0 - >>> G.nodes[2]["community"] = 1 - >>> G.nodes[3]["community"] = 0 - >>> preds = nx.ra_index_soundarajan_hopcroft(G, [(0, 3)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 3) -> 0.50000000 - - References - ---------- - .. [1] Sucheta Soundarajan and John Hopcroft. - Using community information to improve the precision of link - prediction methods. - In Proceedings of the 21st international conference companion on - World Wide Web (WWW '12 Companion). ACM, New York, NY, USA, 607-608. - http://doi.acm.org/10.1145/2187980.2188150 - """ - - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - if Cu != Cv: - return 0 - cnbors = nx.common_neighbors(G, u, v) - return sum(1 / G.degree(w) for w in cnbors if _community(G, w, community) == Cu) - - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(node_attrs="community") -def within_inter_cluster(G, ebunch=None, delta=0.001, community="community"): - """Compute the ratio of within- and inter-cluster common neighbors - of all node pairs in ebunch. - - For two nodes `u` and `v`, if a common neighbor `w` belongs to the - same community as them, `w` is considered as within-cluster common - neighbor of `u` and `v`. Otherwise, it is considered as - inter-cluster common neighbor of `u` and `v`. The ratio between the - size of the set of within- and inter-cluster common neighbors is - defined as the WIC measure. [1]_ - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The WIC measure will be computed for each pair of nodes given in - the iterable. The pairs must be given as 2-tuples (u, v) where - u and v are nodes in the graph. If ebunch is None then all - nonexistent edges in the graph will be used. - Default value: None. - - delta : float, optional (default = 0.001) - Value to prevent division by zero in case there is no - inter-cluster common neighbor between two nodes. See [1]_ for - details. Default value: 0.001. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their WIC measure. - - Raises - ------ - NetworkXNotImplemented - If `G` is a `DiGraph`, a `Multigraph` or a `MultiDiGraph`. - - NetworkXAlgorithmError - - If `delta` is less than or equal to zero. - - If no community information is available for a node in `ebunch` or in `G` (if `ebunch` is `None`). - - NodeNotFound - If `ebunch` has a node that is not in `G`. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 4), (2, 4), (3, 4)]) - >>> G.nodes[0]["community"] = 0 - >>> G.nodes[1]["community"] = 1 - >>> G.nodes[2]["community"] = 0 - >>> G.nodes[3]["community"] = 0 - >>> G.nodes[4]["community"] = 0 - >>> preds = nx.within_inter_cluster(G, [(0, 4)]) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 4) -> 1.99800200 - >>> preds = nx.within_inter_cluster(G, [(0, 4)], delta=0.5) - >>> for u, v, p in preds: - ... print(f"({u}, {v}) -> {p:.8f}") - (0, 4) -> 1.33333333 - - References - ---------- - .. [1] Jorge Carlos Valverde-Rebaza and Alneu de Andrade Lopes. - Link prediction in complex networks based on cluster information. - In Proceedings of the 21st Brazilian conference on Advances in - Artificial Intelligence (SBIA'12) - https://doi.org/10.1007/978-3-642-34459-6_10 - """ - if delta <= 0: - raise nx.NetworkXAlgorithmError("Delta must be greater than zero") - - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - if Cu != Cv: - return 0 - cnbors = nx.common_neighbors(G, u, v) - within = {w for w in cnbors if _community(G, w, community) == Cu} - inter = cnbors - within - return len(within) / (len(inter) + delta) - - return _apply_prediction(G, predict, ebunch) - - -def _community(G, u, community): - """Get the community of the given node.""" - node_u = G.nodes[u] - try: - return node_u[community] - except KeyError as err: - raise nx.NetworkXAlgorithmError( - f"No community information available for Node {u}" - ) from err diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/lowest_common_ancestors.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/lowest_common_ancestors.py deleted file mode 100644 index d580018..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/lowest_common_ancestors.py +++ /dev/null @@ -1,269 +0,0 @@ -"""Algorithms for finding the lowest common ancestor of trees and DAGs.""" - -from collections import defaultdict -from collections.abc import Mapping, Set -from itertools import combinations_with_replacement - -import networkx as nx -from networkx.utils import UnionFind, arbitrary_element, not_implemented_for - -__all__ = [ - "all_pairs_lowest_common_ancestor", - "tree_all_pairs_lowest_common_ancestor", - "lowest_common_ancestor", -] - - -@not_implemented_for("undirected") -@nx._dispatchable -def all_pairs_lowest_common_ancestor(G, pairs=None): - """Return the lowest common ancestor of all pairs or the provided pairs - - Parameters - ---------- - G : NetworkX directed graph - - pairs : iterable of pairs of nodes, optional (default: all pairs) - The pairs of nodes of interest. - If None, will find the LCA of all pairs of nodes. - - Yields - ------ - ((node1, node2), lca) : 2-tuple - Where lca is least common ancestor of node1 and node2. - Note that for the default case, the order of the node pair is not considered, - e.g. you will not get both ``(a, b)`` and ``(b, a)`` - - Raises - ------ - NetworkXPointlessConcept - If `G` is null. - NetworkXError - If `G` is not a DAG. - - Examples - -------- - The default behavior is to yield the lowest common ancestor for all - possible combinations of nodes in `G`, including self-pairings: - - >>> G = nx.DiGraph([(0, 1), (0, 3), (1, 2)]) - >>> dict(nx.all_pairs_lowest_common_ancestor(G)) - {(0, 0): 0, (0, 1): 0, (0, 3): 0, (0, 2): 0, (1, 1): 1, (1, 3): 0, (1, 2): 1, (3, 3): 3, (3, 2): 0, (2, 2): 2} - - The pairs argument can be used to limit the output to only the - specified node pairings: - - >>> dict(nx.all_pairs_lowest_common_ancestor(G, pairs=[(1, 2), (2, 3)])) - {(1, 2): 1, (2, 3): 0} - - Notes - ----- - Only defined on non-null directed acyclic graphs. - - See Also - -------- - lowest_common_ancestor - """ - if not nx.is_directed_acyclic_graph(G): - raise nx.NetworkXError("LCA only defined on directed acyclic graphs.") - if len(G) == 0: - raise nx.NetworkXPointlessConcept("LCA meaningless on null graphs.") - - if pairs is None: - pairs = combinations_with_replacement(G, 2) - else: - # Convert iterator to iterable, if necessary. Trim duplicates. - pairs = dict.fromkeys(pairs) - # Verify that each of the nodes in the provided pairs is in G - nodeset = set(G) - for pair in pairs: - if set(pair) - nodeset: - raise nx.NodeNotFound( - f"Node(s) {set(pair) - nodeset} from pair {pair} not in G." - ) - - # Once input validation is done, construct the generator - def generate_lca_from_pairs(G, pairs): - ancestor_cache = {} - - for v, w in pairs: - if v not in ancestor_cache: - ancestor_cache[v] = nx.ancestors(G, v) - ancestor_cache[v].add(v) - if w not in ancestor_cache: - ancestor_cache[w] = nx.ancestors(G, w) - ancestor_cache[w].add(w) - - common_ancestors = ancestor_cache[v] & ancestor_cache[w] - - if common_ancestors: - common_ancestor = next(iter(common_ancestors)) - while True: - successor = None - for lower_ancestor in G.successors(common_ancestor): - if lower_ancestor in common_ancestors: - successor = lower_ancestor - break - if successor is None: - break - common_ancestor = successor - yield ((v, w), common_ancestor) - - return generate_lca_from_pairs(G, pairs) - - -@not_implemented_for("undirected") -@nx._dispatchable -def lowest_common_ancestor(G, node1, node2, default=None): - """Compute the lowest common ancestor of the given pair of nodes. - - Parameters - ---------- - G : NetworkX directed graph - - node1, node2 : nodes in the graph. - - default : object - Returned if no common ancestor between `node1` and `node2` - - Returns - ------- - The lowest common ancestor of node1 and node2, - or default if they have no common ancestors. - - Examples - -------- - >>> G = nx.DiGraph() - >>> nx.add_path(G, (0, 1, 2, 3)) - >>> nx.add_path(G, (0, 4, 3)) - >>> nx.lowest_common_ancestor(G, 2, 4) - 0 - - See Also - -------- - all_pairs_lowest_common_ancestor""" - - ans = list(all_pairs_lowest_common_ancestor(G, pairs=[(node1, node2)])) - if ans: - assert len(ans) == 1 - return ans[0][1] - return default - - -@not_implemented_for("undirected") -@nx._dispatchable -def tree_all_pairs_lowest_common_ancestor(G, root=None, pairs=None): - r"""Yield the lowest common ancestor for sets of pairs in a tree. - - Parameters - ---------- - G : NetworkX directed graph (must be a tree) - - root : node, optional (default: None) - The root of the subtree to operate on. - If None, assume the entire graph has exactly one source and use that. - - pairs : iterable or iterator of pairs of nodes, optional (default: None) - The pairs of interest. If None, Defaults to all pairs of nodes - under `root` that have a lowest common ancestor. - - Returns - ------- - lcas : generator of tuples `((u, v), lca)` where `u` and `v` are nodes - in `pairs` and `lca` is their lowest common ancestor. - - Examples - -------- - >>> import pprint - >>> G = nx.DiGraph([(1, 3), (2, 4), (1, 2)]) - >>> pprint.pprint(dict(nx.tree_all_pairs_lowest_common_ancestor(G))) - {(1, 1): 1, - (2, 1): 1, - (2, 2): 2, - (3, 1): 1, - (3, 2): 1, - (3, 3): 3, - (3, 4): 1, - (4, 1): 1, - (4, 2): 2, - (4, 4): 4} - - We can also use `pairs` argument to specify the pairs of nodes for which we - want to compute lowest common ancestors. Here is an example: - - >>> dict(nx.tree_all_pairs_lowest_common_ancestor(G, pairs=[(1, 4), (2, 3)])) - {(2, 3): 1, (1, 4): 1} - - Notes - ----- - Only defined on non-null trees represented with directed edges from - parents to children. Uses Tarjan's off-line lowest-common-ancestors - algorithm. Runs in time $O(4 \times (V + E + P))$ time, where 4 is the largest - value of the inverse Ackermann function likely to ever come up in actual - use, and $P$ is the number of pairs requested (or $V^2$ if all are needed). - - Tarjan, R. E. (1979), "Applications of path compression on balanced trees", - Journal of the ACM 26 (4): 690-715, doi:10.1145/322154.322161. - - See Also - -------- - all_pairs_lowest_common_ancestor: similar routine for general DAGs - lowest_common_ancestor: just a single pair for general DAGs - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept("LCA meaningless on null graphs.") - - # Index pairs of interest for efficient lookup from either side. - if pairs is not None: - pair_dict = defaultdict(set) - # See note on all_pairs_lowest_common_ancestor. - if not isinstance(pairs, Mapping | Set): - pairs = set(pairs) - for u, v in pairs: - for n in (u, v): - if n not in G: - msg = f"The node {str(n)} is not in the digraph." - raise nx.NodeNotFound(msg) - pair_dict[u].add(v) - pair_dict[v].add(u) - - # If root is not specified, find the exactly one node with in degree 0 and - # use it. Raise an error if none are found, or more than one is. Also check - # for any nodes with in degree larger than 1, which would imply G is not a - # tree. - if root is None: - for n, deg in G.in_degree: - if deg == 0: - if root is not None: - msg = "No root specified and tree has multiple sources." - raise nx.NetworkXError(msg) - root = n - # checking deg>1 is not sufficient for MultiDiGraphs - elif deg > 1 and len(G.pred[n]) > 1: - msg = "Tree LCA only defined on trees; use DAG routine." - raise nx.NetworkXError(msg) - if root is None: - raise nx.NetworkXError("Graph contains a cycle.") - - # Iterative implementation of Tarjan's offline lca algorithm - # as described in CLRS on page 521 (2nd edition)/page 584 (3rd edition) - uf = UnionFind() - ancestors = {} - for node in G: - ancestors[node] = uf[node] - - colors = defaultdict(bool) - for node in nx.dfs_postorder_nodes(G, root): - colors[node] = True - for v in pair_dict[node] if pairs is not None else G: - if colors[v]: - # If the user requested both directions of a pair, give it. - # Otherwise, just give one. - if pairs is not None and (node, v) in pairs: - yield (node, v), ancestors[uf[v]] - if pairs is None or (v, node) in pairs: - yield (v, node), ancestors[uf[v]] - if node != root: - parent = arbitrary_element(G.pred[node]) - uf.union(parent, node) - ancestors[uf[parent]] = parent diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/matching.py deleted file mode 100644 index 6cfb3c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/matching.py +++ /dev/null @@ -1,1152 +0,0 @@ -"""Functions for computing and verifying matchings in a graph.""" - -from collections import Counter -from itertools import combinations, repeat - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "is_matching", - "is_maximal_matching", - "is_perfect_matching", - "max_weight_matching", - "min_weight_matching", - "maximal_matching", -] - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable -def maximal_matching(G): - r"""Find a maximal matching in the graph. - - A matching is a subset of edges in which no node occurs more than once. - A maximal matching cannot add more edges and still be a matching. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - matching : set - A maximal matching of the graph. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)]) - >>> sorted(nx.maximal_matching(G)) - [(1, 2), (3, 5)] - - Notes - ----- - The algorithm greedily selects a maximal matching M of the graph G - (i.e. no superset of M exists). It runs in $O(|E|)$ time. - """ - matching = set() - nodes = set() - for edge in G.edges(): - # If the edge isn't covered, add it to the matching - # then remove neighborhood of u and v from consideration. - u, v = edge - if u not in nodes and v not in nodes and u != v: - matching.add(edge) - nodes.update(edge) - return matching - - -def matching_dict_to_set(matching): - """Converts matching dict format to matching set format - - Converts a dictionary representing a matching (as returned by - :func:`max_weight_matching`) to a set representing a matching (as - returned by :func:`maximal_matching`). - - In the definition of maximal matching adopted by NetworkX, - self-loops are not allowed, so the provided dictionary is expected - to never have any mapping from a key to itself. However, the - dictionary is expected to have mirrored key/value pairs, for - example, key ``u`` with value ``v`` and key ``v`` with value ``u``. - - """ - edges = set() - for edge in matching.items(): - u, v = edge - if (v, u) in edges or edge in edges: - continue - if u == v: - raise nx.NetworkXError(f"Selfloops cannot appear in matchings {edge}") - edges.add(edge) - return edges - - -@nx._dispatchable -def is_matching(G, matching): - """Return True if ``matching`` is a valid matching of ``G`` - - A *matching* in a graph is a set of edges in which no two distinct - edges share a common endpoint. Each node is incident to at most one - edge in the matching. The edges are said to be independent. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid matching - in the graph. - - Raises - ------ - NetworkXError - If the proposed matching has an edge to a node not in G. - Or if the matching is not a collection of 2-tuple edges. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)]) - >>> nx.is_maximal_matching(G, {1: 3, 2: 4}) # using dict to represent matching - True - - >>> nx.is_matching(G, {(1, 3), (2, 4)}) # using set to represent matching - True - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - - nodes = set() - for edge in matching: - if len(edge) != 2: - raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}") - u, v = edge - if u not in G or v not in G: - raise nx.NetworkXError(f"matching contains edge {edge} with node not in G") - if u == v: - return False - if not G.has_edge(u, v): - return False - if u in nodes or v in nodes: - return False - nodes.update(edge) - return True - - -@nx._dispatchable -def is_maximal_matching(G, matching): - """Return True if ``matching`` is a maximal matching of ``G`` - - A *maximal matching* in a graph is a matching in which adding any - edge would cause the set to no longer be a valid matching. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid maximal - matching in the graph. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (3, 5)]) - >>> nx.is_maximal_matching(G, {(1, 2), (3, 4)}) - True - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - # If the given set is not a matching, then it is not a maximal matching. - edges = set() - nodes = set() - for edge in matching: - if len(edge) != 2: - raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}") - u, v = edge - if u not in G or v not in G: - raise nx.NetworkXError(f"matching contains edge {edge} with node not in G") - if u == v: - return False - if not G.has_edge(u, v): - return False - if u in nodes or v in nodes: - return False - nodes.update(edge) - edges.add(edge) - edges.add((v, u)) - # A matching is maximal if adding any new edge from G to it - # causes the resulting set to match some node twice. - # Be careful to check for adding selfloops - for u, v in G.edges: - if (u, v) not in edges: - # could add edge (u, v) to edges and have a bigger matching - if u not in nodes and v not in nodes and u != v: - return False - return True - - -@nx._dispatchable -def is_perfect_matching(G, matching): - """Return True if ``matching`` is a perfect matching for ``G`` - - A *perfect matching* in a graph is a matching in which exactly one edge - is incident upon each vertex. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid perfect - matching in the graph. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5), (4, 6)]) - >>> my_match = {1: 2, 3: 5, 4: 6} - >>> nx.is_perfect_matching(G, my_match) - True - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - - nodes = set() - for edge in matching: - if len(edge) != 2: - raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}") - u, v = edge - if u not in G or v not in G: - raise nx.NetworkXError(f"matching contains edge {edge} with node not in G") - if u == v: - return False - if not G.has_edge(u, v): - return False - if u in nodes or v in nodes: - return False - nodes.update(edge) - return len(nodes) == len(G) - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def min_weight_matching(G, weight="weight"): - """Computing a minimum-weight maximal matching of G. - - Use the maximum-weight algorithm with edge weights subtracted - from the maximum weight of all edges. - - A matching is a subset of edges in which no node occurs more than once. - The weight of a matching is the sum of the weights of its edges. - A maximal matching cannot add more edges and still be a matching. - The cardinality of a matching is the number of matched edges. - - This method replaces the edge weights with 1 plus the maximum edge weight - minus the original edge weight. - - new_weight = (max_weight + 1) - edge_weight - - then runs :func:`max_weight_matching` with the new weights. - The max weight matching with these new weights corresponds - to the min weight matching using the original weights. - Adding 1 to the max edge weight keeps all edge weights positive - and as integers if they started as integers. - - You might worry that adding 1 to each weight would make the algorithm - favor matchings with more edges. But we use the parameter - `maxcardinality=True` in `max_weight_matching` to ensure that the - number of edges in the competing matchings are the same and thus - the optimum does not change due to changes in the number of edges. - - Read the documentation of `max_weight_matching` for more information. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - If key not found, uses 1 as weight. - - Returns - ------- - matching : set - A minimal weight matching of the graph. - - See Also - -------- - max_weight_matching - """ - if len(G.edges) == 0: - return max_weight_matching(G, maxcardinality=True, weight=weight) - G_edges = G.edges(data=weight, default=1) - max_weight = 1 + max(w for _, _, w in G_edges) - InvG = nx.Graph() - edges = ((u, v, max_weight - w) for u, v, w in G_edges) - InvG.add_weighted_edges_from(edges, weight=weight) - return max_weight_matching(InvG, maxcardinality=True, weight=weight) - - -@not_implemented_for("multigraph") -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight") -def max_weight_matching(G, maxcardinality=False, weight="weight"): - """Compute a maximum-weighted matching of G. - - A matching is a subset of edges in which no node occurs more than once. - The weight of a matching is the sum of the weights of its edges. - A maximal matching cannot add more edges and still be a matching. - The cardinality of a matching is the number of matched edges. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - maxcardinality: bool, optional (default=False) - If maxcardinality is True, compute the maximum-cardinality matching - with maximum weight among all maximum-cardinality matchings. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - If key not found, uses 1 as weight. - - - Returns - ------- - matching : set - A maximal matching of the graph. - - Examples - -------- - >>> G = nx.Graph() - >>> edges = [(1, 2, 6), (1, 3, 2), (2, 3, 1), (2, 4, 7), (3, 5, 9), (4, 5, 3)] - >>> G.add_weighted_edges_from(edges) - >>> sorted(nx.max_weight_matching(G)) - [(2, 4), (5, 3)] - - Notes - ----- - If G has edges with weight attributes the edge data are used as - weight values else the weights are assumed to be 1. - - This function takes time O(number_of_nodes ** 3). - - If all edge weights are integers, the algorithm uses only integer - computations. If floating point weights are used, the algorithm - could return a slightly suboptimal matching due to numeric - precision errors. - - This method is based on the "blossom" method for finding augmenting - paths and the "primal-dual" method for finding a matching of maximum - weight, both methods invented by Jack Edmonds [1]_. - - Bipartite graphs can also be matched using the functions present in - :mod:`networkx.algorithms.bipartite.matching`. - - References - ---------- - .. [1] "Efficient Algorithms for Finding Maximum Matching in Graphs", - Zvi Galil, ACM Computing Surveys, 1986. - """ - # - # The algorithm is taken from "Efficient Algorithms for Finding Maximum - # Matching in Graphs" by Zvi Galil, ACM Computing Surveys, 1986. - # It is based on the "blossom" method for finding augmenting paths and - # the "primal-dual" method for finding a matching of maximum weight, both - # methods invented by Jack Edmonds. - # - # A C program for maximum weight matching by Ed Rothberg was used - # extensively to validate this new code. - # - # Many terms used in the code comments are explained in the paper - # by Galil. You will probably need the paper to make sense of this code. - # - - class NoNode: - """Dummy value which is different from any node.""" - - class Blossom: - """Representation of a non-trivial blossom or sub-blossom.""" - - __slots__ = ["childs", "edges", "mybestedges"] - - # b.childs is an ordered list of b's sub-blossoms, starting with - # the base and going round the blossom. - - # b.edges is the list of b's connecting edges, such that - # b.edges[i] = (v, w) where v is a vertex in b.childs[i] - # and w is a vertex in b.childs[wrap(i+1)]. - - # If b is a top-level S-blossom, - # b.mybestedges is a list of least-slack edges to neighboring - # S-blossoms, or None if no such list has been computed yet. - # This is used for efficient computation of delta3. - - # Generate the blossom's leaf vertices. - def leaves(self): - stack = [*self.childs] - while stack: - t = stack.pop() - if isinstance(t, Blossom): - stack.extend(t.childs) - else: - yield t - - # Get a list of vertices. - gnodes = list(G) - if not gnodes: - return set() # don't bother with empty graphs - - # Find the maximum edge weight. - maxweight = 0 - allinteger = True - for i, j, d in G.edges(data=True): - wt = d.get(weight, 1) - if i != j and wt > maxweight: - maxweight = wt - allinteger = allinteger and (str(type(wt)).split("'")[1] in ("int", "long")) - - # If v is a matched vertex, mate[v] is its partner vertex. - # If v is a single vertex, v does not occur as a key in mate. - # Initially all vertices are single; updated during augmentation. - mate = {} - - # If b is a top-level blossom, - # label.get(b) is None if b is unlabeled (free), - # 1 if b is an S-blossom, - # 2 if b is a T-blossom. - # The label of a vertex is found by looking at the label of its top-level - # containing blossom. - # If v is a vertex inside a T-blossom, label[v] is 2 iff v is reachable - # from an S-vertex outside the blossom. - # Labels are assigned during a stage and reset after each augmentation. - label = {} - - # If b is a labeled top-level blossom, - # labeledge[b] = (v, w) is the edge through which b obtained its label - # such that w is a vertex in b, or None if b's base vertex is single. - # If w is a vertex inside a T-blossom and label[w] == 2, - # labeledge[w] = (v, w) is an edge through which w is reachable from - # outside the blossom. - labeledge = {} - - # If v is a vertex, inblossom[v] is the top-level blossom to which v - # belongs. - # If v is a top-level vertex, inblossom[v] == v since v is itself - # a (trivial) top-level blossom. - # Initially all vertices are top-level trivial blossoms. - inblossom = dict(zip(gnodes, gnodes)) - - # If b is a sub-blossom, - # blossomparent[b] is its immediate parent (sub-)blossom. - # If b is a top-level blossom, blossomparent[b] is None. - blossomparent = dict(zip(gnodes, repeat(None))) - - # If b is a (sub-)blossom, - # blossombase[b] is its base VERTEX (i.e. recursive sub-blossom). - blossombase = dict(zip(gnodes, gnodes)) - - # If w is a free vertex (or an unreached vertex inside a T-blossom), - # bestedge[w] = (v, w) is the least-slack edge from an S-vertex, - # or None if there is no such edge. - # If b is a (possibly trivial) top-level S-blossom, - # bestedge[b] = (v, w) is the least-slack edge to a different S-blossom - # (v inside b), or None if there is no such edge. - # This is used for efficient computation of delta2 and delta3. - bestedge = {} - - # If v is a vertex, - # dualvar[v] = 2 * u(v) where u(v) is the v's variable in the dual - # optimization problem (if all edge weights are integers, multiplication - # by two ensures that all values remain integers throughout the algorithm). - # Initially, u(v) = maxweight / 2. - dualvar = dict(zip(gnodes, repeat(maxweight))) - - # If b is a non-trivial blossom, - # blossomdual[b] = z(b) where z(b) is b's variable in the dual - # optimization problem. - blossomdual = {} - - # If (v, w) in allowedge or (w, v) in allowedg, then the edge - # (v, w) is known to have zero slack in the optimization problem; - # otherwise the edge may or may not have zero slack. - allowedge = {} - - # Queue of newly discovered S-vertices. - queue = [] - - # Return 2 * slack of edge (v, w) (does not work inside blossoms). - def slack(v, w): - return dualvar[v] + dualvar[w] - 2 * G[v][w].get(weight, 1) - - # Assign label t to the top-level blossom containing vertex w, - # coming through an edge from vertex v. - def assignLabel(w, t, v): - b = inblossom[w] - assert label.get(w) is None and label.get(b) is None - label[w] = label[b] = t - if v is not None: - labeledge[w] = labeledge[b] = (v, w) - else: - labeledge[w] = labeledge[b] = None - bestedge[w] = bestedge[b] = None - if t == 1: - # b became an S-vertex/blossom; add it(s vertices) to the queue. - if isinstance(b, Blossom): - queue.extend(b.leaves()) - else: - queue.append(b) - elif t == 2: - # b became a T-vertex/blossom; assign label S to its mate. - # (If b is a non-trivial blossom, its base is the only vertex - # with an external mate.) - base = blossombase[b] - assignLabel(mate[base], 1, base) - - # Trace back from vertices v and w to discover either a new blossom - # or an augmenting path. Return the base vertex of the new blossom, - # or NoNode if an augmenting path was found. - def scanBlossom(v, w): - # Trace back from v and w, placing breadcrumbs as we go. - path = [] - base = NoNode - while v is not NoNode: - # Look for a breadcrumb in v's blossom or put a new breadcrumb. - b = inblossom[v] - if label[b] & 4: - base = blossombase[b] - break - assert label[b] == 1 - path.append(b) - label[b] = 5 - # Trace one step back. - if labeledge[b] is None: - # The base of blossom b is single; stop tracing this path. - assert blossombase[b] not in mate - v = NoNode - else: - assert labeledge[b][0] == mate[blossombase[b]] - v = labeledge[b][0] - b = inblossom[v] - assert label[b] == 2 - # b is a T-blossom; trace one more step back. - v = labeledge[b][0] - # Swap v and w so that we alternate between both paths. - if w is not NoNode: - v, w = w, v - # Remove breadcrumbs. - for b in path: - label[b] = 1 - # Return base vertex, if we found one. - return base - - # Construct a new blossom with given base, through S-vertices v and w. - # Label the new blossom as S; set its dual variable to zero; - # relabel its T-vertices to S and add them to the queue. - def addBlossom(base, v, w): - bb = inblossom[base] - bv = inblossom[v] - bw = inblossom[w] - # Create blossom. - b = Blossom() - blossombase[b] = base - blossomparent[b] = None - blossomparent[bb] = b - # Make list of sub-blossoms and their interconnecting edge endpoints. - b.childs = path = [] - b.edges = edgs = [(v, w)] - # Trace back from v to base. - while bv != bb: - # Add bv to the new blossom. - blossomparent[bv] = b - path.append(bv) - edgs.append(labeledge[bv]) - assert label[bv] == 2 or ( - label[bv] == 1 and labeledge[bv][0] == mate[blossombase[bv]] - ) - # Trace one step back. - v = labeledge[bv][0] - bv = inblossom[v] - # Add base sub-blossom; reverse lists. - path.append(bb) - path.reverse() - edgs.reverse() - # Trace back from w to base. - while bw != bb: - # Add bw to the new blossom. - blossomparent[bw] = b - path.append(bw) - edgs.append((labeledge[bw][1], labeledge[bw][0])) - assert label[bw] == 2 or ( - label[bw] == 1 and labeledge[bw][0] == mate[blossombase[bw]] - ) - # Trace one step back. - w = labeledge[bw][0] - bw = inblossom[w] - # Set label to S. - assert label[bb] == 1 - label[b] = 1 - labeledge[b] = labeledge[bb] - # Set dual variable to zero. - blossomdual[b] = 0 - # Relabel vertices. - for v in b.leaves(): - if label[inblossom[v]] == 2: - # This T-vertex now turns into an S-vertex because it becomes - # part of an S-blossom; add it to the queue. - queue.append(v) - inblossom[v] = b - # Compute b.mybestedges. - bestedgeto = {} - for bv in path: - if isinstance(bv, Blossom): - if bv.mybestedges is not None: - # Walk this subblossom's least-slack edges. - nblist = bv.mybestedges - # The sub-blossom won't need this data again. - bv.mybestedges = None - else: - # This subblossom does not have a list of least-slack - # edges; get the information from the vertices. - nblist = [ - (v, w) for v in bv.leaves() for w in G.neighbors(v) if v != w - ] - else: - nblist = [(bv, w) for w in G.neighbors(bv) if bv != w] - for k in nblist: - (i, j) = k - if inblossom[j] == b: - i, j = j, i - bj = inblossom[j] - if ( - bj != b - and label.get(bj) == 1 - and ((bj not in bestedgeto) or slack(i, j) < slack(*bestedgeto[bj])) - ): - bestedgeto[bj] = k - # Forget about least-slack edge of the subblossom. - bestedge[bv] = None - b.mybestedges = list(bestedgeto.values()) - # Select bestedge[b]. - mybestedge = None - bestedge[b] = None - for k in b.mybestedges: - kslack = slack(*k) - if mybestedge is None or kslack < mybestslack: - mybestedge = k - mybestslack = kslack - bestedge[b] = mybestedge - - # Expand the given top-level blossom. - def expandBlossom(b, endstage): - # This is an obnoxiously complicated recursive function for the sake of - # a stack-transformation. So, we hack around the complexity by using - # a trampoline pattern. By yielding the arguments to each recursive - # call, we keep the actual callstack flat. - - def _recurse(b, endstage): - # Convert sub-blossoms into top-level blossoms. - for s in b.childs: - blossomparent[s] = None - if isinstance(s, Blossom): - if endstage and blossomdual[s] == 0: - # Recursively expand this sub-blossom. - yield s - else: - for v in s.leaves(): - inblossom[v] = s - else: - inblossom[s] = s - # If we expand a T-blossom during a stage, its sub-blossoms must be - # relabeled. - if (not endstage) and label.get(b) == 2: - # Start at the sub-blossom through which the expanding - # blossom obtained its label, and relabel sub-blossoms untili - # we reach the base. - # Figure out through which sub-blossom the expanding blossom - # obtained its label initially. - entrychild = inblossom[labeledge[b][1]] - # Decide in which direction we will go round the blossom. - j = b.childs.index(entrychild) - if j & 1: - # Start index is odd; go forward and wrap. - j -= len(b.childs) - jstep = 1 - else: - # Start index is even; go backward. - jstep = -1 - # Move along the blossom until we get to the base. - v, w = labeledge[b] - while j != 0: - # Relabel the T-sub-blossom. - if jstep == 1: - p, q = b.edges[j] - else: - q, p = b.edges[j - 1] - label[w] = None - label[q] = None - assignLabel(w, 2, v) - # Step to the next S-sub-blossom and note its forward edge. - allowedge[(p, q)] = allowedge[(q, p)] = True - j += jstep - if jstep == 1: - v, w = b.edges[j] - else: - w, v = b.edges[j - 1] - # Step to the next T-sub-blossom. - allowedge[(v, w)] = allowedge[(w, v)] = True - j += jstep - # Relabel the base T-sub-blossom WITHOUT stepping through to - # its mate (so don't call assignLabel). - bw = b.childs[j] - label[w] = label[bw] = 2 - labeledge[w] = labeledge[bw] = (v, w) - bestedge[bw] = None - # Continue along the blossom until we get back to entrychild. - j += jstep - while b.childs[j] != entrychild: - # Examine the vertices of the sub-blossom to see whether - # it is reachable from a neighboring S-vertex outside the - # expanding blossom. - bv = b.childs[j] - if label.get(bv) == 1: - # This sub-blossom just got label S through one of its - # neighbors; leave it be. - j += jstep - continue - if isinstance(bv, Blossom): - for v in bv.leaves(): - if label.get(v): - break - else: - v = bv - # If the sub-blossom contains a reachable vertex, assign - # label T to the sub-blossom. - if label.get(v): - assert label[v] == 2 - assert inblossom[v] == bv - label[v] = None - label[mate[blossombase[bv]]] = None - assignLabel(v, 2, labeledge[v][0]) - j += jstep - # Remove the expanded blossom entirely. - label.pop(b, None) - labeledge.pop(b, None) - bestedge.pop(b, None) - del blossomparent[b] - del blossombase[b] - del blossomdual[b] - - # Now, we apply the trampoline pattern. We simulate a recursive - # callstack by maintaining a stack of generators, each yielding a - # sequence of function arguments. We grow the stack by appending a call - # to _recurse on each argument tuple, and shrink the stack whenever a - # generator is exhausted. - stack = [_recurse(b, endstage)] - while stack: - top = stack[-1] - for s in top: - stack.append(_recurse(s, endstage)) - break - else: - stack.pop() - - # Swap matched/unmatched edges over an alternating path through blossom b - # between vertex v and the base vertex. Keep blossom bookkeeping - # consistent. - def augmentBlossom(b, v): - # This is an obnoxiously complicated recursive function for the sake of - # a stack-transformation. So, we hack around the complexity by using - # a trampoline pattern. By yielding the arguments to each recursive - # call, we keep the actual callstack flat. - - def _recurse(b, v): - # Bubble up through the blossom tree from vertex v to an immediate - # sub-blossom of b. - t = v - while blossomparent[t] != b: - t = blossomparent[t] - # Recursively deal with the first sub-blossom. - if isinstance(t, Blossom): - yield (t, v) - # Decide in which direction we will go round the blossom. - i = j = b.childs.index(t) - if i & 1: - # Start index is odd; go forward and wrap. - j -= len(b.childs) - jstep = 1 - else: - # Start index is even; go backward. - jstep = -1 - # Move along the blossom until we get to the base. - while j != 0: - # Step to the next sub-blossom and augment it recursively. - j += jstep - t = b.childs[j] - if jstep == 1: - w, x = b.edges[j] - else: - x, w = b.edges[j - 1] - if isinstance(t, Blossom): - yield (t, w) - # Step to the next sub-blossom and augment it recursively. - j += jstep - t = b.childs[j] - if isinstance(t, Blossom): - yield (t, x) - # Match the edge connecting those sub-blossoms. - mate[w] = x - mate[x] = w - # Rotate the list of sub-blossoms to put the new base at the front. - b.childs = b.childs[i:] + b.childs[:i] - b.edges = b.edges[i:] + b.edges[:i] - blossombase[b] = blossombase[b.childs[0]] - assert blossombase[b] == v - - # Now, we apply the trampoline pattern. We simulate a recursive - # callstack by maintaining a stack of generators, each yielding a - # sequence of function arguments. We grow the stack by appending a call - # to _recurse on each argument tuple, and shrink the stack whenever a - # generator is exhausted. - stack = [_recurse(b, v)] - while stack: - top = stack[-1] - for args in top: - stack.append(_recurse(*args)) - break - else: - stack.pop() - - # Swap matched/unmatched edges over an alternating path between two - # single vertices. The augmenting path runs through S-vertices v and w. - def augmentMatching(v, w): - for s, j in ((v, w), (w, v)): - # Match vertex s to vertex j. Then trace back from s - # until we find a single vertex, swapping matched and unmatched - # edges as we go. - while 1: - bs = inblossom[s] - assert label[bs] == 1 - assert (labeledge[bs] is None and blossombase[bs] not in mate) or ( - labeledge[bs][0] == mate[blossombase[bs]] - ) - # Augment through the S-blossom from s to base. - if isinstance(bs, Blossom): - augmentBlossom(bs, s) - # Update mate[s] - mate[s] = j - # Trace one step back. - if labeledge[bs] is None: - # Reached single vertex; stop. - break - t = labeledge[bs][0] - bt = inblossom[t] - assert label[bt] == 2 - # Trace one more step back. - s, j = labeledge[bt] - # Augment through the T-blossom from j to base. - assert blossombase[bt] == t - if isinstance(bt, Blossom): - augmentBlossom(bt, j) - # Update mate[j] - mate[j] = s - - # Verify that the optimum solution has been reached. - def verifyOptimum(): - if maxcardinality: - # Vertices may have negative dual; - # find a constant non-negative number to add to all vertex duals. - vdualoffset = max(0, -min(dualvar.values())) - else: - vdualoffset = 0 - # 0. all dual variables are non-negative - assert min(dualvar.values()) + vdualoffset >= 0 - assert len(blossomdual) == 0 or min(blossomdual.values()) >= 0 - # 0. all edges have non-negative slack and - # 1. all matched edges have zero slack; - for i, j, d in G.edges(data=True): - wt = d.get(weight, 1) - if i == j: - continue # ignore self-loops - s = dualvar[i] + dualvar[j] - 2 * wt - iblossoms = [i] - jblossoms = [j] - while blossomparent[iblossoms[-1]] is not None: - iblossoms.append(blossomparent[iblossoms[-1]]) - while blossomparent[jblossoms[-1]] is not None: - jblossoms.append(blossomparent[jblossoms[-1]]) - iblossoms.reverse() - jblossoms.reverse() - for bi, bj in zip(iblossoms, jblossoms): - if bi != bj: - break - s += 2 * blossomdual[bi] - assert s >= 0 - if mate.get(i) == j or mate.get(j) == i: - assert mate[i] == j and mate[j] == i - assert s == 0 - # 2. all single vertices have zero dual value; - for v in gnodes: - assert (v in mate) or dualvar[v] + vdualoffset == 0 - # 3. all blossoms with positive dual value are full. - for b in blossomdual: - if blossomdual[b] > 0: - assert len(b.edges) % 2 == 1 - for i, j in b.edges[1::2]: - assert mate[i] == j and mate[j] == i - # Ok. - - # Main loop: continue until no further improvement is possible. - while 1: - # Each iteration of this loop is a "stage". - # A stage finds an augmenting path and uses that to improve - # the matching. - - # Remove labels from top-level blossoms/vertices. - label.clear() - labeledge.clear() - - # Forget all about least-slack edges. - bestedge.clear() - for b in blossomdual: - b.mybestedges = None - - # Loss of labeling means that we can not be sure that currently - # allowable edges remain allowable throughout this stage. - allowedge.clear() - - # Make queue empty. - queue[:] = [] - - # Label single blossoms/vertices with S and put them in the queue. - for v in gnodes: - if (v not in mate) and label.get(inblossom[v]) is None: - assignLabel(v, 1, None) - - # Loop until we succeed in augmenting the matching. - augmented = 0 - while 1: - # Each iteration of this loop is a "substage". - # A substage tries to find an augmenting path; - # if found, the path is used to improve the matching and - # the stage ends. If there is no augmenting path, the - # primal-dual method is used to pump some slack out of - # the dual variables. - - # Continue labeling until all vertices which are reachable - # through an alternating path have got a label. - while queue and not augmented: - # Take an S vertex from the queue. - v = queue.pop() - assert label[inblossom[v]] == 1 - - # Scan its neighbors: - for w in G.neighbors(v): - if w == v: - continue # ignore self-loops - # w is a neighbor to v - bv = inblossom[v] - bw = inblossom[w] - if bv == bw: - # this edge is internal to a blossom; ignore it - continue - if (v, w) not in allowedge: - kslack = slack(v, w) - if kslack <= 0: - # edge k has zero slack => it is allowable - allowedge[(v, w)] = allowedge[(w, v)] = True - if (v, w) in allowedge: - if label.get(bw) is None: - # (C1) w is a free vertex; - # label w with T and label its mate with S (R12). - assignLabel(w, 2, v) - elif label.get(bw) == 1: - # (C2) w is an S-vertex (not in the same blossom); - # follow back-links to discover either an - # augmenting path or a new blossom. - base = scanBlossom(v, w) - if base is not NoNode: - # Found a new blossom; add it to the blossom - # bookkeeping and turn it into an S-blossom. - addBlossom(base, v, w) - else: - # Found an augmenting path; augment the - # matching and end this stage. - augmentMatching(v, w) - augmented = 1 - break - elif label.get(w) is None: - # w is inside a T-blossom, but w itself has not - # yet been reached from outside the blossom; - # mark it as reached (we need this to relabel - # during T-blossom expansion). - assert label[bw] == 2 - label[w] = 2 - labeledge[w] = (v, w) - elif label.get(bw) == 1: - # keep track of the least-slack non-allowable edge to - # a different S-blossom. - if bestedge.get(bv) is None or kslack < slack(*bestedge[bv]): - bestedge[bv] = (v, w) - elif label.get(w) is None: - # w is a free vertex (or an unreached vertex inside - # a T-blossom) but we can not reach it yet; - # keep track of the least-slack edge that reaches w. - if bestedge.get(w) is None or kslack < slack(*bestedge[w]): - bestedge[w] = (v, w) - - if augmented: - break - - # There is no augmenting path under these constraints; - # compute delta and reduce slack in the optimization problem. - # (Note that our vertex dual variables, edge slacks and delta's - # are pre-multiplied by two.) - deltatype = -1 - delta = deltaedge = deltablossom = None - - # Compute delta1: the minimum value of any vertex dual. - if not maxcardinality: - deltatype = 1 - delta = min(dualvar.values()) - - # Compute delta2: the minimum slack on any edge between - # an S-vertex and a free vertex. - for v in G.nodes(): - if label.get(inblossom[v]) is None and bestedge.get(v) is not None: - d = slack(*bestedge[v]) - if deltatype == -1 or d < delta: - delta = d - deltatype = 2 - deltaedge = bestedge[v] - - # Compute delta3: half the minimum slack on any edge between - # a pair of S-blossoms. - for b in blossomparent: - if ( - blossomparent[b] is None - and label.get(b) == 1 - and bestedge.get(b) is not None - ): - kslack = slack(*bestedge[b]) - if allinteger: - assert (kslack % 2) == 0 - d = kslack // 2 - else: - d = kslack / 2.0 - if deltatype == -1 or d < delta: - delta = d - deltatype = 3 - deltaedge = bestedge[b] - - # Compute delta4: minimum z variable of any T-blossom. - for b in blossomdual: - if ( - blossomparent[b] is None - and label.get(b) == 2 - and (deltatype == -1 or blossomdual[b] < delta) - ): - delta = blossomdual[b] - deltatype = 4 - deltablossom = b - - if deltatype == -1: - # No further improvement possible; max-cardinality optimum - # reached. Do a final delta update to make the optimum - # verifiable. - assert maxcardinality - deltatype = 1 - delta = max(0, min(dualvar.values())) - - # Update dual variables according to delta. - for v in gnodes: - if label.get(inblossom[v]) == 1: - # S-vertex: 2*u = 2*u - 2*delta - dualvar[v] -= delta - elif label.get(inblossom[v]) == 2: - # T-vertex: 2*u = 2*u + 2*delta - dualvar[v] += delta - for b in blossomdual: - if blossomparent[b] is None: - if label.get(b) == 1: - # top-level S-blossom: z = z + 2*delta - blossomdual[b] += delta - elif label.get(b) == 2: - # top-level T-blossom: z = z - 2*delta - blossomdual[b] -= delta - - # Take action at the point where minimum delta occurred. - if deltatype == 1: - # No further improvement possible; optimum reached. - break - elif deltatype == 2: - # Use the least-slack edge to continue the search. - (v, w) = deltaedge - assert label[inblossom[v]] == 1 - allowedge[(v, w)] = allowedge[(w, v)] = True - queue.append(v) - elif deltatype == 3: - # Use the least-slack edge to continue the search. - (v, w) = deltaedge - allowedge[(v, w)] = allowedge[(w, v)] = True - assert label[inblossom[v]] == 1 - queue.append(v) - elif deltatype == 4: - # Expand the least-z blossom. - expandBlossom(deltablossom, False) - - # End of a this substage. - - # Paranoia check that the matching is symmetric. - for v in mate: - assert mate[mate[v]] == v - - # Stop when no more augmenting path can be found. - if not augmented: - break - - # End of a stage; expand all S-blossoms which have zero dual. - for b in list(blossomdual.keys()): - if b not in blossomdual: - continue # already expanded - if blossomparent[b] is None and label.get(b) == 1 and blossomdual[b] == 0: - expandBlossom(b, True) - - # Verify that we reached the optimum solution (only for integer weights). - if allinteger: - verifyOptimum() - - return matching_dict_to_set(mate) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/__init__.py deleted file mode 100644 index cf15ddb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Subpackages related to graph-minor problems. - -In graph theory, an undirected graph H is called a minor of the graph G if H -can be formed from G by deleting edges and vertices and by contracting edges -[1]_. - -References ----------- -.. [1] https://en.wikipedia.org/wiki/Graph_minor -""" - -from networkx.algorithms.minors.contraction import ( - contracted_edge, - contracted_nodes, - equivalence_classes, - identified_nodes, - quotient_graph, -) - -__all__ = [ - "contracted_edge", - "contracted_nodes", - "equivalence_classes", - "identified_nodes", - "quotient_graph", -] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/contraction.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/contraction.py deleted file mode 100644 index e85b577..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/contraction.py +++ /dev/null @@ -1,634 +0,0 @@ -"""Provides functions for computing minors of a graph.""" - -from itertools import chain, combinations, permutations, product - -import networkx as nx -from networkx import density -from networkx.exception import NetworkXException -from networkx.utils import arbitrary_element - -__all__ = [ - "contracted_edge", - "contracted_nodes", - "equivalence_classes", - "identified_nodes", - "quotient_graph", -] - -chaini = chain.from_iterable - - -def equivalence_classes(iterable, relation): - """Returns equivalence classes of `relation` when applied to `iterable`. - - The equivalence classes, or blocks, consist of objects from `iterable` - which are all equivalent. They are defined to be equivalent if the - `relation` function returns `True` when passed any two objects from that - class, and `False` otherwise. To define an equivalence relation the - function must be reflexive, symmetric and transitive. - - Parameters - ---------- - iterable : list, tuple, or set - An iterable of elements/nodes. - - relation : function - A Boolean-valued function that implements an equivalence relation - (reflexive, symmetric, transitive binary relation) on the elements - of `iterable` - it must take two elements and return `True` if - they are related, or `False` if not. - - Returns - ------- - set of frozensets - A set of frozensets representing the partition induced by the equivalence - relation function `relation` on the elements of `iterable`. Each - member set in the return set represents an equivalence class, or - block, of the partition. - - Duplicate elements will be ignored so it makes the most sense for - `iterable` to be a :class:`set`. - - Notes - ----- - This function does not check that `relation` represents an equivalence - relation. You can check that your equivalence classes provide a partition - using `is_partition`. - - Examples - -------- - Let `X` be the set of integers from `0` to `9`, and consider an equivalence - relation `R` on `X` of congruence modulo `3`: this means that two integers - `x` and `y` in `X` are equivalent under `R` if they leave the same - remainder when divided by `3`, i.e. `(x - y) mod 3 = 0`. - - The equivalence classes of this relation are `{0, 3, 6, 9}`, `{1, 4, 7}`, - `{2, 5, 8}`: `0`, `3`, `6`, `9` are all divisible by `3` and leave zero - remainder; `1`, `4`, `7` leave remainder `1`; while `2`, `5` and `8` leave - remainder `2`. We can see this by calling `equivalence_classes` with - `X` and a function implementation of `R`. - - >>> X = set(range(10)) - >>> def mod3(x, y): - ... return (x - y) % 3 == 0 - >>> equivalence_classes(X, mod3) # doctest: +SKIP - {frozenset({1, 4, 7}), frozenset({8, 2, 5}), frozenset({0, 9, 3, 6})} - """ - # For simplicity of implementation, we initialize the return value as a - # list of lists, then convert it to a set of sets at the end of the - # function. - blocks = [] - # Determine the equivalence class for each element of the iterable. - for y in iterable: - # Each element y must be in *exactly one* equivalence class. - # - # Each block is guaranteed to be non-empty - for block in blocks: - x = arbitrary_element(block) - if relation(x, y): - block.append(y) - break - else: - # If the element y is not part of any known equivalence class, it - # must be in its own, so we create a new singleton equivalence - # class for it. - blocks.append([y]) - return {frozenset(block) for block in blocks} - - -@nx._dispatchable(edge_attrs="weight", returns_graph=True) -def quotient_graph( - G, - partition, - edge_relation=None, - node_data=None, - edge_data=None, - weight="weight", - relabel=False, - create_using=None, -): - """Returns the quotient graph of `G` under the specified equivalence - relation on nodes. - - Parameters - ---------- - G : NetworkX graph - The graph for which to return the quotient graph with the - specified node relation. - - partition : function, or dict or list of lists, tuples or sets - If a function, this function must represent an equivalence - relation on the nodes of `G`. It must take two arguments *u* - and *v* and return True exactly when *u* and *v* are in the - same equivalence class. The equivalence classes form the nodes - in the returned graph. - - If a dict of lists/tuples/sets, the keys can be any meaningful - block labels, but the values must be the block lists/tuples/sets - (one list/tuple/set per block), and the blocks must form a valid - partition of the nodes of the graph. That is, each node must be - in exactly one block of the partition. - - If a list of sets, the list must form a valid partition of - the nodes of the graph. That is, each node must be in exactly - one block of the partition. - - edge_relation : Boolean function with two arguments - This function must represent an edge relation on the *blocks* of - the `partition` of `G`. It must take two arguments, *B* and *C*, - each one a set of nodes, and return True exactly when there should be - an edge joining block *B* to block *C* in the returned graph. - - If `edge_relation` is not specified, it is assumed to be the - following relation. Block *B* is related to block *C* if and - only if some node in *B* is adjacent to some node in *C*, - according to the edge set of `G`. - - node_data : function - This function takes one argument, *B*, a set of nodes in `G`, - and must return a dictionary representing the node data - attributes to set on the node representing *B* in the quotient graph. - If None, the following node attributes will be set: - - * 'graph', the subgraph of the graph `G` that this block - represents, - * 'nnodes', the number of nodes in this block, - * 'nedges', the number of edges within this block, - * 'density', the density of the subgraph of `G` that this - block represents. - - edge_data : function - This function takes two arguments, *B* and *C*, each one a set - of nodes, and must return a dictionary representing the edge - data attributes to set on the edge joining *B* and *C*, should - there be an edge joining *B* and *C* in the quotient graph (if - no such edge occurs in the quotient graph as determined by - `edge_relation`, then the output of this function is ignored). - - If the quotient graph would be a multigraph, this function is - not applied, since the edge data from each edge in the graph - `G` appears in the edges of the quotient graph. - - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - - relabel : bool - If True, relabel the nodes of the quotient graph to be - nonnegative integers. Otherwise, the nodes are identified with - :class:`frozenset` instances representing the blocks given in - `partition`. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The quotient graph of `G` under the equivalence relation - specified by `partition`. If the partition were given as a - list of :class:`set` instances and `relabel` is False, - each node will be a :class:`frozenset` corresponding to the same - :class:`set`. - - Raises - ------ - NetworkXException - If the given partition is not a valid partition of the nodes of - `G`. - - Examples - -------- - The quotient graph of the complete bipartite graph under the "same - neighbors" equivalence relation is `K_2`. Under this relation, two nodes - are equivalent if they are not adjacent but have the same neighbor set. - - >>> G = nx.complete_bipartite_graph(2, 3) - >>> same_neighbors = lambda u, v: (u not in G[v] and v not in G[u] and G[u] == G[v]) - >>> Q = nx.quotient_graph(G, same_neighbors) - >>> K2 = nx.complete_graph(2) - >>> nx.is_isomorphic(Q, K2) - True - - The quotient graph of a directed graph under the "same strongly connected - component" equivalence relation is the condensation of the graph (see - :func:`condensation`). This example comes from the Wikipedia article - *`Strongly connected component`_*. - - >>> G = nx.DiGraph() - >>> edges = [ - ... "ab", - ... "be", - ... "bf", - ... "bc", - ... "cg", - ... "cd", - ... "dc", - ... "dh", - ... "ea", - ... "ef", - ... "fg", - ... "gf", - ... "hd", - ... "hf", - ... ] - >>> G.add_edges_from(tuple(x) for x in edges) - >>> components = list(nx.strongly_connected_components(G)) - >>> sorted(sorted(component) for component in components) - [['a', 'b', 'e'], ['c', 'd', 'h'], ['f', 'g']] - >>> - >>> C = nx.condensation(G, components) - >>> component_of = C.graph["mapping"] - >>> same_component = lambda u, v: component_of[u] == component_of[v] - >>> Q = nx.quotient_graph(G, same_component) - >>> nx.is_isomorphic(C, Q) - True - - Node identification can be represented as the quotient of a graph under the - equivalence relation that places the two nodes in one block and each other - node in its own singleton block. - - >>> K24 = nx.complete_bipartite_graph(2, 4) - >>> K34 = nx.complete_bipartite_graph(3, 4) - >>> C = nx.contracted_nodes(K34, 1, 2) - >>> nodes = {1, 2} - >>> is_contracted = lambda u, v: u in nodes and v in nodes - >>> Q = nx.quotient_graph(K34, is_contracted) - >>> nx.is_isomorphic(Q, C) - True - >>> nx.is_isomorphic(Q, K24) - True - - The blockmodeling technique described in [1]_ can be implemented as a - quotient graph. - - >>> G = nx.path_graph(6) - >>> partition = [{0, 1}, {2, 3}, {4, 5}] - >>> M = nx.quotient_graph(G, partition, relabel=True) - >>> list(M.edges()) - [(0, 1), (1, 2)] - - Here is the sample example but using partition as a dict of block sets. - - >>> G = nx.path_graph(6) - >>> partition = {0: {0, 1}, 2: {2, 3}, 4: {4, 5}} - >>> M = nx.quotient_graph(G, partition, relabel=True) - >>> list(M.edges()) - [(0, 1), (1, 2)] - - Partitions can be represented in various ways: - - 0. a list/tuple/set of block lists/tuples/sets - 1. a dict with block labels as keys and blocks lists/tuples/sets as values - 2. a dict with block lists/tuples/sets as keys and block labels as values - 3. a function from nodes in the original iterable to block labels - 4. an equivalence relation function on the target iterable - - As `quotient_graph` is designed to accept partitions represented as (0), (1) or - (4) only, the `equivalence_classes` function can be used to get the partitions - in the right form, in order to call `quotient_graph`. - - .. _Strongly connected component: https://en.wikipedia.org/wiki/Strongly_connected_component - - References - ---------- - .. [1] Patrick Doreian, Vladimir Batagelj, and Anuska Ferligoj. - *Generalized Blockmodeling*. - Cambridge University Press, 2004. - - """ - # If the user provided an equivalence relation as a function to compute - # the blocks of the partition on the nodes of G induced by the - # equivalence relation. - if callable(partition): - # equivalence_classes always return partition of whole G. - partition = equivalence_classes(G, partition) - if not nx.community.is_partition(G, partition): - raise nx.NetworkXException( - "Input `partition` is not an equivalence relation for nodes of G" - ) - return _quotient_graph( - G, - partition, - edge_relation, - node_data, - edge_data, - weight, - relabel, - create_using, - ) - - # If the partition is a dict, it is assumed to be one where the keys are - # user-defined block labels, and values are block lists, tuples or sets. - if isinstance(partition, dict): - partition = list(partition.values()) - - # If the user provided partition as a collection of sets. Then we - # need to check if partition covers all of G nodes. If the answer - # is 'No' then we need to prepare suitable subgraph view. - partition_nodes = set().union(*partition) - if len(partition_nodes) != len(G): - G = G.subgraph(partition_nodes) - # Each node in the graph/subgraph must be in exactly one block. - if not nx.community.is_partition(G, partition): - raise NetworkXException("each node must be in exactly one part of `partition`") - return _quotient_graph( - G, - partition, - edge_relation, - node_data, - edge_data, - weight, - relabel, - create_using, - ) - - -def _quotient_graph( - G, partition, edge_relation, node_data, edge_data, weight, relabel, create_using -): - """Construct the quotient graph assuming input has been checked""" - if create_using is None: - H = G.__class__() - else: - H = nx.empty_graph(0, create_using) - # By default set some basic information about the subgraph that each block - # represents on the nodes in the quotient graph. - if node_data is None: - - def node_data(b): - S = G.subgraph(b) - return { - "graph": S, - "nnodes": len(S), - "nedges": S.number_of_edges(), - "density": density(S), - } - - # Each block of the partition becomes a node in the quotient graph. - partition = [frozenset(b) for b in partition] - H.add_nodes_from((b, node_data(b)) for b in partition) - # By default, the edge relation is the relation defined as follows. B is - # adjacent to C if a node in B is adjacent to a node in C, according to the - # edge set of G. - # - # This is not a particularly efficient implementation of this relation: - # there are O(n^2) pairs to check and each check may require O(log n) time - # (to check set membership). This can certainly be parallelized. - if edge_relation is None: - - def edge_relation(b, c): - return any(v in G[u] for u, v in product(b, c)) - - # By default, sum the weights of the edges joining pairs of nodes across - # blocks to get the weight of the edge joining those two blocks. - if edge_data is None: - - def edge_data(b, c): - edgedata = ( - d - for u, v, d in G.edges(b | c, data=True) - if (u in b and v in c) or (u in c and v in b) - ) - return {"weight": sum(d.get(weight, 1) for d in edgedata)} - - block_pairs = permutations(H, 2) if H.is_directed() else combinations(H, 2) - # In a multigraph, add one edge in the quotient graph for each edge - # in the original graph. - if H.is_multigraph(): - edges = chaini( - ( - (b, c, G.get_edge_data(u, v, default={})) - for u, v in product(b, c) - if v in G[u] - ) - for b, c in block_pairs - if edge_relation(b, c) - ) - # In a simple graph, apply the edge data function to each pair of - # blocks to determine the edge data attributes to apply to each edge - # in the quotient graph. - else: - edges = ( - (b, c, edge_data(b, c)) for (b, c) in block_pairs if edge_relation(b, c) - ) - H.add_edges_from(edges) - # If requested by the user, relabel the nodes to be integers, - # numbered in increasing order from zero in the same order as the - # iteration order of `partition`. - if relabel: - # Can't use nx.convert_node_labels_to_integers() here since we - # want the order of iteration to be the same for backward - # compatibility with the nx.blockmodel() function. - labels = {b: i for i, b in enumerate(partition)} - H = nx.relabel_nodes(H, labels) - return H - - -@nx._dispatchable( - preserve_all_attrs=True, mutates_input={"not copy": 4}, returns_graph=True -) -def contracted_nodes(G, u, v, self_loops=True, copy=True): - """Returns the graph that results from contracting `u` and `v`. - - Node contraction identifies the two nodes as a single node incident to any - edge that was incident to the original two nodes. - - Parameters - ---------- - G : NetworkX graph - The graph whose nodes will be contracted. - - u, v : nodes - Must be nodes in `G`. - - self_loops : Boolean - If this is True, any edges joining `u` and `v` in `G` become - self-loops on the new node in the returned graph. - - copy : Boolean - If this is True (default True), make a copy of - `G` and return that instead of directly changing `G`. - - - Returns - ------- - Networkx graph - If Copy is True, - A new graph object of the same type as `G` (leaving `G` unmodified) - with `u` and `v` identified in a single node. The right node `v` - will be merged into the node `u`, so only `u` will appear in the - returned graph. - If copy is False, - Modifies `G` with `u` and `v` identified in a single node. - The right node `v` will be merged into the node `u`, so - only `u` will appear in the returned graph. - - Notes - ----- - For multigraphs, the edge keys for the realigned edges may - not be the same as the edge keys for the old edges. This is - natural because edge keys are unique only within each pair of nodes. - - For non-multigraphs where `u` and `v` are adjacent to a third node - `w`, the edge (`v`, `w`) will be contracted into the edge (`u`, - `w`) with its attributes stored into a "contraction" attribute. - - This function is also available as `identified_nodes`. - - Examples - -------- - Contracting two nonadjacent nodes of the cycle graph on four nodes `C_4` - yields the path graph (ignoring parallel edges): - - >>> G = nx.cycle_graph(4) - >>> M = nx.contracted_nodes(G, 1, 3) - >>> P3 = nx.path_graph(3) - >>> nx.is_isomorphic(M, P3) - True - - >>> G = nx.MultiGraph(P3) - >>> M = nx.contracted_nodes(G, 0, 2) - >>> M.edges - MultiEdgeView([(0, 1, 0), (0, 1, 1)]) - - >>> G = nx.Graph([(1, 2), (2, 2)]) - >>> H = nx.contracted_nodes(G, 1, 2, self_loops=False) - >>> list(H.nodes()) - [1] - >>> list(H.edges()) - [(1, 1)] - - In a ``MultiDiGraph`` with a self loop, the in and out edges will - be treated separately as edges, so while contracting a node which - has a self loop the contraction will add multiple edges: - - >>> G = nx.MultiDiGraph([(1, 2), (2, 2)]) - >>> H = nx.contracted_nodes(G, 1, 2) - >>> list(H.edges()) # edge 1->2, 2->2, 2<-2 from the original Graph G - [(1, 1), (1, 1), (1, 1)] - >>> H = nx.contracted_nodes(G, 1, 2, self_loops=False) - >>> list(H.edges()) # edge 2->2, 2<-2 from the original Graph G - [(1, 1), (1, 1)] - - See Also - -------- - contracted_edge - quotient_graph - - """ - # Copying has significant overhead and can be disabled if needed - if copy: - H = G.copy() - else: - H = G - - # edge code uses G.edges(v) instead of G.adj[v] to handle multiedges - if H.is_directed(): - edges_to_remap = chain(G.in_edges(v, data=True), G.out_edges(v, data=True)) - else: - edges_to_remap = G.edges(v, data=True) - - # If the H=G, the generators change as H changes - # This makes the edges_to_remap independent of H - if not copy: - edges_to_remap = list(edges_to_remap) - - v_data = H.nodes[v] - H.remove_node(v) - - for prev_w, prev_x, d in edges_to_remap: - w = prev_w if prev_w != v else u - x = prev_x if prev_x != v else u - - if ({prev_w, prev_x} == {u, v}) and not self_loops: - continue - - if not H.has_edge(w, x) or G.is_multigraph(): - H.add_edge(w, x, **d) - else: - if "contraction" in H.edges[(w, x)]: - H.edges[(w, x)]["contraction"][(prev_w, prev_x)] = d - else: - H.edges[(w, x)]["contraction"] = {(prev_w, prev_x): d} - - if "contraction" in H.nodes[u]: - H.nodes[u]["contraction"][v] = v_data - else: - H.nodes[u]["contraction"] = {v: v_data} - return H - - -identified_nodes = contracted_nodes - - -@nx._dispatchable( - preserve_edge_attrs=True, mutates_input={"not copy": 3}, returns_graph=True -) -def contracted_edge(G, edge, self_loops=True, copy=True): - """Returns the graph that results from contracting the specified edge. - - Edge contraction identifies the two endpoints of the edge as a single node - incident to any edge that was incident to the original two nodes. A graph - that results from edge contraction is called a *minor* of the original - graph. - - Parameters - ---------- - G : NetworkX graph - The graph whose edge will be contracted. - - edge : tuple - Must be a pair of nodes in `G`. - - self_loops : Boolean - If this is True, any edges (including `edge`) joining the - endpoints of `edge` in `G` become self-loops on the new node in the - returned graph. - - copy : Boolean (default True) - If this is True, a the contraction will be performed on a copy of `G`, - otherwise the contraction will happen in place. - - Returns - ------- - Networkx graph - A new graph object of the same type as `G` (leaving `G` unmodified) - with endpoints of `edge` identified in a single node. The right node - of `edge` will be merged into the left one, so only the left one will - appear in the returned graph. - - Raises - ------ - ValueError - If `edge` is not an edge in `G`. - - Examples - -------- - Attempting to contract two nonadjacent nodes yields an error: - - >>> G = nx.cycle_graph(4) - >>> nx.contracted_edge(G, (1, 3)) - Traceback (most recent call last): - ... - ValueError: Edge (1, 3) does not exist in graph G; cannot contract it - - Contracting two adjacent nodes in the cycle graph on *n* nodes yields the - cycle graph on *n - 1* nodes: - - >>> C5 = nx.cycle_graph(5) - >>> C4 = nx.cycle_graph(4) - >>> M = nx.contracted_edge(C5, (0, 1), self_loops=False) - >>> nx.is_isomorphic(M, C4) - True - - See also - -------- - contracted_nodes - quotient_graph - - """ - u, v = edge[:2] - if not G.has_edge(u, v): - raise ValueError(f"Edge {edge} does not exist in graph G; cannot contract it") - return contracted_nodes(G, u, v, self_loops=self_loops, copy=copy) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/tests/test_contraction.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/tests/test_contraction.py deleted file mode 100644 index 2246886..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/minors/tests/test_contraction.py +++ /dev/null @@ -1,446 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.minors.contraction` module.""" - -import pytest - -import networkx as nx -from networkx.utils import arbitrary_element, edges_equal, nodes_equal - - -def test_quotient_graph_complete_multipartite(): - """Tests that the quotient graph of the complete *n*-partite graph - under the "same neighbors" node relation is the complete graph on *n* - nodes. - - """ - G = nx.complete_multipartite_graph(2, 3, 4) - # Two nodes are equivalent if they are not adjacent but have the same - # neighbor set. - - def same_neighbors(u, v): - return u not in G[v] and v not in G[u] and G[u] == G[v] - - expected = nx.complete_graph(3) - actual = nx.quotient_graph(G, same_neighbors) - # It won't take too long to run a graph isomorphism algorithm on such - # small graphs. - assert nx.is_isomorphic(expected, actual) - - -def test_quotient_graph_complete_bipartite(): - """Tests that the quotient graph of the complete bipartite graph under - the "same neighbors" node relation is `K_2`. - - """ - G = nx.complete_bipartite_graph(2, 3) - # Two nodes are equivalent if they are not adjacent but have the same - # neighbor set. - - def same_neighbors(u, v): - return u not in G[v] and v not in G[u] and G[u] == G[v] - - expected = nx.complete_graph(2) - actual = nx.quotient_graph(G, same_neighbors) - # It won't take too long to run a graph isomorphism algorithm on such - # small graphs. - assert nx.is_isomorphic(expected, actual) - - -def test_quotient_graph_edge_relation(): - """Tests for specifying an alternate edge relation for the quotient - graph. - - """ - G = nx.path_graph(5) - - def identity(u, v): - return u == v - - def same_parity(b, c): - return arbitrary_element(b) % 2 == arbitrary_element(c) % 2 - - actual = nx.quotient_graph(G, identity, same_parity) - expected = nx.Graph() - expected.add_edges_from([(0, 2), (0, 4), (2, 4)]) - expected.add_edge(1, 3) - assert nx.is_isomorphic(actual, expected) - - -def test_condensation_as_quotient(): - """This tests that the condensation of a graph can be viewed as the - quotient graph under the "in the same connected component" equivalence - relation. - - """ - # This example graph comes from the file `test_strongly_connected.py`. - G = nx.DiGraph() - G.add_edges_from( - [ - (1, 2), - (2, 3), - (2, 11), - (2, 12), - (3, 4), - (4, 3), - (4, 5), - (5, 6), - (6, 5), - (6, 7), - (7, 8), - (7, 9), - (7, 10), - (8, 9), - (9, 7), - (10, 6), - (11, 2), - (11, 4), - (11, 6), - (12, 6), - (12, 11), - ] - ) - scc = list(nx.strongly_connected_components(G)) - C = nx.condensation(G, scc) - component_of = C.graph["mapping"] - # Two nodes are equivalent if they are in the same connected component. - - def same_component(u, v): - return component_of[u] == component_of[v] - - Q = nx.quotient_graph(G, same_component) - assert nx.is_isomorphic(C, Q) - - -def test_path(): - G = nx.path_graph(6) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_path__partition_provided_as_dict_of_lists(): - G = nx.path_graph(6) - partition = {0: [0, 1], 2: [2, 3], 4: [4, 5]} - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_path__partition_provided_as_dict_of_tuples(): - G = nx.path_graph(6) - partition = {0: (0, 1), 2: (2, 3), 4: (4, 5)} - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_path__partition_provided_as_dict_of_sets(): - G = nx.path_graph(6) - partition = {0: {0, 1}, 2: {2, 3}, 4: {4, 5}} - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_multigraph_path(): - G = nx.MultiGraph(nx.path_graph(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_directed_path(): - G = nx.DiGraph() - nx.add_path(G, range(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 0.5 - - -def test_directed_multigraph_path(): - G = nx.MultiDiGraph() - nx.add_path(G, range(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 0.5 - - -def test_overlapping_blocks(): - with pytest.raises(nx.NetworkXException): - G = nx.path_graph(6) - partition = [{0, 1, 2}, {2, 3}, {4, 5}] - nx.quotient_graph(G, partition) - - -def test_weighted_path(): - G = nx.path_graph(6) - for i in range(5): - G[i][i + 1]["w"] = i + 1 - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, weight="w", relabel=True) - assert nodes_equal(M, [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - assert M[0][1]["weight"] == 2 - assert M[1][2]["weight"] == 4 - for n in M: - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1 - - -def test_barbell(): - G = nx.barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1]) - assert edges_equal(M.edges(), [(0, 1)]) - for n in M: - assert M.nodes[n]["nedges"] == 3 - assert M.nodes[n]["nnodes"] == 3 - assert M.nodes[n]["density"] == 1 - - -def test_barbell_plus(): - G = nx.barbell_graph(3, 0) - # Add an extra edge joining the bells. - G.add_edge(0, 5) - partition = [{0, 1, 2}, {3, 4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M, [0, 1]) - assert edges_equal(M.edges(), [(0, 1)]) - assert M[0][1]["weight"] == 2 - for n in M: - assert M.nodes[n]["nedges"] == 3 - assert M.nodes[n]["nnodes"] == 3 - assert M.nodes[n]["density"] == 1 - - -def test_blockmodel(): - G = nx.path_graph(6) - partition = [[0, 1], [2, 3], [4, 5]] - M = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(M.nodes(), [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M.nodes(): - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1.0 - - -def test_multigraph_blockmodel(): - G = nx.MultiGraph(nx.path_graph(6)) - partition = [[0, 1], [2, 3], [4, 5]] - M = nx.quotient_graph(G, partition, create_using=nx.MultiGraph(), relabel=True) - assert nodes_equal(M.nodes(), [0, 1, 2]) - assert edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M.nodes(): - assert M.nodes[n]["nedges"] == 1 - assert M.nodes[n]["nnodes"] == 2 - assert M.nodes[n]["density"] == 1.0 - - -def test_quotient_graph_incomplete_partition(): - G = nx.path_graph(6) - partition = [] - H = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(H.nodes(), []) - assert edges_equal(H.edges(), []) - - partition = [[0, 1], [2, 3], [5]] - H = nx.quotient_graph(G, partition, relabel=True) - assert nodes_equal(H.nodes(), [0, 1, 2]) - assert edges_equal(H.edges(), [(0, 1)]) - - -def test_undirected_node_contraction(): - """Tests for node contraction in an undirected graph.""" - G = nx.cycle_graph(4) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.cycle_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - -def test_directed_node_contraction(): - """Tests for node contraction in a directed graph.""" - G = nx.DiGraph(nx.cycle_graph(4)) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.DiGraph(nx.cycle_graph(3)) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - -def test_undirected_node_contraction_no_copy(): - """Tests for node contraction in an undirected graph - by making changes in place.""" - G = nx.cycle_graph(4) - actual = nx.contracted_nodes(G, 0, 1, copy=False) - expected = nx.cycle_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, G) - assert nx.is_isomorphic(actual, expected) - - -def test_directed_node_contraction_no_copy(): - """Tests for node contraction in a directed graph - by making changes in place.""" - G = nx.DiGraph(nx.cycle_graph(4)) - actual = nx.contracted_nodes(G, 0, 1, copy=False) - expected = nx.DiGraph(nx.cycle_graph(3)) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, G) - assert nx.is_isomorphic(actual, expected) - - -def test_create_multigraph(): - """Tests that using a MultiGraph creates multiple edges.""" - G = nx.path_graph(3, create_using=nx.MultiGraph()) - G.add_edge(0, 1) - G.add_edge(0, 0) - G.add_edge(0, 2) - actual = nx.contracted_nodes(G, 0, 2) - expected = nx.MultiGraph() - expected.add_edge(0, 1) - expected.add_edge(0, 1) - expected.add_edge(0, 1) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert edges_equal(actual.edges, expected.edges) - - -def test_multigraph_keys(): - """Tests that multiedge keys are reset in new graph.""" - G = nx.path_graph(3, create_using=nx.MultiGraph()) - G.add_edge(0, 1, 5) - G.add_edge(0, 0, 0) - G.add_edge(0, 2, 5) - actual = nx.contracted_nodes(G, 0, 2) - expected = nx.MultiGraph() - expected.add_edge(0, 1, 0) - expected.add_edge(0, 1, 5) - expected.add_edge(0, 1, 2) # keyed as 2 b/c 2 edges already in G - expected.add_edge(0, 0, 0) - expected.add_edge(0, 0, 1) # this comes from (0, 2, 5) - assert edges_equal(actual.edges, expected.edges) - - -def test_node_attributes(): - """Tests that node contraction preserves node attributes.""" - G = nx.cycle_graph(4) - # Add some data to the two nodes being contracted. - G.nodes[0]["foo"] = "bar" - G.nodes[1]["baz"] = "xyzzy" - actual = nx.contracted_nodes(G, 0, 1) - # We expect that contracting the nodes 0 and 1 in C_4 yields K_3, but - # with nodes labeled 0, 2, and 3, and with a -loop on 0. - expected = nx.complete_graph(3) - expected = nx.relabel_nodes(expected, {1: 2, 2: 3}) - expected.add_edge(0, 0) - cdict = {1: {"baz": "xyzzy"}} - expected.nodes[0].update({"foo": "bar", "contraction": cdict}) - assert nx.is_isomorphic(actual, expected) - assert actual.nodes == expected.nodes - - -def test_edge_attributes(): - """Tests that node contraction preserves edge attributes.""" - # Shape: src1 --> dest <-- src2 - G = nx.DiGraph([("src1", "dest"), ("src2", "dest")]) - G["src1"]["dest"]["value"] = "src1-->dest" - G["src2"]["dest"]["value"] = "src2-->dest" - H = nx.MultiDiGraph(G) - - G = nx.contracted_nodes(G, "src1", "src2") # New Shape: src1 --> dest - assert G.edges[("src1", "dest")]["value"] == "src1-->dest" - assert ( - G.edges[("src1", "dest")]["contraction"][("src2", "dest")]["value"] - == "src2-->dest" - ) - - H = nx.contracted_nodes(H, "src1", "src2") # New Shape: src1 -(x2)-> dest - assert len(H.edges(("src1", "dest"))) == 2 - - -def test_without_self_loops(): - """Tests for node contraction without preserving -loops.""" - G = nx.cycle_graph(4) - actual = nx.contracted_nodes(G, 0, 1, self_loops=False) - expected = nx.complete_graph(3) - assert nx.is_isomorphic(actual, expected) - - -def test_contract_loop_graph(): - """Tests for node contraction when nodes have loops.""" - G = nx.cycle_graph(4) - G.add_edge(0, 0) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.complete_graph([0, 2, 3]) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert edges_equal(actual.edges, expected.edges) - actual = nx.contracted_nodes(G, 1, 0) - expected = nx.complete_graph([1, 2, 3]) - expected.add_edge(1, 1) - expected.add_edge(1, 1) - assert edges_equal(actual.edges, expected.edges) - - -def test_undirected_edge_contraction(): - """Tests for edge contraction in an undirected graph.""" - G = nx.cycle_graph(4) - actual = nx.contracted_edge(G, (0, 1)) - expected = nx.complete_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - -def test_multigraph_edge_contraction(): - """Tests for edge contraction in a multigraph""" - G = nx.cycle_graph(4) - actual = nx.contracted_edge(G, (0, 1, 0)) - expected = nx.complete_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - -def test_nonexistent_edge(): - """Tests that attempting to contract a nonexistent edge raises an - exception. - - """ - with pytest.raises(ValueError): - G = nx.cycle_graph(4) - nx.contracted_edge(G, (0, 2)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/mis.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/mis.py deleted file mode 100644 index 0652ac4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/mis.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Algorithm to find a maximal (not maximum) independent set. - -""" - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ["maximal_independent_set"] - - -@not_implemented_for("directed") -@py_random_state(2) -@nx._dispatchable -def maximal_independent_set(G, nodes=None, seed=None): - """Returns a random maximal independent set guaranteed to contain - a given set of nodes. - - An independent set is a set of nodes such that the subgraph - of G induced by these nodes contains no edges. A maximal - independent set is an independent set such that it is not possible - to add a new node and still get an independent set. - - Parameters - ---------- - G : NetworkX graph - - nodes : list or iterable - Nodes that must be part of the independent set. This set of nodes - must be independent. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - indep_nodes : list - List of nodes that are part of a maximal independent set. - - Raises - ------ - NetworkXUnfeasible - If the nodes in the provided list are not part of the graph or - do not form an independent set, an exception is raised. - - NetworkXNotImplemented - If `G` is directed. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.maximal_independent_set(G) # doctest: +SKIP - [4, 0, 2] - >>> nx.maximal_independent_set(G, [1]) # doctest: +SKIP - [1, 3] - - Notes - ----- - This algorithm does not solve the maximum independent set problem. - - """ - if not nodes: - nodes = {seed.choice(list(G))} - else: - nodes = set(nodes) - if not nodes.issubset(G): - raise nx.NetworkXUnfeasible(f"{nodes} is not a subset of the nodes of G") - neighbors = set.union(*[set(G.adj[v]) for v in nodes]) - if set.intersection(neighbors, nodes): - raise nx.NetworkXUnfeasible(f"{nodes} is not an independent set of G") - indep_nodes = list(nodes) - available_nodes = set(G.nodes()).difference(neighbors.union(nodes)) - while available_nodes: - node = seed.choice(list(available_nodes)) - indep_nodes.append(node) - available_nodes.difference_update(list(G.adj[node]) + [node]) - return indep_nodes diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/moral.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/moral.py deleted file mode 100644 index e2acf80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/moral.py +++ /dev/null @@ -1,59 +0,0 @@ -r"""Function for computing the moral graph of a directed graph.""" - -import itertools - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["moral_graph"] - - -@not_implemented_for("undirected") -@nx._dispatchable(returns_graph=True) -def moral_graph(G): - r"""Return the Moral Graph - - Returns the moralized graph of a given directed graph. - - Parameters - ---------- - G : NetworkX graph - Directed graph - - Returns - ------- - H : NetworkX graph - The undirected moralized graph of G - - Raises - ------ - NetworkXNotImplemented - If `G` is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (2, 5), (3, 4), (4, 3)]) - >>> G_moral = nx.moral_graph(G) - >>> G_moral.edges() - EdgeView([(1, 2), (2, 3), (2, 5), (2, 4), (3, 4)]) - - Notes - ----- - A moral graph is an undirected graph H = (V, E) generated from a - directed Graph, where if a node has more than one parent node, edges - between these parent nodes are inserted and all directed edges become - undirected. - - https://en.wikipedia.org/wiki/Moral_graph - - References - ---------- - .. [1] Wray L. Buntine. 1995. Chain graphs for learning. - In Proceedings of the Eleventh conference on Uncertainty - in artificial intelligence (UAI'95) - """ - H = G.to_undirected() - for preds in G.pred.values(): - predecessors_combinations = itertools.combinations(preds, r=2) - H.add_edges_from(predecessors_combinations) - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/node_classification.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/node_classification.py deleted file mode 100644 index b69a6c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/node_classification.py +++ /dev/null @@ -1,219 +0,0 @@ -"""This module provides the functions for node classification problem. - -The functions in this module are not imported -into the top level `networkx` namespace. -You can access these functions by importing -the `networkx.algorithms.node_classification` modules, -then accessing the functions as attributes of `node_classification`. -For example: - - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> G.nodes[0]["label"] = "A" - >>> G.nodes[3]["label"] = "B" - >>> node_classification.harmonic_function(G) - ['A', 'A', 'B', 'B'] - -References ----------- -Zhu, X., Ghahramani, Z., & Lafferty, J. (2003, August). -Semi-supervised learning using gaussian fields and harmonic functions. -In ICML (Vol. 3, pp. 912-919). -""" - -import networkx as nx - -__all__ = ["harmonic_function", "local_and_global_consistency"] - - -@nx.utils.not_implemented_for("directed") -@nx._dispatchable(node_attrs="label_name") -def harmonic_function(G, max_iter=30, label_name="label"): - """Node classification by Harmonic function - - Function for computing Harmonic function algorithm by Zhu et al. - - Parameters - ---------- - G : NetworkX Graph - max_iter : int - maximum number of iterations allowed - label_name : string - name of target labels to predict - - Returns - ------- - predicted : list - List of length ``len(G)`` with the predicted labels for each node. - - Raises - ------ - NetworkXError - If no nodes in `G` have attribute `label_name`. - - Examples - -------- - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.nodes[0]["label"] = "A" - >>> G.nodes[3]["label"] = "B" - >>> G.nodes(data=True) - NodeDataView({0: {'label': 'A'}, 1: {}, 2: {}, 3: {'label': 'B'}}) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> predicted = node_classification.harmonic_function(G) - >>> predicted - ['A', 'A', 'B', 'B'] - - References - ---------- - Zhu, X., Ghahramani, Z., & Lafferty, J. (2003, August). - Semi-supervised learning using gaussian fields and harmonic functions. - In ICML (Vol. 3, pp. 912-919). - """ - import numpy as np - import scipy as sp - - X = nx.to_scipy_sparse_array(G) # adjacency matrix - labels, label_dict = _get_label_info(G, label_name) - - if labels.shape[0] == 0: - raise nx.NetworkXError( - f"No node on the input graph is labeled by '{label_name}'." - ) - - n_samples = X.shape[0] - n_classes = label_dict.shape[0] - F = np.zeros((n_samples, n_classes)) - - # Build propagation matrix - degrees = X.sum(axis=0) - degrees[degrees == 0] = 1 # Avoid division by 0 - # TODO: csr_array - D = sp.sparse.csr_array(sp.sparse.diags((1.0 / degrees), offsets=0)) - P = (D @ X).tolil() - P[labels[:, 0]] = 0 # labels[:, 0] indicates IDs of labeled nodes - # Build base matrix - B = np.zeros((n_samples, n_classes)) - B[labels[:, 0], labels[:, 1]] = 1 - - for _ in range(max_iter): - F = (P @ F) + B - - return label_dict[np.argmax(F, axis=1)].tolist() - - -@nx.utils.not_implemented_for("directed") -@nx._dispatchable(node_attrs="label_name") -def local_and_global_consistency(G, alpha=0.99, max_iter=30, label_name="label"): - """Node classification by Local and Global Consistency - - Function for computing Local and global consistency algorithm by Zhou et al. - - Parameters - ---------- - G : NetworkX Graph - alpha : float - Clamping factor - max_iter : int - Maximum number of iterations allowed - label_name : string - Name of target labels to predict - - Returns - ------- - predicted : list - List of length ``len(G)`` with the predicted labels for each node. - - Raises - ------ - NetworkXError - If no nodes in `G` have attribute `label_name`. - - Examples - -------- - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.nodes[0]["label"] = "A" - >>> G.nodes[3]["label"] = "B" - >>> G.nodes(data=True) - NodeDataView({0: {'label': 'A'}, 1: {}, 2: {}, 3: {'label': 'B'}}) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> predicted = node_classification.local_and_global_consistency(G) - >>> predicted - ['A', 'A', 'B', 'B'] - - References - ---------- - Zhou, D., Bousquet, O., Lal, T. N., Weston, J., & Schölkopf, B. (2004). - Learning with local and global consistency. - Advances in neural information processing systems, 16(16), 321-328. - """ - import numpy as np - import scipy as sp - - X = nx.to_scipy_sparse_array(G) # adjacency matrix - labels, label_dict = _get_label_info(G, label_name) - - if labels.shape[0] == 0: - raise nx.NetworkXError( - f"No node on the input graph is labeled by '{label_name}'." - ) - - n_samples = X.shape[0] - n_classes = label_dict.shape[0] - F = np.zeros((n_samples, n_classes)) - - # Build propagation matrix - degrees = X.sum(axis=0) - degrees[degrees == 0] = 1 # Avoid division by 0 - # TODO: csr_array - D2 = np.sqrt(sp.sparse.csr_array(sp.sparse.diags((1.0 / degrees), offsets=0))) - P = alpha * ((D2 @ X) @ D2) - # Build base matrix - B = np.zeros((n_samples, n_classes)) - B[labels[:, 0], labels[:, 1]] = 1 - alpha - - for _ in range(max_iter): - F = (P @ F) + B - - return label_dict[np.argmax(F, axis=1)].tolist() - - -def _get_label_info(G, label_name): - """Get and return information of labels from the input graph - - Parameters - ---------- - G : Network X graph - label_name : string - Name of the target label - - Returns - ------- - labels : numpy array, shape = [n_labeled_samples, 2] - Array of pairs of labeled node ID and label ID - label_dict : numpy array, shape = [n_classes] - Array of labels - i-th element contains the label corresponding label ID `i` - """ - import numpy as np - - labels = [] - label_to_id = {} - lid = 0 - for i, n in enumerate(G.nodes(data=True)): - if label_name in n[1]: - label = n[1][label_name] - if label not in label_to_id: - label_to_id[label] = lid - lid += 1 - labels.append([i, label_to_id[label]]) - labels = np.array(labels) - label_dict = np.array( - [label for label, _ in sorted(label_to_id.items(), key=lambda x: x[1])] - ) - return (labels, label_dict) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/non_randomness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/non_randomness.py deleted file mode 100644 index 1379911..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/non_randomness.py +++ /dev/null @@ -1,98 +0,0 @@ -r"""Computation of graph non-randomness""" - -import math - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["non_randomness"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def non_randomness(G, k=None, weight="weight"): - """Compute the non-randomness of graph G. - - The first returned value nr is the sum of non-randomness values of all - edges within the graph (where the non-randomness of an edge tends to be - small when the two nodes linked by that edge are from two different - communities). - - The second computed value nr_rd is a relative measure that indicates - to what extent graph G is different from random graphs in terms - of probability. When it is close to 0, the graph tends to be more - likely generated by an Erdos Renyi model. - - Parameters - ---------- - G : NetworkX graph - Graph must be symmetric, connected, and without self-loops. - - k : int - The number of communities in G. - If k is not set, the function will use a default community - detection algorithm to set it. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1, i.e., the graph is - binary. - - Returns - ------- - non-randomness : (float, float) tuple - Non-randomness, Relative non-randomness w.r.t. - Erdos Renyi random graphs. - - Raises - ------ - NetworkXException - if the input graph is not connected. - NetworkXError - if the input graph contains self-loops or if graph has no edges. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> nr, nr_rd = nx.non_randomness(G, 2) - >>> nr, nr_rd = nx.non_randomness(G, 2, "weight") - - Notes - ----- - This computes Eq. (4.4) and (4.5) in Ref. [1]_. - - If a weight field is passed, this algorithm will use the eigenvalues - of the weighted adjacency matrix to compute Eq. (4.4) and (4.5). - - References - ---------- - .. [1] Xiaowei Ying and Xintao Wu, - On Randomness Measures for Social Networks, - SIAM International Conference on Data Mining. 2009 - """ - import numpy as np - - # corner case: graph has no edges - if nx.is_empty(G): - raise nx.NetworkXError("non_randomness not applicable to empty graphs") - if not nx.is_connected(G): - raise nx.NetworkXException("Non connected graph.") - if len(list(nx.selfloop_edges(G))) > 0: - raise nx.NetworkXError("Graph must not contain self-loops") - - if k is None: - k = len(tuple(nx.community.label_propagation_communities(G))) - - # eq. 4.4 - eigenvalues = np.linalg.eigvals(nx.to_numpy_array(G, weight=weight)) - nr = float(np.real(np.sum(eigenvalues[:k]))) - - n = G.number_of_nodes() - m = G.number_of_edges() - p = (2 * k * m) / (n * (n - k)) - - # eq. 4.5 - nr_rd = (nr - ((n - 2 * k) * p + k)) / math.sqrt(2 * k * p * (1 - p)) - - return nr, nr_rd diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/__init__.py deleted file mode 100644 index 0ebc6ab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from networkx.algorithms.operators.all import * -from networkx.algorithms.operators.binary import * -from networkx.algorithms.operators.product import * -from networkx.algorithms.operators.unary import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/all.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/all.py deleted file mode 100644 index 549d335..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/all.py +++ /dev/null @@ -1,321 +0,0 @@ -"""Operations on many graphs.""" - -from itertools import chain, repeat - -import networkx as nx - -__all__ = ["union_all", "compose_all", "disjoint_union_all", "intersection_all"] - - -@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True) -def union_all(graphs, rename=()): - """Returns the union of all graphs. - - The graphs must be disjoint, otherwise an exception is raised. - - Parameters - ---------- - graphs : iterable - Iterable of NetworkX graphs - - rename : iterable , optional - Node names of graphs can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". Infinite generators (like itertools.count) - are also supported. - - Returns - ------- - U : a graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - NetworkXError - In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs. - - Notes - ----- - For operating on mixed type graphs, they should be converted to the same type. - >>> G = nx.Graph() - >>> H = nx.DiGraph() - >>> GH = union_all([nx.DiGraph(G), H]) - - To force a disjoint union with node relabeling, use - disjoint_union_all(G,H) or convert_node_labels_to integers(). - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - - Examples - -------- - >>> G1 = nx.Graph([(1, 2), (2, 3)]) - >>> G2 = nx.Graph([(4, 5), (5, 6)]) - >>> result_graph = nx.union_all([G1, G2]) - >>> result_graph.nodes() - NodeView((1, 2, 3, 4, 5, 6)) - >>> result_graph.edges() - EdgeView([(1, 2), (2, 3), (4, 5), (5, 6)]) - - See Also - -------- - union - disjoint_union_all - """ - R = None - seen_nodes = set() - - # rename graph to obtain disjoint node labels - def add_prefix(graph, prefix): - if prefix is None: - return graph - - def label(x): - return f"{prefix}{x}" - - return nx.relabel_nodes(graph, label) - - rename = chain(rename, repeat(None)) - graphs = (add_prefix(G, name) for G, name in zip(graphs, rename)) - - for i, G in enumerate(graphs): - G_nodes_set = set(G.nodes) - if i == 0: - # Union is the same type as first graph - R = G.__class__() - elif G.is_directed() != R.is_directed(): - raise nx.NetworkXError("All graphs must be directed or undirected.") - elif G.is_multigraph() != R.is_multigraph(): - raise nx.NetworkXError("All graphs must be graphs or multigraphs.") - elif not seen_nodes.isdisjoint(G_nodes_set): - raise nx.NetworkXError( - "The node sets of the graphs are not disjoint.\n" - "Use `rename` to specify prefixes for the graphs or use\n" - "disjoint_union(G1, G2, ..., GN)." - ) - - seen_nodes |= G_nodes_set - R.graph.update(G.graph) - R.add_nodes_from(G.nodes(data=True)) - R.add_edges_from( - G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True) - ) - - if R is None: - raise ValueError("cannot apply union_all to an empty list") - - return R - - -@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True) -def disjoint_union_all(graphs): - """Returns the disjoint union of all graphs. - - This operation forces distinct integer node labels starting with 0 - for the first graph in the list and numbering consecutively. - - Parameters - ---------- - graphs : iterable - Iterable of NetworkX graphs - - Returns - ------- - U : A graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - NetworkXError - In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs. - - Examples - -------- - >>> G1 = nx.Graph([(1, 2), (2, 3)]) - >>> G2 = nx.Graph([(4, 5), (5, 6)]) - >>> U = nx.disjoint_union_all([G1, G2]) - >>> list(U.nodes()) - [0, 1, 2, 3, 4, 5] - >>> list(U.edges()) - [(0, 1), (1, 2), (3, 4), (4, 5)] - - Notes - ----- - For operating on mixed type graphs, they should be converted to the same type. - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - """ - - def yield_relabeled(graphs): - first_label = 0 - for G in graphs: - yield nx.convert_node_labels_to_integers(G, first_label=first_label) - first_label += len(G) - - R = union_all(yield_relabeled(graphs)) - - return R - - -@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True) -def compose_all(graphs): - """Returns the composition of all graphs. - - Composition is the simple union of the node sets and edge sets. - The node sets of the supplied graphs need not be disjoint. - - Parameters - ---------- - graphs : iterable - Iterable of NetworkX graphs - - Returns - ------- - C : A graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - NetworkXError - In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs. - - Examples - -------- - >>> G1 = nx.Graph([(1, 2), (2, 3)]) - >>> G2 = nx.Graph([(3, 4), (5, 6)]) - >>> C = nx.compose_all([G1, G2]) - >>> list(C.nodes()) - [1, 2, 3, 4, 5, 6] - >>> list(C.edges()) - [(1, 2), (2, 3), (3, 4), (5, 6)] - - Notes - ----- - For operating on mixed type graphs, they should be converted to the same type. - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - """ - R = None - - # add graph attributes, H attributes take precedent over G attributes - for i, G in enumerate(graphs): - if i == 0: - # create new graph - R = G.__class__() - elif G.is_directed() != R.is_directed(): - raise nx.NetworkXError("All graphs must be directed or undirected.") - elif G.is_multigraph() != R.is_multigraph(): - raise nx.NetworkXError("All graphs must be graphs or multigraphs.") - - R.graph.update(G.graph) - R.add_nodes_from(G.nodes(data=True)) - R.add_edges_from( - G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True) - ) - - if R is None: - raise ValueError("cannot apply compose_all to an empty list") - - return R - - -@nx._dispatchable(graphs="[graphs]", returns_graph=True) -def intersection_all(graphs): - """Returns a new graph that contains only the nodes and the edges that exist in - all graphs. - - Parameters - ---------- - graphs : iterable - Iterable of NetworkX graphs - - Returns - ------- - R : A new graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - NetworkXError - In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs. - - Notes - ----- - For operating on mixed type graphs, they should be converted to the same type. - - Attributes from the graph, nodes, and edges are not copied to the new - graph. - - The resulting graph can be updated with attributes if desired. For example, code which adds the minimum attribute for each node across all graphs could work. - >>> g = nx.Graph() - >>> g.add_node(0, capacity=4) - >>> g.add_node(1, capacity=3) - >>> g.add_edge(0, 1) - - >>> h = g.copy() - >>> h.nodes[0]["capacity"] = 2 - - >>> gh = nx.intersection_all([g, h]) - - >>> new_node_attr = { - ... n: min(*(anyG.nodes[n].get("capacity", float("inf")) for anyG in [g, h])) - ... for n in gh - ... } - >>> nx.set_node_attributes(gh, new_node_attr, "new_capacity") - >>> gh.nodes(data=True) - NodeDataView({0: {'new_capacity': 2}, 1: {'new_capacity': 3}}) - - Examples - -------- - >>> G1 = nx.Graph([(1, 2), (2, 3)]) - >>> G2 = nx.Graph([(2, 3), (3, 4)]) - >>> R = nx.intersection_all([G1, G2]) - >>> list(R.nodes()) - [2, 3] - >>> list(R.edges()) - [(2, 3)] - - """ - R = None - - for i, G in enumerate(graphs): - G_nodes_set = set(G.nodes) - G_edges_set = set(G.edges) - if not G.is_directed(): - if G.is_multigraph(): - G_edges_set.update((v, u, k) for u, v, k in list(G_edges_set)) - else: - G_edges_set.update((v, u) for u, v in list(G_edges_set)) - if i == 0: - # create new graph - R = G.__class__() - node_intersection = G_nodes_set - edge_intersection = G_edges_set - elif G.is_directed() != R.is_directed(): - raise nx.NetworkXError("All graphs must be directed or undirected.") - elif G.is_multigraph() != R.is_multigraph(): - raise nx.NetworkXError("All graphs must be graphs or multigraphs.") - else: - node_intersection &= G_nodes_set - edge_intersection &= G_edges_set - - if R is None: - raise ValueError("cannot apply intersection_all to an empty list") - - R.add_nodes_from(node_intersection) - R.add_edges_from(edge_intersection) - - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/binary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/binary.py deleted file mode 100644 index 08907bf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/binary.py +++ /dev/null @@ -1,450 +0,0 @@ -""" -Operations on graphs including union, intersection, difference. -""" - -import networkx as nx - -__all__ = [ - "union", - "compose", - "disjoint_union", - "intersection", - "difference", - "symmetric_difference", - "full_join", -] -_G_H = {"G": 0, "H": 1} - - -@nx._dispatchable(graphs=_G_H, preserve_all_attrs=True, returns_graph=True) -def union(G, H, rename=()): - """Combine graphs G and H. The names of nodes must be unique. - - A name collision between the graphs will raise an exception. - - A renaming facility is provided to avoid name collisions. - - - Parameters - ---------- - G, H : graph - A NetworkX graph - - rename : iterable , optional - Node names of G and H can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". - - Returns - ------- - U : A union graph with the same type as G. - - See Also - -------- - compose - :func:`~networkx.Graph.update` - disjoint_union - - Notes - ----- - To combine graphs that have common nodes, consider compose(G, H) - or the method, Graph.update(). - - disjoint_union() is similar to union() except that it avoids name clashes - by relabeling the nodes with sequential integers. - - Edge and node attributes are propagated from G and H to the union graph. - Graph attributes are also propagated, but if they are present in both G and H, - then the value from H is used. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)]) - >>> H = nx.Graph([(0, 1), (0, 3), (1, 3), (1, 2)]) - >>> U = nx.union(G, H, rename=("G", "H")) - >>> U.nodes - NodeView(('G0', 'G1', 'G2', 'H0', 'H1', 'H3', 'H2')) - >>> U.edges - EdgeView([('G0', 'G1'), ('G0', 'G2'), ('G1', 'G2'), ('H0', 'H1'), ('H0', 'H3'), ('H1', 'H3'), ('H1', 'H2')]) - - - """ - return nx.union_all([G, H], rename) - - -@nx._dispatchable(graphs=_G_H, preserve_all_attrs=True, returns_graph=True) -def disjoint_union(G, H): - """Combine graphs G and H. The nodes are assumed to be unique (disjoint). - - This algorithm automatically relabels nodes to avoid name collisions. - - Parameters - ---------- - G,H : graph - A NetworkX graph - - Returns - ------- - U : A union graph with the same type as G. - - See Also - -------- - union - compose - :func:`~networkx.Graph.update` - - Notes - ----- - A new graph is created, of the same class as G. It is recommended - that G and H be either both directed or both undirected. - - The nodes of G are relabeled 0 to len(G)-1, and the nodes of H are - relabeled len(G) to len(G)+len(H)-1. - - Renumbering forces G and H to be disjoint, so no exception is ever raised for a name collision. - To preserve the check for common nodes, use union(). - - Edge and node attributes are propagated from G and H to the union graph. - Graph attributes are also propagated, but if they are present in both G and H, - then the value from H is used. - - To combine graphs that have common nodes, consider compose(G, H) - or the method, Graph.update(). - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)]) - >>> H = nx.Graph([(0, 3), (1, 2), (2, 3)]) - >>> G.nodes[0]["key1"] = 5 - >>> H.nodes[0]["key2"] = 10 - >>> U = nx.disjoint_union(G, H) - >>> U.nodes(data=True) - NodeDataView({0: {'key1': 5}, 1: {}, 2: {}, 3: {'key2': 10}, 4: {}, 5: {}, 6: {}}) - >>> U.edges - EdgeView([(0, 1), (0, 2), (1, 2), (3, 4), (4, 6), (5, 6)]) - """ - return nx.disjoint_union_all([G, H]) - - -@nx._dispatchable(graphs=_G_H, returns_graph=True) -def intersection(G, H): - """Returns a new graph that contains only the nodes and the edges that exist in - both G and H. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H can have different node sets but must be both graphs or both multigraphs. - - Raises - ------ - NetworkXError - If one is a MultiGraph and the other one is a graph. - - Returns - ------- - GH : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. If you want a new graph of the intersection of G and H - with the attributes (including edge data) from G use remove_nodes_from() - as follows - - >>> G = nx.path_graph(3) - >>> H = nx.path_graph(5) - >>> R = G.copy() - >>> R.remove_nodes_from(n for n in G if n not in H) - >>> R.remove_edges_from(e for e in G.edges if e not in H.edges) - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)]) - >>> H = nx.Graph([(0, 3), (1, 2), (2, 3)]) - >>> R = nx.intersection(G, H) - >>> R.nodes - NodeView((0, 1, 2)) - >>> R.edges - EdgeView([(1, 2)]) - """ - return nx.intersection_all([G, H]) - - -@nx._dispatchable(graphs=_G_H, returns_graph=True) -def difference(G, H): - """Returns a new graph that contains the edges that exist in G but not in H. - - The node sets of H and G must be the same. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H must have the same node sets. - - Returns - ------- - D : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. If you want a new graph of the difference of G and H with - the attributes (including edge data) from G use remove_nodes_from() - as follows: - - >>> G = nx.path_graph(3) - >>> H = nx.path_graph(5) - >>> R = G.copy() - >>> R.remove_nodes_from(n for n in G if n in H) - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3)]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 3)]) - >>> R = nx.difference(G, H) - >>> R.nodes - NodeView((0, 1, 2, 3)) - >>> R.edges - EdgeView([(0, 2), (1, 3)]) - """ - # create new graph - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError("G and H must both be graphs or multigraphs.") - R = nx.create_empty_copy(G, with_data=False) - - if set(G) != set(H): - raise nx.NetworkXError("Node sets of graphs not equal") - - if G.is_multigraph(): - edges = G.edges(keys=True) - else: - edges = G.edges() - for e in edges: - if not H.has_edge(*e): - R.add_edge(*e) - return R - - -@nx._dispatchable(graphs=_G_H, returns_graph=True) -def symmetric_difference(G, H): - """Returns new graph with edges that exist in either G or H but not both. - - The node sets of H and G must be the same. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H must have the same node sets. - - Returns - ------- - D : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3)]) - >>> H = nx.Graph([(0, 1), (1, 2), (0, 3)]) - >>> R = nx.symmetric_difference(G, H) - >>> R.nodes - NodeView((0, 1, 2, 3)) - >>> R.edges - EdgeView([(0, 2), (0, 3), (1, 3)]) - """ - # create new graph - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError("G and H must both be graphs or multigraphs.") - R = nx.create_empty_copy(G, with_data=False) - - if set(G) != set(H): - raise nx.NetworkXError("Node sets of graphs not equal") - - gnodes = set(G) # set of nodes in G - hnodes = set(H) # set of nodes in H - nodes = gnodes.symmetric_difference(hnodes) - R.add_nodes_from(nodes) - - if G.is_multigraph(): - edges = G.edges(keys=True) - else: - edges = G.edges() - # we could copy the data here but then this function doesn't - # match intersection and difference - for e in edges: - if not H.has_edge(*e): - R.add_edge(*e) - - if H.is_multigraph(): - edges = H.edges(keys=True) - else: - edges = H.edges() - for e in edges: - if not G.has_edge(*e): - R.add_edge(*e) - return R - - -@nx._dispatchable(graphs=_G_H, preserve_all_attrs=True, returns_graph=True) -def compose(G, H): - """Compose graph G with H by combining nodes and edges into a single graph. - - The node sets and edges sets do not need to be disjoint. - - Composing preserves the attributes of nodes and edges. - Attribute values from H take precedent over attribute values from G. - - Parameters - ---------- - G, H : graph - A NetworkX graph - - Returns - ------- - C: A new graph with the same type as G - - See Also - -------- - :func:`~networkx.Graph.update` - union - disjoint_union - - Notes - ----- - It is recommended that G and H be either both directed or both undirected. - - For MultiGraphs, the edges are identified by incident nodes AND edge-key. - This can cause surprises (i.e., edge `(1, 2)` may or may not be the same - in two graphs) if you use MultiGraph without keeping track of edge keys. - - If combining the attributes of common nodes is not desired, consider union(), - which raises an exception for name collisions. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2)]) - >>> H = nx.Graph([(0, 1), (1, 2)]) - >>> R = nx.compose(G, H) - >>> R.nodes - NodeView((0, 1, 2)) - >>> R.edges - EdgeView([(0, 1), (0, 2), (1, 2)]) - - By default, the attributes from `H` take precedent over attributes from `G`. - If you prefer another way of combining attributes, you can update them after the compose operation: - - >>> G = nx.Graph([(0, 1, {"weight": 2.0}), (3, 0, {"weight": 100.0})]) - >>> H = nx.Graph([(0, 1, {"weight": 10.0}), (1, 2, {"weight": -1.0})]) - >>> nx.set_node_attributes(G, {0: "dark", 1: "light", 3: "black"}, name="color") - >>> nx.set_node_attributes(H, {0: "green", 1: "orange", 2: "yellow"}, name="color") - >>> GcomposeH = nx.compose(G, H) - - Normally, color attribute values of nodes of GcomposeH come from H. We can workaround this as follows: - - >>> node_data = { - ... n: G.nodes[n]["color"] + " " + H.nodes[n]["color"] - ... for n in G.nodes & H.nodes - ... } - >>> nx.set_node_attributes(GcomposeH, node_data, "color") - >>> print(GcomposeH.nodes[0]["color"]) - dark green - - >>> print(GcomposeH.nodes[3]["color"]) - black - - Similarly, we can update edge attributes after the compose operation in a way we prefer: - - >>> edge_data = { - ... e: G.edges[e]["weight"] * H.edges[e]["weight"] for e in G.edges & H.edges - ... } - >>> nx.set_edge_attributes(GcomposeH, edge_data, "weight") - >>> print(GcomposeH.edges[(0, 1)]["weight"]) - 20.0 - - >>> print(GcomposeH.edges[(3, 0)]["weight"]) - 100.0 - """ - return nx.compose_all([G, H]) - - -@nx._dispatchable(graphs=_G_H, preserve_all_attrs=True, returns_graph=True) -def full_join(G, H, rename=(None, None)): - """Returns the full join of graphs G and H. - - Full join is the union of G and H in which all edges between - G and H are added. - The node sets of G and H must be disjoint, - otherwise an exception is raised. - - Parameters - ---------- - G, H : graph - A NetworkX graph - - rename : tuple , default=(None, None) - Node names of G and H can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". - - Returns - ------- - U : The full join graph with the same type as G. - - Notes - ----- - It is recommended that G and H be either both directed or both undirected. - - If G is directed, then edges from G to H are added as well as from H to G. - - Note that full_join() does not produce parallel edges for MultiGraphs. - - The full join operation of graphs G and H is the same as getting - their complement, performing a disjoint union, and finally getting - the complement of the resulting graph. - - Graph, edge, and node attributes are propagated from G and H - to the union graph. If a graph attribute is present in both - G and H the value from H is used. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2)]) - >>> H = nx.Graph([(3, 4)]) - >>> R = nx.full_join(G, H, rename=("G", "H")) - >>> R.nodes - NodeView(('G0', 'G1', 'G2', 'H3', 'H4')) - >>> R.edges - EdgeView([('G0', 'G1'), ('G0', 'G2'), ('G0', 'H3'), ('G0', 'H4'), ('G1', 'H3'), ('G1', 'H4'), ('G2', 'H3'), ('G2', 'H4'), ('H3', 'H4')]) - - See Also - -------- - union - disjoint_union - """ - R = union(G, H, rename) - - def add_prefix(graph, prefix): - if prefix is None: - return graph - - def label(x): - return f"{prefix}{x}" - - return nx.relabel_nodes(graph, label) - - G = add_prefix(G, rename[0]) - H = add_prefix(H, rename[1]) - - for i in G: - for j in H: - R.add_edge(i, j) - if R.is_directed(): - for i in H: - for j in G: - R.add_edge(i, j) - - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/product.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/product.py deleted file mode 100644 index 28ca78b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/product.py +++ /dev/null @@ -1,633 +0,0 @@ -""" -Graph products. -""" - -from itertools import product - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "tensor_product", - "cartesian_product", - "lexicographic_product", - "strong_product", - "power", - "rooted_product", - "corona_product", - "modular_product", -] -_G_H = {"G": 0, "H": 1} - - -def _dict_product(d1, d2): - return {k: (d1.get(k), d2.get(k)) for k in set(d1) | set(d2)} - - -# Generators for producing graph products -def _node_product(G, H): - for u, v in product(G, H): - yield ((u, v), _dict_product(G.nodes[u], H.nodes[v])) - - -def _directed_edges_cross_edges(G, H): - if not G.is_multigraph() and not H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - yield (u, x), (v, y), _dict_product(c, d) - if not G.is_multigraph() and H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (u, x), (v, y), k, _dict_product(c, d) - if G.is_multigraph() and not H.is_multigraph(): - for u, v, k, c in G.edges(data=True, keys=True): - for x, y, d in H.edges(data=True): - yield (u, x), (v, y), k, _dict_product(c, d) - if G.is_multigraph() and H.is_multigraph(): - for u, v, j, c in G.edges(data=True, keys=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (u, x), (v, y), (j, k), _dict_product(c, d) - - -def _undirected_edges_cross_edges(G, H): - if not G.is_multigraph() and not H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - yield (v, x), (u, y), _dict_product(c, d) - if not G.is_multigraph() and H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (v, x), (u, y), k, _dict_product(c, d) - if G.is_multigraph() and not H.is_multigraph(): - for u, v, k, c in G.edges(data=True, keys=True): - for x, y, d in H.edges(data=True): - yield (v, x), (u, y), k, _dict_product(c, d) - if G.is_multigraph() and H.is_multigraph(): - for u, v, j, c in G.edges(data=True, keys=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (v, x), (u, y), (j, k), _dict_product(c, d) - - -def _edges_cross_nodes(G, H): - if G.is_multigraph(): - for u, v, k, d in G.edges(data=True, keys=True): - for x in H: - yield (u, x), (v, x), k, d - else: - for u, v, d in G.edges(data=True): - for x in H: - if H.is_multigraph(): - yield (u, x), (v, x), None, d - else: - yield (u, x), (v, x), d - - -def _nodes_cross_edges(G, H): - if H.is_multigraph(): - for x in G: - for u, v, k, d in H.edges(data=True, keys=True): - yield (x, u), (x, v), k, d - else: - for x in G: - for u, v, d in H.edges(data=True): - if G.is_multigraph(): - yield (x, u), (x, v), None, d - else: - yield (x, u), (x, v), d - - -def _edges_cross_nodes_and_nodes(G, H): - if G.is_multigraph(): - for u, v, k, d in G.edges(data=True, keys=True): - for x in H: - for y in H: - yield (u, x), (v, y), k, d - else: - for u, v, d in G.edges(data=True): - for x in H: - for y in H: - if H.is_multigraph(): - yield (u, x), (v, y), None, d - else: - yield (u, x), (v, y), d - - -def _init_product_graph(G, H): - if G.is_directed() != H.is_directed(): - msg = "G and H must be both directed or both undirected" - raise nx.NetworkXError(msg) - if G.is_multigraph() or H.is_multigraph(): - GH = nx.MultiGraph() - else: - GH = nx.Graph() - if G.is_directed(): - GH = GH.to_directed() - return GH - - -@nx._dispatchable(graphs=_G_H, preserve_node_attrs=True, returns_graph=True) -def tensor_product(G, H): - r"""Returns the tensor product of G and H. - - The tensor product $P$ of the graphs $G$ and $H$ has a node set that - is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v), (x,y))$ if and only if $(u,x)$ is an edge in $G$ - and $(v,y)$ is an edge in $H$. - - Tensor product is sometimes also referred to as the categorical product, - direct product, cardinal product or conjunction. - - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The tensor product of G and H. P will be a multi-graph if either G - or H is a multi-graph, will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node("a", a2="Spam") - >>> P = nx.tensor_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_directed_edges_cross_edges(G, H)) - if not GH.is_directed(): - GH.add_edges_from(_undirected_edges_cross_edges(G, H)) - return GH - - -@nx._dispatchable(graphs=_G_H, preserve_node_attrs=True, returns_graph=True) -def cartesian_product(G, H): - r"""Returns the Cartesian product of G and H. - - The Cartesian product $P$ of the graphs $G$ and $H$ has a node set that - is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v),(x,y))$ if and only if either $u$ is equal to $x$ - and both $v$ and $y$ are adjacent in $H$ or if $v$ is equal to $y$ and - both $u$ and $x$ are adjacent in $G$. - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node("a", a2="Spam") - >>> P = nx.cartesian_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_edges_cross_nodes(G, H)) - GH.add_edges_from(_nodes_cross_edges(G, H)) - return GH - - -@nx._dispatchable(graphs=_G_H, preserve_node_attrs=True, returns_graph=True) -def lexicographic_product(G, H): - r"""Returns the lexicographic product of G and H. - - The lexicographical product $P$ of the graphs $G$ and $H$ has a node set - that is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v), (x,y))$ if and only if $(u,v)$ is an edge in $G$ - or $u==v$ and $(x,y)$ is an edge in $H$. - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node("a", a2="Spam") - >>> P = nx.lexicographic_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - # Edges in G regardless of H designation - GH.add_edges_from(_edges_cross_nodes_and_nodes(G, H)) - # For each x in G, only if there is an edge in H - GH.add_edges_from(_nodes_cross_edges(G, H)) - return GH - - -@nx._dispatchable(graphs=_G_H, preserve_node_attrs=True, returns_graph=True) -def strong_product(G, H): - r"""Returns the strong product of G and H. - - The strong product $P$ of the graphs $G$ and $H$ has a node set that - is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,x), (v,y))$ if any of the following conditions - are met: - - - $u=v$ and $(x,y)$ is an edge in $H$ - - $x=y$ and $(u,v)$ is an edge in $G$ - - $(u,v)$ is an edge in $G$ and $(x,y)$ is an edge in $H$ - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node("a", a2="Spam") - >>> P = nx.strong_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_nodes_cross_edges(G, H)) - GH.add_edges_from(_edges_cross_nodes(G, H)) - GH.add_edges_from(_directed_edges_cross_edges(G, H)) - if not GH.is_directed(): - GH.add_edges_from(_undirected_edges_cross_edges(G, H)) - return GH - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def power(G, k): - """Returns the specified power of a graph. - - The $k$th power of a simple graph $G$, denoted $G^k$, is a - graph on the same set of nodes in which two distinct nodes $u$ and - $v$ are adjacent in $G^k$ if and only if the shortest path - distance between $u$ and $v$ in $G$ is at most $k$. - - Parameters - ---------- - G : graph - A NetworkX simple graph object. - - k : positive integer - The power to which to raise the graph `G`. - - Returns - ------- - NetworkX simple graph - `G` to the power `k`. - - Raises - ------ - ValueError - If the exponent `k` is not positive. - - NetworkXNotImplemented - If `G` is not a simple graph. - - Examples - -------- - The number of edges will never decrease when taking successive - powers: - - >>> G = nx.path_graph(4) - >>> list(nx.power(G, 2).edges) - [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)] - >>> list(nx.power(G, 3).edges) - [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - - The `k` th power of a cycle graph on *n* nodes is the complete graph - on *n* nodes, if `k` is at least ``n // 2``: - - >>> G = nx.cycle_graph(5) - >>> H = nx.complete_graph(5) - >>> nx.is_isomorphic(nx.power(G, 2), H) - True - >>> G = nx.cycle_graph(8) - >>> H = nx.complete_graph(8) - >>> nx.is_isomorphic(nx.power(G, 4), H) - True - - References - ---------- - .. [1] J. A. Bondy, U. S. R. Murty, *Graph Theory*. Springer, 2008. - - Notes - ----- - This definition of "power graph" comes from Exercise 3.1.6 of - *Graph Theory* by Bondy and Murty [1]_. - - """ - if k <= 0: - raise ValueError("k must be a positive integer") - H = nx.Graph() - H.add_nodes_from(G) - # update BFS code to ignore self loops. - for n in G: - seen = {} # level (number of hops) when seen in BFS - level = 1 # the current level - nextlevel = G[n] - while nextlevel: - thislevel = nextlevel # advance to next level - nextlevel = {} # and start a new list (fringe) - for v in thislevel: - if v == n: # avoid self loop - continue - if v not in seen: - seen[v] = level # set the level of vertex v - nextlevel.update(G[v]) # add neighbors of v - if k <= level: - break - level += 1 - H.add_edges_from((n, nbr) for nbr in seen) - return H - - -@not_implemented_for("multigraph") -@nx._dispatchable(graphs=_G_H, returns_graph=True) -def rooted_product(G, H, root): - """Return the rooted product of graphs G and H rooted at root in H. - - A new graph is constructed representing the rooted product of - the inputted graphs, G and H, with a root in H. - A rooted product duplicates H for each nodes in G with the root - of H corresponding to the node in G. Nodes are renamed as the direct - product of G and H. The result is a subgraph of the cartesian product. - - Parameters - ---------- - G,H : graph - A NetworkX graph - root : node - A node in H - - Returns - ------- - R : The rooted product of G and H with a specified root in H - - Notes - ----- - The nodes of R are the Cartesian Product of the nodes of G and H. - The nodes of G and H are not relabeled. - """ - if root not in H: - raise nx.NodeNotFound("root must be a vertex in H") - - R = nx.Graph() - R.add_nodes_from(product(G, H)) - - R.add_edges_from(((e[0], root), (e[1], root)) for e in G.edges()) - R.add_edges_from(((g, e[0]), (g, e[1])) for g in G for e in H.edges()) - - return R - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(graphs=_G_H, returns_graph=True) -def corona_product(G, H): - r"""Returns the Corona product of G and H. - - The corona product of $G$ and $H$ is the graph $C = G \circ H$ obtained by - taking one copy of $G$, called the center graph, $|V(G)|$ copies of $H$, - called the outer graph, and making the $i$-th vertex of $G$ adjacent to - every vertex of the $i$-th copy of $H$, where $1 ≤ i ≤ |V(G)|$. - - Parameters - ---------- - G, H: NetworkX graphs - The graphs to take the carona product of. - `G` is the center graph and `H` is the outer graph - - Returns - ------- - C: NetworkX graph - The Corona product of G and H. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> H = nx.path_graph(2) - >>> C = nx.corona_product(G, H) - >>> list(C) - [0, 1, 2, 3, (0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)] - >>> print(C) - Graph with 12 nodes and 16 edges - - References - ---------- - [1] M. Tavakoli, F. Rahbarnia, and A. R. Ashrafi, - "Studying the corona product of graphs under some graph invariants," - Transactions on Combinatorics, vol. 3, no. 3, pp. 43–49, Sep. 2014, - doi: 10.22108/toc.2014.5542. - [2] A. Faraji, "Corona Product in Graph Theory," Ali Faraji, May 11, 2021. - https://blog.alifaraji.ir/math/graph-theory/corona-product.html (accessed Dec. 07, 2021). - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(G) - GH.add_edges_from(G.edges) - - for G_node in G: - # copy nodes of H in GH, call it H_i - GH.add_nodes_from((G_node, v) for v in H) - - # copy edges of H_i based on H - GH.add_edges_from( - ((G_node, e0), (G_node, e1), d) for e0, e1, d in H.edges.data() - ) - - # creating new edges between H_i and a G's node - GH.add_edges_from((G_node, (G_node, H_node)) for H_node in H) - - return GH - - -@nx._dispatchable( - graphs=_G_H, preserve_edge_attrs=True, preserve_node_attrs=True, returns_graph=True -) -def modular_product(G, H): - r"""Returns the Modular product of G and H. - - The modular product of `G` and `H` is the graph $M = G \nabla H$, - consisting of the node set $V(M) = V(G) \times V(H)$ that is the Cartesian - product of the node sets of `G` and `H`. Further, M contains an edge ((u, v), (x, y)): - - - if u is adjacent to x in `G` and v is adjacent to y in `H`, or - - if u is not adjacent to x in `G` and v is not adjacent to y in `H`. - - More formally:: - - E(M) = {((u, v), (x, y)) | ((u, x) in E(G) and (v, y) in E(H)) or - ((u, x) not in E(G) and (v, y) not in E(H))} - - Parameters - ---------- - G, H: NetworkX graphs - The graphs to take the modular product of. - - Returns - ------- - M: NetworkX graph - The Modular product of `G` and `H`. - - Raises - ------ - NetworkXNotImplemented - If `G` is not a simple graph. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> H = nx.path_graph(2) - >>> M = nx.modular_product(G, H) - >>> list(M) - [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)] - >>> print(M) - Graph with 8 nodes and 8 edges - - Notes - ----- - The *modular product* is defined in [1]_ and was first - introduced as the *weak modular product*. - - The modular product reduces the problem of counting isomorphic subgraphs - in `G` and `H` to the problem of counting cliques in M. The subgraphs of - `G` and `H` that are induced by the nodes of a clique in M are - isomorphic [2]_ [3]_. - - References - ---------- - .. [1] R. Hammack, W. Imrich, and S. Klavžar, - "Handbook of Product Graphs", CRC Press, 2011. - - .. [2] H. G. Barrow and R. M. Burstall, - "Subgraph isomorphism, matching relational structures and maximal - cliques", Information Processing Letters, vol. 4, issue 4, pp. 83-84, - 1976, https://doi.org/10.1016/0020-0190(76)90049-1. - - .. [3] V. G. Vizing, "Reduction of the problem of isomorphism and isomorphic - entrance to the task of finding the nondensity of a graph." Proc. Third - All-Union Conference on Problems of Theoretical Cybernetics. 1974. - """ - if G.is_directed() or H.is_directed(): - raise nx.NetworkXNotImplemented( - "Modular product not implemented for directed graphs" - ) - if G.is_multigraph() or H.is_multigraph(): - raise nx.NetworkXNotImplemented( - "Modular product not implemented for multigraphs" - ) - - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - GH.add_edge((u, x), (v, y), **_dict_product(c, d)) - GH.add_edge((v, x), (u, y), **_dict_product(c, d)) - - G = nx.complement(G) - H = nx.complement(H) - - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - GH.add_edge((u, x), (v, y), **_dict_product(c, d)) - GH.add_edge((v, x), (u, y), **_dict_product(c, d)) - - return GH diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_all.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_all.py deleted file mode 100644 index 8ec29c1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_all.py +++ /dev/null @@ -1,328 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -def test_union_all_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - - j = g.copy() - j.graph["name"] = "j" - j.graph["attr"] = "attr" - j.nodes[0]["x"] = 7 - - ghj = nx.union_all([g, h, j], rename=("g", "h", "j")) - assert set(ghj.nodes()) == {"h0", "h1", "g0", "g1", "j0", "j1"} - for n in ghj: - graph, node = n - assert ghj.nodes[n] == eval(graph).nodes[int(node)] - - assert ghj.graph["attr"] == "attr" - assert ghj.graph["name"] == "j" # j graph attributes take precedent - - -def test_intersection_all(): - G = nx.Graph() - H = nx.Graph() - R = nx.Graph(awesome=True) - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - R.add_nodes_from([1, 2, 3, 4]) - R.add_edge(2, 3) - R.add_edge(4, 1) - I = nx.intersection_all([G, H, R]) - assert set(I.nodes()) == {1, 2, 3, 4} - assert sorted(I.edges()) == [(2, 3)] - assert I.graph == {} - - -def test_intersection_all_different_node_sets(): - G = nx.Graph() - H = nx.Graph() - R = nx.Graph() - G.add_nodes_from([1, 2, 3, 4, 6, 7]) - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(6, 7) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - R.add_nodes_from([1, 2, 3, 4, 8, 9]) - R.add_edge(2, 3) - R.add_edge(4, 1) - R.add_edge(8, 9) - I = nx.intersection_all([G, H, R]) - assert set(I.nodes()) == {1, 2, 3, 4} - assert sorted(I.edges()) == [(2, 3)] - - -def test_intersection_all_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - -def test_intersection_all_attributes_different_node_sets(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - g.add_node(2) - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - -def test_intersection_all_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0)] - - -def test_intersection_all_multigraph_attributes_different_node_sets(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - g.add_edge(1, 2, key=1) - g.add_edge(1, 2, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=2) - h.add_edge(0, 1, key=3) - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1), (0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0), (0, 1, 2)] - - -def test_intersection_all_digraph(): - g = nx.DiGraph() - g.add_edges_from([(1, 2), (2, 3)]) - h = nx.DiGraph() - h.add_edges_from([(2, 1), (2, 3)]) - gh = nx.intersection_all([g, h]) - assert sorted(gh.edges()) == [(2, 3)] - - -def test_union_all_and_compose_all(): - K3 = nx.complete_graph(3) - P3 = nx.path_graph(3) - - G1 = nx.DiGraph() - G1.add_edge("A", "B") - G1.add_edge("A", "C") - G1.add_edge("A", "D") - G2 = nx.DiGraph() - G2.add_edge("1", "2") - G2.add_edge("1", "3") - G2.add_edge("1", "4") - - G = nx.union_all([G1, G2]) - H = nx.compose_all([G1, G2]) - assert edges_equal(G.edges(), H.edges()) - assert not G.has_edge("A", "1") - pytest.raises(nx.NetworkXError, nx.union, K3, P3) - H1 = nx.union_all([H, G1], rename=("H", "G1")) - assert sorted(H1.nodes()) == [ - "G1A", - "G1B", - "G1C", - "G1D", - "H1", - "H2", - "H3", - "H4", - "HA", - "HB", - "HC", - "HD", - ] - - H2 = nx.union_all([H, G2], rename=("H", "")) - assert sorted(H2.nodes()) == [ - "1", - "2", - "3", - "4", - "H1", - "H2", - "H3", - "H4", - "HA", - "HB", - "HC", - "HD", - ] - - assert not H1.has_edge("NB", "NA") - - G = nx.compose_all([G, G]) - assert edges_equal(G.edges(), H.edges()) - - G2 = nx.union_all([G2, G2], rename=("", "copy")) - assert sorted(G2.nodes()) == [ - "1", - "2", - "3", - "4", - "copy1", - "copy2", - "copy3", - "copy4", - ] - - assert sorted(G2.neighbors("copy4")) == [] - assert sorted(G2.neighbors("copy1")) == ["copy2", "copy3", "copy4"] - assert len(G) == 8 - assert nx.number_of_edges(G) == 6 - - E = nx.disjoint_union_all([G, G]) - assert len(E) == 16 - assert nx.number_of_edges(E) == 12 - - E = nx.disjoint_union_all([G1, G2]) - assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - - G1 = nx.DiGraph() - G1.add_edge("A", "B") - G2 = nx.DiGraph() - G2.add_edge(1, 2) - G3 = nx.DiGraph() - G3.add_edge(11, 22) - G4 = nx.union_all([G1, G2, G3], rename=("G1", "G2", "G3")) - assert sorted(G4.nodes()) == ["G1A", "G1B", "G21", "G22", "G311", "G322"] - - -def test_union_all_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.union_all([G, H]) - assert set(GH) == set(G) | set(H) - assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True)) - - -def test_input_output(): - l = [nx.Graph([(1, 2)]), nx.Graph([(3, 4)], awesome=True)] - U = nx.disjoint_union_all(l) - assert len(l) == 2 - assert U.graph["awesome"] - C = nx.compose_all(l) - assert len(l) == 2 - l = [nx.Graph([(1, 2)]), nx.Graph([(1, 2)])] - R = nx.intersection_all(l) - assert len(l) == 2 - - -def test_mixed_type_union(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.union_all([G, H, I]) - with pytest.raises(nx.NetworkXError): - X = nx.Graph() - Y = nx.DiGraph() - XY = nx.union_all([X, Y]) - - -def test_mixed_type_disjoint_union(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.disjoint_union_all([G, H, I]) - with pytest.raises(nx.NetworkXError): - X = nx.Graph() - Y = nx.DiGraph() - XY = nx.disjoint_union_all([X, Y]) - - -def test_mixed_type_intersection(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.intersection_all([G, H, I]) - with pytest.raises(nx.NetworkXError): - X = nx.Graph() - Y = nx.DiGraph() - XY = nx.intersection_all([X, Y]) - - -def test_mixed_type_compose(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.compose_all([G, H, I]) - with pytest.raises(nx.NetworkXError): - X = nx.Graph() - Y = nx.DiGraph() - XY = nx.compose_all([X, Y]) - - -def test_empty_union(): - with pytest.raises(ValueError): - nx.union_all([]) - - -def test_empty_disjoint_union(): - with pytest.raises(ValueError): - nx.disjoint_union_all([]) - - -def test_empty_compose_all(): - with pytest.raises(ValueError): - nx.compose_all([]) - - -def test_empty_intersection_all(): - with pytest.raises(ValueError): - nx.intersection_all([]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_binary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_binary.py deleted file mode 100644 index c907cd6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_binary.py +++ /dev/null @@ -1,453 +0,0 @@ -import os - -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -def test_union_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - - gh = nx.union(g, h, rename=("g", "h")) - assert set(gh.nodes()) == {"h0", "h1", "g0", "g1"} - for n in gh: - graph, node = n - assert gh.nodes[n] == eval(graph).nodes[int(node)] - - assert gh.graph["attr"] == "attr" - assert gh.graph["name"] == "h" # h graph attributes take precedent - - -def test_intersection(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - I = nx.intersection(G, H) - assert set(I.nodes()) == {1, 2, 3, 4} - assert sorted(I.edges()) == [(2, 3)] - - -def test_intersection_node_sets_different(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4, 7]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4, 5, 6]) - H.add_edge(2, 3) - H.add_edge(3, 4) - H.add_edge(5, 6) - I = nx.intersection(G, H) - assert set(I.nodes()) == {1, 2, 3, 4} - assert sorted(I.edges()) == [(2, 3)] - - -def test_intersection_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - gh = nx.intersection(g, h) - - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - -def test_intersection_attributes_node_sets_different(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_node(2, x=3) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - h.remove_node(2) - - gh = nx.intersection(g, h) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - -def test_intersection_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.intersection(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0)] - - -def test_intersection_multigraph_attributes_node_set_different(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - g.add_edge(0, 2, key=2) - g.add_edge(0, 2, key=1) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.intersection(g, h) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0)] - - -def test_difference(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - D = nx.difference(G, H) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [(1, 2)] - D = nx.difference(H, G) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [(3, 4)] - D = nx.symmetric_difference(G, H) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [(1, 2), (3, 4)] - - -def test_difference2(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - H.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - H.add_edge(1, 2) - G.add_edge(2, 3) - D = nx.difference(G, H) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [(2, 3)] - D = nx.difference(H, G) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [] - H.add_edge(3, 4) - D = nx.difference(H, G) - assert set(D.nodes()) == {1, 2, 3, 4} - assert sorted(D.edges()) == [(3, 4)] - - -def test_difference_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph["name"] = "g" - - h = g.copy() - h.graph["name"] = "h" - h.graph["attr"] = "attr" - h.nodes[0]["x"] = 7 - - gh = nx.difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [] - # node and graph data should not be copied over - assert gh.nodes.data() != g.nodes.data() - assert gh.graph != g.graph - - -def test_difference_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1), (0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 1), (0, 1, 2)] - - -def test_difference_raise(): - G = nx.path_graph(4) - H = nx.path_graph(3) - pytest.raises(nx.NetworkXError, nx.difference, G, H) - pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H) - - -def test_symmetric_difference_multigraph(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.symmetric_difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == 3 * [(0, 1)] - assert sorted(sorted(e) for e in gh.edges(keys=True)) == [ - [0, 1, 1], - [0, 1, 2], - [0, 1, 3], - ] - - -def test_union_and_compose(): - K3 = nx.complete_graph(3) - P3 = nx.path_graph(3) - - G1 = nx.DiGraph() - G1.add_edge("A", "B") - G1.add_edge("A", "C") - G1.add_edge("A", "D") - G2 = nx.DiGraph() - G2.add_edge("1", "2") - G2.add_edge("1", "3") - G2.add_edge("1", "4") - - G = nx.union(G1, G2) - H = nx.compose(G1, G2) - assert edges_equal(G.edges(), H.edges()) - assert not G.has_edge("A", 1) - pytest.raises(nx.NetworkXError, nx.union, K3, P3) - H1 = nx.union(H, G1, rename=("H", "G1")) - assert sorted(H1.nodes()) == [ - "G1A", - "G1B", - "G1C", - "G1D", - "H1", - "H2", - "H3", - "H4", - "HA", - "HB", - "HC", - "HD", - ] - - H2 = nx.union(H, G2, rename=("H", "")) - assert sorted(H2.nodes()) == [ - "1", - "2", - "3", - "4", - "H1", - "H2", - "H3", - "H4", - "HA", - "HB", - "HC", - "HD", - ] - - assert not H1.has_edge("NB", "NA") - - G = nx.compose(G, G) - assert edges_equal(G.edges(), H.edges()) - - G2 = nx.union(G2, G2, rename=("", "copy")) - assert sorted(G2.nodes()) == [ - "1", - "2", - "3", - "4", - "copy1", - "copy2", - "copy3", - "copy4", - ] - - assert sorted(G2.neighbors("copy4")) == [] - assert sorted(G2.neighbors("copy1")) == ["copy2", "copy3", "copy4"] - assert len(G) == 8 - assert nx.number_of_edges(G) == 6 - - E = nx.disjoint_union(G, G) - assert len(E) == 16 - assert nx.number_of_edges(E) == 12 - - E = nx.disjoint_union(G1, G2) - assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([(1, {"a1": 1})]) - H.add_nodes_from([(1, {"b1": 1})]) - R = nx.compose(G, H) - assert R.nodes == {1: {"a1": 1, "b1": 1}} - - -def test_union_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.union(G, H) - assert set(GH) == set(G) | set(H) - assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True)) - - -def test_disjoint_union_multigraph(): - G = nx.MultiGraph() - G.add_edge(0, 1, key=0) - G.add_edge(0, 1, key=1) - H = nx.MultiGraph() - H.add_edge(2, 3, key=0) - H.add_edge(2, 3, key=1) - GH = nx.disjoint_union(G, H) - assert set(GH) == set(G) | set(H) - assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True)) - - -def test_compose_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.compose(G, H) - assert set(GH) == set(G) | set(H) - assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True)) - H.add_edge(1, 2, key=2) - GH = nx.compose(G, H) - assert set(GH) == set(G) | set(H) - assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True)) - - -def test_full_join_graph(): - # Simple Graphs - G = nx.Graph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.Graph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) - - # Rename - U = nx.full_join(G, H, rename=("g", "h")) - assert set(U) == {"g0", "g1", "g2", "h3", "h4"} - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) - - # Rename graphs with string-like nodes - G = nx.Graph() - G.add_node("a") - G.add_edge("b", "c") - H = nx.Graph() - H.add_edge("d", "e") - - U = nx.full_join(G, H, rename=("g", "h")) - assert set(U) == {"ga", "gb", "gc", "hd", "he"} - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) - - # DiGraphs - G = nx.DiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.DiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2 - - # DiGraphs Rename - U = nx.full_join(G, H, rename=("g", "h")) - assert set(U) == {"g0", "g1", "g2", "h3", "h4"} - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2 - - -def test_full_join_multigraph(): - # MultiGraphs - G = nx.MultiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.MultiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) - - # MultiGraphs rename - U = nx.full_join(G, H, rename=("g", "h")) - assert set(U) == {"g0", "g1", "g2", "h3", "h4"} - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) - - # MultiDiGraphs - G = nx.MultiDiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.MultiDiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2 - - # MultiDiGraphs rename - U = nx.full_join(G, H, rename=("g", "h")) - assert set(U) == {"g0", "g1", "g2", "h3", "h4"} - assert len(U) == len(G) + len(H) - assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2 - - -def test_mixed_type_union(): - G = nx.Graph() - H = nx.MultiGraph() - pytest.raises(nx.NetworkXError, nx.union, G, H) - pytest.raises(nx.NetworkXError, nx.disjoint_union, G, H) - pytest.raises(nx.NetworkXError, nx.intersection, G, H) - pytest.raises(nx.NetworkXError, nx.difference, G, H) - pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H) - pytest.raises(nx.NetworkXError, nx.compose, G, H) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_product.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_product.py deleted file mode 100644 index 8ee54b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_product.py +++ /dev/null @@ -1,491 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -def test_tensor_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.tensor_product(nx.DiGraph(), nx.Graph()) - - -def test_tensor_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.tensor_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.tensor_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_tensor_product_size(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - - G = nx.tensor_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_tensor_product_combinations(): - # basic smoke test, more realistic tests would be useful - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.tensor_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - G = nx.tensor_product(nx.DiGraph(P5), nx.DiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - -def test_tensor_product_classic_result(): - K2 = nx.complete_graph(2) - G = nx.petersen_graph() - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.desargues_graph()) - - G = nx.cycle_graph(5) - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.cycle_graph(10)) - - G = nx.tetrahedral_graph() - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.cubical_graph()) - - -def test_tensor_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.0) - H = nx.erdos_renyi_graph(10, 2 / 10.0) - GH = nx.tensor_product(G, H) - - for u_G, u_H in GH.nodes(): - for v_G, v_H in GH.nodes(): - if H.has_edge(u_H, v_H) and G.has_edge(u_G, v_G): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_cartesian_product_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.cartesian_product(G, H) - assert set(GH) == {(1, 3), (2, 3), (2, 4), (1, 4)} - assert {(frozenset([u, v]), k) for u, v, k in GH.edges(keys=True)} == { - (frozenset([u, v]), k) - for u, v, k in [ - ((1, 3), (2, 3), 0), - ((1, 3), (2, 3), 1), - ((1, 3), (1, 4), 0), - ((1, 3), (1, 4), 1), - ((2, 3), (2, 4), 0), - ((2, 3), (2, 4), 1), - ((2, 4), (1, 4), 0), - ((2, 4), (1, 4), 1), - ] - } - - -def test_cartesian_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.cartesian_product(nx.DiGraph(), nx.Graph()) - - -def test_cartesian_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.cartesian_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.cartesian_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_cartesian_product_size(): - # order(GXH)=order(G)*order(H) - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.cartesian_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - assert nx.number_of_edges(G) == nx.number_of_edges(P5) * nx.number_of_nodes( - K3 - ) + nx.number_of_edges(K3) * nx.number_of_nodes(P5) - G = nx.cartesian_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - assert nx.number_of_edges(G) == nx.number_of_edges(K5) * nx.number_of_nodes( - K3 - ) + nx.number_of_edges(K3) * nx.number_of_nodes(K5) - - -def test_cartesian_product_classic(): - # test some classic product graphs - P2 = nx.path_graph(2) - P3 = nx.path_graph(3) - # cube = 2-path X 2-path - G = nx.cartesian_product(P2, P2) - G = nx.cartesian_product(P2, G) - assert nx.is_isomorphic(G, nx.cubical_graph()) - - # 3x3 grid - G = nx.cartesian_product(P3, P3) - assert nx.is_isomorphic(G, nx.grid_2d_graph(3, 3)) - - -def test_cartesian_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.0) - H = nx.erdos_renyi_graph(10, 2 / 10.0) - GH = nx.cartesian_product(G, H) - - for u_G, u_H in GH.nodes(): - for v_G, v_H in GH.nodes(): - if (u_G == v_G and H.has_edge(u_H, v_H)) or ( - u_H == v_H and G.has_edge(u_G, v_G) - ): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_lexicographic_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.lexicographic_product(nx.DiGraph(), nx.Graph()) - - -def test_lexicographic_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.lexicographic_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.lexicographic_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_lexicographic_product_size(): - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.lexicographic_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_lexicographic_product_combinations(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.lexicographic_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - # No classic easily found classic results for lexicographic product - - -def test_lexicographic_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.0) - H = nx.erdos_renyi_graph(10, 2 / 10.0) - GH = nx.lexicographic_product(G, H) - - for u_G, u_H in GH.nodes(): - for v_G, v_H in GH.nodes(): - if G.has_edge(u_G, v_G) or (u_G == v_G and H.has_edge(u_H, v_H)): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_strong_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.strong_product(nx.DiGraph(), nx.Graph()) - - -def test_strong_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.strong_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.strong_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_strong_product_size(): - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.strong_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_strong_product_combinations(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.strong_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - # No classic easily found classic results for strong product - - -def test_strong_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.0) - H = nx.erdos_renyi_graph(10, 2 / 10.0) - GH = nx.strong_product(G, H) - - for u_G, u_H in GH.nodes(): - for v_G, v_H in GH.nodes(): - if ( - (u_G == v_G and H.has_edge(u_H, v_H)) - or (u_H == v_H and G.has_edge(u_G, v_G)) - or (G.has_edge(u_G, v_G) and H.has_edge(u_H, v_H)) - ): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_graph_power_raises(): - with pytest.raises(nx.NetworkXNotImplemented): - nx.power(nx.MultiDiGraph(), 2) - - -def test_graph_power(): - # wikipedia example for graph power - G = nx.cycle_graph(7) - G.add_edge(6, 7) - G.add_edge(7, 8) - G.add_edge(8, 9) - G.add_edge(9, 2) - H = nx.power(G, 2) - - assert edges_equal( - list(H.edges()), - [ - (0, 1), - (0, 2), - (0, 5), - (0, 6), - (0, 7), - (1, 9), - (1, 2), - (1, 3), - (1, 6), - (2, 3), - (2, 4), - (2, 8), - (2, 9), - (3, 4), - (3, 5), - (3, 9), - (4, 5), - (4, 6), - (5, 6), - (5, 7), - (6, 7), - (6, 8), - (7, 8), - (7, 9), - (8, 9), - ], - ) - - -def test_graph_power_negative(): - with pytest.raises(ValueError): - nx.power(nx.Graph(), -1) - - -def test_rooted_product_raises(): - with pytest.raises(nx.NodeNotFound): - nx.rooted_product(nx.Graph(), nx.path_graph(2), 10) - - -def test_rooted_product(): - G = nx.cycle_graph(5) - H = nx.Graph() - H.add_edges_from([("a", "b"), ("b", "c"), ("b", "d")]) - R = nx.rooted_product(G, H, "a") - assert len(R) == len(G) * len(H) - assert R.size() == G.size() + len(G) * H.size() - - -def test_corona_product(): - G = nx.cycle_graph(3) - H = nx.path_graph(2) - C = nx.corona_product(G, H) - assert len(C) == (len(G) * len(H)) + len(G) - assert C.size() == G.size() + len(G) * H.size() + len(G) * len(H) - - -def test_modular_product(): - G = nx.path_graph(3) - H = nx.path_graph(4) - M = nx.modular_product(G, H) - assert len(M) == len(G) * len(H) - - assert edges_equal( - list(M.edges()), - [ - ((0, 0), (1, 1)), - ((0, 0), (2, 2)), - ((0, 0), (2, 3)), - ((0, 1), (1, 0)), - ((0, 1), (1, 2)), - ((0, 1), (2, 3)), - ((0, 2), (1, 1)), - ((0, 2), (1, 3)), - ((0, 2), (2, 0)), - ((0, 3), (1, 2)), - ((0, 3), (2, 0)), - ((0, 3), (2, 1)), - ((1, 0), (2, 1)), - ((1, 1), (2, 0)), - ((1, 1), (2, 2)), - ((1, 2), (2, 1)), - ((1, 2), (2, 3)), - ((1, 3), (2, 2)), - ], - ) - - -def test_modular_product_raises(): - G = nx.Graph([(0, 1), (1, 2), (2, 0)]) - H = nx.Graph([(0, 1), (1, 2), (2, 0)]) - DG = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - DH = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(G, DH) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(DG, H) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(DG, DH) - - MG = nx.MultiGraph([(0, 1), (1, 2), (2, 0), (0, 1)]) - MH = nx.MultiGraph([(0, 1), (1, 2), (2, 0), (0, 1)]) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(G, MH) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(MG, H) - with pytest.raises(nx.NetworkXNotImplemented): - nx.modular_product(MG, MH) - with pytest.raises(nx.NetworkXNotImplemented): - # check multigraph with no multiedges - nx.modular_product(nx.MultiGraph(G), H) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_unary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_unary.py deleted file mode 100644 index d68e55c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/tests/test_unary.py +++ /dev/null @@ -1,55 +0,0 @@ -import pytest - -import networkx as nx - - -def test_complement(): - null = nx.null_graph() - empty1 = nx.empty_graph(1) - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - K10 = nx.complete_graph(10) - P2 = nx.path_graph(2) - P3 = nx.path_graph(3) - P5 = nx.path_graph(5) - P10 = nx.path_graph(10) - # complement of the complete graph is empty - - G = nx.complement(K3) - assert nx.is_isomorphic(G, nx.empty_graph(3)) - G = nx.complement(K5) - assert nx.is_isomorphic(G, nx.empty_graph(5)) - # for any G, G=complement(complement(G)) - P3cc = nx.complement(nx.complement(P3)) - assert nx.is_isomorphic(P3, P3cc) - nullcc = nx.complement(nx.complement(null)) - assert nx.is_isomorphic(null, nullcc) - b = nx.bull_graph() - bcc = nx.complement(nx.complement(b)) - assert nx.is_isomorphic(b, bcc) - - -def test_complement_2(): - G1 = nx.DiGraph() - G1.add_edge("A", "B") - G1.add_edge("A", "C") - G1.add_edge("A", "D") - G1C = nx.complement(G1) - assert sorted(G1C.edges()) == [ - ("B", "A"), - ("B", "C"), - ("B", "D"), - ("C", "A"), - ("C", "B"), - ("C", "D"), - ("D", "A"), - ("D", "B"), - ("D", "C"), - ] - - -def test_reverse1(): - # Other tests for reverse are done by the DiGraph and MultiDigraph. - G1 = nx.Graph() - pytest.raises(nx.NetworkXError, nx.reverse, G1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/unary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/unary.py deleted file mode 100644 index 79e44d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/operators/unary.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Unary operations on graphs""" - -import networkx as nx - -__all__ = ["complement", "reverse"] - - -@nx._dispatchable(returns_graph=True) -def complement(G): - """Returns the graph complement of G. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - GC : A new graph. - - Notes - ----- - Note that `complement` does not create self-loops and also - does not produce parallel edges for MultiGraphs. - - Graph, node, and edge data are not propagated to the new graph. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (3, 5)]) - >>> G_complement = nx.complement(G) - >>> G_complement.edges() # This shows the edges of the complemented graph - EdgeView([(1, 4), (1, 5), (2, 4), (2, 5), (4, 5)]) - - """ - R = G.__class__() - R.add_nodes_from(G) - R.add_edges_from( - ((n, n2) for n, nbrs in G.adjacency() for n2 in G if n2 not in nbrs if n != n2) - ) - return R - - -@nx._dispatchable(returns_graph=True) -def reverse(G, copy=True): - """Returns the reverse directed graph of G. - - Parameters - ---------- - G : directed graph - A NetworkX directed graph - copy : bool - If True, then a new graph is returned. If False, then the graph is - reversed in place. - - Returns - ------- - H : directed graph - The reversed G. - - Raises - ------ - NetworkXError - If graph is undirected. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 4), (3, 5)]) - >>> G_reversed = nx.reverse(G) - >>> G_reversed.edges() - OutEdgeView([(2, 1), (3, 1), (3, 2), (4, 3), (5, 3)]) - - """ - if not G.is_directed(): - raise nx.NetworkXError("Cannot reverse an undirected graph.") - else: - return G.reverse(copy=copy) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planar_drawing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planar_drawing.py deleted file mode 100644 index ea25809..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planar_drawing.py +++ /dev/null @@ -1,464 +0,0 @@ -from collections import defaultdict - -import networkx as nx - -__all__ = ["combinatorial_embedding_to_pos"] - - -def combinatorial_embedding_to_pos(embedding, fully_triangulate=False): - """Assigns every node a (x, y) position based on the given embedding - - The algorithm iteratively inserts nodes of the input graph in a certain - order and rearranges previously inserted nodes so that the planar drawing - stays valid. This is done efficiently by only maintaining relative - positions during the node placements and calculating the absolute positions - at the end. For more information see [1]_. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - This defines the order of the edges - - fully_triangulate : bool - If set to True the algorithm adds edges to a copy of the input - embedding and makes it chordal. - - Returns - ------- - pos : dict - Maps each node to a tuple that defines the (x, y) position - - References - ---------- - .. [1] M. Chrobak and T.H. Payne: - A Linear-time Algorithm for Drawing a Planar Graph on a Grid 1989 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.6677 - - """ - if len(embedding.nodes()) < 4: - # Position the node in any triangle - default_positions = [(0, 0), (2, 0), (1, 1)] - pos = {} - for i, v in enumerate(embedding.nodes()): - pos[v] = default_positions[i] - return pos - - embedding, outer_face = triangulate_embedding(embedding, fully_triangulate) - - # The following dicts map a node to another node - # If a node is not in the key set it means that the node is not yet in G_k - # If a node maps to None then the corresponding subtree does not exist - left_t_child = {} - right_t_child = {} - - # The following dicts map a node to an integer - delta_x = {} - y_coordinate = {} - - node_list = get_canonical_ordering(embedding, outer_face) - - # 1. Phase: Compute relative positions - - # Initialization - v1, v2, v3 = node_list[0][0], node_list[1][0], node_list[2][0] - - delta_x[v1] = 0 - y_coordinate[v1] = 0 - right_t_child[v1] = v3 - left_t_child[v1] = None - - delta_x[v2] = 1 - y_coordinate[v2] = 0 - right_t_child[v2] = None - left_t_child[v2] = None - - delta_x[v3] = 1 - y_coordinate[v3] = 1 - right_t_child[v3] = v2 - left_t_child[v3] = None - - for k in range(3, len(node_list)): - vk, contour_nbrs = node_list[k] - wp = contour_nbrs[0] - wp1 = contour_nbrs[1] - wq = contour_nbrs[-1] - wq1 = contour_nbrs[-2] - adds_mult_tri = len(contour_nbrs) > 2 - - # Stretch gaps: - delta_x[wp1] += 1 - delta_x[wq] += 1 - - delta_x_wp_wq = sum(delta_x[x] for x in contour_nbrs[1:]) - - # Adjust offsets - delta_x[vk] = (-y_coordinate[wp] + delta_x_wp_wq + y_coordinate[wq]) // 2 - y_coordinate[vk] = (y_coordinate[wp] + delta_x_wp_wq + y_coordinate[wq]) // 2 - delta_x[wq] = delta_x_wp_wq - delta_x[vk] - if adds_mult_tri: - delta_x[wp1] -= delta_x[vk] - - # Install v_k: - right_t_child[wp] = vk - right_t_child[vk] = wq - if adds_mult_tri: - left_t_child[vk] = wp1 - right_t_child[wq1] = None - else: - left_t_child[vk] = None - - # 2. Phase: Set absolute positions - pos = {} - pos[v1] = (0, y_coordinate[v1]) - remaining_nodes = [v1] - while remaining_nodes: - parent_node = remaining_nodes.pop() - - # Calculate position for left child - set_position( - parent_node, left_t_child, remaining_nodes, delta_x, y_coordinate, pos - ) - # Calculate position for right child - set_position( - parent_node, right_t_child, remaining_nodes, delta_x, y_coordinate, pos - ) - return pos - - -def set_position(parent, tree, remaining_nodes, delta_x, y_coordinate, pos): - """Helper method to calculate the absolute position of nodes.""" - child = tree[parent] - parent_node_x = pos[parent][0] - if child is not None: - # Calculate pos of child - child_x = parent_node_x + delta_x[child] - pos[child] = (child_x, y_coordinate[child]) - # Remember to calculate pos of its children - remaining_nodes.append(child) - - -def get_canonical_ordering(embedding, outer_face): - """Returns a canonical ordering of the nodes - - The canonical ordering of nodes (v1, ..., vn) must fulfill the following - conditions: - (See Lemma 1 in [2]_) - - - For the subgraph G_k of the input graph induced by v1, ..., vk it holds: - - 2-connected - - internally triangulated - - the edge (v1, v2) is part of the outer face - - For a node v(k+1) the following holds: - - The node v(k+1) is part of the outer face of G_k - - It has at least two neighbors in G_k - - All neighbors of v(k+1) in G_k lie consecutively on the outer face of - G_k (excluding the edge (v1, v2)). - - The algorithm used here starts with G_n (containing all nodes). It first - selects the nodes v1 and v2. And then tries to find the order of the other - nodes by checking which node can be removed in order to fulfill the - conditions mentioned above. This is done by calculating the number of - chords of nodes on the outer face. For more information see [1]_. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - The embedding must be triangulated - outer_face : list - The nodes on the outer face of the graph - - Returns - ------- - ordering : list - A list of tuples `(vk, wp_wq)`. Here `vk` is the node at this position - in the canonical ordering. The element `wp_wq` is a list of nodes that - make up the outer face of G_k. - - References - ---------- - .. [1] Steven Chaplick. - Canonical Orders of Planar Graphs and (some of) Their Applications 2015 - https://wuecampus2.uni-wuerzburg.de/moodle/pluginfile.php/545727/mod_resource/content/0/vg-ss15-vl03-canonical-orders-druckversion.pdf - .. [2] M. Chrobak and T.H. Payne: - A Linear-time Algorithm for Drawing a Planar Graph on a Grid 1989 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.6677 - - """ - v1 = outer_face[0] - v2 = outer_face[1] - chords = defaultdict(int) # Maps nodes to the number of their chords - marked_nodes = set() - ready_to_pick = set(outer_face) - - # Initialize outer_face_ccw_nbr (do not include v1 -> v2) - outer_face_ccw_nbr = {} - prev_nbr = v2 - for idx in range(2, len(outer_face)): - outer_face_ccw_nbr[prev_nbr] = outer_face[idx] - prev_nbr = outer_face[idx] - outer_face_ccw_nbr[prev_nbr] = v1 - - # Initialize outer_face_cw_nbr (do not include v2 -> v1) - outer_face_cw_nbr = {} - prev_nbr = v1 - for idx in range(len(outer_face) - 1, 0, -1): - outer_face_cw_nbr[prev_nbr] = outer_face[idx] - prev_nbr = outer_face[idx] - - def is_outer_face_nbr(x, y): - if x not in outer_face_ccw_nbr: - return outer_face_cw_nbr[x] == y - if x not in outer_face_cw_nbr: - return outer_face_ccw_nbr[x] == y - return outer_face_ccw_nbr[x] == y or outer_face_cw_nbr[x] == y - - def is_on_outer_face(x): - return x not in marked_nodes and (x in outer_face_ccw_nbr or x == v1) - - # Initialize number of chords - for v in outer_face: - for nbr in embedding.neighbors_cw_order(v): - if is_on_outer_face(nbr) and not is_outer_face_nbr(v, nbr): - chords[v] += 1 - ready_to_pick.discard(v) - - # Initialize canonical_ordering - canonical_ordering = [None] * len(embedding.nodes()) - canonical_ordering[0] = (v1, []) - canonical_ordering[1] = (v2, []) - ready_to_pick.discard(v1) - ready_to_pick.discard(v2) - - for k in range(len(embedding.nodes()) - 1, 1, -1): - # 1. Pick v from ready_to_pick - v = ready_to_pick.pop() - marked_nodes.add(v) - - # v has exactly two neighbors on the outer face (wp and wq) - wp = None - wq = None - # Iterate over neighbors of v to find wp and wq - nbr_iterator = iter(embedding.neighbors_cw_order(v)) - while True: - nbr = next(nbr_iterator) - if nbr in marked_nodes: - # Only consider nodes that are not yet removed - continue - if is_on_outer_face(nbr): - # nbr is either wp or wq - if nbr == v1: - wp = v1 - elif nbr == v2: - wq = v2 - else: - if outer_face_cw_nbr[nbr] == v: - # nbr is wp - wp = nbr - else: - # nbr is wq - wq = nbr - if wp is not None and wq is not None: - # We don't need to iterate any further - break - - # Obtain new nodes on outer face (neighbors of v from wp to wq) - wp_wq = [wp] - nbr = wp - while nbr != wq: - # Get next neighbor (clockwise on the outer face) - next_nbr = embedding[v][nbr]["ccw"] - wp_wq.append(next_nbr) - # Update outer face - outer_face_cw_nbr[nbr] = next_nbr - outer_face_ccw_nbr[next_nbr] = nbr - # Move to next neighbor of v - nbr = next_nbr - - if len(wp_wq) == 2: - # There was a chord between wp and wq, decrease number of chords - chords[wp] -= 1 - if chords[wp] == 0: - ready_to_pick.add(wp) - chords[wq] -= 1 - if chords[wq] == 0: - ready_to_pick.add(wq) - else: - # Update all chords involving w_(p+1) to w_(q-1) - new_face_nodes = set(wp_wq[1:-1]) - for w in new_face_nodes: - # If we do not find a chord for w later we can pick it next - ready_to_pick.add(w) - for nbr in embedding.neighbors_cw_order(w): - if is_on_outer_face(nbr) and not is_outer_face_nbr(w, nbr): - # There is a chord involving w - chords[w] += 1 - ready_to_pick.discard(w) - if nbr not in new_face_nodes: - # Also increase chord for the neighbor - # We only iterator over new_face_nodes - chords[nbr] += 1 - ready_to_pick.discard(nbr) - # Set the canonical ordering node and the list of contour neighbors - canonical_ordering[k] = (v, wp_wq) - - return canonical_ordering - - -def triangulate_face(embedding, v1, v2): - """Triangulates the face given by half edge (v, w) - - Parameters - ---------- - embedding : nx.PlanarEmbedding - v1 : node - The half-edge (v1, v2) belongs to the face that gets triangulated - v2 : node - """ - _, v3 = embedding.next_face_half_edge(v1, v2) - _, v4 = embedding.next_face_half_edge(v2, v3) - if v1 in (v2, v3): - # The component has less than 3 nodes - return - while v1 != v4: - # Add edge if not already present on other side - if embedding.has_edge(v1, v3): - # Cannot triangulate at this position - v1, v2, v3 = v2, v3, v4 - else: - # Add edge for triangulation - embedding.add_half_edge(v1, v3, ccw=v2) - embedding.add_half_edge(v3, v1, cw=v2) - v1, v2, v3 = v1, v3, v4 - # Get next node - _, v4 = embedding.next_face_half_edge(v2, v3) - - -def triangulate_embedding(embedding, fully_triangulate=True): - """Triangulates the embedding. - - Traverses faces of the embedding and adds edges to a copy of the - embedding to triangulate it. - The method also ensures that the resulting graph is 2-connected by adding - edges if the same vertex is contained twice on a path around a face. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - The input graph must contain at least 3 nodes. - - fully_triangulate : bool - If set to False the face with the most nodes is chooses as outer face. - This outer face does not get triangulated. - - Returns - ------- - (embedding, outer_face) : (nx.PlanarEmbedding, list) tuple - The element `embedding` is a new embedding containing all edges from - the input embedding and the additional edges to triangulate the graph. - The element `outer_face` is a list of nodes that lie on the outer face. - If the graph is fully triangulated these are three arbitrary connected - nodes. - - """ - if len(embedding.nodes) <= 1: - return embedding, list(embedding.nodes) - embedding = nx.PlanarEmbedding(embedding) - - # Get a list with a node for each connected component - component_nodes = [next(iter(x)) for x in nx.connected_components(embedding)] - - # 1. Make graph a single component (add edge between components) - for i in range(len(component_nodes) - 1): - v1 = component_nodes[i] - v2 = component_nodes[i + 1] - embedding.connect_components(v1, v2) - - # 2. Calculate faces, ensure 2-connectedness and determine outer face - outer_face = [] # A face with the most number of nodes - face_list = [] - edges_visited = set() # Used to keep track of already visited faces - for v in embedding.nodes(): - for w in embedding.neighbors_cw_order(v): - new_face = make_bi_connected(embedding, v, w, edges_visited) - if new_face: - # Found a new face - face_list.append(new_face) - if len(new_face) > len(outer_face): - # The face is a candidate to be the outer face - outer_face = new_face - - # 3. Triangulate (internal) faces - for face in face_list: - if face is not outer_face or fully_triangulate: - # Triangulate this face - triangulate_face(embedding, face[0], face[1]) - - if fully_triangulate: - v1 = outer_face[0] - v2 = outer_face[1] - v3 = embedding[v2][v1]["ccw"] - outer_face = [v1, v2, v3] - - return embedding, outer_face - - -def make_bi_connected(embedding, starting_node, outgoing_node, edges_counted): - """Triangulate a face and make it 2-connected - - This method also adds all edges on the face to `edges_counted`. - - Parameters - ---------- - embedding: nx.PlanarEmbedding - The embedding that defines the faces - starting_node : node - A node on the face - outgoing_node : node - A node such that the half edge (starting_node, outgoing_node) belongs - to the face - edges_counted: set - Set of all half-edges that belong to a face that have been visited - - Returns - ------- - face_nodes: list - A list of all nodes at the border of this face - """ - - # Check if the face has already been calculated - if (starting_node, outgoing_node) in edges_counted: - # This face was already counted - return [] - edges_counted.add((starting_node, outgoing_node)) - - # Add all edges to edges_counted which have this face to their left - v1 = starting_node - v2 = outgoing_node - face_list = [starting_node] # List of nodes around the face - face_set = set(face_list) # Set for faster queries - _, v3 = embedding.next_face_half_edge(v1, v2) - - # Move the nodes v1, v2, v3 around the face: - while v2 != starting_node or v3 != outgoing_node: - if v1 == v2: - raise nx.NetworkXException("Invalid half-edge") - # cycle is not completed yet - if v2 in face_set: - # v2 encountered twice: Add edge to ensure 2-connectedness - embedding.add_half_edge(v1, v3, ccw=v2) - embedding.add_half_edge(v3, v1, cw=v2) - edges_counted.add((v2, v3)) - edges_counted.add((v3, v1)) - v2 = v1 - else: - face_set.add(v2) - face_list.append(v2) - - # set next edge - v1 = v2 - v2, v3 = embedding.next_face_half_edge(v2, v3) - - # remember that this edge has been counted - edges_counted.add((v1, v2)) - - return face_list diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planarity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planarity.py deleted file mode 100644 index 17d0bec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/planarity.py +++ /dev/null @@ -1,1402 +0,0 @@ -from collections import defaultdict - -import networkx as nx - -__all__ = ["check_planarity", "is_planar", "PlanarEmbedding"] - - -@nx._dispatchable -def is_planar(G): - """Returns True if and only if `G` is planar. - - A graph is *planar* iff it can be drawn in a plane without - any edge intersections. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - bool - Whether the graph is planar. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2)]) - >>> nx.is_planar(G) - True - >>> nx.is_planar(nx.complete_graph(5)) - False - - See Also - -------- - check_planarity : - Check if graph is planar *and* return a `PlanarEmbedding` instance if True. - """ - - return check_planarity(G, counterexample=False)[0] - - -@nx._dispatchable(returns_graph=True) -def check_planarity(G, counterexample=False): - """Check if a graph is planar and return a counterexample or an embedding. - - A graph is planar iff it can be drawn in a plane without - any edge intersections. - - Parameters - ---------- - G : NetworkX graph - counterexample : bool - A Kuratowski subgraph (to proof non planarity) is only returned if set - to true. - - Returns - ------- - (is_planar, certificate) : (bool, NetworkX graph) tuple - is_planar is true if the graph is planar. - If the graph is planar `certificate` is a PlanarEmbedding - otherwise it is a Kuratowski subgraph. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2)]) - >>> is_planar, P = nx.check_planarity(G) - >>> print(is_planar) - True - - When `G` is planar, a `PlanarEmbedding` instance is returned: - - >>> P.get_data() - {0: [1, 2], 1: [0], 2: [0]} - - Notes - ----- - A (combinatorial) embedding consists of cyclic orderings of the incident - edges at each vertex. Given such an embedding there are multiple approaches - discussed in literature to drawing the graph (subject to various - constraints, e.g. integer coordinates), see e.g. [2]. - - The planarity check algorithm and extraction of the combinatorial embedding - is based on the Left-Right Planarity Test [1]. - - A counterexample is only generated if the corresponding parameter is set, - because the complexity of the counterexample generation is higher. - - See also - -------- - is_planar : - Check for planarity without creating a `PlanarEmbedding` or counterexample. - - References - ---------- - .. [1] Ulrik Brandes: - The Left-Right Planarity Test - 2009 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.217.9208 - .. [2] Takao Nishizeki, Md Saidur Rahman: - Planar graph drawing - Lecture Notes Series on Computing: Volume 12 - 2004 - """ - - planarity_state = LRPlanarity(G) - embedding = planarity_state.lr_planarity() - if embedding is None: - # graph is not planar - if counterexample: - return False, get_counterexample(G) - else: - return False, None - else: - # graph is planar - return True, embedding - - -@nx._dispatchable(returns_graph=True) -def check_planarity_recursive(G, counterexample=False): - """Recursive version of :meth:`check_planarity`.""" - planarity_state = LRPlanarity(G) - embedding = planarity_state.lr_planarity_recursive() - if embedding is None: - # graph is not planar - if counterexample: - return False, get_counterexample_recursive(G) - else: - return False, None - else: - # graph is planar - return True, embedding - - -@nx._dispatchable(returns_graph=True) -def get_counterexample(G): - """Obtains a Kuratowski subgraph. - - Raises nx.NetworkXException if G is planar. - - The function removes edges such that the graph is still not planar. - At some point the removal of any edge would make the graph planar. - This subgraph must be a Kuratowski subgraph. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - subgraph : NetworkX graph - A Kuratowski subgraph that proves that G is not planar. - - """ - # copy graph - G = nx.Graph(G) - - if check_planarity(G)[0]: - raise nx.NetworkXException("G is planar - no counter example.") - - # find Kuratowski subgraph - subgraph = nx.Graph() - for u in G: - nbrs = list(G[u]) - for v in nbrs: - G.remove_edge(u, v) - if check_planarity(G)[0]: - G.add_edge(u, v) - subgraph.add_edge(u, v) - - return subgraph - - -@nx._dispatchable(returns_graph=True) -def get_counterexample_recursive(G): - """Recursive version of :meth:`get_counterexample`.""" - - # copy graph - G = nx.Graph(G) - - if check_planarity_recursive(G)[0]: - raise nx.NetworkXException("G is planar - no counter example.") - - # find Kuratowski subgraph - subgraph = nx.Graph() - for u in G: - nbrs = list(G[u]) - for v in nbrs: - G.remove_edge(u, v) - if check_planarity_recursive(G)[0]: - G.add_edge(u, v) - subgraph.add_edge(u, v) - - return subgraph - - -class Interval: - """Represents a set of return edges. - - All return edges in an interval induce a same constraint on the contained - edges, which means that all edges must either have a left orientation or - all edges must have a right orientation. - """ - - def __init__(self, low=None, high=None): - self.low = low - self.high = high - - def empty(self): - """Check if the interval is empty""" - return self.low is None and self.high is None - - def copy(self): - """Returns a copy of this interval""" - return Interval(self.low, self.high) - - def conflicting(self, b, planarity_state): - """Returns True if interval I conflicts with edge b""" - return ( - not self.empty() - and planarity_state.lowpt[self.high] > planarity_state.lowpt[b] - ) - - -class ConflictPair: - """Represents a different constraint between two intervals. - - The edges in the left interval must have a different orientation than - the one in the right interval. - """ - - def __init__(self, left=Interval(), right=Interval()): - self.left = left - self.right = right - - def swap(self): - """Swap left and right intervals""" - temp = self.left - self.left = self.right - self.right = temp - - def lowest(self, planarity_state): - """Returns the lowest lowpoint of a conflict pair""" - if self.left.empty(): - return planarity_state.lowpt[self.right.low] - if self.right.empty(): - return planarity_state.lowpt[self.left.low] - return min( - planarity_state.lowpt[self.left.low], planarity_state.lowpt[self.right.low] - ) - - -def top_of_stack(l): - """Returns the element on top of the stack.""" - if not l: - return None - return l[-1] - - -class LRPlanarity: - """A class to maintain the state during planarity check.""" - - __slots__ = [ - "G", - "roots", - "height", - "lowpt", - "lowpt2", - "nesting_depth", - "parent_edge", - "DG", - "adjs", - "ordered_adjs", - "ref", - "side", - "S", - "stack_bottom", - "lowpt_edge", - "left_ref", - "right_ref", - "embedding", - ] - - def __init__(self, G): - # copy G without adding self-loops - self.G = nx.Graph() - self.G.add_nodes_from(G.nodes) - for e in G.edges: - if e[0] != e[1]: - self.G.add_edge(e[0], e[1]) - - self.roots = [] - - # distance from tree root - self.height = defaultdict(lambda: None) - - self.lowpt = {} # height of lowest return point of an edge - self.lowpt2 = {} # height of second lowest return point - self.nesting_depth = {} # for nesting order - - # None -> missing edge - self.parent_edge = defaultdict(lambda: None) - - # oriented DFS graph - self.DG = nx.DiGraph() - self.DG.add_nodes_from(G.nodes) - - self.adjs = {} - self.ordered_adjs = {} - - self.ref = defaultdict(lambda: None) - self.side = defaultdict(lambda: 1) - - # stack of conflict pairs - self.S = [] - self.stack_bottom = {} - self.lowpt_edge = {} - - self.left_ref = {} - self.right_ref = {} - - self.embedding = PlanarEmbedding() - - def lr_planarity(self): - """Execute the LR planarity test. - - Returns - ------- - embedding : dict - If the graph is planar an embedding is returned. Otherwise None. - """ - if self.G.order() > 2 and self.G.size() > 3 * self.G.order() - 6: - # graph is not planar - return None - - # make adjacency lists for dfs - for v in self.G: - self.adjs[v] = list(self.G[v]) - - # orientation of the graph by depth first search traversal - for v in self.G: - if self.height[v] is None: - self.height[v] = 0 - self.roots.append(v) - self.dfs_orientation(v) - - # Free no longer used variables - self.G = None - self.lowpt2 = None - self.adjs = None - - # testing - for v in self.DG: # sort the adjacency lists by nesting depth - # note: this sorting leads to non linear time - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)] - ) - for v in self.roots: - if not self.dfs_testing(v): - return None - - # Free no longer used variables - self.height = None - self.lowpt = None - self.S = None - self.stack_bottom = None - self.lowpt_edge = None - - for e in self.DG.edges: - self.nesting_depth[e] = self.sign(e) * self.nesting_depth[e] - - self.embedding.add_nodes_from(self.DG.nodes) - for v in self.DG: - # sort the adjacency lists again - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)] - ) - # initialize the embedding - previous_node = None - for w in self.ordered_adjs[v]: - self.embedding.add_half_edge(v, w, ccw=previous_node) - previous_node = w - - # Free no longer used variables - self.DG = None - self.nesting_depth = None - self.ref = None - - # compute the complete embedding - for v in self.roots: - self.dfs_embedding(v) - - # Free no longer used variables - self.roots = None - self.parent_edge = None - self.ordered_adjs = None - self.left_ref = None - self.right_ref = None - self.side = None - - return self.embedding - - def lr_planarity_recursive(self): - """Recursive version of :meth:`lr_planarity`.""" - if self.G.order() > 2 and self.G.size() > 3 * self.G.order() - 6: - # graph is not planar - return None - - # orientation of the graph by depth first search traversal - for v in self.G: - if self.height[v] is None: - self.height[v] = 0 - self.roots.append(v) - self.dfs_orientation_recursive(v) - - # Free no longer used variable - self.G = None - - # testing - for v in self.DG: # sort the adjacency lists by nesting depth - # note: this sorting leads to non linear time - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)] - ) - for v in self.roots: - if not self.dfs_testing_recursive(v): - return None - - for e in self.DG.edges: - self.nesting_depth[e] = self.sign_recursive(e) * self.nesting_depth[e] - - self.embedding.add_nodes_from(self.DG.nodes) - for v in self.DG: - # sort the adjacency lists again - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)] - ) - # initialize the embedding - previous_node = None - for w in self.ordered_adjs[v]: - self.embedding.add_half_edge(v, w, ccw=previous_node) - previous_node = w - - # compute the complete embedding - for v in self.roots: - self.dfs_embedding_recursive(v) - - return self.embedding - - def dfs_orientation(self, v): - """Orient the graph by DFS, compute lowpoints and nesting order.""" - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - # boolean to indicate whether to skip the initial work for an edge - skip_init = defaultdict(lambda: False) - - while dfs_stack: - v = dfs_stack.pop() - e = self.parent_edge[v] - - for w in self.adjs[v][ind[v] :]: - vw = (v, w) - - if not skip_init[vw]: - if (v, w) in self.DG.edges or (w, v) in self.DG.edges: - ind[v] += 1 - continue # the edge was already oriented - - self.DG.add_edge(v, w) # orient the edge - - self.lowpt[vw] = self.height[v] - self.lowpt2[vw] = self.height[v] - if self.height[w] is None: # (v, w) is a tree edge - self.parent_edge[w] = vw - self.height[w] = self.height[v] + 1 - - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - skip_init[vw] = True # don't redo this block - break # handle next node in dfs_stack (i.e. w) - else: # (v, w) is a back edge - self.lowpt[vw] = self.height[w] - - # determine nesting graph - self.nesting_depth[vw] = 2 * self.lowpt[vw] - if self.lowpt2[vw] < self.height[v]: # chordal - self.nesting_depth[vw] += 1 - - # update lowpoints of parent edge e - if e is not None: - if self.lowpt[vw] < self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt[e], self.lowpt2[vw]) - self.lowpt[e] = self.lowpt[vw] - elif self.lowpt[vw] > self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt[vw]) - else: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt2[vw]) - - ind[v] += 1 - - def dfs_orientation_recursive(self, v): - """Recursive version of :meth:`dfs_orientation`.""" - e = self.parent_edge[v] - for w in self.G[v]: - if (v, w) in self.DG.edges or (w, v) in self.DG.edges: - continue # the edge was already oriented - vw = (v, w) - self.DG.add_edge(v, w) # orient the edge - - self.lowpt[vw] = self.height[v] - self.lowpt2[vw] = self.height[v] - if self.height[w] is None: # (v, w) is a tree edge - self.parent_edge[w] = vw - self.height[w] = self.height[v] + 1 - self.dfs_orientation_recursive(w) - else: # (v, w) is a back edge - self.lowpt[vw] = self.height[w] - - # determine nesting graph - self.nesting_depth[vw] = 2 * self.lowpt[vw] - if self.lowpt2[vw] < self.height[v]: # chordal - self.nesting_depth[vw] += 1 - - # update lowpoints of parent edge e - if e is not None: - if self.lowpt[vw] < self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt[e], self.lowpt2[vw]) - self.lowpt[e] = self.lowpt[vw] - elif self.lowpt[vw] > self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt[vw]) - else: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt2[vw]) - - def dfs_testing(self, v): - """Test for LR partition.""" - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - # boolean to indicate whether to skip the initial work for an edge - skip_init = defaultdict(lambda: False) - - while dfs_stack: - v = dfs_stack.pop() - e = self.parent_edge[v] - # to indicate whether to skip the final block after the for loop - skip_final = False - - for w in self.ordered_adjs[v][ind[v] :]: - ei = (v, w) - - if not skip_init[ei]: - self.stack_bottom[ei] = top_of_stack(self.S) - - if ei == self.parent_edge[w]: # tree edge - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - skip_init[ei] = True # don't redo this block - skip_final = True # skip final work after breaking - break # handle next node in dfs_stack (i.e. w) - else: # back edge - self.lowpt_edge[ei] = ei - self.S.append(ConflictPair(right=Interval(ei, ei))) - - # integrate new return edges - if self.lowpt[ei] < self.height[v]: - if w == self.ordered_adjs[v][0]: # e_i has return edge - self.lowpt_edge[e] = self.lowpt_edge[ei] - else: # add constraints of e_i - if not self.add_constraints(ei, e): - # graph is not planar - return False - - ind[v] += 1 - - if not skip_final: - # remove back edges returning to parent - if e is not None: # v isn't root - self.remove_back_edges(e) - - return True - - def dfs_testing_recursive(self, v): - """Recursive version of :meth:`dfs_testing`.""" - e = self.parent_edge[v] - for w in self.ordered_adjs[v]: - ei = (v, w) - self.stack_bottom[ei] = top_of_stack(self.S) - if ei == self.parent_edge[w]: # tree edge - if not self.dfs_testing_recursive(w): - return False - else: # back edge - self.lowpt_edge[ei] = ei - self.S.append(ConflictPair(right=Interval(ei, ei))) - - # integrate new return edges - if self.lowpt[ei] < self.height[v]: - if w == self.ordered_adjs[v][0]: # e_i has return edge - self.lowpt_edge[e] = self.lowpt_edge[ei] - else: # add constraints of e_i - if not self.add_constraints(ei, e): - # graph is not planar - return False - - # remove back edges returning to parent - if e is not None: # v isn't root - self.remove_back_edges(e) - return True - - def add_constraints(self, ei, e): - P = ConflictPair() - # merge return edges of e_i into P.right - while True: - Q = self.S.pop() - if not Q.left.empty(): - Q.swap() - if not Q.left.empty(): # not planar - return False - if self.lowpt[Q.right.low] > self.lowpt[e]: - # merge intervals - if P.right.empty(): # topmost interval - P.right = Q.right.copy() - else: - self.ref[P.right.low] = Q.right.high - P.right.low = Q.right.low - else: # align - self.ref[Q.right.low] = self.lowpt_edge[e] - if top_of_stack(self.S) == self.stack_bottom[ei]: - break - # merge conflicting return edges of e_1,...,e_i-1 into P.L - while top_of_stack(self.S).left.conflicting(ei, self) or top_of_stack( - self.S - ).right.conflicting(ei, self): - Q = self.S.pop() - if Q.right.conflicting(ei, self): - Q.swap() - if Q.right.conflicting(ei, self): # not planar - return False - # merge interval below lowpt(e_i) into P.R - self.ref[P.right.low] = Q.right.high - if Q.right.low is not None: - P.right.low = Q.right.low - - if P.left.empty(): # topmost interval - P.left = Q.left.copy() - else: - self.ref[P.left.low] = Q.left.high - P.left.low = Q.left.low - - if not (P.left.empty() and P.right.empty()): - self.S.append(P) - return True - - def remove_back_edges(self, e): - u = e[0] - # trim back edges ending at parent u - # drop entire conflict pairs - while self.S and top_of_stack(self.S).lowest(self) == self.height[u]: - P = self.S.pop() - if P.left.low is not None: - self.side[P.left.low] = -1 - - if self.S: # one more conflict pair to consider - P = self.S.pop() - # trim left interval - while P.left.high is not None and P.left.high[1] == u: - P.left.high = self.ref[P.left.high] - if P.left.high is None and P.left.low is not None: - # just emptied - self.ref[P.left.low] = P.right.low - self.side[P.left.low] = -1 - P.left.low = None - # trim right interval - while P.right.high is not None and P.right.high[1] == u: - P.right.high = self.ref[P.right.high] - if P.right.high is None and P.right.low is not None: - # just emptied - self.ref[P.right.low] = P.left.low - self.side[P.right.low] = -1 - P.right.low = None - self.S.append(P) - - # side of e is side of a highest return edge - if self.lowpt[e] < self.height[u]: # e has return edge - hl = top_of_stack(self.S).left.high - hr = top_of_stack(self.S).right.high - - if hl is not None and (hr is None or self.lowpt[hl] > self.lowpt[hr]): - self.ref[e] = hl - else: - self.ref[e] = hr - - def dfs_embedding(self, v): - """Completes the embedding.""" - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - - while dfs_stack: - v = dfs_stack.pop() - - for w in self.ordered_adjs[v][ind[v] :]: - ind[v] += 1 - ei = (v, w) - - if ei == self.parent_edge[w]: # tree edge - self.embedding.add_half_edge_first(w, v) - self.left_ref[v] = w - self.right_ref[v] = w - - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - break # handle next node in dfs_stack (i.e. w) - else: # back edge - if self.side[ei] == 1: - self.embedding.add_half_edge(w, v, ccw=self.right_ref[w]) - else: - self.embedding.add_half_edge(w, v, cw=self.left_ref[w]) - self.left_ref[w] = v - - def dfs_embedding_recursive(self, v): - """Recursive version of :meth:`dfs_embedding`.""" - for w in self.ordered_adjs[v]: - ei = (v, w) - if ei == self.parent_edge[w]: # tree edge - self.embedding.add_half_edge_first(w, v) - self.left_ref[v] = w - self.right_ref[v] = w - self.dfs_embedding_recursive(w) - else: # back edge - if self.side[ei] == 1: - # place v directly after right_ref[w] in embed. list of w - self.embedding.add_half_edge(w, v, ccw=self.right_ref[w]) - else: - # place v directly before left_ref[w] in embed. list of w - self.embedding.add_half_edge(w, v, cw=self.left_ref[w]) - self.left_ref[w] = v - - def sign(self, e): - """Resolve the relative side of an edge to the absolute side.""" - # the recursion stack - dfs_stack = [e] - # dict to remember reference edges - old_ref = defaultdict(lambda: None) - - while dfs_stack: - e = dfs_stack.pop() - - if self.ref[e] is not None: - dfs_stack.append(e) # revisit e after finishing self.ref[e] - dfs_stack.append(self.ref[e]) # visit self.ref[e] next - old_ref[e] = self.ref[e] # remember value of self.ref[e] - self.ref[e] = None - else: - self.side[e] *= self.side[old_ref[e]] - - return self.side[e] - - def sign_recursive(self, e): - """Recursive version of :meth:`sign`.""" - if self.ref[e] is not None: - self.side[e] = self.side[e] * self.sign_recursive(self.ref[e]) - self.ref[e] = None - return self.side[e] - - -class PlanarEmbedding(nx.DiGraph): - """Represents a planar graph with its planar embedding. - - The planar embedding is given by a `combinatorial embedding - `_. - - .. note:: `check_planarity` is the preferred way to check if a graph is planar. - - **Neighbor ordering:** - - In comparison to a usual graph structure, the embedding also stores the - order of all neighbors for every vertex. - The order of the neighbors can be given in clockwise (cw) direction or - counterclockwise (ccw) direction. This order is stored as edge attributes - in the underlying directed graph. For the edge (u, v) the edge attribute - 'cw' is set to the neighbor of u that follows immediately after v in - clockwise direction. - - In order for a PlanarEmbedding to be valid it must fulfill multiple - conditions. It is possible to check if these conditions are fulfilled with - the method :meth:`check_structure`. - The conditions are: - - * Edges must go in both directions (because the edge attributes differ) - * Every edge must have a 'cw' and 'ccw' attribute which corresponds to a - correct planar embedding. - - As long as a PlanarEmbedding is invalid only the following methods should - be called: - - * :meth:`add_half_edge` - * :meth:`connect_components` - - Even though the graph is a subclass of nx.DiGraph, it can still be used - for algorithms that require undirected graphs, because the method - :meth:`is_directed` is overridden. This is possible, because a valid - PlanarGraph must have edges in both directions. - - **Half edges:** - - In methods like `add_half_edge` the term "half-edge" is used, which is - a term that is used in `doubly connected edge lists - `_. It is used - to emphasize that the edge is only in one direction and there exists - another half-edge in the opposite direction. - While conventional edges always have two faces (including outer face) next - to them, it is possible to assign each half-edge *exactly one* face. - For a half-edge (u, v) that is oriented such that u is below v then the - face that belongs to (u, v) is to the right of this half-edge. - - See Also - -------- - is_planar : - Preferred way to check if an existing graph is planar. - - check_planarity : - A convenient way to create a `PlanarEmbedding`. If not planar, - it returns a subgraph that shows this. - - Examples - -------- - - Create an embedding of a star graph (compare `nx.star_graph(3)`): - - >>> G = nx.PlanarEmbedding() - >>> G.add_half_edge(0, 1) - >>> G.add_half_edge(0, 2, ccw=1) - >>> G.add_half_edge(0, 3, ccw=2) - >>> G.add_half_edge(1, 0) - >>> G.add_half_edge(2, 0) - >>> G.add_half_edge(3, 0) - - Alternatively the same embedding can also be defined in counterclockwise - orientation. The following results in exactly the same PlanarEmbedding: - - >>> G = nx.PlanarEmbedding() - >>> G.add_half_edge(0, 1) - >>> G.add_half_edge(0, 3, cw=1) - >>> G.add_half_edge(0, 2, cw=3) - >>> G.add_half_edge(1, 0) - >>> G.add_half_edge(2, 0) - >>> G.add_half_edge(3, 0) - - After creating a graph, it is possible to validate that the PlanarEmbedding - object is correct: - - >>> G.check_structure() - - """ - - def __init__(self, incoming_graph_data=None, **attr): - super().__init__(incoming_graph_data=incoming_graph_data, **attr) - self.add_edge = self.__forbidden - self.add_edges_from = self.__forbidden - self.add_weighted_edges_from = self.__forbidden - - def __forbidden(self, *args, **kwargs): - """Forbidden operation - - Any edge additions to a PlanarEmbedding should be done using - method `add_half_edge`. - """ - raise NotImplementedError( - "Use `add_half_edge` method to add edges to a PlanarEmbedding." - ) - - def get_data(self): - """Converts the adjacency structure into a better readable structure. - - Returns - ------- - embedding : dict - A dict mapping all nodes to a list of neighbors sorted in - clockwise order. - - See Also - -------- - set_data - - """ - embedding = {} - for v in self: - embedding[v] = list(self.neighbors_cw_order(v)) - return embedding - - def set_data(self, data): - """Inserts edges according to given sorted neighbor list. - - The input format is the same as the output format of get_data(). - - Parameters - ---------- - data : dict - A dict mapping all nodes to a list of neighbors sorted in - clockwise order. - - See Also - -------- - get_data - - """ - for v in data: - ref = None - for w in reversed(data[v]): - self.add_half_edge(v, w, cw=ref) - ref = w - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges, updating the - PlanarEmbedding to account for any resulting edge removal. - Attempting to remove a non-existent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------ - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - """ - try: - for u in self._pred[n]: - succs_u = self._succ[u] - un_cw = succs_u[n]["cw"] - un_ccw = succs_u[n]["ccw"] - del succs_u[n] - del self._pred[u][n] - if n != un_cw: - succs_u[un_cw]["ccw"] = un_ccw - succs_u[un_ccw]["cw"] = un_cw - del self._node[n] - del self._succ[n] - del self._pred[n] - except KeyError as err: # NetworkXError if n not in self - raise nx.NetworkXError( - f"The node {n} is not in the planar embedding." - ) from err - nx._clear_cache(self) - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently ignored. - - See Also - -------- - remove_node - - Notes - ----- - When removing nodes from an iterator over the graph you are changing, - a `RuntimeError` will be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_nodes)`, and pass this - object to `G.remove_nodes_from`. - - """ - for n in nodes: - if n in self._node: - self.remove_node(n) - # silently skip non-existing nodes - - def neighbors_cw_order(self, v): - """Generator for the neighbors of v in clockwise order. - - Parameters - ---------- - v : node - - Yields - ------ - node - - """ - succs = self._succ[v] - if not succs: - # v has no neighbors - return - start_node = next(reversed(succs)) - yield start_node - current_node = succs[start_node]["cw"] - while start_node != current_node: - yield current_node - current_node = succs[current_node]["cw"] - - def add_half_edge(self, start_node, end_node, *, cw=None, ccw=None): - """Adds a half-edge from `start_node` to `end_node`. - - If the half-edge is not the first one out of `start_node`, a reference - node must be provided either in the clockwise (parameter `cw`) or in - the counterclockwise (parameter `ccw`) direction. Only one of `cw`/`ccw` - can be specified (or neither in the case of the first edge). - Note that specifying a reference in the clockwise (`cw`) direction means - inserting the new edge in the first counterclockwise position with - respect to the reference (and vice-versa). - - Parameters - ---------- - start_node : node - Start node of inserted edge. - end_node : node - End node of inserted edge. - cw, ccw: node - End node of reference edge. - Omit or pass `None` if adding the first out-half-edge of `start_node`. - - - Raises - ------ - NetworkXException - If the `cw` or `ccw` node is not a successor of `start_node`. - If `start_node` has successors, but neither `cw` or `ccw` is provided. - If both `cw` and `ccw` are specified. - - See Also - -------- - connect_components - """ - - succs = self._succ.get(start_node) - if succs: - # there is already some edge out of start_node - leftmost_nbr = next(reversed(self._succ[start_node])) - if cw is not None: - if cw not in succs: - raise nx.NetworkXError("Invalid clockwise reference node.") - if ccw is not None: - raise nx.NetworkXError("Only one of cw/ccw can be specified.") - ref_ccw = succs[cw]["ccw"] - super().add_edge(start_node, end_node, cw=cw, ccw=ref_ccw) - succs[ref_ccw]["cw"] = end_node - succs[cw]["ccw"] = end_node - # when (cw == leftmost_nbr), the newly added neighbor is - # already at the end of dict self._succ[start_node] and - # takes the place of the former leftmost_nbr - move_leftmost_nbr_to_end = cw != leftmost_nbr - elif ccw is not None: - if ccw not in succs: - raise nx.NetworkXError("Invalid counterclockwise reference node.") - ref_cw = succs[ccw]["cw"] - super().add_edge(start_node, end_node, cw=ref_cw, ccw=ccw) - succs[ref_cw]["ccw"] = end_node - succs[ccw]["cw"] = end_node - move_leftmost_nbr_to_end = True - else: - raise nx.NetworkXError( - "Node already has out-half-edge(s), either cw or ccw reference node required." - ) - if move_leftmost_nbr_to_end: - # LRPlanarity (via self.add_half_edge_first()) requires that - # we keep track of the leftmost neighbor, which we accomplish - # by keeping it as the last key in dict self._succ[start_node] - succs[leftmost_nbr] = succs.pop(leftmost_nbr) - - else: - if cw is not None or ccw is not None: - raise nx.NetworkXError("Invalid reference node.") - # adding the first edge out of start_node - super().add_edge(start_node, end_node, ccw=end_node, cw=end_node) - - def check_structure(self): - """Runs without exceptions if this object is valid. - - Checks that the following properties are fulfilled: - - * Edges go in both directions (because the edge attributes differ). - * Every edge has a 'cw' and 'ccw' attribute which corresponds to a - correct planar embedding. - - Running this method verifies that the underlying Graph must be planar. - - Raises - ------ - NetworkXException - This exception is raised with a short explanation if the - PlanarEmbedding is invalid. - """ - # Check fundamental structure - for v in self: - try: - sorted_nbrs = set(self.neighbors_cw_order(v)) - except KeyError as err: - msg = f"Bad embedding. Missing orientation for a neighbor of {v}" - raise nx.NetworkXException(msg) from err - - unsorted_nbrs = set(self[v]) - if sorted_nbrs != unsorted_nbrs: - msg = "Bad embedding. Edge orientations not set correctly." - raise nx.NetworkXException(msg) - for w in self[v]: - # Check if opposite half-edge exists - if not self.has_edge(w, v): - msg = "Bad embedding. Opposite half-edge is missing." - raise nx.NetworkXException(msg) - - # Check planarity - counted_half_edges = set() - for component in nx.connected_components(self): - if len(component) == 1: - # Don't need to check single node component - continue - num_nodes = len(component) - num_half_edges = 0 - num_faces = 0 - for v in component: - for w in self.neighbors_cw_order(v): - num_half_edges += 1 - if (v, w) not in counted_half_edges: - # We encountered a new face - num_faces += 1 - # Mark all half-edges belonging to this face - self.traverse_face(v, w, counted_half_edges) - num_edges = num_half_edges // 2 # num_half_edges is even - if num_nodes - num_edges + num_faces != 2: - # The result does not match Euler's formula - msg = "Bad embedding. The graph does not match Euler's formula" - raise nx.NetworkXException(msg) - - def add_half_edge_ccw(self, start_node, end_node, reference_neighbor): - """Adds a half-edge from start_node to end_node. - - The half-edge is added counter clockwise next to the existing half-edge - (start_node, reference_neighbor). - - Parameters - ---------- - start_node : node - Start node of inserted edge. - end_node : node - End node of inserted edge. - reference_neighbor: node - End node of reference edge. - - Raises - ------ - NetworkXException - If the reference_neighbor does not exist. - - See Also - -------- - add_half_edge - add_half_edge_cw - connect_components - - """ - self.add_half_edge(start_node, end_node, cw=reference_neighbor) - - def add_half_edge_cw(self, start_node, end_node, reference_neighbor): - """Adds a half-edge from start_node to end_node. - - The half-edge is added clockwise next to the existing half-edge - (start_node, reference_neighbor). - - Parameters - ---------- - start_node : node - Start node of inserted edge. - end_node : node - End node of inserted edge. - reference_neighbor: node - End node of reference edge. - - Raises - ------ - NetworkXException - If the reference_neighbor does not exist. - - See Also - -------- - add_half_edge - add_half_edge_ccw - connect_components - """ - self.add_half_edge(start_node, end_node, ccw=reference_neighbor) - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the half-edges (u, v) and (v, u) and update the - edge ordering around the removed edge. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - """ - try: - succs_u = self._succ[u] - succs_v = self._succ[v] - uv_cw = succs_u[v]["cw"] - uv_ccw = succs_u[v]["ccw"] - vu_cw = succs_v[u]["cw"] - vu_ccw = succs_v[u]["ccw"] - del succs_u[v] - del self._pred[v][u] - del succs_v[u] - del self._pred[u][v] - if v != uv_cw: - succs_u[uv_cw]["ccw"] = uv_ccw - succs_u[uv_ccw]["cw"] = uv_cw - if u != vu_cw: - succs_v[vu_cw]["ccw"] = vu_ccw - succs_v[vu_ccw]["cw"] = vu_cw - except KeyError as err: - raise nx.NetworkXError( - f"The edge {u}-{v} is not in the planar embedding." - ) from err - nx._clear_cache(self) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each pair of half-edges between the nodes given in the tuples - will be removed from the graph. The nodes can be passed as: - - - 2-tuples (u, v) half-edges (u, v) and (v, u). - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch = [(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - for e in ebunch: - u, v = e[:2] # ignore edge data - # assuming that the PlanarEmbedding is valid, if the half_edge - # (u, v) is in the graph, then so is half_edge (v, u) - if u in self._succ and v in self._succ[u]: - self.remove_edge(u, v) - - def connect_components(self, v, w): - """Adds half-edges for (v, w) and (w, v) at some position. - - This method should only be called if v and w are in different - components, or it might break the embedding. - This especially means that if `connect_components(v, w)` - is called it is not allowed to call `connect_components(w, v)` - afterwards. The neighbor orientations in both directions are - all set correctly after the first call. - - Parameters - ---------- - v : node - w : node - - See Also - -------- - add_half_edge - """ - if v in self._succ and self._succ[v]: - ref = next(reversed(self._succ[v])) - else: - ref = None - self.add_half_edge(v, w, cw=ref) - if w in self._succ and self._succ[w]: - ref = next(reversed(self._succ[w])) - else: - ref = None - self.add_half_edge(w, v, cw=ref) - - def add_half_edge_first(self, start_node, end_node): - """Add a half-edge and set end_node as start_node's leftmost neighbor. - - The new edge is inserted counterclockwise with respect to the current - leftmost neighbor, if there is one. - - Parameters - ---------- - start_node : node - end_node : node - - See Also - -------- - add_half_edge - connect_components - """ - succs = self._succ.get(start_node) - # the leftmost neighbor is the last entry in the - # self._succ[start_node] dict - leftmost_nbr = next(reversed(succs)) if succs else None - self.add_half_edge(start_node, end_node, cw=leftmost_nbr) - - def next_face_half_edge(self, v, w): - """Returns the following half-edge left of a face. - - Parameters - ---------- - v : node - w : node - - Returns - ------- - half-edge : tuple - """ - new_node = self[w][v]["ccw"] - return w, new_node - - def traverse_face(self, v, w, mark_half_edges=None): - """Returns nodes on the face that belong to the half-edge (v, w). - - The face that is traversed lies to the right of the half-edge (in an - orientation where v is below w). - - Optionally it is possible to pass a set to which all encountered half - edges are added. Before calling this method, this set must not include - any half-edges that belong to the face. - - Parameters - ---------- - v : node - Start node of half-edge. - w : node - End node of half-edge. - mark_half_edges: set, optional - Set to which all encountered half-edges are added. - - Returns - ------- - face : list - A list of nodes that lie on this face. - """ - if mark_half_edges is None: - mark_half_edges = set() - - face_nodes = [v] - mark_half_edges.add((v, w)) - prev_node = v - cur_node = w - # Last half-edge is (incoming_node, v) - incoming_node = self[v][w]["cw"] - - while cur_node != v or prev_node != incoming_node: - face_nodes.append(cur_node) - prev_node, cur_node = self.next_face_half_edge(prev_node, cur_node) - if (prev_node, cur_node) in mark_half_edges: - raise nx.NetworkXException("Bad planar embedding. Impossible face.") - mark_half_edges.add((prev_node, cur_node)) - - return face_nodes - - def is_directed(self): - """A valid PlanarEmbedding is undirected. - - All reverse edges are contained, i.e. for every existing - half-edge (v, w) the half-edge in the opposite direction (w, v) is also - contained. - """ - return False - - def copy(self, as_view=False): - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - super(self.__class__, G).add_edges_from( - (u, v, datadict.copy()) - for u, nbrs in self._adj.items() - for v, datadict in nbrs.items() - ) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/polynomials.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/polynomials.py deleted file mode 100644 index 7ebc755..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/polynomials.py +++ /dev/null @@ -1,306 +0,0 @@ -"""Provides algorithms supporting the computation of graph polynomials. - -Graph polynomials are polynomial-valued graph invariants that encode a wide -variety of structural information. Examples include the Tutte polynomial, -chromatic polynomial, characteristic polynomial, and matching polynomial. An -extensive treatment is provided in [1]_. - -For a simple example, the `~sympy.matrices.matrices.MatrixDeterminant.charpoly` -method can be used to compute the characteristic polynomial from the adjacency -matrix of a graph. Consider the complete graph ``K_4``: - ->>> import sympy ->>> x = sympy.Symbol("x") ->>> G = nx.complete_graph(4) ->>> A = nx.to_numpy_array(G, dtype=int) ->>> M = sympy.SparseMatrix(A) ->>> M.charpoly(x).as_expr() -x**4 - 6*x**2 - 8*x - 3 - - -.. [1] Y. Shi, M. Dehmer, X. Li, I. Gutman, - "Graph Polynomials" -""" - -from collections import deque - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["tutte_polynomial", "chromatic_polynomial"] - - -@not_implemented_for("directed") -@nx._dispatchable -def tutte_polynomial(G): - r"""Returns the Tutte polynomial of `G` - - This function computes the Tutte polynomial via an iterative version of - the deletion-contraction algorithm. - - The Tutte polynomial `T_G(x, y)` is a fundamental graph polynomial invariant in - two variables. It encodes a wide array of information related to the - edge-connectivity of a graph; "Many problems about graphs can be reduced to - problems of finding and evaluating the Tutte polynomial at certain values" [1]_. - In fact, every deletion-contraction-expressible feature of a graph is a - specialization of the Tutte polynomial [2]_ (see Notes for examples). - - There are several equivalent definitions; here are three: - - Def 1 (rank-nullity expansion): For `G` an undirected graph, `n(G)` the - number of vertices of `G`, `E` the edge set of `G`, `V` the vertex set of - `G`, and `c(A)` the number of connected components of the graph with vertex - set `V` and edge set `A` [3]_: - - .. math:: - - T_G(x, y) = \sum_{A \in E} (x-1)^{c(A) - c(E)} (y-1)^{c(A) + |A| - n(G)} - - Def 2 (spanning tree expansion): Let `G` be an undirected graph, `T` a spanning - tree of `G`, and `E` the edge set of `G`. Let `E` have an arbitrary strict - linear order `L`. Let `B_e` be the unique minimal nonempty edge cut of - $E \setminus T \cup {e}$. An edge `e` is internally active with respect to - `T` and `L` if `e` is the least edge in `B_e` according to the linear order - `L`. The internal activity of `T` (denoted `i(T)`) is the number of edges - in $E \setminus T$ that are internally active with respect to `T` and `L`. - Let `P_e` be the unique path in $T \cup {e}$ whose source and target vertex - are the same. An edge `e` is externally active with respect to `T` and `L` - if `e` is the least edge in `P_e` according to the linear order `L`. The - external activity of `T` (denoted `e(T)`) is the number of edges in - $E \setminus T$ that are externally active with respect to `T` and `L`. - Then [4]_ [5]_: - - .. math:: - - T_G(x, y) = \sum_{T \text{ a spanning tree of } G} x^{i(T)} y^{e(T)} - - Def 3 (deletion-contraction recurrence): For `G` an undirected graph, `G-e` - the graph obtained from `G` by deleting edge `e`, `G/e` the graph obtained - from `G` by contracting edge `e`, `k(G)` the number of cut-edges of `G`, - and `l(G)` the number of self-loops of `G`: - - .. math:: - T_G(x, y) = \begin{cases} - x^{k(G)} y^{l(G)}, & \text{if all edges are cut-edges or self-loops} \\ - T_{G-e}(x, y) + T_{G/e}(x, y), & \text{otherwise, for an arbitrary edge $e$ not a cut-edge or loop} - \end{cases} - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - instance of `sympy.core.add.Add` - A Sympy expression representing the Tutte polynomial for `G`. - - Examples - -------- - >>> C = nx.cycle_graph(5) - >>> nx.tutte_polynomial(C) - x**4 + x**3 + x**2 + x + y - - >>> D = nx.diamond_graph() - >>> nx.tutte_polynomial(D) - x**3 + 2*x**2 + 2*x*y + x + y**2 + y - - Notes - ----- - Some specializations of the Tutte polynomial: - - - `T_G(1, 1)` counts the number of spanning trees of `G` - - `T_G(1, 2)` counts the number of connected spanning subgraphs of `G` - - `T_G(2, 1)` counts the number of spanning forests in `G` - - `T_G(0, 2)` counts the number of strong orientations of `G` - - `T_G(2, 0)` counts the number of acyclic orientations of `G` - - Edge contraction is defined and deletion-contraction is introduced in [6]_. - Combinatorial meaning of the coefficients is introduced in [7]_. - Universality, properties, and applications are discussed in [8]_. - - Practically, up-front computation of the Tutte polynomial may be useful when - users wish to repeatedly calculate edge-connectivity-related information - about one or more graphs. - - References - ---------- - .. [1] M. Brandt, - "The Tutte Polynomial." - Talking About Combinatorial Objects Seminar, 2015 - https://math.berkeley.edu/~brandtm/talks/tutte.pdf - .. [2] A. Björklund, T. Husfeldt, P. Kaski, M. Koivisto, - "Computing the Tutte polynomial in vertex-exponential time" - 49th Annual IEEE Symposium on Foundations of Computer Science, 2008 - https://ieeexplore.ieee.org/abstract/document/4691000 - .. [3] Y. Shi, M. Dehmer, X. Li, I. Gutman, - "Graph Polynomials," p. 14 - .. [4] Y. Shi, M. Dehmer, X. Li, I. Gutman, - "Graph Polynomials," p. 46 - .. [5] A. Nešetril, J. Goodall, - "Graph invariants, homomorphisms, and the Tutte polynomial" - https://iuuk.mff.cuni.cz/~andrew/Tutte.pdf - .. [6] D. B. West, - "Introduction to Graph Theory," p. 84 - .. [7] G. Coutinho, - "A brief introduction to the Tutte polynomial" - Structural Analysis of Complex Networks, 2011 - https://homepages.dcc.ufmg.br/~gabriel/seminars/coutinho_tuttepolynomial_seminar.pdf - .. [8] J. A. Ellis-Monaghan, C. Merino, - "Graph polynomials and their applications I: The Tutte polynomial" - Structural Analysis of Complex Networks, 2011 - https://arxiv.org/pdf/0803.3079.pdf - """ - import sympy - - x = sympy.Symbol("x") - y = sympy.Symbol("y") - stack = deque() - stack.append(nx.MultiGraph(G)) - - polynomial = 0 - while stack: - G = stack.pop() - bridges = set(nx.bridges(G)) - - e = None - for i in G.edges: - if (i[0], i[1]) not in bridges and i[0] != i[1]: - e = i - break - if not e: - loops = list(nx.selfloop_edges(G, keys=True)) - polynomial += x ** len(bridges) * y ** len(loops) - else: - # deletion-contraction - C = nx.contracted_edge(G, e, self_loops=True) - C.remove_edge(e[0], e[0]) - G.remove_edge(*e) - stack.append(G) - stack.append(C) - return sympy.simplify(polynomial) - - -@not_implemented_for("directed") -@nx._dispatchable -def chromatic_polynomial(G): - r"""Returns the chromatic polynomial of `G` - - This function computes the chromatic polynomial via an iterative version of - the deletion-contraction algorithm. - - The chromatic polynomial `X_G(x)` is a fundamental graph polynomial - invariant in one variable. Evaluating `X_G(k)` for an natural number `k` - enumerates the proper k-colorings of `G`. - - There are several equivalent definitions; here are three: - - Def 1 (explicit formula): - For `G` an undirected graph, `c(G)` the number of connected components of - `G`, `E` the edge set of `G`, and `G(S)` the spanning subgraph of `G` with - edge set `S` [1]_: - - .. math:: - - X_G(x) = \sum_{S \subseteq E} (-1)^{|S|} x^{c(G(S))} - - - Def 2 (interpolating polynomial): - For `G` an undirected graph, `n(G)` the number of vertices of `G`, `k_0 = 0`, - and `k_i` the number of distinct ways to color the vertices of `G` with `i` - unique colors (for `i` a natural number at most `n(G)`), `X_G(x)` is the - unique Lagrange interpolating polynomial of degree `n(G)` through the points - `(0, k_0), (1, k_1), \dots, (n(G), k_{n(G)})` [2]_. - - - Def 3 (chromatic recurrence): - For `G` an undirected graph, `G-e` the graph obtained from `G` by deleting - edge `e`, `G/e` the graph obtained from `G` by contracting edge `e`, `n(G)` - the number of vertices of `G`, and `e(G)` the number of edges of `G` [3]_: - - .. math:: - X_G(x) = \begin{cases} - x^{n(G)}, & \text{if $e(G)=0$} \\ - X_{G-e}(x) - X_{G/e}(x), & \text{otherwise, for an arbitrary edge $e$} - \end{cases} - - This formulation is also known as the Fundamental Reduction Theorem [4]_. - - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - instance of `sympy.core.add.Add` - A Sympy expression representing the chromatic polynomial for `G`. - - Examples - -------- - >>> C = nx.cycle_graph(5) - >>> nx.chromatic_polynomial(C) - x**5 - 5*x**4 + 10*x**3 - 10*x**2 + 4*x - - >>> G = nx.complete_graph(4) - >>> nx.chromatic_polynomial(G) - x**4 - 6*x**3 + 11*x**2 - 6*x - - Notes - ----- - Interpretation of the coefficients is discussed in [5]_. Several special - cases are listed in [2]_. - - The chromatic polynomial is a specialization of the Tutte polynomial; in - particular, ``X_G(x) = T_G(x, 0)`` [6]_. - - The chromatic polynomial may take negative arguments, though evaluations - may not have chromatic interpretations. For instance, ``X_G(-1)`` enumerates - the acyclic orientations of `G` [7]_. - - References - ---------- - .. [1] D. B. West, - "Introduction to Graph Theory," p. 222 - .. [2] E. W. Weisstein - "Chromatic Polynomial" - MathWorld--A Wolfram Web Resource - https://mathworld.wolfram.com/ChromaticPolynomial.html - .. [3] D. B. West, - "Introduction to Graph Theory," p. 221 - .. [4] J. Zhang, J. Goodall, - "An Introduction to Chromatic Polynomials" - https://math.mit.edu/~apost/courses/18.204_2018/Julie_Zhang_paper.pdf - .. [5] R. C. Read, - "An Introduction to Chromatic Polynomials" - Journal of Combinatorial Theory, 1968 - https://math.berkeley.edu/~mrklug/ReadChromatic.pdf - .. [6] W. T. Tutte, - "Graph-polynomials" - Advances in Applied Mathematics, 2004 - https://www.sciencedirect.com/science/article/pii/S0196885803000411 - .. [7] R. P. Stanley, - "Acyclic orientations of graphs" - Discrete Mathematics, 2006 - https://math.mit.edu/~rstan/pubs/pubfiles/18.pdf - """ - import sympy - - x = sympy.Symbol("x") - stack = deque() - stack.append(nx.MultiGraph(G, contraction_idx=0)) - - polynomial = 0 - while stack: - G = stack.pop() - edges = list(G.edges) - if not edges: - polynomial += (-1) ** G.graph["contraction_idx"] * x ** len(G) - else: - e = edges[0] - C = nx.contracted_edge(G, e, self_loops=True) - C.graph["contraction_idx"] = G.graph["contraction_idx"] + 1 - C.remove_edge(e[0], e[0]) - G.remove_edge(*e) - stack.append(G) - stack.append(C) - return polynomial diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/reciprocity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/reciprocity.py deleted file mode 100644 index 5ea7ed2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/reciprocity.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Algorithms to calculate reciprocity in a directed graph.""" - -import networkx as nx -from networkx import NetworkXError - -from ..utils import not_implemented_for - -__all__ = ["reciprocity", "overall_reciprocity"] - - -@not_implemented_for("undirected", "multigraph") -@nx._dispatchable -def reciprocity(G, nodes=None): - r"""Compute the reciprocity in a directed graph. - - The reciprocity of a directed graph is defined as the ratio - of the number of edges pointing in both directions to the total - number of edges in the graph. - Formally, $r = |{(u,v) \in G|(v,u) \in G}| / |{(u,v) \in G}|$. - - The reciprocity of a single node u is defined similarly, - it is the ratio of the number of edges in both directions to - the total number of edges attached to node u. - - Parameters - ---------- - G : graph - A networkx directed graph - nodes : container of nodes, optional (default=whole graph) - Compute reciprocity for nodes in this container. - - Returns - ------- - out : dictionary - Reciprocity keyed by node label. - - Notes - ----- - The reciprocity is not defined for isolated nodes. - In such cases this function will return None. - - """ - # If `nodes` is not specified, calculate the reciprocity of the graph. - if nodes is None: - return overall_reciprocity(G) - - # If `nodes` represents a single node in the graph, return only its - # reciprocity. - if nodes in G: - reciprocity = next(_reciprocity_iter(G, nodes))[1] - if reciprocity is None: - raise NetworkXError("Not defined for isolated nodes.") - else: - return reciprocity - - # Otherwise, `nodes` represents an iterable of nodes, so return a - # dictionary mapping node to its reciprocity. - return dict(_reciprocity_iter(G, nodes)) - - -def _reciprocity_iter(G, nodes): - """Return an iterator of (node, reciprocity).""" - n = G.nbunch_iter(nodes) - for node in n: - pred = set(G.predecessors(node)) - succ = set(G.successors(node)) - overlap = pred & succ - n_total = len(pred) + len(succ) - - # Reciprocity is not defined for isolated nodes. - # Return None. - if n_total == 0: - yield (node, None) - else: - reciprocity = 2 * len(overlap) / n_total - yield (node, reciprocity) - - -@not_implemented_for("undirected", "multigraph") -@nx._dispatchable -def overall_reciprocity(G): - """Compute the reciprocity for the whole graph. - - See the doc of reciprocity for the definition. - - Parameters - ---------- - G : graph - A networkx graph - - """ - n_all_edge = G.number_of_edges() - n_overlap_edge = (n_all_edge - G.to_undirected().number_of_edges()) * 2 - - if n_all_edge == 0: - raise NetworkXError("Not defined for empty graphs") - - return n_overlap_edge / n_all_edge diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/regular.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/regular.py deleted file mode 100644 index f483ef3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/regular.py +++ /dev/null @@ -1,215 +0,0 @@ -"""Functions for computing and verifying regular graphs.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["is_regular", "is_k_regular", "k_factor"] - - -@nx._dispatchable -def is_regular(G): - """Determines whether the graph ``G`` is a regular graph. - - A regular graph is a graph where each vertex has the same degree. A - regular digraph is a graph where the indegree and outdegree of each - vertex are equal. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - bool - Whether the given graph or digraph is regular. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 1)]) - >>> nx.is_regular(G) - True - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept("Graph has no nodes.") - n1 = nx.utils.arbitrary_element(G) - if not G.is_directed(): - d1 = G.degree(n1) - return all(d1 == d for _, d in G.degree) - else: - d_in = G.in_degree(n1) - in_regular = all(d_in == d for _, d in G.in_degree) - d_out = G.out_degree(n1) - out_regular = all(d_out == d for _, d in G.out_degree) - return in_regular and out_regular - - -@not_implemented_for("directed") -@nx._dispatchable -def is_k_regular(G, k): - """Determines whether the graph ``G`` is a k-regular graph. - - A k-regular graph is a graph where each vertex has degree k. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - bool - Whether the given graph is k-regular. - - Examples - -------- - >>> G = nx.Graph([(1, 2), (2, 3), (3, 4), (4, 1)]) - >>> nx.is_k_regular(G, k=3) - False - - """ - return all(d == k for n, d in G.degree) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(preserve_edge_attrs=True, returns_graph=True) -def k_factor(G, k, matching_weight="weight"): - """Compute a k-factor of G - - A k-factor of a graph is a spanning k-regular subgraph. - A spanning k-regular subgraph of G is a subgraph that contains - each vertex of G and a subset of the edges of G such that each - vertex has degree k. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - matching_weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - Used for finding the max-weighted perfect matching. - If key not found, uses 1 as weight. - - Returns - ------- - G2 : NetworkX graph - A k-factor of G - - Examples - -------- - >>> G = nx.Graph([(1, 2), (2, 3), (3, 4), (4, 1)]) - >>> G2 = nx.k_factor(G, k=1) - >>> G2.edges() - EdgeView([(1, 2), (3, 4)]) - - References - ---------- - .. [1] "An algorithm for computing simple k-factors.", - Meijer, Henk, Yurai Núñez-Rodríguez, and David Rappaport, - Information processing letters, 2009. - """ - - from networkx.algorithms.matching import is_perfect_matching, max_weight_matching - - class LargeKGadget: - def __init__(self, k, degree, node, g): - self.original = node - self.g = g - self.k = k - self.degree = degree - - self.outer_vertices = [(node, x) for x in range(degree)] - self.core_vertices = [(node, x + degree) for x in range(degree - k)] - - def replace_node(self): - adj_view = self.g[self.original] - neighbors = list(adj_view.keys()) - edge_attrs = list(adj_view.values()) - for outer, neighbor, edge_attrs in zip( - self.outer_vertices, neighbors, edge_attrs - ): - self.g.add_edge(outer, neighbor, **edge_attrs) - for core in self.core_vertices: - for outer in self.outer_vertices: - self.g.add_edge(core, outer) - self.g.remove_node(self.original) - - def restore_node(self): - self.g.add_node(self.original) - for outer in self.outer_vertices: - adj_view = self.g[outer] - for neighbor, edge_attrs in list(adj_view.items()): - if neighbor not in self.core_vertices: - self.g.add_edge(self.original, neighbor, **edge_attrs) - break - g.remove_nodes_from(self.outer_vertices) - g.remove_nodes_from(self.core_vertices) - - class SmallKGadget: - def __init__(self, k, degree, node, g): - self.original = node - self.k = k - self.degree = degree - self.g = g - - self.outer_vertices = [(node, x) for x in range(degree)] - self.inner_vertices = [(node, x + degree) for x in range(degree)] - self.core_vertices = [(node, x + 2 * degree) for x in range(k)] - - def replace_node(self): - adj_view = self.g[self.original] - for outer, inner, (neighbor, edge_attrs) in zip( - self.outer_vertices, self.inner_vertices, list(adj_view.items()) - ): - self.g.add_edge(outer, inner) - self.g.add_edge(outer, neighbor, **edge_attrs) - for core in self.core_vertices: - for inner in self.inner_vertices: - self.g.add_edge(core, inner) - self.g.remove_node(self.original) - - def restore_node(self): - self.g.add_node(self.original) - for outer in self.outer_vertices: - adj_view = self.g[outer] - for neighbor, edge_attrs in adj_view.items(): - if neighbor not in self.core_vertices: - self.g.add_edge(self.original, neighbor, **edge_attrs) - break - self.g.remove_nodes_from(self.outer_vertices) - self.g.remove_nodes_from(self.inner_vertices) - self.g.remove_nodes_from(self.core_vertices) - - # Step 1 - if any(d < k for _, d in G.degree): - raise nx.NetworkXUnfeasible("Graph contains a vertex with degree less than k") - g = G.copy() - - # Step 2 - gadgets = [] - for node, degree in list(g.degree): - if k < degree / 2.0: - gadget = SmallKGadget(k, degree, node, g) - else: - gadget = LargeKGadget(k, degree, node, g) - gadget.replace_node() - gadgets.append(gadget) - - # Step 3 - matching = max_weight_matching(g, maxcardinality=True, weight=matching_weight) - - # Step 4 - if not is_perfect_matching(g, matching): - raise nx.NetworkXUnfeasible( - "Cannot find k-factor because no perfect matching exists" - ) - - for edge in g.edges(): - if edge not in matching and (edge[1], edge[0]) not in matching: - g.remove_edge(edge[0], edge[1]) - - for gadget in gadgets: - gadget.restore_node() - - return g diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/richclub.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/richclub.py deleted file mode 100644 index 445b27d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/richclub.py +++ /dev/null @@ -1,138 +0,0 @@ -"""Functions for computing rich-club coefficients.""" - -from itertools import accumulate - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["rich_club_coefficient"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def rich_club_coefficient(G, normalized=True, Q=100, seed=None): - r"""Returns the rich-club coefficient of the graph `G`. - - For each degree *k*, the *rich-club coefficient* is the ratio of the - number of actual to the number of potential edges for nodes with - degree greater than *k*: - - .. math:: - - \phi(k) = \frac{2 E_k}{N_k (N_k - 1)} - - where `N_k` is the number of nodes with degree larger than *k*, and - `E_k` is the number of edges among those nodes. - - Parameters - ---------- - G : NetworkX graph - Undirected graph with neither parallel edges nor self-loops. - normalized : bool (optional) - Normalize using randomized network as in [1]_ - Q : float (optional, default=100) - If `normalized` is True, perform `Q * m` double-edge - swaps, where `m` is the number of edges in `G`, to use as a - null-model for normalization. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - rc : dictionary - A dictionary, keyed by degree, with rich-club coefficient values. - - Raises - ------ - NetworkXError - If `G` has fewer than four nodes and ``normalized=True``. - A randomly sampled graph for normalization cannot be generated in this case. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - >>> rc = nx.rich_club_coefficient(G, normalized=False, seed=42) - >>> rc[0] - 0.4 - - Notes - ----- - The rich club definition and algorithm are found in [1]_. This - algorithm ignores any edge weights and is not defined for directed - graphs or graphs with parallel edges or self loops. - - Normalization is done by computing the rich club coefficient for a randomly - sampled graph with the same degree distribution as `G` by - repeatedly swapping the endpoints of existing edges. For graphs with fewer than 4 - nodes, it is not possible to generate a random graph with a prescribed - degree distribution, as the degree distribution fully determines the graph - (hence making the coefficients trivially normalized to 1). - This function raises an exception in this case. - - Estimates for appropriate values of `Q` are found in [2]_. - - References - ---------- - .. [1] Julian J. McAuley, Luciano da Fontoura Costa, - and Tibério S. Caetano, - "The rich-club phenomenon across complex network hierarchies", - Applied Physics Letters Vol 91 Issue 8, August 2007. - https://arxiv.org/abs/physics/0701290 - .. [2] R. Milo, N. Kashtan, S. Itzkovitz, M. E. J. Newman, U. Alon, - "Uniform generation of random graphs with arbitrary degree - sequences", 2006. https://arxiv.org/abs/cond-mat/0312028 - """ - if nx.number_of_selfloops(G) > 0: - raise Exception( - "rich_club_coefficient is not implemented for graphs with self loops." - ) - rc = _compute_rc(G) - if normalized: - # make R a copy of G, randomize with Q*|E| double edge swaps - # and use rich_club coefficient of R to normalize - R = G.copy() - E = R.number_of_edges() - nx.double_edge_swap(R, Q * E, max_tries=Q * E * 10, seed=seed) - rcran = _compute_rc(R) - rc = {k: v / rcran[k] for k, v in rc.items()} - return rc - - -def _compute_rc(G): - """Returns the rich-club coefficient for each degree in the graph - `G`. - - `G` is an undirected graph without multiedges. - - Returns a dictionary mapping degree to rich-club coefficient for - that degree. - - """ - deghist = nx.degree_histogram(G) - total = sum(deghist) - # Compute the number of nodes with degree greater than `k`, for each - # degree `k` (omitting the last entry, which is zero). - nks = (total - cs for cs in accumulate(deghist) if total - cs > 1) - # Create a sorted list of pairs of edge endpoint degrees. - # - # The list is sorted in reverse order so that we can pop from the - # right side of the list later, instead of popping from the left - # side of the list, which would have a linear time cost. - edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()), reverse=True) - ek = G.number_of_edges() - if ek == 0: - return {} - - k1, k2 = edge_degrees.pop() - rc = {} - for d, nk in enumerate(nks): - while k1 <= d: - if len(edge_degrees) == 0: - ek = 0 - break - k1, k2 = edge_degrees.pop() - ek -= 1 - rc[d] = 2 * ek / (nk * (nk - 1)) - return rc diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/__init__.py deleted file mode 100644 index eb0d91c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from networkx.algorithms.shortest_paths.generic import * -from networkx.algorithms.shortest_paths.unweighted import * -from networkx.algorithms.shortest_paths.weighted import * -from networkx.algorithms.shortest_paths.astar import * -from networkx.algorithms.shortest_paths.dense import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/astar.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/astar.py deleted file mode 100644 index 8d98847..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/astar.py +++ /dev/null @@ -1,241 +0,0 @@ -"""Shortest paths and path lengths using the A* ("A star") algorithm.""" - -from heapq import heappop, heappush -from itertools import count - -import networkx as nx -from networkx.algorithms.shortest_paths.weighted import _weight_function - -__all__ = ["astar_path", "astar_path_length"] - - -@nx._dispatchable(edge_attrs="weight", preserve_node_attrs="heuristic") -def astar_path(G, source, target, heuristic=None, weight="weight", *, cutoff=None): - """Returns a list of nodes in a shortest path between source and target - using the A* ("A-star") algorithm. - - There may be more than one shortest path. This returns only one. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - heuristic : function - A function to evaluate the estimate of the distance - from the a node to the target. The function takes - two nodes arguments and must return a number. - If the heuristic is inadmissible (if it might - overestimate the cost of reaching the goal from a node), - the result may not be a shortest path. - The algorithm does not support updating heuristic - values for the same node due to caching the first - heuristic calculation per node. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - cutoff : float, optional - If this is provided, the search will be bounded to this value. I.e. if - the evaluation function surpasses this value for a node n, the node will not - be expanded further and will be ignored. More formally, let h'(n) be the - heuristic function, and g(n) be the cost of reaching n from the source node. Then, - if g(n) + h'(n) > cutoff, the node will not be explored further. - Note that if the heuristic is inadmissible, it is possible that paths - are ignored even though they satisfy the cutoff. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> print(nx.astar_path(G, 0, 4)) - [0, 1, 2, 3, 4] - >>> G = nx.grid_graph(dim=[3, 3]) # nodes are two-tuples (x,y) - >>> nx.set_edge_attributes(G, {e: e[1][0] * 2 for e in G.edges()}, "cost") - >>> def dist(a, b): - ... (x1, y1) = a - ... (x2, y2) = b - ... return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5 - >>> print(nx.astar_path(G, (0, 0), (2, 2), heuristic=dist, weight="cost")) - [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - See Also - -------- - shortest_path, dijkstra_path - - """ - if source not in G: - raise nx.NodeNotFound(f"Source {source} is not in G") - - if target not in G: - raise nx.NodeNotFound(f"Target {target} is not in G") - - if heuristic is None: - # The default heuristic is h=0 - same as Dijkstra's algorithm - def heuristic(u, v): - return 0 - - push = heappush - pop = heappop - weight = _weight_function(G, weight) - - G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) - - # The queue stores priority, node, cost to reach, and parent. - # Uses Python heapq to keep in priority order. - # Add a counter to the queue to prevent the underlying heap from - # attempting to compare the nodes themselves. The hash breaks ties in the - # priority and is guaranteed unique for all nodes in the graph. - c = count() - queue = [(0, next(c), source, 0, None)] - - # Maps enqueued nodes to distance of discovered paths and the - # computed heuristics to target. We avoid computing the heuristics - # more than once and inserting the node into the queue too many times. - enqueued = {} - # Maps explored nodes to parent closest to the source. - explored = {} - - while queue: - # Pop the smallest item from queue. - _, __, curnode, dist, parent = pop(queue) - - if curnode == target: - path = [curnode] - node = parent - while node is not None: - path.append(node) - node = explored[node] - path.reverse() - return path - - if curnode in explored: - # Do not override the parent of starting node - if explored[curnode] is None: - continue - - # Skip bad paths that were enqueued before finding a better one - qcost, h = enqueued[curnode] - if qcost < dist: - continue - - explored[curnode] = parent - - for neighbor, w in G_succ[curnode].items(): - cost = weight(curnode, neighbor, w) - if cost is None: - continue - ncost = dist + cost - if neighbor in enqueued: - qcost, h = enqueued[neighbor] - # if qcost <= ncost, a less costly path from the - # neighbor to the source was already determined. - # Therefore, we won't attempt to push this neighbor - # to the queue - if qcost <= ncost: - continue - else: - h = heuristic(neighbor, target) - - if cutoff and ncost + h > cutoff: - continue - - enqueued[neighbor] = ncost, h - push(queue, (ncost + h, next(c), neighbor, ncost, curnode)) - - raise nx.NetworkXNoPath(f"Node {target} not reachable from {source}") - - -@nx._dispatchable(edge_attrs="weight", preserve_node_attrs="heuristic") -def astar_path_length( - G, source, target, heuristic=None, weight="weight", *, cutoff=None -): - """Returns the length of the shortest path between source and target using - the A* ("A-star") algorithm. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - heuristic : function - A function to evaluate the estimate of the distance - from the a node to the target. The function takes - two nodes arguments and must return a number. - If the heuristic is inadmissible (if it might - overestimate the cost of reaching the goal from a node), - the result may not be a shortest path. - The algorithm does not support updating heuristic - values for the same node due to caching the first - heuristic calculation per node. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - cutoff : float, optional - If this is provided, the search will be bounded to this value. I.e. if - the evaluation function surpasses this value for a node n, the node will not - be expanded further and will be ignored. More formally, let h'(n) be the - heuristic function, and g(n) be the cost of reaching n from the source node. Then, - if g(n) + h'(n) > cutoff, the node will not be explored further. - Note that if the heuristic is inadmissible, it is possible that paths - are ignored even though they satisfy the cutoff. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - See Also - -------- - astar_path - - """ - if source not in G or target not in G: - msg = f"Either source {source} or target {target} is not in G" - raise nx.NodeNotFound(msg) - - weight = _weight_function(G, weight) - path = astar_path(G, source, target, heuristic, weight, cutoff=cutoff) - return sum(weight(u, v, G[u][v]) for u, v in zip(path[:-1], path[1:])) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/dense.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/dense.py deleted file mode 100644 index 107b920..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/dense.py +++ /dev/null @@ -1,260 +0,0 @@ -"""Floyd-Warshall algorithm for shortest paths.""" - -import networkx as nx - -__all__ = [ - "floyd_warshall", - "floyd_warshall_predecessor_and_distance", - "reconstruct_path", - "floyd_warshall_numpy", -] - - -@nx._dispatchable(edge_attrs="weight") -def floyd_warshall_numpy(G, nodelist=None, weight="weight"): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - This algorithm for finding shortest paths takes advantage of - matrix representations of a graph and works well for dense - graphs where all-pairs shortest path lengths are desired. - The results are returned as a NumPy array, distance[i, j], - where i and j are the indexes of two nodes in nodelist. - The entry distance[i, j] is the distance along a shortest - path from i to j. If no path exists the distance is Inf. - - Parameters - ---------- - G : NetworkX graph - - nodelist : list, optional (default=G.nodes) - The rows and columns are ordered by the nodes in nodelist. - If nodelist is None then the ordering is produced by G.nodes. - Nodelist should include all nodes in G. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - - Returns - ------- - distance : 2D numpy.ndarray - A numpy array of shortest path distances between nodes. - If there is no path between two nodes the value is Inf. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... [(0, 1, 5), (1, 2, 2), (2, 3, -3), (1, 3, 10), (3, 2, 8)] - ... ) - >>> nx.floyd_warshall_numpy(G) - array([[ 0., 5., 7., 4.], - [inf, 0., 2., -1.], - [inf, inf, 0., -3.], - [inf, inf, 8., 0.]]) - - Notes - ----- - Floyd's algorithm is appropriate for finding shortest paths in - dense graphs or graphs with negative weights when Dijkstra's - algorithm fails. This algorithm can still fail if there are negative - cycles. It has running time $O(n^3)$ with running space of $O(n^2)$. - - Raises - ------ - NetworkXError - If nodelist is not a list of the nodes in G. - """ - import numpy as np - - if nodelist is not None: - if not (len(nodelist) == len(G) == len(set(nodelist))): - raise nx.NetworkXError( - "nodelist must contain every node in G with no repeats." - "If you wanted a subgraph of G use G.subgraph(nodelist)" - ) - - # To handle cases when an edge has weight=0, we must make sure that - # nonedges are not given the value 0 as well. - A = nx.to_numpy_array( - G, nodelist, multigraph_weight=min, weight=weight, nonedge=np.inf - ) - n, m = A.shape - np.fill_diagonal(A, 0) # diagonal elements should be zero - for i in range(n): - # The second term has the same shape as A due to broadcasting - A = np.minimum(A, A[i, :][np.newaxis, :] + A[:, i][:, np.newaxis]) - return A - - -@nx._dispatchable(edge_attrs="weight") -def floyd_warshall_predecessor_and_distance(G, weight="weight"): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default= 'weight') - Edge data key corresponding to the edge weight. - - Returns - ------- - predecessor,distance : dictionaries - Dictionaries, keyed by source and target, of predecessors and distances - in the shortest path. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... [ - ... ("s", "u", 10), - ... ("s", "x", 5), - ... ("u", "v", 1), - ... ("u", "x", 2), - ... ("v", "y", 1), - ... ("x", "u", 3), - ... ("x", "v", 5), - ... ("x", "y", 2), - ... ("y", "s", 7), - ... ("y", "v", 6), - ... ] - ... ) - >>> predecessors, _ = nx.floyd_warshall_predecessor_and_distance(G) - >>> print(nx.reconstruct_path("s", "v", predecessors)) - ['s', 'x', 'u', 'v'] - - Notes - ----- - Floyd's algorithm is appropriate for finding shortest paths - in dense graphs or graphs with negative weights when Dijkstra's algorithm - fails. This algorithm can still fail if there are negative cycles. - It has running time $O(n^3)$ with running space of $O(n^2)$. - - See Also - -------- - floyd_warshall - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - """ - from collections import defaultdict - - # dictionary-of-dictionaries representation for dist and pred - # use some defaultdict magick here - # for dist the default is the floating point inf value - dist = defaultdict(lambda: defaultdict(lambda: float("inf"))) - for u in G: - dist[u][u] = 0 - pred = defaultdict(dict) - # initialize path distance dictionary to be the adjacency matrix - # also set the distance to self to 0 (zero diagonal) - undirected = not G.is_directed() - for u, v, d in G.edges(data=True): - e_weight = d.get(weight, 1.0) - dist[u][v] = min(e_weight, dist[u][v]) - pred[u][v] = u - if undirected: - dist[v][u] = min(e_weight, dist[v][u]) - pred[v][u] = v - for w in G: - dist_w = dist[w] # save recomputation - for u in G: - dist_u = dist[u] # save recomputation - for v in G: - d = dist_u[w] + dist_w[v] - if dist_u[v] > d: - dist_u[v] = d - pred[u][v] = pred[w][v] - return dict(pred), dict(dist) - - -@nx._dispatchable(graphs=None) -def reconstruct_path(source, target, predecessors): - """Reconstruct a path from source to target using the predecessors - dict as returned by floyd_warshall_predecessor_and_distance - - Parameters - ---------- - source : node - Starting node for path - - target : node - Ending node for path - - predecessors: dictionary - Dictionary, keyed by source and target, of predecessors in the - shortest path, as returned by floyd_warshall_predecessor_and_distance - - Returns - ------- - path : list - A list of nodes containing the shortest path from source to target - - If source and target are the same, an empty list is returned - - Notes - ----- - This function is meant to give more applicability to the - floyd_warshall_predecessor_and_distance function - - See Also - -------- - floyd_warshall_predecessor_and_distance - """ - if source == target: - return [] - prev = predecessors[source] - curr = prev[target] - path = [target, curr] - while curr != source: - curr = prev[curr] - path.append(curr) - return list(reversed(path)) - - -@nx._dispatchable(edge_attrs="weight") -def floyd_warshall(G, weight="weight"): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default= 'weight') - Edge data key corresponding to the edge weight. - - - Returns - ------- - distance : dict - A dictionary, keyed by source and target, of shortest paths distances - between nodes. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... [(0, 1, 5), (1, 2, 2), (2, 3, -3), (1, 3, 10), (3, 2, 8)] - ... ) - >>> fw = nx.floyd_warshall(G, weight="weight") - >>> results = {a: dict(b) for a, b in fw.items()} - >>> print(results) - {0: {0: 0, 1: 5, 2: 7, 3: 4}, 1: {1: 0, 2: 2, 3: -1, 0: inf}, 2: {2: 0, 3: -3, 0: inf, 1: inf}, 3: {3: 0, 2: 8, 0: inf, 1: inf}} - - Notes - ----- - Floyd's algorithm is appropriate for finding shortest paths - in dense graphs or graphs with negative weights when Dijkstra's algorithm - fails. This algorithm can still fail if there are negative cycles. - It has running time $O(n^3)$ with running space of $O(n^2)$. - - See Also - -------- - floyd_warshall_predecessor_and_distance - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - """ - # could make this its own function to reduce memory costs - return floyd_warshall_predecessor_and_distance(G, weight=weight)[1] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/generic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/generic.py deleted file mode 100644 index 9ac48c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/generic.py +++ /dev/null @@ -1,730 +0,0 @@ -""" -Compute the shortest paths and path lengths between nodes in the graph. - -These algorithms work with undirected and directed graphs. - -""" - -import warnings - -import networkx as nx - -__all__ = [ - "shortest_path", - "all_shortest_paths", - "single_source_all_shortest_paths", - "all_pairs_all_shortest_paths", - "shortest_path_length", - "average_shortest_path_length", - "has_path", -] - - -@nx._dispatchable -def has_path(G, source, target): - """Returns *True* if *G* has a path from *source* to *target*. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - """ - try: - nx.shortest_path(G, source, target) - except nx.NetworkXNoPath: - return False - return True - - -@nx._dispatchable(edge_attrs="weight") -def shortest_path(G, source=None, target=None, weight=None, method="dijkstra"): - """Compute shortest paths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Starting node for path. If not specified, compute shortest - paths for each possible starting node. - - target : node, optional - Ending node for path. If not specified, compute shortest - paths to all possible nodes. - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - path: list or dictionary - All returned paths include both the source and target in the path. - - If the source and target are both specified, return a single list - of nodes in a shortest path from the source to the target. - - If only the source is specified, return a dictionary keyed by - targets with a list of nodes in a shortest path from the source - to one of the targets. - - If only the target is specified, return a dictionary keyed by - sources with a list of nodes in a shortest path from one of the - sources to the target. - - If neither the source nor target are specified return a dictionary - of dictionaries with path[source][target]=[list of nodes in path]. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> print(nx.shortest_path(G, source=0, target=4)) - [0, 1, 2, 3, 4] - >>> p = nx.shortest_path(G, source=0) # target not specified - >>> p[3] # shortest path from source=0 to target=3 - [0, 1, 2, 3] - >>> p = nx.shortest_path(G, target=4) # source not specified - >>> p[1] # shortest path from source=1 to target=4 - [1, 2, 3, 4] - >>> p = dict(nx.shortest_path(G)) # source, target not specified - >>> p[2][4] # shortest path from source=2 to target=4 - [2, 3, 4] - - Notes - ----- - There may be more than one shortest path between a source and target. - This returns only one of them. - - See Also - -------- - all_pairs_shortest_path - all_pairs_dijkstra_path - all_pairs_bellman_ford_path - single_source_shortest_path - single_source_dijkstra_path - single_source_bellman_ford_path - """ - if method not in ("dijkstra", "bellman-ford"): - # so we don't need to check in each branch later - raise ValueError(f"method not supported: {method}") - method = "unweighted" if weight is None else method - if source is None: - if target is None: - warnings.warn( - ( - "\n\nshortest_path will return an iterator that yields\n" - "(node, path) pairs instead of a dictionary when source\n" - "and target are unspecified beginning in version 3.5\n\n" - "To keep the current behavior, use:\n\n" - "\tdict(nx.shortest_path(G))" - ), - FutureWarning, - stacklevel=3, - ) - - # Find paths between all pairs. - if method == "unweighted": - paths = dict(nx.all_pairs_shortest_path(G)) - elif method == "dijkstra": - paths = dict(nx.all_pairs_dijkstra_path(G, weight=weight)) - else: # method == 'bellman-ford': - paths = dict(nx.all_pairs_bellman_ford_path(G, weight=weight)) - else: - # Find paths from all nodes co-accessible to the target. - if G.is_directed(): - G = G.reverse(copy=False) - if method == "unweighted": - paths = nx.single_source_shortest_path(G, target) - elif method == "dijkstra": - paths = nx.single_source_dijkstra_path(G, target, weight=weight) - else: # method == 'bellman-ford': - paths = nx.single_source_bellman_ford_path(G, target, weight=weight) - # Now flip the paths so they go from a source to the target. - for target in paths: - paths[target] = list(reversed(paths[target])) - else: - if target is None: - # Find paths to all nodes accessible from the source. - if method == "unweighted": - paths = nx.single_source_shortest_path(G, source) - elif method == "dijkstra": - paths = nx.single_source_dijkstra_path(G, source, weight=weight) - else: # method == 'bellman-ford': - paths = nx.single_source_bellman_ford_path(G, source, weight=weight) - else: - # Find shortest source-target path. - if method == "unweighted": - paths = nx.bidirectional_shortest_path(G, source, target) - elif method == "dijkstra": - _, paths = nx.bidirectional_dijkstra(G, source, target, weight) - else: # method == 'bellman-ford': - paths = nx.bellman_ford_path(G, source, target, weight) - return paths - - -@nx._dispatchable(edge_attrs="weight") -def shortest_path_length(G, source=None, target=None, weight=None, method="dijkstra"): - """Compute shortest path lengths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Starting node for path. - If not specified, compute shortest path lengths using all nodes as - source nodes. - - target : node, optional - Ending node for path. - If not specified, compute shortest path lengths using all nodes as - target nodes. - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path length. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - length: number or iterator - If the source and target are both specified, return the length of - the shortest path from the source to the target. - - If only the source is specified, return a dict keyed by target - to the shortest path length from the source to that target. - - If only the target is specified, return a dict keyed by source - to the shortest path length from that source to the target. - - If neither the source nor target are specified, return an iterator - over (source, dictionary) where dictionary is keyed by target to - shortest path length from source to that target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.shortest_path_length(G, source=0, target=4) - 4 - >>> p = nx.shortest_path_length(G, source=0) # target not specified - >>> p[4] - 4 - >>> p = nx.shortest_path_length(G, target=4) # source not specified - >>> p[0] - 4 - >>> p = dict(nx.shortest_path_length(G)) # source,target not specified - >>> p[0][4] - 4 - - Notes - ----- - The length of the path is always 1 less than the number of nodes involved - in the path since the length measures the number of edges followed. - - For digraphs this returns the shortest directed path length. To find path - lengths in the reverse direction use G.reverse(copy=False) first to flip - the edge orientation. - - See Also - -------- - all_pairs_shortest_path_length - all_pairs_dijkstra_path_length - all_pairs_bellman_ford_path_length - single_source_shortest_path_length - single_source_dijkstra_path_length - single_source_bellman_ford_path_length - """ - if method not in ("dijkstra", "bellman-ford"): - # so we don't need to check in each branch later - raise ValueError(f"method not supported: {method}") - method = "unweighted" if weight is None else method - if source is None: - if target is None: - # Find paths between all pairs. - if method == "unweighted": - paths = nx.all_pairs_shortest_path_length(G) - elif method == "dijkstra": - paths = nx.all_pairs_dijkstra_path_length(G, weight=weight) - else: # method == 'bellman-ford': - paths = nx.all_pairs_bellman_ford_path_length(G, weight=weight) - else: - # Find paths from all nodes co-accessible to the target. - if G.is_directed(): - G = G.reverse(copy=False) - if method == "unweighted": - path_length = nx.single_source_shortest_path_length - paths = path_length(G, target) - elif method == "dijkstra": - path_length = nx.single_source_dijkstra_path_length - paths = path_length(G, target, weight=weight) - else: # method == 'bellman-ford': - path_length = nx.single_source_bellman_ford_path_length - paths = path_length(G, target, weight=weight) - else: - if target is None: - # Find paths to all nodes accessible from the source. - if method == "unweighted": - paths = nx.single_source_shortest_path_length(G, source) - elif method == "dijkstra": - path_length = nx.single_source_dijkstra_path_length - paths = path_length(G, source, weight=weight) - else: # method == 'bellman-ford': - path_length = nx.single_source_bellman_ford_path_length - paths = path_length(G, source, weight=weight) - else: - # Find shortest source-target path. - if method == "unweighted": - p = nx.bidirectional_shortest_path(G, source, target) - paths = len(p) - 1 - elif method == "dijkstra": - paths = nx.dijkstra_path_length(G, source, target, weight) - else: # method == 'bellman-ford': - paths = nx.bellman_ford_path_length(G, source, target, weight) - return paths - - -@nx._dispatchable(edge_attrs="weight") -def average_shortest_path_length(G, weight=None, method=None): - r"""Returns the average shortest path length. - - The average shortest path length is - - .. math:: - - a =\sum_{\substack{s,t \in V \\ s\neq t}} \frac{d(s, t)}{n(n-1)} - - where `V` is the set of nodes in `G`, - `d(s, t)` is the shortest path from `s` to `t`, - and `n` is the number of nodes in `G`. - - .. versionchanged:: 3.0 - An exception is raised for directed graphs that are not strongly - connected. - - Parameters - ---------- - G : NetworkX graph - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'unweighted' or 'dijkstra') - The algorithm to use to compute the path lengths. - Supported options are 'unweighted', 'dijkstra', 'bellman-ford', - 'floyd-warshall' and 'floyd-warshall-numpy'. - Other method values produce a ValueError. - The default method is 'unweighted' if `weight` is None, - otherwise the default method is 'dijkstra'. - - Raises - ------ - NetworkXPointlessConcept - If `G` is the null graph (that is, the graph on zero nodes). - - NetworkXError - If `G` is not connected (or not strongly connected, in the case - of a directed graph). - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.average_shortest_path_length(G) - 2.0 - - For disconnected graphs, you can compute the average shortest path - length for each component - - >>> G = nx.Graph([(1, 2), (3, 4)]) - >>> for C in (G.subgraph(c).copy() for c in nx.connected_components(G)): - ... print(nx.average_shortest_path_length(C)) - 1.0 - 1.0 - - """ - single_source_methods = ["unweighted", "dijkstra", "bellman-ford"] - all_pairs_methods = ["floyd-warshall", "floyd-warshall-numpy"] - supported_methods = single_source_methods + all_pairs_methods - - if method is None: - method = "unweighted" if weight is None else "dijkstra" - if method not in supported_methods: - raise ValueError(f"method not supported: {method}") - - n = len(G) - # For the special case of the null graph, raise an exception, since - # there are no paths in the null graph. - if n == 0: - msg = ( - "the null graph has no paths, thus there is no average " - "shortest path length" - ) - raise nx.NetworkXPointlessConcept(msg) - # For the special case of the trivial graph, return zero immediately. - if n == 1: - return 0 - # Shortest path length is undefined if the graph is not strongly connected. - if G.is_directed() and not nx.is_strongly_connected(G): - raise nx.NetworkXError("Graph is not strongly connected.") - # Shortest path length is undefined if the graph is not connected. - if not G.is_directed() and not nx.is_connected(G): - raise nx.NetworkXError("Graph is not connected.") - - # Compute all-pairs shortest paths. - def path_length(v): - if method == "unweighted": - return nx.single_source_shortest_path_length(G, v) - elif method == "dijkstra": - return nx.single_source_dijkstra_path_length(G, v, weight=weight) - elif method == "bellman-ford": - return nx.single_source_bellman_ford_path_length(G, v, weight=weight) - - if method in single_source_methods: - # Sum the distances for each (ordered) pair of source and target node. - s = sum(l for u in G for l in path_length(u).values()) - else: - if method == "floyd-warshall": - all_pairs = nx.floyd_warshall(G, weight=weight) - s = sum(sum(t.values()) for t in all_pairs.values()) - elif method == "floyd-warshall-numpy": - s = float(nx.floyd_warshall_numpy(G, weight=weight).sum()) - return s / (n * (n - 1)) - - -@nx._dispatchable(edge_attrs="weight") -def all_shortest_paths(G, source, target, weight=None, method="dijkstra"): - """Compute all shortest simple paths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - target : node - Ending node for path. - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path lengths. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - paths : generator of lists - A generator of all paths between source and target. - - Raises - ------ - ValueError - If `method` is not among the supported options. - - NetworkXNoPath - If `target` cannot be reached from `source`. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2]) - >>> nx.add_path(G, [0, 10, 2]) - >>> print([p for p in nx.all_shortest_paths(G, source=0, target=2)]) - [[0, 1, 2], [0, 10, 2]] - - Notes - ----- - There may be many shortest paths between the source and target. If G - contains zero-weight cycles, this function will not produce all shortest - paths because doing so would produce infinitely many paths of unbounded - length -- instead, we only produce the shortest simple paths. - - See Also - -------- - shortest_path - single_source_shortest_path - all_pairs_shortest_path - """ - method = "unweighted" if weight is None else method - if method == "unweighted": - pred = nx.predecessor(G, source) - elif method == "dijkstra": - pred, dist = nx.dijkstra_predecessor_and_distance(G, source, weight=weight) - elif method == "bellman-ford": - pred, dist = nx.bellman_ford_predecessor_and_distance(G, source, weight=weight) - else: - raise ValueError(f"method not supported: {method}") - - return _build_paths_from_predecessors({source}, target, pred) - - -@nx._dispatchable(edge_attrs="weight") -def single_source_all_shortest_paths(G, source, weight=None, method="dijkstra"): - """Compute all shortest simple paths from the given source in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path lengths. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - paths : generator of dictionary - A generator of all paths between source and all nodes in the graph. - - Raises - ------ - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3, 0]) - >>> dict(nx.single_source_all_shortest_paths(G, source=0)) - {0: [[0]], 1: [[0, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 3]]} - - Notes - ----- - There may be many shortest paths between the source and target. If G - contains zero-weight cycles, this function will not produce all shortest - paths because doing so would produce infinitely many paths of unbounded - length -- instead, we only produce the shortest simple paths. - - See Also - -------- - shortest_path - all_shortest_paths - single_source_shortest_path - all_pairs_shortest_path - all_pairs_all_shortest_paths - """ - method = "unweighted" if weight is None else method - if method == "unweighted": - pred = nx.predecessor(G, source) - elif method == "dijkstra": - pred, dist = nx.dijkstra_predecessor_and_distance(G, source, weight=weight) - elif method == "bellman-ford": - pred, dist = nx.bellman_ford_predecessor_and_distance(G, source, weight=weight) - else: - raise ValueError(f"method not supported: {method}") - for n in G: - try: - yield n, list(_build_paths_from_predecessors({source}, n, pred)) - except nx.NetworkXNoPath: - pass - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_all_shortest_paths(G, weight=None, method="dijkstra"): - """Compute all shortest paths between all nodes. - - Parameters - ---------- - G : NetworkX graph - - weight : None, string or function, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly - three positional arguments: the two endpoints of an edge and - the dictionary of edge attributes for that edge. - The function must return a number. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path lengths. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - paths : generator of dictionary - Dictionary of arrays, keyed by source and target, of all shortest paths. - - Raises - ------ - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> dict(nx.all_pairs_all_shortest_paths(G))[0][2] - [[0, 1, 2], [0, 3, 2]] - >>> dict(nx.all_pairs_all_shortest_paths(G))[0][3] - [[0, 3]] - - Notes - ----- - There may be multiple shortest paths with equal lengths. Unlike - all_pairs_shortest_path, this method returns all shortest paths. - - See Also - -------- - all_pairs_shortest_path - single_source_all_shortest_paths - """ - for n in G: - yield ( - n, - dict(single_source_all_shortest_paths(G, n, weight=weight, method=method)), - ) - - -def _build_paths_from_predecessors(sources, target, pred): - """Compute all simple paths to target, given the predecessors found in - pred, terminating when any source in sources is found. - - Parameters - ---------- - sources : set - Starting nodes for path. - - target : node - Ending node for path. - - pred : dict - A dictionary of predecessor lists, keyed by node - - Returns - ------- - paths : generator of lists - A generator of all paths between source and target. - - Raises - ------ - NetworkXNoPath - If `target` cannot be reached from `source`. - - Notes - ----- - There may be many paths between the sources and target. If there are - cycles among the predecessors, this function will not produce all - possible paths because doing so would produce infinitely many paths - of unbounded length -- instead, we only produce simple paths. - - See Also - -------- - shortest_path - single_source_shortest_path - all_pairs_shortest_path - all_shortest_paths - bellman_ford_path - """ - if target not in pred: - raise nx.NetworkXNoPath(f"Target {target} cannot be reached from given sources") - - seen = {target} - stack = [[target, 0]] - top = 0 - while top >= 0: - node, i = stack[top] - if node in sources: - yield [p for p, n in reversed(stack[: top + 1])] - if len(pred[node]) > i: - stack[top][1] = i + 1 - next = pred[node][i] - if next in seen: - continue - else: - seen.add(next) - top += 1 - if top == len(stack): - stack.append([next, 0]) - else: - stack[top][:] = [next, 0] - else: - seen.discard(node) - top -= 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_astar.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_astar.py deleted file mode 100644 index 40a7d4e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_astar.py +++ /dev/null @@ -1,248 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import pairwise - - -class TestAStar: - @classmethod - def setup_class(cls): - edges = [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - cls.XG = nx.DiGraph() - cls.XG.add_weighted_edges_from(edges) - - def test_multiple_optimal_paths(self): - """Tests that A* algorithm finds any of multiple optimal paths""" - heuristic_values = {"a": 1.35, "b": 1.18, "c": 0.67, "d": 0} - - def h(u, v): - return heuristic_values[u] - - graph = nx.Graph() - points = ["a", "b", "c", "d"] - edges = [("a", "b", 0.18), ("a", "c", 0.68), ("b", "c", 0.50), ("c", "d", 0.67)] - - graph.add_nodes_from(points) - graph.add_weighted_edges_from(edges) - - path1 = ["a", "c", "d"] - path2 = ["a", "b", "c", "d"] - assert nx.astar_path(graph, "a", "d", h) in (path1, path2) - - def test_astar_directed(self): - assert nx.astar_path(self.XG, "s", "v") == ["s", "x", "u", "v"] - assert nx.astar_path_length(self.XG, "s", "v") == 9 - - def test_astar_directed_weight_function(self): - w1 = lambda u, v, d: d["weight"] - assert nx.astar_path(self.XG, "x", "u", weight=w1) == ["x", "u"] - assert nx.astar_path_length(self.XG, "x", "u", weight=w1) == 3 - assert nx.astar_path(self.XG, "s", "v", weight=w1) == ["s", "x", "u", "v"] - assert nx.astar_path_length(self.XG, "s", "v", weight=w1) == 9 - - w2 = lambda u, v, d: None if (u, v) == ("x", "u") else d["weight"] - assert nx.astar_path(self.XG, "x", "u", weight=w2) == ["x", "y", "s", "u"] - assert nx.astar_path_length(self.XG, "x", "u", weight=w2) == 19 - assert nx.astar_path(self.XG, "s", "v", weight=w2) == ["s", "x", "v"] - assert nx.astar_path_length(self.XG, "s", "v", weight=w2) == 10 - - w3 = lambda u, v, d: d["weight"] + 10 - assert nx.astar_path(self.XG, "x", "u", weight=w3) == ["x", "u"] - assert nx.astar_path_length(self.XG, "x", "u", weight=w3) == 13 - assert nx.astar_path(self.XG, "s", "v", weight=w3) == ["s", "x", "v"] - assert nx.astar_path_length(self.XG, "s", "v", weight=w3) == 30 - - def test_astar_multigraph(self): - G = nx.MultiDiGraph(self.XG) - G.add_weighted_edges_from((u, v, 1000) for (u, v) in list(G.edges())) - assert nx.astar_path(G, "s", "v") == ["s", "x", "u", "v"] - assert nx.astar_path_length(G, "s", "v") == 9 - - def test_astar_undirected(self): - GG = self.XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG["u"]["x"]["weight"] = 2 - GG["y"]["v"]["weight"] = 2 - assert nx.astar_path(GG, "s", "v") == ["s", "x", "u", "v"] - assert nx.astar_path_length(GG, "s", "v") == 8 - - def test_astar_directed2(self): - XG2 = nx.DiGraph() - edges = [ - (1, 4, 1), - (4, 5, 1), - (5, 6, 1), - (6, 3, 1), - (1, 3, 50), - (1, 2, 100), - (2, 3, 100), - ] - XG2.add_weighted_edges_from(edges) - assert nx.astar_path(XG2, 1, 3) == [1, 4, 5, 6, 3] - - def test_astar_undirected2(self): - XG3 = nx.Graph() - edges = [(0, 1, 2), (1, 2, 12), (2, 3, 1), (3, 4, 5), (4, 5, 1), (5, 0, 10)] - XG3.add_weighted_edges_from(edges) - assert nx.astar_path(XG3, 0, 3) == [0, 1, 2, 3] - assert nx.astar_path_length(XG3, 0, 3) == 15 - - def test_astar_undirected3(self): - XG4 = nx.Graph() - edges = [ - (0, 1, 2), - (1, 2, 2), - (2, 3, 1), - (3, 4, 1), - (4, 5, 1), - (5, 6, 1), - (6, 7, 1), - (7, 0, 1), - ] - XG4.add_weighted_edges_from(edges) - assert nx.astar_path(XG4, 0, 2) == [0, 1, 2] - assert nx.astar_path_length(XG4, 0, 2) == 4 - - """ Tests that A* finds correct path when multiple paths exist - and the best one is not expanded first (GH issue #3464) - """ - - def test_astar_directed3(self): - heuristic_values = {"n5": 36, "n2": 4, "n1": 0, "n0": 0} - - def h(u, v): - return heuristic_values[u] - - edges = [("n5", "n1", 11), ("n5", "n2", 9), ("n2", "n1", 1), ("n1", "n0", 32)] - graph = nx.DiGraph() - graph.add_weighted_edges_from(edges) - answer = ["n5", "n2", "n1", "n0"] - assert nx.astar_path(graph, "n5", "n0", h) == answer - - """ Tests that parent is not wrongly overridden when a node - is re-explored multiple times. - """ - - def test_astar_directed4(self): - edges = [ - ("a", "b", 1), - ("a", "c", 1), - ("b", "d", 2), - ("c", "d", 1), - ("d", "e", 1), - ] - graph = nx.DiGraph() - graph.add_weighted_edges_from(edges) - assert nx.astar_path(graph, "a", "e") == ["a", "c", "d", "e"] - - # >>> MXG4=NX.MultiGraph(XG4) - # >>> MXG4.add_edge(0,1,3) - # >>> NX.dijkstra_path(MXG4,0,2) - # [0, 1, 2] - - def test_astar_w1(self): - G = nx.DiGraph() - G.add_edges_from( - [ - ("s", "u"), - ("s", "x"), - ("u", "v"), - ("u", "x"), - ("v", "y"), - ("x", "u"), - ("x", "w"), - ("w", "v"), - ("x", "y"), - ("y", "s"), - ("y", "v"), - ] - ) - assert nx.astar_path(G, "s", "v") == ["s", "u", "v"] - assert nx.astar_path_length(G, "s", "v") == 2 - - def test_astar_nopath(self): - with pytest.raises(nx.NodeNotFound): - nx.astar_path(self.XG, "s", "moon") - - def test_astar_cutoff(self): - with pytest.raises(nx.NetworkXNoPath): - # optimal path_length in XG is 9 - nx.astar_path(self.XG, "s", "v", cutoff=8.0) - with pytest.raises(nx.NetworkXNoPath): - nx.astar_path_length(self.XG, "s", "v", cutoff=8.0) - - def test_astar_admissible_heuristic_with_cutoff(self): - heuristic_values = {"s": 36, "y": 4, "x": 0, "u": 0, "v": 0} - - def h(u, v): - return heuristic_values[u] - - assert nx.astar_path_length(self.XG, "s", "v") == 9 - assert nx.astar_path_length(self.XG, "s", "v", heuristic=h) == 9 - assert nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=12) == 9 - assert nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=9) == 9 - with pytest.raises(nx.NetworkXNoPath): - nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=8) - - def test_astar_inadmissible_heuristic_with_cutoff(self): - heuristic_values = {"s": 36, "y": 14, "x": 10, "u": 10, "v": 0} - - def h(u, v): - return heuristic_values[u] - - # optimal path_length in XG is 9. This heuristic gives over-estimate. - assert nx.astar_path_length(self.XG, "s", "v", heuristic=h) == 10 - assert nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=15) == 10 - with pytest.raises(nx.NetworkXNoPath): - nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=9) - with pytest.raises(nx.NetworkXNoPath): - nx.astar_path_length(self.XG, "s", "v", heuristic=h, cutoff=12) - - def test_astar_cutoff2(self): - assert nx.astar_path(self.XG, "s", "v", cutoff=10.0) == ["s", "x", "u", "v"] - assert nx.astar_path_length(self.XG, "s", "v") == 9 - - def test_cycle(self): - C = nx.cycle_graph(7) - assert nx.astar_path(C, 0, 3) == [0, 1, 2, 3] - assert nx.dijkstra_path(C, 0, 4) == [0, 6, 5, 4] - - def test_unorderable_nodes(self): - """Tests that A* accommodates nodes that are not orderable. - - For more information, see issue #554. - - """ - # Create the cycle graph on four nodes, with nodes represented - # as (unorderable) Python objects. - nodes = [object() for n in range(4)] - G = nx.Graph() - G.add_edges_from(pairwise(nodes, cyclic=True)) - path = nx.astar_path(G, nodes[0], nodes[2]) - assert len(path) == 3 - - def test_astar_NetworkXNoPath(self): - """Tests that exception is raised when there exists no - path between source and target""" - G = nx.gnp_random_graph(10, 0.2, seed=10) - with pytest.raises(nx.NetworkXNoPath): - nx.astar_path(G, 4, 9) - - def test_astar_NodeNotFound(self): - """Tests that exception is raised when either - source or target is not in graph""" - G = nx.gnp_random_graph(10, 0.2, seed=10) - with pytest.raises(nx.NodeNotFound): - nx.astar_path_length(G, 11, 9) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense.py deleted file mode 100644 index 6923bfe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense.py +++ /dev/null @@ -1,212 +0,0 @@ -import pytest - -import networkx as nx - - -class TestFloyd: - @classmethod - def setup_class(cls): - pass - - def test_floyd_warshall_predecessor_and_distance(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - assert dist["s"]["v"] == 9 - assert path["s"]["v"] == "u" - assert dist == { - "y": {"y": 0, "x": 12, "s": 7, "u": 15, "v": 6}, - "x": {"y": 2, "x": 0, "s": 9, "u": 3, "v": 4}, - "s": {"y": 7, "x": 5, "s": 0, "u": 8, "v": 9}, - "u": {"y": 2, "x": 2, "s": 9, "u": 0, "v": 1}, - "v": {"y": 1, "x": 13, "s": 8, "u": 16, "v": 0}, - } - - GG = XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG["u"]["x"]["weight"] = 2 - path, dist = nx.floyd_warshall_predecessor_and_distance(GG) - assert dist["s"]["v"] == 8 - # skip this test, could be alternate path s-u-v - # assert_equal(path['s']['v'],'y') - - G = nx.DiGraph() # no weights - G.add_edges_from( - [ - ("s", "u"), - ("s", "x"), - ("u", "v"), - ("u", "x"), - ("v", "y"), - ("x", "u"), - ("x", "v"), - ("x", "y"), - ("y", "s"), - ("y", "v"), - ] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(G) - assert dist["s"]["v"] == 2 - # skip this test, could be alternate path s-u-v - # assert_equal(path['s']['v'],'x') - - # alternate interface - dist = nx.floyd_warshall(G) - assert dist["s"]["v"] == 2 - - # floyd_warshall_predecessor_and_distance returns - # dicts-of-defautdicts - # make sure we don't get empty dictionary - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [("v", "x", 5.0), ("y", "x", 5.0), ("v", "y", 6.0), ("x", "u", 2.0)] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - inf = float("inf") - assert dist == { - "v": {"v": 0, "x": 5.0, "y": 6.0, "u": 7.0}, - "x": {"x": 0, "u": 2.0, "v": inf, "y": inf}, - "y": {"y": 0, "x": 5.0, "v": inf, "u": 7.0}, - "u": {"u": 0, "v": inf, "x": inf, "y": inf}, - } - assert path == { - "v": {"x": "v", "y": "v", "u": "x"}, - "x": {"u": "x"}, - "y": {"x": "y", "u": "x"}, - } - - def test_reconstruct_path(self): - with pytest.raises(KeyError): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - predecessors, _ = nx.floyd_warshall_predecessor_and_distance(XG) - - path = nx.reconstruct_path("s", "v", predecessors) - assert path == ["s", "x", "u", "v"] - - path = nx.reconstruct_path("s", "s", predecessors) - assert path == [] - - # this part raises the keyError - nx.reconstruct_path("1", "2", predecessors) - - def test_cycle(self): - path, dist = nx.floyd_warshall_predecessor_and_distance(nx.cycle_graph(7)) - assert dist[0][3] == 3 - assert path[0][3] == 2 - assert dist[0][4] == 3 - - def test_weighted(self): - XG3 = nx.Graph() - XG3.add_weighted_edges_from( - [[0, 1, 2], [1, 2, 12], [2, 3, 1], [3, 4, 5], [4, 5, 1], [5, 0, 10]] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG3) - assert dist[0][3] == 15 - assert path[0][3] == 2 - - def test_weighted2(self): - XG4 = nx.Graph() - XG4.add_weighted_edges_from( - [ - [0, 1, 2], - [1, 2, 2], - [2, 3, 1], - [3, 4, 1], - [4, 5, 1], - [5, 6, 1], - [6, 7, 1], - [7, 0, 1], - ] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG4) - assert dist[0][2] == 4 - assert path[0][2] == 1 - - def test_weight_parameter(self): - XG4 = nx.Graph() - XG4.add_edges_from( - [ - (0, 1, {"heavy": 2}), - (1, 2, {"heavy": 2}), - (2, 3, {"heavy": 1}), - (3, 4, {"heavy": 1}), - (4, 5, {"heavy": 1}), - (5, 6, {"heavy": 1}), - (6, 7, {"heavy": 1}), - (7, 0, {"heavy": 1}), - ] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG4, weight="heavy") - assert dist[0][2] == 4 - assert path[0][2] == 1 - - def test_zero_distance(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - - for u in XG: - assert dist[u][u] == 0 - - GG = XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG["u"]["x"]["weight"] = 2 - path, dist = nx.floyd_warshall_predecessor_and_distance(GG) - - for u in GG: - dist[u][u] = 0 - - def test_zero_weight(self): - G = nx.DiGraph() - edges = [(1, 2, -2), (2, 3, -4), (1, 5, 1), (5, 4, 0), (4, 3, -5), (2, 5, -7)] - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall(G) - assert dist[1][3] == -14 - - G = nx.MultiDiGraph() - edges.append((2, 5, -7)) - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall(G) - assert dist[1][3] == -14 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py deleted file mode 100644 index 1316e23..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +++ /dev/null @@ -1,89 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") - - -import networkx as nx - - -def test_cycle_numpy(): - dist = nx.floyd_warshall_numpy(nx.cycle_graph(7)) - assert dist[0, 3] == 3 - assert dist[0, 4] == 3 - - -def test_weighted_numpy_three_edges(): - XG3 = nx.Graph() - XG3.add_weighted_edges_from( - [[0, 1, 2], [1, 2, 12], [2, 3, 1], [3, 4, 5], [4, 5, 1], [5, 0, 10]] - ) - dist = nx.floyd_warshall_numpy(XG3) - assert dist[0, 3] == 15 - - -def test_weighted_numpy_two_edges(): - XG4 = nx.Graph() - XG4.add_weighted_edges_from( - [ - [0, 1, 2], - [1, 2, 2], - [2, 3, 1], - [3, 4, 1], - [4, 5, 1], - [5, 6, 1], - [6, 7, 1], - [7, 0, 1], - ] - ) - dist = nx.floyd_warshall_numpy(XG4) - assert dist[0, 2] == 4 - - -def test_weight_parameter_numpy(): - XG4 = nx.Graph() - XG4.add_edges_from( - [ - (0, 1, {"heavy": 2}), - (1, 2, {"heavy": 2}), - (2, 3, {"heavy": 1}), - (3, 4, {"heavy": 1}), - (4, 5, {"heavy": 1}), - (5, 6, {"heavy": 1}), - (6, 7, {"heavy": 1}), - (7, 0, {"heavy": 1}), - ] - ) - dist = nx.floyd_warshall_numpy(XG4, weight="heavy") - assert dist[0, 2] == 4 - - -def test_directed_cycle_numpy(): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - pred, dist = nx.floyd_warshall_predecessor_and_distance(G) - D = nx.utils.dict_to_numpy_array(dist) - np.testing.assert_equal(nx.floyd_warshall_numpy(G), D) - - -def test_zero_weight(): - G = nx.DiGraph() - edges = [(1, 2, -2), (2, 3, -4), (1, 5, 1), (5, 4, 0), (4, 3, -5), (2, 5, -7)] - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall_numpy(G) - assert int(np.min(dist)) == -14 - - G = nx.MultiDiGraph() - edges.append((2, 5, -7)) - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall_numpy(G) - assert int(np.min(dist)) == -14 - - -def test_nodelist(): - G = nx.path_graph(7) - dist = nx.floyd_warshall_numpy(G, nodelist=[3, 5, 4, 6, 2, 1, 0]) - assert dist[0, 3] == 3 - assert dist[0, 1] == 2 - assert dist[6, 2] == 4 - pytest.raises(nx.NetworkXError, nx.floyd_warshall_numpy, G, [1, 3]) - pytest.raises(nx.NetworkXError, nx.floyd_warshall_numpy, G, list(range(9))) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_generic.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_generic.py deleted file mode 100644 index e30de51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_generic.py +++ /dev/null @@ -1,450 +0,0 @@ -import pytest - -import networkx as nx - - -def validate_grid_path(r, c, s, t, p): - assert isinstance(p, list) - assert p[0] == s - assert p[-1] == t - s = ((s - 1) // c, (s - 1) % c) - t = ((t - 1) // c, (t - 1) % c) - assert len(p) == abs(t[0] - s[0]) + abs(t[1] - s[1]) + 1 - p = [((u - 1) // c, (u - 1) % c) for u in p] - for u in p: - assert 0 <= u[0] < r - assert 0 <= u[1] < c - for u, v in zip(p[:-1], p[1:]): - assert (abs(v[0] - u[0]), abs(v[1] - u[1])) in [(0, 1), (1, 0)] - - -class TestGenericPath: - @classmethod - def setup_class(cls): - from networkx import convert_node_labels_to_integers as cnlti - - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.neg_weights = nx.DiGraph() - cls.neg_weights.add_edge(0, 1, weight=1) - cls.neg_weights.add_edge(0, 2, weight=3) - cls.neg_weights.add_edge(1, 3, weight=1) - cls.neg_weights.add_edge(2, 3, weight=-2) - - def test_shortest_path(self): - assert nx.shortest_path(self.cycle, 0, 3) == [0, 1, 2, 3] - assert nx.shortest_path(self.cycle, 0, 4) == [0, 6, 5, 4] - validate_grid_path(4, 4, 1, 12, nx.shortest_path(self.grid, 1, 12)) - assert nx.shortest_path(self.directed_cycle, 0, 3) == [0, 1, 2, 3] - # now with weights - assert nx.shortest_path(self.cycle, 0, 3, weight="weight") == [0, 1, 2, 3] - assert nx.shortest_path(self.cycle, 0, 4, weight="weight") == [0, 6, 5, 4] - validate_grid_path( - 4, 4, 1, 12, nx.shortest_path(self.grid, 1, 12, weight="weight") - ) - assert nx.shortest_path(self.directed_cycle, 0, 3, weight="weight") == [ - 0, - 1, - 2, - 3, - ] - # weights and method specified - assert nx.shortest_path( - self.directed_cycle, 0, 3, weight="weight", method="dijkstra" - ) == [0, 1, 2, 3] - assert nx.shortest_path( - self.directed_cycle, 0, 3, weight="weight", method="bellman-ford" - ) == [0, 1, 2, 3] - # when Dijkstra's will probably (depending on precise implementation) - # incorrectly return [0, 1, 3] instead - assert nx.shortest_path( - self.neg_weights, 0, 3, weight="weight", method="bellman-ford" - ) == [0, 2, 3] - # confirm bad method rejection - pytest.raises(ValueError, nx.shortest_path, self.cycle, method="SPAM") - # confirm absent source rejection - pytest.raises(nx.NodeNotFound, nx.shortest_path, self.cycle, 8) - - def test_shortest_path_target(self): - answer = {0: [0, 1], 1: [1], 2: [2, 1]} - sp = nx.shortest_path(nx.path_graph(3), target=1) - assert sp == answer - # with weights - sp = nx.shortest_path(nx.path_graph(3), target=1, weight="weight") - assert sp == answer - # weights and method specified - sp = nx.shortest_path( - nx.path_graph(3), target=1, weight="weight", method="dijkstra" - ) - assert sp == answer - sp = nx.shortest_path( - nx.path_graph(3), target=1, weight="weight", method="bellman-ford" - ) - assert sp == answer - - def test_shortest_path_length(self): - assert nx.shortest_path_length(self.cycle, 0, 3) == 3 - assert nx.shortest_path_length(self.grid, 1, 12) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4) == 4 - # now with weights - assert nx.shortest_path_length(self.cycle, 0, 3, weight="weight") == 3 - assert nx.shortest_path_length(self.grid, 1, 12, weight="weight") == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4, weight="weight") == 4 - # weights and method specified - assert ( - nx.shortest_path_length( - self.cycle, 0, 3, weight="weight", method="dijkstra" - ) - == 3 - ) - assert ( - nx.shortest_path_length( - self.cycle, 0, 3, weight="weight", method="bellman-ford" - ) - == 3 - ) - # confirm bad method rejection - pytest.raises(ValueError, nx.shortest_path_length, self.cycle, method="SPAM") - # confirm absent source rejection - pytest.raises(nx.NodeNotFound, nx.shortest_path_length, self.cycle, 8) - - def test_shortest_path_length_target(self): - answer = {0: 1, 1: 0, 2: 1} - sp = dict(nx.shortest_path_length(nx.path_graph(3), target=1)) - assert sp == answer - # with weights - sp = nx.shortest_path_length(nx.path_graph(3), target=1, weight="weight") - assert sp == answer - # weights and method specified - sp = nx.shortest_path_length( - nx.path_graph(3), target=1, weight="weight", method="dijkstra" - ) - assert sp == answer - sp = nx.shortest_path_length( - nx.path_graph(3), target=1, weight="weight", method="bellman-ford" - ) - assert sp == answer - - def test_single_source_shortest_path(self): - p = nx.shortest_path(self.cycle, 0) - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - p = nx.shortest_path(self.grid, 1) - validate_grid_path(4, 4, 1, 12, p[12]) - # now with weights - p = nx.shortest_path(self.cycle, 0, weight="weight") - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_dijkstra_path(self.cycle, 0) - p = nx.shortest_path(self.grid, 1, weight="weight") - validate_grid_path(4, 4, 1, 12, p[12]) - # weights and method specified - p = nx.shortest_path(self.cycle, 0, method="dijkstra", weight="weight") - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - p = nx.shortest_path(self.cycle, 0, method="bellman-ford", weight="weight") - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - - def test_single_source_shortest_path_length(self): - ans = dict(nx.shortest_path_length(self.cycle, 0)) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_shortest_path_length(self.cycle, 0)) - ans = dict(nx.shortest_path_length(self.grid, 1)) - assert ans[16] == 6 - # now with weights - ans = dict(nx.shortest_path_length(self.cycle, 0, weight="weight")) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_dijkstra_path_length(self.cycle, 0)) - ans = dict(nx.shortest_path_length(self.grid, 1, weight="weight")) - assert ans[16] == 6 - # weights and method specified - ans = dict( - nx.shortest_path_length(self.cycle, 0, weight="weight", method="dijkstra") - ) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_dijkstra_path_length(self.cycle, 0)) - ans = dict( - nx.shortest_path_length( - self.cycle, 0, weight="weight", method="bellman-ford" - ) - ) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_bellman_ford_path_length(self.cycle, 0)) - - def test_single_source_all_shortest_paths(self): - cycle_ans = {0: [[0]], 1: [[0, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 3]]} - ans = dict(nx.single_source_all_shortest_paths(nx.cycle_graph(4), 0)) - assert sorted(ans[2]) == cycle_ans[2] - ans = dict(nx.single_source_all_shortest_paths(self.grid, 1)) - grid_ans = [ - [1, 2, 3, 7, 11], - [1, 2, 6, 7, 11], - [1, 2, 6, 10, 11], - [1, 5, 6, 7, 11], - [1, 5, 6, 10, 11], - [1, 5, 9, 10, 11], - ] - assert sorted(ans[11]) == grid_ans - ans = dict( - nx.single_source_all_shortest_paths(nx.cycle_graph(4), 0, weight="weight") - ) - assert sorted(ans[2]) == cycle_ans[2] - ans = dict( - nx.single_source_all_shortest_paths( - nx.cycle_graph(4), 0, method="bellman-ford", weight="weight" - ) - ) - assert sorted(ans[2]) == cycle_ans[2] - ans = dict(nx.single_source_all_shortest_paths(self.grid, 1, weight="weight")) - assert sorted(ans[11]) == grid_ans - ans = dict( - nx.single_source_all_shortest_paths( - self.grid, 1, method="bellman-ford", weight="weight" - ) - ) - assert sorted(ans[11]) == grid_ans - G = nx.cycle_graph(4) - G.add_node(4) - ans = dict(nx.single_source_all_shortest_paths(G, 0)) - assert sorted(ans[2]) == [[0, 1, 2], [0, 3, 2]] - ans = dict(nx.single_source_all_shortest_paths(G, 4)) - assert sorted(ans[4]) == [[4]] - - def test_all_pairs_shortest_path(self): - # shortest_path w/o source and target will return a generator instead of - # a dict beginning in version 3.5. Only the first call needs changed here. - p = nx.shortest_path(self.cycle) - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_shortest_path(self.cycle)) - p = dict(nx.shortest_path(self.grid)) - validate_grid_path(4, 4, 1, 12, p[1][12]) - # now with weights - p = dict(nx.shortest_path(self.cycle, weight="weight")) - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_dijkstra_path(self.cycle)) - p = dict(nx.shortest_path(self.grid, weight="weight")) - validate_grid_path(4, 4, 1, 12, p[1][12]) - # weights and method specified - p = dict(nx.shortest_path(self.cycle, weight="weight", method="dijkstra")) - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_dijkstra_path(self.cycle)) - p = dict(nx.shortest_path(self.cycle, weight="weight", method="bellman-ford")) - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_bellman_ford_path(self.cycle)) - - def test_all_pairs_shortest_path_length(self): - ans = dict(nx.shortest_path_length(self.cycle)) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_shortest_path_length(self.cycle)) - ans = dict(nx.shortest_path_length(self.grid)) - assert ans[1][16] == 6 - # now with weights - ans = dict(nx.shortest_path_length(self.cycle, weight="weight")) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_dijkstra_path_length(self.cycle)) - ans = dict(nx.shortest_path_length(self.grid, weight="weight")) - assert ans[1][16] == 6 - # weights and method specified - ans = dict( - nx.shortest_path_length(self.cycle, weight="weight", method="dijkstra") - ) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_dijkstra_path_length(self.cycle)) - ans = dict( - nx.shortest_path_length(self.cycle, weight="weight", method="bellman-ford") - ) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_bellman_ford_path_length(self.cycle)) - - def test_all_pairs_all_shortest_paths(self): - ans = dict(nx.all_pairs_all_shortest_paths(nx.cycle_graph(4))) - assert sorted(ans[1][3]) == [[1, 0, 3], [1, 2, 3]] - ans = dict(nx.all_pairs_all_shortest_paths(nx.cycle_graph(4)), weight="weight") - assert sorted(ans[1][3]) == [[1, 0, 3], [1, 2, 3]] - ans = dict( - nx.all_pairs_all_shortest_paths(nx.cycle_graph(4)), - method="bellman-ford", - weight="weight", - ) - assert sorted(ans[1][3]) == [[1, 0, 3], [1, 2, 3]] - G = nx.cycle_graph(4) - G.add_node(4) - ans = dict(nx.all_pairs_all_shortest_paths(G)) - assert sorted(ans[4][4]) == [[4]] - - def test_has_path(self): - G = nx.Graph() - nx.add_path(G, range(3)) - nx.add_path(G, range(3, 5)) - assert nx.has_path(G, 0, 2) - assert not nx.has_path(G, 0, 4) - - def test_has_path_singleton(self): - G = nx.empty_graph(1) - assert nx.has_path(G, 0, 0) - - def test_all_shortest_paths(self): - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert [[0, 1, 2, 3], [0, 10, 20, 3]] == sorted(nx.all_shortest_paths(G, 0, 3)) - # with weights - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert [[0, 1, 2, 3], [0, 10, 20, 3]] == sorted( - nx.all_shortest_paths(G, 0, 3, weight="weight") - ) - # weights and method specified - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert [[0, 1, 2, 3], [0, 10, 20, 3]] == sorted( - nx.all_shortest_paths(G, 0, 3, weight="weight", method="dijkstra") - ) - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert [[0, 1, 2, 3], [0, 10, 20, 3]] == sorted( - nx.all_shortest_paths(G, 0, 3, weight="weight", method="bellman-ford") - ) - - def test_all_shortest_paths_raise(self): - with pytest.raises(nx.NetworkXNoPath): - G = nx.path_graph(4) - G.add_node(4) - list(nx.all_shortest_paths(G, 0, 4)) - - def test_bad_method(self): - with pytest.raises(ValueError): - G = nx.path_graph(2) - list(nx.all_shortest_paths(G, 0, 1, weight="weight", method="SPAM")) - - def test_single_source_all_shortest_paths_bad_method(self): - with pytest.raises(ValueError): - G = nx.path_graph(2) - dict( - nx.single_source_all_shortest_paths( - G, 0, weight="weight", method="SPAM" - ) - ) - - def test_all_shortest_paths_zero_weight_edge(self): - g = nx.Graph() - nx.add_path(g, [0, 1, 3]) - nx.add_path(g, [0, 1, 2, 3]) - g.edges[1, 2]["weight"] = 0 - paths30d = list( - nx.all_shortest_paths(g, 3, 0, weight="weight", method="dijkstra") - ) - paths03d = list( - nx.all_shortest_paths(g, 0, 3, weight="weight", method="dijkstra") - ) - paths30b = list( - nx.all_shortest_paths(g, 3, 0, weight="weight", method="bellman-ford") - ) - paths03b = list( - nx.all_shortest_paths(g, 0, 3, weight="weight", method="bellman-ford") - ) - assert sorted(paths03d) == sorted(p[::-1] for p in paths30d) - assert sorted(paths03d) == sorted(p[::-1] for p in paths30b) - assert sorted(paths03b) == sorted(p[::-1] for p in paths30b) - - -class TestAverageShortestPathLength: - def test_cycle_graph(self): - ans = nx.average_shortest_path_length(nx.cycle_graph(7)) - assert ans == pytest.approx(2, abs=1e-7) - - def test_path_graph(self): - ans = nx.average_shortest_path_length(nx.path_graph(5)) - assert ans == pytest.approx(2, abs=1e-7) - - def test_weighted(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length(G, weight="weight") - assert ans == pytest.approx(4, abs=1e-7) - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length(G, weight="weight") - assert ans == pytest.approx(4, abs=1e-7) - - def test_specified_methods(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length(G, weight="weight", method="dijkstra") - assert ans == pytest.approx(4, abs=1e-7) - ans = nx.average_shortest_path_length(G, weight="weight", method="bellman-ford") - assert ans == pytest.approx(4, abs=1e-7) - ans = nx.average_shortest_path_length( - G, weight="weight", method="floyd-warshall" - ) - assert ans == pytest.approx(4, abs=1e-7) - - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length(G, weight="weight", method="dijkstra") - assert ans == pytest.approx(4, abs=1e-7) - ans = nx.average_shortest_path_length(G, weight="weight", method="bellman-ford") - assert ans == pytest.approx(4, abs=1e-7) - ans = nx.average_shortest_path_length( - G, weight="weight", method="floyd-warshall" - ) - assert ans == pytest.approx(4, abs=1e-7) - - def test_directed_not_strongly_connected(self): - G = nx.DiGraph([(0, 1)]) - with pytest.raises(nx.NetworkXError, match="Graph is not strongly connected"): - nx.average_shortest_path_length(G) - - def test_undirected_not_connected(self): - g = nx.Graph() - g.add_nodes_from(range(3)) - g.add_edge(0, 1) - pytest.raises(nx.NetworkXError, nx.average_shortest_path_length, g) - - def test_trivial_graph(self): - """Tests that the trivial graph has average path length zero, - since there is exactly one path of length zero in the trivial - graph. - - For more information, see issue #1960. - - """ - G = nx.trivial_graph() - assert nx.average_shortest_path_length(G) == 0 - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.average_shortest_path_length(nx.null_graph()) - - def test_bad_method(self): - with pytest.raises(ValueError): - G = nx.path_graph(2) - nx.average_shortest_path_length(G, weight="weight", method="SPAM") - - -class TestAverageShortestPathLengthNumpy: - @classmethod - def setup_class(cls): - global np - import pytest - - np = pytest.importorskip("numpy") - - def test_specified_methods_numpy(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length( - G, weight="weight", method="floyd-warshall-numpy" - ) - np.testing.assert_almost_equal(ans, 4) - - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length( - G, weight="weight", method="floyd-warshall-numpy" - ) - np.testing.assert_almost_equal(ans, 4) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_unweighted.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_unweighted.py deleted file mode 100644 index f09c8b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_unweighted.py +++ /dev/null @@ -1,149 +0,0 @@ -import pytest - -import networkx as nx - - -def validate_grid_path(r, c, s, t, p): - assert isinstance(p, list) - assert p[0] == s - assert p[-1] == t - s = ((s - 1) // c, (s - 1) % c) - t = ((t - 1) // c, (t - 1) % c) - assert len(p) == abs(t[0] - s[0]) + abs(t[1] - s[1]) + 1 - p = [((u - 1) // c, (u - 1) % c) for u in p] - for u in p: - assert 0 <= u[0] < r - assert 0 <= u[1] < c - for u, v in zip(p[:-1], p[1:]): - assert (abs(v[0] - u[0]), abs(v[1] - u[1])) in [(0, 1), (1, 0)] - - -class TestUnweightedPath: - @classmethod - def setup_class(cls): - from networkx import convert_node_labels_to_integers as cnlti - - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - - def test_bidirectional_shortest_path(self): - assert nx.bidirectional_shortest_path(self.cycle, 0, 3) == [0, 1, 2, 3] - assert nx.bidirectional_shortest_path(self.cycle, 0, 4) == [0, 6, 5, 4] - validate_grid_path( - 4, 4, 1, 12, nx.bidirectional_shortest_path(self.grid, 1, 12) - ) - assert nx.bidirectional_shortest_path(self.directed_cycle, 0, 3) == [0, 1, 2, 3] - # test source = target - assert nx.bidirectional_shortest_path(self.cycle, 3, 3) == [3] - - @pytest.mark.parametrize( - ("src", "tgt"), - ( - (8, 3), # source not in graph - (3, 8), # target not in graph - (8, 10), # neither source nor target in graph - (8, 8), # src == tgt, neither in graph - tests order of input checks - ), - ) - def test_bidirectional_shortest_path_src_tgt_not_in_graph(self, src, tgt): - with pytest.raises( - nx.NodeNotFound, - match=f"(Source {src}|Target {tgt}) is not in G", - ): - nx.bidirectional_shortest_path(self.cycle, src, tgt) - - def test_shortest_path_length(self): - assert nx.shortest_path_length(self.cycle, 0, 3) == 3 - assert nx.shortest_path_length(self.grid, 1, 12) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4) == 4 - # now with weights - assert nx.shortest_path_length(self.cycle, 0, 3, weight=True) == 3 - assert nx.shortest_path_length(self.grid, 1, 12, weight=True) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4, weight=True) == 4 - - def test_single_source_shortest_path(self): - p = nx.single_source_shortest_path(self.directed_cycle, 3) - assert p[0] == [3, 4, 5, 6, 0] - p = nx.single_source_shortest_path(self.cycle, 0) - assert p[3] == [0, 1, 2, 3] - p = nx.single_source_shortest_path(self.cycle, 0, cutoff=0) - assert p == {0: [0]} - - def test_single_source_shortest_path_length(self): - pl = nx.single_source_shortest_path_length - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.cycle, 0)) == lengths - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6} - assert dict(pl(self.directed_cycle, 0)) == lengths - - def test_single_target_shortest_path(self): - p = nx.single_target_shortest_path(self.directed_cycle, 0) - assert p[3] == [3, 4, 5, 6, 0] - p = nx.single_target_shortest_path(self.cycle, 0) - assert p[3] == [3, 2, 1, 0] - p = nx.single_target_shortest_path(self.cycle, 0, cutoff=0) - assert p == {0: [0]} - # test missing targets - target = 8 - with pytest.raises(nx.NodeNotFound, match=f"Target {target} not in G"): - nx.single_target_shortest_path(self.cycle, target) - - def test_single_target_shortest_path_length(self): - pl = nx.single_target_shortest_path_length - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.cycle, 0)) == lengths - lengths = {0: 0, 1: 6, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.directed_cycle, 0)) == lengths - # test missing targets - target = 8 - with pytest.raises(nx.NodeNotFound, match=f"Target {target} is not in G"): - nx.single_target_shortest_path_length(self.cycle, target) - - def test_all_pairs_shortest_path(self): - p = dict(nx.all_pairs_shortest_path(self.cycle)) - assert p[0][3] == [0, 1, 2, 3] - p = dict(nx.all_pairs_shortest_path(self.grid)) - validate_grid_path(4, 4, 1, 12, p[1][12]) - - def test_all_pairs_shortest_path_length(self): - l = dict(nx.all_pairs_shortest_path_length(self.cycle)) - assert l[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - l = dict(nx.all_pairs_shortest_path_length(self.grid)) - assert l[1][16] == 6 - - def test_predecessor_path(self): - G = nx.path_graph(4) - assert nx.predecessor(G, 0) == {0: [], 1: [0], 2: [1], 3: [2]} - assert nx.predecessor(G, 0, 3) == [2] - - def test_predecessor_cycle(self): - G = nx.cycle_graph(4) - pred = nx.predecessor(G, 0) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - - def test_predecessor_cutoff(self): - G = nx.path_graph(4) - p = nx.predecessor(G, 0, 3) - assert 4 not in p - - def test_predecessor_target(self): - G = nx.path_graph(4) - p = nx.predecessor(G, 0, 3) - assert p == [2] - p = nx.predecessor(G, 0, 3, cutoff=2) - assert p == [] - p, s = nx.predecessor(G, 0, 3, return_seen=True) - assert p == [2] - assert s == 3 - p, s = nx.predecessor(G, 0, 3, cutoff=2, return_seen=True) - assert p == [] - assert s == -1 - - def test_predecessor_missing_source(self): - source = 8 - with pytest.raises(nx.NodeNotFound, match=f"Source {source} not in G"): - nx.predecessor(self.cycle, source) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_weighted.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_weighted.py deleted file mode 100644 index dc88572..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/tests/test_weighted.py +++ /dev/null @@ -1,972 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import pairwise - - -def validate_path(G, s, t, soln_len, path, weight="weight"): - assert path[0] == s - assert path[-1] == t - - if callable(weight): - weight_f = weight - else: - if G.is_multigraph(): - - def weight_f(u, v, d): - return min(e.get(weight, 1) for e in d.values()) - - else: - - def weight_f(u, v, d): - return d.get(weight, 1) - - computed = sum(weight_f(u, v, G[u][v]) for u, v in pairwise(path)) - assert soln_len == computed - - -def validate_length_path(G, s, t, soln_len, length, path, weight="weight"): - assert soln_len == length - validate_path(G, s, t, length, path, weight=weight) - - -class WeightedTestBase: - """Base class for test classes that test functions for computing - shortest paths in weighted graphs. - - """ - - def setup_method(self): - """Creates some graphs for use in the unit tests.""" - cnlti = nx.convert_node_labels_to_integers - self.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - self.cycle = nx.cycle_graph(7) - self.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - self.XG = nx.DiGraph() - self.XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - self.MXG = nx.MultiDiGraph(self.XG) - self.MXG.add_edge("s", "u", weight=15) - self.XG2 = nx.DiGraph() - self.XG2.add_weighted_edges_from( - [ - [1, 4, 1], - [4, 5, 1], - [5, 6, 1], - [6, 3, 1], - [1, 3, 50], - [1, 2, 100], - [2, 3, 100], - ] - ) - - self.XG3 = nx.Graph() - self.XG3.add_weighted_edges_from( - [[0, 1, 2], [1, 2, 12], [2, 3, 1], [3, 4, 5], [4, 5, 1], [5, 0, 10]] - ) - - self.XG4 = nx.Graph() - self.XG4.add_weighted_edges_from( - [ - [0, 1, 2], - [1, 2, 2], - [2, 3, 1], - [3, 4, 1], - [4, 5, 1], - [5, 6, 1], - [6, 7, 1], - [7, 0, 1], - ] - ) - self.MXG4 = nx.MultiGraph(self.XG4) - self.MXG4.add_edge(0, 1, weight=3) - self.G = nx.DiGraph() # no weights - self.G.add_edges_from( - [ - ("s", "u"), - ("s", "x"), - ("u", "v"), - ("u", "x"), - ("v", "y"), - ("x", "u"), - ("x", "v"), - ("x", "y"), - ("y", "s"), - ("y", "v"), - ] - ) - - -class TestWeightedPath(WeightedTestBase): - def test_dijkstra(self): - (D, P) = nx.single_source_dijkstra(self.XG, "s") - validate_path(self.XG, "s", "v", 9, P["v"]) - assert D["v"] == 9 - - validate_path( - self.XG, "s", "v", 9, nx.single_source_dijkstra_path(self.XG, "s")["v"] - ) - assert dict(nx.single_source_dijkstra_path_length(self.XG, "s"))["v"] == 9 - - validate_path( - self.XG, "s", "v", 9, nx.single_source_dijkstra(self.XG, "s")[1]["v"] - ) - validate_path( - self.MXG, "s", "v", 9, nx.single_source_dijkstra_path(self.MXG, "s")["v"] - ) - - GG = self.XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG["u"]["x"]["weight"] = 2 - (D, P) = nx.single_source_dijkstra(GG, "s") - validate_path(GG, "s", "v", 8, P["v"]) - assert D["v"] == 8 # uses lower weight of 2 on u<->x edge - validate_path(GG, "s", "v", 8, nx.dijkstra_path(GG, "s", "v")) - assert nx.dijkstra_path_length(GG, "s", "v") == 8 - - validate_path(self.XG2, 1, 3, 4, nx.dijkstra_path(self.XG2, 1, 3)) - validate_path(self.XG3, 0, 3, 15, nx.dijkstra_path(self.XG3, 0, 3)) - assert nx.dijkstra_path_length(self.XG3, 0, 3) == 15 - validate_path(self.XG4, 0, 2, 4, nx.dijkstra_path(self.XG4, 0, 2)) - assert nx.dijkstra_path_length(self.XG4, 0, 2) == 4 - validate_path(self.MXG4, 0, 2, 4, nx.dijkstra_path(self.MXG4, 0, 2)) - validate_path( - self.G, "s", "v", 2, nx.single_source_dijkstra(self.G, "s", "v")[1] - ) - validate_path( - self.G, "s", "v", 2, nx.single_source_dijkstra(self.G, "s")[1]["v"] - ) - - validate_path(self.G, "s", "v", 2, nx.dijkstra_path(self.G, "s", "v")) - assert nx.dijkstra_path_length(self.G, "s", "v") == 2 - - # NetworkXError: node s not reachable from moon - pytest.raises(nx.NetworkXNoPath, nx.dijkstra_path, self.G, "s", "moon") - pytest.raises(nx.NetworkXNoPath, nx.dijkstra_path_length, self.G, "s", "moon") - - validate_path(self.cycle, 0, 3, 3, nx.dijkstra_path(self.cycle, 0, 3)) - validate_path(self.cycle, 0, 4, 3, nx.dijkstra_path(self.cycle, 0, 4)) - - assert nx.single_source_dijkstra(self.cycle, 0, 0) == (0, [0]) - - def test_bidirectional_dijkstra(self): - validate_length_path( - self.XG, "s", "v", 9, *nx.bidirectional_dijkstra(self.XG, "s", "v") - ) - validate_length_path( - self.G, "s", "v", 2, *nx.bidirectional_dijkstra(self.G, "s", "v") - ) - validate_length_path( - self.cycle, 0, 3, 3, *nx.bidirectional_dijkstra(self.cycle, 0, 3) - ) - validate_length_path( - self.cycle, 0, 4, 3, *nx.bidirectional_dijkstra(self.cycle, 0, 4) - ) - validate_length_path( - self.XG3, 0, 3, 15, *nx.bidirectional_dijkstra(self.XG3, 0, 3) - ) - validate_length_path( - self.XG4, 0, 2, 4, *nx.bidirectional_dijkstra(self.XG4, 0, 2) - ) - - # need more tests here - P = nx.single_source_dijkstra_path(self.XG, "s")["v"] - validate_path( - self.XG, - "s", - "v", - sum(self.XG[u][v]["weight"] for u, v in zip(P[:-1], P[1:])), - nx.dijkstra_path(self.XG, "s", "v"), - ) - - # check absent source - G = nx.path_graph(2) - pytest.raises(nx.NodeNotFound, nx.bidirectional_dijkstra, G, 3, 0) - - def test_weight_functions(self): - def heuristic(*z): - return sum(val**2 for val in z) - - def getpath(pred, v, s): - return [v] if v == s else getpath(pred, pred[v], s) + [v] - - def goldberg_radzik(g, s, t, weight="weight"): - pred, dist = nx.goldberg_radzik(g, s, weight=weight) - dist = dist[t] - return dist, getpath(pred, t, s) - - def astar(g, s, t, weight="weight"): - path = nx.astar_path(g, s, t, heuristic, weight=weight) - dist = nx.astar_path_length(g, s, t, heuristic, weight=weight) - return dist, path - - def vlp(G, s, t, l, F, w): - res = F(G, s, t, weight=w) - validate_length_path(G, s, t, l, *res, weight=w) - - G = self.cycle - s = 6 - t = 4 - path = [6] + list(range(t + 1)) - - def weight(u, v, _): - return 1 + v**2 - - length = sum(weight(u, v, None) for u, v in pairwise(path)) - vlp(G, s, t, length, nx.bidirectional_dijkstra, weight) - vlp(G, s, t, length, nx.single_source_dijkstra, weight) - vlp(G, s, t, length, nx.single_source_bellman_ford, weight) - vlp(G, s, t, length, goldberg_radzik, weight) - vlp(G, s, t, length, astar, weight) - - def weight(u, v, _): - return 2 ** (u * v) - - length = sum(weight(u, v, None) for u, v in pairwise(path)) - vlp(G, s, t, length, nx.bidirectional_dijkstra, weight) - vlp(G, s, t, length, nx.single_source_dijkstra, weight) - vlp(G, s, t, length, nx.single_source_bellman_ford, weight) - vlp(G, s, t, length, goldberg_radzik, weight) - vlp(G, s, t, length, astar, weight) - - def test_bidirectional_dijkstra_no_path(self): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5, 6]) - path = nx.bidirectional_dijkstra(G, 1, 6) - - @pytest.mark.parametrize( - "fn", - ( - nx.dijkstra_path, - nx.dijkstra_path_length, - nx.single_source_dijkstra_path, - nx.single_source_dijkstra_path_length, - nx.single_source_dijkstra, - nx.dijkstra_predecessor_and_distance, - ), - ) - def test_absent_source(self, fn): - G = nx.path_graph(2) - with pytest.raises(nx.NodeNotFound): - fn(G, 3, 0) - # Test when source == target, which is handled specially by some functions - with pytest.raises(nx.NodeNotFound): - fn(G, 3, 3) - - def test_dijkstra_predecessor1(self): - G = nx.path_graph(4) - assert nx.dijkstra_predecessor_and_distance(G, 0) == ( - {0: [], 1: [0], 2: [1], 3: [2]}, - {0: 0, 1: 1, 2: 2, 3: 3}, - ) - - def test_dijkstra_predecessor2(self): - # 4-cycle - G = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 0)]) - pred, dist = nx.dijkstra_predecessor_and_distance(G, (0)) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - def test_dijkstra_predecessor3(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - (P, D) = nx.dijkstra_predecessor_and_distance(XG, "s") - assert P["v"] == ["u"] - assert D["v"] == 9 - (P, D) = nx.dijkstra_predecessor_and_distance(XG, "s", cutoff=8) - assert "v" not in D - - def test_single_source_dijkstra_path_length(self): - pl = nx.single_source_dijkstra_path_length - assert dict(pl(self.MXG4, 0))[2] == 4 - spl = pl(self.MXG4, 0, cutoff=2) - assert 2 not in spl - - def test_bidirectional_dijkstra_multigraph(self): - G = nx.MultiGraph() - G.add_edge("a", "b", weight=10) - G.add_edge("a", "b", weight=100) - dp = nx.bidirectional_dijkstra(G, "a", "b") - assert dp == (10, ["a", "b"]) - - def test_dijkstra_pred_distance_multigraph(self): - G = nx.MultiGraph() - G.add_edge("a", "b", key="short", foo=5, weight=100) - G.add_edge("a", "b", key="long", bar=1, weight=110) - p, d = nx.dijkstra_predecessor_and_distance(G, "a") - assert p == {"a": [], "b": ["a"]} - assert d == {"a": 0, "b": 100} - - def test_negative_edge_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - assert not nx.negative_edge_cycle(G) - G.add_edge(8, 9, weight=-7) - G.add_edge(9, 8, weight=3) - graph_size = len(G) - assert nx.negative_edge_cycle(G) - assert graph_size == len(G) - pytest.raises(ValueError, nx.single_source_dijkstra_path_length, G, 8) - pytest.raises(ValueError, nx.single_source_dijkstra, G, 8) - pytest.raises(ValueError, nx.dijkstra_predecessor_and_distance, G, 8) - G.add_edge(9, 10) - pytest.raises(ValueError, nx.bidirectional_dijkstra, G, 8, 10) - G = nx.MultiDiGraph() - G.add_edge(2, 2, weight=-1) - assert nx.negative_edge_cycle(G) - - def test_negative_edge_cycle_empty(self): - G = nx.DiGraph() - assert not nx.negative_edge_cycle(G) - - def test_negative_edge_cycle_custom_weight_key(self): - d = nx.DiGraph() - d.add_edge("a", "b", w=-2) - d.add_edge("b", "a", w=-1) - assert nx.negative_edge_cycle(d, weight="w") - - def test_weight_function(self): - """Tests that a callable weight is interpreted as a weight - function instead of an edge attribute. - - """ - # Create a triangle in which the edge from node 0 to node 2 has - # a large weight and the other two edges have a small weight. - G = nx.complete_graph(3) - G.adj[0][2]["weight"] = 10 - G.adj[0][1]["weight"] = 1 - G.adj[1][2]["weight"] = 1 - - # The weight function will take the multiplicative inverse of - # the weights on the edges. This way, weights that were large - # before now become small and vice versa. - - def weight(u, v, d): - return 1 / d["weight"] - - # The shortest path from 0 to 2 using the actual weights on the - # edges should be [0, 1, 2]. - distance, path = nx.single_source_dijkstra(G, 0, 2) - assert distance == 2 - assert path == [0, 1, 2] - # However, with the above weight function, the shortest path - # should be [0, 2], since that has a very small weight. - distance, path = nx.single_source_dijkstra(G, 0, 2, weight=weight) - assert distance == 1 / 10 - assert path == [0, 2] - - def test_all_pairs_dijkstra_path(self): - cycle = nx.cycle_graph(7) - p = dict(nx.all_pairs_dijkstra_path(cycle)) - assert p[0][3] == [0, 1, 2, 3] - - cycle[1][2]["weight"] = 10 - p = dict(nx.all_pairs_dijkstra_path(cycle)) - assert p[0][3] == [0, 6, 5, 4, 3] - - def test_all_pairs_dijkstra_path_length(self): - cycle = nx.cycle_graph(7) - pl = dict(nx.all_pairs_dijkstra_path_length(cycle)) - assert pl[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - - cycle[1][2]["weight"] = 10 - pl = dict(nx.all_pairs_dijkstra_path_length(cycle)) - assert pl[0] == {0: 0, 1: 1, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - - def test_all_pairs_dijkstra(self): - cycle = nx.cycle_graph(7) - out = dict(nx.all_pairs_dijkstra(cycle)) - assert out[0][0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert out[0][1][3] == [0, 1, 2, 3] - - cycle[1][2]["weight"] = 10 - out = dict(nx.all_pairs_dijkstra(cycle)) - assert out[0][0] == {0: 0, 1: 1, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - assert out[0][1][3] == [0, 6, 5, 4, 3] - - -class TestDijkstraPathLength: - """Unit tests for the :func:`networkx.dijkstra_path_length` - function. - - """ - - def test_weight_function(self): - """Tests for computing the length of the shortest path using - Dijkstra's algorithm with a user-defined weight function. - - """ - # Create a triangle in which the edge from node 0 to node 2 has - # a large weight and the other two edges have a small weight. - G = nx.complete_graph(3) - G.adj[0][2]["weight"] = 10 - G.adj[0][1]["weight"] = 1 - G.adj[1][2]["weight"] = 1 - - # The weight function will take the multiplicative inverse of - # the weights on the edges. This way, weights that were large - # before now become small and vice versa. - - def weight(u, v, d): - return 1 / d["weight"] - - # The shortest path from 0 to 2 using the actual weights on the - # edges should be [0, 1, 2]. However, with the above weight - # function, the shortest path should be [0, 2], since that has a - # very small weight. - length = nx.dijkstra_path_length(G, 0, 2, weight=weight) - assert length == 1 / 10 - - -class TestMultiSourceDijkstra: - """Unit tests for the multi-source dialect of Dijkstra's shortest - path algorithms. - - """ - - def test_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra(nx.Graph(), {}) - - def test_path_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra_path(nx.Graph(), {}) - - def test_path_length_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra_path_length(nx.Graph(), {}) - - @pytest.mark.parametrize( - "fn", - ( - nx.multi_source_dijkstra_path, - nx.multi_source_dijkstra_path_length, - nx.multi_source_dijkstra, - ), - ) - def test_absent_source(self, fn): - G = nx.path_graph(2) - with pytest.raises(nx.NodeNotFound): - fn(G, [3], 0) - with pytest.raises(nx.NodeNotFound): - fn(G, [3], 3) - - def test_two_sources(self): - edges = [(0, 1, 1), (1, 2, 1), (2, 3, 10), (3, 4, 1)] - G = nx.Graph() - G.add_weighted_edges_from(edges) - sources = {0, 4} - distances, paths = nx.multi_source_dijkstra(G, sources) - expected_distances = {0: 0, 1: 1, 2: 2, 3: 1, 4: 0} - expected_paths = {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [4, 3], 4: [4]} - assert distances == expected_distances - assert paths == expected_paths - - def test_simple_paths(self): - G = nx.path_graph(4) - lengths = nx.multi_source_dijkstra_path_length(G, [0]) - assert lengths == {n: n for n in G} - paths = nx.multi_source_dijkstra_path(G, [0]) - assert paths == {n: list(range(n + 1)) for n in G} - - -class TestBellmanFordAndGoldbergRadzik(WeightedTestBase): - def test_single_node_graph(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.single_source_bellman_ford_path(G, 0) == {0: [0]} - assert nx.single_source_bellman_ford_path_length(G, 0) == {0: 0} - assert nx.single_source_bellman_ford(G, 0) == ({0: 0}, {0: [0]}) - assert nx.bellman_ford_predecessor_and_distance(G, 0) == ({0: []}, {0: 0}) - assert nx.goldberg_radzik(G, 0) == ({0: None}, {0: 0}) - - def test_absent_source_bellman_ford(self): - # the check is in _bellman_ford; this provides regression testing - # against later changes to "client" Bellman-Ford functions - G = nx.path_graph(2) - for fn in ( - nx.bellman_ford_predecessor_and_distance, - nx.bellman_ford_path, - nx.bellman_ford_path_length, - nx.single_source_bellman_ford_path, - nx.single_source_bellman_ford_path_length, - nx.single_source_bellman_ford, - ): - pytest.raises(nx.NodeNotFound, fn, G, 3, 0) - pytest.raises(nx.NodeNotFound, fn, G, 3, 3) - - def test_absent_source_goldberg_radzik(self): - with pytest.raises(nx.NodeNotFound): - G = nx.path_graph(2) - nx.goldberg_radzik(G, 3, 0) - - def test_negative_cycle_heuristic(self): - G = nx.DiGraph() - G.add_edge(0, 1, weight=-1) - G.add_edge(1, 2, weight=-1) - G.add_edge(2, 3, weight=-1) - G.add_edge(3, 0, weight=3) - assert not nx.negative_edge_cycle(G, heuristic=True) - G.add_edge(2, 0, weight=1.999) - assert nx.negative_edge_cycle(G, heuristic=True) - G.edges[2, 0]["weight"] = 2 - assert not nx.negative_edge_cycle(G, heuristic=True) - - def test_negative_cycle_consistency(self): - import random - - unif = random.uniform - for random_seed in range(2): # range(20): - random.seed(random_seed) - for density in [0.1, 0.9]: # .3, .7, .9]: - for N in [1, 10, 20]: # range(1, 60 - int(30 * density)): - for max_cost in [1, 90]: # [1, 10, 40, 90]: - G = nx.binomial_graph(N, density, seed=4, directed=True) - edges = ((u, v, unif(-1, max_cost)) for u, v in G.edges) - G.add_weighted_edges_from(edges) - - no_heuristic = nx.negative_edge_cycle(G, heuristic=False) - with_heuristic = nx.negative_edge_cycle(G, heuristic=True) - assert no_heuristic == with_heuristic - - def test_negative_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - G.add_edge(1, 2, weight=-7) - for i in range(5): - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, i - ) - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, i - ) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, i) - pytest.raises( - nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, i - ) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, i) - G = nx.cycle_graph(5) # undirected Graph - G.add_edge(1, 2, weight=-3) - for i in range(5): - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, i - ) - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, i - ) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, i) - pytest.raises( - nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, i - ) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, i) - G = nx.DiGraph([(1, 1, {"weight": -1})]) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, 1) - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, 1 - ) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, 1) - pytest.raises( - nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, 1 - ) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, 1) - G = nx.MultiDiGraph([(1, 1, {"weight": -1})]) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, 1) - pytest.raises( - nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, 1 - ) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, 1) - pytest.raises( - nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, 1 - ) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, 1) - - def test_zero_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - G.add_edge(2, 3, weight=-4) - # check that zero cycle doesn't raise - nx.goldberg_radzik(G, 1) - nx.bellman_ford_predecessor_and_distance(G, 1) - - G.add_edge(2, 3, weight=-4.0001) - # check that negative cycle does raise - pytest.raises( - nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, 1 - ) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, 1) - - def test_find_negative_cycle_longer_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - nx.add_cycle(G, [3, 5, 6, 7, 8, 9]) - G.add_edge(1, 2, weight=-30) - assert nx.find_negative_cycle(G, 1) == [0, 1, 2, 3, 4, 0] - assert nx.find_negative_cycle(G, 7) == [2, 3, 4, 0, 1, 2] - - def test_find_negative_cycle_no_cycle(self): - G = nx.path_graph(5, create_using=nx.DiGraph()) - pytest.raises(nx.NetworkXError, nx.find_negative_cycle, G, 3) - - def test_find_negative_cycle_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1, weight=-1) - assert nx.find_negative_cycle(G, 1) == [1, 0, 1] - - def test_negative_weight(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - G.add_edge(1, 2, weight=-3) - assert nx.single_source_bellman_ford_path(G, 0) == { - 0: [0], - 1: [0, 1], - 2: [0, 1, 2], - 3: [0, 1, 2, 3], - 4: [0, 1, 2, 3, 4], - } - assert nx.single_source_bellman_ford_path_length(G, 0) == { - 0: 0, - 1: 1, - 2: -2, - 3: -1, - 4: 0, - } - assert nx.single_source_bellman_ford(G, 0) == ( - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0}, - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}, - ) - assert nx.bellman_ford_predecessor_and_distance(G, 0) == ( - {0: [], 1: [0], 2: [1], 3: [2], 4: [3]}, - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0}, - ) - assert nx.goldberg_radzik(G, 0) == ( - {0: None, 1: 0, 2: 1, 3: 2, 4: 3}, - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0}, - ) - - def test_not_connected(self): - G = nx.complete_graph(6) - G.add_edge(10, 11) - G.add_edge(10, 12) - assert nx.single_source_bellman_ford_path(G, 0) == { - 0: [0], - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 4], - 5: [0, 5], - } - assert nx.single_source_bellman_ford_path_length(G, 0) == { - 0: 0, - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - } - assert nx.single_source_bellman_ford(G, 0) == ( - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]}, - ) - assert nx.bellman_ford_predecessor_and_distance(G, 0) == ( - {0: [], 1: [0], 2: [0], 3: [0], 4: [0], 5: [0]}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - ) - assert nx.goldberg_radzik(G, 0) == ( - {0: None, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - ) - - # not connected, with a component not containing the source that - # contains a negative cycle. - G = nx.complete_graph(6) - G.add_edges_from( - [ - ("A", "B", {"load": 3}), - ("B", "C", {"load": -10}), - ("C", "A", {"load": 2}), - ] - ) - assert nx.single_source_bellman_ford_path(G, 0, weight="load") == { - 0: [0], - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 4], - 5: [0, 5], - } - assert nx.single_source_bellman_ford_path_length(G, 0, weight="load") == { - 0: 0, - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - } - assert nx.single_source_bellman_ford(G, 0, weight="load") == ( - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]}, - ) - assert nx.bellman_ford_predecessor_and_distance(G, 0, weight="load") == ( - {0: [], 1: [0], 2: [0], 3: [0], 4: [0], 5: [0]}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - ) - assert nx.goldberg_radzik(G, 0, weight="load") == ( - {0: None, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - ) - - def test_multigraph(self): - assert nx.bellman_ford_path(self.MXG, "s", "v") == ["s", "x", "u", "v"] - assert nx.bellman_ford_path_length(self.MXG, "s", "v") == 9 - assert nx.single_source_bellman_ford_path(self.MXG, "s")["v"] == [ - "s", - "x", - "u", - "v", - ] - assert nx.single_source_bellman_ford_path_length(self.MXG, "s")["v"] == 9 - D, P = nx.single_source_bellman_ford(self.MXG, "s", target="v") - assert D == 9 - assert P == ["s", "x", "u", "v"] - P, D = nx.bellman_ford_predecessor_and_distance(self.MXG, "s") - assert P["v"] == ["u"] - assert D["v"] == 9 - P, D = nx.goldberg_radzik(self.MXG, "s") - assert P["v"] == "u" - assert D["v"] == 9 - assert nx.bellman_ford_path(self.MXG4, 0, 2) == [0, 1, 2] - assert nx.bellman_ford_path_length(self.MXG4, 0, 2) == 4 - assert nx.single_source_bellman_ford_path(self.MXG4, 0)[2] == [0, 1, 2] - assert nx.single_source_bellman_ford_path_length(self.MXG4, 0)[2] == 4 - D, P = nx.single_source_bellman_ford(self.MXG4, 0, target=2) - assert D == 4 - assert P == [0, 1, 2] - P, D = nx.bellman_ford_predecessor_and_distance(self.MXG4, 0) - assert P[2] == [1] - assert D[2] == 4 - P, D = nx.goldberg_radzik(self.MXG4, 0) - assert P[2] == 1 - assert D[2] == 4 - - def test_others(self): - assert nx.bellman_ford_path(self.XG, "s", "v") == ["s", "x", "u", "v"] - assert nx.bellman_ford_path_length(self.XG, "s", "v") == 9 - assert nx.single_source_bellman_ford_path(self.XG, "s")["v"] == [ - "s", - "x", - "u", - "v", - ] - assert nx.single_source_bellman_ford_path_length(self.XG, "s")["v"] == 9 - D, P = nx.single_source_bellman_ford(self.XG, "s", target="v") - assert D == 9 - assert P == ["s", "x", "u", "v"] - (P, D) = nx.bellman_ford_predecessor_and_distance(self.XG, "s") - assert P["v"] == ["u"] - assert D["v"] == 9 - (P, D) = nx.goldberg_radzik(self.XG, "s") - assert P["v"] == "u" - assert D["v"] == 9 - - def test_path_graph(self): - G = nx.path_graph(4) - assert nx.single_source_bellman_ford_path(G, 0) == { - 0: [0], - 1: [0, 1], - 2: [0, 1, 2], - 3: [0, 1, 2, 3], - } - assert nx.single_source_bellman_ford_path_length(G, 0) == { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - } - assert nx.single_source_bellman_ford(G, 0) == ( - {0: 0, 1: 1, 2: 2, 3: 3}, - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3]}, - ) - assert nx.bellman_ford_predecessor_and_distance(G, 0) == ( - {0: [], 1: [0], 2: [1], 3: [2]}, - {0: 0, 1: 1, 2: 2, 3: 3}, - ) - assert nx.goldberg_radzik(G, 0) == ( - {0: None, 1: 0, 2: 1, 3: 2}, - {0: 0, 1: 1, 2: 2, 3: 3}, - ) - assert nx.single_source_bellman_ford_path(G, 3) == { - 0: [3, 2, 1, 0], - 1: [3, 2, 1], - 2: [3, 2], - 3: [3], - } - assert nx.single_source_bellman_ford_path_length(G, 3) == { - 0: 3, - 1: 2, - 2: 1, - 3: 0, - } - assert nx.single_source_bellman_ford(G, 3) == ( - {0: 3, 1: 2, 2: 1, 3: 0}, - {0: [3, 2, 1, 0], 1: [3, 2, 1], 2: [3, 2], 3: [3]}, - ) - assert nx.bellman_ford_predecessor_and_distance(G, 3) == ( - {0: [1], 1: [2], 2: [3], 3: []}, - {0: 3, 1: 2, 2: 1, 3: 0}, - ) - assert nx.goldberg_radzik(G, 3) == ( - {0: 1, 1: 2, 2: 3, 3: None}, - {0: 3, 1: 2, 2: 1, 3: 0}, - ) - - def test_4_cycle(self): - # 4-cycle - G = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 0)]) - dist, path = nx.single_source_bellman_ford(G, 0) - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - assert path[0] == [0] - assert path[1] == [0, 1] - assert path[2] in [[0, 1, 2], [0, 3, 2]] - assert path[3] == [0, 3] - - pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - pred, dist = nx.goldberg_radzik(G, 0) - assert pred[0] is None - assert pred[1] == 0 - assert pred[2] in [1, 3] - assert pred[3] == 0 - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - def test_negative_weight_bf_path(self): - G = nx.DiGraph() - G.add_nodes_from("abcd") - G.add_edge("a", "d", weight=0) - G.add_edge("a", "b", weight=1) - G.add_edge("b", "c", weight=-3) - G.add_edge("c", "d", weight=1) - - assert nx.bellman_ford_path(G, "a", "d") == ["a", "b", "c", "d"] - assert nx.bellman_ford_path_length(G, "a", "d") == -1 - - def test_zero_cycle_smoke(self): - D = nx.DiGraph() - D.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1), (3, 1, -2)]) - - nx.bellman_ford_path(D, 1, 3) - nx.dijkstra_path(D, 1, 3) - nx.bidirectional_dijkstra(D, 1, 3) - # FIXME nx.goldberg_radzik(D, 1) - - -class TestJohnsonAlgorithm(WeightedTestBase): - def test_single_node_graph(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.johnson(G) == {0: {0: [0]}} - - def test_negative_cycle(self): - G = nx.DiGraph() - G.add_weighted_edges_from( - [ - ("0", "3", 3), - ("0", "1", -5), - ("1", "0", -5), - ("0", "2", 2), - ("1", "2", 4), - ("2", "3", 1), - ] - ) - pytest.raises(nx.NetworkXUnbounded, nx.johnson, G) - G = nx.Graph() - G.add_weighted_edges_from( - [ - ("0", "3", 3), - ("0", "1", -5), - ("1", "0", -5), - ("0", "2", 2), - ("1", "2", 4), - ("2", "3", 1), - ] - ) - pytest.raises(nx.NetworkXUnbounded, nx.johnson, G) - - def test_negative_weights(self): - G = nx.DiGraph() - G.add_weighted_edges_from( - [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)] - ) - paths = nx.johnson(G) - assert paths == { - "1": {"1": ["1"], "3": ["1", "2", "3"], "2": ["1", "2"]}, - "0": { - "1": ["0", "1"], - "0": ["0"], - "3": ["0", "1", "2", "3"], - "2": ["0", "1", "2"], - }, - "3": {"3": ["3"]}, - "2": {"3": ["2", "3"], "2": ["2"]}, - } - - def test_unweighted_graph(self): - G = nx.Graph() - G.add_edges_from([(1, 0), (2, 1)]) - H = G.copy() - nx.set_edge_attributes(H, values=1, name="weight") - assert nx.johnson(G) == nx.johnson(H) - - def test_partially_weighted_graph_with_negative_edges(self): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (1, 0)]) - G[1][0]["weight"] = -2 - G[0][1]["weight"] = 3 - G[1][2]["weight"] = -4 - - H = G.copy() - H[2][0]["weight"] = 1 - - I = G.copy() - I[2][0]["weight"] = 8 - - assert nx.johnson(G) == nx.johnson(H) - assert nx.johnson(G) != nx.johnson(I) - - def test_graphs(self): - validate_path(self.XG, "s", "v", 9, nx.johnson(self.XG)["s"]["v"]) - validate_path(self.MXG, "s", "v", 9, nx.johnson(self.MXG)["s"]["v"]) - validate_path(self.XG2, 1, 3, 4, nx.johnson(self.XG2)[1][3]) - validate_path(self.XG3, 0, 3, 15, nx.johnson(self.XG3)[0][3]) - validate_path(self.XG4, 0, 2, 4, nx.johnson(self.XG4)[0][2]) - validate_path(self.MXG4, 0, 2, 4, nx.johnson(self.MXG4)[0][2]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/unweighted.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/unweighted.py deleted file mode 100644 index 3aeef85..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/unweighted.py +++ /dev/null @@ -1,579 +0,0 @@ -""" -Shortest path algorithms for unweighted graphs. -""" - -import warnings - -import networkx as nx - -__all__ = [ - "bidirectional_shortest_path", - "single_source_shortest_path", - "single_source_shortest_path_length", - "single_target_shortest_path", - "single_target_shortest_path_length", - "all_pairs_shortest_path", - "all_pairs_shortest_path_length", - "predecessor", -] - - -@nx._dispatchable -def single_source_shortest_path_length(G, source, cutoff=None): - """Compute the shortest path lengths from source to all reachable nodes. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : dict - Dict keyed by node to shortest path length to source. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.single_source_shortest_path_length(G, 0) - >>> length[4] - 4 - >>> for node in length: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - See Also - -------- - shortest_path_length - """ - if source not in G: - raise nx.NodeNotFound(f"Source {source} is not in G") - if cutoff is None: - cutoff = float("inf") - nextlevel = [source] - return dict(_single_shortest_path_length(G._adj, nextlevel, cutoff)) - - -def _single_shortest_path_length(adj, firstlevel, cutoff): - """Yields (node, level) in a breadth first search - - Shortest Path Length helper function - Parameters - ---------- - adj : dict - Adjacency dict or view - firstlevel : list - starting nodes, e.g. [source] or [target] - cutoff : int or float - level at which we stop the process - """ - seen = set(firstlevel) - nextlevel = firstlevel - level = 0 - n = len(adj) - for v in nextlevel: - yield (v, level) - while nextlevel and cutoff > level: - level += 1 - thislevel = nextlevel - nextlevel = [] - for v in thislevel: - for w in adj[v]: - if w not in seen: - seen.add(w) - nextlevel.append(w) - yield (w, level) - if len(seen) == n: - return - - -@nx._dispatchable -def single_target_shortest_path_length(G, target, cutoff=None): - """Compute the shortest path lengths to target from all reachable nodes. - - Parameters - ---------- - G : NetworkX graph - - target : node - Target node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : iterator - (source, shortest path length) iterator - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> length = dict(nx.single_target_shortest_path_length(G, 4)) - >>> length[0] - 4 - >>> for node in range(5): - ... print(f"{node}: {length[node]}") - 0: 4 - 1: 3 - 2: 2 - 3: 1 - 4: 0 - - See Also - -------- - single_source_shortest_path_length, shortest_path_length - """ - if target not in G: - raise nx.NodeNotFound(f"Target {target} is not in G") - - warnings.warn( - ( - "\n\nsingle_target_shortest_path_length will return a dict instead of" - "\nan iterator in version 3.5" - ), - FutureWarning, - stacklevel=3, - ) - - if cutoff is None: - cutoff = float("inf") - # handle either directed or undirected - adj = G._pred if G.is_directed() else G._adj - nextlevel = [target] - # for version 3.3 we will return a dict like this: - # return dict(_single_shortest_path_length(adj, nextlevel, cutoff)) - return _single_shortest_path_length(adj, nextlevel, cutoff) - - -@nx._dispatchable -def all_pairs_shortest_path_length(G, cutoff=None): - """Computes the shortest path lengths between all nodes in `G`. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer, optional - Depth at which to stop the search. Only paths of length at most - `cutoff` are returned. - - Returns - ------- - lengths : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Notes - ----- - The iterator returned only has reachable node pairs. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_shortest_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"1 - {node}: {length[1][node]}") - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - """ - length = single_source_shortest_path_length - # TODO This can be trivially parallelized. - for n in G: - yield (n, length(G, n, cutoff=cutoff)) - - -@nx._dispatchable -def bidirectional_shortest_path(G, source, target): - """Returns a list of nodes in a shortest path between source and target. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - Returns - ------- - path: list - List of nodes in a path from source to target. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3, 0, 4, 5, 6, 7, 4]) - >>> nx.bidirectional_shortest_path(G, 2, 6) - [2, 1, 0, 4, 5, 6] - - See Also - -------- - shortest_path - - Notes - ----- - This algorithm is used by shortest_path(G, source, target). - """ - - if source not in G: - raise nx.NodeNotFound(f"Source {source} is not in G") - - if target not in G: - raise nx.NodeNotFound(f"Target {target} is not in G") - - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from source to w - while w is not None: - path.append(w) - w = pred[w] - path.reverse() - # from w to target - w = succ[path[-1]] - while w is not None: - path.append(w) - w = succ[w] - - return path - - -def _bidirectional_pred_succ(G, source, target): - """Bidirectional shortest path helper. - - Returns (pred, succ, w) where - pred is a dictionary of predecessors from w to the source, and - succ is a dictionary of successors from w to the target. - """ - # does BFS from both source and target and meets in the middle - if target == source: - return ({target: None}, {source: None}, source) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.pred - Gsucc = G.succ - else: - Gpred = G.adj - Gsucc = G.adj - - # predecessor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - while forward_fringe and reverse_fringe: - if len(forward_fringe) <= len(reverse_fringe): - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc[v]: - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: # path found - return pred, succ, w - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred[v]: - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: # found path - return pred, succ, w - - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") - - -@nx._dispatchable -def single_source_shortest_path(G, source, cutoff=None): - """Compute shortest path between source - and all other nodes reachable from source. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - paths : dictionary - Dictionary, keyed by target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.single_source_shortest_path(G, 0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - The shortest path is not necessarily unique. So there can be multiple - paths between the source and each target node, all of which have the - same 'shortest' length. For each target node, this function returns - only one of those paths. - - See Also - -------- - shortest_path - """ - if source not in G: - raise nx.NodeNotFound(f"Source {source} not in G") - - def join(p1, p2): - return p1 + p2 - - if cutoff is None: - cutoff = float("inf") - nextlevel = {source: 1} # list of nodes to check at next level - paths = {source: [source]} # paths dictionary (paths to key from source) - return dict(_single_shortest_path(G.adj, nextlevel, paths, cutoff, join)) - - -def _single_shortest_path(adj, firstlevel, paths, cutoff, join): - """Returns shortest paths - - Shortest Path helper function - Parameters - ---------- - adj : dict - Adjacency dict or view - firstlevel : dict - starting nodes, e.g. {source: 1} or {target: 1} - paths : dict - paths for starting nodes, e.g. {source: [source]} - cutoff : int or float - level at which we stop the process - join : function - function to construct a path from two partial paths. Requires two - list inputs `p1` and `p2`, and returns a list. Usually returns - `p1 + p2` (forward from source) or `p2 + p1` (backward from target) - """ - level = 0 # the current level - nextlevel = firstlevel - while nextlevel and cutoff > level: - thislevel = nextlevel - nextlevel = {} - for v in thislevel: - for w in adj[v]: - if w not in paths: - paths[w] = join(paths[v], [w]) - nextlevel[w] = 1 - level += 1 - return paths - - -@nx._dispatchable -def single_target_shortest_path(G, target, cutoff=None): - """Compute shortest path to target from all nodes that reach target. - - Parameters - ---------- - G : NetworkX graph - - target : node label - Target node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - paths : dictionary - Dictionary, keyed by target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> path = nx.single_target_shortest_path(G, 4) - >>> path[0] - [0, 1, 2, 3, 4] - - Notes - ----- - The shortest path is not necessarily unique. So there can be multiple - paths between the source and each target node, all of which have the - same 'shortest' length. For each target node, this function returns - only one of those paths. - - See Also - -------- - shortest_path, single_source_shortest_path - """ - if target not in G: - raise nx.NodeNotFound(f"Target {target} not in G") - - def join(p1, p2): - return p2 + p1 - - # handle undirected graphs - adj = G.pred if G.is_directed() else G.adj - if cutoff is None: - cutoff = float("inf") - nextlevel = {target: 1} # list of nodes to check at next level - paths = {target: [target]} # paths dictionary (paths to key from source) - return dict(_single_shortest_path(adj, nextlevel, paths, cutoff, join)) - - -@nx._dispatchable -def all_pairs_shortest_path(G, cutoff=None): - """Compute shortest paths between all nodes. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer, optional - Depth at which to stop the search. Only paths of length at most - `cutoff` are returned. - - Returns - ------- - paths : iterator - Dictionary, keyed by source and target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_shortest_path(G)) - >>> print(path[0][4]) - [0, 1, 2, 3, 4] - - Notes - ----- - There may be multiple shortest paths with the same length between - two nodes. For each pair, this function returns only one of those paths. - - See Also - -------- - floyd_warshall - all_pairs_all_shortest_paths - - """ - # TODO This can be trivially parallelized. - for n in G: - yield (n, single_source_shortest_path(G, n, cutoff=cutoff)) - - -@nx._dispatchable -def predecessor(G, source, target=None, cutoff=None, return_seen=None): - """Returns dict of predecessors for the path from source to all nodes in G. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path. If provided only predecessors between - source and target are returned - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - return_seen : bool, optional (default=None) - Whether to return a dictionary, keyed by node, of the level (number of - hops) to reach the node (as seen during breadth-first-search). - - Returns - ------- - pred : dictionary - Dictionary, keyed by node, of predecessors in the shortest path. - - - (pred, seen): tuple of dictionaries - If `return_seen` argument is set to `True`, then a tuple of dictionaries - is returned. The first element is the dictionary, keyed by node, of - predecessors in the shortest path. The second element is the dictionary, - keyed by node, of the level (number of hops) to reach the node (as seen - during breadth-first-search). - - Examples - -------- - >>> G = nx.path_graph(4) - >>> list(G) - [0, 1, 2, 3] - >>> nx.predecessor(G, 0) - {0: [], 1: [0], 2: [1], 3: [2]} - >>> nx.predecessor(G, 0, return_seen=True) - ({0: [], 1: [0], 2: [1], 3: [2]}, {0: 0, 1: 1, 2: 2, 3: 3}) - - - """ - if source not in G: - raise nx.NodeNotFound(f"Source {source} not in G") - - level = 0 # the current level - nextlevel = [source] # list of nodes to check at next level - seen = {source: level} # level (number of hops) when seen in BFS - pred = {source: []} # predecessor dictionary - while nextlevel: - level = level + 1 - thislevel = nextlevel - nextlevel = [] - for v in thislevel: - for w in G[v]: - if w not in seen: - pred[w] = [v] - seen[w] = level - nextlevel.append(w) - elif seen[w] == level: # add v to predecessor list if it - pred[w].append(v) # is at the correct level - if cutoff and cutoff <= level: - break - - if target is not None: - if return_seen: - if target not in pred: - return ([], -1) # No predecessor - return (pred[target], seen[target]) - else: - if target not in pred: - return [] # No predecessor - return pred[target] - else: - if return_seen: - return (pred, seen) - else: - return pred diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/weighted.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/weighted.py deleted file mode 100644 index f8421d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/weighted.py +++ /dev/null @@ -1,2520 +0,0 @@ -""" -Shortest path algorithms for weighted graphs. -""" - -from collections import deque -from heapq import heappop, heappush -from itertools import count - -import networkx as nx -from networkx.algorithms.shortest_paths.generic import _build_paths_from_predecessors - -__all__ = [ - "dijkstra_path", - "dijkstra_path_length", - "bidirectional_dijkstra", - "single_source_dijkstra", - "single_source_dijkstra_path", - "single_source_dijkstra_path_length", - "multi_source_dijkstra", - "multi_source_dijkstra_path", - "multi_source_dijkstra_path_length", - "all_pairs_dijkstra", - "all_pairs_dijkstra_path", - "all_pairs_dijkstra_path_length", - "dijkstra_predecessor_and_distance", - "bellman_ford_path", - "bellman_ford_path_length", - "single_source_bellman_ford", - "single_source_bellman_ford_path", - "single_source_bellman_ford_path_length", - "all_pairs_bellman_ford_path", - "all_pairs_bellman_ford_path_length", - "bellman_ford_predecessor_and_distance", - "negative_edge_cycle", - "find_negative_cycle", - "goldberg_radzik", - "johnson", -] - - -def _weight_function(G, weight): - """Returns a function that returns the weight of an edge. - - The returned function is specifically suitable for input to - functions :func:`_dijkstra` and :func:`_bellman_ford_relaxation`. - - Parameters - ---------- - G : NetworkX graph. - - weight : string or function - If it is callable, `weight` itself is returned. If it is a string, - it is assumed to be the name of the edge attribute that represents - the weight of an edge. In that case, a function is returned that - gets the edge weight according to the specified edge attribute. - - Returns - ------- - function - This function returns a callable that accepts exactly three inputs: - a node, an node adjacent to the first one, and the edge attribute - dictionary for the eedge joining those nodes. That function returns - a number representing the weight of an edge. - - If `G` is a multigraph, and `weight` is not callable, the - minimum edge weight over all parallel edges is returned. If any edge - does not have an attribute with key `weight`, it is assumed to - have weight one. - - """ - if callable(weight): - return weight - # If the weight keyword argument is not callable, we assume it is a - # string representing the edge attribute containing the weight of - # the edge. - if G.is_multigraph(): - return lambda u, v, d: min(attr.get(weight, 1) for attr in d.values()) - return lambda u, v, data: data.get(weight, 1) - - -@nx._dispatchable(edge_attrs="weight") -def dijkstra_path(G, source, target, weight="weight"): - """Returns the shortest weighted path from source to target in G. - - Uses Dijkstra's Method to compute the shortest weighted path - between two nodes in a graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node - - target : node - Ending node - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - path : list - List of nodes in a shortest path. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> print(nx.dijkstra_path(G, 0, 4)) - [0, 1, 2, 3, 4] - - Find edges of shortest path in Multigraph - - >>> G = nx.MultiDiGraph() - >>> G.add_weighted_edges_from([(1, 2, 0.75), (1, 2, 0.5), (2, 3, 0.5), (1, 3, 1.5)]) - >>> nodes = nx.dijkstra_path(G, 1, 3) - >>> edges = nx.utils.pairwise(nodes) - >>> list( - ... (u, v, min(G[u][v], key=lambda k: G[u][v][k].get("weight", 1))) - ... for u, v in edges - ... ) - [(1, 2, 1), (2, 3, 0)] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - The weight function can be used to include node weights. - - >>> def func(u, v, d): - ... node_u_wt = G.nodes[u].get("node_weight", 1) - ... node_v_wt = G.nodes[v].get("node_weight", 1) - ... edge_wt = d.get("weight", 1) - ... return node_u_wt / 2 + node_v_wt / 2 + edge_wt - - In this example we take the average of start and end node - weights of an edge and add it to the weight of the edge. - - The function :func:`single_source_dijkstra` computes both - path and length-of-path if you need both, use that. - - See Also - -------- - bidirectional_dijkstra - bellman_ford_path - single_source_dijkstra - """ - (length, path) = single_source_dijkstra(G, source, target=target, weight=weight) - return path - - -@nx._dispatchable(edge_attrs="weight") -def dijkstra_path_length(G, source, target, weight="weight"): - """Returns the shortest weighted path length in G from source to target. - - Uses Dijkstra's Method to compute the shortest weighted path length - between two nodes in a graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - length : number - Shortest path length. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.dijkstra_path_length(G, 0, 4) - 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - The function :func:`single_source_dijkstra` computes both - path and length-of-path if you need both, use that. - - See Also - -------- - bidirectional_dijkstra - bellman_ford_path_length - single_source_dijkstra - - """ - if source not in G: - raise nx.NodeNotFound(f"Node {source} not found in graph") - if source == target: - return 0 - weight = _weight_function(G, weight) - length = _dijkstra(G, source, weight, target=target) - try: - return length[target] - except KeyError as err: - raise nx.NetworkXNoPath(f"Node {target} not reachable from {source}") from err - - -@nx._dispatchable(edge_attrs="weight") -def single_source_dijkstra_path(G, source, cutoff=None, weight="weight"): - """Find shortest weighted paths in G from a source node. - - Compute shortest path between source and all other reachable - nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - paths : dictionary - Dictionary of shortest path lengths keyed by target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.single_source_dijkstra_path(G, 0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - See Also - -------- - single_source_dijkstra, single_source_bellman_ford - - """ - return multi_source_dijkstra_path(G, {source}, cutoff=cutoff, weight=weight) - - -@nx._dispatchable(edge_attrs="weight") -def single_source_dijkstra_path_length(G, source, cutoff=None, weight="weight"): - """Find shortest weighted path lengths in G from a source node. - - Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - length : dict - Dict keyed by node to shortest path length from source. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.single_source_dijkstra_path_length(G, 0) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - See Also - -------- - single_source_dijkstra, single_source_bellman_ford_path_length - - """ - return multi_source_dijkstra_path_length(G, {source}, cutoff=cutoff, weight=weight) - - -@nx._dispatchable(edge_attrs="weight") -def single_source_dijkstra(G, source, target=None, cutoff=None, weight="weight"): - """Find shortest weighted paths and lengths from a source node. - - Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Uses Dijkstra's algorithm to compute shortest paths and lengths - between a source and all other reachable nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list. - If target is None, paths and lengths to all nodes are computed. - The return value is a tuple of two dictionaries keyed by target nodes. - The first dictionary stores distance to each target node. - The second stores the path to each target node. - If target is not None, returns a tuple (distance, path), where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.single_source_dijkstra(G, 0) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - >>> path[4] - [0, 1, 2, 3, 4] - >>> length, path = nx.single_source_dijkstra(G, 0, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Based on the Python cookbook recipe (119466) at - https://code.activestate.com/recipes/119466/ - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - single_source_dijkstra_path - single_source_dijkstra_path_length - single_source_bellman_ford - """ - return multi_source_dijkstra( - G, {source}, cutoff=cutoff, target=target, weight=weight - ) - - -@nx._dispatchable(edge_attrs="weight") -def multi_source_dijkstra_path(G, sources, cutoff=None, weight="weight"): - """Find shortest weighted paths in G from a given set of source - nodes. - - Compute shortest path between any of the source nodes and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - paths : dictionary - Dictionary of shortest paths keyed by target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.multi_source_dijkstra_path(G, {0, 4}) - >>> path[1] - [0, 1] - >>> path[3] - [4, 3] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra, multi_source_bellman_ford - - """ - length, path = multi_source_dijkstra(G, sources, cutoff=cutoff, weight=weight) - return path - - -@nx._dispatchable(edge_attrs="weight") -def multi_source_dijkstra_path_length(G, sources, cutoff=None, weight="weight"): - """Find shortest weighted path lengths in G from a given set of - source nodes. - - Compute the shortest path length between any of the source nodes and - all other reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - length : dict - Dict keyed by node to shortest path length to nearest source. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.multi_source_dijkstra_path_length(G, {0, 4}) - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 1 - 4: 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra - - """ - if not sources: - raise ValueError("sources must not be empty") - for s in sources: - if s not in G: - raise nx.NodeNotFound(f"Node {s} not found in graph") - weight = _weight_function(G, weight) - return _dijkstra_multisource(G, sources, weight, cutoff=cutoff) - - -@nx._dispatchable(edge_attrs="weight") -def multi_source_dijkstra(G, sources, target=None, cutoff=None, weight="weight"): - """Find shortest weighted paths and lengths from a given set of - source nodes. - - Uses Dijkstra's algorithm to compute the shortest paths and lengths - between one of the source nodes and the given `target`, or all other - reachable nodes if not specified, for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - target : node label, optional - Ending node for path - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list - If target is None, returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from one of the source nodes. - The second stores the path from one of the sources to that node. - If target is not None, returns a tuple of (distance, path) where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.multi_source_dijkstra(G, {0, 4}) - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 1 - 4: 0 - >>> path[1] - [0, 1] - >>> path[3] - [4, 3] - - >>> length, path = nx.multi_source_dijkstra(G, {0, 4}, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Based on the Python cookbook recipe (119466) at - https://code.activestate.com/recipes/119466/ - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra_path - multi_source_dijkstra_path_length - - """ - if not sources: - raise ValueError("sources must not be empty") - for s in sources: - if s not in G: - raise nx.NodeNotFound(f"Node {s} not found in graph") - if target in sources: - return (0, [target]) - weight = _weight_function(G, weight) - paths = {source: [source] for source in sources} # dictionary of paths - dist = _dijkstra_multisource( - G, sources, weight, paths=paths, cutoff=cutoff, target=target - ) - if target is None: - return (dist, paths) - try: - return (dist[target], paths[target]) - except KeyError as err: - raise nx.NetworkXNoPath(f"No path to {target}.") from err - - -def _dijkstra(G, source, weight, pred=None, paths=None, cutoff=None, target=None): - """Uses Dijkstra's algorithm to find shortest weighted paths from a - single source. - - This is a convenience function for :func:`_dijkstra_multisource` - with all the arguments the same, except the keyword argument - `sources` set to ``[source]``. - - """ - return _dijkstra_multisource( - G, [source], weight, pred=pred, paths=paths, cutoff=cutoff, target=target - ) - - -def _dijkstra_multisource( - G, sources, weight, pred=None, paths=None, cutoff=None, target=None -): - """Uses Dijkstra's algorithm to find shortest weighted paths - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty iterable of nodes - Starting nodes for paths. If this is just an iterable containing - a single node, then all paths computed by this function will - start from that node. If there are two or more nodes in this - iterable, the computed paths may begin from any one of the start - nodes. - - weight: function - Function with (u, v, data) input that returns that edge's weight - or None to indicate a hidden edge - - pred: dict of lists, optional(default=None) - dict to store a list of predecessors keyed by that node - If None, predecessors are not stored. - - paths: dict, optional (default=None) - dict to store the path list from source to each node, keyed by node. - If None, paths are not stored. - - target : node label, optional - Ending node for path. Search is halted when target is found. - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - Returns - ------- - distance : dictionary - A mapping from node to shortest distance to that node from one - of the source nodes. - - Raises - ------ - NodeNotFound - If any of `sources` is not in `G`. - - Notes - ----- - The optional predecessor and path dictionaries can be accessed by - the caller through the original pred and paths objects passed - as arguments. No need to explicitly return pred or paths. - - """ - G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) - - push = heappush - pop = heappop - dist = {} # dictionary of final distances - seen = {} - # fringe is heapq with 3-tuples (distance,c,node) - # use the count c to avoid comparing nodes (may not be able to) - c = count() - fringe = [] - for source in sources: - seen[source] = 0 - push(fringe, (0, next(c), source)) - while fringe: - (d, _, v) = pop(fringe) - if v in dist: - continue # already searched this node. - dist[v] = d - if v == target: - break - for u, e in G_succ[v].items(): - cost = weight(v, u, e) - if cost is None: - continue - vu_dist = dist[v] + cost - if cutoff is not None: - if vu_dist > cutoff: - continue - if u in dist: - u_dist = dist[u] - if vu_dist < u_dist: - raise ValueError("Contradictory paths found:", "negative weights?") - elif pred is not None and vu_dist == u_dist: - pred[u].append(v) - elif u not in seen or vu_dist < seen[u]: - seen[u] = vu_dist - push(fringe, (vu_dist, next(c), u)) - if paths is not None: - paths[u] = paths[v] + [u] - if pred is not None: - pred[u] = [v] - elif vu_dist == seen[u]: - if pred is not None: - pred[u].append(v) - - # The optional predecessor and path dictionaries can be accessed - # by the caller via the pred and paths objects passed as arguments. - return dist - - -@nx._dispatchable(edge_attrs="weight") -def dijkstra_predecessor_and_distance(G, source, cutoff=None, weight="weight"): - """Compute weighted shortest path length and predecessors. - - Uses Dijkstra's Method to obtain the shortest weighted paths - and return dictionaries of predecessors for each node and - distance for each node from the `source`. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - pred, distance : dictionaries - Returns two dictionaries representing a list of predecessors - of a node and the distance to each node. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The list of predecessors contains more than one element only when - there are more than one shortest paths to the key node. - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0, 1) - >>> sorted(pred.items()) - [(0, []), (1, [0])] - >>> sorted(dist.items()) - [(0, 0), (1, 1)] - """ - if source not in G: - raise nx.NodeNotFound(f"Node {source} is not found in the graph") - weight = _weight_function(G, weight) - pred = {source: []} # dictionary of predecessors - return (pred, _dijkstra(G, source, weight, pred=pred, cutoff=cutoff)) - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_dijkstra(G, cutoff=None, weight="weight"): - """Find shortest weighted paths and lengths between all nodes. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edge[u][v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Yields - ------ - (node, (distance, path)) : (node obj, (dict, dict)) - Each source node has two associated dicts. The first holds distance - keyed by target and the second holds paths keyed by target. - (See single_source_dijkstra for the source/target node terminology.) - If desired you can apply `dict()` to this function to create a dict - keyed by source node to the two dicts. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> len_path = dict(nx.all_pairs_dijkstra(G)) - >>> len_path[3][0][1] - 2 - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"3 - {node}: {len_path[3][0][node]}") - 3 - 0: 3 - 3 - 1: 2 - 3 - 2: 1 - 3 - 3: 0 - 3 - 4: 1 - >>> len_path[3][1][1] - [3, 2, 1] - >>> for n, (dist, path) in nx.all_pairs_dijkstra(G): - ... print(path[1]) - [0, 1] - [1] - [2, 1] - [3, 2, 1] - [4, 3, 2, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The yielded dicts only have keys for reachable nodes. - """ - for n in G: - dist, path = single_source_dijkstra(G, n, cutoff=cutoff, weight=weight) - yield (n, (dist, path)) - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_dijkstra_path_length(G, cutoff=None, weight="weight"): - """Compute shortest path lengths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - distance : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_dijkstra_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"1 - {node}: {length[1][node]}") - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionary returned only has keys for reachable node pairs. - """ - length = single_source_dijkstra_path_length - for n in G: - yield (n, length(G, n, cutoff=cutoff, weight=weight)) - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_dijkstra_path(G, cutoff=None, weight="weight"): - """Compute shortest paths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Length (sum of edge weights) at which the search is stopped. - If cutoff is provided, only return paths with summed weight <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - paths : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_dijkstra_path(G)) - >>> path[0][4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - floyd_warshall, all_pairs_bellman_ford_path - - """ - path = single_source_dijkstra_path - # TODO This can be trivially parallelized. - for n in G: - yield (n, path(G, n, cutoff=cutoff, weight=weight)) - - -@nx._dispatchable(edge_attrs="weight") -def bellman_ford_predecessor_and_distance( - G, source, target=None, weight="weight", heuristic=False -): - """Compute shortest path lengths and predecessors on shortest paths - in weighted graphs. - - The algorithm has a running time of $O(mn)$ where $n$ is the number of - nodes and $m$ is the number of edges. It is slower than Dijkstra but - can handle negative edge weights. - - If a negative cycle is detected, you can use :func:`find_negative_cycle` - to return the cycle and examine it. Shortest paths are not defined when - a negative cycle exists because once reached, the path can cycle forever - to build up arbitrarily low weights. - - Parameters - ---------- - G : NetworkX graph - The algorithm works for all types of graphs, including directed - graphs and multigraphs. - - source: node label - Starting node for path - - target : node label, optional - Ending node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - heuristic : bool - Determines whether to use a heuristic to early detect negative - cycles at a hopefully negligible cost. - - Returns - ------- - pred, dist : dictionaries - Returns two dictionaries keyed by node to predecessor in the - path and to the distance from the source respectively. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cycle. - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0, 1) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) - >>> G[1][2]["weight"] = -7 - >>> nx.bellman_ford_predecessor_and_distance(G, 0) - Traceback (most recent call last): - ... - networkx.exception.NetworkXUnbounded: Negative cycle detected. - - See Also - -------- - find_negative_cycle - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionaries returned only have keys for nodes reachable from - the source. - - In the case where the (di)graph is not connected, if a component - not containing the source contains a negative (di)cycle, it - will not be detected. - - In NetworkX v2.1 and prior, the source node had predecessor `[None]`. - In NetworkX v2.2 this changed to the source node having predecessor `[]` - """ - if source not in G: - raise nx.NodeNotFound(f"Node {source} is not found in the graph") - weight = _weight_function(G, weight) - if G.is_multigraph(): - if any( - weight(u, v, {k: d}) < 0 - for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True) - ): - raise nx.NetworkXUnbounded("Negative cycle detected.") - else: - if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): - raise nx.NetworkXUnbounded("Negative cycle detected.") - - dist = {source: 0} - pred = {source: []} - - if len(G) == 1: - return pred, dist - - weight = _weight_function(G, weight) - - dist = _bellman_ford( - G, [source], weight, pred=pred, dist=dist, target=target, heuristic=heuristic - ) - return (pred, dist) - - -def _bellman_ford( - G, - source, - weight, - pred=None, - paths=None, - dist=None, - target=None, - heuristic=True, -): - """Calls relaxation loop for Bellman–Ford algorithm and builds paths - - This is an implementation of the SPFA variant. - See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm - - Parameters - ---------- - G : NetworkX graph - - source: list - List of source nodes. The shortest path from any of the source - nodes will be found if multiple sources are provided. - - weight : function - The weight of an edge is the value returned by the function. The - function must accept exactly three positional arguments: the two - endpoints of an edge and the dictionary of edge attributes for - that edge. The function must return a number. - - pred: dict of lists, optional (default=None) - dict to store a list of predecessors keyed by that node - If None, predecessors are not stored - - paths: dict, optional (default=None) - dict to store the path list from source to each node, keyed by node - If None, paths are not stored - - dist: dict, optional (default=None) - dict to store distance from source to the keyed node - If None, returned dist dict contents default to 0 for every node in the - source list - - target: node label, optional - Ending node for path. Path lengths to other destinations may (and - probably will) be incorrect. - - heuristic : bool - Determines whether to use a heuristic to early detect negative - cycles at a hopefully negligible cost. - - Returns - ------- - dist : dict - Returns a dict keyed by node to the distance from the source. - Dicts for paths and pred are in the mutated input dicts by those names. - - Raises - ------ - NodeNotFound - If any of `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cycle - """ - if pred is None: - pred = {v: [] for v in source} - - if dist is None: - dist = {v: 0 for v in source} - - negative_cycle_found = _inner_bellman_ford( - G, - source, - weight, - pred, - dist, - heuristic, - ) - if negative_cycle_found is not None: - raise nx.NetworkXUnbounded("Negative cycle detected.") - - if paths is not None: - sources = set(source) - dsts = [target] if target is not None else pred - for dst in dsts: - gen = _build_paths_from_predecessors(sources, dst, pred) - paths[dst] = next(gen) - - return dist - - -def _inner_bellman_ford( - G, - sources, - weight, - pred, - dist=None, - heuristic=True, -): - """Inner Relaxation loop for Bellman–Ford algorithm. - - This is an implementation of the SPFA variant. - See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm - - Parameters - ---------- - G : NetworkX graph - - source: list - List of source nodes. The shortest path from any of the source - nodes will be found if multiple sources are provided. - - weight : function - The weight of an edge is the value returned by the function. The - function must accept exactly three positional arguments: the two - endpoints of an edge and the dictionary of edge attributes for - that edge. The function must return a number. - - pred: dict of lists - dict to store a list of predecessors keyed by that node - - dist: dict, optional (default=None) - dict to store distance from source to the keyed node - If None, returned dist dict contents default to 0 for every node in the - source list - - heuristic : bool - Determines whether to use a heuristic to early detect negative - cycles at a hopefully negligible cost. - - Returns - ------- - node or None - Return a node `v` where processing discovered a negative cycle. - If no negative cycle found, return None. - - Raises - ------ - NodeNotFound - If any of `source` is not in `G`. - """ - for s in sources: - if s not in G: - raise nx.NodeNotFound(f"Source {s} not in G") - - if pred is None: - pred = {v: [] for v in sources} - - if dist is None: - dist = {v: 0 for v in sources} - - # Heuristic Storage setup. Note: use None because nodes cannot be None - nonexistent_edge = (None, None) - pred_edge = {v: None for v in sources} - recent_update = {v: nonexistent_edge for v in sources} - - G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) - inf = float("inf") - n = len(G) - - count = {} - q = deque(sources) - in_q = set(sources) - while q: - u = q.popleft() - in_q.remove(u) - - # Skip relaxations if any of the predecessors of u is in the queue. - if all(pred_u not in in_q for pred_u in pred[u]): - dist_u = dist[u] - for v, e in G_succ[u].items(): - dist_v = dist_u + weight(u, v, e) - - if dist_v < dist.get(v, inf): - # In this conditional branch we are updating the path with v. - # If it happens that some earlier update also added node v - # that implies the existence of a negative cycle since - # after the update node v would lie on the update path twice. - # The update path is stored up to one of the source nodes, - # therefore u is always in the dict recent_update - if heuristic: - if v in recent_update[u]: - # Negative cycle found! - pred[v].append(u) - return v - - # Transfer the recent update info from u to v if the - # same source node is the head of the update path. - # If the source node is responsible for the cost update, - # then clear the history and use it instead. - if v in pred_edge and pred_edge[v] == u: - recent_update[v] = recent_update[u] - else: - recent_update[v] = (u, v) - - if v not in in_q: - q.append(v) - in_q.add(v) - count_v = count.get(v, 0) + 1 - if count_v == n: - # Negative cycle found! - return v - - count[v] = count_v - dist[v] = dist_v - pred[v] = [u] - pred_edge[v] = u - - elif dist.get(v) is not None and dist_v == dist.get(v): - pred[v].append(u) - - # successfully found shortest_path. No negative cycles found. - return None - - -@nx._dispatchable(edge_attrs="weight") -def bellman_ford_path(G, source, target, weight="weight"): - """Returns the shortest path from source to target in a weighted graph G. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node - - target : node - Ending node - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - path : list - List of nodes in a shortest path. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.bellman_ford_path(G, 0, 4) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - dijkstra_path, bellman_ford_path_length - """ - length, path = single_source_bellman_ford(G, source, target=target, weight=weight) - return path - - -@nx._dispatchable(edge_attrs="weight") -def bellman_ford_path_length(G, source, target, weight="weight"): - """Returns the shortest path length from source to target - in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length : number - Shortest path length. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.bellman_ford_path_length(G, 0, 4) - 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - dijkstra_path_length, bellman_ford_path - """ - if source == target: - if source not in G: - raise nx.NodeNotFound(f"Node {source} not found in graph") - return 0 - - weight = _weight_function(G, weight) - - length = _bellman_ford(G, [source], weight, target=target) - - try: - return length[target] - except KeyError as err: - raise nx.NetworkXNoPath(f"node {target} not reachable from {source}") from err - - -@nx._dispatchable(edge_attrs="weight") -def single_source_bellman_ford_path(G, source, weight="weight"): - """Compute shortest path between source and all other reachable - nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - paths : dictionary - Dictionary of shortest path lengths keyed by target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.single_source_bellman_ford_path(G, 0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra, single_source_bellman_ford - - """ - (length, path) = single_source_bellman_ford(G, source, weight=weight) - return path - - -@nx._dispatchable(edge_attrs="weight") -def single_source_bellman_ford_path_length(G, source, weight="weight"): - """Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length : dictionary - Dictionary of shortest path length keyed by target - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.single_source_bellman_ford_path_length(G, 0) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra, single_source_bellman_ford - - """ - weight = _weight_function(G, weight) - return _bellman_ford(G, [source], weight) - - -@nx._dispatchable(edge_attrs="weight") -def single_source_bellman_ford(G, source, target=None, weight="weight"): - """Compute shortest paths and lengths in a weighted graph G. - - Uses Bellman-Ford algorithm for shortest paths. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list - If target is None, returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from one of the source nodes. - The second stores the path from one of the sources to that node. - If target is not None, returns a tuple of (distance, path) where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.single_source_bellman_ford(G, 0) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"{node}: {length[node]}") - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - >>> path[4] - [0, 1, 2, 3, 4] - >>> length, path = nx.single_source_bellman_ford(G, 0, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra - single_source_bellman_ford_path - single_source_bellman_ford_path_length - """ - if source == target: - if source not in G: - raise nx.NodeNotFound(f"Node {source} is not found in the graph") - return (0, [source]) - - weight = _weight_function(G, weight) - - paths = {source: [source]} # dictionary of paths - dist = _bellman_ford(G, [source], weight, paths=paths, target=target) - if target is None: - return (dist, paths) - try: - return (dist[target], paths[target]) - except KeyError as err: - msg = f"Node {target} not reachable from {source}" - raise nx.NetworkXNoPath(msg) from err - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_bellman_ford_path_length(G, weight="weight"): - """Compute shortest path lengths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_bellman_ford_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print(f"1 - {node}: {length[1][node]}") - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionary returned only has keys for reachable node pairs. - """ - length = single_source_bellman_ford_path_length - for n in G: - yield (n, dict(length(G, n, weight=weight))) - - -@nx._dispatchable(edge_attrs="weight") -def all_pairs_bellman_ford_path(G, weight="weight"): - """Compute shortest paths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function (default="weight") - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - paths : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_bellman_ford_path(G)) - >>> path[0][4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - floyd_warshall, all_pairs_dijkstra_path - - """ - path = single_source_bellman_ford_path - for n in G: - yield (n, path(G, n, weight=weight)) - - -@nx._dispatchable(edge_attrs="weight") -def goldberg_radzik(G, source, weight="weight"): - """Compute shortest path lengths and predecessors on shortest paths - in weighted graphs. - - The algorithm has a running time of $O(mn)$ where $n$ is the number of - nodes and $m$ is the number of edges. It is slower than Dijkstra but - can handle negative edge weights. - - Parameters - ---------- - G : NetworkX graph - The algorithm works for all types of graphs, including directed - graphs and multigraphs. - - source: node label - Starting node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - pred, dist : dictionaries - Returns two dictionaries keyed by node to predecessor in the - path and to the distance from the source respectively. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cycle. - - As of NetworkX v3.2, a zero weight cycle is no longer - incorrectly reported as a negative weight cycle. - - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> pred, dist = nx.goldberg_radzik(G, 0) - >>> sorted(pred.items()) - [(0, None), (1, 0), (2, 1), (3, 2), (4, 3)] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) - >>> G[1][2]["weight"] = -7 - >>> nx.goldberg_radzik(G, 0) - Traceback (most recent call last): - ... - networkx.exception.NetworkXUnbounded: Negative cycle detected. - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionaries returned only have keys for nodes reachable from - the source. - - In the case where the (di)graph is not connected, if a component - not containing the source contains a negative (di)cycle, it - will not be detected. - - """ - if source not in G: - raise nx.NodeNotFound(f"Node {source} is not found in the graph") - weight = _weight_function(G, weight) - if G.is_multigraph(): - if any( - weight(u, v, {k: d}) < 0 - for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True) - ): - raise nx.NetworkXUnbounded("Negative cycle detected.") - else: - if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): - raise nx.NetworkXUnbounded("Negative cycle detected.") - - if len(G) == 1: - return {source: None}, {source: 0} - - G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) - - inf = float("inf") - d = {u: inf for u in G} - d[source] = 0 - pred = {source: None} - - def topo_sort(relabeled): - """Topologically sort nodes relabeled in the previous round and detect - negative cycles. - """ - # List of nodes to scan in this round. Denoted by A in Goldberg and - # Radzik's paper. - to_scan = [] - # In the DFS in the loop below, neg_count records for each node the - # number of edges of negative reduced costs on the path from a DFS root - # to the node in the DFS forest. The reduced cost of an edge (u, v) is - # defined as d[u] + weight[u][v] - d[v]. - # - # neg_count also doubles as the DFS visit marker array. - neg_count = {} - for u in relabeled: - # Skip visited nodes. - if u in neg_count: - continue - d_u = d[u] - # Skip nodes without out-edges of negative reduced costs. - if all(d_u + weight(u, v, e) >= d[v] for v, e in G_succ[u].items()): - continue - # Nonrecursive DFS that inserts nodes reachable from u via edges of - # nonpositive reduced costs into to_scan in (reverse) topological - # order. - stack = [(u, iter(G_succ[u].items()))] - in_stack = {u} - neg_count[u] = 0 - while stack: - u, it = stack[-1] - try: - v, e = next(it) - except StopIteration: - to_scan.append(u) - stack.pop() - in_stack.remove(u) - continue - t = d[u] + weight(u, v, e) - d_v = d[v] - if t < d_v: - is_neg = t < d_v - d[v] = t - pred[v] = u - if v not in neg_count: - neg_count[v] = neg_count[u] + int(is_neg) - stack.append((v, iter(G_succ[v].items()))) - in_stack.add(v) - elif v in in_stack and neg_count[u] + int(is_neg) > neg_count[v]: - # (u, v) is a back edge, and the cycle formed by the - # path v to u and (u, v) contains at least one edge of - # negative reduced cost. The cycle must be of negative - # cost. - raise nx.NetworkXUnbounded("Negative cycle detected.") - to_scan.reverse() - return to_scan - - def relax(to_scan): - """Relax out-edges of relabeled nodes.""" - relabeled = set() - # Scan nodes in to_scan in topological order and relax incident - # out-edges. Add the relabled nodes to labeled. - for u in to_scan: - d_u = d[u] - for v, e in G_succ[u].items(): - w_e = weight(u, v, e) - if d_u + w_e < d[v]: - d[v] = d_u + w_e - pred[v] = u - relabeled.add(v) - return relabeled - - # Set of nodes relabled in the last round of scan operations. Denoted by B - # in Goldberg and Radzik's paper. - relabeled = {source} - - while relabeled: - to_scan = topo_sort(relabeled) - relabeled = relax(to_scan) - - d = {u: d[u] for u in pred} - return pred, d - - -@nx._dispatchable(edge_attrs="weight") -def negative_edge_cycle(G, weight="weight", heuristic=True): - """Returns True if there exists a negative edge cycle anywhere in G. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - heuristic : bool - Determines whether to use a heuristic to early detect negative - cycles at a negligible cost. In case of graphs with a negative cycle, - the performance of detection increases by at least an order of magnitude. - - Returns - ------- - negative_cycle : bool - True if a negative edge cycle exists, otherwise False. - - Examples - -------- - >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) - >>> print(nx.negative_edge_cycle(G)) - False - >>> G[1][2]["weight"] = -7 - >>> print(nx.negative_edge_cycle(G)) - True - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - This algorithm uses bellman_ford_predecessor_and_distance() but finds - negative cycles on any component by first adding a new node connected to - every node, and starting bellman_ford_predecessor_and_distance on that - node. It then removes that extra node. - """ - if G.size() == 0: - return False - - # find unused node to use temporarily - newnode = -1 - while newnode in G: - newnode -= 1 - # connect it to all nodes - G.add_edges_from([(newnode, n) for n in G]) - - try: - bellman_ford_predecessor_and_distance( - G, newnode, weight=weight, heuristic=heuristic - ) - except nx.NetworkXUnbounded: - return True - finally: - G.remove_node(newnode) - return False - - -@nx._dispatchable(edge_attrs="weight") -def find_negative_cycle(G, source, weight="weight"): - """Returns a cycle with negative total weight if it exists. - - Bellman-Ford is used to find shortest_paths. That algorithm - stops if there exists a negative cycle. This algorithm - picks up from there and returns the found negative cycle. - - The cycle consists of a list of nodes in the cycle order. The last - node equals the first to make it a cycle. - You can look up the edge weights in the original graph. In the case - of multigraphs the relevant edge is the minimal weight edge between - the nodes in the 2-tuple. - - If the graph has no negative cycle, a NetworkXError is raised. - - Parameters - ---------- - G : NetworkX graph - - source: node label - The search for the negative cycle will start from this node. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from( - ... [(0, 1, 2), (1, 2, 2), (2, 0, 1), (1, 4, 2), (4, 0, -5)] - ... ) - >>> nx.find_negative_cycle(G, 0) - [4, 0, 1, 4] - - Returns - ------- - cycle : list - A list of nodes in the order of the cycle found. The last node - equals the first to indicate a cycle. - - Raises - ------ - NetworkXError - If no negative cycle is found. - """ - weight = _weight_function(G, weight) - pred = {source: []} - - v = _inner_bellman_ford(G, [source], weight, pred=pred) - if v is None: - raise nx.NetworkXError("No negative cycles detected.") - - # negative cycle detected... find it - neg_cycle = [] - stack = [(v, list(pred[v]))] - seen = {v} - while stack: - node, preds = stack[-1] - if v in preds: - # found the cycle - neg_cycle.extend([node, v]) - neg_cycle = list(reversed(neg_cycle)) - return neg_cycle - - if preds: - nbr = preds.pop() - if nbr not in seen: - stack.append((nbr, list(pred[nbr]))) - neg_cycle.append(node) - seen.add(nbr) - else: - stack.pop() - if neg_cycle: - neg_cycle.pop() - else: - if v in G[v] and weight(G, v, v) < 0: - return [v, v] - # should not reach here - raise nx.NetworkXError("Negative cycle is detected but not found") - # should not get here... - msg = "negative cycle detected but not identified" - raise nx.NetworkXUnbounded(msg) - - -@nx._dispatchable(edge_attrs="weight") -def bidirectional_dijkstra(G, source, target, weight="weight"): - r"""Dijkstra's algorithm for shortest paths using bidirectional search. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node. - - target : node - Ending node. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - Returns - ------- - length, path : number and list - length is the distance from source to target. - path is a list of nodes on a path from source to target. - - Raises - ------ - NodeNotFound - If `source` or `target` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.bidirectional_dijkstra(G, 0, 4) - >>> print(length) - 4 - >>> print(path) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - In practice bidirectional Dijkstra is much more than twice as fast as - ordinary Dijkstra. - - Ordinary Dijkstra expands nodes in a sphere-like manner from the - source. The radius of this sphere will eventually be the length - of the shortest path. Bidirectional Dijkstra will expand nodes - from both the source and the target, making two spheres of half - this radius. Volume of the first sphere is `\pi*r*r` while the - others are `2*\pi*r/2*r/2`, making up half the volume. - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - shortest_path - shortest_path_length - """ - if source not in G: - raise nx.NodeNotFound(f"Source {source} is not in G") - - if target not in G: - raise nx.NodeNotFound(f"Target {target} is not in G") - - if source == target: - return (0, [source]) - - weight = _weight_function(G, weight) - push = heappush - pop = heappop - # Init: [Forward, Backward] - dists = [{}, {}] # dictionary of final distances - paths = [{source: [source]}, {target: [target]}] # dictionary of paths - fringe = [[], []] # heap of (distance, node) for choosing node to expand - seen = [{source: 0}, {target: 0}] # dict of distances to seen nodes - c = count() - # initialize fringe heap - push(fringe[0], (0, next(c), source)) - push(fringe[1], (0, next(c), target)) - # neighs for extracting correct neighbor information - if G.is_directed(): - neighs = [G._succ, G._pred] - else: - neighs = [G._adj, G._adj] - # variables to hold shortest discovered path - # finaldist = 1e30000 - finalpath = [] - dir = 1 - while fringe[0] and fringe[1]: - # choose direction - # dir == 0 is forward direction and dir == 1 is back - dir = 1 - dir - # extract closest to expand - (dist, _, v) = pop(fringe[dir]) - if v in dists[dir]: - # Shortest path to v has already been found - continue - # update distance - dists[dir][v] = dist # equal to seen[dir][v] - if v in dists[1 - dir]: - # if we have scanned v in both directions we are done - # we have now discovered the shortest path - return (finaldist, finalpath) - - for w, d in neighs[dir][v].items(): - # weight(v, w, d) for forward and weight(w, v, d) for back direction - cost = weight(v, w, d) if dir == 0 else weight(w, v, d) - if cost is None: - continue - vwLength = dists[dir][v] + cost - if w in dists[dir]: - if vwLength < dists[dir][w]: - raise ValueError("Contradictory paths found: negative weights?") - elif w not in seen[dir] or vwLength < seen[dir][w]: - # relaxing - seen[dir][w] = vwLength - push(fringe[dir], (vwLength, next(c), w)) - paths[dir][w] = paths[dir][v] + [w] - if w in seen[0] and w in seen[1]: - # see if this path is better than the already - # discovered shortest path - totaldist = seen[0][w] + seen[1][w] - if finalpath == [] or finaldist > totaldist: - finaldist = totaldist - revpath = paths[1][w][:] - revpath.reverse() - finalpath = paths[0][w] + revpath[1:] - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") - - -@nx._dispatchable(edge_attrs="weight") -def johnson(G, weight="weight"): - r"""Uses Johnson's Algorithm to compute shortest paths. - - Johnson's Algorithm finds a shortest path between each pair of - nodes in a weighted graph even if negative weights are present. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance : dictionary - Dictionary, keyed by source and target, of shortest paths. - - Examples - -------- - >>> graph = nx.DiGraph() - >>> graph.add_weighted_edges_from( - ... [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)] - ... ) - >>> paths = nx.johnson(graph, weight="weight") - >>> paths["0"]["2"] - ['0', '1', '2'] - - Notes - ----- - Johnson's algorithm is suitable even for graphs with negative weights. It - works by using the Bellman–Ford algorithm to compute a transformation of - the input graph that removes all negative weights, allowing Dijkstra's - algorithm to be used on the transformed graph. - - The time complexity of this algorithm is $O(n^2 \log n + n m)$, - where $n$ is the number of nodes and $m$ the number of edges in the - graph. For dense graphs, this may be faster than the Floyd–Warshall - algorithm. - - See Also - -------- - floyd_warshall_predecessor_and_distance - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - all_pairs_dijkstra_path - bellman_ford_predecessor_and_distance - all_pairs_bellman_ford_path - all_pairs_bellman_ford_path_length - - """ - dist = {v: 0 for v in G} - pred = {v: [] for v in G} - weight = _weight_function(G, weight) - - # Calculate distance of shortest paths - dist_bellman = _bellman_ford(G, list(G), weight, pred=pred, dist=dist) - - # Update the weight function to take into account the Bellman--Ford - # relaxation distances. - def new_weight(u, v, d): - return weight(u, v, d) + dist_bellman[u] - dist_bellman[v] - - def dist_path(v): - paths = {v: [v]} - _dijkstra(G, v, new_weight, paths=paths) - return paths - - return {v: dist_path(v) for v in G} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/similarity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/similarity.py deleted file mode 100644 index 3c601a7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/similarity.py +++ /dev/null @@ -1,1780 +0,0 @@ -"""Functions measuring similarity using graph edit distance. - -The graph edit distance is the number of edge/node changes needed -to make two graphs isomorphic. - -The default algorithm/implementation is sub-optimal for some graphs. -The problem of finding the exact Graph Edit Distance (GED) is NP-hard -so it is often slow. If the simple interface `graph_edit_distance` -takes too long for your graph, try `optimize_graph_edit_distance` -and/or `optimize_edit_paths`. - -At the same time, I encourage capable people to investigate -alternative GED algorithms, in order to improve the choices available. -""" - -import math -import time -import warnings -from dataclasses import dataclass -from itertools import product - -import networkx as nx -from networkx.utils import np_random_state - -__all__ = [ - "graph_edit_distance", - "optimal_edit_paths", - "optimize_graph_edit_distance", - "optimize_edit_paths", - "simrank_similarity", - "panther_similarity", - "generate_random_paths", -] - - -def debug_print(*args, **kwargs): - print(*args, **kwargs) - - -@nx._dispatchable( - graphs={"G1": 0, "G2": 1}, preserve_edge_attrs=True, preserve_node_attrs=True -) -def graph_edit_distance( - G1, - G2, - node_match=None, - edge_match=None, - node_subst_cost=None, - node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, - edge_del_cost=None, - edge_ins_cost=None, - roots=None, - upper_bound=None, - timeout=None, -): - """Returns GED (graph edit distance) between graphs G1 and G2. - - Graph edit distance is a graph similarity measure analogous to - Levenshtein distance for strings. It is defined as minimum cost - of edit path (sequence of node and edge edit operations) - transforming graph G1 to graph isomorphic to G2. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - roots : 2-tuple - Tuple where first element is a node in G1 and the second - is a node in G2. - These nodes are forced to be matched in the comparison to - allow comparison between rooted graphs. - - upper_bound : numeric - Maximum edit distance to consider. Return None if no edit - distance under or equal to upper_bound exists. - - timeout : numeric - Maximum number of seconds to execute. - After timeout is met, the current best GED is returned. - - Examples - -------- - >>> G1 = nx.cycle_graph(6) - >>> G2 = nx.wheel_graph(7) - >>> nx.graph_edit_distance(G1, G2) - 7.0 - - >>> G1 = nx.star_graph(5) - >>> G2 = nx.star_graph(5) - >>> nx.graph_edit_distance(G1, G2, roots=(0, 0)) - 0.0 - >>> nx.graph_edit_distance(G1, G2, roots=(1, 0)) - 8.0 - - See Also - -------- - optimal_edit_paths, optimize_graph_edit_distance, - - is_isomorphic: test for graph edit distance of 0 - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - bestcost = None - for _, _, cost in optimize_edit_paths( - G1, - G2, - node_match, - edge_match, - node_subst_cost, - node_del_cost, - node_ins_cost, - edge_subst_cost, - edge_del_cost, - edge_ins_cost, - upper_bound, - True, - roots, - timeout, - ): - # assert bestcost is None or cost < bestcost - bestcost = cost - return bestcost - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}) -def optimal_edit_paths( - G1, - G2, - node_match=None, - edge_match=None, - node_subst_cost=None, - node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, - edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None, -): - """Returns all minimum-cost edit paths transforming G1 to G2. - - Graph edit path is a sequence of node and edge edit operations - transforming graph G1 to graph isomorphic to G2. Edit operations - include substitutions, deletions, and insertions. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - Returns - ------- - edit_paths : list of tuples (node_edit_path, edge_edit_path) - - node_edit_path : list of tuples ``(u, v)`` indicating node transformations - between `G1` and `G2`. ``u`` is `None` for insertion, ``v`` is `None` - for deletion. - - edge_edit_path : list of tuples ``((u1, v1), (u2, v2))`` indicating edge - transformations between `G1` and `G2`. ``(None, (u2,v2))`` for insertion - and ``((u1,v1), None)`` for deletion. - - cost : numeric - Optimal edit path cost (graph edit distance). When the cost - is zero, it indicates that `G1` and `G2` are isomorphic. - - Examples - -------- - >>> G1 = nx.cycle_graph(4) - >>> G2 = nx.wheel_graph(5) - >>> paths, cost = nx.optimal_edit_paths(G1, G2) - >>> len(paths) - 40 - >>> cost - 5.0 - - Notes - ----- - To transform `G1` into a graph isomorphic to `G2`, apply the node - and edge edits in the returned ``edit_paths``. - In the case of isomorphic graphs, the cost is zero, and the paths - represent different isomorphic mappings (isomorphisms). That is, the - edits involve renaming nodes and edges to match the structure of `G2`. - - See Also - -------- - graph_edit_distance, optimize_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - paths = [] - bestcost = None - for vertex_path, edge_path, cost in optimize_edit_paths( - G1, - G2, - node_match, - edge_match, - node_subst_cost, - node_del_cost, - node_ins_cost, - edge_subst_cost, - edge_del_cost, - edge_ins_cost, - upper_bound, - False, - ): - # assert bestcost is None or cost <= bestcost - if bestcost is not None and cost < bestcost: - paths = [] - paths.append((vertex_path, edge_path)) - bestcost = cost - return paths, bestcost - - -@nx._dispatchable(graphs={"G1": 0, "G2": 1}) -def optimize_graph_edit_distance( - G1, - G2, - node_match=None, - edge_match=None, - node_subst_cost=None, - node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, - edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None, -): - """Returns consecutive approximations of GED (graph edit distance) - between graphs G1 and G2. - - Graph edit distance is a graph similarity measure analogous to - Levenshtein distance for strings. It is defined as minimum cost - of edit path (sequence of node and edge edit operations) - transforming graph G1 to graph isomorphic to G2. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - Returns - ------- - Generator of consecutive approximations of graph edit distance. - - Examples - -------- - >>> G1 = nx.cycle_graph(6) - >>> G2 = nx.wheel_graph(7) - >>> for v in nx.optimize_graph_edit_distance(G1, G2): - ... minv = v - >>> minv - 7.0 - - See Also - -------- - graph_edit_distance, optimize_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - """ - for _, _, cost in optimize_edit_paths( - G1, - G2, - node_match, - edge_match, - node_subst_cost, - node_del_cost, - node_ins_cost, - edge_subst_cost, - edge_del_cost, - edge_ins_cost, - upper_bound, - True, - ): - yield cost - - -@nx._dispatchable( - graphs={"G1": 0, "G2": 1}, preserve_edge_attrs=True, preserve_node_attrs=True -) -def optimize_edit_paths( - G1, - G2, - node_match=None, - edge_match=None, - node_subst_cost=None, - node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, - edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None, - strictly_decreasing=True, - roots=None, - timeout=None, -): - """GED (graph edit distance) calculation: advanced interface. - - Graph edit path is a sequence of node and edge edit operations - transforming graph G1 to graph isomorphic to G2. Edit operations - include substitutions, deletions, and insertions. - - Graph edit distance is defined as minimum cost of edit path. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - strictly_decreasing : bool - If True, return consecutive approximations of strictly - decreasing cost. Otherwise, return all edit paths of cost - less than or equal to the previous minimum cost. - - roots : 2-tuple - Tuple where first element is a node in G1 and the second - is a node in G2. - These nodes are forced to be matched in the comparison to - allow comparison between rooted graphs. - - timeout : numeric - Maximum number of seconds to execute. - After timeout is met, the current best GED is returned. - - Returns - ------- - Generator of tuples (node_edit_path, edge_edit_path, cost) - node_edit_path : list of tuples (u, v) - edge_edit_path : list of tuples ((u1, v1), (u2, v2)) - cost : numeric - - See Also - -------- - graph_edit_distance, optimize_graph_edit_distance, optimal_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - # TODO: support DiGraph - - import numpy as np - import scipy as sp - - @dataclass - class CostMatrix: - C: ... - lsa_row_ind: ... - lsa_col_ind: ... - ls: ... - - def make_CostMatrix(C, m, n): - # assert(C.shape == (m + n, m + n)) - lsa_row_ind, lsa_col_ind = sp.optimize.linear_sum_assignment(C) - - # Fixup dummy assignments: - # each substitution i<->j should have dummy assignment m+j<->n+i - # NOTE: fast reduce of Cv relies on it - # Create masks for substitution and dummy indices - is_subst = (lsa_row_ind < m) & (lsa_col_ind < n) - is_dummy = (lsa_row_ind >= m) & (lsa_col_ind >= n) - - # Map dummy assignments to the correct indices - lsa_row_ind[is_dummy] = lsa_col_ind[is_subst] + m - lsa_col_ind[is_dummy] = lsa_row_ind[is_subst] + n - - return CostMatrix( - C, lsa_row_ind, lsa_col_ind, C[lsa_row_ind, lsa_col_ind].sum() - ) - - def extract_C(C, i, j, m, n): - # assert(C.shape == (m + n, m + n)) - row_ind = [k in i or k - m in j for k in range(m + n)] - col_ind = [k in j or k - n in i for k in range(m + n)] - return C[row_ind, :][:, col_ind] - - def reduce_C(C, i, j, m, n): - # assert(C.shape == (m + n, m + n)) - row_ind = [k not in i and k - m not in j for k in range(m + n)] - col_ind = [k not in j and k - n not in i for k in range(m + n)] - return C[row_ind, :][:, col_ind] - - def reduce_ind(ind, i): - # assert set(ind) == set(range(len(ind))) - rind = ind[[k not in i for k in ind]] - for k in set(i): - rind[rind >= k] -= 1 - return rind - - def match_edges(u, v, pending_g, pending_h, Ce, matched_uv=None): - """ - Parameters: - u, v: matched vertices, u=None or v=None for - deletion/insertion - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_uv: partial vertex edit path - list of tuples (u, v) of previously matched vertex - mappings u<->v, u=None or v=None for - deletion/insertion - - Returns: - list of (i, j): indices of edge mappings g<->h - localCe: local CostMatrix of edge mappings - (basically submatrix of Ce at cross of rows i, cols j) - """ - M = len(pending_g) - N = len(pending_h) - # assert Ce.C.shape == (M + N, M + N) - - # only attempt to match edges after one node match has been made - # this will stop self-edges on the first node being automatically deleted - # even when a substitution is the better option - if matched_uv is None or len(matched_uv) == 0: - g_ind = [] - h_ind = [] - else: - g_ind = [ - i - for i in range(M) - if pending_g[i][:2] == (u, u) - or any( - pending_g[i][:2] in ((p, u), (u, p), (p, p)) for p, q in matched_uv - ) - ] - h_ind = [ - j - for j in range(N) - if pending_h[j][:2] == (v, v) - or any( - pending_h[j][:2] in ((q, v), (v, q), (q, q)) for p, q in matched_uv - ) - ] - - m = len(g_ind) - n = len(h_ind) - - if m or n: - C = extract_C(Ce.C, g_ind, h_ind, M, N) - # assert C.shape == (m + n, m + n) - - # Forbid structurally invalid matches - # NOTE: inf remembered from Ce construction - for k, i in enumerate(g_ind): - g = pending_g[i][:2] - for l, j in enumerate(h_ind): - h = pending_h[j][:2] - if nx.is_directed(G1) or nx.is_directed(G2): - if any( - g == (p, u) and h == (q, v) or g == (u, p) and h == (v, q) - for p, q in matched_uv - ): - continue - else: - if any( - g in ((p, u), (u, p)) and h in ((q, v), (v, q)) - for p, q in matched_uv - ): - continue - if g == (u, u) or any(g == (p, p) for p, q in matched_uv): - continue - if h == (v, v) or any(h == (q, q) for p, q in matched_uv): - continue - C[k, l] = inf - - localCe = make_CostMatrix(C, m, n) - ij = [ - ( - g_ind[k] if k < m else M + h_ind[l], - h_ind[l] if l < n else N + g_ind[k], - ) - for k, l in zip(localCe.lsa_row_ind, localCe.lsa_col_ind) - if k < m or l < n - ] - - else: - ij = [] - localCe = CostMatrix(np.empty((0, 0)), [], [], 0) - - return ij, localCe - - def reduce_Ce(Ce, ij, m, n): - if len(ij): - i, j = zip(*ij) - m_i = m - sum(1 for t in i if t < m) - n_j = n - sum(1 for t in j if t < n) - return make_CostMatrix(reduce_C(Ce.C, i, j, m, n), m_i, n_j) - return Ce - - def get_edit_ops( - matched_uv, pending_u, pending_v, Cv, pending_g, pending_h, Ce, matched_cost - ): - """ - Parameters: - matched_uv: partial vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - pending_u, pending_v: lists of vertices not yet mapped - Cv: CostMatrix of pending vertex mappings - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_cost: cost of partial edit path - - Returns: - sequence of - (i, j): indices of vertex mapping u<->v - Cv_ij: reduced CostMatrix of pending vertex mappings - (basically Cv with row i, col j removed) - list of (x, y): indices of edge mappings g<->h - Ce_xy: reduced CostMatrix of pending edge mappings - (basically Ce with rows x, cols y removed) - cost: total cost of edit operation - NOTE: most promising ops first - """ - m = len(pending_u) - n = len(pending_v) - # assert Cv.C.shape == (m + n, m + n) - - # 1) a vertex mapping from optimal linear sum assignment - i, j = min( - (k, l) for k, l in zip(Cv.lsa_row_ind, Cv.lsa_col_ind) if k < m or l < n - ) - xy, localCe = match_edges( - pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, - pending_h, - Ce, - matched_uv, - ) - Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) - # assert Ce.ls <= localCe.ls + Ce_xy.ls - if prune(matched_cost + Cv.ls + localCe.ls + Ce_xy.ls): - pass - else: - # get reduced Cv efficiently - Cv_ij = CostMatrix( - reduce_C(Cv.C, (i,), (j,), m, n), - reduce_ind(Cv.lsa_row_ind, (i, m + j)), - reduce_ind(Cv.lsa_col_ind, (j, n + i)), - Cv.ls - Cv.C[i, j], - ) - yield (i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls - - # 2) other candidates, sorted by lower-bound cost estimate - other = [] - fixed_i, fixed_j = i, j - if m <= n: - candidates = ( - (t, fixed_j) - for t in range(m + n) - if t != fixed_i and (t < m or t == m + fixed_j) - ) - else: - candidates = ( - (fixed_i, t) - for t in range(m + n) - if t != fixed_j and (t < n or t == n + fixed_i) - ) - for i, j in candidates: - if prune(matched_cost + Cv.C[i, j] + Ce.ls): - continue - Cv_ij = make_CostMatrix( - reduce_C(Cv.C, (i,), (j,), m, n), - m - 1 if i < m else m, - n - 1 if j < n else n, - ) - # assert Cv.ls <= Cv.C[i, j] + Cv_ij.ls - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + Ce.ls): - continue - xy, localCe = match_edges( - pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, - pending_h, - Ce, - matched_uv, - ) - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls): - continue - Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) - # assert Ce.ls <= localCe.ls + Ce_xy.ls - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls + Ce_xy.ls): - continue - other.append(((i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls)) - - yield from sorted(other, key=lambda t: t[4] + t[1].ls + t[3].ls) - - def get_edit_paths( - matched_uv, - pending_u, - pending_v, - Cv, - matched_gh, - pending_g, - pending_h, - Ce, - matched_cost, - ): - """ - Parameters: - matched_uv: partial vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - pending_u, pending_v: lists of vertices not yet mapped - Cv: CostMatrix of pending vertex mappings - matched_gh: partial edge edit path - list of tuples (g, h) of edge mappings g<->h, - g=None or h=None for deletion/insertion - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_cost: cost of partial edit path - - Returns: - sequence of (vertex_path, edge_path, cost) - vertex_path: complete vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - edge_path: complete edge edit path - list of tuples (g, h) of edge mappings g<->h, - g=None or h=None for deletion/insertion - cost: total cost of edit path - NOTE: path costs are non-increasing - """ - # debug_print('matched-uv:', matched_uv) - # debug_print('matched-gh:', matched_gh) - # debug_print('matched-cost:', matched_cost) - # debug_print('pending-u:', pending_u) - # debug_print('pending-v:', pending_v) - # debug_print(Cv.C) - # assert list(sorted(G1.nodes)) == list(sorted(list(u for u, v in matched_uv if u is not None) + pending_u)) - # assert list(sorted(G2.nodes)) == list(sorted(list(v for u, v in matched_uv if v is not None) + pending_v)) - # debug_print('pending-g:', pending_g) - # debug_print('pending-h:', pending_h) - # debug_print(Ce.C) - # assert list(sorted(G1.edges)) == list(sorted(list(g for g, h in matched_gh if g is not None) + pending_g)) - # assert list(sorted(G2.edges)) == list(sorted(list(h for g, h in matched_gh if h is not None) + pending_h)) - # debug_print() - - if prune(matched_cost + Cv.ls + Ce.ls): - return - - if not max(len(pending_u), len(pending_v)): - # assert not len(pending_g) - # assert not len(pending_h) - # path completed! - # assert matched_cost <= maxcost_value - nonlocal maxcost_value - maxcost_value = min(maxcost_value, matched_cost) - yield matched_uv, matched_gh, matched_cost - - else: - edit_ops = get_edit_ops( - matched_uv, - pending_u, - pending_v, - Cv, - pending_g, - pending_h, - Ce, - matched_cost, - ) - for ij, Cv_ij, xy, Ce_xy, edit_cost in edit_ops: - i, j = ij - # assert Cv.C[i, j] + sum(Ce.C[t] for t in xy) == edit_cost - if prune(matched_cost + edit_cost + Cv_ij.ls + Ce_xy.ls): - continue - - # dive deeper - u = pending_u.pop(i) if i < len(pending_u) else None - v = pending_v.pop(j) if j < len(pending_v) else None - matched_uv.append((u, v)) - for x, y in xy: - len_g = len(pending_g) - len_h = len(pending_h) - matched_gh.append( - ( - pending_g[x] if x < len_g else None, - pending_h[y] if y < len_h else None, - ) - ) - sortedx = sorted(x for x, y in xy) - sortedy = sorted(y for x, y in xy) - G = [ - (pending_g.pop(x) if x < len(pending_g) else None) - for x in reversed(sortedx) - ] - H = [ - (pending_h.pop(y) if y < len(pending_h) else None) - for y in reversed(sortedy) - ] - - yield from get_edit_paths( - matched_uv, - pending_u, - pending_v, - Cv_ij, - matched_gh, - pending_g, - pending_h, - Ce_xy, - matched_cost + edit_cost, - ) - - # backtrack - if u is not None: - pending_u.insert(i, u) - if v is not None: - pending_v.insert(j, v) - matched_uv.pop() - for x, g in zip(sortedx, reversed(G)): - if g is not None: - pending_g.insert(x, g) - for y, h in zip(sortedy, reversed(H)): - if h is not None: - pending_h.insert(y, h) - for _ in xy: - matched_gh.pop() - - # Initialization - - pending_u = list(G1.nodes) - pending_v = list(G2.nodes) - - initial_cost = 0 - if roots: - root_u, root_v = roots - if root_u not in pending_u or root_v not in pending_v: - raise nx.NodeNotFound("Root node not in graph.") - - # remove roots from pending - pending_u.remove(root_u) - pending_v.remove(root_v) - - # cost matrix of vertex mappings - m = len(pending_u) - n = len(pending_v) - C = np.zeros((m + n, m + n)) - if node_subst_cost: - C[0:m, 0:n] = np.array( - [ - node_subst_cost(G1.nodes[u], G2.nodes[v]) - for u in pending_u - for v in pending_v - ] - ).reshape(m, n) - if roots: - initial_cost = node_subst_cost(G1.nodes[root_u], G2.nodes[root_v]) - elif node_match: - C[0:m, 0:n] = np.array( - [ - 1 - int(node_match(G1.nodes[u], G2.nodes[v])) - for u in pending_u - for v in pending_v - ] - ).reshape(m, n) - if roots: - initial_cost = 1 - node_match(G1.nodes[root_u], G2.nodes[root_v]) - else: - # all zeroes - pass - # assert not min(m, n) or C[0:m, 0:n].min() >= 0 - if node_del_cost: - del_costs = [node_del_cost(G1.nodes[u]) for u in pending_u] - else: - del_costs = [1] * len(pending_u) - # assert not m or min(del_costs) >= 0 - if node_ins_cost: - ins_costs = [node_ins_cost(G2.nodes[v]) for v in pending_v] - else: - ins_costs = [1] * len(pending_v) - # assert not n or min(ins_costs) >= 0 - inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n : n + m] = np.array( - [del_costs[i] if i == j else inf for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m : m + n, 0:n] = np.array( - [ins_costs[i] if i == j else inf for i in range(n) for j in range(n)] - ).reshape(n, n) - Cv = make_CostMatrix(C, m, n) - # debug_print(f"Cv: {m} x {n}") - # debug_print(Cv.C) - - pending_g = list(G1.edges) - pending_h = list(G2.edges) - - # cost matrix of edge mappings - m = len(pending_g) - n = len(pending_h) - C = np.zeros((m + n, m + n)) - if edge_subst_cost: - C[0:m, 0:n] = np.array( - [ - edge_subst_cost(G1.edges[g], G2.edges[h]) - for g in pending_g - for h in pending_h - ] - ).reshape(m, n) - elif edge_match: - C[0:m, 0:n] = np.array( - [ - 1 - int(edge_match(G1.edges[g], G2.edges[h])) - for g in pending_g - for h in pending_h - ] - ).reshape(m, n) - else: - # all zeroes - pass - # assert not min(m, n) or C[0:m, 0:n].min() >= 0 - if edge_del_cost: - del_costs = [edge_del_cost(G1.edges[g]) for g in pending_g] - else: - del_costs = [1] * len(pending_g) - # assert not m or min(del_costs) >= 0 - if edge_ins_cost: - ins_costs = [edge_ins_cost(G2.edges[h]) for h in pending_h] - else: - ins_costs = [1] * len(pending_h) - # assert not n or min(ins_costs) >= 0 - inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n : n + m] = np.array( - [del_costs[i] if i == j else inf for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m : m + n, 0:n] = np.array( - [ins_costs[i] if i == j else inf for i in range(n) for j in range(n)] - ).reshape(n, n) - Ce = make_CostMatrix(C, m, n) - # debug_print(f'Ce: {m} x {n}') - # debug_print(Ce.C) - # debug_print() - - maxcost_value = Cv.C.sum() + Ce.C.sum() + 1 - - if timeout is not None: - if timeout <= 0: - raise nx.NetworkXError("Timeout value must be greater than 0") - start = time.perf_counter() - - def prune(cost): - if timeout is not None: - if time.perf_counter() - start > timeout: - return True - if upper_bound is not None: - if cost > upper_bound: - return True - if cost > maxcost_value: - return True - if strictly_decreasing and cost >= maxcost_value: - return True - return False - - # Now go! - - done_uv = [] if roots is None else [roots] - - for vertex_path, edge_path, cost in get_edit_paths( - done_uv, pending_u, pending_v, Cv, [], pending_g, pending_h, Ce, initial_cost - ): - # assert sorted(G1.nodes) == sorted(u for u, v in vertex_path if u is not None) - # assert sorted(G2.nodes) == sorted(v for u, v in vertex_path if v is not None) - # assert sorted(G1.edges) == sorted(g for g, h in edge_path if g is not None) - # assert sorted(G2.edges) == sorted(h for g, h in edge_path if h is not None) - # print(vertex_path, edge_path, cost, file = sys.stderr) - # assert cost == maxcost_value - yield list(vertex_path), list(edge_path), float(cost) - - -@nx._dispatchable -def simrank_similarity( - G, - source=None, - target=None, - importance_factor=0.9, - max_iterations=1000, - tolerance=1e-4, -): - """Returns the SimRank similarity of nodes in the graph ``G``. - - SimRank is a similarity metric that says "two objects are considered - to be similar if they are referenced by similar objects." [1]_. - - The pseudo-code definition from the paper is:: - - def simrank(G, u, v): - in_neighbors_u = G.predecessors(u) - in_neighbors_v = G.predecessors(v) - scale = C / (len(in_neighbors_u) * len(in_neighbors_v)) - return scale * sum( - simrank(G, w, x) for w, x in product(in_neighbors_u, in_neighbors_v) - ) - - where ``G`` is the graph, ``u`` is the source, ``v`` is the target, - and ``C`` is a float decay or importance factor between 0 and 1. - - The SimRank algorithm for determining node similarity is defined in - [2]_. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - - source : node - If this is specified, the returned dictionary maps each node - ``v`` in the graph to the similarity between ``source`` and - ``v``. - - target : node - If both ``source`` and ``target`` are specified, the similarity - value between ``source`` and ``target`` is returned. If - ``target`` is specified but ``source`` is not, this argument is - ignored. - - importance_factor : float - The relative importance of indirect neighbors with respect to - direct neighbors. - - max_iterations : integer - Maximum number of iterations. - - tolerance : float - Error tolerance used to check convergence. When an iteration of - the algorithm finds that no similarity value changes more than - this amount, the algorithm halts. - - Returns - ------- - similarity : dictionary or float - If ``source`` and ``target`` are both ``None``, this returns a - dictionary of dictionaries, where keys are node pairs and value - are similarity of the pair of nodes. - - If ``source`` is not ``None`` but ``target`` is, this returns a - dictionary mapping node to the similarity of ``source`` and that - node. - - If neither ``source`` nor ``target`` is ``None``, this returns - the similarity value for the given pair of nodes. - - Raises - ------ - ExceededMaxIterations - If the algorithm does not converge within ``max_iterations``. - - NodeNotFound - If either ``source`` or ``target`` is not in `G`. - - Examples - -------- - >>> G = nx.cycle_graph(2) - >>> nx.simrank_similarity(G) - {0: {0: 1.0, 1: 0.0}, 1: {0: 0.0, 1: 1.0}} - >>> nx.simrank_similarity(G, source=0) - {0: 1.0, 1: 0.0} - >>> nx.simrank_similarity(G, source=0, target=0) - 1.0 - - The result of this function can be converted to a numpy array - representing the SimRank matrix by using the node order of the - graph to determine which row and column represent each node. - Other ordering of nodes is also possible. - - >>> import numpy as np - >>> sim = nx.simrank_similarity(G) - >>> np.array([[sim[u][v] for v in G] for u in G]) - array([[1., 0.], - [0., 1.]]) - >>> sim_1d = nx.simrank_similarity(G, source=0) - >>> np.array([sim[0][v] for v in G]) - array([1., 0.]) - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/SimRank - .. [2] G. Jeh and J. Widom. - "SimRank: a measure of structural-context similarity", - In KDD'02: Proceedings of the Eighth ACM SIGKDD - International Conference on Knowledge Discovery and Data Mining, - pp. 538--543. ACM Press, 2002. - """ - import numpy as np - - nodelist = list(G) - if source is not None: - if source not in nodelist: - raise nx.NodeNotFound(f"Source node {source} not in G") - else: - s_indx = nodelist.index(source) - else: - s_indx = None - - if target is not None: - if target not in nodelist: - raise nx.NodeNotFound(f"Target node {target} not in G") - else: - t_indx = nodelist.index(target) - else: - t_indx = None - - x = _simrank_similarity_numpy( - G, s_indx, t_indx, importance_factor, max_iterations, tolerance - ) - - if isinstance(x, np.ndarray): - if x.ndim == 1: - return dict(zip(G, x.tolist())) - # else x.ndim == 2 - return {u: dict(zip(G, row)) for u, row in zip(G, x.tolist())} - return float(x) - - -def _simrank_similarity_python( - G, - source=None, - target=None, - importance_factor=0.9, - max_iterations=1000, - tolerance=1e-4, -): - """Returns the SimRank similarity of nodes in the graph ``G``. - - This pure Python version is provided for pedagogical purposes. - - Examples - -------- - >>> G = nx.cycle_graph(2) - >>> nx.similarity._simrank_similarity_python(G) - {0: {0: 1, 1: 0.0}, 1: {0: 0.0, 1: 1}} - >>> nx.similarity._simrank_similarity_python(G, source=0) - {0: 1, 1: 0.0} - >>> nx.similarity._simrank_similarity_python(G, source=0, target=0) - 1 - """ - # build up our similarity adjacency dictionary output - newsim = {u: {v: 1 if u == v else 0 for v in G} for u in G} - - # These functions compute the update to the similarity value of the nodes - # `u` and `v` with respect to the previous similarity values. - def avg_sim(s): - return sum(newsim[w][x] for (w, x) in s) / len(s) if s else 0.0 - - Gadj = G.pred if G.is_directed() else G.adj - - def sim(u, v): - return importance_factor * avg_sim(list(product(Gadj[u], Gadj[v]))) - - for its in range(max_iterations): - oldsim = newsim - newsim = {u: {v: sim(u, v) if u != v else 1 for v in G} for u in G} - is_close = all( - all( - abs(newsim[u][v] - old) <= tolerance * (1 + abs(old)) - for v, old in nbrs.items() - ) - for u, nbrs in oldsim.items() - ) - if is_close: - break - - if its + 1 == max_iterations: - raise nx.ExceededMaxIterations( - f"simrank did not converge after {max_iterations} iterations." - ) - - if source is not None and target is not None: - return newsim[source][target] - if source is not None: - return newsim[source] - return newsim - - -def _simrank_similarity_numpy( - G, - source=None, - target=None, - importance_factor=0.9, - max_iterations=1000, - tolerance=1e-4, -): - """Calculate SimRank of nodes in ``G`` using matrices with ``numpy``. - - The SimRank algorithm for determining node similarity is defined in - [1]_. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - - source : node - If this is specified, the returned dictionary maps each node - ``v`` in the graph to the similarity between ``source`` and - ``v``. - - target : node - If both ``source`` and ``target`` are specified, the similarity - value between ``source`` and ``target`` is returned. If - ``target`` is specified but ``source`` is not, this argument is - ignored. - - importance_factor : float - The relative importance of indirect neighbors with respect to - direct neighbors. - - max_iterations : integer - Maximum number of iterations. - - tolerance : float - Error tolerance used to check convergence. When an iteration of - the algorithm finds that no similarity value changes more than - this amount, the algorithm halts. - - Returns - ------- - similarity : numpy array or float - If ``source`` and ``target`` are both ``None``, this returns a - 2D array containing SimRank scores of the nodes. - - If ``source`` is not ``None`` but ``target`` is, this returns an - 1D array containing SimRank scores of ``source`` and that - node. - - If neither ``source`` nor ``target`` is ``None``, this returns - the similarity value for the given pair of nodes. - - Examples - -------- - >>> G = nx.cycle_graph(2) - >>> nx.similarity._simrank_similarity_numpy(G) - array([[1., 0.], - [0., 1.]]) - >>> nx.similarity._simrank_similarity_numpy(G, source=0) - array([1., 0.]) - >>> nx.similarity._simrank_similarity_numpy(G, source=0, target=0) - 1.0 - - References - ---------- - .. [1] G. Jeh and J. Widom. - "SimRank: a measure of structural-context similarity", - In KDD'02: Proceedings of the Eighth ACM SIGKDD - International Conference on Knowledge Discovery and Data Mining, - pp. 538--543. ACM Press, 2002. - """ - # This algorithm follows roughly - # - # S = max{C * (A.T * S * A), I} - # - # where C is the importance factor, A is the column normalized - # adjacency matrix, and I is the identity matrix. - import numpy as np - - adjacency_matrix = nx.to_numpy_array(G) - - # column-normalize the ``adjacency_matrix`` - s = np.array(adjacency_matrix.sum(axis=0)) - s[s == 0] = 1 - adjacency_matrix /= s # adjacency_matrix.sum(axis=0) - - newsim = np.eye(len(G), dtype=np.float64) - for its in range(max_iterations): - prevsim = newsim.copy() - newsim = importance_factor * ((adjacency_matrix.T @ prevsim) @ adjacency_matrix) - np.fill_diagonal(newsim, 1.0) - - if np.allclose(prevsim, newsim, atol=tolerance): - break - - if its + 1 == max_iterations: - raise nx.ExceededMaxIterations( - f"simrank did not converge after {max_iterations} iterations." - ) - - if source is not None and target is not None: - return float(newsim[source, target]) - if source is not None: - return newsim[source] - return newsim - - -@nx._dispatchable(edge_attrs="weight") -def panther_similarity( - G, source, k=5, path_length=5, c=0.5, delta=0.1, eps=None, weight="weight" -): - r"""Returns the Panther similarity of nodes in the graph `G` to node ``v``. - - Panther is a similarity metric that says "two objects are considered - to be similar if they frequently appear on the same paths." [1]_. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - source : node - Source node for which to find the top `k` similar other nodes - k : int (default = 5) - The number of most similar nodes to return. - path_length : int (default = 5) - How long the randomly generated paths should be (``T`` in [1]_) - c : float (default = 0.5) - A universal positive constant used to scale the number - of sample random paths to generate. - delta : float (default = 0.1) - The probability that the similarity $S$ is not an epsilon-approximation to (R, phi), - where $R$ is the number of random paths and $\phi$ is the probability - that an element sampled from a set $A \subseteq D$, where $D$ is the domain. - eps : float or None (default = None) - The error bound. Per [1]_, a good value is ``sqrt(1/|E|)``. Therefore, - if no value is provided, the recommended computed value will be used. - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - - Returns - ------- - similarity : dictionary - Dictionary of nodes to similarity scores (as floats). Note: - the self-similarity (i.e., ``v``) will not be included in - the returned dictionary. So, for ``k = 5``, a dictionary of - top 4 nodes and their similarity scores will be returned. - - Raises - ------ - NetworkXUnfeasible - If `source` is an isolated node. - - NodeNotFound - If `source` is not in `G`. - - Notes - ----- - The isolated nodes in `G` are ignored. - - Examples - -------- - >>> G = nx.star_graph(10) - >>> sim = nx.panther_similarity(G, 0) - - References - ---------- - .. [1] Zhang, J., Tang, J., Ma, C., Tong, H., Jing, Y., & Li, J. - Panther: Fast top-k similarity search on large networks. - In Proceedings of the ACM SIGKDD International Conference - on Knowledge Discovery and Data Mining (Vol. 2015-August, pp. 1445–1454). - Association for Computing Machinery. https://doi.org/10.1145/2783258.2783267. - """ - import numpy as np - - if source not in G: - raise nx.NodeNotFound(f"Source node {source} not in G") - - isolates = set(nx.isolates(G)) - - if source in isolates: - raise nx.NetworkXUnfeasible( - f"Panther similarity is not defined for the isolated source node {source}." - ) - - G = G.subgraph([node for node in G.nodes if node not in isolates]).copy() - - num_nodes = G.number_of_nodes() - if num_nodes < k: - warnings.warn( - f"Number of nodes is {num_nodes}, but requested k is {k}. " - "Setting k to number of nodes." - ) - k = num_nodes - # According to [1], they empirically determined - # a good value for ``eps`` to be sqrt( 1 / |E| ) - if eps is None: - eps = np.sqrt(1.0 / G.number_of_edges()) - - inv_node_map = {name: index for index, name in enumerate(G.nodes)} - node_map = np.array(G) - - # Calculate the sample size ``R`` for how many paths - # to randomly generate - t_choose_2 = math.comb(path_length, 2) - sample_size = int((c / eps**2) * (np.log2(t_choose_2) + 1 + np.log(1 / delta))) - index_map = {} - _ = list( - generate_random_paths( - G, sample_size, path_length=path_length, index_map=index_map, weight=weight - ) - ) - S = np.zeros(num_nodes) - - inv_sample_size = 1 / sample_size - - source_paths = set(index_map[source]) - - # Calculate the path similarities - # between ``source`` (v) and ``node`` (v_j) - # using our inverted index mapping of - # vertices to paths - for node, paths in index_map.items(): - # Only consider paths where both - # ``node`` and ``source`` are present - common_paths = source_paths.intersection(paths) - S[inv_node_map[node]] = len(common_paths) * inv_sample_size - - # Retrieve top ``k`` similar - # Note: the below performed anywhere from 4-10x faster - # (depending on input sizes) vs the equivalent ``np.argsort(S)[::-1]`` - top_k_unsorted = np.argpartition(S, -k)[-k:] - top_k_sorted = top_k_unsorted[np.argsort(S[top_k_unsorted])][::-1] - - # Add back the similarity scores - top_k_with_val = dict( - zip(node_map[top_k_sorted].tolist(), S[top_k_sorted].tolist()) - ) - - # Remove the self-similarity - top_k_with_val.pop(source, None) - return top_k_with_val - - -@np_random_state(5) -@nx._dispatchable(edge_attrs="weight") -def generate_random_paths( - G, sample_size, path_length=5, index_map=None, weight="weight", seed=None -): - """Randomly generate `sample_size` paths of length `path_length`. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - sample_size : integer - The number of paths to generate. This is ``R`` in [1]_. - path_length : integer (default = 5) - The maximum size of the path to randomly generate. - This is ``T`` in [1]_. According to the paper, ``T >= 5`` is - recommended. - index_map : dictionary, optional - If provided, this will be populated with the inverted - index of nodes mapped to the set of generated random path - indices within ``paths``. - weight : string or None, optional (default="weight") - The name of an edge attribute that holds the numerical value - used as a weight. If None then each edge has weight 1. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - paths : generator of lists - Generator of `sample_size` paths each with length `path_length`. - - Examples - -------- - Note that the return value is the list of paths: - - >>> G = nx.star_graph(3) - >>> random_path = nx.generate_random_paths(G, 2) - - By passing a dictionary into `index_map`, it will build an - inverted index mapping of nodes to the paths in which that node is present: - - >>> G = nx.star_graph(3) - >>> index_map = {} - >>> random_path = nx.generate_random_paths(G, 3, index_map=index_map) - >>> paths_containing_node_0 = [ - ... random_path[path_idx] for path_idx in index_map.get(0, []) - ... ] - - References - ---------- - .. [1] Zhang, J., Tang, J., Ma, C., Tong, H., Jing, Y., & Li, J. - Panther: Fast top-k similarity search on large networks. - In Proceedings of the ACM SIGKDD International Conference - on Knowledge Discovery and Data Mining (Vol. 2015-August, pp. 1445–1454). - Association for Computing Machinery. https://doi.org/10.1145/2783258.2783267. - """ - import numpy as np - - randint_fn = ( - seed.integers if isinstance(seed, np.random.Generator) else seed.randint - ) - - # Calculate transition probabilities between - # every pair of vertices according to Eq. (3) - adj_mat = nx.to_numpy_array(G, weight=weight) - inv_row_sums = np.reciprocal(adj_mat.sum(axis=1)).reshape(-1, 1) - transition_probabilities = adj_mat * inv_row_sums - - node_map = list(G) - num_nodes = G.number_of_nodes() - - for path_index in range(sample_size): - # Sample current vertex v = v_i uniformly at random - node_index = randint_fn(num_nodes) - node = node_map[node_index] - - # Add v into p_r and add p_r into the path set - # of v, i.e., P_v - path = [node] - - # Build the inverted index (P_v) of vertices to paths - if index_map is not None: - if node in index_map: - index_map[node].add(path_index) - else: - index_map[node] = {path_index} - - starting_index = node_index - for _ in range(path_length): - # Randomly sample a neighbor (v_j) according - # to transition probabilities from ``node`` (v) to its neighbors - nbr_index = seed.choice( - num_nodes, p=transition_probabilities[starting_index] - ) - - # Set current vertex (v = v_j) - starting_index = nbr_index - - # Add v into p_r - nbr_node = node_map[nbr_index] - path.append(nbr_node) - - # Add p_r into P_v - if index_map is not None: - if nbr_node in index_map: - index_map[nbr_node].add(path_index) - else: - index_map[nbr_node] = {path_index} - - yield path diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/simple_paths.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/simple_paths.py deleted file mode 100644 index 3605522..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/simple_paths.py +++ /dev/null @@ -1,950 +0,0 @@ -from heapq import heappop, heappush -from itertools import count - -import networkx as nx -from networkx.algorithms.shortest_paths.weighted import _weight_function -from networkx.utils import not_implemented_for, pairwise - -__all__ = [ - "all_simple_paths", - "is_simple_path", - "shortest_simple_paths", - "all_simple_edge_paths", -] - - -@nx._dispatchable -def is_simple_path(G, nodes): - """Returns True if and only if `nodes` form a simple path in `G`. - - A *simple path* in a graph is a nonempty sequence of nodes in which - no node appears more than once in the sequence, and each adjacent - pair of nodes in the sequence is adjacent in the graph. - - Parameters - ---------- - G : graph - A NetworkX graph. - nodes : list - A list of one or more nodes in the graph `G`. - - Returns - ------- - bool - Whether the given list of nodes represents a simple path in `G`. - - Notes - ----- - An empty list of nodes is not a path but a list of one node is a - path. Here's an explanation why. - - This function operates on *node paths*. One could also consider - *edge paths*. There is a bijection between node paths and edge - paths. - - The *length of a path* is the number of edges in the path, so a list - of nodes of length *n* corresponds to a path of length *n* - 1. - Thus the smallest edge path would be a list of zero edges, the empty - path. This corresponds to a list of one node. - - To convert between a node path and an edge path, you can use code - like the following:: - - >>> from networkx.utils import pairwise - >>> nodes = [0, 1, 2, 3] - >>> edges = list(pairwise(nodes)) - >>> edges - [(0, 1), (1, 2), (2, 3)] - >>> nodes = [edges[0][0]] + [v for u, v in edges] - >>> nodes - [0, 1, 2, 3] - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> nx.is_simple_path(G, [2, 3, 0]) - True - >>> nx.is_simple_path(G, [0, 2]) - False - - """ - # The empty list is not a valid path. Could also return - # NetworkXPointlessConcept here. - if len(nodes) == 0: - return False - - # If the list is a single node, just check that the node is actually - # in the graph. - if len(nodes) == 1: - return nodes[0] in G - - # check that all nodes in the list are in the graph, if at least one - # is not in the graph, then this is not a simple path - if not all(n in G for n in nodes): - return False - - # If the list contains repeated nodes, then it's not a simple path - if len(set(nodes)) != len(nodes): - return False - - # Test that each adjacent pair of nodes is adjacent. - return all(v in G[u] for u, v in pairwise(nodes)) - - -@nx._dispatchable -def all_simple_paths(G, source, target, cutoff=None): - """Generate all simple paths in the graph G from source to target. - - A simple path is a path with no repeated nodes. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : nodes - Single node or iterable of nodes at which to end path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - path_generator: generator - A generator that produces lists of simple paths. If there are no paths - between the source and target within the given cutoff the generator - produces no output. If it is possible to traverse the same sequence of - nodes in multiple ways, namely through parallel edges, then it will be - returned multiple times (once for each viable edge combination). - - Examples - -------- - This iterator generates lists of nodes:: - - >>> G = nx.complete_graph(4) - >>> for path in nx.all_simple_paths(G, source=0, target=3): - ... print(path) - ... - [0, 1, 2, 3] - [0, 1, 3] - [0, 2, 1, 3] - [0, 2, 3] - [0, 3] - - You can generate only those paths that are shorter than a certain - length by using the `cutoff` keyword argument:: - - >>> paths = nx.all_simple_paths(G, source=0, target=3, cutoff=2) - >>> print(list(paths)) - [[0, 1, 3], [0, 2, 3], [0, 3]] - - To get each path as the corresponding list of edges, you can use the - :func:`networkx.utils.pairwise` helper function:: - - >>> paths = nx.all_simple_paths(G, source=0, target=3) - >>> for path in map(nx.utils.pairwise, paths): - ... print(list(path)) - [(0, 1), (1, 2), (2, 3)] - [(0, 1), (1, 3)] - [(0, 2), (2, 1), (1, 3)] - [(0, 2), (2, 3)] - [(0, 3)] - - Pass an iterable of nodes as target to generate all paths ending in any of several nodes:: - - >>> G = nx.complete_graph(4) - >>> for path in nx.all_simple_paths(G, source=0, target=[3, 2]): - ... print(path) - ... - [0, 1, 2] - [0, 1, 2, 3] - [0, 1, 3] - [0, 1, 3, 2] - [0, 2] - [0, 2, 1, 3] - [0, 2, 3] - [0, 3] - [0, 3, 1, 2] - [0, 3, 2] - - The singleton path from ``source`` to itself is considered a simple path and is - included in the results: - - >>> G = nx.empty_graph(5) - >>> list(nx.all_simple_paths(G, source=0, target=0)) - [[0]] - - >>> G = nx.path_graph(3) - >>> list(nx.all_simple_paths(G, source=0, target={0, 1, 2})) - [[0], [0, 1], [0, 1, 2]] - - Iterate over each path from the root nodes to the leaf nodes in a - directed acyclic graph using a functional programming approach:: - - >>> from itertools import chain - >>> from itertools import product - >>> from itertools import starmap - >>> from functools import partial - >>> - >>> chaini = chain.from_iterable - >>> - >>> G = nx.DiGraph([(0, 1), (1, 2), (0, 3), (3, 2)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = (v for v, d in G.out_degree() if d == 0) - >>> all_paths = partial(nx.all_simple_paths, G) - >>> list(chaini(starmap(all_paths, product(roots, leaves)))) - [[0, 1, 2], [0, 3, 2]] - - The same list computed using an iterative approach:: - - >>> G = nx.DiGraph([(0, 1), (1, 2), (0, 3), (3, 2)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = (v for v, d in G.out_degree() if d == 0) - >>> all_paths = [] - >>> for root in roots: - ... for leaf in leaves: - ... paths = nx.all_simple_paths(G, root, leaf) - ... all_paths.extend(paths) - >>> all_paths - [[0, 1, 2], [0, 3, 2]] - - Iterate over each path from the root nodes to the leaf nodes in a - directed acyclic graph passing all leaves together to avoid unnecessary - compute:: - - >>> G = nx.DiGraph([(0, 1), (2, 1), (1, 3), (1, 4)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = [v for v, d in G.out_degree() if d == 0] - >>> all_paths = [] - >>> for root in roots: - ... paths = nx.all_simple_paths(G, root, leaves) - ... all_paths.extend(paths) - >>> all_paths - [[0, 1, 3], [0, 1, 4], [2, 1, 3], [2, 1, 4]] - - If parallel edges offer multiple ways to traverse a given sequence of - nodes, this sequence of nodes will be returned multiple times: - - >>> G = nx.MultiDiGraph([(0, 1), (0, 1), (1, 2)]) - >>> list(nx.all_simple_paths(G, 0, 2)) - [[0, 1, 2], [0, 1, 2]] - - Notes - ----- - This algorithm uses a modified depth-first search to generate the - paths [1]_. A single path can be found in $O(V+E)$ time but the - number of simple paths in a graph can be very large, e.g. $O(n!)$ in - the complete graph of order $n$. - - This function does not check that a path exists between `source` and - `target`. For large graphs, this may result in very long runtimes. - Consider using `has_path` to check that a path exists between `source` and - `target` before calling this function on large graphs. - - References - ---------- - .. [1] R. Sedgewick, "Algorithms in C, Part 5: Graph Algorithms", - Addison Wesley Professional, 3rd ed., 2001. - - See Also - -------- - all_shortest_paths, shortest_path, has_path - - """ - for edge_path in all_simple_edge_paths(G, source, target, cutoff): - yield [source] + [edge[1] for edge in edge_path] - - -@nx._dispatchable -def all_simple_edge_paths(G, source, target, cutoff=None): - """Generate lists of edges for all simple paths in G from source to target. - - A simple path is a path with no repeated nodes. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : nodes - Single node or iterable of nodes at which to end path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - path_generator: generator - A generator that produces lists of simple paths. If there are no paths - between the source and target within the given cutoff the generator - produces no output. - For multigraphs, the list of edges have elements of the form `(u,v,k)`. - Where `k` corresponds to the edge key. - - Examples - -------- - - Print the simple path edges of a Graph:: - - >>> g = nx.Graph([(1, 2), (2, 4), (1, 3), (3, 4)]) - >>> for path in sorted(nx.all_simple_edge_paths(g, 1, 4)): - ... print(path) - [(1, 2), (2, 4)] - [(1, 3), (3, 4)] - - Print the simple path edges of a MultiGraph. Returned edges come with - their associated keys:: - - >>> mg = nx.MultiGraph() - >>> mg.add_edge(1, 2, key="k0") - 'k0' - >>> mg.add_edge(1, 2, key="k1") - 'k1' - >>> mg.add_edge(2, 3, key="k0") - 'k0' - >>> for path in sorted(nx.all_simple_edge_paths(mg, 1, 3)): - ... print(path) - [(1, 2, 'k0'), (2, 3, 'k0')] - [(1, 2, 'k1'), (2, 3, 'k0')] - - When ``source`` is one of the targets, the empty path starting and ending at - ``source`` without traversing any edge is considered a valid simple edge path - and is included in the results: - - >>> G = nx.Graph() - >>> G.add_node(0) - >>> paths = list(nx.all_simple_edge_paths(G, 0, 0)) - >>> for path in paths: - ... print(path) - [] - >>> len(paths) - 1 - - - Notes - ----- - This algorithm uses a modified depth-first search to generate the - paths [1]_. A single path can be found in $O(V+E)$ time but the - number of simple paths in a graph can be very large, e.g. $O(n!)$ in - the complete graph of order $n$. - - References - ---------- - .. [1] R. Sedgewick, "Algorithms in C, Part 5: Graph Algorithms", - Addison Wesley Professional, 3rd ed., 2001. - - See Also - -------- - all_shortest_paths, shortest_path, all_simple_paths - - """ - if source not in G: - raise nx.NodeNotFound(f"source node {source} not in graph") - - if target in G: - targets = {target} - else: - try: - targets = set(target) - except TypeError as err: - raise nx.NodeNotFound(f"target node {target} not in graph") from err - - cutoff = cutoff if cutoff is not None else len(G) - 1 - - if cutoff >= 0 and targets: - yield from _all_simple_edge_paths(G, source, targets, cutoff) - - -def _all_simple_edge_paths(G, source, targets, cutoff): - # We simulate recursion with a stack, keeping the current path being explored - # and the outgoing edge iterators at each point in the stack. - # To avoid unnecessary checks, the loop is structured in a way such that a path - # is considered for yielding only after a new node/edge is added. - # We bootstrap the search by adding a dummy iterator to the stack that only yields - # a dummy edge to source (so that the trivial path has a chance of being included). - - get_edges = ( - (lambda node: G.edges(node, keys=True)) - if G.is_multigraph() - else (lambda node: G.edges(node)) - ) - - # The current_path is a dictionary that maps nodes in the path to the edge that was - # used to enter that node (instead of a list of edges) because we want both a fast - # membership test for nodes in the path and the preservation of insertion order. - current_path = {None: None} - stack = [iter([(None, source)])] - - while stack: - # 1. Try to extend the current path. - next_edge = next((e for e in stack[-1] if e[1] not in current_path), None) - if next_edge is None: - # All edges of the last node in the current path have been explored. - stack.pop() - current_path.popitem() - continue - previous_node, next_node, *_ = next_edge - - # 2. Check if we've reached a target. - if next_node in targets: - yield (list(current_path.values()) + [next_edge])[2:] # remove dummy edge - - # 3. Only expand the search through the next node if it makes sense. - if len(current_path) - 1 < cutoff and ( - targets - current_path.keys() - {next_node} - ): - current_path[next_node] = next_edge - stack.append(iter(get_edges(next_node))) - - -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def shortest_simple_paths(G, source, target, weight=None): - """Generate all simple paths in the graph G from source to target, - starting from shortest ones. - - A simple path is a path with no repeated nodes. - - If a weighted shortest path search is to be used, no negative weights - are allowed. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - weight : string or function - If it is a string, it is the name of the edge attribute to be - used as a weight. - - If it is a function, the weight of an edge is the value returned - by the function. The function must accept exactly three positional - arguments: the two endpoints of an edge and the dictionary of edge - attributes for that edge. The function must return a number or None. - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - If None all edges are considered to have unit weight. Default - value None. - - Returns - ------- - path_generator: generator - A generator that produces lists of simple paths, in order from - shortest to longest. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - NetworkXError - If source or target nodes are not in the input graph. - - NetworkXNotImplemented - If the input graph is a Multi[Di]Graph. - - Examples - -------- - - >>> G = nx.cycle_graph(7) - >>> paths = list(nx.shortest_simple_paths(G, 0, 3)) - >>> print(paths) - [[0, 1, 2, 3], [0, 6, 5, 4, 3]] - - You can use this function to efficiently compute the k shortest/best - paths between two nodes. - - >>> from itertools import islice - >>> def k_shortest_paths(G, source, target, k, weight=None): - ... return list( - ... islice(nx.shortest_simple_paths(G, source, target, weight=weight), k) - ... ) - >>> for path in k_shortest_paths(G, 0, 3, 2): - ... print(path) - [0, 1, 2, 3] - [0, 6, 5, 4, 3] - - Notes - ----- - This procedure is based on algorithm by Jin Y. Yen [1]_. Finding - the first $K$ paths requires $O(KN^3)$ operations. - - See Also - -------- - all_shortest_paths - shortest_path - all_simple_paths - - References - ---------- - .. [1] Jin Y. Yen, "Finding the K Shortest Loopless Paths in a - Network", Management Science, Vol. 17, No. 11, Theory Series - (Jul., 1971), pp. 712-716. - - """ - if source not in G: - raise nx.NodeNotFound(f"source node {source} not in graph") - - if target not in G: - raise nx.NodeNotFound(f"target node {target} not in graph") - - if weight is None: - length_func = len - shortest_path_func = _bidirectional_shortest_path - else: - wt = _weight_function(G, weight) - - def length_func(path): - return sum( - wt(u, v, G.get_edge_data(u, v)) for (u, v) in zip(path, path[1:]) - ) - - shortest_path_func = _bidirectional_dijkstra - - listA = [] - listB = PathBuffer() - prev_path = None - while True: - if not prev_path: - length, path = shortest_path_func(G, source, target, weight=weight) - listB.push(length, path) - else: - ignore_nodes = set() - ignore_edges = set() - for i in range(1, len(prev_path)): - root = prev_path[:i] - root_length = length_func(root) - for path in listA: - if path[:i] == root: - ignore_edges.add((path[i - 1], path[i])) - try: - length, spur = shortest_path_func( - G, - root[-1], - target, - ignore_nodes=ignore_nodes, - ignore_edges=ignore_edges, - weight=weight, - ) - path = root[:-1] + spur - listB.push(root_length + length, path) - except nx.NetworkXNoPath: - pass - ignore_nodes.add(root[-1]) - - if listB: - path = listB.pop() - yield path - listA.append(path) - prev_path = path - else: - break - - -class PathBuffer: - def __init__(self): - self.paths = set() - self.sortedpaths = [] - self.counter = count() - - def __len__(self): - return len(self.sortedpaths) - - def push(self, cost, path): - hashable_path = tuple(path) - if hashable_path not in self.paths: - heappush(self.sortedpaths, (cost, next(self.counter), path)) - self.paths.add(hashable_path) - - def pop(self): - (cost, num, path) = heappop(self.sortedpaths) - hashable_path = tuple(path) - self.paths.remove(hashable_path) - return path - - -def _bidirectional_shortest_path( - G, source, target, ignore_nodes=None, ignore_edges=None, weight=None -): - """Returns the shortest path between source and target ignoring - nodes and edges in the containers ignore_nodes and ignore_edges. - - This is a custom modification of the standard bidirectional shortest - path implementation at networkx.algorithms.unweighted - - Parameters - ---------- - G : NetworkX graph - - source : node - starting node for path - - target : node - ending node for path - - ignore_nodes : container of nodes - nodes to ignore, optional - - ignore_edges : container of edges - edges to ignore, optional - - weight : None - This function accepts a weight argument for convenience of - shortest_simple_paths function. It will be ignored. - - Returns - ------- - path: list - List of nodes in a path from source to target. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - See Also - -------- - shortest_path - - """ - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target, ignore_nodes, ignore_edges) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from w to target - while w is not None: - path.append(w) - w = succ[w] - # from source to w - w = pred[path[0]] - while w is not None: - path.insert(0, w) - w = pred[w] - - return len(path), path - - -def _bidirectional_pred_succ(G, source, target, ignore_nodes=None, ignore_edges=None): - """Bidirectional shortest path helper. - Returns (pred,succ,w) where - pred is a dictionary of predecessors from w to the source, and - succ is a dictionary of successors from w to the target. - """ - # does BFS from both source and target and meets in the middle - if ignore_nodes and (source in ignore_nodes or target in ignore_nodes): - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") - if target == source: - return ({target: None}, {source: None}, source) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # support optional nodes filter - if ignore_nodes: - - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if w not in ignore_nodes: - yield w - - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # support optional edges filter - if ignore_edges: - if G.is_directed(): - - def filter_pred_iter(pred_iter): - def iterate(v): - for w in pred_iter(v): - if (w, v) not in ignore_edges: - yield w - - return iterate - - def filter_succ_iter(succ_iter): - def iterate(v): - for w in succ_iter(v): - if (v, w) not in ignore_edges: - yield w - - return iterate - - Gpred = filter_pred_iter(Gpred) - Gsucc = filter_succ_iter(Gsucc) - - else: - - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if (v, w) not in ignore_edges and (w, v) not in ignore_edges: - yield w - - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # predecessor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - while forward_fringe and reverse_fringe: - if len(forward_fringe) <= len(reverse_fringe): - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc(v): - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: - # found path - return pred, succ, w - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred(v): - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: - # found path - return pred, succ, w - - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") - - -def _bidirectional_dijkstra( - G, source, target, weight="weight", ignore_nodes=None, ignore_edges=None -): - """Dijkstra's algorithm for shortest paths using bidirectional search. - - This function returns the shortest path between source and target - ignoring nodes and edges in the containers ignore_nodes and - ignore_edges. - - This is a custom modification of the standard Dijkstra bidirectional - shortest path implementation at networkx.algorithms.weighted - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node. - - target : node - Ending node. - - weight: string, function, optional (default='weight') - Edge data key or weight function corresponding to the edge weight - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number or None to indicate a hidden edge. - - ignore_nodes : container of nodes - nodes to ignore, optional - - ignore_edges : container of edges - edges to ignore, optional - - Returns - ------- - length : number - Shortest path length. - - Returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from the source. - The second stores the path from the source to that node. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - In practice bidirectional Dijkstra is much more than twice as fast as - ordinary Dijkstra. - - Ordinary Dijkstra expands nodes in a sphere-like manner from the - source. The radius of this sphere will eventually be the length - of the shortest path. Bidirectional Dijkstra will expand nodes - from both the source and the target, making two spheres of half - this radius. Volume of the first sphere is pi*r*r while the - others are 2*pi*r/2*r/2, making up half the volume. - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - shortest_path - shortest_path_length - """ - if ignore_nodes and (source in ignore_nodes or target in ignore_nodes): - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") - if source == target: - if source not in G: - raise nx.NodeNotFound(f"Node {source} not in graph") - return (0, [source]) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # support optional nodes filter - if ignore_nodes: - - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if w not in ignore_nodes: - yield w - - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # support optional edges filter - if ignore_edges: - if G.is_directed(): - - def filter_pred_iter(pred_iter): - def iterate(v): - for w in pred_iter(v): - if (w, v) not in ignore_edges: - yield w - - return iterate - - def filter_succ_iter(succ_iter): - def iterate(v): - for w in succ_iter(v): - if (v, w) not in ignore_edges: - yield w - - return iterate - - Gpred = filter_pred_iter(Gpred) - Gsucc = filter_succ_iter(Gsucc) - - else: - - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if (v, w) not in ignore_edges and (w, v) not in ignore_edges: - yield w - - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - wt = _weight_function(G, weight) - push = heappush - pop = heappop - # Init: Forward Backward - dists = [{}, {}] # dictionary of final distances - paths = [{source: [source]}, {target: [target]}] # dictionary of paths - fringe = [[], []] # heap of (distance, node) tuples for - # extracting next node to expand - seen = [{source: 0}, {target: 0}] # dictionary of distances to - # nodes seen - c = count() - # initialize fringe heap - push(fringe[0], (0, next(c), source)) - push(fringe[1], (0, next(c), target)) - # neighs for extracting correct neighbor information - neighs = [Gsucc, Gpred] - # variables to hold shortest discovered path - # finaldist = 1e30000 - finalpath = [] - dir = 1 - while fringe[0] and fringe[1]: - # choose direction - # dir == 0 is forward direction and dir == 1 is back - dir = 1 - dir - # extract closest to expand - (dist, _, v) = pop(fringe[dir]) - if v in dists[dir]: - # Shortest path to v has already been found - continue - # update distance - dists[dir][v] = dist # equal to seen[dir][v] - if v in dists[1 - dir]: - # if we have scanned v in both directions we are done - # we have now discovered the shortest path - return (finaldist, finalpath) - - for w in neighs[dir](v): - if dir == 0: # forward - minweight = wt(v, w, G.get_edge_data(v, w)) - else: # back, must remember to change v,w->w,v - minweight = wt(w, v, G.get_edge_data(w, v)) - if minweight is None: - continue - vwLength = dists[dir][v] + minweight - - if w in dists[dir]: - if vwLength < dists[dir][w]: - raise ValueError("Contradictory paths found: negative weights?") - elif w not in seen[dir] or vwLength < seen[dir][w]: - # relaxing - seen[dir][w] = vwLength - push(fringe[dir], (vwLength, next(c), w)) - paths[dir][w] = paths[dir][v] + [w] - if w in seen[0] and w in seen[1]: - # see if this path is better than the already - # discovered shortest path - totaldist = seen[0][w] + seen[1][w] - if finalpath == [] or finaldist > totaldist: - finaldist = totaldist - revpath = paths[1][w][:] - revpath.reverse() - finalpath = paths[0][w] + revpath[1:] - raise nx.NetworkXNoPath(f"No path between {source} and {target}.") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smallworld.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smallworld.py deleted file mode 100644 index 456a4ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smallworld.py +++ /dev/null @@ -1,404 +0,0 @@ -"""Functions for estimating the small-world-ness of graphs. - -A small world network is characterized by a small average shortest path length, -and a large clustering coefficient. - -Small-worldness is commonly measured with the coefficient sigma or omega. - -Both coefficients compare the average clustering coefficient and shortest path -length of a given graph against the same quantities for an equivalent random -or lattice graph. - -For more information, see the Wikipedia article on small-world network [1]_. - -.. [1] Small-world network:: https://en.wikipedia.org/wiki/Small-world_network - -""" - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ["random_reference", "lattice_reference", "sigma", "omega"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(3) -@nx._dispatchable(returns_graph=True) -def random_reference(G, niter=1, connectivity=True, seed=None): - """Compute a random graph by swapping edges of a given graph. - - Parameters - ---------- - G : graph - An undirected graph with 4 or more nodes. - - niter : integer (optional, default=1) - An edge is rewired approximately `niter` times. - - connectivity : boolean (optional, default=True) - When True, ensure connectivity for the randomized graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The randomized graph. - - Raises - ------ - NetworkXError - If there are fewer than 4 nodes or 2 edges in `G` - - Notes - ----- - The implementation is adapted from the algorithm by Maslov and Sneppen - (2002) [1]_. - - References - ---------- - .. [1] Maslov, Sergei, and Kim Sneppen. - "Specificity and stability in topology of protein networks." - Science 296.5569 (2002): 910-913. - """ - if len(G) < 4: - raise nx.NetworkXError("Graph has fewer than four nodes.") - if len(G.edges) < 2: - raise nx.NetworkXError("Graph has fewer that 2 edges") - - from networkx.utils import cumulative_distribution, discrete_sequence - - local_conn = nx.connectivity.local_edge_connectivity - - G = G.copy() - keys, degrees = zip(*G.degree()) # keys, degree - cdf = cumulative_distribution(degrees) # cdf of degree - nnodes = len(G) - nedges = nx.number_of_edges(G) - niter = niter * nedges - ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) - swapcount = 0 - - for i in range(niter): - n = 0 - while n < ntries: - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ai == ci: - continue # same source, skip - a = keys[ai] # convert index to label - c = keys[ci] - # choose target uniformly from neighbors - b = seed.choice(list(G.neighbors(a))) - d = seed.choice(list(G.neighbors(c))) - if b in [a, c, d] or d in [a, b, c]: - continue # all vertices should be different - - # don't create parallel edges - if (d not in G[a]) and (b not in G[c]): - G.add_edge(a, d) - G.add_edge(c, b) - G.remove_edge(a, b) - G.remove_edge(c, d) - - # Check if the graph is still connected - if connectivity and local_conn(G, a, b) == 0: - # Not connected, revert the swap - G.remove_edge(a, d) - G.remove_edge(c, b) - G.add_edge(a, b) - G.add_edge(c, d) - else: - swapcount += 1 - break - n += 1 - return G - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(4) -@nx._dispatchable(returns_graph=True) -def lattice_reference(G, niter=5, D=None, connectivity=True, seed=None): - """Latticize the given graph by swapping edges. - - Parameters - ---------- - G : graph - An undirected graph. - - niter : integer (optional, default=1) - An edge is rewired approximately niter times. - - D : numpy.array (optional, default=None) - Distance to the diagonal matrix. - - connectivity : boolean (optional, default=True) - Ensure connectivity for the latticized graph when set to True. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The latticized graph. - - Raises - ------ - NetworkXError - If there are fewer than 4 nodes or 2 edges in `G` - - Notes - ----- - The implementation is adapted from the algorithm by Sporns et al. [1]_. - which is inspired from the original work by Maslov and Sneppen(2002) [2]_. - - References - ---------- - .. [1] Sporns, Olaf, and Jonathan D. Zwi. - "The small world of the cerebral cortex." - Neuroinformatics 2.2 (2004): 145-162. - .. [2] Maslov, Sergei, and Kim Sneppen. - "Specificity and stability in topology of protein networks." - Science 296.5569 (2002): 910-913. - """ - import numpy as np - - from networkx.utils import cumulative_distribution, discrete_sequence - - local_conn = nx.connectivity.local_edge_connectivity - - if len(G) < 4: - raise nx.NetworkXError("Graph has fewer than four nodes.") - if len(G.edges) < 2: - raise nx.NetworkXError("Graph has fewer that 2 edges") - # Instead of choosing uniformly at random from a generated edge list, - # this algorithm chooses nonuniformly from the set of nodes with - # probability weighted by degree. - G = G.copy() - keys, degrees = zip(*G.degree()) # keys, degree - cdf = cumulative_distribution(degrees) # cdf of degree - - nnodes = len(G) - nedges = nx.number_of_edges(G) - if D is None: - D = np.zeros((nnodes, nnodes)) - un = np.arange(1, nnodes) - um = np.arange(nnodes - 1, 0, -1) - u = np.append((0,), np.where(un < um, un, um)) - - for v in range(int(np.ceil(nnodes / 2))): - D[nnodes - v - 1, :] = np.append(u[v + 1 :], u[: v + 1]) - D[v, :] = D[nnodes - v - 1, :][::-1] - - niter = niter * nedges - # maximal number of rewiring attempts per 'niter' - max_attempts = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) - - for _ in range(niter): - n = 0 - while n < max_attempts: - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ai == ci: - continue # same source, skip - a = keys[ai] # convert index to label - c = keys[ci] - # choose target uniformly from neighbors - b = seed.choice(list(G.neighbors(a))) - d = seed.choice(list(G.neighbors(c))) - bi = keys.index(b) - di = keys.index(d) - - if b in [a, c, d] or d in [a, b, c]: - continue # all vertices should be different - - # don't create parallel edges - if (d not in G[a]) and (b not in G[c]): - if D[ai, bi] + D[ci, di] >= D[ai, ci] + D[bi, di]: - # only swap if we get closer to the diagonal - G.add_edge(a, d) - G.add_edge(c, b) - G.remove_edge(a, b) - G.remove_edge(c, d) - - # Check if the graph is still connected - if connectivity and local_conn(G, a, b) == 0: - # Not connected, revert the swap - G.remove_edge(a, d) - G.remove_edge(c, b) - G.add_edge(a, b) - G.add_edge(c, d) - else: - break - n += 1 - - return G - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(3) -@nx._dispatchable -def sigma(G, niter=100, nrand=10, seed=None): - """Returns the small-world coefficient (sigma) of the given graph. - - The small-world coefficient is defined as: - sigma = C/Cr / L/Lr - where C and L are respectively the average clustering coefficient and - average shortest path length of G. Cr and Lr are respectively the average - clustering coefficient and average shortest path length of an equivalent - random graph. - - A graph is commonly classified as small-world if sigma>1. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - niter : integer (optional, default=100) - Approximate number of rewiring per edge to compute the equivalent - random graph. - nrand : integer (optional, default=10) - Number of random graphs generated to compute the average clustering - coefficient (Cr) and average shortest path length (Lr). - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - sigma : float - The small-world coefficient of G. - - Notes - ----- - The implementation is adapted from Humphries et al. [1]_ [2]_. - - References - ---------- - .. [1] The brainstem reticular formation is a small-world, not scale-free, - network M. D. Humphries, K. Gurney and T. J. Prescott, - Proc. Roy. Soc. B 2006 273, 503-511, doi:10.1098/rspb.2005.3354. - .. [2] Humphries and Gurney (2008). - "Network 'Small-World-Ness': A Quantitative Method for Determining - Canonical Network Equivalence". - PLoS One. 3 (4). PMID 18446219. doi:10.1371/journal.pone.0002051. - """ - import numpy as np - - # Compute the mean clustering coefficient and average shortest path length - # for an equivalent random graph - randMetrics = {"C": [], "L": []} - for i in range(nrand): - Gr = random_reference(G, niter=niter, seed=seed) - randMetrics["C"].append(nx.transitivity(Gr)) - randMetrics["L"].append(nx.average_shortest_path_length(Gr)) - - C = nx.transitivity(G) - L = nx.average_shortest_path_length(G) - Cr = np.mean(randMetrics["C"]) - Lr = np.mean(randMetrics["L"]) - - sigma = (C / Cr) / (L / Lr) - - return float(sigma) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(3) -@nx._dispatchable -def omega(G, niter=5, nrand=10, seed=None): - """Returns the small-world coefficient (omega) of a graph - - The small-world coefficient of a graph G is: - - omega = Lr/L - C/Cl - - where C and L are respectively the average clustering coefficient and - average shortest path length of G. Lr is the average shortest path length - of an equivalent random graph and Cl is the average clustering coefficient - of an equivalent lattice graph. - - The small-world coefficient (omega) measures how much G is like a lattice - or a random graph. Negative values mean G is similar to a lattice whereas - positive values mean G is a random graph. - Values close to 0 mean that G has small-world characteristics. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - niter: integer (optional, default=5) - Approximate number of rewiring per edge to compute the equivalent - random graph. - - nrand: integer (optional, default=10) - Number of random graphs generated to compute the maximal clustering - coefficient (Cr) and average shortest path length (Lr). - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - - Returns - ------- - omega : float - The small-world coefficient (omega) - - Notes - ----- - The implementation is adapted from the algorithm by Telesford et al. [1]_. - - References - ---------- - .. [1] Telesford, Joyce, Hayasaka, Burdette, and Laurienti (2011). - "The Ubiquity of Small-World Networks". - Brain Connectivity. 1 (0038): 367-75. PMC 3604768. PMID 22432451. - doi:10.1089/brain.2011.0038. - """ - import numpy as np - - # Compute the mean clustering coefficient and average shortest path length - # for an equivalent random graph - randMetrics = {"C": [], "L": []} - - # Calculate initial average clustering coefficient which potentially will - # get replaced by higher clustering coefficients from generated lattice - # reference graphs - Cl = nx.average_clustering(G) - - niter_lattice_reference = niter - niter_random_reference = niter * 2 - - for _ in range(nrand): - # Generate random graph - Gr = random_reference(G, niter=niter_random_reference, seed=seed) - randMetrics["L"].append(nx.average_shortest_path_length(Gr)) - - # Generate lattice graph - Gl = lattice_reference(G, niter=niter_lattice_reference, seed=seed) - - # Replace old clustering coefficient, if clustering is higher in - # generated lattice reference - Cl_temp = nx.average_clustering(Gl) - if Cl_temp > Cl: - Cl = Cl_temp - - C = nx.average_clustering(G) - L = nx.average_shortest_path_length(G) - Lr = np.mean(randMetrics["L"]) - - omega = (Lr / L) - (C / Cl) - - return float(omega) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smetric.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smetric.py deleted file mode 100644 index d985aa8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/smetric.py +++ /dev/null @@ -1,30 +0,0 @@ -import networkx as nx - -__all__ = ["s_metric"] - - -@nx._dispatchable -def s_metric(G): - """Returns the s-metric [1]_ of graph. - - The s-metric is defined as the sum of the products ``deg(u) * deg(v)`` - for every edge ``(u, v)`` in `G`. - - Parameters - ---------- - G : graph - The graph used to compute the s-metric. - - Returns - ------- - s : float - The s-metric of the graph. - - References - ---------- - .. [1] Lun Li, David Alderson, John C. Doyle, and Walter Willinger, - Towards a Theory of Scale-Free Graphs: - Definition, Properties, and Implications (Extended Version), 2005. - https://arxiv.org/abs/cond-mat/0501169 - """ - return float(sum(G.degree(u) * G.degree(v) for (u, v) in G.edges())) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/sparsifiers.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/sparsifiers.py deleted file mode 100644 index 5932237..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/sparsifiers.py +++ /dev/null @@ -1,296 +0,0 @@ -"""Functions for computing sparsifiers of graphs.""" - -import math - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ["spanner"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@py_random_state(3) -@nx._dispatchable(edge_attrs="weight", returns_graph=True) -def spanner(G, stretch, weight=None, seed=None): - """Returns a spanner of the given graph with the given stretch. - - A spanner of a graph G = (V, E) with stretch t is a subgraph - H = (V, E_S) such that E_S is a subset of E and the distance between - any pair of nodes in H is at most t times the distance between the - nodes in G. - - Parameters - ---------- - G : NetworkX graph - An undirected simple graph. - - stretch : float - The stretch of the spanner. - - weight : object - The edge attribute to use as distance. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - NetworkX graph - A spanner of the given graph with the given stretch. - - Raises - ------ - ValueError - If a stretch less than 1 is given. - - Notes - ----- - This function implements the spanner algorithm by Baswana and Sen, - see [1]. - - This algorithm is a randomized las vegas algorithm: The expected - running time is O(km) where k = (stretch + 1) // 2 and m is the - number of edges in G. The returned graph is always a spanner of the - given graph with the specified stretch. For weighted graphs the - number of edges in the spanner is O(k * n^(1 + 1 / k)) where k is - defined as above and n is the number of nodes in G. For unweighted - graphs the number of edges is O(n^(1 + 1 / k) + kn). - - References - ---------- - [1] S. Baswana, S. Sen. A Simple and Linear Time Randomized - Algorithm for Computing Sparse Spanners in Weighted Graphs. - Random Struct. Algorithms 30(4): 532-563 (2007). - """ - if stretch < 1: - raise ValueError("stretch must be at least 1") - - k = (stretch + 1) // 2 - - # initialize spanner H with empty edge set - H = nx.empty_graph() - H.add_nodes_from(G.nodes) - - # phase 1: forming the clusters - # the residual graph has V' from the paper as its node set - # and E' from the paper as its edge set - residual_graph = _setup_residual_graph(G, weight) - # clustering is a dictionary that maps nodes in a cluster to the - # cluster center - clustering = {v: v for v in G.nodes} - sample_prob = math.pow(G.number_of_nodes(), -1 / k) - size_limit = 2 * math.pow(G.number_of_nodes(), 1 + 1 / k) - - i = 0 - while i < k - 1: - # step 1: sample centers - sampled_centers = set() - for center in set(clustering.values()): - if seed.random() < sample_prob: - sampled_centers.add(center) - - # combined loop for steps 2 and 3 - edges_to_add = set() - edges_to_remove = set() - new_clustering = {} - for v in residual_graph.nodes: - if clustering[v] in sampled_centers: - continue - - # step 2: find neighboring (sampled) clusters and - # lightest edges to them - lightest_edge_neighbor, lightest_edge_weight = _lightest_edge_dicts( - residual_graph, clustering, v - ) - neighboring_sampled_centers = ( - set(lightest_edge_weight.keys()) & sampled_centers - ) - - # step 3: add edges to spanner - if not neighboring_sampled_centers: - # connect to each neighboring center via lightest edge - for neighbor in lightest_edge_neighbor.values(): - edges_to_add.add((v, neighbor)) - # remove all incident edges - for neighbor in residual_graph.adj[v]: - edges_to_remove.add((v, neighbor)) - - else: # there is a neighboring sampled center - closest_center = min( - neighboring_sampled_centers, key=lightest_edge_weight.get - ) - closest_center_weight = lightest_edge_weight[closest_center] - closest_center_neighbor = lightest_edge_neighbor[closest_center] - - edges_to_add.add((v, closest_center_neighbor)) - new_clustering[v] = closest_center - - # connect to centers with edge weight less than - # closest_center_weight - for center, edge_weight in lightest_edge_weight.items(): - if edge_weight < closest_center_weight: - neighbor = lightest_edge_neighbor[center] - edges_to_add.add((v, neighbor)) - - # remove edges to centers with edge weight less than - # closest_center_weight - for neighbor in residual_graph.adj[v]: - nbr_cluster = clustering[neighbor] - nbr_weight = lightest_edge_weight[nbr_cluster] - if ( - nbr_cluster == closest_center - or nbr_weight < closest_center_weight - ): - edges_to_remove.add((v, neighbor)) - - # check whether iteration added too many edges to spanner, - # if so repeat - if len(edges_to_add) > size_limit: - # an iteration is repeated O(1) times on expectation - continue - - # iteration succeeded - i = i + 1 - - # actually add edges to spanner - for u, v in edges_to_add: - _add_edge_to_spanner(H, residual_graph, u, v, weight) - - # actually delete edges from residual graph - residual_graph.remove_edges_from(edges_to_remove) - - # copy old clustering data to new_clustering - for node, center in clustering.items(): - if center in sampled_centers: - new_clustering[node] = center - clustering = new_clustering - - # step 4: remove intra-cluster edges - for u in residual_graph.nodes: - for v in list(residual_graph.adj[u]): - if clustering[u] == clustering[v]: - residual_graph.remove_edge(u, v) - - # update residual graph node set - for v in list(residual_graph.nodes): - if v not in clustering: - residual_graph.remove_node(v) - - # phase 2: vertex-cluster joining - for v in residual_graph.nodes: - lightest_edge_neighbor, _ = _lightest_edge_dicts(residual_graph, clustering, v) - for neighbor in lightest_edge_neighbor.values(): - _add_edge_to_spanner(H, residual_graph, v, neighbor, weight) - - return H - - -def _setup_residual_graph(G, weight): - """Setup residual graph as a copy of G with unique edges weights. - - The node set of the residual graph corresponds to the set V' from - the Baswana-Sen paper and the edge set corresponds to the set E' - from the paper. - - This function associates distinct weights to the edges of the - residual graph (even for unweighted input graphs), as required by - the algorithm. - - Parameters - ---------- - G : NetworkX graph - An undirected simple graph. - - weight : object - The edge attribute to use as distance. - - Returns - ------- - NetworkX graph - The residual graph used for the Baswana-Sen algorithm. - """ - residual_graph = G.copy() - - # establish unique edge weights, even for unweighted graphs - for u, v in G.edges(): - if not weight: - residual_graph[u][v]["weight"] = (id(u), id(v)) - else: - residual_graph[u][v]["weight"] = (G[u][v][weight], id(u), id(v)) - - return residual_graph - - -def _lightest_edge_dicts(residual_graph, clustering, node): - """Find the lightest edge to each cluster. - - Searches for the minimum-weight edge to each cluster adjacent to - the given node. - - Parameters - ---------- - residual_graph : NetworkX graph - The residual graph used by the Baswana-Sen algorithm. - - clustering : dictionary - The current clustering of the nodes. - - node : node - The node from which the search originates. - - Returns - ------- - lightest_edge_neighbor, lightest_edge_weight : dictionary, dictionary - lightest_edge_neighbor is a dictionary that maps a center C to - a node v in the corresponding cluster such that the edge from - the given node to v is the lightest edge from the given node to - any node in cluster. lightest_edge_weight maps a center C to the - weight of the aforementioned edge. - - Notes - ----- - If a cluster has no node that is adjacent to the given node in the - residual graph then the center of the cluster is not a key in the - returned dictionaries. - """ - lightest_edge_neighbor = {} - lightest_edge_weight = {} - for neighbor in residual_graph.adj[node]: - nbr_center = clustering[neighbor] - weight = residual_graph[node][neighbor]["weight"] - if ( - nbr_center not in lightest_edge_weight - or weight < lightest_edge_weight[nbr_center] - ): - lightest_edge_neighbor[nbr_center] = neighbor - lightest_edge_weight[nbr_center] = weight - return lightest_edge_neighbor, lightest_edge_weight - - -def _add_edge_to_spanner(H, residual_graph, u, v, weight): - """Add the edge {u, v} to the spanner H and take weight from - the residual graph. - - Parameters - ---------- - H : NetworkX graph - The spanner under construction. - - residual_graph : NetworkX graph - The residual graph used by the Baswana-Sen algorithm. The weight - for the edge is taken from this graph. - - u : node - One endpoint of the edge. - - v : node - The other endpoint of the edge. - - weight : object - The edge attribute to use as distance. - """ - H.add_edge(u, v) - if weight: - H[u][v][weight] = residual_graph[u][v]["weight"][0] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/structuralholes.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/structuralholes.py deleted file mode 100644 index bae42d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/structuralholes.py +++ /dev/null @@ -1,283 +0,0 @@ -"""Functions for computing measures of structural holes.""" - -import networkx as nx - -__all__ = ["constraint", "local_constraint", "effective_size"] - - -@nx._dispatchable(edge_attrs="weight") -def mutual_weight(G, u, v, weight=None): - """Returns the sum of the weights of the edge from `u` to `v` and - the edge from `v` to `u` in `G`. - - `weight` is the edge data key that represents the edge weight. If - the specified key is `None` or is not in the edge data for an edge, - that edge is assumed to have weight 1. - - Pre-conditions: `u` and `v` must both be in `G`. - - """ - try: - a_uv = G[u][v].get(weight, 1) - except KeyError: - a_uv = 0 - try: - a_vu = G[v][u].get(weight, 1) - except KeyError: - a_vu = 0 - return a_uv + a_vu - - -@nx._dispatchable(edge_attrs="weight") -def normalized_mutual_weight(G, u, v, norm=sum, weight=None): - """Returns normalized mutual weight of the edges from `u` to `v` - with respect to the mutual weights of the neighbors of `u` in `G`. - - `norm` specifies how the normalization factor is computed. It must - be a function that takes a single argument and returns a number. - The argument will be an iterable of mutual weights - of pairs ``(u, w)``, where ``w`` ranges over each (in- and - out-)neighbor of ``u``. Commons values for `normalization` are - ``sum`` and ``max``. - - `weight` can be ``None`` or a string, if None, all edge weights - are considered equal. Otherwise holds the name of the edge - attribute used as weight. - - """ - scale = norm(mutual_weight(G, u, w, weight) for w in set(nx.all_neighbors(G, u))) - return 0 if scale == 0 else mutual_weight(G, u, v, weight) / scale - - -@nx._dispatchable(edge_attrs="weight") -def effective_size(G, nodes=None, weight=None): - r"""Returns the effective size of all nodes in the graph ``G``. - - The *effective size* of a node's ego network is based on the concept - of redundancy. A person's ego network has redundancy to the extent - that her contacts are connected to each other as well. The - nonredundant part of a person's relationships is the effective - size of her ego network [1]_. Formally, the effective size of a - node $u$, denoted $e(u)$, is defined by - - .. math:: - - e(u) = \sum_{v \in N(u) \setminus \{u\}} - \left(1 - \sum_{w \in N(v)} p_{uw} m_{vw}\right) - - where $N(u)$ is the set of neighbors of $u$ and $p_{uw}$ is the - normalized mutual weight of the (directed or undirected) edges - joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. And $m_{vw}$ - is the mutual weight of $v$ and $w$ divided by $v$ highest mutual - weight with any of its neighbors. The *mutual weight* of $u$ and $v$ - is the sum of the weights of edges joining them (edge weights are - assumed to be one if the graph is unweighted). - - For the case of unweighted and undirected graphs, Borgatti proposed - a simplified formula to compute effective size [2]_ - - .. math:: - - e(u) = n - \frac{2t}{n} - - where `t` is the number of ties in the ego network (not including - ties to ego) and `n` is the number of nodes (excluding ego). - - Parameters - ---------- - G : NetworkX graph - The graph containing ``v``. Directed graphs are treated like - undirected graphs when computing neighbors of ``v``. - - nodes : container, optional - Container of nodes in the graph ``G`` to compute the effective size. - If None, the effective size of every node is computed. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - dict - Dictionary with nodes as keys and the effective size of the node as values. - - Notes - ----- - Burt also defined the related concept of *efficiency* of a node's ego - network, which is its effective size divided by the degree of that - node [1]_. So you can easily compute efficiency: - - >>> G = nx.DiGraph() - >>> G.add_edges_from([(0, 1), (0, 2), (1, 0), (2, 1)]) - >>> esize = nx.effective_size(G) - >>> efficiency = {n: v / G.degree(n) for n, v in esize.items()} - - See also - -------- - constraint - - References - ---------- - .. [1] Burt, Ronald S. - *Structural Holes: The Social Structure of Competition.* - Cambridge: Harvard University Press, 1995. - - .. [2] Borgatti, S. - "Structural Holes: Unpacking Burt's Redundancy Measures" - CONNECTIONS 20(1):35-38. - http://www.analytictech.com/connections/v20(1)/holes.htm - - """ - - def redundancy(G, u, v, weight=None): - nmw = normalized_mutual_weight - r = sum( - nmw(G, u, w, weight=weight) * nmw(G, v, w, norm=max, weight=weight) - for w in set(nx.all_neighbors(G, u)) - ) - return 1 - r - - effective_size = {} - if nodes is None: - nodes = G - # Use Borgatti's simplified formula for unweighted and undirected graphs - if not G.is_directed() and weight is None: - for v in nodes: - # Effective size is not defined for isolated nodes - if len(G[v]) == 0: - effective_size[v] = float("nan") - continue - E = nx.ego_graph(G, v, center=False, undirected=True) - effective_size[v] = len(E) - (2 * E.size()) / len(E) - else: - for v in nodes: - # Effective size is not defined for isolated nodes - if len(G[v]) == 0: - effective_size[v] = float("nan") - continue - effective_size[v] = sum( - redundancy(G, v, u, weight) for u in set(nx.all_neighbors(G, v)) - ) - return effective_size - - -@nx._dispatchable(edge_attrs="weight") -def constraint(G, nodes=None, weight=None): - r"""Returns the constraint on all nodes in the graph ``G``. - - The *constraint* is a measure of the extent to which a node *v* is - invested in those nodes that are themselves invested in the - neighbors of *v*. Formally, the *constraint on v*, denoted `c(v)`, - is defined by - - .. math:: - - c(v) = \sum_{w \in N(v) \setminus \{v\}} \ell(v, w) - - where $N(v)$ is the subset of the neighbors of `v` that are either - predecessors or successors of `v` and $\ell(v, w)$ is the local - constraint on `v` with respect to `w` [1]_. For the definition of local - constraint, see :func:`local_constraint`. - - Parameters - ---------- - G : NetworkX graph - The graph containing ``v``. This can be either directed or undirected. - - nodes : container, optional - Container of nodes in the graph ``G`` to compute the constraint. If - None, the constraint of every node is computed. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - dict - Dictionary with nodes as keys and the constraint on the node as values. - - See also - -------- - local_constraint - - References - ---------- - .. [1] Burt, Ronald S. - "Structural holes and good ideas". - American Journal of Sociology (110): 349–399. - - """ - if nodes is None: - nodes = G - constraint = {} - for v in nodes: - # Constraint is not defined for isolated nodes - if len(G[v]) == 0: - constraint[v] = float("nan") - continue - constraint[v] = sum( - local_constraint(G, v, n, weight) for n in set(nx.all_neighbors(G, v)) - ) - return constraint - - -@nx._dispatchable(edge_attrs="weight") -def local_constraint(G, u, v, weight=None): - r"""Returns the local constraint on the node ``u`` with respect to - the node ``v`` in the graph ``G``. - - Formally, the *local constraint on u with respect to v*, denoted - $\ell(u, v)$, is defined by - - .. math:: - - \ell(u, v) = \left(p_{uv} + \sum_{w \in N(v)} p_{uw} p_{wv}\right)^2, - - where $N(v)$ is the set of neighbors of $v$ and $p_{uv}$ is the - normalized mutual weight of the (directed or undirected) edges - joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. The *mutual - weight* of $u$ and $v$ is the sum of the weights of edges joining - them (edge weights are assumed to be one if the graph is - unweighted). - - Parameters - ---------- - G : NetworkX graph - The graph containing ``u`` and ``v``. This can be either - directed or undirected. - - u : node - A node in the graph ``G``. - - v : node - A node in the graph ``G``. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - float - The constraint of the node ``v`` in the graph ``G``. - - See also - -------- - constraint - - References - ---------- - .. [1] Burt, Ronald S. - "Structural holes and good ideas". - American Journal of Sociology (110): 349–399. - - """ - nmw = normalized_mutual_weight - direct = nmw(G, u, v, weight=weight) - indirect = sum( - nmw(G, u, w, weight=weight) * nmw(G, w, v, weight=weight) - for w in set(nx.all_neighbors(G, u)) - ) - return (direct + indirect) ** 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/summarization.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/summarization.py deleted file mode 100644 index 23db8da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/summarization.py +++ /dev/null @@ -1,564 +0,0 @@ -""" -Graph summarization finds smaller representations of graphs resulting in faster -runtime of algorithms, reduced storage needs, and noise reduction. -Summarization has applications in areas such as visualization, pattern mining, -clustering and community detection, and more. Core graph summarization -techniques are grouping/aggregation, bit-compression, -simplification/sparsification, and influence based. Graph summarization -algorithms often produce either summary graphs in the form of supergraphs or -sparsified graphs, or a list of independent structures. Supergraphs are the -most common product, which consist of supernodes and original nodes and are -connected by edges and superedges, which represent aggregate edges between -nodes and supernodes. - -Grouping/aggregation based techniques compress graphs by representing -close/connected nodes and edges in a graph by a single node/edge in a -supergraph. Nodes can be grouped together into supernodes based on their -structural similarities or proximity within a graph to reduce the total number -of nodes in a graph. Edge-grouping techniques group edges into lossy/lossless -nodes called compressor or virtual nodes to reduce the total number of edges in -a graph. Edge-grouping techniques can be lossless, meaning that they can be -used to re-create the original graph, or techniques can be lossy, requiring -less space to store the summary graph, but at the expense of lower -reconstruction accuracy of the original graph. - -Bit-compression techniques minimize the amount of information needed to -describe the original graph, while revealing structural patterns in the -original graph. The two-part minimum description length (MDL) is often used to -represent the model and the original graph in terms of the model. A key -difference between graph compression and graph summarization is that graph -summarization focuses on finding structural patterns within the original graph, -whereas graph compression focuses on compressions the original graph to be as -small as possible. **NOTE**: Some bit-compression methods exist solely to -compress a graph without creating a summary graph or finding comprehensible -structural patterns. - -Simplification/Sparsification techniques attempt to create a sparse -representation of a graph by removing unimportant nodes and edges from the -graph. Sparsified graphs differ from supergraphs created by -grouping/aggregation by only containing a subset of the original nodes and -edges of the original graph. - -Influence based techniques aim to find a high-level description of influence -propagation in a large graph. These methods are scarce and have been mostly -applied to social graphs. - -*dedensification* is a grouping/aggregation based technique to compress the -neighborhoods around high-degree nodes in unweighted graphs by adding -compressor nodes that summarize multiple edges of the same type to -high-degree nodes (nodes with a degree greater than a given threshold). -Dedensification was developed for the purpose of increasing performance of -query processing around high-degree nodes in graph databases and enables direct -operations on the compressed graph. The structural patterns surrounding -high-degree nodes in the original is preserved while using fewer edges and -adding a small number of compressor nodes. The degree of nodes present in the -original graph is also preserved. The current implementation of dedensification -supports graphs with one edge type. - -For more information on graph summarization, see `Graph Summarization Methods -and Applications: A Survey `_ -""" - -from collections import Counter, defaultdict - -import networkx as nx - -__all__ = ["dedensify", "snap_aggregation"] - - -@nx._dispatchable(mutates_input={"not copy": 3}, returns_graph=True) -def dedensify(G, threshold, prefix=None, copy=True): - """Compresses neighborhoods around high-degree nodes - - Reduces the number of edges to high-degree nodes by adding compressor nodes - that summarize multiple edges of the same type to high-degree nodes (nodes - with a degree greater than a given threshold). Dedensification also has - the added benefit of reducing the number of edges around high-degree nodes. - The implementation currently supports graphs with a single edge type. - - Parameters - ---------- - G: graph - A networkx graph - threshold: int - Minimum degree threshold of a node to be considered a high degree node. - The threshold must be greater than or equal to 2. - prefix: str or None, optional (default: None) - An optional prefix for denoting compressor nodes - copy: bool, optional (default: True) - Indicates if dedensification should be done inplace - - Returns - ------- - dedensified networkx graph : (graph, set) - 2-tuple of the dedensified graph and set of compressor nodes - - Notes - ----- - According to the algorithm in [1]_, removes edges in a graph by - compressing/decompressing the neighborhoods around high degree nodes by - adding compressor nodes that summarize multiple edges of the same type - to high-degree nodes. Dedensification will only add a compressor node when - doing so will reduce the total number of edges in the given graph. This - implementation currently supports graphs with a single edge type. - - Examples - -------- - Dedensification will only add compressor nodes when doing so would result - in fewer edges:: - - >>> original_graph = nx.DiGraph() - >>> original_graph.add_nodes_from( - ... ["1", "2", "3", "4", "5", "6", "A", "B", "C"] - ... ) - >>> original_graph.add_edges_from( - ... [ - ... ("1", "C"), ("1", "B"), - ... ("2", "C"), ("2", "B"), ("2", "A"), - ... ("3", "B"), ("3", "A"), ("3", "6"), - ... ("4", "C"), ("4", "B"), ("4", "A"), - ... ("5", "B"), ("5", "A"), - ... ("6", "5"), - ... ("A", "6") - ... ] - ... ) - >>> c_graph, c_nodes = nx.dedensify(original_graph, threshold=2) - >>> original_graph.number_of_edges() - 15 - >>> c_graph.number_of_edges() - 14 - - A dedensified, directed graph can be "densified" to reconstruct the - original graph:: - - >>> original_graph = nx.DiGraph() - >>> original_graph.add_nodes_from( - ... ["1", "2", "3", "4", "5", "6", "A", "B", "C"] - ... ) - >>> original_graph.add_edges_from( - ... [ - ... ("1", "C"), ("1", "B"), - ... ("2", "C"), ("2", "B"), ("2", "A"), - ... ("3", "B"), ("3", "A"), ("3", "6"), - ... ("4", "C"), ("4", "B"), ("4", "A"), - ... ("5", "B"), ("5", "A"), - ... ("6", "5"), - ... ("A", "6") - ... ] - ... ) - >>> c_graph, c_nodes = nx.dedensify(original_graph, threshold=2) - >>> # re-densifies the compressed graph into the original graph - >>> for c_node in c_nodes: - ... all_neighbors = set(nx.all_neighbors(c_graph, c_node)) - ... out_neighbors = set(c_graph.neighbors(c_node)) - ... for out_neighbor in out_neighbors: - ... c_graph.remove_edge(c_node, out_neighbor) - ... in_neighbors = all_neighbors - out_neighbors - ... for in_neighbor in in_neighbors: - ... c_graph.remove_edge(in_neighbor, c_node) - ... for out_neighbor in out_neighbors: - ... c_graph.add_edge(in_neighbor, out_neighbor) - ... c_graph.remove_node(c_node) - ... - >>> nx.is_isomorphic(original_graph, c_graph) - True - - References - ---------- - .. [1] Maccioni, A., & Abadi, D. J. (2016, August). - Scalable pattern matching over compressed graphs via dedensification. - In Proceedings of the 22nd ACM SIGKDD International Conference on - Knowledge Discovery and Data Mining (pp. 1755-1764). - http://www.cs.umd.edu/~abadi/papers/graph-dedense.pdf - """ - if threshold < 2: - raise nx.NetworkXError("The degree threshold must be >= 2") - - degrees = G.in_degree if G.is_directed() else G.degree - # Group nodes based on degree threshold - high_degree_nodes = {n for n, d in degrees if d > threshold} - low_degree_nodes = G.nodes() - high_degree_nodes - - auxiliary = {} - for node in G: - high_degree_nbrs = frozenset(high_degree_nodes & set(G[node])) - if high_degree_nbrs: - if high_degree_nbrs in auxiliary: - auxiliary[high_degree_nbrs].add(node) - else: - auxiliary[high_degree_nbrs] = {node} - - if copy: - G = G.copy() - - compressor_nodes = set() - for index, (high_degree_nodes, low_degree_nodes) in enumerate(auxiliary.items()): - low_degree_node_count = len(low_degree_nodes) - high_degree_node_count = len(high_degree_nodes) - old_edges = high_degree_node_count * low_degree_node_count - new_edges = high_degree_node_count + low_degree_node_count - if old_edges <= new_edges: - continue - compression_node = "".join(str(node) for node in high_degree_nodes) - if prefix: - compression_node = str(prefix) + compression_node - for node in low_degree_nodes: - for high_node in high_degree_nodes: - if G.has_edge(node, high_node): - G.remove_edge(node, high_node) - - G.add_edge(node, compression_node) - for node in high_degree_nodes: - G.add_edge(compression_node, node) - compressor_nodes.add(compression_node) - return G, compressor_nodes - - -def _snap_build_graph( - G, - groups, - node_attributes, - edge_attributes, - neighbor_info, - edge_types, - prefix, - supernode_attribute, - superedge_attribute, -): - """ - Build the summary graph from the data structures produced in the SNAP aggregation algorithm - - Used in the SNAP aggregation algorithm to build the output summary graph and supernode - lookup dictionary. This process uses the original graph and the data structures to - create the supernodes with the correct node attributes, and the superedges with the correct - edge attributes - - Parameters - ---------- - G: networkx.Graph - the original graph to be summarized - groups: dict - A dictionary of unique group IDs and their corresponding node groups - node_attributes: iterable - An iterable of the node attributes considered in the summarization process - edge_attributes: iterable - An iterable of the edge attributes considered in the summarization process - neighbor_info: dict - A data structure indicating the number of edges a node has with the - groups in the current summarization of each edge type - edge_types: dict - dictionary of edges in the graph and their corresponding attributes recognized - in the summarization - prefix: string - The prefix to be added to all supernodes - supernode_attribute: str - The node attribute for recording the supernode groupings of nodes - superedge_attribute: str - The edge attribute for recording the edge types represented by superedges - - Returns - ------- - summary graph: Networkx graph - """ - output = G.__class__() - node_label_lookup = {} - for index, group_id in enumerate(groups): - group_set = groups[group_id] - supernode = f"{prefix}{index}" - node_label_lookup[group_id] = supernode - supernode_attributes = { - attr: G.nodes[next(iter(group_set))][attr] for attr in node_attributes - } - supernode_attributes[supernode_attribute] = group_set - output.add_node(supernode, **supernode_attributes) - - for group_id in groups: - group_set = groups[group_id] - source_supernode = node_label_lookup[group_id] - for other_group, group_edge_types in neighbor_info[ - next(iter(group_set)) - ].items(): - if group_edge_types: - target_supernode = node_label_lookup[other_group] - summary_graph_edge = (source_supernode, target_supernode) - - edge_types = [ - dict(zip(edge_attributes, edge_type)) - for edge_type in group_edge_types - ] - - has_edge = output.has_edge(*summary_graph_edge) - if output.is_multigraph(): - if not has_edge: - for edge_type in edge_types: - output.add_edge(*summary_graph_edge, **edge_type) - elif not output.is_directed(): - existing_edge_data = output.get_edge_data(*summary_graph_edge) - for edge_type in edge_types: - if edge_type not in existing_edge_data.values(): - output.add_edge(*summary_graph_edge, **edge_type) - else: - superedge_attributes = {superedge_attribute: edge_types} - output.add_edge(*summary_graph_edge, **superedge_attributes) - - return output - - -def _snap_eligible_group(G, groups, group_lookup, edge_types): - """ - Determines if a group is eligible to be split. - - A group is eligible to be split if all nodes in the group have edges of the same type(s) - with the same other groups. - - Parameters - ---------- - G: graph - graph to be summarized - groups: dict - A dictionary of unique group IDs and their corresponding node groups - group_lookup: dict - dictionary of nodes and their current corresponding group ID - edge_types: dict - dictionary of edges in the graph and their corresponding attributes recognized - in the summarization - - Returns - ------- - tuple: group ID to split, and neighbor-groups participation_counts data structure - """ - nbr_info = {node: {gid: Counter() for gid in groups} for node in group_lookup} - for group_id in groups: - current_group = groups[group_id] - - # build nbr_info for nodes in group - for node in current_group: - nbr_info[node] = {group_id: Counter() for group_id in groups} - edges = G.edges(node, keys=True) if G.is_multigraph() else G.edges(node) - for edge in edges: - neighbor = edge[1] - edge_type = edge_types[edge] - neighbor_group_id = group_lookup[neighbor] - nbr_info[node][neighbor_group_id][edge_type] += 1 - - # check if group_id is eligible to be split - group_size = len(current_group) - for other_group_id in groups: - edge_counts = Counter() - for node in current_group: - edge_counts.update(nbr_info[node][other_group_id].keys()) - - if not all(count == group_size for count in edge_counts.values()): - # only the nbr_info of the returned group_id is required for handling group splits - return group_id, nbr_info - - # if no eligible groups, complete nbr_info is calculated - return None, nbr_info - - -def _snap_split(groups, neighbor_info, group_lookup, group_id): - """ - Splits a group based on edge types and updates the groups accordingly - - Splits the group with the given group_id based on the edge types - of the nodes so that each new grouping will all have the same - edges with other nodes. - - Parameters - ---------- - groups: dict - A dictionary of unique group IDs and their corresponding node groups - neighbor_info: dict - A data structure indicating the number of edges a node has with the - groups in the current summarization of each edge type - edge_types: dict - dictionary of edges in the graph and their corresponding attributes recognized - in the summarization - group_lookup: dict - dictionary of nodes and their current corresponding group ID - group_id: object - ID of group to be split - - Returns - ------- - dict - The updated groups based on the split - """ - new_group_mappings = defaultdict(set) - for node in groups[group_id]: - signature = tuple( - frozenset(edge_types) for edge_types in neighbor_info[node].values() - ) - new_group_mappings[signature].add(node) - - # leave the biggest new_group as the original group - new_groups = sorted(new_group_mappings.values(), key=len) - for new_group in new_groups[:-1]: - # Assign unused integer as the new_group_id - # ids are tuples, so will not interact with the original group_ids - new_group_id = len(groups) - groups[new_group_id] = new_group - groups[group_id] -= new_group - for node in new_group: - group_lookup[node] = new_group_id - - return groups - - -@nx._dispatchable( - node_attrs="[node_attributes]", edge_attrs="[edge_attributes]", returns_graph=True -) -def snap_aggregation( - G, - node_attributes, - edge_attributes=(), - prefix="Supernode-", - supernode_attribute="group", - superedge_attribute="types", -): - """Creates a summary graph based on attributes and connectivity. - - This function uses the Summarization by Grouping Nodes on Attributes - and Pairwise edges (SNAP) algorithm for summarizing a given - graph by grouping nodes by node attributes and their edge attributes - into supernodes in a summary graph. This name SNAP should not be - confused with the Stanford Network Analysis Project (SNAP). - - Here is a high-level view of how this algorithm works: - - 1) Group nodes by node attribute values. - - 2) Iteratively split groups until all nodes in each group have edges - to nodes in the same groups. That is, until all the groups are homogeneous - in their member nodes' edges to other groups. For example, - if all the nodes in group A only have edge to nodes in group B, then the - group is homogeneous and does not need to be split. If all nodes in group B - have edges with nodes in groups {A, C}, but some also have edges with other - nodes in B, then group B is not homogeneous and needs to be split into - groups have edges with {A, C} and a group of nodes having - edges with {A, B, C}. This way, viewers of the summary graph can - assume that all nodes in the group have the exact same node attributes and - the exact same edges. - - 3) Build the output summary graph, where the groups are represented by - super-nodes. Edges represent the edges shared between all the nodes in each - respective groups. - - A SNAP summary graph can be used to visualize graphs that are too large to display - or visually analyze, or to efficiently identify sets of similar nodes with similar connectivity - patterns to other sets of similar nodes based on specified node and/or edge attributes in a graph. - - Parameters - ---------- - G: graph - Networkx Graph to be summarized - node_attributes: iterable, required - An iterable of the node attributes used to group nodes in the summarization process. Nodes - with the same values for these attributes will be grouped together in the summary graph. - edge_attributes: iterable, optional - An iterable of the edge attributes considered in the summarization process. If provided, unique - combinations of the attribute values found in the graph are used to - determine the edge types in the graph. If not provided, all edges - are considered to be of the same type. - prefix: str - The prefix used to denote supernodes in the summary graph. Defaults to 'Supernode-'. - supernode_attribute: str - The node attribute for recording the supernode groupings of nodes. Defaults to 'group'. - superedge_attribute: str - The edge attribute for recording the edge types of multiple edges. Defaults to 'types'. - - Returns - ------- - networkx.Graph: summary graph - - Examples - -------- - SNAP aggregation takes a graph and summarizes it in the context of user-provided - node and edge attributes such that a viewer can more easily extract and - analyze the information represented by the graph - - >>> nodes = { - ... "A": dict(color="Red"), - ... "B": dict(color="Red"), - ... "C": dict(color="Red"), - ... "D": dict(color="Red"), - ... "E": dict(color="Blue"), - ... "F": dict(color="Blue"), - ... } - >>> edges = [ - ... ("A", "E", "Strong"), - ... ("B", "F", "Strong"), - ... ("C", "E", "Weak"), - ... ("D", "F", "Weak"), - ... ] - >>> G = nx.Graph() - >>> for node in nodes: - ... attributes = nodes[node] - ... G.add_node(node, **attributes) - >>> for source, target, type in edges: - ... G.add_edge(source, target, type=type) - >>> node_attributes = ("color",) - >>> edge_attributes = ("type",) - >>> summary_graph = nx.snap_aggregation( - ... G, node_attributes=node_attributes, edge_attributes=edge_attributes - ... ) - - Notes - ----- - The summary graph produced is called a maximum Attribute-edge - compatible (AR-compatible) grouping. According to [1]_, an - AR-compatible grouping means that all nodes in each group have the same - exact node attribute values and the same exact edges and - edge types to one or more nodes in the same groups. The maximal - AR-compatible grouping is the grouping with the minimal cardinality. - - The AR-compatible grouping is the most detailed grouping provided by - any of the SNAP algorithms. - - References - ---------- - .. [1] Y. Tian, R. A. Hankins, and J. M. Patel. Efficient aggregation - for graph summarization. In Proc. 2008 ACM-SIGMOD Int. Conf. - Management of Data (SIGMOD’08), pages 567–580, Vancouver, Canada, - June 2008. - """ - edge_types = { - edge: tuple(attrs.get(attr) for attr in edge_attributes) - for edge, attrs in G.edges.items() - } - if not G.is_directed(): - if G.is_multigraph(): - # list is needed to avoid mutating while iterating - edges = [((v, u, k), etype) for (u, v, k), etype in edge_types.items()] - else: - # list is needed to avoid mutating while iterating - edges = [((v, u), etype) for (u, v), etype in edge_types.items()] - edge_types.update(edges) - - group_lookup = { - node: tuple(attrs[attr] for attr in node_attributes) - for node, attrs in G.nodes.items() - } - groups = defaultdict(set) - for node, node_type in group_lookup.items(): - groups[node_type].add(node) - - eligible_group_id, nbr_info = _snap_eligible_group( - G, groups, group_lookup, edge_types - ) - while eligible_group_id: - groups = _snap_split(groups, nbr_info, group_lookup, eligible_group_id) - eligible_group_id, nbr_info = _snap_eligible_group( - G, groups, group_lookup, edge_types - ) - return _snap_build_graph( - G, - groups, - node_attributes, - edge_attributes, - nbr_info, - edge_types, - prefix, - supernode_attribute, - superedge_attribute, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/swap.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/swap.py deleted file mode 100644 index cb3cc1c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/swap.py +++ /dev/null @@ -1,406 +0,0 @@ -"""Swap edges in a graph.""" - -import math - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ["double_edge_swap", "connected_double_edge_swap", "directed_edge_swap"] - - -@nx.utils.not_implemented_for("undirected") -@py_random_state(3) -@nx._dispatchable(mutates_input=True, returns_graph=True) -def directed_edge_swap(G, *, nswap=1, max_tries=100, seed=None): - """Swap three edges in a directed graph while keeping the node degrees fixed. - - A directed edge swap swaps three edges such that a -> b -> c -> d becomes - a -> c -> b -> d. This pattern of swapping allows all possible states with the - same in- and out-degree distribution in a directed graph to be reached. - - If the swap would create parallel edges (e.g. if a -> c already existed in the - previous example), another attempt is made to find a suitable trio of edges. - - Parameters - ---------- - G : DiGraph - A directed graph - - nswap : integer (optional, default=1) - Number of three-edge (directed) swaps to perform - - max_tries : integer (optional, default=100) - Maximum number of attempts to swap edges - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : DiGraph - The graph after the edges are swapped. - - Raises - ------ - NetworkXError - If `G` is not directed, or - If nswap > max_tries, or - If there are fewer than 4 nodes or 3 edges in `G`. - NetworkXAlgorithmError - If the number of swap attempts exceeds `max_tries` before `nswap` swaps are made - - Notes - ----- - Does not enforce any connectivity constraints. - - The graph G is modified in place. - - A later swap is allowed to undo a previous swap. - - References - ---------- - .. [1] Erdős, Péter L., et al. “A Simple Havel-Hakimi Type Algorithm to Realize - Graphical Degree Sequences of Directed Graphs.†ArXiv:0905.4913 [Math], - Jan. 2010. https://doi.org/10.48550/arXiv.0905.4913. - Published 2010 in Elec. J. Combinatorics (17(1)). R66. - http://www.combinatorics.org/Volume_17/PDF/v17i1r66.pdf - .. [2] “Combinatorics - Reaching All Possible Simple Directed Graphs with a given - Degree Sequence with 2-Edge Swaps.†Mathematics Stack Exchange, - https://math.stackexchange.com/questions/22272/. Accessed 30 May 2022. - """ - if nswap > max_tries: - raise nx.NetworkXError("Number of swaps > number of tries allowed.") - if len(G) < 4: - raise nx.NetworkXError("DiGraph has fewer than four nodes.") - if len(G.edges) < 3: - raise nx.NetworkXError("DiGraph has fewer than 3 edges") - - # Instead of choosing uniformly at random from a generated edge list, - # this algorithm chooses nonuniformly from the set of nodes with - # probability weighted by degree. - tries = 0 - swapcount = 0 - keys, degrees = zip(*G.degree()) # keys, degree - cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree - discrete_sequence = nx.utils.discrete_sequence - - while swapcount < nswap: - # choose source node index from discrete distribution - start_index = discrete_sequence(1, cdistribution=cdf, seed=seed)[0] - start = keys[start_index] - tries += 1 - - if tries > max_tries: - msg = f"Maximum number of swap attempts ({tries}) exceeded before desired swaps achieved ({nswap})." - raise nx.NetworkXAlgorithmError(msg) - - # If the given node doesn't have any out edges, then there isn't anything to swap - if G.out_degree(start) == 0: - continue - second = seed.choice(list(G.succ[start])) - if start == second: - continue - - if G.out_degree(second) == 0: - continue - third = seed.choice(list(G.succ[second])) - if second == third: - continue - - if G.out_degree(third) == 0: - continue - fourth = seed.choice(list(G.succ[third])) - if third == fourth: - continue - - if ( - third not in G.succ[start] - and fourth not in G.succ[second] - and second not in G.succ[third] - ): - # Swap nodes - G.add_edge(start, third) - G.add_edge(third, second) - G.add_edge(second, fourth) - G.remove_edge(start, second) - G.remove_edge(second, third) - G.remove_edge(third, fourth) - swapcount += 1 - - return G - - -@py_random_state(3) -@nx._dispatchable(mutates_input=True, returns_graph=True) -def double_edge_swap(G, nswap=1, max_tries=100, seed=None): - """Swap two edges in the graph while keeping the node degrees fixed. - - A double-edge swap removes two randomly chosen edges u-v and x-y - and creates the new edges u-x and v-y:: - - u--v u v - becomes | | - x--y x y - - If either the edge u-x or v-y already exist no swap is performed - and another attempt is made to find a suitable edge pair. - - Parameters - ---------- - G : graph - An undirected graph - - nswap : integer (optional, default=1) - Number of double-edge swaps to perform - - max_tries : integer (optional) - Maximum number of attempts to swap edges - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The graph after double edge swaps. - - Raises - ------ - NetworkXError - If `G` is directed, or - If `nswap` > `max_tries`, or - If there are fewer than 4 nodes or 2 edges in `G`. - NetworkXAlgorithmError - If the number of swap attempts exceeds `max_tries` before `nswap` swaps are made - - Notes - ----- - Does not enforce any connectivity constraints. - - The graph G is modified in place. - """ - if G.is_directed(): - raise nx.NetworkXError( - "double_edge_swap() not defined for directed graphs. Use directed_edge_swap instead." - ) - if nswap > max_tries: - raise nx.NetworkXError("Number of swaps > number of tries allowed.") - if len(G) < 4: - raise nx.NetworkXError("Graph has fewer than four nodes.") - if len(G.edges) < 2: - raise nx.NetworkXError("Graph has fewer than 2 edges") - # Instead of choosing uniformly at random from a generated edge list, - # this algorithm chooses nonuniformly from the set of nodes with - # probability weighted by degree. - n = 0 - swapcount = 0 - keys, degrees = zip(*G.degree()) # keys, degree - cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree - discrete_sequence = nx.utils.discrete_sequence - while swapcount < nswap: - # if random.random() < 0.5: continue # trick to avoid periodicities? - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ui, xi) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ui == xi: - continue # same source, skip - u = keys[ui] # convert index to label - x = keys[xi] - # choose target uniformly from neighbors - v = seed.choice(list(G[u])) - y = seed.choice(list(G[x])) - if v == y: - continue # same target, skip - if (x not in G[u]) and (y not in G[v]): # don't create parallel edges - G.add_edge(u, x) - G.add_edge(v, y) - G.remove_edge(u, v) - G.remove_edge(x, y) - swapcount += 1 - if n >= max_tries: - e = ( - f"Maximum number of swap attempts ({n}) exceeded " - f"before desired swaps achieved ({nswap})." - ) - raise nx.NetworkXAlgorithmError(e) - n += 1 - return G - - -@py_random_state(3) -@nx._dispatchable(mutates_input=True) -def connected_double_edge_swap(G, nswap=1, _window_threshold=3, seed=None): - """Attempts the specified number of double-edge swaps in the graph `G`. - - A double-edge swap removes two randomly chosen edges `(u, v)` and `(x, - y)` and creates the new edges `(u, x)` and `(v, y)`:: - - u--v u v - becomes | | - x--y x y - - If either `(u, x)` or `(v, y)` already exist, then no swap is performed - so the actual number of swapped edges is always *at most* `nswap`. - - Parameters - ---------- - G : graph - An undirected graph - - nswap : integer (optional, default=1) - Number of double-edge swaps to perform - - _window_threshold : integer - - The window size below which connectedness of the graph will be checked - after each swap. - - The "window" in this function is a dynamically updated integer that - represents the number of swap attempts to make before checking if the - graph remains connected. It is an optimization used to decrease the - running time of the algorithm in exchange for increased complexity of - implementation. - - If the window size is below this threshold, then the algorithm checks - after each swap if the graph remains connected by checking if there is a - path joining the two nodes whose edge was just removed. If the window - size is above this threshold, then the algorithm performs do all the - swaps in the window and only then check if the graph is still connected. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - int - The number of successful swaps - - Raises - ------ - - NetworkXError - - If the input graph is not connected, or if the graph has fewer than four - nodes. - - Notes - ----- - - The initial graph `G` must be connected, and the resulting graph is - connected. The graph `G` is modified in place. - - References - ---------- - .. [1] C. Gkantsidis and M. Mihail and E. Zegura, - The Markov chain simulation method for generating connected - power law random graphs, 2003. - http://citeseer.ist.psu.edu/gkantsidis03markov.html - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected") - if len(G) < 4: - raise nx.NetworkXError("Graph has fewer than four nodes.") - n = 0 - swapcount = 0 - deg = G.degree() - # Label key for nodes - dk = [n for n, d in G.degree()] - cdf = nx.utils.cumulative_distribution([d for n, d in G.degree()]) - discrete_sequence = nx.utils.discrete_sequence - window = 1 - while n < nswap: - wcount = 0 - swapped = [] - # If the window is small, we just check each time whether the graph is - # connected by checking if the nodes that were just separated are still - # connected. - if window < _window_threshold: - # This Boolean keeps track of whether there was a failure or not. - fail = False - while wcount < window and n < nswap: - # Pick two random edges without creating the edge list. Choose - # source nodes from the discrete degree distribution. - (ui, xi) = discrete_sequence(2, cdistribution=cdf, seed=seed) - # If the source nodes are the same, skip this pair. - if ui == xi: - continue - # Convert an index to a node label. - u = dk[ui] - x = dk[xi] - # Choose targets uniformly from neighbors. - v = seed.choice(list(G.neighbors(u))) - y = seed.choice(list(G.neighbors(x))) - # If the target nodes are the same, skip this pair. - if v == y: - continue - if x not in G[u] and y not in G[v]: - G.remove_edge(u, v) - G.remove_edge(x, y) - G.add_edge(u, x) - G.add_edge(v, y) - swapped.append((u, v, x, y)) - swapcount += 1 - n += 1 - # If G remains connected... - if nx.has_path(G, u, v): - wcount += 1 - # Otherwise, undo the changes. - else: - G.add_edge(u, v) - G.add_edge(x, y) - G.remove_edge(u, x) - G.remove_edge(v, y) - swapcount -= 1 - fail = True - # If one of the swaps failed, reduce the window size. - if fail: - window = math.ceil(window / 2) - else: - window += 1 - # If the window is large, then there is a good chance that a bunch of - # swaps will work. It's quicker to do all those swaps first and then - # check if the graph remains connected. - else: - while wcount < window and n < nswap: - # Pick two random edges without creating the edge list. Choose - # source nodes from the discrete degree distribution. - (ui, xi) = discrete_sequence(2, cdistribution=cdf, seed=seed) - # If the source nodes are the same, skip this pair. - if ui == xi: - continue - # Convert an index to a node label. - u = dk[ui] - x = dk[xi] - # Choose targets uniformly from neighbors. - v = seed.choice(list(G.neighbors(u))) - y = seed.choice(list(G.neighbors(x))) - # If the target nodes are the same, skip this pair. - if v == y: - continue - if x not in G[u] and y not in G[v]: - G.remove_edge(u, v) - G.remove_edge(x, y) - G.add_edge(u, x) - G.add_edge(v, y) - swapped.append((u, v, x, y)) - swapcount += 1 - n += 1 - wcount += 1 - # If the graph remains connected, increase the window size. - if nx.is_connected(G): - window += 1 - # Otherwise, undo the changes from the previous window and decrease - # the window size. - else: - while swapped: - (u, v, x, y) = swapped.pop() - G.add_edge(u, v) - G.add_edge(x, y) - G.remove_edge(u, x) - G.remove_edge(v, y) - swapcount -= 1 - window = math.ceil(window / 2) - return swapcount diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_asteroidal.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_asteroidal.py deleted file mode 100644 index 67131b2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_asteroidal.py +++ /dev/null @@ -1,23 +0,0 @@ -import networkx as nx - - -def test_is_at_free(): - is_at_free = nx.asteroidal.is_at_free - - cycle = nx.cycle_graph(6) - assert not is_at_free(cycle) - - path = nx.path_graph(6) - assert is_at_free(path) - - small_graph = nx.complete_graph(2) - assert is_at_free(small_graph) - - petersen = nx.petersen_graph() - assert not is_at_free(petersen) - - clique = nx.complete_graph(6) - assert is_at_free(clique) - - line_clique = nx.line_graph(clique) - assert not is_at_free(line_clique) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_boundary.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_boundary.py deleted file mode 100644 index 856be46..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_boundary.py +++ /dev/null @@ -1,154 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.boundary` module.""" - -from itertools import combinations - -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.utils import edges_equal - - -class TestNodeBoundary: - """Unit tests for the :func:`~networkx.node_boundary` function.""" - - def test_null_graph(self): - """Tests that the null graph has empty node boundaries.""" - null = nx.null_graph() - assert nx.node_boundary(null, []) == set() - assert nx.node_boundary(null, [], []) == set() - assert nx.node_boundary(null, [1, 2, 3]) == set() - assert nx.node_boundary(null, [1, 2, 3], [4, 5, 6]) == set() - assert nx.node_boundary(null, [1, 2, 3], [3, 4, 5]) == set() - - def test_path_graph(self): - P10 = cnlti(nx.path_graph(10), first_label=1) - assert nx.node_boundary(P10, []) == set() - assert nx.node_boundary(P10, [], []) == set() - assert nx.node_boundary(P10, [1, 2, 3]) == {4} - assert nx.node_boundary(P10, [4, 5, 6]) == {3, 7} - assert nx.node_boundary(P10, [3, 4, 5, 6, 7]) == {2, 8} - assert nx.node_boundary(P10, [8, 9, 10]) == {7} - assert nx.node_boundary(P10, [4, 5, 6], [9, 10]) == set() - - def test_complete_graph(self): - K10 = cnlti(nx.complete_graph(10), first_label=1) - assert nx.node_boundary(K10, []) == set() - assert nx.node_boundary(K10, [], []) == set() - assert nx.node_boundary(K10, [1, 2, 3]) == {4, 5, 6, 7, 8, 9, 10} - assert nx.node_boundary(K10, [4, 5, 6]) == {1, 2, 3, 7, 8, 9, 10} - assert nx.node_boundary(K10, [3, 4, 5, 6, 7]) == {1, 2, 8, 9, 10} - assert nx.node_boundary(K10, [4, 5, 6], []) == set() - assert nx.node_boundary(K10, K10) == set() - assert nx.node_boundary(K10, [1, 2, 3], [3, 4, 5]) == {4, 5} - - def test_petersen(self): - """Check boundaries in the petersen graph - - cheeger(G,k)=min(|bdy(S)|/|S| for |S|=k, 0>> list(cycles("abc")) - [('a', 'b', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b')] - - """ - n = len(seq) - cycled_seq = cycle(seq) - for x in seq: - yield tuple(islice(cycled_seq, n)) - next(cycled_seq) - - -def cyclic_equals(seq1, seq2): - """Decide whether two sequences are equal up to cyclic permutations. - - For example:: - - >>> cyclic_equals("xyz", "zxy") - True - >>> cyclic_equals("xyz", "zyx") - False - - """ - # Cast seq2 to a tuple since `cycles()` yields tuples. - seq2 = tuple(seq2) - return any(x == tuple(seq2) for x in cycles(seq1)) - - -class TestChainDecomposition: - """Unit tests for the chain decomposition function.""" - - def assertContainsChain(self, chain, expected): - # A cycle could be expressed in two different orientations, one - # forward and one backward, so we need to check for cyclic - # equality in both orientations. - reversed_chain = list(reversed([tuple(reversed(e)) for e in chain])) - for candidate in expected: - if cyclic_equals(chain, candidate): - break - if cyclic_equals(reversed_chain, candidate): - break - else: - self.fail("chain not found") - - def test_decomposition(self): - edges = [ - # DFS tree edges. - (1, 2), - (2, 3), - (3, 4), - (3, 5), - (5, 6), - (6, 7), - (7, 8), - (5, 9), - (9, 10), - # Nontree edges. - (1, 3), - (1, 4), - (2, 5), - (5, 10), - (6, 8), - ] - G = nx.Graph(edges) - expected = [ - [(1, 3), (3, 2), (2, 1)], - [(1, 4), (4, 3)], - [(2, 5), (5, 3)], - [(5, 10), (10, 9), (9, 5)], - [(6, 8), (8, 7), (7, 6)], - ] - chains = list(nx.chain_decomposition(G, root=1)) - assert len(chains) == len(expected) - - # This chain decomposition isn't unique - # for chain in chains: - # print(chain) - # self.assertContainsChain(chain, expected) - - def test_barbell_graph(self): - # The (3, 0) barbell graph has two triangles joined by a single edge. - G = nx.barbell_graph(3, 0) - chains = list(nx.chain_decomposition(G, root=0)) - expected = [[(0, 1), (1, 2), (2, 0)], [(3, 4), (4, 5), (5, 3)]] - assert len(chains) == len(expected) - for chain in chains: - self.assertContainsChain(chain, expected) - - def test_disconnected_graph(self): - """Test for a graph with multiple connected components.""" - G = nx.barbell_graph(3, 0) - H = nx.barbell_graph(3, 0) - mapping = dict(zip(range(6), "abcdef")) - nx.relabel_nodes(H, mapping, copy=False) - G = nx.union(G, H) - chains = list(nx.chain_decomposition(G)) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - [("a", "b"), ("b", "c"), ("c", "a")], - [("d", "e"), ("e", "f"), ("f", "d")], - ] - assert len(chains) == len(expected) - for chain in chains: - self.assertContainsChain(chain, expected) - - def test_disconnected_graph_root_node(self): - """Test for a single component of a disconnected graph.""" - G = nx.barbell_graph(3, 0) - H = nx.barbell_graph(3, 0) - mapping = dict(zip(range(6), "abcdef")) - nx.relabel_nodes(H, mapping, copy=False) - G = nx.union(G, H) - chains = list(nx.chain_decomposition(G, root="a")) - expected = [ - [("a", "b"), ("b", "c"), ("c", "a")], - [("d", "e"), ("e", "f"), ("f", "d")], - ] - assert len(chains) == len(expected) - for chain in chains: - self.assertContainsChain(chain, expected) - - def test_chain_decomposition_root_not_in_G(self): - """Test chain decomposition when root is not in graph""" - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - with pytest.raises(nx.NodeNotFound): - nx.has_bridges(G, root=6) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_chordal.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_chordal.py deleted file mode 100644 index 148b22f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_chordal.py +++ /dev/null @@ -1,129 +0,0 @@ -import pytest - -import networkx as nx - - -class TestMCS: - @classmethod - def setup_class(cls): - # simple graph - connected_chordal_G = nx.Graph() - connected_chordal_G.add_edges_from( - [ - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (3, 6), - (4, 5), - (4, 6), - (5, 6), - ] - ) - cls.connected_chordal_G = connected_chordal_G - - chordal_G = nx.Graph() - chordal_G.add_edges_from( - [ - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (3, 6), - (4, 5), - (4, 6), - (5, 6), - (7, 8), - ] - ) - chordal_G.add_node(9) - cls.chordal_G = chordal_G - - non_chordal_G = nx.Graph() - non_chordal_G.add_edges_from([(1, 2), (1, 3), (2, 4), (2, 5), (3, 4), (3, 5)]) - cls.non_chordal_G = non_chordal_G - - self_loop_G = nx.Graph() - self_loop_G.add_edges_from([(1, 1)]) - cls.self_loop_G = self_loop_G - - @pytest.mark.parametrize("G", (nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph())) - def test_is_chordal_not_implemented(self, G): - with pytest.raises(nx.NetworkXNotImplemented): - nx.is_chordal(G) - - def test_is_chordal(self): - assert not nx.is_chordal(self.non_chordal_G) - assert nx.is_chordal(self.chordal_G) - assert nx.is_chordal(self.connected_chordal_G) - assert nx.is_chordal(nx.Graph()) - assert nx.is_chordal(nx.complete_graph(3)) - assert nx.is_chordal(nx.cycle_graph(3)) - assert not nx.is_chordal(nx.cycle_graph(5)) - assert nx.is_chordal(self.self_loop_G) - - def test_induced_nodes(self): - G = nx.generators.classic.path_graph(10) - Induced_nodes = nx.find_induced_nodes(G, 1, 9, 2) - assert Induced_nodes == {1, 2, 3, 4, 5, 6, 7, 8, 9} - pytest.raises( - nx.NetworkXTreewidthBoundExceeded, nx.find_induced_nodes, G, 1, 9, 1 - ) - Induced_nodes = nx.find_induced_nodes(self.chordal_G, 1, 6) - assert Induced_nodes == {1, 2, 4, 6} - pytest.raises(nx.NetworkXError, nx.find_induced_nodes, self.non_chordal_G, 1, 5) - - def test_graph_treewidth(self): - with pytest.raises(nx.NetworkXError, match="Input graph is not chordal"): - nx.chordal_graph_treewidth(self.non_chordal_G) - - def test_chordal_find_cliques(self): - cliques = { - frozenset([9]), - frozenset([7, 8]), - frozenset([1, 2, 3]), - frozenset([2, 3, 4]), - frozenset([3, 4, 5, 6]), - } - assert set(nx.chordal_graph_cliques(self.chordal_G)) == cliques - with pytest.raises(nx.NetworkXError, match="Input graph is not chordal"): - set(nx.chordal_graph_cliques(self.non_chordal_G)) - with pytest.raises(nx.NetworkXError, match="Input graph is not chordal"): - set(nx.chordal_graph_cliques(self.self_loop_G)) - - def test_chordal_find_cliques_path(self): - G = nx.path_graph(10) - cliqueset = nx.chordal_graph_cliques(G) - for u, v in G.edges(): - assert frozenset([u, v]) in cliqueset or frozenset([v, u]) in cliqueset - - def test_chordal_find_cliquesCC(self): - cliques = {frozenset([1, 2, 3]), frozenset([2, 3, 4]), frozenset([3, 4, 5, 6])} - cgc = nx.chordal_graph_cliques - assert set(cgc(self.connected_chordal_G)) == cliques - - def test_complete_to_chordal_graph(self): - fgrg = nx.fast_gnp_random_graph - test_graphs = [ - nx.barbell_graph(6, 2), - nx.cycle_graph(15), - nx.wheel_graph(20), - nx.grid_graph([10, 4]), - nx.ladder_graph(15), - nx.star_graph(5), - nx.bull_graph(), - fgrg(20, 0.3, seed=1), - ] - for G in test_graphs: - H, a = nx.complete_to_chordal_graph(G) - assert nx.is_chordal(H) - assert len(a) == H.number_of_nodes() - if nx.is_chordal(G): - assert G.number_of_edges() == H.number_of_edges() - assert set(a.values()) == {0} - else: - assert len(set(a.values())) == H.number_of_nodes() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_clique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_clique.py deleted file mode 100644 index 3bee210..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_clique.py +++ /dev/null @@ -1,291 +0,0 @@ -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti - - -class TestCliques: - def setup_method(self): - z = [3, 4, 3, 4, 2, 4, 2, 1, 1, 1, 1] - self.G = cnlti(nx.generators.havel_hakimi_graph(z), first_label=1) - self.cl = list(nx.find_cliques(self.G)) - H = nx.complete_graph(6) - H = nx.relabel_nodes(H, {i: i + 1 for i in range(6)}) - H.remove_edges_from([(2, 6), (2, 5), (2, 4), (1, 3), (5, 3)]) - self.H = H - - def test_find_cliques1(self): - cl = list(nx.find_cliques(self.G)) - rcl = nx.find_cliques_recursive(self.G) - expected = [[2, 6, 1, 3], [2, 6, 4], [5, 4, 7], [8, 9], [10, 11]] - assert sorted(map(sorted, cl)) == sorted(map(sorted, rcl)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - def test_selfloops(self): - self.G.add_edge(1, 1) - cl = list(nx.find_cliques(self.G)) - rcl = list(nx.find_cliques_recursive(self.G)) - assert set(map(frozenset, cl)) == set(map(frozenset, rcl)) - answer = [{2, 6, 1, 3}, {2, 6, 4}, {5, 4, 7}, {8, 9}, {10, 11}] - assert len(answer) == len(cl) - assert all(set(c) in answer for c in cl) - - def test_find_cliques2(self): - hcl = list(nx.find_cliques(self.H)) - assert sorted(map(sorted, hcl)) == [[1, 2], [1, 4, 5, 6], [2, 3], [3, 4, 6]] - - def test_find_cliques3(self): - # all cliques are [[2, 6, 1, 3], [2, 6, 4], [5, 4, 7], [8, 9], [10, 11]] - - cl = list(nx.find_cliques(self.G, [2])) - rcl = nx.find_cliques_recursive(self.G, [2]) - expected = [[2, 6, 1, 3], [2, 6, 4]] - assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - cl = list(nx.find_cliques(self.G, [2, 3])) - rcl = nx.find_cliques_recursive(self.G, [2, 3]) - expected = [[2, 6, 1, 3]] - assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - cl = list(nx.find_cliques(self.G, [2, 6, 4])) - rcl = nx.find_cliques_recursive(self.G, [2, 6, 4]) - expected = [[2, 6, 4]] - assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - cl = list(nx.find_cliques(self.G, [2, 6, 4])) - rcl = nx.find_cliques_recursive(self.G, [2, 6, 4]) - expected = [[2, 6, 4]] - assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - with pytest.raises(ValueError): - list(nx.find_cliques(self.G, [2, 6, 4, 1])) - - with pytest.raises(ValueError): - list(nx.find_cliques_recursive(self.G, [2, 6, 4, 1])) - - def test_number_of_cliques(self): - G = self.G - assert nx.number_of_cliques(G, 1) == 1 - assert list(nx.number_of_cliques(G, [1]).values()) == [1] - assert list(nx.number_of_cliques(G, [1, 2]).values()) == [1, 2] - assert nx.number_of_cliques(G, [1, 2]) == {1: 1, 2: 2} - assert nx.number_of_cliques(G, 2) == 2 - assert nx.number_of_cliques(G) == { - 1: 1, - 2: 2, - 3: 1, - 4: 2, - 5: 1, - 6: 2, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - assert nx.number_of_cliques(G, nodes=list(G)) == { - 1: 1, - 2: 2, - 3: 1, - 4: 2, - 5: 1, - 6: 2, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - assert nx.number_of_cliques(G, nodes=[2, 3, 4]) == {2: 2, 3: 1, 4: 2} - assert nx.number_of_cliques(G, cliques=self.cl) == { - 1: 1, - 2: 2, - 3: 1, - 4: 2, - 5: 1, - 6: 2, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - assert nx.number_of_cliques(G, list(G), cliques=self.cl) == { - 1: 1, - 2: 2, - 3: 1, - 4: 2, - 5: 1, - 6: 2, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - - def test_node_clique_number(self): - G = self.G - assert nx.node_clique_number(G, 1) == 4 - assert list(nx.node_clique_number(G, [1]).values()) == [4] - assert list(nx.node_clique_number(G, [1, 2]).values()) == [4, 4] - assert nx.node_clique_number(G, [1, 2]) == {1: 4, 2: 4} - assert nx.node_clique_number(G, 1) == 4 - assert nx.node_clique_number(G) == { - 1: 4, - 2: 4, - 3: 4, - 4: 3, - 5: 3, - 6: 4, - 7: 3, - 8: 2, - 9: 2, - 10: 2, - 11: 2, - } - assert nx.node_clique_number(G, cliques=self.cl) == { - 1: 4, - 2: 4, - 3: 4, - 4: 3, - 5: 3, - 6: 4, - 7: 3, - 8: 2, - 9: 2, - 10: 2, - 11: 2, - } - assert nx.node_clique_number(G, [1, 2], cliques=self.cl) == {1: 4, 2: 4} - assert nx.node_clique_number(G, 1, cliques=self.cl) == 4 - - def test_make_clique_bipartite(self): - G = self.G - B = nx.make_clique_bipartite(G) - assert sorted(B) == [-5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - # Project onto the nodes of the original graph. - H = nx.projected_graph(B, range(1, 12)) - assert H.adj == G.adj - # Project onto the nodes representing the cliques. - H1 = nx.projected_graph(B, range(-5, 0)) - # Relabel the negative numbers as positive ones. - H1 = nx.relabel_nodes(H1, {-v: v for v in range(1, 6)}) - assert sorted(H1) == [1, 2, 3, 4, 5] - - def test_make_max_clique_graph(self): - """Tests that the maximal clique graph is the same as the bipartite - clique graph after being projected onto the nodes representing the - cliques. - - """ - G = self.G - B = nx.make_clique_bipartite(G) - # Project onto the nodes representing the cliques. - H1 = nx.projected_graph(B, range(-5, 0)) - # Relabel the negative numbers as nonnegative ones, starting at - # 0. - H1 = nx.relabel_nodes(H1, {-v: v - 1 for v in range(1, 6)}) - H2 = nx.make_max_clique_graph(G) - assert H1.adj == H2.adj - - def test_directed(self): - with pytest.raises(nx.NetworkXNotImplemented): - next(nx.find_cliques(nx.DiGraph())) - - def test_find_cliques_trivial(self): - G = nx.Graph() - assert sorted(nx.find_cliques(G)) == [] - assert sorted(nx.find_cliques_recursive(G)) == [] - - def test_make_max_clique_graph_create_using(self): - G = nx.Graph([(1, 2), (3, 1), (4, 1), (5, 6)]) - E = nx.Graph([(0, 1), (0, 2), (1, 2)]) - E.add_node(3) - assert nx.is_isomorphic(nx.make_max_clique_graph(G, create_using=nx.Graph), E) - - -class TestEnumerateAllCliques: - def test_paper_figure_4(self): - # Same graph as given in Fig. 4 of paper enumerate_all_cliques is - # based on. - # http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1559964&isnumber=33129 - G = nx.Graph() - edges_fig_4 = [ - ("a", "b"), - ("a", "c"), - ("a", "d"), - ("a", "e"), - ("b", "c"), - ("b", "d"), - ("b", "e"), - ("c", "d"), - ("c", "e"), - ("d", "e"), - ("f", "b"), - ("f", "c"), - ("f", "g"), - ("g", "f"), - ("g", "c"), - ("g", "d"), - ("g", "e"), - ] - G.add_edges_from(edges_fig_4) - - cliques = list(nx.enumerate_all_cliques(G)) - clique_sizes = list(map(len, cliques)) - assert sorted(clique_sizes) == clique_sizes - - expected_cliques = [ - ["a"], - ["b"], - ["c"], - ["d"], - ["e"], - ["f"], - ["g"], - ["a", "b"], - ["a", "b", "d"], - ["a", "b", "d", "e"], - ["a", "b", "e"], - ["a", "c"], - ["a", "c", "d"], - ["a", "c", "d", "e"], - ["a", "c", "e"], - ["a", "d"], - ["a", "d", "e"], - ["a", "e"], - ["b", "c"], - ["b", "c", "d"], - ["b", "c", "d", "e"], - ["b", "c", "e"], - ["b", "c", "f"], - ["b", "d"], - ["b", "d", "e"], - ["b", "e"], - ["b", "f"], - ["c", "d"], - ["c", "d", "e"], - ["c", "d", "e", "g"], - ["c", "d", "g"], - ["c", "e"], - ["c", "e", "g"], - ["c", "f"], - ["c", "f", "g"], - ["c", "g"], - ["d", "e"], - ["d", "e", "g"], - ["d", "g"], - ["e", "g"], - ["f", "g"], - ["a", "b", "c"], - ["a", "b", "c", "d"], - ["a", "b", "c", "d", "e"], - ["a", "b", "c", "e"], - ] - - assert sorted(map(sorted, cliques)) == sorted(map(sorted, expected_cliques)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cluster.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cluster.py deleted file mode 100644 index b656ba8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cluster.py +++ /dev/null @@ -1,549 +0,0 @@ -import pytest - -import networkx as nx - - -class TestTriangles: - def test_empty(self): - G = nx.Graph() - assert list(nx.triangles(G).values()) == [] - - def test_path(self): - G = nx.path_graph(10) - assert list(nx.triangles(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - assert nx.triangles(G) == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - - def test_cubical(self): - G = nx.cubical_graph() - assert list(nx.triangles(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0] - assert nx.triangles(G, 1) == 0 - assert list(nx.triangles(G, [1, 2]).values()) == [0, 0] - assert nx.triangles(G, 1) == 0 - assert nx.triangles(G, [1, 2]) == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.triangles(G).values()) == [6, 6, 6, 6, 6] - assert sum(nx.triangles(G).values()) / 3 == 10 - assert nx.triangles(G, 1) == 6 - G.remove_edge(1, 2) - assert list(nx.triangles(G).values()) == [5, 3, 3, 5, 5] - assert nx.triangles(G, 1) == 3 - G.add_edge(3, 3) # ignore self-edges - assert list(nx.triangles(G).values()) == [5, 3, 3, 5, 5] - assert nx.triangles(G, 3) == 5 - - -class TestDirectedClustering: - def test_clustering(self): - G = nx.DiGraph() - assert list(nx.clustering(G).values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10, create_using=nx.DiGraph()) - assert list(nx.clustering(G).values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.clustering(G) == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - assert nx.clustering(G, 0) == 0 - - def test_k5(self): - G = nx.complete_graph(5, create_using=nx.DiGraph()) - assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G) == 1 - G.remove_edge(1, 2) - assert list(nx.clustering(G).values()) == [ - 11 / 12, - 1, - 1, - 11 / 12, - 11 / 12, - ] - assert nx.clustering(G, [1, 4]) == {1: 1, 4: 11 / 12} - G.remove_edge(2, 1) - assert list(nx.clustering(G).values()) == [ - 5 / 6, - 1, - 1, - 5 / 6, - 5 / 6, - ] - assert nx.clustering(G, [1, 4]) == {1: 1, 4: 0.83333333333333337} - assert nx.clustering(G, 4) == 5 / 6 - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(0, 4) - assert nx.clustering(G)[0] == 1 / 6 - - -class TestDirectedWeightedClustering: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - - def test_clustering(self): - G = nx.DiGraph() - assert list(nx.clustering(G, weight="weight").values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10, create_using=nx.DiGraph()) - assert list(nx.clustering(G, weight="weight").values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.clustering(G, weight="weight") == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - - def test_k5(self): - G = nx.complete_graph(5, create_using=nx.DiGraph()) - assert list(nx.clustering(G, weight="weight").values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G, weight="weight") == 1 - G.remove_edge(1, 2) - assert list(nx.clustering(G, weight="weight").values()) == [ - 11 / 12, - 1, - 1, - 11 / 12, - 11 / 12, - ] - assert nx.clustering(G, [1, 4], weight="weight") == {1: 1, 4: 11 / 12} - G.remove_edge(2, 1) - assert list(nx.clustering(G, weight="weight").values()) == [ - 5 / 6, - 1, - 1, - 5 / 6, - 5 / 6, - ] - assert nx.clustering(G, [1, 4], weight="weight") == { - 1: 1, - 4: 0.83333333333333337, - } - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(0, 4, weight=2) - assert nx.clustering(G)[0] == 1 / 6 - # Relaxed comparisons to allow graphblas-algorithms to pass tests - np.testing.assert_allclose(nx.clustering(G, weight="weight")[0], 1 / 12) - np.testing.assert_allclose(nx.clustering(G, 0, weight="weight"), 1 / 12) - - -class TestWeightedClustering: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - - def test_clustering(self): - G = nx.Graph() - assert list(nx.clustering(G, weight="weight").values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert list(nx.clustering(G, weight="weight").values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.clustering(G, weight="weight") == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - - def test_cubical(self): - G = nx.cubical_graph() - assert list(nx.clustering(G, weight="weight").values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.clustering(G, 1) == 0 - assert list(nx.clustering(G, [1, 2], weight="weight").values()) == [0, 0] - assert nx.clustering(G, 1, weight="weight") == 0 - assert nx.clustering(G, [1, 2], weight="weight") == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.clustering(G, weight="weight").values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G, weight="weight") == 1 - G.remove_edge(1, 2) - assert list(nx.clustering(G, weight="weight").values()) == [ - 5 / 6, - 1, - 1, - 5 / 6, - 5 / 6, - ] - assert nx.clustering(G, [1, 4], weight="weight") == { - 1: 1, - 4: 0.83333333333333337, - } - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3) - G.add_edge(0, 4, weight=2) - assert nx.clustering(G)[0] == 1 / 3 - np.testing.assert_allclose(nx.clustering(G, weight="weight")[0], 1 / 6) - np.testing.assert_allclose(nx.clustering(G, 0, weight="weight"), 1 / 6) - - def test_triangle_and_signed_edge(self): - G = nx.cycle_graph(3) - G.add_edge(0, 1, weight=-1) - G.add_edge(3, 0, weight=0) - assert nx.clustering(G)[0] == 1 / 3 - assert nx.clustering(G, weight="weight")[0] == -1 / 3 - - -class TestClustering: - @classmethod - def setup_class(cls): - pytest.importorskip("numpy") - - def test_clustering(self): - G = nx.Graph() - assert list(nx.clustering(G).values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert list(nx.clustering(G).values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.clustering(G) == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - - def test_cubical(self): - G = nx.cubical_graph() - assert list(nx.clustering(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0] - assert nx.clustering(G, 1) == 0 - assert list(nx.clustering(G, [1, 2]).values()) == [0, 0] - assert nx.clustering(G, 1) == 0 - assert nx.clustering(G, [1, 2]) == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G) == 1 - G.remove_edge(1, 2) - assert list(nx.clustering(G).values()) == [ - 5 / 6, - 1, - 1, - 5 / 6, - 5 / 6, - ] - assert nx.clustering(G, [1, 4]) == {1: 1, 4: 0.83333333333333337} - - def test_k5_signed(self): - G = nx.complete_graph(5) - assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G) == 1 - G.remove_edge(1, 2) - G.add_edge(0, 1, weight=-1) - assert list(nx.clustering(G, weight="weight").values()) == [ - 1 / 6, - -1 / 3, - 1, - 3 / 6, - 3 / 6, - ] - - -class TestTransitivity: - def test_transitivity(self): - G = nx.Graph() - assert nx.transitivity(G) == 0 - - def test_path(self): - G = nx.path_graph(10) - assert nx.transitivity(G) == 0 - - def test_cubical(self): - G = nx.cubical_graph() - assert nx.transitivity(G) == 0 - - def test_k5(self): - G = nx.complete_graph(5) - assert nx.transitivity(G) == 1 - G.remove_edge(1, 2) - assert nx.transitivity(G) == 0.875 - - -class TestSquareClustering: - def test_clustering(self): - G = nx.Graph() - assert list(nx.square_clustering(G).values()) == [] - assert nx.square_clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert list(nx.square_clustering(G).values()) == [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ] - assert nx.square_clustering(G) == { - 0: 0, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0, - } - - def test_cubical(self): - G = nx.cubical_graph() - assert list(nx.square_clustering(G).values()) == [ - 1 / 3, - 1 / 3, - 1 / 3, - 1 / 3, - 1 / 3, - 1 / 3, - 1 / 3, - 1 / 3, - ] - assert list(nx.square_clustering(G, [1, 2]).values()) == [1 / 3, 1 / 3] - assert nx.square_clustering(G, [1])[1] == 1 / 3 - assert nx.square_clustering(G, 1) == 1 / 3 - assert nx.square_clustering(G, [1, 2]) == {1: 1 / 3, 2: 1 / 3} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.square_clustering(G).values()) == [1, 1, 1, 1, 1] - - def test_bipartite_k5(self): - G = nx.complete_bipartite_graph(5, 5) - assert list(nx.square_clustering(G).values()) == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - - def test_lind_square_clustering(self): - """Test C4 for figure 1 Lind et al (2005)""" - G = nx.Graph( - [ - (1, 2), - (1, 3), - (1, 6), - (1, 7), - (2, 4), - (2, 5), - (3, 4), - (3, 5), - (6, 7), - (7, 8), - (6, 8), - (7, 9), - (7, 10), - (6, 11), - (6, 12), - (2, 13), - (2, 14), - (3, 15), - (3, 16), - ] - ) - G1 = G.subgraph([1, 2, 3, 4, 5, 13, 14, 15, 16]) - G2 = G.subgraph([1, 6, 7, 8, 9, 10, 11, 12]) - assert nx.square_clustering(G, [1])[1] == 3 / 43 - assert nx.square_clustering(G1, [1])[1] == 2 / 6 - assert nx.square_clustering(G2, [1])[1] == 1 / 5 - - def test_peng_square_clustering(self): - """Test eq2 for figure 1 Peng et al (2008)""" - G = nx.Graph([(1, 2), (1, 3), (2, 4), (3, 4), (3, 5), (3, 6)]) - assert nx.square_clustering(G, [1])[1] == 1 / 3 - - def test_self_loops_square_clustering(self): - G = nx.path_graph(5) - assert nx.square_clustering(G) == {0: 0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0} - G.add_edges_from([(0, 0), (1, 1), (2, 2)]) - assert nx.square_clustering(G) == {0: 1, 1: 0.5, 2: 0.2, 3: 0.0, 4: 0} - - -class TestAverageClustering: - @classmethod - def setup_class(cls): - pytest.importorskip("numpy") - - def test_empty(self): - G = nx.Graph() - with pytest.raises(ZeroDivisionError): - nx.average_clustering(G) - - def test_average_clustering(self): - G = nx.cycle_graph(3) - G.add_edge(2, 3) - assert nx.average_clustering(G) == (1 + 1 + 1 / 3) / 4 - assert nx.average_clustering(G, count_zeros=True) == (1 + 1 + 1 / 3) / 4 - assert nx.average_clustering(G, count_zeros=False) == (1 + 1 + 1 / 3) / 3 - assert nx.average_clustering(G, [1, 2, 3]) == (1 + 1 / 3) / 3 - assert nx.average_clustering(G, [1, 2, 3], count_zeros=True) == (1 + 1 / 3) / 3 - assert nx.average_clustering(G, [1, 2, 3], count_zeros=False) == (1 + 1 / 3) / 2 - - def test_average_clustering_signed(self): - G = nx.cycle_graph(3) - G.add_edge(2, 3) - G.add_edge(0, 1, weight=-1) - assert nx.average_clustering(G, weight="weight") == (-1 - 1 - 1 / 3) / 4 - assert ( - nx.average_clustering(G, weight="weight", count_zeros=True) - == (-1 - 1 - 1 / 3) / 4 - ) - assert ( - nx.average_clustering(G, weight="weight", count_zeros=False) - == (-1 - 1 - 1 / 3) / 3 - ) - - -class TestDirectedAverageClustering: - @classmethod - def setup_class(cls): - pytest.importorskip("numpy") - - def test_empty(self): - G = nx.DiGraph() - with pytest.raises(ZeroDivisionError): - nx.average_clustering(G) - - def test_average_clustering(self): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(2, 3) - assert nx.average_clustering(G) == (1 + 1 + 1 / 3) / 8 - assert nx.average_clustering(G, count_zeros=True) == (1 + 1 + 1 / 3) / 8 - assert nx.average_clustering(G, count_zeros=False) == (1 + 1 + 1 / 3) / 6 - assert nx.average_clustering(G, [1, 2, 3]) == (1 + 1 / 3) / 6 - assert nx.average_clustering(G, [1, 2, 3], count_zeros=True) == (1 + 1 / 3) / 6 - assert nx.average_clustering(G, [1, 2, 3], count_zeros=False) == (1 + 1 / 3) / 4 - - -class TestGeneralizedDegree: - def test_generalized_degree(self): - G = nx.Graph() - assert nx.generalized_degree(G) == {} - - def test_path(self): - G = nx.path_graph(5) - assert nx.generalized_degree(G, 0) == {0: 1} - assert nx.generalized_degree(G, 1) == {0: 2} - - def test_cubical(self): - G = nx.cubical_graph() - assert nx.generalized_degree(G, 0) == {0: 3} - - def test_k5(self): - G = nx.complete_graph(5) - assert nx.generalized_degree(G, 0) == {3: 4} - G.remove_edge(0, 1) - assert nx.generalized_degree(G, 0) == {2: 3} - assert nx.generalized_degree(G, [1, 2]) == {1: {2: 3}, 2: {2: 2, 3: 2}} - assert nx.generalized_degree(G) == { - 0: {2: 3}, - 1: {2: 3}, - 2: {2: 2, 3: 2}, - 3: {2: 2, 3: 2}, - 4: {2: 2, 3: 2}, - } diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_communicability.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_communicability.py deleted file mode 100644 index 0f44709..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_communicability.py +++ /dev/null @@ -1,80 +0,0 @@ -from collections import defaultdict - -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.algorithms.communicability_alg import communicability, communicability_exp - - -class TestCommunicability: - def test_communicability(self): - answer = { - 0: {0: 1.5430806348152435, 1: 1.1752011936438012}, - 1: {0: 1.1752011936438012, 1: 1.5430806348152435}, - } - # answer={(0, 0): 1.5430806348152435, - # (0, 1): 1.1752011936438012, - # (1, 0): 1.1752011936438012, - # (1, 1): 1.5430806348152435} - - result = communicability(nx.path_graph(2)) - for k1, val in result.items(): - for k2 in val: - assert answer[k1][k2] == pytest.approx(result[k1][k2], abs=1e-7) - - def test_communicability2(self): - answer_orig = { - ("1", "1"): 1.6445956054135658, - ("1", "Albert"): 0.7430186221096251, - ("1", "Aric"): 0.7430186221096251, - ("1", "Dan"): 1.6208126320442937, - ("1", "Franck"): 0.42639707170035257, - ("Albert", "1"): 0.7430186221096251, - ("Albert", "Albert"): 2.4368257358712189, - ("Albert", "Aric"): 1.4368257358712191, - ("Albert", "Dan"): 2.0472097037446453, - ("Albert", "Franck"): 1.8340111678944691, - ("Aric", "1"): 0.7430186221096251, - ("Aric", "Albert"): 1.4368257358712191, - ("Aric", "Aric"): 2.4368257358712193, - ("Aric", "Dan"): 2.0472097037446457, - ("Aric", "Franck"): 1.8340111678944691, - ("Dan", "1"): 1.6208126320442937, - ("Dan", "Albert"): 2.0472097037446453, - ("Dan", "Aric"): 2.0472097037446457, - ("Dan", "Dan"): 3.1306328496328168, - ("Dan", "Franck"): 1.4860372442192515, - ("Franck", "1"): 0.42639707170035257, - ("Franck", "Albert"): 1.8340111678944691, - ("Franck", "Aric"): 1.8340111678944691, - ("Franck", "Dan"): 1.4860372442192515, - ("Franck", "Franck"): 2.3876142275231915, - } - - answer = defaultdict(dict) - for (k1, k2), v in answer_orig.items(): - answer[k1][k2] = v - - G1 = nx.Graph( - [ - ("Franck", "Aric"), - ("Aric", "Dan"), - ("Dan", "Albert"), - ("Albert", "Franck"), - ("Dan", "1"), - ("Franck", "Albert"), - ] - ) - - result = communicability(G1) - for k1, val in result.items(): - for k2 in val: - assert answer[k1][k2] == pytest.approx(result[k1][k2], abs=1e-7) - - result = communicability_exp(G1) - for k1, val in result.items(): - for k2 in val: - assert answer[k1][k2] == pytest.approx(result[k1][k2], abs=1e-7) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_core.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_core.py deleted file mode 100644 index 726e98a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_core.py +++ /dev/null @@ -1,266 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import nodes_equal - - -class TestCore: - @classmethod - def setup_class(cls): - # G is the example graph in Figure 1 from Batagelj and - # Zaversnik's paper titled An O(m) Algorithm for Cores - # Decomposition of Networks, 2003, - # http://arXiv.org/abs/cs/0310049. With nodes labeled as - # shown, the 3-core is given by nodes 1-8, the 2-core by nodes - # 9-16, the 1-core by nodes 17-20 and node 21 is in the - # 0-core. - t1 = nx.convert_node_labels_to_integers(nx.tetrahedral_graph(), 1) - t2 = nx.convert_node_labels_to_integers(t1, 5) - G = nx.union(t1, t2) - G.add_edges_from( - [ - (3, 7), - (2, 11), - (11, 5), - (11, 12), - (5, 12), - (12, 19), - (12, 18), - (3, 9), - (7, 9), - (7, 10), - (9, 10), - (9, 20), - (17, 13), - (13, 14), - (14, 15), - (15, 16), - (16, 13), - ] - ) - G.add_node(21) - cls.G = G - - # Create the graph H resulting from the degree sequence - # [0, 1, 2, 2, 2, 2, 3] when using the Havel-Hakimi algorithm. - - degseq = [0, 1, 2, 2, 2, 2, 3] - H = nx.havel_hakimi_graph(degseq) - mapping = {6: 0, 0: 1, 4: 3, 5: 6, 3: 4, 1: 2, 2: 5} - cls.H = nx.relabel_nodes(H, mapping) - - def test_trivial(self): - """Empty graph""" - G = nx.Graph() - assert nx.core_number(G) == {} - - def test_core_number(self): - core = nx.core_number(self.G) - nodes_by_core = [sorted(n for n in core if core[n] == val) for val in range(4)] - assert nodes_equal(nodes_by_core[0], [21]) - assert nodes_equal(nodes_by_core[1], [17, 18, 19, 20]) - assert nodes_equal(nodes_by_core[2], [9, 10, 11, 12, 13, 14, 15, 16]) - assert nodes_equal(nodes_by_core[3], [1, 2, 3, 4, 5, 6, 7, 8]) - - def test_core_number2(self): - core = nx.core_number(self.H) - nodes_by_core = [sorted(n for n in core if core[n] == val) for val in range(3)] - assert nodes_equal(nodes_by_core[0], [0]) - assert nodes_equal(nodes_by_core[1], [1, 3]) - assert nodes_equal(nodes_by_core[2], [2, 4, 5, 6]) - - def test_core_number_multigraph(self): - G = nx.complete_graph(3) - G = nx.MultiGraph(G) - G.add_edge(1, 2) - with pytest.raises( - nx.NetworkXNotImplemented, match="not implemented for multigraph type" - ): - nx.core_number(G) - - def test_core_number_self_loop(self): - G = nx.cycle_graph(3) - G.add_edge(0, 0) - with pytest.raises( - nx.NetworkXNotImplemented, match="Input graph has self loops" - ): - nx.core_number(G) - - def test_directed_core_number(self): - """core number had a bug for directed graphs found in issue #1959""" - # small example where too timid edge removal can make cn[2] = 3 - G = nx.DiGraph() - edges = [(1, 2), (2, 1), (2, 3), (2, 4), (3, 4), (4, 3)] - G.add_edges_from(edges) - assert nx.core_number(G) == {1: 2, 2: 2, 3: 2, 4: 2} - # small example where too aggressive edge removal can make cn[2] = 2 - more_edges = [(1, 5), (3, 5), (4, 5), (3, 6), (4, 6), (5, 6)] - G.add_edges_from(more_edges) - assert nx.core_number(G) == {1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3} - - def test_main_core(self): - main_core_subgraph = nx.k_core(self.H) - assert sorted(main_core_subgraph.nodes()) == [2, 4, 5, 6] - - def test_k_core(self): - # k=0 - k_core_subgraph = nx.k_core(self.H, k=0) - assert sorted(k_core_subgraph.nodes()) == sorted(self.H.nodes()) - # k=1 - k_core_subgraph = nx.k_core(self.H, k=1) - assert sorted(k_core_subgraph.nodes()) == [1, 2, 3, 4, 5, 6] - # k = 2 - k_core_subgraph = nx.k_core(self.H, k=2) - assert sorted(k_core_subgraph.nodes()) == [2, 4, 5, 6] - - def test_k_core_multigraph(self): - core_number = nx.core_number(self.H) - H = nx.MultiGraph(self.H) - with pytest.deprecated_call(): - nx.k_core(H, k=0, core_number=core_number) - - def test_main_crust(self): - main_crust_subgraph = nx.k_crust(self.H) - assert sorted(main_crust_subgraph.nodes()) == [0, 1, 3] - - def test_k_crust(self): - # k = 0 - k_crust_subgraph = nx.k_crust(self.H, k=2) - assert sorted(k_crust_subgraph.nodes()) == sorted(self.H.nodes()) - # k=1 - k_crust_subgraph = nx.k_crust(self.H, k=1) - assert sorted(k_crust_subgraph.nodes()) == [0, 1, 3] - # k=2 - k_crust_subgraph = nx.k_crust(self.H, k=0) - assert sorted(k_crust_subgraph.nodes()) == [0] - - def test_k_crust_multigraph(self): - core_number = nx.core_number(self.H) - H = nx.MultiGraph(self.H) - with pytest.deprecated_call(): - nx.k_crust(H, k=0, core_number=core_number) - - def test_main_shell(self): - main_shell_subgraph = nx.k_shell(self.H) - assert sorted(main_shell_subgraph.nodes()) == [2, 4, 5, 6] - - def test_k_shell(self): - # k=0 - k_shell_subgraph = nx.k_shell(self.H, k=2) - assert sorted(k_shell_subgraph.nodes()) == [2, 4, 5, 6] - # k=1 - k_shell_subgraph = nx.k_shell(self.H, k=1) - assert sorted(k_shell_subgraph.nodes()) == [1, 3] - # k=2 - k_shell_subgraph = nx.k_shell(self.H, k=0) - assert sorted(k_shell_subgraph.nodes()) == [0] - - def test_k_shell_multigraph(self): - core_number = nx.core_number(self.H) - H = nx.MultiGraph(self.H) - with pytest.deprecated_call(): - nx.k_shell(H, k=0, core_number=core_number) - - def test_k_corona(self): - # k=0 - k_corona_subgraph = nx.k_corona(self.H, k=2) - assert sorted(k_corona_subgraph.nodes()) == [2, 4, 5, 6] - # k=1 - k_corona_subgraph = nx.k_corona(self.H, k=1) - assert sorted(k_corona_subgraph.nodes()) == [1] - # k=2 - k_corona_subgraph = nx.k_corona(self.H, k=0) - assert sorted(k_corona_subgraph.nodes()) == [0] - - def test_k_corona_multigraph(self): - core_number = nx.core_number(self.H) - H = nx.MultiGraph(self.H) - with pytest.deprecated_call(): - nx.k_corona(H, k=0, core_number=core_number) - - def test_k_truss(self): - # k=-1 - k_truss_subgraph = nx.k_truss(self.G, -1) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 21)) - # k=0 - k_truss_subgraph = nx.k_truss(self.G, 0) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 21)) - # k=1 - k_truss_subgraph = nx.k_truss(self.G, 1) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 21)) - # k=2 - k_truss_subgraph = nx.k_truss(self.G, 2) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 21)) - # k=3 - k_truss_subgraph = nx.k_truss(self.G, 3) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 13)) - - k_truss_subgraph = nx.k_truss(self.G, 4) - assert sorted(k_truss_subgraph.nodes()) == list(range(1, 9)) - - k_truss_subgraph = nx.k_truss(self.G, 5) - assert sorted(k_truss_subgraph.nodes()) == [] - - def test_k_truss_digraph(self): - G = nx.complete_graph(3) - G = nx.DiGraph(G) - G.add_edge(2, 1) - with pytest.raises( - nx.NetworkXNotImplemented, match="not implemented for directed type" - ): - nx.k_truss(G, k=1) - - def test_k_truss_multigraph(self): - G = nx.complete_graph(3) - G = nx.MultiGraph(G) - G.add_edge(1, 2) - with pytest.raises( - nx.NetworkXNotImplemented, match="not implemented for multigraph type" - ): - nx.k_truss(G, k=1) - - def test_k_truss_self_loop(self): - G = nx.cycle_graph(3) - G.add_edge(0, 0) - with pytest.raises( - nx.NetworkXNotImplemented, match="Input graph has self loops" - ): - nx.k_truss(G, k=1) - - def test_onion_layers(self): - layers = nx.onion_layers(self.G) - nodes_by_layer = [ - sorted(n for n in layers if layers[n] == val) for val in range(1, 7) - ] - assert nodes_equal(nodes_by_layer[0], [21]) - assert nodes_equal(nodes_by_layer[1], [17, 18, 19, 20]) - assert nodes_equal(nodes_by_layer[2], [10, 12, 13, 14, 15, 16]) - assert nodes_equal(nodes_by_layer[3], [9, 11]) - assert nodes_equal(nodes_by_layer[4], [1, 2, 4, 5, 6, 8]) - assert nodes_equal(nodes_by_layer[5], [3, 7]) - - def test_onion_digraph(self): - G = nx.complete_graph(3) - G = nx.DiGraph(G) - G.add_edge(2, 1) - with pytest.raises( - nx.NetworkXNotImplemented, match="not implemented for directed type" - ): - nx.onion_layers(G) - - def test_onion_multigraph(self): - G = nx.complete_graph(3) - G = nx.MultiGraph(G) - G.add_edge(1, 2) - with pytest.raises( - nx.NetworkXNotImplemented, match="not implemented for multigraph type" - ): - nx.onion_layers(G) - - def test_onion_self_loop(self): - G = nx.cycle_graph(3) - G.add_edge(0, 0) - with pytest.raises( - nx.NetworkXNotImplemented, match="Input graph contains self loops" - ): - nx.onion_layers(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_covering.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_covering.py deleted file mode 100644 index b2f97a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_covering.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest - -import networkx as nx - - -class TestMinEdgeCover: - """Tests for :func:`networkx.algorithms.min_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert nx.min_edge_cover(G) == set() - - def test_graph_with_loop(self): - G = nx.Graph() - G.add_edge(0, 0) - assert nx.min_edge_cover(G) == {(0, 0)} - - def test_graph_with_isolated_v(self): - G = nx.Graph() - G.add_node(1) - with pytest.raises( - nx.NetworkXException, - match="Graph has a node with no edge incident on it, so no edge cover exists.", - ): - nx.min_edge_cover(G) - - def test_graph_single_edge(self): - G = nx.Graph([(0, 1)]) - assert nx.min_edge_cover(G) in ({(0, 1)}, {(1, 0)}) - - def test_graph_two_edge_path(self): - G = nx.path_graph(3) - min_cover = nx.min_edge_cover(G) - assert len(min_cover) == 2 - for u, v in G.edges: - assert (u, v) in min_cover or (v, u) in min_cover - - def test_bipartite_explicit(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(["a", "b", "c"], bipartite=1) - G.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")]) - # Use bipartite method by prescribing the algorithm - min_cover = nx.min_edge_cover( - G, nx.algorithms.bipartite.matching.eppstein_matching - ) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 - # Use the default method which is not specialized for bipartite - min_cover2 = nx.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover2) - assert len(min_cover2) == 4 - - def test_complete_graph_even(self): - G = nx.complete_graph(10) - min_cover = nx.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 5 - - def test_complete_graph_odd(self): - G = nx.complete_graph(11) - min_cover = nx.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 6 - - -class TestIsEdgeCover: - """Tests for :func:`networkx.algorithms.is_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert nx.is_edge_cover(G, set()) - - def test_graph_with_loop(self): - G = nx.Graph() - G.add_edge(1, 1) - assert nx.is_edge_cover(G, {(1, 1)}) - - def test_graph_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert nx.is_edge_cover(G, {(0, 0), (1, 1)}) - assert nx.is_edge_cover(G, {(0, 1), (1, 0)}) - assert nx.is_edge_cover(G, {(0, 1)}) - assert not nx.is_edge_cover(G, {(0, 0)}) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cuts.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cuts.py deleted file mode 100644 index 923efa5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cuts.py +++ /dev/null @@ -1,171 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.cuts` module.""" - -import networkx as nx - - -class TestCutSize: - """Unit tests for the :func:`~networkx.cut_size` function.""" - - def test_symmetric(self): - """Tests that the cut size is symmetric.""" - G = nx.barbell_graph(3, 0) - S = {0, 1, 4} - T = {2, 3, 5} - assert nx.cut_size(G, S, T) == 4 - assert nx.cut_size(G, T, S) == 4 - - def test_single_edge(self): - """Tests for a cut of a single edge.""" - G = nx.barbell_graph(3, 0) - S = {0, 1, 2} - T = {3, 4, 5} - assert nx.cut_size(G, S, T) == 1 - assert nx.cut_size(G, T, S) == 1 - - def test_directed(self): - """Tests that each directed edge is counted once in the cut.""" - G = nx.barbell_graph(3, 0).to_directed() - S = {0, 1, 2} - T = {3, 4, 5} - assert nx.cut_size(G, S, T) == 2 - assert nx.cut_size(G, T, S) == 2 - - def test_directed_symmetric(self): - """Tests that a cut in a directed graph is symmetric.""" - G = nx.barbell_graph(3, 0).to_directed() - S = {0, 1, 4} - T = {2, 3, 5} - assert nx.cut_size(G, S, T) == 8 - assert nx.cut_size(G, T, S) == 8 - - def test_multigraph(self): - """Tests that parallel edges are each counted for a cut.""" - G = nx.MultiGraph(["ab", "ab"]) - assert nx.cut_size(G, {"a"}, {"b"}) == 2 - - -class TestVolume: - """Unit tests for the :func:`~networkx.volume` function.""" - - def test_graph(self): - G = nx.cycle_graph(4) - assert nx.volume(G, {0, 1}) == 4 - - def test_digraph(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 0)]) - assert nx.volume(G, {0, 1}) == 2 - - def test_multigraph(self): - edges = list(nx.cycle_graph(4).edges()) - G = nx.MultiGraph(edges * 2) - assert nx.volume(G, {0, 1}) == 8 - - def test_multidigraph(self): - edges = [(0, 1), (1, 2), (2, 3), (3, 0)] - G = nx.MultiDiGraph(edges * 2) - assert nx.volume(G, {0, 1}) == 4 - - def test_barbell(self): - G = nx.barbell_graph(3, 0) - assert nx.volume(G, {0, 1, 2}) == 7 - assert nx.volume(G, {3, 4, 5}) == 7 - - -class TestNormalizedCutSize: - """Unit tests for the :func:`~networkx.normalized_cut_size` function.""" - - def test_graph(self): - G = nx.path_graph(4) - S = {1, 2} - T = set(G) - S - size = nx.normalized_cut_size(G, S, T) - # The cut looks like this: o-{-o--o-}-o - expected = 2 * ((1 / 4) + (1 / 2)) - assert expected == size - # Test with no input T - assert expected == nx.normalized_cut_size(G, S) - - def test_directed(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - S = {1, 2} - T = set(G) - S - size = nx.normalized_cut_size(G, S, T) - # The cut looks like this: o-{->o-->o-}->o - expected = 2 * ((1 / 2) + (1 / 1)) - assert expected == size - # Test with no input T - assert expected == nx.normalized_cut_size(G, S) - - -class TestConductance: - """Unit tests for the :func:`~networkx.conductance` function.""" - - def test_graph(self): - G = nx.barbell_graph(5, 0) - # Consider the singleton sets containing the "bridge" nodes. - # There is only one cut edge, and each set has volume five. - S = {4} - T = {5} - conductance = nx.conductance(G, S, T) - expected = 1 / 5 - assert expected == conductance - # Test with no input T - G2 = nx.barbell_graph(3, 0) - # There is only one cut edge, and each set has volume seven. - S2 = {0, 1, 2} - assert nx.conductance(G2, S2) == 1 / 7 - - -class TestEdgeExpansion: - """Unit tests for the :func:`~networkx.edge_expansion` function.""" - - def test_graph(self): - G = nx.barbell_graph(5, 0) - S = set(range(5)) - T = set(G) - S - expansion = nx.edge_expansion(G, S, T) - expected = 1 / 5 - assert expected == expansion - # Test with no input T - assert expected == nx.edge_expansion(G, S) - - -class TestNodeExpansion: - """Unit tests for the :func:`~networkx.node_expansion` function.""" - - def test_graph(self): - G = nx.path_graph(8) - S = {3, 4, 5} - expansion = nx.node_expansion(G, S) - # The neighborhood of S has cardinality five, and S has - # cardinality three. - expected = 5 / 3 - assert expected == expansion - - -class TestBoundaryExpansion: - """Unit tests for the :func:`~networkx.boundary_expansion` function.""" - - def test_graph(self): - G = nx.complete_graph(10) - S = set(range(4)) - expansion = nx.boundary_expansion(G, S) - # The node boundary of S has cardinality six, and S has - # cardinality three. - expected = 6 / 4 - assert expected == expansion - - -class TestMixingExpansion: - """Unit tests for the :func:`~networkx.mixing_expansion` function.""" - - def test_graph(self): - G = nx.barbell_graph(5, 0) - S = set(range(5)) - T = set(G) - S - expansion = nx.mixing_expansion(G, S, T) - # There is one cut edge, and the total number of edges in the - # graph is twice the total number of edges in a clique of size - # five, plus one more for the bridge. - expected = 1 / (2 * (5 * 4 + 1)) - assert expected == expansion diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cycles.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cycles.py deleted file mode 100644 index dd21405..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_cycles.py +++ /dev/null @@ -1,974 +0,0 @@ -from itertools import chain, islice, tee -from math import inf -from random import shuffle - -import pytest - -import networkx as nx -from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE - - -def check_independent(basis): - if len(basis) == 0: - return - - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") # Required by incidence_matrix - - H = nx.Graph() - for b in basis: - nx.add_cycle(H, b) - inc = nx.incidence_matrix(H, oriented=True) - rank = np.linalg.matrix_rank(inc.toarray(), tol=None, hermitian=False) - assert inc.shape[1] - rank == len(basis) - - -class TestCycles: - @classmethod - def setup_class(cls): - G = nx.Graph() - nx.add_cycle(G, [0, 1, 2, 3]) - nx.add_cycle(G, [0, 3, 4, 5]) - nx.add_cycle(G, [0, 1, 6, 7, 8]) - G.add_edge(8, 9) - cls.G = G - - def is_cyclic_permutation(self, a, b): - n = len(a) - if len(b) != n: - return False - l = a + a - return any(l[i : i + n] == b for i in range(n)) - - def test_cycle_basis(self): - G = self.G - cy = nx.cycle_basis(G, 0) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - cy = nx.cycle_basis(G, 1) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - cy = nx.cycle_basis(G, 9) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - # test disconnected graphs - nx.add_cycle(G, "ABC") - cy = nx.cycle_basis(G, 9) - sort_cy = sorted(sorted(c) for c in cy[:-1]) + [sorted(cy[-1])] - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], ["A", "B", "C"]] - - def test_cycle_basis2(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - cy = nx.cycle_basis(G, 0) - - def test_cycle_basis3(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - cy = nx.cycle_basis(G, 0) - - def test_cycle_basis_ordered(self): - # see gh-6654 replace sets with (ordered) dicts - G = nx.cycle_graph(5) - G.update(nx.cycle_graph(range(3, 8))) - cbG = nx.cycle_basis(G) - - perm = {1: 0, 0: 1} # switch 0 and 1 - H = nx.relabel_nodes(G, perm) - cbH = [[perm.get(n, n) for n in cyc] for cyc in nx.cycle_basis(H)] - assert cbG == cbH - - def test_cycle_basis_self_loop(self): - """Tests the function for graphs with self loops""" - G = nx.Graph() - nx.add_cycle(G, [0, 1, 2, 3]) - nx.add_cycle(G, [0, 0, 6, 2]) - cy = nx.cycle_basis(G) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0], [0, 1, 2], [0, 2, 3], [0, 2, 6]] - - def test_simple_cycles(self): - edges = [(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)] - G = nx.DiGraph(edges) - cc = sorted(nx.simple_cycles(G)) - ca = [[0], [0, 1, 2], [0, 2], [1, 2], [2]] - assert len(cc) == len(ca) - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in ca) - - def test_simple_cycles_singleton(self): - G = nx.Graph([(0, 0)]) # self-loop - assert list(nx.simple_cycles(G)) == [[0]] - - def test_unsortable(self): - # this test ensures that graphs whose nodes without an intrinsic - # ordering do not cause issues - G = nx.DiGraph() - nx.add_cycle(G, ["a", 1]) - c = list(nx.simple_cycles(G)) - assert len(c) == 1 - - def test_simple_cycles_small(self): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3]) - c = sorted(nx.simple_cycles(G)) - assert len(c) == 1 - assert self.is_cyclic_permutation(c[0], [1, 2, 3]) - nx.add_cycle(G, [10, 20, 30]) - cc = sorted(nx.simple_cycles(G)) - assert len(cc) == 2 - ca = [[1, 2, 3], [10, 20, 30]] - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in ca) - - def test_simple_cycles_empty(self): - G = nx.DiGraph() - assert list(nx.simple_cycles(G)) == [] - - def worst_case_graph(self, k): - # see figure 1 in Johnson's paper - # this graph has exactly 3k simple cycles - G = nx.DiGraph() - for n in range(2, k + 2): - G.add_edge(1, n) - G.add_edge(n, k + 2) - G.add_edge(2 * k + 1, 1) - for n in range(k + 2, 2 * k + 2): - G.add_edge(n, 2 * k + 2) - G.add_edge(n, n + 1) - G.add_edge(2 * k + 3, k + 2) - for n in range(2 * k + 3, 3 * k + 3): - G.add_edge(2 * k + 2, n) - G.add_edge(n, 3 * k + 3) - G.add_edge(3 * k + 3, 2 * k + 2) - return G - - def test_worst_case_graph(self): - # see figure 1 in Johnson's paper - for k in range(3, 10): - G = self.worst_case_graph(k) - l = len(list(nx.simple_cycles(G))) - assert l == 3 * k - - def test_recursive_simple_and_not(self): - for k in range(2, 10): - G = self.worst_case_graph(k) - cc = sorted(nx.simple_cycles(G)) - rcc = sorted(nx.recursive_simple_cycles(G)) - assert len(cc) == len(rcc) - for c in cc: - assert any(self.is_cyclic_permutation(c, r) for r in rcc) - for rc in rcc: - assert any(self.is_cyclic_permutation(rc, c) for c in cc) - - def test_simple_graph_with_reported_bug(self): - G = nx.DiGraph() - edges = [ - (0, 2), - (0, 3), - (1, 0), - (1, 3), - (2, 1), - (2, 4), - (3, 2), - (3, 4), - (4, 0), - (4, 1), - (4, 5), - (5, 0), - (5, 1), - (5, 2), - (5, 3), - ] - G.add_edges_from(edges) - cc = sorted(nx.simple_cycles(G)) - assert len(cc) == 26 - rcc = sorted(nx.recursive_simple_cycles(G)) - assert len(cc) == len(rcc) - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in rcc) - for rc in rcc: - assert any(self.is_cyclic_permutation(rc, c) for c in cc) - - -def pairwise(iterable): - a, b = tee(iterable) - next(b, None) - return zip(a, b) - - -def cycle_edges(c): - return pairwise(chain(c, islice(c, 1))) - - -def directed_cycle_edgeset(c): - return frozenset(cycle_edges(c)) - - -def undirected_cycle_edgeset(c): - if len(c) == 1: - return frozenset(cycle_edges(c)) - return frozenset(map(frozenset, cycle_edges(c))) - - -def multigraph_cycle_edgeset(c): - if len(c) <= 2: - return frozenset(cycle_edges(c)) - else: - return frozenset(map(frozenset, cycle_edges(c))) - - -class TestCycleEnumeration: - @staticmethod - def K(n): - return nx.complete_graph(n) - - @staticmethod - def D(n): - return nx.complete_graph(n).to_directed() - - @staticmethod - def edgeset_function(g): - if g.is_directed(): - return directed_cycle_edgeset - elif g.is_multigraph(): - return multigraph_cycle_edgeset - else: - return undirected_cycle_edgeset - - def check_cycle(self, g, c, es, cache, source, original_c, length_bound, chordless): - if length_bound is not None and len(c) > length_bound: - raise RuntimeError( - f"computed cycle {original_c} exceeds length bound {length_bound}" - ) - if source == "computed": - if es in cache: - raise RuntimeError( - f"computed cycle {original_c} has already been found!" - ) - else: - cache[es] = tuple(original_c) - else: - if es in cache: - cache.pop(es) - else: - raise RuntimeError(f"expected cycle {original_c} was not computed") - - if not all(g.has_edge(*e) for e in es): - raise RuntimeError( - f"{source} claimed cycle {original_c} is not a cycle of g" - ) - if chordless and len(g.subgraph(c).edges) > len(c): - raise RuntimeError(f"{source} cycle {original_c} is not chordless") - - def check_cycle_algorithm( - self, - g, - expected_cycles, - length_bound=None, - chordless=False, - algorithm=None, - ): - if algorithm is None: - algorithm = nx.chordless_cycles if chordless else nx.simple_cycles - - # note: we shuffle the labels of g to rule out accidentally-correct - # behavior which occurred during the development of chordless cycle - # enumeration algorithms - - relabel = list(range(len(g))) - shuffle(relabel) - label = dict(zip(g, relabel)) - unlabel = dict(zip(relabel, g)) - h = nx.relabel_nodes(g, label, copy=True) - - edgeset = self.edgeset_function(h) - - params = {} - if length_bound is not None: - params["length_bound"] = length_bound - - cycle_cache = {} - for c in algorithm(h, **params): - original_c = [unlabel[x] for x in c] - es = edgeset(c) - self.check_cycle( - h, c, es, cycle_cache, "computed", original_c, length_bound, chordless - ) - - if isinstance(expected_cycles, int): - if len(cycle_cache) != expected_cycles: - raise RuntimeError( - f"expected {expected_cycles} cycles, got {len(cycle_cache)}" - ) - return - for original_c in expected_cycles: - c = [label[x] for x in original_c] - es = edgeset(c) - self.check_cycle( - h, c, es, cycle_cache, "expected", original_c, length_bound, chordless - ) - - if len(cycle_cache): - for c in cycle_cache.values(): - raise RuntimeError( - f"computed cycle {c} is valid but not in the expected cycle set!" - ) - - def check_cycle_enumeration_integer_sequence( - self, - g_family, - cycle_counts, - length_bound=None, - chordless=False, - algorithm=None, - ): - for g, num_cycles in zip(g_family, cycle_counts): - self.check_cycle_algorithm( - g, - num_cycles, - length_bound=length_bound, - chordless=chordless, - algorithm=algorithm, - ) - - def test_directed_chordless_cycle_digons(self): - g = nx.DiGraph() - nx.add_cycle(g, range(5)) - nx.add_cycle(g, range(5)[::-1]) - g.add_edge(0, 0) - expected_cycles = [(0,), (1, 2), (2, 3), (3, 4)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - self.check_cycle_algorithm(g, expected_cycles, chordless=True, length_bound=2) - - expected_cycles = [c for c in expected_cycles if len(c) < 2] - self.check_cycle_algorithm(g, expected_cycles, chordless=True, length_bound=1) - - def test_directed_chordless_cycle_undirected(self): - g = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 5), (5, 0), (5, 1), (0, 2)]) - expected_cycles = [(0, 2, 3, 4, 5), (1, 2, 3, 4, 5)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - g = nx.DiGraph() - nx.add_cycle(g, range(5)) - nx.add_cycle(g, range(4, 9)) - g.add_edge(7, 3) - expected_cycles = [(0, 1, 2, 3, 4), (3, 4, 5, 6, 7), (4, 5, 6, 7, 8)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - g.add_edge(3, 7) - expected_cycles = [(0, 1, 2, 3, 4), (3, 7), (4, 5, 6, 7, 8)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - expected_cycles = [(3, 7)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True, length_bound=4) - - g.remove_edge(7, 3) - expected_cycles = [(0, 1, 2, 3, 4), (4, 5, 6, 7, 8)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - g = nx.DiGraph((i, j) for i in range(10) for j in range(i)) - expected_cycles = [] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - def test_chordless_cycles_directed(self): - G = nx.DiGraph() - nx.add_cycle(G, range(5)) - nx.add_cycle(G, range(4, 12)) - expected = [[*range(5)], [*range(4, 12)]] - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - G.add_edge(7, 3) - expected.append([*range(3, 8)]) - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - G.add_edge(3, 7) - expected[-1] = [7, 3] - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - expected.pop() - G.remove_edge(7, 3) - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - def test_directed_chordless_cycle_diclique(self): - g_family = [self.D(n) for n in range(10)] - expected_cycles = [(n * n - n) // 2 for n in range(10)] - self.check_cycle_enumeration_integer_sequence( - g_family, expected_cycles, chordless=True - ) - - expected_cycles = [(n * n - n) // 2 for n in range(10)] - self.check_cycle_enumeration_integer_sequence( - g_family, expected_cycles, length_bound=2 - ) - - def test_directed_chordless_loop_blockade(self): - g = nx.DiGraph((i, i) for i in range(10)) - nx.add_cycle(g, range(10)) - expected_cycles = [(i,) for i in range(10)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - self.check_cycle_algorithm(g, expected_cycles, length_bound=1) - - g = nx.MultiDiGraph(g) - g.add_edges_from((i, i) for i in range(0, 10, 2)) - expected_cycles = [(i,) for i in range(1, 10, 2)] - self.check_cycle_algorithm(g, expected_cycles, chordless=True) - - def test_simple_cycles_notable_clique_sequences(self): - # A000292: Number of labeled graphs on n+3 nodes that are triangles. - g_family = [self.K(n) for n in range(2, 12)] - expected = [0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, length_bound=3 - ) - - def triangles(g, **kwargs): - yield from (c for c in nx.simple_cycles(g, **kwargs) if len(c) == 3) - - # directed complete graphs have twice as many triangles thanks to reversal - g_family = [self.D(n) for n in range(2, 12)] - expected = [2 * e for e in expected] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, length_bound=3, algorithm=triangles - ) - - def four_cycles(g, **kwargs): - yield from (c for c in nx.simple_cycles(g, **kwargs) if len(c) == 4) - - # A050534: the number of 4-cycles in the complete graph K_{n+1} - expected = [0, 0, 0, 3, 15, 45, 105, 210, 378, 630, 990] - g_family = [self.K(n) for n in range(1, 12)] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, length_bound=4, algorithm=four_cycles - ) - - # directed complete graphs have twice as many 4-cycles thanks to reversal - expected = [2 * e for e in expected] - g_family = [self.D(n) for n in range(1, 15)] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, length_bound=4, algorithm=four_cycles - ) - - # A006231: the number of elementary circuits in a complete directed graph with n nodes - expected = [0, 1, 5, 20, 84, 409, 2365] - g_family = [self.D(n) for n in range(1, 8)] - self.check_cycle_enumeration_integer_sequence(g_family, expected) - - # A002807: Number of cycles in the complete graph on n nodes K_{n}. - expected = [0, 0, 0, 1, 7, 37, 197, 1172] - g_family = [self.K(n) for n in range(8)] - self.check_cycle_enumeration_integer_sequence(g_family, expected) - - def test_directed_chordless_cycle_parallel_multiedges(self): - g = nx.MultiGraph() - - nx.add_cycle(g, range(5)) - expected = [[*range(5)]] - self.check_cycle_algorithm(g, expected, chordless=True) - - nx.add_cycle(g, range(5)) - expected = [*cycle_edges(range(5))] - self.check_cycle_algorithm(g, expected, chordless=True) - - nx.add_cycle(g, range(5)) - expected = [] - self.check_cycle_algorithm(g, expected, chordless=True) - - g = nx.MultiDiGraph() - - nx.add_cycle(g, range(5)) - expected = [[*range(5)]] - self.check_cycle_algorithm(g, expected, chordless=True) - - nx.add_cycle(g, range(5)) - self.check_cycle_algorithm(g, [], chordless=True) - - nx.add_cycle(g, range(5)) - self.check_cycle_algorithm(g, [], chordless=True) - - g = nx.MultiDiGraph() - - nx.add_cycle(g, range(5)) - nx.add_cycle(g, range(5)[::-1]) - expected = [*cycle_edges(range(5))] - self.check_cycle_algorithm(g, expected, chordless=True) - - nx.add_cycle(g, range(5)) - self.check_cycle_algorithm(g, [], chordless=True) - - def test_chordless_cycles_graph(self): - G = nx.Graph() - nx.add_cycle(G, range(5)) - nx.add_cycle(G, range(4, 12)) - expected = [[*range(5)], [*range(4, 12)]] - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - G.add_edge(7, 3) - expected.append([*range(3, 8)]) - expected.append([4, 3, 7, 8, 9, 10, 11]) - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 5], length_bound=5, chordless=True - ) - - def test_chordless_cycles_giant_hamiltonian(self): - # ... o - e - o - e - o ... # o = odd, e = even - # ... ---/ \-----/ \--- ... # <-- "long" edges - # - # each long edge belongs to exactly one triangle, and one giant cycle - # of length n/2. The remaining edges each belong to a triangle - - n = 1000 - assert n % 2 == 0 - G = nx.Graph() - for v in range(n): - if not v % 2: - G.add_edge(v, (v + 2) % n) - G.add_edge(v, (v + 1) % n) - - expected = [[*range(0, n, 2)]] + [ - [x % n for x in range(i, i + 3)] for i in range(0, n, 2) - ] - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 3], length_bound=3, chordless=True - ) - - # ... o -> e -> o -> e -> o ... # o = odd, e = even - # ... <---/ \---<---/ \---< ... # <-- "long" edges - # - # this time, we orient the short and long edges in opposition - # the cycle structure of this graph is the same, but we need to reverse - # the long one in our representation. Also, we need to drop the size - # because our partitioning algorithm uses strongly connected components - # instead of separating graphs by their strong articulation points - - n = 100 - assert n % 2 == 0 - G = nx.DiGraph() - for v in range(n): - G.add_edge(v, (v + 1) % n) - if not v % 2: - G.add_edge((v + 2) % n, v) - - expected = [[*range(n - 2, -2, -2)]] + [ - [x % n for x in range(i, i + 3)] for i in range(0, n, 2) - ] - self.check_cycle_algorithm(G, expected, chordless=True) - self.check_cycle_algorithm( - G, [c for c in expected if len(c) <= 3], length_bound=3, chordless=True - ) - - def test_simple_cycles_acyclic_tournament(self): - n = 10 - G = nx.DiGraph((x, y) for x in range(n) for y in range(x)) - self.check_cycle_algorithm(G, []) - self.check_cycle_algorithm(G, [], chordless=True) - - for k in range(n + 1): - self.check_cycle_algorithm(G, [], length_bound=k) - self.check_cycle_algorithm(G, [], length_bound=k, chordless=True) - - def test_simple_cycles_graph(self): - testG = nx.cycle_graph(8) - cyc1 = tuple(range(8)) - self.check_cycle_algorithm(testG, [cyc1]) - - testG.add_edge(4, -1) - nx.add_path(testG, [3, -2, -3, -4]) - self.check_cycle_algorithm(testG, [cyc1]) - - testG.update(nx.cycle_graph(range(8, 16))) - cyc2 = tuple(range(8, 16)) - self.check_cycle_algorithm(testG, [cyc1, cyc2]) - - testG.update(nx.cycle_graph(range(4, 12))) - cyc3 = tuple(range(4, 12)) - expected = { - (0, 1, 2, 3, 4, 5, 6, 7), # cyc1 - (8, 9, 10, 11, 12, 13, 14, 15), # cyc2 - (4, 5, 6, 7, 8, 9, 10, 11), # cyc3 - (4, 5, 6, 7, 8, 15, 14, 13, 12, 11), # cyc2 + cyc3 - (0, 1, 2, 3, 4, 11, 10, 9, 8, 7), # cyc1 + cyc3 - (0, 1, 2, 3, 4, 11, 12, 13, 14, 15, 8, 7), # cyc1 + cyc2 + cyc3 - } - self.check_cycle_algorithm(testG, expected) - assert len(expected) == (2**3 - 1) - 1 # 1 disjoint comb: cyc1 + cyc2 - - # Basis size = 5 (2 loops overlapping gives 5 small loops - # E - # / \ Note: A-F = 10-15 - # 1-2-3-4-5 - # / | | \ cyc1=012DAB -- left - # 0 D F 6 cyc2=234E -- top - # \ | | / cyc3=45678F -- right - # B-A-9-8-7 cyc4=89AC -- bottom - # \ / cyc5=234F89AD -- middle - # C - # - # combinations of 5 basis elements: 2^5 - 1 (one includes no cycles) - # - # disjoint combs: (11 total) not simple cycles - # Any pair not including cyc5 => choose(4, 2) = 6 - # Any triple not including cyc5 => choose(4, 3) = 4 - # Any quad not including cyc5 => choose(4, 4) = 1 - # - # we expect 31 - 11 = 20 simple cycles - # - testG = nx.cycle_graph(12) - testG.update(nx.cycle_graph([12, 10, 13, 2, 14, 4, 15, 8]).edges) - expected = (2**5 - 1) - 11 # 11 disjoint combinations - self.check_cycle_algorithm(testG, expected) - - def test_simple_cycles_bounded(self): - # iteratively construct a cluster of nested cycles running in the same direction - # there should be one cycle of every length - d = nx.DiGraph() - expected = [] - for n in range(10): - nx.add_cycle(d, range(n)) - expected.append(n) - for k, e in enumerate(expected): - self.check_cycle_algorithm(d, e, length_bound=k) - - # iteratively construct a path of undirected cycles, connected at articulation - # points. there should be one cycle of every length except 2: no digons - g = nx.Graph() - top = 0 - expected = [] - for n in range(10): - expected.append(n if n < 2 else n - 1) - if n == 2: - # no digons in undirected graphs - continue - nx.add_cycle(g, range(top, top + n)) - top += n - for k, e in enumerate(expected): - self.check_cycle_algorithm(g, e, length_bound=k) - - def test_simple_cycles_bound_corner_cases(self): - G = nx.cycle_graph(4) - DG = nx.cycle_graph(4, create_using=nx.DiGraph) - assert list(nx.simple_cycles(G, length_bound=0)) == [] - assert list(nx.simple_cycles(DG, length_bound=0)) == [] - assert list(nx.chordless_cycles(G, length_bound=0)) == [] - assert list(nx.chordless_cycles(DG, length_bound=0)) == [] - - def test_simple_cycles_bound_error(self): - with pytest.raises(ValueError): - G = nx.DiGraph() - for c in nx.simple_cycles(G, -1): - assert False - - with pytest.raises(ValueError): - G = nx.Graph() - for c in nx.simple_cycles(G, -1): - assert False - - with pytest.raises(ValueError): - G = nx.Graph() - for c in nx.chordless_cycles(G, -1): - assert False - - with pytest.raises(ValueError): - G = nx.DiGraph() - for c in nx.chordless_cycles(G, -1): - assert False - - def test_chordless_cycles_clique(self): - g_family = [self.K(n) for n in range(2, 15)] - expected = [0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, chordless=True - ) - - # directed cliques have as many digons as undirected graphs have edges - expected = [(n * n - n) // 2 for n in range(15)] - g_family = [self.D(n) for n in range(15)] - self.check_cycle_enumeration_integer_sequence( - g_family, expected, chordless=True - ) - - -# These tests might fail with hash randomization since they depend on -# edge_dfs. For more information, see the comments in: -# networkx/algorithms/traversal/tests/test_edgedfs.py - - -class TestFindCycle: - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(-1, 0), (0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - def test_graph_nocycle(self): - G = nx.Graph(self.edges) - pytest.raises(nx.exception.NetworkXNoCycle, nx.find_cycle, G, self.nodes) - - def test_graph_cycle(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(nx.find_cycle(G, self.nodes)) - x_ = [(0, 1), (1, 2), (2, 0)] - assert x == x_ - - def test_graph_orientation_none(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(nx.find_cycle(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 2), (2, 0)] - assert x == x_ - - def test_graph_orientation_original(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(nx.find_cycle(G, self.nodes, orientation="original")) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 0, FORWARD)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes)) - x_ = [(0, 1), (1, 0)] - assert x == x_ - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes, orientation="original")) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 1)] # or (1, 0, 2) - # Hash randomization...could be any edge. - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0)] # (1, 0, 1) - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes, orientation="ignore")) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD)] - assert x == x_ - - def test_digraph_reverse(self): - G = nx.DiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes, orientation="reverse")) - x_ = [(1, 0, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(nx.find_cycle(G, self.nodes, orientation="ignore")) - x_ = [(0, 1, 0, FORWARD), (1, 0, 0, FORWARD)] # or (1, 0, 1, 1) - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - assert x[1][3] == x_[1][3] - - def test_multidigraph_ignore2(self): - # Loop traversed an edge while ignoring its orientation. - G = nx.MultiDiGraph([(0, 1), (1, 2), (1, 2)]) - x = list(nx.find_cycle(G, [0, 1, 2], orientation="ignore")) - x_ = [(1, 2, 0, FORWARD), (1, 2, 1, REVERSE)] - assert x == x_ - - def test_multidigraph_original(self): - # Node 2 doesn't need to be searched again from visited from 4. - # The goal here is to cover the case when 2 to be researched from 4, - # when 4 is visited from the first time (so we must make sure that 4 - # is not visited from 2, and hence, we respect the edge orientation). - G = nx.MultiDiGraph([(0, 1), (1, 2), (2, 3), (4, 2)]) - pytest.raises( - nx.exception.NetworkXNoCycle, - nx.find_cycle, - G, - [0, 1, 2, 3, 4], - orientation="original", - ) - - def test_dag(self): - G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - pytest.raises( - nx.exception.NetworkXNoCycle, nx.find_cycle, G, orientation="original" - ) - x = list(nx.find_cycle(G, orientation="ignore")) - assert x == [(0, 1, FORWARD), (1, 2, FORWARD), (0, 2, REVERSE)] - - def test_prev_explored(self): - # https://github.com/networkx/networkx/issues/2323 - - G = nx.DiGraph() - G.add_edges_from([(1, 0), (2, 0), (1, 2), (2, 1)]) - pytest.raises(nx.NetworkXNoCycle, nx.find_cycle, G, source=0) - x = list(nx.find_cycle(G, 1)) - x_ = [(1, 2), (2, 1)] - assert x == x_ - - x = list(nx.find_cycle(G, 2)) - x_ = [(2, 1), (1, 2)] - assert x == x_ - - x = list(nx.find_cycle(G)) - x_ = [(1, 2), (2, 1)] - assert x == x_ - - def test_no_cycle(self): - # https://github.com/networkx/networkx/issues/2439 - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 0), (3, 1), (3, 2)]) - pytest.raises(nx.NetworkXNoCycle, nx.find_cycle, G, source=0) - pytest.raises(nx.NetworkXNoCycle, nx.find_cycle, G) - - -def assert_basis_equal(a, b): - assert sorted(a) == sorted(b) - - -class TestMinimumCycleBasis: - @classmethod - def setup_class(cls): - T = nx.Graph() - nx.add_cycle(T, [1, 2, 3, 4], weight=1) - T.add_edge(2, 4, weight=5) - cls.diamond_graph = T - - def test_unweighted_diamond(self): - mcb = nx.minimum_cycle_basis(self.diamond_graph) - assert_basis_equal(mcb, [[2, 4, 1], [3, 4, 2]]) - - def test_weighted_diamond(self): - mcb = nx.minimum_cycle_basis(self.diamond_graph, weight="weight") - assert_basis_equal(mcb, [[2, 4, 1], [4, 3, 2, 1]]) - - def test_dimensionality(self): - # checks |MCB|=|E|-|V|+|NC| - ntrial = 10 - for seed in range(1234, 1234 + ntrial): - rg = nx.erdos_renyi_graph(10, 0.3, seed=seed) - nnodes = rg.number_of_nodes() - nedges = rg.number_of_edges() - ncomp = nx.number_connected_components(rg) - - mcb = nx.minimum_cycle_basis(rg) - assert len(mcb) == nedges - nnodes + ncomp - check_independent(mcb) - - def test_complete_graph(self): - cg = nx.complete_graph(5) - mcb = nx.minimum_cycle_basis(cg) - assert all(len(cycle) == 3 for cycle in mcb) - check_independent(mcb) - - def test_tree_graph(self): - tg = nx.balanced_tree(3, 3) - assert not nx.minimum_cycle_basis(tg) - - def test_petersen_graph(self): - G = nx.petersen_graph() - mcb = list(nx.minimum_cycle_basis(G)) - expected = [ - [4, 9, 7, 5, 0], - [1, 2, 3, 4, 0], - [1, 6, 8, 5, 0], - [4, 3, 8, 5, 0], - [1, 6, 9, 4, 0], - [1, 2, 7, 5, 0], - ] - assert len(mcb) == len(expected) - assert all(c in expected for c in mcb) - - # check that order of the nodes is a path - for c in mcb: - assert all(G.has_edge(u, v) for u, v in nx.utils.pairwise(c, cyclic=True)) - # check independence of the basis - check_independent(mcb) - - def test_gh6787_variable_weighted_complete_graph(self): - N = 8 - cg = nx.complete_graph(N) - cg.add_weighted_edges_from([(u, v, 9) for u, v in cg.edges]) - cg.add_weighted_edges_from([(u, v, 1) for u, v in nx.cycle_graph(N).edges]) - mcb = nx.minimum_cycle_basis(cg, weight="weight") - check_independent(mcb) - - def test_gh6787_and_edge_attribute_names(self): - G = nx.cycle_graph(4) - G.add_weighted_edges_from([(0, 2, 10), (1, 3, 10)], weight="dist") - expected = [[1, 3, 0], [3, 2, 1, 0], [1, 2, 0]] - mcb = list(nx.minimum_cycle_basis(G, weight="dist")) - assert len(mcb) == len(expected) - assert all(c in expected for c in mcb) - - # test not using a weight with weight attributes - expected = [[1, 3, 0], [1, 2, 0], [3, 2, 0]] - mcb = list(nx.minimum_cycle_basis(G)) - assert len(mcb) == len(expected) - assert all(c in expected for c in mcb) - - -class TestGirth: - @pytest.mark.parametrize( - ("G", "expected"), - ( - (nx.chvatal_graph(), 4), - (nx.tutte_graph(), 4), - (nx.petersen_graph(), 5), - (nx.heawood_graph(), 6), - (nx.pappus_graph(), 6), - (nx.random_labeled_tree(10, seed=42), inf), - (nx.empty_graph(10), inf), - (nx.Graph(chain(cycle_edges(range(5)), cycle_edges(range(6, 10)))), 4), - ( - nx.Graph( - [ - (0, 6), - (0, 8), - (0, 9), - (1, 8), - (2, 8), - (2, 9), - (4, 9), - (5, 9), - (6, 8), - (6, 9), - (7, 8), - ] - ), - 3, - ), - ), - ) - def test_girth(self, G, expected): - assert nx.girth(G) == expected diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_d_separation.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_d_separation.py deleted file mode 100644 index 6f62971..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_d_separation.py +++ /dev/null @@ -1,348 +0,0 @@ -from itertools import combinations - -import pytest - -import networkx as nx - - -def path_graph(): - """Return a path graph of length three.""" - G = nx.path_graph(3, create_using=nx.DiGraph) - G.graph["name"] = "path" - nx.freeze(G) - return G - - -def fork_graph(): - """Return a three node fork graph.""" - G = nx.DiGraph(name="fork") - G.add_edges_from([(0, 1), (0, 2)]) - nx.freeze(G) - return G - - -def collider_graph(): - """Return a collider/v-structure graph with three nodes.""" - G = nx.DiGraph(name="collider") - G.add_edges_from([(0, 2), (1, 2)]) - nx.freeze(G) - return G - - -def naive_bayes_graph(): - """Return a simply Naive Bayes PGM graph.""" - G = nx.DiGraph(name="naive_bayes") - G.add_edges_from([(0, 1), (0, 2), (0, 3), (0, 4)]) - nx.freeze(G) - return G - - -def asia_graph(): - """Return the 'Asia' PGM graph.""" - G = nx.DiGraph(name="asia") - G.add_edges_from( - [ - ("asia", "tuberculosis"), - ("smoking", "cancer"), - ("smoking", "bronchitis"), - ("tuberculosis", "either"), - ("cancer", "either"), - ("either", "xray"), - ("either", "dyspnea"), - ("bronchitis", "dyspnea"), - ] - ) - nx.freeze(G) - return G - - -@pytest.fixture(name="path_graph") -def path_graph_fixture(): - return path_graph() - - -@pytest.fixture(name="fork_graph") -def fork_graph_fixture(): - return fork_graph() - - -@pytest.fixture(name="collider_graph") -def collider_graph_fixture(): - return collider_graph() - - -@pytest.fixture(name="naive_bayes_graph") -def naive_bayes_graph_fixture(): - return naive_bayes_graph() - - -@pytest.fixture(name="asia_graph") -def asia_graph_fixture(): - return asia_graph() - - -@pytest.fixture() -def large_collider_graph(): - edge_list = [("A", "B"), ("C", "B"), ("B", "D"), ("D", "E"), ("B", "F"), ("G", "E")] - G = nx.DiGraph(edge_list) - return G - - -@pytest.fixture() -def chain_and_fork_graph(): - edge_list = [("A", "B"), ("B", "C"), ("B", "D"), ("D", "C")] - G = nx.DiGraph(edge_list) - return G - - -@pytest.fixture() -def no_separating_set_graph(): - edge_list = [("A", "B")] - G = nx.DiGraph(edge_list) - return G - - -@pytest.fixture() -def large_no_separating_set_graph(): - edge_list = [("A", "B"), ("C", "A"), ("C", "B")] - G = nx.DiGraph(edge_list) - return G - - -@pytest.fixture() -def collider_trek_graph(): - edge_list = [("A", "B"), ("C", "B"), ("C", "D")] - G = nx.DiGraph(edge_list) - return G - - -@pytest.mark.parametrize( - "graph", - [path_graph(), fork_graph(), collider_graph(), naive_bayes_graph(), asia_graph()], -) -def test_markov_condition(graph): - """Test that the Markov condition holds for each PGM graph.""" - for node in graph.nodes: - parents = set(graph.predecessors(node)) - non_descendants = graph.nodes - nx.descendants(graph, node) - {node} - parents - assert nx.is_d_separator(graph, {node}, non_descendants, parents) - - -def test_path_graph_dsep(path_graph): - """Example-based test of d-separation for path_graph.""" - assert nx.is_d_separator(path_graph, {0}, {2}, {1}) - assert not nx.is_d_separator(path_graph, {0}, {2}, set()) - - -def test_fork_graph_dsep(fork_graph): - """Example-based test of d-separation for fork_graph.""" - assert nx.is_d_separator(fork_graph, {1}, {2}, {0}) - assert not nx.is_d_separator(fork_graph, {1}, {2}, set()) - - -def test_collider_graph_dsep(collider_graph): - """Example-based test of d-separation for collider_graph.""" - assert nx.is_d_separator(collider_graph, {0}, {1}, set()) - assert not nx.is_d_separator(collider_graph, {0}, {1}, {2}) - - -def test_naive_bayes_dsep(naive_bayes_graph): - """Example-based test of d-separation for naive_bayes_graph.""" - for u, v in combinations(range(1, 5), 2): - assert nx.is_d_separator(naive_bayes_graph, {u}, {v}, {0}) - assert not nx.is_d_separator(naive_bayes_graph, {u}, {v}, set()) - - -def test_asia_graph_dsep(asia_graph): - """Example-based test of d-separation for asia_graph.""" - assert nx.is_d_separator( - asia_graph, {"asia", "smoking"}, {"dyspnea", "xray"}, {"bronchitis", "either"} - ) - assert nx.is_d_separator( - asia_graph, {"tuberculosis", "cancer"}, {"bronchitis"}, {"smoking", "xray"} - ) - - -def test_undirected_graphs_are_not_supported(): - """ - Test that undirected graphs are not supported. - - d-separation and its related algorithms do not apply in - the case of undirected graphs. - """ - g = nx.path_graph(3, nx.Graph) - with pytest.raises(nx.NetworkXNotImplemented): - nx.is_d_separator(g, {0}, {1}, {2}) - with pytest.raises(nx.NetworkXNotImplemented): - nx.is_minimal_d_separator(g, {0}, {1}, {2}) - with pytest.raises(nx.NetworkXNotImplemented): - nx.find_minimal_d_separator(g, {0}, {1}) - - -def test_cyclic_graphs_raise_error(): - """ - Test that cycle graphs should cause erroring. - - This is because PGMs assume a directed acyclic graph. - """ - g = nx.cycle_graph(3, nx.DiGraph) - with pytest.raises(nx.NetworkXError): - nx.is_d_separator(g, {0}, {1}, {2}) - with pytest.raises(nx.NetworkXError): - nx.find_minimal_d_separator(g, {0}, {1}) - with pytest.raises(nx.NetworkXError): - nx.is_minimal_d_separator(g, {0}, {1}, {2}) - - -def test_invalid_nodes_raise_error(asia_graph): - """ - Test that graphs that have invalid nodes passed in raise errors. - """ - # Check both set and node arguments - with pytest.raises(nx.NodeNotFound): - nx.is_d_separator(asia_graph, {0}, {1}, {2}) - with pytest.raises(nx.NodeNotFound): - nx.is_d_separator(asia_graph, 0, 1, 2) - with pytest.raises(nx.NodeNotFound): - nx.is_minimal_d_separator(asia_graph, {0}, {1}, {2}) - with pytest.raises(nx.NodeNotFound): - nx.is_minimal_d_separator(asia_graph, 0, 1, 2) - with pytest.raises(nx.NodeNotFound): - nx.find_minimal_d_separator(asia_graph, {0}, {1}) - with pytest.raises(nx.NodeNotFound): - nx.find_minimal_d_separator(asia_graph, 0, 1) - - -def test_nondisjoint_node_sets_raise_error(collider_graph): - """ - Test that error is raised when node sets aren't disjoint. - """ - with pytest.raises(nx.NetworkXError): - nx.is_d_separator(collider_graph, 0, 1, 0) - with pytest.raises(nx.NetworkXError): - nx.is_d_separator(collider_graph, 0, 2, 0) - with pytest.raises(nx.NetworkXError): - nx.is_d_separator(collider_graph, 0, 0, 1) - with pytest.raises(nx.NetworkXError): - nx.is_d_separator(collider_graph, 1, 0, 0) - with pytest.raises(nx.NetworkXError): - nx.find_minimal_d_separator(collider_graph, 0, 0) - with pytest.raises(nx.NetworkXError): - nx.find_minimal_d_separator(collider_graph, 0, 1, included=0) - with pytest.raises(nx.NetworkXError): - nx.find_minimal_d_separator(collider_graph, 1, 0, included=0) - with pytest.raises(nx.NetworkXError): - nx.is_minimal_d_separator(collider_graph, 0, 0, set()) - with pytest.raises(nx.NetworkXError): - nx.is_minimal_d_separator(collider_graph, 0, 1, set(), included=0) - with pytest.raises(nx.NetworkXError): - nx.is_minimal_d_separator(collider_graph, 1, 0, set(), included=0) - - -def test_is_minimal_d_separator( - large_collider_graph, - chain_and_fork_graph, - no_separating_set_graph, - large_no_separating_set_graph, - collider_trek_graph, -): - # Case 1: - # create a graph A -> B <- C - # B -> D -> E; - # B -> F; - # G -> E; - assert not nx.is_d_separator(large_collider_graph, {"B"}, {"E"}, set()) - - # minimal set of the corresponding graph - # for B and E should be (D,) - Zmin = nx.find_minimal_d_separator(large_collider_graph, "B", "E") - # check that the minimal d-separator is a d-separating set - assert nx.is_d_separator(large_collider_graph, "B", "E", Zmin) - # the minimal separating set should also pass the test for minimality - assert nx.is_minimal_d_separator(large_collider_graph, "B", "E", Zmin) - # function should also work with set arguments - assert nx.is_minimal_d_separator(large_collider_graph, {"A", "B"}, {"G", "E"}, Zmin) - assert Zmin == {"D"} - - # Case 2: - # create a graph A -> B -> C - # B -> D -> C; - assert not nx.is_d_separator(chain_and_fork_graph, {"A"}, {"C"}, set()) - Zmin = nx.find_minimal_d_separator(chain_and_fork_graph, "A", "C") - - # the minimal separating set should pass the test for minimality - assert nx.is_minimal_d_separator(chain_and_fork_graph, "A", "C", Zmin) - assert Zmin == {"B"} - Znotmin = Zmin.union({"D"}) - assert not nx.is_minimal_d_separator(chain_and_fork_graph, "A", "C", Znotmin) - - # Case 3: - # create a graph A -> B - - # there is no m-separating set between A and B at all, so - # no minimal m-separating set can exist - assert not nx.is_d_separator(no_separating_set_graph, {"A"}, {"B"}, set()) - assert nx.find_minimal_d_separator(no_separating_set_graph, "A", "B") is None - - # Case 4: - # create a graph A -> B with A <- C -> B - - # there is no m-separating set between A and B at all, so - # no minimal m-separating set can exist - # however, the algorithm will initially propose C as a - # minimal (but invalid) separating set - assert not nx.is_d_separator(large_no_separating_set_graph, {"A"}, {"B"}, {"C"}) - assert nx.find_minimal_d_separator(large_no_separating_set_graph, "A", "B") is None - - # Test `included` and `excluded` args - # create graph A -> B <- C -> D - assert nx.find_minimal_d_separator(collider_trek_graph, "A", "D", included="B") == { - "B", - "C", - } - assert ( - nx.find_minimal_d_separator( - collider_trek_graph, "A", "D", included="B", restricted="B" - ) - is None - ) - - -def test_is_minimal_d_separator_checks_dsep(): - """Test that is_minimal_d_separator checks for d-separation as well.""" - g = nx.DiGraph() - g.add_edges_from( - [ - ("A", "B"), - ("A", "E"), - ("B", "C"), - ("B", "D"), - ("D", "C"), - ("D", "F"), - ("E", "D"), - ("E", "F"), - ] - ) - - assert not nx.is_d_separator(g, {"C"}, {"F"}, {"D"}) - - # since {'D'} and {} are not d-separators, we return false - assert not nx.is_minimal_d_separator(g, "C", "F", {"D"}) - assert not nx.is_minimal_d_separator(g, "C", "F", set()) - - -def test__reachable(large_collider_graph): - reachable = nx.algorithms.d_separation._reachable - g = large_collider_graph - x = {"F", "D"} - ancestors = {"A", "B", "C", "D", "F"} - assert reachable(g, x, ancestors, {"B"}) == {"B", "F", "D"} - assert reachable(g, x, ancestors, set()) == ancestors - - -def test_deprecations(): - G = nx.DiGraph([(0, 1), (1, 2)]) - with pytest.deprecated_call(): - nx.d_separated(G, 0, 2, {1}) - with pytest.deprecated_call(): - z = nx.minimal_d_separator(G, 0, 2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dag.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dag.py deleted file mode 100644 index e98a6a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dag.py +++ /dev/null @@ -1,835 +0,0 @@ -from collections import deque -from itertools import combinations, permutations - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, pairwise - - -# Recipe from the itertools documentation. -def _consume(iterator): - "Consume the iterator entirely." - # Feed the entire iterator into a zero-length deque. - deque(iterator, maxlen=0) - - -class TestDagLongestPath: - """Unit tests computing the longest path in a directed acyclic graph.""" - - def test_empty(self): - G = nx.DiGraph() - assert nx.dag_longest_path(G) == [] - - def test_unweighted1(self): - edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (3, 7)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path(G) == [1, 2, 3, 5, 6] - - def test_unweighted2(self): - edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path(G) == [1, 2, 3, 4, 5] - - def test_weighted(self): - G = nx.DiGraph() - edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), (1, 6, 2)] - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path(G) == [2, 3, 5] - - def test_undirected_not_implemented(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path, G) - - def test_unorderable_nodes(self): - """Tests that computing the longest path does not depend on - nodes being orderable. - - For more information, see issue #1989. - - """ - # Create the directed path graph on four nodes in a diamond shape, - # with nodes represented as (unorderable) Python objects. - nodes = [object() for n in range(4)] - G = nx.DiGraph() - G.add_edge(nodes[0], nodes[1]) - G.add_edge(nodes[0], nodes[2]) - G.add_edge(nodes[2], nodes[3]) - G.add_edge(nodes[1], nodes[3]) - - # this will raise NotImplementedError when nodes need to be ordered - nx.dag_longest_path(G) - - def test_multigraph_unweighted(self): - edges = [(1, 2), (2, 3), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.MultiDiGraph(edges) - assert nx.dag_longest_path(G) == [1, 2, 3, 4, 5] - - def test_multigraph_weighted(self): - G = nx.MultiDiGraph() - edges = [ - (1, 2, 2), - (2, 3, 2), - (1, 3, 1), - (1, 3, 5), - (1, 3, 2), - ] - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path(G) == [1, 3] - - def test_multigraph_weighted_default_weight(self): - G = nx.MultiDiGraph([(1, 2), (2, 3)]) # Unweighted edges - G.add_weighted_edges_from([(1, 3, 1), (1, 3, 5), (1, 3, 2)]) - - # Default value for default weight is 1 - assert nx.dag_longest_path(G) == [1, 3] - assert nx.dag_longest_path(G, default_weight=3) == [1, 2, 3] - - -class TestDagLongestPathLength: - """Unit tests for computing the length of a longest path in a - directed acyclic graph. - - """ - - def test_unweighted(self): - edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path_length(G) == 4 - - edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path_length(G) == 4 - - # test degenerate graphs - G = nx.DiGraph() - G.add_node(1) - assert nx.dag_longest_path_length(G) == 0 - - def test_undirected_not_implemented(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path_length, G) - - def test_weighted(self): - edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), (1, 6, 2)] - G = nx.DiGraph() - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path_length(G) == 5 - - def test_multigraph_unweighted(self): - edges = [(1, 2), (2, 3), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.MultiDiGraph(edges) - assert nx.dag_longest_path_length(G) == 4 - - def test_multigraph_weighted(self): - G = nx.MultiDiGraph() - edges = [ - (1, 2, 2), - (2, 3, 2), - (1, 3, 1), - (1, 3, 5), - (1, 3, 2), - ] - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path_length(G) == 5 - - -class TestDAG: - @classmethod - def setup_class(cls): - pass - - def test_topological_sort1(self): - DG = nx.DiGraph([(1, 2), (1, 3), (2, 3)]) - - for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]: - assert tuple(algorithm(DG)) == (1, 2, 3) - - DG.add_edge(3, 2) - - for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]: - pytest.raises(nx.NetworkXUnfeasible, _consume, algorithm(DG)) - - DG.remove_edge(2, 3) - - for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]: - assert tuple(algorithm(DG)) == (1, 3, 2) - - DG.remove_edge(3, 2) - - assert tuple(nx.topological_sort(DG)) in {(1, 2, 3), (1, 3, 2)} - assert tuple(nx.lexicographical_topological_sort(DG)) == (1, 2, 3) - - def test_is_directed_acyclic_graph(self): - G = nx.generators.complete_graph(2) - assert not nx.is_directed_acyclic_graph(G) - assert not nx.is_directed_acyclic_graph(G.to_directed()) - assert not nx.is_directed_acyclic_graph(nx.Graph([(3, 4), (4, 5)])) - assert nx.is_directed_acyclic_graph(nx.DiGraph([(3, 4), (4, 5)])) - - def test_topological_sort2(self): - DG = nx.DiGraph( - { - 1: [2], - 2: [3], - 3: [4], - 4: [5], - 5: [1], - 11: [12], - 12: [13], - 13: [14], - 14: [15], - } - ) - pytest.raises(nx.NetworkXUnfeasible, _consume, nx.topological_sort(DG)) - - assert not nx.is_directed_acyclic_graph(DG) - - DG.remove_edge(1, 2) - _consume(nx.topological_sort(DG)) - assert nx.is_directed_acyclic_graph(DG) - - def test_topological_sort3(self): - DG = nx.DiGraph() - DG.add_edges_from([(1, i) for i in range(2, 5)]) - DG.add_edges_from([(2, i) for i in range(5, 9)]) - DG.add_edges_from([(6, i) for i in range(9, 12)]) - DG.add_edges_from([(4, i) for i in range(12, 15)]) - - def validate(order): - assert isinstance(order, list) - assert set(order) == set(DG) - for u, v in combinations(order, 2): - assert not nx.has_path(DG, v, u) - - validate(list(nx.topological_sort(DG))) - - DG.add_edge(14, 1) - pytest.raises(nx.NetworkXUnfeasible, _consume, nx.topological_sort(DG)) - - def test_topological_sort4(self): - G = nx.Graph() - G.add_edge(1, 2) - # Only directed graphs can be topologically sorted. - pytest.raises(nx.NetworkXError, _consume, nx.topological_sort(G)) - - def test_topological_sort5(self): - G = nx.DiGraph() - G.add_edge(0, 1) - assert list(nx.topological_sort(G)) == [0, 1] - - def test_topological_sort6(self): - for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]: - - def runtime_error(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.add_edge(5 - x, 5) - - def unfeasible_error(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.remove_node(4) - - def runtime_error2(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.remove_node(2) - - pytest.raises(RuntimeError, runtime_error) - pytest.raises(RuntimeError, runtime_error2) - pytest.raises(nx.NetworkXUnfeasible, unfeasible_error) - - def test_all_topological_sorts_1(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 5)]) - assert list(nx.all_topological_sorts(DG)) == [[1, 2, 3, 4, 5]] - - def test_all_topological_sorts_2(self): - DG = nx.DiGraph([(1, 3), (2, 1), (2, 4), (4, 3), (4, 5)]) - assert sorted(nx.all_topological_sorts(DG)) == [ - [2, 1, 4, 3, 5], - [2, 1, 4, 5, 3], - [2, 4, 1, 3, 5], - [2, 4, 1, 5, 3], - [2, 4, 5, 1, 3], - ] - - def test_all_topological_sorts_3(self): - def unfeasible(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 2), (4, 5)]) - # convert to list to execute generator - list(nx.all_topological_sorts(DG)) - - def not_implemented(): - G = nx.Graph([(1, 2), (2, 3)]) - # convert to list to execute generator - list(nx.all_topological_sorts(G)) - - def not_implemented_2(): - G = nx.MultiGraph([(1, 2), (1, 2), (2, 3)]) - list(nx.all_topological_sorts(G)) - - pytest.raises(nx.NetworkXUnfeasible, unfeasible) - pytest.raises(nx.NetworkXNotImplemented, not_implemented) - pytest.raises(nx.NetworkXNotImplemented, not_implemented_2) - - def test_all_topological_sorts_4(self): - DG = nx.DiGraph() - for i in range(7): - DG.add_node(i) - assert sorted(map(list, permutations(DG.nodes))) == sorted( - nx.all_topological_sorts(DG) - ) - - def test_all_topological_sorts_multigraph_1(self): - DG = nx.MultiDiGraph([(1, 2), (1, 2), (2, 3), (3, 4), (3, 5), (3, 5), (3, 5)]) - assert sorted(nx.all_topological_sorts(DG)) == sorted( - [[1, 2, 3, 4, 5], [1, 2, 3, 5, 4]] - ) - - def test_all_topological_sorts_multigraph_2(self): - N = 9 - edges = [] - for i in range(1, N): - edges.extend([(i, i + 1)] * i) - DG = nx.MultiDiGraph(edges) - assert list(nx.all_topological_sorts(DG)) == [list(range(1, N + 1))] - - def test_ancestors(self): - G = nx.DiGraph() - ancestors = nx.algorithms.dag.ancestors - G.add_edges_from([(1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)]) - assert ancestors(G, 6) == {1, 2, 4, 5} - assert ancestors(G, 3) == {1, 4} - assert ancestors(G, 1) == set() - pytest.raises(nx.NetworkXError, ancestors, G, 8) - - def test_descendants(self): - G = nx.DiGraph() - descendants = nx.algorithms.dag.descendants - G.add_edges_from([(1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)]) - assert descendants(G, 1) == {2, 3, 6} - assert descendants(G, 4) == {2, 3, 5, 6} - assert descendants(G, 3) == set() - pytest.raises(nx.NetworkXError, descendants, G, 8) - - def test_transitive_closure(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert edges_equal(nx.transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - assert edges_equal(nx.transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - solution = [(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(sorted(nx.transitive_closure(G).edges()), soln) - - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution) - - G = nx.MultiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution) - - G = nx.MultiDiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution) - - # test if edge data is copied - G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)]) - H = nx.transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - k = 10 - G = nx.DiGraph((i, i + 1, {"f": "b", "weight": i}) for i in range(k)) - H = nx.transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - G = nx.Graph() - with pytest.raises(nx.NetworkXError): - nx.transitive_closure(G, reflexive="wrong input") - - def test_reflexive_transitive_closure(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(nx.transitive_closure(G).edges(), solution) - assert edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(nx.transitive_closure(G).edges(), solution) - assert edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - solution = sorted([(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)]) - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(sorted(nx.transitive_closure(G).edges()), soln) - assert edges_equal(sorted(nx.transitive_closure(G, False).edges()), soln) - assert edges_equal(sorted(nx.transitive_closure(G, None).edges()), solution) - assert edges_equal(sorted(nx.transitive_closure(G, True).edges()), soln) - - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(nx.transitive_closure(G).edges(), solution) - assert edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.MultiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(nx.transitive_closure(G).edges(), solution) - assert edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.MultiDiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert edges_equal(nx.transitive_closure(G).edges(), solution) - assert edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert edges_equal(nx.transitive_closure(G, None).edges(), solution) - - def test_transitive_closure_dag(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - transitive_closure = nx.algorithms.dag.transitive_closure_dag - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert edges_equal(transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - assert edges_equal(transitive_closure(G).edges(), solution) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, transitive_closure, G) - - # test if edge data is copied - G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)]) - H = transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - k = 10 - G = nx.DiGraph((i, i + 1, {"foo": "bar", "weight": i}) for i in range(k)) - H = transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - def test_transitive_reduction(self): - G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]) - transitive_reduction = nx.algorithms.dag.transitive_reduction - solution = [(1, 2), (2, 3), (3, 4)] - assert edges_equal(transitive_reduction(G).edges(), solution) - G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)]) - transitive_reduction = nx.algorithms.dag.transitive_reduction - solution = [(1, 2), (2, 3), (2, 4)] - assert edges_equal(transitive_reduction(G).edges(), solution) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, transitive_reduction, G) - - def _check_antichains(self, solution, result): - sol = [frozenset(a) for a in solution] - res = [frozenset(a) for a in result] - assert set(sol) == set(res) - - def test_antichains(self): - antichains = nx.algorithms.dag.antichains - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [[], [4], [3], [2], [1]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)]) - solution = [ - [], - [4], - [7], - [7, 4], - [6], - [6, 4], - [6, 7], - [6, 7, 4], - [5], - [5, 4], - [3], - [3, 4], - [2], - [1], - ] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph([(1, 2), (1, 3), (3, 4), (3, 5), (5, 6)]) - solution = [ - [], - [6], - [5], - [4], - [4, 6], - [4, 5], - [3], - [2], - [2, 6], - [2, 5], - [2, 4], - [2, 4, 6], - [2, 4, 5], - [2, 3], - [1], - ] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph({0: [1, 2], 1: [4], 2: [3], 3: [4]}) - solution = [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph() - self._check_antichains(list(antichains(G)), [[]]) - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2]) - solution = [[], [0], [1], [1, 0], [2], [2, 0], [2, 1], [2, 1, 0]] - self._check_antichains(list(antichains(G)), solution) - - def f(x): - return list(antichains(x)) - - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, f, G) - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - pytest.raises(nx.NetworkXUnfeasible, f, G) - - def test_lexicographical_topological_sort(self): - G = nx.DiGraph([(1, 2), (2, 3), (1, 4), (1, 5), (2, 6)]) - assert list(nx.lexicographical_topological_sort(G)) == [1, 2, 3, 4, 5, 6] - assert list(nx.lexicographical_topological_sort(G, key=lambda x: x)) == [ - 1, - 2, - 3, - 4, - 5, - 6, - ] - assert list(nx.lexicographical_topological_sort(G, key=lambda x: -x)) == [ - 1, - 5, - 4, - 2, - 6, - 3, - ] - - def test_lexicographical_topological_sort2(self): - """ - Check the case of two or more nodes with same key value. - Want to avoid exception raised due to comparing nodes directly. - See Issue #3493 - """ - - class Test_Node: - def __init__(self, n): - self.label = n - self.priority = 1 - - def __repr__(self): - return f"Node({self.label})" - - def sorting_key(node): - return node.priority - - test_nodes = [Test_Node(n) for n in range(4)] - G = nx.DiGraph() - edges = [(0, 1), (0, 2), (0, 3), (2, 3)] - G.add_edges_from((test_nodes[a], test_nodes[b]) for a, b in edges) - - sorting = list(nx.lexicographical_topological_sort(G, key=sorting_key)) - assert sorting == test_nodes - - -def test_topological_generations(): - G = nx.DiGraph( - {1: [2, 3], 2: [4, 5], 3: [7], 4: [], 5: [6, 7], 6: [], 7: []} - ).reverse() - # order within each generation is inconsequential - generations = [sorted(gen) for gen in nx.topological_generations(G)] - expected = [[4, 6, 7], [3, 5], [2], [1]] - assert generations == expected - - MG = nx.MultiDiGraph(G.edges) - MG.add_edge(2, 1) - generations = [sorted(gen) for gen in nx.topological_generations(MG)] - assert generations == expected - - -def test_topological_generations_empty(): - G = nx.DiGraph() - assert list(nx.topological_generations(G)) == [] - - -def test_topological_generations_cycle(): - G = nx.DiGraph([[2, 1], [3, 1], [1, 2]]) - with pytest.raises(nx.NetworkXUnfeasible): - list(nx.topological_generations(G)) - - -def test_is_aperiodic_cycle(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle2(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [3, 4, 5, 6, 7]) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle3(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [3, 4, 5, 6]) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle4(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - G.add_edge(1, 3) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_selfloop(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - G.add_edge(1, 1) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_undirected_raises(): - G = nx.Graph() - pytest.raises(nx.NetworkXError, nx.is_aperiodic, G) - - -def test_is_aperiodic_empty_graph(): - G = nx.empty_graph(create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXPointlessConcept, match="Graph has no nodes."): - nx.is_aperiodic(G) - - -def test_is_aperiodic_bipartite(): - # Bipartite graph - G = nx.DiGraph(nx.davis_southern_women_graph()) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_rary_tree(): - G = nx.full_rary_tree(3, 27, create_using=nx.DiGraph()) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_disconnected(): - # disconnected graph - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [5, 6, 7, 8]) - assert not nx.is_aperiodic(G) - G.add_edge(1, 3) - G.add_edge(5, 7) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_disconnected2(): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2]) - G.add_edge(3, 3) - assert not nx.is_aperiodic(G) - - -class TestDagToBranching: - """Unit tests for the :func:`networkx.dag_to_branching` function.""" - - def test_single_root(self): - """Tests that a directed acyclic graph with a single degree - zero node produces an arborescence. - - """ - G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)]) - B = nx.dag_to_branching(G) - expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4)]) - assert nx.is_arborescence(B) - assert nx.is_isomorphic(B, expected) - - def test_multiple_roots(self): - """Tests that a directed acyclic graph with multiple degree zero - nodes creates an arborescence with multiple (weakly) connected - components. - - """ - G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3), (5, 2)]) - B = nx.dag_to_branching(G) - expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4), (5, 6), (6, 7)]) - assert nx.is_branching(B) - assert not nx.is_arborescence(B) - assert nx.is_isomorphic(B, expected) - - # # Attributes are not copied by this function. If they were, this would - # # be a good test to uncomment. - # def test_copy_attributes(self): - # """Tests that node attributes are copied in the branching.""" - # G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)]) - # for v in G: - # G.node[v]['label'] = str(v) - # B = nx.dag_to_branching(G) - # # Determine the root node of the branching. - # root = next(v for v, d in B.in_degree() if d == 0) - # assert_equal(B.node[root]['label'], '0') - # children = B[root] - # # Get the left and right children, nodes 1 and 2, respectively. - # left, right = sorted(children, key=lambda v: B.node[v]['label']) - # assert_equal(B.node[left]['label'], '1') - # assert_equal(B.node[right]['label'], '2') - # # Get the left grandchild. - # children = B[left] - # assert_equal(len(children), 1) - # left_grandchild = arbitrary_element(children) - # assert_equal(B.node[left_grandchild]['label'], '3') - # # Get the right grandchild. - # children = B[right] - # assert_equal(len(children), 1) - # right_grandchild = arbitrary_element(children) - # assert_equal(B.node[right_grandchild]['label'], '3') - - def test_already_arborescence(self): - """Tests that a directed acyclic graph that is already an - arborescence produces an isomorphic arborescence as output. - - """ - A = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - B = nx.dag_to_branching(A) - assert nx.is_isomorphic(A, B) - - def test_already_branching(self): - """Tests that a directed acyclic graph that is already a - branching produces an isomorphic branching as output. - - """ - T1 = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - T2 = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - G = nx.disjoint_union(T1, T2) - B = nx.dag_to_branching(G) - assert nx.is_isomorphic(G, B) - - def test_not_acyclic(self): - """Tests that a non-acyclic graph causes an exception.""" - with pytest.raises(nx.HasACycle): - G = nx.DiGraph(pairwise("abc", cyclic=True)) - nx.dag_to_branching(G) - - def test_undirected(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.Graph()) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.MultiGraph()) - - def test_multidigraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.MultiDiGraph()) - - -def test_ancestors_descendants_undirected(): - """Regression test to ensure ancestors and descendants work as expected on - undirected graphs.""" - G = nx.path_graph(5) - nx.ancestors(G, 2) == nx.descendants(G, 2) == {0, 1, 3, 4} - - -def test_compute_v_structures_raise(): - G = nx.Graph() - with pytest.raises(nx.NetworkXNotImplemented, match="for undirected type"): - nx.compute_v_structures(G) - - -def test_compute_v_structures(): - edges = [(0, 1), (0, 2), (3, 2)] - G = nx.DiGraph(edges) - - v_structs = set(nx.compute_v_structures(G)) - assert len(v_structs) == 1 - assert (0, 2, 3) in v_structs - - edges = [("A", "B"), ("C", "B"), ("B", "D"), ("D", "E"), ("G", "E")] - G = nx.DiGraph(edges) - v_structs = set(nx.compute_v_structures(G)) - assert len(v_structs) == 2 - - -def test_compute_v_structures_deprecated(): - G = nx.DiGraph() - with pytest.deprecated_call(): - nx.compute_v_structures(G) - - -def test_v_structures_raise(): - G = nx.Graph() - with pytest.raises(nx.NetworkXNotImplemented, match="for undirected type"): - nx.dag.v_structures(G) - - -@pytest.mark.parametrize( - ("edgelist", "expected"), - ( - ( - [(0, 1), (0, 2), (3, 2)], - {(0, 2, 3)}, - ), - ( - [("A", "B"), ("C", "B"), ("D", "G"), ("D", "E"), ("G", "E")], - {("A", "B", "C")}, - ), - ([(0, 1), (2, 1), (0, 2)], set()), # adjacent parents case: see gh-7385 - ), -) -def test_v_structures(edgelist, expected): - G = nx.DiGraph(edgelist) - v_structs = set(nx.dag.v_structures(G)) - assert v_structs == expected - - -def test_colliders_raise(): - G = nx.Graph() - with pytest.raises(nx.NetworkXNotImplemented, match="for undirected type"): - nx.dag.colliders(G) - - -@pytest.mark.parametrize( - ("edgelist", "expected"), - ( - ( - [(0, 1), (0, 2), (3, 2)], - {(0, 2, 3)}, - ), - ( - [("A", "B"), ("C", "B"), ("D", "G"), ("D", "E"), ("G", "E")], - {("A", "B", "C"), ("D", "E", "G")}, - ), - ), -) -def test_colliders(edgelist, expected): - G = nx.DiGraph(edgelist) - colliders = set(nx.dag.colliders(G)) - assert colliders == expected diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_measures.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_measures.py deleted file mode 100644 index 0b3840f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_measures.py +++ /dev/null @@ -1,774 +0,0 @@ -import math -from random import Random - -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.algorithms.distance_measures import _extrema_bounding - - -def test__extrema_bounding_invalid_compute_kwarg(): - G = nx.path_graph(3) - with pytest.raises(ValueError, match="compute must be one of"): - _extrema_bounding(G, compute="spam") - - -class TestDistance: - def setup_method(self): - G = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - self.G = G - - def test_eccentricity(self): - assert nx.eccentricity(self.G, 1) == 6 - e = nx.eccentricity(self.G) - assert e[1] == 6 - - sp = dict(nx.shortest_path_length(self.G)) - e = nx.eccentricity(self.G, sp=sp) - assert e[1] == 6 - - e = nx.eccentricity(self.G, v=1) - assert e == 6 - - # This behavior changed in version 1.8 (ticket #739) - e = nx.eccentricity(self.G, v=[1, 1]) - assert e[1] == 6 - e = nx.eccentricity(self.G, v=[1, 2]) - assert e[1] == 6 - - # test against graph with one node - G = nx.path_graph(1) - e = nx.eccentricity(G) - assert e[0] == 0 - e = nx.eccentricity(G, v=0) - assert e == 0 - pytest.raises(nx.NetworkXError, nx.eccentricity, G, 1) - - # test against empty graph - G = nx.empty_graph() - e = nx.eccentricity(G) - assert e == {} - - def test_diameter(self): - assert nx.diameter(self.G) == 6 - - def test_harmonic_diameter(self): - assert abs(nx.harmonic_diameter(self.G) - 2.0477815699658715) < 1e-12 - - def test_harmonic_diameter_empty(self): - assert math.isnan(nx.harmonic_diameter(nx.empty_graph())) - - def test_harmonic_diameter_single_node(self): - assert math.isnan(nx.harmonic_diameter(nx.empty_graph(1))) - - def test_harmonic_diameter_discrete(self): - assert math.isinf(nx.harmonic_diameter(nx.empty_graph(3))) - - def test_harmonic_diameter_not_strongly_connected(self): - DG = nx.DiGraph() - DG.add_edge(0, 1) - assert nx.harmonic_diameter(DG) == 2 - - def test_radius(self): - assert nx.radius(self.G) == 4 - - def test_periphery(self): - assert set(nx.periphery(self.G)) == {1, 4, 13, 16} - - def test_center(self): - assert set(nx.center(self.G)) == {6, 7, 10, 11} - - def test_bound_diameter(self): - assert nx.diameter(self.G, usebounds=True) == 6 - - def test_bound_radius(self): - assert nx.radius(self.G, usebounds=True) == 4 - - def test_bound_periphery(self): - result = {1, 4, 13, 16} - assert set(nx.periphery(self.G, usebounds=True)) == result - - def test_bound_center(self): - result = {6, 7, 10, 11} - assert set(nx.center(self.G, usebounds=True)) == result - - def test_radius_exception(self): - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(3, 4) - pytest.raises(nx.NetworkXError, nx.diameter, G) - - def test_eccentricity_infinite(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph([(1, 2), (3, 4)]) - e = nx.eccentricity(G) - - def test_eccentricity_undirected_not_connected(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph([(1, 2), (3, 4)]) - e = nx.eccentricity(G, sp=1) - - def test_eccentricity_directed_weakly_connected(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph([(1, 2), (1, 3)]) - nx.eccentricity(DG) - - -class TestWeightedDistance: - def setup_method(self): - G = nx.Graph() - G.add_edge(0, 1, weight=0.6, cost=0.6, high_cost=6) - G.add_edge(0, 2, weight=0.2, cost=0.2, high_cost=2) - G.add_edge(2, 3, weight=0.1, cost=0.1, high_cost=1) - G.add_edge(2, 4, weight=0.7, cost=0.7, high_cost=7) - G.add_edge(2, 5, weight=0.9, cost=0.9, high_cost=9) - G.add_edge(1, 5, weight=0.3, cost=0.3, high_cost=3) - self.G = G - self.weight_fn = lambda v, u, e: 2 - - def test_eccentricity_weight_None(self): - assert nx.eccentricity(self.G, 1, weight=None) == 3 - e = nx.eccentricity(self.G, weight=None) - assert e[1] == 3 - - e = nx.eccentricity(self.G, v=1, weight=None) - assert e == 3 - - # This behavior changed in version 1.8 (ticket #739) - e = nx.eccentricity(self.G, v=[1, 1], weight=None) - assert e[1] == 3 - e = nx.eccentricity(self.G, v=[1, 2], weight=None) - assert e[1] == 3 - - def test_eccentricity_weight_attr(self): - assert nx.eccentricity(self.G, 1, weight="weight") == 1.5 - e = nx.eccentricity(self.G, weight="weight") - assert ( - e - == nx.eccentricity(self.G, weight="cost") - != nx.eccentricity(self.G, weight="high_cost") - ) - assert e[1] == 1.5 - - e = nx.eccentricity(self.G, v=1, weight="weight") - assert e == 1.5 - - # This behavior changed in version 1.8 (ticket #739) - e = nx.eccentricity(self.G, v=[1, 1], weight="weight") - assert e[1] == 1.5 - e = nx.eccentricity(self.G, v=[1, 2], weight="weight") - assert e[1] == 1.5 - - def test_eccentricity_weight_fn(self): - assert nx.eccentricity(self.G, 1, weight=self.weight_fn) == 6 - e = nx.eccentricity(self.G, weight=self.weight_fn) - assert e[1] == 6 - - e = nx.eccentricity(self.G, v=1, weight=self.weight_fn) - assert e == 6 - - # This behavior changed in version 1.8 (ticket #739) - e = nx.eccentricity(self.G, v=[1, 1], weight=self.weight_fn) - assert e[1] == 6 - e = nx.eccentricity(self.G, v=[1, 2], weight=self.weight_fn) - assert e[1] == 6 - - def test_diameter_weight_None(self): - assert nx.diameter(self.G, weight=None) == 3 - - def test_diameter_weight_attr(self): - assert ( - nx.diameter(self.G, weight="weight") - == nx.diameter(self.G, weight="cost") - == 1.6 - != nx.diameter(self.G, weight="high_cost") - ) - - def test_diameter_weight_fn(self): - assert nx.diameter(self.G, weight=self.weight_fn) == 6 - - def test_radius_weight_None(self): - assert pytest.approx(nx.radius(self.G, weight=None)) == 2 - - def test_radius_weight_attr(self): - assert ( - pytest.approx(nx.radius(self.G, weight="weight")) - == pytest.approx(nx.radius(self.G, weight="cost")) - == 0.9 - != nx.radius(self.G, weight="high_cost") - ) - - def test_radius_weight_fn(self): - assert nx.radius(self.G, weight=self.weight_fn) == 4 - - def test_periphery_weight_None(self): - for v in set(nx.periphery(self.G, weight=None)): - assert nx.eccentricity(self.G, v, weight=None) == nx.diameter( - self.G, weight=None - ) - - def test_periphery_weight_attr(self): - periphery = set(nx.periphery(self.G, weight="weight")) - assert ( - periphery - == set(nx.periphery(self.G, weight="cost")) - == set(nx.periphery(self.G, weight="high_cost")) - ) - for v in periphery: - assert ( - nx.eccentricity(self.G, v, weight="high_cost") - != nx.eccentricity(self.G, v, weight="weight") - == nx.eccentricity(self.G, v, weight="cost") - == nx.diameter(self.G, weight="weight") - == nx.diameter(self.G, weight="cost") - != nx.diameter(self.G, weight="high_cost") - ) - assert nx.eccentricity(self.G, v, weight="high_cost") == nx.diameter( - self.G, weight="high_cost" - ) - - def test_periphery_weight_fn(self): - for v in set(nx.periphery(self.G, weight=self.weight_fn)): - assert nx.eccentricity(self.G, v, weight=self.weight_fn) == nx.diameter( - self.G, weight=self.weight_fn - ) - - def test_center_weight_None(self): - for v in set(nx.center(self.G, weight=None)): - assert pytest.approx(nx.eccentricity(self.G, v, weight=None)) == nx.radius( - self.G, weight=None - ) - - def test_center_weight_attr(self): - center = set(nx.center(self.G, weight="weight")) - assert ( - center - == set(nx.center(self.G, weight="cost")) - != set(nx.center(self.G, weight="high_cost")) - ) - for v in center: - assert ( - nx.eccentricity(self.G, v, weight="high_cost") - != pytest.approx(nx.eccentricity(self.G, v, weight="weight")) - == pytest.approx(nx.eccentricity(self.G, v, weight="cost")) - == nx.radius(self.G, weight="weight") - == nx.radius(self.G, weight="cost") - != nx.radius(self.G, weight="high_cost") - ) - assert nx.eccentricity(self.G, v, weight="high_cost") == nx.radius( - self.G, weight="high_cost" - ) - - def test_center_weight_fn(self): - for v in set(nx.center(self.G, weight=self.weight_fn)): - assert nx.eccentricity(self.G, v, weight=self.weight_fn) == nx.radius( - self.G, weight=self.weight_fn - ) - - def test_bound_diameter_weight_None(self): - assert nx.diameter(self.G, usebounds=True, weight=None) == 3 - - def test_bound_diameter_weight_attr(self): - assert ( - nx.diameter(self.G, usebounds=True, weight="high_cost") - != nx.diameter(self.G, usebounds=True, weight="weight") - == nx.diameter(self.G, usebounds=True, weight="cost") - == 1.6 - != nx.diameter(self.G, usebounds=True, weight="high_cost") - ) - assert nx.diameter(self.G, usebounds=True, weight="high_cost") == nx.diameter( - self.G, usebounds=True, weight="high_cost" - ) - - def test_bound_diameter_weight_fn(self): - assert nx.diameter(self.G, usebounds=True, weight=self.weight_fn) == 6 - - def test_bound_radius_weight_None(self): - assert pytest.approx(nx.radius(self.G, usebounds=True, weight=None)) == 2 - - def test_bound_radius_weight_attr(self): - assert ( - nx.radius(self.G, usebounds=True, weight="high_cost") - != pytest.approx(nx.radius(self.G, usebounds=True, weight="weight")) - == pytest.approx(nx.radius(self.G, usebounds=True, weight="cost")) - == 0.9 - != nx.radius(self.G, usebounds=True, weight="high_cost") - ) - assert nx.radius(self.G, usebounds=True, weight="high_cost") == nx.radius( - self.G, usebounds=True, weight="high_cost" - ) - - def test_bound_radius_weight_fn(self): - assert nx.radius(self.G, usebounds=True, weight=self.weight_fn) == 4 - - def test_bound_periphery_weight_None(self): - result = {1, 3, 4} - assert set(nx.periphery(self.G, usebounds=True, weight=None)) == result - - def test_bound_periphery_weight_attr(self): - result = {4, 5} - assert ( - set(nx.periphery(self.G, usebounds=True, weight="weight")) - == set(nx.periphery(self.G, usebounds=True, weight="cost")) - == result - ) - - def test_bound_periphery_weight_fn(self): - result = {1, 3, 4} - assert ( - set(nx.periphery(self.G, usebounds=True, weight=self.weight_fn)) == result - ) - - def test_bound_center_weight_None(self): - result = {0, 2, 5} - assert set(nx.center(self.G, usebounds=True, weight=None)) == result - - def test_bound_center_weight_attr(self): - result = {0} - assert ( - set(nx.center(self.G, usebounds=True, weight="weight")) - == set(nx.center(self.G, usebounds=True, weight="cost")) - == result - ) - - def test_bound_center_weight_fn(self): - result = {0, 2, 5} - assert set(nx.center(self.G, usebounds=True, weight=self.weight_fn)) == result - - -class TestResistanceDistance: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") - - def setup_method(self): - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(2, 3, weight=4) - G.add_edge(3, 4, weight=1) - G.add_edge(1, 4, weight=3) - self.G = G - - def test_resistance_distance_directed_graph(self): - G = nx.DiGraph() - with pytest.raises(nx.NetworkXNotImplemented): - nx.resistance_distance(G) - - def test_resistance_distance_empty(self): - G = nx.Graph() - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(G) - - def test_resistance_distance_not_connected(self): - with pytest.raises(nx.NetworkXError): - self.G.add_node(5) - nx.resistance_distance(self.G, 1, 5) - - def test_resistance_distance_nodeA_not_in_graph(self): - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(self.G, 9, 1) - - def test_resistance_distance_nodeB_not_in_graph(self): - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(self.G, 1, 9) - - def test_resistance_distance(self): - rd = nx.resistance_distance(self.G, 1, 3, "weight", True) - test_data = 1 / (1 / (2 + 4) + 1 / (1 + 3)) - assert round(rd, 5) == round(test_data, 5) - - def test_resistance_distance_noinv(self): - rd = nx.resistance_distance(self.G, 1, 3, "weight", False) - test_data = 1 / (1 / (1 / 2 + 1 / 4) + 1 / (1 / 1 + 1 / 3)) - assert round(rd, 5) == round(test_data, 5) - - def test_resistance_distance_no_weight(self): - rd = nx.resistance_distance(self.G, 1, 3) - assert round(rd, 5) == 1 - - def test_resistance_distance_neg_weight(self): - self.G[2][3]["weight"] = -4 - rd = nx.resistance_distance(self.G, 1, 3, "weight", True) - test_data = 1 / (1 / (2 + -4) + 1 / (1 + 3)) - assert round(rd, 5) == round(test_data, 5) - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=2) - G.add_edge(2, 3, weight=4) - G.add_edge(3, 4, weight=1) - G.add_edge(1, 4, weight=3) - rd = nx.resistance_distance(G, 1, 3, "weight", True) - assert np.isclose(rd, 1 / (1 / (2 + 4) + 1 / (1 + 3))) - - def test_resistance_distance_div0(self): - with pytest.raises(ZeroDivisionError): - self.G[1][2]["weight"] = 0 - nx.resistance_distance(self.G, 1, 3, "weight") - - def test_resistance_distance_same_node(self): - assert nx.resistance_distance(self.G, 1, 1) == 0 - - def test_resistance_distance_only_nodeA(self): - rd = nx.resistance_distance(self.G, nodeA=1) - test_data = {} - test_data[1] = 0 - test_data[2] = 0.75 - test_data[3] = 1 - test_data[4] = 0.75 - assert type(rd) == dict - assert sorted(rd.keys()) == sorted(test_data.keys()) - for key in rd: - assert np.isclose(rd[key], test_data[key]) - - def test_resistance_distance_only_nodeB(self): - rd = nx.resistance_distance(self.G, nodeB=1) - test_data = {} - test_data[1] = 0 - test_data[2] = 0.75 - test_data[3] = 1 - test_data[4] = 0.75 - assert type(rd) == dict - assert sorted(rd.keys()) == sorted(test_data.keys()) - for key in rd: - assert np.isclose(rd[key], test_data[key]) - - def test_resistance_distance_all(self): - rd = nx.resistance_distance(self.G) - assert type(rd) == dict - assert round(rd[1][3], 5) == 1 - - -class TestEffectiveGraphResistance: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") - - def setup_method(self): - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 3, weight=1) - G.add_edge(2, 3, weight=4) - self.G = G - - def test_effective_graph_resistance_directed_graph(self): - G = nx.DiGraph() - with pytest.raises(nx.NetworkXNotImplemented): - nx.effective_graph_resistance(G) - - def test_effective_graph_resistance_empty(self): - G = nx.Graph() - with pytest.raises(nx.NetworkXError): - nx.effective_graph_resistance(G) - - def test_effective_graph_resistance_not_connected(self): - G = nx.Graph([(1, 2), (3, 4)]) - RG = nx.effective_graph_resistance(G) - assert np.isinf(RG) - - def test_effective_graph_resistance(self): - RG = nx.effective_graph_resistance(self.G, "weight", True) - rd12 = 1 / (1 / (1 + 4) + 1 / 2) - rd13 = 1 / (1 / (1 + 2) + 1 / 4) - rd23 = 1 / (1 / (2 + 4) + 1 / 1) - assert np.isclose(RG, rd12 + rd13 + rd23) - - def test_effective_graph_resistance_noinv(self): - RG = nx.effective_graph_resistance(self.G, "weight", False) - rd12 = 1 / (1 / (1 / 1 + 1 / 4) + 1 / (1 / 2)) - rd13 = 1 / (1 / (1 / 1 + 1 / 2) + 1 / (1 / 4)) - rd23 = 1 / (1 / (1 / 2 + 1 / 4) + 1 / (1 / 1)) - assert np.isclose(RG, rd12 + rd13 + rd23) - - def test_effective_graph_resistance_no_weight(self): - RG = nx.effective_graph_resistance(self.G) - assert np.isclose(RG, 2) - - def test_effective_graph_resistance_neg_weight(self): - self.G[2][3]["weight"] = -4 - RG = nx.effective_graph_resistance(self.G, "weight", True) - rd12 = 1 / (1 / (1 + -4) + 1 / 2) - rd13 = 1 / (1 / (1 + 2) + 1 / (-4)) - rd23 = 1 / (1 / (2 + -4) + 1 / 1) - assert np.isclose(RG, rd12 + rd13 + rd23) - - def test_effective_graph_resistance_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 3, weight=1) - G.add_edge(2, 3, weight=1) - G.add_edge(2, 3, weight=3) - RG = nx.effective_graph_resistance(G, "weight", True) - edge23 = 1 / (1 / 1 + 1 / 3) - rd12 = 1 / (1 / (1 + edge23) + 1 / 2) - rd13 = 1 / (1 / (1 + 2) + 1 / edge23) - rd23 = 1 / (1 / (2 + edge23) + 1 / 1) - assert np.isclose(RG, rd12 + rd13 + rd23) - - def test_effective_graph_resistance_div0(self): - with pytest.raises(ZeroDivisionError): - self.G[1][2]["weight"] = 0 - nx.effective_graph_resistance(self.G, "weight") - - def test_effective_graph_resistance_complete_graph(self): - N = 10 - G = nx.complete_graph(N) - RG = nx.effective_graph_resistance(G) - assert np.isclose(RG, N - 1) - - def test_effective_graph_resistance_path_graph(self): - N = 10 - G = nx.path_graph(N) - RG = nx.effective_graph_resistance(G) - assert np.isclose(RG, (N - 1) * N * (N + 1) // 6) - - -class TestBarycenter: - """Test :func:`networkx.algorithms.distance_measures.barycenter`.""" - - def barycenter_as_subgraph(self, g, **kwargs): - """Return the subgraph induced on the barycenter of g""" - b = nx.barycenter(g, **kwargs) - assert isinstance(b, list) - assert set(b) <= set(g) - return g.subgraph(b) - - def test_must_be_connected(self): - pytest.raises(nx.NetworkXNoPath, nx.barycenter, nx.empty_graph(5)) - - def test_sp_kwarg(self): - # Complete graph K_5. Normally it works... - K_5 = nx.complete_graph(5) - sp = dict(nx.shortest_path_length(K_5)) - assert nx.barycenter(K_5, sp=sp) == list(K_5) - - # ...but not with the weight argument - for u, v, data in K_5.edges.data(): - data["weight"] = 1 - pytest.raises(ValueError, nx.barycenter, K_5, sp=sp, weight="weight") - - # ...and a corrupted sp can make it seem like K_5 is disconnected - del sp[0][1] - pytest.raises(nx.NetworkXNoPath, nx.barycenter, K_5, sp=sp) - - def test_trees(self): - """The barycenter of a tree is a single vertex or an edge. - - See [West01]_, p. 78. - """ - prng = Random(0xDEADBEEF) - for i in range(50): - RT = nx.random_labeled_tree(prng.randint(1, 75), seed=prng) - b = self.barycenter_as_subgraph(RT) - if len(b) == 2: - assert b.size() == 1 - else: - assert len(b) == 1 - assert b.size() == 0 - - def test_this_one_specific_tree(self): - """Test the tree pictured at the bottom of [West01]_, p. 78.""" - g = nx.Graph( - { - "a": ["b"], - "b": ["a", "x"], - "x": ["b", "y"], - "y": ["x", "z"], - "z": ["y", 0, 1, 2, 3, 4], - 0: ["z"], - 1: ["z"], - 2: ["z"], - 3: ["z"], - 4: ["z"], - } - ) - b = self.barycenter_as_subgraph(g, attr="barycentricity") - assert list(b) == ["z"] - assert not b.edges - expected_barycentricity = { - 0: 23, - 1: 23, - 2: 23, - 3: 23, - 4: 23, - "a": 35, - "b": 27, - "x": 21, - "y": 17, - "z": 15, - } - for node, barycentricity in expected_barycentricity.items(): - assert g.nodes[node]["barycentricity"] == barycentricity - - # Doubling weights should do nothing but double the barycentricities - for edge in g.edges: - g.edges[edge]["weight"] = 2 - b = self.barycenter_as_subgraph(g, weight="weight", attr="barycentricity2") - assert list(b) == ["z"] - assert not b.edges - for node, barycentricity in expected_barycentricity.items(): - assert g.nodes[node]["barycentricity2"] == barycentricity * 2 - - -class TestKemenyConstant: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") - - def setup_method(self): - G = nx.Graph() - w12 = 2 - w13 = 3 - w23 = 4 - G.add_edge(1, 2, weight=w12) - G.add_edge(1, 3, weight=w13) - G.add_edge(2, 3, weight=w23) - self.G = G - - def test_kemeny_constant_directed(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(2, 3) - with pytest.raises(nx.NetworkXNotImplemented): - nx.kemeny_constant(G) - - def test_kemeny_constant_not_connected(self): - self.G.add_node(5) - with pytest.raises(nx.NetworkXError): - nx.kemeny_constant(self.G) - - def test_kemeny_constant_no_nodes(self): - G = nx.Graph() - with pytest.raises(nx.NetworkXError): - nx.kemeny_constant(G) - - def test_kemeny_constant_negative_weight(self): - G = nx.Graph() - w12 = 2 - w13 = 3 - w23 = -10 - G.add_edge(1, 2, weight=w12) - G.add_edge(1, 3, weight=w13) - G.add_edge(2, 3, weight=w23) - with pytest.raises(nx.NetworkXError): - nx.kemeny_constant(G, weight="weight") - - def test_kemeny_constant(self): - K = nx.kemeny_constant(self.G, weight="weight") - w12 = 2 - w13 = 3 - w23 = 4 - test_data = ( - 3 - / 2 - * (w12 + w13) - * (w12 + w23) - * (w13 + w23) - / ( - w12**2 * (w13 + w23) - + w13**2 * (w12 + w23) - + w23**2 * (w12 + w13) - + 3 * w12 * w13 * w23 - ) - ) - assert np.isclose(K, test_data) - - def test_kemeny_constant_no_weight(self): - K = nx.kemeny_constant(self.G) - assert np.isclose(K, 4 / 3) - - def test_kemeny_constant_multigraph(self): - G = nx.MultiGraph() - w12_1 = 2 - w12_2 = 1 - w13 = 3 - w23 = 4 - G.add_edge(1, 2, weight=w12_1) - G.add_edge(1, 2, weight=w12_2) - G.add_edge(1, 3, weight=w13) - G.add_edge(2, 3, weight=w23) - K = nx.kemeny_constant(G, weight="weight") - w12 = w12_1 + w12_2 - test_data = ( - 3 - / 2 - * (w12 + w13) - * (w12 + w23) - * (w13 + w23) - / ( - w12**2 * (w13 + w23) - + w13**2 * (w12 + w23) - + w23**2 * (w12 + w13) - + 3 * w12 * w13 * w23 - ) - ) - assert np.isclose(K, test_data) - - def test_kemeny_constant_weight0(self): - G = nx.Graph() - w12 = 0 - w13 = 3 - w23 = 4 - G.add_edge(1, 2, weight=w12) - G.add_edge(1, 3, weight=w13) - G.add_edge(2, 3, weight=w23) - K = nx.kemeny_constant(G, weight="weight") - test_data = ( - 3 - / 2 - * (w12 + w13) - * (w12 + w23) - * (w13 + w23) - / ( - w12**2 * (w13 + w23) - + w13**2 * (w12 + w23) - + w23**2 * (w12 + w13) - + 3 * w12 * w13 * w23 - ) - ) - assert np.isclose(K, test_data) - - def test_kemeny_constant_selfloop(self): - G = nx.Graph() - w11 = 1 - w12 = 2 - w13 = 3 - w23 = 4 - G.add_edge(1, 1, weight=w11) - G.add_edge(1, 2, weight=w12) - G.add_edge(1, 3, weight=w13) - G.add_edge(2, 3, weight=w23) - K = nx.kemeny_constant(G, weight="weight") - test_data = ( - (2 * w11 + 3 * w12 + 3 * w13) - * (w12 + w23) - * (w13 + w23) - / ( - (w12 * w13 + w12 * w23 + w13 * w23) - * (w11 + 2 * w12 + 2 * w13 + 2 * w23) - ) - ) - assert np.isclose(K, test_data) - - def test_kemeny_constant_complete_bipartite_graph(self): - # Theorem 1 in https://www.sciencedirect.com/science/article/pii/S0166218X20302912 - n1 = 5 - n2 = 4 - G = nx.complete_bipartite_graph(n1, n2) - K = nx.kemeny_constant(G) - assert np.isclose(K, n1 + n2 - 3 / 2) - - def test_kemeny_constant_path_graph(self): - # Theorem 2 in https://www.sciencedirect.com/science/article/pii/S0166218X20302912 - n = 10 - G = nx.path_graph(n) - K = nx.kemeny_constant(G) - assert np.isclose(K, n**2 / 3 - 2 * n / 3 + 1 / 2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_regular.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_regular.py deleted file mode 100644 index 545fb6d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_distance_regular.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest - -import networkx as nx -from networkx import is_strongly_regular - - -@pytest.mark.parametrize( - "f", (nx.is_distance_regular, nx.intersection_array, nx.is_strongly_regular) -) -@pytest.mark.parametrize("graph_constructor", (nx.DiGraph, nx.MultiGraph)) -def test_raises_on_directed_and_multigraphs(f, graph_constructor): - G = graph_constructor([(0, 1), (1, 2)]) - with pytest.raises(nx.NetworkXNotImplemented): - f(G) - - -class TestDistanceRegular: - def test_is_distance_regular(self): - assert nx.is_distance_regular(nx.icosahedral_graph()) - assert nx.is_distance_regular(nx.petersen_graph()) - assert nx.is_distance_regular(nx.cubical_graph()) - assert nx.is_distance_regular(nx.complete_bipartite_graph(3, 3)) - assert nx.is_distance_regular(nx.tetrahedral_graph()) - assert nx.is_distance_regular(nx.dodecahedral_graph()) - assert nx.is_distance_regular(nx.pappus_graph()) - assert nx.is_distance_regular(nx.heawood_graph()) - assert nx.is_distance_regular(nx.cycle_graph(3)) - # no distance regular - assert not nx.is_distance_regular(nx.path_graph(4)) - - def test_not_connected(self): - G = nx.cycle_graph(4) - nx.add_cycle(G, [5, 6, 7]) - assert not nx.is_distance_regular(G) - - def test_global_parameters(self): - b, c = nx.intersection_array(nx.cycle_graph(5)) - g = nx.global_parameters(b, c) - assert list(g) == [(0, 0, 2), (1, 0, 1), (1, 1, 0)] - b, c = nx.intersection_array(nx.cycle_graph(3)) - g = nx.global_parameters(b, c) - assert list(g) == [(0, 0, 2), (1, 1, 0)] - - def test_intersection_array(self): - b, c = nx.intersection_array(nx.cycle_graph(5)) - assert b == [2, 1] - assert c == [1, 1] - b, c = nx.intersection_array(nx.dodecahedral_graph()) - assert b == [3, 2, 1, 1, 1] - assert c == [1, 1, 1, 2, 3] - b, c = nx.intersection_array(nx.icosahedral_graph()) - assert b == [5, 2, 1] - assert c == [1, 2, 5] - - -@pytest.mark.parametrize("f", (nx.is_distance_regular, nx.is_strongly_regular)) -def test_empty_graph_raises(f): - G = nx.Graph() - with pytest.raises(nx.NetworkXPointlessConcept, match="Graph has no nodes"): - f(G) - - -class TestStronglyRegular: - """Unit tests for the :func:`~networkx.is_strongly_regular` - function. - - """ - - def test_cycle_graph(self): - """Tests that the cycle graph on five vertices is strongly - regular. - - """ - G = nx.cycle_graph(5) - assert is_strongly_regular(G) - - def test_petersen_graph(self): - """Tests that the Petersen graph is strongly regular.""" - G = nx.petersen_graph() - assert is_strongly_regular(G) - - def test_path_graph(self): - """Tests that the path graph is not strongly regular.""" - G = nx.path_graph(4) - assert not is_strongly_regular(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominance.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominance.py deleted file mode 100644 index 9b804c2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominance.py +++ /dev/null @@ -1,286 +0,0 @@ -import pytest - -import networkx as nx - - -class TestImmediateDominators: - def test_exceptions(self): - G = nx.Graph() - G.add_node(0) - pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0) - G = nx.MultiGraph(G) - pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0) - G = nx.DiGraph([[0, 0]]) - pytest.raises(nx.NetworkXError, nx.immediate_dominators, G, 1) - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.immediate_dominators(G, 0) == {0: 0} - G.add_edge(0, 0) - assert nx.immediate_dominators(G, 0) == {0: 0} - - def test_path(self): - n = 5 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert nx.immediate_dominators(G, 0) == {i: max(i - 1, 0) for i in range(n)} - - def test_cycle(self): - n = 5 - G = nx.cycle_graph(n, create_using=nx.DiGraph()) - assert nx.immediate_dominators(G, 0) == {i: max(i - 1, 0) for i in range(n)} - - def test_unreachable(self): - n = 5 - assert n > 1 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert nx.immediate_dominators(G, n // 2) == { - i: max(i - 1, n // 2) for i in range(n // 2, n) - } - - def test_irreducible1(self): - """ - Graph taken from figure 2 of "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] - G = nx.DiGraph(edges) - assert nx.immediate_dominators(G, 5) == {i: 5 for i in range(1, 6)} - - def test_irreducible2(self): - """ - Graph taken from figure 4 of "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - - edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)] - G = nx.DiGraph(edges) - result = nx.immediate_dominators(G, 6) - assert result == {i: 6 for i in range(1, 7)} - - def test_domrel_png(self): - # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png - edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] - G = nx.DiGraph(edges) - result = nx.immediate_dominators(G, 1) - assert result == {1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 2} - # Test postdominance. - result = nx.immediate_dominators(G.reverse(copy=False), 6) - assert result == {1: 2, 2: 6, 3: 5, 4: 5, 5: 2, 6: 6} - - def test_boost_example(self): - # Graph taken from Figure 1 of - # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm - edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] - G = nx.DiGraph(edges) - result = nx.immediate_dominators(G, 0) - assert result == {0: 0, 1: 0, 2: 1, 3: 1, 4: 3, 5: 4, 6: 4, 7: 1} - # Test postdominance. - result = nx.immediate_dominators(G.reverse(copy=False), 7) - assert result == {0: 1, 1: 7, 2: 7, 3: 4, 4: 5, 5: 7, 6: 4, 7: 7} - - -class TestDominanceFrontiers: - def test_exceptions(self): - G = nx.Graph() - G.add_node(0) - pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0) - G = nx.MultiGraph(G) - pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0) - G = nx.DiGraph([[0, 0]]) - pytest.raises(nx.NetworkXError, nx.dominance_frontiers, G, 1) - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.dominance_frontiers(G, 0) == {0: set()} - G.add_edge(0, 0) - assert nx.dominance_frontiers(G, 0) == {0: set()} - - def test_path(self): - n = 5 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert nx.dominance_frontiers(G, 0) == {i: set() for i in range(n)} - - def test_cycle(self): - n = 5 - G = nx.cycle_graph(n, create_using=nx.DiGraph()) - assert nx.dominance_frontiers(G, 0) == {i: set() for i in range(n)} - - def test_unreachable(self): - n = 5 - assert n > 1 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert nx.dominance_frontiers(G, n // 2) == {i: set() for i in range(n // 2, n)} - - def test_irreducible1(self): - """ - Graph taken from figure 2 of "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] - G = nx.DiGraph(edges) - assert dict(nx.dominance_frontiers(G, 5).items()) == { - 1: {2}, - 2: {1}, - 3: {2}, - 4: {1}, - 5: set(), - } - - def test_irreducible2(self): - """ - Graph taken from figure 4 of "A simple, fast dominance algorithm." (2006). - https://hdl.handle.net/1911/96345 - """ - edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)] - G = nx.DiGraph(edges) - assert nx.dominance_frontiers(G, 6) == { - 1: {2}, - 2: {1, 3}, - 3: {2}, - 4: {2, 3}, - 5: {1}, - 6: set(), - } - - def test_domrel_png(self): - # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png - edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] - G = nx.DiGraph(edges) - assert nx.dominance_frontiers(G, 1) == { - 1: set(), - 2: {2}, - 3: {5}, - 4: {5}, - 5: {2}, - 6: set(), - } - # Test postdominance. - result = nx.dominance_frontiers(G.reverse(copy=False), 6) - assert result == {1: set(), 2: {2}, 3: {2}, 4: {2}, 5: {2}, 6: set()} - - def test_boost_example(self): - # Graph taken from Figure 1 of - # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm - edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] - G = nx.DiGraph(edges) - assert nx.dominance_frontiers(G, 0) == { - 0: set(), - 1: set(), - 2: {7}, - 3: {7}, - 4: {4, 7}, - 5: {7}, - 6: {4}, - 7: set(), - } - # Test postdominance. - result = nx.dominance_frontiers(G.reverse(copy=False), 7) - expected = { - 0: set(), - 1: set(), - 2: {1}, - 3: {1}, - 4: {1, 4}, - 5: {1}, - 6: {4}, - 7: set(), - } - assert result == expected - - def test_discard_issue(self): - # https://github.com/networkx/networkx/issues/2071 - g = nx.DiGraph() - g.add_edges_from( - [ - ("b0", "b1"), - ("b1", "b2"), - ("b2", "b3"), - ("b3", "b1"), - ("b1", "b5"), - ("b5", "b6"), - ("b5", "b8"), - ("b6", "b7"), - ("b8", "b7"), - ("b7", "b3"), - ("b3", "b4"), - ] - ) - df = nx.dominance_frontiers(g, "b0") - assert df == { - "b4": set(), - "b5": {"b3"}, - "b6": {"b7"}, - "b7": {"b3"}, - "b0": set(), - "b1": {"b1"}, - "b2": {"b3"}, - "b3": {"b1"}, - "b8": {"b7"}, - } - - def test_loop(self): - g = nx.DiGraph() - g.add_edges_from([("a", "b"), ("b", "c"), ("b", "a")]) - df = nx.dominance_frontiers(g, "a") - assert df == {"a": set(), "b": set(), "c": set()} - - def test_missing_immediate_doms(self): - # see https://github.com/networkx/networkx/issues/2070 - g = nx.DiGraph() - edges = [ - ("entry_1", "b1"), - ("b1", "b2"), - ("b2", "b3"), - ("b3", "exit"), - ("entry_2", "b3"), - ] - - # entry_1 - # | - # b1 - # | - # b2 entry_2 - # | / - # b3 - # | - # exit - - g.add_edges_from(edges) - # formerly raised KeyError on entry_2 when parsing b3 - # because entry_2 does not have immediate doms (no path) - nx.dominance_frontiers(g, "entry_1") - - def test_loops_larger(self): - # from - # http://ecee.colorado.edu/~waite/Darmstadt/motion.html - g = nx.DiGraph() - edges = [ - ("entry", "exit"), - ("entry", "1"), - ("1", "2"), - ("2", "3"), - ("3", "4"), - ("4", "5"), - ("5", "6"), - ("6", "exit"), - ("6", "2"), - ("5", "3"), - ("4", "4"), - ] - - g.add_edges_from(edges) - df = nx.dominance_frontiers(g, "entry") - answer = { - "entry": set(), - "1": {"exit"}, - "2": {"exit", "2"}, - "3": {"exit", "3", "2"}, - "4": {"exit", "4", "3", "2"}, - "5": {"exit", "3", "2"}, - "6": {"exit", "2"}, - "exit": set(), - } - for n in df: - assert set(df[n]) == set(answer[n]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominating.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominating.py deleted file mode 100644 index b945c73..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_dominating.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest - -import networkx as nx - - -def test_dominating_set(): - G = nx.gnp_random_graph(100, 0.1) - D = nx.dominating_set(G) - assert nx.is_dominating_set(G, D) - D = nx.dominating_set(G, start_with=0) - assert nx.is_dominating_set(G, D) - - -def test_complete(): - """In complete graphs each node is a dominating set. - Thus the dominating set has to be of cardinality 1. - """ - K4 = nx.complete_graph(4) - assert len(nx.dominating_set(K4)) == 1 - K5 = nx.complete_graph(5) - assert len(nx.dominating_set(K5)) == 1 - - -def test_raise_dominating_set(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - D = nx.dominating_set(G, start_with=10) - - -def test_is_dominating_set(): - G = nx.path_graph(4) - d = {1, 3} - assert nx.is_dominating_set(G, d) - d = {0, 2} - assert nx.is_dominating_set(G, d) - d = {1} - assert not nx.is_dominating_set(G, d) - - -def test_wikipedia_is_dominating_set(): - """Example from https://en.wikipedia.org/wiki/Dominating_set""" - G = nx.cycle_graph(4) - G.add_edges_from([(0, 4), (1, 4), (2, 5)]) - assert nx.is_dominating_set(G, {4, 3, 5}) - assert nx.is_dominating_set(G, {0, 2}) - assert nx.is_dominating_set(G, {1, 2}) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_efficiency.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_efficiency.py deleted file mode 100644 index 9a2e7d0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_efficiency.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.efficiency` module.""" - -import networkx as nx - - -class TestEfficiency: - def setup_method(self): - # G1 is a disconnected graph - self.G1 = nx.Graph() - self.G1.add_nodes_from([1, 2, 3]) - # G2 is a cycle graph - self.G2 = nx.cycle_graph(4) - # G3 is the triangle graph with one additional edge - self.G3 = nx.lollipop_graph(3, 1) - - def test_efficiency_disconnected_nodes(self): - """ - When nodes are disconnected, efficiency is 0 - """ - assert nx.efficiency(self.G1, 1, 2) == 0 - - def test_local_efficiency_disconnected_graph(self): - """ - In a disconnected graph the efficiency is 0 - """ - assert nx.local_efficiency(self.G1) == 0 - - def test_efficiency(self): - assert nx.efficiency(self.G2, 0, 1) == 1 - assert nx.efficiency(self.G2, 0, 2) == 1 / 2 - - def test_global_efficiency(self): - assert nx.global_efficiency(self.G2) == 5 / 6 - - def test_global_efficiency_complete_graph(self): - """ - Tests that the average global efficiency of the complete graph is one. - """ - for n in range(2, 10): - G = nx.complete_graph(n) - assert nx.global_efficiency(G) == 1 - - def test_local_efficiency_complete_graph(self): - """ - Test that the local efficiency for a complete graph with at least 3 - nodes should be one. For a graph with only 2 nodes, the induced - subgraph has no edges. - """ - for n in range(3, 10): - G = nx.complete_graph(n) - assert nx.local_efficiency(G) == 1 - - def test_using_ego_graph(self): - """ - Test that the ego graph is used when computing local efficiency. - For more information, see GitHub issue #2710. - """ - assert nx.local_efficiency(self.G3) == 7 / 12 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_euler.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_euler.py deleted file mode 100644 index b5871f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_euler.py +++ /dev/null @@ -1,314 +0,0 @@ -import collections - -import pytest - -import networkx as nx - - -@pytest.mark.parametrize("f", (nx.is_eulerian, nx.is_semieulerian)) -def test_empty_graph_raises(f): - G = nx.Graph() - with pytest.raises(nx.NetworkXPointlessConcept, match="Connectivity is undefined"): - f(G) - - -class TestIsEulerian: - def test_is_eulerian(self): - assert nx.is_eulerian(nx.complete_graph(5)) - assert nx.is_eulerian(nx.complete_graph(7)) - assert nx.is_eulerian(nx.hypercube_graph(4)) - assert nx.is_eulerian(nx.hypercube_graph(6)) - - assert not nx.is_eulerian(nx.complete_graph(4)) - assert not nx.is_eulerian(nx.complete_graph(6)) - assert not nx.is_eulerian(nx.hypercube_graph(3)) - assert not nx.is_eulerian(nx.hypercube_graph(5)) - - assert not nx.is_eulerian(nx.petersen_graph()) - assert not nx.is_eulerian(nx.path_graph(4)) - - def test_is_eulerian2(self): - # not connected - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - assert not nx.is_eulerian(G) - # not strongly connected - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3]) - assert not nx.is_eulerian(G) - G = nx.MultiDiGraph() - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(2, 3) - G.add_edge(3, 1) - assert not nx.is_eulerian(G) - - -class TestEulerianCircuit: - def test_eulerian_circuit_cycle(self): - G = nx.cycle_graph(4) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 3, 2, 1] - assert edges == [(0, 3), (3, 2), (2, 1), (1, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 3, 0] - assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)] - - G = nx.complete_graph(3) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 2, 1] - assert edges == [(0, 2), (2, 1), (1, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 0] - assert edges == [(1, 2), (2, 0), (0, 1)] - - def test_eulerian_circuit_digraph(self): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 1, 2, 3] - assert edges == [(0, 1), (1, 2), (2, 3), (3, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 3, 0] - assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)] - - def test_multigraph(self): - G = nx.MultiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - G.add_edge(1, 2) - G.add_edge(1, 2) - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 3, 2, 1, 2, 1] - assert edges == [(0, 3), (3, 2), (2, 1), (1, 2), (2, 1), (1, 0)] - - def test_multigraph_with_keys(self): - G = nx.MultiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - G.add_edge(1, 2) - G.add_edge(1, 2) - edges = list(nx.eulerian_circuit(G, source=0, keys=True)) - nodes = [u for u, v, k in edges] - assert nodes == [0, 3, 2, 1, 2, 1] - assert edges[:2] == [(0, 3, 0), (3, 2, 0)] - assert collections.Counter(edges[2:5]) == collections.Counter( - [(2, 1, 0), (1, 2, 1), (2, 1, 2)] - ) - assert edges[5:] == [(1, 0, 0)] - - def test_not_eulerian(self): - with pytest.raises(nx.NetworkXError): - f = list(nx.eulerian_circuit(nx.complete_graph(4))) - - -class TestIsSemiEulerian: - def test_is_semieulerian(self): - # Test graphs with Eulerian paths but no cycles return True. - assert nx.is_semieulerian(nx.path_graph(4)) - G = nx.path_graph(6, create_using=nx.DiGraph) - assert nx.is_semieulerian(G) - - # Test graphs with Eulerian cycles return False. - assert not nx.is_semieulerian(nx.complete_graph(5)) - assert not nx.is_semieulerian(nx.complete_graph(7)) - assert not nx.is_semieulerian(nx.hypercube_graph(4)) - assert not nx.is_semieulerian(nx.hypercube_graph(6)) - - -class TestHasEulerianPath: - def test_has_eulerian_path_cyclic(self): - # Test graphs with Eulerian cycles return True. - assert nx.has_eulerian_path(nx.complete_graph(5)) - assert nx.has_eulerian_path(nx.complete_graph(7)) - assert nx.has_eulerian_path(nx.hypercube_graph(4)) - assert nx.has_eulerian_path(nx.hypercube_graph(6)) - - def test_has_eulerian_path_non_cyclic(self): - # Test graphs with Eulerian paths but no cycles return True. - assert nx.has_eulerian_path(nx.path_graph(4)) - G = nx.path_graph(6, create_using=nx.DiGraph) - assert nx.has_eulerian_path(G) - - def test_has_eulerian_path_directed_graph(self): - # Test directed graphs and returns False - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (0, 2)]) - assert not nx.has_eulerian_path(G) - - # Test directed graphs without isolated node returns True - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 0)]) - assert nx.has_eulerian_path(G) - - # Test directed graphs with isolated node returns False - G.add_node(3) - assert not nx.has_eulerian_path(G) - - @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) - def test_has_eulerian_path_not_weakly_connected(self, G): - G.add_edges_from([(0, 1), (2, 3), (3, 2)]) - assert not nx.has_eulerian_path(G) - - @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) - def test_has_eulerian_path_unbalancedins_more_than_one(self, G): - G.add_edges_from([(0, 1), (2, 3)]) - assert not nx.has_eulerian_path(G) - - -class TestFindPathStart: - def testfind_path_start(self): - find_path_start = nx.algorithms.euler._find_path_start - # Test digraphs return correct starting node. - G = nx.path_graph(6, create_using=nx.DiGraph) - assert find_path_start(G) == 0 - edges = [(0, 1), (1, 2), (2, 0), (4, 0)] - assert find_path_start(nx.DiGraph(edges)) == 4 - - # Test graph with no Eulerian path return None. - edges = [(0, 1), (1, 2), (2, 3), (2, 4)] - assert find_path_start(nx.DiGraph(edges)) is None - - -class TestEulerianPath: - def test_eulerian_path(self): - x = [(4, 0), (0, 1), (1, 2), (2, 0)] - for e1, e2 in zip(x, nx.eulerian_path(nx.DiGraph(x))): - assert e1 == e2 - - def test_eulerian_path_straight_link(self): - G = nx.DiGraph() - result = [(1, 2), (2, 3), (3, 4), (4, 5)] - G.add_edges_from(result) - assert result == list(nx.eulerian_path(G)) - assert result == list(nx.eulerian_path(G, source=1)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=3)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=4)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=5)) - - def test_eulerian_path_multigraph(self): - G = nx.MultiDiGraph() - result = [(2, 1), (1, 2), (2, 1), (1, 2), (2, 3), (3, 4), (4, 3)] - G.add_edges_from(result) - assert result == list(nx.eulerian_path(G)) - assert result == list(nx.eulerian_path(G, source=2)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=3)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=4)) - - def test_eulerian_path_eulerian_circuit(self): - G = nx.DiGraph() - result = [(1, 2), (2, 3), (3, 4), (4, 1)] - result2 = [(2, 3), (3, 4), (4, 1), (1, 2)] - result3 = [(3, 4), (4, 1), (1, 2), (2, 3)] - G.add_edges_from(result) - assert result == list(nx.eulerian_path(G)) - assert result == list(nx.eulerian_path(G, source=1)) - assert result2 == list(nx.eulerian_path(G, source=2)) - assert result3 == list(nx.eulerian_path(G, source=3)) - - def test_eulerian_path_undirected(self): - G = nx.Graph() - result = [(1, 2), (2, 3), (3, 4), (4, 5)] - result2 = [(5, 4), (4, 3), (3, 2), (2, 1)] - G.add_edges_from(result) - assert list(nx.eulerian_path(G)) in (result, result2) - assert result == list(nx.eulerian_path(G, source=1)) - assert result2 == list(nx.eulerian_path(G, source=5)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=3)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=2)) - - def test_eulerian_path_multigraph_undirected(self): - G = nx.MultiGraph() - result = [(2, 1), (1, 2), (2, 1), (1, 2), (2, 3), (3, 4)] - G.add_edges_from(result) - assert result == list(nx.eulerian_path(G)) - assert result == list(nx.eulerian_path(G, source=2)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=3)) - with pytest.raises(nx.NetworkXError): - list(nx.eulerian_path(G, source=1)) - - @pytest.mark.parametrize( - ("graph_type", "result"), - ( - (nx.MultiGraph, [(0, 1, 0), (1, 0, 1)]), - (nx.MultiDiGraph, [(0, 1, 0), (1, 0, 0)]), - ), - ) - def test_eulerian_with_keys(self, graph_type, result): - G = graph_type([(0, 1), (1, 0)]) - answer = nx.eulerian_path(G, keys=True) - assert list(answer) == result - - -class TestEulerize: - def test_disconnected(self): - with pytest.raises(nx.NetworkXError): - G = nx.from_edgelist([(0, 1), (2, 3)]) - nx.eulerize(G) - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.eulerize(nx.Graph()) - - def test_null_multigraph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.eulerize(nx.MultiGraph()) - - def test_on_empty_graph(self): - with pytest.raises(nx.NetworkXError): - nx.eulerize(nx.empty_graph(3)) - - def test_on_eulerian(self): - G = nx.cycle_graph(3) - H = nx.eulerize(G) - assert nx.is_isomorphic(G, H) - - def test_on_eulerian_multigraph(self): - G = nx.MultiGraph(nx.cycle_graph(3)) - G.add_edge(0, 1) - H = nx.eulerize(G) - assert nx.is_eulerian(H) - - def test_on_complete_graph(self): - G = nx.complete_graph(4) - assert nx.is_eulerian(nx.eulerize(G)) - assert nx.is_eulerian(nx.eulerize(nx.MultiGraph(G))) - - def test_on_non_eulerian_graph(self): - G = nx.cycle_graph(18) - G.add_edge(0, 18) - G.add_edge(18, 19) - G.add_edge(17, 19) - G.add_edge(4, 20) - G.add_edge(20, 21) - G.add_edge(21, 22) - G.add_edge(22, 23) - G.add_edge(23, 24) - G.add_edge(24, 25) - G.add_edge(25, 26) - G.add_edge(26, 27) - G.add_edge(27, 28) - G.add_edge(28, 13) - assert not nx.is_eulerian(G) - G = nx.eulerize(G) - assert nx.is_eulerian(G) - assert nx.number_of_edges(G) == 39 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graph_hashing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graph_hashing.py deleted file mode 100644 index 0828069..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graph_hashing.py +++ /dev/null @@ -1,686 +0,0 @@ -import pytest - -import networkx as nx -from networkx.generators import directed - -# Unit tests for the :func:`~networkx.weisfeiler_lehman_graph_hash` function - - -def test_empty_graph_hash(): - """ - empty graphs should give hashes regardless of other params - """ - G1 = nx.empty_graph() - G2 = nx.empty_graph() - - h1 = nx.weisfeiler_lehman_graph_hash(G1) - h2 = nx.weisfeiler_lehman_graph_hash(G2) - h3 = nx.weisfeiler_lehman_graph_hash(G2, edge_attr="edge_attr1") - h4 = nx.weisfeiler_lehman_graph_hash(G2, node_attr="node_attr1") - h5 = nx.weisfeiler_lehman_graph_hash( - G2, edge_attr="edge_attr1", node_attr="node_attr1" - ) - h6 = nx.weisfeiler_lehman_graph_hash(G2, iterations=10) - - assert h1 == h2 - assert h1 == h3 - assert h1 == h4 - assert h1 == h5 - assert h1 == h6 - - -def test_directed(): - """ - A directed graph with no bi-directional edges should yield different a graph hash - to the same graph taken as undirected if there are no hash collisions. - """ - r = 10 - for i in range(r): - G_directed = nx.gn_graph(10 + r, seed=100 + i) - G_undirected = nx.to_undirected(G_directed) - - h_directed = nx.weisfeiler_lehman_graph_hash(G_directed) - h_undirected = nx.weisfeiler_lehman_graph_hash(G_undirected) - - assert h_directed != h_undirected - - -def test_reversed(): - """ - A directed graph with no bi-directional edges should yield different a graph hash - to the same graph taken with edge directions reversed if there are no hash collisions. - Here we test a cycle graph which is the minimal counterexample - """ - G = nx.cycle_graph(5, create_using=nx.DiGraph) - nx.set_node_attributes(G, {n: str(n) for n in G.nodes()}, name="label") - - G_reversed = G.reverse() - - h = nx.weisfeiler_lehman_graph_hash(G, node_attr="label") - h_reversed = nx.weisfeiler_lehman_graph_hash(G_reversed, node_attr="label") - - assert h != h_reversed - - -def test_isomorphic(): - """ - graph hashes should be invariant to node-relabeling (when the output is reindexed - by the same mapping) - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=200 + i) - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g1_hash = nx.weisfeiler_lehman_graph_hash(G1) - g2_hash = nx.weisfeiler_lehman_graph_hash(G2) - - assert g1_hash == g2_hash - - -def test_isomorphic_edge_attr(): - """ - Isomorphic graphs with differing edge attributes should yield different graph - hashes if the 'edge_attr' argument is supplied and populated in the graph, - and there are no hash collisions. - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=300 + i) - - for a, b in G1.edges: - G1[a][b]["edge_attr1"] = f"{a}-{b}-1" - G1[a][b]["edge_attr2"] = f"{a}-{b}-2" - - g1_hash_with_edge_attr1 = nx.weisfeiler_lehman_graph_hash( - G1, edge_attr="edge_attr1" - ) - g1_hash_with_edge_attr2 = nx.weisfeiler_lehman_graph_hash( - G1, edge_attr="edge_attr2" - ) - g1_hash_no_edge_attr = nx.weisfeiler_lehman_graph_hash(G1, edge_attr=None) - - assert g1_hash_with_edge_attr1 != g1_hash_no_edge_attr - assert g1_hash_with_edge_attr2 != g1_hash_no_edge_attr - assert g1_hash_with_edge_attr1 != g1_hash_with_edge_attr2 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_with_edge_attr1 = nx.weisfeiler_lehman_graph_hash( - G2, edge_attr="edge_attr1" - ) - g2_hash_with_edge_attr2 = nx.weisfeiler_lehman_graph_hash( - G2, edge_attr="edge_attr2" - ) - - assert g1_hash_with_edge_attr1 == g2_hash_with_edge_attr1 - assert g1_hash_with_edge_attr2 == g2_hash_with_edge_attr2 - - -def test_missing_edge_attr(): - """ - If the 'edge_attr' argument is supplied but is missing from an edge in the graph, - we should raise a KeyError - """ - G = nx.Graph() - G.add_edges_from([(1, 2, {"edge_attr1": "a"}), (1, 3, {})]) - pytest.raises(KeyError, nx.weisfeiler_lehman_graph_hash, G, edge_attr="edge_attr1") - - -def test_isomorphic_node_attr(): - """ - Isomorphic graphs with differing node attributes should yield different graph - hashes if the 'node_attr' argument is supplied and populated in the graph, and - there are no hash collisions. - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=400 + i) - - for u in G1.nodes(): - G1.nodes[u]["node_attr1"] = f"{u}-1" - G1.nodes[u]["node_attr2"] = f"{u}-2" - - g1_hash_with_node_attr1 = nx.weisfeiler_lehman_graph_hash( - G1, node_attr="node_attr1" - ) - g1_hash_with_node_attr2 = nx.weisfeiler_lehman_graph_hash( - G1, node_attr="node_attr2" - ) - g1_hash_no_node_attr = nx.weisfeiler_lehman_graph_hash(G1, node_attr=None) - - assert g1_hash_with_node_attr1 != g1_hash_no_node_attr - assert g1_hash_with_node_attr2 != g1_hash_no_node_attr - assert g1_hash_with_node_attr1 != g1_hash_with_node_attr2 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_with_node_attr1 = nx.weisfeiler_lehman_graph_hash( - G2, node_attr="node_attr1" - ) - g2_hash_with_node_attr2 = nx.weisfeiler_lehman_graph_hash( - G2, node_attr="node_attr2" - ) - - assert g1_hash_with_node_attr1 == g2_hash_with_node_attr1 - assert g1_hash_with_node_attr2 == g2_hash_with_node_attr2 - - -def test_missing_node_attr(): - """ - If the 'node_attr' argument is supplied but is missing from a node in the graph, - we should raise a KeyError - """ - G = nx.Graph() - G.add_nodes_from([(1, {"node_attr1": "a"}), (2, {})]) - G.add_edges_from([(1, 2), (2, 3), (3, 1), (1, 4)]) - pytest.raises(KeyError, nx.weisfeiler_lehman_graph_hash, G, node_attr="node_attr1") - - -def test_isomorphic_edge_attr_and_node_attr(): - """ - Isomorphic graphs with differing node attributes should yield different graph - hashes if the 'node_attr' and 'edge_attr' argument is supplied and populated in - the graph, and there are no hash collisions. - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=500 + i) - - for u in G1.nodes(): - G1.nodes[u]["node_attr1"] = f"{u}-1" - G1.nodes[u]["node_attr2"] = f"{u}-2" - - for a, b in G1.edges: - G1[a][b]["edge_attr1"] = f"{a}-{b}-1" - G1[a][b]["edge_attr2"] = f"{a}-{b}-2" - - g1_hash_edge1_node1 = nx.weisfeiler_lehman_graph_hash( - G1, edge_attr="edge_attr1", node_attr="node_attr1" - ) - g1_hash_edge2_node2 = nx.weisfeiler_lehman_graph_hash( - G1, edge_attr="edge_attr2", node_attr="node_attr2" - ) - g1_hash_edge1_node2 = nx.weisfeiler_lehman_graph_hash( - G1, edge_attr="edge_attr1", node_attr="node_attr2" - ) - g1_hash_no_attr = nx.weisfeiler_lehman_graph_hash(G1) - - assert g1_hash_edge1_node1 != g1_hash_no_attr - assert g1_hash_edge2_node2 != g1_hash_no_attr - assert g1_hash_edge1_node1 != g1_hash_edge2_node2 - assert g1_hash_edge1_node2 != g1_hash_edge2_node2 - assert g1_hash_edge1_node2 != g1_hash_edge1_node1 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_edge1_node1 = nx.weisfeiler_lehman_graph_hash( - G2, edge_attr="edge_attr1", node_attr="node_attr1" - ) - g2_hash_edge2_node2 = nx.weisfeiler_lehman_graph_hash( - G2, edge_attr="edge_attr2", node_attr="node_attr2" - ) - - assert g1_hash_edge1_node1 == g2_hash_edge1_node1 - assert g1_hash_edge2_node2 == g2_hash_edge2_node2 - - -def test_digest_size(): - """ - The hash string lengths should be as expected for a variety of graphs and - digest sizes - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=1000 + i) - - h16 = nx.weisfeiler_lehman_graph_hash(G) - h32 = nx.weisfeiler_lehman_graph_hash(G, digest_size=32) - - assert h16 != h32 - assert len(h16) == 16 * 2 - assert len(h32) == 32 * 2 - - -# Unit tests for the :func:`~networkx.weisfeiler_lehman_hash_subgraphs` function - - -def is_subiteration(a, b): - """ - returns True if that each hash sequence in 'a' is a prefix for - the corresponding sequence indexed by the same node in 'b'. - """ - return all(b[node][: len(hashes)] == hashes for node, hashes in a.items()) - - -def hexdigest_sizes_correct(a, digest_size): - """ - returns True if all hex digest sizes are the expected length in a node:subgraph-hashes - dictionary. Hex digest string length == 2 * bytes digest length since each pair of hex - digits encodes 1 byte (https://docs.python.org/3/library/hashlib.html) - """ - hexdigest_size = digest_size * 2 - list_digest_sizes_correct = lambda l: all(len(x) == hexdigest_size for x in l) - return all(list_digest_sizes_correct(hashes) for hashes in a.values()) - - -def test_empty_graph_subgraph_hash(): - """ " - empty graphs should give empty dict subgraph hashes regardless of other params - """ - G = nx.empty_graph() - - subgraph_hashes1 = nx.weisfeiler_lehman_subgraph_hashes(G) - subgraph_hashes2 = nx.weisfeiler_lehman_subgraph_hashes(G, edge_attr="edge_attr") - subgraph_hashes3 = nx.weisfeiler_lehman_subgraph_hashes(G, node_attr="edge_attr") - subgraph_hashes4 = nx.weisfeiler_lehman_subgraph_hashes(G, iterations=2) - subgraph_hashes5 = nx.weisfeiler_lehman_subgraph_hashes(G, digest_size=64) - - assert subgraph_hashes1 == {} - assert subgraph_hashes2 == {} - assert subgraph_hashes3 == {} - assert subgraph_hashes4 == {} - assert subgraph_hashes5 == {} - - -def test_directed_subgraph_hash(): - """ - A directed graph with no bi-directional edges should yield different subgraph hashes - to the same graph taken as undirected, if all hashes don't collide. - """ - r = 10 - for i in range(r): - G_directed = nx.gn_graph(10 + r, seed=100 + i) - G_undirected = nx.to_undirected(G_directed) - - directed_subgraph_hashes = nx.weisfeiler_lehman_subgraph_hashes(G_directed) - undirected_subgraph_hashes = nx.weisfeiler_lehman_subgraph_hashes(G_undirected) - - assert directed_subgraph_hashes != undirected_subgraph_hashes - - -def test_reversed_subgraph_hash(): - """ - A directed graph with no bi-directional edges should yield different subgraph hashes - to the same graph taken with edge directions reversed if there are no hash collisions. - Here we test a cycle graph which is the minimal counterexample - """ - G = nx.cycle_graph(5, create_using=nx.DiGraph) - nx.set_node_attributes(G, {n: str(n) for n in G.nodes()}, name="label") - - G_reversed = G.reverse() - - h = nx.weisfeiler_lehman_subgraph_hashes(G, node_attr="label") - h_reversed = nx.weisfeiler_lehman_subgraph_hashes(G_reversed, node_attr="label") - - assert h != h_reversed - - -def test_isomorphic_subgraph_hash(): - """ - the subgraph hashes should be invariant to node-relabeling when the output is reindexed - by the same mapping and all hashes don't collide. - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=200 + i) - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g1_subgraph_hashes = nx.weisfeiler_lehman_subgraph_hashes(G1) - g2_subgraph_hashes = nx.weisfeiler_lehman_subgraph_hashes(G2) - - assert g1_subgraph_hashes == {-1 * k: v for k, v in g2_subgraph_hashes.items()} - - -def test_isomorphic_edge_attr_subgraph_hash(): - """ - Isomorphic graphs with differing edge attributes should yield different subgraph - hashes if the 'edge_attr' argument is supplied and populated in the graph, and - all hashes don't collide. - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=300 + i) - - for a, b in G1.edges: - G1[a][b]["edge_attr1"] = f"{a}-{b}-1" - G1[a][b]["edge_attr2"] = f"{a}-{b}-2" - - g1_hash_with_edge_attr1 = nx.weisfeiler_lehman_subgraph_hashes( - G1, edge_attr="edge_attr1" - ) - g1_hash_with_edge_attr2 = nx.weisfeiler_lehman_subgraph_hashes( - G1, edge_attr="edge_attr2" - ) - g1_hash_no_edge_attr = nx.weisfeiler_lehman_subgraph_hashes(G1, edge_attr=None) - - assert g1_hash_with_edge_attr1 != g1_hash_no_edge_attr - assert g1_hash_with_edge_attr2 != g1_hash_no_edge_attr - assert g1_hash_with_edge_attr1 != g1_hash_with_edge_attr2 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_with_edge_attr1 = nx.weisfeiler_lehman_subgraph_hashes( - G2, edge_attr="edge_attr1" - ) - g2_hash_with_edge_attr2 = nx.weisfeiler_lehman_subgraph_hashes( - G2, edge_attr="edge_attr2" - ) - - assert g1_hash_with_edge_attr1 == { - -1 * k: v for k, v in g2_hash_with_edge_attr1.items() - } - assert g1_hash_with_edge_attr2 == { - -1 * k: v for k, v in g2_hash_with_edge_attr2.items() - } - - -def test_missing_edge_attr_subgraph_hash(): - """ - If the 'edge_attr' argument is supplied but is missing from an edge in the graph, - we should raise a KeyError - """ - G = nx.Graph() - G.add_edges_from([(1, 2, {"edge_attr1": "a"}), (1, 3, {})]) - pytest.raises( - KeyError, nx.weisfeiler_lehman_subgraph_hashes, G, edge_attr="edge_attr1" - ) - - -def test_isomorphic_node_attr_subgraph_hash(): - """ - Isomorphic graphs with differing node attributes should yield different subgraph - hashes if the 'node_attr' argument is supplied and populated in the graph, and - all hashes don't collide. - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=400 + i) - - for u in G1.nodes(): - G1.nodes[u]["node_attr1"] = f"{u}-1" - G1.nodes[u]["node_attr2"] = f"{u}-2" - - g1_hash_with_node_attr1 = nx.weisfeiler_lehman_subgraph_hashes( - G1, node_attr="node_attr1" - ) - g1_hash_with_node_attr2 = nx.weisfeiler_lehman_subgraph_hashes( - G1, node_attr="node_attr2" - ) - g1_hash_no_node_attr = nx.weisfeiler_lehman_subgraph_hashes(G1, node_attr=None) - - assert g1_hash_with_node_attr1 != g1_hash_no_node_attr - assert g1_hash_with_node_attr2 != g1_hash_no_node_attr - assert g1_hash_with_node_attr1 != g1_hash_with_node_attr2 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_with_node_attr1 = nx.weisfeiler_lehman_subgraph_hashes( - G2, node_attr="node_attr1" - ) - g2_hash_with_node_attr2 = nx.weisfeiler_lehman_subgraph_hashes( - G2, node_attr="node_attr2" - ) - - assert g1_hash_with_node_attr1 == { - -1 * k: v for k, v in g2_hash_with_node_attr1.items() - } - assert g1_hash_with_node_attr2 == { - -1 * k: v for k, v in g2_hash_with_node_attr2.items() - } - - -def test_missing_node_attr_subgraph_hash(): - """ - If the 'node_attr' argument is supplied but is missing from a node in the graph, - we should raise a KeyError - """ - G = nx.Graph() - G.add_nodes_from([(1, {"node_attr1": "a"}), (2, {})]) - G.add_edges_from([(1, 2), (2, 3), (3, 1), (1, 4)]) - pytest.raises( - KeyError, nx.weisfeiler_lehman_subgraph_hashes, G, node_attr="node_attr1" - ) - - -def test_isomorphic_edge_attr_and_node_attr_subgraph_hash(): - """ - Isomorphic graphs with differing node attributes should yield different subgraph - hashes if the 'node_attr' and 'edge_attr' argument is supplied and populated in - the graph, and all hashes don't collide - The output should still be invariant to node-relabeling - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G1 = nx.erdos_renyi_graph(n, p * i, seed=500 + i) - - for u in G1.nodes(): - G1.nodes[u]["node_attr1"] = f"{u}-1" - G1.nodes[u]["node_attr2"] = f"{u}-2" - - for a, b in G1.edges: - G1[a][b]["edge_attr1"] = f"{a}-{b}-1" - G1[a][b]["edge_attr2"] = f"{a}-{b}-2" - - g1_hash_edge1_node1 = nx.weisfeiler_lehman_subgraph_hashes( - G1, edge_attr="edge_attr1", node_attr="node_attr1" - ) - g1_hash_edge2_node2 = nx.weisfeiler_lehman_subgraph_hashes( - G1, edge_attr="edge_attr2", node_attr="node_attr2" - ) - g1_hash_edge1_node2 = nx.weisfeiler_lehman_subgraph_hashes( - G1, edge_attr="edge_attr1", node_attr="node_attr2" - ) - g1_hash_no_attr = nx.weisfeiler_lehman_subgraph_hashes(G1) - - assert g1_hash_edge1_node1 != g1_hash_no_attr - assert g1_hash_edge2_node2 != g1_hash_no_attr - assert g1_hash_edge1_node1 != g1_hash_edge2_node2 - assert g1_hash_edge1_node2 != g1_hash_edge2_node2 - assert g1_hash_edge1_node2 != g1_hash_edge1_node1 - - G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()}) - - g2_hash_edge1_node1 = nx.weisfeiler_lehman_subgraph_hashes( - G2, edge_attr="edge_attr1", node_attr="node_attr1" - ) - g2_hash_edge2_node2 = nx.weisfeiler_lehman_subgraph_hashes( - G2, edge_attr="edge_attr2", node_attr="node_attr2" - ) - - assert g1_hash_edge1_node1 == { - -1 * k: v for k, v in g2_hash_edge1_node1.items() - } - assert g1_hash_edge2_node2 == { - -1 * k: v for k, v in g2_hash_edge2_node2.items() - } - - -def test_iteration_depth(): - """ - All nodes should have the correct number of subgraph hashes in the output when - using degree as initial node labels - Subsequent iteration depths for the same graph should be additive for each node - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=600 + i) - - depth3 = nx.weisfeiler_lehman_subgraph_hashes(G, iterations=3) - depth4 = nx.weisfeiler_lehman_subgraph_hashes(G, iterations=4) - depth5 = nx.weisfeiler_lehman_subgraph_hashes(G, iterations=5) - - assert all(len(hashes) == 3 for hashes in depth3.values()) - assert all(len(hashes) == 4 for hashes in depth4.values()) - assert all(len(hashes) == 5 for hashes in depth5.values()) - - assert is_subiteration(depth3, depth4) - assert is_subiteration(depth4, depth5) - assert is_subiteration(depth3, depth5) - - -def test_iteration_depth_edge_attr(): - """ - All nodes should have the correct number of subgraph hashes in the output when - setting initial node labels empty and using an edge attribute when aggregating - neighborhoods. - Subsequent iteration depths for the same graph should be additive for each node - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=700 + i) - - for a, b in G.edges: - G[a][b]["edge_attr1"] = f"{a}-{b}-1" - - depth3 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", iterations=3 - ) - depth4 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", iterations=4 - ) - depth5 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", iterations=5 - ) - - assert all(len(hashes) == 3 for hashes in depth3.values()) - assert all(len(hashes) == 4 for hashes in depth4.values()) - assert all(len(hashes) == 5 for hashes in depth5.values()) - - assert is_subiteration(depth3, depth4) - assert is_subiteration(depth4, depth5) - assert is_subiteration(depth3, depth5) - - -def test_iteration_depth_node_attr(): - """ - All nodes should have the correct number of subgraph hashes in the output when - setting initial node labels to an attribute. - Subsequent iteration depths for the same graph should be additive for each node - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=800 + i) - - for u in G.nodes(): - G.nodes[u]["node_attr1"] = f"{u}-1" - - depth3 = nx.weisfeiler_lehman_subgraph_hashes( - G, node_attr="node_attr1", iterations=3 - ) - depth4 = nx.weisfeiler_lehman_subgraph_hashes( - G, node_attr="node_attr1", iterations=4 - ) - depth5 = nx.weisfeiler_lehman_subgraph_hashes( - G, node_attr="node_attr1", iterations=5 - ) - - assert all(len(hashes) == 3 for hashes in depth3.values()) - assert all(len(hashes) == 4 for hashes in depth4.values()) - assert all(len(hashes) == 5 for hashes in depth5.values()) - - assert is_subiteration(depth3, depth4) - assert is_subiteration(depth4, depth5) - assert is_subiteration(depth3, depth5) - - -def test_iteration_depth_node_edge_attr(): - """ - All nodes should have the correct number of subgraph hashes in the output when - setting initial node labels to an attribute and also using an edge attribute when - aggregating neighborhoods. - Subsequent iteration depths for the same graph should be additive for each node - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=900 + i) - - for u in G.nodes(): - G.nodes[u]["node_attr1"] = f"{u}-1" - - for a, b in G.edges: - G[a][b]["edge_attr1"] = f"{a}-{b}-1" - - depth3 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", node_attr="node_attr1", iterations=3 - ) - depth4 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", node_attr="node_attr1", iterations=4 - ) - depth5 = nx.weisfeiler_lehman_subgraph_hashes( - G, edge_attr="edge_attr1", node_attr="node_attr1", iterations=5 - ) - - assert all(len(hashes) == 3 for hashes in depth3.values()) - assert all(len(hashes) == 4 for hashes in depth4.values()) - assert all(len(hashes) == 5 for hashes in depth5.values()) - - assert is_subiteration(depth3, depth4) - assert is_subiteration(depth4, depth5) - assert is_subiteration(depth3, depth5) - - -def test_digest_size_subgraph_hash(): - """ - The hash string lengths should be as expected for a variety of graphs and - digest sizes - """ - n, r = 100, 10 - p = 1.0 / r - for i in range(1, r + 1): - G = nx.erdos_renyi_graph(n, p * i, seed=1000 + i) - - digest_size16_hashes = nx.weisfeiler_lehman_subgraph_hashes(G) - digest_size32_hashes = nx.weisfeiler_lehman_subgraph_hashes(G, digest_size=32) - - assert digest_size16_hashes != digest_size32_hashes - - assert hexdigest_sizes_correct(digest_size16_hashes, 16) - assert hexdigest_sizes_correct(digest_size32_hashes, 32) - - -def test_initial_node_labels_subgraph_hash(): - """ - Including the hashed initial label prepends an extra hash to the lists - """ - G = nx.path_graph(5) - nx.set_node_attributes(G, {i: int(0 < i < 4) for i in G}, "label") - # initial node labels: - # 0--1--1--1--0 - - without_initial_label = nx.weisfeiler_lehman_subgraph_hashes(G, node_attr="label") - assert all(len(v) == 3 for v in without_initial_label.values()) - # 3 different 1 hop nhds - assert len({v[0] for v in without_initial_label.values()}) == 3 - - with_initial_label = nx.weisfeiler_lehman_subgraph_hashes( - G, node_attr="label", include_initial_labels=True - ) - assert all(len(v) == 4 for v in with_initial_label.values()) - # 2 different initial labels - assert len({v[0] for v in with_initial_label.values()}) == 2 - - # check hashes match otherwise - for u in G: - for a, b in zip( - with_initial_label[u][1:], without_initial_label[u], strict=True - ): - assert a == b diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graphical.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graphical.py deleted file mode 100644 index 99f766f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_graphical.py +++ /dev/null @@ -1,163 +0,0 @@ -import pytest - -import networkx as nx - - -def test_valid_degree_sequence1(): - n = 100 - p = 0.3 - for i in range(10): - G = nx.erdos_renyi_graph(n, p) - deg = (d for n, d in G.degree()) - assert nx.is_graphical(deg, method="eg") - assert nx.is_graphical(deg, method="hh") - - -def test_valid_degree_sequence2(): - n = 100 - for i in range(10): - G = nx.barabasi_albert_graph(n, 1) - deg = (d for n, d in G.degree()) - assert nx.is_graphical(deg, method="eg") - assert nx.is_graphical(deg, method="hh") - - -def test_string_input(): - pytest.raises(nx.NetworkXException, nx.is_graphical, [], "foo") - pytest.raises(nx.NetworkXException, nx.is_graphical, ["red"], "hh") - pytest.raises(nx.NetworkXException, nx.is_graphical, ["red"], "eg") - - -def test_non_integer_input(): - pytest.raises(nx.NetworkXException, nx.is_graphical, [72.5], "eg") - pytest.raises(nx.NetworkXException, nx.is_graphical, [72.5], "hh") - - -def test_negative_input(): - assert not nx.is_graphical([-1], "hh") - assert not nx.is_graphical([-1], "eg") - - -class TestAtlas: - @classmethod - def setup_class(cls): - global atlas - from networkx.generators import atlas - - cls.GAG = atlas.graph_atlas_g() - - def test_atlas(self): - for graph in self.GAG: - deg = (d for n, d in graph.degree()) - assert nx.is_graphical(deg, method="eg") - assert nx.is_graphical(deg, method="hh") - - -def test_small_graph_true(): - z = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert nx.is_graphical(z, method="hh") - assert nx.is_graphical(z, method="eg") - z = [10, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2] - assert nx.is_graphical(z, method="hh") - assert nx.is_graphical(z, method="eg") - z = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert nx.is_graphical(z, method="hh") - assert nx.is_graphical(z, method="eg") - - -def test_small_graph_false(): - z = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert not nx.is_graphical(z, method="hh") - assert not nx.is_graphical(z, method="eg") - z = [6, 5, 4, 4, 2, 1, 1, 1] - assert not nx.is_graphical(z, method="hh") - assert not nx.is_graphical(z, method="eg") - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert not nx.is_graphical(z, method="hh") - assert not nx.is_graphical(z, method="eg") - - -def test_directed_degree_sequence(): - # Test a range of valid directed degree sequences - n, r = 100, 10 - p = 1.0 / r - for i in range(r): - G = nx.erdos_renyi_graph(n, p * (i + 1), None, True) - din = (d for n, d in G.in_degree()) - dout = (d for n, d in G.out_degree()) - assert nx.is_digraphical(din, dout) - - -def test_small_directed_sequences(): - dout = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1] - assert nx.is_digraphical(din, dout) - # Test nongraphical directed sequence - dout = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [103, 102, 102, 102, 102, 102, 102, 102, 102, 102] - assert not nx.is_digraphical(din, dout) - # Test digraphical small sequence - dout = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - din = [2, 2, 2, 2, 2, 2, 2, 2, 1, 1] - assert nx.is_digraphical(din, dout) - # Test nonmatching sum - din = [2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1] - assert not nx.is_digraphical(din, dout) - # Test for negative integer in sequence - din = [2, 2, 2, -2, 2, 2, 2, 2, 1, 1, 4] - assert not nx.is_digraphical(din, dout) - # Test for noninteger - din = dout = [1, 1, 1.1, 1] - assert not nx.is_digraphical(din, dout) - din = dout = [1, 1, "rer", 1] - assert not nx.is_digraphical(din, dout) - - -def test_multi_sequence(): - # Test nongraphical multi sequence - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1] - assert not nx.is_multigraphical(seq) - # Test small graphical multi sequence - seq = [6, 5, 4, 4, 2, 1, 1, 1] - assert nx.is_multigraphical(seq) - # Test for negative integer in sequence - seq = [6, 5, 4, -4, 2, 1, 1, 1] - assert not nx.is_multigraphical(seq) - # Test for sequence with odd sum - seq = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert not nx.is_multigraphical(seq) - # Test for noninteger - seq = [1, 1, 1.1, 1] - assert not nx.is_multigraphical(seq) - seq = [1, 1, "rer", 1] - assert not nx.is_multigraphical(seq) - - -def test_pseudo_sequence(): - # Test small valid pseudo sequence - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1] - assert nx.is_pseudographical(seq) - # Test for sequence with odd sum - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert not nx.is_pseudographical(seq) - # Test for negative integer in sequence - seq = [1000, 3, 3, 3, 3, 2, 2, -2, 1, 1] - assert not nx.is_pseudographical(seq) - # Test for noninteger - seq = [1, 1, 1.1, 1] - assert not nx.is_pseudographical(seq) - seq = [1, 1, "rer", 1] - assert not nx.is_pseudographical(seq) - - -def test_numpy_degree_sequence(): - np = pytest.importorskip("numpy") - ds = np.array([1, 2, 2, 2, 1], dtype=np.int64) - assert nx.is_graphical(ds, "eg") - assert nx.is_graphical(ds, "hh") - ds = np.array([1, 2, 2, 2, 1], dtype=np.float64) - assert nx.is_graphical(ds, "eg") - assert nx.is_graphical(ds, "hh") - ds = np.array([1.1, 2, 2, 2, 1], dtype=np.float64) - pytest.raises(nx.NetworkXException, nx.is_graphical, ds, "eg") - pytest.raises(nx.NetworkXException, nx.is_graphical, ds, "hh") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hierarchy.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hierarchy.py deleted file mode 100644 index eaa6a67..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hierarchy.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest - -import networkx as nx - - -def test_hierarchy_undirected(): - G = nx.cycle_graph(5) - pytest.raises(nx.NetworkXError, nx.flow_hierarchy, G) - - -def test_hierarchy_cycle(): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - assert nx.flow_hierarchy(G) == 0.0 - - -def test_hierarchy_tree(): - G = nx.full_rary_tree(2, 16, create_using=nx.DiGraph()) - assert nx.flow_hierarchy(G) == 1.0 - - -def test_hierarchy_1(): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 1), (3, 4), (0, 4)]) - assert nx.flow_hierarchy(G) == 0.5 - - -def test_hierarchy_weight(): - G = nx.DiGraph() - G.add_edges_from( - [ - (0, 1, {"weight": 0.3}), - (1, 2, {"weight": 0.1}), - (2, 3, {"weight": 0.1}), - (3, 1, {"weight": 0.1}), - (3, 4, {"weight": 0.3}), - (0, 4, {"weight": 0.3}), - ] - ) - assert nx.flow_hierarchy(G, weight="weight") == 0.75 - - -@pytest.mark.parametrize("n", (0, 1, 3)) -def test_hierarchy_empty_graph(n): - G = nx.empty_graph(n, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError, match=".*not applicable to empty graphs"): - nx.flow_hierarchy(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hybrid.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hybrid.py deleted file mode 100644 index 6af0016..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_hybrid.py +++ /dev/null @@ -1,24 +0,0 @@ -import networkx as nx - - -def test_2d_grid_graph(): - # FC article claims 2d grid graph of size n is (3,3)-connected - # and (5,9)-connected, but I don't think it is (5,9)-connected - G = nx.grid_2d_graph(8, 8, periodic=True) - assert nx.is_kl_connected(G, 3, 3) - assert not nx.is_kl_connected(G, 5, 9) - (H, graphOK) = nx.kl_connected_subgraph(G, 5, 9, same_as_graph=True) - assert not graphOK - - -def test_small_graph(): - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(2, 3) - assert nx.is_kl_connected(G, 2, 2) - H = nx.kl_connected_subgraph(G, 2, 2) - (H, graphOK) = nx.kl_connected_subgraph( - G, 2, 2, low_memory=True, same_as_graph=True - ) - assert graphOK diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_isolate.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_isolate.py deleted file mode 100644 index d29b306..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_isolate.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.isolates` module.""" - -import networkx as nx - - -def test_is_isolate(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_node(2) - assert not nx.is_isolate(G, 0) - assert not nx.is_isolate(G, 1) - assert nx.is_isolate(G, 2) - - -def test_isolates(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_nodes_from([2, 3]) - assert sorted(nx.isolates(G)) == [2, 3] - - -def test_number_of_isolates(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_nodes_from([2, 3]) - assert nx.number_of_isolates(G) == 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_link_prediction.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_link_prediction.py deleted file mode 100644 index 0878496..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_link_prediction.py +++ /dev/null @@ -1,586 +0,0 @@ -import math -from functools import partial - -import pytest - -import networkx as nx - - -def _test_func(G, ebunch, expected, predict_func, **kwargs): - result = predict_func(G, ebunch, **kwargs) - exp_dict = {tuple(sorted([u, v])): score for u, v, score in expected} - res_dict = {tuple(sorted([u, v])): score for u, v, score in result} - - assert len(exp_dict) == len(res_dict) - for p in exp_dict: - assert exp_dict[p] == pytest.approx(res_dict[p], abs=1e-7) - - -class TestResourceAllocationIndex: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.resource_allocation_index) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 0.75)]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 2)], [(0, 2, 0.5)]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(1, 2)], [(1, 2, 0.25)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - assert pytest.raises( - nx.NetworkXNotImplemented, self.func, graph_type([(0, 1), (1, 2)]), [(0, 2)] - ) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(4) - self.test(G, [(0, 0)], [(0, 0, 1)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 0.5), (1, 2, 0.5), (1, 3, 0)]) - - -class TestJaccardCoefficient: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.jaccard_coefficient) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 0.6)]) - - def test_P4(self): - G = nx.path_graph(4) - self.test(G, [(0, 2)], [(0, 2, 0.5)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - assert pytest.raises( - nx.NetworkXNotImplemented, self.func, graph_type([(0, 1), (1, 2)]), [(0, 2)] - ) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (2, 3)]) - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_isolated_nodes(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 0.5), (1, 2, 0.5), (1, 3, 0)]) - - -class TestAdamicAdarIndex: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.adamic_adar_index) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 3 / math.log(4))]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 2)], [(0, 2, 1 / math.log(2))]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(1, 2)], [(1, 2, 1 / math.log(4))]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - assert pytest.raises( - nx.NetworkXNotImplemented, self.func, graph_type([(0, 1), (1, 2)]), [(0, 2)] - ) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(4) - self.test(G, [(0, 0)], [(0, 0, 3 / math.log(3))]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test( - G, None, [(0, 3, 1 / math.log(2)), (1, 2, 1 / math.log(2)), (1, 3, 0)] - ) - - -class TestCommonNeighborCentrality: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.common_neighbor_centrality) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 3.0)], alpha=1) - self.test(G, [(0, 1)], [(0, 1, 5.0)], alpha=0) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 2)], [(0, 2, 1.25)], alpha=0.5) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(1, 2)], [(1, 2, 1.75)], alpha=0.5) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - assert pytest.raises( - nx.NetworkXNotImplemented, self.func, graph_type([(0, 1), (1, 2)]), [(0, 2)] - ) - - def test_node_u_not_found(self): - G = nx.Graph() - G.add_edges_from([(1, 3), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 1)]) - - def test_node_v_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(4) - assert pytest.raises(nx.NetworkXAlgorithmError, self.test, G, [(0, 0)], []) - - def test_equal_nodes_with_alpha_one_raises_error(self): - G = nx.complete_graph(4) - assert pytest.raises( - nx.NetworkXAlgorithmError, self.test, G, [(0, 0)], [], alpha=1.0 - ) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 1.5), (1, 2, 1.5), (1, 3, 2 / 3)], alpha=0.5) - - -class TestPreferentialAttachment: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.preferential_attachment) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 16)]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 1)], [(0, 1, 2)]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(0, 2)], [(0, 2, 4)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - assert pytest.raises( - nx.NetworkXNotImplemented, self.func, graph_type([(0, 1), (1, 2)]), [(0, 2)] - ) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_zero_degrees(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 2), (1, 2, 2), (1, 3, 1)]) - - -class TestCNSoundarajanHopcroft: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.cn_soundarajan_hopcroft) - cls.test = partial(_test_func, predict_func=cls.func, community="community") - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 1 - self.test(G, [(0, 1)], [(0, 1, 5)]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 2)], [(0, 2, 1)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]["community"] = 1 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 1 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 2)], [(1, 2, 2)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - G = graph_type([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 0)], [(0, 0, 4)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 1 - self.test(G, [(0, 3)], [(0, 3, 2)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 4)], [(1, 4, 4)]) - - def test_custom_community_attribute_name(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["cmty"] = 0 - G.nodes[1]["cmty"] = 0 - G.nodes[2]["cmty"] = 0 - G.nodes[3]["cmty"] = 1 - self.test(G, [(0, 3)], [(0, 3, 2)], community="cmty") - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - self.test(G, None, [(0, 3, 2), (1, 2, 1), (1, 3, 0)]) - - -class TestRAIndexSoundarajanHopcroft: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.ra_index_soundarajan_hopcroft) - cls.test = partial(_test_func, predict_func=cls.func, community="community") - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 1 - self.test(G, [(0, 1)], [(0, 1, 0.5)]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]["community"] = 1 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 1 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 2)], [(1, 2, 0.25)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - G = graph_type([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 0)], [(0, 0, 1)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 4)], [(1, 4, 1)]) - - def test_custom_community_attribute_name(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["cmty"] = 0 - G.nodes[1]["cmty"] = 0 - G.nodes[2]["cmty"] = 0 - G.nodes[3]["cmty"] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)], community="cmty") - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - self.test(G, None, [(0, 3, 0.5), (1, 2, 0), (1, 3, 0)]) - - -class TestWithinInterCluster: - @classmethod - def setup_class(cls): - cls.delta = 0.001 - cls.func = staticmethod(nx.within_inter_cluster) - cls.test = partial( - _test_func, predict_func=cls.func, delta=cls.delta, community="community" - ) - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 1 - self.test(G, [(0, 1)], [(0, 1, 2 / (1 + self.delta))]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]["community"] = 1 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 1 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 2)], [(1, 2, 1 / self.delta)]) - - @pytest.mark.parametrize("graph_type", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) - def test_notimplemented(self, graph_type): - G = graph_type([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_node_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NodeNotFound, self.func, G, [(0, 4)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - self.test(G, [(0, 0)], [(0, 0, 2 / self.delta)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)]) - - def test_no_inter_cluster_common_neighbor(self): - G = nx.complete_graph(4) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - self.test(G, [(0, 3)], [(0, 3, 2 / self.delta)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 0 - G.nodes[3]["community"] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]["community"] = 0 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - G.nodes[4]["community"] = 0 - self.test(G, [(1, 4)], [(1, 4, 2 / self.delta)]) - - def test_invalid_delta(self): - G = nx.complete_graph(3) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXAlgorithmError, self.func, G, [(0, 1)], 0) - assert pytest.raises(nx.NetworkXAlgorithmError, self.func, G, [(0, 1)], -0.5) - - def test_custom_community_attribute_name(self): - G = nx.complete_graph(4) - G.nodes[0]["cmty"] = 0 - G.nodes[1]["cmty"] = 0 - G.nodes[2]["cmty"] = 0 - G.nodes[3]["cmty"] = 0 - self.test(G, [(0, 3)], [(0, 3, 2 / self.delta)], community="cmty") - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]["community"] = 0 - G.nodes[1]["community"] = 1 - G.nodes[2]["community"] = 0 - G.nodes[3]["community"] = 0 - self.test(G, None, [(0, 3, 1 / self.delta), (1, 2, 0), (1, 3, 0)]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_lowest_common_ancestors.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_lowest_common_ancestors.py deleted file mode 100644 index 66d7522..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_lowest_common_ancestors.py +++ /dev/null @@ -1,427 +0,0 @@ -from itertools import chain, combinations, product - -import pytest - -import networkx as nx - -tree_all_pairs_lca = nx.tree_all_pairs_lowest_common_ancestor -all_pairs_lca = nx.all_pairs_lowest_common_ancestor - - -def get_pair(dictionary, n1, n2): - if (n1, n2) in dictionary: - return dictionary[n1, n2] - else: - return dictionary[n2, n1] - - -class TestTreeLCA: - @classmethod - def setup_class(cls): - cls.DG = nx.DiGraph() - edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - cls.DG.add_edges_from(edges) - cls.ans = dict(tree_all_pairs_lca(cls.DG, 0)) - gold = {(n, n): n for n in cls.DG} - gold.update({(0, i): 0 for i in range(1, 7)}) - gold.update( - { - (1, 2): 0, - (1, 3): 1, - (1, 4): 1, - (1, 5): 0, - (1, 6): 0, - (2, 3): 0, - (2, 4): 0, - (2, 5): 2, - (2, 6): 2, - (3, 4): 1, - (3, 5): 0, - (3, 6): 0, - (4, 5): 0, - (4, 6): 0, - (5, 6): 2, - } - ) - - cls.gold = gold - - @staticmethod - def assert_has_same_pairs(d1, d2): - for a, b in ((min(pair), max(pair)) for pair in chain(d1, d2)): - assert get_pair(d1, a, b) == get_pair(d2, a, b) - - def test_tree_all_pairs_lca_default_root(self): - assert dict(tree_all_pairs_lca(self.DG)) == self.ans - - def test_tree_all_pairs_lca_return_subset(self): - test_pairs = [(0, 1), (0, 1), (1, 0)] - ans = dict(tree_all_pairs_lca(self.DG, 0, test_pairs)) - assert (0, 1) in ans and (1, 0) in ans - assert len(ans) == 2 - - def test_tree_all_pairs_lca(self): - all_pairs = chain(combinations(self.DG, 2), ((node, node) for node in self.DG)) - - ans = dict(tree_all_pairs_lca(self.DG, 0, all_pairs)) - self.assert_has_same_pairs(ans, self.ans) - - def test_tree_all_pairs_gold_example(self): - ans = dict(tree_all_pairs_lca(self.DG)) - self.assert_has_same_pairs(self.gold, ans) - - def test_tree_all_pairs_lca_invalid_input(self): - empty_digraph = tree_all_pairs_lca(nx.DiGraph()) - pytest.raises(nx.NetworkXPointlessConcept, list, empty_digraph) - - bad_pairs_digraph = tree_all_pairs_lca(self.DG, pairs=[(-1, -2)]) - pytest.raises(nx.NodeNotFound, list, bad_pairs_digraph) - - def test_tree_all_pairs_lca_subtrees(self): - ans = dict(tree_all_pairs_lca(self.DG, 1)) - gold = { - pair: lca - for (pair, lca) in self.gold.items() - if all(n in (1, 3, 4) for n in pair) - } - self.assert_has_same_pairs(gold, ans) - - def test_tree_all_pairs_lca_disconnected_nodes(self): - G = nx.DiGraph() - G.add_node(1) - assert {(1, 1): 1} == dict(tree_all_pairs_lca(G)) - - G.add_node(0) - assert {(1, 1): 1} == dict(tree_all_pairs_lca(G, 1)) - assert {(0, 0): 0} == dict(tree_all_pairs_lca(G, 0)) - - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_tree_all_pairs_lca_error_if_input_not_tree(self): - # Cycle - G = nx.DiGraph([(1, 2), (2, 1)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - # DAG - G = nx.DiGraph([(0, 2), (1, 2)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_tree_all_pairs_lca_generator(self): - pairs = iter([(0, 1), (0, 1), (1, 0)]) - some_pairs = dict(tree_all_pairs_lca(self.DG, 0, pairs)) - assert (0, 1) in some_pairs and (1, 0) in some_pairs - assert len(some_pairs) == 2 - - def test_tree_all_pairs_lca_nonexisting_pairs_exception(self): - lca = tree_all_pairs_lca(self.DG, 0, [(-1, -1)]) - pytest.raises(nx.NodeNotFound, list, lca) - # check if node is None - lca = tree_all_pairs_lca(self.DG, None, [(-1, -1)]) - pytest.raises(nx.NodeNotFound, list, lca) - - def test_tree_all_pairs_lca_routine_bails_on_DAGs(self): - G = nx.DiGraph([(3, 4), (5, 4)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_tree_all_pairs_lca_not_implemented(self): - NNI = nx.NetworkXNotImplemented - G = nx.Graph([(0, 1)]) - with pytest.raises(NNI): - next(tree_all_pairs_lca(G)) - with pytest.raises(NNI): - next(all_pairs_lca(G)) - pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1) - G = nx.MultiGraph([(0, 1)]) - with pytest.raises(NNI): - next(tree_all_pairs_lca(G)) - with pytest.raises(NNI): - next(all_pairs_lca(G)) - pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1) - - def test_tree_all_pairs_lca_trees_without_LCAs(self): - G = nx.DiGraph() - G.add_node(3) - ans = list(tree_all_pairs_lca(G)) - assert ans == [((3, 3), 3)] - - -class TestMultiTreeLCA(TestTreeLCA): - @classmethod - def setup_class(cls): - cls.DG = nx.MultiDiGraph() - edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - cls.DG.add_edges_from(edges) - cls.ans = dict(tree_all_pairs_lca(cls.DG, 0)) - # add multiedges - cls.DG.add_edges_from(edges) - - gold = {(n, n): n for n in cls.DG} - gold.update({(0, i): 0 for i in range(1, 7)}) - gold.update( - { - (1, 2): 0, - (1, 3): 1, - (1, 4): 1, - (1, 5): 0, - (1, 6): 0, - (2, 3): 0, - (2, 4): 0, - (2, 5): 2, - (2, 6): 2, - (3, 4): 1, - (3, 5): 0, - (3, 6): 0, - (4, 5): 0, - (4, 6): 0, - (5, 6): 2, - } - ) - - cls.gold = gold - - -class TestDAGLCA: - @classmethod - def setup_class(cls): - cls.DG = nx.DiGraph() - nx.add_path(cls.DG, (0, 1, 2, 3)) - nx.add_path(cls.DG, (0, 4, 3)) - nx.add_path(cls.DG, (0, 5, 6, 8, 3)) - nx.add_path(cls.DG, (5, 7, 8)) - cls.DG.add_edge(6, 2) - cls.DG.add_edge(7, 2) - - cls.root_distance = nx.shortest_path_length(cls.DG, source=0) - - cls.gold = { - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 0, - (1, 5): 0, - (1, 6): 0, - (1, 7): 0, - (1, 8): 0, - (2, 2): 2, - (2, 3): 2, - (2, 4): 0, - (2, 5): 5, - (2, 6): 6, - (2, 7): 7, - (2, 8): 7, - (3, 3): 3, - (3, 4): 4, - (3, 5): 5, - (3, 6): 6, - (3, 7): 7, - (3, 8): 8, - (4, 4): 4, - (4, 5): 0, - (4, 6): 0, - (4, 7): 0, - (4, 8): 0, - (5, 5): 5, - (5, 6): 5, - (5, 7): 5, - (5, 8): 5, - (6, 6): 6, - (6, 7): 5, - (6, 8): 6, - (7, 7): 7, - (7, 8): 7, - (8, 8): 8, - } - cls.gold.update(((0, n), 0) for n in cls.DG) - - def assert_lca_dicts_same(self, d1, d2, G=None): - """Checks if d1 and d2 contain the same pairs and - have a node at the same distance from root for each. - If G is None use self.DG.""" - if G is None: - G = self.DG - root_distance = self.root_distance - else: - roots = [n for n, deg in G.in_degree if deg == 0] - assert len(roots) == 1 - root_distance = nx.shortest_path_length(G, source=roots[0]) - - for a, b in ((min(pair), max(pair)) for pair in chain(d1, d2)): - assert ( - root_distance[get_pair(d1, a, b)] == root_distance[get_pair(d2, a, b)] - ) - - def test_all_pairs_lca_gold_example(self): - self.assert_lca_dicts_same(dict(all_pairs_lca(self.DG)), self.gold) - - def test_all_pairs_lca_all_pairs_given(self): - all_pairs = list(product(self.DG.nodes(), self.DG.nodes())) - ans = all_pairs_lca(self.DG, pairs=all_pairs) - self.assert_lca_dicts_same(dict(ans), self.gold) - - def test_all_pairs_lca_generator(self): - all_pairs = product(self.DG.nodes(), self.DG.nodes()) - ans = all_pairs_lca(self.DG, pairs=all_pairs) - self.assert_lca_dicts_same(dict(ans), self.gold) - - def test_all_pairs_lca_input_graph_with_two_roots(self): - G = self.DG.copy() - G.add_edge(9, 10) - G.add_edge(9, 4) - gold = self.gold.copy() - gold[9, 9] = 9 - gold[9, 10] = 9 - gold[9, 4] = 9 - gold[9, 3] = 9 - gold[10, 4] = 9 - gold[10, 3] = 9 - gold[10, 10] = 10 - - testing = dict(all_pairs_lca(G)) - - G.add_edge(-1, 9) - G.add_edge(-1, 0) - self.assert_lca_dicts_same(testing, gold, G) - - def test_all_pairs_lca_nonexisting_pairs_exception(self): - pytest.raises(nx.NodeNotFound, all_pairs_lca, self.DG, [(-1, -1)]) - - def test_all_pairs_lca_pairs_without_lca(self): - G = self.DG.copy() - G.add_node(-1) - gen = all_pairs_lca(G, [(-1, -1), (-1, 0)]) - assert dict(gen) == {(-1, -1): -1} - - def test_all_pairs_lca_null_graph(self): - pytest.raises(nx.NetworkXPointlessConcept, all_pairs_lca, nx.DiGraph()) - - def test_all_pairs_lca_non_dags(self): - pytest.raises(nx.NetworkXError, all_pairs_lca, nx.DiGraph([(3, 4), (4, 3)])) - - def test_all_pairs_lca_nonempty_graph_without_lca(self): - G = nx.DiGraph() - G.add_node(3) - ans = list(all_pairs_lca(G)) - assert ans == [((3, 3), 3)] - - def test_all_pairs_lca_bug_gh4942(self): - G = nx.DiGraph([(0, 2), (1, 2), (2, 3)]) - ans = list(all_pairs_lca(G)) - assert len(ans) == 9 - - def test_all_pairs_lca_default_kwarg(self): - G = nx.DiGraph([(0, 1), (2, 1)]) - sentinel = object() - assert nx.lowest_common_ancestor(G, 0, 2, default=sentinel) is sentinel - - def test_all_pairs_lca_identity(self): - G = nx.DiGraph() - G.add_node(3) - assert nx.lowest_common_ancestor(G, 3, 3) == 3 - - def test_all_pairs_lca_issue_4574(self): - G = nx.DiGraph() - G.add_nodes_from(range(17)) - G.add_edges_from( - [ - (2, 0), - (1, 2), - (3, 2), - (5, 2), - (8, 2), - (11, 2), - (4, 5), - (6, 5), - (7, 8), - (10, 8), - (13, 11), - (14, 11), - (15, 11), - (9, 10), - (12, 13), - (16, 15), - ] - ) - - assert nx.lowest_common_ancestor(G, 7, 9) == None - - def test_all_pairs_lca_one_pair_gh4942(self): - G = nx.DiGraph() - # Note: order edge addition is critical to the test - G.add_edge(0, 1) - G.add_edge(2, 0) - G.add_edge(2, 3) - G.add_edge(4, 0) - G.add_edge(5, 2) - - assert nx.lowest_common_ancestor(G, 1, 3) == 2 - - -class TestMultiDiGraph_DAGLCA(TestDAGLCA): - @classmethod - def setup_class(cls): - cls.DG = nx.MultiDiGraph() - nx.add_path(cls.DG, (0, 1, 2, 3)) - # add multiedges - nx.add_path(cls.DG, (0, 1, 2, 3)) - nx.add_path(cls.DG, (0, 4, 3)) - nx.add_path(cls.DG, (0, 5, 6, 8, 3)) - nx.add_path(cls.DG, (5, 7, 8)) - cls.DG.add_edge(6, 2) - cls.DG.add_edge(7, 2) - - cls.root_distance = nx.shortest_path_length(cls.DG, source=0) - - cls.gold = { - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 0, - (1, 5): 0, - (1, 6): 0, - (1, 7): 0, - (1, 8): 0, - (2, 2): 2, - (2, 3): 2, - (2, 4): 0, - (2, 5): 5, - (2, 6): 6, - (2, 7): 7, - (2, 8): 7, - (3, 3): 3, - (3, 4): 4, - (3, 5): 5, - (3, 6): 6, - (3, 7): 7, - (3, 8): 8, - (4, 4): 4, - (4, 5): 0, - (4, 6): 0, - (4, 7): 0, - (4, 8): 0, - (5, 5): 5, - (5, 6): 5, - (5, 7): 5, - (5, 8): 5, - (6, 6): 6, - (6, 7): 5, - (6, 8): 6, - (7, 7): 7, - (7, 8): 7, - (8, 8): 8, - } - cls.gold.update(((0, n), 0) for n in cls.DG) - - -def test_all_pairs_lca_self_ancestors(): - """Self-ancestors should always be the node itself, i.e. lca of (0, 0) is 0. - See gh-4458.""" - # DAG for test - note order of node/edge addition is relevant - G = nx.DiGraph() - G.add_nodes_from(range(5)) - G.add_edges_from([(1, 0), (2, 0), (3, 2), (4, 1), (4, 3)]) - - ap_lca = nx.all_pairs_lowest_common_ancestor - assert all(u == v == a for (u, v), a in ap_lca(G) if u == v) - MG = nx.MultiDiGraph(G) - assert all(u == v == a for (u, v), a in ap_lca(MG) if u == v) - MG.add_edges_from([(1, 0), (2, 0)]) - assert all(u == v == a for (u, v), a in ap_lca(MG) if u == v) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_matching.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_matching.py deleted file mode 100644 index 37853e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_matching.py +++ /dev/null @@ -1,605 +0,0 @@ -import math -from itertools import permutations - -from pytest import raises - -import networkx as nx -from networkx.algorithms.matching import matching_dict_to_set -from networkx.utils import edges_equal - - -class TestMaxWeightMatching: - """Unit tests for the - :func:`~networkx.algorithms.matching.max_weight_matching` function. - - """ - - def test_trivial1(self): - """Empty graph""" - G = nx.Graph() - assert nx.max_weight_matching(G) == set() - assert nx.min_weight_matching(G) == set() - - def test_selfloop(self): - G = nx.Graph() - G.add_edge(0, 0, weight=100) - assert nx.max_weight_matching(G) == set() - assert nx.min_weight_matching(G) == set() - - def test_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert edges_equal( - nx.max_weight_matching(G), matching_dict_to_set({0: 1, 1: 0}) - ) - assert edges_equal( - nx.min_weight_matching(G), matching_dict_to_set({0: 1, 1: 0}) - ) - - def test_two_path(self): - G = nx.Graph() - G.add_edge("one", "two", weight=10) - G.add_edge("two", "three", weight=11) - assert edges_equal( - nx.max_weight_matching(G), - matching_dict_to_set({"three": "two", "two": "three"}), - ) - assert edges_equal( - nx.min_weight_matching(G), - matching_dict_to_set({"one": "two", "two": "one"}), - ) - - def test_path(self): - G = nx.Graph() - G.add_edge(1, 2, weight=5) - G.add_edge(2, 3, weight=11) - G.add_edge(3, 4, weight=5) - assert edges_equal( - nx.max_weight_matching(G), matching_dict_to_set({2: 3, 3: 2}) - ) - assert edges_equal( - nx.max_weight_matching(G, 1), matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3}) - ) - assert edges_equal( - nx.min_weight_matching(G), matching_dict_to_set({1: 2, 3: 4}) - ) - assert edges_equal( - nx.min_weight_matching(G, 1), matching_dict_to_set({1: 2, 3: 4}) - ) - - def test_square(self): - G = nx.Graph() - G.add_edge(1, 4, weight=2) - G.add_edge(2, 3, weight=2) - G.add_edge(1, 2, weight=1) - G.add_edge(3, 4, weight=4) - assert edges_equal( - nx.max_weight_matching(G), matching_dict_to_set({1: 2, 3: 4}) - ) - assert edges_equal( - nx.min_weight_matching(G), matching_dict_to_set({1: 4, 2: 3}) - ) - - def test_edge_attribute_name(self): - G = nx.Graph() - G.add_edge("one", "two", weight=10, abcd=11) - G.add_edge("two", "three", weight=11, abcd=10) - assert edges_equal( - nx.max_weight_matching(G, weight="abcd"), - matching_dict_to_set({"one": "two", "two": "one"}), - ) - assert edges_equal( - nx.min_weight_matching(G, weight="abcd"), - matching_dict_to_set({"three": "two"}), - ) - - def test_floating_point_weights(self): - G = nx.Graph() - G.add_edge(1, 2, weight=math.pi) - G.add_edge(2, 3, weight=math.exp(1)) - G.add_edge(1, 3, weight=3.0) - G.add_edge(1, 4, weight=math.sqrt(2.0)) - assert edges_equal( - nx.max_weight_matching(G), matching_dict_to_set({1: 4, 2: 3, 3: 2, 4: 1}) - ) - assert edges_equal( - nx.min_weight_matching(G), matching_dict_to_set({1: 4, 2: 3, 3: 2, 4: 1}) - ) - - def test_negative_weights(self): - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 3, weight=-2) - G.add_edge(2, 3, weight=1) - G.add_edge(2, 4, weight=-1) - G.add_edge(3, 4, weight=-6) - assert edges_equal( - nx.max_weight_matching(G), matching_dict_to_set({1: 2, 2: 1}) - ) - assert edges_equal( - nx.max_weight_matching(G, maxcardinality=True), - matching_dict_to_set({1: 3, 2: 4, 3: 1, 4: 2}), - ) - assert edges_equal( - nx.min_weight_matching(G), matching_dict_to_set({1: 2, 3: 4}) - ) - - def test_s_blossom(self): - """Create S-blossom and use it for augmentation:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 8), (1, 3, 9), (2, 3, 10), (3, 4, 7)]) - answer = matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - G.add_weighted_edges_from([(1, 6, 5), (4, 5, 6)]) - answer = matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_s_t_blossom(self): - """Create S-blossom, relabel as T-blossom, use for augmentation:""" - G = nx.Graph() - G.add_weighted_edges_from( - [(1, 2, 9), (1, 3, 8), (2, 3, 10), (1, 4, 5), (4, 5, 4), (1, 6, 3)] - ) - answer = matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - G.add_edge(4, 5, weight=3) - G.add_edge(1, 6, weight=4) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - G.remove_edge(1, 6) - G.add_edge(3, 6, weight=4) - answer = matching_dict_to_set({1: 2, 2: 1, 3: 6, 4: 5, 5: 4, 6: 3}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nested_s_blossom(self): - """Create nested S-blossom, use for augmentation:""" - - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 9), - (1, 3, 9), - (2, 3, 10), - (2, 4, 8), - (3, 5, 8), - (4, 5, 10), - (5, 6, 6), - ] - ) - dict_format = {1: 3, 2: 4, 3: 1, 4: 2, 5: 6, 6: 5} - expected = {frozenset(e) for e in matching_dict_to_set(dict_format)} - answer = {frozenset(e) for e in nx.max_weight_matching(G)} - assert answer == expected - answer = {frozenset(e) for e in nx.min_weight_matching(G)} - assert answer == expected - - def test_nested_s_blossom_relabel(self): - """Create S-blossom, relabel as S, include in nested S-blossom:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 10), - (1, 7, 10), - (2, 3, 12), - (3, 4, 20), - (3, 5, 20), - (4, 5, 25), - (5, 6, 10), - (6, 7, 10), - (7, 8, 8), - ] - ) - answer = matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3, 5: 6, 6: 5, 7: 8, 8: 7}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nested_s_blossom_expand(self): - """Create nested S-blossom, augment, expand recursively:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 8), - (1, 3, 8), - (2, 3, 10), - (2, 4, 12), - (3, 5, 12), - (4, 5, 14), - (4, 6, 12), - (5, 7, 12), - (6, 7, 14), - (7, 8, 12), - ] - ) - answer = matching_dict_to_set({1: 2, 2: 1, 3: 5, 4: 6, 5: 3, 6: 4, 7: 8, 8: 7}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_s_blossom_relabel_expand(self): - """Create S-blossom, relabel as T, expand:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 23), - (1, 5, 22), - (1, 6, 15), - (2, 3, 25), - (3, 4, 22), - (4, 5, 25), - (4, 8, 14), - (5, 7, 13), - ] - ) - answer = matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nested_s_blossom_relabel_expand(self): - """Create nested S-blossom, relabel as T, expand:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 19), - (1, 3, 20), - (1, 8, 8), - (2, 3, 25), - (2, 4, 18), - (3, 5, 18), - (4, 5, 13), - (4, 7, 7), - (5, 6, 7), - ] - ) - answer = matching_dict_to_set({1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1}) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nasty_blossom1(self): - """Create blossom, relabel as T in more than one way, expand, - augment: - """ - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 35), - (5, 7, 26), - (9, 10, 5), - ] - ) - ansdict = {1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9} - answer = matching_dict_to_set(ansdict) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nasty_blossom2(self): - """Again but slightly different:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 26), - (5, 7, 40), - (9, 10, 5), - ] - ) - ans = {1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9} - answer = matching_dict_to_set(ans) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nasty_blossom_least_slack(self): - """Create blossom, relabel as T, expand such that a new - least-slack S-to-free dge is produced, augment: - """ - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 28), - (5, 7, 26), - (9, 10, 5), - ] - ) - ans = {1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9} - answer = matching_dict_to_set(ans) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nasty_blossom_augmenting(self): - """Create nested blossom, relabel as T in more than one way""" - # expand outer blossom such that inner blossom ends up on an - # augmenting path: - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 45), - (1, 7, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 95), - (4, 6, 94), - (5, 6, 94), - (6, 7, 50), - (1, 8, 30), - (3, 11, 35), - (5, 9, 36), - (7, 10, 26), - (11, 12, 5), - ] - ) - ans = { - 1: 8, - 2: 3, - 3: 2, - 4: 6, - 5: 9, - 6: 4, - 7: 10, - 8: 1, - 9: 5, - 10: 7, - 11: 12, - 12: 11, - } - answer = matching_dict_to_set(ans) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_nasty_blossom_expand_recursively(self): - """Create nested S-blossom, relabel as S, expand recursively:""" - G = nx.Graph() - G.add_weighted_edges_from( - [ - (1, 2, 40), - (1, 3, 40), - (2, 3, 60), - (2, 4, 55), - (3, 5, 55), - (4, 5, 50), - (1, 8, 15), - (5, 7, 30), - (7, 6, 10), - (8, 10, 10), - (4, 9, 30), - ] - ) - ans = {1: 2, 2: 1, 3: 5, 4: 9, 5: 3, 6: 7, 7: 6, 8: 10, 9: 4, 10: 8} - answer = matching_dict_to_set(ans) - assert edges_equal(nx.max_weight_matching(G), answer) - assert edges_equal(nx.min_weight_matching(G), answer) - - def test_wrong_graph_type(self): - error = nx.NetworkXNotImplemented - raises(error, nx.max_weight_matching, nx.MultiGraph()) - raises(error, nx.max_weight_matching, nx.MultiDiGraph()) - raises(error, nx.max_weight_matching, nx.DiGraph()) - raises(error, nx.min_weight_matching, nx.DiGraph()) - - -class TestIsMatching: - """Unit tests for the - :func:`~networkx.algorithms.matching.is_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_empty_matching(self): - G = nx.path_graph(4) - assert nx.is_matching(G, set()) - - def test_single_edge(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(1, 2)}) - - def test_edge_order(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(0, 1), (2, 3)}) - assert nx.is_matching(G, {(1, 0), (2, 3)}) - assert nx.is_matching(G, {(0, 1), (3, 2)}) - assert nx.is_matching(G, {(1, 0), (3, 2)}) - - def test_valid_matching(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(0, 1), (2, 3)}) - - def test_invalid_input(self): - error = nx.NetworkXError - G = nx.path_graph(4) - # edge to node not in G - raises(error, nx.is_matching, G, {(0, 5), (2, 3)}) - # edge not a 2-tuple - raises(error, nx.is_matching, G, {(0, 1, 2), (2, 3)}) - raises(error, nx.is_matching, G, {(0,), (2, 3)}) - - def test_selfloops(self): - error = nx.NetworkXError - G = nx.path_graph(4) - # selfloop for node not in G - raises(error, nx.is_matching, G, {(5, 5), (2, 3)}) - # selfloop edge not in G - assert not nx.is_matching(G, {(0, 0), (1, 2), (2, 3)}) - # selfloop edge in G - G.add_edge(0, 0) - assert not nx.is_matching(G, {(0, 0), (1, 2)}) - - def test_invalid_matching(self): - G = nx.path_graph(4) - assert not nx.is_matching(G, {(0, 1), (1, 2), (2, 3)}) - - def test_invalid_edge(self): - G = nx.path_graph(4) - assert not nx.is_matching(G, {(0, 3), (1, 2)}) - raises(nx.NetworkXError, nx.is_matching, G, {(0, 55)}) - - G = nx.DiGraph(G.edges) - assert nx.is_matching(G, {(0, 1)}) - assert not nx.is_matching(G, {(1, 0)}) - - -class TestIsMaximalMatching: - """Unit tests for the - :func:`~networkx.algorithms.matching.is_maximal_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_maximal_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_invalid_input(self): - error = nx.NetworkXError - G = nx.path_graph(4) - # edge to node not in G - raises(error, nx.is_maximal_matching, G, {(0, 5)}) - raises(error, nx.is_maximal_matching, G, {(5, 0)}) - # edge not a 2-tuple - raises(error, nx.is_maximal_matching, G, {(0, 1, 2), (2, 3)}) - raises(error, nx.is_maximal_matching, G, {(0,), (2, 3)}) - - def test_valid(self): - G = nx.path_graph(4) - assert nx.is_maximal_matching(G, {(0, 1), (2, 3)}) - - def test_not_matching(self): - G = nx.path_graph(4) - assert not nx.is_maximal_matching(G, {(0, 1), (1, 2), (2, 3)}) - assert not nx.is_maximal_matching(G, {(0, 3)}) - G.add_edge(0, 0) - assert not nx.is_maximal_matching(G, {(0, 0)}) - - def test_not_maximal(self): - G = nx.path_graph(4) - assert not nx.is_maximal_matching(G, {(0, 1)}) - - -class TestIsPerfectMatching: - """Unit tests for the - :func:`~networkx.algorithms.matching.is_perfect_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_perfect_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_valid(self): - G = nx.path_graph(4) - assert nx.is_perfect_matching(G, {(0, 1), (2, 3)}) - - def test_valid_not_path(self): - G = nx.cycle_graph(4) - G.add_edge(0, 4) - G.add_edge(1, 4) - G.add_edge(5, 2) - - assert nx.is_perfect_matching(G, {(1, 4), (0, 3), (5, 2)}) - - def test_invalid_input(self): - error = nx.NetworkXError - G = nx.path_graph(4) - # edge to node not in G - raises(error, nx.is_perfect_matching, G, {(0, 5)}) - raises(error, nx.is_perfect_matching, G, {(5, 0)}) - # edge not a 2-tuple - raises(error, nx.is_perfect_matching, G, {(0, 1, 2), (2, 3)}) - raises(error, nx.is_perfect_matching, G, {(0,), (2, 3)}) - - def test_selfloops(self): - error = nx.NetworkXError - G = nx.path_graph(4) - # selfloop for node not in G - raises(error, nx.is_perfect_matching, G, {(5, 5), (2, 3)}) - # selfloop edge not in G - assert not nx.is_perfect_matching(G, {(0, 0), (1, 2), (2, 3)}) - # selfloop edge in G - G.add_edge(0, 0) - assert not nx.is_perfect_matching(G, {(0, 0), (1, 2)}) - - def test_not_matching(self): - G = nx.path_graph(4) - assert not nx.is_perfect_matching(G, {(0, 3)}) - assert not nx.is_perfect_matching(G, {(0, 1), (1, 2), (2, 3)}) - - def test_maximal_but_not_perfect(self): - G = nx.cycle_graph(4) - G.add_edge(0, 4) - G.add_edge(1, 4) - - assert not nx.is_perfect_matching(G, {(1, 4), (0, 3)}) - - -class TestMaximalMatching: - """Unit tests for the - :func:`~networkx.algorithms.matching.maximal_matching`. - - """ - - def test_valid_matching(self): - edges = [(1, 2), (1, 5), (2, 3), (2, 5), (3, 4), (3, 6), (5, 6)] - G = nx.Graph(edges) - matching = nx.maximal_matching(G) - assert nx.is_maximal_matching(G, matching) - - def test_single_edge_matching(self): - # In the star graph, any maximal matching has just one edge. - G = nx.star_graph(5) - matching = nx.maximal_matching(G) - assert 1 == len(matching) - assert nx.is_maximal_matching(G, matching) - - def test_self_loops(self): - # Create the path graph with two self-loops. - G = nx.path_graph(3) - G.add_edges_from([(0, 0), (1, 1)]) - matching = nx.maximal_matching(G) - assert len(matching) == 1 - # The matching should never include self-loops. - assert not any(u == v for u, v in matching) - assert nx.is_maximal_matching(G, matching) - - def test_ordering(self): - """Tests that a maximal matching is computed correctly - regardless of the order in which nodes are added to the graph. - - """ - for nodes in permutations(range(3)): - G = nx.Graph() - G.add_nodes_from(nodes) - G.add_edges_from([(0, 1), (0, 2)]) - matching = nx.maximal_matching(G) - assert len(matching) == 1 - assert nx.is_maximal_matching(G, matching) - - def test_wrong_graph_type(self): - error = nx.NetworkXNotImplemented - raises(error, nx.maximal_matching, nx.MultiGraph()) - raises(error, nx.maximal_matching, nx.MultiDiGraph()) - raises(error, nx.maximal_matching, nx.DiGraph()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_max_weight_clique.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_max_weight_clique.py deleted file mode 100644 index 6cd8584..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_max_weight_clique.py +++ /dev/null @@ -1,179 +0,0 @@ -"""Maximum weight clique test suite.""" - -import pytest - -import networkx as nx - - -class TestMaximumWeightClique: - def test_basic_cases(self): - def check_basic_case(graph_func, expected_weight, weight_accessor): - graph = graph_func() - clique, weight = nx.algorithms.max_weight_clique(graph, weight_accessor) - assert verify_clique( - graph, clique, weight, expected_weight, weight_accessor - ) - - for graph_func, (expected_weight, expected_size) in TEST_CASES.items(): - check_basic_case(graph_func, expected_weight, "weight") - check_basic_case(graph_func, expected_size, None) - - def test_key_error(self): - graph = two_node_graph() - with pytest.raises(KeyError): - nx.algorithms.max_weight_clique(graph, "nonexistent-key") - - def test_error_on_non_integer_weight(self): - graph = two_node_graph() - graph.nodes[2]["weight"] = 1.5 - with pytest.raises(ValueError): - nx.algorithms.max_weight_clique(graph) - - def test_unaffected_by_self_loops(self): - graph = two_node_graph() - graph.add_edge(1, 1) - graph.add_edge(2, 2) - clique, weight = nx.algorithms.max_weight_clique(graph, "weight") - assert verify_clique(graph, clique, weight, 30, "weight") - graph = three_node_independent_set() - graph.add_edge(1, 1) - clique, weight = nx.algorithms.max_weight_clique(graph, "weight") - assert verify_clique(graph, clique, weight, 20, "weight") - - def test_30_node_prob(self): - G = nx.Graph() - G.add_nodes_from(range(1, 31)) - for i in range(1, 31): - G.nodes[i]["weight"] = i + 1 - # fmt: off - G.add_edges_from( - [ - (1, 12), (1, 13), (1, 15), (1, 16), (1, 18), (1, 19), (1, 20), - (1, 23), (1, 26), (1, 28), (1, 29), (1, 30), (2, 3), (2, 4), - (2, 5), (2, 8), (2, 9), (2, 10), (2, 14), (2, 17), (2, 18), - (2, 21), (2, 22), (2, 23), (2, 27), (3, 9), (3, 15), (3, 21), - (3, 22), (3, 23), (3, 24), (3, 27), (3, 28), (3, 29), (4, 5), - (4, 6), (4, 8), (4, 21), (4, 22), (4, 23), (4, 26), (4, 28), - (4, 30), (5, 6), (5, 8), (5, 9), (5, 13), (5, 14), (5, 15), - (5, 16), (5, 20), (5, 21), (5, 22), (5, 25), (5, 28), (5, 29), - (6, 7), (6, 8), (6, 13), (6, 17), (6, 18), (6, 19), (6, 24), - (6, 26), (6, 27), (6, 28), (6, 29), (7, 12), (7, 14), (7, 15), - (7, 16), (7, 17), (7, 20), (7, 25), (7, 27), (7, 29), (7, 30), - (8, 10), (8, 15), (8, 16), (8, 18), (8, 20), (8, 22), (8, 24), - (8, 26), (8, 27), (8, 28), (8, 30), (9, 11), (9, 12), (9, 13), - (9, 14), (9, 15), (9, 16), (9, 19), (9, 20), (9, 21), (9, 24), - (9, 30), (10, 12), (10, 15), (10, 18), (10, 19), (10, 20), - (10, 22), (10, 23), (10, 24), (10, 26), (10, 27), (10, 29), - (10, 30), (11, 13), (11, 15), (11, 16), (11, 17), (11, 18), - (11, 19), (11, 20), (11, 22), (11, 29), (11, 30), (12, 14), - (12, 17), (12, 18), (12, 19), (12, 20), (12, 21), (12, 23), - (12, 25), (12, 26), (12, 30), (13, 20), (13, 22), (13, 23), - (13, 24), (13, 30), (14, 16), (14, 20), (14, 21), (14, 22), - (14, 23), (14, 25), (14, 26), (14, 27), (14, 29), (14, 30), - (15, 17), (15, 18), (15, 20), (15, 21), (15, 26), (15, 27), - (15, 28), (16, 17), (16, 18), (16, 19), (16, 20), (16, 21), - (16, 29), (16, 30), (17, 18), (17, 21), (17, 22), (17, 25), - (17, 27), (17, 28), (17, 30), (18, 19), (18, 20), (18, 21), - (18, 22), (18, 23), (18, 24), (19, 20), (19, 22), (19, 23), - (19, 24), (19, 25), (19, 27), (19, 30), (20, 21), (20, 23), - (20, 24), (20, 26), (20, 28), (20, 29), (21, 23), (21, 26), - (21, 27), (21, 29), (22, 24), (22, 25), (22, 26), (22, 29), - (23, 25), (23, 30), (24, 25), (24, 26), (25, 27), (25, 29), - (26, 27), (26, 28), (26, 30), (28, 29), (29, 30), - ] - ) - # fmt: on - clique, weight = nx.algorithms.max_weight_clique(G) - assert verify_clique(G, clique, weight, 111, "weight") - - -# ############################ Utility functions ############################ -def verify_clique( - graph, clique, reported_clique_weight, expected_clique_weight, weight_accessor -): - for node1 in clique: - for node2 in clique: - if node1 == node2: - continue - if not graph.has_edge(node1, node2): - return False - - if weight_accessor is None: - clique_weight = len(clique) - else: - clique_weight = sum(graph.nodes[v]["weight"] for v in clique) - - if clique_weight != expected_clique_weight: - return False - if clique_weight != reported_clique_weight: - return False - - return True - - -# ############################ Graph Generation ############################ - - -def empty_graph(): - return nx.Graph() - - -def one_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1]) - graph.nodes[1]["weight"] = 10 - return graph - - -def two_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1, 2]) - graph.add_edges_from([(1, 2)]) - graph.nodes[1]["weight"] = 10 - graph.nodes[2]["weight"] = 20 - return graph - - -def three_node_clique(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.add_edges_from([(1, 2), (1, 3), (2, 3)]) - graph.nodes[1]["weight"] = 10 - graph.nodes[2]["weight"] = 20 - graph.nodes[3]["weight"] = 5 - return graph - - -def three_node_independent_set(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.nodes[1]["weight"] = 10 - graph.nodes[2]["weight"] = 20 - graph.nodes[3]["weight"] = 5 - return graph - - -def disconnected(): - graph = nx.Graph() - graph.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6)]) - graph.nodes[1]["weight"] = 10 - graph.nodes[2]["weight"] = 20 - graph.nodes[3]["weight"] = 5 - graph.nodes[4]["weight"] = 100 - graph.nodes[5]["weight"] = 200 - graph.nodes[6]["weight"] = 50 - return graph - - -# -------------------------------------------------------------------------- -# Basic tests for all strategies -# For each basic graph function, specify expected weight of max weight clique -# and expected size of maximum clique -TEST_CASES = { - empty_graph: (0, 0), - one_node_graph: (10, 1), - two_node_graph: (30, 2), - three_node_clique: (35, 3), - three_node_independent_set: (20, 1), - disconnected: (300, 2), -} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_mis.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_mis.py deleted file mode 100644 index 02be02d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_mis.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Tests for maximal (not maximum) independent sets. - -""" - -import random - -import pytest - -import networkx as nx - - -def test_random_seed(): - G = nx.empty_graph(5) - assert nx.maximal_independent_set(G, seed=1) == [1, 0, 3, 2, 4] - - -@pytest.mark.parametrize("graph", [nx.complete_graph(5), nx.complete_graph(55)]) -def test_K5(graph): - """Maximal independent set for complete graphs""" - assert all(nx.maximal_independent_set(graph, [n]) == [n] for n in graph) - - -def test_exceptions(): - """Bad input should raise exception.""" - G = nx.florentine_families_graph() - pytest.raises(nx.NetworkXUnfeasible, nx.maximal_independent_set, G, ["Smith"]) - pytest.raises( - nx.NetworkXUnfeasible, nx.maximal_independent_set, G, ["Salviati", "Pazzi"] - ) - # MaximalIndependentSet is not implemented for directed graphs - pytest.raises(nx.NetworkXNotImplemented, nx.maximal_independent_set, nx.DiGraph(G)) - - -def test_florentine_family(): - G = nx.florentine_families_graph() - indep = nx.maximal_independent_set(G, ["Medici", "Bischeri"]) - assert set(indep) == { - "Medici", - "Bischeri", - "Castellani", - "Pazzi", - "Ginori", - "Lamberteschi", - } - - -def test_bipartite(): - G = nx.complete_bipartite_graph(12, 34) - indep = nx.maximal_independent_set(G, [4, 5, 9, 10]) - assert sorted(indep) == list(range(12)) - - -def test_random_graphs(): - """Generate 5 random graphs of different types and sizes and - make sure that all sets are independent and maximal.""" - for i in range(0, 50, 10): - G = nx.erdos_renyi_graph(i * 10 + 1, random.random()) - IS = nx.maximal_independent_set(G) - assert G.subgraph(IS).number_of_edges() == 0 - nbrs_of_MIS = set.union(*(set(G.neighbors(v)) for v in IS)) - assert all(v in nbrs_of_MIS for v in set(G.nodes()).difference(IS)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_moral.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_moral.py deleted file mode 100644 index fc98c97..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_moral.py +++ /dev/null @@ -1,15 +0,0 @@ -import networkx as nx -from networkx.algorithms.moral import moral_graph - - -def test_get_moral_graph(): - graph = nx.DiGraph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([(1, 2), (3, 2), (4, 1), (4, 5), (6, 5), (7, 5)]) - H = moral_graph(graph) - assert not H.is_directed() - assert H.has_edge(1, 3) - assert H.has_edge(4, 6) - assert H.has_edge(6, 7) - assert H.has_edge(4, 7) - assert not H.has_edge(1, 5) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_node_classification.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_node_classification.py deleted file mode 100644 index 2e1fc79..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_node_classification.py +++ /dev/null @@ -1,140 +0,0 @@ -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.algorithms import node_classification - - -class TestHarmonicFunction: - def test_path_graph(self): - G = nx.path_graph(4) - label_name = "label" - G.nodes[0][label_name] = "A" - G.nodes[3][label_name] = "B" - predicted = node_classification.harmonic_function(G, label_name=label_name) - assert predicted[0] == "A" - assert predicted[1] == "A" - assert predicted[2] == "B" - assert predicted[3] == "B" - - def test_no_labels(self): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - node_classification.harmonic_function(G) - - def test_no_nodes(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - node_classification.harmonic_function(G) - - def test_no_edges(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - node_classification.harmonic_function(G) - - def test_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(1, 2) - G.add_edge(2, 3) - label_name = "label" - G.nodes[0][label_name] = "A" - G.nodes[3][label_name] = "B" - node_classification.harmonic_function(G) - - def test_one_labeled_node(self): - G = nx.path_graph(4) - label_name = "label" - G.nodes[0][label_name] = "A" - predicted = node_classification.harmonic_function(G, label_name=label_name) - assert predicted[0] == "A" - assert predicted[1] == "A" - assert predicted[2] == "A" - assert predicted[3] == "A" - - def test_nodes_all_labeled(self): - G = nx.karate_club_graph() - label_name = "club" - predicted = node_classification.harmonic_function(G, label_name=label_name) - for i in range(len(G)): - assert predicted[i] == G.nodes[i][label_name] - - def test_labeled_nodes_are_not_changed(self): - G = nx.karate_club_graph() - label_name = "club" - label_removed = {0, 1, 2, 3, 4, 5, 6, 7} - for i in label_removed: - del G.nodes[i][label_name] - predicted = node_classification.harmonic_function(G, label_name=label_name) - label_not_removed = set(range(len(G))) - label_removed - for i in label_not_removed: - assert predicted[i] == G.nodes[i][label_name] - - -class TestLocalAndGlobalConsistency: - def test_path_graph(self): - G = nx.path_graph(4) - label_name = "label" - G.nodes[0][label_name] = "A" - G.nodes[3][label_name] = "B" - predicted = node_classification.local_and_global_consistency( - G, label_name=label_name - ) - assert predicted[0] == "A" - assert predicted[1] == "A" - assert predicted[2] == "B" - assert predicted[3] == "B" - - def test_no_labels(self): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - node_classification.local_and_global_consistency(G) - - def test_no_nodes(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - node_classification.local_and_global_consistency(G) - - def test_no_edges(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - node_classification.local_and_global_consistency(G) - - def test_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(1, 2) - G.add_edge(2, 3) - label_name = "label" - G.nodes[0][label_name] = "A" - G.nodes[3][label_name] = "B" - node_classification.harmonic_function(G) - - def test_one_labeled_node(self): - G = nx.path_graph(4) - label_name = "label" - G.nodes[0][label_name] = "A" - predicted = node_classification.local_and_global_consistency( - G, label_name=label_name - ) - assert predicted[0] == "A" - assert predicted[1] == "A" - assert predicted[2] == "A" - assert predicted[3] == "A" - - def test_nodes_all_labeled(self): - G = nx.karate_club_graph() - label_name = "club" - predicted = node_classification.local_and_global_consistency( - G, alpha=0, label_name=label_name - ) - for i in range(len(G)): - assert predicted[i] == G.nodes[i][label_name] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_non_randomness.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_non_randomness.py deleted file mode 100644 index 2f495be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_non_randomness.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest - -import networkx as nx - -np = pytest.importorskip("numpy") - - -@pytest.mark.parametrize( - "k, weight, expected", - [ - (None, None, 7.21), # infers 3 communities - (2, None, 11.7), - (None, "weight", 25.45), - (2, "weight", 38.8), - ], -) -def test_non_randomness(k, weight, expected): - G = nx.karate_club_graph() - np.testing.assert_almost_equal( - nx.non_randomness(G, k, weight)[0], expected, decimal=2 - ) - - -def test_non_connected(): - G = nx.Graph([(1, 2)]) - G.add_node(3) - with pytest.raises(nx.NetworkXException, match="Non connected"): - nx.non_randomness(G) - - -def test_self_loops(): - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(1, 1) - with pytest.raises(nx.NetworkXError, match="Graph must not contain self-loops"): - nx.non_randomness(G) - - -def test_empty_graph(): - G = nx.empty_graph(1) - with pytest.raises(nx.NetworkXError, match=".*not applicable to empty graphs"): - nx.non_randomness(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planar_drawing.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planar_drawing.py deleted file mode 100644 index a5de0e0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planar_drawing.py +++ /dev/null @@ -1,274 +0,0 @@ -import math - -import pytest - -import networkx as nx -from networkx.algorithms.planar_drawing import triangulate_embedding - - -def test_graph1(): - embedding_data = {0: [1, 2, 3], 1: [2, 0], 2: [3, 0, 1], 3: [2, 0]} - check_embedding_data(embedding_data) - - -def test_graph2(): - embedding_data = { - 0: [8, 6], - 1: [2, 6, 9], - 2: [8, 1, 7, 9, 6, 4], - 3: [9], - 4: [2], - 5: [6, 8], - 6: [9, 1, 0, 5, 2], - 7: [9, 2], - 8: [0, 2, 5], - 9: [1, 6, 2, 7, 3], - } - check_embedding_data(embedding_data) - - -def test_circle_graph(): - embedding_data = { - 0: [1, 9], - 1: [0, 2], - 2: [1, 3], - 3: [2, 4], - 4: [3, 5], - 5: [4, 6], - 6: [5, 7], - 7: [6, 8], - 8: [7, 9], - 9: [8, 0], - } - check_embedding_data(embedding_data) - - -def test_grid_graph(): - embedding_data = { - (0, 1): [(0, 0), (1, 1), (0, 2)], - (1, 2): [(1, 1), (2, 2), (0, 2)], - (0, 0): [(0, 1), (1, 0)], - (2, 1): [(2, 0), (2, 2), (1, 1)], - (1, 1): [(2, 1), (1, 2), (0, 1), (1, 0)], - (2, 0): [(1, 0), (2, 1)], - (2, 2): [(1, 2), (2, 1)], - (1, 0): [(0, 0), (2, 0), (1, 1)], - (0, 2): [(1, 2), (0, 1)], - } - check_embedding_data(embedding_data) - - -def test_one_node_graph(): - embedding_data = {0: []} - check_embedding_data(embedding_data) - - -def test_two_node_graph(): - embedding_data = {0: [1], 1: [0]} - check_embedding_data(embedding_data) - - -def test_three_node_graph(): - embedding_data = {0: [1, 2], 1: [0, 2], 2: [0, 1]} - check_embedding_data(embedding_data) - - -def test_multiple_component_graph1(): - embedding_data = {0: [], 1: []} - check_embedding_data(embedding_data) - - -def test_multiple_component_graph2(): - embedding_data = {0: [1, 2], 1: [0, 2], 2: [0, 1], 3: [4, 5], 4: [3, 5], 5: [3, 4]} - check_embedding_data(embedding_data) - - -def test_invalid_half_edge(): - with pytest.raises(nx.NetworkXException): - embedding_data = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} - embedding = nx.PlanarEmbedding() - embedding.set_data(embedding_data) - nx.combinatorial_embedding_to_pos(embedding) - - -def test_triangulate_embedding1(): - embedding = nx.PlanarEmbedding() - embedding.add_node(1) - expected_embedding = {1: []} - check_triangulation(embedding, expected_embedding) - - -def test_triangulate_embedding2(): - embedding = nx.PlanarEmbedding() - embedding.connect_components(1, 2) - expected_embedding = {1: [2], 2: [1]} - check_triangulation(embedding, expected_embedding) - - -def check_triangulation(embedding, expected_embedding): - res_embedding, _ = triangulate_embedding(embedding, True) - assert ( - res_embedding.get_data() == expected_embedding - ), "Expected embedding incorrect" - res_embedding, _ = triangulate_embedding(embedding, False) - assert ( - res_embedding.get_data() == expected_embedding - ), "Expected embedding incorrect" - - -def check_embedding_data(embedding_data): - """Checks that the planar embedding of the input is correct""" - embedding = nx.PlanarEmbedding() - embedding.set_data(embedding_data) - pos_fully = nx.combinatorial_embedding_to_pos(embedding, False) - msg = "Planar drawing does not conform to the embedding (fully triangulation)" - assert planar_drawing_conforms_to_embedding(embedding, pos_fully), msg - check_edge_intersections(embedding, pos_fully) - pos_internally = nx.combinatorial_embedding_to_pos(embedding, True) - msg = "Planar drawing does not conform to the embedding (internal triangulation)" - assert planar_drawing_conforms_to_embedding(embedding, pos_internally), msg - check_edge_intersections(embedding, pos_internally) - - -def is_close(a, b, rel_tol=1e-09, abs_tol=0.0): - # Check if float numbers are basically equal, for python >=3.5 there is - # function for that in the standard library - return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) - - -def point_in_between(a, b, p): - # checks if p is on the line between a and b - x1, y1 = a - x2, y2 = b - px, py = p - dist_1_2 = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) - dist_1_p = math.sqrt((x1 - px) ** 2 + (y1 - py) ** 2) - dist_2_p = math.sqrt((x2 - px) ** 2 + (y2 - py) ** 2) - return is_close(dist_1_p + dist_2_p, dist_1_2) - - -def check_edge_intersections(G, pos): - """Check all edges in G for intersections. - - Raises an exception if an intersection is found. - - Parameters - ---------- - G : NetworkX graph - pos : dict - Maps every node to a tuple (x, y) representing its position - - """ - for a, b in G.edges(): - for c, d in G.edges(): - # Check if end points are different - if a != c and b != d and b != c and a != d: - x1, y1 = pos[a] - x2, y2 = pos[b] - x3, y3 = pos[c] - x4, y4 = pos[d] - determinant = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) - if determinant != 0: # the lines are not parallel - # calculate intersection point, see: - # https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection - px = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * ( - x3 * y4 - y3 * x4 - ) / determinant - py = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * ( - x3 * y4 - y3 * x4 - ) / determinant - - # Check if intersection lies between the points - if point_in_between(pos[a], pos[b], (px, py)) and point_in_between( - pos[c], pos[d], (px, py) - ): - msg = f"There is an intersection at {px},{py}" - raise nx.NetworkXException(msg) - - # Check overlap - msg = "A node lies on a edge connecting two other nodes" - if ( - point_in_between(pos[a], pos[b], pos[c]) - or point_in_between(pos[a], pos[b], pos[d]) - or point_in_between(pos[c], pos[d], pos[a]) - or point_in_between(pos[c], pos[d], pos[b]) - ): - raise nx.NetworkXException(msg) - # No edge intersection found - - -class Vector: - """Compare vectors by their angle without loss of precision - - All vectors in direction [0, 1] are the smallest. - The vectors grow in clockwise direction. - """ - - __slots__ = ["x", "y", "node", "quadrant"] - - def __init__(self, x, y, node): - self.x = x - self.y = y - self.node = node - if self.x >= 0 and self.y > 0: - self.quadrant = 1 - elif self.x > 0 and self.y <= 0: - self.quadrant = 2 - elif self.x <= 0 and self.y < 0: - self.quadrant = 3 - else: - self.quadrant = 4 - - def __eq__(self, other): - return self.quadrant == other.quadrant and self.x * other.y == self.y * other.x - - def __lt__(self, other): - if self.quadrant < other.quadrant: - return True - elif self.quadrant > other.quadrant: - return False - else: - return self.x * other.y < self.y * other.x - - def __ne__(self, other): - return self != other - - def __le__(self, other): - return not other < self - - def __gt__(self, other): - return other < self - - def __ge__(self, other): - return not self < other - - -def planar_drawing_conforms_to_embedding(embedding, pos): - """Checks if pos conforms to the planar embedding - - Returns true iff the neighbors are actually oriented in the orientation - specified of the embedding - """ - for v in embedding: - nbr_vectors = [] - v_pos = pos[v] - for nbr in embedding[v]: - new_vector = Vector(pos[nbr][0] - v_pos[0], pos[nbr][1] - v_pos[1], nbr) - nbr_vectors.append(new_vector) - # Sort neighbors according to their phi angle - nbr_vectors.sort() - for idx, nbr_vector in enumerate(nbr_vectors): - cw_vector = nbr_vectors[(idx + 1) % len(nbr_vectors)] - ccw_vector = nbr_vectors[idx - 1] - if ( - embedding[v][nbr_vector.node]["cw"] != cw_vector.node - or embedding[v][nbr_vector.node]["ccw"] != ccw_vector.node - ): - return False - if cw_vector.node != nbr_vector.node and cw_vector == nbr_vector: - # Lines overlap - return False - if ccw_vector.node != nbr_vector.node and ccw_vector == nbr_vector: - # Lines overlap - return False - return True diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planarity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planarity.py deleted file mode 100644 index 99bcff4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_planarity.py +++ /dev/null @@ -1,535 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.planarity import ( - check_planarity_recursive, - get_counterexample, - get_counterexample_recursive, -) - - -class TestLRPlanarity: - """Nose Unit tests for the :mod:`networkx.algorithms.planarity` module. - - Tests three things: - 1. Check that the result is correct - (returns planar if and only if the graph is actually planar) - 2. In case a counter example is returned: Check if it is correct - 3. In case an embedding is returned: Check if its actually an embedding - """ - - @staticmethod - def check_graph(G, is_planar=None): - """Raises an exception if the lr_planarity check returns a wrong result - - Parameters - ---------- - G : NetworkX graph - is_planar : bool - The expected result of the planarity check. - If set to None only counter example or embedding are verified. - - """ - - # obtain results of planarity check - is_planar_lr, result = nx.check_planarity(G, True) - is_planar_lr_rec, result_rec = check_planarity_recursive(G, True) - - if is_planar is not None: - # set a message for the assert - if is_planar: - msg = "Wrong planarity check result. Should be planar." - else: - msg = "Wrong planarity check result. Should be non-planar." - - # check if the result is as expected - assert is_planar == is_planar_lr, msg - assert is_planar == is_planar_lr_rec, msg - - if is_planar_lr: - # check embedding - check_embedding(G, result) - check_embedding(G, result_rec) - else: - # check counter example - check_counterexample(G, result) - check_counterexample(G, result_rec) - - def test_simple_planar_graph(self): - e = [ - (1, 2), - (2, 3), - (3, 4), - (4, 6), - (6, 7), - (7, 1), - (1, 5), - (5, 2), - (2, 4), - (4, 5), - (5, 7), - ] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_planar_with_selfloop(self): - e = [ - (1, 1), - (2, 2), - (3, 3), - (4, 4), - (5, 5), - (1, 2), - (1, 3), - (1, 5), - (2, 5), - (2, 4), - (3, 4), - (3, 5), - (4, 5), - ] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_k3_3(self): - self.check_graph(nx.complete_bipartite_graph(3, 3), is_planar=False) - - def test_k5(self): - self.check_graph(nx.complete_graph(5), is_planar=False) - - def test_multiple_components_planar(self): - e = [(1, 2), (2, 3), (3, 1), (4, 5), (5, 6), (6, 4)] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_multiple_components_non_planar(self): - G = nx.complete_graph(5) - # add another planar component to the non planar component - # G stays non planar - G.add_edges_from([(6, 7), (7, 8), (8, 6)]) - self.check_graph(G, is_planar=False) - - def test_non_planar_with_selfloop(self): - G = nx.complete_graph(5) - # add self loops - for i in range(5): - G.add_edge(i, i) - self.check_graph(G, is_planar=False) - - def test_non_planar1(self): - # tests a graph that has no subgraph directly isomorph to K5 or K3_3 - e = [ - (1, 5), - (1, 6), - (1, 7), - (2, 6), - (2, 3), - (3, 5), - (3, 7), - (4, 5), - (4, 6), - (4, 7), - ] - self.check_graph(nx.Graph(e), is_planar=False) - - def test_loop(self): - # test a graph with a selfloop - e = [(1, 2), (2, 2)] - G = nx.Graph(e) - self.check_graph(G, is_planar=True) - - def test_comp(self): - # test multiple component graph - e = [(1, 2), (3, 4)] - G = nx.Graph(e) - G.remove_edge(1, 2) - self.check_graph(G, is_planar=True) - - def test_goldner_harary(self): - # test goldner-harary graph (a maximal planar graph) - e = [ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (1, 7), - (1, 8), - (1, 10), - (1, 11), - (2, 3), - (2, 4), - (2, 6), - (2, 7), - (2, 9), - (2, 10), - (2, 11), - (3, 4), - (4, 5), - (4, 6), - (4, 7), - (5, 7), - (6, 7), - (7, 8), - (7, 9), - (7, 10), - (8, 10), - (9, 10), - (10, 11), - ] - G = nx.Graph(e) - self.check_graph(G, is_planar=True) - - def test_planar_multigraph(self): - G = nx.MultiGraph([(1, 2), (1, 2), (1, 2), (1, 2), (2, 3), (3, 1)]) - self.check_graph(G, is_planar=True) - - def test_non_planar_multigraph(self): - G = nx.MultiGraph(nx.complete_graph(5)) - G.add_edges_from([(1, 2)] * 5) - self.check_graph(G, is_planar=False) - - def test_planar_digraph(self): - G = nx.DiGraph([(1, 2), (2, 3), (2, 4), (4, 1), (4, 2), (1, 4), (3, 2)]) - self.check_graph(G, is_planar=True) - - def test_non_planar_digraph(self): - G = nx.DiGraph(nx.complete_graph(5)) - G.remove_edge(1, 2) - G.remove_edge(4, 1) - self.check_graph(G, is_planar=False) - - def test_single_component(self): - # Test a graph with only a single node - G = nx.Graph() - G.add_node(1) - self.check_graph(G, is_planar=True) - - def test_graph1(self): - G = nx.Graph( - [ - (3, 10), - (2, 13), - (1, 13), - (7, 11), - (0, 8), - (8, 13), - (0, 2), - (0, 7), - (0, 10), - (1, 7), - ] - ) - self.check_graph(G, is_planar=True) - - def test_graph2(self): - G = nx.Graph( - [ - (1, 2), - (4, 13), - (0, 13), - (4, 5), - (7, 10), - (1, 7), - (0, 3), - (2, 6), - (5, 6), - (7, 13), - (4, 8), - (0, 8), - (0, 9), - (2, 13), - (6, 7), - (3, 6), - (2, 8), - ] - ) - self.check_graph(G, is_planar=False) - - def test_graph3(self): - G = nx.Graph( - [ - (0, 7), - (3, 11), - (3, 4), - (8, 9), - (4, 11), - (1, 7), - (1, 13), - (1, 11), - (3, 5), - (5, 7), - (1, 3), - (0, 4), - (5, 11), - (5, 13), - ] - ) - self.check_graph(G, is_planar=False) - - def test_counterexample_planar(self): - with pytest.raises(nx.NetworkXException): - # Try to get a counterexample of a planar graph - G = nx.Graph() - G.add_node(1) - get_counterexample(G) - - def test_counterexample_planar_recursive(self): - with pytest.raises(nx.NetworkXException): - # Try to get a counterexample of a planar graph - G = nx.Graph() - G.add_node(1) - get_counterexample_recursive(G) - - def test_edge_removal_from_planar_embedding(self): - # PlanarEmbedding.check_structure() must succeed after edge removal - edges = ((0, 1), (1, 2), (2, 3), (3, 4), (4, 0), (0, 2), (0, 3)) - G = nx.Graph(edges) - cert, P = nx.check_planarity(G) - assert cert is True - P.remove_edge(0, 2) - self.check_graph(P, is_planar=True) - P.add_half_edge_ccw(1, 3, 2) - P.add_half_edge_cw(3, 1, 2) - self.check_graph(P, is_planar=True) - P.remove_edges_from(((0, 3), (1, 3))) - self.check_graph(P, is_planar=True) - - -def check_embedding(G, embedding): - """Raises an exception if the combinatorial embedding is not correct - - Parameters - ---------- - G : NetworkX graph - embedding : a dict mapping nodes to a list of edges - This specifies the ordering of the outgoing edges from a node for - a combinatorial embedding - - Notes - ----- - Checks the following things: - - The type of the embedding is correct - - The nodes and edges match the original graph - - Every half edge has its matching opposite half edge - - No intersections of edges (checked by Euler's formula) - """ - - if not isinstance(embedding, nx.PlanarEmbedding): - raise nx.NetworkXException("Bad embedding. Not of type nx.PlanarEmbedding") - - # Check structure - embedding.check_structure() - - # Check that graphs are equivalent - - assert set(G.nodes) == set( - embedding.nodes - ), "Bad embedding. Nodes don't match the original graph." - - # Check that the edges are equal - g_edges = set() - for edge in G.edges: - if edge[0] != edge[1]: - g_edges.add((edge[0], edge[1])) - g_edges.add((edge[1], edge[0])) - assert g_edges == set( - embedding.edges - ), "Bad embedding. Edges don't match the original graph." - - -def check_counterexample(G, sub_graph): - """Raises an exception if the counterexample is wrong. - - Parameters - ---------- - G : NetworkX graph - subdivision_nodes : set - A set of nodes inducing a subgraph as a counterexample - """ - # 1. Create the sub graph - sub_graph = nx.Graph(sub_graph) - - # 2. Remove self loops - for u in sub_graph: - if sub_graph.has_edge(u, u): - sub_graph.remove_edge(u, u) - - # keep track of nodes we might need to contract - contract = list(sub_graph) - - # 3. Contract Edges - while len(contract) > 0: - contract_node = contract.pop() - if contract_node not in sub_graph: - # Node was already contracted - continue - degree = sub_graph.degree[contract_node] - # Check if we can remove the node - if degree == 2: - # Get the two neighbors - neighbors = iter(sub_graph[contract_node]) - u = next(neighbors) - v = next(neighbors) - # Save nodes for later - contract.append(u) - contract.append(v) - # Contract edge - sub_graph.remove_node(contract_node) - sub_graph.add_edge(u, v) - - # 4. Check for isomorphism with K5 or K3_3 graphs - if len(sub_graph) == 5: - if not nx.is_isomorphic(nx.complete_graph(5), sub_graph): - raise nx.NetworkXException("Bad counter example.") - elif len(sub_graph) == 6: - if not nx.is_isomorphic(nx.complete_bipartite_graph(3, 3), sub_graph): - raise nx.NetworkXException("Bad counter example.") - else: - raise nx.NetworkXException("Bad counter example.") - - -class TestPlanarEmbeddingClass: - def test_add_half_edge(self): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge(0, 1) - with pytest.raises( - nx.NetworkXException, match="Invalid clockwise reference node." - ): - embedding.add_half_edge(0, 2, cw=3) - with pytest.raises( - nx.NetworkXException, match="Invalid counterclockwise reference node." - ): - embedding.add_half_edge(0, 2, ccw=3) - with pytest.raises( - nx.NetworkXException, match="Only one of cw/ccw can be specified." - ): - embedding.add_half_edge(0, 2, cw=1, ccw=1) - with pytest.raises( - nx.NetworkXException, - match=( - r"Node already has out-half-edge\(s\), either" - " cw or ccw reference node required." - ), - ): - embedding.add_half_edge(0, 2) - # these should work - embedding.add_half_edge(0, 2, cw=1) - embedding.add_half_edge(0, 3, ccw=1) - assert sorted(embedding.edges(data=True)) == [ - (0, 1, {"ccw": 2, "cw": 3}), - (0, 2, {"cw": 1, "ccw": 3}), - (0, 3, {"cw": 2, "ccw": 1}), - ] - - def test_get_data(self): - embedding = self.get_star_embedding(4) - data = embedding.get_data() - data_cmp = {0: [3, 2, 1], 1: [0], 2: [0], 3: [0]} - assert data == data_cmp - - def test_edge_removal(self): - embedding = nx.PlanarEmbedding() - embedding.set_data( - { - 1: [2, 5, 7], - 2: [1, 3, 4, 5], - 3: [2, 4], - 4: [3, 6, 5, 2], - 5: [7, 1, 2, 4], - 6: [4, 7], - 7: [6, 1, 5], - } - ) - # remove_edges_from() calls remove_edge(), so both are tested here - embedding.remove_edges_from(((5, 4), (1, 5))) - embedding.check_structure() - embedding_expected = nx.PlanarEmbedding() - embedding_expected.set_data( - { - 1: [2, 7], - 2: [1, 3, 4, 5], - 3: [2, 4], - 4: [3, 6, 2], - 5: [7, 2], - 6: [4, 7], - 7: [6, 1, 5], - } - ) - assert nx.utils.graphs_equal(embedding, embedding_expected) - - def test_missing_edge_orientation(self): - embedding = nx.PlanarEmbedding({1: {2: {}}, 2: {1: {}}}) - with pytest.raises(nx.NetworkXException): - # Invalid structure because the orientation of the edge was not set - embedding.check_structure() - - def test_invalid_edge_orientation(self): - embedding = nx.PlanarEmbedding( - { - 1: {2: {"cw": 2, "ccw": 2}}, - 2: {1: {"cw": 1, "ccw": 1}}, - 1: {3: {}}, - 3: {1: {}}, - } - ) - with pytest.raises(nx.NetworkXException): - embedding.check_structure() - - def test_missing_half_edge(self): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge(1, 2) - with pytest.raises(nx.NetworkXException): - # Invalid structure because other half edge is missing - embedding.check_structure() - - def test_not_fulfilling_euler_formula(self): - embedding = nx.PlanarEmbedding() - for i in range(5): - ref = None - for j in range(5): - if i != j: - embedding.add_half_edge(i, j, cw=ref) - ref = j - with pytest.raises(nx.NetworkXException): - embedding.check_structure() - - def test_missing_reference(self): - embedding = nx.PlanarEmbedding() - with pytest.raises(nx.NetworkXException, match="Invalid reference node."): - embedding.add_half_edge(1, 2, ccw=3) - - def test_connect_components(self): - embedding = nx.PlanarEmbedding() - embedding.connect_components(1, 2) - - def test_successful_face_traversal(self): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge(1, 2) - embedding.add_half_edge(2, 1) - face = embedding.traverse_face(1, 2) - assert face == [1, 2] - - def test_unsuccessful_face_traversal(self): - embedding = nx.PlanarEmbedding( - {1: {2: {"cw": 3, "ccw": 2}}, 2: {1: {"cw": 3, "ccw": 1}}} - ) - with pytest.raises(nx.NetworkXException): - embedding.traverse_face(1, 2) - - def test_forbidden_methods(self): - embedding = nx.PlanarEmbedding() - embedding.add_node(42) # no exception - embedding.add_nodes_from([(23, 24)]) # no exception - with pytest.raises(NotImplementedError): - embedding.add_edge(1, 3) - with pytest.raises(NotImplementedError): - embedding.add_edges_from([(0, 2), (1, 4)]) - with pytest.raises(NotImplementedError): - embedding.add_weighted_edges_from([(0, 2, 350), (1, 4, 125)]) - - @staticmethod - def get_star_embedding(n): - embedding = nx.PlanarEmbedding() - ref = None - for i in range(1, n): - embedding.add_half_edge(0, i, cw=ref) - ref = i - embedding.add_half_edge(i, 0) - return embedding diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_polynomials.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_polynomials.py deleted file mode 100644 index a81d6a6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_polynomials.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.polynomials` module.""" - -import pytest - -import networkx as nx - -sympy = pytest.importorskip("sympy") - - -# Mapping of input graphs to a string representation of their tutte polynomials -_test_tutte_graphs = { - nx.complete_graph(1): "1", - nx.complete_graph(4): "x**3 + 3*x**2 + 4*x*y + 2*x + y**3 + 3*y**2 + 2*y", - nx.cycle_graph(5): "x**4 + x**3 + x**2 + x + y", - nx.diamond_graph(): "x**3 + 2*x**2 + 2*x*y + x + y**2 + y", -} - -_test_chromatic_graphs = { - nx.complete_graph(1): "x", - nx.complete_graph(4): "x**4 - 6*x**3 + 11*x**2 - 6*x", - nx.cycle_graph(5): "x**5 - 5*x**4 + 10*x**3 - 10*x**2 + 4*x", - nx.diamond_graph(): "x**4 - 5*x**3 + 8*x**2 - 4*x", - nx.path_graph(5): "x**5 - 4*x**4 + 6*x**3 - 4*x**2 + x", -} - - -@pytest.mark.parametrize(("G", "expected"), _test_tutte_graphs.items()) -def test_tutte_polynomial(G, expected): - assert nx.tutte_polynomial(G).equals(expected) - - -@pytest.mark.parametrize("G", _test_tutte_graphs.keys()) -def test_tutte_polynomial_disjoint(G): - """Tutte polynomial factors into the Tutte polynomials of its components. - Verify this property with the disjoint union of two copies of the input graph. - """ - t_g = nx.tutte_polynomial(G) - H = nx.disjoint_union(G, G) - t_h = nx.tutte_polynomial(H) - assert sympy.simplify(t_g * t_g).equals(t_h) - - -@pytest.mark.parametrize(("G", "expected"), _test_chromatic_graphs.items()) -def test_chromatic_polynomial(G, expected): - assert nx.chromatic_polynomial(G).equals(expected) - - -@pytest.mark.parametrize("G", _test_chromatic_graphs.keys()) -def test_chromatic_polynomial_disjoint(G): - """Chromatic polynomial factors into the Chromatic polynomials of its - components. Verify this property with the disjoint union of two copies of - the input graph. - """ - x_g = nx.chromatic_polynomial(G) - H = nx.disjoint_union(G, G) - x_h = nx.chromatic_polynomial(H) - assert sympy.simplify(x_g * x_g).equals(x_h) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_reciprocity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_reciprocity.py deleted file mode 100644 index e713bc4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_reciprocity.py +++ /dev/null @@ -1,37 +0,0 @@ -import pytest - -import networkx as nx - - -class TestReciprocity: - # test overall reciprocity by passing whole graph - def test_reciprocity_digraph(self): - DG = nx.DiGraph([(1, 2), (2, 1)]) - reciprocity = nx.reciprocity(DG) - assert reciprocity == 1.0 - - # test empty graph's overall reciprocity which will throw an error - def test_overall_reciprocity_empty_graph(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph() - nx.overall_reciprocity(DG) - - # test for reciprocity for a list of nodes - def test_reciprocity_graph_nodes(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 2)]) - reciprocity = nx.reciprocity(DG, [1, 2]) - expected_reciprocity = {1: 0.0, 2: 0.6666666666666666} - assert reciprocity == expected_reciprocity - - # test for reciprocity for a single node - def test_reciprocity_graph_node(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 2)]) - reciprocity = nx.reciprocity(DG, 2) - assert reciprocity == 0.6666666666666666 - - # test for reciprocity for an isolated node - def test_reciprocity_graph_isolated_nodes(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph([(1, 2)]) - DG.add_node(4) - nx.reciprocity(DG, 4) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_regular.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_regular.py deleted file mode 100644 index a8b4c3a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_regular.py +++ /dev/null @@ -1,92 +0,0 @@ -import pytest - -import networkx -import networkx as nx -import networkx.algorithms.regular as reg -import networkx.generators as gen - - -class TestKFactor: - def test_k_factor_trivial(self): - g = gen.cycle_graph(4) - f = reg.k_factor(g, 2) - assert g.edges == f.edges - - def test_k_factor1(self): - g = gen.grid_2d_graph(4, 4) - g_kf = reg.k_factor(g, 2) - for edge in g_kf.edges(): - assert g.has_edge(edge[0], edge[1]) - for _, degree in g_kf.degree(): - assert degree == 2 - - def test_k_factor2(self): - g = gen.complete_graph(6) - g_kf = reg.k_factor(g, 3) - for edge in g_kf.edges(): - assert g.has_edge(edge[0], edge[1]) - for _, degree in g_kf.degree(): - assert degree == 3 - - def test_k_factor3(self): - g = gen.grid_2d_graph(4, 4) - with pytest.raises(nx.NetworkXUnfeasible): - reg.k_factor(g, 3) - - def test_k_factor4(self): - g = gen.lattice.hexagonal_lattice_graph(4, 4) - # Perfect matching doesn't exist for 4,4 hexagonal lattice graph - with pytest.raises(nx.NetworkXUnfeasible): - reg.k_factor(g, 2) - - def test_k_factor5(self): - g = gen.complete_graph(6) - # small k to exercise SmallKGadget - g_kf = reg.k_factor(g, 2) - for edge in g_kf.edges(): - assert g.has_edge(edge[0], edge[1]) - for _, degree in g_kf.degree(): - assert degree == 2 - - -class TestIsRegular: - def test_is_regular1(self): - g = gen.cycle_graph(4) - assert reg.is_regular(g) - - def test_is_regular2(self): - g = gen.complete_graph(5) - assert reg.is_regular(g) - - def test_is_regular3(self): - g = gen.lollipop_graph(5, 5) - assert not reg.is_regular(g) - - def test_is_regular4(self): - g = nx.DiGraph() - g.add_edges_from([(0, 1), (1, 2), (2, 0)]) - assert reg.is_regular(g) - - -def test_is_regular_empty_graph_raises(): - G = nx.Graph() - with pytest.raises(nx.NetworkXPointlessConcept, match="Graph has no nodes"): - nx.is_regular(G) - - -class TestIsKRegular: - def test_is_k_regular1(self): - g = gen.cycle_graph(4) - assert reg.is_k_regular(g, 2) - assert not reg.is_k_regular(g, 3) - - def test_is_k_regular2(self): - g = gen.complete_graph(5) - assert reg.is_k_regular(g, 4) - assert not reg.is_k_regular(g, 3) - assert not reg.is_k_regular(g, 6) - - def test_is_k_regular3(self): - g = gen.lollipop_graph(5, 5) - assert not reg.is_k_regular(g, 5) - assert not reg.is_k_regular(g, 6) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_richclub.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_richclub.py deleted file mode 100644 index 1bdb668..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_richclub.py +++ /dev/null @@ -1,149 +0,0 @@ -import pytest - -import networkx as nx - - -def test_richclub(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rc = nx.richclub.rich_club_coefficient(G, normalized=False) - assert rc == {0: 12.0 / 30, 1: 8.0 / 12} - - # test single value - rc0 = nx.richclub.rich_club_coefficient(G, normalized=False)[0] - assert rc0 == 12.0 / 30.0 - - -def test_richclub_seed(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rcNorm = nx.richclub.rich_club_coefficient(G, Q=2, seed=1) - assert rcNorm == {0: 1.0, 1: 1.0} - - -def test_richclub_normalized(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rcNorm = nx.richclub.rich_club_coefficient(G, Q=2, seed=42) - assert rcNorm == {0: 1.0, 1: 1.0} - - -def test_richclub2(): - T = nx.balanced_tree(2, 10) - rc = nx.richclub.rich_club_coefficient(T, normalized=False) - assert rc == { - 0: 4092 / (2047 * 2046.0), - 1: (2044.0 / (1023 * 1022)), - 2: (2040.0 / (1022 * 1021)), - } - - -def test_richclub3(): - # tests edgecase - G = nx.karate_club_graph() - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == { - 0: 156.0 / 1122, - 1: 154.0 / 1056, - 2: 110.0 / 462, - 3: 78.0 / 240, - 4: 44.0 / 90, - 5: 22.0 / 42, - 6: 10.0 / 20, - 7: 10.0 / 20, - 8: 10.0 / 20, - 9: 6.0 / 12, - 10: 2.0 / 6, - 11: 2.0 / 6, - 12: 0.0, - 13: 0.0, - 14: 0.0, - 15: 0.0, - } - - -def test_richclub4(): - G = nx.Graph() - G.add_edges_from( - [(0, 1), (0, 2), (0, 3), (0, 4), (4, 5), (5, 9), (6, 9), (7, 9), (8, 9)] - ) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 18 / 90.0, 1: 6 / 12.0, 2: 0.0, 3: 0.0} - - -def test_richclub_exception(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - nx.rich_club_coefficient(G) - - -def test_rich_club_exception2(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - nx.rich_club_coefficient(G) - - -def test_rich_club_selfloop(): - G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - G.add_edge(1, 1) # self loop - G.add_edge(1, 2) - with pytest.raises( - Exception, - match="rich_club_coefficient is not implemented for " "graphs with self loops.", - ): - nx.rich_club_coefficient(G) - - -def test_rich_club_leq_3_nodes_unnormalized(): - # edgeless graphs upto 3 nodes - G = nx.Graph() - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {} - - for i in range(3): - G.add_node(i) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {} - - # 2 nodes, single edge - G = nx.Graph() - G.add_edge(0, 1) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 1} - - # 3 nodes, single edge - G = nx.Graph() - G.add_nodes_from([0, 1, 2]) - G.add_edge(0, 1) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 1} - - # 3 nodes, 2 edges - G.add_edge(1, 2) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 2 / 3} - - # 3 nodes, 3 edges - G.add_edge(0, 2) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 1, 1: 1} - - -def test_rich_club_leq_3_nodes_normalized(): - G = nx.Graph() - with pytest.raises( - nx.exception.NetworkXError, - match="Graph has fewer than four nodes", - ): - rc = nx.rich_club_coefficient(G, normalized=True) - - for i in range(3): - G.add_node(i) - with pytest.raises( - nx.exception.NetworkXError, - match="Graph has fewer than four nodes", - ): - rc = nx.rich_club_coefficient(G, normalized=True) - - -# def test_richclub2_normalized(): -# T = nx.balanced_tree(2,10) -# rcNorm = nx.richclub.rich_club_coefficient(T,Q=2) -# assert_true(rcNorm[0] ==1.0 and rcNorm[1] < 0.9 and rcNorm[2] < 0.9) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_similarity.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_similarity.py deleted file mode 100644 index 3836ccf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_similarity.py +++ /dev/null @@ -1,946 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.similarity import ( - graph_edit_distance, - optimal_edit_paths, - optimize_graph_edit_distance, -) -from networkx.generators.classic import ( - circular_ladder_graph, - cycle_graph, - path_graph, - wheel_graph, -) - - -def nmatch(n1, n2): - return n1 == n2 - - -def ematch(e1, e2): - return e1 == e2 - - -def getCanonical(): - G = nx.Graph() - G.add_node("A", label="A") - G.add_node("B", label="B") - G.add_node("C", label="C") - G.add_node("D", label="D") - G.add_edge("A", "B", label="a-b") - G.add_edge("B", "C", label="b-c") - G.add_edge("B", "D", label="b-d") - return G - - -class TestSimilarity: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - - def test_graph_edit_distance_roots_and_timeout(self): - G0 = nx.star_graph(5) - G1 = G0.copy() - pytest.raises(ValueError, graph_edit_distance, G0, G1, roots=[2]) - pytest.raises(ValueError, graph_edit_distance, G0, G1, roots=[2, 3, 4]) - pytest.raises(nx.NodeNotFound, graph_edit_distance, G0, G1, roots=(9, 3)) - pytest.raises(nx.NodeNotFound, graph_edit_distance, G0, G1, roots=(3, 9)) - pytest.raises(nx.NodeNotFound, graph_edit_distance, G0, G1, roots=(9, 9)) - assert graph_edit_distance(G0, G1, roots=(1, 2)) == 0 - assert graph_edit_distance(G0, G1, roots=(0, 1)) == 8 - assert graph_edit_distance(G0, G1, roots=(1, 2), timeout=5) == 0 - assert graph_edit_distance(G0, G1, roots=(0, 1), timeout=5) == 8 - assert graph_edit_distance(G0, G1, roots=(0, 1), timeout=0.0001) is None - # test raise on 0 timeout - pytest.raises(nx.NetworkXError, graph_edit_distance, G0, G1, timeout=0) - - def test_graph_edit_distance(self): - G0 = nx.Graph() - G1 = path_graph(6) - G2 = cycle_graph(6) - G3 = wheel_graph(7) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 11 - assert graph_edit_distance(G1, G0) == 11 - assert graph_edit_distance(G0, G2) == 12 - assert graph_edit_distance(G2, G0) == 12 - assert graph_edit_distance(G0, G3) == 19 - assert graph_edit_distance(G3, G0) == 19 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 1 - assert graph_edit_distance(G2, G1) == 1 - assert graph_edit_distance(G1, G3) == 8 - assert graph_edit_distance(G3, G1) == 8 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 7 - assert graph_edit_distance(G3, G2) == 7 - - assert graph_edit_distance(G3, G3) == 0 - - def test_graph_edit_distance_node_match(self): - G1 = cycle_graph(5) - G2 = cycle_graph(5) - for n, attr in G1.nodes.items(): - attr["color"] = "red" if n % 2 == 0 else "blue" - for n, attr in G2.nodes.items(): - attr["color"] = "red" if n % 2 == 1 else "blue" - assert graph_edit_distance(G1, G2) == 0 - assert ( - graph_edit_distance( - G1, G2, node_match=lambda n1, n2: n1["color"] == n2["color"] - ) - == 1 - ) - - def test_graph_edit_distance_edge_match(self): - G1 = path_graph(6) - G2 = path_graph(6) - for e, attr in G1.edges.items(): - attr["color"] = "red" if min(e) % 2 == 0 else "blue" - for e, attr in G2.edges.items(): - attr["color"] = "red" if min(e) // 3 == 0 else "blue" - assert graph_edit_distance(G1, G2) == 0 - assert ( - graph_edit_distance( - G1, G2, edge_match=lambda e1, e2: e1["color"] == e2["color"] - ) - == 2 - ) - - def test_graph_edit_distance_node_cost(self): - G1 = path_graph(6) - G2 = path_graph(6) - for n, attr in G1.nodes.items(): - attr["color"] = "red" if n % 2 == 0 else "blue" - for n, attr in G2.nodes.items(): - attr["color"] = "red" if n % 2 == 1 else "blue" - - def node_subst_cost(uattr, vattr): - if uattr["color"] == vattr["color"]: - return 1 - else: - return 10 - - def node_del_cost(attr): - if attr["color"] == "blue": - return 20 - else: - return 50 - - def node_ins_cost(attr): - if attr["color"] == "blue": - return 40 - else: - return 100 - - assert ( - graph_edit_distance( - G1, - G2, - node_subst_cost=node_subst_cost, - node_del_cost=node_del_cost, - node_ins_cost=node_ins_cost, - ) - == 6 - ) - - def test_graph_edit_distance_edge_cost(self): - G1 = path_graph(6) - G2 = path_graph(6) - for e, attr in G1.edges.items(): - attr["color"] = "red" if min(e) % 2 == 0 else "blue" - for e, attr in G2.edges.items(): - attr["color"] = "red" if min(e) // 3 == 0 else "blue" - - def edge_subst_cost(gattr, hattr): - if gattr["color"] == hattr["color"]: - return 0.01 - else: - return 0.1 - - def edge_del_cost(attr): - if attr["color"] == "blue": - return 0.2 - else: - return 0.5 - - def edge_ins_cost(attr): - if attr["color"] == "blue": - return 0.4 - else: - return 1.0 - - assert ( - graph_edit_distance( - G1, - G2, - edge_subst_cost=edge_subst_cost, - edge_del_cost=edge_del_cost, - edge_ins_cost=edge_ins_cost, - ) - == 0.23 - ) - - def test_graph_edit_distance_upper_bound(self): - G1 = circular_ladder_graph(2) - G2 = circular_ladder_graph(6) - assert graph_edit_distance(G1, G2, upper_bound=5) is None - assert graph_edit_distance(G1, G2, upper_bound=24) == 22 - assert graph_edit_distance(G1, G2) == 22 - - def test_optimal_edit_paths(self): - G1 = path_graph(3) - G2 = cycle_graph(3) - paths, cost = optimal_edit_paths(G1, G2) - assert cost == 1 - assert len(paths) == 6 - - def canonical(vertex_path, edge_path): - return ( - tuple(sorted(vertex_path)), - tuple(sorted(edge_path, key=lambda x: (None in x, x))), - ) - - expected_paths = [ - ( - [(0, 0), (1, 1), (2, 2)], - [((0, 1), (0, 1)), ((1, 2), (1, 2)), (None, (0, 2))], - ), - ( - [(0, 0), (1, 2), (2, 1)], - [((0, 1), (0, 2)), ((1, 2), (1, 2)), (None, (0, 1))], - ), - ( - [(0, 1), (1, 0), (2, 2)], - [((0, 1), (0, 1)), ((1, 2), (0, 2)), (None, (1, 2))], - ), - ( - [(0, 1), (1, 2), (2, 0)], - [((0, 1), (1, 2)), ((1, 2), (0, 2)), (None, (0, 1))], - ), - ( - [(0, 2), (1, 0), (2, 1)], - [((0, 1), (0, 2)), ((1, 2), (0, 1)), (None, (1, 2))], - ), - ( - [(0, 2), (1, 1), (2, 0)], - [((0, 1), (1, 2)), ((1, 2), (0, 1)), (None, (0, 2))], - ), - ] - assert {canonical(*p) for p in paths} == {canonical(*p) for p in expected_paths} - - def test_optimize_graph_edit_distance(self): - G1 = circular_ladder_graph(2) - G2 = circular_ladder_graph(6) - bestcost = 1000 - for cost in optimize_graph_edit_distance(G1, G2): - assert cost < bestcost - bestcost = cost - assert bestcost == 22 - - # def test_graph_edit_distance_bigger(self): - # G1 = circular_ladder_graph(12) - # G2 = circular_ladder_graph(16) - # assert_equal(graph_edit_distance(G1, G2), 22) - - def test_selfloops(self): - G0 = nx.Graph() - G1 = nx.Graph() - G1.add_edges_from((("A", "A"), ("A", "B"))) - G2 = nx.Graph() - G2.add_edges_from((("A", "B"), ("B", "B"))) - G3 = nx.Graph() - G3.add_edges_from((("A", "A"), ("A", "B"), ("B", "B"))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 4 - assert graph_edit_distance(G1, G0) == 4 - assert graph_edit_distance(G0, G2) == 4 - assert graph_edit_distance(G2, G0) == 4 - assert graph_edit_distance(G0, G3) == 5 - assert graph_edit_distance(G3, G0) == 5 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 0 - assert graph_edit_distance(G2, G1) == 0 - assert graph_edit_distance(G1, G3) == 1 - assert graph_edit_distance(G3, G1) == 1 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 1 - assert graph_edit_distance(G3, G2) == 1 - - assert graph_edit_distance(G3, G3) == 0 - - def test_digraph(self): - G0 = nx.DiGraph() - G1 = nx.DiGraph() - G1.add_edges_from((("A", "B"), ("B", "C"), ("C", "D"), ("D", "A"))) - G2 = nx.DiGraph() - G2.add_edges_from((("A", "B"), ("B", "C"), ("C", "D"), ("A", "D"))) - G3 = nx.DiGraph() - G3.add_edges_from((("A", "B"), ("A", "C"), ("B", "D"), ("C", "D"))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 8 - assert graph_edit_distance(G1, G0) == 8 - assert graph_edit_distance(G0, G2) == 8 - assert graph_edit_distance(G2, G0) == 8 - assert graph_edit_distance(G0, G3) == 8 - assert graph_edit_distance(G3, G0) == 8 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 2 - assert graph_edit_distance(G2, G1) == 2 - assert graph_edit_distance(G1, G3) == 4 - assert graph_edit_distance(G3, G1) == 4 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 2 - assert graph_edit_distance(G3, G2) == 2 - - assert graph_edit_distance(G3, G3) == 0 - - def test_multigraph(self): - G0 = nx.MultiGraph() - G1 = nx.MultiGraph() - G1.add_edges_from((("A", "B"), ("B", "C"), ("A", "C"))) - G2 = nx.MultiGraph() - G2.add_edges_from((("A", "B"), ("B", "C"), ("B", "C"), ("A", "C"))) - G3 = nx.MultiGraph() - G3.add_edges_from((("A", "B"), ("B", "C"), ("A", "C"), ("A", "C"), ("A", "C"))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 6 - assert graph_edit_distance(G1, G0) == 6 - assert graph_edit_distance(G0, G2) == 7 - assert graph_edit_distance(G2, G0) == 7 - assert graph_edit_distance(G0, G3) == 8 - assert graph_edit_distance(G3, G0) == 8 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 1 - assert graph_edit_distance(G2, G1) == 1 - assert graph_edit_distance(G1, G3) == 2 - assert graph_edit_distance(G3, G1) == 2 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 1 - assert graph_edit_distance(G3, G2) == 1 - - assert graph_edit_distance(G3, G3) == 0 - - def test_multidigraph(self): - G1 = nx.MultiDiGraph() - G1.add_edges_from( - ( - ("hardware", "kernel"), - ("kernel", "hardware"), - ("kernel", "userspace"), - ("userspace", "kernel"), - ) - ) - G2 = nx.MultiDiGraph() - G2.add_edges_from( - ( - ("winter", "spring"), - ("spring", "summer"), - ("summer", "autumn"), - ("autumn", "winter"), - ) - ) - - assert graph_edit_distance(G1, G2) == 5 - assert graph_edit_distance(G2, G1) == 5 - - # by https://github.com/jfbeaumont - def testCopy(self): - G = nx.Graph() - G.add_node("A", label="A") - G.add_node("B", label="B") - G.add_edge("A", "B", label="a-b") - assert ( - graph_edit_distance(G, G.copy(), node_match=nmatch, edge_match=ematch) == 0 - ) - - def testSame(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_edge("A", "B", label="a-b") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 0 - - def testOneEdgeLabelDiff(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_edge("A", "B", label="bad") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneNodeLabelDiff(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="Z") - G2.add_node("B", label="B") - G2.add_edge("A", "B", label="a-b") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraNode(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_edge("A", "B", label="a-b") - G2.add_node("C", label="C") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraEdge(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_node("C", label="C") - G1.add_node("C", label="C") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("A", "C", label="a-c") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraNodeAndEdge(self): - G1 = nx.Graph() - G1.add_node("A", label="A") - G1.add_node("B", label="B") - G1.add_edge("A", "B", label="a-b") - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("A", "C", label="a-c") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph1(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("D", label="D") - G2.add_node("E", label="E") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("B", "D", label="b-d") - G2.add_edge("D", "E", label="d-e") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 3 - - def testGraph2(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_node("D", label="D") - G2.add_node("E", label="E") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("B", "C", label="b-c") - G2.add_edge("C", "D", label="c-d") - G2.add_edge("C", "E", label="c-e") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 4 - - def testGraph3(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_node("D", label="D") - G2.add_node("E", label="E") - G2.add_node("F", label="F") - G2.add_node("G", label="G") - G2.add_edge("A", "C", label="a-c") - G2.add_edge("A", "D", label="a-d") - G2.add_edge("D", "E", label="d-e") - G2.add_edge("D", "F", label="d-f") - G2.add_edge("D", "G", label="d-g") - G2.add_edge("E", "B", label="e-b") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 12 - - def testGraph4(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_node("D", label="D") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("B", "C", label="b-c") - G2.add_edge("C", "D", label="c-d") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph4_a(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_node("D", label="D") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("B", "C", label="b-c") - G2.add_edge("A", "D", label="a-d") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph4_b(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node("A", label="A") - G2.add_node("B", label="B") - G2.add_node("C", label="C") - G2.add_node("D", label="D") - G2.add_edge("A", "B", label="a-b") - G2.add_edge("B", "C", label="b-c") - G2.add_edge("B", "D", label="bad") - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - # note: nx.simrank_similarity_numpy not included because returns np.array - simrank_algs = [ - nx.simrank_similarity, - nx.algorithms.similarity._simrank_similarity_python, - ] - - @pytest.mark.parametrize("simrank_similarity", simrank_algs) - def test_simrank_no_source_no_target(self, simrank_similarity): - G = nx.cycle_graph(5) - expected = { - 0: { - 0: 1, - 1: 0.3951219505902448, - 2: 0.5707317069281646, - 3: 0.5707317069281646, - 4: 0.3951219505902449, - }, - 1: { - 0: 0.3951219505902448, - 1: 1, - 2: 0.3951219505902449, - 3: 0.5707317069281646, - 4: 0.5707317069281646, - }, - 2: { - 0: 0.5707317069281646, - 1: 0.3951219505902449, - 2: 1, - 3: 0.3951219505902449, - 4: 0.5707317069281646, - }, - 3: { - 0: 0.5707317069281646, - 1: 0.5707317069281646, - 2: 0.3951219505902449, - 3: 1, - 4: 0.3951219505902449, - }, - 4: { - 0: 0.3951219505902449, - 1: 0.5707317069281646, - 2: 0.5707317069281646, - 3: 0.3951219505902449, - 4: 1, - }, - } - actual = simrank_similarity(G) - for k, v in expected.items(): - assert v == pytest.approx(actual[k], abs=1e-2) - - # For a DiGraph test, use the first graph from the paper cited in - # the docs: https://dl.acm.org/doi/pdf/10.1145/775047.775126 - G = nx.DiGraph() - G.add_node(0, label="Univ") - G.add_node(1, label="ProfA") - G.add_node(2, label="ProfB") - G.add_node(3, label="StudentA") - G.add_node(4, label="StudentB") - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 4), (4, 2), (3, 0)]) - - expected = { - 0: {0: 1, 1: 0.0, 2: 0.1323363991265798, 3: 0.0, 4: 0.03387811817640443}, - 1: {0: 0.0, 1: 1, 2: 0.4135512472705618, 3: 0.0, 4: 0.10586911930126384}, - 2: { - 0: 0.1323363991265798, - 1: 0.4135512472705618, - 2: 1, - 3: 0.04234764772050554, - 4: 0.08822426608438655, - }, - 3: {0: 0.0, 1: 0.0, 2: 0.04234764772050554, 3: 1, 4: 0.3308409978164495}, - 4: { - 0: 0.03387811817640443, - 1: 0.10586911930126384, - 2: 0.08822426608438655, - 3: 0.3308409978164495, - 4: 1, - }, - } - # Use the importance_factor from the paper to get the same numbers. - actual = simrank_similarity(G, importance_factor=0.8) - for k, v in expected.items(): - assert v == pytest.approx(actual[k], abs=1e-2) - - @pytest.mark.parametrize("simrank_similarity", simrank_algs) - def test_simrank_source_no_target(self, simrank_similarity): - G = nx.cycle_graph(5) - expected = { - 0: 1, - 1: 0.3951219505902448, - 2: 0.5707317069281646, - 3: 0.5707317069281646, - 4: 0.3951219505902449, - } - actual = simrank_similarity(G, source=0) - assert expected == pytest.approx(actual, abs=1e-2) - - # For a DiGraph test, use the first graph from the paper cited in - # the docs: https://dl.acm.org/doi/pdf/10.1145/775047.775126 - G = nx.DiGraph() - G.add_node(0, label="Univ") - G.add_node(1, label="ProfA") - G.add_node(2, label="ProfB") - G.add_node(3, label="StudentA") - G.add_node(4, label="StudentB") - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 4), (4, 2), (3, 0)]) - - expected = {0: 1, 1: 0.0, 2: 0.1323363991265798, 3: 0.0, 4: 0.03387811817640443} - # Use the importance_factor from the paper to get the same numbers. - actual = simrank_similarity(G, importance_factor=0.8, source=0) - assert expected == pytest.approx(actual, abs=1e-2) - - @pytest.mark.parametrize("simrank_similarity", simrank_algs) - def test_simrank_noninteger_nodes(self, simrank_similarity): - G = nx.cycle_graph(5) - G = nx.relabel_nodes(G, dict(enumerate("abcde"))) - expected = { - "a": 1, - "b": 0.3951219505902448, - "c": 0.5707317069281646, - "d": 0.5707317069281646, - "e": 0.3951219505902449, - } - actual = simrank_similarity(G, source="a") - assert expected == pytest.approx(actual, abs=1e-2) - - # For a DiGraph test, use the first graph from the paper cited in - # the docs: https://dl.acm.org/doi/pdf/10.1145/775047.775126 - G = nx.DiGraph() - G.add_node(0, label="Univ") - G.add_node(1, label="ProfA") - G.add_node(2, label="ProfB") - G.add_node(3, label="StudentA") - G.add_node(4, label="StudentB") - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 4), (4, 2), (3, 0)]) - node_labels = dict(enumerate(nx.get_node_attributes(G, "label").values())) - G = nx.relabel_nodes(G, node_labels) - - expected = { - "Univ": 1, - "ProfA": 0.0, - "ProfB": 0.1323363991265798, - "StudentA": 0.0, - "StudentB": 0.03387811817640443, - } - # Use the importance_factor from the paper to get the same numbers. - actual = simrank_similarity(G, importance_factor=0.8, source="Univ") - assert expected == pytest.approx(actual, abs=1e-2) - - @pytest.mark.parametrize("simrank_similarity", simrank_algs) - def test_simrank_source_and_target(self, simrank_similarity): - G = nx.cycle_graph(5) - expected = 1 - actual = simrank_similarity(G, source=0, target=0) - assert expected == pytest.approx(actual, abs=1e-2) - - # For a DiGraph test, use the first graph from the paper cited in - # the docs: https://dl.acm.org/doi/pdf/10.1145/775047.775126 - G = nx.DiGraph() - G.add_node(0, label="Univ") - G.add_node(1, label="ProfA") - G.add_node(2, label="ProfB") - G.add_node(3, label="StudentA") - G.add_node(4, label="StudentB") - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 4), (4, 2), (3, 0)]) - - expected = 0.1323363991265798 - # Use the importance_factor from the paper to get the same numbers. - # Use the pair (0,2) because (0,0) and (0,1) have trivial results. - actual = simrank_similarity(G, importance_factor=0.8, source=0, target=2) - assert expected == pytest.approx(actual, abs=1e-5) - - @pytest.mark.parametrize("alg", simrank_algs) - def test_simrank_max_iterations(self, alg): - G = nx.cycle_graph(5) - pytest.raises(nx.ExceededMaxIterations, alg, G, max_iterations=10) - - def test_simrank_source_not_found(self): - G = nx.cycle_graph(5) - with pytest.raises(nx.NodeNotFound, match="Source node 10 not in G"): - nx.simrank_similarity(G, source=10) - - def test_simrank_target_not_found(self): - G = nx.cycle_graph(5) - with pytest.raises(nx.NodeNotFound, match="Target node 10 not in G"): - nx.simrank_similarity(G, target=10) - - def test_simrank_between_versions(self): - G = nx.cycle_graph(5) - # _python tolerance 1e-4 - expected_python_tol4 = { - 0: 1, - 1: 0.394512499239852, - 2: 0.5703550452791322, - 3: 0.5703550452791323, - 4: 0.394512499239852, - } - # _numpy tolerance 1e-4 - expected_numpy_tol4 = { - 0: 1.0, - 1: 0.3947180735764555, - 2: 0.570482097206368, - 3: 0.570482097206368, - 4: 0.3947180735764555, - } - actual = nx.simrank_similarity(G, source=0) - assert expected_numpy_tol4 == pytest.approx(actual, abs=1e-7) - # versions differ at 1e-4 level but equal at 1e-3 - assert expected_python_tol4 != pytest.approx(actual, abs=1e-4) - assert expected_python_tol4 == pytest.approx(actual, abs=1e-3) - - actual = nx.similarity._simrank_similarity_python(G, source=0) - assert expected_python_tol4 == pytest.approx(actual, abs=1e-7) - # versions differ at 1e-4 level but equal at 1e-3 - assert expected_numpy_tol4 != pytest.approx(actual, abs=1e-4) - assert expected_numpy_tol4 == pytest.approx(actual, abs=1e-3) - - def test_simrank_numpy_no_source_no_target(self): - G = nx.cycle_graph(5) - expected = np.array( - [ - [ - 1.0, - 0.3947180735764555, - 0.570482097206368, - 0.570482097206368, - 0.3947180735764555, - ], - [ - 0.3947180735764555, - 1.0, - 0.3947180735764555, - 0.570482097206368, - 0.570482097206368, - ], - [ - 0.570482097206368, - 0.3947180735764555, - 1.0, - 0.3947180735764555, - 0.570482097206368, - ], - [ - 0.570482097206368, - 0.570482097206368, - 0.3947180735764555, - 1.0, - 0.3947180735764555, - ], - [ - 0.3947180735764555, - 0.570482097206368, - 0.570482097206368, - 0.3947180735764555, - 1.0, - ], - ] - ) - actual = nx.similarity._simrank_similarity_numpy(G) - np.testing.assert_allclose(expected, actual, atol=1e-7) - - def test_simrank_numpy_source_no_target(self): - G = nx.cycle_graph(5) - expected = np.array( - [ - 1.0, - 0.3947180735764555, - 0.570482097206368, - 0.570482097206368, - 0.3947180735764555, - ] - ) - actual = nx.similarity._simrank_similarity_numpy(G, source=0) - np.testing.assert_allclose(expected, actual, atol=1e-7) - - def test_simrank_numpy_source_and_target(self): - G = nx.cycle_graph(5) - expected = 1.0 - actual = nx.similarity._simrank_similarity_numpy(G, source=0, target=0) - np.testing.assert_allclose(expected, actual, atol=1e-7) - - def test_panther_similarity_unweighted(self): - np.random.seed(42) - - G = nx.Graph() - G.add_edge(0, 1) - G.add_edge(0, 2) - G.add_edge(0, 3) - G.add_edge(1, 2) - G.add_edge(2, 4) - expected = {3: 0.5, 2: 0.5, 1: 0.5, 4: 0.125} - sim = nx.panther_similarity(G, 0, path_length=2) - assert sim == expected - - def test_panther_similarity_weighted(self): - np.random.seed(42) - - G = nx.Graph() - G.add_edge("v1", "v2", w=5) - G.add_edge("v1", "v3", w=1) - G.add_edge("v1", "v4", w=2) - G.add_edge("v2", "v3", w=0.1) - G.add_edge("v3", "v5", w=1) - expected = {"v3": 0.75, "v4": 0.5, "v2": 0.5, "v5": 0.25} - sim = nx.panther_similarity(G, "v1", path_length=2, weight="w") - assert sim == expected - - def test_panther_similarity_source_not_found(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 2), (2, 4)]) - with pytest.raises(nx.NodeNotFound, match="Source node 10 not in G"): - nx.panther_similarity(G, source=10) - - def test_panther_similarity_isolated(self): - G = nx.Graph() - G.add_nodes_from(range(5)) - with pytest.raises( - nx.NetworkXUnfeasible, - match="Panther similarity is not defined for the isolated source node 1.", - ): - nx.panther_similarity(G, source=1) - - def test_generate_random_paths_unweighted(self): - index_map = {} - num_paths = 10 - path_length = 2 - G = nx.Graph() - G.add_edge(0, 1) - G.add_edge(0, 2) - G.add_edge(0, 3) - G.add_edge(1, 2) - G.add_edge(2, 4) - paths = nx.generate_random_paths( - G, num_paths, path_length=path_length, index_map=index_map, seed=42 - ) - expected_paths = [ - [3, 0, 3], - [4, 2, 1], - [2, 1, 0], - [2, 0, 3], - [3, 0, 1], - [3, 0, 1], - [4, 2, 0], - [2, 1, 0], - [3, 0, 2], - [2, 1, 2], - ] - expected_map = { - 0: {0, 2, 3, 4, 5, 6, 7, 8}, - 1: {1, 2, 4, 5, 7, 9}, - 2: {1, 2, 3, 6, 7, 8, 9}, - 3: {0, 3, 4, 5, 8}, - 4: {1, 6}, - } - - assert expected_paths == list(paths) - assert expected_map == index_map - - def test_generate_random_paths_weighted(self): - np.random.seed(42) - - index_map = {} - num_paths = 10 - path_length = 6 - G = nx.Graph() - G.add_edge("a", "b", weight=0.6) - G.add_edge("a", "c", weight=0.2) - G.add_edge("c", "d", weight=0.1) - G.add_edge("c", "e", weight=0.7) - G.add_edge("c", "f", weight=0.9) - G.add_edge("a", "d", weight=0.3) - paths = nx.generate_random_paths( - G, num_paths, path_length=path_length, index_map=index_map - ) - - expected_paths = [ - ["d", "c", "f", "c", "d", "a", "b"], - ["e", "c", "f", "c", "f", "c", "e"], - ["d", "a", "b", "a", "b", "a", "c"], - ["b", "a", "d", "a", "b", "a", "b"], - ["d", "a", "b", "a", "b", "a", "d"], - ["d", "a", "b", "a", "b", "a", "c"], - ["d", "a", "b", "a", "b", "a", "b"], - ["f", "c", "f", "c", "f", "c", "e"], - ["d", "a", "d", "a", "b", "a", "b"], - ["e", "c", "f", "c", "e", "c", "d"], - ] - expected_map = { - "d": {0, 2, 3, 4, 5, 6, 8, 9}, - "c": {0, 1, 2, 5, 7, 9}, - "f": {0, 1, 9, 7}, - "a": {0, 2, 3, 4, 5, 6, 8}, - "b": {0, 2, 3, 4, 5, 6, 8}, - "e": {1, 9, 7}, - } - - assert expected_paths == list(paths) - assert expected_map == index_map - - def test_symmetry_with_custom_matching(self): - print("G2 is edge (a,b) and G3 is edge (a,a)") - print("but node order for G2 is (a,b) while for G3 it is (b,a)") - - a, b = "A", "B" - G2 = nx.Graph() - G2.add_nodes_from((a, b)) - G2.add_edges_from([(a, b)]) - G3 = nx.Graph() - G3.add_nodes_from((b, a)) - G3.add_edges_from([(a, a)]) - for G in (G2, G3): - for n in G: - G.nodes[n]["attr"] = n - for e in G.edges: - G.edges[e]["attr"] = e - match = lambda x, y: x == y - - print("Starting G2 to G3 GED calculation") - assert nx.graph_edit_distance(G2, G3, node_match=match, edge_match=match) == 1 - - print("Starting G3 to G2 GED calculation") - assert nx.graph_edit_distance(G3, G2, node_match=match, edge_match=match) == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_simple_paths.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_simple_paths.py deleted file mode 100644 index 7855bba..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_simple_paths.py +++ /dev/null @@ -1,803 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.algorithms.simple_paths import ( - _bidirectional_dijkstra, - _bidirectional_shortest_path, -) -from networkx.utils import arbitrary_element, pairwise - - -class TestIsSimplePath: - """Unit tests for the - :func:`networkx.algorithms.simple_paths.is_simple_path` function. - - """ - - def test_empty_list(self): - """Tests that the empty list is not a valid path, since there - should be a one-to-one correspondence between paths as lists of - nodes and paths as lists of edges. - - """ - G = nx.trivial_graph() - assert not nx.is_simple_path(G, []) - - def test_trivial_path(self): - """Tests that the trivial path, a path of length one, is - considered a simple path in a graph. - - """ - G = nx.trivial_graph() - assert nx.is_simple_path(G, [0]) - - def test_trivial_nonpath(self): - """Tests that a list whose sole element is an object not in the - graph is not considered a simple path. - - """ - G = nx.trivial_graph() - assert not nx.is_simple_path(G, ["not a node"]) - - def test_simple_path(self): - G = nx.path_graph(2) - assert nx.is_simple_path(G, [0, 1]) - - def test_non_simple_path(self): - G = nx.path_graph(2) - assert not nx.is_simple_path(G, [0, 1, 0]) - - def test_cycle(self): - G = nx.cycle_graph(3) - assert not nx.is_simple_path(G, [0, 1, 2, 0]) - - def test_missing_node(self): - G = nx.path_graph(2) - assert not nx.is_simple_path(G, [0, 2]) - - def test_missing_starting_node(self): - G = nx.path_graph(2) - assert not nx.is_simple_path(G, [2, 0]) - - def test_directed_path(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - assert nx.is_simple_path(G, [0, 1, 2]) - - def test_directed_non_path(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - assert not nx.is_simple_path(G, [2, 1, 0]) - - def test_directed_cycle(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - assert not nx.is_simple_path(G, [0, 1, 2, 0]) - - def test_multigraph(self): - G = nx.MultiGraph([(0, 1), (0, 1)]) - assert nx.is_simple_path(G, [0, 1]) - - def test_multidigraph(self): - G = nx.MultiDiGraph([(0, 1), (0, 1), (1, 0), (1, 0)]) - assert nx.is_simple_path(G, [0, 1]) - - -# Tests for all_simple_paths -def test_all_simple_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, 3) - assert {tuple(p) for p in paths} == {(0, 1, 2, 3)} - - -def test_all_simple_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4]) - assert {tuple(p) for p in paths} == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_digraph_all_simple_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4]) - assert {tuple(p) for p in paths} == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_all_simple_paths_with_two_targets_cutoff(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4], cutoff=3) - assert {tuple(p) for p in paths} == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_digraph_all_simple_paths_with_two_targets_cutoff(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4], cutoff=3) - assert {tuple(p) for p in paths} == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_all_simple_paths_with_two_targets_in_line_emits_two_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, [2, 3]) - assert {tuple(p) for p in paths} == {(0, 1, 2), (0, 1, 2, 3)} - - -def test_all_simple_paths_ignores_cycle(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_paths(G, 0, 3) - assert {tuple(p) for p in paths} == {(0, 1, 3)} - - -def test_all_simple_paths_with_two_targets_inside_cycle_emits_two_paths(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_paths(G, 0, [2, 3]) - assert {tuple(p) for p in paths} == {(0, 1, 2), (0, 1, 3)} - - -def test_all_simple_paths_source_target(): - G = nx.path_graph(4) - assert list(nx.all_simple_paths(G, 1, 1)) == [[1]] - - -def test_all_simple_paths_cutoff(): - G = nx.complete_graph(4) - paths = nx.all_simple_paths(G, 0, 1, cutoff=1) - assert {tuple(p) for p in paths} == {(0, 1)} - paths = nx.all_simple_paths(G, 0, 1, cutoff=2) - assert {tuple(p) for p in paths} == {(0, 1), (0, 2, 1), (0, 3, 1)} - - -def test_all_simple_paths_on_non_trivial_graph(): - """you may need to draw this graph to make sure it is reasonable""" - G = nx.path_graph(5, create_using=nx.DiGraph()) - G.add_edges_from([(0, 5), (1, 5), (1, 3), (5, 4), (4, 2), (4, 3)]) - paths = nx.all_simple_paths(G, 1, [2, 3]) - assert {tuple(p) for p in paths} == { - (1, 2), - (1, 3, 4, 2), - (1, 5, 4, 2), - (1, 3), - (1, 2, 3), - (1, 5, 4, 3), - (1, 5, 4, 2, 3), - } - paths = nx.all_simple_paths(G, 1, [2, 3], cutoff=3) - assert {tuple(p) for p in paths} == { - (1, 2), - (1, 3, 4, 2), - (1, 5, 4, 2), - (1, 3), - (1, 2, 3), - (1, 5, 4, 3), - } - paths = nx.all_simple_paths(G, 1, [2, 3], cutoff=2) - assert {tuple(p) for p in paths} == {(1, 2), (1, 3), (1, 2, 3)} - - -def test_all_simple_paths_multigraph(): - G = nx.MultiGraph([(1, 2), (1, 2)]) - assert list(nx.all_simple_paths(G, 1, 1)) == [[1]] - nx.add_path(G, [3, 1, 10, 2]) - paths = list(nx.all_simple_paths(G, 1, 2)) - assert len(paths) == 3 - assert {tuple(p) for p in paths} == {(1, 2), (1, 2), (1, 10, 2)} - - -def test_all_simple_paths_multigraph_with_cutoff(): - G = nx.MultiGraph([(1, 2), (1, 2), (1, 10), (10, 2)]) - paths = list(nx.all_simple_paths(G, 1, 2, cutoff=1)) - assert len(paths) == 2 - assert {tuple(p) for p in paths} == {(1, 2), (1, 2)} - - # See GitHub issue #6732. - G = nx.MultiGraph([(0, 1), (0, 2)]) - assert list(nx.all_simple_paths(G, 0, {1, 2}, cutoff=1)) == [[0, 1], [0, 2]] - - -def test_all_simple_paths_directed(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [3, 2, 1]) - paths = nx.all_simple_paths(G, 1, 3) - assert {tuple(p) for p in paths} == {(1, 2, 3)} - - -def test_all_simple_paths_empty(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, 3, cutoff=2) - assert list(paths) == [] - - -def test_all_simple_paths_corner_cases(): - assert list(nx.all_simple_paths(nx.empty_graph(2), 0, 0)) == [[0]] - assert list(nx.all_simple_paths(nx.empty_graph(2), 0, 1)) == [] - assert list(nx.all_simple_paths(nx.path_graph(9), 0, 8, 0)) == [] - - -def test_all_simple_paths_source_in_targets(): - # See GitHub issue #6690. - G = nx.path_graph(3) - assert list(nx.all_simple_paths(G, 0, {0, 1, 2})) == [[0], [0, 1], [0, 1, 2]] - - -def hamiltonian_path(G, source): - source = arbitrary_element(G) - neighbors = set(G[source]) - {source} - n = len(G) - for target in neighbors: - for path in nx.all_simple_paths(G, source, target): - if len(path) == n: - yield path - - -def test_hamiltonian_path(): - from itertools import permutations - - G = nx.complete_graph(4) - paths = [list(p) for p in hamiltonian_path(G, 0)] - exact = [[0] + list(p) for p in permutations([1, 2, 3], 3)] - assert sorted(paths) == sorted(exact) - - -def test_cutoff_zero(): - G = nx.complete_graph(4) - paths = nx.all_simple_paths(G, 0, 3, cutoff=0) - assert [list(p) for p in paths] == [] - paths = nx.all_simple_paths(nx.MultiGraph(G), 0, 3, cutoff=0) - assert [list(p) for p in paths] == [] - - -def test_source_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.all_simple_paths(nx.MultiGraph(G), 0, 3)) - - -def test_target_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.all_simple_paths(nx.MultiGraph(G), 1, 4)) - - -# Tests for all_simple_edge_paths -def test_all_simple_edge_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_edge_paths(G, 0, 3) - assert {tuple(p) for p in paths} == {((0, 1), (1, 2), (2, 3))} - - -def test_all_simple_edge_paths_empty_path(): - G = nx.empty_graph(1) - assert list(nx.all_simple_edge_paths(G, 0, 0)) == [[]] - - -def test_all_simple_edge_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_edge_paths(G, 0, [3, 4]) - assert {tuple(p) for p in paths} == { - ((0, 1), (1, 2), (2, 3)), - ((0, 1), (1, 2), (2, 4)), - } - - -def test_digraph_all_simple_edge_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_edge_paths(G, 0, [3, 4]) - assert {tuple(p) for p in paths} == { - ((0, 1), (1, 2), (2, 3)), - ((0, 1), (1, 2), (2, 4)), - } - - -def test_all_simple_edge_paths_with_two_targets_cutoff(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_edge_paths(G, 0, [3, 4], cutoff=3) - assert {tuple(p) for p in paths} == { - ((0, 1), (1, 2), (2, 3)), - ((0, 1), (1, 2), (2, 4)), - } - - -def test_digraph_all_simple_edge_paths_with_two_targets_cutoff(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_edge_paths(G, 0, [3, 4], cutoff=3) - assert {tuple(p) for p in paths} == { - ((0, 1), (1, 2), (2, 3)), - ((0, 1), (1, 2), (2, 4)), - } - - -def test_all_simple_edge_paths_with_two_targets_in_line_emits_two_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_edge_paths(G, 0, [2, 3]) - assert {tuple(p) for p in paths} == {((0, 1), (1, 2)), ((0, 1), (1, 2), (2, 3))} - - -def test_all_simple_edge_paths_ignores_cycle(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_edge_paths(G, 0, 3) - assert {tuple(p) for p in paths} == {((0, 1), (1, 3))} - - -def test_all_simple_edge_paths_with_two_targets_inside_cycle_emits_two_paths(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_edge_paths(G, 0, [2, 3]) - assert {tuple(p) for p in paths} == {((0, 1), (1, 2)), ((0, 1), (1, 3))} - - -def test_all_simple_edge_paths_source_target(): - G = nx.path_graph(4) - paths = nx.all_simple_edge_paths(G, 1, 1) - assert list(paths) == [[]] - - -def test_all_simple_edge_paths_cutoff(): - G = nx.complete_graph(4) - paths = nx.all_simple_edge_paths(G, 0, 1, cutoff=1) - assert {tuple(p) for p in paths} == {((0, 1),)} - paths = nx.all_simple_edge_paths(G, 0, 1, cutoff=2) - assert {tuple(p) for p in paths} == {((0, 1),), ((0, 2), (2, 1)), ((0, 3), (3, 1))} - - -def test_all_simple_edge_paths_on_non_trivial_graph(): - """you may need to draw this graph to make sure it is reasonable""" - G = nx.path_graph(5, create_using=nx.DiGraph()) - G.add_edges_from([(0, 5), (1, 5), (1, 3), (5, 4), (4, 2), (4, 3)]) - paths = nx.all_simple_edge_paths(G, 1, [2, 3]) - assert {tuple(p) for p in paths} == { - ((1, 2),), - ((1, 3), (3, 4), (4, 2)), - ((1, 5), (5, 4), (4, 2)), - ((1, 3),), - ((1, 2), (2, 3)), - ((1, 5), (5, 4), (4, 3)), - ((1, 5), (5, 4), (4, 2), (2, 3)), - } - paths = nx.all_simple_edge_paths(G, 1, [2, 3], cutoff=3) - assert {tuple(p) for p in paths} == { - ((1, 2),), - ((1, 3), (3, 4), (4, 2)), - ((1, 5), (5, 4), (4, 2)), - ((1, 3),), - ((1, 2), (2, 3)), - ((1, 5), (5, 4), (4, 3)), - } - paths = nx.all_simple_edge_paths(G, 1, [2, 3], cutoff=2) - assert {tuple(p) for p in paths} == {((1, 2),), ((1, 3),), ((1, 2), (2, 3))} - - -def test_all_simple_edge_paths_multigraph(): - G = nx.MultiGraph([(1, 2), (1, 2)]) - paths = nx.all_simple_edge_paths(G, 1, 1) - assert list(paths) == [[]] - nx.add_path(G, [3, 1, 10, 2]) - paths = list(nx.all_simple_edge_paths(G, 1, 2)) - assert len(paths) == 3 - assert {tuple(p) for p in paths} == { - ((1, 2, 0),), - ((1, 2, 1),), - ((1, 10, 0), (10, 2, 0)), - } - - -def test_all_simple_edge_paths_multigraph_with_cutoff(): - G = nx.MultiGraph([(1, 2), (1, 2), (1, 10), (10, 2)]) - paths = list(nx.all_simple_edge_paths(G, 1, 2, cutoff=1)) - assert len(paths) == 2 - assert {tuple(p) for p in paths} == {((1, 2, 0),), ((1, 2, 1),)} - - -def test_all_simple_edge_paths_directed(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [3, 2, 1]) - paths = nx.all_simple_edge_paths(G, 1, 3) - assert {tuple(p) for p in paths} == {((1, 2), (2, 3))} - - -def test_all_simple_edge_paths_empty(): - G = nx.path_graph(4) - paths = nx.all_simple_edge_paths(G, 0, 3, cutoff=2) - assert list(paths) == [] - - -def test_all_simple_edge_paths_corner_cases(): - assert list(nx.all_simple_edge_paths(nx.empty_graph(2), 0, 0)) == [[]] - assert list(nx.all_simple_edge_paths(nx.empty_graph(2), 0, 1)) == [] - assert list(nx.all_simple_edge_paths(nx.path_graph(9), 0, 8, 0)) == [] - - -def test_all_simple_edge_paths_ignores_self_loop(): - G = nx.Graph([(0, 0), (0, 1), (1, 1), (1, 2)]) - assert list(nx.all_simple_edge_paths(G, 0, 2)) == [[(0, 1), (1, 2)]] - - -def hamiltonian_edge_path(G, source): - source = arbitrary_element(G) - neighbors = set(G[source]) - {source} - n = len(G) - for target in neighbors: - for path in nx.all_simple_edge_paths(G, source, target): - if len(path) == n - 1: - yield path - - -def test_hamiltonian__edge_path(): - from itertools import permutations - - G = nx.complete_graph(4) - paths = hamiltonian_edge_path(G, 0) - exact = [list(pairwise([0] + list(p))) for p in permutations([1, 2, 3], 3)] - assert sorted(exact) == sorted(paths) - - -def test_edge_cutoff_zero(): - G = nx.complete_graph(4) - paths = nx.all_simple_edge_paths(G, 0, 3, cutoff=0) - assert [list(p) for p in paths] == [] - paths = nx.all_simple_edge_paths(nx.MultiGraph(G), 0, 3, cutoff=0) - assert [list(p) for p in paths] == [] - - -def test_edge_source_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.all_simple_edge_paths(nx.MultiGraph(G), 0, 3)) - - -def test_edge_target_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.all_simple_edge_paths(nx.MultiGraph(G), 1, 4)) - - -# Tests for shortest_simple_paths -def test_shortest_simple_paths(): - G = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - paths = nx.shortest_simple_paths(G, 1, 12) - assert next(paths) == [1, 2, 3, 4, 8, 12] - assert next(paths) == [1, 5, 6, 7, 8, 12] - assert [len(path) for path in nx.shortest_simple_paths(G, 1, 12)] == sorted( - len(path) for path in nx.all_simple_paths(G, 1, 12) - ) - - -def test_shortest_simple_paths_singleton_path(): - G = nx.empty_graph(3) - assert list(nx.shortest_simple_paths(G, 0, 0)) == [[0]] - - -def test_shortest_simple_paths_directed(): - G = nx.cycle_graph(7, create_using=nx.DiGraph()) - paths = nx.shortest_simple_paths(G, 0, 3) - assert list(paths) == [[0, 1, 2, 3]] - - -def test_shortest_simple_paths_directed_with_weight_function(): - def cost(u, v, x): - return 1 - - G = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - paths = nx.shortest_simple_paths(G, 1, 12) - assert next(paths) == [1, 2, 3, 4, 8, 12] - assert next(paths) == [1, 5, 6, 7, 8, 12] - assert [ - len(path) for path in nx.shortest_simple_paths(G, 1, 12, weight=cost) - ] == sorted(len(path) for path in nx.all_simple_paths(G, 1, 12)) - - -def test_shortest_simple_paths_with_weight_function(): - def cost(u, v, x): - return 1 - - G = nx.cycle_graph(7, create_using=nx.DiGraph()) - paths = nx.shortest_simple_paths(G, 0, 3, weight=cost) - assert list(paths) == [[0, 1, 2, 3]] - - -def test_shortest_simple_paths_with_none_weight_function(): - def cost(u, v, x): - delta = abs(u - v) - # ignore interior edges - return 1 if (delta == 1 or delta == 4) else None - - G = nx.complete_graph(5) - paths = nx.shortest_simple_paths(G, 0, 2, weight=cost) - assert list(paths) == [[0, 1, 2], [0, 4, 3, 2]] - - -def test_Greg_Bernstein(): - g1 = nx.Graph() - g1.add_nodes_from(["N0", "N1", "N2", "N3", "N4"]) - g1.add_edge("N4", "N1", weight=10.0, capacity=50, name="L5") - g1.add_edge("N4", "N0", weight=7.0, capacity=40, name="L4") - g1.add_edge("N0", "N1", weight=10.0, capacity=45, name="L1") - g1.add_edge("N3", "N0", weight=10.0, capacity=50, name="L0") - g1.add_edge("N2", "N3", weight=12.0, capacity=30, name="L2") - g1.add_edge("N1", "N2", weight=15.0, capacity=42, name="L3") - solution = [["N1", "N0", "N3"], ["N1", "N2", "N3"], ["N1", "N4", "N0", "N3"]] - result = list(nx.shortest_simple_paths(g1, "N1", "N3", weight="weight")) - assert result == solution - - -def test_weighted_shortest_simple_path(): - def cost_func(path): - return sum(G.adj[u][v]["weight"] for (u, v) in zip(path, path[1:])) - - G = nx.complete_graph(5) - weight = {(u, v): random.randint(1, 100) for (u, v) in G.edges()} - nx.set_edge_attributes(G, weight, "weight") - cost = 0 - for path in nx.shortest_simple_paths(G, 0, 3, weight="weight"): - this_cost = cost_func(path) - assert cost <= this_cost - cost = this_cost - - -def test_directed_weighted_shortest_simple_path(): - def cost_func(path): - return sum(G.adj[u][v]["weight"] for (u, v) in zip(path, path[1:])) - - G = nx.complete_graph(5) - G = G.to_directed() - weight = {(u, v): random.randint(1, 100) for (u, v) in G.edges()} - nx.set_edge_attributes(G, weight, "weight") - cost = 0 - for path in nx.shortest_simple_paths(G, 0, 3, weight="weight"): - this_cost = cost_func(path) - assert cost <= this_cost - cost = this_cost - - -def test_weighted_shortest_simple_path_issue2427(): - G = nx.Graph() - G.add_edge("IN", "OUT", weight=2) - G.add_edge("IN", "A", weight=1) - G.add_edge("IN", "B", weight=2) - G.add_edge("B", "OUT", weight=2) - assert list(nx.shortest_simple_paths(G, "IN", "OUT", weight="weight")) == [ - ["IN", "OUT"], - ["IN", "B", "OUT"], - ] - G = nx.Graph() - G.add_edge("IN", "OUT", weight=10) - G.add_edge("IN", "A", weight=1) - G.add_edge("IN", "B", weight=1) - G.add_edge("B", "OUT", weight=1) - assert list(nx.shortest_simple_paths(G, "IN", "OUT", weight="weight")) == [ - ["IN", "B", "OUT"], - ["IN", "OUT"], - ] - - -def test_directed_weighted_shortest_simple_path_issue2427(): - G = nx.DiGraph() - G.add_edge("IN", "OUT", weight=2) - G.add_edge("IN", "A", weight=1) - G.add_edge("IN", "B", weight=2) - G.add_edge("B", "OUT", weight=2) - assert list(nx.shortest_simple_paths(G, "IN", "OUT", weight="weight")) == [ - ["IN", "OUT"], - ["IN", "B", "OUT"], - ] - G = nx.DiGraph() - G.add_edge("IN", "OUT", weight=10) - G.add_edge("IN", "A", weight=1) - G.add_edge("IN", "B", weight=1) - G.add_edge("B", "OUT", weight=1) - assert list(nx.shortest_simple_paths(G, "IN", "OUT", weight="weight")) == [ - ["IN", "B", "OUT"], - ["IN", "OUT"], - ] - - -def test_weight_name(): - G = nx.cycle_graph(7) - nx.set_edge_attributes(G, 1, "weight") - nx.set_edge_attributes(G, 1, "foo") - G.adj[1][2]["foo"] = 7 - paths = list(nx.shortest_simple_paths(G, 0, 3, weight="foo")) - solution = [[0, 6, 5, 4, 3], [0, 1, 2, 3]] - assert paths == solution - - -def test_ssp_source_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.shortest_simple_paths(G, 0, 3)) - - -def test_ssp_target_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - list(nx.shortest_simple_paths(G, 1, 4)) - - -def test_ssp_multigraph(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - nx.add_path(G, [1, 2, 3]) - list(nx.shortest_simple_paths(G, 1, 4)) - - -def test_ssp_source_missing2(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5]) - list(nx.shortest_simple_paths(G, 0, 3)) - - -def test_bidirectional_shortest_path_restricted_cycle(): - cycle = nx.cycle_graph(7) - length, path = _bidirectional_shortest_path(cycle, 0, 3) - assert path == [0, 1, 2, 3] - length, path = _bidirectional_shortest_path(cycle, 0, 3, ignore_nodes=[1]) - assert path == [0, 6, 5, 4, 3] - - -def test_bidirectional_shortest_path_restricted_wheel(): - wheel = nx.wheel_graph(6) - length, path = _bidirectional_shortest_path(wheel, 1, 3) - assert path in [[1, 0, 3], [1, 2, 3]] - length, path = _bidirectional_shortest_path(wheel, 1, 3, ignore_nodes=[0]) - assert path == [1, 2, 3] - length, path = _bidirectional_shortest_path(wheel, 1, 3, ignore_nodes=[0, 2]) - assert path == [1, 5, 4, 3] - length, path = _bidirectional_shortest_path( - wheel, 1, 3, ignore_edges=[(1, 0), (5, 0), (2, 3)] - ) - assert path in [[1, 2, 0, 3], [1, 5, 4, 3]] - - -def test_bidirectional_shortest_path_restricted_directed_cycle(): - directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - length, path = _bidirectional_shortest_path(directed_cycle, 0, 3) - assert path == [0, 1, 2, 3] - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - directed_cycle, - 0, - 3, - ignore_nodes=[1], - ) - length, path = _bidirectional_shortest_path( - directed_cycle, 0, 3, ignore_edges=[(2, 1)] - ) - assert path == [0, 1, 2, 3] - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - directed_cycle, - 0, - 3, - ignore_edges=[(1, 2)], - ) - - -def test_bidirectional_shortest_path_ignore(): - G = nx.Graph() - nx.add_path(G, [1, 2]) - nx.add_path(G, [1, 3]) - nx.add_path(G, [1, 4]) - pytest.raises( - nx.NetworkXNoPath, _bidirectional_shortest_path, G, 1, 2, ignore_nodes=[1] - ) - pytest.raises( - nx.NetworkXNoPath, _bidirectional_shortest_path, G, 1, 2, ignore_nodes=[2] - ) - G = nx.Graph() - nx.add_path(G, [1, 3]) - nx.add_path(G, [1, 4]) - nx.add_path(G, [3, 2]) - pytest.raises( - nx.NetworkXNoPath, _bidirectional_shortest_path, G, 1, 2, ignore_nodes=[1, 2] - ) - - -def validate_path(G, s, t, soln_len, path): - assert path[0] == s - assert path[-1] == t - assert soln_len == sum( - G[u][v].get("weight", 1) for u, v in zip(path[:-1], path[1:]) - ) - - -def validate_length_path(G, s, t, soln_len, length, path): - assert soln_len == length - validate_path(G, s, t, length, path) - - -def test_bidirectional_dijkstra_restricted(): - XG = nx.DiGraph() - XG.add_weighted_edges_from( - [ - ("s", "u", 10), - ("s", "x", 5), - ("u", "v", 1), - ("u", "x", 2), - ("v", "y", 1), - ("x", "u", 3), - ("x", "v", 5), - ("x", "y", 2), - ("y", "s", 7), - ("y", "v", 6), - ] - ) - - XG3 = nx.Graph() - XG3.add_weighted_edges_from( - [[0, 1, 2], [1, 2, 12], [2, 3, 1], [3, 4, 5], [4, 5, 1], [5, 0, 10]] - ) - validate_length_path(XG, "s", "v", 9, *_bidirectional_dijkstra(XG, "s", "v")) - validate_length_path( - XG, "s", "v", 10, *_bidirectional_dijkstra(XG, "s", "v", ignore_nodes=["u"]) - ) - validate_length_path( - XG, - "s", - "v", - 11, - *_bidirectional_dijkstra(XG, "s", "v", ignore_edges=[("s", "x")]), - ) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - XG, - "s", - "v", - ignore_nodes=["u"], - ignore_edges=[("s", "x")], - ) - validate_length_path(XG3, 0, 3, 15, *_bidirectional_dijkstra(XG3, 0, 3)) - validate_length_path( - XG3, 0, 3, 16, *_bidirectional_dijkstra(XG3, 0, 3, ignore_nodes=[1]) - ) - validate_length_path( - XG3, 0, 3, 16, *_bidirectional_dijkstra(XG3, 0, 3, ignore_edges=[(2, 3)]) - ) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - XG3, - 0, - 3, - ignore_nodes=[1], - ignore_edges=[(5, 4)], - ) - - -def test_bidirectional_dijkstra_no_path(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5, 6]) - _bidirectional_dijkstra(G, 1, 6) - - -def test_bidirectional_dijkstra_ignore(): - G = nx.Graph() - nx.add_path(G, [1, 2, 10]) - nx.add_path(G, [1, 3, 10]) - pytest.raises(nx.NetworkXNoPath, _bidirectional_dijkstra, G, 1, 2, ignore_nodes=[1]) - pytest.raises(nx.NetworkXNoPath, _bidirectional_dijkstra, G, 1, 2, ignore_nodes=[2]) - pytest.raises( - nx.NetworkXNoPath, _bidirectional_dijkstra, G, 1, 2, ignore_nodes=[1, 2] - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smallworld.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smallworld.py deleted file mode 100644 index d115dd9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smallworld.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest - -pytest.importorskip("numpy") - -import random - -import networkx as nx -from networkx import lattice_reference, omega, random_reference, sigma - -rng = 42 - - -def test_random_reference(): - G = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - Gr = random_reference(G, niter=1, seed=rng) - C = nx.average_clustering(G) - Cr = nx.average_clustering(Gr) - assert C > Cr - - with pytest.raises(nx.NetworkXError): - next(random_reference(nx.Graph())) - with pytest.raises(nx.NetworkXNotImplemented): - next(random_reference(nx.DiGraph())) - - H = nx.Graph(((0, 1), (2, 3))) - Hl = random_reference(H, niter=1, seed=rng) - - -def test_lattice_reference(): - G = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - Gl = lattice_reference(G, niter=1, seed=rng) - L = nx.average_shortest_path_length(G) - Ll = nx.average_shortest_path_length(Gl) - assert Ll > L - - pytest.raises(nx.NetworkXError, lattice_reference, nx.Graph()) - pytest.raises(nx.NetworkXNotImplemented, lattice_reference, nx.DiGraph()) - - H = nx.Graph(((0, 1), (2, 3))) - Hl = lattice_reference(H, niter=1) - - -def test_sigma(): - Gs = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - Gr = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - sigmas = sigma(Gs, niter=1, nrand=2, seed=rng) - sigmar = sigma(Gr, niter=1, nrand=2, seed=rng) - assert sigmar < sigmas - - -def test_omega(): - Gl = nx.connected_watts_strogatz_graph(50, 6, 0, seed=rng) - Gr = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - Gs = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - omegal = omega(Gl, niter=1, nrand=1, seed=rng) - omegar = omega(Gr, niter=1, nrand=1, seed=rng) - omegas = omega(Gs, niter=1, nrand=1, seed=rng) - assert omegal < omegas and omegas < omegar - - # Test that omega lies within the [-1, 1] bounds - G_barbell = nx.barbell_graph(5, 1) - G_karate = nx.karate_club_graph() - - omega_barbell = nx.omega(G_barbell) - omega_karate = nx.omega(G_karate, nrand=2) - - omegas = (omegal, omegar, omegas, omega_barbell, omega_karate) - - for o in omegas: - assert -1 <= o <= 1 - - -@pytest.mark.parametrize("f", (nx.random_reference, nx.lattice_reference)) -def test_graph_no_edges(f): - G = nx.Graph() - G.add_nodes_from([0, 1, 2, 3]) - with pytest.raises(nx.NetworkXError, match="Graph has fewer that 2 edges"): - f(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smetric.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smetric.py deleted file mode 100644 index 528dbc8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_smetric.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -import networkx as nx - - -def test_smetric(): - G = nx.Graph([(1, 2), (2, 3), (2, 4), (1, 4)]) - assert nx.s_metric(G) == 19.0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_sparsifiers.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_sparsifiers.py deleted file mode 100644 index e8604e6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_sparsifiers.py +++ /dev/null @@ -1,138 +0,0 @@ -"""Unit tests for the sparsifier computation functions.""" - -import pytest - -import networkx as nx -from networkx.utils import py_random_state - -_seed = 2 - - -def _test_spanner(G, spanner, stretch, weight=None): - """Test whether a spanner is valid. - - This function tests whether the given spanner is a subgraph of the - given graph G with the same node set. It also tests for all shortest - paths whether they adhere to the given stretch. - - Parameters - ---------- - G : NetworkX graph - The original graph for which the spanner was constructed. - - spanner : NetworkX graph - The spanner to be tested. - - stretch : float - The proclaimed stretch of the spanner. - - weight : object - The edge attribute to use as distance. - """ - # check node set - assert set(G.nodes()) == set(spanner.nodes()) - - # check edge set and weights - for u, v in spanner.edges(): - assert G.has_edge(u, v) - if weight: - assert spanner[u][v][weight] == G[u][v][weight] - - # check connectivity and stretch - original_length = dict(nx.shortest_path_length(G, weight=weight)) - spanner_length = dict(nx.shortest_path_length(spanner, weight=weight)) - for u in G.nodes(): - for v in G.nodes(): - if u in original_length and v in original_length[u]: - assert spanner_length[u][v] <= stretch * original_length[u][v] - - -@py_random_state(1) -def _assign_random_weights(G, seed=None): - """Assigns random weights to the edges of a graph. - - Parameters - ---------- - - G : NetworkX graph - The original graph for which the spanner was constructed. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - for u, v in G.edges(): - G[u][v]["weight"] = seed.random() - - -def test_spanner_trivial(): - """Test a trivial spanner with stretch 1.""" - G = nx.complete_graph(20) - spanner = nx.spanner(G, 1, seed=_seed) - - for u, v in G.edges: - assert spanner.has_edge(u, v) - - -def test_spanner_unweighted_complete_graph(): - """Test spanner construction on a complete unweighted graph.""" - G = nx.complete_graph(20) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_weighted_complete_graph(): - """Test spanner construction on a complete weighted graph.""" - G = nx.complete_graph(20) - _assign_random_weights(G, seed=_seed) - - spanner = nx.spanner(G, 4, weight="weight", seed=_seed) - _test_spanner(G, spanner, 4, weight="weight") - - spanner = nx.spanner(G, 10, weight="weight", seed=_seed) - _test_spanner(G, spanner, 10, weight="weight") - - -def test_spanner_unweighted_gnp_graph(): - """Test spanner construction on an unweighted gnp graph.""" - G = nx.gnp_random_graph(20, 0.4, seed=_seed) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_weighted_gnp_graph(): - """Test spanner construction on an weighted gnp graph.""" - G = nx.gnp_random_graph(20, 0.4, seed=_seed) - _assign_random_weights(G, seed=_seed) - - spanner = nx.spanner(G, 4, weight="weight", seed=_seed) - _test_spanner(G, spanner, 4, weight="weight") - - spanner = nx.spanner(G, 10, weight="weight", seed=_seed) - _test_spanner(G, spanner, 10, weight="weight") - - -def test_spanner_unweighted_disconnected_graph(): - """Test spanner construction on a disconnected graph.""" - G = nx.disjoint_union(nx.complete_graph(10), nx.complete_graph(10)) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_invalid_stretch(): - """Check whether an invalid stretch is caught.""" - with pytest.raises(ValueError): - G = nx.empty_graph() - nx.spanner(G, 0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_structuralholes.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_structuralholes.py deleted file mode 100644 index 1e5952b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_structuralholes.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.structuralholes` module.""" - -import math - -import pytest - -import networkx as nx -from networkx.classes.tests import dispatch_interface - - -class TestStructuralHoles: - """Unit tests for computing measures of structural holes. - - The expected values for these functions were originally computed using the - proprietary software `UCINET`_ and the free software `IGraph`_ , and then - computed by hand to make sure that the results are correct. - - .. _UCINET: https://sites.google.com/site/ucinetsoftware/home - .. _IGraph: http://igraph.org/ - - """ - - def setup_method(self): - self.D = nx.DiGraph() - self.D.add_edges_from([(0, 1), (0, 2), (1, 0), (2, 1)]) - self.D_weights = {(0, 1): 2, (0, 2): 2, (1, 0): 1, (2, 1): 1} - # Example from http://www.analytictech.com/connections/v20(1)/holes.htm - self.G = nx.Graph() - self.G.add_edges_from( - [ - ("A", "B"), - ("A", "F"), - ("A", "G"), - ("A", "E"), - ("E", "G"), - ("F", "G"), - ("B", "G"), - ("B", "D"), - ("D", "G"), - ("G", "C"), - ] - ) - self.G_weights = { - ("A", "B"): 2, - ("A", "F"): 3, - ("A", "G"): 5, - ("A", "E"): 2, - ("E", "G"): 8, - ("F", "G"): 3, - ("B", "G"): 4, - ("B", "D"): 1, - ("D", "G"): 3, - ("G", "C"): 10, - } - - def test_constraint_directed(self): - constraint = nx.constraint(self.D) - assert constraint[0] == pytest.approx(1.003, abs=1e-3) - assert constraint[1] == pytest.approx(1.003, abs=1e-3) - assert constraint[2] == pytest.approx(1.389, abs=1e-3) - - def test_effective_size_directed(self): - effective_size = nx.effective_size(self.D) - assert effective_size[0] == pytest.approx(1.167, abs=1e-3) - assert effective_size[1] == pytest.approx(1.167, abs=1e-3) - assert effective_size[2] == pytest.approx(1, abs=1e-3) - - def test_constraint_weighted_directed(self): - D = self.D.copy() - nx.set_edge_attributes(D, self.D_weights, "weight") - constraint = nx.constraint(D, weight="weight") - assert constraint[0] == pytest.approx(0.840, abs=1e-3) - assert constraint[1] == pytest.approx(1.143, abs=1e-3) - assert constraint[2] == pytest.approx(1.378, abs=1e-3) - - def test_effective_size_weighted_directed(self): - D = self.D.copy() - nx.set_edge_attributes(D, self.D_weights, "weight") - effective_size = nx.effective_size(D, weight="weight") - assert effective_size[0] == pytest.approx(1.567, abs=1e-3) - assert effective_size[1] == pytest.approx(1.083, abs=1e-3) - assert effective_size[2] == pytest.approx(1, abs=1e-3) - - def test_constraint_undirected(self): - constraint = nx.constraint(self.G) - assert constraint["G"] == pytest.approx(0.400, abs=1e-3) - assert constraint["A"] == pytest.approx(0.595, abs=1e-3) - assert constraint["C"] == pytest.approx(1, abs=1e-3) - - def test_effective_size_undirected_borgatti(self): - effective_size = nx.effective_size(self.G) - assert effective_size["G"] == pytest.approx(4.67, abs=1e-2) - assert effective_size["A"] == pytest.approx(2.50, abs=1e-2) - assert effective_size["C"] == pytest.approx(1, abs=1e-2) - - def test_effective_size_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, 1, "weight") - effective_size = nx.effective_size(G, weight="weight") - assert effective_size["G"] == pytest.approx(4.67, abs=1e-2) - assert effective_size["A"] == pytest.approx(2.50, abs=1e-2) - assert effective_size["C"] == pytest.approx(1, abs=1e-2) - - def test_constraint_weighted_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, self.G_weights, "weight") - constraint = nx.constraint(G, weight="weight") - assert constraint["G"] == pytest.approx(0.299, abs=1e-3) - assert constraint["A"] == pytest.approx(0.795, abs=1e-3) - assert constraint["C"] == pytest.approx(1, abs=1e-3) - - def test_effective_size_weighted_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, self.G_weights, "weight") - effective_size = nx.effective_size(G, weight="weight") - assert effective_size["G"] == pytest.approx(5.47, abs=1e-2) - assert effective_size["A"] == pytest.approx(2.47, abs=1e-2) - assert effective_size["C"] == pytest.approx(1, abs=1e-2) - - def test_constraint_isolated(self): - G = self.G.copy() - G.add_node(1) - constraint = nx.constraint(G) - assert math.isnan(constraint[1]) - - def test_effective_size_isolated(self): - G = self.G.copy() - G.add_node(1) - nx.set_edge_attributes(G, self.G_weights, "weight") - effective_size = nx.effective_size(G, weight="weight") - assert math.isnan(effective_size[1]) - - def test_effective_size_borgatti_isolated(self): - G = self.G.copy() - G.add_node(1) - effective_size = nx.effective_size(G) - assert math.isnan(effective_size[1]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_summarization.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_summarization.py deleted file mode 100644 index c3bf82f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_summarization.py +++ /dev/null @@ -1,642 +0,0 @@ -""" -Unit tests for dedensification and graph summarization -""" - -import pytest - -import networkx as nx - - -class TestDirectedDedensification: - def build_original_graph(self): - original_matrix = [ - ("1", "BC"), - ("2", "ABC"), - ("3", ["A", "B", "6"]), - ("4", "ABC"), - ("5", "AB"), - ("6", ["5"]), - ("A", ["6"]), - ] - graph = nx.DiGraph() - for source, targets in original_matrix: - for target in targets: - graph.add_edge(source, target) - return graph - - def build_compressed_graph(self): - compressed_matrix = [ - ("1", "BC"), - ("2", ["ABC"]), - ("3", ["A", "B", "6"]), - ("4", ["ABC"]), - ("5", "AB"), - ("6", ["5"]), - ("A", ["6"]), - ("ABC", "ABC"), - ] - compressed_graph = nx.DiGraph() - for source, targets in compressed_matrix: - for target in targets: - compressed_graph.add_edge(source, target) - return compressed_graph - - def test_empty(self): - """ - Verify that an empty directed graph results in no compressor nodes - """ - G = nx.DiGraph() - compressed_graph, c_nodes = nx.dedensify(G, threshold=2) - assert c_nodes == set() - - @staticmethod - def densify(G, compressor_nodes, copy=True): - """ - Reconstructs the original graph from a dedensified, directed graph - - Parameters - ---------- - G: dedensified graph - A networkx graph - compressor_nodes: iterable - Iterable of compressor nodes in the dedensified graph - inplace: bool, optional (default: False) - Indicates if densification should be done inplace - - Returns - ------- - G: graph - A densified networkx graph - """ - if copy: - G = G.copy() - for compressor_node in compressor_nodes: - all_neighbors = set(nx.all_neighbors(G, compressor_node)) - out_neighbors = set(G.neighbors(compressor_node)) - for out_neighbor in out_neighbors: - G.remove_edge(compressor_node, out_neighbor) - in_neighbors = all_neighbors - out_neighbors - for in_neighbor in in_neighbors: - G.remove_edge(in_neighbor, compressor_node) - for out_neighbor in out_neighbors: - G.add_edge(in_neighbor, out_neighbor) - G.remove_node(compressor_node) - return G - - def setup_method(self): - self.c_nodes = ("ABC",) - - def test_dedensify_edges(self): - """ - Verifies that dedensify produced the correct edges to/from compressor - nodes in a directed graph - """ - G = self.build_original_graph() - compressed_G = self.build_compressed_graph() - compressed_graph, c_nodes = nx.dedensify(G, threshold=2) - for s, t in compressed_graph.edges(): - o_s = "".join(sorted(s)) - o_t = "".join(sorted(t)) - compressed_graph_exists = compressed_graph.has_edge(s, t) - verified_compressed_exists = compressed_G.has_edge(o_s, o_t) - assert compressed_graph_exists == verified_compressed_exists - assert len(c_nodes) == len(self.c_nodes) - - def test_dedensify_edge_count(self): - """ - Verifies that dedensify produced the correct number of compressor nodes - in a directed graph - """ - G = self.build_original_graph() - original_edge_count = len(G.edges()) - c_G, c_nodes = nx.dedensify(G, threshold=2) - compressed_edge_count = len(c_G.edges()) - assert compressed_edge_count <= original_edge_count - compressed_G = self.build_compressed_graph() - assert compressed_edge_count == len(compressed_G.edges()) - - def test_densify_edges(self): - """ - Verifies that densification produces the correct edges from the - original directed graph - """ - compressed_G = self.build_compressed_graph() - original_graph = self.densify(compressed_G, self.c_nodes, copy=True) - G = self.build_original_graph() - for s, t in G.edges(): - assert G.has_edge(s, t) == original_graph.has_edge(s, t) - - def test_densify_edge_count(self): - """ - Verifies that densification produces the correct number of edges in the - original directed graph - """ - compressed_G = self.build_compressed_graph() - compressed_edge_count = len(compressed_G.edges()) - original_graph = self.densify(compressed_G, self.c_nodes) - original_edge_count = len(original_graph.edges()) - assert compressed_edge_count <= original_edge_count - G = self.build_original_graph() - assert original_edge_count == len(G.edges()) - - -class TestUnDirectedDedensification: - def build_original_graph(self): - """ - Builds graph shown in the original research paper - """ - original_matrix = [ - ("1", "CB"), - ("2", "ABC"), - ("3", ["A", "B", "6"]), - ("4", "ABC"), - ("5", "AB"), - ("6", ["5"]), - ("A", ["6"]), - ] - graph = nx.Graph() - for source, targets in original_matrix: - for target in targets: - graph.add_edge(source, target) - return graph - - def test_empty(self): - """ - Verify that an empty undirected graph results in no compressor nodes - """ - G = nx.Graph() - compressed_G, c_nodes = nx.dedensify(G, threshold=2) - assert c_nodes == set() - - def setup_method(self): - self.c_nodes = ("6AB", "ABC") - - def build_compressed_graph(self): - compressed_matrix = [ - ("1", ["B", "C"]), - ("2", ["ABC"]), - ("3", ["6AB"]), - ("4", ["ABC"]), - ("5", ["6AB"]), - ("6", ["6AB", "A"]), - ("A", ["6AB", "ABC"]), - ("B", ["ABC", "6AB"]), - ("C", ["ABC"]), - ] - compressed_graph = nx.Graph() - for source, targets in compressed_matrix: - for target in targets: - compressed_graph.add_edge(source, target) - return compressed_graph - - def test_dedensify_edges(self): - """ - Verifies that dedensify produced correct compressor nodes and the - correct edges to/from the compressor nodes in an undirected graph - """ - G = self.build_original_graph() - c_G, c_nodes = nx.dedensify(G, threshold=2) - v_compressed_G = self.build_compressed_graph() - for s, t in c_G.edges(): - o_s = "".join(sorted(s)) - o_t = "".join(sorted(t)) - has_compressed_edge = c_G.has_edge(s, t) - verified_has_compressed_edge = v_compressed_G.has_edge(o_s, o_t) - assert has_compressed_edge == verified_has_compressed_edge - assert len(c_nodes) == len(self.c_nodes) - - def test_dedensify_edge_count(self): - """ - Verifies that dedensify produced the correct number of edges in an - undirected graph - """ - G = self.build_original_graph() - c_G, c_nodes = nx.dedensify(G, threshold=2, copy=True) - compressed_edge_count = len(c_G.edges()) - verified_original_edge_count = len(G.edges()) - assert compressed_edge_count <= verified_original_edge_count - verified_compressed_G = self.build_compressed_graph() - verified_compressed_edge_count = len(verified_compressed_G.edges()) - assert compressed_edge_count == verified_compressed_edge_count - - -@pytest.mark.parametrize( - "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] -) -def test_summarization_empty(graph_type): - G = graph_type() - summary_graph = nx.snap_aggregation(G, node_attributes=("color",)) - assert nx.is_isomorphic(summary_graph, G) - - -class AbstractSNAP: - node_attributes = ("color",) - - def build_original_graph(self): - pass - - def build_summary_graph(self): - pass - - def test_summary_graph(self): - original_graph = self.build_original_graph() - summary_graph = self.build_summary_graph() - - relationship_attributes = ("type",) - generated_summary_graph = nx.snap_aggregation( - original_graph, self.node_attributes, relationship_attributes - ) - relabeled_summary_graph = self.deterministic_labels(generated_summary_graph) - assert nx.is_isomorphic(summary_graph, relabeled_summary_graph) - - def deterministic_labels(self, G): - node_labels = list(G.nodes) - node_labels = sorted(node_labels, key=lambda n: sorted(G.nodes[n]["group"])[0]) - node_labels.sort() - - label_mapping = {} - for index, node in enumerate(node_labels): - label = f"Supernode-{index}" - label_mapping[node] = label - - return nx.relabel_nodes(G, label_mapping) - - -class TestSNAPNoEdgeTypes(AbstractSNAP): - relationship_attributes = () - - def test_summary_graph(self): - original_graph = self.build_original_graph() - summary_graph = self.build_summary_graph() - - relationship_attributes = ("type",) - generated_summary_graph = nx.snap_aggregation( - original_graph, self.node_attributes - ) - relabeled_summary_graph = self.deterministic_labels(generated_summary_graph) - assert nx.is_isomorphic(summary_graph, relabeled_summary_graph) - - def build_original_graph(self): - nodes = { - "A": {"color": "Red"}, - "B": {"color": "Red"}, - "C": {"color": "Red"}, - "D": {"color": "Red"}, - "E": {"color": "Blue"}, - "F": {"color": "Blue"}, - "G": {"color": "Blue"}, - "H": {"color": "Blue"}, - "I": {"color": "Yellow"}, - "J": {"color": "Yellow"}, - "K": {"color": "Yellow"}, - "L": {"color": "Yellow"}, - } - edges = [ - ("A", "B"), - ("A", "C"), - ("A", "E"), - ("A", "I"), - ("B", "D"), - ("B", "J"), - ("B", "F"), - ("C", "G"), - ("D", "H"), - ("I", "J"), - ("J", "K"), - ("I", "L"), - ] - G = nx.Graph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target in edges: - G.add_edge(source, target) - - return G - - def build_summary_graph(self): - nodes = { - "Supernode-0": {"color": "Red"}, - "Supernode-1": {"color": "Red"}, - "Supernode-2": {"color": "Blue"}, - "Supernode-3": {"color": "Blue"}, - "Supernode-4": {"color": "Yellow"}, - "Supernode-5": {"color": "Yellow"}, - } - edges = [ - ("Supernode-0", "Supernode-0"), - ("Supernode-0", "Supernode-1"), - ("Supernode-0", "Supernode-2"), - ("Supernode-0", "Supernode-4"), - ("Supernode-1", "Supernode-3"), - ("Supernode-4", "Supernode-4"), - ("Supernode-4", "Supernode-5"), - ] - G = nx.Graph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target in edges: - G.add_edge(source, target) - - supernodes = { - "Supernode-0": {"A", "B"}, - "Supernode-1": {"C", "D"}, - "Supernode-2": {"E", "F"}, - "Supernode-3": {"G", "H"}, - "Supernode-4": {"I", "J"}, - "Supernode-5": {"K", "L"}, - } - nx.set_node_attributes(G, supernodes, "group") - return G - - -class TestSNAPUndirected(AbstractSNAP): - def build_original_graph(self): - nodes = { - "A": {"color": "Red"}, - "B": {"color": "Red"}, - "C": {"color": "Red"}, - "D": {"color": "Red"}, - "E": {"color": "Blue"}, - "F": {"color": "Blue"}, - "G": {"color": "Blue"}, - "H": {"color": "Blue"}, - "I": {"color": "Yellow"}, - "J": {"color": "Yellow"}, - "K": {"color": "Yellow"}, - "L": {"color": "Yellow"}, - } - edges = [ - ("A", "B", "Strong"), - ("A", "C", "Weak"), - ("A", "E", "Strong"), - ("A", "I", "Weak"), - ("B", "D", "Weak"), - ("B", "J", "Weak"), - ("B", "F", "Strong"), - ("C", "G", "Weak"), - ("D", "H", "Weak"), - ("I", "J", "Strong"), - ("J", "K", "Strong"), - ("I", "L", "Strong"), - ] - G = nx.Graph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, type in edges: - G.add_edge(source, target, type=type) - - return G - - def build_summary_graph(self): - nodes = { - "Supernode-0": {"color": "Red"}, - "Supernode-1": {"color": "Red"}, - "Supernode-2": {"color": "Blue"}, - "Supernode-3": {"color": "Blue"}, - "Supernode-4": {"color": "Yellow"}, - "Supernode-5": {"color": "Yellow"}, - } - edges = [ - ("Supernode-0", "Supernode-0", "Strong"), - ("Supernode-0", "Supernode-1", "Weak"), - ("Supernode-0", "Supernode-2", "Strong"), - ("Supernode-0", "Supernode-4", "Weak"), - ("Supernode-1", "Supernode-3", "Weak"), - ("Supernode-4", "Supernode-4", "Strong"), - ("Supernode-4", "Supernode-5", "Strong"), - ] - G = nx.Graph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, type in edges: - G.add_edge(source, target, types=[{"type": type}]) - - supernodes = { - "Supernode-0": {"A", "B"}, - "Supernode-1": {"C", "D"}, - "Supernode-2": {"E", "F"}, - "Supernode-3": {"G", "H"}, - "Supernode-4": {"I", "J"}, - "Supernode-5": {"K", "L"}, - } - nx.set_node_attributes(G, supernodes, "group") - return G - - -class TestSNAPDirected(AbstractSNAP): - def build_original_graph(self): - nodes = { - "A": {"color": "Red"}, - "B": {"color": "Red"}, - "C": {"color": "Green"}, - "D": {"color": "Green"}, - "E": {"color": "Blue"}, - "F": {"color": "Blue"}, - "G": {"color": "Yellow"}, - "H": {"color": "Yellow"}, - } - edges = [ - ("A", "C", "Strong"), - ("A", "E", "Strong"), - ("A", "F", "Weak"), - ("B", "D", "Strong"), - ("B", "E", "Weak"), - ("B", "F", "Strong"), - ("C", "G", "Strong"), - ("C", "F", "Strong"), - ("D", "E", "Strong"), - ("D", "H", "Strong"), - ("G", "E", "Strong"), - ("H", "F", "Strong"), - ] - G = nx.DiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, type in edges: - G.add_edge(source, target, type=type) - - return G - - def build_summary_graph(self): - nodes = { - "Supernode-0": {"color": "Red"}, - "Supernode-1": {"color": "Green"}, - "Supernode-2": {"color": "Blue"}, - "Supernode-3": {"color": "Yellow"}, - } - edges = [ - ("Supernode-0", "Supernode-1", [{"type": "Strong"}]), - ("Supernode-0", "Supernode-2", [{"type": "Weak"}, {"type": "Strong"}]), - ("Supernode-1", "Supernode-2", [{"type": "Strong"}]), - ("Supernode-1", "Supernode-3", [{"type": "Strong"}]), - ("Supernode-3", "Supernode-2", [{"type": "Strong"}]), - ] - G = nx.DiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, types in edges: - G.add_edge(source, target, types=types) - - supernodes = { - "Supernode-0": {"A", "B"}, - "Supernode-1": {"C", "D"}, - "Supernode-2": {"E", "F"}, - "Supernode-3": {"G", "H"}, - "Supernode-4": {"I", "J"}, - "Supernode-5": {"K", "L"}, - } - nx.set_node_attributes(G, supernodes, "group") - return G - - -class TestSNAPUndirectedMulti(AbstractSNAP): - def build_original_graph(self): - nodes = { - "A": {"color": "Red"}, - "B": {"color": "Red"}, - "C": {"color": "Red"}, - "D": {"color": "Blue"}, - "E": {"color": "Blue"}, - "F": {"color": "Blue"}, - "G": {"color": "Yellow"}, - "H": {"color": "Yellow"}, - "I": {"color": "Yellow"}, - } - edges = [ - ("A", "D", ["Weak", "Strong"]), - ("B", "E", ["Weak", "Strong"]), - ("D", "I", ["Strong"]), - ("E", "H", ["Strong"]), - ("F", "G", ["Weak"]), - ("I", "G", ["Weak", "Strong"]), - ("I", "H", ["Weak", "Strong"]), - ("G", "H", ["Weak", "Strong"]), - ] - G = nx.MultiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, types in edges: - for type in types: - G.add_edge(source, target, type=type) - - return G - - def build_summary_graph(self): - nodes = { - "Supernode-0": {"color": "Red"}, - "Supernode-1": {"color": "Blue"}, - "Supernode-2": {"color": "Yellow"}, - "Supernode-3": {"color": "Blue"}, - "Supernode-4": {"color": "Yellow"}, - "Supernode-5": {"color": "Red"}, - } - edges = [ - ("Supernode-1", "Supernode-2", [{"type": "Weak"}]), - ("Supernode-2", "Supernode-4", [{"type": "Weak"}, {"type": "Strong"}]), - ("Supernode-3", "Supernode-4", [{"type": "Strong"}]), - ("Supernode-3", "Supernode-5", [{"type": "Weak"}, {"type": "Strong"}]), - ("Supernode-4", "Supernode-4", [{"type": "Weak"}, {"type": "Strong"}]), - ] - G = nx.MultiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, types in edges: - for type in types: - G.add_edge(source, target, type=type) - - supernodes = { - "Supernode-0": {"A", "B"}, - "Supernode-1": {"C", "D"}, - "Supernode-2": {"E", "F"}, - "Supernode-3": {"G", "H"}, - "Supernode-4": {"I", "J"}, - "Supernode-5": {"K", "L"}, - } - nx.set_node_attributes(G, supernodes, "group") - return G - - -class TestSNAPDirectedMulti(AbstractSNAP): - def build_original_graph(self): - nodes = { - "A": {"color": "Red"}, - "B": {"color": "Red"}, - "C": {"color": "Green"}, - "D": {"color": "Green"}, - "E": {"color": "Blue"}, - "F": {"color": "Blue"}, - "G": {"color": "Yellow"}, - "H": {"color": "Yellow"}, - } - edges = [ - ("A", "C", ["Weak", "Strong"]), - ("A", "E", ["Strong"]), - ("A", "F", ["Weak"]), - ("B", "D", ["Weak", "Strong"]), - ("B", "E", ["Weak"]), - ("B", "F", ["Strong"]), - ("C", "G", ["Weak", "Strong"]), - ("C", "F", ["Strong"]), - ("D", "E", ["Strong"]), - ("D", "H", ["Weak", "Strong"]), - ("G", "E", ["Strong"]), - ("H", "F", ["Strong"]), - ] - G = nx.MultiDiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, types in edges: - for type in types: - G.add_edge(source, target, type=type) - - return G - - def build_summary_graph(self): - nodes = { - "Supernode-0": {"color": "Red"}, - "Supernode-1": {"color": "Blue"}, - "Supernode-2": {"color": "Yellow"}, - "Supernode-3": {"color": "Blue"}, - } - edges = [ - ("Supernode-0", "Supernode-1", ["Weak", "Strong"]), - ("Supernode-0", "Supernode-2", ["Weak", "Strong"]), - ("Supernode-1", "Supernode-2", ["Strong"]), - ("Supernode-1", "Supernode-3", ["Weak", "Strong"]), - ("Supernode-3", "Supernode-2", ["Strong"]), - ] - G = nx.MultiDiGraph() - for node in nodes: - attributes = nodes[node] - G.add_node(node, **attributes) - - for source, target, types in edges: - for type in types: - G.add_edge(source, target, type=type) - - supernodes = { - "Supernode-0": {"A", "B"}, - "Supernode-1": {"C", "D"}, - "Supernode-2": {"E", "F"}, - "Supernode-3": {"G", "H"}, - } - nx.set_node_attributes(G, supernodes, "group") - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_swap.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_swap.py deleted file mode 100644 index e765bd5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_swap.py +++ /dev/null @@ -1,179 +0,0 @@ -import pytest - -import networkx as nx - -cycle = nx.cycle_graph(5, create_using=nx.DiGraph) -tree = nx.DiGraph() -tree.add_edges_from(nx.random_labeled_tree(10, seed=42).edges) -path = nx.path_graph(5, create_using=nx.DiGraph) -binomial = nx.binomial_tree(3, create_using=nx.DiGraph) -HH = nx.directed_havel_hakimi_graph([1, 2, 1, 2, 2, 2], [3, 1, 0, 1, 2, 3]) -balanced_tree = nx.balanced_tree(2, 3, create_using=nx.DiGraph) - - -@pytest.mark.parametrize("G", [path, binomial, HH, cycle, tree, balanced_tree]) -def test_directed_edge_swap(G): - in_degree = set(G.in_degree) - out_degree = set(G.out_degree) - edges = set(G.edges) - nx.directed_edge_swap(G, nswap=1, max_tries=100, seed=1) - assert in_degree == set(G.in_degree) - assert out_degree == set(G.out_degree) - assert edges != set(G.edges) - assert 3 == sum(e not in edges for e in G.edges) - - -def test_directed_edge_swap_undo_previous_swap(): - G = nx.DiGraph(nx.path_graph(4).edges) # only 1 swap possible - edges = set(G.edges) - nx.directed_edge_swap(G, nswap=2, max_tries=100) - assert edges == set(G.edges) - - nx.directed_edge_swap(G, nswap=1, max_tries=100, seed=1) - assert {(0, 2), (1, 3), (2, 1)} == set(G.edges) - nx.directed_edge_swap(G, nswap=1, max_tries=100, seed=1) - assert edges == set(G.edges) - - -def test_edge_cases_directed_edge_swap(): - # Tests cases when swaps are impossible, either too few edges exist, or self loops/cycles are unavoidable - # TODO: Rewrite function to explicitly check for impossible swaps and raise error - e = ( - "Maximum number of swap attempts \\(11\\) exceeded " - "before desired swaps achieved \\(\\d\\)." - ) - graph = nx.DiGraph([(0, 0), (0, 1), (1, 0), (2, 3), (3, 2)]) - with pytest.raises(nx.NetworkXAlgorithmError, match=e): - nx.directed_edge_swap(graph, nswap=1, max_tries=10, seed=1) - - -def test_double_edge_swap(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.double_edge_swap(graph, 40) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_double_edge_swap_seed(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.double_edge_swap(graph, 40, seed=1) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_connected_double_edge_swap(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.connected_double_edge_swap(graph, 40, seed=1) - assert nx.is_connected(graph) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_connected_double_edge_swap_low_window_threshold(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.connected_double_edge_swap(graph, 40, _window_threshold=0, seed=1) - assert nx.is_connected(graph) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_connected_double_edge_swap_star(): - # Testing ui==xi in connected_double_edge_swap - graph = nx.star_graph(40) - degrees = sorted(d for n, d in graph.degree()) - G = nx.connected_double_edge_swap(graph, 1, seed=4) - assert nx.is_connected(graph) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_connected_double_edge_swap_star_low_window_threshold(): - # Testing ui==xi in connected_double_edge_swap with low window threshold - graph = nx.star_graph(40) - degrees = sorted(d for n, d in graph.degree()) - G = nx.connected_double_edge_swap(graph, 1, _window_threshold=0, seed=4) - assert nx.is_connected(graph) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_directed_edge_swap_small(): - with pytest.raises(nx.NetworkXError): - G = nx.directed_edge_swap(nx.path_graph(3, create_using=nx.DiGraph)) - - -def test_directed_edge_swap_tries(): - with pytest.raises(nx.NetworkXError): - G = nx.directed_edge_swap( - nx.path_graph(3, create_using=nx.DiGraph), nswap=1, max_tries=0 - ) - - -def test_directed_exception_undirected(): - graph = nx.Graph([(0, 1), (2, 3)]) - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.directed_edge_swap(graph) - - -def test_directed_edge_max_tries(): - with pytest.raises(nx.NetworkXAlgorithmError): - G = nx.directed_edge_swap( - nx.complete_graph(4, nx.DiGraph()), nswap=1, max_tries=5 - ) - - -def test_double_edge_swap_small(): - with pytest.raises(nx.NetworkXError): - G = nx.double_edge_swap(nx.path_graph(3)) - - -def test_double_edge_swap_tries(): - with pytest.raises(nx.NetworkXError): - G = nx.double_edge_swap(nx.path_graph(10), nswap=1, max_tries=0) - - -def test_double_edge_directed(): - graph = nx.DiGraph([(0, 1), (2, 3)]) - with pytest.raises(nx.NetworkXError, match="not defined for directed graphs."): - G = nx.double_edge_swap(graph) - - -def test_double_edge_max_tries(): - with pytest.raises(nx.NetworkXAlgorithmError): - G = nx.double_edge_swap(nx.complete_graph(4), nswap=1, max_tries=5) - - -def test_connected_double_edge_swap_small(): - with pytest.raises(nx.NetworkXError): - G = nx.connected_double_edge_swap(nx.path_graph(3)) - - -def test_connected_double_edge_swap_not_connected(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(3) - nx.add_path(G, [10, 11, 12]) - G = nx.connected_double_edge_swap(G) - - -def test_degree_seq_c4(): - G = nx.cycle_graph(4) - degrees = sorted(d for n, d in G.degree()) - G = nx.double_edge_swap(G, 1, 100) - assert degrees == sorted(d for n, d in G.degree()) - - -def test_fewer_than_4_nodes(): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2]) - with pytest.raises(nx.NetworkXError, match=".*fewer than four nodes."): - nx.directed_edge_swap(G) - - -def test_less_than_3_edges(): - G = nx.DiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([3, 4]) - with pytest.raises(nx.NetworkXError, match=".*fewer than 3 edges"): - nx.directed_edge_swap(G) - - G = nx.Graph() - G.add_nodes_from([0, 1, 2, 3]) - with pytest.raises(nx.NetworkXError, match=".*fewer than 2 edges"): - nx.double_edge_swap(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_threshold.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_threshold.py deleted file mode 100644 index 07aad44..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_threshold.py +++ /dev/null @@ -1,269 +0,0 @@ -""" -Threshold Graphs -================ -""" - -import pytest - -import networkx as nx -import networkx.algorithms.threshold as nxt -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic - -cnlti = nx.convert_node_labels_to_integers - - -class TestGeneratorThreshold: - def test_threshold_sequence_graph_test(self): - G = nx.star_graph(10) - assert nxt.is_threshold_graph(G) - assert nxt.is_threshold_sequence([d for n, d in G.degree()]) - - G = nx.complete_graph(10) - assert nxt.is_threshold_graph(G) - assert nxt.is_threshold_sequence([d for n, d in G.degree()]) - - deg = [3, 2, 2, 1, 1, 1] - assert not nxt.is_threshold_sequence(deg) - - deg = [3, 2, 2, 1] - assert nxt.is_threshold_sequence(deg) - - G = nx.generators.havel_hakimi_graph(deg) - assert nxt.is_threshold_graph(G) - - def test_creation_sequences(self): - deg = [3, 2, 2, 1] - G = nx.generators.havel_hakimi_graph(deg) - - with pytest.raises(ValueError): - nxt.creation_sequence(deg, with_labels=True, compact=True) - - cs0 = nxt.creation_sequence(deg) - H0 = nxt.threshold_graph(cs0) - assert "".join(cs0) == "ddid" - - cs1 = nxt.creation_sequence(deg, with_labels=True) - H1 = nxt.threshold_graph(cs1) - assert cs1 == [(1, "d"), (2, "d"), (3, "i"), (0, "d")] - - cs2 = nxt.creation_sequence(deg, compact=True) - H2 = nxt.threshold_graph(cs2) - assert cs2 == [2, 1, 1] - assert "".join(nxt.uncompact(cs2)) == "ddid" - assert graph_could_be_isomorphic(H0, G) - assert graph_could_be_isomorphic(H0, H1) - assert graph_could_be_isomorphic(H0, H2) - - def test_make_compact(self): - assert nxt.make_compact(["d", "d", "d", "i", "d", "d"]) == [3, 1, 2] - assert nxt.make_compact([3, 1, 2]) == [3, 1, 2] - assert pytest.raises(TypeError, nxt.make_compact, [3.0, 1.0, 2.0]) - - def test_uncompact(self): - assert nxt.uncompact([3, 1, 2]) == ["d", "d", "d", "i", "d", "d"] - assert nxt.uncompact(["d", "d", "i", "d"]) == ["d", "d", "i", "d"] - assert nxt.uncompact( - nxt.uncompact([(1, "d"), (2, "d"), (3, "i"), (0, "d")]) - ) == nxt.uncompact([(1, "d"), (2, "d"), (3, "i"), (0, "d")]) - assert pytest.raises(TypeError, nxt.uncompact, [3.0, 1.0, 2.0]) - - def test_creation_sequence_to_weights(self): - assert nxt.creation_sequence_to_weights([3, 1, 2]) == [ - 0.5, - 0.5, - 0.5, - 0.25, - 0.75, - 0.75, - ] - assert pytest.raises( - TypeError, nxt.creation_sequence_to_weights, [3.0, 1.0, 2.0] - ) - - def test_weights_to_creation_sequence(self): - deg = [3, 2, 2, 1] - with pytest.raises(ValueError): - nxt.weights_to_creation_sequence(deg, with_labels=True, compact=True) - assert nxt.weights_to_creation_sequence(deg, with_labels=True) == [ - (3, "d"), - (1, "d"), - (2, "d"), - (0, "d"), - ] - assert nxt.weights_to_creation_sequence(deg, compact=True) == [4] - - def test_find_alternating_4_cycle(self): - G = nx.Graph() - G.add_edge(1, 2) - assert not nxt.find_alternating_4_cycle(G) - - def test_shortest_path(self): - deg = [3, 2, 2, 1] - G = nx.generators.havel_hakimi_graph(deg) - cs1 = nxt.creation_sequence(deg, with_labels=True) - for n, m in [(3, 0), (0, 3), (0, 2), (0, 1), (1, 3), (3, 1), (1, 2), (2, 3)]: - assert nxt.shortest_path(cs1, n, m) == nx.shortest_path(G, n, m) - - spl = nxt.shortest_path_length(cs1, 3) - spl2 = nxt.shortest_path_length([t for v, t in cs1], 2) - assert spl == spl2 - - spld = {} - for j, pl in enumerate(spl): - n = cs1[j][0] - spld[n] = pl - assert spld == nx.single_source_shortest_path_length(G, 3) - - assert nxt.shortest_path(["d", "d", "d", "i", "d", "d"], 1, 2) == [1, 2] - assert nxt.shortest_path([3, 1, 2], 1, 2) == [1, 2] - assert pytest.raises(TypeError, nxt.shortest_path, [3.0, 1.0, 2.0], 1, 2) - assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], "a", 2) - assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], 1, "b") - assert nxt.shortest_path([3, 1, 2], 1, 1) == [1] - - def test_shortest_path_length(self): - assert nxt.shortest_path_length([3, 1, 2], 1) == [1, 0, 1, 2, 1, 1] - assert nxt.shortest_path_length(["d", "d", "d", "i", "d", "d"], 1) == [ - 1, - 0, - 1, - 2, - 1, - 1, - ] - assert nxt.shortest_path_length(("d", "d", "d", "i", "d", "d"), 1) == [ - 1, - 0, - 1, - 2, - 1, - 1, - ] - assert pytest.raises(TypeError, nxt.shortest_path, [3.0, 1.0, 2.0], 1) - - def test_random_threshold_sequence(self): - assert len(nxt.random_threshold_sequence(10, 0.5)) == 10 - assert nxt.random_threshold_sequence(10, 0.5, seed=42) == [ - "d", - "i", - "d", - "d", - "d", - "i", - "i", - "i", - "d", - "d", - ] - assert pytest.raises(ValueError, nxt.random_threshold_sequence, 10, 1.5) - - def test_right_d_threshold_sequence(self): - assert nxt.right_d_threshold_sequence(3, 2) == ["d", "i", "d"] - assert pytest.raises(ValueError, nxt.right_d_threshold_sequence, 2, 3) - - def test_left_d_threshold_sequence(self): - assert nxt.left_d_threshold_sequence(3, 2) == ["d", "i", "d"] - assert pytest.raises(ValueError, nxt.left_d_threshold_sequence, 2, 3) - - def test_weights_thresholds(self): - wseq = [3, 4, 3, 3, 5, 6, 5, 4, 5, 6] - cs = nxt.weights_to_creation_sequence(wseq, threshold=10) - wseq = nxt.creation_sequence_to_weights(cs) - cs2 = nxt.weights_to_creation_sequence(wseq) - assert cs == cs2 - - wseq = nxt.creation_sequence_to_weights(nxt.uncompact([3, 1, 2, 3, 3, 2, 3])) - assert wseq == [ - s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7] - ] - - wseq = nxt.creation_sequence_to_weights([3, 1, 2, 3, 3, 2, 3]) - assert wseq == [ - s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7] - ] - - wseq = nxt.creation_sequence_to_weights(list(enumerate("ddidiiidididi"))) - assert wseq == [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]] - - wseq = nxt.creation_sequence_to_weights("ddidiiidididi") - assert wseq == [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]] - - wseq = nxt.creation_sequence_to_weights("ddidiiidididid") - ws = [s / 12 for s in [6, 6, 5, 7, 4, 4, 4, 8, 3, 9, 2, 10, 1, 11]] - assert sum(abs(c - d) for c, d in zip(wseq, ws)) < 1e-14 - - def test_finding_routines(self): - G = nx.Graph({1: [2], 2: [3], 3: [4], 4: [5], 5: [6]}) - G.add_edge(2, 4) - G.add_edge(2, 5) - G.add_edge(2, 7) - G.add_edge(3, 6) - G.add_edge(4, 6) - - # Alternating 4 cycle - assert nxt.find_alternating_4_cycle(G) == [1, 2, 3, 6] - - # Threshold graph - TG = nxt.find_threshold_graph(G) - assert nxt.is_threshold_graph(TG) - assert sorted(TG.nodes()) == [1, 2, 3, 4, 5, 7] - - cs = nxt.creation_sequence(dict(TG.degree()), with_labels=True) - assert nxt.find_creation_sequence(G) == cs - - def test_fast_versions_properties_threshold_graphs(self): - cs = "ddiiddid" - G = nxt.threshold_graph(cs) - assert nxt.density("ddiiddid") == nx.density(G) - assert sorted(nxt.degree_sequence(cs)) == sorted(d for n, d in G.degree()) - - ts = nxt.triangle_sequence(cs) - assert ts == list(nx.triangles(G).values()) - assert sum(ts) // 3 == nxt.triangles(cs) - - c1 = nxt.cluster_sequence(cs) - c2 = list(nx.clustering(G).values()) - assert sum(abs(c - d) for c, d in zip(c1, c2)) == pytest.approx(0, abs=1e-7) - - b1 = nx.betweenness_centrality(G).values() - b2 = nxt.betweenness_sequence(cs) - assert sum(abs(c - d) for c, d in zip(b1, b2)) < 1e-7 - - assert nxt.eigenvalues(cs) == [0, 1, 3, 3, 5, 7, 7, 8] - - # Degree Correlation - assert abs(nxt.degree_correlation(cs) + 0.593038821954) < 1e-12 - assert nxt.degree_correlation("diiiddi") == -0.8 - assert nxt.degree_correlation("did") == -1.0 - assert nxt.degree_correlation("ddd") == 1.0 - assert nxt.eigenvalues("dddiii") == [0, 0, 0, 0, 3, 3] - assert nxt.eigenvalues("dddiiid") == [0, 1, 1, 1, 4, 4, 7] - - def test_tg_creation_routines(self): - s = nxt.left_d_threshold_sequence(5, 7) - s = nxt.right_d_threshold_sequence(5, 7) - s1 = nxt.swap_d(s, 1.0, 1.0) - s1 = nxt.swap_d(s, 1.0, 1.0, seed=1) - - def test_eigenvectors(self): - np = pytest.importorskip("numpy") - eigenval = np.linalg.eigvals - pytest.importorskip("scipy") - - cs = "ddiiddid" - G = nxt.threshold_graph(cs) - (tgeval, tgevec) = nxt.eigenvectors(cs) - np.testing.assert_allclose([np.dot(lv, lv) for lv in tgevec], 1.0, rtol=1e-9) - lapl = nx.laplacian_matrix(G) - - def test_create_using(self): - cs = "ddiiddid" - G = nxt.threshold_graph(cs) - assert pytest.raises( - nx.exception.NetworkXError, - nxt.threshold_graph, - cs, - create_using=nx.DiGraph(), - ) - MG = nxt.threshold_graph(cs, create_using=nx.MultiGraph()) - assert sorted(MG.edges()) == sorted(G.edges()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_time_dependent.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_time_dependent.py deleted file mode 100644 index 1e256f4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_time_dependent.py +++ /dev/null @@ -1,431 +0,0 @@ -"""Unit testing for time dependent algorithms.""" - -from datetime import datetime, timedelta - -import pytest - -import networkx as nx - -_delta = timedelta(days=5 * 365) - - -class TestCdIndex: - """Unit testing for the cd index function.""" - - def test_common_graph(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 1) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(1997, 1, 1)}, - 6: {"time": datetime(1998, 1, 1)}, - 7: {"time": datetime(1999, 1, 1)}, - 8: {"time": datetime(1999, 1, 1)}, - 9: {"time": datetime(1998, 1, 1)}, - 10: {"time": datetime(1997, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 4, time_delta=_delta) == 0.17 - - def test_common_graph_with_given_attributes(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 1) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"date": datetime(1992, 1, 1)}, - 1: {"date": datetime(1992, 1, 1)}, - 2: {"date": datetime(1993, 1, 1)}, - 3: {"date": datetime(1993, 1, 1)}, - 4: {"date": datetime(1995, 1, 1)}, - 5: {"date": datetime(1997, 1, 1)}, - 6: {"date": datetime(1998, 1, 1)}, - 7: {"date": datetime(1999, 1, 1)}, - 8: {"date": datetime(1999, 1, 1)}, - 9: {"date": datetime(1998, 1, 1)}, - 10: {"date": datetime(1997, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 4, time_delta=_delta, time="date") == 0.17 - - def test_common_graph_with_int_attributes(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 1) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": 20}, - 1: {"time": 20}, - 2: {"time": 30}, - 3: {"time": 30}, - 4: {"time": 50}, - 5: {"time": 70}, - 6: {"time": 80}, - 7: {"time": 90}, - 8: {"time": 90}, - 9: {"time": 80}, - 10: {"time": 74}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 4, time_delta=50) == 0.17 - - def test_common_graph_with_float_attributes(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 1) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": 20.2}, - 1: {"time": 20.2}, - 2: {"time": 30.7}, - 3: {"time": 30.7}, - 4: {"time": 50.9}, - 5: {"time": 70.1}, - 6: {"time": 80.6}, - 7: {"time": 90.7}, - 8: {"time": 90.7}, - 9: {"time": 80.6}, - 10: {"time": 74.2}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 4, time_delta=50) == 0.17 - - def test_common_graph_with_weights(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 1) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(1997, 1, 1)}, - 6: {"time": datetime(1998, 1, 1), "weight": 5}, - 7: {"time": datetime(1999, 1, 1), "weight": 2}, - 8: {"time": datetime(1999, 1, 1), "weight": 6}, - 9: {"time": datetime(1998, 1, 1), "weight": 3}, - 10: {"time": datetime(1997, 4, 1), "weight": 10}, - } - - nx.set_node_attributes(G, node_attrs) - assert nx.cd_index(G, 4, time_delta=_delta, weight="weight") == 0.04 - - def test_node_with_no_predecessors(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(2005, 1, 1)}, - 6: {"time": datetime(2010, 1, 1)}, - 7: {"time": datetime(2001, 1, 1)}, - 8: {"time": datetime(2020, 1, 1)}, - 9: {"time": datetime(2017, 1, 1)}, - 10: {"time": datetime(2004, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - assert nx.cd_index(G, 4, time_delta=_delta) == 0.0 - - def test_node_with_no_successors(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(8, 2) - G.add_edge(6, 0) - G.add_edge(6, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(1997, 1, 1)}, - 6: {"time": datetime(1998, 1, 1)}, - 7: {"time": datetime(1999, 1, 1)}, - 8: {"time": datetime(1999, 1, 1)}, - 9: {"time": datetime(1998, 1, 1)}, - 10: {"time": datetime(1997, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - assert nx.cd_index(G, 4, time_delta=_delta) == 1.0 - - def test_n_equals_zero(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 3) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(2005, 1, 1)}, - 6: {"time": datetime(2010, 1, 1)}, - 7: {"time": datetime(2001, 1, 1)}, - 8: {"time": datetime(2020, 1, 1)}, - 9: {"time": datetime(2017, 1, 1)}, - 10: {"time": datetime(2004, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - with pytest.raises( - nx.NetworkXError, match="The cd index cannot be defined." - ) as ve: - nx.cd_index(G, 4, time_delta=_delta) - - def test_time_timedelta_compatibility(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(4, 2) - G.add_edge(4, 0) - G.add_edge(4, 3) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": 20.2}, - 1: {"time": 20.2}, - 2: {"time": 30.7}, - 3: {"time": 30.7}, - 4: {"time": 50.9}, - 5: {"time": 70.1}, - 6: {"time": 80.6}, - 7: {"time": 90.7}, - 8: {"time": 90.7}, - 9: {"time": 80.6}, - 10: {"time": 74.2}, - } - - nx.set_node_attributes(G, node_attrs) - - with pytest.raises( - nx.NetworkXError, - match="Addition and comparison are not supported between", - ) as ve: - nx.cd_index(G, 4, time_delta=_delta) - - def test_node_with_no_time(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - G.add_edge(8, 2) - G.add_edge(6, 0) - G.add_edge(6, 3) - G.add_edge(5, 2) - G.add_edge(6, 2) - G.add_edge(6, 4) - G.add_edge(7, 4) - G.add_edge(8, 4) - G.add_edge(9, 4) - G.add_edge(9, 1) - G.add_edge(9, 3) - G.add_edge(10, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 6: {"time": datetime(1998, 1, 1)}, - 7: {"time": datetime(1999, 1, 1)}, - 8: {"time": datetime(1999, 1, 1)}, - 9: {"time": datetime(1998, 1, 1)}, - 10: {"time": datetime(1997, 4, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - with pytest.raises( - nx.NetworkXError, match="Not all nodes have a 'time' attribute." - ) as ve: - nx.cd_index(G, 4, time_delta=_delta) - - def test_maximally_consolidating(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) - G.add_edge(5, 1) - G.add_edge(5, 2) - G.add_edge(5, 3) - G.add_edge(5, 4) - G.add_edge(6, 1) - G.add_edge(6, 5) - G.add_edge(7, 1) - G.add_edge(7, 5) - G.add_edge(8, 2) - G.add_edge(8, 5) - G.add_edge(9, 5) - G.add_edge(9, 3) - G.add_edge(10, 5) - G.add_edge(10, 3) - G.add_edge(10, 4) - G.add_edge(11, 5) - G.add_edge(11, 4) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(1997, 1, 1)}, - 6: {"time": datetime(1998, 1, 1)}, - 7: {"time": datetime(1999, 1, 1)}, - 8: {"time": datetime(1999, 1, 1)}, - 9: {"time": datetime(1998, 1, 1)}, - 10: {"time": datetime(1997, 4, 1)}, - 11: {"time": datetime(1998, 5, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 5, time_delta=_delta) == -1 - - def test_maximally_destabilizing(self): - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) - G.add_edge(5, 1) - G.add_edge(5, 2) - G.add_edge(5, 3) - G.add_edge(5, 4) - G.add_edge(6, 5) - G.add_edge(7, 5) - G.add_edge(8, 5) - G.add_edge(9, 5) - G.add_edge(10, 5) - G.add_edge(11, 5) - - node_attrs = { - 0: {"time": datetime(1992, 1, 1)}, - 1: {"time": datetime(1992, 1, 1)}, - 2: {"time": datetime(1993, 1, 1)}, - 3: {"time": datetime(1993, 1, 1)}, - 4: {"time": datetime(1995, 1, 1)}, - 5: {"time": datetime(1997, 1, 1)}, - 6: {"time": datetime(1998, 1, 1)}, - 7: {"time": datetime(1999, 1, 1)}, - 8: {"time": datetime(1999, 1, 1)}, - 9: {"time": datetime(1998, 1, 1)}, - 10: {"time": datetime(1997, 4, 1)}, - 11: {"time": datetime(1998, 5, 1)}, - } - - nx.set_node_attributes(G, node_attrs) - - assert nx.cd_index(G, 5, time_delta=_delta) == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_tournament.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_tournament.py deleted file mode 100644 index e75abf8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_tournament.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.tournament` module.""" - -from itertools import combinations - -import pytest - -from networkx import DiGraph -from networkx.algorithms.tournament import ( - hamiltonian_path, - index_satisfying, - is_reachable, - is_strongly_connected, - is_tournament, - random_tournament, - score_sequence, - tournament_matrix, -) - - -def test_condition_not_satisfied(): - condition = lambda x: x > 0 - iter_in = [0] - assert index_satisfying(iter_in, condition) == 1 - - -def test_empty_iterable(): - condition = lambda x: x > 0 - with pytest.raises(ValueError): - index_satisfying([], condition) - - -def test_is_tournament(): - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - assert is_tournament(G) - - -def test_self_loops(): - """A tournament must have no self-loops.""" - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - G.add_edge(0, 0) - assert not is_tournament(G) - - -def test_missing_edges(): - """A tournament must not have any pair of nodes without at least - one edge joining the pair. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3)]) - assert not is_tournament(G) - - -def test_bidirectional_edges(): - """A tournament must not have any pair of nodes with greater - than one edge joining the pair. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - G.add_edge(1, 0) - assert not is_tournament(G) - - -def test_graph_is_tournament(): - for _ in range(10): - G = random_tournament(5) - assert is_tournament(G) - - -def test_graph_is_tournament_seed(): - for _ in range(10): - G = random_tournament(5, seed=1) - assert is_tournament(G) - - -def test_graph_is_tournament_one_node(): - G = random_tournament(1) - assert is_tournament(G) - - -def test_graph_is_tournament_zero_node(): - G = random_tournament(0) - assert is_tournament(G) - - -def test_hamiltonian_empty_graph(): - path = hamiltonian_path(DiGraph()) - assert len(path) == 0 - - -def test_path_is_hamiltonian(): - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - path = hamiltonian_path(G) - assert len(path) == 4 - assert all(v in G[u] for u, v in zip(path, path[1:])) - - -def test_hamiltonian_cycle(): - """Tests that :func:`networkx.tournament.hamiltonian_path` - returns a Hamiltonian cycle when provided a strongly connected - tournament. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - path = hamiltonian_path(G) - assert len(path) == 4 - assert all(v in G[u] for u, v in zip(path, path[1:])) - assert path[0] in G[path[-1]] - - -def test_score_sequence_edge(): - G = DiGraph([(0, 1)]) - assert score_sequence(G) == [0, 1] - - -def test_score_sequence_triangle(): - G = DiGraph([(0, 1), (1, 2), (2, 0)]) - assert score_sequence(G) == [1, 1, 1] - - -def test_tournament_matrix(): - np = pytest.importorskip("numpy") - pytest.importorskip("scipy") - npt = np.testing - G = DiGraph([(0, 1)]) - m = tournament_matrix(G) - npt.assert_array_equal(m.todense(), np.array([[0, 1], [-1, 0]])) - - -def test_reachable_pair(): - """Tests for a reachable pair of nodes.""" - G = DiGraph([(0, 1), (1, 2), (2, 0)]) - assert is_reachable(G, 0, 2) - - -def test_same_node_is_reachable(): - """Tests that a node is always reachable from it.""" - # G is an arbitrary tournament on ten nodes. - G = DiGraph(sorted(p) for p in combinations(range(10), 2)) - assert all(is_reachable(G, v, v) for v in G) - - -def test_unreachable_pair(): - """Tests for an unreachable pair of nodes.""" - G = DiGraph([(0, 1), (0, 2), (1, 2)]) - assert not is_reachable(G, 1, 0) - - -def test_is_strongly_connected(): - """Tests for a strongly connected tournament.""" - G = DiGraph([(0, 1), (1, 2), (2, 0)]) - assert is_strongly_connected(G) - - -def test_not_strongly_connected(): - """Tests for a tournament that is not strongly connected.""" - G = DiGraph([(0, 1), (0, 2), (1, 2)]) - assert not is_strongly_connected(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_triads.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_triads.py deleted file mode 100644 index 6267035..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_triads.py +++ /dev/null @@ -1,289 +0,0 @@ -"""Tests for the :mod:`networkx.algorithms.triads` module.""" - -import itertools -from collections import defaultdict -from random import sample - -import pytest - -import networkx as nx - - -def test_all_triplets_deprecated(): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - with pytest.deprecated_call(): - nx.all_triplets(G) - - -def test_random_triad_deprecated(): - G = nx.path_graph(3, create_using=nx.DiGraph) - with pytest.deprecated_call(): - nx.random_triad(G) - - -def test_triadic_census(): - """Tests the triadic_census function.""" - G = nx.DiGraph() - G.add_edges_from(["01", "02", "03", "04", "05", "12", "16", "51", "56", "65"]) - expected = { - "030T": 2, - "120C": 1, - "210": 0, - "120U": 0, - "012": 9, - "102": 3, - "021U": 0, - "111U": 0, - "003": 8, - "030C": 0, - "021D": 9, - "201": 0, - "111D": 1, - "300": 0, - "120D": 0, - "021C": 2, - } - actual = nx.triadic_census(G) - assert expected == actual - - -def test_is_triad(): - """Tests the is_triad function""" - G = nx.karate_club_graph() - G = G.to_directed() - for i in range(100): - nodes = sample(sorted(G.nodes()), 3) - G2 = G.subgraph(nodes) - assert nx.is_triad(G2) - - -def test_all_triplets(): - """Tests the all_triplets function.""" - G = nx.DiGraph() - G.add_edges_from(["01", "02", "03", "04", "05", "12", "16", "51", "56", "65"]) - expected = [ - f"{i},{j},{k}" - for i in range(7) - for j in range(i + 1, 7) - for k in range(j + 1, 7) - ] - expected = [set(x.split(",")) for x in expected] - actual = [set(x) for x in nx.all_triplets(G)] - assert all(any(s1 == s2 for s1 in expected) for s2 in actual) - - -def test_all_triads(): - """Tests the all_triplets function.""" - G = nx.DiGraph() - G.add_edges_from(["01", "02", "03", "04", "05", "12", "16", "51", "56", "65"]) - expected = [ - f"{i},{j},{k}" - for i in range(7) - for j in range(i + 1, 7) - for k in range(j + 1, 7) - ] - expected = [G.subgraph(x.split(",")) for x in expected] - actual = list(nx.all_triads(G)) - assert all(any(nx.is_isomorphic(G1, G2) for G1 in expected) for G2 in actual) - - -def test_triad_type(): - """Tests the triad_type function.""" - # 0 edges (1 type) - G = nx.DiGraph({0: [], 1: [], 2: []}) - assert nx.triad_type(G) == "003" - # 1 edge (1 type) - G = nx.DiGraph({0: [1], 1: [], 2: []}) - assert nx.triad_type(G) == "012" - # 2 edges (4 types) - G = nx.DiGraph([(0, 1), (0, 2)]) - assert nx.triad_type(G) == "021D" - G = nx.DiGraph({0: [1], 1: [0], 2: []}) - assert nx.triad_type(G) == "102" - G = nx.DiGraph([(0, 1), (2, 1)]) - assert nx.triad_type(G) == "021U" - G = nx.DiGraph([(0, 1), (1, 2)]) - assert nx.triad_type(G) == "021C" - # 3 edges (4 types) - G = nx.DiGraph([(0, 1), (1, 0), (2, 1)]) - assert nx.triad_type(G) == "111D" - G = nx.DiGraph([(0, 1), (1, 0), (1, 2)]) - assert nx.triad_type(G) == "111U" - G = nx.DiGraph([(0, 1), (1, 2), (0, 2)]) - assert nx.triad_type(G) == "030T" - G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - assert nx.triad_type(G) == "030C" - # 4 edges (4 types) - G = nx.DiGraph([(0, 1), (1, 0), (2, 0), (0, 2)]) - assert nx.triad_type(G) == "201" - G = nx.DiGraph([(0, 1), (1, 0), (2, 0), (2, 1)]) - assert nx.triad_type(G) == "120D" - G = nx.DiGraph([(0, 1), (1, 0), (0, 2), (1, 2)]) - assert nx.triad_type(G) == "120U" - G = nx.DiGraph([(0, 1), (1, 0), (0, 2), (2, 1)]) - assert nx.triad_type(G) == "120C" - # 5 edges (1 type) - G = nx.DiGraph([(0, 1), (1, 0), (2, 1), (1, 2), (0, 2)]) - assert nx.triad_type(G) == "210" - # 6 edges (1 type) - G = nx.DiGraph([(0, 1), (1, 0), (1, 2), (2, 1), (0, 2), (2, 0)]) - assert nx.triad_type(G) == "300" - - -def test_triads_by_type(): - """Tests the all_triplets function.""" - G = nx.DiGraph() - G.add_edges_from(["01", "02", "03", "04", "05", "12", "16", "51", "56", "65"]) - all_triads = nx.all_triads(G) - expected = defaultdict(list) - for triad in all_triads: - name = nx.triad_type(triad) - expected[name].append(triad) - actual = nx.triads_by_type(G) - assert set(actual.keys()) == set(expected.keys()) - for tri_type, actual_Gs in actual.items(): - expected_Gs = expected[tri_type] - for a in actual_Gs: - assert any(nx.is_isomorphic(a, e) for e in expected_Gs) - - -def test_random_triad(): - """Tests the random_triad function""" - G = nx.karate_club_graph() - G = G.to_directed() - for i in range(100): - assert nx.is_triad(nx.random_triad(G)) - - G = nx.DiGraph() - msg = "at least 3 nodes to form a triad" - with pytest.raises(nx.NetworkXError, match=msg): - nx.random_triad(G) - - -def test_triadic_census_short_path_nodelist(): - G = nx.path_graph("abc", create_using=nx.DiGraph) - expected = {"021C": 1} - for nl in ["a", "b", "c", "ab", "ac", "bc", "abc"]: - triad_census = nx.triadic_census(G, nodelist=nl) - assert expected == {typ: cnt for typ, cnt in triad_census.items() if cnt > 0} - - -def test_triadic_census_correct_nodelist_values(): - G = nx.path_graph(5, create_using=nx.DiGraph) - msg = r"nodelist includes duplicate nodes or nodes not in G" - with pytest.raises(ValueError, match=msg): - nx.triadic_census(G, [1, 2, 2, 3]) - with pytest.raises(ValueError, match=msg): - nx.triadic_census(G, [1, 2, "a", 3]) - - -def test_triadic_census_tiny_graphs(): - tc = nx.triadic_census(nx.empty_graph(0, create_using=nx.DiGraph)) - assert {} == {typ: cnt for typ, cnt in tc.items() if cnt > 0} - tc = nx.triadic_census(nx.empty_graph(1, create_using=nx.DiGraph)) - assert {} == {typ: cnt for typ, cnt in tc.items() if cnt > 0} - tc = nx.triadic_census(nx.empty_graph(2, create_using=nx.DiGraph)) - assert {} == {typ: cnt for typ, cnt in tc.items() if cnt > 0} - tc = nx.triadic_census(nx.DiGraph([(1, 2)])) - assert {} == {typ: cnt for typ, cnt in tc.items() if cnt > 0} - - -def test_triadic_census_selfloops(): - GG = nx.path_graph("abc", create_using=nx.DiGraph) - expected = {"021C": 1} - for n in GG: - G = GG.copy() - G.add_edge(n, n) - tc = nx.triadic_census(G) - assert expected == {typ: cnt for typ, cnt in tc.items() if cnt > 0} - - GG = nx.path_graph("abcde", create_using=nx.DiGraph) - tbt = nx.triads_by_type(GG) - for n in GG: - GG.add_edge(n, n) - tc = nx.triadic_census(GG) - assert tc == {tt: len(tbt[tt]) for tt in tc} - - -def test_triadic_census_four_path(): - G = nx.path_graph("abcd", create_using=nx.DiGraph) - expected = {"012": 2, "021C": 2} - triad_census = nx.triadic_census(G) - assert expected == {typ: cnt for typ, cnt in triad_census.items() if cnt > 0} - - -def test_triadic_census_four_path_nodelist(): - G = nx.path_graph("abcd", create_using=nx.DiGraph) - expected_end = {"012": 2, "021C": 1} - expected_mid = {"012": 1, "021C": 2} - a_triad_census = nx.triadic_census(G, nodelist=["a"]) - assert expected_end == {typ: cnt for typ, cnt in a_triad_census.items() if cnt > 0} - b_triad_census = nx.triadic_census(G, nodelist=["b"]) - assert expected_mid == {typ: cnt for typ, cnt in b_triad_census.items() if cnt > 0} - c_triad_census = nx.triadic_census(G, nodelist=["c"]) - assert expected_mid == {typ: cnt for typ, cnt in c_triad_census.items() if cnt > 0} - d_triad_census = nx.triadic_census(G, nodelist=["d"]) - assert expected_end == {typ: cnt for typ, cnt in d_triad_census.items() if cnt > 0} - - -def test_triadic_census_nodelist(): - """Tests the triadic_census function.""" - G = nx.DiGraph() - G.add_edges_from(["01", "02", "03", "04", "05", "12", "16", "51", "56", "65"]) - expected = { - "030T": 2, - "120C": 1, - "210": 0, - "120U": 0, - "012": 9, - "102": 3, - "021U": 0, - "111U": 0, - "003": 8, - "030C": 0, - "021D": 9, - "201": 0, - "111D": 1, - "300": 0, - "120D": 0, - "021C": 2, - } - actual = {k: 0 for k in expected} - for node in G.nodes(): - node_triad_census = nx.triadic_census(G, nodelist=[node]) - for triad_key in expected: - actual[triad_key] += node_triad_census[triad_key] - # Divide all counts by 3 - for k, v in actual.items(): - actual[k] //= 3 - assert expected == actual - - -@pytest.mark.parametrize("N", [5, 10]) -def test_triadic_census_on_random_graph(N): - G = nx.binomial_graph(N, 0.3, directed=True, seed=42) - tc1 = nx.triadic_census(G) - tbt = nx.triads_by_type(G) - tc2 = {tt: len(tbt[tt]) for tt in tc1} - assert tc1 == tc2 - - for n in G: - tc1 = nx.triadic_census(G, nodelist={n}) - tc2 = {tt: sum(1 for t in tbt.get(tt, []) if n in t) for tt in tc1} - assert tc1 == tc2 - - for ns in itertools.combinations(G, 2): - ns = set(ns) - tc1 = nx.triadic_census(G, nodelist=ns) - tc2 = { - tt: sum(1 for t in tbt.get(tt, []) if any(n in ns for n in t)) for tt in tc1 - } - assert tc1 == tc2 - - for ns in itertools.combinations(G, 3): - ns = set(ns) - tc1 = nx.triadic_census(G, nodelist=ns) - tc2 = { - tt: sum(1 for t in tbt.get(tt, []) if any(n in ns for n in t)) for tt in tc1 - } - assert tc1 == tc2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_vitality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_vitality.py deleted file mode 100644 index 248206e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_vitality.py +++ /dev/null @@ -1,41 +0,0 @@ -import networkx as nx - - -class TestClosenessVitality: - def test_unweighted(self): - G = nx.cycle_graph(3) - vitality = nx.closeness_vitality(G) - assert vitality == {0: 2, 1: 2, 2: 2} - - def test_weighted(self): - G = nx.Graph() - nx.add_cycle(G, [0, 1, 2], weight=2) - vitality = nx.closeness_vitality(G, weight="weight") - assert vitality == {0: 4, 1: 4, 2: 4} - - def test_unweighted_digraph(self): - G = nx.DiGraph(nx.cycle_graph(3)) - vitality = nx.closeness_vitality(G) - assert vitality == {0: 4, 1: 4, 2: 4} - - def test_weighted_digraph(self): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2], weight=2) - nx.add_cycle(G, [2, 1, 0], weight=2) - vitality = nx.closeness_vitality(G, weight="weight") - assert vitality == {0: 8, 1: 8, 2: 8} - - def test_weighted_multidigraph(self): - G = nx.MultiDiGraph() - nx.add_cycle(G, [0, 1, 2], weight=2) - nx.add_cycle(G, [2, 1, 0], weight=2) - vitality = nx.closeness_vitality(G, weight="weight") - assert vitality == {0: 8, 1: 8, 2: 8} - - def test_disconnecting_graph(self): - """Tests that the closeness vitality of a node whose removal - disconnects the graph is negative infinity. - - """ - G = nx.path_graph(3) - assert nx.closeness_vitality(G, node=1) == -float("inf") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_voronoi.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_voronoi.py deleted file mode 100644 index 3269ae6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_voronoi.py +++ /dev/null @@ -1,103 +0,0 @@ -import networkx as nx -from networkx.utils import pairwise - - -class TestVoronoiCells: - """Unit tests for the Voronoi cells function.""" - - def test_isolates(self): - """Tests that a graph with isolated nodes has all isolates in - one block of the partition. - - """ - G = nx.empty_graph(5) - cells = nx.voronoi_cells(G, {0, 2, 4}) - expected = {0: {0}, 2: {2}, 4: {4}, "unreachable": {1, 3}} - assert expected == cells - - def test_undirected_unweighted(self): - G = nx.cycle_graph(6) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 1, 5}, 3: {2, 3, 4}} - assert expected == cells - - def test_directed_unweighted(self): - # This is the singly-linked directed cycle graph on six nodes. - G = nx.DiGraph(pairwise(range(6), cyclic=True)) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 1, 2}, 3: {3, 4, 5}} - assert expected == cells - - def test_directed_inward(self): - """Tests that reversing the graph gives the "inward" Voronoi - partition. - - """ - # This is the singly-linked reverse directed cycle graph on six nodes. - G = nx.DiGraph(pairwise(range(6), cyclic=True)) - G = G.reverse(copy=False) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 4, 5}, 3: {1, 2, 3}} - assert expected == cells - - def test_undirected_weighted(self): - edges = [(0, 1, 10), (1, 2, 1), (2, 3, 1)] - G = nx.Graph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_directed_weighted(self): - edges = [(0, 1, 10), (1, 2, 1), (2, 3, 1), (3, 2, 1), (2, 1, 1)] - G = nx.DiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_multigraph_unweighted(self): - """Tests that the Voronoi cells for a multigraph are the same as - for a simple graph. - - """ - edges = [(0, 1), (1, 2), (2, 3)] - G = nx.MultiGraph(2 * edges) - H = nx.Graph(G) - G_cells = nx.voronoi_cells(G, {0, 3}) - H_cells = nx.voronoi_cells(H, {0, 3}) - assert G_cells == H_cells - - def test_multidigraph_unweighted(self): - # This is the twice-singly-linked directed cycle graph on six nodes. - edges = list(pairwise(range(6), cyclic=True)) - G = nx.MultiDiGraph(2 * edges) - H = nx.DiGraph(G) - G_cells = nx.voronoi_cells(G, {0, 3}) - H_cells = nx.voronoi_cells(H, {0, 3}) - assert G_cells == H_cells - - def test_multigraph_weighted(self): - edges = [(0, 1, 10), (0, 1, 10), (1, 2, 1), (1, 2, 100), (2, 3, 1), (2, 3, 100)] - G = nx.MultiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_multidigraph_weighted(self): - edges = [ - (0, 1, 10), - (0, 1, 10), - (1, 2, 1), - (2, 3, 1), - (3, 2, 10), - (3, 2, 1), - (2, 1, 10), - (2, 1, 1), - ] - G = nx.MultiDiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_walks.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_walks.py deleted file mode 100644 index 7a6b323..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_walks.py +++ /dev/null @@ -1,54 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.walks` module.""" - -import pytest - -import networkx as nx - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -def test_directed(): - G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - num_walks = nx.number_of_walks(G, 3) - expected = {0: {0: 1, 1: 0, 2: 0}, 1: {0: 0, 1: 1, 2: 0}, 2: {0: 0, 1: 0, 2: 1}} - assert num_walks == expected - - -def test_undirected(): - G = nx.cycle_graph(3) - num_walks = nx.number_of_walks(G, 3) - expected = {0: {0: 2, 1: 3, 2: 3}, 1: {0: 3, 1: 2, 2: 3}, 2: {0: 3, 1: 3, 2: 2}} - assert num_walks == expected - - -def test_non_integer_nodes(): - G = nx.DiGraph([("A", "B"), ("B", "C"), ("C", "A")]) - num_walks = nx.number_of_walks(G, 2) - expected = { - "A": {"A": 0, "B": 0, "C": 1}, - "B": {"A": 1, "B": 0, "C": 0}, - "C": {"A": 0, "B": 1, "C": 0}, - } - assert num_walks == expected - - -def test_zero_length(): - G = nx.cycle_graph(3) - num_walks = nx.number_of_walks(G, 0) - expected = {0: {0: 1, 1: 0, 2: 0}, 1: {0: 0, 1: 1, 2: 0}, 2: {0: 0, 1: 0, 2: 1}} - assert num_walks == expected - - -def test_negative_length_exception(): - G = nx.cycle_graph(3) - with pytest.raises(ValueError): - nx.number_of_walks(G, -1) - - -def test_hidden_weight_attr(): - G = nx.cycle_graph(3) - G.add_edge(1, 2, weight=5) - num_walks = nx.number_of_walks(G, 3) - expected = {0: {0: 2, 1: 3, 2: 3}, 1: {0: 3, 1: 2, 2: 3}, 2: {0: 3, 1: 3, 2: 2}} - assert num_walks == expected diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_wiener.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_wiener.py deleted file mode 100644 index aded951..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tests/test_wiener.py +++ /dev/null @@ -1,123 +0,0 @@ -import networkx as nx - - -def test_wiener_index_of_disconnected_graph(): - assert nx.wiener_index(nx.empty_graph(2)) == float("inf") - - -def test_wiener_index_of_directed_graph(): - G = nx.complete_graph(3) - H = nx.DiGraph(G) - assert (2 * nx.wiener_index(G)) == nx.wiener_index(H) - - -def test_wiener_index_of_complete_graph(): - n = 10 - G = nx.complete_graph(n) - assert nx.wiener_index(G) == (n * (n - 1) / 2) - - -def test_wiener_index_of_path_graph(): - # In P_n, there are n - 1 pairs of vertices at distance one, n - - # 2 pairs at distance two, n - 3 at distance three, ..., 1 at - # distance n - 1, so the Wiener index should be - # - # 1 * (n - 1) + 2 * (n - 2) + ... + (n - 2) * 2 + (n - 1) * 1 - # - # For example, in P_5, - # - # 1 * 4 + 2 * 3 + 3 * 2 + 4 * 1 = 2 (1 * 4 + 2 * 3) - # - # and in P_6, - # - # 1 * 5 + 2 * 4 + 3 * 3 + 4 * 2 + 5 * 1 = 2 (1 * 5 + 2 * 4) + 3 * 3 - # - # assuming n is *odd*, this gives the formula - # - # 2 \sum_{i = 1}^{(n - 1) / 2} [i * (n - i)] - # - # assuming n is *even*, this gives the formula - # - # 2 \sum_{i = 1}^{n / 2} [i * (n - i)] - (n / 2) ** 2 - # - n = 9 - G = nx.path_graph(n) - expected = 2 * sum(i * (n - i) for i in range(1, (n // 2) + 1)) - actual = nx.wiener_index(G) - assert expected == actual - - -def test_schultz_and_gutman_index_of_disconnected_graph(): - n = 4 - G = nx.Graph() - G.add_nodes_from(list(range(1, n + 1))) - expected = float("inf") - - G.add_edge(1, 2) - G.add_edge(3, 4) - - actual_1 = nx.schultz_index(G) - actual_2 = nx.gutman_index(G) - - assert expected == actual_1 - assert expected == actual_2 - - -def test_schultz_and_gutman_index_of_complete_bipartite_graph_1(): - n = 3 - m = 3 - cbg = nx.complete_bipartite_graph(n, m) - - expected_1 = n * m * (n + m) + 2 * n * (n - 1) * m + 2 * m * (m - 1) * n - actual_1 = nx.schultz_index(cbg) - - expected_2 = n * m * (n * m) + n * (n - 1) * m * m + m * (m - 1) * n * n - actual_2 = nx.gutman_index(cbg) - - assert expected_1 == actual_1 - assert expected_2 == actual_2 - - -def test_schultz_and_gutman_index_of_complete_bipartite_graph_2(): - n = 2 - m = 5 - cbg = nx.complete_bipartite_graph(n, m) - - expected_1 = n * m * (n + m) + 2 * n * (n - 1) * m + 2 * m * (m - 1) * n - actual_1 = nx.schultz_index(cbg) - - expected_2 = n * m * (n * m) + n * (n - 1) * m * m + m * (m - 1) * n * n - actual_2 = nx.gutman_index(cbg) - - assert expected_1 == actual_1 - assert expected_2 == actual_2 - - -def test_schultz_and_gutman_index_of_complete_graph(): - n = 5 - cg = nx.complete_graph(n) - - expected_1 = n * (n - 1) * (n - 1) - actual_1 = nx.schultz_index(cg) - - assert expected_1 == actual_1 - - expected_2 = n * (n - 1) * (n - 1) * (n - 1) / 2 - actual_2 = nx.gutman_index(cg) - - assert expected_2 == actual_2 - - -def test_schultz_and_gutman_index_of_odd_cycle_graph(): - k = 5 - n = 2 * k + 1 - ocg = nx.cycle_graph(n) - - expected_1 = 2 * n * k * (k + 1) - actual_1 = nx.schultz_index(ocg) - - expected_2 = 2 * n * k * (k + 1) - actual_2 = nx.gutman_index(ocg) - - assert expected_1 == actual_1 - assert expected_2 == actual_2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/threshold.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/threshold.py deleted file mode 100644 index e8fb8ef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/threshold.py +++ /dev/null @@ -1,980 +0,0 @@ -""" -Threshold Graphs - Creation, manipulation and identification. -""" - -from math import sqrt - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ["is_threshold_graph", "find_threshold_graph"] - - -@nx._dispatchable -def is_threshold_graph(G): - """ - Returns `True` if `G` is a threshold graph. - - Parameters - ---------- - G : NetworkX graph instance - An instance of `Graph`, `DiGraph`, `MultiGraph` or `MultiDiGraph` - - Returns - ------- - bool - `True` if `G` is a threshold graph, `False` otherwise. - - Examples - -------- - >>> from networkx.algorithms.threshold import is_threshold_graph - >>> G = nx.path_graph(3) - >>> is_threshold_graph(G) - True - >>> G = nx.barbell_graph(3, 3) - >>> is_threshold_graph(G) - False - - References - ---------- - .. [1] Threshold graphs: https://en.wikipedia.org/wiki/Threshold_graph - """ - return is_threshold_sequence([d for n, d in G.degree()]) - - -def is_threshold_sequence(degree_sequence): - """ - Returns True if the sequence is a threshold degree sequence. - - Uses the property that a threshold graph must be constructed by - adding either dominating or isolated nodes. Thus, it can be - deconstructed iteratively by removing a node of degree zero or a - node that connects to the remaining nodes. If this deconstruction - fails then the sequence is not a threshold sequence. - """ - ds = degree_sequence[:] # get a copy so we don't destroy original - ds.sort() - while ds: - if ds[0] == 0: # if isolated node - ds.pop(0) # remove it - continue - if ds[-1] != len(ds) - 1: # is the largest degree node dominating? - return False # no, not a threshold degree sequence - ds.pop() # yes, largest is the dominating node - ds = [d - 1 for d in ds] # remove it and decrement all degrees - return True - - -def creation_sequence(degree_sequence, with_labels=False, compact=False): - """ - Determines the creation sequence for the given threshold degree sequence. - - The creation sequence is a list of single characters 'd' - or 'i': 'd' for dominating or 'i' for isolated vertices. - Dominating vertices are connected to all vertices present when it - is added. The first node added is by convention 'd'. - This list can be converted to a string if desired using "".join(cs) - - If with_labels==True: - Returns a list of 2-tuples containing the vertex number - and a character 'd' or 'i' which describes the type of vertex. - - If compact==True: - Returns the creation sequence in a compact form that is the number - of 'i's and 'd's alternating. - Examples: - [1,2,2,3] represents d,i,i,d,d,i,i,i - [3,1,2] represents d,d,d,i,d,d - - Notice that the first number is the first vertex to be used for - construction and so is always 'd'. - - with_labels and compact cannot both be True. - - Returns None if the sequence is not a threshold sequence - """ - if with_labels and compact: - raise ValueError("compact sequences cannot be labeled") - - # make an indexed copy - if isinstance(degree_sequence, dict): # labeled degree sequence - ds = [[degree, label] for (label, degree) in degree_sequence.items()] - else: - ds = [[d, i] for i, d in enumerate(degree_sequence)] - ds.sort() - cs = [] # creation sequence - while ds: - if ds[0][0] == 0: # isolated node - (d, v) = ds.pop(0) - if len(ds) > 0: # make sure we start with a d - cs.insert(0, (v, "i")) - else: - cs.insert(0, (v, "d")) - continue - if ds[-1][0] != len(ds) - 1: # Not dominating node - return None # not a threshold degree sequence - (d, v) = ds.pop() - cs.insert(0, (v, "d")) - ds = [[d[0] - 1, d[1]] for d in ds] # decrement due to removing node - - if with_labels: - return cs - if compact: - return make_compact(cs) - return [v[1] for v in cs] # not labeled - - -def make_compact(creation_sequence): - """ - Returns the creation sequence in a compact form - that is the number of 'i's and 'd's alternating. - - Examples - -------- - >>> from networkx.algorithms.threshold import make_compact - >>> make_compact(["d", "i", "i", "d", "d", "i", "i", "i"]) - [1, 2, 2, 3] - >>> make_compact(["d", "d", "d", "i", "d", "d"]) - [3, 1, 2] - - Notice that the first number is the first vertex - to be used for construction and so is always 'd'. - - Labeled creation sequences lose their labels in the - compact representation. - - >>> make_compact([3, 1, 2]) - [3, 1, 2] - """ - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - cs = creation_sequence[:] - elif isinstance(first, tuple): # labeled creation sequence - cs = [s[1] for s in creation_sequence] - elif isinstance(first, int): # compact creation sequence - return creation_sequence - else: - raise TypeError("Not a valid creation sequence type") - - ccs = [] - count = 1 # count the run lengths of d's or i's. - for i in range(1, len(cs)): - if cs[i] == cs[i - 1]: - count += 1 - else: - ccs.append(count) - count = 1 - ccs.append(count) # don't forget the last one - return ccs - - -def uncompact(creation_sequence): - """ - Converts a compact creation sequence for a threshold - graph to a standard creation sequence (unlabeled). - If the creation_sequence is already standard, return it. - See creation_sequence. - """ - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - return creation_sequence - elif isinstance(first, tuple): # labeled creation sequence - return creation_sequence - elif isinstance(first, int): # compact creation sequence - ccscopy = creation_sequence[:] - else: - raise TypeError("Not a valid creation sequence type") - cs = [] - while ccscopy: - cs.extend(ccscopy.pop(0) * ["d"]) - if ccscopy: - cs.extend(ccscopy.pop(0) * ["i"]) - return cs - - -def creation_sequence_to_weights(creation_sequence): - """ - Returns a list of node weights which create the threshold - graph designated by the creation sequence. The weights - are scaled so that the threshold is 1.0. The order of the - nodes is the same as that in the creation sequence. - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - if isinstance(creation_sequence, list): - wseq = creation_sequence[:] - else: - wseq = list(creation_sequence) # string like 'ddidid' - elif isinstance(first, tuple): # labeled creation sequence - wseq = [v[1] for v in creation_sequence] - elif isinstance(first, int): # compact creation sequence - wseq = uncompact(creation_sequence) - else: - raise TypeError("Not a valid creation sequence type") - # pass through twice--first backwards - wseq.reverse() - w = 0 - prev = "i" - for j, s in enumerate(wseq): - if s == "i": - wseq[j] = w - prev = s - elif prev == "i": - prev = s - w += 1 - wseq.reverse() # now pass through forwards - for j, s in enumerate(wseq): - if s == "d": - wseq[j] = w - prev = s - elif prev == "d": - prev = s - w += 1 - # Now scale weights - if prev == "d": - w += 1 - wscale = 1 / w - return [ww * wscale for ww in wseq] - # return wseq - - -def weights_to_creation_sequence( - weights, threshold=1, with_labels=False, compact=False -): - """ - Returns a creation sequence for a threshold graph - determined by the weights and threshold given as input. - If the sum of two node weights is greater than the - threshold value, an edge is created between these nodes. - - The creation sequence is a list of single characters 'd' - or 'i': 'd' for dominating or 'i' for isolated vertices. - Dominating vertices are connected to all vertices present - when it is added. The first node added is by convention 'd'. - - If with_labels==True: - Returns a list of 2-tuples containing the vertex number - and a character 'd' or 'i' which describes the type of vertex. - - If compact==True: - Returns the creation sequence in a compact form that is the number - of 'i's and 'd's alternating. - Examples: - [1,2,2,3] represents d,i,i,d,d,i,i,i - [3,1,2] represents d,d,d,i,d,d - - Notice that the first number is the first vertex to be used for - construction and so is always 'd'. - - with_labels and compact cannot both be True. - """ - if with_labels and compact: - raise ValueError("compact sequences cannot be labeled") - - # make an indexed copy - if isinstance(weights, dict): # labeled weights - wseq = [[w, label] for (label, w) in weights.items()] - else: - wseq = [[w, i] for i, w in enumerate(weights)] - wseq.sort() - cs = [] # creation sequence - cutoff = threshold - wseq[-1][0] - while wseq: - if wseq[0][0] < cutoff: # isolated node - (w, label) = wseq.pop(0) - cs.append((label, "i")) - else: - (w, label) = wseq.pop() - cs.append((label, "d")) - cutoff = threshold - wseq[-1][0] - if len(wseq) == 1: # make sure we start with a d - (w, label) = wseq.pop() - cs.append((label, "d")) - # put in correct order - cs.reverse() - - if with_labels: - return cs - if compact: - return make_compact(cs) - return [v[1] for v in cs] # not labeled - - -# Manipulating NetworkX.Graphs in context of threshold graphs -@nx._dispatchable(graphs=None, returns_graph=True) -def threshold_graph(creation_sequence, create_using=None): - """ - Create a threshold graph from the creation sequence or compact - creation_sequence. - - The input sequence can be a - - creation sequence (e.g. ['d','i','d','d','d','i']) - labeled creation sequence (e.g. [(0,'d'),(2,'d'),(1,'i')]) - compact creation sequence (e.g. [2,1,1,2,0]) - - Use cs=creation_sequence(degree_sequence,labeled=True) - to convert a degree sequence to a creation sequence. - - Returns None if the sequence is not valid - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - ci = list(enumerate(creation_sequence)) - elif isinstance(first, tuple): # labeled creation sequence - ci = creation_sequence[:] - elif isinstance(first, int): # compact creation sequence - cs = uncompact(creation_sequence) - ci = list(enumerate(cs)) - else: - print("not a valid creation sequence type") - return None - - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - G.name = "Threshold Graph" - - # add nodes and edges - # if type is 'i' just add nodea - # if type is a d connect to everything previous - while ci: - (v, node_type) = ci.pop(0) - if node_type == "d": # dominating type, connect to all existing nodes - # We use `for u in list(G):` instead of - # `for u in G:` because we edit the graph `G` in - # the loop. Hence using an iterator will result in - # `RuntimeError: dictionary changed size during iteration` - for u in list(G): - G.add_edge(v, u) - G.add_node(v) - return G - - -@nx._dispatchable -def find_alternating_4_cycle(G): - """ - Returns False if there aren't any alternating 4 cycles. - Otherwise returns the cycle as [a,b,c,d] where (a,b) - and (c,d) are edges and (a,c) and (b,d) are not. - """ - for u, v in G.edges(): - for w in G.nodes(): - if not G.has_edge(u, w) and u != w: - for x in G.neighbors(w): - if not G.has_edge(v, x) and v != x: - return [u, v, w, x] - return False - - -@nx._dispatchable(returns_graph=True) -def find_threshold_graph(G, create_using=None): - """ - Returns a threshold subgraph that is close to largest in `G`. - - The threshold graph will contain the largest degree node in G. - - Parameters - ---------- - G : NetworkX graph instance - An instance of `Graph`, or `MultiDiGraph` - create_using : NetworkX graph class or `None` (default), optional - Type of graph to use when constructing the threshold graph. - If `None`, infer the appropriate graph type from the input. - - Returns - ------- - graph : - A graph instance representing the threshold graph - - Examples - -------- - >>> from networkx.algorithms.threshold import find_threshold_graph - >>> G = nx.barbell_graph(3, 3) - >>> T = find_threshold_graph(G) - >>> T.nodes # may vary - NodeView((7, 8, 5, 6)) - - References - ---------- - .. [1] Threshold graphs: https://en.wikipedia.org/wiki/Threshold_graph - """ - return threshold_graph(find_creation_sequence(G), create_using) - - -@nx._dispatchable -def find_creation_sequence(G): - """ - Find a threshold subgraph that is close to largest in G. - Returns the labeled creation sequence of that threshold graph. - """ - cs = [] - # get a local pointer to the working part of the graph - H = G - while H.order() > 0: - # get new degree sequence on subgraph - dsdict = dict(H.degree()) - ds = [(d, v) for v, d in dsdict.items()] - ds.sort() - # Update threshold graph nodes - if ds[-1][0] == 0: # all are isolated - cs.extend(zip(dsdict, ["i"] * (len(ds) - 1) + ["d"])) - break # Done! - # pull off isolated nodes - while ds[0][0] == 0: - (d, iso) = ds.pop(0) - cs.append((iso, "i")) - # find new biggest node - (d, bigv) = ds.pop() - # add edges of star to t_g - cs.append((bigv, "d")) - # form subgraph of neighbors of big node - H = H.subgraph(H.neighbors(bigv)) - cs.reverse() - return cs - - -# Properties of Threshold Graphs -def triangles(creation_sequence): - """ - Compute number of triangles in the threshold graph with the - given creation sequence. - """ - # shortcut algorithm that doesn't require computing number - # of triangles at each node. - cs = creation_sequence # alias - dr = cs.count("d") # number of d's in sequence - ntri = dr * (dr - 1) * (dr - 2) / 6 # number of triangles in clique of nd d's - # now add dr choose 2 triangles for every 'i' in sequence where - # dr is the number of d's to the right of the current i - for i, typ in enumerate(cs): - if typ == "i": - ntri += dr * (dr - 1) / 2 - else: - dr -= 1 - return ntri - - -def triangle_sequence(creation_sequence): - """ - Return triangle sequence for the given threshold graph creation sequence. - - """ - cs = creation_sequence - seq = [] - dr = cs.count("d") # number of d's to the right of the current pos - dcur = (dr - 1) * (dr - 2) // 2 # number of triangles through a node of clique dr - irun = 0 # number of i's in the last run - drun = 0 # number of d's in the last run - for i, sym in enumerate(cs): - if sym == "d": - drun += 1 - tri = dcur + (dr - 1) * irun # new triangles at this d - else: # cs[i]="i": - if prevsym == "d": # new string of i's - dcur += (dr - 1) * irun # accumulate shared shortest paths - irun = 0 # reset i run counter - dr -= drun # reduce number of d's to right - drun = 0 # reset d run counter - irun += 1 - tri = dr * (dr - 1) // 2 # new triangles at this i - seq.append(tri) - prevsym = sym - return seq - - -def cluster_sequence(creation_sequence): - """ - Return cluster sequence for the given threshold graph creation sequence. - """ - triseq = triangle_sequence(creation_sequence) - degseq = degree_sequence(creation_sequence) - cseq = [] - for i, deg in enumerate(degseq): - tri = triseq[i] - if deg <= 1: # isolated vertex or single pair gets cc 0 - cseq.append(0) - continue - max_size = (deg * (deg - 1)) // 2 - cseq.append(tri / max_size) - return cseq - - -def degree_sequence(creation_sequence): - """ - Return degree sequence for the threshold graph with the given - creation sequence - """ - cs = creation_sequence # alias - seq = [] - rd = cs.count("d") # number of d to the right - for i, sym in enumerate(cs): - if sym == "d": - rd -= 1 - seq.append(rd + i) - else: - seq.append(rd) - return seq - - -def density(creation_sequence): - """ - Return the density of the graph with this creation_sequence. - The density is the fraction of possible edges present. - """ - N = len(creation_sequence) - two_size = sum(degree_sequence(creation_sequence)) - two_possible = N * (N - 1) - den = two_size / two_possible - return den - - -def degree_correlation(creation_sequence): - """ - Return the degree-degree correlation over all edges. - """ - cs = creation_sequence - s1 = 0 # deg_i*deg_j - s2 = 0 # deg_i^2+deg_j^2 - s3 = 0 # deg_i+deg_j - m = 0 # number of edges - rd = cs.count("d") # number of d nodes to the right - rdi = [i for i, sym in enumerate(cs) if sym == "d"] # index of "d"s - ds = degree_sequence(cs) - for i, sym in enumerate(cs): - if sym == "d": - if i != rdi[0]: - print("Logic error in degree_correlation", i, rdi) - raise ValueError - rdi.pop(0) - degi = ds[i] - for dj in rdi: - degj = ds[dj] - s1 += degj * degi - s2 += degi**2 + degj**2 - s3 += degi + degj - m += 1 - denom = 2 * m * s2 - s3 * s3 - numer = 4 * m * s1 - s3 * s3 - if denom == 0: - if numer == 0: - return 1 - raise ValueError(f"Zero Denominator but Numerator is {numer}") - return numer / denom - - -def shortest_path(creation_sequence, u, v): - """ - Find the shortest path between u and v in a - threshold graph G with the given creation_sequence. - - For an unlabeled creation_sequence, the vertices - u and v must be integers in (0,len(sequence)) referring - to the position of the desired vertices in the sequence. - - For a labeled creation_sequence, u and v are labels of vertices. - - Use cs=creation_sequence(degree_sequence,with_labels=True) - to convert a degree sequence to a creation sequence. - - Returns a list of vertices from u to v. - Example: if they are neighbors, it returns [u,v] - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - cs = [(i, creation_sequence[i]) for i in range(len(creation_sequence))] - elif isinstance(first, tuple): # labeled creation sequence - cs = creation_sequence[:] - elif isinstance(first, int): # compact creation sequence - ci = uncompact(creation_sequence) - cs = [(i, ci[i]) for i in range(len(ci))] - else: - raise TypeError("Not a valid creation sequence type") - - verts = [s[0] for s in cs] - if v not in verts: - raise ValueError(f"Vertex {v} not in graph from creation_sequence") - if u not in verts: - raise ValueError(f"Vertex {u} not in graph from creation_sequence") - # Done checking - if u == v: - return [u] - - uindex = verts.index(u) - vindex = verts.index(v) - bigind = max(uindex, vindex) - if cs[bigind][1] == "d": - return [u, v] - # must be that cs[bigind][1]=='i' - cs = cs[bigind:] - while cs: - vert = cs.pop() - if vert[1] == "d": - return [u, vert[0], v] - # All after u are type 'i' so no connection - return -1 - - -def shortest_path_length(creation_sequence, i): - """ - Return the shortest path length from indicated node to - every other node for the threshold graph with the given - creation sequence. - Node is indicated by index i in creation_sequence unless - creation_sequence is labeled in which case, i is taken to - be the label of the node. - - Paths lengths in threshold graphs are at most 2. - Length to unreachable nodes is set to -1. - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - if isinstance(creation_sequence, list): - cs = creation_sequence[:] - else: - cs = list(creation_sequence) - elif isinstance(first, tuple): # labeled creation sequence - cs = [v[1] for v in creation_sequence] - i = [v[0] for v in creation_sequence].index(i) - elif isinstance(first, int): # compact creation sequence - cs = uncompact(creation_sequence) - else: - raise TypeError("Not a valid creation sequence type") - - # Compute - N = len(cs) - spl = [2] * N # length 2 to every node - spl[i] = 0 # except self which is 0 - # 1 for all d's to the right - for j in range(i + 1, N): - if cs[j] == "d": - spl[j] = 1 - if cs[i] == "d": # 1 for all nodes to the left - for j in range(i): - spl[j] = 1 - # and -1 for any trailing i to indicate unreachable - for j in range(N - 1, 0, -1): - if cs[j] == "d": - break - spl[j] = -1 - return spl - - -def betweenness_sequence(creation_sequence, normalized=True): - """ - Return betweenness for the threshold graph with the given creation - sequence. The result is unscaled. To scale the values - to the interval [0,1] divide by (n-1)*(n-2). - """ - cs = creation_sequence - seq = [] # betweenness - lastchar = "d" # first node is always a 'd' - dr = float(cs.count("d")) # number of d's to the right of current pos - irun = 0 # number of i's in the last run - drun = 0 # number of d's in the last run - dlast = 0.0 # betweenness of last d - for i, c in enumerate(cs): - if c == "d": # cs[i]=="d": - # betweenness = amt shared with earlier d's and i's - # + new isolated nodes covered - # + new paths to all previous nodes - b = dlast + (irun - 1) * irun / dr + 2 * irun * (i - drun - irun) / dr - drun += 1 # update counter - else: # cs[i]="i": - if lastchar == "d": # if this is a new run of i's - dlast = b # accumulate betweenness - dr -= drun # update number of d's to the right - drun = 0 # reset d counter - irun = 0 # reset i counter - b = 0 # isolated nodes have zero betweenness - irun += 1 # add another i to the run - seq.append(float(b)) - lastchar = c - - # normalize by the number of possible shortest paths - if normalized: - order = len(cs) - scale = 1.0 / ((order - 1) * (order - 2)) - seq = [s * scale for s in seq] - - return seq - - -def eigenvectors(creation_sequence): - """ - Return a 2-tuple of Laplacian eigenvalues and eigenvectors - for the threshold network with creation_sequence. - The first value is a list of eigenvalues. - The second value is a list of eigenvectors. - The lists are in the same order so corresponding eigenvectors - and eigenvalues are in the same position in the two lists. - - Notice that the order of the eigenvalues returned by eigenvalues(cs) - may not correspond to the order of these eigenvectors. - """ - ccs = make_compact(creation_sequence) - N = sum(ccs) - vec = [0] * N - val = vec[:] - # get number of type d nodes to the right (all for first node) - dr = sum(ccs[::2]) - - nn = ccs[0] - vec[0] = [1.0 / sqrt(N)] * N - val[0] = 0 - e = dr - dr -= nn - type_d = True - i = 1 - dd = 1 - while dd < nn: - scale = 1.0 / sqrt(dd * dd + i) - vec[i] = i * [-scale] + [dd * scale] + [0] * (N - i - 1) - val[i] = e - i += 1 - dd += 1 - if len(ccs) == 1: - return (val, vec) - for nn in ccs[1:]: - scale = 1.0 / sqrt(nn * i * (i + nn)) - vec[i] = i * [-nn * scale] + nn * [i * scale] + [0] * (N - i - nn) - # find eigenvalue - type_d = not type_d - if type_d: - e = i + dr - dr -= nn - else: - e = dr - val[i] = e - st = i - i += 1 - dd = 1 - while dd < nn: - scale = 1.0 / sqrt(i - st + dd * dd) - vec[i] = [0] * st + (i - st) * [-scale] + [dd * scale] + [0] * (N - i - 1) - val[i] = e - i += 1 - dd += 1 - return (val, vec) - - -def spectral_projection(u, eigenpairs): - """ - Returns the coefficients of each eigenvector - in a projection of the vector u onto the normalized - eigenvectors which are contained in eigenpairs. - - eigenpairs should be a list of two objects. The - first is a list of eigenvalues and the second a list - of eigenvectors. The eigenvectors should be lists. - - There's not a lot of error checking on lengths of - arrays, etc. so be careful. - """ - coeff = [] - evect = eigenpairs[1] - for ev in evect: - c = sum(evv * uv for (evv, uv) in zip(ev, u)) - coeff.append(c) - return coeff - - -def eigenvalues(creation_sequence): - """ - Return sequence of eigenvalues of the Laplacian of the threshold - graph for the given creation_sequence. - - Based on the Ferrer's diagram method. The spectrum is integral - and is the conjugate of the degree sequence. - - See:: - - @Article{degree-merris-1994, - author = {Russel Merris}, - title = {Degree maximal graphs are Laplacian integral}, - journal = {Linear Algebra Appl.}, - year = {1994}, - volume = {199}, - pages = {381--389}, - } - - """ - degseq = degree_sequence(creation_sequence) - degseq.sort() - eiglist = [] # zero is always one eigenvalue - eig = 0 - row = len(degseq) - bigdeg = degseq.pop() - while row: - if bigdeg < row: - eiglist.append(eig) - row -= 1 - else: - eig += 1 - if degseq: - bigdeg = degseq.pop() - else: - bigdeg = 0 - return eiglist - - -# Threshold graph creation routines - - -@py_random_state(2) -def random_threshold_sequence(n, p, seed=None): - """ - Create a random threshold sequence of size n. - A creation sequence is built by randomly choosing d's with - probability p and i's with probability 1-p. - - s=nx.random_threshold_sequence(10,0.5) - - returns a threshold sequence of length 10 with equal - probably of an i or a d at each position. - - A "random" threshold graph can be built with - - G=nx.threshold_graph(s) - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - if not (0 <= p <= 1): - raise ValueError("p must be in [0,1]") - - cs = ["d"] # threshold sequences always start with a d - for i in range(1, n): - if seed.random() < p: - cs.append("d") - else: - cs.append("i") - return cs - - -# maybe *_d_threshold_sequence routines should -# be (or be called from) a single routine with a more descriptive name -# and a keyword parameter? -def right_d_threshold_sequence(n, m): - """ - Create a skewed threshold graph with a given number - of vertices (n) and a given number of edges (m). - - The routine returns an unlabeled creation sequence - for the threshold graph. - - FIXME: describe algorithm - - """ - cs = ["d"] + ["i"] * (n - 1) # create sequence with n insolated nodes - - # m n * (n - 1) / 2: - raise ValueError("Too many edges for this many nodes.") - - # connected case m >n-1 - ind = n - 1 - sum = n - 1 - while sum < m: - cs[ind] = "d" - ind -= 1 - sum += ind - ind = m - (sum - ind) - cs[ind] = "d" - return cs - - -def left_d_threshold_sequence(n, m): - """ - Create a skewed threshold graph with a given number - of vertices (n) and a given number of edges (m). - - The routine returns an unlabeled creation sequence - for the threshold graph. - - FIXME: describe algorithm - - """ - cs = ["d"] + ["i"] * (n - 1) # create sequence with n insolated nodes - - # m n * (n - 1) / 2: - raise ValueError("Too many edges for this many nodes.") - - # Connected case when M>N-1 - cs[n - 1] = "d" - sum = n - 1 - ind = 1 - while sum < m: - cs[ind] = "d" - sum += ind - ind += 1 - if sum > m: # be sure not to change the first vertex - cs[sum - m] = "i" - return cs - - -@py_random_state(3) -def swap_d(cs, p_split=1.0, p_combine=1.0, seed=None): - """ - Perform a "swap" operation on a threshold sequence. - - The swap preserves the number of nodes and edges - in the graph for the given sequence. - The resulting sequence is still a threshold sequence. - - Perform one split and one combine operation on the - 'd's of a creation sequence for a threshold graph. - This operation maintains the number of nodes and edges - in the graph, but shifts the edges from node to node - maintaining the threshold quality of the graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - # preprocess the creation sequence - dlist = [i for (i, node_type) in enumerate(cs[1:-1]) if node_type == "d"] - # split - if seed.random() < p_split: - choice = seed.choice(dlist) - split_to = seed.choice(range(choice)) - flip_side = choice - split_to - if split_to != flip_side and cs[split_to] == "i" and cs[flip_side] == "i": - cs[choice] = "i" - cs[split_to] = "d" - cs[flip_side] = "d" - dlist.remove(choice) - # don't add or combine may reverse this action - # dlist.extend([split_to,flip_side]) - # print >>sys.stderr,"split at %s to %s and %s"%(choice,split_to,flip_side) - # combine - if seed.random() < p_combine and dlist: - first_choice = seed.choice(dlist) - second_choice = seed.choice(dlist) - target = first_choice + second_choice - if target >= len(cs) or cs[target] == "d" or first_choice == second_choice: - return cs - # OK to combine - cs[first_choice] = "i" - cs[second_choice] = "i" - cs[target] = "d" - # print >>sys.stderr,"combine %s and %s to make %s."%(first_choice,second_choice,target) - - return cs diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/time_dependent.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/time_dependent.py deleted file mode 100644 index d67cdcf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/time_dependent.py +++ /dev/null @@ -1,142 +0,0 @@ -"""Time dependent algorithms.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["cd_index"] - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(node_attrs={"time": None, "weight": 1}) -def cd_index(G, node, time_delta, *, time="time", weight=None): - r"""Compute the CD index for `node` within the graph `G`. - - Calculates the CD index for the given node of the graph, - considering only its predecessors who have the `time` attribute - smaller than or equal to the `time` attribute of the `node` - plus `time_delta`. - - Parameters - ---------- - G : graph - A directed networkx graph whose nodes have `time` attributes and optionally - `weight` attributes (if a weight is not given, it is considered 1). - node : node - The node for which the CD index is calculated. - time_delta : numeric or timedelta - Amount of time after the `time` attribute of the `node`. The value of - `time_delta` must support comparison with the `time` node attribute. For - example, if the `time` attribute of the nodes are `datetime.datetime` - objects, then `time_delta` should be a `datetime.timedelta` object. - time : string (Optional, default is "time") - The name of the node attribute that will be used for the calculations. - weight : string (Optional, default is None) - The name of the node attribute used as weight. - - Returns - ------- - float - The CD index calculated for the node `node` within the graph `G`. - - Raises - ------ - NetworkXError - If not all nodes have a `time` attribute or - `time_delta` and `time` attribute types are not compatible or - `n` equals 0. - - NetworkXNotImplemented - If `G` is a non-directed graph or a multigraph. - - Examples - -------- - >>> from datetime import datetime, timedelta - >>> G = nx.DiGraph() - >>> nodes = { - ... 1: {"time": datetime(2015, 1, 1)}, - ... 2: {"time": datetime(2012, 1, 1), "weight": 4}, - ... 3: {"time": datetime(2010, 1, 1)}, - ... 4: {"time": datetime(2008, 1, 1)}, - ... 5: {"time": datetime(2014, 1, 1)}, - ... } - >>> G.add_nodes_from([(n, nodes[n]) for n in nodes]) - >>> edges = [(1, 3), (1, 4), (2, 3), (3, 4), (3, 5)] - >>> G.add_edges_from(edges) - >>> delta = timedelta(days=5 * 365) - >>> nx.cd_index(G, 3, time_delta=delta, time="time") - 0.5 - >>> nx.cd_index(G, 3, time_delta=delta, time="time", weight="weight") - 0.12 - - Integers can also be used for the time values: - >>> node_times = {1: 2015, 2: 2012, 3: 2010, 4: 2008, 5: 2014} - >>> nx.set_node_attributes(G, node_times, "new_time") - >>> nx.cd_index(G, 3, time_delta=4, time="new_time") - 0.5 - >>> nx.cd_index(G, 3, time_delta=4, time="new_time", weight="weight") - 0.12 - - Notes - ----- - This method implements the algorithm for calculating the CD index, - as described in the paper by Funk and Owen-Smith [1]_. The CD index - is used in order to check how consolidating or destabilizing a patent - is, hence the nodes of the graph represent patents and the edges show - the citations between these patents. The mathematical model is given - below: - - .. math:: - CD_{t}=\frac{1}{n_{t}}\sum_{i=1}^{n}\frac{-2f_{it}b_{it}+f_{it}}{w_{it}}, - - where `f_{it}` equals 1 if `i` cites the focal patent else 0, `b_{it}` equals - 1 if `i` cites any of the focal patents successors else 0, `n_{t}` is the number - of forward citations in `i` and `w_{it}` is a matrix of weight for patent `i` - at time `t`. - - The `datetime.timedelta` package can lead to off-by-one issues when converting - from years to days. In the example above `timedelta(days=5 * 365)` looks like - 5 years, but it isn't because of leap year days. So it gives the same result - as `timedelta(days=4 * 365)`. But using `timedelta(days=5 * 365 + 1)` gives - a 5 year delta **for this choice of years** but may not if the 5 year gap has - more than 1 leap year. To avoid these issues, use integers to represent years, - or be very careful when you convert units of time. - - References - ---------- - .. [1] Funk, Russell J., and Jason Owen-Smith. - "A dynamic network measure of technological change." - Management science 63, no. 3 (2017): 791-817. - http://russellfunk.org/cdindex/static/papers/funk_ms_2017.pdf - - """ - if not all(time in G.nodes[n] for n in G): - raise nx.NetworkXError("Not all nodes have a 'time' attribute.") - - try: - # get target_date - target_date = G.nodes[node][time] + time_delta - # keep the predecessors that existed before the target date - pred = {i for i in G.pred[node] if G.nodes[i][time] <= target_date} - except: - raise nx.NetworkXError( - "Addition and comparison are not supported between 'time_delta' " - "and 'time' types." - ) - - # -1 if any edge between node's predecessors and node's successors, else 1 - b = [-1 if any(j in G[i] for j in G[node]) else 1 for i in pred] - - # n is size of the union of the focal node's predecessors and its successors' predecessors - n = len(pred.union(*(G.pred[s].keys() - {node} for s in G[node]))) - if n == 0: - raise nx.NetworkXError("The cd index cannot be defined.") - - # calculate cd index - if weight is None: - return round(sum(bi for bi in b) / n, 2) - else: - # If a node has the specified weight attribute, its weight is used in the calculation - # otherwise, a weight of 1 is assumed for that node - weights = [G.nodes[i].get(weight, 1) for i in pred] - return round(sum(bi / wt for bi, wt in zip(b, weights)) / n, 2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tournament.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tournament.py deleted file mode 100644 index 25c1983..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tournament.py +++ /dev/null @@ -1,403 +0,0 @@ -"""Functions concerning tournament graphs. - -A `tournament graph`_ is a complete oriented graph. In other words, it -is a directed graph in which there is exactly one directed edge joining -each pair of distinct nodes. For each function in this module that -accepts a graph as input, you must provide a tournament graph. The -responsibility is on the caller to ensure that the graph is a tournament -graph: - - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - >>> nx.is_tournament(G) - True - -To access the functions in this module, you must access them through the -:mod:`networkx.tournament` module:: - - >>> nx.tournament.is_reachable(G, 0, 1) - True - -.. _tournament graph: https://en.wikipedia.org/wiki/Tournament_%28graph_theory%29 - -""" - -from itertools import combinations - -import networkx as nx -from networkx.algorithms.simple_paths import is_simple_path as is_path -from networkx.utils import arbitrary_element, not_implemented_for, py_random_state - -__all__ = [ - "hamiltonian_path", - "is_reachable", - "is_strongly_connected", - "is_tournament", - "random_tournament", - "score_sequence", -] - - -def index_satisfying(iterable, condition): - """Returns the index of the first element in `iterable` that - satisfies the given condition. - - If no such element is found (that is, when the iterable is - exhausted), this returns the length of the iterable (that is, one - greater than the last index of the iterable). - - `iterable` must not be empty. If `iterable` is empty, this - function raises :exc:`ValueError`. - - """ - # Pre-condition: iterable must not be empty. - for i, x in enumerate(iterable): - if condition(x): - return i - # If we reach the end of the iterable without finding an element - # that satisfies the condition, return the length of the iterable, - # which is one greater than the index of its last element. If the - # iterable was empty, `i` will not be defined, so we raise an - # exception. - try: - return i + 1 - except NameError as err: - raise ValueError("iterable must be non-empty") from err - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_tournament(G): - """Returns True if and only if `G` is a tournament. - - A tournament is a directed graph, with neither self-loops nor - multi-edges, in which there is exactly one directed edge joining - each pair of distinct nodes. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - bool - Whether the given graph is a tournament graph. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - >>> nx.is_tournament(G) - True - - Notes - ----- - Some definitions require a self-loop on each node, but that is not - the convention used here. - - """ - # In a tournament, there is exactly one directed edge joining each pair. - return ( - all((v in G[u]) ^ (u in G[v]) for u, v in combinations(G, 2)) - and nx.number_of_selfloops(G) == 0 - ) - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable -def hamiltonian_path(G): - """Returns a Hamiltonian path in the given tournament graph. - - Each tournament has a Hamiltonian path. If furthermore, the - tournament is strongly connected, then the returned Hamiltonian path - is a Hamiltonian cycle (by joining the endpoints of the path). - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - path : list - A list of nodes which form a Hamiltonian path in `G`. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) - >>> nx.is_tournament(G) - True - >>> nx.tournament.hamiltonian_path(G) - [0, 1, 2, 3] - - Notes - ----- - This is a recursive implementation with an asymptotic running time - of $O(n^2)$, ignoring multiplicative polylogarithmic factors, where - $n$ is the number of nodes in the graph. - - """ - if len(G) == 0: - return [] - if len(G) == 1: - return [arbitrary_element(G)] - v = arbitrary_element(G) - hampath = hamiltonian_path(G.subgraph(set(G) - {v})) - # Get the index of the first node in the path that does *not* have - # an edge to `v`, then insert `v` before that node. - index = index_satisfying(hampath, lambda u: v not in G[u]) - hampath.insert(index, v) - return hampath - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_tournament(n, seed=None): - r"""Returns a random tournament graph on `n` nodes. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : DiGraph - A tournament on `n` nodes, with exactly one directed edge joining - each pair of distinct nodes. - - Notes - ----- - This algorithm adds, for each pair of distinct nodes, an edge with - uniformly random orientation. In other words, `\binom{n}{2}` flips - of an unbiased coin decide the orientations of the edges in the - graph. - - """ - # Flip an unbiased coin for each pair of distinct nodes. - coins = (seed.random() for i in range((n * (n - 1)) // 2)) - pairs = combinations(range(n), 2) - edges = ((u, v) if r < 0.5 else (v, u) for (u, v), r in zip(pairs, coins)) - return nx.DiGraph(edges) - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable -def score_sequence(G): - """Returns the score sequence for the given tournament graph. - - The score sequence is the sorted list of the out-degrees of the - nodes of the graph. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - list - A sorted list of the out-degrees of the nodes of `G`. - - Examples - -------- - >>> G = nx.DiGraph([(1, 0), (1, 3), (0, 2), (0, 3), (2, 1), (3, 2)]) - >>> nx.is_tournament(G) - True - >>> nx.tournament.score_sequence(G) - [1, 1, 2, 2] - - """ - return sorted(d for v, d in G.out_degree()) - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(preserve_edge_attrs={"G": {"weight": 1}}) -def tournament_matrix(G): - r"""Returns the tournament matrix for the given tournament graph. - - This function requires SciPy. - - The *tournament matrix* of a tournament graph with edge set *E* is - the matrix *T* defined by - - .. math:: - - T_{i j} = - \begin{cases} - +1 & \text{if } (i, j) \in E \\ - -1 & \text{if } (j, i) \in E \\ - 0 & \text{if } i == j. - \end{cases} - - An equivalent definition is `T = A - A^T`, where *A* is the - adjacency matrix of the graph `G`. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - SciPy sparse array - The tournament matrix of the tournament graph `G`. - - Raises - ------ - ImportError - If SciPy is not available. - - """ - A = nx.adjacency_matrix(G) - return A - A.T - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable -def is_reachable(G, s, t): - """Decides whether there is a path from `s` to `t` in the - tournament. - - This function is more theoretically efficient than the reachability - checks than the shortest path algorithms in - :mod:`networkx.algorithms.shortest_paths`. - - The given graph **must** be a tournament, otherwise this function's - behavior is undefined. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - s : node - A node in the graph. - - t : node - A node in the graph. - - Returns - ------- - bool - Whether there is a path from `s` to `t` in `G`. - - Examples - -------- - >>> G = nx.DiGraph([(1, 0), (1, 3), (1, 2), (2, 3), (2, 0), (3, 0)]) - >>> nx.is_tournament(G) - True - >>> nx.tournament.is_reachable(G, 1, 3) - True - >>> nx.tournament.is_reachable(G, 3, 2) - False - - Notes - ----- - Although this function is more theoretically efficient than the - generic shortest path functions, a speedup requires the use of - parallelism. Though it may in the future, the current implementation - does not use parallelism, thus you may not see much of a speedup. - - This algorithm comes from [1]. - - References - ---------- - .. [1] Tantau, Till. - "A note on the complexity of the reachability problem for - tournaments." - *Electronic Colloquium on Computational Complexity*. 2001. - - """ - - def two_neighborhood(G, v): - """Returns the set of nodes at distance at most two from `v`. - - `G` must be a graph and `v` a node in that graph. - - The returned set includes the nodes at distance zero (that is, - the node `v` itself), the nodes at distance one (that is, the - out-neighbors of `v`), and the nodes at distance two. - - """ - return { - x for x in G if x == v or x in G[v] or any(is_path(G, [v, z, x]) for z in G) - } - - def is_closed(G, nodes): - """Decides whether the given set of nodes is closed. - - A set *S* of nodes is *closed* if for each node *u* in the graph - not in *S* and for each node *v* in *S*, there is an edge from - *u* to *v*. - - """ - return all(v in G[u] for u in set(G) - nodes for v in nodes) - - neighborhoods = [two_neighborhood(G, v) for v in G] - return all(not (is_closed(G, S) and s in S and t not in S) for S in neighborhoods) - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(name="tournament_is_strongly_connected") -def is_strongly_connected(G): - """Decides whether the given tournament is strongly connected. - - This function is more theoretically efficient than the - :func:`~networkx.algorithms.components.is_strongly_connected` - function. - - The given graph **must** be a tournament, otherwise this function's - behavior is undefined. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - bool - Whether the tournament is strongly connected. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 0)]) - >>> nx.is_tournament(G) - True - >>> nx.tournament.is_strongly_connected(G) - True - >>> G.remove_edge(3, 0) - >>> G.add_edge(0, 3) - >>> nx.is_tournament(G) - True - >>> nx.tournament.is_strongly_connected(G) - False - - Notes - ----- - Although this function is more theoretically efficient than the - generic strong connectivity function, a speedup requires the use of - parallelism. Though it may in the future, the current implementation - does not use parallelism, thus you may not see much of a speedup. - - This algorithm comes from [1]. - - References - ---------- - .. [1] Tantau, Till. - "A note on the complexity of the reachability problem for - tournaments." - *Electronic Colloquium on Computational Complexity*. 2001. - - - """ - return all(is_reachable(G, u, v) for u in G for v in G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/__init__.py deleted file mode 100644 index 93e6cdd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .beamsearch import * -from .breadth_first_search import * -from .depth_first_search import * -from .edgedfs import * -from .edgebfs import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/beamsearch.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/beamsearch.py deleted file mode 100644 index 23fbe7b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/beamsearch.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Basic algorithms for breadth-first searching the nodes of a graph.""" - -import networkx as nx - -__all__ = ["bfs_beam_edges"] - - -@nx._dispatchable -def bfs_beam_edges(G, source, value, width=None): - """Iterates over edges in a beam search. - - The beam search is a generalized breadth-first search in which only - the "best" *w* neighbors of the current node are enqueued, where *w* - is the beam width and "best" is an application-specific - heuristic. In general, a beam search with a small beam width might - not visit each node in the graph. - - .. note:: - - With the default value of ``width=None`` or `width` greater than the - maximum degree of the graph, this function equates to a slower - version of `~networkx.algorithms.traversal.breadth_first_search.bfs_edges`. - All nodes will be visited, though the order of the reported edges may - vary. In such cases, `value` has no effect - consider using `bfs_edges` - directly instead. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for the breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - value : function - A function that takes a node of the graph as input and returns a - real number indicating how "good" it is. A higher value means it - is more likely to be visited sooner during the search. When - visiting a new node, only the `width` neighbors with the highest - `value` are enqueued (in decreasing order of `value`). - - width : int (default = None) - The beam width for the search. This is the number of neighbors - (ordered by `value`) to enqueue when visiting each new node. - - Yields - ------ - edge - Edges in the beam search starting from `source`, given as a pair - of nodes. - - Examples - -------- - To give nodes with, for example, a higher centrality precedence - during the search, set the `value` function to return the centrality - value of the node: - - >>> G = nx.karate_club_graph() - >>> centrality = nx.eigenvector_centrality(G) - >>> list(nx.bfs_beam_edges(G, source=0, value=centrality.get, width=3)) - [(0, 2), (0, 1), (0, 8), (2, 32), (1, 13), (8, 33)] - """ - - if width is None: - width = len(G) - - def successors(v): - """Returns a list of the best neighbors of a node. - - `v` is a node in the graph `G`. - - The "best" neighbors are chosen according to the `value` - function (higher is better). Only the `width` best neighbors of - `v` are returned. - """ - # TODO The Python documentation states that for small values, it - # is better to use `heapq.nlargest`. We should determine the - # threshold at which its better to use `heapq.nlargest()` - # instead of `sorted()[:]` and apply that optimization here. - # - # If `width` is greater than the number of neighbors of `v`, all - # neighbors are returned by the semantics of slicing in - # Python. This occurs in the special case that the user did not - # specify a `width`: in this case all neighbors are always - # returned, so this is just a (slower) implementation of - # `bfs_edges(G, source)` but with a sorted enqueue step. - return iter(sorted(G.neighbors(v), key=value, reverse=True)[:width]) - - yield from nx.generic_bfs_edges(G, source, successors) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/breadth_first_search.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/breadth_first_search.py deleted file mode 100644 index 899dc92..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/breadth_first_search.py +++ /dev/null @@ -1,575 +0,0 @@ -"""Basic algorithms for breadth-first searching the nodes of a graph.""" - -from collections import deque - -import networkx as nx - -__all__ = [ - "bfs_edges", - "bfs_tree", - "bfs_predecessors", - "bfs_successors", - "descendants_at_distance", - "bfs_layers", - "bfs_labeled_edges", - "generic_bfs_edges", -] - - -@nx._dispatchable -def generic_bfs_edges(G, source, neighbors=None, depth_limit=None): - """Iterate over edges in a breadth-first search. - - The breadth-first search begins at `source` and enqueues the - neighbors of newly visited nodes specified by the `neighbors` - function. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for the breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - neighbors : function - A function that takes a newly visited node of the graph as input - and returns an *iterator* (not just a list) of nodes that are - neighbors of that node with custom ordering. If not specified, this is - just the ``G.neighbors`` method, but in general it can be any function - that returns an iterator over some or all of the neighbors of a - given node, in any order. - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth. - - Yields - ------ - edge - Edges in the breadth-first search starting from `source`. - - Examples - -------- - >>> G = nx.path_graph(7) - >>> list(nx.generic_bfs_edges(G, source=0)) - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)] - >>> list(nx.generic_bfs_edges(G, source=2)) - [(2, 1), (2, 3), (1, 0), (3, 4), (4, 5), (5, 6)] - >>> list(nx.generic_bfs_edges(G, source=2, depth_limit=2)) - [(2, 1), (2, 3), (1, 0), (3, 4)] - - The `neighbors` param can be used to specify the visitation order of each - node's neighbors generically. In the following example, we modify the default - neighbor to return *odd* nodes first: - - >>> def odd_first(n): - ... return sorted(G.neighbors(n), key=lambda x: x % 2, reverse=True) - - >>> G = nx.star_graph(5) - >>> list(nx.generic_bfs_edges(G, source=0)) # Default neighbor ordering - [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)] - >>> list(nx.generic_bfs_edges(G, source=0, neighbors=odd_first)) - [(0, 1), (0, 3), (0, 5), (0, 2), (0, 4)] - - Notes - ----- - This implementation is from `PADS`_, which was in the public domain - when it was first accessed in July, 2004. The modifications - to allow depth limits are based on the Wikipedia article - "`Depth-limited-search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS/BFS.py - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - """ - if neighbors is None: - neighbors = G.neighbors - if depth_limit is None: - depth_limit = len(G) - - seen = {source} - n = len(G) - depth = 0 - next_parents_children = [(source, neighbors(source))] - while next_parents_children and depth < depth_limit: - this_parents_children = next_parents_children - next_parents_children = [] - for parent, children in this_parents_children: - for child in children: - if child not in seen: - seen.add(child) - next_parents_children.append((child, neighbors(child))) - yield parent, child - if len(seen) == n: - return - depth += 1 - - -@nx._dispatchable -def bfs_edges(G, source, reverse=False, depth_limit=None, sort_neighbors=None): - """Iterate over edges in a breadth-first-search starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - reverse : bool, optional - If True traverse a directed graph in the reverse direction - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Yields - ------ - edge: 2-tuple of nodes - Yields edges resulting from the breadth-first search. - - Examples - -------- - To get the edges in a breadth-first search:: - - >>> G = nx.path_graph(3) - >>> list(nx.bfs_edges(G, 0)) - [(0, 1), (1, 2)] - >>> list(nx.bfs_edges(G, source=0, depth_limit=1)) - [(0, 1)] - - To get the nodes in a breadth-first search order:: - - >>> G = nx.path_graph(3) - >>> root = 2 - >>> edges = nx.bfs_edges(G, root) - >>> nodes = [root] + [v for u, v in edges] - >>> nodes - [2, 1, 0] - - Notes - ----- - The naming of this function is very similar to - :func:`~networkx.algorithms.traversal.edgebfs.edge_bfs`. The difference - is that ``edge_bfs`` yields edges even if they extend back to an already - explored node while this generator yields the edges of the tree that results - from a breadth-first-search (BFS) so no edges are reported if they extend - to already explored nodes. That means ``edge_bfs`` reports all edges while - ``bfs_edges`` only reports those traversed by a node-based BFS. Yet another - description is that ``bfs_edges`` reports the edges traversed during BFS - while ``edge_bfs`` reports all edges in the order they are explored. - - Based on the breadth-first search implementation in PADS [1]_ - by D. Eppstein, July 2004; with modifications to allow depth limits - as described in [2]_. - - References - ---------- - .. [1] http://www.ics.uci.edu/~eppstein/PADS/BFS.py. - .. [2] https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - :func:`~networkx.algorithms.traversal.depth_first_search.dfs_edges` - :func:`~networkx.algorithms.traversal.edgebfs.edge_bfs` - - """ - if reverse and G.is_directed(): - successors = G.predecessors - else: - successors = G.neighbors - - if sort_neighbors is not None: - yield from generic_bfs_edges( - G, source, lambda node: iter(sort_neighbors(successors(node))), depth_limit - ) - else: - yield from generic_bfs_edges(G, source, successors, depth_limit) - - -@nx._dispatchable(returns_graph=True) -def bfs_tree(G, source, reverse=False, depth_limit=None, sort_neighbors=None): - """Returns an oriented tree constructed from of a breadth-first-search - starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - reverse : bool, optional - If True traverse a directed graph in the reverse direction - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - T: NetworkX DiGraph - An oriented tree - - Examples - -------- - >>> G = nx.path_graph(3) - >>> list(nx.bfs_tree(G, 1).edges()) - [(1, 0), (1, 2)] - >>> H = nx.Graph() - >>> nx.add_path(H, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(H, [2, 7, 8, 9, 10]) - >>> sorted(list(nx.bfs_tree(H, source=3, depth_limit=3).edges())) - [(1, 0), (2, 1), (2, 7), (3, 2), (3, 4), (4, 5), (5, 6), (7, 8)] - - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004. The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_tree - bfs_edges - edge_bfs - """ - T = nx.DiGraph() - T.add_node(source) - edges_gen = bfs_edges( - G, - source, - reverse=reverse, - depth_limit=depth_limit, - sort_neighbors=sort_neighbors, - ) - T.add_edges_from(edges_gen) - return T - - -@nx._dispatchable -def bfs_predecessors(G, source, depth_limit=None, sort_neighbors=None): - """Returns an iterator of predecessors in breadth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - pred: iterator - (node, predecessor) iterator where `predecessor` is the predecessor of - `node` in a breadth first search starting from `source`. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> dict(nx.bfs_predecessors(G, 0)) - {1: 0, 2: 1} - >>> H = nx.Graph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> dict(nx.bfs_predecessors(H, 0)) - {1: 0, 2: 0, 3: 1, 4: 1, 5: 2, 6: 2} - >>> M = nx.Graph() - >>> nx.add_path(M, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(M, [2, 7, 8, 9, 10]) - >>> sorted(nx.bfs_predecessors(M, source=1, depth_limit=3)) - [(0, 1), (2, 1), (3, 2), (4, 3), (7, 2), (8, 7)] - >>> N = nx.DiGraph() - >>> nx.add_path(N, [0, 1, 2, 3, 4, 7]) - >>> nx.add_path(N, [3, 5, 6, 7]) - >>> sorted(nx.bfs_predecessors(N, source=2)) - [(3, 2), (4, 3), (5, 3), (6, 5), (7, 4)] - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004. The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - bfs_edges - edge_bfs - """ - for s, t in bfs_edges( - G, source, depth_limit=depth_limit, sort_neighbors=sort_neighbors - ): - yield (t, s) - - -@nx._dispatchable -def bfs_successors(G, source, depth_limit=None, sort_neighbors=None): - """Returns an iterator of successors in breadth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - succ: iterator - (node, successors) iterator where `successors` is the non-empty list of - successors of `node` in a breadth first search from `source`. - To appear in the iterator, `node` must have successors. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> dict(nx.bfs_successors(G, 0)) - {0: [1], 1: [2]} - >>> H = nx.Graph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> dict(nx.bfs_successors(H, 0)) - {0: [1, 2], 1: [3, 4], 2: [5, 6]} - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(G, [2, 7, 8, 9, 10]) - >>> dict(nx.bfs_successors(G, source=1, depth_limit=3)) - {1: [0, 2], 2: [3, 7], 3: [4], 7: [8]} - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3, 4, 5]) - >>> dict(nx.bfs_successors(G, source=3)) - {3: [4], 4: [5]} - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004.The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - bfs_edges - edge_bfs - """ - parent = source - children = [] - for p, c in bfs_edges( - G, source, depth_limit=depth_limit, sort_neighbors=sort_neighbors - ): - if p == parent: - children.append(c) - continue - yield (parent, children) - children = [c] - parent = p - yield (parent, children) - - -@nx._dispatchable -def bfs_layers(G, sources): - """Returns an iterator of all the layers in breadth-first search traversal. - - Parameters - ---------- - G : NetworkX graph - A graph over which to find the layers using breadth-first search. - - sources : node in `G` or list of nodes in `G` - Specify starting nodes for single source or multiple sources breadth-first search - - Yields - ------ - layer: list of nodes - Yields list of nodes at the same distance from sources - - Examples - -------- - >>> G = nx.path_graph(5) - >>> dict(enumerate(nx.bfs_layers(G, [0, 4]))) - {0: [0, 4], 1: [1, 3], 2: [2]} - >>> H = nx.Graph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> dict(enumerate(nx.bfs_layers(H, [1]))) - {0: [1], 1: [0, 3, 4], 2: [2], 3: [5, 6]} - >>> dict(enumerate(nx.bfs_layers(H, [1, 6]))) - {0: [1, 6], 1: [0, 3, 4, 2], 2: [5]} - """ - if sources in G: - sources = [sources] - - current_layer = list(sources) - visited = set(sources) - - for source in current_layer: - if source not in G: - raise nx.NetworkXError(f"The node {source} is not in the graph.") - - # this is basically BFS, except that the current layer only stores the nodes at - # same distance from sources at each iteration - while current_layer: - yield current_layer - next_layer = [] - for node in current_layer: - for child in G[node]: - if child not in visited: - visited.add(child) - next_layer.append(child) - current_layer = next_layer - - -REVERSE_EDGE = "reverse" -TREE_EDGE = "tree" -FORWARD_EDGE = "forward" -LEVEL_EDGE = "level" - - -@nx._dispatchable -def bfs_labeled_edges(G, sources): - """Iterate over edges in a breadth-first search (BFS) labeled by type. - - We generate triple of the form (*u*, *v*, *d*), where (*u*, *v*) is the - edge being explored in the breadth-first search and *d* is one of the - strings 'tree', 'forward', 'level', or 'reverse'. A 'tree' edge is one in - which *v* is first discovered and placed into the layer below *u*. A - 'forward' edge is one in which *u* is on the layer above *v* and *v* has - already been discovered. A 'level' edge is one in which both *u* and *v* - occur on the same layer. A 'reverse' edge is one in which *u* is on a layer - below *v*. - - We emit each edge exactly once. In an undirected graph, 'reverse' edges do - not occur, because each is discovered either as a 'tree' or 'forward' edge. - - Parameters - ---------- - G : NetworkX graph - A graph over which to find the layers using breadth-first search. - - sources : node in `G` or list of nodes in `G` - Starting nodes for single source or multiple sources breadth-first search - - Yields - ------ - edges: generator - A generator of triples (*u*, *v*, *d*) where (*u*, *v*) is the edge being - explored and *d* is described above. - - Examples - -------- - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph) - >>> list(nx.bfs_labeled_edges(G, 0)) - [(0, 1, 'tree'), (1, 2, 'tree'), (2, 3, 'tree'), (3, 0, 'reverse')] - >>> G = nx.complete_graph(3) - >>> list(nx.bfs_labeled_edges(G, 0)) - [(0, 1, 'tree'), (0, 2, 'tree'), (1, 2, 'level')] - >>> list(nx.bfs_labeled_edges(G, [0, 1])) - [(0, 1, 'level'), (0, 2, 'tree'), (1, 2, 'forward')] - """ - if sources in G: - sources = [sources] - - neighbors = G._adj - directed = G.is_directed() - visited = set() - visit = visited.discard if directed else visited.add - # We use visited in a negative sense, so the visited set stays empty for the - # directed case and level edges are reported on their first occurrence in - # the undirected case. Note our use of visited.discard -- this is built-in - # thus somewhat faster than a python-defined def nop(x): pass - depth = {s: 0 for s in sources} - queue = deque(depth.items()) - push = queue.append - pop = queue.popleft - while queue: - u, du = pop() - for v in neighbors[u]: - if v not in depth: - depth[v] = dv = du + 1 - push((v, dv)) - yield u, v, TREE_EDGE - else: - dv = depth[v] - if du == dv: - if v not in visited: - yield u, v, LEVEL_EDGE - elif du < dv: - yield u, v, FORWARD_EDGE - elif directed: - yield u, v, REVERSE_EDGE - visit(u) - - -@nx._dispatchable -def descendants_at_distance(G, source, distance): - """Returns all nodes at a fixed `distance` from `source` in `G`. - - Parameters - ---------- - G : NetworkX graph - A graph - source : node in `G` - distance : the distance of the wanted nodes from `source` - - Returns - ------- - set() - The descendants of `source` in `G` at the given `distance` from `source` - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.descendants_at_distance(G, 2, 2) - {0, 4} - >>> H = nx.DiGraph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> nx.descendants_at_distance(H, 0, 2) - {3, 4, 5, 6} - >>> nx.descendants_at_distance(H, 5, 0) - {5} - >>> nx.descendants_at_distance(H, 5, 1) - set() - """ - if source not in G: - raise nx.NetworkXError(f"The node {source} is not in the graph.") - - bfs_generator = nx.bfs_layers(G, source) - for i, layer in enumerate(bfs_generator): - if i == distance: - return set(layer) - return set() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/depth_first_search.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/depth_first_search.py deleted file mode 100644 index 5bac5ec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/depth_first_search.py +++ /dev/null @@ -1,529 +0,0 @@ -"""Basic algorithms for depth-first searching the nodes of a graph.""" - -from collections import defaultdict - -import networkx as nx - -__all__ = [ - "dfs_edges", - "dfs_tree", - "dfs_predecessors", - "dfs_successors", - "dfs_preorder_nodes", - "dfs_postorder_nodes", - "dfs_labeled_edges", -] - - -@nx._dispatchable -def dfs_edges(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Iterate over edges in a depth-first-search (DFS). - - Perform a depth-first-search over the nodes of `G` and yield - the edges in order. This may not generate all edges in `G` - (see `~networkx.algorithms.traversal.edgedfs.edge_dfs`). - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and yield edges in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Yields - ------ - edge: 2-tuple of nodes - Yields edges resulting from the depth-first-search. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_edges(G, source=0)) - [(0, 1), (1, 2), (2, 3), (3, 4)] - >>> list(nx.dfs_edges(G, source=0, depth_limit=2)) - [(0, 1), (1, 2)] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in PADS [1]_, with modifications - to allow depth limits based on the Wikipedia article - "Depth-limited search" [2]_. - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.edgedfs.edge_dfs` - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_edges` - - References - ---------- - .. [1] http://www.ics.uci.edu/~eppstein/PADS - .. [2] https://en.wikipedia.org/wiki/Depth-limited_search - """ - if source is None: - # edges for all components - nodes = G - else: - # edges for components with source - nodes = [source] - if depth_limit is None: - depth_limit = len(G) - - get_children = ( - G.neighbors - if sort_neighbors is None - else lambda n: iter(sort_neighbors(G.neighbors(n))) - ) - - visited = set() - for start in nodes: - if start in visited: - continue - visited.add(start) - stack = [(start, get_children(start))] - depth_now = 1 - while stack: - parent, children = stack[-1] - for child in children: - if child not in visited: - yield parent, child - visited.add(child) - if depth_now < depth_limit: - stack.append((child, get_children(child))) - depth_now += 1 - break - else: - stack.pop() - depth_now -= 1 - - -@nx._dispatchable(returns_graph=True) -def dfs_tree(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Returns oriented tree constructed from a depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - T : NetworkX DiGraph - An oriented tree - - Examples - -------- - >>> G = nx.path_graph(5) - >>> T = nx.dfs_tree(G, source=0, depth_limit=2) - >>> list(T.edges()) - [(0, 1), (1, 2)] - >>> T = nx.dfs_tree(G, source=0) - >>> list(T.edges()) - [(0, 1), (1, 2), (2, 3), (3, 4)] - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.edgedfs.edge_dfs` - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_tree` - """ - T = nx.DiGraph() - if source is None: - T.add_nodes_from(G) - else: - T.add_node(source) - T.add_edges_from(dfs_edges(G, source, depth_limit, sort_neighbors=sort_neighbors)) - return T - - -@nx._dispatchable -def dfs_predecessors(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Returns dictionary of predecessors in depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - Note that you will get predecessors for all nodes in the - component containing `source`. This input only specifies - where the DFS starts. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - pred: dict - A dictionary with nodes as keys and predecessor nodes as values. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.dfs_predecessors(G, source=0) - {1: 0, 2: 1, 3: 2} - >>> nx.dfs_predecessors(G, source=0, depth_limit=2) - {1: 0, 2: 1} - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.edgedfs.edge_dfs` - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_tree` - """ - return { - t: s - for s, t in dfs_edges(G, source, depth_limit, sort_neighbors=sort_neighbors) - } - - -@nx._dispatchable -def dfs_successors(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Returns dictionary of successors in depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - Note that you will get successors for all nodes in the - component containing `source`. This input only specifies - where the DFS starts. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - succ: dict - A dictionary with nodes as keys and list of successor nodes as values. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.dfs_successors(G, source=0) - {0: [1], 1: [2], 2: [3], 3: [4]} - >>> nx.dfs_successors(G, source=0, depth_limit=2) - {0: [1], 1: [2]} - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.edgedfs.edge_dfs` - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_tree` - """ - d = defaultdict(list) - for s, t in dfs_edges( - G, - source=source, - depth_limit=depth_limit, - sort_neighbors=sort_neighbors, - ): - d[s].append(t) - return dict(d) - - -@nx._dispatchable -def dfs_postorder_nodes(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Generate nodes in a depth-first-search post-ordering starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - nodes: generator - A generator of nodes in a depth-first-search post-ordering. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_postorder_nodes(G, source=0)) - [4, 3, 2, 1, 0] - >>> list(nx.dfs_postorder_nodes(G, source=0, depth_limit=2)) - [1, 0] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_preorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.edgedfs.edge_dfs` - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_tree` - """ - edges = nx.dfs_labeled_edges( - G, source=source, depth_limit=depth_limit, sort_neighbors=sort_neighbors - ) - return (v for u, v, d in edges if d == "reverse") - - -@nx._dispatchable -def dfs_preorder_nodes(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Generate nodes in a depth-first-search pre-ordering starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and return nodes in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - nodes: generator - A generator of nodes in a depth-first-search pre-ordering. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_preorder_nodes(G, source=0)) - [0, 1, 2, 3, 4] - >>> list(nx.dfs_preorder_nodes(G, source=0, depth_limit=2)) - [0, 1, 2] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_postorder_nodes - dfs_labeled_edges - :func:`~networkx.algorithms.traversal.breadth_first_search.bfs_edges` - """ - edges = nx.dfs_labeled_edges( - G, source=source, depth_limit=depth_limit, sort_neighbors=sort_neighbors - ) - return (v for u, v, d in edges if d == "forward") - - -@nx._dispatchable -def dfs_labeled_edges(G, source=None, depth_limit=None, *, sort_neighbors=None): - """Iterate over edges in a depth-first-search (DFS) labeled by type. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and return edges in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - sort_neighbors : function (default=None) - A function that takes an iterator over nodes as the input, and - returns an iterable of the same nodes with a custom ordering. - For example, `sorted` will sort the nodes in increasing order. - - Returns - ------- - edges: generator - A generator of triples of the form (*u*, *v*, *d*), where (*u*, - *v*) is the edge being explored in the depth-first search and *d* - is one of the strings 'forward', 'nontree', 'reverse', or 'reverse-depth_limit'. - A 'forward' edge is one in which *u* has been visited but *v* has - not. A 'nontree' edge is one in which both *u* and *v* have been - visited but the edge is not in the DFS tree. A 'reverse' edge is - one in which both *u* and *v* have been visited and the edge is in - the DFS tree. When the `depth_limit` is reached via a 'forward' edge, - a 'reverse' edge is immediately generated rather than the subtree - being explored. To indicate this flavor of 'reverse' edge, the string - yielded is 'reverse-depth_limit'. - - Examples - -------- - - The labels reveal the complete transcript of the depth-first search - algorithm in more detail than, for example, :func:`dfs_edges`:: - - >>> from pprint import pprint - >>> - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 1)]) - >>> pprint(list(nx.dfs_labeled_edges(G, source=0))) - [(0, 0, 'forward'), - (0, 1, 'forward'), - (1, 2, 'forward'), - (2, 1, 'nontree'), - (1, 2, 'reverse'), - (0, 1, 'reverse'), - (0, 0, 'reverse')] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_preorder_nodes - dfs_postorder_nodes - """ - # Based on http://www.ics.uci.edu/~eppstein/PADS/DFS.py - # by D. Eppstein, July 2004. - if source is None: - # edges for all components - nodes = G - else: - # edges for components with source - nodes = [source] - if depth_limit is None: - depth_limit = len(G) - - get_children = ( - G.neighbors - if sort_neighbors is None - else lambda n: iter(sort_neighbors(G.neighbors(n))) - ) - - visited = set() - for start in nodes: - if start in visited: - continue - yield start, start, "forward" - visited.add(start) - stack = [(start, get_children(start))] - depth_now = 1 - while stack: - parent, children = stack[-1] - for child in children: - if child in visited: - yield parent, child, "nontree" - else: - yield parent, child, "forward" - visited.add(child) - if depth_now < depth_limit: - stack.append((child, iter(get_children(child)))) - depth_now += 1 - break - else: - yield parent, child, "reverse-depth_limit" - else: - stack.pop() - depth_now -= 1 - if stack: - yield stack[-1][0], parent, "reverse" - yield start, start, "reverse" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgebfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgebfs.py deleted file mode 100644 index 6320ddc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgebfs.py +++ /dev/null @@ -1,178 +0,0 @@ -""" -============================= -Breadth First Search on Edges -============================= - -Algorithms for a breadth-first traversal of edges in a graph. - -""" - -from collections import deque - -import networkx as nx - -FORWARD = "forward" -REVERSE = "reverse" - -__all__ = ["edge_bfs"] - - -@nx._dispatchable -def edge_bfs(G, source=None, orientation=None): - """A directed, breadth-first-search of edges in `G`, beginning at `source`. - - Yield the edges of G in a breadth-first-search order continuing until - all edges are generated. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Yields - ------ - edge : directed edge - A directed edge indicating the path taken by the breadth-first-search. - For graphs, `edge` is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, `edge` is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Examples - -------- - >>> nodes = [0, 1, 2, 3] - >>> edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_bfs(nx.Graph(edges), nodes)) - [(0, 1), (0, 2), (1, 2), (1, 3)] - - >>> list(nx.edge_bfs(nx.DiGraph(edges), nodes)) - [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_bfs(nx.MultiGraph(edges), nodes)) - [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)] - - >>> list(nx.edge_bfs(nx.MultiDiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)] - - >>> list(nx.edge_bfs(nx.DiGraph(edges), nodes, orientation="ignore")) - [(0, 1, 'forward'), (1, 0, 'reverse'), (2, 0, 'reverse'), (2, 1, 'reverse'), (3, 1, 'reverse')] - - >>> list(nx.edge_bfs(nx.MultiDiGraph(edges), nodes, orientation="ignore")) - [(0, 1, 0, 'forward'), (1, 0, 0, 'reverse'), (1, 0, 1, 'reverse'), (2, 0, 0, 'reverse'), (2, 1, 0, 'reverse'), (3, 1, 0, 'reverse')] - - Notes - ----- - The goal of this function is to visit edges. It differs from the more - familiar breadth-first-search of nodes, as provided by - :func:`networkx.algorithms.traversal.breadth_first_search.bfs_edges`, in - that it does not stop once every node has been visited. In a directed graph - with edges [(0, 1), (1, 2), (2, 1)], the edge (2, 1) would not be visited - if not for the functionality provided by this function. - - The naming of this function is very similar to bfs_edges. The difference - is that 'edge_bfs' yields edges even if they extend back to an already - explored node while 'bfs_edges' yields the edges of the tree that results - from a breadth-first-search (BFS) so no edges are reported if they extend - to already explored nodes. That means 'edge_bfs' reports all edges while - 'bfs_edges' only report those traversed by a node-based BFS. Yet another - description is that 'bfs_edges' reports the edges traversed during BFS - while 'edge_bfs' reports all edges in the order they are explored. - - See Also - -------- - bfs_edges - bfs_tree - edge_dfs - - """ - nodes = list(G.nbunch_iter(source)) - if not nodes: - return - - directed = G.is_directed() - kwds = {"data": False} - if G.is_multigraph() is True: - kwds["keys"] = True - - # set up edge lookup - if orientation is None: - - def edges_from(node): - return iter(G.edges(node, **kwds)) - - elif not directed or orientation == "original": - - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - - elif orientation == "reverse": - - def edges_from(node): - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - - elif orientation == "ignore": - - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - - else: - raise nx.NetworkXError("invalid orientation argument.") - - if directed: - neighbors = G.successors - - def edge_id(edge): - # remove direction indicator - return edge[:-1] if orientation is not None else edge - - else: - neighbors = G.neighbors - - def edge_id(edge): - return (frozenset(edge[:2]),) + edge[2:] - - check_reverse = directed and orientation in ("reverse", "ignore") - - # start BFS - visited_nodes = set(nodes) - visited_edges = set() - queue = deque([(n, edges_from(n)) for n in nodes]) - while queue: - parent, children_edges = queue.popleft() - for edge in children_edges: - if check_reverse and edge[-1] == REVERSE: - child = edge[0] - else: - child = edge[1] - if child not in visited_nodes: - visited_nodes.add(child) - queue.append((child, edges_from(child))) - edgeid = edge_id(edge) - if edgeid not in visited_edges: - visited_edges.add(edgeid) - yield edge diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgedfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgedfs.py deleted file mode 100644 index 8f657f3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/edgedfs.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -=========================== -Depth First Search on Edges -=========================== - -Algorithms for a depth-first traversal of edges in a graph. - -""" - -import networkx as nx - -FORWARD = "forward" -REVERSE = "reverse" - -__all__ = ["edge_dfs"] - - -@nx._dispatchable -def edge_dfs(G, source=None, orientation=None): - """A directed, depth-first-search of edges in `G`, beginning at `source`. - - Yield the edges of G in a depth-first-search order continuing until - all edges are generated. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Yields - ------ - edge : directed edge - A directed edge indicating the path taken by the depth-first traversal. - For graphs, `edge` is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, `edge` is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Examples - -------- - >>> nodes = [0, 1, 2, 3] - >>> edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_dfs(nx.Graph(edges), nodes)) - [(0, 1), (1, 2), (1, 3)] - - >>> list(nx.edge_dfs(nx.DiGraph(edges), nodes)) - [(0, 1), (1, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_dfs(nx.MultiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)] - - >>> list(nx.edge_dfs(nx.MultiDiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)] - - >>> list(nx.edge_dfs(nx.DiGraph(edges), nodes, orientation="ignore")) - [(0, 1, 'forward'), (1, 0, 'forward'), (2, 1, 'reverse'), (3, 1, 'reverse')] - - >>> list(nx.edge_dfs(nx.MultiDiGraph(edges), nodes, orientation="ignore")) - [(0, 1, 0, 'forward'), (1, 0, 0, 'forward'), (1, 0, 1, 'reverse'), (2, 1, 0, 'reverse'), (3, 1, 0, 'reverse')] - - Notes - ----- - The goal of this function is to visit edges. It differs from the more - familiar depth-first traversal of nodes, as provided by - :func:`~networkx.algorithms.traversal.depth_first_search.dfs_edges`, in - that it does not stop once every node has been visited. In a directed graph - with edges [(0, 1), (1, 2), (2, 1)], the edge (2, 1) would not be visited - if not for the functionality provided by this function. - - See Also - -------- - :func:`~networkx.algorithms.traversal.depth_first_search.dfs_edges` - - """ - nodes = list(G.nbunch_iter(source)) - if not nodes: - return - - directed = G.is_directed() - kwds = {"data": False} - if G.is_multigraph() is True: - kwds["keys"] = True - - # set up edge lookup - if orientation is None: - - def edges_from(node): - return iter(G.edges(node, **kwds)) - - elif not directed or orientation == "original": - - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - - elif orientation == "reverse": - - def edges_from(node): - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - - elif orientation == "ignore": - - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - - else: - raise nx.NetworkXError("invalid orientation argument.") - - # set up formation of edge_id to easily look up if edge already returned - if directed: - - def edge_id(edge): - # remove direction indicator - return edge[:-1] if orientation is not None else edge - - else: - - def edge_id(edge): - # single id for undirected requires frozenset on nodes - return (frozenset(edge[:2]),) + edge[2:] - - # Basic setup - check_reverse = directed and orientation in ("reverse", "ignore") - - visited_edges = set() - visited_nodes = set() - edges = {} - - # start DFS - for start_node in nodes: - stack = [start_node] - while stack: - current_node = stack[-1] - if current_node not in visited_nodes: - edges[current_node] = edges_from(current_node) - visited_nodes.add(current_node) - - try: - edge = next(edges[current_node]) - except StopIteration: - # No more edges from the current node. - stack.pop() - else: - edgeid = edge_id(edge) - if edgeid not in visited_edges: - visited_edges.add(edgeid) - # Mark the traversed "to" node as to-be-explored. - if check_reverse and edge[-1] == REVERSE: - stack.append(edge[0]) - else: - stack.append(edge[1]) - yield edge diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py deleted file mode 100644 index 049f116..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Unit tests for the beam search functions.""" - -import pytest - -import networkx as nx - - -def test_narrow(): - """Tests that a narrow beam width may cause an incomplete search.""" - # In this search, we enqueue only the neighbor 3 at the first - # step, then only the neighbor 2 at the second step. Once at - # node 2, the search chooses node 3, since it has a higher value - # than node 1, but node 3 has already been visited, so the - # search terminates. - G = nx.cycle_graph(4) - edges = nx.bfs_beam_edges(G, source=0, value=lambda n: n, width=1) - assert list(edges) == [(0, 3), (3, 2)] - - -@pytest.mark.parametrize("width", (2, None)) -def test_wide(width): - """All nodes are searched when `width` is None or >= max degree""" - G = nx.cycle_graph(4) - edges = nx.bfs_beam_edges(G, source=0, value=lambda n: n, width=width) - assert list(edges) == [(0, 3), (0, 1), (3, 2)] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_bfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_bfs.py deleted file mode 100644 index fcfbbc6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_bfs.py +++ /dev/null @@ -1,203 +0,0 @@ -from functools import partial - -import pytest - -import networkx as nx - - -class TestBFS: - @classmethod - def setup_class(cls): - # simple graph - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - cls.G = G - - def test_successor(self): - assert dict(nx.bfs_successors(self.G, source=0)) == {0: [1], 1: [2, 3], 2: [4]} - - def test_predecessor(self): - assert dict(nx.bfs_predecessors(self.G, source=0)) == {1: 0, 2: 1, 3: 1, 4: 2} - - def test_bfs_tree(self): - T = nx.bfs_tree(self.G, source=0) - assert sorted(T.nodes()) == sorted(self.G.nodes()) - assert sorted(T.edges()) == [(0, 1), (1, 2), (1, 3), (2, 4)] - - def test_bfs_edges(self): - edges = nx.bfs_edges(self.G, source=0) - assert list(edges) == [(0, 1), (1, 2), (1, 3), (2, 4)] - - def test_bfs_edges_reverse(self): - D = nx.DiGraph() - D.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = nx.bfs_edges(D, source=4, reverse=True) - assert list(edges) == [(4, 2), (4, 3), (2, 1), (1, 0)] - - def test_bfs_edges_sorting(self): - D = nx.DiGraph() - D.add_edges_from([(0, 1), (0, 2), (1, 4), (1, 3), (2, 5)]) - sort_desc = partial(sorted, reverse=True) - edges_asc = nx.bfs_edges(D, source=0, sort_neighbors=sorted) - edges_desc = nx.bfs_edges(D, source=0, sort_neighbors=sort_desc) - assert list(edges_asc) == [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5)] - assert list(edges_desc) == [(0, 2), (0, 1), (2, 5), (1, 4), (1, 3)] - - def test_bfs_tree_isolates(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - T = nx.bfs_tree(G, source=1) - assert sorted(T.nodes()) == [1] - assert sorted(T.edges()) == [] - - def test_bfs_layers(self): - expected = { - 0: [0], - 1: [1], - 2: [2, 3], - 3: [4], - } - assert dict(enumerate(nx.bfs_layers(self.G, sources=[0]))) == expected - assert dict(enumerate(nx.bfs_layers(self.G, sources=0))) == expected - - def test_bfs_layers_missing_source(self): - with pytest.raises(nx.NetworkXError): - next(nx.bfs_layers(self.G, sources="abc")) - with pytest.raises(nx.NetworkXError): - next(nx.bfs_layers(self.G, sources=["abc"])) - - def test_descendants_at_distance(self): - for distance, descendants in enumerate([{0}, {1}, {2, 3}, {4}]): - assert nx.descendants_at_distance(self.G, 0, distance) == descendants - - def test_descendants_at_distance_missing_source(self): - with pytest.raises(nx.NetworkXError): - nx.descendants_at_distance(self.G, "abc", 0) - - def test_bfs_labeled_edges_directed(self): - D = nx.cycle_graph(5, create_using=nx.DiGraph) - expected = [ - (0, 1, "tree"), - (1, 2, "tree"), - (2, 3, "tree"), - (3, 4, "tree"), - (4, 0, "reverse"), - ] - answer = list(nx.bfs_labeled_edges(D, 0)) - assert expected == answer - - D.add_edge(4, 4) - expected.append((4, 4, "level")) - answer = list(nx.bfs_labeled_edges(D, 0)) - assert expected == answer - - D.add_edge(0, 2) - D.add_edge(1, 5) - D.add_edge(2, 5) - D.remove_edge(4, 4) - expected = [ - (0, 1, "tree"), - (0, 2, "tree"), - (1, 2, "level"), - (1, 5, "tree"), - (2, 3, "tree"), - (2, 5, "forward"), - (3, 4, "tree"), - (4, 0, "reverse"), - ] - answer = list(nx.bfs_labeled_edges(D, 0)) - assert expected == answer - - G = D.to_undirected() - G.add_edge(4, 4) - expected = [ - (0, 1, "tree"), - (0, 2, "tree"), - (0, 4, "tree"), - (1, 2, "level"), - (1, 5, "tree"), - (2, 3, "tree"), - (2, 5, "forward"), - (4, 3, "forward"), - (4, 4, "level"), - ] - answer = list(nx.bfs_labeled_edges(G, 0)) - assert expected == answer - - -class TestBreadthLimitedSearch: - @classmethod - def setup_class(cls): - # a tree - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - nx.add_path(G, [2, 7, 8, 9, 10]) - cls.G = G - # a disconnected graph - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - nx.add_path(D, [2, 7, 8, 9, 10]) - cls.D = D - - def test_limited_bfs_successor(self): - assert dict(nx.bfs_successors(self.G, source=1, depth_limit=3)) == { - 1: [0, 2], - 2: [3, 7], - 3: [4], - 7: [8], - } - result = { - n: sorted(s) for n, s in nx.bfs_successors(self.D, source=7, depth_limit=2) - } - assert result == {8: [9], 2: [3], 7: [2, 8]} - - def test_limited_bfs_predecessor(self): - assert dict(nx.bfs_predecessors(self.G, source=1, depth_limit=3)) == { - 0: 1, - 2: 1, - 3: 2, - 4: 3, - 7: 2, - 8: 7, - } - assert dict(nx.bfs_predecessors(self.D, source=7, depth_limit=2)) == { - 2: 7, - 3: 2, - 8: 7, - 9: 8, - } - - def test_limited_bfs_tree(self): - T = nx.bfs_tree(self.G, source=3, depth_limit=1) - assert sorted(T.edges()) == [(3, 2), (3, 4)] - - def test_limited_bfs_edges(self): - edges = nx.bfs_edges(self.G, source=9, depth_limit=4) - assert list(edges) == [(9, 8), (9, 10), (8, 7), (7, 2), (2, 1), (2, 3)] - - def test_limited_bfs_layers(self): - assert dict(enumerate(nx.bfs_layers(self.G, sources=[0]))) == { - 0: [0], - 1: [1], - 2: [2], - 3: [3, 7], - 4: [4, 8], - 5: [5, 9], - 6: [6, 10], - } - assert dict(enumerate(nx.bfs_layers(self.D, sources=2))) == { - 0: [2], - 1: [3, 7], - 2: [8], - 3: [9], - 4: [10], - } - - def test_limited_descendants_at_distance(self): - for distance, descendants in enumerate( - [{0}, {1}, {2}, {3, 7}, {4, 8}, {5, 9}, {6, 10}] - ): - assert nx.descendants_at_distance(self.G, 0, distance) == descendants - for distance, descendants in enumerate([{2}, {3, 7}, {8}, {9}, {10}]): - assert nx.descendants_at_distance(self.D, 2, distance) == descendants diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_dfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_dfs.py deleted file mode 100644 index e43d7d6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_dfs.py +++ /dev/null @@ -1,305 +0,0 @@ -import networkx as nx - - -class TestDFS: - @classmethod - def setup_class(cls): - # simple graph - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)]) - cls.G = G - # simple graph, disconnected - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - cls.D = D - - def test_preorder_nodes(self): - assert list(nx.dfs_preorder_nodes(self.G, source=0)) == [0, 1, 2, 4, 3] - assert list(nx.dfs_preorder_nodes(self.D)) == [0, 1, 2, 3] - assert list(nx.dfs_preorder_nodes(self.D, source=2)) == [2, 3] - - def test_postorder_nodes(self): - assert list(nx.dfs_postorder_nodes(self.G, source=0)) == [4, 2, 3, 1, 0] - assert list(nx.dfs_postorder_nodes(self.D)) == [1, 0, 3, 2] - assert list(nx.dfs_postorder_nodes(self.D, source=0)) == [1, 0] - - def test_successor(self): - assert nx.dfs_successors(self.G, source=0) == {0: [1], 1: [2, 3], 2: [4]} - assert nx.dfs_successors(self.G, source=1) == {0: [3, 4], 1: [0], 4: [2]} - assert nx.dfs_successors(self.D) == {0: [1], 2: [3]} - assert nx.dfs_successors(self.D, source=1) == {1: [0]} - - def test_predecessor(self): - assert nx.dfs_predecessors(self.G, source=0) == {1: 0, 2: 1, 3: 1, 4: 2} - assert nx.dfs_predecessors(self.D) == {1: 0, 3: 2} - - def test_dfs_tree(self): - exp_nodes = sorted(self.G.nodes()) - exp_edges = [(0, 1), (1, 2), (1, 3), (2, 4)] - # Search from first node - T = nx.dfs_tree(self.G, source=0) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - # Check source=None - T = nx.dfs_tree(self.G, source=None) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - # Check source=None is the default - T = nx.dfs_tree(self.G) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - - def test_dfs_edges(self): - edges = nx.dfs_edges(self.G, source=0) - assert list(edges) == [(0, 1), (1, 2), (2, 4), (1, 3)] - edges = nx.dfs_edges(self.D) - assert list(edges) == [(0, 1), (2, 3)] - - def test_dfs_edges_sorting(self): - G = nx.Graph([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)]) - edges_asc = nx.dfs_edges(G, source=0, sort_neighbors=sorted) - sorted_desc = lambda x: sorted(x, reverse=True) - edges_desc = nx.dfs_edges(G, source=0, sort_neighbors=sorted_desc) - assert list(edges_asc) == [(0, 1), (1, 2), (2, 4), (1, 3)] - assert list(edges_desc) == [(0, 4), (4, 2), (2, 1), (1, 3)] - - def test_dfs_labeled_edges(self): - edges = list(nx.dfs_labeled_edges(self.G, source=0)) - forward = [(u, v) for (u, v, d) in edges if d == "forward"] - assert forward == [(0, 0), (0, 1), (1, 2), (2, 4), (1, 3)] - assert edges == [ - (0, 0, "forward"), - (0, 1, "forward"), - (1, 0, "nontree"), - (1, 2, "forward"), - (2, 1, "nontree"), - (2, 4, "forward"), - (4, 2, "nontree"), - (4, 0, "nontree"), - (2, 4, "reverse"), - (1, 2, "reverse"), - (1, 3, "forward"), - (3, 1, "nontree"), - (3, 0, "nontree"), - (1, 3, "reverse"), - (0, 1, "reverse"), - (0, 3, "nontree"), - (0, 4, "nontree"), - (0, 0, "reverse"), - ] - - def test_dfs_labeled_edges_sorting(self): - G = nx.Graph([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)]) - edges_asc = nx.dfs_labeled_edges(G, source=0, sort_neighbors=sorted) - sorted_desc = lambda x: sorted(x, reverse=True) - edges_desc = nx.dfs_labeled_edges(G, source=0, sort_neighbors=sorted_desc) - assert list(edges_asc) == [ - (0, 0, "forward"), - (0, 1, "forward"), - (1, 0, "nontree"), - (1, 2, "forward"), - (2, 1, "nontree"), - (2, 4, "forward"), - (4, 0, "nontree"), - (4, 2, "nontree"), - (2, 4, "reverse"), - (1, 2, "reverse"), - (1, 3, "forward"), - (3, 0, "nontree"), - (3, 1, "nontree"), - (1, 3, "reverse"), - (0, 1, "reverse"), - (0, 3, "nontree"), - (0, 4, "nontree"), - (0, 0, "reverse"), - ] - assert list(edges_desc) == [ - (0, 0, "forward"), - (0, 4, "forward"), - (4, 2, "forward"), - (2, 4, "nontree"), - (2, 1, "forward"), - (1, 3, "forward"), - (3, 1, "nontree"), - (3, 0, "nontree"), - (1, 3, "reverse"), - (1, 2, "nontree"), - (1, 0, "nontree"), - (2, 1, "reverse"), - (4, 2, "reverse"), - (4, 0, "nontree"), - (0, 4, "reverse"), - (0, 3, "nontree"), - (0, 1, "nontree"), - (0, 0, "reverse"), - ] - - def test_dfs_labeled_disconnected_edges(self): - edges = list(nx.dfs_labeled_edges(self.D)) - forward = [(u, v) for (u, v, d) in edges if d == "forward"] - assert forward == [(0, 0), (0, 1), (2, 2), (2, 3)] - assert edges == [ - (0, 0, "forward"), - (0, 1, "forward"), - (1, 0, "nontree"), - (0, 1, "reverse"), - (0, 0, "reverse"), - (2, 2, "forward"), - (2, 3, "forward"), - (3, 2, "nontree"), - (2, 3, "reverse"), - (2, 2, "reverse"), - ] - - def test_dfs_tree_isolates(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - T = nx.dfs_tree(G, source=1) - assert sorted(T.nodes()) == [1] - assert sorted(T.edges()) == [] - T = nx.dfs_tree(G, source=None) - assert sorted(T.nodes()) == [1, 2] - assert sorted(T.edges()) == [] - - -class TestDepthLimitedSearch: - @classmethod - def setup_class(cls): - # a tree - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - nx.add_path(G, [2, 7, 8, 9, 10]) - cls.G = G - # a disconnected graph - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - nx.add_path(D, [2, 7, 8, 9, 10]) - cls.D = D - - def test_dls_preorder_nodes(self): - assert list(nx.dfs_preorder_nodes(self.G, source=0, depth_limit=2)) == [0, 1, 2] - assert list(nx.dfs_preorder_nodes(self.D, source=1, depth_limit=2)) == ([1, 0]) - - def test_dls_postorder_nodes(self): - assert list(nx.dfs_postorder_nodes(self.G, source=3, depth_limit=3)) == [ - 1, - 7, - 2, - 5, - 4, - 3, - ] - assert list(nx.dfs_postorder_nodes(self.D, source=2, depth_limit=2)) == ( - [3, 7, 2] - ) - - def test_dls_successor(self): - result = nx.dfs_successors(self.G, source=4, depth_limit=3) - assert {n: set(v) for n, v in result.items()} == { - 2: {1, 7}, - 3: {2}, - 4: {3, 5}, - 5: {6}, - } - result = nx.dfs_successors(self.D, source=7, depth_limit=2) - assert {n: set(v) for n, v in result.items()} == {8: {9}, 2: {3}, 7: {8, 2}} - - def test_dls_predecessor(self): - assert nx.dfs_predecessors(self.G, source=0, depth_limit=3) == { - 1: 0, - 2: 1, - 3: 2, - 7: 2, - } - assert nx.dfs_predecessors(self.D, source=2, depth_limit=3) == { - 8: 7, - 9: 8, - 3: 2, - 7: 2, - } - - def test_dls_tree(self): - T = nx.dfs_tree(self.G, source=3, depth_limit=1) - assert sorted(T.edges()) == [(3, 2), (3, 4)] - - def test_dls_edges(self): - edges = nx.dfs_edges(self.G, source=9, depth_limit=4) - assert list(edges) == [(9, 8), (8, 7), (7, 2), (2, 1), (2, 3), (9, 10)] - - def test_dls_labeled_edges_depth_1(self): - edges = list(nx.dfs_labeled_edges(self.G, source=5, depth_limit=1)) - forward = [(u, v) for (u, v, d) in edges if d == "forward"] - assert forward == [(5, 5), (5, 4), (5, 6)] - # Note: reverse-depth_limit edge types were not reported before gh-6240 - assert edges == [ - (5, 5, "forward"), - (5, 4, "forward"), - (5, 4, "reverse-depth_limit"), - (5, 6, "forward"), - (5, 6, "reverse-depth_limit"), - (5, 5, "reverse"), - ] - - def test_dls_labeled_edges_depth_2(self): - edges = list(nx.dfs_labeled_edges(self.G, source=6, depth_limit=2)) - forward = [(u, v) for (u, v, d) in edges if d == "forward"] - assert forward == [(6, 6), (6, 5), (5, 4)] - assert edges == [ - (6, 6, "forward"), - (6, 5, "forward"), - (5, 4, "forward"), - (5, 4, "reverse-depth_limit"), - (5, 6, "nontree"), - (6, 5, "reverse"), - (6, 6, "reverse"), - ] - - def test_dls_labeled_disconnected_edges(self): - edges = list(nx.dfs_labeled_edges(self.D, depth_limit=1)) - assert edges == [ - (0, 0, "forward"), - (0, 1, "forward"), - (0, 1, "reverse-depth_limit"), - (0, 0, "reverse"), - (2, 2, "forward"), - (2, 3, "forward"), - (2, 3, "reverse-depth_limit"), - (2, 7, "forward"), - (2, 7, "reverse-depth_limit"), - (2, 2, "reverse"), - (8, 8, "forward"), - (8, 7, "nontree"), - (8, 9, "forward"), - (8, 9, "reverse-depth_limit"), - (8, 8, "reverse"), - (10, 10, "forward"), - (10, 9, "nontree"), - (10, 10, "reverse"), - ] - # large depth_limit has no impact - edges = list(nx.dfs_labeled_edges(self.D, depth_limit=19)) - assert edges == [ - (0, 0, "forward"), - (0, 1, "forward"), - (1, 0, "nontree"), - (0, 1, "reverse"), - (0, 0, "reverse"), - (2, 2, "forward"), - (2, 3, "forward"), - (3, 2, "nontree"), - (2, 3, "reverse"), - (2, 7, "forward"), - (7, 2, "nontree"), - (7, 8, "forward"), - (8, 7, "nontree"), - (8, 9, "forward"), - (9, 8, "nontree"), - (9, 10, "forward"), - (10, 9, "nontree"), - (9, 10, "reverse"), - (8, 9, "reverse"), - (7, 8, "reverse"), - (2, 7, "reverse"), - (2, 2, "reverse"), - ] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py deleted file mode 100644 index 1bf3fae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py +++ /dev/null @@ -1,147 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE - - -class TestEdgeBFS: - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)] - - def test_empty(self): - G = nx.Graph() - edges = list(nx.edge_bfs(G)) - assert edges == [] - - def test_graph_single_source(self): - G = nx.Graph(self.edges) - G.add_edge(4, 5) - x = list(nx.edge_bfs(G, [0])) - x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] - assert x == x_ - - def test_graph(self): - G = nx.Graph(self.edges) - x = list(nx.edge_bfs(G, self.nodes)) - x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes)) - x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_invalid(self): - G = nx.DiGraph(self.edges) - edge_iterator = nx.edge_bfs(G, self.nodes, orientation="hello") - pytest.raises(nx.NetworkXError, list, edge_iterator) - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation="original")) - x_ = [ - (0, 1, FORWARD), - (1, 0, FORWARD), - (2, 0, FORWARD), - (2, 1, FORWARD), - (3, 1, FORWARD), - ] - assert x == x_ - - def test_digraph2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(nx.edge_bfs(G, [0])) - x_ = [(0, 1), (1, 2), (2, 3)] - assert x == x_ - - def test_digraph_rev(self): - G = nx.DiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation="reverse")) - x_ = [ - (1, 0, REVERSE), - (2, 0, REVERSE), - (0, 1, REVERSE), - (2, 1, REVERSE), - (3, 1, REVERSE), - ] - assert x == x_ - - def test_digraph_rev2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(nx.edge_bfs(G, [3], orientation="reverse")) - x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes)) - x_ = [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)] - # This is an example of where hash randomization can break. - # There are 3! * 2 alternative outputs, such as: - # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)] - # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k) - # edges. So the algorithm only guarantees a partial order. A total - # order is guaranteed only if the graph data structures are ordered. - assert x == x_ - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)] - assert x == x_ - - def test_multidigraph_rev(self): - G = nx.MultiDiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation="reverse")) - x_ = [ - (1, 0, 0, REVERSE), - (1, 0, 1, REVERSE), - (2, 0, 0, REVERSE), - (0, 1, 0, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE), - ] - assert x == x_ - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation="ignore")) - x_ = [ - (0, 1, FORWARD), - (1, 0, REVERSE), - (2, 0, REVERSE), - (2, 1, REVERSE), - (3, 1, REVERSE), - ] - assert x == x_ - - def test_digraph_ignore2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(nx.edge_bfs(G, [0], orientation="ignore")) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(nx.edge_bfs(G, self.nodes, orientation="ignore")) - x_ = [ - (0, 1, 0, FORWARD), - (1, 0, 0, REVERSE), - (1, 0, 1, REVERSE), - (2, 0, 0, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE), - ] - assert x == x_ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py deleted file mode 100644 index 7c1967c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py +++ /dev/null @@ -1,131 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import edge_dfs -from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE - -# These tests can fail with hash randomization. The easiest and clearest way -# to write these unit tests is for the edges to be output in an expected total -# order, but we cannot guarantee the order amongst outgoing edges from a node, -# unless each class uses an ordered data structure for neighbors. This is -# painful to do with the current API. The alternative is that the tests are -# written (IMO confusingly) so that there is not a total order over the edges, -# but only a partial order. Due to the small size of the graphs, hopefully -# failures due to hash randomization will not occur. For an example of how -# this can fail, see TestEdgeDFS.test_multigraph. - - -class TestEdgeDFS: - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - def test_empty(self): - G = nx.Graph() - edges = list(edge_dfs(G)) - assert edges == [] - - def test_graph(self): - G = nx.Graph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1), (1, 2), (1, 3)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1), (1, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_invalid(self): - G = nx.DiGraph(self.edges) - edge_iterator = edge_dfs(G, self.nodes, orientation="hello") - pytest.raises(nx.NetworkXError, list, edge_iterator) - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation="original")) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, FORWARD), (3, 1, FORWARD)] - assert x == x_ - - def test_digraph2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [0])) - x_ = [(0, 1), (1, 2), (2, 3)] - assert x == x_ - - def test_digraph_rev(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation="reverse")) - x_ = [(1, 0, REVERSE), (0, 1, REVERSE), (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_rev2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [3], orientation="reverse")) - x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)] - # This is an example of where hash randomization can break. - # There are 3! * 2 alternative outputs, such as: - # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)] - # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k) - # edges. So the algorithm only guarantees a partial order. A total - # order is guaranteed only if the graph data structures are ordered. - assert x == x_ - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)] - assert x == x_ - - def test_multidigraph_rev(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation="reverse")) - x_ = [ - (1, 0, 0, REVERSE), - (0, 1, 0, REVERSE), - (1, 0, 1, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE), - ] - assert x == x_ - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation="ignore")) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_ignore2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [0], orientation="ignore")) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation="ignore")) - x_ = [ - (0, 1, 0, FORWARD), - (1, 0, 0, FORWARD), - (1, 0, 1, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE), - ] - assert x == x_ diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/__init__.py deleted file mode 100644 index 7120d4b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .branchings import * -from .coding import * -from .mst import * -from .recognition import * -from .operations import * -from .decomposition import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/branchings.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/branchings.py deleted file mode 100644 index cc9c7cf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/branchings.py +++ /dev/null @@ -1,1042 +0,0 @@ -""" -Algorithms for finding optimum branchings and spanning arborescences. - -This implementation is based on: - - J. Edmonds, Optimum branchings, J. Res. Natl. Bur. Standards 71B (1967), - 233–240. URL: http://archive.org/details/jresv71Bn4p233 - -""" - -# TODO: Implement method from Gabow, Galil, Spence and Tarjan: -# -# @article{ -# year={1986}, -# issn={0209-9683}, -# journal={Combinatorica}, -# volume={6}, -# number={2}, -# doi={10.1007/BF02579168}, -# title={Efficient algorithms for finding minimum spanning trees in -# undirected and directed graphs}, -# url={https://doi.org/10.1007/BF02579168}, -# publisher={Springer-Verlag}, -# keywords={68 B 15; 68 C 05}, -# author={Gabow, Harold N. and Galil, Zvi and Spencer, Thomas and Tarjan, -# Robert E.}, -# pages={109-122}, -# language={English} -# } -import string -from dataclasses import dataclass, field -from operator import itemgetter -from queue import PriorityQueue - -import networkx as nx -from networkx.utils import py_random_state - -from .recognition import is_arborescence, is_branching - -__all__ = [ - "branching_weight", - "greedy_branching", - "maximum_branching", - "minimum_branching", - "minimal_branching", - "maximum_spanning_arborescence", - "minimum_spanning_arborescence", - "ArborescenceIterator", -] - -KINDS = {"max", "min"} - -STYLES = { - "branching": "branching", - "arborescence": "arborescence", - "spanning arborescence": "arborescence", -} - -INF = float("inf") - - -@py_random_state(1) -def random_string(L=15, seed=None): - return "".join([seed.choice(string.ascii_letters) for n in range(L)]) - - -def _min_weight(weight): - return -weight - - -def _max_weight(weight): - return weight - - -@nx._dispatchable(edge_attrs={"attr": "default"}) -def branching_weight(G, attr="weight", default=1): - """ - Returns the total weight of a branching. - - You must access this function through the networkx.algorithms.tree module. - - Parameters - ---------- - G : DiGraph - The directed graph. - attr : str - The attribute to use as weights. If None, then each edge will be - treated equally with a weight of 1. - default : float - When `attr` is not None, then if an edge does not have that attribute, - `default` specifies what value it should take. - - Returns - ------- - weight: int or float - The total weight of the branching. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from([(0, 1, 2), (1, 2, 4), (2, 3, 3), (3, 4, 2)]) - >>> nx.tree.branching_weight(G) - 11 - - """ - return sum(edge[2].get(attr, default) for edge in G.edges(data=True)) - - -@py_random_state(4) -@nx._dispatchable(edge_attrs={"attr": "default"}, returns_graph=True) -def greedy_branching(G, attr="weight", default=1, kind="max", seed=None): - """ - Returns a branching obtained through a greedy algorithm. - - This algorithm is wrong, and cannot give a proper optimal branching. - However, we include it for pedagogical reasons, as it can be helpful to - see what its outputs are. - - The output is a branching, and possibly, a spanning arborescence. However, - it is not guaranteed to be optimal in either case. - - Parameters - ---------- - G : DiGraph - The directed graph to scan. - attr : str - The attribute to use as weights. If None, then each edge will be - treated equally with a weight of 1. - default : float - When `attr` is not None, then if an edge does not have that attribute, - `default` specifies what value it should take. - kind : str - The type of optimum to search for: 'min' or 'max' greedy branching. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - B : directed graph - The greedily obtained branching. - - """ - if kind not in KINDS: - raise nx.NetworkXException("Unknown value for `kind`.") - - if kind == "min": - reverse = False - else: - reverse = True - - if attr is None: - # Generate a random string the graph probably won't have. - attr = random_string(seed=seed) - - edges = [(u, v, data.get(attr, default)) for (u, v, data) in G.edges(data=True)] - - # We sort by weight, but also by nodes to normalize behavior across runs. - try: - edges.sort(key=itemgetter(2, 0, 1), reverse=reverse) - except TypeError: - # This will fail in Python 3.x if the nodes are of varying types. - # In that case, we use the arbitrary order. - edges.sort(key=itemgetter(2), reverse=reverse) - - # The branching begins with a forest of no edges. - B = nx.DiGraph() - B.add_nodes_from(G) - - # Now we add edges greedily so long we maintain the branching. - uf = nx.utils.UnionFind() - for i, (u, v, w) in enumerate(edges): - if uf[u] == uf[v]: - # Adding this edge would form a directed cycle. - continue - elif B.in_degree(v) == 1: - # The edge would increase the degree to be greater than one. - continue - else: - # If attr was None, then don't insert weights... - data = {} - if attr is not None: - data[attr] = w - B.add_edge(u, v, **data) - uf.union(u, v) - - return B - - -@nx._dispatchable(preserve_edge_attrs=True, returns_graph=True) -def maximum_branching( - G, - attr="weight", - default=1, - preserve_attrs=False, - partition=None, -): - ####################################### - ### Data Structure Helper Functions ### - ####################################### - - def edmonds_add_edge(G, edge_index, u, v, key, **d): - """ - Adds an edge to `G` while also updating the edge index. - - This algorithm requires the use of an external dictionary to track - the edge keys since it is possible that the source or destination - node of an edge will be changed and the default key-handling - capabilities of the MultiDiGraph class do not account for this. - - Parameters - ---------- - G : MultiDiGraph - The graph to insert an edge into. - edge_index : dict - A mapping from integers to the edges of the graph. - u : node - The source node of the new edge. - v : node - The destination node of the new edge. - key : int - The key to use from `edge_index`. - d : keyword arguments, optional - Other attributes to store on the new edge. - """ - - if key in edge_index: - uu, vv, _ = edge_index[key] - if (u != uu) or (v != vv): - raise Exception(f"Key {key!r} is already in use.") - - G.add_edge(u, v, key, **d) - edge_index[key] = (u, v, G.succ[u][v][key]) - - def edmonds_remove_node(G, edge_index, n): - """ - Remove a node from the graph, updating the edge index to match. - - Parameters - ---------- - G : MultiDiGraph - The graph to remove an edge from. - edge_index : dict - A mapping from integers to the edges of the graph. - n : node - The node to remove from `G`. - """ - keys = set() - for keydict in G.pred[n].values(): - keys.update(keydict) - for keydict in G.succ[n].values(): - keys.update(keydict) - - for key in keys: - del edge_index[key] - - G.remove_node(n) - - ####################### - ### Algorithm Setup ### - ####################### - - # Pick an attribute name that the original graph is unlikly to have - candidate_attr = "edmonds' secret candidate attribute" - new_node_base_name = "edmonds new node base name " - - G_original = G - G = nx.MultiDiGraph() - G.__networkx_cache__ = None # Disable caching - - # A dict to reliably track mutations to the edges using the key of the edge. - G_edge_index = {} - # Each edge is given an arbitrary numerical key - for key, (u, v, data) in enumerate(G_original.edges(data=True)): - d = {attr: data.get(attr, default)} - - if data.get(partition) is not None: - d[partition] = data.get(partition) - - if preserve_attrs: - for d_k, d_v in data.items(): - if d_k != attr: - d[d_k] = d_v - - edmonds_add_edge(G, G_edge_index, u, v, key, **d) - - level = 0 # Stores the number of contracted nodes - - # These are the buckets from the paper. - # - # In the paper, G^i are modified versions of the original graph. - # D^i and E^i are the nodes and edges of the maximal edges that are - # consistent with G^i. In this implementation, D^i and E^i are stored - # together as the graph B^i. We will have strictly more B^i then the - # paper will have. - # - # Note that the data in graphs and branchings are tuples with the graph as - # the first element and the edge index as the second. - B = nx.MultiDiGraph() - B_edge_index = {} - graphs = [] # G^i list - branchings = [] # B^i list - selected_nodes = set() # D^i bucket - uf = nx.utils.UnionFind() - - # A list of lists of edge indices. Each list is a circuit for graph G^i. - # Note the edge list is not required to be a circuit in G^0. - circuits = [] - - # Stores the index of the minimum edge in the circuit found in G^i and B^i. - # The ordering of the edges seems to preserver the weight ordering from - # G^0. So even if the circuit does not form a circuit in G^0, it is still - # true that the minimum edges in circuit G^0 (despite their weights being - # different) - minedge_circuit = [] - - ########################### - ### Algorithm Structure ### - ########################### - - # Each step listed in the algorithm is an inner function. Thus, the overall - # loop structure is: - # - # while True: - # step_I1() - # if cycle detected: - # step_I2() - # elif every node of G is in D and E is a branching: - # break - - ################################## - ### Algorithm Helper Functions ### - ################################## - - def edmonds_find_desired_edge(v): - """ - Find the edge directed towards v with maximal weight. - - If an edge partition exists in this graph, return the included - edge if it exists and never return any excluded edge. - - Note: There can only be one included edge for each vertex otherwise - the edge partition is empty. - - Parameters - ---------- - v : node - The node to search for the maximal weight incoming edge. - """ - edge = None - max_weight = -INF - for u, _, key, data in G.in_edges(v, data=True, keys=True): - # Skip excluded edges - if data.get(partition) == nx.EdgePartition.EXCLUDED: - continue - - new_weight = data[attr] - - # Return the included edge - if data.get(partition) == nx.EdgePartition.INCLUDED: - max_weight = new_weight - edge = (u, v, key, new_weight, data) - break - - # Find the best open edge - if new_weight > max_weight: - max_weight = new_weight - edge = (u, v, key, new_weight, data) - - return edge, max_weight - - def edmonds_step_I2(v, desired_edge, level): - """ - Perform step I2 from Edmonds' paper - - First, check if the last step I1 created a cycle. If it did not, do nothing. - If it did, store the cycle for later reference and contract it. - - Parameters - ---------- - v : node - The current node to consider - desired_edge : edge - The minimum desired edge to remove from the cycle. - level : int - The current level, i.e. the number of cycles that have already been removed. - """ - u = desired_edge[0] - - Q_nodes = nx.shortest_path(B, v, u) - Q_edges = [ - list(B[Q_nodes[i]][vv].keys())[0] for i, vv in enumerate(Q_nodes[1:]) - ] - Q_edges.append(desired_edge[2]) # Add the new edge key to complete the circuit - - # Get the edge in the circuit with the minimum weight. - # Also, save the incoming weights for each node. - minweight = INF - minedge = None - Q_incoming_weight = {} - for edge_key in Q_edges: - u, v, data = B_edge_index[edge_key] - w = data[attr] - # We cannot remove an included edge, even if it is the - # minimum edge in the circuit - Q_incoming_weight[v] = w - if data.get(partition) == nx.EdgePartition.INCLUDED: - continue - if w < minweight: - minweight = w - minedge = edge_key - - circuits.append(Q_edges) - minedge_circuit.append(minedge) - graphs.append((G.copy(), G_edge_index.copy())) - branchings.append((B.copy(), B_edge_index.copy())) - - # Mutate the graph to contract the circuit - new_node = new_node_base_name + str(level) - G.add_node(new_node) - new_edges = [] - for u, v, key, data in G.edges(data=True, keys=True): - if u in Q_incoming_weight: - if v in Q_incoming_weight: - # Circuit edge. For the moment do nothing, - # eventually it will be removed. - continue - else: - # Outgoing edge from a node in the circuit. - # Make it come from the new node instead - dd = data.copy() - new_edges.append((new_node, v, key, dd)) - else: - if v in Q_incoming_weight: - # Incoming edge to the circuit. - # Update it's weight - w = data[attr] - w += minweight - Q_incoming_weight[v] - dd = data.copy() - dd[attr] = w - new_edges.append((u, new_node, key, dd)) - else: - # Outside edge. No modification needed - continue - - for node in Q_nodes: - edmonds_remove_node(G, G_edge_index, node) - edmonds_remove_node(B, B_edge_index, node) - - selected_nodes.difference_update(set(Q_nodes)) - - for u, v, key, data in new_edges: - edmonds_add_edge(G, G_edge_index, u, v, key, **data) - if candidate_attr in data: - del data[candidate_attr] - edmonds_add_edge(B, B_edge_index, u, v, key, **data) - uf.union(u, v) - - def is_root(G, u, edgekeys): - """ - Returns True if `u` is a root node in G. - - Node `u` is a root node if its in-degree over the specified edges is zero. - - Parameters - ---------- - G : Graph - The current graph. - u : node - The node in `G` to check if it is a root. - edgekeys : iterable of edges - The edges for which to check if `u` is a root of. - """ - if u not in G: - raise Exception(f"{u!r} not in G") - - for v in G.pred[u]: - for edgekey in G.pred[u][v]: - if edgekey in edgekeys: - return False, edgekey - else: - return True, None - - nodes = iter(list(G.nodes)) - while True: - try: - v = next(nodes) - except StopIteration: - # If there are no more new nodes to consider, then we should - # meet stopping condition (b) from the paper: - # (b) every node of G^i is in D^i and E^i is a branching - assert len(G) == len(B) - if len(B): - assert is_branching(B) - - graphs.append((G.copy(), G_edge_index.copy())) - branchings.append((B.copy(), B_edge_index.copy())) - circuits.append([]) - minedge_circuit.append(None) - - break - else: - ##################### - ### BEGIN STEP I1 ### - ##################### - - # This is a very simple step, so I don't think it needs a method of it's own - if v in selected_nodes: - continue - - selected_nodes.add(v) - B.add_node(v) - desired_edge, desired_edge_weight = edmonds_find_desired_edge(v) - - # There might be no desired edge if all edges are excluded or - # v is the last node to be added to B, the ultimate root of the branching - if desired_edge is not None and desired_edge_weight > 0: - u = desired_edge[0] - # Flag adding the edge will create a circuit before merging the two - # connected components of u and v in B - circuit = uf[u] == uf[v] - dd = {attr: desired_edge_weight} - if desired_edge[4].get(partition) is not None: - dd[partition] = desired_edge[4].get(partition) - - edmonds_add_edge(B, B_edge_index, u, v, desired_edge[2], **dd) - G[u][v][desired_edge[2]][candidate_attr] = True - uf.union(u, v) - - ################### - ### END STEP I1 ### - ################### - - ##################### - ### BEGIN STEP I2 ### - ##################### - - if circuit: - edmonds_step_I2(v, desired_edge, level) - nodes = iter(list(G.nodes())) - level += 1 - - ################### - ### END STEP I2 ### - ################### - - ##################### - ### BEGIN STEP I3 ### - ##################### - - # Create a new graph of the same class as the input graph - H = G_original.__class__() - - # Start with the branching edges in the last level. - edges = set(branchings[level][1]) - while level > 0: - level -= 1 - - # The current level is i, and we start counting from 0. - # - # We need the node at level i+1 that results from merging a circuit - # at level i. basename_0 is the first merged node and this happens - # at level 1. That is basename_0 is a node at level 1 that results - # from merging a circuit at level 0. - - merged_node = new_node_base_name + str(level) - circuit = circuits[level] - isroot, edgekey = is_root(graphs[level + 1][0], merged_node, edges) - edges.update(circuit) - - if isroot: - minedge = minedge_circuit[level] - if minedge is None: - raise Exception - - # Remove the edge in the cycle with minimum weight - edges.remove(minedge) - else: - # We have identified an edge at the next higher level that - # transitions into the merged node at this level. That edge - # transitions to some corresponding node at the current level. - # - # We want to remove an edge from the cycle that transitions - # into the corresponding node, otherwise the result would not - # be a branching. - - G, G_edge_index = graphs[level] - target = G_edge_index[edgekey][1] - for edgekey in circuit: - u, v, data = G_edge_index[edgekey] - if v == target: - break - else: - raise Exception("Couldn't find edge incoming to merged node.") - - edges.remove(edgekey) - - H.add_nodes_from(G_original) - for edgekey in edges: - u, v, d = graphs[0][1][edgekey] - dd = {attr: d[attr]} - - if preserve_attrs: - for key, value in d.items(): - if key not in [attr, candidate_attr]: - dd[key] = value - - H.add_edge(u, v, **dd) - - ################### - ### END STEP I3 ### - ################### - - return H - - -@nx._dispatchable(preserve_edge_attrs=True, mutates_input=True, returns_graph=True) -def minimum_branching( - G, attr="weight", default=1, preserve_attrs=False, partition=None -): - for _, _, d in G.edges(data=True): - d[attr] = -d.get(attr, default) - nx._clear_cache(G) - - B = maximum_branching(G, attr, default, preserve_attrs, partition) - - for _, _, d in G.edges(data=True): - d[attr] = -d.get(attr, default) - nx._clear_cache(G) - - for _, _, d in B.edges(data=True): - d[attr] = -d.get(attr, default) - nx._clear_cache(B) - - return B - - -@nx._dispatchable(preserve_edge_attrs=True, mutates_input=True, returns_graph=True) -def minimal_branching( - G, /, *, attr="weight", default=1, preserve_attrs=False, partition=None -): - """ - Returns a minimal branching from `G`. - - A minimal branching is a branching similar to a minimal arborescence but - without the requirement that the result is actually a spanning arborescence. - This allows minimal branchinges to be computed over graphs which may not - have arborescence (such as multiple components). - - Parameters - ---------- - G : (multi)digraph-like - The graph to be searched. - attr : str - The edge attribute used in determining optimality. - default : float - The value of the edge attribute used if an edge does not have - the attribute `attr`. - preserve_attrs : bool - If True, preserve the other attributes of the original graph (that are not - passed to `attr`) - partition : str - The key for the edge attribute containing the partition - data on the graph. Edges can be included, excluded or open using the - `EdgePartition` enum. - - Returns - ------- - B : (multi)digraph-like - A minimal branching. - """ - max_weight = -INF - min_weight = INF - for _, _, w in G.edges(data=attr, default=default): - if w > max_weight: - max_weight = w - if w < min_weight: - min_weight = w - - for _, _, d in G.edges(data=True): - # Transform the weights so that the minimum weight is larger than - # the difference between the max and min weights. This is important - # in order to prevent the edge weights from becoming negative during - # computation - d[attr] = max_weight + 1 + (max_weight - min_weight) - d.get(attr, default) - nx._clear_cache(G) - - B = maximum_branching(G, attr, default, preserve_attrs, partition) - - # Reverse the weight transformations - for _, _, d in G.edges(data=True): - d[attr] = max_weight + 1 + (max_weight - min_weight) - d.get(attr, default) - nx._clear_cache(G) - - for _, _, d in B.edges(data=True): - d[attr] = max_weight + 1 + (max_weight - min_weight) - d.get(attr, default) - nx._clear_cache(B) - - return B - - -@nx._dispatchable(preserve_edge_attrs=True, mutates_input=True, returns_graph=True) -def maximum_spanning_arborescence( - G, attr="weight", default=1, preserve_attrs=False, partition=None -): - # In order to use the same algorithm is the maximum branching, we need to adjust - # the weights of the graph. The branching algorithm can choose to not include an - # edge if it doesn't help find a branching, mainly triggered by edges with negative - # weights. - # - # To prevent this from happening while trying to find a spanning arborescence, we - # just have to tweak the edge weights so that they are all positive and cannot - # become negative during the branching algorithm, find the maximum branching and - # then return them to their original values. - - min_weight = INF - max_weight = -INF - for _, _, w in G.edges(data=attr, default=default): - if w < min_weight: - min_weight = w - if w > max_weight: - max_weight = w - - for _, _, d in G.edges(data=True): - d[attr] = d.get(attr, default) - min_weight + 1 - (min_weight - max_weight) - nx._clear_cache(G) - - B = maximum_branching(G, attr, default, preserve_attrs, partition) - - for _, _, d in G.edges(data=True): - d[attr] = d.get(attr, default) + min_weight - 1 + (min_weight - max_weight) - nx._clear_cache(G) - - for _, _, d in B.edges(data=True): - d[attr] = d.get(attr, default) + min_weight - 1 + (min_weight - max_weight) - nx._clear_cache(B) - - if not is_arborescence(B): - raise nx.exception.NetworkXException("No maximum spanning arborescence in G.") - - return B - - -@nx._dispatchable(preserve_edge_attrs=True, mutates_input=True, returns_graph=True) -def minimum_spanning_arborescence( - G, attr="weight", default=1, preserve_attrs=False, partition=None -): - B = minimal_branching( - G, - attr=attr, - default=default, - preserve_attrs=preserve_attrs, - partition=partition, - ) - - if not is_arborescence(B): - raise nx.exception.NetworkXException("No minimum spanning arborescence in G.") - - return B - - -docstring_branching = """ -Returns a {kind} {style} from G. - -Parameters ----------- -G : (multi)digraph-like - The graph to be searched. -attr : str - The edge attribute used to in determining optimality. -default : float - The value of the edge attribute used if an edge does not have - the attribute `attr`. -preserve_attrs : bool - If True, preserve the other attributes of the original graph (that are not - passed to `attr`) -partition : str - The key for the edge attribute containing the partition - data on the graph. Edges can be included, excluded or open using the - `EdgePartition` enum. - -Returns -------- -B : (multi)digraph-like - A {kind} {style}. -""" - -docstring_arborescence = ( - docstring_branching - + """ -Raises ------- -NetworkXException - If the graph does not contain a {kind} {style}. - -""" -) - -maximum_branching.__doc__ = docstring_branching.format( - kind="maximum", style="branching" -) - -minimum_branching.__doc__ = ( - docstring_branching.format(kind="minimum", style="branching") - + """ -See Also --------- - minimal_branching -""" -) - -maximum_spanning_arborescence.__doc__ = docstring_arborescence.format( - kind="maximum", style="spanning arborescence" -) - -minimum_spanning_arborescence.__doc__ = docstring_arborescence.format( - kind="minimum", style="spanning arborescence" -) - - -class ArborescenceIterator: - """ - Iterate over all spanning arborescences of a graph in either increasing or - decreasing cost. - - Notes - ----- - This iterator uses the partition scheme from [1]_ (included edges, - excluded edges and open edges). It generates minimum spanning - arborescences using a modified Edmonds' Algorithm which respects the - partition of edges. For arborescences with the same weight, ties are - broken arbitrarily. - - References - ---------- - .. [1] G.K. Janssens, K. Sörensen, An algorithm to generate all spanning - trees in order of increasing cost, Pesquisa Operacional, 2005-08, - Vol. 25 (2), p. 219-229, - https://www.scielo.br/j/pope/a/XHswBwRwJyrfL88dmMwYNWp/?lang=en - """ - - @dataclass(order=True) - class Partition: - """ - This dataclass represents a partition and stores a dict with the edge - data and the weight of the minimum spanning arborescence of the - partition dict. - """ - - mst_weight: float - partition_dict: dict = field(compare=False) - - def __copy__(self): - return ArborescenceIterator.Partition( - self.mst_weight, self.partition_dict.copy() - ) - - def __init__(self, G, weight="weight", minimum=True, init_partition=None): - """ - Initialize the iterator - - Parameters - ---------- - G : nx.DiGraph - The directed graph which we need to iterate trees over - - weight : String, default = "weight" - The edge attribute used to store the weight of the edge - - minimum : bool, default = True - Return the trees in increasing order while true and decreasing order - while false. - - init_partition : tuple, default = None - In the case that certain edges have to be included or excluded from - the arborescences, `init_partition` should be in the form - `(included_edges, excluded_edges)` where each edges is a - `(u, v)`-tuple inside an iterable such as a list or set. - - """ - self.G = G.copy() - self.weight = weight - self.minimum = minimum - self.method = ( - minimum_spanning_arborescence if minimum else maximum_spanning_arborescence - ) - # Randomly create a key for an edge attribute to hold the partition data - self.partition_key = ( - "ArborescenceIterators super secret partition attribute name" - ) - if init_partition is not None: - partition_dict = {} - for e in init_partition[0]: - partition_dict[e] = nx.EdgePartition.INCLUDED - for e in init_partition[1]: - partition_dict[e] = nx.EdgePartition.EXCLUDED - self.init_partition = ArborescenceIterator.Partition(0, partition_dict) - else: - self.init_partition = None - - def __iter__(self): - """ - Returns - ------- - ArborescenceIterator - The iterator object for this graph - """ - self.partition_queue = PriorityQueue() - self._clear_partition(self.G) - - # Write the initial partition if it exists. - if self.init_partition is not None: - self._write_partition(self.init_partition) - - mst_weight = self.method( - self.G, - self.weight, - partition=self.partition_key, - preserve_attrs=True, - ).size(weight=self.weight) - - self.partition_queue.put( - self.Partition( - mst_weight if self.minimum else -mst_weight, - ( - {} - if self.init_partition is None - else self.init_partition.partition_dict - ), - ) - ) - - return self - - def __next__(self): - """ - Returns - ------- - (multi)Graph - The spanning tree of next greatest weight, which ties broken - arbitrarily. - """ - if self.partition_queue.empty(): - del self.G, self.partition_queue - raise StopIteration - - partition = self.partition_queue.get() - self._write_partition(partition) - next_arborescence = self.method( - self.G, - self.weight, - partition=self.partition_key, - preserve_attrs=True, - ) - self._partition(partition, next_arborescence) - - self._clear_partition(next_arborescence) - return next_arborescence - - def _partition(self, partition, partition_arborescence): - """ - Create new partitions based of the minimum spanning tree of the - current minimum partition. - - Parameters - ---------- - partition : Partition - The Partition instance used to generate the current minimum spanning - tree. - partition_arborescence : nx.Graph - The minimum spanning arborescence of the input partition. - """ - # create two new partitions with the data from the input partition dict - p1 = self.Partition(0, partition.partition_dict.copy()) - p2 = self.Partition(0, partition.partition_dict.copy()) - for e in partition_arborescence.edges: - # determine if the edge was open or included - if e not in partition.partition_dict: - # This is an open edge - p1.partition_dict[e] = nx.EdgePartition.EXCLUDED - p2.partition_dict[e] = nx.EdgePartition.INCLUDED - - self._write_partition(p1) - try: - p1_mst = self.method( - self.G, - self.weight, - partition=self.partition_key, - preserve_attrs=True, - ) - - p1_mst_weight = p1_mst.size(weight=self.weight) - p1.mst_weight = p1_mst_weight if self.minimum else -p1_mst_weight - self.partition_queue.put(p1.__copy__()) - except nx.NetworkXException: - pass - - p1.partition_dict = p2.partition_dict.copy() - - def _write_partition(self, partition): - """ - Writes the desired partition into the graph to calculate the minimum - spanning tree. Also, if one incoming edge is included, mark all others - as excluded so that if that vertex is merged during Edmonds' algorithm - we cannot still pick another of that vertex's included edges. - - Parameters - ---------- - partition : Partition - A Partition dataclass describing a partition on the edges of the - graph. - """ - for u, v, d in self.G.edges(data=True): - if (u, v) in partition.partition_dict: - d[self.partition_key] = partition.partition_dict[(u, v)] - else: - d[self.partition_key] = nx.EdgePartition.OPEN - nx._clear_cache(self.G) - - for n in self.G: - included_count = 0 - excluded_count = 0 - for u, v, d in self.G.in_edges(nbunch=n, data=True): - if d.get(self.partition_key) == nx.EdgePartition.INCLUDED: - included_count += 1 - elif d.get(self.partition_key) == nx.EdgePartition.EXCLUDED: - excluded_count += 1 - # Check that if there is an included edges, all other incoming ones - # are excluded. If not fix it! - if included_count == 1 and excluded_count != self.G.in_degree(n) - 1: - for u, v, d in self.G.in_edges(nbunch=n, data=True): - if d.get(self.partition_key) != nx.EdgePartition.INCLUDED: - d[self.partition_key] = nx.EdgePartition.EXCLUDED - - def _clear_partition(self, G): - """ - Removes partition data from the graph - """ - for u, v, d in G.edges(data=True): - if self.partition_key in d: - del d[self.partition_key] - nx._clear_cache(self.G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/coding.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/coding.py deleted file mode 100644 index f33089f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/coding.py +++ /dev/null @@ -1,413 +0,0 @@ -"""Functions for encoding and decoding trees. - -Since a tree is a highly restricted form of graph, it can be represented -concisely in several ways. This module includes functions for encoding -and decoding trees in the form of nested tuples and Prüfer -sequences. The former requires a rooted tree, whereas the latter can be -applied to unrooted trees. Furthermore, there is a bijection from Prüfer -sequences to labeled trees. - -""" - -from collections import Counter -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "from_nested_tuple", - "from_prufer_sequence", - "NotATree", - "to_nested_tuple", - "to_prufer_sequence", -] - - -class NotATree(nx.NetworkXException): - """Raised when a function expects a tree (that is, a connected - undirected graph with no cycles) but gets a non-tree graph as input - instead. - - """ - - -@not_implemented_for("directed") -@nx._dispatchable(graphs="T") -def to_nested_tuple(T, root, canonical_form=False): - """Returns a nested tuple representation of the given tree. - - The nested tuple representation of a tree is defined - recursively. The tree with one node and no edges is represented by - the empty tuple, ``()``. A tree with ``k`` subtrees is represented - by a tuple of length ``k`` in which each element is the nested tuple - representation of a subtree. - - Parameters - ---------- - T : NetworkX graph - An undirected graph object representing a tree. - - root : node - The node in ``T`` to interpret as the root of the tree. - - canonical_form : bool - If ``True``, each tuple is sorted so that the function returns - a canonical form for rooted trees. This means "lighter" subtrees - will appear as nested tuples before "heavier" subtrees. In this - way, each isomorphic rooted tree has the same nested tuple - representation. - - Returns - ------- - tuple - A nested tuple representation of the tree. - - Notes - ----- - This function is *not* the inverse of :func:`from_nested_tuple`; the - only guarantee is that the rooted trees are isomorphic. - - See also - -------- - from_nested_tuple - to_prufer_sequence - - Examples - -------- - The tree need not be a balanced binary tree:: - - >>> T = nx.Graph() - >>> T.add_edges_from([(0, 1), (0, 2), (0, 3)]) - >>> T.add_edges_from([(1, 4), (1, 5)]) - >>> T.add_edges_from([(3, 6), (3, 7)]) - >>> root = 0 - >>> nx.to_nested_tuple(T, root) - (((), ()), (), ((), ())) - - Continuing the above example, if ``canonical_form`` is ``True``, the - nested tuples will be sorted:: - - >>> nx.to_nested_tuple(T, root, canonical_form=True) - ((), ((), ()), ((), ())) - - Even the path graph can be interpreted as a tree:: - - >>> T = nx.path_graph(4) - >>> root = 0 - >>> nx.to_nested_tuple(T, root) - ((((),),),) - - """ - - def _make_tuple(T, root, _parent): - """Recursively compute the nested tuple representation of the - given rooted tree. - - ``_parent`` is the parent node of ``root`` in the supertree in - which ``T`` is a subtree, or ``None`` if ``root`` is the root of - the supertree. This argument is used to determine which - neighbors of ``root`` are children and which is the parent. - - """ - # Get the neighbors of `root` that are not the parent node. We - # are guaranteed that `root` is always in `T` by construction. - children = set(T[root]) - {_parent} - if len(children) == 0: - return () - nested = (_make_tuple(T, v, root) for v in children) - if canonical_form: - nested = sorted(nested) - return tuple(nested) - - # Do some sanity checks on the input. - if not nx.is_tree(T): - raise nx.NotATree("provided graph is not a tree") - if root not in T: - raise nx.NodeNotFound(f"Graph {T} contains no node {root}") - - return _make_tuple(T, root, None) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_nested_tuple(sequence, sensible_relabeling=False): - """Returns the rooted tree corresponding to the given nested tuple. - - The nested tuple representation of a tree is defined - recursively. The tree with one node and no edges is represented by - the empty tuple, ``()``. A tree with ``k`` subtrees is represented - by a tuple of length ``k`` in which each element is the nested tuple - representation of a subtree. - - Parameters - ---------- - sequence : tuple - A nested tuple representing a rooted tree. - - sensible_relabeling : bool - Whether to relabel the nodes of the tree so that nodes are - labeled in increasing order according to their breadth-first - search order from the root node. - - Returns - ------- - NetworkX graph - The tree corresponding to the given nested tuple, whose root - node is node 0. If ``sensible_labeling`` is ``True``, nodes will - be labeled in breadth-first search order starting from the root - node. - - Notes - ----- - This function is *not* the inverse of :func:`to_nested_tuple`; the - only guarantee is that the rooted trees are isomorphic. - - See also - -------- - to_nested_tuple - from_prufer_sequence - - Examples - -------- - Sensible relabeling ensures that the nodes are labeled from the root - starting at 0:: - - >>> balanced = (((), ()), ((), ())) - >>> T = nx.from_nested_tuple(balanced, sensible_relabeling=True) - >>> edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - >>> all((u, v) in T.edges() or (v, u) in T.edges() for (u, v) in edges) - True - - """ - - def _make_tree(sequence): - """Recursively creates a tree from the given sequence of nested - tuples. - - This function employs the :func:`~networkx.tree.join` function - to recursively join subtrees into a larger tree. - - """ - # The empty sequence represents the empty tree, which is the - # (unique) graph with a single node. We mark the single node - # with an attribute that indicates that it is the root of the - # graph. - if len(sequence) == 0: - return nx.empty_graph(1) - # For a nonempty sequence, get the subtrees for each child - # sequence and join all the subtrees at their roots. After - # joining the subtrees, the root is node 0. - return nx.tree.join_trees([(_make_tree(child), 0) for child in sequence]) - - # Make the tree and remove the `is_root` node attribute added by the - # helper function. - T = _make_tree(sequence) - if sensible_relabeling: - # Relabel the nodes according to their breadth-first search - # order, starting from the root node (that is, the node 0). - bfs_nodes = chain([0], (v for u, v in nx.bfs_edges(T, 0))) - labels = {v: i for i, v in enumerate(bfs_nodes)} - # We would like to use `copy=False`, but `relabel_nodes` doesn't - # allow a relabel mapping that can't be topologically sorted. - T = nx.relabel_nodes(T, labels) - return T - - -@not_implemented_for("directed") -@nx._dispatchable(graphs="T") -def to_prufer_sequence(T): - r"""Returns the Prüfer sequence of the given tree. - - A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and - *n* - 1, inclusive. The tree corresponding to a given Prüfer - sequence can be recovered by repeatedly joining a node in the - sequence with a node with the smallest potential degree according to - the sequence. - - Parameters - ---------- - T : NetworkX graph - An undirected graph object representing a tree. - - Returns - ------- - list - The Prüfer sequence of the given tree. - - Raises - ------ - NetworkXPointlessConcept - If the number of nodes in `T` is less than two. - - NotATree - If `T` is not a tree. - - KeyError - If the set of nodes in `T` is not {0, …, *n* - 1}. - - Notes - ----- - There is a bijection from labeled trees to Prüfer sequences. This - function is the inverse of the :func:`from_prufer_sequence` - function. - - Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead - of from 0 to *n* - 1. This function requires nodes to be labeled in - the latter form. You can use :func:`~networkx.relabel_nodes` to - relabel the nodes of your tree to the appropriate format. - - This implementation is from [1]_ and has a running time of - $O(n)$. - - See also - -------- - to_nested_tuple - from_prufer_sequence - - References - ---------- - .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu. - "An optimal algorithm for Prufer codes." - *Journal of Software Engineering and Applications* 2.02 (2009): 111. - - - Examples - -------- - There is a bijection between Prüfer sequences and labeled trees, so - this function is the inverse of the :func:`from_prufer_sequence` - function: - - >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - >>> tree = nx.Graph(edges) - >>> sequence = nx.to_prufer_sequence(tree) - >>> sequence - [3, 3, 3, 4] - >>> tree2 = nx.from_prufer_sequence(sequence) - >>> list(tree2.edges()) == edges - True - - """ - # Perform some sanity checks on the input. - n = len(T) - if n < 2: - msg = "Prüfer sequence undefined for trees with fewer than two nodes" - raise nx.NetworkXPointlessConcept(msg) - if not nx.is_tree(T): - raise nx.NotATree("provided graph is not a tree") - if set(T) != set(range(n)): - raise KeyError("tree must have node labels {0, ..., n - 1}") - - degree = dict(T.degree()) - - def parents(u): - return next(v for v in T[u] if degree[v] > 1) - - index = u = next(k for k in range(n) if degree[k] == 1) - result = [] - for i in range(n - 2): - v = parents(u) - result.append(v) - degree[v] -= 1 - if v < index and degree[v] == 1: - u = v - else: - index = u = next(k for k in range(index + 1, n) if degree[k] == 1) - return result - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_prufer_sequence(sequence): - r"""Returns the tree corresponding to the given Prüfer sequence. - - A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and - *n* - 1, inclusive. The tree corresponding to a given Prüfer - sequence can be recovered by repeatedly joining a node in the - sequence with a node with the smallest potential degree according to - the sequence. - - Parameters - ---------- - sequence : list - A Prüfer sequence, which is a list of *n* - 2 integers between - zero and *n* - 1, inclusive. - - Returns - ------- - NetworkX graph - The tree corresponding to the given Prüfer sequence. - - Raises - ------ - NetworkXError - If the Prüfer sequence is not valid. - - Notes - ----- - There is a bijection from labeled trees to Prüfer sequences. This - function is the inverse of the :func:`from_prufer_sequence` function. - - Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead - of from 0 to *n* - 1. This function requires nodes to be labeled in - the latter form. You can use :func:`networkx.relabel_nodes` to - relabel the nodes of your tree to the appropriate format. - - This implementation is from [1]_ and has a running time of - $O(n)$. - - References - ---------- - .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu. - "An optimal algorithm for Prufer codes." - *Journal of Software Engineering and Applications* 2.02 (2009): 111. - - - See also - -------- - from_nested_tuple - to_prufer_sequence - - Examples - -------- - There is a bijection between Prüfer sequences and labeled trees, so - this function is the inverse of the :func:`to_prufer_sequence` - function: - - >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - >>> tree = nx.Graph(edges) - >>> sequence = nx.to_prufer_sequence(tree) - >>> sequence - [3, 3, 3, 4] - >>> tree2 = nx.from_prufer_sequence(sequence) - >>> list(tree2.edges()) == edges - True - - """ - n = len(sequence) + 2 - # `degree` stores the remaining degree (plus one) for each node. The - # degree of a node in the decoded tree is one more than the number - # of times it appears in the code. - degree = Counter(chain(sequence, range(n))) - T = nx.empty_graph(n) - # `not_orphaned` is the set of nodes that have a parent in the - # tree. After the loop, there should be exactly two nodes that are - # not in this set. - not_orphaned = set() - index = u = next(k for k in range(n) if degree[k] == 1) - for v in sequence: - # check the validity of the prufer sequence - if v < 0 or v > n - 1: - raise nx.NetworkXError( - f"Invalid Prufer sequence: Values must be between 0 and {n-1}, got {v}" - ) - T.add_edge(u, v) - not_orphaned.add(u) - degree[v] -= 1 - if v < index and degree[v] == 1: - u = v - else: - index = u = next(k for k in range(index + 1, n) if degree[k] == 1) - # At this point, there must be exactly two orphaned nodes; join them. - orphans = set(T) - not_orphaned - u, v = orphans - T.add_edge(u, v) - return T diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/decomposition.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/decomposition.py deleted file mode 100644 index c8b8f24..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/decomposition.py +++ /dev/null @@ -1,88 +0,0 @@ -r"""Function for computing a junction tree of a graph.""" - -from itertools import combinations - -import networkx as nx -from networkx.algorithms import chordal_graph_cliques, complete_to_chordal_graph, moral -from networkx.utils import not_implemented_for - -__all__ = ["junction_tree"] - - -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def junction_tree(G): - r"""Returns a junction tree of a given graph. - - A junction tree (or clique tree) is constructed from a (un)directed graph G. - The tree is constructed based on a moralized and triangulated version of G. - The tree's nodes consist of maximal cliques and sepsets of the revised graph. - The sepset of two cliques is the intersection of the nodes of these cliques, - e.g. the sepset of (A,B,C) and (A,C,E,F) is (A,C). These nodes are often called - "variables" in this literature. The tree is bipartite with each sepset - connected to its two cliques. - - Junction Trees are not unique as the order of clique consideration determines - which sepsets are included. - - The junction tree algorithm consists of five steps [1]_: - - 1. Moralize the graph - 2. Triangulate the graph - 3. Find maximal cliques - 4. Build the tree from cliques, connecting cliques with shared - nodes, set edge-weight to number of shared variables - 5. Find maximum spanning tree - - - Parameters - ---------- - G : networkx.Graph - Directed or undirected graph. - - Returns - ------- - junction_tree : networkx.Graph - The corresponding junction tree of `G`. - - Raises - ------ - NetworkXNotImplemented - Raised if `G` is an instance of `MultiGraph` or `MultiDiGraph`. - - References - ---------- - .. [1] Junction tree algorithm: - https://en.wikipedia.org/wiki/Junction_tree_algorithm - - .. [2] Finn V. Jensen and Frank Jensen. 1994. Optimal - junction trees. In Proceedings of the Tenth international - conference on Uncertainty in artificial intelligence (UAI’94). - Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 360–366. - """ - - clique_graph = nx.Graph() - - if G.is_directed(): - G = moral.moral_graph(G) - chordal_graph, _ = complete_to_chordal_graph(G) - - cliques = [tuple(sorted(i)) for i in chordal_graph_cliques(chordal_graph)] - clique_graph.add_nodes_from(cliques, type="clique") - - for edge in combinations(cliques, 2): - set_edge_0 = set(edge[0]) - set_edge_1 = set(edge[1]) - if not set_edge_0.isdisjoint(set_edge_1): - sepset = tuple(sorted(set_edge_0.intersection(set_edge_1))) - clique_graph.add_edge(edge[0], edge[1], weight=len(sepset), sepset=sepset) - - junction_tree = nx.maximum_spanning_tree(clique_graph) - - for edge in list(junction_tree.edges(data=True)): - junction_tree.add_node(edge[2]["sepset"], type="sepset") - junction_tree.add_edge(edge[0], edge[2]["sepset"]) - junction_tree.add_edge(edge[1], edge[2]["sepset"]) - junction_tree.remove_edge(edge[0], edge[1]) - - return junction_tree diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/mst.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/mst.py deleted file mode 100644 index 554613b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/mst.py +++ /dev/null @@ -1,1284 +0,0 @@ -""" -Algorithms for calculating min/max spanning trees/forests. - -""" - -from dataclasses import dataclass, field -from enum import Enum -from heapq import heappop, heappush -from itertools import count -from math import isnan -from operator import itemgetter -from queue import PriorityQueue - -import networkx as nx -from networkx.utils import UnionFind, not_implemented_for, py_random_state - -__all__ = [ - "minimum_spanning_edges", - "maximum_spanning_edges", - "minimum_spanning_tree", - "maximum_spanning_tree", - "number_of_spanning_trees", - "random_spanning_tree", - "partition_spanning_tree", - "EdgePartition", - "SpanningTreeIterator", -] - - -class EdgePartition(Enum): - """ - An enum to store the state of an edge partition. The enum is written to the - edges of a graph before being pasted to `kruskal_mst_edges`. Options are: - - - EdgePartition.OPEN - - EdgePartition.INCLUDED - - EdgePartition.EXCLUDED - """ - - OPEN = 0 - INCLUDED = 1 - EXCLUDED = 2 - - -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight", preserve_edge_attrs="data") -def boruvka_mst_edges( - G, minimum=True, weight="weight", keys=False, data=True, ignore_nan=False -): - """Iterate over edges of a Borůvka's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The edges of `G` must have distinct weights, - otherwise the edges may not form a tree. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - This argument is ignored since this function is not - implemented for multigraphs; it exists only for consistency - with the other minimum spanning tree functions. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - """ - # Initialize a forest, assuming initially that it is the discrete - # partition of the nodes of the graph. - forest = UnionFind(G) - - def best_edge(component): - """Returns the optimum (minimum or maximum) edge on the edge - boundary of the given set of nodes. - - A return value of ``None`` indicates an empty boundary. - - """ - sign = 1 if minimum else -1 - minwt = float("inf") - boundary = None - for e in nx.edge_boundary(G, component, data=True): - wt = e[-1].get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = f"NaN found as an edge weight. Edge {e}" - raise ValueError(msg) - if wt < minwt: - minwt = wt - boundary = e - return boundary - - # Determine the optimum edge in the edge boundary of each component - # in the forest. - best_edges = (best_edge(component) for component in forest.to_sets()) - best_edges = [edge for edge in best_edges if edge is not None] - # If each entry was ``None``, that means the graph was disconnected, - # so we are done generating the forest. - while best_edges: - # Determine the optimum edge in the edge boundary of each - # component in the forest. - # - # This must be a sequence, not an iterator. In this list, the - # same edge may appear twice, in different orientations (but - # that's okay, since a union operation will be called on the - # endpoints the first time it is seen, but not the second time). - # - # Any ``None`` indicates that the edge boundary for that - # component was empty, so that part of the forest has been - # completed. - # - # TODO This can be parallelized, both in the outer loop over - # each component in the forest and in the computation of the - # minimum. (Same goes for the identical lines outside the loop.) - best_edges = (best_edge(component) for component in forest.to_sets()) - best_edges = [edge for edge in best_edges if edge is not None] - # Join trees in the forest using the best edges, and yield that - # edge, since it is part of the spanning tree. - # - # TODO This loop can be parallelized, to an extent (the union - # operation must be atomic). - for u, v, d in best_edges: - if forest[u] != forest[v]: - if data: - yield u, v, d - else: - yield u, v - forest.union(u, v) - - -@nx._dispatchable( - edge_attrs={"weight": None, "partition": None}, preserve_edge_attrs="data" -) -def kruskal_mst_edges( - G, minimum, weight="weight", keys=True, data=True, ignore_nan=False, partition=None -): - """ - Iterate over edge of a Kruskal's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The graph holding the tree of interest. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - If `G` is a multigraph, `keys` controls whether edge keys ar yielded. - Otherwise `keys` is ignored. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - partition : string (default: None) - The name of the edge attribute holding the partition data, if it exists. - Partition data is written to the edges using the `EdgePartition` enum. - If a partition exists, all included edges and none of the excluded edges - will appear in the final tree. Open edges may or may not be used. - - Yields - ------ - edge tuple - The edges as discovered by Kruskal's method. Each edge can - take the following forms: `(u, v)`, `(u, v, d)` or `(u, v, k, d)` - depending on the `key` and `data` parameters - """ - subtrees = UnionFind() - if G.is_multigraph(): - edges = G.edges(keys=True, data=True) - else: - edges = G.edges(data=True) - - """ - Sort the edges of the graph with respect to the partition data. - Edges are returned in the following order: - - * Included edges - * Open edges from smallest to largest weight - * Excluded edges - """ - included_edges = [] - open_edges = [] - for e in edges: - d = e[-1] - wt = d.get(weight, 1) - if isnan(wt): - if ignore_nan: - continue - raise ValueError(f"NaN found as an edge weight. Edge {e}") - - edge = (wt,) + e - if d.get(partition) == EdgePartition.INCLUDED: - included_edges.append(edge) - elif d.get(partition) == EdgePartition.EXCLUDED: - continue - else: - open_edges.append(edge) - - if minimum: - sorted_open_edges = sorted(open_edges, key=itemgetter(0)) - else: - sorted_open_edges = sorted(open_edges, key=itemgetter(0), reverse=True) - - # Condense the lists into one - included_edges.extend(sorted_open_edges) - sorted_edges = included_edges - del open_edges, sorted_open_edges, included_edges - - # Multigraphs need to handle edge keys in addition to edge data. - if G.is_multigraph(): - for wt, u, v, k, d in sorted_edges: - if subtrees[u] != subtrees[v]: - if keys: - if data: - yield u, v, k, d - else: - yield u, v, k - else: - if data: - yield u, v, d - else: - yield u, v - subtrees.union(u, v) - else: - for wt, u, v, d in sorted_edges: - if subtrees[u] != subtrees[v]: - if data: - yield u, v, d - else: - yield u, v - subtrees.union(u, v) - - -@nx._dispatchable(edge_attrs="weight", preserve_edge_attrs="data") -def prim_mst_edges(G, minimum, weight="weight", keys=True, data=True, ignore_nan=False): - """Iterate over edges of Prim's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The graph holding the tree of interest. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - If `G` is a multigraph, `keys` controls whether edge keys ar yielded. - Otherwise `keys` is ignored. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - """ - is_multigraph = G.is_multigraph() - push = heappush - pop = heappop - - nodes = set(G) - c = count() - - sign = 1 if minimum else -1 - - while nodes: - u = nodes.pop() - frontier = [] - visited = {u} - if is_multigraph: - for v, keydict in G.adj[u].items(): - for k, d in keydict.items(): - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = f"NaN found as an edge weight. Edge {(u, v, k, d)}" - raise ValueError(msg) - push(frontier, (wt, next(c), u, v, k, d)) - else: - for v, d in G.adj[u].items(): - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = f"NaN found as an edge weight. Edge {(u, v, d)}" - raise ValueError(msg) - push(frontier, (wt, next(c), u, v, d)) - while nodes and frontier: - if is_multigraph: - W, _, u, v, k, d = pop(frontier) - else: - W, _, u, v, d = pop(frontier) - if v in visited or v not in nodes: - continue - # Multigraphs need to handle edge keys in addition to edge data. - if is_multigraph and keys: - if data: - yield u, v, k, d - else: - yield u, v, k - else: - if data: - yield u, v, d - else: - yield u, v - # update frontier - visited.add(v) - nodes.discard(v) - if is_multigraph: - for w, keydict in G.adj[v].items(): - if w in visited: - continue - for k2, d2 in keydict.items(): - new_weight = d2.get(weight, 1) * sign - if isnan(new_weight): - if ignore_nan: - continue - msg = f"NaN found as an edge weight. Edge {(v, w, k2, d2)}" - raise ValueError(msg) - push(frontier, (new_weight, next(c), v, w, k2, d2)) - else: - for w, d2 in G.adj[v].items(): - if w in visited: - continue - new_weight = d2.get(weight, 1) * sign - if isnan(new_weight): - if ignore_nan: - continue - msg = f"NaN found as an edge weight. Edge {(v, w, d2)}" - raise ValueError(msg) - push(frontier, (new_weight, next(c), v, w, d2)) - - -ALGORITHMS = { - "boruvka": boruvka_mst_edges, - "borůvka": boruvka_mst_edges, - "kruskal": kruskal_mst_edges, - "prim": prim_mst_edges, -} - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight", preserve_edge_attrs="data") -def minimum_spanning_edges( - G, algorithm="kruskal", weight="weight", keys=True, data=True, ignore_nan=False -): - """Generate edges in a minimum spanning forest of an undirected - weighted graph. - - A minimum spanning tree is a subgraph of the graph (a tree) - with the minimum sum of edge weights. A spanning forest is a - union of the spanning trees for each connected component of the graph. - - Parameters - ---------- - G : undirected Graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - algorithm : string - The algorithm to use when finding a minimum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is 'kruskal'. - - weight : string - Edge data key to use for weight (default 'weight'). - - keys : bool - Whether to yield edge key in multigraphs in addition to the edge. - If `G` is not a multigraph, this is ignored. - - data : bool, optional - If True yield the edge data along with the edge. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - edges : iterator - An iterator over edges in a maximum spanning tree of `G`. - Edges connecting nodes `u` and `v` are represented as tuples: - `(u, v, k, d)` or `(u, v, k)` or `(u, v, d)` or `(u, v)` - - If `G` is a multigraph, `keys` indicates whether the edge key `k` will - be reported in the third position in the edge tuple. `data` indicates - whether the edge datadict `d` will appear at the end of the edge tuple. - - If `G` is not a multigraph, the tuples are `(u, v, d)` if `data` is True - or `(u, v)` if `data` is False. - - Examples - -------- - >>> from networkx.algorithms import tree - - Find minimum spanning edges by Kruskal's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.minimum_spanning_edges(G, algorithm="kruskal", data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [1, 2], [2, 3]] - - Find minimum spanning edges by Prim's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.minimum_spanning_edges(G, algorithm="prim", data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [1, 2], [2, 3]] - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - Modified code from David Eppstein, April 2006 - http://www.ics.uci.edu/~eppstein/PADS/ - - """ - try: - algo = ALGORITHMS[algorithm] - except KeyError as err: - msg = f"{algorithm} is not a valid choice for an algorithm." - raise ValueError(msg) from err - - return algo( - G, minimum=True, weight=weight, keys=keys, data=data, ignore_nan=ignore_nan - ) - - -@not_implemented_for("directed") -@nx._dispatchable(edge_attrs="weight", preserve_edge_attrs="data") -def maximum_spanning_edges( - G, algorithm="kruskal", weight="weight", keys=True, data=True, ignore_nan=False -): - """Generate edges in a maximum spanning forest of an undirected - weighted graph. - - A maximum spanning tree is a subgraph of the graph (a tree) - with the maximum possible sum of edge weights. A spanning forest is a - union of the spanning trees for each connected component of the graph. - - Parameters - ---------- - G : undirected Graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - algorithm : string - The algorithm to use when finding a maximum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is 'kruskal'. - - weight : string - Edge data key to use for weight (default 'weight'). - - keys : bool - Whether to yield edge key in multigraphs in addition to the edge. - If `G` is not a multigraph, this is ignored. - - data : bool, optional - If True yield the edge data along with the edge. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - edges : iterator - An iterator over edges in a maximum spanning tree of `G`. - Edges connecting nodes `u` and `v` are represented as tuples: - `(u, v, k, d)` or `(u, v, k)` or `(u, v, d)` or `(u, v)` - - If `G` is a multigraph, `keys` indicates whether the edge key `k` will - be reported in the third position in the edge tuple. `data` indicates - whether the edge datadict `d` will appear at the end of the edge tuple. - - If `G` is not a multigraph, the tuples are `(u, v, d)` if `data` is True - or `(u, v)` if `data` is False. - - Examples - -------- - >>> from networkx.algorithms import tree - - Find maximum spanning edges by Kruskal's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.maximum_spanning_edges(G, algorithm="kruskal", data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [0, 3], [1, 2]] - - Find maximum spanning edges by Prim's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) # assign weight 2 to edge 0-3 - >>> mst = tree.maximum_spanning_edges(G, algorithm="prim", data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [0, 3], [2, 3]] - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - Modified code from David Eppstein, April 2006 - http://www.ics.uci.edu/~eppstein/PADS/ - """ - try: - algo = ALGORITHMS[algorithm] - except KeyError as err: - msg = f"{algorithm} is not a valid choice for an algorithm." - raise ValueError(msg) from err - - return algo( - G, minimum=False, weight=weight, keys=keys, data=data, ignore_nan=ignore_nan - ) - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def minimum_spanning_tree(G, weight="weight", algorithm="kruskal", ignore_nan=False): - """Returns a minimum spanning tree or forest on an undirected graph `G`. - - Parameters - ---------- - G : undirected graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - weight : str - Data key to use for edge weights. - - algorithm : string - The algorithm to use when finding a minimum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is - 'kruskal'. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - G : NetworkX Graph - A minimum spanning tree or forest. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> T = nx.minimum_spanning_tree(G) - >>> sorted(T.edges(data=True)) - [(0, 1, {}), (1, 2, {}), (2, 3, {})] - - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - There may be more than one tree with the same minimum or maximum weight. - See :mod:`networkx.tree.recognition` for more detailed definitions. - - Isolated nodes with self-loops are in the tree as edgeless isolated nodes. - - """ - edges = minimum_spanning_edges( - G, algorithm, weight, keys=True, data=True, ignore_nan=ignore_nan - ) - T = G.__class__() # Same graph class as G - T.graph.update(G.graph) - T.add_nodes_from(G.nodes.items()) - T.add_edges_from(edges) - return T - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def partition_spanning_tree( - G, minimum=True, weight="weight", partition="partition", ignore_nan=False -): - """ - Find a spanning tree while respecting a partition of edges. - - Edges can be flagged as either `INCLUDED` which are required to be in the - returned tree, `EXCLUDED`, which cannot be in the returned tree and `OPEN`. - - This is used in the SpanningTreeIterator to create new partitions following - the algorithm of Sörensen and Janssens [1]_. - - Parameters - ---------- - G : undirected graph - An undirected graph. - - minimum : bool (default: True) - Determines whether the returned tree is the minimum spanning tree of - the partition of the maximum one. - - weight : str - Data key to use for edge weights. - - partition : str - The key for the edge attribute containing the partition - data on the graph. Edges can be included, excluded or open using the - `EdgePartition` enum. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - - Returns - ------- - G : NetworkX Graph - A minimum spanning tree using all of the included edges in the graph and - none of the excluded edges. - - References - ---------- - .. [1] G.K. Janssens, K. Sörensen, An algorithm to generate all spanning - trees in order of increasing cost, Pesquisa Operacional, 2005-08, - Vol. 25 (2), p. 219-229, - https://www.scielo.br/j/pope/a/XHswBwRwJyrfL88dmMwYNWp/?lang=en - """ - edges = kruskal_mst_edges( - G, - minimum, - weight, - keys=True, - data=True, - ignore_nan=ignore_nan, - partition=partition, - ) - T = G.__class__() # Same graph class as G - T.graph.update(G.graph) - T.add_nodes_from(G.nodes.items()) - T.add_edges_from(edges) - return T - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def maximum_spanning_tree(G, weight="weight", algorithm="kruskal", ignore_nan=False): - """Returns a maximum spanning tree or forest on an undirected graph `G`. - - Parameters - ---------- - G : undirected graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - weight : str - Data key to use for edge weights. - - algorithm : string - The algorithm to use when finding a maximum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is - 'kruskal'. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - - Returns - ------- - G : NetworkX Graph - A maximum spanning tree or forest. - - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> T = nx.maximum_spanning_tree(G) - >>> sorted(T.edges(data=True)) - [(0, 1, {}), (0, 3, {'weight': 2}), (1, 2, {})] - - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - There may be more than one tree with the same minimum or maximum weight. - See :mod:`networkx.tree.recognition` for more detailed definitions. - - Isolated nodes with self-loops are in the tree as edgeless isolated nodes. - - """ - edges = maximum_spanning_edges( - G, algorithm, weight, keys=True, data=True, ignore_nan=ignore_nan - ) - edges = list(edges) - T = G.__class__() # Same graph class as G - T.graph.update(G.graph) - T.add_nodes_from(G.nodes.items()) - T.add_edges_from(edges) - return T - - -@py_random_state(3) -@nx._dispatchable(preserve_edge_attrs=True, returns_graph=True) -def random_spanning_tree(G, weight=None, *, multiplicative=True, seed=None): - """ - Sample a random spanning tree using the edges weights of `G`. - - This function supports two different methods for determining the - probability of the graph. If ``multiplicative=True``, the probability - is based on the product of edge weights, and if ``multiplicative=False`` - it is based on the sum of the edge weight. However, since it is - easier to determine the total weight of all spanning trees for the - multiplicative version, that is significantly faster and should be used if - possible. Additionally, setting `weight` to `None` will cause a spanning tree - to be selected with uniform probability. - - The function uses algorithm A8 in [1]_ . - - Parameters - ---------- - G : nx.Graph - An undirected version of the original graph. - - weight : string - The edge key for the edge attribute holding edge weight. - - multiplicative : bool, default=True - If `True`, the probability of each tree is the product of its edge weight - over the sum of the product of all the spanning trees in the graph. If - `False`, the probability is the sum of its edge weight over the sum of - the sum of weights for all spanning trees in the graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - nx.Graph - A spanning tree using the distribution defined by the weight of the tree. - - References - ---------- - .. [1] V. Kulkarni, Generating random combinatorial objects, Journal of - Algorithms, 11 (1990), pp. 185–207 - """ - - def find_node(merged_nodes, node): - """ - We can think of clusters of contracted nodes as having one - representative in the graph. Each node which is not in merged_nodes - is still its own representative. Since a representative can be later - contracted, we need to recursively search though the dict to find - the final representative, but once we know it we can use path - compression to speed up the access of the representative for next time. - - This cannot be replaced by the standard NetworkX union_find since that - data structure will merge nodes with less representing nodes into the - one with more representing nodes but this function requires we merge - them using the order that contract_edges contracts using. - - Parameters - ---------- - merged_nodes : dict - The dict storing the mapping from node to representative - node - The node whose representative we seek - - Returns - ------- - The representative of the `node` - """ - if node not in merged_nodes: - return node - else: - rep = find_node(merged_nodes, merged_nodes[node]) - merged_nodes[node] = rep - return rep - - def prepare_graph(): - """ - For the graph `G`, remove all edges not in the set `V` and then - contract all edges in the set `U`. - - Returns - ------- - A copy of `G` which has had all edges not in `V` removed and all edges - in `U` contracted. - """ - - # The result is a MultiGraph version of G so that parallel edges are - # allowed during edge contraction - result = nx.MultiGraph(incoming_graph_data=G) - - # Remove all edges not in V - edges_to_remove = set(result.edges()).difference(V) - result.remove_edges_from(edges_to_remove) - - # Contract all edges in U - # - # Imagine that you have two edges to contract and they share an - # endpoint like this: - # [0] ----- [1] ----- [2] - # If we contract (0, 1) first, the contraction function will always - # delete the second node it is passed so the resulting graph would be - # [0] ----- [2] - # and edge (1, 2) no longer exists but (0, 2) would need to be contracted - # in its place now. That is why I use the below dict as a merge-find - # data structure with path compression to track how the nodes are merged. - merged_nodes = {} - - for u, v in U: - u_rep = find_node(merged_nodes, u) - v_rep = find_node(merged_nodes, v) - # We cannot contract a node with itself - if u_rep == v_rep: - continue - nx.contracted_nodes(result, u_rep, v_rep, self_loops=False, copy=False) - merged_nodes[v_rep] = u_rep - - return merged_nodes, result - - def spanning_tree_total_weight(G, weight): - """ - Find the sum of weights of the spanning trees of `G` using the - appropriate `method`. - - This is easy if the chosen method is 'multiplicative', since we can - use Kirchhoff's Tree Matrix Theorem directly. However, with the - 'additive' method, this process is slightly more complex and less - computationally efficient as we have to find the number of spanning - trees which contain each possible edge in the graph. - - Parameters - ---------- - G : NetworkX Graph - The graph to find the total weight of all spanning trees on. - - weight : string - The key for the weight edge attribute of the graph. - - Returns - ------- - float - The sum of either the multiplicative or additive weight for all - spanning trees in the graph. - """ - if multiplicative: - return nx.total_spanning_tree_weight(G, weight) - else: - # There are two cases for the total spanning tree additive weight. - # 1. There is one edge in the graph. Then the only spanning tree is - # that edge itself, which will have a total weight of that edge - # itself. - if G.number_of_edges() == 1: - return G.edges(data=weight).__iter__().__next__()[2] - # 2. There are no edges or two or more edges in the graph. Then, we find the - # total weight of the spanning trees using the formula in the - # reference paper: take the weight of each edge and multiply it by - # the number of spanning trees which include that edge. This - # can be accomplished by contracting the edge and finding the - # multiplicative total spanning tree weight if the weight of each edge - # is assumed to be 1, which is conveniently built into networkx already, - # by calling total_spanning_tree_weight with weight=None. - # Note that with no edges the returned value is just zero. - else: - total = 0 - for u, v, w in G.edges(data=weight): - total += w * nx.total_spanning_tree_weight( - nx.contracted_edge(G, edge=(u, v), self_loops=False), None - ) - return total - - if G.number_of_nodes() < 2: - # no edges in the spanning tree - return nx.empty_graph(G.nodes) - - U = set() - st_cached_value = 0 - V = set(G.edges()) - shuffled_edges = list(G.edges()) - seed.shuffle(shuffled_edges) - - for u, v in shuffled_edges: - e_weight = G[u][v][weight] if weight is not None else 1 - node_map, prepared_G = prepare_graph() - G_total_tree_weight = spanning_tree_total_weight(prepared_G, weight) - # Add the edge to U so that we can compute the total tree weight - # assuming we include that edge - # Now, if (u, v) cannot exist in G because it is fully contracted out - # of existence, then it by definition cannot influence G_e's Kirchhoff - # value. But, we also cannot pick it. - rep_edge = (find_node(node_map, u), find_node(node_map, v)) - # Check to see if the 'representative edge' for the current edge is - # in prepared_G. If so, then we can pick it. - if rep_edge in prepared_G.edges: - prepared_G_e = nx.contracted_edge( - prepared_G, edge=rep_edge, self_loops=False - ) - G_e_total_tree_weight = spanning_tree_total_weight(prepared_G_e, weight) - if multiplicative: - threshold = e_weight * G_e_total_tree_weight / G_total_tree_weight - else: - numerator = ( - st_cached_value + e_weight - ) * nx.total_spanning_tree_weight(prepared_G_e) + G_e_total_tree_weight - denominator = ( - st_cached_value * nx.total_spanning_tree_weight(prepared_G) - + G_total_tree_weight - ) - threshold = numerator / denominator - else: - threshold = 0.0 - z = seed.uniform(0.0, 1.0) - if z > threshold: - # Remove the edge from V since we did not pick it. - V.remove((u, v)) - else: - # Add the edge to U since we picked it. - st_cached_value += e_weight - U.add((u, v)) - # If we decide to keep an edge, it may complete the spanning tree. - if len(U) == G.number_of_nodes() - 1: - spanning_tree = nx.Graph() - spanning_tree.add_edges_from(U) - return spanning_tree - raise Exception(f"Something went wrong! Only {len(U)} edges in the spanning tree!") - - -class SpanningTreeIterator: - """ - Iterate over all spanning trees of a graph in either increasing or - decreasing cost. - - Notes - ----- - This iterator uses the partition scheme from [1]_ (included edges, - excluded edges and open edges) as well as a modified Kruskal's Algorithm - to generate minimum spanning trees which respect the partition of edges. - For spanning trees with the same weight, ties are broken arbitrarily. - - References - ---------- - .. [1] G.K. Janssens, K. Sörensen, An algorithm to generate all spanning - trees in order of increasing cost, Pesquisa Operacional, 2005-08, - Vol. 25 (2), p. 219-229, - https://www.scielo.br/j/pope/a/XHswBwRwJyrfL88dmMwYNWp/?lang=en - """ - - @dataclass(order=True) - class Partition: - """ - This dataclass represents a partition and stores a dict with the edge - data and the weight of the minimum spanning tree of the partition dict. - """ - - mst_weight: float - partition_dict: dict = field(compare=False) - - def __copy__(self): - return SpanningTreeIterator.Partition( - self.mst_weight, self.partition_dict.copy() - ) - - def __init__(self, G, weight="weight", minimum=True, ignore_nan=False): - """ - Initialize the iterator - - Parameters - ---------- - G : nx.Graph - The directed graph which we need to iterate trees over - - weight : String, default = "weight" - The edge attribute used to store the weight of the edge - - minimum : bool, default = True - Return the trees in increasing order while true and decreasing order - while false. - - ignore_nan : bool, default = False - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - """ - self.G = G.copy() - self.G.__networkx_cache__ = None # Disable caching - self.weight = weight - self.minimum = minimum - self.ignore_nan = ignore_nan - # Randomly create a key for an edge attribute to hold the partition data - self.partition_key = ( - "SpanningTreeIterators super secret partition attribute name" - ) - - def __iter__(self): - """ - Returns - ------- - SpanningTreeIterator - The iterator object for this graph - """ - self.partition_queue = PriorityQueue() - self._clear_partition(self.G) - mst_weight = partition_spanning_tree( - self.G, self.minimum, self.weight, self.partition_key, self.ignore_nan - ).size(weight=self.weight) - - self.partition_queue.put( - self.Partition(mst_weight if self.minimum else -mst_weight, {}) - ) - - return self - - def __next__(self): - """ - Returns - ------- - (multi)Graph - The spanning tree of next greatest weight, which ties broken - arbitrarily. - """ - if self.partition_queue.empty(): - del self.G, self.partition_queue - raise StopIteration - - partition = self.partition_queue.get() - self._write_partition(partition) - next_tree = partition_spanning_tree( - self.G, self.minimum, self.weight, self.partition_key, self.ignore_nan - ) - self._partition(partition, next_tree) - - self._clear_partition(next_tree) - return next_tree - - def _partition(self, partition, partition_tree): - """ - Create new partitions based of the minimum spanning tree of the - current minimum partition. - - Parameters - ---------- - partition : Partition - The Partition instance used to generate the current minimum spanning - tree. - partition_tree : nx.Graph - The minimum spanning tree of the input partition. - """ - # create two new partitions with the data from the input partition dict - p1 = self.Partition(0, partition.partition_dict.copy()) - p2 = self.Partition(0, partition.partition_dict.copy()) - for e in partition_tree.edges: - # determine if the edge was open or included - if e not in partition.partition_dict: - # This is an open edge - p1.partition_dict[e] = EdgePartition.EXCLUDED - p2.partition_dict[e] = EdgePartition.INCLUDED - - self._write_partition(p1) - p1_mst = partition_spanning_tree( - self.G, - self.minimum, - self.weight, - self.partition_key, - self.ignore_nan, - ) - p1_mst_weight = p1_mst.size(weight=self.weight) - if nx.is_connected(p1_mst): - p1.mst_weight = p1_mst_weight if self.minimum else -p1_mst_weight - self.partition_queue.put(p1.__copy__()) - p1.partition_dict = p2.partition_dict.copy() - - def _write_partition(self, partition): - """ - Writes the desired partition into the graph to calculate the minimum - spanning tree. - - Parameters - ---------- - partition : Partition - A Partition dataclass describing a partition on the edges of the - graph. - """ - - partition_dict = partition.partition_dict - partition_key = self.partition_key - G = self.G - - edges = ( - G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True) - ) - for *e, d in edges: - d[partition_key] = partition_dict.get(tuple(e), EdgePartition.OPEN) - - def _clear_partition(self, G): - """ - Removes partition data from the graph - """ - partition_key = self.partition_key - edges = ( - G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True) - ) - for *e, d in edges: - if partition_key in d: - del d[partition_key] - - -@nx._dispatchable(edge_attrs="weight") -def number_of_spanning_trees(G, *, root=None, weight=None): - """Returns the number of spanning trees in `G`. - - A spanning tree for an undirected graph is a tree that connects - all nodes in the graph. For a directed graph, the analog of a - spanning tree is called a (spanning) arborescence. The arborescence - includes a unique directed path from the `root` node to each other node. - The graph must be weakly connected, and the root must be a node - that includes all nodes as successors [3]_. Note that to avoid - discussing sink-roots and reverse-arborescences, we have reversed - the edge orientation from [3]_ and use the in-degree laplacian. - - This function (when `weight` is `None`) returns the number of - spanning trees for an undirected graph and the number of - arborescences from a single root node for a directed graph. - When `weight` is the name of an edge attribute which holds the - weight value of each edge, the function returns the sum over - all trees of the multiplicative weight of each tree. That is, - the weight of the tree is the product of its edge weights. - - Kirchoff's Tree Matrix Theorem states that any cofactor of the - Laplacian matrix of a graph is the number of spanning trees in the - graph. (Here we use cofactors for a diagonal entry so that the - cofactor becomes the determinant of the matrix with one row - and its matching column removed.) For a weighted Laplacian matrix, - the cofactor is the sum across all spanning trees of the - multiplicative weight of each tree. That is, the weight of each - tree is the product of its edge weights. The theorem is also - known as Kirchhoff's theorem [1]_ and the Matrix-Tree theorem [2]_. - - For directed graphs, a similar theorem (Tutte's Theorem) holds with - the cofactor chosen to be the one with row and column removed that - correspond to the root. The cofactor is the number of arborescences - with the specified node as root. And the weighted version gives the - sum of the arborescence weights with root `root`. The arborescence - weight is the product of its edge weights. - - Parameters - ---------- - G : NetworkX graph - - root : node - A node in the directed graph `G` that has all nodes as descendants. - (This is ignored for undirected graphs.) - - weight : string or None, optional (default=None) - The name of the edge attribute holding the edge weight. - If `None`, then each edge is assumed to have a weight of 1. - - Returns - ------- - Number - Undirected graphs: - The number of spanning trees of the graph `G`. - Or the sum of all spanning tree weights of the graph `G` - where the weight of a tree is the product of its edge weights. - Directed graphs: - The number of arborescences of `G` rooted at node `root`. - Or the sum of all arborescence weights of the graph `G` with - specified root where the weight of an arborescence is the product - of its edge weights. - - Raises - ------ - NetworkXPointlessConcept - If `G` does not contain any nodes. - - NetworkXError - If the graph `G` is directed and the root node - is not specified or is not in G. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> round(nx.number_of_spanning_trees(G)) - 125 - - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=2) - >>> G.add_edge(1, 3, weight=1) - >>> G.add_edge(2, 3, weight=1) - >>> round(nx.number_of_spanning_trees(G, weight="weight")) - 5 - - Notes - ----- - Self-loops are excluded. Multi-edges are contracted in one edge - equal to the sum of the weights. - - References - ---------- - .. [1] Wikipedia - "Kirchhoff's theorem." - https://en.wikipedia.org/wiki/Kirchhoff%27s_theorem - .. [2] Kirchhoff, G. R. - Über die Auflösung der Gleichungen, auf welche man - bei der Untersuchung der linearen Vertheilung - Galvanischer Ströme geführt wird - Annalen der Physik und Chemie, vol. 72, pp. 497-508, 1847. - .. [3] Margoliash, J. - "Matrix-Tree Theorem for Directed Graphs" - https://www.math.uchicago.edu/~may/VIGRE/VIGRE2010/REUPapers/Margoliash.pdf - """ - import numpy as np - - if len(G) == 0: - raise nx.NetworkXPointlessConcept("Graph G must contain at least one node.") - - # undirected G - if not nx.is_directed(G): - if not nx.is_connected(G): - return 0 - G_laplacian = nx.laplacian_matrix(G, weight=weight).toarray() - return float(np.linalg.det(G_laplacian[1:, 1:])) - - # directed G - if root is None: - raise nx.NetworkXError("Input `root` must be provided when G is directed") - if root not in G: - raise nx.NetworkXError("The node root is not in the graph G.") - if not nx.is_weakly_connected(G): - return 0 - - # Compute directed Laplacian matrix - nodelist = [root] + [n for n in G if n != root] - A = nx.adjacency_matrix(G, nodelist=nodelist, weight=weight) - D = np.diag(A.sum(axis=0)) - G_laplacian = D - A - - # Compute number of spanning trees - return float(np.linalg.det(G_laplacian[1:, 1:])) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/operations.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/operations.py deleted file mode 100644 index 6c3e839..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/operations.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Operations on trees.""" - -from functools import partial -from itertools import accumulate, chain - -import networkx as nx - -__all__ = ["join_trees"] - - -# Argument types don't match dispatching, but allow manual selection of backend -@nx._dispatchable(graphs=None, returns_graph=True) -def join_trees(rooted_trees, *, label_attribute=None, first_label=0): - """Returns a new rooted tree made by joining `rooted_trees` - - Constructs a new tree by joining each tree in `rooted_trees`. - A new root node is added and connected to each of the roots - of the input trees. While copying the nodes from the trees, - relabeling to integers occurs. If the `label_attribute` is provided, - the old node labels will be stored in the new tree under this attribute. - - Parameters - ---------- - rooted_trees : list - A list of pairs in which each left element is a NetworkX graph - object representing a tree and each right element is the root - node of that tree. The nodes of these trees will be relabeled to - integers. - - label_attribute : str - If provided, the old node labels will be stored in the new tree - under this node attribute. If not provided, the original labels - of the nodes in the input trees are not stored. - - first_label : int, optional (default=0) - Specifies the label for the new root node. If provided, the root node of the joined tree - will have this label. If not provided, the root node will default to a label of 0. - - Returns - ------- - NetworkX graph - The rooted tree resulting from joining the provided `rooted_trees`. The new tree has a root node - labeled as specified by `first_label` (defaulting to 0 if not provided). Subtrees from the input - `rooted_trees` are attached to this new root node. Each non-root node, if the `label_attribute` - is provided, has an attribute that indicates the original label of the node in the input tree. - - Notes - ----- - Trees are stored in NetworkX as NetworkX Graphs. There is no specific - enforcement of the fact that these are trees. Testing for each tree - can be done using :func:`networkx.is_tree`. - - Graph, edge, and node attributes are propagated from the given - rooted trees to the created tree. If there are any overlapping graph - attributes, those from later trees will overwrite those from earlier - trees in the tuple of positional arguments. - - Examples - -------- - Join two full balanced binary trees of height *h* to get a full - balanced binary tree of depth *h* + 1:: - - >>> h = 4 - >>> left = nx.balanced_tree(2, h) - >>> right = nx.balanced_tree(2, h) - >>> joined_tree = nx.join_trees([(left, 0), (right, 0)]) - >>> nx.is_isomorphic(joined_tree, nx.balanced_tree(2, h + 1)) - True - - """ - if not rooted_trees: - return nx.empty_graph(1) - - # Unzip the zipped list of (tree, root) pairs. - trees, roots = zip(*rooted_trees) - - # The join of the trees has the same type as the type of the first tree. - R = type(trees[0])() - - lengths = (len(tree) for tree in trees[:-1]) - first_labels = list(accumulate(lengths, initial=first_label + 1)) - - new_roots = [] - for tree, root, first_node in zip(trees, roots, first_labels): - new_root = first_node + list(tree.nodes()).index(root) - new_roots.append(new_root) - - # Relabel the nodes so that their union is the integers starting at first_label. - relabel = partial( - nx.convert_node_labels_to_integers, label_attribute=label_attribute - ) - new_trees = [ - relabel(tree, first_label=first_label) - for tree, first_label in zip(trees, first_labels) - ] - - # Add all sets of nodes and edges, attributes - for tree in new_trees: - R.update(tree) - - # Finally, join the subtrees at the root. We know first_label is unused by the way we relabeled the subtrees. - R.add_node(first_label) - R.add_edges_from((first_label, root) for root in new_roots) - - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/recognition.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/recognition.py deleted file mode 100644 index a9eae98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/recognition.py +++ /dev/null @@ -1,273 +0,0 @@ -""" -Recognition Tests -================= - -A *forest* is an acyclic, undirected graph, and a *tree* is a connected forest. -Depending on the subfield, there are various conventions for generalizing these -definitions to directed graphs. - -In one convention, directed variants of forest and tree are defined in an -identical manner, except that the direction of the edges is ignored. In effect, -each directed edge is treated as a single undirected edge. Then, additional -restrictions are imposed to define *branchings* and *arborescences*. - -In another convention, directed variants of forest and tree correspond to -the previous convention's branchings and arborescences, respectively. Then two -new terms, *polyforest* and *polytree*, are defined to correspond to the other -convention's forest and tree. - -Summarizing:: - - +-----------------------------+ - | Convention A | Convention B | - +=============================+ - | forest | polyforest | - | tree | polytree | - | branching | forest | - | arborescence | tree | - +-----------------------------+ - -Each convention has its reasons. The first convention emphasizes definitional -similarity in that directed forests and trees are only concerned with -acyclicity and do not have an in-degree constraint, just as their undirected -counterparts do not. The second convention emphasizes functional similarity -in the sense that the directed analog of a spanning tree is a spanning -arborescence. That is, take any spanning tree and choose one node as the root. -Then every edge is assigned a direction such there is a directed path from the -root to every other node. The result is a spanning arborescence. - -NetworkX follows convention "A". Explicitly, these are: - -undirected forest - An undirected graph with no undirected cycles. - -undirected tree - A connected, undirected forest. - -directed forest - A directed graph with no undirected cycles. Equivalently, the underlying - graph structure (which ignores edge orientations) is an undirected forest. - In convention B, this is known as a polyforest. - -directed tree - A weakly connected, directed forest. Equivalently, the underlying graph - structure (which ignores edge orientations) is an undirected tree. In - convention B, this is known as a polytree. - -branching - A directed forest with each node having, at most, one parent. So the maximum - in-degree is equal to 1. In convention B, this is known as a forest. - -arborescence - A directed tree with each node having, at most, one parent. So the maximum - in-degree is equal to 1. In convention B, this is known as a tree. - -For trees and arborescences, the adjective "spanning" may be added to designate -that the graph, when considered as a forest/branching, consists of a single -tree/arborescence that includes all nodes in the graph. It is true, by -definition, that every tree/arborescence is spanning with respect to the nodes -that define the tree/arborescence and so, it might seem redundant to introduce -the notion of "spanning". However, the nodes may represent a subset of -nodes from a larger graph, and it is in this context that the term "spanning" -becomes a useful notion. - -""" - -import networkx as nx - -__all__ = ["is_arborescence", "is_branching", "is_forest", "is_tree"] - - -@nx.utils.not_implemented_for("undirected") -@nx._dispatchable -def is_arborescence(G): - """ - Returns True if `G` is an arborescence. - - An arborescence is a directed tree with maximum in-degree equal to 1. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is an arborescence. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (0, 2), (2, 3), (3, 4)]) - >>> nx.is_arborescence(G) - True - >>> G.remove_edge(0, 1) - >>> G.add_edge(1, 2) # maximum in-degree is 2 - >>> nx.is_arborescence(G) - False - - Notes - ----- - In another convention, an arborescence is known as a *tree*. - - See Also - -------- - is_tree - - """ - return is_tree(G) and max(d for n, d in G.in_degree()) <= 1 - - -@nx.utils.not_implemented_for("undirected") -@nx._dispatchable -def is_branching(G): - """ - Returns True if `G` is a branching. - - A branching is a directed forest with maximum in-degree equal to 1. - - Parameters - ---------- - G : directed graph - The directed graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a branching. - - Examples - -------- - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 4)]) - >>> nx.is_branching(G) - True - >>> G.remove_edge(2, 3) - >>> G.add_edge(3, 1) # maximum in-degree is 2 - >>> nx.is_branching(G) - False - - Notes - ----- - In another convention, a branching is also known as a *forest*. - - See Also - -------- - is_forest - - """ - return is_forest(G) and max(d for n, d in G.in_degree()) <= 1 - - -@nx._dispatchable -def is_forest(G): - """ - Returns True if `G` is a forest. - - A forest is a graph with no undirected cycles. - - For directed graphs, `G` is a forest if the underlying graph is a forest. - The underlying graph is obtained by treating each directed edge as a single - undirected edge in a multigraph. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a forest. - - Raises - ------ - NetworkXPointlessConcept - If `G` is empty. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(1, 2), (1, 3), (2, 4), (2, 5)]) - >>> nx.is_forest(G) - True - >>> G.add_edge(4, 1) - >>> nx.is_forest(G) - False - - Notes - ----- - In another convention, a directed forest is known as a *polyforest* and - then *forest* corresponds to a *branching*. - - See Also - -------- - is_branching - - """ - if len(G) == 0: - raise nx.exception.NetworkXPointlessConcept("G has no nodes.") - - if G.is_directed(): - components = (G.subgraph(c) for c in nx.weakly_connected_components(G)) - else: - components = (G.subgraph(c) for c in nx.connected_components(G)) - - return all(len(c) - 1 == c.number_of_edges() for c in components) - - -@nx._dispatchable -def is_tree(G): - """ - Returns True if `G` is a tree. - - A tree is a connected graph with no undirected cycles. - - For directed graphs, `G` is a tree if the underlying graph is a tree. The - underlying graph is obtained by treating each directed edge as a single - undirected edge in a multigraph. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a tree. - - Raises - ------ - NetworkXPointlessConcept - If `G` is empty. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(1, 2), (1, 3), (2, 4), (2, 5)]) - >>> nx.is_tree(G) # n-1 edges - True - >>> G.add_edge(3, 4) - >>> nx.is_tree(G) # n edges - False - - Notes - ----- - In another convention, a directed tree is known as a *polytree* and then - *tree* corresponds to an *arborescence*. - - See Also - -------- - is_arborescence - - """ - if len(G) == 0: - raise nx.exception.NetworkXPointlessConcept("G has no nodes.") - - if G.is_directed(): - is_connected = nx.is_weakly_connected - else: - is_connected = nx.is_connected - - # A connected graph with no cycles has n-1 edges. - return len(G) - 1 == G.number_of_edges() and is_connected(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_branchings.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_branchings.py deleted file mode 100644 index e19ddee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_branchings.py +++ /dev/null @@ -1,624 +0,0 @@ -import math -from operator import itemgetter - -import pytest - -np = pytest.importorskip("numpy") - -import networkx as nx -from networkx.algorithms.tree import branchings, recognition - -# -# Explicitly discussed examples from Edmonds paper. -# - -# Used in Figures A-F. -# -# fmt: off -G_array = np.array([ - # 0 1 2 3 4 5 6 7 8 - [0, 0, 12, 0, 12, 0, 0, 0, 0], # 0 - [4, 0, 0, 0, 0, 13, 0, 0, 0], # 1 - [0, 17, 0, 21, 0, 12, 0, 0, 0], # 2 - [5, 0, 0, 0, 17, 0, 18, 0, 0], # 3 - [0, 0, 0, 0, 0, 0, 0, 12, 0], # 4 - [0, 0, 0, 0, 0, 0, 14, 0, 12], # 5 - [0, 0, 21, 0, 0, 0, 0, 0, 15], # 6 - [0, 0, 0, 19, 0, 0, 15, 0, 0], # 7 - [0, 0, 0, 0, 0, 0, 0, 18, 0], # 8 -], dtype=int) - -# Two copies of the graph from the original paper as disconnected components -G_big_array = np.zeros(np.array(G_array.shape) * 2, dtype=int) -G_big_array[:G_array.shape[0], :G_array.shape[1]] = G_array -G_big_array[G_array.shape[0]:, G_array.shape[1]:] = G_array - -# fmt: on - - -def G1(): - G = nx.from_numpy_array(G_array, create_using=nx.MultiDiGraph) - return G - - -def G2(): - # Now we shift all the weights by -10. - # Should not affect optimal arborescence, but does affect optimal branching. - Garr = G_array.copy() - Garr[np.nonzero(Garr)] -= 10 - G = nx.from_numpy_array(Garr, create_using=nx.MultiDiGraph) - return G - - -# An optimal branching for G1 that is also a spanning arborescence. So it is -# also an optimal spanning arborescence. -# -optimal_arborescence_1 = [ - (0, 2, 12), - (2, 1, 17), - (2, 3, 21), - (1, 5, 13), - (3, 4, 17), - (3, 6, 18), - (6, 8, 15), - (8, 7, 18), -] - -# For G2, the optimal branching of G1 (with shifted weights) is no longer -# an optimal branching, but it is still an optimal spanning arborescence -# (just with shifted weights). An optimal branching for G2 is similar to what -# appears in figure G (this is greedy_subopt_branching_1a below), but with the -# edge (3, 0, 5), which is now (3, 0, -5), removed. Thus, the optimal branching -# is not a spanning arborescence. The code finds optimal_branching_2a. -# An alternative and equivalent branching is optimal_branching_2b. We would -# need to modify the code to iterate through all equivalent optimal branchings. -# -# These are maximal branchings or arborescences. -optimal_branching_2a = [ - (5, 6, 4), - (6, 2, 11), - (6, 8, 5), - (8, 7, 8), - (2, 1, 7), - (2, 3, 11), - (3, 4, 7), -] -optimal_branching_2b = [ - (8, 7, 8), - (7, 3, 9), - (3, 4, 7), - (3, 6, 8), - (6, 2, 11), - (2, 1, 7), - (1, 5, 3), -] -optimal_arborescence_2 = [ - (0, 2, 2), - (2, 1, 7), - (2, 3, 11), - (1, 5, 3), - (3, 4, 7), - (3, 6, 8), - (6, 8, 5), - (8, 7, 8), -] - -# Two suboptimal maximal branchings on G1 obtained from a greedy algorithm. -# 1a matches what is shown in Figure G in Edmonds's paper. -greedy_subopt_branching_1a = [ - (5, 6, 14), - (6, 2, 21), - (6, 8, 15), - (8, 7, 18), - (2, 1, 17), - (2, 3, 21), - (3, 0, 5), - (3, 4, 17), -] -greedy_subopt_branching_1b = [ - (8, 7, 18), - (7, 6, 15), - (6, 2, 21), - (2, 1, 17), - (2, 3, 21), - (1, 5, 13), - (3, 0, 5), - (3, 4, 17), -] - - -def build_branching(edges, double=False): - G = nx.DiGraph() - for u, v, weight in edges: - G.add_edge(u, v, weight=weight) - if double: - G.add_edge(u + 9, v + 9, weight=weight) - return G - - -def sorted_edges(G, attr="weight", default=1): - edges = [(u, v, data.get(attr, default)) for (u, v, data) in G.edges(data=True)] - edges = sorted(edges, key=lambda x: (x[2], x[1], x[0])) - return edges - - -def assert_equal_branchings(G1, G2, attr="weight", default=1): - edges1 = list(G1.edges(data=True)) - edges2 = list(G2.edges(data=True)) - assert len(edges1) == len(edges2) - - # Grab the weights only. - e1 = sorted_edges(G1, attr, default) - e2 = sorted_edges(G2, attr, default) - - for a, b in zip(e1, e2): - assert a[:2] == b[:2] - np.testing.assert_almost_equal(a[2], b[2]) - - -################ - - -def test_optimal_branching1(): - G = build_branching(optimal_arborescence_1) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 131 - - -def test_optimal_branching2a(): - G = build_branching(optimal_branching_2a) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 53 - - -def test_optimal_branching2b(): - G = build_branching(optimal_branching_2b) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 53 - - -def test_optimal_arborescence2(): - G = build_branching(optimal_arborescence_2) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 51 - - -def test_greedy_suboptimal_branching1a(): - G = build_branching(greedy_subopt_branching_1a) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 128 - - -def test_greedy_suboptimal_branching1b(): - G = build_branching(greedy_subopt_branching_1b) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 127 - - -def test_greedy_max1(): - # Standard test. - # - G = G1() - B = branchings.greedy_branching(G) - # There are only two possible greedy branchings. The sorting is such - # that it should equal the second suboptimal branching: 1b. - B_ = build_branching(greedy_subopt_branching_1b) - assert_equal_branchings(B, B_) - - -def test_greedy_branching_kwarg_kind(): - G = G1() - with pytest.raises(nx.NetworkXException, match="Unknown value for `kind`."): - B = branchings.greedy_branching(G, kind="lol") - - -def test_greedy_branching_for_unsortable_nodes(): - G = nx.DiGraph() - G.add_weighted_edges_from([((2, 3), 5, 1), (3, "a", 1), (2, 4, 5)]) - edges = [(u, v, data.get("weight", 1)) for (u, v, data) in G.edges(data=True)] - with pytest.raises(TypeError): - edges.sort(key=itemgetter(2, 0, 1), reverse=True) - B = branchings.greedy_branching(G, kind="max").edges(data=True) - assert list(B) == [ - ((2, 3), 5, {"weight": 1}), - (3, "a", {"weight": 1}), - (2, 4, {"weight": 5}), - ] - - -def test_greedy_max2(): - # Different default weight. - # - G = G1() - del G[1][0][0]["weight"] - B = branchings.greedy_branching(G, default=6) - # Chosen so that edge (3,0,5) is not selected and (1,0,6) is instead. - - edges = [ - (1, 0, 6), - (1, 5, 13), - (7, 6, 15), - (2, 1, 17), - (3, 4, 17), - (8, 7, 18), - (2, 3, 21), - (6, 2, 21), - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_) - - -def test_greedy_max3(): - # All equal weights. - # - G = G1() - B = branchings.greedy_branching(G, attr=None) - - # This is mostly arbitrary...the output was generated by running the algo. - edges = [ - (2, 1, 1), - (3, 0, 1), - (3, 4, 1), - (5, 8, 1), - (6, 2, 1), - (7, 3, 1), - (7, 6, 1), - (8, 7, 1), - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_, default=1) - - -def test_greedy_min(): - G = G1() - B = branchings.greedy_branching(G, kind="min") - - edges = [ - (1, 0, 4), - (0, 2, 12), - (0, 4, 12), - (2, 5, 12), - (4, 7, 12), - (5, 8, 12), - (5, 6, 14), - (7, 3, 19), - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_) - - -def test_edmonds1_maxbranch(): - G = G1() - x = branchings.maximum_branching(G) - x_ = build_branching(optimal_arborescence_1) - assert_equal_branchings(x, x_) - - -def test_edmonds1_maxarbor(): - G = G1() - x = branchings.maximum_spanning_arborescence(G) - x_ = build_branching(optimal_arborescence_1) - assert_equal_branchings(x, x_) - - -def test_edmonds1_minimal_branching(): - # graph will have something like a minimum arborescence but no spanning one - G = nx.from_numpy_array(G_big_array, create_using=nx.DiGraph) - B = branchings.minimal_branching(G) - edges = [ - (3, 0, 5), - (0, 2, 12), - (0, 4, 12), - (2, 5, 12), - (4, 7, 12), - (5, 8, 12), - (5, 6, 14), - (2, 1, 17), - ] - B_ = build_branching(edges, double=True) - assert_equal_branchings(B, B_) - - -def test_edmonds2_maxbranch(): - G = G2() - x = branchings.maximum_branching(G) - x_ = build_branching(optimal_branching_2a) - assert_equal_branchings(x, x_) - - -def test_edmonds2_maxarbor(): - G = G2() - x = branchings.maximum_spanning_arborescence(G) - x_ = build_branching(optimal_arborescence_2) - assert_equal_branchings(x, x_) - - -def test_edmonds2_minarbor(): - G = G1() - x = branchings.minimum_spanning_arborescence(G) - # This was obtained from algorithm. Need to verify it independently. - # Branch weight is: 96 - edges = [ - (3, 0, 5), - (0, 2, 12), - (0, 4, 12), - (2, 5, 12), - (4, 7, 12), - (5, 8, 12), - (5, 6, 14), - (2, 1, 17), - ] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edmonds3_minbranch1(): - G = G1() - x = branchings.minimum_branching(G) - edges = [] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edmonds3_minbranch2(): - G = G1() - G.add_edge(8, 9, weight=-10) - x = branchings.minimum_branching(G) - edges = [(8, 9, -10)] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -# Need more tests - - -def test_mst(): - # Make sure we get the same results for undirected graphs. - # Example from: https://en.wikipedia.org/wiki/Kruskal's_algorithm - G = nx.Graph() - edgelist = [ - (0, 3, [("weight", 5)]), - (0, 1, [("weight", 7)]), - (1, 3, [("weight", 9)]), - (1, 2, [("weight", 8)]), - (1, 4, [("weight", 7)]), - (3, 4, [("weight", 15)]), - (3, 5, [("weight", 6)]), - (2, 4, [("weight", 5)]), - (4, 5, [("weight", 8)]), - (4, 6, [("weight", 9)]), - (5, 6, [("weight", 11)]), - ] - G.add_edges_from(edgelist) - G = G.to_directed() - x = branchings.minimum_spanning_arborescence(G) - - edges = [ - ({0, 1}, 7), - ({0, 3}, 5), - ({3, 5}, 6), - ({1, 4}, 7), - ({4, 2}, 5), - ({4, 6}, 9), - ] - - assert x.number_of_edges() == len(edges) - for u, v, d in x.edges(data=True): - assert ({u, v}, d["weight"]) in edges - - -def test_mixed_nodetypes(): - # Smoke test to make sure no TypeError is raised for mixed node types. - G = nx.Graph() - edgelist = [(0, 3, [("weight", 5)]), (0, "1", [("weight", 5)])] - G.add_edges_from(edgelist) - G = G.to_directed() - x = branchings.minimum_spanning_arborescence(G) - - -def test_edmonds1_minbranch(): - # Using -G_array and min should give the same as optimal_arborescence_1, - # but with all edges negative. - edges = [(u, v, -w) for (u, v, w) in optimal_arborescence_1] - - G = nx.from_numpy_array(-G_array, create_using=nx.DiGraph) - - # Quickly make sure max branching is empty. - x = branchings.maximum_branching(G) - x_ = build_branching([]) - assert_equal_branchings(x, x_) - - # Now test the min branching. - x = branchings.minimum_branching(G) - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edge_attribute_preservation_normal_graph(): - # Test that edge attributes are preserved when finding an optimum graph - # using the Edmonds class for normal graphs. - G = nx.Graph() - - edgelist = [ - (0, 1, [("weight", 5), ("otherattr", 1), ("otherattr2", 3)]), - (0, 2, [("weight", 5), ("otherattr", 2), ("otherattr2", 2)]), - (1, 2, [("weight", 6), ("otherattr", 3), ("otherattr2", 1)]), - ] - G.add_edges_from(edgelist) - - B = branchings.maximum_branching(G, preserve_attrs=True) - - assert B[0][1]["otherattr"] == 1 - assert B[0][1]["otherattr2"] == 3 - - -def test_edge_attribute_preservation_multigraph(): - # Test that edge attributes are preserved when finding an optimum graph - # using the Edmonds class for multigraphs. - G = nx.MultiGraph() - - edgelist = [ - (0, 1, [("weight", 5), ("otherattr", 1), ("otherattr2", 3)]), - (0, 2, [("weight", 5), ("otherattr", 2), ("otherattr2", 2)]), - (1, 2, [("weight", 6), ("otherattr", 3), ("otherattr2", 1)]), - ] - G.add_edges_from(edgelist * 2) # Make sure we have duplicate edge paths - - B = branchings.maximum_branching(G, preserve_attrs=True) - - assert B[0][1][0]["otherattr"] == 1 - assert B[0][1][0]["otherattr2"] == 3 - - -def test_edge_attribute_discard(): - # Test that edge attributes are discarded if we do not specify to keep them - G = nx.Graph() - - edgelist = [ - (0, 1, [("weight", 5), ("otherattr", 1), ("otherattr2", 3)]), - (0, 2, [("weight", 5), ("otherattr", 2), ("otherattr2", 2)]), - (1, 2, [("weight", 6), ("otherattr", 3), ("otherattr2", 1)]), - ] - G.add_edges_from(edgelist) - - B = branchings.maximum_branching(G, preserve_attrs=False) - - edge_dict = B[0][1] - with pytest.raises(KeyError): - _ = edge_dict["otherattr"] - - -def test_partition_spanning_arborescence(): - """ - Test that we can generate minimum spanning arborescences which respect the - given partition. - """ - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - G[3][0]["partition"] = nx.EdgePartition.EXCLUDED - G[2][3]["partition"] = nx.EdgePartition.INCLUDED - G[7][3]["partition"] = nx.EdgePartition.EXCLUDED - G[0][2]["partition"] = nx.EdgePartition.EXCLUDED - G[6][2]["partition"] = nx.EdgePartition.INCLUDED - - actual_edges = [ - (0, 4, 12), - (1, 0, 4), - (1, 5, 13), - (2, 3, 21), - (4, 7, 12), - (5, 6, 14), - (5, 8, 12), - (6, 2, 21), - ] - - B = branchings.minimum_spanning_arborescence(G, partition="partition") - assert_equal_branchings(build_branching(actual_edges), B) - - -def test_arborescence_iterator_min(): - """ - Tests the arborescence iterator. - - A brute force method found 680 arborescences in this graph. - This test will not verify all of them individually, but will check two - things - - * The iterator returns 680 arborescences - * The weight of the arborescences is non-strictly increasing - - for more information please visit - https://mjschwenne.github.io/2021/06/10/implementing-the-iterators.html - """ - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - - arborescence_count = 0 - arborescence_weight = -math.inf - for B in branchings.ArborescenceIterator(G): - arborescence_count += 1 - new_arborescence_weight = B.size(weight="weight") - assert new_arborescence_weight >= arborescence_weight - arborescence_weight = new_arborescence_weight - - assert arborescence_count == 680 - - -def test_arborescence_iterator_max(): - """ - Tests the arborescence iterator. - - A brute force method found 680 arborescences in this graph. - This test will not verify all of them individually, but will check two - things - - * The iterator returns 680 arborescences - * The weight of the arborescences is non-strictly decreasing - - for more information please visit - https://mjschwenne.github.io/2021/06/10/implementing-the-iterators.html - """ - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - - arborescence_count = 0 - arborescence_weight = math.inf - for B in branchings.ArborescenceIterator(G, minimum=False): - arborescence_count += 1 - new_arborescence_weight = B.size(weight="weight") - assert new_arborescence_weight <= arborescence_weight - arborescence_weight = new_arborescence_weight - - assert arborescence_count == 680 - - -def test_arborescence_iterator_initial_partition(): - """ - Tests the arborescence iterator with three included edges and three excluded - in the initial partition. - - A brute force method similar to the one used in the above tests found that - there are 16 arborescences which contain the included edges and not the - excluded edges. - """ - G = nx.from_numpy_array(G_array, create_using=nx.DiGraph) - included_edges = [(1, 0), (5, 6), (8, 7)] - excluded_edges = [(0, 2), (3, 6), (1, 5)] - - arborescence_count = 0 - arborescence_weight = -math.inf - for B in branchings.ArborescenceIterator( - G, init_partition=(included_edges, excluded_edges) - ): - arborescence_count += 1 - new_arborescence_weight = B.size(weight="weight") - assert new_arborescence_weight >= arborescence_weight - arborescence_weight = new_arborescence_weight - for e in included_edges: - assert e in B.edges - for e in excluded_edges: - assert e not in B.edges - assert arborescence_count == 16 - - -def test_branchings_with_default_weights(): - """ - Tests that various branching algorithms work on graphs without weights. - For more information, see issue #7279. - """ - graph = nx.erdos_renyi_graph(10, p=0.2, directed=True, seed=123) - - assert all( - "weight" not in d for (u, v, d) in graph.edges(data=True) - ), "test is for graphs without a weight attribute" - - # Calling these functions will modify graph inplace to add weights - # copy the graph to avoid this. - nx.minimum_spanning_arborescence(graph.copy()) - nx.maximum_spanning_arborescence(graph.copy()) - nx.minimum_branching(graph.copy()) - nx.maximum_branching(graph.copy()) - nx.algorithms.tree.minimal_branching(graph.copy()) - nx.algorithms.tree.branching_weight(graph.copy()) - nx.algorithms.tree.greedy_branching(graph.copy()) - - assert all( - "weight" not in d for (u, v, d) in graph.edges(data=True) - ), "The above calls should not modify the initial graph in-place" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_coding.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_coding.py deleted file mode 100644 index 26bd408..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_coding.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Unit tests for the :mod:`~networkx.algorithms.tree.coding` module.""" - -from itertools import product - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -class TestPruferSequence: - """Unit tests for the Prüfer sequence encoding and decoding - functions. - - """ - - def test_nontree(self): - with pytest.raises(nx.NotATree): - G = nx.cycle_graph(3) - nx.to_prufer_sequence(G) - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.to_prufer_sequence(nx.null_graph()) - - def test_trivial_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.to_prufer_sequence(nx.trivial_graph()) - - def test_bad_integer_labels(self): - with pytest.raises(KeyError): - T = nx.Graph(nx.utils.pairwise("abc")) - nx.to_prufer_sequence(T) - - def test_encoding(self): - """Tests for encoding a tree as a Prüfer sequence using the - iterative strategy. - - """ - # Example from Wikipedia. - tree = nx.Graph([(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)]) - sequence = nx.to_prufer_sequence(tree) - assert sequence == [3, 3, 3, 4] - - def test_decoding(self): - """Tests for decoding a tree from a Prüfer sequence.""" - # Example from Wikipedia. - sequence = [3, 3, 3, 4] - tree = nx.from_prufer_sequence(sequence) - assert nodes_equal(list(tree), list(range(6))) - edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - assert edges_equal(list(tree.edges()), edges) - - def test_decoding2(self): - # Example from "An Optimal Algorithm for Prufer Codes". - sequence = [2, 4, 0, 1, 3, 3] - tree = nx.from_prufer_sequence(sequence) - assert nodes_equal(list(tree), list(range(8))) - edges = [(0, 1), (0, 4), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)] - assert edges_equal(list(tree.edges()), edges) - - def test_inverse(self): - """Tests that the encoding and decoding functions are inverses.""" - for T in nx.nonisomorphic_trees(4): - T2 = nx.from_prufer_sequence(nx.to_prufer_sequence(T)) - assert nodes_equal(list(T), list(T2)) - assert edges_equal(list(T.edges()), list(T2.edges())) - - for seq in product(range(4), repeat=2): - seq2 = nx.to_prufer_sequence(nx.from_prufer_sequence(seq)) - assert list(seq) == seq2 - - -class TestNestedTuple: - """Unit tests for the nested tuple encoding and decoding functions.""" - - def test_nontree(self): - with pytest.raises(nx.NotATree): - G = nx.cycle_graph(3) - nx.to_nested_tuple(G, 0) - - def test_unknown_root(self): - with pytest.raises(nx.NodeNotFound): - G = nx.path_graph(2) - nx.to_nested_tuple(G, "bogus") - - def test_encoding(self): - T = nx.full_rary_tree(2, 2**3 - 1) - expected = (((), ()), ((), ())) - actual = nx.to_nested_tuple(T, 0) - assert nodes_equal(expected, actual) - - def test_canonical_form(self): - T = nx.Graph() - T.add_edges_from([(0, 1), (0, 2), (0, 3)]) - T.add_edges_from([(1, 4), (1, 5)]) - T.add_edges_from([(3, 6), (3, 7)]) - root = 0 - actual = nx.to_nested_tuple(T, root, canonical_form=True) - expected = ((), ((), ()), ((), ())) - assert actual == expected - - def test_decoding(self): - balanced = (((), ()), ((), ())) - expected = nx.full_rary_tree(2, 2**3 - 1) - actual = nx.from_nested_tuple(balanced) - assert nx.is_isomorphic(expected, actual) - - def test_sensible_relabeling(self): - balanced = (((), ()), ((), ())) - T = nx.from_nested_tuple(balanced, sensible_relabeling=True) - edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - assert nodes_equal(list(T), list(range(2**3 - 1))) - assert edges_equal(list(T.edges()), edges) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_decomposition.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_decomposition.py deleted file mode 100644 index 8c37605..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_decomposition.py +++ /dev/null @@ -1,79 +0,0 @@ -import networkx as nx -from networkx.algorithms.tree.decomposition import junction_tree - - -def test_junction_tree_directed_confounders(): - B = nx.DiGraph() - B.add_edges_from([("A", "C"), ("B", "C"), ("C", "D"), ("C", "E")]) - - G = junction_tree(B) - J = nx.Graph() - J.add_edges_from( - [ - (("C", "E"), ("C",)), - (("C",), ("A", "B", "C")), - (("A", "B", "C"), ("C",)), - (("C",), ("C", "D")), - ] - ) - - assert nx.is_isomorphic(G, J) - - -def test_junction_tree_directed_unconnected_nodes(): - B = nx.DiGraph() - B.add_nodes_from([("A", "B", "C", "D")]) - G = junction_tree(B) - - J = nx.Graph() - J.add_nodes_from([("A", "B", "C", "D")]) - - assert nx.is_isomorphic(G, J) - - -def test_junction_tree_directed_cascade(): - B = nx.DiGraph() - B.add_edges_from([("A", "B"), ("B", "C"), ("C", "D")]) - G = junction_tree(B) - - J = nx.Graph() - J.add_edges_from( - [ - (("A", "B"), ("B",)), - (("B",), ("B", "C")), - (("B", "C"), ("C",)), - (("C",), ("C", "D")), - ] - ) - assert nx.is_isomorphic(G, J) - - -def test_junction_tree_directed_unconnected_edges(): - B = nx.DiGraph() - B.add_edges_from([("A", "B"), ("C", "D"), ("E", "F")]) - G = junction_tree(B) - - J = nx.Graph() - J.add_nodes_from([("A", "B"), ("C", "D"), ("E", "F")]) - - assert nx.is_isomorphic(G, J) - - -def test_junction_tree_undirected(): - B = nx.Graph() - B.add_edges_from([("A", "C"), ("A", "D"), ("B", "C"), ("C", "E")]) - G = junction_tree(B) - - J = nx.Graph() - J.add_edges_from( - [ - (("A", "D"), ("A",)), - (("A",), ("A", "C")), - (("A", "C"), ("C",)), - (("C",), ("B", "C")), - (("B", "C"), ("C",)), - (("C",), ("C", "E")), - ] - ) - - assert nx.is_isomorphic(G, J) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_mst.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_mst.py deleted file mode 100644 index f8945a7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_mst.py +++ /dev/null @@ -1,918 +0,0 @@ -"""Unit tests for the :mod:`networkx.algorithms.tree.mst` module.""" - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -def test_unknown_algorithm(): - with pytest.raises(ValueError): - nx.minimum_spanning_tree(nx.Graph(), algorithm="random") - with pytest.raises( - ValueError, match="random is not a valid choice for an algorithm." - ): - nx.maximum_spanning_edges(nx.Graph(), algorithm="random") - - -class MinimumSpanningTreeTestBase: - """Base class for test classes for minimum spanning tree algorithms. - This class contains some common tests that will be inherited by - subclasses. Each subclass must have a class attribute - :data:`algorithm` that is a string representing the algorithm to - run, as described under the ``algorithm`` keyword argument for the - :func:`networkx.minimum_spanning_edges` function. Subclasses can - then implement any algorithm-specific tests. - """ - - def setup_method(self, method): - """Creates an example graph and stores the expected minimum and - maximum spanning tree edges. - """ - # This stores the class attribute `algorithm` in an instance attribute. - self.algo = self.algorithm - # This example graph comes from Wikipedia: - # https://en.wikipedia.org/wiki/Kruskal's_algorithm - edges = [ - (0, 1, 7), - (0, 3, 5), - (1, 2, 8), - (1, 3, 9), - (1, 4, 7), - (2, 4, 5), - (3, 4, 15), - (3, 5, 6), - (4, 5, 8), - (4, 6, 9), - (5, 6, 11), - ] - self.G = nx.Graph() - self.G.add_weighted_edges_from(edges) - self.minimum_spanning_edgelist = [ - (0, 1, {"weight": 7}), - (0, 3, {"weight": 5}), - (1, 4, {"weight": 7}), - (2, 4, {"weight": 5}), - (3, 5, {"weight": 6}), - (4, 6, {"weight": 9}), - ] - self.maximum_spanning_edgelist = [ - (0, 1, {"weight": 7}), - (1, 2, {"weight": 8}), - (1, 3, {"weight": 9}), - (3, 4, {"weight": 15}), - (4, 6, {"weight": 9}), - (5, 6, {"weight": 11}), - ] - - def test_minimum_edges(self): - edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert edges_equal(actual, self.minimum_spanning_edgelist) - - def test_maximum_edges(self): - edges = nx.maximum_spanning_edges(self.G, algorithm=self.algo) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert edges_equal(actual, self.maximum_spanning_edgelist) - - def test_without_data(self): - edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo, data=False) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] - assert edges_equal(actual, expected) - - def test_nan_weights(self): - # Edge weights NaN never appear in the spanning tree. see #2164 - G = self.G - G.add_edge(0, 12, weight=float("nan")) - edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, data=False, ignore_nan=True - ) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] - assert edges_equal(actual, expected) - # Now test for raising exception - edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, data=False, ignore_nan=False - ) - with pytest.raises(ValueError): - list(edges) - # test default for ignore_nan as False - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False) - with pytest.raises(ValueError): - list(edges) - - def test_nan_weights_MultiGraph(self): - G = nx.MultiGraph() - G.add_edge(0, 12, weight=float("nan")) - edges = nx.minimum_spanning_edges( - G, algorithm="prim", data=False, ignore_nan=False - ) - with pytest.raises(ValueError): - list(edges) - # test default for ignore_nan as False - edges = nx.minimum_spanning_edges(G, algorithm="prim", data=False) - with pytest.raises(ValueError): - list(edges) - - def test_nan_weights_order(self): - # now try again with a nan edge at the beginning of G.nodes - edges = [ - (0, 1, 7), - (0, 3, 5), - (1, 2, 8), - (1, 3, 9), - (1, 4, 7), - (2, 4, 5), - (3, 4, 15), - (3, 5, 6), - (4, 5, 8), - (4, 6, 9), - (5, 6, 11), - ] - G = nx.Graph() - G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) - G.add_edge(0, 7, weight=float("nan")) - edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, data=False, ignore_nan=True - ) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] - assert edges_equal(actual, shift) - - def test_isolated_node(self): - # now try again with an isolated node - edges = [ - (0, 1, 7), - (0, 3, 5), - (1, 2, 8), - (1, 3, 9), - (1, 4, 7), - (2, 4, 5), - (3, 4, 15), - (3, 5, 6), - (4, 5, 8), - (4, 6, 9), - (5, 6, 11), - ] - G = nx.Graph() - G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) - G.add_node(0) - edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, data=False, ignore_nan=True - ) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] - assert edges_equal(actual, shift) - - def test_minimum_tree(self): - T = nx.minimum_spanning_tree(self.G, algorithm=self.algo) - actual = sorted(T.edges(data=True)) - assert edges_equal(actual, self.minimum_spanning_edgelist) - - def test_maximum_tree(self): - T = nx.maximum_spanning_tree(self.G, algorithm=self.algo) - actual = sorted(T.edges(data=True)) - assert edges_equal(actual, self.maximum_spanning_edgelist) - - def test_disconnected(self): - G = nx.Graph([(0, 1, {"weight": 1}), (2, 3, {"weight": 2})]) - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert nodes_equal(list(T), list(range(4))) - assert edges_equal(list(T.edges()), [(0, 1), (2, 3)]) - - def test_empty_graph(self): - G = nx.empty_graph(3) - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert nodes_equal(sorted(T), list(range(3))) - assert T.number_of_edges() == 0 - - def test_attributes(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1, color="red", distance=7) - G.add_edge(2, 3, weight=1, color="green", distance=2) - G.add_edge(1, 3, weight=10, color="blue", distance=1) - G.graph["foo"] = "bar" - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert T.graph == G.graph - assert nodes_equal(T, G) - for u, v in T.edges(): - assert T.adj[u][v] == G.adj[u][v] - - def test_weight_attribute(self): - G = nx.Graph() - G.add_edge(0, 1, weight=1, distance=7) - G.add_edge(0, 2, weight=30, distance=1) - G.add_edge(1, 2, weight=1, distance=1) - G.add_node(3) - T = nx.minimum_spanning_tree(G, algorithm=self.algo, weight="distance") - assert nodes_equal(sorted(T), list(range(4))) - assert edges_equal(sorted(T.edges()), [(0, 2), (1, 2)]) - T = nx.maximum_spanning_tree(G, algorithm=self.algo, weight="distance") - assert nodes_equal(sorted(T), list(range(4))) - assert edges_equal(sorted(T.edges()), [(0, 1), (0, 2)]) - - -class TestBoruvka(MinimumSpanningTreeTestBase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Borůvka's algorithm. - """ - - algorithm = "boruvka" - - def test_unicode_name(self): - """Tests that using a Unicode string can correctly indicate - Borůvka's algorithm. - """ - edges = nx.minimum_spanning_edges(self.G, algorithm="borůvka") - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert edges_equal(actual, self.minimum_spanning_edgelist) - - -class MultigraphMSTTestBase(MinimumSpanningTreeTestBase): - # Abstract class - - def test_multigraph_keys_min(self): - """Tests that the minimum spanning edges of a multigraph - preserves edge keys. - """ - G = nx.MultiGraph() - G.add_edge(0, 1, key="a", weight=2) - G.add_edge(0, 1, key="b", weight=1) - min_edges = nx.minimum_spanning_edges - mst_edges = min_edges(G, algorithm=self.algo, data=False) - assert edges_equal([(0, 1, "b")], list(mst_edges)) - - def test_multigraph_keys_max(self): - """Tests that the maximum spanning edges of a multigraph - preserves edge keys. - """ - G = nx.MultiGraph() - G.add_edge(0, 1, key="a", weight=2) - G.add_edge(0, 1, key="b", weight=1) - max_edges = nx.maximum_spanning_edges - mst_edges = max_edges(G, algorithm=self.algo, data=False) - assert edges_equal([(0, 1, "a")], list(mst_edges)) - - -class TestKruskal(MultigraphMSTTestBase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Kruskal's algorithm. - """ - - algorithm = "kruskal" - - def test_key_data_bool(self): - """Tests that the keys and data values are included in - MST edges based on whether keys and data parameters are - true or false""" - G = nx.MultiGraph() - G.add_edge(1, 2, key=1, weight=2) - G.add_edge(1, 2, key=2, weight=3) - G.add_edge(3, 2, key=1, weight=2) - G.add_edge(3, 1, key=1, weight=4) - - # keys are included and data is not included - mst_edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, keys=True, data=False - ) - assert edges_equal([(1, 2, 1), (2, 3, 1)], list(mst_edges)) - - # keys are not included and data is included - mst_edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, keys=False, data=True - ) - assert edges_equal( - [(1, 2, {"weight": 2}), (2, 3, {"weight": 2})], list(mst_edges) - ) - - # both keys and data are not included - mst_edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, keys=False, data=False - ) - assert edges_equal([(1, 2), (2, 3)], list(mst_edges)) - - # both keys and data are included - mst_edges = nx.minimum_spanning_edges( - G, algorithm=self.algo, keys=True, data=True - ) - assert edges_equal( - [(1, 2, 1, {"weight": 2}), (2, 3, 1, {"weight": 2})], list(mst_edges) - ) - - -class TestPrim(MultigraphMSTTestBase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Prim's algorithm. - """ - - algorithm = "prim" - - def test_prim_mst_edges_simple_graph(self): - H = nx.Graph() - H.add_edge(1, 2, key=2, weight=3) - H.add_edge(3, 2, key=1, weight=2) - H.add_edge(3, 1, key=1, weight=4) - - mst_edges = nx.minimum_spanning_edges(H, algorithm=self.algo, ignore_nan=True) - assert edges_equal( - [(1, 2, {"key": 2, "weight": 3}), (2, 3, {"key": 1, "weight": 2})], - list(mst_edges), - ) - - def test_ignore_nan(self): - """Tests that the edges with NaN weights are ignored or - raise an Error based on ignore_nan is true or false""" - H = nx.MultiGraph() - H.add_edge(1, 2, key=1, weight=float("nan")) - H.add_edge(1, 2, key=2, weight=3) - H.add_edge(3, 2, key=1, weight=2) - H.add_edge(3, 1, key=1, weight=4) - - # NaN weight edges are ignored when ignore_nan=True - mst_edges = nx.minimum_spanning_edges(H, algorithm=self.algo, ignore_nan=True) - assert edges_equal( - [(1, 2, 2, {"weight": 3}), (2, 3, 1, {"weight": 2})], list(mst_edges) - ) - - # NaN weight edges raise Error when ignore_nan=False - with pytest.raises(ValueError): - list(nx.minimum_spanning_edges(H, algorithm=self.algo, ignore_nan=False)) - - def test_multigraph_keys_tree(self): - G = nx.MultiGraph() - G.add_edge(0, 1, key="a", weight=2) - G.add_edge(0, 1, key="b", weight=1) - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert edges_equal([(0, 1, 1)], list(T.edges(data="weight"))) - - def test_multigraph_keys_tree_max(self): - G = nx.MultiGraph() - G.add_edge(0, 1, key="a", weight=2) - G.add_edge(0, 1, key="b", weight=1) - T = nx.maximum_spanning_tree(G, algorithm=self.algo) - assert edges_equal([(0, 1, 2)], list(T.edges(data="weight"))) - - -class TestSpanningTreeIterator: - """ - Tests the spanning tree iterator on the example graph in the 2005 Sörensen - and Janssens paper An Algorithm to Generate all Spanning Trees of a Graph in - Order of Increasing Cost - """ - - def setup_method(self): - # Original Graph - edges = [(0, 1, 5), (1, 2, 4), (1, 4, 6), (2, 3, 5), (2, 4, 7), (3, 4, 3)] - self.G = nx.Graph() - self.G.add_weighted_edges_from(edges) - # List of lists of spanning trees in increasing order - self.spanning_trees = [ - # 1, MST, cost = 17 - [ - (0, 1, {"weight": 5}), - (1, 2, {"weight": 4}), - (2, 3, {"weight": 5}), - (3, 4, {"weight": 3}), - ], - # 2, cost = 18 - [ - (0, 1, {"weight": 5}), - (1, 2, {"weight": 4}), - (1, 4, {"weight": 6}), - (3, 4, {"weight": 3}), - ], - # 3, cost = 19 - [ - (0, 1, {"weight": 5}), - (1, 4, {"weight": 6}), - (2, 3, {"weight": 5}), - (3, 4, {"weight": 3}), - ], - # 4, cost = 19 - [ - (0, 1, {"weight": 5}), - (1, 2, {"weight": 4}), - (2, 4, {"weight": 7}), - (3, 4, {"weight": 3}), - ], - # 5, cost = 20 - [ - (0, 1, {"weight": 5}), - (1, 2, {"weight": 4}), - (1, 4, {"weight": 6}), - (2, 3, {"weight": 5}), - ], - # 6, cost = 21 - [ - (0, 1, {"weight": 5}), - (1, 4, {"weight": 6}), - (2, 4, {"weight": 7}), - (3, 4, {"weight": 3}), - ], - # 7, cost = 21 - [ - (0, 1, {"weight": 5}), - (1, 2, {"weight": 4}), - (2, 3, {"weight": 5}), - (2, 4, {"weight": 7}), - ], - # 8, cost = 23 - [ - (0, 1, {"weight": 5}), - (1, 4, {"weight": 6}), - (2, 3, {"weight": 5}), - (2, 4, {"weight": 7}), - ], - ] - - def test_minimum_spanning_tree_iterator(self): - """ - Tests that the spanning trees are correctly returned in increasing order - """ - tree_index = 0 - for tree in nx.SpanningTreeIterator(self.G): - actual = sorted(tree.edges(data=True)) - assert edges_equal(actual, self.spanning_trees[tree_index]) - tree_index += 1 - - def test_maximum_spanning_tree_iterator(self): - """ - Tests that the spanning trees are correctly returned in decreasing order - """ - tree_index = 7 - for tree in nx.SpanningTreeIterator(self.G, minimum=False): - actual = sorted(tree.edges(data=True)) - assert edges_equal(actual, self.spanning_trees[tree_index]) - tree_index -= 1 - - -class TestSpanningTreeMultiGraphIterator: - """ - Uses the same graph as the above class but with an added edge of twice the weight. - """ - - def setup_method(self): - # New graph - edges = [ - (0, 1, 5), - (0, 1, 10), - (1, 2, 4), - (1, 2, 8), - (1, 4, 6), - (1, 4, 12), - (2, 3, 5), - (2, 3, 10), - (2, 4, 7), - (2, 4, 14), - (3, 4, 3), - (3, 4, 6), - ] - self.G = nx.MultiGraph() - self.G.add_weighted_edges_from(edges) - - # There are 128 trees. I'd rather not list all 128 here, and computing them - # on such a small graph actually doesn't take that long. - from itertools import combinations - - self.spanning_trees = [] - for e in combinations(self.G.edges, 4): - tree = self.G.edge_subgraph(e) - if nx.is_tree(tree): - self.spanning_trees.append(sorted(tree.edges(keys=True, data=True))) - - def test_minimum_spanning_tree_iterator_multigraph(self): - """ - Tests that the spanning trees are correctly returned in increasing order - """ - tree_index = 0 - last_weight = 0 - for tree in nx.SpanningTreeIterator(self.G): - actual = sorted(tree.edges(keys=True, data=True)) - weight = sum([e[3]["weight"] for e in actual]) - assert actual in self.spanning_trees - assert weight >= last_weight - tree_index += 1 - - def test_maximum_spanning_tree_iterator_multigraph(self): - """ - Tests that the spanning trees are correctly returned in decreasing order - """ - tree_index = 127 - # Maximum weight tree is 46 - last_weight = 50 - for tree in nx.SpanningTreeIterator(self.G, minimum=False): - actual = sorted(tree.edges(keys=True, data=True)) - weight = sum([e[3]["weight"] for e in actual]) - assert actual in self.spanning_trees - assert weight <= last_weight - tree_index -= 1 - - -def test_random_spanning_tree_multiplicative_small(): - """ - Using a fixed seed, sample one tree for repeatability. - """ - from math import exp - - pytest.importorskip("scipy") - - gamma = { - (0, 1): -0.6383, - (0, 2): -0.6827, - (0, 5): 0, - (1, 2): -1.0781, - (1, 4): 0, - (2, 3): 0, - (5, 3): -0.2820, - (5, 4): -0.3327, - (4, 3): -0.9927, - } - - # The undirected support of gamma - G = nx.Graph() - for u, v in gamma: - G.add_edge(u, v, lambda_key=exp(gamma[(u, v)])) - - solution_edges = [(2, 3), (3, 4), (0, 5), (5, 4), (4, 1)] - solution = nx.Graph() - solution.add_edges_from(solution_edges) - - sampled_tree = nx.random_spanning_tree(G, "lambda_key", seed=42) - - assert nx.utils.edges_equal(solution.edges, sampled_tree.edges) - - -@pytest.mark.slow -def test_random_spanning_tree_multiplicative_large(): - """ - Sample many trees from the distribution created in the last test - """ - from math import exp - from random import Random - - pytest.importorskip("numpy") - stats = pytest.importorskip("scipy.stats") - - gamma = { - (0, 1): -0.6383, - (0, 2): -0.6827, - (0, 5): 0, - (1, 2): -1.0781, - (1, 4): 0, - (2, 3): 0, - (5, 3): -0.2820, - (5, 4): -0.3327, - (4, 3): -0.9927, - } - - # The undirected support of gamma - G = nx.Graph() - for u, v in gamma: - G.add_edge(u, v, lambda_key=exp(gamma[(u, v)])) - - # Find the multiplicative weight for each tree. - total_weight = 0 - tree_expected = {} - for t in nx.SpanningTreeIterator(G): - # Find the multiplicative weight of the spanning tree - weight = 1 - for u, v, d in t.edges(data="lambda_key"): - weight *= d - tree_expected[t] = weight - total_weight += weight - - # Assert that every tree has an entry in the expected distribution - assert len(tree_expected) == 75 - - # Set the sample size and then calculate the expected number of times we - # expect to see each tree. This test uses a near minimum sample size where - # the most unlikely tree has an expected frequency of 5.15. - # (Minimum required is 5) - # - # Here we also initialize the tree_actual dict so that we know the keys - # match between the two. We will later take advantage of the fact that since - # python 3.7 dict order is guaranteed so the expected and actual data will - # have the same order. - sample_size = 1200 - tree_actual = {} - for t in tree_expected: - tree_expected[t] = (tree_expected[t] / total_weight) * sample_size - tree_actual[t] = 0 - - # Sample the spanning trees - # - # Assert that they are actually trees and record which of the 75 trees we - # have sampled. - # - # For repeatability, we want to take advantage of the decorators in NetworkX - # to randomly sample the same sample each time. However, if we pass in a - # constant seed to sample_spanning_tree we will get the same tree each time. - # Instead, we can create our own random number generator with a fixed seed - # and pass those into sample_spanning_tree. - rng = Random(37) - for _ in range(sample_size): - sampled_tree = nx.random_spanning_tree(G, "lambda_key", seed=rng) - assert nx.is_tree(sampled_tree) - - for t in tree_expected: - if nx.utils.edges_equal(t.edges, sampled_tree.edges): - tree_actual[t] += 1 - break - - # Conduct a Chi squared test to see if the actual distribution matches the - # expected one at an alpha = 0.05 significance level. - # - # H_0: The distribution of trees in tree_actual matches the normalized product - # of the edge weights in the tree. - # - # H_a: The distribution of trees in tree_actual follows some other - # distribution of spanning trees. - _, p = stats.chisquare(list(tree_actual.values()), list(tree_expected.values())) - - # Assert that p is greater than the significance level so that we do not - # reject the null hypothesis - assert not p < 0.05 - - -def test_random_spanning_tree_additive_small(): - """ - Sample a single spanning tree from the additive method. - """ - pytest.importorskip("scipy") - - edges = { - (0, 1): 1, - (0, 2): 1, - (0, 5): 3, - (1, 2): 2, - (1, 4): 3, - (2, 3): 3, - (5, 3): 4, - (5, 4): 5, - (4, 3): 4, - } - - # Build the graph - G = nx.Graph() - for u, v in edges: - G.add_edge(u, v, weight=edges[(u, v)]) - - solution_edges = [(0, 2), (1, 2), (2, 3), (3, 4), (3, 5)] - solution = nx.Graph() - solution.add_edges_from(solution_edges) - - sampled_tree = nx.random_spanning_tree( - G, weight="weight", multiplicative=False, seed=37 - ) - - assert nx.utils.edges_equal(solution.edges, sampled_tree.edges) - - -@pytest.mark.slow -def test_random_spanning_tree_additive_large(): - """ - Sample many spanning trees from the additive method. - """ - from random import Random - - pytest.importorskip("numpy") - stats = pytest.importorskip("scipy.stats") - - edges = { - (0, 1): 1, - (0, 2): 1, - (0, 5): 3, - (1, 2): 2, - (1, 4): 3, - (2, 3): 3, - (5, 3): 4, - (5, 4): 5, - (4, 3): 4, - } - - # Build the graph - G = nx.Graph() - for u, v in edges: - G.add_edge(u, v, weight=edges[(u, v)]) - - # Find the additive weight for each tree. - total_weight = 0 - tree_expected = {} - for t in nx.SpanningTreeIterator(G): - # Find the multiplicative weight of the spanning tree - weight = 0 - for u, v, d in t.edges(data="weight"): - weight += d - tree_expected[t] = weight - total_weight += weight - - # Assert that every tree has an entry in the expected distribution - assert len(tree_expected) == 75 - - # Set the sample size and then calculate the expected number of times we - # expect to see each tree. This test uses a near minimum sample size where - # the most unlikely tree has an expected frequency of 5.07. - # (Minimum required is 5) - # - # Here we also initialize the tree_actual dict so that we know the keys - # match between the two. We will later take advantage of the fact that since - # python 3.7 dict order is guaranteed so the expected and actual data will - # have the same order. - sample_size = 500 - tree_actual = {} - for t in tree_expected: - tree_expected[t] = (tree_expected[t] / total_weight) * sample_size - tree_actual[t] = 0 - - # Sample the spanning trees - # - # Assert that they are actually trees and record which of the 75 trees we - # have sampled. - # - # For repeatability, we want to take advantage of the decorators in NetworkX - # to randomly sample the same sample each time. However, if we pass in a - # constant seed to sample_spanning_tree we will get the same tree each time. - # Instead, we can create our own random number generator with a fixed seed - # and pass those into sample_spanning_tree. - rng = Random(37) - for _ in range(sample_size): - sampled_tree = nx.random_spanning_tree( - G, "weight", multiplicative=False, seed=rng - ) - assert nx.is_tree(sampled_tree) - - for t in tree_expected: - if nx.utils.edges_equal(t.edges, sampled_tree.edges): - tree_actual[t] += 1 - break - - # Conduct a Chi squared test to see if the actual distribution matches the - # expected one at an alpha = 0.05 significance level. - # - # H_0: The distribution of trees in tree_actual matches the normalized product - # of the edge weights in the tree. - # - # H_a: The distribution of trees in tree_actual follows some other - # distribution of spanning trees. - _, p = stats.chisquare(list(tree_actual.values()), list(tree_expected.values())) - - # Assert that p is greater than the significance level so that we do not - # reject the null hypothesis - assert not p < 0.05 - - -def test_random_spanning_tree_empty_graph(): - G = nx.Graph() - rst = nx.tree.random_spanning_tree(G) - assert len(rst.nodes) == 0 - assert len(rst.edges) == 0 - - -def test_random_spanning_tree_single_node_graph(): - G = nx.Graph() - G.add_node(0) - rst = nx.tree.random_spanning_tree(G) - assert len(rst.nodes) == 1 - assert len(rst.edges) == 0 - - -def test_random_spanning_tree_single_node_loop(): - G = nx.Graph() - G.add_node(0) - G.add_edge(0, 0) - rst = nx.tree.random_spanning_tree(G) - assert len(rst.nodes) == 1 - assert len(rst.edges) == 0 - - -class TestNumberSpanningTrees: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") - - def test_nst_disconnected(self): - G = nx.empty_graph(2) - assert np.isclose(nx.number_of_spanning_trees(G), 0) - - def test_nst_no_nodes(self): - G = nx.Graph() - with pytest.raises(nx.NetworkXPointlessConcept): - nx.number_of_spanning_trees(G) - - def test_nst_weight(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1) - G.add_edge(1, 3, weight=1) - G.add_edge(2, 3, weight=2) - # weights are ignored - assert np.isclose(nx.number_of_spanning_trees(G), 3) - # including weight - assert np.isclose(nx.number_of_spanning_trees(G, weight="weight"), 5) - - def test_nst_negative_weight(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1) - G.add_edge(1, 3, weight=-1) - G.add_edge(2, 3, weight=-2) - # weights are ignored - assert np.isclose(nx.number_of_spanning_trees(G), 3) - # including weight - assert np.isclose(nx.number_of_spanning_trees(G, weight="weight"), -1) - - def test_nst_selfloop(self): - # self-loops are ignored - G = nx.complete_graph(3) - G.add_edge(1, 1) - assert np.isclose(nx.number_of_spanning_trees(G), 3) - - def test_nst_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2) - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(2, 3) - assert np.isclose(nx.number_of_spanning_trees(G), 5) - - def test_nst_complete_graph(self): - # this is known as Cayley's formula - N = 5 - G = nx.complete_graph(N) - assert np.isclose(nx.number_of_spanning_trees(G), N ** (N - 2)) - - def test_nst_path_graph(self): - G = nx.path_graph(5) - assert np.isclose(nx.number_of_spanning_trees(G), 1) - - def test_nst_cycle_graph(self): - G = nx.cycle_graph(5) - assert np.isclose(nx.number_of_spanning_trees(G), 5) - - def test_nst_directed_noroot(self): - G = nx.empty_graph(3, create_using=nx.MultiDiGraph) - with pytest.raises(nx.NetworkXError): - nx.number_of_spanning_trees(G) - - def test_nst_directed_root_not_exist(self): - G = nx.empty_graph(3, create_using=nx.MultiDiGraph) - with pytest.raises(nx.NetworkXError): - nx.number_of_spanning_trees(G, root=42) - - def test_nst_directed_not_weak_connected(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(3, 4) - assert np.isclose(nx.number_of_spanning_trees(G, root=1), 0) - - def test_nst_directed_cycle_graph(self): - G = nx.DiGraph() - G = nx.cycle_graph(7, G) - assert np.isclose(nx.number_of_spanning_trees(G, root=0), 1) - - def test_nst_directed_complete_graph(self): - G = nx.DiGraph() - G = nx.complete_graph(7, G) - assert np.isclose(nx.number_of_spanning_trees(G, root=0), 7**5) - - def test_nst_directed_multi(self): - G = nx.MultiDiGraph() - G = nx.cycle_graph(3, G) - G.add_edge(1, 2) - assert np.isclose(nx.number_of_spanning_trees(G, root=0), 2) - - def test_nst_directed_selfloop(self): - G = nx.MultiDiGraph() - G = nx.cycle_graph(3, G) - G.add_edge(1, 1) - assert np.isclose(nx.number_of_spanning_trees(G, root=0), 1) - - def test_nst_directed_weak_connected(self): - G = nx.MultiDiGraph() - G = nx.cycle_graph(3, G) - G.remove_edge(1, 2) - assert np.isclose(nx.number_of_spanning_trees(G, root=0), 0) - - def test_nst_directed_weighted(self): - # from root=1: - # arborescence 1: 1->2, 1->3, weight=2*1 - # arborescence 2: 1->2, 2->3, weight=2*3 - G = nx.DiGraph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 3, weight=1) - G.add_edge(2, 3, weight=3) - Nst = nx.number_of_spanning_trees(G, root=1, weight="weight") - assert np.isclose(Nst, 8) - Nst = nx.number_of_spanning_trees(G, root=2, weight="weight") - assert np.isclose(Nst, 0) - Nst = nx.number_of_spanning_trees(G, root=3, weight="weight") - assert np.isclose(Nst, 0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_operations.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_operations.py deleted file mode 100644 index 284d94e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_operations.py +++ /dev/null @@ -1,53 +0,0 @@ -from itertools import chain - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -def _check_custom_label_attribute(input_trees, res_tree, label_attribute): - res_attr_dict = nx.get_node_attributes(res_tree, label_attribute) - res_attr_set = set(res_attr_dict.values()) - input_label = (tree for tree, root in input_trees) - input_label_set = set(chain.from_iterable(input_label)) - return res_attr_set == input_label_set - - -def test_empty_sequence(): - """Joining the empty sequence results in the tree with one node.""" - T = nx.join_trees([]) - assert len(T) == 1 - assert T.number_of_edges() == 0 - - -def test_single(): - """Joining just one tree yields a tree with one more node.""" - T = nx.empty_graph(1) - trees = [(T, 0)] - actual_with_label = nx.join_trees(trees, label_attribute="custom_label") - expected = nx.path_graph(2) - assert nodes_equal(list(expected), list(actual_with_label)) - assert edges_equal(list(expected.edges()), list(actual_with_label.edges())) - - -def test_basic(): - """Joining multiple subtrees at a root node.""" - trees = [(nx.full_rary_tree(2, 2**2 - 1), 0) for i in range(2)] - expected = nx.full_rary_tree(2, 2**3 - 1) - actual = nx.join_trees(trees, label_attribute="old_labels") - assert nx.is_isomorphic(actual, expected) - assert _check_custom_label_attribute(trees, actual, "old_labels") - - actual_without_label = nx.join_trees(trees) - assert nx.is_isomorphic(actual_without_label, expected) - # check that no labels were stored - assert all(not data for _, data in actual_without_label.nodes(data=True)) - - -def test_first_label(): - """Test the functionality of the first_label argument.""" - T1 = nx.path_graph(3) - T2 = nx.path_graph(2) - actual = nx.join_trees([(T1, 0), (T2, 0)], first_label=10) - expected_nodes = set(range(10, 16)) - assert set(actual.nodes()) == expected_nodes - assert set(actual.neighbors(10)) == {11, 14} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_recognition.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_recognition.py deleted file mode 100644 index 105f5a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/tree/tests/test_recognition.py +++ /dev/null @@ -1,174 +0,0 @@ -import pytest - -import networkx as nx - - -class TestTreeRecognition: - graph = nx.Graph - multigraph = nx.MultiGraph - - @classmethod - def setup_class(cls): - cls.T1 = cls.graph() - - cls.T2 = cls.graph() - cls.T2.add_node(1) - - cls.T3 = cls.graph() - cls.T3.add_nodes_from(range(5)) - edges = [(i, i + 1) for i in range(4)] - cls.T3.add_edges_from(edges) - - cls.T5 = cls.multigraph() - cls.T5.add_nodes_from(range(5)) - edges = [(i, i + 1) for i in range(4)] - cls.T5.add_edges_from(edges) - - cls.T6 = cls.graph() - cls.T6.add_nodes_from([6, 7]) - cls.T6.add_edge(6, 7) - - cls.F1 = nx.compose(cls.T6, cls.T3) - - cls.N4 = cls.graph() - cls.N4.add_node(1) - cls.N4.add_edge(1, 1) - - cls.N5 = cls.graph() - cls.N5.add_nodes_from(range(5)) - - cls.N6 = cls.graph() - cls.N6.add_nodes_from(range(3)) - cls.N6.add_edges_from([(0, 1), (1, 2), (2, 0)]) - - cls.NF1 = nx.compose(cls.T6, cls.N6) - - def test_null_tree(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_tree(self.graph()) - - def test_null_tree2(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_tree(self.multigraph()) - - def test_null_forest(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_forest(self.graph()) - - def test_null_forest2(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_forest(self.multigraph()) - - def test_is_tree(self): - assert nx.is_tree(self.T2) - assert nx.is_tree(self.T3) - assert nx.is_tree(self.T5) - - def test_is_not_tree(self): - assert not nx.is_tree(self.N4) - assert not nx.is_tree(self.N5) - assert not nx.is_tree(self.N6) - - def test_is_forest(self): - assert nx.is_forest(self.T2) - assert nx.is_forest(self.T3) - assert nx.is_forest(self.T5) - assert nx.is_forest(self.F1) - assert nx.is_forest(self.N5) - - def test_is_not_forest(self): - assert not nx.is_forest(self.N4) - assert not nx.is_forest(self.N6) - assert not nx.is_forest(self.NF1) - - -class TestDirectedTreeRecognition(TestTreeRecognition): - graph = nx.DiGraph - multigraph = nx.MultiDiGraph - - -def test_disconnected_graph(): - # https://github.com/networkx/networkx/issues/1144 - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (3, 4)]) - assert not nx.is_tree(G) - - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (3, 4)]) - assert not nx.is_tree(G) - - -def test_dag_nontree(): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (0, 2), (1, 2)]) - assert not nx.is_tree(G) - assert nx.is_directed_acyclic_graph(G) - - -def test_multicycle(): - G = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (0, 1)]) - assert not nx.is_tree(G) - assert nx.is_directed_acyclic_graph(G) - - -def test_emptybranch(): - G = nx.DiGraph() - G.add_nodes_from(range(10)) - assert nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_is_branching_empty_graph_raises(): - G = nx.DiGraph() - with pytest.raises(nx.NetworkXPointlessConcept, match="G has no nodes."): - nx.is_branching(G) - - -def test_path(): - G = nx.DiGraph() - nx.add_path(G, range(5)) - assert nx.is_branching(G) - assert nx.is_arborescence(G) - - -def test_notbranching1(): - # Acyclic violation. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (1, 0)]) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notbranching2(): - # In-degree violation. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (0, 2), (3, 2)]) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notarborescence1(): - # Not an arborescence due to not spanning. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (5, 6)]) - assert nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notarborescence2(): - # Not an arborescence due to in-degree violation. - G = nx.MultiDiGraph() - nx.add_path(G, range(5)) - G.add_edge(6, 4) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_is_arborescense_empty_graph_raises(): - G = nx.DiGraph() - with pytest.raises(nx.NetworkXPointlessConcept, match="G has no nodes."): - nx.is_arborescence(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/triads.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/triads.py deleted file mode 100644 index 640fc30..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/triads.py +++ /dev/null @@ -1,604 +0,0 @@ -# See https://github.com/networkx/networkx/pull/1474 -# Copyright 2011 Reya Group -# Copyright 2011 Alex Levenson -# Copyright 2011 Diederik van Liere -"""Functions for analyzing triads of a graph.""" - -from collections import defaultdict -from itertools import combinations, permutations - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = [ - "triadic_census", - "is_triad", - "all_triplets", - "all_triads", - "triads_by_type", - "triad_type", - "random_triad", -] - -#: The integer codes representing each type of triad. -#: -#: Triads that are the same up to symmetry have the same code. -TRICODES = ( - 1, - 2, - 2, - 3, - 2, - 4, - 6, - 8, - 2, - 6, - 5, - 7, - 3, - 8, - 7, - 11, - 2, - 6, - 4, - 8, - 5, - 9, - 9, - 13, - 6, - 10, - 9, - 14, - 7, - 14, - 12, - 15, - 2, - 5, - 6, - 7, - 6, - 9, - 10, - 14, - 4, - 9, - 9, - 12, - 8, - 13, - 14, - 15, - 3, - 7, - 8, - 11, - 7, - 12, - 14, - 15, - 8, - 14, - 13, - 15, - 11, - 15, - 15, - 16, -) - -#: The names of each type of triad. The order of the elements is -#: important: it corresponds to the tricodes given in :data:`TRICODES`. -TRIAD_NAMES = ( - "003", - "012", - "102", - "021D", - "021U", - "021C", - "111D", - "111U", - "030T", - "030C", - "201", - "120D", - "120U", - "120C", - "210", - "300", -) - - -#: A dictionary mapping triad code to triad name. -TRICODE_TO_NAME = {i: TRIAD_NAMES[code - 1] for i, code in enumerate(TRICODES)} - - -def _tricode(G, v, u, w): - """Returns the integer code of the given triad. - - This is some fancy magic that comes from Batagelj and Mrvar's paper. It - treats each edge joining a pair of `v`, `u`, and `w` as a bit in - the binary representation of an integer. - - """ - combos = ((v, u, 1), (u, v, 2), (v, w, 4), (w, v, 8), (u, w, 16), (w, u, 32)) - return sum(x for u, v, x in combos if v in G[u]) - - -@not_implemented_for("undirected") -@nx._dispatchable -def triadic_census(G, nodelist=None): - """Determines the triadic census of a directed graph. - - The triadic census is a count of how many of the 16 possible types of - triads are present in a directed graph. If a list of nodes is passed, then - only those triads are taken into account which have elements of nodelist in them. - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - nodelist : list - List of nodes for which you want to calculate triadic census - - Returns - ------- - census : dict - Dictionary with triad type as keys and number of occurrences as values. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1), (3, 4), (4, 1), (4, 2)]) - >>> triadic_census = nx.triadic_census(G) - >>> for key, value in triadic_census.items(): - ... print(f"{key}: {value}") - 003: 0 - 012: 0 - 102: 0 - 021D: 0 - 021U: 0 - 021C: 0 - 111D: 0 - 111U: 0 - 030T: 2 - 030C: 2 - 201: 0 - 120D: 0 - 120U: 0 - 120C: 0 - 210: 0 - 300: 0 - - Notes - ----- - This algorithm has complexity $O(m)$ where $m$ is the number of edges in - the graph. - - For undirected graphs, the triadic census can be computed by first converting - the graph into a directed graph using the ``G.to_directed()`` method. - After this conversion, only the triad types 003, 102, 201 and 300 will be - present in the undirected scenario. - - Raises - ------ - ValueError - If `nodelist` contains duplicate nodes or nodes not in `G`. - If you want to ignore this you can preprocess with `set(nodelist) & G.nodes` - - See also - -------- - triad_graph - - References - ---------- - .. [1] Vladimir Batagelj and Andrej Mrvar, A subquadratic triad census - algorithm for large sparse networks with small maximum degree, - University of Ljubljana, - http://vlado.fmf.uni-lj.si/pub/networks/doc/triads/triads.pdf - - """ - nodeset = set(G.nbunch_iter(nodelist)) - if nodelist is not None and len(nodelist) != len(nodeset): - raise ValueError("nodelist includes duplicate nodes or nodes not in G") - - N = len(G) - Nnot = N - len(nodeset) # can signal special counting for subset of nodes - - # create an ordering of nodes with nodeset nodes first - m = {n: i for i, n in enumerate(nodeset)} - if Nnot: - # add non-nodeset nodes later in the ordering - not_nodeset = G.nodes - nodeset - m.update((n, i + N) for i, n in enumerate(not_nodeset)) - - # build all_neighbor dicts for easy counting - # After Python 3.8 can leave off these keys(). Speedup also using G._pred - # nbrs = {n: G._pred[n].keys() | G._succ[n].keys() for n in G} - nbrs = {n: G.pred[n].keys() | G.succ[n].keys() for n in G} - dbl_nbrs = {n: G.pred[n].keys() & G.succ[n].keys() for n in G} - - if Nnot: - sgl_nbrs = {n: G.pred[n].keys() ^ G.succ[n].keys() for n in not_nodeset} - # find number of edges not incident to nodes in nodeset - sgl = sum(1 for n in not_nodeset for nbr in sgl_nbrs[n] if nbr not in nodeset) - sgl_edges_outside = sgl // 2 - dbl = sum(1 for n in not_nodeset for nbr in dbl_nbrs[n] if nbr not in nodeset) - dbl_edges_outside = dbl // 2 - - # Initialize the count for each triad to be zero. - census = {name: 0 for name in TRIAD_NAMES} - # Main loop over nodes - for v in nodeset: - vnbrs = nbrs[v] - dbl_vnbrs = dbl_nbrs[v] - if Nnot: - # set up counts of edges attached to v. - sgl_unbrs_bdy = sgl_unbrs_out = dbl_unbrs_bdy = dbl_unbrs_out = 0 - for u in vnbrs: - if m[u] <= m[v]: - continue - unbrs = nbrs[u] - neighbors = (vnbrs | unbrs) - {u, v} - # Count connected triads. - for w in neighbors: - if m[u] < m[w] or (m[v] < m[w] < m[u] and v not in nbrs[w]): - code = _tricode(G, v, u, w) - census[TRICODE_TO_NAME[code]] += 1 - - # Use a formula for dyadic triads with edge incident to v - if u in dbl_vnbrs: - census["102"] += N - len(neighbors) - 2 - else: - census["012"] += N - len(neighbors) - 2 - - # Count edges attached to v. Subtract later to get triads with v isolated - # _out are (u,unbr) for unbrs outside boundary of nodeset - # _bdy are (u,unbr) for unbrs on boundary of nodeset (get double counted) - if Nnot and u not in nodeset: - sgl_unbrs = sgl_nbrs[u] - sgl_unbrs_bdy += len(sgl_unbrs & vnbrs - nodeset) - sgl_unbrs_out += len(sgl_unbrs - vnbrs - nodeset) - dbl_unbrs = dbl_nbrs[u] - dbl_unbrs_bdy += len(dbl_unbrs & vnbrs - nodeset) - dbl_unbrs_out += len(dbl_unbrs - vnbrs - nodeset) - # if nodeset == G.nodes, skip this b/c we will find the edge later. - if Nnot: - # Count edges outside nodeset not connected with v (v isolated triads) - census["012"] += sgl_edges_outside - (sgl_unbrs_out + sgl_unbrs_bdy // 2) - census["102"] += dbl_edges_outside - (dbl_unbrs_out + dbl_unbrs_bdy // 2) - - # calculate null triads: "003" - # null triads = total number of possible triads - all found triads - total_triangles = (N * (N - 1) * (N - 2)) // 6 - triangles_without_nodeset = (Nnot * (Nnot - 1) * (Nnot - 2)) // 6 - total_census = total_triangles - triangles_without_nodeset - census["003"] = total_census - sum(census.values()) - - return census - - -@nx._dispatchable -def is_triad(G): - """Returns True if the graph G is a triad, else False. - - Parameters - ---------- - G : graph - A NetworkX Graph - - Returns - ------- - istriad : boolean - Whether G is a valid triad - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - >>> nx.is_triad(G) - True - >>> G.add_edge(0, 1) - >>> nx.is_triad(G) - False - """ - if isinstance(G, nx.Graph): - if G.order() == 3 and nx.is_directed(G): - if not any((n, n) in G.edges() for n in G.nodes()): - return True - return False - - -@not_implemented_for("undirected") -@nx._dispatchable -def all_triplets(G): - """Returns a generator of all possible sets of 3 nodes in a DiGraph. - - .. deprecated:: 3.3 - - all_triplets is deprecated and will be removed in NetworkX version 3.5. - Use `itertools.combinations` instead:: - - all_triplets = itertools.combinations(G, 3) - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - - Returns - ------- - triplets : generator of 3-tuples - Generator of tuples of 3 nodes - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - >>> list(nx.all_triplets(G)) - [(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)] - - """ - import warnings - - warnings.warn( - ( - "\n\nall_triplets is deprecated and will be removed in v3.5.\n" - "Use `itertools.combinations(G, 3)` instead." - ), - category=DeprecationWarning, - stacklevel=4, - ) - triplets = combinations(G.nodes(), 3) - return triplets - - -@not_implemented_for("undirected") -@nx._dispatchable(returns_graph=True) -def all_triads(G): - """A generator of all possible triads in G. - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - - Returns - ------- - all_triads : generator of DiGraphs - Generator of triads (order-3 DiGraphs) - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1), (3, 4), (4, 1), (4, 2)]) - >>> for triad in nx.all_triads(G): - ... print(triad.edges) - [(1, 2), (2, 3), (3, 1)] - [(1, 2), (4, 1), (4, 2)] - [(3, 1), (3, 4), (4, 1)] - [(2, 3), (3, 4), (4, 2)] - - """ - triplets = combinations(G.nodes(), 3) - for triplet in triplets: - yield G.subgraph(triplet).copy() - - -@not_implemented_for("undirected") -@nx._dispatchable -def triads_by_type(G): - """Returns a list of all triads for each triad type in a directed graph. - There are exactly 16 different types of triads possible. Suppose 1, 2, 3 are three - nodes, they will be classified as a particular triad type if their connections - are as follows: - - - 003: 1, 2, 3 - - 012: 1 -> 2, 3 - - 102: 1 <-> 2, 3 - - 021D: 1 <- 2 -> 3 - - 021U: 1 -> 2 <- 3 - - 021C: 1 -> 2 -> 3 - - 111D: 1 <-> 2 <- 3 - - 111U: 1 <-> 2 -> 3 - - 030T: 1 -> 2 -> 3, 1 -> 3 - - 030C: 1 <- 2 <- 3, 1 -> 3 - - 201: 1 <-> 2 <-> 3 - - 120D: 1 <- 2 -> 3, 1 <-> 3 - - 120U: 1 -> 2 <- 3, 1 <-> 3 - - 120C: 1 -> 2 -> 3, 1 <-> 3 - - 210: 1 -> 2 <-> 3, 1 <-> 3 - - 300: 1 <-> 2 <-> 3, 1 <-> 3 - - Refer to the :doc:`example gallery ` - for visual examples of the triad types. - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - - Returns - ------- - tri_by_type : dict - Dictionary with triad types as keys and lists of triads as values. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 1), (5, 6), (5, 4), (6, 7)]) - >>> dict = nx.triads_by_type(G) - >>> dict["120C"][0].edges() - OutEdgeView([(1, 2), (1, 3), (2, 3), (3, 1)]) - >>> dict["012"][0].edges() - OutEdgeView([(1, 2)]) - - References - ---------- - .. [1] Snijders, T. (2012). "Transitivity and triads." University of - Oxford. - https://web.archive.org/web/20170830032057/http://www.stats.ox.ac.uk/~snijders/Trans_Triads_ha.pdf - """ - # num_triads = o * (o - 1) * (o - 2) // 6 - # if num_triads > TRIAD_LIMIT: print(WARNING) - all_tri = all_triads(G) - tri_by_type = defaultdict(list) - for triad in all_tri: - name = triad_type(triad) - tri_by_type[name].append(triad) - return tri_by_type - - -@not_implemented_for("undirected") -@nx._dispatchable -def triad_type(G): - """Returns the sociological triad type for a triad. - - Parameters - ---------- - G : digraph - A NetworkX DiGraph with 3 nodes - - Returns - ------- - triad_type : str - A string identifying the triad type - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - >>> nx.triad_type(G) - '030C' - >>> G.add_edge(1, 3) - >>> nx.triad_type(G) - '120C' - - Notes - ----- - There can be 6 unique edges in a triad (order-3 DiGraph) (so 2^^6=64 unique - triads given 3 nodes). These 64 triads each display exactly 1 of 16 - topologies of triads (topologies can be permuted). These topologies are - identified by the following notation: - - {m}{a}{n}{type} (for example: 111D, 210, 102) - - Here: - - {m} = number of mutual ties (takes 0, 1, 2, 3); a mutual tie is (0,1) - AND (1,0) - {a} = number of asymmetric ties (takes 0, 1, 2, 3); an asymmetric tie - is (0,1) BUT NOT (1,0) or vice versa - {n} = number of null ties (takes 0, 1, 2, 3); a null tie is NEITHER - (0,1) NOR (1,0) - {type} = a letter (takes U, D, C, T) corresponding to up, down, cyclical - and transitive. This is only used for topologies that can have - more than one form (eg: 021D and 021U). - - References - ---------- - .. [1] Snijders, T. (2012). "Transitivity and triads." University of - Oxford. - https://web.archive.org/web/20170830032057/http://www.stats.ox.ac.uk/~snijders/Trans_Triads_ha.pdf - """ - if not is_triad(G): - raise nx.NetworkXAlgorithmError("G is not a triad (order-3 DiGraph)") - num_edges = len(G.edges()) - if num_edges == 0: - return "003" - elif num_edges == 1: - return "012" - elif num_edges == 2: - e1, e2 = G.edges() - if set(e1) == set(e2): - return "102" - elif e1[0] == e2[0]: - return "021D" - elif e1[1] == e2[1]: - return "021U" - elif e1[1] == e2[0] or e2[1] == e1[0]: - return "021C" - elif num_edges == 3: - for e1, e2, e3 in permutations(G.edges(), 3): - if set(e1) == set(e2): - if e3[0] in e1: - return "111U" - # e3[1] in e1: - return "111D" - elif set(e1).symmetric_difference(set(e2)) == set(e3): - if {e1[0], e2[0], e3[0]} == {e1[0], e2[0], e3[0]} == set(G.nodes()): - return "030C" - # e3 == (e1[0], e2[1]) and e2 == (e1[1], e3[1]): - return "030T" - elif num_edges == 4: - for e1, e2, e3, e4 in permutations(G.edges(), 4): - if set(e1) == set(e2): - # identify pair of symmetric edges (which necessarily exists) - if set(e3) == set(e4): - return "201" - if {e3[0]} == {e4[0]} == set(e3).intersection(set(e4)): - return "120D" - if {e3[1]} == {e4[1]} == set(e3).intersection(set(e4)): - return "120U" - if e3[1] == e4[0]: - return "120C" - elif num_edges == 5: - return "210" - elif num_edges == 6: - return "300" - - -@not_implemented_for("undirected") -@py_random_state(1) -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def random_triad(G, seed=None): - """Returns a random triad from a directed graph. - - .. deprecated:: 3.3 - - random_triad is deprecated and will be removed in version 3.5. - Use random sampling directly instead:: - - G.subgraph(random.sample(list(G), 3)) - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G2 : subgraph - A randomly selected triad (order-3 NetworkX DiGraph) - - Raises - ------ - NetworkXError - If the input Graph has less than 3 nodes. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 1), (5, 6), (5, 4), (6, 7)]) - >>> triad = nx.random_triad(G, seed=1) - >>> triad.edges - OutEdgeView([(1, 2)]) - - """ - import warnings - - warnings.warn( - ( - "\n\nrandom_triad is deprecated and will be removed in NetworkX v3.5.\n" - "Use random.sample instead, e.g.::\n\n" - "\tG.subgraph(random.sample(list(G), 3))\n" - ), - category=DeprecationWarning, - stacklevel=5, - ) - if len(G) < 3: - raise nx.NetworkXError( - f"G needs at least 3 nodes to form a triad; (it has {len(G)} nodes)" - ) - nodes = seed.sample(list(G.nodes()), 3) - G2 = G.subgraph(nodes) - return G2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/vitality.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/vitality.py deleted file mode 100644 index bf4b016..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/vitality.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Vitality measures. -""" - -from functools import partial - -import networkx as nx - -__all__ = ["closeness_vitality"] - - -@nx._dispatchable(edge_attrs="weight") -def closeness_vitality(G, node=None, weight=None, wiener_index=None): - """Returns the closeness vitality for nodes in the graph. - - The *closeness vitality* of a node, defined in Section 3.6.2 of [1], - is the change in the sum of distances between all node pairs when - excluding that node. - - Parameters - ---------- - G : NetworkX graph - A strongly-connected graph. - - weight : string - The name of the edge attribute used as weight. This is passed - directly to the :func:`~networkx.wiener_index` function. - - node : object - If specified, only the closeness vitality for this node will be - returned. Otherwise, a dictionary mapping each node to its - closeness vitality will be returned. - - Other parameters - ---------------- - wiener_index : number - If you have already computed the Wiener index of the graph - `G`, you can provide that value here. Otherwise, it will be - computed for you. - - Returns - ------- - dictionary or float - If `node` is None, this function returns a dictionary - with nodes as keys and closeness vitality as the - value. Otherwise, it returns only the closeness vitality for the - specified `node`. - - The closeness vitality of a node may be negative infinity if - removing that node would disconnect the graph. - - Examples - -------- - >>> G = nx.cycle_graph(3) - >>> nx.closeness_vitality(G) - {0: 2.0, 1: 2.0, 2: 2.0} - - See Also - -------- - closeness_centrality - - References - ---------- - .. [1] Ulrik Brandes, Thomas Erlebach (eds.). - *Network Analysis: Methodological Foundations*. - Springer, 2005. - - - """ - if wiener_index is None: - wiener_index = nx.wiener_index(G, weight=weight) - if node is not None: - after = nx.wiener_index(G.subgraph(set(G) - {node}), weight=weight) - return wiener_index - after - vitality = partial(closeness_vitality, G, weight=weight, wiener_index=wiener_index) - return {v: vitality(node=v) for v in G} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/voronoi.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/voronoi.py deleted file mode 100644 index 609a68d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/voronoi.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Functions for computing the Voronoi cells of a graph.""" - -import networkx as nx -from networkx.utils import groups - -__all__ = ["voronoi_cells"] - - -@nx._dispatchable(edge_attrs="weight") -def voronoi_cells(G, center_nodes, weight="weight"): - """Returns the Voronoi cells centered at `center_nodes` with respect - to the shortest-path distance metric. - - If $C$ is a set of nodes in the graph and $c$ is an element of $C$, - the *Voronoi cell* centered at a node $c$ is the set of all nodes - $v$ that are closer to $c$ than to any other center node in $C$ with - respect to the shortest-path distance metric. [1]_ - - For directed graphs, this will compute the "outward" Voronoi cells, - as defined in [1]_, in which distance is measured from the center - nodes to the target node. For the "inward" Voronoi cells, use the - :meth:`DiGraph.reverse` method to reverse the orientation of the - edges before invoking this function on the directed graph. - - Parameters - ---------- - G : NetworkX graph - - center_nodes : set - A nonempty set of nodes in the graph `G` that represent the - center of the Voronoi cells. - - weight : string or function - The edge attribute (or an arbitrary function) representing the - weight of an edge. This keyword argument is as described in the - documentation for :func:`~networkx.multi_source_dijkstra_path`, - for example. - - Returns - ------- - dictionary - A mapping from center node to set of all nodes in the graph - closer to that center node than to any other center node. The - keys of the dictionary are the element of `center_nodes`, and - the values of the dictionary form a partition of the nodes of - `G`. - - Examples - -------- - To get only the partition of the graph induced by the Voronoi cells, - take the collection of all values in the returned dictionary:: - - >>> G = nx.path_graph(6) - >>> center_nodes = {0, 3} - >>> cells = nx.voronoi_cells(G, center_nodes) - >>> partition = set(map(frozenset, cells.values())) - >>> sorted(map(sorted, partition)) - [[0, 1], [2, 3, 4, 5]] - - Raises - ------ - ValueError - If `center_nodes` is empty. - - References - ---------- - .. [1] Erwig, Martin. (2000),"The graph Voronoi diagram with applications." - *Networks*, 36: 156--163. - https://doi.org/10.1002/1097-0037(200010)36:3<156::AID-NET2>3.0.CO;2-L - - """ - # Determine the shortest paths from any one of the center nodes to - # every node in the graph. - # - # This raises `ValueError` if `center_nodes` is an empty set. - paths = nx.multi_source_dijkstra_path(G, center_nodes, weight=weight) - # Determine the center node from which the shortest path originates. - nearest = {v: p[0] for v, p in paths.items()} - # Get the mapping from center node to all nodes closer to it than to - # any other center node. - cells = groups(nearest) - # We collect all unreachable nodes under a special key, if there are any. - unreachable = set(G) - set(nearest) - if unreachable: - cells["unreachable"] = unreachable - return cells diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/walks.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/walks.py deleted file mode 100644 index 0ef9dac..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/walks.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Function for computing walks in a graph.""" - -import networkx as nx - -__all__ = ["number_of_walks"] - - -@nx._dispatchable -def number_of_walks(G, walk_length): - """Returns the number of walks connecting each pair of nodes in `G` - - A *walk* is a sequence of nodes in which each adjacent pair of nodes - in the sequence is adjacent in the graph. A walk can repeat the same - edge and go in the opposite direction just as people can walk on a - set of paths, but standing still is not counted as part of the walk. - - This function only counts the walks with `walk_length` edges. Note that - the number of nodes in the walk sequence is one more than `walk_length`. - The number of walks can grow very quickly on a larger graph - and with a larger walk length. - - Parameters - ---------- - G : NetworkX graph - - walk_length : int - A nonnegative integer representing the length of a walk. - - Returns - ------- - dict - A dictionary of dictionaries in which outer keys are source - nodes, inner keys are target nodes, and inner values are the - number of walks of length `walk_length` connecting those nodes. - - Raises - ------ - ValueError - If `walk_length` is negative - - Examples - -------- - - >>> G = nx.Graph([(0, 1), (1, 2)]) - >>> walks = nx.number_of_walks(G, 2) - >>> walks - {0: {0: 1, 1: 0, 2: 1}, 1: {0: 0, 1: 2, 2: 0}, 2: {0: 1, 1: 0, 2: 1}} - >>> total_walks = sum(sum(tgts.values()) for _, tgts in walks.items()) - - You can also get the number of walks from a specific source node using the - returned dictionary. For example, number of walks of length 1 from node 0 - can be found as follows: - - >>> walks = nx.number_of_walks(G, 1) - >>> walks[0] - {0: 0, 1: 1, 2: 0} - >>> sum(walks[0].values()) # walks from 0 of length 1 - 1 - - Similarly, a target node can also be specified: - - >>> walks[0][1] - 1 - - """ - import numpy as np - - if walk_length < 0: - raise ValueError(f"`walk_length` cannot be negative: {walk_length}") - - A = nx.adjacency_matrix(G, weight=None) - # TODO: Use matrix_power from scipy.sparse when available - # power = sp.sparse.linalg.matrix_power(A, walk_length) - power = np.linalg.matrix_power(A.toarray(), walk_length) - result = { - u: {v: power.item(u_idx, v_idx) for v_idx, v in enumerate(G)} - for u_idx, u in enumerate(G) - } - return result diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/wiener.py b/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/wiener.py deleted file mode 100644 index ac3abe4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/algorithms/wiener.py +++ /dev/null @@ -1,226 +0,0 @@ -"""Functions related to the Wiener Index of a graph. - -The Wiener Index is a topological measure of a graph -related to the distance between nodes and their degree. -The Schultz Index and Gutman Index are similar measures. -They are used categorize molecules via the network of -atoms connected by chemical bonds. The indices are -correlated with functional aspects of the molecules. - -References ----------- -.. [1] `Wikipedia: Wiener Index `_ -.. [2] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, - Croatica Chemica Acta, 71 (1998), 21-51. - https://hrcak.srce.hr/132323 -""" - -import itertools as it - -import networkx as nx - -__all__ = ["wiener_index", "schultz_index", "gutman_index"] - - -@nx._dispatchable(edge_attrs="weight") -def wiener_index(G, weight=None): - """Returns the Wiener index of the given graph. - - The *Wiener index* of a graph is the sum of the shortest-path - (weighted) distances between each pair of reachable nodes. - For pairs of nodes in undirected graphs, only one orientation - of the pair is counted. - - Parameters - ---------- - G : NetworkX graph - - weight : string or None, optional (default: None) - If None, every edge has weight 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - The edge weights are used to computing shortest-path distances. - - Returns - ------- - number - The Wiener index of the graph `G`. - - Raises - ------ - NetworkXError - If the graph `G` is not connected. - - Notes - ----- - If a pair of nodes is not reachable, the distance is assumed to be - infinity. This means that for graphs that are not - strongly-connected, this function returns ``inf``. - - The Wiener index is not usually defined for directed graphs, however - this function uses the natural generalization of the Wiener index to - directed graphs. - - Examples - -------- - The Wiener index of the (unweighted) complete graph on *n* nodes - equals the number of pairs of the *n* nodes, since each pair of - nodes is at distance one:: - - >>> n = 10 - >>> G = nx.complete_graph(n) - >>> nx.wiener_index(G) == n * (n - 1) / 2 - True - - Graphs that are not strongly-connected have infinite Wiener index:: - - >>> G = nx.empty_graph(2) - >>> nx.wiener_index(G) - inf - - References - ---------- - .. [1] `Wikipedia: Wiener Index `_ - """ - connected = nx.is_strongly_connected(G) if G.is_directed() else nx.is_connected(G) - if not connected: - return float("inf") - - spl = nx.shortest_path_length(G, weight=weight) - total = sum(it.chain.from_iterable(nbrs.values() for node, nbrs in spl)) - # Need to account for double counting pairs of nodes in undirected graphs. - return total if G.is_directed() else total / 2 - - -@nx.utils.not_implemented_for("directed") -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def schultz_index(G, weight=None): - r"""Returns the Schultz Index (of the first kind) of `G` - - The *Schultz Index* [3]_ of a graph is the sum over all node pairs of - distances times the sum of degrees. Consider an undirected graph `G`. - For each node pair ``(u, v)`` compute ``dist(u, v) * (deg(u) + deg(v)`` - where ``dist`` is the shortest path length between two nodes and ``deg`` - is the degree of a node. - - The Schultz Index is the sum of these quantities over all (unordered) - pairs of nodes. - - Parameters - ---------- - G : NetworkX graph - The undirected graph of interest. - weight : string or None, optional (default: None) - If None, every edge has weight 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - The edge weights are used to computing shortest-path distances. - - Returns - ------- - number - The first kind of Schultz Index of the graph `G`. - - Examples - -------- - The Schultz Index of the (unweighted) complete graph on *n* nodes - equals the number of pairs of the *n* nodes times ``2 * (n - 1)``, - since each pair of nodes is at distance one and the sum of degree - of two nodes is ``2 * (n - 1)``. - - >>> n = 10 - >>> G = nx.complete_graph(n) - >>> nx.schultz_index(G) == (n * (n - 1) / 2) * (2 * (n - 1)) - True - - Graph that is disconnected - - >>> nx.schultz_index(nx.empty_graph(2)) - inf - - References - ---------- - .. [1] I. Gutman, Selected properties of the Schultz molecular topological index, - J. Chem. Inf. Comput. Sci. 34 (1994), 1087–1089. - https://doi.org/10.1021/ci00021a009 - .. [2] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, - Croatica Chemica Acta, 71 (1998), 21-51. - https://hrcak.srce.hr/132323 - .. [3] H. P. Schultz, Topological organic chemistry. 1. - Graph theory and topological indices of alkanes,i - J. Chem. Inf. Comput. Sci. 29 (1989), 239–257. - - """ - if not nx.is_connected(G): - return float("inf") - - spl = nx.shortest_path_length(G, weight=weight) - d = dict(G.degree, weight=weight) - return sum(dist * (d[u] + d[v]) for u, info in spl for v, dist in info.items()) / 2 - - -@nx.utils.not_implemented_for("directed") -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def gutman_index(G, weight=None): - r"""Returns the Gutman Index for the graph `G`. - - The *Gutman Index* measures the topology of networks, especially for molecule - networks of atoms connected by bonds [1]_. It is also called the Schultz Index - of the second kind [2]_. - - Consider an undirected graph `G` with node set ``V``. - The Gutman Index of a graph is the sum over all (unordered) pairs of nodes - of nodes ``(u, v)``, with distance ``dist(u, v)`` and degrees ``deg(u)`` - and ``deg(v)``, of ``dist(u, v) * deg(u) * deg(v)`` - - Parameters - ---------- - G : NetworkX graph - - weight : string or None, optional (default: None) - If None, every edge has weight 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - The edge weights are used to computing shortest-path distances. - - Returns - ------- - number - The Gutman Index of the graph `G`. - - Examples - -------- - The Gutman Index of the (unweighted) complete graph on *n* nodes - equals the number of pairs of the *n* nodes times ``(n - 1) * (n - 1)``, - since each pair of nodes is at distance one and the product of degree of two - vertices is ``(n - 1) * (n - 1)``. - - >>> n = 10 - >>> G = nx.complete_graph(n) - >>> nx.gutman_index(G) == (n * (n - 1) / 2) * ((n - 1) * (n - 1)) - True - - Graphs that are disconnected - - >>> G = nx.empty_graph(2) - >>> nx.gutman_index(G) - inf - - References - ---------- - .. [1] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, - Croatica Chemica Acta, 71 (1998), 21-51. - https://hrcak.srce.hr/132323 - .. [2] I. Gutman, Selected properties of the Schultz molecular topological index, - J. Chem. Inf. Comput. Sci. 34 (1994), 1087–1089. - https://doi.org/10.1021/ci00021a009 - - """ - if not nx.is_connected(G): - return float("inf") - - spl = nx.shortest_path_length(G, weight=weight) - d = dict(G.degree, weight=weight) - return sum(dist * d[u] * d[v] for u, vinfo in spl for v, dist in vinfo.items()) / 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/__init__.py deleted file mode 100644 index 721fa8b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .graph import Graph -from .digraph import DiGraph -from .multigraph import MultiGraph -from .multidigraph import MultiDiGraph - -from .function import * -from .graphviews import subgraph_view, reverse_view - -from networkx.classes import filters - -from networkx.classes import coreviews -from networkx.classes import graphviews -from networkx.classes import reportviews diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/coreviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/coreviews.py deleted file mode 100644 index a6e8521..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/coreviews.py +++ /dev/null @@ -1,431 +0,0 @@ -"""Views of core data structures such as nested Mappings (e.g. dict-of-dicts). -These ``Views`` often restrict element access, with either the entire view or -layers of nested mappings being read-only. -""" - -from collections.abc import Mapping - -__all__ = [ - "AtlasView", - "AdjacencyView", - "MultiAdjacencyView", - "UnionAtlas", - "UnionAdjacency", - "UnionMultiInner", - "UnionMultiAdjacency", - "FilterAtlas", - "FilterAdjacency", - "FilterMultiInner", - "FilterMultiAdjacency", -] - - -class AtlasView(Mapping): - """An AtlasView is a Read-only Mapping of Mappings. - - It is a View into a dict-of-dict data structure. - The inner level of dict is read-write. But the - outer level is read-only. - - See Also - ======== - AdjacencyView: View into dict-of-dict-of-dict - MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict - """ - - __slots__ = ("_atlas",) - - def __getstate__(self): - return {"_atlas": self._atlas} - - def __setstate__(self, state): - self._atlas = state["_atlas"] - - def __init__(self, d): - self._atlas = d - - def __len__(self): - return len(self._atlas) - - def __iter__(self): - return iter(self._atlas) - - def __getitem__(self, key): - return self._atlas[key] - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - def __str__(self): - return str(self._atlas) # {nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return f"{self.__class__.__name__}({self._atlas!r})" - - -class AdjacencyView(AtlasView): - """An AdjacencyView is a Read-only Map of Maps of Maps. - - It is a View into a dict-of-dict-of-dict data structure. - The inner level of dict is read-write. But the - outer levels are read-only. - - See Also - ======== - AtlasView: View into dict-of-dict - MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict - """ - - __slots__ = () # Still uses AtlasView slots names _atlas - - def __getitem__(self, name): - return AtlasView(self._atlas[name]) - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - -class MultiAdjacencyView(AdjacencyView): - """An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps. - - It is a View into a dict-of-dict-of-dict-of-dict data structure. - The inner level of dict is read-write. But the - outer levels are read-only. - - See Also - ======== - AtlasView: View into dict-of-dict - AdjacencyView: View into dict-of-dict-of-dict - """ - - __slots__ = () # Still uses AtlasView slots names _atlas - - def __getitem__(self, name): - return AdjacencyView(self._atlas[name]) - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - -class UnionAtlas(Mapping): - """A read-only union of two atlases (dict-of-dict). - - The two dict-of-dicts represent the inner dict of - an Adjacency: `G.succ[node]` and `G.pred[node]`. - The inner level of dict of both hold attribute key:value - pairs and is read-write. But the outer level is read-only. - - See Also - ======== - UnionAdjacency: View into dict-of-dict-of-dict - UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict - """ - - __slots__ = ("_succ", "_pred") - - def __getstate__(self): - return {"_succ": self._succ, "_pred": self._pred} - - def __setstate__(self, state): - self._succ = state["_succ"] - self._pred = state["_pred"] - - def __init__(self, succ, pred): - self._succ = succ - self._pred = pred - - def __len__(self): - return len(self._succ.keys() | self._pred.keys()) - - def __iter__(self): - return iter(set(self._succ.keys()) | set(self._pred.keys())) - - def __getitem__(self, key): - try: - return self._succ[key] - except KeyError: - return self._pred[key] - - def copy(self): - result = {nbr: dd.copy() for nbr, dd in self._succ.items()} - for nbr, dd in self._pred.items(): - if nbr in result: - result[nbr].update(dd) - else: - result[nbr] = dd.copy() - return result - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})" - - -class UnionAdjacency(Mapping): - """A read-only union of dict Adjacencies as a Map of Maps of Maps. - - The two input dict-of-dict-of-dicts represent the union of - `G.succ` and `G.pred`. Return values are UnionAtlas - The inner level of dict is read-write. But the - middle and outer levels are read-only. - - succ : a dict-of-dict-of-dict {node: nbrdict} - pred : a dict-of-dict-of-dict {node: nbrdict} - The keys for the two dicts should be the same - - See Also - ======== - UnionAtlas: View into dict-of-dict - UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict - """ - - __slots__ = ("_succ", "_pred") - - def __getstate__(self): - return {"_succ": self._succ, "_pred": self._pred} - - def __setstate__(self, state): - self._succ = state["_succ"] - self._pred = state["_pred"] - - def __init__(self, succ, pred): - # keys must be the same for two input dicts - assert len(set(succ.keys()) ^ set(pred.keys())) == 0 - self._succ = succ - self._pred = pred - - def __len__(self): - return len(self._succ) # length of each dict should be the same - - def __iter__(self): - return iter(self._succ) - - def __getitem__(self, nbr): - return UnionAtlas(self._succ[nbr], self._pred[nbr]) - - def copy(self): - return {n: self[n].copy() for n in self._succ} - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})" - - -class UnionMultiInner(UnionAtlas): - """A read-only union of two inner dicts of MultiAdjacencies. - - The two input dict-of-dict-of-dicts represent the union of - `G.succ[node]` and `G.pred[node]` for MultiDiGraphs. - Return values are UnionAtlas. - The inner level of dict is read-write. But the outer levels are read-only. - - See Also - ======== - UnionAtlas: View into dict-of-dict - UnionAdjacency: View into dict-of-dict-of-dict - UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict - """ - - __slots__ = () # Still uses UnionAtlas slots names _succ, _pred - - def __getitem__(self, node): - in_succ = node in self._succ - in_pred = node in self._pred - if in_succ: - if in_pred: - return UnionAtlas(self._succ[node], self._pred[node]) - return UnionAtlas(self._succ[node], {}) - return UnionAtlas({}, self._pred[node]) - - def copy(self): - nodes = set(self._succ.keys()) | set(self._pred.keys()) - return {n: self[n].copy() for n in nodes} - - -class UnionMultiAdjacency(UnionAdjacency): - """A read-only union of two dict MultiAdjacencies. - - The two input dict-of-dict-of-dict-of-dicts represent the union of - `G.succ` and `G.pred` for MultiDiGraphs. Return values are UnionAdjacency. - The inner level of dict is read-write. But the outer levels are read-only. - - See Also - ======== - UnionAtlas: View into dict-of-dict - UnionMultiInner: View into dict-of-dict-of-dict - """ - - __slots__ = () # Still uses UnionAdjacency slots names _succ, _pred - - def __getitem__(self, node): - return UnionMultiInner(self._succ[node], self._pred[node]) - - -class FilterAtlas(Mapping): # nodedict, nbrdict, keydict - """A read-only Mapping of Mappings with filtering criteria for nodes. - - It is a view into a dict-of-dict data structure, and it selects only - nodes that meet the criteria defined by ``NODE_OK``. - - See Also - ======== - FilterAdjacency - FilterMultiInner - FilterMultiAdjacency - """ - - def __init__(self, d, NODE_OK): - self._atlas = d - self.NODE_OK = NODE_OK - - def __len__(self): - # check whether NODE_OK stores the number of nodes as `length` - # or the nodes themselves as a set `nodes`. If not, count the nodes. - if hasattr(self.NODE_OK, "length"): - return self.NODE_OK.length - if hasattr(self.NODE_OK, "nodes"): - return len(self.NODE_OK.nodes & self._atlas.keys()) - return sum(1 for n in self._atlas if self.NODE_OK(n)) - - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return (n for n in self.NODE_OK.nodes if n in self._atlas) - return (n for n in self._atlas if self.NODE_OK(n)) - - def __getitem__(self, key): - if key in self._atlas and self.NODE_OK(key): - return self._atlas[key] - raise KeyError(f"Key {key} not found") - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return f"{self.__class__.__name__}({self._atlas!r}, {self.NODE_OK!r})" - - -class FilterAdjacency(Mapping): # edgedict - """A read-only Mapping of Mappings with filtering criteria for nodes and edges. - - It is a view into a dict-of-dict-of-dict data structure, and it selects nodes - and edges that satisfy specific criteria defined by ``NODE_OK`` and ``EDGE_OK``, - respectively. - - See Also - ======== - FilterAtlas - FilterMultiInner - FilterMultiAdjacency - """ - - def __init__(self, d, NODE_OK, EDGE_OK): - self._atlas = d - self.NODE_OK = NODE_OK - self.EDGE_OK = EDGE_OK - - def __len__(self): - # check whether NODE_OK stores the number of nodes as `length` - # or the nodes themselves as a set `nodes`. If not, count the nodes. - if hasattr(self.NODE_OK, "length"): - return self.NODE_OK.length - if hasattr(self.NODE_OK, "nodes"): - return len(self.NODE_OK.nodes & self._atlas.keys()) - return sum(1 for n in self._atlas if self.NODE_OK(n)) - - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return (n for n in self.NODE_OK.nodes if n in self._atlas) - return (n for n in self._atlas if self.NODE_OK(n)) - - def __getitem__(self, node): - if node in self._atlas and self.NODE_OK(node): - - def new_node_ok(nbr): - return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr) - - return FilterAtlas(self._atlas[node], new_node_ok) - raise KeyError(f"Key {node} not found") - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - name = self.__class__.__name__ - return f"{name}({self._atlas!r}, {self.NODE_OK!r}, {self.EDGE_OK!r})" - - -class FilterMultiInner(FilterAdjacency): # muliedge_seconddict - """A read-only Mapping of Mappings with filtering criteria for nodes and edges. - - It is a view into a dict-of-dict-of-dict-of-dict data structure, and it selects nodes - and edges that meet specific criteria defined by ``NODE_OK`` and ``EDGE_OK``. - - See Also - ======== - FilterAtlas - FilterAdjacency - FilterMultiAdjacency - """ - - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - my_nodes = (n for n in self.NODE_OK.nodes if n in self._atlas) - else: - my_nodes = (n for n in self._atlas if self.NODE_OK(n)) - for n in my_nodes: - some_keys_ok = False - for key in self._atlas[n]: - if self.EDGE_OK(n, key): - some_keys_ok = True - break - if some_keys_ok is True: - yield n - - def __getitem__(self, nbr): - if nbr in self._atlas and self.NODE_OK(nbr): - - def new_node_ok(key): - return self.EDGE_OK(nbr, key) - - return FilterAtlas(self._atlas[nbr], new_node_ok) - raise KeyError(f"Key {nbr} not found") - - -class FilterMultiAdjacency(FilterAdjacency): # multiedgedict - """A read-only Mapping of Mappings with filtering criteria - for nodes and edges. - - It is a view into a dict-of-dict-of-dict-of-dict data structure, - and it selects nodes and edges that satisfy specific criteria - defined by ``NODE_OK`` and ``EDGE_OK``, respectively. - - See Also - ======== - FilterAtlas - FilterAdjacency - FilterMultiInner - """ - - def __getitem__(self, node): - if node in self._atlas and self.NODE_OK(node): - - def edge_ok(nbr, key): - return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key) - - return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok) - raise KeyError(f"Key {node} not found") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/digraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/digraph.py deleted file mode 100644 index 2ba56de..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/digraph.py +++ /dev/null @@ -1,1352 +0,0 @@ -"""Base class for directed graphs.""" - -from copy import deepcopy -from functools import cached_property - -import networkx as nx -from networkx import convert -from networkx.classes.coreviews import AdjacencyView -from networkx.classes.graph import Graph -from networkx.classes.reportviews import ( - DiDegreeView, - InDegreeView, - InEdgeView, - OutDegreeView, - OutEdgeView, -) -from networkx.exception import NetworkXError - -__all__ = ["DiGraph"] - - -class _CachedPropertyResetterAdjAndSucc: - """Data Descriptor class that syncs and resets cached properties adj and succ - - The cached properties `adj` and `succ` are reset whenever `_adj` or `_succ` - are set to new objects. In addition, the attributes `_succ` and `_adj` - are synced so these two names point to the same object. - - Warning: most of the time, when ``G._adj`` is set, ``G._pred`` should also - be set to maintain a valid data structure. They share datadicts. - - This object sits on a class and ensures that any instance of that - class clears its cached properties "succ" and "adj" whenever the - underlying instance attributes "_succ" or "_adj" are set to a new object. - It only affects the set process of the obj._adj and obj._succ attribute. - All get/del operations act as they normally would. - - For info on Data Descriptors see: https://docs.python.org/3/howto/descriptor.html - """ - - def __set__(self, obj, value): - od = obj.__dict__ - od["_adj"] = value - od["_succ"] = value - # reset cached properties - props = [ - "adj", - "succ", - "edges", - "out_edges", - "degree", - "out_degree", - "in_degree", - ] - for prop in props: - if prop in od: - del od[prop] - - -class _CachedPropertyResetterPred: - """Data Descriptor class for _pred that resets ``pred`` cached_property when needed - - This assumes that the ``cached_property`` ``G.pred`` should be reset whenever - ``G._pred`` is set to a new value. - - Warning: most of the time, when ``G._pred`` is set, ``G._adj`` should also - be set to maintain a valid data structure. They share datadicts. - - This object sits on a class and ensures that any instance of that - class clears its cached property "pred" whenever the underlying - instance attribute "_pred" is set to a new object. It only affects - the set process of the obj._pred attribute. All get/del operations - act as they normally would. - - For info on Data Descriptors see: https://docs.python.org/3/howto/descriptor.html - """ - - def __set__(self, obj, value): - od = obj.__dict__ - od["_pred"] = value - # reset cached properties - props = ["pred", "in_edges", "degree", "out_degree", "in_degree"] - for prop in props: - if prop in od: - del od[prop] - - -class DiGraph(Graph): - """ - Base class for directed graphs. - - A DiGraph stores nodes and edges with optional data, or attributes. - - DiGraphs hold directed edges. Self loops are allowed but multiple - (parallel) edges are not. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, 2D NumPy array, SciPy - sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - MultiGraph - MultiDiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.DiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> G.add_edge(1, 2) - - a list of edges, - - >>> G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. There are no errors when adding - nodes or edges that already exist. - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.DiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time="5pm") - >>> G.add_nodes_from([3], time="2pm") - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]["room"] = 714 - >>> del G.nodes[1]["room"] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> G.add_edge(1, 2, weight=4.7) - >>> G.add_edges_from([(3, 4), (4, 5)], color="red") - >>> G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})]) - >>> G[1][2]["weight"] = 4.7 - >>> G.edges[1, 2]["weight"] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, 2]` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, eattr in nbrsdict.items(): - ... if "weight" in eattr: - ... # Do something useful with the edges - ... pass - - But the edges reporting object is often more convenient: - - >>> for u, v, weight in G.edges(data="weight"): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using object-attributes and methods. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes`, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n]`, `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The Graph class uses a dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge data keyed by neighbor. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these three dicts can be replaced in a subclass by a user defined - dict-like object. In general, the dict-like features should be - maintained but extra features can be added. To replace one of the - dicts create a new graph class by changing the class(!) variable - holding the factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, optional (default: dict) - Factory function to be used to create the adjacency list - dict which holds edge data keyed by neighbor. - It should require no arguments and return a dict-like object - - edge_attr_dict_factory : function, optional (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - **Subclassing Example** - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {"weight": 1} - ... - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - """ - - _adj = _CachedPropertyResetterAdjAndSucc() # type: ignore[assignment] - _succ = _adj # type: ignore[has-type] - _pred = _CachedPropertyResetterPred() - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a 2D NumPy array, a - SciPy sparse array, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name="my graph") - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes - self._node = self.node_dict_factory() # dictionary for node attr - # We store two adjacency lists: - # the predecessors of node n are stored in the dict self._pred - # the successors of node n are stored in the dict self._succ=self._adj - self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict successor - self._pred = self.adjlist_outer_dict_factory() # predecessor - # Note: self._succ = self._adj # successor - - self.__networkx_cache__ = {} - # attempt to load graph with data - if incoming_graph_data is not None: - convert.to_networkx_graph(incoming_graph_data, create_using=self) - # load graph attributes (must be after convert) - self.graph.update(attr) - - @cached_property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return AdjacencyView(self._succ) - - @cached_property - def succ(self): - """Graph adjacency object holding the successors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.succ[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.succ behaves like a dict. Useful idioms include - `for nbr, datadict in G.succ[n].items():`. A data-view not provided - by dicts also exists: `for nbr, foovalue in G.succ[node].data('foo'):` - and a default can be set via a `default` argument to the `data` method. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` is identical to `G.succ`. - """ - return AdjacencyView(self._succ) - - @cached_property - def pred(self): - """Graph adjacency object holding the predecessors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.pred[2][3]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.pred behaves like a dict. Useful idioms include - `for nbr, datadict in G.pred[n].items():`. A data-view not provided - by dicts also exists: `for nbr, foovalue in G.pred[node].data('foo'):` - A default can be set via a `default` argument to the `data` method. - """ - return AdjacencyView(self._pred) - - def add_node(self, node_for_adding, **attr): - """Add a single node `node_for_adding` and update node attributes. - - Parameters - ---------- - node_for_adding : node - A node can be any hashable Python object except None. - attr : keyword arguments, optional - Set or change node attributes using key=value. - - See Also - -------- - add_nodes_from - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_node(1) - >>> G.add_node("Hello") - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_node(K3) - >>> G.number_of_nodes() - 3 - - Use keywords set/change node attributes: - - >>> G.add_node(1, size=10) - >>> G.add_node(3, weight=0.4, UTM=("13S", 382871, 3972649)) - - Notes - ----- - A hashable object is one that can be used as a key in a Python - dictionary. This includes strings, numbers, tuples of strings - and numbers, etc. - - On many platforms hashable items also include mutables such as - NetworkX Graphs, though one should be careful that the hash - doesn't change on mutables. - """ - if node_for_adding not in self._succ: - if node_for_adding is None: - raise ValueError("None cannot be a node") - self._succ[node_for_adding] = self.adjlist_inner_dict_factory() - self._pred[node_for_adding] = self.adjlist_inner_dict_factory() - attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: # update attr even if node already exists - self._node[node_for_adding].update(attr) - nx._clear_cache(self) - - def add_nodes_from(self, nodes_for_adding, **attr): - """Add multiple nodes. - - Parameters - ---------- - nodes_for_adding : iterable container - A container of nodes (list, dict, set, etc.). - OR - A container of (node, attribute dict) tuples. - Node attributes are updated using the attribute dict. - attr : keyword arguments, optional (default= no attributes) - Update attributes for all nodes in nodes. - Node attributes specified in nodes as a tuple take - precedence over attributes specified via keyword arguments. - - See Also - -------- - add_node - - Notes - ----- - When adding nodes from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_nodes)`, and pass this - object to `G.add_nodes_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_nodes_from("Hello") - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_nodes_from(K3) - >>> sorted(G.nodes(), key=str) - [0, 1, 2, 'H', 'e', 'l', 'o'] - - Use keywords to update specific node attributes for every node. - - >>> G.add_nodes_from([1, 2], size=10) - >>> G.add_nodes_from([3, 4], weight=0.4) - - Use (node, attrdict) tuples to update attributes for specific nodes. - - >>> G.add_nodes_from([(1, dict(size=11)), (2, {"color": "blue"})]) - >>> G.nodes[1]["size"] - 11 - >>> H = nx.Graph() - >>> H.add_nodes_from(G.nodes(data=True)) - >>> H.nodes[1]["size"] - 11 - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.DiGraph([(0, 1), (1, 2), (3, 4)]) - >>> # wrong way - will raise RuntimeError - >>> # G.add_nodes_from(n + 1 for n in G.nodes) - >>> # correct way - >>> G.add_nodes_from(list(n + 1 for n in G.nodes)) - """ - for n in nodes_for_adding: - try: - newnode = n not in self._node - newdict = attr - except TypeError: - n, ndict = n - newnode = n not in self._node - newdict = attr.copy() - newdict.update(ndict) - if newnode: - if n is None: - raise ValueError("None cannot be a node") - self._succ[n] = self.adjlist_inner_dict_factory() - self._pred[n] = self.adjlist_inner_dict_factory() - self._node[n] = self.node_attr_dict_factory() - self._node[n].update(newdict) - nx._clear_cache(self) - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges. - Attempting to remove a nonexistent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------ - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> list(G.edges) - [(0, 1), (1, 2)] - >>> G.remove_node(1) - >>> list(G.edges) - [] - - """ - try: - nbrs = self._succ[n] - del self._node[n] - except KeyError as err: # NetworkXError if n not in self - raise NetworkXError(f"The node {n} is not in the digraph.") from err - for u in nbrs: - del self._pred[u][n] # remove all edges n-u in digraph - del self._succ[n] # remove node from succ - for u in self._pred[n]: - del self._succ[u][n] # remove all edges n-u in digraph - del self._pred[n] # remove node from pred - nx._clear_cache(self) - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently ignored. - - See Also - -------- - remove_node - - Notes - ----- - When removing nodes from an iterator over the graph you are changing, - a `RuntimeError` will be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_nodes)`, and pass this - object to `G.remove_nodes_from`. - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = list(G.nodes) - >>> e - [0, 1, 2] - >>> G.remove_nodes_from(e) - >>> list(G.nodes) - [] - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.DiGraph([(0, 1), (1, 2), (3, 4)]) - >>> # this command will fail, as the graph's dict is modified during iteration - >>> # G.remove_nodes_from(n for n in G.nodes if n < 2) - >>> # this command will work, since the dictionary underlying graph is not modified - >>> G.remove_nodes_from(list(n for n in G.nodes if n < 2)) - """ - for n in nodes: - try: - succs = self._succ[n] - del self._node[n] - for u in succs: - del self._pred[u][n] # remove all edges n-u in digraph - del self._succ[n] # now remove node - for u in self._pred[n]: - del self._succ[u][n] # remove all edges n-u in digraph - del self._pred[n] # now remove node - except KeyError: - pass # silent failure on remove - nx._clear_cache(self) - - def add_edge(self, u_of_edge, v_of_edge, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_of_edge, v_of_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - Adding an edge that already exists updates the edge data. - - Many NetworkX algorithms designed for weighted graphs use - an edge attribute (by default `weight`) to hold a numerical value. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = (1, 2) - >>> G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - - Associate data to edges using keywords: - - >>> G.add_edge(1, 2, weight=3) - >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> G.add_edge(1, 2) - >>> G[1][2].update({0: 5}) - >>> G.edges[1, 2].update({0: 5}) - """ - u, v = u_of_edge, v_of_edge - # add nodes - if u not in self._succ: - if u is None: - raise ValueError("None cannot be a node") - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - if v is None: - raise ValueError("None cannot be a node") - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - # add the edge - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - self._succ[u][v] = datadict - self._pred[v][u] = datadict - nx._clear_cache(self) - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges must be given as 2-tuples (u, v) or - 3-tuples (u, v, d) where d is a dictionary containing edge data. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - When adding edges from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_edges)`, and pass this - object to `G.add_edges_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label="WN2898") - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - >>> # Grow graph by one new node, adding edges to all existing nodes. - >>> # wrong way - will raise RuntimeError - >>> # G.add_edges_from(((5, n) for n in G.nodes)) - >>> # right way - note that there will be no self-edge for node 5 - >>> G.add_edges_from(list((5, n) for n in G.nodes)) - """ - for e in ebunch_to_add: - ne = len(e) - if ne == 3: - u, v, dd = e - elif ne == 2: - u, v = e - dd = {} - else: - raise NetworkXError(f"Edge tuple {e} must be a 2-tuple or 3-tuple.") - if u not in self._succ: - if u is None: - raise ValueError("None cannot be a node") - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - if v is None: - raise ValueError("None cannot be a node") - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - datadict.update(dd) - self._succ[u][v] = datadict - self._pred[v][u] = datadict - nx._clear_cache(self) - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the edge between nodes u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, etc - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - >>> e = (2, 3, {"weight": 7}) # an edge with attribute data - >>> G.remove_edge(*e[:2]) # select first part of edge tuple - """ - try: - del self._succ[u][v] - del self._pred[v][u] - except KeyError as err: - raise NetworkXError(f"The edge {u}-{v} not in graph.") from err - nx._clear_cache(self) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) edge between u and v. - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch = [(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - for e in ebunch: - u, v = e[:2] # ignore edge data - if u in self._succ and v in self._succ[u]: - del self._succ[u][v] - del self._pred[v][u] - nx._clear_cache(self) - - def has_successor(self, u, v): - """Returns True if node u has successor v. - - This is true if graph has the edge u->v. - """ - return u in self._succ and v in self._succ[u] - - def has_predecessor(self, u, v): - """Returns True if node u has predecessor v. - - This is true if graph has the edge u<-v. - """ - return u in self._pred and v in self._pred[u] - - def successors(self, n): - """Returns an iterator over successor nodes of n. - - A successor of n is a node m such that there exists a directed - edge from n to m. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------ - NetworkXError - If n is not in the graph. - - See Also - -------- - predecessors - - Notes - ----- - neighbors() and successors() are the same. - """ - try: - return iter(self._succ[n]) - except KeyError as err: - raise NetworkXError(f"The node {n} is not in the digraph.") from err - - # digraph definitions - neighbors = successors - - def predecessors(self, n): - """Returns an iterator over predecessor nodes of n. - - A predecessor of n is a node m such that there exists a directed - edge from m to n. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------ - NetworkXError - If n is not in the graph. - - See Also - -------- - successors - """ - try: - return iter(self._pred[n]) - except KeyError as err: - raise NetworkXError(f"The node {n} is not in the digraph.") from err - - @cached_property - def edges(self): - """An OutEdgeView of the DiGraph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, default=None) - - The OutEdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges.data('color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges from these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : OutEdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - See Also - -------- - in_edges, out_edges - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> nx.add_path(G, [0, 1, 2]) - >>> G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - OutEdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data("weight", default=1) - OutEdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges([0, 2]) # only edges originating from these nodes - OutEdgeDataView([(0, 1), (2, 3)]) - >>> G.edges(0) # only edges from node 0 - OutEdgeDataView([(0, 1)]) - - """ - return OutEdgeView(self) - - # alias out_edges to edges - @cached_property - def out_edges(self): - return OutEdgeView(self) - - out_edges.__doc__ = edges.__doc__ - - @cached_property - def in_edges(self): - """A view of the in edges of the graph as G.in_edges or G.in_edges(). - - in_edges(self, nbunch=None, data=False, default=None): - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - in_edges : InEdgeView or InEdgeDataView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2, color="blue") - >>> G.in_edges() - InEdgeView([(1, 2)]) - >>> G.in_edges(nbunch=2) - InEdgeDataView([(1, 2)]) - - See Also - -------- - edges - """ - return InEdgeView(self) - - @cached_property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - DiDegreeView or int - If multiple nodes are requested (the default), returns a `DiDegreeView` - mapping nodes to their degree. - If a single node is requested, returns the degree of the node as an integer. - - See Also - -------- - in_degree, out_degree - - Examples - -------- - >>> G = nx.DiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - - """ - return DiDegreeView(self) - - @cached_property - def in_degree(self): - """An InDegreeView for (node, in_degree) or in_degree for single node. - - The node in_degree is the number of edges pointing to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iteration over (node, in_degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - In-degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, in-degree). - - See Also - -------- - degree, out_degree - - Examples - -------- - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.in_degree(0) # node 0 with degree 0 - 0 - >>> list(G.in_degree([0, 1, 2])) - [(0, 0), (1, 1), (2, 1)] - - """ - return InDegreeView(self) - - @cached_property - def out_degree(self): - """An OutDegreeView for (node, out_degree) - - The node out_degree is the number of edges pointing out of the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator over (node, out_degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Out-degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, out-degree). - - See Also - -------- - degree, in_degree - - Examples - -------- - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.out_degree(0) # node 0 with degree 1 - 1 - >>> list(G.out_degree([0, 1, 2])) - [(0, 1), (1, 1), (2, 1)] - - """ - return OutDegreeView(self) - - def clear(self): - """Remove all nodes and edges from the graph. - - This also removes the name, and all graph, node, and edge attributes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear() - >>> list(G.nodes) - [] - >>> list(G.edges) - [] - - """ - self._succ.clear() - self._pred.clear() - self._node.clear() - self.graph.clear() - nx._clear_cache(self) - - def clear_edges(self): - """Remove all edges from the graph without altering nodes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear_edges() - >>> list(G.nodes) - [0, 1, 2, 3] - >>> list(G.edges) - [] - - """ - for predecessor_dict in self._pred.values(): - predecessor_dict.clear() - for successor_dict in self._succ.values(): - successor_dict.clear() - nx._clear_cache(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return False - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return True - - def to_undirected(self, reciprocal=False, as_view=False): - """Returns an undirected representation of the digraph. - - Parameters - ---------- - reciprocal : bool (optional) - If True only keep edges that appear in both directions - in the original digraph. - as_view : bool (optional, default=False) - If True return an undirected view of the original directed graph. - - Returns - ------- - G : Graph - An undirected graph with the same name and nodes and - with edge (u, v, data) if either (u, v, data) or (v, u, data) - is in the digraph. If both edges exist in digraph and - their edge data is different, only one edge is created - with an arbitrary choice of which edge data to use. - You must check and correct for this manually if desired. - - See Also - -------- - Graph, copy, add_edge, add_edges_from - - Notes - ----- - If edges in both directions (u, v) and (v, u) exist in the - graph, attributes for the new undirected edge will be a combination of - the attributes of the directed edges. The edge data is updated - in the (arbitrary) order that the edges are encountered. For - more customized control of the edge attributes use add_edge(). - - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar G=DiGraph(D) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed DiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - Graph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - if reciprocal is True: - G.add_edges_from( - (u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items() - if v in self._pred[u] - ) - else: - G.add_edges_from( - (u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items() - ) - return G - - def reverse(self, copy=True): - """Returns the reverse of the graph. - - The reverse is a graph with the same nodes and edges - but with the directions of the edges reversed. - - Parameters - ---------- - copy : bool optional (default=True) - If True, return a new DiGraph holding the reversed edges. - If False, the reverse graph is created using a view of - the original graph. - """ - if copy: - H = self.__class__() - H.graph.update(deepcopy(self.graph)) - H.add_nodes_from((n, deepcopy(d)) for n, d in self.nodes.items()) - H.add_edges_from((v, u, deepcopy(d)) for u, v, d in self.edges(data=True)) - return H - return nx.reverse_view(self) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/filters.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/filters.py deleted file mode 100644 index e989e22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/filters.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Filter factories to hide or show sets of nodes and edges. - -These filters return the function used when creating `SubGraph`. -""" - -__all__ = [ - "no_filter", - "hide_nodes", - "hide_edges", - "hide_multiedges", - "hide_diedges", - "hide_multidiedges", - "show_nodes", - "show_edges", - "show_multiedges", - "show_diedges", - "show_multidiedges", -] - - -def no_filter(*items): - """Returns a filter function that always evaluates to True.""" - return True - - -def hide_nodes(nodes): - """Returns a filter function that hides specific nodes.""" - nodes = set(nodes) - return lambda node: node not in nodes - - -def hide_diedges(edges): - """Returns a filter function that hides specific directed edges.""" - edges = {(u, v) for u, v in edges} - return lambda u, v: (u, v) not in edges - - -def hide_edges(edges): - """Returns a filter function that hides specific undirected edges.""" - alledges = set(edges) | {(v, u) for (u, v) in edges} - return lambda u, v: (u, v) not in alledges - - -def hide_multidiedges(edges): - """Returns a filter function that hides specific multi-directed edges.""" - edges = {(u, v, k) for u, v, k in edges} - return lambda u, v, k: (u, v, k) not in edges - - -def hide_multiedges(edges): - """Returns a filter function that hides specific multi-undirected edges.""" - alledges = set(edges) | {(v, u, k) for (u, v, k) in edges} - return lambda u, v, k: (u, v, k) not in alledges - - -# write show_nodes as a class to make SubGraph pickleable -class show_nodes: - """Filter class to show specific nodes. - - Attach the set of nodes as an attribute to speed up this commonly used filter - - Note that another allowed attribute for filters is to store the number of nodes - on the filter as attribute `length` (used in `__len__`). It is a user - responsibility to ensure this attribute is accurate if present. - """ - - def __init__(self, nodes): - self.nodes = set(nodes) - - def __call__(self, node): - return node in self.nodes - - -def show_diedges(edges): - """Returns a filter function that shows specific directed edges.""" - edges = {(u, v) for u, v in edges} - return lambda u, v: (u, v) in edges - - -def show_edges(edges): - """Returns a filter function that shows specific undirected edges.""" - alledges = set(edges) | {(v, u) for (u, v) in edges} - return lambda u, v: (u, v) in alledges - - -def show_multidiedges(edges): - """Returns a filter function that shows specific multi-directed edges.""" - edges = {(u, v, k) for u, v, k in edges} - return lambda u, v, k: (u, v, k) in edges - - -def show_multiedges(edges): - """Returns a filter function that shows specific multi-undirected edges.""" - alledges = set(edges) | {(v, u, k) for (u, v, k) in edges} - return lambda u, v, k: (u, v, k) in alledges diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/function.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/function.py deleted file mode 100644 index 7f42f93..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/function.py +++ /dev/null @@ -1,1407 +0,0 @@ -"""Functional interface to graph methods and assorted utilities.""" - -from collections import Counter -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = [ - "nodes", - "edges", - "degree", - "degree_histogram", - "neighbors", - "number_of_nodes", - "number_of_edges", - "density", - "is_directed", - "freeze", - "is_frozen", - "subgraph", - "induced_subgraph", - "edge_subgraph", - "restricted_view", - "to_directed", - "to_undirected", - "add_star", - "add_path", - "add_cycle", - "create_empty_copy", - "set_node_attributes", - "get_node_attributes", - "remove_node_attributes", - "set_edge_attributes", - "get_edge_attributes", - "remove_edge_attributes", - "all_neighbors", - "non_neighbors", - "non_edges", - "common_neighbors", - "is_weighted", - "is_negatively_weighted", - "is_empty", - "selfloop_edges", - "nodes_with_selfloops", - "number_of_selfloops", - "path_weight", - "is_path", -] - - -def nodes(G): - """Returns a NodeView over the graph nodes. - - This function wraps the :func:`G.nodes ` property. - """ - return G.nodes() - - -def edges(G, nbunch=None): - """Returns an edge view of edges incident to nodes in nbunch. - - Return all edges if nbunch is unspecified or nbunch=None. - - For digraphs, edges=out_edges - - This function wraps the :func:`G.edges ` property. - """ - return G.edges(nbunch) - - -def degree(G, nbunch=None, weight=None): - """Returns a degree view of single node or of nbunch of nodes. - If nbunch is omitted, then return degrees of *all* nodes. - - This function wraps the :func:`G.degree ` property. - """ - return G.degree(nbunch, weight) - - -def neighbors(G, n): - """Returns an iterator over all neighbors of node n. - - This function wraps the :func:`G.neighbors ` function. - """ - return G.neighbors(n) - - -def number_of_nodes(G): - """Returns the number of nodes in the graph. - - This function wraps the :func:`G.number_of_nodes ` function. - """ - return G.number_of_nodes() - - -def number_of_edges(G): - """Returns the number of edges in the graph. - - This function wraps the :func:`G.number_of_edges ` function. - """ - return G.number_of_edges() - - -def density(G): - r"""Returns the density of a graph. - - The density for undirected graphs is - - .. math:: - - d = \frac{2m}{n(n-1)}, - - and for directed graphs is - - .. math:: - - d = \frac{m}{n(n-1)}, - - where `n` is the number of nodes and `m` is the number of edges in `G`. - - Notes - ----- - The density is 0 for a graph without edges and 1 for a complete graph. - The density of multigraphs can be higher than 1. - - Self loops are counted in the total number of edges so graphs with self - loops can have density higher than 1. - """ - n = number_of_nodes(G) - m = number_of_edges(G) - if m == 0 or n <= 1: - return 0 - d = m / (n * (n - 1)) - if not G.is_directed(): - d *= 2 - return d - - -def degree_histogram(G): - """Returns a list of the frequency of each degree value. - - Parameters - ---------- - G : Networkx graph - A graph - - Returns - ------- - hist : list - A list of frequencies of degrees. - The degree values are the index in the list. - - Notes - ----- - Note: the bins are width one, hence len(list) can be large - (Order(number_of_edges)) - """ - counts = Counter(d for n, d in G.degree()) - return [counts.get(i, 0) for i in range(max(counts) + 1 if counts else 0)] - - -def is_directed(G): - """Return True if graph is directed.""" - return G.is_directed() - - -def frozen(*args, **kwargs): - """Dummy method for raising errors when trying to modify frozen graphs""" - raise nx.NetworkXError("Frozen graph can't be modified") - - -def freeze(G): - """Modify graph to prevent further change by adding or removing - nodes or edges. - - Node and edge data can still be modified. - - Parameters - ---------- - G : graph - A NetworkX graph - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G = nx.freeze(G) - >>> try: - ... G.add_edge(4, 5) - ... except nx.NetworkXError as err: - ... print(str(err)) - Frozen graph can't be modified - - Notes - ----- - To "unfreeze" a graph you must make a copy by creating a new graph object: - - >>> graph = nx.path_graph(4) - >>> frozen_graph = nx.freeze(graph) - >>> unfrozen_graph = nx.Graph(frozen_graph) - >>> nx.is_frozen(unfrozen_graph) - False - - See Also - -------- - is_frozen - """ - G.add_node = frozen - G.add_nodes_from = frozen - G.remove_node = frozen - G.remove_nodes_from = frozen - G.add_edge = frozen - G.add_edges_from = frozen - G.add_weighted_edges_from = frozen - G.remove_edge = frozen - G.remove_edges_from = frozen - G.clear = frozen - G.clear_edges = frozen - G.frozen = True - return G - - -def is_frozen(G): - """Returns True if graph is frozen. - - Parameters - ---------- - G : graph - A NetworkX graph - - See Also - -------- - freeze - """ - try: - return G.frozen - except AttributeError: - return False - - -def add_star(G_to_add_to, nodes_for_star, **attr): - """Add a star to Graph G_to_add_to. - - The first node in `nodes_for_star` is the middle of the star. - It is connected to all other nodes. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_star : iterable container - A container of nodes. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in star. - - See Also - -------- - add_path, add_cycle - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_star(G, [0, 1, 2, 3]) - >>> nx.add_star(G, [10, 11, 12], weight=2) - """ - nlist = iter(nodes_for_star) - try: - v = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(v) - edges = ((v, n) for n in nlist) - G_to_add_to.add_edges_from(edges, **attr) - - -def add_path(G_to_add_to, nodes_for_path, **attr): - """Add a path to the Graph G_to_add_to. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_path : iterable container - A container of nodes. A path will be constructed from - the nodes (in order) and added to the graph. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in path. - - See Also - -------- - add_star, add_cycle - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> nx.add_path(G, [10, 11, 12], weight=7) - """ - nlist = iter(nodes_for_path) - try: - first_node = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(first_node) - G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist)), **attr) - - -def add_cycle(G_to_add_to, nodes_for_cycle, **attr): - """Add a cycle to the Graph G_to_add_to. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_cycle: iterable container - A container of nodes. A cycle will be constructed from - the nodes (in order) and added to the graph. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in cycle. - - See Also - -------- - add_path, add_star - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> nx.add_cycle(G, [0, 1, 2, 3]) - >>> nx.add_cycle(G, [10, 11, 12], weight=7) - """ - nlist = iter(nodes_for_cycle) - try: - first_node = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(first_node) - G_to_add_to.add_edges_from( - pairwise(chain((first_node,), nlist), cyclic=True), **attr - ) - - -def subgraph(G, nbunch): - """Returns the subgraph induced on nodes in nbunch. - - Parameters - ---------- - G : graph - A NetworkX graph - - nbunch : list, iterable - A container of nodes that will be iterated through once (thus - it should be an iterator or be iterable). Each element of the - container should be a valid node type: any hashable type except - None. If nbunch is None, return all edges data in the graph. - Nodes in nbunch that are not in the graph will be (quietly) - ignored. - - Notes - ----- - subgraph(G) calls G.subgraph() - """ - return G.subgraph(nbunch) - - -def induced_subgraph(G, nbunch): - """Returns a SubGraph view of `G` showing only nodes in nbunch. - - The induced subgraph of a graph on a set of nodes N is the - graph with nodes N and edges from G which have both ends in N. - - Parameters - ---------- - G : NetworkX Graph - nbunch : node, container of nodes or None (for all nodes) - - Returns - ------- - subgraph : SubGraph View - A read-only view of the subgraph in `G` induced by the nodes. - Changes to the graph `G` will be reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - For an inplace reduction of a graph to a subgraph you can remove nodes: - `G.remove_nodes_from(n in G if n not in set(nbunch))` - - If you are going to compute subgraphs of your subgraphs you could - end up with a chain of views that can be very slow once the chain - has about 15 views in it. If they are all induced subgraphs, you - can short-cut the chain by making them all subgraphs of the original - graph. The graph class method `G.subgraph` does this when `G` is - a subgraph. In contrast, this function allows you to choose to build - chains or not, as you wish. The returned subgraph is a view on `G`. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = nx.induced_subgraph(G, [0, 1, 3]) - >>> list(H.edges) - [(0, 1)] - >>> list(H.nodes) - [0, 1, 3] - """ - induced_nodes = nx.filters.show_nodes(G.nbunch_iter(nbunch)) - return nx.subgraph_view(G, filter_node=induced_nodes) - - -def edge_subgraph(G, edges): - """Returns a view of the subgraph induced by the specified edges. - - The induced subgraph contains each edge in `edges` and each - node incident to any of those edges. - - Parameters - ---------- - G : NetworkX Graph - edges : iterable - An iterable of edges. Edges not present in `G` are ignored. - - Returns - ------- - subgraph : SubGraph View - A read-only edge-induced subgraph of `G`. - Changes to `G` are reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - If you create a subgraph of a subgraph recursively you can end up - with a chain of subgraphs that becomes very slow with about 15 - nested subgraph views. Luckily the edge_subgraph filter nests - nicely so you can use the original graph as G in this function - to avoid chains. We do not rule out chains programmatically so - that odd cases like an `edge_subgraph` of a `restricted_view` - can be created. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> H = G.edge_subgraph([(0, 1), (3, 4)]) - >>> list(H.nodes) - [0, 1, 3, 4] - >>> list(H.edges) - [(0, 1), (3, 4)] - """ - nxf = nx.filters - edges = set(edges) - nodes = set() - for e in edges: - nodes.update(e[:2]) - induced_nodes = nxf.show_nodes(nodes) - if G.is_multigraph(): - if G.is_directed(): - induced_edges = nxf.show_multidiedges(edges) - else: - induced_edges = nxf.show_multiedges(edges) - else: - if G.is_directed(): - induced_edges = nxf.show_diedges(edges) - else: - induced_edges = nxf.show_edges(edges) - return nx.subgraph_view(G, filter_node=induced_nodes, filter_edge=induced_edges) - - -def restricted_view(G, nodes, edges): - """Returns a view of `G` with hidden nodes and edges. - - The resulting subgraph filters out node `nodes` and edges `edges`. - Filtered out nodes also filter out any of their edges. - - Parameters - ---------- - G : NetworkX Graph - nodes : iterable - An iterable of nodes. Nodes not present in `G` are ignored. - edges : iterable - An iterable of edges. Edges not present in `G` are ignored. - - Returns - ------- - subgraph : SubGraph View - A read-only restricted view of `G` filtering out nodes and edges. - Changes to `G` are reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - If you create a subgraph of a subgraph recursively you may end up - with a chain of subgraph views. Such chains can get quite slow - for lengths near 15. To avoid long chains, try to make your subgraph - based on the original graph. We do not rule out chains programmatically - so that odd cases like an `edge_subgraph` of a `restricted_view` - can be created. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> H = nx.restricted_view(G, [0], [(1, 2), (3, 4)]) - >>> list(H.nodes) - [1, 2, 3, 4] - >>> list(H.edges) - [(2, 3)] - """ - nxf = nx.filters - hide_nodes = nxf.hide_nodes(nodes) - if G.is_multigraph(): - if G.is_directed(): - hide_edges = nxf.hide_multidiedges(edges) - else: - hide_edges = nxf.hide_multiedges(edges) - else: - if G.is_directed(): - hide_edges = nxf.hide_diedges(edges) - else: - hide_edges = nxf.hide_edges(edges) - return nx.subgraph_view(G, filter_node=hide_nodes, filter_edge=hide_edges) - - -def to_directed(graph): - """Returns a directed view of the graph `graph`. - - Identical to graph.to_directed(as_view=True) - Note that graph.to_directed defaults to `as_view=False` - while this function always provides a view. - """ - return graph.to_directed(as_view=True) - - -def to_undirected(graph): - """Returns an undirected view of the graph `graph`. - - Identical to graph.to_undirected(as_view=True) - Note that graph.to_undirected defaults to `as_view=False` - while this function always provides a view. - """ - return graph.to_undirected(as_view=True) - - -def create_empty_copy(G, with_data=True): - """Returns a copy of the graph G with all of the edges removed. - - Parameters - ---------- - G : graph - A NetworkX graph - - with_data : bool (default=True) - Propagate Graph and Nodes data to the new graph. - - See Also - -------- - empty_graph - - """ - H = G.__class__() - H.add_nodes_from(G.nodes(data=with_data)) - if with_data: - H.graph.update(G.graph) - return H - - -def set_node_attributes(G, values, name=None): - """Sets node attributes from a given value or dictionary of values. - - .. Warning:: The call order of arguments `values` and `name` - switched between v1.x & v2.x. - - Parameters - ---------- - G : NetworkX Graph - - values : scalar value, dict-like - What the node attribute should be set to. If `values` is - not a dictionary, then it is treated as a single attribute value - that is then applied to every node in `G`. This means that if - you provide a mutable object, like a list, updates to that object - will be reflected in the node attribute for every node. - The attribute name will be `name`. - - If `values` is a dict or a dict of dict, it should be keyed - by node to either an attribute value or a dict of attribute key/value - pairs used to update the node's attributes. - - name : string (optional, default=None) - Name of the node attribute to set if values is a scalar. - - Examples - -------- - After computing some property of the nodes of a graph, you may want - to assign a node attribute to store the value of that property for - each node:: - - >>> G = nx.path_graph(3) - >>> bb = nx.betweenness_centrality(G) - >>> isinstance(bb, dict) - True - >>> nx.set_node_attributes(G, bb, "betweenness") - >>> G.nodes[1]["betweenness"] - 1.0 - - If you provide a list as the second argument, updates to the list - will be reflected in the node attribute for each node:: - - >>> G = nx.path_graph(3) - >>> labels = [] - >>> nx.set_node_attributes(G, labels, "labels") - >>> labels.append("foo") - >>> G.nodes[0]["labels"] - ['foo'] - >>> G.nodes[1]["labels"] - ['foo'] - >>> G.nodes[2]["labels"] - ['foo'] - - If you provide a dictionary of dictionaries as the second argument, - the outer dictionary is assumed to be keyed by node to an inner - dictionary of node attributes for that node:: - - >>> G = nx.path_graph(3) - >>> attrs = {0: {"attr1": 20, "attr2": "nothing"}, 1: {"attr2": 3}} - >>> nx.set_node_attributes(G, attrs) - >>> G.nodes[0]["attr1"] - 20 - >>> G.nodes[0]["attr2"] - 'nothing' - >>> G.nodes[1]["attr2"] - 3 - >>> G.nodes[2] - {} - - Note that if the dictionary contains nodes that are not in `G`, the - values are silently ignored:: - - >>> G = nx.Graph() - >>> G.add_node(0) - >>> nx.set_node_attributes(G, {0: "red", 1: "blue"}, name="color") - >>> G.nodes[0]["color"] - 'red' - >>> 1 in G.nodes - False - - """ - # Set node attributes based on type of `values` - if name is not None: # `values` must not be a dict of dict - try: # `values` is a dict - for n, v in values.items(): - try: - G.nodes[n][name] = values[n] - except KeyError: - pass - except AttributeError: # `values` is a constant - for n in G: - G.nodes[n][name] = values - else: # `values` must be dict of dict - for n, d in values.items(): - try: - G.nodes[n].update(d) - except KeyError: - pass - nx._clear_cache(G) - - -def get_node_attributes(G, name, default=None): - """Get node attributes from graph - - Parameters - ---------- - G : NetworkX Graph - - name : string - Attribute name - - default: object (default=None) - Default value of the node attribute if there is no value set for that - node in graph. If `None` then nodes without this attribute are not - included in the returned dict. - - Returns - ------- - Dictionary of attributes keyed by node. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([1, 2, 3], color="red") - >>> color = nx.get_node_attributes(G, "color") - >>> color[1] - 'red' - >>> G.add_node(4) - >>> color = nx.get_node_attributes(G, "color", default="yellow") - >>> color[4] - 'yellow' - """ - if default is not None: - return {n: d.get(name, default) for n, d in G.nodes.items()} - return {n: d[name] for n, d in G.nodes.items() if name in d} - - -def remove_node_attributes(G, *attr_names, nbunch=None): - """Remove node attributes from all nodes in the graph. - - Parameters - ---------- - G : NetworkX Graph - - *attr_names : List of Strings - The attribute names to remove from the graph. - - nbunch : List of Nodes - Remove the node attributes only from the nodes in this list. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([1, 2, 3], color="blue") - >>> nx.get_node_attributes(G, "color") - {1: 'blue', 2: 'blue', 3: 'blue'} - >>> nx.remove_node_attributes(G, "color") - >>> nx.get_node_attributes(G, "color") - {} - """ - - if nbunch is None: - nbunch = G.nodes() - - for attr in attr_names: - for n, d in G.nodes(data=True): - if n in nbunch: - try: - del d[attr] - except KeyError: - pass - - -def set_edge_attributes(G, values, name=None): - """Sets edge attributes from a given value or dictionary of values. - - .. Warning:: The call order of arguments `values` and `name` - switched between v1.x & v2.x. - - Parameters - ---------- - G : NetworkX Graph - - values : scalar value, dict-like - What the edge attribute should be set to. If `values` is - not a dictionary, then it is treated as a single attribute value - that is then applied to every edge in `G`. This means that if - you provide a mutable object, like a list, updates to that object - will be reflected in the edge attribute for each edge. The attribute - name will be `name`. - - If `values` is a dict or a dict of dict, it should be keyed - by edge tuple to either an attribute value or a dict of attribute - key/value pairs used to update the edge's attributes. - For multigraphs, the edge tuples must be of the form ``(u, v, key)``, - where `u` and `v` are nodes and `key` is the edge key. - For non-multigraphs, the keys must be tuples of the form ``(u, v)``. - - name : string (optional, default=None) - Name of the edge attribute to set if values is a scalar. - - Examples - -------- - After computing some property of the edges of a graph, you may want - to assign a edge attribute to store the value of that property for - each edge:: - - >>> G = nx.path_graph(3) - >>> bb = nx.edge_betweenness_centrality(G, normalized=False) - >>> nx.set_edge_attributes(G, bb, "betweenness") - >>> G.edges[1, 2]["betweenness"] - 2.0 - - If you provide a list as the second argument, updates to the list - will be reflected in the edge attribute for each edge:: - - >>> labels = [] - >>> nx.set_edge_attributes(G, labels, "labels") - >>> labels.append("foo") - >>> G.edges[0, 1]["labels"] - ['foo'] - >>> G.edges[1, 2]["labels"] - ['foo'] - - If you provide a dictionary of dictionaries as the second argument, - the entire dictionary will be used to update edge attributes:: - - >>> G = nx.path_graph(3) - >>> attrs = {(0, 1): {"attr1": 20, "attr2": "nothing"}, (1, 2): {"attr2": 3}} - >>> nx.set_edge_attributes(G, attrs) - >>> G[0][1]["attr1"] - 20 - >>> G[0][1]["attr2"] - 'nothing' - >>> G[1][2]["attr2"] - 3 - - The attributes of one Graph can be used to set those of another. - - >>> H = nx.path_graph(3) - >>> nx.set_edge_attributes(H, G.edges) - - Note that if the dict contains edges that are not in `G`, they are - silently ignored:: - - >>> G = nx.Graph([(0, 1)]) - >>> nx.set_edge_attributes(G, {(1, 2): {"weight": 2.0}}) - >>> (1, 2) in G.edges() - False - - For multigraphs, the `values` dict is expected to be keyed by 3-tuples - including the edge key:: - - >>> MG = nx.MultiGraph() - >>> edges = [(0, 1), (0, 1)] - >>> MG.add_edges_from(edges) # Returns list of edge keys - [0, 1] - >>> attributes = {(0, 1, 0): {"cost": 21}, (0, 1, 1): {"cost": 7}} - >>> nx.set_edge_attributes(MG, attributes) - >>> MG[0][1][0]["cost"] - 21 - >>> MG[0][1][1]["cost"] - 7 - - If MultiGraph attributes are desired for a Graph, you must convert the 3-tuple - multiedge to a 2-tuple edge and the last multiedge's attribute value will - overwrite the previous values. Continuing from the previous case we get:: - - >>> H = nx.path_graph([0, 1, 2]) - >>> nx.set_edge_attributes(H, {(u, v): ed for u, v, ed in MG.edges.data()}) - >>> nx.get_edge_attributes(H, "cost") - {(0, 1): 7} - - """ - if name is not None: - # `values` does not contain attribute names - try: - # if `values` is a dict using `.items()` => {edge: value} - if G.is_multigraph(): - for (u, v, key), value in values.items(): - try: - G._adj[u][v][key][name] = value - except KeyError: - pass - else: - for (u, v), value in values.items(): - try: - G._adj[u][v][name] = value - except KeyError: - pass - except AttributeError: - # treat `values` as a constant - for u, v, data in G.edges(data=True): - data[name] = values - else: - # `values` consists of doct-of-dict {edge: {attr: value}} shape - if G.is_multigraph(): - for (u, v, key), d in values.items(): - try: - G._adj[u][v][key].update(d) - except KeyError: - pass - else: - for (u, v), d in values.items(): - try: - G._adj[u][v].update(d) - except KeyError: - pass - nx._clear_cache(G) - - -def get_edge_attributes(G, name, default=None): - """Get edge attributes from graph - - Parameters - ---------- - G : NetworkX Graph - - name : string - Attribute name - - default: object (default=None) - Default value of the edge attribute if there is no value set for that - edge in graph. If `None` then edges without this attribute are not - included in the returned dict. - - Returns - ------- - Dictionary of attributes keyed by edge. For (di)graphs, the keys are - 2-tuples of the form: (u, v). For multi(di)graphs, the keys are 3-tuples of - the form: (u, v, key). - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [1, 2, 3], color="red") - >>> color = nx.get_edge_attributes(G, "color") - >>> color[(1, 2)] - 'red' - >>> G.add_edge(3, 4) - >>> color = nx.get_edge_attributes(G, "color", default="yellow") - >>> color[(3, 4)] - 'yellow' - """ - if G.is_multigraph(): - edges = G.edges(keys=True, data=True) - else: - edges = G.edges(data=True) - if default is not None: - return {x[:-1]: x[-1].get(name, default) for x in edges} - return {x[:-1]: x[-1][name] for x in edges if name in x[-1]} - - -def remove_edge_attributes(G, *attr_names, ebunch=None): - """Remove edge attributes from all edges in the graph. - - Parameters - ---------- - G : NetworkX Graph - - *attr_names : List of Strings - The attribute names to remove from the graph. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> nx.set_edge_attributes(G, {(u, v): u + v for u, v in G.edges()}, name="weight") - >>> nx.get_edge_attributes(G, "weight") - {(0, 1): 1, (1, 2): 3} - >>> remove_edge_attributes(G, "weight") - >>> nx.get_edge_attributes(G, "weight") - {} - """ - if ebunch is None: - ebunch = G.edges(keys=True) if G.is_multigraph() else G.edges() - - for attr in attr_names: - edges = ( - G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True) - ) - for *e, d in edges: - if tuple(e) in ebunch: - try: - del d[attr] - except KeyError: - pass - - -def all_neighbors(graph, node): - """Returns all of the neighbors of a node in the graph. - - If the graph is directed returns predecessors as well as successors. - - Parameters - ---------- - graph : NetworkX graph - Graph to find neighbors. - - node : node - The node whose neighbors will be returned. - - Returns - ------- - neighbors : iterator - Iterator of neighbors - """ - if graph.is_directed(): - values = chain(graph.predecessors(node), graph.successors(node)) - else: - values = graph.neighbors(node) - return values - - -def non_neighbors(graph, node): - """Returns the non-neighbors of the node in the graph. - - Parameters - ---------- - graph : NetworkX graph - Graph to find neighbors. - - node : node - The node whose neighbors will be returned. - - Returns - ------- - non_neighbors : set - Set of nodes in the graph that are not neighbors of the node. - """ - return graph._adj.keys() - graph._adj[node].keys() - {node} - - -def non_edges(graph): - """Returns the nonexistent edges in the graph. - - Parameters - ---------- - graph : NetworkX graph. - Graph to find nonexistent edges. - - Returns - ------- - non_edges : iterator - Iterator of edges that are not in the graph. - """ - if graph.is_directed(): - for u in graph: - for v in non_neighbors(graph, u): - yield (u, v) - else: - nodes = set(graph) - while nodes: - u = nodes.pop() - for v in nodes - set(graph[u]): - yield (u, v) - - -@not_implemented_for("directed") -def common_neighbors(G, u, v): - """Returns the common neighbors of two nodes in a graph. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - u, v : nodes - Nodes in the graph. - - Returns - ------- - cnbors : set - Set of common neighbors of u and v in the graph. - - Raises - ------ - NetworkXError - If u or v is not a node in the graph. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> sorted(nx.common_neighbors(G, 0, 1)) - [2, 3, 4] - """ - if u not in G: - raise nx.NetworkXError("u is not in the graph.") - if v not in G: - raise nx.NetworkXError("v is not in the graph.") - - return G._adj[u].keys() & G._adj[v].keys() - {u, v} - - -def is_weighted(G, edge=None, weight="weight"): - """Returns True if `G` has weighted edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - edge : tuple, optional - A 2-tuple specifying the only edge in `G` that will be tested. If - None, then every edge in `G` is tested. - - weight: string, optional - The attribute name used to query for edge weights. - - Returns - ------- - bool - A boolean signifying if `G`, or the specified edge, is weighted. - - Raises - ------ - NetworkXError - If the specified edge does not exist. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.is_weighted(G) - False - >>> nx.is_weighted(G, (2, 3)) - False - - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2, weight=1) - >>> nx.is_weighted(G) - True - - """ - if edge is not None: - data = G.get_edge_data(*edge) - if data is None: - msg = f"Edge {edge!r} does not exist." - raise nx.NetworkXError(msg) - return weight in data - - if is_empty(G): - # Special handling required since: all([]) == True - return False - - return all(weight in data for u, v, data in G.edges(data=True)) - - -@nx._dispatchable(edge_attrs="weight") -def is_negatively_weighted(G, edge=None, weight="weight"): - """Returns True if `G` has negatively weighted edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - edge : tuple, optional - A 2-tuple specifying the only edge in `G` that will be tested. If - None, then every edge in `G` is tested. - - weight: string, optional - The attribute name used to query for edge weights. - - Returns - ------- - bool - A boolean signifying if `G`, or the specified edge, is negatively - weighted. - - Raises - ------ - NetworkXError - If the specified edge does not exist. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(1, 3), (2, 4), (2, 6)]) - >>> G.add_edge(1, 2, weight=4) - >>> nx.is_negatively_weighted(G, (1, 2)) - False - >>> G[2][4]["weight"] = -2 - >>> nx.is_negatively_weighted(G) - True - >>> G = nx.DiGraph() - >>> edges = [("0", "3", 3), ("0", "1", -5), ("1", "0", -2)] - >>> G.add_weighted_edges_from(edges) - >>> nx.is_negatively_weighted(G) - True - - """ - if edge is not None: - data = G.get_edge_data(*edge) - if data is None: - msg = f"Edge {edge!r} does not exist." - raise nx.NetworkXError(msg) - return weight in data and data[weight] < 0 - - return any(weight in data and data[weight] < 0 for u, v, data in G.edges(data=True)) - - -def is_empty(G): - """Returns True if `G` has no edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - Returns - ------- - bool - True if `G` has no edges, and False otherwise. - - Notes - ----- - An empty graph can have nodes but not edges. The empty graph with zero - nodes is known as the null graph. This is an $O(n)$ operation where n - is the number of nodes in the graph. - - """ - return not any(G._adj.values()) - - -def nodes_with_selfloops(G): - """Returns an iterator over nodes with self loops. - - A node with a self loop has an edge with both ends adjacent - to that node. - - Returns - ------- - nodelist : iterator - A iterator over nodes with self loops. - - See Also - -------- - selfloop_edges, number_of_selfloops - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge(1, 1) - >>> G.add_edge(1, 2) - >>> list(nx.nodes_with_selfloops(G)) - [1] - - """ - return (n for n, nbrs in G._adj.items() if n in nbrs) - - -def selfloop_edges(G, data=False, keys=False, default=None): - """Returns an iterator over selfloop edges. - - A selfloop edge has the same node at both ends. - - Parameters - ---------- - G : graph - A NetworkX graph. - data : string or bool, optional (default=False) - Return selfloop edges as two tuples (u, v) (data=False) - or three-tuples (u, v, datadict) (data=True) - or three-tuples (u, v, datavalue) (data='attrname') - keys : bool, optional (default=False) - If True, return edge keys with each edge. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edgeiter : iterator over edge tuples - An iterator over all selfloop edges. - - See Also - -------- - nodes_with_selfloops, number_of_selfloops - - Examples - -------- - >>> G = nx.MultiGraph() # or Graph, DiGraph, MultiDiGraph, etc - >>> ekey = G.add_edge(1, 1) - >>> ekey = G.add_edge(1, 2) - >>> list(nx.selfloop_edges(G)) - [(1, 1)] - >>> list(nx.selfloop_edges(G, data=True)) - [(1, 1, {})] - >>> list(nx.selfloop_edges(G, keys=True)) - [(1, 1, 0)] - >>> list(nx.selfloop_edges(G, keys=True, data=True)) - [(1, 1, 0, {})] - """ - if data is True: - if G.is_multigraph(): - if keys is True: - return ( - (n, n, k, d) - for n, nbrs in G._adj.items() - if n in nbrs - for k, d in nbrs[n].items() - ) - else: - return ( - (n, n, d) - for n, nbrs in G._adj.items() - if n in nbrs - for d in nbrs[n].values() - ) - else: - return ((n, n, nbrs[n]) for n, nbrs in G._adj.items() if n in nbrs) - elif data is not False: - if G.is_multigraph(): - if keys is True: - return ( - (n, n, k, d.get(data, default)) - for n, nbrs in G._adj.items() - if n in nbrs - for k, d in nbrs[n].items() - ) - else: - return ( - (n, n, d.get(data, default)) - for n, nbrs in G._adj.items() - if n in nbrs - for d in nbrs[n].values() - ) - else: - return ( - (n, n, nbrs[n].get(data, default)) - for n, nbrs in G._adj.items() - if n in nbrs - ) - else: - if G.is_multigraph(): - if keys is True: - return ( - (n, n, k) - for n, nbrs in G._adj.items() - if n in nbrs - for k in nbrs[n] - ) - else: - return ( - (n, n) - for n, nbrs in G._adj.items() - if n in nbrs - for i in range(len(nbrs[n])) # for easy edge removal (#4068) - ) - else: - return ((n, n) for n, nbrs in G._adj.items() if n in nbrs) - - -def number_of_selfloops(G): - """Returns the number of selfloop edges. - - A selfloop edge has the same node at both ends. - - Returns - ------- - nloops : int - The number of selfloops. - - See Also - -------- - nodes_with_selfloops, selfloop_edges - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge(1, 1) - >>> G.add_edge(1, 2) - >>> nx.number_of_selfloops(G) - 1 - """ - return sum(1 for _ in nx.selfloop_edges(G)) - - -def is_path(G, path): - """Returns whether or not the specified path exists. - - For it to return True, every node on the path must exist and - each consecutive pair must be connected via one or more edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - path : list - A list of nodes which defines the path to traverse - - Returns - ------- - bool - True if `path` is a valid path in `G` - - """ - try: - return all(nbr in G._adj[node] for node, nbr in nx.utils.pairwise(path)) - except (KeyError, TypeError): - return False - - -def path_weight(G, path, weight): - """Returns total cost associated with specified path and weight - - Parameters - ---------- - G : graph - A NetworkX graph. - - path: list - A list of node labels which defines the path to traverse - - weight: string - A string indicating which edge attribute to use for path cost - - Returns - ------- - cost: int or float - An integer or a float representing the total cost with respect to the - specified weight of the specified path - - Raises - ------ - NetworkXNoPath - If the specified edge does not exist. - """ - multigraph = G.is_multigraph() - cost = 0 - - if not nx.is_path(G, path): - raise nx.NetworkXNoPath("path does not exist") - for node, nbr in nx.utils.pairwise(path): - if multigraph: - cost += min(v[weight] for v in G._adj[node][nbr].values()) - else: - cost += G._adj[node][nbr][weight] - return cost diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/graph.py deleted file mode 100644 index 6828705..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/graph.py +++ /dev/null @@ -1,2058 +0,0 @@ -"""Base class for undirected graphs. - -The Graph class allows any hashable object as a node -and can associate key/value attribute pairs with each undirected edge. - -Self-loops are allowed but multiple edges are not (see MultiGraph). - -For directed graphs see DiGraph and MultiDiGraph. -""" - -from copy import deepcopy -from functools import cached_property - -import networkx as nx -from networkx import convert -from networkx.classes.coreviews import AdjacencyView -from networkx.classes.reportviews import DegreeView, EdgeView, NodeView -from networkx.exception import NetworkXError - -__all__ = ["Graph"] - - -class _CachedPropertyResetterAdj: - """Data Descriptor class for _adj that resets ``adj`` cached_property when needed - - This assumes that the ``cached_property`` ``G.adj`` should be reset whenever - ``G._adj`` is set to a new value. - - This object sits on a class and ensures that any instance of that - class clears its cached property "adj" whenever the underlying - instance attribute "_adj" is set to a new object. It only affects - the set process of the obj._adj attribute. All get/del operations - act as they normally would. - - For info on Data Descriptors see: https://docs.python.org/3/howto/descriptor.html - """ - - def __set__(self, obj, value): - od = obj.__dict__ - od["_adj"] = value - # reset cached properties - props = ["adj", "edges", "degree"] - for prop in props: - if prop in od: - del od[prop] - - -class _CachedPropertyResetterNode: - """Data Descriptor class for _node that resets ``nodes`` cached_property when needed - - This assumes that the ``cached_property`` ``G.node`` should be reset whenever - ``G._node`` is set to a new value. - - This object sits on a class and ensures that any instance of that - class clears its cached property "nodes" whenever the underlying - instance attribute "_node" is set to a new object. It only affects - the set process of the obj._adj attribute. All get/del operations - act as they normally would. - - For info on Data Descriptors see: https://docs.python.org/3/howto/descriptor.html - """ - - def __set__(self, obj, value): - od = obj.__dict__ - od["_node"] = value - # reset cached properties - if "nodes" in od: - del od["nodes"] - - -class Graph: - """ - Base class for undirected graphs. - - A Graph stores nodes and edges with optional data, or attributes. - - Graphs hold undirected edges. Self loops are allowed but multiple - (parallel) edges are not. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes, except that `None` is not allowed as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, 2D NumPy array, SciPy - sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - DiGraph - MultiGraph - MultiDiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.Graph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> G.add_edge(1, 2) - - a list of edges, - - >>> G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. There are no errors when adding - nodes or edges that already exist. - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.Graph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time="5pm") - >>> G.add_nodes_from([3], time="2pm") - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]["room"] = 714 # node must exist already to use G.nodes - >>> del G.nodes[1]["room"] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> G.add_edge(1, 2, weight=4.7) - >>> G.add_edges_from([(3, 4), (4, 5)], color="red") - >>> G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})]) - >>> G[1][2]["weight"] = 4.7 - >>> G.edges[1, 2]["weight"] = 4 - - Warning: we protect the graph data structure by making `G.edges` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, eattr in nbrsdict.items(): - ... if "weight" in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, weight in G.edges.data("weight"): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using object-attributes and methods. - Reporting typically provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes`, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n]`, `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The Graph class uses a dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge data keyed by neighbor. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these three dicts can be replaced in a subclass by a user defined - dict-like object. In general, the dict-like features should be - maintained but extra features can be added. To replace one of the - dicts create a new graph class by changing the class(!) variable - holding the factory for that dict-like structure. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds edge data keyed by neighbor. - It should require no arguments and return a dict-like object - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherit without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - **Subclassing Example** - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {"weight": 1} - ... - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - """ - - __networkx_backend__ = "networkx" - - _adj = _CachedPropertyResetterAdj() - _node = _CachedPropertyResetterNode() - - node_dict_factory = dict - node_attr_dict_factory = dict - adjlist_outer_dict_factory = dict - adjlist_inner_dict_factory = dict - edge_attr_dict_factory = dict - graph_attr_dict_factory = dict - - def to_directed_class(self): - """Returns the class to use for empty directed copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return nx.DiGraph - - def to_undirected_class(self): - """Returns the class to use for empty undirected copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return Graph - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a 2D NumPy array, a - SciPy sparse array, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name="my graph") - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes - self._node = self.node_dict_factory() # empty node attribute dict - self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict - self.__networkx_cache__ = {} - # attempt to load graph with data - if incoming_graph_data is not None: - convert.to_networkx_graph(incoming_graph_data, create_using=self) - # load graph attributes (must be after convert) - self.graph.update(attr) - - @cached_property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return AdjacencyView(self._adj) - - @property - def name(self): - """String identifier of the graph. - - This graph attribute appears in the attribute dict G.graph - keyed by the string `"name"`. as well as an attribute (technically - a property) `G.name`. This is entirely user controlled. - """ - return self.graph.get("name", "") - - @name.setter - def name(self, s): - self.graph["name"] = s - nx._clear_cache(self) - - def __str__(self): - """Returns a short summary of the graph. - - Returns - ------- - info : string - Graph information including the graph name (if any), graph type, and the - number of nodes and edges. - - Examples - -------- - >>> G = nx.Graph(name="foo") - >>> str(G) - "Graph named 'foo' with 0 nodes and 0 edges" - - >>> G = nx.path_graph(3) - >>> str(G) - 'Graph with 3 nodes and 2 edges' - - """ - return "".join( - [ - type(self).__name__, - f" named {self.name!r}" if self.name else "", - f" with {self.number_of_nodes()} nodes and {self.number_of_edges()} edges", - ] - ) - - def __iter__(self): - """Iterate over the nodes. Use: 'for n in G'. - - Returns - ------- - niter : iterator - An iterator over all nodes in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G] - [0, 1, 2, 3] - >>> list(G) - [0, 1, 2, 3] - """ - return iter(self._node) - - def __contains__(self, n): - """Returns True if n is a node, False otherwise. Use: 'n in G'. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> 1 in G - True - """ - try: - return n in self._node - except TypeError: - return False - - def __len__(self): - """Returns the number of nodes in the graph. Use: 'len(G)'. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes: identical method - order: identical method - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> len(G) - 4 - - """ - return len(self._node) - - def __getitem__(self, n): - """Returns a dict of neighbors of node n. Use: 'G[n]'. - - Parameters - ---------- - n : node - A node in the graph. - - Returns - ------- - adj_dict : dictionary - The adjacency dictionary for nodes connected to n. - - Notes - ----- - G[n] is the same as G.adj[n] and similar to G.neighbors(n) - (which is an iterator over G.adj[n]) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0] - AtlasView({1: {}}) - """ - return self.adj[n] - - def add_node(self, node_for_adding, **attr): - """Add a single node `node_for_adding` and update node attributes. - - Parameters - ---------- - node_for_adding : node - A node can be any hashable Python object except None. - attr : keyword arguments, optional - Set or change node attributes using key=value. - - See Also - -------- - add_nodes_from - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_node(1) - >>> G.add_node("Hello") - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_node(K3) - >>> G.number_of_nodes() - 3 - - Use keywords set/change node attributes: - - >>> G.add_node(1, size=10) - >>> G.add_node(3, weight=0.4, UTM=("13S", 382871, 3972649)) - - Notes - ----- - A hashable object is one that can be used as a key in a Python - dictionary. This includes strings, numbers, tuples of strings - and numbers, etc. - - On many platforms hashable items also include mutables such as - NetworkX Graphs, though one should be careful that the hash - doesn't change on mutables. - """ - if node_for_adding not in self._node: - if node_for_adding is None: - raise ValueError("None cannot be a node") - self._adj[node_for_adding] = self.adjlist_inner_dict_factory() - attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: # update attr even if node already exists - self._node[node_for_adding].update(attr) - nx._clear_cache(self) - - def add_nodes_from(self, nodes_for_adding, **attr): - """Add multiple nodes. - - Parameters - ---------- - nodes_for_adding : iterable container - A container of nodes (list, dict, set, etc.). - OR - A container of (node, attribute dict) tuples. - Node attributes are updated using the attribute dict. - attr : keyword arguments, optional (default= no attributes) - Update attributes for all nodes in nodes. - Node attributes specified in nodes as a tuple take - precedence over attributes specified via keyword arguments. - - See Also - -------- - add_node - - Notes - ----- - When adding nodes from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_nodes)`, and pass this - object to `G.add_nodes_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_nodes_from("Hello") - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_nodes_from(K3) - >>> sorted(G.nodes(), key=str) - [0, 1, 2, 'H', 'e', 'l', 'o'] - - Use keywords to update specific node attributes for every node. - - >>> G.add_nodes_from([1, 2], size=10) - >>> G.add_nodes_from([3, 4], weight=0.4) - - Use (node, attrdict) tuples to update attributes for specific nodes. - - >>> G.add_nodes_from([(1, dict(size=11)), (2, {"color": "blue"})]) - >>> G.nodes[1]["size"] - 11 - >>> H = nx.Graph() - >>> H.add_nodes_from(G.nodes(data=True)) - >>> H.nodes[1]["size"] - 11 - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.Graph([(0, 1), (1, 2), (3, 4)]) - >>> # wrong way - will raise RuntimeError - >>> # G.add_nodes_from(n + 1 for n in G.nodes) - >>> # correct way - >>> G.add_nodes_from(list(n + 1 for n in G.nodes)) - """ - for n in nodes_for_adding: - try: - newnode = n not in self._node - newdict = attr - except TypeError: - n, ndict = n - newnode = n not in self._node - newdict = attr.copy() - newdict.update(ndict) - if newnode: - if n is None: - raise ValueError("None cannot be a node") - self._adj[n] = self.adjlist_inner_dict_factory() - self._node[n] = self.node_attr_dict_factory() - self._node[n].update(newdict) - nx._clear_cache(self) - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges. - Attempting to remove a nonexistent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------ - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> list(G.edges) - [(0, 1), (1, 2)] - >>> G.remove_node(1) - >>> list(G.edges) - [] - - """ - adj = self._adj - try: - nbrs = list(adj[n]) # list handles self-loops (allows mutation) - del self._node[n] - except KeyError as err: # NetworkXError if n not in self - raise NetworkXError(f"The node {n} is not in the graph.") from err - for u in nbrs: - del adj[u][n] # remove all edges n-u in graph - del adj[n] # now remove node - nx._clear_cache(self) - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently - ignored. - - See Also - -------- - remove_node - - Notes - ----- - When removing nodes from an iterator over the graph you are changing, - a `RuntimeError` will be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_nodes)`, and pass this - object to `G.remove_nodes_from`. - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = list(G.nodes) - >>> e - [0, 1, 2] - >>> G.remove_nodes_from(e) - >>> list(G.nodes) - [] - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.Graph([(0, 1), (1, 2), (3, 4)]) - >>> # this command will fail, as the graph's dict is modified during iteration - >>> # G.remove_nodes_from(n for n in G.nodes if n < 2) - >>> # this command will work, since the dictionary underlying graph is not modified - >>> G.remove_nodes_from(list(n for n in G.nodes if n < 2)) - """ - adj = self._adj - for n in nodes: - try: - del self._node[n] - for u in list(adj[n]): # list handles self-loops - del adj[u][n] # (allows mutation of dict in loop) - del adj[n] - except KeyError: - pass - nx._clear_cache(self) - - @cached_property - def nodes(self): - """A NodeView of the Graph as G.nodes or G.nodes(). - - Can be used as `G.nodes` for data lookup and for set-like operations. - Can also be used as `G.nodes(data='color', default=None)` to return a - NodeDataView which reports specific node data but no set operations. - It presents a dict-like interface as well with `G.nodes.items()` - iterating over `(node, nodedata)` 2-tuples and `G.nodes[3]['foo']` - providing the value of the `foo` attribute for node `3`. In addition, - a view `G.nodes.data('foo')` provides a dict-like interface to the - `foo` attribute of each node. `G.nodes.data('foo', default=1)` - provides a default for nodes that do not have attribute `foo`. - - Parameters - ---------- - data : string or bool, optional (default=False) - The node attribute returned in 2-tuple (n, ddict[data]). - If True, return entire node attribute dict as (n, ddict). - If False, return just the nodes n. - - default : value, optional (default=None) - Value used for nodes that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - NodeView - Allows set-like operations over the nodes as well as node - attribute dict lookup and calling to get a NodeDataView. - A NodeDataView iterates over `(n, data)` and has no set operations. - A NodeView iterates over `n` and includes set operations. - - When called, if data is False, an iterator over nodes. - Otherwise an iterator of 2-tuples (node, attribute value) - where the attribute is specified in `data`. - If data is True then the attribute becomes the - entire data dictionary. - - Notes - ----- - If your node data is not needed, it is simpler and equivalent - to use the expression ``for n in G``, or ``list(G)``. - - Examples - -------- - There are two simple ways of getting a list of all nodes in the graph: - - >>> G = nx.path_graph(3) - >>> list(G.nodes) - [0, 1, 2] - >>> list(G) - [0, 1, 2] - - To get the node data along with the nodes: - - >>> G.add_node(1, time="5pm") - >>> G.nodes[0]["foo"] = "bar" - >>> list(G.nodes(data=True)) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - >>> list(G.nodes.data()) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - - >>> list(G.nodes(data="foo")) - [(0, 'bar'), (1, None), (2, None)] - >>> list(G.nodes.data("foo")) - [(0, 'bar'), (1, None), (2, None)] - - >>> list(G.nodes(data="time")) - [(0, None), (1, '5pm'), (2, None)] - >>> list(G.nodes.data("time")) - [(0, None), (1, '5pm'), (2, None)] - - >>> list(G.nodes(data="time", default="Not Available")) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - >>> list(G.nodes.data("time", default="Not Available")) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - - If some of your nodes have an attribute and the rest are assumed - to have a default attribute value you can create a dictionary - from node/attribute pairs using the `default` keyword argument - to guarantee the value is never None:: - - >>> G = nx.Graph() - >>> G.add_node(0) - >>> G.add_node(1, weight=2) - >>> G.add_node(2, weight=3) - >>> dict(G.nodes(data="weight", default=1)) - {0: 1, 1: 2, 2: 3} - - """ - return NodeView(self) - - def number_of_nodes(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - order: identical method - __len__: identical method - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.number_of_nodes() - 3 - """ - return len(self._node) - - def order(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes: identical method - __len__: identical method - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.order() - 3 - """ - return len(self._node) - - def has_node(self, n): - """Returns True if the graph contains the node n. - - Identical to `n in G` - - Parameters - ---------- - n : node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_node(0) - True - - It is more readable and simpler to use - - >>> 0 in G - True - - """ - try: - return n in self._node - except TypeError: - return False - - def add_edge(self, u_of_edge, v_of_edge, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_of_edge, v_of_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - Adding an edge that already exists updates the edge data. - - Many NetworkX algorithms designed for weighted graphs use - an edge attribute (by default `weight`) to hold a numerical value. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = (1, 2) - >>> G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - - Associate data to edges using keywords: - - >>> G.add_edge(1, 2, weight=3) - >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> G.add_edge(1, 2) - >>> G[1][2].update({0: 5}) - >>> G.edges[1, 2].update({0: 5}) - """ - u, v = u_of_edge, v_of_edge - # add nodes - if u not in self._node: - if u is None: - raise ValueError("None cannot be a node") - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - if v is None: - raise ValueError("None cannot be a node") - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - # add the edge - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - nx._clear_cache(self) - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges must be given as 2-tuples (u, v) or - 3-tuples (u, v, d) where d is a dictionary containing edge data. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - When adding edges from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_edges)`, and pass this - object to `G.add_edges_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label="WN2898") - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - >>> # Grow graph by one new node, adding edges to all existing nodes. - >>> # wrong way - will raise RuntimeError - >>> # G.add_edges_from(((5, n) for n in G.nodes)) - >>> # correct way - note that there will be no self-edge for node 5 - >>> G.add_edges_from(list((5, n) for n in G.nodes)) - """ - for e in ebunch_to_add: - ne = len(e) - if ne == 3: - u, v, dd = e - elif ne == 2: - u, v = e - dd = {} # doesn't need edge_attr_dict_factory - else: - raise NetworkXError(f"Edge tuple {e} must be a 2-tuple or 3-tuple.") - if u not in self._node: - if u is None: - raise ValueError("None cannot be a node") - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - if v is None: - raise ValueError("None cannot be a node") - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - datadict.update(dd) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - nx._clear_cache(self) - - def add_weighted_edges_from(self, ebunch_to_add, weight="weight", **attr): - """Add weighted edges in `ebunch_to_add` with specified weight attr - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the list or container will be added - to the graph. The edges must be given as 3-tuples (u, v, w) - where w is a number. - weight : string, optional (default= 'weight') - The attribute name for the edge weights to be added. - attr : keyword arguments, optional (default= no attributes) - Edge attributes to add/update for all edges. - - See Also - -------- - add_edge : add a single edge - add_edges_from : add multiple edges - - Notes - ----- - Adding the same edge twice for Graph/DiGraph simply updates - the edge data. For MultiGraph/MultiDiGraph, duplicate edges - are stored. - - When adding edges from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_edges)`, and pass this - object to `G.add_weighted_edges_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_weighted_edges_from([(0, 1, 3.0), (1, 2, 7.5)]) - - Evaluate an iterator over edges before passing it - - >>> G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - >>> weight = 0.1 - >>> # Grow graph by one new node, adding edges to all existing nodes. - >>> # wrong way - will raise RuntimeError - >>> # G.add_weighted_edges_from(((5, n, weight) for n in G.nodes)) - >>> # correct way - note that there will be no self-edge for node 5 - >>> G.add_weighted_edges_from(list((5, n, weight) for n in G.nodes)) - """ - self.add_edges_from(((u, v, {weight: d}) for u, v, d in ebunch_to_add), **attr) - nx._clear_cache(self) - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the edge between nodes u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, etc - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - >>> e = (2, 3, {"weight": 7}) # an edge with attribute data - >>> G.remove_edge(*e[:2]) # select first part of edge tuple - """ - try: - del self._adj[u][v] - if u != v: # self-loop needs only one entry removed - del self._adj[v][u] - except KeyError as err: - raise NetworkXError(f"The edge {u}-{v} is not in the graph") from err - nx._clear_cache(self) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) edge between u and v. - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch = [(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - adj = self._adj - for e in ebunch: - u, v = e[:2] # ignore edge data if present - if u in adj and v in adj[u]: - del adj[u][v] - if u != v: # self loop needs only one entry removed - del adj[v][u] - nx._clear_cache(self) - - def update(self, edges=None, nodes=None): - """Update the graph using nodes/edges/graphs as input. - - Like dict.update, this method takes a graph as input, adding the - graph's nodes and edges to this graph. It can also take two inputs: - edges and nodes. Finally it can take either edges or nodes. - To specify only nodes the keyword `nodes` must be used. - - The collections of edges and nodes are treated similarly to - the add_edges_from/add_nodes_from methods. When iterated, they - should yield 2-tuples (u, v) or 3-tuples (u, v, datadict). - - Parameters - ---------- - edges : Graph object, collection of edges, or None - The first parameter can be a graph or some edges. If it has - attributes `nodes` and `edges`, then it is taken to be a - Graph-like object and those attributes are used as collections - of nodes and edges to be added to the graph. - If the first parameter does not have those attributes, it is - treated as a collection of edges and added to the graph. - If the first argument is None, no edges are added. - nodes : collection of nodes, or None - The second parameter is treated as a collection of nodes - to be added to the graph unless it is None. - If `edges is None` and `nodes is None` an exception is raised. - If the first parameter is a Graph, then `nodes` is ignored. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> G.update(nx.complete_graph(range(4, 10))) - >>> from itertools import combinations - >>> edges = ( - ... (u, v, {"power": u * v}) - ... for u, v in combinations(range(10, 20), 2) - ... if u * v < 225 - ... ) - >>> nodes = [1000] # for singleton, use a container - >>> G.update(edges, nodes) - - Notes - ----- - It you want to update the graph using an adjacency structure - it is straightforward to obtain the edges/nodes from adjacency. - The following examples provide common cases, your adjacency may - be slightly different and require tweaks of these examples:: - - >>> # dict-of-set/list/tuple - >>> adj = {1: {2, 3}, 2: {1, 3}, 3: {1, 2}} - >>> e = [(u, v) for u, nbrs in adj.items() for v in nbrs] - >>> G.update(edges=e, nodes=adj) - - >>> DG = nx.DiGraph() - >>> # dict-of-dict-of-attribute - >>> adj = {1: {2: 1.3, 3: 0.7}, 2: {1: 1.4}, 3: {1: 0.7}} - >>> e = [ - ... (u, v, {"weight": d}) - ... for u, nbrs in adj.items() - ... for v, d in nbrs.items() - ... ] - >>> DG.update(edges=e, nodes=adj) - - >>> # dict-of-dict-of-dict - >>> adj = {1: {2: {"weight": 1.3}, 3: {"color": 0.7, "weight": 1.2}}} - >>> e = [ - ... (u, v, {"weight": d}) - ... for u, nbrs in adj.items() - ... for v, d in nbrs.items() - ... ] - >>> DG.update(edges=e, nodes=adj) - - >>> # predecessor adjacency (dict-of-set) - >>> pred = {1: {2, 3}, 2: {3}, 3: {3}} - >>> e = [(v, u) for u, nbrs in pred.items() for v in nbrs] - - >>> # MultiGraph dict-of-dict-of-dict-of-attribute - >>> MDG = nx.MultiDiGraph() - >>> adj = { - ... 1: {2: {0: {"weight": 1.3}, 1: {"weight": 1.2}}}, - ... 3: {2: {0: {"weight": 0.7}}}, - ... } - >>> e = [ - ... (u, v, ekey, d) - ... for u, nbrs in adj.items() - ... for v, keydict in nbrs.items() - ... for ekey, d in keydict.items() - ... ] - >>> MDG.update(edges=e) - - See Also - -------- - add_edges_from: add multiple edges to a graph - add_nodes_from: add multiple nodes to a graph - """ - if edges is not None: - if nodes is not None: - self.add_nodes_from(nodes) - self.add_edges_from(edges) - else: - # check if edges is a Graph object - try: - graph_nodes = edges.nodes - graph_edges = edges.edges - except AttributeError: - # edge not Graph-like - self.add_edges_from(edges) - else: # edges is Graph-like - self.add_nodes_from(graph_nodes.data()) - self.add_edges_from(graph_edges.data()) - self.graph.update(edges.graph) - elif nodes is not None: - self.add_nodes_from(nodes) - else: - raise NetworkXError("update needs nodes or edges input") - - def has_edge(self, u, v): - """Returns True if the edge (u, v) is in the graph. - - This is the same as `v in G[u]` without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> e = (0, 1, {"weight": 7}) - >>> G.has_edge(*e[:2]) # e is a 3-tuple (u, v, data_dictionary) - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives KeyError if 0 not in G - True - - """ - try: - return v in self._adj[u] - except KeyError: - return False - - def neighbors(self, n): - """Returns an iterator over all neighbors of node n. - - This is identical to `iter(G[n])` - - Parameters - ---------- - n : node - A node in the graph - - Returns - ------- - neighbors : iterator - An iterator over all neighbors of node n - - Raises - ------ - NetworkXError - If the node n is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G.neighbors(0)] - [1] - - Notes - ----- - Alternate ways to access the neighbors are ``G.adj[n]`` or ``G[n]``: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge("a", "b", weight=7) - >>> G["a"] - AtlasView({'b': {'weight': 7}}) - >>> G = nx.path_graph(4) - >>> [n for n in G[0]] - [1] - """ - try: - return iter(self._adj[n]) - except KeyError as err: - raise NetworkXError(f"The node {n} is not in the graph.") from err - - @cached_property - def edges(self): - """An EdgeView of the Graph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, default=None) - - The EdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges.data('color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges from these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : EdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.path_graph(3) # or MultiGraph, etc - >>> G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - EdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data("weight", default=1) - EdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges([0, 3]) # only edges from these nodes - EdgeDataView([(0, 1), (3, 2)]) - >>> G.edges(0) # only edges from node 0 - EdgeDataView([(0, 1)]) - """ - return EdgeView(self) - - def get_edge_data(self, u, v, default=None): - """Returns the attribute dictionary associated with edge (u, v). - - This is identical to `G[u][v]` except the default is returned - instead of an exception if the edge doesn't exist. - - Parameters - ---------- - u, v : nodes - default: any Python object (default=None) - Value to return if the edge (u, v) is not found. - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0][1] - {} - - Warning: Assigning to `G[u][v]` is not permitted. - But it is safe to assign attributes `G[u][v]['foo']` - - >>> G[0][1]["weight"] = 7 - >>> G[0][1]["weight"] - 7 - >>> G[1][0]["weight"] - 7 - - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.get_edge_data(0, 1) # default edge data is {} - {} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {} - >>> G.get_edge_data("a", "b", default=0) # edge not in graph, return 0 - 0 - """ - try: - return self._adj[u][v] - except KeyError: - return default - - def adjacency(self): - """Returns an iterator over (node, adjacency dict) tuples for all nodes. - - For directed graphs, only outgoing neighbors/adjacencies are included. - - Returns - ------- - adj_iter : iterator - An iterator over (node, adjacency dictionary) for all nodes in - the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [(n, nbrdict) for n, nbrdict in G.adjacency()] - [(0, {1: {}}), (1, {0: {}, 2: {}}), (2, {1: {}, 3: {}}), (3, {2: {}})] - - """ - return iter(self._adj.items()) - - @cached_property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - DegreeView or int - If multiple nodes are requested (the default), returns a `DegreeView` - mapping nodes to their degree. - If a single node is requested, returns the degree of the node as an integer. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.degree[0] # node 0 has degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - """ - return DegreeView(self) - - def clear(self): - """Remove all nodes and edges from the graph. - - This also removes the name, and all graph, node, and edge attributes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear() - >>> list(G.nodes) - [] - >>> list(G.edges) - [] - - """ - self._adj.clear() - self._node.clear() - self.graph.clear() - nx._clear_cache(self) - - def clear_edges(self): - """Remove all edges from the graph without altering nodes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear_edges() - >>> list(G.nodes) - [0, 1, 2, 3] - >>> list(G.edges) - [] - """ - for nbr_dict in self._adj.values(): - nbr_dict.clear() - nx._clear_cache(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return False - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return False - - def copy(self, as_view=False): - """Returns a copy of the graph. - - The copy method by default returns an independent shallow copy - of the graph and attributes. That is, if an attribute is a - container, that container is shared by the original an the copy. - Use Python's `copy.deepcopy` for new containers. - - If `as_view` is True then a view is returned instead of a copy. - - Notes - ----- - All copies reproduce the graph structure, but data attributes - may be handled in different ways. There are four types of copies - of a graph that people might want. - - Deepcopy -- A "deepcopy" copies the graph structure as well as - all data attributes and any objects they might contain. - The entire graph object is new so that changes in the copy - do not affect the original object. (see Python's copy.deepcopy) - - Data Reference (Shallow) -- For a shallow copy the graph structure - is copied but the edge, node and graph attribute dicts are - references to those in the original graph. This saves - time and memory but could cause confusion if you change an attribute - in one graph and it changes the attribute in the other. - NetworkX does not provide this level of shallow copy. - - Independent Shallow -- This copy creates new independent attribute - dicts and then does a shallow copy of the attributes. That is, any - attributes that are containers are shared between the new graph - and the original. This is exactly what `dict.copy()` provides. - You can obtain this style copy using: - - >>> G = nx.path_graph(5) - >>> H = G.copy() - >>> H = G.copy(as_view=False) - >>> H = nx.Graph(G) - >>> H = G.__class__(G) - - Fresh Data -- For fresh data, the graph structure is copied while - new empty data attribute dicts are created. The resulting graph - is independent of the original and it has no edge, node or graph - attributes. Fresh copies are not enabled. Instead use: - - >>> H = G.__class__() - >>> H.add_nodes_from(G) - >>> H.add_edges_from(G.edges) - - View -- Inspired by dict-views, graph-views act like read-only - versions of the original graph, providing a copy of the original - structure without requiring any memory for copying the information. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Parameters - ---------- - as_view : bool, optional (default=False) - If True, the returned graph-view provides a read-only view - of the original graph without actually copying any data. - - Returns - ------- - G : Graph - A copy of the graph. - - See Also - -------- - to_directed: return a directed copy of the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.copy() - - """ - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - G.add_edges_from( - (u, v, datadict.copy()) - for u, nbrs in self._adj.items() - for v, datadict in nbrs.items() - ) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : DiGraph - A directed graph with the same name, same nodes, and with - each edge (u, v, data) replaced by two directed edges - (u, v, data) and (v, u, data). - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=DiGraph(G) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed Graph to use dict-like objects - in the data structure, those changes do not transfer to the - DiGraph created by this method. - - Examples - -------- - >>> G = nx.Graph() # or MultiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - - If already directed, return a (deep) copy - - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1)] - """ - graph_class = self.to_directed_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from( - (u, v, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, data in nbrs.items() - ) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Parameters - ---------- - as_view : bool (optional, default=False) - If True return a view of the original undirected graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - Graph, copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar `G = nx.DiGraph(D)` which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed DiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - Graph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from( - (u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items() - ) - return G - - def subgraph(self, nodes): - """Returns a SubGraph view of the subgraph induced on `nodes`. - - The induced subgraph of the graph contains the nodes in `nodes` - and the edges between those nodes. - - Parameters - ---------- - nodes : list, iterable - A container of nodes which will be iterated through once. - - Returns - ------- - G : SubGraph View - A subgraph view of the graph. The graph structure cannot be - changed but node/edge attributes can and are shared with the - original graph. - - Notes - ----- - The graph, edge and node attributes are shared with the original graph. - Changes to the graph structure is ruled out by the view, but changes - to attributes are reflected in the original graph. - - To create a subgraph with its own copy of the edge/node attributes use: - G.subgraph(nodes).copy() - - For an inplace reduction of a graph to a subgraph you can remove nodes: - G.remove_nodes_from([n for n in G if n not in set(nodes)]) - - Subgraph views are sometimes NOT what you want. In most cases where - you want to do more than simply look at the induced edges, it makes - more sense to just create the subgraph as its own graph with code like: - - :: - - # Create a subgraph SG based on a (possibly multigraph) G - SG = G.__class__() - SG.add_nodes_from((n, G.nodes[n]) for n in largest_wcc) - if SG.is_multigraph(): - SG.add_edges_from( - (n, nbr, key, d) - for n, nbrs in G.adj.items() - if n in largest_wcc - for nbr, keydict in nbrs.items() - if nbr in largest_wcc - for key, d in keydict.items() - ) - else: - SG.add_edges_from( - (n, nbr, d) - for n, nbrs in G.adj.items() - if n in largest_wcc - for nbr, d in nbrs.items() - if nbr in largest_wcc - ) - SG.graph.update(G.graph) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.subgraph([0, 1, 2]) - >>> list(H.edges) - [(0, 1), (1, 2)] - """ - induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nodes)) - # if already a subgraph, don't make a chain - subgraph = nx.subgraph_view - if hasattr(self, "_NODE_OK"): - return subgraph( - self._graph, filter_node=induced_nodes, filter_edge=self._EDGE_OK - ) - return subgraph(self, filter_node=induced_nodes) - - def edge_subgraph(self, edges): - """Returns the subgraph induced by the specified edges. - - The induced subgraph contains each edge in `edges` and each - node incident to any one of those edges. - - Parameters - ---------- - edges : iterable - An iterable of edges in this graph. - - Returns - ------- - G : Graph - An edge-induced subgraph of this graph with the same edge - attributes. - - Notes - ----- - The graph, edge, and node attributes in the returned subgraph - view are references to the corresponding attributes in the original - graph. The view is read-only. - - To create a full graph version of the subgraph with its own copy - of the edge or node attributes, use:: - - G.edge_subgraph(edges).copy() - - Examples - -------- - >>> G = nx.path_graph(5) - >>> H = G.edge_subgraph([(0, 1), (3, 4)]) - >>> list(H.nodes) - [0, 1, 3, 4] - >>> list(H.edges) - [(0, 1), (3, 4)] - - """ - return nx.edge_subgraph(self, edges) - - def size(self, weight=None): - """Returns the number of edges or total of all edge weights. - - Parameters - ---------- - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - - Returns - ------- - size : numeric - The number of edges or - (if weight keyword is provided) the total weight sum. - - If weight is None, returns an int. Otherwise a float - (or more general numeric if the weights are more general). - - See Also - -------- - number_of_edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.size() - 3 - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge("a", "b", weight=2) - >>> G.add_edge("b", "c", weight=4) - >>> G.size() - 2 - >>> G.size(weight="weight") - 6.0 - """ - s = sum(d for v, d in self.degree(weight=weight)) - # If `weight` is None, the sum of the degrees is guaranteed to be - # even, so we can perform integer division and hence return an - # integer. Otherwise, the sum of the weighted degrees is not - # guaranteed to be an integer, so we perform "real" division. - return s // 2 if weight is None else s / 2 - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (default=all edges) - If u and v are specified, return the number of edges between - u and v. Otherwise return the total number of all edges. - - Returns - ------- - nedges : int - The number of edges in the graph. If nodes `u` and `v` are - specified return the number of edges between those nodes. If - the graph is directed, this only returns the number of edges - from `u` to `v`. - - See Also - -------- - size - - Examples - -------- - For undirected graphs, this method counts the total number of - edges in the graph: - - >>> G = nx.path_graph(4) - >>> G.number_of_edges() - 3 - - If you specify two nodes, this counts the total number of edges - joining the two nodes: - - >>> G.number_of_edges(0, 1) - 1 - - For directed graphs, this method can count the total number of - directed edges from `u` to `v`: - - >>> G = nx.DiGraph() - >>> G.add_edge(0, 1) - >>> G.add_edge(1, 0) - >>> G.number_of_edges(0, 1) - 1 - - """ - if u is None: - return int(self.size()) - if v in self._adj[u]: - return 1 - return 0 - - def nbunch_iter(self, nbunch=None): - """Returns an iterator over nodes contained in nbunch that are - also in the graph. - - The nodes in nbunch are checked for membership in the graph - and if not are silently ignored. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - Returns - ------- - niter : iterator - An iterator over nodes in nbunch that are also in the graph. - If nbunch is None, iterate over all nodes in the graph. - - Raises - ------ - NetworkXError - If nbunch is not a node or sequence of nodes. - If a node in nbunch is not hashable. - - See Also - -------- - Graph.__iter__ - - Notes - ----- - When nbunch is an iterator, the returned iterator yields values - directly from nbunch, becoming exhausted when nbunch is exhausted. - - To test whether nbunch is a single node, one can use - "if nbunch in self:", even after processing with this routine. - - If nbunch is not a node or a (possibly empty) sequence/iterator - or None, a :exc:`NetworkXError` is raised. Also, if any object in - nbunch is not hashable, a :exc:`NetworkXError` is raised. - """ - if nbunch is None: # include all nodes via iterator - bunch = iter(self._adj) - elif nbunch in self: # if nbunch is a single node - bunch = iter([nbunch]) - else: # if nbunch is a sequence of nodes - - def bunch_iter(nlist, adj): - try: - for n in nlist: - if n in adj: - yield n - except TypeError as err: - exc, message = err, err.args[0] - # capture error for non-sequence/iterator nbunch. - if "iter" in message: - exc = NetworkXError( - "nbunch is not a node or a sequence of nodes." - ) - # capture error for unhashable node. - if "hashable" in message: - exc = NetworkXError( - f"Node {n} in sequence nbunch is not a valid node." - ) - raise exc - - bunch = bunch_iter(nbunch, self._adj) - return bunch diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/graphviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/graphviews.py deleted file mode 100644 index 0b09df6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/graphviews.py +++ /dev/null @@ -1,269 +0,0 @@ -"""View of Graphs as SubGraph, Reverse, Directed, Undirected. - -In some algorithms it is convenient to temporarily morph -a graph to exclude some nodes or edges. It should be better -to do that via a view than to remove and then re-add. -In other algorithms it is convenient to temporarily morph -a graph to reverse directed edges, or treat a directed graph -as undirected, etc. This module provides those graph views. - -The resulting views are essentially read-only graphs that -report data from the original graph object. We provide an -attribute G._graph which points to the underlying graph object. - -Note: Since graphviews look like graphs, one can end up with -view-of-view-of-view chains. Be careful with chains because -they become very slow with about 15 nested views. -For the common simple case of node induced subgraphs created -from the graph class, we short-cut the chain by returning a -subgraph of the original graph directly rather than a subgraph -of a subgraph. We are careful not to disrupt any edge filter in -the middle subgraph. In general, determining how to short-cut -the chain is tricky and much harder with restricted_views than -with induced subgraphs. -Often it is easiest to use .copy() to avoid chains. -""" - -import networkx as nx -from networkx.classes.coreviews import ( - FilterAdjacency, - FilterAtlas, - FilterMultiAdjacency, - UnionAdjacency, - UnionMultiAdjacency, -) -from networkx.classes.filters import no_filter -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for - -__all__ = ["generic_graph_view", "subgraph_view", "reverse_view"] - - -def generic_graph_view(G, create_using=None): - """Returns a read-only view of `G`. - - The graph `G` and its attributes are not copied but viewed through the new graph object - of the same class as `G` (or of the class specified in `create_using`). - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - create_using : NetworkX graph constructor, optional (default=None) - Graph type to create. If graph instance, then cleared before populated. - If `None`, then the appropriate Graph type is inferred from `G`. - - Returns - ------- - newG : graph - A view of the input graph `G` and its attributes as viewed through - the `create_using` class. - - Raises - ------ - NetworkXError - If `G` is a multigraph (or multidigraph) but `create_using` is not, or vice versa. - - Notes - ----- - The returned graph view is read-only (cannot modify the graph). - Yet the view reflects any changes in `G`. The intent is to mimic dict views. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=0.3) - >>> G.add_edge(2, 3, weight=0.5) - >>> G.edges(data=True) - EdgeDataView([(1, 2, {'weight': 0.3}), (2, 3, {'weight': 0.5})]) - - The view exposes the attributes from the original graph. - - >>> viewG = nx.graphviews.generic_graph_view(G) - >>> viewG.edges(data=True) - EdgeDataView([(1, 2, {'weight': 0.3}), (2, 3, {'weight': 0.5})]) - - Changes to `G` are reflected in `viewG`. - - >>> G.remove_edge(2, 3) - >>> G.edges(data=True) - EdgeDataView([(1, 2, {'weight': 0.3})]) - - >>> viewG.edges(data=True) - EdgeDataView([(1, 2, {'weight': 0.3})]) - - We can change the graph type with the `create_using` parameter. - - >>> type(G) - - >>> viewDG = nx.graphviews.generic_graph_view(G, create_using=nx.DiGraph) - >>> type(viewDG) - - """ - if create_using is None: - newG = G.__class__() - else: - newG = nx.empty_graph(0, create_using) - if G.is_multigraph() != newG.is_multigraph(): - raise NetworkXError("Multigraph for G must agree with create_using") - newG = nx.freeze(newG) - - # create view by assigning attributes from G - newG._graph = G - newG.graph = G.graph - - newG._node = G._node - if newG.is_directed(): - if G.is_directed(): - newG._succ = G._succ - newG._pred = G._pred - # newG._adj is synced with _succ - else: - newG._succ = G._adj - newG._pred = G._adj - # newG._adj is synced with _succ - elif G.is_directed(): - if G.is_multigraph(): - newG._adj = UnionMultiAdjacency(G._succ, G._pred) - else: - newG._adj = UnionAdjacency(G._succ, G._pred) - else: - newG._adj = G._adj - return newG - - -def subgraph_view(G, *, filter_node=no_filter, filter_edge=no_filter): - """View of `G` applying a filter on nodes and edges. - - `subgraph_view` provides a read-only view of the input graph that excludes - nodes and edges based on the outcome of two filter functions `filter_node` - and `filter_edge`. - - The `filter_node` function takes one argument --- the node --- and returns - `True` if the node should be included in the subgraph, and `False` if it - should not be included. - - The `filter_edge` function takes two (or three arguments if `G` is a - multi-graph) --- the nodes describing an edge, plus the edge-key if - parallel edges are possible --- and returns `True` if the edge should be - included in the subgraph, and `False` if it should not be included. - - Both node and edge filter functions are called on graph elements as they - are queried, meaning there is no up-front cost to creating the view. - - Parameters - ---------- - G : networkx.Graph - A directed/undirected graph/multigraph - - filter_node : callable, optional - A function taking a node as input, which returns `True` if the node - should appear in the view. - - filter_edge : callable, optional - A function taking as input the two nodes describing an edge (plus the - edge-key if `G` is a multi-graph), which returns `True` if the edge - should appear in the view. - - Returns - ------- - graph : networkx.Graph - A read-only graph view of the input graph. - - Examples - -------- - >>> G = nx.path_graph(6) - - Filter functions operate on the node, and return `True` if the node should - appear in the view: - - >>> def filter_node(n1): - ... return n1 != 5 - >>> view = nx.subgraph_view(G, filter_node=filter_node) - >>> view.nodes() - NodeView((0, 1, 2, 3, 4)) - - We can use a closure pattern to filter graph elements based on additional - data --- for example, filtering on edge data attached to the graph: - - >>> G[3][4]["cross_me"] = False - >>> def filter_edge(n1, n2): - ... return G[n1][n2].get("cross_me", True) - >>> view = nx.subgraph_view(G, filter_edge=filter_edge) - >>> view.edges() - EdgeView([(0, 1), (1, 2), (2, 3), (4, 5)]) - - >>> view = nx.subgraph_view( - ... G, - ... filter_node=filter_node, - ... filter_edge=filter_edge, - ... ) - >>> view.nodes() - NodeView((0, 1, 2, 3, 4)) - >>> view.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - """ - newG = nx.freeze(G.__class__()) - newG._NODE_OK = filter_node - newG._EDGE_OK = filter_edge - - # create view by assigning attributes from G - newG._graph = G - newG.graph = G.graph - - newG._node = FilterAtlas(G._node, filter_node) - if G.is_multigraph(): - Adj = FilterMultiAdjacency - - def reverse_edge(u, v, k=None): - return filter_edge(v, u, k) - - else: - Adj = FilterAdjacency - - def reverse_edge(u, v, k=None): - return filter_edge(v, u) - - if G.is_directed(): - newG._succ = Adj(G._succ, filter_node, filter_edge) - newG._pred = Adj(G._pred, filter_node, reverse_edge) - # newG._adj is synced with _succ - else: - newG._adj = Adj(G._adj, filter_node, filter_edge) - return newG - - -@not_implemented_for("undirected") -def reverse_view(G): - """View of `G` with edge directions reversed - - `reverse_view` returns a read-only view of the input graph where - edge directions are reversed. - - Identical to digraph.reverse(copy=False) - - Parameters - ---------- - G : networkx.DiGraph - - Returns - ------- - graph : networkx.DiGraph - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2) - >>> G.add_edge(2, 3) - >>> G.edges() - OutEdgeView([(1, 2), (2, 3)]) - - >>> view = nx.reverse_view(G) - >>> view.edges() - OutEdgeView([(2, 1), (3, 2)]) - """ - newG = generic_graph_view(G) - newG._succ, newG._pred = G._pred, G._succ - # newG._adj is synced with _succ - return newG diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/multidigraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/multidigraph.py deleted file mode 100644 index 597af79..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/multidigraph.py +++ /dev/null @@ -1,966 +0,0 @@ -"""Base class for MultiDiGraph.""" - -from copy import deepcopy -from functools import cached_property - -import networkx as nx -from networkx import convert -from networkx.classes.coreviews import MultiAdjacencyView -from networkx.classes.digraph import DiGraph -from networkx.classes.multigraph import MultiGraph -from networkx.classes.reportviews import ( - DiMultiDegreeView, - InMultiDegreeView, - InMultiEdgeView, - OutMultiDegreeView, - OutMultiEdgeView, -) -from networkx.exception import NetworkXError - -__all__ = ["MultiDiGraph"] - - -class MultiDiGraph(MultiGraph, DiGraph): - """A directed graph class that can store multiedges. - - Multiedges are multiple edges between two nodes. Each edge - can hold optional data or attributes. - - A MultiDiGraph holds directed edges. Self loops are allowed. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, 2D NumPy array, SciPy - sparse matrix, or PyGraphviz graph. - - multigraph_input : bool or None (default None) - Note: Only used when `incoming_graph_data` is a dict. - If True, `incoming_graph_data` is assumed to be a - dict-of-dict-of-dict-of-dict structure keyed by - node to neighbor to edge keys to edge data for multi-edges. - A NetworkXError is raised if this is not the case. - If False, :func:`to_networkx_graph` is used to try to determine - the dict's graph data structure as either a dict-of-dict-of-dict - keyed by node to neighbor to edge data, or a dict-of-iterable - keyed by node to neighbors. - If None, the treatment for True is tried, but if it fails, - the treatment for False is tried. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - DiGraph - MultiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.MultiDiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> key = G.add_edge(1, 2) - - a list of edges, - - >>> keys = G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> keys = G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. If an edge already exists, an additional - edge is created and stored using a key to identify the edge. - By default the key is the lowest unused integer. - - >>> keys = G.add_edges_from([(4, 5, dict(route=282)), (4, 5, dict(route=37))]) - >>> G[4] - AdjacencyView({5: {0: {}, 1: {'route': 282}, 2: {'route': 37}}}) - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.MultiDiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time="5pm") - >>> G.add_nodes_from([3], time="2pm") - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]["room"] = 714 - >>> del G.nodes[1]["room"] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> key = G.add_edge(1, 2, weight=4.7) - >>> keys = G.add_edges_from([(3, 4), (4, 5)], color="red") - >>> keys = G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})]) - >>> G[1][2][0]["weight"] = 4.7 - >>> G.edges[1, 2, 0]["weight"] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, - 2, 0]` a read-only dict-like structure. However, you can assign to - attributes in e.g. `G.edges[1, 2, 0]`. Thus, use 2 sets of brackets - to add/change data attributes: `G.edges[1, 2, 0]['weight'] = 4` - (for multigraphs the edge key is required: `MG.edges[u, v, - key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - >>> G[1] # adjacency dict-like view mapping neighbor -> edge key -> edge attributes - AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}}) - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are available as an adjacency-view `G.adj` object or via - the method `G.adjacency()`. - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, keydict in nbrsdict.items(): - ... for key, eattr in keydict.items(): - ... if "weight" in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, keys, weight in G.edges(data="weight", keys=True): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using methods and object-attributes. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes`, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n]`, `edges[u, v, k]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The MultiDiGraph class uses a dict-of-dict-of-dict-of-dict structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information - and holds edge_key dicts keyed by neighbor. The edge_key dict holds - each edge_attr dict keyed by edge key. The inner dict - (edge_attr_dict) represents the edge data and holds edge attribute - values keyed by attribute names. - - Each of these four dicts in the dict-of-dict-of-dict-of-dict - structure can be replaced by a user defined dict-like object. - In general, the dict-like features should be maintained but - extra features can be added. To replace one of the dicts create - a new graph class by changing the class(!) variable holding the - factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory - and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds multiedge key dicts keyed by neighbor. - It should require no arguments and return a dict-like object. - - edge_key_dict_factory : function, (default: dict) - Factory function to be used to create the edge key dict - which holds edge data keyed by edge key. - It should require no arguments and return a dict-like object. - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - **Subclassing Example** - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {"weight": 1} - ... - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - """ - - # node_dict_factory = dict # already assigned in Graph - # adjlist_outer_dict_factory = dict - # adjlist_inner_dict_factory = dict - edge_key_dict_factory = dict - # edge_attr_dict_factory = dict - - def __init__(self, incoming_graph_data=None, multigraph_input=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph - Data to initialize graph. If incoming_graph_data=None (default) - an empty graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a 2D NumPy array, a - SciPy sparse array, or a PyGraphviz graph. - - multigraph_input : bool or None (default None) - Note: Only used when `incoming_graph_data` is a dict. - If True, `incoming_graph_data` is assumed to be a - dict-of-dict-of-dict-of-dict structure keyed by - node to neighbor to edge keys to edge data for multi-edges. - A NetworkXError is raised if this is not the case. - If False, :func:`to_networkx_graph` is used to try to determine - the dict's graph data structure as either a dict-of-dict-of-dict - keyed by node to neighbor to edge data, or a dict-of-iterable - keyed by node to neighbors. - If None, the treatment for True is tried, but if it fails, - the treatment for False is tried. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name="my graph") - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - # multigraph_input can be None/True/False. So check "is not False" - if isinstance(incoming_graph_data, dict) and multigraph_input is not False: - DiGraph.__init__(self) - try: - convert.from_dict_of_dicts( - incoming_graph_data, create_using=self, multigraph_input=True - ) - self.graph.update(attr) - except Exception as err: - if multigraph_input is True: - raise nx.NetworkXError( - f"converting multigraph_input raised:\n{type(err)}: {err}" - ) - DiGraph.__init__(self, incoming_graph_data, **attr) - else: - DiGraph.__init__(self, incoming_graph_data, **attr) - - @cached_property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return MultiAdjacencyView(self._succ) - - @cached_property - def succ(self): - """Graph adjacency object holding the successors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.succ` is identical to `G.adj`. - """ - return MultiAdjacencyView(self._succ) - - @cached_property - def pred(self): - """Graph adjacency object holding the predecessors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - """ - return MultiAdjacencyView(self._pred) - - def add_edge(self, u_for_edge, v_for_edge, key=None, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_for_edge, v_for_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - key : hashable identifier, optional (default=lowest unused integer) - Used to distinguish multiedges between a pair of nodes. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - The edge key assigned to the edge. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - To replace/update edge data, use the optional key argument - to identify a unique edge. Otherwise a new edge will be created. - - NetworkX algorithms designed for weighted graphs cannot use - multigraphs directly because it is not clear how to handle - multiedge weights. Convert to Graph using edge attribute - 'weight' to enable weighted graph algorithms. - - Default keys are generated using the method `new_edge_key()`. - This method can be overridden by subclassing the base class and - providing a custom `new_edge_key()` method. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.MultiDiGraph() - >>> e = (1, 2) - >>> key = G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - 1 - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - [2] - - Associate data to edges using keywords: - - >>> key = G.add_edge(1, 2, weight=3) - >>> key = G.add_edge(1, 2, key=0, weight=4) # update data for key=0 - >>> key = G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> ekey = G.add_edge(1, 2) - >>> G[1][2][0].update({0: 5}) - >>> G.edges[1, 2, 0].update({0: 5}) - """ - u, v = u_for_edge, v_for_edge - # add nodes - if u not in self._succ: - if u is None: - raise ValueError("None cannot be a node") - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - if v is None: - raise ValueError("None cannot be a node") - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - if key is None: - key = self.new_edge_key(u, v) - if v in self._succ[u]: - keydict = self._adj[u][v] - datadict = keydict.get(key, self.edge_attr_dict_factory()) - datadict.update(attr) - keydict[key] = datadict - else: - # selfloops work this way without special treatment - datadict = self.edge_attr_dict_factory() - datadict.update(attr) - keydict = self.edge_key_dict_factory() - keydict[key] = datadict - self._succ[u][v] = keydict - self._pred[v][u] = keydict - nx._clear_cache(self) - return key - - def remove_edge(self, u, v, key=None): - """Remove an edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove an edge between nodes u and v. - key : hashable identifier, optional (default=None) - Used to distinguish multiple edges between a pair of nodes. - If None, remove a single edge between u and v. If there are - multiple edges, removes the last edge added in terms of - insertion order. - - Raises - ------ - NetworkXError - If there is not an edge between u and v, or - if there is no edge with the specified key. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - - For multiple edges - - >>> G = nx.MultiDiGraph() - >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned - [0, 1, 2] - - When ``key=None`` (the default), edges are removed in the opposite - order that they were added: - - >>> G.remove_edge(1, 2) - >>> G.edges(keys=True) - OutMultiEdgeView([(1, 2, 0), (1, 2, 1)]) - - For edges with keys - - >>> G = nx.MultiDiGraph() - >>> G.add_edge(1, 2, key="first") - 'first' - >>> G.add_edge(1, 2, key="second") - 'second' - >>> G.remove_edge(1, 2, key="first") - >>> G.edges(keys=True) - OutMultiEdgeView([(1, 2, 'second')]) - - """ - try: - d = self._adj[u][v] - except KeyError as err: - raise NetworkXError(f"The edge {u}-{v} is not in the graph.") from err - # remove the edge with specified data - if key is None: - d.popitem() - else: - try: - del d[key] - except KeyError as err: - msg = f"The edge {u}-{v} with key {key} is not in the graph." - raise NetworkXError(msg) from err - if len(d) == 0: - # remove the key entries if last edge - del self._succ[u][v] - del self._pred[v][u] - nx._clear_cache(self) - - @cached_property - def edges(self): - """An OutMultiEdgeView of the Graph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, keys=False, default=None) - - The OutMultiEdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, ``G.edges[u, v, k]['color']`` provides the value of the color - attribute for the edge from ``u`` to ``v`` with key ``k`` while - ``for (u, v, k, c) in G.edges(data='color', default='red', keys=True):`` - iterates through all the edges yielding the color attribute with - default `'red'` if no color attribute exists. - - Edges are returned as tuples with optional data and keys - in the order (node, neighbor, key, data). If ``keys=True`` is not - provided, the tuples will just be (node, neighbor, data), but - multiple tuples with the same node and neighbor will be - generated when multiple edges between two nodes exist. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges from these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge, creating (u, v, k, - d) tuples when data is also requested (the default) and (u, - v, k) tuples when data is not requested. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : OutMultiEdgeView - A view of edge attributes, usually it iterates over (u, v) - (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as ``edges[u, v, k]['foo']``. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2]) - >>> key = G.add_edge(2, 3, weight=5) - >>> key2 = G.add_edge(1, 2) # second edge between these nodes - >>> [e for e in G.edges()] - [(0, 1), (1, 2), (1, 2), (2, 3)] - >>> list(G.edges(data=True)) # default data is {} (empty dict) - [(0, 1, {}), (1, 2, {}), (1, 2, {}), (2, 3, {'weight': 5})] - >>> list(G.edges(data="weight", default=1)) - [(0, 1, 1), (1, 2, 1), (1, 2, 1), (2, 3, 5)] - >>> list(G.edges(keys=True)) # default keys are integers - [(0, 1, 0), (1, 2, 0), (1, 2, 1), (2, 3, 0)] - >>> list(G.edges(data=True, keys=True)) - [(0, 1, 0, {}), (1, 2, 0, {}), (1, 2, 1, {}), (2, 3, 0, {'weight': 5})] - >>> list(G.edges(data="weight", default=1, keys=True)) - [(0, 1, 0, 1), (1, 2, 0, 1), (1, 2, 1, 1), (2, 3, 0, 5)] - >>> list(G.edges([0, 2])) - [(0, 1), (2, 3)] - >>> list(G.edges(0)) - [(0, 1)] - >>> list(G.edges(1)) - [(1, 2), (1, 2)] - - See Also - -------- - in_edges, out_edges - """ - return OutMultiEdgeView(self) - - # alias out_edges to edges - @cached_property - def out_edges(self): - return OutMultiEdgeView(self) - - out_edges.__doc__ = edges.__doc__ - - @cached_property - def in_edges(self): - """A view of the in edges of the graph as G.in_edges or G.in_edges(). - - in_edges(self, nbunch=None, data=False, keys=False, default=None) - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge, creating 3-tuples - (u, v, k) or with data, 4-tuples (u, v, k, d). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - in_edges : InMultiEdgeView or InMultiEdgeDataView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as `edges[u, v, k]['foo']`. - - See Also - -------- - edges - """ - return InMultiEdgeView(self) - - @cached_property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - DiMultiDegreeView or int - If multiple nodes are requested (the default), returns a `DiMultiDegreeView` - mapping nodes to their degree. - If a single node is requested, returns the degree of the node as an integer. - - See Also - -------- - out_degree, in_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - >>> G.add_edge(0, 1) # parallel edge - 1 - >>> list(G.degree([0, 1, 2])) # parallel edges are counted - [(0, 2), (1, 3), (2, 2)] - - """ - return DiMultiDegreeView(self) - - @cached_property - def in_degree(self): - """A DegreeView for (node, in_degree) or in_degree for single node. - - The node in-degree is the number of edges pointing into the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, in-degree). - - See Also - -------- - degree, out_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.in_degree(0) # node 0 with degree 0 - 0 - >>> list(G.in_degree([0, 1, 2])) - [(0, 0), (1, 1), (2, 1)] - >>> G.add_edge(0, 1) # parallel edge - 1 - >>> list(G.in_degree([0, 1, 2])) # parallel edges counted - [(0, 0), (1, 2), (2, 1)] - - """ - return InMultiDegreeView(self) - - @cached_property - def out_degree(self): - """Returns an iterator for (node, out-degree) or out-degree for single node. - - out_degree(self, nbunch=None, weight=None) - - The node out-degree is the number of edges pointing out of the node. - This function returns the out-degree for a single node or an iterator - for a bunch of nodes or if nothing is passed as argument. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, out-degree). - - See Also - -------- - degree, in_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.out_degree(0) # node 0 with degree 1 - 1 - >>> list(G.out_degree([0, 1, 2])) - [(0, 1), (1, 1), (2, 1)] - >>> G.add_edge(0, 1) # parallel edge - 1 - >>> list(G.out_degree([0, 1, 2])) # counts parallel edges - [(0, 2), (1, 1), (2, 1)] - - """ - return OutMultiDegreeView(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return True - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return True - - def to_undirected(self, reciprocal=False, as_view=False): - """Returns an undirected representation of the digraph. - - Parameters - ---------- - reciprocal : bool (optional) - If True only keep edges that appear in both directions - in the original digraph. - as_view : bool (optional, default=False) - If True return an undirected view of the original directed graph. - - Returns - ------- - G : MultiGraph - An undirected graph with the same name and nodes and - with edge (u, v, data) if either (u, v, data) or (v, u, data) - is in the digraph. If both edges exist in digraph and - their edge data is different, only one edge is created - with an arbitrary choice of which edge data to use. - You must check and correct for this manually if desired. - - See Also - -------- - MultiGraph, copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=MultiDiGraph(G) which - returns a shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed MultiDiGraph to use dict-like - objects in the data structure, those changes do not transfer - to the MultiGraph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - if reciprocal is True: - G.add_edges_from( - (u, v, key, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, data in keydict.items() - if v in self._pred[u] and key in self._pred[u][v] - ) - else: - G.add_edges_from( - (u, v, key, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, data in keydict.items() - ) - return G - - def reverse(self, copy=True): - """Returns the reverse of the graph. - - The reverse is a graph with the same nodes and edges - but with the directions of the edges reversed. - - Parameters - ---------- - copy : bool optional (default=True) - If True, return a new DiGraph holding the reversed edges. - If False, the reverse graph is created using a view of - the original graph. - """ - if copy: - H = self.__class__() - H.graph.update(deepcopy(self.graph)) - H.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - H.add_edges_from( - (v, u, k, deepcopy(d)) - for u, v, k, d in self.edges(keys=True, data=True) - ) - return H - return nx.reverse_view(self) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/multigraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/multigraph.py deleted file mode 100644 index 0e3f1ae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/multigraph.py +++ /dev/null @@ -1,1283 +0,0 @@ -"""Base class for MultiGraph.""" - -from copy import deepcopy -from functools import cached_property - -import networkx as nx -from networkx import NetworkXError, convert -from networkx.classes.coreviews import MultiAdjacencyView -from networkx.classes.graph import Graph -from networkx.classes.reportviews import MultiDegreeView, MultiEdgeView - -__all__ = ["MultiGraph"] - - -class MultiGraph(Graph): - """ - An undirected graph class that can store multiedges. - - Multiedges are multiple edges between two nodes. Each edge - can hold optional data or attributes. - - A MultiGraph holds undirected edges. Self loops are allowed. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes, in a MultiGraph each edge has a key to - distinguish between multiple edges that have the same source and - destination nodes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, 2D NumPy array, - SciPy sparse array, or PyGraphviz graph. - - multigraph_input : bool or None (default None) - Note: Only used when `incoming_graph_data` is a dict. - If True, `incoming_graph_data` is assumed to be a - dict-of-dict-of-dict-of-dict structure keyed by - node to neighbor to edge keys to edge data for multi-edges. - A NetworkXError is raised if this is not the case. - If False, :func:`to_networkx_graph` is used to try to determine - the dict's graph data structure as either a dict-of-dict-of-dict - keyed by node to neighbor to edge data, or a dict-of-iterable - keyed by node to neighbors. - If None, the treatment for True is tried, but if it fails, - the treatment for False is tried. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - DiGraph - MultiDiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.MultiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> key = G.add_edge(1, 2) - - a list of edges, - - >>> keys = G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> keys = G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. If an edge already exists, an additional - edge is created and stored using a key to identify the edge. - By default the key is the lowest unused integer. - - >>> keys = G.add_edges_from([(4, 5, {"route": 28}), (4, 5, {"route": 37})]) - >>> G[4] - AdjacencyView({3: {0: {}}, 5: {0: {}, 1: {'route': 28}, 2: {'route': 37}}}) - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.MultiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time="5pm") - >>> G.add_nodes_from([3], time="2pm") - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]["room"] = 714 - >>> del G.nodes[1]["room"] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> key = G.add_edge(1, 2, weight=4.7) - >>> keys = G.add_edges_from([(3, 4), (4, 5)], color="red") - >>> keys = G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})]) - >>> G[1][2][0]["weight"] = 4.7 - >>> G.edges[1, 2, 0]["weight"] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, - 2, 0]` a read-only dict-like structure. However, you can assign to - attributes in e.g. `G.edges[1, 2, 0]`. Thus, use 2 sets of brackets - to add/change data attributes: `G.edges[1, 2, 0]['weight'] = 4`. - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - >>> G[1] # adjacency dict-like view mapping neighbor -> edge key -> edge attributes - AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}}) - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()`. - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, keydict in nbrsdict.items(): - ... for key, eattr in keydict.items(): - ... if "weight" in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, keys, weight in G.edges(data="weight", keys=True): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using methods and object-attributes. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes`, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n]`, `edges[u, v, k]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The MultiGraph class uses a dict-of-dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information - and holds edge_key dicts keyed by neighbor. The edge_key dict holds - each edge_attr dict keyed by edge key. The inner dict - (edge_attr_dict) represents the edge data and holds edge attribute - values keyed by attribute names. - - Each of these four dicts in the dict-of-dict-of-dict-of-dict - structure can be replaced by a user defined dict-like object. - In general, the dict-like features should be maintained but - extra features can be added. To replace one of the dicts create - a new graph class by changing the class(!) variable holding the - factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory - and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds multiedge key dicts keyed by neighbor. - It should require no arguments and return a dict-like object. - - edge_key_dict_factory : function, (default: dict) - Factory function to be used to create the edge key dict - which holds edge data keyed by edge key. - It should require no arguments and return a dict-like object. - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - **Subclassing Example** - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {"weight": 1} - ... - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - """ - - # node_dict_factory = dict # already assigned in Graph - # adjlist_outer_dict_factory = dict - # adjlist_inner_dict_factory = dict - edge_key_dict_factory = dict - # edge_attr_dict_factory = dict - - def to_directed_class(self): - """Returns the class to use for empty directed copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return nx.MultiDiGraph - - def to_undirected_class(self): - """Returns the class to use for empty undirected copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return MultiGraph - - def __init__(self, incoming_graph_data=None, multigraph_input=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph - Data to initialize graph. If incoming_graph_data=None (default) - an empty graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a 2D NumPy array, a - SciPy sparse array, or a PyGraphviz graph. - - multigraph_input : bool or None (default None) - Note: Only used when `incoming_graph_data` is a dict. - If True, `incoming_graph_data` is assumed to be a - dict-of-dict-of-dict-of-dict structure keyed by - node to neighbor to edge keys to edge data for multi-edges. - A NetworkXError is raised if this is not the case. - If False, :func:`to_networkx_graph` is used to try to determine - the dict's graph data structure as either a dict-of-dict-of-dict - keyed by node to neighbor to edge data, or a dict-of-iterable - keyed by node to neighbors. - If None, the treatment for True is tried, but if it fails, - the treatment for False is tried. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.MultiGraph() - >>> G = nx.MultiGraph(name="my graph") - >>> e = [(1, 2), (1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.MultiGraph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.MultiGraph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - # multigraph_input can be None/True/False. So check "is not False" - if isinstance(incoming_graph_data, dict) and multigraph_input is not False: - Graph.__init__(self) - try: - convert.from_dict_of_dicts( - incoming_graph_data, create_using=self, multigraph_input=True - ) - self.graph.update(attr) - except Exception as err: - if multigraph_input is True: - raise nx.NetworkXError( - f"converting multigraph_input raised:\n{type(err)}: {err}" - ) - Graph.__init__(self, incoming_graph_data, **attr) - else: - Graph.__init__(self, incoming_graph_data, **attr) - - @cached_property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-data-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, edgesdict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - - Examples - -------- - >>> e = [(1, 2), (1, 2), (1, 3), (3, 4)] # list of edges - >>> G = nx.MultiGraph(e) - >>> G.edges[1, 2, 0]["weight"] = 3 - >>> result = set() - >>> for edgekey, data in G[1][2].items(): - ... result.add(data.get("weight", 1)) - >>> result - {1, 3} - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return MultiAdjacencyView(self._adj) - - def new_edge_key(self, u, v): - """Returns an unused key for edges between nodes `u` and `v`. - - The nodes `u` and `v` do not need to be already in the graph. - - Notes - ----- - In the standard MultiGraph class the new key is the number of existing - edges between `u` and `v` (increased if necessary to ensure unused). - The first edge will have key 0, then 1, etc. If an edge is removed - further new_edge_keys may not be in this order. - - Parameters - ---------- - u, v : nodes - - Returns - ------- - key : int - """ - try: - keydict = self._adj[u][v] - except KeyError: - return 0 - key = len(keydict) - while key in keydict: - key += 1 - return key - - def add_edge(self, u_for_edge, v_for_edge, key=None, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_for_edge, v_for_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - key : hashable identifier, optional (default=lowest unused integer) - Used to distinguish multiedges between a pair of nodes. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - The edge key assigned to the edge. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - To replace/update edge data, use the optional key argument - to identify a unique edge. Otherwise a new edge will be created. - - NetworkX algorithms designed for weighted graphs cannot use - multigraphs directly because it is not clear how to handle - multiedge weights. Convert to Graph using edge attribute - 'weight' to enable weighted graph algorithms. - - Default keys are generated using the method `new_edge_key()`. - This method can be overridden by subclassing the base class and - providing a custom `new_edge_key()` method. - - Examples - -------- - The following each add an additional edge e=(1, 2) to graph G: - - >>> G = nx.MultiGraph() - >>> e = (1, 2) - >>> ekey = G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - 1 - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - [2] - - Associate data to edges using keywords: - - >>> ekey = G.add_edge(1, 2, weight=3) - >>> ekey = G.add_edge(1, 2, key=0, weight=4) # update data for key=0 - >>> ekey = G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> ekey = G.add_edge(1, 2) - >>> G[1][2][0].update({0: 5}) - >>> G.edges[1, 2, 0].update({0: 5}) - """ - u, v = u_for_edge, v_for_edge - # add nodes - if u not in self._adj: - if u is None: - raise ValueError("None cannot be a node") - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._adj: - if v is None: - raise ValueError("None cannot be a node") - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - if key is None: - key = self.new_edge_key(u, v) - if v in self._adj[u]: - keydict = self._adj[u][v] - datadict = keydict.get(key, self.edge_attr_dict_factory()) - datadict.update(attr) - keydict[key] = datadict - else: - # selfloops work this way without special treatment - datadict = self.edge_attr_dict_factory() - datadict.update(attr) - keydict = self.edge_key_dict_factory() - keydict[key] = datadict - self._adj[u][v] = keydict - self._adj[v][u] = keydict - nx._clear_cache(self) - return key - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges can be: - - - 2-tuples (u, v) or - - 3-tuples (u, v, d) for an edge data dict d, or - - 3-tuples (u, v, k) for not iterable key k, or - - 4-tuples (u, v, k, d) for an edge with data and key k - - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - A list of edge keys assigned to the edges in `ebunch`. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - Default keys are generated using the method ``new_edge_key()``. - This method can be overridden by subclassing the base class and - providing a custom ``new_edge_key()`` method. - - When adding edges from an iterator over the graph you are changing, - a `RuntimeError` can be raised with message: - `RuntimeError: dictionary changed size during iteration`. This - happens when the graph's underlying dictionary is modified during - iteration. To avoid this error, evaluate the iterator into a separate - object, e.g. by using `list(iterator_of_edges)`, and pass this - object to `G.add_edges_from`. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label="WN2898") - - Evaluate an iterator over a graph if using it to modify the same graph - - >>> G = nx.MultiGraph([(1, 2), (2, 3), (3, 4)]) - >>> # Grow graph by one new node, adding edges to all existing nodes. - >>> # wrong way - will raise RuntimeError - >>> # G.add_edges_from(((5, n) for n in G.nodes)) - >>> # right way - note that there will be no self-edge for node 5 - >>> assigned_keys = G.add_edges_from(list((5, n) for n in G.nodes)) - """ - keylist = [] - for e in ebunch_to_add: - ne = len(e) - if ne == 4: - u, v, key, dd = e - elif ne == 3: - u, v, dd = e - key = None - elif ne == 2: - u, v = e - dd = {} - key = None - else: - msg = f"Edge tuple {e} must be a 2-tuple, 3-tuple or 4-tuple." - raise NetworkXError(msg) - ddd = {} - ddd.update(attr) - try: - ddd.update(dd) - except (TypeError, ValueError): - if ne != 3: - raise - key = dd # ne == 3 with 3rd value not dict, must be a key - key = self.add_edge(u, v, key) - self[u][v][key].update(ddd) - keylist.append(key) - nx._clear_cache(self) - return keylist - - def remove_edge(self, u, v, key=None): - """Remove an edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove an edge between nodes u and v. - key : hashable identifier, optional (default=None) - Used to distinguish multiple edges between a pair of nodes. - If None, remove a single edge between u and v. If there are - multiple edges, removes the last edge added in terms of - insertion order. - - Raises - ------ - NetworkXError - If there is not an edge between u and v, or - if there is no edge with the specified key. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.MultiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - - For multiple edges - - >>> G = nx.MultiGraph() # or MultiDiGraph, etc - >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned - [0, 1, 2] - - When ``key=None`` (the default), edges are removed in the opposite - order that they were added: - - >>> G.remove_edge(1, 2) - >>> G.edges(keys=True) - MultiEdgeView([(1, 2, 0), (1, 2, 1)]) - >>> G.remove_edge(2, 1) # edges are not directed - >>> G.edges(keys=True) - MultiEdgeView([(1, 2, 0)]) - - For edges with keys - - >>> G = nx.MultiGraph() - >>> G.add_edge(1, 2, key="first") - 'first' - >>> G.add_edge(1, 2, key="second") - 'second' - >>> G.remove_edge(1, 2, key="first") - >>> G.edges(keys=True) - MultiEdgeView([(1, 2, 'second')]) - - """ - try: - d = self._adj[u][v] - except KeyError as err: - raise NetworkXError(f"The edge {u}-{v} is not in the graph.") from err - # remove the edge with specified data - if key is None: - d.popitem() - else: - try: - del d[key] - except KeyError as err: - msg = f"The edge {u}-{v} with key {key} is not in the graph." - raise NetworkXError(msg) from err - if len(d) == 0: - # remove the key entries if last edge - del self._adj[u][v] - if u != v: # check for selfloop - del self._adj[v][u] - nx._clear_cache(self) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) A single edge between u and v is removed. - - 3-tuples (u, v, key) The edge identified by key is removed. - - 4-tuples (u, v, key, data) where data is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch = [(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - - Removing multiple copies of edges - - >>> G = nx.MultiGraph() - >>> keys = G.add_edges_from([(1, 2), (1, 2), (1, 2)]) - >>> G.remove_edges_from([(1, 2), (2, 1)]) # edges aren't directed - >>> list(G.edges()) - [(1, 2)] - >>> G.remove_edges_from([(1, 2), (1, 2)]) # silently ignore extra copy - >>> list(G.edges) # now empty graph - [] - - When the edge is a 2-tuple ``(u, v)`` but there are multiple edges between - u and v in the graph, the most recent edge (in terms of insertion - order) is removed. - - >>> G = nx.MultiGraph() - >>> for key in ("x", "y", "a"): - ... k = G.add_edge(0, 1, key=key) - >>> G.edges(keys=True) - MultiEdgeView([(0, 1, 'x'), (0, 1, 'y'), (0, 1, 'a')]) - >>> G.remove_edges_from([(0, 1)]) - >>> G.edges(keys=True) - MultiEdgeView([(0, 1, 'x'), (0, 1, 'y')]) - - """ - for e in ebunch: - try: - self.remove_edge(*e[:3]) - except NetworkXError: - pass - nx._clear_cache(self) - - def has_edge(self, u, v, key=None): - """Returns True if the graph has an edge between nodes u and v. - - This is the same as `v in G[u] or key in G[u][v]` - without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - - key : hashable identifier, optional (default=None) - If specified return True only if the edge with - key is found. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - Can be called either using two nodes u, v, an edge tuple (u, v), - or an edge tuple (u, v, key). - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> G.add_edge(0, 1, key="a") - 'a' - >>> G.has_edge(0, 1, key="a") # specify key - True - >>> G.has_edge(1, 0, key="a") # edges aren't directed - True - >>> e = (0, 1, "a") - >>> G.has_edge(*e) # e is a 3-tuple (u, v, 'a') - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives :exc:`KeyError` if 0 not in G - True - >>> 0 in G[1] # other order; also gives :exc:`KeyError` if 0 not in G - True - - """ - try: - if key is None: - return v in self._adj[u] - else: - return key in self._adj[u][v] - except KeyError: - return False - - @cached_property - def edges(self): - """Returns an iterator over the edges. - - edges(self, nbunch=None, data=False, keys=False, default=None) - - The MultiEdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, ``G.edges[u, v, k]['color']`` provides the value of the color - attribute for the edge from ``u`` to ``v`` with key ``k`` while - ``for (u, v, k, c) in G.edges(data='color', keys=True, default="red"):`` - iterates through all the edges yielding the color attribute with - default `'red'` if no color attribute exists. - - Edges are returned as tuples with optional data and keys - in the order (node, neighbor, key, data). If ``keys=True`` is not - provided, the tuples will just be (node, neighbor, data), but - multiple tuples with the same node and neighbor will be generated - when multiple edges exist between two nodes. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges from these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge, creating (u, v, k) - tuples or (u, v, k, d) tuples if data is also requested. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : MultiEdgeView - A view of edge attributes, usually it iterates over (u, v) - (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as ``edges[u, v, k]['foo']``. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.MultiGraph() - >>> nx.add_path(G, [0, 1, 2]) - >>> key = G.add_edge(2, 3, weight=5) - >>> key2 = G.add_edge(2, 1, weight=2) # multi-edge - >>> [e for e in G.edges()] - [(0, 1), (1, 2), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - MultiEdgeDataView([(0, 1, {}), (1, 2, {}), (1, 2, {'weight': 2}), (2, 3, {'weight': 5})]) - >>> G.edges.data("weight", default=1) - MultiEdgeDataView([(0, 1, 1), (1, 2, 1), (1, 2, 2), (2, 3, 5)]) - >>> G.edges(keys=True) # default keys are integers - MultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 1), (2, 3, 0)]) - >>> G.edges.data(keys=True) - MultiEdgeDataView([(0, 1, 0, {}), (1, 2, 0, {}), (1, 2, 1, {'weight': 2}), (2, 3, 0, {'weight': 5})]) - >>> G.edges.data("weight", default=1, keys=True) - MultiEdgeDataView([(0, 1, 0, 1), (1, 2, 0, 1), (1, 2, 1, 2), (2, 3, 0, 5)]) - >>> G.edges([0, 3]) # Note ordering of tuples from listed sources - MultiEdgeDataView([(0, 1), (3, 2)]) - >>> G.edges([0, 3, 2, 1]) # Note ordering of tuples - MultiEdgeDataView([(0, 1), (3, 2), (2, 1), (2, 1)]) - >>> G.edges(0) - MultiEdgeDataView([(0, 1)]) - """ - return MultiEdgeView(self) - - def get_edge_data(self, u, v, key=None, default=None): - """Returns the attribute dictionary associated with edge (u, v, - key). - - If a key is not provided, returns a dictionary mapping edge keys - to attribute dictionaries for each edge between u and v. - - This is identical to `G[u][v][key]` except the default is returned - instead of an exception is the edge doesn't exist. - - Parameters - ---------- - u, v : nodes - - default : any Python object (default=None) - Value to return if the specific edge (u, v, key) is not - found, OR if there are no edges between u and v and no key - is specified. - - key : hashable identifier, optional (default=None) - Return data only for the edge with specified key, as an - attribute dictionary (rather than a dictionary mapping keys - to attribute dictionaries). - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary, OR a dictionary mapping edge - keys to attribute dictionaries for each of those edges if no - specific key is provided (even if there's only one edge - between u and v). - - Examples - -------- - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> key = G.add_edge(0, 1, key="a", weight=7) - >>> G[0][1]["a"] # key='a' - {'weight': 7} - >>> G.edges[0, 1, "a"] # key='a' - {'weight': 7} - - Warning: we protect the graph data structure by making - `G.edges` and `G[1][2]` read-only dict-like structures. - However, you can assign values to attributes in e.g. - `G.edges[1, 2, 'a']` or `G[1][2]['a']` using an additional - bracket as shown next. You need to specify all edge info - to assign to the edge data associated with an edge. - - >>> G[0][1]["a"]["weight"] = 10 - >>> G.edges[0, 1, "a"]["weight"] = 10 - >>> G[0][1]["a"]["weight"] - 10 - >>> G.edges[1, 0, "a"]["weight"] - 10 - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.edges[0, 1, 0]["weight"] = 5 - >>> G.get_edge_data(0, 1) - {0: {'weight': 5}} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {0: {'weight': 5}} - >>> G.get_edge_data(3, 0) # edge not in graph, returns None - >>> G.get_edge_data(3, 0, default=0) # edge not in graph, return default - 0 - >>> G.get_edge_data(1, 0, 0) # specific key gives back - {'weight': 5} - """ - try: - if key is None: - return self._adj[u][v] - else: - return self._adj[u][v][key] - except KeyError: - return default - - @cached_property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - MultiDegreeView or int - If multiple nodes are requested (the default), returns a `MultiDegreeView` - mapping nodes to their degree. - If a single node is requested, returns the degree of the node as an integer. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1])) - [(0, 1), (1, 2)] - - """ - return MultiDegreeView(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return True - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return False - - def copy(self, as_view=False): - """Returns a copy of the graph. - - The copy method by default returns an independent shallow copy - of the graph and attributes. That is, if an attribute is a - container, that container is shared by the original an the copy. - Use Python's `copy.deepcopy` for new containers. - - If `as_view` is True then a view is returned instead of a copy. - - Notes - ----- - All copies reproduce the graph structure, but data attributes - may be handled in different ways. There are four types of copies - of a graph that people might want. - - Deepcopy -- A "deepcopy" copies the graph structure as well as - all data attributes and any objects they might contain. - The entire graph object is new so that changes in the copy - do not affect the original object. (see Python's copy.deepcopy) - - Data Reference (Shallow) -- For a shallow copy the graph structure - is copied but the edge, node and graph attribute dicts are - references to those in the original graph. This saves - time and memory but could cause confusion if you change an attribute - in one graph and it changes the attribute in the other. - NetworkX does not provide this level of shallow copy. - - Independent Shallow -- This copy creates new independent attribute - dicts and then does a shallow copy of the attributes. That is, any - attributes that are containers are shared between the new graph - and the original. This is exactly what `dict.copy()` provides. - You can obtain this style copy using: - - >>> G = nx.path_graph(5) - >>> H = G.copy() - >>> H = G.copy(as_view=False) - >>> H = nx.Graph(G) - >>> H = G.__class__(G) - - Fresh Data -- For fresh data, the graph structure is copied while - new empty data attribute dicts are created. The resulting graph - is independent of the original and it has no edge, node or graph - attributes. Fresh copies are not enabled. Instead use: - - >>> H = G.__class__() - >>> H.add_nodes_from(G) - >>> H.add_edges_from(G.edges) - - View -- Inspired by dict-views, graph-views act like read-only - versions of the original graph, providing a copy of the original - structure without requiring any memory for copying the information. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Parameters - ---------- - as_view : bool, optional (default=False) - If True, the returned graph-view provides a read-only view - of the original graph without actually copying any data. - - Returns - ------- - G : Graph - A copy of the graph. - - See Also - -------- - to_directed: return a directed copy of the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.copy() - - """ - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - G.add_edges_from( - (u, v, key, datadict.copy()) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items() - ) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : MultiDiGraph - A directed graph with the same name, same nodes, and with - each edge (u, v, k, data) replaced by two directed edges - (u, v, k, data) and (v, u, k, data). - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=MultiDiGraph(G) which - returns a shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed MultiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - MultiDiGraph created by this method. - - Examples - -------- - >>> G = nx.MultiGraph() - >>> G.add_edge(0, 1) - 0 - >>> G.add_edge(0, 1) - 1 - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1)] - - If already directed, return a (deep) copy - - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1) - 0 - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1, 0)] - """ - graph_class = self.to_directed_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from( - (u, v, key, deepcopy(datadict)) - for u, nbrs in self.adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items() - ) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar `G = nx.MultiGraph(D)` - which returns a shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/3/library/copy.html. - - Warning: If you have subclassed MultiGraph to use dict-like - objects in the data structure, those changes do not transfer - to the MultiGraph created by this method. - - Examples - -------- - >>> G = nx.MultiGraph([(0, 1), (0, 1), (1, 2)]) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 2, 0), (2, 1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1, 0), (0, 1, 1), (1, 2, 0)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from( - (u, v, key, deepcopy(datadict)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items() - ) - return G - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (Default=all edges) - If u and v are specified, return the number of edges between - u and v. Otherwise return the total number of all edges. - - Returns - ------- - nedges : int - The number of edges in the graph. If nodes `u` and `v` are - specified return the number of edges between those nodes. If - the graph is directed, this only returns the number of edges - from `u` to `v`. - - See Also - -------- - size - - Examples - -------- - For undirected multigraphs, this method counts the total number - of edges in the graph:: - - >>> G = nx.MultiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 2)]) - [0, 1, 0] - >>> G.number_of_edges() - 3 - - If you specify two nodes, this counts the total number of edges - joining the two nodes:: - - >>> G.number_of_edges(0, 1) - 2 - - For directed multigraphs, this method can count the total number - of directed edges from `u` to `v`:: - - >>> G = nx.MultiDiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 0)]) - [0, 1, 0] - >>> G.number_of_edges(0, 1) - 2 - >>> G.number_of_edges(1, 0) - 1 - - """ - if u is None: - return self.size() - try: - edgedata = self._adj[u][v] - except KeyError: - return 0 # no such edge - return len(edgedata) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/reportviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/reportviews.py deleted file mode 100644 index 789662d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/reportviews.py +++ /dev/null @@ -1,1447 +0,0 @@ -""" -View Classes provide node, edge and degree "views" of a graph. - -Views for nodes, edges and degree are provided for all base graph classes. -A view means a read-only object that is quick to create, automatically -updated when the graph changes, and provides basic access like `n in V`, -`for n in V`, `V[n]` and sometimes set operations. - -The views are read-only iterable containers that are updated as the -graph is updated. As with dicts, the graph should not be updated -while iterating through the view. Views can be iterated multiple times. - -Edge and Node views also allow data attribute lookup. -The resulting attribute dict is writable as `G.edges[3, 4]['color']='red'` -Degree views allow lookup of degree values for single nodes. -Weighted degree is supported with the `weight` argument. - -NodeView -======== - - `V = G.nodes` (or `V = G.nodes()`) allows `len(V)`, `n in V`, set - operations e.g. "G.nodes & H.nodes", and `dd = G.nodes[n]`, where - `dd` is the node data dict. Iteration is over the nodes by default. - -NodeDataView -============ - - To iterate over (node, data) pairs, use arguments to `G.nodes()` - to create a DataView e.g. `DV = G.nodes(data='color', default='red')`. - The DataView iterates as `for n, color in DV` and allows - `(n, 'red') in DV`. Using `DV = G.nodes(data=True)`, the DataViews - use the full datadict in writeable form also allowing contain testing as - `(n, {'color': 'red'}) in VD`. DataViews allow set operations when - data attributes are hashable. - -DegreeView -========== - - `V = G.degree` allows iteration over (node, degree) pairs as well - as lookup: `deg=V[n]`. There are many flavors of DegreeView - for In/Out/Directed/Multi. For Directed Graphs, `G.degree` - counts both in and out going edges. `G.out_degree` and - `G.in_degree` count only specific directions. - Weighted degree using edge data attributes is provide via - `V = G.degree(weight='attr_name')` where any string with the - attribute name can be used. `weight=None` is the default. - No set operations are implemented for degrees, use NodeView. - - The argument `nbunch` restricts iteration to nodes in nbunch. - The DegreeView can still lookup any node even if nbunch is specified. - -EdgeView -======== - - `V = G.edges` or `V = G.edges()` allows iteration over edges as well as - `e in V`, set operations and edge data lookup `dd = G.edges[2, 3]`. - Iteration is over 2-tuples `(u, v)` for Graph/DiGraph. For multigraphs - edges 3-tuples `(u, v, key)` are the default but 2-tuples can be obtained - via `V = G.edges(keys=False)`. - - Set operations for directed graphs treat the edges as a set of 2-tuples. - For undirected graphs, 2-tuples are not a unique representation of edges. - So long as the set being compared to contains unique representations - of its edges, the set operations will act as expected. If the other - set contains both `(0, 1)` and `(1, 0)` however, the result of set - operations may contain both representations of the same edge. - -EdgeDataView -============ - - Edge data can be reported using an EdgeDataView typically created - by calling an EdgeView: `DV = G.edges(data='weight', default=1)`. - The EdgeDataView allows iteration over edge tuples, membership checking - but no set operations. - - Iteration depends on `data` and `default` and for multigraph `keys` - If `data is False` (the default) then iterate over 2-tuples `(u, v)`. - If `data is True` iterate over 3-tuples `(u, v, datadict)`. - Otherwise iterate over `(u, v, datadict.get(data, default))`. - For Multigraphs, if `keys is True`, replace `u, v` with `u, v, key` - to create 3-tuples and 4-tuples. - - The argument `nbunch` restricts edges to those incident to nodes in nbunch. -""" - -from abc import ABC -from collections.abc import Mapping, Set - -import networkx as nx - -__all__ = [ - "NodeView", - "NodeDataView", - "EdgeView", - "OutEdgeView", - "InEdgeView", - "EdgeDataView", - "OutEdgeDataView", - "InEdgeDataView", - "MultiEdgeView", - "OutMultiEdgeView", - "InMultiEdgeView", - "MultiEdgeDataView", - "OutMultiEdgeDataView", - "InMultiEdgeDataView", - "DegreeView", - "DiDegreeView", - "InDegreeView", - "OutDegreeView", - "MultiDegreeView", - "DiMultiDegreeView", - "InMultiDegreeView", - "OutMultiDegreeView", -] - - -# NodeViews -class NodeView(Mapping, Set): - """A NodeView class to act as G.nodes for a NetworkX Graph - - Set operations act on the nodes without considering data. - Iteration is over nodes. Node data can be looked up like a dict. - Use NodeDataView to iterate over node data or to specify a data - attribute for lookup. NodeDataView is created by calling the NodeView. - - Parameters - ---------- - graph : NetworkX graph-like class - - Examples - -------- - >>> G = nx.path_graph(3) - >>> NV = G.nodes() - >>> 2 in NV - True - >>> for n in NV: - ... print(n) - 0 - 1 - 2 - >>> assert NV & {1, 2, 3} == {1, 2} - - >>> G.add_node(2, color="blue") - >>> NV[2] - {'color': 'blue'} - >>> G.add_node(8, color="red") - >>> NDV = G.nodes(data=True) - >>> (2, NV[2]) in NDV - True - >>> for n, dd in NDV: - ... print((n, dd.get("color", "aqua"))) - (0, 'aqua') - (1, 'aqua') - (2, 'blue') - (8, 'red') - >>> NDV[2] == NV[2] - True - - >>> NVdata = G.nodes(data="color", default="aqua") - >>> (2, NVdata[2]) in NVdata - True - >>> for n, dd in NVdata: - ... print((n, dd)) - (0, 'aqua') - (1, 'aqua') - (2, 'blue') - (8, 'red') - >>> NVdata[2] == NV[2] # NVdata gets 'color', NV gets datadict - False - """ - - __slots__ = ("_nodes",) - - def __getstate__(self): - return {"_nodes": self._nodes} - - def __setstate__(self, state): - self._nodes = state["_nodes"] - - def __init__(self, graph): - self._nodes = graph._node - - # Mapping methods - def __len__(self): - return len(self._nodes) - - def __iter__(self): - return iter(self._nodes) - - def __getitem__(self, n): - if isinstance(n, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.nodes)[{n.start}:{n.stop}:{n.step}]" - ) - return self._nodes[n] - - # Set methods - def __contains__(self, n): - return n in self._nodes - - @classmethod - def _from_iterable(cls, it): - return set(it) - - # DataView method - def __call__(self, data=False, default=None): - if data is False: - return self - return NodeDataView(self._nodes, data, default) - - def data(self, data=True, default=None): - """ - Return a read-only view of node data. - - Parameters - ---------- - data : bool or node data key, default=True - If ``data=True`` (the default), return a `NodeDataView` object that - maps each node to *all* of its attributes. `data` may also be an - arbitrary key, in which case the `NodeDataView` maps each node to - the value for the keyed attribute. In this case, if a node does - not have the `data` attribute, the `default` value is used. - default : object, default=None - The value used when a node does not have a specific attribute. - - Returns - ------- - NodeDataView - The layout of the returned NodeDataView depends on the value of the - `data` parameter. - - Notes - ----- - If ``data=False``, returns a `NodeView` object without data. - - See Also - -------- - NodeDataView - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from( - ... [ - ... (0, {"color": "red", "weight": 10}), - ... (1, {"color": "blue"}), - ... (2, {"color": "yellow", "weight": 2}), - ... ] - ... ) - - Accessing node data with ``data=True`` (the default) returns a - NodeDataView mapping each node to all of its attributes: - - >>> G.nodes.data() - NodeDataView({0: {'color': 'red', 'weight': 10}, 1: {'color': 'blue'}, 2: {'color': 'yellow', 'weight': 2}}) - - If `data` represents a key in the node attribute dict, a NodeDataView mapping - the nodes to the value for that specific key is returned: - - >>> G.nodes.data("color") - NodeDataView({0: 'red', 1: 'blue', 2: 'yellow'}, data='color') - - If a specific key is not found in an attribute dict, the value specified - by `default` is returned: - - >>> G.nodes.data("weight", default=-999) - NodeDataView({0: 10, 1: -999, 2: 2}, data='weight') - - Note that there is no check that the `data` key is in any of the - node attribute dictionaries: - - >>> G.nodes.data("height") - NodeDataView({0: None, 1: None, 2: None}, data='height') - """ - if data is False: - return self - return NodeDataView(self._nodes, data, default) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return f"{self.__class__.__name__}({tuple(self)})" - - -class NodeDataView(Set): - """A DataView class for nodes of a NetworkX Graph - - The main use for this class is to iterate through node-data pairs. - The data can be the entire data-dictionary for each node, or it - can be a specific attribute (with default) for each node. - Set operations are enabled with NodeDataView, but don't work in - cases where the data is not hashable. Use with caution. - Typically, set operations on nodes use NodeView, not NodeDataView. - That is, they use `G.nodes` instead of `G.nodes(data='foo')`. - - Parameters - ========== - graph : NetworkX graph-like class - data : bool or string (default=False) - default : object (default=None) - """ - - __slots__ = ("_nodes", "_data", "_default") - - def __getstate__(self): - return {"_nodes": self._nodes, "_data": self._data, "_default": self._default} - - def __setstate__(self, state): - self._nodes = state["_nodes"] - self._data = state["_data"] - self._default = state["_default"] - - def __init__(self, nodedict, data=False, default=None): - self._nodes = nodedict - self._data = data - self._default = default - - @classmethod - def _from_iterable(cls, it): - try: - return set(it) - except TypeError as err: - if "unhashable" in str(err): - msg = " : Could be b/c data=True or your values are unhashable" - raise TypeError(str(err) + msg) from err - raise - - def __len__(self): - return len(self._nodes) - - def __iter__(self): - data = self._data - if data is False: - return iter(self._nodes) - if data is True: - return iter(self._nodes.items()) - return ( - (n, dd[data] if data in dd else self._default) - for n, dd in self._nodes.items() - ) - - def __contains__(self, n): - try: - node_in = n in self._nodes - except TypeError: - n, d = n - return n in self._nodes and self[n] == d - if node_in is True: - return node_in - try: - n, d = n - except (TypeError, ValueError): - return False - return n in self._nodes and self[n] == d - - def __getitem__(self, n): - if isinstance(n, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.nodes.data())[{n.start}:{n.stop}:{n.step}]" - ) - ddict = self._nodes[n] - data = self._data - if data is False or data is True: - return ddict - return ddict[data] if data in ddict else self._default - - def __str__(self): - return str(list(self)) - - def __repr__(self): - name = self.__class__.__name__ - if self._data is False: - return f"{name}({tuple(self)})" - if self._data is True: - return f"{name}({dict(self)})" - return f"{name}({dict(self)}, data={self._data!r})" - - -# DegreeViews -class DiDegreeView: - """A View class for degree of nodes in a NetworkX Graph - - The functionality is like dict.items() with (node, degree) pairs. - Additional functionality includes read-only lookup of node degree, - and calling with optional features nbunch (for only a subset of nodes) - and weight (use edge weights to compute degree). - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : node, container of nodes, or None meaning all nodes (default=None) - weight : bool or string (default=None) - - Notes - ----- - DegreeView can still lookup any node even if nbunch is specified. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> DV = G.degree() - >>> assert DV[2] == 1 - >>> assert sum(deg for n, deg in DV) == 4 - - >>> DVweight = G.degree(weight="span") - >>> G.add_edge(1, 2, span=34) - >>> DVweight[2] - 34 - >>> DVweight[0] # default edge weight is 1 - 1 - >>> sum(span for n, span in DVweight) # sum weighted degrees - 70 - - >>> DVnbunch = G.degree(nbunch=(1, 2)) - >>> assert len(list(DVnbunch)) == 2 # iteration over nbunch only - """ - - def __init__(self, G, nbunch=None, weight=None): - self._graph = G - self._succ = G._succ if hasattr(G, "_succ") else G._adj - self._pred = G._pred if hasattr(G, "_pred") else G._adj - self._nodes = self._succ if nbunch is None else list(G.nbunch_iter(nbunch)) - self._weight = weight - - def __call__(self, nbunch=None, weight=None): - if nbunch is None: - if weight == self._weight: - return self - return self.__class__(self._graph, None, weight) - try: - if nbunch in self._nodes: - if weight == self._weight: - return self[nbunch] - return self.__class__(self._graph, None, weight)[nbunch] - except TypeError: - pass - return self.__class__(self._graph, nbunch, weight) - - def __getitem__(self, n): - weight = self._weight - succs = self._succ[n] - preds = self._pred[n] - if weight is None: - return len(succs) + len(preds) - return sum(dd.get(weight, 1) for dd in succs.values()) + sum( - dd.get(weight, 1) for dd in preds.values() - ) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - yield (n, len(succs) + len(preds)) - else: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum(dd.get(weight, 1) for dd in succs.values()) + sum( - dd.get(weight, 1) for dd in preds.values() - ) - yield (n, deg) - - def __len__(self): - return len(self._nodes) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return f"{self.__class__.__name__}({dict(self)})" - - -class DegreeView(DiDegreeView): - """A DegreeView class to act as G.degree for a NetworkX Graph - - Typical usage focuses on iteration over `(node, degree)` pairs. - The degree is by default the number of edges incident to the node. - Optional argument `weight` enables weighted degree using the edge - attribute named in the `weight` argument. Reporting and iteration - can also be restricted to a subset of nodes using `nbunch`. - - Additional functionality include node lookup so that `G.degree[n]` - reported the (possibly weighted) degree of node `n`. Calling the - view creates a view with different arguments `nbunch` or `weight`. - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : node, container of nodes, or None meaning all nodes (default=None) - weight : string or None (default=None) - - Notes - ----- - DegreeView can still lookup any node even if nbunch is specified. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> DV = G.degree() - >>> assert DV[2] == 1 - >>> assert G.degree[2] == 1 - >>> assert sum(deg for n, deg in DV) == 4 - - >>> DVweight = G.degree(weight="span") - >>> G.add_edge(1, 2, span=34) - >>> DVweight[2] - 34 - >>> DVweight[0] # default edge weight is 1 - 1 - >>> sum(span for n, span in DVweight) # sum weighted degrees - 70 - - >>> DVnbunch = G.degree(nbunch=(1, 2)) - >>> assert len(list(DVnbunch)) == 2 # iteration over nbunch only - """ - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return len(nbrs) + (n in nbrs) - return sum(dd.get(weight, 1) for dd in nbrs.values()) + ( - n in nbrs and nbrs[n].get(weight, 1) - ) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - yield (n, len(nbrs) + (n in nbrs)) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(dd.get(weight, 1) for dd in nbrs.values()) + ( - n in nbrs and nbrs[n].get(weight, 1) - ) - yield (n, deg) - - -class OutDegreeView(DiDegreeView): - """A DegreeView class to report out_degree for a DiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if self._weight is None: - return len(nbrs) - return sum(dd.get(self._weight, 1) for dd in nbrs.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - yield (n, len(succs)) - else: - for n in self._nodes: - succs = self._succ[n] - deg = sum(dd.get(weight, 1) for dd in succs.values()) - yield (n, deg) - - -class InDegreeView(DiDegreeView): - """A DegreeView class to report in_degree for a DiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._pred[n] - if weight is None: - return len(nbrs) - return sum(dd.get(weight, 1) for dd in nbrs.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - preds = self._pred[n] - yield (n, len(preds)) - else: - for n in self._nodes: - preds = self._pred[n] - deg = sum(dd.get(weight, 1) for dd in preds.values()) - yield (n, deg) - - -class MultiDegreeView(DiDegreeView): - """A DegreeView class for undirected multigraphs; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return sum(len(keys) for keys in nbrs.values()) + ( - n in nbrs and len(nbrs[n]) - ) - # edge weighted graph - degree is sum of nbr edge weights - deg = sum( - d.get(weight, 1) for key_dict in nbrs.values() for d in key_dict.values() - ) - if n in nbrs: - deg += sum(d.get(weight, 1) for d in nbrs[n].values()) - return deg - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(len(keys) for keys in nbrs.values()) + ( - n in nbrs and len(nbrs[n]) - ) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum( - d.get(weight, 1) - for key_dict in nbrs.values() - for d in key_dict.values() - ) - if n in nbrs: - deg += sum(d.get(weight, 1) for d in nbrs[n].values()) - yield (n, deg) - - -class DiMultiDegreeView(DiDegreeView): - """A DegreeView class for MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - succs = self._succ[n] - preds = self._pred[n] - if weight is None: - return sum(len(keys) for keys in succs.values()) + sum( - len(keys) for keys in preds.values() - ) - # edge weighted graph - degree is sum of nbr edge weights - deg = sum( - d.get(weight, 1) for key_dict in succs.values() for d in key_dict.values() - ) + sum( - d.get(weight, 1) for key_dict in preds.values() for d in key_dict.values() - ) - return deg - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum(len(keys) for keys in succs.values()) + sum( - len(keys) for keys in preds.values() - ) - yield (n, deg) - else: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum( - d.get(weight, 1) - for key_dict in succs.values() - for d in key_dict.values() - ) + sum( - d.get(weight, 1) - for key_dict in preds.values() - for d in key_dict.values() - ) - yield (n, deg) - - -class InMultiDegreeView(DiDegreeView): - """A DegreeView class for inward degree of MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._pred[n] - if weight is None: - return sum(len(data) for data in nbrs.values()) - # edge weighted graph - degree is sum of nbr edge weights - return sum( - d.get(weight, 1) for key_dict in nbrs.values() for d in key_dict.values() - ) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._pred[n] - deg = sum(len(data) for data in nbrs.values()) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._pred[n] - deg = sum( - d.get(weight, 1) - for key_dict in nbrs.values() - for d in key_dict.values() - ) - yield (n, deg) - - -class OutMultiDegreeView(DiDegreeView): - """A DegreeView class for outward degree of MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return sum(len(data) for data in nbrs.values()) - # edge weighted graph - degree is sum of nbr edge weights - return sum( - d.get(weight, 1) for key_dict in nbrs.values() for d in key_dict.values() - ) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(len(data) for data in nbrs.values()) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum( - d.get(weight, 1) - for key_dict in nbrs.values() - for d in key_dict.values() - ) - yield (n, deg) - - -# A base class for all edge views. Ensures all edge view and edge data view -# objects/classes are captured by `isinstance(obj, EdgeViewABC)` and -# `issubclass(cls, EdgeViewABC)` respectively -class EdgeViewABC(ABC): - pass - - -# EdgeDataViews -class OutEdgeDataView(EdgeViewABC): - """EdgeDataView for outward edges of DiGraph; See EdgeDataView""" - - __slots__ = ( - "_viewer", - "_nbunch", - "_data", - "_default", - "_adjdict", - "_nodes_nbrs", - "_report", - ) - - def __getstate__(self): - return { - "viewer": self._viewer, - "nbunch": self._nbunch, - "data": self._data, - "default": self._default, - } - - def __setstate__(self, state): - self.__init__(**state) - - def __init__(self, viewer, nbunch=None, data=False, *, default=None): - self._viewer = viewer - adjdict = self._adjdict = viewer._adjdict - if nbunch is None: - self._nodes_nbrs = adjdict.items - else: - # dict retains order of nodes but acts like a set - nbunch = dict.fromkeys(viewer._graph.nbunch_iter(nbunch)) - self._nodes_nbrs = lambda: [(n, adjdict[n]) for n in nbunch] - self._nbunch = nbunch - self._data = data - self._default = default - # Set _report based on data and default - if data is True: - self._report = lambda n, nbr, dd: (n, nbr, dd) - elif data is False: - self._report = lambda n, nbr, dd: (n, nbr) - else: # data is attribute name - self._report = ( - lambda n, nbr, dd: (n, nbr, dd[data]) - if data in dd - else (n, nbr, default) - ) - - def __len__(self): - return sum(len(nbrs) for n, nbrs in self._nodes_nbrs()) - - def __iter__(self): - return ( - self._report(n, nbr, dd) - for n, nbrs in self._nodes_nbrs() - for nbr, dd in nbrs.items() - ) - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and u not in self._nbunch: - return False # this edge doesn't start in nbunch - try: - ddict = self._adjdict[u][v] - except KeyError: - return False - return e == self._report(u, v, ddict) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return f"{self.__class__.__name__}({list(self)})" - - -class EdgeDataView(OutEdgeDataView): - """A EdgeDataView class for edges of Graph - - This view is primarily used to iterate over the edges reporting - edges as node-tuples with edge data optionally reported. The - argument `nbunch` allows restriction to edges incident to nodes - in that container/singleton. The default (nbunch=None) - reports all edges. The arguments `data` and `default` control - what edge data is reported. The default `data is False` reports - only node-tuples for each edge. If `data is True` the entire edge - data dict is returned. Otherwise `data` is assumed to hold the name - of the edge attribute to report with default `default` if that - edge attribute is not present. - - Parameters - ---------- - nbunch : container of nodes, node or None (default None) - data : False, True or string (default False) - default : default value (default None) - - Examples - -------- - >>> G = nx.path_graph(3) - >>> G.add_edge(1, 2, foo="bar") - >>> list(G.edges(data="foo", default="biz")) - [(0, 1, 'biz'), (1, 2, 'bar')] - >>> assert (0, 1, "biz") in G.edges(data="foo", default="biz") - """ - - __slots__ = () - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, dd in nbrs.items(): - if nbr not in seen: - yield self._report(n, nbr, dd) - seen[n] = 1 - del seen - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and u not in self._nbunch and v not in self._nbunch: - return False # this edge doesn't start and it doesn't end in nbunch - try: - ddict = self._adjdict[u][v] - except KeyError: - return False - return e == self._report(u, v, ddict) - - -class InEdgeDataView(OutEdgeDataView): - """An EdgeDataView class for outward edges of DiGraph; See EdgeDataView""" - - __slots__ = () - - def __iter__(self): - return ( - self._report(nbr, n, dd) - for n, nbrs in self._nodes_nbrs() - for nbr, dd in nbrs.items() - ) - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and v not in self._nbunch: - return False # this edge doesn't end in nbunch - try: - ddict = self._adjdict[v][u] - except KeyError: - return False - return e == self._report(u, v, ddict) - - -class OutMultiEdgeDataView(OutEdgeDataView): - """An EdgeDataView for outward edges of MultiDiGraph; See EdgeDataView""" - - __slots__ = ("keys",) - - def __getstate__(self): - return { - "viewer": self._viewer, - "nbunch": self._nbunch, - "keys": self.keys, - "data": self._data, - "default": self._default, - } - - def __setstate__(self, state): - self.__init__(**state) - - def __init__(self, viewer, nbunch=None, data=False, *, default=None, keys=False): - self._viewer = viewer - adjdict = self._adjdict = viewer._adjdict - self.keys = keys - if nbunch is None: - self._nodes_nbrs = adjdict.items - else: - # dict retains order of nodes but acts like a set - nbunch = dict.fromkeys(viewer._graph.nbunch_iter(nbunch)) - self._nodes_nbrs = lambda: [(n, adjdict[n]) for n in nbunch] - self._nbunch = nbunch - self._data = data - self._default = default - # Set _report based on data and default - if data is True: - if keys is True: - self._report = lambda n, nbr, k, dd: (n, nbr, k, dd) - else: - self._report = lambda n, nbr, k, dd: (n, nbr, dd) - elif data is False: - if keys is True: - self._report = lambda n, nbr, k, dd: (n, nbr, k) - else: - self._report = lambda n, nbr, k, dd: (n, nbr) - else: # data is attribute name - if keys is True: - self._report = ( - lambda n, nbr, k, dd: (n, nbr, k, dd[data]) - if data in dd - else (n, nbr, k, default) - ) - else: - self._report = ( - lambda n, nbr, k, dd: (n, nbr, dd[data]) - if data in dd - else (n, nbr, default) - ) - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - return ( - self._report(n, nbr, k, dd) - for n, nbrs in self._nodes_nbrs() - for nbr, kd in nbrs.items() - for k, dd in kd.items() - ) - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and u not in self._nbunch: - return False # this edge doesn't start in nbunch - try: - kdict = self._adjdict[u][v] - except KeyError: - return False - if self.keys is True: - k = e[2] - try: - dd = kdict[k] - except KeyError: - return False - return e == self._report(u, v, k, dd) - return any(e == self._report(u, v, k, dd) for k, dd in kdict.items()) - - -class MultiEdgeDataView(OutMultiEdgeDataView): - """An EdgeDataView class for edges of MultiGraph; See EdgeDataView""" - - __slots__ = () - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, kd in nbrs.items(): - if nbr not in seen: - for k, dd in kd.items(): - yield self._report(n, nbr, k, dd) - seen[n] = 1 - del seen - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and u not in self._nbunch and v not in self._nbunch: - return False # this edge doesn't start and doesn't end in nbunch - try: - kdict = self._adjdict[u][v] - except KeyError: - try: - kdict = self._adjdict[v][u] - except KeyError: - return False - if self.keys is True: - k = e[2] - try: - dd = kdict[k] - except KeyError: - return False - return e == self._report(u, v, k, dd) - return any(e == self._report(u, v, k, dd) for k, dd in kdict.items()) - - -class InMultiEdgeDataView(OutMultiEdgeDataView): - """An EdgeDataView for inward edges of MultiDiGraph; See EdgeDataView""" - - __slots__ = () - - def __iter__(self): - return ( - self._report(nbr, n, k, dd) - for n, nbrs in self._nodes_nbrs() - for nbr, kd in nbrs.items() - for k, dd in kd.items() - ) - - def __contains__(self, e): - u, v = e[:2] - if self._nbunch is not None and v not in self._nbunch: - return False # this edge doesn't end in nbunch - try: - kdict = self._adjdict[v][u] - except KeyError: - return False - if self.keys is True: - k = e[2] - dd = kdict[k] - return e == self._report(u, v, k, dd) - return any(e == self._report(u, v, k, dd) for k, dd in kdict.items()) - - -# EdgeViews have set operations and no data reported -class OutEdgeView(Set, Mapping, EdgeViewABC): - """A EdgeView class for outward edges of a DiGraph""" - - __slots__ = ("_adjdict", "_graph", "_nodes_nbrs") - - def __getstate__(self): - return {"_graph": self._graph, "_adjdict": self._adjdict} - - def __setstate__(self, state): - self._graph = state["_graph"] - self._adjdict = state["_adjdict"] - self._nodes_nbrs = self._adjdict.items - - @classmethod - def _from_iterable(cls, it): - return set(it) - - dataview = OutEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._succ if hasattr(G, "succ") else G._adj - self._nodes_nbrs = self._adjdict.items - - # Set methods - def __len__(self): - return sum(len(nbrs) for n, nbrs in self._nodes_nbrs()) - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr in nbrs: - yield (n, nbr) - - def __contains__(self, e): - try: - u, v = e - return v in self._adjdict[u] - except KeyError: - return False - - # Mapping Methods - def __getitem__(self, e): - if isinstance(e, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.edges)[{e.start}:{e.stop}:{e.step}]" - ) - u, v = e - try: - return self._adjdict[u][v] - except KeyError as ex: # Customize msg to indicate exception origin - raise KeyError(f"The edge {e} is not in the graph.") - - # EdgeDataView methods - def __call__(self, nbunch=None, data=False, *, default=None): - if nbunch is None and data is False: - return self - return self.dataview(self, nbunch, data, default=default) - - def data(self, data=True, default=None, nbunch=None): - """ - Return a read-only view of edge data. - - Parameters - ---------- - data : bool or edge attribute key - If ``data=True``, then the data view maps each edge to a dictionary - containing all of its attributes. If `data` is a key in the edge - dictionary, then the data view maps each edge to its value for - the keyed attribute. In this case, if the edge doesn't have the - attribute, the `default` value is returned. - default : object, default=None - The value used when an edge does not have a specific attribute - nbunch : container of nodes, optional (default=None) - Allows restriction to edges only involving certain nodes. All edges - are considered by default. - - Returns - ------- - dataview - Returns an `EdgeDataView` for undirected Graphs, `OutEdgeDataView` - for DiGraphs, `MultiEdgeDataView` for MultiGraphs and - `OutMultiEdgeDataView` for MultiDiGraphs. - - Notes - ----- - If ``data=False``, returns an `EdgeView` without any edge data. - - See Also - -------- - EdgeDataView - OutEdgeDataView - MultiEdgeDataView - OutMultiEdgeDataView - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from( - ... [ - ... (0, 1, {"dist": 3, "capacity": 20}), - ... (1, 2, {"dist": 4}), - ... (2, 0, {"dist": 5}), - ... ] - ... ) - - Accessing edge data with ``data=True`` (the default) returns an - edge data view object listing each edge with all of its attributes: - - >>> G.edges.data() - EdgeDataView([(0, 1, {'dist': 3, 'capacity': 20}), (0, 2, {'dist': 5}), (1, 2, {'dist': 4})]) - - If `data` represents a key in the edge attribute dict, a dataview listing - each edge with its value for that specific key is returned: - - >>> G.edges.data("dist") - EdgeDataView([(0, 1, 3), (0, 2, 5), (1, 2, 4)]) - - `nbunch` can be used to limit the edges: - - >>> G.edges.data("dist", nbunch=[0]) - EdgeDataView([(0, 1, 3), (0, 2, 5)]) - - If a specific key is not found in an edge attribute dict, the value - specified by `default` is used: - - >>> G.edges.data("capacity") - EdgeDataView([(0, 1, 20), (0, 2, None), (1, 2, None)]) - - Note that there is no check that the `data` key is present in any of - the edge attribute dictionaries: - - >>> G.edges.data("speed") - EdgeDataView([(0, 1, None), (0, 2, None), (1, 2, None)]) - """ - if nbunch is None and data is False: - return self - return self.dataview(self, nbunch, data, default=default) - - # String Methods - def __str__(self): - return str(list(self)) - - def __repr__(self): - return f"{self.__class__.__name__}({list(self)})" - - -class EdgeView(OutEdgeView): - """A EdgeView class for edges of a Graph - - This densely packed View allows iteration over edges, data lookup - like a dict and set operations on edges represented by node-tuples. - In addition, edge data can be controlled by calling this object - possibly creating an EdgeDataView. Typically edges are iterated over - and reported as `(u, v)` node tuples or `(u, v, key)` node/key tuples - for multigraphs. Those edge representations can also be using to - lookup the data dict for any edge. Set operations also are available - where those tuples are the elements of the set. - Calling this object with optional arguments `data`, `default` and `keys` - controls the form of the tuple (see EdgeDataView). Optional argument - `nbunch` allows restriction to edges only involving certain nodes. - - If `data is False` (the default) then iterate over 2-tuples `(u, v)`. - If `data is True` iterate over 3-tuples `(u, v, datadict)`. - Otherwise iterate over `(u, v, datadict.get(data, default))`. - For Multigraphs, if `keys is True`, replace `u, v` with `u, v, key` above. - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : (default= all nodes in graph) only report edges with these nodes - keys : (only for MultiGraph. default=False) report edge key in tuple - data : bool or string (default=False) see above - default : object (default=None) - - Examples - ======== - >>> G = nx.path_graph(4) - >>> EV = G.edges() - >>> (2, 3) in EV - True - >>> for u, v in EV: - ... print((u, v)) - (0, 1) - (1, 2) - (2, 3) - >>> assert EV & {(1, 2), (3, 4)} == {(1, 2)} - - >>> EVdata = G.edges(data="color", default="aqua") - >>> G.add_edge(2, 3, color="blue") - >>> assert (2, 3, "blue") in EVdata - >>> for u, v, c in EVdata: - ... print(f"({u}, {v}) has color: {c}") - (0, 1) has color: aqua - (1, 2) has color: aqua - (2, 3) has color: blue - - >>> EVnbunch = G.edges(nbunch=2) - >>> assert (2, 3) in EVnbunch - >>> assert (0, 1) not in EVnbunch - >>> for u, v in EVnbunch: - ... assert u == 2 or v == 2 - - >>> MG = nx.path_graph(4, create_using=nx.MultiGraph) - >>> EVmulti = MG.edges(keys=True) - >>> (2, 3, 0) in EVmulti - True - >>> (2, 3) in EVmulti # 2-tuples work even when keys is True - True - >>> key = MG.add_edge(2, 3) - >>> for u, v, k in EVmulti: - ... print((u, v, k)) - (0, 1, 0) - (1, 2, 0) - (2, 3, 0) - (2, 3, 1) - """ - - __slots__ = () - - dataview = EdgeDataView - - def __len__(self): - num_nbrs = (len(nbrs) + (n in nbrs) for n, nbrs in self._nodes_nbrs()) - return sum(num_nbrs) // 2 - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr in list(nbrs): - if nbr not in seen: - yield (n, nbr) - seen[n] = 1 - del seen - - def __contains__(self, e): - try: - u, v = e[:2] - return v in self._adjdict[u] or u in self._adjdict[v] - except (KeyError, ValueError): - return False - - -class InEdgeView(OutEdgeView): - """A EdgeView class for inward edges of a DiGraph""" - - __slots__ = () - - def __setstate__(self, state): - self._graph = state["_graph"] - self._adjdict = state["_adjdict"] - self._nodes_nbrs = self._adjdict.items - - dataview = InEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr in nbrs: - yield (nbr, n) - - def __contains__(self, e): - try: - u, v = e - return u in self._adjdict[v] - except KeyError: - return False - - def __getitem__(self, e): - if isinstance(e, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.in_edges)[{e.start}:{e.stop}:{e.step}]" - ) - u, v = e - return self._adjdict[v][u] - - -class OutMultiEdgeView(OutEdgeView): - """A EdgeView class for outward edges of a MultiDiGraph""" - - __slots__ = () - - dataview = OutMultiEdgeDataView - - def __len__(self): - return sum( - len(kdict) for n, nbrs in self._nodes_nbrs() for nbr, kdict in nbrs.items() - ) - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr, kdict in nbrs.items(): - for key in kdict: - yield (n, nbr, key) - - def __contains__(self, e): - N = len(e) - if N == 3: - u, v, k = e - elif N == 2: - u, v = e - k = 0 - else: - raise ValueError("MultiEdge must have length 2 or 3") - try: - return k in self._adjdict[u][v] - except KeyError: - return False - - def __getitem__(self, e): - if isinstance(e, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.edges)[{e.start}:{e.stop}:{e.step}]" - ) - u, v, k = e - return self._adjdict[u][v][k] - - def __call__(self, nbunch=None, data=False, *, default=None, keys=False): - if nbunch is None and data is False and keys is True: - return self - return self.dataview(self, nbunch, data, default=default, keys=keys) - - def data(self, data=True, default=None, nbunch=None, keys=False): - if nbunch is None and data is False and keys is True: - return self - return self.dataview(self, nbunch, data, default=default, keys=keys) - - -class MultiEdgeView(OutMultiEdgeView): - """A EdgeView class for edges of a MultiGraph""" - - __slots__ = () - - dataview = MultiEdgeDataView - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, kd in nbrs.items(): - if nbr not in seen: - for k, dd in kd.items(): - yield (n, nbr, k) - seen[n] = 1 - del seen - - -class InMultiEdgeView(OutMultiEdgeView): - """A EdgeView class for inward edges of a MultiDiGraph""" - - __slots__ = () - - def __setstate__(self, state): - self._graph = state["_graph"] - self._adjdict = state["_adjdict"] - self._nodes_nbrs = self._adjdict.items - - dataview = InMultiEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr, kdict in nbrs.items(): - for key in kdict: - yield (nbr, n, key) - - def __contains__(self, e): - N = len(e) - if N == 3: - u, v, k = e - elif N == 2: - u, v = e - k = 0 - else: - raise ValueError("MultiEdge must have length 2 or 3") - try: - return k in self._adjdict[v][u] - except KeyError: - return False - - def __getitem__(self, e): - if isinstance(e, slice): - raise nx.NetworkXError( - f"{type(self).__name__} does not support slicing, " - f"try list(G.in_edges)[{e.start}:{e.stop}:{e.step}]" - ) - u, v, k = e - return self._adjdict[v][u][k] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/dispatch_interface.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/dispatch_interface.py deleted file mode 100644 index 5cc908d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/dispatch_interface.py +++ /dev/null @@ -1,185 +0,0 @@ -# This file contains utilities for testing the dispatching feature - -# A full test of all dispatchable algorithms is performed by -# modifying the pytest invocation and setting an environment variable -# NETWORKX_TEST_BACKEND=nx_loopback pytest -# This is comprehensive, but only tests the `test_override_dispatch` -# function in networkx.classes.backends. - -# To test the `_dispatchable` function directly, several tests scattered throughout -# NetworkX have been augmented to test normal and dispatch mode. -# Searching for `dispatch_interface` should locate the specific tests. - -import networkx as nx -from networkx import DiGraph, Graph, MultiDiGraph, MultiGraph, PlanarEmbedding -from networkx.classes.reportviews import NodeView - - -class LoopbackGraph(Graph): - __networkx_backend__ = "nx_loopback" - - -class LoopbackDiGraph(DiGraph): - __networkx_backend__ = "nx_loopback" - - -class LoopbackMultiGraph(MultiGraph): - __networkx_backend__ = "nx_loopback" - - -class LoopbackMultiDiGraph(MultiDiGraph): - __networkx_backend__ = "nx_loopback" - - -class LoopbackPlanarEmbedding(PlanarEmbedding): - __networkx_backend__ = "nx_loopback" - - -def convert(graph): - if isinstance(graph, PlanarEmbedding): - return LoopbackPlanarEmbedding(graph) - if isinstance(graph, MultiDiGraph): - return LoopbackMultiDiGraph(graph) - if isinstance(graph, MultiGraph): - return LoopbackMultiGraph(graph) - if isinstance(graph, DiGraph): - return LoopbackDiGraph(graph) - if isinstance(graph, Graph): - return LoopbackGraph(graph) - raise TypeError(f"Unsupported type of graph: {type(graph)}") - - -class LoopbackBackendInterface: - def __getattr__(self, item): - try: - return nx.utils.backends._registered_algorithms[item].orig_func - except KeyError: - raise AttributeError(item) from None - - @staticmethod - def convert_from_nx( - graph, - *, - edge_attrs=None, - node_attrs=None, - preserve_edge_attrs=None, - preserve_node_attrs=None, - preserve_graph_attrs=None, - name=None, - graph_name=None, - ): - if name in { - # Raise if input graph changes. See test_dag.py::test_topological_sort6 - "lexicographical_topological_sort", - "topological_generations", - "topological_sort", - # Would be nice to some day avoid these cutoffs of full testing - }: - return graph - if isinstance(graph, NodeView): - # Convert to a Graph with only nodes (no edges) - new_graph = Graph() - new_graph.add_nodes_from(graph.items()) - graph = new_graph - G = LoopbackGraph() - elif not isinstance(graph, Graph): - raise TypeError( - f"Bad type for graph argument {graph_name} in {name}: {type(graph)}" - ) - elif graph.__class__ in {Graph, LoopbackGraph}: - G = LoopbackGraph() - elif graph.__class__ in {DiGraph, LoopbackDiGraph}: - G = LoopbackDiGraph() - elif graph.__class__ in {MultiGraph, LoopbackMultiGraph}: - G = LoopbackMultiGraph() - elif graph.__class__ in {MultiDiGraph, LoopbackMultiDiGraph}: - G = LoopbackMultiDiGraph() - elif graph.__class__ in {PlanarEmbedding, LoopbackPlanarEmbedding}: - G = LoopbackDiGraph() # or LoopbackPlanarEmbedding - else: - # Would be nice to handle these better some day - # nx.algorithms.approximation.kcomponents._AntiGraph - # nx.classes.tests.test_multidigraph.MultiDiGraphSubClass - # nx.classes.tests.test_multigraph.MultiGraphSubClass - G = graph.__class__() - - if preserve_graph_attrs: - G.graph.update(graph.graph) - - # add nodes - G.add_nodes_from(graph) - if preserve_node_attrs: - for n, dd in G._node.items(): - dd.update(graph.nodes[n]) - elif node_attrs: - for n, dd in G._node.items(): - dd.update( - (attr, graph._node[n].get(attr, default)) - for attr, default in node_attrs.items() - if default is not None or attr in graph._node[n] - ) - - # tools to build datadict and keydict - if preserve_edge_attrs: - - def G_new_datadict(old_dd): - return G.edge_attr_dict_factory(old_dd) - elif edge_attrs: - - def G_new_datadict(old_dd): - return G.edge_attr_dict_factory( - (attr, old_dd.get(attr, default)) - for attr, default in edge_attrs.items() - if default is not None or attr in old_dd - ) - else: - - def G_new_datadict(old_dd): - return G.edge_attr_dict_factory() - - if G.is_multigraph(): - - def G_new_inner(keydict): - kd = G.adjlist_inner_dict_factory( - (k, G_new_datadict(dd)) for k, dd in keydict.items() - ) - return kd - else: - G_new_inner = G_new_datadict - - # add edges keeping the same order in _adj and _pred - G_adj = G._adj - if G.is_directed(): - for n, nbrs in graph._adj.items(): - G_adj[n].update((nbr, G_new_inner(dd)) for nbr, dd in nbrs.items()) - # ensure same datadict for pred and adj; and pred order of graph._pred - G_pred = G._pred - for n, nbrs in graph._pred.items(): - G_pred[n].update((nbr, G_adj[nbr][n]) for nbr in nbrs) - else: # undirected - for n, nbrs in graph._adj.items(): - # ensure same datadict for both ways; and adj order of graph._adj - G_adj[n].update( - (nbr, G_adj[nbr][n] if n in G_adj[nbr] else G_new_inner(dd)) - for nbr, dd in nbrs.items() - ) - - return G - - @staticmethod - def convert_to_nx(obj, *, name=None): - return obj - - @staticmethod - def on_start_tests(items): - # Verify that items can be xfailed - for item in items: - assert hasattr(item, "add_marker") - - def can_run(self, name, args, kwargs): - # It is unnecessary to define this function if algorithms are fully supported. - # We include it for illustration purposes. - return hasattr(self, name) - - -backend_interface = LoopbackBackendInterface() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/historical_tests.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/historical_tests.py deleted file mode 100644 index 9dad24e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/historical_tests.py +++ /dev/null @@ -1,475 +0,0 @@ -"""Original NetworkX graph tests""" - -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.utils import edges_equal, nodes_equal - - -class HistoricalTests: - @classmethod - def setup_class(cls): - cls.null = nx.null_graph() - cls.P1 = cnlti(nx.path_graph(1), first_label=1) - cls.P3 = cnlti(nx.path_graph(3), first_label=1) - cls.P10 = cnlti(nx.path_graph(10), first_label=1) - cls.K1 = cnlti(nx.complete_graph(1), first_label=1) - cls.K3 = cnlti(nx.complete_graph(3), first_label=1) - cls.K4 = cnlti(nx.complete_graph(4), first_label=1) - cls.K5 = cnlti(nx.complete_graph(5), first_label=1) - cls.K10 = cnlti(nx.complete_graph(10), first_label=1) - cls.G = nx.Graph - - def test_name(self): - G = self.G(name="test") - assert G.name == "test" - H = self.G() - assert H.name == "" - - # Nodes - - def test_add_remove_node(self): - G = self.G() - G.add_node("A") - assert G.has_node("A") - G.remove_node("A") - assert not G.has_node("A") - - def test_nonhashable_node(self): - # Test if a non-hashable object is in the Graph. A python dict will - # raise a TypeError, but for a Graph class a simple False should be - # returned (see Graph __contains__). If it cannot be a node then it is - # not a node. - G = self.G() - assert not G.has_node(["A"]) - assert not G.has_node({"A": 1}) - - def test_add_nodes_from(self): - G = self.G() - G.add_nodes_from(list("ABCDEFGHIJKL")) - assert G.has_node("L") - G.remove_nodes_from(["H", "I", "J", "K", "L"]) - G.add_nodes_from([1, 2, 3, 4]) - assert sorted(G.nodes(), key=str) == [ - 1, - 2, - 3, - 4, - "A", - "B", - "C", - "D", - "E", - "F", - "G", - ] - # test __iter__ - assert sorted(G, key=str) == [1, 2, 3, 4, "A", "B", "C", "D", "E", "F", "G"] - - def test_contains(self): - G = self.G() - G.add_node("A") - assert "A" in G - assert [] not in G # never raise a Key or TypeError in this test - assert {1: 1} not in G - - def test_add_remove(self): - # Test add_node and remove_node acting for various nbunch - G = self.G() - G.add_node("m") - assert G.has_node("m") - G.add_node("m") # no complaints - pytest.raises(nx.NetworkXError, G.remove_node, "j") - G.remove_node("m") - assert list(G) == [] - - def test_nbunch_is_list(self): - G = self.G() - G.add_nodes_from(list("ABCD")) - G.add_nodes_from(self.P3) # add nbunch of nodes (nbunch=Graph) - assert sorted(G.nodes(), key=str) == [1, 2, 3, "A", "B", "C", "D"] - G.remove_nodes_from(self.P3) # remove nbunch of nodes (nbunch=Graph) - assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D"] - - def test_nbunch_is_set(self): - G = self.G() - nbunch = set("ABCDEFGHIJKL") - G.add_nodes_from(nbunch) - assert G.has_node("L") - - def test_nbunch_dict(self): - # nbunch is a dict with nodes as keys - G = self.G() - nbunch = set("ABCDEFGHIJKL") - G.add_nodes_from(nbunch) - nbunch = {"I": "foo", "J": 2, "K": True, "L": "spam"} - G.remove_nodes_from(nbunch) - assert sorted(G.nodes(), key=str), ["A", "B", "C", "D", "E", "F", "G", "H"] - - def test_nbunch_iterator(self): - G = self.G() - G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"]) - n_iter = self.P3.nodes() - G.add_nodes_from(n_iter) - assert sorted(G.nodes(), key=str) == [ - 1, - 2, - 3, - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - ] - n_iter = self.P3.nodes() # rebuild same iterator - G.remove_nodes_from(n_iter) # remove nbunch of nodes (nbunch=iterator) - assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D", "E", "F", "G", "H"] - - def test_nbunch_graph(self): - G = self.G() - G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"]) - nbunch = self.K3 - G.add_nodes_from(nbunch) - assert sorted(G.nodes(), key=str), [ - 1, - 2, - 3, - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - ] - - # Edges - - def test_add_edge(self): - G = self.G() - pytest.raises(TypeError, G.add_edge, "A") - - G.add_edge("A", "B") # testing add_edge() - G.add_edge("A", "B") # should fail silently - assert G.has_edge("A", "B") - assert not G.has_edge("A", "C") - assert G.has_edge(*("A", "B")) - if G.is_directed(): - assert not G.has_edge("B", "A") - else: - # G is undirected, so B->A is an edge - assert G.has_edge("B", "A") - - G.add_edge("A", "C") # test directedness - G.add_edge("C", "A") - G.remove_edge("C", "A") - if G.is_directed(): - assert G.has_edge("A", "C") - else: - assert not G.has_edge("A", "C") - assert not G.has_edge("C", "A") - - def test_self_loop(self): - G = self.G() - G.add_edge("A", "A") # test self loops - assert G.has_edge("A", "A") - G.remove_edge("A", "A") - G.add_edge("X", "X") - assert G.has_node("X") - G.remove_node("X") - G.add_edge("A", "Z") # should add the node silently - assert G.has_node("Z") - - def test_add_edges_from(self): - G = self.G() - G.add_edges_from([("B", "C")]) # test add_edges_from() - assert G.has_edge("B", "C") - if G.is_directed(): - assert not G.has_edge("C", "B") - else: - assert G.has_edge("C", "B") # undirected - - G.add_edges_from([("D", "F"), ("B", "D")]) - assert G.has_edge("D", "F") - assert G.has_edge("B", "D") - - if G.is_directed(): - assert not G.has_edge("D", "B") - else: - assert G.has_edge("D", "B") # undirected - - def test_add_edges_from2(self): - G = self.G() - # after failing silently, should add 2nd edge - G.add_edges_from([tuple("IJ"), list("KK"), tuple("JK")]) - assert G.has_edge(*("I", "J")) - assert G.has_edge(*("K", "K")) - assert G.has_edge(*("J", "K")) - if G.is_directed(): - assert not G.has_edge(*("K", "J")) - else: - assert G.has_edge(*("K", "J")) - - def test_add_edges_from3(self): - G = self.G() - G.add_edges_from(zip(list("ACD"), list("CDE"))) - assert G.has_edge("D", "E") - assert not G.has_edge("E", "C") - - def test_remove_edge(self): - G = self.G() - G.add_nodes_from([1, 2, 3, "A", "B", "C", "D", "E", "F", "G", "H"]) - - G.add_edges_from(zip(list("MNOP"), list("NOPM"))) - assert G.has_edge("O", "P") - assert G.has_edge("P", "M") - G.remove_node("P") # tests remove_node()'s handling of edges. - assert not G.has_edge("P", "M") - pytest.raises(TypeError, G.remove_edge, "M") - - G.add_edge("N", "M") - assert G.has_edge("M", "N") - G.remove_edge("M", "N") - assert not G.has_edge("M", "N") - - # self loop fails silently - G.remove_edges_from([list("HI"), list("DF"), tuple("KK"), tuple("JK")]) - assert not G.has_edge("H", "I") - assert not G.has_edge("J", "K") - G.remove_edges_from([list("IJ"), list("KK"), list("JK")]) - assert not G.has_edge("I", "J") - G.remove_nodes_from(set("ZEFHIMNO")) - G.add_edge("J", "K") - - def test_edges_nbunch(self): - # Test G.edges(nbunch) with various forms of nbunch - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - # node not in nbunch should be quietly ignored - pytest.raises(nx.NetworkXError, G.edges, 6) - assert list(G.edges("Z")) == [] # iterable non-node - # nbunch can be an empty list - assert list(G.edges([])) == [] - if G.is_directed(): - elist = [("A", "B"), ("A", "C"), ("B", "D")] - else: - elist = [("A", "B"), ("A", "C"), ("B", "C"), ("B", "D")] - # nbunch can be a list - assert edges_equal(list(G.edges(["A", "B"])), elist) - # nbunch can be a set - assert edges_equal(G.edges({"A", "B"}), elist) - # nbunch can be a graph - G1 = self.G() - G1.add_nodes_from("AB") - assert edges_equal(G.edges(G1), elist) - # nbunch can be a dict with nodes as keys - ndict = {"A": "thing1", "B": "thing2"} - assert edges_equal(G.edges(ndict), elist) - # nbunch can be a single node - assert edges_equal(list(G.edges("A")), [("A", "B"), ("A", "C")]) - assert nodes_equal(sorted(G), ["A", "B", "C", "D"]) - - # nbunch can be nothing (whole graph) - assert edges_equal( - list(G.edges()), - [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")], - ) - - def test_degree(self): - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - assert G.degree("A") == 2 - - # degree of single node in iterable container must return dict - assert list(G.degree(["A"])) == [("A", 2)] - assert sorted(d for n, d in G.degree(["A", "B"])) == [2, 3] - assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3] - - def test_degree2(self): - H = self.G() - H.add_edges_from([(1, 24), (1, 2)]) - assert sorted(d for n, d in H.degree([1, 24])) == [1, 2] - - def test_degree_graph(self): - P3 = nx.path_graph(3) - P5 = nx.path_graph(5) - # silently ignore nodes not in P3 - assert dict(d for n, d in P3.degree(["A", "B"])) == {} - # nbunch can be a graph - assert sorted(d for n, d in P5.degree(P3)) == [1, 2, 2] - # nbunch can be a graph that's way too big - assert sorted(d for n, d in P3.degree(P5)) == [1, 1, 2] - assert list(P5.degree([])) == [] - assert dict(P5.degree([])) == {} - - def test_null(self): - null = nx.null_graph() - assert list(null.degree()) == [] - assert dict(null.degree()) == {} - - def test_order_size(self): - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - assert G.order() == 4 - assert G.size() == 5 - assert G.number_of_edges() == 5 - assert G.number_of_edges("A", "B") == 1 - assert G.number_of_edges("A", "D") == 0 - - def test_copy(self): - G = self.G() - H = G.copy() # copy - assert H.adj == G.adj - assert H.name == G.name - assert H is not G - - def test_subgraph(self): - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - SG = G.subgraph(["A", "B", "D"]) - assert nodes_equal(list(SG), ["A", "B", "D"]) - assert edges_equal(list(SG.edges()), [("A", "B"), ("B", "D")]) - - def test_to_directed(self): - G = self.G() - if not G.is_directed(): - G.add_edges_from( - [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")] - ) - - DG = G.to_directed() - assert DG is not G # directed copy or copy - - assert DG.is_directed() - assert DG.name == G.name - assert DG.adj == G.adj - assert sorted(DG.out_edges(list("AB"))) == [ - ("A", "B"), - ("A", "C"), - ("B", "A"), - ("B", "C"), - ("B", "D"), - ] - DG.remove_edge("A", "B") - assert DG.has_edge("B", "A") # this removes B-A but not A-B - assert not DG.has_edge("A", "B") - - def test_to_undirected(self): - G = self.G() - if G.is_directed(): - G.add_edges_from( - [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")] - ) - UG = G.to_undirected() # to_undirected - assert UG is not G - assert not UG.is_directed() - assert G.is_directed() - assert UG.name == G.name - assert UG.adj != G.adj - assert sorted(UG.edges(list("AB"))) == [ - ("A", "B"), - ("A", "C"), - ("B", "C"), - ("B", "D"), - ] - assert sorted(UG.edges(["A", "B"])) == [ - ("A", "B"), - ("A", "C"), - ("B", "C"), - ("B", "D"), - ] - UG.remove_edge("A", "B") - assert not UG.has_edge("B", "A") - assert not UG.has_edge("A", "B") - - def test_neighbors(self): - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - G.add_nodes_from("GJK") - assert sorted(G["A"]) == ["B", "C"] - assert sorted(G.neighbors("A")) == ["B", "C"] - assert sorted(G.neighbors("A")) == ["B", "C"] - assert sorted(G.neighbors("G")) == [] - pytest.raises(nx.NetworkXError, G.neighbors, "j") - - def test_iterators(self): - G = self.G() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]) - G.add_nodes_from("GJK") - assert sorted(G.nodes()) == ["A", "B", "C", "D", "G", "J", "K"] - assert edges_equal( - G.edges(), [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")] - ) - - assert sorted(v for k, v in G.degree()) == [0, 0, 0, 2, 2, 3, 3] - assert sorted(G.degree(), key=str) == [ - ("A", 2), - ("B", 3), - ("C", 3), - ("D", 2), - ("G", 0), - ("J", 0), - ("K", 0), - ] - assert sorted(G.neighbors("A")) == ["B", "C"] - pytest.raises(nx.NetworkXError, G.neighbors, "X") - G.clear() - assert nx.number_of_nodes(G) == 0 - assert nx.number_of_edges(G) == 0 - - def test_null_subgraph(self): - # Subgraph of a null graph is a null graph - nullgraph = nx.null_graph() - G = nx.null_graph() - H = G.subgraph([]) - assert nx.is_isomorphic(H, nullgraph) - - def test_empty_subgraph(self): - # Subgraph of an empty graph is an empty graph. test 1 - nullgraph = nx.null_graph() - E5 = nx.empty_graph(5) - E10 = nx.empty_graph(10) - H = E10.subgraph([]) - assert nx.is_isomorphic(H, nullgraph) - H = E10.subgraph([1, 2, 3, 4, 5]) - assert nx.is_isomorphic(H, E5) - - def test_complete_subgraph(self): - # Subgraph of a complete graph is a complete graph - K1 = nx.complete_graph(1) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - H = K5.subgraph([1, 2, 3]) - assert nx.is_isomorphic(H, K3) - - def test_subgraph_nbunch(self): - nullgraph = nx.null_graph() - K1 = nx.complete_graph(1) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - # Test G.subgraph(nbunch), where nbunch is a single node - H = K5.subgraph(1) - assert nx.is_isomorphic(H, K1) - # Test G.subgraph(nbunch), where nbunch is a set - H = K5.subgraph({1}) - assert nx.is_isomorphic(H, K1) - # Test G.subgraph(nbunch), where nbunch is an iterator - H = K5.subgraph(iter(K3)) - assert nx.is_isomorphic(H, K3) - # Test G.subgraph(nbunch), where nbunch is another graph - H = K5.subgraph(K3) - assert nx.is_isomorphic(H, K3) - H = K5.subgraph([9]) - assert nx.is_isomorphic(H, nullgraph) - - def test_node_tuple_issue(self): - H = self.G() - # Test error handling of tuple as a node - pytest.raises(nx.NetworkXError, H.remove_node, (1, 2)) - H.remove_nodes_from([(1, 2)]) # no error - pytest.raises(nx.NetworkXError, H.neighbors, (1, 2)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_coreviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_coreviews.py deleted file mode 100644 index 24de7f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_coreviews.py +++ /dev/null @@ -1,362 +0,0 @@ -import pickle - -import pytest - -import networkx as nx - - -class TestAtlasView: - # node->data - def setup_method(self): - self.d = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}} - self.av = nx.classes.coreviews.AtlasView(self.d) - - def test_pickle(self): - view = self.av - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - pview = pickle.loads(pickle.dumps(view)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.av) == len(self.d) - - def test_iter(self): - assert list(self.av) == list(self.d) - - def test_getitem(self): - assert self.av[1] is self.d[1] - assert self.av[2]["color"] == 1 - pytest.raises(KeyError, self.av.__getitem__, 3) - - def test_copy(self): - avcopy = self.av.copy() - assert avcopy[0] == self.av[0] - assert avcopy == self.av - assert avcopy[0] is not self.av[0] - assert avcopy is not self.av - avcopy[5] = {} - assert avcopy != self.av - - avcopy[0]["ht"] = 4 - assert avcopy[0] != self.av[0] - self.av[0]["ht"] = 4 - assert avcopy[0] == self.av[0] - del self.av[0]["ht"] - - assert not hasattr(self.av, "__setitem__") - - def test_items(self): - assert sorted(self.av.items()) == sorted(self.d.items()) - - def test_str(self): - out = str(self.d) - assert str(self.av) == out - - def test_repr(self): - out = "AtlasView(" + str(self.d) + ")" - assert repr(self.av) == out - - -class TestAdjacencyView: - # node->nbr->data - def setup_method(self): - dd = {"color": "blue", "weight": 1.2} - self.nd = {0: dd, 1: {}, 2: {"color": 1}} - self.adj = {3: self.nd, 0: {3: dd}, 1: {}, 2: {3: {"color": 1}}} - self.adjview = nx.classes.coreviews.AdjacencyView(self.adj) - - def test_pickle(self): - view = self.adjview - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.adjview) == len(self.adj) - - def test_iter(self): - assert list(self.adjview) == list(self.adj) - - def test_getitem(self): - assert self.adjview[1] is not self.adj[1] - assert self.adjview[3][0] is self.adjview[0][3] - assert self.adjview[2][3]["color"] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3]["ht"] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3]["ht"] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3]["ht"] - - assert not hasattr(self.adjview, "__setitem__") - - def test_items(self): - view_items = sorted((n, dict(d)) for n, d in self.adjview.items()) - assert view_items == sorted(self.adj.items()) - - def test_str(self): - out = str(dict(self.adj)) - assert str(self.adjview) == out - - def test_repr(self): - out = self.adjview.__class__.__name__ + "(" + str(self.adj) + ")" - assert repr(self.adjview) == out - - -class TestMultiAdjacencyView(TestAdjacencyView): - # node->nbr->key->data - def setup_method(self): - dd = {"color": "blue", "weight": 1.2} - self.kd = {0: dd, 1: {}, 2: {"color": 1}} - self.nd = {3: self.kd, 0: {3: dd}, 1: {0: {}}, 2: {3: {"color": 1}}} - self.adj = {3: self.nd, 0: {3: {3: dd}}, 1: {}, 2: {3: {8: {}}}} - self.adjview = nx.classes.coreviews.MultiAdjacencyView(self.adj) - - def test_getitem(self): - assert self.adjview[1] is not self.adj[1] - assert self.adjview[3][0][3] is self.adjview[0][3][3] - assert self.adjview[3][2][3]["color"] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3][8]["ht"] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3][8]["ht"] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3][8]["ht"] - - assert not hasattr(self.adjview, "__setitem__") - - -class TestUnionAtlas: - # node->data - def setup_method(self): - self.s = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}} - self.p = {3: {"color": "blue", "weight": 1.2}, 4: {}, 2: {"watch": 2}} - self.av = nx.classes.coreviews.UnionAtlas(self.s, self.p) - - def test_pickle(self): - view = self.av - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.av) == len(self.s.keys() | self.p.keys()) == 5 - - def test_iter(self): - assert set(self.av) == set(self.s) | set(self.p) - - def test_getitem(self): - assert self.av[0] is self.s[0] - assert self.av[4] is self.p[4] - assert self.av[2]["color"] == 1 - pytest.raises(KeyError, self.av[2].__getitem__, "watch") - pytest.raises(KeyError, self.av.__getitem__, 8) - - def test_copy(self): - avcopy = self.av.copy() - assert avcopy[0] == self.av[0] - assert avcopy[0] is not self.av[0] - assert avcopy is not self.av - avcopy[5] = {} - assert avcopy != self.av - - avcopy[0]["ht"] = 4 - assert avcopy[0] != self.av[0] - self.av[0]["ht"] = 4 - assert avcopy[0] == self.av[0] - del self.av[0]["ht"] - - assert not hasattr(self.av, "__setitem__") - - def test_items(self): - expected = dict(self.p.items()) - expected.update(self.s) - assert sorted(self.av.items()) == sorted(expected.items()) - - def test_str(self): - out = str(dict(self.av)) - assert str(self.av) == out - - def test_repr(self): - out = f"{self.av.__class__.__name__}({self.s}, {self.p})" - assert repr(self.av) == out - - -class TestUnionAdjacency: - # node->nbr->data - def setup_method(self): - dd = {"color": "blue", "weight": 1.2} - self.nd = {0: dd, 1: {}, 2: {"color": 1}} - self.s = {3: self.nd, 0: {}, 1: {}, 2: {3: {"color": 1}}} - self.p = {3: {}, 0: {3: dd}, 1: {0: {}}, 2: {1: {"color": 1}}} - self.adjview = nx.classes.coreviews.UnionAdjacency(self.s, self.p) - - def test_pickle(self): - view = self.adjview - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.adjview) == len(self.s) - - def test_iter(self): - assert sorted(self.adjview) == sorted(self.s) - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[3][0] is self.adjview[0][3] - assert self.adjview[2][3]["color"] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3]["ht"] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3]["ht"] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3]["ht"] - - assert not hasattr(self.adjview, "__setitem__") - - def test_str(self): - out = str(dict(self.adjview)) - assert str(self.adjview) == out - - def test_repr(self): - clsname = self.adjview.__class__.__name__ - out = f"{clsname}({self.s}, {self.p})" - assert repr(self.adjview) == out - - -class TestUnionMultiInner(TestUnionAdjacency): - # nbr->key->data - def setup_method(self): - dd = {"color": "blue", "weight": 1.2} - self.kd = {7: {}, "ekey": {}, 9: {"color": 1}} - self.s = {3: self.kd, 0: {7: dd}, 1: {}, 2: {"key": {"color": 1}}} - self.p = {3: {}, 0: {3: dd}, 1: {}, 2: {1: {"span": 2}}} - self.adjview = nx.classes.coreviews.UnionMultiInner(self.s, self.p) - - def test_len(self): - assert len(self.adjview) == len(self.s.keys() | self.p.keys()) == 4 - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[0][7] is self.adjview[0][3] - assert self.adjview[2]["key"]["color"] == 1 - assert self.adjview[2][1]["span"] == 2 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - pytest.raises(KeyError, self.adjview[1].__getitem__, "key") - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][1]["width"] = 8 - assert avcopy[2] != self.adjview[2] - self.adjview[2][1]["width"] = 8 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][1]["width"] - - assert not hasattr(self.adjview, "__setitem__") - assert hasattr(avcopy, "__setitem__") - - -class TestUnionMultiAdjacency(TestUnionAdjacency): - # node->nbr->key->data - def setup_method(self): - dd = {"color": "blue", "weight": 1.2} - self.kd = {7: {}, 8: {}, 9: {"color": 1}} - self.nd = {3: self.kd, 0: {9: dd}, 1: {8: {}}, 2: {9: {"color": 1}}} - self.s = {3: self.nd, 0: {3: {7: dd}}, 1: {}, 2: {3: {8: {}}}} - self.p = {3: {}, 0: {3: {9: dd}}, 1: {}, 2: {1: {8: {}}}} - self.adjview = nx.classes.coreviews.UnionMultiAdjacency(self.s, self.p) - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[3][0][9] is self.adjview[0][3][9] - assert self.adjview[3][2][9]["color"] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3][8]["ht"] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3][8]["ht"] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3][8]["ht"] - - assert not hasattr(self.adjview, "__setitem__") - assert hasattr(avcopy, "__setitem__") - - -class TestFilteredGraphs: - def setup_method(self): - self.Graphs = [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] - - def test_hide_show_nodes(self): - SubGraph = nx.subgraph_view - for Graph in self.Graphs: - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, filter_node=nx.filters.hide_nodes([0, 1])) - assert SG.nodes == RG.nodes - assert SG.edges == RG.edges - SGC = SG.copy() - RGC = RG.copy() - assert SGC.nodes == RGC.nodes - assert SGC.edges == RGC.edges - - def test_str_repr(self): - SubGraph = nx.subgraph_view - for Graph in self.Graphs: - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, filter_node=nx.filters.hide_nodes([0, 1])) - str(SG.adj) - str(RG.adj) - repr(SG.adj) - repr(RG.adj) - str(SG.adj[2]) - str(RG.adj[2]) - repr(SG.adj[2]) - repr(RG.adj[2]) - - def test_copy(self): - SubGraph = nx.subgraph_view - for Graph in self.Graphs: - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, filter_node=nx.filters.hide_nodes([0, 1])) - RsG = SubGraph(G, filter_node=nx.filters.show_nodes([2, 3])) - assert G.adj.copy() == G.adj - assert G.adj[2].copy() == G.adj[2] - assert SG.adj.copy() == SG.adj - assert SG.adj[2].copy() == SG.adj[2] - assert RG.adj.copy() == RG.adj - assert RG.adj[2].copy() == RG.adj[2] - assert RsG.adj.copy() == RsG.adj - assert RsG.adj[2].copy() == RsG.adj[2] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph.py deleted file mode 100644 index b9972f9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph.py +++ /dev/null @@ -1,331 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import nodes_equal - -from .test_graph import BaseAttrGraphTester, BaseGraphTester -from .test_graph import TestEdgeSubgraph as _TestGraphEdgeSubgraph -from .test_graph import TestGraph as _TestGraph - - -class BaseDiGraphTester(BaseGraphTester): - def test_has_successor(self): - G = self.K3 - assert G.has_successor(0, 1) - assert not G.has_successor(0, -1) - - def test_successors(self): - G = self.K3 - assert sorted(G.successors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.successors(-1) - - def test_has_predecessor(self): - G = self.K3 - assert G.has_predecessor(0, 1) - assert not G.has_predecessor(0, -1) - - def test_predecessors(self): - G = self.K3 - assert sorted(G.predecessors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.predecessors(-1) - - def test_edges(self): - G = self.K3 - assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - assert sorted(G.edges([0, 1])) == [(0, 1), (0, 2), (1, 0), (1, 2)] - with pytest.raises(nx.NetworkXError): - G.edges(-1) - - def test_out_edges(self): - G = self.K3 - assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - with pytest.raises(nx.NetworkXError): - G.out_edges(-1) - - def test_out_edges_dir(self): - G = self.P3 - assert sorted(G.out_edges()) == [(0, 1), (1, 2)] - assert sorted(G.out_edges(0)) == [(0, 1)] - assert sorted(G.out_edges(2)) == [] - - def test_out_edges_data(self): - G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})]) - assert sorted(G.out_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})] - assert sorted(G.out_edges(0, data=True)) == [(0, 1, {"data": 0})] - assert sorted(G.out_edges(data="data")) == [(0, 1, 0), (1, 0, None)] - assert sorted(G.out_edges(0, data="data")) == [(0, 1, 0)] - - def test_in_edges_dir(self): - G = self.P3 - assert sorted(G.in_edges()) == [(0, 1), (1, 2)] - assert sorted(G.in_edges(0)) == [] - assert sorted(G.in_edges(2)) == [(1, 2)] - - def test_in_edges_data(self): - G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})]) - assert sorted(G.in_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})] - assert sorted(G.in_edges(1, data=True)) == [(0, 1, {"data": 0})] - assert sorted(G.in_edges(data="data")) == [(0, 1, 0), (1, 0, None)] - assert sorted(G.in_edges(1, data="data")) == [(0, 1, 0)] - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)] - assert dict(G.degree()) == {0: 4, 1: 4, 2: 4} - assert G.degree(0) == 4 - assert list(G.degree(iter([0]))) == [(0, 4)] # run through iterator - - def test_in_degree(self): - G = self.K3 - assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2} - assert G.in_degree(0) == 2 - assert list(G.in_degree(iter([0]))) == [(0, 2)] # run through iterator - - def test_out_degree(self): - G = self.K3 - assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2} - assert G.out_degree(0) == 2 - assert list(G.out_degree(iter([0]))) == [(0, 2)] - - def test_size(self): - G = self.K3 - assert G.size() == 6 - assert G.number_of_edges() == 6 - - def test_to_undirected_reciprocal(self): - G = self.Graph() - G.add_edge(1, 2) - assert G.to_undirected().has_edge(1, 2) - assert not G.to_undirected(reciprocal=True).has_edge(1, 2) - G.add_edge(2, 1) - assert G.to_undirected(reciprocal=True).has_edge(1, 2) - - def test_reverse_copy(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - R = G.reverse() - assert sorted(R.edges()) == [(1, 0), (2, 1)] - R.remove_edge(1, 0) - assert sorted(R.edges()) == [(2, 1)] - assert sorted(G.edges()) == [(0, 1), (1, 2)] - - def test_reverse_nocopy(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - R = G.reverse(copy=False) - assert sorted(R.edges()) == [(1, 0), (2, 1)] - with pytest.raises(nx.NetworkXError): - R.remove_edge(1, 0) - - def test_reverse_hashable(self): - class Foo: - pass - - x = Foo() - y = Foo() - G = nx.DiGraph() - G.add_edge(x, y) - assert nodes_equal(G.nodes(), G.reverse().nodes()) - assert [(y, x)] == list(G.reverse().edges()) - - def test_di_cache_reset(self): - G = self.K3.copy() - old_succ = G.succ - assert id(G.succ) == id(old_succ) - old_adj = G.adj - assert id(G.adj) == id(old_adj) - - G._succ = {} - assert id(G.succ) != id(old_succ) - assert id(G.adj) != id(old_adj) - - old_pred = G.pred - assert id(G.pred) == id(old_pred) - G._pred = {} - assert id(G.pred) != id(old_pred) - - def test_di_attributes_cached(self): - G = self.K3.copy() - assert id(G.in_edges) == id(G.in_edges) - assert id(G.out_edges) == id(G.out_edges) - assert id(G.in_degree) == id(G.in_degree) - assert id(G.out_degree) == id(G.out_degree) - assert id(G.succ) == id(G.succ) - assert id(G.pred) == id(G.pred) - - -class BaseAttrDiGraphTester(BaseDiGraphTester, BaseAttrGraphTester): - def test_edges_data(self): - G = self.K3 - all_edges = [ - (0, 1, {}), - (0, 2, {}), - (1, 0, {}), - (1, 2, {}), - (2, 0, {}), - (2, 1, {}), - ] - assert sorted(G.edges(data=True)) == all_edges - assert sorted(G.edges(0, data=True)) == all_edges[:2] - assert sorted(G.edges([0, 1], data=True)) == all_edges[:4] - with pytest.raises(nx.NetworkXError): - G.edges(-1, True) - - def test_in_degree_weighted(self): - G = self.K3.copy() - G.add_edge(0, 1, weight=0.3, other=1.2) - assert sorted(G.in_degree(weight="weight")) == [(0, 2), (1, 1.3), (2, 2)] - assert dict(G.in_degree(weight="weight")) == {0: 2, 1: 1.3, 2: 2} - assert G.in_degree(1, weight="weight") == 1.3 - assert sorted(G.in_degree(weight="other")) == [(0, 2), (1, 2.2), (2, 2)] - assert dict(G.in_degree(weight="other")) == {0: 2, 1: 2.2, 2: 2} - assert G.in_degree(1, weight="other") == 2.2 - assert list(G.in_degree(iter([1]), weight="other")) == [(1, 2.2)] - - def test_out_degree_weighted(self): - G = self.K3.copy() - G.add_edge(0, 1, weight=0.3, other=1.2) - assert sorted(G.out_degree(weight="weight")) == [(0, 1.3), (1, 2), (2, 2)] - assert dict(G.out_degree(weight="weight")) == {0: 1.3, 1: 2, 2: 2} - assert G.out_degree(0, weight="weight") == 1.3 - assert sorted(G.out_degree(weight="other")) == [(0, 2.2), (1, 2), (2, 2)] - assert dict(G.out_degree(weight="other")) == {0: 2.2, 1: 2, 2: 2} - assert G.out_degree(0, weight="other") == 2.2 - assert list(G.out_degree(iter([0]), weight="other")) == [(0, 2.2)] - - -class TestDiGraph(BaseAttrDiGraphTester, _TestGraph): - """Tests specific to dict-of-dict-of-dict digraph data structure""" - - def setup_method(self): - self.Graph = nx.DiGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3, ed4, ed5, ed6 = ({}, {}, {}, {}, {}, {}) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._succ = self.k3adj # K3._adj is synced with K3._succ - self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}} - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - ed1, ed2 = ({}, {}) - self.P3 = self.Graph() - self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}} - self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}} - # P3._adj is synced with P3._succ - self.P3._node = {} - self.P3._node[0] = {} - self.P3._node[1] = {} - self.P3._node[2] = {} - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})] - assert sorted(G.succ.items()) == [(1, {2: {}}), (2, {1: {}})] - assert sorted(G.pred.items()) == [(1, {2: {}}), (2, {1: {}})] - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {}}, 1: {}} - assert G.succ == {0: {1: {}}, 1: {}} - assert G.pred == {0: {}, 1: {0: {}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {}}, 1: {}} - assert G.succ == {0: {1: {}}, 1: {}} - assert G.pred == {0: {}, 1: {0: {}}} - with pytest.raises(ValueError, match="None cannot be a node"): - G.add_edge(None, 3) - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {"data": 3})], data=2) - assert G.adj == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}} - assert G.succ == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}} - assert G.pred == {0: {}, 1: {0: {"data": 2}}, 2: {0: {"data": 3}}} - - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) # not a tuple - with pytest.raises(ValueError, match="None cannot be a node"): - G.add_edges_from([(None, 3), (3, 2)]) - - def test_remove_edge(self): - G = self.K3.copy() - G.remove_edge(0, 1) - assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}} - assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - def test_remove_edges_from(self): - G = self.K3.copy() - G.remove_edges_from([(0, 1)]) - assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}} - assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - G.remove_edges_from([(0, 0)]) # silent fail - - def test_clear(self): - G = self.K3 - G.graph["name"] = "K3" - G.clear() - assert list(G.nodes) == [] - assert G.succ == {} - assert G.pred == {} - assert G.graph == {} - - def test_clear_edges(self): - G = self.K3 - G.graph["name"] = "K3" - nodes = list(G.nodes) - G.clear_edges() - assert list(G.nodes) == nodes - expected = {0: {}, 1: {}, 2: {}} - assert G.succ == expected - assert G.pred == expected - assert list(G.edges) == [] - assert G.graph["name"] == "K3" - - -class TestEdgeSubgraph(_TestGraphEdgeSubgraph): - """Unit tests for the :meth:`DiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a doubly-linked path graph on five nodes. - G = nx.DiGraph(nx.path_graph(5)) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]["name"] = f"node{i}" - G.edges[0, 1]["name"] = "edge01" - G.edges[3, 4]["name"] = "edge34" - G.graph["name"] = "graph" - # Get the subgraph induced by the first and last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1), (3, 4)]) - - def test_pred_succ(self): - """Test that nodes are added to predecessors and successors. - - For more information, see GitHub issue #2370. - - """ - G = nx.DiGraph() - G.add_edge(0, 1) - H = G.edge_subgraph([(0, 1)]) - assert list(H.predecessors(0)) == [] - assert list(H.successors(0)) == [1] - assert list(H.predecessors(1)) == [0] - assert list(H.successors(1)) == [] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph_historical.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph_historical.py deleted file mode 100644 index 4f2b1da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_digraph_historical.py +++ /dev/null @@ -1,111 +0,0 @@ -"""Original NetworkX graph tests""" - -import pytest - -import networkx -import networkx as nx - -from .historical_tests import HistoricalTests - - -class TestDiGraphHistorical(HistoricalTests): - @classmethod - def setup_class(cls): - HistoricalTests.setup_class() - cls.G = nx.DiGraph - - def test_in_degree(self): - G = self.G() - G.add_nodes_from("GJK") - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")]) - - assert sorted(d for n, d in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2] - assert dict(G.in_degree()) == { - "A": 0, - "C": 2, - "B": 1, - "D": 2, - "G": 0, - "K": 0, - "J": 0, - } - - def test_out_degree(self): - G = self.G() - G.add_nodes_from("GJK") - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")]) - assert sorted(v for k, v in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2] - assert dict(G.out_degree()) == { - "A": 2, - "C": 1, - "B": 2, - "D": 0, - "G": 0, - "K": 0, - "J": 0, - } - - def test_degree_digraph(self): - H = nx.DiGraph() - H.add_edges_from([(1, 24), (1, 2)]) - assert sorted(d for n, d in H.in_degree([1, 24])) == [0, 1] - assert sorted(d for n, d in H.out_degree([1, 24])) == [0, 2] - assert sorted(d for n, d in H.degree([1, 24])) == [1, 2] - - def test_neighbors(self): - G = self.G() - G.add_nodes_from("GJK") - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")]) - - assert sorted(G.neighbors("C")) == ["D"] - assert sorted(G["C"]) == ["D"] - assert sorted(G.neighbors("A")) == ["B", "C"] - pytest.raises(nx.NetworkXError, G.neighbors, "j") - pytest.raises(nx.NetworkXError, G.neighbors, "j") - - def test_successors(self): - G = self.G() - G.add_nodes_from("GJK") - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")]) - assert sorted(G.successors("A")) == ["B", "C"] - assert sorted(G.successors("A")) == ["B", "C"] - assert sorted(G.successors("G")) == [] - assert sorted(G.successors("D")) == [] - assert sorted(G.successors("G")) == [] - pytest.raises(nx.NetworkXError, G.successors, "j") - pytest.raises(nx.NetworkXError, G.successors, "j") - - def test_predecessors(self): - G = self.G() - G.add_nodes_from("GJK") - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")]) - assert sorted(G.predecessors("C")) == ["A", "B"] - assert sorted(G.predecessors("C")) == ["A", "B"] - assert sorted(G.predecessors("G")) == [] - assert sorted(G.predecessors("A")) == [] - assert sorted(G.predecessors("G")) == [] - assert sorted(G.predecessors("A")) == [] - assert sorted(G.successors("D")) == [] - - pytest.raises(nx.NetworkXError, G.predecessors, "j") - pytest.raises(nx.NetworkXError, G.predecessors, "j") - - def test_reverse(self): - G = nx.complete_graph(10) - H = G.to_directed() - HR = H.reverse() - assert nx.is_isomorphic(H, HR) - assert sorted(H.edges()) == sorted(HR.edges()) - - def test_reverse2(self): - H = nx.DiGraph() - foo = [H.add_edge(u, u + 1) for u in range(5)] - HR = H.reverse() - for u in range(5): - assert HR.has_edge(u + 1, u) - - def test_reverse3(self): - H = nx.DiGraph() - H.add_nodes_from([1, 2, 3, 4]) - HR = H.reverse() - assert sorted(HR.nodes()) == [1, 2, 3, 4] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_filters.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_filters.py deleted file mode 100644 index 2da5911..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_filters.py +++ /dev/null @@ -1,177 +0,0 @@ -import pytest - -import networkx as nx - - -class TestFilterFactory: - def test_no_filter(self): - nf = nx.filters.no_filter - assert nf() - assert nf(1) - assert nf(2, 1) - - def test_hide_nodes(self): - f = nx.classes.filters.hide_nodes([1, 2, 3]) - assert not f(1) - assert not f(2) - assert not f(3) - assert f(4) - assert f(0) - assert f("a") - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f) - - def test_show_nodes(self): - f = nx.classes.filters.show_nodes([1, 2, 3]) - assert f(1) - assert f(2) - assert f(3) - assert not f(4) - assert not f(0) - assert not f("a") - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f) - - def test_hide_edges(self): - factory = nx.classes.filters.hide_edges - f = factory([(1, 2), (3, 4)]) - assert not f(1, 2) - assert not f(3, 4) - assert not f(4, 3) - assert f(2, 3) - assert f(0, -1) - assert f("a", "b") - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_show_edges(self): - factory = nx.classes.filters.show_edges - f = factory([(1, 2), (3, 4)]) - assert f(1, 2) - assert f(3, 4) - assert f(4, 3) - assert not f(2, 3) - assert not f(0, -1) - assert not f("a", "b") - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_hide_diedges(self): - factory = nx.classes.filters.hide_diedges - f = factory([(1, 2), (3, 4)]) - assert not f(1, 2) - assert not f(3, 4) - assert f(4, 3) - assert f(2, 3) - assert f(0, -1) - assert f("a", "b") - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_show_diedges(self): - factory = nx.classes.filters.show_diedges - f = factory([(1, 2), (3, 4)]) - assert f(1, 2) - assert f(3, 4) - assert not f(4, 3) - assert not f(2, 3) - assert not f(0, -1) - assert not f("a", "b") - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_hide_multiedges(self): - factory = nx.classes.filters.hide_multiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert not f(1, 2, 0) - assert not f(1, 2, 1) - assert f(1, 2, 2) - assert f(3, 4, 0) - assert not f(3, 4, 1) - assert not f(4, 3, 1) - assert f(4, 3, 0) - assert f(2, 3, 0) - assert f(0, -1, 0) - assert f("a", "b", 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_show_multiedges(self): - factory = nx.classes.filters.show_multiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert f(1, 2, 0) - assert f(1, 2, 1) - assert not f(1, 2, 2) - assert not f(3, 4, 0) - assert f(3, 4, 1) - assert f(4, 3, 1) - assert not f(4, 3, 0) - assert not f(2, 3, 0) - assert not f(0, -1, 0) - assert not f("a", "b", 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_hide_multidiedges(self): - factory = nx.classes.filters.hide_multidiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert not f(1, 2, 0) - assert not f(1, 2, 1) - assert f(1, 2, 2) - assert f(3, 4, 0) - assert not f(3, 4, 1) - assert f(4, 3, 1) - assert f(4, 3, 0) - assert f(2, 3, 0) - assert f(0, -1, 0) - assert f("a", "b", 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_show_multidiedges(self): - factory = nx.classes.filters.show_multidiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert f(1, 2, 0) - assert f(1, 2, 1) - assert not f(1, 2, 2) - assert not f(3, 4, 0) - assert f(3, 4, 1) - assert not f(4, 3, 1) - assert not f(4, 3, 0) - assert not f(2, 3, 0) - assert not f(0, -1, 0) - assert not f("a", "b", 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_function.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_function.py deleted file mode 100644 index f86890d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_function.py +++ /dev/null @@ -1,1035 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -def test_degree_histogram_empty(): - G = nx.Graph() - assert nx.degree_histogram(G) == [] - - -class TestFunction: - def setup_method(self): - self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name="Test") - self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0} - self.Gnodes = list(range(5)) - self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)] - self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}) - self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0} - self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0} - self.DGnodes = list(range(5)) - self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)] - - def test_nodes(self): - assert nodes_equal(self.G.nodes(), list(nx.nodes(self.G))) - assert nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG))) - - def test_edges(self): - assert edges_equal(self.G.edges(), list(nx.edges(self.G))) - assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG)) - assert edges_equal( - self.G.edges(nbunch=[0, 1, 3]), list(nx.edges(self.G, nbunch=[0, 1, 3])) - ) - assert sorted(self.DG.edges(nbunch=[0, 1, 3])) == sorted( - nx.edges(self.DG, nbunch=[0, 1, 3]) - ) - - def test_degree(self): - assert edges_equal(self.G.degree(), list(nx.degree(self.G))) - assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG)) - assert edges_equal( - self.G.degree(nbunch=[0, 1]), list(nx.degree(self.G, nbunch=[0, 1])) - ) - assert sorted(self.DG.degree(nbunch=[0, 1])) == sorted( - nx.degree(self.DG, nbunch=[0, 1]) - ) - assert edges_equal( - self.G.degree(weight="weight"), list(nx.degree(self.G, weight="weight")) - ) - assert sorted(self.DG.degree(weight="weight")) == sorted( - nx.degree(self.DG, weight="weight") - ) - - def test_neighbors(self): - assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1)) - assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1)) - - def test_number_of_nodes(self): - assert self.G.number_of_nodes() == nx.number_of_nodes(self.G) - assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG) - - def test_number_of_edges(self): - assert self.G.number_of_edges() == nx.number_of_edges(self.G) - assert self.DG.number_of_edges() == nx.number_of_edges(self.DG) - - def test_is_directed(self): - assert self.G.is_directed() == nx.is_directed(self.G) - assert self.DG.is_directed() == nx.is_directed(self.DG) - - def test_add_star(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - nx.add_star(G, nlist) - assert edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)]) - - G = self.G.copy() - nx.add_star(G, nlist, weight=2.0) - assert edges_equal( - G.edges(nlist, data=True), - [ - (12, 13, {"weight": 2.0}), - (12, 14, {"weight": 2.0}), - (12, 15, {"weight": 2.0}), - ], - ) - - G = self.G.copy() - nlist = [12] - nx.add_star(G, nlist) - assert nodes_equal(G, list(self.G) + nlist) - - G = self.G.copy() - nlist = [] - nx.add_star(G, nlist) - assert nodes_equal(G.nodes, self.Gnodes) - assert edges_equal(G.edges, self.G.edges) - - def test_add_path(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - nx.add_path(G, nlist) - assert edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)]) - G = self.G.copy() - nx.add_path(G, nlist, weight=2.0) - assert edges_equal( - G.edges(nlist, data=True), - [ - (12, 13, {"weight": 2.0}), - (13, 14, {"weight": 2.0}), - (14, 15, {"weight": 2.0}), - ], - ) - - G = self.G.copy() - nlist = ["node"] - nx.add_path(G, nlist) - assert edges_equal(G.edges(nlist), []) - assert nodes_equal(G, list(self.G) + ["node"]) - - G = self.G.copy() - nlist = iter(["node"]) - nx.add_path(G, nlist) - assert edges_equal(G.edges(["node"]), []) - assert nodes_equal(G, list(self.G) + ["node"]) - - G = self.G.copy() - nlist = [12] - nx.add_path(G, nlist) - assert edges_equal(G.edges(nlist), []) - assert nodes_equal(G, list(self.G) + [12]) - - G = self.G.copy() - nlist = iter([12]) - nx.add_path(G, nlist) - assert edges_equal(G.edges([12]), []) - assert nodes_equal(G, list(self.G) + [12]) - - G = self.G.copy() - nlist = [] - nx.add_path(G, nlist) - assert edges_equal(G.edges, self.G.edges) - assert nodes_equal(G, list(self.G)) - - G = self.G.copy() - nlist = iter([]) - nx.add_path(G, nlist) - assert edges_equal(G.edges, self.G.edges) - assert nodes_equal(G, list(self.G)) - - def test_add_cycle(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - oklists = [ - [(12, 13), (12, 15), (13, 14), (14, 15)], - [(12, 13), (13, 14), (14, 15), (15, 12)], - ] - nx.add_cycle(G, nlist) - assert sorted(G.edges(nlist)) in oklists - G = self.G.copy() - oklists = [ - [ - (12, 13, {"weight": 1.0}), - (12, 15, {"weight": 1.0}), - (13, 14, {"weight": 1.0}), - (14, 15, {"weight": 1.0}), - ], - [ - (12, 13, {"weight": 1.0}), - (13, 14, {"weight": 1.0}), - (14, 15, {"weight": 1.0}), - (15, 12, {"weight": 1.0}), - ], - ] - nx.add_cycle(G, nlist, weight=1.0) - assert sorted(G.edges(nlist, data=True)) in oklists - - G = self.G.copy() - nlist = [12] - nx.add_cycle(G, nlist) - assert nodes_equal(G, list(self.G) + nlist) - - G = self.G.copy() - nlist = [] - nx.add_cycle(G, nlist) - assert nodes_equal(G.nodes, self.Gnodes) - assert edges_equal(G.edges, self.G.edges) - - def test_subgraph(self): - assert ( - self.G.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.G, [0, 1, 2, 4]).adj - ) - assert ( - self.DG.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.DG, [0, 1, 2, 4]).adj - ) - assert ( - self.G.subgraph([0, 1, 2, 4]).adj - == nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj - ) - assert ( - self.DG.subgraph([0, 1, 2, 4]).adj - == nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj - ) - # subgraph-subgraph chain is allowed in function interface - H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4]) - assert H._graph is not self.G - assert H.adj == self.G.subgraph([0, 1, 4]).adj - - def test_edge_subgraph(self): - assert ( - self.G.edge_subgraph([(1, 2), (0, 3)]).adj - == nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj - ) - assert ( - self.DG.edge_subgraph([(1, 2), (0, 3)]).adj - == nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj - ) - - def test_create_empty_copy(self): - G = nx.create_empty_copy(self.G, with_data=False) - assert nodes_equal(G, list(self.G)) - assert G.graph == {} - assert G._node == {}.fromkeys(self.G.nodes(), {}) - assert G._adj == {}.fromkeys(self.G.nodes(), {}) - G = nx.create_empty_copy(self.G) - assert nodes_equal(G, list(self.G)) - assert G.graph == self.G.graph - assert G._node == self.G._node - assert G._adj == {}.fromkeys(self.G.nodes(), {}) - - def test_degree_histogram(self): - assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1] - - def test_density(self): - assert nx.density(self.G) == 0.5 - assert nx.density(self.DG) == 0.3 - G = nx.Graph() - G.add_node(1) - assert nx.density(G) == 0.0 - - def test_density_selfloop(self): - G = nx.Graph() - G.add_edge(1, 1) - assert nx.density(G) == 0.0 - G.add_edge(1, 2) - assert nx.density(G) == 2.0 - - def test_freeze(self): - G = nx.freeze(self.G) - assert G.frozen - pytest.raises(nx.NetworkXError, G.add_node, 1) - pytest.raises(nx.NetworkXError, G.add_nodes_from, [1]) - pytest.raises(nx.NetworkXError, G.remove_node, 1) - pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1]) - pytest.raises(nx.NetworkXError, G.add_edge, 1, 2) - pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)]) - pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2) - pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)]) - pytest.raises(nx.NetworkXError, G.clear_edges) - pytest.raises(nx.NetworkXError, G.clear) - - def test_is_frozen(self): - assert not nx.is_frozen(self.G) - G = nx.freeze(self.G) - assert G.frozen == nx.is_frozen(self.G) - assert G.frozen - - def test_node_attributes_are_still_mutable_on_frozen_graph(self): - G = nx.freeze(nx.path_graph(3)) - node = G.nodes[0] - node["node_attribute"] = True - assert node["node_attribute"] == True - - def test_edge_attributes_are_still_mutable_on_frozen_graph(self): - G = nx.freeze(nx.path_graph(3)) - edge = G.edges[(0, 1)] - edge["edge_attribute"] = True - assert edge["edge_attribute"] == True - - def test_neighbors_complete_graph(self): - graph = nx.complete_graph(100) - pop = random.sample(list(graph), 1) - nbors = list(nx.neighbors(graph, pop[0])) - # should be all the other vertices in the graph - assert len(nbors) == len(graph) - 1 - - graph = nx.path_graph(100) - node = random.sample(list(graph), 1)[0] - nbors = list(nx.neighbors(graph, node)) - # should be all the other vertices in the graph - if node != 0 and node != 99: - assert len(nbors) == 2 - else: - assert len(nbors) == 1 - - # create a star graph with 99 outer nodes - graph = nx.star_graph(99) - nbors = list(nx.neighbors(graph, 0)) - assert len(nbors) == 99 - - def test_non_neighbors(self): - graph = nx.complete_graph(100) - pop = random.sample(list(graph), 1) - nbors = nx.non_neighbors(graph, pop[0]) - # should be all the other vertices in the graph - assert len(nbors) == 0 - - graph = nx.path_graph(100) - node = random.sample(list(graph), 1)[0] - nbors = nx.non_neighbors(graph, node) - # should be all the other vertices in the graph - if node != 0 and node != 99: - assert len(nbors) == 97 - else: - assert len(nbors) == 98 - - # create a star graph with 99 outer nodes - graph = nx.star_graph(99) - nbors = nx.non_neighbors(graph, 0) - assert len(nbors) == 0 - - # disconnected graph - graph = nx.Graph() - graph.add_nodes_from(range(10)) - nbors = nx.non_neighbors(graph, 0) - assert len(nbors) == 9 - - def test_non_edges(self): - # All possible edges exist - graph = nx.complete_graph(5) - nedges = list(nx.non_edges(graph)) - assert len(nedges) == 0 - - graph = nx.path_graph(4) - expected = [(0, 2), (0, 3), (1, 3)] - nedges = list(nx.non_edges(graph)) - for u, v in expected: - assert (u, v) in nedges or (v, u) in nedges - - graph = nx.star_graph(4) - expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - nedges = list(nx.non_edges(graph)) - for u, v in expected: - assert (u, v) in nedges or (v, u) in nedges - - # Directed graphs - graph = nx.DiGraph() - graph.add_edges_from([(0, 2), (2, 0), (2, 1)]) - expected = [(0, 1), (1, 0), (1, 2)] - nedges = list(nx.non_edges(graph)) - for e in expected: - assert e in nedges - - def test_is_weighted(self): - G = nx.Graph() - assert not nx.is_weighted(G) - - G = nx.path_graph(4) - assert not nx.is_weighted(G) - assert not nx.is_weighted(G, (2, 3)) - - G.add_node(4) - G.add_edge(3, 4, weight=4) - assert not nx.is_weighted(G) - assert nx.is_weighted(G, (3, 4)) - - G = nx.DiGraph() - G.add_weighted_edges_from( - [ - ("0", "3", 3), - ("0", "1", -5), - ("1", "0", -5), - ("0", "2", 2), - ("1", "2", 4), - ("2", "3", 1), - ] - ) - assert nx.is_weighted(G) - assert nx.is_weighted(G, ("1", "0")) - - G = G.to_undirected() - assert nx.is_weighted(G) - assert nx.is_weighted(G, ("1", "0")) - - pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2)) - - def test_is_negatively_weighted(self): - G = nx.Graph() - assert not nx.is_negatively_weighted(G) - - G.add_node(1) - G.add_nodes_from([2, 3, 4, 5]) - assert not nx.is_negatively_weighted(G) - - G.add_edge(1, 2, weight=4) - assert not nx.is_negatively_weighted(G, (1, 2)) - - G.add_edges_from([(1, 3), (2, 4), (2, 6)]) - G[1][3]["color"] = "blue" - assert not nx.is_negatively_weighted(G) - assert not nx.is_negatively_weighted(G, (1, 3)) - - G[2][4]["weight"] = -2 - assert nx.is_negatively_weighted(G, (2, 4)) - assert nx.is_negatively_weighted(G) - - G = nx.DiGraph() - G.add_weighted_edges_from( - [ - ("0", "3", 3), - ("0", "1", -5), - ("1", "0", -2), - ("0", "2", 2), - ("1", "2", -3), - ("2", "3", 1), - ] - ) - assert nx.is_negatively_weighted(G) - assert not nx.is_negatively_weighted(G, ("0", "3")) - assert nx.is_negatively_weighted(G, ("1", "0")) - - pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4)) - - -class TestCommonNeighbors: - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.common_neighbors) - - def test_func(G, u, v, expected): - result = sorted(cls.func(G, u, v)) - assert result == expected - - cls.test = staticmethod(test_func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, 0, 1, [2, 3, 4]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, 0, 2, [1]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, 1, 2, [0]) - - def test_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2)]) - self.func(G, 0, 2) - - def test_nonexistent_nodes(self): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6) - - def test_custom1(self): - """Case of no common neighbors.""" - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, 0, 1, []) - - def test_custom2(self): - """Case of equal nodes.""" - G = nx.complete_graph(4) - self.test(G, 0, 0, [1, 2, 3]) - - -@pytest.mark.parametrize( - "graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) -) -def test_set_node_attributes(graph_type): - # Test single value - G = nx.path_graph(3, create_using=graph_type) - vals = 100 - attr = "hello" - nx.set_node_attributes(G, vals, attr) - assert G.nodes[0][attr] == vals - assert G.nodes[1][attr] == vals - assert G.nodes[2][attr] == vals - - # Test dictionary - G = nx.path_graph(3, create_using=graph_type) - vals = dict(zip(sorted(G.nodes()), range(len(G)))) - attr = "hi" - nx.set_node_attributes(G, vals, attr) - assert G.nodes[0][attr] == 0 - assert G.nodes[1][attr] == 1 - assert G.nodes[2][attr] == 2 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=graph_type) - d = {"hi": 0, "hello": 200} - vals = dict.fromkeys(G.nodes(), d) - vals.pop(0) - nx.set_node_attributes(G, vals) - assert G.nodes[0] == {} - assert G.nodes[1]["hi"] == 0 - assert G.nodes[2]["hello"] == 200 - - -@pytest.mark.parametrize( - ("values", "name"), - ( - ({0: "red", 1: "blue"}, "color"), # values dictionary - ({0: {"color": "red"}, 1: {"color": "blue"}}, None), # dict-of-dict - ), -) -def test_set_node_attributes_ignores_extra_nodes(values, name): - """ - When `values` is a dict or dict-of-dict keyed by nodes, ensure that keys - that correspond to nodes not in G are ignored. - """ - G = nx.Graph() - G.add_node(0) - nx.set_node_attributes(G, values, name) - assert G.nodes[0]["color"] == "red" - assert 1 not in G.nodes - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph)) -def test_set_edge_attributes(graph_type): - # Test single value - G = nx.path_graph(3, create_using=graph_type) - attr = "hello" - vals = 3 - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][attr] == vals - assert G[1][2][attr] == vals - - # Test multiple values - G = nx.path_graph(3, create_using=graph_type) - attr = "hi" - edges = [(0, 1), (1, 2)] - vals = dict(zip(edges, range(len(edges)))) - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][attr] == 0 - assert G[1][2][attr] == 1 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=graph_type) - d = {"hi": 0, "hello": 200} - edges = [(0, 1)] - vals = dict.fromkeys(edges, d) - nx.set_edge_attributes(G, vals) - assert G[0][1]["hi"] == 0 - assert G[0][1]["hello"] == 200 - assert G[1][2] == {} - - -@pytest.mark.parametrize( - ("values", "name"), - ( - ({(0, 1): 1.0, (0, 2): 2.0}, "weight"), # values dict - ({(0, 1): {"weight": 1.0}, (0, 2): {"weight": 2.0}}, None), # values dod - ), -) -def test_set_edge_attributes_ignores_extra_edges(values, name): - """If `values` is a dict or dict-of-dicts containing edges that are not in - G, data associate with these edges should be ignored. - """ - G = nx.Graph([(0, 1)]) - nx.set_edge_attributes(G, values, name) - assert G[0][1]["weight"] == 1.0 - assert (0, 2) not in G.edges - - -@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph)) -def test_set_edge_attributes_multi(graph_type): - # Test single value - G = nx.path_graph(3, create_using=graph_type) - attr = "hello" - vals = 3 - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][0][attr] == vals - assert G[1][2][0][attr] == vals - - # Test multiple values - G = nx.path_graph(3, create_using=graph_type) - attr = "hi" - edges = [(0, 1, 0), (1, 2, 0)] - vals = dict(zip(edges, range(len(edges)))) - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][0][attr] == 0 - assert G[1][2][0][attr] == 1 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=graph_type) - d = {"hi": 0, "hello": 200} - edges = [(0, 1, 0)] - vals = dict.fromkeys(edges, d) - nx.set_edge_attributes(G, vals) - assert G[0][1][0]["hi"] == 0 - assert G[0][1][0]["hello"] == 200 - assert G[1][2][0] == {} - - -@pytest.mark.parametrize( - ("values", "name"), - ( - ({(0, 1, 0): 1.0, (0, 2, 0): 2.0}, "weight"), # values dict - ({(0, 1, 0): {"weight": 1.0}, (0, 2, 0): {"weight": 2.0}}, None), # values dod - ), -) -def test_set_edge_attributes_multi_ignores_extra_edges(values, name): - """If `values` is a dict or dict-of-dicts containing edges that are not in - G, data associate with these edges should be ignored. - """ - G = nx.MultiGraph([(0, 1, 0), (0, 1, 1)]) - nx.set_edge_attributes(G, values, name) - assert G[0][1][0]["weight"] == 1.0 - assert G[0][1][1] == {} - assert (0, 2) not in G.edges() - - -def test_get_node_attributes(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - G = nx.path_graph(3, create_using=G) - attr = "hello" - vals = 100 - nx.set_node_attributes(G, vals, attr) - attrs = nx.get_node_attributes(G, attr) - assert attrs[0] == vals - assert attrs[1] == vals - assert attrs[2] == vals - default_val = 1 - G.add_node(4) - attrs = nx.get_node_attributes(G, attr, default=default_val) - assert attrs[4] == default_val - - -def test_get_edge_attributes(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - G = nx.path_graph(3, create_using=G) - attr = "hello" - vals = 100 - nx.set_edge_attributes(G, vals, attr) - attrs = nx.get_edge_attributes(G, attr) - assert len(attrs) == 2 - - for edge in G.edges: - assert attrs[edge] == vals - - default_val = vals - G.add_edge(4, 5) - deafult_attrs = nx.get_edge_attributes(G, attr, default=default_val) - assert len(deafult_attrs) == 3 - - for edge in G.edges: - assert deafult_attrs[edge] == vals - - -@pytest.mark.parametrize( - "graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) -) -def test_remove_node_attributes(graph_type): - # Test removing single attribute - G = nx.path_graph(3, create_using=graph_type) - vals = 100 - attr = "hello" - nx.set_node_attributes(G, vals, attr) - nx.remove_node_attributes(G, attr) - assert attr not in G.nodes[0] - assert attr not in G.nodes[1] - assert attr not in G.nodes[2] - - # Test removing single attribute when multiple present - G = nx.path_graph(3, create_using=graph_type) - other_vals = 200 - other_attr = "other" - nx.set_node_attributes(G, vals, attr) - nx.set_node_attributes(G, other_vals, other_attr) - nx.remove_node_attributes(G, attr) - assert attr not in G.nodes[0] - assert G.nodes[0][other_attr] == other_vals - assert attr not in G.nodes[1] - assert G.nodes[1][other_attr] == other_vals - assert attr not in G.nodes[2] - assert G.nodes[2][other_attr] == other_vals - - # Test removing multiple attributes - G = nx.path_graph(3, create_using=graph_type) - nx.set_node_attributes(G, vals, attr) - nx.set_node_attributes(G, other_vals, other_attr) - nx.remove_node_attributes(G, attr, other_attr) - assert attr not in G.nodes[0] and other_attr not in G.nodes[0] - assert attr not in G.nodes[1] and other_attr not in G.nodes[1] - assert attr not in G.nodes[2] and other_attr not in G.nodes[2] - - # Test removing multiple (but not all) attributes - G = nx.path_graph(3, create_using=graph_type) - third_vals = 300 - third_attr = "three" - nx.set_node_attributes( - G, - { - n: {attr: vals, other_attr: other_vals, third_attr: third_vals} - for n in G.nodes() - }, - ) - nx.remove_node_attributes(G, other_attr, third_attr) - assert other_attr not in G.nodes[0] and third_attr not in G.nodes[0] - assert other_attr not in G.nodes[1] and third_attr not in G.nodes[1] - assert other_attr not in G.nodes[2] and third_attr not in G.nodes[2] - assert G.nodes[0][attr] == vals - assert G.nodes[1][attr] == vals - assert G.nodes[2][attr] == vals - - # Test incomplete node attributes - G = nx.path_graph(3, create_using=graph_type) - nx.set_node_attributes( - G, - { - 1: {attr: vals, other_attr: other_vals}, - 2: {attr: vals, other_attr: other_vals}, - }, - ) - nx.remove_node_attributes(G, attr) - assert attr not in G.nodes[0] - assert attr not in G.nodes[1] - assert attr not in G.nodes[2] - assert G.nodes[1][other_attr] == other_vals - assert G.nodes[2][other_attr] == other_vals - - # Test removing on a subset of nodes - G = nx.path_graph(3, create_using=graph_type) - nx.set_node_attributes( - G, - { - n: {attr: vals, other_attr: other_vals, third_attr: third_vals} - for n in G.nodes() - }, - ) - nx.remove_node_attributes(G, attr, other_attr, nbunch=[0, 1]) - assert attr not in G.nodes[0] and other_attr not in G.nodes[0] - assert attr not in G.nodes[1] and other_attr not in G.nodes[1] - assert attr in G.nodes[2] and other_attr in G.nodes[2] - assert third_attr in G.nodes[0] and G.nodes[0][third_attr] == third_vals - assert third_attr in G.nodes[1] and G.nodes[1][third_attr] == third_vals - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph)) -def test_remove_edge_attributes(graph_type): - # Test removing single attribute - G = nx.path_graph(3, create_using=graph_type) - attr = "hello" - vals = 100 - nx.set_edge_attributes(G, vals, attr) - nx.remove_edge_attributes(G, attr) - assert len(nx.get_edge_attributes(G, attr)) == 0 - - # Test removing only some attributes - G = nx.path_graph(3, create_using=graph_type) - other_attr = "other" - other_vals = 200 - nx.set_edge_attributes(G, vals, attr) - nx.set_edge_attributes(G, other_vals, other_attr) - nx.remove_edge_attributes(G, attr) - - assert attr not in G[0][1] - assert attr not in G[1][2] - assert G[0][1][other_attr] == 200 - assert G[1][2][other_attr] == 200 - - # Test removing multiple attributes - G = nx.path_graph(3, create_using=graph_type) - nx.set_edge_attributes(G, vals, attr) - nx.set_edge_attributes(G, other_vals, other_attr) - nx.remove_edge_attributes(G, attr, other_attr) - assert attr not in G[0][1] and other_attr not in G[0][1] - assert attr not in G[1][2] and other_attr not in G[1][2] - - # Test removing multiple (not all) attributes - G = nx.path_graph(3, create_using=graph_type) - third_attr = "third" - third_vals = 300 - nx.set_edge_attributes( - G, - { - (u, v): {attr: vals, other_attr: other_vals, third_attr: third_vals} - for u, v in G.edges() - }, - ) - nx.remove_edge_attributes(G, other_attr, third_attr) - assert other_attr not in G[0][1] and third_attr not in G[0][1] - assert other_attr not in G[1][2] and third_attr not in G[1][2] - assert G[0][1][attr] == vals - assert G[1][2][attr] == vals - - # Test removing incomplete edge attributes - G = nx.path_graph(3, create_using=graph_type) - nx.set_edge_attributes(G, {(0, 1): {attr: vals, other_attr: other_vals}}) - nx.remove_edge_attributes(G, other_attr) - assert other_attr not in G[0][1] and G[0][1][attr] == vals - assert other_attr not in G[1][2] - - # Test removing subset of edge attributes - G = nx.path_graph(3, create_using=graph_type) - nx.set_edge_attributes( - G, - { - (u, v): {attr: vals, other_attr: other_vals, third_attr: third_vals} - for u, v in G.edges() - }, - ) - nx.remove_edge_attributes(G, other_attr, third_attr, ebunch=[(0, 1)]) - assert other_attr not in G[0][1] and third_attr not in G[0][1] - assert other_attr in G[1][2] and third_attr in G[1][2] - - -@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph)) -def test_remove_multi_edge_attributes(graph_type): - # Test removing single attribute - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - attr = "hello" - vals = 100 - nx.set_edge_attributes(G, vals, attr) - nx.remove_edge_attributes(G, attr) - assert attr not in G[0][1][0] - assert attr not in G[1][2][0] - assert attr not in G[1][2][1] - - # Test removing only some attributes - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - other_attr = "other" - other_vals = 200 - nx.set_edge_attributes(G, vals, attr) - nx.set_edge_attributes(G, other_vals, other_attr) - nx.remove_edge_attributes(G, attr) - assert attr not in G[0][1][0] - assert attr not in G[1][2][0] - assert attr not in G[1][2][1] - assert G[0][1][0][other_attr] == other_vals - assert G[1][2][0][other_attr] == other_vals - assert G[1][2][1][other_attr] == other_vals - - # Test removing multiple attributes - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - nx.set_edge_attributes(G, vals, attr) - nx.set_edge_attributes(G, other_vals, other_attr) - nx.remove_edge_attributes(G, attr, other_attr) - assert attr not in G[0][1][0] and other_attr not in G[0][1][0] - assert attr not in G[1][2][0] and other_attr not in G[1][2][0] - assert attr not in G[1][2][1] and other_attr not in G[1][2][1] - - # Test removing multiple (not all) attributes - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - third_attr = "third" - third_vals = 300 - nx.set_edge_attributes( - G, - { - (u, v, k): {attr: vals, other_attr: other_vals, third_attr: third_vals} - for u, v, k in G.edges(keys=True) - }, - ) - nx.remove_edge_attributes(G, other_attr, third_attr) - assert other_attr not in G[0][1][0] and third_attr not in G[0][1][0] - assert other_attr not in G[1][2][0] and other_attr not in G[1][2][0] - assert other_attr not in G[1][2][1] and other_attr not in G[1][2][1] - assert G[0][1][0][attr] == vals - assert G[1][2][0][attr] == vals - assert G[1][2][1][attr] == vals - - # Test removing incomplete edge attributes - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - nx.set_edge_attributes( - G, - { - (0, 1, 0): {attr: vals, other_attr: other_vals}, - (1, 2, 1): {attr: vals, other_attr: other_vals}, - }, - ) - nx.remove_edge_attributes(G, other_attr) - assert other_attr not in G[0][1][0] and G[0][1][0][attr] == vals - assert other_attr not in G[1][2][0] - assert other_attr not in G[1][2][1] - - # Test removing subset of edge attributes - G = nx.path_graph(3, create_using=graph_type) - G.add_edge(1, 2) - nx.set_edge_attributes( - G, - { - (0, 1, 0): {attr: vals, other_attr: other_vals}, - (1, 2, 0): {attr: vals, other_attr: other_vals}, - (1, 2, 1): {attr: vals, other_attr: other_vals}, - }, - ) - nx.remove_edge_attributes(G, attr, ebunch=[(0, 1, 0), (1, 2, 0)]) - assert attr not in G[0][1][0] and other_attr in G[0][1][0] - assert attr not in G[1][2][0] and other_attr in G[1][2][0] - assert attr in G[1][2][1] and other_attr in G[1][2][1] - - -def test_is_empty(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - assert nx.is_empty(G) - G.add_nodes_from(range(5)) - assert nx.is_empty(G) - G.add_edges_from([(1, 2), (3, 4)]) - assert not nx.is_empty(G) - - -@pytest.mark.parametrize( - "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] -) -def test_selfloops(graph_type): - G = nx.complete_graph(3, create_using=graph_type) - G.add_edge(0, 0) - assert nodes_equal(nx.nodes_with_selfloops(G), [0]) - assert edges_equal(nx.selfloop_edges(G), [(0, 0)]) - assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})]) - assert nx.number_of_selfloops(G) == 1 - - -@pytest.mark.parametrize( - "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] -) -def test_selfloop_edges_attr(graph_type): - G = nx.complete_graph(3, create_using=graph_type) - G.add_edge(0, 0) - G.add_edge(1, 1, weight=2) - assert edges_equal( - nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})] - ) - assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)]) - - -def test_selfloop_edges_multi_with_data_and_keys(): - G = nx.complete_graph(3, create_using=nx.MultiGraph) - G.add_edge(0, 0, weight=10) - G.add_edge(0, 0, weight=100) - assert edges_equal( - nx.selfloop_edges(G, data="weight", keys=True), [(0, 0, 0, 10), (0, 0, 1, 100)] - ) - - -@pytest.mark.parametrize("graph_type", [nx.Graph, nx.DiGraph]) -def test_selfloops_removal(graph_type): - G = nx.complete_graph(3, create_using=graph_type) - G.add_edge(0, 0) - G.remove_edges_from(nx.selfloop_edges(G, keys=True)) - G.add_edge(0, 0) - G.remove_edges_from(nx.selfloop_edges(G, data=True)) - G.add_edge(0, 0) - G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True)) - - -@pytest.mark.parametrize("graph_type", [nx.MultiGraph, nx.MultiDiGraph]) -def test_selfloops_removal_multi(graph_type): - """test removing selfloops behavior vis-a-vis altering a dict while iterating. - cf. gh-4068""" - G = nx.complete_graph(3, create_using=graph_type) - # Defaults - see gh-4080 - G.add_edge(0, 0) - G.add_edge(0, 0) - G.remove_edges_from(nx.selfloop_edges(G)) - assert (0, 0) not in G.edges() - # With keys - G.add_edge(0, 0) - G.add_edge(0, 0) - with pytest.raises(RuntimeError): - G.remove_edges_from(nx.selfloop_edges(G, keys=True)) - # With data - G.add_edge(0, 0) - G.add_edge(0, 0) - with pytest.raises(TypeError): - G.remove_edges_from(nx.selfloop_edges(G, data=True)) - # With keys and data - G.add_edge(0, 0) - G.add_edge(0, 0) - with pytest.raises(RuntimeError): - G.remove_edges_from(nx.selfloop_edges(G, data=True, keys=True)) - - -def test_pathweight(): - valid_path = [1, 2, 3] - invalid_path = [1, 3, 2] - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - edges = [ - (1, 2, {"cost": 5, "dist": 6}), - (2, 3, {"cost": 3, "dist": 4}), - (1, 2, {"cost": 1, "dist": 2}), - ] - for graph in graphs: - graph.add_edges_from(edges) - assert nx.path_weight(graph, valid_path, "cost") == 4 - assert nx.path_weight(graph, valid_path, "dist") == 6 - pytest.raises(nx.NetworkXNoPath, nx.path_weight, graph, invalid_path, "cost") - - -@pytest.mark.parametrize( - "G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()) -) -def test_ispath(G): - G.add_edges_from([(1, 2), (2, 3), (1, 2), (3, 4)]) - valid_path = [1, 2, 3, 4] - invalid_path = [1, 2, 4, 3] # wrong node order - another_invalid_path = [1, 2, 3, 4, 5] # contains node not in G - assert nx.is_path(G, valid_path) - assert not nx.is_path(G, invalid_path) - assert not nx.is_path(G, another_invalid_path) - - -@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) -def test_restricted_view(G): - G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]) - G.add_node(4) - H = nx.restricted_view(G, [0, 2, 5], [(1, 2), (3, 4)]) - assert set(H.nodes()) == {1, 3, 4} - assert set(H.edges()) == {(1, 1)} - - -@pytest.mark.parametrize("G", (nx.MultiGraph(), nx.MultiDiGraph())) -def test_restricted_view_multi(G): - G.add_edges_from( - [(0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (1, 0, 0), (1, 1, 0), (1, 2, 0)] - ) - G.add_node(4) - H = nx.restricted_view(G, [0, 2, 5], [(1, 2, 0), (3, 4, 0)]) - assert set(H.nodes()) == {1, 3, 4} - assert set(H.edges()) == {(1, 1)} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph.py deleted file mode 100644 index b0048a3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph.py +++ /dev/null @@ -1,920 +0,0 @@ -import gc -import pickle -import platform -import weakref - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, graphs_equal, nodes_equal - - -class BaseGraphTester: - """Tests for data-structure independent graph class features.""" - - def test_contains(self): - G = self.K3 - assert 1 in G - assert 4 not in G - assert "b" not in G - assert [] not in G # no exception for nonhashable - assert {1: 1} not in G # no exception for nonhashable - - def test_order(self): - G = self.K3 - assert len(G) == 3 - assert G.order() == 3 - assert G.number_of_nodes() == 3 - - def test_nodes(self): - G = self.K3 - assert isinstance(G._node, G.node_dict_factory) - assert isinstance(G._adj, G.adjlist_outer_dict_factory) - assert all( - isinstance(adj, G.adjlist_inner_dict_factory) for adj in G._adj.values() - ) - assert sorted(G.nodes()) == self.k3nodes - assert sorted(G.nodes(data=True)) == [(0, {}), (1, {}), (2, {})] - - def test_none_node(self): - G = self.Graph() - with pytest.raises(ValueError): - G.add_node(None) - with pytest.raises(ValueError): - G.add_nodes_from([None]) - with pytest.raises(ValueError): - G.add_edge(0, None) - with pytest.raises(ValueError): - G.add_edges_from([(0, None)]) - - def test_has_node(self): - G = self.K3 - assert G.has_node(1) - assert not G.has_node(4) - assert not G.has_node([]) # no exception for nonhashable - assert not G.has_node({1: 1}) # no exception for nonhashable - - def test_has_edge(self): - G = self.K3 - assert G.has_edge(0, 1) - assert not G.has_edge(0, -1) - - def test_neighbors(self): - G = self.K3 - assert sorted(G.neighbors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.neighbors(-1) - - @pytest.mark.skipif( - platform.python_implementation() == "PyPy", reason="PyPy gc is different" - ) - def test_memory_leak(self): - G = self.Graph() - - def count_objects_of_type(_type): - # Iterating over all objects tracked by gc can include weak references - # whose weakly-referenced objects may no longer exist. Calling `isinstance` - # on such a weak reference will raise ReferenceError. There are at least - # three workarounds for this: one is to compare type names instead of using - # `isinstance` such as `type(obj).__name__ == typename`, another is to use - # `type(obj) == _type`, and the last is to ignore ProxyTypes as we do below. - # NOTE: even if this safeguard is deemed unnecessary to pass NetworkX tests, - # we should still keep it for maximum safety for other NetworkX backends. - return sum( - 1 - for obj in gc.get_objects() - if not isinstance(obj, weakref.ProxyTypes) and isinstance(obj, _type) - ) - - gc.collect() - before = count_objects_of_type(self.Graph) - G.copy() - gc.collect() - after = count_objects_of_type(self.Graph) - assert before == after - - # test a subgraph of the base class - class MyGraph(self.Graph): - pass - - gc.collect() - G = MyGraph() - before = count_objects_of_type(MyGraph) - G.copy() - gc.collect() - after = count_objects_of_type(MyGraph) - assert before == after - - def test_edges(self): - G = self.K3 - assert isinstance(G._adj, G.adjlist_outer_dict_factory) - assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)]) - assert edges_equal(G.edges(0), [(0, 1), (0, 2)]) - assert edges_equal(G.edges([0, 1]), [(0, 1), (0, 2), (1, 2)]) - with pytest.raises(nx.NetworkXError): - G.edges(-1) - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.degree()) == {0: 2, 1: 2, 2: 2} - assert G.degree(0) == 2 - with pytest.raises(nx.NetworkXError): - G.degree(-1) # node not in graph - - def test_size(self): - G = self.K3 - assert G.size() == 3 - assert G.number_of_edges() == 3 - - def test_nbunch_iter(self): - G = self.K3 - assert nodes_equal(G.nbunch_iter(), self.k3nodes) # all nodes - assert nodes_equal(G.nbunch_iter(0), [0]) # single node - assert nodes_equal(G.nbunch_iter([0, 1]), [0, 1]) # sequence - # sequence with none in graph - assert nodes_equal(G.nbunch_iter([-1]), []) - # string sequence with none in graph - assert nodes_equal(G.nbunch_iter("foo"), []) - # node not in graph doesn't get caught upon creation of iterator - bunch = G.nbunch_iter(-1) - # but gets caught when iterator used - with pytest.raises(nx.NetworkXError, match="is not a node or a sequence"): - list(bunch) - # unhashable doesn't get caught upon creation of iterator - bunch = G.nbunch_iter([0, 1, 2, {}]) - # but gets caught when iterator hits the unhashable - with pytest.raises( - nx.NetworkXError, match="in sequence nbunch is not a valid node" - ): - list(bunch) - - def test_nbunch_iter_node_format_raise(self): - # Tests that a node that would have failed string formatting - # doesn't cause an error when attempting to raise a - # :exc:`nx.NetworkXError`. - - # For more information, see pull request #1813. - G = self.Graph() - nbunch = [("x", set())] - with pytest.raises(nx.NetworkXError): - list(G.nbunch_iter(nbunch)) - - def test_selfloop_degree(self): - G = self.Graph() - G.add_edge(1, 1) - assert sorted(G.degree()) == [(1, 2)] - assert dict(G.degree()) == {1: 2} - assert G.degree(1) == 2 - assert sorted(G.degree([1])) == [(1, 2)] - assert G.degree(1, weight="weight") == 2 - - def test_selfloops(self): - G = self.K3.copy() - G.add_edge(0, 0) - assert nodes_equal(nx.nodes_with_selfloops(G), [0]) - assert edges_equal(nx.selfloop_edges(G), [(0, 0)]) - assert nx.number_of_selfloops(G) == 1 - G.remove_edge(0, 0) - G.add_edge(0, 0) - G.remove_edges_from([(0, 0)]) - G.add_edge(1, 1) - G.remove_node(1) - G.add_edge(0, 0) - G.add_edge(1, 1) - G.remove_nodes_from([0, 1]) - - def test_cache_reset(self): - G = self.K3.copy() - old_adj = G.adj - assert id(G.adj) == id(old_adj) - G._adj = {} - assert id(G.adj) != id(old_adj) - - old_nodes = G.nodes - assert id(G.nodes) == id(old_nodes) - G._node = {} - assert id(G.nodes) != id(old_nodes) - - def test_attributes_cached(self): - G = self.K3.copy() - assert id(G.nodes) == id(G.nodes) - assert id(G.edges) == id(G.edges) - assert id(G.degree) == id(G.degree) - assert id(G.adj) == id(G.adj) - - -class BaseAttrGraphTester(BaseGraphTester): - """Tests of graph class attribute features.""" - - def test_weighted_degree(self): - G = self.Graph() - G.add_edge(1, 2, weight=2, other=3) - G.add_edge(2, 3, weight=3, other=4) - assert sorted(d for n, d in G.degree(weight="weight")) == [2, 3, 5] - assert dict(G.degree(weight="weight")) == {1: 2, 2: 5, 3: 3} - assert G.degree(1, weight="weight") == 2 - assert nodes_equal((G.degree([1], weight="weight")), [(1, 2)]) - - assert nodes_equal((d for n, d in G.degree(weight="other")), [3, 7, 4]) - assert dict(G.degree(weight="other")) == {1: 3, 2: 7, 3: 4} - assert G.degree(1, weight="other") == 3 - assert edges_equal((G.degree([1], weight="other")), [(1, 3)]) - - def add_attributes(self, G): - G.graph["foo"] = [] - G.nodes[0]["foo"] = [] - G.remove_edge(1, 2) - ll = [] - G.add_edge(1, 2, foo=ll) - G.add_edge(2, 1, foo=ll) - - def test_name(self): - G = self.Graph(name="") - assert G.name == "" - G = self.Graph(name="test") - assert G.name == "test" - - def test_str_unnamed(self): - G = self.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - assert str(G) == f"{type(G).__name__} with 3 nodes and 2 edges" - - def test_str_named(self): - G = self.Graph(name="foo") - G.add_edges_from([(1, 2), (2, 3)]) - assert str(G) == f"{type(G).__name__} named 'foo' with 3 nodes and 2 edges" - - def test_graph_chain(self): - G = self.Graph([(0, 1), (1, 2)]) - DG = G.to_directed(as_view=True) - SDG = DG.subgraph([0, 1]) - RSDG = SDG.reverse(copy=False) - assert G is DG._graph - assert DG is SDG._graph - assert SDG is RSDG._graph - - def test_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy edge datadict but any container attr are same - H = G.copy() - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - def test_class_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy edge datadict but any container attr are same - H = G.__class__(G) - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - def test_fresh_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy graph structure but use fresh datadict - H = G.__class__() - H.add_nodes_from(G) - H.add_edges_from(G.edges()) - assert len(G.nodes[0]) == 1 - ddict = G.adj[1][2][0] if G.is_multigraph() else G.adj[1][2] - assert len(ddict) == 1 - assert len(H.nodes[0]) == 0 - ddict = H.adj[1][2][0] if H.is_multigraph() else H.adj[1][2] - assert len(ddict) == 0 - - def is_deepcopy(self, H, G): - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.deep_copy_attrdict(H, G) - - def deep_copy_attrdict(self, H, G): - self.deepcopy_graph_attr(H, G) - self.deepcopy_node_attr(H, G) - self.deepcopy_edge_attr(H, G) - - def deepcopy_graph_attr(self, H, G): - assert G.graph["foo"] == H.graph["foo"] - G.graph["foo"].append(1) - assert G.graph["foo"] != H.graph["foo"] - - def deepcopy_node_attr(self, H, G): - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - G.nodes[0]["foo"].append(1) - assert G.nodes[0]["foo"] != H.nodes[0]["foo"] - - def deepcopy_edge_attr(self, H, G): - assert G[1][2]["foo"] == H[1][2]["foo"] - G[1][2]["foo"].append(1) - assert G[1][2]["foo"] != H[1][2]["foo"] - - def is_shallow_copy(self, H, G): - self.graphs_equal(H, G) - self.shallow_copy_attrdict(H, G) - - def shallow_copy_attrdict(self, H, G): - self.shallow_copy_graph_attr(H, G) - self.shallow_copy_node_attr(H, G) - self.shallow_copy_edge_attr(H, G) - - def shallow_copy_graph_attr(self, H, G): - assert G.graph["foo"] == H.graph["foo"] - G.graph["foo"].append(1) - assert G.graph["foo"] == H.graph["foo"] - - def shallow_copy_node_attr(self, H, G): - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - G.nodes[0]["foo"].append(1) - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - - def shallow_copy_edge_attr(self, H, G): - assert G[1][2]["foo"] == H[1][2]["foo"] - G[1][2]["foo"].append(1) - assert G[1][2]["foo"] == H[1][2]["foo"] - - def same_attrdict(self, H, G): - old_foo = H[1][2]["foo"] - H.adj[1][2]["foo"] = "baz" - assert G.edges == H.edges - H.adj[1][2]["foo"] = old_foo - assert G.edges == H.edges - - old_foo = H.nodes[0]["foo"] - H.nodes[0]["foo"] = "baz" - assert G.nodes == H.nodes - H.nodes[0]["foo"] = old_foo - assert G.nodes == H.nodes - - def different_attrdict(self, H, G): - old_foo = H[1][2]["foo"] - H.adj[1][2]["foo"] = "baz" - assert G._adj != H._adj - H.adj[1][2]["foo"] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]["foo"] - H.nodes[0]["foo"] = "baz" - assert G._node != H._node - H.nodes[0]["foo"] = old_foo - assert G._node == H._node - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2] is H._adj[2][1] - assert G._adj[1][2] is G._adj[2][1] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2] is H._pred[2][1] - assert G._succ[1][2] is G._pred[2][1] - - def test_graph_attr(self): - G = self.K3.copy() - G.graph["foo"] = "bar" - assert isinstance(G.graph, G.graph_attr_dict_factory) - assert G.graph["foo"] == "bar" - del G.graph["foo"] - assert G.graph == {} - H = self.Graph(foo="bar") - assert H.graph["foo"] == "bar" - - def test_node_attr(self): - G = self.K3.copy() - G.add_node(1, foo="bar") - assert all( - isinstance(d, G.node_attr_dict_factory) for u, d in G.nodes(data=True) - ) - assert nodes_equal(G.nodes(), [0, 1, 2]) - assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "bar"}), (2, {})]) - G.nodes[1]["foo"] = "baz" - assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "baz"}), (2, {})]) - assert nodes_equal(G.nodes(data="foo"), [(0, None), (1, "baz"), (2, None)]) - assert nodes_equal( - G.nodes(data="foo", default="bar"), [(0, "bar"), (1, "baz"), (2, "bar")] - ) - - def test_node_attr2(self): - G = self.K3.copy() - a = {"foo": "bar"} - G.add_node(3, **a) - assert nodes_equal(G.nodes(), [0, 1, 2, 3]) - assert nodes_equal( - G.nodes(data=True), [(0, {}), (1, {}), (2, {}), (3, {"foo": "bar"})] - ) - - def test_edge_lookup(self): - G = self.Graph() - G.add_edge(1, 2, foo="bar") - assert edges_equal(G.edges[1, 2], {"foo": "bar"}) - - def test_edge_attr(self): - G = self.Graph() - G.add_edge(1, 2, foo="bar") - assert all( - isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True) - ) - assert edges_equal(G.edges(data=True), [(1, 2, {"foo": "bar"})]) - assert edges_equal(G.edges(data="foo"), [(1, 2, "bar")]) - - def test_edge_attr2(self): - G = self.Graph() - G.add_edges_from([(1, 2), (3, 4)], foo="foo") - assert edges_equal( - G.edges(data=True), [(1, 2, {"foo": "foo"}), (3, 4, {"foo": "foo"})] - ) - assert edges_equal(G.edges(data="foo"), [(1, 2, "foo"), (3, 4, "foo")]) - - def test_edge_attr3(self): - G = self.Graph() - G.add_edges_from([(1, 2, {"weight": 32}), (3, 4, {"weight": 64})], foo="foo") - assert edges_equal( - G.edges(data=True), - [ - (1, 2, {"foo": "foo", "weight": 32}), - (3, 4, {"foo": "foo", "weight": 64}), - ], - ) - - G.remove_edges_from([(1, 2), (3, 4)]) - G.add_edge(1, 2, data=7, spam="bar", bar="foo") - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})] - ) - - def test_edge_attr4(self): - G = self.Graph() - G.add_edge(1, 2, data=7, spam="bar", bar="foo") - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})] - ) - G[1][2]["data"] = 10 # OK to set data like this - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})] - ) - - G.adj[1][2]["data"] = 20 - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})] - ) - G.edges[1, 2]["data"] = 21 # another spelling, "edge" - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})] - ) - G.adj[1][2]["listdata"] = [20, 200] - G.adj[1][2]["weight"] = 20 - dd = { - "data": 21, - "spam": "bar", - "bar": "foo", - "listdata": [20, 200], - "weight": 20, - } - assert edges_equal(G.edges(data=True), [(1, 2, dd)]) - - def test_to_undirected(self): - G = self.K3 - self.add_attributes(G) - H = nx.Graph(G) - self.is_shallow_copy(H, G) - self.different_attrdict(H, G) - H = G.to_undirected() - self.is_deepcopy(H, G) - - def test_to_directed_as_view(self): - H = nx.path_graph(2, create_using=self.Graph) - H2 = H.to_directed(as_view=True) - assert H is H2._graph - assert H2.has_edge(0, 1) - assert H2.has_edge(1, 0) or H.is_directed() - pytest.raises(nx.NetworkXError, H2.add_node, -1) - pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2) - H.add_edge(1, 2) - assert H2.has_edge(1, 2) - assert H2.has_edge(2, 1) or H.is_directed() - - def test_to_undirected_as_view(self): - H = nx.path_graph(2, create_using=self.Graph) - H2 = H.to_undirected(as_view=True) - assert H is H2._graph - assert H2.has_edge(0, 1) - assert H2.has_edge(1, 0) - pytest.raises(nx.NetworkXError, H2.add_node, -1) - pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2) - H.add_edge(1, 2) - assert H2.has_edge(1, 2) - assert H2.has_edge(2, 1) - - def test_directed_class(self): - G = self.Graph() - - class newGraph(G.to_undirected_class()): - def to_directed_class(self): - return newDiGraph - - def to_undirected_class(self): - return newGraph - - class newDiGraph(G.to_directed_class()): - def to_directed_class(self): - return newDiGraph - - def to_undirected_class(self): - return newGraph - - G = newDiGraph() if G.is_directed() else newGraph() - H = G.to_directed() - assert isinstance(H, newDiGraph) - H = G.to_undirected() - assert isinstance(H, newGraph) - - def test_to_directed(self): - G = self.K3 - self.add_attributes(G) - H = nx.DiGraph(G) - self.is_shallow_copy(H, G) - self.different_attrdict(H, G) - H = G.to_directed() - self.is_deepcopy(H, G) - - def test_subgraph(self): - G = self.K3 - self.add_attributes(G) - H = G.subgraph([0, 1, 2, 5]) - self.graphs_equal(H, G) - self.same_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - H = G.subgraph(0) - assert H.adj == {0: {}} - H = G.subgraph([]) - assert H.adj == {} - assert G.adj != {} - - def test_selfloops_attr(self): - G = self.K3.copy() - G.add_edge(0, 0) - G.add_edge(1, 1, weight=2) - assert edges_equal( - nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})] - ) - assert edges_equal( - nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)] - ) - - -class TestGraph(BaseAttrGraphTester): - """Tests specific to dict-of-dict-of-dict graph data structure""" - - def setup_method(self): - self.Graph = nx.Graph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = ({}, {}, {}) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_pickle(self): - G = self.K3 - pg = pickle.loads(pickle.dumps(G, -1)) - self.graphs_equal(pg, G) - pg = pickle.loads(pickle.dumps(G)) - self.graphs_equal(pg, G) - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})] - - def test_adjacency(self): - G = self.K3 - assert dict(G.adjacency()) == { - 0: {1: {}, 2: {}}, - 1: {0: {}, 2: {}}, - 2: {0: {}, 1: {}}, - } - - def test_getitem(self): - G = self.K3 - assert G.adj[0] == {1: {}, 2: {}} - assert G[0] == {1: {}, 2: {}} - with pytest.raises(KeyError): - G.__getitem__("j") - with pytest.raises(TypeError): - G.__getitem__(["A"]) - - def test_add_node(self): - G = self.Graph() - G.add_node(0) - assert G.adj == {0: {}} - # test add attributes - G.add_node(1, c="red") - G.add_node(2, c="blue") - G.add_node(3, c="red") - assert G.nodes[1]["c"] == "red" - assert G.nodes[2]["c"] == "blue" - assert G.nodes[3]["c"] == "red" - # test updating attributes - G.add_node(1, c="blue") - G.add_node(2, c="red") - G.add_node(3, c="blue") - assert G.nodes[1]["c"] == "blue" - assert G.nodes[2]["c"] == "red" - assert G.nodes[3]["c"] == "blue" - - def test_add_nodes_from(self): - G = self.Graph() - G.add_nodes_from([0, 1, 2]) - assert G.adj == {0: {}, 1: {}, 2: {}} - # test add attributes - G.add_nodes_from([0, 1, 2], c="red") - assert G.nodes[0]["c"] == "red" - assert G.nodes[2]["c"] == "red" - # test that attribute dicts are not the same - assert G.nodes[0] is not G.nodes[1] - # test updating attributes - G.add_nodes_from([0, 1, 2], c="blue") - assert G.nodes[0]["c"] == "blue" - assert G.nodes[2]["c"] == "blue" - assert G.nodes[0] is not G.nodes[1] - # test tuple input - H = self.Graph() - H.add_nodes_from(G.nodes(data=True)) - assert H.nodes[0]["c"] == "blue" - assert H.nodes[2]["c"] == "blue" - assert H.nodes[0] is not H.nodes[1] - # specific overrides general - H.add_nodes_from([0, (1, {"c": "green"}), (3, {"c": "cyan"})], c="red") - assert H.nodes[0]["c"] == "red" - assert H.nodes[1]["c"] == "green" - assert H.nodes[2]["c"] == "blue" - assert H.nodes[3]["c"] == "cyan" - - def test_remove_node(self): - G = self.K3.copy() - G.remove_node(0) - assert G.adj == {1: {2: {}}, 2: {1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_node(-1) - - # generator here to implement list,set,string... - - def test_remove_nodes_from(self): - G = self.K3.copy() - G.remove_nodes_from([0, 1]) - assert G.adj == {2: {}} - G.remove_nodes_from([-1]) # silent fail - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {}}, 1: {0: {}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {}}, 1: {0: {}}} - G = self.Graph() - with pytest.raises(ValueError): - G.add_edge(None, "anything") - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {"weight": 3})]) - assert G.adj == { - 0: {1: {}, 2: {"weight": 3}}, - 1: {0: {}}, - 2: {0: {"weight": 3}}, - } - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {"weight": 3}), (1, 2, {"data": 4})], data=2) - assert G.adj == { - 0: {1: {"data": 2}, 2: {"weight": 3, "data": 2}}, - 1: {0: {"data": 2}, 2: {"data": 4}}, - 2: {0: {"weight": 3, "data": 2}, 1: {"data": 4}}, - } - - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) # not a tuple - with pytest.raises(ValueError): - G.add_edges_from([(None, 3), (3, 2)]) # None cannot be a node - - def test_remove_edge(self): - G = self.K3.copy() - G.remove_edge(0, 1) - assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - def test_remove_edges_from(self): - G = self.K3.copy() - G.remove_edges_from([(0, 1)]) - assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - G.remove_edges_from([(0, 0)]) # silent fail - - def test_clear(self): - G = self.K3.copy() - G.graph["name"] = "K3" - G.clear() - assert list(G.nodes) == [] - assert G.adj == {} - assert G.graph == {} - - def test_clear_edges(self): - G = self.K3.copy() - G.graph["name"] = "K3" - nodes = list(G.nodes) - G.clear_edges() - assert list(G.nodes) == nodes - assert G.adj == {0: {}, 1: {}, 2: {}} - assert list(G.edges) == [] - assert G.graph["name"] == "K3" - - def test_edges_data(self): - G = self.K3 - all_edges = [(0, 1, {}), (0, 2, {}), (1, 2, {})] - assert edges_equal(G.edges(data=True), all_edges) - assert edges_equal(G.edges(0, data=True), [(0, 1, {}), (0, 2, {})]) - assert edges_equal(G.edges([0, 1], data=True), all_edges) - with pytest.raises(nx.NetworkXError): - G.edges(-1, True) - - def test_get_edge_data(self): - G = self.K3.copy() - assert G.get_edge_data(0, 1) == {} - assert G[0][1] == {} - assert G.get_edge_data(10, 20) is None - assert G.get_edge_data(-1, 0) is None - assert G.get_edge_data(-1, 0, default=1) == 1 - - def test_update(self): - # specify both edges and nodes - G = self.K3.copy() - G.update(nodes=[3, (4, {"size": 2})], edges=[(4, 5), (6, 7, {"weight": 2})]) - nlist = [ - (0, {}), - (1, {}), - (2, {}), - (3, {}), - (4, {"size": 2}), - (5, {}), - (6, {}), - (7, {}), - ] - assert sorted(G.nodes.data()) == nlist - if G.is_directed(): - elist = [ - (0, 1, {}), - (0, 2, {}), - (1, 0, {}), - (1, 2, {}), - (2, 0, {}), - (2, 1, {}), - (4, 5, {}), - (6, 7, {"weight": 2}), - ] - else: - elist = [ - (0, 1, {}), - (0, 2, {}), - (1, 2, {}), - (4, 5, {}), - (6, 7, {"weight": 2}), - ] - assert sorted(G.edges.data()) == elist - assert G.graph == {} - - # no keywords -- order is edges, nodes - G = self.K3.copy() - G.update([(4, 5), (6, 7, {"weight": 2})], [3, (4, {"size": 2})]) - assert sorted(G.nodes.data()) == nlist - assert sorted(G.edges.data()) == elist - assert G.graph == {} - - # update using only a graph - G = self.Graph() - G.graph["foo"] = "bar" - G.add_node(2, data=4) - G.add_edge(0, 1, weight=0.5) - GG = G.copy() - H = self.Graph() - GG.update(H) - assert graphs_equal(G, GG) - H.update(G) - assert graphs_equal(H, G) - - # update nodes only - H = self.Graph() - H.update(nodes=[3, 4]) - assert H.nodes ^ {3, 4} == set() - assert H.size() == 0 - - # update edges only - H = self.Graph() - H.update(edges=[(3, 4)]) - assert sorted(H.edges.data()) == [(3, 4, {})] - assert H.size() == 1 - - # No inputs -> exception - with pytest.raises(nx.NetworkXError): - nx.Graph().update() - - -class TestEdgeSubgraph: - """Unit tests for the :meth:`Graph.edge_subgraph` method.""" - - def setup_method(self): - # Create a path graph on five nodes. - G = nx.path_graph(5) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]["name"] = f"node{i}" - G.edges[0, 1]["name"] = "edge01" - G.edges[3, 4]["name"] = "edge34" - G.graph["name"] = "graph" - # Get the subgraph induced by the first and last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1), (3, 4)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert [(0, 1, "edge01"), (3, 4, "edge34")] == sorted(self.H.edges(data="name")) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_remove_node(self): - """Tests that removing a node in the original graph does - affect the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes()) - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]["name"] = "foo" - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]["name"] = "bar" - assert self.G.nodes[1] == self.H.nodes[1] - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v in self.H.edges(): - assert self.G.edges[u, v] == self.H.edges[u, v] - # Making a change to G should make a change in H and vice versa. - self.G.edges[0, 1]["name"] = "foo" - assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"] - self.H.edges[3, 4]["name"] = "bar" - assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"] - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph_historical.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph_historical.py deleted file mode 100644 index 36aba71..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graph_historical.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Original NetworkX graph tests""" - -import networkx -import networkx as nx - -from .historical_tests import HistoricalTests - - -class TestGraphHistorical(HistoricalTests): - @classmethod - def setup_class(cls): - HistoricalTests.setup_class() - cls.G = nx.Graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graphviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graphviews.py deleted file mode 100644 index 591c760..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_graphviews.py +++ /dev/null @@ -1,350 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - -# Note: SubGraph views are not tested here. They have their own testing file - - -class TestReverseView: - def setup_method(self): - self.G = nx.path_graph(9, create_using=nx.DiGraph()) - self.rv = nx.reverse_view(self.G) - - def test_pickle(self): - import pickle - - rv = self.rv - prv = pickle.loads(pickle.dumps(rv, -1)) - assert rv._node == prv._node - assert rv._adj == prv._adj - assert rv.graph == prv.graph - - def test_contains(self): - assert (2, 3) in self.G.edges - assert (3, 2) not in self.G.edges - assert (2, 3) not in self.rv.edges - assert (3, 2) in self.rv.edges - - def test_iter(self): - expected = sorted(tuple(reversed(e)) for e in self.G.edges) - assert sorted(self.rv.edges) == expected - - def test_exceptions(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.reverse_view, G) - - def test_subclass(self): - class MyGraph(nx.DiGraph): - def my_method(self): - return "me" - - def to_directed_class(self): - return MyGraph() - - M = MyGraph() - M.add_edge(1, 2) - RM = nx.reverse_view(M) - print("RM class", RM.__class__) - RMC = RM.copy() - print("RMC class", RMC.__class__) - print(RMC.edges) - assert RMC.has_edge(2, 1) - assert RMC.my_method() == "me" - - -class TestMultiReverseView: - def setup_method(self): - self.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - self.G.add_edge(4, 5) - self.rv = nx.reverse_view(self.G) - - def test_pickle(self): - import pickle - - rv = self.rv - prv = pickle.loads(pickle.dumps(rv, -1)) - assert rv._node == prv._node - assert rv._adj == prv._adj - assert rv.graph == prv.graph - - def test_contains(self): - assert (2, 3, 0) in self.G.edges - assert (3, 2, 0) not in self.G.edges - assert (2, 3, 0) not in self.rv.edges - assert (3, 2, 0) in self.rv.edges - assert (5, 4, 1) in self.rv.edges - assert (4, 5, 1) not in self.rv.edges - - def test_iter(self): - expected = sorted((v, u, k) for u, v, k in self.G.edges) - assert sorted(self.rv.edges) == expected - - def test_exceptions(self): - MG = nx.MultiGraph(self.G) - pytest.raises(nx.NetworkXNotImplemented, nx.reverse_view, MG) - - -def test_generic_multitype(): - nxg = nx.graphviews - G = nx.DiGraph([(1, 2)]) - with pytest.raises(nx.NetworkXError): - nxg.generic_graph_view(G, create_using=nx.MultiGraph) - G = nx.MultiDiGraph([(1, 2)]) - with pytest.raises(nx.NetworkXError): - nxg.generic_graph_view(G, create_using=nx.DiGraph) - - -class TestToDirected: - def setup_method(self): - self.G = nx.path_graph(9) - self.dv = nx.to_directed(self.G) - self.MG = nx.path_graph(9, create_using=nx.MultiGraph()) - self.Mdv = nx.to_directed(self.MG) - - def test_directed(self): - assert not self.G.is_directed() - assert self.dv.is_directed() - - def test_already_directed(self): - dd = nx.to_directed(self.dv) - Mdd = nx.to_directed(self.Mdv) - assert edges_equal(dd.edges, self.dv.edges) - assert edges_equal(Mdd.edges, self.Mdv.edges) - - def test_pickle(self): - import pickle - - dv = self.dv - pdv = pickle.loads(pickle.dumps(dv, -1)) - assert dv._node == pdv._node - assert dv._succ == pdv._succ - assert dv._pred == pdv._pred - assert dv.graph == pdv.graph - - def test_contains(self): - assert (2, 3) in self.G.edges - assert (3, 2) in self.G.edges - assert (2, 3) in self.dv.edges - assert (3, 2) in self.dv.edges - - def test_iter(self): - revd = [tuple(reversed(e)) for e in self.G.edges] - expected = sorted(list(self.G.edges) + revd) - assert sorted(self.dv.edges) == expected - - -class TestToUndirected: - def setup_method(self): - self.DG = nx.path_graph(9, create_using=nx.DiGraph()) - self.uv = nx.to_undirected(self.DG) - self.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph()) - self.Muv = nx.to_undirected(self.MDG) - - def test_directed(self): - assert self.DG.is_directed() - assert not self.uv.is_directed() - - def test_already_directed(self): - uu = nx.to_undirected(self.uv) - Muu = nx.to_undirected(self.Muv) - assert edges_equal(uu.edges, self.uv.edges) - assert edges_equal(Muu.edges, self.Muv.edges) - - def test_pickle(self): - import pickle - - uv = self.uv - puv = pickle.loads(pickle.dumps(uv, -1)) - assert uv._node == puv._node - assert uv._adj == puv._adj - assert uv.graph == puv.graph - assert hasattr(uv, "_graph") - - def test_contains(self): - assert (2, 3) in self.DG.edges - assert (3, 2) not in self.DG.edges - assert (2, 3) in self.uv.edges - assert (3, 2) in self.uv.edges - - def test_iter(self): - expected = sorted(self.DG.edges) - assert sorted(self.uv.edges) == expected - - -class TestChainsOfViews: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.DG = nx.path_graph(9, create_using=nx.DiGraph()) - cls.MG = nx.path_graph(9, create_using=nx.MultiGraph()) - cls.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.Gv = nx.to_undirected(cls.DG) - cls.DGv = nx.to_directed(cls.G) - cls.MGv = nx.to_undirected(cls.MDG) - cls.MDGv = nx.to_directed(cls.MG) - cls.Rv = cls.DG.reverse() - cls.MRv = cls.MDG.reverse() - cls.graphs = [ - cls.G, - cls.DG, - cls.MG, - cls.MDG, - cls.Gv, - cls.DGv, - cls.MGv, - cls.MDGv, - cls.Rv, - cls.MRv, - ] - for G in cls.graphs: - G.edges, G.nodes, G.degree - - def test_pickle(self): - import pickle - - for G in self.graphs: - H = pickle.loads(pickle.dumps(G, -1)) - assert edges_equal(H.edges, G.edges) - assert nodes_equal(H.nodes, G.nodes) - - def test_subgraph_of_subgraph(self): - SGv = nx.subgraph(self.G, range(3, 7)) - SDGv = nx.subgraph(self.DG, range(3, 7)) - SMGv = nx.subgraph(self.MG, range(3, 7)) - SMDGv = nx.subgraph(self.MDG, range(3, 7)) - for G in self.graphs + [SGv, SDGv, SMGv, SMDGv]: - SG = nx.induced_subgraph(G, [4, 5, 6]) - assert list(SG) == [4, 5, 6] - SSG = SG.subgraph([6, 7]) - assert list(SSG) == [6] - # subgraph-subgraph chain is short-cut in base class method - assert SSG._graph is G - - def test_restricted_induced_subgraph_chains(self): - """Test subgraph chains that both restrict and show nodes/edges. - - A restricted_view subgraph should allow induced subgraphs using - G.subgraph that automagically without a chain (meaning the result - is a subgraph view of the original graph not a subgraph-of-subgraph. - """ - hide_nodes = [3, 4, 5] - hide_edges = [(6, 7)] - RG = nx.restricted_view(self.G, hide_nodes, hide_edges) - nodes = [4, 5, 6, 7, 8] - SG = nx.induced_subgraph(RG, nodes) - SSG = RG.subgraph(nodes) - assert RG._graph is self.G - assert SSG._graph is self.G - assert SG._graph is RG - assert edges_equal(SG.edges, SSG.edges) - # should be same as morphing the graph - CG = self.G.copy() - CG.remove_nodes_from(hide_nodes) - CG.remove_edges_from(hide_edges) - assert edges_equal(CG.edges(nodes), SSG.edges) - CG.remove_nodes_from([0, 1, 2, 3]) - assert edges_equal(CG.edges, SSG.edges) - # switch order: subgraph first, then restricted view - SSSG = self.G.subgraph(nodes) - RSG = nx.restricted_view(SSSG, hide_nodes, hide_edges) - assert RSG._graph is not self.G - assert edges_equal(RSG.edges, CG.edges) - - def test_subgraph_copy(self): - for origG in self.graphs: - G = nx.Graph(origG) - SG = G.subgraph([4, 5, 6]) - H = SG.copy() - assert type(G) == type(H) - - def test_subgraph_todirected(self): - SG = nx.induced_subgraph(self.G, [4, 5, 6]) - SSG = SG.to_directed() - assert sorted(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 4), (5, 6), (6, 5)] - - def test_subgraph_toundirected(self): - SG = nx.induced_subgraph(self.G, [4, 5, 6]) - SSG = SG.to_undirected() - assert list(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 6)] - - def test_reverse_subgraph_toundirected(self): - G = self.DG.reverse(copy=False) - SG = G.subgraph([4, 5, 6]) - SSG = SG.to_undirected() - assert list(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 6)] - - def test_reverse_reverse_copy(self): - G = self.DG.reverse(copy=False) - H = G.reverse(copy=True) - assert H.nodes == self.DG.nodes - assert H.edges == self.DG.edges - G = self.MDG.reverse(copy=False) - H = G.reverse(copy=True) - assert H.nodes == self.MDG.nodes - assert H.edges == self.MDG.edges - - def test_subgraph_edgesubgraph_toundirected(self): - G = self.G.copy() - SG = G.subgraph([4, 5, 6]) - SSG = SG.edge_subgraph([(4, 5), (5, 4)]) - USSG = SSG.to_undirected() - assert list(USSG) == [4, 5] - assert sorted(USSG.edges) == [(4, 5)] - - def test_copy_subgraph(self): - G = self.G.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, "_graph") # is a view - assert not hasattr(DCSG, "_graph") # not a view - - def test_copy_disubgraph(self): - G = self.DG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, "_graph") # is a view - assert not hasattr(DCSG, "_graph") # not a view - - def test_copy_multidisubgraph(self): - G = self.MDG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, "_graph") # is a view - assert not hasattr(DCSG, "_graph") # not a view - - def test_copy_multisubgraph(self): - G = self.MG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, "_graph") # is a view - assert not hasattr(DCSG, "_graph") # not a view - - def test_copy_of_view(self): - G = nx.MultiGraph(self.MGv) - assert G.__class__.__name__ == "MultiGraph" - G = G.copy(as_view=True) - assert G.__class__.__name__ == "MultiGraph" - - def test_subclass(self): - class MyGraph(nx.DiGraph): - def my_method(self): - return "me" - - def to_directed_class(self): - return MyGraph() - - for origG in self.graphs: - G = MyGraph(origG) - SG = G.subgraph([4, 5, 6]) - H = SG.copy() - assert SG.my_method() == "me" - assert H.my_method() == "me" - assert 3 not in H or 3 in SG diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multidigraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multidigraph.py deleted file mode 100644 index fc0bd54..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multidigraph.py +++ /dev/null @@ -1,459 +0,0 @@ -from collections import UserDict - -import pytest - -import networkx as nx -from networkx.utils import edges_equal - -from .test_multigraph import BaseMultiGraphTester -from .test_multigraph import TestEdgeSubgraph as _TestMultiGraphEdgeSubgraph -from .test_multigraph import TestMultiGraph as _TestMultiGraph - - -class BaseMultiDiGraphTester(BaseMultiGraphTester): - def test_edges(self): - G = self.K3 - edges = [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.edges()) == edges - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - pytest.raises((KeyError, nx.NetworkXError), G.edges, -1) - - def test_edges_data(self): - G = self.K3 - edges = [(0, 1, {}), (0, 2, {}), (1, 0, {}), (1, 2, {}), (2, 0, {}), (2, 1, {})] - assert sorted(G.edges(data=True)) == edges - assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})] - pytest.raises((KeyError, nx.NetworkXError), G.neighbors, -1) - - def test_edges_multi(self): - G = self.K3 - assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - G.add_edge(0, 1) - assert sorted(G.edges()) == [ - (0, 1), - (0, 1), - (0, 2), - (1, 0), - (1, 2), - (2, 0), - (2, 1), - ] - - def test_out_edges(self): - G = self.K3 - assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - pytest.raises((KeyError, nx.NetworkXError), G.out_edges, -1) - assert sorted(G.out_edges(0, keys=True)) == [(0, 1, 0), (0, 2, 0)] - - def test_out_edges_multi(self): - G = self.K3 - assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - G.add_edge(0, 1, 2) - assert sorted(G.out_edges()) == [ - (0, 1), - (0, 1), - (0, 2), - (1, 0), - (1, 2), - (2, 0), - (2, 1), - ] - - def test_out_edges_data(self): - G = self.K3 - assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})] - G.remove_edge(0, 1) - G.add_edge(0, 1, data=1) - assert sorted(G.edges(0, data=True)) == [(0, 1, {"data": 1}), (0, 2, {})] - assert sorted(G.edges(0, data="data")) == [(0, 1, 1), (0, 2, None)] - assert sorted(G.edges(0, data="data", default=-1)) == [(0, 1, 1), (0, 2, -1)] - - def test_in_edges(self): - G = self.K3 - assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)] - pytest.raises((KeyError, nx.NetworkXError), G.in_edges, -1) - G.add_edge(0, 1, 2) - assert sorted(G.in_edges()) == [ - (0, 1), - (0, 1), - (0, 2), - (1, 0), - (1, 2), - (2, 0), - (2, 1), - ] - assert sorted(G.in_edges(0, keys=True)) == [(1, 0, 0), (2, 0, 0)] - - def test_in_edges_no_keys(self): - G = self.K3 - assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)] - G.add_edge(0, 1, 2) - assert sorted(G.in_edges()) == [ - (0, 1), - (0, 1), - (0, 2), - (1, 0), - (1, 2), - (2, 0), - (2, 1), - ] - - assert sorted(G.in_edges(data=True, keys=False)) == [ - (0, 1, {}), - (0, 1, {}), - (0, 2, {}), - (1, 0, {}), - (1, 2, {}), - (2, 0, {}), - (2, 1, {}), - ] - - def test_in_edges_data(self): - G = self.K3 - assert sorted(G.in_edges(0, data=True)) == [(1, 0, {}), (2, 0, {})] - G.remove_edge(1, 0) - G.add_edge(1, 0, data=1) - assert sorted(G.in_edges(0, data=True)) == [(1, 0, {"data": 1}), (2, 0, {})] - assert sorted(G.in_edges(0, data="data")) == [(1, 0, 1), (2, 0, None)] - assert sorted(G.in_edges(0, data="data", default=-1)) == [(1, 0, 1), (2, 0, -1)] - - def is_shallow(self, H, G): - # graph - assert G.graph["foo"] == H.graph["foo"] - G.graph["foo"].append(1) - assert G.graph["foo"] == H.graph["foo"] - # node - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - G.nodes[0]["foo"].append(1) - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - # edge - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - G[1][2][0]["foo"].append(1) - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - - def is_deep(self, H, G): - # graph - assert G.graph["foo"] == H.graph["foo"] - G.graph["foo"].append(1) - assert G.graph["foo"] != H.graph["foo"] - # node - assert G.nodes[0]["foo"] == H.nodes[0]["foo"] - G.nodes[0]["foo"].append(1) - assert G.nodes[0]["foo"] != H.nodes[0]["foo"] - # edge - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - G[1][2][0]["foo"].append(1) - assert G[1][2][0]["foo"] != H[1][2][0]["foo"] - - def test_to_undirected(self): - # MultiDiGraph -> MultiGraph changes number of edges so it is - # not a copy operation... use is_shallow, not is_shallow_copy - G = self.K3 - self.add_attributes(G) - H = nx.MultiGraph(G) - # self.is_shallow(H,G) - # the result is traversal order dependent so we - # can't use the is_shallow() test here. - try: - assert edges_equal(H.edges(), [(0, 1), (1, 2), (2, 0)]) - except AssertionError: - assert edges_equal(H.edges(), [(0, 1), (1, 2), (1, 2), (2, 0)]) - H = G.to_undirected() - self.is_deep(H, G) - - def test_has_successor(self): - G = self.K3 - assert G.has_successor(0, 1) - assert not G.has_successor(0, -1) - - def test_successors(self): - G = self.K3 - assert sorted(G.successors(0)) == [1, 2] - pytest.raises((KeyError, nx.NetworkXError), G.successors, -1) - - def test_has_predecessor(self): - G = self.K3 - assert G.has_predecessor(0, 1) - assert not G.has_predecessor(0, -1) - - def test_predecessors(self): - G = self.K3 - assert sorted(G.predecessors(0)) == [1, 2] - pytest.raises((KeyError, nx.NetworkXError), G.predecessors, -1) - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)] - assert dict(G.degree()) == {0: 4, 1: 4, 2: 4} - assert G.degree(0) == 4 - assert list(G.degree(iter([0]))) == [(0, 4)] - G.add_edge(0, 1, weight=0.3, other=1.2) - assert sorted(G.degree(weight="weight")) == [(0, 4.3), (1, 4.3), (2, 4)] - assert sorted(G.degree(weight="other")) == [(0, 5.2), (1, 5.2), (2, 4)] - - def test_in_degree(self): - G = self.K3 - assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2} - assert G.in_degree(0) == 2 - assert list(G.in_degree(iter([0]))) == [(0, 2)] - assert G.in_degree(0, weight="weight") == 2 - - def test_out_degree(self): - G = self.K3 - assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2} - assert G.out_degree(0) == 2 - assert list(G.out_degree(iter([0]))) == [(0, 2)] - assert G.out_degree(0, weight="weight") == 2 - - def test_size(self): - G = self.K3 - assert G.size() == 6 - assert G.number_of_edges() == 6 - G.add_edge(0, 1, weight=0.3, other=1.2) - assert round(G.size(weight="weight"), 2) == 6.3 - assert round(G.size(weight="other"), 2) == 7.2 - - def test_to_undirected_reciprocal(self): - G = self.Graph() - G.add_edge(1, 2) - assert G.to_undirected().has_edge(1, 2) - assert not G.to_undirected(reciprocal=True).has_edge(1, 2) - G.add_edge(2, 1) - assert G.to_undirected(reciprocal=True).has_edge(1, 2) - - def test_reverse_copy(self): - G = nx.MultiDiGraph([(0, 1), (0, 1)]) - R = G.reverse() - assert sorted(R.edges()) == [(1, 0), (1, 0)] - R.remove_edge(1, 0) - assert sorted(R.edges()) == [(1, 0)] - assert sorted(G.edges()) == [(0, 1), (0, 1)] - - def test_reverse_nocopy(self): - G = nx.MultiDiGraph([(0, 1), (0, 1)]) - R = G.reverse(copy=False) - assert sorted(R.edges()) == [(1, 0), (1, 0)] - pytest.raises(nx.NetworkXError, R.remove_edge, 1, 0) - - def test_di_attributes_cached(self): - G = self.K3.copy() - assert id(G.in_edges) == id(G.in_edges) - assert id(G.out_edges) == id(G.out_edges) - assert id(G.in_degree) == id(G.in_degree) - assert id(G.out_degree) == id(G.out_degree) - assert id(G.succ) == id(G.succ) - assert id(G.pred) == id(G.pred) - - -class TestMultiDiGraph(BaseMultiDiGraphTester, _TestMultiGraph): - def setup_method(self): - self.Graph = nx.MultiDiGraph - # build K3 - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._succ = {0: {}, 1: {}, 2: {}} - # K3._adj is synced with K3._succ - self.K3._pred = {0: {}, 1: {}, 2: {}} - for u in self.k3nodes: - for v in self.k3nodes: - if u == v: - continue - d = {0: {}} - self.K3._succ[u][v] = d - self.K3._pred[v][u] = d - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G._adj == {0: {1: {0: {}}}, 1: {}} - assert G._succ == {0: {1: {0: {}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G._adj == {0: {1: {0: {}}}, 1: {}} - assert G._succ == {0: {1: {0: {}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}}}} - with pytest.raises(ValueError, match="None cannot be a node"): - G.add_edge(None, 3) - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 1, {"weight": 3})]) - assert G._adj == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}} - assert G._succ == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}, 1: {"weight": 3}}}} - - G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2) - assert G._succ == { - 0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}}, - 1: {}, - } - assert G._pred == { - 0: {}, - 1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}}, - } - - G = self.Graph() - edges = [ - (0, 1, {"weight": 3}), - (0, 1, (("weight", 2),)), - (0, 1, 5), - (0, 1, "s"), - ] - G.add_edges_from(edges) - keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}} - assert G._succ == {0: {1: keydict}, 1: {}} - assert G._pred == {1: {0: keydict}, 0: {}} - - # too few in tuple - pytest.raises(nx.NetworkXError, G.add_edges_from, [(0,)]) - # too many in tuple - pytest.raises(nx.NetworkXError, G.add_edges_from, [(0, 1, 2, 3, 4)]) - # not a tuple - pytest.raises(TypeError, G.add_edges_from, [0]) - with pytest.raises(ValueError, match="None cannot be a node"): - G.add_edges_from([(None, 3), (3, 2)]) - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G._succ == { - 0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - assert G._pred == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0) - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, 0, 2, key=1) - - def test_remove_multiedge(self): - G = self.K3 - G.add_edge(0, 1, key="parallel edge") - G.remove_edge(0, 1, key="parallel edge") - assert G._adj == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - - assert G._succ == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - - assert G._pred == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - G.remove_edge(0, 1) - assert G._succ == { - 0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - assert G._pred == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0) - - def test_remove_edges_from(self): - G = self.K3 - G.remove_edges_from([(0, 1)]) - assert G._succ == { - 0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - assert G._pred == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - G.remove_edges_from([(0, 0)]) # silent fail - - -class TestEdgeSubgraph(_TestMultiGraphEdgeSubgraph): - """Unit tests for the :meth:`MultiDiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a quadruply-linked path graph on five nodes. - G = nx.MultiDiGraph() - nx.add_path(G, range(5)) - nx.add_path(G, range(5)) - nx.add_path(G, reversed(range(5))) - nx.add_path(G, reversed(range(5))) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]["name"] = f"node{i}" - G.adj[0][1][0]["name"] = "edge010" - G.adj[0][1][1]["name"] = "edge011" - G.adj[3][4][0]["name"] = "edge340" - G.adj[3][4][1]["name"] = "edge341" - G.graph["name"] = "graph" - # Get the subgraph induced by one of the first edges and one of - # the last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)]) - - -class CustomDictClass(UserDict): - pass - - -class MultiDiGraphSubClass(nx.MultiDiGraph): - node_dict_factory = CustomDictClass # type: ignore[assignment] - node_attr_dict_factory = CustomDictClass # type: ignore[assignment] - adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment] - adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment] - edge_key_dict_factory = CustomDictClass # type: ignore[assignment] - edge_attr_dict_factory = CustomDictClass # type: ignore[assignment] - graph_attr_dict_factory = CustomDictClass # type: ignore[assignment] - - -class TestMultiDiGraphSubclass(TestMultiDiGraph): - def setup_method(self): - self.Graph = MultiDiGraphSubClass - # build K3 - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._succ = self.K3.adjlist_outer_dict_factory( - { - 0: self.K3.adjlist_inner_dict_factory(), - 1: self.K3.adjlist_inner_dict_factory(), - 2: self.K3.adjlist_inner_dict_factory(), - } - ) - # K3._adj is synced with K3._succ - self.K3._pred = {0: {}, 1: {}, 2: {}} - for u in self.k3nodes: - for v in self.k3nodes: - if u == v: - continue - d = {0: {}} - self.K3._succ[u][v] = d - self.K3._pred[v][u] = d - self.K3._node = self.K3.node_dict_factory() - self.K3._node[0] = self.K3.node_attr_dict_factory() - self.K3._node[1] = self.K3.node_attr_dict_factory() - self.K3._node[2] = self.K3.node_attr_dict_factory() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multigraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multigraph.py deleted file mode 100644 index cd912d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_multigraph.py +++ /dev/null @@ -1,528 +0,0 @@ -from collections import UserDict - -import pytest - -import networkx as nx -from networkx.utils import edges_equal - -from .test_graph import BaseAttrGraphTester -from .test_graph import TestGraph as _TestGraph - - -class BaseMultiGraphTester(BaseAttrGraphTester): - def test_has_edge(self): - G = self.K3 - assert G.has_edge(0, 1) - assert not G.has_edge(0, -1) - assert G.has_edge(0, 1, 0) - assert not G.has_edge(0, 1, 1) - - def test_get_edge_data(self): - G = self.K3 - assert G.get_edge_data(0, 1) == {0: {}} - assert G[0][1] == {0: {}} - assert G[0][1][0] == {} - assert G.get_edge_data(10, 20) is None - assert G.get_edge_data(0, 1, 0) == {} - - def test_adjacency(self): - G = self.K3 - assert dict(G.adjacency()) == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - - def deepcopy_edge_attr(self, H, G): - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - G[1][2][0]["foo"].append(1) - assert G[1][2][0]["foo"] != H[1][2][0]["foo"] - - def shallow_copy_edge_attr(self, H, G): - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - G[1][2][0]["foo"].append(1) - assert G[1][2][0]["foo"] == H[1][2][0]["foo"] - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2][0] is H._adj[2][1][0] - assert G._adj[1][2][0] is G._adj[2][1][0] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2][0] is H._pred[2][1][0] - assert G._succ[1][2][0] is G._pred[2][1][0] - - def same_attrdict(self, H, G): - # same attrdict in the edgedata - old_foo = H[1][2][0]["foo"] - H.adj[1][2][0]["foo"] = "baz" - assert G._adj == H._adj - H.adj[1][2][0]["foo"] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]["foo"] - H.nodes[0]["foo"] = "baz" - assert G._node == H._node - H.nodes[0]["foo"] = old_foo - assert G._node == H._node - - def different_attrdict(self, H, G): - # used by graph_equal_but_different - old_foo = H[1][2][0]["foo"] - H.adj[1][2][0]["foo"] = "baz" - assert G._adj != H._adj - H.adj[1][2][0]["foo"] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]["foo"] - H.nodes[0]["foo"] = "baz" - assert G._node != H._node - H.nodes[0]["foo"] = old_foo - assert G._node == H._node - - def test_to_undirected(self): - G = self.K3 - self.add_attributes(G) - H = nx.MultiGraph(G) - self.is_shallow_copy(H, G) - H = G.to_undirected() - self.is_deepcopy(H, G) - - def test_to_directed(self): - G = self.K3 - self.add_attributes(G) - H = nx.MultiDiGraph(G) - self.is_shallow_copy(H, G) - H = G.to_directed() - self.is_deepcopy(H, G) - - def test_number_of_edges_selfloops(self): - G = self.K3 - G.add_edge(0, 0) - G.add_edge(0, 0) - G.add_edge(0, 0, key="parallel edge") - G.remove_edge(0, 0, key="parallel edge") - assert G.number_of_edges(0, 0) == 2 - G.remove_edge(0, 0) - assert G.number_of_edges(0, 0) == 1 - - def test_edge_lookup(self): - G = self.Graph() - G.add_edge(1, 2, foo="bar") - G.add_edge(1, 2, "key", foo="biz") - assert edges_equal(G.edges[1, 2, 0], {"foo": "bar"}) - assert edges_equal(G.edges[1, 2, "key"], {"foo": "biz"}) - - def test_edge_attr(self): - G = self.Graph() - G.add_edge(1, 2, key="k1", foo="bar") - G.add_edge(1, 2, key="k2", foo="baz") - assert isinstance(G.get_edge_data(1, 2), G.edge_key_dict_factory) - assert all( - isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True) - ) - assert edges_equal( - G.edges(keys=True, data=True), - [(1, 2, "k1", {"foo": "bar"}), (1, 2, "k2", {"foo": "baz"})], - ) - assert edges_equal( - G.edges(keys=True, data="foo"), [(1, 2, "k1", "bar"), (1, 2, "k2", "baz")] - ) - - def test_edge_attr4(self): - G = self.Graph() - G.add_edge(1, 2, key=0, data=7, spam="bar", bar="foo") - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})] - ) - G[1][2][0]["data"] = 10 # OK to set data like this - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})] - ) - - G.adj[1][2][0]["data"] = 20 - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})] - ) - G.edges[1, 2, 0]["data"] = 21 # another spelling, "edge" - assert edges_equal( - G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})] - ) - G.adj[1][2][0]["listdata"] = [20, 200] - G.adj[1][2][0]["weight"] = 20 - assert edges_equal( - G.edges(data=True), - [ - ( - 1, - 2, - { - "data": 21, - "spam": "bar", - "bar": "foo", - "listdata": [20, 200], - "weight": 20, - }, - ) - ], - ) - - -class TestMultiGraph(BaseMultiGraphTester, _TestGraph): - def setup_method(self): - self.Graph = nx.MultiGraph - # build K3 - ed1, ed2, ed3 = ({0: {}}, {0: {}}, {0: {}}) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - expected = [(1, {2: {0: {}}}), (2, {1: {0: {}}})] - assert sorted(G.adj.items()) == expected - - def test_data_multigraph_input(self): - # standard case with edge keys and edge data - edata0 = {"w": 200, "s": "foo"} - edata1 = {"w": 201, "s": "bar"} - keydict = {0: edata0, 1: edata1} - dododod = {"a": {"b": keydict}} - - multiple_edge = [("a", "b", 0, edata0), ("a", "b", 1, edata1)] - single_edge = [("a", "b", 0, keydict)] - - G = self.Graph(dododod, multigraph_input=True) - assert list(G.edges(keys=True, data=True)) == multiple_edge - G = self.Graph(dododod, multigraph_input=None) - assert list(G.edges(keys=True, data=True)) == multiple_edge - G = self.Graph(dododod, multigraph_input=False) - assert list(G.edges(keys=True, data=True)) == single_edge - - # test round-trip to_dict_of_dict and MultiGraph constructor - G = self.Graph(dododod, multigraph_input=True) - H = self.Graph(nx.to_dict_of_dicts(G)) - assert nx.is_isomorphic(G, H) is True # test that default is True - for mgi in [True, False]: - H = self.Graph(nx.to_dict_of_dicts(G), multigraph_input=mgi) - assert nx.is_isomorphic(G, H) == mgi - - # Set up cases for when incoming_graph_data is not multigraph_input - etraits = {"w": 200, "s": "foo"} - egraphics = {"color": "blue", "shape": "box"} - edata = {"traits": etraits, "graphics": egraphics} - dodod1 = {"a": {"b": edata}} - dodod2 = {"a": {"b": etraits}} - dodod3 = {"a": {"b": {"traits": etraits, "s": "foo"}}} - dol = {"a": ["b"]} - - multiple_edge = [("a", "b", "traits", etraits), ("a", "b", "graphics", egraphics)] - single_edge = [("a", "b", 0, {})] # type: ignore[var-annotated] - single_edge1 = [("a", "b", 0, edata)] - single_edge2 = [("a", "b", 0, etraits)] - single_edge3 = [("a", "b", 0, {"traits": etraits, "s": "foo"})] - - cases = [ # (dod, mgi, edges) - (dodod1, True, multiple_edge), - (dodod1, False, single_edge1), - (dodod2, False, single_edge2), - (dodod3, False, single_edge3), - (dol, False, single_edge), - ] - - @pytest.mark.parametrize("dod, mgi, edges", cases) - def test_non_multigraph_input(self, dod, mgi, edges): - G = self.Graph(dod, multigraph_input=mgi) - assert list(G.edges(keys=True, data=True)) == edges - G = nx.to_networkx_graph(dod, create_using=self.Graph, multigraph_input=mgi) - assert list(G.edges(keys=True, data=True)) == edges - - mgi_none_cases = [ - (dodod1, multiple_edge), - (dodod2, single_edge2), - (dodod3, single_edge3), - ] - - @pytest.mark.parametrize("dod, edges", mgi_none_cases) - def test_non_multigraph_input_mgi_none(self, dod, edges): - # test constructor without to_networkx_graph for mgi=None - G = self.Graph(dod) - assert list(G.edges(keys=True, data=True)) == edges - - raise_cases = [dodod2, dodod3, dol] - - @pytest.mark.parametrize("dod", raise_cases) - def test_non_multigraph_input_raise(self, dod): - # cases where NetworkXError is raised - pytest.raises(nx.NetworkXError, self.Graph, dod, multigraph_input=True) - pytest.raises( - nx.NetworkXError, - nx.to_networkx_graph, - dod, - create_using=self.Graph, - multigraph_input=True, - ) - - def test_getitem(self): - G = self.K3 - assert G[0] == {1: {0: {}}, 2: {0: {}}} - with pytest.raises(KeyError): - G.__getitem__("j") - with pytest.raises(TypeError): - G.__getitem__(["A"]) - - def test_remove_node(self): - G = self.K3 - G.remove_node(0) - assert G.adj == {1: {2: {0: {}}}, 2: {1: {0: {}}}} - with pytest.raises(nx.NetworkXError): - G.remove_node(-1) - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}} - G = self.Graph() - with pytest.raises(ValueError): - G.add_edge(None, "anything") - - def test_add_edge_conflicting_key(self): - G = self.Graph() - G.add_edge(0, 1, key=1) - G.add_edge(0, 1) - assert G.number_of_edges() == 2 - G = self.Graph() - G.add_edges_from([(0, 1, 1, {})]) - G.add_edges_from([(0, 1)]) - assert G.number_of_edges() == 2 - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 1, {"weight": 3})]) - assert G.adj == { - 0: {1: {0: {}, 1: {"weight": 3}}}, - 1: {0: {0: {}, 1: {"weight": 3}}}, - } - G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2) - assert G.adj == { - 0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}}, - 1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}}, - } - G = self.Graph() - edges = [ - (0, 1, {"weight": 3}), - (0, 1, (("weight", 2),)), - (0, 1, 5), - (0, 1, "s"), - ] - G.add_edges_from(edges) - keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}} - assert G._adj == {0: {1: keydict}, 1: {0: keydict}} - - # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) - # too many in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3, 4)]) - # not a tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) - - def test_multigraph_add_edges_from_four_tuple_misordered(self): - """add_edges_from expects 4-tuples of the format (u, v, key, data_dict). - - Ensure 4-tuples of form (u, v, data_dict, key) raise exception. - """ - G = nx.MultiGraph() - with pytest.raises(TypeError): - # key/data values flipped in 4-tuple - G.add_edges_from([(0, 1, {"color": "red"}, 0)]) - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G.adj == {0: {2: {0: {}}}, 1: {2: {0: {}}}, 2: {0: {0: {}}, 1: {0: {}}}} - - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - with pytest.raises(nx.NetworkXError): - G.remove_edge(0, 2, key=1) - - def test_remove_edges_from(self): - G = self.K3.copy() - G.remove_edges_from([(0, 1)]) - kd = {0: {}} - assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}} - G.remove_edges_from([(0, 0)]) # silent fail - self.K3.add_edge(0, 1) - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=True, keys=True))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=False, keys=True))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=False, keys=False))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from([(0, 1, 0), (0, 2, 0, {}), (1, 2)]) - assert G.adj == {0: {1: {1: {}}}, 1: {0: {1: {}}}, 2: {}} - - def test_remove_multiedge(self): - G = self.K3 - G.add_edge(0, 1, key="parallel edge") - G.remove_edge(0, 1, key="parallel edge") - assert G.adj == { - 0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}, - } - G.remove_edge(0, 1) - kd = {0: {}} - assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - -class TestEdgeSubgraph: - """Unit tests for the :meth:`MultiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a doubly-linked path graph on five nodes. - G = nx.MultiGraph() - nx.add_path(G, range(5)) - nx.add_path(G, range(5)) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]["name"] = f"node{i}" - G.adj[0][1][0]["name"] = "edge010" - G.adj[0][1][1]["name"] = "edge011" - G.adj[3][4][0]["name"] = "edge340" - G.adj[3][4][1]["name"] = "edge341" - G.graph["name"] = "graph" - # Get the subgraph induced by one of the first edges and one of - # the last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert [(0, 1, 0, "edge010"), (3, 4, 1, "edge341")] == sorted( - self.H.edges(keys=True, data="name") - ) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_remove_node(self): - """Tests that removing a node in the original graph does - affect the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes()) - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]["name"] = "foo" - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]["name"] = "bar" - assert self.G.nodes[1] == self.H.nodes[1] - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v, k in self.H.edges(keys=True): - assert self.G._adj[u][v][k] == self.H._adj[u][v][k] - # Making a change to G should make a change in H and vice versa. - self.G._adj[0][1][0]["name"] = "foo" - assert self.G._adj[0][1][0]["name"] == self.H._adj[0][1][0]["name"] - self.H._adj[3][4][1]["name"] = "bar" - assert self.G._adj[3][4][1]["name"] == self.H._adj[3][4][1]["name"] - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph - - -class CustomDictClass(UserDict): - pass - - -class MultiGraphSubClass(nx.MultiGraph): - node_dict_factory = CustomDictClass # type: ignore[assignment] - node_attr_dict_factory = CustomDictClass # type: ignore[assignment] - adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment] - adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment] - edge_key_dict_factory = CustomDictClass # type: ignore[assignment] - edge_attr_dict_factory = CustomDictClass # type: ignore[assignment] - graph_attr_dict_factory = CustomDictClass # type: ignore[assignment] - - -class TestMultiGraphSubclass(TestMultiGraph): - def setup_method(self): - self.Graph = MultiGraphSubClass - # build K3 - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.K3.adjlist_outer_dict_factory( - { - 0: self.K3.adjlist_inner_dict_factory(), - 1: self.K3.adjlist_inner_dict_factory(), - 2: self.K3.adjlist_inner_dict_factory(), - } - ) - self.K3._pred = {0: {}, 1: {}, 2: {}} - for u in self.k3nodes: - for v in self.k3nodes: - if u != v: - d = {0: {}} - self.K3._adj[u][v] = d - self.K3._adj[v][u] = d - self.K3._node = self.K3.node_dict_factory() - self.K3._node[0] = self.K3.node_attr_dict_factory() - self.K3._node[1] = self.K3.node_attr_dict_factory() - self.K3._node[2] = self.K3.node_attr_dict_factory() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_reportviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_reportviews.py deleted file mode 100644 index 789c829..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_reportviews.py +++ /dev/null @@ -1,1435 +0,0 @@ -import pickle -from copy import deepcopy - -import pytest - -import networkx as nx -from networkx.classes import reportviews as rv -from networkx.classes.reportviews import NodeDataView - - -# Nodes -class TestNodeView: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.nv = cls.G.nodes # NodeView(G) - - def test_pickle(self): - import pickle - - nv = self.nv - pnv = pickle.loads(pickle.dumps(nv, -1)) - assert nv == pnv - assert nv.__slots__ == pnv.__slots__ - - def test_str(self): - assert str(self.nv) == "[0, 1, 2, 3, 4, 5, 6, 7, 8]" - - def test_repr(self): - assert repr(self.nv) == "NodeView((0, 1, 2, 3, 4, 5, 6, 7, 8))" - - def test_contains(self): - G = self.G.copy() - nv = G.nodes - assert 7 in nv - assert 9 not in nv - G.remove_node(7) - G.add_node(9) - assert 7 not in nv - assert 9 in nv - - def test_getitem(self): - G = self.G.copy() - nv = G.nodes - G.nodes[3]["foo"] = "bar" - assert nv[7] == {} - assert nv[3] == {"foo": "bar"} - # slicing - with pytest.raises(nx.NetworkXError): - G.nodes[0:5] - - def test_iter(self): - nv = self.nv - for i, n in enumerate(nv): - assert i == n - inv = iter(nv) - assert next(inv) == 0 - assert iter(nv) != nv - assert iter(inv) == inv - inv2 = iter(nv) - next(inv2) - assert list(inv) == list(inv2) - # odd case where NodeView calls NodeDataView with data=False - nnv = nv(data=False) - for i, n in enumerate(nnv): - assert i == n - - def test_call(self): - nodes = self.nv - assert nodes is nodes() - assert nodes is not nodes(data=True) - assert nodes is not nodes(data="weight") - - -class TestNodeDataView: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.nv = NodeDataView(cls.G) - cls.ndv = cls.G.nodes.data(True) - cls.nwv = cls.G.nodes.data("foo") - - def test_viewtype(self): - nv = self.G.nodes - ndvfalse = nv.data(False) - assert nv is ndvfalse - assert nv is not self.ndv - - def test_pickle(self): - import pickle - - nv = self.nv - pnv = pickle.loads(pickle.dumps(nv, -1)) - assert nv == pnv - assert nv.__slots__ == pnv.__slots__ - - def test_str(self): - msg = str([(n, {}) for n in range(9)]) - assert str(self.ndv) == msg - - def test_repr(self): - expected = "NodeDataView((0, 1, 2, 3, 4, 5, 6, 7, 8))" - assert repr(self.nv) == expected - expected = ( - "NodeDataView({0: {}, 1: {}, 2: {}, 3: {}, " - + "4: {}, 5: {}, 6: {}, 7: {}, 8: {}})" - ) - assert repr(self.ndv) == expected - expected = ( - "NodeDataView({0: None, 1: None, 2: None, 3: None, 4: None, " - + "5: None, 6: None, 7: None, 8: None}, data='foo')" - ) - assert repr(self.nwv) == expected - - def test_contains(self): - G = self.G.copy() - nv = G.nodes.data() - nwv = G.nodes.data("foo") - G.nodes[3]["foo"] = "bar" - assert (7, {}) in nv - assert (3, {"foo": "bar"}) in nv - assert (3, "bar") in nwv - assert (7, None) in nwv - # default - nwv_def = G.nodes(data="foo", default="biz") - assert (7, "biz") in nwv_def - assert (3, "bar") in nwv_def - - def test_getitem(self): - G = self.G.copy() - nv = G.nodes - G.nodes[3]["foo"] = "bar" - assert nv[3] == {"foo": "bar"} - # default - nwv_def = G.nodes(data="foo", default="biz") - assert nwv_def[7], "biz" - assert nwv_def[3] == "bar" - # slicing - with pytest.raises(nx.NetworkXError): - G.nodes.data()[0:5] - - def test_iter(self): - G = self.G.copy() - nv = G.nodes.data() - ndv = G.nodes.data(True) - nwv = G.nodes.data("foo") - for i, (n, d) in enumerate(nv): - assert i == n - assert d == {} - inv = iter(nv) - assert next(inv) == (0, {}) - G.nodes[3]["foo"] = "bar" - # default - for n, d in nv: - if n == 3: - assert d == {"foo": "bar"} - else: - assert d == {} - # data=True - for n, d in ndv: - if n == 3: - assert d == {"foo": "bar"} - else: - assert d == {} - # data='foo' - for n, d in nwv: - if n == 3: - assert d == "bar" - else: - assert d is None - # data='foo', default=1 - for n, d in G.nodes.data("foo", default=1): - if n == 3: - assert d == "bar" - else: - assert d == 1 - - -def test_nodedataview_unhashable(): - G = nx.path_graph(9) - G.nodes[3]["foo"] = "bar" - nvs = [G.nodes.data()] - nvs.append(G.nodes.data(True)) - H = G.copy() - H.nodes[4]["foo"] = {1, 2, 3} - nvs.append(H.nodes.data(True)) - # raise unhashable - for nv in nvs: - pytest.raises(TypeError, set, nv) - pytest.raises(TypeError, eval, "nv | nv", locals()) - # no raise... hashable - Gn = G.nodes.data(False) - set(Gn) - Gn | Gn - Gn = G.nodes.data("foo") - set(Gn) - Gn | Gn - - -class TestNodeViewSetOps: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]["foo"] = "bar" - cls.nv = cls.G.nodes - - def n_its(self, nodes): - return set(nodes) - - def test_len(self): - G = self.G.copy() - nv = G.nodes - assert len(nv) == 9 - G.remove_node(7) - assert len(nv) == 8 - G.add_node(9) - assert len(nv) == 9 - - def test_and(self): - # print("G & H nodes:", gnv & hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv & some_nodes == self.n_its(range(5, 9)) - assert some_nodes & nv == self.n_its(range(5, 9)) - - def test_or(self): - # print("G | H nodes:", gnv | hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv | some_nodes == self.n_its(range(12)) - assert some_nodes | nv == self.n_its(range(12)) - - def test_xor(self): - # print("G ^ H nodes:", gnv ^ hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - nodes = {0, 1, 2, 3, 4, 9, 10, 11} - assert nv ^ some_nodes == self.n_its(nodes) - assert some_nodes ^ nv == self.n_its(nodes) - - def test_sub(self): - # print("G - H nodes:", gnv - hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv - some_nodes == self.n_its(range(5)) - assert some_nodes - nv == self.n_its(range(9, 12)) - - -class TestNodeDataViewSetOps(TestNodeViewSetOps): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]["foo"] = "bar" - cls.nv = cls.G.nodes.data("foo") - - def n_its(self, nodes): - return {(node, "bar" if node == 3 else None) for node in nodes} - - -class TestNodeDataViewDefaultSetOps(TestNodeDataViewSetOps): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]["foo"] = "bar" - cls.nv = cls.G.nodes.data("foo", default=1) - - def n_its(self, nodes): - return {(node, "bar" if node == 3 else 1) for node in nodes} - - -# Edges Data View -class TestEdgeDataView: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.eview = nx.reportviews.EdgeView - - def test_pickle(self): - import pickle - - ev = self.eview(self.G)(data=True) - pev = pickle.loads(pickle.dumps(ev, -1)) - assert list(ev) == list(pev) - assert ev.__slots__ == pev.__slots__ - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]].update(kwds) - - def test_str(self): - ev = self.eview(self.G)(data=True) - rep = str([(n, n + 1, {}) for n in range(8)]) - assert str(ev) == rep - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "EdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_iterdata(self): - G = self.G.copy() - evr = self.eview(G) - ev = evr(data=True) - ev_def = evr(data="foo", default=1) - - for u, v, d in ev: - pass - assert d == {} - - for u, v, wt in ev_def: - pass - assert wt == 1 - - self.modify_edge(G, (2, 3), foo="bar") - for e in ev: - assert len(e) == 3 - if set(e[:2]) == {2, 3}: - assert e[2] == {"foo": "bar"} - checked = True - else: - assert e[2] == {} - assert checked - - for e in ev_def: - assert len(e) == 3 - if set(e[:2]) == {2, 3}: - assert e[2] == "bar" - checked_wt = True - else: - assert e[2] == 1 - assert checked_wt - - def test_iter(self): - evr = self.eview(self.G) - ev = evr() - for u, v in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_contains(self): - evr = self.eview(self.G) - ev = evr() - if self.G.is_directed(): - assert (1, 2) in ev and (2, 1) not in ev - else: - assert (1, 2) in ev and (2, 1) in ev - assert (1, 4) not in ev - assert (1, 90) not in ev - assert (90, 1) not in ev - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - if self.G.is_directed(): - assert (0, 1) in ev - assert (1, 2) not in ev - assert (2, 3) in ev - else: - assert (0, 1) in ev - assert (1, 2) in ev - assert (2, 3) in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - def test_len(self): - evr = self.eview(self.G) - ev = evr(data="foo") - assert len(ev) == 8 - assert len(evr(1)) == 2 - assert len(evr([1, 2, 3])) == 4 - - assert len(self.G.edges(1)) == 2 - assert len(self.G.edges()) == 8 - assert len(self.G.edges) == 8 - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 3 - assert len(H.edges()) == 9 - assert len(H.edges) == 9 - - -class TestOutEdgeDataView(TestEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.DiGraph()) - cls.eview = nx.reportviews.OutEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "OutEdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_len(self): - evr = self.eview(self.G) - ev = evr(data="foo") - assert len(ev) == 8 - assert len(evr(1)) == 1 - assert len(evr([1, 2, 3])) == 3 - - assert len(self.G.edges(1)) == 1 - assert len(self.G.edges()) == 8 - assert len(self.G.edges) == 8 - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 2 - assert len(H.edges()) == 9 - assert len(H.edges) == 9 - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - assert (0, 1) in ev - assert (1, 2) not in ev - assert (2, 3) in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - -class TestInEdgeDataView(TestOutEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.DiGraph()) - cls.eview = nx.reportviews.InEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "InEdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - assert (0, 1) not in ev - assert (1, 2) in ev - assert (2, 3) not in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - -class TestMultiEdgeDataView(TestEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiGraph()) - cls.eview = nx.reportviews.MultiEdgeView - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]][0].update(kwds) - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "MultiEdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - assert (0, 1) in ev - assert (1, 2) in ev - assert (2, 3) in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - -class TestOutMultiEdgeDataView(TestOutEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.eview = nx.reportviews.OutMultiEdgeView - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]][0].update(kwds) - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "OutMultiEdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - assert (0, 1) in ev - assert (1, 2) not in ev - assert (2, 3) in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - -class TestInMultiEdgeDataView(TestOutMultiEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.eview = nx.reportviews.InMultiEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = ( - "InMultiEdgeDataView([(0, 1, {}), (1, 2, {}), " - + "(2, 3, {}), (3, 4, {}), " - + "(4, 5, {}), (5, 6, {}), " - + "(6, 7, {}), (7, 8, {})])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - evr = self.eview(self.G) - ev = evr(nbunch=[0, 2]) - assert (0, 1) not in ev - assert (1, 2) in ev - assert (2, 3) not in ev - assert (3, 4) not in ev - assert (4, 5) not in ev - assert (5, 6) not in ev - assert (7, 8) not in ev - assert (8, 9) not in ev - - -# Edge Views -class TestEdgeView: - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.eview = nx.reportviews.EdgeView - - def test_pickle(self): - import pickle - - ev = self.eview(self.G) - pev = pickle.loads(pickle.dumps(ev, -1)) - assert ev == pev - assert ev.__slots__ == pev.__slots__ - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]].update(kwds) - - def test_str(self): - ev = self.eview(self.G) - rep = str([(n, n + 1) for n in range(8)]) - assert str(ev) == rep - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "EdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " - + "(4, 5), (5, 6), (6, 7), (7, 8)])" - ) - assert repr(ev) == rep - - def test_getitem(self): - G = self.G.copy() - ev = G.edges - G.edges[0, 1]["foo"] = "bar" - assert ev[0, 1] == {"foo": "bar"} - - # slicing - with pytest.raises(nx.NetworkXError, match=".*does not support slicing"): - G.edges[0:5] - - # Invalid edge - with pytest.raises(KeyError, match=r".*edge.*is not in the graph."): - G.edges[0, 9] - - def test_call(self): - ev = self.eview(self.G) - assert id(ev) == id(ev()) - assert id(ev) == id(ev(data=False)) - assert id(ev) != id(ev(data=True)) - assert id(ev) != id(ev(nbunch=1)) - - def test_data(self): - ev = self.eview(self.G) - assert id(ev) != id(ev.data()) - assert id(ev) == id(ev.data(data=False)) - assert id(ev) != id(ev.data(data=True)) - assert id(ev) != id(ev.data(nbunch=1)) - - def test_iter(self): - ev = self.eview(self.G) - for u, v in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_contains(self): - ev = self.eview(self.G) - edv = ev() - if self.G.is_directed(): - assert (1, 2) in ev and (2, 1) not in ev - assert (1, 2) in edv and (2, 1) not in edv - else: - assert (1, 2) in ev and (2, 1) in ev - assert (1, 2) in edv and (2, 1) in edv - assert (1, 4) not in ev - assert (1, 4) not in edv - # edge not in graph - assert (1, 90) not in ev - assert (90, 1) not in ev - assert (1, 90) not in edv - assert (90, 1) not in edv - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) in evn - assert (1, 2) in evn - assert (2, 3) in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - def test_len(self): - ev = self.eview(self.G) - num_ed = 9 if self.G.is_multigraph() else 8 - assert len(ev) == num_ed - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 3 + H.is_multigraph() - H.is_directed() - assert len(H.edges()) == num_ed + 1 - assert len(H.edges) == num_ed + 1 - - def test_and(self): - # print("G & H edges:", gnv & hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - if self.G.is_directed(): - assert some_edges & ev, {(0, 1)} - assert ev & some_edges, {(0, 1)} - else: - assert ev & some_edges == {(0, 1), (1, 0)} - assert some_edges & ev == {(0, 1), (1, 0)} - return - - def test_or(self): - # print("G | H edges:", gnv | hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - result1 = {(n, n + 1) for n in range(8)} - result1.update(some_edges) - result2 = {(n + 1, n) for n in range(8)} - result2.update(some_edges) - assert (ev | some_edges) in (result1, result2) - assert (some_edges | ev) in (result1, result2) - - def test_xor(self): - # print("G ^ H edges:", gnv ^ hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - if self.G.is_directed(): - result = {(n, n + 1) for n in range(1, 8)} - result.update({(1, 0), (0, 2)}) - assert ev ^ some_edges == result - else: - result = {(n, n + 1) for n in range(1, 8)} - result.update({(0, 2)}) - assert ev ^ some_edges == result - return - - def test_sub(self): - # print("G - H edges:", gnv - hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - result = {(n, n + 1) for n in range(8)} - result.remove((0, 1)) - assert ev - some_edges, result - - -class TestOutEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.DiGraph()) - cls.eview = nx.reportviews.OutEdgeView - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "OutEdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " - + "(4, 5), (5, 6), (6, 7), (7, 8)])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) in evn - assert (1, 2) not in evn - assert (2, 3) in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - -class TestInEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.DiGraph()) - cls.eview = nx.reportviews.InEdgeView - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "InEdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " - + "(4, 5), (5, 6), (6, 7), (7, 8)])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) not in evn - assert (1, 2) in evn - assert (2, 3) not in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - -class TestMultiEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiGraph()) - cls.G.add_edge(1, 2, key=3, foo="bar") - cls.eview = nx.reportviews.MultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_str(self): - ev = self.eview(self.G) - replist = [(n, n + 1, 0) for n in range(8)] - replist.insert(2, (1, 2, 3)) - rep = str(replist) - assert str(ev) == rep - - def test_getitem(self): - G = self.G.copy() - ev = G.edges - G.edges[0, 1, 0]["foo"] = "bar" - assert ev[0, 1, 0] == {"foo": "bar"} - - # slicing - with pytest.raises(nx.NetworkXError): - G.edges[0:5] - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "MultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0), " - + "(3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - ) - assert repr(ev) == rep - - def test_call(self): - ev = self.eview(self.G) - assert id(ev) == id(ev(keys=True)) - assert id(ev) == id(ev(data=False, keys=True)) - assert id(ev) != id(ev(keys=False)) - assert id(ev) != id(ev(data=True)) - assert id(ev) != id(ev(nbunch=1)) - - def test_data(self): - ev = self.eview(self.G) - assert id(ev) != id(ev.data()) - assert id(ev) == id(ev.data(data=False, keys=True)) - assert id(ev) != id(ev.data(keys=False)) - assert id(ev) != id(ev.data(data=True)) - assert id(ev) != id(ev.data(nbunch=1)) - - def test_iter(self): - ev = self.eview(self.G) - for u, v, k in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1, 0) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_iterkeys(self): - G = self.G - evr = self.eview(G) - ev = evr(keys=True) - for u, v, k in ev: - pass - assert k == 0 - ev = evr(keys=True, data="foo", default=1) - for u, v, k, wt in ev: - pass - assert wt == 1 - - self.modify_edge(G, (2, 3, 0), foo="bar") - ev = evr(keys=True, data=True) - for e in ev: - assert len(e) == 4 - print("edge:", e) - if set(e[:2]) == {2, 3}: - print(self.G._adj[2][3]) - assert e[2] == 0 - assert e[3] == {"foo": "bar"} - checked = True - elif set(e[:3]) == {1, 2, 3}: - assert e[2] == 3 - assert e[3] == {"foo": "bar"} - checked_multi = True - else: - assert e[2] == 0 - assert e[3] == {} - assert checked - assert checked_multi - ev = evr(keys=True, data="foo", default=1) - for e in ev: - if set(e[:2]) == {1, 2} and e[2] == 3: - assert e[3] == "bar" - if set(e[:2]) == {1, 2} and e[2] == 0: - assert e[3] == 1 - if set(e[:2]) == {2, 3}: - assert e[2] == 0 - assert e[3] == "bar" - assert len(e) == 4 - checked_wt = True - assert checked_wt - ev = evr(keys=True) - for e in ev: - assert len(e) == 3 - elist = sorted([(i, i + 1, 0) for i in range(8)] + [(1, 2, 3)]) - assert sorted(ev) == elist - # test that the keyword arguments are passed correctly - ev = evr((1, 2), "foo", keys=True, default=1) - with pytest.raises(TypeError): - evr((1, 2), "foo", True, 1) - with pytest.raises(TypeError): - evr((1, 2), "foo", True, default=1) - for e in ev: - if set(e[:2]) == {1, 2}: - assert e[2] in {0, 3} - if e[2] == 3: - assert e[3] == "bar" - else: # e[2] == 0 - assert e[3] == 1 - if G.is_directed(): - assert len(list(ev)) == 3 - else: - assert len(list(ev)) == 4 - - def test_or(self): - # print("G | H edges:", gnv | hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - result = {(n, n + 1, 0) for n in range(8)} - result.update(some_edges) - result.update({(1, 2, 3)}) - assert ev | some_edges == result - assert some_edges | ev == result - - def test_sub(self): - # print("G - H edges:", gnv - hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - result = {(n, n + 1, 0) for n in range(8)} - result.remove((0, 1, 0)) - result.update({(1, 2, 3)}) - assert ev - some_edges, result - assert some_edges - ev, result - - def test_xor(self): - # print("G ^ H edges:", gnv ^ hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - if self.G.is_directed(): - result = {(n, n + 1, 0) for n in range(1, 8)} - result.update({(1, 0, 0), (0, 2, 0), (1, 2, 3)}) - assert ev ^ some_edges == result - assert some_edges ^ ev == result - else: - result = {(n, n + 1, 0) for n in range(1, 8)} - result.update({(0, 2, 0), (1, 2, 3)}) - assert ev ^ some_edges == result - assert some_edges ^ ev == result - - def test_and(self): - # print("G & H edges:", gnv & hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - if self.G.is_directed(): - assert ev & some_edges == {(0, 1, 0)} - assert some_edges & ev == {(0, 1, 0)} - else: - assert ev & some_edges == {(0, 1, 0), (1, 0, 0)} - assert some_edges & ev == {(0, 1, 0), (1, 0, 0)} - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) in evn - assert (1, 2) in evn - assert (2, 3) in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - -class TestOutMultiEdgeView(TestMultiEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiDiGraph()) - cls.G.add_edge(1, 2, key=3, foo="bar") - cls.eview = nx.reportviews.OutMultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "OutMultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0)," - + " (3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) in evn - assert (1, 2) not in evn - assert (2, 3) in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - -class TestInMultiEdgeView(TestMultiEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiDiGraph()) - cls.G.add_edge(1, 2, key=3, foo="bar") - cls.eview = nx.reportviews.InMultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_repr(self): - ev = self.eview(self.G) - rep = ( - "InMultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0), " - + "(3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - ) - assert repr(ev) == rep - - def test_contains_with_nbunch(self): - ev = self.eview(self.G) - evn = ev(nbunch=[0, 2]) - assert (0, 1) not in evn - assert (1, 2) in evn - assert (2, 3) not in evn - assert (3, 4) not in evn - assert (4, 5) not in evn - assert (5, 6) not in evn - assert (7, 8) not in evn - assert (8, 9) not in evn - - -# Degrees -class TestDegreeView: - GRAPH = nx.Graph - dview = nx.reportviews.DegreeView - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(6, cls.GRAPH()) - cls.G.add_edge(1, 3, foo=2) - cls.G.add_edge(1, 3, foo=3) - - def test_pickle(self): - import pickle - - deg = self.G.degree - pdeg = pickle.loads(pickle.dumps(deg, -1)) - assert dict(deg) == dict(pdeg) - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 3), (2, 2), (3, 3), (4, 2), (5, 1)]) - assert str(dv) == rep - dv = self.G.degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.dview(self.G) - rep = "DegreeView({0: 1, 1: 3, 2: 2, 3: 3, 4: 2, 5: 1})" - assert repr(dv) == rep - - def test_iter(self): - dv = self.dview(self.G) - for n, d in dv: - pass - idv = iter(dv) - assert iter(dv) != dv - assert iter(idv) == idv - assert next(idv) == (0, dv[0]) - assert next(idv) == (1, dv[1]) - # weighted - dv = self.dview(self.G, weight="foo") - for n, d in dv: - pass - idv = iter(dv) - assert iter(dv) != dv - assert iter(idv) == idv - assert next(idv) == (0, dv[0]) - assert next(idv) == (1, dv[1]) - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 2), (3, 3)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 3 - assert dv[2] == 2 - assert dv[3] == 3 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 1 - assert dv[1] == 5 - assert dv[2] == 2 - assert dv[3] == 5 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 1 - dvw = dv(1, weight="foo") - assert dvw == 5 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 2), (3, 5)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 1 - assert dvd[1] == 5 - assert dvd[2] == 2 - assert dvd[3] == 5 - - def test_len(self): - dv = self.dview(self.G) - assert len(dv) == 6 - - -class TestDiDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.DiDegreeView - - def test_repr(self): - dv = self.G.degree() - rep = "DiDegreeView({0: 1, 1: 3, 2: 2, 3: 3, 4: 2, 5: 1})" - assert repr(dv) == rep - - -class TestOutDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.OutDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 2), (2, 1), (3, 1), (4, 1), (5, 0)]) - assert str(dv) == rep - dv = self.G.out_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.out_degree() - rep = "OutDegreeView({0: 1, 1: 2, 2: 1, 3: 1, 4: 1, 5: 0})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 1)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 2 - assert dv[2] == 1 - assert dv[3] == 1 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 1 - assert dv[1] == 4 - assert dv[2] == 1 - assert dv[3] == 1 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 1 - dvw = dv(1, weight="foo") - assert dvw == 4 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 1), (3, 1)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 1 - assert dvd[1] == 4 - assert dvd[2] == 1 - assert dvd[3] == 1 - - -class TestInDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.InDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 0), (1, 1), (2, 1), (3, 2), (4, 1), (5, 1)]) - assert str(dv) == rep - dv = self.G.in_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.in_degree() - rep = "InDegreeView({0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 0 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 2)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 2 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 4 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 0 - dvw = dv(1, weight="foo") - assert dvw == 1 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 1), (3, 4)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 0 - assert dvd[1] == 1 - assert dvd[2] == 1 - assert dvd[3] == 4 - - -class TestMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiGraph - dview = nx.reportviews.MultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 4), (2, 2), (3, 4), (4, 2), (5, 1)]) - assert str(dv) == rep - dv = self.G.degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.degree() - rep = "MultiDegreeView({0: 1, 1: 4, 2: 2, 3: 4, 4: 2, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 2), (3, 4)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 4 - assert dv[2] == 2 - assert dv[3] == 4 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 1 - assert dv[1] == 7 - assert dv[2] == 2 - assert dv[3] == 7 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 1 - dvw = dv(1, weight="foo") - assert dvw == 7 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 2), (3, 7)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 1 - assert dvd[1] == 7 - assert dvd[2] == 2 - assert dvd[3] == 7 - - -class TestDiMultiDegreeView(TestMultiDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.DiMultiDegreeView - - def test_repr(self): - dv = self.G.degree() - rep = "DiMultiDegreeView({0: 1, 1: 4, 2: 2, 3: 4, 4: 2, 5: 1})" - assert repr(dv) == rep - - -class TestOutMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.OutMultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 3), (2, 1), (3, 1), (4, 1), (5, 0)]) - assert str(dv) == rep - dv = self.G.out_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.out_degree() - rep = "OutMultiDegreeView({0: 1, 1: 3, 2: 1, 3: 1, 4: 1, 5: 0})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 1)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 3 - assert dv[2] == 1 - assert dv[3] == 1 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 1 - assert dv[1] == 6 - assert dv[2] == 1 - assert dv[3] == 1 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 1 - dvw = dv(1, weight="foo") - assert dvw == 6 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 1), (3, 1)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 1 - assert dvd[1] == 6 - assert dvd[2] == 1 - assert dvd[3] == 1 - - -class TestInMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.InMultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 0), (1, 1), (2, 1), (3, 3), (4, 1), (5, 1)]) - assert str(dv) == rep - dv = self.G.in_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.in_degree() - rep = "InMultiDegreeView({0: 0, 1: 1, 2: 1, 3: 3, 4: 1, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 0 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 3)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 3 - dv = self.dview(self.G, weight="foo") - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 6 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight="foo") - assert dvw == 0 - dvw = dv(1, weight="foo") - assert dvw == 1 - dvw = dv([2, 3], weight="foo") - assert sorted(dvw) == [(2, 1), (3, 6)] - dvd = dict(dv(weight="foo")) - assert dvd[0] == 0 - assert dvd[1] == 1 - assert dvd[2] == 1 - assert dvd[3] == 6 - - -@pytest.mark.parametrize( - ("reportview", "err_msg_terms"), - ( - (rv.NodeView, "list(G.nodes"), - (rv.NodeDataView, "list(G.nodes.data"), - (rv.EdgeView, "list(G.edges"), - # Directed EdgeViews - (rv.InEdgeView, "list(G.in_edges"), - (rv.OutEdgeView, "list(G.edges"), - # Multi EdgeViews - (rv.MultiEdgeView, "list(G.edges"), - (rv.InMultiEdgeView, "list(G.in_edges"), - (rv.OutMultiEdgeView, "list(G.edges"), - ), -) -def test_slicing_reportviews(reportview, err_msg_terms): - G = nx.complete_graph(3) - view = reportview(G) - with pytest.raises(nx.NetworkXError) as exc: - view[0:2] - errmsg = str(exc.value) - assert type(view).__name__ in errmsg - assert err_msg_terms in errmsg - - -@pytest.mark.parametrize( - "graph", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] -) -def test_cache_dict_get_set_state(graph): - G = nx.path_graph(5, graph()) - G.nodes, G.edges, G.adj, G.degree - if G.is_directed(): - G.pred, G.succ, G.in_edges, G.out_edges, G.in_degree, G.out_degree - cached_dict = G.__dict__ - assert "nodes" in cached_dict - assert "edges" in cached_dict - assert "adj" in cached_dict - assert "degree" in cached_dict - if G.is_directed(): - assert "pred" in cached_dict - assert "succ" in cached_dict - assert "in_edges" in cached_dict - assert "out_edges" in cached_dict - assert "in_degree" in cached_dict - assert "out_degree" in cached_dict - - # Raises error if the cached properties and views do not work - pickle.loads(pickle.dumps(G, -1)) - deepcopy(G) - - -def test_edge_views_inherit_from_EdgeViewABC(): - all_edge_view_classes = (v for v in dir(nx.reportviews) if "Edge" in v) - for eview_class in all_edge_view_classes: - assert issubclass( - getattr(nx.reportviews, eview_class), nx.reportviews.EdgeViewABC - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_special.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_special.py deleted file mode 100644 index 1fa7960..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_special.py +++ /dev/null @@ -1,131 +0,0 @@ -import networkx as nx - -from .test_digraph import BaseDiGraphTester -from .test_digraph import TestDiGraph as _TestDiGraph -from .test_graph import BaseGraphTester -from .test_graph import TestGraph as _TestGraph -from .test_multidigraph import TestMultiDiGraph as _TestMultiDiGraph -from .test_multigraph import TestMultiGraph as _TestMultiGraph - - -def test_factories(): - class mydict1(dict): - pass - - class mydict2(dict): - pass - - class mydict3(dict): - pass - - class mydict4(dict): - pass - - class mydict5(dict): - pass - - for Graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph): - # print("testing class: ", Graph.__name__) - class MyGraph(Graph): - node_dict_factory = mydict1 - adjlist_outer_dict_factory = mydict2 - adjlist_inner_dict_factory = mydict3 - edge_key_dict_factory = mydict4 - edge_attr_dict_factory = mydict5 - - G = MyGraph() - assert isinstance(G._node, mydict1) - assert isinstance(G._adj, mydict2) - G.add_node(1) - assert isinstance(G._adj[1], mydict3) - if G.is_directed(): - assert isinstance(G._pred, mydict2) - assert isinstance(G._succ, mydict2) - assert isinstance(G._pred[1], mydict3) - G.add_edge(1, 2) - if G.is_multigraph(): - assert isinstance(G._adj[1][2], mydict4) - assert isinstance(G._adj[1][2][0], mydict5) - else: - assert isinstance(G._adj[1][2], mydict5) - - -class TestSpecialGraph(_TestGraph): - def setup_method(self): - _TestGraph.setup_method(self) - self.Graph = nx.Graph - - -class TestThinGraph(BaseGraphTester): - def setup_method(self): - all_edge_dict = {"weight": 1} - - class MyGraph(nx.Graph): - def edge_attr_dict_factory(self): - return all_edge_dict - - self.Graph = MyGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - -class TestSpecialDiGraph(_TestDiGraph): - def setup_method(self): - _TestDiGraph.setup_method(self) - self.Graph = nx.DiGraph - - -class TestThinDiGraph(BaseDiGraphTester): - def setup_method(self): - all_edge_dict = {"weight": 1} - - class MyGraph(nx.DiGraph): - def edge_attr_dict_factory(self): - return all_edge_dict - - self.Graph = MyGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict) - ed4, ed5, ed6 = (all_edge_dict, all_edge_dict, all_edge_dict) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._succ = self.k3adj - # K3._adj is synced with K3._succ - self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}} - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - ed1, ed2 = (all_edge_dict, all_edge_dict) - self.P3 = self.Graph() - self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}} - # P3._adj is synced with P3._succ - self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}} - self.P3._node = {} - self.P3._node[0] = {} - self.P3._node[1] = {} - self.P3._node[2] = {} - - -class TestSpecialMultiGraph(_TestMultiGraph): - def setup_method(self): - _TestMultiGraph.setup_method(self) - self.Graph = nx.MultiGraph - - -class TestSpecialMultiDiGraph(_TestMultiDiGraph): - def setup_method(self): - _TestMultiDiGraph.setup_method(self) - self.Graph = nx.MultiDiGraph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_subgraphviews.py b/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_subgraphviews.py deleted file mode 100644 index 73e0fdd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/classes/tests/test_subgraphviews.py +++ /dev/null @@ -1,362 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -class TestSubGraphView: - gview = staticmethod(nx.subgraph_view) - graph = nx.Graph - hide_edges_filter = staticmethod(nx.filters.hide_edges) - show_edges_filter = staticmethod(nx.filters.show_edges) - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=cls.graph()) - cls.hide_edges_w_hide_nodes = {(3, 4), (4, 5), (5, 6)} - - def test_hidden_nodes(self): - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - gview = self.gview - G = gview(self.G, filter_node=nodes_gone) - assert self.G.nodes - G.nodes == {4, 5} - assert self.G.edges - G.edges == self.hide_edges_w_hide_nodes - if G.is_directed(): - assert list(G[3]) == [] - assert list(G[2]) == [3] - else: - assert list(G[3]) == [2] - assert set(G[2]) == {1, 3} - pytest.raises(KeyError, G.__getitem__, 4) - pytest.raises(KeyError, G.__getitem__, 112) - pytest.raises(KeyError, G.__getitem__, 111) - assert G.degree(3) == (3 if G.is_multigraph() else 1) - assert G.size() == (7 if G.is_multigraph() else 5) - - def test_hidden_edges(self): - hide_edges = [(2, 3), (8, 7), (222, 223)] - edges_gone = self.hide_edges_filter(hide_edges) - gview = self.gview - G = gview(self.G, filter_edge=edges_gone) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert self.G.edges - G.edges == {(2, 3)} - assert list(G[2]) == [] - assert list(G.pred[3]) == [] - assert list(G.pred[2]) == [1] - assert G.size() == 7 - else: - assert self.G.edges - G.edges == {(2, 3), (7, 8)} - assert list(G[2]) == [1] - assert G.size() == 6 - assert list(G[3]) == [4] - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - assert G.degree(3) == 1 - - def test_shown_node(self): - induced_subgraph = nx.filters.show_nodes([2, 3, 111]) - gview = self.gview - G = gview(self.G, filter_node=induced_subgraph) - assert set(G.nodes) == {2, 3} - if G.is_directed(): - assert list(G[3]) == [] - else: - assert list(G[3]) == [2] - assert list(G[2]) == [3] - pytest.raises(KeyError, G.__getitem__, 4) - pytest.raises(KeyError, G.__getitem__, 112) - pytest.raises(KeyError, G.__getitem__, 111) - assert G.degree(3) == (3 if G.is_multigraph() else 1) - assert G.size() == (3 if G.is_multigraph() else 1) - - def test_shown_edges(self): - show_edges = [(2, 3), (8, 7), (222, 223)] - edge_subgraph = self.show_edges_filter(show_edges) - G = self.gview(self.G, filter_edge=edge_subgraph) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert G.edges == {(2, 3)} - assert list(G[3]) == [] - assert list(G[2]) == [3] - assert list(G.pred[3]) == [2] - assert list(G.pred[2]) == [] - assert G.size() == 1 - else: - assert G.edges == {(2, 3), (7, 8)} - assert list(G[3]) == [2] - assert list(G[2]) == [3] - assert G.size() == 2 - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - assert G.degree(3) == 1 - - -class TestSubDiGraphView(TestSubGraphView): - gview = staticmethod(nx.subgraph_view) - graph = nx.DiGraph - hide_edges_filter = staticmethod(nx.filters.hide_diedges) - show_edges_filter = staticmethod(nx.filters.show_diedges) - hide_edges = [(2, 3), (8, 7), (222, 223)] - excluded = {(2, 3), (3, 4), (4, 5), (5, 6)} - - def test_inoutedges(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, filter_node=nodes_gone, filter_edge=edges_gone) - - assert self.G.in_edges - G.in_edges == self.excluded - assert self.G.out_edges - G.out_edges == self.excluded - - def test_pred(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, filter_node=nodes_gone, filter_edge=edges_gone) - - assert list(G.pred[2]) == [1] - assert list(G.pred[6]) == [] - - def test_inout_degree(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, filter_node=nodes_gone, filter_edge=edges_gone) - - assert G.degree(2) == 1 - assert G.out_degree(2) == 0 - assert G.in_degree(2) == 1 - assert G.size() == 4 - - -# multigraph -class TestMultiGraphView(TestSubGraphView): - gview = staticmethod(nx.subgraph_view) - graph = nx.MultiGraph - hide_edges_filter = staticmethod(nx.filters.hide_multiedges) - show_edges_filter = staticmethod(nx.filters.show_multiedges) - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=cls.graph()) - multiedges = {(2, 3, 4), (2, 3, 5)} - cls.G.add_edges_from(multiedges) - cls.hide_edges_w_hide_nodes = {(3, 4, 0), (4, 5, 0), (5, 6, 0)} - - def test_hidden_edges(self): - hide_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)] - edges_gone = self.hide_edges_filter(hide_edges) - G = self.gview(self.G, filter_edge=edges_gone) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert self.G.edges - G.edges == {(2, 3, 4)} - assert list(G[3]) == [4] - assert list(G[2]) == [3] - assert list(G.pred[3]) == [2] # only one 2 but two edges - assert list(G.pred[2]) == [1] - assert G.size() == 9 - else: - assert self.G.edges - G.edges == {(2, 3, 4), (7, 8, 0)} - assert list(G[3]) == [2, 4] - assert list(G[2]) == [1, 3] - assert G.size() == 8 - assert G.degree(3) == 3 - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - - def test_shown_edges(self): - show_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)] - edge_subgraph = self.show_edges_filter(show_edges) - G = self.gview(self.G, filter_edge=edge_subgraph) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert G.edges == {(2, 3, 4)} - assert list(G[3]) == [] - assert list(G.pred[3]) == [2] - assert list(G.pred[2]) == [] - assert G.size() == 1 - else: - assert G.edges == {(2, 3, 4), (7, 8, 0)} - assert G.size() == 2 - assert list(G[3]) == [2] - assert G.degree(3) == 1 - assert list(G[2]) == [3] - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - - -# multidigraph -class TestMultiDiGraphView(TestMultiGraphView, TestSubDiGraphView): - gview = staticmethod(nx.subgraph_view) - graph = nx.MultiDiGraph - hide_edges_filter = staticmethod(nx.filters.hide_multidiedges) - show_edges_filter = staticmethod(nx.filters.show_multidiedges) - hide_edges = [(2, 3, 0), (8, 7, 0), (222, 223, 0)] - excluded = {(2, 3, 0), (3, 4, 0), (4, 5, 0), (5, 6, 0)} - - def test_inout_degree(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, filter_node=nodes_gone, filter_edge=edges_gone) - - assert G.degree(2) == 3 - assert G.out_degree(2) == 2 - assert G.in_degree(2) == 1 - assert G.size() == 6 - - -# induced_subgraph -class TestInducedSubGraph: - @classmethod - def setup_class(cls): - cls.K3 = G = nx.complete_graph(3) - G.graph["foo"] = [] - G.nodes[0]["foo"] = [] - G.remove_edge(1, 2) - ll = [] - G.add_edge(1, 2, foo=ll) - G.add_edge(2, 1, foo=ll) - - def test_full_graph(self): - G = self.K3 - H = nx.induced_subgraph(G, [0, 1, 2, 5]) - assert H.name == G.name - self.graphs_equal(H, G) - self.same_attrdict(H, G) - - def test_partial_subgraph(self): - G = self.K3 - H = nx.induced_subgraph(G, 0) - assert dict(H.adj) == {0: {}} - assert dict(G.adj) != {0: {}} - - H = nx.induced_subgraph(G, [0, 1]) - assert dict(H.adj) == {0: {1: {}}, 1: {0: {}}} - - def same_attrdict(self, H, G): - old_foo = H[1][2]["foo"] - H.edges[1, 2]["foo"] = "baz" - assert G.edges == H.edges - H.edges[1, 2]["foo"] = old_foo - assert G.edges == H.edges - old_foo = H.nodes[0]["foo"] - H.nodes[0]["foo"] = "baz" - assert G.nodes == H.nodes - H.nodes[0]["foo"] = old_foo - assert G.nodes == H.nodes - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2] is H._adj[2][1] - assert G._adj[1][2] is G._adj[2][1] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2] is H._pred[2][1] - assert G._succ[1][2] is G._pred[2][1] - - -# edge_subgraph -class TestEdgeSubGraph: - @classmethod - def setup_class(cls): - # Create a path graph on five nodes. - cls.G = G = nx.path_graph(5) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]["name"] = f"node{i}" - G.edges[0, 1]["name"] = "edge01" - G.edges[3, 4]["name"] = "edge34" - G.graph["name"] = "graph" - # Get the subgraph induced by the first and last edges. - cls.H = nx.edge_subgraph(G, [(0, 1), (3, 4)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [(0, "node0"), (1, "node1"), (3, "node3"), (4, "node4")] == sorted( - self.H.nodes.data("name") - ) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert edges_equal( - [(0, 1, "edge01"), (3, 4, "edge34")], self.H.edges.data("name") - ) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes) - self.G.remove_node(5) - - def test_remove_node(self): - """Tests that removing a node in the original graph - removes the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes) - self.G.add_node(0, name="node0") - self.G.add_edge(0, 1, name="edge01") - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]["name"] = "foo" - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]["name"] = "bar" - assert self.G.nodes[1] == self.H.nodes[1] - # Revert the change, so tests pass with pytest-randomly - self.G.nodes[0]["name"] = "node0" - self.H.nodes[1]["name"] = "node1" - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v in self.H.edges(): - assert self.G.edges[u, v] == self.H.edges[u, v] - # Making a change to G should make a change in H and vice versa. - self.G.edges[0, 1]["name"] = "foo" - assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"] - self.H.edges[3, 4]["name"] = "bar" - assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"] - # Revert the change, so tests pass with pytest-randomly - self.G.edges[0, 1]["name"] = "edge01" - self.H.edges[3, 4]["name"] = "edge34" - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph - - def test_readonly(self): - """Tests that the subgraph cannot change the graph structure""" - pytest.raises(nx.NetworkXError, self.H.add_node, 5) - pytest.raises(nx.NetworkXError, self.H.remove_node, 0) - pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6) - pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/conftest.py b/extensions/.local/lib/python3.11/site-packages/networkx/conftest.py deleted file mode 100644 index 4a261c6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/conftest.py +++ /dev/null @@ -1,284 +0,0 @@ -""" -Testing -======= - -General guidelines for writing good tests: - -- doctests always assume ``import networkx as nx`` so don't add that -- prefer pytest fixtures over classes with setup methods. -- use the ``@pytest.mark.parametrize`` decorator -- use ``pytest.importorskip`` for numpy, scipy, pandas, and matplotlib b/c of PyPy. - and add the module to the relevant entries below. - -""" - -import os -import sys -import warnings -from importlib.metadata import entry_points - -import pytest - -import networkx - - -def pytest_addoption(parser): - parser.addoption( - "--runslow", action="store_true", default=False, help="run slow tests" - ) - parser.addoption( - "--backend", - action="store", - default=None, - help="Run tests with a backend by auto-converting nx graphs to backend graphs", - ) - parser.addoption( - "--fallback-to-nx", - action="store_true", - default=False, - help="Run nx function if a backend doesn't implement a dispatchable function" - " (use with --backend)", - ) - - -def pytest_configure(config): - config.addinivalue_line("markers", "slow: mark test as slow to run") - backend = config.getoption("--backend") - if backend is None: - backend = os.environ.get("NETWORKX_TEST_BACKEND") - # nx_loopback backend is only available when testing with a backend - loopback_ep = entry_points(name="nx_loopback", group="networkx.backends") - if not loopback_ep: - warnings.warn( - "\n\n WARNING: Mixed NetworkX configuration! \n\n" - " This environment has mixed configuration for networkx.\n" - " The test object nx_loopback is not configured correctly.\n" - " You should not be seeing this message.\n" - " Try `pip install -e .`, or change your PYTHONPATH\n" - " Make sure python finds the networkx repo you are testing\n\n" - ) - config.backend = backend - if backend: - # We will update `networkx.config.backend_priority` below in `*_modify_items` - # to allow tests to get set up with normal networkx graphs. - networkx.utils.backends.backends["nx_loopback"] = loopback_ep["nx_loopback"] - networkx.utils.backends.backend_info["nx_loopback"] = {} - networkx.config.backends = networkx.utils.Config( - nx_loopback=networkx.utils.Config(), - **networkx.config.backends, - ) - fallback_to_nx = config.getoption("--fallback-to-nx") - if not fallback_to_nx: - fallback_to_nx = os.environ.get("NETWORKX_FALLBACK_TO_NX") - networkx.config.fallback_to_nx = bool(fallback_to_nx) - - -def pytest_collection_modifyitems(config, items): - # Setting this to True here allows tests to be set up before dispatching - # any function call to a backend. - if config.backend: - # Allow pluggable backends to add markers to tests (such as skip or xfail) - # when running in auto-conversion test mode - backend_name = config.backend - if backend_name != "networkx": - networkx.utils.backends._dispatchable._is_testing = True - networkx.config.backend_priority.algos = [backend_name] - networkx.config.backend_priority.generators = [backend_name] - backend = networkx.utils.backends.backends[backend_name].load() - if hasattr(backend, "on_start_tests"): - getattr(backend, "on_start_tests")(items) - - if config.getoption("--runslow"): - # --runslow given in cli: do not skip slow tests - return - skip_slow = pytest.mark.skip(reason="need --runslow option to run") - for item in items: - if "slow" in item.keywords: - item.add_marker(skip_slow) - - -# TODO: The warnings below need to be dealt with, but for now we silence them. -@pytest.fixture(autouse=True) -def set_warnings(): - warnings.filterwarnings( - "ignore", - category=FutureWarning, - message="\n\nsingle_target_shortest_path_length", - ) - warnings.filterwarnings( - "ignore", - category=FutureWarning, - message="\n\nshortest_path", - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nThe `normalized`" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nall_triplets" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nrandom_triad" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="minimal_d_separator" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="d_separated" - ) - warnings.filterwarnings("ignore", category=DeprecationWarning, message="\n\nk_core") - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nk_shell" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nk_crust" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\nk_corona" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\ntotal_spanning_tree_weight" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message=r"\n\nThe 'create=matrix'" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="\n\n`compute_v_structures" - ) - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="Keyword argument 'link'" - ) - - -@pytest.fixture(autouse=True) -def add_nx(doctest_namespace): - doctest_namespace["nx"] = networkx - - -# What dependencies are installed? - -try: - import numpy - - has_numpy = True -except ImportError: - has_numpy = False - -try: - import scipy - - has_scipy = True -except ImportError: - has_scipy = False - -try: - import matplotlib - - has_matplotlib = True -except ImportError: - has_matplotlib = False - -try: - import pandas - - has_pandas = True -except ImportError: - has_pandas = False - -try: - import pygraphviz - - has_pygraphviz = True -except ImportError: - has_pygraphviz = False - -try: - import pydot - - has_pydot = True -except ImportError: - has_pydot = False - -try: - import sympy - - has_sympy = True -except ImportError: - has_sympy = False - - -# List of files that pytest should ignore - -collect_ignore = [] - -needs_numpy = [ - "algorithms/approximation/traveling_salesman.py", - "algorithms/centrality/current_flow_closeness.py", - "algorithms/centrality/laplacian.py", - "algorithms/node_classification.py", - "algorithms/non_randomness.py", - "algorithms/polynomials.py", - "algorithms/shortest_paths/dense.py", - "algorithms/tree/mst.py", - "drawing/nx_latex.py", - "generators/expanders.py", - "linalg/bethehessianmatrix.py", - "linalg/laplacianmatrix.py", - "utils/misc.py", -] -needs_scipy = [ - "algorithms/approximation/traveling_salesman.py", - "algorithms/assortativity/correlation.py", - "algorithms/assortativity/mixing.py", - "algorithms/assortativity/pairs.py", - "algorithms/bipartite/matrix.py", - "algorithms/bipartite/spectral.py", - "algorithms/centrality/current_flow_betweenness.py", - "algorithms/centrality/current_flow_betweenness_subset.py", - "algorithms/centrality/eigenvector.py", - "algorithms/centrality/katz.py", - "algorithms/centrality/laplacian.py", - "algorithms/centrality/second_order.py", - "algorithms/centrality/subgraph_alg.py", - "algorithms/communicability_alg.py", - "algorithms/community/divisive.py", - "algorithms/distance_measures.py", - "algorithms/link_analysis/hits_alg.py", - "algorithms/link_analysis/pagerank_alg.py", - "algorithms/node_classification.py", - "algorithms/similarity.py", - "algorithms/tree/mst.py", - "algorithms/walks.py", - "convert_matrix.py", - "drawing/layout.py", - "drawing/nx_pylab.py", - "generators/spectral_graph_forge.py", - "generators/expanders.py", - "linalg/algebraicconnectivity.py", - "linalg/attrmatrix.py", - "linalg/bethehessianmatrix.py", - "linalg/graphmatrix.py", - "linalg/laplacianmatrix.py", - "linalg/modularitymatrix.py", - "linalg/spectrum.py", - "utils/rcm.py", -] -needs_matplotlib = ["drawing/nx_pylab.py", "generators/classic.py"] -needs_pandas = ["convert_matrix.py"] -needs_pygraphviz = ["drawing/nx_agraph.py"] -needs_pydot = ["drawing/nx_pydot.py"] -needs_sympy = ["algorithms/polynomials.py"] - -if not has_numpy: - collect_ignore += needs_numpy -if not has_scipy: - collect_ignore += needs_scipy -if not has_matplotlib: - collect_ignore += needs_matplotlib -if not has_pandas: - collect_ignore += needs_pandas -if not has_pygraphviz: - collect_ignore += needs_pygraphviz -if not has_pydot: - collect_ignore += needs_pydot -if not has_sympy: - collect_ignore += needs_sympy diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/convert.py b/extensions/.local/lib/python3.11/site-packages/networkx/convert.py deleted file mode 100644 index 3f89c35..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/convert.py +++ /dev/null @@ -1,502 +0,0 @@ -"""Functions to convert NetworkX graphs to and from other formats. - -The preferred way of converting data to a NetworkX graph is through the -graph constructor. The constructor calls the to_networkx_graph() function -which attempts to guess the input type and convert it automatically. - -Examples --------- -Create a graph with a single edge from a dictionary of dictionaries - ->>> d = {0: {1: 1}} # dict-of-dicts single edge (0,1) ->>> G = nx.Graph(d) - -See Also --------- -nx_agraph, nx_pydot -""" - -import warnings -from collections.abc import Collection, Generator, Iterator - -import networkx as nx - -__all__ = [ - "to_networkx_graph", - "from_dict_of_dicts", - "to_dict_of_dicts", - "from_dict_of_lists", - "to_dict_of_lists", - "from_edgelist", - "to_edgelist", -] - - -def to_networkx_graph(data, create_using=None, multigraph_input=False): - """Make a NetworkX graph from a known data structure. - - The preferred way to call this is automatically - from the class constructor - - >>> d = {0: {1: {"weight": 1}}} # dict-of-dicts single edge (0,1) - >>> G = nx.Graph(d) - - instead of the equivalent - - >>> G = nx.from_dict_of_dicts(d) - - Parameters - ---------- - data : object to be converted - - Current known types are: - any NetworkX graph - dict-of-dicts - dict-of-lists - container (e.g. set, list, tuple) of edges - iterator (e.g. itertools.chain) that produces edges - generator of edges - Pandas DataFrame (row per edge) - 2D numpy array - scipy sparse array - pygraphviz agraph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - multigraph_input : bool (default False) - If True and data is a dict_of_dicts, - try to create a multigraph assuming dict_of_dict_of_lists. - If data and create_using are both multigraphs then create - a multigraph from a multigraph. - - """ - # NX graph - if hasattr(data, "adj"): - try: - result = from_dict_of_dicts( - data.adj, - create_using=create_using, - multigraph_input=data.is_multigraph(), - ) - # data.graph should be dict-like - result.graph.update(data.graph) - # data.nodes should be dict-like - # result.add_node_from(data.nodes.items()) possible but - # for custom node_attr_dict_factory which may be hashable - # will be unexpected behavior - for n, dd in data.nodes.items(): - result._node[n].update(dd) - return result - except Exception as err: - raise nx.NetworkXError("Input is not a correct NetworkX graph.") from err - - # dict of dicts/lists - if isinstance(data, dict): - try: - return from_dict_of_dicts( - data, create_using=create_using, multigraph_input=multigraph_input - ) - except Exception as err1: - if multigraph_input is True: - raise nx.NetworkXError( - f"converting multigraph_input raised:\n{type(err1)}: {err1}" - ) - try: - return from_dict_of_lists(data, create_using=create_using) - except Exception as err2: - raise TypeError("Input is not known type.") from err2 - - # edgelists - if isinstance(data, list | tuple | nx.reportviews.EdgeViewABC | Iterator): - try: - return from_edgelist(data, create_using=create_using) - except: - pass - - # pygraphviz agraph - if hasattr(data, "is_strict"): - try: - return nx.nx_agraph.from_agraph(data, create_using=create_using) - except Exception as err: - raise nx.NetworkXError("Input is not a correct pygraphviz graph.") from err - - # Pandas DataFrame - try: - import pandas as pd - - if isinstance(data, pd.DataFrame): - if data.shape[0] == data.shape[1]: - try: - return nx.from_pandas_adjacency(data, create_using=create_using) - except Exception as err: - msg = "Input is not a correct Pandas DataFrame adjacency matrix." - raise nx.NetworkXError(msg) from err - else: - try: - return nx.from_pandas_edgelist( - data, edge_attr=True, create_using=create_using - ) - except Exception as err: - msg = "Input is not a correct Pandas DataFrame edge-list." - raise nx.NetworkXError(msg) from err - except ImportError: - pass - - # numpy array - try: - import numpy as np - - if isinstance(data, np.ndarray): - try: - return nx.from_numpy_array(data, create_using=create_using) - except Exception as err: - raise nx.NetworkXError( - f"Failed to interpret array as an adjacency matrix." - ) from err - except ImportError: - pass - - # scipy sparse array - any format - try: - import scipy - - if hasattr(data, "format"): - try: - return nx.from_scipy_sparse_array(data, create_using=create_using) - except Exception as err: - raise nx.NetworkXError( - "Input is not a correct scipy sparse array type." - ) from err - except ImportError: - pass - - # Note: most general check - should remain last in order of execution - # Includes containers (e.g. list, set, dict, etc.), generators, and - # iterators (e.g. itertools.chain) of edges - - if isinstance(data, Collection | Generator | Iterator): - try: - return from_edgelist(data, create_using=create_using) - except Exception as err: - raise nx.NetworkXError("Input is not a valid edge list") from err - - raise nx.NetworkXError("Input is not a known data type for conversion.") - - -@nx._dispatchable -def to_dict_of_lists(G, nodelist=None): - """Returns adjacency representation of graph as a dictionary of lists. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - Notes - ----- - Completely ignores edge data for MultiGraph and MultiDiGraph. - - """ - if nodelist is None: - nodelist = G - - d = {} - for n in nodelist: - d[n] = [nbr for nbr in G.neighbors(n) if nbr in nodelist] - return d - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_dict_of_lists(d, create_using=None): - """Returns a graph from a dictionary of lists. - - Parameters - ---------- - d : dictionary of lists - A dictionary of lists adjacency representation. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> dol = {0: [1]} # single edge (0,1) - >>> G = nx.from_dict_of_lists(dol) - - or - - >>> G = nx.Graph(dol) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_nodes_from(d) - if G.is_multigraph() and not G.is_directed(): - # a dict_of_lists can't show multiedges. BUT for undirected graphs, - # each edge shows up twice in the dict_of_lists. - # So we need to treat this case separately. - seen = {} - for node, nbrlist in d.items(): - for nbr in nbrlist: - if nbr not in seen: - G.add_edge(node, nbr) - seen[node] = 1 # don't allow reverse edge to show up - else: - G.add_edges_from( - ((node, nbr) for node, nbrlist in d.items() for nbr in nbrlist) - ) - return G - - -def to_dict_of_dicts(G, nodelist=None, edge_data=None): - """Returns adjacency representation of graph as a dictionary of dictionaries. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - edge_data : scalar, optional - If provided, the value of the dictionary will be set to `edge_data` for - all edges. Usual values could be `1` or `True`. If `edge_data` is - `None` (the default), the edgedata in `G` is used, resulting in a - dict-of-dict-of-dicts. If `G` is a MultiGraph, the result will be a - dict-of-dict-of-dict-of-dicts. See Notes for an approach to customize - handling edge data. `edge_data` should *not* be a container. - - Returns - ------- - dod : dict - A nested dictionary representation of `G`. Note that the level of - nesting depends on the type of `G` and the value of `edge_data` - (see Examples). - - See Also - -------- - from_dict_of_dicts, to_dict_of_lists - - Notes - ----- - For a more custom approach to handling edge data, try:: - - dod = { - n: {nbr: custom(n, nbr, dd) for nbr, dd in nbrdict.items()} - for n, nbrdict in G.adj.items() - } - - where `custom` returns the desired edge data for each edge between `n` and - `nbr`, given existing edge data `dd`. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> nx.to_dict_of_dicts(G) - {0: {1: {}}, 1: {0: {}, 2: {}}, 2: {1: {}}} - - Edge data is preserved by default (``edge_data=None``), resulting - in dict-of-dict-of-dicts where the innermost dictionary contains the - edge data: - - >>> G = nx.Graph() - >>> G.add_edges_from( - ... [ - ... (0, 1, {"weight": 1.0}), - ... (1, 2, {"weight": 2.0}), - ... (2, 0, {"weight": 1.0}), - ... ] - ... ) - >>> d = nx.to_dict_of_dicts(G) - >>> d # doctest: +SKIP - {0: {1: {'weight': 1.0}, 2: {'weight': 1.0}}, - 1: {0: {'weight': 1.0}, 2: {'weight': 2.0}}, - 2: {1: {'weight': 2.0}, 0: {'weight': 1.0}}} - >>> d[1][2]["weight"] - 2.0 - - If `edge_data` is not `None`, edge data in the original graph (if any) is - replaced: - - >>> d = nx.to_dict_of_dicts(G, edge_data=1) - >>> d - {0: {1: 1, 2: 1}, 1: {0: 1, 2: 1}, 2: {1: 1, 0: 1}} - >>> d[1][2] - 1 - - This also applies to MultiGraphs: edge data is preserved by default: - - >>> G = nx.MultiGraph() - >>> G.add_edge(0, 1, key="a", weight=1.0) - 'a' - >>> G.add_edge(0, 1, key="b", weight=5.0) - 'b' - >>> d = nx.to_dict_of_dicts(G) - >>> d # doctest: +SKIP - {0: {1: {'a': {'weight': 1.0}, 'b': {'weight': 5.0}}}, - 1: {0: {'a': {'weight': 1.0}, 'b': {'weight': 5.0}}}} - >>> d[0][1]["b"]["weight"] - 5.0 - - But multi edge data is lost if `edge_data` is not `None`: - - >>> d = nx.to_dict_of_dicts(G, edge_data=10) - >>> d - {0: {1: 10}, 1: {0: 10}} - """ - dod = {} - if nodelist is None: - if edge_data is None: - for u, nbrdict in G.adjacency(): - dod[u] = nbrdict.copy() - else: # edge_data is not None - for u, nbrdict in G.adjacency(): - dod[u] = dod.fromkeys(nbrdict, edge_data) - else: # nodelist is not None - if edge_data is None: - for u in nodelist: - dod[u] = {} - for v, data in ((v, data) for v, data in G[u].items() if v in nodelist): - dod[u][v] = data - else: # nodelist and edge_data are not None - for u in nodelist: - dod[u] = {} - for v in (v for v in G[u] if v in nodelist): - dod[u][v] = edge_data - return dod - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_dict_of_dicts(d, create_using=None, multigraph_input=False): - """Returns a graph from a dictionary of dictionaries. - - Parameters - ---------- - d : dictionary of dictionaries - A dictionary of dictionaries adjacency representation. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - multigraph_input : bool (default False) - When True, the dict `d` is assumed - to be a dict-of-dict-of-dict-of-dict structure keyed by - node to neighbor to edge keys to edge data for multi-edges. - Otherwise this routine assumes dict-of-dict-of-dict keyed by - node to neighbor to edge data. - - Examples - -------- - >>> dod = {0: {1: {"weight": 1}}} # single edge (0,1) - >>> G = nx.from_dict_of_dicts(dod) - - or - - >>> G = nx.Graph(dod) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_nodes_from(d) - # does dict d represent a MultiGraph or MultiDiGraph? - if multigraph_input: - if G.is_directed(): - if G.is_multigraph(): - G.add_edges_from( - (u, v, key, data) - for u, nbrs in d.items() - for v, datadict in nbrs.items() - for key, data in datadict.items() - ) - else: - G.add_edges_from( - (u, v, data) - for u, nbrs in d.items() - for v, datadict in nbrs.items() - for key, data in datadict.items() - ) - else: # Undirected - if G.is_multigraph(): - seen = set() # don't add both directions of undirected graph - for u, nbrs in d.items(): - for v, datadict in nbrs.items(): - if (u, v) not in seen: - G.add_edges_from( - (u, v, key, data) for key, data in datadict.items() - ) - seen.add((v, u)) - else: - seen = set() # don't add both directions of undirected graph - for u, nbrs in d.items(): - for v, datadict in nbrs.items(): - if (u, v) not in seen: - G.add_edges_from( - (u, v, data) for key, data in datadict.items() - ) - seen.add((v, u)) - - else: # not a multigraph to multigraph transfer - if G.is_multigraph() and not G.is_directed(): - # d can have both representations u-v, v-u in dict. Only add one. - # We don't need this check for digraphs since we add both directions, - # or for Graph() since it is done implicitly (parallel edges not allowed) - seen = set() - for u, nbrs in d.items(): - for v, data in nbrs.items(): - if (u, v) not in seen: - G.add_edge(u, v, key=0) - G[u][v][0].update(data) - seen.add((v, u)) - else: - G.add_edges_from( - ((u, v, data) for u, nbrs in d.items() for v, data in nbrs.items()) - ) - return G - - -@nx._dispatchable(preserve_edge_attrs=True) -def to_edgelist(G, nodelist=None): - """Returns a list of edges in the graph. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - """ - if nodelist is None: - return G.edges(data=True) - return G.edges(nodelist, data=True) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_edgelist(edgelist, create_using=None): - """Returns a graph from a list of edges. - - Parameters - ---------- - edgelist : list or iterator - Edge tuples - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> edgelist = [(0, 1)] # single edge (0,1) - >>> G = nx.from_edgelist(edgelist) - - or - - >>> G = nx.Graph(edgelist) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_edges_from(edgelist) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/convert_matrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/convert_matrix.py deleted file mode 100644 index 8992627..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/convert_matrix.py +++ /dev/null @@ -1,1317 +0,0 @@ -"""Functions to convert NetworkX graphs to and from common data containers -like numpy arrays, scipy sparse arrays, and pandas DataFrames. - -The preferred way of converting data to a NetworkX graph is through the -graph constructor. The constructor calls the `~networkx.convert.to_networkx_graph` -function which attempts to guess the input type and convert it automatically. - -Examples --------- -Create a 10 node random graph from a numpy array - ->>> import numpy as np ->>> rng = np.random.default_rng() ->>> a = rng.integers(low=0, high=2, size=(10, 10)) ->>> DG = nx.from_numpy_array(a, create_using=nx.DiGraph) - -or equivalently: - ->>> DG = nx.DiGraph(a) - -which calls `from_numpy_array` internally based on the type of ``a``. - -See Also --------- -nx_agraph, nx_pydot -""" - -import itertools -from collections import defaultdict - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "from_pandas_adjacency", - "to_pandas_adjacency", - "from_pandas_edgelist", - "to_pandas_edgelist", - "from_scipy_sparse_array", - "to_scipy_sparse_array", - "from_numpy_array", - "to_numpy_array", -] - - -@nx._dispatchable(edge_attrs="weight") -def to_pandas_adjacency( - G, - nodelist=None, - dtype=None, - order=None, - multigraph_weight=sum, - weight="weight", - nonedge=0.0, -): - """Returns the graph adjacency matrix as a Pandas DataFrame. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the Pandas DataFrame. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - multigraph_weight : {sum, min, max}, optional - An operator that determines how weights in multigraphs are handled. - The default is to sum the weights of the multiple edges. - - weight : string or None, optional - The edge attribute that holds the numerical value used for - the edge weight. If an edge does not have that attribute, then the - value 1 is used instead. - - nonedge : float, optional - The matrix values corresponding to nonedges are typically set to zero. - However, this could be undesirable if there are matrix values - corresponding to actual edges that also have the value zero. If so, - one might prefer nonedges to have some other value, such as nan. - - Returns - ------- - df : Pandas DataFrame - Graph adjacency matrix - - Notes - ----- - For directed graphs, entry i,j corresponds to an edge from i to j. - - The DataFrame entries are assigned to the weight edge attribute. When - an edge does not have a weight attribute, the value of the entry is set to - the number 1. For multiple (parallel) edges, the values of the entries - are determined by the 'multigraph_weight' parameter. The default is to - sum the weight attributes for each of the parallel edges. - - When `nodelist` does not contain every node in `G`, the matrix is built - from the subgraph of `G` that is induced by the nodes in `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting Pandas DataFrame can be modified as follows:: - - >>> import pandas as pd - >>> G = nx.Graph([(1, 1), (2, 2)]) - >>> df = nx.to_pandas_adjacency(G) - >>> df - 1 2 - 1 1.0 0.0 - 2 0.0 1.0 - >>> diag_idx = list(range(len(df))) - >>> df.iloc[diag_idx, diag_idx] *= 2 - >>> df - 1 2 - 1 2.0 0.0 - 2 0.0 2.0 - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> nx.to_pandas_adjacency(G, nodelist=[0, 1, 2], dtype=int) - 0 1 2 - 0 0 2 0 - 1 1 0 0 - 2 0 0 4 - - """ - import pandas as pd - - M = to_numpy_array( - G, - nodelist=nodelist, - dtype=dtype, - order=order, - multigraph_weight=multigraph_weight, - weight=weight, - nonedge=nonedge, - ) - if nodelist is None: - nodelist = list(G) - return pd.DataFrame(data=M, index=nodelist, columns=nodelist) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_pandas_adjacency(df, create_using=None): - r"""Returns a graph from Pandas DataFrame. - - The Pandas DataFrame is interpreted as an adjacency matrix for the graph. - - Parameters - ---------- - df : Pandas DataFrame - An adjacency matrix representation of a graph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.DiGraph, - and entry i,j of df corresponds to an edge from i to j. - - If `df` has a single data type for each entry it will be converted to an - appropriate Python data type. - - If you have node attributes stored in a separate dataframe `df_nodes`, - you can load those attributes to the graph `G` using the following code: - - ``` - df_nodes = pd.DataFrame({"node_id": [1, 2, 3], "attribute1": ["A", "B", "C"]}) - G.add_nodes_from((n, dict(d)) for n, d in df_nodes.iterrows()) - ``` - - If `df` has a user-specified compound data type the names - of the data fields will be used as attribute keys in the resulting - NetworkX graph. - - See Also - -------- - to_pandas_adjacency - - Examples - -------- - Simple integer weights on edges: - - >>> import pandas as pd - >>> pd.options.display.max_columns = 20 - >>> df = pd.DataFrame([[1, 1], [2, 1]]) - >>> df - 0 1 - 0 1 1 - 1 2 1 - >>> G = nx.from_pandas_adjacency(df) - >>> G.name = "Graph from pandas adjacency matrix" - >>> print(G) - Graph named 'Graph from pandas adjacency matrix' with 2 nodes and 3 edges - """ - - try: - df = df[df.index] - except Exception as err: - missing = list(set(df.index).difference(set(df.columns))) - msg = f"{missing} not in columns" - raise nx.NetworkXError("Columns must match Indices.", msg) from err - - A = df.values - G = from_numpy_array(A, create_using=create_using, nodelist=df.columns) - - return G - - -@nx._dispatchable(preserve_edge_attrs=True) -def to_pandas_edgelist( - G, - source="source", - target="target", - nodelist=None, - dtype=None, - edge_key=None, -): - """Returns the graph edge list as a Pandas DataFrame. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the Pandas DataFrame. - - source : str or int, optional - A valid column name (string or integer) for the source nodes (for the - directed case). - - target : str or int, optional - A valid column name (string or integer) for the target nodes (for the - directed case). - - nodelist : list, optional - Use only nodes specified in nodelist - - dtype : dtype, default None - Use to create the DataFrame. Data type to force. - Only a single dtype is allowed. If None, infer. - - edge_key : str or int or None, optional (default=None) - A valid column name (string or integer) for the edge keys (for the - multigraph case). If None, edge keys are not stored in the DataFrame. - - Returns - ------- - df : Pandas DataFrame - Graph edge list - - Examples - -------- - >>> G = nx.Graph( - ... [ - ... ("A", "B", {"cost": 1, "weight": 7}), - ... ("C", "E", {"cost": 9, "weight": 10}), - ... ] - ... ) - >>> df = nx.to_pandas_edgelist(G, nodelist=["A", "C"]) - >>> df[["source", "target", "cost", "weight"]] - source target cost weight - 0 A B 1 7 - 1 C E 9 10 - - >>> G = nx.MultiGraph([("A", "B", {"cost": 1}), ("A", "B", {"cost": 9})]) - >>> df = nx.to_pandas_edgelist(G, nodelist=["A", "C"], edge_key="ekey") - >>> df[["source", "target", "cost", "ekey"]] - source target cost ekey - 0 A B 1 0 - 1 A B 9 1 - - """ - import pandas as pd - - if nodelist is None: - edgelist = G.edges(data=True) - else: - edgelist = G.edges(nodelist, data=True) - source_nodes = [s for s, _, _ in edgelist] - target_nodes = [t for _, t, _ in edgelist] - - all_attrs = set().union(*(d.keys() for _, _, d in edgelist)) - if source in all_attrs: - raise nx.NetworkXError(f"Source name {source!r} is an edge attr name") - if target in all_attrs: - raise nx.NetworkXError(f"Target name {target!r} is an edge attr name") - - nan = float("nan") - edge_attr = {k: [d.get(k, nan) for _, _, d in edgelist] for k in all_attrs} - - if G.is_multigraph() and edge_key is not None: - if edge_key in all_attrs: - raise nx.NetworkXError(f"Edge key name {edge_key!r} is an edge attr name") - edge_keys = [k for _, _, k in G.edges(keys=True)] - edgelistdict = {source: source_nodes, target: target_nodes, edge_key: edge_keys} - else: - edgelistdict = {source: source_nodes, target: target_nodes} - - edgelistdict.update(edge_attr) - return pd.DataFrame(edgelistdict, dtype=dtype) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_pandas_edgelist( - df, - source="source", - target="target", - edge_attr=None, - create_using=None, - edge_key=None, -): - """Returns a graph from Pandas DataFrame containing an edge list. - - The Pandas DataFrame should contain at least two columns of node names and - zero or more columns of edge attributes. Each row will be processed as one - edge instance. - - Note: This function iterates over DataFrame.values, which is not - guaranteed to retain the data type across columns in the row. This is only - a problem if your row is entirely numeric and a mix of ints and floats. In - that case, all values will be returned as floats. See the - DataFrame.iterrows documentation for an example. - - Parameters - ---------- - df : Pandas DataFrame - An edge list representation of a graph - - source : str or int - A valid column name (string or integer) for the source nodes (for the - directed case). - - target : str or int - A valid column name (string or integer) for the target nodes (for the - directed case). - - edge_attr : str or int, iterable, True, or None - A valid column name (str or int) or iterable of column names that are - used to retrieve items and add them to the graph as edge attributes. - If `True`, all columns will be added except `source`, `target` and `edge_key`. - If `None`, no edge attributes are added to the graph. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - edge_key : str or None, optional (default=None) - A valid column name for the edge keys (for a MultiGraph). The values in - this column are used for the edge keys when adding edges if create_using - is a multigraph. - - If you have node attributes stored in a separate dataframe `df_nodes`, - you can load those attributes to the graph `G` using the following code: - - ``` - df_nodes = pd.DataFrame({"node_id": [1, 2, 3], "attribute1": ["A", "B", "C"]}) - G.add_nodes_from((n, dict(d)) for n, d in df_nodes.iterrows()) - ``` - - See Also - -------- - to_pandas_edgelist - - Examples - -------- - Simple integer weights on edges: - - >>> import pandas as pd - >>> pd.options.display.max_columns = 20 - >>> import numpy as np - >>> rng = np.random.RandomState(seed=5) - >>> ints = rng.randint(1, 11, size=(3, 2)) - >>> a = ["A", "B", "C"] - >>> b = ["D", "A", "E"] - >>> df = pd.DataFrame(ints, columns=["weight", "cost"]) - >>> df[0] = a - >>> df["b"] = b - >>> df[["weight", "cost", 0, "b"]] - weight cost 0 b - 0 4 7 A D - 1 7 1 B A - 2 10 9 C E - >>> G = nx.from_pandas_edgelist(df, 0, "b", ["weight", "cost"]) - >>> G["E"]["C"]["weight"] - 10 - >>> G["E"]["C"]["cost"] - 9 - >>> edges = pd.DataFrame( - ... { - ... "source": [0, 1, 2], - ... "target": [2, 2, 3], - ... "weight": [3, 4, 5], - ... "color": ["red", "blue", "blue"], - ... } - ... ) - >>> G = nx.from_pandas_edgelist(edges, edge_attr=True) - >>> G[0][2]["color"] - 'red' - - Build multigraph with custom keys: - - >>> edges = pd.DataFrame( - ... { - ... "source": [0, 1, 2, 0], - ... "target": [2, 2, 3, 2], - ... "my_edge_key": ["A", "B", "C", "D"], - ... "weight": [3, 4, 5, 6], - ... "color": ["red", "blue", "blue", "blue"], - ... } - ... ) - >>> G = nx.from_pandas_edgelist( - ... edges, - ... edge_key="my_edge_key", - ... edge_attr=["weight", "color"], - ... create_using=nx.MultiGraph(), - ... ) - >>> G[0][2] - AtlasView({'A': {'weight': 3, 'color': 'red'}, 'D': {'weight': 6, 'color': 'blue'}}) - - - """ - g = nx.empty_graph(0, create_using) - - if edge_attr is None: - if g.is_multigraph() and edge_key is not None: - for u, v, k in zip(df[source], df[target], df[edge_key]): - g.add_edge(u, v, k) - else: - g.add_edges_from(zip(df[source], df[target])) - return g - - reserved_columns = [source, target] - if g.is_multigraph() and edge_key is not None: - reserved_columns.append(edge_key) - - # Additional columns requested - attr_col_headings = [] - attribute_data = [] - if edge_attr is True: - attr_col_headings = [c for c in df.columns if c not in reserved_columns] - elif isinstance(edge_attr, list | tuple): - attr_col_headings = edge_attr - else: - attr_col_headings = [edge_attr] - if len(attr_col_headings) == 0: - raise nx.NetworkXError( - f"Invalid edge_attr argument: No columns found with name: {attr_col_headings}" - ) - - try: - attribute_data = zip(*[df[col] for col in attr_col_headings]) - except (KeyError, TypeError) as err: - msg = f"Invalid edge_attr argument: {edge_attr}" - raise nx.NetworkXError(msg) from err - - if g.is_multigraph(): - # => append the edge keys from the df to the bundled data - if edge_key is not None: - try: - multigraph_edge_keys = df[edge_key] - attribute_data = zip(attribute_data, multigraph_edge_keys) - except (KeyError, TypeError) as err: - msg = f"Invalid edge_key argument: {edge_key}" - raise nx.NetworkXError(msg) from err - - for s, t, attrs in zip(df[source], df[target], attribute_data): - if edge_key is not None: - attrs, multigraph_edge_key = attrs - key = g.add_edge(s, t, key=multigraph_edge_key) - else: - key = g.add_edge(s, t) - - g[s][t][key].update(zip(attr_col_headings, attrs)) - else: - for s, t, attrs in zip(df[source], df[target], attribute_data): - g.add_edge(s, t) - g[s][t].update(zip(attr_col_headings, attrs)) - - return g - - -@nx._dispatchable(edge_attrs="weight") -def to_scipy_sparse_array(G, nodelist=None, dtype=None, weight="weight", format="csr"): - """Returns the graph adjacency matrix as a SciPy sparse array. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the sparse array. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by ``G.nodes()``. - - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. If None, then the - NumPy default is used. - - weight : string or None, optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - format : str in {'bsr', 'csr', 'csc', 'coo', 'lil', 'dia', 'dok'} - The format of the sparse array to be returned (default 'csr'). For - some algorithms different implementations of sparse arrays - can perform better. See [1]_ for details. - - Returns - ------- - A : SciPy sparse array - Graph adjacency matrix. - - Notes - ----- - For directed graphs, matrix entry ``i, j`` corresponds to an edge from - ``i`` to ``j``. - - The values of the adjacency matrix are populated using the edge attribute held in - parameter `weight`. When an edge does not have that attribute, the - value of the entry is 1. - - For multiple edges the matrix values are the sums of the edge weights. - - When `nodelist` does not contain every node in `G`, the adjacency matrix - is built from the subgraph of `G` that is induced by the nodes in - `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting array can be modified as follows:: - - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.to_scipy_sparse_array(G) - >>> A.toarray() - array([[1]]) - >>> A.setdiag(A.diagonal() * 2) - >>> A.toarray() - array([[2]]) - - Examples - -------- - - Basic usage: - - >>> G = nx.path_graph(4) - >>> A = nx.to_scipy_sparse_array(G) - >>> A # doctest: +SKIP - - - >>> A.toarray() - array([[0, 1, 0, 0], - [1, 0, 1, 0], - [0, 1, 0, 1], - [0, 0, 1, 0]]) - - .. note:: The `toarray` method is used in these examples to better visualize - the adjacancy matrix. For a dense representation of the adjaceny matrix, - use `to_numpy_array` instead. - - Directed graphs: - - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - >>> nx.to_scipy_sparse_array(G).toarray() - array([[0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1], - [0, 0, 0, 0]]) - - >>> H = G.reverse() - >>> H.edges - OutEdgeView([(1, 0), (2, 1), (3, 2)]) - >>> nx.to_scipy_sparse_array(H).toarray() - array([[0, 0, 0, 0], - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0]]) - - By default, the order of the rows/columns of the adjacency matrix is determined - by the ordering of the nodes in `G`: - - >>> G = nx.Graph() - >>> G.add_nodes_from([3, 5, 0, 1]) - >>> G.add_edges_from([(1, 3), (1, 5)]) - >>> nx.to_scipy_sparse_array(G).toarray() - array([[0, 0, 0, 1], - [0, 0, 0, 1], - [0, 0, 0, 0], - [1, 1, 0, 0]]) - - The ordering of the rows can be changed with `nodelist`: - - >>> ordered = [0, 1, 3, 5] - >>> nx.to_scipy_sparse_array(G, nodelist=ordered).toarray() - array([[0, 0, 0, 0], - [0, 0, 1, 1], - [0, 1, 0, 0], - [0, 1, 0, 0]]) - - If `nodelist` contains a subset of the nodes in `G`, the adjacency matrix - for the node-induced subgraph is produced: - - >>> nx.to_scipy_sparse_array(G, nodelist=[1, 3, 5]).toarray() - array([[0, 1, 1], - [1, 0, 0], - [1, 0, 0]]) - - The values of the adjacency matrix are drawn from the edge attribute - specified by the `weight` parameter: - - >>> G = nx.path_graph(4) - >>> nx.set_edge_attributes( - ... G, values={(0, 1): 1, (1, 2): 10, (2, 3): 2}, name="weight" - ... ) - >>> nx.set_edge_attributes( - ... G, values={(0, 1): 50, (1, 2): 35, (2, 3): 10}, name="capacity" - ... ) - >>> nx.to_scipy_sparse_array(G).toarray() # Default weight="weight" - array([[ 0, 1, 0, 0], - [ 1, 0, 10, 0], - [ 0, 10, 0, 2], - [ 0, 0, 2, 0]]) - >>> nx.to_scipy_sparse_array(G, weight="capacity").toarray() - array([[ 0, 50, 0, 0], - [50, 0, 35, 0], - [ 0, 35, 0, 10], - [ 0, 0, 10, 0]]) - - Any edges that don't have a `weight` attribute default to 1: - - >>> G[1][2].pop("capacity") - 35 - >>> nx.to_scipy_sparse_array(G, weight="capacity").toarray() - array([[ 0, 50, 0, 0], - [50, 0, 1, 0], - [ 0, 1, 0, 10], - [ 0, 0, 10, 0]]) - - When `G` is a multigraph, the values in the adjacency matrix are given by - the sum of the `weight` edge attribute over each edge key: - - >>> G = nx.MultiDiGraph([(0, 1), (0, 1), (0, 1), (2, 0)]) - >>> nx.to_scipy_sparse_array(G).toarray() - array([[0, 3, 0], - [0, 0, 0], - [1, 0, 0]]) - - References - ---------- - .. [1] Scipy Dev. References, "Sparse Arrays", - https://docs.scipy.org/doc/scipy/reference/sparse.html - """ - import scipy as sp - - if len(G) == 0: - raise nx.NetworkXError("Graph has no nodes or edges") - - if nodelist is None: - nodelist = list(G) - nlen = len(G) - else: - nlen = len(nodelist) - if nlen == 0: - raise nx.NetworkXError("nodelist has no nodes") - nodeset = set(G.nbunch_iter(nodelist)) - if nlen != len(nodeset): - for n in nodelist: - if n not in G: - raise nx.NetworkXError(f"Node {n} in nodelist is not in G") - raise nx.NetworkXError("nodelist contains duplicates.") - if nlen < len(G): - G = G.subgraph(nodelist) - - index = dict(zip(nodelist, range(nlen))) - coefficients = zip( - *((index[u], index[v], wt) for u, v, wt in G.edges(data=weight, default=1)) - ) - try: - row, col, data = coefficients - except ValueError: - # there is no edge in the subgraph - row, col, data = [], [], [] - - if G.is_directed(): - A = sp.sparse.coo_array((data, (row, col)), shape=(nlen, nlen), dtype=dtype) - else: - # symmetrize matrix - d = data + data - r = row + col - c = col + row - # selfloop entries get double counted when symmetrizing - # so we subtract the data on the diagonal - selfloops = list(nx.selfloop_edges(G, data=weight, default=1)) - if selfloops: - diag_index, diag_data = zip(*((index[u], -wt) for u, v, wt in selfloops)) - d += diag_data - r += diag_index - c += diag_index - A = sp.sparse.coo_array((d, (r, c)), shape=(nlen, nlen), dtype=dtype) - try: - return A.asformat(format) - except ValueError as err: - raise nx.NetworkXError(f"Unknown sparse matrix format: {format}") from err - - -def _csr_gen_triples(A): - """Converts a SciPy sparse array in **Compressed Sparse Row** format to - an iterable of weighted edge triples. - - """ - nrows = A.shape[0] - indptr, dst_indices, data = A.indptr, A.indices, A.data - import numpy as np - - src_indices = np.repeat(np.arange(nrows), np.diff(indptr)) - return zip(src_indices.tolist(), dst_indices.tolist(), A.data.tolist()) - - -def _csc_gen_triples(A): - """Converts a SciPy sparse array in **Compressed Sparse Column** format to - an iterable of weighted edge triples. - - """ - ncols = A.shape[1] - indptr, src_indices, data = A.indptr, A.indices, A.data - import numpy as np - - dst_indices = np.repeat(np.arange(ncols), np.diff(indptr)) - return zip(src_indices.tolist(), dst_indices.tolist(), A.data.tolist()) - - -def _coo_gen_triples(A): - """Converts a SciPy sparse array in **Coordinate** format to an iterable - of weighted edge triples. - - """ - return zip(A.row.tolist(), A.col.tolist(), A.data.tolist()) - - -def _dok_gen_triples(A): - """Converts a SciPy sparse array in **Dictionary of Keys** format to an - iterable of weighted edge triples. - - """ - for (r, c), v in A.items(): - # Use `v.item()` to convert a NumPy scalar to the appropriate Python scalar - yield int(r), int(c), v.item() - - -def _generate_weighted_edges(A): - """Returns an iterable over (u, v, w) triples, where u and v are adjacent - vertices and w is the weight of the edge joining u and v. - - `A` is a SciPy sparse array (in any format). - - """ - if A.format == "csr": - return _csr_gen_triples(A) - if A.format == "csc": - return _csc_gen_triples(A) - if A.format == "dok": - return _dok_gen_triples(A) - # If A is in any other format (including COO), convert it to COO format. - return _coo_gen_triples(A.tocoo()) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_scipy_sparse_array( - A, parallel_edges=False, create_using=None, edge_attribute="weight" -): - """Creates a new graph from an adjacency matrix given as a SciPy sparse - array. - - Parameters - ---------- - A: scipy.sparse array - An adjacency matrix representation of a graph - - parallel_edges : Boolean - If this is True, `create_using` is a multigraph, and `A` is an - integer matrix, then entry *(i, j)* in the matrix is interpreted as the - number of parallel edges joining vertices *i* and *j* in the graph. - If it is False, then the entries in the matrix are interpreted as - the weight of a single edge joining the vertices. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - edge_attribute: string - Name of edge attribute to store matrix numeric value. The data will - have the same type as the matrix entry (int, float, (real,imag)). - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.DiGraph, - and entry i,j of A corresponds to an edge from i to j. - - If `create_using` is :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the - entries of `A` are of type :class:`int`, then this function returns a - multigraph (constructed from `create_using`) with parallel edges. - In this case, `edge_attribute` will be ignored. - - If `create_using` indicates an undirected multigraph, then only the edges - indicated by the upper triangle of the matrix `A` will be added to the - graph. - - Examples - -------- - >>> import scipy as sp - >>> A = sp.sparse.eye(2, 2, 1) - >>> G = nx.from_scipy_sparse_array(A) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is False, then the entries will be treated - as weights for edges joining the nodes (without creating parallel edges): - - >>> A = sp.sparse.csr_array([[1, 1], [1, 2]]) - >>> G = nx.from_scipy_sparse_array(A, create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 2}}) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is True, then the entries will be treated - as the number of parallel edges joining those two vertices: - - >>> A = sp.sparse.csr_array([[1, 1], [1, 2]]) - >>> G = nx.from_scipy_sparse_array( - ... A, parallel_edges=True, create_using=nx.MultiGraph - ... ) - >>> G[1][1] - AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) - - """ - G = nx.empty_graph(0, create_using) - n, m = A.shape - if n != m: - raise nx.NetworkXError(f"Adjacency matrix not square: nx,ny={A.shape}") - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(range(n)) - # Create an iterable over (u, v, w) triples and for each triple, add an - # edge from u to v with weight w. - triples = _generate_weighted_edges(A) - # If the entries in the adjacency matrix are integers, the graph is a - # multigraph, and parallel_edges is True, then create parallel edges, each - # with weight 1, for each entry in the adjacency matrix. Otherwise, create - # one edge for each positive entry in the adjacency matrix and set the - # weight of that edge to be the entry in the matrix. - if A.dtype.kind in ("i", "u") and G.is_multigraph() and parallel_edges: - chain = itertools.chain.from_iterable - # The following line is equivalent to: - # - # for (u, v) in edges: - # for d in range(A[u, v]): - # G.add_edge(u, v, weight=1) - # - triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) - # If we are creating an undirected multigraph, only add the edges from the - # upper triangle of the matrix. Otherwise, add all the edges. This relies - # on the fact that the vertices created in the - # `_generated_weighted_edges()` function are actually the row/column - # indices for the matrix `A`. - # - # Without this check, we run into a problem where each edge is added twice - # when `G.add_weighted_edges_from()` is invoked below. - if G.is_multigraph() and not G.is_directed(): - triples = ((u, v, d) for u, v, d in triples if u <= v) - G.add_weighted_edges_from(triples, weight=edge_attribute) - return G - - -@nx._dispatchable(edge_attrs="weight") # edge attrs may also be obtained from `dtype` -def to_numpy_array( - G, - nodelist=None, - dtype=None, - order=None, - multigraph_weight=sum, - weight="weight", - nonedge=0.0, -): - """Returns the graph adjacency matrix as a NumPy array. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy array. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is ``None``, then the ordering is produced by ``G.nodes()``. - - dtype : NumPy data type, optional - A NumPy data type used to initialize the array. If None, then the NumPy - default is used. The dtype can be structured if `weight=None`, in which - case the dtype field names are used to look up edge attributes. The - result is a structured array where each named field in the dtype - corresponds to the adjacency for that edge attribute. See examples for - details. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. If None, then the NumPy default - is used. - - multigraph_weight : callable, optional - An function that determines how weights in multigraphs are handled. - The function should accept a sequence of weights and return a single - value. The default is to sum the weights of the multiple edges. - - weight : string or None optional (default = 'weight') - The edge attribute that holds the numerical value used for - the edge weight. If an edge does not have that attribute, then the - value 1 is used instead. `weight` must be ``None`` if a structured - dtype is used. - - nonedge : array_like (default = 0.0) - The value used to represent non-edges in the adjacency matrix. - The array values corresponding to nonedges are typically set to zero. - However, this could be undesirable if there are array values - corresponding to actual edges that also have the value zero. If so, - one might prefer nonedges to have some other value, such as ``nan``. - - Returns - ------- - A : NumPy ndarray - Graph adjacency matrix - - Raises - ------ - NetworkXError - If `dtype` is a structured dtype and `G` is a multigraph - ValueError - If `dtype` is a structured dtype and `weight` is not `None` - - See Also - -------- - from_numpy_array - - Notes - ----- - For directed graphs, entry ``i, j`` corresponds to an edge from ``i`` to ``j``. - - Entries in the adjacency matrix are given by the `weight` edge attribute. - When an edge does not have a weight attribute, the value of the entry is - set to the number 1. For multiple (parallel) edges, the values of the - entries are determined by the `multigraph_weight` parameter. The default is - to sum the weight attributes for each of the parallel edges. - - When `nodelist` does not contain every node in `G`, the adjacency matrix is - built from the subgraph of `G` that is induced by the nodes in `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal array entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting NumPy array can be modified as follows: - - >>> import numpy as np - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.to_numpy_array(G) - >>> A - array([[1.]]) - >>> A[np.diag_indices_from(A)] *= 2 - >>> A - array([[2.]]) - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> nx.to_numpy_array(G, nodelist=[0, 1, 2]) - array([[0., 2., 0.], - [1., 0., 0.], - [0., 0., 4.]]) - - When `nodelist` argument is used, nodes of `G` which do not appear in the `nodelist` - and their edges are not included in the adjacency matrix. Here is an example: - - >>> G = nx.Graph() - >>> G.add_edge(3, 1) - >>> G.add_edge(2, 0) - >>> G.add_edge(2, 1) - >>> G.add_edge(3, 0) - >>> nx.to_numpy_array(G, nodelist=[1, 2, 3]) - array([[0., 1., 1.], - [1., 0., 0.], - [1., 0., 0.]]) - - This function can also be used to create adjacency matrices for multiple - edge attributes with structured dtypes: - - >>> G = nx.Graph() - >>> G.add_edge(0, 1, weight=10) - >>> G.add_edge(1, 2, cost=5) - >>> G.add_edge(2, 3, weight=3, cost=-4.0) - >>> dtype = np.dtype([("weight", int), ("cost", float)]) - >>> A = nx.to_numpy_array(G, dtype=dtype, weight=None) - >>> A["weight"] - array([[ 0, 10, 0, 0], - [10, 0, 1, 0], - [ 0, 1, 0, 3], - [ 0, 0, 3, 0]]) - >>> A["cost"] - array([[ 0., 1., 0., 0.], - [ 1., 0., 5., 0.], - [ 0., 5., 0., -4.], - [ 0., 0., -4., 0.]]) - - As stated above, the argument "nonedge" is useful especially when there are - actually edges with weight 0 in the graph. Setting a nonedge value different than 0, - makes it much clearer to differentiate such 0-weighted edges and actual nonedge values. - - >>> G = nx.Graph() - >>> G.add_edge(3, 1, weight=2) - >>> G.add_edge(2, 0, weight=0) - >>> G.add_edge(2, 1, weight=0) - >>> G.add_edge(3, 0, weight=1) - >>> nx.to_numpy_array(G, nonedge=-1.0) - array([[-1., 2., -1., 1.], - [ 2., -1., 0., -1.], - [-1., 0., -1., 0.], - [ 1., -1., 0., -1.]]) - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - nlen = len(nodelist) - - # Input validation - nodeset = set(nodelist) - if nodeset - set(G): - raise nx.NetworkXError(f"Nodes {nodeset - set(G)} in nodelist is not in G") - if len(nodeset) < nlen: - raise nx.NetworkXError("nodelist contains duplicates.") - - A = np.full((nlen, nlen), fill_value=nonedge, dtype=dtype, order=order) - - # Corner cases: empty nodelist or graph without any edges - if nlen == 0 or G.number_of_edges() == 0: - return A - - # If dtype is structured and weight is None, use dtype field names as - # edge attributes - edge_attrs = None # Only single edge attribute by default - if A.dtype.names: - if weight is None: - edge_attrs = dtype.names - else: - raise ValueError( - "Specifying `weight` not supported for structured dtypes\n." - "To create adjacency matrices from structured dtypes, use `weight=None`." - ) - - # Map nodes to row/col in matrix - idx = dict(zip(nodelist, range(nlen))) - if len(nodelist) < len(G): - G = G.subgraph(nodelist).copy() - - # Collect all edge weights and reduce with `multigraph_weights` - if G.is_multigraph(): - if edge_attrs: - raise nx.NetworkXError( - "Structured arrays are not supported for MultiGraphs" - ) - d = defaultdict(list) - for u, v, wt in G.edges(data=weight, default=1.0): - d[(idx[u], idx[v])].append(wt) - i, j = np.array(list(d.keys())).T # indices - wts = [multigraph_weight(ws) for ws in d.values()] # reduced weights - else: - i, j, wts = [], [], [] - - # Special branch: multi-attr adjacency from structured dtypes - if edge_attrs: - # Extract edges with all data - for u, v, data in G.edges(data=True): - i.append(idx[u]) - j.append(idx[v]) - wts.append(data) - # Map each attribute to the appropriate named field in the - # structured dtype - for attr in edge_attrs: - attr_data = [wt.get(attr, 1.0) for wt in wts] - A[attr][i, j] = attr_data - if not G.is_directed(): - A[attr][j, i] = attr_data - return A - - for u, v, wt in G.edges(data=weight, default=1.0): - i.append(idx[u]) - j.append(idx[v]) - wts.append(wt) - - # Set array values with advanced indexing - A[i, j] = wts - if not G.is_directed(): - A[j, i] = wts - - return A - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_numpy_array( - A, parallel_edges=False, create_using=None, edge_attr="weight", *, nodelist=None -): - """Returns a graph from a 2D NumPy array. - - The 2D NumPy array is interpreted as an adjacency matrix for the graph. - - Parameters - ---------- - A : a 2D numpy.ndarray - An adjacency matrix representation of a graph - - parallel_edges : Boolean - If this is True, `create_using` is a multigraph, and `A` is an - integer array, then entry *(i, j)* in the array is interpreted as the - number of parallel edges joining vertices *i* and *j* in the graph. - If it is False, then the entries in the array are interpreted as - the weight of a single edge joining the vertices. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - edge_attr : String, optional (default="weight") - The attribute to which the array values are assigned on each edge. If - it is None, edge attributes will not be assigned. - - nodelist : sequence of nodes, optional - A sequence of objects to use as the nodes in the graph. If provided, the - list of nodes must be the same length as the dimensions of `A`. The - default is `None`, in which case the nodes are drawn from ``range(n)``. - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.DiGraph, - and entry i,j of A corresponds to an edge from i to j. - - If `create_using` is :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the - entries of `A` are of type :class:`int`, then this function returns a - multigraph (of the same type as `create_using`) with parallel edges. - - If `create_using` indicates an undirected multigraph, then only the edges - indicated by the upper triangle of the array `A` will be added to the - graph. - - If `edge_attr` is Falsy (False or None), edge attributes will not be - assigned, and the array data will be treated like a binary mask of - edge presence or absence. Otherwise, the attributes will be assigned - as follows: - - If the NumPy array has a single data type for each array entry it - will be converted to an appropriate Python data type. - - If the NumPy array has a user-specified compound data type the names - of the data fields will be used as attribute keys in the resulting - NetworkX graph. - - See Also - -------- - to_numpy_array - - Examples - -------- - Simple integer weights on edges: - - >>> import numpy as np - >>> A = np.array([[1, 1], [2, 1]]) - >>> G = nx.from_numpy_array(A) - >>> G.edges(data=True) - EdgeDataView([(0, 0, {'weight': 1}), (0, 1, {'weight': 2}), (1, 1, {'weight': 1})]) - - If `create_using` indicates a multigraph and the array has only integer - entries and `parallel_edges` is False, then the entries will be treated - as weights for edges joining the nodes (without creating parallel edges): - - >>> A = np.array([[1, 1], [1, 2]]) - >>> G = nx.from_numpy_array(A, create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 2}}) - - If `create_using` indicates a multigraph and the array has only integer - entries and `parallel_edges` is True, then the entries will be treated - as the number of parallel edges joining those two vertices: - - >>> A = np.array([[1, 1], [1, 2]]) - >>> temp = nx.MultiGraph() - >>> G = nx.from_numpy_array(A, parallel_edges=True, create_using=temp) - >>> G[1][1] - AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) - - User defined compound data type on edges: - - >>> dt = [("weight", float), ("cost", int)] - >>> A = np.array([[(1.0, 2)]], dtype=dt) - >>> G = nx.from_numpy_array(A) - >>> G.edges() - EdgeView([(0, 0)]) - >>> G[0][0]["cost"] - 2 - >>> G[0][0]["weight"] - 1.0 - - """ - kind_to_python_type = { - "f": float, - "i": int, - "u": int, - "b": bool, - "c": complex, - "S": str, - "U": str, - "V": "void", - } - G = nx.empty_graph(0, create_using) - if A.ndim != 2: - raise nx.NetworkXError(f"Input array must be 2D, not {A.ndim}") - n, m = A.shape - if n != m: - raise nx.NetworkXError(f"Adjacency matrix not square: nx,ny={A.shape}") - dt = A.dtype - try: - python_type = kind_to_python_type[dt.kind] - except Exception as err: - raise TypeError(f"Unknown numpy data type: {dt}") from err - if _default_nodes := (nodelist is None): - nodelist = range(n) - else: - if len(nodelist) != n: - raise ValueError("nodelist must have the same length as A.shape[0]") - - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(nodelist) - # Get a list of all the entries in the array with nonzero entries. These - # coordinates become edges in the graph. (convert to int from np.int64) - edges = ((int(e[0]), int(e[1])) for e in zip(*A.nonzero())) - # handle numpy constructed data type - if python_type == "void": - # Sort the fields by their offset, then by dtype, then by name. - fields = sorted( - (offset, dtype, name) for name, (dtype, offset) in A.dtype.fields.items() - ) - triples = ( - ( - u, - v, - {} - if edge_attr in [False, None] - else { - name: kind_to_python_type[dtype.kind](val) - for (_, dtype, name), val in zip(fields, A[u, v]) - }, - ) - for u, v in edges - ) - # If the entries in the adjacency matrix are integers, the graph is a - # multigraph, and parallel_edges is True, then create parallel edges, each - # with weight 1, for each entry in the adjacency matrix. Otherwise, create - # one edge for each positive entry in the adjacency matrix and set the - # weight of that edge to be the entry in the matrix. - elif python_type is int and G.is_multigraph() and parallel_edges: - chain = itertools.chain.from_iterable - # The following line is equivalent to: - # - # for (u, v) in edges: - # for d in range(A[u, v]): - # G.add_edge(u, v, weight=1) - # - if edge_attr in [False, None]: - triples = chain(((u, v, {}) for d in range(A[u, v])) for (u, v) in edges) - else: - triples = chain( - ((u, v, {edge_attr: 1}) for d in range(A[u, v])) for (u, v) in edges - ) - else: # basic data type - if edge_attr in [False, None]: - triples = ((u, v, {}) for u, v in edges) - else: - triples = ((u, v, {edge_attr: python_type(A[u, v])}) for u, v in edges) - # If we are creating an undirected multigraph, only add the edges from the - # upper triangle of the matrix. Otherwise, add all the edges. This relies - # on the fact that the vertices created in the - # `_generated_weighted_edges()` function are actually the row/column - # indices for the matrix `A`. - # - # Without this check, we run into a problem where each edge is added twice - # when `G.add_edges_from()` is invoked below. - if G.is_multigraph() and not G.is_directed(): - triples = ((u, v, d) for u, v, d in triples if u <= v) - # Remap nodes if user provided custom `nodelist` - if not _default_nodes: - idx_to_node = dict(enumerate(nodelist)) - triples = ((idx_to_node[u], idx_to_node[v], d) for u, v, d in triples) - G.add_edges_from(triples) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/__init__.py deleted file mode 100644 index 0f53309..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# graph drawing and interface to graphviz - -from .layout import * -from .nx_latex import * -from .nx_pylab import * -from . import nx_agraph -from . import nx_pydot diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/layout.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/layout.py deleted file mode 100644 index 20d34a1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/layout.py +++ /dev/null @@ -1,1630 +0,0 @@ -""" -****** -Layout -****** - -Node positioning algorithms for graph drawing. - -For `random_layout()` the possible resulting shape -is a square of side [0, scale] (default: [0, 1]) -Changing `center` shifts the layout by that amount. - -For the other layout routines, the extent is -[center - scale, center + scale] (default: [-1, 1]). - -Warning: Most layout routines have only been tested in 2-dimensions. - -""" - -import networkx as nx -from networkx.utils import np_random_state - -__all__ = [ - "bipartite_layout", - "circular_layout", - "forceatlas2_layout", - "kamada_kawai_layout", - "random_layout", - "rescale_layout", - "rescale_layout_dict", - "shell_layout", - "spring_layout", - "spectral_layout", - "planar_layout", - "fruchterman_reingold_layout", - "spiral_layout", - "multipartite_layout", - "bfs_layout", - "arf_layout", -] - - -def _process_params(G, center, dim): - # Some boilerplate code. - import numpy as np - - if not isinstance(G, nx.Graph): - empty_graph = nx.Graph() - empty_graph.add_nodes_from(G) - G = empty_graph - - if center is None: - center = np.zeros(dim) - else: - center = np.asarray(center) - - if len(center) != dim: - msg = "length of center coordinates must match dimension of layout" - raise ValueError(msg) - - return G, center - - -@np_random_state(3) -def random_layout(G, center=None, dim=2, seed=None): - """Position nodes uniformly at random in the unit square. - - For every node, a position is generated by choosing each of dim - coordinates uniformly at random on the interval [0.0, 1.0). - - NumPy (http://scipy.org) is required for this function. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - seed : int, RandomState instance or None optional (default=None) - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> pos = nx.random_layout(G) - - """ - import numpy as np - - G, center = _process_params(G, center, dim) - pos = seed.rand(len(G), dim) + center - pos = pos.astype(np.float32) - pos = dict(zip(G, pos)) - - return pos - - -def circular_layout(G, scale=1, center=None, dim=2): - # dim=2 only - """Position nodes on a circle. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - If dim>2, the remaining dimensions are set to zero - in the returned positions. - If dim<2, a ValueError is raised. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------ - ValueError - If dim < 2 - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.circular_layout(G) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - import numpy as np - - if dim < 2: - raise ValueError("cannot handle dimensions < 2") - - G, center = _process_params(G, center, dim) - - paddims = max(0, (dim - 2)) - - if len(G) == 0: - pos = {} - elif len(G) == 1: - pos = {nx.utils.arbitrary_element(G): center} - else: - # Discard the extra angle since it matches 0 radians. - theta = np.linspace(0, 1, len(G) + 1)[:-1] * 2 * np.pi - theta = theta.astype(np.float32) - pos = np.column_stack( - [np.cos(theta), np.sin(theta), np.zeros((len(G), paddims))] - ) - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - - return pos - - -def shell_layout(G, nlist=None, rotate=None, scale=1, center=None, dim=2): - """Position nodes in concentric circles. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - nlist : list of lists - List of node lists for each shell. - - rotate : angle in radians (default=pi/len(nlist)) - Angle by which to rotate the starting position of each shell - relative to the starting position of the previous shell. - To recreate behavior before v2.5 use rotate=0. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout, currently only dim=2 is supported. - Other dimension values result in a ValueError. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------ - ValueError - If dim != 2 - - Examples - -------- - >>> G = nx.path_graph(4) - >>> shells = [[0], [1, 2, 3]] - >>> pos = nx.shell_layout(G, shells) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - import numpy as np - - if dim != 2: - raise ValueError("can only handle 2 dimensions") - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G): center} - - if nlist is None: - # draw the whole graph in one shell - nlist = [list(G)] - - radius_bump = scale / len(nlist) - - if len(nlist[0]) == 1: - # single node at center - radius = 0.0 - else: - # else start at r=1 - radius = radius_bump - - if rotate is None: - rotate = np.pi / len(nlist) - first_theta = rotate - npos = {} - for nodes in nlist: - # Discard the last angle (endpoint=False) since 2*pi matches 0 radians - theta = ( - np.linspace(0, 2 * np.pi, len(nodes), endpoint=False, dtype=np.float32) - + first_theta - ) - pos = radius * np.column_stack([np.cos(theta), np.sin(theta)]) + center - npos.update(zip(nodes, pos)) - radius += radius_bump - first_theta += rotate - - return npos - - -def bipartite_layout( - G, nodes, align="vertical", scale=1, center=None, aspect_ratio=4 / 3 -): - """Position nodes in two straight lines. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - nodes : list or container - Nodes in one node set of the bipartite graph. - This set will be placed on left or top. - - align : string (default='vertical') - The alignment of nodes. Vertical or horizontal. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - aspect_ratio : number (default=4/3): - The ratio of the width to the height of the layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.bipartite.gnmk_random_graph(3, 5, 10, seed=123) - >>> top = nx.bipartite.sets(G)[0] - >>> pos = nx.bipartite_layout(G, top) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - - import numpy as np - - if align not in ("vertical", "horizontal"): - msg = "align must be either vertical or horizontal." - raise ValueError(msg) - - G, center = _process_params(G, center=center, dim=2) - if len(G) == 0: - return {} - - height = 1 - width = aspect_ratio * height - offset = (width / 2, height / 2) - - top = dict.fromkeys(nodes) - bottom = [v for v in G if v not in top] - nodes = list(top) + bottom - - left_xs = np.repeat(0, len(top)) - right_xs = np.repeat(width, len(bottom)) - left_ys = np.linspace(0, height, len(top)) - right_ys = np.linspace(0, height, len(bottom)) - - top_pos = np.column_stack([left_xs, left_ys]) - offset - bottom_pos = np.column_stack([right_xs, right_ys]) - offset - - pos = np.concatenate([top_pos, bottom_pos]) - pos = rescale_layout(pos, scale=scale) + center - if align == "horizontal": - pos = pos[:, ::-1] # swap x and y coords - pos = dict(zip(nodes, pos)) - return pos - - -@np_random_state(10) -def spring_layout( - G, - k=None, - pos=None, - fixed=None, - iterations=50, - threshold=1e-4, - weight="weight", - scale=1, - center=None, - dim=2, - seed=None, -): - """Position nodes using Fruchterman-Reingold force-directed algorithm. - - The algorithm simulates a force-directed representation of the network - treating edges as springs holding nodes close, while treating nodes - as repelling objects, sometimes called an anti-gravity force. - Simulation continues until the positions are close to an equilibrium. - - There are some hard-coded values: minimal distance between - nodes (0.01) and "temperature" of 0.1 to ensure nodes don't fly away. - During the simulation, `k` helps determine the distance between nodes, - though `scale` and `center` determine the size and place after - rescaling occurs at the end of the simulation. - - Fixing some nodes doesn't allow them to move in the simulation. - It also turns off the rescaling feature at the simulation's end. - In addition, setting `scale` to `None` turns off rescaling. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - k : float (default=None) - Optimal distance between nodes. If None the distance is set to - 1/sqrt(n) where n is the number of nodes. Increase this value - to move nodes farther apart. - - pos : dict or None optional (default=None) - Initial positions for nodes as a dictionary with node as keys - and values as a coordinate list or tuple. If None, then use - random initial positions. - - fixed : list or None optional (default=None) - Nodes to keep fixed at initial position. - Nodes not in ``G.nodes`` are ignored. - ValueError raised if `fixed` specified and `pos` not. - - iterations : int optional (default=50) - Maximum number of iterations taken - - threshold: float optional (default = 1e-4) - Threshold for relative error in node position changes. - The iteration stops if the error is below this threshold. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. Larger means a stronger attractive force. - If None, then all edge weights are 1. - - scale : number or None (default: 1) - Scale factor for positions. Not used unless `fixed is None`. - If scale is None, no rescaling is performed. - - center : array-like or None - Coordinate pair around which to center the layout. - Not used unless `fixed is None`. - - dim : int - Dimension of layout. - - seed : int, RandomState instance or None optional (default=None) - Used only for the initial positions in the algorithm. - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spring_layout(G) - - # The same using longer but equivalent function name - >>> pos = nx.fruchterman_reingold_layout(G) - """ - import numpy as np - - G, center = _process_params(G, center, dim) - - if fixed is not None: - if pos is None: - raise ValueError("nodes are fixed without positions given") - for node in fixed: - if node not in pos: - raise ValueError("nodes are fixed without positions given") - nfixed = {node: i for i, node in enumerate(G)} - fixed = np.asarray([nfixed[node] for node in fixed if node in nfixed]) - - if pos is not None: - # Determine size of existing domain to adjust initial positions - dom_size = max(coord for pos_tup in pos.values() for coord in pos_tup) - if dom_size == 0: - dom_size = 1 - pos_arr = seed.rand(len(G), dim) * dom_size + center - - for i, n in enumerate(G): - if n in pos: - pos_arr[i] = np.asarray(pos[n]) - else: - pos_arr = None - dom_size = 1 - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G.nodes()): center} - - try: - # Sparse matrix - if len(G) < 500: # sparse solver for large graphs - raise ValueError - A = nx.to_scipy_sparse_array(G, weight=weight, dtype="f") - if k is None and fixed is not None: - # We must adjust k by domain size for layouts not near 1x1 - nnodes, _ = A.shape - k = dom_size / np.sqrt(nnodes) - pos = _sparse_fruchterman_reingold( - A, k, pos_arr, fixed, iterations, threshold, dim, seed - ) - except ValueError: - A = nx.to_numpy_array(G, weight=weight) - if k is None and fixed is not None: - # We must adjust k by domain size for layouts not near 1x1 - nnodes, _ = A.shape - k = dom_size / np.sqrt(nnodes) - pos = _fruchterman_reingold( - A, k, pos_arr, fixed, iterations, threshold, dim, seed - ) - if fixed is None and scale is not None: - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - return pos - - -fruchterman_reingold_layout = spring_layout - - -@np_random_state(7) -def _fruchterman_reingold( - A, k=None, pos=None, fixed=None, iterations=50, threshold=1e-4, dim=2, seed=None -): - # Position nodes in adjacency matrix A using Fruchterman-Reingold - # Entry point for NetworkX graph is fruchterman_reingold_layout() - import numpy as np - - try: - nnodes, _ = A.shape - except AttributeError as err: - msg = "fruchterman_reingold() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) from err - - if pos is None: - # random initial positions - pos = np.asarray(seed.rand(nnodes, dim), dtype=A.dtype) - else: - # make sure positions are of same type as matrix - pos = pos.astype(A.dtype) - - # optimal distance between nodes - if k is None: - k = np.sqrt(1.0 / nnodes) - # the initial "temperature" is about .1 of domain area (=1x1) - # this is the largest step allowed in the dynamics. - # We need to calculate this in case our fixed positions force our domain - # to be much bigger than 1x1 - t = max(max(pos.T[0]) - min(pos.T[0]), max(pos.T[1]) - min(pos.T[1])) * 0.1 - # simple cooling scheme. - # linearly step down by dt on each iteration so last iteration is size dt. - dt = t / (iterations + 1) - delta = np.zeros((pos.shape[0], pos.shape[0], pos.shape[1]), dtype=A.dtype) - # the inscrutable (but fast) version - # this is still O(V^2) - # could use multilevel methods to speed this up significantly - for iteration in range(iterations): - # matrix of difference between points - delta = pos[:, np.newaxis, :] - pos[np.newaxis, :, :] - # distance between points - distance = np.linalg.norm(delta, axis=-1) - # enforce minimum distance of 0.01 - np.clip(distance, 0.01, None, out=distance) - # displacement "force" - displacement = np.einsum( - "ijk,ij->ik", delta, (k * k / distance**2 - A * distance / k) - ) - # update positions - length = np.linalg.norm(displacement, axis=-1) - length = np.where(length < 0.01, 0.1, length) - delta_pos = np.einsum("ij,i->ij", displacement, t / length) - if fixed is not None: - # don't change positions of fixed nodes - delta_pos[fixed] = 0.0 - pos += delta_pos - # cool temperature - t -= dt - if (np.linalg.norm(delta_pos) / nnodes) < threshold: - break - return pos - - -@np_random_state(7) -def _sparse_fruchterman_reingold( - A, k=None, pos=None, fixed=None, iterations=50, threshold=1e-4, dim=2, seed=None -): - # Position nodes in adjacency matrix A using Fruchterman-Reingold - # Entry point for NetworkX graph is fruchterman_reingold_layout() - # Sparse version - import numpy as np - import scipy as sp - - try: - nnodes, _ = A.shape - except AttributeError as err: - msg = "fruchterman_reingold() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) from err - # make sure we have a LIst of Lists representation - try: - A = A.tolil() - except AttributeError: - A = (sp.sparse.coo_array(A)).tolil() - - if pos is None: - # random initial positions - pos = np.asarray(seed.rand(nnodes, dim), dtype=A.dtype) - else: - # make sure positions are of same type as matrix - pos = pos.astype(A.dtype) - - # no fixed nodes - if fixed is None: - fixed = [] - - # optimal distance between nodes - if k is None: - k = np.sqrt(1.0 / nnodes) - # the initial "temperature" is about .1 of domain area (=1x1) - # this is the largest step allowed in the dynamics. - t = max(max(pos.T[0]) - min(pos.T[0]), max(pos.T[1]) - min(pos.T[1])) * 0.1 - # simple cooling scheme. - # linearly step down by dt on each iteration so last iteration is size dt. - dt = t / (iterations + 1) - - displacement = np.zeros((dim, nnodes)) - for iteration in range(iterations): - displacement *= 0 - # loop over rows - for i in range(A.shape[0]): - if i in fixed: - continue - # difference between this row's node position and all others - delta = (pos[i] - pos).T - # distance between points - distance = np.sqrt((delta**2).sum(axis=0)) - # enforce minimum distance of 0.01 - distance = np.where(distance < 0.01, 0.01, distance) - # the adjacency matrix row - Ai = A.getrowview(i).toarray() # TODO: revisit w/ sparse 1D container - # displacement "force" - displacement[:, i] += ( - delta * (k * k / distance**2 - Ai * distance / k) - ).sum(axis=1) - # update positions - length = np.sqrt((displacement**2).sum(axis=0)) - length = np.where(length < 0.01, 0.1, length) - delta_pos = (displacement * t / length).T - pos += delta_pos - # cool temperature - t -= dt - if (np.linalg.norm(delta_pos) / nnodes) < threshold: - break - return pos - - -def kamada_kawai_layout( - G, dist=None, pos=None, weight="weight", scale=1, center=None, dim=2 -): - """Position nodes using Kamada-Kawai path-length cost-function. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - dist : dict (default=None) - A two-level dictionary of optimal distances between nodes, - indexed by source and destination node. - If None, the distance is computed using shortest_path_length(). - - pos : dict or None optional (default=None) - Initial positions for nodes as a dictionary with node as keys - and values as a coordinate list or tuple. If None, then use - circular_layout() for dim >= 2 and a linear layout for dim == 1. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None, then all edge weights are 1. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.kamada_kawai_layout(G) - """ - import numpy as np - - G, center = _process_params(G, center, dim) - nNodes = len(G) - if nNodes == 0: - return {} - - if dist is None: - dist = dict(nx.shortest_path_length(G, weight=weight)) - dist_mtx = 1e6 * np.ones((nNodes, nNodes)) - for row, nr in enumerate(G): - if nr not in dist: - continue - rdist = dist[nr] - for col, nc in enumerate(G): - if nc not in rdist: - continue - dist_mtx[row][col] = rdist[nc] - - if pos is None: - if dim >= 3: - pos = random_layout(G, dim=dim) - elif dim == 2: - pos = circular_layout(G, dim=dim) - else: - pos = dict(zip(G, np.linspace(0, 1, len(G)))) - pos_arr = np.array([pos[n] for n in G]) - - pos = _kamada_kawai_solve(dist_mtx, pos_arr, dim) - - pos = rescale_layout(pos, scale=scale) + center - return dict(zip(G, pos)) - - -def _kamada_kawai_solve(dist_mtx, pos_arr, dim): - # Anneal node locations based on the Kamada-Kawai cost-function, - # using the supplied matrix of preferred inter-node distances, - # and starting locations. - - import numpy as np - import scipy as sp - - meanwt = 1e-3 - costargs = (np, 1 / (dist_mtx + np.eye(dist_mtx.shape[0]) * 1e-3), meanwt, dim) - - optresult = sp.optimize.minimize( - _kamada_kawai_costfn, - pos_arr.ravel(), - method="L-BFGS-B", - args=costargs, - jac=True, - ) - - return optresult.x.reshape((-1, dim)) - - -def _kamada_kawai_costfn(pos_vec, np, invdist, meanweight, dim): - # Cost-function and gradient for Kamada-Kawai layout algorithm - nNodes = invdist.shape[0] - pos_arr = pos_vec.reshape((nNodes, dim)) - - delta = pos_arr[:, np.newaxis, :] - pos_arr[np.newaxis, :, :] - nodesep = np.linalg.norm(delta, axis=-1) - direction = np.einsum("ijk,ij->ijk", delta, 1 / (nodesep + np.eye(nNodes) * 1e-3)) - - offset = nodesep * invdist - 1.0 - offset[np.diag_indices(nNodes)] = 0 - - cost = 0.5 * np.sum(offset**2) - grad = np.einsum("ij,ij,ijk->ik", invdist, offset, direction) - np.einsum( - "ij,ij,ijk->jk", invdist, offset, direction - ) - - # Additional parabolic term to encourage mean position to be near origin: - sumpos = np.sum(pos_arr, axis=0) - cost += 0.5 * meanweight * np.sum(sumpos**2) - grad += meanweight * sumpos - - return (cost, grad.ravel()) - - -def spectral_layout(G, weight="weight", scale=1, center=None, dim=2): - """Position nodes using the eigenvectors of the graph Laplacian. - - Using the unnormalized Laplacian, the layout shows possible clusters of - nodes which are an approximation of the ratio cut. If dim is the number of - dimensions then the positions are the entries of the dim eigenvectors - corresponding to the ascending eigenvalues starting from the second one. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None, then all edge weights are 1. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spectral_layout(G) - - Notes - ----- - Directed graphs will be considered as undirected graphs when - positioning the nodes. - - For larger graphs (>500 nodes) this will use the SciPy sparse - eigenvalue solver (ARPACK). - """ - # handle some special cases that break the eigensolvers - import numpy as np - - G, center = _process_params(G, center, dim) - - if len(G) <= 2: - if len(G) == 0: - pos = np.array([]) - elif len(G) == 1: - pos = np.array([center]) - else: - pos = np.array([np.zeros(dim), np.array(center) * 2.0]) - return dict(zip(G, pos)) - try: - # Sparse matrix - if len(G) < 500: # dense solver is faster for small graphs - raise ValueError - A = nx.to_scipy_sparse_array(G, weight=weight, dtype="d") - # Symmetrize directed graphs - if G.is_directed(): - A = A + np.transpose(A) - pos = _sparse_spectral(A, dim) - except (ImportError, ValueError): - # Dense matrix - A = nx.to_numpy_array(G, weight=weight) - # Symmetrize directed graphs - if G.is_directed(): - A += A.T - pos = _spectral(A, dim) - - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - return pos - - -def _spectral(A, dim=2): - # Input adjacency matrix A - # Uses dense eigenvalue solver from numpy - import numpy as np - - try: - nnodes, _ = A.shape - except AttributeError as err: - msg = "spectral() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) from err - - # form Laplacian matrix where D is diagonal of degrees - D = np.identity(nnodes, dtype=A.dtype) * np.sum(A, axis=1) - L = D - A - - eigenvalues, eigenvectors = np.linalg.eig(L) - # sort and keep smallest nonzero - index = np.argsort(eigenvalues)[1 : dim + 1] # 0 index is zero eigenvalue - return np.real(eigenvectors[:, index]) - - -def _sparse_spectral(A, dim=2): - # Input adjacency matrix A - # Uses sparse eigenvalue solver from scipy - # Could use multilevel methods here, see Koren "On spectral graph drawing" - import numpy as np - import scipy as sp - - try: - nnodes, _ = A.shape - except AttributeError as err: - msg = "sparse_spectral() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) from err - - # form Laplacian matrix - # TODO: Rm csr_array wrapper in favor of spdiags array constructor when available - D = sp.sparse.csr_array(sp.sparse.spdiags(A.sum(axis=1), 0, nnodes, nnodes)) - L = D - A - - k = dim + 1 - # number of Lanczos vectors for ARPACK solver.What is the right scaling? - ncv = max(2 * k + 1, int(np.sqrt(nnodes))) - # return smallest k eigenvalues and eigenvectors - eigenvalues, eigenvectors = sp.sparse.linalg.eigsh(L, k, which="SM", ncv=ncv) - index = np.argsort(eigenvalues)[1:k] # 0 index is zero eigenvalue - return np.real(eigenvectors[:, index]) - - -def planar_layout(G, scale=1, center=None, dim=2): - """Position nodes without edge intersections. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. If G is of type - nx.PlanarEmbedding, the positions are selected accordingly. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------ - NetworkXException - If G is not planar - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.planar_layout(G) - """ - import numpy as np - - if dim != 2: - raise ValueError("can only handle 2 dimensions") - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - - if isinstance(G, nx.PlanarEmbedding): - embedding = G - else: - is_planar, embedding = nx.check_planarity(G) - if not is_planar: - raise nx.NetworkXException("G is not planar.") - pos = nx.combinatorial_embedding_to_pos(embedding) - node_list = list(embedding) - pos = np.vstack([pos[x] for x in node_list]) - pos = pos.astype(np.float64) - pos = rescale_layout(pos, scale=scale) + center - return dict(zip(node_list, pos)) - - -def spiral_layout(G, scale=1, center=None, dim=2, resolution=0.35, equidistant=False): - """Position nodes in a spiral layout. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - scale : number (default: 1) - Scale factor for positions. - center : array-like or None - Coordinate pair around which to center the layout. - dim : int, default=2 - Dimension of layout, currently only dim=2 is supported. - Other dimension values result in a ValueError. - resolution : float, default=0.35 - The compactness of the spiral layout returned. - Lower values result in more compressed spiral layouts. - equidistant : bool, default=False - If True, nodes will be positioned equidistant from each other - by decreasing angle further from center. - If False, nodes will be positioned at equal angles - from each other by increasing separation further from center. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------ - ValueError - If dim != 2 - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spiral_layout(G) - >>> nx.draw(G, pos=pos) - - Notes - ----- - This algorithm currently only works in two dimensions. - - """ - import numpy as np - - if dim != 2: - raise ValueError("can only handle 2 dimensions") - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G): center} - - pos = [] - if equidistant: - chord = 1 - step = 0.5 - theta = resolution - theta += chord / (step * theta) - for _ in range(len(G)): - r = step * theta - theta += chord / r - pos.append([np.cos(theta) * r, np.sin(theta) * r]) - - else: - dist = np.arange(len(G), dtype=float) - angle = resolution * dist - pos = np.transpose(dist * np.array([np.cos(angle), np.sin(angle)])) - - pos = rescale_layout(np.array(pos), scale=scale) + center - - pos = dict(zip(G, pos)) - - return pos - - -def multipartite_layout(G, subset_key="subset", align="vertical", scale=1, center=None): - """Position nodes in layers of straight lines. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - subset_key : string or dict (default='subset') - If a string, the key of node data in G that holds the node subset. - If a dict, keyed by layer number to the nodes in that layer/subset. - - align : string (default='vertical') - The alignment of nodes. Vertical or horizontal. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.complete_multipartite_graph(28, 16, 10) - >>> pos = nx.multipartite_layout(G) - - or use a dict to provide the layers of the layout - - >>> G = nx.Graph([(0, 1), (1, 2), (1, 3), (3, 4)]) - >>> layers = {"a": [0], "b": [1], "c": [2, 3], "d": [4]} - >>> pos = nx.multipartite_layout(G, subset_key=layers) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - Network does not need to be a complete multipartite graph. As long as nodes - have subset_key data, they will be placed in the corresponding layers. - - """ - import numpy as np - - if align not in ("vertical", "horizontal"): - msg = "align must be either vertical or horizontal." - raise ValueError(msg) - - G, center = _process_params(G, center=center, dim=2) - if len(G) == 0: - return {} - - try: - # check if subset_key is dict-like - if len(G) != sum(len(nodes) for nodes in subset_key.values()): - raise nx.NetworkXError( - "all nodes must be in one subset of `subset_key` dict" - ) - except AttributeError: - # subset_key is not a dict, hence a string - node_to_subset = nx.get_node_attributes(G, subset_key) - if len(node_to_subset) != len(G): - raise nx.NetworkXError( - f"all nodes need a subset_key attribute: {subset_key}" - ) - subset_key = nx.utils.groups(node_to_subset) - - # Sort by layer, if possible - try: - layers = dict(sorted(subset_key.items())) - except TypeError: - layers = subset_key - - pos = None - nodes = [] - width = len(layers) - for i, layer in enumerate(layers.values()): - height = len(layer) - xs = np.repeat(i, height) - ys = np.arange(0, height, dtype=float) - offset = ((width - 1) / 2, (height - 1) / 2) - layer_pos = np.column_stack([xs, ys]) - offset - if pos is None: - pos = layer_pos - else: - pos = np.concatenate([pos, layer_pos]) - nodes.extend(layer) - pos = rescale_layout(pos, scale=scale) + center - if align == "horizontal": - pos = pos[:, ::-1] # swap x and y coords - pos = dict(zip(nodes, pos)) - return pos - - -@np_random_state("seed") -def arf_layout( - G, - pos=None, - scaling=1, - a=1.1, - etol=1e-6, - dt=1e-3, - max_iter=1000, - *, - seed=None, -): - """Arf layout for networkx - - The attractive and repulsive forces (arf) layout [1] - improves the spring layout in three ways. First, it - prevents congestion of highly connected nodes due to - strong forcing between nodes. Second, it utilizes the - layout space more effectively by preventing large gaps - that spring layout tends to create. Lastly, the arf - layout represents symmetries in the layout better than - the default spring layout. - - Parameters - ---------- - G : nx.Graph or nx.DiGraph - Networkx graph. - pos : dict - Initial position of the nodes. If set to None a - random layout will be used. - scaling : float - Scales the radius of the circular layout space. - a : float - Strength of springs between connected nodes. Should be larger than 1. The greater a, the clearer the separation ofunconnected sub clusters. - etol : float - Gradient sum of spring forces must be larger than `etol` before successful termination. - dt : float - Time step for force differential equation simulations. - max_iter : int - Max iterations before termination of the algorithm. - seed : int, RandomState instance or None optional (default=None) - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - - References - .. [1] "Self-Organization Applied to Dynamic Network Layout", M. Geipel, - International Journal of Modern Physics C, 2007, Vol 18, No 10, pp. 1537-1549. - https://doi.org/10.1142/S0129183107011558 https://arxiv.org/abs/0704.1748 - - Returns - ------- - pos : dict - A dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.grid_graph((5, 5)) - >>> pos = nx.arf_layout(G) - - """ - import warnings - - import numpy as np - - if a <= 1: - msg = "The parameter a should be larger than 1" - raise ValueError(msg) - - pos_tmp = nx.random_layout(G, seed=seed) - if pos is None: - pos = pos_tmp - else: - for node in G.nodes(): - if node not in pos: - pos[node] = pos_tmp[node].copy() - - # Initialize spring constant matrix - N = len(G) - # No nodes no computation - if N == 0: - return pos - - # init force of springs - K = np.ones((N, N)) - np.eye(N) - node_order = {node: i for i, node in enumerate(G)} - for x, y in G.edges(): - if x != y: - idx, jdx = (node_order[i] for i in (x, y)) - K[idx, jdx] = a - - # vectorize values - p = np.asarray(list(pos.values())) - - # equation 10 in [1] - rho = scaling * np.sqrt(N) - - # looping variables - error = etol + 1 - n_iter = 0 - while error > etol: - diff = p[:, np.newaxis] - p[np.newaxis] - A = np.linalg.norm(diff, axis=-1)[..., np.newaxis] - # attraction_force - repulsions force - # suppress nans due to division; caused by diagonal set to zero. - # Does not affect the computation due to nansum - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - change = K[..., np.newaxis] * diff - rho / A * diff - change = np.nansum(change, axis=0) - p += change * dt - - error = np.linalg.norm(change, axis=-1).sum() - if n_iter > max_iter: - break - n_iter += 1 - return dict(zip(G.nodes(), p)) - - -@np_random_state("seed") -def forceatlas2_layout( - G, - pos=None, - *, - max_iter=100, - jitter_tolerance=1.0, - scaling_ratio=2.0, - gravity=1.0, - distributed_action=False, - strong_gravity=False, - node_mass=None, - node_size=None, - weight=None, - dissuade_hubs=False, - linlog=False, - seed=None, - dim=2, -): - """Position nodes using the ForceAtlas2 force-directed layout algorithm. - - This function applies the ForceAtlas2 layout algorithm [1]_ to a NetworkX graph, - positioning the nodes in a way that visually represents the structure of the graph. - The algorithm uses physical simulation to minimize the energy of the system, - resulting in a more readable layout. - - Parameters - ---------- - G : nx.Graph - A NetworkX graph to be laid out. - pos : dict or None, optional - Initial positions of the nodes. If None, random initial positions are used. - max_iter : int (default: 100) - Number of iterations for the layout optimization. - jitter_tolerance : float (default: 1.0) - Controls the tolerance for adjusting the speed of layout generation. - scaling_ratio : float (default: 2.0) - Determines the scaling of attraction and repulsion forces. - distributed_attraction : bool (default: False) - Distributes the attraction force evenly among nodes. - strong_gravity : bool (default: False) - Applies a strong gravitational pull towards the center. - node_mass : dict or None, optional - Maps nodes to their masses, influencing the attraction to other nodes. - node_size : dict or None, optional - Maps nodes to their sizes, preventing crowding by creating a halo effect. - dissuade_hubs : bool (default: False) - Prevents the clustering of hub nodes. - linlog : bool (default: False) - Uses logarithmic attraction instead of linear. - seed : int, RandomState instance or None optional (default=None) - Used only for the initial positions in the algorithm. - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - dim : int (default: 2) - Sets the dimensions for the layout. Ignored if `pos` is provided. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.florentine_families_graph() - >>> pos = nx.forceatlas2_layout(G) - >>> nx.draw(G, pos=pos) - - References - ---------- - .. [1] Jacomy, M., Venturini, T., Heymann, S., & Bastian, M. (2014). - ForceAtlas2, a continuous graph layout algorithm for handy network - visualization designed for the Gephi software. PloS one, 9(6), e98679. - https://doi.org/10.1371/journal.pone.0098679 - """ - import numpy as np - - if len(G) == 0: - return {} - # parse optional pos positions - if pos is None: - pos = nx.random_layout(G, dim=dim, seed=seed) - pos_arr = np.array(list(pos.values())) - else: - # set default node interval within the initial pos values - pos_init = np.array(list(pos.values())) - max_pos = pos_init.max(axis=0) - min_pos = pos_init.min(axis=0) - dim = max_pos.size - pos_arr = min_pos + seed.rand(len(G), dim) * (max_pos - min_pos) - for idx, node in enumerate(G): - if node in pos: - pos_arr[idx] = pos[node].copy() - - mass = np.zeros(len(G)) - size = np.zeros(len(G)) - - # Only adjust for size when the users specifies size other than default (1) - adjust_sizes = False - if node_size is None: - node_size = {} - else: - adjust_sizes = True - - if node_mass is None: - node_mass = {} - - for idx, node in enumerate(G): - mass[idx] = node_mass.get(node, G.degree(node) + 1) - size[idx] = node_size.get(node, 1) - - n = len(G) - gravities = np.zeros((n, dim)) - attraction = np.zeros((n, dim)) - repulsion = np.zeros((n, dim)) - A = nx.to_numpy_array(G, weight=weight) - - def estimate_factor(n, swing, traction, speed, speed_efficiency, jitter_tolerance): - """Computes the scaling factor for the force in the ForceAtlas2 layout algorithm. - - This helper function adjusts the speed and - efficiency of the layout generation based on the - current state of the system, such as the number of - nodes, current swing, and traction forces. - - Parameters - ---------- - n : int - Number of nodes in the graph. - swing : float - The current swing, representing the oscillation of the nodes. - traction : float - The current traction force, representing the attraction between nodes. - speed : float - The current speed of the layout generation. - speed_efficiency : float - The efficiency of the current speed, influencing how fast the layout converges. - jitter_tolerance : float - The tolerance for jitter, affecting how much speed adjustment is allowed. - - Returns - ------- - tuple - A tuple containing the updated speed and speed efficiency. - - Notes - ----- - This function is a part of the ForceAtlas2 layout algorithm and is used to dynamically adjust the - layout parameters to achieve an optimal and stable visualization. - - """ - import numpy as np - - # estimate jitter - opt_jitter = 0.05 * np.sqrt(n) - min_jitter = np.sqrt(opt_jitter) - max_jitter = 10 - min_speed_efficiency = 0.05 - - other = min(max_jitter, opt_jitter * traction / n**2) - jitter = jitter_tolerance * max(min_jitter, other) - - if swing / traction > 2.0: - if speed_efficiency > min_speed_efficiency: - speed_efficiency *= 0.5 - jitter = max(jitter, jitter_tolerance) - if swing == 0: - target_speed = np.inf - else: - target_speed = jitter * speed_efficiency * traction / swing - - if swing > jitter * traction: - if speed_efficiency > min_speed_efficiency: - speed_efficiency *= 0.7 - elif speed < 1000: - speed_efficiency *= 1.3 - - max_rise = 0.5 - speed = speed + min(target_speed - speed, max_rise * speed) - return speed, speed_efficiency - - speed = 1 - speed_efficiency = 1 - swing = 1 - traction = 1 - for _ in range(max_iter): - # compute pairwise difference - diff = pos_arr[:, None] - pos_arr[None] - # compute pairwise distance - distance = np.linalg.norm(diff, axis=-1) - - # linear attraction - if linlog: - attraction = -np.log(1 + distance) / distance - np.fill_diagonal(attraction, 0) - attraction = np.einsum("ij, ij -> ij", attraction, A) - attraction = np.einsum("ijk, ij -> ik", diff, attraction) - - else: - attraction = -np.einsum("ijk, ij -> ik", diff, A) - - if distributed_action: - attraction /= mass[:, None] - - # repulsion - tmp = mass[:, None] @ mass[None] - if adjust_sizes: - distance += -size[:, None] - size[None] - - d2 = distance**2 - # remove self-interaction - np.fill_diagonal(tmp, 0) - np.fill_diagonal(d2, 1) - factor = (tmp / d2) * scaling_ratio - repulsion = np.einsum("ijk, ij -> ik", diff, factor) - - # gravity - gravities = ( - -gravity - * mass[:, None] - * pos_arr - / np.linalg.norm(pos_arr, axis=-1)[:, None] - ) - - if strong_gravity: - gravities *= np.linalg.norm(pos_arr, axis=-1)[:, None] - # total forces - update = attraction + repulsion + gravities - - # compute total swing and traction - swing += (mass * np.linalg.norm(pos_arr - update, axis=-1)).sum() - traction += (0.5 * mass * np.linalg.norm(pos_arr + update, axis=-1)).sum() - - speed, speed_efficiency = estimate_factor( - n, - swing, - traction, - speed, - speed_efficiency, - jitter_tolerance, - ) - - # update pos - if adjust_sizes: - swinging = mass * np.linalg.norm(update, axis=-1) - factor = 0.1 * speed / (1 + np.sqrt(speed * swinging)) - df = np.linalg.norm(update, axis=-1) - factor = np.minimum(factor * df, 10.0 * np.ones(df.shape)) / df - else: - swinging = mass * np.linalg.norm(update, axis=-1) - factor = speed / (1 + np.sqrt(speed * swinging)) - - pos_arr += update * factor[:, None] - if abs((update * factor[:, None]).sum()) < 1e-10: - break - - return dict(zip(G, pos_arr)) - - -def rescale_layout(pos, scale=1): - """Returns scaled position array to (-scale, scale) in all axes. - - The function acts on NumPy arrays which hold position information. - Each position is one row of the array. The dimension of the space - equals the number of columns. Each coordinate in one column. - - To rescale, the mean (center) is subtracted from each axis separately. - Then all values are scaled so that the largest magnitude value - from all axes equals `scale` (thus, the aspect ratio is preserved). - The resulting NumPy Array is returned (order of rows unchanged). - - Parameters - ---------- - pos : numpy array - positions to be scaled. Each row is a position. - - scale : number (default: 1) - The size of the resulting extent in all directions. - - Returns - ------- - pos : numpy array - scaled positions. Each row is a position. - - See Also - -------- - rescale_layout_dict - """ - import numpy as np - - # Find max length over all dimensions - pos -= pos.mean(axis=0) - lim = np.abs(pos).max() # max coordinate for all axes - # rescale to (-scale, scale) in all directions, preserves aspect - if lim > 0: - pos *= scale / lim - return pos - - -def rescale_layout_dict(pos, scale=1): - """Return a dictionary of scaled positions keyed by node - - Parameters - ---------- - pos : A dictionary of positions keyed by node - - scale : number (default: 1) - The size of the resulting extent in all directions. - - Returns - ------- - pos : A dictionary of positions keyed by node - - Examples - -------- - >>> import numpy as np - >>> pos = {0: np.array((0, 0)), 1: np.array((1, 1)), 2: np.array((0.5, 0.5))} - >>> nx.rescale_layout_dict(pos) - {0: array([-1., -1.]), 1: array([1., 1.]), 2: array([0., 0.])} - - >>> pos = {0: np.array((0, 0)), 1: np.array((-1, 1)), 2: np.array((-0.5, 0.5))} - >>> nx.rescale_layout_dict(pos, scale=2) - {0: array([ 2., -2.]), 1: array([-2., 2.]), 2: array([0., 0.])} - - See Also - -------- - rescale_layout - """ - import numpy as np - - if not pos: # empty_graph - return {} - pos_v = np.array(list(pos.values())) - pos_v = rescale_layout(pos_v, scale=scale) - return dict(zip(pos, pos_v)) - - -def bfs_layout(G, start, *, align="vertical", scale=1, center=None): - """Position nodes according to breadth-first search algorithm. - - Parameters - ---------- - G : NetworkX graph - A position will be assigned to every node in G. - - start : node in `G` - Starting node for bfs - - center : array-like or None - Coordinate pair around which to center the layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.bfs_layout(G, 0) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - G, center = _process_params(G, center, 2) - - # Compute layers with BFS - layers = dict(enumerate(nx.bfs_layers(G, start))) - - if len(G) != sum(len(nodes) for nodes in layers.values()): - raise nx.NetworkXError( - "bfs_layout didn't include all nodes. Perhaps use input graph:\n" - " G.subgraph(nx.node_connected_component(G, start))" - ) - - # Compute node positions with multipartite_layout - return multipartite_layout( - G, subset_key=layers, align=align, scale=scale, center=center - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py deleted file mode 100644 index b394729..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py +++ /dev/null @@ -1,464 +0,0 @@ -""" -*************** -Graphviz AGraph -*************** - -Interface to pygraphviz AGraph class. - -Examples --------- ->>> G = nx.complete_graph(5) ->>> A = nx.nx_agraph.to_agraph(G) ->>> H = nx.nx_agraph.from_agraph(A) - -See Also --------- - - Pygraphviz: http://pygraphviz.github.io/ - - Graphviz: https://www.graphviz.org - - DOT Language: http://www.graphviz.org/doc/info/lang.html -""" - -import os -import tempfile - -import networkx as nx - -__all__ = [ - "from_agraph", - "to_agraph", - "write_dot", - "read_dot", - "graphviz_layout", - "pygraphviz_layout", - "view_pygraphviz", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_agraph(A, create_using=None): - """Returns a NetworkX Graph or DiGraph from a PyGraphviz graph. - - Parameters - ---------- - A : PyGraphviz AGraph - A graph created with PyGraphviz - - create_using : NetworkX graph constructor, optional (default=None) - Graph type to create. If graph instance, then cleared before populated. - If `None`, then the appropriate Graph type is inferred from `A`. - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_agraph.to_agraph(K5) - >>> G = nx.nx_agraph.from_agraph(A) - - Notes - ----- - The Graph G will have a dictionary G.graph_attr containing - the default graphviz attributes for graphs, nodes and edges. - - Default node attributes will be in the dictionary G.node_attr - which is keyed by node. - - Edge attributes will be returned as edge data in G. With - edge_attr=False the edge data will be the Graphviz edge weight - attribute or the value 1 if no edge weight attribute is found. - - """ - if create_using is None: - if A.is_directed(): - if A.is_strict(): - create_using = nx.DiGraph - else: - create_using = nx.MultiDiGraph - else: - if A.is_strict(): - create_using = nx.Graph - else: - create_using = nx.MultiGraph - - # assign defaults - N = nx.empty_graph(0, create_using) - if A.name is not None: - N.name = A.name - - # add graph attributes - N.graph.update(A.graph_attr) - - # add nodes, attributes to N.node_attr - for n in A.nodes(): - str_attr = {str(k): v for k, v in n.attr.items()} - N.add_node(str(n), **str_attr) - - # add edges, assign edge data as dictionary of attributes - for e in A.edges(): - u, v = str(e[0]), str(e[1]) - attr = dict(e.attr) - str_attr = {str(k): v for k, v in attr.items()} - if not N.is_multigraph(): - if e.name is not None: - str_attr["key"] = e.name - N.add_edge(u, v, **str_attr) - else: - N.add_edge(u, v, key=e.name, **str_attr) - - # add default attributes for graph, nodes, and edges - # hang them on N.graph_attr - N.graph["graph"] = dict(A.graph_attr) - N.graph["node"] = dict(A.node_attr) - N.graph["edge"] = dict(A.edge_attr) - return N - - -def to_agraph(N): - """Returns a pygraphviz graph from a NetworkX graph N. - - Parameters - ---------- - N : NetworkX graph - A graph created with NetworkX - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_agraph.to_agraph(K5) - - Notes - ----- - If N has an dict N.graph_attr an attempt will be made first - to copy properties attached to the graph (see from_agraph) - and then updated with the calling arguments if any. - - """ - try: - import pygraphviz - except ImportError as err: - raise ImportError("requires pygraphviz http://pygraphviz.github.io/") from err - directed = N.is_directed() - strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() - - A = pygraphviz.AGraph(name=N.name, strict=strict, directed=directed) - - # default graph attributes - A.graph_attr.update(N.graph.get("graph", {})) - A.node_attr.update(N.graph.get("node", {})) - A.edge_attr.update(N.graph.get("edge", {})) - - A.graph_attr.update( - (k, v) for k, v in N.graph.items() if k not in ("graph", "node", "edge") - ) - - # add nodes - for n, nodedata in N.nodes(data=True): - A.add_node(n) - # Add node data - a = A.get_node(n) - for key, val in nodedata.items(): - if key == "pos": - a.attr["pos"] = f"{val[0]},{val[1]}!" - else: - a.attr[key] = str(val) - - # loop over edges - if N.is_multigraph(): - for u, v, key, edgedata in N.edges(data=True, keys=True): - str_edgedata = {k: str(v) for k, v in edgedata.items() if k != "key"} - A.add_edge(u, v, key=str(key)) - # Add edge data - a = A.get_edge(u, v) - a.attr.update(str_edgedata) - - else: - for u, v, edgedata in N.edges(data=True): - str_edgedata = {k: str(v) for k, v in edgedata.items()} - A.add_edge(u, v) - # Add edge data - a = A.get_edge(u, v) - a.attr.update(str_edgedata) - - return A - - -def write_dot(G, path): - """Write NetworkX graph G to Graphviz dot format on path. - - Parameters - ---------- - G : graph - A networkx graph - path : filename - Filename or file handle to write - - Notes - ----- - To use a specific graph layout, call ``A.layout`` prior to `write_dot`. - Note that some graphviz layouts are not guaranteed to be deterministic, - see https://gitlab.com/graphviz/graphviz/-/issues/1767 for more info. - """ - A = to_agraph(G) - A.write(path) - A.clear() - return - - -@nx._dispatchable(name="agraph_read_dot", graphs=None, returns_graph=True) -def read_dot(path): - """Returns a NetworkX graph from a dot file on path. - - Parameters - ---------- - path : file or string - File name or file handle to read. - """ - try: - import pygraphviz - except ImportError as err: - raise ImportError( - "read_dot() requires pygraphviz http://pygraphviz.github.io/" - ) from err - A = pygraphviz.AGraph(file=path) - gr = from_agraph(A) - A.clear() - return gr - - -def graphviz_layout(G, prog="neato", root=None, args=""): - """Create node positions for G using Graphviz. - - Parameters - ---------- - G : NetworkX graph - A graph created with NetworkX - prog : string - Name of Graphviz layout program - root : string, optional - Root node for twopi layout - args : string, optional - Extra arguments to Graphviz layout program - - Returns - ------- - Dictionary of x, y, positions keyed by node. - - Examples - -------- - >>> G = nx.petersen_graph() - >>> pos = nx.nx_agraph.graphviz_layout(G) - >>> pos = nx.nx_agraph.graphviz_layout(G, prog="dot") - - Notes - ----- - This is a wrapper for pygraphviz_layout. - - Note that some graphviz layouts are not guaranteed to be deterministic, - see https://gitlab.com/graphviz/graphviz/-/issues/1767 for more info. - """ - return pygraphviz_layout(G, prog=prog, root=root, args=args) - - -def pygraphviz_layout(G, prog="neato", root=None, args=""): - """Create node positions for G using Graphviz. - - Parameters - ---------- - G : NetworkX graph - A graph created with NetworkX - prog : string - Name of Graphviz layout program - root : string, optional - Root node for twopi layout - args : string, optional - Extra arguments to Graphviz layout program - - Returns - ------- - node_pos : dict - Dictionary of x, y, positions keyed by node. - - Examples - -------- - >>> G = nx.petersen_graph() - >>> pos = nx.nx_agraph.graphviz_layout(G) - >>> pos = nx.nx_agraph.graphviz_layout(G, prog="dot") - - Notes - ----- - If you use complex node objects, they may have the same string - representation and GraphViz could treat them as the same node. - The layout may assign both nodes a single location. See Issue #1568 - If this occurs in your case, consider relabeling the nodes just - for the layout computation using something similar to:: - - >>> H = nx.convert_node_labels_to_integers(G, label_attribute="node_label") - >>> H_layout = nx.nx_agraph.pygraphviz_layout(G, prog="dot") - >>> G_layout = {H.nodes[n]["node_label"]: p for n, p in H_layout.items()} - - Note that some graphviz layouts are not guaranteed to be deterministic, - see https://gitlab.com/graphviz/graphviz/-/issues/1767 for more info. - """ - try: - import pygraphviz - except ImportError as err: - raise ImportError("requires pygraphviz http://pygraphviz.github.io/") from err - if root is not None: - args += f"-Groot={root}" - A = to_agraph(G) - A.layout(prog=prog, args=args) - node_pos = {} - for n in G: - node = pygraphviz.Node(A, n) - try: - xs = node.attr["pos"].split(",") - node_pos[n] = tuple(float(x) for x in xs) - except: - print("no position for node", n) - node_pos[n] = (0.0, 0.0) - return node_pos - - -@nx.utils.open_file(5, "w+b") -def view_pygraphviz( - G, edgelabel=None, prog="dot", args="", suffix="", path=None, show=True -): - """Views the graph G using the specified layout algorithm. - - Parameters - ---------- - G : NetworkX graph - The machine to draw. - edgelabel : str, callable, None - If a string, then it specifies the edge attribute to be displayed - on the edge labels. If a callable, then it is called for each - edge and it should return the string to be displayed on the edges. - The function signature of `edgelabel` should be edgelabel(data), - where `data` is the edge attribute dictionary. - prog : string - Name of Graphviz layout program. - args : str - Additional arguments to pass to the Graphviz layout program. - suffix : str - If `filename` is None, we save to a temporary file. The value of - `suffix` will appear at the tail end of the temporary filename. - path : str, None - The filename used to save the image. If None, save to a temporary - file. File formats are the same as those from pygraphviz.agraph.draw. - show : bool, default = True - Whether to display the graph with :mod:`PIL.Image.show`, - default is `True`. If `False`, the rendered graph is still available - at `path`. - - Returns - ------- - path : str - The filename of the generated image. - A : PyGraphviz graph - The PyGraphviz graph instance used to generate the image. - - Notes - ----- - If this function is called in succession too quickly, sometimes the - image is not displayed. So you might consider time.sleep(.5) between - calls if you experience problems. - - Note that some graphviz layouts are not guaranteed to be deterministic, - see https://gitlab.com/graphviz/graphviz/-/issues/1767 for more info. - - """ - if not len(G): - raise nx.NetworkXException("An empty graph cannot be drawn.") - - # If we are providing default values for graphviz, these must be set - # before any nodes or edges are added to the PyGraphviz graph object. - # The reason for this is that default values only affect incoming objects. - # If you change the default values after the objects have been added, - # then they inherit no value and are set only if explicitly set. - - # to_agraph() uses these values. - attrs = ["edge", "node", "graph"] - for attr in attrs: - if attr not in G.graph: - G.graph[attr] = {} - - # These are the default values. - edge_attrs = {"fontsize": "10"} - node_attrs = { - "style": "filled", - "fillcolor": "#0000FF40", - "height": "0.75", - "width": "0.75", - "shape": "circle", - } - graph_attrs = {} - - def update_attrs(which, attrs): - # Update graph attributes. Return list of those which were added. - added = [] - for k, v in attrs.items(): - if k not in G.graph[which]: - G.graph[which][k] = v - added.append(k) - - def clean_attrs(which, added): - # Remove added attributes - for attr in added: - del G.graph[which][attr] - if not G.graph[which]: - del G.graph[which] - - # Update all default values - update_attrs("edge", edge_attrs) - update_attrs("node", node_attrs) - update_attrs("graph", graph_attrs) - - # Convert to agraph, so we inherit default values - A = to_agraph(G) - - # Remove the default values we added to the original graph. - clean_attrs("edge", edge_attrs) - clean_attrs("node", node_attrs) - clean_attrs("graph", graph_attrs) - - # If the user passed in an edgelabel, we update the labels for all edges. - if edgelabel is not None: - if not callable(edgelabel): - - def func(data): - return "".join([" ", str(data[edgelabel]), " "]) - - else: - func = edgelabel - - # update all the edge labels - if G.is_multigraph(): - for u, v, key, data in G.edges(keys=True, data=True): - # PyGraphviz doesn't convert the key to a string. See #339 - edge = A.get_edge(u, v, str(key)) - edge.attr["label"] = str(func(data)) - else: - for u, v, data in G.edges(data=True): - edge = A.get_edge(u, v) - edge.attr["label"] = str(func(data)) - - if path is None: - ext = "png" - if suffix: - suffix = f"_{suffix}.{ext}" - else: - suffix = f".{ext}" - path = tempfile.NamedTemporaryFile(suffix=suffix, delete=False) - else: - # Assume the decorator worked and it is a file-object. - pass - - # Write graph to file - A.draw(path=path, format=None, prog=prog, args=args) - path.close() - - # Show graph in a new window (depends on platform configuration) - if show: - from PIL import Image - - Image.open(path.name).show() - - return path.name, A diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_latex.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_latex.py deleted file mode 100644 index 5fdbf78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_latex.py +++ /dev/null @@ -1,572 +0,0 @@ -r""" -***** -LaTeX -***** - -Export NetworkX graphs in LaTeX format using the TikZ library within TeX/LaTeX. -Usually, you will want the drawing to appear in a figure environment so -you use ``to_latex(G, caption="A caption")``. If you want the raw -drawing commands without a figure environment use :func:`to_latex_raw`. -And if you want to write to a file instead of just returning the latex -code as a string, use ``write_latex(G, "filename.tex", caption="A caption")``. - -To construct a figure with subfigures for each graph to be shown, provide -``to_latex`` or ``write_latex`` a list of graphs, a list of subcaptions, -and a number of rows of subfigures inside the figure. - -To be able to refer to the figures or subfigures in latex using ``\\ref``, -the keyword ``latex_label`` is available for figures and `sub_labels` for -a list of labels, one for each subfigure. - -We intend to eventually provide an interface to the TikZ Graph -features which include e.g. layout algorithms. - -Let us know via github what you'd like to see available, or better yet -give us some code to do it, or even better make a github pull request -to add the feature. - -The TikZ approach -================= -Drawing options can be stored on the graph as node/edge attributes, or -can be provided as dicts keyed by node/edge to a string of the options -for that node/edge. Similarly a label can be shown for each node/edge -by specifying the labels as graph node/edge attributes or by providing -a dict keyed by node/edge to the text to be written for that node/edge. - -Options for the tikzpicture environment (e.g. "[scale=2]") can be provided -via a keyword argument. Similarly default node and edge options can be -provided through keywords arguments. The default node options are applied -to the single TikZ "path" that draws all nodes (and no edges). The default edge -options are applied to a TikZ "scope" which contains a path for each edge. - -Examples -======== ->>> G = nx.path_graph(3) ->>> nx.write_latex(G, "just_my_figure.tex", as_document=True) ->>> nx.write_latex(G, "my_figure.tex", caption="A path graph", latex_label="fig1") ->>> latex_code = nx.to_latex(G) # a string rather than a file - -You can change many features of the nodes and edges. - ->>> G = nx.path_graph(4, create_using=nx.DiGraph) ->>> pos = {n: (n, n) for n in G} # nodes set on a line - ->>> G.nodes[0]["style"] = "blue" ->>> G.nodes[2]["style"] = "line width=3,draw" ->>> G.nodes[3]["label"] = "Stop" ->>> G.edges[(0, 1)]["label"] = "1st Step" ->>> G.edges[(0, 1)]["label_opts"] = "near start" ->>> G.edges[(1, 2)]["style"] = "line width=3" ->>> G.edges[(1, 2)]["label"] = "2nd Step" ->>> G.edges[(2, 3)]["style"] = "green" ->>> G.edges[(2, 3)]["label"] = "3rd Step" ->>> G.edges[(2, 3)]["label_opts"] = "near end" - ->>> nx.write_latex(G, "latex_graph.tex", pos=pos, as_document=True) - -Then compile the LaTeX using something like ``pdflatex latex_graph.tex`` -and view the pdf file created: ``latex_graph.pdf``. - -If you want **subfigures** each containing one graph, you can input a list of graphs. - ->>> H1 = nx.path_graph(4) ->>> H2 = nx.complete_graph(4) ->>> H3 = nx.path_graph(8) ->>> H4 = nx.complete_graph(8) ->>> graphs = [H1, H2, H3, H4] ->>> caps = ["Path 4", "Complete graph 4", "Path 8", "Complete graph 8"] ->>> lbls = ["fig2a", "fig2b", "fig2c", "fig2d"] ->>> nx.write_latex(graphs, "subfigs.tex", n_rows=2, sub_captions=caps, sub_labels=lbls) ->>> latex_code = nx.to_latex(graphs, n_rows=2, sub_captions=caps, sub_labels=lbls) - ->>> node_color = {0: "red", 1: "orange", 2: "blue", 3: "gray!90"} ->>> edge_width = {e: "line width=1.5" for e in H3.edges} ->>> pos = nx.circular_layout(H3) ->>> latex_code = nx.to_latex(H3, pos, node_options=node_color, edge_options=edge_width) ->>> print(latex_code) -\documentclass{report} -\usepackage{tikz} -\usepackage{subcaption} - -\begin{document} -\begin{figure} - \begin{tikzpicture} - \draw - (1.0, 0.0) node[red] (0){0} - (0.707, 0.707) node[orange] (1){1} - (-0.0, 1.0) node[blue] (2){2} - (-0.707, 0.707) node[gray!90] (3){3} - (-1.0, -0.0) node (4){4} - (-0.707, -0.707) node (5){5} - (0.0, -1.0) node (6){6} - (0.707, -0.707) node (7){7}; - \begin{scope}[-] - \draw[line width=1.5] (0) to (1); - \draw[line width=1.5] (1) to (2); - \draw[line width=1.5] (2) to (3); - \draw[line width=1.5] (3) to (4); - \draw[line width=1.5] (4) to (5); - \draw[line width=1.5] (5) to (6); - \draw[line width=1.5] (6) to (7); - \end{scope} - \end{tikzpicture} -\end{figure} -\end{document} - -Notes ------ -If you want to change the preamble/postamble of the figure/document/subfigure -environment, use the keyword arguments: `figure_wrapper`, `document_wrapper`, -`subfigure_wrapper`. The default values are stored in private variables -e.g. ``nx.nx_layout._DOCUMENT_WRAPPER`` - -References ----------- -TikZ: https://tikz.dev/ - -TikZ options details: https://tikz.dev/tikz-actions -""" - -import numbers -import os - -import networkx as nx - -__all__ = [ - "to_latex_raw", - "to_latex", - "write_latex", -] - - -@nx.utils.not_implemented_for("multigraph") -def to_latex_raw( - G, - pos="pos", - tikz_options="", - default_node_options="", - node_options="node_options", - node_label="label", - default_edge_options="", - edge_options="edge_options", - edge_label="label", - edge_label_options="edge_label_options", -): - """Return a string of the LaTeX/TikZ code to draw `G` - - This function produces just the code for the tikzpicture - without any enclosing environment. - - Parameters - ========== - G : NetworkX graph - The NetworkX graph to be drawn - pos : string or dict (default "pos") - The name of the node attribute on `G` that holds the position of each node. - Positions can be sequences of length 2 with numbers for (x,y) coordinates. - They can also be strings to denote positions in TikZ style, such as (x, y) - or (angle:radius). - If a dict, it should be keyed by node to a position. - If an empty dict, a circular layout is computed by TikZ. - tikz_options : string - The tikzpicture options description defining the options for the picture. - Often large scale options like `[scale=2]`. - default_node_options : string - The draw options for a path of nodes. Individual node options override these. - node_options : string or dict - The name of the node attribute on `G` that holds the options for each node. - Or a dict keyed by node to a string holding the options for that node. - node_label : string or dict - The name of the node attribute on `G` that holds the node label (text) - displayed for each node. If the attribute is "" or not present, the node - itself is drawn as a string. LaTeX processing such as ``"$A_1$"`` is allowed. - Or a dict keyed by node to a string holding the label for that node. - default_edge_options : string - The options for the scope drawing all edges. The default is "[-]" for - undirected graphs and "[->]" for directed graphs. - edge_options : string or dict - The name of the edge attribute on `G` that holds the options for each edge. - If the edge is a self-loop and ``"loop" not in edge_options`` the option - "loop," is added to the options for the self-loop edge. Hence you can - use "[loop above]" explicitly, but the default is "[loop]". - Or a dict keyed by edge to a string holding the options for that edge. - edge_label : string or dict - The name of the edge attribute on `G` that holds the edge label (text) - displayed for each edge. If the attribute is "" or not present, no edge - label is drawn. - Or a dict keyed by edge to a string holding the label for that edge. - edge_label_options : string or dict - The name of the edge attribute on `G` that holds the label options for - each edge. For example, "[sloped,above,blue]". The default is no options. - Or a dict keyed by edge to a string holding the label options for that edge. - - Returns - ======= - latex_code : string - The text string which draws the desired graph(s) when compiled by LaTeX. - - See Also - ======== - to_latex - write_latex - """ - i4 = "\n " - i8 = "\n " - - # set up position dict - # TODO allow pos to be None and use a nice TikZ default - if not isinstance(pos, dict): - pos = nx.get_node_attributes(G, pos) - if not pos: - # circular layout with radius 2 - pos = {n: f"({round(360.0 * i / len(G), 3)}:2)" for i, n in enumerate(G)} - for node in G: - if node not in pos: - raise nx.NetworkXError(f"node {node} has no specified pos {pos}") - posnode = pos[node] - if not isinstance(posnode, str): - try: - posx, posy = posnode - pos[node] = f"({round(posx, 3)}, {round(posy, 3)})" - except (TypeError, ValueError): - msg = f"position pos[{node}] is not 2-tuple or a string: {posnode}" - raise nx.NetworkXError(msg) - - # set up all the dicts - if not isinstance(node_options, dict): - node_options = nx.get_node_attributes(G, node_options) - if not isinstance(node_label, dict): - node_label = nx.get_node_attributes(G, node_label) - if not isinstance(edge_options, dict): - edge_options = nx.get_edge_attributes(G, edge_options) - if not isinstance(edge_label, dict): - edge_label = nx.get_edge_attributes(G, edge_label) - if not isinstance(edge_label_options, dict): - edge_label_options = nx.get_edge_attributes(G, edge_label_options) - - # process default options (add brackets or not) - topts = "" if tikz_options == "" else f"[{tikz_options.strip('[]')}]" - defn = "" if default_node_options == "" else f"[{default_node_options.strip('[]')}]" - linestyle = f"{'->' if G.is_directed() else '-'}" - if default_edge_options == "": - defe = "[" + linestyle + "]" - elif "-" in default_edge_options: - defe = default_edge_options - else: - defe = f"[{linestyle},{default_edge_options.strip('[]')}]" - - # Construct the string line by line - result = " \\begin{tikzpicture}" + topts - result += i4 + " \\draw" + defn - # load the nodes - for n in G: - # node options goes inside square brackets - nopts = f"[{node_options[n].strip('[]')}]" if n in node_options else "" - # node text goes inside curly brackets {} - ntext = f"{{{node_label[n]}}}" if n in node_label else f"{{{n}}}" - - result += i8 + f"{pos[n]} node{nopts} ({n}){ntext}" - result += ";\n" - - # load the edges - result += " \\begin{scope}" + defe - for edge in G.edges: - u, v = edge[:2] - e_opts = f"{edge_options[edge]}".strip("[]") if edge in edge_options else "" - # add loop options for selfloops if not present - if u == v and "loop" not in e_opts: - e_opts = "loop," + e_opts - e_opts = f"[{e_opts}]" if e_opts != "" else "" - # TODO -- handle bending of multiedges - - els = edge_label_options[edge] if edge in edge_label_options else "" - # edge label options goes inside square brackets [] - els = f"[{els.strip('[]')}]" - # edge text is drawn using the TikZ node command inside curly brackets {} - e_label = f" node{els} {{{edge_label[edge]}}}" if edge in edge_label else "" - - result += i8 + f"\\draw{e_opts} ({u}) to{e_label} ({v});" - - result += "\n \\end{scope}\n \\end{tikzpicture}\n" - return result - - -_DOC_WRAPPER_TIKZ = r"""\documentclass{{report}} -\usepackage{{tikz}} -\usepackage{{subcaption}} - -\begin{{document}} -{content} -\end{{document}}""" - - -_FIG_WRAPPER = r"""\begin{{figure}} -{content}{caption}{label} -\end{{figure}}""" - - -_SUBFIG_WRAPPER = r""" \begin{{subfigure}}{{{size}\textwidth}} -{content}{caption}{label} - \end{{subfigure}}""" - - -def to_latex( - Gbunch, - pos="pos", - tikz_options="", - default_node_options="", - node_options="node_options", - node_label="node_label", - default_edge_options="", - edge_options="edge_options", - edge_label="edge_label", - edge_label_options="edge_label_options", - caption="", - latex_label="", - sub_captions=None, - sub_labels=None, - n_rows=1, - as_document=True, - document_wrapper=_DOC_WRAPPER_TIKZ, - figure_wrapper=_FIG_WRAPPER, - subfigure_wrapper=_SUBFIG_WRAPPER, -): - """Return latex code to draw the graph(s) in `Gbunch` - - The TikZ drawing utility in LaTeX is used to draw the graph(s). - If `Gbunch` is a graph, it is drawn in a figure environment. - If `Gbunch` is an iterable of graphs, each is drawn in a subfigure environment - within a single figure environment. - - If `as_document` is True, the figure is wrapped inside a document environment - so that the resulting string is ready to be compiled by LaTeX. Otherwise, - the string is ready for inclusion in a larger tex document using ``\\include`` - or ``\\input`` statements. - - Parameters - ========== - Gbunch : NetworkX graph or iterable of NetworkX graphs - The NetworkX graph to be drawn or an iterable of graphs - to be drawn inside subfigures of a single figure. - pos : string or list of strings - The name of the node attribute on `G` that holds the position of each node. - Positions can be sequences of length 2 with numbers for (x,y) coordinates. - They can also be strings to denote positions in TikZ style, such as (x, y) - or (angle:radius). - If a dict, it should be keyed by node to a position. - If an empty dict, a circular layout is computed by TikZ. - If you are drawing many graphs in subfigures, use a list of position dicts. - tikz_options : string - The tikzpicture options description defining the options for the picture. - Often large scale options like `[scale=2]`. - default_node_options : string - The draw options for a path of nodes. Individual node options override these. - node_options : string or dict - The name of the node attribute on `G` that holds the options for each node. - Or a dict keyed by node to a string holding the options for that node. - node_label : string or dict - The name of the node attribute on `G` that holds the node label (text) - displayed for each node. If the attribute is "" or not present, the node - itself is drawn as a string. LaTeX processing such as ``"$A_1$"`` is allowed. - Or a dict keyed by node to a string holding the label for that node. - default_edge_options : string - The options for the scope drawing all edges. The default is "[-]" for - undirected graphs and "[->]" for directed graphs. - edge_options : string or dict - The name of the edge attribute on `G` that holds the options for each edge. - If the edge is a self-loop and ``"loop" not in edge_options`` the option - "loop," is added to the options for the self-loop edge. Hence you can - use "[loop above]" explicitly, but the default is "[loop]". - Or a dict keyed by edge to a string holding the options for that edge. - edge_label : string or dict - The name of the edge attribute on `G` that holds the edge label (text) - displayed for each edge. If the attribute is "" or not present, no edge - label is drawn. - Or a dict keyed by edge to a string holding the label for that edge. - edge_label_options : string or dict - The name of the edge attribute on `G` that holds the label options for - each edge. For example, "[sloped,above,blue]". The default is no options. - Or a dict keyed by edge to a string holding the label options for that edge. - caption : string - The caption string for the figure environment - latex_label : string - The latex label used for the figure for easy referral from the main text - sub_captions : list of strings - The sub_caption string for each subfigure in the figure - sub_latex_labels : list of strings - The latex label for each subfigure in the figure - n_rows : int - The number of rows of subfigures to arrange for multiple graphs - as_document : bool - Whether to wrap the latex code in a document environment for compiling - document_wrapper : formatted text string with variable ``content``. - This text is called to evaluate the content embedded in a document - environment with a preamble setting up TikZ. - figure_wrapper : formatted text string - This text is evaluated with variables ``content``, ``caption`` and ``label``. - It wraps the content and if a caption is provided, adds the latex code for - that caption, and if a label is provided, adds the latex code for a label. - subfigure_wrapper : formatted text string - This text evaluate variables ``size``, ``content``, ``caption`` and ``label``. - It wraps the content and if a caption is provided, adds the latex code for - that caption, and if a label is provided, adds the latex code for a label. - The size is the vertical size of each row of subfigures as a fraction. - - Returns - ======= - latex_code : string - The text string which draws the desired graph(s) when compiled by LaTeX. - - See Also - ======== - write_latex - to_latex_raw - """ - if hasattr(Gbunch, "adj"): - raw = to_latex_raw( - Gbunch, - pos, - tikz_options, - default_node_options, - node_options, - node_label, - default_edge_options, - edge_options, - edge_label, - edge_label_options, - ) - else: # iterator of graphs - sbf = subfigure_wrapper - size = 1 / n_rows - - N = len(Gbunch) - if isinstance(pos, str | dict): - pos = [pos] * N - if sub_captions is None: - sub_captions = [""] * N - if sub_labels is None: - sub_labels = [""] * N - if not (len(Gbunch) == len(pos) == len(sub_captions) == len(sub_labels)): - raise nx.NetworkXError( - "length of Gbunch, sub_captions and sub_figures must agree" - ) - - raw = "" - for G, pos, subcap, sublbl in zip(Gbunch, pos, sub_captions, sub_labels): - subraw = to_latex_raw( - G, - pos, - tikz_options, - default_node_options, - node_options, - node_label, - default_edge_options, - edge_options, - edge_label, - edge_label_options, - ) - cap = f" \\caption{{{subcap}}}" if subcap else "" - lbl = f"\\label{{{sublbl}}}" if sublbl else "" - raw += sbf.format(size=size, content=subraw, caption=cap, label=lbl) - raw += "\n" - - # put raw latex code into a figure environment and optionally into a document - raw = raw[:-1] - cap = f"\n \\caption{{{caption}}}" if caption else "" - lbl = f"\\label{{{latex_label}}}" if latex_label else "" - fig = figure_wrapper.format(content=raw, caption=cap, label=lbl) - if as_document: - return document_wrapper.format(content=fig) - return fig - - -@nx.utils.open_file(1, mode="w") -def write_latex(Gbunch, path, **options): - """Write the latex code to draw the graph(s) onto `path`. - - This convenience function creates the latex drawing code as a string - and writes that to a file ready to be compiled when `as_document` is True - or ready to be ``import`` ed or ``include`` ed into your main LaTeX document. - - The `path` argument can be a string filename or a file handle to write to. - - Parameters - ---------- - Gbunch : NetworkX graph or iterable of NetworkX graphs - If Gbunch is a graph, it is drawn in a figure environment. - If Gbunch is an iterable of graphs, each is drawn in a subfigure - environment within a single figure environment. - path : filename - Filename or file handle to write to - options : dict - By default, TikZ is used with options: (others are ignored):: - - pos : string or dict or list - The name of the node attribute on `G` that holds the position of each node. - Positions can be sequences of length 2 with numbers for (x,y) coordinates. - They can also be strings to denote positions in TikZ style, such as (x, y) - or (angle:radius). - If a dict, it should be keyed by node to a position. - If an empty dict, a circular layout is computed by TikZ. - If you are drawing many graphs in subfigures, use a list of position dicts. - tikz_options : string - The tikzpicture options description defining the options for the picture. - Often large scale options like `[scale=2]`. - default_node_options : string - The draw options for a path of nodes. Individual node options override these. - node_options : string or dict - The name of the node attribute on `G` that holds the options for each node. - Or a dict keyed by node to a string holding the options for that node. - node_label : string or dict - The name of the node attribute on `G` that holds the node label (text) - displayed for each node. If the attribute is "" or not present, the node - itself is drawn as a string. LaTeX processing such as ``"$A_1$"`` is allowed. - Or a dict keyed by node to a string holding the label for that node. - default_edge_options : string - The options for the scope drawing all edges. The default is "[-]" for - undirected graphs and "[->]" for directed graphs. - edge_options : string or dict - The name of the edge attribute on `G` that holds the options for each edge. - If the edge is a self-loop and ``"loop" not in edge_options`` the option - "loop," is added to the options for the self-loop edge. Hence you can - use "[loop above]" explicitly, but the default is "[loop]". - Or a dict keyed by edge to a string holding the options for that edge. - edge_label : string or dict - The name of the edge attribute on `G` that holds the edge label (text) - displayed for each edge. If the attribute is "" or not present, no edge - label is drawn. - Or a dict keyed by edge to a string holding the label for that edge. - edge_label_options : string or dict - The name of the edge attribute on `G` that holds the label options for - each edge. For example, "[sloped,above,blue]". The default is no options. - Or a dict keyed by edge to a string holding the label options for that edge. - caption : string - The caption string for the figure environment - latex_label : string - The latex label used for the figure for easy referral from the main text - sub_captions : list of strings - The sub_caption string for each subfigure in the figure - sub_latex_labels : list of strings - The latex label for each subfigure in the figure - n_rows : int - The number of rows of subfigures to arrange for multiple graphs - as_document : bool - Whether to wrap the latex code in a document environment for compiling - document_wrapper : formatted text string with variable ``content``. - This text is called to evaluate the content embedded in a document - environment with a preamble setting up the TikZ syntax. - figure_wrapper : formatted text string - This text is evaluated with variables ``content``, ``caption`` and ``label``. - It wraps the content and if a caption is provided, adds the latex code for - that caption, and if a label is provided, adds the latex code for a label. - subfigure_wrapper : formatted text string - This text evaluate variables ``size``, ``content``, ``caption`` and ``label``. - It wraps the content and if a caption is provided, adds the latex code for - that caption, and if a label is provided, adds the latex code for a label. - The size is the vertical size of each row of subfigures as a fraction. - - See Also - ======== - to_latex - """ - path.write(to_latex(Gbunch, **options)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pydot.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pydot.py deleted file mode 100644 index 7df0c11..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pydot.py +++ /dev/null @@ -1,352 +0,0 @@ -""" -***** -Pydot -***** - -Import and export NetworkX graphs in Graphviz dot format using pydot. - -Either this module or nx_agraph can be used to interface with graphviz. - -Examples --------- ->>> G = nx.complete_graph(5) ->>> PG = nx.nx_pydot.to_pydot(G) ->>> H = nx.nx_pydot.from_pydot(PG) - -See Also --------- - - pydot: https://github.com/erocarrera/pydot - - Graphviz: https://www.graphviz.org - - DOT Language: http://www.graphviz.org/doc/info/lang.html -""" - -from locale import getpreferredencoding - -import networkx as nx -from networkx.utils import open_file - -__all__ = [ - "write_dot", - "read_dot", - "graphviz_layout", - "pydot_layout", - "to_pydot", - "from_pydot", -] - - -@open_file(1, mode="w") -def write_dot(G, path): - """Write NetworkX graph G to Graphviz dot format on path. - - Path can be a string or a file handle. - """ - P = to_pydot(G) - path.write(P.to_string()) - return - - -@open_file(0, mode="r") -@nx._dispatchable(name="pydot_read_dot", graphs=None, returns_graph=True) -def read_dot(path): - """Returns a NetworkX :class:`MultiGraph` or :class:`MultiDiGraph` from the - dot file with the passed path. - - If this file contains multiple graphs, only the first such graph is - returned. All graphs _except_ the first are silently ignored. - - Parameters - ---------- - path : str or file - Filename or file handle. - - Returns - ------- - G : MultiGraph or MultiDiGraph - A :class:`MultiGraph` or :class:`MultiDiGraph`. - - Notes - ----- - Use `G = nx.Graph(nx.nx_pydot.read_dot(path))` to return a :class:`Graph` instead of a - :class:`MultiGraph`. - """ - import pydot - - data = path.read() - - # List of one or more "pydot.Dot" instances deserialized from this file. - P_list = pydot.graph_from_dot_data(data) - - # Convert only the first such instance into a NetworkX graph. - return from_pydot(P_list[0]) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_pydot(P): - """Returns a NetworkX graph from a Pydot graph. - - Parameters - ---------- - P : Pydot graph - A graph created with Pydot - - Returns - ------- - G : NetworkX multigraph - A MultiGraph or MultiDiGraph. - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_pydot.to_pydot(K5) - >>> G = nx.nx_pydot.from_pydot(A) # return MultiGraph - - # make a Graph instead of MultiGraph - >>> G = nx.Graph(nx.nx_pydot.from_pydot(A)) - - """ - - if P.get_strict(None): # pydot bug: get_strict() shouldn't take argument - multiedges = False - else: - multiedges = True - - if P.get_type() == "graph": # undirected - if multiedges: - N = nx.MultiGraph() - else: - N = nx.Graph() - else: - if multiedges: - N = nx.MultiDiGraph() - else: - N = nx.DiGraph() - - # assign defaults - name = P.get_name().strip('"') - if name != "": - N.name = name - - # add nodes, attributes to N.node_attr - for p in P.get_node_list(): - n = p.get_name().strip('"') - if n in ("node", "graph", "edge"): - continue - N.add_node(n, **p.get_attributes()) - - # add edges - for e in P.get_edge_list(): - u = e.get_source() - v = e.get_destination() - attr = e.get_attributes() - s = [] - d = [] - - if isinstance(u, str): - s.append(u.strip('"')) - else: - for unodes in u["nodes"]: - s.append(unodes.strip('"')) - - if isinstance(v, str): - d.append(v.strip('"')) - else: - for vnodes in v["nodes"]: - d.append(vnodes.strip('"')) - - for source_node in s: - for destination_node in d: - N.add_edge(source_node, destination_node, **attr) - - # add default attributes for graph, nodes, edges - pattr = P.get_attributes() - if pattr: - N.graph["graph"] = pattr - try: - N.graph["node"] = P.get_node_defaults()[0] - except (IndexError, TypeError): - pass # N.graph['node']={} - try: - N.graph["edge"] = P.get_edge_defaults()[0] - except (IndexError, TypeError): - pass # N.graph['edge']={} - return N - - -def to_pydot(N): - """Returns a pydot graph from a NetworkX graph N. - - Parameters - ---------- - N : NetworkX graph - A graph created with NetworkX - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> P = nx.nx_pydot.to_pydot(K5) - - Notes - ----- - - """ - import pydot - - # set Graphviz graph type - if N.is_directed(): - graph_type = "digraph" - else: - graph_type = "graph" - strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() - - name = N.name - graph_defaults = N.graph.get("graph", {}) - if name == "": - P = pydot.Dot("", graph_type=graph_type, strict=strict, **graph_defaults) - else: - P = pydot.Dot( - f'"{name}"', graph_type=graph_type, strict=strict, **graph_defaults - ) - try: - P.set_node_defaults(**N.graph["node"]) - except KeyError: - pass - try: - P.set_edge_defaults(**N.graph["edge"]) - except KeyError: - pass - - for n, nodedata in N.nodes(data=True): - str_nodedata = {str(k): str(v) for k, v in nodedata.items()} - n = str(n) - p = pydot.Node(n, **str_nodedata) - P.add_node(p) - - if N.is_multigraph(): - for u, v, key, edgedata in N.edges(data=True, keys=True): - str_edgedata = {str(k): str(v) for k, v in edgedata.items() if k != "key"} - u, v = str(u), str(v) - edge = pydot.Edge(u, v, key=str(key), **str_edgedata) - P.add_edge(edge) - - else: - for u, v, edgedata in N.edges(data=True): - str_edgedata = {str(k): str(v) for k, v in edgedata.items()} - u, v = str(u), str(v) - edge = pydot.Edge(u, v, **str_edgedata) - P.add_edge(edge) - return P - - -def graphviz_layout(G, prog="neato", root=None): - """Create node positions using Pydot and Graphviz. - - Returns a dictionary of positions keyed by node. - - Parameters - ---------- - G : NetworkX Graph - The graph for which the layout is computed. - prog : string (default: 'neato') - The name of the GraphViz program to use for layout. - Options depend on GraphViz version but may include: - 'dot', 'twopi', 'fdp', 'sfdp', 'circo' - root : Node from G or None (default: None) - The node of G from which to start some layout algorithms. - - Returns - ------- - Dictionary of (x, y) positions keyed by node. - - Examples - -------- - >>> G = nx.complete_graph(4) - >>> pos = nx.nx_pydot.graphviz_layout(G) - >>> pos = nx.nx_pydot.graphviz_layout(G, prog="dot") - - Notes - ----- - This is a wrapper for pydot_layout. - """ - return pydot_layout(G=G, prog=prog, root=root) - - -def pydot_layout(G, prog="neato", root=None): - """Create node positions using :mod:`pydot` and Graphviz. - - Parameters - ---------- - G : Graph - NetworkX graph to be laid out. - prog : string (default: 'neato') - Name of the GraphViz command to use for layout. - Options depend on GraphViz version but may include: - 'dot', 'twopi', 'fdp', 'sfdp', 'circo' - root : Node from G or None (default: None) - The node of G from which to start some layout algorithms. - - Returns - ------- - dict - Dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.complete_graph(4) - >>> pos = nx.nx_pydot.pydot_layout(G) - >>> pos = nx.nx_pydot.pydot_layout(G, prog="dot") - - Notes - ----- - If you use complex node objects, they may have the same string - representation and GraphViz could treat them as the same node. - The layout may assign both nodes a single location. See Issue #1568 - If this occurs in your case, consider relabeling the nodes just - for the layout computation using something similar to:: - - H = nx.convert_node_labels_to_integers(G, label_attribute="node_label") - H_layout = nx.nx_pydot.pydot_layout(H, prog="dot") - G_layout = {H.nodes[n]["node_label"]: p for n, p in H_layout.items()} - - """ - import pydot - - P = to_pydot(G) - if root is not None: - P.set("root", str(root)) - - # List of low-level bytes comprising a string in the dot language converted - # from the passed graph with the passed external GraphViz command. - D_bytes = P.create_dot(prog=prog) - - # Unique string decoded from these bytes with the preferred locale encoding - D = str(D_bytes, encoding=getpreferredencoding()) - - if D == "": # no data returned - print(f"Graphviz layout with {prog} failed") - print() - print("To debug what happened try:") - print("P = nx.nx_pydot.to_pydot(G)") - print('P.write_dot("file.dot")') - print(f"And then run {prog} on file.dot") - return - - # List of one or more "pydot.Dot" instances deserialized from this string. - Q_list = pydot.graph_from_dot_data(D) - assert len(Q_list) == 1 - - # The first and only such instance, as guaranteed by the above assertion. - Q = Q_list[0] - - node_pos = {} - for n in G.nodes(): - str_n = str(n) - node = Q.get_node(pydot.quote_id_if_necessary(str_n)) - - if isinstance(node, list): - node = node[0] - pos = node.get_pos()[1:-1] # strip leading and trailing double quotes - if pos is not None: - xx, yy = pos.split(",") - node_pos[n] = (float(xx), float(yy)) - return node_pos diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pylab.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pylab.py deleted file mode 100644 index c4d24cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/nx_pylab.py +++ /dev/null @@ -1,1979 +0,0 @@ -""" -********** -Matplotlib -********** - -Draw networks with matplotlib. - -Examples --------- ->>> G = nx.complete_graph(5) ->>> nx.draw(G) - -See Also --------- - - :doc:`matplotlib ` - - :func:`matplotlib.pyplot.scatter` - - :obj:`matplotlib.patches.FancyArrowPatch` -""" - -import collections -import itertools -from numbers import Number - -import networkx as nx -from networkx.drawing.layout import ( - circular_layout, - forceatlas2_layout, - kamada_kawai_layout, - planar_layout, - random_layout, - shell_layout, - spectral_layout, - spring_layout, -) - -__all__ = [ - "draw", - "draw_networkx", - "draw_networkx_nodes", - "draw_networkx_edges", - "draw_networkx_labels", - "draw_networkx_edge_labels", - "draw_circular", - "draw_kamada_kawai", - "draw_random", - "draw_spectral", - "draw_spring", - "draw_planar", - "draw_shell", - "draw_forceatlas2", -] - - -def draw(G, pos=None, ax=None, **kwds): - """Draw the graph G with Matplotlib. - - Draw the graph as a simple representation with no node - labels or edge labels and using the full Matplotlib figure area - and no axis labels by default. See draw_networkx() for more - full-featured drawing that allows title, axis labels etc. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary, optional - A dictionary with nodes as keys and positions as values. - If not specified a spring layout positioning will be computed. - See :py:mod:`networkx.drawing.layout` for functions that - compute node positions. - - ax : Matplotlib Axes object, optional - Draw the graph in specified Matplotlib axes. - - kwds : optional keywords - See networkx.draw_networkx() for a description of optional keywords. - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> nx.draw(G) - >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout - - See Also - -------- - draw_networkx - draw_networkx_nodes - draw_networkx_edges - draw_networkx_labels - draw_networkx_edge_labels - - Notes - ----- - This function has the same name as pylab.draw and pyplot.draw - so beware when using `from networkx import *` - - since you might overwrite the pylab.draw function. - - With pyplot use - - >>> import matplotlib.pyplot as plt - >>> G = nx.dodecahedral_graph() - >>> nx.draw(G) # networkx draw() - >>> plt.draw() # pyplot draw() - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - """ - import matplotlib.pyplot as plt - - if ax is None: - cf = plt.gcf() - else: - cf = ax.get_figure() - cf.set_facecolor("w") - if ax is None: - if cf.axes: - ax = cf.gca() - else: - ax = cf.add_axes((0, 0, 1, 1)) - - if "with_labels" not in kwds: - kwds["with_labels"] = "labels" in kwds - - draw_networkx(G, pos=pos, ax=ax, **kwds) - ax.set_axis_off() - plt.draw_if_interactive() - return - - -def draw_networkx(G, pos=None, arrows=None, with_labels=True, **kwds): - r"""Draw the graph G using Matplotlib. - - Draw the graph with Matplotlib with options for node positions, - labeling, titles, and many other drawing features. - See draw() for simple drawing without labels or axes. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary, optional - A dictionary with nodes as keys and positions as values. - If not specified a spring layout positioning will be computed. - See :py:mod:`networkx.drawing.layout` for functions that - compute node positions. - - arrows : bool or None, optional (default=None) - If `None`, directed graphs draw arrowheads with - `~matplotlib.patches.FancyArrowPatch`, while undirected graphs draw edges - via `~matplotlib.collections.LineCollection` for speed. - If `True`, draw arrowheads with FancyArrowPatches (bendable and stylish). - If `False`, draw edges using LineCollection (linear and fast). - For directed graphs, if True draw arrowheads. - Note: Arrows will be the same color as edges. - - arrowstyle : str (default='-\|>' for directed graphs) - For directed graphs, choose the style of the arrowsheads. - For undirected graphs default to '-' - - See `matplotlib.patches.ArrowStyle` for more options. - - arrowsize : int or list (default=10) - For directed graphs, choose the size of the arrow head's length and - width. A list of values can be passed in to assign a different size for arrow head's length and width. - See `matplotlib.patches.FancyArrowPatch` for attribute `mutation_scale` - for more info. - - with_labels : bool (default=True) - Set to True to draw labels on the nodes. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - nodelist : list (default=list(G)) - Draw only specified nodes - - edgelist : list (default=list(G.edges())) - Draw only specified edges - - node_size : scalar or array (default=300) - Size of nodes. If an array is specified it must be the - same length as nodelist. - - node_color : color or array of colors (default='#1f78b4') - Node color. Can be a single color or a sequence of colors with the same - length as nodelist. Color can be string or rgb (or rgba) tuple of - floats from 0-1. If numeric values are specified they will be - mapped to colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - node_shape : string (default='o') - The shape of the node. Specification is as matplotlib.scatter - marker, one of 'so^>v>> G = nx.dodecahedral_graph() - >>> nx.draw(G) - >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout - - >>> import matplotlib.pyplot as plt - >>> limits = plt.axis("off") # turn off axis - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - - See Also - -------- - draw - draw_networkx_nodes - draw_networkx_edges - draw_networkx_labels - draw_networkx_edge_labels - """ - from inspect import signature - - import matplotlib.pyplot as plt - - # Get all valid keywords by inspecting the signatures of draw_networkx_nodes, - # draw_networkx_edges, draw_networkx_labels - - valid_node_kwds = signature(draw_networkx_nodes).parameters.keys() - valid_edge_kwds = signature(draw_networkx_edges).parameters.keys() - valid_label_kwds = signature(draw_networkx_labels).parameters.keys() - - # Create a set with all valid keywords across the three functions and - # remove the arguments of this function (draw_networkx) - valid_kwds = (valid_node_kwds | valid_edge_kwds | valid_label_kwds) - { - "G", - "pos", - "arrows", - "with_labels", - } - - if any(k not in valid_kwds for k in kwds): - invalid_args = ", ".join([k for k in kwds if k not in valid_kwds]) - raise ValueError(f"Received invalid argument(s): {invalid_args}") - - node_kwds = {k: v for k, v in kwds.items() if k in valid_node_kwds} - edge_kwds = {k: v for k, v in kwds.items() if k in valid_edge_kwds} - label_kwds = {k: v for k, v in kwds.items() if k in valid_label_kwds} - - if pos is None: - pos = nx.drawing.spring_layout(G) # default to spring layout - - draw_networkx_nodes(G, pos, **node_kwds) - draw_networkx_edges(G, pos, arrows=arrows, **edge_kwds) - if with_labels: - draw_networkx_labels(G, pos, **label_kwds) - plt.draw_if_interactive() - - -def draw_networkx_nodes( - G, - pos, - nodelist=None, - node_size=300, - node_color="#1f78b4", - node_shape="o", - alpha=None, - cmap=None, - vmin=None, - vmax=None, - ax=None, - linewidths=None, - edgecolors=None, - label=None, - margins=None, - hide_ticks=True, -): - """Draw the nodes of the graph G. - - This draws only the nodes of the graph G. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - nodelist : list (default list(G)) - Draw only specified nodes - - node_size : scalar or array (default=300) - Size of nodes. If an array it must be the same length as nodelist. - - node_color : color or array of colors (default='#1f78b4') - Node color. Can be a single color or a sequence of colors with the same - length as nodelist. Color can be string or rgb (or rgba) tuple of - floats from 0-1. If numeric values are specified they will be - mapped to colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - node_shape : string (default='o') - The shape of the node. Specification is as matplotlib.scatter - marker, one of 'so^>v>> G = nx.dodecahedral_graph() - >>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - - See Also - -------- - draw - draw_networkx - draw_networkx_edges - draw_networkx_labels - draw_networkx_edge_labels - """ - from collections.abc import Iterable - - import matplotlib as mpl - import matplotlib.collections # call as mpl.collections - import matplotlib.pyplot as plt - import numpy as np - - if ax is None: - ax = plt.gca() - - if nodelist is None: - nodelist = list(G) - - if len(nodelist) == 0: # empty nodelist, no drawing - return mpl.collections.PathCollection(None) - - try: - xy = np.asarray([pos[v] for v in nodelist]) - except KeyError as err: - raise nx.NetworkXError(f"Node {err} has no position.") from err - - if isinstance(alpha, Iterable): - node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax) - alpha = None - - if not isinstance(node_shape, np.ndarray) and not isinstance(node_shape, list): - node_shape = np.array([node_shape for _ in range(len(nodelist))]) - - for shape in np.unique(node_shape): - node_collection = ax.scatter( - xy[node_shape == shape, 0], - xy[node_shape == shape, 1], - s=node_size, - c=node_color, - marker=shape, - cmap=cmap, - vmin=vmin, - vmax=vmax, - alpha=alpha, - linewidths=linewidths, - edgecolors=edgecolors, - label=label, - ) - if hide_ticks: - ax.tick_params( - axis="both", - which="both", - bottom=False, - left=False, - labelbottom=False, - labelleft=False, - ) - - if margins is not None: - if isinstance(margins, Iterable): - ax.margins(*margins) - else: - ax.margins(margins) - - node_collection.set_zorder(2) - return node_collection - - -class FancyArrowFactory: - """Draw arrows with `matplotlib.patches.FancyarrowPatch`""" - - class ConnectionStyleFactory: - def __init__(self, connectionstyles, selfloop_height, ax=None): - import matplotlib as mpl - import matplotlib.path # call as mpl.path - import numpy as np - - self.ax = ax - self.mpl = mpl - self.np = np - self.base_connection_styles = [ - mpl.patches.ConnectionStyle(cs) for cs in connectionstyles - ] - self.n = len(self.base_connection_styles) - self.selfloop_height = selfloop_height - - def curved(self, edge_index): - return self.base_connection_styles[edge_index % self.n] - - def self_loop(self, edge_index): - def self_loop_connection(posA, posB, *args, **kwargs): - if not self.np.all(posA == posB): - raise nx.NetworkXError( - "`self_loop` connection style method" - "is only to be used for self-loops" - ) - # this is called with _screen space_ values - # so convert back to data space - data_loc = self.ax.transData.inverted().transform(posA) - v_shift = 0.1 * self.selfloop_height - h_shift = v_shift * 0.5 - # put the top of the loop first so arrow is not hidden by node - path = self.np.asarray( - [ - # 1 - [0, v_shift], - # 4 4 4 - [h_shift, v_shift], - [h_shift, 0], - [0, 0], - # 4 4 4 - [-h_shift, 0], - [-h_shift, v_shift], - [0, v_shift], - ] - ) - # Rotate self loop 90 deg. if more than 1 - # This will allow for maximum of 4 visible self loops - if edge_index % 4: - x, y = path.T - for _ in range(edge_index % 4): - x, y = y, -x - path = self.np.array([x, y]).T - return self.mpl.path.Path( - self.ax.transData.transform(data_loc + path), [1, 4, 4, 4, 4, 4, 4] - ) - - return self_loop_connection - - def __init__( - self, - edge_pos, - edgelist, - nodelist, - edge_indices, - node_size, - selfloop_height, - connectionstyle="arc3", - node_shape="o", - arrowstyle="-", - arrowsize=10, - edge_color="k", - alpha=None, - linewidth=1.0, - style="solid", - min_source_margin=0, - min_target_margin=0, - ax=None, - ): - import matplotlib as mpl - import matplotlib.patches # call as mpl.patches - import matplotlib.pyplot as plt - import numpy as np - - if isinstance(connectionstyle, str): - connectionstyle = [connectionstyle] - elif np.iterable(connectionstyle): - connectionstyle = list(connectionstyle) - else: - msg = "ConnectionStyleFactory arg `connectionstyle` must be str or iterable" - raise nx.NetworkXError(msg) - self.ax = ax - self.mpl = mpl - self.np = np - self.edge_pos = edge_pos - self.edgelist = edgelist - self.nodelist = nodelist - self.node_shape = node_shape - self.min_source_margin = min_source_margin - self.min_target_margin = min_target_margin - self.edge_indices = edge_indices - self.node_size = node_size - self.connectionstyle_factory = self.ConnectionStyleFactory( - connectionstyle, selfloop_height, ax - ) - self.arrowstyle = arrowstyle - self.arrowsize = arrowsize - self.arrow_colors = mpl.colors.colorConverter.to_rgba_array(edge_color, alpha) - self.linewidth = linewidth - self.style = style - if isinstance(arrowsize, list) and len(arrowsize) != len(edge_pos): - raise ValueError("arrowsize should have the same length as edgelist") - - def __call__(self, i): - (x1, y1), (x2, y2) = self.edge_pos[i] - shrink_source = 0 # space from source to tail - shrink_target = 0 # space from head to target - if ( - self.np.iterable(self.min_source_margin) - and not isinstance(self.min_source_margin, str) - and not isinstance(self.min_source_margin, tuple) - ): - min_source_margin = self.min_source_margin[i] - else: - min_source_margin = self.min_source_margin - - if ( - self.np.iterable(self.min_target_margin) - and not isinstance(self.min_target_margin, str) - and not isinstance(self.min_target_margin, tuple) - ): - min_target_margin = self.min_target_margin[i] - else: - min_target_margin = self.min_target_margin - - if self.np.iterable(self.node_size): # many node sizes - source, target = self.edgelist[i][:2] - source_node_size = self.node_size[self.nodelist.index(source)] - target_node_size = self.node_size[self.nodelist.index(target)] - shrink_source = self.to_marker_edge(source_node_size, self.node_shape) - shrink_target = self.to_marker_edge(target_node_size, self.node_shape) - else: - shrink_source = self.to_marker_edge(self.node_size, self.node_shape) - shrink_target = shrink_source - shrink_source = max(shrink_source, min_source_margin) - shrink_target = max(shrink_target, min_target_margin) - - # scale factor of arrow head - if isinstance(self.arrowsize, list): - mutation_scale = self.arrowsize[i] - else: - mutation_scale = self.arrowsize - - if len(self.arrow_colors) > i: - arrow_color = self.arrow_colors[i] - elif len(self.arrow_colors) == 1: - arrow_color = self.arrow_colors[0] - else: # Cycle through colors - arrow_color = self.arrow_colors[i % len(self.arrow_colors)] - - if self.np.iterable(self.linewidth): - if len(self.linewidth) > i: - linewidth = self.linewidth[i] - else: - linewidth = self.linewidth[i % len(self.linewidth)] - else: - linewidth = self.linewidth - - if ( - self.np.iterable(self.style) - and not isinstance(self.style, str) - and not isinstance(self.style, tuple) - ): - if len(self.style) > i: - linestyle = self.style[i] - else: # Cycle through styles - linestyle = self.style[i % len(self.style)] - else: - linestyle = self.style - - if x1 == x2 and y1 == y2: - connectionstyle = self.connectionstyle_factory.self_loop( - self.edge_indices[i] - ) - else: - connectionstyle = self.connectionstyle_factory.curved(self.edge_indices[i]) - - if ( - self.np.iterable(self.arrowstyle) - and not isinstance(self.arrowstyle, str) - and not isinstance(self.arrowstyle, tuple) - ): - arrowstyle = self.arrowstyle[i] - else: - arrowstyle = self.arrowstyle - - return self.mpl.patches.FancyArrowPatch( - (x1, y1), - (x2, y2), - arrowstyle=arrowstyle, - shrinkA=shrink_source, - shrinkB=shrink_target, - mutation_scale=mutation_scale, - color=arrow_color, - linewidth=linewidth, - connectionstyle=connectionstyle, - linestyle=linestyle, - zorder=1, # arrows go behind nodes - ) - - def to_marker_edge(self, marker_size, marker): - if marker in "s^>v', - For undirected graphs default to '-'. - - See `matplotlib.patches.ArrowStyle` for more options. - - arrowsize : int or list of ints(default=10) - For directed graphs, choose the size of the arrow head's length and - width. See `matplotlib.patches.FancyArrowPatch` for attribute - `mutation_scale` for more info. - - connectionstyle : string or iterable of strings (default="arc3") - Pass the connectionstyle parameter to create curved arc of rounding - radius rad. For example, connectionstyle='arc3,rad=0.2'. - See `matplotlib.patches.ConnectionStyle` and - `matplotlib.patches.FancyArrowPatch` for more info. - If Iterable, index indicates i'th edge key of MultiGraph - - node_size : scalar or array (default=300) - Size of nodes. Though the nodes are not drawn with this function, the - node size is used in determining edge positioning. - - nodelist : list, optional (default=G.nodes()) - This provides the node order for the `node_size` array (if it is an array). - - node_shape : string (default='o') - The marker used for nodes, used in determining edge positioning. - Specification is as a `matplotlib.markers` marker, e.g. one of 'so^>v>> G = nx.dodecahedral_graph() - >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) - - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)]) - >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) - >>> alphas = [0.3, 0.4, 0.5] - >>> for i, arc in enumerate(arcs): # change alpha values of arcs - ... arc.set_alpha(alphas[i]) - - The FancyArrowPatches corresponding to self-loops are not always - returned, but can always be accessed via the ``patches`` attribute of the - `matplotlib.Axes` object. - - >>> import matplotlib.pyplot as plt - >>> fig, ax = plt.subplots() - >>> G = nx.Graph([(0, 1), (0, 0)]) # Self-loop at node 0 - >>> edge_collection = nx.draw_networkx_edges(G, pos=nx.circular_layout(G), ax=ax) - >>> self_loop_fap = ax.patches[0] - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - - See Also - -------- - draw - draw_networkx - draw_networkx_nodes - draw_networkx_labels - draw_networkx_edge_labels - - """ - import warnings - - import matplotlib as mpl - import matplotlib.collections # call as mpl.collections - import matplotlib.colors # call as mpl.colors - import matplotlib.pyplot as plt - import numpy as np - - # The default behavior is to use LineCollection to draw edges for - # undirected graphs (for performance reasons) and use FancyArrowPatches - # for directed graphs. - # The `arrows` keyword can be used to override the default behavior - if arrows is None: - use_linecollection = not (G.is_directed() or G.is_multigraph()) - else: - if not isinstance(arrows, bool): - raise TypeError("Argument `arrows` must be of type bool or None") - use_linecollection = not arrows - - if isinstance(connectionstyle, str): - connectionstyle = [connectionstyle] - elif np.iterable(connectionstyle): - connectionstyle = list(connectionstyle) - else: - msg = "draw_networkx_edges arg `connectionstyle` must be str or iterable" - raise nx.NetworkXError(msg) - - # Some kwargs only apply to FancyArrowPatches. Warn users when they use - # non-default values for these kwargs when LineCollection is being used - # instead of silently ignoring the specified option - if use_linecollection: - msg = ( - "\n\nThe {0} keyword argument is not applicable when drawing edges\n" - "with LineCollection.\n\n" - "To make this warning go away, either specify `arrows=True` to\n" - "force FancyArrowPatches or use the default values.\n" - "Note that using FancyArrowPatches may be slow for large graphs.\n" - ) - if arrowstyle is not None: - warnings.warn(msg.format("arrowstyle"), category=UserWarning, stacklevel=2) - if arrowsize != 10: - warnings.warn(msg.format("arrowsize"), category=UserWarning, stacklevel=2) - if min_source_margin != 0: - warnings.warn( - msg.format("min_source_margin"), category=UserWarning, stacklevel=2 - ) - if min_target_margin != 0: - warnings.warn( - msg.format("min_target_margin"), category=UserWarning, stacklevel=2 - ) - if any(cs != "arc3" for cs in connectionstyle): - warnings.warn( - msg.format("connectionstyle"), category=UserWarning, stacklevel=2 - ) - - # NOTE: Arrowstyle modification must occur after the warnings section - if arrowstyle is None: - arrowstyle = "-|>" if G.is_directed() else "-" - - if ax is None: - ax = plt.gca() - - if edgelist is None: - edgelist = list(G.edges) # (u, v, k) for multigraph (u, v) otherwise - - if len(edgelist): - if G.is_multigraph(): - key_count = collections.defaultdict(lambda: itertools.count(0)) - edge_indices = [next(key_count[tuple(e[:2])]) for e in edgelist] - else: - edge_indices = [0] * len(edgelist) - else: # no edges! - return [] - - if nodelist is None: - nodelist = list(G.nodes()) - - # FancyArrowPatch handles color=None different from LineCollection - if edge_color is None: - edge_color = "k" - - # set edge positions - edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) - - # Check if edge_color is an array of floats and map to edge_cmap. - # This is the only case handled differently from matplotlib - if ( - np.iterable(edge_color) - and (len(edge_color) == len(edge_pos)) - and np.all([isinstance(c, Number) for c in edge_color]) - ): - if edge_cmap is not None: - assert isinstance(edge_cmap, mpl.colors.Colormap) - else: - edge_cmap = plt.get_cmap() - if edge_vmin is None: - edge_vmin = min(edge_color) - if edge_vmax is None: - edge_vmax = max(edge_color) - color_normal = mpl.colors.Normalize(vmin=edge_vmin, vmax=edge_vmax) - edge_color = [edge_cmap(color_normal(e)) for e in edge_color] - - # compute initial view - minx = np.amin(np.ravel(edge_pos[:, :, 0])) - maxx = np.amax(np.ravel(edge_pos[:, :, 0])) - miny = np.amin(np.ravel(edge_pos[:, :, 1])) - maxy = np.amax(np.ravel(edge_pos[:, :, 1])) - w = maxx - minx - h = maxy - miny - - # Self-loops are scaled by view extent, except in cases the extent - # is 0, e.g. for a single node. In this case, fall back to scaling - # by the maximum node size - selfloop_height = h if h != 0 else 0.005 * np.array(node_size).max() - fancy_arrow_factory = FancyArrowFactory( - edge_pos, - edgelist, - nodelist, - edge_indices, - node_size, - selfloop_height, - connectionstyle, - node_shape, - arrowstyle, - arrowsize, - edge_color, - alpha, - width, - style, - min_source_margin, - min_target_margin, - ax=ax, - ) - - # Draw the edges - if use_linecollection: - edge_collection = mpl.collections.LineCollection( - edge_pos, - colors=edge_color, - linewidths=width, - antialiaseds=(1,), - linestyle=style, - alpha=alpha, - ) - edge_collection.set_cmap(edge_cmap) - edge_collection.set_clim(edge_vmin, edge_vmax) - edge_collection.set_zorder(1) # edges go behind nodes - edge_collection.set_label(label) - ax.add_collection(edge_collection) - edge_viz_obj = edge_collection - - # Make sure selfloop edges are also drawn - # --------------------------------------- - selfloops_to_draw = [loop for loop in nx.selfloop_edges(G) if loop in edgelist] - if selfloops_to_draw: - edgelist_tuple = list(map(tuple, edgelist)) - arrow_collection = [] - for loop in selfloops_to_draw: - i = edgelist_tuple.index(loop) - arrow = fancy_arrow_factory(i) - arrow_collection.append(arrow) - ax.add_patch(arrow) - else: - edge_viz_obj = [] - for i in range(len(edgelist)): - arrow = fancy_arrow_factory(i) - ax.add_patch(arrow) - edge_viz_obj.append(arrow) - - # update view after drawing - padx, pady = 0.05 * w, 0.05 * h - corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) - ax.update_datalim(corners) - ax.autoscale_view() - - if hide_ticks: - ax.tick_params( - axis="both", - which="both", - bottom=False, - left=False, - labelbottom=False, - labelleft=False, - ) - - return edge_viz_obj - - -def draw_networkx_labels( - G, - pos, - labels=None, - font_size=12, - font_color="k", - font_family="sans-serif", - font_weight="normal", - alpha=None, - bbox=None, - horizontalalignment="center", - verticalalignment="center", - ax=None, - clip_on=True, - hide_ticks=True, -): - """Draw node labels on the graph G. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - labels : dictionary (default={n: n for n in G}) - Node labels in a dictionary of text labels keyed by node. - Node-keys in labels should appear as keys in `pos`. - If needed use: `{n:lab for n,lab in labels.items() if n in pos}` - - font_size : int or dictionary of nodes to ints (default=12) - Font size for text labels. - - font_color : color or dictionary of nodes to colors (default='k' black) - Font color string. Color can be string or rgb (or rgba) tuple of - floats from 0-1. - - font_weight : string or dictionary of nodes to strings (default='normal') - Font weight. - - font_family : string or dictionary of nodes to strings (default='sans-serif') - Font family. - - alpha : float or None or dictionary of nodes to floats (default=None) - The text transparency. - - bbox : Matplotlib bbox, (default is Matplotlib's ax.text default) - Specify text box properties (e.g. shape, color etc.) for node labels. - - horizontalalignment : string or array of strings (default='center') - Horizontal alignment {'center', 'right', 'left'}. If an array is - specified it must be the same length as `nodelist`. - - verticalalignment : string (default='center') - Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'}. - If an array is specified it must be the same length as `nodelist`. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - clip_on : bool (default=True) - Turn on clipping of node labels at axis boundaries - - hide_ticks : bool, optional - Hide ticks of axes. When `True` (the default), ticks and ticklabels - are removed from the axes. To set ticks and tick labels to the pyplot default, - use ``hide_ticks=False``. - - Returns - ------- - dict - `dict` of labels keyed on the nodes - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - - See Also - -------- - draw - draw_networkx - draw_networkx_nodes - draw_networkx_edges - draw_networkx_edge_labels - """ - import matplotlib.pyplot as plt - - if ax is None: - ax = plt.gca() - - if labels is None: - labels = {n: n for n in G.nodes()} - - individual_params = set() - - def check_individual_params(p_value, p_name): - if isinstance(p_value, dict): - if len(p_value) != len(labels): - raise ValueError(f"{p_name} must have the same length as labels.") - individual_params.add(p_name) - - def get_param_value(node, p_value, p_name): - if p_name in individual_params: - return p_value[node] - return p_value - - check_individual_params(font_size, "font_size") - check_individual_params(font_color, "font_color") - check_individual_params(font_weight, "font_weight") - check_individual_params(font_family, "font_family") - check_individual_params(alpha, "alpha") - - text_items = {} # there is no text collection so we'll fake one - for n, label in labels.items(): - (x, y) = pos[n] - if not isinstance(label, str): - label = str(label) # this makes "1" and 1 labeled the same - t = ax.text( - x, - y, - label, - size=get_param_value(n, font_size, "font_size"), - color=get_param_value(n, font_color, "font_color"), - family=get_param_value(n, font_family, "font_family"), - weight=get_param_value(n, font_weight, "font_weight"), - alpha=get_param_value(n, alpha, "alpha"), - horizontalalignment=horizontalalignment, - verticalalignment=verticalalignment, - transform=ax.transData, - bbox=bbox, - clip_on=clip_on, - ) - text_items[n] = t - - if hide_ticks: - ax.tick_params( - axis="both", - which="both", - bottom=False, - left=False, - labelbottom=False, - labelleft=False, - ) - - return text_items - - -def draw_networkx_edge_labels( - G, - pos, - edge_labels=None, - label_pos=0.5, - font_size=10, - font_color="k", - font_family="sans-serif", - font_weight="normal", - alpha=None, - bbox=None, - horizontalalignment="center", - verticalalignment="center", - ax=None, - rotate=True, - clip_on=True, - node_size=300, - nodelist=None, - connectionstyle="arc3", - hide_ticks=True, -): - """Draw edge labels. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - edge_labels : dictionary (default=None) - Edge labels in a dictionary of labels keyed by edge two-tuple. - Only labels for the keys in the dictionary are drawn. - - label_pos : float (default=0.5) - Position of edge label along edge (0=head, 0.5=center, 1=tail) - - font_size : int (default=10) - Font size for text labels - - font_color : color (default='k' black) - Font color string. Color can be string or rgb (or rgba) tuple of - floats from 0-1. - - font_weight : string (default='normal') - Font weight - - font_family : string (default='sans-serif') - Font family - - alpha : float or None (default=None) - The text transparency - - bbox : Matplotlib bbox, optional - Specify text box properties (e.g. shape, color etc.) for edge labels. - Default is {boxstyle='round', ec=(1.0, 1.0, 1.0), fc=(1.0, 1.0, 1.0)}. - - horizontalalignment : string (default='center') - Horizontal alignment {'center', 'right', 'left'} - - verticalalignment : string (default='center') - Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'} - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - rotate : bool (default=True) - Rotate edge labels to lie parallel to edges - - clip_on : bool (default=True) - Turn on clipping of edge labels at axis boundaries - - node_size : scalar or array (default=300) - Size of nodes. If an array it must be the same length as nodelist. - - nodelist : list, optional (default=G.nodes()) - This provides the node order for the `node_size` array (if it is an array). - - connectionstyle : string or iterable of strings (default="arc3") - Pass the connectionstyle parameter to create curved arc of rounding - radius rad. For example, connectionstyle='arc3,rad=0.2'. - See `matplotlib.patches.ConnectionStyle` and - `matplotlib.patches.FancyArrowPatch` for more info. - If Iterable, index indicates i'th edge key of MultiGraph - - hide_ticks : bool, optional - Hide ticks of axes. When `True` (the default), ticks and ticklabels - are removed from the axes. To set ticks and tick labels to the pyplot default, - use ``hide_ticks=False``. - - Returns - ------- - dict - `dict` of labels keyed by edge - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.org/documentation/latest/auto_examples/index.html - - See Also - -------- - draw - draw_networkx - draw_networkx_nodes - draw_networkx_edges - draw_networkx_labels - """ - import matplotlib as mpl - import matplotlib.pyplot as plt - import numpy as np - - class CurvedArrowText(mpl.text.Text): - def __init__( - self, - arrow, - *args, - label_pos=0.5, - labels_horizontal=False, - ax=None, - **kwargs, - ): - # Bind to FancyArrowPatch - self.arrow = arrow - # how far along the text should be on the curve, - # 0 is at start, 1 is at end etc. - self.label_pos = label_pos - self.labels_horizontal = labels_horizontal - if ax is None: - ax = plt.gca() - self.ax = ax - self.x, self.y, self.angle = self._update_text_pos_angle(arrow) - - # Create text object - super().__init__(self.x, self.y, *args, rotation=self.angle, **kwargs) - # Bind to axis - self.ax.add_artist(self) - - def _get_arrow_path_disp(self, arrow): - """ - This is part of FancyArrowPatch._get_path_in_displaycoord - It omits the second part of the method where path is converted - to polygon based on width - The transform is taken from ax, not the object, as the object - has not been added yet, and doesn't have transform - """ - dpi_cor = arrow._dpi_cor - # trans_data = arrow.get_transform() - trans_data = self.ax.transData - if arrow._posA_posB is not None: - posA = arrow._convert_xy_units(arrow._posA_posB[0]) - posB = arrow._convert_xy_units(arrow._posA_posB[1]) - (posA, posB) = trans_data.transform((posA, posB)) - _path = arrow.get_connectionstyle()( - posA, - posB, - patchA=arrow.patchA, - patchB=arrow.patchB, - shrinkA=arrow.shrinkA * dpi_cor, - shrinkB=arrow.shrinkB * dpi_cor, - ) - else: - _path = trans_data.transform_path(arrow._path_original) - # Return is in display coordinates - return _path - - def _update_text_pos_angle(self, arrow): - # Fractional label position - path_disp = self._get_arrow_path_disp(arrow) - (x1, y1), (cx, cy), (x2, y2) = path_disp.vertices - # Text position at a proportion t along the line in display coords - # default is 0.5 so text appears at the halfway point - t = self.label_pos - tt = 1 - t - x = tt**2 * x1 + 2 * t * tt * cx + t**2 * x2 - y = tt**2 * y1 + 2 * t * tt * cy + t**2 * y2 - if self.labels_horizontal: - # Horizontal text labels - angle = 0 - else: - # Labels parallel to curve - change_x = 2 * tt * (cx - x1) + 2 * t * (x2 - cx) - change_y = 2 * tt * (cy - y1) + 2 * t * (y2 - cy) - angle = (np.arctan2(change_y, change_x) / (2 * np.pi)) * 360 - # Text is "right way up" - if angle > 90: - angle -= 180 - if angle < -90: - angle += 180 - (x, y) = self.ax.transData.inverted().transform((x, y)) - return x, y, angle - - def draw(self, renderer): - # recalculate the text position and angle - self.x, self.y, self.angle = self._update_text_pos_angle(self.arrow) - self.set_position((self.x, self.y)) - self.set_rotation(self.angle) - # redraw text - super().draw(renderer) - - # use default box of white with white border - if bbox is None: - bbox = {"boxstyle": "round", "ec": (1.0, 1.0, 1.0), "fc": (1.0, 1.0, 1.0)} - - if isinstance(connectionstyle, str): - connectionstyle = [connectionstyle] - elif np.iterable(connectionstyle): - connectionstyle = list(connectionstyle) - else: - raise nx.NetworkXError( - "draw_networkx_edges arg `connectionstyle` must be" - "string or iterable of strings" - ) - - if ax is None: - ax = plt.gca() - - if edge_labels is None: - kwds = {"keys": True} if G.is_multigraph() else {} - edge_labels = {tuple(edge): d for *edge, d in G.edges(data=True, **kwds)} - # NOTHING TO PLOT - if not edge_labels: - return {} - edgelist, labels = zip(*edge_labels.items()) - - if nodelist is None: - nodelist = list(G.nodes()) - - # set edge positions - edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) - - if G.is_multigraph(): - key_count = collections.defaultdict(lambda: itertools.count(0)) - edge_indices = [next(key_count[tuple(e[:2])]) for e in edgelist] - else: - edge_indices = [0] * len(edgelist) - - # Used to determine self loop mid-point - # Note, that this will not be accurate, - # if not drawing edge_labels for all edges drawn - h = 0 - if edge_labels: - miny = np.amin(np.ravel(edge_pos[:, :, 1])) - maxy = np.amax(np.ravel(edge_pos[:, :, 1])) - h = maxy - miny - selfloop_height = h if h != 0 else 0.005 * np.array(node_size).max() - fancy_arrow_factory = FancyArrowFactory( - edge_pos, - edgelist, - nodelist, - edge_indices, - node_size, - selfloop_height, - connectionstyle, - ax=ax, - ) - - individual_params = {} - - def check_individual_params(p_value, p_name): - # TODO should this be list or array (as in a numpy array)? - if isinstance(p_value, list): - if len(p_value) != len(edgelist): - raise ValueError(f"{p_name} must have the same length as edgelist.") - individual_params[p_name] = p_value.iter() - - # Don't need to pass in an edge because these are lists, not dicts - def get_param_value(p_value, p_name): - if p_name in individual_params: - return next(individual_params[p_name]) - return p_value - - check_individual_params(font_size, "font_size") - check_individual_params(font_color, "font_color") - check_individual_params(font_weight, "font_weight") - check_individual_params(alpha, "alpha") - check_individual_params(horizontalalignment, "horizontalalignment") - check_individual_params(verticalalignment, "verticalalignment") - check_individual_params(rotate, "rotate") - check_individual_params(label_pos, "label_pos") - - text_items = {} - for i, (edge, label) in enumerate(zip(edgelist, labels)): - if not isinstance(label, str): - label = str(label) # this makes "1" and 1 labeled the same - - n1, n2 = edge[:2] - arrow = fancy_arrow_factory(i) - if n1 == n2: - connectionstyle_obj = arrow.get_connectionstyle() - posA = ax.transData.transform(pos[n1]) - path_disp = connectionstyle_obj(posA, posA) - path_data = ax.transData.inverted().transform_path(path_disp) - x, y = path_data.vertices[0] - text_items[edge] = ax.text( - x, - y, - label, - size=get_param_value(font_size, "font_size"), - color=get_param_value(font_color, "font_color"), - family=get_param_value(font_family, "font_family"), - weight=get_param_value(font_weight, "font_weight"), - alpha=get_param_value(alpha, "alpha"), - horizontalalignment=get_param_value( - horizontalalignment, "horizontalalignment" - ), - verticalalignment=get_param_value( - verticalalignment, "verticalalignment" - ), - rotation=0, - transform=ax.transData, - bbox=bbox, - zorder=1, - clip_on=clip_on, - ) - else: - text_items[edge] = CurvedArrowText( - arrow, - label, - size=get_param_value(font_size, "font_size"), - color=get_param_value(font_color, "font_color"), - family=get_param_value(font_family, "font_family"), - weight=get_param_value(font_weight, "font_weight"), - alpha=get_param_value(alpha, "alpha"), - horizontalalignment=get_param_value( - horizontalalignment, "horizontalalignment" - ), - verticalalignment=get_param_value( - verticalalignment, "verticalalignment" - ), - transform=ax.transData, - bbox=bbox, - zorder=1, - clip_on=clip_on, - label_pos=get_param_value(label_pos, "label_pos"), - labels_horizontal=not get_param_value(rotate, "rotate"), - ax=ax, - ) - - if hide_ticks: - ax.tick_params( - axis="both", - which="both", - bottom=False, - left=False, - labelbottom=False, - labelleft=False, - ) - - return text_items - - -def draw_circular(G, **kwargs): - """Draw the graph `G` with a circular layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.circular_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - The layout is computed each time this function is called. For - repeated drawing it is much more efficient to call - `~networkx.drawing.layout.circular_layout` directly and reuse the result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.circular_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.draw_circular(G) - - See Also - -------- - :func:`~networkx.drawing.layout.circular_layout` - """ - draw(G, circular_layout(G), **kwargs) - - -def draw_kamada_kawai(G, **kwargs): - """Draw the graph `G` with a Kamada-Kawai force-directed layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.kamada_kawai_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.kamada_kawai_layout` directly and reuse the - result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.kamada_kawai_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.draw_kamada_kawai(G) - - See Also - -------- - :func:`~networkx.drawing.layout.kamada_kawai_layout` - """ - draw(G, kamada_kawai_layout(G), **kwargs) - - -def draw_random(G, **kwargs): - """Draw the graph `G` with a random layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.random_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.random_layout` directly and reuse the result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.random_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> nx.draw_random(G) - - See Also - -------- - :func:`~networkx.drawing.layout.random_layout` - """ - draw(G, random_layout(G), **kwargs) - - -def draw_spectral(G, **kwargs): - """Draw the graph `G` with a spectral 2D layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.spectral_layout(G), **kwargs) - - For more information about how node positions are determined, see - `~networkx.drawing.layout.spectral_layout`. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.spectral_layout` directly and reuse the result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.spectral_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.draw_spectral(G) - - See Also - -------- - :func:`~networkx.drawing.layout.spectral_layout` - """ - draw(G, spectral_layout(G), **kwargs) - - -def draw_spring(G, **kwargs): - """Draw the graph `G` with a spring layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.spring_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - `~networkx.drawing.layout.spring_layout` is also the default layout for - `draw`, so this function is equivalent to `draw`. - - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.spring_layout` directly and reuse the result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.spring_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(20) - >>> nx.draw_spring(G) - - See Also - -------- - draw - :func:`~networkx.drawing.layout.spring_layout` - """ - draw(G, spring_layout(G), **kwargs) - - -def draw_shell(G, nlist=None, **kwargs): - """Draw networkx graph `G` with shell layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.shell_layout(G, nlist=nlist), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - nlist : list of list of nodes, optional - A list containing lists of nodes representing the shells. - Default is `None`, meaning all nodes are in a single shell. - See `~networkx.drawing.layout.shell_layout` for details. - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Notes - ----- - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.shell_layout` directly and reuse the result:: - - >>> G = nx.complete_graph(5) - >>> pos = nx.shell_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(4) - >>> shells = [[0], [1, 2, 3]] - >>> nx.draw_shell(G, nlist=shells) - - See Also - -------- - :func:`~networkx.drawing.layout.shell_layout` - """ - draw(G, shell_layout(G, nlist=nlist), **kwargs) - - -def draw_planar(G, **kwargs): - """Draw a planar networkx graph `G` with planar layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.planar_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A planar networkx graph - - kwargs : optional keywords - See `draw_networkx` for a description of optional keywords. - - Raises - ------ - NetworkXException - When `G` is not planar - - Notes - ----- - The layout is computed each time this function is called. - For repeated drawing it is much more efficient to call - `~networkx.drawing.layout.planar_layout` directly and reuse the result:: - - >>> G = nx.path_graph(5) - >>> pos = nx.planar_layout(G) - >>> nx.draw(G, pos=pos) # Draw the original graph - >>> # Draw a subgraph, reusing the same node positions - >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red") - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.draw_planar(G) - - See Also - -------- - :func:`~networkx.drawing.layout.planar_layout` - """ - draw(G, planar_layout(G), **kwargs) - - -def draw_forceatlas2(G, **kwargs): - """Draw a networkx graph with forceatlas2 layout. - - This is a convenience function equivalent to:: - - nx.draw(G, pos=nx.forceatlas2_layout(G), **kwargs) - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, forceatlas2_layout(G), **kwargs) - - -def apply_alpha(colors, alpha, elem_list, cmap=None, vmin=None, vmax=None): - """Apply an alpha (or list of alphas) to the colors provided. - - Parameters - ---------- - - colors : color string or array of floats (default='r') - Color of element. Can be a single color format string, - or a sequence of colors with the same length as nodelist. - If numeric values are specified they will be mapped to - colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - alpha : float or array of floats - Alpha values for elements. This can be a single alpha value, in - which case it will be applied to all the elements of color. Otherwise, - if it is an array, the elements of alpha will be applied to the colors - in order (cycling through alpha multiple times if necessary). - - elem_list : array of networkx objects - The list of elements which are being colored. These could be nodes, - edges or labels. - - cmap : matplotlib colormap - Color map for use if colors is a list of floats corresponding to points - on a color mapping. - - vmin, vmax : float - Minimum and maximum values for normalizing colors if a colormap is used - - Returns - ------- - - rgba_colors : numpy ndarray - Array containing RGBA format values for each of the node colours. - - """ - from itertools import cycle, islice - - import matplotlib as mpl - import matplotlib.cm # call as mpl.cm - import matplotlib.colors # call as mpl.colors - import numpy as np - - # If we have been provided with a list of numbers as long as elem_list, - # apply the color mapping. - if len(colors) == len(elem_list) and isinstance(colors[0], Number): - mapper = mpl.cm.ScalarMappable(cmap=cmap) - mapper.set_clim(vmin, vmax) - rgba_colors = mapper.to_rgba(colors) - # Otherwise, convert colors to matplotlib's RGB using the colorConverter - # object. These are converted to numpy ndarrays to be consistent with the - # to_rgba method of ScalarMappable. - else: - try: - rgba_colors = np.array([mpl.colors.colorConverter.to_rgba(colors)]) - except ValueError: - rgba_colors = np.array( - [mpl.colors.colorConverter.to_rgba(color) for color in colors] - ) - # Set the final column of the rgba_colors to have the relevant alpha values - try: - # If alpha is longer than the number of colors, resize to the number of - # elements. Also, if rgba_colors.size (the number of elements of - # rgba_colors) is the same as the number of elements, resize the array, - # to avoid it being interpreted as a colormap by scatter() - if len(alpha) > len(rgba_colors) or rgba_colors.size == len(elem_list): - rgba_colors = np.resize(rgba_colors, (len(elem_list), 4)) - rgba_colors[1:, 0] = rgba_colors[0, 0] - rgba_colors[1:, 1] = rgba_colors[0, 1] - rgba_colors[1:, 2] = rgba_colors[0, 2] - rgba_colors[:, 3] = list(islice(cycle(alpha), len(rgba_colors))) - except TypeError: - rgba_colors[:, -1] = alpha - return rgba_colors diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/baseline/test_house_with_colors.png b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/baseline/test_house_with_colors.png deleted file mode 100644 index 6c9e5bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/baseline/test_house_with_colors.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1508bda48445c23ab882f801f1c0dd0472f97ae414245c3ab1094005fda4455a -size 21918 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_agraph.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_agraph.py deleted file mode 100644 index b351a1d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_agraph.py +++ /dev/null @@ -1,241 +0,0 @@ -"""Unit tests for PyGraphviz interface.""" - -import warnings - -import pytest - -pygraphviz = pytest.importorskip("pygraphviz") - - -import networkx as nx -from networkx.utils import edges_equal, graphs_equal, nodes_equal - - -class TestAGraph: - def build_graph(self, G): - edges = [("A", "B"), ("A", "C"), ("A", "C"), ("B", "C"), ("A", "D")] - G.add_edges_from(edges) - G.add_node("E") - G.graph["metal"] = "bronze" - return G - - def assert_equal(self, G1, G2): - assert nodes_equal(G1.nodes(), G2.nodes()) - assert edges_equal(G1.edges(), G2.edges()) - assert G1.graph["metal"] == G2.graph["metal"] - - @pytest.mark.parametrize( - "G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()) - ) - def test_agraph_roundtripping(self, G, tmp_path): - G = self.build_graph(G) - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - self.assert_equal(G, H) - - fname = tmp_path / "test.dot" - nx.drawing.nx_agraph.write_dot(H, fname) - Hin = nx.nx_agraph.read_dot(fname) - self.assert_equal(H, Hin) - - fname = tmp_path / "fh_test.dot" - with open(fname, "w") as fh: - nx.drawing.nx_agraph.write_dot(H, fh) - - with open(fname) as fh: - Hin = nx.nx_agraph.read_dot(fh) - self.assert_equal(H, Hin) - - def test_from_agraph_name(self): - G = nx.Graph(name="test") - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - assert G.name == "test" - - @pytest.mark.parametrize( - "graph_class", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) - ) - def test_from_agraph_create_using(self, graph_class): - G = nx.path_graph(3) - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A, create_using=graph_class) - assert isinstance(H, graph_class) - - def test_from_agraph_named_edges(self): - # Create an AGraph from an existing (non-multi) Graph - G = nx.Graph() - G.add_nodes_from([0, 1]) - A = nx.nx_agraph.to_agraph(G) - # Add edge (+ name, given by key) to the AGraph - A.add_edge(0, 1, key="foo") - # Verify a.name roundtrips out to 'key' in from_agraph - H = nx.nx_agraph.from_agraph(A) - assert isinstance(H, nx.Graph) - assert ("0", "1", {"key": "foo"}) in H.edges(data=True) - - def test_to_agraph_with_nodedata(self): - G = nx.Graph() - G.add_node(1, color="red") - A = nx.nx_agraph.to_agraph(G) - assert dict(A.nodes()[0].attr) == {"color": "red"} - - @pytest.mark.parametrize("graph_class", (nx.Graph, nx.MultiGraph)) - def test_to_agraph_with_edgedata(self, graph_class): - G = graph_class() - G.add_nodes_from([0, 1]) - G.add_edge(0, 1, color="yellow") - A = nx.nx_agraph.to_agraph(G) - assert dict(A.edges()[0].attr) == {"color": "yellow"} - - def test_view_pygraphviz_path(self, tmp_path): - G = nx.complete_graph(3) - input_path = str(tmp_path / "graph.png") - out_path, A = nx.nx_agraph.view_pygraphviz(G, path=input_path, show=False) - assert out_path == input_path - # Ensure file is not empty - with open(input_path, "rb") as fh: - data = fh.read() - assert len(data) > 0 - - def test_view_pygraphviz_file_suffix(self, tmp_path): - G = nx.complete_graph(3) - path, A = nx.nx_agraph.view_pygraphviz(G, suffix=1, show=False) - assert path[-6:] == "_1.png" - - def test_view_pygraphviz(self): - G = nx.Graph() # "An empty graph cannot be drawn." - pytest.raises(nx.NetworkXException, nx.nx_agraph.view_pygraphviz, G) - G = nx.barbell_graph(4, 6) - nx.nx_agraph.view_pygraphviz(G, show=False) - - def test_view_pygraphviz_edgelabel(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7) - G.add_edge(2, 3, weight=8) - path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel="weight", show=False) - for edge in A.edges(): - assert edge.attr["weight"] in ("7", "8") - - def test_view_pygraphviz_callable_edgelabel(self): - G = nx.complete_graph(3) - - def foo_label(data): - return "foo" - - path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel=foo_label, show=False) - for edge in A.edges(): - assert edge.attr["label"] == "foo" - - def test_view_pygraphviz_multigraph_edgelabels(self): - G = nx.MultiGraph() - G.add_edge(0, 1, key=0, name="left_fork") - G.add_edge(0, 1, key=1, name="right_fork") - path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel="name", show=False) - edges = A.edges() - assert len(edges) == 2 - for edge in edges: - assert edge.attr["label"].strip() in ("left_fork", "right_fork") - - def test_graph_with_reserved_keywords(self): - # test attribute/keyword clash case for #1582 - # node: n - # edges: u,v - G = nx.Graph() - G = self.build_graph(G) - G.nodes["E"]["n"] = "keyword" - G.edges[("A", "B")]["u"] = "keyword" - G.edges[("A", "B")]["v"] = "keyword" - A = nx.nx_agraph.to_agraph(G) - - def test_view_pygraphviz_no_added_attrs_to_input(self): - G = nx.complete_graph(2) - path, A = nx.nx_agraph.view_pygraphviz(G, show=False) - assert G.graph == {} - - @pytest.mark.xfail(reason="known bug in clean_attrs") - def test_view_pygraphviz_leaves_input_graph_unmodified(self): - G = nx.complete_graph(2) - # Add entries to graph dict that to_agraph handles specially - G.graph["node"] = {"width": "0.80"} - G.graph["edge"] = {"fontsize": "14"} - path, A = nx.nx_agraph.view_pygraphviz(G, show=False) - assert G.graph == {"node": {"width": "0.80"}, "edge": {"fontsize": "14"}} - - def test_graph_with_AGraph_attrs(self): - G = nx.complete_graph(2) - # Add entries to graph dict that to_agraph handles specially - G.graph["node"] = {"width": "0.80"} - G.graph["edge"] = {"fontsize": "14"} - path, A = nx.nx_agraph.view_pygraphviz(G, show=False) - # Ensure user-specified values are not lost - assert dict(A.node_attr)["width"] == "0.80" - assert dict(A.edge_attr)["fontsize"] == "14" - - def test_round_trip_empty_graph(self): - G = nx.Graph() - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - # assert graphs_equal(G, H) - AA = nx.nx_agraph.to_agraph(H) - HH = nx.nx_agraph.from_agraph(AA) - assert graphs_equal(H, HH) - G.graph["graph"] = {} - G.graph["node"] = {} - G.graph["edge"] = {} - assert graphs_equal(G, HH) - - @pytest.mark.xfail(reason="integer->string node conversion in round trip") - def test_round_trip_integer_nodes(self): - G = nx.complete_graph(3) - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - assert graphs_equal(G, H) - - def test_graphviz_alias(self): - G = self.build_graph(nx.Graph()) - pos_graphviz = nx.nx_agraph.graphviz_layout(G) - pos_pygraphviz = nx.nx_agraph.pygraphviz_layout(G) - assert pos_graphviz == pos_pygraphviz - - @pytest.mark.parametrize("root", range(5)) - def test_pygraphviz_layout_root(self, root): - # NOTE: test depends on layout prog being deterministic - G = nx.complete_graph(5) - A = nx.nx_agraph.to_agraph(G) - # Get layout with root arg is not None - pygv_layout = nx.nx_agraph.pygraphviz_layout(G, prog="circo", root=root) - # Equivalent layout directly on AGraph - A.layout(args=f"-Groot={root}", prog="circo") - # Parse AGraph layout - a1_pos = tuple(float(v) for v in dict(A.get_node("1").attr)["pos"].split(",")) - assert pygv_layout[1] == a1_pos - - def test_2d_layout(self): - G = nx.Graph() - G = self.build_graph(G) - G.graph["dimen"] = 2 - pos = nx.nx_agraph.pygraphviz_layout(G, prog="neato") - pos = list(pos.values()) - assert len(pos) == 5 - assert len(pos[0]) == 2 - - def test_3d_layout(self): - G = nx.Graph() - G = self.build_graph(G) - G.graph["dimen"] = 3 - pos = nx.nx_agraph.pygraphviz_layout(G, prog="neato") - pos = list(pos.values()) - assert len(pos) == 5 - assert len(pos[0]) == 3 - - def test_no_warnings_raised(self): - # Test that no warnings are raised when Networkx graph - # is converted to Pygraphviz graph and 'pos' - # attribute is given - G = nx.Graph() - G.add_node(0, pos=(0, 0)) - G.add_node(1, pos=(1, 1)) - A = nx.nx_agraph.to_agraph(G) - with warnings.catch_warnings(record=True) as record: - A.layout() - assert len(record) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_latex.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_latex.py deleted file mode 100644 index 14ab542..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_latex.py +++ /dev/null @@ -1,292 +0,0 @@ -import pytest - -import networkx as nx - - -def test_tikz_attributes(): - G = nx.path_graph(4, create_using=nx.DiGraph) - pos = {n: (n, n) for n in G} - - G.add_edge(0, 0) - G.edges[(0, 0)]["label"] = "Loop" - G.edges[(0, 0)]["label_options"] = "midway" - - G.nodes[0]["style"] = "blue" - G.nodes[1]["style"] = "line width=3,draw" - G.nodes[2]["style"] = "circle,draw,blue!50" - G.nodes[3]["label"] = "Stop" - G.edges[(0, 1)]["label"] = "1st Step" - G.edges[(0, 1)]["label_options"] = "near end" - G.edges[(2, 3)]["label"] = "3rd Step" - G.edges[(2, 3)]["label_options"] = "near start" - G.edges[(2, 3)]["style"] = "bend left,green" - G.edges[(1, 2)]["label"] = "2nd" - G.edges[(1, 2)]["label_options"] = "pos=0.5" - G.edges[(1, 2)]["style"] = ">->,bend right,line width=3,green!90" - - output_tex = nx.to_latex( - G, - pos=pos, - as_document=False, - tikz_options="[scale=3]", - node_options="style", - edge_options="style", - node_label="label", - edge_label="label", - edge_label_options="label_options", - ) - expected_tex = r"""\begin{figure} - \begin{tikzpicture}[scale=3] - \draw - (0, 0) node[blue] (0){0} - (1, 1) node[line width=3,draw] (1){1} - (2, 2) node[circle,draw,blue!50] (2){2} - (3, 3) node (3){Stop}; - \begin{scope}[->] - \draw (0) to node[near end] {1st Step} (1); - \draw[loop,] (0) to node[midway] {Loop} (0); - \draw[>->,bend right,line width=3,green!90] (1) to node[pos=0.5] {2nd} (2); - \draw[bend left,green] (2) to node[near start] {3rd Step} (3); - \end{scope} - \end{tikzpicture} -\end{figure}""" - - assert output_tex == expected_tex - # print(output_tex) - # # Pretty way to assert that A.to_document() == expected_tex - # content_same = True - # for aa, bb in zip(expected_tex.split("\n"), output_tex.split("\n")): - # if aa != bb: - # content_same = False - # print(f"-{aa}|\n+{bb}|") - # assert content_same - - -def test_basic_multiple_graphs(): - H1 = nx.path_graph(4) - H2 = nx.complete_graph(4) - H3 = nx.path_graph(8) - H4 = nx.complete_graph(8) - captions = [ - "Path on 4 nodes", - "Complete graph on 4 nodes", - "Path on 8 nodes", - "Complete graph on 8 nodes", - ] - labels = ["fig2a", "fig2b", "fig2c", "fig2d"] - latex_code = nx.to_latex( - [H1, H2, H3, H4], - n_rows=2, - sub_captions=captions, - sub_labels=labels, - ) - # print(latex_code) - assert "begin{document}" in latex_code - assert "begin{figure}" in latex_code - assert latex_code.count("begin{subfigure}") == 4 - assert latex_code.count("tikzpicture") == 8 - assert latex_code.count("[-]") == 4 - - -def test_basic_tikz(): - expected_tex = r"""\documentclass{report} -\usepackage{tikz} -\usepackage{subcaption} - -\begin{document} -\begin{figure} - \begin{subfigure}{0.5\textwidth} - \begin{tikzpicture}[scale=2] - \draw[gray!90] - (0.749, 0.702) node[red!90] (0){0} - (1.0, -0.014) node[red!90] (1){1} - (-0.777, -0.705) node (2){2} - (-0.984, 0.042) node (3){3} - (-0.028, 0.375) node[cyan!90] (4){4} - (-0.412, 0.888) node (5){5} - (0.448, -0.856) node (6){6} - (0.003, -0.431) node[cyan!90] (7){7}; - \begin{scope}[->,gray!90] - \draw (0) to (4); - \draw (0) to (5); - \draw (0) to (6); - \draw (0) to (7); - \draw (1) to (4); - \draw (1) to (5); - \draw (1) to (6); - \draw (1) to (7); - \draw (2) to (4); - \draw (2) to (5); - \draw (2) to (6); - \draw (2) to (7); - \draw (3) to (4); - \draw (3) to (5); - \draw (3) to (6); - \draw (3) to (7); - \end{scope} - \end{tikzpicture} - \caption{My tikz number 1 of 2}\label{tikz_1_2} - \end{subfigure} - \begin{subfigure}{0.5\textwidth} - \begin{tikzpicture}[scale=2] - \draw[gray!90] - (0.749, 0.702) node[green!90] (0){0} - (1.0, -0.014) node[green!90] (1){1} - (-0.777, -0.705) node (2){2} - (-0.984, 0.042) node (3){3} - (-0.028, 0.375) node[purple!90] (4){4} - (-0.412, 0.888) node (5){5} - (0.448, -0.856) node (6){6} - (0.003, -0.431) node[purple!90] (7){7}; - \begin{scope}[->,gray!90] - \draw (0) to (4); - \draw (0) to (5); - \draw (0) to (6); - \draw (0) to (7); - \draw (1) to (4); - \draw (1) to (5); - \draw (1) to (6); - \draw (1) to (7); - \draw (2) to (4); - \draw (2) to (5); - \draw (2) to (6); - \draw (2) to (7); - \draw (3) to (4); - \draw (3) to (5); - \draw (3) to (6); - \draw (3) to (7); - \end{scope} - \end{tikzpicture} - \caption{My tikz number 2 of 2}\label{tikz_2_2} - \end{subfigure} - \caption{A graph generated with python and latex.} -\end{figure} -\end{document}""" - - edges = [ - (0, 4), - (0, 5), - (0, 6), - (0, 7), - (1, 4), - (1, 5), - (1, 6), - (1, 7), - (2, 4), - (2, 5), - (2, 6), - (2, 7), - (3, 4), - (3, 5), - (3, 6), - (3, 7), - ] - G = nx.DiGraph() - G.add_nodes_from(range(8)) - G.add_edges_from(edges) - pos = { - 0: (0.7490296171687696, 0.702353520257394), - 1: (1.0, -0.014221357723796535), - 2: (-0.7765783344161441, -0.7054170966808919), - 3: (-0.9842690223417624, 0.04177547602465483), - 4: (-0.02768523817180917, 0.3745724439551441), - 5: (-0.41154855146767433, 0.8880106515525136), - 6: (0.44780153389148264, -0.8561492709269164), - 7: (0.0032499953371383505, -0.43092436645809945), - } - - rc_node_color = {0: "red!90", 1: "red!90", 4: "cyan!90", 7: "cyan!90"} - gp_node_color = {0: "green!90", 1: "green!90", 4: "purple!90", 7: "purple!90"} - - H = G.copy() - nx.set_node_attributes(G, rc_node_color, "color") - nx.set_node_attributes(H, gp_node_color, "color") - - sub_captions = ["My tikz number 1 of 2", "My tikz number 2 of 2"] - sub_labels = ["tikz_1_2", "tikz_2_2"] - - output_tex = nx.to_latex( - [G, H], - [pos, pos], - tikz_options="[scale=2]", - default_node_options="gray!90", - default_edge_options="gray!90", - node_options="color", - sub_captions=sub_captions, - sub_labels=sub_labels, - caption="A graph generated with python and latex.", - n_rows=2, - as_document=True, - ) - - assert output_tex == expected_tex - # print(output_tex) - # # Pretty way to assert that A.to_document() == expected_tex - # content_same = True - # for aa, bb in zip(expected_tex.split("\n"), output_tex.split("\n")): - # if aa != bb: - # content_same = False - # print(f"-{aa}|\n+{bb}|") - # assert content_same - - -def test_exception_pos_single_graph(to_latex=nx.to_latex): - # smoke test that pos can be a string - G = nx.path_graph(4) - to_latex(G, pos="pos") - - # must include all nodes - pos = {0: (1, 2), 1: (0, 1), 2: (2, 1)} - with pytest.raises(nx.NetworkXError): - to_latex(G, pos) - - # must have 2 values - pos[3] = (1, 2, 3) - with pytest.raises(nx.NetworkXError): - to_latex(G, pos) - pos[3] = 2 - with pytest.raises(nx.NetworkXError): - to_latex(G, pos) - - # check that passes with 2 values - pos[3] = (3, 2) - to_latex(G, pos) - - -def test_exception_multiple_graphs(to_latex=nx.to_latex): - G = nx.path_graph(3) - pos_bad = {0: (1, 2), 1: (0, 1)} - pos_OK = {0: (1, 2), 1: (0, 1), 2: (2, 1)} - fourG = [G, G, G, G] - fourpos = [pos_OK, pos_OK, pos_OK, pos_OK] - - # input single dict to use for all graphs - to_latex(fourG, pos_OK) - with pytest.raises(nx.NetworkXError): - to_latex(fourG, pos_bad) - - # input list of dicts to use for all graphs - to_latex(fourG, fourpos) - with pytest.raises(nx.NetworkXError): - to_latex(fourG, [pos_bad, pos_bad, pos_bad, pos_bad]) - - # every pos dict must include all nodes - with pytest.raises(nx.NetworkXError): - to_latex(fourG, [pos_OK, pos_OK, pos_bad, pos_OK]) - - # test sub_captions and sub_labels (len must match Gbunch) - with pytest.raises(nx.NetworkXError): - to_latex(fourG, fourpos, sub_captions=["hi", "hi"]) - - with pytest.raises(nx.NetworkXError): - to_latex(fourG, fourpos, sub_labels=["hi", "hi"]) - - # all pass - to_latex(fourG, fourpos, sub_captions=["hi"] * 4, sub_labels=["lbl"] * 4) - - -def test_exception_multigraph(): - G = nx.path_graph(4, create_using=nx.MultiGraph) - G.add_edge(1, 2) - with pytest.raises(nx.NetworkXNotImplemented): - nx.to_latex(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_layout.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_layout.py deleted file mode 100644 index 7f0412c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_layout.py +++ /dev/null @@ -1,538 +0,0 @@ -"""Unit tests for layout functions.""" - -import pytest - -import networkx as nx - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -class TestLayout: - @classmethod - def setup_class(cls): - cls.Gi = nx.grid_2d_graph(5, 5) - cls.Gs = nx.Graph() - nx.add_path(cls.Gs, "abcdef") - cls.bigG = nx.grid_2d_graph(25, 25) # > 500 nodes for sparse - - def test_spring_fixed_without_pos(self): - G = nx.path_graph(4) - pytest.raises(ValueError, nx.spring_layout, G, fixed=[0]) - pos = {0: (1, 1), 2: (0, 0)} - pytest.raises(ValueError, nx.spring_layout, G, fixed=[0, 1], pos=pos) - nx.spring_layout(G, fixed=[0, 2], pos=pos) # No ValueError - - def test_spring_init_pos(self): - # Tests GH #2448 - import math - - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (2, 3)]) - - init_pos = {0: (0.0, 0.0)} - fixed_pos = [0] - pos = nx.fruchterman_reingold_layout(G, pos=init_pos, fixed=fixed_pos) - has_nan = any(math.isnan(c) for coords in pos.values() for c in coords) - assert not has_nan, "values should not be nan" - - def test_smoke_empty_graph(self): - G = [] - nx.random_layout(G) - nx.circular_layout(G) - nx.planar_layout(G) - nx.spring_layout(G) - nx.fruchterman_reingold_layout(G) - nx.spectral_layout(G) - nx.shell_layout(G) - nx.bipartite_layout(G, G) - nx.spiral_layout(G) - nx.multipartite_layout(G) - nx.kamada_kawai_layout(G) - - def test_smoke_int(self): - G = self.Gi - nx.random_layout(G) - nx.circular_layout(G) - nx.planar_layout(G) - nx.spring_layout(G) - nx.forceatlas2_layout(G) - nx.fruchterman_reingold_layout(G) - nx.fruchterman_reingold_layout(self.bigG) - nx.spectral_layout(G) - nx.spectral_layout(G.to_directed()) - nx.spectral_layout(self.bigG) - nx.spectral_layout(self.bigG.to_directed()) - nx.shell_layout(G) - nx.spiral_layout(G) - nx.kamada_kawai_layout(G) - nx.kamada_kawai_layout(G, dim=1) - nx.kamada_kawai_layout(G, dim=3) - nx.arf_layout(G) - - def test_smoke_string(self): - G = self.Gs - nx.random_layout(G) - nx.circular_layout(G) - nx.planar_layout(G) - nx.spring_layout(G) - nx.forceatlas2_layout(G) - nx.fruchterman_reingold_layout(G) - nx.spectral_layout(G) - nx.shell_layout(G) - nx.spiral_layout(G) - nx.kamada_kawai_layout(G) - nx.kamada_kawai_layout(G, dim=1) - nx.kamada_kawai_layout(G, dim=3) - nx.arf_layout(G) - - def check_scale_and_center(self, pos, scale, center): - center = np.array(center) - low = center - scale - hi = center + scale - vpos = np.array(list(pos.values())) - length = vpos.max(0) - vpos.min(0) - assert (length <= 2 * scale).all() - assert (vpos >= low).all() - assert (vpos <= hi).all() - - def test_scale_and_center_arg(self): - sc = self.check_scale_and_center - c = (4, 5) - G = nx.complete_graph(9) - G.add_node(9) - sc(nx.random_layout(G, center=c), scale=0.5, center=(4.5, 5.5)) - # rest can have 2*scale length: [-scale, scale] - sc(nx.spring_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.spectral_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.circular_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.shell_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.spiral_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.kamada_kawai_layout(G, scale=2, center=c), scale=2, center=c) - - c = (2, 3, 5) - sc(nx.kamada_kawai_layout(G, dim=3, scale=2, center=c), scale=2, center=c) - - def test_planar_layout_non_planar_input(self): - G = nx.complete_graph(9) - pytest.raises(nx.NetworkXException, nx.planar_layout, G) - - def test_smoke_planar_layout_embedding_input(self): - embedding = nx.PlanarEmbedding() - embedding.set_data({0: [1, 2], 1: [0, 2], 2: [0, 1]}) - nx.planar_layout(embedding) - - def test_default_scale_and_center(self): - sc = self.check_scale_and_center - c = (0, 0) - G = nx.complete_graph(9) - G.add_node(9) - sc(nx.random_layout(G), scale=0.5, center=(0.5, 0.5)) - sc(nx.spring_layout(G), scale=1, center=c) - sc(nx.spectral_layout(G), scale=1, center=c) - sc(nx.circular_layout(G), scale=1, center=c) - sc(nx.shell_layout(G), scale=1, center=c) - sc(nx.spiral_layout(G), scale=1, center=c) - sc(nx.kamada_kawai_layout(G), scale=1, center=c) - - c = (0, 0, 0) - sc(nx.kamada_kawai_layout(G, dim=3), scale=1, center=c) - - def test_circular_planar_and_shell_dim_error(self): - G = nx.path_graph(4) - pytest.raises(ValueError, nx.circular_layout, G, dim=1) - pytest.raises(ValueError, nx.shell_layout, G, dim=1) - pytest.raises(ValueError, nx.shell_layout, G, dim=3) - pytest.raises(ValueError, nx.planar_layout, G, dim=1) - pytest.raises(ValueError, nx.planar_layout, G, dim=3) - - def test_adjacency_interface_numpy(self): - A = nx.to_numpy_array(self.Gs) - pos = nx.drawing.layout._fruchterman_reingold(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._fruchterman_reingold(A, dim=3) - assert pos.shape == (6, 3) - pos = nx.drawing.layout._sparse_fruchterman_reingold(A) - assert pos.shape == (6, 2) - - def test_adjacency_interface_scipy(self): - A = nx.to_scipy_sparse_array(self.Gs, dtype="d") - pos = nx.drawing.layout._sparse_fruchterman_reingold(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._sparse_spectral(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._sparse_fruchterman_reingold(A, dim=3) - assert pos.shape == (6, 3) - - def test_single_nodes(self): - G = nx.path_graph(1) - vpos = nx.shell_layout(G) - assert not vpos[0].any() - G = nx.path_graph(4) - vpos = nx.shell_layout(G, [[0], [1, 2], [3]]) - assert not vpos[0].any() - assert vpos[3].any() # ensure node 3 not at origin (#3188) - assert np.linalg.norm(vpos[3]) <= 1 # ensure node 3 fits (#3753) - vpos = nx.shell_layout(G, [[0], [1, 2], [3]], rotate=0) - assert np.linalg.norm(vpos[3]) <= 1 # ensure node 3 fits (#3753) - - def test_smoke_initial_pos_forceatlas2(self): - pos = nx.circular_layout(self.Gi) - npos = nx.forceatlas2_layout(self.Gi, pos=pos) - - def test_smoke_initial_pos_fruchterman_reingold(self): - pos = nx.circular_layout(self.Gi) - npos = nx.fruchterman_reingold_layout(self.Gi, pos=pos) - - def test_smoke_initial_pos_arf(self): - pos = nx.circular_layout(self.Gi) - npos = nx.arf_layout(self.Gi, pos=pos) - - def test_fixed_node_fruchterman_reingold(self): - # Dense version (numpy based) - pos = nx.circular_layout(self.Gi) - npos = nx.spring_layout(self.Gi, pos=pos, fixed=[(0, 0)]) - assert tuple(pos[(0, 0)]) == tuple(npos[(0, 0)]) - # Sparse version (scipy based) - pos = nx.circular_layout(self.bigG) - npos = nx.spring_layout(self.bigG, pos=pos, fixed=[(0, 0)]) - for axis in range(2): - assert pos[(0, 0)][axis] == pytest.approx(npos[(0, 0)][axis], abs=1e-7) - - def test_center_parameter(self): - G = nx.path_graph(1) - nx.random_layout(G, center=(1, 1)) - vpos = nx.circular_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.planar_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spring_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.fruchterman_reingold_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spectral_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.shell_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spiral_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - - def test_center_wrong_dimensions(self): - G = nx.path_graph(1) - assert id(nx.spring_layout) == id(nx.fruchterman_reingold_layout) - pytest.raises(ValueError, nx.random_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.circular_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.planar_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spring_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spring_layout, G, dim=3, center=(1, 1)) - pytest.raises(ValueError, nx.spectral_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spectral_layout, G, dim=3, center=(1, 1)) - pytest.raises(ValueError, nx.shell_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spiral_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.kamada_kawai_layout, G, center=(1, 1, 1)) - - def test_empty_graph(self): - G = nx.empty_graph() - vpos = nx.random_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.circular_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.planar_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.bipartite_layout(G, G) - assert vpos == {} - vpos = nx.spring_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.fruchterman_reingold_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.spectral_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.shell_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.spiral_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.multipartite_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.kamada_kawai_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.forceatlas2_layout(G) - assert vpos == {} - vpos = nx.arf_layout(G) - assert vpos == {} - - def test_bipartite_layout(self): - G = nx.complete_bipartite_graph(3, 5) - top, bottom = nx.bipartite.sets(G) - - vpos = nx.bipartite_layout(G, top) - assert len(vpos) == len(G) - - top_x = vpos[list(top)[0]][0] - bottom_x = vpos[list(bottom)[0]][0] - for node in top: - assert vpos[node][0] == top_x - for node in bottom: - assert vpos[node][0] == bottom_x - - vpos = nx.bipartite_layout( - G, top, align="horizontal", center=(2, 2), scale=2, aspect_ratio=1 - ) - assert len(vpos) == len(G) - - top_y = vpos[list(top)[0]][1] - bottom_y = vpos[list(bottom)[0]][1] - for node in top: - assert vpos[node][1] == top_y - for node in bottom: - assert vpos[node][1] == bottom_y - - pytest.raises(ValueError, nx.bipartite_layout, G, top, align="foo") - - def test_multipartite_layout(self): - sizes = (0, 5, 7, 2, 8) - G = nx.complete_multipartite_graph(*sizes) - - vpos = nx.multipartite_layout(G) - assert len(vpos) == len(G) - - start = 0 - for n in sizes: - end = start + n - assert all(vpos[start][0] == vpos[i][0] for i in range(start + 1, end)) - start += n - - vpos = nx.multipartite_layout(G, align="horizontal", scale=2, center=(2, 2)) - assert len(vpos) == len(G) - - start = 0 - for n in sizes: - end = start + n - assert all(vpos[start][1] == vpos[i][1] for i in range(start + 1, end)) - start += n - - pytest.raises(ValueError, nx.multipartite_layout, G, align="foo") - - def test_kamada_kawai_costfn_1d(self): - costfn = nx.drawing.layout._kamada_kawai_costfn - - pos = np.array([4.0, 7.0]) - invdist = 1 / np.array([[0.1, 2.0], [2.0, 0.3]]) - - cost, grad = costfn(pos, np, invdist, meanweight=0, dim=1) - - assert cost == pytest.approx(((3 / 2.0 - 1) ** 2), abs=1e-7) - assert grad[0] == pytest.approx((-0.5), abs=1e-7) - assert grad[1] == pytest.approx(0.5, abs=1e-7) - - def check_kamada_kawai_costfn(self, pos, invdist, meanwt, dim): - costfn = nx.drawing.layout._kamada_kawai_costfn - - cost, grad = costfn(pos.ravel(), np, invdist, meanweight=meanwt, dim=dim) - - expected_cost = 0.5 * meanwt * np.sum(np.sum(pos, axis=0) ** 2) - for i in range(pos.shape[0]): - for j in range(i + 1, pos.shape[0]): - diff = np.linalg.norm(pos[i] - pos[j]) - expected_cost += (diff * invdist[i][j] - 1.0) ** 2 - - assert cost == pytest.approx(expected_cost, abs=1e-7) - - dx = 1e-4 - for nd in range(pos.shape[0]): - for dm in range(pos.shape[1]): - idx = nd * pos.shape[1] + dm - ps = pos.flatten() - - ps[idx] += dx - cplus = costfn(ps, np, invdist, meanweight=meanwt, dim=pos.shape[1])[0] - - ps[idx] -= 2 * dx - cminus = costfn(ps, np, invdist, meanweight=meanwt, dim=pos.shape[1])[0] - - assert grad[idx] == pytest.approx((cplus - cminus) / (2 * dx), abs=1e-5) - - def test_kamada_kawai_costfn(self): - invdist = 1 / np.array([[0.1, 2.1, 1.7], [2.1, 0.2, 0.6], [1.7, 0.6, 0.3]]) - meanwt = 0.3 - - # 2d - pos = np.array([[1.3, -3.2], [2.7, -0.3], [5.1, 2.5]]) - - self.check_kamada_kawai_costfn(pos, invdist, meanwt, 2) - - # 3d - pos = np.array([[0.9, 8.6, -8.7], [-10, -0.5, -7.1], [9.1, -8.1, 1.6]]) - - self.check_kamada_kawai_costfn(pos, invdist, meanwt, 3) - - def test_spiral_layout(self): - G = self.Gs - - # a lower value of resolution should result in a more compact layout - # intuitively, the total distance from the start and end nodes - # via each node in between (transiting through each) will be less, - # assuming rescaling does not occur on the computed node positions - pos_standard = np.array(list(nx.spiral_layout(G, resolution=0.35).values())) - pos_tighter = np.array(list(nx.spiral_layout(G, resolution=0.34).values())) - distances = np.linalg.norm(pos_standard[:-1] - pos_standard[1:], axis=1) - distances_tighter = np.linalg.norm(pos_tighter[:-1] - pos_tighter[1:], axis=1) - assert sum(distances) > sum(distances_tighter) - - # return near-equidistant points after the first value if set to true - pos_equidistant = np.array(list(nx.spiral_layout(G, equidistant=True).values())) - distances_equidistant = np.linalg.norm( - pos_equidistant[:-1] - pos_equidistant[1:], axis=1 - ) - assert np.allclose( - distances_equidistant[1:], distances_equidistant[-1], atol=0.01 - ) - - def test_spiral_layout_equidistant(self): - G = nx.path_graph(10) - pos = nx.spiral_layout(G, equidistant=True) - # Extract individual node positions as an array - p = np.array(list(pos.values())) - # Elementwise-distance between node positions - dist = np.linalg.norm(p[1:] - p[:-1], axis=1) - assert np.allclose(np.diff(dist), 0, atol=1e-3) - - def test_forceatlas2_layout_partial_input_test(self): - # check whether partial pos input still returns a full proper position - G = self.Gs - node = nx.utils.arbitrary_element(G) - pos = nx.circular_layout(G) - del pos[node] - pos = nx.forceatlas2_layout(G, pos=pos) - assert len(pos) == len(G) - - def test_rescale_layout_dict(self): - G = nx.empty_graph() - vpos = nx.random_layout(G, center=(1, 1)) - assert nx.rescale_layout_dict(vpos) == {} - - G = nx.empty_graph(2) - vpos = {0: (0.0, 0.0), 1: (1.0, 1.0)} - s_vpos = nx.rescale_layout_dict(vpos) - assert np.linalg.norm([sum(x) for x in zip(*s_vpos.values())]) < 1e-6 - - G = nx.empty_graph(3) - vpos = {0: (0, 0), 1: (1, 1), 2: (0.5, 0.5)} - s_vpos = nx.rescale_layout_dict(vpos) - - expectation = { - 0: np.array((-1, -1)), - 1: np.array((1, 1)), - 2: np.array((0, 0)), - } - for k, v in expectation.items(): - assert (s_vpos[k] == v).all() - s_vpos = nx.rescale_layout_dict(vpos, scale=2) - expectation = { - 0: np.array((-2, -2)), - 1: np.array((2, 2)), - 2: np.array((0, 0)), - } - for k, v in expectation.items(): - assert (s_vpos[k] == v).all() - - def test_arf_layout_partial_input_test(self): - # Checks whether partial pos input still returns a proper position. - G = self.Gs - node = nx.utils.arbitrary_element(G) - pos = nx.circular_layout(G) - del pos[node] - pos = nx.arf_layout(G, pos=pos) - assert len(pos) == len(G) - - def test_arf_layout_negative_a_check(self): - """ - Checks input parameters correctly raises errors. For example, `a` should be larger than 1 - """ - G = self.Gs - pytest.raises(ValueError, nx.arf_layout, G=G, a=-1) - - def test_smoke_seed_input(self): - G = self.Gs - nx.random_layout(G, seed=42) - nx.spring_layout(G, seed=42) - nx.arf_layout(G, seed=42) - nx.forceatlas2_layout(G, seed=42) - - -def test_multipartite_layout_nonnumeric_partition_labels(): - """See gh-5123.""" - G = nx.Graph() - G.add_node(0, subset="s0") - G.add_node(1, subset="s0") - G.add_node(2, subset="s1") - G.add_node(3, subset="s1") - G.add_edges_from([(0, 2), (0, 3), (1, 2)]) - pos = nx.multipartite_layout(G) - assert len(pos) == len(G) - - -def test_multipartite_layout_layer_order(): - """Return the layers in sorted order if the layers of the multipartite - graph are sortable. See gh-5691""" - G = nx.Graph() - node_group = dict(zip(("a", "b", "c", "d", "e"), (2, 3, 1, 2, 4))) - for node, layer in node_group.items(): - G.add_node(node, subset=layer) - - # Horizontal alignment, therefore y-coord determines layers - pos = nx.multipartite_layout(G, align="horizontal") - - layers = nx.utils.groups(node_group) - pos_from_layers = nx.multipartite_layout(G, align="horizontal", subset_key=layers) - for (n1, p1), (n2, p2) in zip(pos.items(), pos_from_layers.items()): - assert n1 == n2 and (p1 == p2).all() - - # Nodes "a" and "d" are in the same layer - assert pos["a"][-1] == pos["d"][-1] - # positions should be sorted according to layer - assert pos["c"][-1] < pos["a"][-1] < pos["b"][-1] < pos["e"][-1] - - # Make sure that multipartite_layout still works when layers are not sortable - G.nodes["a"]["subset"] = "layer_0" # Can't sort mixed strs/ints - pos_nosort = nx.multipartite_layout(G) # smoke test: this should not raise - assert pos_nosort.keys() == pos.keys() - - -def _num_nodes_per_bfs_layer(pos): - """Helper function to extract the number of nodes in each layer of bfs_layout""" - x = np.array(list(pos.values()))[:, 0] # node positions in layered dimension - _, layer_count = np.unique(x, return_counts=True) - return layer_count - - -@pytest.mark.parametrize("n", range(2, 7)) -def test_bfs_layout_complete_graph(n): - """The complete graph should result in two layers: the starting node and - a second layer containing all neighbors.""" - G = nx.complete_graph(n) - pos = nx.bfs_layout(G, start=0) - assert np.array_equal(_num_nodes_per_bfs_layer(pos), [1, n - 1]) - - -def test_bfs_layout_barbell(): - G = nx.barbell_graph(5, 3) - # Start in one of the "bells" - pos = nx.bfs_layout(G, start=0) - # start, bell-1, [1] * len(bar)+1, bell-1 - expected_nodes_per_layer = [1, 4, 1, 1, 1, 1, 4] - assert np.array_equal(_num_nodes_per_bfs_layer(pos), expected_nodes_per_layer) - # Start in the other "bell" - expect same layer pattern - pos = nx.bfs_layout(G, start=12) - assert np.array_equal(_num_nodes_per_bfs_layer(pos), expected_nodes_per_layer) - # Starting in the center of the bar, expect layers to be symmetric - pos = nx.bfs_layout(G, start=6) - # Expected layers: {6 (start)}, {5, 7}, {4, 8}, {8 nodes from remainder of bells} - expected_nodes_per_layer = [1, 2, 2, 8] - assert np.array_equal(_num_nodes_per_bfs_layer(pos), expected_nodes_per_layer) - - -def test_bfs_layout_disconnected(): - G = nx.complete_graph(5) - G.add_edges_from([(10, 11), (11, 12)]) - with pytest.raises(nx.NetworkXError, match="bfs_layout didn't include all nodes"): - nx.bfs_layout(G, start=0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pydot.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pydot.py deleted file mode 100644 index acf93d7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pydot.py +++ /dev/null @@ -1,146 +0,0 @@ -"""Unit tests for pydot drawing functions.""" - -from io import StringIO - -import pytest - -import networkx as nx -from networkx.utils import graphs_equal - -pydot = pytest.importorskip("pydot") - - -class TestPydot: - @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) - @pytest.mark.parametrize("prog", ("neato", "dot")) - def test_pydot(self, G, prog, tmp_path): - """ - Validate :mod:`pydot`-based usage of the passed NetworkX graph with the - passed basename of an external GraphViz command (e.g., `dot`, `neato`). - """ - - # Set the name of this graph to... "G". Failing to do so will - # subsequently trip an assertion expecting this name. - G.graph["name"] = "G" - - # Add arbitrary nodes and edges to the passed empty graph. - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("A", "D")]) - G.add_node("E") - - # Validate layout of this graph with the passed GraphViz command. - graph_layout = nx.nx_pydot.pydot_layout(G, prog=prog) - assert isinstance(graph_layout, dict) - - # Convert this graph into a "pydot.Dot" instance. - P = nx.nx_pydot.to_pydot(G) - - # Convert this "pydot.Dot" instance back into a graph of the same type. - G2 = G.__class__(nx.nx_pydot.from_pydot(P)) - - # Validate the original and resulting graphs to be the same. - assert graphs_equal(G, G2) - - fname = tmp_path / "out.dot" - - # Serialize this "pydot.Dot" instance to a temporary file in dot format - P.write_raw(fname) - - # Deserialize a list of new "pydot.Dot" instances back from this file. - Pin_list = pydot.graph_from_dot_file(path=fname, encoding="utf-8") - - # Validate this file to contain only one graph. - assert len(Pin_list) == 1 - - # The single "pydot.Dot" instance deserialized from this file. - Pin = Pin_list[0] - - # Sorted list of all nodes in the original "pydot.Dot" instance. - n1 = sorted(p.get_name() for p in P.get_node_list()) - - # Sorted list of all nodes in the deserialized "pydot.Dot" instance. - n2 = sorted(p.get_name() for p in Pin.get_node_list()) - - # Validate these instances to contain the same nodes. - assert n1 == n2 - - # Sorted list of all edges in the original "pydot.Dot" instance. - e1 = sorted((e.get_source(), e.get_destination()) for e in P.get_edge_list()) - - # Sorted list of all edges in the original "pydot.Dot" instance. - e2 = sorted((e.get_source(), e.get_destination()) for e in Pin.get_edge_list()) - - # Validate these instances to contain the same edges. - assert e1 == e2 - - # Deserialize a new graph of the same type back from this file. - Hin = nx.nx_pydot.read_dot(fname) - Hin = G.__class__(Hin) - - # Validate the original and resulting graphs to be the same. - assert graphs_equal(G, Hin) - - def test_read_write(self): - G = nx.MultiGraph() - G.graph["name"] = "G" - G.add_edge("1", "2", key="0") # read assumes strings - fh = StringIO() - nx.nx_pydot.write_dot(G, fh) - fh.seek(0) - H = nx.nx_pydot.read_dot(fh) - assert graphs_equal(G, H) - - -def test_pydot_issue_7581(tmp_path): - """Validate that `nx_pydot.pydot_layout` handles nodes - with characters like "\n", " ". - - Those characters cause `pydot` to escape and quote them on output, - which caused #7581. - """ - G = nx.Graph() - G.add_edges_from([("A\nbig test", "B"), ("A\nbig test", "C"), ("B", "C")]) - - graph_layout = nx.nx_pydot.pydot_layout(G, prog="dot") - assert isinstance(graph_layout, dict) - - # Convert the graph to pydot and back into a graph. There should be no difference. - P = nx.nx_pydot.to_pydot(G) - G2 = nx.Graph(nx.nx_pydot.from_pydot(P)) - assert graphs_equal(G, G2) - - -@pytest.mark.parametrize( - "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] -) -def test_hashable_pydot(graph_type): - # gh-5790 - G = graph_type() - G.add_edge("5", frozenset([1]), t='"Example:A"', l=False) - G.add_edge("1", 2, w=True, t=("node1",), l=frozenset(["node1"])) - G.add_edge("node", (3, 3), w="string") - - assert [ - {"t": '"Example:A"', "l": "False"}, - {"w": "True", "t": "('node1',)", "l": "frozenset({'node1'})"}, - {"w": "string"}, - ] == [ - attr - for _, _, attr in nx.nx_pydot.from_pydot(nx.nx_pydot.to_pydot(G)).edges.data() - ] - - assert {str(i) for i in G.nodes()} == set( - nx.nx_pydot.from_pydot(nx.nx_pydot.to_pydot(G)).nodes - ) - - -def test_pydot_numerical_name(): - G = nx.Graph() - G.add_edges_from([("A", "B"), (0, 1)]) - graph_layout = nx.nx_pydot.pydot_layout(G, prog="dot") - assert isinstance(graph_layout, dict) - assert "0" not in graph_layout - assert 0 in graph_layout - assert "1" not in graph_layout - assert 1 in graph_layout - assert "A" in graph_layout - assert "B" in graph_layout diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pylab.py b/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pylab.py deleted file mode 100644 index c9931db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/drawing/tests/test_pylab.py +++ /dev/null @@ -1,1029 +0,0 @@ -"""Unit tests for matplotlib drawing functions.""" - -import itertools -import os -import warnings - -import pytest - -mpl = pytest.importorskip("matplotlib") -np = pytest.importorskip("numpy") -mpl.use("PS") -plt = pytest.importorskip("matplotlib.pyplot") -plt.rcParams["text.usetex"] = False - - -import networkx as nx - -barbell = nx.barbell_graph(4, 6) - - -def test_draw(): - try: - functions = [ - nx.draw_circular, - nx.draw_kamada_kawai, - nx.draw_planar, - nx.draw_random, - nx.draw_spectral, - nx.draw_spring, - nx.draw_shell, - ] - options = [{"node_color": "black", "node_size": 100, "width": 3}] - for function, option in itertools.product(functions, options): - function(barbell, **option) - plt.savefig("test.ps") - except ModuleNotFoundError: # draw_kamada_kawai requires scipy - pass - finally: - try: - os.unlink("test.ps") - except OSError: - pass - - -def test_draw_shell_nlist(): - try: - nlist = [list(range(4)), list(range(4, 10)), list(range(10, 14))] - nx.draw_shell(barbell, nlist=nlist) - plt.savefig("test.ps") - finally: - try: - os.unlink("test.ps") - except OSError: - pass - - -def test_edge_colormap(): - colors = range(barbell.number_of_edges()) - nx.draw_spring( - barbell, edge_color=colors, width=4, edge_cmap=plt.cm.Blues, with_labels=True - ) - # plt.show() - - -def test_arrows(): - nx.draw_spring(barbell.to_directed()) - # plt.show() - - -@pytest.mark.parametrize( - ("edge_color", "expected"), - ( - (None, "black"), # Default - ("r", "red"), # Non-default color string - (["r"], "red"), # Single non-default color in a list - ((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple - ([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list - ((0, 1, 0, 1), "lime"), # single color as rgba tuple - ([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list - ("#0000ff", "blue"), # single color hex code - (["#0000ff"], "blue"), # hex code in list - ), -) -@pytest.mark.parametrize("edgelist", (None, [(0, 1)])) -def test_single_edge_color_undirected(edge_color, expected, edgelist): - """Tests ways of specifying all edges have a single color for edges - drawn with a LineCollection""" - - G = nx.path_graph(3) - drawn_edges = nx.draw_networkx_edges( - G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color - ) - assert mpl.colors.same_color(drawn_edges.get_color(), expected) - - -@pytest.mark.parametrize( - ("edge_color", "expected"), - ( - (None, "black"), # Default - ("r", "red"), # Non-default color string - (["r"], "red"), # Single non-default color in a list - ((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple - ([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list - ((0, 1, 0, 1), "lime"), # single color as rgba tuple - ([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list - ("#0000ff", "blue"), # single color hex code - (["#0000ff"], "blue"), # hex code in list - ), -) -@pytest.mark.parametrize("edgelist", (None, [(0, 1)])) -def test_single_edge_color_directed(edge_color, expected, edgelist): - """Tests ways of specifying all edges have a single color for edges drawn - with FancyArrowPatches""" - - G = nx.path_graph(3, create_using=nx.DiGraph) - drawn_edges = nx.draw_networkx_edges( - G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color - ) - for fap in drawn_edges: - assert mpl.colors.same_color(fap.get_edgecolor(), expected) - - -def test_edge_color_tuple_interpretation(): - """If edge_color is a sequence with the same length as edgelist, then each - value in edge_color is mapped onto each edge via colormap.""" - G = nx.path_graph(6, create_using=nx.DiGraph) - pos = {n: (n, n) for n in range(len(G))} - - # num edges != 3 or 4 --> edge_color interpreted as rgb(a) - for ec in ((0, 0, 1), (0, 0, 1, 1)): - # More than 4 edges - drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=ec) - for fap in drawn_edges: - assert mpl.colors.same_color(fap.get_edgecolor(), ec) - # Fewer than 3 edges - drawn_edges = nx.draw_networkx_edges( - G, pos, edgelist=[(0, 1), (1, 2)], edge_color=ec - ) - for fap in drawn_edges: - assert mpl.colors.same_color(fap.get_edgecolor(), ec) - - # num edges == 3, len(edge_color) == 4: interpreted as rgba - drawn_edges = nx.draw_networkx_edges( - G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1, 1) - ) - for fap in drawn_edges: - assert mpl.colors.same_color(fap.get_edgecolor(), "blue") - - # num edges == 4, len(edge_color) == 3: interpreted as rgb - drawn_edges = nx.draw_networkx_edges( - G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1) - ) - for fap in drawn_edges: - assert mpl.colors.same_color(fap.get_edgecolor(), "blue") - - # num edges == len(edge_color) == 3: interpreted with cmap, *not* as rgb - drawn_edges = nx.draw_networkx_edges( - G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1) - ) - assert mpl.colors.same_color( - drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor() - ) - for fap in drawn_edges: - assert not mpl.colors.same_color(fap.get_edgecolor(), "blue") - - # num edges == len(edge_color) == 4: interpreted with cmap, *not* as rgba - drawn_edges = nx.draw_networkx_edges( - G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1, 1) - ) - assert mpl.colors.same_color( - drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor() - ) - assert mpl.colors.same_color( - drawn_edges[2].get_edgecolor(), drawn_edges[3].get_edgecolor() - ) - for fap in drawn_edges: - assert not mpl.colors.same_color(fap.get_edgecolor(), "blue") - - -def test_fewer_edge_colors_than_num_edges_directed(): - """Test that the edge colors are cycled when there are fewer specified - colors than edges.""" - G = barbell.to_directed() - pos = nx.random_layout(barbell) - edgecolors = ("r", "g", "b") - drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors) - for fap, expected in zip(drawn_edges, itertools.cycle(edgecolors)): - assert mpl.colors.same_color(fap.get_edgecolor(), expected) - - -def test_more_edge_colors_than_num_edges_directed(): - """Test that extra edge colors are ignored when there are more specified - colors than edges.""" - G = nx.path_graph(4, create_using=nx.DiGraph) # 3 edges - pos = nx.random_layout(barbell) - edgecolors = ("r", "g", "b", "c") # 4 edge colors - drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors) - for fap, expected in zip(drawn_edges, edgecolors[:-1]): - assert mpl.colors.same_color(fap.get_edgecolor(), expected) - - -def test_edge_color_string_with_global_alpha_undirected(): - edge_collection = nx.draw_networkx_edges( - barbell, - pos=nx.random_layout(barbell), - edgelist=[(0, 1), (1, 2)], - edge_color="purple", - alpha=0.2, - ) - ec = edge_collection.get_color().squeeze() # as rgba tuple - assert len(edge_collection.get_paths()) == 2 - assert mpl.colors.same_color(ec[:-1], "purple") - assert ec[-1] == 0.2 - - -def test_edge_color_string_with_global_alpha_directed(): - drawn_edges = nx.draw_networkx_edges( - barbell.to_directed(), - pos=nx.random_layout(barbell), - edgelist=[(0, 1), (1, 2)], - edge_color="purple", - alpha=0.2, - ) - assert len(drawn_edges) == 2 - for fap in drawn_edges: - ec = fap.get_edgecolor() # As rgba tuple - assert mpl.colors.same_color(ec[:-1], "purple") - assert ec[-1] == 0.2 - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph)) -def test_edge_width_default_value(graph_type): - """Test the default linewidth for edges drawn either via LineCollection or - FancyArrowPatches.""" - G = nx.path_graph(2, create_using=graph_type) - pos = {n: (n, n) for n in range(len(G))} - drawn_edges = nx.draw_networkx_edges(G, pos) - if isinstance(drawn_edges, list): # directed case: list of FancyArrowPatch - drawn_edges = drawn_edges[0] - assert drawn_edges.get_linewidth() == 1 - - -@pytest.mark.parametrize( - ("edgewidth", "expected"), - ( - (3, 3), # single-value, non-default - ([3], 3), # Single value as a list - ), -) -def test_edge_width_single_value_undirected(edgewidth, expected): - G = nx.path_graph(4) - pos = {n: (n, n) for n in range(len(G))} - drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth) - assert len(drawn_edges.get_paths()) == 3 - assert drawn_edges.get_linewidth() == expected - - -@pytest.mark.parametrize( - ("edgewidth", "expected"), - ( - (3, 3), # single-value, non-default - ([3], 3), # Single value as a list - ), -) -def test_edge_width_single_value_directed(edgewidth, expected): - G = nx.path_graph(4, create_using=nx.DiGraph) - pos = {n: (n, n) for n in range(len(G))} - drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth) - assert len(drawn_edges) == 3 - for fap in drawn_edges: - assert fap.get_linewidth() == expected - - -@pytest.mark.parametrize( - "edgelist", - ( - [(0, 1), (1, 2), (2, 3)], # one width specification per edge - None, # fewer widths than edges - widths cycle - [(0, 1), (1, 2)], # More widths than edges - unused widths ignored - ), -) -def test_edge_width_sequence(edgelist): - G = barbell.to_directed() - pos = nx.random_layout(G) - widths = (0.5, 2.0, 12.0) - drawn_edges = nx.draw_networkx_edges(G, pos, edgelist=edgelist, width=widths) - for fap, expected_width in zip(drawn_edges, itertools.cycle(widths)): - assert fap.get_linewidth() == expected_width - - -def test_edge_color_with_edge_vmin_vmax(): - """Test that edge_vmin and edge_vmax properly set the dynamic range of the - color map when num edges == len(edge_colors).""" - G = nx.path_graph(3, create_using=nx.DiGraph) - pos = nx.random_layout(G) - # Extract colors from the original (unscaled) colormap - drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=[0, 1.0]) - orig_colors = [e.get_edgecolor() for e in drawn_edges] - # Colors from scaled colormap - drawn_edges = nx.draw_networkx_edges( - G, pos, edge_color=[0.2, 0.8], edge_vmin=0.2, edge_vmax=0.8 - ) - scaled_colors = [e.get_edgecolor() for e in drawn_edges] - assert mpl.colors.same_color(orig_colors, scaled_colors) - - -def test_directed_edges_linestyle_default(): - """Test default linestyle for edges drawn with FancyArrowPatches.""" - G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges - pos = {n: (n, n) for n in range(len(G))} - - # edge with default style - drawn_edges = nx.draw_networkx_edges(G, pos) - assert len(drawn_edges) == 3 - for fap in drawn_edges: - assert fap.get_linestyle() == "solid" - - -@pytest.mark.parametrize( - "style", - ( - "dashed", # edge with string style - "--", # edge with simplified string style - (1, (1, 1)), # edge with (offset, onoffseq) style - ), -) -def test_directed_edges_linestyle_single_value(style): - """Tests support for specifying linestyles with a single value to be applied to - all edges in ``draw_networkx_edges`` for FancyArrowPatch outputs - (e.g. directed edges).""" - - G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges - pos = {n: (n, n) for n in range(len(G))} - - drawn_edges = nx.draw_networkx_edges(G, pos, style=style) - assert len(drawn_edges) == 3 - for fap in drawn_edges: - assert fap.get_linestyle() == style - - -@pytest.mark.parametrize( - "style_seq", - ( - ["dashed"], # edge with string style in list - ["--"], # edge with simplified string style in list - [(1, (1, 1))], # edge with (offset, onoffseq) style in list - ["--", "-", ":"], # edges with styles for each edge - ["--", "-"], # edges with fewer styles than edges (styles cycle) - ["--", "-", ":", "-."], # edges with more styles than edges (extra unused) - ), -) -def test_directed_edges_linestyle_sequence(style_seq): - """Tests support for specifying linestyles with sequences in - ``draw_networkx_edges`` for FancyArrowPatch outputs (e.g. directed edges).""" - - G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges - pos = {n: (n, n) for n in range(len(G))} - - drawn_edges = nx.draw_networkx_edges(G, pos, style=style_seq) - assert len(drawn_edges) == 3 - for fap, style in zip(drawn_edges, itertools.cycle(style_seq)): - assert fap.get_linestyle() == style - - -def test_return_types(): - from matplotlib.collections import LineCollection, PathCollection - from matplotlib.patches import FancyArrowPatch - - G = nx.cubical_graph(nx.Graph) - dG = nx.cubical_graph(nx.DiGraph) - pos = nx.spring_layout(G) - dpos = nx.spring_layout(dG) - # nodes - nodes = nx.draw_networkx_nodes(G, pos) - assert isinstance(nodes, PathCollection) - # edges - edges = nx.draw_networkx_edges(dG, dpos, arrows=True) - assert isinstance(edges, list) - if len(edges) > 0: - assert isinstance(edges[0], FancyArrowPatch) - edges = nx.draw_networkx_edges(dG, dpos, arrows=False) - assert isinstance(edges, LineCollection) - edges = nx.draw_networkx_edges(G, dpos, arrows=None) - assert isinstance(edges, LineCollection) - edges = nx.draw_networkx_edges(dG, pos, arrows=None) - assert isinstance(edges, list) - if len(edges) > 0: - assert isinstance(edges[0], FancyArrowPatch) - - -def test_labels_and_colors(): - G = nx.cubical_graph() - pos = nx.spring_layout(G) # positions for all nodes - # nodes - nx.draw_networkx_nodes( - G, pos, nodelist=[0, 1, 2, 3], node_color="r", node_size=500, alpha=0.75 - ) - nx.draw_networkx_nodes( - G, - pos, - nodelist=[4, 5, 6, 7], - node_color="b", - node_size=500, - alpha=[0.25, 0.5, 0.75, 1.0], - ) - # edges - nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5) - nx.draw_networkx_edges( - G, - pos, - edgelist=[(0, 1), (1, 2), (2, 3), (3, 0)], - width=8, - alpha=0.5, - edge_color="r", - ) - nx.draw_networkx_edges( - G, - pos, - edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)], - width=8, - alpha=0.5, - edge_color="b", - ) - nx.draw_networkx_edges( - G, - pos, - edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)], - arrows=True, - min_source_margin=0.5, - min_target_margin=0.75, - width=8, - edge_color="b", - ) - # some math labels - labels = {} - labels[0] = r"$a$" - labels[1] = r"$b$" - labels[2] = r"$c$" - labels[3] = r"$d$" - labels[4] = r"$\alpha$" - labels[5] = r"$\beta$" - labels[6] = r"$\gamma$" - labels[7] = r"$\delta$" - colors = {n: "k" if n % 2 == 0 else "r" for n in range(8)} - nx.draw_networkx_labels(G, pos, labels, font_size=16) - nx.draw_networkx_labels(G, pos, labels, font_size=16, font_color=colors) - nx.draw_networkx_edge_labels(G, pos, edge_labels=None, rotate=False) - nx.draw_networkx_edge_labels(G, pos, edge_labels={(4, 5): "4-5"}) - # plt.show() - - -@pytest.mark.mpl_image_compare -def test_house_with_colors(): - G = nx.house_graph() - # explicitly set positions - fig, ax = plt.subplots() - pos = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0.5, 2.0)} - - # Plot nodes with different properties for the "wall" and "roof" nodes - nx.draw_networkx_nodes( - G, - pos, - node_size=3000, - nodelist=[0, 1, 2, 3], - node_color="tab:blue", - ) - nx.draw_networkx_nodes( - G, pos, node_size=2000, nodelist=[4], node_color="tab:orange" - ) - nx.draw_networkx_edges(G, pos, alpha=0.5, width=6) - # Customize axes - ax.margins(0.11) - plt.tight_layout() - plt.axis("off") - return fig - - -def test_axes(): - fig, ax = plt.subplots() - nx.draw(barbell, ax=ax) - nx.draw_networkx_edge_labels(barbell, nx.circular_layout(barbell), ax=ax) - - -def test_empty_graph(): - G = nx.Graph() - nx.draw(G) - - -def test_draw_empty_nodes_return_values(): - # See Issue #3833 - import matplotlib.collections # call as mpl.collections - - G = nx.Graph([(1, 2), (2, 3)]) - DG = nx.DiGraph([(1, 2), (2, 3)]) - pos = nx.circular_layout(G) - assert isinstance( - nx.draw_networkx_nodes(G, pos, nodelist=[]), mpl.collections.PathCollection - ) - assert isinstance( - nx.draw_networkx_nodes(DG, pos, nodelist=[]), mpl.collections.PathCollection - ) - - # drawing empty edges used to return an empty LineCollection or empty list. - # Now it is always an empty list (because edges are now lists of FancyArrows) - assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=True) == [] - assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=False) == [] - assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=False) == [] - assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=True) == [] - - -def test_multigraph_edgelist_tuples(): - # See Issue #3295 - G = nx.path_graph(3, create_using=nx.MultiDiGraph) - nx.draw_networkx(G, edgelist=[(0, 1, 0)]) - nx.draw_networkx(G, edgelist=[(0, 1, 0)], node_size=[10, 20, 0]) - - -def test_alpha_iter(): - pos = nx.random_layout(barbell) - fig = plt.figure() - # with fewer alpha elements than nodes - fig.add_subplot(131) # Each test in a new axis object - nx.draw_networkx_nodes(barbell, pos, alpha=[0.1, 0.2]) - # with equal alpha elements and nodes - num_nodes = len(barbell.nodes) - alpha = [x / num_nodes for x in range(num_nodes)] - colors = range(num_nodes) - fig.add_subplot(132) - nx.draw_networkx_nodes(barbell, pos, node_color=colors, alpha=alpha) - # with more alpha elements than nodes - alpha.append(1) - fig.add_subplot(133) - nx.draw_networkx_nodes(barbell, pos, alpha=alpha) - - -def test_multiple_node_shapes(): - G = nx.path_graph(4) - ax = plt.figure().add_subplot(111) - nx.draw(G, node_shape=["o", "h", "s", "^"], ax=ax) - scatters = [ - s for s in ax.get_children() if isinstance(s, mpl.collections.PathCollection) - ] - assert len(scatters) == 4 - - -def test_individualized_font_attributes(): - G = nx.karate_club_graph() - ax = plt.figure().add_subplot(111) - nx.draw( - G, - ax=ax, - font_color={n: "k" if n % 2 else "r" for n in G.nodes()}, - font_size={n: int(n / (34 / 15) + 5) for n in G.nodes()}, - ) - for n, t in zip( - G.nodes(), - [ - t - for t in ax.get_children() - if isinstance(t, mpl.text.Text) and len(t.get_text()) > 0 - ], - ): - expected = "black" if n % 2 else "red" - - assert mpl.colors.same_color(t.get_color(), expected) - assert int(n / (34 / 15) + 5) == t.get_size() - - -def test_individualized_edge_attributes(): - G = nx.karate_club_graph() - ax = plt.figure().add_subplot(111) - arrowstyles = ["-|>" if (u + v) % 2 == 0 else "-[" for u, v in G.edges()] - arrowsizes = [10 * (u % 2 + v % 2) + 10 for u, v in G.edges()] - nx.draw(G, ax=ax, arrows=True, arrowstyle=arrowstyles, arrowsize=arrowsizes) - arrows = [ - f for f in ax.get_children() if isinstance(f, mpl.patches.FancyArrowPatch) - ] - for e, a in zip(G.edges(), arrows): - assert a.get_mutation_scale() == 10 * (e[0] % 2 + e[1] % 2) + 10 - expected = ( - mpl.patches.ArrowStyle.BracketB - if sum(e) % 2 - else mpl.patches.ArrowStyle.CurveFilledB - ) - assert isinstance(a.get_arrowstyle(), expected) - - -def test_error_invalid_kwds(): - with pytest.raises(ValueError, match="Received invalid argument"): - nx.draw(barbell, foo="bar") - - -def test_draw_networkx_arrowsize_incorrect_size(): - G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 3)]) - arrowsize = [1, 2, 3] - with pytest.raises( - ValueError, match="arrowsize should have the same length as edgelist" - ): - nx.draw(G, arrowsize=arrowsize) - - -@pytest.mark.parametrize("arrowsize", (30, [10, 20, 30])) -def test_draw_edges_arrowsize(arrowsize): - G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - pos = {0: (0, 0), 1: (0, 1), 2: (1, 0)} - edges = nx.draw_networkx_edges(G, pos=pos, arrowsize=arrowsize) - - arrowsize = itertools.repeat(arrowsize) if isinstance(arrowsize, int) else arrowsize - - for fap, expected in zip(edges, arrowsize): - assert isinstance(fap, mpl.patches.FancyArrowPatch) - assert fap.get_mutation_scale() == expected - - -@pytest.mark.parametrize("arrowstyle", ("-|>", ["-|>", "-[", "<|-|>"])) -def test_draw_edges_arrowstyle(arrowstyle): - G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - pos = {0: (0, 0), 1: (0, 1), 2: (1, 0)} - edges = nx.draw_networkx_edges(G, pos=pos, arrowstyle=arrowstyle) - - arrowstyle = ( - itertools.repeat(arrowstyle) if isinstance(arrowstyle, str) else arrowstyle - ) - - arrow_objects = { - "-|>": mpl.patches.ArrowStyle.CurveFilledB, - "-[": mpl.patches.ArrowStyle.BracketB, - "<|-|>": mpl.patches.ArrowStyle.CurveFilledAB, - } - - for fap, expected in zip(edges, arrowstyle): - assert isinstance(fap, mpl.patches.FancyArrowPatch) - assert isinstance(fap.get_arrowstyle(), arrow_objects[expected]) - - -def test_np_edgelist(): - # see issue #4129 - nx.draw_networkx(barbell, edgelist=np.array([(0, 2), (0, 3)])) - - -def test_draw_nodes_missing_node_from_position(): - G = nx.path_graph(3) - pos = {0: (0, 0), 1: (1, 1)} # No position for node 2 - with pytest.raises(nx.NetworkXError, match="has no position"): - nx.draw_networkx_nodes(G, pos) - - -# NOTE: parametrizing on marker to test both branches of internal -# nx.draw_networkx_edges.to_marker_edge function -@pytest.mark.parametrize("node_shape", ("o", "s")) -def test_draw_edges_min_source_target_margins(node_shape): - """Test that there is a wider gap between the node and the start of an - incident edge when min_source_margin is specified. - - This test checks that the use of min_{source/target}_margin kwargs result - in shorter (more padding) between the edges and source and target nodes. - As a crude visual example, let 's' and 't' represent source and target - nodes, respectively: - - Default: - s-----------------------------t - - With margins: - s ----------------------- t - - """ - # Create a single axis object to get consistent pixel coords across - # multiple draws - fig, ax = plt.subplots() - G = nx.DiGraph([(0, 1)]) - pos = {0: (0, 0), 1: (1, 0)} # horizontal layout - # Get leftmost and rightmost points of the FancyArrowPatch object - # representing the edge between nodes 0 and 1 (in pixel coordinates) - default_patch = nx.draw_networkx_edges(G, pos, ax=ax, node_shape=node_shape)[0] - default_extent = default_patch.get_extents().corners()[::2, 0] - # Now, do the same but with "padding" for the source and target via the - # min_{source/target}_margin kwargs - padded_patch = nx.draw_networkx_edges( - G, - pos, - ax=ax, - node_shape=node_shape, - min_source_margin=100, - min_target_margin=100, - )[0] - padded_extent = padded_patch.get_extents().corners()[::2, 0] - - # With padding, the left-most extent of the edge should be further to the - # right - assert padded_extent[0] > default_extent[0] - # And the rightmost extent of the edge, further to the left - assert padded_extent[1] < default_extent[1] - - -# NOTE: parametrizing on marker to test both branches of internal -# nx.draw_networkx_edges.to_marker_edge function -@pytest.mark.parametrize("node_shape", ("o", "s")) -def test_draw_edges_min_source_target_margins_individual(node_shape): - """Test that there is a wider gap between the node and the start of an - incident edge when min_source_margin is specified. - - This test checks that the use of min_{source/target}_margin kwargs result - in shorter (more padding) between the edges and source and target nodes. - As a crude visual example, let 's' and 't' represent source and target - nodes, respectively: - - Default: - s-----------------------------t - - With margins: - s ----------------------- t - - """ - # Create a single axis object to get consistent pixel coords across - # multiple draws - fig, ax = plt.subplots() - G = nx.DiGraph([(0, 1), (1, 2)]) - pos = {0: (0, 0), 1: (1, 0), 2: (2, 0)} # horizontal layout - # Get leftmost and rightmost points of the FancyArrowPatch object - # representing the edge between nodes 0 and 1 (in pixel coordinates) - default_patch = nx.draw_networkx_edges(G, pos, ax=ax, node_shape=node_shape) - default_extent = [d.get_extents().corners()[::2, 0] for d in default_patch] - # Now, do the same but with "padding" for the source and target via the - # min_{source/target}_margin kwargs - padded_patch = nx.draw_networkx_edges( - G, - pos, - ax=ax, - node_shape=node_shape, - min_source_margin=[98, 102], - min_target_margin=[98, 102], - ) - padded_extent = [p.get_extents().corners()[::2, 0] for p in padded_patch] - for d, p in zip(default_extent, padded_extent): - print(f"{p=}, {d=}") - # With padding, the left-most extent of the edge should be further to the - # right - assert p[0] > d[0] - # And the rightmost extent of the edge, further to the left - assert p[1] < d[1] - - -def test_nonzero_selfloop_with_single_node(): - """Ensure that selfloop extent is non-zero when there is only one node.""" - # Create explicit axis object for test - fig, ax = plt.subplots() - # Graph with single node + self loop - G = nx.DiGraph() - G.add_node(0) - G.add_edge(0, 0) - # Draw - patch = nx.draw_networkx_edges(G, {0: (0, 0)})[0] - # The resulting patch must have non-zero extent - bbox = patch.get_extents() - assert bbox.width > 0 and bbox.height > 0 - # Cleanup - plt.delaxes(ax) - plt.close() - - -def test_nonzero_selfloop_with_single_edge_in_edgelist(): - """Ensure that selfloop extent is non-zero when only a single edge is - specified in the edgelist. - """ - # Create explicit axis object for test - fig, ax = plt.subplots() - # Graph with selfloop - G = nx.path_graph(2, create_using=nx.DiGraph) - G.add_edge(1, 1) - pos = {n: (n, n) for n in G.nodes} - # Draw only the selfloop edge via the `edgelist` kwarg - patch = nx.draw_networkx_edges(G, pos, edgelist=[(1, 1)])[0] - # The resulting patch must have non-zero extent - bbox = patch.get_extents() - assert bbox.width > 0 and bbox.height > 0 - # Cleanup - plt.delaxes(ax) - plt.close() - - -def test_apply_alpha(): - """Test apply_alpha when there is a mismatch between the number of - supplied colors and elements. - """ - nodelist = [0, 1, 2] - colorlist = ["r", "g", "b"] - alpha = 0.5 - rgba_colors = nx.drawing.nx_pylab.apply_alpha(colorlist, alpha, nodelist) - assert all(rgba_colors[:, -1] == alpha) - - -def test_draw_edges_toggling_with_arrows_kwarg(): - """ - The `arrows` keyword argument is used as a 3-way switch to select which - type of object to use for drawing edges: - - ``arrows=None`` -> default (FancyArrowPatches for directed, else LineCollection) - - ``arrows=True`` -> FancyArrowPatches - - ``arrows=False`` -> LineCollection - """ - import matplotlib.collections - import matplotlib.patches - - UG = nx.path_graph(3) - DG = nx.path_graph(3, create_using=nx.DiGraph) - pos = {n: (n, n) for n in UG} - - # Use FancyArrowPatches when arrows=True, regardless of graph type - for G in (UG, DG): - edges = nx.draw_networkx_edges(G, pos, arrows=True) - assert len(edges) == len(G.edges) - assert isinstance(edges[0], mpl.patches.FancyArrowPatch) - - # Use LineCollection when arrows=False, regardless of graph type - for G in (UG, DG): - edges = nx.draw_networkx_edges(G, pos, arrows=False) - assert isinstance(edges, mpl.collections.LineCollection) - - # Default behavior when arrows=None: FAPs for directed, LC's for undirected - edges = nx.draw_networkx_edges(UG, pos) - assert isinstance(edges, mpl.collections.LineCollection) - edges = nx.draw_networkx_edges(DG, pos) - assert len(edges) == len(G.edges) - assert isinstance(edges[0], mpl.patches.FancyArrowPatch) - - -@pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx)) -def test_draw_networkx_arrows_default_undirected(drawing_func): - import matplotlib.collections - - G = nx.path_graph(3) - fig, ax = plt.subplots() - drawing_func(G, ax=ax) - assert any(isinstance(c, mpl.collections.LineCollection) for c in ax.collections) - assert not ax.patches - plt.delaxes(ax) - plt.close() - - -@pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx)) -def test_draw_networkx_arrows_default_directed(drawing_func): - import matplotlib.collections - - G = nx.path_graph(3, create_using=nx.DiGraph) - fig, ax = plt.subplots() - drawing_func(G, ax=ax) - assert not any( - isinstance(c, mpl.collections.LineCollection) for c in ax.collections - ) - assert ax.patches - plt.delaxes(ax) - plt.close() - - -def test_edgelist_kwarg_not_ignored(): - # See gh-4994 - G = nx.path_graph(3) - G.add_edge(0, 0) - fig, ax = plt.subplots() - nx.draw(G, edgelist=[(0, 1), (1, 2)], ax=ax) # Exclude self-loop from edgelist - assert not ax.patches - plt.delaxes(ax) - plt.close() - - -@pytest.mark.parametrize( - ("G", "expected_n_edges"), - ([nx.DiGraph(), 2], [nx.MultiGraph(), 4], [nx.MultiDiGraph(), 4]), -) -def test_draw_networkx_edges_multiedge_connectionstyle(G, expected_n_edges): - """Draws edges correctly for 3 types of graphs and checks for valid length""" - for i, (u, v) in enumerate([(0, 1), (0, 1), (0, 1), (0, 2)]): - G.add_edge(u, v, weight=round(i / 3, 2)) - pos = {n: (n, n) for n in G} - # Raises on insufficient connectionstyle length - for conn_style in [ - "arc3,rad=0.1", - ["arc3,rad=0.1", "arc3,rad=0.1"], - ["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.2"], - ]: - nx.draw_networkx_edges(G, pos, connectionstyle=conn_style) - arrows = nx.draw_networkx_edges(G, pos, connectionstyle=conn_style) - assert len(arrows) == expected_n_edges - - -@pytest.mark.parametrize( - ("G", "expected_n_edges"), - ([nx.DiGraph(), 2], [nx.MultiGraph(), 4], [nx.MultiDiGraph(), 4]), -) -def test_draw_networkx_edge_labels_multiedge_connectionstyle(G, expected_n_edges): - """Draws labels correctly for 3 types of graphs and checks for valid length and class names""" - for i, (u, v) in enumerate([(0, 1), (0, 1), (0, 1), (0, 2)]): - G.add_edge(u, v, weight=round(i / 3, 2)) - pos = {n: (n, n) for n in G} - # Raises on insufficient connectionstyle length - arrows = nx.draw_networkx_edges( - G, pos, connectionstyle=["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.1"] - ) - for conn_style in [ - "arc3,rad=0.1", - ["arc3,rad=0.1", "arc3,rad=0.2"], - ["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.1"], - ]: - text_items = nx.draw_networkx_edge_labels(G, pos, connectionstyle=conn_style) - assert len(text_items) == expected_n_edges - for ti in text_items.values(): - assert ti.__class__.__name__ == "CurvedArrowText" - - -def test_draw_networkx_edge_label_multiedge(): - G = nx.MultiGraph() - G.add_edge(0, 1, weight=10) - G.add_edge(0, 1, weight=20) - edge_labels = nx.get_edge_attributes(G, "weight") # Includes edge keys - pos = {n: (n, n) for n in G} - text_items = nx.draw_networkx_edge_labels( - G, - pos, - edge_labels=edge_labels, - connectionstyle=["arc3,rad=0.1", "arc3,rad=0.2"], - ) - assert len(text_items) == 2 - - -def test_draw_networkx_edge_label_empty_dict(): - """Regression test for draw_networkx_edge_labels with empty dict. See - gh-5372.""" - G = nx.path_graph(3) - pos = {n: (n, n) for n in G.nodes} - assert nx.draw_networkx_edge_labels(G, pos, edge_labels={}) == {} - - -def test_draw_networkx_edges_undirected_selfloop_colors(): - """When an edgelist is supplied along with a sequence of colors, check that - the self-loops have the correct colors.""" - fig, ax = plt.subplots() - # Edge list and corresponding colors - edgelist = [(1, 3), (1, 2), (2, 3), (1, 1), (3, 3), (2, 2)] - edge_colors = ["pink", "cyan", "black", "red", "blue", "green"] - - G = nx.Graph(edgelist) - pos = {n: (n, n) for n in G.nodes} - nx.draw_networkx_edges(G, pos, ax=ax, edgelist=edgelist, edge_color=edge_colors) - - # Verify that there are three fancy arrow patches (1 per self loop) - assert len(ax.patches) == 3 - - # These are points that should be contained in the self loops. For example, - # sl_points[0] will be (1, 1.1), which is inside the "path" of the first - # self-loop but outside the others - sl_points = np.array(edgelist[-3:]) + np.array([0, 0.1]) - - # Check that the mapping between self-loop locations and their colors is - # correct - for fap, clr, slp in zip(ax.patches, edge_colors[-3:], sl_points): - assert fap.get_path().contains_point(slp) - assert mpl.colors.same_color(fap.get_edgecolor(), clr) - plt.delaxes(ax) - plt.close() - - -@pytest.mark.parametrize( - "fap_only_kwarg", # Non-default values for kwargs that only apply to FAPs - ( - {"arrowstyle": "-"}, - {"arrowsize": 20}, - {"connectionstyle": "arc3,rad=0.2"}, - {"min_source_margin": 10}, - {"min_target_margin": 10}, - ), -) -def test_user_warnings_for_unused_edge_drawing_kwargs(fap_only_kwarg): - """Users should get a warning when they specify a non-default value for - one of the kwargs that applies only to edges drawn with FancyArrowPatches, - but FancyArrowPatches aren't being used under the hood.""" - G = nx.path_graph(3) - pos = {n: (n, n) for n in G} - fig, ax = plt.subplots() - # By default, an undirected graph will use LineCollection to represent - # the edges - kwarg_name = list(fap_only_kwarg.keys())[0] - with pytest.warns( - UserWarning, match=f"\n\nThe {kwarg_name} keyword argument is not applicable" - ): - nx.draw_networkx_edges(G, pos, ax=ax, **fap_only_kwarg) - # FancyArrowPatches are always used when `arrows=True` is specified. - # Check that warnings are *not* raised in this case - with warnings.catch_warnings(): - # Escalate warnings -> errors so tests fail if warnings are raised - warnings.simplefilter("error") - nx.draw_networkx_edges(G, pos, ax=ax, arrows=True, **fap_only_kwarg) - - plt.delaxes(ax) - plt.close() - - -@pytest.mark.parametrize("draw_fn", (nx.draw, nx.draw_circular)) -def test_no_warning_on_default_draw_arrowstyle(draw_fn): - # See gh-7284 - fig, ax = plt.subplots() - G = nx.cycle_graph(5) - with warnings.catch_warnings(record=True) as w: - draw_fn(G, ax=ax) - assert len(w) == 0 - - plt.delaxes(ax) - plt.close() - - -@pytest.mark.parametrize("hide_ticks", [False, True]) -@pytest.mark.parametrize( - "method", - [ - nx.draw_networkx, - nx.draw_networkx_edge_labels, - nx.draw_networkx_edges, - nx.draw_networkx_labels, - nx.draw_networkx_nodes, - ], -) -def test_hide_ticks(method, hide_ticks): - G = nx.path_graph(3) - pos = {n: (n, n) for n in G.nodes} - _, ax = plt.subplots() - method(G, pos=pos, ax=ax, hide_ticks=hide_ticks) - for axis in [ax.xaxis, ax.yaxis]: - assert bool(axis.get_ticklabels()) != hide_ticks - - plt.delaxes(ax) - plt.close() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/exception.py b/extensions/.local/lib/python3.11/site-packages/networkx/exception.py deleted file mode 100644 index c960cf1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/exception.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -********** -Exceptions -********** - -Base exceptions and errors for NetworkX. -""" - -__all__ = [ - "HasACycle", - "NodeNotFound", - "PowerIterationFailedConvergence", - "ExceededMaxIterations", - "AmbiguousSolution", - "NetworkXAlgorithmError", - "NetworkXException", - "NetworkXError", - "NetworkXNoCycle", - "NetworkXNoPath", - "NetworkXNotImplemented", - "NetworkXPointlessConcept", - "NetworkXUnbounded", - "NetworkXUnfeasible", -] - - -class NetworkXException(Exception): - """Base class for exceptions in NetworkX.""" - - -class NetworkXError(NetworkXException): - """Exception for a serious error in NetworkX""" - - -class NetworkXPointlessConcept(NetworkXException): - """Raised when a null graph is provided as input to an algorithm - that cannot use it. - - The null graph is sometimes considered a pointless concept [1]_, - thus the name of the exception. - - Notes - ----- - Null graphs and empty graphs are often used interchangeably but they - are well defined in NetworkX. An ``empty_graph`` is a graph with ``n`` nodes - and 0 edges, and a ``null_graph`` is a graph with 0 nodes and 0 edges. - - References - ---------- - .. [1] Harary, F. and Read, R. "Is the Null Graph a Pointless - Concept?" In Graphs and Combinatorics Conference, George - Washington University. New York: Springer-Verlag, 1973. - - """ - - -class NetworkXAlgorithmError(NetworkXException): - """Exception for unexpected termination of algorithms.""" - - -class NetworkXUnfeasible(NetworkXAlgorithmError): - """Exception raised by algorithms trying to solve a problem - instance that has no feasible solution.""" - - -class NetworkXNoPath(NetworkXUnfeasible): - """Exception for algorithms that should return a path when running - on graphs where such a path does not exist.""" - - -class NetworkXNoCycle(NetworkXUnfeasible): - """Exception for algorithms that should return a cycle when running - on graphs where such a cycle does not exist.""" - - -class HasACycle(NetworkXException): - """Raised if a graph has a cycle when an algorithm expects that it - will have no cycles. - - """ - - -class NetworkXUnbounded(NetworkXAlgorithmError): - """Exception raised by algorithms trying to solve a maximization - or a minimization problem instance that is unbounded.""" - - -class NetworkXNotImplemented(NetworkXException): - """Exception raised by algorithms not implemented for a type of graph.""" - - -class NodeNotFound(NetworkXException): - """Exception raised if requested node is not present in the graph""" - - -class AmbiguousSolution(NetworkXException): - """Raised if more than one valid solution exists for an intermediary step - of an algorithm. - - In the face of ambiguity, refuse the temptation to guess. - This may occur, for example, when trying to determine the - bipartite node sets in a disconnected bipartite graph when - computing bipartite matchings. - - """ - - -class ExceededMaxIterations(NetworkXException): - """Raised if a loop iterates too many times without breaking. - - This may occur, for example, in an algorithm that computes - progressively better approximations to a value but exceeds an - iteration bound specified by the user. - - """ - - -class PowerIterationFailedConvergence(ExceededMaxIterations): - """Raised when the power iteration method fails to converge within a - specified iteration limit. - - `num_iterations` is the number of iterations that have been - completed when this exception was raised. - - """ - - def __init__(self, num_iterations, *args, **kw): - msg = f"power iteration failed to converge within {num_iterations} iterations" - exception_message = msg - superinit = super().__init__ - superinit(self, exception_message, *args, **kw) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/__init__.py deleted file mode 100644 index 6ec027c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -A package for generating various graphs in networkx. - -""" - -from networkx.generators.atlas import * -from networkx.generators.classic import * -from networkx.generators.cographs import * -from networkx.generators.community import * -from networkx.generators.degree_seq import * -from networkx.generators.directed import * -from networkx.generators.duplication import * -from networkx.generators.ego import * -from networkx.generators.expanders import * -from networkx.generators.geometric import * -from networkx.generators.harary_graph import * -from networkx.generators.internet_as_graphs import * -from networkx.generators.intersection import * -from networkx.generators.interval_graph import * -from networkx.generators.joint_degree_seq import * -from networkx.generators.lattice import * -from networkx.generators.line import * -from networkx.generators.mycielski import * -from networkx.generators.nonisomorphic_trees import * -from networkx.generators.random_clustered import * -from networkx.generators.random_graphs import * -from networkx.generators.small import * -from networkx.generators.social import * -from networkx.generators.spectral_graph_forge import * -from networkx.generators.stochastic import * -from networkx.generators.sudoku import * -from networkx.generators.time_series import * -from networkx.generators.trees import * -from networkx.generators.triads import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.dat.gz b/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.dat.gz deleted file mode 100644 index 2cb5d13..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.dat.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73fc416df0164923607751cb759f4ae81deb5f6550bf25be59c86de3b747e41d -size 8887 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.py deleted file mode 100644 index c5dd8d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/atlas.py +++ /dev/null @@ -1,180 +0,0 @@ -""" -Generators for the small graph atlas. -""" - -import gzip -import importlib.resources -import os -import os.path -from itertools import islice - -import networkx as nx - -__all__ = ["graph_atlas", "graph_atlas_g"] - -#: The total number of graphs in the atlas. -#: -#: The graphs are labeled starting from 0 and extending to (but not -#: including) this number. -NUM_GRAPHS = 1253 - -#: The path to the data file containing the graph edge lists. -#: -#: This is the absolute path of the gzipped text file containing the -#: edge list for each graph in the atlas. The file contains one entry -#: per graph in the atlas, in sequential order, starting from graph -#: number 0 and extending through graph number 1252 (see -#: :data:`NUM_GRAPHS`). Each entry looks like -#: -#: .. sourcecode:: text -#: -#: GRAPH 6 -#: NODES 3 -#: 0 1 -#: 0 2 -#: -#: where the first two lines are the graph's index in the atlas and the -#: number of nodes in the graph, and the remaining lines are the edge -#: list. -#: -#: This file was generated from a Python list of graphs via code like -#: the following:: -#: -#: import gzip -#: from networkx.generators.atlas import graph_atlas_g -#: from networkx.readwrite.edgelist import write_edgelist -#: -#: with gzip.open('atlas.dat.gz', 'wb') as f: -#: for i, G in enumerate(graph_atlas_g()): -#: f.write(bytes(f'GRAPH {i}\n', encoding='utf-8')) -#: f.write(bytes(f'NODES {len(G)}\n', encoding='utf-8')) -#: write_edgelist(G, f, data=False) -#: - -# Path to the atlas file -ATLAS_FILE = importlib.resources.files("networkx.generators") / "atlas.dat.gz" - - -def _generate_graphs(): - """Sequentially read the file containing the edge list data for the - graphs in the atlas and generate the graphs one at a time. - - This function reads the file given in :data:`.ATLAS_FILE`. - - """ - with gzip.open(ATLAS_FILE, "rb") as f: - line = f.readline() - while line and line.startswith(b"GRAPH"): - # The first two lines of each entry tell us the index of the - # graph in the list and the number of nodes in the graph. - # They look like this: - # - # GRAPH 3 - # NODES 2 - # - graph_index = int(line[6:].rstrip()) - line = f.readline() - num_nodes = int(line[6:].rstrip()) - # The remaining lines contain the edge list, until the next - # GRAPH line (or until the end of the file). - edgelist = [] - line = f.readline() - while line and not line.startswith(b"GRAPH"): - edgelist.append(line.rstrip()) - line = f.readline() - G = nx.Graph() - G.name = f"G{graph_index}" - G.add_nodes_from(range(num_nodes)) - G.add_edges_from(tuple(map(int, e.split())) for e in edgelist) - yield G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def graph_atlas(i): - """Returns graph number `i` from the Graph Atlas. - - For more information, see :func:`.graph_atlas_g`. - - Parameters - ---------- - i : int - The index of the graph from the atlas to get. The graph at index - 0 is assumed to be the null graph. - - Returns - ------- - list - A list of :class:`~networkx.Graph` objects, the one at index *i* - corresponding to the graph *i* in the Graph Atlas. - - See also - -------- - graph_atlas_g - - Notes - ----- - The time required by this function increases linearly with the - argument `i`, since it reads a large file sequentially in order to - generate the graph [1]_. - - References - ---------- - .. [1] Ronald C. Read and Robin J. Wilson, *An Atlas of Graphs*. - Oxford University Press, 1998. - - """ - if not (0 <= i < NUM_GRAPHS): - raise ValueError(f"index must be between 0 and {NUM_GRAPHS}") - return next(islice(_generate_graphs(), i, None)) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def graph_atlas_g(): - """Returns the list of all graphs with up to seven nodes named in the - Graph Atlas. - - The graphs are listed in increasing order by - - 1. number of nodes, - 2. number of edges, - 3. degree sequence (for example 111223 < 112222), - 4. number of automorphisms, - - in that order, with three exceptions as described in the *Notes* - section below. This causes the list to correspond with the index of - the graphs in the Graph Atlas [atlas]_, with the first graph, - ``G[0]``, being the null graph. - - Returns - ------- - list - A list of :class:`~networkx.Graph` objects, the one at index *i* - corresponding to the graph *i* in the Graph Atlas. - - See also - -------- - graph_atlas - - Notes - ----- - This function may be expensive in both time and space, since it - reads a large file sequentially in order to populate the list. - - Although the NetworkX atlas functions match the order of graphs - given in the "Atlas of Graphs" book, there are (at least) three - errors in the ordering described in the book. The following three - pairs of nodes violate the lexicographically nondecreasing sorted - degree sequence rule: - - - graphs 55 and 56 with degree sequences 001111 and 000112, - - graphs 1007 and 1008 with degree sequences 3333444 and 3333336, - - graphs 1012 and 1213 with degree sequences 1244555 and 1244456. - - References - ---------- - .. [atlas] Ronald C. Read and Robin J. Wilson, - *An Atlas of Graphs*. - Oxford University Press, 1998. - - """ - return list(_generate_graphs()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/classic.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/classic.py deleted file mode 100644 index a461e7b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/classic.py +++ /dev/null @@ -1,1068 +0,0 @@ -"""Generators for some classic graphs. - -The typical graph builder function is called as follows: - ->>> G = nx.complete_graph(100) - -returning the complete graph on n nodes labeled 0, .., 99 -as a simple graph. Except for `empty_graph`, all the functions -in this module return a Graph class (i.e. a simple, undirected graph). - -""" - -import itertools -import numbers - -import networkx as nx -from networkx.classes import Graph -from networkx.exception import NetworkXError -from networkx.utils import nodes_or_number, pairwise - -__all__ = [ - "balanced_tree", - "barbell_graph", - "binomial_tree", - "complete_graph", - "complete_multipartite_graph", - "circular_ladder_graph", - "circulant_graph", - "cycle_graph", - "dorogovtsev_goltsev_mendes_graph", - "empty_graph", - "full_rary_tree", - "kneser_graph", - "ladder_graph", - "lollipop_graph", - "null_graph", - "path_graph", - "star_graph", - "tadpole_graph", - "trivial_graph", - "turan_graph", - "wheel_graph", -] - - -# ------------------------------------------------------------------- -# Some Classic Graphs -# ------------------------------------------------------------------- - - -def _tree_edges(n, r): - if n == 0: - return - # helper function for trees - # yields edges in rooted tree at 0 with n nodes and branching ratio r - nodes = iter(range(n)) - parents = [next(nodes)] # stack of max length r - while parents: - source = parents.pop(0) - for i in range(r): - try: - target = next(nodes) - parents.append(target) - yield source, target - except StopIteration: - break - - -@nx._dispatchable(graphs=None, returns_graph=True) -def full_rary_tree(r, n, create_using=None): - """Creates a full r-ary tree of `n` nodes. - - Sometimes called a k-ary, n-ary, or m-ary tree. - "... all non-leaf nodes have exactly r children and all levels - are full except for some rightmost position of the bottom level - (if a leaf at the bottom level is missing, then so are all of the - leaves to its right." [1]_ - - .. plot:: - - >>> nx.draw(nx.full_rary_tree(2, 10)) - - Parameters - ---------- - r : int - branching factor of the tree - n : int - Number of nodes in the tree - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - An r-ary tree with n nodes - - References - ---------- - .. [1] An introduction to data structures and algorithms, - James Andrew Storer, Birkhauser Boston 2001, (page 225). - """ - G = empty_graph(n, create_using) - G.add_edges_from(_tree_edges(n, r)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def kneser_graph(n, k): - """Returns the Kneser Graph with parameters `n` and `k`. - - The Kneser Graph has nodes that are k-tuples (subsets) of the integers - between 0 and ``n-1``. Nodes are adjacent if their corresponding sets are disjoint. - - Parameters - ---------- - n: int - Number of integers from which to make node subsets. - Subsets are drawn from ``set(range(n))``. - k: int - Size of the subsets. - - Returns - ------- - G : NetworkX Graph - - Examples - -------- - >>> G = nx.kneser_graph(5, 2) - >>> G.number_of_nodes() - 10 - >>> G.number_of_edges() - 15 - >>> nx.is_isomorphic(G, nx.petersen_graph()) - True - """ - if n <= 0: - raise NetworkXError("n should be greater than zero") - if k <= 0 or k > n: - raise NetworkXError("k should be greater than zero and smaller than n") - - G = nx.Graph() - # Create all k-subsets of [0, 1, ..., n-1] - subsets = list(itertools.combinations(range(n), k)) - - if 2 * k > n: - G.add_nodes_from(subsets) - - universe = set(range(n)) - comb = itertools.combinations # only to make it all fit on one line - G.add_edges_from((s, t) for s in subsets for t in comb(universe - set(s), k)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def balanced_tree(r, h, create_using=None): - """Returns the perfectly balanced `r`-ary tree of height `h`. - - .. plot:: - - >>> nx.draw(nx.balanced_tree(2, 3)) - - Parameters - ---------- - r : int - Branching factor of the tree; each node will have `r` - children. - - h : int - Height of the tree. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : NetworkX graph - A balanced `r`-ary tree of height `h`. - - Notes - ----- - This is the rooted tree where all leaves are at distance `h` from - the root. The root has degree `r` and all other internal nodes - have degree `r + 1`. - - Node labels are integers, starting from zero. - - A balanced tree is also known as a *complete r-ary tree*. - - """ - # The number of nodes in the balanced tree is `1 + r + ... + r^h`, - # which is computed by using the closed-form formula for a geometric - # sum with ratio `r`. In the special case that `r` is 1, the number - # of nodes is simply `h + 1` (since the tree is actually a path - # graph). - if r == 1: - n = h + 1 - else: - # This must be an integer if both `r` and `h` are integers. If - # they are not, we force integer division anyway. - n = (1 - r ** (h + 1)) // (1 - r) - return full_rary_tree(r, n, create_using=create_using) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def barbell_graph(m1, m2, create_using=None): - """Returns the Barbell Graph: two complete graphs connected by a path. - - .. plot:: - - >>> nx.draw(nx.barbell_graph(4, 2)) - - Parameters - ---------- - m1 : int - Size of the left and right barbells, must be greater than 2. - - m2 : int - Length of the path connecting the barbells. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Only undirected Graphs are supported. - - Returns - ------- - G : NetworkX graph - A barbell graph. - - Notes - ----- - - - Two identical complete graphs $K_{m1}$ form the left and right bells, - and are connected by a path $P_{m2}$. - - The `2*m1+m2` nodes are numbered - `0, ..., m1-1` for the left barbell, - `m1, ..., m1+m2-1` for the path, - and `m1+m2, ..., 2*m1+m2-1` for the right barbell. - - The 3 subgraphs are joined via the edges `(m1-1, m1)` and - `(m1+m2-1, m1+m2)`. If `m2=0`, this is merely two complete - graphs joined together. - - This graph is an extremal example in David Aldous - and Jim Fill's e-text on Random Walks on Graphs. - - """ - if m1 < 2: - raise NetworkXError("Invalid graph description, m1 should be >=2") - if m2 < 0: - raise NetworkXError("Invalid graph description, m2 should be >=0") - - # left barbell - G = complete_graph(m1, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - # connecting path - G.add_nodes_from(range(m1, m1 + m2 - 1)) - if m2 > 1: - G.add_edges_from(pairwise(range(m1, m1 + m2))) - - # right barbell - G.add_edges_from( - (u, v) for u in range(m1 + m2, 2 * m1 + m2) for v in range(u + 1, 2 * m1 + m2) - ) - - # connect it up - G.add_edge(m1 - 1, m1) - if m2 > 0: - G.add_edge(m1 + m2 - 1, m1 + m2) - - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def binomial_tree(n, create_using=None): - """Returns the Binomial Tree of order n. - - The binomial tree of order 0 consists of a single node. A binomial tree of order k - is defined recursively by linking two binomial trees of order k-1: the root of one is - the leftmost child of the root of the other. - - .. plot:: - - >>> nx.draw(nx.binomial_tree(3)) - - Parameters - ---------- - n : int - Order of the binomial tree. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : NetworkX graph - A binomial tree of $2^n$ nodes and $2^n - 1$ edges. - - """ - G = nx.empty_graph(1, create_using) - - N = 1 - for i in range(n): - # Use G.edges() to ensure 2-tuples. G.edges is 3-tuple for MultiGraph - edges = [(u + N, v + N) for (u, v) in G.edges()] - G.add_edges_from(edges) - G.add_edge(0, N) - N *= 2 - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def complete_graph(n, create_using=None): - """Return the complete graph `K_n` with n nodes. - - A complete graph on `n` nodes means that all pairs - of distinct nodes have an edge connecting them. - - .. plot:: - - >>> nx.draw(nx.complete_graph(5)) - - Parameters - ---------- - n : int or iterable container of nodes - If n is an integer, nodes are from range(n). - If n is a container of nodes, those nodes appear in the graph. - Warning: n is not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> G = nx.complete_graph(9) - >>> len(G) - 9 - >>> G.size() - 36 - >>> G = nx.complete_graph(range(11, 14)) - >>> list(G.nodes()) - [11, 12, 13] - >>> G = nx.complete_graph(4, nx.DiGraph()) - >>> G.is_directed() - True - - """ - _, nodes = n - G = empty_graph(nodes, create_using) - if len(nodes) > 1: - if G.is_directed(): - edges = itertools.permutations(nodes, 2) - else: - edges = itertools.combinations(nodes, 2) - G.add_edges_from(edges) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def circular_ladder_graph(n, create_using=None): - """Returns the circular ladder graph $CL_n$ of length n. - - $CL_n$ consists of two concentric n-cycles in which - each of the n pairs of concentric nodes are joined by an edge. - - Node labels are the integers 0 to n-1 - - .. plot:: - - >>> nx.draw(nx.circular_ladder_graph(5)) - - """ - G = ladder_graph(n, create_using) - G.add_edge(0, n - 1) - G.add_edge(n, 2 * n - 1) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def circulant_graph(n, offsets, create_using=None): - r"""Returns the circulant graph $Ci_n(x_1, x_2, ..., x_m)$ with $n$ nodes. - - The circulant graph $Ci_n(x_1, ..., x_m)$ consists of $n$ nodes $0, ..., n-1$ - such that node $i$ is connected to nodes $(i + x) \mod n$ and $(i - x) \mod n$ - for all $x$ in $x_1, ..., x_m$. Thus $Ci_n(1)$ is a cycle graph. - - .. plot:: - - >>> nx.draw(nx.circulant_graph(10, [1])) - - Parameters - ---------- - n : integer - The number of nodes in the graph. - offsets : list of integers - A list of node offsets, $x_1$ up to $x_m$, as described above. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX Graph of type create_using - - Examples - -------- - Many well-known graph families are subfamilies of the circulant graphs; - for example, to create the cycle graph on n points, we connect every - node to nodes on either side (with offset plus or minus one). For n = 10, - - >>> G = nx.circulant_graph(10, [1]) - >>> edges = [ - ... (0, 9), - ... (0, 1), - ... (1, 2), - ... (2, 3), - ... (3, 4), - ... (4, 5), - ... (5, 6), - ... (6, 7), - ... (7, 8), - ... (8, 9), - ... ] - >>> sorted(edges) == sorted(G.edges()) - True - - Similarly, we can create the complete graph - on 5 points with the set of offsets [1, 2]: - - >>> G = nx.circulant_graph(5, [1, 2]) - >>> edges = [ - ... (0, 1), - ... (0, 2), - ... (0, 3), - ... (0, 4), - ... (1, 2), - ... (1, 3), - ... (1, 4), - ... (2, 3), - ... (2, 4), - ... (3, 4), - ... ] - >>> sorted(edges) == sorted(G.edges()) - True - - """ - G = empty_graph(n, create_using) - for i in range(n): - for j in offsets: - G.add_edge(i, (i - j) % n) - G.add_edge(i, (i + j) % n) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def cycle_graph(n, create_using=None): - """Returns the cycle graph $C_n$ of cyclically connected nodes. - - $C_n$ is a path with its two end-nodes connected. - - .. plot:: - - >>> nx.draw(nx.cycle_graph(5)) - - Parameters - ---------- - n : int or iterable container of nodes - If n is an integer, nodes are from `range(n)`. - If n is a container of nodes, those nodes appear in the graph. - Warning: n is not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - If create_using is directed, the direction is in increasing order. - - """ - _, nodes = n - G = empty_graph(nodes, create_using) - G.add_edges_from(pairwise(nodes, cyclic=True)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def dorogovtsev_goltsev_mendes_graph(n, create_using=None): - """Returns the hierarchically constructed Dorogovtsev--Goltsev--Mendes graph. - - The Dorogovtsev--Goltsev--Mendes [1]_ procedure deterministically produces a - scale-free graph with ``3/2 * (3**(n-1) + 1)`` nodes - and ``3**n`` edges for a given `n`. - - Note that `n` denotes the number of times the state transition is applied, - starting from the base graph with ``n = 0`` (no transitions), as in [2]_. - This is different from the parameter ``t = n - 1`` in [1]_. - - .. plot:: - - >>> nx.draw(nx.dorogovtsev_goltsev_mendes_graph(3)) - - Parameters - ---------- - n : integer - The generation number. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. Directed graphs and multigraphs are not supported. - - Returns - ------- - G : NetworkX `Graph` - - Raises - ------ - NetworkXError - If `n` is less than zero. - - If `create_using` is a directed graph or multigraph. - - Examples - -------- - >>> G = nx.dorogovtsev_goltsev_mendes_graph(3) - >>> G.number_of_nodes() - 15 - >>> G.number_of_edges() - 27 - >>> nx.is_planar(G) - True - - References - ---------- - .. [1] S. N. Dorogovtsev, A. V. Goltsev and J. F. F. Mendes, - "Pseudofractal scale-free web", Physical Review E 65, 066122, 2002. - https://arxiv.org/pdf/cond-mat/0112143.pdf - .. [2] Weisstein, Eric W. "Dorogovtsev--Goltsev--Mendes Graph". - From MathWorld--A Wolfram Web Resource. - https://mathworld.wolfram.com/Dorogovtsev-Goltsev-MendesGraph.html - """ - if n < 0: - raise NetworkXError("n must be greater than or equal to 0") - - G = empty_graph(0, create_using) - if G.is_directed(): - raise NetworkXError("directed graph not supported") - if G.is_multigraph(): - raise NetworkXError("multigraph not supported") - - G.add_edge(0, 1) - new_node = 2 # next node to be added - for _ in range(n): # iterate over number of generations. - new_edges = [] - for u, v in G.edges(): - new_edges.append((u, new_node)) - new_edges.append((v, new_node)) - new_node += 1 - - G.add_edges_from(new_edges) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def empty_graph(n=0, create_using=None, default=Graph): - """Returns the empty graph with n nodes and zero edges. - - .. plot:: - - >>> nx.draw(nx.empty_graph(5)) - - Parameters - ---------- - n : int or iterable container of nodes (default = 0) - If n is an integer, nodes are from `range(n)`. - If n is a container of nodes, those nodes appear in the graph. - create_using : Graph Instance, Constructor or None - Indicator of type of graph to return. - If a Graph-type instance, then clear and use it. - If None, use the `default` constructor. - If a constructor, call it to create an empty graph. - default : Graph constructor (optional, default = nx.Graph) - The constructor to use if create_using is None. - If None, then nx.Graph is used. - This is used when passing an unknown `create_using` value - through your home-grown function to `empty_graph` and - you want a default constructor other than nx.Graph. - - Examples - -------- - >>> G = nx.empty_graph(10) - >>> G.number_of_nodes() - 10 - >>> G.number_of_edges() - 0 - >>> G = nx.empty_graph("ABC") - >>> G.number_of_nodes() - 3 - >>> sorted(G) - ['A', 'B', 'C'] - - Notes - ----- - The variable create_using should be a Graph Constructor or a - "graph"-like object. Constructors, e.g. `nx.Graph` or `nx.MultiGraph` - will be used to create the returned graph. "graph"-like objects - will be cleared (nodes and edges will be removed) and refitted as - an empty "graph" with nodes specified in n. This capability - is useful for specifying the class-nature of the resulting empty - "graph" (i.e. Graph, DiGraph, MyWeirdGraphClass, etc.). - - The variable create_using has three main uses: - Firstly, the variable create_using can be used to create an - empty digraph, multigraph, etc. For example, - - >>> n = 10 - >>> G = nx.empty_graph(n, create_using=nx.DiGraph) - - will create an empty digraph on n nodes. - - Secondly, one can pass an existing graph (digraph, multigraph, - etc.) via create_using. For example, if G is an existing graph - (resp. digraph, multigraph, etc.), then empty_graph(n, create_using=G) - will empty G (i.e. delete all nodes and edges using G.clear()) - and then add n nodes and zero edges, and return the modified graph. - - Thirdly, when constructing your home-grown graph creation function - you can use empty_graph to construct the graph by passing a user - defined create_using to empty_graph. In this case, if you want the - default constructor to be other than nx.Graph, specify `default`. - - >>> def mygraph(n, create_using=None): - ... G = nx.empty_graph(n, create_using, nx.MultiGraph) - ... G.add_edges_from([(0, 1), (0, 1)]) - ... return G - >>> G = mygraph(3) - >>> G.is_multigraph() - True - >>> G = mygraph(3, nx.Graph) - >>> G.is_multigraph() - False - - See also create_empty_copy(G). - - """ - if create_using is None: - G = default() - elif isinstance(create_using, type): - G = create_using() - elif not hasattr(create_using, "adj"): - raise TypeError("create_using is not a valid NetworkX graph type or instance") - else: - # create_using is a NetworkX style Graph - create_using.clear() - G = create_using - - _, nodes = n - G.add_nodes_from(nodes) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def ladder_graph(n, create_using=None): - """Returns the Ladder graph of length n. - - This is two paths of n nodes, with - each pair connected by a single edge. - - Node labels are the integers 0 to 2*n - 1. - - .. plot:: - - >>> nx.draw(nx.ladder_graph(5)) - - """ - G = empty_graph(2 * n, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - G.add_edges_from(pairwise(range(n))) - G.add_edges_from(pairwise(range(n, 2 * n))) - G.add_edges_from((v, v + n) for v in range(n)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number([0, 1]) -def lollipop_graph(m, n, create_using=None): - """Returns the Lollipop Graph; ``K_m`` connected to ``P_n``. - - This is the Barbell Graph without the right barbell. - - .. plot:: - - >>> nx.draw(nx.lollipop_graph(3, 4)) - - Parameters - ---------- - m, n : int or iterable container of nodes - If an integer, nodes are from ``range(m)`` and ``range(m, m+n)``. - If a container of nodes, those nodes appear in the graph. - Warning: `m` and `n` are not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - - The nodes for `m` appear in the complete graph $K_m$ and the nodes - for `n` appear in the path $P_n$ - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - Networkx graph - A complete graph with `m` nodes connected to a path of length `n`. - - Notes - ----- - The 2 subgraphs are joined via an edge ``(m-1, m)``. - If ``n=0``, this is merely a complete graph. - - (This graph is an extremal example in David Aldous and Jim - Fill's etext on Random Walks on Graphs.) - - """ - m, m_nodes = m - M = len(m_nodes) - if M < 2: - raise NetworkXError("Invalid description: m should indicate at least 2 nodes") - - n, n_nodes = n - if isinstance(m, numbers.Integral) and isinstance(n, numbers.Integral): - n_nodes = list(range(M, M + n)) - N = len(n_nodes) - - # the ball - G = complete_graph(m_nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - # the stick - G.add_nodes_from(n_nodes) - if N > 1: - G.add_edges_from(pairwise(n_nodes)) - - if len(G) != M + N: - raise NetworkXError("Nodes must be distinct in containers m and n") - - # connect ball to stick - if M > 0 and N > 0: - G.add_edge(m_nodes[-1], n_nodes[0]) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def null_graph(create_using=None): - """Returns the Null graph with no nodes or edges. - - See empty_graph for the use of create_using. - - """ - G = empty_graph(0, create_using) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def path_graph(n, create_using=None): - """Returns the Path graph `P_n` of linearly connected nodes. - - .. plot:: - - >>> nx.draw(nx.path_graph(5)) - - Parameters - ---------- - n : int or iterable - If an integer, nodes are 0 to n - 1. - If an iterable of nodes, in the order they appear in the path. - Warning: n is not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - """ - _, nodes = n - G = empty_graph(nodes, create_using) - G.add_edges_from(pairwise(nodes)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def star_graph(n, create_using=None): - """Return the star graph - - The star graph consists of one center node connected to n outer nodes. - - .. plot:: - - >>> nx.draw(nx.star_graph(6)) - - Parameters - ---------- - n : int or iterable - If an integer, node labels are 0 to n with center 0. - If an iterable of nodes, the center is the first. - Warning: n is not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - The graph has n+1 nodes for integer n. - So star_graph(3) is the same as star_graph(range(4)). - """ - n, nodes = n - if isinstance(n, numbers.Integral): - nodes.append(int(n)) # there should be n+1 nodes - G = empty_graph(nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - if len(nodes) > 1: - hub, *spokes = nodes - G.add_edges_from((hub, node) for node in spokes) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number([0, 1]) -def tadpole_graph(m, n, create_using=None): - """Returns the (m,n)-tadpole graph; ``C_m`` connected to ``P_n``. - - This graph on m+n nodes connects a cycle of size `m` to a path of length `n`. - It looks like a tadpole. It is also called a kite graph or a dragon graph. - - .. plot:: - - >>> nx.draw(nx.tadpole_graph(3, 5)) - - Parameters - ---------- - m, n : int or iterable container of nodes - If an integer, nodes are from ``range(m)`` and ``range(m,m+n)``. - If a container of nodes, those nodes appear in the graph. - Warning: `m` and `n` are not checked for duplicates and if present the - resulting graph may not be as desired. - - The nodes for `m` appear in the cycle graph $C_m$ and the nodes - for `n` appear in the path $P_n$. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - Networkx graph - A cycle of size `m` connected to a path of length `n`. - - Raises - ------ - NetworkXError - If ``m < 2``. The tadpole graph is undefined for ``m<2``. - - Notes - ----- - The 2 subgraphs are joined via an edge ``(m-1, m)``. - If ``n=0``, this is a cycle graph. - `m` and/or `n` can be a container of nodes instead of an integer. - - """ - m, m_nodes = m - M = len(m_nodes) - if M < 2: - raise NetworkXError("Invalid description: m should indicate at least 2 nodes") - - n, n_nodes = n - if isinstance(m, numbers.Integral) and isinstance(n, numbers.Integral): - n_nodes = list(range(M, M + n)) - - # the circle - G = cycle_graph(m_nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - # the stick - nx.add_path(G, [m_nodes[-1]] + list(n_nodes)) - - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def trivial_graph(create_using=None): - """Return the Trivial graph with one node (with label 0) and no edges. - - .. plot:: - - >>> nx.draw(nx.trivial_graph(), with_labels=True) - - """ - G = empty_graph(1, create_using) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def turan_graph(n, r): - r"""Return the Turan Graph - - The Turan Graph is a complete multipartite graph on $n$ nodes - with $r$ disjoint subsets. That is, edges connect each node to - every node not in its subset. - - Given $n$ and $r$, we create a complete multipartite graph with - $r-(n \mod r)$ partitions of size $n/r$, rounded down, and - $n \mod r$ partitions of size $n/r+1$, rounded down. - - .. plot:: - - >>> nx.draw(nx.turan_graph(6, 2)) - - Parameters - ---------- - n : int - The number of nodes. - r : int - The number of partitions. - Must be less than or equal to n. - - Notes - ----- - Must satisfy $1 <= r <= n$. - The graph has $(r-1)(n^2)/(2r)$ edges, rounded down. - """ - - if not 1 <= r <= n: - raise NetworkXError("Must satisfy 1 <= r <= n") - - partitions = [n // r] * (r - (n % r)) + [n // r + 1] * (n % r) - G = complete_multipartite_graph(*partitions) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number(0) -def wheel_graph(n, create_using=None): - """Return the wheel graph - - The wheel graph consists of a hub node connected to a cycle of (n-1) nodes. - - .. plot:: - - >>> nx.draw(nx.wheel_graph(5)) - - Parameters - ---------- - n : int or iterable - If an integer, node labels are 0 to n with center 0. - If an iterable of nodes, the center is the first. - Warning: n is not checked for duplicates and if present the - resulting graph may not be as desired. Make sure you have no duplicates. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Node labels are the integers 0 to n - 1. - """ - _, nodes = n - G = empty_graph(nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - if len(nodes) > 1: - hub, *rim = nodes - G.add_edges_from((hub, node) for node in rim) - if len(rim) > 1: - G.add_edges_from(pairwise(rim, cyclic=True)) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def complete_multipartite_graph(*subset_sizes): - """Returns the complete multipartite graph with the specified subset sizes. - - .. plot:: - - >>> nx.draw(nx.complete_multipartite_graph(1, 2, 3)) - - Parameters - ---------- - subset_sizes : tuple of integers or tuple of node iterables - The arguments can either all be integer number of nodes or they - can all be iterables of nodes. If integers, they represent the - number of nodes in each subset of the multipartite graph. - If iterables, each is used to create the nodes for that subset. - The length of subset_sizes is the number of subsets. - - Returns - ------- - G : NetworkX Graph - Returns the complete multipartite graph with the specified subsets. - - For each node, the node attribute 'subset' is an integer - indicating which subset contains the node. - - Examples - -------- - Creating a complete tripartite graph, with subsets of one, two, and three - nodes, respectively. - - >>> G = nx.complete_multipartite_graph(1, 2, 3) - >>> [G.nodes[u]["subset"] for u in G] - [0, 1, 1, 2, 2, 2] - >>> list(G.edges(0)) - [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)] - >>> list(G.edges(2)) - [(2, 0), (2, 3), (2, 4), (2, 5)] - >>> list(G.edges(4)) - [(4, 0), (4, 1), (4, 2)] - - >>> G = nx.complete_multipartite_graph("a", "bc", "def") - >>> [G.nodes[u]["subset"] for u in sorted(G)] - [0, 1, 1, 2, 2, 2] - - Notes - ----- - This function generalizes several other graph builder functions. - - - If no subset sizes are given, this returns the null graph. - - If a single subset size `n` is given, this returns the empty graph on - `n` nodes. - - If two subset sizes `m` and `n` are given, this returns the complete - bipartite graph on `m + n` nodes. - - If subset sizes `1` and `n` are given, this returns the star graph on - `n + 1` nodes. - - See also - -------- - complete_bipartite_graph - """ - # The complete multipartite graph is an undirected simple graph. - G = Graph() - - if len(subset_sizes) == 0: - return G - - # set up subsets of nodes - try: - extents = pairwise(itertools.accumulate((0,) + subset_sizes)) - subsets = [range(start, end) for start, end in extents] - except TypeError: - subsets = subset_sizes - else: - if any(size < 0 for size in subset_sizes): - raise NetworkXError(f"Negative number of nodes not valid: {subset_sizes}") - - # add nodes with subset attribute - # while checking that ints are not mixed with iterables - try: - for i, subset in enumerate(subsets): - G.add_nodes_from(subset, subset=i) - except TypeError as err: - raise NetworkXError("Arguments must be all ints or all iterables") from err - - # Across subsets, all nodes should be adjacent. - # We can use itertools.combinations() because undirected. - for subset1, subset2 in itertools.combinations(subsets, 2): - G.add_edges_from(itertools.product(subset1, subset2)) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/cographs.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/cographs.py deleted file mode 100644 index 6635b32..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/cographs.py +++ /dev/null @@ -1,68 +0,0 @@ -r"""Generators for cographs - -A cograph is a graph containing no path on four vertices. -Cographs or $P_4$-free graphs can be obtained from a single vertex -by disjoint union and complementation operations. - -References ----------- -.. [0] D.G. Corneil, H. Lerchs, L.Stewart Burlingham, - "Complement reducible graphs", - Discrete Applied Mathematics, Volume 3, Issue 3, 1981, Pages 163-174, - ISSN 0166-218X. -""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ["random_cograph"] - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_cograph(n, seed=None): - r"""Returns a random cograph with $2 ^ n$ nodes. - - A cograph is a graph containing no path on four vertices. - Cographs or $P_4$-free graphs can be obtained from a single vertex - by disjoint union and complementation operations. - - This generator starts off from a single vertex and performs disjoint - union and full join operations on itself. - The decision on which operation will take place is random. - - Parameters - ---------- - n : int - The order of the cograph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : A random graph containing no path on four vertices. - - See Also - -------- - full_join - union - - References - ---------- - .. [1] D.G. Corneil, H. Lerchs, L.Stewart Burlingham, - "Complement reducible graphs", - Discrete Applied Mathematics, Volume 3, Issue 3, 1981, Pages 163-174, - ISSN 0166-218X. - """ - R = nx.empty_graph(1) - - for i in range(n): - RR = nx.relabel_nodes(R.copy(), lambda x: x + len(R)) - - if seed.randint(0, 1) == 0: - R = nx.full_join(R, RR) - else: - R = nx.disjoint_union(R, RR) - - return R diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/community.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/community.py deleted file mode 100644 index a7f2294..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/community.py +++ /dev/null @@ -1,1070 +0,0 @@ -"""Generators for classes of graphs used in studying social networks.""" - -import itertools -import math - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "caveman_graph", - "connected_caveman_graph", - "relaxed_caveman_graph", - "random_partition_graph", - "planted_partition_graph", - "gaussian_random_partition_graph", - "ring_of_cliques", - "windmill_graph", - "stochastic_block_model", - "LFR_benchmark_graph", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def caveman_graph(l, k): - """Returns a caveman graph of `l` cliques of size `k`. - - Parameters - ---------- - l : int - Number of cliques - k : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - caveman graph - - Notes - ----- - This returns an undirected graph, it can be converted to a directed - graph using :func:`nx.to_directed`, or a multigraph using - ``nx.MultiGraph(nx.caveman_graph(l, k))``. Only the undirected version is - described in [1]_ and it is unclear which of the directed - generalizations is most useful. - - Examples - -------- - >>> G = nx.caveman_graph(3, 3) - - See also - -------- - - connected_caveman_graph - - References - ---------- - .. [1] Watts, D. J. 'Networks, Dynamics, and the Small-World Phenomenon.' - Amer. J. Soc. 105, 493-527, 1999. - """ - # l disjoint cliques of size k - G = nx.empty_graph(l * k) - if k > 1: - for start in range(0, l * k, k): - edges = itertools.combinations(range(start, start + k), 2) - G.add_edges_from(edges) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def connected_caveman_graph(l, k): - """Returns a connected caveman graph of `l` cliques of size `k`. - - The connected caveman graph is formed by creating `n` cliques of size - `k`, then a single edge in each clique is rewired to a node in an - adjacent clique. - - Parameters - ---------- - l : int - number of cliques - k : int - size of cliques (k at least 2 or NetworkXError is raised) - - Returns - ------- - G : NetworkX Graph - connected caveman graph - - Raises - ------ - NetworkXError - If the size of cliques `k` is smaller than 2. - - Notes - ----- - This returns an undirected graph, it can be converted to a directed - graph using :func:`nx.to_directed`, or a multigraph using - ``nx.MultiGraph(nx.caveman_graph(l, k))``. Only the undirected version is - described in [1]_ and it is unclear which of the directed - generalizations is most useful. - - Examples - -------- - >>> G = nx.connected_caveman_graph(3, 3) - - References - ---------- - .. [1] Watts, D. J. 'Networks, Dynamics, and the Small-World Phenomenon.' - Amer. J. Soc. 105, 493-527, 1999. - """ - if k < 2: - raise nx.NetworkXError( - "The size of cliques in a connected caveman graph must be at least 2." - ) - - G = nx.caveman_graph(l, k) - for start in range(0, l * k, k): - G.remove_edge(start, start + 1) - G.add_edge(start, (start - 1) % (l * k)) - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def relaxed_caveman_graph(l, k, p, seed=None): - """Returns a relaxed caveman graph. - - A relaxed caveman graph starts with `l` cliques of size `k`. Edges are - then randomly rewired with probability `p` to link different cliques. - - Parameters - ---------- - l : int - Number of groups - k : int - Size of cliques - p : float - Probability of rewiring each edge. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph - Relaxed Caveman Graph - - Raises - ------ - NetworkXError - If p is not in [0,1] - - Examples - -------- - >>> G = nx.relaxed_caveman_graph(2, 3, 0.1, seed=42) - - References - ---------- - .. [1] Santo Fortunato, Community Detection in Graphs, - Physics Reports Volume 486, Issues 3-5, February 2010, Pages 75-174. - https://arxiv.org/abs/0906.0612 - """ - G = nx.caveman_graph(l, k) - nodes = list(G) - for u, v in G.edges(): - if seed.random() < p: # rewire the edge - x = seed.choice(nodes) - if G.has_edge(u, x): - continue - G.remove_edge(u, v) - G.add_edge(u, x) - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_partition_graph(sizes, p_in, p_out, seed=None, directed=False): - """Returns the random partition graph with a partition of sizes. - - A partition graph is a graph of communities with sizes defined by - s in sizes. Nodes in the same group are connected with probability - p_in and nodes of different groups are connected with probability - p_out. - - Parameters - ---------- - sizes : list of ints - Sizes of groups - p_in : float - probability of edges with in groups - p_out : float - probability of edges between groups - directed : boolean optional, default=False - Whether to create a directed graph - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph or DiGraph - random partition graph of size sum(gs) - - Raises - ------ - NetworkXError - If p_in or p_out is not in [0,1] - - Examples - -------- - >>> G = nx.random_partition_graph([10, 10, 10], 0.25, 0.01) - >>> len(G) - 30 - >>> partition = G.graph["partition"] - >>> len(partition) - 3 - - Notes - ----- - This is a generalization of the planted-l-partition described in - [1]_. It allows for the creation of groups of any size. - - The partition is store as a graph attribute 'partition'. - - References - ---------- - .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174. https://arxiv.org/abs/0906.0612 - """ - # Use geometric method for O(n+m) complexity algorithm - # partition = nx.community_sets(nx.get_node_attributes(G, 'affiliation')) - if not 0.0 <= p_in <= 1.0: - raise nx.NetworkXError("p_in must be in [0,1]") - if not 0.0 <= p_out <= 1.0: - raise nx.NetworkXError("p_out must be in [0,1]") - - # create connection matrix - num_blocks = len(sizes) - p = [[p_out for s in range(num_blocks)] for r in range(num_blocks)] - for r in range(num_blocks): - p[r][r] = p_in - - return stochastic_block_model( - sizes, - p, - nodelist=None, - seed=seed, - directed=directed, - selfloops=False, - sparse=True, - ) - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def planted_partition_graph(l, k, p_in, p_out, seed=None, directed=False): - """Returns the planted l-partition graph. - - This model partitions a graph with n=l*k vertices in - l groups with k vertices each. Vertices of the same - group are linked with a probability p_in, and vertices - of different groups are linked with probability p_out. - - Parameters - ---------- - l : int - Number of groups - k : int - Number of vertices in each group - p_in : float - probability of connecting vertices within a group - p_out : float - probability of connected vertices between groups - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool,optional (default=False) - If True return a directed graph - - Returns - ------- - G : NetworkX Graph or DiGraph - planted l-partition graph - - Raises - ------ - NetworkXError - If `p_in`, `p_out` are not in `[0, 1]` - - Examples - -------- - >>> G = nx.planted_partition_graph(4, 3, 0.5, 0.1, seed=42) - - See Also - -------- - random_partition_model - - References - ---------- - .. [1] A. Condon, R.M. Karp, Algorithms for graph partitioning - on the planted partition model, - Random Struct. Algor. 18 (2001) 116-140. - - .. [2] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174. https://arxiv.org/abs/0906.0612 - """ - return random_partition_graph([k] * l, p_in, p_out, seed=seed, directed=directed) - - -@py_random_state(6) -@nx._dispatchable(graphs=None, returns_graph=True) -def gaussian_random_partition_graph(n, s, v, p_in, p_out, directed=False, seed=None): - """Generate a Gaussian random partition graph. - - A Gaussian random partition graph is created by creating k partitions - each with a size drawn from a normal distribution with mean s and variance - s/v. Nodes are connected within clusters with probability p_in and - between clusters with probability p_out[1] - - Parameters - ---------- - n : int - Number of nodes in the graph - s : float - Mean cluster size - v : float - Shape parameter. The variance of cluster size distribution is s/v. - p_in : float - Probability of intra cluster connection. - p_out : float - Probability of inter cluster connection. - directed : boolean, optional default=False - Whether to create a directed graph or not - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph or DiGraph - gaussian random partition graph - - Raises - ------ - NetworkXError - If s is > n - If p_in or p_out is not in [0,1] - - Notes - ----- - Note the number of partitions is dependent on s,v and n, and that the - last partition may be considerably smaller, as it is sized to simply - fill out the nodes [1] - - See Also - -------- - random_partition_graph - - Examples - -------- - >>> G = nx.gaussian_random_partition_graph(100, 10, 10, 0.25, 0.1) - >>> len(G) - 100 - - References - ---------- - .. [1] Ulrik Brandes, Marco Gaertler, Dorothea Wagner, - Experiments on Graph Clustering Algorithms, - In the proceedings of the 11th Europ. Symp. Algorithms, 2003. - """ - if s > n: - raise nx.NetworkXError("s must be <= n") - assigned = 0 - sizes = [] - while True: - size = int(seed.gauss(s, s / v + 0.5)) - if size < 1: # how to handle 0 or negative sizes? - continue - if assigned + size >= n: - sizes.append(n - assigned) - break - assigned += size - sizes.append(size) - return random_partition_graph(sizes, p_in, p_out, seed=seed, directed=directed) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def ring_of_cliques(num_cliques, clique_size): - """Defines a "ring of cliques" graph. - - A ring of cliques graph is consisting of cliques, connected through single - links. Each clique is a complete graph. - - Parameters - ---------- - num_cliques : int - Number of cliques - clique_size : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - ring of cliques graph - - Raises - ------ - NetworkXError - If the number of cliques is lower than 2 or - if the size of cliques is smaller than 2. - - Examples - -------- - >>> G = nx.ring_of_cliques(8, 4) - - See Also - -------- - connected_caveman_graph - - Notes - ----- - The `connected_caveman_graph` graph removes a link from each clique to - connect it with the next clique. Instead, the `ring_of_cliques` graph - simply adds the link without removing any link from the cliques. - """ - if num_cliques < 2: - raise nx.NetworkXError("A ring of cliques must have at least two cliques") - if clique_size < 2: - raise nx.NetworkXError("The cliques must have at least two nodes") - - G = nx.Graph() - for i in range(num_cliques): - edges = itertools.combinations( - range(i * clique_size, i * clique_size + clique_size), 2 - ) - G.add_edges_from(edges) - G.add_edge( - i * clique_size + 1, (i + 1) * clique_size % (num_cliques * clique_size) - ) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def windmill_graph(n, k): - """Generate a windmill graph. - A windmill graph is a graph of `n` cliques each of size `k` that are all - joined at one node. - It can be thought of as taking a disjoint union of `n` cliques of size `k`, - selecting one point from each, and contracting all of the selected points. - Alternatively, one could generate `n` cliques of size `k-1` and one node - that is connected to all other nodes in the graph. - - Parameters - ---------- - n : int - Number of cliques - k : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - windmill graph with n cliques of size k - - Raises - ------ - NetworkXError - If the number of cliques is less than two - If the size of the cliques are less than two - - Examples - -------- - >>> G = nx.windmill_graph(4, 5) - - Notes - ----- - The node labeled `0` will be the node connected to all other nodes. - Note that windmill graphs are usually denoted `Wd(k,n)`, so the parameters - are in the opposite order as the parameters of this method. - """ - if n < 2: - msg = "A windmill graph must have at least two cliques" - raise nx.NetworkXError(msg) - if k < 2: - raise nx.NetworkXError("The cliques must have at least two nodes") - - G = nx.disjoint_union_all( - itertools.chain( - [nx.complete_graph(k)], (nx.complete_graph(k - 1) for _ in range(n - 1)) - ) - ) - G.add_edges_from((0, i) for i in range(k, G.number_of_nodes())) - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def stochastic_block_model( - sizes, p, nodelist=None, seed=None, directed=False, selfloops=False, sparse=True -): - """Returns a stochastic block model graph. - - This model partitions the nodes in blocks of arbitrary sizes, and places - edges between pairs of nodes independently, with a probability that depends - on the blocks. - - Parameters - ---------- - sizes : list of ints - Sizes of blocks - p : list of list of floats - Element (r,s) gives the density of edges going from the nodes - of group r to nodes of group s. - p must match the number of groups (len(sizes) == len(p)), - and it must be symmetric if the graph is undirected. - nodelist : list, optional - The block tags are assigned according to the node identifiers - in nodelist. If nodelist is None, then the ordering is the - range [0,sum(sizes)-1]. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : boolean optional, default=False - Whether to create a directed graph or not. - selfloops : boolean optional, default=False - Whether to include self-loops or not. - sparse: boolean optional, default=True - Use the sparse heuristic to speed up the generator. - - Returns - ------- - g : NetworkX Graph or DiGraph - Stochastic block model graph of size sum(sizes) - - Raises - ------ - NetworkXError - If probabilities are not in [0,1]. - If the probability matrix is not square (directed case). - If the probability matrix is not symmetric (undirected case). - If the sizes list does not match nodelist or the probability matrix. - If nodelist contains duplicate. - - Examples - -------- - >>> sizes = [75, 75, 300] - >>> probs = [[0.25, 0.05, 0.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]] - >>> g = nx.stochastic_block_model(sizes, probs, seed=0) - >>> len(g) - 450 - >>> H = nx.quotient_graph(g, g.graph["partition"], relabel=True) - >>> for v in H.nodes(data=True): - ... print(round(v[1]["density"], 3)) - 0.245 - 0.348 - 0.405 - >>> for v in H.edges(data=True): - ... print(round(1.0 * v[2]["weight"] / (sizes[v[0]] * sizes[v[1]]), 3)) - 0.051 - 0.022 - 0.07 - - See Also - -------- - random_partition_graph - planted_partition_graph - gaussian_random_partition_graph - gnp_random_graph - - References - ---------- - .. [1] Holland, P. W., Laskey, K. B., & Leinhardt, S., - "Stochastic blockmodels: First steps", - Social networks, 5(2), 109-137, 1983. - """ - # Check if dimensions match - if len(sizes) != len(p): - raise nx.NetworkXException("'sizes' and 'p' do not match.") - # Check for probability symmetry (undirected) and shape (directed) - for row in p: - if len(p) != len(row): - raise nx.NetworkXException("'p' must be a square matrix.") - if not directed: - p_transpose = [list(i) for i in zip(*p)] - for i in zip(p, p_transpose): - for j in zip(i[0], i[1]): - if abs(j[0] - j[1]) > 1e-08: - raise nx.NetworkXException("'p' must be symmetric.") - # Check for probability range - for row in p: - for prob in row: - if prob < 0 or prob > 1: - raise nx.NetworkXException("Entries of 'p' not in [0,1].") - # Check for nodelist consistency - if nodelist is not None: - if len(nodelist) != sum(sizes): - raise nx.NetworkXException("'nodelist' and 'sizes' do not match.") - if len(nodelist) != len(set(nodelist)): - raise nx.NetworkXException("nodelist contains duplicate.") - else: - nodelist = range(sum(sizes)) - - # Setup the graph conditionally to the directed switch. - block_range = range(len(sizes)) - if directed: - g = nx.DiGraph() - block_iter = itertools.product(block_range, block_range) - else: - g = nx.Graph() - block_iter = itertools.combinations_with_replacement(block_range, 2) - # Split nodelist in a partition (list of sets). - size_cumsum = [sum(sizes[0:x]) for x in range(len(sizes) + 1)] - g.graph["partition"] = [ - set(nodelist[size_cumsum[x] : size_cumsum[x + 1]]) - for x in range(len(size_cumsum) - 1) - ] - # Setup nodes and graph name - for block_id, nodes in enumerate(g.graph["partition"]): - for node in nodes: - g.add_node(node, block=block_id) - - g.name = "stochastic_block_model" - - # Test for edge existence - parts = g.graph["partition"] - for i, j in block_iter: - if i == j: - if directed: - if selfloops: - edges = itertools.product(parts[i], parts[i]) - else: - edges = itertools.permutations(parts[i], 2) - else: - edges = itertools.combinations(parts[i], 2) - if selfloops: - edges = itertools.chain(edges, zip(parts[i], parts[i])) - for e in edges: - if seed.random() < p[i][j]: - g.add_edge(*e) - else: - edges = itertools.product(parts[i], parts[j]) - if sparse: - if p[i][j] == 1: # Test edges cases p_ij = 0 or 1 - for e in edges: - g.add_edge(*e) - elif p[i][j] > 0: - while True: - try: - logrand = math.log(seed.random()) - skip = math.floor(logrand / math.log(1 - p[i][j])) - # consume "skip" edges - next(itertools.islice(edges, skip, skip), None) - e = next(edges) - g.add_edge(*e) # __safe - except StopIteration: - break - else: - for e in edges: - if seed.random() < p[i][j]: - g.add_edge(*e) # __safe - return g - - -def _zipf_rv_below(gamma, xmin, threshold, seed): - """Returns a random value chosen from the bounded Zipf distribution. - - Repeatedly draws values from the Zipf distribution until the - threshold is met, then returns that value. - """ - result = nx.utils.zipf_rv(gamma, xmin, seed) - while result > threshold: - result = nx.utils.zipf_rv(gamma, xmin, seed) - return result - - -def _powerlaw_sequence(gamma, low, high, condition, length, max_iters, seed): - """Returns a list of numbers obeying a constrained power law distribution. - - ``gamma`` and ``low`` are the parameters for the Zipf distribution. - - ``high`` is the maximum allowed value for values draw from the Zipf - distribution. For more information, see :func:`_zipf_rv_below`. - - ``condition`` and ``length`` are Boolean-valued functions on - lists. While generating the list, random values are drawn and - appended to the list until ``length`` is satisfied by the created - list. Once ``condition`` is satisfied, the sequence generated in - this way is returned. - - ``max_iters`` indicates the number of times to generate a list - satisfying ``length``. If the number of iterations exceeds this - value, :exc:`~networkx.exception.ExceededMaxIterations` is raised. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - for i in range(max_iters): - seq = [] - while not length(seq): - seq.append(_zipf_rv_below(gamma, low, high, seed)) - if condition(seq): - return seq - raise nx.ExceededMaxIterations("Could not create power law sequence") - - -def _hurwitz_zeta(x, q, tolerance): - """The Hurwitz zeta function, or the Riemann zeta function of two arguments. - - ``x`` must be greater than one and ``q`` must be positive. - - This function repeatedly computes subsequent partial sums until - convergence, as decided by ``tolerance``. - """ - z = 0 - z_prev = -float("inf") - k = 0 - while abs(z - z_prev) > tolerance: - z_prev = z - z += 1 / ((k + q) ** x) - k += 1 - return z - - -def _generate_min_degree(gamma, average_degree, max_degree, tolerance, max_iters): - """Returns a minimum degree from the given average degree.""" - # Defines zeta function whether or not Scipy is available - try: - from scipy.special import zeta - except ImportError: - - def zeta(x, q): - return _hurwitz_zeta(x, q, tolerance) - - min_deg_top = max_degree - min_deg_bot = 1 - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - itrs = 0 - mid_avg_deg = 0 - while abs(mid_avg_deg - average_degree) > tolerance: - if itrs > max_iters: - raise nx.ExceededMaxIterations("Could not match average_degree") - mid_avg_deg = 0 - for x in range(int(min_deg_mid), max_degree + 1): - mid_avg_deg += (x ** (-gamma + 1)) / zeta(gamma, min_deg_mid) - if mid_avg_deg > average_degree: - min_deg_top = min_deg_mid - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - else: - min_deg_bot = min_deg_mid - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - itrs += 1 - # return int(min_deg_mid + 0.5) - return round(min_deg_mid) - - -def _generate_communities(degree_seq, community_sizes, mu, max_iters, seed): - """Returns a list of sets, each of which represents a community. - - ``degree_seq`` is the degree sequence that must be met by the - graph. - - ``community_sizes`` is the community size distribution that must be - met by the generated list of sets. - - ``mu`` is a float in the interval [0, 1] indicating the fraction of - intra-community edges incident to each node. - - ``max_iters`` is the number of times to try to add a node to a - community. This must be greater than the length of - ``degree_seq``, otherwise this function will always fail. If - the number of iterations exceeds this value, - :exc:`~networkx.exception.ExceededMaxIterations` is raised. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - The communities returned by this are sets of integers in the set {0, - ..., *n* - 1}, where *n* is the length of ``degree_seq``. - - """ - # This assumes the nodes in the graph will be natural numbers. - result = [set() for _ in community_sizes] - n = len(degree_seq) - free = list(range(n)) - for i in range(max_iters): - v = free.pop() - c = seed.choice(range(len(community_sizes))) - # s = int(degree_seq[v] * (1 - mu) + 0.5) - s = round(degree_seq[v] * (1 - mu)) - # If the community is large enough, add the node to the chosen - # community. Otherwise, return it to the list of unaffiliated - # nodes. - if s < community_sizes[c]: - result[c].add(v) - else: - free.append(v) - # If the community is too big, remove a node from it. - if len(result[c]) > community_sizes[c]: - free.append(result[c].pop()) - if not free: - return result - msg = "Could not assign communities; try increasing min_community" - raise nx.ExceededMaxIterations(msg) - - -@py_random_state(11) -@nx._dispatchable(graphs=None, returns_graph=True) -def LFR_benchmark_graph( - n, - tau1, - tau2, - mu, - average_degree=None, - min_degree=None, - max_degree=None, - min_community=None, - max_community=None, - tol=1.0e-7, - max_iters=500, - seed=None, -): - r"""Returns the LFR benchmark graph. - - This algorithm proceeds as follows: - - 1) Find a degree sequence with a power law distribution, and minimum - value ``min_degree``, which has approximate average degree - ``average_degree``. This is accomplished by either - - a) specifying ``min_degree`` and not ``average_degree``, - b) specifying ``average_degree`` and not ``min_degree``, in which - case a suitable minimum degree will be found. - - ``max_degree`` can also be specified, otherwise it will be set to - ``n``. Each node *u* will have $\mu \mathrm{deg}(u)$ edges - joining it to nodes in communities other than its own and $(1 - - \mu) \mathrm{deg}(u)$ edges joining it to nodes in its own - community. - 2) Generate community sizes according to a power law distribution - with exponent ``tau2``. If ``min_community`` and - ``max_community`` are not specified they will be selected to be - ``min_degree`` and ``max_degree``, respectively. Community sizes - are generated until the sum of their sizes equals ``n``. - 3) Each node will be randomly assigned a community with the - condition that the community is large enough for the node's - intra-community degree, $(1 - \mu) \mathrm{deg}(u)$ as - described in step 2. If a community grows too large, a random node - will be selected for reassignment to a new community, until all - nodes have been assigned a community. - 4) Each node *u* then adds $(1 - \mu) \mathrm{deg}(u)$ - intra-community edges and $\mu \mathrm{deg}(u)$ inter-community - edges. - - Parameters - ---------- - n : int - Number of nodes in the created graph. - - tau1 : float - Power law exponent for the degree distribution of the created - graph. This value must be strictly greater than one. - - tau2 : float - Power law exponent for the community size distribution in the - created graph. This value must be strictly greater than one. - - mu : float - Fraction of inter-community edges incident to each node. This - value must be in the interval [0, 1]. - - average_degree : float - Desired average degree of nodes in the created graph. This value - must be in the interval [0, *n*]. Exactly one of this and - ``min_degree`` must be specified, otherwise a - :exc:`NetworkXError` is raised. - - min_degree : int - Minimum degree of nodes in the created graph. This value must be - in the interval [0, *n*]. Exactly one of this and - ``average_degree`` must be specified, otherwise a - :exc:`NetworkXError` is raised. - - max_degree : int - Maximum degree of nodes in the created graph. If not specified, - this is set to ``n``, the total number of nodes in the graph. - - min_community : int - Minimum size of communities in the graph. If not specified, this - is set to ``min_degree``. - - max_community : int - Maximum size of communities in the graph. If not specified, this - is set to ``n``, the total number of nodes in the graph. - - tol : float - Tolerance when comparing floats, specifically when comparing - average degree values. - - max_iters : int - Maximum number of iterations to try to create the community sizes, - degree distribution, and community affiliations. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX graph - The LFR benchmark graph generated according to the specified - parameters. - - Each node in the graph has a node attribute ``'community'`` that - stores the community (that is, the set of nodes) that includes - it. - - Raises - ------ - NetworkXError - If any of the parameters do not meet their upper and lower bounds: - - - ``tau1`` and ``tau2`` must be strictly greater than 1. - - ``mu`` must be in [0, 1]. - - ``max_degree`` must be in {1, ..., *n*}. - - ``min_community`` and ``max_community`` must be in {0, ..., - *n*}. - - If not exactly one of ``average_degree`` and ``min_degree`` is - specified. - - If ``min_degree`` is not specified and a suitable ``min_degree`` - cannot be found. - - ExceededMaxIterations - If a valid degree sequence cannot be created within - ``max_iters`` number of iterations. - - If a valid set of community sizes cannot be created within - ``max_iters`` number of iterations. - - If a valid community assignment cannot be created within ``10 * - n * max_iters`` number of iterations. - - Examples - -------- - Basic usage:: - - >>> from networkx.generators.community import LFR_benchmark_graph - >>> n = 250 - >>> tau1 = 3 - >>> tau2 = 1.5 - >>> mu = 0.1 - >>> G = LFR_benchmark_graph( - ... n, tau1, tau2, mu, average_degree=5, min_community=20, seed=10 - ... ) - - Continuing the example above, you can get the communities from the - node attributes of the graph:: - - >>> communities = {frozenset(G.nodes[v]["community"]) for v in G} - - Notes - ----- - This algorithm differs slightly from the original way it was - presented in [1]. - - 1) Rather than connecting the graph via a configuration model then - rewiring to match the intra-community and inter-community - degrees, we do this wiring explicitly at the end, which should be - equivalent. - 2) The code posted on the author's website [2] calculates the random - power law distributed variables and their average using - continuous approximations, whereas we use the discrete - distributions here as both degree and community size are - discrete. - - Though the authors describe the algorithm as quite robust, testing - during development indicates that a somewhat narrower parameter set - is likely to successfully produce a graph. Some suggestions have - been provided in the event of exceptions. - - References - ---------- - .. [1] "Benchmark graphs for testing community detection algorithms", - Andrea Lancichinetti, Santo Fortunato, and Filippo Radicchi, - Phys. Rev. E 78, 046110 2008 - .. [2] https://www.santofortunato.net/resources - - """ - # Perform some basic parameter validation. - if not tau1 > 1: - raise nx.NetworkXError("tau1 must be greater than one") - if not tau2 > 1: - raise nx.NetworkXError("tau2 must be greater than one") - if not 0 <= mu <= 1: - raise nx.NetworkXError("mu must be in the interval [0, 1]") - - # Validate parameters for generating the degree sequence. - if max_degree is None: - max_degree = n - elif not 0 < max_degree <= n: - raise nx.NetworkXError("max_degree must be in the interval (0, n]") - if not ((min_degree is None) ^ (average_degree is None)): - raise nx.NetworkXError( - "Must assign exactly one of min_degree and average_degree" - ) - if min_degree is None: - min_degree = _generate_min_degree( - tau1, average_degree, max_degree, tol, max_iters - ) - - # Generate a degree sequence with a power law distribution. - low, high = min_degree, max_degree - - def condition(seq): - return sum(seq) % 2 == 0 - - def length(seq): - return len(seq) >= n - - deg_seq = _powerlaw_sequence(tau1, low, high, condition, length, max_iters, seed) - - # Validate parameters for generating the community size sequence. - if min_community is None: - min_community = min(deg_seq) - if max_community is None: - max_community = max(deg_seq) - - # Generate a community size sequence with a power law distribution. - # - # TODO The original code incremented the number of iterations each - # time a new Zipf random value was drawn from the distribution. This - # differed from the way the number of iterations was incremented in - # `_powerlaw_degree_sequence`, so this code was changed to match - # that one. As a result, this code is allowed many more chances to - # generate a valid community size sequence. - low, high = min_community, max_community - - def condition(seq): - return sum(seq) == n - - def length(seq): - return sum(seq) >= n - - comms = _powerlaw_sequence(tau2, low, high, condition, length, max_iters, seed) - - # Generate the communities based on the given degree sequence and - # community sizes. - max_iters *= 10 * n - communities = _generate_communities(deg_seq, comms, mu, max_iters, seed) - - # Finally, generate the benchmark graph based on the given - # communities, joining nodes according to the intra- and - # inter-community degrees. - G = nx.Graph() - G.add_nodes_from(range(n)) - for c in communities: - for u in c: - while G.degree(u) < round(deg_seq[u] * (1 - mu)): - v = seed.choice(list(c)) - G.add_edge(u, v) - while G.degree(u) < deg_seq[u]: - v = seed.choice(range(n)) - if v not in c: - G.add_edge(u, v) - G.nodes[u]["community"] = c - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/degree_seq.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/degree_seq.py deleted file mode 100644 index a27dd22..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/degree_seq.py +++ /dev/null @@ -1,867 +0,0 @@ -"""Generate graphs with a given degree sequence or expected degree sequence.""" - -import heapq -import math -from itertools import chain, combinations, zip_longest -from operator import itemgetter - -import networkx as nx -from networkx.utils import py_random_state, random_weighted_sample - -__all__ = [ - "configuration_model", - "directed_configuration_model", - "expected_degree_graph", - "havel_hakimi_graph", - "directed_havel_hakimi_graph", - "degree_sequence_tree", - "random_degree_sequence_graph", -] - -chaini = chain.from_iterable - - -def _to_stublist(degree_sequence): - """Returns a list of degree-repeated node numbers. - - ``degree_sequence`` is a list of nonnegative integers representing - the degrees of nodes in a graph. - - This function returns a list of node numbers with multiplicities - according to the given degree sequence. For example, if the first - element of ``degree_sequence`` is ``3``, then the first node number, - ``0``, will appear at the head of the returned list three times. The - node numbers are assumed to be the numbers zero through - ``len(degree_sequence) - 1``. - - Examples - -------- - - >>> degree_sequence = [1, 2, 3] - >>> _to_stublist(degree_sequence) - [0, 1, 1, 2, 2, 2] - - If a zero appears in the sequence, that means the node exists but - has degree zero, so that number will be skipped in the returned - list:: - - >>> degree_sequence = [2, 0, 1] - >>> _to_stublist(degree_sequence) - [0, 0, 2] - - """ - return list(chaini([n] * d for n, d in enumerate(degree_sequence))) - - -def _configuration_model( - deg_sequence, create_using, directed=False, in_deg_sequence=None, seed=None -): - """Helper function for generating either undirected or directed - configuration model graphs. - - ``deg_sequence`` is a list of nonnegative integers representing the - degree of the node whose label is the index of the list element. - - ``create_using`` see :func:`~networkx.empty_graph`. - - ``directed`` and ``in_deg_sequence`` are required if you want the - returned graph to be generated using the directed configuration - model algorithm. If ``directed`` is ``False``, then ``deg_sequence`` - is interpreted as the degree sequence of an undirected graph and - ``in_deg_sequence`` is ignored. Otherwise, if ``directed`` is - ``True``, then ``deg_sequence`` is interpreted as the out-degree - sequence and ``in_deg_sequence`` as the in-degree sequence of a - directed graph. - - .. note:: - - ``deg_sequence`` and ``in_deg_sequence`` need not be the same - length. - - ``seed`` is a random.Random or numpy.random.RandomState instance - - This function returns a graph, directed if and only if ``directed`` - is ``True``, generated according to the configuration model - algorithm. For more information on the algorithm, see the - :func:`configuration_model` or :func:`directed_configuration_model` - functions. - - """ - n = len(deg_sequence) - G = nx.empty_graph(n, create_using) - # If empty, return the null graph immediately. - if n == 0: - return G - # Build a list of available degree-repeated nodes. For example, - # for degree sequence [3, 2, 1, 1, 1], the "stub list" is - # initially [0, 0, 0, 1, 1, 2, 3, 4], that is, node 0 has degree - # 3 and thus is repeated 3 times, etc. - # - # Also, shuffle the stub list in order to get a random sequence of - # node pairs. - if directed: - pairs = zip_longest(deg_sequence, in_deg_sequence, fillvalue=0) - # Unzip the list of pairs into a pair of lists. - out_deg, in_deg = zip(*pairs) - - out_stublist = _to_stublist(out_deg) - in_stublist = _to_stublist(in_deg) - - seed.shuffle(out_stublist) - seed.shuffle(in_stublist) - else: - stublist = _to_stublist(deg_sequence) - # Choose a random balanced bipartition of the stublist, which - # gives a random pairing of nodes. In this implementation, we - # shuffle the list and then split it in half. - n = len(stublist) - half = n // 2 - seed.shuffle(stublist) - out_stublist, in_stublist = stublist[:half], stublist[half:] - G.add_edges_from(zip(out_stublist, in_stublist)) - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def configuration_model(deg_sequence, create_using=None, seed=None): - """Returns a random graph with the given degree sequence. - - The configuration model generates a random pseudograph (graph with - parallel edges and self loops) by randomly assigning edges to - match the given degree sequence. - - Parameters - ---------- - deg_sequence : list of nonnegative integers - Each list entry corresponds to the degree of a node. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiGraph - A graph with the specified degree sequence. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence. - - Raises - ------ - NetworkXError - If the degree sequence does not have an even sum. - - See Also - -------- - is_graphical - - Notes - ----- - As described by Newman [1]_. - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the degree - sequence does not have an even sum. - - This configuration model construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. - - The density of self-loops and parallel edges tends to decrease as - the number of nodes increases. However, typically the number of - self-loops will approach a Poisson distribution with a nonzero mean, - and similarly for the number of parallel edges. Consider a node - with *k* stubs. The probability of being joined to another stub of - the same node is basically (*k* - *1*) / *N*, where *k* is the - degree and *N* is the number of nodes. So the probability of a - self-loop scales like *c* / *N* for some constant *c*. As *N* grows, - this means we expect *c* self-loops. Similarly for parallel edges. - - References - ---------- - .. [1] M.E.J. Newman, "The structure and function of complex networks", - SIAM REVIEW 45-2, pp 167-256, 2003. - - Examples - -------- - You can create a degree sequence following a particular distribution - by using the one of the distribution functions in - :mod:`~networkx.utils.random_sequence` (or one of your own). For - example, to create an undirected multigraph on one hundred nodes - with degree sequence chosen from the power law distribution: - - >>> sequence = nx.random_powerlaw_tree_sequence(100, tries=5000) - >>> G = nx.configuration_model(sequence) - >>> len(G) - 100 - >>> actual_degrees = [d for v, d in G.degree()] - >>> actual_degrees == sequence - True - - The returned graph is a multigraph, which may have parallel - edges. To remove any parallel edges from the returned graph: - - >>> G = nx.Graph(G) - - Similarly, to remove self-loops: - - >>> G.remove_edges_from(nx.selfloop_edges(G)) - - """ - if sum(deg_sequence) % 2 != 0: - msg = "Invalid degree sequence: sum of degrees must be even, not odd" - raise nx.NetworkXError(msg) - - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXNotImplemented("not implemented for directed graphs") - - G = _configuration_model(deg_sequence, G, seed=seed) - - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def directed_configuration_model( - in_degree_sequence, out_degree_sequence, create_using=None, seed=None -): - """Returns a directed_random graph with the given degree sequences. - - The configuration model generates a random directed pseudograph - (graph with parallel edges and self loops) by randomly assigning - edges to match the given degree sequences. - - Parameters - ---------- - in_degree_sequence : list of nonnegative integers - Each list entry corresponds to the in-degree of a node. - out_degree_sequence : list of nonnegative integers - Each list entry corresponds to the out-degree of a node. - create_using : NetworkX graph constructor, optional (default MultiDiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiDiGraph - A graph with the specified degree sequences. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence. - - Raises - ------ - NetworkXError - If the degree sequences do not have the same sum. - - See Also - -------- - configuration_model - - Notes - ----- - Algorithm as described by Newman [1]_. - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the degree - sequences does not have the same sum. - - This configuration model construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. This - "finite-size effect" decreases as the size of the graph increases. - - References - ---------- - .. [1] Newman, M. E. J. and Strogatz, S. H. and Watts, D. J. - Random graphs with arbitrary degree distributions and their applications - Phys. Rev. E, 64, 026118 (2001) - - Examples - -------- - One can modify the in- and out-degree sequences from an existing - directed graph in order to create a new directed graph. For example, - here we modify the directed path graph: - - >>> D = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - >>> din = list(d for n, d in D.in_degree()) - >>> dout = list(d for n, d in D.out_degree()) - >>> din.append(1) - >>> dout[0] = 2 - >>> # We now expect an edge from node 0 to a new node, node 3. - ... D = nx.directed_configuration_model(din, dout) - - The returned graph is a directed multigraph, which may have parallel - edges. To remove any parallel edges from the returned graph: - - >>> D = nx.DiGraph(D) - - Similarly, to remove self-loops: - - >>> D.remove_edges_from(nx.selfloop_edges(D)) - - """ - if sum(in_degree_sequence) != sum(out_degree_sequence): - msg = "Invalid degree sequences: sequences must have equal sums" - raise nx.NetworkXError(msg) - - if create_using is None: - create_using = nx.MultiDiGraph - - G = _configuration_model( - out_degree_sequence, - create_using, - directed=True, - in_deg_sequence=in_degree_sequence, - seed=seed, - ) - - name = "directed configuration_model {} nodes {} edges" - return G - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def expected_degree_graph(w, seed=None, selfloops=True): - r"""Returns a random graph with given expected degrees. - - Given a sequence of expected degrees $W=(w_0,w_1,\ldots,w_{n-1})$ - of length $n$ this algorithm assigns an edge between node $u$ and - node $v$ with probability - - .. math:: - - p_{uv} = \frac{w_u w_v}{\sum_k w_k} . - - Parameters - ---------- - w : list - The list of expected degrees. - selfloops: bool (default=True) - Set to False to remove the possibility of self-loop edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - - Examples - -------- - >>> z = [10 for i in range(100)] - >>> G = nx.expected_degree_graph(z) - - Notes - ----- - The nodes have integer labels corresponding to index of expected degrees - input sequence. - - The complexity of this algorithm is $\mathcal{O}(n+m)$ where $n$ is the - number of nodes and $m$ is the expected number of edges. - - The model in [1]_ includes the possibility of self-loop edges. - Set selfloops=False to produce a graph without self loops. - - For finite graphs this model doesn't produce exactly the given - expected degree sequence. Instead the expected degrees are as - follows. - - For the case without self loops (selfloops=False), - - .. math:: - - E[deg(u)] = \sum_{v \ne u} p_{uv} - = w_u \left( 1 - \frac{w_u}{\sum_k w_k} \right) . - - - NetworkX uses the standard convention that a self-loop edge counts 2 - in the degree of a node, so with self loops (selfloops=True), - - .. math:: - - E[deg(u)] = \sum_{v \ne u} p_{uv} + 2 p_{uu} - = w_u \left( 1 + \frac{w_u}{\sum_k w_k} \right) . - - References - ---------- - .. [1] Fan Chung and L. Lu, Connected components in random graphs with - given expected degree sequences, Ann. Combinatorics, 6, - pp. 125-145, 2002. - .. [2] Joel Miller and Aric Hagberg, - Efficient generation of networks with given expected degrees, - in Algorithms and Models for the Web-Graph (WAW 2011), - Alan Frieze, Paul Horn, and PaweÅ‚ PraÅ‚at (Eds), LNCS 6732, - pp. 115-126, 2011. - """ - n = len(w) - G = nx.empty_graph(n) - - # If there are no nodes are no edges in the graph, return the empty graph. - if n == 0 or max(w) == 0: - return G - - rho = 1 / sum(w) - # Sort the weights in decreasing order. The original order of the - # weights dictates the order of the (integer) node labels, so we - # need to remember the permutation applied in the sorting. - order = sorted(enumerate(w), key=itemgetter(1), reverse=True) - mapping = {c: u for c, (u, v) in enumerate(order)} - seq = [v for u, v in order] - last = n - if not selfloops: - last -= 1 - for u in range(last): - v = u - if not selfloops: - v += 1 - factor = seq[u] * rho - p = min(seq[v] * factor, 1) - while v < n and p > 0: - if p != 1: - r = seed.random() - v += math.floor(math.log(r, 1 - p)) - if v < n: - q = min(seq[v] * factor, 1) - if seed.random() < q / p: - G.add_edge(mapping[u], mapping[v]) - v += 1 - p = q - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def havel_hakimi_graph(deg_sequence, create_using=None): - """Returns a simple graph with given degree sequence constructed - using the Havel-Hakimi algorithm. - - Parameters - ---------- - deg_sequence: list of integers - Each integer corresponds to the degree of a node (need not be sorted). - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Directed graphs are not allowed. - - Raises - ------ - NetworkXException - For a non-graphical degree sequence (i.e. one - not realizable by some simple graph). - - Notes - ----- - The Havel-Hakimi algorithm constructs a simple graph by - successively connecting the node of highest degree to other nodes - of highest degree, resorting remaining nodes by degree, and - repeating the process. The resulting graph has a high - degree-associativity. Nodes are labeled 1,.., len(deg_sequence), - corresponding to their position in deg_sequence. - - The basic algorithm is from Hakimi [1]_ and was generalized by - Kleitman and Wang [2]_. - - References - ---------- - .. [1] Hakimi S., On Realizability of a Set of Integers as - Degrees of the Vertices of a Linear Graph. I, - Journal of SIAM, 10(3), pp. 496-506 (1962) - .. [2] Kleitman D.J. and Wang D.L. - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - if not nx.is_graphical(deg_sequence): - raise nx.NetworkXError("Invalid degree sequence") - - p = len(deg_sequence) - G = nx.empty_graph(p, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed graphs are not supported") - num_degs = [[] for i in range(p)] - dmax, dsum, n = 0, 0, 0 - for d in deg_sequence: - # Process only the non-zero integers - if d > 0: - num_degs[d].append(n) - dmax, dsum, n = max(dmax, d), dsum + d, n + 1 - # Return graph if no edges - if n == 0: - return G - - modstubs = [(0, 0)] * (dmax + 1) - # Successively reduce degree sequence by removing the maximum degree - while n > 0: - # Retrieve the maximum degree in the sequence - while len(num_degs[dmax]) == 0: - dmax -= 1 - # If there are not enough stubs to connect to, then the sequence is - # not graphical - if dmax > n - 1: - raise nx.NetworkXError("Non-graphical integer sequence") - - # Remove largest stub in list - source = num_degs[dmax].pop() - n -= 1 - # Reduce the next dmax largest stubs - mslen = 0 - k = dmax - for i in range(dmax): - while len(num_degs[k]) == 0: - k -= 1 - target = num_degs[k].pop() - G.add_edge(source, target) - n -= 1 - if k > 1: - modstubs[mslen] = (k - 1, target) - mslen += 1 - # Add back to the list any nonzero stubs that were removed - for i in range(mslen): - (stubval, stubtarget) = modstubs[i] - num_degs[stubval].append(stubtarget) - n += 1 - - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def directed_havel_hakimi_graph(in_deg_sequence, out_deg_sequence, create_using=None): - """Returns a directed graph with the given degree sequences. - - Parameters - ---------- - in_deg_sequence : list of integers - Each list entry corresponds to the in-degree of a node. - out_deg_sequence : list of integers - Each list entry corresponds to the out-degree of a node. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : DiGraph - A graph with the specified degree sequences. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence - - Raises - ------ - NetworkXError - If the degree sequences are not digraphical. - - See Also - -------- - configuration_model - - Notes - ----- - Algorithm as described by Kleitman and Wang [1]_. - - References - ---------- - .. [1] D.J. Kleitman and D.L. Wang - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - in_deg_sequence = nx.utils.make_list_of_ints(in_deg_sequence) - out_deg_sequence = nx.utils.make_list_of_ints(out_deg_sequence) - - # Process the sequences and form two heaps to store degree pairs with - # either zero or nonzero out degrees - sumin, sumout = 0, 0 - nin, nout = len(in_deg_sequence), len(out_deg_sequence) - maxn = max(nin, nout) - G = nx.empty_graph(maxn, create_using, default=nx.DiGraph) - if maxn == 0: - return G - maxin = 0 - stubheap, zeroheap = [], [] - for n in range(maxn): - in_deg, out_deg = 0, 0 - if n < nout: - out_deg = out_deg_sequence[n] - if n < nin: - in_deg = in_deg_sequence[n] - if in_deg < 0 or out_deg < 0: - raise nx.NetworkXError( - "Invalid degree sequences. Sequence values must be positive." - ) - sumin, sumout, maxin = sumin + in_deg, sumout + out_deg, max(maxin, in_deg) - if in_deg > 0: - stubheap.append((-1 * out_deg, -1 * in_deg, n)) - elif out_deg > 0: - zeroheap.append((-1 * out_deg, n)) - if sumin != sumout: - raise nx.NetworkXError( - "Invalid degree sequences. Sequences must have equal sums." - ) - heapq.heapify(stubheap) - heapq.heapify(zeroheap) - - modstubs = [(0, 0, 0)] * (maxin + 1) - # Successively reduce degree sequence by removing the maximum - while stubheap: - # Remove first value in the sequence with a non-zero in degree - (freeout, freein, target) = heapq.heappop(stubheap) - freein *= -1 - if freein > len(stubheap) + len(zeroheap): - raise nx.NetworkXError("Non-digraphical integer sequence") - - # Attach arcs from the nodes with the most stubs - mslen = 0 - for i in range(freein): - if zeroheap and (not stubheap or stubheap[0][0] > zeroheap[0][0]): - (stubout, stubsource) = heapq.heappop(zeroheap) - stubin = 0 - else: - (stubout, stubin, stubsource) = heapq.heappop(stubheap) - if stubout == 0: - raise nx.NetworkXError("Non-digraphical integer sequence") - G.add_edge(stubsource, target) - # Check if source is now totally connected - if stubout + 1 < 0 or stubin < 0: - modstubs[mslen] = (stubout + 1, stubin, stubsource) - mslen += 1 - - # Add the nodes back to the heaps that still have available stubs - for i in range(mslen): - stub = modstubs[i] - if stub[1] < 0: - heapq.heappush(stubheap, stub) - else: - heapq.heappush(zeroheap, (stub[0], stub[2])) - if freeout < 0: - heapq.heappush(zeroheap, (freeout, target)) - - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def degree_sequence_tree(deg_sequence, create_using=None): - """Make a tree for the given degree sequence. - - A tree has #nodes-#edges=1 so - the degree sequence must have - len(deg_sequence)-sum(deg_sequence)/2=1 - """ - # The sum of the degree sequence must be even (for any undirected graph). - degree_sum = sum(deg_sequence) - if degree_sum % 2 != 0: - msg = "Invalid degree sequence: sum of degrees must be even, not odd" - raise nx.NetworkXError(msg) - if len(deg_sequence) - degree_sum // 2 != 1: - msg = ( - "Invalid degree sequence: tree must have number of nodes equal" - " to one less than the number of edges" - ) - raise nx.NetworkXError(msg) - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # Sort all degrees greater than 1 in decreasing order. - # - # TODO Does this need to be sorted in reverse order? - deg = sorted((s for s in deg_sequence if s > 1), reverse=True) - - # make path graph as backbone - n = len(deg) + 2 - nx.add_path(G, range(n)) - last = n - - # add the leaves - for source in range(1, n - 1): - nedges = deg.pop() - 2 - for target in range(last, last + nedges): - G.add_edge(source, target) - last += nedges - - # in case we added one too many - if len(G) > len(deg_sequence): - G.remove_node(0) - return G - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_degree_sequence_graph(sequence, seed=None, tries=10): - r"""Returns a simple random graph with the given degree sequence. - - If the maximum degree $d_m$ in the sequence is $O(m^{1/4})$ then the - algorithm produces almost uniform random graphs in $O(m d_m)$ time - where $m$ is the number of edges. - - Parameters - ---------- - sequence : list of integers - Sequence of degrees - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int, optional - Maximum number of tries to create a graph - - Returns - ------- - G : Graph - A graph with the specified degree sequence. - Nodes are labeled starting at 0 with an index - corresponding to the position in the sequence. - - Raises - ------ - NetworkXUnfeasible - If the degree sequence is not graphical. - NetworkXError - If a graph is not produced in specified number of tries - - See Also - -------- - is_graphical, configuration_model - - Notes - ----- - The generator algorithm [1]_ is not guaranteed to produce a graph. - - References - ---------- - .. [1] Moshen Bayati, Jeong Han Kim, and Amin Saberi, - A sequential algorithm for generating random graphs. - Algorithmica, Volume 58, Number 4, 860-910, - DOI: 10.1007/s00453-009-9340-1 - - Examples - -------- - >>> sequence = [1, 2, 2, 3] - >>> G = nx.random_degree_sequence_graph(sequence, seed=42) - >>> sorted(d for n, d in G.degree()) - [1, 2, 2, 3] - """ - DSRG = DegreeSequenceRandomGraph(sequence, seed) - for try_n in range(tries): - try: - return DSRG.generate() - except nx.NetworkXUnfeasible: - pass - raise nx.NetworkXError(f"failed to generate graph in {tries} tries") - - -class DegreeSequenceRandomGraph: - # class to generate random graphs with a given degree sequence - # use random_degree_sequence_graph() - def __init__(self, degree, rng): - if not nx.is_graphical(degree): - raise nx.NetworkXUnfeasible("degree sequence is not graphical") - self.rng = rng - self.degree = list(degree) - # node labels are integers 0,...,n-1 - self.m = sum(self.degree) / 2.0 # number of edges - try: - self.dmax = max(self.degree) # maximum degree - except ValueError: - self.dmax = 0 - - def generate(self): - # remaining_degree is mapping from int->remaining degree - self.remaining_degree = dict(enumerate(self.degree)) - # add all nodes to make sure we get isolated nodes - self.graph = nx.Graph() - self.graph.add_nodes_from(self.remaining_degree) - # remove zero degree nodes - for n, d in list(self.remaining_degree.items()): - if d == 0: - del self.remaining_degree[n] - if len(self.remaining_degree) > 0: - # build graph in three phases according to how many unmatched edges - self.phase1() - self.phase2() - self.phase3() - return self.graph - - def update_remaining(self, u, v, aux_graph=None): - # decrement remaining nodes, modify auxiliary graph if in phase3 - if aux_graph is not None: - # remove edges from auxiliary graph - aux_graph.remove_edge(u, v) - if self.remaining_degree[u] == 1: - del self.remaining_degree[u] - if aux_graph is not None: - aux_graph.remove_node(u) - else: - self.remaining_degree[u] -= 1 - if self.remaining_degree[v] == 1: - del self.remaining_degree[v] - if aux_graph is not None: - aux_graph.remove_node(v) - else: - self.remaining_degree[v] -= 1 - - def p(self, u, v): - # degree probability - return 1 - self.degree[u] * self.degree[v] / (4.0 * self.m) - - def q(self, u, v): - # remaining degree probability - norm = max(self.remaining_degree.values()) ** 2 - return self.remaining_degree[u] * self.remaining_degree[v] / norm - - def suitable_edge(self): - """Returns True if and only if an arbitrary remaining node can - potentially be joined with some other remaining node. - - """ - nodes = iter(self.remaining_degree) - u = next(nodes) - return any(v not in self.graph[u] for v in nodes) - - def phase1(self): - # choose node pairs from (degree) weighted distribution - rem_deg = self.remaining_degree - while sum(rem_deg.values()) >= 2 * self.dmax**2: - u, v = sorted(random_weighted_sample(rem_deg, 2, self.rng)) - if self.graph.has_edge(u, v): - continue - if self.rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v) - - def phase2(self): - # choose remaining nodes uniformly at random and use rejection sampling - remaining_deg = self.remaining_degree - rng = self.rng - while len(remaining_deg) >= 2 * self.dmax: - while True: - u, v = sorted(rng.sample(list(remaining_deg.keys()), 2)) - if self.graph.has_edge(u, v): - continue - if rng.random() < self.q(u, v): - break - if rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v) - - def phase3(self): - # build potential remaining edges and choose with rejection sampling - potential_edges = combinations(self.remaining_degree, 2) - # build auxiliary graph of potential edges not already in graph - H = nx.Graph( - [(u, v) for (u, v) in potential_edges if not self.graph.has_edge(u, v)] - ) - rng = self.rng - while self.remaining_degree: - if not self.suitable_edge(): - raise nx.NetworkXUnfeasible("no suitable edges left") - while True: - u, v = sorted(rng.choice(list(H.edges()))) - if rng.random() < self.q(u, v): - break - if rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v, aux_graph=H) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/directed.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/directed.py deleted file mode 100644 index 4548726..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/directed.py +++ /dev/null @@ -1,501 +0,0 @@ -""" -Generators for some directed graphs, including growing network (GN) graphs and -scale-free graphs. - -""" - -import numbers -from collections import Counter - -import networkx as nx -from networkx.generators.classic import empty_graph -from networkx.utils import discrete_sequence, py_random_state, weighted_choice - -__all__ = [ - "gn_graph", - "gnc_graph", - "gnr_graph", - "random_k_out_graph", - "scale_free_graph", -] - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def gn_graph(n, kernel=None, create_using=None, seed=None): - """Returns the growing network (GN) digraph with `n` nodes. - - The GN graph is built by adding nodes one at a time with a link to one - previously added node. The target node for the link is chosen with - probability based on degree. The default attachment kernel is a linear - function of the degree of a node. - - The graph is always a (directed) tree. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - kernel : function - The attachment kernel. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - To create the undirected GN graph, use the :meth:`~DiGraph.to_directed` - method:: - - >>> D = nx.gn_graph(10) # the GN graph - >>> G = D.to_undirected() # the undirected version - - To specify an attachment kernel, use the `kernel` keyword argument:: - - >>> D = nx.gn_graph(10, kernel=lambda x: x**1.5) # A_k = k^1.5 - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Organization of Growing Random Networks, - Phys. Rev. E, 63, 066123, 2001. - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if kernel is None: - - def kernel(x): - return x - - if n == 1: - return G - - G.add_edge(1, 0) # get started - ds = [1, 1] # degree sequence - - for source in range(2, n): - # compute distribution from kernel and degree - dist = [kernel(d) for d in ds] - # choose target from discrete distribution - target = discrete_sequence(1, distribution=dist, seed=seed)[0] - G.add_edge(source, target) - ds.append(1) # the source has only one link (degree one) - ds[target] += 1 # add one to the target link degree - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def gnr_graph(n, p, create_using=None, seed=None): - """Returns the growing network with redirection (GNR) digraph with `n` - nodes and redirection probability `p`. - - The GNR graph is built by adding nodes one at a time with a link to one - previously added node. The previous target node is chosen uniformly at - random. With probability `p` the link is instead "redirected" to the - successor node of the target. - - The graph is always a (directed) tree. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - p : float - The redirection probability. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - To create the undirected GNR graph, use the :meth:`~DiGraph.to_directed` - method:: - - >>> D = nx.gnr_graph(10, 0.5) # the GNR graph - >>> G = D.to_undirected() # the undirected version - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Organization of Growing Random Networks, - Phys. Rev. E, 63, 066123, 2001. - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if n == 1: - return G - - for source in range(1, n): - target = seed.randrange(0, source) - if seed.random() < p and target != 0: - target = next(G.successors(target)) - G.add_edge(source, target) - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def gnc_graph(n, create_using=None, seed=None): - """Returns the growing network with copying (GNC) digraph with `n` nodes. - - The GNC graph is built by adding nodes one at a time with a link to one - previously added node (chosen uniformly at random) and to all of that - node's successors. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Network Growth by Copying, - Phys. Rev. E, 71, 036118, 2005k.}, - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if n == 1: - return G - - for source in range(1, n): - target = seed.randrange(0, source) - for succ in G.successors(target): - G.add_edge(source, succ) - G.add_edge(source, target) - return G - - -@py_random_state(6) -@nx._dispatchable(graphs=None, returns_graph=True) -def scale_free_graph( - n, - alpha=0.41, - beta=0.54, - gamma=0.05, - delta_in=0.2, - delta_out=0, - seed=None, - initial_graph=None, -): - """Returns a scale-free directed graph. - - Parameters - ---------- - n : integer - Number of nodes in graph - alpha : float - Probability for adding a new node connected to an existing node - chosen randomly according to the in-degree distribution. - beta : float - Probability for adding an edge between two existing nodes. - One existing node is chosen randomly according the in-degree - distribution and the other chosen randomly according to the out-degree - distribution. - gamma : float - Probability for adding a new node connected to an existing node - chosen randomly according to the out-degree distribution. - delta_in : float - Bias for choosing nodes from in-degree distribution. - delta_out : float - Bias for choosing nodes from out-degree distribution. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - initial_graph : MultiDiGraph instance, optional - Build the scale-free graph starting from this initial MultiDiGraph, - if provided. - - Returns - ------- - MultiDiGraph - - Examples - -------- - Create a scale-free graph on one hundred nodes:: - - >>> G = nx.scale_free_graph(100) - - Notes - ----- - The sum of `alpha`, `beta`, and `gamma` must be 1. - - References - ---------- - .. [1] B. Bollobás, C. Borgs, J. Chayes, and O. Riordan, - Directed scale-free graphs, - Proceedings of the fourteenth annual ACM-SIAM Symposium on - Discrete Algorithms, 132--139, 2003. - """ - - def _choose_node(candidates, node_list, delta): - if delta > 0: - bias_sum = len(node_list) * delta - p_delta = bias_sum / (bias_sum + len(candidates)) - if seed.random() < p_delta: - return seed.choice(node_list) - return seed.choice(candidates) - - if initial_graph is not None and hasattr(initial_graph, "_adj"): - if not isinstance(initial_graph, nx.MultiDiGraph): - raise nx.NetworkXError("initial_graph must be a MultiDiGraph.") - G = initial_graph - else: - # Start with 3-cycle - G = nx.MultiDiGraph([(0, 1), (1, 2), (2, 0)]) - - if alpha <= 0: - raise ValueError("alpha must be > 0.") - if beta <= 0: - raise ValueError("beta must be > 0.") - if gamma <= 0: - raise ValueError("gamma must be > 0.") - - if abs(alpha + beta + gamma - 1.0) >= 1e-9: - raise ValueError("alpha+beta+gamma must equal 1.") - - if delta_in < 0: - raise ValueError("delta_in must be >= 0.") - - if delta_out < 0: - raise ValueError("delta_out must be >= 0.") - - # pre-populate degree states - vs = sum((count * [idx] for idx, count in G.out_degree()), []) - ws = sum((count * [idx] for idx, count in G.in_degree()), []) - - # pre-populate node state - node_list = list(G.nodes()) - - # see if there already are number-based nodes - numeric_nodes = [n for n in node_list if isinstance(n, numbers.Number)] - if len(numeric_nodes) > 0: - # set cursor for new nodes appropriately - cursor = max(int(n.real) for n in numeric_nodes) + 1 - else: - # or start at zero - cursor = 0 - - while len(G) < n: - r = seed.random() - - # random choice in alpha,beta,gamma ranges - if r < alpha: - # alpha - # add new node v - v = cursor - cursor += 1 - # also add to node state - node_list.append(v) - # choose w according to in-degree and delta_in - w = _choose_node(ws, node_list, delta_in) - - elif r < alpha + beta: - # beta - # choose v according to out-degree and delta_out - v = _choose_node(vs, node_list, delta_out) - # choose w according to in-degree and delta_in - w = _choose_node(ws, node_list, delta_in) - - else: - # gamma - # choose v according to out-degree and delta_out - v = _choose_node(vs, node_list, delta_out) - # add new node w - w = cursor - cursor += 1 - # also add to node state - node_list.append(w) - - # add edge to graph - G.add_edge(v, w) - - # update degree states - vs.append(v) - ws.append(w) - - return G - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_uniform_k_out_graph(n, k, self_loops=True, with_replacement=True, seed=None): - """Returns a random `k`-out graph with uniform attachment. - - A random `k`-out graph with uniform attachment is a multidigraph - generated by the following algorithm. For each node *u*, choose - `k` nodes *v* uniformly at random (with replacement). Add a - directed edge joining *u* to *v*. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - - k : int - The out-degree of each node in the returned graph. - - self_loops : bool - If True, self-loops are allowed when generating the graph. - - with_replacement : bool - If True, neighbors are chosen with replacement and the - returned graph will be a directed multigraph. Otherwise, - neighbors are chosen without replacement and the returned graph - will be a directed graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - NetworkX graph - A `k`-out-regular directed graph generated according to the - above algorithm. It will be a multigraph if and only if - `with_replacement` is True. - - Raises - ------ - ValueError - If `with_replacement` is False and `k` is greater than - `n`. - - See also - -------- - random_k_out_graph - - Notes - ----- - The return digraph or multidigraph may not be strongly connected, or - even weakly connected. - - If `with_replacement` is True, this function is similar to - :func:`random_k_out_graph`, if that function had parameter `alpha` - set to positive infinity. - - """ - if with_replacement: - create_using = nx.MultiDiGraph() - - def sample(v, nodes): - if not self_loops: - nodes = nodes - {v} - return (seed.choice(list(nodes)) for i in range(k)) - - else: - create_using = nx.DiGraph() - - def sample(v, nodes): - if not self_loops: - nodes = nodes - {v} - return seed.sample(list(nodes), k) - - G = nx.empty_graph(n, create_using) - nodes = set(G) - for u in G: - G.add_edges_from((u, v) for v in sample(u, nodes)) - return G - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_k_out_graph(n, k, alpha, self_loops=True, seed=None): - """Returns a random `k`-out graph with preferential attachment. - - A random `k`-out graph with preferential attachment is a - multidigraph generated by the following algorithm. - - 1. Begin with an empty digraph, and initially set each node to have - weight `alpha`. - 2. Choose a node `u` with out-degree less than `k` uniformly at - random. - 3. Choose a node `v` from with probability proportional to its - weight. - 4. Add a directed edge from `u` to `v`, and increase the weight - of `v` by one. - 5. If each node has out-degree `k`, halt, otherwise repeat from - step 2. - - For more information on this model of random graph, see [1]. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - - k : int - The out-degree of each node in the returned graph. - - alpha : float - A positive :class:`float` representing the initial weight of - each vertex. A higher number means that in step 3 above, nodes - will be chosen more like a true uniformly random sample, and a - lower number means that nodes are more likely to be chosen as - their in-degree increases. If this parameter is not positive, a - :exc:`ValueError` is raised. - - self_loops : bool - If True, self-loops are allowed when generating the graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`~networkx.classes.MultiDiGraph` - A `k`-out-regular multidigraph generated according to the above - algorithm. - - Raises - ------ - ValueError - If `alpha` is not positive. - - Notes - ----- - The returned multidigraph may not be strongly connected, or even - weakly connected. - - References - ---------- - [1]: Peterson, Nicholas R., and Boris Pittel. - "Distance between two random `k`-out digraphs, with and without - preferential attachment." - arXiv preprint arXiv:1311.5961 (2013). - - - """ - if alpha < 0: - raise ValueError("alpha must be positive") - G = nx.empty_graph(n, create_using=nx.MultiDiGraph) - weights = Counter({v: alpha for v in G}) - for i in range(k * n): - u = seed.choice([v for v, d in G.out_degree() if d < k]) - # If self-loops are not allowed, make the source node `u` have - # weight zero. - if not self_loops: - adjustment = Counter({u: weights[u]}) - else: - adjustment = Counter() - v = weighted_choice(weights - adjustment, seed=seed) - G.add_edge(u, v) - weights[v] += 1 - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/duplication.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/duplication.py deleted file mode 100644 index 3c3ade6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/duplication.py +++ /dev/null @@ -1,174 +0,0 @@ -"""Functions for generating graphs based on the "duplication" method. - -These graph generators start with a small initial graph then duplicate -nodes and (partially) duplicate their edges. These functions are -generally inspired by biological networks. - -""" - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import py_random_state -from networkx.utils.misc import check_create_using - -__all__ = ["partial_duplication_graph", "duplication_divergence_graph"] - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def partial_duplication_graph(N, n, p, q, seed=None, *, create_using=None): - """Returns a random graph using the partial duplication model. - - Parameters - ---------- - N : int - The total number of nodes in the final graph. - - n : int - The number of nodes in the initial clique. - - p : float - The probability of joining each neighbor of a node to the - duplicate node. Must be a number in the between zero and one, - inclusive. - - q : float - The probability of joining the source node to the duplicate - node. Must be a number in the between zero and one, inclusive. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - A graph of nodes is grown by creating a fully connected graph - of size `n`. The following procedure is then repeated until - a total of `N` nodes have been reached. - - 1. A random node, *u*, is picked and a new node, *v*, is created. - 2. For each neighbor of *u* an edge from the neighbor to *v* is created - with probability `p`. - 3. An edge from *u* to *v* is created with probability `q`. - - This algorithm appears in [1]. - - This implementation allows the possibility of generating - disconnected graphs. - - References - ---------- - .. [1] Knudsen Michael, and Carsten Wiuf. "A Markov chain approach to - randomly grown graphs." Journal of Applied Mathematics 2008. - - - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if p < 0 or p > 1 or q < 0 or q > 1: - msg = "partial duplication graph must have 0 <= p, q <= 1." - raise NetworkXError(msg) - if n > N: - raise NetworkXError("partial duplication graph must have n <= N.") - - G = nx.complete_graph(n, create_using) - for new_node in range(n, N): - # Pick a random vertex, u, already in the graph. - src_node = seed.randint(0, new_node - 1) - - # Add a new vertex, v, to the graph. - G.add_node(new_node) - - # For each neighbor of u... - for nbr_node in list(nx.all_neighbors(G, src_node)): - # Add the neighbor to v with probability p. - if seed.random() < p: - G.add_edge(new_node, nbr_node) - - # Join v and u with probability q. - if seed.random() < q: - G.add_edge(new_node, src_node) - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def duplication_divergence_graph(n, p, seed=None, *, create_using=None): - """Returns an undirected graph using the duplication-divergence model. - - A graph of `n` nodes is created by duplicating the initial nodes - and retaining edges incident to the original nodes with a retention - probability `p`. - - Parameters - ---------- - n : int - The desired number of nodes in the graph. - p : float - The probability for retaining the edge of the replicated node. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `p` is not a valid probability. - If `n` is less than 2. - - Notes - ----- - This algorithm appears in [1]. - - This implementation disallows the possibility of generating - disconnected graphs. - - References - ---------- - .. [1] I. Ispolatov, P. L. Krapivsky, A. Yuryev, - "Duplication-divergence model of protein interaction network", - Phys. Rev. E, 71, 061911, 2005. - - """ - if p > 1 or p < 0: - msg = f"NetworkXError p={p} is not in [0,1]." - raise nx.NetworkXError(msg) - if n < 2: - msg = "n must be greater than or equal to 2" - raise nx.NetworkXError(msg) - - create_using = check_create_using(create_using, directed=False, multigraph=False) - G = nx.empty_graph(create_using=create_using) - - # Initialize the graph with two connected nodes. - G.add_edge(0, 1) - i = 2 - while i < n: - # Choose a random node from current graph to duplicate. - random_node = seed.choice(list(G)) - # Make the replica. - G.add_node(i) - # flag indicates whether at least one edge is connected on the replica. - flag = False - for nbr in G.neighbors(random_node): - if seed.random() < p: - # Link retention step. - G.add_edge(i, nbr) - flag = True - if not flag: - # Delete replica if no edges retained. - G.remove_node(i) - else: - # Successful duplication. - i += 1 - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/ego.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/ego.py deleted file mode 100644 index 1c70543..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/ego.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Ego graph. -""" - -__all__ = ["ego_graph"] - -import networkx as nx - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def ego_graph(G, n, radius=1, center=True, undirected=False, distance=None): - """Returns induced subgraph of neighbors centered at node n within - a given radius. - - Parameters - ---------- - G : graph - A NetworkX Graph or DiGraph - - n : node - A single node - - radius : number, optional - Include all neighbors of distance<=radius from n. - - center : bool, optional - If False, do not include center node in graph - - undirected : bool, optional - If True use both in- and out-neighbors of directed graphs. - - distance : key, optional - Use specified edge data key as distance. For example, setting - distance='weight' will use the edge weight to measure the - distance from the node n. - - Notes - ----- - For directed graphs D this produces the "out" neighborhood - or successors. If you want the neighborhood of predecessors - first reverse the graph with D.reverse(). If you want both - directions use the keyword argument undirected=True. - - Node, edge, and graph attributes are copied to the returned subgraph. - """ - if undirected: - if distance is not None: - sp, _ = nx.single_source_dijkstra( - G.to_undirected(), n, cutoff=radius, weight=distance - ) - else: - sp = dict( - nx.single_source_shortest_path_length( - G.to_undirected(), n, cutoff=radius - ) - ) - else: - if distance is not None: - sp, _ = nx.single_source_dijkstra(G, n, cutoff=radius, weight=distance) - else: - sp = dict(nx.single_source_shortest_path_length(G, n, cutoff=radius)) - - H = G.subgraph(sp).copy() - if not center: - H.remove_node(n) - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/expanders.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/expanders.py deleted file mode 100644 index befdb0e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/expanders.py +++ /dev/null @@ -1,474 +0,0 @@ -"""Provides explicit constructions of expander graphs.""" - -import itertools - -import networkx as nx - -__all__ = [ - "margulis_gabber_galil_graph", - "chordal_cycle_graph", - "paley_graph", - "maybe_regular_expander", - "is_regular_expander", - "random_regular_expander_graph", -] - - -# Other discrete torus expanders can be constructed by using the following edge -# sets. For more information, see Chapter 4, "Expander Graphs", in -# "Pseudorandomness", by Salil Vadhan. -# -# For a directed expander, add edges from (x, y) to: -# -# (x, y), -# ((x + 1) % n, y), -# (x, (y + 1) % n), -# (x, (x + y) % n), -# (-y % n, x) -# -# For an undirected expander, add the reverse edges. -# -# Also appearing in the paper of Gabber and Galil: -# -# (x, y), -# (x, (x + y) % n), -# (x, (x + y + 1) % n), -# ((x + y) % n, y), -# ((x + y + 1) % n, y) -# -# and: -# -# (x, y), -# ((x + 2*y) % n, y), -# ((x + (2*y + 1)) % n, y), -# ((x + (2*y + 2)) % n, y), -# (x, (y + 2*x) % n), -# (x, (y + (2*x + 1)) % n), -# (x, (y + (2*x + 2)) % n), -# -@nx._dispatchable(graphs=None, returns_graph=True) -def margulis_gabber_galil_graph(n, create_using=None): - r"""Returns the Margulis-Gabber-Galil undirected MultiGraph on `n^2` nodes. - - The undirected MultiGraph is regular with degree `8`. Nodes are integer - pairs. The second-largest eigenvalue of the adjacency matrix of the graph - is at most `5 \sqrt{2}`, regardless of `n`. - - Parameters - ---------- - n : int - Determines the number of nodes in the graph: `n^2`. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : graph - The constructed undirected multigraph. - - Raises - ------ - NetworkXError - If the graph is directed or not a multigraph. - - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed() or not G.is_multigraph(): - msg = "`create_using` must be an undirected multigraph." - raise nx.NetworkXError(msg) - - for x, y in itertools.product(range(n), repeat=2): - for u, v in ( - ((x + 2 * y) % n, y), - ((x + (2 * y + 1)) % n, y), - (x, (y + 2 * x) % n), - (x, (y + (2 * x + 1)) % n), - ): - G.add_edge((x, y), (u, v)) - G.graph["name"] = f"margulis_gabber_galil_graph({n})" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def chordal_cycle_graph(p, create_using=None): - """Returns the chordal cycle graph on `p` nodes. - - The returned graph is a cycle graph on `p` nodes with chords joining each - vertex `x` to its inverse modulo `p`. This graph is a (mildly explicit) - 3-regular expander [1]_. - - `p` *must* be a prime number. - - Parameters - ---------- - p : a prime number - - The number of vertices in the graph. This also indicates where the - chordal edges in the cycle will be created. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : graph - The constructed undirected multigraph. - - Raises - ------ - NetworkXError - - If `create_using` indicates directed or not a multigraph. - - References - ---------- - - .. [1] Theorem 4.4.2 in A. Lubotzky. "Discrete groups, expanding graphs and - invariant measures", volume 125 of Progress in Mathematics. - Birkhäuser Verlag, Basel, 1994. - - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed() or not G.is_multigraph(): - msg = "`create_using` must be an undirected multigraph." - raise nx.NetworkXError(msg) - - for x in range(p): - left = (x - 1) % p - right = (x + 1) % p - # Here we apply Fermat's Little Theorem to compute the multiplicative - # inverse of x in Z/pZ. By Fermat's Little Theorem, - # - # x^p = x (mod p) - # - # Therefore, - # - # x * x^(p - 2) = 1 (mod p) - # - # The number 0 is a special case: we just let its inverse be itself. - chord = pow(x, p - 2, p) if x > 0 else 0 - for y in (left, right, chord): - G.add_edge(x, y) - G.graph["name"] = f"chordal_cycle_graph({p})" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def paley_graph(p, create_using=None): - r"""Returns the Paley $\frac{(p-1)}{2}$ -regular graph on $p$ nodes. - - The returned graph is a graph on $\mathbb{Z}/p\mathbb{Z}$ with edges between $x$ and $y$ - if and only if $x-y$ is a nonzero square in $\mathbb{Z}/p\mathbb{Z}$. - - If $p \equiv 1 \pmod 4$, $-1$ is a square in $\mathbb{Z}/p\mathbb{Z}$ and therefore $x-y$ is a square if and - only if $y-x$ is also a square, i.e the edges in the Paley graph are symmetric. - - If $p \equiv 3 \pmod 4$, $-1$ is not a square in $\mathbb{Z}/p\mathbb{Z}$ and therefore either $x-y$ or $y-x$ - is a square in $\mathbb{Z}/p\mathbb{Z}$ but not both. - - Note that a more general definition of Paley graphs extends this construction - to graphs over $q=p^n$ vertices, by using the finite field $F_q$ instead of $\mathbb{Z}/p\mathbb{Z}$. - This construction requires to compute squares in general finite fields and is - not what is implemented here (i.e `paley_graph(25)` does not return the true - Paley graph associated with $5^2$). - - Parameters - ---------- - p : int, an odd prime number. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : graph - The constructed directed graph. - - Raises - ------ - NetworkXError - If the graph is a multigraph. - - References - ---------- - Chapter 13 in B. Bollobas, Random Graphs. Second edition. - Cambridge Studies in Advanced Mathematics, 73. - Cambridge University Press, Cambridge (2001). - """ - G = nx.empty_graph(0, create_using, default=nx.DiGraph) - if G.is_multigraph(): - msg = "`create_using` cannot be a multigraph." - raise nx.NetworkXError(msg) - - # Compute the squares in Z/pZ. - # Make it a set to uniquify (there are exactly (p-1)/2 squares in Z/pZ - # when is prime). - square_set = {(x**2) % p for x in range(1, p) if (x**2) % p != 0} - - for x in range(p): - for x2 in square_set: - G.add_edge(x, (x + x2) % p) - G.graph["name"] = f"paley({p})" - return G - - -@nx.utils.decorators.np_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def maybe_regular_expander(n, d, *, create_using=None, max_tries=100, seed=None): - r"""Utility for creating a random regular expander. - - Returns a random $d$-regular graph on $n$ nodes which is an expander - graph with very good probability. - - Parameters - ---------- - n : int - The number of nodes. - d : int - The degree of each node. - create_using : Graph Instance or Constructor - Indicator of type of graph to return. - If a Graph-type instance, then clear and use it. - If a constructor, call it to create an empty graph. - Use the Graph constructor by default. - max_tries : int. (default: 100) - The number of allowed loops when generating each independent cycle - seed : (default: None) - Seed used to set random number generation state. See :ref`Randomness`. - - Notes - ----- - The nodes are numbered from $0$ to $n - 1$. - - The graph is generated by taking $d / 2$ random independent cycles. - - Joel Friedman proved that in this model the resulting - graph is an expander with probability - $1 - O(n^{-\tau})$ where $\tau = \lceil (\sqrt{d - 1}) / 2 \rceil - 1$. [1]_ - - Examples - -------- - >>> G = nx.maybe_regular_expander(n=200, d=6, seed=8020) - - Returns - ------- - G : graph - The constructed undirected graph. - - Raises - ------ - NetworkXError - If $d % 2 != 0$ as the degree must be even. - If $n - 1$ is less than $ 2d $ as the graph is complete at most. - If max_tries is reached - - See Also - -------- - is_regular_expander - random_regular_expander_graph - - References - ---------- - .. [1] Joel Friedman, - A Proof of Alon’s Second Eigenvalue Conjecture and Related Problems, 2004 - https://arxiv.org/abs/cs/0405020 - - """ - - import numpy as np - - if n < 1: - raise nx.NetworkXError("n must be a positive integer") - - if not (d >= 2): - raise nx.NetworkXError("d must be greater than or equal to 2") - - if not (d % 2 == 0): - raise nx.NetworkXError("d must be even") - - if not (n - 1 >= d): - raise nx.NetworkXError( - f"Need n-1>= d to have room for {d//2} independent cycles with {n} nodes" - ) - - G = nx.empty_graph(n, create_using) - - if n < 2: - return G - - cycles = [] - edges = set() - - # Create d / 2 cycles - for i in range(d // 2): - iterations = max_tries - # Make sure the cycles are independent to have a regular graph - while len(edges) != (i + 1) * n: - iterations -= 1 - # Faster than random.permutation(n) since there are only - # (n-1)! distinct cycles against n! permutations of size n - cycle = seed.permutation(n - 1).tolist() - cycle.append(n - 1) - - new_edges = { - (u, v) - for u, v in nx.utils.pairwise(cycle, cyclic=True) - if (u, v) not in edges and (v, u) not in edges - } - # If the new cycle has no edges in common with previous cycles - # then add it to the list otherwise try again - if len(new_edges) == n: - cycles.append(cycle) - edges.update(new_edges) - - if iterations == 0: - raise nx.NetworkXError("Too many iterations in maybe_regular_expander") - - G.add_edges_from(edges) - - return G - - -@nx.utils.not_implemented_for("directed") -@nx.utils.not_implemented_for("multigraph") -@nx._dispatchable(preserve_edge_attrs={"G": {"weight": 1}}) -def is_regular_expander(G, *, epsilon=0): - r"""Determines whether the graph G is a regular expander. [1]_ - - An expander graph is a sparse graph with strong connectivity properties. - - More precisely, this helper checks whether the graph is a - regular $(n, d, \lambda)$-expander with $\lambda$ close to - the Alon-Boppana bound and given by - $\lambda = 2 \sqrt{d - 1} + \epsilon$. [2]_ - - In the case where $\epsilon = 0$ then if the graph successfully passes the test - it is a Ramanujan graph. [3]_ - - A Ramanujan graph has spectral gap almost as large as possible, which makes them - excellent expanders. - - Parameters - ---------- - G : NetworkX graph - epsilon : int, float, default=0 - - Returns - ------- - bool - Whether the given graph is a regular $(n, d, \lambda)$-expander - where $\lambda = 2 \sqrt{d - 1} + \epsilon$. - - Examples - -------- - >>> G = nx.random_regular_expander_graph(20, 4) - >>> nx.is_regular_expander(G) - True - - See Also - -------- - maybe_regular_expander - random_regular_expander_graph - - References - ---------- - .. [1] Expander graph, https://en.wikipedia.org/wiki/Expander_graph - .. [2] Alon-Boppana bound, https://en.wikipedia.org/wiki/Alon%E2%80%93Boppana_bound - .. [3] Ramanujan graphs, https://en.wikipedia.org/wiki/Ramanujan_graph - - """ - - import numpy as np - from scipy.sparse.linalg import eigsh - - if epsilon < 0: - raise nx.NetworkXError("epsilon must be non negative") - - if not nx.is_regular(G): - return False - - _, d = nx.utils.arbitrary_element(G.degree) - - A = nx.adjacency_matrix(G, dtype=float) - lams = eigsh(A, which="LM", k=2, return_eigenvectors=False) - - # lambda2 is the second biggest eigenvalue - lambda2 = min(lams) - - # Use bool() to convert numpy scalar to Python Boolean - return bool(abs(lambda2) < 2 ** np.sqrt(d - 1) + epsilon) - - -@nx.utils.decorators.np_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_regular_expander_graph( - n, d, *, epsilon=0, create_using=None, max_tries=100, seed=None -): - r"""Returns a random regular expander graph on $n$ nodes with degree $d$. - - An expander graph is a sparse graph with strong connectivity properties. [1]_ - - More precisely the returned graph is a $(n, d, \lambda)$-expander with - $\lambda = 2 \sqrt{d - 1} + \epsilon$, close to the Alon-Boppana bound. [2]_ - - In the case where $\epsilon = 0$ it returns a Ramanujan graph. - A Ramanujan graph has spectral gap almost as large as possible, - which makes them excellent expanders. [3]_ - - Parameters - ---------- - n : int - The number of nodes. - d : int - The degree of each node. - epsilon : int, float, default=0 - max_tries : int, (default: 100) - The number of allowed loops, also used in the maybe_regular_expander utility - seed : (default: None) - Seed used to set random number generation state. See :ref`Randomness`. - - Raises - ------ - NetworkXError - If max_tries is reached - - Examples - -------- - >>> G = nx.random_regular_expander_graph(20, 4) - >>> nx.is_regular_expander(G) - True - - Notes - ----- - This loops over `maybe_regular_expander` and can be slow when - $n$ is too big or $\epsilon$ too small. - - See Also - -------- - maybe_regular_expander - is_regular_expander - - References - ---------- - .. [1] Expander graph, https://en.wikipedia.org/wiki/Expander_graph - .. [2] Alon-Boppana bound, https://en.wikipedia.org/wiki/Alon%E2%80%93Boppana_bound - .. [3] Ramanujan graphs, https://en.wikipedia.org/wiki/Ramanujan_graph - - """ - G = maybe_regular_expander( - n, d, create_using=create_using, max_tries=max_tries, seed=seed - ) - iterations = max_tries - - while not is_regular_expander(G, epsilon=epsilon): - iterations -= 1 - G = maybe_regular_expander( - n=n, d=d, create_using=create_using, max_tries=max_tries, seed=seed - ) - - if iterations == 0: - raise nx.NetworkXError( - "Too many iterations in random_regular_expander_graph" - ) - - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/geometric.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/geometric.py deleted file mode 100644 index 7f19281..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/geometric.py +++ /dev/null @@ -1,1048 +0,0 @@ -"""Generators for geometric graphs.""" - -import math -from bisect import bisect_left -from itertools import accumulate, combinations, product - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "geometric_edges", - "geographical_threshold_graph", - "navigable_small_world_graph", - "random_geometric_graph", - "soft_random_geometric_graph", - "thresholded_random_geometric_graph", - "waxman_graph", - "geometric_soft_configuration_graph", -] - - -@nx._dispatchable(node_attrs="pos_name") -def geometric_edges(G, radius, p=2, *, pos_name="pos"): - """Returns edge list of node pairs within `radius` of each other. - - Parameters - ---------- - G : networkx graph - The graph from which to generate the edge list. The nodes in `G` should - have an attribute ``pos`` corresponding to the node position, which is - used to compute the distance to other nodes. - radius : scalar - The distance threshold. Edges are included in the edge list if the - distance between the two nodes is less than `radius`. - pos_name : string, default="pos" - The name of the node attribute which represents the position of each - node in 2D coordinates. Every node in the Graph must have this attribute. - p : scalar, default=2 - The `Minkowski distance metric - `_ used to compute - distances. The default value is 2, i.e. Euclidean distance. - - Returns - ------- - edges : list - List of edges whose distances are less than `radius` - - Notes - ----- - Radius uses Minkowski distance metric `p`. - If scipy is available, `scipy.spatial.cKDTree` is used to speed computation. - - Examples - -------- - Create a graph with nodes that have a "pos" attribute representing 2D - coordinates. - - >>> G = nx.Graph() - >>> G.add_nodes_from( - ... [ - ... (0, {"pos": (0, 0)}), - ... (1, {"pos": (3, 0)}), - ... (2, {"pos": (8, 0)}), - ... ] - ... ) - >>> nx.geometric_edges(G, radius=1) - [] - >>> nx.geometric_edges(G, radius=4) - [(0, 1)] - >>> nx.geometric_edges(G, radius=6) - [(0, 1), (1, 2)] - >>> nx.geometric_edges(G, radius=9) - [(0, 1), (0, 2), (1, 2)] - """ - # Input validation - every node must have a "pos" attribute - for n, pos in G.nodes(data=pos_name): - if pos is None: - raise nx.NetworkXError( - f"Node {n} (and all nodes) must have a '{pos_name}' attribute." - ) - - # NOTE: See _geometric_edges for the actual implementation. The reason this - # is split into two functions is to avoid the overhead of input validation - # every time the function is called internally in one of the other - # geometric generators - return _geometric_edges(G, radius, p, pos_name) - - -def _geometric_edges(G, radius, p, pos_name): - """ - Implements `geometric_edges` without input validation. See `geometric_edges` - for complete docstring. - """ - nodes_pos = G.nodes(data=pos_name) - try: - import scipy as sp - except ImportError: - # no scipy KDTree so compute by for-loop - radius_p = radius**p - edges = [ - (u, v) - for (u, pu), (v, pv) in combinations(nodes_pos, 2) - if sum(abs(a - b) ** p for a, b in zip(pu, pv)) <= radius_p - ] - return edges - # scipy KDTree is available - nodes, coords = list(zip(*nodes_pos)) - kdtree = sp.spatial.cKDTree(coords) # Cannot provide generator. - edge_indexes = kdtree.query_pairs(radius, p) - edges = [(nodes[u], nodes[v]) for u, v in sorted(edge_indexes)] - return edges - - -@py_random_state(5) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_geometric_graph( - n, radius, dim=2, pos=None, p=2, seed=None, *, pos_name="pos" -): - """Returns a random geometric graph in the unit cube of dimensions `dim`. - - The random geometric graph model places `n` nodes uniformly at - random in the unit cube. Two nodes are joined by an edge if the - distance between the nodes is at most `radius`. - - Edges are determined using a KDTree when SciPy is available. - This reduces the time complexity from $O(n^2)$ to $O(n)$. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - p : float, optional - Which Minkowski distance metric to use. `p` has to meet the condition - ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - This should not be confused with the `p` of an ErdÅ‘s-Rényi random - graph, which represents probability. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - pos_name : string, default="pos" - The name of the node attribute which represents the position - in 2D coordinates of the node in the returned graph. - - Returns - ------- - Graph - A random geometric graph, undirected and without self-loops. - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. - - Examples - -------- - Create a random geometric graph on twenty nodes where nodes are joined by - an edge if their distance is at most 0.1:: - - >>> G = nx.random_geometric_graph(20, 0.1) - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2:: - - >>> import random - >>> n = 20 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> G = nx.random_geometric_graph(n, 0.2, pos=pos) - - References - ---------- - .. [1] Penrose, Mathew, *Random Geometric Graphs*, - Oxford Studies in Probability, 5, 2003. - - """ - # TODO Is this function just a special case of the geographical - # threshold graph? - # - # half_radius = {v: radius / 2 for v in n} - # return geographical_threshold_graph(nodes, theta=1, alpha=1, - # weight=half_radius) - # - G = nx.empty_graph(n) - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in G} - nx.set_node_attributes(G, pos, pos_name) - - G.add_edges_from(_geometric_edges(G, radius, p, pos_name)) - return G - - -@py_random_state(6) -@nx._dispatchable(graphs=None, returns_graph=True) -def soft_random_geometric_graph( - n, radius, dim=2, pos=None, p=2, p_dist=None, seed=None, *, pos_name="pos" -): - r"""Returns a soft random geometric graph in the unit cube. - - The soft random geometric graph [1] model places `n` nodes uniformly at - random in the unit cube in dimension `dim`. Two nodes of distance, `dist`, - computed by the `p`-Minkowski distance metric are joined by an edge with - probability `p_dist` if the computed distance metric value of the nodes - is at most `radius`, otherwise they are not joined. - - Edges within `radius` of each other are determined using a KDTree when - SciPy is available. This reduces the time complexity from :math:`O(n^2)` - to :math:`O(n)`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - p : float, optional - Which Minkowski distance metric to use. - `p` has to meet the condition ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - - This should not be confused with the `p` of an ErdÅ‘s-Rényi random - graph, which represents probability. - p_dist : function, optional - A probability density function computing the probability of - connecting two nodes that are of distance, dist, computed by the - Minkowski distance metric. The probability density function, `p_dist`, - must be any function that takes the metric value as input - and outputs a single probability value between 0-1. The scipy.stats - package has many probability distribution functions implemented and - tools for custom probability distribution definitions [2], and passing - the .pdf method of scipy.stats distributions can be used here. If the - probability function, `p_dist`, is not supplied, the default function - is an exponential distribution with rate parameter :math:`\lambda=1`. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - pos_name : string, default="pos" - The name of the node attribute which represents the position - in 2D coordinates of the node in the returned graph. - - Returns - ------- - Graph - A soft random geometric graph, undirected and without self-loops. - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. - - Examples - -------- - Default Graph: - - G = nx.soft_random_geometric_graph(50, 0.2) - - Custom Graph: - - Create a soft random geometric graph on 100 uniformly distributed nodes - where nodes are joined by an edge with probability computed from an - exponential distribution with rate parameter :math:`\lambda=1` if their - Euclidean distance is at most 0.2. - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2 - - The scipy.stats package can be used to define the probability distribution - with the .pdf method used as `p_dist`. - - :: - - >>> import random - >>> import math - >>> n = 100 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> p_dist = lambda dist: math.exp(-dist) - >>> G = nx.soft_random_geometric_graph(n, 0.2, pos=pos, p_dist=p_dist) - - References - ---------- - .. [1] Penrose, Mathew D. "Connectivity of soft random geometric graphs." - The Annals of Applied Probability 26.2 (2016): 986-1028. - .. [2] scipy.stats - - https://docs.scipy.org/doc/scipy/reference/tutorial/stats.html - - """ - G = nx.empty_graph(n) - G.name = f"soft_random_geometric_graph({n}, {radius}, {dim})" - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in G} - nx.set_node_attributes(G, pos, pos_name) - - # if p_dist function not supplied the default function is an exponential - # distribution with rate parameter :math:`\lambda=1`. - if p_dist is None: - - def p_dist(dist): - return math.exp(-dist) - - def should_join(edge): - u, v = edge - dist = (sum(abs(a - b) ** p for a, b in zip(pos[u], pos[v]))) ** (1 / p) - return seed.random() < p_dist(dist) - - G.add_edges_from(filter(should_join, _geometric_edges(G, radius, p, pos_name))) - return G - - -@py_random_state(7) -@nx._dispatchable(graphs=None, returns_graph=True) -def geographical_threshold_graph( - n, - theta, - dim=2, - pos=None, - weight=None, - metric=None, - p_dist=None, - seed=None, - *, - pos_name="pos", - weight_name="weight", -): - r"""Returns a geographical threshold graph. - - The geographical threshold graph model places $n$ nodes uniformly at - random in a rectangular domain. Each node $u$ is assigned a weight - $w_u$. Two nodes $u$ and $v$ are joined by an edge if - - .. math:: - - (w_u + w_v)p_{dist}(r) \ge \theta - - where `r` is the distance between `u` and `v`, `p_dist` is any function of - `r`, and :math:`\theta` as the threshold parameter. `p_dist` is used to - give weight to the distance between nodes when deciding whether or not - they should be connected. The larger `p_dist` is, the more prone nodes - separated by `r` are to be connected, and vice versa. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - theta: float - Threshold value - dim : int, optional - Dimension of graph - pos : dict - Node positions as a dictionary of tuples keyed by node. - weight : dict - Node weights as a dictionary of numbers keyed by node. - metric : function - A metric on vectors of numbers (represented as lists or - tuples). This must be a function that accepts two lists (or - tuples) as input and yields a number as output. The function - must also satisfy the four requirements of a `metric`_. - Specifically, if $d$ is the function and $x$, $y$, - and $z$ are vectors in the graph, then $d$ must satisfy - - 1. $d(x, y) \ge 0$, - 2. $d(x, y) = 0$ if and only if $x = y$, - 3. $d(x, y) = d(y, x)$, - 4. $d(x, z) \le d(x, y) + d(y, z)$. - - If this argument is not specified, the Euclidean distance metric is - used. - - .. _metric: https://en.wikipedia.org/wiki/Metric_%28mathematics%29 - p_dist : function, optional - Any function used to give weight to the distance between nodes when - deciding whether or not they should be connected. `p_dist` was - originally conceived as a probability density function giving the - probability of connecting two nodes that are of metric distance `r` - apart. The implementation here allows for more arbitrary definitions - of `p_dist` that do not need to correspond to valid probability - density functions. The :mod:`scipy.stats` package has many - probability density functions implemented and tools for custom - probability density definitions, and passing the ``.pdf`` method of - scipy.stats distributions can be used here. If ``p_dist=None`` - (the default), the exponential function :math:`r^{-2}` is used. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - pos_name : string, default="pos" - The name of the node attribute which represents the position - in 2D coordinates of the node in the returned graph. - weight_name : string, default="weight" - The name of the node attribute which represents the weight - of the node in the returned graph. - - Returns - ------- - Graph - A random geographic threshold graph, undirected and without - self-loops. - - Each node has a node attribute ``pos`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. Similarly, each node has a node - attribute ``weight`` that stores the weight of that node as - provided or as generated. - - Examples - -------- - Specify an alternate distance metric using the ``metric`` keyword - argument. For example, to use the `taxicab metric`_ instead of the - default `Euclidean metric`_:: - - >>> dist = lambda x, y: sum(abs(a - b) for a, b in zip(x, y)) - >>> G = nx.geographical_threshold_graph(10, 0.1, metric=dist) - - .. _taxicab metric: https://en.wikipedia.org/wiki/Taxicab_geometry - .. _Euclidean metric: https://en.wikipedia.org/wiki/Euclidean_distance - - Notes - ----- - If weights are not specified they are assigned to nodes by drawing randomly - from the exponential distribution with rate parameter $\lambda=1$. - To specify weights from a different distribution, use the `weight` keyword - argument:: - - >>> import random - >>> n = 20 - >>> w = {i: random.expovariate(5.0) for i in range(n)} - >>> G = nx.geographical_threshold_graph(20, 50, weight=w) - - If node positions are not specified they are randomly assigned from the - uniform distribution. - - References - ---------- - .. [1] Masuda, N., Miwa, H., Konno, N.: - Geographical threshold graphs with small-world and scale-free - properties. - Physical Review E 71, 036108 (2005) - .. [2] Milan Bradonjić, Aric Hagberg and Allon G. Percus, - Giant component and connectivity in geographical threshold graphs, - in Algorithms and Models for the Web-Graph (WAW 2007), - Antony Bonato and Fan Chung (Eds), pp. 209--216, 2007 - """ - G = nx.empty_graph(n) - # If no weights are provided, choose them from an exponential - # distribution. - if weight is None: - weight = {v: seed.expovariate(1) for v in G} - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in G} - # If no distance metric is provided, use Euclidean distance. - if metric is None: - metric = math.dist - nx.set_node_attributes(G, weight, weight_name) - nx.set_node_attributes(G, pos, pos_name) - - # if p_dist is not supplied, use default r^-2 - if p_dist is None: - - def p_dist(r): - return r**-2 - - # Returns ``True`` if and only if the nodes whose attributes are - # ``du`` and ``dv`` should be joined, according to the threshold - # condition. - def should_join(pair): - u, v = pair - u_pos, v_pos = pos[u], pos[v] - u_weight, v_weight = weight[u], weight[v] - return (u_weight + v_weight) * p_dist(metric(u_pos, v_pos)) >= theta - - G.add_edges_from(filter(should_join, combinations(G, 2))) - return G - - -@py_random_state(6) -@nx._dispatchable(graphs=None, returns_graph=True) -def waxman_graph( - n, - beta=0.4, - alpha=0.1, - L=None, - domain=(0, 0, 1, 1), - metric=None, - seed=None, - *, - pos_name="pos", -): - r"""Returns a Waxman random graph. - - The Waxman random graph model places `n` nodes uniformly at random - in a rectangular domain. Each pair of nodes at distance `d` is - joined by an edge with probability - - .. math:: - p = \beta \exp(-d / \alpha L). - - This function implements both Waxman models, using the `L` keyword - argument. - - * Waxman-1: if `L` is not specified, it is set to be the maximum distance - between any pair of nodes. - * Waxman-2: if `L` is specified, the distance between a pair of nodes is - chosen uniformly at random from the interval `[0, L]`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - beta: float - Model parameter - alpha: float - Model parameter - L : float, optional - Maximum distance between nodes. If not specified, the actual distance - is calculated. - domain : four-tuple of numbers, optional - Domain size, given as a tuple of the form `(x_min, y_min, x_max, - y_max)`. - metric : function - A metric on vectors of numbers (represented as lists or - tuples). This must be a function that accepts two lists (or - tuples) as input and yields a number as output. The function - must also satisfy the four requirements of a `metric`_. - Specifically, if $d$ is the function and $x$, $y$, - and $z$ are vectors in the graph, then $d$ must satisfy - - 1. $d(x, y) \ge 0$, - 2. $d(x, y) = 0$ if and only if $x = y$, - 3. $d(x, y) = d(y, x)$, - 4. $d(x, z) \le d(x, y) + d(y, z)$. - - If this argument is not specified, the Euclidean distance metric is - used. - - .. _metric: https://en.wikipedia.org/wiki/Metric_%28mathematics%29 - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - pos_name : string, default="pos" - The name of the node attribute which represents the position - in 2D coordinates of the node in the returned graph. - - Returns - ------- - Graph - A random Waxman graph, undirected and without self-loops. Each - node has a node attribute ``'pos'`` that stores the position of - that node in Euclidean space as generated by this function. - - Examples - -------- - Specify an alternate distance metric using the ``metric`` keyword - argument. For example, to use the "`taxicab metric`_" instead of the - default `Euclidean metric`_:: - - >>> dist = lambda x, y: sum(abs(a - b) for a, b in zip(x, y)) - >>> G = nx.waxman_graph(10, 0.5, 0.1, metric=dist) - - .. _taxicab metric: https://en.wikipedia.org/wiki/Taxicab_geometry - .. _Euclidean metric: https://en.wikipedia.org/wiki/Euclidean_distance - - Notes - ----- - Starting in NetworkX 2.0 the parameters alpha and beta align with their - usual roles in the probability distribution. In earlier versions their - positions in the expression were reversed. Their position in the calling - sequence reversed as well to minimize backward incompatibility. - - References - ---------- - .. [1] B. M. Waxman, *Routing of multipoint connections*. - IEEE J. Select. Areas Commun. 6(9),(1988) 1617--1622. - """ - G = nx.empty_graph(n) - (xmin, ymin, xmax, ymax) = domain - # Each node gets a uniformly random position in the given rectangle. - pos = {v: (seed.uniform(xmin, xmax), seed.uniform(ymin, ymax)) for v in G} - nx.set_node_attributes(G, pos, pos_name) - # If no distance metric is provided, use Euclidean distance. - if metric is None: - metric = math.dist - # If the maximum distance L is not specified (that is, we are in the - # Waxman-1 model), then find the maximum distance between any pair - # of nodes. - # - # In the Waxman-1 model, join nodes randomly based on distance. In - # the Waxman-2 model, join randomly based on random l. - if L is None: - L = max(metric(x, y) for x, y in combinations(pos.values(), 2)) - - def dist(u, v): - return metric(pos[u], pos[v]) - - else: - - def dist(u, v): - return seed.random() * L - - # `pair` is the pair of nodes to decide whether to join. - def should_join(pair): - return seed.random() < beta * math.exp(-dist(*pair) / (alpha * L)) - - G.add_edges_from(filter(should_join, combinations(G, 2))) - return G - - -@py_random_state(5) -@nx._dispatchable(graphs=None, returns_graph=True) -def navigable_small_world_graph(n, p=1, q=1, r=2, dim=2, seed=None): - r"""Returns a navigable small-world graph. - - A navigable small-world graph is a directed grid with additional long-range - connections that are chosen randomly. - - [...] we begin with a set of nodes [...] that are identified with the set - of lattice points in an $n \times n$ square, - $\{(i, j): i \in \{1, 2, \ldots, n\}, j \in \{1, 2, \ldots, n\}\}$, - and we define the *lattice distance* between two nodes $(i, j)$ and - $(k, l)$ to be the number of "lattice steps" separating them: - $d((i, j), (k, l)) = |k - i| + |l - j|$. - - For a universal constant $p >= 1$, the node $u$ has a directed edge to - every other node within lattice distance $p$---these are its *local - contacts*. For universal constants $q >= 0$ and $r >= 0$ we also - construct directed edges from $u$ to $q$ other nodes (the *long-range - contacts*) using independent random trials; the $i$th directed edge from - $u$ has endpoint $v$ with probability proportional to $[d(u,v)]^{-r}$. - - -- [1]_ - - Parameters - ---------- - n : int - The length of one side of the lattice; the number of nodes in - the graph is therefore $n^2$. - p : int - The diameter of short range connections. Each node is joined with every - other node within this lattice distance. - q : int - The number of long-range connections for each node. - r : float - Exponent for decaying probability of connections. The probability of - connecting to a node at lattice distance $d$ is $1/d^r$. - dim : int - Dimension of grid - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] J. Kleinberg. The small-world phenomenon: An algorithmic - perspective. Proc. 32nd ACM Symposium on Theory of Computing, 2000. - """ - if p < 1: - raise nx.NetworkXException("p must be >= 1") - if q < 0: - raise nx.NetworkXException("q must be >= 0") - if r < 0: - raise nx.NetworkXException("r must be >= 0") - - G = nx.DiGraph() - nodes = list(product(range(n), repeat=dim)) - for p1 in nodes: - probs = [0] - for p2 in nodes: - if p1 == p2: - continue - d = sum((abs(b - a) for a, b in zip(p1, p2))) - if d <= p: - G.add_edge(p1, p2) - probs.append(d**-r) - cdf = list(accumulate(probs)) - for _ in range(q): - target = nodes[bisect_left(cdf, seed.uniform(0, cdf[-1]))] - G.add_edge(p1, target) - return G - - -@py_random_state(7) -@nx._dispatchable(graphs=None, returns_graph=True) -def thresholded_random_geometric_graph( - n, - radius, - theta, - dim=2, - pos=None, - weight=None, - p=2, - seed=None, - *, - pos_name="pos", - weight_name="weight", -): - r"""Returns a thresholded random geometric graph in the unit cube. - - The thresholded random geometric graph [1] model places `n` nodes - uniformly at random in the unit cube of dimensions `dim`. Each node - `u` is assigned a weight :math:`w_u`. Two nodes `u` and `v` are - joined by an edge if they are within the maximum connection distance, - `radius` computed by the `p`-Minkowski distance and the summation of - weights :math:`w_u` + :math:`w_v` is greater than or equal - to the threshold parameter `theta`. - - Edges within `radius` of each other are determined using a KDTree when - SciPy is available. This reduces the time complexity from :math:`O(n^2)` - to :math:`O(n)`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - theta: float - Threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - weight : dict, optional - Node weights as a dictionary of numbers keyed by node. - p : float, optional (default 2) - Which Minkowski distance metric to use. `p` has to meet the condition - ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - - This should not be confused with the `p` of an ErdÅ‘s-Rényi random - graph, which represents probability. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - pos_name : string, default="pos" - The name of the node attribute which represents the position - in 2D coordinates of the node in the returned graph. - weight_name : string, default="weight" - The name of the node attribute which represents the weight - of the node in the returned graph. - - Returns - ------- - Graph - A thresholded random geographic graph, undirected and without - self-loops. - - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. Similarly, each node has a nodethre - attribute ``'weight'`` that stores the weight of that node as - provided or as generated. - - Examples - -------- - Default Graph: - - G = nx.thresholded_random_geometric_graph(50, 0.2, 0.1) - - Custom Graph: - - Create a thresholded random geometric graph on 50 uniformly distributed - nodes where nodes are joined by an edge if their sum weights drawn from - a exponential distribution with rate = 5 are >= theta = 0.1 and their - Euclidean distance is at most 0.2. - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2 - - If weights are not specified they are assigned to nodes by drawing randomly - from the exponential distribution with rate parameter :math:`\lambda=1`. - To specify weights from a different distribution, use the `weight` keyword - argument:: - - :: - - >>> import random - >>> import math - >>> n = 50 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> w = {i: random.expovariate(5.0) for i in range(n)} - >>> G = nx.thresholded_random_geometric_graph(n, 0.2, 0.1, 2, pos, w) - - References - ---------- - .. [1] http://cole-maclean.github.io/blog/files/thesis.pdf - - """ - G = nx.empty_graph(n) - G.name = f"thresholded_random_geometric_graph({n}, {radius}, {theta}, {dim})" - # If no weights are provided, choose them from an exponential - # distribution. - if weight is None: - weight = {v: seed.expovariate(1) for v in G} - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in G} - # If no distance metric is provided, use Euclidean distance. - nx.set_node_attributes(G, weight, weight_name) - nx.set_node_attributes(G, pos, pos_name) - - edges = ( - (u, v) - for u, v in _geometric_edges(G, radius, p, pos_name) - if weight[u] + weight[v] >= theta - ) - G.add_edges_from(edges) - return G - - -@py_random_state(5) -@nx._dispatchable(graphs=None, returns_graph=True) -def geometric_soft_configuration_graph( - *, beta, n=None, gamma=None, mean_degree=None, kappas=None, seed=None -): - r"""Returns a random graph from the geometric soft configuration model. - - The $\mathbb{S}^1$ model [1]_ is the geometric soft configuration model - which is able to explain many fundamental features of real networks such as - small-world property, heteregenous degree distributions, high level of - clustering, and self-similarity. - - In the geometric soft configuration model, a node $i$ is assigned two hidden - variables: a hidden degree $\kappa_i$, quantifying its popularity, influence, - or importance, and an angular position $\theta_i$ in a circle abstracting the - similarity space, where angular distances between nodes are a proxy for their - similarity. Focusing on the angular position, this model is often called - the $\mathbb{S}^1$ model (a one-dimensional sphere). The circle's radius is - adjusted to $R = N/2\pi$, where $N$ is the number of nodes, so that the density - is set to 1 without loss of generality. - - The connection probability between any pair of nodes increases with - the product of their hidden degrees (i.e., their combined popularities), - and decreases with the angular distance between the two nodes. - Specifically, nodes $i$ and $j$ are connected with the probability - - $p_{ij} = \frac{1}{1 + \frac{d_{ij}^\beta}{\left(\mu \kappa_i \kappa_j\right)^{\max(1, \beta)}}}$ - - where $d_{ij} = R\Delta\theta_{ij}$ is the arc length of the circle between - nodes $i$ and $j$ separated by an angular distance $\Delta\theta_{ij}$. - Parameters $\mu$ and $\beta$ (also called inverse temperature) control the - average degree and the clustering coefficient, respectively. - - It can be shown [2]_ that the model undergoes a structural phase transition - at $\beta=1$ so that for $\beta<1$ networks are unclustered in the thermodynamic - limit (when $N\to \infty$) whereas for $\beta>1$ the ensemble generates - networks with finite clustering coefficient. - - The $\mathbb{S}^1$ model can be expressed as a purely geometric model - $\mathbb{H}^2$ in the hyperbolic plane [3]_ by mapping the hidden degree of - each node into a radial coordinate as - - $r_i = \hat{R} - \frac{2 \max(1, \beta)}{\beta \zeta} \ln \left(\frac{\kappa_i}{\kappa_0}\right)$ - - where $\hat{R}$ is the radius of the hyperbolic disk and $\zeta$ is the curvature, - - $\hat{R} = \frac{2}{\zeta} \ln \left(\frac{N}{\pi}\right) - - \frac{2\max(1, \beta)}{\beta \zeta} \ln (\mu \kappa_0^2)$ - - The connection probability then reads - - $p_{ij} = \frac{1}{1 + \exp\left({\frac{\beta\zeta}{2} (x_{ij} - \hat{R})}\right)}$ - - where - - $x_{ij} = r_i + r_j + \frac{2}{\zeta} \ln \frac{\Delta\theta_{ij}}{2}$ - - is a good approximation of the hyperbolic distance between two nodes separated - by an angular distance $\Delta\theta_{ij}$ with radial coordinates $r_i$ and $r_j$. - For $\beta > 1$, the curvature $\zeta = 1$, for $\beta < 1$, $\zeta = \beta^{-1}$. - - - Parameters - ---------- - Either `n`, `gamma`, `mean_degree` are provided or `kappas`. The values of - `n`, `gamma`, `mean_degree` (if provided) are used to construct a random - kappa-dict keyed by node with values sampled from a power-law distribution. - - beta : positive number - Inverse temperature, controlling the clustering coefficient. - n : int (default: None) - Size of the network (number of nodes). - If not provided, `kappas` must be provided and holds the nodes. - gamma : float (default: None) - Exponent of the power-law distribution for hidden degrees `kappas`. - If not provided, `kappas` must be provided directly. - mean_degree : float (default: None) - The mean degree in the network. - If not provided, `kappas` must be provided directly. - kappas : dict (default: None) - A dict keyed by node to its hidden degree value. - If not provided, random values are computed based on a power-law - distribution using `n`, `gamma` and `mean_degree`. - seed : int, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A random geometric soft configuration graph (undirected with no self-loops). - Each node has three node-attributes: - - - ``kappa`` that represents the hidden degree. - - - ``theta`` the position in the similarity space ($\mathbb{S}^1$) which is - also the angular position in the hyperbolic plane. - - - ``radius`` the radial position in the hyperbolic plane - (based on the hidden degree). - - - Examples - -------- - Generate a network with specified parameters: - - >>> G = nx.geometric_soft_configuration_graph( - ... beta=1.5, n=100, gamma=2.7, mean_degree=5 - ... ) - - Create a geometric soft configuration graph with 100 nodes. The $\beta$ parameter - is set to 1.5 and the exponent of the powerlaw distribution of the hidden - degrees is 2.7 with mean value of 5. - - Generate a network with predefined hidden degrees: - - >>> kappas = {i: 10 for i in range(100)} - >>> G = nx.geometric_soft_configuration_graph(beta=2.5, kappas=kappas) - - Create a geometric soft configuration graph with 100 nodes. The $\beta$ parameter - is set to 2.5 and all nodes with hidden degree $\kappa=10$. - - - References - ---------- - .. [1] Serrano, M. Ã., Krioukov, D., & Boguñá, M. (2008). Self-similarity - of complex networks and hidden metric spaces. Physical review letters, 100(7), 078701. - - .. [2] van der Kolk, J., Serrano, M. Ã., & Boguñá, M. (2022). An anomalous - topological phase transition in spatial random graphs. Communications Physics, 5(1), 245. - - .. [3] Krioukov, D., Papadopoulos, F., Kitsak, M., Vahdat, A., & Boguná, M. (2010). - Hyperbolic geometry of complex networks. Physical Review E, 82(3), 036106. - - """ - if beta <= 0: - raise nx.NetworkXError("The parameter beta cannot be smaller or equal to 0.") - - if kappas is not None: - if not all((n is None, gamma is None, mean_degree is None)): - raise nx.NetworkXError( - "When kappas is input, n, gamma and mean_degree must not be." - ) - - n = len(kappas) - mean_degree = sum(kappas) / len(kappas) - else: - if any((n is None, gamma is None, mean_degree is None)): - raise nx.NetworkXError( - "Please provide either kappas, or all 3 of: n, gamma and mean_degree." - ) - - # Generate `n` hidden degrees from a powerlaw distribution - # with given exponent `gamma` and mean value `mean_degree` - gam_ratio = (gamma - 2) / (gamma - 1) - kappa_0 = mean_degree * gam_ratio * (1 - 1 / n) / (1 - 1 / n**gam_ratio) - base = 1 - 1 / n - power = 1 / (1 - gamma) - kappas = {i: kappa_0 * (1 - seed.random() * base) ** power for i in range(n)} - - G = nx.Graph() - R = n / (2 * math.pi) - - # Approximate values for mu in the thermodynamic limit (when n -> infinity) - if beta > 1: - mu = beta * math.sin(math.pi / beta) / (2 * math.pi * mean_degree) - elif beta == 1: - mu = 1 / (2 * mean_degree * math.log(n)) - else: - mu = (1 - beta) / (2**beta * mean_degree * n ** (1 - beta)) - - # Generate random positions on a circle - thetas = {k: seed.uniform(0, 2 * math.pi) for k in kappas} - - for u in kappas: - for v in list(G): - angle = math.pi - math.fabs(math.pi - math.fabs(thetas[u] - thetas[v])) - dij = math.pow(R * angle, beta) - mu_kappas = math.pow(mu * kappas[u] * kappas[v], max(1, beta)) - p_ij = 1 / (1 + dij / mu_kappas) - - # Create an edge with a certain connection probability - if seed.random() < p_ij: - G.add_edge(u, v) - G.add_node(u) - - nx.set_node_attributes(G, thetas, "theta") - nx.set_node_attributes(G, kappas, "kappa") - - # Map hidden degrees into the radial coordinates - zeta = 1 if beta > 1 else 1 / beta - kappa_min = min(kappas.values()) - R_c = 2 * max(1, beta) / (beta * zeta) - R_hat = (2 / zeta) * math.log(n / math.pi) - R_c * math.log(mu * kappa_min) - radii = {node: R_hat - R_c * math.log(kappa) for node, kappa in kappas.items()} - nx.set_node_attributes(G, radii, "radius") - - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/harary_graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/harary_graph.py deleted file mode 100644 index 591587d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/harary_graph.py +++ /dev/null @@ -1,199 +0,0 @@ -"""Generators for Harary graphs - -This module gives two generators for the Harary graph, which was -introduced by the famous mathematician Frank Harary in his 1962 work [H]_. -The first generator gives the Harary graph that maximizes the node -connectivity with given number of nodes and given number of edges. -The second generator gives the Harary graph that minimizes -the number of edges in the graph with given node connectivity and -number of nodes. - -References ----------- -.. [H] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - -""" - -import networkx as nx -from networkx.exception import NetworkXError - -__all__ = ["hnm_harary_graph", "hkn_harary_graph"] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def hnm_harary_graph(n, m, create_using=None): - """Returns the Harary graph with given numbers of nodes and edges. - - The Harary graph $H_{n,m}$ is the graph that maximizes node connectivity - with $n$ nodes and $m$ edges. - - This maximum node connectivity is known to be floor($2m/n$). [1]_ - - Parameters - ---------- - n: integer - The number of nodes the generated graph is to contain - - m: integer - The number of edges the generated graph is to contain - - create_using : NetworkX graph constructor, optional Graph type - to create (default=nx.Graph). If graph instance, then cleared - before populated. - - Returns - ------- - NetworkX graph - The Harary graph $H_{n,m}$. - - See Also - -------- - hkn_harary_graph - - Notes - ----- - This algorithm runs in $O(m)$ time. - It is implemented by following the Reference [2]_. - - References - ---------- - .. [1] F. T. Boesch, A. Satyanarayana, and C. L. Suffel, - "A Survey of Some Network Reliability Analysis and Synthesis Results," - Networks, pp. 99-107, 2009. - - .. [2] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - """ - - if n < 1: - raise NetworkXError("The number of nodes must be >= 1!") - if m < n - 1: - raise NetworkXError("The number of edges must be >= n - 1 !") - if m > n * (n - 1) // 2: - raise NetworkXError("The number of edges must be <= n(n-1)/2") - - # Construct an empty graph with n nodes first - H = nx.empty_graph(n, create_using) - # Get the floor of average node degree - d = 2 * m // n - - # Test the parity of n and d - if (n % 2 == 0) or (d % 2 == 0): - # Start with a regular graph of d degrees - offset = d // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - if d & 1: - # in case d is odd; n must be even in this case - half = n // 2 - for i in range(half): - # add edges diagonally - H.add_edge(i, i + half) - # Get the remainder of 2*m modulo n - r = 2 * m % n - if r > 0: - # add remaining edges at offset+1 - for i in range(r // 2): - H.add_edge(i, i + offset + 1) - else: - # Start with a regular graph of (d - 1) degrees - offset = (d - 1) // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - half = n // 2 - for i in range(m - n * offset): - # add the remaining m - n*offset edges between i and i+half - H.add_edge(i, (i + half) % n) - - return H - - -@nx._dispatchable(graphs=None, returns_graph=True) -def hkn_harary_graph(k, n, create_using=None): - """Returns the Harary graph with given node connectivity and node number. - - The Harary graph $H_{k,n}$ is the graph that minimizes the number of - edges needed with given node connectivity $k$ and node number $n$. - - This smallest number of edges is known to be ceil($kn/2$) [1]_. - - Parameters - ---------- - k: integer - The node connectivity of the generated graph - - n: integer - The number of nodes the generated graph is to contain - - create_using : NetworkX graph constructor, optional Graph type - to create (default=nx.Graph). If graph instance, then cleared - before populated. - - Returns - ------- - NetworkX graph - The Harary graph $H_{k,n}$. - - See Also - -------- - hnm_harary_graph - - Notes - ----- - This algorithm runs in $O(kn)$ time. - It is implemented by following the Reference [2]_. - - References - ---------- - .. [1] Weisstein, Eric W. "Harary Graph." From MathWorld--A Wolfram Web - Resource. http://mathworld.wolfram.com/HararyGraph.html. - - .. [2] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - """ - - if k < 1: - raise NetworkXError("The node connectivity must be >= 1!") - if n < k + 1: - raise NetworkXError("The number of nodes must be >= k+1 !") - - # in case of connectivity 1, simply return the path graph - if k == 1: - H = nx.path_graph(n, create_using) - return H - - # Construct an empty graph with n nodes first - H = nx.empty_graph(n, create_using) - - # Test the parity of k and n - if (k % 2 == 0) or (n % 2 == 0): - # Construct a regular graph with k degrees - offset = k // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - if k & 1: - # odd degree; n must be even in this case - half = n // 2 - for i in range(half): - # add edges diagonally - H.add_edge(i, i + half) - else: - # Construct a regular graph with (k - 1) degrees - offset = (k - 1) // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - half = n // 2 - for i in range(half + 1): - # add half+1 edges between i and i+half - H.add_edge(i, (i + half) % n) - - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/internet_as_graphs.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/internet_as_graphs.py deleted file mode 100644 index 449d543..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/internet_as_graphs.py +++ /dev/null @@ -1,441 +0,0 @@ -"""Generates graphs resembling the Internet Autonomous System network""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ["random_internet_as_graph"] - - -def uniform_int_from_avg(a, m, seed): - """Pick a random integer with uniform probability. - - Returns a random integer uniformly taken from a distribution with - minimum value 'a' and average value 'm', X~U(a,b), E[X]=m, X in N where - b = 2*m - a. - - Notes - ----- - p = (b-floor(b))/2 - X = X1 + X2; X1~U(a,floor(b)), X2~B(p) - E[X] = E[X1] + E[X2] = (floor(b)+a)/2 + (b-floor(b))/2 = (b+a)/2 = m - """ - - from math import floor - - assert m >= a - b = 2 * m - a - p = (b - floor(b)) / 2 - X1 = round(seed.random() * (floor(b) - a) + a) - if seed.random() < p: - X2 = 1 - else: - X2 = 0 - return X1 + X2 - - -def choose_pref_attach(degs, seed): - """Pick a random value, with a probability given by its weight. - - Returns a random choice among degs keys, each of which has a - probability proportional to the corresponding dictionary value. - - Parameters - ---------- - degs: dictionary - It contains the possible values (keys) and the corresponding - probabilities (values) - seed: random state - - Returns - ------- - v: object - A key of degs or None if degs is empty - """ - - if len(degs) == 0: - return None - s = sum(degs.values()) - if s == 0: - return seed.choice(list(degs.keys())) - v = seed.random() * s - - nodes = list(degs.keys()) - i = 0 - acc = degs[nodes[i]] - while v > acc: - i += 1 - acc += degs[nodes[i]] - return nodes[i] - - -class AS_graph_generator: - """Generates random internet AS graphs.""" - - def __init__(self, n, seed): - """Initializes variables. Immediate numbers are taken from [1]. - - Parameters - ---------- - n: integer - Number of graph nodes - seed: random state - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - GG: AS_graph_generator object - - References - ---------- - [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - self.seed = seed - self.n_t = min(n, round(self.seed.random() * 2 + 4)) # num of T nodes - self.n_m = round(0.15 * n) # number of M nodes - self.n_cp = round(0.05 * n) # number of CP nodes - self.n_c = max(0, n - self.n_t - self.n_m - self.n_cp) # number of C nodes - - self.d_m = 2 + (2.5 * n) / 10000 # average multihoming degree for M nodes - self.d_cp = 2 + (1.5 * n) / 10000 # avg multihoming degree for CP nodes - self.d_c = 1 + (5 * n) / 100000 # average multihoming degree for C nodes - - self.p_m_m = 1 + (2 * n) / 10000 # avg num of peer edges between M and M - self.p_cp_m = 0.2 + (2 * n) / 10000 # avg num of peer edges between CP, M - self.p_cp_cp = 0.05 + (2 * n) / 100000 # avg num of peer edges btwn CP, CP - - self.t_m = 0.375 # probability M's provider is T - self.t_cp = 0.375 # probability CP's provider is T - self.t_c = 0.125 # probability C's provider is T - - def t_graph(self): - """Generates the core mesh network of tier one nodes of a AS graph. - - Returns - ------- - G: Networkx Graph - Core network - """ - - self.G = nx.Graph() - for i in range(self.n_t): - self.G.add_node(i, type="T") - for r in self.regions: - self.regions[r].add(i) - for j in self.G.nodes(): - if i != j: - self.add_edge(i, j, "peer") - self.customers[i] = set() - self.providers[i] = set() - return self.G - - def add_edge(self, i, j, kind): - if kind == "transit": - customer = str(i) - else: - customer = "none" - self.G.add_edge(i, j, type=kind, customer=customer) - - def choose_peer_pref_attach(self, node_list): - """Pick a node with a probability weighted by its peer degree. - - Pick a node from node_list with preferential attachment - computed only on their peer degree - """ - - d = {} - for n in node_list: - d[n] = self.G.nodes[n]["peers"] - return choose_pref_attach(d, self.seed) - - def choose_node_pref_attach(self, node_list): - """Pick a node with a probability weighted by its degree. - - Pick a node from node_list with preferential attachment - computed on their degree - """ - - degs = dict(self.G.degree(node_list)) - return choose_pref_attach(degs, self.seed) - - def add_customer(self, i, j): - """Keep the dictionaries 'customers' and 'providers' consistent.""" - - self.customers[j].add(i) - self.providers[i].add(j) - for z in self.providers[j]: - self.customers[z].add(i) - self.providers[i].add(z) - - def add_node(self, i, kind, reg2prob, avg_deg, t_edge_prob): - """Add a node and its customer transit edges to the graph. - - Parameters - ---------- - i: object - Identifier of the new node - kind: string - Type of the new node. Options are: 'M' for middle node, 'CP' for - content provider and 'C' for customer. - reg2prob: float - Probability the new node can be in two different regions. - avg_deg: float - Average number of transit nodes of which node i is customer. - t_edge_prob: float - Probability node i establish a customer transit edge with a tier - one (T) node - - Returns - ------- - i: object - Identifier of the new node - """ - - regs = 1 # regions in which node resides - if self.seed.random() < reg2prob: # node is in two regions - regs = 2 - node_options = set() - - self.G.add_node(i, type=kind, peers=0) - self.customers[i] = set() - self.providers[i] = set() - self.nodes[kind].add(i) - for r in self.seed.sample(list(self.regions), regs): - node_options = node_options.union(self.regions[r]) - self.regions[r].add(i) - - edge_num = uniform_int_from_avg(1, avg_deg, self.seed) - - t_options = node_options.intersection(self.nodes["T"]) - m_options = node_options.intersection(self.nodes["M"]) - if i in m_options: - m_options.remove(i) - d = 0 - while d < edge_num and (len(t_options) > 0 or len(m_options) > 0): - if len(m_options) == 0 or ( - len(t_options) > 0 and self.seed.random() < t_edge_prob - ): # add edge to a T node - j = self.choose_node_pref_attach(t_options) - t_options.remove(j) - else: - j = self.choose_node_pref_attach(m_options) - m_options.remove(j) - self.add_edge(i, j, "transit") - self.add_customer(i, j) - d += 1 - - return i - - def add_m_peering_link(self, m, to_kind): - """Add a peering link between two middle tier (M) nodes. - - Target node j is drawn considering a preferential attachment based on - other M node peering degree. - - Parameters - ---------- - m: object - Node identifier - to_kind: string - type for target node j (must be always M) - - Returns - ------- - success: boolean - """ - - # candidates are of type 'M' and are not customers of m - node_options = self.nodes["M"].difference(self.customers[m]) - # candidates are not providers of m - node_options = node_options.difference(self.providers[m]) - # remove self - if m in node_options: - node_options.remove(m) - - # remove candidates we are already connected to - for j in self.G.neighbors(m): - if j in node_options: - node_options.remove(j) - - if len(node_options) > 0: - j = self.choose_peer_pref_attach(node_options) - self.add_edge(m, j, "peer") - self.G.nodes[m]["peers"] += 1 - self.G.nodes[j]["peers"] += 1 - return True - else: - return False - - def add_cp_peering_link(self, cp, to_kind): - """Add a peering link to a content provider (CP) node. - - Target node j can be CP or M and it is drawn uniformly among the nodes - belonging to the same region as cp. - - Parameters - ---------- - cp: object - Node identifier - to_kind: string - type for target node j (must be M or CP) - - Returns - ------- - success: boolean - """ - - node_options = set() - for r in self.regions: # options include nodes in the same region(s) - if cp in self.regions[r]: - node_options = node_options.union(self.regions[r]) - - # options are restricted to the indicated kind ('M' or 'CP') - node_options = self.nodes[to_kind].intersection(node_options) - - # remove self - if cp in node_options: - node_options.remove(cp) - - # remove nodes that are cp's providers - node_options = node_options.difference(self.providers[cp]) - - # remove nodes we are already connected to - for j in self.G.neighbors(cp): - if j in node_options: - node_options.remove(j) - - if len(node_options) > 0: - j = self.seed.sample(list(node_options), 1)[0] - self.add_edge(cp, j, "peer") - self.G.nodes[cp]["peers"] += 1 - self.G.nodes[j]["peers"] += 1 - return True - else: - return False - - def graph_regions(self, rn): - """Initializes AS network regions. - - Parameters - ---------- - rn: integer - Number of regions - """ - - self.regions = {} - for i in range(rn): - self.regions["REG" + str(i)] = set() - - def add_peering_links(self, from_kind, to_kind): - """Utility function to add peering links among node groups.""" - peer_link_method = None - if from_kind == "M": - peer_link_method = self.add_m_peering_link - m = self.p_m_m - if from_kind == "CP": - peer_link_method = self.add_cp_peering_link - if to_kind == "M": - m = self.p_cp_m - else: - m = self.p_cp_cp - - for i in self.nodes[from_kind]: - num = uniform_int_from_avg(0, m, self.seed) - for _ in range(num): - peer_link_method(i, to_kind) - - def generate(self): - """Generates a random AS network graph as described in [1]. - - Returns - ------- - G: Graph object - - Notes - ----- - The process steps are the following: first we create the core network - of tier one nodes, then we add the middle tier (M), the content - provider (CP) and the customer (C) nodes along with their transit edges - (link i,j means i is customer of j). Finally we add peering links - between M nodes, between M and CP nodes and between CP node couples. - For a detailed description of the algorithm, please refer to [1]. - - References - ---------- - [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - self.graph_regions(5) - self.customers = {} - self.providers = {} - self.nodes = {"T": set(), "M": set(), "CP": set(), "C": set()} - - self.t_graph() - self.nodes["T"] = set(self.G.nodes()) - - i = len(self.nodes["T"]) - for _ in range(self.n_m): - self.nodes["M"].add(self.add_node(i, "M", 0.2, self.d_m, self.t_m)) - i += 1 - for _ in range(self.n_cp): - self.nodes["CP"].add(self.add_node(i, "CP", 0.05, self.d_cp, self.t_cp)) - i += 1 - for _ in range(self.n_c): - self.nodes["C"].add(self.add_node(i, "C", 0, self.d_c, self.t_c)) - i += 1 - - self.add_peering_links("M", "M") - self.add_peering_links("CP", "M") - self.add_peering_links("CP", "CP") - - return self.G - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_internet_as_graph(n, seed=None): - """Generates a random undirected graph resembling the Internet AS network - - Parameters - ---------- - n: integer in [1000, 10000] - Number of graph nodes - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G: Networkx Graph object - A randomly generated undirected graph - - Notes - ----- - This algorithm returns an undirected graph resembling the Internet - Autonomous System (AS) network, it uses the approach by Elmokashfi et al. - [1]_ and it grants the properties described in the related paper [1]_. - - Each node models an autonomous system, with an attribute 'type' specifying - its kind; tier-1 (T), mid-level (M), customer (C) or content-provider (CP). - Each edge models an ADV communication link (hence, bidirectional) with - attributes: - - - type: transit|peer, the kind of commercial agreement between nodes; - - customer: , the identifier of the node acting as customer - ('none' if type is peer). - - References - ---------- - .. [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - GG = AS_graph_generator(n, seed) - G = GG.generate() - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/intersection.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/intersection.py deleted file mode 100644 index e63af5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/intersection.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Generators for random intersection graphs. -""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "uniform_random_intersection_graph", - "k_random_intersection_graph", - "general_random_intersection_graph", -] - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def uniform_random_intersection_graph(n, m, p, seed=None): - """Returns a uniform random intersection graph. - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - p : float - Probability of connecting nodes between bipartite sets - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph - - References - ---------- - .. [1] K.B. Singer-Cohen, Random Intersection Graphs, 1995, - PhD thesis, Johns Hopkins University - .. [2] Fill, J. A., Scheinerman, E. R., and Singer-Cohen, K. B., - Random intersection graphs when m = !(n): - An equivalence theorem relating the evolution of the g(n, m, p) - and g(n, p) models. Random Struct. Algorithms 16, 2 (2000), 156–176. - """ - from networkx.algorithms import bipartite - - G = bipartite.random_graph(n, m, p, seed) - return nx.projected_graph(G, range(n)) - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def k_random_intersection_graph(n, m, k, seed=None): - """Returns a intersection graph with randomly chosen attribute sets for - each node that are of equal size (k). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - k : float - Size of attribute set to assign to each node. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph, uniform_random_intersection_graph - - References - ---------- - .. [1] Godehardt, E., and Jaworski, J. - Two models of random intersection graphs and their applications. - Electronic Notes in Discrete Mathematics 10 (2001), 129--132. - """ - G = nx.empty_graph(n + m) - mset = range(n, n + m) - for v in range(n): - targets = seed.sample(mset, k) - G.add_edges_from(zip([v] * len(targets), targets)) - return nx.projected_graph(G, range(n)) - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def general_random_intersection_graph(n, m, p, seed=None): - """Returns a random intersection graph with independent probabilities - for connections between node and attribute sets. - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - p : list of floats of length m - Probabilities for connecting nodes to each attribute - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph, uniform_random_intersection_graph - - References - ---------- - .. [1] Nikoletseas, S. E., Raptopoulos, C., and Spirakis, P. G. - The existence and efficient construction of large independent sets - in general random intersection graphs. In ICALP (2004), J. D´ıaz, - J. Karhum¨aki, A. Lepist¨o, and D. Sannella, Eds., vol. 3142 - of Lecture Notes in Computer Science, Springer, pp. 1029–1040. - """ - if len(p) != m: - raise ValueError("Probability list p must have m elements.") - G = nx.empty_graph(n + m) - mset = range(n, n + m) - for u in range(n): - for v, q in zip(mset, p): - if seed.random() < q: - G.add_edge(u, v) - return nx.projected_graph(G, range(n)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/interval_graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/interval_graph.py deleted file mode 100644 index 6a3fda4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/interval_graph.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -Generators for interval graph. -""" - -from collections.abc import Sequence - -import networkx as nx - -__all__ = ["interval_graph"] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def interval_graph(intervals): - """Generates an interval graph for a list of intervals given. - - In graph theory, an interval graph is an undirected graph formed from a set - of closed intervals on the real line, with a vertex for each interval - and an edge between vertices whose intervals intersect. - It is the intersection graph of the intervals. - - More information can be found at: - https://en.wikipedia.org/wiki/Interval_graph - - Parameters - ---------- - intervals : a sequence of intervals, say (l, r) where l is the left end, - and r is the right end of the closed interval. - - Returns - ------- - G : networkx graph - - Examples - -------- - >>> intervals = [(-2, 3), [1, 4], (2, 3), (4, 6)] - >>> G = nx.interval_graph(intervals) - >>> sorted(G.edges) - [((-2, 3), (1, 4)), ((-2, 3), (2, 3)), ((1, 4), (2, 3)), ((1, 4), (4, 6))] - - Raises - ------ - :exc:`TypeError` - if `intervals` contains None or an element which is not - collections.abc.Sequence or not a length of 2. - :exc:`ValueError` - if `intervals` contains an interval such that min1 > max1 - where min1,max1 = interval - """ - intervals = list(intervals) - for interval in intervals: - if not (isinstance(interval, Sequence) and len(interval) == 2): - raise TypeError( - "Each interval must have length 2, and be a " - "collections.abc.Sequence such as tuple or list." - ) - if interval[0] > interval[1]: - raise ValueError(f"Interval must have lower value first. Got {interval}") - - graph = nx.Graph() - - tupled_intervals = [tuple(interval) for interval in intervals] - graph.add_nodes_from(tupled_intervals) - - while tupled_intervals: - min1, max1 = interval1 = tupled_intervals.pop() - for interval2 in tupled_intervals: - min2, max2 = interval2 - if max1 >= min2 and max2 >= min1: - graph.add_edge(interval1, interval2) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/joint_degree_seq.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/joint_degree_seq.py deleted file mode 100644 index c426df9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/joint_degree_seq.py +++ /dev/null @@ -1,664 +0,0 @@ -"""Generate graphs with a given joint degree and directed joint degree""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "is_valid_joint_degree", - "is_valid_directed_joint_degree", - "joint_degree_graph", - "directed_joint_degree_graph", -] - - -@nx._dispatchable(graphs=None) -def is_valid_joint_degree(joint_degrees): - """Checks whether the given joint degree dictionary is realizable. - - A *joint degree dictionary* is a dictionary of dictionaries, in - which entry ``joint_degrees[k][l]`` is an integer representing the - number of edges joining nodes of degree *k* with nodes of degree - *l*. Such a dictionary is realizable as a simple graph if and only - if the following conditions are satisfied. - - - each entry must be an integer, - - the total number of nodes of degree *k*, computed by - ``sum(joint_degrees[k].values()) / k``, must be an integer, - - the total number of edges joining nodes of degree *k* with - nodes of degree *l* cannot exceed the total number of possible edges, - - each diagonal entry ``joint_degrees[k][k]`` must be even (this is - a convention assumed by the :func:`joint_degree_graph` function). - - - Parameters - ---------- - joint_degrees : dictionary of dictionary of integers - A joint degree dictionary in which entry ``joint_degrees[k][l]`` - is the number of edges joining nodes of degree *k* with nodes of - degree *l*. - - Returns - ------- - bool - Whether the given joint degree dictionary is realizable as a - simple graph. - - References - ---------- - .. [1] M. Gjoka, M. Kurant, A. Markopoulou, "2.5K Graphs: from Sampling - to Generation", IEEE Infocom, 2013. - .. [2] I. Stanton, A. Pinar, "Constructing and sampling graphs with a - prescribed joint degree distribution", Journal of Experimental - Algorithmics, 2012. - """ - - degree_count = {} - for k in joint_degrees: - if k > 0: - k_size = sum(joint_degrees[k].values()) / k - if not k_size.is_integer(): - return False - degree_count[k] = k_size - - for k in joint_degrees: - for l in joint_degrees[k]: - if not float(joint_degrees[k][l]).is_integer(): - return False - - if (k != l) and (joint_degrees[k][l] > degree_count[k] * degree_count[l]): - return False - elif k == l: - if joint_degrees[k][k] > degree_count[k] * (degree_count[k] - 1): - return False - if joint_degrees[k][k] % 2 != 0: - return False - - # if all above conditions have been satisfied then the input - # joint degree is realizable as a simple graph. - return True - - -def _neighbor_switch(G, w, unsat, h_node_residual, avoid_node_id=None): - """Releases one free stub for ``w``, while preserving joint degree in G. - - Parameters - ---------- - G : NetworkX graph - Graph in which the neighbor switch will take place. - w : integer - Node id for which we will execute this neighbor switch. - unsat : set of integers - Set of unsaturated node ids that have the same degree as w. - h_node_residual: dictionary of integers - Keeps track of the remaining stubs for a given node. - avoid_node_id: integer - Node id to avoid when selecting w_prime. - - Notes - ----- - First, it selects *w_prime*, an unsaturated node that has the same degree - as ``w``. Second, it selects *switch_node*, a neighbor node of ``w`` that - is not connected to *w_prime*. Then it executes an edge swap i.e. removes - (``w``,*switch_node*) and adds (*w_prime*,*switch_node*). Gjoka et. al. [1] - prove that such an edge swap is always possible. - - References - ---------- - .. [1] M. Gjoka, B. Tillman, A. Markopoulou, "Construction of Simple - Graphs with a Target Joint Degree Matrix and Beyond", IEEE Infocom, '15 - """ - - if (avoid_node_id is None) or (h_node_residual[avoid_node_id] > 1): - # select unsaturated node w_prime that has the same degree as w - w_prime = next(iter(unsat)) - else: - # assume that the node pair (v,w) has been selected for connection. if - # - neighbor_switch is called for node w, - # - nodes v and w have the same degree, - # - node v=avoid_node_id has only one stub left, - # then prevent v=avoid_node_id from being selected as w_prime. - - iter_var = iter(unsat) - while True: - w_prime = next(iter_var) - if w_prime != avoid_node_id: - break - - # select switch_node, a neighbor of w, that is not connected to w_prime - w_prime_neighbs = G[w_prime] # slightly faster declaring this variable - for v in G[w]: - if (v not in w_prime_neighbs) and (v != w_prime): - switch_node = v - break - - # remove edge (w,switch_node), add edge (w_prime,switch_node) and update - # data structures - G.remove_edge(w, switch_node) - G.add_edge(w_prime, switch_node) - h_node_residual[w] += 1 - h_node_residual[w_prime] -= 1 - if h_node_residual[w_prime] == 0: - unsat.remove(w_prime) - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def joint_degree_graph(joint_degrees, seed=None): - """Generates a random simple graph with the given joint degree dictionary. - - Parameters - ---------- - joint_degrees : dictionary of dictionary of integers - A joint degree dictionary in which entry ``joint_degrees[k][l]`` is the - number of edges joining nodes of degree *k* with nodes of degree *l*. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - A graph with the specified joint degree dictionary. - - Raises - ------ - NetworkXError - If *joint_degrees* dictionary is not realizable. - - Notes - ----- - In each iteration of the "while loop" the algorithm picks two disconnected - nodes *v* and *w*, of degree *k* and *l* correspondingly, for which - ``joint_degrees[k][l]`` has not reached its target yet. It then adds - edge (*v*, *w*) and increases the number of edges in graph G by one. - - The intelligence of the algorithm lies in the fact that it is always - possible to add an edge between such disconnected nodes *v* and *w*, - even if one or both nodes do not have free stubs. That is made possible by - executing a "neighbor switch", an edge rewiring move that releases - a free stub while keeping the joint degree of G the same. - - The algorithm continues for E (number of edges) iterations of - the "while loop", at the which point all entries of the given - ``joint_degrees[k][l]`` have reached their target values and the - construction is complete. - - References - ---------- - .. [1] M. Gjoka, B. Tillman, A. Markopoulou, "Construction of Simple - Graphs with a Target Joint Degree Matrix and Beyond", IEEE Infocom, '15 - - Examples - -------- - >>> joint_degrees = { - ... 1: {4: 1}, - ... 2: {2: 2, 3: 2, 4: 2}, - ... 3: {2: 2, 4: 1}, - ... 4: {1: 1, 2: 2, 3: 1}, - ... } - >>> G = nx.joint_degree_graph(joint_degrees) - >>> - """ - - if not is_valid_joint_degree(joint_degrees): - msg = "Input joint degree dict not realizable as a simple graph" - raise nx.NetworkXError(msg) - - # compute degree count from joint_degrees - degree_count = {k: sum(l.values()) // k for k, l in joint_degrees.items() if k > 0} - - # start with empty N-node graph - N = sum(degree_count.values()) - G = nx.empty_graph(N) - - # for a given degree group, keep the list of all node ids - h_degree_nodelist = {} - - # for a given node, keep track of the remaining stubs - h_node_residual = {} - - # populate h_degree_nodelist and h_node_residual - nodeid = 0 - for degree, num_nodes in degree_count.items(): - h_degree_nodelist[degree] = range(nodeid, nodeid + num_nodes) - for v in h_degree_nodelist[degree]: - h_node_residual[v] = degree - nodeid += int(num_nodes) - - # iterate over every degree pair (k,l) and add the number of edges given - # for each pair - for k in joint_degrees: - for l in joint_degrees[k]: - # n_edges_add is the number of edges to add for the - # degree pair (k,l) - n_edges_add = joint_degrees[k][l] - - if (n_edges_add > 0) and (k >= l): - # number of nodes with degree k and l - k_size = degree_count[k] - l_size = degree_count[l] - - # k_nodes and l_nodes consist of all nodes of degree k and l - k_nodes = h_degree_nodelist[k] - l_nodes = h_degree_nodelist[l] - - # k_unsat and l_unsat consist of nodes of degree k and l that - # are unsaturated (nodes that have at least 1 available stub) - k_unsat = {v for v in k_nodes if h_node_residual[v] > 0} - - if k != l: - l_unsat = {w for w in l_nodes if h_node_residual[w] > 0} - else: - l_unsat = k_unsat - n_edges_add = joint_degrees[k][l] // 2 - - while n_edges_add > 0: - # randomly pick nodes v and w that have degrees k and l - v = k_nodes[seed.randrange(k_size)] - w = l_nodes[seed.randrange(l_size)] - - # if nodes v and w are disconnected then attempt to connect - if not G.has_edge(v, w) and (v != w): - # if node v has no free stubs then do neighbor switch - if h_node_residual[v] == 0: - _neighbor_switch(G, v, k_unsat, h_node_residual) - - # if node w has no free stubs then do neighbor switch - if h_node_residual[w] == 0: - if k != l: - _neighbor_switch(G, w, l_unsat, h_node_residual) - else: - _neighbor_switch( - G, w, l_unsat, h_node_residual, avoid_node_id=v - ) - - # add edge (v, w) and update data structures - G.add_edge(v, w) - h_node_residual[v] -= 1 - h_node_residual[w] -= 1 - n_edges_add -= 1 - - if h_node_residual[v] == 0: - k_unsat.discard(v) - if h_node_residual[w] == 0: - l_unsat.discard(w) - return G - - -@nx._dispatchable(graphs=None) -def is_valid_directed_joint_degree(in_degrees, out_degrees, nkk): - """Checks whether the given directed joint degree input is realizable - - Parameters - ---------- - in_degrees : list of integers - in degree sequence contains the in degrees of nodes. - out_degrees : list of integers - out degree sequence contains the out degrees of nodes. - nkk : dictionary of dictionary of integers - directed joint degree dictionary. for nodes of out degree k (first - level of dict) and nodes of in degree l (second level of dict) - describes the number of edges. - - Returns - ------- - boolean - returns true if given input is realizable, else returns false. - - Notes - ----- - Here is the list of conditions that the inputs (in/out degree sequences, - nkk) need to satisfy for simple directed graph realizability: - - - Condition 0: in_degrees and out_degrees have the same length - - Condition 1: nkk[k][l] is integer for all k,l - - Condition 2: sum(nkk[k])/k = number of nodes with partition id k, is an - integer and matching degree sequence - - Condition 3: number of edges and non-chords between k and l cannot exceed - maximum possible number of edges - - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - """ - V = {} # number of nodes with in/out degree. - forbidden = {} - if len(in_degrees) != len(out_degrees): - return False - - for idx in range(len(in_degrees)): - i = in_degrees[idx] - o = out_degrees[idx] - V[(i, 0)] = V.get((i, 0), 0) + 1 - V[(o, 1)] = V.get((o, 1), 0) + 1 - - forbidden[(o, i)] = forbidden.get((o, i), 0) + 1 - - S = {} # number of edges going from in/out degree nodes. - for k in nkk: - for l in nkk[k]: - val = nkk[k][l] - if not float(val).is_integer(): # condition 1 - return False - - if val > 0: - S[(k, 1)] = S.get((k, 1), 0) + val - S[(l, 0)] = S.get((l, 0), 0) + val - # condition 3 - if val + forbidden.get((k, l), 0) > V[(k, 1)] * V[(l, 0)]: - return False - - return all(S[s] / s[0] == V[s] for s in S) - - -def _directed_neighbor_switch( - G, w, unsat, h_node_residual_out, chords, h_partition_in, partition -): - """Releases one free stub for node w, while preserving joint degree in G. - - Parameters - ---------- - G : networkx directed graph - graph within which the edge swap will take place. - w : integer - node id for which we need to perform a neighbor switch. - unsat: set of integers - set of node ids that have the same degree as w and are unsaturated. - h_node_residual_out: dict of integers - for a given node, keeps track of the remaining stubs to be added. - chords: set of tuples - keeps track of available positions to add edges. - h_partition_in: dict of integers - for a given node, keeps track of its partition id (in degree). - partition: integer - partition id to check if chords have to be updated. - - Notes - ----- - First, it selects node w_prime that (1) has the same degree as w and - (2) is unsaturated. Then, it selects node v, a neighbor of w, that is - not connected to w_prime and does an edge swap i.e. removes (w,v) and - adds (w_prime,v). If neighbor switch is not possible for w using - w_prime and v, then return w_prime; in [1] it's proven that - such unsaturated nodes can be used. - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - """ - w_prime = unsat.pop() - unsat.add(w_prime) - # select node t, a neighbor of w, that is not connected to w_prime - w_neighbs = list(G.successors(w)) - # slightly faster declaring this variable - w_prime_neighbs = list(G.successors(w_prime)) - - for v in w_neighbs: - if (v not in w_prime_neighbs) and w_prime != v: - # removes (w,v), add (w_prime,v) and update data structures - G.remove_edge(w, v) - G.add_edge(w_prime, v) - - if h_partition_in[v] == partition: - chords.add((w, v)) - chords.discard((w_prime, v)) - - h_node_residual_out[w] += 1 - h_node_residual_out[w_prime] -= 1 - if h_node_residual_out[w_prime] == 0: - unsat.remove(w_prime) - return None - - # If neighbor switch didn't work, use unsaturated node - return w_prime - - -def _directed_neighbor_switch_rev( - G, w, unsat, h_node_residual_in, chords, h_partition_out, partition -): - """The reverse of directed_neighbor_switch. - - Parameters - ---------- - G : networkx directed graph - graph within which the edge swap will take place. - w : integer - node id for which we need to perform a neighbor switch. - unsat: set of integers - set of node ids that have the same degree as w and are unsaturated. - h_node_residual_in: dict of integers - for a given node, keeps track of the remaining stubs to be added. - chords: set of tuples - keeps track of available positions to add edges. - h_partition_out: dict of integers - for a given node, keeps track of its partition id (out degree). - partition: integer - partition id to check if chords have to be updated. - - Notes - ----- - Same operation as directed_neighbor_switch except it handles this operation - for incoming edges instead of outgoing. - """ - w_prime = unsat.pop() - unsat.add(w_prime) - # slightly faster declaring these as variables. - w_neighbs = list(G.predecessors(w)) - w_prime_neighbs = list(G.predecessors(w_prime)) - # select node v, a neighbor of w, that is not connected to w_prime. - for v in w_neighbs: - if (v not in w_prime_neighbs) and w_prime != v: - # removes (v,w), add (v,w_prime) and update data structures. - G.remove_edge(v, w) - G.add_edge(v, w_prime) - if h_partition_out[v] == partition: - chords.add((v, w)) - chords.discard((v, w_prime)) - - h_node_residual_in[w] += 1 - h_node_residual_in[w_prime] -= 1 - if h_node_residual_in[w_prime] == 0: - unsat.remove(w_prime) - return None - - # If neighbor switch didn't work, use the unsaturated node. - return w_prime - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def directed_joint_degree_graph(in_degrees, out_degrees, nkk, seed=None): - """Generates a random simple directed graph with the joint degree. - - Parameters - ---------- - degree_seq : list of tuples (of size 3) - degree sequence contains tuples of nodes with node id, in degree and - out degree. - nkk : dictionary of dictionary of integers - directed joint degree dictionary, for nodes of out degree k (first - level of dict) and nodes of in degree l (second level of dict) - describes the number of edges. - seed : hashable object, optional - Seed for random number generator. - - Returns - ------- - G : Graph - A directed graph with the specified inputs. - - Raises - ------ - NetworkXError - If degree_seq and nkk are not realizable as a simple directed graph. - - - Notes - ----- - Similarly to the undirected version: - In each iteration of the "while loop" the algorithm picks two disconnected - nodes v and w, of degree k and l correspondingly, for which nkk[k][l] has - not reached its target yet i.e. (for given k,l): n_edges_add < nkk[k][l]. - It then adds edge (v,w) and always increases the number of edges in graph G - by one. - - The intelligence of the algorithm lies in the fact that it is always - possible to add an edge between disconnected nodes v and w, for which - nkk[degree(v)][degree(w)] has not reached its target, even if one or both - nodes do not have free stubs. If either node v or w does not have a free - stub, we perform a "neighbor switch", an edge rewiring move that releases a - free stub while keeping nkk the same. - - The difference for the directed version lies in the fact that neighbor - switches might not be able to rewire, but in these cases unsaturated nodes - can be reassigned to use instead, see [1] for detailed description and - proofs. - - The algorithm continues for E (number of edges in the graph) iterations of - the "while loop", at which point all entries of the given nkk[k][l] have - reached their target values and the construction is complete. - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - - Examples - -------- - >>> in_degrees = [0, 1, 1, 2] - >>> out_degrees = [1, 1, 1, 1] - >>> nkk = {1: {1: 2, 2: 2}} - >>> G = nx.directed_joint_degree_graph(in_degrees, out_degrees, nkk) - >>> - """ - if not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk): - msg = "Input is not realizable as a simple graph" - raise nx.NetworkXError(msg) - - # start with an empty directed graph. - G = nx.DiGraph() - - # for a given group, keep the list of all node ids. - h_degree_nodelist_in = {} - h_degree_nodelist_out = {} - # for a given group, keep the list of all unsaturated node ids. - h_degree_nodelist_in_unsat = {} - h_degree_nodelist_out_unsat = {} - # for a given node, keep track of the remaining stubs to be added. - h_node_residual_out = {} - h_node_residual_in = {} - # for a given node, keep track of the partition id. - h_partition_out = {} - h_partition_in = {} - # keep track of non-chords between pairs of partition ids. - non_chords = {} - - # populate data structures - for idx, i in enumerate(in_degrees): - idx = int(idx) - if i > 0: - h_degree_nodelist_in.setdefault(i, []) - h_degree_nodelist_in_unsat.setdefault(i, set()) - h_degree_nodelist_in[i].append(idx) - h_degree_nodelist_in_unsat[i].add(idx) - h_node_residual_in[idx] = i - h_partition_in[idx] = i - - for idx, o in enumerate(out_degrees): - o = out_degrees[idx] - non_chords[(o, in_degrees[idx])] = non_chords.get((o, in_degrees[idx]), 0) + 1 - idx = int(idx) - if o > 0: - h_degree_nodelist_out.setdefault(o, []) - h_degree_nodelist_out_unsat.setdefault(o, set()) - h_degree_nodelist_out[o].append(idx) - h_degree_nodelist_out_unsat[o].add(idx) - h_node_residual_out[idx] = o - h_partition_out[idx] = o - - G.add_node(idx) - - nk_in = {} - nk_out = {} - for p in h_degree_nodelist_in: - nk_in[p] = len(h_degree_nodelist_in[p]) - for p in h_degree_nodelist_out: - nk_out[p] = len(h_degree_nodelist_out[p]) - - # iterate over every degree pair (k,l) and add the number of edges given - # for each pair. - for k in nkk: - for l in nkk[k]: - n_edges_add = nkk[k][l] - - if n_edges_add > 0: - # chords contains a random set of potential edges. - chords = set() - - k_len = nk_out[k] - l_len = nk_in[l] - chords_sample = seed.sample( - range(k_len * l_len), n_edges_add + non_chords.get((k, l), 0) - ) - - num = 0 - while len(chords) < n_edges_add: - i = h_degree_nodelist_out[k][chords_sample[num] % k_len] - j = h_degree_nodelist_in[l][chords_sample[num] // k_len] - num += 1 - if i != j: - chords.add((i, j)) - - # k_unsat and l_unsat consist of nodes of in/out degree k and l - # that are unsaturated i.e. those nodes that have at least one - # available stub - k_unsat = h_degree_nodelist_out_unsat[k] - l_unsat = h_degree_nodelist_in_unsat[l] - - while n_edges_add > 0: - v, w = chords.pop() - chords.add((v, w)) - - # if node v has no free stubs then do neighbor switch. - if h_node_residual_out[v] == 0: - _v = _directed_neighbor_switch( - G, - v, - k_unsat, - h_node_residual_out, - chords, - h_partition_in, - l, - ) - if _v is not None: - v = _v - - # if node w has no free stubs then do neighbor switch. - if h_node_residual_in[w] == 0: - _w = _directed_neighbor_switch_rev( - G, - w, - l_unsat, - h_node_residual_in, - chords, - h_partition_out, - k, - ) - if _w is not None: - w = _w - - # add edge (v,w) and update data structures. - G.add_edge(v, w) - h_node_residual_out[v] -= 1 - h_node_residual_in[w] -= 1 - n_edges_add -= 1 - chords.discard((v, w)) - - if h_node_residual_out[v] == 0: - k_unsat.discard(v) - if h_node_residual_in[w] == 0: - l_unsat.discard(w) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/lattice.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/lattice.py deleted file mode 100644 index 95e520d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/lattice.py +++ /dev/null @@ -1,367 +0,0 @@ -"""Functions for generating grid graphs and lattices - -The :func:`grid_2d_graph`, :func:`triangular_lattice_graph`, and -:func:`hexagonal_lattice_graph` functions correspond to the three -`regular tilings of the plane`_, the square, triangular, and hexagonal -tilings, respectively. :func:`grid_graph` and :func:`hypercube_graph` -are similar for arbitrary dimensions. Useful relevant discussion can -be found about `Triangular Tiling`_, and `Square, Hex and Triangle Grids`_ - -.. _regular tilings of the plane: https://en.wikipedia.org/wiki/List_of_regular_polytopes_and_compounds#Euclidean_tilings -.. _Square, Hex and Triangle Grids: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ -.. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling - -""" - -from itertools import repeat -from math import sqrt - -import networkx as nx -from networkx.classes import set_node_attributes -from networkx.exception import NetworkXError -from networkx.generators.classic import cycle_graph, empty_graph, path_graph -from networkx.relabel import relabel_nodes -from networkx.utils import flatten, nodes_or_number, pairwise - -__all__ = [ - "grid_2d_graph", - "grid_graph", - "hypercube_graph", - "triangular_lattice_graph", - "hexagonal_lattice_graph", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -@nodes_or_number([0, 1]) -def grid_2d_graph(m, n, periodic=False, create_using=None): - """Returns the two-dimensional grid graph. - - The grid graph has each node connected to its four nearest neighbors. - - Parameters - ---------- - m, n : int or iterable container of nodes - If an integer, nodes are from `range(n)`. - If a container, elements become the coordinate of the nodes. - - periodic : bool or iterable - If `periodic` is True, both dimensions are periodic. If False, none - are periodic. If `periodic` is iterable, it should yield 2 bool - values indicating whether the 1st and 2nd axes, respectively, are - periodic. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The (possibly periodic) grid graph of the specified dimensions. - - """ - G = empty_graph(0, create_using) - row_name, rows = m - col_name, cols = n - G.add_nodes_from((i, j) for i in rows for j in cols) - G.add_edges_from(((i, j), (pi, j)) for pi, i in pairwise(rows) for j in cols) - G.add_edges_from(((i, j), (i, pj)) for i in rows for pj, j in pairwise(cols)) - - try: - periodic_r, periodic_c = periodic - except TypeError: - periodic_r = periodic_c = periodic - - if periodic_r and len(rows) > 2: - first = rows[0] - last = rows[-1] - G.add_edges_from(((first, j), (last, j)) for j in cols) - if periodic_c and len(cols) > 2: - first = cols[0] - last = cols[-1] - G.add_edges_from(((i, first), (i, last)) for i in rows) - # both directions for directed - if G.is_directed(): - G.add_edges_from((v, u) for u, v in G.edges()) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def grid_graph(dim, periodic=False): - """Returns the *n*-dimensional grid graph. - - The dimension *n* is the length of the list `dim` and the size in - each dimension is the value of the corresponding list element. - - Parameters - ---------- - dim : list or tuple of numbers or iterables of nodes - 'dim' is a tuple or list with, for each dimension, either a number - that is the size of that dimension or an iterable of nodes for - that dimension. The dimension of the grid_graph is the length - of `dim`. - - periodic : bool or iterable - If `periodic` is True, all dimensions are periodic. If False all - dimensions are not periodic. If `periodic` is iterable, it should - yield `dim` bool values each of which indicates whether the - corresponding axis is periodic. - - Returns - ------- - NetworkX graph - The (possibly periodic) grid graph of the specified dimensions. - - Examples - -------- - To produce a 2 by 3 by 4 grid graph, a graph on 24 nodes: - - >>> from networkx import grid_graph - >>> G = grid_graph(dim=(2, 3, 4)) - >>> len(G) - 24 - >>> G = grid_graph(dim=(range(7, 9), range(3, 6))) - >>> len(G) - 6 - """ - from networkx.algorithms.operators.product import cartesian_product - - if not dim: - return empty_graph(0) - - try: - func = (cycle_graph if p else path_graph for p in periodic) - except TypeError: - func = repeat(cycle_graph if periodic else path_graph) - - G = next(func)(dim[0]) - for current_dim in dim[1:]: - Gnew = next(func)(current_dim) - G = cartesian_product(Gnew, G) - # graph G is done but has labels of the form (1, (2, (3, 1))) so relabel - H = relabel_nodes(G, flatten) - return H - - -@nx._dispatchable(graphs=None, returns_graph=True) -def hypercube_graph(n): - """Returns the *n*-dimensional hypercube graph. - - The nodes are the integers between 0 and ``2 ** n - 1``, inclusive. - - For more information on the hypercube graph, see the Wikipedia - article `Hypercube graph`_. - - .. _Hypercube graph: https://en.wikipedia.org/wiki/Hypercube_graph - - Parameters - ---------- - n : int - The dimension of the hypercube. - The number of nodes in the graph will be ``2 ** n``. - - Returns - ------- - NetworkX graph - The hypercube graph of dimension *n*. - """ - dim = n * [2] - G = grid_graph(dim) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def triangular_lattice_graph( - m, n, periodic=False, with_positions=True, create_using=None -): - r"""Returns the $m$ by $n$ triangular lattice graph. - - The `triangular lattice graph`_ is a two-dimensional `grid graph`_ in - which each square unit has a diagonal edge (each grid unit has a chord). - - The returned graph has $m$ rows and $n$ columns of triangles. Rows and - columns include both triangles pointing up and down. Rows form a strip - of constant height. Columns form a series of diamond shapes, staggered - with the columns on either side. Another way to state the size is that - the nodes form a grid of `m+1` rows and `(n + 1) // 2` columns. - The odd row nodes are shifted horizontally relative to the even rows. - - Directed graph types have edges pointed up or right. - - Positions of nodes are computed by default or `with_positions is True`. - The position of each node (embedded in a euclidean plane) is stored in - the graph using equilateral triangles with sidelength 1. - The height between rows of nodes is thus $\sqrt(3)/2$. - Nodes lie in the first quadrant with the node $(0, 0)$ at the origin. - - .. _triangular lattice graph: http://mathworld.wolfram.com/TriangularGrid.html - .. _grid graph: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ - .. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling - - Parameters - ---------- - m : int - The number of rows in the lattice. - - n : int - The number of columns in the lattice. - - periodic : bool (default: False) - If True, join the boundary vertices of the grid using periodic - boundary conditions. The join between boundaries is the final row - and column of triangles. This means there is one row and one column - fewer nodes for the periodic lattice. Periodic lattices require - `m >= 3`, `n >= 5` and are allowed but misaligned if `m` or `n` are odd - - with_positions : bool (default: True) - Store the coordinates of each node in the graph node attribute 'pos'. - The coordinates provide a lattice with equilateral triangles. - Periodic positions shift the nodes vertically in a nonlinear way so - the edges don't overlap so much. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The *m* by *n* triangular lattice graph. - """ - H = empty_graph(0, create_using) - if n == 0 or m == 0: - return H - if periodic: - if n < 5 or m < 3: - msg = f"m > 2 and n > 4 required for periodic. m={m}, n={n}" - raise NetworkXError(msg) - - N = (n + 1) // 2 # number of nodes in row - rows = range(m + 1) - cols = range(N + 1) - # Make grid - H.add_edges_from(((i, j), (i + 1, j)) for j in rows for i in cols[:N]) - H.add_edges_from(((i, j), (i, j + 1)) for j in rows[:m] for i in cols) - # add diagonals - H.add_edges_from(((i, j), (i + 1, j + 1)) for j in rows[1:m:2] for i in cols[:N]) - H.add_edges_from(((i + 1, j), (i, j + 1)) for j in rows[:m:2] for i in cols[:N]) - # identify boundary nodes if periodic - from networkx.algorithms.minors import contracted_nodes - - if periodic is True: - for i in cols: - H = contracted_nodes(H, (i, 0), (i, m)) - for j in rows[:m]: - H = contracted_nodes(H, (0, j), (N, j)) - elif n % 2: - # remove extra nodes - H.remove_nodes_from((N, j) for j in rows[1::2]) - - # Add position node attributes - if with_positions: - ii = (i for i in cols for j in rows) - jj = (j for i in cols for j in rows) - xx = (0.5 * (j % 2) + i for i in cols for j in rows) - h = sqrt(3) / 2 - if periodic: - yy = (h * j + 0.01 * i * i for i in cols for j in rows) - else: - yy = (h * j for i in cols for j in rows) - pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy) if (i, j) in H} - set_node_attributes(H, pos, "pos") - return H - - -@nx._dispatchable(graphs=None, returns_graph=True) -def hexagonal_lattice_graph( - m, n, periodic=False, with_positions=True, create_using=None -): - """Returns an `m` by `n` hexagonal lattice graph. - - The *hexagonal lattice graph* is a graph whose nodes and edges are - the `hexagonal tiling`_ of the plane. - - The returned graph will have `m` rows and `n` columns of hexagons. - `Odd numbered columns`_ are shifted up relative to even numbered columns. - - Positions of nodes are computed by default or `with_positions is True`. - Node positions creating the standard embedding in the plane - with sidelength 1 and are stored in the node attribute 'pos'. - `pos = nx.get_node_attributes(G, 'pos')` creates a dict ready for drawing. - - .. _hexagonal tiling: https://en.wikipedia.org/wiki/Hexagonal_tiling - .. _Odd numbered columns: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ - - Parameters - ---------- - m : int - The number of rows of hexagons in the lattice. - - n : int - The number of columns of hexagons in the lattice. - - periodic : bool - Whether to make a periodic grid by joining the boundary vertices. - For this to work `n` must be even and both `n > 1` and `m > 1`. - The periodic connections create another row and column of hexagons - so these graphs have fewer nodes as boundary nodes are identified. - - with_positions : bool (default: True) - Store the coordinates of each node in the graph node attribute 'pos'. - The coordinates provide a lattice with vertical columns of hexagons - offset to interleave and cover the plane. - Periodic positions shift the nodes vertically in a nonlinear way so - the edges don't overlap so much. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - If graph is directed, edges will point up or right. - - Returns - ------- - NetworkX graph - The *m* by *n* hexagonal lattice graph. - """ - G = empty_graph(0, create_using) - if m == 0 or n == 0: - return G - if periodic and (n % 2 == 1 or m < 2 or n < 2): - msg = "periodic hexagonal lattice needs m > 1, n > 1 and even n" - raise NetworkXError(msg) - - M = 2 * m # twice as many nodes as hexagons vertically - rows = range(M + 2) - cols = range(n + 1) - # make lattice - col_edges = (((i, j), (i, j + 1)) for i in cols for j in rows[: M + 1]) - row_edges = (((i, j), (i + 1, j)) for i in cols[:n] for j in rows if i % 2 == j % 2) - G.add_edges_from(col_edges) - G.add_edges_from(row_edges) - # Remove corner nodes with one edge - G.remove_node((0, M + 1)) - G.remove_node((n, (M + 1) * (n % 2))) - - # identify boundary nodes if periodic - from networkx.algorithms.minors import contracted_nodes - - if periodic: - for i in cols[:n]: - G = contracted_nodes(G, (i, 0), (i, M)) - for i in cols[1:]: - G = contracted_nodes(G, (i, 1), (i, M + 1)) - for j in rows[1:M]: - G = contracted_nodes(G, (0, j), (n, j)) - G.remove_node((n, M)) - - # calc position in embedded space - ii = (i for i in cols for j in rows) - jj = (j for i in cols for j in rows) - xx = (0.5 + i + i // 2 + (j % 2) * ((i % 2) - 0.5) for i in cols for j in rows) - h = sqrt(3) / 2 - if periodic: - yy = (h * j + 0.01 * i * i for i in cols for j in rows) - else: - yy = (h * j for i in cols for j in rows) - # exclude nodes not in G - pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy) if (i, j) in G} - set_node_attributes(G, pos, "pos") - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/line.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/line.py deleted file mode 100644 index 87d2518..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/line.py +++ /dev/null @@ -1,500 +0,0 @@ -"""Functions for generating line graphs.""" - -from collections import defaultdict -from functools import partial -from itertools import combinations - -import networkx as nx -from networkx.utils import arbitrary_element -from networkx.utils.decorators import not_implemented_for - -__all__ = ["line_graph", "inverse_line_graph"] - - -@nx._dispatchable(returns_graph=True) -def line_graph(G, create_using=None): - r"""Returns the line graph of the graph or digraph `G`. - - The line graph of a graph `G` has a node for each edge in `G` and an - edge joining those nodes if the two edges in `G` share a common node. For - directed graphs, nodes are adjacent exactly when the edges they represent - form a directed path of length two. - - The nodes of the line graph are 2-tuples of nodes in the original graph (or - 3-tuples for multigraphs, with the key of the edge as the third element). - - For information about self-loops and more discussion, see the **Notes** - section below. - - Parameters - ---------- - G : graph - A NetworkX Graph, DiGraph, MultiGraph, or MultiDigraph. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - L : graph - The line graph of G. - - Examples - -------- - >>> G = nx.star_graph(3) - >>> L = nx.line_graph(G) - >>> print(sorted(map(sorted, L.edges()))) # makes a 3-clique, K3 - [[(0, 1), (0, 2)], [(0, 1), (0, 3)], [(0, 2), (0, 3)]] - - Edge attributes from `G` are not copied over as node attributes in `L`, but - attributes can be copied manually: - - >>> G = nx.path_graph(4) - >>> G.add_edges_from((u, v, {"tot": u + v}) for u, v in G.edges) - >>> G.edges(data=True) - EdgeDataView([(0, 1, {'tot': 1}), (1, 2, {'tot': 3}), (2, 3, {'tot': 5})]) - >>> H = nx.line_graph(G) - >>> H.add_nodes_from((node, G.edges[node]) for node in H) - >>> H.nodes(data=True) - NodeDataView({(0, 1): {'tot': 1}, (2, 3): {'tot': 5}, (1, 2): {'tot': 3}}) - - Notes - ----- - Graph, node, and edge data are not propagated to the new graph. For - undirected graphs, the nodes in G must be sortable, otherwise the - constructed line graph may not be correct. - - *Self-loops in undirected graphs* - - For an undirected graph `G` without multiple edges, each edge can be - written as a set `\{u, v\}`. Its line graph `L` has the edges of `G` as - its nodes. If `x` and `y` are two nodes in `L`, then `\{x, y\}` is an edge - in `L` if and only if the intersection of `x` and `y` is nonempty. Thus, - the set of all edges is determined by the set of all pairwise intersections - of edges in `G`. - - Trivially, every edge in G would have a nonzero intersection with itself, - and so every node in `L` should have a self-loop. This is not so - interesting, and the original context of line graphs was with simple - graphs, which had no self-loops or multiple edges. The line graph was also - meant to be a simple graph and thus, self-loops in `L` are not part of the - standard definition of a line graph. In a pairwise intersection matrix, - this is analogous to excluding the diagonal entries from the line graph - definition. - - Self-loops and multiple edges in `G` add nodes to `L` in a natural way, and - do not require any fundamental changes to the definition. It might be - argued that the self-loops we excluded before should now be included. - However, the self-loops are still "trivial" in some sense and thus, are - usually excluded. - - *Self-loops in directed graphs* - - For a directed graph `G` without multiple edges, each edge can be written - as a tuple `(u, v)`. Its line graph `L` has the edges of `G` as its - nodes. If `x` and `y` are two nodes in `L`, then `(x, y)` is an edge in `L` - if and only if the tail of `x` matches the head of `y`, for example, if `x - = (a, b)` and `y = (b, c)` for some vertices `a`, `b`, and `c` in `G`. - - Due to the directed nature of the edges, it is no longer the case that - every edge in `G` should have a self-loop in `L`. Now, the only time - self-loops arise is if a node in `G` itself has a self-loop. So such - self-loops are no longer "trivial" but instead, represent essential - features of the topology of `G`. For this reason, the historical - development of line digraphs is such that self-loops are included. When the - graph `G` has multiple edges, once again only superficial changes are - required to the definition. - - References - ---------- - * Harary, Frank, and Norman, Robert Z., "Some properties of line digraphs", - Rend. Circ. Mat. Palermo, II. Ser. 9 (1960), 161--168. - * Hemminger, R. L.; Beineke, L. W. (1978), "Line graphs and line digraphs", - in Beineke, L. W.; Wilson, R. J., Selected Topics in Graph Theory, - Academic Press Inc., pp. 271--305. - - """ - if G.is_directed(): - L = _lg_directed(G, create_using=create_using) - else: - L = _lg_undirected(G, selfloops=False, create_using=create_using) - return L - - -def _lg_directed(G, create_using=None): - """Returns the line graph L of the (multi)digraph G. - - Edges in G appear as nodes in L, represented as tuples of the form (u,v) - or (u,v,key) if G is a multidigraph. A node in L corresponding to the edge - (u,v) is connected to every node corresponding to an edge (v,w). - - Parameters - ---------- - G : digraph - A directed graph or directed multigraph. - create_using : NetworkX graph constructor, optional - Graph type to create. If graph instance, then cleared before populated. - Default is to use the same graph class as `G`. - - """ - L = nx.empty_graph(0, create_using, default=G.__class__) - - # Create a graph specific edge function. - get_edges = partial(G.edges, keys=True) if G.is_multigraph() else G.edges - - for from_node in get_edges(): - # from_node is: (u,v) or (u,v,key) - L.add_node(from_node) - for to_node in get_edges(from_node[1]): - L.add_edge(from_node, to_node) - - return L - - -def _lg_undirected(G, selfloops=False, create_using=None): - """Returns the line graph L of the (multi)graph G. - - Edges in G appear as nodes in L, represented as sorted tuples of the form - (u,v), or (u,v,key) if G is a multigraph. A node in L corresponding to - the edge {u,v} is connected to every node corresponding to an edge that - involves u or v. - - Parameters - ---------- - G : graph - An undirected graph or multigraph. - selfloops : bool - If `True`, then self-loops are included in the line graph. If `False`, - they are excluded. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - The standard algorithm for line graphs of undirected graphs does not - produce self-loops. - - """ - L = nx.empty_graph(0, create_using, default=G.__class__) - - # Graph specific functions for edges. - get_edges = partial(G.edges, keys=True) if G.is_multigraph() else G.edges - - # Determine if we include self-loops or not. - shift = 0 if selfloops else 1 - - # Introduce numbering of nodes - node_index = {n: i for i, n in enumerate(G)} - - # Lift canonical representation of nodes to edges in line graph - edge_key_function = lambda edge: (node_index[edge[0]], node_index[edge[1]]) - - edges = set() - for u in G: - # Label nodes as a sorted tuple of nodes in original graph. - # Decide on representation of {u, v} as (u, v) or (v, u) depending on node_index. - # -> This ensures a canonical representation and avoids comparing values of different types. - nodes = [tuple(sorted(x[:2], key=node_index.get)) + x[2:] for x in get_edges(u)] - - if len(nodes) == 1: - # Then the edge will be an isolated node in L. - L.add_node(nodes[0]) - - # Add a clique of `nodes` to graph. To prevent double adding edges, - # especially important for multigraphs, we store the edges in - # canonical form in a set. - for i, a in enumerate(nodes): - edges.update( - [ - tuple(sorted((a, b), key=edge_key_function)) - for b in nodes[i + shift :] - ] - ) - - L.add_edges_from(edges) - return L - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def inverse_line_graph(G): - """Returns the inverse line graph of graph G. - - If H is a graph, and G is the line graph of H, such that G = L(H). - Then H is the inverse line graph of G. - - Not all graphs are line graphs and these do not have an inverse line graph. - In these cases this function raises a NetworkXError. - - Parameters - ---------- - G : graph - A NetworkX Graph - - Returns - ------- - H : graph - The inverse line graph of G. - - Raises - ------ - NetworkXNotImplemented - If G is directed or a multigraph - - NetworkXError - If G is not a line graph - - Notes - ----- - This is an implementation of the Roussopoulos algorithm[1]_. - - If G consists of multiple components, then the algorithm doesn't work. - You should invert every component separately: - - >>> K5 = nx.complete_graph(5) - >>> P4 = nx.Graph([("a", "b"), ("b", "c"), ("c", "d")]) - >>> G = nx.union(K5, P4) - >>> root_graphs = [] - >>> for comp in nx.connected_components(G): - ... root_graphs.append(nx.inverse_line_graph(G.subgraph(comp))) - >>> len(root_graphs) - 2 - - References - ---------- - .. [1] Roussopoulos, N.D. , "A max {m, n} algorithm for determining the graph H from - its line graph G", Information Processing Letters 2, (1973), 108--112, ISSN 0020-0190, - `DOI link `_ - - """ - if G.number_of_nodes() == 0: - return nx.empty_graph(1) - elif G.number_of_nodes() == 1: - v = arbitrary_element(G) - a = (v, 0) - b = (v, 1) - H = nx.Graph([(a, b)]) - return H - elif G.number_of_nodes() > 1 and G.number_of_edges() == 0: - msg = ( - "inverse_line_graph() doesn't work on an edgeless graph. " - "Please use this function on each component separately." - ) - raise nx.NetworkXError(msg) - - if nx.number_of_selfloops(G) != 0: - msg = ( - "A line graph as generated by NetworkX has no selfloops, so G has no " - "inverse line graph. Please remove the selfloops from G and try again." - ) - raise nx.NetworkXError(msg) - - starting_cell = _select_starting_cell(G) - P = _find_partition(G, starting_cell) - # count how many times each vertex appears in the partition set - P_count = {u: 0 for u in G.nodes} - for p in P: - for u in p: - P_count[u] += 1 - - if max(P_count.values()) > 2: - msg = "G is not a line graph (vertex found in more than two partition cells)" - raise nx.NetworkXError(msg) - W = tuple((u,) for u in P_count if P_count[u] == 1) - H = nx.Graph() - H.add_nodes_from(P) - H.add_nodes_from(W) - for a, b in combinations(H.nodes, 2): - if any(a_bit in b for a_bit in a): - H.add_edge(a, b) - return H - - -def _triangles(G, e): - """Return list of all triangles containing edge e""" - u, v = e - if u not in G: - raise nx.NetworkXError(f"Vertex {u} not in graph") - if v not in G[u]: - raise nx.NetworkXError(f"Edge ({u}, {v}) not in graph") - triangle_list = [] - for x in G[u]: - if x in G[v]: - triangle_list.append((u, v, x)) - return triangle_list - - -def _odd_triangle(G, T): - """Test whether T is an odd triangle in G - - Parameters - ---------- - G : NetworkX Graph - T : 3-tuple of vertices forming triangle in G - - Returns - ------- - True is T is an odd triangle - False otherwise - - Raises - ------ - NetworkXError - T is not a triangle in G - - Notes - ----- - An odd triangle is one in which there exists another vertex in G which is - adjacent to either exactly one or exactly all three of the vertices in the - triangle. - - """ - for u in T: - if u not in G.nodes(): - raise nx.NetworkXError(f"Vertex {u} not in graph") - for e in list(combinations(T, 2)): - if e[0] not in G[e[1]]: - raise nx.NetworkXError(f"Edge ({e[0]}, {e[1]}) not in graph") - - T_nbrs = defaultdict(int) - for t in T: - for v in G[t]: - if v not in T: - T_nbrs[v] += 1 - return any(T_nbrs[v] in [1, 3] for v in T_nbrs) - - -def _find_partition(G, starting_cell): - """Find a partition of the vertices of G into cells of complete graphs - - Parameters - ---------- - G : NetworkX Graph - starting_cell : tuple of vertices in G which form a cell - - Returns - ------- - List of tuples of vertices of G - - Raises - ------ - NetworkXError - If a cell is not a complete subgraph then G is not a line graph - """ - G_partition = G.copy() - P = [starting_cell] # partition set - G_partition.remove_edges_from(list(combinations(starting_cell, 2))) - # keep list of partitioned nodes which might have an edge in G_partition - partitioned_vertices = list(starting_cell) - while G_partition.number_of_edges() > 0: - # there are still edges left and so more cells to be made - u = partitioned_vertices.pop() - deg_u = len(G_partition[u]) - if deg_u != 0: - # if u still has edges then we need to find its other cell - # this other cell must be a complete subgraph or else G is - # not a line graph - new_cell = [u] + list(G_partition[u]) - for u in new_cell: - for v in new_cell: - if (u != v) and (v not in G_partition[u]): - msg = ( - "G is not a line graph " - "(partition cell not a complete subgraph)" - ) - raise nx.NetworkXError(msg) - P.append(tuple(new_cell)) - G_partition.remove_edges_from(list(combinations(new_cell, 2))) - partitioned_vertices += new_cell - return P - - -def _select_starting_cell(G, starting_edge=None): - """Select a cell to initiate _find_partition - - Parameters - ---------- - G : NetworkX Graph - starting_edge: an edge to build the starting cell from - - Returns - ------- - Tuple of vertices in G - - Raises - ------ - NetworkXError - If it is determined that G is not a line graph - - Notes - ----- - If starting edge not specified then pick an arbitrary edge - doesn't - matter which. However, this function may call itself requiring a - specific starting edge. Note that the r, s notation for counting - triangles is the same as in the Roussopoulos paper cited above. - """ - if starting_edge is None: - e = arbitrary_element(G.edges()) - else: - e = starting_edge - if e[0] not in G.nodes(): - raise nx.NetworkXError(f"Vertex {e[0]} not in graph") - if e[1] not in G[e[0]]: - msg = f"starting_edge ({e[0]}, {e[1]}) is not in the Graph" - raise nx.NetworkXError(msg) - e_triangles = _triangles(G, e) - r = len(e_triangles) - if r == 0: - # there are no triangles containing e, so the starting cell is just e - starting_cell = e - elif r == 1: - # there is exactly one triangle, T, containing e. If other 2 edges - # of T belong only to this triangle then T is starting cell - T = e_triangles[0] - a, b, c = T - # ab was original edge so check the other 2 edges - ac_edges = len(_triangles(G, (a, c))) - bc_edges = len(_triangles(G, (b, c))) - if ac_edges == 1: - if bc_edges == 1: - starting_cell = T - else: - return _select_starting_cell(G, starting_edge=(b, c)) - else: - return _select_starting_cell(G, starting_edge=(a, c)) - else: - # r >= 2 so we need to count the number of odd triangles, s - s = 0 - odd_triangles = [] - for T in e_triangles: - if _odd_triangle(G, T): - s += 1 - odd_triangles.append(T) - if r == 2 and s == 0: - # in this case either triangle works, so just use T - starting_cell = T - elif r - 1 <= s <= r: - # check if odd triangles containing e form complete subgraph - triangle_nodes = set() - for T in odd_triangles: - for x in T: - triangle_nodes.add(x) - - for u in triangle_nodes: - for v in triangle_nodes: - if u != v and (v not in G[u]): - msg = ( - "G is not a line graph (odd triangles " - "do not form complete subgraph)" - ) - raise nx.NetworkXError(msg) - # otherwise then we can use this as the starting cell - starting_cell = tuple(triangle_nodes) - - else: - msg = ( - "G is not a line graph (incorrect number of " - "odd triangles around starting edge)" - ) - raise nx.NetworkXError(msg) - return starting_cell diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/mycielski.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/mycielski.py deleted file mode 100644 index 804b903..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/mycielski.py +++ /dev/null @@ -1,110 +0,0 @@ -"""Functions related to the Mycielski Operation and the Mycielskian family -of graphs. - -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["mycielskian", "mycielski_graph"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(returns_graph=True) -def mycielskian(G, iterations=1): - r"""Returns the Mycielskian of a simple, undirected graph G - - The Mycielskian of graph preserves a graph's triangle free - property while increasing the chromatic number by 1. - - The Mycielski Operation on a graph, :math:`G=(V, E)`, constructs a new - graph with :math:`2|V| + 1` nodes and :math:`3|E| + |V|` edges. - - The construction is as follows: - - Let :math:`V = {0, ..., n-1}`. Construct another vertex set - :math:`U = {n, ..., 2n}` and a vertex, `w`. - Construct a new graph, `M`, with vertices :math:`U \bigcup V \bigcup w`. - For edges, :math:`(u, v) \in E` add edges :math:`(u, v), (u, v + n)`, and - :math:`(u + n, v)` to M. Finally, for all vertices :math:`u \in U`, add - edge :math:`(u, w)` to M. - - The Mycielski Operation can be done multiple times by repeating the above - process iteratively. - - More information can be found at https://en.wikipedia.org/wiki/Mycielskian - - Parameters - ---------- - G : graph - A simple, undirected NetworkX graph - iterations : int - The number of iterations of the Mycielski operation to - perform on G. Defaults to 1. Must be a non-negative integer. - - Returns - ------- - M : graph - The Mycielskian of G after the specified number of iterations. - - Notes - ----- - Graph, node, and edge data are not necessarily propagated to the new graph. - - """ - - M = nx.convert_node_labels_to_integers(G) - - for i in range(iterations): - n = M.number_of_nodes() - M.add_nodes_from(range(n, 2 * n)) - old_edges = list(M.edges()) - M.add_edges_from((u, v + n) for u, v in old_edges) - M.add_edges_from((u + n, v) for u, v in old_edges) - M.add_node(2 * n) - M.add_edges_from((u + n, 2 * n) for u in range(n)) - - return M - - -@nx._dispatchable(graphs=None, returns_graph=True) -def mycielski_graph(n): - """Generator for the n_th Mycielski Graph. - - The Mycielski family of graphs is an infinite set of graphs. - :math:`M_1` is the singleton graph, :math:`M_2` is two vertices with an - edge, and, for :math:`i > 2`, :math:`M_i` is the Mycielskian of - :math:`M_{i-1}`. - - More information can be found at - http://mathworld.wolfram.com/MycielskiGraph.html - - Parameters - ---------- - n : int - The desired Mycielski Graph. - - Returns - ------- - M : graph - The n_th Mycielski Graph - - Notes - ----- - The first graph in the Mycielski sequence is the singleton graph. - The Mycielskian of this graph is not the :math:`P_2` graph, but rather the - :math:`P_2` graph with an extra, isolated vertex. The second Mycielski - graph is the :math:`P_2` graph, so the first two are hard coded. - The remaining graphs are generated using the Mycielski operation. - - """ - - if n < 1: - raise nx.NetworkXError("must satisfy n >= 1") - - if n == 1: - return nx.empty_graph(1) - - else: - return mycielskian(nx.path_graph(2), n - 2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/nonisomorphic_trees.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/nonisomorphic_trees.py deleted file mode 100644 index 9716cf3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/nonisomorphic_trees.py +++ /dev/null @@ -1,212 +0,0 @@ -""" -Implementation of the Wright, Richmond, Odlyzko and McKay (WROM) -algorithm for the enumeration of all non-isomorphic free trees of a -given order. Rooted trees are represented by level sequences, i.e., -lists in which the i-th element specifies the distance of vertex i to -the root. - -""" - -__all__ = ["nonisomorphic_trees", "number_of_nonisomorphic_trees"] - -import networkx as nx - - -@nx._dispatchable(graphs=None, returns_graph=True) -def nonisomorphic_trees(order, create="graph"): - """Generates lists of nonisomorphic trees - - Parameters - ---------- - order : int - order of the desired tree(s) - - create : one of {"graph", "matrix"} (default="graph") - If ``"graph"`` is selected a list of ``Graph`` instances will be returned, - if matrix is selected a list of adjacency matrices will be returned. - - .. deprecated:: 3.3 - - The `create` argument is deprecated and will be removed in NetworkX - version 3.5. In the future, `nonisomorphic_trees` will yield graph - instances by default. To generate adjacency matrices, call - ``nx.to_numpy_array`` on the output, e.g.:: - - [nx.to_numpy_array(G) for G in nx.nonisomorphic_trees(N)] - - Yields - ------ - list - A list of nonisomorphic trees, in one of two formats depending on the - value of the `create` parameter: - - ``create="graph"``: yields a list of `networkx.Graph` instances - - ``create="matrix"``: yields a list of list-of-lists representing adjacency matrices - """ - - if order < 2: - raise ValueError - # start at the path graph rooted at its center - layout = list(range(order // 2 + 1)) + list(range(1, (order + 1) // 2)) - - while layout is not None: - layout = _next_tree(layout) - if layout is not None: - if create == "graph": - yield _layout_to_graph(layout) - elif create == "matrix": - import warnings - - warnings.warn( - ( - "\n\nThe 'create=matrix' argument of nonisomorphic_trees\n" - "is deprecated and will be removed in version 3.5.\n" - "Use ``nx.to_numpy_array`` to convert graphs to adjacency " - "matrices, e.g.::\n\n" - " [nx.to_numpy_array(G) for G in nx.nonisomorphic_trees(N)]" - ), - category=DeprecationWarning, - stacklevel=2, - ) - - yield _layout_to_matrix(layout) - layout = _next_rooted_tree(layout) - - -@nx._dispatchable(graphs=None) -def number_of_nonisomorphic_trees(order): - """Returns the number of nonisomorphic trees - - Parameters - ---------- - order : int - order of the desired tree(s) - - Returns - ------- - length : Number of nonisomorphic graphs for the given order - - References - ---------- - - """ - return sum(1 for _ in nonisomorphic_trees(order)) - - -def _next_rooted_tree(predecessor, p=None): - """One iteration of the Beyer-Hedetniemi algorithm.""" - - if p is None: - p = len(predecessor) - 1 - while predecessor[p] == 1: - p -= 1 - if p == 0: - return None - - q = p - 1 - while predecessor[q] != predecessor[p] - 1: - q -= 1 - result = list(predecessor) - for i in range(p, len(result)): - result[i] = result[i - p + q] - return result - - -def _next_tree(candidate): - """One iteration of the Wright, Richmond, Odlyzko and McKay - algorithm.""" - - # valid representation of a free tree if: - # there are at least two vertices at layer 1 - # (this is always the case because we start at the path graph) - left, rest = _split_tree(candidate) - - # and the left subtree of the root - # is less high than the tree with the left subtree removed - left_height = max(left) - rest_height = max(rest) - valid = rest_height >= left_height - - if valid and rest_height == left_height: - # and, if left and rest are of the same height, - # if left does not encompass more vertices - if len(left) > len(rest): - valid = False - # and, if they have the same number or vertices, - # if left does not come after rest lexicographically - elif len(left) == len(rest) and left > rest: - valid = False - - if valid: - return candidate - else: - # jump to the next valid free tree - p = len(left) - new_candidate = _next_rooted_tree(candidate, p) - if candidate[p] > 2: - new_left, new_rest = _split_tree(new_candidate) - new_left_height = max(new_left) - suffix = range(1, new_left_height + 2) - new_candidate[-len(suffix) :] = suffix - return new_candidate - - -def _split_tree(layout): - """Returns a tuple of two layouts, one containing the left - subtree of the root vertex, and one containing the original tree - with the left subtree removed.""" - - one_found = False - m = None - for i in range(len(layout)): - if layout[i] == 1: - if one_found: - m = i - break - else: - one_found = True - - if m is None: - m = len(layout) - - left = [layout[i] - 1 for i in range(1, m)] - rest = [0] + [layout[i] for i in range(m, len(layout))] - return (left, rest) - - -def _layout_to_matrix(layout): - """Create the adjacency matrix for the tree specified by the - given layout (level sequence).""" - - result = [[0] * len(layout) for i in range(len(layout))] - stack = [] - for i in range(len(layout)): - i_level = layout[i] - if stack: - j = stack[-1] - j_level = layout[j] - while j_level >= i_level: - stack.pop() - j = stack[-1] - j_level = layout[j] - result[i][j] = result[j][i] = 1 - stack.append(i) - return result - - -def _layout_to_graph(layout): - """Create a NetworkX Graph for the tree specified by the - given layout(level sequence)""" - G = nx.Graph() - stack = [] - for i in range(len(layout)): - i_level = layout[i] - if stack: - j = stack[-1] - j_level = layout[j] - while j_level >= i_level: - stack.pop() - j = stack[-1] - j_level = layout[j] - G.add_edge(i, j) - stack.append(i) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_clustered.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_clustered.py deleted file mode 100644 index 8fbf855..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_clustered.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Generate graphs with given degree and triangle sequence.""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ["random_clustered_graph"] - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_clustered_graph(joint_degree_sequence, create_using=None, seed=None): - r"""Generate a random graph with the given joint independent edge degree and - triangle degree sequence. - - This uses a configuration model-like approach to generate a random graph - (with parallel edges and self-loops) by randomly assigning edges to match - the given joint degree sequence. - - The joint degree sequence is a list of pairs of integers of the form - $[(d_{1,i}, d_{1,t}), \dotsc, (d_{n,i}, d_{n,t})]$. According to this list, - vertex $u$ is a member of $d_{u,t}$ triangles and has $d_{u, i}$ other - edges. The number $d_{u,t}$ is the *triangle degree* of $u$ and the number - $d_{u,i}$ is the *independent edge degree*. - - Parameters - ---------- - joint_degree_sequence : list of integer pairs - Each list entry corresponds to the independent edge degree and - triangle degree of a node. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiGraph - A graph with the specified degree sequence. Nodes are labeled - starting at 0 with an index corresponding to the position in - deg_sequence. - - Raises - ------ - NetworkXError - If the independent edge degree sequence sum is not even - or the triangle degree sequence sum is not divisible by 3. - - Notes - ----- - As described by Miller [1]_ (see also Newman [2]_ for an equivalent - description). - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the - independent degree sequence does not have an even sum or the - triangle degree sequence sum is not divisible by 3. - - This configuration model-like construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. This - "finite-size effect" decreases as the size of the graph increases. - - References - ---------- - .. [1] Joel C. Miller. "Percolation and epidemics in random clustered - networks". In: Physical review. E, Statistical, nonlinear, and soft - matter physics 80 (2 Part 1 August 2009). - .. [2] M. E. J. Newman. "Random Graphs with Clustering". - In: Physical Review Letters 103 (5 July 2009) - - Examples - -------- - >>> deg = [(1, 0), (1, 0), (1, 0), (2, 0), (1, 0), (2, 1), (0, 1), (0, 1)] - >>> G = nx.random_clustered_graph(deg) - - To remove parallel edges: - - >>> G = nx.Graph(G) - - To remove self loops: - - >>> G.remove_edges_from(nx.selfloop_edges(G)) - - """ - # In Python 3, zip() returns an iterator. Make this into a list. - joint_degree_sequence = list(joint_degree_sequence) - - N = len(joint_degree_sequence) - G = nx.empty_graph(N, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - ilist = [] - tlist = [] - for n in G: - degrees = joint_degree_sequence[n] - for icount in range(degrees[0]): - ilist.append(n) - for tcount in range(degrees[1]): - tlist.append(n) - - if len(ilist) % 2 != 0 or len(tlist) % 3 != 0: - raise nx.NetworkXError("Invalid degree sequence") - - seed.shuffle(ilist) - seed.shuffle(tlist) - while ilist: - G.add_edge(ilist.pop(), ilist.pop()) - while tlist: - n1 = tlist.pop() - n2 = tlist.pop() - n3 = tlist.pop() - G.add_edges_from([(n1, n2), (n1, n3), (n2, n3)]) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_graphs.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_graphs.py deleted file mode 100644 index 90ae0d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/random_graphs.py +++ /dev/null @@ -1,1400 +0,0 @@ -""" -Generators for random graphs. - -""" - -import itertools -import math -from collections import defaultdict - -import networkx as nx -from networkx.utils import py_random_state - -from ..utils.misc import check_create_using -from .classic import complete_graph, empty_graph, path_graph, star_graph -from .degree_seq import degree_sequence_tree - -__all__ = [ - "fast_gnp_random_graph", - "gnp_random_graph", - "dense_gnm_random_graph", - "gnm_random_graph", - "erdos_renyi_graph", - "binomial_graph", - "newman_watts_strogatz_graph", - "watts_strogatz_graph", - "connected_watts_strogatz_graph", - "random_regular_graph", - "barabasi_albert_graph", - "dual_barabasi_albert_graph", - "extended_barabasi_albert_graph", - "powerlaw_cluster_graph", - "random_lobster", - "random_shell_graph", - "random_powerlaw_tree", - "random_powerlaw_tree_sequence", - "random_kernel_graph", -] - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def fast_gnp_random_graph(n, p, seed=None, directed=False, *, create_using=None): - """Returns a $G_{n,p}$ random graph, also known as an ErdÅ‘s-Rényi graph or - a binomial graph. - - Parameters - ---------- - n : int - The number of nodes. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True, this function returns a directed graph. - create_using : Graph constructor, optional (default=nx.Graph or nx.DiGraph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph types are not supported and raise a ``NetworkXError``. - By default NetworkX Graph or DiGraph are used depending on `directed`. - - Notes - ----- - The $G_{n,p}$ graph algorithm chooses each of the $[n (n - 1)] / 2$ - (undirected) or $n (n - 1)$ (directed) possible edges with probability $p$. - - This algorithm [1]_ runs in $O(n + m)$ time, where `m` is the expected number of - edges, which equals $p n (n - 1) / 2$. This should be faster than - :func:`gnp_random_graph` when $p$ is small and the expected number of edges - is small (that is, the graph is sparse). - - See Also - -------- - gnp_random_graph - - References - ---------- - .. [1] Vladimir Batagelj and Ulrik Brandes, - "Efficient generation of large random networks", - Phys. Rev. E, 71, 036113, 2005. - """ - default = nx.DiGraph if directed else nx.Graph - create_using = check_create_using( - create_using, directed=directed, multigraph=False, default=default - ) - if p <= 0 or p >= 1: - return nx.gnp_random_graph( - n, p, seed=seed, directed=directed, create_using=create_using - ) - - G = empty_graph(n, create_using=create_using) - - lp = math.log(1.0 - p) - - if directed: - v = 1 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= v and v < n: - w = w - v - v = v + 1 - if v < n: - G.add_edge(w, v) - - # Nodes in graph are from 0,n-1 (start with v as the second node index). - v = 1 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= v and v < n: - w = w - v - v = v + 1 - if v < n: - G.add_edge(v, w) - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def gnp_random_graph(n, p, seed=None, directed=False, *, create_using=None): - """Returns a $G_{n,p}$ random graph, also known as an ErdÅ‘s-Rényi graph - or a binomial graph. - - The $G_{n,p}$ model chooses each of the possible edges with probability $p$. - - Parameters - ---------- - n : int - The number of nodes. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True, this function returns a directed graph. - create_using : Graph constructor, optional (default=nx.Graph or nx.DiGraph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph types are not supported and raise a ``NetworkXError``. - By default NetworkX Graph or DiGraph are used depending on `directed`. - - See Also - -------- - fast_gnp_random_graph - - Notes - ----- - This algorithm [2]_ runs in $O(n^2)$ time. For sparse graphs (that is, for - small values of $p$), :func:`fast_gnp_random_graph` is a faster algorithm. - - :func:`binomial_graph` and :func:`erdos_renyi_graph` are - aliases for :func:`gnp_random_graph`. - - >>> nx.binomial_graph is nx.gnp_random_graph - True - >>> nx.erdos_renyi_graph is nx.gnp_random_graph - True - - References - ---------- - .. [1] P. ErdÅ‘s and A. Rényi, On Random Graphs, Publ. Math. 6, 290 (1959). - .. [2] E. N. Gilbert, Random Graphs, Ann. Math. Stat., 30, 1141 (1959). - """ - default = nx.DiGraph if directed else nx.Graph - create_using = check_create_using( - create_using, directed=directed, multigraph=False, default=default - ) - if p >= 1: - return complete_graph(n, create_using=create_using) - - G = nx.empty_graph(n, create_using=create_using) - if p <= 0: - return G - - edgetool = itertools.permutations if directed else itertools.combinations - for e in edgetool(range(n), 2): - if seed.random() < p: - G.add_edge(*e) - return G - - -# add some aliases to common names -binomial_graph = gnp_random_graph -erdos_renyi_graph = gnp_random_graph - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def dense_gnm_random_graph(n, m, seed=None, *, create_using=None): - """Returns a $G_{n,m}$ random graph. - - In the $G_{n,m}$ model, a graph is chosen uniformly at random from the set - of all graphs with $n$ nodes and $m$ edges. - - This algorithm should be faster than :func:`gnm_random_graph` for dense - graphs. - - Parameters - ---------- - n : int - The number of nodes. - m : int - The number of edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - See Also - -------- - gnm_random_graph - - Notes - ----- - Algorithm by Keith M. Briggs Mar 31, 2006. - Inspired by Knuth's Algorithm S (Selection sampling technique), - in section 3.4.2 of [1]_. - - References - ---------- - .. [1] Donald E. Knuth, The Art of Computer Programming, - Volume 2/Seminumerical algorithms, Third Edition, Addison-Wesley, 1997. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - mmax = n * (n - 1) // 2 - if m >= mmax: - return complete_graph(n, create_using) - G = empty_graph(n, create_using) - - if n == 1: - return G - - u = 0 - v = 1 - t = 0 - k = 0 - while True: - if seed.randrange(mmax - t) < m - k: - G.add_edge(u, v) - k += 1 - if k == m: - return G - t += 1 - v += 1 - if v == n: # go to next row of adjacency matrix - u += 1 - v = u + 1 - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def gnm_random_graph(n, m, seed=None, directed=False, *, create_using=None): - """Returns a $G_{n,m}$ random graph. - - In the $G_{n,m}$ model, a graph is chosen uniformly at random from the set - of all graphs with $n$ nodes and $m$ edges. - - This algorithm should be faster than :func:`dense_gnm_random_graph` for - sparse graphs. - - Parameters - ---------- - n : int - The number of nodes. - m : int - The number of edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - create_using : Graph constructor, optional (default=nx.Graph or nx.DiGraph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph types are not supported and raise a ``NetworkXError``. - By default NetworkX Graph or DiGraph are used depending on `directed`. - - See also - -------- - dense_gnm_random_graph - - """ - default = nx.DiGraph if directed else nx.Graph - create_using = check_create_using( - create_using, directed=directed, multigraph=False, default=default - ) - if n == 1: - return nx.empty_graph(n, create_using=create_using) - max_edges = n * (n - 1) if directed else n * (n - 1) / 2.0 - if m >= max_edges: - return complete_graph(n, create_using=create_using) - - G = nx.empty_graph(n, create_using=create_using) - nlist = list(G) - edge_count = 0 - while edge_count < m: - # generate random edge,u,v - u = seed.choice(nlist) - v = seed.choice(nlist) - if u == v or G.has_edge(u, v): - continue - else: - G.add_edge(u, v) - edge_count = edge_count + 1 - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def newman_watts_strogatz_graph(n, k, p, seed=None, *, create_using=None): - """Returns a Newman–Watts–Strogatz small-world graph. - - Parameters - ---------- - n : int - The number of nodes. - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of adding a new edge for each edge. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is - connected with its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ - is odd). Then shortcuts are created by adding new edges as follows: for - each edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest - neighbors" with probability $p$ add a new edge $(u, w)$ with - randomly-chosen existing node $w$. In contrast with - :func:`watts_strogatz_graph`, no edges are removed. - - See Also - -------- - watts_strogatz_graph - - References - ---------- - .. [1] M. E. J. Newman and D. J. Watts, - Renormalization group analysis of the small-world network model, - Physics Letters A, 263, 341, 1999. - https://doi.org/10.1016/S0375-9601(99)00757-4 - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if k > n: - raise nx.NetworkXError("k>=n, choose smaller k or larger n") - - # If k == n the graph return is a complete graph - if k == n: - return nx.complete_graph(n, create_using) - - G = empty_graph(n, create_using) - nlist = list(G.nodes()) - fromv = nlist - # connect the k/2 neighbors - for j in range(1, k // 2 + 1): - tov = fromv[j:] + fromv[0:j] # the first j are now last - for i in range(len(fromv)): - G.add_edge(fromv[i], tov[i]) - # for each edge u-v, with probability p, randomly select existing - # node w and add new edge u-w - e = list(G.edges()) - for u, v in e: - if seed.random() < p: - w = seed.choice(nlist) - # no self-loops and reject if edge u-w exists - # is that the correct NWS model? - while w == u or G.has_edge(u, w): - w = seed.choice(nlist) - if G.degree(u) >= n - 1: - break # skip this rewiring - else: - G.add_edge(u, w) - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def watts_strogatz_graph(n, k, p, seed=None, *, create_using=None): - """Returns a Watts–Strogatz small-world graph. - - Parameters - ---------- - n : int - The number of nodes - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of rewiring each edge - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - See Also - -------- - newman_watts_strogatz_graph - connected_watts_strogatz_graph - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is joined - to its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ is odd). - Then shortcuts are created by replacing some edges as follows: for each - edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest neighbors" - with probability $p$ replace it with a new edge $(u, w)$ with uniformly - random choice of existing node $w$. - - In contrast with :func:`newman_watts_strogatz_graph`, the random rewiring - does not increase the number of edges. The rewired graph is not guaranteed - to be connected as in :func:`connected_watts_strogatz_graph`. - - References - ---------- - .. [1] Duncan J. Watts and Steven H. Strogatz, - Collective dynamics of small-world networks, - Nature, 393, pp. 440--442, 1998. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if k > n: - raise nx.NetworkXError("k>n, choose smaller k or larger n") - - # If k == n, the graph is complete not Watts-Strogatz - if k == n: - G = nx.complete_graph(n, create_using) - return G - - G = nx.empty_graph(n, create_using=create_using) - nodes = list(range(n)) # nodes are labeled 0 to n-1 - # connect each node to k/2 neighbors - for j in range(1, k // 2 + 1): - targets = nodes[j:] + nodes[0:j] # first j nodes are now last in list - G.add_edges_from(zip(nodes, targets)) - # rewire edges from each node - # loop over all nodes in order (label) and neighbors in order (distance) - # no self loops or multiple edges allowed - for j in range(1, k // 2 + 1): # outer loop is neighbors - targets = nodes[j:] + nodes[0:j] # first j nodes are now last in list - # inner loop in node order - for u, v in zip(nodes, targets): - if seed.random() < p: - w = seed.choice(nodes) - # Enforce no self-loops or multiple edges - while w == u or G.has_edge(u, w): - w = seed.choice(nodes) - if G.degree(u) >= n - 1: - break # skip this rewiring - else: - G.remove_edge(u, v) - G.add_edge(u, w) - return G - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def connected_watts_strogatz_graph(n, k, p, tries=100, seed=None, *, create_using=None): - """Returns a connected Watts–Strogatz small-world graph. - - Attempts to generate a connected graph by repeated generation of - Watts–Strogatz small-world graphs. An exception is raised if the maximum - number of tries is exceeded. - - Parameters - ---------- - n : int - The number of nodes - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of rewiring each edge - tries : int - Number of attempts to generate a connected graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is joined - to its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ is odd). - Then shortcuts are created by replacing some edges as follows: for each - edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest neighbors" - with probability $p$ replace it with a new edge $(u, w)$ with uniformly - random choice of existing node $w$. - The entire process is repeated until a connected graph results. - - See Also - -------- - newman_watts_strogatz_graph - watts_strogatz_graph - - References - ---------- - .. [1] Duncan J. Watts and Steven H. Strogatz, - Collective dynamics of small-world networks, - Nature, 393, pp. 440--442, 1998. - """ - for i in range(tries): - # seed is an RNG so should change sequence each call - G = watts_strogatz_graph(n, k, p, seed, create_using=create_using) - if nx.is_connected(G): - return G - raise nx.NetworkXError("Maximum number of tries exceeded") - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_regular_graph(d, n, seed=None, *, create_using=None): - r"""Returns a random $d$-regular graph on $n$ nodes. - - A regular graph is a graph where each node has the same number of neighbors. - - The resulting graph has no self-loops or parallel edges. - - Parameters - ---------- - d : int - The degree of each node. - n : integer - The number of nodes. The value of $n \times d$ must be even. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - The nodes are numbered from $0$ to $n - 1$. - - Kim and Vu's paper [2]_ shows that this algorithm samples in an - asymptotically uniform way from the space of random graphs when - $d = O(n^{1 / 3 - \epsilon})$. - - Raises - ------ - - NetworkXError - If $n \times d$ is odd or $d$ is greater than or equal to $n$. - - References - ---------- - .. [1] A. Steger and N. Wormald, - Generating random regular graphs quickly, - Probability and Computing 8 (1999), 377-396, 1999. - https://doi.org/10.1017/S0963548399003867 - - .. [2] Jeong Han Kim and Van H. Vu, - Generating random regular graphs, - Proceedings of the thirty-fifth ACM symposium on Theory of computing, - San Diego, CA, USA, pp 213--222, 2003. - http://portal.acm.org/citation.cfm?id=780542.780576 - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if (n * d) % 2 != 0: - raise nx.NetworkXError("n * d must be even") - - if not 0 <= d < n: - raise nx.NetworkXError("the 0 <= d < n inequality must be satisfied") - - G = nx.empty_graph(n, create_using=create_using) - - if d == 0: - return G - - def _suitable(edges, potential_edges): - # Helper subroutine to check if there are suitable edges remaining - # If False, the generation of the graph has failed - if not potential_edges: - return True - for s1 in potential_edges: - for s2 in potential_edges: - # Two iterators on the same dictionary are guaranteed - # to visit it in the same order if there are no - # intervening modifications. - if s1 == s2: - # Only need to consider s1-s2 pair one time - break - if s1 > s2: - s1, s2 = s2, s1 - if (s1, s2) not in edges: - return True - return False - - def _try_creation(): - # Attempt to create an edge set - - edges = set() - stubs = list(range(n)) * d - - while stubs: - potential_edges = defaultdict(lambda: 0) - seed.shuffle(stubs) - stubiter = iter(stubs) - for s1, s2 in zip(stubiter, stubiter): - if s1 > s2: - s1, s2 = s2, s1 - if s1 != s2 and ((s1, s2) not in edges): - edges.add((s1, s2)) - else: - potential_edges[s1] += 1 - potential_edges[s2] += 1 - - if not _suitable(edges, potential_edges): - return None # failed to find suitable edge set - - stubs = [ - node - for node, potential in potential_edges.items() - for _ in range(potential) - ] - return edges - - # Even though a suitable edge set exists, - # the generation of such a set is not guaranteed. - # Try repeatedly to find one. - edges = _try_creation() - while edges is None: - edges = _try_creation() - G.add_edges_from(edges) - - return G - - -def _random_subset(seq, m, rng): - """Return m unique elements from seq. - - This differs from random.sample which can return repeated - elements if seq holds repeated elements. - - Note: rng is a random.Random or numpy.random.RandomState instance. - """ - targets = set() - while len(targets) < m: - x = rng.choice(seq) - targets.add(x) - return targets - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def barabasi_albert_graph(n, m, seed=None, initial_graph=None, *, create_using=None): - """Returns a random graph using Barabási–Albert preferential attachment - - A graph of $n$ nodes is grown by attaching new nodes each with $m$ - edges that are preferentially attached to existing nodes with high degree. - - Parameters - ---------- - n : int - Number of nodes - m : int - Number of edges to attach from a new node to existing nodes - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - initial_graph : Graph or None (default) - Initial network for Barabási–Albert algorithm. - It should be a connected graph for most use cases. - A copy of `initial_graph` is used. - If None, starts from a star graph on (m+1) nodes. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m < n``, or - the initial graph number of nodes m0 does not satisfy ``m <= m0 <= n``. - - References - ---------- - .. [1] A. L. Barabási and R. Albert "Emergence of scaling in - random networks", Science 286, pp 509-512, 1999. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if m < 1 or m >= n: - raise nx.NetworkXError( - f"Barabási–Albert network must have m >= 1 and m < n, m = {m}, n = {n}" - ) - - if initial_graph is None: - # Default initial graph : star graph on (m + 1) nodes - G = star_graph(m, create_using) - else: - if len(initial_graph) < m or len(initial_graph) > n: - raise nx.NetworkXError( - f"Barabási–Albert initial graph needs between m={m} and n={n} nodes" - ) - G = initial_graph.copy() - - # List of existing nodes, with nodes repeated once for each adjacent edge - repeated_nodes = [n for n, d in G.degree() for _ in range(d)] - # Start adding the other n - m0 nodes. - source = len(G) - while source < n: - # Now choose m unique nodes from the existing nodes - # Pick uniformly from repeated_nodes (preferential attachment) - targets = _random_subset(repeated_nodes, m, seed) - # Add edges to m nodes from the source. - G.add_edges_from(zip([source] * m, targets)) - # Add one node to the list for each new edge just created. - repeated_nodes.extend(targets) - # And the new node "source" has m edges to add to the list. - repeated_nodes.extend([source] * m) - - source += 1 - return G - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def dual_barabasi_albert_graph( - n, m1, m2, p, seed=None, initial_graph=None, *, create_using=None -): - """Returns a random graph using dual Barabási–Albert preferential attachment - - A graph of $n$ nodes is grown by attaching new nodes each with either $m_1$ - edges (with probability $p$) or $m_2$ edges (with probability $1-p$) that - are preferentially attached to existing nodes with high degree. - - Parameters - ---------- - n : int - Number of nodes - m1 : int - Number of edges to link each new node to existing nodes with probability $p$ - m2 : int - Number of edges to link each new node to existing nodes with probability $1-p$ - p : float - The probability of attaching $m_1$ edges (as opposed to $m_2$ edges) - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - initial_graph : Graph or None (default) - Initial network for Barabási–Albert algorithm. - A copy of `initial_graph` is used. - It should be connected for most use cases. - If None, starts from an star graph on max(m1, m2) + 1 nodes. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m1` and `m2` do not satisfy ``1 <= m1,m2 < n``, or - `p` does not satisfy ``0 <= p <= 1``, or - the initial graph number of nodes m0 does not satisfy m1, m2 <= m0 <= n. - - References - ---------- - .. [1] N. Moshiri "The dual-Barabasi-Albert model", arXiv:1810.10538. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if m1 < 1 or m1 >= n: - raise nx.NetworkXError( - f"Dual Barabási–Albert must have m1 >= 1 and m1 < n, m1 = {m1}, n = {n}" - ) - if m2 < 1 or m2 >= n: - raise nx.NetworkXError( - f"Dual Barabási–Albert must have m2 >= 1 and m2 < n, m2 = {m2}, n = {n}" - ) - if p < 0 or p > 1: - raise nx.NetworkXError( - f"Dual Barabási–Albert network must have 0 <= p <= 1, p = {p}" - ) - - # For simplicity, if p == 0 or 1, just return BA - if p == 1: - return barabasi_albert_graph(n, m1, seed, create_using=create_using) - elif p == 0: - return barabasi_albert_graph(n, m2, seed, create_using=create_using) - - if initial_graph is None: - # Default initial graph : star graph on max(m1, m2) nodes - G = star_graph(max(m1, m2), create_using) - else: - if len(initial_graph) < max(m1, m2) or len(initial_graph) > n: - raise nx.NetworkXError( - f"Barabási–Albert initial graph must have between " - f"max(m1, m2) = {max(m1, m2)} and n = {n} nodes" - ) - G = initial_graph.copy() - - # Target nodes for new edges - targets = list(G) - # List of existing nodes, with nodes repeated once for each adjacent edge - repeated_nodes = [n for n, d in G.degree() for _ in range(d)] - # Start adding the remaining nodes. - source = len(G) - while source < n: - # Pick which m to use (m1 or m2) - if seed.random() < p: - m = m1 - else: - m = m2 - # Now choose m unique nodes from the existing nodes - # Pick uniformly from repeated_nodes (preferential attachment) - targets = _random_subset(repeated_nodes, m, seed) - # Add edges to m nodes from the source. - G.add_edges_from(zip([source] * m, targets)) - # Add one node to the list for each new edge just created. - repeated_nodes.extend(targets) - # And the new node "source" has m edges to add to the list. - repeated_nodes.extend([source] * m) - - source += 1 - return G - - -@py_random_state(4) -@nx._dispatchable(graphs=None, returns_graph=True) -def extended_barabasi_albert_graph(n, m, p, q, seed=None, *, create_using=None): - """Returns an extended Barabási–Albert model graph. - - An extended Barabási–Albert model graph is a random graph constructed - using preferential attachment. The extended model allows new edges, - rewired edges or new nodes. Based on the probabilities $p$ and $q$ - with $p + q < 1$, the growing behavior of the graph is determined as: - - 1) With $p$ probability, $m$ new edges are added to the graph, - starting from randomly chosen existing nodes and attached preferentially at the - other end. - - 2) With $q$ probability, $m$ existing edges are rewired - by randomly choosing an edge and rewiring one end to a preferentially chosen node. - - 3) With $(1 - p - q)$ probability, $m$ new nodes are added to the graph - with edges attached preferentially. - - When $p = q = 0$, the model behaves just like the Barabási–Alber model. - - Parameters - ---------- - n : int - Number of nodes - m : int - Number of edges with which a new node attaches to existing nodes - p : float - Probability value for adding an edge between existing nodes. p + q < 1 - q : float - Probability value of rewiring of existing edges. p + q < 1 - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m < n`` or ``1 >= p + q`` - - References - ---------- - .. [1] Albert, R., & Barabási, A. L. (2000) - Topology of evolving networks: local events and universality - Physical review letters, 85(24), 5234. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if m < 1 or m >= n: - msg = f"Extended Barabasi-Albert network needs m>=1 and m= 1: - msg = f"Extended Barabasi-Albert network needs p + q <= 1, p={p}, q={q}" - raise nx.NetworkXError(msg) - - # Add m initial nodes (m0 in barabasi-speak) - G = empty_graph(m, create_using) - - # List of nodes to represent the preferential attachment random selection. - # At the creation of the graph, all nodes are added to the list - # so that even nodes that are not connected have a chance to get selected, - # for rewiring and adding of edges. - # With each new edge, nodes at the ends of the edge are added to the list. - attachment_preference = [] - attachment_preference.extend(range(m)) - - # Start adding the other n-m nodes. The first node is m. - new_node = m - while new_node < n: - a_probability = seed.random() - - # Total number of edges of a Clique of all the nodes - clique_degree = len(G) - 1 - clique_size = (len(G) * clique_degree) / 2 - - # Adding m new edges, if there is room to add them - if a_probability < p and G.size() <= clique_size - m: - # Select the nodes where an edge can be added - eligible_nodes = [nd for nd, deg in G.degree() if deg < clique_degree] - for i in range(m): - # Choosing a random source node from eligible_nodes - src_node = seed.choice(eligible_nodes) - - # Picking a possible node that is not 'src_node' or - # neighbor with 'src_node', with preferential attachment - prohibited_nodes = list(G[src_node]) - prohibited_nodes.append(src_node) - # This will raise an exception if the sequence is empty - dest_node = seed.choice( - [nd for nd in attachment_preference if nd not in prohibited_nodes] - ) - # Adding the new edge - G.add_edge(src_node, dest_node) - - # Appending both nodes to add to their preferential attachment - attachment_preference.append(src_node) - attachment_preference.append(dest_node) - - # Adjusting the eligible nodes. Degree may be saturated. - if G.degree(src_node) == clique_degree: - eligible_nodes.remove(src_node) - if G.degree(dest_node) == clique_degree and dest_node in eligible_nodes: - eligible_nodes.remove(dest_node) - - # Rewiring m edges, if there are enough edges - elif p <= a_probability < (p + q) and m <= G.size() < clique_size: - # Selecting nodes that have at least 1 edge but that are not - # fully connected to ALL other nodes (center of star). - # These nodes are the pivot nodes of the edges to rewire - eligible_nodes = [nd for nd, deg in G.degree() if 0 < deg < clique_degree] - for i in range(m): - # Choosing a random source node - node = seed.choice(eligible_nodes) - - # The available nodes do have a neighbor at least. - nbr_nodes = list(G[node]) - - # Choosing the other end that will get detached - src_node = seed.choice(nbr_nodes) - - # Picking a target node that is not 'node' or - # neighbor with 'node', with preferential attachment - nbr_nodes.append(node) - dest_node = seed.choice( - [nd for nd in attachment_preference if nd not in nbr_nodes] - ) - # Rewire - G.remove_edge(node, src_node) - G.add_edge(node, dest_node) - - # Adjusting the preferential attachment list - attachment_preference.remove(src_node) - attachment_preference.append(dest_node) - - # Adjusting the eligible nodes. - # nodes may be saturated or isolated. - if G.degree(src_node) == 0 and src_node in eligible_nodes: - eligible_nodes.remove(src_node) - if dest_node in eligible_nodes: - if G.degree(dest_node) == clique_degree: - eligible_nodes.remove(dest_node) - else: - if G.degree(dest_node) == 1: - eligible_nodes.append(dest_node) - - # Adding new node with m edges - else: - # Select the edges' nodes by preferential attachment - targets = _random_subset(attachment_preference, m, seed) - G.add_edges_from(zip([new_node] * m, targets)) - - # Add one node to the list for each new edge just created. - attachment_preference.extend(targets) - # The new node has m edges to it, plus itself: m + 1 - attachment_preference.extend([new_node] * (m + 1)) - new_node += 1 - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def powerlaw_cluster_graph(n, m, p, seed=None, *, create_using=None): - """Holme and Kim algorithm for growing graphs with powerlaw - degree distribution and approximate average clustering. - - Parameters - ---------- - n : int - the number of nodes - m : int - the number of random edges to add for each new node - p : float, - Probability of adding a triangle after adding a random edge - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - The average clustering has a hard time getting above a certain - cutoff that depends on `m`. This cutoff is often quite low. The - transitivity (fraction of triangles to possible triangles) seems to - decrease with network size. - - It is essentially the Barabási–Albert (BA) growth model with an - extra step that each random edge is followed by a chance of - making an edge to one of its neighbors too (and thus a triangle). - - This algorithm improves on BA in the sense that it enables a - higher average clustering to be attained if desired. - - It seems possible to have a disconnected graph with this algorithm - since the initial `m` nodes may not be all linked to a new node - on the first iteration like the BA model. - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m <= n`` or `p` does not - satisfy ``0 <= p <= 1``. - - References - ---------- - .. [1] P. Holme and B. J. Kim, - "Growing scale-free networks with tunable clustering", - Phys. Rev. E, 65, 026107, 2002. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if m < 1 or n < m: - raise nx.NetworkXError(f"NetworkXError must have m>1 and m 1 or p < 0: - raise nx.NetworkXError(f"NetworkXError p must be in [0,1], p={p}") - - G = empty_graph(m, create_using) # add m initial nodes (m0 in barabasi-speak) - repeated_nodes = list(G) # list of existing nodes to sample from - # with nodes repeated once for each adjacent edge - source = m # next node is m - while source < n: # Now add the other n-1 nodes - possible_targets = _random_subset(repeated_nodes, m, seed) - # do one preferential attachment for new node - target = possible_targets.pop() - G.add_edge(source, target) - repeated_nodes.append(target) # add one node to list for each new link - count = 1 - while count < m: # add m-1 more new links - if seed.random() < p: # clustering step: add triangle - neighborhood = [ - nbr - for nbr in G.neighbors(target) - if not G.has_edge(source, nbr) and nbr != source - ] - if neighborhood: # if there is a neighbor without a link - nbr = seed.choice(neighborhood) - G.add_edge(source, nbr) # add triangle - repeated_nodes.append(nbr) - count = count + 1 - continue # go to top of while loop - # else do preferential attachment step if above fails - target = possible_targets.pop() - G.add_edge(source, target) - repeated_nodes.append(target) - count = count + 1 - - repeated_nodes.extend([source] * m) # add source node to list m times - source += 1 - return G - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_lobster(n, p1, p2, seed=None, *, create_using=None): - """Returns a random lobster graph. - - A lobster is a tree that reduces to a caterpillar when pruning all - leaf nodes. A caterpillar is a tree that reduces to a path graph - when pruning all leaf nodes; setting `p2` to zero produces a caterpillar. - - This implementation iterates on the probabilities `p1` and `p2` to add - edges at levels 1 and 2, respectively. Graphs are therefore constructed - iteratively with uniform randomness at each level rather than being selected - uniformly at random from the set of all possible lobsters. - - Parameters - ---------- - n : int - The expected number of nodes in the backbone - p1 : float - Probability of adding an edge to the backbone - p2 : float - Probability of adding an edge one level beyond backbone - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Grap) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Raises - ------ - NetworkXError - If `p1` or `p2` parameters are >= 1 because the while loops would never finish. - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - p1, p2 = abs(p1), abs(p2) - if any(p >= 1 for p in [p1, p2]): - raise nx.NetworkXError("Probability values for `p1` and `p2` must both be < 1.") - - # a necessary ingredient in any self-respecting graph library - llen = int(2 * seed.random() * n + 0.5) - L = path_graph(llen, create_using) - # build caterpillar: add edges to path graph with probability p1 - current_node = llen - 1 - for n in range(llen): - while seed.random() < p1: # add fuzzy caterpillar parts - current_node += 1 - L.add_edge(n, current_node) - cat_node = current_node - while seed.random() < p2: # add crunchy lobster bits - current_node += 1 - L.add_edge(cat_node, current_node) - return L # voila, un lobster! - - -@py_random_state(1) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_shell_graph(constructor, seed=None, *, create_using=None): - """Returns a random shell graph for the constructor given. - - Parameters - ---------- - constructor : list of three-tuples - Represents the parameters for a shell, starting at the center - shell. Each element of the list must be of the form `(n, m, - d)`, where `n` is the number of nodes in the shell, `m` is - the number of edges in the shell, and `d` is the ratio of - inter-shell (next) edges to intra-shell edges. If `d` is zero, - there will be no intra-shell edges, and if `d` is one there - will be all possible intra-shell edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. Graph instances are not supported. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Examples - -------- - >>> constructor = [(10, 20, 0.8), (20, 40, 0.8)] - >>> G = nx.random_shell_graph(constructor) - - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - G = empty_graph(0, create_using) - - glist = [] - intra_edges = [] - nnodes = 0 - # create gnm graphs for each shell - for n, m, d in constructor: - inter_edges = int(m * d) - intra_edges.append(m - inter_edges) - g = nx.convert_node_labels_to_integers( - gnm_random_graph(n, inter_edges, seed=seed, create_using=G.__class__), - first_label=nnodes, - ) - glist.append(g) - nnodes += n - G = nx.operators.union(G, g) - - # connect the shells randomly - for gi in range(len(glist) - 1): - nlist1 = list(glist[gi]) - nlist2 = list(glist[gi + 1]) - total_edges = intra_edges[gi] - edge_count = 0 - while edge_count < total_edges: - u = seed.choice(nlist1) - v = seed.choice(nlist2) - if u == v or G.has_edge(u, v): - continue - else: - G.add_edge(u, v) - edge_count = edge_count + 1 - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_powerlaw_tree(n, gamma=3, seed=None, tries=100, *, create_using=None): - """Returns a tree with a power law degree distribution. - - Parameters - ---------- - n : int - The number of nodes. - gamma : float - Exponent of the power law. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int - Number of attempts to adjust the sequence to make it a tree. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Raises - ------ - NetworkXError - If no valid sequence is found within the maximum number of - attempts. - - Notes - ----- - A trial power law degree sequence is chosen and then elements are - swapped with new elements from a powerlaw distribution until the - sequence makes a tree (by checking, for example, that the number of - edges is one smaller than the number of nodes). - - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - # This call may raise a NetworkXError if the number of tries is succeeded. - seq = random_powerlaw_tree_sequence(n, gamma=gamma, seed=seed, tries=tries) - G = degree_sequence_tree(seq, create_using) - return G - - -@py_random_state(2) -@nx._dispatchable(graphs=None) -def random_powerlaw_tree_sequence(n, gamma=3, seed=None, tries=100): - """Returns a degree sequence for a tree with a power law distribution. - - Parameters - ---------- - n : int, - The number of nodes. - gamma : float - Exponent of the power law. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int - Number of attempts to adjust the sequence to make it a tree. - - Raises - ------ - NetworkXError - If no valid sequence is found within the maximum number of - attempts. - - Notes - ----- - A trial power law degree sequence is chosen and then elements are - swapped with new elements from a power law distribution until - the sequence makes a tree (by checking, for example, that the number of - edges is one smaller than the number of nodes). - - """ - # get trial sequence - z = nx.utils.powerlaw_sequence(n, exponent=gamma, seed=seed) - # round to integer values in the range [0,n] - zseq = [min(n, max(round(s), 0)) for s in z] - - # another sequence to swap values from - z = nx.utils.powerlaw_sequence(tries, exponent=gamma, seed=seed) - # round to integer values in the range [0,n] - swap = [min(n, max(round(s), 0)) for s in z] - - for deg in swap: - # If this degree sequence can be the degree sequence of a tree, return - # it. It can be a tree if the number of edges is one fewer than the - # number of nodes, or in other words, `n - sum(zseq) / 2 == 1`. We - # use an equivalent condition below that avoids floating point - # operations. - if 2 * n - sum(zseq) == 2: - return zseq - index = seed.randint(0, n - 1) - zseq[index] = swap.pop() - - raise nx.NetworkXError( - f"Exceeded max ({tries}) attempts for a valid tree sequence." - ) - - -@py_random_state(3) -@nx._dispatchable(graphs=None, returns_graph=True) -def random_kernel_graph( - n, kernel_integral, kernel_root=None, seed=None, *, create_using=None -): - r"""Returns an random graph based on the specified kernel. - - The algorithm chooses each of the $[n(n-1)]/2$ possible edges with - probability specified by a kernel $\kappa(x,y)$ [1]_. The kernel - $\kappa(x,y)$ must be a symmetric (in $x,y$), non-negative, - bounded function. - - Parameters - ---------- - n : int - The number of nodes - kernel_integral : function - Function that returns the definite integral of the kernel $\kappa(x,y)$, - $F(y,a,b) := \int_a^b \kappa(x,y)dx$ - kernel_root: function (optional) - Function that returns the root $b$ of the equation $F(y,a,b) = r$. - If None, the root is found using :func:`scipy.optimize.brentq` - (this requires SciPy). - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - create_using : Graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Multigraph and directed types are not supported and raise a ``NetworkXError``. - - Notes - ----- - The kernel is specified through its definite integral which must be - provided as one of the arguments. If the integral and root of the - kernel integral can be found in $O(1)$ time then this algorithm runs in - time $O(n+m)$ where m is the expected number of edges [2]_. - - The nodes are set to integers from $0$ to $n-1$. - - Examples - -------- - Generate an ErdÅ‘s–Rényi random graph $G(n,c/n)$, with kernel - $\kappa(x,y)=c$ where $c$ is the mean expected degree. - - >>> def integral(u, w, z): - ... return c * (z - w) - >>> def root(u, w, r): - ... return r / c + w - >>> c = 1 - >>> graph = nx.random_kernel_graph(1000, integral, root) - - See Also - -------- - gnp_random_graph - expected_degree_graph - - References - ---------- - .. [1] Bollobás, Béla, Janson, S. and Riordan, O. - "The phase transition in inhomogeneous random graphs", - *Random Structures Algorithms*, 31, 3--122, 2007. - - .. [2] Hagberg A, Lemons N (2015), - "Fast Generation of Sparse Random Kernel Graphs". - PLoS ONE 10(9): e0135177, 2015. doi:10.1371/journal.pone.0135177 - """ - create_using = check_create_using(create_using, directed=False, multigraph=False) - if kernel_root is None: - import scipy as sp - - def kernel_root(y, a, r): - def my_function(b): - return kernel_integral(y, a, b) - r - - return sp.optimize.brentq(my_function, a, 1) - - graph = nx.empty_graph(create_using=create_using) - graph.add_nodes_from(range(n)) - (i, j) = (1, 1) - while i < n: - r = -math.log(1 - seed.random()) # (1-seed.random()) in (0, 1] - if kernel_integral(i / n, j / n, 1) <= r: - i, j = i + 1, i + 1 - else: - j = math.ceil(n * kernel_root(i / n, j / n, r)) - graph.add_edge(i - 1, j - 1) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/small.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/small.py deleted file mode 100644 index acd2fbc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/small.py +++ /dev/null @@ -1,993 +0,0 @@ -""" -Various small and named graphs, together with some compact generators. - -""" - -__all__ = [ - "LCF_graph", - "bull_graph", - "chvatal_graph", - "cubical_graph", - "desargues_graph", - "diamond_graph", - "dodecahedral_graph", - "frucht_graph", - "heawood_graph", - "hoffman_singleton_graph", - "house_graph", - "house_x_graph", - "icosahedral_graph", - "krackhardt_kite_graph", - "moebius_kantor_graph", - "octahedral_graph", - "pappus_graph", - "petersen_graph", - "sedgewick_maze_graph", - "tetrahedral_graph", - "truncated_cube_graph", - "truncated_tetrahedron_graph", - "tutte_graph", -] - -from functools import wraps - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.generators.classic import ( - complete_graph, - cycle_graph, - empty_graph, - path_graph, -) - - -def _raise_on_directed(func): - """ - A decorator which inspects the `create_using` argument and raises a - NetworkX exception when `create_using` is a DiGraph (class or instance) for - graph generators that do not support directed outputs. - """ - - @wraps(func) - def wrapper(*args, **kwargs): - if kwargs.get("create_using") is not None: - G = nx.empty_graph(create_using=kwargs["create_using"]) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - return func(*args, **kwargs) - - return wrapper - - -@nx._dispatchable(graphs=None, returns_graph=True) -def LCF_graph(n, shift_list, repeats, create_using=None): - """ - Return the cubic graph specified in LCF notation. - - LCF (Lederberg-Coxeter-Fruchte) notation[1]_ is a compressed - notation used in the generation of various cubic Hamiltonian - graphs of high symmetry. See, for example, `dodecahedral_graph`, - `desargues_graph`, `heawood_graph` and `pappus_graph`. - - Nodes are drawn from ``range(n)``. Each node ``n_i`` is connected with - node ``n_i + shift % n`` where ``shift`` is given by cycling through - the input `shift_list` `repeat` s times. - - Parameters - ---------- - n : int - The starting graph is the `n`-cycle with nodes ``0, ..., n-1``. - The null graph is returned if `n` < 1. - - shift_list : list - A list of integer shifts mod `n`, ``[s1, s2, .., sk]`` - - repeats : int - Integer specifying the number of times that shifts in `shift_list` - are successively applied to each current node in the n-cycle - to generate an edge between ``n_current`` and ``n_current + shift mod n``. - - Returns - ------- - G : Graph - A graph instance created from the specified LCF notation. - - Examples - -------- - The utility graph $K_{3,3}$ - - >>> G = nx.LCF_graph(6, [3, -3], 3) - >>> G.edges() - EdgeView([(0, 1), (0, 5), (0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4), (4, 5)]) - - The Heawood graph: - - >>> G = nx.LCF_graph(14, [5, -5], 7) - >>> nx.is_isomorphic(G, nx.heawood_graph()) - True - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/LCF_notation - - """ - if n <= 0: - return empty_graph(0, create_using) - - # start with the n-cycle - G = cycle_graph(n, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - G.name = "LCF_graph" - nodes = sorted(G) - - n_extra_edges = repeats * len(shift_list) - # edges are added n_extra_edges times - # (not all of these need be new) - if n_extra_edges < 1: - return G - - for i in range(n_extra_edges): - shift = shift_list[i % len(shift_list)] # cycle through shift_list - v1 = nodes[i % n] # cycle repeatedly through nodes - v2 = nodes[(i + shift) % n] - G.add_edge(v1, v2) - return G - - -# ------------------------------------------------------------------------------- -# Various small and named graphs -# ------------------------------------------------------------------------------- - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def bull_graph(create_using=None): - """ - Returns the Bull Graph - - The Bull Graph has 5 nodes and 5 edges. It is a planar undirected - graph in the form of a triangle with two disjoint pendant edges [1]_ - The name comes from the triangle and pendant edges representing - respectively the body and legs of a bull. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - A bull graph with 5 nodes - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Bull_graph. - - """ - G = nx.from_dict_of_lists( - {0: [1, 2], 1: [0, 2, 3], 2: [0, 1, 4], 3: [1], 4: [2]}, - create_using=create_using, - ) - G.name = "Bull Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def chvatal_graph(create_using=None): - """ - Returns the Chvátal Graph - - The Chvátal Graph is an undirected graph with 12 nodes and 24 edges [1]_. - It has 370 distinct (directed) Hamiltonian cycles, giving a unique generalized - LCF notation of order 4, two of order 6 , and 43 of order 1 [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - The Chvátal graph with 12 nodes and 24 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Chv%C3%A1tal_graph - .. [2] https://mathworld.wolfram.com/ChvatalGraph.html - - """ - G = nx.from_dict_of_lists( - { - 0: [1, 4, 6, 9], - 1: [2, 5, 7], - 2: [3, 6, 8], - 3: [4, 7, 9], - 4: [5, 8], - 5: [10, 11], - 6: [10, 11], - 7: [8, 11], - 8: [10], - 9: [10, 11], - }, - create_using=create_using, - ) - G.name = "Chvatal Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def cubical_graph(create_using=None): - """ - Returns the 3-regular Platonic Cubical Graph - - The skeleton of the cube (the nodes and edges) form a graph, with 8 - nodes, and 12 edges. It is a special case of the hypercube graph. - It is one of 5 Platonic graphs, each a skeleton of its - Platonic solid [1]_. - Such graphs arise in parallel processing in computers. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - A cubical graph with 8 nodes and 12 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Cube#Cubical_graph - - """ - G = nx.from_dict_of_lists( - { - 0: [1, 3, 4], - 1: [0, 2, 7], - 2: [1, 3, 6], - 3: [0, 2, 5], - 4: [0, 5, 7], - 5: [3, 4, 6], - 6: [2, 5, 7], - 7: [1, 4, 6], - }, - create_using=create_using, - ) - G.name = "Platonic Cubical Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def desargues_graph(create_using=None): - """ - Returns the Desargues Graph - - The Desargues Graph is a non-planar, distance-transitive cubic graph - with 20 nodes and 30 edges [1]_. - It is a symmetric graph. It can be represented in LCF notation - as [5,-5,9,-9]^5 [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Desargues Graph with 20 nodes and 30 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Desargues_graph - .. [2] https://mathworld.wolfram.com/DesarguesGraph.html - """ - G = LCF_graph(20, [5, -5, 9, -9], 5, create_using) - G.name = "Desargues Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def diamond_graph(create_using=None): - """ - Returns the Diamond graph - - The Diamond Graph is planar undirected graph with 4 nodes and 5 edges. - It is also sometimes known as the double triangle graph or kite graph [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Diamond Graph with 4 nodes and 5 edges - - References - ---------- - .. [1] https://mathworld.wolfram.com/DiamondGraph.html - """ - G = nx.from_dict_of_lists( - {0: [1, 2], 1: [0, 2, 3], 2: [0, 1, 3], 3: [1, 2]}, create_using=create_using - ) - G.name = "Diamond Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def dodecahedral_graph(create_using=None): - """ - Returns the Platonic Dodecahedral graph. - - The dodecahedral graph has 20 nodes and 30 edges. The skeleton of the - dodecahedron forms a graph. It is one of 5 Platonic graphs [1]_. - It can be described in LCF notation as: - ``[10, 7, 4, -4, -7, 10, -4, 7, -7, 4]^2`` [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Dodecahedral Graph with 20 nodes and 30 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Regular_dodecahedron#Dodecahedral_graph - .. [2] https://mathworld.wolfram.com/DodecahedralGraph.html - - """ - G = LCF_graph(20, [10, 7, 4, -4, -7, 10, -4, 7, -7, 4], 2, create_using) - G.name = "Dodecahedral Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def frucht_graph(create_using=None): - """ - Returns the Frucht Graph. - - The Frucht Graph is the smallest cubical graph whose - automorphism group consists only of the identity element [1]_. - It has 12 nodes and 18 edges and no nontrivial symmetries. - It is planar and Hamiltonian [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Frucht Graph with 12 nodes and 18 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Frucht_graph - .. [2] https://mathworld.wolfram.com/FruchtGraph.html - - """ - G = cycle_graph(7, create_using) - G.add_edges_from( - [ - [0, 7], - [1, 7], - [2, 8], - [3, 9], - [4, 9], - [5, 10], - [6, 10], - [7, 11], - [8, 11], - [8, 9], - [10, 11], - ] - ) - - G.name = "Frucht Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def heawood_graph(create_using=None): - """ - Returns the Heawood Graph, a (3,6) cage. - - The Heawood Graph is an undirected graph with 14 nodes and 21 edges, - named after Percy John Heawood [1]_. - It is cubic symmetric, nonplanar, Hamiltonian, and can be represented - in LCF notation as ``[5,-5]^7`` [2]_. - It is the unique (3,6)-cage: the regular cubic graph of girth 6 with - minimal number of vertices [3]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Heawood Graph with 14 nodes and 21 edges - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Heawood_graph - .. [2] https://mathworld.wolfram.com/HeawoodGraph.html - .. [3] https://www.win.tue.nl/~aeb/graphs/Heawood.html - - """ - G = LCF_graph(14, [5, -5], 7, create_using) - G.name = "Heawood Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def hoffman_singleton_graph(): - """ - Returns the Hoffman-Singleton Graph. - - The Hoffman–Singleton graph is a symmetrical undirected graph - with 50 nodes and 175 edges. - All indices lie in ``Z % 5``: that is, the integers mod 5 [1]_. - It is the only regular graph of vertex degree 7, diameter 2, and girth 5. - It is the unique (7,5)-cage graph and Moore graph, and contains many - copies of the Petersen graph [2]_. - - Returns - ------- - G : networkx Graph - Hoffman–Singleton Graph with 50 nodes and 175 edges - - Notes - ----- - Constructed from pentagon and pentagram as follows: Take five pentagons $P_h$ - and five pentagrams $Q_i$ . Join vertex $j$ of $P_h$ to vertex $h·i+j$ of $Q_i$ [3]_. - - References - ---------- - .. [1] https://blogs.ams.org/visualinsight/2016/02/01/hoffman-singleton-graph/ - .. [2] https://mathworld.wolfram.com/Hoffman-SingletonGraph.html - .. [3] https://en.wikipedia.org/wiki/Hoffman%E2%80%93Singleton_graph - - """ - G = nx.Graph() - for i in range(5): - for j in range(5): - G.add_edge(("pentagon", i, j), ("pentagon", i, (j - 1) % 5)) - G.add_edge(("pentagon", i, j), ("pentagon", i, (j + 1) % 5)) - G.add_edge(("pentagram", i, j), ("pentagram", i, (j - 2) % 5)) - G.add_edge(("pentagram", i, j), ("pentagram", i, (j + 2) % 5)) - for k in range(5): - G.add_edge(("pentagon", i, j), ("pentagram", k, (i * k + j) % 5)) - G = nx.convert_node_labels_to_integers(G) - G.name = "Hoffman-Singleton Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def house_graph(create_using=None): - """ - Returns the House graph (square with triangle on top) - - The house graph is a simple undirected graph with - 5 nodes and 6 edges [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - House graph in the form of a square with a triangle on top - - References - ---------- - .. [1] https://mathworld.wolfram.com/HouseGraph.html - """ - G = nx.from_dict_of_lists( - {0: [1, 2], 1: [0, 3], 2: [0, 3, 4], 3: [1, 2, 4], 4: [2, 3]}, - create_using=create_using, - ) - G.name = "House Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def house_x_graph(create_using=None): - """ - Returns the House graph with a cross inside the house square. - - The House X-graph is the House graph plus the two edges connecting diagonally - opposite vertices of the square base. It is also one of the two graphs - obtained by removing two edges from the pentatope graph [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - House graph with diagonal vertices connected - - References - ---------- - .. [1] https://mathworld.wolfram.com/HouseGraph.html - """ - G = house_graph(create_using) - G.add_edges_from([(0, 3), (1, 2)]) - G.name = "House-with-X-inside Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def icosahedral_graph(create_using=None): - """ - Returns the Platonic Icosahedral graph. - - The icosahedral graph has 12 nodes and 30 edges. It is a Platonic graph - whose nodes have the connectivity of the icosahedron. It is undirected, - regular and Hamiltonian [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Icosahedral graph with 12 nodes and 30 edges. - - References - ---------- - .. [1] https://mathworld.wolfram.com/IcosahedralGraph.html - """ - G = nx.from_dict_of_lists( - { - 0: [1, 5, 7, 8, 11], - 1: [2, 5, 6, 8], - 2: [3, 6, 8, 9], - 3: [4, 6, 9, 10], - 4: [5, 6, 10, 11], - 5: [6, 11], - 7: [8, 9, 10, 11], - 8: [9], - 9: [10], - 10: [11], - }, - create_using=create_using, - ) - G.name = "Platonic Icosahedral Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def krackhardt_kite_graph(create_using=None): - """ - Returns the Krackhardt Kite Social Network. - - A 10 actor social network introduced by David Krackhardt - to illustrate different centrality measures [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Krackhardt Kite graph with 10 nodes and 18 edges - - Notes - ----- - The traditional labeling is: - Andre=1, Beverley=2, Carol=3, Diane=4, - Ed=5, Fernando=6, Garth=7, Heather=8, Ike=9, Jane=10. - - References - ---------- - .. [1] Krackhardt, David. "Assessing the Political Landscape: Structure, - Cognition, and Power in Organizations". Administrative Science Quarterly. - 35 (2): 342–369. doi:10.2307/2393394. JSTOR 2393394. June 1990. - - """ - G = nx.from_dict_of_lists( - { - 0: [1, 2, 3, 5], - 1: [0, 3, 4, 6], - 2: [0, 3, 5], - 3: [0, 1, 2, 4, 5, 6], - 4: [1, 3, 6], - 5: [0, 2, 3, 6, 7], - 6: [1, 3, 4, 5, 7], - 7: [5, 6, 8], - 8: [7, 9], - 9: [8], - }, - create_using=create_using, - ) - G.name = "Krackhardt Kite Social Network" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def moebius_kantor_graph(create_using=None): - """ - Returns the Moebius-Kantor graph. - - The Möbius-Kantor graph is the cubic symmetric graph on 16 nodes. - Its LCF notation is [5,-5]^8, and it is isomorphic to the generalized - Petersen graph [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Moebius-Kantor graph - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius%E2%80%93Kantor_graph - - """ - G = LCF_graph(16, [5, -5], 8, create_using) - G.name = "Moebius-Kantor Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def octahedral_graph(create_using=None): - """ - Returns the Platonic Octahedral graph. - - The octahedral graph is the 6-node 12-edge Platonic graph having the - connectivity of the octahedron [1]_. If 6 couples go to a party, - and each person shakes hands with every person except his or her partner, - then this graph describes the set of handshakes that take place; - for this reason it is also called the cocktail party graph [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Octahedral graph - - References - ---------- - .. [1] https://mathworld.wolfram.com/OctahedralGraph.html - .. [2] https://en.wikipedia.org/wiki/Tur%C3%A1n_graph#Special_cases - - """ - G = nx.from_dict_of_lists( - {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]}, - create_using=create_using, - ) - G.name = "Platonic Octahedral Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def pappus_graph(): - """ - Returns the Pappus graph. - - The Pappus graph is a cubic symmetric distance-regular graph with 18 nodes - and 27 edges. It is Hamiltonian and can be represented in LCF notation as - [5,7,-7,7,-7,-5]^3 [1]_. - - Returns - ------- - G : networkx Graph - Pappus graph - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Pappus_graph - """ - G = LCF_graph(18, [5, 7, -7, 7, -7, -5], 3) - G.name = "Pappus Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def petersen_graph(create_using=None): - """ - Returns the Petersen graph. - - The Peterson graph is a cubic, undirected graph with 10 nodes and 15 edges [1]_. - Julius Petersen constructed the graph as the smallest counterexample - against the claim that a connected bridgeless cubic graph - has an edge colouring with three colours [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Petersen graph - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Petersen_graph - .. [2] https://www.win.tue.nl/~aeb/drg/graphs/Petersen.html - """ - G = nx.from_dict_of_lists( - { - 0: [1, 4, 5], - 1: [0, 2, 6], - 2: [1, 3, 7], - 3: [2, 4, 8], - 4: [3, 0, 9], - 5: [0, 7, 8], - 6: [1, 8, 9], - 7: [2, 5, 9], - 8: [3, 5, 6], - 9: [4, 6, 7], - }, - create_using=create_using, - ) - G.name = "Petersen Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def sedgewick_maze_graph(create_using=None): - """ - Return a small maze with a cycle. - - This is the maze used in Sedgewick, 3rd Edition, Part 5, Graph - Algorithms, Chapter 18, e.g. Figure 18.2 and following [1]_. - Nodes are numbered 0,..,7 - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Small maze with a cycle - - References - ---------- - .. [1] Figure 18.2, Chapter 18, Graph Algorithms (3rd Ed), Sedgewick - """ - G = empty_graph(0, create_using) - G.add_nodes_from(range(8)) - G.add_edges_from([[0, 2], [0, 7], [0, 5]]) - G.add_edges_from([[1, 7], [2, 6]]) - G.add_edges_from([[3, 4], [3, 5]]) - G.add_edges_from([[4, 5], [4, 7], [4, 6]]) - G.name = "Sedgewick Maze" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def tetrahedral_graph(create_using=None): - """ - Returns the 3-regular Platonic Tetrahedral graph. - - Tetrahedral graph has 4 nodes and 6 edges. It is a - special case of the complete graph, K4, and wheel graph, W4. - It is one of the 5 platonic graphs [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Tetrahedral Graph - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Tetrahedron#Tetrahedral_graph - - """ - G = complete_graph(4, create_using) - G.name = "Platonic Tetrahedral Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def truncated_cube_graph(create_using=None): - """ - Returns the skeleton of the truncated cube. - - The truncated cube is an Archimedean solid with 14 regular - faces (6 octagonal and 8 triangular), 36 edges and 24 nodes [1]_. - The truncated cube is created by truncating (cutting off) the tips - of the cube one third of the way into each edge [2]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Skeleton of the truncated cube - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Truncated_cube - .. [2] https://www.coolmath.com/reference/polyhedra-truncated-cube - - """ - G = nx.from_dict_of_lists( - { - 0: [1, 2, 4], - 1: [11, 14], - 2: [3, 4], - 3: [6, 8], - 4: [5], - 5: [16, 18], - 6: [7, 8], - 7: [10, 12], - 8: [9], - 9: [17, 20], - 10: [11, 12], - 11: [14], - 12: [13], - 13: [21, 22], - 14: [15], - 15: [19, 23], - 16: [17, 18], - 17: [20], - 18: [19], - 19: [23], - 20: [21], - 21: [22], - 22: [23], - }, - create_using=create_using, - ) - G.name = "Truncated Cube Graph" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def truncated_tetrahedron_graph(create_using=None): - """ - Returns the skeleton of the truncated Platonic tetrahedron. - - The truncated tetrahedron is an Archimedean solid with 4 regular hexagonal faces, - 4 equilateral triangle faces, 12 nodes and 18 edges. It can be constructed by truncating - all 4 vertices of a regular tetrahedron at one third of the original edge length [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Skeleton of the truncated tetrahedron - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Truncated_tetrahedron - - """ - G = path_graph(12, create_using) - G.add_edges_from([(0, 2), (0, 9), (1, 6), (3, 11), (4, 11), (5, 7), (8, 10)]) - G.name = "Truncated Tetrahedron Graph" - return G - - -@_raise_on_directed -@nx._dispatchable(graphs=None, returns_graph=True) -def tutte_graph(create_using=None): - """ - Returns the Tutte graph. - - The Tutte graph is a cubic polyhedral, non-Hamiltonian graph. It has - 46 nodes and 69 edges. - It is a counterexample to Tait's conjecture that every 3-regular polyhedron - has a Hamiltonian cycle. - It can be realized geometrically from a tetrahedron by multiply truncating - three of its vertices [1]_. - - Parameters - ---------- - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - Tutte graph - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Tutte_graph - """ - G = nx.from_dict_of_lists( - { - 0: [1, 2, 3], - 1: [4, 26], - 2: [10, 11], - 3: [18, 19], - 4: [5, 33], - 5: [6, 29], - 6: [7, 27], - 7: [8, 14], - 8: [9, 38], - 9: [10, 37], - 10: [39], - 11: [12, 39], - 12: [13, 35], - 13: [14, 15], - 14: [34], - 15: [16, 22], - 16: [17, 44], - 17: [18, 43], - 18: [45], - 19: [20, 45], - 20: [21, 41], - 21: [22, 23], - 22: [40], - 23: [24, 27], - 24: [25, 32], - 25: [26, 31], - 26: [33], - 27: [28], - 28: [29, 32], - 29: [30], - 30: [31, 33], - 31: [32], - 34: [35, 38], - 35: [36], - 36: [37, 39], - 37: [38], - 40: [41, 44], - 41: [42], - 42: [43, 45], - 43: [44], - }, - create_using=create_using, - ) - G.name = "Tutte's Graph" - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/social.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/social.py deleted file mode 100644 index f41b2d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/social.py +++ /dev/null @@ -1,554 +0,0 @@ -""" -Famous social networks. -""" - -import networkx as nx - -__all__ = [ - "karate_club_graph", - "davis_southern_women_graph", - "florentine_families_graph", - "les_miserables_graph", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def karate_club_graph(): - """Returns Zachary's Karate Club graph. - - Each node in the returned graph has a node attribute 'club' that - indicates the name of the club to which the member represented by that node - belongs, either 'Mr. Hi' or 'Officer'. Each edge has a weight based on the - number of contexts in which that edge's incident node members interacted. - - The dataset is derived from the 'Club After Split From Data' column of Table 3 in [1]_. - This was in turn derived from the 'Club After Fission' column of Table 1 in the - same paper. Note that the nodes are 0-indexed in NetworkX, but 1-indexed in the - paper (the 'Individual Number in Matrix C' column of Table 3 starts at 1). This - means, for example, that ``G.nodes[9]["club"]`` returns 'Officer', which - corresponds to row 10 of Table 3 in the paper. - - Examples - -------- - To get the name of the club to which a node belongs:: - - >>> G = nx.karate_club_graph() - >>> G.nodes[5]["club"] - 'Mr. Hi' - >>> G.nodes[9]["club"] - 'Officer' - - References - ---------- - .. [1] Zachary, Wayne W. - "An Information Flow Model for Conflict and Fission in Small Groups." - *Journal of Anthropological Research*, 33, 452--473, (1977). - """ - # Create the set of all members, and the members of each club. - all_members = set(range(34)) - club1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 16, 17, 19, 21} - # club2 = all_members - club1 - - G = nx.Graph() - G.add_nodes_from(all_members) - G.name = "Zachary's Karate Club" - - zacharydat = """\ -0 4 5 3 3 3 3 2 2 0 2 3 2 3 0 0 0 2 0 2 0 2 0 0 0 0 0 0 0 0 0 2 0 0 -4 0 6 3 0 0 0 4 0 0 0 0 0 5 0 0 0 1 0 2 0 2 0 0 0 0 0 0 0 0 2 0 0 0 -5 6 0 3 0 0 0 4 5 1 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 3 0 -3 3 3 0 0 0 0 3 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 0 0 2 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 0 0 5 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 2 5 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 4 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 4 3 -0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -2 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -3 5 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 -0 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 -2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 4 0 2 0 0 5 4 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 0 0 0 2 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 2 0 0 0 0 0 0 7 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 2 -0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 3 0 0 0 0 0 0 0 0 4 -0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 4 0 0 0 0 0 3 2 -0 2 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 -2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 7 0 0 2 0 0 0 4 4 -0 0 2 0 0 0 0 0 3 0 0 0 0 0 3 3 0 0 1 0 3 0 2 5 0 0 0 0 0 4 3 4 0 5 -0 0 0 0 0 0 0 0 4 2 0 0 0 3 2 4 0 0 2 1 1 0 3 4 0 0 2 4 2 2 3 4 5 0""" - - for row, line in enumerate(zacharydat.split("\n")): - thisrow = [int(b) for b in line.split()] - for col, entry in enumerate(thisrow): - if entry >= 1: - G.add_edge(row, col, weight=entry) - - # Add the name of each member's club as a node attribute. - for v in G: - G.nodes[v]["club"] = "Mr. Hi" if v in club1 else "Officer" - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def davis_southern_women_graph(): - """Returns Davis Southern women social network. - - This is a bipartite graph. - - References - ---------- - .. [1] A. Davis, Gardner, B. B., Gardner, M. R., 1941. Deep South. - University of Chicago Press, Chicago, IL. - """ - G = nx.Graph() - # Top nodes - women = [ - "Evelyn Jefferson", - "Laura Mandeville", - "Theresa Anderson", - "Brenda Rogers", - "Charlotte McDowd", - "Frances Anderson", - "Eleanor Nye", - "Pearl Oglethorpe", - "Ruth DeSand", - "Verne Sanderson", - "Myra Liddel", - "Katherina Rogers", - "Sylvia Avondale", - "Nora Fayette", - "Helen Lloyd", - "Dorothy Murchison", - "Olivia Carleton", - "Flora Price", - ] - G.add_nodes_from(women, bipartite=0) - # Bottom nodes - events = [ - "E1", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "E10", - "E11", - "E12", - "E13", - "E14", - ] - G.add_nodes_from(events, bipartite=1) - - G.add_edges_from( - [ - ("Evelyn Jefferson", "E1"), - ("Evelyn Jefferson", "E2"), - ("Evelyn Jefferson", "E3"), - ("Evelyn Jefferson", "E4"), - ("Evelyn Jefferson", "E5"), - ("Evelyn Jefferson", "E6"), - ("Evelyn Jefferson", "E8"), - ("Evelyn Jefferson", "E9"), - ("Laura Mandeville", "E1"), - ("Laura Mandeville", "E2"), - ("Laura Mandeville", "E3"), - ("Laura Mandeville", "E5"), - ("Laura Mandeville", "E6"), - ("Laura Mandeville", "E7"), - ("Laura Mandeville", "E8"), - ("Theresa Anderson", "E2"), - ("Theresa Anderson", "E3"), - ("Theresa Anderson", "E4"), - ("Theresa Anderson", "E5"), - ("Theresa Anderson", "E6"), - ("Theresa Anderson", "E7"), - ("Theresa Anderson", "E8"), - ("Theresa Anderson", "E9"), - ("Brenda Rogers", "E1"), - ("Brenda Rogers", "E3"), - ("Brenda Rogers", "E4"), - ("Brenda Rogers", "E5"), - ("Brenda Rogers", "E6"), - ("Brenda Rogers", "E7"), - ("Brenda Rogers", "E8"), - ("Charlotte McDowd", "E3"), - ("Charlotte McDowd", "E4"), - ("Charlotte McDowd", "E5"), - ("Charlotte McDowd", "E7"), - ("Frances Anderson", "E3"), - ("Frances Anderson", "E5"), - ("Frances Anderson", "E6"), - ("Frances Anderson", "E8"), - ("Eleanor Nye", "E5"), - ("Eleanor Nye", "E6"), - ("Eleanor Nye", "E7"), - ("Eleanor Nye", "E8"), - ("Pearl Oglethorpe", "E6"), - ("Pearl Oglethorpe", "E8"), - ("Pearl Oglethorpe", "E9"), - ("Ruth DeSand", "E5"), - ("Ruth DeSand", "E7"), - ("Ruth DeSand", "E8"), - ("Ruth DeSand", "E9"), - ("Verne Sanderson", "E7"), - ("Verne Sanderson", "E8"), - ("Verne Sanderson", "E9"), - ("Verne Sanderson", "E12"), - ("Myra Liddel", "E8"), - ("Myra Liddel", "E9"), - ("Myra Liddel", "E10"), - ("Myra Liddel", "E12"), - ("Katherina Rogers", "E8"), - ("Katherina Rogers", "E9"), - ("Katherina Rogers", "E10"), - ("Katherina Rogers", "E12"), - ("Katherina Rogers", "E13"), - ("Katherina Rogers", "E14"), - ("Sylvia Avondale", "E7"), - ("Sylvia Avondale", "E8"), - ("Sylvia Avondale", "E9"), - ("Sylvia Avondale", "E10"), - ("Sylvia Avondale", "E12"), - ("Sylvia Avondale", "E13"), - ("Sylvia Avondale", "E14"), - ("Nora Fayette", "E6"), - ("Nora Fayette", "E7"), - ("Nora Fayette", "E9"), - ("Nora Fayette", "E10"), - ("Nora Fayette", "E11"), - ("Nora Fayette", "E12"), - ("Nora Fayette", "E13"), - ("Nora Fayette", "E14"), - ("Helen Lloyd", "E7"), - ("Helen Lloyd", "E8"), - ("Helen Lloyd", "E10"), - ("Helen Lloyd", "E11"), - ("Helen Lloyd", "E12"), - ("Dorothy Murchison", "E8"), - ("Dorothy Murchison", "E9"), - ("Olivia Carleton", "E9"), - ("Olivia Carleton", "E11"), - ("Flora Price", "E9"), - ("Flora Price", "E11"), - ] - ) - G.graph["top"] = women - G.graph["bottom"] = events - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def florentine_families_graph(): - """Returns Florentine families graph. - - References - ---------- - .. [1] Ronald L. Breiger and Philippa E. Pattison - Cumulated social roles: The duality of persons and their algebras,1 - Social Networks, Volume 8, Issue 3, September 1986, Pages 215-256 - """ - G = nx.Graph() - G.add_edge("Acciaiuoli", "Medici") - G.add_edge("Castellani", "Peruzzi") - G.add_edge("Castellani", "Strozzi") - G.add_edge("Castellani", "Barbadori") - G.add_edge("Medici", "Barbadori") - G.add_edge("Medici", "Ridolfi") - G.add_edge("Medici", "Tornabuoni") - G.add_edge("Medici", "Albizzi") - G.add_edge("Medici", "Salviati") - G.add_edge("Salviati", "Pazzi") - G.add_edge("Peruzzi", "Strozzi") - G.add_edge("Peruzzi", "Bischeri") - G.add_edge("Strozzi", "Ridolfi") - G.add_edge("Strozzi", "Bischeri") - G.add_edge("Ridolfi", "Tornabuoni") - G.add_edge("Tornabuoni", "Guadagni") - G.add_edge("Albizzi", "Ginori") - G.add_edge("Albizzi", "Guadagni") - G.add_edge("Bischeri", "Guadagni") - G.add_edge("Guadagni", "Lamberteschi") - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def les_miserables_graph(): - """Returns coappearance network of characters in the novel Les Miserables. - - References - ---------- - .. [1] D. E. Knuth, 1993. - The Stanford GraphBase: a platform for combinatorial computing, - pp. 74-87. New York: AcM Press. - """ - G = nx.Graph() - G.add_edge("Napoleon", "Myriel", weight=1) - G.add_edge("MlleBaptistine", "Myriel", weight=8) - G.add_edge("MmeMagloire", "Myriel", weight=10) - G.add_edge("MmeMagloire", "MlleBaptistine", weight=6) - G.add_edge("CountessDeLo", "Myriel", weight=1) - G.add_edge("Geborand", "Myriel", weight=1) - G.add_edge("Champtercier", "Myriel", weight=1) - G.add_edge("Cravatte", "Myriel", weight=1) - G.add_edge("Count", "Myriel", weight=2) - G.add_edge("OldMan", "Myriel", weight=1) - G.add_edge("Valjean", "Labarre", weight=1) - G.add_edge("Valjean", "MmeMagloire", weight=3) - G.add_edge("Valjean", "MlleBaptistine", weight=3) - G.add_edge("Valjean", "Myriel", weight=5) - G.add_edge("Marguerite", "Valjean", weight=1) - G.add_edge("MmeDeR", "Valjean", weight=1) - G.add_edge("Isabeau", "Valjean", weight=1) - G.add_edge("Gervais", "Valjean", weight=1) - G.add_edge("Listolier", "Tholomyes", weight=4) - G.add_edge("Fameuil", "Tholomyes", weight=4) - G.add_edge("Fameuil", "Listolier", weight=4) - G.add_edge("Blacheville", "Tholomyes", weight=4) - G.add_edge("Blacheville", "Listolier", weight=4) - G.add_edge("Blacheville", "Fameuil", weight=4) - G.add_edge("Favourite", "Tholomyes", weight=3) - G.add_edge("Favourite", "Listolier", weight=3) - G.add_edge("Favourite", "Fameuil", weight=3) - G.add_edge("Favourite", "Blacheville", weight=4) - G.add_edge("Dahlia", "Tholomyes", weight=3) - G.add_edge("Dahlia", "Listolier", weight=3) - G.add_edge("Dahlia", "Fameuil", weight=3) - G.add_edge("Dahlia", "Blacheville", weight=3) - G.add_edge("Dahlia", "Favourite", weight=5) - G.add_edge("Zephine", "Tholomyes", weight=3) - G.add_edge("Zephine", "Listolier", weight=3) - G.add_edge("Zephine", "Fameuil", weight=3) - G.add_edge("Zephine", "Blacheville", weight=3) - G.add_edge("Zephine", "Favourite", weight=4) - G.add_edge("Zephine", "Dahlia", weight=4) - G.add_edge("Fantine", "Tholomyes", weight=3) - G.add_edge("Fantine", "Listolier", weight=3) - G.add_edge("Fantine", "Fameuil", weight=3) - G.add_edge("Fantine", "Blacheville", weight=3) - G.add_edge("Fantine", "Favourite", weight=4) - G.add_edge("Fantine", "Dahlia", weight=4) - G.add_edge("Fantine", "Zephine", weight=4) - G.add_edge("Fantine", "Marguerite", weight=2) - G.add_edge("Fantine", "Valjean", weight=9) - G.add_edge("MmeThenardier", "Fantine", weight=2) - G.add_edge("MmeThenardier", "Valjean", weight=7) - G.add_edge("Thenardier", "MmeThenardier", weight=13) - G.add_edge("Thenardier", "Fantine", weight=1) - G.add_edge("Thenardier", "Valjean", weight=12) - G.add_edge("Cosette", "MmeThenardier", weight=4) - G.add_edge("Cosette", "Valjean", weight=31) - G.add_edge("Cosette", "Tholomyes", weight=1) - G.add_edge("Cosette", "Thenardier", weight=1) - G.add_edge("Javert", "Valjean", weight=17) - G.add_edge("Javert", "Fantine", weight=5) - G.add_edge("Javert", "Thenardier", weight=5) - G.add_edge("Javert", "MmeThenardier", weight=1) - G.add_edge("Javert", "Cosette", weight=1) - G.add_edge("Fauchelevent", "Valjean", weight=8) - G.add_edge("Fauchelevent", "Javert", weight=1) - G.add_edge("Bamatabois", "Fantine", weight=1) - G.add_edge("Bamatabois", "Javert", weight=1) - G.add_edge("Bamatabois", "Valjean", weight=2) - G.add_edge("Perpetue", "Fantine", weight=1) - G.add_edge("Simplice", "Perpetue", weight=2) - G.add_edge("Simplice", "Valjean", weight=3) - G.add_edge("Simplice", "Fantine", weight=2) - G.add_edge("Simplice", "Javert", weight=1) - G.add_edge("Scaufflaire", "Valjean", weight=1) - G.add_edge("Woman1", "Valjean", weight=2) - G.add_edge("Woman1", "Javert", weight=1) - G.add_edge("Judge", "Valjean", weight=3) - G.add_edge("Judge", "Bamatabois", weight=2) - G.add_edge("Champmathieu", "Valjean", weight=3) - G.add_edge("Champmathieu", "Judge", weight=3) - G.add_edge("Champmathieu", "Bamatabois", weight=2) - G.add_edge("Brevet", "Judge", weight=2) - G.add_edge("Brevet", "Champmathieu", weight=2) - G.add_edge("Brevet", "Valjean", weight=2) - G.add_edge("Brevet", "Bamatabois", weight=1) - G.add_edge("Chenildieu", "Judge", weight=2) - G.add_edge("Chenildieu", "Champmathieu", weight=2) - G.add_edge("Chenildieu", "Brevet", weight=2) - G.add_edge("Chenildieu", "Valjean", weight=2) - G.add_edge("Chenildieu", "Bamatabois", weight=1) - G.add_edge("Cochepaille", "Judge", weight=2) - G.add_edge("Cochepaille", "Champmathieu", weight=2) - G.add_edge("Cochepaille", "Brevet", weight=2) - G.add_edge("Cochepaille", "Chenildieu", weight=2) - G.add_edge("Cochepaille", "Valjean", weight=2) - G.add_edge("Cochepaille", "Bamatabois", weight=1) - G.add_edge("Pontmercy", "Thenardier", weight=1) - G.add_edge("Boulatruelle", "Thenardier", weight=1) - G.add_edge("Eponine", "MmeThenardier", weight=2) - G.add_edge("Eponine", "Thenardier", weight=3) - G.add_edge("Anzelma", "Eponine", weight=2) - G.add_edge("Anzelma", "Thenardier", weight=2) - G.add_edge("Anzelma", "MmeThenardier", weight=1) - G.add_edge("Woman2", "Valjean", weight=3) - G.add_edge("Woman2", "Cosette", weight=1) - G.add_edge("Woman2", "Javert", weight=1) - G.add_edge("MotherInnocent", "Fauchelevent", weight=3) - G.add_edge("MotherInnocent", "Valjean", weight=1) - G.add_edge("Gribier", "Fauchelevent", weight=2) - G.add_edge("MmeBurgon", "Jondrette", weight=1) - G.add_edge("Gavroche", "MmeBurgon", weight=2) - G.add_edge("Gavroche", "Thenardier", weight=1) - G.add_edge("Gavroche", "Javert", weight=1) - G.add_edge("Gavroche", "Valjean", weight=1) - G.add_edge("Gillenormand", "Cosette", weight=3) - G.add_edge("Gillenormand", "Valjean", weight=2) - G.add_edge("Magnon", "Gillenormand", weight=1) - G.add_edge("Magnon", "MmeThenardier", weight=1) - G.add_edge("MlleGillenormand", "Gillenormand", weight=9) - G.add_edge("MlleGillenormand", "Cosette", weight=2) - G.add_edge("MlleGillenormand", "Valjean", weight=2) - G.add_edge("MmePontmercy", "MlleGillenormand", weight=1) - G.add_edge("MmePontmercy", "Pontmercy", weight=1) - G.add_edge("MlleVaubois", "MlleGillenormand", weight=1) - G.add_edge("LtGillenormand", "MlleGillenormand", weight=2) - G.add_edge("LtGillenormand", "Gillenormand", weight=1) - G.add_edge("LtGillenormand", "Cosette", weight=1) - G.add_edge("Marius", "MlleGillenormand", weight=6) - G.add_edge("Marius", "Gillenormand", weight=12) - G.add_edge("Marius", "Pontmercy", weight=1) - G.add_edge("Marius", "LtGillenormand", weight=1) - G.add_edge("Marius", "Cosette", weight=21) - G.add_edge("Marius", "Valjean", weight=19) - G.add_edge("Marius", "Tholomyes", weight=1) - G.add_edge("Marius", "Thenardier", weight=2) - G.add_edge("Marius", "Eponine", weight=5) - G.add_edge("Marius", "Gavroche", weight=4) - G.add_edge("BaronessT", "Gillenormand", weight=1) - G.add_edge("BaronessT", "Marius", weight=1) - G.add_edge("Mabeuf", "Marius", weight=1) - G.add_edge("Mabeuf", "Eponine", weight=1) - G.add_edge("Mabeuf", "Gavroche", weight=1) - G.add_edge("Enjolras", "Marius", weight=7) - G.add_edge("Enjolras", "Gavroche", weight=7) - G.add_edge("Enjolras", "Javert", weight=6) - G.add_edge("Enjolras", "Mabeuf", weight=1) - G.add_edge("Enjolras", "Valjean", weight=4) - G.add_edge("Combeferre", "Enjolras", weight=15) - G.add_edge("Combeferre", "Marius", weight=5) - G.add_edge("Combeferre", "Gavroche", weight=6) - G.add_edge("Combeferre", "Mabeuf", weight=2) - G.add_edge("Prouvaire", "Gavroche", weight=1) - G.add_edge("Prouvaire", "Enjolras", weight=4) - G.add_edge("Prouvaire", "Combeferre", weight=2) - G.add_edge("Feuilly", "Gavroche", weight=2) - G.add_edge("Feuilly", "Enjolras", weight=6) - G.add_edge("Feuilly", "Prouvaire", weight=2) - G.add_edge("Feuilly", "Combeferre", weight=5) - G.add_edge("Feuilly", "Mabeuf", weight=1) - G.add_edge("Feuilly", "Marius", weight=1) - G.add_edge("Courfeyrac", "Marius", weight=9) - G.add_edge("Courfeyrac", "Enjolras", weight=17) - G.add_edge("Courfeyrac", "Combeferre", weight=13) - G.add_edge("Courfeyrac", "Gavroche", weight=7) - G.add_edge("Courfeyrac", "Mabeuf", weight=2) - G.add_edge("Courfeyrac", "Eponine", weight=1) - G.add_edge("Courfeyrac", "Feuilly", weight=6) - G.add_edge("Courfeyrac", "Prouvaire", weight=3) - G.add_edge("Bahorel", "Combeferre", weight=5) - G.add_edge("Bahorel", "Gavroche", weight=5) - G.add_edge("Bahorel", "Courfeyrac", weight=6) - G.add_edge("Bahorel", "Mabeuf", weight=2) - G.add_edge("Bahorel", "Enjolras", weight=4) - G.add_edge("Bahorel", "Feuilly", weight=3) - G.add_edge("Bahorel", "Prouvaire", weight=2) - G.add_edge("Bahorel", "Marius", weight=1) - G.add_edge("Bossuet", "Marius", weight=5) - G.add_edge("Bossuet", "Courfeyrac", weight=12) - G.add_edge("Bossuet", "Gavroche", weight=5) - G.add_edge("Bossuet", "Bahorel", weight=4) - G.add_edge("Bossuet", "Enjolras", weight=10) - G.add_edge("Bossuet", "Feuilly", weight=6) - G.add_edge("Bossuet", "Prouvaire", weight=2) - G.add_edge("Bossuet", "Combeferre", weight=9) - G.add_edge("Bossuet", "Mabeuf", weight=1) - G.add_edge("Bossuet", "Valjean", weight=1) - G.add_edge("Joly", "Bahorel", weight=5) - G.add_edge("Joly", "Bossuet", weight=7) - G.add_edge("Joly", "Gavroche", weight=3) - G.add_edge("Joly", "Courfeyrac", weight=5) - G.add_edge("Joly", "Enjolras", weight=5) - G.add_edge("Joly", "Feuilly", weight=5) - G.add_edge("Joly", "Prouvaire", weight=2) - G.add_edge("Joly", "Combeferre", weight=5) - G.add_edge("Joly", "Mabeuf", weight=1) - G.add_edge("Joly", "Marius", weight=2) - G.add_edge("Grantaire", "Bossuet", weight=3) - G.add_edge("Grantaire", "Enjolras", weight=3) - G.add_edge("Grantaire", "Combeferre", weight=1) - G.add_edge("Grantaire", "Courfeyrac", weight=2) - G.add_edge("Grantaire", "Joly", weight=2) - G.add_edge("Grantaire", "Gavroche", weight=1) - G.add_edge("Grantaire", "Bahorel", weight=1) - G.add_edge("Grantaire", "Feuilly", weight=1) - G.add_edge("Grantaire", "Prouvaire", weight=1) - G.add_edge("MotherPlutarch", "Mabeuf", weight=3) - G.add_edge("Gueulemer", "Thenardier", weight=5) - G.add_edge("Gueulemer", "Valjean", weight=1) - G.add_edge("Gueulemer", "MmeThenardier", weight=1) - G.add_edge("Gueulemer", "Javert", weight=1) - G.add_edge("Gueulemer", "Gavroche", weight=1) - G.add_edge("Gueulemer", "Eponine", weight=1) - G.add_edge("Babet", "Thenardier", weight=6) - G.add_edge("Babet", "Gueulemer", weight=6) - G.add_edge("Babet", "Valjean", weight=1) - G.add_edge("Babet", "MmeThenardier", weight=1) - G.add_edge("Babet", "Javert", weight=2) - G.add_edge("Babet", "Gavroche", weight=1) - G.add_edge("Babet", "Eponine", weight=1) - G.add_edge("Claquesous", "Thenardier", weight=4) - G.add_edge("Claquesous", "Babet", weight=4) - G.add_edge("Claquesous", "Gueulemer", weight=4) - G.add_edge("Claquesous", "Valjean", weight=1) - G.add_edge("Claquesous", "MmeThenardier", weight=1) - G.add_edge("Claquesous", "Javert", weight=1) - G.add_edge("Claquesous", "Eponine", weight=1) - G.add_edge("Claquesous", "Enjolras", weight=1) - G.add_edge("Montparnasse", "Javert", weight=1) - G.add_edge("Montparnasse", "Babet", weight=2) - G.add_edge("Montparnasse", "Gueulemer", weight=2) - G.add_edge("Montparnasse", "Claquesous", weight=2) - G.add_edge("Montparnasse", "Valjean", weight=1) - G.add_edge("Montparnasse", "Gavroche", weight=1) - G.add_edge("Montparnasse", "Eponine", weight=1) - G.add_edge("Montparnasse", "Thenardier", weight=1) - G.add_edge("Toussaint", "Cosette", weight=2) - G.add_edge("Toussaint", "Javert", weight=1) - G.add_edge("Toussaint", "Valjean", weight=1) - G.add_edge("Child1", "Gavroche", weight=2) - G.add_edge("Child2", "Gavroche", weight=2) - G.add_edge("Child2", "Child1", weight=3) - G.add_edge("Brujon", "Babet", weight=3) - G.add_edge("Brujon", "Gueulemer", weight=3) - G.add_edge("Brujon", "Thenardier", weight=3) - G.add_edge("Brujon", "Gavroche", weight=1) - G.add_edge("Brujon", "Eponine", weight=1) - G.add_edge("Brujon", "Claquesous", weight=1) - G.add_edge("Brujon", "Montparnasse", weight=1) - G.add_edge("MmeHucheloup", "Bossuet", weight=1) - G.add_edge("MmeHucheloup", "Joly", weight=1) - G.add_edge("MmeHucheloup", "Grantaire", weight=1) - G.add_edge("MmeHucheloup", "Bahorel", weight=1) - G.add_edge("MmeHucheloup", "Courfeyrac", weight=1) - G.add_edge("MmeHucheloup", "Gavroche", weight=1) - G.add_edge("MmeHucheloup", "Enjolras", weight=1) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/spectral_graph_forge.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/spectral_graph_forge.py deleted file mode 100644 index 39a87f7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/spectral_graph_forge.py +++ /dev/null @@ -1,120 +0,0 @@ -"""Generates graphs with a given eigenvector structure""" - -import networkx as nx -from networkx.utils import np_random_state - -__all__ = ["spectral_graph_forge"] - - -@np_random_state(3) -@nx._dispatchable(returns_graph=True) -def spectral_graph_forge(G, alpha, transformation="identity", seed=None): - """Returns a random simple graph with spectrum resembling that of `G` - - This algorithm, called Spectral Graph Forge (SGF), computes the - eigenvectors of a given graph adjacency matrix, filters them and - builds a random graph with a similar eigenstructure. - SGF has been proved to be particularly useful for synthesizing - realistic social networks and it can also be used to anonymize - graph sensitive data. - - Parameters - ---------- - G : Graph - alpha : float - Ratio representing the percentage of eigenvectors of G to consider, - values in [0,1]. - transformation : string, optional - Represents the intended matrix linear transformation, possible values - are 'identity' and 'modularity' - seed : integer, random_state, or None (default) - Indicator of numpy random number generation state. - See :ref:`Randomness`. - - Returns - ------- - H : Graph - A graph with a similar eigenvector structure of the input one. - - Raises - ------ - NetworkXError - If transformation has a value different from 'identity' or 'modularity' - - Notes - ----- - Spectral Graph Forge (SGF) generates a random simple graph resembling the - global properties of the given one. - It leverages the low-rank approximation of the associated adjacency matrix - driven by the *alpha* precision parameter. - SGF preserves the number of nodes of the input graph and their ordering. - This way, nodes of output graphs resemble the properties of the input one - and attributes can be directly mapped. - - It considers the graph adjacency matrices which can optionally be - transformed to other symmetric real matrices (currently transformation - options include *identity* and *modularity*). - The *modularity* transformation, in the sense of Newman's modularity matrix - allows the focusing on community structure related properties of the graph. - - SGF applies a low-rank approximation whose fixed rank is computed from the - ratio *alpha* of the input graph adjacency matrix dimension. - This step performs a filtering on the input eigenvectors similar to the low - pass filtering common in telecommunications. - - The filtered values (after truncation) are used as input to a Bernoulli - sampling for constructing a random adjacency matrix. - - References - ---------- - .. [1] L. Baldesi, C. T. Butts, A. Markopoulou, "Spectral Graph Forge: - Graph Generation Targeting Modularity", IEEE Infocom, '18. - https://arxiv.org/abs/1801.01715 - .. [2] M. Newman, "Networks: an introduction", Oxford university press, - 2010 - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> H = nx.spectral_graph_forge(G, 0.3) - >>> - """ - import numpy as np - import scipy as sp - - available_transformations = ["identity", "modularity"] - alpha = np.clip(alpha, 0, 1) - A = nx.to_numpy_array(G) - n = A.shape[1] - level = round(n * alpha) - - if transformation not in available_transformations: - msg = f"{transformation!r} is not a valid transformation. " - msg += f"Transformations: {available_transformations}" - raise nx.NetworkXError(msg) - - K = np.ones((1, n)) @ A - - B = A - if transformation == "modularity": - B -= K.T @ K / K.sum() - - # Compute low-rank approximation of B - evals, evecs = np.linalg.eigh(B) - k = np.argsort(np.abs(evals))[::-1] # indices of evals in descending order - evecs[:, k[np.arange(level, n)]] = 0 # set smallest eigenvectors to 0 - B = evecs @ np.diag(evals) @ evecs.T - - if transformation == "modularity": - B += K.T @ K / K.sum() - - B = np.clip(B, 0, 1) - np.fill_diagonal(B, 0) - - for i in range(n - 1): - B[i, i + 1 :] = sp.stats.bernoulli.rvs(B[i, i + 1 :], random_state=seed) - B[i + 1 :, i] = np.transpose(B[i, i + 1 :]) - - H = nx.from_numpy_array(B) - - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/stochastic.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/stochastic.py deleted file mode 100644 index f53e231..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/stochastic.py +++ /dev/null @@ -1,54 +0,0 @@ -"""Functions for generating stochastic graphs from a given weighted directed -graph. - -""" - -import networkx as nx -from networkx.classes import DiGraph, MultiDiGraph -from networkx.utils import not_implemented_for - -__all__ = ["stochastic_graph"] - - -@not_implemented_for("undirected") -@nx._dispatchable( - edge_attrs="weight", mutates_input={"not copy": 1}, returns_graph=True -) -def stochastic_graph(G, copy=True, weight="weight"): - """Returns a right-stochastic representation of directed graph `G`. - - A right-stochastic graph is a weighted digraph in which for each - node, the sum of the weights of all the out-edges of that node is - 1. If the graph is already weighted (for example, via a 'weight' - edge attribute), the reweighting takes that into account. - - Parameters - ---------- - G : directed graph - A :class:`~networkx.DiGraph` or :class:`~networkx.MultiDiGraph`. - - copy : boolean, optional - If this is True, then this function returns a new graph with - the stochastic reweighting. Otherwise, the original graph is - modified in-place (and also returned, for convenience). - - weight : edge attribute key (optional, default='weight') - Edge attribute key used for reading the existing weight and - setting the new weight. If no attribute with this key is found - for an edge, then the edge weight is assumed to be 1. If an edge - has a weight, it must be a positive number. - - """ - if copy: - G = MultiDiGraph(G) if G.is_multigraph() else DiGraph(G) - # There is a tradeoff here: the dictionary of node degrees may - # require a lot of memory, whereas making a call to `G.out_degree` - # inside the loop may be costly in computation time. - degree = dict(G.out_degree(weight=weight)) - for u, v, d in G.edges(data=True): - if degree[u] == 0: - d[weight] = 0 - else: - d[weight] = d.get(weight, 1) / degree[u] - nx._clear_cache(G) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/sudoku.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/sudoku.py deleted file mode 100644 index f288ed2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/sudoku.py +++ /dev/null @@ -1,131 +0,0 @@ -"""Generator for Sudoku graphs - -This module gives a generator for n-Sudoku graphs. It can be used to develop -algorithms for solving or generating Sudoku puzzles. - -A completed Sudoku grid is a 9x9 array of integers between 1 and 9, with no -number appearing twice in the same row, column, or 3x3 box. - -+---------+---------+---------+ -| | 8 6 4 | | 3 7 1 | | 2 5 9 | -| | 3 2 5 | | 8 4 9 | | 7 6 1 | -| | 9 7 1 | | 2 6 5 | | 8 4 3 | -+---------+---------+---------+ -| | 4 3 6 | | 1 9 2 | | 5 8 7 | -| | 1 9 8 | | 6 5 7 | | 4 3 2 | -| | 2 5 7 | | 4 8 3 | | 9 1 6 | -+---------+---------+---------+ -| | 6 8 9 | | 7 3 4 | | 1 2 5 | -| | 7 1 3 | | 5 2 8 | | 6 9 4 | -| | 5 4 2 | | 9 1 6 | | 3 7 8 | -+---------+---------+---------+ - - -The Sudoku graph is an undirected graph with 81 vertices, corresponding to -the cells of a Sudoku grid. It is a regular graph of degree 20. Two distinct -vertices are adjacent if and only if the corresponding cells belong to the -same row, column, or box. A completed Sudoku grid corresponds to a vertex -coloring of the Sudoku graph with nine colors. - -More generally, the n-Sudoku graph is a graph with n^4 vertices, corresponding -to the cells of an n^2 by n^2 grid. Two distinct vertices are adjacent if and -only if they belong to the same row, column, or n by n box. - -References ----------- -.. [1] Herzberg, A. M., & Murty, M. R. (2007). Sudoku squares and chromatic - polynomials. Notices of the AMS, 54(6), 708-717. -.. [2] Sander, Torsten (2009), "Sudoku graphs are integral", - Electronic Journal of Combinatorics, 16 (1): Note 25, 7pp, MR 2529816 -.. [3] Wikipedia contributors. "Glossary of Sudoku." Wikipedia, The Free - Encyclopedia, 3 Dec. 2019. Web. 22 Dec. 2019. -""" - -import networkx as nx -from networkx.exception import NetworkXError - -__all__ = ["sudoku_graph"] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def sudoku_graph(n=3): - """Returns the n-Sudoku graph. The default value of n is 3. - - The n-Sudoku graph is a graph with n^4 vertices, corresponding to the - cells of an n^2 by n^2 grid. Two distinct vertices are adjacent if and - only if they belong to the same row, column, or n-by-n box. - - Parameters - ---------- - n: integer - The order of the Sudoku graph, equal to the square root of the - number of rows. The default is 3. - - Returns - ------- - NetworkX graph - The n-Sudoku graph Sud(n). - - Examples - -------- - >>> G = nx.sudoku_graph() - >>> G.number_of_nodes() - 81 - >>> G.number_of_edges() - 810 - >>> sorted(G.neighbors(42)) - [6, 15, 24, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 51, 52, 53, 60, 69, 78] - >>> G = nx.sudoku_graph(2) - >>> G.number_of_nodes() - 16 - >>> G.number_of_edges() - 56 - - References - ---------- - .. [1] Herzberg, A. M., & Murty, M. R. (2007). Sudoku squares and chromatic - polynomials. Notices of the AMS, 54(6), 708-717. - .. [2] Sander, Torsten (2009), "Sudoku graphs are integral", - Electronic Journal of Combinatorics, 16 (1): Note 25, 7pp, MR 2529816 - .. [3] Wikipedia contributors. "Glossary of Sudoku." Wikipedia, The Free - Encyclopedia, 3 Dec. 2019. Web. 22 Dec. 2019. - """ - - if n < 0: - raise NetworkXError("The order must be greater than or equal to zero.") - - n2 = n * n - n3 = n2 * n - n4 = n3 * n - - # Construct an empty graph with n^4 nodes - G = nx.empty_graph(n4) - - # A Sudoku graph of order 0 or 1 has no edges - if n < 2: - return G - - # Add edges for cells in the same row - for row_no in range(n2): - row_start = row_no * n2 - for j in range(1, n2): - for i in range(j): - G.add_edge(row_start + i, row_start + j) - - # Add edges for cells in the same column - for col_no in range(n2): - for j in range(col_no, n4, n2): - for i in range(col_no, j, n2): - G.add_edge(i, j) - - # Add edges for cells in the same box - for band_no in range(n): - for stack_no in range(n): - box_start = n3 * band_no + n * stack_no - for j in range(1, n2): - for i in range(j): - u = box_start + (i % n) + n2 * (i // n) - v = box_start + (j % n) + n2 * (j // n) - G.add_edge(u, v) - - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_atlas.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_atlas.py deleted file mode 100644 index add4741..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_atlas.py +++ /dev/null @@ -1,75 +0,0 @@ -from itertools import groupby - -import pytest - -import networkx as nx -from networkx import graph_atlas, graph_atlas_g -from networkx.generators.atlas import NUM_GRAPHS -from networkx.utils import edges_equal, nodes_equal, pairwise - - -class TestAtlasGraph: - """Unit tests for the :func:`~networkx.graph_atlas` function.""" - - def test_index_too_small(self): - with pytest.raises(ValueError): - graph_atlas(-1) - - def test_index_too_large(self): - with pytest.raises(ValueError): - graph_atlas(NUM_GRAPHS) - - def test_graph(self): - G = graph_atlas(6) - assert nodes_equal(G.nodes(), range(3)) - assert edges_equal(G.edges(), [(0, 1), (0, 2)]) - - -class TestAtlasGraphG: - """Unit tests for the :func:`~networkx.graph_atlas_g` function.""" - - @classmethod - def setup_class(cls): - cls.GAG = graph_atlas_g() - - def test_sizes(self): - G = self.GAG[0] - assert G.number_of_nodes() == 0 - assert G.number_of_edges() == 0 - - G = self.GAG[7] - assert G.number_of_nodes() == 3 - assert G.number_of_edges() == 3 - - def test_names(self): - for i, G in enumerate(self.GAG): - assert int(G.name[1:]) == i - - def test_nondecreasing_nodes(self): - # check for nondecreasing number of nodes - for n1, n2 in pairwise(map(len, self.GAG)): - assert n2 <= n1 + 1 - - def test_nondecreasing_edges(self): - # check for nondecreasing number of edges (for fixed number of - # nodes) - for n, group in groupby(self.GAG, key=nx.number_of_nodes): - for m1, m2 in pairwise(map(nx.number_of_edges, group)): - assert m2 <= m1 + 1 - - def test_nondecreasing_degree_sequence(self): - # Check for lexicographically nondecreasing degree sequences - # (for fixed number of nodes and edges). - # - # There are three exceptions to this rule in the order given in - # the "Atlas of Graphs" book, so we need to manually exclude - # those. - exceptions = [("G55", "G56"), ("G1007", "G1008"), ("G1012", "G1013")] - for n, group in groupby(self.GAG, key=nx.number_of_nodes): - for m, group in groupby(group, key=nx.number_of_edges): - for G1, G2 in pairwise(group): - if (G1.name, G2.name) in exceptions: - continue - d1 = sorted(d for v, d in G1.degree()) - d2 = sorted(d for v, d in G2.degree()) - assert d1 <= d2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_classic.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_classic.py deleted file mode 100644 index 9353c7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_classic.py +++ /dev/null @@ -1,640 +0,0 @@ -""" -==================== -Generators - Classic -==================== - -Unit tests for various classic graph generators in generators/classic.py -""" - -import itertools -import typing - -import pytest - -import networkx as nx -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic -from networkx.utils import edges_equal, nodes_equal - -is_isomorphic = graph_could_be_isomorphic - - -class TestGeneratorClassic: - def test_balanced_tree(self): - # balanced_tree(r,h) is a tree with (r**(h+1)-1)/(r-1) edges - for r, h in [(2, 2), (3, 3), (6, 2)]: - t = nx.balanced_tree(r, h) - order = t.order() - assert order == (r ** (h + 1) - 1) / (r - 1) - assert nx.is_connected(t) - assert t.size() == order - 1 - dh = nx.degree_histogram(t) - assert dh[0] == 0 # no nodes of 0 - assert dh[1] == r**h # nodes of degree 1 are leaves - assert dh[r] == 1 # root is degree r - assert dh[r + 1] == order - r**h - 1 # everyone else is degree r+1 - assert len(dh) == r + 2 - - def test_balanced_tree_star(self): - # balanced_tree(r,1) is the r-star - t = nx.balanced_tree(r=2, h=1) - assert is_isomorphic(t, nx.star_graph(2)) - t = nx.balanced_tree(r=5, h=1) - assert is_isomorphic(t, nx.star_graph(5)) - t = nx.balanced_tree(r=10, h=1) - assert is_isomorphic(t, nx.star_graph(10)) - - def test_balanced_tree_path(self): - """Tests that the balanced tree with branching factor one is the - path graph. - - """ - # A tree of height four has five levels. - T = nx.balanced_tree(1, 4) - P = nx.path_graph(5) - assert is_isomorphic(T, P) - - def test_full_rary_tree(self): - r = 2 - n = 9 - t = nx.full_rary_tree(r, n) - assert t.order() == n - assert nx.is_connected(t) - dh = nx.degree_histogram(t) - assert dh[0] == 0 # no nodes of 0 - assert dh[1] == 5 # nodes of degree 1 are leaves - assert dh[r] == 1 # root is degree r - assert dh[r + 1] == 9 - 5 - 1 # everyone else is degree r+1 - assert len(dh) == r + 2 - - def test_full_rary_tree_balanced(self): - t = nx.full_rary_tree(2, 15) - th = nx.balanced_tree(2, 3) - assert is_isomorphic(t, th) - - def test_full_rary_tree_path(self): - t = nx.full_rary_tree(1, 10) - assert is_isomorphic(t, nx.path_graph(10)) - - def test_full_rary_tree_empty(self): - t = nx.full_rary_tree(0, 10) - assert is_isomorphic(t, nx.empty_graph(10)) - t = nx.full_rary_tree(3, 0) - assert is_isomorphic(t, nx.empty_graph(0)) - - def test_full_rary_tree_3_20(self): - t = nx.full_rary_tree(3, 20) - assert t.order() == 20 - - def test_barbell_graph(self): - # number of nodes = 2*m1 + m2 (2 m1-complete graphs + m2-path + 2 edges) - # number of edges = 2*(nx.number_of_edges(m1-complete graph) + m2 + 1 - m1 = 3 - m2 = 5 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - m1 = 4 - m2 = 10 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - m1 = 3 - m2 = 20 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - # Raise NetworkXError if m1<2 - m1 = 1 - m2 = 20 - pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2) - - # Raise NetworkXError if m2<0 - m1 = 5 - m2 = -2 - pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2) - - # nx.barbell_graph(2,m) = nx.path_graph(m+4) - m1 = 2 - m2 = 5 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - m1 = 2 - m2 = 10 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - m1 = 2 - m2 = 20 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - pytest.raises( - nx.NetworkXError, nx.barbell_graph, m1, m2, create_using=nx.DiGraph() - ) - - mb = nx.barbell_graph(m1, m2, create_using=nx.MultiGraph()) - assert edges_equal(mb.edges(), b.edges()) - - def test_binomial_tree(self): - graphs = (None, nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) - for create_using in graphs: - for n in range(4): - b = nx.binomial_tree(n, create_using) - assert nx.number_of_nodes(b) == 2**n - assert nx.number_of_edges(b) == (2**n - 1) - - def test_complete_graph(self): - # complete_graph(m) is a connected graph with - # m nodes and m*(m+1)/2 edges - for m in [0, 1, 3, 5]: - g = nx.complete_graph(m) - assert nx.number_of_nodes(g) == m - assert nx.number_of_edges(g) == m * (m - 1) // 2 - - mg = nx.complete_graph(m, create_using=nx.MultiGraph) - assert edges_equal(mg.edges(), g.edges()) - - g = nx.complete_graph("abc") - assert nodes_equal(g.nodes(), ["a", "b", "c"]) - assert g.size() == 3 - - # creates a self-loop... should it? - g = nx.complete_graph("abcb") - assert nodes_equal(g.nodes(), ["a", "b", "c"]) - assert g.size() == 4 - - g = nx.complete_graph("abcb", create_using=nx.MultiGraph) - assert nodes_equal(g.nodes(), ["a", "b", "c"]) - assert g.size() == 6 - - def test_complete_digraph(self): - # complete_graph(m) is a connected graph with - # m nodes and m*(m+1)/2 edges - for m in [0, 1, 3, 5]: - g = nx.complete_graph(m, create_using=nx.DiGraph) - assert nx.number_of_nodes(g) == m - assert nx.number_of_edges(g) == m * (m - 1) - - g = nx.complete_graph("abc", create_using=nx.DiGraph) - assert len(g) == 3 - assert g.size() == 6 - assert g.is_directed() - - def test_circular_ladder_graph(self): - G = nx.circular_ladder_graph(5) - pytest.raises( - nx.NetworkXError, nx.circular_ladder_graph, 5, create_using=nx.DiGraph - ) - mG = nx.circular_ladder_graph(5, create_using=nx.MultiGraph) - assert edges_equal(mG.edges(), G.edges()) - - def test_circulant_graph(self): - # Ci_n(1) is the cycle graph for all n - Ci6_1 = nx.circulant_graph(6, [1]) - C6 = nx.cycle_graph(6) - assert edges_equal(Ci6_1.edges(), C6.edges()) - - # Ci_n(1, 2, ..., n div 2) is the complete graph for all n - Ci7 = nx.circulant_graph(7, [1, 2, 3]) - K7 = nx.complete_graph(7) - assert edges_equal(Ci7.edges(), K7.edges()) - - # Ci_6(1, 3) is K_3,3 i.e. the utility graph - Ci6_1_3 = nx.circulant_graph(6, [1, 3]) - K3_3 = nx.complete_bipartite_graph(3, 3) - assert is_isomorphic(Ci6_1_3, K3_3) - - def test_cycle_graph(self): - G = nx.cycle_graph(4) - assert edges_equal(G.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)]) - mG = nx.cycle_graph(4, create_using=nx.MultiGraph) - assert edges_equal(mG.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)]) - G = nx.cycle_graph(4, create_using=nx.DiGraph) - assert not G.has_edge(2, 1) - assert G.has_edge(1, 2) - assert G.is_directed() - - G = nx.cycle_graph("abc") - assert len(G) == 3 - assert G.size() == 3 - G = nx.cycle_graph("abcb") - assert len(G) == 3 - assert G.size() == 2 - g = nx.cycle_graph("abc", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 3 - assert g.is_directed() - g = nx.cycle_graph("abcb", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 4 - - def test_dorogovtsev_goltsev_mendes_graph(self): - G = nx.dorogovtsev_goltsev_mendes_graph(0) - assert edges_equal(G.edges(), [(0, 1)]) - assert nodes_equal(list(G), [0, 1]) - G = nx.dorogovtsev_goltsev_mendes_graph(1) - assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)]) - assert nx.average_clustering(G) == 1.0 - assert nx.average_shortest_path_length(G) == 1.0 - assert sorted(nx.triangles(G).values()) == [1, 1, 1] - assert nx.is_planar(G) - G = nx.dorogovtsev_goltsev_mendes_graph(2) - assert nx.number_of_nodes(G) == 6 - assert nx.number_of_edges(G) == 9 - assert nx.average_clustering(G) == 0.75 - assert nx.average_shortest_path_length(G) == 1.4 - assert nx.is_planar(G) - G = nx.dorogovtsev_goltsev_mendes_graph(10) - assert nx.number_of_nodes(G) == 29526 - assert nx.number_of_edges(G) == 59049 - assert G.degree(0) == 1024 - assert G.degree(1) == 1024 - assert G.degree(2) == 1024 - - with pytest.raises(nx.NetworkXError, match=r"n must be greater than"): - nx.dorogovtsev_goltsev_mendes_graph(-1) - with pytest.raises(nx.NetworkXError, match=r"directed graph not supported"): - nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError, match=r"multigraph not supported"): - nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.MultiGraph) - with pytest.raises(nx.NetworkXError): - nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.MultiDiGraph) - - def test_create_using(self): - G = nx.empty_graph() - assert isinstance(G, nx.Graph) - pytest.raises(TypeError, nx.empty_graph, create_using=0.0) - pytest.raises(TypeError, nx.empty_graph, create_using="Graph") - - G = nx.empty_graph(create_using=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - G = nx.empty_graph(create_using=nx.DiGraph) - assert isinstance(G, nx.DiGraph) - - G = nx.empty_graph(create_using=nx.DiGraph, default=nx.MultiGraph) - assert isinstance(G, nx.DiGraph) - G = nx.empty_graph(create_using=None, default=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - G = nx.empty_graph(default=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - - G = nx.path_graph(5) - H = nx.empty_graph(create_using=G) - assert not H.is_multigraph() - assert not H.is_directed() - assert len(H) == 0 - assert G is H - - H = nx.empty_graph(create_using=nx.MultiGraph()) - assert H.is_multigraph() - assert not H.is_directed() - assert G is not H - - # test for subclasses that also use typing.Protocol. See gh-6243 - class Mixin(typing.Protocol): - pass - - class MyGraph(Mixin, nx.DiGraph): - pass - - G = nx.empty_graph(create_using=MyGraph) - - def test_empty_graph(self): - G = nx.empty_graph() - assert nx.number_of_nodes(G) == 0 - G = nx.empty_graph(42) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - - G = nx.empty_graph("abc") - assert len(G) == 3 - assert G.size() == 0 - - # create empty digraph - G = nx.empty_graph(42, create_using=nx.DiGraph(name="duh")) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.DiGraph) - - # create empty multigraph - G = nx.empty_graph(42, create_using=nx.MultiGraph(name="duh")) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.MultiGraph) - - # create empty graph from another - pete = nx.petersen_graph() - G = nx.empty_graph(42, create_using=pete) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.Graph) - - def test_ladder_graph(self): - for i, G in [ - (0, nx.empty_graph(0)), - (1, nx.path_graph(2)), - (2, nx.hypercube_graph(2)), - (10, nx.grid_graph([2, 10])), - ]: - assert is_isomorphic(nx.ladder_graph(i), G) - - pytest.raises(nx.NetworkXError, nx.ladder_graph, 2, create_using=nx.DiGraph) - - g = nx.ladder_graph(2) - mg = nx.ladder_graph(2, create_using=nx.MultiGraph) - assert edges_equal(mg.edges(), g.edges()) - - @pytest.mark.parametrize(("m", "n"), [(3, 5), (4, 10), (3, 20)]) - def test_lollipop_graph_right_sizes(self, m, n): - G = nx.lollipop_graph(m, n) - assert nx.number_of_nodes(G) == m + n - assert nx.number_of_edges(G) == m * (m - 1) / 2 + n - - @pytest.mark.parametrize(("m", "n"), [("ab", ""), ("abc", "defg")]) - def test_lollipop_graph_size_node_sequence(self, m, n): - G = nx.lollipop_graph(m, n) - assert nx.number_of_nodes(G) == len(m) + len(n) - assert nx.number_of_edges(G) == len(m) * (len(m) - 1) / 2 + len(n) - - def test_lollipop_graph_exceptions(self): - # Raise NetworkXError if m<2 - pytest.raises(nx.NetworkXError, nx.lollipop_graph, -1, 2) - pytest.raises(nx.NetworkXError, nx.lollipop_graph, 1, 20) - pytest.raises(nx.NetworkXError, nx.lollipop_graph, "", 20) - pytest.raises(nx.NetworkXError, nx.lollipop_graph, "a", 20) - - # Raise NetworkXError if n<0 - pytest.raises(nx.NetworkXError, nx.lollipop_graph, 5, -2) - - # raise NetworkXError if create_using is directed - with pytest.raises(nx.NetworkXError): - nx.lollipop_graph(2, 20, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError): - nx.lollipop_graph(2, 20, create_using=nx.MultiDiGraph) - - @pytest.mark.parametrize(("m", "n"), [(2, 0), (2, 5), (2, 10), ("ab", 20)]) - def test_lollipop_graph_same_as_path_when_m1_is_2(self, m, n): - G = nx.lollipop_graph(m, n) - assert is_isomorphic(G, nx.path_graph(n + 2)) - - def test_lollipop_graph_for_multigraph(self): - G = nx.lollipop_graph(5, 20) - MG = nx.lollipop_graph(5, 20, create_using=nx.MultiGraph) - assert edges_equal(MG.edges(), G.edges()) - - @pytest.mark.parametrize( - ("m", "n"), - [(4, "abc"), ("abcd", 3), ([1, 2, 3, 4], "abc"), ("abcd", [1, 2, 3])], - ) - def test_lollipop_graph_mixing_input_types(self, m, n): - expected = nx.compose(nx.complete_graph(4), nx.path_graph(range(100, 103))) - expected.add_edge(0, 100) # Connect complete graph and path graph - assert is_isomorphic(nx.lollipop_graph(m, n), expected) - - def test_lollipop_graph_non_builtin_ints(self): - np = pytest.importorskip("numpy") - G = nx.lollipop_graph(np.int32(4), np.int64(3)) - expected = nx.compose(nx.complete_graph(4), nx.path_graph(range(100, 103))) - expected.add_edge(0, 100) # Connect complete graph and path graph - assert is_isomorphic(G, expected) - - def test_null_graph(self): - assert nx.number_of_nodes(nx.null_graph()) == 0 - - def test_path_graph(self): - p = nx.path_graph(0) - assert is_isomorphic(p, nx.null_graph()) - - p = nx.path_graph(1) - assert is_isomorphic(p, nx.empty_graph(1)) - - p = nx.path_graph(10) - assert nx.is_connected(p) - assert sorted(d for n, d in p.degree()) == [1, 1, 2, 2, 2, 2, 2, 2, 2, 2] - assert p.order() - 1 == p.size() - - dp = nx.path_graph(3, create_using=nx.DiGraph) - assert dp.has_edge(0, 1) - assert not dp.has_edge(1, 0) - - mp = nx.path_graph(10, create_using=nx.MultiGraph) - assert edges_equal(mp.edges(), p.edges()) - - G = nx.path_graph("abc") - assert len(G) == 3 - assert G.size() == 2 - G = nx.path_graph("abcb") - assert len(G) == 3 - assert G.size() == 2 - g = nx.path_graph("abc", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 2 - assert g.is_directed() - g = nx.path_graph("abcb", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 3 - - G = nx.path_graph((1, 2, 3, 2, 4)) - assert G.has_edge(2, 4) - - def test_star_graph(self): - assert is_isomorphic(nx.star_graph(""), nx.empty_graph(0)) - assert is_isomorphic(nx.star_graph([]), nx.empty_graph(0)) - assert is_isomorphic(nx.star_graph(0), nx.empty_graph(1)) - assert is_isomorphic(nx.star_graph(1), nx.path_graph(2)) - assert is_isomorphic(nx.star_graph(2), nx.path_graph(3)) - assert is_isomorphic(nx.star_graph(5), nx.complete_bipartite_graph(1, 5)) - - s = nx.star_graph(10) - assert sorted(d for n, d in s.degree()) == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10] - - pytest.raises(nx.NetworkXError, nx.star_graph, 10, create_using=nx.DiGraph) - - ms = nx.star_graph(10, create_using=nx.MultiGraph) - assert edges_equal(ms.edges(), s.edges()) - - G = nx.star_graph("abc") - assert len(G) == 3 - assert G.size() == 2 - - G = nx.star_graph("abcb") - assert len(G) == 3 - assert G.size() == 2 - G = nx.star_graph("abcb", create_using=nx.MultiGraph) - assert len(G) == 3 - assert G.size() == 3 - - G = nx.star_graph("abcdefg") - assert len(G) == 7 - assert G.size() == 6 - - def test_non_int_integers_for_star_graph(self): - np = pytest.importorskip("numpy") - G = nx.star_graph(np.int32(3)) - assert len(G) == 4 - assert G.size() == 3 - - @pytest.mark.parametrize(("m", "n"), [(3, 0), (3, 5), (4, 10), (3, 20)]) - def test_tadpole_graph_right_sizes(self, m, n): - G = nx.tadpole_graph(m, n) - assert nx.number_of_nodes(G) == m + n - assert nx.number_of_edges(G) == m + n - (m == 2) - - @pytest.mark.parametrize(("m", "n"), [("ab", ""), ("ab", "c"), ("abc", "defg")]) - def test_tadpole_graph_size_node_sequences(self, m, n): - G = nx.tadpole_graph(m, n) - assert nx.number_of_nodes(G) == len(m) + len(n) - assert nx.number_of_edges(G) == len(m) + len(n) - (len(m) == 2) - - def test_tadpole_graph_exceptions(self): - # Raise NetworkXError if m<2 - pytest.raises(nx.NetworkXError, nx.tadpole_graph, -1, 3) - pytest.raises(nx.NetworkXError, nx.tadpole_graph, 0, 3) - pytest.raises(nx.NetworkXError, nx.tadpole_graph, 1, 3) - - # Raise NetworkXError if n<0 - pytest.raises(nx.NetworkXError, nx.tadpole_graph, 5, -2) - - # Raise NetworkXError for digraphs - with pytest.raises(nx.NetworkXError): - nx.tadpole_graph(2, 20, create_using=nx.DiGraph) - with pytest.raises(nx.NetworkXError): - nx.tadpole_graph(2, 20, create_using=nx.MultiDiGraph) - - @pytest.mark.parametrize(("m", "n"), [(2, 0), (2, 5), (2, 10), ("ab", 20)]) - def test_tadpole_graph_same_as_path_when_m_is_2(self, m, n): - G = nx.tadpole_graph(m, n) - assert is_isomorphic(G, nx.path_graph(n + 2)) - - @pytest.mark.parametrize("m", [4, 7]) - def test_tadpole_graph_same_as_cycle_when_m2_is_0(self, m): - G = nx.tadpole_graph(m, 0) - assert is_isomorphic(G, nx.cycle_graph(m)) - - def test_tadpole_graph_for_multigraph(self): - G = nx.tadpole_graph(5, 20) - MG = nx.tadpole_graph(5, 20, create_using=nx.MultiGraph) - assert edges_equal(MG.edges(), G.edges()) - - @pytest.mark.parametrize( - ("m", "n"), - [(4, "abc"), ("abcd", 3), ([1, 2, 3, 4], "abc"), ("abcd", [1, 2, 3])], - ) - def test_tadpole_graph_mixing_input_types(self, m, n): - expected = nx.compose(nx.cycle_graph(4), nx.path_graph(range(100, 103))) - expected.add_edge(0, 100) # Connect cycle and path - assert is_isomorphic(nx.tadpole_graph(m, n), expected) - - def test_tadpole_graph_non_builtin_integers(self): - np = pytest.importorskip("numpy") - G = nx.tadpole_graph(np.int32(4), np.int64(3)) - expected = nx.compose(nx.cycle_graph(4), nx.path_graph(range(100, 103))) - expected.add_edge(0, 100) # Connect cycle and path - assert is_isomorphic(G, expected) - - def test_trivial_graph(self): - assert nx.number_of_nodes(nx.trivial_graph()) == 1 - - def test_turan_graph(self): - assert nx.number_of_edges(nx.turan_graph(13, 4)) == 63 - assert is_isomorphic( - nx.turan_graph(13, 4), nx.complete_multipartite_graph(3, 4, 3, 3) - ) - - def test_wheel_graph(self): - for n, G in [ - ("", nx.null_graph()), - (0, nx.null_graph()), - (1, nx.empty_graph(1)), - (2, nx.path_graph(2)), - (3, nx.complete_graph(3)), - (4, nx.complete_graph(4)), - ]: - g = nx.wheel_graph(n) - assert is_isomorphic(g, G) - - g = nx.wheel_graph(10) - assert sorted(d for n, d in g.degree()) == [3, 3, 3, 3, 3, 3, 3, 3, 3, 9] - - pytest.raises(nx.NetworkXError, nx.wheel_graph, 10, create_using=nx.DiGraph) - - mg = nx.wheel_graph(10, create_using=nx.MultiGraph()) - assert edges_equal(mg.edges(), g.edges()) - - G = nx.wheel_graph("abc") - assert len(G) == 3 - assert G.size() == 3 - - G = nx.wheel_graph("abcb") - assert len(G) == 3 - assert G.size() == 4 - G = nx.wheel_graph("abcb", nx.MultiGraph) - assert len(G) == 3 - assert G.size() == 6 - - def test_non_int_integers_for_wheel_graph(self): - np = pytest.importorskip("numpy") - G = nx.wheel_graph(np.int32(3)) - assert len(G) == 3 - assert G.size() == 3 - - def test_complete_0_partite_graph(self): - """Tests that the complete 0-partite graph is the null graph.""" - G = nx.complete_multipartite_graph() - H = nx.null_graph() - assert nodes_equal(G, H) - assert edges_equal(G.edges(), H.edges()) - - def test_complete_1_partite_graph(self): - """Tests that the complete 1-partite graph is the empty graph.""" - G = nx.complete_multipartite_graph(3) - H = nx.empty_graph(3) - assert nodes_equal(G, H) - assert edges_equal(G.edges(), H.edges()) - - def test_complete_2_partite_graph(self): - """Tests that the complete 2-partite graph is the complete bipartite - graph. - - """ - G = nx.complete_multipartite_graph(2, 3) - H = nx.complete_bipartite_graph(2, 3) - assert nodes_equal(G, H) - assert edges_equal(G.edges(), H.edges()) - - def test_complete_multipartite_graph(self): - """Tests for generating the complete multipartite graph.""" - G = nx.complete_multipartite_graph(2, 3, 4) - blocks = [(0, 1), (2, 3, 4), (5, 6, 7, 8)] - # Within each block, no two vertices should be adjacent. - for block in blocks: - for u, v in itertools.combinations_with_replacement(block, 2): - assert v not in G[u] - assert G.nodes[u] == G.nodes[v] - # Across blocks, all vertices should be adjacent. - for block1, block2 in itertools.combinations(blocks, 2): - for u, v in itertools.product(block1, block2): - assert v in G[u] - assert G.nodes[u] != G.nodes[v] - with pytest.raises(nx.NetworkXError, match="Negative number of nodes"): - nx.complete_multipartite_graph(2, -3, 4) - - def test_kneser_graph(self): - # the petersen graph is a special case of the kneser graph when n=5 and k=2 - assert is_isomorphic(nx.kneser_graph(5, 2), nx.petersen_graph()) - - # when k is 1, the kneser graph returns a complete graph with n vertices - for i in range(1, 7): - assert is_isomorphic(nx.kneser_graph(i, 1), nx.complete_graph(i)) - - # the kneser graph of n and n-1 is the empty graph with n vertices - for j in range(3, 7): - assert is_isomorphic(nx.kneser_graph(j, j - 1), nx.empty_graph(j)) - - # in general the number of edges of the kneser graph is equal to - # (n choose k) times (n-k choose k) divided by 2 - assert nx.number_of_edges(nx.kneser_graph(8, 3)) == 280 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_cographs.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_cographs.py deleted file mode 100644 index a71849b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_cographs.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.cographs` module.""" - -import networkx as nx - - -def test_random_cograph(): - n = 3 - G = nx.random_cograph(n) - - assert len(G) == 2**n - - # Every connected subgraph of G has diameter <= 2 - if nx.is_connected(G): - assert nx.diameter(G) <= 2 - else: - components = nx.connected_components(G) - for component in components: - assert nx.diameter(G.subgraph(component)) <= 2 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_community.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_community.py deleted file mode 100644 index 2fa107f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_community.py +++ /dev/null @@ -1,362 +0,0 @@ -import pytest - -import networkx as nx - - -def test_random_partition_graph(): - G = nx.random_partition_graph([3, 3, 3], 1, 0, seed=42) - C = G.graph["partition"] - assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}] - assert len(G) == 9 - assert len(list(G.edges())) == 9 - - G = nx.random_partition_graph([3, 3, 3], 0, 1) - C = G.graph["partition"] - assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}] - assert len(G) == 9 - assert len(list(G.edges())) == 27 - - G = nx.random_partition_graph([3, 3, 3], 1, 0, directed=True) - C = G.graph["partition"] - assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}] - assert len(G) == 9 - assert len(list(G.edges())) == 18 - - G = nx.random_partition_graph([3, 3, 3], 0, 1, directed=True) - C = G.graph["partition"] - assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}] - assert len(G) == 9 - assert len(list(G.edges())) == 54 - - G = nx.random_partition_graph([1, 2, 3, 4, 5], 0.5, 0.1) - C = G.graph["partition"] - assert C == [{0}, {1, 2}, {3, 4, 5}, {6, 7, 8, 9}, {10, 11, 12, 13, 14}] - assert len(G) == 15 - - rpg = nx.random_partition_graph - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 1.1, 0.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], -0.1, 0.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, 1.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, -0.1) - - -def test_planted_partition_graph(): - G = nx.planted_partition_graph(4, 3, 1, 0, seed=42) - C = G.graph["partition"] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 12 - - G = nx.planted_partition_graph(4, 3, 0, 1) - C = G.graph["partition"] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 54 - - G = nx.planted_partition_graph(10, 4, 0.5, 0.1, seed=42) - C = G.graph["partition"] - assert len(C) == 10 - assert len(G) == 40 - - G = nx.planted_partition_graph(4, 3, 1, 0, directed=True) - C = G.graph["partition"] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 24 - - G = nx.planted_partition_graph(4, 3, 0, 1, directed=True) - C = G.graph["partition"] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 108 - - G = nx.planted_partition_graph(10, 4, 0.5, 0.1, seed=42, directed=True) - C = G.graph["partition"] - assert len(C) == 10 - assert len(G) == 40 - - ppg = nx.planted_partition_graph - pytest.raises(nx.NetworkXError, ppg, 3, 3, 1.1, 0.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, -0.1, 0.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, 1.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, -0.1) - - -def test_relaxed_caveman_graph(): - G = nx.relaxed_caveman_graph(4, 3, 0) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 1) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 0.5) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 0.5, seed=42) - assert len(G) == 12 - - -def test_connected_caveman_graph(): - G = nx.connected_caveman_graph(4, 3) - assert len(G) == 12 - - G = nx.connected_caveman_graph(1, 5) - K5 = nx.complete_graph(5) - K5.remove_edge(3, 4) - assert nx.is_isomorphic(G, K5) - - # need at least 2 nodes in each clique - pytest.raises(nx.NetworkXError, nx.connected_caveman_graph, 4, 1) - - -def test_caveman_graph(): - G = nx.caveman_graph(4, 3) - assert len(G) == 12 - - G = nx.caveman_graph(5, 1) - E5 = nx.empty_graph(5) - assert nx.is_isomorphic(G, E5) - - G = nx.caveman_graph(1, 5) - K5 = nx.complete_graph(5) - assert nx.is_isomorphic(G, K5) - - -def test_gaussian_random_partition_graph(): - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01) - assert len(G) == 100 - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01, directed=True) - assert len(G) == 100 - G = nx.gaussian_random_partition_graph( - 100, 10, 10, 0.3, 0.01, directed=False, seed=42 - ) - assert len(G) == 100 - assert not isinstance(G, nx.DiGraph) - G = nx.gaussian_random_partition_graph( - 100, 10, 10, 0.3, 0.01, directed=True, seed=42 - ) - assert len(G) == 100 - assert isinstance(G, nx.DiGraph) - pytest.raises( - nx.NetworkXError, nx.gaussian_random_partition_graph, 100, 101, 10, 1, 0 - ) - # Test when clusters are likely less than 1 - G = nx.gaussian_random_partition_graph(10, 0.5, 0.5, 0.5, 0.5, seed=1) - assert len(G) == 10 - - -def test_ring_of_cliques(): - for i in range(2, 20, 3): - for j in range(2, 20, 3): - G = nx.ring_of_cliques(i, j) - assert G.number_of_nodes() == i * j - if i != 2 or j != 1: - expected_num_edges = i * (((j * (j - 1)) // 2) + 1) - else: - # the edge that already exists cannot be duplicated - expected_num_edges = i * (((j * (j - 1)) // 2) + 1) - 1 - assert G.number_of_edges() == expected_num_edges - with pytest.raises( - nx.NetworkXError, match="A ring of cliques must have at least two cliques" - ): - nx.ring_of_cliques(1, 5) - with pytest.raises( - nx.NetworkXError, match="The cliques must have at least two nodes" - ): - nx.ring_of_cliques(3, 0) - - -def test_windmill_graph(): - for n in range(2, 20, 3): - for k in range(2, 20, 3): - G = nx.windmill_graph(n, k) - assert G.number_of_nodes() == (k - 1) * n + 1 - assert G.number_of_edges() == n * k * (k - 1) / 2 - assert G.degree(0) == G.number_of_nodes() - 1 - for i in range(1, G.number_of_nodes()): - assert G.degree(i) == k - 1 - with pytest.raises( - nx.NetworkXError, match="A windmill graph must have at least two cliques" - ): - nx.windmill_graph(1, 3) - with pytest.raises( - nx.NetworkXError, match="The cliques must have at least two nodes" - ): - nx.windmill_graph(3, 0) - - -def test_stochastic_block_model(): - sizes = [75, 75, 300] - probs = [[0.25, 0.05, 0.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]] - G = nx.stochastic_block_model(sizes, probs, seed=0) - C = G.graph["partition"] - assert len(C) == 3 - assert len(G) == 450 - assert G.size() == 22160 - - GG = nx.stochastic_block_model(sizes, probs, range(450), seed=0) - assert G.nodes == GG.nodes - - # Test Exceptions - sbm = nx.stochastic_block_model - badnodelist = list(range(400)) # not enough nodes to match sizes - badprobs1 = [[0.25, 0.05, 1.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]] - badprobs2 = [[0.25, 0.05, 0.02], [0.05, -0.35, 0.07], [0.02, 0.07, 0.40]] - probs_rect1 = [[0.25, 0.05, 0.02], [0.05, -0.35, 0.07]] - probs_rect2 = [[0.25, 0.05], [0.05, -0.35], [0.02, 0.07]] - asymprobs = [[0.25, 0.05, 0.01], [0.05, -0.35, 0.07], [0.02, 0.07, 0.40]] - pytest.raises(nx.NetworkXException, sbm, sizes, badprobs1) - pytest.raises(nx.NetworkXException, sbm, sizes, badprobs2) - pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect1, directed=True) - pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect2, directed=True) - pytest.raises(nx.NetworkXException, sbm, sizes, asymprobs, directed=False) - pytest.raises(nx.NetworkXException, sbm, sizes, probs, badnodelist) - nodelist = [0] + list(range(449)) # repeated node name in nodelist - pytest.raises(nx.NetworkXException, sbm, sizes, probs, nodelist) - - # Extra keyword arguments test - GG = nx.stochastic_block_model(sizes, probs, seed=0, selfloops=True) - assert G.nodes == GG.nodes - GG = nx.stochastic_block_model(sizes, probs, selfloops=True, directed=True) - assert G.nodes == GG.nodes - GG = nx.stochastic_block_model(sizes, probs, seed=0, sparse=False) - assert G.nodes == GG.nodes - - -def test_generator(): - n = 250 - tau1 = 3 - tau2 = 1.5 - mu = 0.1 - G = nx.LFR_benchmark_graph( - n, tau1, tau2, mu, average_degree=5, min_community=20, seed=10 - ) - assert len(G) == 250 - C = {frozenset(G.nodes[v]["community"]) for v in G} - assert nx.community.is_partition(G.nodes(), C) - - -def test_invalid_tau1(): - with pytest.raises(nx.NetworkXError, match="tau2 must be greater than one"): - n = 100 - tau1 = 2 - tau2 = 1 - mu = 0.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_invalid_tau2(): - with pytest.raises(nx.NetworkXError, match="tau1 must be greater than one"): - n = 100 - tau1 = 1 - tau2 = 2 - mu = 0.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_mu_too_large(): - with pytest.raises(nx.NetworkXError, match="mu must be in the interval \\[0, 1\\]"): - n = 100 - tau1 = 2 - tau2 = 2 - mu = 1.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_mu_too_small(): - with pytest.raises(nx.NetworkXError, match="mu must be in the interval \\[0, 1\\]"): - n = 100 - tau1 = 2 - tau2 = 2 - mu = -1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_both_degrees_none(): - with pytest.raises( - nx.NetworkXError, - match="Must assign exactly one of min_degree and average_degree", - ): - n = 100 - tau1 = 2 - tau2 = 2 - mu = 1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu) - - -def test_neither_degrees_none(): - with pytest.raises( - nx.NetworkXError, - match="Must assign exactly one of min_degree and average_degree", - ): - n = 100 - tau1 = 2 - tau2 = 2 - mu = 1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, average_degree=5) - - -def test_max_iters_exceeded(): - with pytest.raises( - nx.ExceededMaxIterations, - match="Could not assign communities; try increasing min_community", - ): - n = 10 - tau1 = 2 - tau2 = 2 - mu = 0.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, max_iters=10, seed=1) - - -def test_max_deg_out_of_range(): - with pytest.raises( - nx.NetworkXError, match="max_degree must be in the interval \\(0, n\\]" - ): - n = 10 - tau1 = 2 - tau2 = 2 - mu = 0.1 - nx.LFR_benchmark_graph( - n, tau1, tau2, mu, max_degree=n + 1, max_iters=10, seed=1 - ) - - -def test_max_community(): - n = 250 - tau1 = 3 - tau2 = 1.5 - mu = 0.1 - G = nx.LFR_benchmark_graph( - n, - tau1, - tau2, - mu, - average_degree=5, - max_degree=100, - min_community=50, - max_community=200, - seed=10, - ) - assert len(G) == 250 - C = {frozenset(G.nodes[v]["community"]) for v in G} - assert nx.community.is_partition(G.nodes(), C) - - -def test_powerlaw_iterations_exceeded(): - with pytest.raises( - nx.ExceededMaxIterations, match="Could not create power law sequence" - ): - n = 100 - tau1 = 2 - tau2 = 2 - mu = 1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, max_iters=0) - - -def test_no_scipy_zeta(): - zeta2 = 1.6449340668482264 - assert abs(zeta2 - nx.generators.community._hurwitz_zeta(2, 1, 0.0001)) < 0.01 - - -def test_generate_min_degree_itr(): - with pytest.raises( - nx.ExceededMaxIterations, match="Could not match average_degree" - ): - nx.generators.community._generate_min_degree(2, 2, 1, 0.01, 0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_degree_seq.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_degree_seq.py deleted file mode 100644 index 39ed59a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_degree_seq.py +++ /dev/null @@ -1,230 +0,0 @@ -import pytest - -import networkx as nx - - -class TestConfigurationModel: - """Unit tests for the :func:`~networkx.configuration_model` - function. - - """ - - def test_empty_degree_sequence(self): - """Tests that an empty degree sequence yields the null graph.""" - G = nx.configuration_model([]) - assert len(G) == 0 - - def test_degree_zero(self): - """Tests that a degree sequence of all zeros yields the empty - graph. - - """ - G = nx.configuration_model([0, 0, 0]) - assert len(G) == 3 - assert G.number_of_edges() == 0 - - def test_degree_sequence(self): - """Tests that the degree sequence of the generated graph matches - the input degree sequence. - - """ - deg_seq = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - G = nx.configuration_model(deg_seq, seed=12345678) - assert sorted((d for n, d in G.degree()), reverse=True) == [ - 5, - 3, - 3, - 3, - 3, - 2, - 2, - 2, - 1, - 1, - 1, - ] - assert sorted((d for n, d in G.degree(range(len(deg_seq)))), reverse=True) == [ - 5, - 3, - 3, - 3, - 3, - 2, - 2, - 2, - 1, - 1, - 1, - ] - - def test_random_seed(self): - """Tests that each call with the same random seed generates the - same graph. - - """ - deg_seq = [3] * 12 - G1 = nx.configuration_model(deg_seq, seed=1000) - G2 = nx.configuration_model(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - G1 = nx.configuration_model(deg_seq, seed=10) - G2 = nx.configuration_model(deg_seq, seed=10) - assert nx.is_isomorphic(G1, G2) - - def test_directed_disallowed(self): - """Tests that attempting to create a configuration model graph - using a directed graph yields an exception. - - """ - with pytest.raises(nx.NetworkXNotImplemented): - nx.configuration_model([], create_using=nx.DiGraph()) - - def test_odd_degree_sum(self): - """Tests that a degree sequence whose sum is odd yields an - exception. - - """ - with pytest.raises(nx.NetworkXError): - nx.configuration_model([1, 2]) - - -def test_directed_configuration_raise_unequal(): - with pytest.raises(nx.NetworkXError): - zin = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1] - zout = [5, 3, 3, 3, 3, 2, 2, 2, 1, 2] - nx.directed_configuration_model(zin, zout) - - -def test_directed_configuration_model(): - G = nx.directed_configuration_model([], [], seed=0) - assert len(G) == 0 - - -def test_simple_directed_configuration_model(): - G = nx.directed_configuration_model([1, 1], [1, 1], seed=0) - assert len(G) == 2 - - -def test_expected_degree_graph_empty(): - # empty graph has empty degree sequence - deg_seq = [] - G = nx.expected_degree_graph(deg_seq) - assert dict(G.degree()) == {} - - -def test_expected_degree_graph(): - # test that fixed seed delivers the same graph - deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - G1 = nx.expected_degree_graph(deg_seq, seed=1000) - assert len(G1) == 12 - - G2 = nx.expected_degree_graph(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - - G1 = nx.expected_degree_graph(deg_seq, seed=10) - G2 = nx.expected_degree_graph(deg_seq, seed=10) - assert nx.is_isomorphic(G1, G2) - - -def test_expected_degree_graph_selfloops(): - deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - G1 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False) - G2 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False) - assert nx.is_isomorphic(G1, G2) - assert len(G1) == 12 - - -def test_expected_degree_graph_skew(): - deg_seq = [10, 2, 2, 2, 2] - G1 = nx.expected_degree_graph(deg_seq, seed=1000) - G2 = nx.expected_degree_graph(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - assert len(G1) == 5 - - -def test_havel_hakimi_construction(): - G = nx.havel_hakimi_graph([]) - assert len(G) == 0 - - z = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - z = ["A", 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - - z = [5, 4, 3, 3, 3, 2, 2, 2] - G = nx.havel_hakimi_graph(z) - G = nx.configuration_model(z) - z = [6, 5, 4, 4, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - - z = [10, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2] - - G = nx.havel_hakimi_graph(z) - - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z, create_using=nx.DiGraph()) - - -def test_directed_havel_hakimi(): - # Test range of valid directed degree sequences - n, r = 100, 10 - p = 1.0 / r - for i in range(r): - G1 = nx.erdos_renyi_graph(n, p * (i + 1), None, True) - din1 = [d for n, d in G1.in_degree()] - dout1 = [d for n, d in G1.out_degree()] - G2 = nx.directed_havel_hakimi_graph(din1, dout1) - din2 = [d for n, d in G2.in_degree()] - dout2 = [d for n, d in G2.out_degree()] - assert sorted(din1) == sorted(din2) - assert sorted(dout1) == sorted(dout2) - - # Test non-graphical sequence - dout = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [103, 102, 102, 102, 102, 102, 102, 102, 102, 102] - pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout) - # Test valid sequences - dout = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - din = [2, 2, 2, 2, 2, 2, 2, 2, 0, 2] - G2 = nx.directed_havel_hakimi_graph(din, dout) - dout2 = (d for n, d in G2.out_degree()) - din2 = (d for n, d in G2.in_degree()) - assert sorted(dout) == sorted(dout2) - assert sorted(din) == sorted(din2) - # Test unequal sums - din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] - pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout) - # Test for negative values - din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2] - pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout) - - -def test_degree_sequence_tree(): - z = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - G = nx.degree_sequence_tree(z) - assert len(G) == len(z) - assert len(list(G.edges())) == sum(z) / 2 - - pytest.raises( - nx.NetworkXError, nx.degree_sequence_tree, z, create_using=nx.DiGraph() - ) - - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - pytest.raises(nx.NetworkXError, nx.degree_sequence_tree, z) - - -def test_random_degree_sequence_graph(): - d = [1, 2, 2, 3] - G = nx.random_degree_sequence_graph(d, seed=42) - assert d == sorted(d for n, d in G.degree()) - - -def test_random_degree_sequence_graph_raise(): - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - pytest.raises(nx.NetworkXUnfeasible, nx.random_degree_sequence_graph, z) - - -def test_random_degree_sequence_large(): - G1 = nx.fast_gnp_random_graph(100, 0.1, seed=42) - d1 = (d for n, d in G1.degree()) - G2 = nx.random_degree_sequence_graph(d1, seed=42) - d2 = (d for n, d in G2.degree()) - assert sorted(d1) == sorted(d2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_directed.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_directed.py deleted file mode 100644 index 8078d9f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_directed.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Generators - Directed Graphs ----------------------------- -""" - -import pytest - -import networkx as nx -from networkx.classes import Graph, MultiDiGraph -from networkx.generators.directed import ( - gn_graph, - gnc_graph, - gnr_graph, - random_k_out_graph, - random_uniform_k_out_graph, - scale_free_graph, -) - - -class TestGeneratorsDirected: - def test_smoke_test_random_graphs(self): - gn_graph(100) - gnr_graph(100, 0.5) - gnc_graph(100) - scale_free_graph(100) - - gn_graph(100, seed=42) - gnr_graph(100, 0.5, seed=42) - gnc_graph(100, seed=42) - scale_free_graph(100, seed=42) - - def test_create_using_keyword_arguments(self): - pytest.raises(nx.NetworkXError, gn_graph, 100, create_using=Graph()) - pytest.raises(nx.NetworkXError, gnr_graph, 100, 0.5, create_using=Graph()) - pytest.raises(nx.NetworkXError, gnc_graph, 100, create_using=Graph()) - G = gn_graph(100, seed=1) - MG = gn_graph(100, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - G = gnr_graph(100, 0.5, seed=1) - MG = gnr_graph(100, 0.5, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - G = gnc_graph(100, seed=1) - MG = gnc_graph(100, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - - G = scale_free_graph( - 100, - alpha=0.3, - beta=0.4, - gamma=0.3, - delta_in=0.3, - delta_out=0.1, - initial_graph=nx.cycle_graph(4, create_using=MultiDiGraph), - seed=1, - ) - pytest.raises(ValueError, scale_free_graph, 100, 0.5, 0.4, 0.3) - pytest.raises(ValueError, scale_free_graph, 100, alpha=-0.3) - pytest.raises(ValueError, scale_free_graph, 100, beta=-0.3) - pytest.raises(ValueError, scale_free_graph, 100, gamma=-0.3) - - def test_parameters(self): - G = nx.DiGraph() - G.add_node(0) - - def kernel(x): - return x - - assert nx.is_isomorphic(gn_graph(1), G) - assert nx.is_isomorphic(gn_graph(1, kernel=kernel), G) - assert nx.is_isomorphic(gnc_graph(1), G) - assert nx.is_isomorphic(gnr_graph(1, 0.5), G) - - -def test_scale_free_graph_negative_delta(): - with pytest.raises(ValueError, match="delta_in must be >= 0."): - scale_free_graph(10, delta_in=-1) - with pytest.raises(ValueError, match="delta_out must be >= 0."): - scale_free_graph(10, delta_out=-1) - - -def test_non_numeric_ordering(): - G = MultiDiGraph([("a", "b"), ("b", "c"), ("c", "a")]) - s = scale_free_graph(3, initial_graph=G) - assert len(s) == 3 - assert len(s.edges) == 3 - - -@pytest.mark.parametrize("ig", (nx.Graph(), nx.DiGraph([(0, 1)]))) -def test_scale_free_graph_initial_graph_kwarg(ig): - with pytest.raises(nx.NetworkXError): - scale_free_graph(100, initial_graph=ig) - - -class TestRandomKOutGraph: - """Unit tests for the - :func:`~networkx.generators.directed.random_k_out_graph` function. - - """ - - def test_regularity(self): - """Tests that the generated graph is `k`-out-regular.""" - n = 10 - k = 3 - alpha = 1 - G = random_k_out_graph(n, k, alpha) - assert all(d == k for v, d in G.out_degree()) - G = random_k_out_graph(n, k, alpha, seed=42) - assert all(d == k for v, d in G.out_degree()) - - def test_no_self_loops(self): - """Tests for forbidding self-loops.""" - n = 10 - k = 3 - alpha = 1 - G = random_k_out_graph(n, k, alpha, self_loops=False) - assert nx.number_of_selfloops(G) == 0 - - def test_negative_alpha(self): - with pytest.raises(ValueError, match="alpha must be positive"): - random_k_out_graph(10, 3, -1) - - -class TestUniformRandomKOutGraph: - """Unit tests for the - :func:`~networkx.generators.directed.random_uniform_k_out_graph` - function. - - """ - - def test_regularity(self): - """Tests that the generated graph is `k`-out-regular.""" - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k) - assert all(d == k for v, d in G.out_degree()) - G = random_uniform_k_out_graph(n, k, seed=42) - assert all(d == k for v, d in G.out_degree()) - - def test_no_self_loops(self): - """Tests for forbidding self-loops.""" - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, self_loops=False) - assert nx.number_of_selfloops(G) == 0 - assert all(d == k for v, d in G.out_degree()) - - def test_with_replacement(self): - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, with_replacement=True) - assert G.is_multigraph() - assert all(d == k for v, d in G.out_degree()) - n = 10 - k = 9 - G = random_uniform_k_out_graph(n, k, with_replacement=False, self_loops=False) - assert nx.number_of_selfloops(G) == 0 - assert all(d == k for v, d in G.out_degree()) - - def test_without_replacement(self): - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, with_replacement=False) - assert not G.is_multigraph() - assert all(d == k for v, d in G.out_degree()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_duplication.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_duplication.py deleted file mode 100644 index 9b6100b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_duplication.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.duplication` module.""" - -import pytest - -import networkx as nx - - -class TestDuplicationDivergenceGraph: - """Unit tests for the - :func:`networkx.generators.duplication.duplication_divergence_graph` - function. - - """ - - def test_final_size(self): - G = nx.duplication_divergence_graph(3, p=1) - assert len(G) == 3 - G = nx.duplication_divergence_graph(3, p=1, seed=42) - assert len(G) == 3 - - def test_probability_too_large(self): - with pytest.raises(nx.NetworkXError): - nx.duplication_divergence_graph(3, p=2) - - def test_probability_too_small(self): - with pytest.raises(nx.NetworkXError): - nx.duplication_divergence_graph(3, p=-1) - - def test_non_extreme_probability_value(self): - G = nx.duplication_divergence_graph(6, p=0.3, seed=42) - assert len(G) == 6 - assert list(G.degree()) == [(0, 2), (1, 3), (2, 2), (3, 3), (4, 1), (5, 1)] - - def test_minimum_desired_nodes(self): - with pytest.raises( - nx.NetworkXError, match=".*n must be greater than or equal to 2" - ): - nx.duplication_divergence_graph(1, p=1) - - def test_create_using(self): - class DummyGraph(nx.Graph): - pass - - class DummyDiGraph(nx.DiGraph): - pass - - G = nx.duplication_divergence_graph(6, 0.3, seed=42, create_using=DummyGraph) - assert isinstance(G, DummyGraph) - with pytest.raises(nx.NetworkXError, match="create_using must not be directed"): - nx.duplication_divergence_graph(6, 0.3, seed=42, create_using=DummyDiGraph) - - -class TestPartialDuplicationGraph: - """Unit tests for the - :func:`networkx.generators.duplication.partial_duplication_graph` - function. - - """ - - def test_final_size(self): - N = 10 - n = 5 - p = 0.5 - q = 0.5 - G = nx.partial_duplication_graph(N, n, p, q) - assert len(G) == N - G = nx.partial_duplication_graph(N, n, p, q, seed=42) - assert len(G) == N - - def test_initial_clique_size(self): - N = 10 - n = 10 - p = 0.5 - q = 0.5 - G = nx.partial_duplication_graph(N, n, p, q) - assert len(G) == n - - def test_invalid_initial_size(self): - with pytest.raises(nx.NetworkXError): - N = 5 - n = 10 - p = 0.5 - q = 0.5 - G = nx.partial_duplication_graph(N, n, p, q) - - def test_invalid_probabilities(self): - N = 1 - n = 1 - for p, q in [(0.5, 2), (0.5, -1), (2, 0.5), (-1, 0.5)]: - args = (N, n, p, q) - pytest.raises(nx.NetworkXError, nx.partial_duplication_graph, *args) - - def test_create_using(self): - class DummyGraph(nx.Graph): - pass - - class DummyDiGraph(nx.DiGraph): - pass - - G = nx.partial_duplication_graph(10, 5, 0.5, 0.5, create_using=DummyGraph) - assert isinstance(G, DummyGraph) - with pytest.raises(nx.NetworkXError, match="create_using must not be directed"): - nx.partial_duplication_graph(10, 5, 0.5, 0.5, create_using=DummyDiGraph) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_ego.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_ego.py deleted file mode 100644 index f6fc779..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_ego.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -ego graph ---------- -""" - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -class TestGeneratorEgo: - def test_ego(self): - G = nx.star_graph(3) - H = nx.ego_graph(G, 0) - assert nx.is_isomorphic(G, H) - G.add_edge(1, 11) - G.add_edge(2, 22) - G.add_edge(3, 33) - H = nx.ego_graph(G, 0) - assert nx.is_isomorphic(nx.star_graph(3), H) - G = nx.path_graph(3) - H = nx.ego_graph(G, 0) - assert edges_equal(H.edges(), [(0, 1)]) - H = nx.ego_graph(G, 0, undirected=True) - assert edges_equal(H.edges(), [(0, 1)]) - H = nx.ego_graph(G, 0, center=False) - assert edges_equal(H.edges(), []) - - def test_ego_distance(self): - G = nx.Graph() - G.add_edge(0, 1, weight=2, distance=1) - G.add_edge(1, 2, weight=2, distance=2) - G.add_edge(2, 3, weight=2, distance=1) - assert nodes_equal(nx.ego_graph(G, 0, radius=3).nodes(), [0, 1, 2, 3]) - eg = nx.ego_graph(G, 0, radius=3, distance="weight") - assert nodes_equal(eg.nodes(), [0, 1]) - eg = nx.ego_graph(G, 0, radius=3, distance="weight", undirected=True) - assert nodes_equal(eg.nodes(), [0, 1]) - eg = nx.ego_graph(G, 0, radius=3, distance="distance") - assert nodes_equal(eg.nodes(), [0, 1, 2]) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_expanders.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_expanders.py deleted file mode 100644 index 7cebc58..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_expanders.py +++ /dev/null @@ -1,162 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.expanders` module.""" - -import pytest - -import networkx as nx - - -@pytest.mark.parametrize("n", (2, 3, 5, 6, 10)) -def test_margulis_gabber_galil_graph_properties(n): - g = nx.margulis_gabber_galil_graph(n) - assert g.number_of_nodes() == n * n - for node in g: - assert g.degree(node) == 8 - assert len(node) == 2 - for i in node: - assert int(i) == i - assert 0 <= i < n - - -@pytest.mark.parametrize("n", (2, 3, 5, 6, 10)) -def test_margulis_gabber_galil_graph_eigvals(n): - np = pytest.importorskip("numpy") - sp = pytest.importorskip("scipy") - - g = nx.margulis_gabber_galil_graph(n) - # Eigenvalues are already sorted using the scipy eigvalsh, - # but the implementation in numpy does not guarantee order. - w = sorted(sp.linalg.eigvalsh(nx.adjacency_matrix(g).toarray())) - assert w[-2] < 5 * np.sqrt(2) - - -@pytest.mark.parametrize("p", (3, 5, 7, 11)) # Primes -def test_chordal_cycle_graph(p): - """Test for the :func:`networkx.chordal_cycle_graph` function.""" - G = nx.chordal_cycle_graph(p) - assert len(G) == p - # TODO The second largest eigenvalue should be smaller than a constant, - # independent of the number of nodes in the graph: - # - # eigs = sorted(sp.linalg.eigvalsh(nx.adjacency_matrix(G).toarray())) - # assert_less(eigs[-2], ...) - # - - -@pytest.mark.parametrize("p", (3, 5, 7, 11, 13)) # Primes -def test_paley_graph(p): - """Test for the :func:`networkx.paley_graph` function.""" - G = nx.paley_graph(p) - # G has p nodes - assert len(G) == p - # G is (p-1)/2-regular - in_degrees = {G.in_degree(node) for node in G.nodes} - out_degrees = {G.out_degree(node) for node in G.nodes} - assert len(in_degrees) == 1 and in_degrees.pop() == (p - 1) // 2 - assert len(out_degrees) == 1 and out_degrees.pop() == (p - 1) // 2 - - # If p = 1 mod 4, -1 is a square mod 4 and therefore the - # edge in the Paley graph are symmetric. - if p % 4 == 1: - for u, v in G.edges: - assert (v, u) in G.edges - - -@pytest.mark.parametrize("d, n", [(2, 7), (4, 10), (4, 16)]) -def test_maybe_regular_expander(d, n): - pytest.importorskip("numpy") - G = nx.maybe_regular_expander(n, d) - - assert len(G) == n, "Should have n nodes" - assert len(G.edges) == n * d / 2, "Should have n*d/2 edges" - assert nx.is_k_regular(G, d), "Should be d-regular" - - -@pytest.mark.parametrize("n", (3, 5, 6, 10)) -def test_is_regular_expander(n): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - G = nx.complete_graph(n) - - assert nx.is_regular_expander(G) == True, "Should be a regular expander" - - -@pytest.mark.parametrize("d, n", [(2, 7), (4, 10), (4, 16)]) -def test_random_regular_expander(d, n): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - G = nx.random_regular_expander_graph(n, d) - - assert len(G) == n, "Should have n nodes" - assert len(G.edges) == n * d / 2, "Should have n*d/2 edges" - assert nx.is_k_regular(G, d), "Should be d-regular" - assert nx.is_regular_expander(G) == True, "Should be a regular expander" - - -def test_random_regular_expander_explicit_construction(): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - G = nx.random_regular_expander_graph(d=4, n=5) - - assert len(G) == 5 and len(G.edges) == 10, "Should be a complete graph" - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph, nx.MultiDiGraph)) -def test_margulis_gabber_galil_graph_badinput(graph_type): - with pytest.raises( - nx.NetworkXError, match="`create_using` must be an undirected multigraph" - ): - nx.margulis_gabber_galil_graph(3, create_using=graph_type) - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph, nx.MultiDiGraph)) -def test_chordal_cycle_graph_badinput(graph_type): - with pytest.raises( - nx.NetworkXError, match="`create_using` must be an undirected multigraph" - ): - nx.chordal_cycle_graph(3, create_using=graph_type) - - -def test_paley_graph_badinput(): - with pytest.raises( - nx.NetworkXError, match="`create_using` cannot be a multigraph." - ): - nx.paley_graph(3, create_using=nx.MultiGraph) - - -def test_maybe_regular_expander_badinput(): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - - with pytest.raises(nx.NetworkXError, match="n must be a positive integer"): - nx.maybe_regular_expander(n=-1, d=2) - - with pytest.raises(nx.NetworkXError, match="d must be greater than or equal to 2"): - nx.maybe_regular_expander(n=10, d=0) - - with pytest.raises(nx.NetworkXError, match="Need n-1>= d to have room"): - nx.maybe_regular_expander(n=5, d=6) - - -def test_is_regular_expander_badinput(): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - - with pytest.raises(nx.NetworkXError, match="epsilon must be non negative"): - nx.is_regular_expander(nx.Graph(), epsilon=-1) - - -def test_random_regular_expander_badinput(): - pytest.importorskip("numpy") - pytest.importorskip("scipy") - - with pytest.raises(nx.NetworkXError, match="n must be a positive integer"): - nx.random_regular_expander_graph(n=-1, d=2) - - with pytest.raises(nx.NetworkXError, match="d must be greater than or equal to 2"): - nx.random_regular_expander_graph(n=10, d=0) - - with pytest.raises(nx.NetworkXError, match="Need n-1>= d to have room"): - nx.random_regular_expander_graph(n=5, d=6) - - with pytest.raises(nx.NetworkXError, match="epsilon must be non negative"): - nx.random_regular_expander_graph(n=4, d=2, epsilon=-1) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_geometric.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_geometric.py deleted file mode 100644 index f1c68be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_geometric.py +++ /dev/null @@ -1,488 +0,0 @@ -import math -import random -from itertools import combinations - -import pytest - -import networkx as nx - - -def l1dist(x, y): - return sum(abs(a - b) for a, b in zip(x, y)) - - -class TestRandomGeometricGraph: - """Unit tests for :func:`~networkx.random_geometric_graph`""" - - def test_number_of_nodes(self): - G = nx.random_geometric_graph(50, 0.25, seed=42) - assert len(G) == 50 - G = nx.random_geometric_graph(range(50), 0.25, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - """ - # Use the Euclidean metric, the default according to the - # documentation. - G = nx.random_geometric_graph(50, 0.25) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the generator.""" - # Use the L1 metric. - G = nx.random_geometric_graph(50, 0.25, p=1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert l1dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not l1dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs.""" - import string - - nodes = list(string.ascii_lowercase) - G = nx.random_geometric_graph(nodes, 0.25) - assert len(G) == len(nodes) - - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_pos_name(self): - G = nx.random_geometric_graph(50, 0.25, seed=42, pos_name="coords") - assert all(len(d["coords"]) == 2 for n, d in G.nodes.items()) - - -class TestSoftRandomGeometricGraph: - """Unit tests for :func:`~networkx.soft_random_geometric_graph`""" - - def test_number_of_nodes(self): - G = nx.soft_random_geometric_graph(50, 0.25, seed=42) - assert len(G) == 50 - G = nx.soft_random_geometric_graph(range(50), 0.25, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - """ - # Use the Euclidean metric, the default according to the - # documentation. - G = nx.soft_random_geometric_graph(50, 0.25) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the generator.""" - - # Use the L1 metric. - def dist(x, y): - return sum(abs(a - b) for a, b in zip(x, y)) - - G = nx.soft_random_geometric_graph(50, 0.25, p=1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs.""" - import string - - nodes = list(string.ascii_lowercase) - G = nx.soft_random_geometric_graph(nodes, 0.25) - assert len(G) == len(nodes) - - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_p_dist_default(self): - """Tests default p_dict = 0.5 returns graph with edge count <= RGG with - same n, radius, dim and positions - """ - nodes = 50 - dim = 2 - pos = {v: [random.random() for i in range(dim)] for v in range(nodes)} - RGG = nx.random_geometric_graph(50, 0.25, pos=pos) - SRGG = nx.soft_random_geometric_graph(50, 0.25, pos=pos) - assert len(SRGG.edges()) <= len(RGG.edges()) - - def test_p_dist_zero(self): - """Tests if p_dict = 0 returns disconnected graph with 0 edges""" - - def p_dist(dist): - return 0 - - G = nx.soft_random_geometric_graph(50, 0.25, p_dist=p_dist) - assert len(G.edges) == 0 - - def test_pos_name(self): - G = nx.soft_random_geometric_graph(50, 0.25, seed=42, pos_name="coords") - assert all(len(d["coords"]) == 2 for n, d in G.nodes.items()) - - -def join(G, u, v, theta, alpha, metric): - """Returns ``True`` if and only if the nodes whose attributes are - ``du`` and ``dv`` should be joined, according to the threshold - condition for geographical threshold graphs. - - ``G`` is an undirected NetworkX graph, and ``u`` and ``v`` are nodes - in that graph. The nodes must have node attributes ``'pos'`` and - ``'weight'``. - - ``metric`` is a distance metric. - """ - du, dv = G.nodes[u], G.nodes[v] - u_pos, v_pos = du["pos"], dv["pos"] - u_weight, v_weight = du["weight"], dv["weight"] - return (u_weight + v_weight) * metric(u_pos, v_pos) ** alpha >= theta - - -class TestGeographicalThresholdGraph: - """Unit tests for :func:`~networkx.geographical_threshold_graph`""" - - def test_number_of_nodes(self): - G = nx.geographical_threshold_graph(50, 100, seed=42) - assert len(G) == 50 - G = nx.geographical_threshold_graph(range(50), 100, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if their - distances meet the given threshold. - """ - # Use the Euclidean metric and alpha = -2 - # the default according to the documentation. - G = nx.geographical_threshold_graph(50, 10) - for u, v in combinations(G, 2): - # Adjacent vertices must exceed the threshold. - if v in G[u]: - assert join(G, u, v, 10, -2, math.dist) - # Nonadjacent vertices must not exceed the threshold. - else: - assert not join(G, u, v, 10, -2, math.dist) - - def test_metric(self): - """Tests for providing an alternate distance metric to the generator.""" - # Use the L1 metric. - G = nx.geographical_threshold_graph(50, 10, metric=l1dist) - for u, v in combinations(G, 2): - # Adjacent vertices must exceed the threshold. - if v in G[u]: - assert join(G, u, v, 10, -2, l1dist) - # Nonadjacent vertices must not exceed the threshold. - else: - assert not join(G, u, v, 10, -2, l1dist) - - def test_p_dist_zero(self): - """Tests if p_dict = 0 returns disconnected graph with 0 edges""" - - def p_dist(dist): - return 0 - - G = nx.geographical_threshold_graph(50, 1, p_dist=p_dist) - assert len(G.edges) == 0 - - def test_pos_weight_name(self): - gtg = nx.geographical_threshold_graph - G = gtg(50, 100, seed=42, pos_name="coords", weight_name="wt") - assert all(len(d["coords"]) == 2 for n, d in G.nodes.items()) - assert all(d["wt"] > 0 for n, d in G.nodes.items()) - - -class TestWaxmanGraph: - """Unit tests for the :func:`~networkx.waxman_graph` function.""" - - def test_number_of_nodes_1(self): - G = nx.waxman_graph(50, 0.5, 0.1, seed=42) - assert len(G) == 50 - G = nx.waxman_graph(range(50), 0.5, 0.1, seed=42) - assert len(G) == 50 - - def test_number_of_nodes_2(self): - G = nx.waxman_graph(50, 0.5, 0.1, L=1) - assert len(G) == 50 - G = nx.waxman_graph(range(50), 0.5, 0.1, L=1) - assert len(G) == 50 - - def test_metric(self): - """Tests for providing an alternate distance metric to the generator.""" - # Use the L1 metric. - G = nx.waxman_graph(50, 0.5, 0.1, metric=l1dist) - assert len(G) == 50 - - def test_pos_name(self): - G = nx.waxman_graph(50, 0.5, 0.1, seed=42, pos_name="coords") - assert all(len(d["coords"]) == 2 for n, d in G.nodes.items()) - - -class TestNavigableSmallWorldGraph: - def test_navigable_small_world(self): - G = nx.navigable_small_world_graph(5, p=1, q=0, seed=42) - gg = nx.grid_2d_graph(5, 5).to_directed() - assert nx.is_isomorphic(G, gg) - - G = nx.navigable_small_world_graph(5, p=1, q=0, dim=3) - gg = nx.grid_graph([5, 5, 5]).to_directed() - assert nx.is_isomorphic(G, gg) - - G = nx.navigable_small_world_graph(5, p=1, q=0, dim=1) - gg = nx.grid_graph([5]).to_directed() - assert nx.is_isomorphic(G, gg) - - def test_invalid_diameter_value(self): - with pytest.raises(nx.NetworkXException, match=".*p must be >= 1"): - nx.navigable_small_world_graph(5, p=0, q=0, dim=1) - - def test_invalid_long_range_connections_value(self): - with pytest.raises(nx.NetworkXException, match=".*q must be >= 0"): - nx.navigable_small_world_graph(5, p=1, q=-1, dim=1) - - def test_invalid_exponent_for_decaying_probability_value(self): - with pytest.raises(nx.NetworkXException, match=".*r must be >= 0"): - nx.navigable_small_world_graph(5, p=1, q=0, r=-1, dim=1) - - def test_r_between_0_and_1(self): - """Smoke test for radius in range [0, 1]""" - # q=0 means no long-range connections - G = nx.navigable_small_world_graph(3, p=1, q=0, r=0.5, dim=2, seed=42) - expected = nx.grid_2d_graph(3, 3, create_using=nx.DiGraph) - assert nx.utils.graphs_equal(G, expected) - - @pytest.mark.parametrize("seed", range(2478, 2578, 10)) - def test_r_general_scaling(self, seed): - """The probability of adding a long-range edge scales with `1 / dist**r`, - so a navigable_small_world graph created with r < 1 should generally - result in more edges than a navigable_small_world graph with r >= 1 - (for 0 < q << n). - - N.B. this is probabilistic, so this test may not hold for all seeds.""" - G1 = nx.navigable_small_world_graph(7, q=3, r=0.5, seed=seed) - G2 = nx.navigable_small_world_graph(7, q=3, r=1, seed=seed) - G3 = nx.navigable_small_world_graph(7, q=3, r=2, seed=seed) - assert G1.number_of_edges() > G2.number_of_edges() - assert G2.number_of_edges() > G3.number_of_edges() - - -class TestThresholdedRandomGeometricGraph: - """Unit tests for :func:`~networkx.thresholded_random_geometric_graph`""" - - def test_number_of_nodes(self): - G = nx.thresholded_random_geometric_graph(50, 0.2, 0.1, seed=42) - assert len(G) == 50 - G = nx.thresholded_random_geometric_graph(range(50), 0.2, 0.1, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - """ - # Use the Euclidean metric, the default according to the - # documentation. - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, seed=42) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the generator.""" - - # Use the L1 metric. - def dist(x, y): - return sum(abs(a - b) for a, b in zip(x, y)) - - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, p=1, seed=42) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs.""" - import string - - nodes = list(string.ascii_lowercase) - G = nx.thresholded_random_geometric_graph(nodes, 0.25, 0.1, seed=42) - assert len(G) == len(nodes) - - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25 - - def test_theta(self): - """Tests that pairs of vertices adjacent if and only if their sum - weights exceeds the threshold parameter theta. - """ - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, seed=42) - - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert (G.nodes[u]["weight"] + G.nodes[v]["weight"]) >= 0.1 - - def test_pos_name(self): - trgg = nx.thresholded_random_geometric_graph - G = trgg(50, 0.25, 0.1, seed=42, pos_name="p", weight_name="wt") - assert all(len(d["p"]) == 2 for n, d in G.nodes.items()) - assert all(d["wt"] > 0 for n, d in G.nodes.items()) - - -def test_geometric_edges_pos_attribute(): - G = nx.Graph() - G.add_nodes_from( - [ - (0, {"position": (0, 0)}), - (1, {"position": (0, 1)}), - (2, {"position": (1, 0)}), - ] - ) - expected_edges = [(0, 1), (0, 2)] - assert expected_edges == nx.geometric_edges(G, radius=1, pos_name="position") - - -def test_geometric_edges_raises_no_pos(): - G = nx.path_graph(3) - msg = "all nodes. must have a '" - with pytest.raises(nx.NetworkXError, match=msg): - nx.geometric_edges(G, radius=1) - - -def test_number_of_nodes_S1(): - G = nx.geometric_soft_configuration_graph( - beta=1.5, n=100, gamma=2.7, mean_degree=10, seed=42 - ) - assert len(G) == 100 - - -def test_set_attributes_S1(): - G = nx.geometric_soft_configuration_graph( - beta=1.5, n=100, gamma=2.7, mean_degree=10, seed=42 - ) - kappas = nx.get_node_attributes(G, "kappa") - assert len(kappas) == 100 - thetas = nx.get_node_attributes(G, "theta") - assert len(thetas) == 100 - radii = nx.get_node_attributes(G, "radius") - assert len(radii) == 100 - - -def test_mean_kappas_mean_degree_S1(): - G = nx.geometric_soft_configuration_graph( - beta=2.5, n=50, gamma=2.7, mean_degree=10, seed=8023 - ) - - kappas = nx.get_node_attributes(G, "kappa") - mean_kappas = sum(kappas.values()) / len(kappas) - assert math.fabs(mean_kappas - 10) < 0.5 - - degrees = dict(G.degree()) - mean_degree = sum(degrees.values()) / len(degrees) - assert math.fabs(mean_degree - 10) < 1 - - -def test_dict_kappas_S1(): - kappas = {i: 10 for i in range(1000)} - G = nx.geometric_soft_configuration_graph(beta=1, kappas=kappas) - assert len(G) == 1000 - kappas = nx.get_node_attributes(G, "kappa") - assert all(kappa == 10 for kappa in kappas.values()) - - -def test_beta_clustering_S1(): - G1 = nx.geometric_soft_configuration_graph( - beta=1.5, n=100, gamma=3.5, mean_degree=10, seed=42 - ) - G2 = nx.geometric_soft_configuration_graph( - beta=3.0, n=100, gamma=3.5, mean_degree=10, seed=42 - ) - assert nx.average_clustering(G1) < nx.average_clustering(G2) - - -def test_wrong_parameters_S1(): - with pytest.raises( - nx.NetworkXError, - match="Please provide either kappas, or all 3 of: n, gamma and mean_degree.", - ): - G = nx.geometric_soft_configuration_graph( - beta=1.5, gamma=3.5, mean_degree=10, seed=42 - ) - - with pytest.raises( - nx.NetworkXError, - match="When kappas is input, n, gamma and mean_degree must not be.", - ): - kappas = {i: 10 for i in range(1000)} - G = nx.geometric_soft_configuration_graph( - beta=1.5, kappas=kappas, gamma=2.3, seed=42 - ) - - with pytest.raises( - nx.NetworkXError, - match="Please provide either kappas, or all 3 of: n, gamma and mean_degree.", - ): - G = nx.geometric_soft_configuration_graph(beta=1.5, seed=42) - - -def test_negative_beta_S1(): - with pytest.raises( - nx.NetworkXError, match="The parameter beta cannot be smaller or equal to 0." - ): - G = nx.geometric_soft_configuration_graph( - beta=-1, n=100, gamma=2.3, mean_degree=10, seed=42 - ) - - -def test_non_zero_clustering_beta_lower_one_S1(): - G = nx.geometric_soft_configuration_graph( - beta=0.5, n=100, gamma=3.5, mean_degree=10, seed=42 - ) - assert nx.average_clustering(G) > 0 - - -def test_mean_degree_influence_on_connectivity_S1(): - low_mean_degree = 2 - high_mean_degree = 20 - G_low = nx.geometric_soft_configuration_graph( - beta=1.2, n=100, gamma=2.7, mean_degree=low_mean_degree, seed=42 - ) - G_high = nx.geometric_soft_configuration_graph( - beta=1.2, n=100, gamma=2.7, mean_degree=high_mean_degree, seed=42 - ) - assert nx.number_connected_components(G_low) > nx.number_connected_components( - G_high - ) - - -def test_compare_mean_kappas_different_gammas_S1(): - G1 = nx.geometric_soft_configuration_graph( - beta=1.5, n=20, gamma=2.7, mean_degree=5, seed=42 - ) - G2 = nx.geometric_soft_configuration_graph( - beta=1.5, n=20, gamma=3.5, mean_degree=5, seed=42 - ) - kappas1 = nx.get_node_attributes(G1, "kappa") - mean_kappas1 = sum(kappas1.values()) / len(kappas1) - kappas2 = nx.get_node_attributes(G2, "kappa") - mean_kappas2 = sum(kappas2.values()) / len(kappas2) - assert math.fabs(mean_kappas1 - mean_kappas2) < 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_harary_graph.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_harary_graph.py deleted file mode 100644 index 8a0142d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_harary_graph.py +++ /dev/null @@ -1,133 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.harary_graph` module.""" - -import pytest - -import networkx as nx -from networkx.algorithms.isomorphism.isomorph import is_isomorphic -from networkx.generators.harary_graph import hkn_harary_graph, hnm_harary_graph - - -class TestHararyGraph: - """ - Suppose n nodes, m >= n-1 edges, d = 2m // n, r = 2m % n - """ - - def test_hnm_harary_graph(self): - # When d is even and r = 0, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,d/2+1))) - for n, m in [(5, 5), (6, 12), (7, 14)]: - G1 = hnm_harary_graph(n, m) - d = 2 * m // n - G2 = nx.circulant_graph(n, list(range(1, d // 2 + 1))) - assert is_isomorphic(G1, G2) - - # When d is even and r > 0, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,d/2+1))) - # with r edges added arbitrarily - for n, m in [(5, 7), (6, 13), (7, 16)]: - G1 = hnm_harary_graph(n, m) - d = 2 * m // n - G2 = nx.circulant_graph(n, list(range(1, d // 2 + 1))) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # When d is odd and n is even and r = 0, the hnm_harary_graph(n,m) - # is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2]) - for n, m in [(6, 9), (8, 12), (10, 15)]: - G1 = hnm_harary_graph(n, m) - d = 2 * m // n - L = list(range(1, (d + 1) // 2)) - L.append(n // 2) - G2 = nx.circulant_graph(n, L) - assert is_isomorphic(G1, G2) - - # When d is odd and n is even and r > 0, the hnm_harary_graph(n,m) - # is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2]) - # with r edges added arbitrarily - for n, m in [(6, 10), (8, 13), (10, 17)]: - G1 = hnm_harary_graph(n, m) - d = 2 * m // n - L = list(range(1, (d + 1) // 2)) - L.append(n // 2) - G2 = nx.circulant_graph(n, L) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # When d is odd and n is odd, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,(d+1)/2)) - # with m - n*(d-1)/2 edges added arbitrarily - for n, m in [(5, 4), (7, 12), (9, 14)]: - G1 = hnm_harary_graph(n, m) - d = 2 * m // n - L = list(range(1, (d + 1) // 2)) - G2 = nx.circulant_graph(n, L) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # Raise NetworkXError if n<1 - n = 0 - m = 0 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - # Raise NetworkXError if m < n-1 - n = 6 - m = 4 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - # Raise NetworkXError if m > n(n-1)/2 - n = 6 - m = 16 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - """ - Suppose connectivity k, number of nodes n - """ - - def test_hkn_harary_graph(self): - # When k == 1, the hkn_harary_graph(k,n) is - # the path_graph(n) - for k, n in [(1, 6), (1, 7)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.path_graph(n) - assert is_isomorphic(G1, G2) - - # When k is even, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,k/2+1))) - for k, n in [(2, 6), (2, 7), (4, 6), (4, 7)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.circulant_graph(n, list(range(1, k // 2 + 1))) - assert is_isomorphic(G1, G2) - - # When k is odd and n is even, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,(k+1)/2)) plus [n/2]) - for k, n in [(3, 6), (5, 8), (7, 10)]: - G1 = hkn_harary_graph(k, n) - L = list(range(1, (k + 1) // 2)) - L.append(n // 2) - G2 = nx.circulant_graph(n, L) - assert is_isomorphic(G1, G2) - - # When k is odd and n is odd, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,(k+1)/2))) with - # n//2+1 edges added between node i and node i+n//2+1 - for k, n in [(3, 5), (5, 9), (7, 11)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.circulant_graph(n, list(range(1, (k + 1) // 2))) - eSet1 = set(G1.edges) - eSet2 = set(G2.edges) - eSet3 = set() - half = n // 2 - for i in range(half + 1): - # add half+1 edges between i and i+half - eSet3.add((i, (i + half) % n)) - assert eSet1 == eSet2 | eSet3 - - # Raise NetworkXError if k<1 - k = 0 - n = 0 - pytest.raises(nx.NetworkXError, hkn_harary_graph, k, n) - - # Raise NetworkXError if ndegree_count[1]*degree_count[4] - joint_degrees_3 = { - 1: {4: 2}, - 2: {2: 2, 3: 2, 4: 2}, - 3: {2: 2, 4: 1}, - 4: {1: 2, 2: 2, 3: 1}, - } - assert not is_valid_joint_degree(joint_degrees_3) - - # test condition 5 - # joint_degrees_5[1][1] not even - joint_degrees_5 = {1: {1: 9}} - assert not is_valid_joint_degree(joint_degrees_5) - - -def test_joint_degree_graph(ntimes=10): - for _ in range(ntimes): - seed = int(time.time()) - - n, m, p = 20, 10, 1 - # generate random graph with model powerlaw_cluster and calculate - # its joint degree - g = powerlaw_cluster_graph(n, m, p, seed=seed) - joint_degrees_g = degree_mixing_dict(g, normalized=False) - - # generate simple undirected graph with given joint degree - # joint_degrees_g - G = joint_degree_graph(joint_degrees_g) - joint_degrees_G = degree_mixing_dict(G, normalized=False) - - # assert that the given joint degree is equal to the generated - # graph's joint degree - assert joint_degrees_g == joint_degrees_G - - -def test_is_valid_directed_joint_degree(): - in_degrees = [0, 1, 1, 2] - out_degrees = [1, 1, 1, 1] - nkk = {1: {1: 2, 2: 2}} - assert is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, values are not integers. - nkk = {1: {1: 1.5, 2: 2.5}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, number of edges between 1-2 are insufficient. - nkk = {1: {1: 2, 2: 1}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, in/out degree sequences have different number of nodes. - out_degrees = [1, 1, 1] - nkk = {1: {1: 2, 2: 2}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, degree sequences have fewer than required nodes. - in_degrees = [0, 1, 2] - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - -def test_directed_joint_degree_graph(n=15, m=100, ntimes=1000): - for _ in range(ntimes): - # generate gnm random graph and calculate its joint degree. - g = gnm_random_graph(n, m, None, directed=True) - - # in-degree sequence of g as a list of integers. - in_degrees = list(dict(g.in_degree()).values()) - # out-degree sequence of g as a list of integers. - out_degrees = list(dict(g.out_degree()).values()) - nkk = degree_mixing_dict(g) - - # generate simple directed graph with given degree sequence and joint - # degree matrix. - G = directed_joint_degree_graph(in_degrees, out_degrees, nkk) - - # assert degree sequence correctness. - assert in_degrees == list(dict(G.in_degree()).values()) - assert out_degrees == list(dict(G.out_degree()).values()) - # assert joint degree matrix correctness. - assert nkk == degree_mixing_dict(G) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_lattice.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_lattice.py deleted file mode 100644 index 5012324..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_lattice.py +++ /dev/null @@ -1,246 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.lattice` module.""" - -from itertools import product - -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -class TestGrid2DGraph: - """Unit tests for :func:`networkx.generators.lattice.grid_2d_graph`""" - - def test_number_of_vertices(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - assert len(G) == m * n - - def test_degree_distribution(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - expected_histogram = [0, 0, 4, 2 * (m + n) - 8, (m - 2) * (n - 2)] - assert nx.degree_histogram(G) == expected_histogram - - def test_directed(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - H = nx.grid_2d_graph(m, n, create_using=nx.DiGraph()) - assert H.succ == G.adj - assert H.pred == G.adj - - def test_multigraph(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - H = nx.grid_2d_graph(m, n, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.grid_2d_graph(0, 0, periodic=True) - assert dict(G.degree()) == {} - - for m, n, H in [ - (2, 2, nx.cycle_graph(4)), - (1, 7, nx.cycle_graph(7)), - (7, 1, nx.cycle_graph(7)), - (2, 5, nx.circular_ladder_graph(5)), - (5, 2, nx.circular_ladder_graph(5)), - (2, 4, nx.cubical_graph()), - (4, 2, nx.cubical_graph()), - ]: - G = nx.grid_2d_graph(m, n, periodic=True) - assert nx.could_be_isomorphic(G, H) - - def test_periodic_iterable(self): - m, n = 3, 7 - for a, b in product([0, 1], [0, 1]): - G = nx.grid_2d_graph(m, n, periodic=(a, b)) - assert G.number_of_nodes() == m * n - assert G.number_of_edges() == (m + a - 1) * n + (n + b - 1) * m - - def test_periodic_directed(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.DiGraph()) - assert H.succ == G.adj - assert H.pred == G.adj - - def test_periodic_multigraph(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.MultiGraph()) - assert list(G.edges()) == list(H.edges()) - - def test_exceptions(self): - pytest.raises(nx.NetworkXError, nx.grid_2d_graph, -3, 2) - pytest.raises(nx.NetworkXError, nx.grid_2d_graph, 3, -2) - pytest.raises(TypeError, nx.grid_2d_graph, 3.3, 2) - pytest.raises(TypeError, nx.grid_2d_graph, 3, 2.2) - - def test_node_input(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(range(4), range(2), periodic=True) - assert nx.is_isomorphic(H, G) - H = nx.grid_2d_graph("abcd", "ef", periodic=True) - assert nx.is_isomorphic(H, G) - G = nx.grid_2d_graph(5, 6) - H = nx.grid_2d_graph(range(5), range(6)) - assert edges_equal(H, G) - - -class TestGridGraph: - """Unit tests for :func:`networkx.generators.lattice.grid_graph`""" - - def test_grid_graph(self): - """grid_graph([n,m]) is a connected simple graph with the - following properties: - number_of_nodes = n*m - degree_histogram = [0,0,4,2*(n+m)-8,(n-2)*(m-2)] - """ - for n, m in [(3, 5), (5, 3), (4, 5), (5, 4)]: - dim = [n, m] - g = nx.grid_graph(dim) - assert len(g) == n * m - assert nx.degree_histogram(g) == [ - 0, - 0, - 4, - 2 * (n + m) - 8, - (n - 2) * (m - 2), - ] - - for n, m in [(1, 5), (5, 1)]: - dim = [n, m] - g = nx.grid_graph(dim) - assert len(g) == n * m - assert nx.is_isomorphic(g, nx.path_graph(5)) - - # mg = nx.grid_graph([n,m], create_using=MultiGraph()) - # assert_equal(mg.edges(), g.edges()) - - def test_node_input(self): - G = nx.grid_graph([range(7, 9), range(3, 6)]) - assert len(G) == 2 * 3 - assert nx.is_isomorphic(G, nx.grid_graph([2, 3])) - - def test_periodic_iterable(self): - m, n, k = 3, 7, 5 - for a, b, c in product([0, 1], [0, 1], [0, 1]): - G = nx.grid_graph([m, n, k], periodic=(a, b, c)) - num_e = (m + a - 1) * n * k + (n + b - 1) * m * k + (k + c - 1) * m * n - assert G.number_of_nodes() == m * n * k - assert G.number_of_edges() == num_e - - -class TestHypercubeGraph: - """Unit tests for :func:`networkx.generators.lattice.hypercube_graph`""" - - def test_special_cases(self): - for n, H in [ - (0, nx.null_graph()), - (1, nx.path_graph(2)), - (2, nx.cycle_graph(4)), - (3, nx.cubical_graph()), - ]: - G = nx.hypercube_graph(n) - assert nx.could_be_isomorphic(G, H) - - def test_degree_distribution(self): - for n in range(1, 10): - G = nx.hypercube_graph(n) - expected_histogram = [0] * n + [2**n] - assert nx.degree_histogram(G) == expected_histogram - - -class TestTriangularLatticeGraph: - "Tests for :func:`networkx.generators.lattice.triangular_lattice_graph`" - - def test_lattice_points(self): - """Tests that the graph is really a triangular lattice.""" - for m, n in [(2, 3), (2, 2), (2, 1), (3, 3), (3, 2), (3, 4)]: - G = nx.triangular_lattice_graph(m, n) - N = (n + 1) // 2 - assert len(G) == (m + 1) * (1 + N) - (n % 2) * ((m + 1) // 2) - for i, j in G.nodes(): - nbrs = G[(i, j)] - if i < N: - assert (i + 1, j) in nbrs - if j < m: - assert (i, j + 1) in nbrs - if j < m and (i > 0 or j % 2) and (i < N or (j + 1) % 2): - assert (i + 1, j + 1) in nbrs or (i - 1, j + 1) in nbrs - - def test_directed(self): - """Tests for creating a directed triangular lattice.""" - G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph()) - H = nx.triangular_lattice_graph(3, 4, create_using=nx.DiGraph()) - assert H.is_directed() - for u, v in H.edges(): - assert v[1] >= u[1] - if v[1] == u[1]: - assert v[0] > u[0] - - def test_multigraph(self): - """Tests for creating a triangular lattice multigraph.""" - G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph()) - H = nx.triangular_lattice_graph(3, 4, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.triangular_lattice_graph(4, 6, periodic=True) - assert len(G) == 12 - assert G.size() == 36 - # all degrees are 6 - assert len([n for n, d in G.degree() if d != 6]) == 0 - G = nx.triangular_lattice_graph(5, 7, periodic=True) - TLG = nx.triangular_lattice_graph - pytest.raises(nx.NetworkXError, TLG, 2, 4, periodic=True) - pytest.raises(nx.NetworkXError, TLG, 4, 4, periodic=True) - pytest.raises(nx.NetworkXError, TLG, 2, 6, periodic=True) - - -class TestHexagonalLatticeGraph: - "Tests for :func:`networkx.generators.lattice.hexagonal_lattice_graph`" - - def test_lattice_points(self): - """Tests that the graph is really a hexagonal lattice.""" - for m, n in [(4, 5), (4, 4), (4, 3), (3, 2), (3, 3), (3, 5)]: - G = nx.hexagonal_lattice_graph(m, n) - assert len(G) == 2 * (m + 1) * (n + 1) - 2 - C_6 = nx.cycle_graph(6) - hexagons = [ - [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)], - [(0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4)], - [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)], - [(2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)], - [(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4)], - ] - for hexagon in hexagons: - assert nx.is_isomorphic(G.subgraph(hexagon), C_6) - - def test_directed(self): - """Tests for creating a directed hexagonal lattice.""" - G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph()) - H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.DiGraph()) - assert H.is_directed() - pos = nx.get_node_attributes(H, "pos") - for u, v in H.edges(): - assert pos[v][1] >= pos[u][1] - if pos[v][1] == pos[u][1]: - assert pos[v][0] > pos[u][0] - - def test_multigraph(self): - """Tests for creating a hexagonal lattice multigraph.""" - G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph()) - H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.hexagonal_lattice_graph(4, 6, periodic=True) - assert len(G) == 48 - assert G.size() == 72 - # all degrees are 3 - assert len([n for n, d in G.degree() if d != 3]) == 0 - G = nx.hexagonal_lattice_graph(5, 8, periodic=True) - HLG = nx.hexagonal_lattice_graph - pytest.raises(nx.NetworkXError, HLG, 2, 7, periodic=True) - pytest.raises(nx.NetworkXError, HLG, 1, 4, periodic=True) - pytest.raises(nx.NetworkXError, HLG, 2, 1, periodic=True) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_line.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_line.py deleted file mode 100644 index 7f5454e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_line.py +++ /dev/null @@ -1,309 +0,0 @@ -import pytest - -import networkx as nx -from networkx.generators import line -from networkx.utils import edges_equal - - -class TestGeneratorLine: - def test_star(self): - G = nx.star_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, nx.complete_graph(5)) - - def test_path(self): - G = nx.path_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, nx.path_graph(4)) - - def test_cycle(self): - G = nx.cycle_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, G) - - def test_digraph1(self): - G = nx.DiGraph([(0, 1), (0, 2), (0, 3)]) - L = nx.line_graph(G) - # no edge graph, but with nodes - assert L.adj == {(0, 1): {}, (0, 2): {}, (0, 3): {}} - - def test_multigraph1(self): - G = nx.MultiGraph([(0, 1), (0, 1), (1, 0), (0, 2), (2, 0), (0, 3)]) - L = nx.line_graph(G) - # no edge graph, but with nodes - assert edges_equal( - L.edges(), - [ - ((0, 3, 0), (0, 1, 0)), - ((0, 3, 0), (0, 2, 0)), - ((0, 3, 0), (0, 2, 1)), - ((0, 3, 0), (0, 1, 1)), - ((0, 3, 0), (0, 1, 2)), - ((0, 1, 0), (0, 1, 1)), - ((0, 1, 0), (0, 2, 0)), - ((0, 1, 0), (0, 1, 2)), - ((0, 1, 0), (0, 2, 1)), - ((0, 1, 1), (0, 1, 2)), - ((0, 1, 1), (0, 2, 0)), - ((0, 1, 1), (0, 2, 1)), - ((0, 1, 2), (0, 2, 0)), - ((0, 1, 2), (0, 2, 1)), - ((0, 2, 0), (0, 2, 1)), - ], - ) - - def test_multigraph2(self): - G = nx.MultiGraph([(1, 2), (2, 1)]) - L = nx.line_graph(G) - assert edges_equal(L.edges(), [((1, 2, 0), (1, 2, 1))]) - - def test_multidigraph1(self): - G = nx.MultiDiGraph([(1, 2), (2, 1)]) - L = nx.line_graph(G) - assert edges_equal(L.edges(), [((1, 2, 0), (2, 1, 0)), ((2, 1, 0), (1, 2, 0))]) - - def test_multidigraph2(self): - G = nx.MultiDiGraph([(0, 1), (0, 1), (0, 1), (1, 2)]) - L = nx.line_graph(G) - assert edges_equal( - L.edges(), - [((0, 1, 0), (1, 2, 0)), ((0, 1, 1), (1, 2, 0)), ((0, 1, 2), (1, 2, 0))], - ) - - def test_digraph2(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G) - assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - def test_create1(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G, create_using=nx.Graph()) - assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - def test_create2(self): - G = nx.Graph([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G, create_using=nx.DiGraph()) - assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - -class TestGeneratorInverseLine: - def test_example(self): - G = nx.Graph() - G_edges = [ - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [2, 3], - [2, 5], - [2, 6], - [2, 7], - [3, 4], - [3, 5], - [6, 7], - [6, 8], - [7, 8], - ] - G.add_edges_from(G_edges) - H = nx.inverse_line_graph(G) - solution = nx.Graph() - solution_edges = [ - ("a", "b"), - ("a", "c"), - ("a", "d"), - ("a", "e"), - ("c", "d"), - ("e", "f"), - ("e", "g"), - ("f", "g"), - ] - solution.add_edges_from(solution_edges) - assert nx.is_isomorphic(H, solution) - - def test_example_2(self): - G = nx.Graph() - G_edges = [[1, 2], [1, 3], [2, 3], [3, 4], [3, 5], [4, 5]] - G.add_edges_from(G_edges) - H = nx.inverse_line_graph(G) - solution = nx.Graph() - solution_edges = [("a", "c"), ("b", "c"), ("c", "d"), ("d", "e"), ("d", "f")] - solution.add_edges_from(solution_edges) - assert nx.is_isomorphic(H, solution) - - def test_pair(self): - G = nx.path_graph(2) - H = nx.inverse_line_graph(G) - solution = nx.path_graph(3) - assert nx.is_isomorphic(H, solution) - - def test_line(self): - G = nx.path_graph(5) - solution = nx.path_graph(6) - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, solution) - - def test_triangle_graph(self): - G = nx.complete_graph(3) - H = nx.inverse_line_graph(G) - alternative_solution = nx.Graph() - alternative_solution.add_edges_from([[0, 1], [0, 2], [0, 3]]) - # there are two alternative inverse line graphs for this case - # so long as we get one of them the test should pass - assert nx.is_isomorphic(H, G) or nx.is_isomorphic(H, alternative_solution) - - def test_cycle(self): - G = nx.cycle_graph(5) - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, G) - - def test_empty(self): - G = nx.Graph() - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, nx.complete_graph(1)) - - def test_K1(self): - G = nx.complete_graph(1) - H = nx.inverse_line_graph(G) - solution = nx.path_graph(2) - assert nx.is_isomorphic(H, solution) - - def test_edgeless_graph(self): - G = nx.empty_graph(5) - with pytest.raises(nx.NetworkXError, match="edgeless graph"): - nx.inverse_line_graph(G) - - def test_selfloops_error(self): - G = nx.cycle_graph(4) - G.add_edge(0, 0) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - def test_non_line_graphs(self): - # Tests several known non-line graphs for impossibility - # Adapted from L.W.Beineke, "Characterizations of derived graphs" - - # claw graph - claw = nx.star_graph(3) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, claw) - - # wheel graph with 6 nodes - wheel = nx.wheel_graph(6) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, wheel) - - # K5 with one edge remove - K5m = nx.complete_graph(5) - K5m.remove_edge(0, 1) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, K5m) - - # graph without any odd triangles (contains claw as induced subgraph) - G = nx.compose(nx.path_graph(2), nx.complete_bipartite_graph(2, 3)) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - ## Variations on a diamond graph - - # Diamond + 2 edges (+ "roof") - G = nx.diamond_graph() - G.add_edges_from([(4, 0), (5, 3)]) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - G.add_edge(4, 5) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - # Diamond + 2 connected edges - G = nx.diamond_graph() - G.add_edges_from([(4, 0), (4, 3)]) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - # Diamond + K3 + one edge (+ 2*K3) - G = nx.diamond_graph() - G.add_edges_from([(4, 0), (4, 1), (4, 2), (5, 3)]) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - G.add_edges_from([(5, 1), (5, 2)]) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - # 4 triangles - G = nx.diamond_graph() - G.add_edges_from([(4, 0), (4, 1), (5, 2), (5, 3)]) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - def test_wrong_graph_type(self): - G = nx.DiGraph() - G_edges = [[0, 1], [0, 2], [0, 3]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G) - - G = nx.MultiGraph() - G_edges = [[0, 1], [0, 2], [0, 3]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G) - - def test_line_inverse_line_complete(self): - G = nx.complete_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_path(self): - G = nx.path_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_hypercube(self): - G = nx.hypercube_graph(5) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_cycle(self): - G = nx.cycle_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_star(self): - G = nx.star_graph(20) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_multipartite(self): - G = nx.complete_multipartite_graph(3, 4, 5) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_dgm(self): - G = nx.dorogovtsev_goltsev_mendes_graph(4) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_different_node_types(self): - G = nx.path_graph([1, 2, 3, "a", "b", "c"]) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - -class TestGeneratorPrivateFunctions: - def test_triangles_error(self): - G = nx.diamond_graph() - pytest.raises(nx.NetworkXError, line._triangles, G, (4, 0)) - pytest.raises(nx.NetworkXError, line._triangles, G, (0, 3)) - - def test_odd_triangles_error(self): - G = nx.diamond_graph() - pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 4)) - pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 3)) - - def test_select_starting_cell_error(self): - G = nx.diamond_graph() - pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (4, 0)) - pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (0, 3)) - - def test_diamond_graph(self): - G = nx.diamond_graph() - for edge in G.edges: - cell = line._select_starting_cell(G, starting_edge=edge) - # Starting cell should always be one of the two triangles - assert len(cell) == 3 - assert all(v in G[u] for u in cell for v in cell if u != v) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_mycielski.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_mycielski.py deleted file mode 100644 index eb12b14..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_mycielski.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.mycielski` module.""" - -import pytest - -import networkx as nx - - -class TestMycielski: - def test_construction(self): - G = nx.path_graph(2) - M = nx.mycielskian(G) - assert nx.is_isomorphic(M, nx.cycle_graph(5)) - - def test_size(self): - G = nx.path_graph(2) - M = nx.mycielskian(G, 2) - assert len(M) == 11 - assert M.size() == 20 - - def test_mycielski_graph_generator(self): - G = nx.mycielski_graph(1) - assert nx.is_isomorphic(G, nx.empty_graph(1)) - G = nx.mycielski_graph(2) - assert nx.is_isomorphic(G, nx.path_graph(2)) - G = nx.mycielski_graph(3) - assert nx.is_isomorphic(G, nx.cycle_graph(5)) - G = nx.mycielski_graph(4) - assert nx.is_isomorphic(G, nx.mycielskian(nx.cycle_graph(5))) - with pytest.raises(nx.NetworkXError, match="must satisfy n >= 1"): - nx.mycielski_graph(0) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_nonisomorphic_trees.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_nonisomorphic_trees.py deleted file mode 100644 index c73d44a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_nonisomorphic_trees.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Unit tests for WROM algorithm generator in generators/nonisomorphic_trees.py -""" - -import pytest - -import networkx as nx -from networkx.utils import edges_equal - - -class TestGeneratorNonIsomorphicTrees: - def test_tree_structure(self): - # test for tree structure for nx.nonisomorphic_trees() - def f(x): - return list(nx.nonisomorphic_trees(x)) - - for i in f(6): - assert nx.is_tree(i) - for i in f(8): - assert nx.is_tree(i) - - def test_nonisomorphism(self): - # test for nonisomorphism of trees for nx.nonisomorphic_trees() - def f(x): - return list(nx.nonisomorphic_trees(x)) - - trees = f(6) - for i in range(len(trees)): - for j in range(i + 1, len(trees)): - assert not nx.is_isomorphic(trees[i], trees[j]) - trees = f(8) - for i in range(len(trees)): - for j in range(i + 1, len(trees)): - assert not nx.is_isomorphic(trees[i], trees[j]) - - def test_number_of_nonisomorphic_trees(self): - # http://oeis.org/A000055 - assert nx.number_of_nonisomorphic_trees(2) == 1 - assert nx.number_of_nonisomorphic_trees(3) == 1 - assert nx.number_of_nonisomorphic_trees(4) == 2 - assert nx.number_of_nonisomorphic_trees(5) == 3 - assert nx.number_of_nonisomorphic_trees(6) == 6 - assert nx.number_of_nonisomorphic_trees(7) == 11 - assert nx.number_of_nonisomorphic_trees(8) == 23 - - def test_nonisomorphic_trees(self): - def f(x): - return list(nx.nonisomorphic_trees(x)) - - assert edges_equal(f(3)[0].edges(), [(0, 1), (0, 2)]) - assert edges_equal(f(4)[0].edges(), [(0, 1), (0, 3), (1, 2)]) - assert edges_equal(f(4)[1].edges(), [(0, 1), (0, 2), (0, 3)]) - - def test_nonisomorphic_trees_matrix(self): - trees_2 = [[[0, 1], [1, 0]]] - with pytest.deprecated_call(): - assert list(nx.nonisomorphic_trees(2, create="matrix")) == trees_2 - - trees_3 = [[[0, 1, 1], [1, 0, 0], [1, 0, 0]]] - with pytest.deprecated_call(): - assert list(nx.nonisomorphic_trees(3, create="matrix")) == trees_3 - - trees_4 = [ - [[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]], - [[0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]], - ] - with pytest.deprecated_call(): - assert list(nx.nonisomorphic_trees(4, create="matrix")) == trees_4 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_clustered.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_clustered.py deleted file mode 100644 index 8506652..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_clustered.py +++ /dev/null @@ -1,33 +0,0 @@ -import pytest - -import networkx as nx - - -class TestRandomClusteredGraph: - def test_custom_joint_degree_sequence(self): - node = [1, 1, 1, 2, 1, 2, 0, 0] - tri = [0, 0, 0, 0, 0, 1, 1, 1] - joint_degree_sequence = zip(node, tri) - G = nx.random_clustered_graph(joint_degree_sequence) - assert G.number_of_nodes() == 8 - assert G.number_of_edges() == 7 - - def test_tuple_joint_degree_sequence(self): - G = nx.random_clustered_graph([(1, 2), (2, 1), (1, 1), (1, 1), (1, 1), (2, 0)]) - assert G.number_of_nodes() == 6 - assert G.number_of_edges() == 10 - - def test_invalid_joint_degree_sequence_type(self): - with pytest.raises(nx.NetworkXError, match="Invalid degree sequence"): - nx.random_clustered_graph([[1, 1], [2, 1], [0, 1]]) - - def test_invalid_joint_degree_sequence_value(self): - with pytest.raises(nx.NetworkXError, match="Invalid degree sequence"): - nx.random_clustered_graph([[1, 1], [1, 2], [0, 1]]) - - def test_directed_graph_raises_error(self): - with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"): - nx.random_clustered_graph( - [(1, 2), (2, 1), (1, 1), (1, 1), (1, 1), (2, 0)], - create_using=nx.DiGraph, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_graphs.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_graphs.py deleted file mode 100644 index 3262e54..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_random_graphs.py +++ /dev/null @@ -1,478 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.random_graphs` module.""" - -import pytest - -import networkx as nx - -_gnp_generators = [ - nx.gnp_random_graph, - nx.fast_gnp_random_graph, - nx.binomial_graph, - nx.erdos_renyi_graph, -] - - -@pytest.mark.parametrize("generator", _gnp_generators) -@pytest.mark.parametrize("directed", (True, False)) -def test_gnp_generators_negative_edge_probability(generator, directed): - """If the edge probability `p` is <=0, the resulting graph should have no edges.""" - G = generator(10, -1.1, directed=directed) - assert len(G) == 10 - assert G.number_of_edges() == 0 - assert G.is_directed() == directed - - -@pytest.mark.parametrize("generator", _gnp_generators) -@pytest.mark.parametrize( - ("directed", "expected_num_edges"), - [(False, 45), (True, 90)], -) -def test_gnp_generators_greater_than_1_edge_probability( - generator, directed, expected_num_edges -): - """If the edge probability `p` is >=1, the resulting graph should be complete.""" - G = generator(10, 1.1, directed=directed) - assert len(G) == 10 - assert G.number_of_edges() == expected_num_edges - assert G.is_directed() == directed - - -@pytest.mark.parametrize("generator", _gnp_generators) -@pytest.mark.parametrize("directed", (True, False)) -def test_gnp_generators_basic(generator, directed): - """If the edge probability `p` is >0 and <1, test only the basic properties.""" - G = generator(10, 0.1, directed=directed) - assert len(G) == 10 - assert G.is_directed() == directed - - -@pytest.mark.parametrize("generator", _gnp_generators) -def test_gnp_generators_for_p_close_to_1(generator): - """If the edge probability `p` is close to 1, the resulting graph should have all edges.""" - runs = 100 - edges = sum( - generator(10, 0.99999, directed=True).number_of_edges() for _ in range(runs) - ) - assert abs(edges / float(runs) - 90) <= runs * 2.0 / 100 - - -@pytest.mark.parametrize("generator", _gnp_generators) -@pytest.mark.parametrize("p", (0.2, 0.8)) -@pytest.mark.parametrize("directed", (True, False)) -def test_gnp_generators_edge_probability(generator, p, directed): - """Test that gnp generators generate edges according to the their probability `p`.""" - runs = 5000 - n = 5 - edge_counts = [[0] * n for _ in range(n)] - for i in range(runs): - G = generator(n, p, directed=directed) - for v, w in G.edges: - edge_counts[v][w] += 1 - if not directed: - edge_counts[w][v] += 1 - for v in range(n): - for w in range(n): - if v == w: - # There should be no loops - assert edge_counts[v][w] == 0 - else: - # Each edge should have been generated with probability close to p - assert abs(edge_counts[v][w] / float(runs) - p) <= 0.03 - - -@pytest.mark.parametrize( - "generator", [nx.gnp_random_graph, nx.binomial_graph, nx.erdos_renyi_graph] -) -@pytest.mark.parametrize( - ("seed", "directed", "expected_num_edges"), - [(42, False, 1219), (42, True, 2454), (314, False, 1247), (314, True, 2476)], -) -def test_gnp_random_graph_aliases(generator, seed, directed, expected_num_edges): - """Test that aliases give the same result with the same seed.""" - G = generator(100, 0.25, seed=seed, directed=directed) - assert len(G) == 100 - assert G.number_of_edges() == expected_num_edges - assert G.is_directed() == directed - - -class TestGeneratorsRandom: - def test_random_graph(self): - seed = 42 - G = nx.gnm_random_graph(100, 20, seed) - G = nx.gnm_random_graph(100, 20, seed, directed=True) - G = nx.dense_gnm_random_graph(100, 20, seed) - - G = nx.barabasi_albert_graph(100, 1, seed) - G = nx.barabasi_albert_graph(100, 3, seed) - assert G.number_of_edges() == (97 * 3) - - G = nx.barabasi_albert_graph(100, 3, seed, nx.complete_graph(5)) - assert G.number_of_edges() == (10 + 95 * 3) - - G = nx.extended_barabasi_albert_graph(100, 1, 0, 0, seed) - assert G.number_of_edges() == 99 - G = nx.extended_barabasi_albert_graph(100, 3, 0, 0, seed) - assert G.number_of_edges() == 97 * 3 - G = nx.extended_barabasi_albert_graph(100, 1, 0, 0.5, seed) - assert G.number_of_edges() == 99 - G = nx.extended_barabasi_albert_graph(100, 2, 0.5, 0, seed) - assert G.number_of_edges() > 100 * 3 - assert G.number_of_edges() < 100 * 4 - - G = nx.extended_barabasi_albert_graph(100, 2, 0.3, 0.3, seed) - assert G.number_of_edges() > 100 * 2 - assert G.number_of_edges() < 100 * 4 - - G = nx.powerlaw_cluster_graph(100, 1, 1.0, seed) - G = nx.powerlaw_cluster_graph(100, 3, 0.0, seed) - assert G.number_of_edges() == (97 * 3) - - G = nx.random_regular_graph(10, 20, seed) - - pytest.raises(nx.NetworkXError, nx.random_regular_graph, 3, 21) - pytest.raises(nx.NetworkXError, nx.random_regular_graph, 33, 21) - - constructor = [(10, 20, 0.8), (20, 40, 0.8)] - G = nx.random_shell_graph(constructor, seed) - - def is_caterpillar(g): - """ - A tree is a caterpillar iff all nodes of degree >=3 are surrounded - by at most two nodes of degree two or greater. - ref: http://mathworld.wolfram.com/CaterpillarGraph.html - """ - deg_over_3 = [n for n in g if g.degree(n) >= 3] - for n in deg_over_3: - nbh_deg_over_2 = [nbh for nbh in g.neighbors(n) if g.degree(nbh) >= 2] - if not len(nbh_deg_over_2) <= 2: - return False - return True - - def is_lobster(g): - """ - A tree is a lobster if it has the property that the removal of leaf - nodes leaves a caterpillar graph (Gallian 2007) - ref: http://mathworld.wolfram.com/LobsterGraph.html - """ - non_leafs = [n for n in g if g.degree(n) > 1] - return is_caterpillar(g.subgraph(non_leafs)) - - G = nx.random_lobster(10, 0.1, 0.5, seed) - assert max(G.degree(n) for n in G.nodes()) > 3 - assert is_lobster(G) - pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 0.1, 1, seed) - pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 1, 1, seed) - pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 1, 0.5, seed) - - # docstring says this should be a caterpillar - G = nx.random_lobster(10, 0.1, 0.0, seed) - assert is_caterpillar(G) - - # difficult to find seed that requires few tries - seq = nx.random_powerlaw_tree_sequence(10, 3, seed=14, tries=1) - G = nx.random_powerlaw_tree(10, 3, seed=14, tries=1) - - def test_dual_barabasi_albert(self, m1=1, m2=4, p=0.5): - """ - Tests that the dual BA random graph generated behaves consistently. - - Tests the exceptions are raised as expected. - - The graphs generation are repeated several times to prevent lucky shots - - """ - seeds = [42, 314, 2718] - initial_graph = nx.complete_graph(10) - - for seed in seeds: - # This should be BA with m = m1 - BA1 = nx.barabasi_albert_graph(100, m1, seed) - DBA1 = nx.dual_barabasi_albert_graph(100, m1, m2, 1, seed) - assert BA1.edges() == DBA1.edges() - - # This should be BA with m = m2 - BA2 = nx.barabasi_albert_graph(100, m2, seed) - DBA2 = nx.dual_barabasi_albert_graph(100, m1, m2, 0, seed) - assert BA2.edges() == DBA2.edges() - - BA3 = nx.barabasi_albert_graph(100, m1, seed) - DBA3 = nx.dual_barabasi_albert_graph(100, m1, m1, p, seed) - # We can't compare edges here since randomness is "consumed" when drawing - # between m1 and m2 - assert BA3.size() == DBA3.size() - - DBA = nx.dual_barabasi_albert_graph(100, m1, m2, p, seed, initial_graph) - BA1 = nx.barabasi_albert_graph(100, m1, seed, initial_graph) - BA2 = nx.barabasi_albert_graph(100, m2, seed, initial_graph) - assert ( - min(BA1.size(), BA2.size()) <= DBA.size() <= max(BA1.size(), BA2.size()) - ) - - # Testing exceptions - dbag = nx.dual_barabasi_albert_graph - pytest.raises(nx.NetworkXError, dbag, m1, m1, m2, 0) - pytest.raises(nx.NetworkXError, dbag, m2, m1, m2, 0) - pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, -0.5) - pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, 1.5) - initial = nx.complete_graph(max(m1, m2) - 1) - pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, p, initial_graph=initial) - - def test_extended_barabasi_albert(self, m=2): - """ - Tests that the extended BA random graph generated behaves consistently. - - Tests the exceptions are raised as expected. - - The graphs generation are repeated several times to prevent lucky-shots - - """ - seeds = [42, 314, 2718] - - for seed in seeds: - BA_model = nx.barabasi_albert_graph(100, m, seed) - BA_model_edges = BA_model.number_of_edges() - - # This behaves just like BA, the number of edges must be the same - G1 = nx.extended_barabasi_albert_graph(100, m, 0, 0, seed) - assert G1.size() == BA_model_edges - - # More than twice more edges should have been added - G1 = nx.extended_barabasi_albert_graph(100, m, 0.8, 0, seed) - assert G1.size() > BA_model_edges * 2 - - # Only edge rewiring, so the number of edges less than original - G2 = nx.extended_barabasi_albert_graph(100, m, 0, 0.8, seed) - assert G2.size() == BA_model_edges - - # Mixed scenario: less edges than G1 and more edges than G2 - G3 = nx.extended_barabasi_albert_graph(100, m, 0.3, 0.3, seed) - assert G3.size() > G2.size() - assert G3.size() < G1.size() - - # Testing exceptions - ebag = nx.extended_barabasi_albert_graph - pytest.raises(nx.NetworkXError, ebag, m, m, 0, 0) - pytest.raises(nx.NetworkXError, ebag, 1, 0.5, 0, 0) - pytest.raises(nx.NetworkXError, ebag, 100, 2, 0.5, 0.5) - - def test_random_zero_regular_graph(self): - """Tests that a 0-regular graph has the correct number of nodes and - edges. - - """ - seed = 42 - G = nx.random_regular_graph(0, 10, seed) - assert len(G) == 10 - assert G.number_of_edges() == 0 - - def test_gnm(self): - G = nx.gnm_random_graph(10, 3) - assert len(G) == 10 - assert G.number_of_edges() == 3 - - G = nx.gnm_random_graph(10, 3, seed=42) - assert len(G) == 10 - assert G.number_of_edges() == 3 - - G = nx.gnm_random_graph(10, 100) - assert len(G) == 10 - assert G.number_of_edges() == 45 - - G = nx.gnm_random_graph(10, 100, directed=True) - assert len(G) == 10 - assert G.number_of_edges() == 90 - - G = nx.gnm_random_graph(10, -1.1) - assert len(G) == 10 - assert G.number_of_edges() == 0 - - def test_watts_strogatz_big_k(self): - # Test to make sure than n <= k - pytest.raises(nx.NetworkXError, nx.watts_strogatz_graph, 10, 11, 0.25) - pytest.raises(nx.NetworkXError, nx.newman_watts_strogatz_graph, 10, 11, 0.25) - - # could create an infinite loop, now doesn't - # infinite loop used to occur when a node has degree n-1 and needs to rewire - nx.watts_strogatz_graph(10, 9, 0.25, seed=0) - nx.newman_watts_strogatz_graph(10, 9, 0.5, seed=0) - - # Test k==n scenario - nx.watts_strogatz_graph(10, 10, 0.25, seed=0) - nx.newman_watts_strogatz_graph(10, 10, 0.25, seed=0) - - def test_random_kernel_graph(self): - def integral(u, w, z): - return c * (z - w) - - def root(u, w, r): - return r / c + w - - c = 1 - graph = nx.random_kernel_graph(1000, integral, root) - graph = nx.random_kernel_graph(1000, integral, root, seed=42) - assert len(graph) == 1000 - - -@pytest.mark.parametrize( - ("k", "expected_num_nodes", "expected_num_edges"), - [ - (2, 10, 10), - (4, 10, 20), - ], -) -def test_watts_strogatz(k, expected_num_nodes, expected_num_edges): - G = nx.watts_strogatz_graph(10, k, 0.25, seed=42) - assert len(G) == expected_num_nodes - assert G.number_of_edges() == expected_num_edges - - -def test_newman_watts_strogatz_zero_probability(): - G = nx.newman_watts_strogatz_graph(10, 2, 0.0, seed=42) - assert len(G) == 10 - assert G.number_of_edges() == 10 - - -def test_newman_watts_strogatz_nonzero_probability(): - G = nx.newman_watts_strogatz_graph(10, 4, 0.25, seed=42) - assert len(G) == 10 - assert G.number_of_edges() >= 20 - - -def test_connected_watts_strogatz(): - G = nx.connected_watts_strogatz_graph(10, 2, 0.1, tries=10, seed=42) - assert len(G) == 10 - assert G.number_of_edges() == 10 - - -def test_connected_watts_strogatz_zero_tries(): - with pytest.raises(nx.NetworkXError, match="Maximum number of tries exceeded"): - nx.connected_watts_strogatz_graph(10, 2, 0.1, tries=0) - - -@pytest.mark.parametrize( - "generator, kwargs", - [ - (nx.fast_gnp_random_graph, {"n": 20, "p": 0.2, "directed": False}), - (nx.fast_gnp_random_graph, {"n": 20, "p": 0.2, "directed": True}), - (nx.gnp_random_graph, {"n": 20, "p": 0.2, "directed": False}), - (nx.gnp_random_graph, {"n": 20, "p": 0.2, "directed": True}), - (nx.dense_gnm_random_graph, {"n": 30, "m": 4}), - (nx.gnm_random_graph, {"n": 30, "m": 4, "directed": False}), - (nx.gnm_random_graph, {"n": 30, "m": 4, "directed": True}), - (nx.newman_watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}), - (nx.watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}), - (nx.connected_watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}), - (nx.random_regular_graph, {"d": 5, "n": 20}), - (nx.barabasi_albert_graph, {"n": 40, "m": 3}), - (nx.dual_barabasi_albert_graph, {"n": 40, "m1": 3, "m2": 2, "p": 0.1}), - (nx.extended_barabasi_albert_graph, {"n": 40, "m": 3, "p": 0.1, "q": 0.2}), - (nx.powerlaw_cluster_graph, {"n": 40, "m": 3, "p": 0.1}), - (nx.random_lobster, {"n": 40, "p1": 0.1, "p2": 0.2}), - (nx.random_shell_graph, {"constructor": [(10, 20, 0.8), (20, 40, 0.8)]}), - (nx.random_powerlaw_tree, {"n": 10, "seed": 14, "tries": 1}), - ( - nx.random_kernel_graph, - { - "n": 10, - "kernel_integral": lambda u, w, z: z - w, - "kernel_root": lambda u, w, r: r + w, - }, - ), - ], -) -@pytest.mark.parametrize("create_using_instance", [False, True]) -def test_create_using(generator, kwargs, create_using_instance): - class DummyGraph(nx.Graph): - pass - - class DummyDiGraph(nx.DiGraph): - pass - - create_using_type = DummyDiGraph if kwargs.get("directed") else DummyGraph - create_using = create_using_type() if create_using_instance else create_using_type - graph = generator(**kwargs, create_using=create_using) - assert isinstance(graph, create_using_type) - - -@pytest.mark.parametrize("directed", [True, False]) -@pytest.mark.parametrize("fn", (nx.fast_gnp_random_graph, nx.gnp_random_graph)) -def test_gnp_fns_disallow_multigraph(fn, directed): - with pytest.raises(nx.NetworkXError, match="must not be a multi-graph"): - fn(20, 0.2, create_using=nx.MultiGraph) - - -@pytest.mark.parametrize("fn", (nx.gnm_random_graph, nx.dense_gnm_random_graph)) -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_gnm_fns_disallow_directed_and_multigraph(fn, graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - fn(10, 20, create_using=graphtype) - - -@pytest.mark.parametrize( - "fn", - ( - nx.newman_watts_strogatz_graph, - nx.watts_strogatz_graph, - nx.connected_watts_strogatz_graph, - ), -) -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_watts_strogatz_disallow_directed_and_multigraph(fn, graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - fn(10, 2, 0.2, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_random_regular_graph_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.random_regular_graph(2, 10, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_barabasi_albert_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.barabasi_albert_graph(10, 3, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_dual_barabasi_albert_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.dual_barabasi_albert_graph(10, 2, 1, 0.4, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_extended_barabasi_albert_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.extended_barabasi_albert_graph(10, 2, 0.2, 0.3, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_powerlaw_cluster_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.powerlaw_cluster_graph(10, 5, 0.2, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_random_lobster_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.random_lobster(10, 0.1, 0.1, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_random_shell_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.random_shell_graph([(10, 20, 2), (10, 20, 5)], create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_random_powerlaw_tree_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.random_powerlaw_tree(10, create_using=graphtype) - - -@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)) -def test_random_kernel_disallow_directed_and_multigraph(graphtype): - with pytest.raises(nx.NetworkXError, match="must not be"): - nx.random_kernel_graph( - 10, lambda y, a, b: a + b, lambda u, w, r: r + w, create_using=graphtype - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_small.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_small.py deleted file mode 100644 index 355d6d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_small.py +++ /dev/null @@ -1,208 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic - -is_isomorphic = graph_could_be_isomorphic - -"""Generators - Small -===================== - -Some small graphs -""" - -null = nx.null_graph() - - -class TestGeneratorsSmall: - def test__LCF_graph(self): - # If n<=0, then return the null_graph - G = nx.LCF_graph(-10, [1, 2], 100) - assert is_isomorphic(G, null) - G = nx.LCF_graph(0, [1, 2], 3) - assert is_isomorphic(G, null) - G = nx.LCF_graph(0, [1, 2], 10) - assert is_isomorphic(G, null) - - # Test that LCF(n,[],0) == cycle_graph(n) - for a, b, c in [(5, [], 0), (10, [], 0), (5, [], 1), (10, [], 10)]: - G = nx.LCF_graph(a, b, c) - assert is_isomorphic(G, nx.cycle_graph(a)) - - # Generate the utility graph K_{3,3} - G = nx.LCF_graph(6, [3, -3], 3) - utility_graph = nx.complete_bipartite_graph(3, 3) - assert is_isomorphic(G, utility_graph) - - with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"): - G = nx.LCF_graph(6, [3, -3], 3, create_using=nx.DiGraph) - - def test_properties_named_small_graphs(self): - G = nx.bull_graph() - assert sorted(G) == list(range(5)) - assert G.number_of_edges() == 5 - assert sorted(d for n, d in G.degree()) == [1, 1, 2, 3, 3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 2 - - G = nx.chvatal_graph() - assert sorted(G) == list(range(12)) - assert G.number_of_edges() == 24 - assert [d for n, d in G.degree()] == 12 * [4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.cubical_graph() - assert sorted(G) == list(range(8)) - assert G.number_of_edges() == 12 - assert [d for n, d in G.degree()] == 8 * [3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.desargues_graph() - assert sorted(G) == list(range(20)) - assert G.number_of_edges() == 30 - assert [d for n, d in G.degree()] == 20 * [3] - - G = nx.diamond_graph() - assert sorted(G) == list(range(4)) - assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 1 - - G = nx.dodecahedral_graph() - assert sorted(G) == list(range(20)) - assert G.number_of_edges() == 30 - assert [d for n, d in G.degree()] == 20 * [3] - assert nx.diameter(G) == 5 - assert nx.radius(G) == 5 - - G = nx.frucht_graph() - assert sorted(G) == list(range(12)) - assert G.number_of_edges() == 18 - assert [d for n, d in G.degree()] == 12 * [3] - assert nx.diameter(G) == 4 - assert nx.radius(G) == 3 - - G = nx.heawood_graph() - assert sorted(G) == list(range(14)) - assert G.number_of_edges() == 21 - assert [d for n, d in G.degree()] == 14 * [3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.hoffman_singleton_graph() - assert sorted(G) == list(range(50)) - assert G.number_of_edges() == 175 - assert [d for n, d in G.degree()] == 50 * [7] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.house_graph() - assert sorted(G) == list(range(5)) - assert G.number_of_edges() == 6 - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 3, 3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.house_x_graph() - assert sorted(G) == list(range(5)) - assert G.number_of_edges() == 8 - assert sorted(d for n, d in G.degree()) == [2, 3, 3, 4, 4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 1 - - G = nx.icosahedral_graph() - assert sorted(G) == list(range(12)) - assert G.number_of_edges() == 30 - assert [d for n, d in G.degree()] == [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.krackhardt_kite_graph() - assert sorted(G) == list(range(10)) - assert G.number_of_edges() == 18 - assert sorted(d for n, d in G.degree()) == [1, 2, 3, 3, 3, 4, 4, 5, 5, 6] - - G = nx.moebius_kantor_graph() - assert sorted(G) == list(range(16)) - assert G.number_of_edges() == 24 - assert [d for n, d in G.degree()] == 16 * [3] - assert nx.diameter(G) == 4 - - G = nx.octahedral_graph() - assert sorted(G) == list(range(6)) - assert G.number_of_edges() == 12 - assert [d for n, d in G.degree()] == 6 * [4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.pappus_graph() - assert sorted(G) == list(range(18)) - assert G.number_of_edges() == 27 - assert [d for n, d in G.degree()] == 18 * [3] - assert nx.diameter(G) == 4 - - G = nx.petersen_graph() - assert sorted(G) == list(range(10)) - assert G.number_of_edges() == 15 - assert [d for n, d in G.degree()] == 10 * [3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.sedgewick_maze_graph() - assert sorted(G) == list(range(8)) - assert G.number_of_edges() == 10 - assert sorted(d for n, d in G.degree()) == [1, 2, 2, 2, 3, 3, 3, 4] - - G = nx.tetrahedral_graph() - assert sorted(G) == list(range(4)) - assert G.number_of_edges() == 6 - assert [d for n, d in G.degree()] == [3, 3, 3, 3] - assert nx.diameter(G) == 1 - assert nx.radius(G) == 1 - - G = nx.truncated_cube_graph() - assert sorted(G) == list(range(24)) - assert G.number_of_edges() == 36 - assert [d for n, d in G.degree()] == 24 * [3] - - G = nx.truncated_tetrahedron_graph() - assert sorted(G) == list(range(12)) - assert G.number_of_edges() == 18 - assert [d for n, d in G.degree()] == 12 * [3] - - G = nx.tutte_graph() - assert sorted(G) == list(range(46)) - assert G.number_of_edges() == 69 - assert [d for n, d in G.degree()] == 46 * [3] - - # Test create_using with directed or multigraphs on small graphs - pytest.raises(nx.NetworkXError, nx.tutte_graph, create_using=nx.DiGraph) - MG = nx.tutte_graph(create_using=nx.MultiGraph) - assert sorted(MG.edges()) == sorted(G.edges()) - - -@pytest.mark.parametrize( - "fn", - ( - nx.bull_graph, - nx.chvatal_graph, - nx.cubical_graph, - nx.diamond_graph, - nx.house_graph, - nx.house_x_graph, - nx.icosahedral_graph, - nx.krackhardt_kite_graph, - nx.octahedral_graph, - nx.petersen_graph, - nx.truncated_cube_graph, - nx.tutte_graph, - ), -) -@pytest.mark.parametrize( - "create_using", (nx.DiGraph, nx.MultiDiGraph, nx.DiGraph([(0, 1)])) -) -def tests_raises_with_directed_create_using(fn, create_using): - with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"): - fn(create_using=create_using) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_spectral_graph_forge.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_spectral_graph_forge.py deleted file mode 100644 index b554bfd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_spectral_graph_forge.py +++ /dev/null @@ -1,49 +0,0 @@ -import pytest - -pytest.importorskip("numpy") -pytest.importorskip("scipy") - - -from networkx import is_isomorphic -from networkx.exception import NetworkXError -from networkx.generators import karate_club_graph -from networkx.generators.spectral_graph_forge import spectral_graph_forge -from networkx.utils import nodes_equal - - -def test_spectral_graph_forge(): - G = karate_club_graph() - - seed = 54321 - - # common cases, just checking node number preserving and difference - # between identity and modularity cases - H = spectral_graph_forge(G, 0.1, transformation="identity", seed=seed) - assert nodes_equal(G, H) - - I = spectral_graph_forge(G, 0.1, transformation="identity", seed=seed) - assert nodes_equal(G, H) - assert is_isomorphic(I, H) - - I = spectral_graph_forge(G, 0.1, transformation="modularity", seed=seed) - assert nodes_equal(G, I) - - assert not is_isomorphic(I, H) - - # with all the eigenvectors, output graph is identical to the input one - H = spectral_graph_forge(G, 1, transformation="modularity", seed=seed) - assert nodes_equal(G, H) - assert is_isomorphic(G, H) - - # invalid alpha input value, it is silently truncated in [0,1] - H = spectral_graph_forge(G, -1, transformation="identity", seed=seed) - assert nodes_equal(G, H) - - H = spectral_graph_forge(G, 10, transformation="identity", seed=seed) - assert nodes_equal(G, H) - assert is_isomorphic(G, H) - - # invalid transformation mode, checking the error raising - pytest.raises( - NetworkXError, spectral_graph_forge, G, 0.1, transformation="unknown", seed=seed - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_stochastic.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_stochastic.py deleted file mode 100644 index 0404d9d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_stochastic.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.stochastic` module.""" - -import pytest - -import networkx as nx - - -class TestStochasticGraph: - """Unit tests for the :func:`~networkx.stochastic_graph` function.""" - - def test_default_weights(self): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(0, 2) - S = nx.stochastic_graph(G) - assert nx.is_isomorphic(G, S) - assert sorted(S.edges(data=True)) == [ - (0, 1, {"weight": 0.5}), - (0, 2, {"weight": 0.5}), - ] - - def test_in_place(self): - """Tests for an in-place reweighting of the edges of the graph.""" - G = nx.DiGraph() - G.add_edge(0, 1, weight=1) - G.add_edge(0, 2, weight=1) - nx.stochastic_graph(G, copy=False) - assert sorted(G.edges(data=True)) == [ - (0, 1, {"weight": 0.5}), - (0, 2, {"weight": 0.5}), - ] - - def test_arbitrary_weights(self): - G = nx.DiGraph() - G.add_edge(0, 1, weight=1) - G.add_edge(0, 2, weight=1) - S = nx.stochastic_graph(G) - assert sorted(S.edges(data=True)) == [ - (0, 1, {"weight": 0.5}), - (0, 2, {"weight": 0.5}), - ] - - def test_multidigraph(self): - G = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (0, 1), (0, 2), (0, 2)]) - S = nx.stochastic_graph(G) - d = {"weight": 0.25} - assert sorted(S.edges(data=True)) == [ - (0, 1, d), - (0, 1, d), - (0, 2, d), - (0, 2, d), - ] - - def test_zero_weights(self): - """Smoke test: ensure ZeroDivisionError is not raised.""" - G = nx.DiGraph() - G.add_edge(0, 1, weight=0) - G.add_edge(0, 2, weight=0) - S = nx.stochastic_graph(G) - assert sorted(S.edges(data=True)) == [ - (0, 1, {"weight": 0}), - (0, 2, {"weight": 0}), - ] - - def test_graph_disallowed(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.stochastic_graph(nx.Graph()) - - def test_multigraph_disallowed(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.stochastic_graph(nx.MultiGraph()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_sudoku.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_sudoku.py deleted file mode 100644 index 7c3560a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_sudoku.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.sudoku_graph` module.""" - -import pytest - -import networkx as nx - - -def test_sudoku_negative(): - """Raise an error when generating a Sudoku graph of order -1.""" - pytest.raises(nx.NetworkXError, nx.sudoku_graph, n=-1) - - -@pytest.mark.parametrize("n", [0, 1, 2, 3, 4]) -def test_sudoku_generator(n): - """Generate Sudoku graphs of various sizes and verify their properties.""" - G = nx.sudoku_graph(n) - expected_nodes = n**4 - expected_degree = (n - 1) * (3 * n + 1) - expected_edges = expected_nodes * expected_degree // 2 - assert not G.is_directed() - assert not G.is_multigraph() - assert G.number_of_nodes() == expected_nodes - assert G.number_of_edges() == expected_edges - assert all(d == expected_degree for _, d in G.degree) - - if n == 2: - assert sorted(G.neighbors(6)) == [2, 3, 4, 5, 7, 10, 14] - elif n == 3: - assert sorted(G.neighbors(42)) == [ - 6, - 15, - 24, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 43, - 44, - 51, - 52, - 53, - 60, - 69, - 78, - ] - elif n == 4: - assert sorted(G.neighbors(0)) == [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 32, - 33, - 34, - 35, - 48, - 49, - 50, - 51, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - 176, - 192, - 208, - 224, - 240, - ] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_time_series.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_time_series.py deleted file mode 100644 index 5d0cc90..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_time_series.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.time_series` module.""" - -import itertools - -import networkx as nx - - -def test_visibility_graph__empty_series__empty_graph(): - null_graph = nx.visibility_graph([]) # move along nothing to see here - assert nx.is_empty(null_graph) - - -def test_visibility_graph__single_value_ts__single_node_graph(): - node_graph = nx.visibility_graph([10]) # So Lonely - assert node_graph.number_of_nodes() == 1 - assert node_graph.number_of_edges() == 0 - - -def test_visibility_graph__two_values_ts__single_edge_graph(): - edge_graph = nx.visibility_graph([10, 20]) # Two of Us - assert list(edge_graph.edges) == [(0, 1)] - - -def test_visibility_graph__convex_series__complete_graph(): - series = [i**2 for i in range(10)] # no obstructions - expected_series_length = len(series) - - actual_graph = nx.visibility_graph(series) - - assert actual_graph.number_of_nodes() == expected_series_length - assert actual_graph.number_of_edges() == 45 - assert nx.is_isomorphic(actual_graph, nx.complete_graph(expected_series_length)) - - -def test_visibility_graph__concave_series__path_graph(): - series = [-(i**2) for i in range(10)] # Slip Slidin' Away - expected_node_count = len(series) - - actual_graph = nx.visibility_graph(series) - - assert actual_graph.number_of_nodes() == expected_node_count - assert actual_graph.number_of_edges() == expected_node_count - 1 - assert nx.is_isomorphic(actual_graph, nx.path_graph(expected_node_count)) - - -def test_visibility_graph__flat_series__path_graph(): - series = [0] * 10 # living in 1D flatland - expected_node_count = len(series) - - actual_graph = nx.visibility_graph(series) - - assert actual_graph.number_of_nodes() == expected_node_count - assert actual_graph.number_of_edges() == expected_node_count - 1 - assert nx.is_isomorphic(actual_graph, nx.path_graph(expected_node_count)) - - -def test_visibility_graph_cyclic_series(): - series = list(itertools.islice(itertools.cycle((2, 1, 3)), 17)) # It's so bumpy! - expected_node_count = len(series) - - actual_graph = nx.visibility_graph(series) - - assert actual_graph.number_of_nodes() == expected_node_count - assert actual_graph.number_of_edges() == 25 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_trees.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_trees.py deleted file mode 100644 index 7932436..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_trees.py +++ /dev/null @@ -1,195 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx.utils import arbitrary_element, graphs_equal - - -@pytest.mark.parametrize("prefix_tree_fn", (nx.prefix_tree, nx.prefix_tree_recursive)) -def test_basic_prefix_tree(prefix_tree_fn): - # This example is from the Wikipedia article "Trie" - # . - strings = ["a", "to", "tea", "ted", "ten", "i", "in", "inn"] - T = prefix_tree_fn(strings) - root, NIL = 0, -1 - - def source_label(v): - return T.nodes[v]["source"] - - # First, we check that the tree has the expected - # structure. Recall that each node that corresponds to one of - # the input strings has an edge to the NIL node. - # - # Consider the three children at level 1 in the trie. - a, i, t = sorted(T[root], key=source_label) - # Check the 'a' branch. - assert len(T[a]) == 1 - nil = arbitrary_element(T[a]) - assert len(T[nil]) == 0 - # Check the 'i' branch. - assert len(T[i]) == 2 - nil, in_ = sorted(T[i], key=source_label) - assert len(T[nil]) == 0 - assert len(T[in_]) == 2 - nil, inn = sorted(T[in_], key=source_label) - assert len(T[nil]) == 0 - assert len(T[inn]) == 1 - nil = arbitrary_element(T[inn]) - assert len(T[nil]) == 0 - # Check the 't' branch. - te, to = sorted(T[t], key=source_label) - assert len(T[to]) == 1 - nil = arbitrary_element(T[to]) - assert len(T[nil]) == 0 - tea, ted, ten = sorted(T[te], key=source_label) - assert len(T[tea]) == 1 - assert len(T[ted]) == 1 - assert len(T[ten]) == 1 - nil = arbitrary_element(T[tea]) - assert len(T[nil]) == 0 - nil = arbitrary_element(T[ted]) - assert len(T[nil]) == 0 - nil = arbitrary_element(T[ten]) - assert len(T[nil]) == 0 - - # Next, we check that the "sources" of each of the nodes is the - # rightmost letter in the string corresponding to the path to - # that node. - assert source_label(root) is None - assert source_label(a) == "a" - assert source_label(i) == "i" - assert source_label(t) == "t" - assert source_label(in_) == "n" - assert source_label(inn) == "n" - assert source_label(to) == "o" - assert source_label(te) == "e" - assert source_label(tea) == "a" - assert source_label(ted) == "d" - assert source_label(ten) == "n" - assert source_label(NIL) == "NIL" - - -@pytest.mark.parametrize( - "strings", - ( - ["a", "to", "tea", "ted", "ten", "i", "in", "inn"], - ["ab", "abs", "ad"], - ["ab", "abs", "ad", ""], - ["distant", "disparaging", "distant", "diamond", "ruby"], - ), -) -def test_implementations_consistent(strings): - """Ensure results are consistent between prefix_tree implementations.""" - assert graphs_equal(nx.prefix_tree(strings), nx.prefix_tree_recursive(strings)) - - -def test_random_labeled_rooted_tree(): - for i in range(1, 10): - t1 = nx.random_labeled_rooted_tree(i, seed=42) - t2 = nx.random_labeled_rooted_tree(i, seed=42) - assert nx.utils.misc.graphs_equal(t1, t2) - assert nx.is_tree(t1) - assert "root" in t1.graph - assert "roots" not in t1.graph - - -def test_random_labeled_tree_n_zero(): - """Tests if n = 0 then the NetworkXPointlessConcept exception is raised.""" - with pytest.raises(nx.NetworkXPointlessConcept): - T = nx.random_labeled_tree(0, seed=1234) - with pytest.raises(nx.NetworkXPointlessConcept): - T = nx.random_labeled_rooted_tree(0, seed=1234) - - -def test_random_labeled_rooted_forest(): - for i in range(1, 10): - t1 = nx.random_labeled_rooted_forest(i, seed=42) - t2 = nx.random_labeled_rooted_forest(i, seed=42) - assert nx.utils.misc.graphs_equal(t1, t2) - for c in nx.connected_components(t1): - assert nx.is_tree(t1.subgraph(c)) - assert "root" not in t1.graph - assert "roots" in t1.graph - - -def test_random_labeled_rooted_forest_n_zero(): - """Tests generation of empty labeled forests.""" - F = nx.random_labeled_rooted_forest(0, seed=1234) - assert len(F) == 0 - assert len(F.graph["roots"]) == 0 - - -def test_random_unlabeled_rooted_tree(): - for i in range(1, 10): - t1 = nx.random_unlabeled_rooted_tree(i, seed=42) - t2 = nx.random_unlabeled_rooted_tree(i, seed=42) - assert nx.utils.misc.graphs_equal(t1, t2) - assert nx.is_tree(t1) - assert "root" in t1.graph - assert "roots" not in t1.graph - t = nx.random_unlabeled_rooted_tree(15, number_of_trees=10, seed=43) - random.seed(43) - s = nx.random_unlabeled_rooted_tree(15, number_of_trees=10, seed=random) - for i in range(10): - assert nx.utils.misc.graphs_equal(t[i], s[i]) - assert nx.is_tree(t[i]) - assert "root" in t[i].graph - assert "roots" not in t[i].graph - - -def test_random_unlabeled_tree_n_zero(): - """Tests if n = 0 then the NetworkXPointlessConcept exception is raised.""" - with pytest.raises(nx.NetworkXPointlessConcept): - T = nx.random_unlabeled_tree(0, seed=1234) - with pytest.raises(nx.NetworkXPointlessConcept): - T = nx.random_unlabeled_rooted_tree(0, seed=1234) - - -def test_random_unlabeled_rooted_forest(): - with pytest.raises(ValueError): - nx.random_unlabeled_rooted_forest(10, q=0, seed=42) - for i in range(1, 10): - for q in range(1, i + 1): - t1 = nx.random_unlabeled_rooted_forest(i, q=q, seed=42) - t2 = nx.random_unlabeled_rooted_forest(i, q=q, seed=42) - assert nx.utils.misc.graphs_equal(t1, t2) - for c in nx.connected_components(t1): - assert nx.is_tree(t1.subgraph(c)) - assert len(c) <= q - assert "root" not in t1.graph - assert "roots" in t1.graph - t = nx.random_unlabeled_rooted_forest(15, number_of_forests=10, seed=43) - random.seed(43) - s = nx.random_unlabeled_rooted_forest(15, number_of_forests=10, seed=random) - for i in range(10): - assert nx.utils.misc.graphs_equal(t[i], s[i]) - for c in nx.connected_components(t[i]): - assert nx.is_tree(t[i].subgraph(c)) - assert "root" not in t[i].graph - assert "roots" in t[i].graph - - -def test_random_unlabeled_forest_n_zero(): - """Tests generation of empty unlabeled forests.""" - F = nx.random_unlabeled_rooted_forest(0, seed=1234) - assert len(F) == 0 - assert len(F.graph["roots"]) == 0 - - -def test_random_unlabeled_tree(): - for i in range(1, 10): - t1 = nx.random_unlabeled_tree(i, seed=42) - t2 = nx.random_unlabeled_tree(i, seed=42) - assert nx.utils.misc.graphs_equal(t1, t2) - assert nx.is_tree(t1) - assert "root" not in t1.graph - assert "roots" not in t1.graph - t = nx.random_unlabeled_tree(10, number_of_trees=10, seed=43) - random.seed(43) - s = nx.random_unlabeled_tree(10, number_of_trees=10, seed=random) - for i in range(10): - assert nx.utils.misc.graphs_equal(t[i], s[i]) - assert nx.is_tree(t[i]) - assert "root" not in t[i].graph - assert "roots" not in t[i].graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_triads.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_triads.py deleted file mode 100644 index 463844b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/tests/test_triads.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.triads` module.""" - -import pytest - -from networkx import triad_graph - - -def test_triad_graph(): - G = triad_graph("030T") - assert [tuple(e) for e in ("ab", "ac", "cb")] == sorted(G.edges()) - - -def test_invalid_name(): - with pytest.raises(ValueError): - triad_graph("bogus") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/time_series.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/time_series.py deleted file mode 100644 index 592d773..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/time_series.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Time Series Graphs -""" - -import itertools - -import networkx as nx - -__all__ = ["visibility_graph"] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def visibility_graph(series): - """ - Return a Visibility Graph of an input Time Series. - - A visibility graph converts a time series into a graph. The constructed graph - uses integer nodes to indicate which event in the series the node represents. - Edges are formed as follows: consider a bar plot of the series and view that - as a side view of a landscape with a node at the top of each bar. An edge - means that the nodes can be connected by a straight "line-of-sight" without - being obscured by any bars between the nodes. - - The resulting graph inherits several properties of the series in its structure. - Thereby, periodic series convert into regular graphs, random series convert - into random graphs, and fractal series convert into scale-free networks [1]_. - - Parameters - ---------- - series : Sequence[Number] - A Time Series sequence (iterable and sliceable) of numeric values - representing times. - - Returns - ------- - NetworkX Graph - The Visibility Graph of the input series - - Examples - -------- - >>> series_list = [range(10), [2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3]] - >>> for s in series_list: - ... g = nx.visibility_graph(s) - ... print(g) - Graph with 10 nodes and 9 edges - Graph with 12 nodes and 18 edges - - References - ---------- - .. [1] Lacasa, Lucas, Bartolo Luque, Fernando Ballesteros, Jordi Luque, and Juan Carlos Nuno. - "From time series to complex networks: The visibility graph." Proceedings of the - National Academy of Sciences 105, no. 13 (2008): 4972-4975. - https://www.pnas.org/doi/10.1073/pnas.0709247105 - """ - - # Sequential values are always connected - G = nx.path_graph(len(series)) - nx.set_node_attributes(G, dict(enumerate(series)), "value") - - # Check all combinations of nodes n series - for (n1, t1), (n2, t2) in itertools.combinations(enumerate(series), 2): - # check if any value between obstructs line of sight - slope = (t2 - t1) / (n2 - n1) - offset = t2 - slope * n2 - - obstructed = any( - t >= slope * n + offset - for n, t in enumerate(series[n1 + 1 : n2], start=n1 + 1) - ) - - if not obstructed: - G.add_edge(n1, n2) - - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/trees.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/trees.py deleted file mode 100644 index 30849a8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/trees.py +++ /dev/null @@ -1,1071 +0,0 @@ -"""Functions for generating trees. - -The functions sampling trees at random in this module come -in two variants: labeled and unlabeled. The labeled variants -sample from every possible tree with the given number of nodes -uniformly at random. The unlabeled variants sample from every -possible *isomorphism class* of trees with the given number -of nodes uniformly at random. - -To understand the difference, consider the following example. -There are two isomorphism classes of trees with four nodes. -One is that of the path graph, the other is that of the -star graph. The unlabeled variant will return a line graph or -a star graph with probability 1/2. - -The labeled variant will return the line graph -with probability 3/4 and the star graph with probability 1/4, -because there are more labeled variants of the line graph -than of the star graph. More precisely, the line graph has -an automorphism group of order 2, whereas the star graph has -an automorphism group of order 6, so the line graph has three -times as many labeled variants as the star graph, and thus -three more chances to be drawn. - -Additionally, some functions in this module can sample rooted -trees and forests uniformly at random. A rooted tree is a tree -with a designated root node. A rooted forest is a disjoint union -of rooted trees. -""" - -import warnings -from collections import Counter, defaultdict -from math import comb, factorial - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "prefix_tree", - "prefix_tree_recursive", - "random_labeled_tree", - "random_labeled_rooted_tree", - "random_labeled_rooted_forest", - "random_unlabeled_tree", - "random_unlabeled_rooted_tree", - "random_unlabeled_rooted_forest", -] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def prefix_tree(paths): - """Creates a directed prefix tree from a list of paths. - - Usually the paths are described as strings or lists of integers. - - A "prefix tree" represents the prefix structure of the strings. - Each node represents a prefix of some string. The root represents - the empty prefix with children for the single letter prefixes which - in turn have children for each double letter prefix starting with - the single letter corresponding to the parent node, and so on. - - More generally the prefixes do not need to be strings. A prefix refers - to the start of a sequence. The root has children for each one element - prefix and they have children for each two element prefix that starts - with the one element sequence of the parent, and so on. - - Note that this implementation uses integer nodes with an attribute. - Each node has an attribute "source" whose value is the original element - of the path to which this node corresponds. For example, suppose `paths` - consists of one path: "can". Then the nodes `[1, 2, 3]` which represent - this path have "source" values "c", "a" and "n". - - All the descendants of a node have a common prefix in the sequence/path - associated with that node. From the returned tree, the prefix for each - node can be constructed by traversing the tree up to the root and - accumulating the "source" values along the way. - - The root node is always `0` and has "source" attribute `None`. - The root is the only node with in-degree zero. - The nil node is always `-1` and has "source" attribute `"NIL"`. - The nil node is the only node with out-degree zero. - - - Parameters - ---------- - paths: iterable of paths - An iterable of paths which are themselves sequences. - Matching prefixes among these sequences are identified with - nodes of the prefix tree. One leaf of the tree is associated - with each path. (Identical paths are associated with the same - leaf of the tree.) - - - Returns - ------- - tree: DiGraph - A directed graph representing an arborescence consisting of the - prefix tree generated by `paths`. Nodes are directed "downward", - from parent to child. A special "synthetic" root node is added - to be the parent of the first node in each path. A special - "synthetic" leaf node, the "nil" node `-1`, is added to be the child - of all nodes representing the last element in a path. (The - addition of this nil node technically makes this not an - arborescence but a directed acyclic graph; removing the nil node - makes it an arborescence.) - - - Notes - ----- - The prefix tree is also known as a *trie*. - - - Examples - -------- - Create a prefix tree from a list of strings with common prefixes:: - - >>> paths = ["ab", "abs", "ad"] - >>> T = nx.prefix_tree(paths) - >>> list(T.edges) - [(0, 1), (1, 2), (1, 4), (2, -1), (2, 3), (3, -1), (4, -1)] - - The leaf nodes can be obtained as predecessors of the nil node:: - - >>> root, NIL = 0, -1 - >>> list(T.predecessors(NIL)) - [2, 3, 4] - - To recover the original paths that generated the prefix tree, - traverse up the tree from the node `-1` to the node `0`:: - - >>> recovered = [] - >>> for v in T.predecessors(NIL): - ... prefix = "" - ... while v != root: - ... prefix = str(T.nodes[v]["source"]) + prefix - ... v = next(T.predecessors(v)) # only one predecessor - ... recovered.append(prefix) - >>> sorted(recovered) - ['ab', 'abs', 'ad'] - """ - - def get_children(parent, paths): - children = defaultdict(list) - # Populate dictionary with key(s) as the child/children of the root and - # value(s) as the remaining paths of the corresponding child/children - for path in paths: - # If path is empty, we add an edge to the NIL node. - if not path: - tree.add_edge(parent, NIL) - continue - child, *rest = path - # `child` may exist as the head of more than one path in `paths`. - children[child].append(rest) - return children - - # Initialize the prefix tree with a root node and a nil node. - tree = nx.DiGraph() - root = 0 - tree.add_node(root, source=None) - NIL = -1 - tree.add_node(NIL, source="NIL") - children = get_children(root, paths) - stack = [(root, iter(children.items()))] - while stack: - parent, remaining_children = stack[-1] - try: - child, remaining_paths = next(remaining_children) - # Pop item off stack if there are no remaining children - except StopIteration: - stack.pop() - continue - # We relabel each child with an unused name. - new_name = len(tree) - 1 - # The "source" node attribute stores the original node name. - tree.add_node(new_name, source=child) - tree.add_edge(parent, new_name) - children = get_children(new_name, remaining_paths) - stack.append((new_name, iter(children.items()))) - - return tree - - -@nx._dispatchable(graphs=None, returns_graph=True) -def prefix_tree_recursive(paths): - """Recursively creates a directed prefix tree from a list of paths. - - The original recursive version of prefix_tree for comparison. It is - the same algorithm but the recursion is unrolled onto a stack. - - Usually the paths are described as strings or lists of integers. - - A "prefix tree" represents the prefix structure of the strings. - Each node represents a prefix of some string. The root represents - the empty prefix with children for the single letter prefixes which - in turn have children for each double letter prefix starting with - the single letter corresponding to the parent node, and so on. - - More generally the prefixes do not need to be strings. A prefix refers - to the start of a sequence. The root has children for each one element - prefix and they have children for each two element prefix that starts - with the one element sequence of the parent, and so on. - - Note that this implementation uses integer nodes with an attribute. - Each node has an attribute "source" whose value is the original element - of the path to which this node corresponds. For example, suppose `paths` - consists of one path: "can". Then the nodes `[1, 2, 3]` which represent - this path have "source" values "c", "a" and "n". - - All the descendants of a node have a common prefix in the sequence/path - associated with that node. From the returned tree, ehe prefix for each - node can be constructed by traversing the tree up to the root and - accumulating the "source" values along the way. - - The root node is always `0` and has "source" attribute `None`. - The root is the only node with in-degree zero. - The nil node is always `-1` and has "source" attribute `"NIL"`. - The nil node is the only node with out-degree zero. - - - Parameters - ---------- - paths: iterable of paths - An iterable of paths which are themselves sequences. - Matching prefixes among these sequences are identified with - nodes of the prefix tree. One leaf of the tree is associated - with each path. (Identical paths are associated with the same - leaf of the tree.) - - - Returns - ------- - tree: DiGraph - A directed graph representing an arborescence consisting of the - prefix tree generated by `paths`. Nodes are directed "downward", - from parent to child. A special "synthetic" root node is added - to be the parent of the first node in each path. A special - "synthetic" leaf node, the "nil" node `-1`, is added to be the child - of all nodes representing the last element in a path. (The - addition of this nil node technically makes this not an - arborescence but a directed acyclic graph; removing the nil node - makes it an arborescence.) - - - Notes - ----- - The prefix tree is also known as a *trie*. - - - Examples - -------- - Create a prefix tree from a list of strings with common prefixes:: - - >>> paths = ["ab", "abs", "ad"] - >>> T = nx.prefix_tree(paths) - >>> list(T.edges) - [(0, 1), (1, 2), (1, 4), (2, -1), (2, 3), (3, -1), (4, -1)] - - The leaf nodes can be obtained as predecessors of the nil node. - - >>> root, NIL = 0, -1 - >>> list(T.predecessors(NIL)) - [2, 3, 4] - - To recover the original paths that generated the prefix tree, - traverse up the tree from the node `-1` to the node `0`:: - - >>> recovered = [] - >>> for v in T.predecessors(NIL): - ... prefix = "" - ... while v != root: - ... prefix = str(T.nodes[v]["source"]) + prefix - ... v = next(T.predecessors(v)) # only one predecessor - ... recovered.append(prefix) - >>> sorted(recovered) - ['ab', 'abs', 'ad'] - """ - - def _helper(paths, root, tree): - """Recursively create a trie from the given list of paths. - - `paths` is a list of paths, each of which is itself a list of - nodes, relative to the given `root` (but not including it). This - list of paths will be interpreted as a tree-like structure, in - which two paths that share a prefix represent two branches of - the tree with the same initial segment. - - `root` is the parent of the node at index 0 in each path. - - `tree` is the "accumulator", the :class:`networkx.DiGraph` - representing the branching to which the new nodes and edges will - be added. - - """ - # For each path, remove the first node and make it a child of root. - # Any remaining paths then get processed recursively. - children = defaultdict(list) - for path in paths: - # If path is empty, we add an edge to the NIL node. - if not path: - tree.add_edge(root, NIL) - continue - child, *rest = path - # `child` may exist as the head of more than one path in `paths`. - children[child].append(rest) - # Add a node for each child, connect root, recurse to remaining paths - for child, remaining_paths in children.items(): - # We relabel each child with an unused name. - new_name = len(tree) - 1 - # The "source" node attribute stores the original node name. - tree.add_node(new_name, source=child) - tree.add_edge(root, new_name) - _helper(remaining_paths, new_name, tree) - - # Initialize the prefix tree with a root node and a nil node. - tree = nx.DiGraph() - root = 0 - tree.add_node(root, source=None) - NIL = -1 - tree.add_node(NIL, source="NIL") - # Populate the tree. - _helper(paths, root, tree) - return tree - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_labeled_tree(n, *, seed=None): - """Returns a labeled tree on `n` nodes chosen uniformly at random. - - Generating uniformly distributed random Prüfer sequences and - converting them into the corresponding trees is a straightforward - method of generating uniformly distributed random labeled trees. - This function implements this method. - - Parameters - ---------- - n : int - The number of nodes, greater than zero. - seed : random_state - Indicator of random number generation state. - See :ref:`Randomness` - - Returns - ------- - :class:`networkx.Graph` - A `networkx.Graph` with nodes in the set {0, …, *n* - 1}. - - Raises - ------ - NetworkXPointlessConcept - If `n` is zero (because the null graph is not a tree). - - Examples - -------- - >>> G = nx.random_labeled_tree(5, seed=42) - >>> nx.is_tree(G) - True - >>> G.edges - EdgeView([(0, 1), (0, 3), (0, 2), (2, 4)]) - - A tree with *arbitrarily directed* edges can be created by assigning - generated edges to a ``DiGraph``: - - >>> DG = nx.DiGraph() - >>> DG.add_edges_from(G.edges) - >>> nx.is_tree(DG) - True - >>> DG.edges - OutEdgeView([(0, 1), (0, 3), (0, 2), (2, 4)]) - """ - # Cannot create a Prüfer sequence unless `n` is at least two. - if n == 0: - raise nx.NetworkXPointlessConcept("the null graph is not a tree") - if n == 1: - return nx.empty_graph(1) - return nx.from_prufer_sequence([seed.choice(range(n)) for i in range(n - 2)]) - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_labeled_rooted_tree(n, *, seed=None): - """Returns a labeled rooted tree with `n` nodes. - - The returned tree is chosen uniformly at random from all labeled rooted trees. - - Parameters - ---------- - n : int - The number of nodes - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`networkx.Graph` - A `networkx.Graph` with integer nodes 0 <= node <= `n` - 1. - The root of the tree is selected uniformly from the nodes. - The "root" graph attribute identifies the root of the tree. - - Notes - ----- - This function returns the result of :func:`random_labeled_tree` - with a randomly selected root. - - Raises - ------ - NetworkXPointlessConcept - If `n` is zero (because the null graph is not a tree). - """ - t = random_labeled_tree(n, seed=seed) - t.graph["root"] = seed.randint(0, n - 1) - return t - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_labeled_rooted_forest(n, *, seed=None): - """Returns a labeled rooted forest with `n` nodes. - - The returned forest is chosen uniformly at random using a - generalization of Prüfer sequences [1]_ in the form described in [2]_. - - Parameters - ---------- - n : int - The number of nodes. - seed : random_state - See :ref:`Randomness`. - - Returns - ------- - :class:`networkx.Graph` - A `networkx.Graph` with integer nodes 0 <= node <= `n` - 1. - The "roots" graph attribute is a set of integers containing the roots. - - References - ---------- - .. [1] Knuth, Donald E. "Another Enumeration of Trees." - Canadian Journal of Mathematics, 20 (1968): 1077-1086. - https://doi.org/10.4153/CJM-1968-104-8 - .. [2] Rubey, Martin. "Counting Spanning Trees". Diplomarbeit - zur Erlangung des akademischen Grades Magister der - Naturwissenschaften an der Formal- und Naturwissenschaftlichen - Fakultät der Universität Wien. Wien, May 2000. - """ - - # Select the number of roots by iterating over the cumulative count of trees - # with at most k roots - def _select_k(n, seed): - r = seed.randint(0, (n + 1) ** (n - 1) - 1) - cum_sum = 0 - for k in range(1, n): - cum_sum += (factorial(n - 1) * n ** (n - k)) // ( - factorial(k - 1) * factorial(n - k) - ) - if r < cum_sum: - return k - - return n - - F = nx.empty_graph(n) - if n == 0: - F.graph["roots"] = {} - return F - # Select the number of roots k - k = _select_k(n, seed) - if k == n: - F.graph["roots"] = set(range(n)) - return F # Nothing to do - # Select the roots - roots = seed.sample(range(n), k) - # Nonroots - p = set(range(n)).difference(roots) - # Coding sequence - N = [seed.randint(0, n - 1) for i in range(n - k - 1)] - # Multiset of elements in N also in p - degree = Counter([x for x in N if x in p]) - # Iterator over the elements of p with degree zero - iterator = iter(x for x in p if degree[x] == 0) - u = last = next(iterator) - # This loop is identical to that for Prüfer sequences, - # except that we can draw nodes only from p - for v in N: - F.add_edge(u, v) - degree[v] -= 1 - if v < last and degree[v] == 0: - u = v - else: - last = u = next(iterator) - - F.add_edge(u, roots[0]) - F.graph["roots"] = set(roots) - return F - - -# The following functions support generation of unlabeled trees and forests. - - -def _to_nx(edges, n_nodes, root=None, roots=None): - """ - Converts the (edges, n_nodes) input to a :class:`networkx.Graph`. - The (edges, n_nodes) input is a list of even length, where each pair - of consecutive integers represents an edge, and an integer `n_nodes`. - Integers in the list are elements of `range(n_nodes)`. - - Parameters - ---------- - edges : list of ints - The flattened list of edges of the graph. - n_nodes : int - The number of nodes of the graph. - root: int (default=None) - If not None, the "root" attribute of the graph will be set to this value. - roots: collection of ints (default=None) - If not None, he "roots" attribute of the graph will be set to this value. - - Returns - ------- - :class:`networkx.Graph` - The graph with `n_nodes` nodes and edges given by `edges`. - """ - G = nx.empty_graph(n_nodes) - G.add_edges_from(edges) - if root is not None: - G.graph["root"] = root - if roots is not None: - G.graph["roots"] = roots - return G - - -def _num_rooted_trees(n, cache_trees): - """Returns the number of unlabeled rooted trees with `n` nodes. - - See also https://oeis.org/A000081. - - Parameters - ---------- - n : int - The number of nodes - cache_trees : list of ints - The $i$-th element is the number of unlabeled rooted trees with $i$ nodes, - which is used as a cache (and is extended to length $n+1$ if needed) - - Returns - ------- - int - The number of unlabeled rooted trees with `n` nodes. - """ - for n_i in range(len(cache_trees), n + 1): - cache_trees.append( - sum( - [ - d * cache_trees[n_i - j * d] * cache_trees[d] - for d in range(1, n_i) - for j in range(1, (n_i - 1) // d + 1) - ] - ) - // (n_i - 1) - ) - return cache_trees[n] - - -def _select_jd_trees(n, cache_trees, seed): - """Returns a pair $(j,d)$ with a specific probability - - Given $n$, returns a pair of positive integers $(j,d)$ with the probability - specified in formula (5) of Chapter 29 of [1]_. - - Parameters - ---------- - n : int - The number of nodes - cache_trees : list of ints - Cache for :func:`_num_rooted_trees`. - seed : random_state - See :ref:`Randomness`. - - Returns - ------- - (int, int) - A pair of positive integers $(j,d)$ satisfying formula (5) of - Chapter 29 of [1]_. - - References - ---------- - .. [1] Nijenhuis, Albert, and Wilf, Herbert S. - "Combinatorial algorithms: for computers and calculators." - Academic Press, 1978. - https://doi.org/10.1016/C2013-0-11243-3 - """ - p = seed.randint(0, _num_rooted_trees(n, cache_trees) * (n - 1) - 1) - cumsum = 0 - for d in range(n - 1, 0, -1): - for j in range(1, (n - 1) // d + 1): - cumsum += ( - d - * _num_rooted_trees(n - j * d, cache_trees) - * _num_rooted_trees(d, cache_trees) - ) - if p < cumsum: - return (j, d) - - -def _random_unlabeled_rooted_tree(n, cache_trees, seed): - """Returns an unlabeled rooted tree with `n` nodes. - - Returns an unlabeled rooted tree with `n` nodes chosen uniformly - at random using the "RANRUT" algorithm from [1]_. - The tree is returned in the form: (list_of_edges, number_of_nodes) - - Parameters - ---------- - n : int - The number of nodes, greater than zero. - cache_trees : list ints - Cache for :func:`_num_rooted_trees`. - seed : random_state - See :ref:`Randomness`. - - Returns - ------- - (list_of_edges, number_of_nodes) : list, int - A random unlabeled rooted tree with `n` nodes as a 2-tuple - ``(list_of_edges, number_of_nodes)``. - The root is node 0. - - References - ---------- - .. [1] Nijenhuis, Albert, and Wilf, Herbert S. - "Combinatorial algorithms: for computers and calculators." - Academic Press, 1978. - https://doi.org/10.1016/C2013-0-11243-3 - """ - if n == 1: - edges, n_nodes = [], 1 - return edges, n_nodes - if n == 2: - edges, n_nodes = [(0, 1)], 2 - return edges, n_nodes - - j, d = _select_jd_trees(n, cache_trees, seed) - t1, t1_nodes = _random_unlabeled_rooted_tree(n - j * d, cache_trees, seed) - t2, t2_nodes = _random_unlabeled_rooted_tree(d, cache_trees, seed) - t12 = [(0, t2_nodes * i + t1_nodes) for i in range(j)] - t1.extend(t12) - for _ in range(j): - t1.extend((n1 + t1_nodes, n2 + t1_nodes) for n1, n2 in t2) - t1_nodes += t2_nodes - - return t1, t1_nodes - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_unlabeled_rooted_tree(n, *, number_of_trees=None, seed=None): - """Returns a number of unlabeled rooted trees uniformly at random - - Returns one or more (depending on `number_of_trees`) - unlabeled rooted trees with `n` nodes drawn uniformly - at random. - - Parameters - ---------- - n : int - The number of nodes - number_of_trees : int or None (default) - If not None, this number of trees is generated and returned. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`networkx.Graph` or list of :class:`networkx.Graph` - A single `networkx.Graph` (or a list thereof, if `number_of_trees` - is specified) with nodes in the set {0, …, *n* - 1}. - The "root" graph attribute identifies the root of the tree. - - Notes - ----- - The trees are generated using the "RANRUT" algorithm from [1]_. - The algorithm needs to compute some counting functions - that are relatively expensive: in case several trees are needed, - it is advisable to use the `number_of_trees` optional argument - to reuse the counting functions. - - Raises - ------ - NetworkXPointlessConcept - If `n` is zero (because the null graph is not a tree). - - References - ---------- - .. [1] Nijenhuis, Albert, and Wilf, Herbert S. - "Combinatorial algorithms: for computers and calculators." - Academic Press, 1978. - https://doi.org/10.1016/C2013-0-11243-3 - """ - if n == 0: - raise nx.NetworkXPointlessConcept("the null graph is not a tree") - cache_trees = [0, 1] # initial cache of number of rooted trees - if number_of_trees is None: - return _to_nx(*_random_unlabeled_rooted_tree(n, cache_trees, seed), root=0) - return [ - _to_nx(*_random_unlabeled_rooted_tree(n, cache_trees, seed), root=0) - for i in range(number_of_trees) - ] - - -def _num_rooted_forests(n, q, cache_forests): - """Returns the number of unlabeled rooted forests with `n` nodes, and with - no more than `q` nodes per tree. A recursive formula for this is (2) in - [1]_. This function is implemented using dynamic programming instead of - recursion. - - Parameters - ---------- - n : int - The number of nodes. - q : int - The maximum number of nodes for each tree of the forest. - cache_forests : list of ints - The $i$-th element is the number of unlabeled rooted forests with - $i$ nodes, and with no more than `q` nodes per tree; this is used - as a cache (and is extended to length `n` + 1 if needed). - - Returns - ------- - int - The number of unlabeled rooted forests with `n` nodes with no more than - `q` nodes per tree. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - for n_i in range(len(cache_forests), n + 1): - q_i = min(n_i, q) - cache_forests.append( - sum( - [ - d * cache_forests[n_i - j * d] * cache_forests[d - 1] - for d in range(1, q_i + 1) - for j in range(1, n_i // d + 1) - ] - ) - // n_i - ) - - return cache_forests[n] - - -def _select_jd_forests(n, q, cache_forests, seed): - """Given `n` and `q`, returns a pair of positive integers $(j,d)$ - such that $j\\leq d$, with probability satisfying (F1) of [1]_. - - Parameters - ---------- - n : int - The number of nodes. - q : int - The maximum number of nodes for each tree of the forest. - cache_forests : list of ints - Cache for :func:`_num_rooted_forests`. - seed : random_state - See :ref:`Randomness`. - - Returns - ------- - (int, int) - A pair of positive integers $(j,d)$ - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - p = seed.randint(0, _num_rooted_forests(n, q, cache_forests) * n - 1) - cumsum = 0 - for d in range(q, 0, -1): - for j in range(1, n // d + 1): - cumsum += ( - d - * _num_rooted_forests(n - j * d, q, cache_forests) - * _num_rooted_forests(d - 1, q, cache_forests) - ) - if p < cumsum: - return (j, d) - - -def _random_unlabeled_rooted_forest(n, q, cache_trees, cache_forests, seed): - """Returns an unlabeled rooted forest with `n` nodes, and with no more - than `q` nodes per tree, drawn uniformly at random. It is an implementation - of the algorithm "Forest" of [1]_. - - Parameters - ---------- - n : int - The number of nodes. - q : int - The maximum number of nodes per tree. - cache_trees : - Cache for :func:`_num_rooted_trees`. - cache_forests : - Cache for :func:`_num_rooted_forests`. - seed : random_state - See :ref:`Randomness`. - - Returns - ------- - (edges, n, r) : (list, int, list) - The forest (edges, n) and a list r of root nodes. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - if n == 0: - return ([], 0, []) - - j, d = _select_jd_forests(n, q, cache_forests, seed) - t1, t1_nodes, r1 = _random_unlabeled_rooted_forest( - n - j * d, q, cache_trees, cache_forests, seed - ) - t2, t2_nodes = _random_unlabeled_rooted_tree(d, cache_trees, seed) - for _ in range(j): - r1.append(t1_nodes) - t1.extend((n1 + t1_nodes, n2 + t1_nodes) for n1, n2 in t2) - t1_nodes += t2_nodes - return t1, t1_nodes, r1 - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_unlabeled_rooted_forest(n, *, q=None, number_of_forests=None, seed=None): - """Returns a forest or list of forests selected at random. - - Returns one or more (depending on `number_of_forests`) - unlabeled rooted forests with `n` nodes, and with no more than - `q` nodes per tree, drawn uniformly at random. - The "roots" graph attribute identifies the roots of the forest. - - Parameters - ---------- - n : int - The number of nodes - q : int or None (default) - The maximum number of nodes per tree. - number_of_forests : int or None (default) - If not None, this number of forests is generated and returned. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`networkx.Graph` or list of :class:`networkx.Graph` - A single `networkx.Graph` (or a list thereof, if `number_of_forests` - is specified) with nodes in the set {0, …, *n* - 1}. - The "roots" graph attribute is a set containing the roots - of the trees in the forest. - - Notes - ----- - This function implements the algorithm "Forest" of [1]_. - The algorithm needs to compute some counting functions - that are relatively expensive: in case several trees are needed, - it is advisable to use the `number_of_forests` optional argument - to reuse the counting functions. - - Raises - ------ - ValueError - If `n` is non-zero but `q` is zero. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - if q is None: - q = n - if q == 0 and n != 0: - raise ValueError("q must be a positive integer if n is positive.") - - cache_trees = [0, 1] # initial cache of number of rooted trees - cache_forests = [1] # initial cache of number of rooted forests - - if number_of_forests is None: - g, nodes, rs = _random_unlabeled_rooted_forest( - n, q, cache_trees, cache_forests, seed - ) - return _to_nx(g, nodes, roots=set(rs)) - - res = [] - for i in range(number_of_forests): - g, nodes, rs = _random_unlabeled_rooted_forest( - n, q, cache_trees, cache_forests, seed - ) - res.append(_to_nx(g, nodes, roots=set(rs))) - return res - - -def _num_trees(n, cache_trees): - """Returns the number of unlabeled trees with `n` nodes. - - See also https://oeis.org/A000055. - - Parameters - ---------- - n : int - The number of nodes. - cache_trees : list of ints - Cache for :func:`_num_rooted_trees`. - - Returns - ------- - int - The number of unlabeled trees with `n` nodes. - """ - r = _num_rooted_trees(n, cache_trees) - sum( - [ - _num_rooted_trees(j, cache_trees) * _num_rooted_trees(n - j, cache_trees) - for j in range(1, n // 2 + 1) - ] - ) - if n % 2 == 0: - r += comb(_num_rooted_trees(n // 2, cache_trees) + 1, 2) - return r - - -def _bicenter(n, cache, seed): - """Returns a bi-centroidal tree on `n` nodes drawn uniformly at random. - - This function implements the algorithm Bicenter of [1]_. - - Parameters - ---------- - n : int - The number of nodes (must be even). - cache : list of ints. - Cache for :func:`_num_rooted_trees`. - seed : random_state - See :ref:`Randomness` - - Returns - ------- - (edges, n) - The tree as a list of edges and number of nodes. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - t, t_nodes = _random_unlabeled_rooted_tree(n // 2, cache, seed) - if seed.randint(0, _num_rooted_trees(n // 2, cache)) == 0: - t2, t2_nodes = t, t_nodes - else: - t2, t2_nodes = _random_unlabeled_rooted_tree(n // 2, cache, seed) - t.extend([(n1 + (n // 2), n2 + (n // 2)) for n1, n2 in t2]) - t.append((0, n // 2)) - return t, t_nodes + t2_nodes - - -def _random_unlabeled_tree(n, cache_trees, cache_forests, seed): - """Returns a tree on `n` nodes drawn uniformly at random. - It implements the Wilf's algorithm "Free" of [1]_. - - Parameters - ---------- - n : int - The number of nodes, greater than zero. - cache_trees : list of ints - Cache for :func:`_num_rooted_trees`. - cache_forests : list of ints - Cache for :func:`_num_rooted_forests`. - seed : random_state - Indicator of random number generation state. - See :ref:`Randomness` - - Returns - ------- - (edges, n) - The tree as a list of edges and number of nodes. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - if n % 2 == 1: - p = 0 - else: - p = comb(_num_rooted_trees(n // 2, cache_trees) + 1, 2) - if seed.randint(0, _num_trees(n, cache_trees) - 1) < p: - return _bicenter(n, cache_trees, seed) - else: - f, n_f, r = _random_unlabeled_rooted_forest( - n - 1, (n - 1) // 2, cache_trees, cache_forests, seed - ) - for i in r: - f.append((i, n_f)) - return f, n_f + 1 - - -@py_random_state("seed") -@nx._dispatchable(graphs=None, returns_graph=True) -def random_unlabeled_tree(n, *, number_of_trees=None, seed=None): - """Returns a tree or list of trees chosen randomly. - - Returns one or more (depending on `number_of_trees`) - unlabeled trees with `n` nodes drawn uniformly at random. - - Parameters - ---------- - n : int - The number of nodes - number_of_trees : int or None (default) - If not None, this number of trees is generated and returned. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`networkx.Graph` or list of :class:`networkx.Graph` - A single `networkx.Graph` (or a list thereof, if - `number_of_trees` is specified) with nodes in the set {0, …, *n* - 1}. - - Raises - ------ - NetworkXPointlessConcept - If `n` is zero (because the null graph is not a tree). - - Notes - ----- - This function generates an unlabeled tree uniformly at random using - Wilf's algorithm "Free" of [1]_. The algorithm needs to - compute some counting functions that are relatively expensive: - in case several trees are needed, it is advisable to use the - `number_of_trees` optional argument to reuse the counting - functions. - - References - ---------- - .. [1] Wilf, Herbert S. "The uniform selection of free trees." - Journal of Algorithms 2.2 (1981): 204-207. - https://doi.org/10.1016/0196-6774(81)90021-3 - """ - if n == 0: - raise nx.NetworkXPointlessConcept("the null graph is not a tree") - - cache_trees = [0, 1] # initial cache of number of rooted trees - cache_forests = [1] # initial cache of number of rooted forests - if number_of_trees is None: - return _to_nx(*_random_unlabeled_tree(n, cache_trees, cache_forests, seed)) - else: - return [ - _to_nx(*_random_unlabeled_tree(n, cache_trees, cache_forests, seed)) - for i in range(number_of_trees) - ] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/generators/triads.py b/extensions/.local/lib/python3.11/site-packages/networkx/generators/triads.py deleted file mode 100644 index 09b722d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/generators/triads.py +++ /dev/null @@ -1,94 +0,0 @@ -# See https://github.com/networkx/networkx/pull/1474 -# Copyright 2011 Reya Group -# Copyright 2011 Alex Levenson -# Copyright 2011 Diederik van Liere -"""Functions that generate the triad graphs, that is, the possible -digraphs on three nodes. - -""" - -import networkx as nx -from networkx.classes import DiGraph - -__all__ = ["triad_graph"] - -#: Dictionary mapping triad name to list of directed edges in the -#: digraph representation of that triad (with nodes 'a', 'b', and 'c'). -TRIAD_EDGES = { - "003": [], - "012": ["ab"], - "102": ["ab", "ba"], - "021D": ["ba", "bc"], - "021U": ["ab", "cb"], - "021C": ["ab", "bc"], - "111D": ["ac", "ca", "bc"], - "111U": ["ac", "ca", "cb"], - "030T": ["ab", "cb", "ac"], - "030C": ["ba", "cb", "ac"], - "201": ["ab", "ba", "ac", "ca"], - "120D": ["bc", "ba", "ac", "ca"], - "120U": ["ab", "cb", "ac", "ca"], - "120C": ["ab", "bc", "ac", "ca"], - "210": ["ab", "bc", "cb", "ac", "ca"], - "300": ["ab", "ba", "bc", "cb", "ac", "ca"], -} - - -@nx._dispatchable(graphs=None, returns_graph=True) -def triad_graph(triad_name): - """Returns the triad graph with the given name. - - Each string in the following tuple is a valid triad name:: - - ( - "003", - "012", - "102", - "021D", - "021U", - "021C", - "111D", - "111U", - "030T", - "030C", - "201", - "120D", - "120U", - "120C", - "210", - "300", - ) - - Each triad name corresponds to one of the possible valid digraph on - three nodes. - - Parameters - ---------- - triad_name : string - The name of a triad, as described above. - - Returns - ------- - :class:`~networkx.DiGraph` - The digraph on three nodes with the given name. The nodes of the - graph are the single-character strings 'a', 'b', and 'c'. - - Raises - ------ - ValueError - If `triad_name` is not the name of a triad. - - See also - -------- - triadic_census - - """ - if triad_name not in TRIAD_EDGES: - raise ValueError( - f'unknown triad name "{triad_name}"; use one of the triad names' - " in the TRIAD_NAMES constant" - ) - G = DiGraph() - G.add_nodes_from("abc") - G.add_edges_from(TRIAD_EDGES[triad_name]) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/lazy_imports.py b/extensions/.local/lib/python3.11/site-packages/networkx/lazy_imports.py deleted file mode 100644 index 396404b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/lazy_imports.py +++ /dev/null @@ -1,188 +0,0 @@ -import importlib -import importlib.util -import inspect -import os -import sys -import types - -__all__ = ["attach", "_lazy_import"] - - -def attach(module_name, submodules=None, submod_attrs=None): - """Attach lazily loaded submodules, and functions or other attributes. - - Typically, modules import submodules and attributes as follows:: - - import mysubmodule - import anothersubmodule - - from .foo import someattr - - The idea of this function is to replace the `__init__.py` - module's `__getattr__`, `__dir__`, and `__all__` attributes such that - all imports work exactly the way they normally would, except that the - actual import is delayed until the resulting module object is first used. - - The typical way to call this function, replacing the above imports, is:: - - __getattr__, __lazy_dir__, __all__ = lazy.attach( - __name__, ["mysubmodule", "anothersubmodule"], {"foo": "someattr"} - ) - - This functionality requires Python 3.7 or higher. - - Parameters - ---------- - module_name : str - Typically use __name__. - submodules : set - List of submodules to lazily import. - submod_attrs : dict - Dictionary of submodule -> list of attributes / functions. - These attributes are imported as they are used. - - Returns - ------- - __getattr__, __dir__, __all__ - - """ - if submod_attrs is None: - submod_attrs = {} - - if submodules is None: - submodules = set() - else: - submodules = set(submodules) - - attr_to_modules = { - attr: mod for mod, attrs in submod_attrs.items() for attr in attrs - } - - __all__ = list(submodules | attr_to_modules.keys()) - - def __getattr__(name): - if name in submodules: - return importlib.import_module(f"{module_name}.{name}") - elif name in attr_to_modules: - submod = importlib.import_module(f"{module_name}.{attr_to_modules[name]}") - return getattr(submod, name) - else: - raise AttributeError(f"No {module_name} attribute {name}") - - def __dir__(): - return __all__ - - if os.environ.get("EAGER_IMPORT", ""): - for attr in set(attr_to_modules.keys()) | submodules: - __getattr__(attr) - - return __getattr__, __dir__, list(__all__) - - -class DelayedImportErrorModule(types.ModuleType): - def __init__(self, frame_data, *args, **kwargs): - self.__frame_data = frame_data - super().__init__(*args, **kwargs) - - def __getattr__(self, x): - if x in ("__class__", "__file__", "__frame_data"): - super().__getattr__(x) - else: - fd = self.__frame_data - raise ModuleNotFoundError( - f"No module named '{fd['spec']}'\n\n" - "This error is lazily reported, having originally occurred in\n" - f' File {fd["filename"]}, line {fd["lineno"]}, in {fd["function"]}\n\n' - f'----> {"".join(fd["code_context"] or "").strip()}' - ) - - -def _lazy_import(fullname): - """Return a lazily imported proxy for a module or library. - - Warning - ------- - Importing using this function can currently cause trouble - when the user tries to import from a subpackage of a module before - the package is fully imported. In particular, this idiom may not work: - - np = lazy_import("numpy") - from numpy.lib import recfunctions - - This is due to a difference in the way Python's LazyLoader handles - subpackage imports compared to the normal import process. Hopefully - we will get Python's LazyLoader to fix this, or find a workaround. - In the meantime, this is a potential problem. - - The workaround is to import numpy before importing from the subpackage. - - Notes - ----- - We often see the following pattern:: - - def myfunc(): - import scipy as sp - sp.argmin(...) - .... - - This is to prevent a library, in this case `scipy`, from being - imported at function definition time, since that can be slow. - - This function provides a proxy module that, upon access, imports - the actual module. So the idiom equivalent to the above example is:: - - sp = lazy.load("scipy") - - def myfunc(): - sp.argmin(...) - .... - - The initial import time is fast because the actual import is delayed - until the first attribute is requested. The overall import time may - decrease as well for users that don't make use of large portions - of the library. - - Parameters - ---------- - fullname : str - The full name of the package or subpackage to import. For example:: - - sp = lazy.load("scipy") # import scipy as sp - spla = lazy.load("scipy.linalg") # import scipy.linalg as spla - - Returns - ------- - pm : importlib.util._LazyModule - Proxy module. Can be used like any regularly imported module. - Actual loading of the module occurs upon first attribute request. - - """ - try: - return sys.modules[fullname] - except: - pass - - # Not previously loaded -- look it up - spec = importlib.util.find_spec(fullname) - - if spec is None: - try: - parent = inspect.stack()[1] - frame_data = { - "spec": fullname, - "filename": parent.filename, - "lineno": parent.lineno, - "function": parent.function, - "code_context": parent.code_context, - } - return DelayedImportErrorModule(frame_data, "DelayedImportErrorModule") - finally: - del parent - - module = importlib.util.module_from_spec(spec) - sys.modules[fullname] = module - - loader = importlib.util.LazyLoader(spec.loader) - loader.exec_module(module) - - return module diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/__init__.py deleted file mode 100644 index 119db18..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from networkx.linalg.attrmatrix import * -from networkx.linalg import attrmatrix -from networkx.linalg.spectrum import * -from networkx.linalg import spectrum -from networkx.linalg.graphmatrix import * -from networkx.linalg import graphmatrix -from networkx.linalg.laplacianmatrix import * -from networkx.linalg import laplacianmatrix -from networkx.linalg.algebraicconnectivity import * -from networkx.linalg.modularitymatrix import * -from networkx.linalg import modularitymatrix -from networkx.linalg.bethehessianmatrix import * -from networkx.linalg import bethehessianmatrix diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/algebraicconnectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/algebraicconnectivity.py deleted file mode 100644 index c94972a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/algebraicconnectivity.py +++ /dev/null @@ -1,657 +0,0 @@ -""" -Algebraic connectivity and Fiedler vectors of undirected graphs. -""" - -from functools import partial - -import networkx as nx -from networkx.utils import ( - not_implemented_for, - np_random_state, - reverse_cuthill_mckee_ordering, -) - -__all__ = [ - "algebraic_connectivity", - "fiedler_vector", - "spectral_ordering", - "spectral_bisection", -] - - -class _PCGSolver: - """Preconditioned conjugate gradient method. - - To solve Ax = b: - M = A.diagonal() # or some other preconditioner - solver = _PCGSolver(lambda x: A * x, lambda x: M * x) - x = solver.solve(b) - - The inputs A and M are functions which compute - matrix multiplication on the argument. - A - multiply by the matrix A in Ax=b - M - multiply by M, the preconditioner surrogate for A - - Warning: There is no limit on number of iterations. - """ - - def __init__(self, A, M): - self._A = A - self._M = M - - def solve(self, B, tol): - import numpy as np - - # Densifying step - can this be kept sparse? - B = np.asarray(B) - X = np.ndarray(B.shape, order="F") - for j in range(B.shape[1]): - X[:, j] = self._solve(B[:, j], tol) - return X - - def _solve(self, b, tol): - import numpy as np - import scipy as sp - - A = self._A - M = self._M - tol *= sp.linalg.blas.dasum(b) - # Initialize. - x = np.zeros(b.shape) - r = b.copy() - z = M(r) - rz = sp.linalg.blas.ddot(r, z) - p = z.copy() - # Iterate. - while True: - Ap = A(p) - alpha = rz / sp.linalg.blas.ddot(p, Ap) - x = sp.linalg.blas.daxpy(p, x, a=alpha) - r = sp.linalg.blas.daxpy(Ap, r, a=-alpha) - if sp.linalg.blas.dasum(r) < tol: - return x - z = M(r) - beta = sp.linalg.blas.ddot(r, z) - beta, rz = beta / rz, beta - p = sp.linalg.blas.daxpy(p, z, a=beta) - - -class _LUSolver: - """LU factorization. - - To solve Ax = b: - solver = _LUSolver(A) - x = solver.solve(b) - - optional argument `tol` on solve method is ignored but included - to match _PCGsolver API. - """ - - def __init__(self, A): - import scipy as sp - - self._LU = sp.sparse.linalg.splu( - A, - permc_spec="MMD_AT_PLUS_A", - diag_pivot_thresh=0.0, - options={"Equil": True, "SymmetricMode": True}, - ) - - def solve(self, B, tol=None): - import numpy as np - - B = np.asarray(B) - X = np.ndarray(B.shape, order="F") - for j in range(B.shape[1]): - X[:, j] = self._LU.solve(B[:, j]) - return X - - -def _preprocess_graph(G, weight): - """Compute edge weights and eliminate zero-weight edges.""" - if G.is_directed(): - H = nx.MultiGraph() - H.add_nodes_from(G) - H.add_weighted_edges_from( - ((u, v, e.get(weight, 1.0)) for u, v, e in G.edges(data=True) if u != v), - weight=weight, - ) - G = H - if not G.is_multigraph(): - edges = ( - (u, v, abs(e.get(weight, 1.0))) for u, v, e in G.edges(data=True) if u != v - ) - else: - edges = ( - (u, v, sum(abs(e.get(weight, 1.0)) for e in G[u][v].values())) - for u, v in G.edges() - if u != v - ) - H = nx.Graph() - H.add_nodes_from(G) - H.add_weighted_edges_from((u, v, e) for u, v, e in edges if e != 0) - return H - - -def _rcm_estimate(G, nodelist): - """Estimate the Fiedler vector using the reverse Cuthill-McKee ordering.""" - import numpy as np - - G = G.subgraph(nodelist) - order = reverse_cuthill_mckee_ordering(G) - n = len(nodelist) - index = dict(zip(nodelist, range(n))) - x = np.ndarray(n, dtype=float) - for i, u in enumerate(order): - x[index[u]] = i - x -= (n - 1) / 2.0 - return x - - -def _tracemin_fiedler(L, X, normalized, tol, method): - """Compute the Fiedler vector of L using the TraceMIN-Fiedler algorithm. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix - of the graph. This function starts with the Laplacian L, not the Graph. - - Parameters - ---------- - L : Laplacian of a possibly weighted or normalized, but undirected graph - - X : Initial guess for a solution. Usually a matrix of random numbers. - This function allows more than one column in X to identify more than - one eigenvector if desired. - - normalized : bool - Whether the normalized Laplacian matrix is used. - - tol : float - Tolerance of relative residual in eigenvalue computation. - Warning: There is no limit on number of iterations. - - method : string - Should be 'tracemin_pcg' or 'tracemin_lu'. - Otherwise exception is raised. - - Returns - ------- - sigma, X : Two NumPy arrays of floats. - The lowest eigenvalues and corresponding eigenvectors of L. - The size of input X determines the size of these outputs. - As this is for Fiedler vectors, the zero eigenvalue (and - constant eigenvector) are avoided. - """ - import numpy as np - import scipy as sp - - n = X.shape[0] - - if normalized: - # Form the normalized Laplacian matrix and determine the eigenvector of - # its nullspace. - e = np.sqrt(L.diagonal()) - # TODO: rm csr_array wrapper when spdiags array creation becomes available - D = sp.sparse.csr_array(sp.sparse.spdiags(1 / e, 0, n, n, format="csr")) - L = D @ L @ D - e *= 1.0 / np.linalg.norm(e, 2) - - if normalized: - - def project(X): - """Make X orthogonal to the nullspace of L.""" - X = np.asarray(X) - for j in range(X.shape[1]): - X[:, j] -= (X[:, j] @ e) * e - - else: - - def project(X): - """Make X orthogonal to the nullspace of L.""" - X = np.asarray(X) - for j in range(X.shape[1]): - X[:, j] -= X[:, j].sum() / n - - if method == "tracemin_pcg": - D = L.diagonal().astype(float) - solver = _PCGSolver(lambda x: L @ x, lambda x: D * x) - elif method == "tracemin_lu": - # Convert A to CSC to suppress SparseEfficiencyWarning. - A = sp.sparse.csc_array(L, dtype=float, copy=True) - # Force A to be nonsingular. Since A is the Laplacian matrix of a - # connected graph, its rank deficiency is one, and thus one diagonal - # element needs to modified. Changing to infinity forces a zero in the - # corresponding element in the solution. - i = (A.indptr[1:] - A.indptr[:-1]).argmax() - A[i, i] = np.inf - solver = _LUSolver(A) - else: - raise nx.NetworkXError(f"Unknown linear system solver: {method}") - - # Initialize. - Lnorm = abs(L).sum(axis=1).flatten().max() - project(X) - W = np.ndarray(X.shape, order="F") - - while True: - # Orthonormalize X. - X = np.linalg.qr(X)[0] - # Compute iteration matrix H. - W[:, :] = L @ X - H = X.T @ W - sigma, Y = sp.linalg.eigh(H, overwrite_a=True) - # Compute the Ritz vectors. - X = X @ Y - # Test for convergence exploiting the fact that L * X == W * Y. - res = sp.linalg.blas.dasum(W @ Y[:, 0] - sigma[0] * X[:, 0]) / Lnorm - if res < tol: - break - # Compute X = L \ X / (X' * (L \ X)). - # L \ X can have an arbitrary projection on the nullspace of L, - # which will be eliminated. - W[:, :] = solver.solve(X, tol) - X = (sp.linalg.inv(W.T @ X) @ W.T).T # Preserves Fortran storage order. - project(X) - - return sigma, np.asarray(X) - - -def _get_fiedler_func(method): - """Returns a function that solves the Fiedler eigenvalue problem.""" - import numpy as np - - if method == "tracemin": # old style keyword `. - - Returns - ------- - algebraic_connectivity : float - Algebraic connectivity. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - See Also - -------- - laplacian_matrix - - Examples - -------- - For undirected graphs algebraic connectivity can tell us if a graph is connected or not - `G` is connected iff ``algebraic_connectivity(G) > 0``: - - >>> G = nx.complete_graph(5) - >>> nx.algebraic_connectivity(G) > 0 - True - >>> G.add_node(10) # G is no longer connected - >>> nx.algebraic_connectivity(G) > 0 - False - - """ - if len(G) < 2: - raise nx.NetworkXError("graph has less than two nodes.") - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - return 0.0 - - L = nx.laplacian_matrix(G) - if L.shape[0] == 2: - return 2.0 * float(L[0, 0]) if not normalized else 2.0 - - find_fiedler = _get_fiedler_func(method) - x = None if method != "lobpcg" else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return float(sigma) - - -@not_implemented_for("directed") -@np_random_state(5) -@nx._dispatchable(edge_attrs="weight") -def fiedler_vector( - G, weight="weight", normalized=False, tol=1e-8, method="tracemin_pcg", seed=None -): - """Returns the Fiedler vector of a connected undirected graph. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix - of the graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - fiedler_vector : NumPy array of floats. - Fiedler vector. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes or is not connected. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - See Also - -------- - laplacian_matrix - - Examples - -------- - Given a connected graph the signs of the values in the Fiedler vector can be - used to partition the graph into two components. - - >>> G = nx.barbell_graph(5, 0) - >>> nx.fiedler_vector(G, normalized=True, seed=1) - array([-0.32864129, -0.32864129, -0.32864129, -0.32864129, -0.26072899, - 0.26072899, 0.32864129, 0.32864129, 0.32864129, 0.32864129]) - - The connected components are the two 5-node cliques of the barbell graph. - """ - import numpy as np - - if len(G) < 2: - raise nx.NetworkXError("graph has less than two nodes.") - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - raise nx.NetworkXError("graph is not connected.") - - if len(G) == 2: - return np.array([1.0, -1.0]) - - find_fiedler = _get_fiedler_func(method) - L = nx.laplacian_matrix(G) - x = None if method != "lobpcg" else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return fiedler - - -@np_random_state(5) -@nx._dispatchable(edge_attrs="weight") -def spectral_ordering( - G, weight="weight", normalized=False, tol=1e-8, method="tracemin_pcg", seed=None -): - """Compute the spectral_ordering of a graph. - - The spectral ordering of a graph is an ordering of its nodes where nodes - in the same weakly connected components appear contiguous and ordered by - their corresponding elements in the Fiedler vector of the component. - - Parameters - ---------- - G : NetworkX graph - A graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - spectral_ordering : NumPy array of floats. - Spectral ordering of nodes. - - Raises - ------ - NetworkXError - If G is empty. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - See Also - -------- - laplacian_matrix - """ - if len(G) == 0: - raise nx.NetworkXError("graph is empty.") - G = _preprocess_graph(G, weight) - - find_fiedler = _get_fiedler_func(method) - order = [] - for component in nx.connected_components(G): - size = len(component) - if size > 2: - L = nx.laplacian_matrix(G, component) - x = None if method != "lobpcg" else _rcm_estimate(G, component) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - sort_info = zip(fiedler, range(size), component) - order.extend(u for x, c, u in sorted(sort_info)) - else: - order.extend(component) - - return order - - -@nx._dispatchable(edge_attrs="weight") -def spectral_bisection( - G, weight="weight", normalized=False, tol=1e-8, method="tracemin_pcg", seed=None -): - """Bisect the graph using the Fiedler vector. - - This method uses the Fiedler vector to bisect a graph. - The partition is defined by the nodes which are associated with - either positive or negative values in the vector. - - Parameters - ---------- - G : NetworkX Graph - - weight : str, optional (default: weight) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - bisection : tuple of sets - Sets with the bisection of nodes - - Examples - -------- - >>> G = nx.barbell_graph(3, 0) - >>> nx.spectral_bisection(G) - ({0, 1, 2}, {3, 4, 5}) - - References - ---------- - .. [1] M. E. J Newman 'Networks: An Introduction', pages 364-370 - Oxford University Press 2011. - """ - import numpy as np - - v = nx.fiedler_vector(G, weight, normalized, tol, method, seed) - nodes = np.array(list(G)) - pos_vals = v >= 0 - - return set(nodes[~pos_vals].tolist()), set(nodes[pos_vals].tolist()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/attrmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/attrmatrix.py deleted file mode 100644 index b5a7049..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/attrmatrix.py +++ /dev/null @@ -1,465 +0,0 @@ -""" -Functions for constructing matrix-like objects from graph attributes. -""" - -import networkx as nx - -__all__ = ["attr_matrix", "attr_sparse_matrix"] - - -def _node_value(G, node_attr): - """Returns a function that returns a value from G.nodes[u]. - - We return a function expecting a node as its sole argument. Then, in the - simplest scenario, the returned function will return G.nodes[u][node_attr]. - However, we also handle the case when `node_attr` is None or when it is a - function itself. - - Parameters - ---------- - G : graph - A NetworkX graph - - node_attr : {None, str, callable} - Specification of how the value of the node attribute should be obtained - from the node attribute dictionary. - - Returns - ------- - value : function - A function expecting a node as its sole argument. The function will - returns a value from G.nodes[u] that depends on `edge_attr`. - - """ - if node_attr is None: - - def value(u): - return u - - elif not callable(node_attr): - # assume it is a key for the node attribute dictionary - def value(u): - return G.nodes[u][node_attr] - - else: - # Advanced: Allow users to specify something else. - # - # For example, - # node_attr = lambda u: G.nodes[u].get('size', .5) * 3 - # - value = node_attr - - return value - - -def _edge_value(G, edge_attr): - """Returns a function that returns a value from G[u][v]. - - Suppose there exists an edge between u and v. Then we return a function - expecting u and v as arguments. For Graph and DiGraph, G[u][v] is - the edge attribute dictionary, and the function (essentially) returns - G[u][v][edge_attr]. However, we also handle cases when `edge_attr` is None - and when it is a function itself. For MultiGraph and MultiDiGraph, G[u][v] - is a dictionary of all edges between u and v. In this case, the returned - function sums the value of `edge_attr` for every edge between u and v. - - Parameters - ---------- - G : graph - A NetworkX graph - - edge_attr : {None, str, callable} - Specification of how the value of the edge attribute should be obtained - from the edge attribute dictionary, G[u][v]. For multigraphs, G[u][v] - is a dictionary of all the edges between u and v. This allows for - special treatment of multiedges. - - Returns - ------- - value : function - A function expecting two nodes as parameters. The nodes should - represent the from- and to- node of an edge. The function will - return a value from G[u][v] that depends on `edge_attr`. - - """ - - if edge_attr is None: - # topological count of edges - - if G.is_multigraph(): - - def value(u, v): - return len(G[u][v]) - - else: - - def value(u, v): - return 1 - - elif not callable(edge_attr): - # assume it is a key for the edge attribute dictionary - - if edge_attr == "weight": - # provide a default value - if G.is_multigraph(): - - def value(u, v): - return sum(d.get(edge_attr, 1) for d in G[u][v].values()) - - else: - - def value(u, v): - return G[u][v].get(edge_attr, 1) - - else: - # otherwise, the edge attribute MUST exist for each edge - if G.is_multigraph(): - - def value(u, v): - return sum(d[edge_attr] for d in G[u][v].values()) - - else: - - def value(u, v): - return G[u][v][edge_attr] - - else: - # Advanced: Allow users to specify something else. - # - # Alternative default value: - # edge_attr = lambda u,v: G[u][v].get('thickness', .5) - # - # Function on an attribute: - # edge_attr = lambda u,v: abs(G[u][v]['weight']) - # - # Handle Multi(Di)Graphs differently: - # edge_attr = lambda u,v: numpy.prod([d['size'] for d in G[u][v].values()]) - # - # Ignore multiple edges - # edge_attr = lambda u,v: 1 if len(G[u][v]) else 0 - # - value = edge_attr - - return value - - -@nx._dispatchable(edge_attrs={"edge_attr": None}, node_attrs="node_attr") -def attr_matrix( - G, - edge_attr=None, - node_attr=None, - normalized=False, - rc_order=None, - dtype=None, - order=None, -): - """Returns the attribute matrix using attributes from `G` as a numpy array. - - If only `G` is passed in, then the adjacency matrix is constructed. - - Let A be a discrete set of values for the node attribute `node_attr`. Then - the elements of A represent the rows and columns of the constructed matrix. - Now, iterate through every edge e=(u,v) in `G` and consider the value - of the edge attribute `edge_attr`. If ua and va are the values of the - node attribute `node_attr` for u and v, respectively, then the value of - the edge attribute is added to the matrix element at (ua, va). - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the attribute matrix. - - edge_attr : str, optional - Each element of the matrix represents a running total of the - specified edge attribute for edges whose node attributes correspond - to the rows/cols of the matrix. The attribute must be present for - all edges in the graph. If no attribute is specified, then we - just count the number of edges whose node attributes correspond - to the matrix element. - - node_attr : str, optional - Each row and column in the matrix represents a particular value - of the node attribute. The attribute must be present for all nodes - in the graph. Note, the values of this attribute should be reliably - hashable. So, float values are not recommended. If no attribute is - specified, then the rows and columns will be the nodes of the graph. - - normalized : bool, optional - If True, then each row is normalized by the summation of its values. - - rc_order : list, optional - A list of the node attribute values. This list specifies the ordering - of rows and columns of the array. If no ordering is provided, then - the ordering will be random (and also, a return value). - - Other Parameters - ---------------- - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. Keep in mind certain - dtypes can yield unexpected results if the array is to be normalized. - The parameter is passed to numpy.zeros(). If unspecified, the NumPy - default is used. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. This parameter is passed to - numpy.zeros(). If unspecified, the NumPy default is used. - - Returns - ------- - M : 2D NumPy ndarray - The attribute matrix. - - ordering : list - If `rc_order` was specified, then only the attribute matrix is returned. - However, if `rc_order` was None, then the ordering used to construct - the matrix is returned as well. - - Examples - -------- - Construct an adjacency matrix: - - >>> G = nx.Graph() - >>> G.add_edge(0, 1, thickness=1, weight=3) - >>> G.add_edge(0, 2, thickness=2) - >>> G.add_edge(1, 2, thickness=3) - >>> nx.attr_matrix(G, rc_order=[0, 1, 2]) - array([[0., 1., 1.], - [1., 0., 1.], - [1., 1., 0.]]) - - Alternatively, we can obtain the matrix describing edge thickness. - - >>> nx.attr_matrix(G, edge_attr="thickness", rc_order=[0, 1, 2]) - array([[0., 1., 2.], - [1., 0., 3.], - [2., 3., 0.]]) - - We can also color the nodes and ask for the probability distribution over - all edges (u,v) describing: - - Pr(v has color Y | u has color X) - - >>> G.nodes[0]["color"] = "red" - >>> G.nodes[1]["color"] = "red" - >>> G.nodes[2]["color"] = "blue" - >>> rc = ["red", "blue"] - >>> nx.attr_matrix(G, node_attr="color", normalized=True, rc_order=rc) - array([[0.33333333, 0.66666667], - [1. , 0. ]]) - - For example, the above tells us that for all edges (u,v): - - Pr( v is red | u is red) = 1/3 - Pr( v is blue | u is red) = 2/3 - - Pr( v is red | u is blue) = 1 - Pr( v is blue | u is blue) = 0 - - Finally, we can obtain the total weights listed by the node colors. - - >>> nx.attr_matrix(G, edge_attr="weight", node_attr="color", rc_order=rc) - array([[3., 2.], - [2., 0.]]) - - Thus, the total weight over all edges (u,v) with u and v having colors: - - (red, red) is 3 # the sole contribution is from edge (0,1) - (red, blue) is 2 # contributions from edges (0,2) and (1,2) - (blue, red) is 2 # same as (red, blue) since graph is undirected - (blue, blue) is 0 # there are no edges with blue endpoints - - """ - import numpy as np - - edge_value = _edge_value(G, edge_attr) - node_value = _node_value(G, node_attr) - - if rc_order is None: - ordering = list({node_value(n) for n in G}) - else: - ordering = rc_order - - N = len(ordering) - undirected = not G.is_directed() - index = dict(zip(ordering, range(N))) - M = np.zeros((N, N), dtype=dtype, order=order) - - seen = set() - for u, nbrdict in G.adjacency(): - for v in nbrdict: - # Obtain the node attribute values. - i, j = index[node_value(u)], index[node_value(v)] - if v not in seen: - M[i, j] += edge_value(u, v) - if undirected: - M[j, i] = M[i, j] - - if undirected: - seen.add(u) - - if normalized: - M /= M.sum(axis=1).reshape((N, 1)) - - if rc_order is None: - return M, ordering - else: - return M - - -@nx._dispatchable(edge_attrs={"edge_attr": None}, node_attrs="node_attr") -def attr_sparse_matrix( - G, edge_attr=None, node_attr=None, normalized=False, rc_order=None, dtype=None -): - """Returns a SciPy sparse array using attributes from G. - - If only `G` is passed in, then the adjacency matrix is constructed. - - Let A be a discrete set of values for the node attribute `node_attr`. Then - the elements of A represent the rows and columns of the constructed matrix. - Now, iterate through every edge e=(u,v) in `G` and consider the value - of the edge attribute `edge_attr`. If ua and va are the values of the - node attribute `node_attr` for u and v, respectively, then the value of - the edge attribute is added to the matrix element at (ua, va). - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - edge_attr : str, optional - Each element of the matrix represents a running total of the - specified edge attribute for edges whose node attributes correspond - to the rows/cols of the matrix. The attribute must be present for - all edges in the graph. If no attribute is specified, then we - just count the number of edges whose node attributes correspond - to the matrix element. - - node_attr : str, optional - Each row and column in the matrix represents a particular value - of the node attribute. The attribute must be present for all nodes - in the graph. Note, the values of this attribute should be reliably - hashable. So, float values are not recommended. If no attribute is - specified, then the rows and columns will be the nodes of the graph. - - normalized : bool, optional - If True, then each row is normalized by the summation of its values. - - rc_order : list, optional - A list of the node attribute values. This list specifies the ordering - of rows and columns of the array. If no ordering is provided, then - the ordering will be random (and also, a return value). - - Other Parameters - ---------------- - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. Keep in mind certain - dtypes can yield unexpected results if the array is to be normalized. - The parameter is passed to numpy.zeros(). If unspecified, the NumPy - default is used. - - Returns - ------- - M : SciPy sparse array - The attribute matrix. - - ordering : list - If `rc_order` was specified, then only the matrix is returned. - However, if `rc_order` was None, then the ordering used to construct - the matrix is returned as well. - - Examples - -------- - Construct an adjacency matrix: - - >>> G = nx.Graph() - >>> G.add_edge(0, 1, thickness=1, weight=3) - >>> G.add_edge(0, 2, thickness=2) - >>> G.add_edge(1, 2, thickness=3) - >>> M = nx.attr_sparse_matrix(G, rc_order=[0, 1, 2]) - >>> M.toarray() - array([[0., 1., 1.], - [1., 0., 1.], - [1., 1., 0.]]) - - Alternatively, we can obtain the matrix describing edge thickness. - - >>> M = nx.attr_sparse_matrix(G, edge_attr="thickness", rc_order=[0, 1, 2]) - >>> M.toarray() - array([[0., 1., 2.], - [1., 0., 3.], - [2., 3., 0.]]) - - We can also color the nodes and ask for the probability distribution over - all edges (u,v) describing: - - Pr(v has color Y | u has color X) - - >>> G.nodes[0]["color"] = "red" - >>> G.nodes[1]["color"] = "red" - >>> G.nodes[2]["color"] = "blue" - >>> rc = ["red", "blue"] - >>> M = nx.attr_sparse_matrix(G, node_attr="color", normalized=True, rc_order=rc) - >>> M.toarray() - array([[0.33333333, 0.66666667], - [1. , 0. ]]) - - For example, the above tells us that for all edges (u,v): - - Pr( v is red | u is red) = 1/3 - Pr( v is blue | u is red) = 2/3 - - Pr( v is red | u is blue) = 1 - Pr( v is blue | u is blue) = 0 - - Finally, we can obtain the total weights listed by the node colors. - - >>> M = nx.attr_sparse_matrix(G, edge_attr="weight", node_attr="color", rc_order=rc) - >>> M.toarray() - array([[3., 2.], - [2., 0.]]) - - Thus, the total weight over all edges (u,v) with u and v having colors: - - (red, red) is 3 # the sole contribution is from edge (0,1) - (red, blue) is 2 # contributions from edges (0,2) and (1,2) - (blue, red) is 2 # same as (red, blue) since graph is undirected - (blue, blue) is 0 # there are no edges with blue endpoints - - """ - import numpy as np - import scipy as sp - - edge_value = _edge_value(G, edge_attr) - node_value = _node_value(G, node_attr) - - if rc_order is None: - ordering = list({node_value(n) for n in G}) - else: - ordering = rc_order - - N = len(ordering) - undirected = not G.is_directed() - index = dict(zip(ordering, range(N))) - M = sp.sparse.lil_array((N, N), dtype=dtype) - - seen = set() - for u, nbrdict in G.adjacency(): - for v in nbrdict: - # Obtain the node attribute values. - i, j = index[node_value(u)], index[node_value(v)] - if v not in seen: - M[i, j] += edge_value(u, v) - if undirected: - M[j, i] = M[i, j] - - if undirected: - seen.add(u) - - if normalized: - M *= 1 / M.sum(axis=1)[:, np.newaxis] # in-place mult preserves sparse - - if rc_order is None: - return M, ordering - else: - return M diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/bethehessianmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/bethehessianmatrix.py deleted file mode 100644 index 3d42fc6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/bethehessianmatrix.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Bethe Hessian or deformed Laplacian matrix of graphs.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["bethe_hessian_matrix"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable -def bethe_hessian_matrix(G, r=None, nodelist=None): - r"""Returns the Bethe Hessian matrix of G. - - The Bethe Hessian is a family of matrices parametrized by r, defined as - H(r) = (r^2 - 1) I - r A + D where A is the adjacency matrix, D is the - diagonal matrix of node degrees, and I is the identify matrix. It is equal - to the graph laplacian when the regularizer r = 1. - - The default choice of regularizer should be the ratio [2]_ - - .. math:: - r_m = \left(\sum k_i \right)^{-1}\left(\sum k_i^2 \right) - 1 - - Parameters - ---------- - G : Graph - A NetworkX graph - r : float - Regularizer parameter - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by ``G.nodes()``. - - Returns - ------- - H : scipy.sparse.csr_array - The Bethe Hessian matrix of `G`, with parameter `r`. - - Examples - -------- - >>> k = [3, 2, 2, 1, 0] - >>> G = nx.havel_hakimi_graph(k) - >>> H = nx.bethe_hessian_matrix(G) - >>> H.toarray() - array([[ 3.5625, -1.25 , -1.25 , -1.25 , 0. ], - [-1.25 , 2.5625, -1.25 , 0. , 0. ], - [-1.25 , -1.25 , 2.5625, 0. , 0. ], - [-1.25 , 0. , 0. , 1.5625, 0. ], - [ 0. , 0. , 0. , 0. , 0.5625]]) - - See Also - -------- - bethe_hessian_spectrum - adjacency_matrix - laplacian_matrix - - References - ---------- - .. [1] A. Saade, F. Krzakala and L. Zdeborová - "Spectral Clustering of Graphs with the Bethe Hessian", - Advances in Neural Information Processing Systems, 2014. - .. [2] C. M. Le, E. Levina - "Estimating the number of communities in networks by spectral methods" - arXiv:1507.00827, 2015. - """ - import scipy as sp - - if nodelist is None: - nodelist = list(G) - if r is None: - r = sum(d**2 for v, d in nx.degree(G)) / sum(d for v, d in nx.degree(G)) - 1 - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, format="csr") - n, m = A.shape - # TODO: Rm csr_array wrapper when spdiags array creation becomes available - D = sp.sparse.csr_array(sp.sparse.spdiags(A.sum(axis=1), 0, m, n, format="csr")) - # TODO: Rm csr_array wrapper when eye array creation becomes available - I = sp.sparse.csr_array(sp.sparse.eye(m, n, format="csr")) - return (r**2 - 1) * I - r * A + D diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/graphmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/graphmatrix.py deleted file mode 100644 index 9f477bc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/graphmatrix.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -Adjacency matrix and incidence matrix of graphs. -""" - -import networkx as nx - -__all__ = ["incidence_matrix", "adjacency_matrix"] - - -@nx._dispatchable(edge_attrs="weight") -def incidence_matrix( - G, nodelist=None, edgelist=None, oriented=False, weight=None, *, dtype=None -): - """Returns incidence matrix of G. - - The incidence matrix assigns each row to a node and each column to an edge. - For a standard incidence matrix a 1 appears wherever a row's node is - incident on the column's edge. For an oriented incidence matrix each - edge is assigned an orientation (arbitrarily for undirected and aligning to - direction for directed). A -1 appears for the source (tail) of an edge and - 1 for the destination (head) of the edge. The elements are zero otherwise. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional (default= all nodes in G) - The rows are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - edgelist : list, optional (default= all edges in G) - The columns are ordered according to the edges in edgelist. - If edgelist is None, then the ordering is produced by G.edges(). - - oriented: bool, optional (default=False) - If True, matrix elements are +1 or -1 for the head or tail node - respectively of each edge. If False, +1 occurs at both nodes. - - weight : string or None, optional (default=None) - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. Edge weights, if used, - should be positive so that the orientation can provide the sign. - - dtype : a NumPy dtype or None (default=None) - The dtype of the output sparse array. This type should be a compatible - type of the weight argument, eg. if weight would return a float this - argument should also be a float. - If None, then the default for SciPy is used. - - Returns - ------- - A : SciPy sparse array - The incidence matrix of G. - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges in edgelist should be - (u,v,key) 3-tuples. - - "Networks are the best discrete model for so many problems in - applied mathematics" [1]_. - - References - ---------- - .. [1] Gil Strang, Network applications: A = incidence matrix, - http://videolectures.net/mit18085f07_strang_lec03/ - """ - import scipy as sp - - if nodelist is None: - nodelist = list(G) - if edgelist is None: - if G.is_multigraph(): - edgelist = list(G.edges(keys=True)) - else: - edgelist = list(G.edges()) - A = sp.sparse.lil_array((len(nodelist), len(edgelist)), dtype=dtype) - node_index = {node: i for i, node in enumerate(nodelist)} - for ei, e in enumerate(edgelist): - (u, v) = e[:2] - if u == v: - continue # self loops give zero column - try: - ui = node_index[u] - vi = node_index[v] - except KeyError as err: - raise nx.NetworkXError( - f"node {u} or {v} in edgelist but not in nodelist" - ) from err - if weight is None: - wt = 1 - else: - if G.is_multigraph(): - ekey = e[2] - wt = G[u][v][ekey].get(weight, 1) - else: - wt = G[u][v].get(weight, 1) - if oriented: - A[ui, ei] = -wt - A[vi, ei] = wt - else: - A[ui, ei] = wt - A[vi, ei] = wt - return A.asformat("csc") - - -@nx._dispatchable(edge_attrs="weight") -def adjacency_matrix(G, nodelist=None, dtype=None, weight="weight"): - """Returns adjacency matrix of `G`. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If ``nodelist=None`` (the default), then the ordering is produced by - ``G.nodes()``. - - dtype : NumPy data-type, optional - The desired data-type for the array. - If `None`, then the NumPy default is used. - - weight : string or None, optional (default='weight') - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - A : SciPy sparse array - Adjacency matrix representation of G. - - Notes - ----- - For directed graphs, entry ``i, j`` corresponds to an edge from ``i`` to ``j``. - - If you want a pure Python adjacency matrix representation try - :func:`~networkx.convert.to_dict_of_dicts` which will return a - dictionary-of-dictionaries format that can be addressed as a - sparse matrix. - - For multigraphs with parallel edges the weights are summed. - See :func:`networkx.convert_matrix.to_numpy_array` for other options. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the edge weight attribute - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting SciPy sparse array can be modified as follows:: - - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.adjacency_matrix(G) - >>> A.toarray() - array([[1]]) - >>> A.setdiag(A.diagonal() * 2) - >>> A.toarray() - array([[2]]) - - See Also - -------- - to_numpy_array - to_scipy_sparse_array - to_dict_of_dicts - adjacency_spectrum - """ - return nx.to_scipy_sparse_array(G, nodelist=nodelist, dtype=dtype, weight=weight) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/laplacianmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/laplacianmatrix.py deleted file mode 100644 index d49ae49..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/laplacianmatrix.py +++ /dev/null @@ -1,617 +0,0 @@ -"""Laplacian matrix of graphs. - -All calculations here are done using the out-degree. For Laplacians using -in-degree, use `G.reverse(copy=False)` instead of `G` and take the transpose. - -The `laplacian_matrix` function provides an unnormalized matrix, -while `normalized_laplacian_matrix`, `directed_laplacian_matrix`, -and `directed_combinatorial_laplacian_matrix` are all normalized. -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = [ - "laplacian_matrix", - "normalized_laplacian_matrix", - "total_spanning_tree_weight", - "directed_laplacian_matrix", - "directed_combinatorial_laplacian_matrix", -] - - -@nx._dispatchable(edge_attrs="weight") -def laplacian_matrix(G, nodelist=None, weight="weight"): - """Returns the Laplacian matrix of G. - - The graph Laplacian is the matrix L = D - A, where - A is the adjacency matrix and D is the diagonal matrix of node degrees. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - L : SciPy sparse array - The Laplacian matrix of G. - - Notes - ----- - For MultiGraph, the edges weights are summed. - - This returns an unnormalized matrix. For a normalized output, - use `normalized_laplacian_matrix`, `directed_laplacian_matrix`, - or `directed_combinatorial_laplacian_matrix`. - - This calculation uses the out-degree of the graph `G`. To use the - in-degree for calculations instead, use `G.reverse(copy=False)` and - take the transpose. - - See Also - -------- - :func:`~networkx.convert_matrix.to_numpy_array` - normalized_laplacian_matrix - directed_laplacian_matrix - directed_combinatorial_laplacian_matrix - :func:`~networkx.linalg.spectrum.laplacian_spectrum` - - Examples - -------- - For graphs with multiple connected components, L is permutation-similar - to a block diagonal matrix where each block is the respective Laplacian - matrix for each component. - - >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)]) - >>> print(nx.laplacian_matrix(G).toarray()) - [[ 1 -1 0 0 0] - [-1 2 -1 0 0] - [ 0 -1 1 0 0] - [ 0 0 0 1 -1] - [ 0 0 0 -1 1]] - - >>> edges = [ - ... (1, 2), - ... (2, 1), - ... (2, 4), - ... (4, 3), - ... (3, 4), - ... ] - >>> DiG = nx.DiGraph(edges) - >>> print(nx.laplacian_matrix(DiG).toarray()) - [[ 1 -1 0 0] - [-1 2 -1 0] - [ 0 0 1 -1] - [ 0 0 -1 1]] - - Notice that node 4 is represented by the third column and row. This is because - by default the row/column order is the order of `G.nodes` (i.e. the node added - order -- in the edgelist, 4 first appears in (2, 4), before node 3 in edge (4, 3).) - To control the node order of the matrix, use the `nodelist` argument. - - >>> print(nx.laplacian_matrix(DiG, nodelist=[1, 2, 3, 4]).toarray()) - [[ 1 -1 0 0] - [-1 2 0 -1] - [ 0 0 1 -1] - [ 0 0 -1 1]] - - This calculation uses the out-degree of the graph `G`. To use the - in-degree for calculations instead, use `G.reverse(copy=False)` and - take the transpose. - - >>> print(nx.laplacian_matrix(DiG.reverse(copy=False)).toarray().T) - [[ 1 -1 0 0] - [-1 1 -1 0] - [ 0 0 2 -1] - [ 0 0 -1 1]] - - References - ---------- - .. [1] Langville, Amy N., and Carl D. Meyer. Google’s PageRank and Beyond: - The Science of Search Engine Rankings. Princeton University Press, 2006. - - """ - import scipy as sp - - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, format="csr") - n, m = A.shape - # TODO: rm csr_array wrapper when spdiags can produce arrays - D = sp.sparse.csr_array(sp.sparse.spdiags(A.sum(axis=1), 0, m, n, format="csr")) - return D - A - - -@nx._dispatchable(edge_attrs="weight") -def normalized_laplacian_matrix(G, nodelist=None, weight="weight"): - r"""Returns the normalized Laplacian matrix of G. - - The normalized graph Laplacian is the matrix - - .. math:: - - N = D^{-1/2} L D^{-1/2} - - where `L` is the graph Laplacian and `D` is the diagonal matrix of - node degrees [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - N : SciPy sparse array - The normalized Laplacian matrix of G. - - Notes - ----- - For MultiGraph, the edges weights are summed. - See :func:`to_numpy_array` for other options. - - If the Graph contains selfloops, D is defined as ``diag(sum(A, 1))``, where A is - the adjacency matrix [2]_. - - This calculation uses the out-degree of the graph `G`. To use the - in-degree for calculations instead, use `G.reverse(copy=False)` and - take the transpose. - - For an unnormalized output, use `laplacian_matrix`. - - Examples - -------- - - >>> import numpy as np - >>> edges = [ - ... (1, 2), - ... (2, 1), - ... (2, 4), - ... (4, 3), - ... (3, 4), - ... ] - >>> DiG = nx.DiGraph(edges) - >>> print(nx.normalized_laplacian_matrix(DiG).toarray()) - [[ 1. -0.70710678 0. 0. ] - [-0.70710678 1. -0.70710678 0. ] - [ 0. 0. 1. -1. ] - [ 0. 0. -1. 1. ]] - - Notice that node 4 is represented by the third column and row. This is because - by default the row/column order is the order of `G.nodes` (i.e. the node added - order -- in the edgelist, 4 first appears in (2, 4), before node 3 in edge (4, 3).) - To control the node order of the matrix, use the `nodelist` argument. - - >>> print(nx.normalized_laplacian_matrix(DiG, nodelist=[1, 2, 3, 4]).toarray()) - [[ 1. -0.70710678 0. 0. ] - [-0.70710678 1. 0. -0.70710678] - [ 0. 0. 1. -1. ] - [ 0. 0. -1. 1. ]] - >>> G = nx.Graph(edges) - >>> print(nx.normalized_laplacian_matrix(G).toarray()) - [[ 1. -0.70710678 0. 0. ] - [-0.70710678 1. -0.5 0. ] - [ 0. -0.5 1. -0.70710678] - [ 0. 0. -0.70710678 1. ]] - - See Also - -------- - laplacian_matrix - normalized_laplacian_spectrum - directed_laplacian_matrix - directed_combinatorial_laplacian_matrix - - References - ---------- - .. [1] Fan Chung-Graham, Spectral Graph Theory, - CBMS Regional Conference Series in Mathematics, Number 92, 1997. - .. [2] Steve Butler, Interlacing For Weighted Graphs Using The Normalized - Laplacian, Electronic Journal of Linear Algebra, Volume 16, pp. 90-98, - March 2007. - .. [3] Langville, Amy N., and Carl D. Meyer. Google’s PageRank and Beyond: - The Science of Search Engine Rankings. Princeton University Press, 2006. - """ - import numpy as np - import scipy as sp - - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, format="csr") - n, _ = A.shape - diags = A.sum(axis=1) - # TODO: rm csr_array wrapper when spdiags can produce arrays - D = sp.sparse.csr_array(sp.sparse.spdiags(diags, 0, n, n, format="csr")) - L = D - A - with np.errstate(divide="ignore"): - diags_sqrt = 1.0 / np.sqrt(diags) - diags_sqrt[np.isinf(diags_sqrt)] = 0 - # TODO: rm csr_array wrapper when spdiags can produce arrays - DH = sp.sparse.csr_array(sp.sparse.spdiags(diags_sqrt, 0, n, n, format="csr")) - return DH @ (L @ DH) - - -@nx._dispatchable(edge_attrs="weight") -def total_spanning_tree_weight(G, weight=None, root=None): - """ - Returns the total weight of all spanning trees of `G`. - - Kirchoff's Tree Matrix Theorem [1]_, [2]_ states that the determinant of any - cofactor of the Laplacian matrix of a graph is the number of spanning trees - in the graph. For a weighted Laplacian matrix, it is the sum across all - spanning trees of the multiplicative weight of each tree. That is, the - weight of each tree is the product of its edge weights. - - For unweighted graphs, the total weight equals the number of spanning trees in `G`. - - For directed graphs, the total weight follows by summing over all directed - spanning trees in `G` that start in the `root` node [3]_. - - .. deprecated:: 3.3 - - ``total_spanning_tree_weight`` is deprecated and will be removed in v3.5. - Use ``nx.number_of_spanning_trees(G)`` instead. - - Parameters - ---------- - G : NetworkX Graph - - weight : string or None, optional (default=None) - The key for the edge attribute holding the edge weight. - If None, then each edge has weight 1. - - root : node (only required for directed graphs) - A node in the directed graph `G`. - - Returns - ------- - total_weight : float - Undirected graphs: - The sum of the total multiplicative weights for all spanning trees in `G`. - Directed graphs: - The sum of the total multiplicative weights for all spanning trees of `G`, - rooted at node `root`. - - Raises - ------ - NetworkXPointlessConcept - If `G` does not contain any nodes. - - NetworkXError - If the graph `G` is not (weakly) connected, - or if `G` is directed and the root node is not specified or not in G. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> round(nx.total_spanning_tree_weight(G)) - 125 - - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=2) - >>> G.add_edge(1, 3, weight=1) - >>> G.add_edge(2, 3, weight=1) - >>> round(nx.total_spanning_tree_weight(G, "weight")) - 5 - - Notes - ----- - Self-loops are excluded. Multi-edges are contracted in one edge - equal to the sum of the weights. - - References - ---------- - .. [1] Wikipedia - "Kirchhoff's theorem." - https://en.wikipedia.org/wiki/Kirchhoff%27s_theorem - .. [2] Kirchhoff, G. R. - Über die Auflösung der Gleichungen, auf welche man - bei der Untersuchung der linearen Vertheilung - Galvanischer Ströme geführt wird - Annalen der Physik und Chemie, vol. 72, pp. 497-508, 1847. - .. [3] Margoliash, J. - "Matrix-Tree Theorem for Directed Graphs" - https://www.math.uchicago.edu/~may/VIGRE/VIGRE2010/REUPapers/Margoliash.pdf - """ - import warnings - - warnings.warn( - ( - "\n\ntotal_spanning_tree_weight is deprecated and will be removed in v3.5.\n" - "Use `nx.number_of_spanning_trees(G)` instead." - ), - category=DeprecationWarning, - stacklevel=3, - ) - - return nx.number_of_spanning_trees(G, weight=weight, root=root) - - -############################################################################### -# Code based on work from https://github.com/bjedwards - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def directed_laplacian_matrix( - G, nodelist=None, weight="weight", walk_type=None, alpha=0.95 -): - r"""Returns the directed Laplacian matrix of G. - - The graph directed Laplacian is the matrix - - .. math:: - - L = I - \frac{1}{2} \left (\Phi^{1/2} P \Phi^{-1/2} + \Phi^{-1/2} P^T \Phi^{1/2} \right ) - - where `I` is the identity matrix, `P` is the transition matrix of the - graph, and `\Phi` a matrix with the Perron vector of `P` in the diagonal and - zeros elsewhere [1]_. - - Depending on the value of walk_type, `P` can be the transition matrix - induced by a random walk, a lazy random walk, or a random walk with - teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - One of ``"random"``, ``"lazy"``, or ``"pagerank"``. If ``walk_type=None`` - (the default), then a value is selected according to the properties of `G`: - - ``walk_type="random"`` if `G` is strongly connected and aperiodic - - ``walk_type="lazy"`` if `G` is strongly connected but not aperiodic - - ``walk_type="pagerank"`` for all other cases. - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - L : NumPy matrix - Normalized Laplacian of G. - - Notes - ----- - Only implemented for DiGraphs - - The result is always a symmetric matrix. - - This calculation uses the out-degree of the graph `G`. To use the - in-degree for calculations instead, use `G.reverse(copy=False)` and - take the transpose. - - See Also - -------- - laplacian_matrix - normalized_laplacian_matrix - directed_combinatorial_laplacian_matrix - - References - ---------- - .. [1] Fan Chung (2005). - Laplacians and the Cheeger inequality for directed graphs. - Annals of Combinatorics, 9(1), 2005 - """ - import numpy as np - import scipy as sp - - # NOTE: P has type ndarray if walk_type=="pagerank", else csr_array - P = _transition_matrix( - G, nodelist=nodelist, weight=weight, walk_type=walk_type, alpha=alpha - ) - - n, m = P.shape - - evals, evecs = sp.sparse.linalg.eigs(P.T, k=1) - v = evecs.flatten().real - p = v / v.sum() - # p>=0 by Perron-Frobenius Thm. Use abs() to fix roundoff across zero gh-6865 - sqrtp = np.sqrt(np.abs(p)) - Q = ( - # TODO: rm csr_array wrapper when spdiags creates arrays - sp.sparse.csr_array(sp.sparse.spdiags(sqrtp, 0, n, n)) - @ P - # TODO: rm csr_array wrapper when spdiags creates arrays - @ sp.sparse.csr_array(sp.sparse.spdiags(1.0 / sqrtp, 0, n, n)) - ) - # NOTE: This could be sparsified for the non-pagerank cases - I = np.identity(len(G)) - - return I - (Q + Q.T) / 2.0 - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def directed_combinatorial_laplacian_matrix( - G, nodelist=None, weight="weight", walk_type=None, alpha=0.95 -): - r"""Return the directed combinatorial Laplacian matrix of G. - - The graph directed combinatorial Laplacian is the matrix - - .. math:: - - L = \Phi - \frac{1}{2} \left (\Phi P + P^T \Phi \right) - - where `P` is the transition matrix of the graph and `\Phi` a matrix - with the Perron vector of `P` in the diagonal and zeros elsewhere [1]_. - - Depending on the value of walk_type, `P` can be the transition matrix - induced by a random walk, a lazy random walk, or a random walk with - teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - One of ``"random"``, ``"lazy"``, or ``"pagerank"``. If ``walk_type=None`` - (the default), then a value is selected according to the properties of `G`: - - ``walk_type="random"`` if `G` is strongly connected and aperiodic - - ``walk_type="lazy"`` if `G` is strongly connected but not aperiodic - - ``walk_type="pagerank"`` for all other cases. - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - L : NumPy matrix - Combinatorial Laplacian of G. - - Notes - ----- - Only implemented for DiGraphs - - The result is always a symmetric matrix. - - This calculation uses the out-degree of the graph `G`. To use the - in-degree for calculations instead, use `G.reverse(copy=False)` and - take the transpose. - - See Also - -------- - laplacian_matrix - normalized_laplacian_matrix - directed_laplacian_matrix - - References - ---------- - .. [1] Fan Chung (2005). - Laplacians and the Cheeger inequality for directed graphs. - Annals of Combinatorics, 9(1), 2005 - """ - import scipy as sp - - P = _transition_matrix( - G, nodelist=nodelist, weight=weight, walk_type=walk_type, alpha=alpha - ) - - n, m = P.shape - - evals, evecs = sp.sparse.linalg.eigs(P.T, k=1) - v = evecs.flatten().real - p = v / v.sum() - # NOTE: could be improved by not densifying - # TODO: Rm csr_array wrapper when spdiags array creation becomes available - Phi = sp.sparse.csr_array(sp.sparse.spdiags(p, 0, n, n)).toarray() - - return Phi - (Phi @ P + P.T @ Phi) / 2.0 - - -def _transition_matrix(G, nodelist=None, weight="weight", walk_type=None, alpha=0.95): - """Returns the transition matrix of G. - - This is a row stochastic giving the transition probabilities while - performing a random walk on the graph. Depending on the value of walk_type, - P can be the transition matrix induced by a random walk, a lazy random walk, - or a random walk with teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - One of ``"random"``, ``"lazy"``, or ``"pagerank"``. If ``walk_type=None`` - (the default), then a value is selected according to the properties of `G`: - - ``walk_type="random"`` if `G` is strongly connected and aperiodic - - ``walk_type="lazy"`` if `G` is strongly connected but not aperiodic - - ``walk_type="pagerank"`` for all other cases. - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - P : numpy.ndarray - transition matrix of G. - - Raises - ------ - NetworkXError - If walk_type not specified or alpha not in valid range - """ - import numpy as np - import scipy as sp - - if walk_type is None: - if nx.is_strongly_connected(G): - if nx.is_aperiodic(G): - walk_type = "random" - else: - walk_type = "lazy" - else: - walk_type = "pagerank" - - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, dtype=float) - n, m = A.shape - if walk_type in ["random", "lazy"]: - # TODO: Rm csr_array wrapper when spdiags array creation becomes available - DI = sp.sparse.csr_array(sp.sparse.spdiags(1.0 / A.sum(axis=1), 0, n, n)) - if walk_type == "random": - P = DI @ A - else: - # TODO: Rm csr_array wrapper when identity array creation becomes available - I = sp.sparse.csr_array(sp.sparse.identity(n)) - P = (I + DI @ A) / 2.0 - - elif walk_type == "pagerank": - if not (0 < alpha < 1): - raise nx.NetworkXError("alpha must be between 0 and 1") - # this is using a dense representation. NOTE: This should be sparsified! - A = A.toarray() - # add constant to dangling nodes' row - A[A.sum(axis=1) == 0, :] = 1 / n - # normalize - A = A / A.sum(axis=1)[np.newaxis, :].T - P = alpha * A + (1 - alpha) / n - else: - raise nx.NetworkXError("walk_type must be random, lazy, or pagerank") - - return P diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/modularitymatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/modularitymatrix.py deleted file mode 100644 index 0287910..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/modularitymatrix.py +++ /dev/null @@ -1,166 +0,0 @@ -"""Modularity matrix of graphs.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["modularity_matrix", "directed_modularity_matrix"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def modularity_matrix(G, nodelist=None, weight=None): - r"""Returns the modularity matrix of G. - - The modularity matrix is the matrix B = A - , where A is the adjacency - matrix and is the average adjacency matrix, assuming that the graph - is described by the configuration model. - - More specifically, the element B_ij of B is defined as - - .. math:: - A_{ij} - {k_i k_j \over 2 m} - - where k_i is the degree of node i, and where m is the number of edges - in the graph. When weight is set to a name of an attribute edge, Aij, k_i, - k_j and m are computed using its value. - - Parameters - ---------- - G : Graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - Returns - ------- - B : Numpy array - The modularity matrix of G. - - Examples - -------- - >>> k = [3, 2, 2, 1, 0] - >>> G = nx.havel_hakimi_graph(k) - >>> B = nx.modularity_matrix(G) - - - See Also - -------- - to_numpy_array - modularity_spectrum - adjacency_matrix - directed_modularity_matrix - - References - ---------- - .. [1] M. E. J. Newman, "Modularity and community structure in networks", - Proc. Natl. Acad. Sci. USA, vol. 103, pp. 8577-8582, 2006. - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, format="csr") - k = A.sum(axis=1) - m = k.sum() * 0.5 - # Expected adjacency matrix - X = np.outer(k, k) / (2 * m) - - return A - X - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -@nx._dispatchable(edge_attrs="weight") -def directed_modularity_matrix(G, nodelist=None, weight=None): - """Returns the directed modularity matrix of G. - - The modularity matrix is the matrix B = A - , where A is the adjacency - matrix and is the expected adjacency matrix, assuming that the graph - is described by the configuration model. - - More specifically, the element B_ij of B is defined as - - .. math:: - B_{ij} = A_{ij} - k_i^{out} k_j^{in} / m - - where :math:`k_i^{in}` is the in degree of node i, and :math:`k_j^{out}` is the out degree - of node j, with m the number of edges in the graph. When weight is set - to a name of an attribute edge, Aij, k_i, k_j and m are computed using - its value. - - Parameters - ---------- - G : DiGraph - A NetworkX DiGraph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - Returns - ------- - B : Numpy array - The modularity matrix of G. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edges_from( - ... ( - ... (1, 2), - ... (1, 3), - ... (3, 1), - ... (3, 2), - ... (3, 5), - ... (4, 5), - ... (4, 6), - ... (5, 4), - ... (5, 6), - ... (6, 4), - ... ) - ... ) - >>> B = nx.directed_modularity_matrix(G) - - - Notes - ----- - NetworkX defines the element A_ij of the adjacency matrix as 1 if there - is a link going from node i to node j. Leicht and Newman use the opposite - definition. This explains the different expression for B_ij. - - See Also - -------- - to_numpy_array - modularity_spectrum - adjacency_matrix - modularity_matrix - - References - ---------- - .. [1] E. A. Leicht, M. E. J. Newman, - "Community structure in directed networks", - Phys. Rev Lett., vol. 100, no. 11, p. 118703, 2008. - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, format="csr") - k_in = A.sum(axis=0) - k_out = A.sum(axis=1) - m = k_in.sum() - # Expected adjacency matrix - X = np.outer(k_out, k_in) / m - - return A - X diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/spectrum.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/spectrum.py deleted file mode 100644 index 079b185..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/spectrum.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -Eigenvalue spectrum of graphs. -""" - -import networkx as nx - -__all__ = [ - "laplacian_spectrum", - "adjacency_spectrum", - "modularity_spectrum", - "normalized_laplacian_spectrum", - "bethe_hessian_spectrum", -] - - -@nx._dispatchable(edge_attrs="weight") -def laplacian_spectrum(G, weight="weight"): - """Returns eigenvalues of the Laplacian of G - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See :func:`~networkx.convert_matrix.to_numpy_array` for other options. - - See Also - -------- - laplacian_matrix - - Examples - -------- - The multiplicity of 0 as an eigenvalue of the laplacian matrix is equal - to the number of connected components of G. - - >>> G = nx.Graph() # Create a graph with 5 nodes and 3 connected components - >>> G.add_nodes_from(range(5)) - >>> G.add_edges_from([(0, 2), (3, 4)]) - >>> nx.laplacian_spectrum(G) - array([0., 0., 0., 2., 2.]) - - """ - import scipy as sp - - return sp.linalg.eigvalsh(nx.laplacian_matrix(G, weight=weight).todense()) - - -@nx._dispatchable(edge_attrs="weight") -def normalized_laplacian_spectrum(G, weight="weight"): - """Return eigenvalues of the normalized Laplacian of G - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_array for other options. - - See Also - -------- - normalized_laplacian_matrix - """ - import scipy as sp - - return sp.linalg.eigvalsh( - nx.normalized_laplacian_matrix(G, weight=weight).todense() - ) - - -@nx._dispatchable(edge_attrs="weight") -def adjacency_spectrum(G, weight="weight"): - """Returns eigenvalues of the adjacency matrix of G. - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_array for other options. - - See Also - -------- - adjacency_matrix - """ - import scipy as sp - - return sp.linalg.eigvals(nx.adjacency_matrix(G, weight=weight).todense()) - - -@nx._dispatchable -def modularity_spectrum(G): - """Returns eigenvalues of the modularity matrix of G. - - Parameters - ---------- - G : Graph - A NetworkX Graph or DiGraph - - Returns - ------- - evals : NumPy array - Eigenvalues - - See Also - -------- - modularity_matrix - - References - ---------- - .. [1] M. E. J. Newman, "Modularity and community structure in networks", - Proc. Natl. Acad. Sci. USA, vol. 103, pp. 8577-8582, 2006. - """ - import scipy as sp - - if G.is_directed(): - return sp.linalg.eigvals(nx.directed_modularity_matrix(G)) - else: - return sp.linalg.eigvals(nx.modularity_matrix(G)) - - -@nx._dispatchable -def bethe_hessian_spectrum(G, r=None): - """Returns eigenvalues of the Bethe Hessian matrix of G. - - Parameters - ---------- - G : Graph - A NetworkX Graph or DiGraph - - r : float - Regularizer parameter - - Returns - ------- - evals : NumPy array - Eigenvalues - - See Also - -------- - bethe_hessian_matrix - - References - ---------- - .. [1] A. Saade, F. Krzakala and L. Zdeborová - "Spectral clustering of graphs with the bethe hessian", - Advances in Neural Information Processing Systems. 2014. - """ - import scipy as sp - - return sp.linalg.eigvalsh(nx.bethe_hessian_matrix(G, r).todense()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py deleted file mode 100644 index 089d917..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py +++ /dev/null @@ -1,402 +0,0 @@ -from math import sqrt - -import pytest - -np = pytest.importorskip("numpy") - - -import networkx as nx - -methods = ("tracemin_pcg", "tracemin_lu", "lanczos", "lobpcg") - - -def test_algebraic_connectivity_tracemin_chol(): - """Test that "tracemin_chol" raises an exception.""" - pytest.importorskip("scipy") - G = nx.barbell_graph(5, 4) - with pytest.raises(nx.NetworkXError): - nx.algebraic_connectivity(G, method="tracemin_chol") - - -def test_fiedler_vector_tracemin_chol(): - """Test that "tracemin_chol" raises an exception.""" - pytest.importorskip("scipy") - G = nx.barbell_graph(5, 4) - with pytest.raises(nx.NetworkXError): - nx.fiedler_vector(G, method="tracemin_chol") - - -def test_spectral_ordering_tracemin_chol(): - """Test that "tracemin_chol" raises an exception.""" - pytest.importorskip("scipy") - G = nx.barbell_graph(5, 4) - with pytest.raises(nx.NetworkXError): - nx.spectral_ordering(G, method="tracemin_chol") - - -def test_fiedler_vector_tracemin_unknown(): - """Test that "tracemin_unknown" raises an exception.""" - pytest.importorskip("scipy") - G = nx.barbell_graph(5, 4) - L = nx.laplacian_matrix(G) - X = np.asarray(np.random.normal(size=(1, L.shape[0]))).T - with pytest.raises(nx.NetworkXError, match="Unknown linear system solver"): - nx.linalg.algebraicconnectivity._tracemin_fiedler( - L, X, normalized=False, tol=1e-8, method="tracemin_unknown" - ) - - -def test_spectral_bisection(): - pytest.importorskip("scipy") - G = nx.barbell_graph(3, 0) - C = nx.spectral_bisection(G) - assert C == ({0, 1, 2}, {3, 4, 5}) - - mapping = dict(enumerate("badfec")) - G = nx.relabel_nodes(G, mapping) - C = nx.spectral_bisection(G) - assert C == ( - {mapping[0], mapping[1], mapping[2]}, - {mapping[3], mapping[4], mapping[5]}, - ) - - -def check_eigenvector(A, l, x): - nx = np.linalg.norm(x) - # Check zeroness. - assert nx != pytest.approx(0, abs=1e-07) - y = A @ x - ny = np.linalg.norm(y) - # Check collinearity. - assert x @ y == pytest.approx(nx * ny, abs=1e-7) - # Check eigenvalue. - assert ny == pytest.approx(l * nx, abs=1e-7) - - -class TestAlgebraicConnectivity: - @pytest.mark.parametrize("method", methods) - def test_directed(self, method): - G = nx.DiGraph() - pytest.raises( - nx.NetworkXNotImplemented, nx.algebraic_connectivity, G, method=method - ) - pytest.raises(nx.NetworkXNotImplemented, nx.fiedler_vector, G, method=method) - - @pytest.mark.parametrize("method", methods) - def test_null_and_singleton(self, method): - G = nx.Graph() - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method=method) - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method) - G.add_edge(0, 0) - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method=method) - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method) - - @pytest.mark.parametrize("method", methods) - def test_disconnected(self, method): - G = nx.Graph() - G.add_nodes_from(range(2)) - assert nx.algebraic_connectivity(G) == 0 - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method) - G.add_edge(0, 1, weight=0) - assert nx.algebraic_connectivity(G) == 0 - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method) - - def test_unrecognized_method(self): - pytest.importorskip("scipy") - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method="unknown") - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method="unknown") - - @pytest.mark.parametrize("method", methods) - def test_two_nodes(self, method): - pytest.importorskip("scipy") - G = nx.Graph() - G.add_edge(0, 1, weight=1) - A = nx.laplacian_matrix(G) - assert nx.algebraic_connectivity(G, tol=1e-12, method=method) == pytest.approx( - 2, abs=1e-7 - ) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, 2, x) - - @pytest.mark.parametrize("method", methods) - def test_two_nodes_multigraph(self, method): - pytest.importorskip("scipy") - G = nx.MultiGraph() - G.add_edge(0, 0, spam=1e8) - G.add_edge(0, 1, spam=1) - G.add_edge(0, 1, spam=-2) - A = -3 * nx.laplacian_matrix(G, weight="spam") - assert nx.algebraic_connectivity( - G, weight="spam", tol=1e-12, method=method - ) == pytest.approx(6, abs=1e-7) - x = nx.fiedler_vector(G, weight="spam", tol=1e-12, method=method) - check_eigenvector(A, 6, x) - - def test_abbreviation_of_method(self): - pytest.importorskip("scipy") - G = nx.path_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2 + sqrt(2)) - ac = nx.algebraic_connectivity(G, tol=1e-12, method="tracemin") - assert ac == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, tol=1e-12, method="tracemin") - check_eigenvector(A, sigma, x) - - @pytest.mark.parametrize("method", methods) - def test_path(self, method): - pytest.importorskip("scipy") - G = nx.path_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2 + sqrt(2)) - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert ac == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - @pytest.mark.parametrize("method", methods) - def test_problematic_graph_issue_2381(self, method): - pytest.importorskip("scipy") - G = nx.path_graph(4) - G.add_edges_from([(4, 2), (5, 1)]) - A = nx.laplacian_matrix(G) - sigma = 0.438447187191 - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert ac == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - @pytest.mark.parametrize("method", methods) - def test_cycle(self, method): - pytest.importorskip("scipy") - G = nx.cycle_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2) - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert ac == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - @pytest.mark.parametrize("method", methods) - def test_seed_argument(self, method): - pytest.importorskip("scipy") - G = nx.cycle_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2) - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method, seed=1) - assert ac == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, tol=1e-12, method=method, seed=1) - check_eigenvector(A, sigma, x) - - @pytest.mark.parametrize( - ("normalized", "sigma", "laplacian_fn"), - ( - (False, 0.2434017461399311, nx.laplacian_matrix), - (True, 0.08113391537997749, nx.normalized_laplacian_matrix), - ), - ) - @pytest.mark.parametrize("method", methods) - def test_buckminsterfullerene(self, normalized, sigma, laplacian_fn, method): - pytest.importorskip("scipy") - G = nx.Graph( - [ - (1, 10), - (1, 41), - (1, 59), - (2, 12), - (2, 42), - (2, 60), - (3, 6), - (3, 43), - (3, 57), - (4, 8), - (4, 44), - (4, 58), - (5, 13), - (5, 56), - (5, 57), - (6, 10), - (6, 31), - (7, 14), - (7, 56), - (7, 58), - (8, 12), - (8, 32), - (9, 23), - (9, 53), - (9, 59), - (10, 15), - (11, 24), - (11, 53), - (11, 60), - (12, 16), - (13, 14), - (13, 25), - (14, 26), - (15, 27), - (15, 49), - (16, 28), - (16, 50), - (17, 18), - (17, 19), - (17, 54), - (18, 20), - (18, 55), - (19, 23), - (19, 41), - (20, 24), - (20, 42), - (21, 31), - (21, 33), - (21, 57), - (22, 32), - (22, 34), - (22, 58), - (23, 24), - (25, 35), - (25, 43), - (26, 36), - (26, 44), - (27, 51), - (27, 59), - (28, 52), - (28, 60), - (29, 33), - (29, 34), - (29, 56), - (30, 51), - (30, 52), - (30, 53), - (31, 47), - (32, 48), - (33, 45), - (34, 46), - (35, 36), - (35, 37), - (36, 38), - (37, 39), - (37, 49), - (38, 40), - (38, 50), - (39, 40), - (39, 51), - (40, 52), - (41, 47), - (42, 48), - (43, 49), - (44, 50), - (45, 46), - (45, 54), - (46, 55), - (47, 54), - (48, 55), - ] - ) - A = laplacian_fn(G) - try: - assert nx.algebraic_connectivity( - G, normalized=normalized, tol=1e-12, method=method - ) == pytest.approx(sigma, abs=1e-7) - x = nx.fiedler_vector(G, normalized=normalized, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - except nx.NetworkXError as err: - if err.args not in ( - ("Cholesky solver unavailable.",), - ("LU solver unavailable.",), - ): - raise - - -class TestSpectralOrdering: - _graphs = (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) - - @pytest.mark.parametrize("graph", _graphs) - def test_nullgraph(self, graph): - G = graph() - pytest.raises(nx.NetworkXError, nx.spectral_ordering, G) - - @pytest.mark.parametrize("graph", _graphs) - def test_singleton(self, graph): - G = graph() - G.add_node("x") - assert nx.spectral_ordering(G) == ["x"] - G.add_edge("x", "x", weight=33) - G.add_edge("x", "x", weight=33) - assert nx.spectral_ordering(G) == ["x"] - - def test_unrecognized_method(self): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, nx.spectral_ordering, G, method="unknown") - - @pytest.mark.parametrize("method", methods) - def test_three_nodes(self, method): - pytest.importorskip("scipy") - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1)], weight="spam") - order = nx.spectral_ordering(G, weight="spam", method=method) - assert set(order) == set(G) - assert {1, 3} in (set(order[:-1]), set(order[1:])) - - @pytest.mark.parametrize("method", methods) - def test_three_nodes_multigraph(self, method): - pytest.importorskip("scipy") - G = nx.MultiDiGraph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1), (2, 3, 2)]) - order = nx.spectral_ordering(G, method=method) - assert set(order) == set(G) - assert {2, 3} in (set(order[:-1]), set(order[1:])) - - @pytest.mark.parametrize("method", methods) - def test_path(self, method): - pytest.importorskip("scipy") - path = list(range(10)) - np.random.shuffle(path) - G = nx.Graph() - nx.add_path(G, path) - order = nx.spectral_ordering(G, method=method) - assert order in [path, list(reversed(path))] - - @pytest.mark.parametrize("method", methods) - def test_seed_argument(self, method): - pytest.importorskip("scipy") - path = list(range(10)) - np.random.shuffle(path) - G = nx.Graph() - nx.add_path(G, path) - order = nx.spectral_ordering(G, method=method, seed=1) - assert order in [path, list(reversed(path))] - - @pytest.mark.parametrize("method", methods) - def test_disconnected(self, method): - pytest.importorskip("scipy") - G = nx.Graph() - nx.add_path(G, range(0, 10, 2)) - nx.add_path(G, range(1, 10, 2)) - order = nx.spectral_ordering(G, method=method) - assert set(order) == set(G) - seqs = [ - list(range(0, 10, 2)), - list(range(8, -1, -2)), - list(range(1, 10, 2)), - list(range(9, -1, -2)), - ] - assert order[:5] in seqs - assert order[5:] in seqs - - @pytest.mark.parametrize( - ("normalized", "expected_order"), - ( - (False, [[1, 2, 0, 3, 4, 5, 6, 9, 7, 8], [8, 7, 9, 6, 5, 4, 3, 0, 2, 1]]), - (True, [[1, 2, 3, 0, 4, 5, 9, 6, 7, 8], [8, 7, 6, 9, 5, 4, 0, 3, 2, 1]]), - ), - ) - @pytest.mark.parametrize("method", methods) - def test_cycle(self, normalized, expected_order, method): - pytest.importorskip("scipy") - path = list(range(10)) - G = nx.Graph() - nx.add_path(G, path, weight=5) - G.add_edge(path[-1], path[0], weight=1) - A = nx.laplacian_matrix(G).todense() - order = nx.spectral_ordering(G, normalized=normalized, method=method) - assert order in expected_order diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_attrmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_attrmatrix.py deleted file mode 100644 index 01574bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_attrmatrix.py +++ /dev/null @@ -1,108 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") - -import networkx as nx - - -def test_attr_matrix(): - G = nx.Graph() - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 2, thickness=2) - G.add_edge(1, 2, thickness=3) - - def node_attr(u): - return G.nodes[u].get("size", 0.5) * 3 - - def edge_attr(u, v): - return G[u][v].get("thickness", 0.5) - - M = nx.attr_matrix(G, edge_attr=edge_attr, node_attr=node_attr) - np.testing.assert_equal(M[0], np.array([[6.0]])) - assert M[1] == [1.5] - - -def test_attr_matrix_directed(): - G = nx.DiGraph() - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 2, thickness=2) - G.add_edge(1, 2, thickness=3) - M = nx.attr_matrix(G, rc_order=[0, 1, 2]) - # fmt: off - data = np.array( - [[0., 1., 1.], - [0., 0., 1.], - [0., 0., 0.]] - ) - # fmt: on - np.testing.assert_equal(M, np.array(data)) - - -def test_attr_matrix_multigraph(): - G = nx.MultiGraph() - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 2, thickness=2) - G.add_edge(1, 2, thickness=3) - M = nx.attr_matrix(G, rc_order=[0, 1, 2]) - # fmt: off - data = np.array( - [[0., 3., 1.], - [3., 0., 1.], - [1., 1., 0.]] - ) - # fmt: on - np.testing.assert_equal(M, np.array(data)) - M = nx.attr_matrix(G, edge_attr="weight", rc_order=[0, 1, 2]) - # fmt: off - data = np.array( - [[0., 9., 1.], - [9., 0., 1.], - [1., 1., 0.]] - ) - # fmt: on - np.testing.assert_equal(M, np.array(data)) - M = nx.attr_matrix(G, edge_attr="thickness", rc_order=[0, 1, 2]) - # fmt: off - data = np.array( - [[0., 3., 2.], - [3., 0., 3.], - [2., 3., 0.]] - ) - # fmt: on - np.testing.assert_equal(M, np.array(data)) - - -def test_attr_sparse_matrix(): - pytest.importorskip("scipy") - G = nx.Graph() - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 2, thickness=2) - G.add_edge(1, 2, thickness=3) - M = nx.attr_sparse_matrix(G) - mtx = M[0] - data = np.ones((3, 3), float) - np.fill_diagonal(data, 0) - np.testing.assert_equal(mtx.todense(), np.array(data)) - assert M[1] == [0, 1, 2] - - -def test_attr_sparse_matrix_directed(): - pytest.importorskip("scipy") - G = nx.DiGraph() - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 1, thickness=1, weight=3) - G.add_edge(0, 2, thickness=2) - G.add_edge(1, 2, thickness=3) - M = nx.attr_sparse_matrix(G, rc_order=[0, 1, 2]) - # fmt: off - data = np.array( - [[0., 1., 1.], - [0., 0., 1.], - [0., 0., 0.]] - ) - # fmt: on - np.testing.assert_equal(M.todense(), np.array(data)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_bethehessian.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_bethehessian.py deleted file mode 100644 index 339fe1b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_bethehessian.py +++ /dev/null @@ -1,41 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestBetheHessian: - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.P = nx.path_graph(3) - - def test_bethe_hessian(self): - "Bethe Hessian matrix" - # fmt: off - H = np.array([[4, -2, 0], - [-2, 5, -2], - [0, -2, 4]]) - # fmt: on - permutation = [2, 0, 1] - # Bethe Hessian gives expected form - np.testing.assert_equal(nx.bethe_hessian_matrix(self.P, r=2).todense(), H) - # nodelist is correctly implemented - np.testing.assert_equal( - nx.bethe_hessian_matrix(self.P, r=2, nodelist=permutation).todense(), - H[np.ix_(permutation, permutation)], - ) - # Equal to Laplacian matrix when r=1 - np.testing.assert_equal( - nx.bethe_hessian_matrix(self.G, r=1).todense(), - nx.laplacian_matrix(self.G).todense(), - ) - # Correct default for the regularizer r - np.testing.assert_equal( - nx.bethe_hessian_matrix(self.G).todense(), - nx.bethe_hessian_matrix(self.G, r=1.25).todense(), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_graphmatrix.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_graphmatrix.py deleted file mode 100644 index 519198b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_graphmatrix.py +++ /dev/null @@ -1,276 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.generators.degree_seq import havel_hakimi_graph - - -def test_incidence_matrix_simple(): - deg = [3, 2, 2, 1, 0] - G = havel_hakimi_graph(deg) - deg = [(1, 0), (1, 0), (1, 0), (2, 0), (1, 0), (2, 1), (0, 1), (0, 1)] - MG = nx.random_clustered_graph(deg, seed=42) - - I = nx.incidence_matrix(G, dtype=int).todense() - # fmt: off - expected = np.array( - [[1, 1, 1, 0], - [0, 1, 0, 1], - [1, 0, 0, 1], - [0, 0, 1, 0], - [0, 0, 0, 0]] - ) - # fmt: on - np.testing.assert_equal(I, expected) - - I = nx.incidence_matrix(MG, dtype=int).todense() - # fmt: off - expected = np.array( - [[1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 1, 0], - [0, 0, 0, 0, 0, 1, 1], - [0, 0, 0, 0, 1, 0, 1]] - ) - # fmt: on - np.testing.assert_equal(I, expected) - - with pytest.raises(NetworkXError): - nx.incidence_matrix(G, nodelist=[0, 1]) - - -class TestGraphMatrix: - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - # fmt: off - cls.OI = np.array( - [[-1, -1, -1, 0], - [1, 0, 0, -1], - [0, 1, 0, 1], - [0, 0, 1, 0], - [0, 0, 0, 0]] - ) - cls.A = np.array( - [[0, 1, 1, 1, 0], - [1, 0, 1, 0, 0], - [1, 1, 0, 0, 0], - [1, 0, 0, 0, 0], - [0, 0, 0, 0, 0]] - ) - # fmt: on - cls.WG = havel_hakimi_graph(deg) - cls.WG.add_edges_from( - (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges() - ) - # fmt: off - cls.WA = np.array( - [[0, 0.5, 0.5, 0.5, 0], - [0.5, 0, 0.5, 0, 0], - [0.5, 0.5, 0, 0, 0], - [0.5, 0, 0, 0, 0], - [0, 0, 0, 0, 0]] - ) - # fmt: on - cls.MG = nx.MultiGraph(cls.G) - cls.MG2 = cls.MG.copy() - cls.MG2.add_edge(0, 1) - # fmt: off - cls.MG2A = np.array( - [[0, 2, 1, 1, 0], - [2, 0, 1, 0, 0], - [1, 1, 0, 0, 0], - [1, 0, 0, 0, 0], - [0, 0, 0, 0, 0]] - ) - cls.MGOI = np.array( - [[-1, -1, -1, -1, 0], - [1, 1, 0, 0, -1], - [0, 0, 1, 0, 1], - [0, 0, 0, 1, 0], - [0, 0, 0, 0, 0]] - ) - # fmt: on - cls.no_edges_G = nx.Graph([(1, 2), (3, 2, {"weight": 8})]) - cls.no_edges_A = np.array([[0, 0], [0, 0]]) - - def test_incidence_matrix(self): - "Conversion to incidence matrix" - I = nx.incidence_matrix( - self.G, - nodelist=sorted(self.G), - edgelist=sorted(self.G.edges()), - oriented=True, - dtype=int, - ).todense() - np.testing.assert_equal(I, self.OI) - - I = nx.incidence_matrix( - self.G, - nodelist=sorted(self.G), - edgelist=sorted(self.G.edges()), - oriented=False, - dtype=int, - ).todense() - np.testing.assert_equal(I, np.abs(self.OI)) - - I = nx.incidence_matrix( - self.MG, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG.edges()), - oriented=True, - dtype=int, - ).todense() - np.testing.assert_equal(I, self.OI) - - I = nx.incidence_matrix( - self.MG, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG.edges()), - oriented=False, - dtype=int, - ).todense() - np.testing.assert_equal(I, np.abs(self.OI)) - - I = nx.incidence_matrix( - self.MG2, - nodelist=sorted(self.MG2), - edgelist=sorted(self.MG2.edges()), - oriented=True, - dtype=int, - ).todense() - np.testing.assert_equal(I, self.MGOI) - - I = nx.incidence_matrix( - self.MG2, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG2.edges()), - oriented=False, - dtype=int, - ).todense() - np.testing.assert_equal(I, np.abs(self.MGOI)) - - I = nx.incidence_matrix(self.G, dtype=np.uint8) - assert I.dtype == np.uint8 - - def test_weighted_incidence_matrix(self): - I = nx.incidence_matrix( - self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True, - dtype=int, - ).todense() - np.testing.assert_equal(I, self.OI) - - I = nx.incidence_matrix( - self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=False, - dtype=int, - ).todense() - np.testing.assert_equal(I, np.abs(self.OI)) - - # np.testing.assert_equal(nx.incidence_matrix(self.WG,oriented=True, - # weight='weight').todense(),0.5*self.OI) - # np.testing.assert_equal(nx.incidence_matrix(self.WG,weight='weight').todense(), - # np.abs(0.5*self.OI)) - # np.testing.assert_equal(nx.incidence_matrix(self.WG,oriented=True,weight='other').todense(), - # 0.3*self.OI) - - I = nx.incidence_matrix( - self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True, - weight="weight", - ).todense() - np.testing.assert_equal(I, 0.5 * self.OI) - - I = nx.incidence_matrix( - self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=False, - weight="weight", - ).todense() - np.testing.assert_equal(I, np.abs(0.5 * self.OI)) - - I = nx.incidence_matrix( - self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True, - weight="other", - ).todense() - np.testing.assert_equal(I, 0.3 * self.OI) - - # WMG=nx.MultiGraph(self.WG) - # WMG.add_edge(0,1,weight=0.5,other=0.3) - # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='weight').todense(), - # np.abs(0.5*self.MGOI)) - # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='weight',oriented=True).todense(), - # 0.5*self.MGOI) - # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='other',oriented=True).todense(), - # 0.3*self.MGOI) - - WMG = nx.MultiGraph(self.WG) - WMG.add_edge(0, 1, weight=0.5, other=0.3) - - I = nx.incidence_matrix( - WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=True, - weight="weight", - ).todense() - np.testing.assert_equal(I, 0.5 * self.MGOI) - - I = nx.incidence_matrix( - WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=False, - weight="weight", - ).todense() - np.testing.assert_equal(I, np.abs(0.5 * self.MGOI)) - - I = nx.incidence_matrix( - WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=True, - weight="other", - ).todense() - np.testing.assert_equal(I, 0.3 * self.MGOI) - - def test_adjacency_matrix(self): - "Conversion to adjacency matrix" - np.testing.assert_equal(nx.adjacency_matrix(self.G).todense(), self.A) - np.testing.assert_equal(nx.adjacency_matrix(self.MG).todense(), self.A) - np.testing.assert_equal(nx.adjacency_matrix(self.MG2).todense(), self.MG2A) - np.testing.assert_equal( - nx.adjacency_matrix(self.G, nodelist=[0, 1]).todense(), self.A[:2, :2] - ) - np.testing.assert_equal(nx.adjacency_matrix(self.WG).todense(), self.WA) - np.testing.assert_equal( - nx.adjacency_matrix(self.WG, weight=None).todense(), self.A - ) - np.testing.assert_equal( - nx.adjacency_matrix(self.MG2, weight=None).todense(), self.MG2A - ) - np.testing.assert_equal( - nx.adjacency_matrix(self.WG, weight="other").todense(), 0.6 * self.WA - ) - np.testing.assert_equal( - nx.adjacency_matrix(self.no_edges_G, nodelist=[1, 3]).todense(), - self.no_edges_A, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_laplacian.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_laplacian.py deleted file mode 100644 index 23f1b28..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_laplacian.py +++ /dev/null @@ -1,336 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph -from networkx.generators.expanders import margulis_gabber_galil_graph - - -class TestLaplacian: - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.WG = nx.Graph( - (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges() - ) - cls.WG.add_node(4) - cls.MG = nx.MultiGraph(cls.G) - - # Graph with clsloops - cls.Gsl = cls.G.copy() - for node in cls.Gsl.nodes(): - cls.Gsl.add_edge(node, node) - - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". - cls.DiG = nx.DiGraph() - cls.DiG.add_edges_from( - ( - (1, 2), - (1, 3), - (3, 1), - (3, 2), - (3, 5), - (4, 5), - (4, 6), - (5, 4), - (5, 6), - (6, 4), - ) - ) - cls.DiMG = nx.MultiDiGraph(cls.DiG) - cls.DiWG = nx.DiGraph( - (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.DiG.edges() - ) - cls.DiGsl = cls.DiG.copy() - for node in cls.DiGsl.nodes(): - cls.DiGsl.add_edge(node, node) - - def test_laplacian(self): - "Graph Laplacian" - # fmt: off - NL = np.array([[ 3, -1, -1, -1, 0], - [-1, 2, -1, 0, 0], - [-1, -1, 2, 0, 0], - [-1, 0, 0, 1, 0], - [ 0, 0, 0, 0, 0]]) - # fmt: on - WL = 0.5 * NL - OL = 0.3 * NL - # fmt: off - DiNL = np.array([[ 2, -1, -1, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0], - [-1, -1, 3, -1, 0, 0], - [ 0, 0, 0, 2, -1, -1], - [ 0, 0, 0, -1, 2, -1], - [ 0, 0, 0, 0, -1, 1]]) - # fmt: on - DiWL = 0.5 * DiNL - DiOL = 0.3 * DiNL - np.testing.assert_equal(nx.laplacian_matrix(self.G).todense(), NL) - np.testing.assert_equal(nx.laplacian_matrix(self.MG).todense(), NL) - np.testing.assert_equal( - nx.laplacian_matrix(self.G, nodelist=[0, 1]).todense(), - np.array([[1, -1], [-1, 1]]), - ) - np.testing.assert_equal(nx.laplacian_matrix(self.WG).todense(), WL) - np.testing.assert_equal(nx.laplacian_matrix(self.WG, weight=None).todense(), NL) - np.testing.assert_equal( - nx.laplacian_matrix(self.WG, weight="other").todense(), OL - ) - - np.testing.assert_equal(nx.laplacian_matrix(self.DiG).todense(), DiNL) - np.testing.assert_equal(nx.laplacian_matrix(self.DiMG).todense(), DiNL) - np.testing.assert_equal( - nx.laplacian_matrix(self.DiG, nodelist=[1, 2]).todense(), - np.array([[1, -1], [0, 0]]), - ) - np.testing.assert_equal(nx.laplacian_matrix(self.DiWG).todense(), DiWL) - np.testing.assert_equal( - nx.laplacian_matrix(self.DiWG, weight=None).todense(), DiNL - ) - np.testing.assert_equal( - nx.laplacian_matrix(self.DiWG, weight="other").todense(), DiOL - ) - - def test_normalized_laplacian(self): - "Generalized Graph Laplacian" - # fmt: off - G = np.array([[ 1. , -0.408, -0.408, -0.577, 0.], - [-0.408, 1. , -0.5 , 0. , 0.], - [-0.408, -0.5 , 1. , 0. , 0.], - [-0.577, 0. , 0. , 1. , 0.], - [ 0. , 0. , 0. , 0. , 0.]]) - GL = np.array([[ 1. , -0.408, -0.408, -0.577, 0. ], - [-0.408, 1. , -0.5 , 0. , 0. ], - [-0.408, -0.5 , 1. , 0. , 0. ], - [-0.577, 0. , 0. , 1. , 0. ], - [ 0. , 0. , 0. , 0. , 0. ]]) - Lsl = np.array([[ 0.75 , -0.2887, -0.2887, -0.3536, 0. ], - [-0.2887, 0.6667, -0.3333, 0. , 0. ], - [-0.2887, -0.3333, 0.6667, 0. , 0. ], - [-0.3536, 0. , 0. , 0.5 , 0. ], - [ 0. , 0. , 0. , 0. , 0. ]]) - - DiG = np.array([[ 1. , 0. , -0.4082, 0. , 0. , 0. ], - [ 0. , 0. , 0. , 0. , 0. , 0. ], - [-0.4082, 0. , 1. , 0. , -0.4082, 0. ], - [ 0. , 0. , 0. , 1. , -0.5 , -0.7071], - [ 0. , 0. , 0. , -0.5 , 1. , -0.7071], - [ 0. , 0. , 0. , -0.7071, 0. , 1. ]]) - DiGL = np.array([[ 1. , 0. , -0.4082, 0. , 0. , 0. ], - [ 0. , 0. , 0. , 0. , 0. , 0. ], - [-0.4082, 0. , 1. , -0.4082, 0. , 0. ], - [ 0. , 0. , 0. , 1. , -0.5 , -0.7071], - [ 0. , 0. , 0. , -0.5 , 1. , -0.7071], - [ 0. , 0. , 0. , 0. , -0.7071, 1. ]]) - DiLsl = np.array([[ 0.6667, -0.5774, -0.2887, 0. , 0. , 0. ], - [ 0. , 0. , 0. , 0. , 0. , 0. ], - [-0.2887, -0.5 , 0.75 , -0.2887, 0. , 0. ], - [ 0. , 0. , 0. , 0.6667, -0.3333, -0.4082], - [ 0. , 0. , 0. , -0.3333, 0.6667, -0.4082], - [ 0. , 0. , 0. , 0. , -0.4082, 0.5 ]]) - # fmt: on - - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.G, nodelist=range(5)).todense(), - G, - decimal=3, - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.G).todense(), GL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.MG).todense(), GL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.WG).todense(), GL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.WG, weight="other").todense(), - GL, - decimal=3, - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.Gsl).todense(), Lsl, decimal=3 - ) - - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix( - self.DiG, - nodelist=range(1, 1 + 6), - ).todense(), - DiG, - decimal=3, - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.DiG).todense(), DiGL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.DiMG).todense(), DiGL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.DiWG).todense(), DiGL, decimal=3 - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.DiWG, weight="other").todense(), - DiGL, - decimal=3, - ) - np.testing.assert_almost_equal( - nx.normalized_laplacian_matrix(self.DiGsl).todense(), DiLsl, decimal=3 - ) - - -def test_directed_laplacian(): - "Directed Laplacian" - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". The graph contains dangling nodes, so - # the pagerank random walk is selected by directed_laplacian - G = nx.DiGraph() - G.add_edges_from( - ( - (1, 2), - (1, 3), - (3, 1), - (3, 2), - (3, 5), - (4, 5), - (4, 6), - (5, 4), - (5, 6), - (6, 4), - ) - ) - # fmt: off - GL = np.array([[ 0.9833, -0.2941, -0.3882, -0.0291, -0.0231, -0.0261], - [-0.2941, 0.8333, -0.2339, -0.0536, -0.0589, -0.0554], - [-0.3882, -0.2339, 0.9833, -0.0278, -0.0896, -0.0251], - [-0.0291, -0.0536, -0.0278, 0.9833, -0.4878, -0.6675], - [-0.0231, -0.0589, -0.0896, -0.4878, 0.9833, -0.2078], - [-0.0261, -0.0554, -0.0251, -0.6675, -0.2078, 0.9833]]) - # fmt: on - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G)) - np.testing.assert_almost_equal(L, GL, decimal=3) - - # Make the graph strongly connected, so we can use a random and lazy walk - G.add_edges_from(((2, 5), (6, 1))) - # fmt: off - GL = np.array([[ 1. , -0.3062, -0.4714, 0. , 0. , -0.3227], - [-0.3062, 1. , -0.1443, 0. , -0.3162, 0. ], - [-0.4714, -0.1443, 1. , 0. , -0.0913, 0. ], - [ 0. , 0. , 0. , 1. , -0.5 , -0.5 ], - [ 0. , -0.3162, -0.0913, -0.5 , 1. , -0.25 ], - [-0.3227, 0. , 0. , -0.5 , -0.25 , 1. ]]) - # fmt: on - L = nx.directed_laplacian_matrix( - G, alpha=0.9, nodelist=sorted(G), walk_type="random" - ) - np.testing.assert_almost_equal(L, GL, decimal=3) - - # fmt: off - GL = np.array([[ 0.5 , -0.1531, -0.2357, 0. , 0. , -0.1614], - [-0.1531, 0.5 , -0.0722, 0. , -0.1581, 0. ], - [-0.2357, -0.0722, 0.5 , 0. , -0.0456, 0. ], - [ 0. , 0. , 0. , 0.5 , -0.25 , -0.25 ], - [ 0. , -0.1581, -0.0456, -0.25 , 0.5 , -0.125 ], - [-0.1614, 0. , 0. , -0.25 , -0.125 , 0.5 ]]) - # fmt: on - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G), walk_type="lazy") - np.testing.assert_almost_equal(L, GL, decimal=3) - - # Make a strongly connected periodic graph - G = nx.DiGraph() - G.add_edges_from(((1, 2), (2, 4), (4, 1), (1, 3), (3, 4))) - # fmt: off - GL = np.array([[ 0.5 , -0.176, -0.176, -0.25 ], - [-0.176, 0.5 , 0. , -0.176], - [-0.176, 0. , 0.5 , -0.176], - [-0.25 , -0.176, -0.176, 0.5 ]]) - # fmt: on - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G)) - np.testing.assert_almost_equal(L, GL, decimal=3) - - -def test_directed_combinatorial_laplacian(): - "Directed combinatorial Laplacian" - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". The graph contains dangling nodes, so - # the pagerank random walk is selected by directed_laplacian - G = nx.DiGraph() - G.add_edges_from( - ( - (1, 2), - (1, 3), - (3, 1), - (3, 2), - (3, 5), - (4, 5), - (4, 6), - (5, 4), - (5, 6), - (6, 4), - ) - ) - # fmt: off - GL = np.array([[ 0.0366, -0.0132, -0.0153, -0.0034, -0.0020, -0.0027], - [-0.0132, 0.0450, -0.0111, -0.0076, -0.0062, -0.0069], - [-0.0153, -0.0111, 0.0408, -0.0035, -0.0083, -0.0027], - [-0.0034, -0.0076, -0.0035, 0.3688, -0.1356, -0.2187], - [-0.0020, -0.0062, -0.0083, -0.1356, 0.2026, -0.0505], - [-0.0027, -0.0069, -0.0027, -0.2187, -0.0505, 0.2815]]) - # fmt: on - - L = nx.directed_combinatorial_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G)) - np.testing.assert_almost_equal(L, GL, decimal=3) - - # Make the graph strongly connected, so we can use a random and lazy walk - G.add_edges_from(((2, 5), (6, 1))) - - # fmt: off - GL = np.array([[ 0.1395, -0.0349, -0.0465, 0. , 0. , -0.0581], - [-0.0349, 0.093 , -0.0116, 0. , -0.0465, 0. ], - [-0.0465, -0.0116, 0.0698, 0. , -0.0116, 0. ], - [ 0. , 0. , 0. , 0.2326, -0.1163, -0.1163], - [ 0. , -0.0465, -0.0116, -0.1163, 0.2326, -0.0581], - [-0.0581, 0. , 0. , -0.1163, -0.0581, 0.2326]]) - # fmt: on - - L = nx.directed_combinatorial_laplacian_matrix( - G, alpha=0.9, nodelist=sorted(G), walk_type="random" - ) - np.testing.assert_almost_equal(L, GL, decimal=3) - - # fmt: off - GL = np.array([[ 0.0698, -0.0174, -0.0233, 0. , 0. , -0.0291], - [-0.0174, 0.0465, -0.0058, 0. , -0.0233, 0. ], - [-0.0233, -0.0058, 0.0349, 0. , -0.0058, 0. ], - [ 0. , 0. , 0. , 0.1163, -0.0581, -0.0581], - [ 0. , -0.0233, -0.0058, -0.0581, 0.1163, -0.0291], - [-0.0291, 0. , 0. , -0.0581, -0.0291, 0.1163]]) - # fmt: on - - L = nx.directed_combinatorial_laplacian_matrix( - G, alpha=0.9, nodelist=sorted(G), walk_type="lazy" - ) - np.testing.assert_almost_equal(L, GL, decimal=3) - - E = nx.DiGraph(margulis_gabber_galil_graph(2)) - L = nx.directed_combinatorial_laplacian_matrix(E) - # fmt: off - expected = np.array( - [[ 0.16666667, -0.08333333, -0.08333333, 0. ], - [-0.08333333, 0.16666667, 0. , -0.08333333], - [-0.08333333, 0. , 0.16666667, -0.08333333], - [ 0. , -0.08333333, -0.08333333, 0.16666667]] - ) - # fmt: on - np.testing.assert_almost_equal(L, expected, decimal=6) - - with pytest.raises(nx.NetworkXError): - nx.directed_combinatorial_laplacian_matrix(G, walk_type="pagerank", alpha=100) - with pytest.raises(nx.NetworkXError): - nx.directed_combinatorial_laplacian_matrix(G, walk_type="silly") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_modularity.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_modularity.py deleted file mode 100644 index 9f94ff4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_modularity.py +++ /dev/null @@ -1,87 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestModularity: - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". (Used for test_directed_laplacian) - cls.DG = nx.DiGraph() - cls.DG.add_edges_from( - ( - (1, 2), - (1, 3), - (3, 1), - (3, 2), - (3, 5), - (4, 5), - (4, 6), - (5, 4), - (5, 6), - (6, 4), - ) - ) - - def test_modularity(self): - "Modularity matrix" - # fmt: off - B = np.array([[-1.125, 0.25, 0.25, 0.625, 0.], - [0.25, -0.5, 0.5, -0.25, 0.], - [0.25, 0.5, -0.5, -0.25, 0.], - [0.625, -0.25, -0.25, -0.125, 0.], - [0., 0., 0., 0., 0.]]) - # fmt: on - - permutation = [4, 0, 1, 2, 3] - np.testing.assert_equal(nx.modularity_matrix(self.G), B) - np.testing.assert_equal( - nx.modularity_matrix(self.G, nodelist=permutation), - B[np.ix_(permutation, permutation)], - ) - - def test_modularity_weight(self): - "Modularity matrix with weights" - # fmt: off - B = np.array([[-1.125, 0.25, 0.25, 0.625, 0.], - [0.25, -0.5, 0.5, -0.25, 0.], - [0.25, 0.5, -0.5, -0.25, 0.], - [0.625, -0.25, -0.25, -0.125, 0.], - [0., 0., 0., 0., 0.]]) - # fmt: on - - G_weighted = self.G.copy() - for n1, n2 in G_weighted.edges(): - G_weighted.edges[n1, n2]["weight"] = 0.5 - # The following test would fail in networkx 1.1 - np.testing.assert_equal(nx.modularity_matrix(G_weighted), B) - # The following test that the modularity matrix get rescaled accordingly - np.testing.assert_equal( - nx.modularity_matrix(G_weighted, weight="weight"), 0.5 * B - ) - - def test_directed_modularity(self): - "Directed Modularity matrix" - # fmt: off - B = np.array([[-0.2, 0.6, 0.8, -0.4, -0.4, -0.4], - [0., 0., 0., 0., 0., 0.], - [0.7, 0.4, -0.3, -0.6, 0.4, -0.6], - [-0.2, -0.4, -0.2, -0.4, 0.6, 0.6], - [-0.2, -0.4, -0.2, 0.6, -0.4, 0.6], - [-0.1, -0.2, -0.1, 0.8, -0.2, -0.2]]) - # fmt: on - node_permutation = [5, 1, 2, 3, 4, 6] - idx_permutation = [4, 0, 1, 2, 3, 5] - mm = nx.directed_modularity_matrix(self.DG, nodelist=sorted(self.DG)) - np.testing.assert_equal(mm, B) - np.testing.assert_equal( - nx.directed_modularity_matrix(self.DG, nodelist=node_permutation), - B[np.ix_(idx_permutation, idx_permutation)], - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_spectrum.py b/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_spectrum.py deleted file mode 100644 index e910130..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/linalg/tests/test_spectrum.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -pytest.importorskip("scipy") - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestSpectrum: - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.P = nx.path_graph(3) - cls.WG = nx.Graph( - (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges() - ) - cls.WG.add_node(4) - cls.DG = nx.DiGraph() - nx.add_path(cls.DG, [0, 1, 2]) - - def test_laplacian_spectrum(self): - "Laplacian eigenvalues" - evals = np.array([0, 0, 1, 3, 4]) - e = sorted(nx.laplacian_spectrum(self.G)) - np.testing.assert_almost_equal(e, evals) - e = sorted(nx.laplacian_spectrum(self.WG, weight=None)) - np.testing.assert_almost_equal(e, evals) - e = sorted(nx.laplacian_spectrum(self.WG)) - np.testing.assert_almost_equal(e, 0.5 * evals) - e = sorted(nx.laplacian_spectrum(self.WG, weight="other")) - np.testing.assert_almost_equal(e, 0.3 * evals) - - def test_normalized_laplacian_spectrum(self): - "Normalized Laplacian eigenvalues" - evals = np.array([0, 0, 0.7712864461218, 1.5, 1.7287135538781]) - e = sorted(nx.normalized_laplacian_spectrum(self.G)) - np.testing.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight=None)) - np.testing.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG)) - np.testing.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight="other")) - np.testing.assert_almost_equal(e, evals) - - def test_adjacency_spectrum(self): - "Adjacency eigenvalues" - evals = np.array([-np.sqrt(2), 0, np.sqrt(2)]) - e = sorted(nx.adjacency_spectrum(self.P)) - np.testing.assert_almost_equal(e, evals) - - def test_modularity_spectrum(self): - "Modularity eigenvalues" - evals = np.array([-1.5, 0.0, 0.0]) - e = sorted(nx.modularity_spectrum(self.P)) - np.testing.assert_almost_equal(e, evals) - # Directed modularity eigenvalues - evals = np.array([-0.5, 0.0, 0.0]) - e = sorted(nx.modularity_spectrum(self.DG)) - np.testing.assert_almost_equal(e, evals) - - def test_bethe_hessian_spectrum(self): - "Bethe Hessian eigenvalues" - evals = np.array([0.5 * (9 - np.sqrt(33)), 4, 0.5 * (9 + np.sqrt(33))]) - e = sorted(nx.bethe_hessian_spectrum(self.P, r=2)) - np.testing.assert_almost_equal(e, evals) - # Collapses back to Laplacian: - e1 = sorted(nx.bethe_hessian_spectrum(self.P, r=1)) - e2 = sorted(nx.laplacian_spectrum(self.P)) - np.testing.assert_almost_equal(e1, e2) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/__init__.py deleted file mode 100644 index a805c50..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -A package for reading and writing graphs in various formats. - -""" - -from networkx.readwrite.adjlist import * -from networkx.readwrite.multiline_adjlist import * -from networkx.readwrite.edgelist import * -from networkx.readwrite.pajek import * -from networkx.readwrite.leda import * -from networkx.readwrite.sparse6 import * -from networkx.readwrite.graph6 import * -from networkx.readwrite.gml import * -from networkx.readwrite.graphml import * -from networkx.readwrite.gexf import * -from networkx.readwrite.json_graph import * -from networkx.readwrite.text import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/adjlist.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/adjlist.py deleted file mode 100644 index 768af5a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/adjlist.py +++ /dev/null @@ -1,310 +0,0 @@ -""" -************** -Adjacency List -************** -Read and write NetworkX graphs as adjacency lists. - -Adjacency list format is useful for graphs without data associated -with nodes or edges and for nodes that can be meaningfully represented -as strings. - -Format ------- -The adjacency list format consists of lines with node labels. The -first label in a line is the source node. Further labels in the line -are considered target nodes and are added to the graph along with an edge -between the source node and target node. - -The graph with edges a-b, a-c, d-e can be represented as the following -adjacency list (anything following the # in a line is a comment):: - - a b c # source target target - d e -""" - -__all__ = ["generate_adjlist", "write_adjlist", "parse_adjlist", "read_adjlist"] - -import networkx as nx -from networkx.utils import open_file - - -def generate_adjlist(G, delimiter=" "): - """Generate a single line of the graph G in adjacency list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> for line in nx.generate_adjlist(G): - ... print(line) - 0 1 2 3 - 1 2 3 - 2 3 - 3 4 - 4 5 - 5 6 - 6 - - See Also - -------- - write_adjlist, read_adjlist - - Notes - ----- - The default `delimiter=" "` will result in unexpected results if node names contain - whitespace characters. To avoid this problem, specify an alternate delimiter when spaces are - valid in node names. - - NB: This option is not available for data that isn't user-generated. - - """ - directed = G.is_directed() - seen = set() - for s, nbrs in G.adjacency(): - line = str(s) + delimiter - for t, data in nbrs.items(): - if not directed and t in seen: - continue - if G.is_multigraph(): - for d in data.values(): - line += str(t) + delimiter - else: - line += str(t) + delimiter - if not directed: - seen.add(s) - yield line[: -len(delimiter)] - - -@open_file(1, mode="wb") -def write_adjlist(G, path, comments="#", delimiter=" ", encoding="utf-8"): - """Write graph G in single-line adjacency-list format to path. - - - Parameters - ---------- - G : NetworkX graph - - path : string or file - Filename or file handle for data output. - Filenames ending in .gz or .bz2 will be compressed. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels - - encoding : string, optional - Text encoding. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_adjlist(G, "test.adjlist") - - The path can be a filehandle or a string with the name of the file. If a - filehandle is provided, it has to be opened in 'wb' mode. - - >>> fh = open("test.adjlist", "wb") - >>> nx.write_adjlist(G, fh) - - Notes - ----- - The default `delimiter=" "` will result in unexpected results if node names contain - whitespace characters. To avoid this problem, specify an alternate delimiter when spaces are - valid in node names. - NB: This option is not available for data that isn't user-generated. - - This format does not store graph, node, or edge data. - - See Also - -------- - read_adjlist, generate_adjlist - """ - import sys - import time - - pargs = comments + " ".join(sys.argv) + "\n" - header = ( - pargs - + comments - + f" GMT {time.asctime(time.gmtime())}\n" - + comments - + f" {G.name}\n" - ) - path.write(header.encode(encoding)) - - for line in generate_adjlist(G, delimiter): - line += "\n" - path.write(line.encode(encoding)) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_adjlist( - lines, comments="#", delimiter=None, create_using=None, nodetype=None -): - """Parse lines of a graph adjacency list representation. - - Parameters - ---------- - lines : list or iterator of strings - Input data in adjlist format - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in adjacency list format. - - Examples - -------- - >>> lines = ["1 2 5", "2 3 4", "3 5", "4", "5"] - >>> G = nx.parse_adjlist(lines, nodetype=int) - >>> nodes = [1, 2, 3, 4, 5] - >>> all(node in G for node in nodes) - True - >>> edges = [(1, 2), (1, 5), (2, 3), (2, 4), (3, 5)] - >>> all((u, v) in G.edges() or (v, u) in G.edges() for (u, v) in edges) - True - - See Also - -------- - read_adjlist - - """ - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not len(line): - continue - vlist = line.rstrip("\n").split(delimiter) - u = vlist.pop(0) - # convert types - if nodetype is not None: - try: - u = nodetype(u) - except BaseException as err: - raise TypeError( - f"Failed to convert node ({u}) to type {nodetype}" - ) from err - G.add_node(u) - if nodetype is not None: - try: - vlist = list(map(nodetype, vlist)) - except BaseException as err: - raise TypeError( - f"Failed to convert nodes ({','.join(vlist)}) to type {nodetype}" - ) from err - G.add_edges_from([(u, v) for v in vlist]) - return G - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_adjlist( - path, - comments="#", - delimiter=None, - create_using=None, - nodetype=None, - encoding="utf-8", -): - """Read graph in adjacency list format from path. - - Parameters - ---------- - path : string or file - Filename or file handle to read. - Filenames ending in .gz or .bz2 will be uncompressed. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in adjacency list format. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_adjlist(G, "test.adjlist") - >>> G = nx.read_adjlist("test.adjlist") - - The path can be a filehandle or a string with the name of the file. If a - filehandle is provided, it has to be opened in 'rb' mode. - - >>> fh = open("test.adjlist", "rb") - >>> G = nx.read_adjlist(fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_adjlist(G, "test.adjlist.gz") - >>> G = nx.read_adjlist("test.adjlist.gz") - - The optional nodetype is a function to convert node strings to nodetype. - - For example - - >>> G = nx.read_adjlist("test.adjlist", nodetype=int) - - will attempt to convert all nodes to integer type. - - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - - The optional create_using parameter indicates the type of NetworkX graph - created. The default is `nx.Graph`, an undirected graph. - To read the data as a directed graph use - - >>> G = nx.read_adjlist("test.adjlist", create_using=nx.DiGraph) - - Notes - ----- - This format does not store graph or node data. - - See Also - -------- - write_adjlist - """ - lines = (line.decode(encoding) for line in path) - return parse_adjlist( - lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/edgelist.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/edgelist.py deleted file mode 100644 index 393b64e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/edgelist.py +++ /dev/null @@ -1,489 +0,0 @@ -""" -********** -Edge Lists -********** -Read and write NetworkX graphs as edge lists. - -The multi-line adjacency list format is useful for graphs with nodes -that can be meaningfully represented as strings. With the edgelist -format simple edge data can be stored but node or graph data is not. -There is no way of representing isolated nodes unless the node has a -self-loop edge. - -Format ------- -You can read or write three formats of edge lists with these functions. - -Node pairs with no data:: - - 1 2 - -Python dictionary as data:: - - 1 2 {'weight':7, 'color':'green'} - -Arbitrary data:: - - 1 2 7 green -""" - -__all__ = [ - "generate_edgelist", - "write_edgelist", - "parse_edgelist", - "read_edgelist", - "read_weighted_edgelist", - "write_weighted_edgelist", -] - -import networkx as nx -from networkx.utils import open_file - - -def generate_edgelist(G, delimiter=" ", data=True): - """Generate a single line of the graph G in edge list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - data : bool or list of keys - If False generate no edge data. If True use a dictionary - representation of edge data. If a list of keys use a list of data - values corresponding to the keys. - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> G[1][2]["weight"] = 3 - >>> G[3][4]["capacity"] = 12 - >>> for line in nx.generate_edgelist(G, data=False): - ... print(line) - 0 1 - 0 2 - 0 3 - 1 2 - 1 3 - 2 3 - 3 4 - 4 5 - 5 6 - - >>> for line in nx.generate_edgelist(G): - ... print(line) - 0 1 {} - 0 2 {} - 0 3 {} - 1 2 {'weight': 3} - 1 3 {} - 2 3 {} - 3 4 {'capacity': 12} - 4 5 {} - 5 6 {} - - >>> for line in nx.generate_edgelist(G, data=["weight"]): - ... print(line) - 0 1 - 0 2 - 0 3 - 1 2 3 - 1 3 - 2 3 - 3 4 - 4 5 - 5 6 - - See Also - -------- - write_adjlist, read_adjlist - """ - if data is True: - for u, v, d in G.edges(data=True): - e = u, v, dict(d) - yield delimiter.join(map(str, e)) - elif data is False: - for u, v in G.edges(data=False): - e = u, v - yield delimiter.join(map(str, e)) - else: - for u, v, d in G.edges(data=True): - e = [u, v] - try: - e.extend(d[k] for k in data) - except KeyError: - pass # missing data for this edge, should warn? - yield delimiter.join(map(str, e)) - - -@open_file(1, mode="wb") -def write_edgelist(G, path, comments="#", delimiter=" ", data=True, encoding="utf-8"): - """Write graph as a list of edges. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - data : bool or list, optional - If False write no edge data. - If True write a string representation of the edge data dictionary.. - If a list (or other iterable) is provided, write the keys specified - in the list. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_edgelist(G, "test.edgelist") - >>> G = nx.path_graph(4) - >>> fh = open("test.edgelist", "wb") - >>> nx.write_edgelist(G, fh) - >>> nx.write_edgelist(G, "test.edgelist.gz") - >>> nx.write_edgelist(G, "test.edgelist.gz", data=False) - - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=7, color="red") - >>> nx.write_edgelist(G, "test.edgelist", data=False) - >>> nx.write_edgelist(G, "test.edgelist", data=["color"]) - >>> nx.write_edgelist(G, "test.edgelist", data=["color", "weight"]) - - See Also - -------- - read_edgelist - write_weighted_edgelist - """ - - for line in generate_edgelist(G, delimiter, data): - line += "\n" - path.write(line.encode(encoding)) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_edgelist( - lines, comments="#", delimiter=None, create_using=None, nodetype=None, data=True -): - """Parse lines of an edge list representation of a graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in edgelist format - comments : string, optional - Marker for comment lines. Default is `'#'`. To specify that no character - should be treated as a comment, use ``comments=None``. - delimiter : string, optional - Separator for node labels. Default is `None`, meaning any whitespace. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : Python type, optional - Convert nodes to this type. Default is `None`, meaning no conversion is - performed. - data : bool or list of (label,type) tuples - If `False` generate no edge data or if `True` use a dictionary - representation of edge data or a list tuples specifying dictionary - key names and types for edge data. - - Returns - ------- - G: NetworkX Graph - The graph corresponding to lines - - Examples - -------- - Edgelist with no data: - - >>> lines = ["1 2", "2 3", "3 4"] - >>> G = nx.parse_edgelist(lines, nodetype=int) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges()) - [(1, 2), (2, 3), (3, 4)] - - Edgelist with data in Python dictionary representation: - - >>> lines = ["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"] - >>> G = nx.parse_edgelist(lines, nodetype=int) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] - - Edgelist with data in a list: - - >>> lines = ["1 2 3", "2 3 27", "3 4 3.0"] - >>> G = nx.parse_edgelist(lines, nodetype=int, data=(("weight", float),)) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] - - See Also - -------- - read_weighted_edgelist - """ - from ast import literal_eval - - G = nx.empty_graph(0, create_using) - for line in lines: - if comments is not None: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not line: - continue - # split line, should have 2 or more - s = line.rstrip("\n").split(delimiter) - if len(s) < 2: - continue - u = s.pop(0) - v = s.pop(0) - d = s - if nodetype is not None: - try: - u = nodetype(u) - v = nodetype(v) - except Exception as err: - raise TypeError( - f"Failed to convert nodes {u},{v} to type {nodetype}." - ) from err - - if len(d) == 0 or data is False: - # no data or data type specified - edgedata = {} - elif data is True: - # no edge types specified - try: # try to evaluate as dictionary - if delimiter == ",": - edgedata_str = ",".join(d) - else: - edgedata_str = " ".join(d) - edgedata = dict(literal_eval(edgedata_str.strip())) - except Exception as err: - raise TypeError( - f"Failed to convert edge data ({d}) to dictionary." - ) from err - else: - # convert edge data to dictionary with specified keys and type - if len(d) != len(data): - raise IndexError( - f"Edge data {d} and data_keys {data} are not the same length" - ) - edgedata = {} - for (edge_key, edge_type), edge_value in zip(data, d): - try: - edge_value = edge_type(edge_value) - except Exception as err: - raise TypeError( - f"Failed to convert {edge_key} data {edge_value} " - f"to type {edge_type}." - ) from err - edgedata.update({edge_key: edge_value}) - G.add_edge(u, v, **edgedata) - return G - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_edgelist( - path, - comments="#", - delimiter=None, - create_using=None, - nodetype=None, - data=True, - edgetype=None, - encoding="utf-8", -): - """Read a graph from a list of edges. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. To specify that - no character should be treated as a comment, use ``comments=None``. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - data : bool or list of (label,type) tuples - Tuples specifying dictionary key names and types for edge data - edgetype : int, float, str, Python type, optional OBSOLETE - Convert edge data from strings to specified type and use as 'weight' - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Examples - -------- - >>> nx.write_edgelist(nx.path_graph(4), "test.edgelist") - >>> G = nx.read_edgelist("test.edgelist") - - >>> fh = open("test.edgelist", "rb") - >>> G = nx.read_edgelist(fh) - >>> fh.close() - - >>> G = nx.read_edgelist("test.edgelist", nodetype=int) - >>> G = nx.read_edgelist("test.edgelist", create_using=nx.DiGraph) - - Edgelist with data in a list: - - >>> textline = "1 2 3" - >>> fh = open("test.edgelist", "w") - >>> d = fh.write(textline) - >>> fh.close() - >>> G = nx.read_edgelist("test.edgelist", nodetype=int, data=(("weight", float),)) - >>> list(G) - [1, 2] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0})] - - See parse_edgelist() for more examples of formatting. - - See Also - -------- - parse_edgelist - write_edgelist - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - """ - lines = (line if isinstance(line, str) else line.decode(encoding) for line in path) - return parse_edgelist( - lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - data=data, - ) - - -def write_weighted_edgelist(G, path, comments="#", delimiter=" ", encoding="utf-8"): - """Write graph G as a list of edges with numeric weights. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. - Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=7) - >>> nx.write_weighted_edgelist(G, "test.weighted.edgelist") - - See Also - -------- - read_edgelist - write_edgelist - read_weighted_edgelist - """ - write_edgelist( - G, - path, - comments=comments, - delimiter=delimiter, - data=("weight",), - encoding=encoding, - ) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def read_weighted_edgelist( - path, - comments="#", - delimiter=None, - create_using=None, - nodetype=None, - encoding="utf-8", -): - """Read a graph as list of edges with numeric weights. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - - Example edgelist file format. - - With numeric edge data:: - - # read with - # >>> G=nx.read_weighted_edgelist(fh) - # source target data - a b 1 - a c 3.14159 - d e 42 - - See Also - -------- - write_weighted_edgelist - """ - return read_edgelist( - path, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - data=(("weight", float),), - encoding=encoding, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gexf.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gexf.py deleted file mode 100644 index f830dd1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gexf.py +++ /dev/null @@ -1,1066 +0,0 @@ -"""Read and write graphs in GEXF format. - -.. warning:: - This parser uses the standard xml library present in Python, which is - insecure - see :external+python:mod:`xml` for additional information. - Only parse GEFX files you trust. - -GEXF (Graph Exchange XML Format) is a language for describing complex -network structures, their associated data and dynamics. - -This implementation does not support mixed graphs (directed and -undirected edges together). - -Format ------- -GEXF is an XML format. See http://gexf.net/schema.html for the -specification and http://gexf.net/basic.html for examples. -""" - -import itertools -import time -from xml.etree.ElementTree import ( - Element, - ElementTree, - SubElement, - register_namespace, - tostring, -) - -import networkx as nx -from networkx.utils import open_file - -__all__ = ["write_gexf", "read_gexf", "relabel_gexf_graph", "generate_gexf"] - - -@open_file(1, mode="wb") -def write_gexf(G, path, encoding="utf-8", prettyprint=True, version="1.2draft"): - """Write G in GEXF format to path. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Node attributes are checked according to the version of the GEXF - schemas used for parameters which are not user defined, - e.g. visualization 'viz' [2]_. See example for usage. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or file name to write. - File names ending in .gz or .bz2 will be compressed. - encoding : string (optional, default: 'utf-8') - Encoding for text data. - prettyprint : bool (optional, default: True) - If True use line breaks and indenting in output XML. - version: string (optional, default: '1.2draft') - The version of GEXF to be used for nodes attributes checking - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gexf(G, "test.gexf") - - # visualization data - >>> G.nodes[0]["viz"] = {"size": 54} - >>> G.nodes[0]["viz"]["position"] = {"x": 0, "y": 1} - >>> G.nodes[0]["viz"]["color"] = {"r": 0, "g": 0, "b": 256} - - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - The node id attribute is set to be the string of the node label. - If you want to specify an id use set it as node data, e.g. - node['a']['id']=1 to set the id of node 'a' to 1. - - References - ---------- - .. [1] GEXF File Format, http://gexf.net/ - .. [2] GEXF schema, http://gexf.net/schema.html - """ - writer = GEXFWriter(encoding=encoding, prettyprint=prettyprint, version=version) - writer.add_graph(G) - writer.write(path) - - -def generate_gexf(G, encoding="utf-8", prettyprint=True, version="1.2draft"): - """Generate lines of GEXF format representation of G. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - encoding : string (optional, default: 'utf-8') - Encoding for text data. - prettyprint : bool (optional, default: True) - If True use line breaks and indenting in output XML. - version : string (default: 1.2draft) - Version of GEFX File Format (see http://gexf.net/schema.html) - Supported values: "1.1draft", "1.2draft" - - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed=\n - >>> s = linefeed.join(nx.generate_gexf(G)) - >>> for line in nx.generate_gexf(G): # doctest: +SKIP - ... print(line) - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - The node id attribute is set to be the string of the node label. - If you want to specify an id use set it as node data, e.g. - node['a']['id']=1 to set the id of node 'a' to 1. - - References - ---------- - .. [1] GEXF File Format, https://gephi.org/gexf/format/ - """ - writer = GEXFWriter(encoding=encoding, prettyprint=prettyprint, version=version) - writer.add_graph(G) - yield from str(writer).splitlines() - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_gexf(path, node_type=None, relabel=False, version="1.2draft"): - """Read graph in GEXF format from path. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Parameters - ---------- - path : file or string - File or file name to read. - File names ending in .gz or .bz2 will be decompressed. - node_type: Python type (default: None) - Convert node ids to this type if not None. - relabel : bool (default: False) - If True relabel the nodes to use the GEXF node "label" attribute - instead of the node "id" attribute as the NetworkX node label. - version : string (default: 1.2draft) - Version of GEFX File Format (see http://gexf.net/schema.html) - Supported values: "1.1draft", "1.2draft" - - Returns - ------- - graph: NetworkX graph - If no parallel edges are found a Graph or DiGraph is returned. - Otherwise a MultiGraph or MultiDiGraph is returned. - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - References - ---------- - .. [1] GEXF File Format, http://gexf.net/ - """ - reader = GEXFReader(node_type=node_type, version=version) - if relabel: - G = relabel_gexf_graph(reader(path)) - else: - G = reader(path) - return G - - -class GEXF: - versions = { - "1.1draft": { - "NS_GEXF": "http://www.gexf.net/1.1draft", - "NS_VIZ": "http://www.gexf.net/1.1draft/viz", - "NS_XSI": "http://www.w3.org/2001/XMLSchema-instance", - "SCHEMALOCATION": " ".join( - [ - "http://www.gexf.net/1.1draft", - "http://www.gexf.net/1.1draft/gexf.xsd", - ] - ), - "VERSION": "1.1", - }, - "1.2draft": { - "NS_GEXF": "http://www.gexf.net/1.2draft", - "NS_VIZ": "http://www.gexf.net/1.2draft/viz", - "NS_XSI": "http://www.w3.org/2001/XMLSchema-instance", - "SCHEMALOCATION": " ".join( - [ - "http://www.gexf.net/1.2draft", - "http://www.gexf.net/1.2draft/gexf.xsd", - ] - ), - "VERSION": "1.2", - }, - } - - def construct_types(self): - types = [ - (int, "integer"), - (float, "float"), - (float, "double"), - (bool, "boolean"), - (list, "string"), - (dict, "string"), - (int, "long"), - (str, "liststring"), - (str, "anyURI"), - (str, "string"), - ] - - # These additions to types allow writing numpy types - try: - import numpy as np - except ImportError: - pass - else: - # prepend so that python types are created upon read (last entry wins) - types = [ - (np.float64, "float"), - (np.float32, "float"), - (np.float16, "float"), - (np.int_, "int"), - (np.int8, "int"), - (np.int16, "int"), - (np.int32, "int"), - (np.int64, "int"), - (np.uint8, "int"), - (np.uint16, "int"), - (np.uint32, "int"), - (np.uint64, "int"), - (np.int_, "int"), - (np.intc, "int"), - (np.intp, "int"), - ] + types - - self.xml_type = dict(types) - self.python_type = dict(reversed(a) for a in types) - - # http://www.w3.org/TR/xmlschema-2/#boolean - convert_bool = { - "true": True, - "false": False, - "True": True, - "False": False, - "0": False, - 0: False, - "1": True, - 1: True, - } - - def set_version(self, version): - d = self.versions.get(version) - if d is None: - raise nx.NetworkXError(f"Unknown GEXF version {version}.") - self.NS_GEXF = d["NS_GEXF"] - self.NS_VIZ = d["NS_VIZ"] - self.NS_XSI = d["NS_XSI"] - self.SCHEMALOCATION = d["SCHEMALOCATION"] - self.VERSION = d["VERSION"] - self.version = version - - -class GEXFWriter(GEXF): - # class for writing GEXF format files - # use write_gexf() function - def __init__( - self, graph=None, encoding="utf-8", prettyprint=True, version="1.2draft" - ): - self.construct_types() - self.prettyprint = prettyprint - self.encoding = encoding - self.set_version(version) - self.xml = Element( - "gexf", - { - "xmlns": self.NS_GEXF, - "xmlns:xsi": self.NS_XSI, - "xsi:schemaLocation": self.SCHEMALOCATION, - "version": self.VERSION, - }, - ) - - # Make meta element a non-graph element - # Also add lastmodifieddate as attribute, not tag - meta_element = Element("meta") - subelement_text = f"NetworkX {nx.__version__}" - SubElement(meta_element, "creator").text = subelement_text - meta_element.set("lastmodifieddate", time.strftime("%Y-%m-%d")) - self.xml.append(meta_element) - - register_namespace("viz", self.NS_VIZ) - - # counters for edge and attribute identifiers - self.edge_id = itertools.count() - self.attr_id = itertools.count() - self.all_edge_ids = set() - # default attributes are stored in dictionaries - self.attr = {} - self.attr["node"] = {} - self.attr["edge"] = {} - self.attr["node"]["dynamic"] = {} - self.attr["node"]["static"] = {} - self.attr["edge"]["dynamic"] = {} - self.attr["edge"]["static"] = {} - - if graph is not None: - self.add_graph(graph) - - def __str__(self): - if self.prettyprint: - self.indent(self.xml) - s = tostring(self.xml).decode(self.encoding) - return s - - def add_graph(self, G): - # first pass through G collecting edge ids - for u, v, dd in G.edges(data=True): - eid = dd.get("id") - if eid is not None: - self.all_edge_ids.add(str(eid)) - # set graph attributes - if G.graph.get("mode") == "dynamic": - mode = "dynamic" - else: - mode = "static" - # Add a graph element to the XML - if G.is_directed(): - default = "directed" - else: - default = "undirected" - name = G.graph.get("name", "") - graph_element = Element("graph", defaultedgetype=default, mode=mode, name=name) - self.graph_element = graph_element - self.add_nodes(G, graph_element) - self.add_edges(G, graph_element) - self.xml.append(graph_element) - - def add_nodes(self, G, graph_element): - nodes_element = Element("nodes") - for node, data in G.nodes(data=True): - node_data = data.copy() - node_id = str(node_data.pop("id", node)) - kw = {"id": node_id} - label = str(node_data.pop("label", node)) - kw["label"] = label - try: - pid = node_data.pop("pid") - kw["pid"] = str(pid) - except KeyError: - pass - try: - start = node_data.pop("start") - kw["start"] = str(start) - self.alter_graph_mode_timeformat(start) - except KeyError: - pass - try: - end = node_data.pop("end") - kw["end"] = str(end) - self.alter_graph_mode_timeformat(end) - except KeyError: - pass - # add node element with attributes - node_element = Element("node", **kw) - # add node element and attr subelements - default = G.graph.get("node_default", {}) - node_data = self.add_parents(node_element, node_data) - if self.VERSION == "1.1": - node_data = self.add_slices(node_element, node_data) - else: - node_data = self.add_spells(node_element, node_data) - node_data = self.add_viz(node_element, node_data) - node_data = self.add_attributes("node", node_element, node_data, default) - nodes_element.append(node_element) - graph_element.append(nodes_element) - - def add_edges(self, G, graph_element): - def edge_key_data(G): - # helper function to unify multigraph and graph edge iterator - if G.is_multigraph(): - for u, v, key, data in G.edges(data=True, keys=True): - edge_data = data.copy() - edge_data.update(key=key) - edge_id = edge_data.pop("id", None) - if edge_id is None: - edge_id = next(self.edge_id) - while str(edge_id) in self.all_edge_ids: - edge_id = next(self.edge_id) - self.all_edge_ids.add(str(edge_id)) - yield u, v, edge_id, edge_data - else: - for u, v, data in G.edges(data=True): - edge_data = data.copy() - edge_id = edge_data.pop("id", None) - if edge_id is None: - edge_id = next(self.edge_id) - while str(edge_id) in self.all_edge_ids: - edge_id = next(self.edge_id) - self.all_edge_ids.add(str(edge_id)) - yield u, v, edge_id, edge_data - - edges_element = Element("edges") - for u, v, key, edge_data in edge_key_data(G): - kw = {"id": str(key)} - try: - edge_label = edge_data.pop("label") - kw["label"] = str(edge_label) - except KeyError: - pass - try: - edge_weight = edge_data.pop("weight") - kw["weight"] = str(edge_weight) - except KeyError: - pass - try: - edge_type = edge_data.pop("type") - kw["type"] = str(edge_type) - except KeyError: - pass - try: - start = edge_data.pop("start") - kw["start"] = str(start) - self.alter_graph_mode_timeformat(start) - except KeyError: - pass - try: - end = edge_data.pop("end") - kw["end"] = str(end) - self.alter_graph_mode_timeformat(end) - except KeyError: - pass - source_id = str(G.nodes[u].get("id", u)) - target_id = str(G.nodes[v].get("id", v)) - edge_element = Element("edge", source=source_id, target=target_id, **kw) - default = G.graph.get("edge_default", {}) - if self.VERSION == "1.1": - edge_data = self.add_slices(edge_element, edge_data) - else: - edge_data = self.add_spells(edge_element, edge_data) - edge_data = self.add_viz(edge_element, edge_data) - edge_data = self.add_attributes("edge", edge_element, edge_data, default) - edges_element.append(edge_element) - graph_element.append(edges_element) - - def add_attributes(self, node_or_edge, xml_obj, data, default): - # Add attrvalues to node or edge - attvalues = Element("attvalues") - if len(data) == 0: - return data - mode = "static" - for k, v in data.items(): - # rename generic multigraph key to avoid any name conflict - if k == "key": - k = "networkx_key" - val_type = type(v) - if val_type not in self.xml_type: - raise TypeError(f"attribute value type is not allowed: {val_type}") - if isinstance(v, list): - # dynamic data - for val, start, end in v: - val_type = type(val) - if start is not None or end is not None: - mode = "dynamic" - self.alter_graph_mode_timeformat(start) - self.alter_graph_mode_timeformat(end) - break - attr_id = self.get_attr_id( - str(k), self.xml_type[val_type], node_or_edge, default, mode - ) - for val, start, end in v: - e = Element("attvalue") - e.attrib["for"] = attr_id - e.attrib["value"] = str(val) - # Handle nan, inf, -inf differently - if val_type == float: - if e.attrib["value"] == "inf": - e.attrib["value"] = "INF" - elif e.attrib["value"] == "nan": - e.attrib["value"] = "NaN" - elif e.attrib["value"] == "-inf": - e.attrib["value"] = "-INF" - if start is not None: - e.attrib["start"] = str(start) - if end is not None: - e.attrib["end"] = str(end) - attvalues.append(e) - else: - # static data - mode = "static" - attr_id = self.get_attr_id( - str(k), self.xml_type[val_type], node_or_edge, default, mode - ) - e = Element("attvalue") - e.attrib["for"] = attr_id - if isinstance(v, bool): - e.attrib["value"] = str(v).lower() - else: - e.attrib["value"] = str(v) - # Handle float nan, inf, -inf differently - if val_type == float: - if e.attrib["value"] == "inf": - e.attrib["value"] = "INF" - elif e.attrib["value"] == "nan": - e.attrib["value"] = "NaN" - elif e.attrib["value"] == "-inf": - e.attrib["value"] = "-INF" - attvalues.append(e) - xml_obj.append(attvalues) - return data - - def get_attr_id(self, title, attr_type, edge_or_node, default, mode): - # find the id of the attribute or generate a new id - try: - return self.attr[edge_or_node][mode][title] - except KeyError: - # generate new id - new_id = str(next(self.attr_id)) - self.attr[edge_or_node][mode][title] = new_id - attr_kwargs = {"id": new_id, "title": title, "type": attr_type} - attribute = Element("attribute", **attr_kwargs) - # add subelement for data default value if present - default_title = default.get(title) - if default_title is not None: - default_element = Element("default") - default_element.text = str(default_title) - attribute.append(default_element) - # new insert it into the XML - attributes_element = None - for a in self.graph_element.findall("attributes"): - # find existing attributes element by class and mode - a_class = a.get("class") - a_mode = a.get("mode", "static") - if a_class == edge_or_node and a_mode == mode: - attributes_element = a - if attributes_element is None: - # create new attributes element - attr_kwargs = {"mode": mode, "class": edge_or_node} - attributes_element = Element("attributes", **attr_kwargs) - self.graph_element.insert(0, attributes_element) - attributes_element.append(attribute) - return new_id - - def add_viz(self, element, node_data): - viz = node_data.pop("viz", False) - if viz: - color = viz.get("color") - if color is not None: - if self.VERSION == "1.1": - e = Element( - f"{{{self.NS_VIZ}}}color", - r=str(color.get("r")), - g=str(color.get("g")), - b=str(color.get("b")), - ) - else: - e = Element( - f"{{{self.NS_VIZ}}}color", - r=str(color.get("r")), - g=str(color.get("g")), - b=str(color.get("b")), - a=str(color.get("a", 1.0)), - ) - element.append(e) - - size = viz.get("size") - if size is not None: - e = Element(f"{{{self.NS_VIZ}}}size", value=str(size)) - element.append(e) - - thickness = viz.get("thickness") - if thickness is not None: - e = Element(f"{{{self.NS_VIZ}}}thickness", value=str(thickness)) - element.append(e) - - shape = viz.get("shape") - if shape is not None: - if shape.startswith("http"): - e = Element( - f"{{{self.NS_VIZ}}}shape", value="image", uri=str(shape) - ) - else: - e = Element(f"{{{self.NS_VIZ}}}shape", value=str(shape)) - element.append(e) - - position = viz.get("position") - if position is not None: - e = Element( - f"{{{self.NS_VIZ}}}position", - x=str(position.get("x")), - y=str(position.get("y")), - z=str(position.get("z")), - ) - element.append(e) - return node_data - - def add_parents(self, node_element, node_data): - parents = node_data.pop("parents", False) - if parents: - parents_element = Element("parents") - for p in parents: - e = Element("parent") - e.attrib["for"] = str(p) - parents_element.append(e) - node_element.append(parents_element) - return node_data - - def add_slices(self, node_or_edge_element, node_or_edge_data): - slices = node_or_edge_data.pop("slices", False) - if slices: - slices_element = Element("slices") - for start, end in slices: - e = Element("slice", start=str(start), end=str(end)) - slices_element.append(e) - node_or_edge_element.append(slices_element) - return node_or_edge_data - - def add_spells(self, node_or_edge_element, node_or_edge_data): - spells = node_or_edge_data.pop("spells", False) - if spells: - spells_element = Element("spells") - for start, end in spells: - e = Element("spell") - if start is not None: - e.attrib["start"] = str(start) - self.alter_graph_mode_timeformat(start) - if end is not None: - e.attrib["end"] = str(end) - self.alter_graph_mode_timeformat(end) - spells_element.append(e) - node_or_edge_element.append(spells_element) - return node_or_edge_data - - def alter_graph_mode_timeformat(self, start_or_end): - # If 'start' or 'end' appears, alter Graph mode to dynamic and - # set timeformat - if self.graph_element.get("mode") == "static": - if start_or_end is not None: - if isinstance(start_or_end, str): - timeformat = "date" - elif isinstance(start_or_end, float): - timeformat = "double" - elif isinstance(start_or_end, int): - timeformat = "long" - else: - raise nx.NetworkXError( - "timeformat should be of the type int, float or str" - ) - self.graph_element.set("timeformat", timeformat) - self.graph_element.set("mode", "dynamic") - - def write(self, fh): - # Serialize graph G in GEXF to the open fh - if self.prettyprint: - self.indent(self.xml) - document = ElementTree(self.xml) - document.write(fh, encoding=self.encoding, xml_declaration=True) - - def indent(self, elem, level=0): - # in-place prettyprint formatter - i = "\n" + " " * level - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - self.indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -class GEXFReader(GEXF): - # Class to read GEXF format files - # use read_gexf() function - def __init__(self, node_type=None, version="1.2draft"): - self.construct_types() - self.node_type = node_type - # assume simple graph and test for multigraph on read - self.simple_graph = True - self.set_version(version) - - def __call__(self, stream): - self.xml = ElementTree(file=stream) - g = self.xml.find(f"{{{self.NS_GEXF}}}graph") - if g is not None: - return self.make_graph(g) - # try all the versions - for version in self.versions: - self.set_version(version) - g = self.xml.find(f"{{{self.NS_GEXF}}}graph") - if g is not None: - return self.make_graph(g) - raise nx.NetworkXError("No element in GEXF file.") - - def make_graph(self, graph_xml): - # start with empty DiGraph or MultiDiGraph - edgedefault = graph_xml.get("defaultedgetype", None) - if edgedefault == "directed": - G = nx.MultiDiGraph() - else: - G = nx.MultiGraph() - - # graph attributes - graph_name = graph_xml.get("name", "") - if graph_name != "": - G.graph["name"] = graph_name - graph_start = graph_xml.get("start") - if graph_start is not None: - G.graph["start"] = graph_start - graph_end = graph_xml.get("end") - if graph_end is not None: - G.graph["end"] = graph_end - graph_mode = graph_xml.get("mode", "") - if graph_mode == "dynamic": - G.graph["mode"] = "dynamic" - else: - G.graph["mode"] = "static" - - # timeformat - self.timeformat = graph_xml.get("timeformat") - if self.timeformat == "date": - self.timeformat = "string" - - # node and edge attributes - attributes_elements = graph_xml.findall(f"{{{self.NS_GEXF}}}attributes") - # dictionaries to hold attributes and attribute defaults - node_attr = {} - node_default = {} - edge_attr = {} - edge_default = {} - for a in attributes_elements: - attr_class = a.get("class") - if attr_class == "node": - na, nd = self.find_gexf_attributes(a) - node_attr.update(na) - node_default.update(nd) - G.graph["node_default"] = node_default - elif attr_class == "edge": - ea, ed = self.find_gexf_attributes(a) - edge_attr.update(ea) - edge_default.update(ed) - G.graph["edge_default"] = edge_default - else: - raise # unknown attribute class - - # Hack to handle Gephi0.7beta bug - # add weight attribute - ea = {"weight": {"type": "double", "mode": "static", "title": "weight"}} - ed = {} - edge_attr.update(ea) - edge_default.update(ed) - G.graph["edge_default"] = edge_default - - # add nodes - nodes_element = graph_xml.find(f"{{{self.NS_GEXF}}}nodes") - if nodes_element is not None: - for node_xml in nodes_element.findall(f"{{{self.NS_GEXF}}}node"): - self.add_node(G, node_xml, node_attr) - - # add edges - edges_element = graph_xml.find(f"{{{self.NS_GEXF}}}edges") - if edges_element is not None: - for edge_xml in edges_element.findall(f"{{{self.NS_GEXF}}}edge"): - self.add_edge(G, edge_xml, edge_attr) - - # switch to Graph or DiGraph if no parallel edges were found. - if self.simple_graph: - if G.is_directed(): - G = nx.DiGraph(G) - else: - G = nx.Graph(G) - return G - - def add_node(self, G, node_xml, node_attr, node_pid=None): - # add a single node with attributes to the graph - - # get attributes and subattributues for node - data = self.decode_attr_elements(node_attr, node_xml) - data = self.add_parents(data, node_xml) # add any parents - if self.VERSION == "1.1": - data = self.add_slices(data, node_xml) # add slices - else: - data = self.add_spells(data, node_xml) # add spells - data = self.add_viz(data, node_xml) # add viz - data = self.add_start_end(data, node_xml) # add start/end - - # find the node id and cast it to the appropriate type - node_id = node_xml.get("id") - if self.node_type is not None: - node_id = self.node_type(node_id) - - # every node should have a label - node_label = node_xml.get("label") - data["label"] = node_label - - # parent node id - node_pid = node_xml.get("pid", node_pid) - if node_pid is not None: - data["pid"] = node_pid - - # check for subnodes, recursive - subnodes = node_xml.find(f"{{{self.NS_GEXF}}}nodes") - if subnodes is not None: - for node_xml in subnodes.findall(f"{{{self.NS_GEXF}}}node"): - self.add_node(G, node_xml, node_attr, node_pid=node_id) - - G.add_node(node_id, **data) - - def add_start_end(self, data, xml): - # start and end times - ttype = self.timeformat - node_start = xml.get("start") - if node_start is not None: - data["start"] = self.python_type[ttype](node_start) - node_end = xml.get("end") - if node_end is not None: - data["end"] = self.python_type[ttype](node_end) - return data - - def add_viz(self, data, node_xml): - # add viz element for node - viz = {} - color = node_xml.find(f"{{{self.NS_VIZ}}}color") - if color is not None: - if self.VERSION == "1.1": - viz["color"] = { - "r": int(color.get("r")), - "g": int(color.get("g")), - "b": int(color.get("b")), - } - else: - viz["color"] = { - "r": int(color.get("r")), - "g": int(color.get("g")), - "b": int(color.get("b")), - "a": float(color.get("a", 1)), - } - - size = node_xml.find(f"{{{self.NS_VIZ}}}size") - if size is not None: - viz["size"] = float(size.get("value")) - - thickness = node_xml.find(f"{{{self.NS_VIZ}}}thickness") - if thickness is not None: - viz["thickness"] = float(thickness.get("value")) - - shape = node_xml.find(f"{{{self.NS_VIZ}}}shape") - if shape is not None: - viz["shape"] = shape.get("shape") - if viz["shape"] == "image": - viz["shape"] = shape.get("uri") - - position = node_xml.find(f"{{{self.NS_VIZ}}}position") - if position is not None: - viz["position"] = { - "x": float(position.get("x", 0)), - "y": float(position.get("y", 0)), - "z": float(position.get("z", 0)), - } - - if len(viz) > 0: - data["viz"] = viz - return data - - def add_parents(self, data, node_xml): - parents_element = node_xml.find(f"{{{self.NS_GEXF}}}parents") - if parents_element is not None: - data["parents"] = [] - for p in parents_element.findall(f"{{{self.NS_GEXF}}}parent"): - parent = p.get("for") - data["parents"].append(parent) - return data - - def add_slices(self, data, node_or_edge_xml): - slices_element = node_or_edge_xml.find(f"{{{self.NS_GEXF}}}slices") - if slices_element is not None: - data["slices"] = [] - for s in slices_element.findall(f"{{{self.NS_GEXF}}}slice"): - start = s.get("start") - end = s.get("end") - data["slices"].append((start, end)) - return data - - def add_spells(self, data, node_or_edge_xml): - spells_element = node_or_edge_xml.find(f"{{{self.NS_GEXF}}}spells") - if spells_element is not None: - data["spells"] = [] - ttype = self.timeformat - for s in spells_element.findall(f"{{{self.NS_GEXF}}}spell"): - start = self.python_type[ttype](s.get("start")) - end = self.python_type[ttype](s.get("end")) - data["spells"].append((start, end)) - return data - - def add_edge(self, G, edge_element, edge_attr): - # add an edge to the graph - - # raise error if we find mixed directed and undirected edges - edge_direction = edge_element.get("type") - if G.is_directed() and edge_direction == "undirected": - raise nx.NetworkXError("Undirected edge found in directed graph.") - if (not G.is_directed()) and edge_direction == "directed": - raise nx.NetworkXError("Directed edge found in undirected graph.") - - # Get source and target and recast type if required - source = edge_element.get("source") - target = edge_element.get("target") - if self.node_type is not None: - source = self.node_type(source) - target = self.node_type(target) - - data = self.decode_attr_elements(edge_attr, edge_element) - data = self.add_start_end(data, edge_element) - - if self.VERSION == "1.1": - data = self.add_slices(data, edge_element) # add slices - else: - data = self.add_spells(data, edge_element) # add spells - - # GEXF stores edge ids as an attribute - # NetworkX uses them as keys in multigraphs - # if networkx_key is not specified as an attribute - edge_id = edge_element.get("id") - if edge_id is not None: - data["id"] = edge_id - - # check if there is a 'multigraph_key' and use that as edge_id - multigraph_key = data.pop("networkx_key", None) - if multigraph_key is not None: - edge_id = multigraph_key - - weight = edge_element.get("weight") - if weight is not None: - data["weight"] = float(weight) - - edge_label = edge_element.get("label") - if edge_label is not None: - data["label"] = edge_label - - if G.has_edge(source, target): - # seen this edge before - this is a multigraph - self.simple_graph = False - G.add_edge(source, target, key=edge_id, **data) - if edge_direction == "mutual": - G.add_edge(target, source, key=edge_id, **data) - - def decode_attr_elements(self, gexf_keys, obj_xml): - # Use the key information to decode the attr XML - attr = {} - # look for outer '' element - attr_element = obj_xml.find(f"{{{self.NS_GEXF}}}attvalues") - if attr_element is not None: - # loop over elements - for a in attr_element.findall(f"{{{self.NS_GEXF}}}attvalue"): - key = a.get("for") # for is required - try: # should be in our gexf_keys dictionary - title = gexf_keys[key]["title"] - except KeyError as err: - raise nx.NetworkXError(f"No attribute defined for={key}.") from err - atype = gexf_keys[key]["type"] - value = a.get("value") - if atype == "boolean": - value = self.convert_bool[value] - else: - value = self.python_type[atype](value) - if gexf_keys[key]["mode"] == "dynamic": - # for dynamic graphs use list of three-tuples - # [(value1,start1,end1), (value2,start2,end2), etc] - ttype = self.timeformat - start = self.python_type[ttype](a.get("start")) - end = self.python_type[ttype](a.get("end")) - if title in attr: - attr[title].append((value, start, end)) - else: - attr[title] = [(value, start, end)] - else: - # for static graphs just assign the value - attr[title] = value - return attr - - def find_gexf_attributes(self, attributes_element): - # Extract all the attributes and defaults - attrs = {} - defaults = {} - mode = attributes_element.get("mode") - for k in attributes_element.findall(f"{{{self.NS_GEXF}}}attribute"): - attr_id = k.get("id") - title = k.get("title") - atype = k.get("type") - attrs[attr_id] = {"title": title, "type": atype, "mode": mode} - # check for the 'default' subelement of key element and add - default = k.find(f"{{{self.NS_GEXF}}}default") - if default is not None: - if atype == "boolean": - value = self.convert_bool[default.text] - else: - value = self.python_type[atype](default.text) - defaults[title] = value - return attrs, defaults - - -def relabel_gexf_graph(G): - """Relabel graph using "label" node keyword for node label. - - Parameters - ---------- - G : graph - A NetworkX graph read from GEXF data - - Returns - ------- - H : graph - A NetworkX graph with relabeled nodes - - Raises - ------ - NetworkXError - If node labels are missing or not unique while relabel=True. - - Notes - ----- - This function relabels the nodes in a NetworkX graph with the - "label" attribute. It also handles relabeling the specific GEXF - node attributes "parents", and "pid". - """ - # build mapping of node labels, do some error checking - try: - mapping = [(u, G.nodes[u]["label"]) for u in G] - except KeyError as err: - raise nx.NetworkXError( - "Failed to relabel nodes: missing node labels found. Use relabel=False." - ) from err - x, y = zip(*mapping) - if len(set(y)) != len(G): - raise nx.NetworkXError( - "Failed to relabel nodes: " - "duplicate node labels found. " - "Use relabel=False." - ) - mapping = dict(mapping) - H = nx.relabel_nodes(G, mapping) - # relabel attributes - for n in G: - m = mapping[n] - H.nodes[m]["id"] = n - H.nodes[m].pop("label") - if "pid" in H.nodes[m]: - H.nodes[m]["pid"] = mapping[G.nodes[n]["pid"]] - if "parents" in H.nodes[m]: - H.nodes[m]["parents"] = [mapping[p] for p in G.nodes[n]["parents"]] - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gml.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gml.py deleted file mode 100644 index 891d709..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/gml.py +++ /dev/null @@ -1,879 +0,0 @@ -""" -Read graphs in GML format. - -"GML, the Graph Modelling Language, is our proposal for a portable -file format for graphs. GML's key features are portability, simple -syntax, extensibility and flexibility. A GML file consists of a -hierarchical key-value lists. Graphs can be annotated with arbitrary -data structures. The idea for a common file format was born at the -GD'95; this proposal is the outcome of many discussions. GML is the -standard file format in the Graphlet graph editor system. It has been -overtaken and adapted by several other systems for drawing graphs." - -GML files are stored using a 7-bit ASCII encoding with any extended -ASCII characters (iso8859-1) appearing as HTML character entities. -You will need to give some thought into how the exported data should -interact with different languages and even different Python versions. -Re-importing from gml is also a concern. - -Without specifying a `stringizer`/`destringizer`, the code is capable of -writing `int`/`float`/`str`/`dict`/`list` data as required by the GML -specification. For writing other data types, and for reading data other -than `str` you need to explicitly supply a `stringizer`/`destringizer`. - -For additional documentation on the GML file format, please see the -`GML website `_. - -Several example graphs in GML format may be found on Mark Newman's -`Network data page `_. -""" - -import html.entities as htmlentitydefs -import re -import warnings -from ast import literal_eval -from collections import defaultdict -from enum import Enum -from io import StringIO -from typing import Any, NamedTuple - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file - -__all__ = ["read_gml", "parse_gml", "generate_gml", "write_gml"] - - -def escape(text): - """Use XML character references to escape characters. - - Use XML character references for unprintable or non-ASCII - characters, double quotes and ampersands in a string - """ - - def fixup(m): - ch = m.group(0) - return "&#" + str(ord(ch)) + ";" - - text = re.sub('[^ -~]|[&"]', fixup, text) - return text if isinstance(text, str) else str(text) - - -def unescape(text): - """Replace XML character references with the referenced characters""" - - def fixup(m): - text = m.group(0) - if text[1] == "#": - # Character reference - if text[2] == "x": - code = int(text[3:-1], 16) - else: - code = int(text[2:-1]) - else: - # Named entity - try: - code = htmlentitydefs.name2codepoint[text[1:-1]] - except KeyError: - return text # leave unchanged - try: - return chr(code) - except (ValueError, OverflowError): - return text # leave unchanged - - return re.sub("&(?:[0-9A-Za-z]+|#(?:[0-9]+|x[0-9A-Fa-f]+));", fixup, text) - - -def literal_destringizer(rep): - """Convert a Python literal to the value it represents. - - Parameters - ---------- - rep : string - A Python literal. - - Returns - ------- - value : object - The value of the Python literal. - - Raises - ------ - ValueError - If `rep` is not a Python literal. - """ - if isinstance(rep, str): - orig_rep = rep - try: - return literal_eval(rep) - except SyntaxError as err: - raise ValueError(f"{orig_rep!r} is not a valid Python literal") from err - else: - raise ValueError(f"{rep!r} is not a string") - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_gml(path, label="label", destringizer=None): - """Read graph in GML format from `path`. - - Parameters - ---------- - path : filename or filehandle - The filename or filehandle to read from. - - label : string, optional - If not None, the parsed nodes will be renamed according to node - attributes indicated by `label`. Default value: 'label'. - - destringizer : callable, optional - A `destringizer` that recovers values stored as strings in GML. If it - cannot convert a string to a value, a `ValueError` is raised. Default - value : None. - - Returns - ------- - G : NetworkX graph - The parsed graph. - - Raises - ------ - NetworkXError - If the input cannot be parsed. - - See Also - -------- - write_gml, parse_gml - literal_destringizer - - Notes - ----- - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - writing `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For writing other data types, and for reading data other - than `str` you need to explicitly supply a `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gml(G, "test.gml") - - GML values are interpreted as strings by default: - - >>> H = nx.read_gml("test.gml") - >>> H.nodes - NodeView(('0', '1', '2', '3')) - - When a `destringizer` is provided, GML values are converted to the provided type. - For example, integer nodes can be recovered as shown below: - - >>> J = nx.read_gml("test.gml", destringizer=int) - >>> J.nodes - NodeView((0, 1, 2, 3)) - - """ - - def filter_lines(lines): - for line in lines: - try: - line = line.decode("ascii") - except UnicodeDecodeError as err: - raise NetworkXError("input is not ASCII-encoded") from err - if not isinstance(line, str): - lines = str(lines) - if line and line[-1] == "\n": - line = line[:-1] - yield line - - G = parse_gml_lines(filter_lines(path), label, destringizer) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_gml(lines, label="label", destringizer=None): - """Parse GML graph from a string or iterable. - - Parameters - ---------- - lines : string or iterable of strings - Data in GML format. - - label : string, optional - If not None, the parsed nodes will be renamed according to node - attributes indicated by `label`. Default value: 'label'. - - destringizer : callable, optional - A `destringizer` that recovers values stored as strings in GML. If it - cannot convert a string to a value, a `ValueError` is raised. Default - value : None. - - Returns - ------- - G : NetworkX graph - The parsed graph. - - Raises - ------ - NetworkXError - If the input cannot be parsed. - - See Also - -------- - write_gml, read_gml - - Notes - ----- - This stores nested GML attributes as dictionaries in the NetworkX graph, - node, and edge attribute structures. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - writing `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For writing other data types, and for reading data other - than `str` you need to explicitly supply a `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - """ - - def decode_line(line): - if isinstance(line, bytes): - try: - line.decode("ascii") - except UnicodeDecodeError as err: - raise NetworkXError("input is not ASCII-encoded") from err - if not isinstance(line, str): - line = str(line) - return line - - def filter_lines(lines): - if isinstance(lines, str): - lines = decode_line(lines) - lines = lines.splitlines() - yield from lines - else: - for line in lines: - line = decode_line(line) - if line and line[-1] == "\n": - line = line[:-1] - if line.find("\n") != -1: - raise NetworkXError("input line contains newline") - yield line - - G = parse_gml_lines(filter_lines(lines), label, destringizer) - return G - - -class Pattern(Enum): - """encodes the index of each token-matching pattern in `tokenize`.""" - - KEYS = 0 - REALS = 1 - INTS = 2 - STRINGS = 3 - DICT_START = 4 - DICT_END = 5 - COMMENT_WHITESPACE = 6 - - -class Token(NamedTuple): - category: Pattern - value: Any - line: int - position: int - - -LIST_START_VALUE = "_networkx_list_start" - - -def parse_gml_lines(lines, label, destringizer): - """Parse GML `lines` into a graph.""" - - def tokenize(): - patterns = [ - r"[A-Za-z][0-9A-Za-z_]*\b", # keys - # reals - r"[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.[0-9]*|INF)(?:[Ee][+-]?[0-9]+)?", - r"[+-]?[0-9]+", # ints - r'".*?"', # strings - r"\[", # dict start - r"\]", # dict end - r"#.*$|\s+", # comments and whitespaces - ] - tokens = re.compile("|".join(f"({pattern})" for pattern in patterns)) - lineno = 0 - multilines = [] # entries spread across multiple lines - for line in lines: - pos = 0 - - # deal with entries spread across multiple lines - # - # should we actually have to deal with escaped "s then do it here - if multilines: - multilines.append(line.strip()) - if line[-1] == '"': # closing multiline entry - # multiline entries will be joined by space. cannot - # reintroduce newlines as this will break the tokenizer - line = " ".join(multilines) - multilines = [] - else: # continued multiline entry - lineno += 1 - continue - else: - if line.count('"') == 1: # opening multiline entry - if line.strip()[0] != '"' and line.strip()[-1] != '"': - # since we expect something like key "value", the " should not be found at ends - # otherwise tokenizer will pick up the formatting mistake. - multilines = [line.rstrip()] - lineno += 1 - continue - - length = len(line) - - while pos < length: - match = tokens.match(line, pos) - if match is None: - m = f"cannot tokenize {line[pos:]} at ({lineno + 1}, {pos + 1})" - raise NetworkXError(m) - for i in range(len(patterns)): - group = match.group(i + 1) - if group is not None: - if i == 0: # keys - value = group.rstrip() - elif i == 1: # reals - value = float(group) - elif i == 2: # ints - value = int(group) - else: - value = group - if i != 6: # comments and whitespaces - yield Token(Pattern(i), value, lineno + 1, pos + 1) - pos += len(group) - break - lineno += 1 - yield Token(None, None, lineno + 1, 1) # EOF - - def unexpected(curr_token, expected): - category, value, lineno, pos = curr_token - value = repr(value) if value is not None else "EOF" - raise NetworkXError(f"expected {expected}, found {value} at ({lineno}, {pos})") - - def consume(curr_token, category, expected): - if curr_token.category == category: - return next(tokens) - unexpected(curr_token, expected) - - def parse_kv(curr_token): - dct = defaultdict(list) - while curr_token.category == Pattern.KEYS: - key = curr_token.value - curr_token = next(tokens) - category = curr_token.category - if category == Pattern.REALS or category == Pattern.INTS: - value = curr_token.value - curr_token = next(tokens) - elif category == Pattern.STRINGS: - value = unescape(curr_token.value[1:-1]) - if destringizer: - try: - value = destringizer(value) - except ValueError: - pass - # Special handling for empty lists and tuples - if value == "()": - value = () - if value == "[]": - value = [] - curr_token = next(tokens) - elif category == Pattern.DICT_START: - curr_token, value = parse_dict(curr_token) - else: - # Allow for string convertible id and label values - if key in ("id", "label", "source", "target"): - try: - # String convert the token value - value = unescape(str(curr_token.value)) - if destringizer: - try: - value = destringizer(value) - except ValueError: - pass - curr_token = next(tokens) - except Exception: - msg = ( - "an int, float, string, '[' or string" - + " convertible ASCII value for node id or label" - ) - unexpected(curr_token, msg) - # Special handling for nan and infinity. Since the gml language - # defines unquoted strings as keys, the numeric and string branches - # are skipped and we end up in this special branch, so we need to - # convert the current token value to a float for NAN and plain INF. - # +/-INF are handled in the pattern for 'reals' in tokenize(). This - # allows labels and values to be nan or infinity, but not keys. - elif curr_token.value in {"NAN", "INF"}: - value = float(curr_token.value) - curr_token = next(tokens) - else: # Otherwise error out - unexpected(curr_token, "an int, float, string or '['") - dct[key].append(value) - - def clean_dict_value(value): - if not isinstance(value, list): - return value - if len(value) == 1: - return value[0] - if value[0] == LIST_START_VALUE: - return value[1:] - return value - - dct = {key: clean_dict_value(value) for key, value in dct.items()} - return curr_token, dct - - def parse_dict(curr_token): - # dict start - curr_token = consume(curr_token, Pattern.DICT_START, "'['") - # dict contents - curr_token, dct = parse_kv(curr_token) - # dict end - curr_token = consume(curr_token, Pattern.DICT_END, "']'") - return curr_token, dct - - def parse_graph(): - curr_token, dct = parse_kv(next(tokens)) - if curr_token.category is not None: # EOF - unexpected(curr_token, "EOF") - if "graph" not in dct: - raise NetworkXError("input contains no graph") - graph = dct["graph"] - if isinstance(graph, list): - raise NetworkXError("input contains more than one graph") - return graph - - tokens = tokenize() - graph = parse_graph() - - directed = graph.pop("directed", False) - multigraph = graph.pop("multigraph", False) - if not multigraph: - G = nx.DiGraph() if directed else nx.Graph() - else: - G = nx.MultiDiGraph() if directed else nx.MultiGraph() - graph_attr = {k: v for k, v in graph.items() if k not in ("node", "edge")} - G.graph.update(graph_attr) - - def pop_attr(dct, category, attr, i): - try: - return dct.pop(attr) - except KeyError as err: - raise NetworkXError(f"{category} #{i} has no {attr!r} attribute") from err - - nodes = graph.get("node", []) - mapping = {} - node_labels = set() - for i, node in enumerate(nodes if isinstance(nodes, list) else [nodes]): - id = pop_attr(node, "node", "id", i) - if id in G: - raise NetworkXError(f"node id {id!r} is duplicated") - if label is not None and label != "id": - node_label = pop_attr(node, "node", label, i) - if node_label in node_labels: - raise NetworkXError(f"node label {node_label!r} is duplicated") - node_labels.add(node_label) - mapping[id] = node_label - G.add_node(id, **node) - - edges = graph.get("edge", []) - for i, edge in enumerate(edges if isinstance(edges, list) else [edges]): - source = pop_attr(edge, "edge", "source", i) - target = pop_attr(edge, "edge", "target", i) - if source not in G: - raise NetworkXError(f"edge #{i} has undefined source {source!r}") - if target not in G: - raise NetworkXError(f"edge #{i} has undefined target {target!r}") - if not multigraph: - if not G.has_edge(source, target): - G.add_edge(source, target, **edge) - else: - arrow = "->" if directed else "--" - msg = f"edge #{i} ({source!r}{arrow}{target!r}) is duplicated" - raise nx.NetworkXError(msg) - else: - key = edge.pop("key", None) - if key is not None and G.has_edge(source, target, key): - arrow = "->" if directed else "--" - msg = f"edge #{i} ({source!r}{arrow}{target!r}, {key!r})" - msg2 = 'Hint: If multigraph add "multigraph 1" to file header.' - raise nx.NetworkXError(msg + " is duplicated\n" + msg2) - G.add_edge(source, target, key, **edge) - - if label is not None and label != "id": - G = nx.relabel_nodes(G, mapping) - return G - - -def literal_stringizer(value): - """Convert a `value` to a Python literal in GML representation. - - Parameters - ---------- - value : object - The `value` to be converted to GML representation. - - Returns - ------- - rep : string - A double-quoted Python literal representing value. Unprintable - characters are replaced by XML character references. - - Raises - ------ - ValueError - If `value` cannot be converted to GML. - - Notes - ----- - The original value can be recovered using the - :func:`networkx.readwrite.gml.literal_destringizer` function. - """ - - def stringize(value): - if isinstance(value, int | bool) or value is None: - if value is True: # GML uses 1/0 for boolean values. - buf.write(str(1)) - elif value is False: - buf.write(str(0)) - else: - buf.write(str(value)) - elif isinstance(value, str): - text = repr(value) - if text[0] != "u": - try: - value.encode("latin1") - except UnicodeEncodeError: - text = "u" + text - buf.write(text) - elif isinstance(value, float | complex | str | bytes): - buf.write(repr(value)) - elif isinstance(value, list): - buf.write("[") - first = True - for item in value: - if not first: - buf.write(",") - else: - first = False - stringize(item) - buf.write("]") - elif isinstance(value, tuple): - if len(value) > 1: - buf.write("(") - first = True - for item in value: - if not first: - buf.write(",") - else: - first = False - stringize(item) - buf.write(")") - elif value: - buf.write("(") - stringize(value[0]) - buf.write(",)") - else: - buf.write("()") - elif isinstance(value, dict): - buf.write("{") - first = True - for key, value in value.items(): - if not first: - buf.write(",") - else: - first = False - stringize(key) - buf.write(":") - stringize(value) - buf.write("}") - elif isinstance(value, set): - buf.write("{") - first = True - for item in value: - if not first: - buf.write(",") - else: - first = False - stringize(item) - buf.write("}") - else: - msg = f"{value!r} cannot be converted into a Python literal" - raise ValueError(msg) - - buf = StringIO() - stringize(value) - return buf.getvalue() - - -def generate_gml(G, stringizer=None): - r"""Generate a single entry of the graph `G` in GML format. - - Parameters - ---------- - G : NetworkX graph - The graph to be converted to GML. - - stringizer : callable, optional - A `stringizer` which converts non-int/non-float/non-dict values into - strings. If it cannot convert a value into a string, it should raise a - `ValueError` to indicate that. Default value: None. - - Returns - ------- - lines: generator of strings - Lines of GML data. Newlines are not appended. - - Raises - ------ - NetworkXError - If `stringizer` cannot convert a value into a string, or the value to - convert is not a string while `stringizer` is None. - - See Also - -------- - literal_stringizer - - Notes - ----- - Graph attributes named 'directed', 'multigraph', 'node' or - 'edge', node attributes named 'id' or 'label', edge attributes - named 'source' or 'target' (or 'key' if `G` is a multigraph) - are ignored because these attribute names are used to encode the graph - structure. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - writing `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For writing other data types, and for reading data other - than `str` you need to explicitly supply a `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_node("1") - >>> print("\n".join(nx.generate_gml(G))) - graph [ - node [ - id 0 - label "1" - ] - ] - >>> G = nx.MultiGraph([("a", "b"), ("a", "b")]) - >>> print("\n".join(nx.generate_gml(G))) - graph [ - multigraph 1 - node [ - id 0 - label "a" - ] - node [ - id 1 - label "b" - ] - edge [ - source 0 - target 1 - key 0 - ] - edge [ - source 0 - target 1 - key 1 - ] - ] - """ - valid_keys = re.compile("^[A-Za-z][0-9A-Za-z_]*$") - - def stringize(key, value, ignored_keys, indent, in_list=False): - if not isinstance(key, str): - raise NetworkXError(f"{key!r} is not a string") - if not valid_keys.match(key): - raise NetworkXError(f"{key!r} is not a valid key") - if not isinstance(key, str): - key = str(key) - if key not in ignored_keys: - if isinstance(value, int | bool): - if key == "label": - yield indent + key + ' "' + str(value) + '"' - elif value is True: - # python bool is an instance of int - yield indent + key + " 1" - elif value is False: - yield indent + key + " 0" - # GML only supports signed 32-bit integers - elif value < -(2**31) or value >= 2**31: - yield indent + key + ' "' + str(value) + '"' - else: - yield indent + key + " " + str(value) - elif isinstance(value, float): - text = repr(value).upper() - # GML matches INF to keys, so prepend + to INF. Use repr(float(*)) - # instead of string literal to future proof against changes to repr. - if text == repr(float("inf")).upper(): - text = "+" + text - else: - # GML requires that a real literal contain a decimal point, but - # repr may not output a decimal point when the mantissa is - # integral and hence needs fixing. - epos = text.rfind("E") - if epos != -1 and text.find(".", 0, epos) == -1: - text = text[:epos] + "." + text[epos:] - if key == "label": - yield indent + key + ' "' + text + '"' - else: - yield indent + key + " " + text - elif isinstance(value, dict): - yield indent + key + " [" - next_indent = indent + " " - for key, value in value.items(): - yield from stringize(key, value, (), next_indent) - yield indent + "]" - elif isinstance(value, tuple) and key == "label": - yield indent + key + f" \"({','.join(repr(v) for v in value)})\"" - elif isinstance(value, list | tuple) and key != "label" and not in_list: - if len(value) == 0: - yield indent + key + " " + f'"{value!r}"' - if len(value) == 1: - yield indent + key + " " + f'"{LIST_START_VALUE}"' - for val in value: - yield from stringize(key, val, (), indent, True) - else: - if stringizer: - try: - value = stringizer(value) - except ValueError as err: - raise NetworkXError( - f"{value!r} cannot be converted into a string" - ) from err - if not isinstance(value, str): - raise NetworkXError(f"{value!r} is not a string") - yield indent + key + ' "' + escape(value) + '"' - - multigraph = G.is_multigraph() - yield "graph [" - - # Output graph attributes - if G.is_directed(): - yield " directed 1" - if multigraph: - yield " multigraph 1" - ignored_keys = {"directed", "multigraph", "node", "edge"} - for attr, value in G.graph.items(): - yield from stringize(attr, value, ignored_keys, " ") - - # Output node data - node_id = dict(zip(G, range(len(G)))) - ignored_keys = {"id", "label"} - for node, attrs in G.nodes.items(): - yield " node [" - yield " id " + str(node_id[node]) - yield from stringize("label", node, (), " ") - for attr, value in attrs.items(): - yield from stringize(attr, value, ignored_keys, " ") - yield " ]" - - # Output edge data - ignored_keys = {"source", "target"} - kwargs = {"data": True} - if multigraph: - ignored_keys.add("key") - kwargs["keys"] = True - for e in G.edges(**kwargs): - yield " edge [" - yield " source " + str(node_id[e[0]]) - yield " target " + str(node_id[e[1]]) - if multigraph: - yield from stringize("key", e[2], (), " ") - for attr, value in e[-1].items(): - yield from stringize(attr, value, ignored_keys, " ") - yield " ]" - yield "]" - - -@open_file(1, mode="wb") -def write_gml(G, path, stringizer=None): - """Write a graph `G` in GML format to the file or file handle `path`. - - Parameters - ---------- - G : NetworkX graph - The graph to be converted to GML. - - path : filename or filehandle - The filename or filehandle to write. Files whose names end with .gz or - .bz2 will be compressed. - - stringizer : callable, optional - A `stringizer` which converts non-int/non-float/non-dict values into - strings. If it cannot convert a value into a string, it should raise a - `ValueError` to indicate that. Default value: None. - - Raises - ------ - NetworkXError - If `stringizer` cannot convert a value into a string, or the value to - convert is not a string while `stringizer` is None. - - See Also - -------- - read_gml, generate_gml - literal_stringizer - - Notes - ----- - Graph attributes named 'directed', 'multigraph', 'node' or - 'edge', node attributes named 'id' or 'label', edge attributes - named 'source' or 'target' (or 'key' if `G` is a multigraph) - are ignored because these attribute names are used to encode the graph - structure. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - writing `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For writing other data types, and for reading data other - than `str` you need to explicitly supply a `stringizer`/`destringizer`. - - Note that while we allow non-standard GML to be read from a file, we make - sure to write GML format. In particular, underscores are not allowed in - attribute names. - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gml(G, "test.gml") - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_gml(G, "test.gml.gz") - """ - for line in generate_gml(G, stringizer): - path.write((line + "\n").encode("ascii")) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graph6.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graph6.py deleted file mode 100644 index 4ff2f93..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graph6.py +++ /dev/null @@ -1,417 +0,0 @@ -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain. -"""Functions for reading and writing graphs in the *graph6* format. - -The *graph6* file format is suitable for small graphs or large dense -graphs. For large sparse graphs, use the *sparse6* format. - -For more information, see the `graph6`_ homepage. - -.. _graph6: http://users.cecs.anu.edu.au/~bdm/data/formats.html - -""" - -from itertools import islice - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for, open_file - -__all__ = ["from_graph6_bytes", "read_graph6", "to_graph6_bytes", "write_graph6"] - - -def _generate_graph6_bytes(G, nodes, header): - """Yield bytes in the graph6 encoding of a graph. - - `G` is an undirected simple graph. `nodes` is the list of nodes for - which the node-induced subgraph will be encoded; if `nodes` is the - list of all nodes in the graph, the entire graph will be - encoded. `header` is a Boolean that specifies whether to generate - the header ``b'>>graph6<<'`` before the remaining data. - - This function generates `bytes` objects in the following order: - - 1. the header (if requested), - 2. the encoding of the number of nodes, - 3. each character, one-at-a-time, in the encoding of the requested - node-induced subgraph, - 4. a newline character. - - This function raises :exc:`ValueError` if the graph is too large for - the graph6 format (that is, greater than ``2 ** 36`` nodes). - - """ - n = len(G) - if n >= 2**36: - raise ValueError( - "graph6 is only defined if number of nodes is less than 2 ** 36" - ) - if header: - yield b">>graph6<<" - for d in n_to_data(n): - yield str.encode(chr(d + 63)) - # This generates the same as `(v in G[u] for u, v in combinations(G, 2))`, - # but in "column-major" order instead of "row-major" order. - bits = (nodes[j] in G[nodes[i]] for j in range(1, n) for i in range(j)) - chunk = list(islice(bits, 6)) - while chunk: - d = sum(b << 5 - i for i, b in enumerate(chunk)) - yield str.encode(chr(d + 63)) - chunk = list(islice(bits, 6)) - yield b"\n" - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_graph6_bytes(bytes_in): - """Read a simple undirected graph in graph6 format from bytes. - - Parameters - ---------- - bytes_in : bytes - Data in graph6 format, without a trailing newline. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If bytes_in is unable to be parsed in graph6 format - - ValueError - If any character ``c`` in bytes_in does not satisfy - ``63 <= ord(c) < 127``. - - Examples - -------- - >>> G = nx.from_graph6_bytes(b"A_") - >>> sorted(G.edges()) - [(0, 1)] - - See Also - -------- - read_graph6, write_graph6 - - References - ---------- - .. [1] Graph6 specification - - - """ - - def bits(): - """Returns sequence of individual bits from 6-bit-per-value - list of data values.""" - for d in data: - for i in [5, 4, 3, 2, 1, 0]: - yield (d >> i) & 1 - - if bytes_in.startswith(b">>graph6<<"): - bytes_in = bytes_in[10:] - - data = [c - 63 for c in bytes_in] - if any(c > 63 for c in data): - raise ValueError("each input character must be in range(63, 127)") - - n, data = data_to_n(data) - nd = (n * (n - 1) // 2 + 5) // 6 - if len(data) != nd: - raise NetworkXError( - f"Expected {n * (n - 1) // 2} bits but got {len(data) * 6} in graph6" - ) - - G = nx.Graph() - G.add_nodes_from(range(n)) - for (i, j), b in zip(((i, j) for j in range(1, n) for i in range(j)), bits()): - if b: - G.add_edge(i, j) - - return G - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -def to_graph6_bytes(G, nodes=None, header=True): - """Convert a simple undirected graph to bytes in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' bytes to head of data. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - >>> nx.to_graph6_bytes(nx.path_graph(2)) - b'>>graph6< - - """ - if nodes is not None: - G = G.subgraph(nodes) - H = nx.convert_node_labels_to_integers(G) - nodes = sorted(H.nodes()) - return b"".join(_generate_graph6_bytes(H, nodes, header)) - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_graph6(path): - """Read simple undirected graphs in graph6 format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - - Returns - ------- - G : Graph or list of Graphs - If the file contains multiple lines then a list of graphs is returned - - Raises - ------ - NetworkXError - If the string is unable to be parsed in graph6 format - - Examples - -------- - You can read a graph6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile(delete=False) as f: - ... _ = f.write(b">>graph6<>> list(G.edges()) - [(0, 1)] - - You can also read a graph6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b">>graph6<>> list(G.edges()) - [(0, 1)] - - See Also - -------- - from_graph6_bytes, write_graph6 - - References - ---------- - .. [1] Graph6 specification - - - """ - glist = [] - for line in path: - line = line.strip() - if not len(line): - continue - glist.append(from_graph6_bytes(line)) - if len(glist) == 1: - return glist[0] - else: - return glist - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -@open_file(1, mode="wb") -def write_graph6(G, path, nodes=None, header=True): - """Write a simple undirected graph to a path in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - path : str - The path naming the file to which to write the graph. - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' string to head of data - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - You can write a graph6 file by giving the path to a file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile(delete=False) as f: - ... nx.write_graph6(nx.path_graph(2), f.name) - ... _ = f.seek(0) - ... print(f.read()) - b'>>graph6< - - """ - return write_graph6_file(G, path, nodes=nodes, header=header) - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -def write_graph6_file(G, f, nodes=None, header=True): - """Write a simple undirected graph to a file-like object in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - f : file-like object - The file to write. - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' string to head of data - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - You can write a graph6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_graph6(nx.path_graph(2), f) - ... _ = f.seek(0) - ... print(f.read()) - b'>>graph6< - - """ - if nodes is not None: - G = G.subgraph(nodes) - H = nx.convert_node_labels_to_integers(G) - nodes = sorted(H.nodes()) - for b in _generate_graph6_bytes(H, nodes, header): - f.write(b) - - -def data_to_n(data): - """Read initial one-, four- or eight-unit value from graph6 - integer sequence. - - Return (value, rest of seq.)""" - if data[0] <= 62: - return data[0], data[1:] - if data[1] <= 62: - return (data[1] << 12) + (data[2] << 6) + data[3], data[4:] - return ( - (data[2] << 30) - + (data[3] << 24) - + (data[4] << 18) - + (data[5] << 12) - + (data[6] << 6) - + data[7], - data[8:], - ) - - -def n_to_data(n): - """Convert an integer to one-, four- or eight-unit graph6 sequence. - - This function is undefined if `n` is not in ``range(2 ** 36)``. - - """ - if n <= 62: - return [n] - elif n <= 258047: - return [63, (n >> 12) & 0x3F, (n >> 6) & 0x3F, n & 0x3F] - else: # if n <= 68719476735: - return [ - 63, - 63, - (n >> 30) & 0x3F, - (n >> 24) & 0x3F, - (n >> 18) & 0x3F, - (n >> 12) & 0x3F, - (n >> 6) & 0x3F, - n & 0x3F, - ] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graphml.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graphml.py deleted file mode 100644 index 7d0a1da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/graphml.py +++ /dev/null @@ -1,1053 +0,0 @@ -""" -******* -GraphML -******* -Read and write graphs in GraphML format. - -.. warning:: - - This parser uses the standard xml library present in Python, which is - insecure - see :external+python:mod:`xml` for additional information. - Only parse GraphML files you trust. - -This implementation does not support mixed graphs (directed and unidirected -edges together), hyperedges, nested graphs, or ports. - -"GraphML is a comprehensive and easy-to-use file format for graphs. It -consists of a language core to describe the structural properties of a -graph and a flexible extension mechanism to add application-specific -data. Its main features include support of - - * directed, undirected, and mixed graphs, - * hypergraphs, - * hierarchical graphs, - * graphical representations, - * references to external data, - * application-specific attribute data, and - * light-weight parsers. - -Unlike many other file formats for graphs, GraphML does not use a -custom syntax. Instead, it is based on XML and hence ideally suited as -a common denominator for all kinds of services generating, archiving, -or processing graphs." - -http://graphml.graphdrawing.org/ - -Format ------- -GraphML is an XML format. See -http://graphml.graphdrawing.org/specification.html for the specification and -http://graphml.graphdrawing.org/primer/graphml-primer.html -for examples. -""" - -import warnings -from collections import defaultdict - -import networkx as nx -from networkx.utils import open_file - -__all__ = [ - "write_graphml", - "read_graphml", - "generate_graphml", - "write_graphml_xml", - "write_graphml_lxml", - "parse_graphml", - "GraphMLWriter", - "GraphMLReader", -] - - -@open_file(1, mode="wb") -def write_graphml_xml( - G, - path, - encoding="utf-8", - prettyprint=True, - infer_numeric_types=False, - named_key_ids=False, - edge_id_from_attribute=None, -): - """Write G in GraphML XML format to path - - Parameters - ---------- - G : graph - A networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - infer_numeric_types : boolean - Determine if numeric types should be generalized. - For example, if edges have both int and float 'weight' attributes, - we infer in GraphML that both are floats. - named_key_ids : bool (optional) - If True use attr.name as value for key elements' id attribute. - edge_id_from_attribute : dict key (optional) - If provided, the graphml edge id is set by looking up the corresponding - edge data attribute keyed by this parameter. If `None` or the key does not exist in edge data, - the edge id is set by the edge key if `G` is a MultiGraph, else the edge id is left unset. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_graphml(G, "test.graphml") - - Notes - ----- - This implementation does not support mixed graphs (directed - and unidirected edges together) hyperedges, nested graphs, or ports. - """ - writer = GraphMLWriter( - encoding=encoding, - prettyprint=prettyprint, - infer_numeric_types=infer_numeric_types, - named_key_ids=named_key_ids, - edge_id_from_attribute=edge_id_from_attribute, - ) - writer.add_graph_element(G) - writer.dump(path) - - -@open_file(1, mode="wb") -def write_graphml_lxml( - G, - path, - encoding="utf-8", - prettyprint=True, - infer_numeric_types=False, - named_key_ids=False, - edge_id_from_attribute=None, -): - """Write G in GraphML XML format to path - - This function uses the LXML framework and should be faster than - the version using the xml library. - - Parameters - ---------- - G : graph - A networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - infer_numeric_types : boolean - Determine if numeric types should be generalized. - For example, if edges have both int and float 'weight' attributes, - we infer in GraphML that both are floats. - named_key_ids : bool (optional) - If True use attr.name as value for key elements' id attribute. - edge_id_from_attribute : dict key (optional) - If provided, the graphml edge id is set by looking up the corresponding - edge data attribute keyed by this parameter. If `None` or the key does not exist in edge data, - the edge id is set by the edge key if `G` is a MultiGraph, else the edge id is left unset. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_graphml_lxml(G, "fourpath.graphml") - - Notes - ----- - This implementation does not support mixed graphs (directed - and unidirected edges together) hyperedges, nested graphs, or ports. - """ - try: - import lxml.etree as lxmletree - except ImportError: - return write_graphml_xml( - G, - path, - encoding, - prettyprint, - infer_numeric_types, - named_key_ids, - edge_id_from_attribute, - ) - - writer = GraphMLWriterLxml( - path, - graph=G, - encoding=encoding, - prettyprint=prettyprint, - infer_numeric_types=infer_numeric_types, - named_key_ids=named_key_ids, - edge_id_from_attribute=edge_id_from_attribute, - ) - writer.dump() - - -def generate_graphml( - G, - encoding="utf-8", - prettyprint=True, - named_key_ids=False, - edge_id_from_attribute=None, -): - """Generate GraphML lines for G - - Parameters - ---------- - G : graph - A networkx graph - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - named_key_ids : bool (optional) - If True use attr.name as value for key elements' id attribute. - edge_id_from_attribute : dict key (optional) - If provided, the graphml edge id is set by looking up the corresponding - edge data attribute keyed by this parameter. If `None` or the key does not exist in edge data, - the edge id is set by the edge key if `G` is a MultiGraph, else the edge id is left unset. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed = \n - >>> s = linefeed.join(nx.generate_graphml(G)) - >>> for line in nx.generate_graphml(G): # doctest: +SKIP - ... print(line) - - Notes - ----- - This implementation does not support mixed graphs (directed and unidirected - edges together) hyperedges, nested graphs, or ports. - """ - writer = GraphMLWriter( - encoding=encoding, - prettyprint=prettyprint, - named_key_ids=named_key_ids, - edge_id_from_attribute=edge_id_from_attribute, - ) - writer.add_graph_element(G) - yield from str(writer).splitlines() - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_graphml(path, node_type=str, edge_key_type=int, force_multigraph=False): - """Read graph in GraphML format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - node_type: Python type (default: str) - Convert node ids to this type - - edge_key_type: Python type (default: int) - Convert graphml edge ids to this type. Multigraphs use id as edge key. - Non-multigraphs add to edge attribute dict with name "id". - - force_multigraph : bool (default: False) - If True, return a multigraph with edge keys. If False (the default) - return a multigraph when multiedges are in the graph. - - Returns - ------- - graph: NetworkX graph - If parallel edges are present or `force_multigraph=True` then - a MultiGraph or MultiDiGraph is returned. Otherwise a Graph/DiGraph. - The returned graph is directed if the file indicates it should be. - - Notes - ----- - Default node and edge attributes are not propagated to each node and edge. - They can be obtained from `G.graph` and applied to node and edge attributes - if desired using something like this: - - >>> default_color = G.graph["node_default"]["color"] # doctest: +SKIP - >>> for node, data in G.nodes(data=True): # doctest: +SKIP - ... if "color" not in data: - ... data["color"] = default_color - >>> default_color = G.graph["edge_default"]["color"] # doctest: +SKIP - >>> for u, v, data in G.edges(data=True): # doctest: +SKIP - ... if "color" not in data: - ... data["color"] = default_color - - This implementation does not support mixed graphs (directed and unidirected - edges together), hypergraphs, nested graphs, or ports. - - For multigraphs the GraphML edge "id" will be used as the edge - key. If not specified then they "key" attribute will be used. If - there is no "key" attribute a default NetworkX multigraph edge key - will be provided. - - Files with the yEd "yfiles" extension can be read. The type of the node's - shape is preserved in the `shape_type` node attribute. - - yEd compressed files ("file.graphmlz" extension) can be read by renaming - the file to "file.graphml.gz". - - """ - reader = GraphMLReader(node_type, edge_key_type, force_multigraph) - # need to check for multiple graphs - glist = list(reader(path=path)) - if len(glist) == 0: - # If no graph comes back, try looking for an incomplete header - header = b'' - path.seek(0) - old_bytes = path.read() - new_bytes = old_bytes.replace(b"", header) - glist = list(reader(string=new_bytes)) - if len(glist) == 0: - raise nx.NetworkXError("file not successfully read as graphml") - return glist[0] - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_graphml( - graphml_string, node_type=str, edge_key_type=int, force_multigraph=False -): - """Read graph in GraphML format from string. - - Parameters - ---------- - graphml_string : string - String containing graphml information - (e.g., contents of a graphml file). - - node_type: Python type (default: str) - Convert node ids to this type - - edge_key_type: Python type (default: int) - Convert graphml edge ids to this type. Multigraphs use id as edge key. - Non-multigraphs add to edge attribute dict with name "id". - - force_multigraph : bool (default: False) - If True, return a multigraph with edge keys. If False (the default) - return a multigraph when multiedges are in the graph. - - - Returns - ------- - graph: NetworkX graph - If no parallel edges are found a Graph or DiGraph is returned. - Otherwise a MultiGraph or MultiDiGraph is returned. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed = \n - >>> s = linefeed.join(nx.generate_graphml(G)) - >>> H = nx.parse_graphml(s) - - Notes - ----- - Default node and edge attributes are not propagated to each node and edge. - They can be obtained from `G.graph` and applied to node and edge attributes - if desired using something like this: - - >>> default_color = G.graph["node_default"]["color"] # doctest: +SKIP - >>> for node, data in G.nodes(data=True): # doctest: +SKIP - ... if "color" not in data: - ... data["color"] = default_color - >>> default_color = G.graph["edge_default"]["color"] # doctest: +SKIP - >>> for u, v, data in G.edges(data=True): # doctest: +SKIP - ... if "color" not in data: - ... data["color"] = default_color - - This implementation does not support mixed graphs (directed and unidirected - edges together), hypergraphs, nested graphs, or ports. - - For multigraphs the GraphML edge "id" will be used as the edge - key. If not specified then they "key" attribute will be used. If - there is no "key" attribute a default NetworkX multigraph edge key - will be provided. - - """ - reader = GraphMLReader(node_type, edge_key_type, force_multigraph) - # need to check for multiple graphs - glist = list(reader(string=graphml_string)) - if len(glist) == 0: - # If no graph comes back, try looking for an incomplete header - header = '' - new_string = graphml_string.replace("", header) - glist = list(reader(string=new_string)) - if len(glist) == 0: - raise nx.NetworkXError("file not successfully read as graphml") - return glist[0] - - -class GraphML: - NS_GRAPHML = "http://graphml.graphdrawing.org/xmlns" - NS_XSI = "http://www.w3.org/2001/XMLSchema-instance" - # xmlns:y="http://www.yworks.com/xml/graphml" - NS_Y = "http://www.yworks.com/xml/graphml" - SCHEMALOCATION = " ".join( - [ - "http://graphml.graphdrawing.org/xmlns", - "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd", - ] - ) - - def construct_types(self): - types = [ - (int, "integer"), # for Gephi GraphML bug - (str, "yfiles"), - (str, "string"), - (int, "int"), - (int, "long"), - (float, "float"), - (float, "double"), - (bool, "boolean"), - ] - - # These additions to types allow writing numpy types - try: - import numpy as np - except: - pass - else: - # prepend so that python types are created upon read (last entry wins) - types = [ - (np.float64, "float"), - (np.float32, "float"), - (np.float16, "float"), - (np.int_, "int"), - (np.int8, "int"), - (np.int16, "int"), - (np.int32, "int"), - (np.int64, "int"), - (np.uint8, "int"), - (np.uint16, "int"), - (np.uint32, "int"), - (np.uint64, "int"), - (np.int_, "int"), - (np.intc, "int"), - (np.intp, "int"), - ] + types - - self.xml_type = dict(types) - self.python_type = dict(reversed(a) for a in types) - - # This page says that data types in GraphML follow Java(TM). - # http://graphml.graphdrawing.org/primer/graphml-primer.html#AttributesDefinition - # true and false are the only boolean literals: - # http://en.wikibooks.org/wiki/Java_Programming/Literals#Boolean_Literals - convert_bool = { - # We use data.lower() in actual use. - "true": True, - "false": False, - # Include integer strings for convenience. - "0": False, - 0: False, - "1": True, - 1: True, - } - - def get_xml_type(self, key): - """Wrapper around the xml_type dict that raises a more informative - exception message when a user attempts to use data of a type not - supported by GraphML.""" - try: - return self.xml_type[key] - except KeyError as err: - raise TypeError( - f"GraphML does not support type {key} as data values." - ) from err - - -class GraphMLWriter(GraphML): - def __init__( - self, - graph=None, - encoding="utf-8", - prettyprint=True, - infer_numeric_types=False, - named_key_ids=False, - edge_id_from_attribute=None, - ): - self.construct_types() - from xml.etree.ElementTree import Element - - self.myElement = Element - - self.infer_numeric_types = infer_numeric_types - self.prettyprint = prettyprint - self.named_key_ids = named_key_ids - self.edge_id_from_attribute = edge_id_from_attribute - self.encoding = encoding - self.xml = self.myElement( - "graphml", - { - "xmlns": self.NS_GRAPHML, - "xmlns:xsi": self.NS_XSI, - "xsi:schemaLocation": self.SCHEMALOCATION, - }, - ) - self.keys = {} - self.attributes = defaultdict(list) - self.attribute_types = defaultdict(set) - - if graph is not None: - self.add_graph_element(graph) - - def __str__(self): - from xml.etree.ElementTree import tostring - - if self.prettyprint: - self.indent(self.xml) - s = tostring(self.xml).decode(self.encoding) - return s - - def attr_type(self, name, scope, value): - """Infer the attribute type of data named name. Currently this only - supports inference of numeric types. - - If self.infer_numeric_types is false, type is used. Otherwise, pick the - most general of types found across all values with name and scope. This - means edges with data named 'weight' are treated separately from nodes - with data named 'weight'. - """ - if self.infer_numeric_types: - types = self.attribute_types[(name, scope)] - - if len(types) > 1: - types = {self.get_xml_type(t) for t in types} - if "string" in types: - return str - elif "float" in types or "double" in types: - return float - else: - return int - else: - return list(types)[0] - else: - return type(value) - - def get_key(self, name, attr_type, scope, default): - keys_key = (name, attr_type, scope) - try: - return self.keys[keys_key] - except KeyError: - if self.named_key_ids: - new_id = name - else: - new_id = f"d{len(list(self.keys))}" - - self.keys[keys_key] = new_id - key_kwargs = { - "id": new_id, - "for": scope, - "attr.name": name, - "attr.type": attr_type, - } - key_element = self.myElement("key", **key_kwargs) - # add subelement for data default value if present - if default is not None: - default_element = self.myElement("default") - default_element.text = str(default) - key_element.append(default_element) - self.xml.insert(0, key_element) - return new_id - - def add_data(self, name, element_type, value, scope="all", default=None): - """ - Make a data element for an edge or a node. Keep a log of the - type in the keys table. - """ - if element_type not in self.xml_type: - raise nx.NetworkXError( - f"GraphML writer does not support {element_type} as data values." - ) - keyid = self.get_key(name, self.get_xml_type(element_type), scope, default) - data_element = self.myElement("data", key=keyid) - data_element.text = str(value) - return data_element - - def add_attributes(self, scope, xml_obj, data, default): - """Appends attribute data to edges or nodes, and stores type information - to be added later. See add_graph_element. - """ - for k, v in data.items(): - self.attribute_types[(str(k), scope)].add(type(v)) - self.attributes[xml_obj].append([k, v, scope, default.get(k)]) - - def add_nodes(self, G, graph_element): - default = G.graph.get("node_default", {}) - for node, data in G.nodes(data=True): - node_element = self.myElement("node", id=str(node)) - self.add_attributes("node", node_element, data, default) - graph_element.append(node_element) - - def add_edges(self, G, graph_element): - if G.is_multigraph(): - for u, v, key, data in G.edges(data=True, keys=True): - edge_element = self.myElement( - "edge", - source=str(u), - target=str(v), - id=str(data.get(self.edge_id_from_attribute)) - if self.edge_id_from_attribute - and self.edge_id_from_attribute in data - else str(key), - ) - default = G.graph.get("edge_default", {}) - self.add_attributes("edge", edge_element, data, default) - graph_element.append(edge_element) - else: - for u, v, data in G.edges(data=True): - if self.edge_id_from_attribute and self.edge_id_from_attribute in data: - # select attribute to be edge id - edge_element = self.myElement( - "edge", - source=str(u), - target=str(v), - id=str(data.get(self.edge_id_from_attribute)), - ) - else: - # default: no edge id - edge_element = self.myElement("edge", source=str(u), target=str(v)) - default = G.graph.get("edge_default", {}) - self.add_attributes("edge", edge_element, data, default) - graph_element.append(edge_element) - - def add_graph_element(self, G): - """ - Serialize graph G in GraphML to the stream. - """ - if G.is_directed(): - default_edge_type = "directed" - else: - default_edge_type = "undirected" - - graphid = G.graph.pop("id", None) - if graphid is None: - graph_element = self.myElement("graph", edgedefault=default_edge_type) - else: - graph_element = self.myElement( - "graph", edgedefault=default_edge_type, id=graphid - ) - default = {} - data = { - k: v - for (k, v) in G.graph.items() - if k not in ["node_default", "edge_default"] - } - self.add_attributes("graph", graph_element, data, default) - self.add_nodes(G, graph_element) - self.add_edges(G, graph_element) - - # self.attributes contains a mapping from XML Objects to a list of - # data that needs to be added to them. - # We postpone processing in order to do type inference/generalization. - # See self.attr_type - for xml_obj, data in self.attributes.items(): - for k, v, scope, default in data: - xml_obj.append( - self.add_data( - str(k), self.attr_type(k, scope, v), str(v), scope, default - ) - ) - self.xml.append(graph_element) - - def add_graphs(self, graph_list): - """Add many graphs to this GraphML document.""" - for G in graph_list: - self.add_graph_element(G) - - def dump(self, stream): - from xml.etree.ElementTree import ElementTree - - if self.prettyprint: - self.indent(self.xml) - document = ElementTree(self.xml) - document.write(stream, encoding=self.encoding, xml_declaration=True) - - def indent(self, elem, level=0): - # in-place prettyprint formatter - i = "\n" + level * " " - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - self.indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -class IncrementalElement: - """Wrapper for _IncrementalWriter providing an Element like interface. - - This wrapper does not intend to be a complete implementation but rather to - deal with those calls used in GraphMLWriter. - """ - - def __init__(self, xml, prettyprint): - self.xml = xml - self.prettyprint = prettyprint - - def append(self, element): - self.xml.write(element, pretty_print=self.prettyprint) - - -class GraphMLWriterLxml(GraphMLWriter): - def __init__( - self, - path, - graph=None, - encoding="utf-8", - prettyprint=True, - infer_numeric_types=False, - named_key_ids=False, - edge_id_from_attribute=None, - ): - self.construct_types() - import lxml.etree as lxmletree - - self.myElement = lxmletree.Element - - self._encoding = encoding - self._prettyprint = prettyprint - self.named_key_ids = named_key_ids - self.edge_id_from_attribute = edge_id_from_attribute - self.infer_numeric_types = infer_numeric_types - - self._xml_base = lxmletree.xmlfile(path, encoding=encoding) - self._xml = self._xml_base.__enter__() - self._xml.write_declaration() - - # We need to have a xml variable that support insertion. This call is - # used for adding the keys to the document. - # We will store those keys in a plain list, and then after the graph - # element is closed we will add them to the main graphml element. - self.xml = [] - self._keys = self.xml - self._graphml = self._xml.element( - "graphml", - { - "xmlns": self.NS_GRAPHML, - "xmlns:xsi": self.NS_XSI, - "xsi:schemaLocation": self.SCHEMALOCATION, - }, - ) - self._graphml.__enter__() - self.keys = {} - self.attribute_types = defaultdict(set) - - if graph is not None: - self.add_graph_element(graph) - - def add_graph_element(self, G): - """ - Serialize graph G in GraphML to the stream. - """ - if G.is_directed(): - default_edge_type = "directed" - else: - default_edge_type = "undirected" - - graphid = G.graph.pop("id", None) - if graphid is None: - graph_element = self._xml.element("graph", edgedefault=default_edge_type) - else: - graph_element = self._xml.element( - "graph", edgedefault=default_edge_type, id=graphid - ) - - # gather attributes types for the whole graph - # to find the most general numeric format needed. - # Then pass through attributes to create key_id for each. - graphdata = { - k: v - for k, v in G.graph.items() - if k not in ("node_default", "edge_default") - } - node_default = G.graph.get("node_default", {}) - edge_default = G.graph.get("edge_default", {}) - # Graph attributes - for k, v in graphdata.items(): - self.attribute_types[(str(k), "graph")].add(type(v)) - for k, v in graphdata.items(): - element_type = self.get_xml_type(self.attr_type(k, "graph", v)) - self.get_key(str(k), element_type, "graph", None) - # Nodes and data - for node, d in G.nodes(data=True): - for k, v in d.items(): - self.attribute_types[(str(k), "node")].add(type(v)) - for node, d in G.nodes(data=True): - for k, v in d.items(): - T = self.get_xml_type(self.attr_type(k, "node", v)) - self.get_key(str(k), T, "node", node_default.get(k)) - # Edges and data - if G.is_multigraph(): - for u, v, ekey, d in G.edges(keys=True, data=True): - for k, v in d.items(): - self.attribute_types[(str(k), "edge")].add(type(v)) - for u, v, ekey, d in G.edges(keys=True, data=True): - for k, v in d.items(): - T = self.get_xml_type(self.attr_type(k, "edge", v)) - self.get_key(str(k), T, "edge", edge_default.get(k)) - else: - for u, v, d in G.edges(data=True): - for k, v in d.items(): - self.attribute_types[(str(k), "edge")].add(type(v)) - for u, v, d in G.edges(data=True): - for k, v in d.items(): - T = self.get_xml_type(self.attr_type(k, "edge", v)) - self.get_key(str(k), T, "edge", edge_default.get(k)) - - # Now add attribute keys to the xml file - for key in self.xml: - self._xml.write(key, pretty_print=self._prettyprint) - - # The incremental_writer writes each node/edge as it is created - incremental_writer = IncrementalElement(self._xml, self._prettyprint) - with graph_element: - self.add_attributes("graph", incremental_writer, graphdata, {}) - self.add_nodes(G, incremental_writer) # adds attributes too - self.add_edges(G, incremental_writer) # adds attributes too - - def add_attributes(self, scope, xml_obj, data, default): - """Appends attribute data.""" - for k, v in data.items(): - data_element = self.add_data( - str(k), self.attr_type(str(k), scope, v), str(v), scope, default.get(k) - ) - xml_obj.append(data_element) - - def __str__(self): - return object.__str__(self) - - def dump(self, stream=None): - self._graphml.__exit__(None, None, None) - self._xml_base.__exit__(None, None, None) - - -# default is lxml is present. -write_graphml = write_graphml_lxml - - -class GraphMLReader(GraphML): - """Read a GraphML document. Produces NetworkX graph objects.""" - - def __init__(self, node_type=str, edge_key_type=int, force_multigraph=False): - self.construct_types() - self.node_type = node_type - self.edge_key_type = edge_key_type - self.multigraph = force_multigraph # If False, test for multiedges - self.edge_ids = {} # dict mapping (u,v) tuples to edge id attributes - - def __call__(self, path=None, string=None): - from xml.etree.ElementTree import ElementTree, fromstring - - if path is not None: - self.xml = ElementTree(file=path) - elif string is not None: - self.xml = fromstring(string) - else: - raise ValueError("Must specify either 'path' or 'string' as kwarg") - (keys, defaults) = self.find_graphml_keys(self.xml) - for g in self.xml.findall(f"{{{self.NS_GRAPHML}}}graph"): - yield self.make_graph(g, keys, defaults) - - def make_graph(self, graph_xml, graphml_keys, defaults, G=None): - # set default graph type - edgedefault = graph_xml.get("edgedefault", None) - if G is None: - if edgedefault == "directed": - G = nx.MultiDiGraph() - else: - G = nx.MultiGraph() - # set defaults for graph attributes - G.graph["node_default"] = {} - G.graph["edge_default"] = {} - for key_id, value in defaults.items(): - key_for = graphml_keys[key_id]["for"] - name = graphml_keys[key_id]["name"] - python_type = graphml_keys[key_id]["type"] - if key_for == "node": - G.graph["node_default"].update({name: python_type(value)}) - if key_for == "edge": - G.graph["edge_default"].update({name: python_type(value)}) - # hyperedges are not supported - hyperedge = graph_xml.find(f"{{{self.NS_GRAPHML}}}hyperedge") - if hyperedge is not None: - raise nx.NetworkXError("GraphML reader doesn't support hyperedges") - # add nodes - for node_xml in graph_xml.findall(f"{{{self.NS_GRAPHML}}}node"): - self.add_node(G, node_xml, graphml_keys, defaults) - # add edges - for edge_xml in graph_xml.findall(f"{{{self.NS_GRAPHML}}}edge"): - self.add_edge(G, edge_xml, graphml_keys) - # add graph data - data = self.decode_data_elements(graphml_keys, graph_xml) - G.graph.update(data) - - # switch to Graph or DiGraph if no parallel edges were found - if self.multigraph: - return G - - G = nx.DiGraph(G) if G.is_directed() else nx.Graph(G) - # add explicit edge "id" from file as attribute in NX graph. - nx.set_edge_attributes(G, values=self.edge_ids, name="id") - return G - - def add_node(self, G, node_xml, graphml_keys, defaults): - """Add a node to the graph.""" - # warn on finding unsupported ports tag - ports = node_xml.find(f"{{{self.NS_GRAPHML}}}port") - if ports is not None: - warnings.warn("GraphML port tag not supported.") - # find the node by id and cast it to the appropriate type - node_id = self.node_type(node_xml.get("id")) - # get data/attributes for node - data = self.decode_data_elements(graphml_keys, node_xml) - G.add_node(node_id, **data) - # get child nodes - if node_xml.attrib.get("yfiles.foldertype") == "group": - graph_xml = node_xml.find(f"{{{self.NS_GRAPHML}}}graph") - self.make_graph(graph_xml, graphml_keys, defaults, G) - - def add_edge(self, G, edge_element, graphml_keys): - """Add an edge to the graph.""" - # warn on finding unsupported ports tag - ports = edge_element.find(f"{{{self.NS_GRAPHML}}}port") - if ports is not None: - warnings.warn("GraphML port tag not supported.") - - # raise error if we find mixed directed and undirected edges - directed = edge_element.get("directed") - if G.is_directed() and directed == "false": - msg = "directed=false edge found in directed graph." - raise nx.NetworkXError(msg) - if (not G.is_directed()) and directed == "true": - msg = "directed=true edge found in undirected graph." - raise nx.NetworkXError(msg) - - source = self.node_type(edge_element.get("source")) - target = self.node_type(edge_element.get("target")) - data = self.decode_data_elements(graphml_keys, edge_element) - # GraphML stores edge ids as an attribute - # NetworkX uses them as keys in multigraphs too if no key - # attribute is specified - edge_id = edge_element.get("id") - if edge_id: - # self.edge_ids is used by `make_graph` method for non-multigraphs - self.edge_ids[source, target] = edge_id - try: - edge_id = self.edge_key_type(edge_id) - except ValueError: # Could not convert. - pass - else: - edge_id = data.get("key") - - if G.has_edge(source, target): - # mark this as a multigraph - self.multigraph = True - - # Use add_edges_from to avoid error with add_edge when `'key' in data` - # Note there is only one edge here... - G.add_edges_from([(source, target, edge_id, data)]) - - def decode_data_elements(self, graphml_keys, obj_xml): - """Use the key information to decode the data XML if present.""" - data = {} - for data_element in obj_xml.findall(f"{{{self.NS_GRAPHML}}}data"): - key = data_element.get("key") - try: - data_name = graphml_keys[key]["name"] - data_type = graphml_keys[key]["type"] - except KeyError as err: - raise nx.NetworkXError(f"Bad GraphML data: no key {key}") from err - text = data_element.text - # assume anything with subelements is a yfiles extension - if text is not None and len(list(data_element)) == 0: - if data_type == bool: - # Ignore cases. - # http://docs.oracle.com/javase/6/docs/api/java/lang/ - # Boolean.html#parseBoolean%28java.lang.String%29 - data[data_name] = self.convert_bool[text.lower()] - else: - data[data_name] = data_type(text) - elif len(list(data_element)) > 0: - # Assume yfiles as subelements, try to extract node_label - node_label = None - # set GenericNode's configuration as shape type - gn = data_element.find(f"{{{self.NS_Y}}}GenericNode") - if gn is not None: - data["shape_type"] = gn.get("configuration") - for node_type in ["GenericNode", "ShapeNode", "SVGNode", "ImageNode"]: - pref = f"{{{self.NS_Y}}}{node_type}/{{{self.NS_Y}}}" - geometry = data_element.find(f"{pref}Geometry") - if geometry is not None: - data["x"] = geometry.get("x") - data["y"] = geometry.get("y") - if node_label is None: - node_label = data_element.find(f"{pref}NodeLabel") - shape = data_element.find(f"{pref}Shape") - if shape is not None: - data["shape_type"] = shape.get("type") - if node_label is not None: - data["label"] = node_label.text - - # check all the different types of edges available in yEd. - for edge_type in [ - "PolyLineEdge", - "SplineEdge", - "QuadCurveEdge", - "BezierEdge", - "ArcEdge", - ]: - pref = f"{{{self.NS_Y}}}{edge_type}/{{{self.NS_Y}}}" - edge_label = data_element.find(f"{pref}EdgeLabel") - if edge_label is not None: - break - if edge_label is not None: - data["label"] = edge_label.text - elif text is None: - data[data_name] = "" - return data - - def find_graphml_keys(self, graph_element): - """Extracts all the keys and key defaults from the xml.""" - graphml_keys = {} - graphml_key_defaults = {} - for k in graph_element.findall(f"{{{self.NS_GRAPHML}}}key"): - attr_id = k.get("id") - attr_type = k.get("attr.type") - attr_name = k.get("attr.name") - yfiles_type = k.get("yfiles.type") - if yfiles_type is not None: - attr_name = yfiles_type - attr_type = "yfiles" - if attr_type is None: - attr_type = "string" - warnings.warn(f"No key type for id {attr_id}. Using string") - if attr_name is None: - raise nx.NetworkXError(f"Unknown key for id {attr_id}.") - graphml_keys[attr_id] = { - "name": attr_name, - "type": self.python_type[attr_type], - "for": k.get("for"), - } - # check for "default" sub-element of key element - default = k.find(f"{{{self.NS_GRAPHML}}}default") - if default is not None: - # Handle default values identically to data element values - python_type = graphml_keys[attr_id]["type"] - if python_type == bool: - graphml_key_defaults[attr_id] = self.convert_bool[ - default.text.lower() - ] - else: - graphml_key_defaults[attr_id] = python_type(default.text) - return graphml_keys, graphml_key_defaults diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/__init__.py deleted file mode 100644 index 532c71d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -********* -JSON data -********* -Generate and parse JSON serializable data for NetworkX graphs. - -These formats are suitable for use with the d3.js examples https://d3js.org/ - -The three formats that you can generate with NetworkX are: - - - node-link like in the d3.js example https://bl.ocks.org/mbostock/4062045 - - tree like in the d3.js example https://bl.ocks.org/mbostock/4063550 - - adjacency like in the d3.js example https://bost.ocks.org/mike/miserables/ -""" - -from networkx.readwrite.json_graph.node_link import * -from networkx.readwrite.json_graph.adjacency import * -from networkx.readwrite.json_graph.tree import * -from networkx.readwrite.json_graph.cytoscape import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/adjacency.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/adjacency.py deleted file mode 100644 index 3b05747..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/adjacency.py +++ /dev/null @@ -1,156 +0,0 @@ -import networkx as nx - -__all__ = ["adjacency_data", "adjacency_graph"] - -_attrs = {"id": "id", "key": "key"} - - -def adjacency_data(G, attrs=_attrs): - """Returns data in adjacency format that is suitable for JSON serialization - and use in JavaScript documents. - - Parameters - ---------- - G : NetworkX graph - - attrs : dict - A dictionary that contains two keys 'id' and 'key'. The corresponding - values provide the attribute names for storing NetworkX-internal graph - data. The values should be unique. Default value: - :samp:`dict(id='id', key='key')`. - - If some user-defined graph data use these attribute names as data keys, - they may be silently dropped. - - Returns - ------- - data : dict - A dictionary with adjacency formatted data. - - Raises - ------ - NetworkXError - If values in attrs are not unique. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([(1, 2)]) - >>> data = json_graph.adjacency_data(G) - - To serialize with json - - >>> import json - >>> s = json.dumps(data) - - Notes - ----- - Graph, node, and link attributes will be written when using this format - but attribute keys must be strings if you want to serialize the resulting - data with JSON. - - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - adjacency_graph, node_link_data, tree_data - """ - multigraph = G.is_multigraph() - id_ = attrs["id"] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs["key"] - if id_ == key: - raise nx.NetworkXError("Attribute names are not unique.") - data = {} - data["directed"] = G.is_directed() - data["multigraph"] = multigraph - data["graph"] = list(G.graph.items()) - data["nodes"] = [] - data["adjacency"] = [] - for n, nbrdict in G.adjacency(): - data["nodes"].append({**G.nodes[n], id_: n}) - adj = [] - if multigraph: - for nbr, keys in nbrdict.items(): - for k, d in keys.items(): - adj.append({**d, id_: nbr, key: k}) - else: - for nbr, d in nbrdict.items(): - adj.append({**d, id_: nbr}) - data["adjacency"].append(adj) - return data - - -@nx._dispatchable(graphs=None, returns_graph=True) -def adjacency_graph(data, directed=False, multigraph=True, attrs=_attrs): - """Returns graph from adjacency data format. - - Parameters - ---------- - data : dict - Adjacency list formatted graph data - - directed : bool - If True, and direction not specified in data, return a directed graph. - - multigraph : bool - If True, and multigraph not specified in data, return a multigraph. - - attrs : dict - A dictionary that contains two keys 'id' and 'key'. The corresponding - values provide the attribute names for storing NetworkX-internal graph - data. The values should be unique. Default value: - :samp:`dict(id='id', key='key')`. - - Returns - ------- - G : NetworkX graph - A NetworkX graph object - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([(1, 2)]) - >>> data = json_graph.adjacency_data(G) - >>> H = json_graph.adjacency_graph(data) - - Notes - ----- - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - adjacency_graph, node_link_data, tree_data - """ - multigraph = data.get("multigraph", multigraph) - directed = data.get("directed", directed) - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - id_ = attrs["id"] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs["key"] - graph.graph = dict(data.get("graph", [])) - mapping = [] - for d in data["nodes"]: - node_data = d.copy() - node = node_data.pop(id_) - mapping.append(node) - graph.add_node(node) - graph.nodes[node].update(node_data) - for i, d in enumerate(data["adjacency"]): - source = mapping[i] - for tdata in d: - target_data = tdata.copy() - target = target_data.pop(id_) - if not multigraph: - graph.add_edge(source, target) - graph[source][target].update(target_data) - else: - ky = target_data.pop(key, None) - graph.add_edge(source, target, key=ky) - graph[source][target][ky].update(target_data) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/cytoscape.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/cytoscape.py deleted file mode 100644 index 2f3b217..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/cytoscape.py +++ /dev/null @@ -1,178 +0,0 @@ -import networkx as nx - -__all__ = ["cytoscape_data", "cytoscape_graph"] - - -def cytoscape_data(G, name="name", ident="id"): - """Returns data in Cytoscape JSON format (cyjs). - - Parameters - ---------- - G : NetworkX Graph - The graph to convert to cytoscape format - name : string - A string which is mapped to the 'name' node element in cyjs format. - Must not have the same value as `ident`. - ident : string - A string which is mapped to the 'id' node element in cyjs format. - Must not have the same value as `name`. - - Returns - ------- - data: dict - A dictionary with cyjs formatted data. - - Raises - ------ - NetworkXError - If the values for `name` and `ident` are identical. - - See Also - -------- - cytoscape_graph: convert a dictionary in cyjs format to a graph - - References - ---------- - .. [1] Cytoscape user's manual: - http://manual.cytoscape.org/en/stable/index.html - - Examples - -------- - >>> G = nx.path_graph(2) - >>> nx.cytoscape_data(G) # doctest: +SKIP - {'data': [], - 'directed': False, - 'multigraph': False, - 'elements': {'nodes': [{'data': {'id': '0', 'value': 0, 'name': '0'}}, - {'data': {'id': '1', 'value': 1, 'name': '1'}}], - 'edges': [{'data': {'source': 0, 'target': 1}}]}} - """ - if name == ident: - raise nx.NetworkXError("name and ident must be different.") - - jsondata = {"data": list(G.graph.items())} - jsondata["directed"] = G.is_directed() - jsondata["multigraph"] = G.is_multigraph() - jsondata["elements"] = {"nodes": [], "edges": []} - nodes = jsondata["elements"]["nodes"] - edges = jsondata["elements"]["edges"] - - for i, j in G.nodes.items(): - n = {"data": j.copy()} - n["data"]["id"] = j.get(ident) or str(i) - n["data"]["value"] = i - n["data"]["name"] = j.get(name) or str(i) - nodes.append(n) - - if G.is_multigraph(): - for e in G.edges(keys=True): - n = {"data": G.adj[e[0]][e[1]][e[2]].copy()} - n["data"]["source"] = e[0] - n["data"]["target"] = e[1] - n["data"]["key"] = e[2] - edges.append(n) - else: - for e in G.edges(): - n = {"data": G.adj[e[0]][e[1]].copy()} - n["data"]["source"] = e[0] - n["data"]["target"] = e[1] - edges.append(n) - return jsondata - - -@nx._dispatchable(graphs=None, returns_graph=True) -def cytoscape_graph(data, name="name", ident="id"): - """ - Create a NetworkX graph from a dictionary in cytoscape JSON format. - - Parameters - ---------- - data : dict - A dictionary of data conforming to cytoscape JSON format. - name : string - A string which is mapped to the 'name' node element in cyjs format. - Must not have the same value as `ident`. - ident : string - A string which is mapped to the 'id' node element in cyjs format. - Must not have the same value as `name`. - - Returns - ------- - graph : a NetworkX graph instance - The `graph` can be an instance of `Graph`, `DiGraph`, `MultiGraph`, or - `MultiDiGraph` depending on the input data. - - Raises - ------ - NetworkXError - If the `name` and `ident` attributes are identical. - - See Also - -------- - cytoscape_data: convert a NetworkX graph to a dict in cyjs format - - References - ---------- - .. [1] Cytoscape user's manual: - http://manual.cytoscape.org/en/stable/index.html - - Examples - -------- - >>> data_dict = { - ... "data": [], - ... "directed": False, - ... "multigraph": False, - ... "elements": { - ... "nodes": [ - ... {"data": {"id": "0", "value": 0, "name": "0"}}, - ... {"data": {"id": "1", "value": 1, "name": "1"}}, - ... ], - ... "edges": [{"data": {"source": 0, "target": 1}}], - ... }, - ... } - >>> G = nx.cytoscape_graph(data_dict) - >>> G.name - '' - >>> G.nodes() - NodeView((0, 1)) - >>> G.nodes(data=True)[0] - {'id': '0', 'value': 0, 'name': '0'} - >>> G.edges(data=True) - EdgeDataView([(0, 1, {'source': 0, 'target': 1})]) - """ - if name == ident: - raise nx.NetworkXError("name and ident must be different.") - - multigraph = data.get("multigraph") - directed = data.get("directed") - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - graph.graph = dict(data.get("data")) - for d in data["elements"]["nodes"]: - node_data = d["data"].copy() - node = d["data"]["value"] - - if d["data"].get(name): - node_data[name] = d["data"].get(name) - if d["data"].get(ident): - node_data[ident] = d["data"].get(ident) - - graph.add_node(node) - graph.nodes[node].update(node_data) - - for d in data["elements"]["edges"]: - edge_data = d["data"].copy() - sour = d["data"]["source"] - targ = d["data"]["target"] - if multigraph: - key = d["data"].get("key", 0) - graph.add_edge(sour, targ, key=key) - graph.edges[sour, targ, key].update(edge_data) - else: - graph.add_edge(sour, targ) - graph.edges[sour, targ].update(edge_data) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/node_link.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/node_link.py deleted file mode 100644 index 63ca978..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/node_link.py +++ /dev/null @@ -1,330 +0,0 @@ -import warnings -from itertools import count - -import networkx as nx - -__all__ = ["node_link_data", "node_link_graph"] - - -def _to_tuple(x): - """Converts lists to tuples, including nested lists. - - All other non-list inputs are passed through unmodified. This function is - intended to be used to convert potentially nested lists from json files - into valid nodes. - - Examples - -------- - >>> _to_tuple([1, 2, [3, 4]]) - (1, 2, (3, 4)) - """ - if not isinstance(x, tuple | list): - return x - return tuple(map(_to_tuple, x)) - - -def node_link_data( - G, - *, - source="source", - target="target", - name="id", - key="key", - edges=None, - nodes="nodes", - link=None, -): - """Returns data in node-link format that is suitable for JSON serialization - and use in JavaScript documents. - - Parameters - ---------- - G : NetworkX graph - source : string - A string that provides the 'source' attribute name for storing NetworkX-internal graph data. - target : string - A string that provides the 'target' attribute name for storing NetworkX-internal graph data. - name : string - A string that provides the 'name' attribute name for storing NetworkX-internal graph data. - key : string - A string that provides the 'key' attribute name for storing NetworkX-internal graph data. - edges : string - A string that provides the 'edges' attribute name for storing NetworkX-internal graph data. - nodes : string - A string that provides the 'nodes' attribute name for storing NetworkX-internal graph data. - link : string - .. deprecated:: 3.4 - - The `link` argument is deprecated and will be removed in version `3.6`. - Use the `edges` keyword instead. - - A string that provides the 'edges' attribute name for storing NetworkX-internal graph data. - - Returns - ------- - data : dict - A dictionary with node-link formatted data. - - Raises - ------ - NetworkXError - If the values of 'source', 'target' and 'key' are not unique. - - Examples - -------- - >>> from pprint import pprint - >>> G = nx.Graph([("A", "B")]) - >>> data1 = nx.node_link_data(G, edges="edges") - >>> pprint(data1) - {'directed': False, - 'edges': [{'source': 'A', 'target': 'B'}], - 'graph': {}, - 'multigraph': False, - 'nodes': [{'id': 'A'}, {'id': 'B'}]} - - To serialize with JSON - - >>> import json - >>> s1 = json.dumps(data1) - >>> s1 - '{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"id": "A"}, {"id": "B"}], "edges": [{"source": "A", "target": "B"}]}' - - A graph can also be serialized by passing `node_link_data` as an encoder function. - - >>> s1 = json.dumps(G, default=nx.node_link_data) - >>> s1 - '{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"id": "A"}, {"id": "B"}], "links": [{"source": "A", "target": "B"}]}' - - The attribute names for storing NetworkX-internal graph data can - be specified as keyword options. - - >>> H = nx.gn_graph(2) - >>> data2 = nx.node_link_data( - ... H, edges="links", source="from", target="to", nodes="vertices" - ... ) - >>> pprint(data2) - {'directed': True, - 'graph': {}, - 'links': [{'from': 1, 'to': 0}], - 'multigraph': False, - 'vertices': [{'id': 0}, {'id': 1}]} - - Notes - ----- - Graph, node, and link attributes are stored in this format. Note that - attribute keys will be converted to strings in order to comply with JSON. - - Attribute 'key' is only used for multigraphs. - - To use `node_link_data` in conjunction with `node_link_graph`, - the keyword names for the attributes must match. - - See Also - -------- - node_link_graph, adjacency_data, tree_data - """ - # TODO: Remove between the lines when `link` deprecation expires - # ------------------------------------------------------------- - if link is not None: - warnings.warn( - "Keyword argument 'link' is deprecated; use 'edges' instead", - DeprecationWarning, - stacklevel=2, - ) - if edges is not None: - raise ValueError( - "Both 'edges' and 'link' are specified. Use 'edges', 'link' will be remove in a future release" - ) - else: - edges = link - else: - if edges is None: - warnings.warn( - ( - '\nThe default value will be `edges="edges" in NetworkX 3.6.\n\n' - "To make this warning go away, explicitly set the edges kwarg, e.g.:\n\n" - ' nx.node_link_data(G, edges="links") to preserve current behavior, or\n' - ' nx.node_link_data(G, edges="edges") for forward compatibility.' - ), - FutureWarning, - ) - edges = "links" - # ------------------------------------------------------------ - - multigraph = G.is_multigraph() - - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else key - if len({source, target, key}) < 3: - raise nx.NetworkXError("Attribute names are not unique.") - data = { - "directed": G.is_directed(), - "multigraph": multigraph, - "graph": G.graph, - nodes: [{**G.nodes[n], name: n} for n in G], - } - if multigraph: - data[edges] = [ - {**d, source: u, target: v, key: k} - for u, v, k, d in G.edges(keys=True, data=True) - ] - else: - data[edges] = [{**d, source: u, target: v} for u, v, d in G.edges(data=True)] - return data - - -@nx._dispatchable(graphs=None, returns_graph=True) -def node_link_graph( - data, - directed=False, - multigraph=True, - *, - source="source", - target="target", - name="id", - key="key", - edges=None, - nodes="nodes", - link=None, -): - """Returns graph from node-link data format. - - Useful for de-serialization from JSON. - - Parameters - ---------- - data : dict - node-link formatted graph data - - directed : bool - If True, and direction not specified in data, return a directed graph. - - multigraph : bool - If True, and multigraph not specified in data, return a multigraph. - - source : string - A string that provides the 'source' attribute name for storing NetworkX-internal graph data. - target : string - A string that provides the 'target' attribute name for storing NetworkX-internal graph data. - name : string - A string that provides the 'name' attribute name for storing NetworkX-internal graph data. - key : string - A string that provides the 'key' attribute name for storing NetworkX-internal graph data. - edges : string - A string that provides the 'edges' attribute name for storing NetworkX-internal graph data. - nodes : string - A string that provides the 'nodes' attribute name for storing NetworkX-internal graph data. - link : string - .. deprecated:: 3.4 - - The `link` argument is deprecated and will be removed in version `3.6`. - Use the `edges` keyword instead. - - A string that provides the 'edges' attribute name for storing NetworkX-internal graph data. - - Returns - ------- - G : NetworkX graph - A NetworkX graph object - - Examples - -------- - - Create data in node-link format by converting a graph. - - >>> from pprint import pprint - >>> G = nx.Graph([("A", "B")]) - >>> data = nx.node_link_data(G, edges="edges") - >>> pprint(data) - {'directed': False, - 'edges': [{'source': 'A', 'target': 'B'}], - 'graph': {}, - 'multigraph': False, - 'nodes': [{'id': 'A'}, {'id': 'B'}]} - - Revert data in node-link format to a graph. - - >>> H = nx.node_link_graph(data, edges="edges") - >>> print(H.edges) - [('A', 'B')] - - To serialize and deserialize a graph with JSON, - - >>> import json - >>> d = json.dumps(nx.node_link_data(G, edges="edges")) - >>> H = nx.node_link_graph(json.loads(d), edges="edges") - >>> print(G.edges, H.edges) - [('A', 'B')] [('A', 'B')] - - - Notes - ----- - Attribute 'key' is only used for multigraphs. - - To use `node_link_data` in conjunction with `node_link_graph`, - the keyword names for the attributes must match. - - See Also - -------- - node_link_data, adjacency_data, tree_data - """ - # TODO: Remove between the lines when `link` deprecation expires - # ------------------------------------------------------------- - if link is not None: - warnings.warn( - "Keyword argument 'link' is deprecated; use 'edges' instead", - DeprecationWarning, - stacklevel=2, - ) - if edges is not None: - raise ValueError( - "Both 'edges' and 'link' are specified. Use 'edges', 'link' will be remove in a future release" - ) - else: - edges = link - else: - if edges is None: - warnings.warn( - ( - '\nThe default value will be changed to `edges="edges" in NetworkX 3.6.\n\n' - "To make this warning go away, explicitly set the edges kwarg, e.g.:\n\n" - ' nx.node_link_graph(data, edges="links") to preserve current behavior, or\n' - ' nx.node_link_graph(data, edges="edges") for forward compatibility.' - ), - FutureWarning, - ) - edges = "links" - # ------------------------------------------------------------- - - multigraph = data.get("multigraph", multigraph) - directed = data.get("directed", directed) - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else key - graph.graph = data.get("graph", {}) - c = count() - for d in data[nodes]: - node = _to_tuple(d.get(name, next(c))) - nodedata = {str(k): v for k, v in d.items() if k != name} - graph.add_node(node, **nodedata) - for d in data[edges]: - src = tuple(d[source]) if isinstance(d[source], list) else d[source] - tgt = tuple(d[target]) if isinstance(d[target], list) else d[target] - if not multigraph: - edgedata = {str(k): v for k, v in d.items() if k != source and k != target} - graph.add_edge(src, tgt, **edgedata) - else: - ky = d.get(key, None) - edgedata = { - str(k): v - for k, v in d.items() - if k != source and k != target and k != key - } - graph.add_edge(src, tgt, ky, **edgedata) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py deleted file mode 100644 index 3750638..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py +++ /dev/null @@ -1,78 +0,0 @@ -import copy -import json - -import pytest - -import networkx as nx -from networkx.readwrite.json_graph import adjacency_data, adjacency_graph -from networkx.utils import graphs_equal - - -class TestAdjacency: - def test_graph(self): - G = nx.path_graph(4) - H = adjacency_graph(adjacency_data(G)) - assert graphs_equal(G, H) - - def test_graph_attributes(self): - G = nx.path_graph(4) - G.add_node(1, color="red") - G.add_edge(1, 2, width=7) - G.graph["foo"] = "bar" - G.graph[1] = "one" - - H = adjacency_graph(adjacency_data(G)) - assert graphs_equal(G, H) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - d = json.dumps(adjacency_data(G)) - H = adjacency_graph(json.loads(d)) - assert graphs_equal(G, H) - assert H.graph["foo"] == "bar" - assert H.graph[1] == "one" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - def test_digraph(self): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - H = adjacency_graph(adjacency_data(G)) - assert H.is_directed() - assert graphs_equal(G, H) - - def test_multidigraph(self): - G = nx.MultiDiGraph() - nx.add_path(G, [1, 2, 3]) - H = adjacency_graph(adjacency_data(G)) - assert H.is_directed() - assert H.is_multigraph() - assert graphs_equal(G, H) - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, key="first") - G.add_edge(1, 2, key="second", color="blue") - H = adjacency_graph(adjacency_data(G)) - assert graphs_equal(G, H) - assert H[1][2]["second"]["color"] == "blue" - - def test_input_data_is_not_modified_when_building_graph(self): - G = nx.path_graph(4) - input_data = adjacency_data(G) - orig_data = copy.deepcopy(input_data) - # Ensure input is unmodified by deserialisation - assert graphs_equal(G, adjacency_graph(input_data)) - assert input_data == orig_data - - def test_adjacency_form_json_serialisable(self): - G = nx.path_graph(4) - H = adjacency_graph(json.loads(json.dumps(adjacency_data(G)))) - assert graphs_equal(G, H) - - def test_exception(self): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - attrs = {"id": "node", "key": "node"} - adjacency_data(G, attrs) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py deleted file mode 100644 index 5d47f21..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py +++ /dev/null @@ -1,78 +0,0 @@ -import copy -import json - -import pytest - -import networkx as nx -from networkx.readwrite.json_graph import cytoscape_data, cytoscape_graph - - -def test_graph(): - G = nx.path_graph(4) - H = cytoscape_graph(cytoscape_data(G)) - assert nx.is_isomorphic(G, H) - - -def test_input_data_is_not_modified_when_building_graph(): - G = nx.path_graph(4) - input_data = cytoscape_data(G) - orig_data = copy.deepcopy(input_data) - # Ensure input is unmodified by cytoscape_graph (gh-4173) - cytoscape_graph(input_data) - assert input_data == orig_data - - -def test_graph_attributes(): - G = nx.path_graph(4) - G.add_node(1, color="red") - G.add_edge(1, 2, width=7) - G.graph["foo"] = "bar" - G.graph[1] = "one" - G.add_node(3, name="node", id="123") - - H = cytoscape_graph(cytoscape_data(G)) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - assert H.nodes[3]["name"] == "node" - assert H.nodes[3]["id"] == "123" - - d = json.dumps(cytoscape_data(G)) - H = cytoscape_graph(json.loads(d)) - assert H.graph["foo"] == "bar" - assert H.graph[1] == "one" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - assert H.nodes[3]["name"] == "node" - assert H.nodes[3]["id"] == "123" - - -def test_digraph(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - H = cytoscape_graph(cytoscape_data(G)) - assert H.is_directed() - assert nx.is_isomorphic(G, H) - - -def test_multidigraph(): - G = nx.MultiDiGraph() - nx.add_path(G, [1, 2, 3]) - H = cytoscape_graph(cytoscape_data(G)) - assert H.is_directed() - assert H.is_multigraph() - - -def test_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key="first") - G.add_edge(1, 2, key="second", color="blue") - H = cytoscape_graph(cytoscape_data(G)) - assert nx.is_isomorphic(G, H) - assert H[1][2]["second"]["color"] == "blue" - - -def test_exception(): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - cytoscape_data(G, name="foo", ident="foo") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py deleted file mode 100644 index f903f60..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py +++ /dev/null @@ -1,175 +0,0 @@ -import json - -import pytest - -import networkx as nx -from networkx.readwrite.json_graph import node_link_data, node_link_graph - - -def test_node_link_edges_default_future_warning(): - "Test FutureWarning is raised when `edges=None` in node_link_data and node_link_graph" - G = nx.Graph([(1, 2)]) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - data = nx.node_link_data(G) # edges=None, the default - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = nx.node_link_graph(data) # edges=None, the default - - -def test_node_link_deprecated_link_param(): - G = nx.Graph([(1, 2)]) - with pytest.warns(DeprecationWarning, match="Keyword argument 'link'"): - data = nx.node_link_data(G, link="links") - with pytest.warns(DeprecationWarning, match="Keyword argument 'link'"): - H = nx.node_link_graph(data, link="links") - - -class TestNodeLink: - # TODO: To be removed when signature change complete - def test_custom_attrs_dep(self): - G = nx.path_graph(4) - G.add_node(1, color="red") - G.add_edge(1, 2, width=7) - G.graph[1] = "one" - G.graph["foo"] = "bar" - - attrs = { - "source": "c_source", - "target": "c_target", - "name": "c_id", - "key": "c_key", - "link": "c_links", - } - - H = node_link_graph(node_link_data(G, **attrs), multigraph=False, **attrs) - assert nx.is_isomorphic(G, H) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - # provide only a partial dictionary of keywords. - # This is similar to an example in the doc string - attrs = { - "link": "c_links", - "source": "c_source", - "target": "c_target", - } - H = node_link_graph(node_link_data(G, **attrs), multigraph=False, **attrs) - assert nx.is_isomorphic(G, H) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - def test_exception_dep(self): - G = nx.MultiDiGraph() - with pytest.raises(nx.NetworkXError): - with pytest.warns(FutureWarning, match="\nThe default value will be"): - node_link_data(G, name="node", source="node", target="node", key="node") - - def test_graph(self): - G = nx.path_graph(4) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(node_link_data(G)) - assert nx.is_isomorphic(G, H) - - def test_graph_attributes(self): - G = nx.path_graph(4) - G.add_node(1, color="red") - G.add_edge(1, 2, width=7) - G.graph[1] = "one" - G.graph["foo"] = "bar" - - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(node_link_data(G)) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - with pytest.warns(FutureWarning, match="\nThe default value will be"): - d = json.dumps(node_link_data(G)) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(json.loads(d)) - assert H.graph["foo"] == "bar" - assert H.graph["1"] == "one" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 - - def test_digraph(self): - G = nx.DiGraph() - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(node_link_data(G)) - assert H.is_directed() - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, key="first") - G.add_edge(1, 2, key="second", color="blue") - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(node_link_data(G)) - assert nx.is_isomorphic(G, H) - assert H[1][2]["second"]["color"] == "blue" - - def test_graph_with_tuple_nodes(self): - G = nx.Graph() - G.add_edge((0, 0), (1, 0), color=[255, 255, 0]) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - d = node_link_data(G) - dumped_d = json.dumps(d) - dd = json.loads(dumped_d) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(dd) - assert H.nodes[(0, 0)] == G.nodes[(0, 0)] - assert H[(0, 0)][(1, 0)]["color"] == [255, 255, 0] - - def test_unicode_keys(self): - q = "qualité" - G = nx.Graph() - G.add_node(1, **{q: q}) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - s = node_link_data(G) - output = json.dumps(s, ensure_ascii=False) - data = json.loads(output) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(data) - assert H.nodes[1][q] == q - - def test_exception(self): - G = nx.MultiDiGraph() - attrs = {"name": "node", "source": "node", "target": "node", "key": "node"} - with pytest.raises(nx.NetworkXError): - with pytest.warns(FutureWarning, match="\nThe default value will be"): - node_link_data(G, **attrs) - - def test_string_ids(self): - q = "qualité" - G = nx.DiGraph() - G.add_node("A") - G.add_node(q) - G.add_edge("A", q) - with pytest.warns(FutureWarning, match="\nThe default value will be"): - data = node_link_data(G) - assert data["links"][0]["source"] == "A" - assert data["links"][0]["target"] == q - with pytest.warns(FutureWarning, match="\nThe default value will be"): - H = node_link_graph(data) - assert nx.is_isomorphic(G, H) - - def test_custom_attrs(self): - G = nx.path_graph(4) - G.add_node(1, color="red") - G.add_edge(1, 2, width=7) - G.graph[1] = "one" - G.graph["foo"] = "bar" - - attrs = { - "source": "c_source", - "target": "c_target", - "name": "c_id", - "key": "c_key", - "link": "c_links", - } - - H = node_link_graph(node_link_data(G, **attrs), multigraph=False, **attrs) - assert nx.is_isomorphic(G, H) - assert H.graph["foo"] == "bar" - assert H.nodes[1]["color"] == "red" - assert H[1][2]["width"] == 7 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_tree.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_tree.py deleted file mode 100644 index 643a14d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tests/test_tree.py +++ /dev/null @@ -1,48 +0,0 @@ -import json - -import pytest - -import networkx as nx -from networkx.readwrite.json_graph import tree_data, tree_graph - - -def test_graph(): - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3], color="red") - G.add_edge(1, 2, foo=7) - G.add_edge(1, 3, foo=10) - G.add_edge(3, 4, foo=10) - H = tree_graph(tree_data(G, 1)) - assert nx.is_isomorphic(G, H) - - -def test_graph_attributes(): - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3], color="red") - G.add_edge(1, 2, foo=7) - G.add_edge(1, 3, foo=10) - G.add_edge(3, 4, foo=10) - H = tree_graph(tree_data(G, 1)) - assert H.nodes[1]["color"] == "red" - - d = json.dumps(tree_data(G, 1)) - H = tree_graph(json.loads(d)) - assert H.nodes[1]["color"] == "red" - - -def test_exceptions(): - with pytest.raises(TypeError, match="is not a tree."): - G = nx.complete_graph(3) - tree_data(G, 0) - with pytest.raises(TypeError, match="is not directed."): - G = nx.path_graph(3) - tree_data(G, 0) - with pytest.raises(TypeError, match="is not weakly connected."): - G = nx.path_graph(3, create_using=nx.DiGraph) - G.add_edge(2, 0) - G.add_node(3) - tree_data(G, 0) - with pytest.raises(nx.NetworkXError, match="must be different."): - G = nx.MultiDiGraph() - G.add_node(0) - tree_data(G, 0, ident="node", children="node") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tree.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tree.py deleted file mode 100644 index 22b07b0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/json_graph/tree.py +++ /dev/null @@ -1,137 +0,0 @@ -from itertools import chain - -import networkx as nx - -__all__ = ["tree_data", "tree_graph"] - - -def tree_data(G, root, ident="id", children="children"): - """Returns data in tree format that is suitable for JSON serialization - and use in JavaScript documents. - - Parameters - ---------- - G : NetworkX graph - G must be an oriented tree - - root : node - The root of the tree - - ident : string - Attribute name for storing NetworkX-internal graph data. `ident` must - have a different value than `children`. The default is 'id'. - - children : string - Attribute name for storing NetworkX-internal graph data. `children` - must have a different value than `ident`. The default is 'children'. - - Returns - ------- - data : dict - A dictionary with node-link formatted data. - - Raises - ------ - NetworkXError - If `children` and `ident` attributes are identical. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.DiGraph([(1, 2)]) - >>> data = json_graph.tree_data(G, root=1) - - To serialize with json - - >>> import json - >>> s = json.dumps(data) - - Notes - ----- - Node attributes are stored in this format but keys - for attributes must be strings if you want to serialize with JSON. - - Graph and edge attributes are not stored. - - See Also - -------- - tree_graph, node_link_data, adjacency_data - """ - if G.number_of_nodes() != G.number_of_edges() + 1: - raise TypeError("G is not a tree.") - if not G.is_directed(): - raise TypeError("G is not directed.") - if not nx.is_weakly_connected(G): - raise TypeError("G is not weakly connected.") - - if ident == children: - raise nx.NetworkXError("The values for `id` and `children` must be different.") - - def add_children(n, G): - nbrs = G[n] - if len(nbrs) == 0: - return [] - children_ = [] - for child in nbrs: - d = {**G.nodes[child], ident: child} - c = add_children(child, G) - if c: - d[children] = c - children_.append(d) - return children_ - - return {**G.nodes[root], ident: root, children: add_children(root, G)} - - -@nx._dispatchable(graphs=None, returns_graph=True) -def tree_graph(data, ident="id", children="children"): - """Returns graph from tree data format. - - Parameters - ---------- - data : dict - Tree formatted graph data - - ident : string - Attribute name for storing NetworkX-internal graph data. `ident` must - have a different value than `children`. The default is 'id'. - - children : string - Attribute name for storing NetworkX-internal graph data. `children` - must have a different value than `ident`. The default is 'children'. - - Returns - ------- - G : NetworkX DiGraph - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.DiGraph([(1, 2)]) - >>> data = json_graph.tree_data(G, root=1) - >>> H = json_graph.tree_graph(data) - - See Also - -------- - tree_data, node_link_data, adjacency_data - """ - graph = nx.DiGraph() - - def add_children(parent, children_): - for data in children_: - child = data[ident] - graph.add_edge(parent, child) - grandchildren = data.get(children, []) - if grandchildren: - add_children(child, grandchildren) - nodedata = { - str(k): v for k, v in data.items() if k != ident and k != children - } - graph.add_node(child, **nodedata) - - root = data[ident] - children_ = data.get(children, []) - nodedata = {str(k): v for k, v in data.items() if k != ident and k != children} - graph.add_node(root, **nodedata) - add_children(root, children_) - return graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/leda.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/leda.py deleted file mode 100644 index 9fb57db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/leda.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Read graphs in LEDA format. - -LEDA is a C++ class library for efficient data types and algorithms. - -Format ------- -See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - -""" -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain. - -__all__ = ["read_leda", "parse_leda"] - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_leda(path, encoding="UTF-8"): - """Read graph in LEDA format from path. - - Parameters - ---------- - path : file or string - File or filename to read. Filenames ending in .gz or .bz2 will be - uncompressed. - - Returns - ------- - G : NetworkX graph - - Examples - -------- - G=nx.read_leda('file.leda') - - References - ---------- - .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - """ - lines = (line.decode(encoding) for line in path) - G = parse_leda(lines) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_leda(lines): - """Read graph in LEDA format from string or iterable. - - Parameters - ---------- - lines : string or iterable - Data in LEDA format. - - Returns - ------- - G : NetworkX graph - - Examples - -------- - G=nx.parse_leda(string) - - References - ---------- - .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - """ - if isinstance(lines, str): - lines = iter(lines.split("\n")) - lines = iter( - [ - line.rstrip("\n") - for line in lines - if not (line.startswith(("#", "\n")) or line == "") - ] - ) - for i in range(3): - next(lines) - # Graph - du = int(next(lines)) # -1=directed, -2=undirected - if du == -1: - G = nx.DiGraph() - else: - G = nx.Graph() - - # Nodes - n = int(next(lines)) # number of nodes - node = {} - for i in range(1, n + 1): # LEDA counts from 1 to n - symbol = next(lines).rstrip().strip("|{}| ") - if symbol == "": - symbol = str(i) # use int if no label - could be trouble - node[i] = symbol - - G.add_nodes_from([s for i, s in node.items()]) - - # Edges - m = int(next(lines)) # number of edges - for i in range(m): - try: - s, t, reversal, label = next(lines).split() - except BaseException as err: - raise NetworkXError(f"Too few fields in LEDA.GRAPH edge {i+1}") from err - # BEWARE: no handling of reversal edges - G.add_edge(node[int(s)], node[int(t)], label=label[2:-2]) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/multiline_adjlist.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/multiline_adjlist.py deleted file mode 100644 index 808445d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/multiline_adjlist.py +++ /dev/null @@ -1,393 +0,0 @@ -""" -************************* -Multi-line Adjacency List -************************* -Read and write NetworkX graphs as multi-line adjacency lists. - -The multi-line adjacency list format is useful for graphs with -nodes that can be meaningfully represented as strings. With this format -simple edge data can be stored but node or graph data is not. - -Format ------- -The first label in a line is the source node label followed by the node degree -d. The next d lines are target node labels and optional edge data. -That pattern repeats for all nodes in the graph. - -The graph with edges a-b, a-c, d-e can be represented as the following -adjacency list (anything following the # in a line is a comment):: - - # example.multiline-adjlist - a 2 - b - c - d 1 - e -""" - -__all__ = [ - "generate_multiline_adjlist", - "write_multiline_adjlist", - "parse_multiline_adjlist", - "read_multiline_adjlist", -] - -import networkx as nx -from networkx.utils import open_file - - -def generate_multiline_adjlist(G, delimiter=" "): - """Generate a single line of the graph G in multiline adjacency list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - Returns - ------- - lines : string - Lines of data in multiline adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> for line in nx.generate_multiline_adjlist(G): - ... print(line) - 0 3 - 1 {} - 2 {} - 3 {} - 1 2 - 2 {} - 3 {} - 2 1 - 3 {} - 3 1 - 4 {} - 4 1 - 5 {} - 5 1 - 6 {} - 6 0 - - See Also - -------- - write_multiline_adjlist, read_multiline_adjlist - """ - if G.is_directed(): - if G.is_multigraph(): - for s, nbrs in G.adjacency(): - nbr_edges = [ - (u, data) - for u, datadict in nbrs.items() - for key, data in datadict.items() - ] - deg = len(nbr_edges) - yield str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield str(u) - else: - yield str(u) + delimiter + str(d) - else: # directed single edges - for s, nbrs in G.adjacency(): - deg = len(nbrs) - yield str(s) + delimiter + str(deg) - for u, d in nbrs.items(): - if d is None: - yield str(u) - else: - yield str(u) + delimiter + str(d) - else: # undirected - if G.is_multigraph(): - seen = set() # helper dict used to avoid duplicate edges - for s, nbrs in G.adjacency(): - nbr_edges = [ - (u, data) - for u, datadict in nbrs.items() - if u not in seen - for key, data in datadict.items() - ] - deg = len(nbr_edges) - yield str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield str(u) - else: - yield str(u) + delimiter + str(d) - seen.add(s) - else: # undirected single edges - seen = set() # helper dict used to avoid duplicate edges - for s, nbrs in G.adjacency(): - nbr_edges = [(u, d) for u, d in nbrs.items() if u not in seen] - deg = len(nbr_edges) - yield str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield str(u) - else: - yield str(u) + delimiter + str(d) - seen.add(s) - - -@open_file(1, mode="wb") -def write_multiline_adjlist(G, path, delimiter=" ", comments="#", encoding="utf-8"): - """Write the graph G in multiline adjacency list format to path - - Parameters - ---------- - G : NetworkX graph - - path : string or file - Filename or file handle to write to. - Filenames ending in .gz or .bz2 will be compressed. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels - - encoding : string, optional - Text encoding. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_multiline_adjlist(G, "test.adjlist") - - The path can be a file handle or a string with the name of the file. If a - file handle is provided, it has to be opened in 'wb' mode. - - >>> fh = open("test.adjlist", "wb") - >>> nx.write_multiline_adjlist(G, fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G, "test.adjlist.gz") - - See Also - -------- - read_multiline_adjlist - """ - import sys - import time - - pargs = comments + " ".join(sys.argv) - header = ( - f"{pargs}\n" - + comments - + f" GMT {time.asctime(time.gmtime())}\n" - + comments - + f" {G.name}\n" - ) - path.write(header.encode(encoding)) - - for multiline in generate_multiline_adjlist(G, delimiter): - multiline += "\n" - path.write(multiline.encode(encoding)) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_multiline_adjlist( - lines, comments="#", delimiter=None, create_using=None, nodetype=None, edgetype=None -): - """Parse lines of a multiline adjacency list representation of a graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in multiline adjlist format - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - edgetype : Python type, optional - Convert edges to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in multiline adjacency list format. - - Examples - -------- - >>> lines = [ - ... "1 2", - ... "2 {'weight':3, 'name': 'Frodo'}", - ... "3 {}", - ... "2 1", - ... "5 {'weight':6, 'name': 'Saruman'}", - ... ] - >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype=int) - >>> list(G) - [1, 2, 3, 5] - - """ - from ast import literal_eval - - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not line: - continue - try: - (u, deg) = line.rstrip("\n").split(delimiter) - deg = int(deg) - except BaseException as err: - raise TypeError(f"Failed to read node and degree on line ({line})") from err - if nodetype is not None: - try: - u = nodetype(u) - except BaseException as err: - raise TypeError( - f"Failed to convert node ({u}) to type {nodetype}" - ) from err - G.add_node(u) - for i in range(deg): - while True: - try: - line = next(lines) - except StopIteration as err: - msg = f"Failed to find neighbor for node ({u})" - raise TypeError(msg) from err - p = line.find(comments) - if p >= 0: - line = line[:p] - if line: - break - vlist = line.rstrip("\n").split(delimiter) - numb = len(vlist) - if numb < 1: - continue # isolated node - v = vlist.pop(0) - data = "".join(vlist) - if nodetype is not None: - try: - v = nodetype(v) - except BaseException as err: - raise TypeError( - f"Failed to convert node ({v}) to type {nodetype}" - ) from err - if edgetype is not None: - try: - edgedata = {"weight": edgetype(data)} - except BaseException as err: - raise TypeError( - f"Failed to convert edge data ({data}) to type {edgetype}" - ) from err - else: - try: # try to evaluate - edgedata = literal_eval(data) - except: - edgedata = {} - G.add_edge(u, v, **edgedata) - - return G - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_multiline_adjlist( - path, - comments="#", - delimiter=None, - create_using=None, - nodetype=None, - edgetype=None, - encoding="utf-8", -): - """Read graph in multi-line adjacency list format from path. - - Parameters - ---------- - path : string or file - Filename or file handle to read. - Filenames ending in .gz or .bz2 will be uncompressed. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - edgetype : Python type, optional - Convert edge data to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_multiline_adjlist(G, "test.adjlist") - >>> G = nx.read_multiline_adjlist("test.adjlist") - - The path can be a file or a string with the name of the file. If a - file s provided, it has to be opened in 'rb' mode. - - >>> fh = open("test.adjlist", "rb") - >>> G = nx.read_multiline_adjlist(fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G, "test.adjlist.gz") - >>> G = nx.read_multiline_adjlist("test.adjlist.gz") - - The optional nodetype is a function to convert node strings to nodetype. - - For example - - >>> G = nx.read_multiline_adjlist("test.adjlist", nodetype=int) - - will attempt to convert all nodes to integer type. - - The optional edgetype is a function to convert edge data strings to - edgetype. - - >>> G = nx.read_multiline_adjlist("test.adjlist") - - The optional create_using parameter is a NetworkX graph container. - The default is Graph(), an undirected graph. To read the data as - a directed graph use - - >>> G = nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph) - - Notes - ----- - This format does not store graph, node, or edge data. - - See Also - -------- - write_multiline_adjlist - """ - lines = (line.decode(encoding) for line in path) - return parse_multiline_adjlist( - lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - edgetype=edgetype, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/p2g.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/p2g.py deleted file mode 100644 index 804adb2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/p2g.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -This module provides the following: read and write of p2g format -used in metabolic pathway studies. - -See https://web.archive.org/web/20080626113807/http://www.cs.purdue.edu/homes/koyuturk/pathway/ for a description. - -The summary is included here: - -A file that describes a uniquely labeled graph (with extension ".gr") -format looks like the following: - - -name -3 4 -a -1 2 -b - -c -0 2 - -"name" is simply a description of what the graph corresponds to. The -second line displays the number of nodes and number of edges, -respectively. This sample graph contains three nodes labeled "a", "b", -and "c". The rest of the graph contains two lines for each node. The -first line for a node contains the node label. After the declaration -of the node label, the out-edges of that node in the graph are -provided. For instance, "a" is linked to nodes 1 and 2, which are -labeled "b" and "c", while the node labeled "b" has no outgoing -edges. Observe that node labeled "c" has an outgoing edge to -itself. Indeed, self-loops are allowed. Node index starts from 0. - -""" - -import networkx as nx -from networkx.utils import open_file - - -@open_file(1, mode="w") -def write_p2g(G, path, encoding="utf-8"): - """Write NetworkX graph in p2g format. - - Notes - ----- - This format is meant to be used with directed graphs with - possible self loops. - """ - path.write((f"{G.name}\n").encode(encoding)) - path.write((f"{G.order()} {G.size()}\n").encode(encoding)) - nodes = list(G) - # make dictionary mapping nodes to integers - nodenumber = dict(zip(nodes, range(len(nodes)))) - for n in nodes: - path.write((f"{n}\n").encode(encoding)) - for nbr in G.neighbors(n): - path.write((f"{nodenumber[nbr]} ").encode(encoding)) - path.write("\n".encode(encoding)) - - -@open_file(0, mode="r") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_p2g(path, encoding="utf-8"): - """Read graph in p2g format from path. - - Returns - ------- - MultiDiGraph - - Notes - ----- - If you want a DiGraph (with no self loops allowed and no edge data) - use D=nx.DiGraph(read_p2g(path)) - """ - lines = (line.decode(encoding) for line in path) - G = parse_p2g(lines) - return G - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_p2g(lines): - """Parse p2g format graph from string or iterable. - - Returns - ------- - MultiDiGraph - """ - description = next(lines).strip() - # are multiedges (parallel edges) allowed? - G = nx.MultiDiGraph(name=description, selfloops=True) - nnodes, nedges = map(int, next(lines).split()) - nodelabel = {} - nbrs = {} - # loop over the nodes keeping track of node labels and out neighbors - # defer adding edges until all node labels are known - for i in range(nnodes): - n = next(lines).strip() - nodelabel[i] = n - G.add_node(n) - nbrs[n] = map(int, next(lines).split()) - # now we know all of the node labels so we can add the edges - # with the correct labels - for n in G: - for nbr in nbrs[n]: - G.add_edge(n, nodelabel[nbr]) - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/pajek.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/pajek.py deleted file mode 100644 index f148f16..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/pajek.py +++ /dev/null @@ -1,286 +0,0 @@ -""" -***** -Pajek -***** -Read graphs in Pajek format. - -This implementation handles directed and undirected graphs including -those with self loops and parallel edges. - -Format ------- -See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm -for format information. - -""" - -import warnings - -import networkx as nx -from networkx.utils import open_file - -__all__ = ["read_pajek", "parse_pajek", "generate_pajek", "write_pajek"] - - -def generate_pajek(G): - """Generate lines in Pajek graph format. - - Parameters - ---------- - G : graph - A Networkx graph - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - if G.name == "": - name = "NetworkX" - else: - name = G.name - # Apparently many Pajek format readers can't process this line - # So we'll leave it out for now. - # yield '*network %s'%name - - # write nodes with attributes - yield f"*vertices {G.order()}" - nodes = list(G) - # make dictionary mapping nodes to integers - nodenumber = dict(zip(nodes, range(1, len(nodes) + 1))) - for n in nodes: - # copy node attributes and pop mandatory attributes - # to avoid duplication. - na = G.nodes.get(n, {}).copy() - x = na.pop("x", 0.0) - y = na.pop("y", 0.0) - try: - id = int(na.pop("id", nodenumber[n])) - except ValueError as err: - err.args += ( - ( - "Pajek format requires 'id' to be an int()." - " Refer to the 'Relabeling nodes' section." - ), - ) - raise - nodenumber[n] = id - shape = na.pop("shape", "ellipse") - s = " ".join(map(make_qstr, (id, n, x, y, shape))) - # only optional attributes are left in na. - for k, v in na.items(): - if isinstance(v, str) and v.strip() != "": - s += f" {make_qstr(k)} {make_qstr(v)}" - else: - warnings.warn( - f"Node attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}." - ) - yield s - - # write edges with attributes - if G.is_directed(): - yield "*arcs" - else: - yield "*edges" - for u, v, edgedata in G.edges(data=True): - d = edgedata.copy() - value = d.pop("weight", 1.0) # use 1 as default edge value - s = " ".join(map(make_qstr, (nodenumber[u], nodenumber[v], value))) - for k, v in d.items(): - if isinstance(v, str) and v.strip() != "": - s += f" {make_qstr(k)} {make_qstr(v)}" - else: - warnings.warn( - f"Edge attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}." - ) - yield s - - -@open_file(1, mode="wb") -def write_pajek(G, path, encoding="UTF-8"): - """Write graph in Pajek format to path. - - Parameters - ---------- - G : graph - A Networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_pajek(G, "test.net") - - Warnings - -------- - Optional node attributes and edge attributes must be non-empty strings. - Otherwise it will not be written into the file. You will need to - convert those attributes to strings if you want to keep them. - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - for line in generate_pajek(G): - line += "\n" - path.write(line.encode(encoding)) - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_pajek(path, encoding="UTF-8"): - """Read graph in Pajek format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be uncompressed. - - Returns - ------- - G : NetworkX MultiGraph or MultiDiGraph. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_pajek(G, "test.net") - >>> G = nx.read_pajek("test.net") - - To create a Graph instead of a MultiGraph use - - >>> G1 = nx.Graph(G) - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - lines = (line.decode(encoding) for line in path) - return parse_pajek(lines) - - -@nx._dispatchable(graphs=None, returns_graph=True) -def parse_pajek(lines): - """Parse Pajek format graph from string or iterable. - - Parameters - ---------- - lines : string or iterable - Data in Pajek format. - - Returns - ------- - G : NetworkX graph - - See Also - -------- - read_pajek - - """ - import shlex - - # multigraph=False - if isinstance(lines, str): - lines = iter(lines.split("\n")) - lines = iter([line.rstrip("\n") for line in lines]) - G = nx.MultiDiGraph() # are multiedges allowed in Pajek? assume yes - labels = [] # in the order of the file, needed for matrix - while lines: - try: - l = next(lines) - except: # EOF - break - if l.lower().startswith("*network"): - try: - label, name = l.split(None, 1) - except ValueError: - # Line was not of the form: *network NAME - pass - else: - G.graph["name"] = name - elif l.lower().startswith("*vertices"): - nodelabels = {} - l, nnodes = l.split() - for i in range(int(nnodes)): - l = next(lines) - try: - splitline = [ - x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8")) - ] - except AttributeError: - splitline = shlex.split(str(l)) - id, label = splitline[0:2] - labels.append(label) - G.add_node(label) - nodelabels[id] = label - G.nodes[label]["id"] = id - try: - x, y, shape = splitline[2:5] - G.nodes[label].update( - {"x": float(x), "y": float(y), "shape": shape} - ) - except: - pass - extra_attr = zip(splitline[5::2], splitline[6::2]) - G.nodes[label].update(extra_attr) - elif l.lower().startswith("*edges") or l.lower().startswith("*arcs"): - if l.lower().startswith("*edge"): - # switch from multidigraph to multigraph - G = nx.MultiGraph(G) - if l.lower().startswith("*arcs"): - # switch to directed with multiple arcs for each existing edge - G = G.to_directed() - for l in lines: - try: - splitline = [ - x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8")) - ] - except AttributeError: - splitline = shlex.split(str(l)) - - if len(splitline) < 2: - continue - ui, vi = splitline[0:2] - u = nodelabels.get(ui, ui) - v = nodelabels.get(vi, vi) - # parse the data attached to this edge and put in a dictionary - edge_data = {} - try: - # there should always be a single value on the edge? - w = splitline[2:3] - edge_data.update({"weight": float(w[0])}) - except: - pass - # if there isn't, just assign a 1 - # edge_data.update({'value':1}) - extra_attr = zip(splitline[3::2], splitline[4::2]) - edge_data.update(extra_attr) - # if G.has_edge(u,v): - # multigraph=True - G.add_edge(u, v, **edge_data) - elif l.lower().startswith("*matrix"): - G = nx.DiGraph(G) - adj_list = ( - (labels[row], labels[col], {"weight": int(data)}) - for (row, line) in enumerate(lines) - for (col, data) in enumerate(line.split()) - if int(data) != 0 - ) - G.add_edges_from(adj_list) - - return G - - -def make_qstr(t): - """Returns the string representation of t. - Add outer double-quotes if the string has a space. - """ - if not isinstance(t, str): - t = str(t) - if " " in t: - t = f'"{t}"' - return t diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/sparse6.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/sparse6.py deleted file mode 100644 index 74d16db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/sparse6.py +++ /dev/null @@ -1,377 +0,0 @@ -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at https://www.ics.uci.edu/~eppstein/PADS/ is public domain. -"""Functions for reading and writing graphs in the *sparse6* format. - -The *sparse6* file format is a space-efficient format for large sparse -graphs. For small graphs or large dense graphs, use the *graph6* file -format. - -For more information, see the `sparse6`_ homepage. - -.. _sparse6: https://users.cecs.anu.edu.au/~bdm/data/formats.html - -""" - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.readwrite.graph6 import data_to_n, n_to_data -from networkx.utils import not_implemented_for, open_file - -__all__ = ["from_sparse6_bytes", "read_sparse6", "to_sparse6_bytes", "write_sparse6"] - - -def _generate_sparse6_bytes(G, nodes, header): - """Yield bytes in the sparse6 encoding of a graph. - - `G` is an undirected simple graph. `nodes` is the list of nodes for - which the node-induced subgraph will be encoded; if `nodes` is the - list of all nodes in the graph, the entire graph will be - encoded. `header` is a Boolean that specifies whether to generate - the header ``b'>>sparse6<<'`` before the remaining data. - - This function generates `bytes` objects in the following order: - - 1. the header (if requested), - 2. the encoding of the number of nodes, - 3. each character, one-at-a-time, in the encoding of the requested - node-induced subgraph, - 4. a newline character. - - This function raises :exc:`ValueError` if the graph is too large for - the graph6 format (that is, greater than ``2 ** 36`` nodes). - - """ - n = len(G) - if n >= 2**36: - raise ValueError( - "sparse6 is only defined if number of nodes is less than 2 ** 36" - ) - if header: - yield b">>sparse6<<" - yield b":" - for d in n_to_data(n): - yield str.encode(chr(d + 63)) - - k = 1 - while 1 << k < n: - k += 1 - - def enc(x): - """Big endian k-bit encoding of x""" - return [1 if (x & 1 << (k - 1 - i)) else 0 for i in range(k)] - - edges = sorted((max(u, v), min(u, v)) for u, v in G.edges()) - bits = [] - curv = 0 - for v, u in edges: - if v == curv: # current vertex edge - bits.append(0) - bits.extend(enc(u)) - elif v == curv + 1: # next vertex edge - curv += 1 - bits.append(1) - bits.extend(enc(u)) - else: # skip to vertex v and then add edge to u - curv = v - bits.append(1) - bits.extend(enc(v)) - bits.append(0) - bits.extend(enc(u)) - if k < 6 and n == (1 << k) and ((-len(bits)) % 6) >= k and curv < (n - 1): - # Padding special case: small k, n=2^k, - # more than k bits of padding needed, - # current vertex is not (n-1) -- - # appending 1111... would add a loop on (n-1) - bits.append(0) - bits.extend([1] * ((-len(bits)) % 6)) - else: - bits.extend([1] * ((-len(bits)) % 6)) - - data = [ - (bits[i + 0] << 5) - + (bits[i + 1] << 4) - + (bits[i + 2] << 3) - + (bits[i + 3] << 2) - + (bits[i + 4] << 1) - + (bits[i + 5] << 0) - for i in range(0, len(bits), 6) - ] - - for d in data: - yield str.encode(chr(d + 63)) - yield b"\n" - - -@nx._dispatchable(graphs=None, returns_graph=True) -def from_sparse6_bytes(string): - """Read an undirected graph in sparse6 format from string. - - Parameters - ---------- - string : string - Data in sparse6 format - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If the string is unable to be parsed in sparse6 format - - Examples - -------- - >>> G = nx.from_sparse6_bytes(b":A_") - >>> sorted(G.edges()) - [(0, 1), (0, 1), (0, 1)] - - See Also - -------- - read_sparse6, write_sparse6 - - References - ---------- - .. [1] Sparse6 specification - - - """ - if string.startswith(b">>sparse6<<"): - string = string[11:] - if not string.startswith(b":"): - raise NetworkXError("Expected leading colon in sparse6") - - chars = [c - 63 for c in string[1:]] - n, data = data_to_n(chars) - k = 1 - while 1 << k < n: - k += 1 - - def parseData(): - """Returns stream of pairs b[i], x[i] for sparse6 format.""" - chunks = iter(data) - d = None # partial data word - dLen = 0 # how many unparsed bits are left in d - - while 1: - if dLen < 1: - try: - d = next(chunks) - except StopIteration: - return - dLen = 6 - dLen -= 1 - b = (d >> dLen) & 1 # grab top remaining bit - - x = d & ((1 << dLen) - 1) # partially built up value of x - xLen = dLen # how many bits included so far in x - while xLen < k: # now grab full chunks until we have enough - try: - d = next(chunks) - except StopIteration: - return - dLen = 6 - x = (x << 6) + d - xLen += 6 - x = x >> (xLen - k) # shift back the extra bits - dLen = xLen - k - yield b, x - - v = 0 - - G = nx.MultiGraph() - G.add_nodes_from(range(n)) - - multigraph = False - for b, x in parseData(): - if b == 1: - v += 1 - # padding with ones can cause overlarge number here - if x >= n or v >= n: - break - elif x > v: - v = x - else: - if G.has_edge(x, v): - multigraph = True - G.add_edge(x, v) - if not multigraph: - G = nx.Graph(G) - return G - - -def to_sparse6_bytes(G, nodes=None, header=True): - """Convert an undirected graph to bytes in sparse6 format. - - Parameters - ---------- - G : Graph (undirected) - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>sparse6<<' bytes to head of data. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the sparse6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - >>> nx.to_sparse6_bytes(nx.path_graph(2)) - b'>>sparse6<<:An\\n' - - See Also - -------- - to_sparse6_bytes, read_sparse6, write_sparse6_bytes - - Notes - ----- - The returned bytes end with a newline character. - - The format does not support edge or node labels. - - References - ---------- - .. [1] Graph6 specification - - - """ - if nodes is not None: - G = G.subgraph(nodes) - G = nx.convert_node_labels_to_integers(G, ordering="sorted") - return b"".join(_generate_sparse6_bytes(G, nodes, header)) - - -@open_file(0, mode="rb") -@nx._dispatchable(graphs=None, returns_graph=True) -def read_sparse6(path): - """Read an undirected graph in sparse6 format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - - Returns - ------- - G : Graph/Multigraph or list of Graphs/MultiGraphs - If the file contains multiple lines then a list of graphs is returned - - Raises - ------ - NetworkXError - If the string is unable to be parsed in sparse6 format - - Examples - -------- - You can read a sparse6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile(delete=False) as f: - ... _ = f.write(b">>sparse6<<:An\\n") - ... _ = f.seek(0) - ... G = nx.read_sparse6(f.name) - >>> list(G.edges()) - [(0, 1)] - - You can also read a sparse6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b">>sparse6<<:An\\n") - ... _ = f.seek(0) - ... G = nx.read_sparse6(f) - >>> list(G.edges()) - [(0, 1)] - - See Also - -------- - read_sparse6, from_sparse6_bytes - - References - ---------- - .. [1] Sparse6 specification - - - """ - glist = [] - for line in path: - line = line.strip() - if not len(line): - continue - glist.append(from_sparse6_bytes(line)) - if len(glist) == 1: - return glist[0] - else: - return glist - - -@not_implemented_for("directed") -@open_file(1, mode="wb") -def write_sparse6(G, path, nodes=None, header=True): - """Write graph G to given path in sparse6 format. - - Parameters - ---------- - G : Graph (undirected) - - path : file or string - File or filename to write - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by G.nodes() is used. - - header: bool - If True add '>>sparse6<<' string to head of data - - Raises - ------ - NetworkXError - If the graph is directed - - Examples - -------- - You can write a sparse6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile(delete=False) as f: - ... nx.write_sparse6(nx.path_graph(2), f.name) - ... print(f.read()) - b'>>sparse6<<:An\\n' - - You can also write a sparse6 file by giving an open file-like object:: - - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_sparse6(nx.path_graph(2), f) - ... _ = f.seek(0) - ... print(f.read()) - b'>>sparse6<<:An\\n' - - See Also - -------- - read_sparse6, from_sparse6_bytes - - Notes - ----- - The format does not support edge or node labels. - - References - ---------- - .. [1] Sparse6 specification - - - """ - if nodes is not None: - G = G.subgraph(nodes) - G = nx.convert_node_labels_to_integers(G, ordering="sorted") - for b in _generate_sparse6_bytes(G, nodes, header): - path.write(b) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_adjlist.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_adjlist.py deleted file mode 100644 index f2218eb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_adjlist.py +++ /dev/null @@ -1,262 +0,0 @@ -""" -Unit tests for adjlist. -""" - -import io - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, graphs_equal, nodes_equal - - -class TestAdjlist: - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")] - cls.G.add_edges_from(e) - cls.G.add_node("g") - cls.DG = nx.DiGraph(cls.G) - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_read_multiline_adjlist_1(self): - # Unit test for https://networkx.lanl.gov/trac/ticket/252 - s = b"""# comment line -1 2 -# comment line -2 -3 -""" - bytesIO = io.BytesIO(s) - G = nx.read_multiline_adjlist(bytesIO) - adj = {"1": {"3": {}, "2": {}}, "3": {"1": {}}, "2": {"1": {}}} - assert graphs_equal(G, nx.Graph(adj)) - - def test_unicode(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname) - assert graphs_equal(G, H) - - def test_latin1_err(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - fname = tmp_path / "adjlist.txt" - with pytest.raises(UnicodeEncodeError): - nx.write_multiline_adjlist(G, fname, encoding="latin-1") - - def test_latin1(self, tmp_path): - G = nx.Graph() - name1 = "Bj" + chr(246) + "rk" - name2 = chr(220) + "ber" - G.add_edge(name1, "Radiohead", **{name2: 3}) - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname, encoding="latin-1") - H = nx.read_multiline_adjlist(fname, encoding="latin-1") - assert graphs_equal(G, H) - - def test_parse_adjlist(self): - lines = ["1 2 5", "2 3 4", "3 5", "4", "5"] - nx.parse_adjlist(lines, nodetype=int) # smoke test - with pytest.raises(TypeError): - nx.parse_adjlist(lines, nodetype="int") - lines = ["1 2 5", "2 b", "c"] - with pytest.raises(TypeError): - nx.parse_adjlist(lines, nodetype=int) - - def test_adjlist_graph(self, tmp_path): - G = self.G - fname = tmp_path / "adjlist.txt" - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname) - H2 = nx.read_adjlist(fname) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_adjlist_digraph(self, tmp_path): - G = self.DG - fname = tmp_path / "adjlist.txt" - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, create_using=nx.DiGraph()) - H2 = nx.read_adjlist(fname, create_using=nx.DiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_adjlist_integers(self, tmp_path): - fname = tmp_path / "adjlist.txt" - G = nx.convert_node_labels_to_integers(self.G) - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int) - H2 = nx.read_adjlist(fname, nodetype=int) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_adjlist_multigraph(self, tmp_path): - G = self.XG - fname = tmp_path / "adjlist.txt" - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_adjlist_multidigraph(self, tmp_path): - G = self.XDG - fname = tmp_path / "adjlist.txt" - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - H2 = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_adjlist_delimiter(self): - fh = io.BytesIO() - G = nx.path_graph(3) - nx.write_adjlist(G, fh, delimiter=":") - fh.seek(0) - H = nx.read_adjlist(fh, nodetype=int, delimiter=":") - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - -class TestMultilineAdjlist: - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")] - cls.G.add_edges_from(e) - cls.G.add_node("g") - cls.DG = nx.DiGraph(cls.G) - cls.DG.remove_edge("b", "a") - cls.DG.remove_edge("b", "c") - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_parse_multiline_adjlist(self): - lines = [ - "1 2", - "b {'weight':3, 'name': 'Frodo'}", - "c {}", - "d 1", - "e {'weight':6, 'name': 'Saruman'}", - ] - nx.parse_multiline_adjlist(iter(lines)) # smoke test - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines), nodetype=int) - nx.parse_multiline_adjlist(iter(lines), edgetype=str) # smoke test - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines), nodetype=int) - lines = ["1 a"] - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines)) - lines = ["a 2"] - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines), nodetype=int) - lines = ["1 2"] - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines)) - lines = ["1 2", "2 {}"] - with pytest.raises(TypeError): - nx.parse_multiline_adjlist(iter(lines)) - - def test_multiline_adjlist_graph(self, tmp_path): - G = self.G - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname) - H2 = nx.read_multiline_adjlist(fname) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_multiline_adjlist_digraph(self, tmp_path): - G = self.DG - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph()) - H2 = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_multiline_adjlist_integers(self, tmp_path): - fname = tmp_path / "adjlist.txt" - G = nx.convert_node_labels_to_integers(self.G) - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, nodetype=int) - H2 = nx.read_multiline_adjlist(fname, nodetype=int) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_multiline_adjlist_multigraph(self, tmp_path): - G = self.XG - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = nx.read_multiline_adjlist( - fname, nodetype=int, create_using=nx.MultiGraph() - ) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_multiline_adjlist_multidigraph(self, tmp_path): - G = self.XDG - fname = tmp_path / "adjlist.txt" - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist( - fname, nodetype=int, create_using=nx.MultiDiGraph() - ) - H2 = nx.read_multiline_adjlist( - fname, nodetype=int, create_using=nx.MultiDiGraph() - ) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_multiline_adjlist_delimiter(self): - fh = io.BytesIO() - G = nx.path_graph(3) - nx.write_multiline_adjlist(G, fh, delimiter=":") - fh.seek(0) - H = nx.read_multiline_adjlist(fh, nodetype=int, delimiter=":") - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - -@pytest.mark.parametrize( - ("lines", "delim"), - ( - (["1 2 5", "2 3 4", "3 5", "4", "5"], None), # No extra whitespace - (["1\t2\t5", "2\t3\t4", "3\t5", "4", "5"], "\t"), # tab-delimited - ( - ["1\t2\t5", "2\t3\t4", "3\t5\t", "4\t", "5"], - "\t", - ), # tab-delimited, extra delims - ( - ["1\t2\t5", "2\t3\t4", "3\t5\t\t\n", "4\t", "5"], - "\t", - ), # extra delim+newlines - ), -) -def test_adjlist_rstrip_parsing(lines, delim): - """Regression test related to gh-7465""" - expected = nx.Graph([(1, 2), (1, 5), (2, 3), (2, 4), (3, 5)]) - nx.utils.graphs_equal(nx.parse_adjlist(lines, delimiter=delim), expected) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_edgelist.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_edgelist.py deleted file mode 100644 index fe58b3b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_edgelist.py +++ /dev/null @@ -1,314 +0,0 @@ -""" -Unit tests for edgelists. -""" - -import io -import textwrap - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, graphs_equal, nodes_equal - -edges_no_data = textwrap.dedent( - """ - # comment line - 1 2 - # comment line - 2 3 - """ -) - - -edges_with_values = textwrap.dedent( - """ - # comment line - 1 2 2.0 - # comment line - 2 3 3.0 - """ -) - - -edges_with_weight = textwrap.dedent( - """ - # comment line - 1 2 {'weight':2.0} - # comment line - 2 3 {'weight':3.0} - """ -) - - -edges_with_multiple_attrs = textwrap.dedent( - """ - # comment line - 1 2 {'weight':2.0, 'color':'green'} - # comment line - 2 3 {'weight':3.0, 'color':'red'} - """ -) - - -edges_with_multiple_attrs_csv = textwrap.dedent( - """ - # comment line - 1, 2, {'weight':2.0, 'color':'green'} - # comment line - 2, 3, {'weight':3.0, 'color':'red'} - """ -) - - -_expected_edges_weights = [(1, 2, {"weight": 2.0}), (2, 3, {"weight": 3.0})] -_expected_edges_multiattr = [ - (1, 2, {"weight": 2.0, "color": "green"}), - (2, 3, {"weight": 3.0, "color": "red"}), -] - - -@pytest.mark.parametrize( - ("data", "extra_kwargs"), - ( - (edges_no_data, {}), - (edges_with_values, {}), - (edges_with_weight, {}), - (edges_with_multiple_attrs, {}), - (edges_with_multiple_attrs_csv, {"delimiter": ","}), - ), -) -def test_read_edgelist_no_data(data, extra_kwargs): - bytesIO = io.BytesIO(data.encode("utf-8")) - G = nx.read_edgelist(bytesIO, nodetype=int, data=False, **extra_kwargs) - assert edges_equal(G.edges(), [(1, 2), (2, 3)]) - - -def test_read_weighted_edgelist(): - bytesIO = io.BytesIO(edges_with_values.encode("utf-8")) - G = nx.read_weighted_edgelist(bytesIO, nodetype=int) - assert edges_equal(G.edges(data=True), _expected_edges_weights) - - -@pytest.mark.parametrize( - ("data", "extra_kwargs", "expected"), - ( - (edges_with_weight, {}, _expected_edges_weights), - (edges_with_multiple_attrs, {}, _expected_edges_multiattr), - (edges_with_multiple_attrs_csv, {"delimiter": ","}, _expected_edges_multiattr), - ), -) -def test_read_edgelist_with_data(data, extra_kwargs, expected): - bytesIO = io.BytesIO(data.encode("utf-8")) - G = nx.read_edgelist(bytesIO, nodetype=int, **extra_kwargs) - assert edges_equal(G.edges(data=True), expected) - - -@pytest.fixture -def example_graph(): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 3.0), (2, 3, 27.0), (3, 4, 3.0)]) - return G - - -def test_parse_edgelist_no_data(example_graph): - G = example_graph - H = nx.parse_edgelist(["1 2", "2 3", "3 4"], nodetype=int) - assert nodes_equal(G.nodes, H.nodes) - assert edges_equal(G.edges, H.edges) - - -def test_parse_edgelist_with_data_dict(example_graph): - G = example_graph - H = nx.parse_edgelist( - ["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"], nodetype=int - ) - assert nodes_equal(G.nodes, H.nodes) - assert edges_equal(G.edges(data=True), H.edges(data=True)) - - -def test_parse_edgelist_with_data_list(example_graph): - G = example_graph - H = nx.parse_edgelist( - ["1 2 3", "2 3 27", "3 4 3.0"], nodetype=int, data=(("weight", float),) - ) - assert nodes_equal(G.nodes, H.nodes) - assert edges_equal(G.edges(data=True), H.edges(data=True)) - - -def test_parse_edgelist(): - # ignore lines with less than 2 nodes - lines = ["1;2", "2 3", "3 4"] - G = nx.parse_edgelist(lines, nodetype=int) - assert list(G.edges()) == [(2, 3), (3, 4)] - # unknown nodetype - with pytest.raises(TypeError, match="Failed to convert nodes"): - lines = ["1 2", "2 3", "3 4"] - nx.parse_edgelist(lines, nodetype="nope") - # lines have invalid edge format - with pytest.raises(TypeError, match="Failed to convert edge data"): - lines = ["1 2 3", "2 3", "3 4"] - nx.parse_edgelist(lines, nodetype=int) - # edge data and data_keys not the same length - with pytest.raises(IndexError, match="not the same length"): - lines = ["1 2 3", "2 3 27", "3 4 3.0"] - nx.parse_edgelist( - lines, nodetype=int, data=(("weight", float), ("capacity", int)) - ) - # edge data can't be converted to edge type - with pytest.raises(TypeError, match="Failed to convert"): - lines = ["1 2 't1'", "2 3 't3'", "3 4 't3'"] - nx.parse_edgelist(lines, nodetype=int, data=(("weight", float),)) - - -def test_comments_None(): - edgelist = ["node#1 node#2", "node#2 node#3"] - # comments=None supported to ignore all comment characters - G = nx.parse_edgelist(edgelist, comments=None) - H = nx.Graph([e.split(" ") for e in edgelist]) - assert edges_equal(G.edges, H.edges) - - -class TestEdgelist: - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")] - cls.G.add_edges_from(e) - cls.G.add_node("g") - cls.DG = nx.DiGraph(cls.G) - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_write_edgelist_1(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - nx.write_edgelist(G, fh, data=False) - fh.seek(0) - assert fh.read() == b"1 2\n2 3\n" - - def test_write_edgelist_2(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - nx.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {}\n2 3 {}\n" - - def test_write_edgelist_3(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - nx.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {'weight': 2.0}\n2 3 {'weight': 3.0}\n" - - def test_write_edgelist_4(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - nx.write_edgelist(G, fh, data=[("weight")]) - fh.seek(0) - assert fh.read() == b"1 2 2.0\n2 3 3.0\n" - - def test_unicode(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname) - assert graphs_equal(G, H) - - def test_latin1_issue(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", **{name2: 3}) - fname = tmp_path / "el.txt" - with pytest.raises(UnicodeEncodeError): - nx.write_edgelist(G, fname, encoding="latin-1") - - def test_latin1(self, tmp_path): - G = nx.Graph() - name1 = "Bj" + chr(246) + "rk" - name2 = chr(220) + "ber" - G.add_edge(name1, "Radiohead", **{name2: 3}) - fname = tmp_path / "el.txt" - - nx.write_edgelist(G, fname, encoding="latin-1") - H = nx.read_edgelist(fname, encoding="latin-1") - assert graphs_equal(G, H) - - def test_edgelist_graph(self, tmp_path): - G = self.G - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname) - H2 = nx.read_edgelist(fname) - assert H is not H2 # they should be different graphs - G.remove_node("g") # isolated nodes are not written in edgelist - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_digraph(self, tmp_path): - G = self.DG - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, create_using=nx.DiGraph()) - H2 = nx.read_edgelist(fname, create_using=nx.DiGraph()) - assert H is not H2 # they should be different graphs - G.remove_node("g") # isolated nodes are not written in edgelist - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_integers(self, tmp_path): - G = nx.convert_node_labels_to_integers(self.G) - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int) - # isolated nodes are not written in edgelist - G.remove_nodes_from(list(nx.isolates(G))) - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_multigraph(self, tmp_path): - G = self.XG - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - def test_edgelist_multidigraph(self, tmp_path): - G = self.XDG - fname = tmp_path / "el.txt" - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - assert H is not H2 # they should be different graphs - assert nodes_equal(list(H), list(G)) - assert edges_equal(list(H.edges()), list(G.edges())) - - -def test_edgelist_consistent_strip_handling(): - """See gh-7462 - - Input when printed looks like:: - - 1 2 3 - 2 3 - 3 4 3.0 - - Note the trailing \\t after the `3` in the second row, indicating an empty - data value. - """ - s = io.StringIO("1\t2\t3\n2\t3\t\n3\t4\t3.0") - G = nx.parse_edgelist(s, delimiter="\t", nodetype=int, data=[("value", str)]) - assert sorted(G.edges(data="value")) == [(1, 2, "3"), (2, 3, ""), (3, 4, "3.0")] diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gexf.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gexf.py deleted file mode 100644 index 6ff14c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gexf.py +++ /dev/null @@ -1,557 +0,0 @@ -import io -import time - -import pytest - -import networkx as nx - - -class TestGEXF: - @classmethod - def setup_class(cls): - cls.simple_directed_data = """ - - - - - - - - - - - -""" - cls.simple_directed_graph = nx.DiGraph() - cls.simple_directed_graph.add_node("0", label="Hello") - cls.simple_directed_graph.add_node("1", label="World") - cls.simple_directed_graph.add_edge("0", "1", id="0") - - cls.simple_directed_fh = io.BytesIO(cls.simple_directed_data.encode("UTF-8")) - - cls.attribute_data = """\ - - - Gephi.org - A Web network - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - cls.attribute_graph = nx.DiGraph() - cls.attribute_graph.graph["node_default"] = {"frog": True} - cls.attribute_graph.add_node( - "0", label="Gephi", url="https://gephi.org", indegree=1, frog=False - ) - cls.attribute_graph.add_node( - "1", label="Webatlas", url="http://webatlas.fr", indegree=2, frog=False - ) - cls.attribute_graph.add_node( - "2", label="RTGI", url="http://rtgi.fr", indegree=1, frog=True - ) - cls.attribute_graph.add_node( - "3", - label="BarabasiLab", - url="http://barabasilab.com", - indegree=1, - frog=True, - ) - cls.attribute_graph.add_edge("0", "1", id="0", label="foo") - cls.attribute_graph.add_edge("0", "2", id="1") - cls.attribute_graph.add_edge("1", "0", id="2") - cls.attribute_graph.add_edge("2", "1", id="3") - cls.attribute_graph.add_edge("0", "3", id="4") - cls.attribute_fh = io.BytesIO(cls.attribute_data.encode("UTF-8")) - - cls.simple_undirected_data = """ - - - - - - - - - - - -""" - cls.simple_undirected_graph = nx.Graph() - cls.simple_undirected_graph.add_node("0", label="Hello") - cls.simple_undirected_graph.add_node("1", label="World") - cls.simple_undirected_graph.add_edge("0", "1", id="0") - - cls.simple_undirected_fh = io.BytesIO( - cls.simple_undirected_data.encode("UTF-8") - ) - - def test_read_simple_directed_graphml(self): - G = self.simple_directed_graph - H = nx.read_gexf(self.simple_directed_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - def test_write_read_simple_directed_graphml(self): - G = self.simple_directed_graph - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - def test_read_simple_undirected_graphml(self): - G = self.simple_undirected_graph - H = nx.read_gexf(self.simple_undirected_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - self.simple_undirected_fh.seek(0) - - def test_read_attribute_graphml(self): - G = self.attribute_graph - H = nx.read_gexf(self.attribute_fh) - assert sorted(G.nodes(True)) == sorted(H.nodes(data=True)) - ge = sorted(G.edges(data=True)) - he = sorted(H.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - self.attribute_fh.seek(0) - - def test_directed_edge_in_undirected(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_undirected_edge_in_directed(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_key_raises(self): - s = """ - - - - - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_relabel(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_gexf(fh, relabel=True) - assert sorted(G.nodes()) == ["Hello", "Word"] - - def test_default_attribute(self): - G = nx.Graph() - G.add_node(1, label="1", color="green") - nx.add_path(G, [0, 1, 2, 3]) - G.add_edge(1, 2, foo=3) - G.graph["node_default"] = {"color": "yellow"} - G.graph["edge_default"] = {"foo": 7} - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - # Reading a gexf graph always sets mode attribute to either - # 'static' or 'dynamic'. Remove the mode attribute from the - # read graph for the sake of comparing remaining attributes. - del H.graph["mode"] - assert G.graph == H.graph - - def test_serialize_ints_to_strings(self): - G = nx.Graph() - G.add_node(1, id=7, label=77) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert list(H) == [7] - assert H.nodes[7]["label"] == "77" - - def test_write_with_node_attributes(self): - # Addresses #673. - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3)]) - for i in range(4): - G.nodes[i]["id"] = i - G.nodes[i]["label"] = i - G.nodes[i]["pid"] = i - G.nodes[i]["start"] = i - G.nodes[i]["end"] = i + 1 - - expected = f""" - - NetworkX {nx.__version__} - - - - - - - - - - - - - - -""" - obtained = "\n".join(nx.generate_gexf(G)) - assert expected == obtained - - def test_edge_id_construct(self): - G = nx.Graph() - G.add_edges_from([(0, 1, {"id": 0}), (1, 2, {"id": 2}), (2, 3)]) - - expected = f""" - - NetworkX {nx.__version__} - - - - - - - - - - - - - - -""" - - obtained = "\n".join(nx.generate_gexf(G)) - assert expected == obtained - - def test_numpy_type(self): - np = pytest.importorskip("numpy") - G = nx.path_graph(4) - nx.set_node_attributes(G, {n: n for n in np.arange(4)}, "number") - G[0][1]["edge-number"] = np.float64(1.1) - - expected = f""" - - NetworkX {nx.__version__} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - obtained = "\n".join(nx.generate_gexf(G)) - assert expected == obtained - - def test_bool(self): - G = nx.Graph() - G.add_node(1, testattr=True) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert H.nodes[1]["testattr"] - - # Test for NaN, INF and -INF - def test_specials(self): - from math import isnan - - inf, nan = float("inf"), float("nan") - G = nx.Graph() - G.add_node(1, testattr=inf, strdata="inf", key="a") - G.add_node(2, testattr=nan, strdata="nan", key="b") - G.add_node(3, testattr=-inf, strdata="-inf", key="c") - - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - filetext = fh.read() - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - - assert b"INF" in filetext - assert b"NaN" in filetext - assert b"-INF" in filetext - - assert H.nodes[1]["testattr"] == inf - assert isnan(H.nodes[2]["testattr"]) - assert H.nodes[3]["testattr"] == -inf - - assert H.nodes[1]["strdata"] == "inf" - assert H.nodes[2]["strdata"] == "nan" - assert H.nodes[3]["strdata"] == "-inf" - - assert H.nodes[1]["networkx_key"] == "a" - assert H.nodes[2]["networkx_key"] == "b" - assert H.nodes[3]["networkx_key"] == "c" - - def test_simple_list(self): - G = nx.Graph() - list_value = [(1, 2, 3), (9, 1, 2)] - G.add_node(1, key=list_value) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert H.nodes[1]["networkx_key"] == list_value - - def test_dynamic_mode(self): - G = nx.Graph() - G.add_node(1, label="1", color="green") - G.graph["mode"] = "dynamic" - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - def test_multigraph_with_missing_attributes(self): - G = nx.MultiGraph() - G.add_node(0, label="1", color="green") - G.add_node(1, label="2", color="green") - G.add_edge(0, 1, id="0", weight=3, type="undirected", start=0, end=1) - G.add_edge(0, 1, id="1", label="foo", start=0, end=1) - G.add_edge(0, 1) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - def test_missing_viz_attributes(self): - G = nx.Graph() - G.add_node(0, label="1", color="green") - G.nodes[0]["viz"] = {"size": 54} - G.nodes[0]["viz"]["position"] = {"x": 0, "y": 1, "z": 0} - G.nodes[0]["viz"]["color"] = {"r": 0, "g": 0, "b": 256} - G.nodes[0]["viz"]["shape"] = "http://random.url" - G.nodes[0]["viz"]["thickness"] = 2 - fh = io.BytesIO() - nx.write_gexf(G, fh, version="1.1draft") - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - # Test missing alpha value for version >draft1.1 - set default alpha value - # to 1.0 instead of `None` when writing for better general compatibility - fh = io.BytesIO() - # G.nodes[0]["viz"]["color"] does not have an alpha value explicitly defined - # so the default is used instead - nx.write_gexf(G, fh, version="1.2draft") - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert H.nodes[0]["viz"]["color"]["a"] == 1.0 - - # Second graph for the other branch - G = nx.Graph() - G.add_node(0, label="1", color="green") - G.nodes[0]["viz"] = {"size": 54} - G.nodes[0]["viz"]["position"] = {"x": 0, "y": 1, "z": 0} - G.nodes[0]["viz"]["color"] = {"r": 0, "g": 0, "b": 256, "a": 0.5} - G.nodes[0]["viz"]["shape"] = "ftp://random.url" - G.nodes[0]["viz"]["thickness"] = 2 - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - def test_slice_and_spell(self): - # Test spell first, so version = 1.2 - G = nx.Graph() - G.add_node(0, label="1", color="green") - G.nodes[0]["spells"] = [(1, 2)] - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - G = nx.Graph() - G.add_node(0, label="1", color="green") - G.nodes[0]["slices"] = [(1, 2)] - fh = io.BytesIO() - nx.write_gexf(G, fh, version="1.1draft") - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) - - def test_add_parent(self): - G = nx.Graph() - G.add_node(0, label="1", color="green", parents=[1, 2]) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(sorted(e) for e in G.edges()) == sorted( - sorted(e) for e in H.edges() - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gml.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gml.py deleted file mode 100644 index f575ad2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_gml.py +++ /dev/null @@ -1,744 +0,0 @@ -import codecs -import io -import math -from ast import literal_eval -from contextlib import contextmanager -from textwrap import dedent - -import pytest - -import networkx as nx -from networkx.readwrite.gml import literal_destringizer, literal_stringizer - - -class TestGraph: - @classmethod - def setup_class(cls): - cls.simple_data = """Creator "me" -Version "xx" -graph [ - comment "This is a sample graph" - directed 1 - IsPlanar 1 - pos [ x 0 y 1 ] - node [ - id 1 - label "Node 1" - pos [ x 1 y 1 ] - ] - node [ - id 2 - pos [ x 1 y 2 ] - label "Node 2" - ] - node [ - id 3 - label "Node 3" - pos [ x 1 y 3 ] - ] - edge [ - source 1 - target 2 - label "Edge from node 1 to node 2" - color [line "blue" thickness 3] - - ] - edge [ - source 2 - target 3 - label "Edge from node 2 to node 3" - ] - edge [ - source 3 - target 1 - label "Edge from node 3 to node 1" - ] -] -""" - - def test_parse_gml_cytoscape_bug(self): - # example from issue #321, originally #324 in trac - cytoscape_example = """ -Creator "Cytoscape" -Version 1.0 -graph [ - node [ - root_index -3 - id -3 - graphics [ - x -96.0 - y -67.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node2" - ] - node [ - root_index -2 - id -2 - graphics [ - x 63.0 - y 37.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node1" - ] - node [ - root_index -1 - id -1 - graphics [ - x -31.0 - y -17.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node0" - ] - edge [ - root_index -2 - target -2 - source -1 - graphics [ - width 1.5 - fill "#0000ff" - type "line" - Line [ - ] - source_arrow 0 - target_arrow 3 - ] - label "DirectedEdge" - ] - edge [ - root_index -1 - target -1 - source -3 - graphics [ - width 1.5 - fill "#0000ff" - type "line" - Line [ - ] - source_arrow 0 - target_arrow 3 - ] - label "DirectedEdge" - ] -] -""" - nx.parse_gml(cytoscape_example) - - def test_parse_gml(self): - G = nx.parse_gml(self.simple_data, label="label") - assert sorted(G.nodes()) == ["Node 1", "Node 2", "Node 3"] - assert sorted(G.edges()) == [ - ("Node 1", "Node 2"), - ("Node 2", "Node 3"), - ("Node 3", "Node 1"), - ] - - assert sorted(G.edges(data=True)) == [ - ( - "Node 1", - "Node 2", - { - "color": {"line": "blue", "thickness": 3}, - "label": "Edge from node 1 to node 2", - }, - ), - ("Node 2", "Node 3", {"label": "Edge from node 2 to node 3"}), - ("Node 3", "Node 1", {"label": "Edge from node 3 to node 1"}), - ] - - def test_read_gml(self, tmp_path): - fname = tmp_path / "test.gml" - with open(fname, "w") as fh: - fh.write(self.simple_data) - Gin = nx.read_gml(fname, label="label") - G = nx.parse_gml(self.simple_data, label="label") - assert sorted(G.nodes(data=True)) == sorted(Gin.nodes(data=True)) - assert sorted(G.edges(data=True)) == sorted(Gin.edges(data=True)) - - def test_labels_are_strings(self): - # GML requires labels to be strings (i.e., in quotes) - answer = """graph [ - node [ - id 0 - label "1203" - ] -]""" - G = nx.Graph() - G.add_node(1203) - data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) - assert data == answer - - def test_relabel_duplicate(self): - data = """ -graph -[ - label "" - directed 1 - node - [ - id 0 - label "same" - ] - node - [ - id 1 - label "same" - ] -] -""" - fh = io.BytesIO(data.encode("UTF-8")) - fh.seek(0) - pytest.raises(nx.NetworkXError, nx.read_gml, fh, label="label") - - @pytest.mark.parametrize("stringizer", (None, literal_stringizer)) - def test_tuplelabels(self, stringizer): - # https://github.com/networkx/networkx/pull/1048 - # Writing tuple labels to GML failed. - G = nx.Graph() - G.add_edge((0, 1), (1, 0)) - data = "\n".join(nx.generate_gml(G, stringizer=stringizer)) - answer = """graph [ - node [ - id 0 - label "(0,1)" - ] - node [ - id 1 - label "(1,0)" - ] - edge [ - source 0 - target 1 - ] -]""" - assert data == answer - - def test_quotes(self, tmp_path): - # https://github.com/networkx/networkx/issues/1061 - # Encoding quotes as HTML entities. - G = nx.path_graph(1) - G.name = "path_graph(1)" - attr = 'This is "quoted" and this is a copyright: ' + chr(169) - G.nodes[0]["demo"] = attr - with open(tmp_path / "test.gml", "w+b") as fobj: - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode("ascii") - answer = """graph [ - name "path_graph(1)" - node [ - id 0 - label "0" - demo "This is "quoted" and this is a copyright: ©" - ] -]""" - assert data == answer - - def test_unicode_node(self, tmp_path): - node = "node" + chr(169) - G = nx.Graph() - G.add_node(node) - with open(tmp_path / "test.gml", "w+b") as fobj: - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode("ascii") - answer = """graph [ - node [ - id 0 - label "node©" - ] -]""" - assert data == answer - - def test_float_label(self, tmp_path): - node = 1.0 - G = nx.Graph() - G.add_node(node) - with open(tmp_path / "test.gml", "w+b") as fobj: - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode("ascii") - answer = """graph [ - node [ - id 0 - label "1.0" - ] -]""" - assert data == answer - - def test_special_float_label(self, tmp_path): - special_floats = [float("nan"), float("+inf"), float("-inf")] - try: - import numpy as np - - special_floats += [np.nan, np.inf, np.inf * -1] - except ImportError: - special_floats += special_floats - - G = nx.cycle_graph(len(special_floats)) - attrs = dict(enumerate(special_floats)) - nx.set_node_attributes(G, attrs, "nodefloat") - edges = list(G.edges) - attrs = {edges[i]: value for i, value in enumerate(special_floats)} - nx.set_edge_attributes(G, attrs, "edgefloat") - - with open(tmp_path / "test.gml", "w+b") as fobj: - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode("ascii") - answer = """graph [ - node [ - id 0 - label "0" - nodefloat NAN - ] - node [ - id 1 - label "1" - nodefloat +INF - ] - node [ - id 2 - label "2" - nodefloat -INF - ] - node [ - id 3 - label "3" - nodefloat NAN - ] - node [ - id 4 - label "4" - nodefloat +INF - ] - node [ - id 5 - label "5" - nodefloat -INF - ] - edge [ - source 0 - target 1 - edgefloat NAN - ] - edge [ - source 0 - target 5 - edgefloat +INF - ] - edge [ - source 1 - target 2 - edgefloat -INF - ] - edge [ - source 2 - target 3 - edgefloat NAN - ] - edge [ - source 3 - target 4 - edgefloat +INF - ] - edge [ - source 4 - target 5 - edgefloat -INF - ] -]""" - assert data == answer - - fobj.seek(0) - graph = nx.read_gml(fobj) - for indx, value in enumerate(special_floats): - node_value = graph.nodes[str(indx)]["nodefloat"] - if math.isnan(value): - assert math.isnan(node_value) - else: - assert node_value == value - - edge = edges[indx] - string_edge = (str(edge[0]), str(edge[1])) - edge_value = graph.edges[string_edge]["edgefloat"] - if math.isnan(value): - assert math.isnan(edge_value) - else: - assert edge_value == value - - def test_name(self): - G = nx.parse_gml('graph [ name "x" node [ id 0 label "x" ] ]') - assert "x" == G.graph["name"] - G = nx.parse_gml('graph [ node [ id 0 label "x" ] ]') - assert "" == G.name - assert "name" not in G.graph - - def test_graph_types(self): - for directed in [None, False, True]: - for multigraph in [None, False, True]: - gml = "graph [" - if directed is not None: - gml += " directed " + str(int(directed)) - if multigraph is not None: - gml += " multigraph " + str(int(multigraph)) - gml += ' node [ id 0 label "0" ]' - gml += " edge [ source 0 target 0 ]" - gml += " ]" - G = nx.parse_gml(gml) - assert bool(directed) == G.is_directed() - assert bool(multigraph) == G.is_multigraph() - gml = "graph [\n" - if directed is True: - gml += " directed 1\n" - if multigraph is True: - gml += " multigraph 1\n" - gml += """ node [ - id 0 - label "0" - ] - edge [ - source 0 - target 0 -""" - if multigraph: - gml += " key 0\n" - gml += " ]\n]" - assert gml == "\n".join(nx.generate_gml(G)) - - def test_data_types(self): - data = [ - True, - False, - 10**20, - -2e33, - "'", - '"&&&""', - [{(b"\xfd",): "\x7f", chr(0x4444): (1, 2)}, (2, "3")], - ] - data.append(chr(0x14444)) - data.append(literal_eval("{2.3j, 1 - 2.3j, ()}")) - G = nx.Graph() - G.name = data - G.graph["data"] = data - G.add_node(0, int=-1, data={"data": data}) - G.add_edge(0, 0, float=-2.5, data=data) - gml = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) - G = nx.parse_gml(gml, destringizer=literal_destringizer) - assert data == G.name - assert {"name": data, "data": data} == G.graph - assert list(G.nodes(data=True)) == [(0, {"int": -1, "data": {"data": data}})] - assert list(G.edges(data=True)) == [(0, 0, {"float": -2.5, "data": data})] - G = nx.Graph() - G.graph["data"] = "frozenset([1, 2, 3])" - G = nx.parse_gml(nx.generate_gml(G), destringizer=literal_eval) - assert G.graph["data"] == "frozenset([1, 2, 3])" - - def test_escape_unescape(self): - gml = """graph [ - name "&"䑄��&unknown;" -]""" - G = nx.parse_gml(gml) - assert ( - '&"\x0f' + chr(0x4444) + "��&unknown;" - == G.name - ) - gml = "\n".join(nx.generate_gml(G)) - alnu = "#1234567890;&#x1234567890abcdef" - answer = ( - """graph [ - name "&"䑄&""" - + alnu - + """;&unknown;" -]""" - ) - assert answer == gml - - def test_exceptions(self, tmp_path): - pytest.raises(ValueError, literal_destringizer, "(") - pytest.raises(ValueError, literal_destringizer, "frozenset([1, 2, 3])") - pytest.raises(ValueError, literal_destringizer, literal_destringizer) - pytest.raises(ValueError, literal_stringizer, frozenset([1, 2, 3])) - pytest.raises(ValueError, literal_stringizer, literal_stringizer) - with open(tmp_path / "test.gml", "w+b") as f: - f.write(codecs.BOM_UTF8 + b"graph[]") - f.seek(0) - pytest.raises(nx.NetworkXError, nx.read_gml, f) - - def assert_parse_error(gml): - pytest.raises(nx.NetworkXError, nx.parse_gml, gml) - - assert_parse_error(["graph [\n\n", "]"]) - assert_parse_error("") - assert_parse_error('Creator ""') - assert_parse_error("0") - assert_parse_error("graph ]") - assert_parse_error("graph [ 1 ]") - assert_parse_error("graph [ 1.E+2 ]") - assert_parse_error('graph [ "A" ]') - assert_parse_error("graph [ ] graph ]") - assert_parse_error("graph [ ] graph [ ]") - assert_parse_error("graph [ data [1, 2, 3] ]") - assert_parse_error("graph [ node [ ] ]") - assert_parse_error("graph [ node [ id 0 ] ]") - nx.parse_gml('graph [ node [ id "a" ] ]', label="id") - assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 0 label 1 ] ]") - assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 1 label 0 ] ]") - assert_parse_error("graph [ node [ id 0 label 0 ] edge [ ] ]") - assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 ] ]") - nx.parse_gml("graph [edge [ source 0 target 0 ] node [ id 0 label 0 ] ]") - assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 1 target 0 ] ]") - assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 target 1 ] ]") - assert_parse_error( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 ] edge [ source 1 target 0 ] ]" - ) - nx.parse_gml( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 ] edge [ source 1 target 0 ] " - "directed 1 ]" - ) - nx.parse_gml( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 ] edge [ source 0 target 1 ]" - "multigraph 1 ]" - ) - nx.parse_gml( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 ]" - "multigraph 1 ]" - ) - assert_parse_error( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 key 0 ]" - "multigraph 1 ]" - ) - nx.parse_gml( - "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " - "edge [ source 0 target 1 key 0 ] edge [ source 1 target 0 key 0 ]" - "directed 1 multigraph 1 ]" - ) - - # Tests for string convertible alphanumeric id and label values - nx.parse_gml("graph [edge [ source a target a ] node [ id a label b ] ]") - nx.parse_gml( - "graph [ node [ id n42 label 0 ] node [ id x43 label 1 ]" - "edge [ source n42 target x43 key 0 ]" - "edge [ source x43 target n42 key 0 ]" - "directed 1 multigraph 1 ]" - ) - assert_parse_error( - "graph [edge [ source '\u4200' target '\u4200' ] " - + "node [ id '\u4200' label b ] ]" - ) - - def assert_generate_error(*args, **kwargs): - pytest.raises( - nx.NetworkXError, lambda: list(nx.generate_gml(*args, **kwargs)) - ) - - G = nx.Graph() - G.graph[3] = 3 - assert_generate_error(G) - G = nx.Graph() - G.graph["3"] = 3 - assert_generate_error(G) - G = nx.Graph() - G.graph["data"] = frozenset([1, 2, 3]) - assert_generate_error(G, stringizer=literal_stringizer) - - def test_label_kwarg(self): - G = nx.parse_gml(self.simple_data, label="id") - assert sorted(G.nodes) == [1, 2, 3] - labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] - assert labels == ["Node 1", "Node 2", "Node 3"] - - G = nx.parse_gml(self.simple_data, label=None) - assert sorted(G.nodes) == [1, 2, 3] - labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] - assert labels == ["Node 1", "Node 2", "Node 3"] - - def test_outofrange_integers(self, tmp_path): - # GML restricts integers to 32 signed bits. - # Check that we honor this restriction on export - G = nx.Graph() - # Test export for numbers that barely fit or don't fit into 32 bits, - # and 3 numbers in the middle - numbers = { - "toosmall": (-(2**31)) - 1, - "small": -(2**31), - "med1": -4, - "med2": 0, - "med3": 17, - "big": (2**31) - 1, - "toobig": 2**31, - } - G.add_node("Node", **numbers) - - fname = tmp_path / "test.gml" - nx.write_gml(G, fname) - # Check that the export wrote the nonfitting numbers as strings - G2 = nx.read_gml(fname) - for attr, value in G2.nodes["Node"].items(): - if attr == "toosmall" or attr == "toobig": - assert type(value) == str - else: - assert type(value) == int - - def test_multiline(self): - # example from issue #6836 - multiline_example = """ -graph -[ - node - [ - id 0 - label "multiline node" - label2 "multiline1 - multiline2 - multiline3" - alt_name "id 0" - ] -] -""" - G = nx.parse_gml(multiline_example) - assert G.nodes["multiline node"] == { - "label2": "multiline1 multiline2 multiline3", - "alt_name": "id 0", - } - - -@contextmanager -def byte_file(): - _file_handle = io.BytesIO() - yield _file_handle - _file_handle.seek(0) - - -class TestPropertyLists: - def test_writing_graph_with_multi_element_property_list(self): - g = nx.Graph() - g.add_node("n1", properties=["element", 0, 1, 2.5, True, False]) - with byte_file() as f: - nx.write_gml(g, f) - result = f.read().decode() - - assert result == dedent( - """\ - graph [ - node [ - id 0 - label "n1" - properties "element" - properties 0 - properties 1 - properties 2.5 - properties 1 - properties 0 - ] - ] - """ - ) - - def test_writing_graph_with_one_element_property_list(self): - g = nx.Graph() - g.add_node("n1", properties=["element"]) - with byte_file() as f: - nx.write_gml(g, f) - result = f.read().decode() - - assert result == dedent( - """\ - graph [ - node [ - id 0 - label "n1" - properties "_networkx_list_start" - properties "element" - ] - ] - """ - ) - - def test_reading_graph_with_list_property(self): - with byte_file() as f: - f.write( - dedent( - """ - graph [ - node [ - id 0 - label "n1" - properties "element" - properties 0 - properties 1 - properties 2.5 - ] - ] - """ - ).encode("ascii") - ) - f.seek(0) - graph = nx.read_gml(f) - assert graph.nodes(data=True)["n1"] == {"properties": ["element", 0, 1, 2.5]} - - def test_reading_graph_with_single_element_list_property(self): - with byte_file() as f: - f.write( - dedent( - """ - graph [ - node [ - id 0 - label "n1" - properties "_networkx_list_start" - properties "element" - ] - ] - """ - ).encode("ascii") - ) - f.seek(0) - graph = nx.read_gml(f) - assert graph.nodes(data=True)["n1"] == {"properties": ["element"]} - - -@pytest.mark.parametrize("coll", ([], ())) -def test_stringize_empty_list_tuple(coll): - G = nx.path_graph(2) - G.nodes[0]["test"] = coll # test serializing an empty collection - f = io.BytesIO() - nx.write_gml(G, f) # Smoke test - should not raise - f.seek(0) - H = nx.read_gml(f) - assert H.nodes["0"]["test"] == coll # Check empty list round-trips properly - # Check full round-tripping. Note that nodes are loaded as strings by - # default, so there needs to be some remapping prior to comparison - H = nx.relabel_nodes(H, {"0": 0, "1": 1}) - assert nx.utils.graphs_equal(G, H) - # Same as above, but use destringizer for node remapping. Should have no - # effect on node attr - f.seek(0) - H = nx.read_gml(f, destringizer=int) - assert nx.utils.graphs_equal(G, H) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_graph6.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_graph6.py deleted file mode 100644 index a803269..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_graph6.py +++ /dev/null @@ -1,168 +0,0 @@ -from io import BytesIO - -import pytest - -import networkx as nx -import networkx.readwrite.graph6 as g6 -from networkx.utils import edges_equal, nodes_equal - - -class TestGraph6Utils: - def test_n_data_n_conversion(self): - for i in [0, 1, 42, 62, 63, 64, 258047, 258048, 7744773, 68719476735]: - assert g6.data_to_n(g6.n_to_data(i))[0] == i - assert g6.data_to_n(g6.n_to_data(i))[1] == [] - assert g6.data_to_n(g6.n_to_data(i) + [42, 43])[1] == [42, 43] - - -class TestFromGraph6Bytes: - def test_from_graph6_bytes(self): - data = b"DF{" - G = nx.from_graph6_bytes(data) - assert nodes_equal(G.nodes(), [0, 1, 2, 3, 4]) - assert edges_equal( - G.edges(), [(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - ) - - def test_read_equals_from_bytes(self): - data = b"DF{" - G = nx.from_graph6_bytes(data) - fh = BytesIO(data) - Gin = nx.read_graph6(fh) - assert nodes_equal(G.nodes(), Gin.nodes()) - assert edges_equal(G.edges(), Gin.edges()) - - -class TestReadGraph6: - def test_read_many_graph6(self): - """Test for reading many graphs from a file into a list.""" - data = b"DF{\nD`{\nDqK\nD~{\n" - fh = BytesIO(data) - glist = nx.read_graph6(fh) - assert len(glist) == 4 - for G in glist: - assert sorted(G) == list(range(5)) - - -class TestWriteGraph6: - """Unit tests for writing a graph to a file in graph6 format.""" - - def test_null_graph(self): - result = BytesIO() - nx.write_graph6(nx.null_graph(), result) - assert result.getvalue() == b">>graph6<>graph6<<@\n" - - def test_complete_graph(self): - result = BytesIO() - nx.write_graph6(nx.complete_graph(4), result) - assert result.getvalue() == b">>graph6<>graph6<>graph6<>graph6<>graph6<<@\n" - - def test_complete_graph(self): - assert g6.to_graph6_bytes(nx.complete_graph(4)) == b">>graph6<>graph6< - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - cls.simple_directed_graph = nx.DiGraph() - cls.simple_directed_graph.add_node("n10") - cls.simple_directed_graph.add_edge("n0", "n2", id="foo") - cls.simple_directed_graph.add_edge("n0", "n2") - cls.simple_directed_graph.add_edges_from( - [ - ("n1", "n2"), - ("n2", "n3"), - ("n3", "n5"), - ("n3", "n4"), - ("n4", "n6"), - ("n6", "n5"), - ("n5", "n7"), - ("n6", "n8"), - ("n8", "n7"), - ("n8", "n9"), - ] - ) - cls.simple_directed_fh = io.BytesIO(cls.simple_directed_data.encode("UTF-8")) - - cls.attribute_data = """ - - - yellow - - - - - green - - - - blue - - - red - - - - turquoise - - - 1.0 - - - 1.0 - - - 2.0 - - - - - - 1.1 - - - -""" - cls.attribute_graph = nx.DiGraph(id="G") - cls.attribute_graph.graph["node_default"] = {"color": "yellow"} - cls.attribute_graph.add_node("n0", color="green") - cls.attribute_graph.add_node("n2", color="blue") - cls.attribute_graph.add_node("n3", color="red") - cls.attribute_graph.add_node("n4") - cls.attribute_graph.add_node("n5", color="turquoise") - cls.attribute_graph.add_edge("n0", "n2", id="e0", weight=1.0) - cls.attribute_graph.add_edge("n0", "n1", id="e1", weight=1.0) - cls.attribute_graph.add_edge("n1", "n3", id="e2", weight=2.0) - cls.attribute_graph.add_edge("n3", "n2", id="e3") - cls.attribute_graph.add_edge("n2", "n4", id="e4") - cls.attribute_graph.add_edge("n3", "n5", id="e5") - cls.attribute_graph.add_edge("n5", "n4", id="e6", weight=1.1) - cls.attribute_fh = io.BytesIO(cls.attribute_data.encode("UTF-8")) - - cls.node_attribute_default_data = """ - - false - 0 - 0 - 0.0 - 0.0 - Foo - - - - - - - """ - cls.node_attribute_default_graph = nx.DiGraph(id="G") - cls.node_attribute_default_graph.graph["node_default"] = { - "boolean_attribute": False, - "int_attribute": 0, - "long_attribute": 0, - "float_attribute": 0.0, - "double_attribute": 0.0, - "string_attribute": "Foo", - } - cls.node_attribute_default_graph.add_node("n0") - cls.node_attribute_default_graph.add_node("n1") - cls.node_attribute_default_graph.add_edge("n0", "n1", id="e0") - cls.node_attribute_default_fh = io.BytesIO( - cls.node_attribute_default_data.encode("UTF-8") - ) - - cls.attribute_named_key_ids_data = """ - - - - - - - val1 - val2 - - - val_one - val2 - - - edge_value - - - -""" - cls.attribute_named_key_ids_graph = nx.DiGraph() - cls.attribute_named_key_ids_graph.add_node("0", prop1="val1", prop2="val2") - cls.attribute_named_key_ids_graph.add_node("1", prop1="val_one", prop2="val2") - cls.attribute_named_key_ids_graph.add_edge("0", "1", edge_prop="edge_value") - fh = io.BytesIO(cls.attribute_named_key_ids_data.encode("UTF-8")) - cls.attribute_named_key_ids_fh = fh - - cls.attribute_numeric_type_data = """ - - - - - - 1 - - - 2.0 - - - 1 - - - k - - - 1.0 - - - -""" - cls.attribute_numeric_type_graph = nx.DiGraph() - cls.attribute_numeric_type_graph.add_node("n0", weight=1) - cls.attribute_numeric_type_graph.add_node("n1", weight=2.0) - cls.attribute_numeric_type_graph.add_edge("n0", "n1", weight=1) - cls.attribute_numeric_type_graph.add_edge("n1", "n1", weight=1.0) - fh = io.BytesIO(cls.attribute_numeric_type_data.encode("UTF-8")) - cls.attribute_numeric_type_fh = fh - - cls.simple_undirected_data = """ - - - - - - - - - - -""" - # - cls.simple_undirected_graph = nx.Graph() - cls.simple_undirected_graph.add_node("n10") - cls.simple_undirected_graph.add_edge("n0", "n2", id="foo") - cls.simple_undirected_graph.add_edges_from([("n1", "n2"), ("n2", "n3")]) - fh = io.BytesIO(cls.simple_undirected_data.encode("UTF-8")) - cls.simple_undirected_fh = fh - - cls.undirected_multigraph_data = """ - - - - - - - - - - -""" - cls.undirected_multigraph = nx.MultiGraph() - cls.undirected_multigraph.add_node("n10") - cls.undirected_multigraph.add_edge("n0", "n2", id="e0") - cls.undirected_multigraph.add_edge("n1", "n2", id="e1") - cls.undirected_multigraph.add_edge("n2", "n1", id="e2") - fh = io.BytesIO(cls.undirected_multigraph_data.encode("UTF-8")) - cls.undirected_multigraph_fh = fh - - cls.undirected_multigraph_no_multiedge_data = """ - - - - - - - - - - -""" - cls.undirected_multigraph_no_multiedge = nx.MultiGraph() - cls.undirected_multigraph_no_multiedge.add_node("n10") - cls.undirected_multigraph_no_multiedge.add_edge("n0", "n2", id="e0") - cls.undirected_multigraph_no_multiedge.add_edge("n1", "n2", id="e1") - cls.undirected_multigraph_no_multiedge.add_edge("n2", "n3", id="e2") - fh = io.BytesIO(cls.undirected_multigraph_no_multiedge_data.encode("UTF-8")) - cls.undirected_multigraph_no_multiedge_fh = fh - - cls.multigraph_only_ids_for_multiedges_data = """ - - - - - - - - - - -""" - cls.multigraph_only_ids_for_multiedges = nx.MultiGraph() - cls.multigraph_only_ids_for_multiedges.add_node("n10") - cls.multigraph_only_ids_for_multiedges.add_edge("n0", "n2") - cls.multigraph_only_ids_for_multiedges.add_edge("n1", "n2", id="e1") - cls.multigraph_only_ids_for_multiedges.add_edge("n2", "n1", id="e2") - fh = io.BytesIO(cls.multigraph_only_ids_for_multiedges_data.encode("UTF-8")) - cls.multigraph_only_ids_for_multiedges_fh = fh - - -class TestReadGraphML(BaseGraphML): - def test_read_simple_directed_graphml(self): - G = self.simple_directed_graph - H = nx.read_graphml(self.simple_directed_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - PG = nx.parse_graphml(self.simple_directed_data) - assert sorted(G.nodes()) == sorted(PG.nodes()) - assert sorted(G.edges()) == sorted(PG.edges()) - assert sorted(G.edges(data=True)) == sorted(PG.edges(data=True)) - - def test_read_simple_undirected_graphml(self): - G = self.simple_undirected_graph - H = nx.read_graphml(self.simple_undirected_fh) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - self.simple_undirected_fh.seek(0) - - PG = nx.parse_graphml(self.simple_undirected_data) - assert nodes_equal(G.nodes(), PG.nodes()) - assert edges_equal(G.edges(), PG.edges()) - - def test_read_undirected_multigraph_graphml(self): - G = self.undirected_multigraph - H = nx.read_graphml(self.undirected_multigraph_fh) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - self.undirected_multigraph_fh.seek(0) - - PG = nx.parse_graphml(self.undirected_multigraph_data) - assert nodes_equal(G.nodes(), PG.nodes()) - assert edges_equal(G.edges(), PG.edges()) - - def test_read_undirected_multigraph_no_multiedge_graphml(self): - G = self.undirected_multigraph_no_multiedge - H = nx.read_graphml(self.undirected_multigraph_no_multiedge_fh) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - self.undirected_multigraph_no_multiedge_fh.seek(0) - - PG = nx.parse_graphml(self.undirected_multigraph_no_multiedge_data) - assert nodes_equal(G.nodes(), PG.nodes()) - assert edges_equal(G.edges(), PG.edges()) - - def test_read_undirected_multigraph_only_ids_for_multiedges_graphml(self): - G = self.multigraph_only_ids_for_multiedges - H = nx.read_graphml(self.multigraph_only_ids_for_multiedges_fh) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - self.multigraph_only_ids_for_multiedges_fh.seek(0) - - PG = nx.parse_graphml(self.multigraph_only_ids_for_multiedges_data) - assert nodes_equal(G.nodes(), PG.nodes()) - assert edges_equal(G.edges(), PG.edges()) - - def test_read_attribute_graphml(self): - G = self.attribute_graph - H = nx.read_graphml(self.attribute_fh) - assert nodes_equal(G.nodes(True), sorted(H.nodes(data=True))) - ge = sorted(G.edges(data=True)) - he = sorted(H.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - self.attribute_fh.seek(0) - - PG = nx.parse_graphml(self.attribute_data) - assert sorted(G.nodes(True)) == sorted(PG.nodes(data=True)) - ge = sorted(G.edges(data=True)) - he = sorted(PG.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - - def test_node_default_attribute_graphml(self): - G = self.node_attribute_default_graph - H = nx.read_graphml(self.node_attribute_default_fh) - assert G.graph["node_default"] == H.graph["node_default"] - - def test_directed_edge_in_undirected(self): - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_undirected_edge_in_directed(self): - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_key_raise(self): - s = """ - - - yellow - - - - - green - - - - blue - - - 1.0 - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_hyperedge_raise(self): - s = """ - - - yellow - - - - - green - - - - blue - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_multigraph_keys(self): - # Test that reading multigraphs uses edge id attributes as keys - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_graphml(fh) - expected = [("n0", "n1", "e0"), ("n0", "n1", "e1")] - assert sorted(G.edges(keys=True)) == expected - fh.seek(0) - H = nx.parse_graphml(s) - assert sorted(H.edges(keys=True)) == expected - - def test_preserve_multi_edge_data(self): - """ - Test that data and keys of edges are preserved on consequent - write and reads - """ - G = nx.MultiGraph() - G.add_node(1) - G.add_node(2) - G.add_edges_from( - [ - # edges with no data, no keys: - (1, 2), - # edges with only data: - (1, 2, {"key": "data_key1"}), - (1, 2, {"id": "data_id2"}), - (1, 2, {"key": "data_key3", "id": "data_id3"}), - # edges with both data and keys: - (1, 2, 103, {"key": "data_key4"}), - (1, 2, 104, {"id": "data_id5"}), - (1, 2, 105, {"key": "data_key6", "id": "data_id7"}), - ] - ) - fh = io.BytesIO() - nx.write_graphml(G, fh) - fh.seek(0) - H = nx.read_graphml(fh, node_type=int) - assert edges_equal(G.edges(data=True, keys=True), H.edges(data=True, keys=True)) - assert G._adj == H._adj - - Gadj = { - str(node): { - str(nbr): {str(ekey): dd for ekey, dd in key_dict.items()} - for nbr, key_dict in nbr_dict.items() - } - for node, nbr_dict in G._adj.items() - } - fh.seek(0) - HH = nx.read_graphml(fh, node_type=str, edge_key_type=str) - assert Gadj == HH._adj - - fh.seek(0) - string_fh = fh.read() - HH = nx.parse_graphml(string_fh, node_type=str, edge_key_type=str) - assert Gadj == HH._adj - - def test_yfiles_extension(self): - data = """ - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - 2 - - - - - - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - -""" - fh = io.BytesIO(data.encode("UTF-8")) - G = nx.read_graphml(fh, force_multigraph=True) - assert list(G.edges()) == [("n0", "n1")] - assert G.has_edge("n0", "n1", key="e0") - assert G.nodes["n0"]["label"] == "1" - assert G.nodes["n1"]["label"] == "2" - assert G.nodes["n2"]["label"] == "3" - assert G.nodes["n0"]["shape_type"] == "rectangle" - assert G.nodes["n1"]["shape_type"] == "rectangle" - assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator" - assert G.nodes["n2"]["description"] == "description\nline1\nline2" - fh.seek(0) - G = nx.read_graphml(fh) - assert list(G.edges()) == [("n0", "n1")] - assert G["n0"]["n1"]["id"] == "e0" - assert G.nodes["n0"]["label"] == "1" - assert G.nodes["n1"]["label"] == "2" - assert G.nodes["n2"]["label"] == "3" - assert G.nodes["n0"]["shape_type"] == "rectangle" - assert G.nodes["n1"]["shape_type"] == "rectangle" - assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator" - assert G.nodes["n2"]["description"] == "description\nline1\nline2" - - H = nx.parse_graphml(data, force_multigraph=True) - assert list(H.edges()) == [("n0", "n1")] - assert H.has_edge("n0", "n1", key="e0") - assert H.nodes["n0"]["label"] == "1" - assert H.nodes["n1"]["label"] == "2" - assert H.nodes["n2"]["label"] == "3" - - H = nx.parse_graphml(data) - assert list(H.edges()) == [("n0", "n1")] - assert H["n0"]["n1"]["id"] == "e0" - assert H.nodes["n0"]["label"] == "1" - assert H.nodes["n1"]["label"] == "2" - assert H.nodes["n2"]["label"] == "3" - - def test_bool(self): - s = """ - - - false - - - - true - - - - false - - - FaLsE - - - True - - - 0 - - - 1 - - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_graphml(fh) - H = nx.parse_graphml(s) - for graph in [G, H]: - assert graph.nodes["n0"]["test"] - assert not graph.nodes["n2"]["test"] - assert not graph.nodes["n3"]["test"] - assert graph.nodes["n4"]["test"] - assert not graph.nodes["n5"]["test"] - assert graph.nodes["n6"]["test"] - - def test_graphml_header_line(self): - good = """ - - - false - - - - true - - - -""" - bad = """ - - - false - - - - true - - - -""" - ugly = """ - - - false - - - - true - - - -""" - for s in (good, bad): - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_graphml(fh) - H = nx.parse_graphml(s) - for graph in [G, H]: - assert graph.nodes["n0"]["test"] - - fh = io.BytesIO(ugly.encode("UTF-8")) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, ugly) - - def test_read_attributes_with_groups(self): - data = """\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - - - - Group 3 - - - - - - - - - - Folder 3 - - - - - - - - - - - - - - - - - - - - - Group 1 - - - - - - - - - - Folder 1 - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - - - Group 2 - - - - - - - - - - Folder 2 - - - - - - - - - - - - - - - - - - 5 - - - - - - - - - - - - - - - - - - - 6 - - - - - - - - - - - - - - - - - - - - - - - 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - # verify that nodes / attributes are correctly read when part of a group - fh = io.BytesIO(data.encode("UTF-8")) - G = nx.read_graphml(fh) - data = [x for _, x in G.nodes(data=True)] - assert len(data) == 9 - for node_data in data: - assert node_data["CustomProperty"] != "" - - def test_long_attribute_type(self): - # test that graphs with attr.type="long" (as produced by botch and - # dose3) can be parsed - s = """ - - - - - 4284 - - -""" - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_graphml(fh) - expected = [("n1", {"cudfversion": 4284})] - assert sorted(G.nodes(data=True)) == expected - fh.seek(0) - H = nx.parse_graphml(s) - assert sorted(H.nodes(data=True)) == expected - - -class TestWriteGraphML(BaseGraphML): - writer = staticmethod(nx.write_graphml_lxml) - - @classmethod - def setup_class(cls): - BaseGraphML.setup_class() - _ = pytest.importorskip("lxml.etree") - - def test_write_interface(self): - try: - import lxml.etree - - assert nx.write_graphml == nx.write_graphml_lxml - except ImportError: - assert nx.write_graphml == nx.write_graphml_xml - - def test_write_read_simple_directed_graphml(self): - G = self.simple_directed_graph - G.graph["hi"] = "there" - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - def test_GraphMLWriter_add_graphs(self): - gmlw = GraphMLWriter() - G = self.simple_directed_graph - H = G.copy() - gmlw.add_graphs([G, H]) - - def test_write_read_simple_no_prettyprint(self): - G = self.simple_directed_graph - G.graph["hi"] = "there" - G.graph["id"] = "1" - fh = io.BytesIO() - self.writer(G, fh, prettyprint=False) - fh.seek(0) - H = nx.read_graphml(fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - def test_write_read_attribute_named_key_ids_graphml(self): - from xml.etree.ElementTree import parse - - G = self.attribute_named_key_ids_graph - fh = io.BytesIO() - self.writer(G, fh, named_key_ids=True) - fh.seek(0) - H = nx.read_graphml(fh) - fh.seek(0) - - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - assert edges_equal(G.edges(data=True), H.edges(data=True)) - self.attribute_named_key_ids_fh.seek(0) - - xml = parse(fh) - # Children are the key elements, and the graph element - children = list(xml.getroot()) - assert len(children) == 4 - - keys = [child.items() for child in children[:3]] - - assert len(keys) == 3 - assert ("id", "edge_prop") in keys[0] - assert ("attr.name", "edge_prop") in keys[0] - assert ("id", "prop2") in keys[1] - assert ("attr.name", "prop2") in keys[1] - assert ("id", "prop1") in keys[2] - assert ("attr.name", "prop1") in keys[2] - - # Confirm the read graph nodes/edge are identical when compared to - # default writing behavior. - default_behavior_fh = io.BytesIO() - nx.write_graphml(G, default_behavior_fh) - default_behavior_fh.seek(0) - H = nx.read_graphml(default_behavior_fh) - - named_key_ids_behavior_fh = io.BytesIO() - nx.write_graphml(G, named_key_ids_behavior_fh, named_key_ids=True) - named_key_ids_behavior_fh.seek(0) - J = nx.read_graphml(named_key_ids_behavior_fh) - - assert all(n1 == n2 for (n1, n2) in zip(H.nodes, J.nodes)) - assert all(e1 == e2 for (e1, e2) in zip(H.edges, J.edges)) - - def test_write_read_attribute_numeric_type_graphml(self): - from xml.etree.ElementTree import parse - - G = self.attribute_numeric_type_graph - fh = io.BytesIO() - self.writer(G, fh, infer_numeric_types=True) - fh.seek(0) - H = nx.read_graphml(fh) - fh.seek(0) - - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - assert edges_equal(G.edges(data=True), H.edges(data=True)) - self.attribute_numeric_type_fh.seek(0) - - xml = parse(fh) - # Children are the key elements, and the graph element - children = list(xml.getroot()) - assert len(children) == 3 - - keys = [child.items() for child in children[:2]] - - assert len(keys) == 2 - assert ("attr.type", "double") in keys[0] - assert ("attr.type", "double") in keys[1] - - def test_more_multigraph_keys(self, tmp_path): - """Writing keys as edge id attributes means keys become strings. - The original keys are stored as data, so read them back in - if `str(key) == edge_id` - This allows the adjacency to remain the same. - """ - G = nx.MultiGraph() - G.add_edges_from([("a", "b", 2), ("a", "b", 3)]) - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname) - assert H.is_multigraph() - assert edges_equal(G.edges(keys=True), H.edges(keys=True)) - assert G._adj == H._adj - - def test_default_attribute(self): - G = nx.Graph(name="Fred") - G.add_node(1, label=1, color="green") - nx.add_path(G, [0, 1, 2, 3]) - G.add_edge(1, 2, weight=3) - G.graph["node_default"] = {"color": "yellow"} - G.graph["edge_default"] = {"weight": 7} - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh, node_type=int) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - assert G.graph == H.graph - - def test_mixed_type_attributes(self): - G = nx.MultiGraph() - G.add_node("n0", special=False) - G.add_node("n1", special=0) - G.add_edge("n0", "n1", special=False) - G.add_edge("n0", "n1", special=0) - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert not H.nodes["n0"]["special"] - assert H.nodes["n1"]["special"] == 0 - assert not H.edges["n0", "n1", 0]["special"] - assert H.edges["n0", "n1", 1]["special"] == 0 - - def test_str_number_mixed_type_attributes(self): - G = nx.MultiGraph() - G.add_node("n0", special="hello") - G.add_node("n1", special=0) - G.add_edge("n0", "n1", special="hello") - G.add_edge("n0", "n1", special=0) - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert H.nodes["n0"]["special"] == "hello" - assert H.nodes["n1"]["special"] == 0 - assert H.edges["n0", "n1", 0]["special"] == "hello" - assert H.edges["n0", "n1", 1]["special"] == 0 - - def test_mixed_int_type_number_attributes(self): - np = pytest.importorskip("numpy") - G = nx.MultiGraph() - G.add_node("n0", special=np.int64(0)) - G.add_node("n1", special=1) - G.add_edge("n0", "n1", special=np.int64(2)) - G.add_edge("n0", "n1", special=3) - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert H.nodes["n0"]["special"] == 0 - assert H.nodes["n1"]["special"] == 1 - assert H.edges["n0", "n1", 0]["special"] == 2 - assert H.edges["n0", "n1", 1]["special"] == 3 - - def test_multigraph_to_graph(self, tmp_path): - # test converting multigraph to graph if no parallel edges found - G = nx.MultiGraph() - G.add_edges_from([("a", "b", 2), ("b", "c", 3)]) # no multiedges - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname) - assert not H.is_multigraph() - H = nx.read_graphml(fname, force_multigraph=True) - assert H.is_multigraph() - - # add a multiedge - G.add_edge("a", "b", "e-id") - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname) - assert H.is_multigraph() - H = nx.read_graphml(fname, force_multigraph=True) - assert H.is_multigraph() - - def test_write_generate_edge_id_from_attribute(self, tmp_path): - from xml.etree.ElementTree import parse - - G = nx.Graph() - G.add_edges_from([("a", "b"), ("b", "c"), ("a", "c")]) - edge_attributes = {e: str(e) for e in G.edges} - nx.set_edge_attributes(G, edge_attributes, "eid") - fname = tmp_path / "test.graphml" - # set edge_id_from_attribute e.g. "eid" for write_graphml() - self.writer(G, fname, edge_id_from_attribute="eid") - # set edge_id_from_attribute e.g. "eid" for generate_graphml() - generator = nx.generate_graphml(G, edge_id_from_attribute="eid") - - H = nx.read_graphml(fname) - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - # NetworkX adds explicit edge "id" from file as attribute - nx.set_edge_attributes(G, edge_attributes, "id") - assert edges_equal(G.edges(data=True), H.edges(data=True)) - - tree = parse(fname) - children = list(tree.getroot()) - assert len(children) == 2 - edge_ids = [ - edge.attrib["id"] - for edge in tree.getroot().findall( - ".//{http://graphml.graphdrawing.org/xmlns}edge" - ) - ] - # verify edge id value is equal to specified attribute value - assert sorted(edge_ids) == sorted(edge_attributes.values()) - - # check graphml generated from generate_graphml() - data = "".join(generator) - J = nx.parse_graphml(data) - assert sorted(G.nodes()) == sorted(J.nodes()) - assert sorted(G.edges()) == sorted(J.edges()) - # NetworkX adds explicit edge "id" from file as attribute - nx.set_edge_attributes(G, edge_attributes, "id") - assert edges_equal(G.edges(data=True), J.edges(data=True)) - - def test_multigraph_write_generate_edge_id_from_attribute(self, tmp_path): - from xml.etree.ElementTree import parse - - G = nx.MultiGraph() - G.add_edges_from([("a", "b"), ("b", "c"), ("a", "c"), ("a", "b")]) - edge_attributes = {e: str(e) for e in G.edges} - nx.set_edge_attributes(G, edge_attributes, "eid") - fname = tmp_path / "test.graphml" - # set edge_id_from_attribute e.g. "eid" for write_graphml() - self.writer(G, fname, edge_id_from_attribute="eid") - # set edge_id_from_attribute e.g. "eid" for generate_graphml() - generator = nx.generate_graphml(G, edge_id_from_attribute="eid") - - H = nx.read_graphml(fname) - assert H.is_multigraph() - H = nx.read_graphml(fname, force_multigraph=True) - assert H.is_multigraph() - - assert nodes_equal(G.nodes(), H.nodes()) - assert edges_equal(G.edges(), H.edges()) - assert sorted(data.get("eid") for u, v, data in H.edges(data=True)) == sorted( - edge_attributes.values() - ) - # NetworkX uses edge_ids as keys in multigraphs if no key - assert sorted(key for u, v, key in H.edges(keys=True)) == sorted( - edge_attributes.values() - ) - - tree = parse(fname) - children = list(tree.getroot()) - assert len(children) == 2 - edge_ids = [ - edge.attrib["id"] - for edge in tree.getroot().findall( - ".//{http://graphml.graphdrawing.org/xmlns}edge" - ) - ] - # verify edge id value is equal to specified attribute value - assert sorted(edge_ids) == sorted(edge_attributes.values()) - - # check graphml generated from generate_graphml() - graphml_data = "".join(generator) - J = nx.parse_graphml(graphml_data) - assert J.is_multigraph() - - assert nodes_equal(G.nodes(), J.nodes()) - assert edges_equal(G.edges(), J.edges()) - assert sorted(data.get("eid") for u, v, data in J.edges(data=True)) == sorted( - edge_attributes.values() - ) - # NetworkX uses edge_ids as keys in multigraphs if no key - assert sorted(key for u, v, key in J.edges(keys=True)) == sorted( - edge_attributes.values() - ) - - def test_numpy_float64(self, tmp_path): - np = pytest.importorskip("numpy") - wt = np.float64(3.4) - G = nx.Graph([(1, 2, {"weight": wt})]) - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=int) - assert G.edges == H.edges - wtG = G[1][2]["weight"] - wtH = H[1][2]["weight"] - assert wtG == pytest.approx(wtH, abs=1e-6) - assert type(wtG) == np.float64 - assert type(wtH) == float - - def test_numpy_float32(self, tmp_path): - np = pytest.importorskip("numpy") - wt = np.float32(3.4) - G = nx.Graph([(1, 2, {"weight": wt})]) - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=int) - assert G.edges == H.edges - wtG = G[1][2]["weight"] - wtH = H[1][2]["weight"] - assert wtG == pytest.approx(wtH, abs=1e-6) - assert type(wtG) == np.float32 - assert type(wtH) == float - - def test_numpy_float64_inference(self, tmp_path): - np = pytest.importorskip("numpy") - G = self.attribute_numeric_type_graph - G.edges[("n1", "n1")]["weight"] = np.float64(1.1) - fname = tmp_path / "test.graphml" - self.writer(G, fname, infer_numeric_types=True) - H = nx.read_graphml(fname) - assert G._adj == H._adj - - def test_unicode_attributes(self, tmp_path): - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - node_type = str - G.add_edge(name1, "Radiohead", foo=name2) - fname = tmp_path / "test.graphml" - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=node_type) - assert G._adj == H._adj - - def test_unicode_escape(self): - # test for handling json escaped strings in python 2 Issue #1880 - import json - - a = {"a": '{"a": "123"}'} # an object with many chars to escape - sa = json.dumps(a) - G = nx.Graph() - G.graph["test"] = sa - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert G.graph["test"] == H.graph["test"] - - -class TestXMLGraphML(TestWriteGraphML): - writer = staticmethod(nx.write_graphml_xml) - - @classmethod - def setup_class(cls): - TestWriteGraphML.setup_class() - - -def test_exception_for_unsupported_datatype_node_attr(): - """Test that a detailed exception is raised when an attribute is of a type - not supported by GraphML, e.g. a list""" - pytest.importorskip("lxml.etree") - # node attribute - G = nx.Graph() - G.add_node(0, my_list_attribute=[0, 1, 2]) - fh = io.BytesIO() - with pytest.raises(TypeError, match="GraphML does not support"): - nx.write_graphml(G, fh) - - -def test_exception_for_unsupported_datatype_edge_attr(): - """Test that a detailed exception is raised when an attribute is of a type - not supported by GraphML, e.g. a list""" - pytest.importorskip("lxml.etree") - # edge attribute - G = nx.Graph() - G.add_edge(0, 1, my_list_attribute=[0, 1, 2]) - fh = io.BytesIO() - with pytest.raises(TypeError, match="GraphML does not support"): - nx.write_graphml(G, fh) - - -def test_exception_for_unsupported_datatype_graph_attr(): - """Test that a detailed exception is raised when an attribute is of a type - not supported by GraphML, e.g. a list""" - pytest.importorskip("lxml.etree") - # graph attribute - G = nx.Graph() - G.graph["my_list_attribute"] = [0, 1, 2] - fh = io.BytesIO() - with pytest.raises(TypeError, match="GraphML does not support"): - nx.write_graphml(G, fh) - - -def test_empty_attribute(): - """Tests that a GraphML string with an empty attribute can be parsed - correctly.""" - s = """ - - - - - - aaa - bbb - - - ccc - - - - """ - fh = io.BytesIO(s.encode("UTF-8")) - G = nx.read_graphml(fh) - assert G.nodes["0"] == {"foo": "aaa", "bar": "bbb"} - assert G.nodes["1"] == {"foo": "ccc", "bar": ""} diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_leda.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_leda.py deleted file mode 100644 index 8ac5ecc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_leda.py +++ /dev/null @@ -1,30 +0,0 @@ -import io - -import networkx as nx - - -class TestLEDA: - def test_parse_leda(self): - data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|""" - G = nx.parse_leda(data) - G = nx.parse_leda(data.split("\n")) - assert sorted(G.nodes()) == ["v1", "v2", "v3", "v4", "v5"] - assert sorted(G.edges(data=True)) == [ - ("v1", "v2", {"label": "4"}), - ("v1", "v3", {"label": "3"}), - ("v2", "v3", {"label": "2"}), - ("v3", "v4", {"label": "3"}), - ("v3", "v5", {"label": "7"}), - ("v4", "v5", {"label": "6"}), - ("v5", "v1", {"label": "foo"}), - ] - - def test_read_LEDA(self): - fh = io.BytesIO() - data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|""" - G = nx.parse_leda(data) - fh.write(data.encode("UTF-8")) - fh.seek(0) - Gin = nx.read_leda(fh) - assert sorted(G.nodes()) == sorted(Gin.nodes()) - assert sorted(G.edges()) == sorted(Gin.edges()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_p2g.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_p2g.py deleted file mode 100644 index e4c50de..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_p2g.py +++ /dev/null @@ -1,62 +0,0 @@ -import io - -import networkx as nx -from networkx.readwrite.p2g import read_p2g, write_p2g -from networkx.utils import edges_equal - - -class TestP2G: - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")] - cls.G.add_edges_from(e) - cls.G.add_node("g") - cls.DG = nx.DiGraph(cls.G) - - def test_read_p2g(self): - s = b"""\ -name -3 4 -a -1 2 -b - -c -0 2 -""" - bytesIO = io.BytesIO(s) - G = read_p2g(bytesIO) - assert G.name == "name" - assert sorted(G) == ["a", "b", "c"] - edges = [(str(u), str(v)) for u, v in G.edges()] - assert edges_equal(G.edges(), [("a", "c"), ("a", "b"), ("c", "a"), ("c", "c")]) - - def test_write_p2g(self): - s = b"""foo -3 2 -1 -1 -2 -2 -3 - -""" - fh = io.BytesIO() - G = nx.DiGraph() - G.name = "foo" - G.add_edges_from([(1, 2), (2, 3)]) - write_p2g(G, fh) - fh.seek(0) - r = fh.read() - assert r == s - - def test_write_read_p2g(self): - fh = io.BytesIO() - G = nx.DiGraph() - G.name = "foo" - G.add_edges_from([("a", "b"), ("b", "c")]) - write_p2g(G, fh) - fh.seek(0) - H = read_p2g(fh) - assert edges_equal(G.edges(), H.edges()) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_pajek.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_pajek.py deleted file mode 100644 index 317ebe8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_pajek.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -Pajek tests -""" - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -class TestPajek: - @classmethod - def setup_class(cls): - cls.data = """*network Tralala\n*vertices 4\n 1 "A1" 0.0938 0.0896 ellipse x_fact 1 y_fact 1\n 2 "Bb" 0.8188 0.2458 ellipse x_fact 1 y_fact 1\n 3 "C" 0.3688 0.7792 ellipse x_fact 1\n 4 "D2" 0.9583 0.8563 ellipse x_fact 1\n*arcs\n1 1 1 h2 0 w 3 c Blue s 3 a1 -130 k1 0.6 a2 -130 k2 0.6 ap 0.5 l "Bezier loop" lc BlueViolet fos 20 lr 58 lp 0.3 la 360\n2 1 1 h2 0 a1 120 k1 1.3 a2 -120 k2 0.3 ap 25 l "Bezier arc" lphi 270 la 180 lr 19 lp 0.5\n1 2 1 h2 0 a1 40 k1 2.8 a2 30 k2 0.8 ap 25 l "Bezier arc" lphi 90 la 0 lp 0.65\n4 2 -1 h2 0 w 1 k1 -2 k2 250 ap 25 l "Circular arc" c Red lc OrangeRed\n3 4 1 p Dashed h2 0 w 2 c OliveGreen ap 25 l "Straight arc" lc PineGreen\n1 3 1 p Dashed h2 0 w 5 k1 -1 k2 -20 ap 25 l "Oval arc" c Brown lc Black\n3 3 -1 h1 6 w 1 h2 12 k1 -2 k2 -15 ap 0.5 l "Circular loop" c Red lc OrangeRed lphi 270 la 180""" - cls.G = nx.MultiDiGraph() - cls.G.add_nodes_from(["A1", "Bb", "C", "D2"]) - cls.G.add_edges_from( - [ - ("A1", "A1"), - ("A1", "Bb"), - ("A1", "C"), - ("Bb", "A1"), - ("C", "C"), - ("C", "D2"), - ("D2", "Bb"), - ] - ) - - cls.G.graph["name"] = "Tralala" - - def test_parse_pajek_simple(self): - # Example without node positions or shape - data = """*Vertices 2\n1 "1"\n2 "2"\n*Edges\n1 2\n2 1""" - G = nx.parse_pajek(data) - assert sorted(G.nodes()) == ["1", "2"] - assert edges_equal(G.edges(), [("1", "2"), ("1", "2")]) - - def test_parse_pajek(self): - G = nx.parse_pajek(self.data) - assert sorted(G.nodes()) == ["A1", "Bb", "C", "D2"] - assert edges_equal( - G.edges(), - [ - ("A1", "A1"), - ("A1", "Bb"), - ("A1", "C"), - ("Bb", "A1"), - ("C", "C"), - ("C", "D2"), - ("D2", "Bb"), - ], - ) - - def test_parse_pajet_mat(self): - data = """*Vertices 3\n1 "one"\n2 "two"\n3 "three"\n*Matrix\n1 1 0\n0 1 0\n0 1 0\n""" - G = nx.parse_pajek(data) - assert set(G.nodes()) == {"one", "two", "three"} - assert G.nodes["two"] == {"id": "2"} - assert edges_equal( - set(G.edges()), - {("one", "one"), ("two", "one"), ("two", "two"), ("two", "three")}, - ) - - def test_read_pajek(self, tmp_path): - G = nx.parse_pajek(self.data) - # Read data from file - fname = tmp_path / "test.pjk" - with open(fname, "wb") as fh: - fh.write(self.data.encode("UTF-8")) - - Gin = nx.read_pajek(fname) - assert sorted(G.nodes()) == sorted(Gin.nodes()) - assert edges_equal(G.edges(), Gin.edges()) - assert self.G.graph == Gin.graph - for n in G: - assert G.nodes[n] == Gin.nodes[n] - - def test_write_pajek(self): - import io - - G = nx.parse_pajek(self.data) - fh = io.BytesIO() - nx.write_pajek(G, fh) - fh.seek(0) - H = nx.read_pajek(fh) - assert nodes_equal(list(G), list(H)) - assert edges_equal(list(G.edges()), list(H.edges())) - # Graph name is left out for now, therefore it is not tested. - # assert_equal(G.graph, H.graph) - - def test_ignored_attribute(self): - import io - - G = nx.Graph() - fh = io.BytesIO() - G.add_node(1, int_attr=1) - G.add_node(2, empty_attr=" ") - G.add_edge(1, 2, int_attr=2) - G.add_edge(2, 3, empty_attr=" ") - - import warnings - - with warnings.catch_warnings(record=True) as w: - nx.write_pajek(G, fh) - assert len(w) == 4 - - def test_noname(self): - # Make sure we can parse a line such as: *network - # Issue #952 - line = "*network\n" - other_lines = self.data.split("\n")[1:] - data = line + "\n".join(other_lines) - G = nx.parse_pajek(data) - - def test_unicode(self): - import io - - G = nx.Graph() - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - G.add_edge(name1, "Radiohead", foo=name2) - fh = io.BytesIO() - nx.write_pajek(G, fh) - fh.seek(0) - H = nx.read_pajek(fh) - assert nodes_equal(list(G), list(H)) - assert edges_equal(list(G.edges()), list(H.edges())) - assert G.graph == H.graph diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_sparse6.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_sparse6.py deleted file mode 100644 index 344ad0e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_sparse6.py +++ /dev/null @@ -1,166 +0,0 @@ -from io import BytesIO - -import pytest - -import networkx as nx -from networkx.utils import edges_equal, nodes_equal - - -class TestSparseGraph6: - def test_from_sparse6_bytes(self): - data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM" - G = nx.from_sparse6_bytes(data) - assert nodes_equal( - sorted(G.nodes()), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], - ) - assert edges_equal( - G.edges(), - [ - (0, 1), - (0, 2), - (0, 3), - (1, 12), - (1, 14), - (2, 13), - (2, 15), - (3, 16), - (3, 17), - (4, 7), - (4, 9), - (4, 11), - (5, 6), - (5, 8), - (5, 9), - (6, 10), - (6, 11), - (7, 8), - (7, 10), - (8, 12), - (9, 15), - (10, 14), - (11, 13), - (12, 16), - (13, 17), - (14, 17), - (15, 16), - ], - ) - - def test_from_bytes_multigraph_graph(self): - graph_data = b":An" - G = nx.from_sparse6_bytes(graph_data) - assert type(G) == nx.Graph - multigraph_data = b":Ab" - M = nx.from_sparse6_bytes(multigraph_data) - assert type(M) == nx.MultiGraph - - def test_read_sparse6(self): - data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM" - G = nx.from_sparse6_bytes(data) - fh = BytesIO(data) - Gin = nx.read_sparse6(fh) - assert nodes_equal(G.nodes(), Gin.nodes()) - assert edges_equal(G.edges(), Gin.edges()) - - def test_read_many_graph6(self): - # Read many graphs into list - data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM\n" b":Q___dCfDEdcEgcbEGbFIaJ`JaHN`IM" - fh = BytesIO(data) - glist = nx.read_sparse6(fh) - assert len(glist) == 2 - for G in glist: - assert nodes_equal( - G.nodes(), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], - ) - - -class TestWriteSparse6: - """Unit tests for writing graphs in the sparse6 format. - - Most of the test cases were checked against the sparse6 encoder in Sage. - - """ - - def test_null_graph(self): - G = nx.null_graph() - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:?\n" - - def test_trivial_graph(self): - G = nx.trivial_graph() - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:@\n" - - def test_empty_graph(self): - G = nx.empty_graph(5) - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:D\n" - - def test_large_empty_graph(self): - G = nx.empty_graph(68) - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:~?@C\n" - - def test_very_large_empty_graph(self): - G = nx.empty_graph(258049) - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:~~???~?@\n" - - def test_complete_graph(self): - G = nx.complete_graph(4) - result = BytesIO() - nx.write_sparse6(G, result) - assert result.getvalue() == b">>sparse6<<:CcKI\n" - - def test_no_header(self): - G = nx.complete_graph(4) - result = BytesIO() - nx.write_sparse6(G, result, header=False) - assert result.getvalue() == b":CcKI\n" - - def test_padding(self): - codes = (b":Cdv", b":DaYn", b":EaYnN", b":FaYnL", b":GaYnLz") - for n, code in enumerate(codes, start=4): - G = nx.path_graph(n) - result = BytesIO() - nx.write_sparse6(G, result, header=False) - assert result.getvalue() == code + b"\n" - - def test_complete_bipartite(self): - G = nx.complete_bipartite_graph(6, 9) - result = BytesIO() - nx.write_sparse6(G, result) - # Compared with sage - expected = b">>sparse6<<:Nk" + b"?G`cJ" * 9 + b"\n" - assert result.getvalue() == expected - - def test_read_write_inverse(self): - for i in list(range(13)) + [31, 47, 62, 63, 64, 72]: - m = min(2 * i, i * i // 2) - g = nx.random_graphs.gnm_random_graph(i, m, seed=i) - gstr = BytesIO() - nx.write_sparse6(g, gstr, header=False) - # Strip the trailing newline. - gstr = gstr.getvalue().rstrip() - g2 = nx.from_sparse6_bytes(gstr) - assert g2.order() == g.order() - assert edges_equal(g2.edges(), g.edges()) - - def test_no_directed_graphs(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.write_sparse6(nx.DiGraph(), BytesIO()) - - def test_write_path(self, tmp_path): - # Get a valid temporary file name - fullfilename = str(tmp_path / "test.s6") - # file should be closed now, so write_sparse6 can open it - nx.write_sparse6(nx.null_graph(), fullfilename) - with open(fullfilename, mode="rb") as fh: - assert fh.read() == b">>sparse6<<:?\n" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_text.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_text.py deleted file mode 100644 index b2b7448..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/tests/test_text.py +++ /dev/null @@ -1,1742 +0,0 @@ -import random -from itertools import product -from textwrap import dedent - -import pytest - -import networkx as nx - - -def test_generate_network_text_forest_directed(): - # Create a directed forest with labels - graph = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph) - for node in graph.nodes: - graph.nodes[node]["label"] = "node_" + chr(ord("a") + node) - - node_target = dedent( - """ - ╙── 0 - ├─╼ 1 - │ ├─╼ 3 - │ └─╼ 4 - └─╼ 2 - ├─╼ 5 - └─╼ 6 - """ - ).strip() - - label_target = dedent( - """ - ╙── node_a - ├─╼ node_b - │ ├─╼ node_d - │ └─╼ node_e - └─╼ node_c - ├─╼ node_f - └─╼ node_g - """ - ).strip() - - # Basic node case - ret = nx.generate_network_text(graph, with_labels=False) - assert "\n".join(ret) == node_target - - # Basic label case - ret = nx.generate_network_text(graph, with_labels=True) - assert "\n".join(ret) == label_target - - -def test_write_network_text_empty_graph(): - def _graph_str(g, **kw): - printbuf = [] - nx.write_network_text(g, printbuf.append, end="", **kw) - return "\n".join(printbuf) - - assert _graph_str(nx.DiGraph()) == "â•™" - assert _graph_str(nx.Graph()) == "â•™" - assert _graph_str(nx.DiGraph(), ascii_only=True) == "+" - assert _graph_str(nx.Graph(), ascii_only=True) == "+" - - -def test_write_network_text_within_forest_glyph(): - g = nx.DiGraph() - g.add_nodes_from([1, 2, 3, 4]) - g.add_edge(2, 4) - lines = [] - write = lines.append - nx.write_network_text(g, path=write, end="") - nx.write_network_text(g, path=write, ascii_only=True, end="") - text = "\n".join(lines) - target = dedent( - """ - ╟── 1 - ╟── 2 - ╎ └─╼ 4 - ╙── 3 - +-- 1 - +-- 2 - : L-> 4 - +-- 3 - """ - ).strip() - assert text == target - - -def test_generate_network_text_directed_multi_tree(): - tree1 = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph) - tree2 = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph) - forest = nx.disjoint_union_all([tree1, tree2]) - ret = "\n".join(nx.generate_network_text(forest)) - - target = dedent( - """ - ╟── 0 - ╎ ├─╼ 1 - ╎ │ ├─╼ 3 - ╎ │ └─╼ 4 - ╎ └─╼ 2 - ╎ ├─╼ 5 - ╎ └─╼ 6 - ╙── 7 - ├─╼ 8 - │ ├─╼ 10 - │ └─╼ 11 - └─╼ 9 - ├─╼ 12 - └─╼ 13 - """ - ).strip() - assert ret == target - - tree3 = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph) - forest = nx.disjoint_union_all([tree1, tree2, tree3]) - ret = "\n".join(nx.generate_network_text(forest, sources=[0, 14, 7])) - - target = dedent( - """ - ╟── 0 - ╎ ├─╼ 1 - ╎ │ ├─╼ 3 - ╎ │ └─╼ 4 - ╎ └─╼ 2 - ╎ ├─╼ 5 - ╎ └─╼ 6 - ╟── 14 - ╎ ├─╼ 15 - ╎ │ ├─╼ 17 - ╎ │ └─╼ 18 - ╎ └─╼ 16 - ╎ ├─╼ 19 - ╎ └─╼ 20 - ╙── 7 - ├─╼ 8 - │ ├─╼ 10 - │ └─╼ 11 - └─╼ 9 - ├─╼ 12 - └─╼ 13 - """ - ).strip() - assert ret == target - - ret = "\n".join( - nx.generate_network_text(forest, sources=[0, 14, 7], ascii_only=True) - ) - - target = dedent( - """ - +-- 0 - : |-> 1 - : | |-> 3 - : | L-> 4 - : L-> 2 - : |-> 5 - : L-> 6 - +-- 14 - : |-> 15 - : | |-> 17 - : | L-> 18 - : L-> 16 - : |-> 19 - : L-> 20 - +-- 7 - |-> 8 - | |-> 10 - | L-> 11 - L-> 9 - |-> 12 - L-> 13 - """ - ).strip() - assert ret == target - - -def test_generate_network_text_undirected_multi_tree(): - tree1 = nx.balanced_tree(r=2, h=2, create_using=nx.Graph) - tree2 = nx.balanced_tree(r=2, h=2, create_using=nx.Graph) - tree2 = nx.relabel_nodes(tree2, {n: n + len(tree1) for n in tree2.nodes}) - forest = nx.union(tree1, tree2) - ret = "\n".join(nx.generate_network_text(forest, sources=[0, 7])) - - target = dedent( - """ - ╟── 0 - ╎ ├── 1 - ╎ │ ├── 3 - ╎ │ └── 4 - ╎ └── 2 - ╎ ├── 5 - ╎ └── 6 - ╙── 7 - ├── 8 - │ ├── 10 - │ └── 11 - └── 9 - ├── 12 - └── 13 - """ - ).strip() - assert ret == target - - ret = "\n".join(nx.generate_network_text(forest, sources=[0, 7], ascii_only=True)) - - target = dedent( - """ - +-- 0 - : |-- 1 - : | |-- 3 - : | L-- 4 - : L-- 2 - : |-- 5 - : L-- 6 - +-- 7 - |-- 8 - | |-- 10 - | L-- 11 - L-- 9 - |-- 12 - L-- 13 - """ - ).strip() - assert ret == target - - -def test_generate_network_text_forest_undirected(): - # Create a directed forest - graph = nx.balanced_tree(r=2, h=2, create_using=nx.Graph) - - node_target0 = dedent( - """ - ╙── 0 - ├── 1 - │ ├── 3 - │ └── 4 - └── 2 - ├── 5 - └── 6 - """ - ).strip() - - # defined starting point - ret = "\n".join(nx.generate_network_text(graph, sources=[0])) - assert ret == node_target0 - - # defined starting point - node_target2 = dedent( - """ - ╙── 2 - ├── 0 - │ └── 1 - │ ├── 3 - │ └── 4 - ├── 5 - └── 6 - """ - ).strip() - ret = "\n".join(nx.generate_network_text(graph, sources=[2])) - assert ret == node_target2 - - -def test_generate_network_text_overspecified_sources(): - """ - When sources are directly specified, we won't be able to determine when we - are in the last component, so there will always be a trailing, leftmost - pipe. - """ - graph = nx.disjoint_union_all( - [ - nx.balanced_tree(r=2, h=1, create_using=nx.DiGraph), - nx.balanced_tree(r=1, h=2, create_using=nx.DiGraph), - nx.balanced_tree(r=2, h=1, create_using=nx.DiGraph), - ] - ) - - # defined starting point - target1 = dedent( - """ - ╟── 0 - ╎ ├─╼ 1 - ╎ └─╼ 2 - ╟── 3 - ╎ └─╼ 4 - ╎ └─╼ 5 - ╟── 6 - ╎ ├─╼ 7 - ╎ └─╼ 8 - """ - ).strip() - - target2 = dedent( - """ - ╟── 0 - ╎ ├─╼ 1 - ╎ └─╼ 2 - ╟── 3 - ╎ └─╼ 4 - ╎ └─╼ 5 - ╙── 6 - ├─╼ 7 - └─╼ 8 - """ - ).strip() - - got1 = "\n".join(nx.generate_network_text(graph, sources=graph.nodes)) - got2 = "\n".join(nx.generate_network_text(graph)) - assert got1 == target1 - assert got2 == target2 - - -def test_write_network_text_iterative_add_directed_edges(): - """ - Walk through the cases going from a disconnected to fully connected graph - """ - graph = nx.DiGraph() - graph.add_nodes_from([1, 2, 3, 4]) - lines = [] - write = lines.append - write("--- initial state ---") - nx.write_network_text(graph, path=write, end="") - for i, j in product(graph.nodes, graph.nodes): - write(f"--- add_edge({i}, {j}) ---") - graph.add_edge(i, j) - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - # defined starting point - target = dedent( - """ - --- initial state --- - ╟── 1 - ╟── 2 - ╟── 3 - ╙── 4 - --- add_edge(1, 1) --- - ╟── 1 ╾ 1 - ╎ └─╼ ... - ╟── 2 - ╟── 3 - ╙── 4 - --- add_edge(1, 2) --- - ╟── 1 ╾ 1 - ╎ ├─╼ 2 - ╎ └─╼ ... - ╟── 3 - ╙── 4 - --- add_edge(1, 3) --- - ╟── 1 ╾ 1 - ╎ ├─╼ 2 - ╎ ├─╼ 3 - ╎ └─╼ ... - ╙── 4 - --- add_edge(1, 4) --- - ╙── 1 ╾ 1 - ├─╼ 2 - ├─╼ 3 - ├─╼ 4 - └─╼ ... - --- add_edge(2, 1) --- - ╙── 2 ╾ 1 - └─╼ 1 ╾ 1 - ├─╼ 3 - ├─╼ 4 - └─╼ ... - --- add_edge(2, 2) --- - ╙── 1 ╾ 1, 2 - ├─╼ 2 ╾ 2 - │ └─╼ ... - ├─╼ 3 - ├─╼ 4 - └─╼ ... - --- add_edge(2, 3) --- - ╙── 1 ╾ 1, 2 - ├─╼ 2 ╾ 2 - │ ├─╼ 3 ╾ 1 - │ └─╼ ... - ├─╼ 4 - └─╼ ... - --- add_edge(2, 4) --- - ╙── 1 ╾ 1, 2 - ├─╼ 2 ╾ 2 - │ ├─╼ 3 ╾ 1 - │ ├─╼ 4 ╾ 1 - │ └─╼ ... - └─╼ ... - --- add_edge(3, 1) --- - ╙── 2 ╾ 1, 2 - ├─╼ 1 ╾ 1, 3 - │ ├─╼ 3 ╾ 2 - │ │ └─╼ ... - │ ├─╼ 4 ╾ 2 - │ └─╼ ... - └─╼ ... - --- add_edge(3, 2) --- - ╙── 3 ╾ 1, 2 - ├─╼ 1 ╾ 1, 2 - │ ├─╼ 2 ╾ 2, 3 - │ │ ├─╼ 4 ╾ 1 - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(3, 3) --- - ╙── 1 ╾ 1, 2, 3 - ├─╼ 2 ╾ 2, 3 - │ ├─╼ 3 ╾ 1, 3 - │ │ └─╼ ... - │ ├─╼ 4 ╾ 1 - │ └─╼ ... - └─╼ ... - --- add_edge(3, 4) --- - ╙── 1 ╾ 1, 2, 3 - ├─╼ 2 ╾ 2, 3 - │ ├─╼ 3 ╾ 1, 3 - │ │ ├─╼ 4 ╾ 1, 2 - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(4, 1) --- - ╙── 2 ╾ 1, 2, 3 - ├─╼ 1 ╾ 1, 3, 4 - │ ├─╼ 3 ╾ 2, 3 - │ │ ├─╼ 4 ╾ 1, 2 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(4, 2) --- - ╙── 3 ╾ 1, 2, 3 - ├─╼ 1 ╾ 1, 2, 4 - │ ├─╼ 2 ╾ 2, 3, 4 - │ │ ├─╼ 4 ╾ 1, 3 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(4, 3) --- - ╙── 4 ╾ 1, 2, 3 - ├─╼ 1 ╾ 1, 2, 3 - │ ├─╼ 2 ╾ 2, 3, 4 - │ │ ├─╼ 3 ╾ 1, 3, 4 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(4, 4) --- - ╙── 1 ╾ 1, 2, 3, 4 - ├─╼ 2 ╾ 2, 3, 4 - │ ├─╼ 3 ╾ 1, 3, 4 - │ │ ├─╼ 4 ╾ 1, 2, 4 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - """ - ).strip() - assert target == text - - -def test_write_network_text_iterative_add_undirected_edges(): - """ - Walk through the cases going from a disconnected to fully connected graph - """ - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4]) - lines = [] - write = lines.append - write("--- initial state ---") - nx.write_network_text(graph, path=write, end="") - for i, j in product(graph.nodes, graph.nodes): - if i == j: - continue - write(f"--- add_edge({i}, {j}) ---") - graph.add_edge(i, j) - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - --- initial state --- - ╟── 1 - ╟── 2 - ╟── 3 - ╙── 4 - --- add_edge(1, 2) --- - ╟── 3 - ╟── 4 - ╙── 1 - └── 2 - --- add_edge(1, 3) --- - ╟── 4 - ╙── 2 - └── 1 - └── 3 - --- add_edge(1, 4) --- - ╙── 2 - └── 1 - ├── 3 - └── 4 - --- add_edge(2, 1) --- - ╙── 2 - └── 1 - ├── 3 - └── 4 - --- add_edge(2, 3) --- - ╙── 4 - └── 1 - ├── 2 - │ └── 3 ─ 1 - └── ... - --- add_edge(2, 4) --- - ╙── 3 - ├── 1 - │ ├── 2 ─ 3 - │ │ └── 4 ─ 1 - │ └── ... - └── ... - --- add_edge(3, 1) --- - ╙── 3 - ├── 1 - │ ├── 2 ─ 3 - │ │ └── 4 ─ 1 - │ └── ... - └── ... - --- add_edge(3, 2) --- - ╙── 3 - ├── 1 - │ ├── 2 ─ 3 - │ │ └── 4 ─ 1 - │ └── ... - └── ... - --- add_edge(3, 4) --- - ╙── 1 - ├── 2 - │ ├── 3 ─ 1 - │ │ └── 4 ─ 1, 2 - │ └── ... - └── ... - --- add_edge(4, 1) --- - ╙── 1 - ├── 2 - │ ├── 3 ─ 1 - │ │ └── 4 ─ 1, 2 - │ └── ... - └── ... - --- add_edge(4, 2) --- - ╙── 1 - ├── 2 - │ ├── 3 ─ 1 - │ │ └── 4 ─ 1, 2 - │ └── ... - └── ... - --- add_edge(4, 3) --- - ╙── 1 - ├── 2 - │ ├── 3 ─ 1 - │ │ └── 4 ─ 1, 2 - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_iterative_add_random_directed_edges(): - """ - Walk through the cases going from a disconnected to fully connected graph - """ - - rng = random.Random(724466096) - graph = nx.DiGraph() - graph.add_nodes_from([1, 2, 3, 4, 5]) - possible_edges = list(product(graph.nodes, graph.nodes)) - rng.shuffle(possible_edges) - graph.add_edges_from(possible_edges[0:8]) - lines = [] - write = lines.append - write("--- initial state ---") - nx.write_network_text(graph, path=write, end="") - for i, j in possible_edges[8:12]: - write(f"--- add_edge({i}, {j}) ---") - graph.add_edge(i, j) - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - --- initial state --- - ╙── 3 ╾ 5 - └─╼ 2 ╾ 2 - ├─╼ 4 ╾ 4 - │ ├─╼ 5 - │ │ ├─╼ 1 ╾ 1 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(4, 1) --- - ╙── 3 ╾ 5 - └─╼ 2 ╾ 2 - ├─╼ 4 ╾ 4 - │ ├─╼ 5 - │ │ ├─╼ 1 ╾ 1, 4 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(2, 1) --- - ╙── 3 ╾ 5 - └─╼ 2 ╾ 2 - ├─╼ 4 ╾ 4 - │ ├─╼ 5 - │ │ ├─╼ 1 ╾ 1, 4, 2 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(5, 2) --- - ╙── 3 ╾ 5 - └─╼ 2 ╾ 2, 5 - ├─╼ 4 ╾ 4 - │ ├─╼ 5 - │ │ ├─╼ 1 ╾ 1, 4, 2 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- add_edge(1, 5) --- - ╙── 3 ╾ 5 - └─╼ 2 ╾ 2, 5 - ├─╼ 4 ╾ 4 - │ ├─╼ 5 ╾ 1 - │ │ ├─╼ 1 ╾ 1, 4, 2 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - - """ - ).strip() - assert target == text - - -def test_write_network_text_nearly_forest(): - g = nx.DiGraph() - g.add_edge(1, 2) - g.add_edge(1, 5) - g.add_edge(2, 3) - g.add_edge(3, 4) - g.add_edge(5, 6) - g.add_edge(6, 7) - g.add_edge(6, 8) - orig = g.copy() - g.add_edge(1, 8) # forward edge - g.add_edge(4, 2) # back edge - g.add_edge(6, 3) # cross edge - lines = [] - write = lines.append - write("--- directed case ---") - nx.write_network_text(orig, path=write, end="") - write("--- add (1, 8), (4, 2), (6, 3) ---") - nx.write_network_text(g, path=write, end="") - write("--- undirected case ---") - nx.write_network_text(orig.to_undirected(), path=write, sources=[1], end="") - write("--- add (1, 8), (4, 2), (6, 3) ---") - nx.write_network_text(g.to_undirected(), path=write, sources=[1], end="") - text = "\n".join(lines) - target = dedent( - """ - --- directed case --- - ╙── 1 - ├─╼ 2 - │ └─╼ 3 - │ └─╼ 4 - └─╼ 5 - └─╼ 6 - ├─╼ 7 - └─╼ 8 - --- add (1, 8), (4, 2), (6, 3) --- - ╙── 1 - ├─╼ 2 ╾ 4 - │ └─╼ 3 ╾ 6 - │ └─╼ 4 - │ └─╼ ... - ├─╼ 5 - │ └─╼ 6 - │ ├─╼ 7 - │ ├─╼ 8 ╾ 1 - │ └─╼ ... - └─╼ ... - --- undirected case --- - ╙── 1 - ├── 2 - │ └── 3 - │ └── 4 - └── 5 - └── 6 - ├── 7 - └── 8 - --- add (1, 8), (4, 2), (6, 3) --- - ╙── 1 - ├── 2 - │ ├── 3 - │ │ ├── 4 ─ 2 - │ │ └── 6 - │ │ ├── 5 ─ 1 - │ │ ├── 7 - │ │ └── 8 ─ 1 - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_complete_graph_ascii_only(): - graph = nx.generators.complete_graph(5, create_using=nx.DiGraph) - lines = [] - write = lines.append - write("--- directed case ---") - nx.write_network_text(graph, path=write, ascii_only=True, end="") - write("--- undirected case ---") - nx.write_network_text(graph.to_undirected(), path=write, ascii_only=True, end="") - text = "\n".join(lines) - target = dedent( - """ - --- directed case --- - +-- 0 <- 1, 2, 3, 4 - |-> 1 <- 2, 3, 4 - | |-> 2 <- 0, 3, 4 - | | |-> 3 <- 0, 1, 4 - | | | |-> 4 <- 0, 1, 2 - | | | | L-> ... - | | | L-> ... - | | L-> ... - | L-> ... - L-> ... - --- undirected case --- - +-- 0 - |-- 1 - | |-- 2 - 0 - | | |-- 3 - 0, 1 - | | | L-- 4 - 0, 1, 2 - | | L-- ... - | L-- ... - L-- ... - """ - ).strip() - assert target == text - - -def test_write_network_text_with_labels(): - graph = nx.generators.complete_graph(5, create_using=nx.DiGraph) - for n in graph.nodes: - graph.nodes[n]["label"] = f"Node(n={n})" - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, with_labels=True, ascii_only=False, end="") - text = "\n".join(lines) - # Non trees with labels can get somewhat out of hand with network text - # because we need to immediately show every non-tree edge to the right - target = dedent( - """ - ╙── Node(n=0) ╾ Node(n=1), Node(n=2), Node(n=3), Node(n=4) - ├─╼ Node(n=1) ╾ Node(n=2), Node(n=3), Node(n=4) - │ ├─╼ Node(n=2) ╾ Node(n=0), Node(n=3), Node(n=4) - │ │ ├─╼ Node(n=3) ╾ Node(n=0), Node(n=1), Node(n=4) - │ │ │ ├─╼ Node(n=4) ╾ Node(n=0), Node(n=1), Node(n=2) - │ │ │ │ └─╼ ... - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - """ - ).strip() - assert target == text - - -def test_write_network_text_complete_graphs(): - lines = [] - write = lines.append - for k in [0, 1, 2, 3, 4, 5]: - g = nx.generators.complete_graph(k) - write(f"--- undirected k={k} ---") - nx.write_network_text(g, path=write, end="") - - for k in [0, 1, 2, 3, 4, 5]: - g = nx.generators.complete_graph(k, nx.DiGraph) - write(f"--- directed k={k} ---") - nx.write_network_text(g, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - --- undirected k=0 --- - â•™ - --- undirected k=1 --- - ╙── 0 - --- undirected k=2 --- - ╙── 0 - └── 1 - --- undirected k=3 --- - ╙── 0 - ├── 1 - │ └── 2 ─ 0 - └── ... - --- undirected k=4 --- - ╙── 0 - ├── 1 - │ ├── 2 ─ 0 - │ │ └── 3 ─ 0, 1 - │ └── ... - └── ... - --- undirected k=5 --- - ╙── 0 - ├── 1 - │ ├── 2 ─ 0 - │ │ ├── 3 ─ 0, 1 - │ │ │ └── 4 ─ 0, 1, 2 - │ │ └── ... - │ └── ... - └── ... - --- directed k=0 --- - â•™ - --- directed k=1 --- - ╙── 0 - --- directed k=2 --- - ╙── 0 ╾ 1 - └─╼ 1 - └─╼ ... - --- directed k=3 --- - ╙── 0 ╾ 1, 2 - ├─╼ 1 ╾ 2 - │ ├─╼ 2 ╾ 0 - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- directed k=4 --- - ╙── 0 ╾ 1, 2, 3 - ├─╼ 1 ╾ 2, 3 - │ ├─╼ 2 ╾ 0, 3 - │ │ ├─╼ 3 ╾ 0, 1 - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- directed k=5 --- - ╙── 0 ╾ 1, 2, 3, 4 - ├─╼ 1 ╾ 2, 3, 4 - │ ├─╼ 2 ╾ 0, 3, 4 - │ │ ├─╼ 3 ╾ 0, 1, 4 - │ │ │ ├─╼ 4 ╾ 0, 1, 2 - │ │ │ │ └─╼ ... - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - """ - ).strip() - assert target == text - - -def test_write_network_text_multiple_sources(): - g = nx.DiGraph() - g.add_edge(1, 2) - g.add_edge(1, 3) - g.add_edge(2, 4) - g.add_edge(3, 5) - g.add_edge(3, 6) - g.add_edge(5, 4) - g.add_edge(4, 1) - g.add_edge(1, 5) - lines = [] - write = lines.append - # Use each node as the starting point to demonstrate how the representation - # changes. - nodes = sorted(g.nodes()) - for n in nodes: - write(f"--- source node: {n} ---") - nx.write_network_text(g, path=write, sources=[n], end="") - text = "\n".join(lines) - target = dedent( - """ - --- source node: 1 --- - ╙── 1 ╾ 4 - ├─╼ 2 - │ └─╼ 4 ╾ 5 - │ └─╼ ... - ├─╼ 3 - │ ├─╼ 5 ╾ 1 - │ │ └─╼ ... - │ └─╼ 6 - └─╼ ... - --- source node: 2 --- - ╙── 2 ╾ 1 - └─╼ 4 ╾ 5 - └─╼ 1 - ├─╼ 3 - │ ├─╼ 5 ╾ 1 - │ │ └─╼ ... - │ └─╼ 6 - └─╼ ... - --- source node: 3 --- - ╙── 3 ╾ 1 - ├─╼ 5 ╾ 1 - │ └─╼ 4 ╾ 2 - │ └─╼ 1 - │ ├─╼ 2 - │ │ └─╼ ... - │ └─╼ ... - └─╼ 6 - --- source node: 4 --- - ╙── 4 ╾ 2, 5 - └─╼ 1 - ├─╼ 2 - │ └─╼ ... - ├─╼ 3 - │ ├─╼ 5 ╾ 1 - │ │ └─╼ ... - │ └─╼ 6 - └─╼ ... - --- source node: 5 --- - ╙── 5 ╾ 3, 1 - └─╼ 4 ╾ 2 - └─╼ 1 - ├─╼ 2 - │ └─╼ ... - ├─╼ 3 - │ ├─╼ 6 - │ └─╼ ... - └─╼ ... - --- source node: 6 --- - ╙── 6 ╾ 3 - """ - ).strip() - assert target == text - - -def test_write_network_text_star_graph(): - graph = nx.star_graph(5, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 1 - └── 0 - ├── 2 - ├── 3 - ├── 4 - └── 5 - """ - ).strip() - assert target == text - - -def test_write_network_text_path_graph(): - graph = nx.path_graph(3, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 0 - └── 1 - └── 2 - """ - ).strip() - assert target == text - - -def test_write_network_text_lollipop_graph(): - graph = nx.lollipop_graph(4, 2, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 5 - └── 4 - └── 3 - ├── 0 - │ ├── 1 ─ 3 - │ │ └── 2 ─ 0, 3 - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_wheel_graph(): - graph = nx.wheel_graph(7, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 1 - ├── 0 - │ ├── 2 ─ 1 - │ │ └── 3 ─ 0 - │ │ └── 4 ─ 0 - │ │ └── 5 ─ 0 - │ │ └── 6 ─ 0, 1 - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_circular_ladder_graph(): - graph = nx.circular_ladder_graph(4, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 0 - ├── 1 - │ ├── 2 - │ │ ├── 3 ─ 0 - │ │ │ └── 7 - │ │ │ ├── 6 ─ 2 - │ │ │ │ └── 5 ─ 1 - │ │ │ │ └── 4 ─ 0, 7 - │ │ │ └── ... - │ │ └── ... - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_dorogovtsev_goltsev_mendes_graph(): - graph = nx.dorogovtsev_goltsev_mendes_graph(4, create_using=nx.Graph) - lines = [] - write = lines.append - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - ╙── 15 - ├── 0 - │ ├── 1 ─ 15 - │ │ ├── 2 ─ 0 - │ │ │ ├── 4 ─ 0 - │ │ │ │ ├── 9 ─ 0 - │ │ │ │ │ ├── 22 ─ 0 - │ │ │ │ │ └── 38 ─ 4 - │ │ │ │ ├── 13 ─ 2 - │ │ │ │ │ ├── 34 ─ 2 - │ │ │ │ │ └── 39 ─ 4 - │ │ │ │ ├── 18 ─ 0 - │ │ │ │ ├── 30 ─ 2 - │ │ │ │ └── ... - │ │ │ ├── 5 ─ 1 - │ │ │ │ ├── 12 ─ 1 - │ │ │ │ │ ├── 29 ─ 1 - │ │ │ │ │ └── 40 ─ 5 - │ │ │ │ ├── 14 ─ 2 - │ │ │ │ │ ├── 35 ─ 2 - │ │ │ │ │ └── 41 ─ 5 - │ │ │ │ ├── 25 ─ 1 - │ │ │ │ ├── 31 ─ 2 - │ │ │ │ └── ... - │ │ │ ├── 7 ─ 0 - │ │ │ │ ├── 20 ─ 0 - │ │ │ │ └── 32 ─ 2 - │ │ │ ├── 10 ─ 1 - │ │ │ │ ├── 27 ─ 1 - │ │ │ │ └── 33 ─ 2 - │ │ │ ├── 16 ─ 0 - │ │ │ ├── 23 ─ 1 - │ │ │ └── ... - │ │ ├── 3 ─ 0 - │ │ │ ├── 8 ─ 0 - │ │ │ │ ├── 21 ─ 0 - │ │ │ │ └── 36 ─ 3 - │ │ │ ├── 11 ─ 1 - │ │ │ │ ├── 28 ─ 1 - │ │ │ │ └── 37 ─ 3 - │ │ │ ├── 17 ─ 0 - │ │ │ ├── 24 ─ 1 - │ │ │ └── ... - │ │ ├── 6 ─ 0 - │ │ │ ├── 19 ─ 0 - │ │ │ └── 26 ─ 1 - │ │ └── ... - │ └── ... - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_tree_max_depth(): - orig = nx.balanced_tree(r=1, h=3, create_using=nx.DiGraph) - lines = [] - write = lines.append - write("--- directed case, max_depth=0 ---") - nx.write_network_text(orig, path=write, end="", max_depth=0) - write("--- directed case, max_depth=1 ---") - nx.write_network_text(orig, path=write, end="", max_depth=1) - write("--- directed case, max_depth=2 ---") - nx.write_network_text(orig, path=write, end="", max_depth=2) - write("--- directed case, max_depth=3 ---") - nx.write_network_text(orig, path=write, end="", max_depth=3) - write("--- directed case, max_depth=4 ---") - nx.write_network_text(orig, path=write, end="", max_depth=4) - write("--- undirected case, max_depth=0 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=0) - write("--- undirected case, max_depth=1 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=1) - write("--- undirected case, max_depth=2 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=2) - write("--- undirected case, max_depth=3 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=3) - write("--- undirected case, max_depth=4 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=4) - text = "\n".join(lines) - target = dedent( - """ - --- directed case, max_depth=0 --- - â•™ ... - --- directed case, max_depth=1 --- - ╙── 0 - └─╼ ... - --- directed case, max_depth=2 --- - ╙── 0 - └─╼ 1 - └─╼ ... - --- directed case, max_depth=3 --- - ╙── 0 - └─╼ 1 - └─╼ 2 - └─╼ ... - --- directed case, max_depth=4 --- - ╙── 0 - └─╼ 1 - └─╼ 2 - └─╼ 3 - --- undirected case, max_depth=0 --- - â•™ ... - --- undirected case, max_depth=1 --- - ╙── 0 ─ 1 - └── ... - --- undirected case, max_depth=2 --- - ╙── 0 - └── 1 ─ 2 - └── ... - --- undirected case, max_depth=3 --- - ╙── 0 - └── 1 - └── 2 ─ 3 - └── ... - --- undirected case, max_depth=4 --- - ╙── 0 - └── 1 - └── 2 - └── 3 - """ - ).strip() - assert target == text - - -def test_write_network_text_graph_max_depth(): - orig = nx.erdos_renyi_graph(10, 0.15, directed=True, seed=40392) - lines = [] - write = lines.append - write("--- directed case, max_depth=None ---") - nx.write_network_text(orig, path=write, end="", max_depth=None) - write("--- directed case, max_depth=0 ---") - nx.write_network_text(orig, path=write, end="", max_depth=0) - write("--- directed case, max_depth=1 ---") - nx.write_network_text(orig, path=write, end="", max_depth=1) - write("--- directed case, max_depth=2 ---") - nx.write_network_text(orig, path=write, end="", max_depth=2) - write("--- directed case, max_depth=3 ---") - nx.write_network_text(orig, path=write, end="", max_depth=3) - write("--- undirected case, max_depth=None ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=None) - write("--- undirected case, max_depth=0 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=0) - write("--- undirected case, max_depth=1 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=1) - write("--- undirected case, max_depth=2 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=2) - write("--- undirected case, max_depth=3 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=3) - text = "\n".join(lines) - target = dedent( - """ - --- directed case, max_depth=None --- - ╟── 4 - ╎ ├─╼ 0 ╾ 3 - ╎ ├─╼ 5 ╾ 7 - ╎ │ └─╼ 3 - ╎ │ ├─╼ 1 ╾ 9 - ╎ │ │ └─╼ 9 ╾ 6 - ╎ │ │ ├─╼ 6 - ╎ │ │ │ └─╼ ... - ╎ │ │ ├─╼ 7 ╾ 4 - ╎ │ │ │ ├─╼ 2 - ╎ │ │ │ └─╼ ... - ╎ │ │ └─╼ ... - ╎ │ └─╼ ... - ╎ └─╼ ... - ╙── 8 - --- directed case, max_depth=0 --- - â•™ ... - --- directed case, max_depth=1 --- - ╟── 4 - ╎ └─╼ ... - ╙── 8 - --- directed case, max_depth=2 --- - ╟── 4 - ╎ ├─╼ 0 ╾ 3 - ╎ ├─╼ 5 ╾ 7 - ╎ │ └─╼ ... - ╎ └─╼ 7 ╾ 9 - ╎ └─╼ ... - ╙── 8 - --- directed case, max_depth=3 --- - ╟── 4 - ╎ ├─╼ 0 ╾ 3 - ╎ ├─╼ 5 ╾ 7 - ╎ │ └─╼ 3 - ╎ │ └─╼ ... - ╎ └─╼ 7 ╾ 9 - ╎ ├─╼ 2 - ╎ └─╼ ... - ╙── 8 - --- undirected case, max_depth=None --- - ╟── 8 - ╙── 2 - └── 7 - ├── 4 - │ ├── 0 - │ │ └── 3 - │ │ ├── 1 - │ │ │ └── 9 ─ 7 - │ │ │ └── 6 - │ │ └── 5 ─ 4, 7 - │ └── ... - └── ... - --- undirected case, max_depth=0 --- - â•™ ... - --- undirected case, max_depth=1 --- - ╟── 8 - ╙── 2 ─ 7 - └── ... - --- undirected case, max_depth=2 --- - ╟── 8 - ╙── 2 - └── 7 ─ 4, 5, 9 - └── ... - --- undirected case, max_depth=3 --- - ╟── 8 - ╙── 2 - └── 7 - ├── 4 ─ 0, 5 - │ └── ... - ├── 5 ─ 4, 3 - │ └── ... - └── 9 ─ 1, 6 - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_clique_max_depth(): - orig = nx.complete_graph(5, nx.DiGraph) - lines = [] - write = lines.append - write("--- directed case, max_depth=None ---") - nx.write_network_text(orig, path=write, end="", max_depth=None) - write("--- directed case, max_depth=0 ---") - nx.write_network_text(orig, path=write, end="", max_depth=0) - write("--- directed case, max_depth=1 ---") - nx.write_network_text(orig, path=write, end="", max_depth=1) - write("--- directed case, max_depth=2 ---") - nx.write_network_text(orig, path=write, end="", max_depth=2) - write("--- directed case, max_depth=3 ---") - nx.write_network_text(orig, path=write, end="", max_depth=3) - write("--- undirected case, max_depth=None ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=None) - write("--- undirected case, max_depth=0 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=0) - write("--- undirected case, max_depth=1 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=1) - write("--- undirected case, max_depth=2 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=2) - write("--- undirected case, max_depth=3 ---") - nx.write_network_text(orig.to_undirected(), path=write, end="", max_depth=3) - text = "\n".join(lines) - target = dedent( - """ - --- directed case, max_depth=None --- - ╙── 0 ╾ 1, 2, 3, 4 - ├─╼ 1 ╾ 2, 3, 4 - │ ├─╼ 2 ╾ 0, 3, 4 - │ │ ├─╼ 3 ╾ 0, 1, 4 - │ │ │ ├─╼ 4 ╾ 0, 1, 2 - │ │ │ │ └─╼ ... - │ │ │ └─╼ ... - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- directed case, max_depth=0 --- - â•™ ... - --- directed case, max_depth=1 --- - ╙── 0 ╾ 1, 2, 3, 4 - └─╼ ... - --- directed case, max_depth=2 --- - ╙── 0 ╾ 1, 2, 3, 4 - ├─╼ 1 ╾ 2, 3, 4 - │ └─╼ ... - ├─╼ 2 ╾ 1, 3, 4 - │ └─╼ ... - ├─╼ 3 ╾ 1, 2, 4 - │ └─╼ ... - └─╼ 4 ╾ 1, 2, 3 - └─╼ ... - --- directed case, max_depth=3 --- - ╙── 0 ╾ 1, 2, 3, 4 - ├─╼ 1 ╾ 2, 3, 4 - │ ├─╼ 2 ╾ 0, 3, 4 - │ │ └─╼ ... - │ ├─╼ 3 ╾ 0, 2, 4 - │ │ └─╼ ... - │ ├─╼ 4 ╾ 0, 2, 3 - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - --- undirected case, max_depth=None --- - ╙── 0 - ├── 1 - │ ├── 2 ─ 0 - │ │ ├── 3 ─ 0, 1 - │ │ │ └── 4 ─ 0, 1, 2 - │ │ └── ... - │ └── ... - └── ... - --- undirected case, max_depth=0 --- - â•™ ... - --- undirected case, max_depth=1 --- - ╙── 0 ─ 1, 2, 3, 4 - └── ... - --- undirected case, max_depth=2 --- - ╙── 0 - ├── 1 ─ 2, 3, 4 - │ └── ... - ├── 2 ─ 1, 3, 4 - │ └── ... - ├── 3 ─ 1, 2, 4 - │ └── ... - └── 4 ─ 1, 2, 3 - --- undirected case, max_depth=3 --- - ╙── 0 - ├── 1 - │ ├── 2 ─ 0, 3, 4 - │ │ └── ... - │ ├── 3 ─ 0, 2, 4 - │ │ └── ... - │ └── 4 ─ 0, 2, 3 - └── ... - """ - ).strip() - assert target == text - - -def test_write_network_text_custom_label(): - # Create a directed forest with labels - graph = nx.erdos_renyi_graph(5, 0.4, directed=True, seed=359222358) - for node in graph.nodes: - graph.nodes[node]["label"] = f"Node({node})" - graph.nodes[node]["chr"] = chr(node + ord("a") - 1) - if node % 2 == 0: - graph.nodes[node]["part"] = chr(node + ord("a")) - - lines = [] - write = lines.append - write("--- when with_labels=True, uses the 'label' attr ---") - nx.write_network_text(graph, path=write, with_labels=True, end="", max_depth=None) - write("--- when with_labels=False, uses str(node) value ---") - nx.write_network_text(graph, path=write, with_labels=False, end="", max_depth=None) - write("--- when with_labels is a string, use that attr ---") - nx.write_network_text(graph, path=write, with_labels="chr", end="", max_depth=None) - write("--- fallback to str(node) when the attr does not exist ---") - nx.write_network_text(graph, path=write, with_labels="part", end="", max_depth=None) - - text = "\n".join(lines) - target = dedent( - """ - --- when with_labels=True, uses the 'label' attr --- - ╙── Node(1) - └─╼ Node(3) ╾ Node(2) - ├─╼ Node(0) - │ ├─╼ Node(2) ╾ Node(3), Node(4) - │ │ └─╼ ... - │ └─╼ Node(4) - │ └─╼ ... - └─╼ ... - --- when with_labels=False, uses str(node) value --- - ╙── 1 - └─╼ 3 ╾ 2 - ├─╼ 0 - │ ├─╼ 2 ╾ 3, 4 - │ │ └─╼ ... - │ └─╼ 4 - │ └─╼ ... - └─╼ ... - --- when with_labels is a string, use that attr --- - ╙── a - └─╼ c ╾ b - ├─╼ ` - │ ├─╼ b ╾ c, d - │ │ └─╼ ... - │ └─╼ d - │ └─╼ ... - └─╼ ... - --- fallback to str(node) when the attr does not exist --- - ╙── 1 - └─╼ 3 ╾ c - ├─╼ a - │ ├─╼ c ╾ 3, e - │ │ └─╼ ... - │ └─╼ e - │ └─╼ ... - └─╼ ... - """ - ).strip() - assert target == text - - -def test_write_network_text_vertical_chains(): - graph1 = nx.lollipop_graph(4, 2, create_using=nx.Graph) - graph1.add_edge(0, -1) - graph1.add_edge(-1, -2) - graph1.add_edge(-2, -3) - - graph2 = graph1.to_directed() - graph2.remove_edges_from([(u, v) for u, v in graph2.edges if v > u]) - - lines = [] - write = lines.append - write("--- Undirected UTF ---") - nx.write_network_text(graph1, path=write, end="", vertical_chains=True) - write("--- Undirected ASCI ---") - nx.write_network_text( - graph1, path=write, end="", vertical_chains=True, ascii_only=True - ) - write("--- Directed UTF ---") - nx.write_network_text(graph2, path=write, end="", vertical_chains=True) - write("--- Directed ASCI ---") - nx.write_network_text( - graph2, path=write, end="", vertical_chains=True, ascii_only=True - ) - - text = "\n".join(lines) - target = dedent( - """ - --- Undirected UTF --- - ╙── 5 - │ - 4 - │ - 3 - ├── 0 - │ ├── 1 ─ 3 - │ │ │ - │ │ 2 ─ 0, 3 - │ ├── -1 - │ │ │ - │ │ -2 - │ │ │ - │ │ -3 - │ └── ... - └── ... - --- Undirected ASCI --- - +-- 5 - | - 4 - | - 3 - |-- 0 - | |-- 1 - 3 - | | | - | | 2 - 0, 3 - | |-- -1 - | | | - | | -2 - | | | - | | -3 - | L-- ... - L-- ... - --- Directed UTF --- - ╙── 5 - ╽ - 4 - ╽ - 3 - ├─╼ 0 ╾ 1, 2 - │ ╽ - │ -1 - │ ╽ - │ -2 - │ ╽ - │ -3 - ├─╼ 1 ╾ 2 - │ └─╼ ... - └─╼ 2 - └─╼ ... - --- Directed ASCI --- - +-- 5 - ! - 4 - ! - 3 - |-> 0 <- 1, 2 - | ! - | -1 - | ! - | -2 - | ! - | -3 - |-> 1 <- 2 - | L-> ... - L-> 2 - L-> ... - """ - ).strip() - assert target == text - - -def test_collapse_directed(): - graph = nx.balanced_tree(r=2, h=3, create_using=nx.DiGraph) - lines = [] - write = lines.append - write("--- Original ---") - nx.write_network_text(graph, path=write, end="") - graph.nodes[1]["collapse"] = True - write("--- Collapse Node 1 ---") - nx.write_network_text(graph, path=write, end="") - write("--- Add alternate path (5, 3) to collapsed zone") - graph.add_edge(5, 3) - nx.write_network_text(graph, path=write, end="") - write("--- Collapse Node 0 ---") - graph.nodes[0]["collapse"] = True - nx.write_network_text(graph, path=write, end="") - text = "\n".join(lines) - target = dedent( - """ - --- Original --- - ╙── 0 - ├─╼ 1 - │ ├─╼ 3 - │ │ ├─╼ 7 - │ │ └─╼ 8 - │ └─╼ 4 - │ ├─╼ 9 - │ └─╼ 10 - └─╼ 2 - ├─╼ 5 - │ ├─╼ 11 - │ └─╼ 12 - └─╼ 6 - ├─╼ 13 - └─╼ 14 - --- Collapse Node 1 --- - ╙── 0 - ├─╼ 1 - │ └─╼ ... - └─╼ 2 - ├─╼ 5 - │ ├─╼ 11 - │ └─╼ 12 - └─╼ 6 - ├─╼ 13 - └─╼ 14 - --- Add alternate path (5, 3) to collapsed zone - ╙── 0 - ├─╼ 1 - │ └─╼ ... - └─╼ 2 - ├─╼ 5 - │ ├─╼ 11 - │ ├─╼ 12 - │ └─╼ 3 ╾ 1 - │ ├─╼ 7 - │ └─╼ 8 - └─╼ 6 - ├─╼ 13 - └─╼ 14 - --- Collapse Node 0 --- - ╙── 0 - └─╼ ... - """ - ).strip() - assert target == text - - -def test_collapse_undirected(): - graph = nx.balanced_tree(r=2, h=3, create_using=nx.Graph) - lines = [] - write = lines.append - write("--- Original ---") - nx.write_network_text(graph, path=write, end="", sources=[0]) - graph.nodes[1]["collapse"] = True - write("--- Collapse Node 1 ---") - nx.write_network_text(graph, path=write, end="", sources=[0]) - write("--- Add alternate path (5, 3) to collapsed zone") - graph.add_edge(5, 3) - nx.write_network_text(graph, path=write, end="", sources=[0]) - write("--- Collapse Node 0 ---") - graph.nodes[0]["collapse"] = True - nx.write_network_text(graph, path=write, end="", sources=[0]) - text = "\n".join(lines) - target = dedent( - """ - --- Original --- - ╙── 0 - ├── 1 - │ ├── 3 - │ │ ├── 7 - │ │ └── 8 - │ └── 4 - │ ├── 9 - │ └── 10 - └── 2 - ├── 5 - │ ├── 11 - │ └── 12 - └── 6 - ├── 13 - └── 14 - --- Collapse Node 1 --- - ╙── 0 - ├── 1 ─ 3, 4 - │ └── ... - └── 2 - ├── 5 - │ ├── 11 - │ └── 12 - └── 6 - ├── 13 - └── 14 - --- Add alternate path (5, 3) to collapsed zone - ╙── 0 - ├── 1 ─ 3, 4 - │ └── ... - └── 2 - ├── 5 - │ ├── 11 - │ ├── 12 - │ └── 3 ─ 1 - │ ├── 7 - │ └── 8 - └── 6 - ├── 13 - └── 14 - --- Collapse Node 0 --- - ╙── 0 ─ 1, 2 - └── ... - """ - ).strip() - assert target == text - - -def generate_test_graphs(): - """ - Generate a gauntlet of different test graphs with different properties - """ - import random - - rng = random.Random(976689776) - num_randomized = 3 - - for directed in [0, 1]: - cls = nx.DiGraph if directed else nx.Graph - - for num_nodes in range(17): - # Disconnected graph - graph = cls() - graph.add_nodes_from(range(num_nodes)) - yield graph - - # Randomize graphs - if num_nodes > 0: - for p in [0.1, 0.3, 0.5, 0.7, 0.9]: - for seed in range(num_randomized): - graph = nx.erdos_renyi_graph( - num_nodes, p, directed=directed, seed=rng - ) - yield graph - - yield nx.complete_graph(num_nodes, cls) - - yield nx.path_graph(3, create_using=cls) - yield nx.balanced_tree(r=1, h=3, create_using=cls) - if not directed: - yield nx.circular_ladder_graph(4, create_using=cls) - yield nx.star_graph(5, create_using=cls) - yield nx.lollipop_graph(4, 2, create_using=cls) - yield nx.wheel_graph(7, create_using=cls) - yield nx.dorogovtsev_goltsev_mendes_graph(4, create_using=cls) - - -@pytest.mark.parametrize( - ("vertical_chains", "ascii_only"), - tuple( - [ - (vertical_chains, ascii_only) - for vertical_chains in [0, 1] - for ascii_only in [0, 1] - ] - ), -) -def test_network_text_round_trip(vertical_chains, ascii_only): - """ - Write the graph to network text format, then parse it back in, assert it is - the same as the original graph. Passing this test is strong validation of - both the format generator and parser. - """ - from networkx.readwrite.text import _parse_network_text - - for graph in generate_test_graphs(): - graph = nx.relabel_nodes(graph, {n: str(n) for n in graph.nodes}) - lines = list( - nx.generate_network_text( - graph, vertical_chains=vertical_chains, ascii_only=ascii_only - ) - ) - new = _parse_network_text(lines) - try: - assert new.nodes == graph.nodes - assert new.edges == graph.edges - except Exception: - nx.write_network_text(graph) - raise diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/text.py b/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/text.py deleted file mode 100644 index c54901d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/readwrite/text.py +++ /dev/null @@ -1,852 +0,0 @@ -""" -Text-based visual representations of graphs -""" - -import sys -import warnings -from collections import defaultdict - -import networkx as nx -from networkx.utils import open_file - -__all__ = ["generate_network_text", "write_network_text"] - - -class BaseGlyphs: - @classmethod - def as_dict(cls): - return { - a: getattr(cls, a) - for a in dir(cls) - if not a.startswith("_") and a != "as_dict" - } - - -class AsciiBaseGlyphs(BaseGlyphs): - empty: str = "+" - newtree_last: str = "+-- " - newtree_mid: str = "+-- " - endof_forest: str = " " - within_forest: str = ": " - within_tree: str = "| " - - -class AsciiDirectedGlyphs(AsciiBaseGlyphs): - last: str = "L-> " - mid: str = "|-> " - backedge: str = "<-" - vertical_edge: str = "!" - - -class AsciiUndirectedGlyphs(AsciiBaseGlyphs): - last: str = "L-- " - mid: str = "|-- " - backedge: str = "-" - vertical_edge: str = "|" - - -class UtfBaseGlyphs(BaseGlyphs): - # Notes on available box and arrow characters - # https://en.wikipedia.org/wiki/Box-drawing_character - # https://stackoverflow.com/questions/2701192/triangle-arrow - empty: str = "â•™" - newtree_last: str = "╙── " - newtree_mid: str = "╟── " - endof_forest: str = " " - within_forest: str = "╎ " - within_tree: str = "│ " - - -class UtfDirectedGlyphs(UtfBaseGlyphs): - last: str = "└─╼ " - mid: str = "├─╼ " - backedge: str = "╾" - vertical_edge: str = "╽" - - -class UtfUndirectedGlyphs(UtfBaseGlyphs): - last: str = "└── " - mid: str = "├── " - backedge: str = "─" - vertical_edge: str = "│" - - -def generate_network_text( - graph, - with_labels=True, - sources=None, - max_depth=None, - ascii_only=False, - vertical_chains=False, -): - """Generate lines in the "network text" format - - This works via a depth-first traversal of the graph and writing a line for - each unique node encountered. Non-tree edges are written to the right of - each node, and connection to a non-tree edge is indicated with an ellipsis. - This representation works best when the input graph is a forest, but any - graph can be represented. - - This notation is original to networkx, although it is simple enough that it - may be known in existing literature. See #5602 for details. The procedure - is summarized as follows: - - 1. Given a set of source nodes (which can be specified, or automatically - discovered via finding the (strongly) connected components and choosing one - node with minimum degree from each), we traverse the graph in depth first - order. - - 2. Each reachable node will be printed exactly once on it's own line. - - 3. Edges are indicated in one of four ways: - - a. a parent "L-style" connection on the upper left. This corresponds to - a traversal in the directed DFS tree. - - b. a backref "<-style" connection shown directly on the right. For - directed graphs, these are drawn for any incoming edges to a node that - is not a parent edge. For undirected graphs, these are drawn for only - the non-parent edges that have already been represented (The edges that - have not been represented will be handled in the recursive case). - - c. a child "L-style" connection on the lower right. Drawing of the - children are handled recursively. - - d. if ``vertical_chains`` is true, and a parent node only has one child - a "vertical-style" edge is drawn between them. - - 4. The children of each node (wrt the directed DFS tree) are drawn - underneath and to the right of it. In the case that a child node has already - been drawn the connection is replaced with an ellipsis ("...") to indicate - that there is one or more connections represented elsewhere. - - 5. If a maximum depth is specified, an edge to nodes past this maximum - depth will be represented by an ellipsis. - - 6. If a node has a truthy "collapse" value, then we do not traverse past - that node. - - Parameters - ---------- - graph : nx.DiGraph | nx.Graph - Graph to represent - - with_labels : bool | str - If True will use the "label" attribute of a node to display if it - exists otherwise it will use the node value itself. If given as a - string, then that attribute name will be used instead of "label". - Defaults to True. - - sources : List - Specifies which nodes to start traversal from. Note: nodes that are not - reachable from one of these sources may not be shown. If unspecified, - the minimal set of nodes needed to reach all others will be used. - - max_depth : int | None - The maximum depth to traverse before stopping. Defaults to None. - - ascii_only : Boolean - If True only ASCII characters are used to construct the visualization - - vertical_chains : Boolean - If True, chains of nodes will be drawn vertically when possible. - - Yields - ------ - str : a line of generated text - - Examples - -------- - >>> graph = nx.path_graph(10) - >>> graph.add_node("A") - >>> graph.add_node("B") - >>> graph.add_node("C") - >>> graph.add_node("D") - >>> graph.add_edge(9, "A") - >>> graph.add_edge(9, "B") - >>> graph.add_edge(9, "C") - >>> graph.add_edge("C", "D") - >>> graph.add_edge("C", "E") - >>> graph.add_edge("C", "F") - >>> nx.write_network_text(graph) - ╙── 0 - └── 1 - └── 2 - └── 3 - └── 4 - └── 5 - └── 6 - └── 7 - └── 8 - └── 9 - ├── A - ├── B - └── C - ├── D - ├── E - └── F - >>> nx.write_network_text(graph, vertical_chains=True) - ╙── 0 - │ - 1 - │ - 2 - │ - 3 - │ - 4 - │ - 5 - │ - 6 - │ - 7 - │ - 8 - │ - 9 - ├── A - ├── B - └── C - ├── D - ├── E - └── F - """ - from typing import Any, NamedTuple - - class StackFrame(NamedTuple): - parent: Any - node: Any - indents: list - this_islast: bool - this_vertical: bool - - collapse_attr = "collapse" - - is_directed = graph.is_directed() - - if is_directed: - glyphs = AsciiDirectedGlyphs if ascii_only else UtfDirectedGlyphs - succ = graph.succ - pred = graph.pred - else: - glyphs = AsciiUndirectedGlyphs if ascii_only else UtfUndirectedGlyphs - succ = graph.adj - pred = graph.adj - - if isinstance(with_labels, str): - label_attr = with_labels - elif with_labels: - label_attr = "label" - else: - label_attr = None - - if max_depth == 0: - yield glyphs.empty + " ..." - elif len(graph.nodes) == 0: - yield glyphs.empty - else: - # If the nodes to traverse are unspecified, find the minimal set of - # nodes that will reach the entire graph - if sources is None: - sources = _find_sources(graph) - - # Populate the stack with each: - # 1. parent node in the DFS tree (or None for root nodes), - # 2. the current node in the DFS tree - # 2. a list of indentations indicating depth - # 3. a flag indicating if the node is the final one to be written. - # Reverse the stack so sources are popped in the correct order. - last_idx = len(sources) - 1 - stack = [ - StackFrame(None, node, [], (idx == last_idx), False) - for idx, node in enumerate(sources) - ][::-1] - - num_skipped_children = defaultdict(lambda: 0) - seen_nodes = set() - while stack: - parent, node, indents, this_islast, this_vertical = stack.pop() - - if node is not Ellipsis: - skip = node in seen_nodes - if skip: - # Mark that we skipped a parent's child - num_skipped_children[parent] += 1 - - if this_islast: - # If we reached the last child of a parent, and we skipped - # any of that parents children, then we should emit an - # ellipsis at the end after this. - if num_skipped_children[parent] and parent is not None: - # Append the ellipsis to be emitted last - next_islast = True - try_frame = StackFrame( - node, Ellipsis, indents, next_islast, False - ) - stack.append(try_frame) - - # Redo this frame, but not as a last object - next_islast = False - try_frame = StackFrame( - parent, node, indents, next_islast, this_vertical - ) - stack.append(try_frame) - continue - - if skip: - continue - seen_nodes.add(node) - - if not indents: - # Top level items (i.e. trees in the forest) get different - # glyphs to indicate they are not actually connected - if this_islast: - this_vertical = False - this_prefix = indents + [glyphs.newtree_last] - next_prefix = indents + [glyphs.endof_forest] - else: - this_prefix = indents + [glyphs.newtree_mid] - next_prefix = indents + [glyphs.within_forest] - - else: - # Non-top-level items - if this_vertical: - this_prefix = indents - next_prefix = indents - else: - if this_islast: - this_prefix = indents + [glyphs.last] - next_prefix = indents + [glyphs.endof_forest] - else: - this_prefix = indents + [glyphs.mid] - next_prefix = indents + [glyphs.within_tree] - - if node is Ellipsis: - label = " ..." - suffix = "" - children = [] - else: - if label_attr is not None: - label = str(graph.nodes[node].get(label_attr, node)) - else: - label = str(node) - - # Determine if we want to show the children of this node. - if collapse_attr is not None: - collapse = graph.nodes[node].get(collapse_attr, False) - else: - collapse = False - - # Determine: - # (1) children to traverse into after showing this node. - # (2) parents to immediately show to the right of this node. - if is_directed: - # In the directed case we must show every successor node - # note: it may be skipped later, but we don't have that - # information here. - children = list(succ[node]) - # In the directed case we must show every predecessor - # except for parent we directly traversed from. - handled_parents = {parent} - else: - # Showing only the unseen children results in a more - # concise representation for the undirected case. - children = [ - child for child in succ[node] if child not in seen_nodes - ] - - # In the undirected case, parents are also children, so we - # only need to immediately show the ones we can no longer - # traverse - handled_parents = {*children, parent} - - if max_depth is not None and len(indents) == max_depth - 1: - # Use ellipsis to indicate we have reached maximum depth - if children: - children = [Ellipsis] - handled_parents = {parent} - - if collapse: - # Collapsing a node is the same as reaching maximum depth - if children: - children = [Ellipsis] - handled_parents = {parent} - - # The other parents are other predecessors of this node that - # are not handled elsewhere. - other_parents = [p for p in pred[node] if p not in handled_parents] - if other_parents: - if label_attr is not None: - other_parents_labels = ", ".join( - [ - str(graph.nodes[p].get(label_attr, p)) - for p in other_parents - ] - ) - else: - other_parents_labels = ", ".join( - [str(p) for p in other_parents] - ) - suffix = " ".join(["", glyphs.backedge, other_parents_labels]) - else: - suffix = "" - - # Emit the line for this node, this will be called for each node - # exactly once. - if this_vertical: - yield "".join(this_prefix + [glyphs.vertical_edge]) - - yield "".join(this_prefix + [label, suffix]) - - if vertical_chains: - if is_directed: - num_children = len(set(children)) - else: - num_children = len(set(children) - {parent}) - # The next node can be drawn vertically if it is the only - # remaining child of this node. - next_is_vertical = num_children == 1 - else: - next_is_vertical = False - - # Push children on the stack in reverse order so they are popped in - # the original order. - for idx, child in enumerate(children[::-1]): - next_islast = idx == 0 - try_frame = StackFrame( - node, child, next_prefix, next_islast, next_is_vertical - ) - stack.append(try_frame) - - -@open_file(1, "w") -def write_network_text( - graph, - path=None, - with_labels=True, - sources=None, - max_depth=None, - ascii_only=False, - end="\n", - vertical_chains=False, -): - """Creates a nice text representation of a graph - - This works via a depth-first traversal of the graph and writing a line for - each unique node encountered. Non-tree edges are written to the right of - each node, and connection to a non-tree edge is indicated with an ellipsis. - This representation works best when the input graph is a forest, but any - graph can be represented. - - Parameters - ---------- - graph : nx.DiGraph | nx.Graph - Graph to represent - - path : string or file or callable or None - Filename or file handle for data output. - if a function, then it will be called for each generated line. - if None, this will default to "sys.stdout.write" - - with_labels : bool | str - If True will use the "label" attribute of a node to display if it - exists otherwise it will use the node value itself. If given as a - string, then that attribute name will be used instead of "label". - Defaults to True. - - sources : List - Specifies which nodes to start traversal from. Note: nodes that are not - reachable from one of these sources may not be shown. If unspecified, - the minimal set of nodes needed to reach all others will be used. - - max_depth : int | None - The maximum depth to traverse before stopping. Defaults to None. - - ascii_only : Boolean - If True only ASCII characters are used to construct the visualization - - end : string - The line ending character - - vertical_chains : Boolean - If True, chains of nodes will be drawn vertically when possible. - - Examples - -------- - >>> graph = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph) - >>> nx.write_network_text(graph) - ╙── 0 - ├─╼ 1 - │ ├─╼ 3 - │ └─╼ 4 - └─╼ 2 - ├─╼ 5 - └─╼ 6 - - >>> # A near tree with one non-tree edge - >>> graph.add_edge(5, 1) - >>> nx.write_network_text(graph) - ╙── 0 - ├─╼ 1 ╾ 5 - │ ├─╼ 3 - │ └─╼ 4 - └─╼ 2 - ├─╼ 5 - │ └─╼ ... - └─╼ 6 - - >>> graph = nx.cycle_graph(5) - >>> nx.write_network_text(graph) - ╙── 0 - ├── 1 - │ └── 2 - │ └── 3 - │ └── 4 ─ 0 - └── ... - - >>> graph = nx.cycle_graph(5, nx.DiGraph) - >>> nx.write_network_text(graph, vertical_chains=True) - ╙── 0 ╾ 4 - ╽ - 1 - ╽ - 2 - ╽ - 3 - ╽ - 4 - └─╼ ... - - >>> nx.write_network_text(graph, vertical_chains=True, ascii_only=True) - +-- 0 <- 4 - ! - 1 - ! - 2 - ! - 3 - ! - 4 - L-> ... - - >>> graph = nx.generators.barbell_graph(4, 2) - >>> nx.write_network_text(graph, vertical_chains=False) - ╙── 4 - ├── 5 - │ └── 6 - │ ├── 7 - │ │ ├── 8 ─ 6 - │ │ │ └── 9 ─ 6, 7 - │ │ └── ... - │ └── ... - └── 3 - ├── 0 - │ ├── 1 ─ 3 - │ │ └── 2 ─ 0, 3 - │ └── ... - └── ... - >>> nx.write_network_text(graph, vertical_chains=True) - ╙── 4 - ├── 5 - │ │ - │ 6 - │ ├── 7 - │ │ ├── 8 ─ 6 - │ │ │ │ - │ │ │ 9 ─ 6, 7 - │ │ └── ... - │ └── ... - └── 3 - ├── 0 - │ ├── 1 ─ 3 - │ │ │ - │ │ 2 ─ 0, 3 - │ └── ... - └── ... - - >>> graph = nx.complete_graph(5, create_using=nx.Graph) - >>> nx.write_network_text(graph) - ╙── 0 - ├── 1 - │ ├── 2 ─ 0 - │ │ ├── 3 ─ 0, 1 - │ │ │ └── 4 ─ 0, 1, 2 - │ │ └── ... - │ └── ... - └── ... - - >>> graph = nx.complete_graph(3, create_using=nx.DiGraph) - >>> nx.write_network_text(graph) - ╙── 0 ╾ 1, 2 - ├─╼ 1 ╾ 2 - │ ├─╼ 2 ╾ 0 - │ │ └─╼ ... - │ └─╼ ... - └─╼ ... - """ - if path is None: - # The path is unspecified, write to stdout - _write = sys.stdout.write - elif hasattr(path, "write"): - # The path is already an open file - _write = path.write - elif callable(path): - # The path is a custom callable - _write = path - else: - raise TypeError(type(path)) - - for line in generate_network_text( - graph, - with_labels=with_labels, - sources=sources, - max_depth=max_depth, - ascii_only=ascii_only, - vertical_chains=vertical_chains, - ): - _write(line + end) - - -def _find_sources(graph): - """ - Determine a minimal set of nodes such that the entire graph is reachable - """ - # For each connected part of the graph, choose at least - # one node as a starting point, preferably without a parent - if graph.is_directed(): - # Choose one node from each SCC with minimum in_degree - sccs = list(nx.strongly_connected_components(graph)) - # condensing the SCCs forms a dag, the nodes in this graph with - # 0 in-degree correspond to the SCCs from which the minimum set - # of nodes from which all other nodes can be reached. - scc_graph = nx.condensation(graph, sccs) - supernode_to_nodes = {sn: [] for sn in scc_graph.nodes()} - # Note: the order of mapping differs between pypy and cpython - # so we have to loop over graph nodes for consistency - mapping = scc_graph.graph["mapping"] - for n in graph.nodes: - sn = mapping[n] - supernode_to_nodes[sn].append(n) - sources = [] - for sn in scc_graph.nodes(): - if scc_graph.in_degree[sn] == 0: - scc = supernode_to_nodes[sn] - node = min(scc, key=lambda n: graph.in_degree[n]) - sources.append(node) - else: - # For undirected graph, the entire graph will be reachable as - # long as we consider one node from every connected component - sources = [ - min(cc, key=lambda n: graph.degree[n]) - for cc in nx.connected_components(graph) - ] - sources = sorted(sources, key=lambda n: graph.degree[n]) - return sources - - -def _parse_network_text(lines): - """Reconstructs a graph from a network text representation. - - This is mainly used for testing. Network text is for display, not - serialization, as such this cannot parse all network text representations - because node labels can be ambiguous with the glyphs and indentation used - to represent edge structure. Additionally, there is no way to determine if - disconnected graphs were originally directed or undirected. - - Parameters - ---------- - lines : list or iterator of strings - Input data in network text format - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in network text format. - """ - from itertools import chain - from typing import Any, NamedTuple, Union - - class ParseStackFrame(NamedTuple): - node: Any - indent: int - has_vertical_child: int | None - - initial_line_iter = iter(lines) - - is_ascii = None - is_directed = None - - ############## - # Initial Pass - ############## - - # Do an initial pass over the lines to determine what type of graph it is. - # Remember what these lines were, so we can reiterate over them in the - # parsing pass. - initial_lines = [] - try: - first_line = next(initial_line_iter) - except StopIteration: - ... - else: - initial_lines.append(first_line) - # The first character indicates if it is an ASCII or UTF graph - first_char = first_line[0] - if first_char in { - UtfBaseGlyphs.empty, - UtfBaseGlyphs.newtree_mid[0], - UtfBaseGlyphs.newtree_last[0], - }: - is_ascii = False - elif first_char in { - AsciiBaseGlyphs.empty, - AsciiBaseGlyphs.newtree_mid[0], - AsciiBaseGlyphs.newtree_last[0], - }: - is_ascii = True - else: - raise AssertionError(f"Unexpected first character: {first_char}") - - if is_ascii: - directed_glyphs = AsciiDirectedGlyphs.as_dict() - undirected_glyphs = AsciiUndirectedGlyphs.as_dict() - else: - directed_glyphs = UtfDirectedGlyphs.as_dict() - undirected_glyphs = UtfUndirectedGlyphs.as_dict() - - # For both directed / undirected glyphs, determine which glyphs never - # appear as substrings in the other undirected / directed glyphs. Glyphs - # with this property unambiguously indicates if a graph is directed / - # undirected. - directed_items = set(directed_glyphs.values()) - undirected_items = set(undirected_glyphs.values()) - unambiguous_directed_items = [] - for item in directed_items: - other_items = undirected_items - other_supersets = [other for other in other_items if item in other] - if not other_supersets: - unambiguous_directed_items.append(item) - unambiguous_undirected_items = [] - for item in undirected_items: - other_items = directed_items - other_supersets = [other for other in other_items if item in other] - if not other_supersets: - unambiguous_undirected_items.append(item) - - for line in initial_line_iter: - initial_lines.append(line) - if any(item in line for item in unambiguous_undirected_items): - is_directed = False - break - elif any(item in line for item in unambiguous_directed_items): - is_directed = True - break - - if is_directed is None: - # Not enough information to determine, choose undirected by default - is_directed = False - - glyphs = directed_glyphs if is_directed else undirected_glyphs - - # the backedge symbol by itself can be ambiguous, but with spaces around it - # becomes unambiguous. - backedge_symbol = " " + glyphs["backedge"] + " " - - # Reconstruct an iterator over all of the lines. - parsing_line_iter = chain(initial_lines, initial_line_iter) - - ############## - # Parsing Pass - ############## - - edges = [] - nodes = [] - is_empty = None - - noparent = object() # sentinel value - - # keep a stack of previous nodes that could be parents of subsequent nodes - stack = [ParseStackFrame(noparent, -1, None)] - - for line in parsing_line_iter: - if line == glyphs["empty"]: - # If the line is the empty glyph, we are done. - # There shouldn't be anything else after this. - is_empty = True - continue - - if backedge_symbol in line: - # This line has one or more backedges, separate those out - node_part, backedge_part = line.split(backedge_symbol) - backedge_nodes = [u.strip() for u in backedge_part.split(", ")] - # Now the node can be parsed - node_part = node_part.rstrip() - prefix, node = node_part.rsplit(" ", 1) - node = node.strip() - # Add the backedges to the edge list - edges.extend([(u, node) for u in backedge_nodes]) - else: - # No backedge, the tail of this line is the node - prefix, node = line.rsplit(" ", 1) - node = node.strip() - - prev = stack.pop() - - if node in glyphs["vertical_edge"]: - # Previous node is still the previous node, but we know it will - # have exactly one child, which will need to have its nesting level - # adjusted. - modified_prev = ParseStackFrame( - prev.node, - prev.indent, - True, - ) - stack.append(modified_prev) - continue - - # The length of the string before the node characters give us a hint - # about our nesting level. The only case where this doesn't work is - # when there are vertical chains, which is handled explicitly. - indent = len(prefix) - curr = ParseStackFrame(node, indent, None) - - if prev.has_vertical_child: - # In this case we know prev must be the parent of our current line, - # so we don't have to search the stack. (which is good because the - # indentation check wouldn't work in this case). - ... - else: - # If the previous node nesting-level is greater than the current - # nodes nesting-level than the previous node was the end of a path, - # and is not our parent. We can safely pop nodes off the stack - # until we find one with a comparable nesting-level, which is our - # parent. - while curr.indent <= prev.indent: - prev = stack.pop() - - if node == "...": - # The current previous node is no longer a valid parent, - # keep it popped from the stack. - stack.append(prev) - else: - # The previous and current nodes may still be parents, so add them - # back onto the stack. - stack.append(prev) - stack.append(curr) - - # Add the node and the edge to its parent to the node / edge lists. - nodes.append(curr.node) - if prev.node is not noparent: - edges.append((prev.node, curr.node)) - - if is_empty: - # Sanity check - assert len(nodes) == 0 - - # Reconstruct the graph - cls = nx.DiGraph if is_directed else nx.Graph - new = cls() - new.add_nodes_from(nodes) - new.add_edges_from(edges) - return new diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/relabel.py b/extensions/.local/lib/python3.11/site-packages/networkx/relabel.py deleted file mode 100644 index 4b870f7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/relabel.py +++ /dev/null @@ -1,285 +0,0 @@ -import networkx as nx - -__all__ = ["convert_node_labels_to_integers", "relabel_nodes"] - - -@nx._dispatchable( - preserve_all_attrs=True, mutates_input={"not copy": 2}, returns_graph=True -) -def relabel_nodes(G, mapping, copy=True): - """Relabel the nodes of the graph G according to a given mapping. - - The original node ordering may not be preserved if `copy` is `False` and the - mapping includes overlap between old and new labels. - - Parameters - ---------- - G : graph - A NetworkX graph - - mapping : dictionary - A dictionary with the old labels as keys and new labels as values. - A partial mapping is allowed. Mapping 2 nodes to a single node is allowed. - Any non-node keys in the mapping are ignored. - - copy : bool (optional, default=True) - If True return a copy, or if False relabel the nodes in place. - - Examples - -------- - To create a new graph with nodes relabeled according to a given - dictionary: - - >>> G = nx.path_graph(3) - >>> sorted(G) - [0, 1, 2] - >>> mapping = {0: "a", 1: "b", 2: "c"} - >>> H = nx.relabel_nodes(G, mapping) - >>> sorted(H) - ['a', 'b', 'c'] - - Nodes can be relabeled with any hashable object, including numbers - and strings: - - >>> import string - >>> G = nx.path_graph(26) # nodes are integers 0 through 25 - >>> sorted(G)[:3] - [0, 1, 2] - >>> mapping = dict(zip(G, string.ascii_lowercase)) - >>> G = nx.relabel_nodes(G, mapping) # nodes are characters a through z - >>> sorted(G)[:3] - ['a', 'b', 'c'] - >>> mapping = dict(zip(G, range(1, 27))) - >>> G = nx.relabel_nodes(G, mapping) # nodes are integers 1 through 26 - >>> sorted(G)[:3] - [1, 2, 3] - - To perform a partial in-place relabeling, provide a dictionary - mapping only a subset of the nodes, and set the `copy` keyword - argument to False: - - >>> G = nx.path_graph(3) # nodes 0-1-2 - >>> mapping = {0: "a", 1: "b"} # 0->'a' and 1->'b' - >>> G = nx.relabel_nodes(G, mapping, copy=False) - >>> sorted(G, key=str) - [2, 'a', 'b'] - - A mapping can also be given as a function: - - >>> G = nx.path_graph(3) - >>> H = nx.relabel_nodes(G, lambda x: x**2) - >>> list(H) - [0, 1, 4] - - In a multigraph, relabeling two or more nodes to the same new node - will retain all edges, but may change the edge keys in the process: - - >>> G = nx.MultiGraph() - >>> G.add_edge(0, 1, value="a") # returns the key for this edge - 0 - >>> G.add_edge(0, 2, value="b") - 0 - >>> G.add_edge(0, 3, value="c") - 0 - >>> mapping = {1: 4, 2: 4, 3: 4} - >>> H = nx.relabel_nodes(G, mapping, copy=True) - >>> print(H[0]) - {4: {0: {'value': 'a'}, 1: {'value': 'b'}, 2: {'value': 'c'}}} - - This works for in-place relabeling too: - - >>> G = nx.relabel_nodes(G, mapping, copy=False) - >>> print(G[0]) - {4: {0: {'value': 'a'}, 1: {'value': 'b'}, 2: {'value': 'c'}}} - - Notes - ----- - Only the nodes specified in the mapping will be relabeled. - Any non-node keys in the mapping are ignored. - - The keyword setting copy=False modifies the graph in place. - Relabel_nodes avoids naming collisions by building a - directed graph from ``mapping`` which specifies the order of - relabelings. Naming collisions, such as a->b, b->c, are ordered - such that "b" gets renamed to "c" before "a" gets renamed "b". - In cases of circular mappings (e.g. a->b, b->a), modifying the - graph is not possible in-place and an exception is raised. - In that case, use copy=True. - - If a relabel operation on a multigraph would cause two or more - edges to have the same source, target and key, the second edge must - be assigned a new key to retain all edges. The new key is set - to the lowest non-negative integer not already used as a key - for edges between these two nodes. Note that this means non-numeric - keys may be replaced by numeric keys. - - See Also - -------- - convert_node_labels_to_integers - """ - # you can pass any callable e.g. f(old_label) -> new_label or - # e.g. str(old_label) -> new_label, but we'll just make a dictionary here regardless - m = {n: mapping(n) for n in G} if callable(mapping) else mapping - - if copy: - return _relabel_copy(G, m) - else: - return _relabel_inplace(G, m) - - -def _relabel_inplace(G, mapping): - if len(mapping.keys() & mapping.values()) > 0: - # labels sets overlap - # can we topological sort and still do the relabeling? - D = nx.DiGraph(list(mapping.items())) - D.remove_edges_from(nx.selfloop_edges(D)) - try: - nodes = reversed(list(nx.topological_sort(D))) - except nx.NetworkXUnfeasible as err: - raise nx.NetworkXUnfeasible( - "The node label sets are overlapping and no ordering can " - "resolve the mapping. Use copy=True." - ) from err - else: - # non-overlapping label sets, sort them in the order of G nodes - nodes = [n for n in G if n in mapping] - - multigraph = G.is_multigraph() - directed = G.is_directed() - - for old in nodes: - # Test that old is in both mapping and G, otherwise ignore. - try: - new = mapping[old] - G.add_node(new, **G.nodes[old]) - except KeyError: - continue - if new == old: - continue - if multigraph: - new_edges = [ - (new, new if old == target else target, key, data) - for (_, target, key, data) in G.edges(old, data=True, keys=True) - ] - if directed: - new_edges += [ - (new if old == source else source, new, key, data) - for (source, _, key, data) in G.in_edges(old, data=True, keys=True) - ] - # Ensure new edges won't overwrite existing ones - seen = set() - for i, (source, target, key, data) in enumerate(new_edges): - if target in G[source] and key in G[source][target]: - new_key = 0 if not isinstance(key, int | float) else key - while new_key in G[source][target] or (target, new_key) in seen: - new_key += 1 - new_edges[i] = (source, target, new_key, data) - seen.add((target, new_key)) - else: - new_edges = [ - (new, new if old == target else target, data) - for (_, target, data) in G.edges(old, data=True) - ] - if directed: - new_edges += [ - (new if old == source else source, new, data) - for (source, _, data) in G.in_edges(old, data=True) - ] - G.remove_node(old) - G.add_edges_from(new_edges) - return G - - -def _relabel_copy(G, mapping): - H = G.__class__() - H.add_nodes_from(mapping.get(n, n) for n in G) - H._node.update((mapping.get(n, n), d.copy()) for n, d in G.nodes.items()) - if G.is_multigraph(): - new_edges = [ - (mapping.get(n1, n1), mapping.get(n2, n2), k, d.copy()) - for (n1, n2, k, d) in G.edges(keys=True, data=True) - ] - - # check for conflicting edge-keys - undirected = not G.is_directed() - seen_edges = set() - for i, (source, target, key, data) in enumerate(new_edges): - while (source, target, key) in seen_edges: - if not isinstance(key, int | float): - key = 0 - key += 1 - seen_edges.add((source, target, key)) - if undirected: - seen_edges.add((target, source, key)) - new_edges[i] = (source, target, key, data) - - H.add_edges_from(new_edges) - else: - H.add_edges_from( - (mapping.get(n1, n1), mapping.get(n2, n2), d.copy()) - for (n1, n2, d) in G.edges(data=True) - ) - H.graph.update(G.graph) - return H - - -@nx._dispatchable(preserve_all_attrs=True, returns_graph=True) -def convert_node_labels_to_integers( - G, first_label=0, ordering="default", label_attribute=None -): - """Returns a copy of the graph G with the nodes relabeled using - consecutive integers. - - Parameters - ---------- - G : graph - A NetworkX graph - - first_label : int, optional (default=0) - An integer specifying the starting offset in numbering nodes. - The new integer labels are numbered first_label, ..., n-1+first_label. - - ordering : string - "default" : inherit node ordering from G.nodes() - "sorted" : inherit node ordering from sorted(G.nodes()) - "increasing degree" : nodes are sorted by increasing degree - "decreasing degree" : nodes are sorted by decreasing degree - - label_attribute : string, optional (default=None) - Name of node attribute to store old label. If None no attribute - is created. - - Notes - ----- - Node and edge attribute data are copied to the new (relabeled) graph. - - There is no guarantee that the relabeling of nodes to integers will - give the same two integers for two (even identical graphs). - Use the `ordering` argument to try to preserve the order. - - See Also - -------- - relabel_nodes - """ - N = G.number_of_nodes() + first_label - if ordering == "default": - mapping = dict(zip(G.nodes(), range(first_label, N))) - elif ordering == "sorted": - nlist = sorted(G.nodes()) - mapping = dict(zip(nlist, range(first_label, N))) - elif ordering == "increasing degree": - dv_pairs = [(d, n) for (n, d) in G.degree()] - dv_pairs.sort() # in-place sort from lowest to highest degree - mapping = dict(zip([n for d, n in dv_pairs], range(first_label, N))) - elif ordering == "decreasing degree": - dv_pairs = [(d, n) for (n, d) in G.degree()] - dv_pairs.sort() # in-place sort from lowest to highest degree - dv_pairs.reverse() - mapping = dict(zip([n for d, n in dv_pairs], range(first_label, N))) - else: - raise nx.NetworkXError(f"Unknown node ordering: {ordering}") - H = relabel_nodes(G, mapping) - # create node attribute with the old label - if label_attribute is not None: - nx.set_node_attributes(H, {v: k for k, v in mapping.items()}, label_attribute) - return H diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_all_random_functions.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_all_random_functions.py deleted file mode 100644 index 5e45815..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_all_random_functions.py +++ /dev/null @@ -1,250 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -import random - -import networkx as nx -from networkx.algorithms import approximation as approx -from networkx.algorithms import threshold - -progress = 0 - -# store the random numbers after setting a global seed -np.random.seed(42) -np_rv = np.random.rand() -random.seed(42) -py_rv = random.random() - - -def t(f, *args, **kwds): - """call one function and check if global RNG changed""" - global progress - progress += 1 - print(progress, ",", end="") - - f(*args, **kwds) - - after_np_rv = np.random.rand() - # if np_rv != after_np_rv: - # print(np_rv, after_np_rv, "don't match np!") - assert np_rv == after_np_rv - np.random.seed(42) - - after_py_rv = random.random() - # if py_rv != after_py_rv: - # print(py_rv, after_py_rv, "don't match py!") - assert py_rv == after_py_rv - random.seed(42) - - -def run_all_random_functions(seed): - n = 20 - m = 10 - k = l = 2 - s = v = 10 - p = q = p1 = p2 = p_in = p_out = 0.4 - alpha = radius = theta = 0.75 - sizes = (20, 20, 10) - colors = [1, 2, 3] - G = nx.barbell_graph(12, 20) - H = nx.cycle_graph(3) - H.add_weighted_edges_from((u, v, 0.2) for u, v in H.edges) - deg_sequence = [3, 2, 1, 3, 2, 1, 3, 2, 1, 2, 1, 2, 1] - in_degree_sequence = w = sequence = aseq = bseq = deg_sequence - - # print("starting...") - t(nx.maximal_independent_set, G, seed=seed) - t(nx.rich_club_coefficient, G, seed=seed, normalized=False) - t(nx.random_reference, G, seed=seed) - t(nx.lattice_reference, G, seed=seed) - t(nx.sigma, G, 1, 2, seed=seed) - t(nx.omega, G, 1, 2, seed=seed) - # print("out of smallworld.py") - t(nx.double_edge_swap, G, seed=seed) - # print("starting connected_double_edge_swap") - t(nx.connected_double_edge_swap, nx.complete_graph(9), seed=seed) - # print("ending connected_double_edge_swap") - t(nx.random_layout, G, seed=seed) - t(nx.fruchterman_reingold_layout, G, seed=seed) - t(nx.algebraic_connectivity, G, seed=seed) - t(nx.fiedler_vector, G, seed=seed) - t(nx.spectral_ordering, G, seed=seed) - # print('starting average_clustering') - t(approx.average_clustering, G, seed=seed) - t(approx.simulated_annealing_tsp, H, "greedy", source=1, seed=seed) - t(approx.threshold_accepting_tsp, H, "greedy", source=1, seed=seed) - t( - approx.traveling_salesman_problem, - H, - method=lambda G, weight: approx.simulated_annealing_tsp( - G, "greedy", weight, seed=seed - ), - ) - t( - approx.traveling_salesman_problem, - H, - method=lambda G, weight: approx.threshold_accepting_tsp( - G, "greedy", weight, seed=seed - ), - ) - t(nx.betweenness_centrality, G, seed=seed) - t(nx.edge_betweenness_centrality, G, seed=seed) - t(nx.approximate_current_flow_betweenness_centrality, G, seed=seed) - # print("kernighan") - t(nx.algorithms.community.kernighan_lin_bisection, G, seed=seed) - # nx.algorithms.community.asyn_lpa_communities(G, seed=seed) - t(nx.algorithms.tree.greedy_branching, G, seed=seed) - # print('done with graph argument functions') - - t(nx.spectral_graph_forge, G, alpha, seed=seed) - t(nx.algorithms.community.asyn_fluidc, G, k, max_iter=1, seed=seed) - t( - nx.algorithms.connectivity.edge_augmentation.greedy_k_edge_augmentation, - G, - k, - seed=seed, - ) - t(nx.algorithms.coloring.strategy_random_sequential, G, colors, seed=seed) - - cs = ["d", "i", "i", "d", "d", "i"] - t(threshold.swap_d, cs, seed=seed) - t(nx.configuration_model, deg_sequence, seed=seed) - t( - nx.directed_configuration_model, - in_degree_sequence, - in_degree_sequence, - seed=seed, - ) - t(nx.expected_degree_graph, w, seed=seed) - t(nx.random_degree_sequence_graph, sequence, seed=seed) - joint_degrees = { - 1: {4: 1}, - 2: {2: 2, 3: 2, 4: 2}, - 3: {2: 2, 4: 1}, - 4: {1: 1, 2: 2, 3: 1}, - } - t(nx.joint_degree_graph, joint_degrees, seed=seed) - joint_degree_sequence = [ - (1, 0), - (1, 0), - (1, 0), - (2, 0), - (1, 0), - (2, 1), - (0, 1), - (0, 1), - ] - t(nx.random_clustered_graph, joint_degree_sequence, seed=seed) - constructor = [(3, 3, 0.5), (10, 10, 0.7)] - t(nx.random_shell_graph, constructor, seed=seed) - t(nx.random_triad, G.to_directed(), seed=seed) - mapping = {1: 0.4, 2: 0.3, 3: 0.3} - t(nx.utils.random_weighted_sample, mapping, k, seed=seed) - t(nx.utils.weighted_choice, mapping, seed=seed) - t(nx.algorithms.bipartite.configuration_model, aseq, bseq, seed=seed) - t(nx.algorithms.bipartite.preferential_attachment_graph, aseq, p, seed=seed) - - def kernel_integral(u, w, z): - return z - w - - t(nx.random_kernel_graph, n, kernel_integral, seed=seed) - - sizes = [75, 75, 300] - probs = [[0.25, 0.05, 0.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]] - t(nx.stochastic_block_model, sizes, probs, seed=seed) - t(nx.random_partition_graph, sizes, p_in, p_out, seed=seed) - - # print("starting generator functions") - t(threshold.random_threshold_sequence, n, p, seed=seed) - t(nx.tournament.random_tournament, n, seed=seed) - t(nx.relaxed_caveman_graph, l, k, p, seed=seed) - t(nx.planted_partition_graph, l, k, p_in, p_out, seed=seed) - t(nx.gaussian_random_partition_graph, n, s, v, p_in, p_out, seed=seed) - t(nx.gn_graph, n, seed=seed) - t(nx.gnr_graph, n, p, seed=seed) - t(nx.gnc_graph, n, seed=seed) - t(nx.scale_free_graph, n, seed=seed) - t(nx.directed.random_uniform_k_out_graph, n, k, seed=seed) - t(nx.random_k_out_graph, n, k, alpha, seed=seed) - N = 1000 - t(nx.partial_duplication_graph, N, n, p, q, seed=seed) - t(nx.duplication_divergence_graph, n, p, seed=seed) - t(nx.random_geometric_graph, n, radius, seed=seed) - t(nx.soft_random_geometric_graph, n, radius, seed=seed) - t(nx.geographical_threshold_graph, n, theta, seed=seed) - t(nx.waxman_graph, n, seed=seed) - t(nx.navigable_small_world_graph, n, seed=seed) - t(nx.thresholded_random_geometric_graph, n, radius, theta, seed=seed) - t(nx.uniform_random_intersection_graph, n, m, p, seed=seed) - t(nx.k_random_intersection_graph, n, m, k, seed=seed) - - t(nx.general_random_intersection_graph, n, 2, [0.1, 0.5], seed=seed) - t(nx.fast_gnp_random_graph, n, p, seed=seed) - t(nx.gnp_random_graph, n, p, seed=seed) - t(nx.dense_gnm_random_graph, n, m, seed=seed) - t(nx.gnm_random_graph, n, m, seed=seed) - t(nx.newman_watts_strogatz_graph, n, k, p, seed=seed) - t(nx.watts_strogatz_graph, n, k, p, seed=seed) - t(nx.connected_watts_strogatz_graph, n, k, p, seed=seed) - t(nx.random_regular_graph, 3, n, seed=seed) - t(nx.barabasi_albert_graph, n, m, seed=seed) - t(nx.extended_barabasi_albert_graph, n, m, p, q, seed=seed) - t(nx.powerlaw_cluster_graph, n, m, p, seed=seed) - t(nx.random_lobster, n, p1, p2, seed=seed) - t(nx.random_powerlaw_tree, n, seed=seed, tries=5000) - t(nx.random_powerlaw_tree_sequence, 10, seed=seed, tries=5000) - t(nx.random_labeled_tree, n, seed=seed) - t(nx.utils.powerlaw_sequence, n, seed=seed) - t(nx.utils.zipf_rv, 2.3, seed=seed) - cdist = [0.2, 0.4, 0.5, 0.7, 0.9, 1.0] - t(nx.utils.discrete_sequence, n, cdistribution=cdist, seed=seed) - t(nx.algorithms.bipartite.random_graph, n, m, p, seed=seed) - t(nx.algorithms.bipartite.gnmk_random_graph, n, m, k, seed=seed) - LFR = nx.generators.LFR_benchmark_graph - t( - LFR, - 25, - 3, - 1.5, - 0.1, - average_degree=3, - min_community=10, - seed=seed, - max_community=20, - ) - t(nx.random_internet_as_graph, n, seed=seed) - # print("done") - - -# choose to test an integer seed, or whether a single RNG can be everywhere -# np_rng = np.random.RandomState(14) -# seed = np_rng -# seed = 14 - - -@pytest.mark.slow -# print("NetworkX Version:", nx.__version__) -def test_rng_interface(): - global progress - - # try different kinds of seeds - for seed in [14, np.random.RandomState(14)]: - np.random.seed(42) - random.seed(42) - run_all_random_functions(seed) - progress = 0 - - # check that both global RNGs are unaffected - after_np_rv = np.random.rand() - # if np_rv != after_np_rv: - # print(np_rv, after_np_rv, "don't match np!") - assert np_rv == after_np_rv - after_py_rv = random.random() - # if py_rv != after_py_rv: - # print(py_rv, after_py_rv, "don't match py!") - assert py_rv == after_py_rv - - -# print("\nDone testing seed:", seed) - -# test_rng_interface() diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert.py deleted file mode 100644 index 44bed94..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert.py +++ /dev/null @@ -1,321 +0,0 @@ -import pytest - -import networkx as nx -from networkx.convert import ( - from_dict_of_dicts, - from_dict_of_lists, - to_dict_of_dicts, - to_dict_of_lists, - to_networkx_graph, -) -from networkx.generators.classic import barbell_graph, cycle_graph -from networkx.utils import edges_equal, graphs_equal, nodes_equal - - -class TestConvert: - def edgelists_equal(self, e1, e2): - return sorted(sorted(e) for e in e1) == sorted(sorted(e) for e in e2) - - def test_simple_graphs(self): - for dest, source in [ - (to_dict_of_dicts, from_dict_of_dicts), - (to_dict_of_lists, from_dict_of_lists), - ]: - G = barbell_graph(10, 3) - G.graph = {} - dod = dest(G) - - # Dict of [dicts, lists] - GG = source(dod) - assert graphs_equal(G, GG) - GW = to_networkx_graph(dod) - assert graphs_equal(G, GW) - GI = nx.Graph(dod) - assert graphs_equal(G, GI) - - # With nodelist keyword - P4 = nx.path_graph(4) - P3 = nx.path_graph(3) - P4.graph = {} - P3.graph = {} - dod = dest(P4, nodelist=[0, 1, 2]) - Gdod = nx.Graph(dod) - assert graphs_equal(Gdod, P3) - - def test_exceptions(self): - # NX graph - class G: - adj = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # pygraphviz agraph - class G: - is_strict = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # Dict of [dicts, lists] - G = {"a": 0} - pytest.raises(TypeError, to_networkx_graph, G) - - # list or generator of edges - class G: - next = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # no match - pytest.raises(nx.NetworkXError, to_networkx_graph, "a") - - def test_digraphs(self): - for dest, source in [ - (to_dict_of_dicts, from_dict_of_dicts), - (to_dict_of_lists, from_dict_of_lists), - ]: - G = cycle_graph(10) - - # Dict of [dicts, lists] - dod = dest(G) - GG = source(dod) - assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod) - assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.Graph(dod) - assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GI.edges())) - - G = cycle_graph(10, create_using=nx.DiGraph) - dod = dest(G) - GG = source(dod, create_using=nx.DiGraph) - assert sorted(G.nodes()) == sorted(GG.nodes()) - assert sorted(G.edges()) == sorted(GG.edges()) - GW = to_networkx_graph(dod, create_using=nx.DiGraph) - assert sorted(G.nodes()) == sorted(GW.nodes()) - assert sorted(G.edges()) == sorted(GW.edges()) - GI = nx.DiGraph(dod) - assert sorted(G.nodes()) == sorted(GI.nodes()) - assert sorted(G.edges()) == sorted(GI.edges()) - - def test_graph(self): - g = nx.cycle_graph(10) - G = nx.Graph() - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, u) for u, v in g.edges()) - - # Dict of dicts - dod = to_dict_of_dicts(G) - GG = from_dict_of_dicts(dod, create_using=nx.Graph) - assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod, create_using=nx.Graph) - assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.Graph(dod) - assert sorted(G.nodes()) == sorted(GI.nodes()) - assert sorted(G.edges()) == sorted(GI.edges()) - - # Dict of lists - dol = to_dict_of_lists(G) - GG = from_dict_of_lists(dol, create_using=nx.Graph) - # dict of lists throws away edge data so set it to none - enone = [(u, v, {}) for (u, v, d) in G.edges(data=True)] - assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert edges_equal(enone, sorted(GG.edges(data=True))) - GW = to_networkx_graph(dol, create_using=nx.Graph) - assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert edges_equal(enone, sorted(GW.edges(data=True))) - GI = nx.Graph(dol) - assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert edges_equal(enone, sorted(GI.edges(data=True))) - - def test_with_multiedges_self_loops(self): - G = cycle_graph(10) - XG = nx.Graph() - XG.add_nodes_from(G) - XG.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGM = nx.MultiGraph() - XGM.add_nodes_from(G) - XGM.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGM.add_edge(0, 1, weight=2) # multiedge - XGS = nx.Graph() - XGS.add_nodes_from(G) - XGS.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGS.add_edge(0, 0, weight=100) # self loop - - # Dict of dicts - # with self loops, OK - dod = to_dict_of_dicts(XGS) - GG = from_dict_of_dicts(dod, create_using=nx.Graph) - assert nodes_equal(XGS.nodes(), GG.nodes()) - assert edges_equal(XGS.edges(), GG.edges()) - GW = to_networkx_graph(dod, create_using=nx.Graph) - assert nodes_equal(XGS.nodes(), GW.nodes()) - assert edges_equal(XGS.edges(), GW.edges()) - GI = nx.Graph(dod) - assert nodes_equal(XGS.nodes(), GI.nodes()) - assert edges_equal(XGS.edges(), GI.edges()) - - # Dict of lists - # with self loops, OK - dol = to_dict_of_lists(XGS) - GG = from_dict_of_lists(dol, create_using=nx.Graph) - # dict of lists throws away edge data so set it to none - enone = [(u, v, {}) for (u, v, d) in XGS.edges(data=True)] - assert nodes_equal(sorted(XGS.nodes()), sorted(GG.nodes())) - assert edges_equal(enone, sorted(GG.edges(data=True))) - GW = to_networkx_graph(dol, create_using=nx.Graph) - assert nodes_equal(sorted(XGS.nodes()), sorted(GW.nodes())) - assert edges_equal(enone, sorted(GW.edges(data=True))) - GI = nx.Graph(dol) - assert nodes_equal(sorted(XGS.nodes()), sorted(GI.nodes())) - assert edges_equal(enone, sorted(GI.edges(data=True))) - - # Dict of dicts - # with multiedges, OK - dod = to_dict_of_dicts(XGM) - GG = from_dict_of_dicts(dod, create_using=nx.MultiGraph, multigraph_input=True) - assert nodes_equal(sorted(XGM.nodes()), sorted(GG.nodes())) - assert edges_equal(sorted(XGM.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod, create_using=nx.MultiGraph, multigraph_input=True) - assert nodes_equal(sorted(XGM.nodes()), sorted(GW.nodes())) - assert edges_equal(sorted(XGM.edges()), sorted(GW.edges())) - GI = nx.MultiGraph(dod) - assert nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes())) - assert sorted(XGM.edges()) == sorted(GI.edges()) - GE = from_dict_of_dicts(dod, create_using=nx.MultiGraph, multigraph_input=False) - assert nodes_equal(sorted(XGM.nodes()), sorted(GE.nodes())) - assert sorted(XGM.edges()) != sorted(GE.edges()) - GI = nx.MultiGraph(XGM) - assert nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes())) - assert edges_equal(sorted(XGM.edges()), sorted(GI.edges())) - GM = nx.MultiGraph(G) - assert nodes_equal(sorted(GM.nodes()), sorted(G.nodes())) - assert edges_equal(sorted(GM.edges()), sorted(G.edges())) - - # Dict of lists - # with multiedges, OK, but better write as DiGraph else you'll - # get double edges - dol = to_dict_of_lists(G) - GG = from_dict_of_lists(dol, create_using=nx.MultiGraph) - assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dol, create_using=nx.MultiGraph) - assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.MultiGraph(dol) - assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert edges_equal(sorted(G.edges()), sorted(GI.edges())) - - def test_edgelists(self): - P = nx.path_graph(4) - e = [(0, 1), (1, 2), (2, 3)] - G = nx.Graph(e) - assert nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert edges_equal(sorted(G.edges()), sorted(P.edges())) - assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - e = [(0, 1, {}), (1, 2, {}), (2, 3, {})] - G = nx.Graph(e) - assert nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert edges_equal(sorted(G.edges()), sorted(P.edges())) - assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - e = ((n, n + 1) for n in range(3)) - G = nx.Graph(e) - assert nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert edges_equal(sorted(G.edges()), sorted(P.edges())) - assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - def test_directed_to_undirected(self): - edges1 = [(0, 1), (1, 2), (2, 0)] - edges2 = [(0, 1), (1, 2), (0, 2)] - assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges2)).edges(), edges1) - assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges2)).edges(), edges1) - - assert self.edgelists_equal( - nx.MultiGraph(nx.MultiDiGraph(edges1)).edges(), edges1 - ) - assert self.edgelists_equal( - nx.MultiGraph(nx.MultiDiGraph(edges2)).edges(), edges1 - ) - - assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges2)).edges(), edges1) - - def test_attribute_dict_integrity(self): - # we must not replace dict-like graph data structures with dicts - G = nx.Graph() - G.add_nodes_from("abc") - H = to_networkx_graph(G, create_using=nx.Graph) - assert list(H.nodes) == list(G.nodes) - H = nx.DiGraph(G) - assert list(H.nodes) == list(G.nodes) - - def test_to_edgelist(self): - G = nx.Graph([(1, 1)]) - elist = nx.to_edgelist(G, nodelist=list(G)) - assert edges_equal(G.edges(data=True), elist) - - def test_custom_node_attr_dict_safekeeping(self): - class custom_dict(dict): - pass - - class Custom(nx.Graph): - node_attr_dict_factory = custom_dict - - g = nx.Graph() - g.add_node(1, weight=1) - - h = Custom(g) - assert isinstance(g._node[1], dict) - assert isinstance(h._node[1], custom_dict) - - # this raise exception - # h._node.update((n, dd.copy()) for n, dd in g.nodes.items()) - # assert isinstance(h._node[1], custom_dict) - - -@pytest.mark.parametrize( - "edgelist", - ( - # Graph with no edge data - [(0, 1), (1, 2)], - # Graph with edge data - [(0, 1, {"weight": 1.0}), (1, 2, {"weight": 2.0})], - ), -) -def test_to_dict_of_dicts_with_edgedata_param(edgelist): - G = nx.Graph() - G.add_edges_from(edgelist) - # Innermost dict value == edge_data when edge_data != None. - # In the case when G has edge data, it is overwritten - expected = {0: {1: 10}, 1: {0: 10, 2: 10}, 2: {1: 10}} - assert nx.to_dict_of_dicts(G, edge_data=10) == expected - - -def test_to_dict_of_dicts_with_edgedata_and_nodelist(): - G = nx.path_graph(5) - nodelist = [2, 3, 4] - expected = {2: {3: 10}, 3: {2: 10, 4: 10}, 4: {3: 10}} - assert nx.to_dict_of_dicts(G, nodelist=nodelist, edge_data=10) == expected - - -def test_to_dict_of_dicts_with_edgedata_multigraph(): - """Multi edge data overwritten when edge_data != None""" - G = nx.MultiGraph() - G.add_edge(0, 1, key="a") - G.add_edge(0, 1, key="b") - # Multi edge data lost when edge_data is not None - expected = {0: {1: 10}, 1: {0: 10}} - assert nx.to_dict_of_dicts(G, edge_data=10) == expected - - -def test_to_networkx_graph_non_edgelist(): - invalid_edgelist = [1, 2, 3] - with pytest.raises(nx.NetworkXError, match="Input is not a valid edge list"): - nx.to_networkx_graph(invalid_edgelist) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_numpy.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_numpy.py deleted file mode 100644 index 1c39afd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_numpy.py +++ /dev/null @@ -1,532 +0,0 @@ -import itertools - -import pytest - -np = pytest.importorskip("numpy") -npt = pytest.importorskip("numpy.testing") - -import networkx as nx -from networkx.generators.classic import barbell_graph, cycle_graph, path_graph -from networkx.utils import graphs_equal - - -class TestConvertNumpyArray: - def setup_method(self): - self.G1 = barbell_graph(10, 3) - self.G2 = cycle_graph(10, create_using=nx.DiGraph) - self.G3 = self.create_weighted(nx.Graph()) - self.G4 = self.create_weighted(nx.DiGraph()) - - def create_weighted(self, G): - g = cycle_graph(4) - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, 10 + u) for u, v in g.edges()) - return G - - def assert_equal(self, G1, G2): - assert sorted(G1.nodes()) == sorted(G2.nodes()) - assert sorted(G1.edges()) == sorted(G2.edges()) - - def identity_conversion(self, G, A, create_using): - assert A.sum() > 0 - GG = nx.from_numpy_array(A, create_using=create_using) - self.assert_equal(G, GG) - GW = nx.to_networkx_graph(A, create_using=create_using) - self.assert_equal(G, GW) - GI = nx.empty_graph(0, create_using).__class__(A) - self.assert_equal(G, GI) - - def test_shape(self): - "Conversion from non-square array." - A = np.array([[1, 2, 3], [4, 5, 6]]) - pytest.raises(nx.NetworkXError, nx.from_numpy_array, A) - - def test_identity_graph_array(self): - "Conversion from graph to array to graph." - A = nx.to_numpy_array(self.G1) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_digraph_array(self): - """Conversion from digraph to array to digraph.""" - A = nx.to_numpy_array(self.G2) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_weighted_graph_array(self): - """Conversion from weighted graph to array to weighted graph.""" - A = nx.to_numpy_array(self.G3) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_digraph_array(self): - """Conversion from weighted digraph to array to weighted digraph.""" - A = nx.to_numpy_array(self.G4) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_nodelist(self): - """Conversion from graph to array to graph with nodelist.""" - P4 = path_graph(4) - P3 = path_graph(3) - nodelist = list(P3) - A = nx.to_numpy_array(P4, nodelist=nodelist) - GA = nx.Graph(A) - self.assert_equal(GA, P3) - - # Make nodelist ambiguous by containing duplicates. - nodelist += [nodelist[0]] - pytest.raises(nx.NetworkXError, nx.to_numpy_array, P3, nodelist=nodelist) - - # Make nodelist invalid by including nonexistent nodes - nodelist = [-1, 0, 1] - with pytest.raises( - nx.NetworkXError, - match=f"Nodes {nodelist - P3.nodes} in nodelist is not in G", - ): - nx.to_numpy_array(P3, nodelist=nodelist) - - def test_weight_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3)) - P4 = path_graph(4) - A = nx.to_numpy_array(P4) - np.testing.assert_equal(A, nx.to_numpy_array(WP4, weight=None)) - np.testing.assert_equal(0.5 * A, nx.to_numpy_array(WP4)) - np.testing.assert_equal(0.3 * A, nx.to_numpy_array(WP4, weight="other")) - - def test_from_numpy_array_type(self): - A = np.array([[1]]) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == int - - A = np.array([[1]]).astype(float) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == float - - A = np.array([[1]]).astype(str) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == str - - A = np.array([[1]]).astype(bool) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == bool - - A = np.array([[1]]).astype(complex) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == complex - - A = np.array([[1]]).astype(object) - pytest.raises(TypeError, nx.from_numpy_array, A) - - A = np.array([[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]]) - with pytest.raises( - nx.NetworkXError, match=f"Input array must be 2D, not {A.ndim}" - ): - g = nx.from_numpy_array(A) - - def test_from_numpy_array_dtype(self): - dt = [("weight", float), ("cost", int)] - A = np.array([[(1.0, 2)]], dtype=dt) - G = nx.from_numpy_array(A) - assert type(G[0][0]["weight"]) == float - assert type(G[0][0]["cost"]) == int - assert G[0][0]["cost"] == 2 - assert G[0][0]["weight"] == 1.0 - - def test_from_numpy_array_parallel_edges(self): - """Tests that the :func:`networkx.from_numpy_array` function - interprets integer weights as the number of parallel edges when - creating a multigraph. - - """ - A = np.array([[1, 1], [1, 2]]) - # First, with a simple graph, each integer entry in the adjacency - # matrix is interpreted as the weight of a single edge in the graph. - expected = nx.DiGraph() - edges = [(0, 0), (0, 1), (1, 0)] - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - expected.add_edge(1, 1, weight=2) - actual = nx.from_numpy_array(A, parallel_edges=True, create_using=nx.DiGraph) - assert graphs_equal(actual, expected) - actual = nx.from_numpy_array(A, parallel_edges=False, create_using=nx.DiGraph) - assert graphs_equal(actual, expected) - # Now each integer entry in the adjacency matrix is interpreted as the - # number of parallel edges in the graph if the appropriate keyword - # argument is specified. - edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)] - expected = nx.MultiDiGraph() - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - actual = nx.from_numpy_array( - A, parallel_edges=True, create_using=nx.MultiDiGraph - ) - assert graphs_equal(actual, expected) - expected = nx.MultiDiGraph() - expected.add_edges_from(set(edges), weight=1) - # The sole self-loop (edge 0) on vertex 1 should have weight 2. - expected[1][1][0]["weight"] = 2 - actual = nx.from_numpy_array( - A, parallel_edges=False, create_using=nx.MultiDiGraph - ) - assert graphs_equal(actual, expected) - - @pytest.mark.parametrize( - "dt", - ( - None, # default - int, # integer dtype - np.dtype( - [("weight", "f8"), ("color", "i1")] - ), # Structured dtype with named fields - ), - ) - def test_from_numpy_array_no_edge_attr(self, dt): - A = np.array([[0, 1], [1, 0]], dtype=dt) - G = nx.from_numpy_array(A, edge_attr=None) - assert "weight" not in G.edges[0, 1] - assert len(G.edges[0, 1]) == 0 - - def test_from_numpy_array_multiedge_no_edge_attr(self): - A = np.array([[0, 2], [2, 0]]) - G = nx.from_numpy_array(A, create_using=nx.MultiDiGraph, edge_attr=None) - assert all("weight" not in e for _, e in G[0][1].items()) - assert len(G[0][1][0]) == 0 - - def test_from_numpy_array_custom_edge_attr(self): - A = np.array([[0, 2], [3, 0]]) - G = nx.from_numpy_array(A, edge_attr="cost") - assert "weight" not in G.edges[0, 1] - assert G.edges[0, 1]["cost"] == 3 - - def test_symmetric(self): - """Tests that a symmetric array has edges added only once to an - undirected multigraph when using :func:`networkx.from_numpy_array`. - - """ - A = np.array([[0, 1], [1, 0]]) - G = nx.from_numpy_array(A, create_using=nx.MultiGraph) - expected = nx.MultiGraph() - expected.add_edge(0, 1, weight=1) - assert graphs_equal(G, expected) - - def test_dtype_int_graph(self): - """Test that setting dtype int actually gives an integer array. - - For more information, see GitHub pull request #1363. - - """ - G = nx.complete_graph(3) - A = nx.to_numpy_array(G, dtype=int) - assert A.dtype == int - - def test_dtype_int_multigraph(self): - """Test that setting dtype int actually gives an integer array. - - For more information, see GitHub pull request #1363. - - """ - G = nx.MultiGraph(nx.complete_graph(3)) - A = nx.to_numpy_array(G, dtype=int) - assert A.dtype == int - - -@pytest.fixture -def multigraph_test_graph(): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=7) - G.add_edge(1, 2, weight=70) - return G - - -@pytest.mark.parametrize(("operator", "expected"), ((sum, 77), (min, 7), (max, 70))) -def test_numpy_multigraph(multigraph_test_graph, operator, expected): - A = nx.to_numpy_array(multigraph_test_graph, multigraph_weight=operator) - assert A[1, 0] == expected - - -def test_to_numpy_array_multigraph_nodelist(multigraph_test_graph): - G = multigraph_test_graph - G.add_edge(0, 1, weight=3) - A = nx.to_numpy_array(G, nodelist=[1, 2]) - assert A.shape == (2, 2) - assert A[1, 0] == 77 - - -@pytest.mark.parametrize( - "G, expected", - [ - (nx.Graph(), np.array([[0, 1 + 2j], [1 + 2j, 0]], dtype=complex)), - (nx.DiGraph(), np.array([[0, 1 + 2j], [0, 0]], dtype=complex)), - ], -) -def test_to_numpy_array_complex_weights(G, expected): - G.add_edge(0, 1, weight=1 + 2j) - A = nx.to_numpy_array(G, dtype=complex) - npt.assert_array_equal(A, expected) - - -def test_to_numpy_array_arbitrary_weights(): - G = nx.DiGraph() - w = 922337203685477580102 # Out of range for int64 - G.add_edge(0, 1, weight=922337203685477580102) # val not representable by int64 - A = nx.to_numpy_array(G, dtype=object) - expected = np.array([[0, w], [0, 0]], dtype=object) - npt.assert_array_equal(A, expected) - - # Undirected - A = nx.to_numpy_array(G.to_undirected(), dtype=object) - expected = np.array([[0, w], [w, 0]], dtype=object) - npt.assert_array_equal(A, expected) - - -@pytest.mark.parametrize( - "func, expected", - ((min, -1), (max, 10), (sum, 11), (np.mean, 11 / 3), (np.median, 2)), -) -def test_to_numpy_array_multiweight_reduction(func, expected): - """Test various functions for reducing multiedge weights.""" - G = nx.MultiDiGraph() - weights = [-1, 2, 10.0] - for w in weights: - G.add_edge(0, 1, weight=w) - A = nx.to_numpy_array(G, multigraph_weight=func, dtype=float) - assert np.allclose(A, [[0, expected], [0, 0]]) - - # Undirected case - A = nx.to_numpy_array(G.to_undirected(), multigraph_weight=func, dtype=float) - assert np.allclose(A, [[0, expected], [expected, 0]]) - - -@pytest.mark.parametrize( - ("G, expected"), - [ - (nx.Graph(), [[(0, 0), (10, 5)], [(10, 5), (0, 0)]]), - (nx.DiGraph(), [[(0, 0), (10, 5)], [(0, 0), (0, 0)]]), - ], -) -def test_to_numpy_array_structured_dtype_attrs_from_fields(G, expected): - """When `dtype` is structured (i.e. has names) and `weight` is None, use - the named fields of the dtype to look up edge attributes.""" - G.add_edge(0, 1, weight=10, cost=5.0) - dtype = np.dtype([("weight", int), ("cost", int)]) - A = nx.to_numpy_array(G, dtype=dtype, weight=None) - expected = np.asarray(expected, dtype=dtype) - npt.assert_array_equal(A, expected) - - -def test_to_numpy_array_structured_dtype_single_attr_default(): - G = nx.path_graph(3) - dtype = np.dtype([("weight", float)]) # A single named field - A = nx.to_numpy_array(G, dtype=dtype, weight=None) - expected = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float) - npt.assert_array_equal(A["weight"], expected) - - -@pytest.mark.parametrize( - ("field_name", "expected_attr_val"), - [ - ("weight", 1), - ("cost", 3), - ], -) -def test_to_numpy_array_structured_dtype_single_attr(field_name, expected_attr_val): - G = nx.Graph() - G.add_edge(0, 1, cost=3) - dtype = np.dtype([(field_name, float)]) - A = nx.to_numpy_array(G, dtype=dtype, weight=None) - expected = np.array([[0, expected_attr_val], [expected_attr_val, 0]], dtype=float) - npt.assert_array_equal(A[field_name], expected) - - -@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph)) -@pytest.mark.parametrize( - "edge", - [ - (0, 1), # No edge attributes - (0, 1, {"weight": 10}), # One edge attr - (0, 1, {"weight": 5, "flow": -4}), # Multiple but not all edge attrs - (0, 1, {"weight": 2.0, "cost": 10, "flow": -45}), # All attrs - ], -) -def test_to_numpy_array_structured_dtype_multiple_fields(graph_type, edge): - G = graph_type([edge]) - dtype = np.dtype([("weight", float), ("cost", float), ("flow", float)]) - A = nx.to_numpy_array(G, dtype=dtype, weight=None) - for attr in dtype.names: - expected = nx.to_numpy_array(G, dtype=float, weight=attr) - npt.assert_array_equal(A[attr], expected) - - -@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) -def test_to_numpy_array_structured_dtype_scalar_nonedge(G): - G.add_edge(0, 1, weight=10) - dtype = np.dtype([("weight", float), ("cost", float)]) - A = nx.to_numpy_array(G, dtype=dtype, weight=None, nonedge=np.nan) - for attr in dtype.names: - expected = nx.to_numpy_array(G, dtype=float, weight=attr, nonedge=np.nan) - npt.assert_array_equal(A[attr], expected) - - -@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph())) -def test_to_numpy_array_structured_dtype_nonedge_ary(G): - """Similar to the scalar case, except has a different non-edge value for - each named field.""" - G.add_edge(0, 1, weight=10) - dtype = np.dtype([("weight", float), ("cost", float)]) - nonedges = np.array([(0, np.inf)], dtype=dtype) - A = nx.to_numpy_array(G, dtype=dtype, weight=None, nonedge=nonedges) - for attr in dtype.names: - nonedge = nonedges[attr] - expected = nx.to_numpy_array(G, dtype=float, weight=attr, nonedge=nonedge) - npt.assert_array_equal(A[attr], expected) - - -def test_to_numpy_array_structured_dtype_with_weight_raises(): - """Using both a structured dtype (with named fields) and specifying a `weight` - parameter is ambiguous.""" - G = nx.path_graph(3) - dtype = np.dtype([("weight", int), ("cost", int)]) - exception_msg = "Specifying `weight` not supported for structured dtypes" - with pytest.raises(ValueError, match=exception_msg): - nx.to_numpy_array(G, dtype=dtype) # Default is weight="weight" - with pytest.raises(ValueError, match=exception_msg): - nx.to_numpy_array(G, dtype=dtype, weight="cost") - - -@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph)) -def test_to_numpy_array_structured_multigraph_raises(graph_type): - G = nx.path_graph(3, create_using=graph_type) - dtype = np.dtype([("weight", int), ("cost", int)]) - with pytest.raises(nx.NetworkXError, match="Structured arrays are not supported"): - nx.to_numpy_array(G, dtype=dtype, weight=None) - - -def test_from_numpy_array_nodelist_bad_size(): - """An exception is raised when `len(nodelist) != A.shape[0]`.""" - n = 5 # Number of nodes - A = np.diag(np.ones(n - 1), k=1) # Adj. matrix for P_n - expected = nx.path_graph(n) - - assert graphs_equal(nx.from_numpy_array(A, edge_attr=None), expected) - nodes = list(range(n)) - assert graphs_equal( - nx.from_numpy_array(A, edge_attr=None, nodelist=nodes), expected - ) - - # Too many node labels - nodes = list(range(n + 1)) - with pytest.raises(ValueError, match="nodelist must have the same length as A"): - nx.from_numpy_array(A, nodelist=nodes) - - # Too few node labels - nodes = list(range(n - 1)) - with pytest.raises(ValueError, match="nodelist must have the same length as A"): - nx.from_numpy_array(A, nodelist=nodes) - - -@pytest.mark.parametrize( - "nodes", - ( - [4, 3, 2, 1, 0], - [9, 7, 1, 2, 8], - ["a", "b", "c", "d", "e"], - [(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)], - ["A", 2, 7, "spam", (1, 3)], - ), -) -def test_from_numpy_array_nodelist(nodes): - A = np.diag(np.ones(4), k=1) - # Without edge attributes - expected = nx.relabel_nodes( - nx.path_graph(5), mapping=dict(enumerate(nodes)), copy=True - ) - G = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes) - assert graphs_equal(G, expected) - - # With edge attributes - nx.set_edge_attributes(expected, 1.0, name="weight") - G = nx.from_numpy_array(A, nodelist=nodes) - assert graphs_equal(G, expected) - - -@pytest.mark.parametrize( - "nodes", - ( - [4, 3, 2, 1, 0], - [9, 7, 1, 2, 8], - ["a", "b", "c", "d", "e"], - [(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)], - ["A", 2, 7, "spam", (1, 3)], - ), -) -def test_from_numpy_array_nodelist_directed(nodes): - A = np.diag(np.ones(4), k=1) - # Without edge attributes - H = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 4)]) - expected = nx.relabel_nodes(H, mapping=dict(enumerate(nodes)), copy=True) - G = nx.from_numpy_array(A, create_using=nx.DiGraph, edge_attr=None, nodelist=nodes) - assert graphs_equal(G, expected) - - # With edge attributes - nx.set_edge_attributes(expected, 1.0, name="weight") - G = nx.from_numpy_array(A, create_using=nx.DiGraph, nodelist=nodes) - assert graphs_equal(G, expected) - - -@pytest.mark.parametrize( - "nodes", - ( - [4, 3, 2, 1, 0], - [9, 7, 1, 2, 8], - ["a", "b", "c", "d", "e"], - [(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)], - ["A", 2, 7, "spam", (1, 3)], - ), -) -def test_from_numpy_array_nodelist_multigraph(nodes): - A = np.array( - [ - [0, 1, 0, 0, 0], - [1, 0, 2, 0, 0], - [0, 2, 0, 3, 0], - [0, 0, 3, 0, 4], - [0, 0, 0, 4, 0], - ] - ) - - H = nx.MultiGraph() - for i, edge in enumerate(((0, 1), (1, 2), (2, 3), (3, 4))): - H.add_edges_from(itertools.repeat(edge, i + 1)) - expected = nx.relabel_nodes(H, mapping=dict(enumerate(nodes)), copy=True) - - G = nx.from_numpy_array( - A, - parallel_edges=True, - create_using=nx.MultiGraph, - edge_attr=None, - nodelist=nodes, - ) - assert graphs_equal(G, expected) - - -@pytest.mark.parametrize( - "nodes", - ( - [4, 3, 2, 1, 0], - [9, 7, 1, 2, 8], - ["a", "b", "c", "d", "e"], - [(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)], - ["A", 2, 7, "spam", (1, 3)], - ), -) -@pytest.mark.parametrize("graph", (nx.complete_graph, nx.cycle_graph, nx.wheel_graph)) -def test_from_numpy_array_nodelist_rountrip(graph, nodes): - G = graph(5) - A = nx.to_numpy_array(G) - expected = nx.relabel_nodes(G, mapping=dict(enumerate(nodes)), copy=True) - H = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes) - assert graphs_equal(H, expected) - - # With an isolated node - G = graph(4) - G.add_node("foo") - A = nx.to_numpy_array(G) - expected = nx.relabel_nodes(G, mapping=dict(zip(G.nodes, nodes)), copy=True) - H = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes) - assert graphs_equal(H, expected) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_pandas.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_pandas.py deleted file mode 100644 index 8c3f02a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_pandas.py +++ /dev/null @@ -1,349 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import edges_equal, graphs_equal, nodes_equal - -np = pytest.importorskip("numpy") -pd = pytest.importorskip("pandas") - - -class TestConvertPandas: - def setup_method(self): - self.rng = np.random.RandomState(seed=5) - ints = self.rng.randint(1, 11, size=(3, 2)) - a = ["A", "B", "C"] - b = ["D", "A", "E"] - df = pd.DataFrame(ints, columns=["weight", "cost"]) - df[0] = a # Column label 0 (int) - df["b"] = b # Column label 'b' (str) - self.df = df - - mdf = pd.DataFrame([[4, 16, "A", "D"]], columns=["weight", "cost", 0, "b"]) - self.mdf = pd.concat([df, mdf]) - - def test_exceptions(self): - G = pd.DataFrame(["a"]) # adj - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - G = pd.DataFrame(["a", 0.0]) # elist - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - df = pd.DataFrame([[1, 1], [1, 0]], dtype=int, index=[1, 2], columns=["a", "b"]) - pytest.raises(nx.NetworkXError, nx.from_pandas_adjacency, df) - - def test_from_edgelist_all_attr(self): - Gtrue = nx.Graph( - [ - ("E", "C", {"cost": 9, "weight": 10}), - ("B", "A", {"cost": 1, "weight": 7}), - ("A", "D", {"cost": 7, "weight": 4}), - ] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", True) - assert graphs_equal(G, Gtrue) - # MultiGraph - MGtrue = nx.MultiGraph(Gtrue) - MGtrue.add_edge("A", "D", cost=16, weight=4) - MG = nx.from_pandas_edgelist(self.mdf, 0, "b", True, nx.MultiGraph()) - assert graphs_equal(MG, MGtrue) - - def test_from_edgelist_multi_attr(self): - Gtrue = nx.Graph( - [ - ("E", "C", {"cost": 9, "weight": 10}), - ("B", "A", {"cost": 1, "weight": 7}), - ("A", "D", {"cost": 7, "weight": 4}), - ] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", ["weight", "cost"]) - assert graphs_equal(G, Gtrue) - - def test_from_edgelist_multi_attr_incl_target(self): - Gtrue = nx.Graph( - [ - ("E", "C", {0: "C", "b": "E", "weight": 10}), - ("B", "A", {0: "B", "b": "A", "weight": 7}), - ("A", "D", {0: "A", "b": "D", "weight": 4}), - ] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", [0, "b", "weight"]) - assert graphs_equal(G, Gtrue) - - def test_from_edgelist_multidigraph_and_edge_attr(self): - # example from issue #2374 - edges = [ - ("X1", "X4", {"Co": "zA", "Mi": 0, "St": "X1"}), - ("X1", "X4", {"Co": "zB", "Mi": 54, "St": "X2"}), - ("X1", "X4", {"Co": "zB", "Mi": 49, "St": "X3"}), - ("X1", "X4", {"Co": "zB", "Mi": 44, "St": "X4"}), - ("Y1", "Y3", {"Co": "zC", "Mi": 0, "St": "Y1"}), - ("Y1", "Y3", {"Co": "zC", "Mi": 34, "St": "Y2"}), - ("Y1", "Y3", {"Co": "zC", "Mi": 29, "St": "X2"}), - ("Y1", "Y3", {"Co": "zC", "Mi": 24, "St": "Y3"}), - ("Z1", "Z3", {"Co": "zD", "Mi": 0, "St": "Z1"}), - ("Z1", "Z3", {"Co": "zD", "Mi": 14, "St": "X3"}), - ] - Gtrue = nx.MultiDiGraph(edges) - data = { - "O": ["X1", "X1", "X1", "X1", "Y1", "Y1", "Y1", "Y1", "Z1", "Z1"], - "D": ["X4", "X4", "X4", "X4", "Y3", "Y3", "Y3", "Y3", "Z3", "Z3"], - "St": ["X1", "X2", "X3", "X4", "Y1", "Y2", "X2", "Y3", "Z1", "X3"], - "Co": ["zA", "zB", "zB", "zB", "zC", "zC", "zC", "zC", "zD", "zD"], - "Mi": [0, 54, 49, 44, 0, 34, 29, 24, 0, 14], - } - df = pd.DataFrame.from_dict(data) - G1 = nx.from_pandas_edgelist( - df, source="O", target="D", edge_attr=True, create_using=nx.MultiDiGraph - ) - G2 = nx.from_pandas_edgelist( - df, - source="O", - target="D", - edge_attr=["St", "Co", "Mi"], - create_using=nx.MultiDiGraph, - ) - assert graphs_equal(G1, Gtrue) - assert graphs_equal(G2, Gtrue) - - def test_from_edgelist_one_attr(self): - Gtrue = nx.Graph( - [ - ("E", "C", {"weight": 10}), - ("B", "A", {"weight": 7}), - ("A", "D", {"weight": 4}), - ] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", "weight") - assert graphs_equal(G, Gtrue) - - def test_from_edgelist_int_attr_name(self): - # note: this also tests that edge_attr can be `source` - Gtrue = nx.Graph( - [("E", "C", {0: "C"}), ("B", "A", {0: "B"}), ("A", "D", {0: "A"})] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", 0) - assert graphs_equal(G, Gtrue) - - def test_from_edgelist_invalid_attr(self): - pytest.raises( - nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", "misspell" - ) - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", 1) - # see Issue #3562 - edgeframe = pd.DataFrame([[0, 1], [1, 2], [2, 0]], columns=["s", "t"]) - pytest.raises( - nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", True - ) - pytest.raises( - nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", "weight" - ) - pytest.raises( - nx.NetworkXError, - nx.from_pandas_edgelist, - edgeframe, - "s", - "t", - ["weight", "size"], - ) - - def test_from_edgelist_no_attr(self): - Gtrue = nx.Graph([("E", "C", {}), ("B", "A", {}), ("A", "D", {})]) - G = nx.from_pandas_edgelist(self.df, 0, "b") - assert graphs_equal(G, Gtrue) - - def test_from_edgelist(self): - # Pandas DataFrame - G = nx.cycle_graph(10) - G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) - - edgelist = nx.to_edgelist(G) - source = [s for s, t, d in edgelist] - target = [t for s, t, d in edgelist] - weight = [d["weight"] for s, t, d in edgelist] - edges = pd.DataFrame({"source": source, "target": target, "weight": weight}) - - GG = nx.from_pandas_edgelist(edges, edge_attr="weight") - assert nodes_equal(G.nodes(), GG.nodes()) - assert edges_equal(G.edges(), GG.edges()) - GW = nx.to_networkx_graph(edges, create_using=nx.Graph) - assert nodes_equal(G.nodes(), GW.nodes()) - assert edges_equal(G.edges(), GW.edges()) - - def test_to_edgelist_default_source_or_target_col_exists(self): - G = nx.path_graph(10) - G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) - nx.set_edge_attributes(G, 0, name="source") - pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G) - - # drop source column to test an exception raised for the target column - for u, v, d in G.edges(data=True): - d.pop("source", None) - - nx.set_edge_attributes(G, 0, name="target") - pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G) - - def test_to_edgelist_custom_source_or_target_col_exists(self): - G = nx.path_graph(10) - G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) - nx.set_edge_attributes(G, 0, name="source_col_name") - pytest.raises( - nx.NetworkXError, nx.to_pandas_edgelist, G, source="source_col_name" - ) - - # drop source column to test an exception raised for the target column - for u, v, d in G.edges(data=True): - d.pop("source_col_name", None) - - nx.set_edge_attributes(G, 0, name="target_col_name") - pytest.raises( - nx.NetworkXError, nx.to_pandas_edgelist, G, target="target_col_name" - ) - - def test_to_edgelist_edge_key_col_exists(self): - G = nx.path_graph(10, create_using=nx.MultiGraph) - G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges())) - nx.set_edge_attributes(G, 0, name="edge_key_name") - pytest.raises( - nx.NetworkXError, nx.to_pandas_edgelist, G, edge_key="edge_key_name" - ) - - def test_from_adjacency(self): - nodelist = [1, 2] - dftrue = pd.DataFrame( - [[1, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist - ) - G = nx.Graph([(1, 1), (1, 2)]) - df = nx.to_pandas_adjacency(G, dtype=int) - pd.testing.assert_frame_equal(df, dftrue) - - @pytest.mark.parametrize("graph", [nx.Graph, nx.MultiGraph]) - def test_roundtrip(self, graph): - # edgelist - Gtrue = graph([(1, 1), (1, 2)]) - df = nx.to_pandas_edgelist(Gtrue) - G = nx.from_pandas_edgelist(df, create_using=graph) - assert graphs_equal(Gtrue, G) - # adjacency - adj = {1: {1: {"weight": 1}, 2: {"weight": 1}}, 2: {1: {"weight": 1}}} - Gtrue = graph(adj) - df = nx.to_pandas_adjacency(Gtrue, dtype=int) - G = nx.from_pandas_adjacency(df, create_using=graph) - assert graphs_equal(Gtrue, G) - - def test_from_adjacency_named(self): - # example from issue #3105 - data = { - "A": {"A": 0, "B": 0, "C": 0}, - "B": {"A": 1, "B": 0, "C": 0}, - "C": {"A": 0, "B": 1, "C": 0}, - } - dftrue = pd.DataFrame(data, dtype=np.intp) - df = dftrue[["A", "C", "B"]] - G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph()) - df = nx.to_pandas_adjacency(G, dtype=np.intp) - pd.testing.assert_frame_equal(df, dftrue) - - @pytest.mark.parametrize("edge_attr", [["attr2", "attr3"], True]) - def test_edgekey_with_multigraph(self, edge_attr): - df = pd.DataFrame( - { - "source": {"A": "N1", "B": "N2", "C": "N1", "D": "N1"}, - "target": {"A": "N2", "B": "N3", "C": "N1", "D": "N2"}, - "attr1": {"A": "F1", "B": "F2", "C": "F3", "D": "F4"}, - "attr2": {"A": 1, "B": 0, "C": 0, "D": 0}, - "attr3": {"A": 0, "B": 1, "C": 0, "D": 1}, - } - ) - Gtrue = nx.MultiGraph( - [ - ("N1", "N2", "F1", {"attr2": 1, "attr3": 0}), - ("N2", "N3", "F2", {"attr2": 0, "attr3": 1}), - ("N1", "N1", "F3", {"attr2": 0, "attr3": 0}), - ("N1", "N2", "F4", {"attr2": 0, "attr3": 1}), - ] - ) - # example from issue #4065 - G = nx.from_pandas_edgelist( - df, - source="source", - target="target", - edge_attr=edge_attr, - edge_key="attr1", - create_using=nx.MultiGraph(), - ) - assert graphs_equal(G, Gtrue) - - df_roundtrip = nx.to_pandas_edgelist(G, edge_key="attr1") - df_roundtrip = df_roundtrip.sort_values("attr1") - df_roundtrip.index = ["A", "B", "C", "D"] - pd.testing.assert_frame_equal( - df, df_roundtrip[["source", "target", "attr1", "attr2", "attr3"]] - ) - - def test_edgekey_with_normal_graph_no_action(self): - Gtrue = nx.Graph( - [ - ("E", "C", {"cost": 9, "weight": 10}), - ("B", "A", {"cost": 1, "weight": 7}), - ("A", "D", {"cost": 7, "weight": 4}), - ] - ) - G = nx.from_pandas_edgelist(self.df, 0, "b", True, edge_key="weight") - assert graphs_equal(G, Gtrue) - - def test_nonexisting_edgekey_raises(self): - with pytest.raises(nx.exception.NetworkXError): - nx.from_pandas_edgelist( - self.df, - source="source", - target="target", - edge_key="Not_real", - edge_attr=True, - create_using=nx.MultiGraph(), - ) - - def test_multigraph_with_edgekey_no_edgeattrs(self): - Gtrue = nx.MultiGraph() - Gtrue.add_edge(0, 1, key=0) - Gtrue.add_edge(0, 1, key=3) - df = nx.to_pandas_edgelist(Gtrue, edge_key="key") - expected = pd.DataFrame({"source": [0, 0], "target": [1, 1], "key": [0, 3]}) - pd.testing.assert_frame_equal(expected, df) - G = nx.from_pandas_edgelist(df, edge_key="key", create_using=nx.MultiGraph) - assert graphs_equal(Gtrue, G) - - -def test_to_pandas_adjacency_with_nodelist(): - G = nx.complete_graph(5) - nodelist = [1, 4] - expected = pd.DataFrame( - [[0, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist - ) - pd.testing.assert_frame_equal( - expected, nx.to_pandas_adjacency(G, nodelist, dtype=int) - ) - - -def test_to_pandas_edgelist_with_nodelist(): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3)], weight=2.0) - G.add_edge(0, 5, weight=100) - df = nx.to_pandas_edgelist(G, nodelist=[1, 2]) - assert 0 not in df["source"].to_numpy() - assert 100 not in df["weight"].to_numpy() - - -def test_from_pandas_adjacency_with_index_collisions(): - """See gh-7407""" - df = pd.DataFrame( - [ - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1], - [0, 0, 0, 0], - ], - index=[1010001, 2, 1, 1010002], - columns=[1010001, 2, 1, 1010002], - ) - G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph) - expected = nx.DiGraph([(1010001, 2), (2, 1), (1, 1010002)]) - assert nodes_equal(G.nodes, expected.nodes) - assert edges_equal(G.edges, expected.edges) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_scipy.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_scipy.py deleted file mode 100644 index aa513b8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_convert_scipy.py +++ /dev/null @@ -1,282 +0,0 @@ -import pytest - -np = pytest.importorskip("numpy") -sp = pytest.importorskip("scipy") - -import networkx as nx -from networkx.generators.classic import barbell_graph, cycle_graph, path_graph -from networkx.utils import graphs_equal - - -class TestConvertScipy: - def setup_method(self): - self.G1 = barbell_graph(10, 3) - self.G2 = cycle_graph(10, create_using=nx.DiGraph) - - self.G3 = self.create_weighted(nx.Graph()) - self.G4 = self.create_weighted(nx.DiGraph()) - - def test_exceptions(self): - class G: - format = None - - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - - def create_weighted(self, G): - g = cycle_graph(4) - e = list(g.edges()) - source = [u for u, v in e] - dest = [v for u, v in e] - weight = [s + 10 for s in source] - ex = zip(source, dest, weight) - G.add_weighted_edges_from(ex) - return G - - def identity_conversion(self, G, A, create_using): - GG = nx.from_scipy_sparse_array(A, create_using=create_using) - assert nx.is_isomorphic(G, GG) - - GW = nx.to_networkx_graph(A, create_using=create_using) - assert nx.is_isomorphic(G, GW) - - GI = nx.empty_graph(0, create_using).__class__(A) - assert nx.is_isomorphic(G, GI) - - ACSR = A.tocsr() - GI = nx.empty_graph(0, create_using).__class__(ACSR) - assert nx.is_isomorphic(G, GI) - - ACOO = A.tocoo() - GI = nx.empty_graph(0, create_using).__class__(ACOO) - assert nx.is_isomorphic(G, GI) - - ACSC = A.tocsc() - GI = nx.empty_graph(0, create_using).__class__(ACSC) - assert nx.is_isomorphic(G, GI) - - AD = A.todense() - GI = nx.empty_graph(0, create_using).__class__(AD) - assert nx.is_isomorphic(G, GI) - - AA = A.toarray() - GI = nx.empty_graph(0, create_using).__class__(AA) - assert nx.is_isomorphic(G, GI) - - def test_shape(self): - "Conversion from non-square sparse array." - A = sp.sparse.lil_array([[1, 2, 3], [4, 5, 6]]) - pytest.raises(nx.NetworkXError, nx.from_scipy_sparse_array, A) - - def test_identity_graph_matrix(self): - "Conversion from graph to sparse matrix to graph." - A = nx.to_scipy_sparse_array(self.G1) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_digraph_matrix(self): - "Conversion from digraph to sparse matrix to digraph." - A = nx.to_scipy_sparse_array(self.G2) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_weighted_graph_matrix(self): - """Conversion from weighted graph to sparse matrix to weighted graph.""" - A = nx.to_scipy_sparse_array(self.G3) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_digraph_matrix(self): - """Conversion from weighted digraph to sparse matrix to weighted digraph.""" - A = nx.to_scipy_sparse_array(self.G4) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_nodelist(self): - """Conversion from graph to sparse matrix to graph with nodelist.""" - P4 = path_graph(4) - P3 = path_graph(3) - nodelist = list(P3.nodes()) - A = nx.to_scipy_sparse_array(P4, nodelist=nodelist) - GA = nx.Graph(A) - assert nx.is_isomorphic(GA, P3) - - pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=[]) - # Test nodelist duplicates. - long_nl = nodelist + [0] - pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=long_nl) - - # Test nodelist contains non-nodes - non_nl = [-1, 0, 1, 2] - pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=non_nl) - - def test_weight_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3)) - P4 = path_graph(4) - A = nx.to_scipy_sparse_array(P4) - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - np.testing.assert_equal( - 0.5 * A.todense(), nx.to_scipy_sparse_array(WP4).todense() - ) - np.testing.assert_equal( - 0.3 * A.todense(), nx.to_scipy_sparse_array(WP4, weight="other").todense() - ) - - def test_format_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3)) - P4 = path_graph(4) - A = nx.to_scipy_sparse_array(P4, format="csr") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="csc") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="coo") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="bsr") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="lil") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="dia") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - A = nx.to_scipy_sparse_array(P4, format="dok") - np.testing.assert_equal( - A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense() - ) - - def test_format_keyword_raise(self): - with pytest.raises(nx.NetworkXError): - WP4 = nx.Graph() - WP4.add_edges_from( - (n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3) - ) - P4 = path_graph(4) - nx.to_scipy_sparse_array(P4, format="any_other") - - def test_null_raise(self): - with pytest.raises(nx.NetworkXError): - nx.to_scipy_sparse_array(nx.Graph()) - - def test_empty(self): - G = nx.Graph() - G.add_node(1) - M = nx.to_scipy_sparse_array(G) - np.testing.assert_equal(M.toarray(), np.array([[0]])) - - def test_ordering(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(3, 1) - M = nx.to_scipy_sparse_array(G, nodelist=[3, 2, 1]) - np.testing.assert_equal( - M.toarray(), np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) - ) - - def test_selfloop_graph(self): - G = nx.Graph([(1, 1)]) - M = nx.to_scipy_sparse_array(G) - np.testing.assert_equal(M.toarray(), np.array([[1]])) - - G.add_edges_from([(2, 3), (3, 4)]) - M = nx.to_scipy_sparse_array(G, nodelist=[2, 3, 4]) - np.testing.assert_equal( - M.toarray(), np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) - ) - - def test_selfloop_digraph(self): - G = nx.DiGraph([(1, 1)]) - M = nx.to_scipy_sparse_array(G) - np.testing.assert_equal(M.toarray(), np.array([[1]])) - - G.add_edges_from([(2, 3), (3, 4)]) - M = nx.to_scipy_sparse_array(G, nodelist=[2, 3, 4]) - np.testing.assert_equal( - M.toarray(), np.array([[0, 1, 0], [0, 0, 1], [0, 0, 0]]) - ) - - def test_from_scipy_sparse_array_parallel_edges(self): - """Tests that the :func:`networkx.from_scipy_sparse_array` function - interprets integer weights as the number of parallel edges when - creating a multigraph. - - """ - A = sp.sparse.csr_array([[1, 1], [1, 2]]) - # First, with a simple graph, each integer entry in the adjacency - # matrix is interpreted as the weight of a single edge in the graph. - expected = nx.DiGraph() - edges = [(0, 0), (0, 1), (1, 0)] - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - expected.add_edge(1, 1, weight=2) - actual = nx.from_scipy_sparse_array( - A, parallel_edges=True, create_using=nx.DiGraph - ) - assert graphs_equal(actual, expected) - actual = nx.from_scipy_sparse_array( - A, parallel_edges=False, create_using=nx.DiGraph - ) - assert graphs_equal(actual, expected) - # Now each integer entry in the adjacency matrix is interpreted as the - # number of parallel edges in the graph if the appropriate keyword - # argument is specified. - edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)] - expected = nx.MultiDiGraph() - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - actual = nx.from_scipy_sparse_array( - A, parallel_edges=True, create_using=nx.MultiDiGraph - ) - assert graphs_equal(actual, expected) - expected = nx.MultiDiGraph() - expected.add_edges_from(set(edges), weight=1) - # The sole self-loop (edge 0) on vertex 1 should have weight 2. - expected[1][1][0]["weight"] = 2 - actual = nx.from_scipy_sparse_array( - A, parallel_edges=False, create_using=nx.MultiDiGraph - ) - assert graphs_equal(actual, expected) - - def test_symmetric(self): - """Tests that a symmetric matrix has edges added only once to an - undirected multigraph when using - :func:`networkx.from_scipy_sparse_array`. - - """ - A = sp.sparse.csr_array([[0, 1], [1, 0]]) - G = nx.from_scipy_sparse_array(A, create_using=nx.MultiGraph) - expected = nx.MultiGraph() - expected.add_edge(0, 1, weight=1) - assert graphs_equal(G, expected) - - -@pytest.mark.parametrize("sparse_format", ("csr", "csc", "dok")) -def test_from_scipy_sparse_array_formats(sparse_format): - """Test all formats supported by _generate_weighted_edges.""" - # trinode complete graph with non-uniform edge weights - expected = nx.Graph() - expected.add_edges_from( - [ - (0, 1, {"weight": 3}), - (0, 2, {"weight": 2}), - (1, 0, {"weight": 3}), - (1, 2, {"weight": 1}), - (2, 0, {"weight": 2}), - (2, 1, {"weight": 1}), - ] - ) - A = sp.sparse.coo_array([[0, 3, 2], [3, 0, 1], [2, 1, 0]]).asformat(sparse_format) - assert graphs_equal(expected, nx.from_scipy_sparse_array(A)) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_exceptions.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_exceptions.py deleted file mode 100644 index cf59983..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_exceptions.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -import networkx as nx - -# smoke tests for exceptions - - -def test_raises_networkxexception(): - with pytest.raises(nx.NetworkXException): - raise nx.NetworkXException - - -def test_raises_networkxerr(): - with pytest.raises(nx.NetworkXError): - raise nx.NetworkXError - - -def test_raises_networkx_pointless_concept(): - with pytest.raises(nx.NetworkXPointlessConcept): - raise nx.NetworkXPointlessConcept - - -def test_raises_networkxalgorithmerr(): - with pytest.raises(nx.NetworkXAlgorithmError): - raise nx.NetworkXAlgorithmError - - -def test_raises_networkx_unfeasible(): - with pytest.raises(nx.NetworkXUnfeasible): - raise nx.NetworkXUnfeasible - - -def test_raises_networkx_no_path(): - with pytest.raises(nx.NetworkXNoPath): - raise nx.NetworkXNoPath - - -def test_raises_networkx_unbounded(): - with pytest.raises(nx.NetworkXUnbounded): - raise nx.NetworkXUnbounded diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_import.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_import.py deleted file mode 100644 index 32aafdf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_import.py +++ /dev/null @@ -1,11 +0,0 @@ -import pytest - - -def test_namespace_alias(): - with pytest.raises(ImportError): - from networkx import nx - - -def test_namespace_nesting(): - with pytest.raises(ImportError): - from networkx import networkx diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_lazy_imports.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_lazy_imports.py deleted file mode 100644 index 9b7f1b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_lazy_imports.py +++ /dev/null @@ -1,97 +0,0 @@ -import importlib -import sys -import types - -import pytest - -import networkx.lazy_imports as lazy - - -def test_lazy_import_basics(): - math = lazy._lazy_import("math") - anything_not_real = lazy._lazy_import("anything_not_real") - - # Now test that accessing attributes does what it should - assert math.sin(math.pi) == pytest.approx(0, 1e-6) - # poor-mans pytest.raises for testing errors on attribute access - try: - anything_not_real.pi - assert False # Should not get here - except ModuleNotFoundError: - pass - assert isinstance(anything_not_real, lazy.DelayedImportErrorModule) - # see if it changes for second access - try: - anything_not_real.pi - assert False # Should not get here - except ModuleNotFoundError: - pass - - -def test_lazy_import_impact_on_sys_modules(): - math = lazy._lazy_import("math") - anything_not_real = lazy._lazy_import("anything_not_real") - - assert type(math) == types.ModuleType - assert "math" in sys.modules - assert type(anything_not_real) == lazy.DelayedImportErrorModule - assert "anything_not_real" not in sys.modules - - # only do this if numpy is installed - np_test = pytest.importorskip("numpy") - np = lazy._lazy_import("numpy") - assert type(np) == types.ModuleType - assert "numpy" in sys.modules - - np.pi # trigger load of numpy - - assert type(np) == types.ModuleType - assert "numpy" in sys.modules - - -def test_lazy_import_nonbuiltins(): - sp = lazy._lazy_import("scipy") - np = lazy._lazy_import("numpy") - if isinstance(sp, lazy.DelayedImportErrorModule): - try: - sp.special.erf - assert False - except ModuleNotFoundError: - pass - elif isinstance(np, lazy.DelayedImportErrorModule): - try: - np.sin(np.pi) - assert False - except ModuleNotFoundError: - pass - else: - assert sp.special.erf(np.pi) == pytest.approx(1, 1e-4) - - -def test_lazy_attach(): - name = "mymod" - submods = ["mysubmodule", "anothersubmodule"] - myall = {"not_real_submod": ["some_var_or_func"]} - - locls = { - "attach": lazy.attach, - "name": name, - "submods": submods, - "myall": myall, - } - s = "__getattr__, __lazy_dir__, __all__ = attach(name, submods, myall)" - - exec(s, {}, locls) - expected = { - "attach": lazy.attach, - "name": name, - "submods": submods, - "myall": myall, - "__getattr__": None, - "__lazy_dir__": None, - "__all__": None, - } - assert locls.keys() == expected.keys() - for k, v in expected.items(): - if v is not None: - assert locls[k] == v diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_relabel.py b/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_relabel.py deleted file mode 100644 index 0ebf4d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/tests/test_relabel.py +++ /dev/null @@ -1,347 +0,0 @@ -import pytest - -import networkx as nx -from networkx.generators.classic import empty_graph -from networkx.utils import edges_equal, nodes_equal - - -class TestRelabel: - def test_convert_node_labels_to_integers(self): - # test that empty graph converts fine for all options - G = empty_graph() - H = nx.convert_node_labels_to_integers(G, 100) - assert list(H.nodes()) == [] - assert list(H.edges()) == [] - - for opt in ["default", "sorted", "increasing degree", "decreasing degree"]: - G = empty_graph() - H = nx.convert_node_labels_to_integers(G, 100, ordering=opt) - assert list(H.nodes()) == [] - assert list(H.edges()) == [] - - G = empty_graph() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - H = nx.convert_node_labels_to_integers(G) - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - - H = nx.convert_node_labels_to_integers(G, 1000) - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert nodes_equal(H.nodes(), [1000, 1001, 1002, 1003]) - - H = nx.convert_node_labels_to_integers(G, ordering="increasing degree") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 1 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 3 - - H = nx.convert_node_labels_to_integers(G, ordering="decreasing degree") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 3 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 1 - - H = nx.convert_node_labels_to_integers( - G, ordering="increasing degree", label_attribute="label" - ) - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 1 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 3 - - # check mapping - assert H.nodes[3]["label"] == "C" - assert H.nodes[0]["label"] == "D" - assert H.nodes[1]["label"] == "A" or H.nodes[2]["label"] == "A" - assert H.nodes[1]["label"] == "B" or H.nodes[2]["label"] == "B" - - def test_convert_to_integers2(self): - G = empty_graph() - G.add_edges_from([("C", "D"), ("A", "B"), ("A", "C"), ("B", "C")]) - H = nx.convert_node_labels_to_integers(G, ordering="sorted") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - - H = nx.convert_node_labels_to_integers( - G, ordering="sorted", label_attribute="label" - ) - assert H.nodes[0]["label"] == "A" - assert H.nodes[1]["label"] == "B" - assert H.nodes[2]["label"] == "C" - assert H.nodes[3]["label"] == "D" - - def test_convert_to_integers_raise(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.convert_node_labels_to_integers(G, ordering="increasing age") - - def test_relabel_nodes_copy(self): - G = nx.empty_graph() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"} - H = nx.relabel_nodes(G, mapping) - assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"]) - - def test_relabel_nodes_function(self): - G = nx.empty_graph() - G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - # function mapping no longer encouraged but works - - def mapping(n): - return ord(n) - - H = nx.relabel_nodes(G, mapping) - assert nodes_equal(H.nodes(), [65, 66, 67, 68]) - - def test_relabel_nodes_callable_type(self): - G = nx.path_graph(4) - H = nx.relabel_nodes(G, str) - assert nodes_equal(H.nodes, ["0", "1", "2", "3"]) - - @pytest.mark.parametrize("non_mc", ("0123", ["0", "1", "2", "3"])) - def test_relabel_nodes_non_mapping_or_callable(self, non_mc): - """If `mapping` is neither a Callable or a Mapping, an exception - should be raised.""" - G = nx.path_graph(4) - with pytest.raises(AttributeError): - nx.relabel_nodes(G, non_mc) - - def test_relabel_nodes_graph(self): - G = nx.Graph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"} - H = nx.relabel_nodes(G, mapping) - assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"]) - - def test_relabel_nodes_orderedgraph(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - G.add_edges_from([(1, 3), (2, 3)]) - mapping = {1: "a", 2: "b", 3: "c"} - H = nx.relabel_nodes(G, mapping) - assert list(H.nodes) == ["a", "b", "c"] - - def test_relabel_nodes_digraph(self): - G = nx.DiGraph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"} - H = nx.relabel_nodes(G, mapping, copy=False) - assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"]) - - def test_relabel_nodes_multigraph(self): - G = nx.MultiGraph([("a", "b"), ("a", "b")]) - mapping = {"a": "aardvark", "b": "bear"} - G = nx.relabel_nodes(G, mapping, copy=False) - assert nodes_equal(G.nodes(), ["aardvark", "bear"]) - assert edges_equal(G.edges(), [("aardvark", "bear"), ("aardvark", "bear")]) - - def test_relabel_nodes_multidigraph(self): - G = nx.MultiDiGraph([("a", "b"), ("a", "b")]) - mapping = {"a": "aardvark", "b": "bear"} - G = nx.relabel_nodes(G, mapping, copy=False) - assert nodes_equal(G.nodes(), ["aardvark", "bear"]) - assert edges_equal(G.edges(), [("aardvark", "bear"), ("aardvark", "bear")]) - - def test_relabel_isolated_nodes_to_same(self): - G = nx.Graph() - G.add_nodes_from(range(4)) - mapping = {1: 1} - H = nx.relabel_nodes(G, mapping, copy=False) - assert nodes_equal(H.nodes(), list(range(4))) - - def test_relabel_nodes_missing(self): - G = nx.Graph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")]) - mapping = {0: "aardvark"} - # copy=True - H = nx.relabel_nodes(G, mapping, copy=True) - assert nodes_equal(H.nodes, G.nodes) - # copy=False - GG = G.copy() - nx.relabel_nodes(G, mapping, copy=False) - assert nodes_equal(G.nodes, GG.nodes) - - def test_relabel_copy_name(self): - G = nx.Graph() - H = nx.relabel_nodes(G, {}, copy=True) - assert H.graph == G.graph - H = nx.relabel_nodes(G, {}, copy=False) - assert H.graph == G.graph - G.name = "first" - H = nx.relabel_nodes(G, {}, copy=True) - assert H.graph == G.graph - H = nx.relabel_nodes(G, {}, copy=False) - assert H.graph == G.graph - - def test_relabel_toposort(self): - K5 = nx.complete_graph(4) - G = nx.complete_graph(4) - G = nx.relabel_nodes(G, {i: i + 1 for i in range(4)}, copy=False) - assert nx.is_isomorphic(K5, G) - G = nx.complete_graph(4) - G = nx.relabel_nodes(G, {i: i - 1 for i in range(4)}, copy=False) - assert nx.is_isomorphic(K5, G) - - def test_relabel_selfloop(self): - G = nx.DiGraph([(1, 1), (1, 2), (2, 3)]) - G = nx.relabel_nodes(G, {1: "One", 2: "Two", 3: "Three"}, copy=False) - assert nodes_equal(G.nodes(), ["One", "Three", "Two"]) - G = nx.MultiDiGraph([(1, 1), (1, 2), (2, 3)]) - G = nx.relabel_nodes(G, {1: "One", 2: "Two", 3: "Three"}, copy=False) - assert nodes_equal(G.nodes(), ["One", "Three", "Two"]) - G = nx.MultiDiGraph([(1, 1)]) - G = nx.relabel_nodes(G, {1: 0}, copy=False) - assert nodes_equal(G.nodes(), [0]) - - def test_relabel_multidigraph_inout_merge_nodes(self): - for MG in (nx.MultiGraph, nx.MultiDiGraph): - for cc in (True, False): - G = MG([(0, 4), (1, 4), (4, 2), (4, 3)]) - G[0][4][0]["value"] = "a" - G[1][4][0]["value"] = "b" - G[4][2][0]["value"] = "c" - G[4][3][0]["value"] = "d" - G.add_edge(0, 4, key="x", value="e") - G.add_edge(4, 3, key="x", value="f") - mapping = {0: 9, 1: 9, 2: 9, 3: 9} - H = nx.relabel_nodes(G, mapping, copy=cc) - # No ordering on keys enforced - assert {"value": "a"} in H[9][4].values() - assert {"value": "b"} in H[9][4].values() - assert {"value": "c"} in H[4][9].values() - assert len(H[4][9]) == 3 if G.is_directed() else 6 - assert {"value": "d"} in H[4][9].values() - assert {"value": "e"} in H[9][4].values() - assert {"value": "f"} in H[4][9].values() - assert len(H[9][4]) == 3 if G.is_directed() else 6 - - def test_relabel_multigraph_merge_inplace(self): - G = nx.MultiGraph([(0, 1), (0, 2), (0, 3), (0, 1), (0, 2), (0, 3)]) - G[0][1][0]["value"] = "a" - G[0][2][0]["value"] = "b" - G[0][3][0]["value"] = "c" - mapping = {1: 4, 2: 4, 3: 4} - nx.relabel_nodes(G, mapping, copy=False) - # No ordering on keys enforced - assert {"value": "a"} in G[0][4].values() - assert {"value": "b"} in G[0][4].values() - assert {"value": "c"} in G[0][4].values() - - def test_relabel_multidigraph_merge_inplace(self): - G = nx.MultiDiGraph([(0, 1), (0, 2), (0, 3)]) - G[0][1][0]["value"] = "a" - G[0][2][0]["value"] = "b" - G[0][3][0]["value"] = "c" - mapping = {1: 4, 2: 4, 3: 4} - nx.relabel_nodes(G, mapping, copy=False) - # No ordering on keys enforced - assert {"value": "a"} in G[0][4].values() - assert {"value": "b"} in G[0][4].values() - assert {"value": "c"} in G[0][4].values() - - def test_relabel_multidigraph_inout_copy(self): - G = nx.MultiDiGraph([(0, 4), (1, 4), (4, 2), (4, 3)]) - G[0][4][0]["value"] = "a" - G[1][4][0]["value"] = "b" - G[4][2][0]["value"] = "c" - G[4][3][0]["value"] = "d" - G.add_edge(0, 4, key="x", value="e") - G.add_edge(4, 3, key="x", value="f") - mapping = {0: 9, 1: 9, 2: 9, 3: 9} - H = nx.relabel_nodes(G, mapping, copy=True) - # No ordering on keys enforced - assert {"value": "a"} in H[9][4].values() - assert {"value": "b"} in H[9][4].values() - assert {"value": "c"} in H[4][9].values() - assert len(H[4][9]) == 3 - assert {"value": "d"} in H[4][9].values() - assert {"value": "e"} in H[9][4].values() - assert {"value": "f"} in H[4][9].values() - assert len(H[9][4]) == 3 - - def test_relabel_multigraph_merge_copy(self): - G = nx.MultiGraph([(0, 1), (0, 2), (0, 3)]) - G[0][1][0]["value"] = "a" - G[0][2][0]["value"] = "b" - G[0][3][0]["value"] = "c" - mapping = {1: 4, 2: 4, 3: 4} - H = nx.relabel_nodes(G, mapping, copy=True) - assert {"value": "a"} in H[0][4].values() - assert {"value": "b"} in H[0][4].values() - assert {"value": "c"} in H[0][4].values() - - def test_relabel_multidigraph_merge_copy(self): - G = nx.MultiDiGraph([(0, 1), (0, 2), (0, 3)]) - G[0][1][0]["value"] = "a" - G[0][2][0]["value"] = "b" - G[0][3][0]["value"] = "c" - mapping = {1: 4, 2: 4, 3: 4} - H = nx.relabel_nodes(G, mapping, copy=True) - assert {"value": "a"} in H[0][4].values() - assert {"value": "b"} in H[0][4].values() - assert {"value": "c"} in H[0][4].values() - - def test_relabel_multigraph_nonnumeric_key(self): - for MG in (nx.MultiGraph, nx.MultiDiGraph): - for cc in (True, False): - G = nx.MultiGraph() - G.add_edge(0, 1, key="I", value="a") - G.add_edge(0, 2, key="II", value="b") - G.add_edge(0, 3, key="II", value="c") - mapping = {1: 4, 2: 4, 3: 4} - nx.relabel_nodes(G, mapping, copy=False) - assert {"value": "a"} in G[0][4].values() - assert {"value": "b"} in G[0][4].values() - assert {"value": "c"} in G[0][4].values() - assert 0 in G[0][4] - assert "I" in G[0][4] - assert "II" in G[0][4] - - def test_relabel_circular(self): - G = nx.path_graph(3) - mapping = {0: 1, 1: 0} - H = nx.relabel_nodes(G, mapping, copy=True) - with pytest.raises(nx.NetworkXUnfeasible): - H = nx.relabel_nodes(G, mapping, copy=False) - - def test_relabel_preserve_node_order_full_mapping_with_copy_true(self): - G = nx.path_graph(3) - original_order = list(G.nodes()) - mapping = {2: "a", 1: "b", 0: "c"} # dictionary keys out of order on purpose - H = nx.relabel_nodes(G, mapping, copy=True) - new_order = list(H.nodes()) - assert [mapping.get(i, i) for i in original_order] == new_order - - def test_relabel_preserve_node_order_full_mapping_with_copy_false(self): - G = nx.path_graph(3) - original_order = list(G) - mapping = {2: "a", 1: "b", 0: "c"} # dictionary keys out of order on purpose - H = nx.relabel_nodes(G, mapping, copy=False) - new_order = list(H) - assert [mapping.get(i, i) for i in original_order] == new_order - - def test_relabel_preserve_node_order_partial_mapping_with_copy_true(self): - G = nx.path_graph(3) - original_order = list(G) - mapping = {1: "a", 0: "b"} # partial mapping and keys out of order on purpose - H = nx.relabel_nodes(G, mapping, copy=True) - new_order = list(H) - assert [mapping.get(i, i) for i in original_order] == new_order - - def test_relabel_preserve_node_order_partial_mapping_with_copy_false(self): - G = nx.path_graph(3) - original_order = list(G) - mapping = {1: "a", 0: "b"} # partial mapping and keys out of order on purpose - H = nx.relabel_nodes(G, mapping, copy=False) - new_order = list(H) - assert [mapping.get(i, i) for i in original_order] != new_order diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/__init__.py deleted file mode 100644 index d6abb17..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from networkx.utils.misc import * -from networkx.utils.decorators import * -from networkx.utils.random_sequence import * -from networkx.utils.union_find import * -from networkx.utils.rcm import * -from networkx.utils.heaps import * -from networkx.utils.configs import * -from networkx.utils.backends import * diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/backends.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/backends.py deleted file mode 100644 index 0b41d4c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/backends.py +++ /dev/null @@ -1,2501 +0,0 @@ -""" -Docs for backend users -~~~~~~~~~~~~~~~~~~~~~~ -NetworkX utilizes a plugin-dispatch architecture. A valid NetworkX backend -specifies `entry points -`_, named -``networkx.backends`` and an optional ``networkx.backend_info`` when it is -installed (not imported). This allows NetworkX to dispatch (redirect) function -calls to the backend so the execution flows to the designated backend -implementation. This design enhances flexibility and integration, making -NetworkX more adaptable and efficient. - -NetworkX can dispatch to backends **explicitly** (this requires changing code) -or **automatically** (this requires setting configuration or environment -variables). The best way to use a backend depends on the backend, your use -case, and whether you want to automatically convert to or from backend -graphs. Automatic conversions of graphs is always opt-in. - -To explicitly dispatch to a backend, use the `backend=` keyword argument in a -dispatchable function. This will convert (and cache by default) input NetworkX -graphs to backend graphs and call the backend implementation. Another explicit -way to use a backend is to create a backend graph directly--for example, -perhaps the backend has its own functions for loading data and creating -graphs--and pass that graph to a dispatchable function, which will then call -the backend implementation without converting. - -Using automatic dispatch requires setting configuration options. Every NetworkX -configuration may also be set from an environment variable and are processed at -the time networkx is imported. The following configuration variables are -supported: - -* ``nx.config.backend_priority`` (``NETWORKX_BACKEND_PRIORITY`` env var), a - list of backends, controls dispatchable functions that don't return graphs - such as e.g. ``nx.pagerank``. When one of these functions is called with - NetworkX graphs as input, the dispatcher iterates over the backends listed in - this backend_priority config and will use the first backend that implements - this function. The input NetworkX graphs are converted (and cached by - default) to backend graphs. Using this configuration can allow you to use the - full flexibility of NetworkX graphs and the performance of backend - implementations, but possible downsides are that creating NetworkX graphs, - converting to backend graphs, and caching backend graphs may all be - expensive. - -* ``nx.config.backend_priority.algos`` (``NETWORKX_BACKEND_PRIORITY_ALGOS`` env - var), can be used instead of ``nx.config.backend_priority`` - (``NETWORKX_BACKEND_PRIORITY`` env var) to emphasize that the setting only - affects the dispatching of algorithm functions as described above. - -* ``nx.config.backend_priority.generators`` - (``NETWORKX_BACKEND_PRIORITY_GENERATORS`` env var), a list of backends, - controls dispatchable functions that return graphs such as - nx.from_pandas_edgelist and nx.empty_graph. When one of these functions is - called, the first backend listed in this backend_priority config that - implements this function will be used and will return a backend graph. When - this backend graph is passed to other dispatchable NetworkX functions, it - will use the backend implementation if it exists or raise by default unless - nx.config.fallback_to_nx is True (default is False). Using this configuration - avoids creating NetworkX graphs, which subsequently avoids the need to - convert to and cache backend graphs as when using - nx.config.backend_priority.algos, but possible downsides are that the backend - graph may not behave the same as a NetworkX graph and the backend may not - implement all algorithms that you use, which may break your workflow. - -* ``nx.config.fallback_to_nx`` (``NETWORKX_FALLBACK_TO_NX`` env var), a boolean - (default False), controls what happens when a backend graph is passed to a - dispatchable function that is not implemented by that backend. The default - behavior when False is to raise. If True, then the backend graph will be - converted (and cached by default) to a NetworkX graph and will run with the - default NetworkX implementation. Enabling this configuration can allow - workflows to complete if the backend does not implement all algorithms used - by the workflow, but a possible downside is that it may require converting - the input backend graph to a NetworkX graph, which may be expensive. If a - backend graph is duck-type compatible as a NetworkX graph, then the backend - may choose not to convert to a NetworkX graph and use the incoming graph - as-is. - -* ``nx.config.cache_converted_graphs`` (``NETWORKX_CACHE_CONVERTED_GRAPHS`` env - var), a boolean (default True), controls whether graph conversions are cached - to G.__networkx_cache__ or not. Caching can improve performance by avoiding - repeated conversions, but it uses more memory. - -.. note:: Backends *should* follow the NetworkX backend naming convention. For - example, if a backend is named ``parallel`` and specified using - ``backend=parallel`` or ``NETWORKX_BACKEND_PRIORITY=parallel``, the package - installed is ``nx-parallel``, and we would use ``import nx_parallel`` if we - were to import the backend package directly. - -Backends are encouraged to document how they recommend to be used and whether -their graph types are duck-type compatible as NetworkX graphs. If backend -graphs are NetworkX-compatible and you want your workflow to automatically -"just work" with a backend--converting and caching if necessary--then use all -of the above configurations. Automatically converting graphs is opt-in, and -configuration gives the user control. - -Examples: ---------- - -Use the ``cugraph`` backend for every algorithm function it supports. This will -allow for fall back to the default NetworkX implementations for algorithm calls -not supported by cugraph because graph generator functions are still returning -NetworkX graphs. - -.. code-block:: bash - - bash> NETWORKX_BACKEND_PRIORITY=cugraph python my_networkx_script.py - -Explicitly use the ``parallel`` backend for a function call. - -.. code-block:: python - - nx.betweenness_centrality(G, k=10, backend="parallel") - -Explicitly use the ``parallel`` backend for a function call by passing an -instance of the backend graph type to the function. - -.. code-block:: python - - H = nx_parallel.ParallelGraph(G) - nx.betweenness_centrality(H, k=10) - -Explicitly use the ``parallel`` backend and pass additional backend-specific -arguments. Here, ``get_chunks`` is an argument unique to the ``parallel`` -backend. - -.. code-block:: python - - nx.betweenness_centrality(G, k=10, backend="parallel", get_chunks=get_chunks) - -Automatically dispatch the ``cugraph`` backend for all NetworkX algorithms and -generators, and allow the backend graph object returned from generators to be -passed to NetworkX functions the backend does not support. - -.. code-block:: bash - - bash> NETWORKX_BACKEND_PRIORITY_ALGOS=cugraph \\ - NETWORKX_BACKEND_PRIORITY_GENERATORS=cugraph \\ - NETWORKX_FALLBACK_TO_NX=True \\ - python my_networkx_script.py - -How does this work? -------------------- - -If you've looked at functions in the NetworkX codebase, you might have seen the -``@nx._dispatchable`` decorator on most of the functions. This decorator allows the NetworkX -function to dispatch to the corresponding backend function if available. When the decorated -function is called, it first checks for a backend to run the function, and if no appropriate -backend is specified or available, it runs the NetworkX version of the function. - -Backend Keyword Argument -^^^^^^^^^^^^^^^^^^^^^^^^ - -When a decorated function is called with the ``backend`` kwarg provided, it checks -if the specified backend is installed, and loads it. Next it checks whether to convert -input graphs by first resolving the backend of each input graph by looking -for an attribute named ``__networkx_backend__`` that holds the backend name for that -graph type. If all input graphs backend matches the ``backend`` kwarg, the backend's -function is called with the original inputs. If any of the input graphs do not match -the ``backend`` kwarg, they are converted to the backend graph type before calling. -Exceptions are raised if any step is not possible, e.g. if the backend does not -implement this function. - -Finding a Backend -^^^^^^^^^^^^^^^^^ - -When a decorated function is called without a ``backend`` kwarg, it tries to find a -dispatchable backend function. -The backend type of each input graph parameter is resolved (using the -``__networkx_backend__`` attribute) and if they all agree, that backend's function -is called if possible. Otherwise the backends listed in the config ``backend_priority`` -are considered one at a time in order. If that backend supports the function and -can convert the input graphs to its backend type, that backend function is called. -Otherwise the next backend is considered. - -During this process, the backends can provide helpful information to the dispatcher -via helper methods in the backend's interface. Backend methods ``can_run`` and -``should_run`` are used by the dispatcher to determine whether to use the backend -function. If the number of nodes is small, it might be faster to run the NetworkX -version of the function. This is how backends can provide info about whether to run. - -Falling Back to NetworkX -^^^^^^^^^^^^^^^^^^^^^^^^ - -If none of the backends are appropriate, we "fall back" to the NetworkX function. -That means we resolve the backends of all input graphs and if all are NetworkX -graphs we call the NetworkX function. If any are not NetworkX graphs, we raise -an exception unless the `fallback_to_nx` config is set. If it is, we convert all -graph types to NetworkX graph types before calling the NetworkX function. - -Functions that mutate the graph -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Any function decorated with the option that indicates it mutates the graph goes through -a slightly different path to automatically find backends. These functions typically -generate a graph, or add attributes or change the graph structure. The config -`backend_priority.generators` holds a list of backend names similar to the config -`backend_priority`. The process is similar for finding a matching backend. Once found, -the backend function is called and a backend graph is returned (instead of a NetworkX -graph). You can then use this backend graph in any function supported by the backend. -And you can use it for functions not supported by the backend if you set the config -`fallback_to_nx` to allow it to convert the backend graph to a NetworkX graph before -calling the function. - -Optional keyword arguments -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Backends can add optional keyword parameters to NetworkX functions to allow you to -control aspects of the backend algorithm. Thus the function signatures can be extended -beyond the NetworkX function signature. For example, the ``parallel`` backend might -have a parameter to specify how many CPUs to use. These parameters are collected -by the dispatchable decorator code at the start of the function call and used when -calling the backend function. - -Existing Backends -^^^^^^^^^^^^^^^^^ - -NetworkX does not know all the backends that have been created. In fact, the -NetworkX library does not need to know that a backend exists for it to work. As -long as the backend package creates the ``entry_point``, and provides the -correct interface, it will be called when the user requests it using one of the -three approaches described above. Some backends have been working with the -NetworkX developers to ensure smooth operation. - -Refer to the :doc:`/backends` section to see a list of available backends known -to work with the current stable release of NetworkX. - -.. _introspect: - -Introspection and Logging -------------------------- -Introspection techniques aim to demystify dispatching and backend graph conversion behaviors. - -The primary way to see what the dispatch machinery is doing is by enabling logging. -This can help you verify that the backend you specified is being used. -You can enable NetworkX's backend logger to print to ``sys.stderr`` like this:: - - import logging - nxl = logging.getLogger("networkx") - nxl.addHandler(logging.StreamHandler()) - nxl.setLevel(logging.DEBUG) - -And you can disable it by running this:: - - nxl.setLevel(logging.CRITICAL) - -Refer to :external+python:mod:`logging` to learn more about the logging facilities in Python. - -By looking at the ``.backends`` attribute, you can get the set of all currently -installed backends that implement a particular function. For example:: - - >>> nx.betweenness_centrality.backends # doctest: +SKIP - {'parallel'} - -The function docstring will also show which installed backends support it -along with any backend-specific notes and keyword arguments:: - - >>> help(nx.betweenness_centrality) # doctest: +SKIP - ... - Backends - -------- - parallel : Parallel backend for NetworkX algorithms - The parallel computation is implemented by dividing the nodes into chunks - and computing betweenness centrality for each chunk concurrently. - ... - -The NetworkX documentation website also includes info about trusted backends of NetworkX in function references. -For example, see :func:`~networkx.algorithms.shortest_paths.weighted.all_pairs_bellman_ford_path_length`. - -Introspection capabilities are currently limited, but we are working to improve them. -We plan to make it easier to answer questions such as: - -- What happened (and why)? -- What *will* happen (and why)? -- Where was time spent (including conversions)? -- What is in the cache and how much memory is it using? - -Transparency is essential to allow for greater understanding, debug-ability, -and customization. After all, NetworkX dispatching is extremely flexible and can -support advanced workflows with multiple backends and fine-tuned configuration, -but introspection can be helpful by describing *when* and *how* to evolve your workflow -to meet your needs. If you have suggestions for how to improve introspection, please -`let us know `_! - -Docs for backend developers -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Creating a custom backend -------------------------- - -1. Defining a ``BackendInterface`` object: - - Note that the ``BackendInterface`` doesn't need to must be a class. It can be an - instance of a class, or a module as well. You can define the following methods or - functions in your backend's ``BackendInterface`` object.: - - 1. ``convert_from_nx`` and ``convert_to_nx`` methods or functions are required for - backend dispatching to work. The arguments to ``convert_from_nx`` are: - - - ``G`` : NetworkX Graph - - ``edge_attrs`` : dict, optional - Dictionary mapping edge attributes to default values if missing in ``G``. - If None, then no edge attributes will be converted and default may be 1. - - ``node_attrs``: dict, optional - Dictionary mapping node attributes to default values if missing in ``G``. - If None, then no node attributes will be converted. - - ``preserve_edge_attrs`` : bool - Whether to preserve all edge attributes. - - ``preserve_node_attrs`` : bool - Whether to preserve all node attributes. - - ``preserve_graph_attrs`` : bool - Whether to preserve all graph attributes. - - ``preserve_all_attrs`` : bool - Whether to preserve all graph, node, and edge attributes. - - ``name`` : str - The name of the algorithm. - - ``graph_name`` : str - The name of the graph argument being converted. - - 2. ``can_run`` (Optional): - If your backend only partially implements an algorithm, you can define - a ``can_run(name, args, kwargs)`` function in your ``BackendInterface`` object that - returns True or False indicating whether the backend can run the algorithm with - the given arguments or not. Instead of a boolean you can also return a string - message to inform the user why that algorithm can't be run. - - 3. ``should_run`` (Optional): - A backend may also define ``should_run(name, args, kwargs)`` - that is similar to ``can_run``, but answers whether the backend *should* be run. - ``should_run`` is only run when performing backend graph conversions. Like - ``can_run``, it receives the original arguments so it can decide whether it - should be run by inspecting the arguments. ``can_run`` runs before - ``should_run``, so ``should_run`` may assume ``can_run`` is True. If not - implemented by the backend, ``can_run``and ``should_run`` are assumed to - always return True if the backend implements the algorithm. - - 4. ``on_start_tests`` (Optional): - A special ``on_start_tests(items)`` function may be defined by the backend. - It will be called with the list of NetworkX tests discovered. Each item - is a test object that can be marked as xfail if the backend does not support - the test using ``item.add_marker(pytest.mark.xfail(reason=...))``. - -2. Adding entry points - - To be discoverable by NetworkX, your package must register an - `entry-point `_ - ``networkx.backends`` in the package's metadata, with a `key pointing to your - dispatch object `_ . - For example, if you are using ``setuptools`` to manage your backend package, - you can `add the following to your pyproject.toml file `_:: - - [project.entry-points."networkx.backends"] - backend_name = "your_backend_interface_object" - - You can also add the ``backend_info`` entry-point. It points towards the ``get_info`` - function that returns all the backend information, which is then used to build the - "Additional Backend Implementation" box at the end of algorithm's documentation - page. Note that the `get_info` function shouldn't import your backend package.:: - - [project.entry-points."networkx.backend_info"] - backend_name = "your_get_info_function" - - The ``get_info`` should return a dictionary with following key-value pairs: - - ``backend_name`` : str or None - It is the name passed in the ``backend`` kwarg. - - ``project`` : str or None - The name of your backend project. - - ``package`` : str or None - The name of your backend package. - - ``url`` : str or None - This is the url to either your backend's codebase or documentation, and - will be displayed as a hyperlink to the ``backend_name``, in the - "Additional backend implementations" section. - - ``short_summary`` : str or None - One line summary of your backend which will be displayed in the - "Additional backend implementations" section. - - ``default_config`` : dict - A dictionary mapping the backend config parameter names to their default values. - This is used to automatically initialize the default configs for all the - installed backends at the time of networkx's import. - - .. seealso:: `~networkx.utils.configs.Config` - - - ``functions`` : dict or None - A dictionary mapping function names to a dictionary of information - about the function. The information can include the following keys: - - - ``url`` : str or None - The url to ``function``'s source code or documentation. - - ``additional_docs`` : str or None - A short description or note about the backend function's - implementation. - - ``additional_parameters`` : dict or None - A dictionary mapping additional parameters headers to their - short descriptions. For example:: - - "additional_parameters": { - 'param1 : str, function (default = "chunks")' : "...", - 'param2 : int' : "...", - } - - If any of these keys are not present, the corresponding information - will not be displayed in the "Additional backend implementations" - section on NetworkX docs website. - - Note that your backend's docs would only appear on the official NetworkX docs only - if your backend is a trusted backend of NetworkX, and is present in the - `.circleci/config.yml` and `.github/workflows/deploy-docs.yml` files in the - NetworkX repository. - -3. Defining a Backend Graph class - - The backend must create an object with an attribute ``__networkx_backend__`` that holds - a string with the entry point name:: - - class BackendGraph: - __networkx_backend__ = "backend_name" - ... - - A backend graph instance may have a ``G.__networkx_cache__`` dict to enable - caching, and care should be taken to clear the cache when appropriate. - -Testing the Custom backend --------------------------- - -To test your custom backend, you can run the NetworkX test suite on your backend. -This also ensures that the custom backend is compatible with NetworkX's API. -The following steps will help you run the tests: - -1. Setting Backend Environment Variables: - - ``NETWORKX_TEST_BACKEND`` : Setting this to your backend's ``backend_name`` will - let NetworkX's dispatch machinery to automatically convert a regular NetworkX - ``Graph``, ``DiGraph``, ``MultiGraph``, etc. to their backend equivalents, using - ``your_backend_interface_object.convert_from_nx(G, ...)`` function. - - ``NETWORKX_FALLBACK_TO_NX`` (default=False) : Setting this variable to `True` will - instruct tests to use a NetworkX ``Graph`` for algorithms not implemented by your - custom backend. Setting this to `False` will only run the tests for algorithms - implemented by your custom backend and tests for other algorithms will ``xfail``. - -2. Running Tests: - You can invoke NetworkX tests for your custom backend with the following commands:: - - NETWORKX_TEST_BACKEND= - NETWORKX_FALLBACK_TO_NX=True # or False - pytest --pyargs networkx - -How tests are run? ------------------- - -1. While dispatching to the backend implementation the ``_convert_and_call`` function - is used and while testing the ``_convert_and_call_for_tests`` function is used. - Other than testing it also checks for functions that return numpy scalars, and - for functions that return graphs it runs the backend implementation and the - networkx implementation and then converts the backend graph into a NetworkX graph - and then compares them, and returns the networkx graph. This can be regarded as - (pragmatic) technical debt. We may replace these checks in the future. - -2. Conversions while running tests: - - Convert NetworkX graphs using ``.convert_from_nx(G, ...)`` into - the backend graph. - - Pass the backend graph objects to the backend implementation of the algorithm. - - Convert the result back to a form expected by NetworkX tests using - ``.convert_to_nx(result, ...)``. - - For nx_loopback, the graph is copied using the dispatchable metadata - -3. Dispatchable algorithms that are not implemented by the backend - will cause a ``pytest.xfail``, when the ``NETWORKX_FALLBACK_TO_NX`` - environment variable is set to ``False``, giving some indication that - not all tests are running, while avoiding causing an explicit failure. -""" - -import inspect -import itertools -import logging -import os -import warnings -from functools import partial -from importlib.metadata import entry_points - -import networkx as nx - -from .configs import BackendPriorities, Config, NetworkXConfig -from .decorators import argmap - -__all__ = ["_dispatchable"] - -_logger = logging.getLogger(__name__) - - -def _do_nothing(): - """This does nothing at all, yet it helps turn `_dispatchable` into functions.""" - - -def _get_backends(group, *, load_and_call=False): - """ - Retrieve NetworkX ``backends`` and ``backend_info`` from the entry points. - - Parameters - ----------- - group : str - The entry_point to be retrieved. - load_and_call : bool, optional - If True, load and call the backend. Defaults to False. - - Returns - -------- - dict - A dictionary mapping backend names to their respective backend objects. - - Notes - ------ - If a backend is defined more than once, a warning is issued. - The `nx_loopback` backend is removed if it exists, as it is only available during testing. - A warning is displayed if an error occurs while loading a backend. - """ - items = entry_points(group=group) - rv = {} - for ep in items: - if ep.name in rv: - warnings.warn( - f"networkx backend defined more than once: {ep.name}", - RuntimeWarning, - stacklevel=2, - ) - elif load_and_call: - try: - rv[ep.name] = ep.load()() - except Exception as exc: - warnings.warn( - f"Error encountered when loading info for backend {ep.name}: {exc}", - RuntimeWarning, - stacklevel=2, - ) - else: - rv[ep.name] = ep - rv.pop("nx_loopback", None) - return rv - - -# Note: "networkx" will be in `backend_info`, but not `backends` or `config.backends`. -# It is valid to use "networkx"` as backend argument and in `config.backend_priority`. -# We may make "networkx" a "proper" backend and have it in `backends` and `config.backends`. -backends = _get_backends("networkx.backends") -backend_info = {} # fill backend_info after networkx is imported in __init__.py - -# Load and cache backends on-demand -_loaded_backends = {} # type: ignore[var-annotated] -_registered_algorithms = {} - - -# Get default configuration from environment variables at import time -def _comma_sep_to_list(string): - return [stripped for x in string.strip().split(",") if (stripped := x.strip())] - - -def _set_configs_from_environment(): - """Initialize ``config.backend_priority``, load backend_info and config. - - This gets default values from environment variables (see ``nx.config`` for details). - This function is run at the very end of importing networkx. It is run at this time - to avoid loading backend_info before the rest of networkx is imported in case a - backend uses networkx for its backend_info (e.g. subclassing the Config class.) - """ - # backend_info is defined above as empty dict. Fill it after import finishes. - backend_info.update(_get_backends("networkx.backend_info", load_and_call=True)) - backend_info.update( - (backend, {}) for backend in backends.keys() - backend_info.keys() - ) - - # set up config based on backend_info and environment - config = NetworkXConfig( - backend_priority=BackendPriorities( - algos=[], - generators=[], - ), - backends=Config( - **{ - backend: ( - cfg - if isinstance(cfg := info["default_config"], Config) - else Config(**cfg) - ) - if "default_config" in info - else Config() - for backend, info in backend_info.items() - } - ), - cache_converted_graphs=bool( - os.environ.get("NETWORKX_CACHE_CONVERTED_GRAPHS", True) - ), - fallback_to_nx=bool(os.environ.get("NETWORKX_FALLBACK_TO_NX", False)), - warnings_to_ignore={ - x.strip() - for x in os.environ.get("NETWORKX_WARNINGS_TO_IGNORE", "").split(",") - if x.strip() - }, - ) - backend_info["networkx"] = {} - type(config.backends).__doc__ = "All installed NetworkX backends and their configs." - - # NETWORKX_BACKEND_PRIORITY is the same as NETWORKX_BACKEND_PRIORITY_ALGOS - priorities = { - key[26:].lower(): val - for key, val in os.environ.items() - if key.startswith("NETWORKX_BACKEND_PRIORITY_") - } - backend_priority = config.backend_priority - backend_priority.algos = ( - _comma_sep_to_list(priorities.pop("algos")) - if "algos" in priorities - else _comma_sep_to_list( - os.environ.get( - "NETWORKX_BACKEND_PRIORITY", - os.environ.get("NETWORKX_AUTOMATIC_BACKENDS", ""), - ) - ) - ) - backend_priority.generators = _comma_sep_to_list(priorities.pop("generators", "")) - for key in sorted(priorities): - backend_priority[key] = _comma_sep_to_list(priorities[key]) - - return config - - -def _always_run(name, args, kwargs): - return True - - -def _load_backend(backend_name): - if backend_name in _loaded_backends: - return _loaded_backends[backend_name] - if backend_name not in backends: - raise ImportError(f"'{backend_name}' backend is not installed") - rv = _loaded_backends[backend_name] = backends[backend_name].load() - if not hasattr(rv, "can_run"): - rv.can_run = _always_run - if not hasattr(rv, "should_run"): - rv.should_run = _always_run - return rv - - -class _dispatchable: - _is_testing = False - - class _fallback_to_nx: - """Class property that returns ``nx.config.fallback_to_nx``.""" - - def __get__(self, instance, owner=None): - warnings.warn( - "`_dispatchable._fallback_to_nx` is deprecated and will be removed " - "in NetworkX v3.5. Use `nx.config.fallback_to_nx` instead.", - category=DeprecationWarning, - stacklevel=2, - ) - return nx.config.fallback_to_nx - - # Note that chaining `@classmethod` and `@property` was removed in Python 3.13 - _fallback_to_nx = _fallback_to_nx() # type: ignore[assignment,misc] - - def __new__( - cls, - func=None, - *, - name=None, - graphs="G", - edge_attrs=None, - node_attrs=None, - preserve_edge_attrs=False, - preserve_node_attrs=False, - preserve_graph_attrs=False, - preserve_all_attrs=False, - mutates_input=False, - returns_graph=False, - ): - """A decorator function that is used to redirect the execution of ``func`` - function to its backend implementation. - - This decorator function dispatches to - a different backend implementation based on the input graph types, and it also - manages all the ``backend_kwargs``. Usage can be any of the following decorator - forms: - - - ``@_dispatchable`` - - ``@_dispatchable()`` - - ``@_dispatchable(name="override_name")`` - - ``@_dispatchable(graphs="graph_var_name")`` - - ``@_dispatchable(edge_attrs="weight")`` - - ``@_dispatchable(graphs={"G": 0, "H": 1}, edge_attrs={"weight": "default"})`` - with 0 and 1 giving the position in the signature function for graph - objects. When ``edge_attrs`` is a dict, keys are keyword names and values - are defaults. - - Parameters - ---------- - func : callable, optional - The function to be decorated. If ``func`` is not provided, returns a - partial object that can be used to decorate a function later. If ``func`` - is provided, returns a new callable object that dispatches to a backend - algorithm based on input graph types. - - name : str, optional - The name of the algorithm to use for dispatching. If not provided, - the name of ``func`` will be used. ``name`` is useful to avoid name - conflicts, as all dispatched algorithms live in a single namespace. - For example, ``tournament.is_strongly_connected`` had a name conflict - with the standard ``nx.is_strongly_connected``, so we used - ``@_dispatchable(name="tournament_is_strongly_connected")``. - - graphs : str or dict or None, default "G" - If a string, the parameter name of the graph, which must be the first - argument of the wrapped function. If more than one graph is required - for the algorithm (or if the graph is not the first argument), provide - a dict keyed to argument names with argument position as values for each - graph argument. For example, ``@_dispatchable(graphs={"G": 0, "auxiliary?": 4})`` - indicates the 0th parameter ``G`` of the function is a required graph, - and the 4th parameter ``auxiliary?`` is an optional graph. - To indicate that an argument is a list of graphs, do ``"[graphs]"``. - Use ``graphs=None``, if *no* arguments are NetworkX graphs such as for - graph generators, readers, and conversion functions. - - edge_attrs : str or dict, optional - ``edge_attrs`` holds information about edge attribute arguments - and default values for those edge attributes. - If a string, ``edge_attrs`` holds the function argument name that - indicates a single edge attribute to include in the converted graph. - The default value for this attribute is 1. To indicate that an argument - is a list of attributes (all with default value 1), use e.g. ``"[attrs]"``. - If a dict, ``edge_attrs`` holds a dict keyed by argument names, with - values that are either the default value or, if a string, the argument - name that indicates the default value. - - node_attrs : str or dict, optional - Like ``edge_attrs``, but for node attributes. - - preserve_edge_attrs : bool or str or dict, optional - For bool, whether to preserve all edge attributes. - For str, the parameter name that may indicate (with ``True`` or a - callable argument) whether all edge attributes should be preserved - when converting. - For dict of ``{graph_name: {attr: default}}``, indicate pre-determined - edge attributes (and defaults) to preserve for input graphs. - - preserve_node_attrs : bool or str or dict, optional - Like ``preserve_edge_attrs``, but for node attributes. - - preserve_graph_attrs : bool or set - For bool, whether to preserve all graph attributes. - For set, which input graph arguments to preserve graph attributes. - - preserve_all_attrs : bool - Whether to preserve all edge, node and graph attributes. - This overrides all the other preserve_*_attrs. - - mutates_input : bool or dict, default False - For bool, whether the function mutates an input graph argument. - For dict of ``{arg_name: arg_pos}``, arguments that indicate whether an - input graph will be mutated, and ``arg_name`` may begin with ``"not "`` - to negate the logic (for example, this is used by ``copy=`` arguments). - By default, dispatching doesn't convert input graphs to a different - backend for functions that mutate input graphs. - - returns_graph : bool, default False - Whether the function can return or yield a graph object. By default, - dispatching doesn't convert input graphs to a different backend for - functions that return graphs. - """ - if func is None: - return partial( - _dispatchable, - name=name, - graphs=graphs, - edge_attrs=edge_attrs, - node_attrs=node_attrs, - preserve_edge_attrs=preserve_edge_attrs, - preserve_node_attrs=preserve_node_attrs, - preserve_graph_attrs=preserve_graph_attrs, - preserve_all_attrs=preserve_all_attrs, - mutates_input=mutates_input, - returns_graph=returns_graph, - ) - if isinstance(func, str): - raise TypeError("'name' and 'graphs' must be passed by keyword") from None - # If name not provided, use the name of the function - if name is None: - name = func.__name__ - - self = object.__new__(cls) - - # standard function-wrapping stuff - # __annotations__ not used - self.__name__ = func.__name__ - # self.__doc__ = func.__doc__ # __doc__ handled as cached property - self.__defaults__ = func.__defaults__ - # We "magically" add `backend=` keyword argument to allow backend to be specified - if func.__kwdefaults__: - self.__kwdefaults__ = {**func.__kwdefaults__, "backend": None} - else: - self.__kwdefaults__ = {"backend": None} - self.__module__ = func.__module__ - self.__qualname__ = func.__qualname__ - self.__dict__.update(func.__dict__) - self.__wrapped__ = func - - # Supplement docstring with backend info; compute and cache when needed - self._orig_doc = func.__doc__ - self._cached_doc = None - - self.orig_func = func - self.name = name - self.edge_attrs = edge_attrs - self.node_attrs = node_attrs - self.preserve_edge_attrs = preserve_edge_attrs or preserve_all_attrs - self.preserve_node_attrs = preserve_node_attrs or preserve_all_attrs - self.preserve_graph_attrs = preserve_graph_attrs or preserve_all_attrs - self.mutates_input = mutates_input - # Keep `returns_graph` private for now, b/c we may extend info on return types - self._returns_graph = returns_graph - - if edge_attrs is not None and not isinstance(edge_attrs, str | dict): - raise TypeError( - f"Bad type for edge_attrs: {type(edge_attrs)}. Expected str or dict." - ) from None - if node_attrs is not None and not isinstance(node_attrs, str | dict): - raise TypeError( - f"Bad type for node_attrs: {type(node_attrs)}. Expected str or dict." - ) from None - if not isinstance(self.preserve_edge_attrs, bool | str | dict): - raise TypeError( - f"Bad type for preserve_edge_attrs: {type(self.preserve_edge_attrs)}." - " Expected bool, str, or dict." - ) from None - if not isinstance(self.preserve_node_attrs, bool | str | dict): - raise TypeError( - f"Bad type for preserve_node_attrs: {type(self.preserve_node_attrs)}." - " Expected bool, str, or dict." - ) from None - if not isinstance(self.preserve_graph_attrs, bool | set): - raise TypeError( - f"Bad type for preserve_graph_attrs: {type(self.preserve_graph_attrs)}." - " Expected bool or set." - ) from None - if not isinstance(self.mutates_input, bool | dict): - raise TypeError( - f"Bad type for mutates_input: {type(self.mutates_input)}." - " Expected bool or dict." - ) from None - if not isinstance(self._returns_graph, bool): - raise TypeError( - f"Bad type for returns_graph: {type(self._returns_graph)}." - " Expected bool." - ) from None - - if isinstance(graphs, str): - graphs = {graphs: 0} - elif graphs is None: - pass - elif not isinstance(graphs, dict): - raise TypeError( - f"Bad type for graphs: {type(graphs)}. Expected str or dict." - ) from None - elif len(graphs) == 0: - raise KeyError("'graphs' must contain at least one variable name") from None - - # This dict comprehension is complicated for better performance; equivalent shown below. - self.optional_graphs = set() - self.list_graphs = set() - if graphs is None: - self.graphs = {} - else: - self.graphs = { - self.optional_graphs.add(val := k[:-1]) or val - if (last := k[-1]) == "?" - else self.list_graphs.add(val := k[1:-1]) or val - if last == "]" - else k: v - for k, v in graphs.items() - } - # The above is equivalent to: - # self.optional_graphs = {k[:-1] for k in graphs if k[-1] == "?"} - # self.list_graphs = {k[1:-1] for k in graphs if k[-1] == "]"} - # self.graphs = {k[:-1] if k[-1] == "?" else k: v for k, v in graphs.items()} - - # Compute and cache the signature on-demand - self._sig = None - - # Which backends implement this function? - self.backends = { - backend - for backend, info in backend_info.items() - if "functions" in info and name in info["functions"] - } - - if name in _registered_algorithms: - raise KeyError( - f"Algorithm already exists in dispatch registry: {name}" - ) from None - # Use the magic of `argmap` to turn `self` into a function. This does result - # in small additional overhead compared to calling `_dispatchable` directly, - # but `argmap` has the magical property that it can stack with other `argmap` - # decorators "for free". Being a function is better for REPRs and type-checkers. - self = argmap(_do_nothing)(self) - _registered_algorithms[name] = self - return self - - @property - def __doc__(self): - """If the cached documentation exists, it is returned. - Otherwise, the documentation is generated using _make_doc() method, - cached, and then returned.""" - - if (rv := self._cached_doc) is not None: - return rv - rv = self._cached_doc = self._make_doc() - return rv - - @__doc__.setter - def __doc__(self, val): - """Sets the original documentation to the given value and resets the - cached documentation.""" - - self._orig_doc = val - self._cached_doc = None - - @property - def __signature__(self): - """Return the signature of the original function, with the addition of - the `backend` and `backend_kwargs` parameters.""" - - if self._sig is None: - sig = inspect.signature(self.orig_func) - # `backend` is now a reserved argument used by dispatching. - # assert "backend" not in sig.parameters - if not any( - p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values() - ): - sig = sig.replace( - parameters=[ - *sig.parameters.values(), - inspect.Parameter( - "backend", inspect.Parameter.KEYWORD_ONLY, default=None - ), - inspect.Parameter( - "backend_kwargs", inspect.Parameter.VAR_KEYWORD - ), - ] - ) - else: - *parameters, var_keyword = sig.parameters.values() - sig = sig.replace( - parameters=[ - *parameters, - inspect.Parameter( - "backend", inspect.Parameter.KEYWORD_ONLY, default=None - ), - var_keyword, - ] - ) - self._sig = sig - return self._sig - - def __call__(self, /, *args, backend=None, **kwargs): - """Returns the result of the original function, or the backend function if - the backend is specified and that backend implements `func`.""" - - if not backends: - # Fast path if no backends are installed - if backend is not None and backend != "networkx": - raise ImportError(f"'{backend}' backend is not installed") - return self.orig_func(*args, **kwargs) - - # Use `backend_name` in this function instead of `backend`. - # This is purely for aesthetics and to make it easier to search for this - # variable since "backend" is used in many comments and log/error messages. - backend_name = backend - if backend_name is not None and backend_name not in backend_info: - raise ImportError(f"'{backend_name}' backend is not installed") - - graphs_resolved = {} - for gname, pos in self.graphs.items(): - if pos < len(args): - if gname in kwargs: - raise TypeError(f"{self.name}() got multiple values for {gname!r}") - graph = args[pos] - elif gname in kwargs: - graph = kwargs[gname] - elif gname not in self.optional_graphs: - raise TypeError( - f"{self.name}() missing required graph argument: {gname}" - ) - else: - continue - if graph is None: - if gname not in self.optional_graphs: - raise TypeError( - f"{self.name}() required graph argument {gname!r} is None; must be a graph" - ) - else: - graphs_resolved[gname] = graph - - # Alternative to the above that does not check duplicated args or missing required graphs. - # graphs_resolved = { - # gname: graph - # for gname, pos in self.graphs.items() - # if (graph := args[pos] if pos < len(args) else kwargs.get(gname)) is not None - # } - - # Check if any graph comes from a backend - if self.list_graphs: - # Make sure we don't lose values by consuming an iterator - args = list(args) - for gname in self.list_graphs & graphs_resolved.keys(): - list_of_graphs = list(graphs_resolved[gname]) - graphs_resolved[gname] = list_of_graphs - if gname in kwargs: - kwargs[gname] = list_of_graphs - else: - args[self.graphs[gname]] = list_of_graphs - - graph_backend_names = { - getattr(g, "__networkx_backend__", None) - for gname, g in graphs_resolved.items() - if gname not in self.list_graphs - } - for gname in self.list_graphs & graphs_resolved.keys(): - graph_backend_names.update( - getattr(g, "__networkx_backend__", None) - for g in graphs_resolved[gname] - ) - else: - graph_backend_names = { - getattr(g, "__networkx_backend__", None) - for g in graphs_resolved.values() - } - - backend_priority = nx.config.backend_priority.get( - self.name, - nx.config.backend_priority.generators - if self._returns_graph - else nx.config.backend_priority.algos, - ) - if self._is_testing and backend_priority and backend_name is None: - # Special path if we are running networkx tests with a backend. - # This even runs for (and handles) functions that mutate input graphs. - return self._convert_and_call_for_tests( - backend_priority[0], - args, - kwargs, - fallback_to_nx=nx.config.fallback_to_nx, - ) - - graph_backend_names.discard(None) - if backend_name is not None: - # Must run with the given backend. - # `can_run` only used for better log and error messages. - # Check `mutates_input` for logging, not behavior. - blurb = ( - "No other backends will be attempted, because the backend was " - f"specified with the `backend='{backend_name}'` keyword argument." - ) - extra_message = ( - f"'{backend_name}' backend raised NotImplementedError when calling " - f"`{self.name}'. {blurb}" - ) - if not graph_backend_names or graph_backend_names == {backend_name}: - # All graphs are backend graphs--no need to convert! - if self._can_backend_run(backend_name, args, kwargs): - return self._call_with_backend( - backend_name, args, kwargs, extra_message=extra_message - ) - if self._does_backend_have(backend_name): - extra = " for the given arguments" - else: - extra = "" - raise NotImplementedError( - f"`{self.name}' is not implemented by '{backend_name}' backend" - f"{extra}. {blurb}" - ) - if self._can_convert(backend_name, graph_backend_names): - if self._can_backend_run(backend_name, args, kwargs): - if self._will_call_mutate_input(args, kwargs): - _logger.debug( - "`%s' will mutate an input graph. This prevents automatic conversion " - "to, and use of, backends listed in `nx.config.backend_priority`. " - "Using backend specified by the " - "`backend='%s'` keyword argument. This may change behavior by not " - "mutating inputs.", - self.name, - backend_name, - ) - mutations = [] - else: - mutations = None - rv = self._convert_and_call( - backend_name, - graph_backend_names, - args, - kwargs, - extra_message=extra_message, - mutations=mutations, - ) - if mutations: - for cache, key in mutations: - # If the call mutates inputs, then remove all inputs gotten - # from cache. We do this after all conversions (and call) so - # that a graph can be gotten from a cache multiple times. - cache.pop(key, None) - return rv - if self._does_backend_have(backend_name): - extra = " for the given arguments" - else: - extra = "" - raise NotImplementedError( - f"`{self.name}' is not implemented by '{backend_name}' backend" - f"{extra}. {blurb}" - ) - if len(graph_backend_names) == 1: - maybe_s = "" - graph_backend_names = f"'{next(iter(graph_backend_names))}'" - else: - maybe_s = "s" - raise TypeError( - f"`{self.name}' is unable to convert graph from backend{maybe_s} " - f"{graph_backend_names} to '{backend_name}' backend, which was " - f"specified with the `backend='{backend_name}'` keyword argument. " - f"{blurb}" - ) - - if self._will_call_mutate_input(args, kwargs): - # The current behavior for functions that mutate input graphs: - # - # 1. If backend is specified by `backend=` keyword, use it (done above). - # 2. If inputs are from one backend, try to use it. - # 3. If all input graphs are instances of `nx.Graph`, then run with the - # default "networkx" implementation. - # - # Do not automatically convert if a call will mutate inputs, because doing - # so would change behavior. Hence, we should fail if there are multiple input - # backends or if the input backend does not implement the function. However, - # we offer a way for backends to circumvent this if they do not implement - # this function: we will fall back to the default "networkx" implementation - # without using conversions if all input graphs are subclasses of `nx.Graph`. - blurb = ( - "conversions between backends (if configured) will not be attempted, " - "because this may change behavior. You may specify a backend to use " - "by passing e.g. `backend='networkx'` keyword, but this may also " - "change behavior by not mutating inputs." - ) - fallback_blurb = ( - "This call will mutate inputs, so fall back to 'networkx' " - "backend (without converting) since all input graphs are " - "instances of nx.Graph and are hopefully compatible.", - ) - if len(graph_backend_names) == 1: - [backend_name] = graph_backend_names - msg_template = ( - f"Backend '{backend_name}' does not implement `{self.name}'%s. " - f"This call will mutate an input, so automatic {blurb}" - ) - # `can_run` is only used for better log and error messages - try: - if self._can_backend_run(backend_name, args, kwargs): - return self._call_with_backend( - backend_name, - args, - kwargs, - extra_message=msg_template % " with these arguments", - ) - except NotImplementedError as exc: - if all(isinstance(g, nx.Graph) for g in graphs_resolved.values()): - _logger.debug( - "Backend '%s' raised when calling `%s': %s. %s", - backend_name, - self.name, - exc, - fallback_blurb, - ) - else: - raise - else: - if nx.config.fallback_to_nx and all( - # Consider dropping the `isinstance` check here to allow - # duck-type graphs, but let's wait for a backend to ask us. - isinstance(g, nx.Graph) - for g in graphs_resolved.values() - ): - # Log that we are falling back to networkx - _logger.debug( - "Backend '%s' can't run `%s'. %s", - backend_name, - self.name, - fallback_blurb, - ) - else: - if self._does_backend_have(backend_name): - extra = " with these arguments" - else: - extra = "" - raise NotImplementedError(msg_template % extra) - elif nx.config.fallback_to_nx and all( - # Consider dropping the `isinstance` check here to allow - # duck-type graphs, but let's wait for a backend to ask us. - isinstance(g, nx.Graph) - for g in graphs_resolved.values() - ): - # Log that we are falling back to networkx - _logger.debug( - "`%s' was called with inputs from multiple backends: %s. %s", - self.name, - graph_backend_names, - fallback_blurb, - ) - else: - raise RuntimeError( - f"`{self.name}' will mutate an input, but it was called with inputs " - f"from multiple backends: {graph_backend_names}. Automatic {blurb}" - ) - # At this point, no backends are available to handle the call with - # the input graph types, but if the input graphs are compatible - # nx.Graph instances, fall back to networkx without converting. - return self.orig_func(*args, **kwargs) - - # We may generalize fallback configuration as e.g. `nx.config.backend_fallback` - if nx.config.fallback_to_nx or not graph_backend_names: - # Use "networkx" by default if there are no inputs from backends. - # For example, graph generators should probably return NetworkX graphs - # instead of raising NotImplementedError. - backend_fallback = ["networkx"] - else: - backend_fallback = [] - - # ########################## - # # How this behaves today # - # ########################## - # - # The prose below describes the implementation and a *possible* way to - # generalize "networkx" as "just another backend". The code is structured - # to perhaps someday support backend-to-backend conversions (including - # simply passing objects from one backend directly to another backend; - # the dispatch machinery does not necessarily need to perform conversions), - # but since backend-to-backend matching is not yet supported, the following - # code is merely a convenient way to implement dispatch behaviors that have - # been carefully developed since NetworkX 3.0 and to include falling back - # to the default NetworkX implementation. - # - # The current behavior for functions that don't mutate input graphs: - # - # 1. If backend is specified by `backend=` keyword, use it (done above). - # 2. If input is from a backend other than "networkx", try to use it. - # - Note: if present, "networkx" graphs will be converted to the backend. - # 3. If input is from "networkx" (or no backend), try to use backends from - # `backend_priority` before running with the default "networkx" implementation. - # 4. If configured, "fall back" and run with the default "networkx" implementation. - # - # ################################################ - # # How this is implemented and may work someday # - # ################################################ - # - # Let's determine the order of backends we should try according - # to `backend_priority`, `backend_fallback`, and input backends. - # There are two† dimensions of priorities to consider: - # backend_priority > unspecified > backend_fallback - # and - # backend of an input > not a backend of an input - # These are combined to form five groups of priorities as such: - # - # input ~input - # +-------+-------+ - # backend_priority | 1 | 2 | - # unspecified | 3 | N/A | (if only 1) - # backend_fallback | 4 | 5 | - # +-------+-------+ - # - # This matches the behaviors we developed in versions 3.0 to 3.2, it - # ought to cover virtually all use cases we expect, and I (@eriknw) don't - # think it can be done any simpler (although it can be generalized further - # and made to be more complicated to capture 100% of *possible* use cases). - # Some observations: - # - # 1. If an input is in `backend_priority`, it will be used before trying a - # backend that is higher priority in `backend_priority` and not an input. - # 2. To prioritize converting from one backend to another even if both implement - # a function, list one in `backend_priority` and one in `backend_fallback`. - # 3. To disable conversions, set `backend_priority` and `backend_fallback` to []. - # - # †: There is actually a third dimension of priorities: - # should_run == True > should_run == False - # Backends with `can_run == True` and `should_run == False` are tried last. - # - seen = set() - group1 = [] # In backend_priority, and an input - group2 = [] # In backend_priority, but not an input - for name in backend_priority: - if name in seen: - continue - seen.add(name) - if name in graph_backend_names: - group1.append(name) - else: - group2.append(name) - group4 = [] # In backend_fallback, and an input - group5 = [] # In backend_fallback, but not an input - for name in backend_fallback: - if name in seen: - continue - seen.add(name) - if name in graph_backend_names: - group4.append(name) - else: - group5.append(name) - # An input, but not in backend_priority or backend_fallback. - group3 = graph_backend_names - seen - if len(group3) > 1: - # `group3` backends are not configured for automatic conversion or fallback. - # There are at least two issues if this group contains multiple backends: - # - # 1. How should we prioritize them? We have no good way to break ties. - # Although we could arbitrarily choose alphabetical or left-most, - # let's follow the Zen of Python and refuse the temptation to guess. - # 2. We probably shouldn't automatically convert to these backends, - # because we are not configured to do so. - # - # (2) is important to allow disabling all conversions by setting both - # `nx.config.backend_priority` and `nx.config.backend_fallback` to []. - # - # If there is a single backend in `group3`, then giving it priority over - # the fallback backends is what is generally expected. For example, this - # allows input graphs of `backend_fallback` backends (such as "networkx") - # to be converted to, and run with, the unspecified backend. - _logger.debug( - "Call to `%s' has inputs from multiple backends, %s, that " - "have no priority set in `nx.config.backend_priority`, " - "so automatic conversions to " - "these backends will not be attempted.", - self.name, - group3, - ) - group3 = () - - try_order = list(itertools.chain(group1, group2, group3, group4, group5)) - if len(try_order) > 1: - # Should we consider adding an option for more verbose logging? - # For example, we could explain the order of `try_order` in detail. - _logger.debug( - "Call to `%s' has inputs from %s backends, and will try to use " - "backends in the following order: %s", - self.name, - graph_backend_names or "no", - try_order, - ) - backends_to_try_again = [] - for is_not_first, backend_name in enumerate(try_order): - if is_not_first: - _logger.debug("Trying next backend: '%s'", backend_name) - try: - if not graph_backend_names or graph_backend_names == {backend_name}: - if self._can_backend_run(backend_name, args, kwargs): - return self._call_with_backend(backend_name, args, kwargs) - elif self._can_convert( - backend_name, graph_backend_names - ) and self._can_backend_run(backend_name, args, kwargs): - if self._should_backend_run(backend_name, args, kwargs): - rv = self._convert_and_call( - backend_name, graph_backend_names, args, kwargs - ) - if ( - self._returns_graph - and graph_backend_names - and backend_name not in graph_backend_names - ): - # If the function has graph inputs and graph output, we try - # to make it so the backend of the return type will match the - # backend of the input types. In case this is not possible, - # let's tell the user that the backend of the return graph - # has changed. Perhaps we could try to convert back, but - # "fallback" backends for graph generators should typically - # be compatible with NetworkX graphs. - _logger.debug( - "Call to `%s' is returning a graph from a different " - "backend! It has inputs from %s backends, but ran with " - "'%s' backend and is returning graph from '%s' backend", - self.name, - graph_backend_names, - backend_name, - backend_name, - ) - return rv - # `should_run` is False, but `can_run` is True, so try again later - backends_to_try_again.append(backend_name) - except NotImplementedError as exc: - _logger.debug( - "Backend '%s' raised when calling `%s': %s", - backend_name, - self.name, - exc, - ) - - # We are about to fail. Let's try backends with can_run=True and should_run=False. - # This is unlikely to help today since we try to run with "networkx" before this. - for backend_name in backends_to_try_again: - _logger.debug( - "Trying backend: '%s' (ignoring `should_run=False`)", backend_name - ) - try: - rv = self._convert_and_call( - backend_name, graph_backend_names, args, kwargs - ) - if ( - self._returns_graph - and graph_backend_names - and backend_name not in graph_backend_names - ): - _logger.debug( - "Call to `%s' is returning a graph from a different " - "backend! It has inputs from %s backends, but ran with " - "'%s' backend and is returning graph from '%s' backend", - self.name, - graph_backend_names, - backend_name, - backend_name, - ) - return rv - except NotImplementedError as exc: - _logger.debug( - "Backend '%s' raised when calling `%s': %s", - backend_name, - self.name, - exc, - ) - # As a final effort, we could try to convert and run with `group3` backends - # that we discarded when `len(group3) > 1`, but let's not consider doing - # so until there is a reasonable request for it. - - if len(unspecified_backends := graph_backend_names - seen) > 1: - raise TypeError( - f"Unable to convert inputs from {graph_backend_names} backends and " - f"run `{self.name}'. NetworkX is configured to automatically convert " - f"to {try_order} backends. To remedy this, you may enable automatic " - f"conversion to {unspecified_backends} backends by adding them to " - "`nx.config.backend_priority`, or you " - "may specify a backend to use with the `backend=` keyword argument." - ) - raise NotImplementedError( - f"`{self.name}' is not implemented by {try_order} backends. To remedy " - "this, you may enable automatic conversion to more backends (including " - "'networkx') by adding them to `nx.config.backend_priority`, " - "or you may specify a backend to use with " - "the `backend=` keyword argument." - ) - - def _will_call_mutate_input(self, args, kwargs): - return (mutates_input := self.mutates_input) and ( - mutates_input is True - or any( - # If `mutates_input` begins with "not ", then assume the argument is bool, - # otherwise treat it as a node or edge attribute if it's not None. - not ( - args[arg_pos] - if len(args) > arg_pos - # This assumes that e.g. `copy=True` is the default - else kwargs.get(arg_name[4:], True) - ) - if arg_name.startswith("not ") - else (args[arg_pos] if len(args) > arg_pos else kwargs.get(arg_name)) - is not None - for arg_name, arg_pos in mutates_input.items() - ) - ) - - def _can_convert(self, backend_name, graph_backend_names): - # Backend-to-backend conversion not supported yet. - # We can only convert to and from networkx. - rv = backend_name == "networkx" or graph_backend_names.issubset( - {"networkx", backend_name} - ) - if not rv: - _logger.debug( - "Unable to convert from %s backends to '%s' backend", - graph_backend_names, - backend_name, - ) - return rv - - def _does_backend_have(self, backend_name): - """Does the specified backend have this algorithm?""" - if backend_name == "networkx": - return True - # Inspect the backend; don't trust metadata used to create `self.backends` - backend = _load_backend(backend_name) - return hasattr(backend, self.name) - - def _can_backend_run(self, backend_name, args, kwargs): - """Can the specified backend run this algorithm with these arguments?""" - if backend_name == "networkx": - return True - backend = _load_backend(backend_name) - # `backend.can_run` and `backend.should_run` may return strings that describe - # why they can't or shouldn't be run. - if not hasattr(backend, self.name): - _logger.debug( - "Backend '%s' does not implement `%s'", backend_name, self.name - ) - return False - can_run = backend.can_run(self.name, args, kwargs) - if isinstance(can_run, str) or not can_run: - reason = f", because: {can_run}" if isinstance(can_run, str) else "" - _logger.debug( - "Backend '%s' can't run `%s` with arguments: %s%s", - backend_name, - self.name, - _LazyArgsRepr(self, args, kwargs), - reason, - ) - return False - return True - - def _should_backend_run(self, backend_name, args, kwargs): - """Should the specified backend run this algorithm with these arguments? - - Note that this does not check ``backend.can_run``. - """ - # `backend.can_run` and `backend.should_run` may return strings that describe - # why they can't or shouldn't be run. - if backend_name == "networkx": - return True - backend = _load_backend(backend_name) - should_run = backend.should_run(self.name, args, kwargs) - if isinstance(should_run, str) or not should_run: - reason = f", because: {should_run}" if isinstance(should_run, str) else "" - _logger.debug( - "Backend '%s' shouldn't run `%s` with arguments: %s%s", - backend_name, - self.name, - _LazyArgsRepr(self, args, kwargs), - reason, - ) - return False - return True - - def _convert_arguments(self, backend_name, args, kwargs, *, use_cache, mutations): - """Convert graph arguments to the specified backend. - - Returns - ------- - args tuple and kwargs dict - """ - bound = self.__signature__.bind(*args, **kwargs) - bound.apply_defaults() - if not self.graphs: - bound_kwargs = bound.kwargs - del bound_kwargs["backend"] - return bound.args, bound_kwargs - if backend_name == "networkx": - # `backend_interface.convert_from_nx` preserves everything - preserve_edge_attrs = preserve_node_attrs = preserve_graph_attrs = True - else: - preserve_edge_attrs = self.preserve_edge_attrs - preserve_node_attrs = self.preserve_node_attrs - preserve_graph_attrs = self.preserve_graph_attrs - edge_attrs = self.edge_attrs - node_attrs = self.node_attrs - # Convert graphs into backend graph-like object - # Include the edge and/or node labels if provided to the algorithm - if preserve_edge_attrs is False: - # e.g. `preserve_edge_attrs=False` - pass - elif preserve_edge_attrs is True: - # e.g. `preserve_edge_attrs=True` - edge_attrs = None - elif isinstance(preserve_edge_attrs, str): - if bound.arguments[preserve_edge_attrs] is True or callable( - bound.arguments[preserve_edge_attrs] - ): - # e.g. `preserve_edge_attrs="attr"` and `func(attr=True)` - # e.g. `preserve_edge_attrs="attr"` and `func(attr=myfunc)` - preserve_edge_attrs = True - edge_attrs = None - elif bound.arguments[preserve_edge_attrs] is False and ( - isinstance(edge_attrs, str) - and edge_attrs == preserve_edge_attrs - or isinstance(edge_attrs, dict) - and preserve_edge_attrs in edge_attrs - ): - # e.g. `preserve_edge_attrs="attr"` and `func(attr=False)` - # Treat `False` argument as meaning "preserve_edge_data=False" - # and not `False` as the edge attribute to use. - preserve_edge_attrs = False - edge_attrs = None - else: - # e.g. `preserve_edge_attrs="attr"` and `func(attr="weight")` - preserve_edge_attrs = False - # Else: e.g. `preserve_edge_attrs={"G": {"weight": 1}}` - - if edge_attrs is None: - # May have been set to None above b/c all attributes are preserved - pass - elif isinstance(edge_attrs, str): - if edge_attrs[0] == "[": - # e.g. `edge_attrs="[edge_attributes]"` (argument of list of attributes) - # e.g. `func(edge_attributes=["foo", "bar"])` - edge_attrs = { - edge_attr: 1 for edge_attr in bound.arguments[edge_attrs[1:-1]] - } - elif callable(bound.arguments[edge_attrs]): - # e.g. `edge_attrs="weight"` and `func(weight=myfunc)` - preserve_edge_attrs = True - edge_attrs = None - elif bound.arguments[edge_attrs] is not None: - # e.g. `edge_attrs="weight"` and `func(weight="foo")` (default of 1) - edge_attrs = {bound.arguments[edge_attrs]: 1} - elif self.name == "to_numpy_array" and hasattr( - bound.arguments["dtype"], "names" - ): - # Custom handling: attributes may be obtained from `dtype` - edge_attrs = { - edge_attr: 1 for edge_attr in bound.arguments["dtype"].names - } - else: - # e.g. `edge_attrs="weight"` and `func(weight=None)` - edge_attrs = None - else: - # e.g. `edge_attrs={"attr": "default"}` and `func(attr="foo", default=7)` - # e.g. `edge_attrs={"attr": 0}` and `func(attr="foo")` - edge_attrs = { - edge_attr: bound.arguments.get(val, 1) if isinstance(val, str) else val - for key, val in edge_attrs.items() - if (edge_attr := bound.arguments[key]) is not None - } - - if preserve_node_attrs is False: - # e.g. `preserve_node_attrs=False` - pass - elif preserve_node_attrs is True: - # e.g. `preserve_node_attrs=True` - node_attrs = None - elif isinstance(preserve_node_attrs, str): - if bound.arguments[preserve_node_attrs] is True or callable( - bound.arguments[preserve_node_attrs] - ): - # e.g. `preserve_node_attrs="attr"` and `func(attr=True)` - # e.g. `preserve_node_attrs="attr"` and `func(attr=myfunc)` - preserve_node_attrs = True - node_attrs = None - elif bound.arguments[preserve_node_attrs] is False and ( - isinstance(node_attrs, str) - and node_attrs == preserve_node_attrs - or isinstance(node_attrs, dict) - and preserve_node_attrs in node_attrs - ): - # e.g. `preserve_node_attrs="attr"` and `func(attr=False)` - # Treat `False` argument as meaning "preserve_node_data=False" - # and not `False` as the node attribute to use. Is this used? - preserve_node_attrs = False - node_attrs = None - else: - # e.g. `preserve_node_attrs="attr"` and `func(attr="weight")` - preserve_node_attrs = False - # Else: e.g. `preserve_node_attrs={"G": {"pos": None}}` - - if node_attrs is None: - # May have been set to None above b/c all attributes are preserved - pass - elif isinstance(node_attrs, str): - if node_attrs[0] == "[": - # e.g. `node_attrs="[node_attributes]"` (argument of list of attributes) - # e.g. `func(node_attributes=["foo", "bar"])` - node_attrs = { - node_attr: None for node_attr in bound.arguments[node_attrs[1:-1]] - } - elif callable(bound.arguments[node_attrs]): - # e.g. `node_attrs="weight"` and `func(weight=myfunc)` - preserve_node_attrs = True - node_attrs = None - elif bound.arguments[node_attrs] is not None: - # e.g. `node_attrs="weight"` and `func(weight="foo")` - node_attrs = {bound.arguments[node_attrs]: None} - else: - # e.g. `node_attrs="weight"` and `func(weight=None)` - node_attrs = None - else: - # e.g. `node_attrs={"attr": "default"}` and `func(attr="foo", default=7)` - # e.g. `node_attrs={"attr": 0}` and `func(attr="foo")` - node_attrs = { - node_attr: bound.arguments.get(val) if isinstance(val, str) else val - for key, val in node_attrs.items() - if (node_attr := bound.arguments[key]) is not None - } - - # It should be safe to assume that we either have networkx graphs or backend graphs. - # Future work: allow conversions between backends. - for gname in self.graphs: - if gname in self.list_graphs: - bound.arguments[gname] = [ - self._convert_graph( - backend_name, - g, - edge_attrs=edge_attrs, - node_attrs=node_attrs, - preserve_edge_attrs=preserve_edge_attrs, - preserve_node_attrs=preserve_node_attrs, - preserve_graph_attrs=preserve_graph_attrs, - graph_name=gname, - use_cache=use_cache, - mutations=mutations, - ) - if getattr(g, "__networkx_backend__", "networkx") != backend_name - else g - for g in bound.arguments[gname] - ] - else: - graph = bound.arguments[gname] - if graph is None: - if gname in self.optional_graphs: - continue - raise TypeError( - f"Missing required graph argument `{gname}` in {self.name} function" - ) - if isinstance(preserve_edge_attrs, dict): - preserve_edges = False - edges = preserve_edge_attrs.get(gname, edge_attrs) - else: - preserve_edges = preserve_edge_attrs - edges = edge_attrs - if isinstance(preserve_node_attrs, dict): - preserve_nodes = False - nodes = preserve_node_attrs.get(gname, node_attrs) - else: - preserve_nodes = preserve_node_attrs - nodes = node_attrs - if isinstance(preserve_graph_attrs, set): - preserve_graph = gname in preserve_graph_attrs - else: - preserve_graph = preserve_graph_attrs - if getattr(graph, "__networkx_backend__", "networkx") != backend_name: - bound.arguments[gname] = self._convert_graph( - backend_name, - graph, - edge_attrs=edges, - node_attrs=nodes, - preserve_edge_attrs=preserve_edges, - preserve_node_attrs=preserve_nodes, - preserve_graph_attrs=preserve_graph, - graph_name=gname, - use_cache=use_cache, - mutations=mutations, - ) - bound_kwargs = bound.kwargs - del bound_kwargs["backend"] - return bound.args, bound_kwargs - - def _convert_graph( - self, - backend_name, - graph, - *, - edge_attrs, - node_attrs, - preserve_edge_attrs, - preserve_node_attrs, - preserve_graph_attrs, - graph_name, - use_cache, - mutations, - ): - if ( - use_cache - and (nx_cache := getattr(graph, "__networkx_cache__", None)) is not None - ): - cache = nx_cache.setdefault("backends", {}).setdefault(backend_name, {}) - key = _get_cache_key( - edge_attrs=edge_attrs, - node_attrs=node_attrs, - preserve_edge_attrs=preserve_edge_attrs, - preserve_node_attrs=preserve_node_attrs, - preserve_graph_attrs=preserve_graph_attrs, - ) - compat_key, rv = _get_from_cache(cache, key, mutations=mutations) - if rv is not None: - if "cache" not in nx.config.warnings_to_ignore: - warnings.warn( - "Note: conversions to backend graphs are saved to cache " - "(`G.__networkx_cache__` on the original graph) by default." - "\n\nThis warning means the cached graph is being used " - f"for the {backend_name!r} backend in the " - f"call to {self.name}.\n\nFor the cache to be consistent " - "(i.e., correct), the input graph must not have been " - "manually mutated since the cached graph was created. " - "Examples of manually mutating the graph data structures " - "resulting in an inconsistent cache include:\n\n" - " >>> G[u][v][key] = val\n\n" - "and\n\n" - " >>> for u, v, d in G.edges(data=True):\n" - " ... d[key] = val\n\n" - "Using methods such as `G.add_edge(u, v, weight=val)` " - "will correctly clear the cache to keep it consistent. " - "You may also use `G.__networkx_cache__.clear()` to " - "manually clear the cache, or set `G.__networkx_cache__` " - "to None to disable caching for G. Enable or disable caching " - "globally via `nx.config.cache_converted_graphs` config.\n\n" - "To disable this warning:\n\n" - ' >>> nx.config.warnings_to_ignore.add("cache")\n' - ) - _logger.debug( - "Using cached converted graph (from '%s' to '%s' backend) " - "in call to `%s' for '%s' argument", - getattr(graph, "__networkx_backend__", None), - backend_name, - self.name, - graph_name, - ) - return rv - - if backend_name == "networkx": - # Perhaps we should check that "__networkx_backend__" attribute exists - # and return the original object if not. - if not hasattr(graph, "__networkx_backend__"): - _logger.debug( - "Unable to convert input to 'networkx' backend in call to `%s' for " - "'%s argument, because it is not from a backend (i.e., it does not " - "have `G.__networkx_backend__` attribute). Using the original " - "object: %s", - self.name, - graph_name, - graph, - ) - # This may fail, but let it fail in the networkx function - return graph - backend = _load_backend(graph.__networkx_backend__) - rv = backend.convert_to_nx(graph) - else: - backend = _load_backend(backend_name) - rv = backend.convert_from_nx( - graph, - edge_attrs=edge_attrs, - node_attrs=node_attrs, - preserve_edge_attrs=preserve_edge_attrs, - preserve_node_attrs=preserve_node_attrs, - # Always preserve graph attrs when we are caching b/c this should be - # cheap and may help prevent extra (unnecessary) conversions. Because - # we do this, we don't need `preserve_graph_attrs` in the cache key. - preserve_graph_attrs=preserve_graph_attrs or use_cache, - name=self.name, - graph_name=graph_name, - ) - if use_cache and nx_cache is not None and mutations is None: - _set_to_cache(cache, key, rv) - _logger.debug( - "Caching converted graph (from '%s' to '%s' backend) " - "in call to `%s' for '%s' argument", - getattr(graph, "__networkx_backend__", None), - backend_name, - self.name, - graph_name, - ) - - return rv - - def _call_with_backend(self, backend_name, args, kwargs, *, extra_message=None): - """Call this dispatchable function with a backend without converting inputs.""" - if backend_name == "networkx": - return self.orig_func(*args, **kwargs) - backend = _load_backend(backend_name) - _logger.debug( - "Using backend '%s' for call to `%s' with arguments: %s", - backend_name, - self.name, - _LazyArgsRepr(self, args, kwargs), - ) - try: - return getattr(backend, self.name)(*args, **kwargs) - except NotImplementedError as exc: - if extra_message is not None: - _logger.debug( - "Backend '%s' raised when calling `%s': %s", - backend_name, - self.name, - exc, - ) - raise NotImplementedError(extra_message) from exc - raise - - def _convert_and_call( - self, - backend_name, - input_backend_names, - args, - kwargs, - *, - extra_message=None, - mutations=None, - ): - """Call this dispatchable function with a backend after converting inputs. - - Parameters - ---------- - backend_name : str - input_backend_names : set[str] - args : arguments tuple - kwargs : keywords dict - extra_message : str, optional - Additional message to log if NotImplementedError is raised by backend. - mutations : list, optional - Used to clear objects gotten from cache if inputs will be mutated. - """ - if backend_name == "networkx": - func = self.orig_func - else: - backend = _load_backend(backend_name) - func = getattr(backend, self.name) - other_backend_names = input_backend_names - {backend_name} - _logger.debug( - "Converting input graphs from %s backend%s to '%s' backend for call to `%s'", - other_backend_names - if len(other_backend_names) > 1 - else f"'{next(iter(other_backend_names))}'", - "s" if len(other_backend_names) > 1 else "", - backend_name, - self.name, - ) - try: - converted_args, converted_kwargs = self._convert_arguments( - backend_name, - args, - kwargs, - use_cache=nx.config.cache_converted_graphs, - mutations=mutations, - ) - except NotImplementedError as exc: - # Only log the exception if we are adding an extra message - # because we don't want to lose any information. - _logger.debug( - "Failed to convert graphs from %s to '%s' backend for call to `%s'" - + ("" if extra_message is None else ": %s"), - input_backend_names, - backend_name, - self.name, - *(() if extra_message is None else (exc,)), - ) - if extra_message is not None: - raise NotImplementedError(extra_message) from exc - raise - if backend_name != "networkx": - _logger.debug( - "Using backend '%s' for call to `%s' with arguments: %s", - backend_name, - self.name, - _LazyArgsRepr(self, converted_args, converted_kwargs), - ) - try: - return func(*converted_args, **converted_kwargs) - except NotImplementedError as exc: - if extra_message is not None: - _logger.debug( - "Backend '%s' raised when calling `%s': %s", - backend_name, - self.name, - exc, - ) - raise NotImplementedError(extra_message) from exc - raise - - def _convert_and_call_for_tests( - self, backend_name, args, kwargs, *, fallback_to_nx=False - ): - """Call this dispatchable function with a backend; for use with testing.""" - backend = _load_backend(backend_name) - if not self._can_backend_run(backend_name, args, kwargs): - if fallback_to_nx or not self.graphs: - if fallback_to_nx: - _logger.debug( - "Falling back to use 'networkx' instead of '%s' backend " - "for call to `%s' with arguments: %s", - backend_name, - self.name, - _LazyArgsRepr(self, args, kwargs), - ) - return self.orig_func(*args, **kwargs) - - import pytest - - msg = f"'{self.name}' not implemented by {backend_name}" - if hasattr(backend, self.name): - msg += " with the given arguments" - pytest.xfail(msg) - - from collections.abc import Iterable, Iterator, Mapping - from copy import copy, deepcopy - from io import BufferedReader, BytesIO, StringIO, TextIOWrapper - from itertools import tee - from random import Random - - import numpy as np - from numpy.random import Generator, RandomState - from scipy.sparse import sparray - - # We sometimes compare the backend result to the original result, - # so we need two sets of arguments. We tee iterators and copy - # random state so that they may be used twice. - if not args: - args1 = args2 = args - else: - args1, args2 = zip( - *( - (arg, deepcopy(arg)) - if isinstance(arg, RandomState) - else (arg, copy(arg)) - if isinstance(arg, BytesIO | StringIO | Random | Generator) - else tee(arg) - if isinstance(arg, Iterator) - and not isinstance(arg, BufferedReader | TextIOWrapper) - else (arg, arg) - for arg in args - ) - ) - if not kwargs: - kwargs1 = kwargs2 = kwargs - else: - kwargs1, kwargs2 = zip( - *( - ((k, v), (k, deepcopy(v))) - if isinstance(v, RandomState) - else ((k, v), (k, copy(v))) - if isinstance(v, BytesIO | StringIO | Random | Generator) - else ((k, (teed := tee(v))[0]), (k, teed[1])) - if isinstance(v, Iterator) - and not isinstance(v, BufferedReader | TextIOWrapper) - else ((k, v), (k, v)) - for k, v in kwargs.items() - ) - ) - kwargs1 = dict(kwargs1) - kwargs2 = dict(kwargs2) - try: - converted_args, converted_kwargs = self._convert_arguments( - backend_name, args1, kwargs1, use_cache=False, mutations=None - ) - _logger.debug( - "Using backend '%s' for call to `%s' with arguments: %s", - backend_name, - self.name, - _LazyArgsRepr(self, converted_args, converted_kwargs), - ) - result = getattr(backend, self.name)(*converted_args, **converted_kwargs) - except NotImplementedError as exc: - if fallback_to_nx: - _logger.debug( - "Graph conversion failed; falling back to use 'networkx' instead " - "of '%s' backend for call to `%s'", - backend_name, - self.name, - ) - return self.orig_func(*args2, **kwargs2) - import pytest - - pytest.xfail( - exc.args[0] if exc.args else f"{self.name} raised {type(exc).__name__}" - ) - # Verify that `self._returns_graph` is correct. This compares the return type - # to the type expected from `self._returns_graph`. This handles tuple and list - # return types, but *does not* catch functions that yield graphs. - if ( - self._returns_graph - != ( - isinstance(result, nx.Graph) - or hasattr(result, "__networkx_backend__") - or isinstance(result, tuple | list) - and any( - isinstance(x, nx.Graph) or hasattr(x, "__networkx_backend__") - for x in result - ) - ) - and not ( - # May return Graph or None - self.name in {"check_planarity", "check_planarity_recursive"} - and any(x is None for x in result) - ) - and not ( - # May return Graph or dict - self.name in {"held_karp_ascent"} - and any(isinstance(x, dict) for x in result) - ) - and self.name - not in { - # yields graphs - "all_triads", - "general_k_edge_subgraphs", - # yields graphs or arrays - "nonisomorphic_trees", - } - ): - raise RuntimeError(f"`returns_graph` is incorrect for {self.name}") - - def check_result(val, depth=0): - if isinstance(val, np.number): - raise RuntimeError( - f"{self.name} returned a numpy scalar {val} ({type(val)}, depth={depth})" - ) - if isinstance(val, np.ndarray | sparray): - return - if isinstance(val, nx.Graph): - check_result(val._node, depth=depth + 1) - check_result(val._adj, depth=depth + 1) - return - if isinstance(val, Iterator): - raise NotImplementedError - if isinstance(val, Iterable) and not isinstance(val, str): - for x in val: - check_result(x, depth=depth + 1) - if isinstance(val, Mapping): - for x in val.values(): - check_result(x, depth=depth + 1) - - def check_iterator(it): - for val in it: - try: - check_result(val) - except RuntimeError as exc: - raise RuntimeError( - f"{self.name} returned a numpy scalar {val} ({type(val)})" - ) from exc - yield val - - if self.name in {"from_edgelist"}: - # numpy scalars are explicitly given as values in some tests - pass - elif isinstance(result, Iterator): - result = check_iterator(result) - else: - try: - check_result(result) - except RuntimeError as exc: - raise RuntimeError( - f"{self.name} returned a numpy scalar {result} ({type(result)})" - ) from exc - check_result(result) - - if self.name in { - "edmonds_karp", - "barycenter", - "contracted_edge", - "contracted_nodes", - "stochastic_graph", - "relabel_nodes", - "maximum_branching", - "incremental_closeness_centrality", - "minimal_branching", - "minimum_spanning_arborescence", - "recursive_simple_cycles", - "connected_double_edge_swap", - }: - # Special-case algorithms that mutate input graphs - bound = self.__signature__.bind(*converted_args, **converted_kwargs) - bound.apply_defaults() - bound2 = self.__signature__.bind(*args2, **kwargs2) - bound2.apply_defaults() - if self.name in { - "minimal_branching", - "minimum_spanning_arborescence", - "recursive_simple_cycles", - "connected_double_edge_swap", - }: - G1 = backend.convert_to_nx(bound.arguments["G"]) - G2 = bound2.arguments["G"] - G2._adj = G1._adj - if G2.is_directed(): - G2._pred = G1._pred - nx._clear_cache(G2) - elif self.name == "edmonds_karp": - R1 = backend.convert_to_nx(bound.arguments["residual"]) - R2 = bound2.arguments["residual"] - if R1 is not None and R2 is not None: - for k, v in R1.edges.items(): - R2.edges[k]["flow"] = v["flow"] - R2.graph.update(R1.graph) - nx._clear_cache(R2) - elif self.name == "barycenter" and bound.arguments["attr"] is not None: - G1 = backend.convert_to_nx(bound.arguments["G"]) - G2 = bound2.arguments["G"] - attr = bound.arguments["attr"] - for k, v in G1.nodes.items(): - G2.nodes[k][attr] = v[attr] - nx._clear_cache(G2) - elif ( - self.name in {"contracted_nodes", "contracted_edge"} - and not bound.arguments["copy"] - ): - # Edges and nodes changed; node "contraction" and edge "weight" attrs - G1 = backend.convert_to_nx(bound.arguments["G"]) - G2 = bound2.arguments["G"] - G2.__dict__.update(G1.__dict__) - nx._clear_cache(G2) - elif self.name == "stochastic_graph" and not bound.arguments["copy"]: - G1 = backend.convert_to_nx(bound.arguments["G"]) - G2 = bound2.arguments["G"] - for k, v in G1.edges.items(): - G2.edges[k]["weight"] = v["weight"] - nx._clear_cache(G2) - elif ( - self.name == "relabel_nodes" - and not bound.arguments["copy"] - or self.name in {"incremental_closeness_centrality"} - ): - G1 = backend.convert_to_nx(bound.arguments["G"]) - G2 = bound2.arguments["G"] - if G1 is G2: - return G2 - G2._node.clear() - G2._node.update(G1._node) - G2._adj.clear() - G2._adj.update(G1._adj) - if hasattr(G1, "_pred") and hasattr(G2, "_pred"): - G2._pred.clear() - G2._pred.update(G1._pred) - if hasattr(G1, "_succ") and hasattr(G2, "_succ"): - G2._succ.clear() - G2._succ.update(G1._succ) - nx._clear_cache(G2) - if self.name == "relabel_nodes": - return G2 - return backend.convert_to_nx(result) - - converted_result = backend.convert_to_nx(result) - if isinstance(converted_result, nx.Graph) and self.name not in { - "boykov_kolmogorov", - "preflow_push", - "quotient_graph", - "shortest_augmenting_path", - "spectral_graph_forge", - # We don't handle tempfile.NamedTemporaryFile arguments - "read_gml", - "read_graph6", - "read_sparse6", - # We don't handle io.BufferedReader or io.TextIOWrapper arguments - "bipartite_read_edgelist", - "read_adjlist", - "read_edgelist", - "read_graphml", - "read_multiline_adjlist", - "read_pajek", - "from_pydot", - "pydot_read_dot", - "agraph_read_dot", - # graph comparison fails b/c of nan values - "read_gexf", - }: - # For graph return types (e.g. generators), we compare that results are - # the same between the backend and networkx, then return the original - # networkx result so the iteration order will be consistent in tests. - G = self.orig_func(*args2, **kwargs2) - if not nx.utils.graphs_equal(G, converted_result): - assert G.number_of_nodes() == converted_result.number_of_nodes() - assert G.number_of_edges() == converted_result.number_of_edges() - assert G.graph == converted_result.graph - assert G.nodes == converted_result.nodes - assert G.adj == converted_result.adj - assert type(G) is type(converted_result) - raise AssertionError("Graphs are not equal") - return G - return converted_result - - def _make_doc(self): - """Generate the backends section at the end for functions having an alternate - backend implementation(s) using the `backend_info` entry-point.""" - - if not self.backends: - return self._orig_doc - lines = [ - "Backends", - "--------", - ] - for backend in sorted(self.backends): - info = backend_info[backend] - if "short_summary" in info: - lines.append(f"{backend} : {info['short_summary']}") - else: - lines.append(backend) - if "functions" not in info or self.name not in info["functions"]: - lines.append("") - continue - - func_info = info["functions"][self.name] - - # Renaming extra_docstring to additional_docs - if func_docs := ( - func_info.get("additional_docs") or func_info.get("extra_docstring") - ): - lines.extend( - f" {line}" if line else line for line in func_docs.split("\n") - ) - add_gap = True - else: - add_gap = False - - # Renaming extra_parameters to additional_parameters - if extra_parameters := ( - func_info.get("extra_parameters") - or func_info.get("additional_parameters") - ): - if add_gap: - lines.append("") - lines.append(" Additional parameters:") - for param in sorted(extra_parameters): - lines.append(f" {param}") - if desc := extra_parameters[param]: - lines.append(f" {desc}") - lines.append("") - else: - lines.append("") - - if func_url := func_info.get("url"): - lines.append(f"[`Source <{func_url}>`_]") - lines.append("") - - lines.pop() # Remove last empty line - to_add = "\n ".join(lines) - if not self._orig_doc: - return f"The original docstring for {self.name} was empty.\n\n {to_add}" - return f"{self._orig_doc.rstrip()}\n\n {to_add}" - - def __reduce__(self): - """Allow this object to be serialized with pickle. - - This uses the global registry `_registered_algorithms` to deserialize. - """ - return _restore_dispatchable, (self.name,) - - -def _restore_dispatchable(name): - return _registered_algorithms[name].__wrapped__ - - -def _get_cache_key( - *, - edge_attrs, - node_attrs, - preserve_edge_attrs, - preserve_node_attrs, - preserve_graph_attrs, -): - """Return key used by networkx caching given arguments for ``convert_from_nx``.""" - # edge_attrs: dict | None - # node_attrs: dict | None - # preserve_edge_attrs: bool (False if edge_attrs is not None) - # preserve_node_attrs: bool (False if node_attrs is not None) - return ( - frozenset(edge_attrs.items()) - if edge_attrs is not None - else preserve_edge_attrs, - frozenset(node_attrs.items()) - if node_attrs is not None - else preserve_node_attrs, - ) - - -def _get_from_cache(cache, key, *, backend_name=None, mutations=None): - """Search the networkx cache for a graph that is compatible with ``key``. - - Parameters - ---------- - cache : dict - If ``backend_name`` is given, then this is treated as ``G.__networkx_cache__``, - but if ``backend_name`` is None, then this is treated as the resolved inner - cache such as ``G.__networkx_cache__["backends"][backend_name]``. - key : tuple - Cache key from ``_get_cache_key``. - backend_name : str, optional - Name of the backend to control how ``cache`` is interpreted. - mutations : list, optional - Used internally to clear objects gotten from cache if inputs will be mutated. - - Returns - ------- - tuple or None - The key of the compatible graph found in the cache. - graph or None - A compatible graph or None. - """ - if backend_name is not None: - cache = cache.get("backends", {}).get(backend_name, {}) - if not cache: - return None, None - - # Do a simple search for a cached graph with compatible data. - # For example, if we need a single attribute, then it's okay - # to use a cached graph that preserved all attributes. - # This looks for an exact match first. - edge_key, node_key = key - for compat_key in itertools.product( - (edge_key, True) if edge_key is not True else (True,), - (node_key, True) if node_key is not True else (True,), - ): - if (rv := cache.get(compat_key)) is not None: - if mutations is not None: - # Remove this item from the cache (after all conversions) if - # the call to this dispatchable function will mutate an input. - mutations.append((cache, compat_key)) - return compat_key, rv - if edge_key is not True and node_key is not True: - # Iterate over the items in `cache` to see if any are compatible. - # For example, if no edge attributes are needed, then a graph - # with any edge attribute will suffice. We use the same logic - # below (but switched) to clear unnecessary items from the cache. - # Use `list(cache.items())` to be thread-safe. - for (ekey, nkey), graph in list(cache.items()): - if edge_key is False or ekey is True: - pass # Cache works for edge data! - elif edge_key is True or ekey is False or not edge_key.issubset(ekey): - continue # Cache missing required edge data; does not work - if node_key is False or nkey is True: - pass # Cache works for node data! - elif node_key is True or nkey is False or not node_key.issubset(nkey): - continue # Cache missing required node data; does not work - if mutations is not None: - # Remove this item from the cache (after all conversions) if - # the call to this dispatchable function will mutate an input. - mutations.append((cache, (ekey, nkey))) - return (ekey, nkey), graph - return None, None - - -def _set_to_cache(cache, key, graph, *, backend_name=None): - """Set a backend graph to the cache, and remove unnecessary cached items. - - Parameters - ---------- - cache : dict - If ``backend_name`` is given, then this is treated as ``G.__networkx_cache__``, - but if ``backend_name`` is None, then this is treated as the resolved inner - cache such as ``G.__networkx_cache__["backends"][backend_name]``. - key : tuple - Cache key from ``_get_cache_key``. - graph : graph - backend_name : str, optional - Name of the backend to control how ``cache`` is interpreted. - - Returns - ------- - dict - The items that were removed from the cache. - """ - if backend_name is not None: - cache = cache.setdefault("backends", {}).setdefault(backend_name, {}) - # Remove old cached items that are no longer necessary since they - # are dominated/subsumed/outdated by what was just calculated. - # This uses the same logic as above, but with keys switched. - # Also, don't update the cache here if the call will mutate an input. - removed = {} - edge_key, node_key = key - cache[key] = graph # Set at beginning to be thread-safe - for cur_key in list(cache): - if cur_key == key: - continue - ekey, nkey = cur_key - if ekey is False or edge_key is True: - pass - elif ekey is True or edge_key is False or not ekey.issubset(edge_key): - continue - if nkey is False or node_key is True: - pass - elif nkey is True or node_key is False or not nkey.issubset(node_key): - continue - # Use pop instead of del to try to be thread-safe - if (graph := cache.pop(cur_key, None)) is not None: - removed[cur_key] = graph - return removed - - -class _LazyArgsRepr: - """Simple wrapper to display arguments of dispatchable functions in logging calls.""" - - def __init__(self, func, args, kwargs): - self.func = func - self.args = args - self.kwargs = kwargs - self.value = None - - def __repr__(self): - if self.value is None: - bound = self.func.__signature__.bind_partial(*self.args, **self.kwargs) - inner = ", ".join(f"{key}={val!r}" for key, val in bound.arguments.items()) - self.value = f"({inner})" - return self.value - - -if os.environ.get("_NETWORKX_BUILDING_DOCS_"): - # When building docs with Sphinx, use the original function with the - # dispatched __doc__, b/c Sphinx renders normal Python functions better. - # This doesn't show e.g. `*, backend=None, **backend_kwargs` in the - # signatures, which is probably okay. It does allow the docstring to be - # updated based on the installed backends. - _orig_dispatchable = _dispatchable - - def _dispatchable(func=None, **kwargs): # type: ignore[no-redef] - if func is None: - return partial(_dispatchable, **kwargs) - dispatched_func = _orig_dispatchable(func, **kwargs) - func.__doc__ = dispatched_func.__doc__ - return func - - _dispatchable.__doc__ = _orig_dispatchable.__new__.__doc__ # type: ignore[method-assign,assignment] - _sig = inspect.signature(_orig_dispatchable.__new__) - _dispatchable.__signature__ = _sig.replace( # type: ignore[method-assign,assignment] - parameters=[v for k, v in _sig.parameters.items() if k != "cls"] - ) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/configs.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/configs.py deleted file mode 100644 index 24c80f8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/configs.py +++ /dev/null @@ -1,387 +0,0 @@ -import collections -import os -import typing -import warnings -from dataclasses import dataclass - -__all__ = ["Config"] - - -@dataclass(init=False, eq=False, slots=True, kw_only=True, match_args=False) -class Config: - """The base class for NetworkX configuration. - - There are two ways to use this to create configurations. The recommended way - is to subclass ``Config`` with docs and annotations. - - >>> class MyConfig(Config): - ... '''Breakfast!''' - ... - ... eggs: int - ... spam: int - ... - ... def _on_setattr(self, key, value): - ... assert isinstance(value, int) and value >= 0 - ... return value - >>> cfg = MyConfig(eggs=1, spam=5) - - Another way is to simply pass the initial configuration as keyword arguments to - the ``Config`` instance: - - >>> cfg1 = Config(eggs=1, spam=5) - >>> cfg1 - Config(eggs=1, spam=5) - - Once defined, config items may be modified, but can't be added or deleted by default. - ``Config`` is a ``Mapping``, and can get and set configs via attributes or brackets: - - >>> cfg.eggs = 2 - >>> cfg.eggs - 2 - >>> cfg["spam"] = 42 - >>> cfg["spam"] - 42 - - For convenience, it can also set configs within a context with the "with" statement: - - >>> with cfg(spam=3): - ... print("spam (in context):", cfg.spam) - spam (in context): 3 - >>> print("spam (after context):", cfg.spam) - spam (after context): 42 - - Subclasses may also define ``_on_setattr`` (as done in the example above) - to ensure the value being assigned is valid: - - >>> cfg.spam = -1 - Traceback (most recent call last): - ... - AssertionError - - If a more flexible configuration object is needed that allows adding and deleting - configurations, then pass ``strict=False`` when defining the subclass: - - >>> class FlexibleConfig(Config, strict=False): - ... default_greeting: str = "Hello" - >>> flexcfg = FlexibleConfig() - >>> flexcfg.name = "Mr. Anderson" - >>> flexcfg - FlexibleConfig(default_greeting='Hello', name='Mr. Anderson') - """ - - def __init_subclass__(cls, strict=True): - cls._strict = strict - - def __new__(cls, **kwargs): - orig_class = cls - if cls is Config: - # Enable the "simple" case of accepting config definition as keywords - cls = type( - cls.__name__, - (cls,), - {"__annotations__": {key: typing.Any for key in kwargs}}, - ) - cls = dataclass( - eq=False, - repr=cls._strict, - slots=cls._strict, - kw_only=True, - match_args=False, - )(cls) - if not cls._strict: - cls.__repr__ = _flexible_repr - cls._orig_class = orig_class # Save original class so we can pickle - cls._prev = None # Stage previous configs to enable use as context manager - cls._context_stack = [] # Stack of previous configs when used as context - instance = object.__new__(cls) - instance.__init__(**kwargs) - return instance - - def _on_setattr(self, key, value): - """Process config value and check whether it is valid. Useful for subclasses.""" - return value - - def _on_delattr(self, key): - """Callback for when a config item is being deleted. Useful for subclasses.""" - - # Control behavior of attributes - def __dir__(self): - return self.__dataclass_fields__.keys() - - def __setattr__(self, key, value): - if self._strict and key not in self.__dataclass_fields__: - raise AttributeError(f"Invalid config name: {key!r}") - value = self._on_setattr(key, value) - object.__setattr__(self, key, value) - self.__class__._prev = None - - def __delattr__(self, key): - if self._strict: - raise TypeError( - f"Configuration items can't be deleted (can't delete {key!r})." - ) - self._on_delattr(key) - object.__delattr__(self, key) - self.__class__._prev = None - - # Be a `collection.abc.Collection` - def __contains__(self, key): - return ( - key in self.__dataclass_fields__ if self._strict else key in self.__dict__ - ) - - def __iter__(self): - return iter(self.__dataclass_fields__ if self._strict else self.__dict__) - - def __len__(self): - return len(self.__dataclass_fields__ if self._strict else self.__dict__) - - def __reversed__(self): - return reversed(self.__dataclass_fields__ if self._strict else self.__dict__) - - # Add dunder methods for `collections.abc.Mapping` - def __getitem__(self, key): - try: - return getattr(self, key) - except AttributeError as err: - raise KeyError(*err.args) from None - - def __setitem__(self, key, value): - try: - self.__setattr__(key, value) - except AttributeError as err: - raise KeyError(*err.args) from None - - def __delitem__(self, key): - try: - self.__delattr__(key) - except AttributeError as err: - raise KeyError(*err.args) from None - - _ipython_key_completions_ = __dir__ # config[" - - # Go ahead and make it a `collections.abc.Mapping` - def get(self, key, default=None): - return getattr(self, key, default) - - def items(self): - return collections.abc.ItemsView(self) - - def keys(self): - return collections.abc.KeysView(self) - - def values(self): - return collections.abc.ValuesView(self) - - # dataclass can define __eq__ for us, but do it here so it works after pickling - def __eq__(self, other): - if not isinstance(other, Config): - return NotImplemented - return self._orig_class == other._orig_class and self.items() == other.items() - - # Make pickle work - def __reduce__(self): - return self._deserialize, (self._orig_class, dict(self)) - - @staticmethod - def _deserialize(cls, kwargs): - return cls(**kwargs) - - # Allow to be used as context manager - def __call__(self, **kwargs): - kwargs = {key: self._on_setattr(key, val) for key, val in kwargs.items()} - prev = dict(self) - for key, val in kwargs.items(): - setattr(self, key, val) - self.__class__._prev = prev - return self - - def __enter__(self): - if self.__class__._prev is None: - raise RuntimeError( - "Config being used as a context manager without config items being set. " - "Set config items via keyword arguments when calling the config object. " - "For example, using config as a context manager should be like:\n\n" - ' >>> with cfg(breakfast="spam"):\n' - " ... ... # Do stuff\n" - ) - self.__class__._context_stack.append(self.__class__._prev) - self.__class__._prev = None - return self - - def __exit__(self, exc_type, exc_value, traceback): - prev = self.__class__._context_stack.pop() - for key, val in prev.items(): - setattr(self, key, val) - - -def _flexible_repr(self): - return ( - f"{self.__class__.__qualname__}(" - + ", ".join(f"{key}={val!r}" for key, val in self.__dict__.items()) - + ")" - ) - - -# Register, b/c `Mapping.__subclasshook__` returns `NotImplemented` -collections.abc.Mapping.register(Config) - - -class BackendPriorities(Config, strict=False): - """Configuration to control automatic conversion to and calling of backends. - - Priority is given to backends listed earlier. - - Parameters - ---------- - algos : list of backend names - This controls "algorithms" such as ``nx.pagerank`` that don't return a graph. - generators : list of backend names - This controls "generators" such as ``nx.from_pandas_edgelist`` that return a graph. - kwargs : variadic keyword arguments of function name to list of backend names - This allows each function to be configured separately and will override the config - in ``algos`` or ``generators`` if present. The dispatchable function name may be - gotten from the ``.name`` attribute such as ``nx.pagerank.name`` (it's typically - the same as the name of the function). - """ - - algos: list[str] - generators: list[str] - - def _on_setattr(self, key, value): - from .backends import _registered_algorithms, backend_info - - if key in {"algos", "generators"}: - pass - elif key not in _registered_algorithms: - raise AttributeError( - f"Invalid config name: {key!r}. Expected 'algos', 'generators', or a name " - "of a dispatchable function (e.g. `.name` attribute of the function)." - ) - if not (isinstance(value, list) and all(isinstance(x, str) for x in value)): - raise TypeError( - f"{key!r} config must be a list of backend names; got {value!r}" - ) - if missing := {x for x in value if x not in backend_info}: - missing = ", ".join(map(repr, sorted(missing))) - raise ValueError(f"Unknown backend when setting {key!r}: {missing}") - return value - - def _on_delattr(self, key): - if key in {"algos", "generators"}: - raise TypeError(f"{key!r} configuration item can't be deleted.") - - -class NetworkXConfig(Config): - """Configuration for NetworkX that controls behaviors such as how to use backends. - - Attribute and bracket notation are supported for getting and setting configurations:: - - >>> nx.config.backend_priority == nx.config["backend_priority"] - True - - Parameters - ---------- - backend_priority : list of backend names or dict or BackendPriorities - Enable automatic conversion of graphs to backend graphs for functions - implemented by the backend. Priority is given to backends listed earlier. - This is a nested configuration with keys ``algos``, ``generators``, and, - optionally, function names. Setting this value to a list of backend names - will set ``nx.config.backend_priority.algos``. For more information, see - ``help(nx.config.backend_priority)``. Default is empty list. - - backends : Config mapping of backend names to backend Config - The keys of the Config mapping are names of all installed NetworkX backends, - and the values are their configurations as Config mappings. - - cache_converted_graphs : bool - If True, then save converted graphs to the cache of the input graph. Graph - conversion may occur when automatically using a backend from `backend_priority` - or when using the `backend=` keyword argument to a function call. Caching can - improve performance by avoiding repeated conversions, but it uses more memory. - Care should be taken to not manually mutate a graph that has cached graphs; for - example, ``G[u][v][k] = val`` changes the graph, but does not clear the cache. - Using methods such as ``G.add_edge(u, v, weight=val)`` will clear the cache to - keep it consistent. ``G.__networkx_cache__.clear()`` manually clears the cache. - Default is True. - - fallback_to_nx : bool - If True, then "fall back" and run with the default "networkx" implementation - for dispatchable functions not implemented by backends of input graphs. When a - backend graph is passed to a dispatchable function, the default behavior is to - use the implementation from that backend if possible and raise if not. Enabling - ``fallback_to_nx`` makes the networkx implementation the fallback to use instead - of raising, and will convert the backend graph to a networkx-compatible graph. - Default is False. - - warnings_to_ignore : set of strings - Control which warnings from NetworkX are not emitted. Valid elements: - - - `"cache"`: when a cached value is used from ``G.__networkx_cache__``. - - Notes - ----- - Environment variables may be used to control some default configurations: - - - ``NETWORKX_BACKEND_PRIORITY``: set ``backend_priority.algos`` from comma-separated names. - - ``NETWORKX_CACHE_CONVERTED_GRAPHS``: set ``cache_converted_graphs`` to True if nonempty. - - ``NETWORKX_FALLBACK_TO_NX``: set ``fallback_to_nx`` to True if nonempty. - - ``NETWORKX_WARNINGS_TO_IGNORE``: set `warnings_to_ignore` from comma-separated names. - - and can be used for finer control of ``backend_priority`` such as: - - - ``NETWORKX_BACKEND_PRIORITY_ALGOS``: same as ``NETWORKX_BACKEND_PRIORITY`` to set ``backend_priority.algos``. - - This is a global configuration. Use with caution when using from multiple threads. - """ - - backend_priority: BackendPriorities - backends: Config - cache_converted_graphs: bool - fallback_to_nx: bool - warnings_to_ignore: set[str] - - def _on_setattr(self, key, value): - from .backends import backend_info - - if key == "backend_priority": - if isinstance(value, list): - getattr(self, key).algos = value - value = getattr(self, key) - elif isinstance(value, dict): - kwargs = value - value = BackendPriorities(algos=[], generators=[]) - for key, val in kwargs.items(): - setattr(value, key, val) - elif not isinstance(value, BackendPriorities): - raise TypeError( - f"{key!r} config must be a dict of lists of backend names; got {value!r}" - ) - elif key == "backends": - if not ( - isinstance(value, Config) - and all(isinstance(key, str) for key in value) - and all(isinstance(val, Config) for val in value.values()) - ): - raise TypeError( - f"{key!r} config must be a Config of backend configs; got {value!r}" - ) - if missing := {x for x in value if x not in backend_info}: - missing = ", ".join(map(repr, sorted(missing))) - raise ValueError(f"Unknown backend when setting {key!r}: {missing}") - elif key in {"cache_converted_graphs", "fallback_to_nx"}: - if not isinstance(value, bool): - raise TypeError(f"{key!r} config must be True or False; got {value!r}") - elif key == "warnings_to_ignore": - if not (isinstance(value, set) and all(isinstance(x, str) for x in value)): - raise TypeError( - f"{key!r} config must be a set of warning names; got {value!r}" - ) - known_warnings = {"cache"} - if missing := {x for x in value if x not in known_warnings}: - missing = ", ".join(map(repr, sorted(missing))) - raise ValueError( - f"Unknown warning when setting {key!r}: {missing}. Valid entries: " - + ", ".join(sorted(known_warnings)) - ) - return value diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/decorators.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/decorators.py deleted file mode 100644 index 36ae9be..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/decorators.py +++ /dev/null @@ -1,1237 +0,0 @@ -import bz2 -import collections -import gzip -import inspect -import itertools -import re -import warnings -from collections import defaultdict -from contextlib import contextmanager -from functools import wraps -from inspect import Parameter, signature -from os.path import splitext -from pathlib import Path - -import networkx as nx -from networkx.utils import create_py_random_state, create_random_state - -__all__ = [ - "not_implemented_for", - "open_file", - "nodes_or_number", - "np_random_state", - "py_random_state", - "argmap", -] - - -def not_implemented_for(*graph_types): - """Decorator to mark algorithms as not implemented - - Parameters - ---------- - graph_types : container of strings - Entries must be one of "directed", "undirected", "multigraph", or "graph". - - Returns - ------- - _require : function - The decorated function. - - Raises - ------ - NetworkXNotImplemented - If any of the packages cannot be imported - - Notes - ----- - Multiple types are joined logically with "and". - For "or" use multiple @not_implemented_for() lines. - - Examples - -------- - Decorate functions like this:: - - @not_implemented_for("directed") - def sp_function(G): - pass - - - # rule out MultiDiGraph - @not_implemented_for("directed", "multigraph") - def sp_np_function(G): - pass - - - # rule out all except DiGraph - @not_implemented_for("undirected") - @not_implemented_for("multigraph") - def sp_np_function(G): - pass - """ - if ("directed" in graph_types) and ("undirected" in graph_types): - raise ValueError("Function not implemented on directed AND undirected graphs?") - if ("multigraph" in graph_types) and ("graph" in graph_types): - raise ValueError("Function not implemented on graph AND multigraphs?") - if not set(graph_types) < {"directed", "undirected", "multigraph", "graph"}: - raise KeyError( - "use one or more of directed, undirected, multigraph, graph. " - f"You used {graph_types}" - ) - - # 3-way logic: True if "directed" input, False if "undirected" input, else None - dval = ("directed" in graph_types) or "undirected" not in graph_types and None - mval = ("multigraph" in graph_types) or "graph" not in graph_types and None - errmsg = f"not implemented for {' '.join(graph_types)} type" - - def _not_implemented_for(g): - if (mval is None or mval == g.is_multigraph()) and ( - dval is None or dval == g.is_directed() - ): - raise nx.NetworkXNotImplemented(errmsg) - - return g - - return argmap(_not_implemented_for, 0) - - -# To handle new extensions, define a function accepting a `path` and `mode`. -# Then add the extension to _dispatch_dict. -fopeners = { - ".gz": gzip.open, - ".gzip": gzip.open, - ".bz2": bz2.BZ2File, -} -_dispatch_dict = defaultdict(lambda: open, **fopeners) - - -def open_file(path_arg, mode="r"): - """Decorator to ensure clean opening and closing of files. - - Parameters - ---------- - path_arg : string or int - Name or index of the argument that is a path. - - mode : str - String for opening mode. - - Returns - ------- - _open_file : function - Function which cleanly executes the io. - - Examples - -------- - Decorate functions like this:: - - @open_file(0, "r") - def read_function(pathname): - pass - - - @open_file(1, "w") - def write_function(G, pathname): - pass - - - @open_file(1, "w") - def write_function(G, pathname="graph.dot"): - pass - - - @open_file("pathname", "w") - def write_function(G, pathname="graph.dot"): - pass - - - @open_file("path", "w+") - def another_function(arg, **kwargs): - path = kwargs["path"] - pass - - Notes - ----- - Note that this decorator solves the problem when a path argument is - specified as a string, but it does not handle the situation when the - function wants to accept a default of None (and then handle it). - - Here is an example of how to handle this case:: - - @open_file("path") - def some_function(arg1, arg2, path=None): - if path is None: - fobj = tempfile.NamedTemporaryFile(delete=False) - else: - # `path` could have been a string or file object or something - # similar. In any event, the decorator has given us a file object - # and it will close it for us, if it should. - fobj = path - - try: - fobj.write("blah") - finally: - if path is None: - fobj.close() - - Normally, we'd want to use "with" to ensure that fobj gets closed. - However, the decorator will make `path` a file object for us, - and using "with" would undesirably close that file object. - Instead, we use a try block, as shown above. - When we exit the function, fobj will be closed, if it should be, by the decorator. - """ - - def _open_file(path): - # Now we have the path_arg. There are two types of input to consider: - # 1) string representing a path that should be opened - # 2) an already opened file object - if isinstance(path, str): - ext = splitext(path)[1] - elif isinstance(path, Path): - # path is a pathlib reference to a filename - ext = path.suffix - path = str(path) - else: - # could be None, or a file handle, in which case the algorithm will deal with it - return path, lambda: None - - fobj = _dispatch_dict[ext](path, mode=mode) - return fobj, lambda: fobj.close() - - return argmap(_open_file, path_arg, try_finally=True) - - -def nodes_or_number(which_args): - """Decorator to allow number of nodes or container of nodes. - - With this decorator, the specified argument can be either a number or a container - of nodes. If it is a number, the nodes used are `range(n)`. - This allows `nx.complete_graph(50)` in place of `nx.complete_graph(list(range(50)))`. - And it also allows `nx.complete_graph(any_list_of_nodes)`. - - Parameters - ---------- - which_args : string or int or sequence of strings or ints - If string, the name of the argument to be treated. - If int, the index of the argument to be treated. - If more than one node argument is allowed, can be a list of locations. - - Returns - ------- - _nodes_or_numbers : function - Function which replaces int args with ranges. - - Examples - -------- - Decorate functions like this:: - - @nodes_or_number("nodes") - def empty_graph(nodes): - # nodes is converted to a list of nodes - - @nodes_or_number(0) - def empty_graph(nodes): - # nodes is converted to a list of nodes - - @nodes_or_number(["m1", "m2"]) - def grid_2d_graph(m1, m2, periodic=False): - # m1 and m2 are each converted to a list of nodes - - @nodes_or_number([0, 1]) - def grid_2d_graph(m1, m2, periodic=False): - # m1 and m2 are each converted to a list of nodes - - @nodes_or_number(1) - def full_rary_tree(r, n) - # presumably r is a number. It is not handled by this decorator. - # n is converted to a list of nodes - """ - - def _nodes_or_number(n): - try: - nodes = list(range(n)) - except TypeError: - nodes = tuple(n) - else: - if n < 0: - raise nx.NetworkXError(f"Negative number of nodes not valid: {n}") - return (n, nodes) - - try: - iter_wa = iter(which_args) - except TypeError: - iter_wa = (which_args,) - - return argmap(_nodes_or_number, *iter_wa) - - -def np_random_state(random_state_argument): - """Decorator to generate a numpy RandomState or Generator instance. - - The decorator processes the argument indicated by `random_state_argument` - using :func:`nx.utils.create_random_state`. - The argument value can be a seed (integer), or a `numpy.random.RandomState` - or `numpy.random.RandomState` instance or (`None` or `numpy.random`). - The latter two options use the global random number generator for `numpy.random`. - - The returned instance is a `numpy.random.RandomState` or `numpy.random.Generator`. - - Parameters - ---------- - random_state_argument : string or int - The name or index of the argument to be converted - to a `numpy.random.RandomState` instance. - - Returns - ------- - _random_state : function - Function whose random_state keyword argument is a RandomState instance. - - Examples - -------- - Decorate functions like this:: - - @np_random_state("seed") - def random_float(seed=None): - return seed.rand() - - - @np_random_state(0) - def random_float(rng=None): - return rng.rand() - - - @np_random_state(1) - def random_array(dims, random_state=1): - return random_state.rand(*dims) - - See Also - -------- - py_random_state - """ - return argmap(create_random_state, random_state_argument) - - -def py_random_state(random_state_argument): - """Decorator to generate a random.Random instance (or equiv). - - This decorator processes `random_state_argument` using - :func:`nx.utils.create_py_random_state`. - The input value can be a seed (integer), or a random number generator:: - - If int, return a random.Random instance set with seed=int. - If random.Random instance, return it. - If None or the `random` package, return the global random number - generator used by `random`. - If np.random package, or the default numpy RandomState instance, - return the default numpy random number generator wrapped in a - `PythonRandomViaNumpyBits` class. - If np.random.Generator instance, return it wrapped in a - `PythonRandomViaNumpyBits` class. - - # Legacy options - If np.random.RandomState instance, return it wrapped in a - `PythonRandomInterface` class. - If a `PythonRandomInterface` instance, return it - - Parameters - ---------- - random_state_argument : string or int - The name of the argument or the index of the argument in args that is - to be converted to the random.Random instance or numpy.random.RandomState - instance that mimics basic methods of random.Random. - - Returns - ------- - _random_state : function - Function whose random_state_argument is converted to a Random instance. - - Examples - -------- - Decorate functions like this:: - - @py_random_state("random_state") - def random_float(random_state=None): - return random_state.rand() - - - @py_random_state(0) - def random_float(rng=None): - return rng.rand() - - - @py_random_state(1) - def random_array(dims, seed=12345): - return seed.rand(*dims) - - See Also - -------- - np_random_state - """ - - return argmap(create_py_random_state, random_state_argument) - - -class argmap: - """A decorator to apply a map to arguments before calling the function - - This class provides a decorator that maps (transforms) arguments of the function - before the function is called. Thus for example, we have similar code - in many functions to determine whether an argument is the number of nodes - to be created, or a list of nodes to be handled. The decorator provides - the code to accept either -- transforming the indicated argument into a - list of nodes before the actual function is called. - - This decorator class allows us to process single or multiple arguments. - The arguments to be processed can be specified by string, naming the argument, - or by index, specifying the item in the args list. - - Parameters - ---------- - func : callable - The function to apply to arguments - - *args : iterable of (int, str or tuple) - A list of parameters, specified either as strings (their names), ints - (numerical indices) or tuples, which may contain ints, strings, and - (recursively) tuples. Each indicates which parameters the decorator - should map. Tuples indicate that the map function takes (and returns) - multiple parameters in the same order and nested structure as indicated - here. - - try_finally : bool (default: False) - When True, wrap the function call in a try-finally block with code - for the finally block created by `func`. This is used when the map - function constructs an object (like a file handle) that requires - post-processing (like closing). - - Note: try_finally decorators cannot be used to decorate generator - functions. - - Examples - -------- - Most of these examples use `@argmap(...)` to apply the decorator to - the function defined on the next line. - In the NetworkX codebase however, `argmap` is used within a function to - construct a decorator. That is, the decorator defines a mapping function - and then uses `argmap` to build and return a decorated function. - A simple example is a decorator that specifies which currency to report money. - The decorator (named `convert_to`) would be used like:: - - @convert_to("US_Dollars", "income") - def show_me_the_money(name, income): - print(f"{name} : {income}") - - And the code to create the decorator might be:: - - def convert_to(currency, which_arg): - def _convert(amount): - if amount.currency != currency: - amount = amount.to_currency(currency) - return amount - - return argmap(_convert, which_arg) - - Despite this common idiom for argmap, most of the following examples - use the `@argmap(...)` idiom to save space. - - Here's an example use of argmap to sum the elements of two of the functions - arguments. The decorated function:: - - @argmap(sum, "xlist", "zlist") - def foo(xlist, y, zlist): - return xlist - y + zlist - - is syntactic sugar for:: - - def foo(xlist, y, zlist): - x = sum(xlist) - z = sum(zlist) - return x - y + z - - and is equivalent to (using argument indexes):: - - @argmap(sum, "xlist", 2) - def foo(xlist, y, zlist): - return xlist - y + zlist - - or:: - - @argmap(sum, "zlist", 0) - def foo(xlist, y, zlist): - return xlist - y + zlist - - Transforming functions can be applied to multiple arguments, such as:: - - def swap(x, y): - return y, x - - # the 2-tuple tells argmap that the map `swap` has 2 inputs/outputs. - @argmap(swap, ("a", "b")): - def foo(a, b, c): - return a / b * c - - is equivalent to:: - - def foo(a, b, c): - a, b = swap(a, b) - return a / b * c - - More generally, the applied arguments can be nested tuples of strings or ints. - The syntax `@argmap(some_func, ("a", ("b", "c")))` would expect `some_func` to - accept 2 inputs with the second expected to be a 2-tuple. It should then return - 2 outputs with the second a 2-tuple. The returns values would replace input "a" - "b" and "c" respectively. Similarly for `@argmap(some_func, (0, ("b", 2)))`. - - Also, note that an index larger than the number of named parameters is allowed - for variadic functions. For example:: - - def double(a): - return 2 * a - - - @argmap(double, 3) - def overflow(a, *args): - return a, args - - - print(overflow(1, 2, 3, 4, 5, 6)) # output is 1, (2, 3, 8, 5, 6) - - **Try Finally** - - Additionally, this `argmap` class can be used to create a decorator that - initiates a try...finally block. The decorator must be written to return - both the transformed argument and a closing function. - This feature was included to enable the `open_file` decorator which might - need to close the file or not depending on whether it had to open that file. - This feature uses the keyword-only `try_finally` argument to `@argmap`. - - For example this map opens a file and then makes sure it is closed:: - - def open_file(fn): - f = open(fn) - return f, lambda: f.close() - - The decorator applies that to the function `foo`:: - - @argmap(open_file, "file", try_finally=True) - def foo(file): - print(file.read()) - - is syntactic sugar for:: - - def foo(file): - file, close_file = open_file(file) - try: - print(file.read()) - finally: - close_file() - - and is equivalent to (using indexes):: - - @argmap(open_file, 0, try_finally=True) - def foo(file): - print(file.read()) - - Here's an example of the try_finally feature used to create a decorator:: - - def my_closing_decorator(which_arg): - def _opener(path): - if path is None: - path = open(path) - fclose = path.close - else: - # assume `path` handles the closing - fclose = lambda: None - return path, fclose - - return argmap(_opener, which_arg, try_finally=True) - - which can then be used as:: - - @my_closing_decorator("file") - def fancy_reader(file=None): - # this code doesn't need to worry about closing the file - print(file.read()) - - Decorators with try_finally = True cannot be used with generator functions, - because the `finally` block is evaluated before the generator is exhausted:: - - @argmap(open_file, "file", try_finally=True) - def file_to_lines(file): - for line in file.readlines(): - yield line - - is equivalent to:: - - def file_to_lines_wrapped(file): - for line in file.readlines(): - yield line - - - def file_to_lines_wrapper(file): - try: - file = open_file(file) - return file_to_lines_wrapped(file) - finally: - file.close() - - which behaves similarly to:: - - def file_to_lines_whoops(file): - file = open_file(file) - file.close() - for line in file.readlines(): - yield line - - because the `finally` block of `file_to_lines_wrapper` is executed before - the caller has a chance to exhaust the iterator. - - Notes - ----- - An object of this class is callable and intended to be used when - defining a decorator. Generally, a decorator takes a function as input - and constructs a function as output. Specifically, an `argmap` object - returns the input function decorated/wrapped so that specified arguments - are mapped (transformed) to new values before the decorated function is called. - - As an overview, the argmap object returns a new function with all the - dunder values of the original function (like `__doc__`, `__name__`, etc). - Code for this decorated function is built based on the original function's - signature. It starts by mapping the input arguments to potentially new - values. Then it calls the decorated function with these new values in place - of the indicated arguments that have been mapped. The return value of the - original function is then returned. This new function is the function that - is actually called by the user. - - Three additional features are provided. - 1) The code is lazily compiled. That is, the new function is returned - as an object without the code compiled, but with all information - needed so it can be compiled upon it's first invocation. This saves - time on import at the cost of additional time on the first call of - the function. Subsequent calls are then just as fast as normal. - - 2) If the "try_finally" keyword-only argument is True, a try block - follows each mapped argument, matched on the other side of the wrapped - call, by a finally block closing that mapping. We expect func to return - a 2-tuple: the mapped value and a function to be called in the finally - clause. This feature was included so the `open_file` decorator could - provide a file handle to the decorated function and close the file handle - after the function call. It even keeps track of whether to close the file - handle or not based on whether it had to open the file or the input was - already open. So, the decorated function does not need to include any - code to open or close files. - - 3) The maps applied can process multiple arguments. For example, - you could swap two arguments using a mapping, or transform - them to their sum and their difference. This was included to allow - a decorator in the `quality.py` module that checks that an input - `partition` is a valid partition of the nodes of the input graph `G`. - In this example, the map has inputs `(G, partition)`. After checking - for a valid partition, the map either raises an exception or leaves - the inputs unchanged. Thus many functions that make this check can - use the decorator rather than copy the checking code into each function. - More complicated nested argument structures are described below. - - The remaining notes describe the code structure and methods for this - class in broad terms to aid in understanding how to use it. - - Instantiating an `argmap` object simply stores the mapping function and - the input identifiers of which arguments to map. The resulting decorator - is ready to use this map to decorate any function. Calling that object - (`argmap.__call__`, but usually done via `@my_decorator`) a lazily - compiled thin wrapper of the decorated function is constructed, - wrapped with the necessary function dunder attributes like `__doc__` - and `__name__`. That thinly wrapped function is returned as the - decorated function. When that decorated function is called, the thin - wrapper of code calls `argmap._lazy_compile` which compiles the decorated - function (using `argmap.compile`) and replaces the code of the thin - wrapper with the newly compiled code. This saves the compilation step - every import of networkx, at the cost of compiling upon the first call - to the decorated function. - - When the decorated function is compiled, the code is recursively assembled - using the `argmap.assemble` method. The recursive nature is needed in - case of nested decorators. The result of the assembly is a number of - useful objects. - - sig : the function signature of the original decorated function as - constructed by :func:`argmap.signature`. This is constructed - using `inspect.signature` but enhanced with attribute - strings `sig_def` and `sig_call`, and other information - specific to mapping arguments of this function. - This information is used to construct a string of code defining - the new decorated function. - - wrapped_name : a unique internally used name constructed by argmap - for the decorated function. - - functions : a dict of the functions used inside the code of this - decorated function, to be used as `globals` in `exec`. - This dict is recursively updated to allow for nested decorating. - - mapblock : code (as a list of strings) to map the incoming argument - values to their mapped values. - - finallys : code (as a list of strings) to provide the possibly nested - set of finally clauses if needed. - - mutable_args : a bool indicating whether the `sig.args` tuple should be - converted to a list so mutation can occur. - - After this recursive assembly process, the `argmap.compile` method - constructs code (as strings) to convert the tuple `sig.args` to a list - if needed. It joins the defining code with appropriate indents and - compiles the result. Finally, this code is evaluated and the original - wrapper's implementation is replaced with the compiled version (see - `argmap._lazy_compile` for more details). - - Other `argmap` methods include `_name` and `_count` which allow internally - generated names to be unique within a python session. - The methods `_flatten` and `_indent` process the nested lists of strings - into properly indented python code ready to be compiled. - - More complicated nested tuples of arguments also allowed though - usually not used. For the simple 2 argument case, the argmap - input ("a", "b") implies the mapping function will take 2 arguments - and return a 2-tuple of mapped values. A more complicated example - with argmap input `("a", ("b", "c"))` requires the mapping function - take 2 inputs, with the second being a 2-tuple. It then must output - the 3 mapped values in the same nested structure `(newa, (newb, newc))`. - This level of generality is not often needed, but was convenient - to implement when handling the multiple arguments. - - See Also - -------- - not_implemented_for - open_file - nodes_or_number - py_random_state - networkx.algorithms.community.quality.require_partition - - """ - - def __init__(self, func, *args, try_finally=False): - self._func = func - self._args = args - self._finally = try_finally - - @staticmethod - def _lazy_compile(func): - """Compile the source of a wrapped function - - Assemble and compile the decorated function, and intrusively replace its - code with the compiled version's. The thinly wrapped function becomes - the decorated function. - - Parameters - ---------- - func : callable - A function returned by argmap.__call__ which is in the process - of being called for the first time. - - Returns - ------- - func : callable - The same function, with a new __code__ object. - - Notes - ----- - It was observed in NetworkX issue #4732 [1] that the import time of - NetworkX was significantly bloated by the use of decorators: over half - of the import time was being spent decorating functions. This was - somewhat improved by a change made to the `decorator` library, at the - cost of a relatively heavy-weight call to `inspect.Signature.bind` - for each call to the decorated function. - - The workaround we arrived at is to do minimal work at the time of - decoration. When the decorated function is called for the first time, - we compile a function with the same function signature as the wrapped - function. The resulting decorated function is faster than one made by - the `decorator` library, so that the overhead of the first call is - 'paid off' after a small number of calls. - - References - ---------- - - [1] https://github.com/networkx/networkx/issues/4732 - - """ - real_func = func.__argmap__.compile(func.__wrapped__) - func.__code__ = real_func.__code__ - func.__globals__.update(real_func.__globals__) - func.__dict__.update(real_func.__dict__) - return func - - def __call__(self, f): - """Construct a lazily decorated wrapper of f. - - The decorated function will be compiled when it is called for the first time, - and it will replace its own __code__ object so subsequent calls are fast. - - Parameters - ---------- - f : callable - A function to be decorated. - - Returns - ------- - func : callable - The decorated function. - - See Also - -------- - argmap._lazy_compile - """ - - def func(*args, __wrapper=None, **kwargs): - return argmap._lazy_compile(__wrapper)(*args, **kwargs) - - # standard function-wrapping stuff - func.__name__ = f.__name__ - func.__doc__ = f.__doc__ - func.__defaults__ = f.__defaults__ - func.__kwdefaults__.update(f.__kwdefaults__ or {}) - func.__module__ = f.__module__ - func.__qualname__ = f.__qualname__ - func.__dict__.update(f.__dict__) - func.__wrapped__ = f - - # now that we've wrapped f, we may have picked up some __dict__ or - # __kwdefaults__ items that were set by a previous argmap. Thus, we set - # these values after those update() calls. - - # If we attempt to access func from within itself, that happens through - # a closure -- which trips an error when we replace func.__code__. The - # standard workaround for functions which can't see themselves is to use - # a Y-combinator, as we do here. - func.__kwdefaults__["_argmap__wrapper"] = func - - # this self-reference is here because functools.wraps preserves - # everything in __dict__, and we don't want to mistake a non-argmap - # wrapper for an argmap wrapper - func.__self__ = func - - # this is used to variously call self.assemble and self.compile - func.__argmap__ = self - - if hasattr(f, "__argmap__"): - func.__is_generator = f.__is_generator - else: - func.__is_generator = inspect.isgeneratorfunction(f) - - if self._finally and func.__is_generator: - raise nx.NetworkXError("argmap cannot decorate generators with try_finally") - - return func - - __count = 0 - - @classmethod - def _count(cls): - """Maintain a globally-unique identifier for function names and "file" names - - Note that this counter is a class method reporting a class variable - so the count is unique within a Python session. It could differ from - session to session for a specific decorator depending on the order - that the decorators are created. But that doesn't disrupt `argmap`. - - This is used in two places: to construct unique variable names - in the `_name` method and to construct unique fictitious filenames - in the `_compile` method. - - Returns - ------- - count : int - An integer unique to this Python session (simply counts from zero) - """ - cls.__count += 1 - return cls.__count - - _bad_chars = re.compile("[^a-zA-Z0-9_]") - - @classmethod - def _name(cls, f): - """Mangle the name of a function to be unique but somewhat human-readable - - The names are unique within a Python session and set using `_count`. - - Parameters - ---------- - f : str or object - - Returns - ------- - name : str - The mangled version of `f.__name__` (if `f.__name__` exists) or `f` - - """ - f = f.__name__ if hasattr(f, "__name__") else f - fname = re.sub(cls._bad_chars, "_", f) - return f"argmap_{fname}_{cls._count()}" - - def compile(self, f): - """Compile the decorated function. - - Called once for a given decorated function -- collects the code from all - argmap decorators in the stack, and compiles the decorated function. - - Much of the work done here uses the `assemble` method to allow recursive - treatment of multiple argmap decorators on a single decorated function. - That flattens the argmap decorators, collects the source code to construct - a single decorated function, then compiles/executes/returns that function. - - The source code for the decorated function is stored as an attribute - `_code` on the function object itself. - - Note that Python's `compile` function requires a filename, but this - code is constructed without a file, so a fictitious filename is used - to describe where the function comes from. The name is something like: - "argmap compilation 4". - - Parameters - ---------- - f : callable - The function to be decorated - - Returns - ------- - func : callable - The decorated file - - """ - sig, wrapped_name, functions, mapblock, finallys, mutable_args = self.assemble( - f - ) - - call = f"{sig.call_sig.format(wrapped_name)}#" - mut_args = f"{sig.args} = list({sig.args})" if mutable_args else "" - body = argmap._indent(sig.def_sig, mut_args, mapblock, call, finallys) - code = "\n".join(body) - - locl = {} - globl = dict(functions.values()) - filename = f"{self.__class__} compilation {self._count()}" - compiled = compile(code, filename, "exec") - exec(compiled, globl, locl) - func = locl[sig.name] - func._code = code - return func - - def assemble(self, f): - """Collects components of the source for the decorated function wrapping f. - - If `f` has multiple argmap decorators, we recursively assemble the stack of - decorators into a single flattened function. - - This method is part of the `compile` method's process yet separated - from that method to allow recursive processing. The outputs are - strings, dictionaries and lists that collect needed info to - flatten any nested argmap-decoration. - - Parameters - ---------- - f : callable - The function to be decorated. If f is argmapped, we assemble it. - - Returns - ------- - sig : argmap.Signature - The function signature as an `argmap.Signature` object. - wrapped_name : str - The mangled name used to represent the wrapped function in the code - being assembled. - functions : dict - A dictionary mapping id(g) -> (mangled_name(g), g) for functions g - referred to in the code being assembled. These need to be present - in the ``globals`` scope of ``exec`` when defining the decorated - function. - mapblock : list of lists and/or strings - Code that implements mapping of parameters including any try blocks - if needed. This code will precede the decorated function call. - finallys : list of lists and/or strings - Code that implements the finally blocks to post-process the - arguments (usually close any files if needed) after the - decorated function is called. - mutable_args : bool - True if the decorator needs to modify positional arguments - via their indices. The compile method then turns the argument - tuple into a list so that the arguments can be modified. - """ - - # first, we check if f is already argmapped -- if that's the case, - # build up the function recursively. - # > mapblock is generally a list of function calls of the sort - # arg = func(arg) - # in addition to some try-blocks if needed. - # > finallys is a recursive list of finally blocks of the sort - # finally: - # close_func_1() - # finally: - # close_func_2() - # > functions is a dict of functions used in the scope of our decorated - # function. It will be used to construct globals used in compilation. - # We make functions[id(f)] = name_of_f, f to ensure that a given - # function is stored and named exactly once even if called by - # nested decorators. - if hasattr(f, "__argmap__") and f.__self__ is f: - ( - sig, - wrapped_name, - functions, - mapblock, - finallys, - mutable_args, - ) = f.__argmap__.assemble(f.__wrapped__) - functions = dict(functions) # shallow-copy just in case - else: - sig = self.signature(f) - wrapped_name = self._name(f) - mapblock, finallys = [], [] - functions = {id(f): (wrapped_name, f)} - mutable_args = False - - if id(self._func) in functions: - fname, _ = functions[id(self._func)] - else: - fname, _ = functions[id(self._func)] = self._name(self._func), self._func - - # this is a bit complicated -- we can call functions with a variety of - # nested arguments, so long as their input and output are tuples with - # the same nested structure. e.g. ("a", "b") maps arguments a and b. - # A more complicated nesting like (0, (3, 4)) maps arguments 0, 3, 4 - # expecting the mapping to output new values in the same nested shape. - # The ability to argmap multiple arguments was necessary for - # the decorator `nx.algorithms.community.quality.require_partition`, and - # while we're not taking full advantage of the ability to handle - # multiply-nested tuples, it was convenient to implement this in - # generality because the recursive call to `get_name` is necessary in - # any case. - applied = set() - - def get_name(arg, first=True): - nonlocal mutable_args - if isinstance(arg, tuple): - name = ", ".join(get_name(x, False) for x in arg) - return name if first else f"({name})" - if arg in applied: - raise nx.NetworkXError(f"argument {arg} is specified multiple times") - applied.add(arg) - if arg in sig.names: - return sig.names[arg] - elif isinstance(arg, str): - if sig.kwargs is None: - raise nx.NetworkXError( - f"name {arg} is not a named parameter and this function doesn't have kwargs" - ) - return f"{sig.kwargs}[{arg!r}]" - else: - if sig.args is None: - raise nx.NetworkXError( - f"index {arg} not a parameter index and this function doesn't have args" - ) - mutable_args = True - return f"{sig.args}[{arg - sig.n_positional}]" - - if self._finally: - # here's where we handle try_finally decorators. Such a decorator - # returns a mapped argument and a function to be called in a - # finally block. This feature was required by the open_file - # decorator. The below generates the code - # - # name, final = func(name) #<--append to mapblock - # try: #<--append to mapblock - # ... more argmapping and try blocks - # return WRAPPED_FUNCTION(...) - # ... more finally blocks - # finally: #<--prepend to finallys - # final() #<--prepend to finallys - # - for a in self._args: - name = get_name(a) - final = self._name(name) - mapblock.append(f"{name}, {final} = {fname}({name})") - mapblock.append("try:") - finallys = ["finally:", f"{final}()#", "#", finallys] - else: - mapblock.extend( - f"{name} = {fname}({name})" for name in map(get_name, self._args) - ) - - return sig, wrapped_name, functions, mapblock, finallys, mutable_args - - @classmethod - def signature(cls, f): - r"""Construct a Signature object describing `f` - - Compute a Signature so that we can write a function wrapping f with - the same signature and call-type. - - Parameters - ---------- - f : callable - A function to be decorated - - Returns - ------- - sig : argmap.Signature - The Signature of f - - Notes - ----- - The Signature is a namedtuple with names: - - name : a unique version of the name of the decorated function - signature : the inspect.signature of the decorated function - def_sig : a string used as code to define the new function - call_sig : a string used as code to call the decorated function - names : a dict keyed by argument name and index to the argument's name - n_positional : the number of positional arguments in the signature - args : the name of the VAR_POSITIONAL argument if any, i.e. \*theseargs - kwargs : the name of the VAR_KEYWORDS argument if any, i.e. \*\*kwargs - - These named attributes of the signature are used in `assemble` and `compile` - to construct a string of source code for the decorated function. - - """ - sig = inspect.signature(f, follow_wrapped=False) - def_sig = [] - call_sig = [] - names = {} - - kind = None - args = None - kwargs = None - npos = 0 - for i, param in enumerate(sig.parameters.values()): - # parameters can be position-only, keyword-or-position, keyword-only - # in any combination, but only in the order as above. we do edge - # detection to add the appropriate punctuation - prev = kind - kind = param.kind - if prev == param.POSITIONAL_ONLY != kind: - # the last token was position-only, but this one isn't - def_sig.append("/") - if ( - param.VAR_POSITIONAL - != prev - != param.KEYWORD_ONLY - == kind - != param.VAR_POSITIONAL - ): - # param is the first keyword-only arg and isn't starred - def_sig.append("*") - - # star arguments as appropriate - if kind == param.VAR_POSITIONAL: - name = "*" + param.name - args = param.name - count = 0 - elif kind == param.VAR_KEYWORD: - name = "**" + param.name - kwargs = param.name - count = 0 - else: - names[i] = names[param.name] = param.name - name = param.name - count = 1 - - # assign to keyword-only args in the function call - if kind == param.KEYWORD_ONLY: - call_sig.append(f"{name} = {name}") - else: - npos += count - call_sig.append(name) - - def_sig.append(name) - - fname = cls._name(f) - def_sig = f'def {fname}({", ".join(def_sig)}):' - - call_sig = f"return {{}}({', '.join(call_sig)})" - - return cls.Signature(fname, sig, def_sig, call_sig, names, npos, args, kwargs) - - Signature = collections.namedtuple( - "Signature", - [ - "name", - "signature", - "def_sig", - "call_sig", - "names", - "n_positional", - "args", - "kwargs", - ], - ) - - @staticmethod - def _flatten(nestlist, visited): - """flattens a recursive list of lists that doesn't have cyclic references - - Parameters - ---------- - nestlist : iterable - A recursive list of objects to be flattened into a single iterable - - visited : set - A set of object ids which have been walked -- initialize with an - empty set - - Yields - ------ - Non-list objects contained in nestlist - - """ - for thing in nestlist: - if isinstance(thing, list): - if id(thing) in visited: - raise ValueError("A cycle was found in nestlist. Be a tree.") - else: - visited.add(id(thing)) - yield from argmap._flatten(thing, visited) - else: - yield thing - - _tabs = " " * 64 - - @staticmethod - def _indent(*lines): - """Indent list of code lines to make executable Python code - - Indents a tree-recursive list of strings, following the rule that one - space is added to the tab after a line that ends in a colon, and one is - removed after a line that ends in an hashmark. - - Parameters - ---------- - *lines : lists and/or strings - A recursive list of strings to be assembled into properly indented - code. - - Returns - ------- - code : str - - Examples - -------- - - argmap._indent(*["try:", "try:", "pass#", "finally:", "pass#", "#", - "finally:", "pass#"]) - - renders to - - '''try: - try: - pass# - finally: - pass# - # - finally: - pass#''' - """ - depth = 0 - for line in argmap._flatten(lines, set()): - yield f"{argmap._tabs[:depth]}{line}" - depth += (line[-1:] == ":") - (line[-1:] == "#") diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/heaps.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/heaps.py deleted file mode 100644 index 3db2790..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/heaps.py +++ /dev/null @@ -1,340 +0,0 @@ -""" -Min-heaps. -""" - -from heapq import heappop, heappush -from itertools import count - -import networkx as nx - -__all__ = ["MinHeap", "PairingHeap", "BinaryHeap"] - - -class MinHeap: - """Base class for min-heaps. - - A MinHeap stores a collection of key-value pairs ordered by their values. - It supports querying the minimum pair, inserting a new pair, decreasing the - value in an existing pair and deleting the minimum pair. - """ - - class _Item: - """Used by subclassess to represent a key-value pair.""" - - __slots__ = ("key", "value") - - def __init__(self, key, value): - self.key = key - self.value = value - - def __repr__(self): - return repr((self.key, self.value)) - - def __init__(self): - """Initialize a new min-heap.""" - self._dict = {} - - def min(self): - """Query the minimum key-value pair. - - Returns - ------- - key, value : tuple - The key-value pair with the minimum value in the heap. - - Raises - ------ - NetworkXError - If the heap is empty. - """ - raise NotImplementedError - - def pop(self): - """Delete the minimum pair in the heap. - - Returns - ------- - key, value : tuple - The key-value pair with the minimum value in the heap. - - Raises - ------ - NetworkXError - If the heap is empty. - """ - raise NotImplementedError - - def get(self, key, default=None): - """Returns the value associated with a key. - - Parameters - ---------- - key : hashable object - The key to be looked up. - - default : object - Default value to return if the key is not present in the heap. - Default value: None. - - Returns - ------- - value : object. - The value associated with the key. - """ - raise NotImplementedError - - def insert(self, key, value, allow_increase=False): - """Insert a new key-value pair or modify the value in an existing - pair. - - Parameters - ---------- - key : hashable object - The key. - - value : object comparable with existing values. - The value. - - allow_increase : bool - Whether the value is allowed to increase. If False, attempts to - increase an existing value have no effect. Default value: False. - - Returns - ------- - decreased : bool - True if a pair is inserted or the existing value is decreased. - """ - raise NotImplementedError - - def __nonzero__(self): - """Returns whether the heap if empty.""" - return bool(self._dict) - - def __bool__(self): - """Returns whether the heap if empty.""" - return bool(self._dict) - - def __len__(self): - """Returns the number of key-value pairs in the heap.""" - return len(self._dict) - - def __contains__(self, key): - """Returns whether a key exists in the heap. - - Parameters - ---------- - key : any hashable object. - The key to be looked up. - """ - return key in self._dict - - -class PairingHeap(MinHeap): - """A pairing heap.""" - - class _Node(MinHeap._Item): - """A node in a pairing heap. - - A tree in a pairing heap is stored using the left-child, right-sibling - representation. - """ - - __slots__ = ("left", "next", "prev", "parent") - - def __init__(self, key, value): - super().__init__(key, value) - # The leftmost child. - self.left = None - # The next sibling. - self.next = None - # The previous sibling. - self.prev = None - # The parent. - self.parent = None - - def __init__(self): - """Initialize a pairing heap.""" - super().__init__() - self._root = None - - def min(self): - if self._root is None: - raise nx.NetworkXError("heap is empty.") - return (self._root.key, self._root.value) - - def pop(self): - if self._root is None: - raise nx.NetworkXError("heap is empty.") - min_node = self._root - self._root = self._merge_children(self._root) - del self._dict[min_node.key] - return (min_node.key, min_node.value) - - def get(self, key, default=None): - node = self._dict.get(key) - return node.value if node is not None else default - - def insert(self, key, value, allow_increase=False): - node = self._dict.get(key) - root = self._root - if node is not None: - if value < node.value: - node.value = value - if node is not root and value < node.parent.value: - self._cut(node) - self._root = self._link(root, node) - return True - elif allow_increase and value > node.value: - node.value = value - child = self._merge_children(node) - # Nonstandard step: Link the merged subtree with the root. See - # below for the standard step. - if child is not None: - self._root = self._link(self._root, child) - # Standard step: Perform a decrease followed by a pop as if the - # value were the smallest in the heap. Then insert the new - # value into the heap. - # if node is not root: - # self._cut(node) - # if child is not None: - # root = self._link(root, child) - # self._root = self._link(root, node) - # else: - # self._root = (self._link(node, child) - # if child is not None else node) - return False - else: - # Insert a new key. - node = self._Node(key, value) - self._dict[key] = node - self._root = self._link(root, node) if root is not None else node - return True - - def _link(self, root, other): - """Link two nodes, making the one with the smaller value the parent of - the other. - """ - if other.value < root.value: - root, other = other, root - next = root.left - other.next = next - if next is not None: - next.prev = other - other.prev = None - root.left = other - other.parent = root - return root - - def _merge_children(self, root): - """Merge the subtrees of the root using the standard two-pass method. - The resulting subtree is detached from the root. - """ - node = root.left - root.left = None - if node is not None: - link = self._link - # Pass 1: Merge pairs of consecutive subtrees from left to right. - # At the end of the pass, only the prev pointers of the resulting - # subtrees have meaningful values. The other pointers will be fixed - # in pass 2. - prev = None - while True: - next = node.next - if next is None: - node.prev = prev - break - next_next = next.next - node = link(node, next) - node.prev = prev - prev = node - if next_next is None: - break - node = next_next - # Pass 2: Successively merge the subtrees produced by pass 1 from - # right to left with the rightmost one. - prev = node.prev - while prev is not None: - prev_prev = prev.prev - node = link(prev, node) - prev = prev_prev - # Now node can become the new root. Its has no parent nor siblings. - node.prev = None - node.next = None - node.parent = None - return node - - def _cut(self, node): - """Cut a node from its parent.""" - prev = node.prev - next = node.next - if prev is not None: - prev.next = next - else: - node.parent.left = next - node.prev = None - if next is not None: - next.prev = prev - node.next = None - node.parent = None - - -class BinaryHeap(MinHeap): - """A binary heap.""" - - def __init__(self): - """Initialize a binary heap.""" - super().__init__() - self._heap = [] - self._count = count() - - def min(self): - dict = self._dict - if not dict: - raise nx.NetworkXError("heap is empty") - heap = self._heap - pop = heappop - # Repeatedly remove stale key-value pairs until a up-to-date one is - # met. - while True: - value, _, key = heap[0] - if key in dict and value == dict[key]: - break - pop(heap) - return (key, value) - - def pop(self): - dict = self._dict - if not dict: - raise nx.NetworkXError("heap is empty") - heap = self._heap - pop = heappop - # Repeatedly remove stale key-value pairs until a up-to-date one is - # met. - while True: - value, _, key = heap[0] - pop(heap) - if key in dict and value == dict[key]: - break - del dict[key] - return (key, value) - - def get(self, key, default=None): - return self._dict.get(key, default) - - def insert(self, key, value, allow_increase=False): - dict = self._dict - if key in dict: - old_value = dict[key] - if value < old_value or (allow_increase and value > old_value): - # Since there is no way to efficiently obtain the location of a - # key-value pair in the heap, insert a new pair even if ones - # with the same key may already be present. Deem the old ones - # as stale and skip them when the minimum pair is queried. - dict[key] = value - heappush(self._heap, (value, next(self._count), key)) - return value < old_value - return False - else: - dict[key] = value - heappush(self._heap, (value, next(self._count), key)) - return True diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/mapped_queue.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/mapped_queue.py deleted file mode 100644 index 0dcea36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/mapped_queue.py +++ /dev/null @@ -1,297 +0,0 @@ -"""Priority queue class with updatable priorities.""" - -import heapq - -__all__ = ["MappedQueue"] - - -class _HeapElement: - """This proxy class separates the heap element from its priority. - - The idea is that using a 2-tuple (priority, element) works - for sorting, but not for dict lookup because priorities are - often floating point values so round-off can mess up equality. - - So, we need inequalities to look at the priority (for sorting) - and equality (and hash) to look at the element to enable - updates to the priority. - - Unfortunately, this class can be tricky to work with if you forget that - `__lt__` compares the priority while `__eq__` compares the element. - In `greedy_modularity_communities()` the following code is - used to check that two _HeapElements differ in either element or priority: - - if d_oldmax != row_max or d_oldmax.priority != row_max.priority: - - If the priorities are the same, this implementation uses the element - as a tiebreaker. This provides compatibility with older systems that - use tuples to combine priority and elements. - """ - - __slots__ = ["priority", "element", "_hash"] - - def __init__(self, priority, element): - self.priority = priority - self.element = element - self._hash = hash(element) - - def __lt__(self, other): - try: - other_priority = other.priority - except AttributeError: - return self.priority < other - # assume comparing to another _HeapElement - if self.priority == other_priority: - try: - return self.element < other.element - except TypeError as err: - raise TypeError( - "Consider using a tuple, with a priority value that can be compared." - ) - return self.priority < other_priority - - def __gt__(self, other): - try: - other_priority = other.priority - except AttributeError: - return self.priority > other - # assume comparing to another _HeapElement - if self.priority == other_priority: - try: - return self.element > other.element - except TypeError as err: - raise TypeError( - "Consider using a tuple, with a priority value that can be compared." - ) - return self.priority > other_priority - - def __eq__(self, other): - try: - return self.element == other.element - except AttributeError: - return self.element == other - - def __hash__(self): - return self._hash - - def __getitem__(self, indx): - return self.priority if indx == 0 else self.element[indx - 1] - - def __iter__(self): - yield self.priority - try: - yield from self.element - except TypeError: - yield self.element - - def __repr__(self): - return f"_HeapElement({self.priority}, {self.element})" - - -class MappedQueue: - """The MappedQueue class implements a min-heap with removal and update-priority. - - The min heap uses heapq as well as custom written _siftup and _siftdown - methods to allow the heap positions to be tracked by an additional dict - keyed by element to position. The smallest element can be popped in O(1) time, - new elements can be pushed in O(log n) time, and any element can be removed - or updated in O(log n) time. The queue cannot contain duplicate elements - and an attempt to push an element already in the queue will have no effect. - - MappedQueue complements the heapq package from the python standard - library. While MappedQueue is designed for maximum compatibility with - heapq, it adds element removal, lookup, and priority update. - - Parameters - ---------- - data : dict or iterable - - Examples - -------- - - A `MappedQueue` can be created empty, or optionally, given a dictionary - of initial elements and priorities. The methods `push`, `pop`, - `remove`, and `update` operate on the queue. - - >>> colors_nm = {"red": 665, "blue": 470, "green": 550} - >>> q = MappedQueue(colors_nm) - >>> q.remove("red") - >>> q.update("green", "violet", 400) - >>> q.push("indigo", 425) - True - >>> [q.pop().element for i in range(len(q.heap))] - ['violet', 'indigo', 'blue'] - - A `MappedQueue` can also be initialized with a list or other iterable. The priority is assumed - to be the sort order of the items in the list. - - >>> q = MappedQueue([916, 50, 4609, 493, 237]) - >>> q.remove(493) - >>> q.update(237, 1117) - >>> [q.pop() for i in range(len(q.heap))] - [50, 916, 1117, 4609] - - An exception is raised if the elements are not comparable. - - >>> q = MappedQueue([100, "a"]) - Traceback (most recent call last): - ... - TypeError: '<' not supported between instances of 'int' and 'str' - - To avoid the exception, use a dictionary to assign priorities to the elements. - - >>> q = MappedQueue({100: 0, "a": 1}) - - References - ---------- - .. [1] Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2001). - Introduction to algorithms second edition. - .. [2] Knuth, D. E. (1997). The art of computer programming (Vol. 3). - Pearson Education. - """ - - def __init__(self, data=None): - """Priority queue class with updatable priorities.""" - if data is None: - self.heap = [] - elif isinstance(data, dict): - self.heap = [_HeapElement(v, k) for k, v in data.items()] - else: - self.heap = list(data) - self.position = {} - self._heapify() - - def _heapify(self): - """Restore heap invariant and recalculate map.""" - heapq.heapify(self.heap) - self.position = {elt: pos for pos, elt in enumerate(self.heap)} - if len(self.heap) != len(self.position): - raise AssertionError("Heap contains duplicate elements") - - def __len__(self): - return len(self.heap) - - def push(self, elt, priority=None): - """Add an element to the queue.""" - if priority is not None: - elt = _HeapElement(priority, elt) - # If element is already in queue, do nothing - if elt in self.position: - return False - # Add element to heap and dict - pos = len(self.heap) - self.heap.append(elt) - self.position[elt] = pos - # Restore invariant by sifting down - self._siftdown(0, pos) - return True - - def pop(self): - """Remove and return the smallest element in the queue.""" - # Remove smallest element - elt = self.heap[0] - del self.position[elt] - # If elt is last item, remove and return - if len(self.heap) == 1: - self.heap.pop() - return elt - # Replace root with last element - last = self.heap.pop() - self.heap[0] = last - self.position[last] = 0 - # Restore invariant by sifting up - self._siftup(0) - # Return smallest element - return elt - - def update(self, elt, new, priority=None): - """Replace an element in the queue with a new one.""" - if priority is not None: - new = _HeapElement(priority, new) - # Replace - pos = self.position[elt] - self.heap[pos] = new - del self.position[elt] - self.position[new] = pos - # Restore invariant by sifting up - self._siftup(pos) - - def remove(self, elt): - """Remove an element from the queue.""" - # Find and remove element - try: - pos = self.position[elt] - del self.position[elt] - except KeyError: - # Not in queue - raise - # If elt is last item, remove and return - if pos == len(self.heap) - 1: - self.heap.pop() - return - # Replace elt with last element - last = self.heap.pop() - self.heap[pos] = last - self.position[last] = pos - # Restore invariant by sifting up - self._siftup(pos) - - def _siftup(self, pos): - """Move smaller child up until hitting a leaf. - - Built to mimic code for heapq._siftup - only updating position dict too. - """ - heap, position = self.heap, self.position - end_pos = len(heap) - startpos = pos - newitem = heap[pos] - # Shift up the smaller child until hitting a leaf - child_pos = (pos << 1) + 1 # start with leftmost child position - while child_pos < end_pos: - # Set child_pos to index of smaller child. - child = heap[child_pos] - right_pos = child_pos + 1 - if right_pos < end_pos: - right = heap[right_pos] - if not child < right: - child = right - child_pos = right_pos - # Move the smaller child up. - heap[pos] = child - position[child] = pos - pos = child_pos - child_pos = (pos << 1) + 1 - # pos is a leaf position. Put newitem there, and bubble it up - # to its final resting place (by sifting its parents down). - while pos > 0: - parent_pos = (pos - 1) >> 1 - parent = heap[parent_pos] - if not newitem < parent: - break - heap[pos] = parent - position[parent] = pos - pos = parent_pos - heap[pos] = newitem - position[newitem] = pos - - def _siftdown(self, start_pos, pos): - """Restore invariant. keep swapping with parent until smaller. - - Built to mimic code for heapq._siftdown - only updating position dict too. - """ - heap, position = self.heap, self.position - newitem = heap[pos] - # Follow the path to the root, moving parents down until finding a place - # newitem fits. - while pos > start_pos: - parent_pos = (pos - 1) >> 1 - parent = heap[parent_pos] - if not newitem < parent: - break - heap[pos] = parent - position[parent] = pos - pos = parent_pos - heap[pos] = newitem - position[newitem] = pos diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/misc.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/misc.py deleted file mode 100644 index b42d890..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/misc.py +++ /dev/null @@ -1,653 +0,0 @@ -""" -Miscellaneous Helpers for NetworkX. - -These are not imported into the base networkx namespace but -can be accessed, for example, as - ->>> import networkx ->>> networkx.utils.make_list_of_ints({1, 2, 3}) -[1, 2, 3] ->>> networkx.utils.arbitrary_element({5, 1, 7}) # doctest: +SKIP -1 -""" - -import random -import sys -import uuid -import warnings -from collections import defaultdict, deque -from collections.abc import Iterable, Iterator, Sized -from itertools import chain, tee - -import networkx as nx - -__all__ = [ - "flatten", - "make_list_of_ints", - "dict_to_numpy_array", - "arbitrary_element", - "pairwise", - "groups", - "create_random_state", - "create_py_random_state", - "PythonRandomInterface", - "PythonRandomViaNumpyBits", - "nodes_equal", - "edges_equal", - "graphs_equal", - "_clear_cache", -] - - -# some cookbook stuff -# used in deciding whether something is a bunch of nodes, edges, etc. -# see G.add_nodes and others in Graph Class in networkx/base.py - - -def flatten(obj, result=None): - """Return flattened version of (possibly nested) iterable object.""" - if not isinstance(obj, Iterable | Sized) or isinstance(obj, str): - return obj - if result is None: - result = [] - for item in obj: - if not isinstance(item, Iterable | Sized) or isinstance(item, str): - result.append(item) - else: - flatten(item, result) - return tuple(result) - - -def make_list_of_ints(sequence): - """Return list of ints from sequence of integral numbers. - - All elements of the sequence must satisfy int(element) == element - or a ValueError is raised. Sequence is iterated through once. - - If sequence is a list, the non-int values are replaced with ints. - So, no new list is created - """ - if not isinstance(sequence, list): - result = [] - for i in sequence: - errmsg = f"sequence is not all integers: {i}" - try: - ii = int(i) - except ValueError: - raise nx.NetworkXError(errmsg) from None - if ii != i: - raise nx.NetworkXError(errmsg) - result.append(ii) - return result - # original sequence is a list... in-place conversion to ints - for indx, i in enumerate(sequence): - errmsg = f"sequence is not all integers: {i}" - if isinstance(i, int): - continue - try: - ii = int(i) - except ValueError: - raise nx.NetworkXError(errmsg) from None - if ii != i: - raise nx.NetworkXError(errmsg) - sequence[indx] = ii - return sequence - - -def dict_to_numpy_array(d, mapping=None): - """Convert a dictionary of dictionaries to a numpy array - with optional mapping.""" - try: - return _dict_to_numpy_array2(d, mapping) - except (AttributeError, TypeError): - # AttributeError is when no mapping was provided and v.keys() fails. - # TypeError is when a mapping was provided and d[k1][k2] fails. - return _dict_to_numpy_array1(d, mapping) - - -def _dict_to_numpy_array2(d, mapping=None): - """Convert a dictionary of dictionaries to a 2d numpy array - with optional mapping. - - """ - import numpy as np - - if mapping is None: - s = set(d.keys()) - for k, v in d.items(): - s.update(v.keys()) - mapping = dict(zip(s, range(len(s)))) - n = len(mapping) - a = np.zeros((n, n)) - for k1, i in mapping.items(): - for k2, j in mapping.items(): - try: - a[i, j] = d[k1][k2] - except KeyError: - pass - return a - - -def _dict_to_numpy_array1(d, mapping=None): - """Convert a dictionary of numbers to a 1d numpy array with optional mapping.""" - import numpy as np - - if mapping is None: - s = set(d.keys()) - mapping = dict(zip(s, range(len(s)))) - n = len(mapping) - a = np.zeros(n) - for k1, i in mapping.items(): - i = mapping[k1] - a[i] = d[k1] - return a - - -def arbitrary_element(iterable): - """Returns an arbitrary element of `iterable` without removing it. - - This is most useful for "peeking" at an arbitrary element of a set, - but can be used for any list, dictionary, etc., as well. - - Parameters - ---------- - iterable : `abc.collections.Iterable` instance - Any object that implements ``__iter__``, e.g. set, dict, list, tuple, - etc. - - Returns - ------- - The object that results from ``next(iter(iterable))`` - - Raises - ------ - ValueError - If `iterable` is an iterator (because the current implementation of - this function would consume an element from the iterator). - - Examples - -------- - Arbitrary elements from common Iterable objects: - - >>> nx.utils.arbitrary_element([1, 2, 3]) # list - 1 - >>> nx.utils.arbitrary_element((1, 2, 3)) # tuple - 1 - >>> nx.utils.arbitrary_element({1, 2, 3}) # set - 1 - >>> d = {k: v for k, v in zip([1, 2, 3], [3, 2, 1])} - >>> nx.utils.arbitrary_element(d) # dict_keys - 1 - >>> nx.utils.arbitrary_element(d.values()) # dict values - 3 - - `str` is also an Iterable: - - >>> nx.utils.arbitrary_element("hello") - 'h' - - :exc:`ValueError` is raised if `iterable` is an iterator: - - >>> iterator = iter([1, 2, 3]) # Iterator, *not* Iterable - >>> nx.utils.arbitrary_element(iterator) - Traceback (most recent call last): - ... - ValueError: cannot return an arbitrary item from an iterator - - Notes - ----- - This function does not return a *random* element. If `iterable` is - ordered, sequential calls will return the same value:: - - >>> l = [1, 2, 3] - >>> nx.utils.arbitrary_element(l) - 1 - >>> nx.utils.arbitrary_element(l) - 1 - - """ - if isinstance(iterable, Iterator): - raise ValueError("cannot return an arbitrary item from an iterator") - # Another possible implementation is ``for x in iterable: return x``. - return next(iter(iterable)) - - -# Recipe from the itertools documentation. -def pairwise(iterable, cyclic=False): - "s -> (s0, s1), (s1, s2), (s2, s3), ..." - a, b = tee(iterable) - first = next(b, None) - if cyclic is True: - return zip(a, chain(b, (first,))) - return zip(a, b) - - -def groups(many_to_one): - """Converts a many-to-one mapping into a one-to-many mapping. - - `many_to_one` must be a dictionary whose keys and values are all - :term:`hashable`. - - The return value is a dictionary mapping values from `many_to_one` - to sets of keys from `many_to_one` that have that value. - - Examples - -------- - >>> from networkx.utils import groups - >>> many_to_one = {"a": 1, "b": 1, "c": 2, "d": 3, "e": 3} - >>> groups(many_to_one) # doctest: +SKIP - {1: {'a', 'b'}, 2: {'c'}, 3: {'e', 'd'}} - """ - one_to_many = defaultdict(set) - for v, k in many_to_one.items(): - one_to_many[k].add(v) - return dict(one_to_many) - - -def create_random_state(random_state=None): - """Returns a numpy.random.RandomState or numpy.random.Generator instance - depending on input. - - Parameters - ---------- - random_state : int or NumPy RandomState or Generator instance, optional (default=None) - If int, return a numpy.random.RandomState instance set with seed=int. - if `numpy.random.RandomState` instance, return it. - if `numpy.random.Generator` instance, return it. - if None or numpy.random, return the global random number generator used - by numpy.random. - """ - import numpy as np - - if random_state is None or random_state is np.random: - return np.random.mtrand._rand - if isinstance(random_state, np.random.RandomState): - return random_state - if isinstance(random_state, int): - return np.random.RandomState(random_state) - if isinstance(random_state, np.random.Generator): - return random_state - msg = ( - f"{random_state} cannot be used to create a numpy.random.RandomState or\n" - "numpy.random.Generator instance" - ) - raise ValueError(msg) - - -class PythonRandomViaNumpyBits(random.Random): - """Provide the random.random algorithms using a numpy.random bit generator - - The intent is to allow people to contribute code that uses Python's random - library, but still allow users to provide a single easily controlled random - bit-stream for all work with NetworkX. This implementation is based on helpful - comments and code from Robert Kern on NumPy's GitHub Issue #24458. - - This implementation supersedes that of `PythonRandomInterface` which rewrote - methods to account for subtle differences in API between `random` and - `numpy.random`. Instead this subclasses `random.Random` and overwrites - the methods `random`, `getrandbits`, `getstate`, `setstate` and `seed`. - It makes them use the rng values from an input numpy `RandomState` or `Generator`. - Those few methods allow the rest of the `random.Random` methods to provide - the API interface of `random.random` while using randomness generated by - a numpy generator. - """ - - def __init__(self, rng=None): - try: - import numpy as np - except ImportError: - msg = "numpy not found, only random.random available." - warnings.warn(msg, ImportWarning) - - if rng is None: - self._rng = np.random.mtrand._rand - else: - self._rng = rng - - # Not necessary, given our overriding of gauss() below, but it's - # in the superclass and nominally public, so initialize it here. - self.gauss_next = None - - def random(self): - """Get the next random number in the range 0.0 <= X < 1.0.""" - return self._rng.random() - - def getrandbits(self, k): - """getrandbits(k) -> x. Generates an int with k random bits.""" - if k < 0: - raise ValueError("number of bits must be non-negative") - numbytes = (k + 7) // 8 # bits / 8 and rounded up - x = int.from_bytes(self._rng.bytes(numbytes), "big") - return x >> (numbytes * 8 - k) # trim excess bits - - def getstate(self): - return self._rng.__getstate__() - - def setstate(self, state): - self._rng.__setstate__(state) - - def seed(self, *args, **kwds): - "Do nothing override method." - raise NotImplementedError("seed() not implemented in PythonRandomViaNumpyBits") - - -################################################################## -class PythonRandomInterface: - """PythonRandomInterface is included for backward compatibility - New code should use PythonRandomViaNumpyBits instead. - """ - - def __init__(self, rng=None): - try: - import numpy as np - except ImportError: - msg = "numpy not found, only random.random available." - warnings.warn(msg, ImportWarning) - - if rng is None: - self._rng = np.random.mtrand._rand - else: - self._rng = rng - - def random(self): - return self._rng.random() - - def uniform(self, a, b): - return a + (b - a) * self._rng.random() - - def randrange(self, a, b=None): - import numpy as np - - if b is None: - a, b = 0, a - if b > 9223372036854775807: # from np.iinfo(np.int64).max - tmp_rng = PythonRandomViaNumpyBits(self._rng) - return tmp_rng.randrange(a, b) - - if isinstance(self._rng, np.random.Generator): - return self._rng.integers(a, b) - return self._rng.randint(a, b) - - # NOTE: the numpy implementations of `choice` don't support strings, so - # this cannot be replaced with self._rng.choice - def choice(self, seq): - import numpy as np - - if isinstance(self._rng, np.random.Generator): - idx = self._rng.integers(0, len(seq)) - else: - idx = self._rng.randint(0, len(seq)) - return seq[idx] - - def gauss(self, mu, sigma): - return self._rng.normal(mu, sigma) - - def shuffle(self, seq): - return self._rng.shuffle(seq) - - # Some methods don't match API for numpy RandomState. - # Commented out versions are not used by NetworkX - - def sample(self, seq, k): - return self._rng.choice(list(seq), size=(k,), replace=False) - - def randint(self, a, b): - import numpy as np - - if b > 9223372036854775807: # from np.iinfo(np.int64).max - tmp_rng = PythonRandomViaNumpyBits(self._rng) - return tmp_rng.randint(a, b) - - if isinstance(self._rng, np.random.Generator): - return self._rng.integers(a, b + 1) - return self._rng.randint(a, b + 1) - - # exponential as expovariate with 1/argument, - def expovariate(self, scale): - return self._rng.exponential(1 / scale) - - # pareto as paretovariate with 1/argument, - def paretovariate(self, shape): - return self._rng.pareto(shape) - - -# weibull as weibullvariate multiplied by beta, -# def weibullvariate(self, alpha, beta): -# return self._rng.weibull(alpha) * beta -# -# def triangular(self, low, high, mode): -# return self._rng.triangular(low, mode, high) -# -# def choices(self, seq, weights=None, cum_weights=None, k=1): -# return self._rng.choice(seq - - -def create_py_random_state(random_state=None): - """Returns a random.Random instance depending on input. - - Parameters - ---------- - random_state : int or random number generator or None (default=None) - - If int, return a `random.Random` instance set with seed=int. - - If `random.Random` instance, return it. - - If None or the `np.random` package, return the global random number - generator used by `np.random`. - - If an `np.random.Generator` instance, or the `np.random` package, or - the global numpy random number generator, then return it. - wrapped in a `PythonRandomViaNumpyBits` class. - - If a `PythonRandomViaNumpyBits` instance, return it. - - If a `PythonRandomInterface` instance, return it. - - If a `np.random.RandomState` instance and not the global numpy default, - return it wrapped in `PythonRandomInterface` for backward bit-stream - matching with legacy code. - - Notes - ----- - - A diagram intending to illustrate the relationships behind our support - for numpy random numbers is called - `NetworkX Numpy Random Numbers `_. - - More discussion about this support also appears in - `gh-6869#comment `_. - - Wrappers of numpy.random number generators allow them to mimic the Python random - number generation algorithms. For example, Python can create arbitrarily large - random ints, and the wrappers use Numpy bit-streams with CPython's random module - to choose arbitrarily large random integers too. - - We provide two wrapper classes: - `PythonRandomViaNumpyBits` is usually what you want and is always used for - `np.Generator` instances. But for users who need to recreate random numbers - produced in NetworkX 3.2 or earlier, we maintain the `PythonRandomInterface` - wrapper as well. We use it only used if passed a (non-default) `np.RandomState` - instance pre-initialized from a seed. Otherwise the newer wrapper is used. - """ - if random_state is None or random_state is random: - return random._inst - if isinstance(random_state, random.Random): - return random_state - if isinstance(random_state, int): - return random.Random(random_state) - - try: - import numpy as np - except ImportError: - pass - else: - if isinstance(random_state, PythonRandomInterface | PythonRandomViaNumpyBits): - return random_state - if isinstance(random_state, np.random.Generator): - return PythonRandomViaNumpyBits(random_state) - if random_state is np.random: - return PythonRandomViaNumpyBits(np.random.mtrand._rand) - - if isinstance(random_state, np.random.RandomState): - if random_state is np.random.mtrand._rand: - return PythonRandomViaNumpyBits(random_state) - # Only need older interface if specially constructed RandomState used - return PythonRandomInterface(random_state) - - msg = f"{random_state} cannot be used to generate a random.Random instance" - raise ValueError(msg) - - -def nodes_equal(nodes1, nodes2): - """Check if nodes are equal. - - Equality here means equal as Python objects. - Node data must match if included. - The order of nodes is not relevant. - - Parameters - ---------- - nodes1, nodes2 : iterables of nodes, or (node, datadict) tuples - - Returns - ------- - bool - True if nodes are equal, False otherwise. - """ - nlist1 = list(nodes1) - nlist2 = list(nodes2) - try: - d1 = dict(nlist1) - d2 = dict(nlist2) - except (ValueError, TypeError): - d1 = dict.fromkeys(nlist1) - d2 = dict.fromkeys(nlist2) - return d1 == d2 - - -def edges_equal(edges1, edges2): - """Check if edges are equal. - - Equality here means equal as Python objects. - Edge data must match if included. - The order of the edges is not relevant. - - Parameters - ---------- - edges1, edges2 : iterables of with u, v nodes as - edge tuples (u, v), or - edge tuples with data dicts (u, v, d), or - edge tuples with keys and data dicts (u, v, k, d) - - Returns - ------- - bool - True if edges are equal, False otherwise. - """ - from collections import defaultdict - - d1 = defaultdict(dict) - d2 = defaultdict(dict) - c1 = 0 - for c1, e in enumerate(edges1): - u, v = e[0], e[1] - data = [e[2:]] - if v in d1[u]: - data = d1[u][v] + data - d1[u][v] = data - d1[v][u] = data - c2 = 0 - for c2, e in enumerate(edges2): - u, v = e[0], e[1] - data = [e[2:]] - if v in d2[u]: - data = d2[u][v] + data - d2[u][v] = data - d2[v][u] = data - if c1 != c2: - return False - # can check one direction because lengths are the same. - for n, nbrdict in d1.items(): - for nbr, datalist in nbrdict.items(): - if n not in d2: - return False - if nbr not in d2[n]: - return False - d2datalist = d2[n][nbr] - for data in datalist: - if datalist.count(data) != d2datalist.count(data): - return False - return True - - -def graphs_equal(graph1, graph2): - """Check if graphs are equal. - - Equality here means equal as Python objects (not isomorphism). - Node, edge and graph data must match. - - Parameters - ---------- - graph1, graph2 : graph - - Returns - ------- - bool - True if graphs are equal, False otherwise. - """ - return ( - graph1.adj == graph2.adj - and graph1.nodes == graph2.nodes - and graph1.graph == graph2.graph - ) - - -def _clear_cache(G): - """Clear the cache of a graph (currently stores converted graphs). - - Caching is controlled via ``nx.config.cache_converted_graphs`` configuration. - """ - if cache := getattr(G, "__networkx_cache__", None): - cache.clear() - - -def check_create_using(create_using, *, directed=None, multigraph=None, default=None): - """Assert that create_using has good properties - - This checks for desired directedness and multi-edge properties. - It returns `create_using` unless that is `None` when it returns - the optionally specified default value. - - Parameters - ---------- - create_using : None, graph class or instance - The input value of create_using for a function. - directed : None or bool - Whether to check `create_using.is_directed() == directed`. - If None, do not assert directedness. - multigraph : None or bool - Whether to check `create_using.is_multigraph() == multigraph`. - If None, do not assert multi-edge property. - default : None or graph class - The graph class to return if create_using is None. - - Returns - ------- - create_using : graph class or instance - The provided graph class or instance, or if None, the `default` value. - - Raises - ------ - NetworkXError - When `create_using` doesn't match the properties specified by `directed` - or `multigraph` parameters. - """ - if default is None: - default = nx.Graph - G = create_using if create_using is not None else default - - G_directed = G.is_directed(None) if isinstance(G, type) else G.is_directed() - G_multigraph = G.is_multigraph(None) if isinstance(G, type) else G.is_multigraph() - - if directed is not None: - if directed and not G_directed: - raise nx.NetworkXError("create_using must be directed") - if not directed and G_directed: - raise nx.NetworkXError("create_using must not be directed") - - if multigraph is not None: - if multigraph and not G_multigraph: - raise nx.NetworkXError("create_using must be a multi-graph") - if not multigraph and G_multigraph: - raise nx.NetworkXError("create_using must not be a multi-graph") - return G diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/random_sequence.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/random_sequence.py deleted file mode 100644 index 20a7b5e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/random_sequence.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -Utilities for generating random numbers, random sequences, and -random selections. -""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = [ - "powerlaw_sequence", - "zipf_rv", - "cumulative_distribution", - "discrete_sequence", - "random_weighted_sample", - "weighted_choice", -] - - -# The same helpers for choosing random sequences from distributions -# uses Python's random module -# https://docs.python.org/3/library/random.html - - -@py_random_state(2) -def powerlaw_sequence(n, exponent=2.0, seed=None): - """ - Return sample sequence of length n from a power law distribution. - """ - return [seed.paretovariate(exponent - 1) for i in range(n)] - - -@py_random_state(2) -def zipf_rv(alpha, xmin=1, seed=None): - r"""Returns a random value chosen from the Zipf distribution. - - The return value is an integer drawn from the probability distribution - - .. math:: - - p(x)=\frac{x^{-\alpha}}{\zeta(\alpha, x_{\min})}, - - where $\zeta(\alpha, x_{\min})$ is the Hurwitz zeta function. - - Parameters - ---------- - alpha : float - Exponent value of the distribution - xmin : int - Minimum value - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - x : int - Random value from Zipf distribution - - Raises - ------ - ValueError: - If xmin < 1 or - If alpha <= 1 - - Notes - ----- - The rejection algorithm generates random values for a the power-law - distribution in uniformly bounded expected time dependent on - parameters. See [1]_ for details on its operation. - - Examples - -------- - >>> nx.utils.zipf_rv(alpha=2, xmin=3, seed=42) - 8 - - References - ---------- - .. [1] Luc Devroye, Non-Uniform Random Variate Generation, - Springer-Verlag, New York, 1986. - """ - if xmin < 1: - raise ValueError("xmin < 1") - if alpha <= 1: - raise ValueError("a <= 1.0") - a1 = alpha - 1.0 - b = 2**a1 - while True: - u = 1.0 - seed.random() # u in (0,1] - v = seed.random() # v in [0,1) - x = int(xmin * u ** -(1.0 / a1)) - t = (1.0 + (1.0 / x)) ** a1 - if v * x * (t - 1.0) / (b - 1.0) <= t / b: - break - return x - - -def cumulative_distribution(distribution): - """Returns normalized cumulative distribution from discrete distribution.""" - - cdf = [0.0] - psum = sum(distribution) - for i in range(len(distribution)): - cdf.append(cdf[i] + distribution[i] / psum) - return cdf - - -@py_random_state(3) -def discrete_sequence(n, distribution=None, cdistribution=None, seed=None): - """ - Return sample sequence of length n from a given discrete distribution - or discrete cumulative distribution. - - One of the following must be specified. - - distribution = histogram of values, will be normalized - - cdistribution = normalized discrete cumulative distribution - - """ - import bisect - - if cdistribution is not None: - cdf = cdistribution - elif distribution is not None: - cdf = cumulative_distribution(distribution) - else: - raise nx.NetworkXError( - "discrete_sequence: distribution or cdistribution missing" - ) - - # get a uniform random number - inputseq = [seed.random() for i in range(n)] - - # choose from CDF - seq = [bisect.bisect_left(cdf, s) - 1 for s in inputseq] - return seq - - -@py_random_state(2) -def random_weighted_sample(mapping, k, seed=None): - """Returns k items without replacement from a weighted sample. - - The input is a dictionary of items with weights as values. - """ - if k > len(mapping): - raise ValueError("sample larger than population") - sample = set() - while len(sample) < k: - sample.add(weighted_choice(mapping, seed)) - return list(sample) - - -@py_random_state(1) -def weighted_choice(mapping, seed=None): - """Returns a single element from a weighted sample. - - The input is a dictionary of items with weights as values. - """ - # use roulette method - rnd = seed.random() * sum(mapping.values()) - for k, w in mapping.items(): - rnd -= w - if rnd < 0: - return k diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/rcm.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/rcm.py deleted file mode 100644 index e7366ff..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/rcm.py +++ /dev/null @@ -1,159 +0,0 @@ -""" -Cuthill-McKee ordering of graph nodes to produce sparse matrices -""" - -from collections import deque -from operator import itemgetter - -import networkx as nx - -from ..utils import arbitrary_element - -__all__ = ["cuthill_mckee_ordering", "reverse_cuthill_mckee_ordering"] - - -def cuthill_mckee_ordering(G, heuristic=None): - """Generate an ordering (permutation) of the graph nodes to make - a sparse matrix. - - Uses the Cuthill-McKee heuristic (based on breadth-first search) [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - heuristic : function, optional - Function to choose starting node for RCM algorithm. If None - a node from a pseudo-peripheral pair is used. A user-defined function - can be supplied that takes a graph object and returns a single node. - - Returns - ------- - nodes : generator - Generator of nodes in Cuthill-McKee ordering. - - Examples - -------- - >>> from networkx.utils import cuthill_mckee_ordering - >>> G = nx.path_graph(4) - >>> rcm = list(cuthill_mckee_ordering(G)) - >>> A = nx.adjacency_matrix(G, nodelist=rcm) - - Smallest degree node as heuristic function: - - >>> def smallest_degree(G): - ... return min(G, key=G.degree) - >>> rcm = list(cuthill_mckee_ordering(G, heuristic=smallest_degree)) - - - See Also - -------- - reverse_cuthill_mckee_ordering - - Notes - ----- - The optimal solution the bandwidth reduction is NP-complete [2]_. - - - References - ---------- - .. [1] E. Cuthill and J. McKee. - Reducing the bandwidth of sparse symmetric matrices, - In Proc. 24th Nat. Conf. ACM, pages 157-172, 1969. - http://doi.acm.org/10.1145/800195.805928 - .. [2] Steven S. Skiena. 1997. The Algorithm Design Manual. - Springer-Verlag New York, Inc., New York, NY, USA. - """ - for c in nx.connected_components(G): - yield from connected_cuthill_mckee_ordering(G.subgraph(c), heuristic) - - -def reverse_cuthill_mckee_ordering(G, heuristic=None): - """Generate an ordering (permutation) of the graph nodes to make - a sparse matrix. - - Uses the reverse Cuthill-McKee heuristic (based on breadth-first search) - [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - heuristic : function, optional - Function to choose starting node for RCM algorithm. If None - a node from a pseudo-peripheral pair is used. A user-defined function - can be supplied that takes a graph object and returns a single node. - - Returns - ------- - nodes : generator - Generator of nodes in reverse Cuthill-McKee ordering. - - Examples - -------- - >>> from networkx.utils import reverse_cuthill_mckee_ordering - >>> G = nx.path_graph(4) - >>> rcm = list(reverse_cuthill_mckee_ordering(G)) - >>> A = nx.adjacency_matrix(G, nodelist=rcm) - - Smallest degree node as heuristic function: - - >>> def smallest_degree(G): - ... return min(G, key=G.degree) - >>> rcm = list(reverse_cuthill_mckee_ordering(G, heuristic=smallest_degree)) - - - See Also - -------- - cuthill_mckee_ordering - - Notes - ----- - The optimal solution the bandwidth reduction is NP-complete [2]_. - - References - ---------- - .. [1] E. Cuthill and J. McKee. - Reducing the bandwidth of sparse symmetric matrices, - In Proc. 24th Nat. Conf. ACM, pages 157-72, 1969. - http://doi.acm.org/10.1145/800195.805928 - .. [2] Steven S. Skiena. 1997. The Algorithm Design Manual. - Springer-Verlag New York, Inc., New York, NY, USA. - """ - return reversed(list(cuthill_mckee_ordering(G, heuristic=heuristic))) - - -def connected_cuthill_mckee_ordering(G, heuristic=None): - # the cuthill mckee algorithm for connected graphs - if heuristic is None: - start = pseudo_peripheral_node(G) - else: - start = heuristic(G) - visited = {start} - queue = deque([start]) - while queue: - parent = queue.popleft() - yield parent - nd = sorted(G.degree(set(G[parent]) - visited), key=itemgetter(1)) - children = [n for n, d in nd] - visited.update(children) - queue.extend(children) - - -def pseudo_peripheral_node(G): - # helper for cuthill-mckee to find a node in a "pseudo peripheral pair" - # to use as good starting node - u = arbitrary_element(G) - lp = 0 - v = u - while True: - spl = dict(nx.shortest_path_length(G, v)) - l = max(spl.values()) - if l <= lp: - break - lp = l - farthest = (n for n, dist in spl.items() if dist == l) - v, deg = min(G.degree(farthest), key=itemgetter(1)) - return v diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/__init__.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test__init.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test__init.py deleted file mode 100644 index ecbcce3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test__init.py +++ /dev/null @@ -1,11 +0,0 @@ -import pytest - - -def test_utils_namespace(): - """Ensure objects are not unintentionally exposed in utils namespace.""" - with pytest.raises(ImportError): - from networkx.utils import nx - with pytest.raises(ImportError): - from networkx.utils import sys - with pytest.raises(ImportError): - from networkx.utils import defaultdict, deque diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_backends.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_backends.py deleted file mode 100644 index ad006f0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_backends.py +++ /dev/null @@ -1,170 +0,0 @@ -import pickle - -import pytest - -import networkx as nx - -sp = pytest.importorskip("scipy") -pytest.importorskip("numpy") - - -def test_dispatch_kwds_vs_args(): - G = nx.path_graph(4) - nx.pagerank(G) - nx.pagerank(G=G) - with pytest.raises(TypeError): - nx.pagerank() - - -def test_pickle(): - count = 0 - for name, func in nx.utils.backends._registered_algorithms.items(): - pickled = pickle.dumps(func.__wrapped__) - assert pickle.loads(pickled) is func.__wrapped__ - try: - # Some functions can't be pickled, but it's not b/c of _dispatchable - pickled = pickle.dumps(func) - except pickle.PicklingError: - continue - assert pickle.loads(pickled) is func - count += 1 - assert count > 0 - assert pickle.loads(pickle.dumps(nx.inverse_line_graph)) is nx.inverse_line_graph - - -@pytest.mark.skipif( - "not nx.config.backend_priority.algos " - "or nx.config.backend_priority.algos[0] != 'nx_loopback'" -) -def test_graph_converter_needs_backend(): - # When testing, `nx.from_scipy_sparse_array` will *always* call the backend - # implementation if it's implemented. If `backend=` isn't given, then the result - # will be converted back to NetworkX via `convert_to_nx`. - # If not testing, then calling `nx.from_scipy_sparse_array` w/o `backend=` will - # always call the original version. `backend=` is *required* to call the backend. - from networkx.classes.tests.dispatch_interface import ( - LoopbackBackendInterface, - LoopbackGraph, - ) - - A = sp.sparse.coo_array([[0, 3, 2], [3, 0, 1], [2, 1, 0]]) - - side_effects = [] - - def from_scipy_sparse_array(self, *args, **kwargs): - side_effects.append(1) # Just to prove this was called - return self.convert_from_nx( - self.__getattr__("from_scipy_sparse_array")(*args, **kwargs), - preserve_edge_attrs=True, - preserve_node_attrs=True, - preserve_graph_attrs=True, - ) - - @staticmethod - def convert_to_nx(obj, *, name=None): - if type(obj) is nx.Graph: - return obj - return nx.Graph(obj) - - # *This mutates LoopbackBackendInterface!* - orig_convert_to_nx = LoopbackBackendInterface.convert_to_nx - LoopbackBackendInterface.convert_to_nx = convert_to_nx - LoopbackBackendInterface.from_scipy_sparse_array = from_scipy_sparse_array - - try: - assert side_effects == [] - assert type(nx.from_scipy_sparse_array(A)) is nx.Graph - assert side_effects == [1] - assert ( - type(nx.from_scipy_sparse_array(A, backend="nx_loopback")) is LoopbackGraph - ) - assert side_effects == [1, 1] - # backend="networkx" is default implementation - assert type(nx.from_scipy_sparse_array(A, backend="networkx")) is nx.Graph - assert side_effects == [1, 1] - finally: - LoopbackBackendInterface.convert_to_nx = staticmethod(orig_convert_to_nx) - del LoopbackBackendInterface.from_scipy_sparse_array - with pytest.raises(ImportError, match="backend is not installed"): - nx.from_scipy_sparse_array(A, backend="bad-backend-name") - - -@pytest.mark.skipif( - "not nx.config.backend_priority.algos " - "or nx.config.backend_priority.algos[0] != 'nx_loopback'" -) -def test_networkx_backend(): - """Test using `backend="networkx"` in a dispatchable function.""" - # (Implementing this test is harder than it should be) - from networkx.classes.tests.dispatch_interface import ( - LoopbackBackendInterface, - LoopbackGraph, - ) - - G = LoopbackGraph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4)]) - - @staticmethod - def convert_to_nx(obj, *, name=None): - if isinstance(obj, LoopbackGraph): - new_graph = nx.Graph() - new_graph.__dict__.update(obj.__dict__) - return new_graph - return obj - - # *This mutates LoopbackBackendInterface!* - # This uses the same trick as in the previous test. - orig_convert_to_nx = LoopbackBackendInterface.convert_to_nx - LoopbackBackendInterface.convert_to_nx = convert_to_nx - try: - G2 = nx.ego_graph(G, 0, backend="networkx") - assert type(G2) is nx.Graph - finally: - LoopbackBackendInterface.convert_to_nx = staticmethod(orig_convert_to_nx) - - -def test_dispatchable_are_functions(): - assert type(nx.pagerank) is type(nx.pagerank.orig_func) - - -@pytest.mark.skipif("not nx.utils.backends.backends") -def test_mixing_backend_graphs(): - from networkx.classes.tests import dispatch_interface - - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(2, 3) - H = nx.Graph() - H.add_edge(2, 3) - rv = nx.intersection(G, H) - assert set(nx.intersection(G, H)) == {2, 3} - G2 = dispatch_interface.convert(G) - H2 = dispatch_interface.convert(H) - if "nx_loopback" in nx.config.backend_priority: - # Auto-convert - assert set(nx.intersection(G2, H)) == {2, 3} - assert set(nx.intersection(G, H2)) == {2, 3} - elif not nx.config.backend_priority and "nx_loopback" not in nx.config.backends: - # G2 and H2 are backend objects for a backend that is not registered! - with pytest.raises(ImportError, match="backend is not installed"): - nx.intersection(G2, H) - with pytest.raises(ImportError, match="backend is not installed"): - nx.intersection(G, H2) - # It would be nice to test passing graphs from *different* backends, - # but we are not set up to do this yet. - - -def test_bad_backend_name(): - """Using `backend=` raises with unknown backend even if there are no backends.""" - with pytest.raises( - ImportError, match="'this_backend_does_not_exist' backend is not installed" - ): - nx.null_graph(backend="this_backend_does_not_exist") - - -def test_fallback_to_nx(): - with pytest.warns(DeprecationWarning, match="_fallback_to_nx"): - # Check as class property - assert nx._dispatchable._fallback_to_nx == nx.config.fallback_to_nx - # Check as instance property - assert nx.pagerank.__wrapped__._fallback_to_nx == nx.config.fallback_to_nx diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_config.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_config.py deleted file mode 100644 index 7416b0a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_config.py +++ /dev/null @@ -1,231 +0,0 @@ -import collections -import pickle - -import pytest - -import networkx as nx -from networkx.utils.configs import BackendPriorities, Config - - -# Define this at module level so we can test pickling -class ExampleConfig(Config): - """Example configuration.""" - - x: int - y: str - - def _on_setattr(self, key, value): - if key == "x" and value <= 0: - raise ValueError("x must be positive") - if key == "y" and not isinstance(value, str): - raise TypeError("y must be a str") - return value - - -class EmptyConfig(Config): - pass - - -@pytest.mark.parametrize("cfg", [EmptyConfig(), Config()]) -def test_config_empty(cfg): - assert dir(cfg) == [] - with pytest.raises(AttributeError): - cfg.x = 1 - with pytest.raises(KeyError): - cfg["x"] = 1 - with pytest.raises(AttributeError): - cfg.x - with pytest.raises(KeyError): - cfg["x"] - assert len(cfg) == 0 - assert "x" not in cfg - assert cfg == cfg - assert cfg.get("x", 2) == 2 - assert set(cfg.keys()) == set() - assert set(cfg.values()) == set() - assert set(cfg.items()) == set() - cfg2 = pickle.loads(pickle.dumps(cfg)) - assert cfg == cfg2 - assert isinstance(cfg, collections.abc.Collection) - assert isinstance(cfg, collections.abc.Mapping) - - -def test_config_subclass(): - with pytest.raises(TypeError, match="missing 2 required keyword-only"): - ExampleConfig() - with pytest.raises(ValueError, match="x must be positive"): - ExampleConfig(x=0, y="foo") - with pytest.raises(TypeError, match="unexpected keyword"): - ExampleConfig(x=1, y="foo", z="bad config") - with pytest.raises(TypeError, match="unexpected keyword"): - EmptyConfig(z="bad config") - cfg = ExampleConfig(x=1, y="foo") - assert cfg.x == 1 - assert cfg["x"] == 1 - assert cfg["y"] == "foo" - assert cfg.y == "foo" - assert "x" in cfg - assert "y" in cfg - assert "z" not in cfg - assert len(cfg) == 2 - assert set(iter(cfg)) == {"x", "y"} - assert set(cfg.keys()) == {"x", "y"} - assert set(cfg.values()) == {1, "foo"} - assert set(cfg.items()) == {("x", 1), ("y", "foo")} - assert dir(cfg) == ["x", "y"] - cfg.x = 2 - cfg["y"] = "bar" - assert cfg["x"] == 2 - assert cfg.y == "bar" - with pytest.raises(TypeError, match="can't be deleted"): - del cfg.x - with pytest.raises(TypeError, match="can't be deleted"): - del cfg["y"] - assert cfg.x == 2 - assert cfg == cfg - assert cfg == ExampleConfig(x=2, y="bar") - assert cfg != ExampleConfig(x=3, y="baz") - assert cfg != Config(x=2, y="bar") - with pytest.raises(TypeError, match="y must be a str"): - cfg["y"] = 5 - with pytest.raises(ValueError, match="x must be positive"): - cfg.x = -5 - assert cfg.get("x", 10) == 2 - with pytest.raises(AttributeError): - cfg.z = 5 - with pytest.raises(KeyError): - cfg["z"] = 5 - with pytest.raises(AttributeError): - cfg.z - with pytest.raises(KeyError): - cfg["z"] - cfg2 = pickle.loads(pickle.dumps(cfg)) - assert cfg == cfg2 - assert cfg.__doc__ == "Example configuration." - assert cfg2.__doc__ == "Example configuration." - - -def test_config_defaults(): - class DefaultConfig(Config): - x: int = 0 - y: int - - cfg = DefaultConfig(y=1) - assert cfg.x == 0 - cfg = DefaultConfig(x=2, y=1) - assert cfg.x == 2 - - -def test_nxconfig(): - assert isinstance(nx.config.backend_priority, BackendPriorities) - assert isinstance(nx.config.backend_priority.algos, list) - assert isinstance(nx.config.backends, Config) - with pytest.raises(TypeError, match="must be a list of backend names"): - nx.config.backend_priority.algos = "nx_loopback" - with pytest.raises(ValueError, match="Unknown backend when setting"): - nx.config.backend_priority.algos = ["this_almost_certainly_is_not_a_backend"] - with pytest.raises(TypeError, match="must be a Config of backend configs"): - nx.config.backends = {} - with pytest.raises(TypeError, match="must be a Config of backend configs"): - nx.config.backends = Config(plausible_backend_name={}) - with pytest.raises(ValueError, match="Unknown backend when setting"): - nx.config.backends = Config(this_almost_certainly_is_not_a_backend=Config()) - with pytest.raises(TypeError, match="must be True or False"): - nx.config.cache_converted_graphs = "bad value" - with pytest.raises(TypeError, match="must be a set of "): - nx.config.warnings_to_ignore = 7 - with pytest.raises(ValueError, match="Unknown warning "): - nx.config.warnings_to_ignore = {"bad value"} - - -def test_not_strict(): - class FlexibleConfig(Config, strict=False): - x: int - - cfg = FlexibleConfig(x=1) - assert "_strict" not in cfg - assert len(cfg) == 1 - assert list(cfg) == ["x"] - assert list(cfg.keys()) == ["x"] - assert list(cfg.values()) == [1] - assert list(cfg.items()) == [("x", 1)] - assert cfg.x == 1 - assert cfg["x"] == 1 - assert "x" in cfg - assert hasattr(cfg, "x") - assert "FlexibleConfig(x=1)" in repr(cfg) - assert cfg == FlexibleConfig(x=1) - del cfg.x - assert "FlexibleConfig()" in repr(cfg) - assert len(cfg) == 0 - assert not hasattr(cfg, "x") - assert "x" not in cfg - assert not hasattr(cfg, "y") - assert "y" not in cfg - cfg.y = 2 - assert len(cfg) == 1 - assert list(cfg) == ["y"] - assert list(cfg.keys()) == ["y"] - assert list(cfg.values()) == [2] - assert list(cfg.items()) == [("y", 2)] - assert cfg.y == 2 - assert cfg["y"] == 2 - assert hasattr(cfg, "y") - assert "y" in cfg - del cfg["y"] - assert len(cfg) == 0 - assert list(cfg) == [] - with pytest.raises(AttributeError, match="y"): - del cfg.y - with pytest.raises(KeyError, match="y"): - del cfg["y"] - with pytest.raises(TypeError, match="missing 1 required keyword-only"): - FlexibleConfig() - # Be strict when first creating the config object - with pytest.raises(TypeError, match="unexpected keyword argument 'y'"): - FlexibleConfig(x=1, y=2) - - class FlexibleConfigWithDefault(Config, strict=False): - x: int = 0 - - assert FlexibleConfigWithDefault().x == 0 - assert FlexibleConfigWithDefault(x=1)["x"] == 1 - - -def test_context(): - cfg = Config(x=1) - with cfg(x=2) as c: - assert c.x == 2 - c.x = 3 - assert cfg.x == 3 - assert cfg.x == 1 - - with cfg(x=2) as c: - assert c == cfg - assert cfg.x == 2 - with cfg(x=3) as c2: - assert c2 == cfg - assert cfg.x == 3 - with pytest.raises(RuntimeError, match="context manager without"): - with cfg as c3: # Forgot to call `cfg(...)` - pass - assert cfg.x == 3 - assert cfg.x == 2 - assert cfg.x == 1 - - c = cfg(x=4) # Not yet as context (not recommended, but possible) - assert c == cfg - assert cfg.x == 4 - # Cheat by looking at internal data; context stack should only grow with __enter__ - assert cfg._prev is not None - assert cfg._context_stack == [] - with c: - assert c == cfg - assert cfg.x == 4 - assert cfg.x == 1 - # Cheat again; there was no preceding `cfg(...)` call this time - assert cfg._prev is None - with pytest.raises(RuntimeError, match="context manager without"): - with cfg: - pass - assert cfg.x == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_decorators.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_decorators.py deleted file mode 100644 index 0a4aeab..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_decorators.py +++ /dev/null @@ -1,510 +0,0 @@ -import os -import pathlib -import random -import tempfile - -import pytest - -import networkx as nx -from networkx.utils.decorators import ( - argmap, - not_implemented_for, - np_random_state, - open_file, - py_random_state, -) -from networkx.utils.misc import PythonRandomInterface, PythonRandomViaNumpyBits - - -def test_not_implemented_decorator(): - @not_implemented_for("directed") - def test_d(G): - pass - - test_d(nx.Graph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_d(nx.DiGraph()) - - @not_implemented_for("undirected") - def test_u(G): - pass - - test_u(nx.DiGraph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_u(nx.Graph()) - - @not_implemented_for("multigraph") - def test_m(G): - pass - - test_m(nx.Graph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_m(nx.MultiGraph()) - - @not_implemented_for("graph") - def test_g(G): - pass - - test_g(nx.MultiGraph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_g(nx.Graph()) - - # not MultiDiGraph (multiple arguments => AND) - @not_implemented_for("directed", "multigraph") - def test_not_md(G): - pass - - test_not_md(nx.Graph()) - test_not_md(nx.DiGraph()) - test_not_md(nx.MultiGraph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_not_md(nx.MultiDiGraph()) - - # Graph only (multiple decorators => OR) - @not_implemented_for("directed") - @not_implemented_for("multigraph") - def test_graph_only(G): - pass - - test_graph_only(nx.Graph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_graph_only(nx.DiGraph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_graph_only(nx.MultiGraph()) - with pytest.raises(nx.NetworkXNotImplemented): - test_graph_only(nx.MultiDiGraph()) - - with pytest.raises(ValueError): - not_implemented_for("directed", "undirected") - - with pytest.raises(ValueError): - not_implemented_for("multigraph", "graph") - - -def test_not_implemented_decorator_key(): - with pytest.raises(KeyError): - - @not_implemented_for("foo") - def test1(G): - pass - - test1(nx.Graph()) - - -def test_not_implemented_decorator_raise(): - with pytest.raises(nx.NetworkXNotImplemented): - - @not_implemented_for("graph") - def test1(G): - pass - - test1(nx.Graph()) - - -class TestOpenFileDecorator: - def setup_method(self): - self.text = ["Blah... ", "BLAH ", "BLAH!!!!"] - self.fobj = tempfile.NamedTemporaryFile("wb+", delete=False) - self.name = self.fobj.name - - def teardown_method(self): - self.fobj.close() - os.unlink(self.name) - - def write(self, path): - for text in self.text: - path.write(text.encode("ascii")) - - @open_file(1, "r") - def read(self, path): - return path.readlines()[0] - - @staticmethod - @open_file(0, "wb") - def writer_arg0(path): - path.write(b"demo") - - @open_file(1, "wb+") - def writer_arg1(self, path): - self.write(path) - - @open_file(2, "wb") - def writer_arg2default(self, x, path=None): - if path is None: - with tempfile.NamedTemporaryFile("wb+") as fh: - self.write(fh) - else: - self.write(path) - - @open_file(4, "wb") - def writer_arg4default(self, x, y, other="hello", path=None, **kwargs): - if path is None: - with tempfile.NamedTemporaryFile("wb+") as fh: - self.write(fh) - else: - self.write(path) - - @open_file("path", "wb") - def writer_kwarg(self, **kwargs): - path = kwargs.get("path", None) - if path is None: - with tempfile.NamedTemporaryFile("wb+") as fh: - self.write(fh) - else: - self.write(path) - - def test_writer_arg0_str(self): - self.writer_arg0(self.name) - - def test_writer_arg0_fobj(self): - self.writer_arg0(self.fobj) - - def test_writer_arg0_pathlib(self): - self.writer_arg0(pathlib.Path(self.name)) - - def test_writer_arg1_str(self): - self.writer_arg1(self.name) - assert self.read(self.name) == "".join(self.text) - - def test_writer_arg1_fobj(self): - self.writer_arg1(self.fobj) - assert not self.fobj.closed - self.fobj.close() - assert self.read(self.name) == "".join(self.text) - - def test_writer_arg2default_str(self): - self.writer_arg2default(0, path=None) - self.writer_arg2default(0, path=self.name) - assert self.read(self.name) == "".join(self.text) - - def test_writer_arg2default_fobj(self): - self.writer_arg2default(0, path=self.fobj) - assert not self.fobj.closed - self.fobj.close() - assert self.read(self.name) == "".join(self.text) - - def test_writer_arg2default_fobj_path_none(self): - self.writer_arg2default(0, path=None) - - def test_writer_arg4default_fobj(self): - self.writer_arg4default(0, 1, dog="dog", other="other") - self.writer_arg4default(0, 1, dog="dog", other="other", path=self.name) - assert self.read(self.name) == "".join(self.text) - - def test_writer_kwarg_str(self): - self.writer_kwarg(path=self.name) - assert self.read(self.name) == "".join(self.text) - - def test_writer_kwarg_fobj(self): - self.writer_kwarg(path=self.fobj) - self.fobj.close() - assert self.read(self.name) == "".join(self.text) - - def test_writer_kwarg_path_none(self): - self.writer_kwarg(path=None) - - -class TestRandomState: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - - @np_random_state(1) - def instantiate_np_random_state(self, random_state): - allowed = (np.random.RandomState, np.random.Generator) - assert isinstance(random_state, allowed) - return random_state.random() - - @py_random_state(1) - def instantiate_py_random_state(self, random_state): - allowed = (random.Random, PythonRandomInterface, PythonRandomViaNumpyBits) - assert isinstance(random_state, allowed) - return random_state.random() - - def test_random_state_None(self): - np.random.seed(42) - rv = np.random.random() - np.random.seed(42) - assert rv == self.instantiate_np_random_state(None) - - random.seed(42) - rv = random.random() - random.seed(42) - assert rv == self.instantiate_py_random_state(None) - - def test_random_state_np_random(self): - np.random.seed(42) - rv = np.random.random() - np.random.seed(42) - assert rv == self.instantiate_np_random_state(np.random) - np.random.seed(42) - assert rv == self.instantiate_py_random_state(np.random) - - def test_random_state_int(self): - np.random.seed(42) - np_rv = np.random.random() - random.seed(42) - py_rv = random.random() - - np.random.seed(42) - seed = 1 - rval = self.instantiate_np_random_state(seed) - rval_expected = np.random.RandomState(seed).rand() - assert rval == rval_expected - # test that global seed wasn't changed in function - assert np_rv == np.random.random() - - random.seed(42) - rval = self.instantiate_py_random_state(seed) - rval_expected = random.Random(seed).random() - assert rval == rval_expected - # test that global seed wasn't changed in function - assert py_rv == random.random() - - def test_random_state_np_random_Generator(self): - np.random.seed(42) - np_rv = np.random.random() - np.random.seed(42) - seed = 1 - - rng = np.random.default_rng(seed) - rval = self.instantiate_np_random_state(rng) - rval_expected = np.random.default_rng(seed).random() - assert rval == rval_expected - - rval = self.instantiate_py_random_state(rng) - rval_expected = np.random.default_rng(seed).random(size=2)[1] - assert rval == rval_expected - # test that global seed wasn't changed in function - assert np_rv == np.random.random() - - def test_random_state_np_random_RandomState(self): - np.random.seed(42) - np_rv = np.random.random() - np.random.seed(42) - seed = 1 - - rng = np.random.RandomState(seed) - rval = self.instantiate_np_random_state(rng) - rval_expected = np.random.RandomState(seed).random() - assert rval == rval_expected - - rval = self.instantiate_py_random_state(rng) - rval_expected = np.random.RandomState(seed).random(size=2)[1] - assert rval == rval_expected - # test that global seed wasn't changed in function - assert np_rv == np.random.random() - - def test_random_state_py_random(self): - seed = 1 - rng = random.Random(seed) - rv = self.instantiate_py_random_state(rng) - assert rv == random.Random(seed).random() - - pytest.raises(ValueError, self.instantiate_np_random_state, rng) - - -def test_random_state_string_arg_index(): - with pytest.raises(nx.NetworkXError): - - @np_random_state("a") - def make_random_state(rs): - pass - - rstate = make_random_state(1) - - -def test_py_random_state_string_arg_index(): - with pytest.raises(nx.NetworkXError): - - @py_random_state("a") - def make_random_state(rs): - pass - - rstate = make_random_state(1) - - -def test_random_state_invalid_arg_index(): - with pytest.raises(nx.NetworkXError): - - @np_random_state(2) - def make_random_state(rs): - pass - - rstate = make_random_state(1) - - -def test_py_random_state_invalid_arg_index(): - with pytest.raises(nx.NetworkXError): - - @py_random_state(2) - def make_random_state(rs): - pass - - rstate = make_random_state(1) - - -class TestArgmap: - class ArgmapError(RuntimeError): - pass - - def test_trivial_function(self): - def do_not_call(x): - raise ArgmapError("do not call this function") - - @argmap(do_not_call) - def trivial_argmap(): - return 1 - - assert trivial_argmap() == 1 - - def test_trivial_iterator(self): - def do_not_call(x): - raise ArgmapError("do not call this function") - - @argmap(do_not_call) - def trivial_argmap(): - yield from (1, 2, 3) - - assert tuple(trivial_argmap()) == (1, 2, 3) - - def test_contextmanager(self): - container = [] - - def contextmanager(x): - nonlocal container - return x, lambda: container.append(x) - - @argmap(contextmanager, 0, 1, 2, try_finally=True) - def foo(x, y, z): - return x, y, z - - x, y, z = foo("a", "b", "c") - - # context exits are called in reverse - assert container == ["c", "b", "a"] - - def test_tryfinally_generator(self): - container = [] - - def singleton(x): - return (x,) - - with pytest.raises(nx.NetworkXError): - - @argmap(singleton, 0, 1, 2, try_finally=True) - def foo(x, y, z): - yield from (x, y, z) - - @argmap(singleton, 0, 1, 2) - def foo(x, y, z): - return x + y + z - - q = foo("a", "b", "c") - - assert q == ("a", "b", "c") - - def test_actual_vararg(self): - @argmap(lambda x: -x, 4) - def foo(x, y, *args): - return (x, y) + tuple(args) - - assert foo(1, 2, 3, 4, 5, 6) == (1, 2, 3, 4, -5, 6) - - def test_signature_destroying_intermediate_decorator(self): - def add_one_to_first_bad_decorator(f): - """Bad because it doesn't wrap the f signature (clobbers it)""" - - def decorated(a, *args, **kwargs): - return f(a + 1, *args, **kwargs) - - return decorated - - add_two_to_second = argmap(lambda b: b + 2, 1) - - @add_two_to_second - @add_one_to_first_bad_decorator - def add_one_and_two(a, b): - return a, b - - assert add_one_and_two(5, 5) == (6, 7) - - def test_actual_kwarg(self): - @argmap(lambda x: -x, "arg") - def foo(*, arg): - return arg - - assert foo(arg=3) == -3 - - def test_nested_tuple(self): - def xform(x, y): - u, v = y - return x + u + v, (x + u, x + v) - - # we're testing args and kwargs here, too - @argmap(xform, (0, ("t", 2))) - def foo(a, *args, **kwargs): - return a, args, kwargs - - a, args, kwargs = foo(1, 2, 3, t=4) - - assert a == 1 + 4 + 3 - assert args == (2, 1 + 3) - assert kwargs == {"t": 1 + 4} - - def test_flatten(self): - assert tuple(argmap._flatten([[[[[], []], [], []], [], [], []]], set())) == () - - rlist = ["a", ["b", "c"], [["d"], "e"], "f"] - assert "".join(argmap._flatten(rlist, set())) == "abcdef" - - def test_indent(self): - code = "\n".join( - argmap._indent( - *[ - "try:", - "try:", - "pass#", - "finally:", - "pass#", - "#", - "finally:", - "pass#", - ] - ) - ) - assert ( - code - == """try: - try: - pass# - finally: - pass# - # -finally: - pass#""" - ) - - def test_immediate_raise(self): - @not_implemented_for("directed") - def yield_nodes(G): - yield from G - - G = nx.Graph([(1, 2)]) - D = nx.DiGraph() - - # test first call (argmap is compiled and executed) - with pytest.raises(nx.NetworkXNotImplemented): - node_iter = yield_nodes(D) - - # test second call (argmap is only executed) - with pytest.raises(nx.NetworkXNotImplemented): - node_iter = yield_nodes(D) - - # ensure that generators still make generators - node_iter = yield_nodes(G) - next(node_iter) - next(node_iter) - with pytest.raises(StopIteration): - next(node_iter) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_heaps.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_heaps.py deleted file mode 100644 index 5ea3871..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_heaps.py +++ /dev/null @@ -1,131 +0,0 @@ -import pytest - -import networkx as nx -from networkx.utils import BinaryHeap, PairingHeap - - -class X: - def __eq__(self, other): - raise self is other - - def __ne__(self, other): - raise self is not other - - def __lt__(self, other): - raise TypeError("cannot compare") - - def __le__(self, other): - raise TypeError("cannot compare") - - def __ge__(self, other): - raise TypeError("cannot compare") - - def __gt__(self, other): - raise TypeError("cannot compare") - - def __hash__(self): - return hash(id(self)) - - -x = X() - - -data = [ # min should not invent an element. - ("min", nx.NetworkXError), - # Popping an empty heap should fail. - ("pop", nx.NetworkXError), - # Getting nonexisting elements should return None. - ("get", 0, None), - ("get", x, None), - ("get", None, None), - # Inserting a new key should succeed. - ("insert", x, 1, True), - ("get", x, 1), - ("min", (x, 1)), - # min should not pop the top element. - ("min", (x, 1)), - # Inserting a new key of different type should succeed. - ("insert", 1, -2.0, True), - # int and float values should interop. - ("min", (1, -2.0)), - # pop removes minimum-valued element. - ("insert", 3, -(10**100), True), - ("insert", 4, 5, True), - ("pop", (3, -(10**100))), - ("pop", (1, -2.0)), - # Decrease-insert should succeed. - ("insert", 4, -50, True), - ("insert", 4, -60, False, True), - # Decrease-insert should not create duplicate keys. - ("pop", (4, -60)), - ("pop", (x, 1)), - # Popping all elements should empty the heap. - ("min", nx.NetworkXError), - ("pop", nx.NetworkXError), - # Non-value-changing insert should fail. - ("insert", x, 0, True), - ("insert", x, 0, False, False), - ("min", (x, 0)), - ("insert", x, 0, True, False), - ("min", (x, 0)), - # Failed insert should not create duplicate keys. - ("pop", (x, 0)), - ("pop", nx.NetworkXError), - # Increase-insert should succeed when allowed. - ("insert", None, 0, True), - ("insert", 2, -1, True), - ("min", (2, -1)), - ("insert", 2, 1, True, False), - ("min", (None, 0)), - # Increase-insert should fail when disallowed. - ("insert", None, 2, False, False), - ("min", (None, 0)), - # Failed increase-insert should not create duplicate keys. - ("pop", (None, 0)), - ("pop", (2, 1)), - ("min", nx.NetworkXError), - ("pop", nx.NetworkXError), -] - - -def _test_heap_class(cls, *args, **kwargs): - heap = cls(*args, **kwargs) - # Basic behavioral test - for op in data: - if op[-1] is not nx.NetworkXError: - assert op[-1] == getattr(heap, op[0])(*op[1:-1]) - else: - pytest.raises(op[-1], getattr(heap, op[0]), *op[1:-1]) - # Coverage test. - for i in range(99, -1, -1): - assert heap.insert(i, i) - for i in range(50): - assert heap.pop() == (i, i) - for i in range(100): - assert heap.insert(i, i) == (i < 50) - for i in range(100): - assert not heap.insert(i, i + 1) - for i in range(50): - assert heap.pop() == (i, i) - for i in range(100): - assert heap.insert(i, i + 1) == (i < 50) - for i in range(49): - assert heap.pop() == (i, i + 1) - assert sorted([heap.pop(), heap.pop()]) == [(49, 50), (50, 50)] - for i in range(51, 100): - assert not heap.insert(i, i + 1, True) - for i in range(51, 70): - assert heap.pop() == (i, i + 1) - for i in range(100): - assert heap.insert(i, i) - for i in range(100): - assert heap.pop() == (i, i) - pytest.raises(nx.NetworkXError, heap.pop) - - -def test_PairingHeap(): - _test_heap_class(PairingHeap) - - -def test_BinaryHeap(): - _test_heap_class(BinaryHeap) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_mapped_queue.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_mapped_queue.py deleted file mode 100644 index ca9b7e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_mapped_queue.py +++ /dev/null @@ -1,268 +0,0 @@ -import pytest - -from networkx.utils.mapped_queue import MappedQueue, _HeapElement - - -def test_HeapElement_gtlt(): - bar = _HeapElement(1.1, "a") - foo = _HeapElement(1, "b") - assert foo < bar - assert bar > foo - assert foo < 1.1 - assert 1 < bar - - -def test_HeapElement_gtlt_tied_priority(): - bar = _HeapElement(1, "a") - foo = _HeapElement(1, "b") - assert foo > bar - assert bar < foo - - -def test_HeapElement_eq(): - bar = _HeapElement(1.1, "a") - foo = _HeapElement(1, "a") - assert foo == bar - assert bar == foo - assert foo == "a" - - -def test_HeapElement_iter(): - foo = _HeapElement(1, "a") - bar = _HeapElement(1.1, (3, 2, 1)) - assert list(foo) == [1, "a"] - assert list(bar) == [1.1, 3, 2, 1] - - -def test_HeapElement_getitem(): - foo = _HeapElement(1, "a") - bar = _HeapElement(1.1, (3, 2, 1)) - assert foo[1] == "a" - assert foo[0] == 1 - assert bar[0] == 1.1 - assert bar[2] == 2 - assert bar[3] == 1 - pytest.raises(IndexError, bar.__getitem__, 4) - pytest.raises(IndexError, foo.__getitem__, 2) - - -class TestMappedQueue: - def setup_method(self): - pass - - def _check_map(self, q): - assert q.position == {elt: pos for pos, elt in enumerate(q.heap)} - - def _make_mapped_queue(self, h): - q = MappedQueue() - q.heap = h - q.position = {elt: pos for pos, elt in enumerate(h)} - return q - - def test_heapify(self): - h = [5, 4, 3, 2, 1, 0] - q = self._make_mapped_queue(h) - q._heapify() - self._check_map(q) - - def test_init(self): - h = [5, 4, 3, 2, 1, 0] - q = MappedQueue(h) - self._check_map(q) - - def test_incomparable(self): - h = [5, 4, "a", 2, 1, 0] - pytest.raises(TypeError, MappedQueue, h) - - def test_len(self): - h = [5, 4, 3, 2, 1, 0] - q = MappedQueue(h) - self._check_map(q) - assert len(q) == 6 - - def test_siftup_leaf(self): - h = [2] - h_sifted = [2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftup_one_child(self): - h = [2, 0] - h_sifted = [0, 2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftup_left_child(self): - h = [2, 0, 1] - h_sifted = [0, 2, 1] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftup_right_child(self): - h = [2, 1, 0] - h_sifted = [0, 1, 2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftup_multiple(self): - h = [0, 1, 2, 4, 3, 5, 6] - h_sifted = [0, 1, 2, 4, 3, 5, 6] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftdown_leaf(self): - h = [2] - h_sifted = [2] - q = self._make_mapped_queue(h) - q._siftdown(0, 0) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftdown_single(self): - h = [1, 0] - h_sifted = [0, 1] - q = self._make_mapped_queue(h) - q._siftdown(0, len(h) - 1) - assert q.heap == h_sifted - self._check_map(q) - - def test_siftdown_multiple(self): - h = [1, 2, 3, 4, 5, 6, 7, 0] - h_sifted = [0, 1, 3, 2, 5, 6, 7, 4] - q = self._make_mapped_queue(h) - q._siftdown(0, len(h) - 1) - assert q.heap == h_sifted - self._check_map(q) - - def test_push(self): - to_push = [6, 1, 4, 3, 2, 5, 0] - h_sifted = [0, 2, 1, 6, 3, 5, 4] - q = MappedQueue() - for elt in to_push: - q.push(elt) - assert q.heap == h_sifted - self._check_map(q) - - def test_push_duplicate(self): - to_push = [2, 1, 0] - h_sifted = [0, 2, 1] - q = MappedQueue() - for elt in to_push: - inserted = q.push(elt) - assert inserted - assert q.heap == h_sifted - self._check_map(q) - inserted = q.push(1) - assert not inserted - - def test_pop(self): - h = [3, 4, 6, 0, 1, 2, 5] - h_sorted = sorted(h) - q = self._make_mapped_queue(h) - q._heapify() - popped = [q.pop() for _ in range(len(h))] - assert popped == h_sorted - self._check_map(q) - - def test_remove_leaf(self): - h = [0, 2, 1, 6, 3, 5, 4] - h_removed = [0, 2, 1, 6, 4, 5] - q = self._make_mapped_queue(h) - removed = q.remove(3) - assert q.heap == h_removed - - def test_remove_root(self): - h = [0, 2, 1, 6, 3, 5, 4] - h_removed = [1, 2, 4, 6, 3, 5] - q = self._make_mapped_queue(h) - removed = q.remove(0) - assert q.heap == h_removed - - def test_update_leaf(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [0, 15, 10, 60, 20, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(30, 15) - assert q.heap == h_updated - - def test_update_root(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [10, 20, 35, 60, 30, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(0, 35) - assert q.heap == h_updated - - -class TestMappedDict(TestMappedQueue): - def _make_mapped_queue(self, h): - priority_dict = {elt: elt for elt in h} - return MappedQueue(priority_dict) - - def test_init(self): - d = {5: 0, 4: 1, "a": 2, 2: 3, 1: 4} - q = MappedQueue(d) - assert q.position == d - - def test_ties(self): - d = {5: 0, 4: 1, 3: 2, 2: 3, 1: 4} - q = MappedQueue(d) - assert q.position == {elt: pos for pos, elt in enumerate(q.heap)} - - def test_pop(self): - d = {5: 0, 4: 1, 3: 2, 2: 3, 1: 4} - q = MappedQueue(d) - assert q.pop() == _HeapElement(0, 5) - assert q.position == {elt: pos for pos, elt in enumerate(q.heap)} - - def test_empty_pop(self): - q = MappedQueue() - pytest.raises(IndexError, q.pop) - - def test_incomparable_ties(self): - d = {5: 0, 4: 0, "a": 0, 2: 0, 1: 0} - pytest.raises(TypeError, MappedQueue, d) - - def test_push(self): - to_push = [6, 1, 4, 3, 2, 5, 0] - h_sifted = [0, 2, 1, 6, 3, 5, 4] - q = MappedQueue() - for elt in to_push: - q.push(elt, priority=elt) - assert q.heap == h_sifted - self._check_map(q) - - def test_push_duplicate(self): - to_push = [2, 1, 0] - h_sifted = [0, 2, 1] - q = MappedQueue() - for elt in to_push: - inserted = q.push(elt, priority=elt) - assert inserted - assert q.heap == h_sifted - self._check_map(q) - inserted = q.push(1, priority=1) - assert not inserted - - def test_update_leaf(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [0, 15, 10, 60, 20, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(30, 15, priority=15) - assert q.heap == h_updated - - def test_update_root(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [10, 20, 35, 60, 30, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(0, 35, priority=35) - assert q.heap == h_updated diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_misc.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_misc.py deleted file mode 100644 index eff36b2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_misc.py +++ /dev/null @@ -1,268 +0,0 @@ -import random -from copy import copy - -import pytest - -import networkx as nx -from networkx.utils import ( - PythonRandomInterface, - PythonRandomViaNumpyBits, - arbitrary_element, - create_py_random_state, - create_random_state, - dict_to_numpy_array, - discrete_sequence, - flatten, - groups, - make_list_of_ints, - pairwise, - powerlaw_sequence, -) -from networkx.utils.misc import _dict_to_numpy_array1, _dict_to_numpy_array2 - -nested_depth = ( - 1, - 2, - (3, 4, ((5, 6, (7,), (8, (9, 10), 11), (12, 13, (14, 15)), 16), 17), 18, 19), - 20, -) - -nested_set = { - (1, 2, 3, 4), - (5, 6, 7, 8, 9), - (10, 11, (12, 13, 14), (15, 16, 17, 18)), - 19, - 20, -} - -nested_mixed = [ - 1, - (2, 3, {4, (5, 6), 7}, [8, 9]), - {10: "foo", 11: "bar", (12, 13): "baz"}, - {(14, 15): "qwe", 16: "asd"}, - (17, (18, "19"), 20), -] - - -@pytest.mark.parametrize("result", [None, [], ["existing"], ["existing1", "existing2"]]) -@pytest.mark.parametrize("nested", [nested_depth, nested_mixed, nested_set]) -def test_flatten(nested, result): - if result is None: - val = flatten(nested, result) - assert len(val) == 20 - else: - _result = copy(result) # because pytest passes parameters as is - nexisting = len(_result) - val = flatten(nested, _result) - assert len(val) == len(_result) == 20 + nexisting - - assert issubclass(type(val), tuple) - - -def test_make_list_of_ints(): - mylist = [1, 2, 3.0, 42, -2] - assert make_list_of_ints(mylist) is mylist - assert make_list_of_ints(mylist) == mylist - assert type(make_list_of_ints(mylist)[2]) is int - pytest.raises(nx.NetworkXError, make_list_of_ints, [1, 2, 3, "kermit"]) - pytest.raises(nx.NetworkXError, make_list_of_ints, [1, 2, 3.1]) - - -def test_random_number_distribution(): - # smoke test only - z = powerlaw_sequence(20, exponent=2.5) - z = discrete_sequence(20, distribution=[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3]) - - -class TestNumpyArray: - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - - def test_numpy_to_list_of_ints(self): - a = np.array([1, 2, 3], dtype=np.int64) - b = np.array([1.0, 2, 3]) - c = np.array([1.1, 2, 3]) - assert type(make_list_of_ints(a)) == list - assert make_list_of_ints(b) == list(b) - B = make_list_of_ints(b) - assert type(B[0]) == int - pytest.raises(nx.NetworkXError, make_list_of_ints, c) - - def test__dict_to_numpy_array1(self): - d = {"a": 1, "b": 2} - a = _dict_to_numpy_array1(d, mapping={"a": 0, "b": 1}) - np.testing.assert_allclose(a, np.array([1, 2])) - a = _dict_to_numpy_array1(d, mapping={"b": 0, "a": 1}) - np.testing.assert_allclose(a, np.array([2, 1])) - - a = _dict_to_numpy_array1(d) - np.testing.assert_allclose(a.sum(), 3) - - def test__dict_to_numpy_array2(self): - d = {"a": {"a": 1, "b": 2}, "b": {"a": 10, "b": 20}} - - mapping = {"a": 1, "b": 0} - a = _dict_to_numpy_array2(d, mapping=mapping) - np.testing.assert_allclose(a, np.array([[20, 10], [2, 1]])) - - a = _dict_to_numpy_array2(d) - np.testing.assert_allclose(a.sum(), 33) - - def test_dict_to_numpy_array_a(self): - d = {"a": {"a": 1, "b": 2}, "b": {"a": 10, "b": 20}} - - mapping = {"a": 0, "b": 1} - a = dict_to_numpy_array(d, mapping=mapping) - np.testing.assert_allclose(a, np.array([[1, 2], [10, 20]])) - - mapping = {"a": 1, "b": 0} - a = dict_to_numpy_array(d, mapping=mapping) - np.testing.assert_allclose(a, np.array([[20, 10], [2, 1]])) - - a = _dict_to_numpy_array2(d) - np.testing.assert_allclose(a.sum(), 33) - - def test_dict_to_numpy_array_b(self): - d = {"a": 1, "b": 2} - - mapping = {"a": 0, "b": 1} - a = dict_to_numpy_array(d, mapping=mapping) - np.testing.assert_allclose(a, np.array([1, 2])) - - a = _dict_to_numpy_array1(d) - np.testing.assert_allclose(a.sum(), 3) - - -def test_pairwise(): - nodes = range(4) - node_pairs = [(0, 1), (1, 2), (2, 3)] - node_pairs_cycle = node_pairs + [(3, 0)] - assert list(pairwise(nodes)) == node_pairs - assert list(pairwise(iter(nodes))) == node_pairs - assert list(pairwise(nodes, cyclic=True)) == node_pairs_cycle - empty_iter = iter(()) - assert list(pairwise(empty_iter)) == [] - empty_iter = iter(()) - assert list(pairwise(empty_iter, cyclic=True)) == [] - - -def test_groups(): - many_to_one = dict(zip("abcde", [0, 0, 1, 1, 2])) - actual = groups(many_to_one) - expected = {0: {"a", "b"}, 1: {"c", "d"}, 2: {"e"}} - assert actual == expected - assert {} == groups({}) - - -def test_create_random_state(): - np = pytest.importorskip("numpy") - rs = np.random.RandomState - - assert isinstance(create_random_state(1), rs) - assert isinstance(create_random_state(None), rs) - assert isinstance(create_random_state(np.random), rs) - assert isinstance(create_random_state(rs(1)), rs) - # Support for numpy.random.Generator - rng = np.random.default_rng() - assert isinstance(create_random_state(rng), np.random.Generator) - pytest.raises(ValueError, create_random_state, "a") - - assert np.all(rs(1).rand(10) == create_random_state(1).rand(10)) - - -def test_create_py_random_state(): - pyrs = random.Random - - assert isinstance(create_py_random_state(1), pyrs) - assert isinstance(create_py_random_state(None), pyrs) - assert isinstance(create_py_random_state(pyrs(1)), pyrs) - pytest.raises(ValueError, create_py_random_state, "a") - - np = pytest.importorskip("numpy") - - rs = np.random.RandomState - rng = np.random.default_rng(1000) - rng_explicit = np.random.Generator(np.random.SFC64()) - old_nprs = PythonRandomInterface - nprs = PythonRandomViaNumpyBits - assert isinstance(create_py_random_state(np.random), nprs) - assert isinstance(create_py_random_state(rs(1)), old_nprs) - assert isinstance(create_py_random_state(rng), nprs) - assert isinstance(create_py_random_state(rng_explicit), nprs) - # test default rng input - assert isinstance(PythonRandomInterface(), old_nprs) - assert isinstance(PythonRandomViaNumpyBits(), nprs) - - # VeryLargeIntegers Smoke test (they raise error for np.random) - int64max = 9223372036854775807 # from np.iinfo(np.int64).max - for r in (rng, rs(1)): - prs = create_py_random_state(r) - prs.randrange(3, int64max + 5) - prs.randint(3, int64max + 5) - - -def test_PythonRandomInterface_RandomState(): - np = pytest.importorskip("numpy") - - seed = 42 - rs = np.random.RandomState - rng = PythonRandomInterface(rs(seed)) - rs42 = rs(seed) - - # make sure these functions are same as expected outcome - assert rng.randrange(3, 5) == rs42.randint(3, 5) - assert rng.choice([1, 2, 3]) == rs42.choice([1, 2, 3]) - assert rng.gauss(0, 1) == rs42.normal(0, 1) - assert rng.expovariate(1.5) == rs42.exponential(1 / 1.5) - assert np.all(rng.shuffle([1, 2, 3]) == rs42.shuffle([1, 2, 3])) - assert np.all( - rng.sample([1, 2, 3], 2) == rs42.choice([1, 2, 3], (2,), replace=False) - ) - assert np.all( - [rng.randint(3, 5) for _ in range(100)] - == [rs42.randint(3, 6) for _ in range(100)] - ) - assert rng.random() == rs42.random_sample() - - -def test_PythonRandomInterface_Generator(): - np = pytest.importorskip("numpy") - - seed = 42 - rng = np.random.default_rng(seed) - pri = PythonRandomInterface(np.random.default_rng(seed)) - - # make sure these functions are same as expected outcome - assert pri.randrange(3, 5) == rng.integers(3, 5) - assert pri.choice([1, 2, 3]) == rng.choice([1, 2, 3]) - assert pri.gauss(0, 1) == rng.normal(0, 1) - assert pri.expovariate(1.5) == rng.exponential(1 / 1.5) - assert np.all(pri.shuffle([1, 2, 3]) == rng.shuffle([1, 2, 3])) - assert np.all( - pri.sample([1, 2, 3], 2) == rng.choice([1, 2, 3], (2,), replace=False) - ) - assert np.all( - [pri.randint(3, 5) for _ in range(100)] - == [rng.integers(3, 6) for _ in range(100)] - ) - assert pri.random() == rng.random() - - -@pytest.mark.parametrize( - ("iterable_type", "expected"), ((list, 1), (tuple, 1), (str, "["), (set, 1)) -) -def test_arbitrary_element(iterable_type, expected): - iterable = iterable_type([1, 2, 3]) - assert arbitrary_element(iterable) == expected - - -@pytest.mark.parametrize( - "iterator", - ((i for i in range(3)), iter([1, 2, 3])), # generator -) -def test_arbitrary_element_raises(iterator): - """Value error is raised when input is an iterator.""" - with pytest.raises(ValueError, match="from an iterator"): - arbitrary_element(iterator) diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_random_sequence.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_random_sequence.py deleted file mode 100644 index 1d1b957..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_random_sequence.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest - -from networkx.utils import ( - powerlaw_sequence, - random_weighted_sample, - weighted_choice, - zipf_rv, -) - - -def test_degree_sequences(): - seq = powerlaw_sequence(10, seed=1) - seq = powerlaw_sequence(10) - assert len(seq) == 10 - - -def test_zipf_rv(): - r = zipf_rv(2.3, xmin=2, seed=1) - r = zipf_rv(2.3, 2, 1) - r = zipf_rv(2.3) - assert type(r), int - pytest.raises(ValueError, zipf_rv, 0.5) - pytest.raises(ValueError, zipf_rv, 2, xmin=0) - - -def test_random_weighted_sample(): - mapping = {"a": 10, "b": 20} - s = random_weighted_sample(mapping, 2, seed=1) - s = random_weighted_sample(mapping, 2) - assert sorted(s) == sorted(mapping.keys()) - pytest.raises(ValueError, random_weighted_sample, mapping, 3) - - -def test_random_weighted_choice(): - mapping = {"a": 10, "b": 0} - c = weighted_choice(mapping, seed=1) - c = weighted_choice(mapping) - assert c == "a" diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_rcm.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_rcm.py deleted file mode 100644 index 88702b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_rcm.py +++ /dev/null @@ -1,63 +0,0 @@ -import networkx as nx -from networkx.utils import reverse_cuthill_mckee_ordering - - -def test_reverse_cuthill_mckee(): - # example graph from - # http://www.boost.org/doc/libs/1_37_0/libs/graph/example/cuthill_mckee_ordering.cpp - G = nx.Graph( - [ - (0, 3), - (0, 5), - (1, 2), - (1, 4), - (1, 6), - (1, 9), - (2, 3), - (2, 4), - (3, 5), - (3, 8), - (4, 6), - (5, 6), - (5, 7), - (6, 7), - ] - ) - rcm = list(reverse_cuthill_mckee_ordering(G)) - assert rcm in [[0, 8, 5, 7, 3, 6, 2, 4, 1, 9], [0, 8, 5, 7, 3, 6, 4, 2, 1, 9]] - - -def test_rcm_alternate_heuristic(): - # example from - G = nx.Graph( - [ - (0, 0), - (0, 4), - (1, 1), - (1, 2), - (1, 5), - (1, 7), - (2, 2), - (2, 4), - (3, 3), - (3, 6), - (4, 4), - (5, 5), - (5, 7), - (6, 6), - (7, 7), - ] - ) - - answers = [ - [6, 3, 5, 7, 1, 2, 4, 0], - [6, 3, 7, 5, 1, 2, 4, 0], - [7, 5, 1, 2, 4, 0, 6, 3], - ] - - def smallest_degree(G): - deg, node = min((d, n) for n, d in G.degree()) - return node - - rcm = list(reverse_cuthill_mckee_ordering(G, heuristic=smallest_degree)) - assert rcm in answers diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_unionfind.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_unionfind.py deleted file mode 100644 index 2d30580..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/tests/test_unionfind.py +++ /dev/null @@ -1,55 +0,0 @@ -import networkx as nx - - -def test_unionfind(): - # Fixed by: 2cddd5958689bdecdcd89b91ac9aaf6ce0e4f6b8 - # Previously (in 2.x), the UnionFind class could handle mixed types. - # But in Python 3.x, this causes a TypeError such as: - # TypeError: unorderable types: str() > int() - # - # Now we just make sure that no exception is raised. - x = nx.utils.UnionFind() - x.union(0, "a") - - -def test_subtree_union(): - # See https://github.com/networkx/networkx/pull/3224 - # (35db1b551ee65780794a357794f521d8768d5049). - # Test if subtree unions hare handled correctly by to_sets(). - uf = nx.utils.UnionFind() - uf.union(1, 2) - uf.union(3, 4) - uf.union(4, 5) - uf.union(1, 5) - assert list(uf.to_sets()) == [{1, 2, 3, 4, 5}] - - -def test_unionfind_weights(): - # Tests if weights are computed correctly with unions of many elements - uf = nx.utils.UnionFind() - uf.union(1, 4, 7) - uf.union(2, 5, 8) - uf.union(3, 6, 9) - uf.union(1, 2, 3, 4, 5, 6, 7, 8, 9) - assert uf.weights[uf[1]] == 9 - - -def test_unbalanced_merge_weights(): - # Tests if the largest set's root is used as the new root when merging - uf = nx.utils.UnionFind() - uf.union(1, 2, 3) - uf.union(4, 5, 6, 7, 8, 9) - assert uf.weights[uf[1]] == 3 - assert uf.weights[uf[4]] == 6 - largest_root = uf[4] - uf.union(1, 4) - assert uf[1] == largest_root - assert uf.weights[largest_root] == 9 - - -def test_empty_union(): - # Tests if a null-union does nothing. - uf = nx.utils.UnionFind((0, 1)) - uf.union() - assert uf[0] == 0 - assert uf[1] == 1 diff --git a/extensions/.local/lib/python3.11/site-packages/networkx/utils/union_find.py b/extensions/.local/lib/python3.11/site-packages/networkx/utils/union_find.py deleted file mode 100644 index 2a07129..0000000 --- a/extensions/.local/lib/python3.11/site-packages/networkx/utils/union_find.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Union-find data structure. -""" - -from networkx.utils import groups - - -class UnionFind: - """Union-find data structure. - - Each unionFind instance X maintains a family of disjoint sets of - hashable objects, supporting the following two methods: - - - X[item] returns a name for the set containing the given item. - Each set is named by an arbitrarily-chosen one of its members; as - long as the set remains unchanged it will keep the same name. If - the item is not yet part of a set in X, a new singleton set is - created for it. - - - X.union(item1, item2, ...) merges the sets containing each item - into a single larger set. If any item is not yet part of a set - in X, it is added to X as one of the members of the merged set. - - Union-find data structure. Based on Josiah Carlson's code, - https://code.activestate.com/recipes/215912/ - with significant additional changes by D. Eppstein. - http://www.ics.uci.edu/~eppstein/PADS/UnionFind.py - - """ - - def __init__(self, elements=None): - """Create a new empty union-find structure. - - If *elements* is an iterable, this structure will be initialized - with the discrete partition on the given set of elements. - - """ - if elements is None: - elements = () - self.parents = {} - self.weights = {} - for x in elements: - self.weights[x] = 1 - self.parents[x] = x - - def __getitem__(self, object): - """Find and return the name of the set containing the object.""" - - # check for previously unknown object - if object not in self.parents: - self.parents[object] = object - self.weights[object] = 1 - return object - - # find path of objects leading to the root - path = [] - root = self.parents[object] - while root != object: - path.append(object) - object = root - root = self.parents[object] - - # compress the path and return - for ancestor in path: - self.parents[ancestor] = root - return root - - def __iter__(self): - """Iterate through all items ever found or unioned by this structure.""" - return iter(self.parents) - - def to_sets(self): - """Iterates over the sets stored in this structure. - - For example:: - - >>> partition = UnionFind("xyz") - >>> sorted(map(sorted, partition.to_sets())) - [['x'], ['y'], ['z']] - >>> partition.union("x", "y") - >>> sorted(map(sorted, partition.to_sets())) - [['x', 'y'], ['z']] - - """ - # Ensure fully pruned paths - for x in self.parents: - _ = self[x] # Evaluated for side-effect only - - yield from groups(self.parents).values() - - def union(self, *objects): - """Find the sets containing the objects and merge them all.""" - # Find the heaviest root according to its weight. - roots = iter( - sorted( - {self[x] for x in objects}, key=lambda r: self.weights[r], reverse=True - ) - ) - try: - root = next(roots) - except StopIteration: - return - - for r in roots: - self.weights[root] += self.weights[r] - self.parents[r] = root diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/LICENSE deleted file mode 100644 index 733c072..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/LICENSE +++ /dev/null @@ -1,675 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/METADATA deleted file mode 100644 index 667e93a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/METADATA +++ /dev/null @@ -1,812 +0,0 @@ -Metadata-Version: 2.1 -Name: phonemizer -Version: 3.3.0 -Summary: Simple text to phones converter for multiple languages -Author: Hadrien Titeux -Author-email: Mathieu Bernard -License: GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for - software and other kinds of works. - - The licenses for most software and other practical works are designed - to take away your freedom to share and change the works. By contrast, - the GNU General Public License is intended to guarantee your freedom to - share and change all versions of a program--to make sure it remains free - software for all its users. We, the Free Software Foundation, use the - GNU General Public License for most of our software; it applies also to - any other work released this way by its authors. You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - them if you wish), that you receive source code or can get it if you - want it, that you can change the software or use pieces of it in new - free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you - these rights or asking you to surrender the rights. Therefore, you have - certain responsibilities if you distribute copies of the software, or if - you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must pass on to the recipients the same - freedoms that you received. You must make sure that they, too, receive - or can get the source code. And you must show them these terms so they - know their rights. - - Developers that use the GNU GPL protect your rights with two steps: - (1) assert copyright on the software, and (2) offer you this License - giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains - that there is no warranty for this free software. For both users' and - authors' sake, the GPL requires that modified versions be marked as - changed, so that their problems will not be attributed erroneously to - authors of previous versions. - - Some devices are designed to deny users access to install or run - modified versions of the software inside them, although the manufacturer - can do so. This is fundamentally incompatible with the aim of - protecting users' freedom to change the software. The systematic - pattern of such abuse occurs in the area of products for individuals to - use, which is precisely where it is most unacceptable. Therefore, we - have designed this version of the GPL to prohibit the practice for those - products. If such problems arise substantially in other domains, we - stand ready to extend this provision to those domains in future versions - of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. - States should not allow patents to restrict development and use of - software on general-purpose computers, but in those that do, we wish to - avoid the special danger that patents applied to a free program could - make it effectively proprietary. To prevent this, the GPL assures that - patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and - modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of - works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this - License. Each licensee is addressed as "you". "Licensees" and - "recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work - in a fashion requiring copyright permission, other than the making of an - exact copy. The resulting work is called a "modified version" of the - earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based - on the Program. - - To "propagate" a work means to do anything with it that, without - permission, would make you directly or secondarily liable for - infringement under applicable copyright law, except executing it on a - computer or modifying a private copy. Propagation includes copying, - distribution (with or without modification), making available to the - public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other - parties to make or receive copies. Mere interaction with a user through - a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" - to the extent that it includes a convenient and prominently visible - feature that (1) displays an appropriate copyright notice, and (2) - tells the user that there is no warranty for the work (except to the - extent that warranties are provided), that licensees may convey the - work under this License, and how to view a copy of this License. If - the interface presents a list of user commands or options, such as a - menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work - for making modifications to it. "Object code" means any non-source - form of a work. - - A "Standard Interface" means an interface that either is an official - standard defined by a recognized standards body, or, in the case of - interfaces specified for a particular programming language, one that - is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other - than the work as a whole, that (a) is included in the normal form of - packaging a Major Component, but which is not part of that Major - Component, and (b) serves only to enable use of the work with that - Major Component, or to implement a Standard Interface for which an - implementation is available to the public in source code form. A - "Major Component", in this context, means a major essential component - (kernel, window system, and so on) of the specific operating system - (if any) on which the executable work runs, or a compiler used to - produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all - the source code needed to generate, install, and (for an executable - work) run the object code and to modify the work, including scripts to - control those activities. However, it does not include the work's - System Libraries, or general-purpose tools or generally available free - programs which are used unmodified in performing those activities but - which are not part of the work. For example, Corresponding Source - includes interface definition files associated with source files for - the work, and the source code for shared libraries and dynamically - linked subprograms that the work is specifically designed to require, - such as by intimate data communication or control flow between those - subprograms and other parts of the work. - - The Corresponding Source need not include anything that users - can regenerate automatically from other parts of the Corresponding - Source. - - The Corresponding Source for a work in source code form is that - same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of - copyright on the Program, and are irrevocable provided the stated - conditions are met. This License explicitly affirms your unlimited - permission to run the unmodified Program. The output from running a - covered work is covered by this License only if the output, given its - content, constitutes a covered work. This License acknowledges your - rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not - convey, without conditions so long as your license otherwise remains - in force. You may convey covered works to others for the sole purpose - of having them make modifications exclusively for you, or provide you - with facilities for running those works, provided that you comply with - the terms of this License in conveying all material for which you do - not control copyright. Those thus making or running the covered works - for you must do so exclusively on your behalf, under your direction - and control, on terms that prohibit them from making any copies of - your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under - the conditions stated below. Sublicensing is not allowed; section 10 - makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological - measure under any applicable law fulfilling obligations under article - 11 of the WIPO copyright treaty adopted on 20 December 1996, or - similar laws prohibiting or restricting circumvention of such - measures. - - When you convey a covered work, you waive any legal power to forbid - circumvention of technological measures to the extent such circumvention - is effected by exercising rights under this License with respect to - the covered work, and you disclaim any intention to limit operation or - modification of the work as a means of enforcing, against the work's - users, your or third parties' legal rights to forbid circumvention of - technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you - receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice; - keep intact all notices stating that this License and any - non-permissive terms added in accord with section 7 apply to the code; - keep intact all notices of the absence of any warranty; and give all - recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, - and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to - produce it from the Program, in the form of source code under the - terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent - works, which are not by their nature extensions of the covered work, - and which are not combined with it such as to form a larger program, - in or on a volume of a storage or distribution medium, is called an - "aggregate" if the compilation and its resulting copyright are not - used to limit the access or legal rights of the compilation's users - beyond what the individual works permit. Inclusion of a covered work - in an aggregate does not cause this License to apply to the other - parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms - of sections 4 and 5, provided that you also convey the - machine-readable Corresponding Source under the terms of this License, - in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded - from the Corresponding Source as a System Library, need not be - included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any - tangible personal property which is normally used for personal, family, - or household purposes, or (2) anything designed or sold for incorporation - into a dwelling. In determining whether a product is a consumer product, - doubtful cases shall be resolved in favor of coverage. For a particular - product received by a particular user, "normally used" refers to a - typical or common use of that class of product, regardless of the status - of the particular user or of the way in which the particular user - actually uses, or expects or is expected to use, the product. A product - is a consumer product regardless of whether the product has substantial - commercial, industrial or non-consumer uses, unless such uses represent - the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, - procedures, authorization keys, or other information required to install - and execute modified versions of a covered work in that User Product from - a modified version of its Corresponding Source. The information must - suffice to ensure that the continued functioning of the modified object - code is in no case prevented or interfered with solely because - modification has been made. - - If you convey an object code work under this section in, or with, or - specifically for use in, a User Product, and the conveying occurs as - part of a transaction in which the right of possession and use of the - User Product is transferred to the recipient in perpetuity or for a - fixed term (regardless of how the transaction is characterized), the - Corresponding Source conveyed under this section must be accompanied - by the Installation Information. But this requirement does not apply - if neither you nor any third party retains the ability to install - modified object code on the User Product (for example, the work has - been installed in ROM). - - The requirement to provide Installation Information does not include a - requirement to continue to provide support service, warranty, or updates - for a work that has been modified or installed by the recipient, or for - the User Product in which it has been modified or installed. Access to a - network may be denied when the modification itself materially and - adversely affects the operation of the network or violates the rules and - protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, - in accord with this section must be in a format that is publicly - documented (and with an implementation available to the public in - source code form), and must require no special password or key for - unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this - License by making exceptions from one or more of its conditions. - Additional permissions that are applicable to the entire Program shall - be treated as though they were included in this License, to the extent - that they are valid under applicable law. If additional permissions - apply only to part of the Program, that part may be used separately - under those permissions, but the entire Program remains governed by - this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option - remove any additional permissions from that copy, or from any part of - it. (Additional permissions may be written to require their own - removal in certain cases when you modify the work.) You may place - additional permissions on material, added by you to a covered work, - for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you - add to a covered work, you may (if authorized by the copyright holders of - that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further - restrictions" within the meaning of section 10. If the Program as you - received it, or any part of it, contains a notice stating that it is - governed by this License along with a term that is a further - restriction, you may remove that term. If a license document contains - a further restriction but permits relicensing or conveying under this - License, you may add to a covered work material governed by the terms - of that license document, provided that the further restriction does - not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you - must place, in the relevant source files, a statement of the - additional terms that apply to those files, or a notice indicating - where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the - form of a separately written license, or stated as exceptions; - the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly - provided under this License. Any attempt otherwise to propagate or - modify it is void, and will automatically terminate your rights under - this License (including any patent licenses granted under the third - paragraph of section 11). - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the copyright - holder fails to notify you of the violation by some reasonable means - prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from that - copyright holder, and you cure the violation prior to 30 days after - your receipt of the notice. - - Termination of your rights under this section does not terminate the - licenses of parties who have received copies or rights from you under - this License. If your rights have been terminated and not permanently - reinstated, you do not qualify to receive new licenses for the same - material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or - run a copy of the Program. Ancillary propagation of a covered work - occurring solely as a consequence of using peer-to-peer transmission - to receive a copy likewise does not require acceptance. However, - nothing other than this License grants you permission to propagate or - modify any covered work. These actions infringe copyright if you do - not accept this License. Therefore, by modifying or propagating a - covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically - receives a license from the original licensors, to run, modify and - propagate that work, subject to this License. You are not responsible - for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an - organization, or substantially all assets of one, or subdividing an - organization, or merging organizations. If propagation of a covered - work results from an entity transaction, each party to that - transaction who receives a copy of the work also receives whatever - licenses to the work the party's predecessor in interest had or could - give under the previous paragraph, plus a right to possession of the - Corresponding Source of the work from the predecessor in interest, if - the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the - rights granted or affirmed under this License. For example, you may - not impose a license fee, royalty, or other charge for exercise of - rights granted under this License, and you may not initiate litigation - (including a cross-claim or counterclaim in a lawsuit) alleging that - any patent claim is infringed by making, using, selling, offering for - sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this - License of the Program or a work on which the Program is based. The - work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims - owned or controlled by the contributor, whether already acquired or - hereafter acquired, that would be infringed by some manner, permitted - by this License, of making, using, or selling its contributor version, - but do not include claims that would be infringed only as a - consequence of further modification of the contributor version. For - purposes of this definition, "control" includes the right to grant - patent sublicenses in a manner consistent with the requirements of - this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free - patent license under the contributor's essential patent claims, to - make, use, sell, offer for sale, import and otherwise run, modify and - propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express - agreement or commitment, however denominated, not to enforce a patent - (such as an express permission to practice a patent or covenant not to - sue for patent infringement). To "grant" such a patent license to a - party means to make such an agreement or commitment not to enforce a - patent against the party. - - If you convey a covered work, knowingly relying on a patent license, - and the Corresponding Source of the work is not available for anyone - to copy, free of charge and under the terms of this License, through a - publicly available network server or other readily accessible means, - then you must either (1) cause the Corresponding Source to be so - available, or (2) arrange to deprive yourself of the benefit of the - patent license for this particular work, or (3) arrange, in a manner - consistent with the requirements of this License, to extend the patent - license to downstream recipients. "Knowingly relying" means you have - actual knowledge that, but for the patent license, your conveying the - covered work in a country, or your recipient's use of the covered work - in a country, would infringe one or more identifiable patents in that - country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or - arrangement, you convey, or propagate by procuring conveyance of, a - covered work, and grant a patent license to some of the parties - receiving the covered work authorizing them to use, propagate, modify - or convey a specific copy of the covered work, then the patent license - you grant is automatically extended to all recipients of the covered - work and works based on it. - - A patent license is "discriminatory" if it does not include within - the scope of its coverage, prohibits the exercise of, or is - conditioned on the non-exercise of one or more of the rights that are - specifically granted under this License. You may not convey a covered - work if you are a party to an arrangement with a third party that is - in the business of distributing software, under which you make payment - to the third party based on the extent of your activity of conveying - the work, and under which the third party grants, to any of the - parties who would receive the covered work from you, a discriminatory - patent license (a) in connection with copies of the covered work - conveyed by you (or copies made from those copies), or (b) primarily - for and in connection with specific products or compilations that - contain the covered work, unless you entered into that arrangement, - or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting - any implied license or other defenses to infringement that may - otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot convey a - covered work so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you may - not convey it at all. For example, if you agree to terms that obligate you - to collect a royalty for further conveying from those to whom you convey - the Program, the only way you could satisfy both those terms and this - License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have - permission to link or combine any covered work with a work licensed - under version 3 of the GNU Affero General Public License into a single - combined work, and to convey the resulting work. The terms of this - License will continue to apply to the part which is the covered work, - but the special requirements of the GNU Affero General Public License, - section 13, concerning interaction through a network will apply to the - combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of - the GNU General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the - Program specifies that a certain numbered version of the GNU General - Public License "or any later version" applies to it, you have the - option of following the terms and conditions either of that numbered - version or of any later version published by the Free Software - Foundation. If the Program does not specify a version number of the - GNU General Public License, you may choose any version ever published - by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future - versions of the GNU General Public License can be used, that proxy's - public statement of acceptance of a version permanently authorizes you - to choose that version for the Program. - - Later license versions may give you additional or different - permissions. However, no additional obligations are imposed on any - author or copyright holder as a result of your choosing to follow a - later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY - APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY - OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM - IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF - ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS - THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY - GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE - USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD - PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), - EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF - SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided - above cannot be given local legal effect according to their terms, - reviewing courts shall apply local law that most closely approximates - an absolute waiver of all civil liability in connection with the - Program, unless a warranty or assumption of liability accompanies a - copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest - possible use to the public, the best way to achieve this is to make it - free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest - to attach them to the start of each source file to most effectively - state the exclusion of warranty; and each file should have at least - the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short - notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - - The hypothetical commands `show w' and `show c' should show the appropriate - parts of the General Public License. Of course, your program's commands - might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, - if any, to sign a "copyright disclaimer" for the program, if necessary. - For more information on this, and how to apply and follow the GNU GPL, see - . - - The GNU General Public License does not permit incorporating your program - into proprietary programs. If your program is a subroutine library, you - may consider it more useful to permit linking proprietary applications with - the library. If this is what you want to do, use the GNU Lesser General - Public License instead of this License. But first, please read - . - - -Project-URL: Documentation, https://bootphon.github.io/phonemizer/ -Project-URL: Repository, https://github.com/bootphon/phonemizer -Project-URL: Issues, https://github.com/bootphon/phonemizer -Project-URL: Changelog, https://github.com/bootphon/phonemizer/blob/master/docs/source/changelog.rst -Keywords: linguistics,G2P,phone,espeak,festival,TTS -Classifier: Programming Language :: Python :: 3 -Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) -Classifier: Operating System :: OS Independent -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: joblib -Requires-Dist: segments -Requires-Dist: attrs >=18.1 -Requires-Dist: dlinfo -Requires-Dist: typing-extensions -Provides-Extra: doc -Requires-Dist: sphinx ; extra == 'doc' -Requires-Dist: sphinx-rtd-theme ; extra == 'doc' -Provides-Extra: test -Requires-Dist: pytest >=6.0 ; extra == 'test' -Requires-Dist: pytest-cov ; extra == 'test' -Requires-Dist: coverage[toml] ; extra == 'test' - -| **Tests** | [![Linux][badge-test-linux]](https://github.com/bootphon/phonemizer/actions/workflows/linux.yaml) [![MacOS][badge-test-macos]](https://github.com/bootphon/phonemizer/actions/workflows/macos.yaml) [![Windows][badge-test-windows]](https://github.com/bootphon/phonemizer/actions/workflows/windows.yaml) [![Codecov][badge-codecov]](https://codecov.io/gh/bootphon/phonemizer) | -|------------------:| --- | -| **Documentation** | [![Doc](https://github.com/bootphon/phonemizer/actions/workflows/doc.yaml/badge.svg)](https://bootphon.github.io/phonemizer/) | -| **Release** | [![GitHub release (latest SemVer)][badge-github-version]](https://github.com/bootphon/phonemizer/releases/latest) [![PyPI][badge-pypi-version]](https://pypi.python.org/pypi/phonemizer) [![downloads][badge-pypi-downloads]](https://pypi.python.org/pypi/phonemizer) | -| **Citation** | [![status][badge-joss]](https://joss.theoj.org/papers/08d1ffc14f233f56942f78f3742b266e) [![DOI][badge-zenodo]](https://doi.org/10.5281/zenodo.1045825) | - ---- - -# Phonemizer -- *foÊŠnmaɪzÉš* - -* The phonemizer allows simple phonemization of words and texts in many languages. - -* Provides both the `phonemize` command-line tool and the Python function - `phonemizer.phonemize`. See [the package's documentation](https://bootphon.github.io/phonemizer/). - -* It is based on four backends: **espeak**, **espeak-mbrola**, **festival** and - **segments**. The backends have different properties and capabilities resumed - in table below. The backend choice is let to the user. - - * [espeak-ng](https://github.com/espeak-ng/espeak-ng) is a Text-to-Speech - software supporting a lot of languages and IPA (International Phonetic - Alphabet) output. - - * [espeak-ng-mbrola](https://github.com/espeak-ng/espeak-ng/blob/master/docs/mbrola.md) - uses the SAMPA phonetic alphabet instead of IPA but does not preserve word - boundaries. - - * [festival](http://www.cstr.ed.ac.uk/projects/festival) is another - Tex-to-Speech engine. Its phonemizer backend currently supports only - American English. It uses a [custom phoneset][festival-phoneset], but it - allows tokenization at the syllable level. - - * [segments](https://github.com/cldf/segments) is a Unicode tokenizer that - build a phonemization from a grapheme to phoneme mapping provided as a file - by the user. - - | | espeak | espeak-mbrola | festival | segments | - | ---: | --- | --- | --- | --- | - | **phone set** | [IPA] | [SAMPA] | [custom][festival-phoneset] | user defined | - | **supported languages** | [100+][espeak-languages] | [35][mbrola-languages] | US English | user defined | - | **processing speed** | fast | slow | very slow | fast | - | **phone tokens** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | - | **syllable tokens** | :x: | :x: | :heavy_check_mark: | :x: | - | **word tokens** | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | - | **punctuation preservation** | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | - | **stressed phones** | :heavy_check_mark: | :x: | :x: | :x: | - | [**tie**][tie-IPA] | :heavy_check_mark: | :x: | :x: | :x: | - - - -## Citation - -To refenrece the `phonemizer` in your own work, please cite the following [JOSS -paper](https://joss.theoj.org/papers/10.21105/joss.03958). - -```bibtex -@article{Bernard2021, - doi = {10.21105/joss.03958}, - url = {https://doi.org/10.21105/joss.03958}, - year = {2021}, - publisher = {The Open Journal}, - volume = {6}, - number = {68}, - pages = {3958}, - author = {Mathieu Bernard and Hadrien Titeux}, - title = {Phonemizer: Text to Phones Transcription for Multiple Languages in Python}, - journal = {Journal of Open Source Software} -} -``` - - -## Licence - -**Copyright 2015-2021 Mathieu Bernard** - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - - -[badge-test-linux]: https://github.com/bootphon/phonemizer/actions/workflows/linux.yaml/badge.svg?branch=master -[badge-test-macos]: https://github.com/bootphon/phonemizer/actions/workflows/macos.yaml/badge.svg?branch=master -[badge-test-windows]: https://github.com/bootphon/phonemizer/actions/workflows/windows.yaml/badge.svg?branch=master -[badge-codecov]: https://img.shields.io/codecov/c/github/bootphon/phonemizer -[badge-github-version]: https://img.shields.io/github/v/release/bootphon/phonemizer -[badge-pypi-version]: https://img.shields.io/pypi/v/phonemizer -[badge-pypi-downloads]: https://img.shields.io/pypi/dm/phonemizer -[badge-joss]: https://joss.theoj.org/papers/08d1ffc14f233f56942f78f3742b266e/status.svg -[badge-zenodo]: https://zenodo.org/badge/56728069.svg -[phonemizer-1.0]: https://github.com/bootphon/phonemizer/releases/tag/v1.0 -[festival-phoneset]: http://www.festvox.org/bsv/c4711.html -[IPA]: https://en.wikipedia.org/wiki/International_Phonetic_Alphabet -[SAMPA]: https://en.wikipedia.org/wiki/SAMPA -[phonemize-function]: https://github.com/bootphon/phonemizer/blob/c5e2f3878d6db391ec7253173f44e4a85cfe41e3/phonemizer/phonemize.py#L33-L156 -[tie-IPA]: https://en.wikipedia.org/wiki/Tie_(typography)#International_Phonetic_Alphabet -[espeak-languages]: https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md -[mbrola-languages]: https://github.com/numediart/MBROLA-voices diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/RECORD deleted file mode 100644 index ac3bf38..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/RECORD +++ /dev/null @@ -1,51 +0,0 @@ -docs/source/conf.py,sha256=j_G_53oU4L7C5dNOj7P5LhVcEu4yd4_x2BfimTb9_OQ,2051 -phonemizer/__init__.py,sha256=ieetH6bFvNIRE0fJM6Li__EZqSbUjeNI9ETq3wWQSJ0,837 -phonemizer/logger.py,sha256=F9IFuMIagEp0wYn3jUF0MOae14bk4l5R0ErFiPbYqjQ,2141 -phonemizer/main.py,sha256=O1RUWNXauW4JMVx8jHI4CQIBeExu3sjiO0Mzia13UyA,15824 -phonemizer/phonemize.py,sha256=93_nEUbtv_nkWEhYOMNu6qPQKbfk7BdorPL6JfFAL-o,12872 -phonemizer/punctuation.py,sha256=6Ph8j03KxOJM8iQ-vVFpjqU9TCrCyioGAyTm9vhOw3Q,8764 -phonemizer/separator.py,sha256=mbSsXlN8qnxDFyp8waZsnuP8ANuP86a3dj_MkGdF3-E,4151 -phonemizer/utils.py,sha256=-FdZCKvdNOiVVuAjhoBzI3tfwpJuzdG4EDuQTWW5CHM,4187 -phonemizer/version.py,sha256=BmedCzrHrWrCgiyg1o1ZriHGjNk6w9hDZfxCen9HxPk,2350 -phonemizer/backend/__init__.py,sha256=i4USZR7DxTaAul6BJzK4tcLH7hEEdCXI4J-ZwD3LFeA,1112 -phonemizer/backend/base.py,sha256=d6kD6VAIZjFDw03RMcnd2M1kbXbmZ1M9-qFMzVo2vq0,9185 -phonemizer/backend/segments.py,sha256=6Sga-tIkMRv5RmhdQTzDMoKyyZzK_6D5OkXv8ZkD9yI,5404 -phonemizer/backend/espeak/__init__.py,sha256=yvURen0id8uQ5i3mGhPDbB22euPyjrYppQqnnXXMYGI,735 -phonemizer/backend/espeak/api.py,sha256=rTMOWHMidE0HI4RNPgtIwFRXYETWeohm_JTnLvROXqw,9857 -phonemizer/backend/espeak/base.py,sha256=EpgtJumAIsn86rU7O7NDN9kqph7T9Imh2yunan-KXYo,3746 -phonemizer/backend/espeak/espeak.py,sha256=Gc6Rn5XmC4-o5rZ79LJ9N1RJ44G-UUBrn_18BJcND00,6680 -phonemizer/backend/espeak/language_switch.py,sha256=1EdYpWOFwU2slUVg3QROYbcMoMMj7f83hQoBUdICcno,6929 -phonemizer/backend/espeak/mbrola.py,sha256=C62MllV9AdgKoQnU09_CrD0BO-Tm6wvnumwk92moNUs,4147 -phonemizer/backend/espeak/voice.py,sha256=rRdQiLWoQG4QxYq68L6Vaq2Xa9sft1TuTSZQ1-EskKg,2982 -phonemizer/backend/espeak/words_mismatch.py,sha256=qVZlQC-rOUbO635qrc7ctXHHFTOCQayG7h9kUEstGVg,5122 -phonemizer/backend/espeak/wrapper.py,sha256=BXGiK_DX-6D-rb-NjCwOE96yJRes1OAvGl0anGUIud0,13346 -phonemizer/backend/festival/__init__.py,sha256=nHDtSzmHeKbrKEU2mDePVX5LHgBC09qRsLliLpzg8sY,737 -phonemizer/backend/festival/festival.py,sha256=7Vgv5O6jWw0beZYiadRSnxEiCjqB41UJYoQyLcJKsbs,12303 -phonemizer/backend/festival/lispy.py,sha256=xipPoFB-EyFWDznb9AWQcMpYzhGbFJdgZ4EfnzSg9kI,1972 -phonemizer/share/festival/phonemize.scm,sha256=Aj0Oy_kyKF7rQEoVu-H0pPzw4UWNwT1Syu8O6As2VH8,1378 -phonemizer/share/segments/chintang.g2p,sha256=4efV_eQiGgRQZL-b53E41YPeCprTJk6NEDcmgJTtyL0,133 -phonemizer/share/segments/cree.g2p,sha256=bChrLTuHdbAfR5839Iu6cnqIExVDxyFP1XKGVQyCusw,133 -phonemizer/share/segments/inuktitut.g2p,sha256=3OXFjSKUCheayNNdIQsZ_K2hkmL91aPlW3QphUPCz70,93 -phonemizer/share/segments/japanese.g2p,sha256=zikPxAXjtSdbQoVtUwv076_PJDTOFOMeNWuT_ZzWb-s,188 -phonemizer/share/segments/sesotho.g2p,sha256=KCS0sPDGBdyT1QGVRZEwOuCzKn0lbjM_zHXOqf_1CQk,211 -phonemizer/share/segments/yucatec.g2p,sha256=I9xvHfwEZlX1JUkuGBzMftH0dQILPtDqCKNXdiwiLrM,297 -test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -test/test_espeak.py,sha256=mi08qSz7H5pFxN6NK90WY3DAxk4Ap5u3AEGkT5BMBm0,7394 -test/test_espeak_lang_switch.py,sha256=0Y0PBnHF9JEUJCaZVNJEYg4cRga9s9lVsctc7CEQbD8,5082 -test/test_espeak_word_mismatch.py,sha256=etH7cTD1wdhLbeJ5874HUqoEx-_V1u0XWKynvySA2s0,2689 -test/test_espeak_wrapper.py,sha256=vb9o3JN031g81mRYD7RN6GH-1LkDhesL1W0hF7U1M4I,4114 -test/test_festival.py,sha256=1HeyidikWf_n8R_qXuqyxzKn5RNUkHobhN1diE8nf5o,3802 -test/test_import.py,sha256=zN7BRCjQxY3KQidsVwD1YvNNokyqBWKW61982F85k7Y,326 -test/test_main.py,sha256=_DYsoDfi-A4R8itL7zQLgNSCfeKTo-D2E8-DdHwQk9A,5387 -test/test_mbrola.py,sha256=Fyk0XxX4WAhRDDmhayCU8o3kdM8lZ_LdcuxwX1FVN0M,3300 -test/test_phonemize.py,sha256=xqTUqf83D1gMvpE6W2LzQpr-iMRLutk0ZzKwA4Wa6K0,11503 -test/test_punctuation.py,sha256=mbgQA_m7e5mzOY0chEcIKkHtF-R24oOULfSTYSOZMic,9713 -test/test_segments.py,sha256=LD4Zll_WT0yae4Rn4cqicC5hOSwk9-wj2diMPhgdzSk,3867 -test/test_separator.py,sha256=Afle2Xmb4swowJhIRm4t0RE2pLuznn_PPpBM6aH983M,2664 -test/test_utils.py,sha256=Bhk_SnWKtdmEr64NHFzdNGdKqAPCLRTk_dj2MTwj_NA,1728 -phonemizer-3.3.0.dist-info/LICENSE,sha256=1i8GWDCqNznMAxFWuWkIBcey6BG0oXjItKzYcl1WHJQ,35142 -phonemizer-3.3.0.dist-info/METADATA,sha256=BiODGB8mE2_tFT6MYGBcAtdfkWMnJ2FAUAXfGQNGp-U,48247 -phonemizer-3.3.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91 -phonemizer-3.3.0.dist-info/entry_points.txt,sha256=PgnnDOPvchzkWgnlrKRj7yTCWa8J8DaBRbn4dizP5ZA,51 -phonemizer-3.3.0.dist-info/top_level.txt,sha256=6bRqt82inMYJD-7hdZ_vN7ApcwYHtmBRniQDK-Syo-E,21 -phonemizer-3.3.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/WHEEL deleted file mode 100644 index 1a9c535..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (72.1.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/entry_points.txt deleted file mode 100644 index b11aa1a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -phonemize = phonemizer.main:main diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/top_level.txt deleted file mode 100644 index 807917a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer-3.3.0.dist-info/top_level.txt +++ /dev/null @@ -1,3 +0,0 @@ -docs -phonemizer -test diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/__init__.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/__init__.py deleted file mode 100644 index 36a21a4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonologizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonologizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonologizer. If not, see . -"""Multilingual text to phones converter""" - -from .phonemize import phonemize # pylint: disable=unused-import - - -__version__ = '3.3.0' -"""Phonemizer version""" diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/__init__.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/__init__.py deleted file mode 100644 index 8d10c1b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonologizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonologizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonologizer. If not, see . -"""Multilingual text to phonemes converter""" - -# pylint: disable=unused-import - -from .espeak.espeak import EspeakBackend -from .espeak.mbrola import EspeakMbrolaBackend -from .festival.festival import FestivalBackend -from .segments import SegmentsBackend - - -BACKENDS = {b.name(): b for b in ( - EspeakBackend, FestivalBackend, SegmentsBackend, EspeakMbrolaBackend)} -"""The different phonemization backends as a mapping (name, class)""" diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/base.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/base.py deleted file mode 100644 index 4efc8ec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/base.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Abstract base class for phonemization backends""" - -import abc -import itertools -import re -from logging import Logger -from typing import Optional, List, Any, Dict, Tuple, Union, Pattern - -import joblib - -from phonemizer.logger import get_logger -from phonemizer.punctuation import Punctuation -from phonemizer.separator import Separator, default_separator -from phonemizer.utils import chunks - - -class BaseBackend(abc.ABC): - """Abstract base class of all the phonemization backends - - Provides a common interface to all backends. The central method is - `phonemize()` - - Parameters - ---------- - language: str - The language code of the input text, must be supported by - the backend. If ``backend`` is 'segments', the language can be a file with - a grapheme to phoneme mapping. - - preserve_punctuation: bool - When True, will keep the punctuation in the - phonemized output. Not supported by the 'espeak-mbrola' backend. Default - to False and remove all the punctuation. - - punctuation_marks: str - The punctuation marks to consider when dealing with punctuation, either for removal or preservation. - Can be defined as a string or regular expression. Default to Punctuation.default_marks(). - - logger: logging.Logger - the logging instance where to send - messages. If not specified, use the default system logger. - - Raises - ------ - RuntimeError - if the backend is not available of if the `language` cannot be initialized. - - """ - - def __init__(self, language: str, - punctuation_marks: Optional[Union[str, Pattern]] = None, - preserve_punctuation: bool = False, - logger: Optional[Logger] = None): - - if punctuation_marks is None: - punctuation_marks = Punctuation.default_marks() - - if logger is None: - logger = get_logger() - - # ensure the backend is installed on the system - if not self.is_available(): - raise RuntimeError( # pragma: nocover - '{} not installed on your system'.format(self.name())) - - self._logger = logger - self._logger.info( - 'initializing backend %s-%s', - self.name(), '.'.join(str(v) for v in self.version())) - - # ensure the backend support the requested language - self._language = self._init_language(language) - - # setup punctuation processing - self._preserve_punctuation = preserve_punctuation - self._punctuator = Punctuation(punctuation_marks) - - @classmethod - def _init_language(cls, language): - """Language initialization - - This method may be overloaded in child classes (see Segments backend) - - """ - if not cls.is_supported_language(language): - raise RuntimeError( - f'language "{language}" is not supported by the ' - f'{cls.name()} backend') - return language - - @property - def logger(self): - """A logging.Logger instance where to send messages""" - return self._logger - - @property - def language(self): - """The language code configured to be used for phonemization""" - return self._language - - @staticmethod - @abc.abstractmethod - def name(): - """The name of the backend""" - - @classmethod - @abc.abstractmethod - def is_available(cls): - """Returns True if the backend is installed, False otherwise""" - - @classmethod - @abc.abstractmethod - def version(cls): - """Return the backend version as a tuple (major, minor, patch)""" - - @staticmethod - @abc.abstractmethod - def supported_languages() -> Dict[str, str]: - """Return a dict of language codes -> name supported by the backend""" - - @classmethod - def is_supported_language(cls, language: str): - """Returns True if `language` is supported by the backend""" - return language in cls.supported_languages() - - def phonemize(self, text: List[str], - separator: Optional[Separator] = None, - strip: bool = False, - njobs: int = 1) -> List[str]: - """Returns the `text` phonemized for the given language - - Parameters - ---------- - text: list of str - The text to be phonemized. Each string in the list - is considered as a separated line. Each line is considered as a text - utterance. Any empty utterance will be ignored. - - separator: Separator - string separators between phonemes, syllables - and words, default to separator.default_separator. Syllable separator - is considered only for the festival backend. Word separator is - ignored by the 'espeak-mbrola' backend. - - strip: bool - If True, don't output the last word and phone separators - of a token, default to False. - - njobs : int - The number of parallel jobs to launch. The input text is - split in ``njobs`` parts, phonemized on parallel instances of the - backend and the outputs are finally collapsed. - - Returns - ------- - phonemized text: list of str - The input ``text`` phonemized for the given ``language`` and ``backend``. - - Raises - ------ - RuntimeError - if something went wrong during the phonemization - - """ - if isinstance(text, str): - # changed in phonemizer-3.0, warn the user - raise RuntimeError( - 'input text to phonemize() is str but it must be list of str') - - if separator is None: - separator = default_separator - - text, punctuation_marks = self._phonemize_preprocess(text) - - if njobs == 1: - # phonemize the text forced as a string - phonemized = self._phonemize_aux(text, 0, separator, strip) - else: - # If using parallel jobs, disable the log as stderr is not - # picklable. - self.logger.info('running %s on %s jobs', self.name(), njobs) - - # we have here a list of phonemized chunks - phonemized = joblib.Parallel(n_jobs=njobs)( - joblib.delayed(self._phonemize_aux)( - # chunk[0] is the text, chunk[1] is the offset - chunk[0], chunk[1], separator, strip) - for chunk in zip(*chunks(text, njobs))) - - # flatten them in a single list - phonemized = self._flatten(phonemized) - - return self._phonemize_postprocess(phonemized, punctuation_marks, separator, strip) - - @staticmethod - def _flatten(phonemized: List[List[Any]]): - """Flatten a list of lists into a single one - - From [[1, 2], [3], [4]] returns [1, 2, 3, 4]. This method is used to - format the output as obtained using multiple jobs. - - """ - return list(itertools.chain(*phonemized)) - - @abc.abstractmethod - def _phonemize_aux(self, text: List[str], offset: int, separator: Separator, strip: bool) -> List[str]: - """The "concrete" phonemization method - - Must be implemented in child classes. `separator` and `strip` - parameters are as given to the phonemize() method. `text` is as - returned by _phonemize_preprocess(). `offset` is line number of the - first line in `text` with respect to the original text (this is only - usefull with running on chunks in multiple jobs. When using a single - jobs the offset is 0). - - """ - - def _phonemize_preprocess(self, text: List[str]) -> Tuple[Union[str, List[str]], List]: - """Preprocess the text before phonemization - - Removes the punctuation (keep trace of punctuation marks for further - restoration if required by the `preserve_punctuation` option). - - """ - if self._preserve_punctuation: - # a tuple (text, punctuation marks) - return self._punctuator.preserve(text) - return self._punctuator.remove(text), [] - - def _phonemize_postprocess(self, phonemized: List[str], - punctuation_marks, - separator: Separator, - strip: bool): - """Postprocess the raw phonemized output - - Restores the punctuation as needed. - - """ - if self._preserve_punctuation: - return self._punctuator.restore(phonemized, punctuation_marks, separator, strip) - return phonemized diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/__init__.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/__init__.py deleted file mode 100644 index 48139db..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonologizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonologizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonologizer. If not, see . -"""Phonemizer module for espeak backend implementation""" diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/api.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/api.py deleted file mode 100644 index dbf7b3e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/api.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Low-level bindings to the espeak API""" - -import atexit -import ctypes -import pathlib -import shutil -import sys -import tempfile -import weakref -from ctypes import CDLL -from pathlib import Path -from typing import Union - -from phonemizer.backend.espeak.voice import EspeakVoice - -if sys.platform != 'win32': - # cause a crash on Windows - import dlinfo - - -class EspeakAPI: - """Exposes the espeak API to the EspeakWrapper - - This class exposes only low-level bindings to the API and should not be - used directly. - - """ - - def __init__(self, library: Union[str, Path]): - # set to None to avoid an AttributeError in _delete if the __init__ - # method raises, will be properly initialized below - self._library = None - - # Because the library is not designed to be wrapped nor to be used in - # multithreaded/multiprocess contexts (massive use of global variables) - # we need a copy of the original library for each instance of the - # wrapper... (see "man dlopen" on Linux/MacOS: we cannot load two times - # the same library because a reference is then returned by dlopen). The - # tweak is therefore to make a copy of the original library in a - # different (temporary) directory. - try: - # load the original library in order to retrieve its full path? - # Forced as str as it is required on Windows. - espeak: CDLL = ctypes.cdll.LoadLibrary(str(library)) - library_path = self._shared_library_path(espeak) - del espeak - except OSError as error: - raise RuntimeError( - f'failed to load espeak library: {str(error)}') from None - - # will be automatically destroyed after use - self._tempdir = tempfile.mkdtemp() - - # properly exit when the wrapper object is destroyed (see - # https://docs.python.org/3/library/weakref.html#comparing-finalizers-with-del-methods). - # But... weakref implementation does not work on windows so we register - # the cleanup with atexit. This means that, on Windows, all the - # temporary directories created by EspeakAPI instances will remain on - # disk until the Python process exit. - if sys.platform == 'win32': # pragma: nocover - atexit.register(self._delete_win32) - else: - weakref.finalize(self, self._delete, self._library, self._tempdir) - - espeak_copy = pathlib.Path(self._tempdir) / library_path.name - shutil.copy(library_path, espeak_copy, follow_symlinks=False) - - # finally load the library copy and initialize it. 0x02 is - # AUDIO_OUTPUT_SYNCHRONOUS in the espeak API - self._library = ctypes.cdll.LoadLibrary(str(espeak_copy)) - try: - if self._library.espeak_Initialize(0x02, 0, None, 0) <= 0: - raise RuntimeError( # pragma: nocover - 'failed to initialize espeak shared library') - except AttributeError: # pragma: nocover - raise RuntimeError( - 'failed to load espeak library') from None - - # the path to the original one (the copy is considered an - # implementation detail and is not exposed) - self._library_path = library_path - - def _delete_win32(self): # pragma: nocover - # Windows does not support static methods with ctypes libraries - # (library == None) so we use a proxy method... - self._delete(self._library, self._tempdir) - - @staticmethod - def _delete(library, tempdir): - try: - # clean up the espeak library allocated memory - library.espeak_Terminate() - except AttributeError: # library not loaded - pass - - # on Windows it is required to unload the library or the .dll file - # cannot be erased from the temporary directory - if sys.platform == 'win32': # pragma: nocover - # pylint: disable=import-outside-toplevel - # pylint: disable=protected-access - # pylint: disable=no-member - import _ctypes - _ctypes.FreeLibrary(library._handle) - - # clean up the tempdir containing the copy of the library - shutil.rmtree(tempdir) - - @property - def library_path(self): - """Absolute path to the espeak library being in use""" - return self._library_path - - @staticmethod - def _shared_library_path(library) -> Path: - """Returns the absolute path to `library` - - This function is cross-platform and works for Linux, MacOS and Windows. - Raises a RuntimeError if the library path cannot be retrieved - - """ - # pylint: disable=protected-access - path = pathlib.Path(library._name).resolve() - if path.is_file(): - return path - - try: - # Linux or MacOS only, ImportError on Windows - return pathlib.Path(dlinfo.DLInfo(library).path).resolve() - except (Exception, ImportError): # pragma: nocover - raise RuntimeError( - f'failed to retrieve the path to {library} library') from None - - def info(self): - """Bindings to espeak_Info - - Returns - ------- - version, data_path: encoded strings containing the espeak version - number and data path respectively - - """ - f_info = self._library.espeak_Info - f_info.restype = ctypes.c_char_p - data_path = ctypes.c_char_p() - version = f_info(ctypes.byref(data_path)) - return version, data_path.value - - def list_voices(self, name): - """Bindings to espeak_ListVoices - - Parameters - ---------- - name (str or None): if specified, a filter on voices to be listed - - Returns - ------- - voices: a pointer to EspeakVoice.Struct instances - - """ - f_list_voices = self._library.espeak_ListVoices - f_list_voices.argtypes = [ctypes.POINTER(EspeakVoice.VoiceStruct)] - f_list_voices.restype = ctypes.POINTER( - ctypes.POINTER(EspeakVoice.VoiceStruct)) - return f_list_voices(name) - - def set_voice_by_name(self, name) -> int: - """Bindings to espeak_SetVoiceByName - - Parameters - ---------- - name (str) : the voice name to setup - - Returns - ------- - 0 on success, non-zero integer on failure - - """ - f_set_voice_by_name = self._library.espeak_SetVoiceByName - f_set_voice_by_name.argtypes = [ctypes.c_char_p] - return f_set_voice_by_name(name) - - def get_current_voice(self): - """Bindings to espeak_GetCurrentVoice - - Returns - ------- - a EspeakVoice.Struct instance or None if no voice has been setup - - """ - f_get_current_voice = self._library.espeak_GetCurrentVoice - f_get_current_voice.restype = ctypes.POINTER(EspeakVoice.VoiceStruct) - return f_get_current_voice().contents - - def text_to_phonemes(self, text_ptr, text_mode, phonemes_mode): - """Bindings to espeak_TextToPhonemes - - Parameters - ---------- - text_ptr (pointer): the text to be phonemized, as a pointer to a - pointer of chars - text_mode (bits field): see espeak sources for details - phonemes_mode (bits field): see espeak sources for details - - Returns - ------- - an encoded string containing the computed phonemes - - """ - f_text_to_phonemes = self._library.espeak_TextToPhonemes - f_text_to_phonemes.restype = ctypes.c_char_p - f_text_to_phonemes.argtypes = [ - ctypes.POINTER(ctypes.c_char_p), - ctypes.c_int, - ctypes.c_int] - return f_text_to_phonemes(text_ptr, text_mode, phonemes_mode) - - def set_phoneme_trace(self, mode, file_pointer): - """"Bindings on espeak_SetPhonemeTrace - - This method must be called before any call to synthetize() - - Parameters - ---------- - mode (bits field): see espeak sources for details - file_pointer (FILE*): a pointer to an opened file in which to output - the phoneme trace - - """ - f_set_phoneme_trace = self._library.espeak_SetPhonemeTrace - f_set_phoneme_trace.argtypes = [ - ctypes.c_int, - ctypes.c_void_p] - f_set_phoneme_trace(mode, file_pointer) - - def synthetize(self, text_ptr, size, mode): - """Bindings on espeak_Synth - - The output phonemes are sent to the file specified by a call to - set_phoneme_trace(). - - Parameters - ---------- - text (pointer) : a pointer to chars - size (int) : number of chars in `text` - mode (bits field) : see espeak sources for details - - Returns - ------- - 0 on success, non-zero integer on failure - - """ - f_synthetize = self._library.espeak_Synth - f_synthetize.argtypes = [ - ctypes.c_void_p, - ctypes.c_size_t, - ctypes.c_uint, - ctypes.c_int, # position_type - ctypes.c_uint, - ctypes.POINTER(ctypes.c_uint), - ctypes.c_void_p] - return f_synthetize(text_ptr, size, 0, 1, 0, mode, None, None) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/base.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/base.py deleted file mode 100644 index 387598b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/base.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Base class of espeak backends for the phonemizer""" - -import abc -from logging import Logger -from typing import Optional, Union, Pattern - -from phonemizer.backend.base import BaseBackend -from phonemizer.backend.espeak.wrapper import EspeakWrapper -from phonemizer.logger import get_logger -from phonemizer.punctuation import Punctuation -from phonemizer.separator import Separator - - -class BaseEspeakBackend(BaseBackend): - """Abstract espeak backend for the phonemizer - - Base class of the concrete backends Espeak and EspeakMbrola. It provides - facilities to find espeak library and read espeak version. - - """ - def __init__(self, language: str, - punctuation_marks: Optional[Union[str, Pattern]] = None, - preserve_punctuation: bool = False, - logger: Optional[Logger] = None): - super().__init__( - language, - punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, - logger=logger) - - self._espeak = EspeakWrapper() - self.logger.debug('loaded %s', self._espeak.library_path) - - - @classmethod - def set_library(cls, library): - """Sets the espeak backend to use `library` - - If this is not set, the backend uses the default espeak shared library - from the system installation. - - Parameters - ---------- - library (str or None) : the path to the espeak shared library to use as - backend. Set `library` to None to restore the default. - - """ - EspeakWrapper.set_library(library) - - @classmethod - def library(cls): - """Returns the espeak library used as backend - - The following precedence rule applies for library lookup: - - 1. As specified by BaseEspeakBackend.set_library() - 2. Or as specified by the environment variable - PHONEMIZER_ESPEAK_LIBRARY - 3. Or the default espeak library found on the system - - Raises - ------ - RuntimeError if the espeak library cannot be found or if the - environment variable PHONEMIZER_ESPEAK_LIBRARY is set to a - non-readable file - - """ - return EspeakWrapper.library() - - @classmethod - def is_available(cls) -> bool: - try: - EspeakWrapper() - except RuntimeError: # pragma: nocover - return False - return True - - @classmethod - def is_espeak_ng(cls) -> bool: - """Returns True if using espeak-ng, False otherwise""" - # espeak-ng starts with version 1.49 - return cls.version() >= (1, 49) - - @classmethod - def version(cls): - """Espeak version as a tuple (major, minor, patch) - - Raises - ------ - RuntimeError if BaseEspeakBackend.is_available() is False or if the - version cannot be extracted for some reason. - - """ - return EspeakWrapper().version - - @abc.abstractmethod - def _postprocess_line(self, line: str, num: int, - separator: Separator, strip: bool) -> str: - pass diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/espeak.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/espeak.py deleted file mode 100644 index 766af5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/espeak.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Espeak backend for the phonemizer""" - -import itertools -import re -from logging import Logger -from typing import Optional, Tuple, List, Union, Pattern - -from phonemizer.backend.espeak.base import BaseEspeakBackend -from phonemizer.backend.espeak.language_switch import ( - get_language_switch_processor, LanguageSwitch, BaseLanguageSwitch) -from phonemizer.backend.espeak.words_mismatch import ( - get_words_mismatch_processor, WordMismatch, BaseWordsMismatch) -from phonemizer.backend.espeak.wrapper import EspeakWrapper -from phonemizer.separator import Separator - - -class EspeakBackend(BaseEspeakBackend): - """Espeak backend for the phonemizer""" - # a regular expression to find phonemes stresses in espeak output - _ESPEAK_STRESS_RE = re.compile(r"[ˈˌ'-]+") - - # pylint: disable=too-many-arguments - def __init__(self, language: str, - punctuation_marks: Optional[Union[str, Pattern]] = None, - preserve_punctuation: bool = False, - with_stress: bool = False, - tie: Union[bool, str] = False, - language_switch: LanguageSwitch = 'keep-flags', - words_mismatch: WordMismatch = 'ignore', - logger: Optional[Logger] = None): - super().__init__( - language, punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, logger=logger) - - self._espeak.set_voice(language) - self._with_stress = with_stress - self._tie = self._init_tie(tie) - self._lang_switch: BaseLanguageSwitch = get_language_switch_processor( - language_switch, self.logger, self.language) - self._words_mismatch: BaseWordsMismatch = get_words_mismatch_processor( - words_mismatch, self.logger) - - @staticmethod - def _init_tie(tie) -> Optional[str]: - if not tie: - return None - - if tie is True: # default U+361 tie character - return 'Í¡' - - # non default tie charcacter - tie = str(tie) - if len(tie) != 1: - raise RuntimeError( - f'explicit tie must be a single charcacter but is {tie}') - return tie - - @staticmethod - def name(): - return 'espeak' - - @classmethod - def supported_languages(cls): - return { - voice.language: voice.name - for voice in EspeakWrapper().available_voices()} - - def _phonemize_aux(self, text, offset, separator, strip): - if self._tie is not None and separator.phone: - self.logger.warning( - 'cannot use ties AND phone separation, ' - 'ignoring phone separator') - - output = [] - lang_switches = [] - for num, line in enumerate(text, start=1): - line = self._espeak.text_to_phonemes(line, self._tie) - line, has_switch = self._postprocess_line( - line, num, separator, strip) - output.append(line) - if has_switch: - lang_switches.append(num + offset) - - return output, lang_switches - - def _process_stress(self, word): - if self._with_stress: - return word - # remove the stresses on phonemes - return re.sub(self._ESPEAK_STRESS_RE, '', word) - - def _process_tie(self, word: str, separator: Separator): - # NOTE a bug in espeak append ties to (en) flags so as (Í¡eÍ¡n). - # We do not correct it here. - if self._tie is not None and self._tie != 'Í¡': - # replace default 'Í¡' by the requested one - return word.replace('Í¡', self._tie) - return word.replace('_', separator.phone) - - def _postprocess_line(self, line: str, num: int, - separator: Separator, strip: bool) -> Tuple[str, bool]: - # espeak can split an utterance into several lines because - # of punctuation, here we merge the lines into a single one - line = line.strip().replace('\n', ' ').replace(' ', ' ') - - # due to a bug in espeak-ng, some additional separators can be - # added at the end of a word. Here a quick fix to solve that - # issue. See https://github.com/espeak-ng/espeak-ng/issues/694 - line = re.sub(r'_+', '_', line) - line = re.sub(r'_ ', ' ', line) - - line, has_switch = self._lang_switch.process(line) - if not line: - return '', has_switch - - out_line = '' - for word in line.split(' '): - word = self._process_stress(word.strip()) - if not strip and self._tie is None: - word += '_' - word = self._process_tie(word, separator) - out_line += word + separator.word - - if strip and separator.word: - # erase the last word separator from the line - out_line = out_line[:-len(separator.word)] - - return out_line, has_switch - - def _phonemize_preprocess(self, text: List[str]) -> Tuple[Union[str, List[str]], List]: - text, punctuation_marks = super()._phonemize_preprocess(text) - self._words_mismatch.count_text(text) - return text, punctuation_marks - - def _phonemize_postprocess(self, phonemized, punctuation_marks, separator: Separator, strip: bool): - text = phonemized[0] - switches = phonemized[1] - - self._words_mismatch.count_phonemized(text, separator) - self._lang_switch.warning(switches) - - phonemized = super()._phonemize_postprocess(text, punctuation_marks, separator, strip) - return self._words_mismatch.process(phonemized) - - @staticmethod - def _flatten(phonemized) -> List: - """Specialization of BaseBackend._flatten for the espeak backend - - From [([1, 2], ['a', 'b']), ([3],), ([4], ['c'])] to [[1, 2, 3, 4], - ['a', 'b', 'c']]. - - """ - flattened = [] - for i in range(len(phonemized[0])): - flattened.append( - list(itertools.chain( - c for chunk in phonemized for c in chunk[i]))) - return flattened diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/language_switch.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/language_switch.py deleted file mode 100644 index f094e73..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/language_switch.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Manages language switches for the espeak backend - -This module is used in phonemizer.backend.EspeakBackend and should be -considered private. - -It manages languages switches that occur during phonemization, where a part of -a text is phonemized in a language different from the target language. For -instance the sentence "j'aime le football" in French will be phonemized by -espeak as "Ê’É›m lÉ™ (en)fÊŠtbÉ”Ël(fr)", "football" be pronounced as an English -word. This may cause two issues to end users. First it introduces undesirable -(.) language switch flags. It may introduce extra phones that are not present -in the target language phoneset. - -This module implements 3 alternative solutions the user can choose when -initializing the espeak backend: -- 'keep-flags' preserves the language switch flags, -- 'remove-flags' removes the flags (.) but preserves the words with alternative - phoneset, -- 'remove-utterance' removes the utterances where flags are detected. - -""" - -import abc -import re -from logging import Logger -from typing import List, Tuple -from typing_extensions import TypeAlias, Literal - -LanguageSwitch: TypeAlias = Literal['keep-flags', 'remove-flags', 'remove-utterance'] - - -def get_language_switch_processor(mode: LanguageSwitch, logger: Logger, language: str) -> 'BaseLanguageSwitch': - """Returns a language switch processor initialized from `mode` - - The `mode` can be one of the following: - - 'keep-flags' to preserve the switch flags - - 'remove-flags' to suppress the switch flags - - 'remove-utterance' to suppress the entire utterance - - Raises a RuntimeError if the `mode` is unknown. - - """ - processors = { - 'keep-flags': KeepFlags, - 'remove-flags': RemoveFlags, - 'remove-utterance': RemoveUtterances} - - try: - return processors[mode](logger, language) - except KeyError: - raise RuntimeError( - f'mode "{mode}" invalid, must be in {", ".join(processors.keys())}' - ) from None - - -class BaseLanguageSwitch(abc.ABC): - """The base class for language switch processors - - Parameters - ---------- - logger (logging.Logger) : a logger instance to send warnings when language - switches are detected. - language (str) : the language code currently in use by the phonemizer, to - customize warning content - - """ - # a regular expression to find language switch flags in espeak output, - # Switches have the following form (here a switch from English to French): - # "something (fr)quelque chose(en) another thing". - _ESPEAK_FLAGS_RE = re.compile(r'\(.+?\)') - - def __init__(self, logger: Logger, language: str): - self._logger = logger - self._language = language - - @classmethod - def is_language_switch(cls, utterance: str) -> bool: - """Returns True is a language switch is present in the `utterance`""" - return bool(cls._ESPEAK_FLAGS_RE.search(utterance)) - - @classmethod - @abc.abstractmethod - def process(cls, utterance: str) -> Tuple[str, bool]: - """Detects and process language switches according to the mode - - This method is called on each utterance as a phonemization - post-processing step. - - Returns - ------- - processed_utterance (str) : the utterance either preserved, deleted (as - '') or with the switch removed - has_switch (bool): True if a language switch flag is found in the - `utterance` and False otherwise - - """ - - @abc.abstractmethod - def warning(self, switches: List[int]): - """Sends warnings to the logger with recorded language switches - - This method is called a single time at the very end of the - phonemization process. - - Parameters - ---------- - switches (list of int) : the line numbers where language switches has - been detected during phonemization - - """ - - -class KeepFlags(BaseLanguageSwitch): - """Preserves utterances even if language switch flags are present""" - - @classmethod - def process(cls, utterance: str) -> Tuple[str, bool]: - return utterance, cls.is_language_switch(utterance) - - def warning(self, switches: List[int]): - if not switches: - return - - nswitches = len(switches) - self._logger.warning( - '%s utterances containing language switches ' - 'on lines %s', nswitches, - ', '.join(str(switch) for switch in sorted(switches))) - self._logger.warning( - 'extra phones may appear in the "%s" phoneset', self._language) - self._logger.warning( - 'language switch flags have been kept ' - '(applying "keep-flags" policy)') - - -class RemoveFlags(BaseLanguageSwitch): - """Removes the language switch flags when detected""" - - @classmethod - def process(cls, utterance: str) -> Tuple[str, bool]: - if cls.is_language_switch(utterance): - # remove all the (lang) flags in the current utterance - return re.sub(cls._ESPEAK_FLAGS_RE, '', utterance), True - return utterance, False - - def warning(self, switches: List[int]): - if not switches: - return - - nswitches = len(switches) - self._logger.warning( - '%s utterances containing language switches ' - 'on lines %s', nswitches, - ', '.join(str(switch) for switch in sorted(switches))) - self._logger.warning( - 'extra phones may appear in the "%s" phoneset', self._language) - self._logger.warning( - 'language switch flags have been removed ' - '(applying "remove-flags" policy)') - - -class RemoveUtterances(BaseLanguageSwitch): - """Remove the entire utterance when a language switch flag is detected""" - - @classmethod - def process(cls, utterance: str) -> Tuple[str, bool]: - if cls.is_language_switch(utterance): - # drop the entire utterance - return '', True - return utterance, False - - def warning(self, switches: List[int]): - if not switches: - return - - nswitches = len(switches) - self._logger.warning( - 'removed %s utterances containing language switches ' - '(applying "remove-utterance" policy)', nswitches) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/mbrola.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/mbrola.py deleted file mode 100644 index 5ef15c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/mbrola.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Mbrola backend for the phonemizer""" - -import pathlib -import shutil -import sys -from logging import Logger -from pathlib import Path -from typing import Union, Optional, List, Dict - -from phonemizer.backend.espeak.base import BaseEspeakBackend -from phonemizer.backend.espeak.wrapper import EspeakWrapper -from phonemizer.separator import Separator - - -class EspeakMbrolaBackend(BaseEspeakBackend): - """Espeak-mbrola backend for the phonemizer""" - # this will be initialized once, at the first call to supported_languages() - _supported_languages = None - - def __init__(self, language: str, logger: Optional[Logger] = None): - super().__init__(language, logger=logger) - self._espeak.set_voice(language) - - @staticmethod - def name(): - return 'espeak-mbrola' - - @classmethod - def is_available(cls) -> bool: - """Mbrola backend is available for espeak>=1.49""" - return ( - BaseEspeakBackend.is_available() and - shutil.which('mbrola') and - BaseEspeakBackend.is_espeak_ng()) - - @classmethod - def _all_supported_languages(cls): - # retrieve the mbrola voices. This voices must be installed separately. - voices = EspeakWrapper().available_voices('mbrola') - return {voice.identifier[3:]: voice.name for voice in voices} - - @classmethod - def _is_language_installed(cls, language: str, data_path: Union[str, Path]) \ - -> bool: - """Returns True if the required mbrola voice is installed""" - # this is a reimplementation of LoadMbrolaTable from espeak - # synth_mbrola.h sources - voice = language[3:] # remove mb- prefix - - if pathlib.Path(data_path / 'mbrola' / voice).is_file(): - return True # pragma: nocover - - if sys.platform != 'win32': - candidates = [ - f'/usr/share/mbrola/{voice}', - f'/usr/share/mbrola/{voice}/{voice}', - f'/usr/share/mbrola/voices/{voice}'] - for candidate in candidates: - if pathlib.Path(candidate).is_file(): - return True - - return False - - @classmethod - def supported_languages(cls) -> Dict[str, str]: # pragma: nocover - """Returns the list of installed mbrola voices""" - if cls._supported_languages is None: - data_path = EspeakWrapper().data_path - cls._supported_languages = { - k: v for k, v in cls._all_supported_languages().items() - if cls._is_language_installed(k, data_path)} - return cls._supported_languages - - def _phonemize_aux(self, text: List[str], offset: int, - separator: Separator, strip: bool) -> List[str]: - output = [] - for num, line in enumerate(text, start=1): - line = self._espeak.synthetize(line) - line = self._postprocess_line(line, offset + num, separator, strip) - output.append(line) - return output - - def _postprocess_line(self, line: str, num: int, - separator: Separator, strip: bool) -> str: - # retrieve the phonemes with the correct SAMPA alphabet (but - # without word separation) - phonemes = ( - phn.split('\t')[0] for phn in line.split('\n') if phn.strip()) - phonemes = separator.phone.join(pho for pho in phonemes if pho != '_') - - if not strip: - phonemes += separator.phone - - return phonemes diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/voice.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/voice.py deleted file mode 100644 index d953939..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/voice.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Voice struct from Espeak API exposed to Python""" - -import ctypes - - -# This class can be a dataclass for compatibility with python-3.6 we don't use -# the dataclasses module. -class EspeakVoice: - """A helper class to expose voice structures within C and Python""" - - def __init__(self, name: str = '', language: str = '', identifier: str = ''): - self._name = name - self._language = language - self._identifier = identifier - - @property - def name(self): - """Voice name""" - return self._name - - @property - def language(self): - """Language code""" - return self._language - - @property - def identifier(self): - """Path to the voice file wrt espeak data path""" - return self._identifier - - def __eq__(self, other: 'EspeakVoice'): - return ( - self.name == other.name and - self.language == other.language and - self.identifier == other.identifier) - - def __hash__(self): - return hash((self.name, self.language, self.identifier)) - - class VoiceStruct(ctypes.Structure): # pylint: disable=too-few-public-methods - """A helper class to fetch voices information from the espeak library. - - The espeak_VOICE struct is defined in speak_lib.h from the espeak code. - Here we use only name (voice name), languages (language code) and - identifier (voice file) information. - - """ - _fields_ = [ - ('name', ctypes.c_char_p), - ('languages', ctypes.c_char_p), - ('identifier', ctypes.c_char_p)] - - def to_ctypes(self): - """Converts the Voice instance to an espeak ctypes structure""" - return self.VoiceStruct( - self.name.encode('utf8') if self.name else None, - self.language.encode('utf8') if self.language else None, - self.identifier.encode('utf8') if self.identifier else None) - - @classmethod - def from_ctypes(cls, struct: VoiceStruct): - """Returns a Voice instance built from an espeak ctypes structure""" - return cls( - name=(struct.name or b'').decode(), - # discard a useless char prepended by espeak - language=(struct.languages or b'0').decode()[1:], - identifier=(struct.identifier or b'').decode()) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/words_mismatch.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/words_mismatch.py deleted file mode 100644 index 30f206b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/words_mismatch.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Manages words count mismatches for the espeak backend""" - -import abc -import re -from logging import Logger -from typing import List, Tuple - -from typing_extensions import TypeAlias, Literal, Union - -from phonemizer.separator import Separator - - -WordMismatch: TypeAlias = Literal["warn", "ignore"] - - -def get_words_mismatch_processor(mode: WordMismatch, logger: Logger) -> 'BaseWordsMismatch': - """Returns a word count mismatch processor according to `mode` - - The `mode` can be one of the following: - - `ignore` to ignore words mismatches - - `warn` to display a warning on each mismatched utterance - - `remove` to remove any utterance containing a words mismatch - - Raises a RuntimeError if the `mode` is unknown. - - """ - processors = { - 'ignore': Ignore, - 'warn': Warn, - 'remove': Remove} - - try: - return processors[mode](logger) - except KeyError: - raise RuntimeError( - f'mode {mode} invalid, must be in {", ".join(processors.keys())}' - ) from None - - -class BaseWordsMismatch(abc.ABC): - """The base class of all word count mismatch processors""" - _RE_SPACES = re.compile(r'\s+') - - def __init__(self, logger: Logger): - self._logger = logger - self._count_txt = [] - self._count_phn = [] - - @classmethod - def _count_words( - cls, - text: List[str], - wordsep: Union[str, re.Pattern] = _RE_SPACES) -> List[int]: - """Return the number of words contained in each line of `text`""" - if not isinstance(wordsep, re.Pattern): - wordsep = re.escape(wordsep) - - return [ - len([w for w in re.split(wordsep, line.strip()) if w]) - for line in text] - - def _mismatched_lines(self) -> List[Tuple[int, int, int]]: - """Returns a list of (num_line, nwords_input, nwords_output) - - Consider only the lines where nwords_input != nwords_output. Raises a - RuntimeError if input and output do not have the same number of lines. - - """ - if len(self._count_txt) != len(self._count_phn): - raise RuntimeError( # pragma: nocover - f'number of lines in input and output must be equal, ' - f'we have: input={len(self._count_txt)}, ' - f'output={len(self._count_phn)}') - - return [ - (n, t, p) for n, (t, p) in - enumerate(zip(self._count_txt, self._count_phn)) - if t != p] - - def _resume(self, nmismatch: int, nlines: int): - """Logs a high level undetailed warning""" - if nmismatch: - self._logger.warning( - 'words count mismatch on %s%% of the lines (%s/%s)', - round(nmismatch / nlines, 2) * 100, nmismatch, nlines) - - def count_text(self, text: List[str]): - """Stores the number of words in each input line""" - self._count_txt = self._count_words(text) - - def count_phonemized(self, text: List[str], separator: Separator): - """Stores the number of words in each output line""" - self._count_phn = self._count_words(text, separator.word) - - @abc.abstractmethod - def process(self, text: List[str]) -> List[str]: - """Detects and process word count misatches according to the mode - - This method is called at the very end of phonemization, during - post-processing. - - """ - - -class Ignore(BaseWordsMismatch): - """Ignores word count mismatches""" - - def process(self, text: List[str]) -> List[str]: - self._resume(len(self._mismatched_lines()), len(text)) - return text - - -class Warn(BaseWordsMismatch): - """Warns on every mismatch detected""" - - def process(self, text: List[str]) -> List[str]: - mismatch = self._mismatched_lines() - for num, ntxt, nphn in mismatch: - self._logger.warning( - 'words count mismatch on line %s ' - '(expected %s words but get %s)', - num + 1, ntxt, nphn) - - self._resume(len(mismatch), len(text)) - return text - - -class Remove(BaseWordsMismatch): - """Removes any utterance containing a word count mismatch""" - - def process(self, text: List[str]) -> List[str]: - mismatch = [line[0] for line in self._mismatched_lines()] - self._resume(len(mismatch), len(text)) - self._logger.warning('removing the mismatched lines') - - for index in mismatch: - text[index] = '' - return text diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/wrapper.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/wrapper.py deleted file mode 100644 index 84a79f5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/espeak/wrapper.py +++ /dev/null @@ -1,370 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Wrapper on espeak-ng library""" - -import ctypes -import ctypes.util -import functools -import os -import pathlib -import sys -import tempfile -import weakref -from typing import Tuple, Dict - -from phonemizer.backend.espeak.api import EspeakAPI -from phonemizer.backend.espeak.voice import EspeakVoice - - -class EspeakWrapper: - """Wrapper on espeak shared library - - The aim of this wrapper is not to be exhaustive but to encapsulate the - espeak functions required for phonemization. It relies on a espeak shared - library (*.so on Linux, *.dylib on Mac and *.dll on Windows) that must be - installed on the system. - - Use the function `EspeakWrapper.set_library()` before instanciation to - customize the library to use. - - Raises - ------ - RuntimeError if the espeak shared library cannot be loaded - - """ - # a static variable used to overload the default espeak library installed - # on the system. The user can choose an alternative espeak library with - # the method EspeakWrapper.set_library(). - _ESPEAK_LIBRARY = None - - def __init__(self): - # the following attributes are accessed through properties and are - # lazily initialized - self._version: Tuple[int, ...] = None - self._data_path = None - self._voice = None - - # load the espeak API - self._espeak = EspeakAPI(self.library()) - - # lazy loading of attributes only required for the synthetize method - self._libc_ = None - self._tempfile_ = None - - @property - def _libc(self): - if self._libc_ is None: - self._libc_ = ( - ctypes.windll.msvcrt if sys.platform == 'win32' else - ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))) - return self._libc_ - - @property - def _tempfile(self): - if self._tempfile_ is None: - # this will automatically removed at exit - # pylint: disable=consider-using-with - self._tempfile_ = tempfile.NamedTemporaryFile() - weakref.finalize(self._tempfile_, self._tempfile_.close) - return self._tempfile_ - - def __getstate__(self): - """For pickling, when phonemizing on multiple jobs""" - return { - 'version': self._version, - 'data_path': self._data_path, - 'voice': self._voice} - - def __setstate__(self, state: Dict): - """For unpickling, when phonemizing on multiple jobs""" - self.__init__() - self._version = state['version'] - self._data_path = state['data_path'] - self._voice = state['voice'] - if self._voice: - if 'mb' in self._voice.identifier: # mbrola voice - self.set_voice(self._voice.identifier[3:]) - else: - self.set_voice(self._voice.language) - - @classmethod - def set_library(cls, library: str): - """Sets the espeak backend to use `library` - - If this is not set, the backend uses the default espeak shared library - from the system installation. - - Parameters - ---------- - library (str or None) : the path to the espeak shared library to use as - backend. Set `library` to None to restore the default. - - """ - cls._ESPEAK_LIBRARY = library - - @classmethod - def library(cls): - """Returns the espeak library used as backend - - The following precedence rule applies for library lookup: - - 1. As specified by BaseEspeakBackend.set_library() - 2. Or as specified by the environment variable - PHONEMIZER_ESPEAK_LIBRARY - 3. Or the default espeak library found on the system - - Raises - ------ - RuntimeError if the espeak library cannot be found or if the - environment variable PHONEMIZER_ESPEAK_LIBRARY is set to a - non-readable file - - """ - if cls._ESPEAK_LIBRARY: - return cls._ESPEAK_LIBRARY - - if 'PHONEMIZER_ESPEAK_LIBRARY' in os.environ: - library = pathlib.Path(os.environ['PHONEMIZER_ESPEAK_LIBRARY']) - if not (library.is_file() and os.access(library, os.R_OK)): - raise RuntimeError( # pragma: nocover - f'PHONEMIZER_ESPEAK_LIBRARY={library} ' - f'is not a readable file') - return library.resolve() - - library = ( - ctypes.util.find_library('espeak-ng') or - ctypes.util.find_library('espeak')) - if not library: # pragma: nocover - raise RuntimeError( - 'failed to find espeak library') - return library - - def _fetch_version_and_path(self): - """Initializes version and dapa path from the espeak library""" - version, data_path = self._espeak.info() - - # pylint: disable=no-member - self._data_path = pathlib.Path(data_path.decode()) - if not self._data_path.is_dir(): # pragma: nocover - raise RuntimeError('failed to retrieve espeak data directory') - - # espeak-1.48 appends the release date to version number, here we - # simply ignore it - version = version.decode().strip().split(' ')[0].replace('-dev', '') - self._version = tuple(int(v) for v in version.split('.')) - - @property - def version(self) -> Tuple[int, int, int]: - """The espeak version as a tuple of integers (major, minor, patch)""" - if self._version is None: - self._fetch_version_and_path() - return self._version - - @property - def library_path(self): - """The espeak library as a pathlib.Path instance""" - return self._espeak.library_path - - @property - def data_path(self): - """The espeak data directory as a pathlib.Path instance""" - if self._data_path is None: - self._fetch_version_and_path() - return self._data_path - - @property - def voice(self): - """The configured voice as an EspeakVoice instance - - If `set_voice` has not been called, returns None - - """ - return self._voice - - @functools.lru_cache(maxsize=None) - def available_voices(self, name=None): - """Voices available for phonemization, as a list of `EspeakVoice`""" - if name: - name = EspeakVoice(language=name).to_ctypes() - voices = self._espeak.list_voices(name or None) - - index = 0 - available_voices = [] - # voices is an array to pointers, terminated by None - while voices[index]: - voice = voices[index].contents - available_voices.append(EspeakVoice( - name=os.fsdecode(voice.name).replace('_', ' '), - language=os.fsdecode(voice.languages)[1:], - identifier=os.fsdecode(voice.identifier))) - index += 1 - return available_voices - - def set_voice(self, voice_code): - """Setup the voice to use for phonemization - - Parameters - ---------- - voice_code (str) : Must be a valid language code that is actually - supported by espeak - - Raises - ------ - RuntimeError if the required voice cannot be initialized - - """ - if 'mb' in voice_code: - # this is an mbrola voice code. Select the voice by using - # identifier in the format 'mb/{voice_code}' - available = { - voice.identifier[3:]: voice.identifier - for voice in self.available_voices('mbrola')} - else: - # this are espeak voices. Select the voice using it's attached - # language code. Consider only the first voice of a given code as - # they are sorted by relevancy - available = {} - for voice in self.available_voices(): - if voice.language not in available: - available[voice.language] = voice.identifier - - try: - voice_name = available[voice_code] - except KeyError: - raise RuntimeError(f'invalid voice code "{voice_code}"') from None - - if self._espeak.set_voice_by_name(voice_name.encode('utf8')) != 0: - raise RuntimeError( # pragma: nocover - f'failed to load voice "{voice_code}"') - - voice = self._get_voice() - if not voice: # pragma: nocover - raise RuntimeError(f'failed to load voice "{voice_code}"') - self._voice = voice - - def _get_voice(self): - """Returns the current voice used for phonemization - - If no voice has been set up, returns None. - - """ - voice = self._espeak.get_current_voice() - if voice.name: - return EspeakVoice.from_ctypes(voice) - return None # pragma: nocover - - def text_to_phonemes(self, text: str, tie: bool = False) -> str: - """Translates a text into phonemes, must call set_voice() first. - - This method is used by the Espeak backend. Wrapper on the - espeak_TextToPhonemes function. - - Parameters - ---------- - text (str) : the text to phonemize - - tie (bool, optional) : When True use a 'Í¡' character between - consecutive characters of a single phoneme. Else separate phoneme - with '_'. This option requires espeak>=1.49. Default to False. - - Returns - ------- - phonemes (str) : the phonemes for the text encoded in IPA, with '_' as - phonemes separator (excepted if ``tie`` is True) and ' ' as word - separator. - - """ - if self.voice is None: # pragma: nocover - raise RuntimeError('no voice specified') - - if tie and self.version <= (1, 48, 3): - raise RuntimeError( # pragma: nocover - 'tie option only compatible with espeak>=1.49') - - # from Python string to C void** (a pointer to a pointer to chars) - text_ptr = ctypes.pointer(ctypes.c_char_p(text.encode('utf8'))) - - # input text is encoded as UTF8 - text_mode = 1 - - # output phonemes in IPA and separated by _, or with a tie character if - # required. See comments for the function espeak_TextToPhonemes in - # speak_lib.h of the espeak sources for details. - if self.version <= (1, 48, 3): # pragma: nocover - phonemes_mode = 0x03 | 0x01 << 4 - elif tie: - phonemes_mode = 0x02 | 0x01 << 7 | ord('Í¡') << 8 - else: - phonemes_mode = ord('_') << 8 | 0x02 - - result = [] - while text_ptr.contents.value is not None: - phonemes = self._espeak.text_to_phonemes( - text_ptr, text_mode, phonemes_mode) - if phonemes: - result.append(phonemes.decode()) - return ' '.join(result) - - def synthetize(self, text: str): - """Translates a text into phonemes, must call set_voice() first. - - Only compatible with espeak>=1.49. This method is used by the - EspeakMbrola backend. Wrapper on the espeak_Synthesize function. - - Parameters - ---------- - text (str) : the text to phonemize - - Returns - ------- - phonemes (str) : the phonemes for the text encoded in SAMPA, with '_' - as phonemes separator and no word separation. - - """ - - if self.version < (1, 49): # pragma: nocover - raise RuntimeError('not compatible with espeak<=1.48') - if self.voice is None: # pragma: nocover - raise RuntimeError('no voice specified') - - # init libc fopen and fclose functions - self._libc.fopen.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self._libc.fopen.restype = ctypes.c_void_p - self._libc.fclose.argtypes = [ctypes.c_void_p] - self._libc.fclose.restype = ctypes.c_int - - # output phonemes in SAMPA and separated by _. Write the result to a - # tempfile which is read back after phonemization (seems not possible - # to redirect to stdout). See comments for the function - # espeak_SetPhonemeTrace in speak_lib.h of the espeak sources for - # details. - self._tempfile.truncate(0) - file_p = self._libc.fopen( - self._tempfile.name.encode(), - self._tempfile.mode.encode()) - - self._espeak.set_phoneme_trace(0x01 << 4 | ord('_') << 8, file_p) - status = self._espeak.synthetize( - ctypes.c_char_p(text.encode('utf8')), - ctypes.c_size_t(len(text) + 1), - ctypes.c_uint(0x01)) - self._libc.fclose(file_p) # because flush does not work... - - if status != 0: # pragma: nocover - raise RuntimeError('failed to synthetize') - - self._tempfile.seek(0) - phonemized = self._tempfile.read().decode().strip() - return phonemized diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/__init__.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/__init__.py deleted file mode 100644 index af3b51b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonologizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonologizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonologizer. If not, see . -"""Phonemizer module for festival backend implementation""" diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/festival.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/festival.py deleted file mode 100644 index dbaae48..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/festival.py +++ /dev/null @@ -1,334 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Festival backend for the phonemizer""" - -import os -import pathlib -import re -import shlex -import shutil -import subprocess -import sys -import tempfile -from logging import Logger -from pathlib import Path -from typing import Optional, Dict, List, IO, Union, Pattern - -from phonemizer.backend.base import BaseBackend -from phonemizer.backend.festival import lispy -from phonemizer.separator import Separator -from phonemizer.utils import get_package_resource, version_as_tuple - - -class FestivalBackend(BaseBackend): - """Festival backend for the phonemizer""" - # a static variable used to overload the default festival binary installed - # on the system. The user can choose an alternative festival binary with - # the method FestivalBackend.set_executable(). - _FESTIVAL_EXECUTABLE = None - - def __init__(self, language: str, - punctuation_marks: Optional[Union[str, Pattern]] = None, - preserve_punctuation: bool = False, - logger: Optional[Logger] = None): - super().__init__( - language, - punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, - logger=logger) - - self.logger.debug('festival executable is %s', self.executable()) - - # the Scheme script to be send to festival - script_file = get_package_resource('festival/phonemize.scm') - with open(script_file, 'r') as fscript: - self._script = fscript.read() - self.logger.debug('loaded %s', script_file) - - @staticmethod - def name(): - return 'festival' - - @classmethod - def set_executable(cls, executable: str): - """Sets the festival backend to use `executable` - - If this is not set, the backend uses the default festival executable - from the system installation. - - Parameters - ---------- - executable (str) : the path to the festival executable to use as - backend. Set `executable` to None to restore the default. - - Raises - ------ - RuntimeError if `executable` is not an executable file. - - """ - if executable is None: - cls._FESTIVAL_EXECUTABLE = None - return - - executable = pathlib.Path(executable) - if not (executable.is_file() and os.access(executable, os.X_OK)): - raise RuntimeError( - f'{executable} is not an executable file') - - cls._FESTIVAL_EXECUTABLE = executable.resolve() - - @classmethod - def executable(cls) -> Path: - """Returns the absolute path to the festival executable used as backend - - The following precedence rule applies for executable lookup: - - 1. As specified by FestivalBackend.set_executable() - 2. Or as specified by the environment variable - PHONEMIZER_FESTIVAL_EXECUTABLE - 3. Or the default 'festival' binary found on the system with ``shutil.which('festival')`` - - - Raises - ------ - RuntimeError - if the festival executable cannot be found or if the - environment variable PHONEMIZER_FESTIVAL_EXECUTABLE is set to a - non-executable file - - """ - if cls._FESTIVAL_EXECUTABLE: - return cls._FESTIVAL_EXECUTABLE - - if 'PHONEMIZER_FESTIVAL_EXECUTABLE' in os.environ: - executable = pathlib.Path(os.environ[ - 'PHONEMIZER_FESTIVAL_EXECUTABLE']) - if not ( - executable.is_file() - and os.access(executable, mode=os.X_OK) - ): - raise RuntimeError( - f'PHONEMIZER_FESTIVAL_EXECUTABLE={executable} ' - f'is not an executable file') - return executable.resolve() - - executable = shutil.which('festival') - if not executable: # pragma: nocover - raise RuntimeError( - 'failed to find festival executable') - return Path(executable).resolve() - - @classmethod - def is_available(cls): - """True if the festival executable is available, False otherwise""" - try: - cls.executable() - except RuntimeError: # pragma: nocover - return False - return True - - @classmethod - def version(cls): - """Festival version as a tupe of integers (major, minor, patch) - - Raises - ------ - RuntimeError if FestivalBackend.is_available() is False or if the - version cannot be extracted for some reason. - - """ - - festival = cls.executable() - - # the full version version string includes extra information - # we don't need - long_version = subprocess.check_output( - [festival, '--version']).decode('latin1').strip() - - # extract the version number with a regular expression - festival_version_re = r'.* ([0-9\.]+[0-9]):' - try: - version = re.match(festival_version_re, long_version).group(1) - except AttributeError: - raise RuntimeError( - f'cannot extract festival version from {festival}') from None - - return version_as_tuple(version) - - @staticmethod - def supported_languages() -> Dict[str, str]: - """A dictionnary of language codes -> name supported by festival - - Actually only en-us (American English) is supported. - - """ - return {'en-us': 'english-us'} - - # pylint: disable=unused-argument - def _phonemize_aux(self, text: List[str], offset: int, separator: Separator, strip: bool) -> List[str]: - """Return a phonemized version of `text` with festival - - This function is a wrapper on festival, a text to speech - program, allowing simple phonemization of some English - text. The US phoneset we use is the default one in festival, - as described at http://www.festvox.org/bsv/c4711.html - - Any opening and closing parenthesis in `text` are removed, as - they interfer with the Scheme expression syntax. Moreover - double quotes are replaced by simple quotes because double - quotes denotes utterances boundaries in festival. - - Parsing a ill-formed Scheme expression during post-processing - (typically with unbalanced parenthesis) raises an IndexError. - - """ - text = self._preprocess(text) - if len(text) == 0: - return [] - text = self._process(text) - text = self._postprocess(text, separator, strip) - return text - - @staticmethod - def _double_quoted(line: str) -> str: - """Return the string `line` surrounded by double quotes""" - return '"' + line + '"' - - @staticmethod - def _cleaned(line: str): - """Remove 'forbidden' characters from the line""" - # special case (very unlikely but causes a crash in festival) - # where a line is only made of ' - if set(line) == set("'"): - line = '' - - # remove forbidden characters (reserved for scheme, ie festival - # scripting language) - return line.replace('"', '').replace('(', '').replace(')', '').strip() - - @classmethod - def _preprocess(cls, text: List[str]): - """Returns the contents of `text` formatted for festival input - - This function adds double quotes to begining and end of each - line in text, if not already presents. The returned result is - a multiline string. Empty lines in inputs are ignored. - - """ - cleaned_text = ( - cls._cleaned(line) for line in text if line != '') - - return '\n'.join( - cls._double_quoted(line) for line in cleaned_text if line != '') - - def _process(self, text: str): - """Return the raw phonemization of `text` - - This function delegates to festival the text analysis and - syllabic structure extraction. - - Return a string containing the "SylStructure" relation tree of - the text, as a scheme expression. - - """ - with tempfile.NamedTemporaryFile('w+', delete=False) as data: - try: - # save the text as a tempfile - data.write(text) - data.close() - - # fix the path name for windows - name = data.name - if sys.platform == 'win32': # pragma: nocover - name = name.replace('\\', '\\\\') - - with tempfile.NamedTemporaryFile('w+', delete=False) as scm: - try: - scm.write(self._script.format(name)) - scm.close() - - cmd = f'{self.executable()} -b {scm.name}' - if self.logger: - self.logger.debug('running %s', cmd) - - # redirect stderr to a tempfile and displaying it only - # on errors. Messages are something like: "UniSyn: - # using default diphone ax-ax for y-pau". This is - # related to wave synthesis (done by festival during - # phonemization). - with tempfile.TemporaryFile('w+') as fstderr: - return self._run_festival(cmd, fstderr) - finally: - os.remove(scm.name) - finally: - os.remove(data.name) - - @staticmethod - def _run_festival(cmd: str, fstderr: IO) -> str: - """Runs the festival command for phonemization - - Returns the raw phonemized output (need to be postprocesses). Raises a - RuntimeError if festival fails. - - """ - try: - output = subprocess.check_output( - shlex.split(cmd, posix=False), stderr=fstderr) - - # festival seems to use latin1 and not utf8 - return re.sub(' +', ' ', output.decode('latin1')) - - except subprocess.CalledProcessError as err: # pragma: nocover - fstderr.seek(0) - raise RuntimeError( - f'Command "{cmd}" returned exit status {err.returncode}, ' - f'output is:\n{fstderr.read()}') from None - - @staticmethod - def _postprocess_syll(syll: List[str], separator: Separator, strip: bool) -> str: - """Parse a syllable from festival to phonemized output""" - sep = separator.phone - out = (phone[0][0].replace('"', '') for phone in syll[1:]) - out = sep.join(o for o in out if o != '') - return out if strip else out + sep - - @classmethod - def _postprocess_word(cls, word: List[List[str]], separator: Separator, strip: bool) -> str: - """Parse a word from festival to phonemized output""" - sep = separator.syllable - out = sep.join( - cls._postprocess_syll(syll, separator, strip) - for syll in word[1:]) - return out if strip else out + sep - - @classmethod - def _postprocess_line(cls, line: str, separator, strip: bool) -> str: - """Parse a line from festival to phonemized output""" - sep = separator.word - out = [] - for word in lispy.parse(line): - word = cls._postprocess_word(word, separator, strip) - if word != '': - out.append(word) - out = sep.join(out) - - return out if strip else out + sep - - @classmethod - def _postprocess(cls, tree: str, separator: Separator, strip: bool) -> List[str]: - """Conversion from festival syllable tree to desired format""" - return [cls._postprocess_line(line, separator, strip) - for line in tree.split('\n') - if line not in ['', '(nil nil nil)']] diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/lispy.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/lispy.py deleted file mode 100644 index 7931f98..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/festival/lispy.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Parse a Scheme expression as a nested list - -The main function of this module is lispy.parse, other ones should be -considered private. This module is a dependency of the festival -backend. - -From http://www.norvig.com/lispy.html - -""" -from typing import List, Union - - -def parse(program: str): - """Read a Scheme expression from a string - - Return a nested list - - Raises an IndexError if the expression is not valid scheme - (unbalanced parenthesis). - - >>> parse('(+ 2 (* 5 2))') - ['+', '2', ['*', '5', '2']] - - """ - return _read_from_tokens(_tokenize(program)) - - -def _tokenize(chars: str) -> List[str]: - """Convert a string of characters into a list of tokens.""" - return chars.replace('(', ' ( ').replace(')', ' ) ').split() - - -Expr = Union[str, List['Expr']] - - -def _read_from_tokens(tokens: List[str]) -> Expr: - """Read an expression from a sequence of tokens""" - if len(tokens) == 0: # pragma: nocover - raise SyntaxError('unexpected EOF while reading') - - token = tokens.pop(0) - if token == '(': - expr = [] - while tokens[0] != ')': - expr.append(_read_from_tokens(tokens)) - tokens.pop(0) # pop off ')' - return expr - - if token == ')': # pragma: nocover - raise SyntaxError('unexpected )') - - return token diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/segments.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/segments.py deleted file mode 100644 index 201450c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/backend/segments.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Segments backend for the phonemizer""" - -import pathlib -from logging import Logger -from typing import Optional, Dict, List, Union, Pattern - -import segments - -from phonemizer.backend.base import BaseBackend -from phonemizer.separator import Separator -from phonemizer.utils import get_package_resource, version_as_tuple - - -class SegmentsBackend(BaseBackend): - """Segments backends for the phonemizer - - The phonemize method will raise a ValueError when parsing an - unknown morpheme. - - """ - - def __init__(self, language: str, - punctuation_marks: Optional[Union[str, Pattern]] = None, - preserve_punctuation: bool = False, - logger: Optional[Logger] = None): - # will be initialized in _init_language() from super().__init__() - self._tokenizer: Optional[segments.Tokenizer] = None - super().__init__( - language, - punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, - logger=logger) - - def _init_language(self, language): - # load the grapheme to phoneme mapping - profile = self._load_g2p_profile(language) - self._tokenizer = segments.Tokenizer(profile=profile) - - # this is the language code - return pathlib.Path(language).stem - - @staticmethod - def name(): - return 'segments' - - @classmethod - def version(cls): - return version_as_tuple(segments.__version__) - - @classmethod - def is_available(cls): - return True - - @staticmethod - def supported_languages(): - """Returns a dict of language: file supported by the segments backend - - The supported languages have a grapheme to phoneme conversion file - bundled with phonemizer. Users can also use their own file as - parameter of the phonemize() function. - - """ - # directory phonemizer/share/segments - directory = get_package_resource('segments') - - # supported languages are files with the 'g2p' extension - return {g2p.stem: g2p - for g2p in directory.iterdir() if g2p.suffix == '.g2p'} - - @classmethod - def is_supported_language(cls, language: str) -> bool: - if pathlib.Path(language).is_file(): - try: - cls._load_g2p_profile(language) - return True - except RuntimeError: - return False - return language in cls.supported_languages() - - @classmethod - def _load_g2p_profile(cls, language: str) -> segments.Profile: - """Returns a segments profile from a `language`""" - # make sure the g2p file exists - if not pathlib.Path(language).is_file(): - try: - language = cls.supported_languages()[language] - except KeyError: - raise RuntimeError( - f'grapheme to phoneme file not found: ' - f'{language}') from None - - # load the mapping grapheme -> phoneme from the file, make sure all - # lines are well formatted - g2p: Dict[str, str] = {} - with open(language, 'r', encoding='utf8') as flang: - for num, line in enumerate(flang): - elts = line.strip().split() - if not len(elts) == 2: - raise RuntimeError( - 'grapheme to phoneme file, line {} must have 2 rows ' - 'but have {}: {}'.format(num + 1, len(elts), language)) - g2p[elts[0]] = elts[1] - - # build the segments profile from the g2p mapping - return segments.Profile( - *[{'Grapheme': k, 'mapping': v} for k, v in g2p.items()]) - - # pylint: disable=unused-argument - def _phonemize_aux(self, text: List[str], offset: int, separator: Separator, strip: bool) -> List[str]: - # tokenize the input text per utterance - phonemized = ( - self._tokenizer(line, column='mapping', errors='strict') - for line in text) - - # the output of segments is always strip, so we need to add - # token separation at the end when strip is False. - if not strip: - # add word separator at end of utterance - phonemized = (p + ' # ' for p in phonemized) - # add phoneme separator at end of word - phonemized = (p.replace(' # ', ' # ') for p in phonemized) - - # replace default separators by our custom ones - phonemized = (p.replace(' # ', '#') for p in phonemized) - phonemized = (p.replace(' ', separator.phone) for p in phonemized) - phonemized = (p.replace('#', separator.word) for p in phonemized) - - # return the result as a list of utterances - return list(phonemized) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/logger.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/logger.py deleted file mode 100644 index a823dae..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/logger.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Logging facilities for the phonemizer""" - -import logging -import sys -from logging import Logger - - -def get_logger(verbosity: str = 'quiet', name: str = 'phonemizer') -> Logger: - """Returns a configured logging.Logger instance - - The logger is configured to output messages on the standard error stream - (stderr). - - Parameters - ---------- - verbosity (str) : The level of verbosity, must be 'verbose' (displays - debug/info and warning messages), 'normal' (warnings only) or 'quiet' (do - not display anything). - name (str) : The logger name, default to 'phonemizer' - - Raises - ------ - RuntimeError if `verbosity` is not 'normal', 'verbose', or 'quiet'. - - """ - # make sure the verbosity argument is valid - valid_verbosity = ['normal', 'verbose', 'quiet'] - if verbosity not in valid_verbosity: - raise RuntimeError( - f'verbosity is {verbosity} but must be in ' - f'{", ".join(valid_verbosity)}') - - logger = logging.getLogger(name) - - # setup output to stderr - logger.handlers = [] - handler = logging.StreamHandler(sys.stderr) - - # setup verbosity level - logger.setLevel(logging.WARNING) - if verbosity == 'verbose': - logger.setLevel(logging.DEBUG) - elif verbosity == 'quiet': - handler = logging.NullHandler() - - # setup messages format - handler.setFormatter(logging.Formatter('[%(levelname)s] %(message)s')) - logger.addHandler(handler) - return logger diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/main.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/main.py deleted file mode 100644 index be27d3f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/main.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Command-line phonemizer tool, have a 'phonemizer --help' to get in""" - -import argparse -import os -import sys -import re - -from phonemizer import phonemize, separator, version, logger, punctuation -from phonemizer.backend import BACKENDS - - -class CatchExceptions: # pragma: nocover - """Decorator wrapping a function in a try/except block - - When an exception occurs, display a user friendly message on - standard output before exiting with error code 1. - - The detected exceptions are ValueError, OSError, RuntimeError, - AssertionError and KeyboardInterrupt. - - Parameters - ---------- - function : - The function to wrap in a try/except block - - """ - def __init__(self, function): - self.function = function - - def __call__(self): - """Executes the wrapped function and catch common exceptions""" - try: - self.function() - - except (IOError, ValueError, OSError, - RuntimeError, AssertionError) as err: - self.exit('fatal error: {}'.format(err)) - - except KeyboardInterrupt: - self.exit('keyboard interruption, exiting') - - @staticmethod - def exit(msg): - """Write `msg` on stderr and exit with error code 1""" - sys.stderr.write(msg.strip() + '\n') - sys.exit(1) - - -def parse_args(): - """Argument parser for the phonemization script""" - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description='''Multilingual text to phonemes converter - -The 'phonemize' program allows simple phonemization of words and texts -in many language using four backends: espeak, espeak-mbrola, festival -and segments. - -- espeak is a text-to-speech software supporting multiple languages - and IPA (International Phonetic Alphabet) output. See - http://espeak.sourceforge.net or - https://github.com/espeak-ng/espeak-ng - -- espeak-mbrola uses the SAMPA phonetic alphabet, it requires mbrola to be - installed as well as additional mbrola voices. It does not support word or - syllable tokenization. See - https://github.com/espeak-ng/espeak-ng/blob/master/docs/mbrola.md - -- festival is also a text-to-speech software. Currently only American - English is supported and festival uses a custom phoneset - (http://www.festvox.org/bsv/c4711.html), but festival is the only - backend supporting tokenization at the syllable - level. See http://www.cstr.ed.ac.uk/projects/festival - -- segments is a Unicode tokenizer that build a phonemization from a - grapheme to phoneme mapping provided as a file by the user. See - https://github.com/cldf/segments. - -See the '--list-languages' option below for details on the languages -supported by each backend. - -''', - epilog=''' -Examples: - -* Phonemize a US English text with espeak - - $ echo 'hello world' | phonemize -l en-us -b espeak - hÉ™loÊŠ wÉœËld - -* Phonemize a US English text with festival - - $ echo 'hello world' | phonemize -l en-us -b festival - hhaxlow werld - -* Phonemize a Japanese text with segments - - $ echo 'konnichiwa tsekai' | phonemize -l japanese -b segments - konnitʃiwa tÍ¡sekai - -* Add a separator between phones - - $ echo 'hello world' | phonemize -l en-us -b festival -p '-' --strip - hh-ax-l-ow w-er-l-d - -* Phonemize some French text file using espeak - - $ phonemize -l fr-fr -b espeak text.txt -o phones.txt - ''') - - # general arguments - parser.add_argument( - '-V', '--version', - action='store_true', - help='show version information and exit.') - - group = parser.add_mutually_exclusive_group() - group.add_argument( - '-v', '--verbose', - action='store_true', - help='write all log messages to stderr ' - '(displays only warnings by default).') - group.add_argument( - '-q', '--quiet', - action='store_true', - help='do not display any log message, even warnings.') - - parser.add_argument( - '-j', '--njobs', - type=int, metavar='', default=1, - help='number of parallel jobs, default is %(default)s.') - - # input/output arguments - group = parser.add_argument_group('input/output') - group.add_argument( - 'input', - default=sys.stdin, nargs='?', metavar='', - help='input text file to phonemize, if not specified read from stdin.') - - group.add_argument( - '-o', '--output', - default=sys.stdout, metavar='', - help='output text file to write, if not specified write to stdout.') - - group.add_argument( - '--prepend-text', - default=False, const=True, nargs='?', metavar='', - help='''prepend each line of the phonemized output text with its - matching input text. If a string is specified as option value, use it - as field separator, else use one of "|", "||", "|||", "||||" by - selecting the first one that is not configured as a token separator - (see -p/-s/-w options).''') - - group.add_argument( - '--preserve-empty-lines', - action='store_true', - help='''preserve the empty lines in the phonemized output, default is - to remove them.''') - - group = parser.add_argument_group('backends') - group.add_argument( - '-b', '--backend', - metavar='', default=None, - choices=['espeak', 'espeak-mbrola', 'festival', 'segments'], - help="""the phonemization backend, must be 'espeak', 'espeak-mbrola', - 'festival' or 'segments'. Default is 'espeak'.""") - - group.add_argument( - '-L', '--list-languages', - action='store_true', - help="""list available languages (and exit) for the specified backend, - or for all backends if none selected.""") - - group = parser.add_argument_group('language') - group.add_argument( - '-l', '--language', - metavar='', default='en-us', - help='''the language code of the input text, use '--list-languages' - for a list of supported languages. Default is %(default)s.''') - - group = parser.add_argument_group('token separators') - group.add_argument( - '-p', '--phone-separator', - metavar='', default=separator.default_separator.phone, - help='phone separator, default is "%(default)s".') - - group.add_argument( - '-w', '--word-separator', - metavar='', default=separator.default_separator.word, - help='''word separator, not valid for espeak-mbrola backend, - default is "%(default)s".''') - - group.add_argument( - '-s', '--syllable-separator', - metavar='', default=separator.default_separator.syllable, - help='''syllable separator, only valid for festival backend, - this option has no effect if another backend is used. - Default is "%(default)s".''') - - group.add_argument( - '--strip', - action='store_true', - help='removes the end separators in phonemized tokens.') - - group = parser.add_argument_group('specific to espeak backend') - try: - espeak_library = BACKENDS['espeak'].library() - except RuntimeError: # pragma: nocover - espeak_library = None - - group.add_argument( - '--espeak-library', - default=None, type=str, metavar='', - help=f'''the path to the espeak shared library to use (*.so on Linux, - *.dylib on Mac and *.dll on Windows, useful to overload the default - espeak version installed on the system). Default to - {espeak_library}. This path can also be specified - using the PHONEMIZER_ESPEAK_LIBRARY environment variable.''') - group.add_argument( - '--tie', - nargs='?', default=False, const=True, metavar='', - help='''when the option is set, use a tie character within multi-letter - phoneme names, default to U+361 (as in d͡ʒ), 'z' means ZWJ character, - only compatible with espeak>1.48 and incompatible with the - -p/--phone-separator option''') - group.add_argument( - '--with-stress', - action='store_true', - help='''when the option is set, the stresses on phonemes are present - (stresses characters are ˈ'ËŒ). By default stresses are removed.''') - group.add_argument( - '--language-switch', - default='keep-flags', - choices=['keep-flags', 'remove-flags', 'remove-utterance'], - help="""espeak can pronounce some words in another language (typically - English) when phonemizing a text. This option setups the policy to use - when such a language switch occurs. Three values are available: - 'keep-flags' (the default), 'remove-flags' or 'remove-utterance'. The - 'keep-flags' policy keeps the language switching flags, for example - (en) or (jp), in the output. The 'remove-flags' policy removes them and - the 'remove-utterance' policy removes the whole line of text including - a language switch.""") - group.add_argument( - '--words-mismatch', - default='ignore', choices=['ignore', 'warn', 'remove'], - help="""espeak can join two consecutive words or drop some words, - yielding a word count mismatch between orthographic and phonemized - text. This option setups the policy to use when such a words count - mismatch occurs. Three values are available: 'ignore' (the default) - which do nothing, 'warn' which issue a warning for each mismatched - line, and 'remove' which remove the mismatched lines from the - output.""") - - group = parser.add_argument_group('specific to festival backend') - try: - festival_executable = BACKENDS['festival'].executable() - except RuntimeError: # pragma: nocover - festival_executable = None - - group.add_argument( - '--festival-executable', - default=None, type=str, metavar='', - help=f'''the path to the festival executable to use (useful to - overload the default festival installed on the system). Default to - {festival_executable}. This path can also be specified using the - PHONEMIZER_FESTIVAL_EXECUTABLE environment variable.''') - - group = parser.add_argument_group( - 'punctuation processing', - description='not available for espeak-mbrola backend') - group.add_argument( - '--preserve-punctuation', - action='store_true', - help='''preserve the punctuation marks in the phonemized output, - default is to remove them.''') - group.add_argument( - '--punctuation-marks', - type=str, metavar='', - default=punctuation.Punctuation.default_marks(), - help='''the marks to consider during punctuation processing (either - for removal or preservation). Default is %(default)s.''') - group.add_argument( - '--punctuation-marks-is-regex', - action='store_true', - help="""interpret the '--punctuation-marks' parameter as a regex. - Default is to interpret as a string.""") - - return parser.parse_args() - - -def list_languages(args_backend): - """Returns the available languages for the given `backend` as a str""" - for backend in BACKENDS.keys() if not args_backend else [args_backend]: - print( - f'supported languages for {backend} are:\n' + - '\n'.join(f'\t{k}\t->\t{v}' for k, v in sorted( - BACKENDS[backend].supported_languages().items()))) - - -def get_logger(verbose, quiet): - """Returns a configured logger""" - verbosity = 'normal' - if verbose: - verbosity = 'verbose' - elif quiet: - verbosity = 'quiet' - return logger.get_logger(verbosity=verbosity) - - -def setup_stream(stream, mode): - """If `stream` is a filename, open it as a file""" - if isinstance(stream, str): - # pylint: disable=consider-using-with - return open(stream, mode, encoding='utf8') - return stream # pragma: nocover - - -@CatchExceptions -def main(): - """Phonemize a text from command-line arguments""" - args = parse_args() - - # setup a custom path to espeak and festival if required (this must be done - # before generating the version message) - if args.espeak_library: - BACKENDS['espeak'].set_library(args.espeak_library) - if args.festival_executable: - BACKENDS['festival'].set_executable(args.festival_executable) - - # display version information and exit - if args.version: - print(version.version()) - return - - # list supported languages and exit - if args.list_languages: - print(list_languages(args.backend)) - return - - # set default backend as espeak if not specified - args.backend = args.backend or 'espeak' - - # configure logging according to --verbose/--quiet options - log = get_logger(args.verbose, args.quiet) - - # configure input:output as a readable/writable streams - streamin = setup_stream(args.input, 'r') - log.debug('reading from %s', streamin.name) - streamout = setup_stream(args.output, 'w') - log.debug('writing to %s', streamout.name) - - # configure the separator for phonemes, syllables and words. - if args.backend == 'espeak-mbrola': - log.debug('using espeak-mbrola backend: ignoring word separator') - sep = separator.Separator( - phone=args.phone_separator, - syllable=None, - word=None) - else: - sep = separator.Separator( - phone=args.phone_separator, - syllable=args.syllable_separator, - word=args.word_separator) - log.debug('separator is %s', sep) - - if args.prepend_text: - input_output_separator = sep.input_output_separator(args.prepend_text) - log.debug( - 'prepend input text to output, separator is "%s"', - input_output_separator) - else: - input_output_separator = False - - if args.punctuation_marks_is_regex: - try: - log.debug('punctuation marks is regex %s', args.punctuation_marks) - args.punctuation_marks = re.compile(args.punctuation_marks) - except re.error: - # manually close the open streams for windows - streamin.close() - streamout.close() - raise ValueError(f"can't compile regex pattern from {args.punctuation_marks}") - - # phonemize the input text - out = phonemize( - streamin.readlines(), - language=args.language, - backend=args.backend, - separator=sep, - strip=args.strip, - prepend_text=args.prepend_text, - preserve_empty_lines=args.preserve_empty_lines, - preserve_punctuation=args.preserve_punctuation, - punctuation_marks=args.punctuation_marks, - with_stress=args.with_stress, - tie=args.tie, - language_switch=args.language_switch, - words_mismatch=args.words_mismatch, - njobs=args.njobs, - logger=log) - - if out and input_output_separator: - streamout.write( - os.linesep.join( - f'{line[0]} {input_output_separator} {line[1]}' - for line in out) - + os.linesep) - elif out: - streamout.write(os.linesep.join(out) + os.linesep) - - -if __name__ == '__main__': # pragma: nocover - main() diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/phonemize.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/phonemize.py deleted file mode 100644 index 435ebca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/phonemize.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Provides the phonemize function - -To use it in your own code, type: - - from phonemizer import phonemize - -""" - -import os -import sys -from logging import Logger -from typing import Optional, Union, List, Pattern - -from typing_extensions import Literal - -from phonemizer.backend import BACKENDS -from phonemizer.backend.base import BaseBackend -from phonemizer.backend.espeak.language_switch import LanguageSwitch -from phonemizer.backend.espeak.words_mismatch import WordMismatch -from phonemizer.logger import get_logger -from phonemizer.punctuation import Punctuation -from phonemizer.separator import default_separator, Separator -from phonemizer.utils import list2str, str2list - -Backend = Literal['espeak', 'espeak-mbrola', 'festival', 'segments'] - - -def phonemize( # pylint: disable=too-many-arguments - text, - language: str = 'en-us', - backend: Backend = 'espeak', - separator: Optional[Separator] = default_separator, - strip: bool = False, - prepend_text: bool = False, - preserve_empty_lines: bool = False, - preserve_punctuation: bool = False, - punctuation_marks: Union[str, Pattern] = Punctuation.default_marks(), - with_stress: bool = False, - tie: Union[bool, str] = False, - language_switch: LanguageSwitch = 'keep-flags', - words_mismatch: WordMismatch = 'ignore', - njobs: int = 1, - logger: Logger = get_logger()): - """Multilingual text to phonemes converter - - Return a phonemized version of an input `text`, given its `language` and a - phonemization `backend`. - - Note - ---- - - To improve the processing speed it is better to minimize the calls to this - function: provide the input text as a list and call phonemize() a single - time is much more efficient than calling it on each element of the list. - Indeed the initialization of the phonemization backend can be expensive, - especially for espeak. In one example, - - Do this: - - >>> text = [line1, line2, ...] - >>> phonemize(text, ...) - - Not this: - - >>> for line in text: - >>> phonemize(line, ...) - - Parameters - ---------- - - text: str or list of str - The text to be phonemized. Any empty line will - be ignored. If ``text`` is an str, it can be multiline (lines being - separated by ``\\n``). If ``text`` is a list, each element is considered as a - separated line. Each line is considered as a text utterance. - - language: str - The language code of the input text, must be supported by - the backend. If ``backend`` is 'segments', the language can be a file with - a grapheme to phoneme mapping. - - backend: str, optional - The software backend to use for phonemization, - must be 'festival' (US English only is supported, coded 'en-us'), - 'espeak', 'espeak-mbrola' or 'segments'. - - separator: Separator - string separators between phonemes, syllables and - words, default to separator.default_separator. Syllable separator is - considered only for the festival backend. Word separator is ignored by - the 'espeak-mbrola' backend. Initialize it as follows: - >>> from phonemizer.separator import Separator - >>> separator = Separator(phone='-', word=' ') - - strip: bool, optional - If True, don't output the last word and phone - separators of a token, default to False. - - prepend_text: bool, optional - When True, returns a pair (input utterance, - phonemized utterance) for each line of the input text. When False, - returns only the phonemized utterances. Default to False - - preserve_empty_lines: bool, optional - When True, will keep the empty lines - in the phonemized output. Default to False and remove all empty lines. - - preserve_punctuation: bool, optional - When True, will keep the punctuation - in the phonemized output. Not supported by the 'espeak-mbrola' backend. - Default to False and remove all the punctuation. - - punctuation_marks: str or re.Pattern, optional - The punctuation marks to consider when dealing with punctuation, - either for removal or preservation. Can be defined as a string or regular expression. - Default to Punctuation.default_marks(). - - with_stress: bool, optional - This option is only valid for the 'espeak' - backend. When True the stresses on phonemes are present (stresses - characters are ˈ'ËŒ). When False stresses are removed. Default to False. - - tie: bool or char, optional - This option is only valid for the 'espeak' - backend with espeak>=1.49. It is incompatible with phone separator. When - not False, use a tie character within multi-letter phoneme names. When - True, the char 'U+361' is used (as in d͡ʒ), 'z' means ZWJ character, - default to False. - - language_switch: str, optional - Espeak can output some words in another - language (typically English) when phonemizing a text. This option setups - the policy to use when such a language switch occurs. Three values are - available : 'keep-flags' (the default), 'remove-flags' or - 'remove-utterance'. The 'keep-flags' policy keeps the language switching - flags, for example "(en) or (jp)", in the output. The 'remove-flags' - policy removes them and the 'remove-utterance' policy removes the whole - line of text including a language switch. This option is only valid for - the 'espeak' backend. - - words_mismatch: str, optional - Espeak can join two consecutive words or - drop some words, yielding a word count mismatch between orthographic and - phonemized text. This option setups the policy to use when such a words - count mismatch occurs. Three values are available: 'ignore' (the default) - which do nothing, 'warn' which issue a warning for each mismatched line, - and 'remove' which remove the mismatched lines from the output. - - njobs: int - The number of parallel jobs to launch. The input text is split - in ``njobs`` parts, phonemized on parallel instances of the backend and the - outputs are finally collapsed. - - logger: logging.Logger - the logging instance where to send messages. If - not specified, use the default system logger. - - Returns - ------- - phonemized text: str or list of str - The input ``text`` phonemized for the - given ``language`` and ``backend``. The returned value has the same type of - the input text (either a list or a string), excepted if ``prepend_input`` - is True where the output is forced as a list of pairs (input_text, - phonemized text). - - Raises - ------ - RuntimeError - if the ``backend`` is not valid or is valid but not installed, - if the ``language`` is not supported by the ``backend``, if any incompatible options are used. - - """ - # ensure we are using a compatible Python version - if sys.version_info < (3, 6): # pragma: nocover - logger.error( - 'Your are using python-%s which is unsupported by the phonemizer, ' - 'please update to python>=3.6', ".".join(sys.version_info)) - - # ensure the arguments are valid - _check_arguments( - backend, with_stress, tie, separator, language_switch, words_mismatch) - - # preserve_punctuation and word separator not valid for espeak-mbrola - if backend == 'espeak-mbrola' and preserve_punctuation: - logger.warning('espeak-mbrola backend cannot preserve punctuation') - if backend == 'espeak-mbrola' and separator.word: - logger.warning('espeak-mbrola backend cannot preserve word separation') - - # initialize the phonemization backend - if backend == 'espeak': - phonemizer = BACKENDS[backend]( - language, - punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, - with_stress=with_stress, - tie=tie, - language_switch=language_switch, - words_mismatch=words_mismatch, - logger=logger) - elif backend == 'espeak-mbrola': - phonemizer = BACKENDS[backend]( - language, - logger=logger) - else: # festival or segments - phonemizer = BACKENDS[backend]( - language, - punctuation_marks=punctuation_marks, - preserve_punctuation=preserve_punctuation, - logger=logger) - - # do the phonemization - return _phonemize(phonemizer, text, separator, strip, njobs, prepend_text, preserve_empty_lines) - - -def _check_arguments( # pylint: disable=too-many-arguments - backend: Backend, - with_stress: bool, - tie: Union[bool, str], - separator: Separator, - language_switch: LanguageSwitch, - words_mismatch: WordMismatch): - """Auxiliary function to phonemize() - - Ensures the parameters are compatible with each other, raises a - RuntimeError the first encountered error. - - """ - # ensure the backend is either espeak, festival or segments - if backend not in ('espeak', 'espeak-mbrola', 'festival', 'segments'): - raise RuntimeError( - '{} is not a supported backend, choose in {}.' - .format(backend, ', '.join( - ('espeak', 'espeak-mbrola', 'festival', 'segments')))) - - # with_stress option only valid for espeak - if with_stress and backend != 'espeak': - raise RuntimeError( - 'the "with_stress" option is available for espeak backend only, ' - 'but you are using {} backend'.format(backend)) - - # tie option only valid for espeak - if tie and backend != 'espeak': - raise RuntimeError( - 'the "tie" option is available for espeak backend only, ' - 'but you are using {} backend'.format(backend)) - - # tie option incompatible with phone separator - if tie and separator.phone: - raise RuntimeError( - 'the "tie" option is incompatible with phone separator ' - f'(which is "{separator.phone}")') - - # language_switch option only valid for espeak - if language_switch != 'keep-flags' and backend != 'espeak': - raise RuntimeError( - 'the "language_switch" option is available for espeak backend ' - 'only, but you are using {} backend'.format(backend)) - - # words_mismatch option only valid for espeak - if words_mismatch != 'ignore' and backend != 'espeak': - raise RuntimeError( - 'the "words_mismatch" option is available for espeak backend ' - 'only, but you are using {} backend'.format(backend)) - - -def _phonemize( # pylint: disable=too-many-arguments - backend: BaseBackend, - text: Union[str, List[str]], - separator: Separator, - strip: bool, - njobs: int, - prepend_text: bool, - preserve_empty_lines: bool): - """Auxiliary function to phonemize() - - Does the phonemization and returns the phonemized text. Raises a - RuntimeError on error. - - """ - # remember the text type for output (either list or string) - text_type = type(text) - - # force the text as a list - text = [line.strip(os.linesep) for line in str2list(text)] - - # if preserving empty lines, note the index of each empty line - if preserve_empty_lines: - empty_lines = [n for n, line in enumerate(text) if not line.strip()] - - # ignore empty lines - text = [line for line in text if line.strip()] - - if (text): - # phonemize the text - phonemized = backend.phonemize( - text, separator=separator, strip=strip, njobs=njobs) - else: - phonemized = [] - - # if preserving empty lines, reinsert them into text and phonemized lists - if preserve_empty_lines: - for i in empty_lines: # noqa - if prepend_text: - text.insert(i, '') - phonemized.insert(i, '') - - # at that point, the phonemized text is a list of str. Format it as - # expected by the parameters - if prepend_text: - return list(zip(text, phonemized)) - if text_type == str: - return list2str(phonemized) - return phonemized diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/punctuation.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/punctuation.py deleted file mode 100644 index 4d157ec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/punctuation.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Implementation of punctuation processing""" - -import collections -import re -from typing import List, Union, Tuple, Pattern - -from phonemizer.utils import str2list -from phonemizer.separator import Separator - -# The punctuation marks considered by default. -_DEFAULT_MARKS = ';:,.!?¡¿—…"«»“â€(){}[]' - -_MarkIndex = collections.namedtuple( - '_mark_index', ['index', 'mark', 'position']) - - -class Punctuation: - """Preserve or remove the punctuation during phonemization - - Backends behave differently with punctuation: festival and espeak ignore it - and remove it silently whereas segments will raise an error. The - Punctuation class solves that issue by "hiding" the punctuation to the - phonemization backend and restoring it afterwards. - - Parameters - ---------- - marks (str or re.Pattern) : The punctuation marks to consider for processing - (either removal or preservation). If a string, each mark must be made of - a single character. Default to Punctuation.default_marks(). - - """ - - def __init__(self, marks: Union[str, Pattern] = _DEFAULT_MARKS): - self._marks: str = None # noqa - self._marks_re: Pattern[str] = None # noqa - self.marks = marks - - @staticmethod - def default_marks(): - """Returns the default punctuation marks as a string""" - return _DEFAULT_MARKS - - @property - def marks(self): - """The punctuation marks as a string""" - if self._marks: - return self._marks - raise ValueError('punctuation initialized from regex, cannot access marks as a string') - - @marks.setter - def marks(self, value: Union[str, Pattern]): - if isinstance(value, Pattern): - # catch the pattern surrounded by zero or more spaces on either side - self._marks_re = re.compile(r'((' + value.pattern + r')|\s)+') - self._marks = None - elif isinstance(value, str): - self._marks = ''.join(set(value)) - - # catching all the marks in one regular expression: zero or more spaces - # + one or more marks + zero or more spaces. - self._marks_re = re.compile(fr'(\s*[{re.escape(self._marks)}]+\s*)+') - else: - raise ValueError('punctuation marks must be defined as a string or re.Pattern') - - def remove(self, text: Union[str, List[str]]) -> Union[str, List[str]]: - """Returns the `text` with all punctuation marks replaced by spaces - - The input `text` can be a string or a list and is returned with the - same type and punctuation removed. - - """ - - def aux(text: str) -> str: - return re.sub(self._marks_re, ' ', text).strip() - - if isinstance(text, str): - return aux(text) - return [aux(line) for line in text] - - def preserve(self, text: Union[List[str], str]) -> Tuple[List[List[str]], List[_MarkIndex]]: - """Removes punctuation from `text`, allowing for furter restoration - - This method returns the text as a list of punctuated chunks, along with - a list of punctuation marks for furter restoration: - - 'hello, my world!' -> ['hello', 'my world'], [',', '!'] - - """ - text: List[str] = str2list(text) - preserved_text = [] - preserved_marks = [] - - for num, line in enumerate(text): - line, marks = self._preserve_line(line, num) - preserved_text += line - preserved_marks += marks - return [line for line in preserved_text if line], preserved_marks - - def _preserve_line(self, line: str, num: int) -> Tuple[List[str], List[_MarkIndex]]: - """Auxiliary method for Punctuation.preserve()""" - matches = list(re.finditer(self._marks_re, line)) - if not matches: - return [line], [] - - # the line is made only of punctuation marks - if len(matches) == 1 and matches[0].group() == line: - return [], [_MarkIndex(num, line, 'A')] - - # build the list of mark indexes required to restore the punctuation - marks = [] - for match in matches: - # find the position of the punctuation mark in the utterance: - # begin (B), end (E), in the middle (I) or alone (A) - position = 'I' - if match == matches[0] and line.startswith(match.group()): - position = 'B' - elif match == matches[-1] and line.endswith(match.group()): - position = 'E' - marks.append(_MarkIndex(num, match.group(), position)) - - # split the line into sublines, each separated by a punctuation mark - preserved_line = [] - for mark in marks: - split = line.split(mark.mark) - prefix, suffix = split[0], mark.mark.join(split[1:]) - preserved_line.append(prefix) - line = suffix - - # append any trailing text to the preserved line - return preserved_line + [line], marks - - @classmethod - def restore(cls, text: Union[str, List[str]], - marks: List[_MarkIndex], - sep: Separator, - strip: bool) -> List[str]: - """Restore punctuation in a text. - - This is the reverse operation of Punctuation.preserve(). It takes a - list of punctuated chunks and a list of punctuation marks, as well as - the separator and strip parameters used by phonemize. It returns the - punctuated text as a list: - - ['hello', 'my world'], [',', '!'] -> ['hello, my world!'] - - """ - text = str2list(text) - punctuated_text = [] - pos = 0 - - while text or marks: - - if not marks: - for line in text: - # if strip is False, ensure the final word ends with a word separator - if not strip and sep.word and not line.endswith(sep.word): - line = line + sep.word - punctuated_text.append(line) - text = [] - elif not text: - # nothing has been phonemized, returns the marks alone, with internal - # spaces replaced by the word separator - punctuated_text.append(re.sub(' ', sep.word, ''.join(m.mark for m in marks))) - marks = [] - - else: - current_mark = marks[0] - if current_mark.index == pos: - - # place the current mark here - mark = marks[0] - marks = marks[1:] - # replace internal spaces in the current mark with the word separator - mark = re.sub(' ', sep.word, mark.mark) - - # remove the word last separator from the current word - if sep.word and text[0].endswith(sep.word): - text[0] = text[0][:-len(sep.word)] - - if current_mark.position == 'B': - text[0] = mark + text[0] - elif current_mark.position == 'E': - punctuated_text.append(text[0] + mark + ('' if strip or mark.endswith(sep.word) else sep.word)) - text = text[1:] - pos = pos + 1 - elif current_mark.position == 'A': - punctuated_text.append(mark + ('' if strip or mark.endswith(sep.word) else sep.word)) - pos = pos + 1 - else: - # position == 'I' - if len(text) == 1: # pragma: nocover - # a corner case where the final part of an intermediate - # mark (I) has not been phonemized - text[0] = text[0] + mark - else: - first_word = text[0] - text = text[1:] - text[0] = first_word + mark + text[0] - - else: - punctuated_text.append(text[0]) - text = text[1:] - pos = pos + 1 - - - return punctuated_text diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/separator.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/separator.py deleted file mode 100644 index e6ddd83..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/separator.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Provides the Separator tuple and its default value""" -from typing import Optional, Union - - -class Separator: - """Defines phone, syllable and word boundary tokens""" - - def __init__(self, word: str = ' ', - syllable: Optional[str] = None, - phone: Optional[str] = None): - # check we have different separators, None excluded - sep1 = list(sep for sep in (phone, syllable, word) if sep) - sep2 = set(sep for sep in (phone, syllable, word) if sep) - if len(sep1) != len(sep2): - raise ValueError( - 'illegal separator with word="{}", syllable="{}" and ' - 'phone="{}", must be all differents if not empty' - .format(phone, syllable, word)) - - self._phone = str(phone) if phone else '' - self._syllable = str(syllable) if syllable else '' - self._word = str(word) if word else '' - - def __eq__(self, other: 'Separator'): - return ( - self.phone == other.phone - and self.syllable == other.syllable - and self.word == other.word) - - def __str__(self): - return ( - f'(phone: "{self.phone}", ' - f'syllable: "{self.syllable}", ' - f'word: "{self.word}")') - - @property - def phone(self): - """Phones separator""" - return self._phone - - @property - def syllable(self): - """Syllables separator""" - return self._syllable - - @property - def word(self): - """Words separator""" - return self._word - - def __contains__(self, value: str): - """Returns True if the separator has `value` as token separation""" - return value in {self.phone, self.syllable, self.word} - - def input_output_separator(self, field_separator: Union[str, bool]) \ - -> Union[str, bool]: - """Returns a suitable input/output separator based on token separator - - The input/output separator split orthographic and phonetic texts when - using the --prepend-text option from command-line. - - Parameters - ---------- - - field_separator: bool or str - If str, ensures it's value is not - already defined as a token separator. If True choose one of "|", - "||", "|||", "||||" (the first one that is not defined as a token - separator) - - Returns - ------- - The input/output separator, or False if ``field_separator`` is False - - Raises - ------ - RuntimeError - if ``field_separator`` is a str but is already registered as token separator - - """ - if not field_separator: - return False - - if isinstance(field_separator, str): - if field_separator in self: - raise RuntimeError( - f'cannot prepend input with "{field_separator}" because ' - f'it is already a token separator: {self}') - return field_separator - - if field_separator is True: - field_separator = '|' - while field_separator in self: - field_separator += '|' - return field_separator - - # not a bool nor a str - raise RuntimeError( - 'invalid input/output separator, must be bool or str but is' - f'{field_separator}') - - -default_separator = Separator(phone='', syllable='', word=' ') -"""The default separation characters for phonemes, syllables and words""" diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/festival/phonemize.scm b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/festival/phonemize.scm deleted file mode 100644 index 4b76828..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/festival/phonemize.scm +++ /dev/null @@ -1,30 +0,0 @@ -;; Copyright 2015-2021 Mathieu Bernard -;; -;; This file is part of phonemizer: you can redistribute it and/or -;; modify it under the terms of the GNU General Public License as -;; published by the Free Software Foundation, either version 3 of the -;; License, or (at your option) any later version. -;; -;; Phonemizer is distributed in the hope that it will be useful, but -;; WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;; General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with phonemizer. If not, see . - -;; This script is executed by festival for English text phonemization. -(define (phonemize line) - "(phonemize LINE) -Extract the phonemes of the string LINE as a tree and write it to stdout." - (set! utterance (eval (list 'Utterance 'Text line))) - (utt.synth utterance) - ;; Use of print instead of pprintf to have each utterance on one line - (print (utt.relation_tree utterance "SylStructure"))) - -;; This double braket have to be replaced by the name of the text file -;; you want to read data from. To be parsed by festival as a unique -;; utterance, each line of that file must begin and end with -;; double-quotes. -(set! lines (load "{}" t)) -(mapcar (lambda (line) (phonemize line)) lines) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/chintang.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/chintang.g2p deleted file mode 100644 index b0afa65..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/chintang.g2p +++ /dev/null @@ -1,27 +0,0 @@ -a ÊŒ -â aË -b b -ch tʃ -d d -e eË -f f -g g -h h -i ɪ -î iË -j dÊ’ -k k -kw kÊ· -l l -m m -n n -o ÊŠ -p p -s s -sh ʃ -t t -th θ -u ÊŠ -û o -w w -y j diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/cree.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/cree.g2p deleted file mode 100644 index 1654488..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/cree.g2p +++ /dev/null @@ -1,27 +0,0 @@ -a ÊŒ -â aË -b b -ch tʃ -d d -e eË -f f -g g -h h -i ɪ -î iË -j dÊ’ -k k -kw kÊ· -l l -m m -n n -o ÊŠ -p p -s s -sh ʃ -t t -th θ -u ÊŠ -û o -w w -y j diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/inuktitut.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/inuktitut.g2p deleted file mode 100644 index beaa1aa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/inuktitut.g2p +++ /dev/null @@ -1,20 +0,0 @@ -a a -g g -h h -i i -j j -k k -l l -ll ɬ -m m -n n -ng Å‹ -nng ŋŋ -p p -q q -r Ê -rng É´ -s s -t t -u u -v v diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/japanese.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/japanese.g2p deleted file mode 100644 index 3292b78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/japanese.g2p +++ /dev/null @@ -1,35 +0,0 @@ -a a -aa aË -b b -by bʲ -ch tʃ -d d -e e -ee eË -f ɸ -g g -gy gʲ -h h -hy ç -i i -j dÊ’ -k k -ky kʲ -m m -my mʲ -n n -ny ɲ -o o -oo oË -p p -py pʲ -r r -ry rʲ -sh ʃ -t t -ts tÍ¡s -u ɯ -uu É¯Ë -w w -y j -z z diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/sesotho.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/sesotho.g2p deleted file mode 100644 index 7227f51..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/sesotho.g2p +++ /dev/null @@ -1,38 +0,0 @@ -a a -b b -ch tʃʰ -d d -e e -f f -g χ -h h -hl ɬ -i i -j dÊ’ -k k -kg kx -kh kʰ -l l -m m -n n -ng Å‹ -nq ǃ̃ -ny ɲ -o o -p t -ph pʰ -q ǃ -qh ǃʰ -r r -s s -sh ʃ -t t -th tʰ -tj tʃ -tl tɬ -tlh tɬʰ -ts tÍ¡s -tsh tÍ¡sʰ -u u -w w -y j diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/yucatec.g2p b/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/yucatec.g2p deleted file mode 100644 index c4ca83c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/share/segments/yucatec.g2p +++ /dev/null @@ -1,45 +0,0 @@ -a a -aa aË -aʼ a̰ -aʼa aÌ°Ë -b b -ch t̠͡ʃ -chʼ t̠͡ʃʼ -e e -ee eË -eʼ ḛ -eʼe eÌ°Ë -f f -h h -i i -ii iË -iʼ ḭ -iʼi iÌ°Ë -j x -k k -kʼ kʼ -l l -m m -n n -ñ n -o o -oo oË -oʼ o̰ -oʼo oÌ°Ë -p pʼ -pʼ pʼ -qu k -r r -s s -x ʃ -t t -ts tÍ¡s -tsʼ tÍ¡sʼ -tʼ tʼ -u u -uu uË -uʼ ṵ -uʼu uÌ°Ë -w w -y j -z s diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/utils.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/utils.py deleted file mode 100644 index 5d52767..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/utils.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Provides utility functions for the phonemizer""" - -import os -from numbers import Number -from pathlib import Path -from typing import Union, List, Tuple, Iterable - -import importlib - - -def cumsum(iterable: Iterable[Number]) -> List[Number]: - """Returns the cumulative sum of the `iterable` as a list""" - res = [] - cumulative = 0 - for value in iterable: - cumulative += value - res.append(cumulative) - return res - - -def str2list(text: Union[str, List[str]]) -> List[str]: - """Returns the string `text` as a list of lines, split by \n""" - if isinstance(text, str): - return text.strip(os.linesep).split(os.linesep) - return text - - -def list2str(text: Union[str, List[str]]) -> str: - """Returns the list of lines `text` as a single string separated by \n""" - if isinstance(text, str): - return text - return os.linesep.join(text) - - -def chunks(text: Union[str, List[str]], num: int) \ - -> Tuple[List[List[str]], List[int]]: - """Return a maximum of `num` equally sized chunks of a `text` - - This method is usefull when phonemizing a single text on multiple jobs. - - The exact number of chunks returned is `m = min(num, len(str2list(text)))`. - Only the m-1 first chunks have equal size. The last chunk can be longer. - The input `text` can be a list or a string. Return a list of `m` strings. - - Parameters - ---------- - text (str or list) : The text to divide in chunks - - num (int) : The number of chunks to build, must be a strictly positive - integer. - - Returns - ------- - chunks (list of list of str) : The chunked text with utterances separated - by '\n'. - - offsets (list of int) : offset used below to recover the line numbers in - the input text wrt the chunks - - """ - text: List[str] = str2list(text) - size = int(max(1, len(text) / num)) # noqa - nchunks = min(num, len(text)) - - text_chunks = [ - text[i * size:(i + 1) * size] for i in range(nchunks - 1)] - - last = text[(nchunks - 1) * size:] - if last: - text_chunks.append(last) - - offsets = [0] + cumsum((len(c) for c in text_chunks[:-1])) - return text_chunks, offsets - - -def get_package_resource(path: str) -> Path: - """Returns the absolute path to a phonemizer resource file or directory - - The packages resource are stored within the source tree in the - 'phonemizer/share' directory and, once the package is installed, are moved - to another system directory (e.g. /share/phonemizer). - - Parameters - ---------- - path (str) : the file or directory to get, must be relative to - 'phonemizer/share'. - - Raises - ------ - ValueError if the required `path` is not found - - Returns - ------- - The absolute path to the required resource as a `pathlib.Path` - - """ - try: - # new in python-3.9 - path = importlib.resources.files('phonemizer') / 'share' / path - except AttributeError: # pragma: nocover - with importlib.resources.path('phonemizer', 'share') as share: - path = share / path - - if not path.exists(): # pragma: nocover - raise ValueError(f'the requested resource does not exist: {path}') - - return path.resolve() - - -def version_as_tuple(version: str) -> Tuple[int, ...]: - """Returns a tuple of integers from a version string - - Any '-dev' in version string is ignored. For instance, returns (1, 2, 3) - from '1.2.3' or (0, 2) from '0.2-dev' - - """ - return tuple(int(v) for v in version.replace('-dev', '').split('.')) diff --git a/extensions/.local/lib/python3.11/site-packages/phonemizer/version.py b/extensions/.local/lib/python3.11/site-packages/phonemizer/version.py deleted file mode 100644 index df0e844..0000000 --- a/extensions/.local/lib/python3.11/site-packages/phonemizer/version.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Phonemizer version description""" - -import importlib - -from phonemizer.backend import ( - EspeakBackend, EspeakMbrolaBackend, FestivalBackend, SegmentsBackend) - - -def _version_as_str(vers): - """From (1, 49, 3) to '1.49.3'""" - return '.'.join(str(v) for v in vers) - - -def version(): - """Return version information for front and backends""" - # version of the phonemizer - _version = 'phonemizer-' + importlib.metadata.version('phonemizer') - - # for each backend, check if it is available or not. If so get its version - available = [] - unavailable = [] - - if EspeakBackend.is_available(): - available.append( - 'espeak-' + ('ng-' if EspeakBackend.is_espeak_ng() else '') - + _version_as_str(EspeakBackend.version())) - else: # pragma: nocover - unavailable.append('espeak') - - if EspeakMbrolaBackend.is_available(): - available.append('espeak-mbrola') - else: # pragma: nocover - unavailable.append('espeak-mbrola') - - if FestivalBackend.is_available(): - available.append( - 'festival-' + _version_as_str(FestivalBackend.version())) - else: # pragma: nocover - unavailable.append('festival') - - if SegmentsBackend.is_available(): - available.append( - 'segments-' + _version_as_str(SegmentsBackend.version())) - else: # pragma: nocover - unavailable.append('segments') - - # resumes the backends status in the final version string - if available: - _version += '\navailable backends: ' + ', '.join(available) - if unavailable: # pragma: nocover - _version += '\nuninstalled backends: ' + ', '.join(unavailable) - - return _version diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/LICENSE deleted file mode 100644 index 1e65815..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/LICENSE +++ /dev/null @@ -1,54 +0,0 @@ -Copyright 2017- Paul Ganssle -Copyright 2017- dateutil contributors (see AUTHORS file) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -The above license applies to all contributions after 2017-12-01, as well as -all contributions that have been re-licensed (see AUTHORS file for the list of -contributors who have re-licensed their code). --------------------------------------------------------------------------------- -dateutil - Extensions to the standard Python datetime module. - -Copyright (c) 2003-2011 - Gustavo Niemeyer -Copyright (c) 2012-2014 - Tomi Pieviläinen -Copyright (c) 2014-2016 - Yaron de Leeuw -Copyright (c) 2015- - Paul Ganssle -Copyright (c) 2015- - dateutil contributors (see AUTHORS file) - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The above BSD License Applies to all code, even that also covered by Apache 2.0. \ No newline at end of file diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/METADATA deleted file mode 100644 index 577f2bf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/METADATA +++ /dev/null @@ -1,204 +0,0 @@ -Metadata-Version: 2.1 -Name: python-dateutil -Version: 2.9.0.post0 -Summary: Extensions to the standard Python datetime module -Home-page: https://github.com/dateutil/dateutil -Author: Gustavo Niemeyer -Author-email: gustavo@niemeyer.net -Maintainer: Paul Ganssle -Maintainer-email: dateutil@python.org -License: Dual License -Project-URL: Documentation, https://dateutil.readthedocs.io/en/stable/ -Project-URL: Source, https://github.com/dateutil/dateutil -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Software Development :: Libraries -Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,>=2.7 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: six >=1.5 - -dateutil - powerful extensions to datetime -========================================== - -|pypi| |support| |licence| - -|gitter| |readthedocs| - -|travis| |appveyor| |pipelines| |coverage| - -.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square - :target: https://pypi.org/project/python-dateutil/ - :alt: pypi version - -.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square - :target: https://pypi.org/project/python-dateutil/ - :alt: supported Python version - -.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build - :target: https://travis-ci.org/dateutil/dateutil - :alt: travis build status - -.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor - :target: https://ci.appveyor.com/project/dateutil/dateutil - :alt: appveyor build status - -.. |pipelines| image:: https://dev.azure.com/pythondateutilazure/dateutil/_apis/build/status/dateutil.dateutil?branchName=master - :target: https://dev.azure.com/pythondateutilazure/dateutil/_build/latest?definitionId=1&branchName=master - :alt: azure pipelines build status - -.. |coverage| image:: https://codecov.io/gh/dateutil/dateutil/branch/master/graphs/badge.svg?branch=master - :target: https://codecov.io/gh/dateutil/dateutil?branch=master - :alt: Code coverage - -.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg - :alt: Join the chat at https://gitter.im/dateutil/dateutil - :target: https://gitter.im/dateutil/dateutil - -.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square - :target: https://pypi.org/project/python-dateutil/ - :alt: licence - -.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs - :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/ - :target: https://dateutil.readthedocs.io/en/latest/ - -The `dateutil` module provides powerful extensions to -the standard `datetime` module, available in Python. - -Installation -============ -`dateutil` can be installed from PyPI using `pip` (note that the package name is -different from the importable name):: - - pip install python-dateutil - -Download -======== -dateutil is available on PyPI -https://pypi.org/project/python-dateutil/ - -The documentation is hosted at: -https://dateutil.readthedocs.io/en/stable/ - -Code -==== -The code and issue tracker are hosted on GitHub: -https://github.com/dateutil/dateutil/ - -Features -======== - -* Computing of relative deltas (next month, next year, - next Monday, last week of month, etc); -* Computing of relative deltas between two given - date and/or datetime objects; -* Computing of dates based on very flexible recurrence rules, - using a superset of the `iCalendar `_ - specification. Parsing of RFC strings is supported as well. -* Generic parsing of dates in almost any string format; -* Timezone (tzinfo) implementations for tzfile(5) format - files (/etc/localtime, /usr/share/zoneinfo, etc), TZ - environment string (in all known formats), iCalendar - format files, given ranges (with help from relative deltas), - local machine timezone, fixed offset timezone, UTC timezone, - and Windows registry-based time zones. -* Internal up-to-date world timezone information based on - Olson's database. -* Computing of Easter Sunday dates for any given year, - using Western, Orthodox or Julian algorithms; -* A comprehensive test suite. - -Quick example -============= -Here's a snapshot, just to give an idea about the power of the -package. For more examples, look at the documentation. - -Suppose you want to know how much time is left, in -years/months/days/etc, before the next easter happening on a -year with a Friday 13th in August, and you want to get today's -date out of the "date" unix system command. Here is the code: - -.. code-block:: python3 - - >>> from dateutil.relativedelta import * - >>> from dateutil.easter import * - >>> from dateutil.rrule import * - >>> from dateutil.parser import * - >>> from datetime import * - >>> now = parse("Sat Oct 11 17:13:46 UTC 2003") - >>> today = now.date() - >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year - >>> rdelta = relativedelta(easter(year), today) - >>> print("Today is: %s" % today) - Today is: 2003-10-11 - >>> print("Year with next Aug 13th on a Friday is: %s" % year) - Year with next Aug 13th on a Friday is: 2004 - >>> print("How far is the Easter of that year: %s" % rdelta) - How far is the Easter of that year: relativedelta(months=+6) - >>> print("And the Easter of that year is: %s" % (today+rdelta)) - And the Easter of that year is: 2004-04-11 - -Being exactly 6 months ahead was **really** a coincidence :) - -Contributing -============ - -We welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository. - - -Author -====== -The dateutil module was written by Gustavo Niemeyer -in 2003. - -It is maintained by: - -* Gustavo Niemeyer 2003-2011 -* Tomi Pieviläinen 2012-2014 -* Yaron de Leeuw 2014-2016 -* Paul Ganssle 2015- - -Starting with version 2.4.1 and running until 2.8.2, all source and binary -distributions will be signed by a PGP key that has, at the very least, been -signed by the key which made the previous release. A table of release signing -keys can be found below: - -=========== ============================ -Releases Signing key fingerprint -=========== ============================ -2.4.1-2.8.2 `6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB`_ -=========== ============================ - -New releases *may* have signed tags, but binary and source distributions -uploaded to PyPI will no longer have GPG signatures attached. - -Contact -======= -Our mailing list is available at `dateutil@python.org `_. As it is hosted by the PSF, it is subject to the `PSF code of -conduct `_. - -License -======= - -All contributions after December 1, 2017 released under dual license - either `Apache 2.0 License `_ or the `BSD 3-Clause License `_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License. - - -.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB: - https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD deleted file mode 100644 index e2507fe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD +++ /dev/null @@ -1,25 +0,0 @@ -dateutil/__init__.py,sha256=Mqam67WO9IkTmUFyI66vS6IoSXTp9G388DadH2LCMLY,620 -dateutil/_common.py,sha256=77w0yytkrxlYbSn--lDVPUMabUXRR9I3lBv_vQRUqUY,932 -dateutil/_version.py,sha256=BV031OxDDAmy58neUg5yyqLkLaqIw7ibK9As3jiMib0,166 -dateutil/easter.py,sha256=dyBi-lKvimH1u_k6p7Z0JJK72QhqVtVBsqByvpEPKvc,2678 -dateutil/relativedelta.py,sha256=IY_mglMjoZbYfrvloTY2ce02aiVjPIkiZfqgNTZRfuA,24903 -dateutil/rrule.py,sha256=KJzKlaCd1jEbu4A38ZltslaoAUh9nSbdbOFdjp70Kew,66557 -dateutil/tzwin.py,sha256=7Ar4vdQCnnM0mKR3MUjbIKsZrBVfHgdwsJZc_mGYRew,59 -dateutil/utils.py,sha256=dKCchEw8eObi0loGTx91unBxm_7UGlU3v_FjFMdqwYM,1965 -dateutil/parser/__init__.py,sha256=wWk6GFuxTpjoggCGtgkceJoti4pVjl4_fHQXpNOaSYg,1766 -dateutil/parser/_parser.py,sha256=7klDdyicksQB_Xgl-3UAmBwzCYor1AIZqklIcT6dH_8,58796 -dateutil/parser/isoparser.py,sha256=8Fy999bnCd1frSdOYuOraWfJTtd5W7qQ51NwNuH_hXM,13233 -dateutil/tz/__init__.py,sha256=F-Mz13v6jYseklQf9Te9J6nzcLDmq47gORa61K35_FA,444 -dateutil/tz/_common.py,sha256=cgzDTANsOXvEc86cYF77EsliuSab8Puwpsl5-bX3_S4,12977 -dateutil/tz/_factories.py,sha256=unb6XQNXrPMveksTCU-Ag8jmVZs4SojoPUcAHpWnrvU,2569 -dateutil/tz/tz.py,sha256=EUnEdMfeThXiY6l4sh9yBabZ63_POzy01zSsh9thn1o,62855 -dateutil/tz/win.py,sha256=xJszWgSwE1xPx_HJj4ZkepyukC_hNy016WMcXhbRaB8,12935 -dateutil/zoneinfo/__init__.py,sha256=KYg0pthCMjcp5MXSEiBJn3nMjZeNZav7rlJw5-tz1S4,5889 -dateutil/zoneinfo/dateutil-zoneinfo.tar.gz,sha256=0-pS57bpaN4NiE3xKIGTWW-pW4A9tPkqGCeac5gARHU,156400 -dateutil/zoneinfo/rebuild.py,sha256=MiqYzCIHvNbMH-LdRYLv-4T0EIA7hDKt5GLR0IRTLdI,2392 -python_dateutil-2.9.0.post0.dist-info/LICENSE,sha256=ugD1Gg2SgjtaHN4n2LW50jIeZ-2NqbwWPv-W1eF-V34,2889 -python_dateutil-2.9.0.post0.dist-info/METADATA,sha256=qdQ22jIr6AgzL5jYgyWZjofLaTpniplp_rTPrXKabpM,8354 -python_dateutil-2.9.0.post0.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110 -python_dateutil-2.9.0.post0.dist-info/top_level.txt,sha256=4tjdWkhRZvF7LA_BYe_L9gB2w_p2a-z5y6ArjaRkot8,9 -python_dateutil-2.9.0.post0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -python_dateutil-2.9.0.post0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/WHEEL deleted file mode 100644 index 4724c45..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.42.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/top_level.txt deleted file mode 100644 index 6650148..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -dateutil diff --git a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/zip-safe b/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/extensions/.local/lib/python3.11/site-packages/python_dateutil-2.9.0.post0.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/LICENSE deleted file mode 100644 index 75e852b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2002-2025, RDFLib Team -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/METADATA deleted file mode 100644 index 9e27aa5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/METADATA +++ /dev/null @@ -1,277 +0,0 @@ -Metadata-Version: 2.3 -Name: rdflib -Version: 7.1.4 -Summary: RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information. -License: BSD-3-Clause -Author: Daniel 'eikeon' Krech -Author-email: eikeon@eikeon.com -Maintainer: RDFLib Team -Maintainer-email: rdflib-dev@googlegroups.com -Requires-Python: >=3.8.1,<4.0.0 -Classifier: License :: OSI Approved :: BSD License -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Provides-Extra: berkeleydb -Provides-Extra: html -Provides-Extra: lxml -Provides-Extra: networkx -Provides-Extra: orjson -Requires-Dist: berkeleydb (>=18.1.0,<19.0.0) ; extra == "berkeleydb" -Requires-Dist: html5rdf (>=1.2,<2) ; extra == "html" -Requires-Dist: isodate (>=0.7.2,<1.0.0) ; python_version < "3.11" -Requires-Dist: lxml (>=4.3,<6.0) ; extra == "lxml" -Requires-Dist: networkx (>=2,<4) ; extra == "networkx" -Requires-Dist: orjson (>=3.9.14,<4) ; extra == "orjson" -Requires-Dist: pyparsing (>=2.1.0,<4) -Project-URL: Documentation, https://rdflib.readthedocs.org/ -Project-URL: Repository, https://github.com/RDFLib/rdflib -Description-Content-Type: text/markdown - -![](docs/_static/RDFlib.png) - -RDFLib -====== -[![Build Status](https://github.com/RDFLib/rdflib/actions/workflows/validate.yaml/badge.svg?branch=main)](https://github.com/RDFLib/rdflib/actions?query=branch%3Amain) -[![Documentation Status](https://readthedocs.org/projects/rdflib/badge/?version=latest)](https://rdflib.readthedocs.io/en/latest/?badge=latest) -[![Coveralls branch](https://img.shields.io/coveralls/RDFLib/rdflib/main.svg)](https://coveralls.io/r/RDFLib/rdflib?branch=main) - -[![GitHub stars](https://img.shields.io/github/stars/RDFLib/rdflib.svg)](https://github.com/RDFLib/rdflib/stargazers) -[![Downloads](https://pepy.tech/badge/rdflib/week)](https://pepy.tech/project/rdflib) -[![PyPI](https://img.shields.io/pypi/v/rdflib.svg)](https://pypi.python.org/pypi/rdflib) -[![PyPI](https://img.shields.io/pypi/pyversions/rdflib.svg)](https://pypi.python.org/pypi/rdflib) -[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6845245.svg)](https://doi.org/10.5281/zenodo.6845245) - -[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/RDFLib/rdflib) -[![Gitter](https://badges.gitter.im/RDFLib/rdflib.svg)](https://gitter.im/RDFLib/rdflib?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -[![Matrix](https://img.shields.io/matrix/rdflib:matrix.org?label=matrix.org%20chat)](https://matrix.to/#/#RDFLib_rdflib:gitter.im) - -RDFLib is a pure Python package for working with [RDF](http://www.w3.org/RDF/). RDFLib contains most things you need to work with RDF, including: - -* parsers and serializers for RDF/XML, N3, NTriples, N-Quads, Turtle, TriX, Trig, JSON-LD and even HexTuples -* a Graph interface which can be backed by any one of a number of Store implementations -* Store implementations for in-memory, persistent on disk (Berkeley DB) and remote SPARQL endpoints - * additional Stores can be supplied via plugins -* a SPARQL 1.1 implementation - supporting SPARQL 1.1 Queries and Update statements -* SPARQL function extension mechanisms - -## RDFlib Family of packages -The RDFlib community maintains many RDF-related Python code repositories with different purposes. For example: - -* [rdflib](https://github.com/RDFLib/rdflib) - the RDFLib core -* [sparqlwrapper](https://github.com/RDFLib/sparqlwrapper) - a simple Python wrapper around a SPARQL service to remotely execute your queries -* [pyLODE](https://github.com/RDFLib/pyLODE) - An OWL ontology documentation tool using Python and templating, based on LODE -* [pySHACL](https://github.com/RDFLib/pySHACL) - A pure Python module which allows for the validation of RDF graphs against SHACL graphs -* [OWL-RL](https://github.com/RDFLib/OWL-RL) - A simple implementation of the OWL2 RL Profile which expands the graph with all possible triples that OWL RL defines. - -Please see the list for all packages/repositories here: - -* - -Help with maintenance of all of the RDFLib family of packages is always welcome and appreciated. - -## Versions & Releases - -* `main` branch in this repository is the current unstable release - version 8 alpha -* `7.1.4` tidy-up release, possibly last 7.x release -* `7.1.3` current stable release, small improvements to 7.1.1 -* `7.1.2` previously deleted release -* `7.1.1` previous stable release - * see -* `7.0.0` previous stable release, supports Python 3.8.1+ only. - * see [Releases](https://github.com/RDFLib/rdflib/releases) -* `6.x.y` supports Python 3.7+ only. Many improvements over 5.0.0 - * see [Releases](https://github.com/RDFLib/rdflib/releases) -* `5.x.y` supports Python 2.7 and 3.4+ and is [mostly backwards compatible with 4.2.2](https://rdflib.readthedocs.io/en/stable/upgrade4to5.html). - -See for the release details. - -## Documentation -See for our documentation built from the code. Note that there are `latest`, `stable` and versioned builds, such as `5.0.0`, matching releases. - -## Installation -The stable release of RDFLib may be installed with Python's package management tool *pip*: - - $ pip install rdflib - -Some features of RDFLib require optional dependencies which may be installed using *pip* extras: - - $ pip install rdflib[berkeleydb,networkx,html,lxml,orjson] - -Alternatively manually download the package from the Python Package -Index (PyPI) at https://pypi.python.org/pypi/rdflib - -### Installation of the current main branch (for developers) - -With *pip* you can also install rdflib from the git repository with one of the following options: - - $ pip install git+https://github.com/rdflib/rdflib@main - -or - - $ pip install -e git+https://github.com/rdflib/rdflib@main#egg=rdflib - -or from your locally cloned repository you can install it with one of the following options: - - $ poetry install # installs into a poetry-managed venv - -or - - $ pip install -e . - -## Getting Started -RDFLib aims to be a pythonic RDF API. RDFLib's main data object is a `Graph` which is a Python collection -of RDF *Subject, Predicate, Object* Triples: - -To create graph and load it with RDF data from DBPedia then print the results: - -```python -from rdflib import Graph -g = Graph() -g.parse('http://dbpedia.org/resource/Semantic_Web') - -for s, p, o in g: - print(s, p, o) -``` -The components of the triples are URIs (resources) or Literals -(values). - -URIs are grouped together by *namespace*, common namespaces are included in RDFLib: - -```python -from rdflib.namespace import DC, DCTERMS, DOAP, FOAF, SKOS, OWL, RDF, RDFS, VOID, XMLNS, XSD -``` - -You can use them like this: - -```python -from rdflib import Graph, URIRef, Literal -from rdflib.namespace import RDFS, XSD - -g = Graph() -semweb = URIRef('http://dbpedia.org/resource/Semantic_Web') -type = g.value(semweb, RDFS.label) -``` -Where `RDFS` is the RDFS namespace, `XSD` the XML Schema Datatypes namespace and `g.value` returns an object of the triple-pattern given (or an arbitrary one if multiple exist). - -Or like this, adding a triple to a graph `g`: - -```python -g.add(( - URIRef("http://example.com/person/nick"), - FOAF.givenName, - Literal("Nick", datatype=XSD.string) -)) -``` -The triple (in n-triples notation) ` "Nick"^^ .` -is created where the property `FOAF.givenName` is the URI `` and `XSD.string` is the -URI ``. - -You can bind namespaces to prefixes to shorten the URIs for RDF/XML, Turtle, N3, TriG, TriX & JSON-LD serializations: - - ```python -g.bind("foaf", FOAF) -g.bind("xsd", XSD) -``` -This will allow the n-triples triple above to be serialised like this: - ```python -print(g.serialize(format="turtle")) -``` - -With these results: -```turtle -PREFIX foaf: -PREFIX xsd: - - foaf:givenName "Nick"^^xsd:string . -``` - -New Namespaces can also be defined: - -```python -dbpedia = Namespace('http://dbpedia.org/ontology/') - -abstracts = list(x for x in g.objects(semweb, dbpedia['abstract']) if x.language=='en') -``` - -See also [./examples](./examples) - - -## Features -The library contains parsers and serializers for RDF/XML, N3, -NTriples, N-Quads, Turtle, TriX, JSON-LD, RDFa and Microdata. - -The library presents a Graph interface which can be backed by -any one of a number of Store implementations. - -This core RDFLib package includes store implementations for -in-memory storage and persistent storage on top of the Berkeley DB. - -A SPARQL 1.1 implementation is included - supporting SPARQL 1.1 Queries and Update statements. - -RDFLib is open source and is maintained on [GitHub](https://github.com/RDFLib/rdflib/). RDFLib releases, current and previous -are listed on [PyPI](https://pypi.python.org/pypi/rdflib/) - -Multiple other projects are contained within the RDFlib "family", see . - -## Running tests - -### Running the tests on the host - -Run the test suite with `pytest`. -```shell -poetry install -poetry run pytest -``` - -### Running test coverage on the host with coverage report - -Run the test suite and generate a HTML coverage report with `pytest` and `pytest-cov`. -```shell -poetry run pytest --cov -``` - -### Viewing test coverage - -Once tests have produced HTML output of the coverage report, view it by running: -```shell -poetry run pytest --cov --cov-report term --cov-report html -python -m http.server --directory=htmlcov -``` - -## Contributing - -RDFLib survives and grows via user contributions! -Please read our [contributing guide](https://rdflib.readthedocs.io/en/latest/CONTRIBUTING.html) and [developers guide](https://rdflib.readthedocs.io/en/latest/developers.html) to get started. -Please consider lodging Pull Requests here: - -* - -To get a development environment consider using Gitpod or Google Cloud Shell. - -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/RDFLib/rdflib) -[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://shell.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FRDFLib%2Frdflib&cloudshell_git_branch=main&cloudshell_open_in_editor=README.md) - -You can also raise issues here: - -* - -## Support & Contacts -For general "how do I..." queries, please use https://stackoverflow.com and tag your question with `rdflib`. -Existing questions: - -* - -If you want to contact the rdflib maintainers, please do so via: - -* the rdflib-dev mailing list: -* the chat, which is available at [gitter](https://gitter.im/RDFLib/rdflib) or via matrix [#RDFLib_rdflib:gitter.im](https://matrix.to/#/#RDFLib_rdflib:gitter.im) - diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/RECORD deleted file mode 100644 index 6ecc00e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/RECORD +++ /dev/null @@ -1,129 +0,0 @@ -rdflib/__init__.py,sha256=45nVfJXj6gKUN41dKfeitAXiRxStV4DgRaAHDJOm2SY,4810 -rdflib/_networking.py,sha256=h7fmP4F-UOBl13LgwohSVZ-eFhlOvBmQtFCtn7BunmM,4625 -rdflib/_type_checking.py,sha256=3DX4uvHqtemcA22WRyvh5dHfhXCI-rdAju7W9siJQug,910 -rdflib/collection.py,sha256=ps9jitftHUJY8qtah0nh0sWf7nAe_mGDWJaXsFbAvaQ,9984 -rdflib/compare.py,sha256=QBVk0M0PNzNqWQJdyujPK4ndmtDkKvZF-rN9N8oOP2U,21980 -rdflib/compat.py,sha256=lmdF6eDnroUYERcZsYrr9xEvXfaiD8-hdAEKoeqvk9w,2406 -rdflib/container.py,sha256=ZBpM2gRKlBPPgcxiKhABDDU4C6-tr5fEI0hB2fYrHRw,8227 -rdflib/events.py,sha256=YIzmlMEzEH_geUyYVCx8il-ucQQdZJiCiciEuTxRnCU,2945 -rdflib/exceptions.py,sha256=5LYvnkGqs0snG8nRe9OF9jndaJnd54ayKS2slH7ahZc,850 -rdflib/extras/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -rdflib/extras/cmdlineutils.py,sha256=5AH_JNF--DRZWSXh5PoHi4lm9nivXnioz1w1pMrkCxE,1948 -rdflib/extras/describer.py,sha256=-Pu7QuA5kJBY6Chv-2hFULsBuU4d8YBBQ1WWKDymlpw,9272 -rdflib/extras/external_graph_libs.py,sha256=sFoMcAwQynQfyTxwj31KAVo3uQZ3xPvxZZ1_dmOIkBo,11926 -rdflib/extras/infixowl.py,sha256=4RiZpBWZehLEjrP1sU4L76xDiBTz-JsyGR9Tmx4nIKw,80793 -rdflib/extras/shacl.py,sha256=7h62KQbun5pDMmq3PVek2IF_4XFY3MrheAGHeDile9I,8313 -rdflib/graph.py,sha256=FARsWuQO5QxpHcInxFLaUUvPEOiDAkRgPEux0EtVWHo,115894 -rdflib/namespace/_BRICK.py,sha256=XsMA9-_01jbMR1T9l-3600q4K1v4TZU8nAn7pjbiIKA,126990 -rdflib/namespace/_CSVW.py,sha256=veMbUAm24GONxs1Kdk1VMat65niKWEPySlqcT8YxLQg,12976 -rdflib/namespace/_DC.py,sha256=mjA91wYdEvT-Hx79RHZgcpMB_SVw_yjwj98F6_iD4vg,1673 -rdflib/namespace/_DCAM.py,sha256=JxvGJe95380fDIvZsgUhIGYGI9aIF7aF_4hf6RjY63Y,887 -rdflib/namespace/_DCAT.py,sha256=pHlF5yFsUAu6RqfbyvULir6tiQpDTCiNzPGwIbGEiYs,5474 -rdflib/namespace/_DCMITYPE.py,sha256=MC2f0ChRgWho8hS9Rv1dGO3LY_g1WP1WPkwcYfh6d6c,1337 -rdflib/namespace/_DCTERMS.py,sha256=4HDU5fid7Z0v6MOUuZpvvHnNQ3MzMeboizsfgJg4qxA,10012 -rdflib/namespace/_DOAP.py,sha256=wk_uK25tvoAjwJSieIpiUeg1iJoCq6yd33D2fPWokSQ,14664 -rdflib/namespace/_FOAF.py,sha256=io2arNzBsiYtHXJVxz9UdhljSPNFEkC4L_YmWqTomqI,6247 -rdflib/namespace/_GEO.py,sha256=wQZK_UEQNK47HqcKVUdUcuj-jTaYsoMtNNC3wC3ktBY,9137 -rdflib/namespace/_ODRL2.py,sha256=yeDIBtPymmv0cwsxoW22OogQibcBkMl1OC4IZH2ECYs,22158 -rdflib/namespace/_ORG.py,sha256=zhobrfzEmjam_W0JeZKKJxIcvID3SE1TcWKjrD8CIuo,13207 -rdflib/namespace/_OWL.py,sha256=Q_A272osHglNHzvJVaaR0-h31TuJBeLKS2TS7NM5R7w,10480 -rdflib/namespace/_PROF.py,sha256=QKYhG7ulMe_6wKS5Ye6FZ_oghKeVmo7Qdcupk7vMlyQ,2807 -rdflib/namespace/_PROV.py,sha256=DNq0vTDBa9Vh4rXMVnz5VJ8vIRSPltHn8nhljdyStes,24148 -rdflib/namespace/_QB.py,sha256=bPegKsZ_iZh47HPoeRqIN2k1FXNYG6kITECKaqN75vw,5413 -rdflib/namespace/_RDF.py,sha256=icPqdMkOC1ukMJDyGFR6nWdC7KsMp1cuHX2_587SXnc,2249 -rdflib/namespace/_RDFS.py,sha256=Gw0zTb0B0VTn2pvwI3bQYEqjH91JguG_XSy3den7DDA,1488 -rdflib/namespace/_SDO.py,sha256=iCWwLFWqoupbQK7d2k_7zqD84SZ90LAHijexqTU47kU,424141 -rdflib/namespace/_SH.py,sha256=dMK9rpvD9JqrVssb3jYUniuOQjF4Ug4C-3nK86ahPPQ,23321 -rdflib/namespace/_SKOS.py,sha256=qnTVyb31WxMoFf2vRcEnAYXJXaEwsVpCNKeUMl73_d8,4715 -rdflib/namespace/_SOSA.py,sha256=BzuIlQSzNgaN5jYMQaR0HA4COX68wsROl2gOI2in8v8,7117 -rdflib/namespace/_SSN.py,sha256=T9JKgBQdipzcKc3o6xwz4wM9WLI-avhywRXROqCbHkM,3213 -rdflib/namespace/_TIME.py,sha256=JiSNziV0A4r8KMstVppHgeY8ZHzDzQhzwU7lHybpblI,12936 -rdflib/namespace/_VANN.py,sha256=pKantDMzEu_wfOFT7zXYIhFlsgTJu_ylgv5PCpRGLJE,1232 -rdflib/namespace/_VOID.py,sha256=Nyv3GnciRwLLu6aNL-feMbrRuYv4fU66deCwDVCFSjA,4689 -rdflib/namespace/_WGS.py,sha256=HPXnL6MqFJ8b6uVl_QdgG456dZLKfwH89UpAC7G58Pc,633 -rdflib/namespace/_XSD.py,sha256=vPN0Cg5PcZzqIj4NdwhFiYOJuiHYbCUb5v-tBsWAQGs,6276 -rdflib/namespace/__init__.py,sha256=4CygT9SOx0RW4Hq6sUn_xs0TF5I-WaVXpYySysYioVE,34459 -rdflib/parser.py,sha256=-L6ICHjJmfh48c6XYronS-vGtc7IUiCfbvae-ZDR6-A,27922 -rdflib/paths.py,sha256=paWIOfe1kzASeFglLB3wQtjtPfUvjc-AjDboPHi99oM,21574 -rdflib/plugin.py,sha256=OxrWq--ks70qn2cr4DCJd_QBb-BKcjgkmf9oxitKdEE,13018 -rdflib/plugins/__init__.py,sha256=39nGkLLAy54hfMDO9jCpUoaAcVeDdmKCKB3xRQ7KnkA,111 -rdflib/plugins/parsers/RDFVOC.py,sha256=WTqXCoT8Lu3o58z6IqECgu30aKumUGDRQX4iApKgZSE,481 -rdflib/plugins/parsers/__init__.py,sha256=ekSQ4YBr0bT86j5BplDSgH-SoHHF3gZP_xShRG6Z6Dk,9 -rdflib/plugins/parsers/hext.py,sha256=1J4ZexQ2lrqgwip-7c5JOqBWAR0961XMmFmtEJuT1xE,6459 -rdflib/plugins/parsers/jsonld.py,sha256=EFfkXMiVgt_9FSXpddUoMi8NUyr-TcBx9MI3SMESHuk,24464 -rdflib/plugins/parsers/notation3.py,sha256=dhZRrIP2JXh-H8eRMkkxA-z-dFb6iKiuL6X8IDDhGoE,67225 -rdflib/plugins/parsers/nquads.py,sha256=Cfj7oKSMnlaFkjCjfaclbPCgDFF6Y3teM4ntHJnxLDs,5092 -rdflib/plugins/parsers/ntriples.py,sha256=oJEJMa7ZKjrWmCTGEQK6isIUJQDB2SEE4PoukEQ1_4I,12690 -rdflib/plugins/parsers/patch.py,sha256=4svNTg51HFJbV5Ky1u1HLAvCk2D29A69UsmXeMK67J4,6714 -rdflib/plugins/parsers/rdfxml.py,sha256=HqrCEUreFhGzsAdxP_64u-iLNFqWPsZz0-MxBbDwjK4,25898 -rdflib/plugins/parsers/trig.py,sha256=_KKmS5XYnGMv8pqoVBNTo9LyLjNTcr1GKkOyb0jscMU,5428 -rdflib/plugins/parsers/trix.py,sha256=gh_msqDxG8xuiNUUree42KbDJUHRjmqp9ZbjwY3kBQk,10078 -rdflib/plugins/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -rdflib/plugins/serializers/hext.py,sha256=xc__dMPlKO5beQqQLWFD2wPyldht72t6B2r805TG1Bo,7549 -rdflib/plugins/serializers/jsonld.py,sha256=3lEKgQeJEcN7iUktezhRM3-MyKaVGQ7VPgCUqkvIb_A,15351 -rdflib/plugins/serializers/longturtle.py,sha256=Drwl567oldL5NtfeQTHz2s_yYKSMZRof7-nhWIbX6ZQ,10339 -rdflib/plugins/serializers/n3.py,sha256=BYiEPX6kCyL49zmlW2LkGsqrYTacVx6wrbZak0Liluc,3105 -rdflib/plugins/serializers/nquads.py,sha256=9Na0JfLO-8IGcIhR3D9C6H0SgAc5LIwlkxnEDSMGdUo,1837 -rdflib/plugins/serializers/nt.py,sha256=GJOw3cdCji2ff3dPyMx65CIIsmSqFAiRV_5PO716Yqc,3131 -rdflib/plugins/serializers/patch.py,sha256=aok828-wYXwUsY1dp60WisO3BCOqtokoxRrqugvekjU,4089 -rdflib/plugins/serializers/rdfxml.py,sha256=KGWzBqkraqp6LVNAbm42DfebjknalmJqR5Dw5cL3q5U,15685 -rdflib/plugins/serializers/trig.py,sha256=2t0F4dLVSnXuTIrE2z9hP7GW3j9nWVBC2NxMj2gM8T8,3980 -rdflib/plugins/serializers/trix.py,sha256=gysxJQwLxTijVs620CRzRqS-BIQIThep9ks1QsdTT_I,3429 -rdflib/plugins/serializers/turtle.py,sha256=buMf0jc_VbfZYTVWDmvaRIOl8a4826e5Rqk3aqhqRXQ,15502 -rdflib/plugins/serializers/xmlwriter.py,sha256=Cg10lhGxKYyKe71WwTeCJ9RQ7p4VaEol9FagoIBEiJo,4284 -rdflib/plugins/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -rdflib/plugins/shared/jsonld/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -rdflib/plugins/shared/jsonld/context.py,sha256=3fK0EQrfsVD_SGddo-GJM3_mX5Gz9jp0McF4aFW0OYI,23106 -rdflib/plugins/shared/jsonld/errors.py,sha256=QGRCaFanGyYmXrw2LNTTYBYklvz_bUG5VyysZFyYxY4,435 -rdflib/plugins/shared/jsonld/keys.py,sha256=SHKyniVqNBoV6MtUKmk_ltE2JXoFUbwpi7vtW8tLGrY,534 -rdflib/plugins/shared/jsonld/util.py,sha256=VDesnp3mbMpfe0qEPg2mPwCk7QF8JTAyVI_J45J1RQQ,12822 -rdflib/plugins/sparql/__init__.py,sha256=7P5HqP5XdcwaX5hrI6n8_Mc0E1pOWU477JJhodyHevY,1379 -rdflib/plugins/sparql/aggregates.py,sha256=rmSkZPnikO7dBMkjkWs4g2S_eFjGBdbhkdpIpFWEqyk,10681 -rdflib/plugins/sparql/algebra.py,sha256=T-dr_lTEMu7oZCJJtSd74MJDK2B93vUJYJVQW5MBYL8,60999 -rdflib/plugins/sparql/datatypes.py,sha256=E8Oo4eIkl1d6rg6wjzjok0ZDeQECygU3bTxEsIz8vHI,2547 -rdflib/plugins/sparql/evaluate.py,sha256=XwPACIg8ikVHiSCWJ9-PGo954is7yhB2kCoZtFfpfNY,21814 -rdflib/plugins/sparql/evalutils.py,sha256=HUFnd5GJ6_OCV-zI4gidCnHfZHCxD3zN6MtRdr01nQk,4908 -rdflib/plugins/sparql/operators.py,sha256=2xv4x_XkmpIwwJor7R7v32neYtdRtBjBaC1tb6skg-Q,36819 -rdflib/plugins/sparql/parser.py,sha256=FsKaQ0zTaR3bNPaZqPp4R6xXIaJhudc9r2HuJVlN5dM,51688 -rdflib/plugins/sparql/parserutils.py,sha256=K5j6ghKrTwt0_6abCJWG4zK5p7yf5b1hyFqiuwujI7M,9202 -rdflib/plugins/sparql/processor.py,sha256=5ECDK2782FULXTmtJbPNPY5XhnpKTbSWw5XuPovAaPM,4936 -rdflib/plugins/sparql/results/__init__.py,sha256=4N9RA47kn1q0uOiRJddc_TpU9tiibuoq2pmUG2dio18,58 -rdflib/plugins/sparql/results/csvresults.py,sha256=qSIlhddaKC6y48PhiwORjFQf6UcG5Je5jmuqlB7vddM,3708 -rdflib/plugins/sparql/results/graph.py,sha256=6slf96keAyM3w0stGN9jdJQl2xnPnYSrOv5AcqTX9QQ,530 -rdflib/plugins/sparql/results/jsonresults.py,sha256=AXNRvqNph1N8bCKJ6fQy2sfjQQpCPY5HvzMiRiNMzIo,5541 -rdflib/plugins/sparql/results/rdfresults.py,sha256=0nGwPcdkyhLXTQGdNdFSO7CWEQJi8nWjrxfVmBO3SFQ,2780 -rdflib/plugins/sparql/results/tsvresults.py,sha256=zwrrHeL9Ur1tNv2UuG8jr0Lql_V-l6MwavqRoCA7dXw,3118 -rdflib/plugins/sparql/results/txtresults.py,sha256=wU3nVevDaRpVnXF7n2U5nvaqnRvk1bOQ46ZufcVOvZ0,3136 -rdflib/plugins/sparql/results/xmlresults.py,sha256=BlvBDWhJjk8ZE8gkRoLstta7V7ZEZUvRXLCIypYSFuc,12236 -rdflib/plugins/sparql/sparql.py,sha256=2yjv-n0N7QE2O4d7J5JJ7Xh6hDJAQXbRv-NL8sSBuk0,15830 -rdflib/plugins/sparql/update.py,sha256=z-pVF-UGBa54snywD_TQg_OsL9R_7tQfoq3s8H51jB4,11502 -rdflib/plugins/stores/__init__.py,sha256=NGddME-fuVX1SBSkNld2FBLchmKR8rNs5mi3EL3Top8,67 -rdflib/plugins/stores/auditable.py,sha256=8byKEmRbsDolmDhidKPzhiq3BZN7iK7ZDs3yeru7wdw,7872 -rdflib/plugins/stores/berkeleydb.py,sha256=GR-61ejRIcyQEiBkn1czthk8mJWQtTGj-xCMPQnLobc,29510 -rdflib/plugins/stores/concurrent.py,sha256=RRDdaKQPV0MAkV9EjDBoRTf06QRsmBnD2hCQOivVW_w,2719 -rdflib/plugins/stores/memory.py,sha256=6jvyGatLBsn-PKf-XmxCzg9mOPkifJ3TlZE9z4dkTO4,30102 -rdflib/plugins/stores/regexmatching.py,sha256=4nMbcJN7ayFdll6VhSUmCAWIwMBHBOgU_Yt8LTvQ2Ao,6490 -rdflib/plugins/stores/sparqlconnector.py,sha256=p-tK8HWbgHL_6IJLfdsaaQBlU7MQZ7ez4UhvmIw6zKI,6499 -rdflib/plugins/stores/sparqlstore.py,sha256=EaSzWtezBpkgOH1Ls8A3CpMdMLwJ3WlMcpHyKbvoJTQ,38947 -rdflib/py.typed,sha256=KT9WNyn4878ZisihNjjF3Bm2qu8R9s2F5irJrg8vxhQ,66 -rdflib/query.py,sha256=Zm-Sdh2ItowA5NOGI7oVv_5XzSe8GYewf04mxwTNHwg,15084 -rdflib/resource.py,sha256=3WUi8eORT8pfcibMjMes-1YeaTeo_HKveQ1LQWwmObE,13989 -rdflib/serializer.py,sha256=ZoGUQgdvipC2MQX-rDv2Bamgb_rNPVVb8BzaHICUfV0,1309 -rdflib/store.py,sha256=41ompboCBePJ5BwAe4ilXZBYDBL7mzY6izV4mXe4AII,15997 -rdflib/term.py,sha256=a43BOi9sXJWg_53fsb7PjxF6SXFnKFuppN9LYAzuKQM,89231 -rdflib/tools/__init__.py,sha256=YzY7Eyz4zw8Ib5fl5bv4bQXzbAbsVxa2LrybTtJDYw0,58 -rdflib/tools/chunk_serializer.py,sha256=qU-7Zsfh2zrsviQyLCiRXMKaFfo3LeafS6mEWeXm2YY,4830 -rdflib/tools/csv2rdf.py,sha256=f3xbvIQtThwTinEFuoxaIzYk2dDWf_3zbf2U7v5lyvw,16696 -rdflib/tools/defined_namespace_creator.py,sha256=0Dns50_gRl7tO7rL6jN2USYAADvjLWFkQlTI8MZfSkw,6719 -rdflib/tools/graphisomorphism.py,sha256=8gZxbH5vKhpZ6vIVY8ohJ8SoBRJOMZhQVDkhKMr2ZuA,3411 -rdflib/tools/rdf2dot.py,sha256=lKdE1Xi7O8N-4rcUnh1KLtwxsC_Uop03eh-BrV2JCiU,4995 -rdflib/tools/rdfpipe.py,sha256=4PZ6ufyXANPTQlEyJm_5IdNAiFlC6xr-gpo_BNHxEHE,5498 -rdflib/tools/rdfs2dot.py,sha256=kLf9cK-cC5WECqRRD1S6Vk-6c2-Vk_kniytbxvWf5CY,3783 -rdflib/util.py,sha256=5mE34oBp25x3jWTjijAtGCQ7oBOqvwnFK1aOz7xLZcU,17596 -rdflib/void.py,sha256=KsD_bmJnJA64XahflTyq1Fm-5EtHkEa-Br4-KLCTm1g,4641 -rdflib/xsd_datetime.py,sha256=q_8F2mj9tSb8QARFP6dH40xnKr-Lh7yE7U2jistiezM,26256 -rdflib-7.1.4.dist-info/LICENSE,sha256=8pQbC6z8Rsa_4TzZjKtorbeENXTDeCmX46J2TNVFviM,1524 -rdflib-7.1.4.dist-info/METADATA,sha256=8vbZU4iFAgZ8nncWlIZZAa0EmEZZH5yxNweMnH67TQs,11551 -rdflib-7.1.4.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88 -rdflib-7.1.4.dist-info/entry_points.txt,sha256=UJ2UwT8m9TvV7UrdJM2fcEREwExL_RQVEfnID-Qnkdk,212 -rdflib-7.1.4.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/WHEEL deleted file mode 100644 index cafd7e1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: poetry-core 2.0.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/entry_points.txt deleted file mode 100644 index e2543c7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib-7.1.4.dist-info/entry_points.txt +++ /dev/null @@ -1,7 +0,0 @@ -[console_scripts] -csv2rdf=rdflib.tools.csv2rdf:main -rdf2dot=rdflib.tools.rdf2dot:main -rdfgraphisomorphism=rdflib.tools.graphisomorphism:main -rdfpipe=rdflib.tools.rdfpipe:main -rdfs2dot=rdflib.tools.rdfs2dot:main - diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/__init__.py deleted file mode 100644 index 051c5e3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/__init__.py +++ /dev/null @@ -1,202 +0,0 @@ -"""A pure Python package providing the core RDF constructs. - -The packages is intended to provide the core RDF types and interfaces -for working with RDF. The package defines a plugin interface for -parsers, stores, and serializers that other packages can use to -implement parsers, stores, and serializers that will plug into the -rdflib package. - -The primary interface `rdflib` exposes to work with RDF is -`rdflib.graph.Graph`. - -A tiny example: - - >>> from rdflib import Graph, URIRef, Literal - - >>> g = Graph() - >>> result = g.parse("http://www.w3.org/2000/10/swap/test/meet/blue.rdf") - - >>> print("graph has %s statements." % len(g)) - graph has 4 statements. - >>> - >>> for s, p, o in g: - ... if (s, p, o) not in g: - ... raise Exception("It better be!") - - >>> s = g.serialize(format='nt') - >>> - >>> sorted(g) == [ - ... (URIRef("http://meetings.example.com/cal#m1"), - ... URIRef("http://www.example.org/meeting_organization#homePage"), - ... URIRef("http://meetings.example.com/m1/hp")), - ... (URIRef("http://www.example.org/people#fred"), - ... URIRef("http://www.example.org/meeting_organization#attending"), - ... URIRef("http://meetings.example.com/cal#m1")), - ... (URIRef("http://www.example.org/people#fred"), - ... URIRef("http://www.example.org/personal_details#GivenName"), - ... Literal("Fred")), - ... (URIRef("http://www.example.org/people#fred"), - ... URIRef("http://www.example.org/personal_details#hasEmail"), - ... URIRef("mailto:fred@example.com")) - ... ] - True - -""" - -import logging -import sys -from importlib import metadata - -_DISTRIBUTION_METADATA = metadata.metadata("rdflib") - -__docformat__ = "restructuredtext en" - -__version__: str = _DISTRIBUTION_METADATA["Version"] -__date__ = "2025-03-29" - -__all__ = [ - "URIRef", - "BNode", - "IdentifiedNode", - "Literal", - "Node", - "Variable", - "Namespace", - "Dataset", - "Graph", - "ConjunctiveGraph", - "BRICK", - "CSVW", - "DC", - "DCAT", - "DCMITYPE", - "DCTERMS", - "DOAP", - "FOAF", - "ODRL2", - "ORG", - "OWL", - "PROF", - "PROV", - "QB", - "RDF", - "RDFS", - "SDO", - "SH", - "SKOS", - "SOSA", - "SSN", - "TIME", - "VANN", - "VOID", - "XMLNS", - "XSD", - "util", - "plugin", - "query", - "NORMALIZE_LITERALS", -] - -logger = logging.getLogger(__name__) - -try: - import __main__ - - if ( - not hasattr(__main__, "__file__") - and sys.stdout is not None - and hasattr(sys.stderr, "isatty") - and sys.stderr.isatty() - ): - # show log messages in interactive mode - logger.setLevel(logging.INFO) - logger.addHandler(logging.StreamHandler()) - del __main__ -except ImportError: - # Main already imported from elsewhere - import warnings - - warnings.warn("__main__ already imported", ImportWarning) - del warnings - -del sys - - -NORMALIZE_LITERALS = True -""" -If True - Literals lexical forms are normalized when created. -I.e. the lexical forms is parsed according to data-type, then the -stored lexical form is the re-serialized value that was parsed. - -Illegal values for a datatype are simply kept. The normalized keyword -for Literal.__new__ can override this. - -For example: - ->>> from rdflib import Literal,XSD ->>> Literal("01", datatype=XSD.int) -rdflib.term.Literal("1", datatype=rdflib.term.URIRef("http://www.w3.org/2001/XMLSchema#integer")) - -This flag may be changed at any time, but will only affect literals -created after that time, previously created literals will remain -(un)normalized. - -""" - - -DAWG_LITERAL_COLLATION = False -""" -DAWG_LITERAL_COLLATION determines how literals are ordered or compared -to each other. - -In SPARQL, applying the >,<,>=,<= operators to literals of -incompatible data-types is an error, i.e: - -Literal(2)>Literal('cake') is neither true nor false, but an error. - -This is a problem in PY3, where lists of Literals of incompatible -types can no longer be sorted. - -Setting this flag to True gives you strict DAWG/SPARQL compliance, -setting it to False will order Literals with incompatible datatypes by -datatype URI - -In particular, this determines how the rich comparison operators for -Literal work, eq, __neq__, __lt__, etc. -""" - - -from rdflib.graph import ConjunctiveGraph, Dataset, Graph -from rdflib.namespace import ( - BRICK, - CSVW, - DC, - DCAT, - DCMITYPE, - DCTERMS, - DOAP, - FOAF, - ODRL2, - ORG, - OWL, - PROF, - PROV, - QB, - RDF, - RDFS, - SDO, - SH, - SKOS, - SOSA, - SSN, - TIME, - VANN, - VOID, - XMLNS, - XSD, - Namespace, -) -from rdflib.term import BNode, IdentifiedNode, Literal, Node, URIRef, Variable - -from rdflib import plugin, query, util # isort:skip -from rdflib.container import * # isort:skip # noqa: F403 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/_networking.py b/extensions/.local/lib/python3.11/site-packages/rdflib/_networking.py deleted file mode 100644 index 311096a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/_networking.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -import string -import sys -from typing import Dict -from urllib.error import HTTPError -from urllib.parse import quote as urlquote -from urllib.parse import urljoin, urlsplit -from urllib.request import HTTPRedirectHandler, Request, urlopen -from urllib.response import addinfourl - - -def _make_redirect_request(request: Request, http_error: HTTPError) -> Request: - """ - Create a new request object for a redirected request. - - The logic is based on `urllib.request.HTTPRedirectHandler` from `this commit _`. - - :param request: The original request that resulted in the redirect. - :param http_error: The response to the original request that indicates a - redirect should occur and contains the new location. - :return: A new request object to the location indicated by the response. - :raises HTTPError: the supplied ``http_error`` if the redirect request - cannot be created. - :raises ValueError: If the response code is `None`. - :raises ValueError: If the response does not contain a ``Location`` header - or the ``Location`` header is not a string. - :raises HTTPError: If the scheme of the new location is not ``http``, - ``https``, or ``ftp``. - :raises HTTPError: If there are too many redirects or a redirect loop. - """ - new_url = http_error.headers.get("Location") - if new_url is None: - raise http_error - if not isinstance(new_url, str): - raise ValueError(f"Location header {new_url!r} is not a string") - - new_url_parts = urlsplit(new_url) - - # For security reasons don't allow redirection to anything other than http, - # https or ftp. - if new_url_parts.scheme not in ("http", "https", "ftp", ""): - raise HTTPError( - new_url, - http_error.code, - f"{http_error.reason} - Redirection to url {new_url!r} is not allowed", - http_error.headers, - http_error.fp, - ) - - # http.client.parse_headers() decodes as ISO-8859-1. Recover the original - # bytes and percent-encode non-ASCII bytes, and any special characters such - # as the space. - new_url = urlquote(new_url, encoding="iso-8859-1", safe=string.punctuation) - new_url = urljoin(request.full_url, new_url) - - # XXX Probably want to forget about the state of the current - # request, although that might interact poorly with other - # handlers that also use handler-specific request attributes - content_headers = ("content-length", "content-type") - newheaders = { - k: v for k, v in request.headers.items() if k.lower() not in content_headers - } - new_request = Request( - new_url, - headers=newheaders, - origin_req_host=request.origin_req_host, - unverifiable=True, - ) - - visited: Dict[str, int] - if hasattr(request, "redirect_dict"): - visited = request.redirect_dict - if ( - visited.get(new_url, 0) >= HTTPRedirectHandler.max_repeats - or len(visited) >= HTTPRedirectHandler.max_redirections - ): - raise HTTPError( - request.full_url, - http_error.code, - HTTPRedirectHandler.inf_msg + http_error.reason, - http_error.headers, - http_error.fp, - ) - else: - visited = {} - setattr(request, "redirect_dict", visited) - - setattr(new_request, "redirect_dict", visited) - visited[new_url] = visited.get(new_url, 0) + 1 - return new_request - - -def _urlopen(request: Request) -> addinfourl: - """ - This is a shim for `urlopen` that handles HTTP redirects with status code - 308 (Permanent Redirect). - - This function should be removed once all supported versions of Python - handles the 308 HTTP status code. - - :param request: The request to open. - :return: The response to the request. - """ - try: - return urlopen(request) - except HTTPError as error: - if error.code == 308 and sys.version_info < (3, 11): - # HTTP response code 308 (Permanent Redirect) is not supported by python - # versions older than 3.11. See and - # for more details. - # This custom error handling should be removed once all supported - # versions of Python handles 308. - new_request = _make_redirect_request(request, error) - return _urlopen(new_request) - else: - raise diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/_type_checking.py b/extensions/.local/lib/python3.11/site-packages/rdflib/_type_checking.py deleted file mode 100644 index 1bbeda1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/_type_checking.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -This module contains type aliases that should only be used when type checking -as it would otherwise introduce a runtime dependency on `typing_extensions` for -older python versions which is not desirable. - -This was made mainly to accommodate ``sphinx-autodoc-typehints`` which cannot -recognize type aliases from imported files if the type aliases are defined -inside ``if TYPE_CHECKING:``. So instead of placing the type aliases in normal -modules inside ``TYPE_CHECKING`` guards they are in this file which should only -be imported inside ``TYPE_CHECKING`` guards. - -.. important:: - Things inside this module are not for use outside of RDFLib - and this module is not part the the RDFLib public API. -""" - -__all__ = [ - "_NamespaceSetString", - "_MulPathMod", -] - - -from typing import Literal as PyLiteral - -_NamespaceSetString = PyLiteral["core", "rdflib", "none"] -_MulPathMod = PyLiteral["*", "+", "?"] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/collection.py b/extensions/.local/lib/python3.11/site-packages/rdflib/collection.py deleted file mode 100644 index ed0a48f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/collection.py +++ /dev/null @@ -1,277 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Iterable, Iterator, List, Optional - -from rdflib.namespace import RDF -from rdflib.term import BNode, Node - -if TYPE_CHECKING: - from rdflib.graph import Graph - -__all__ = ["Collection"] - - -class Collection: - """ - See "Emulating container types": - https://docs.python.org/reference/datamodel.html#emulating-container-types - - >>> from rdflib.term import Literal - >>> from rdflib.graph import Graph - >>> from pprint import pprint - >>> listname = BNode() - >>> g = Graph('Memory') - >>> listItem1 = BNode() - >>> listItem2 = BNode() - >>> g.add((listname, RDF.first, Literal(1))) # doctest: +ELLIPSIS - )> - >>> g.add((listname, RDF.rest, listItem1)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem1, RDF.first, Literal(2))) # doctest: +ELLIPSIS - )> - >>> g.add((listItem1, RDF.rest, listItem2)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem2, RDF.rest, RDF.nil)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem2, RDF.first, Literal(3))) # doctest: +ELLIPSIS - )> - >>> c = Collection(g,listname) - >>> pprint([term.n3() for term in c]) - ['"1"^^', - '"2"^^', - '"3"^^'] - - >>> Literal(1) in c - True - >>> len(c) - 3 - >>> c._get_container(1) == listItem1 - True - >>> c.index(Literal(2)) == 1 - True - - The collection is immutable if ``uri`` is the empty list - (``http://www.w3.org/1999/02/22-rdf-syntax-ns#nil``). - """ - - def __init__(self, graph: Graph, uri: Node, seq: List[Node] = []): - self.graph = graph - self.uri = uri or BNode() - if seq: - self += seq - - def n3(self) -> str: - """ - >>> from rdflib.term import Literal - >>> from rdflib.graph import Graph - >>> listname = BNode() - >>> g = Graph('Memory') - >>> listItem1 = BNode() - >>> listItem2 = BNode() - >>> g.add((listname, RDF.first, Literal(1))) # doctest: +ELLIPSIS - )> - >>> g.add((listname, RDF.rest, listItem1)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem1, RDF.first, Literal(2))) # doctest: +ELLIPSIS - )> - >>> g.add((listItem1, RDF.rest, listItem2)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem2, RDF.rest, RDF.nil)) # doctest: +ELLIPSIS - )> - >>> g.add((listItem2, RDF.first, Literal(3))) # doctest: +ELLIPSIS - )> - >>> c = Collection(g, listname) - >>> print(c.n3()) #doctest: +NORMALIZE_WHITESPACE - ( "1"^^ - "2"^^ - "3"^^ ) - """ - return "( %s )" % (" ".join([i.n3() for i in self])) - - def _get_container(self, index: int) -> Optional[Node]: - """Gets the first, rest holding node at index.""" - assert isinstance(index, int) - graph = self.graph - container: Optional[Node] = self.uri - i = 0 - while i < index: - i += 1 - container = graph.value(container, RDF.rest) - if container is None: - break - return container - - def __len__(self) -> int: - """length of items in collection.""" - return len(list(self.graph.items(self.uri))) - - def index(self, item: Node) -> int: - """ - Returns the 0-based numerical index of the item in the list - """ - listname = self.uri - index = 0 - while True: - if (listname, RDF.first, item) in self.graph: - return index - else: - newlink = list(self.graph.objects(listname, RDF.rest)) - index += 1 - if newlink == [RDF.nil]: - raise ValueError("%s is not in %s" % (item, self.uri)) - elif not newlink: - raise Exception("Malformed RDF Collection: %s" % self.uri) - else: - assert len(newlink) == 1, "Malformed RDF Collection: %s" % self.uri - listname = newlink[0] - - def __getitem__(self, key: int) -> Node: - """TODO""" - c = self._get_container(key) - if c: - v = self.graph.value(c, RDF.first) - if v: - return v - else: - raise KeyError(key) - else: - raise IndexError(key) - - def __setitem__(self, key: int, value: Node) -> None: - """TODO""" - c = self._get_container(key) - if c: - self.graph.set((c, RDF.first, value)) - else: - raise IndexError(key) - - def __delitem__(self, key: int) -> None: - """ - >>> from rdflib.namespace import RDF, RDFS - >>> from rdflib import Graph - >>> from pprint import pformat - >>> g = Graph() - >>> a = BNode('foo') - >>> b = BNode('bar') - >>> c = BNode('baz') - >>> g.add((a, RDF.first, RDF.type)) # doctest: +ELLIPSIS - )> - >>> g.add((a, RDF.rest, b)) # doctest: +ELLIPSIS - )> - >>> g.add((b, RDF.first, RDFS.label)) # doctest: +ELLIPSIS - )> - >>> g.add((b, RDF.rest, c)) # doctest: +ELLIPSIS - )> - >>> g.add((c, RDF.first, RDFS.comment)) # doctest: +ELLIPSIS - )> - >>> g.add((c, RDF.rest, RDF.nil)) # doctest: +ELLIPSIS - )> - >>> len(g) - 6 - >>> def listAncestry(node, graph): - ... for i in graph.subjects(RDF.rest, node): - ... yield i - >>> [str(node.n3()) - ... for node in g.transitiveClosure(listAncestry, RDF.nil)] - ['_:baz', '_:bar', '_:foo'] - >>> lst = Collection(g, a) - >>> len(lst) - 3 - >>> b == lst._get_container(1) - True - >>> c == lst._get_container(2) - True - >>> del lst[1] - >>> len(lst) - 2 - >>> len(g) - 4 - - """ - self[key] # to raise any potential key exceptions - graph = self.graph - current = self._get_container(key) - assert current - if len(self) == 1 and key > 0: - pass - elif key == len(self) - 1: - # the tail - priorlink = self._get_container(key - 1) - # type error: Argument 1 to "set" of "Graph" has incompatible type "Tuple[Optional[Node], URIRef, URIRef]"; expected "Tuple[Node, Node, Any]" - self.graph.set((priorlink, RDF.rest, RDF.nil)) # type: ignore[arg-type] - graph.remove((current, None, None)) - else: - next = self._get_container(key + 1) - prior = self._get_container(key - 1) - assert next and prior - graph.remove((current, None, None)) - graph.set((prior, RDF.rest, next)) - - def __iter__(self) -> Iterator[Node]: - """Iterator over items in Collections""" - return self.graph.items(self.uri) - - def _end(self) -> Node: - # find end of list - container = self.uri - while True: - rest = self.graph.value(container, RDF.rest) - if rest is None or rest == RDF.nil: - return container - else: - container = rest - - def append(self, item: Node) -> Collection: - """ - >>> from rdflib.term import Literal - >>> from rdflib.graph import Graph - >>> listname = BNode() - >>> g = Graph() - >>> c = Collection(g,listname,[Literal(1),Literal(2)]) - >>> links = [ - ... list(g.subjects(object=i, predicate=RDF.first))[0] for i in c] - >>> len([i for i in links if (i, RDF.rest, RDF.nil) in g]) - 1 - - """ - - end = self._end() - if end == RDF.nil: - raise ValueError("Cannot append to empty list") - - if (end, RDF.first, None) in self.graph: - # append new node to the end of the linked list - node = BNode() - self.graph.set((end, RDF.rest, node)) - end = node - - self.graph.add((end, RDF.first, item)) - self.graph.add((end, RDF.rest, RDF.nil)) - return self - - def __iadd__(self, other: Iterable[Node]): - end = self._end() - if end == RDF.nil: - raise ValueError("Cannot append to empty list") - self.graph.remove((end, RDF.rest, None)) - - for item in other: - if (end, RDF.first, None) in self.graph: - nxt = BNode() - self.graph.add((end, RDF.rest, nxt)) - end = nxt - - self.graph.add((end, RDF.first, item)) - - self.graph.add((end, RDF.rest, RDF.nil)) - return self - - def clear(self): - container: Optional[Node] = self.uri - graph = self.graph - while container: - rest = graph.value(container, RDF.rest) - graph.remove((container, RDF.first, None)) - graph.remove((container, RDF.rest, None)) - container = rest - return self diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/compare.py b/extensions/.local/lib/python3.11/site-packages/rdflib/compare.py deleted file mode 100644 index afc2c40..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/compare.py +++ /dev/null @@ -1,631 +0,0 @@ -""" -A collection of utilities for canonicalizing and inspecting graphs. - -Among other things, they solve of the problem of deterministic bnode -comparisons. - -Warning: the time to canonicalize bnodes may increase exponentially on -degenerate larger graphs. Use with care! - -Example of comparing two graphs:: - - >>> g1 = Graph().parse(format='n3', data=''' - ... @prefix : . - ... :rel - ... , - ... [ :label "Same" ], - ... , - ... [ :label "A" ] . - ... ''') - >>> g2 = Graph().parse(format='n3', data=''' - ... @prefix : . - ... :rel - ... , - ... [ :label "Same" ], - ... , - ... [ :label "B" ] . - ... ''') - >>> - >>> iso1 = to_isomorphic(g1) - >>> iso2 = to_isomorphic(g2) - -These are not isomorphic:: - - >>> iso1 == iso2 - False - -Diff the two graphs:: - - >>> in_both, in_first, in_second = graph_diff(iso1, iso2) - -Present in both:: - - >>> def dump_nt_sorted(g): - ... for l in sorted(g.serialize(format='nt').splitlines()): - ... if l: print(l.decode('ascii')) - - >>> dump_nt_sorted(in_both) #doctest: +SKIP - - . - - _:cbcaabaaba17fecbc304a64f8edee4335e . - _:cbcaabaaba17fecbc304a64f8edee4335e - "Same" . - -Only in first:: - - >>> dump_nt_sorted(in_first) #doctest: +SKIP - - . - - _:cb124e4c6da0579f810c0ffe4eff485bd9 . - _:cb124e4c6da0579f810c0ffe4eff485bd9 - "A" . - -Only in second:: - - >>> dump_nt_sorted(in_second) #doctest: +SKIP - - . - - _:cb558f30e21ddfc05ca53108348338ade8 . - _:cb558f30e21ddfc05ca53108348338ade8 - "B" . -""" - -from __future__ import annotations - -# TODO: -# - Doesn't handle quads. -# - Add warning and/or safety mechanism before working on large graphs? -# - use this in existing Graph.isomorphic? - -__all__ = [ - "IsomorphicGraph", - "to_isomorphic", - "isomorphic", - "to_canonical_graph", - "graph_diff", - "similar", -] - -from collections import defaultdict -from datetime import datetime -from hashlib import sha256 -from typing import ( - TYPE_CHECKING, - Callable, - Dict, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) - -from rdflib.graph import ConjunctiveGraph, Graph, ReadOnlyGraphAggregate, _TripleType -from rdflib.term import BNode, IdentifiedNode, Node, URIRef - -if TYPE_CHECKING: - from _hashlib import HASH - - -def _total_seconds(td): - result = td.days * 24 * 60 * 60 - result += td.seconds - result += td.microseconds / 1000000.0 - return result - - -class _runtime: # noqa: N801 - def __init__(self, label): - self.label = label - - def __call__(self, f): - if self.label is None: - self.label = f.__name__ + "_runtime" - - def wrapped_f(*args, **kwargs): - start = datetime.now() - result = f(*args, **kwargs) - if "stats" in kwargs and kwargs["stats"] is not None: - stats = kwargs["stats"] - stats[self.label] = _total_seconds(datetime.now() - start) - return result - - return wrapped_f - - -class _call_count: # noqa: N801 - def __init__(self, label): - self.label = label - - def __call__(self, f): - if self.label is None: - self.label = f.__name__ + "_runtime" - - def wrapped_f(*args, **kwargs): - if "stats" in kwargs and kwargs["stats"] is not None: - stats = kwargs["stats"] - if self.label not in stats: - stats[self.label] = 0 - stats[self.label] += 1 - return f(*args, **kwargs) - - return wrapped_f - - -class IsomorphicGraph(ConjunctiveGraph): - """An implementation of the RGDA1 graph digest algorithm. - - An implementation of RGDA1 (publication below), - a combination of Sayers & Karp's graph digest algorithm using - sum and SHA-256 - and traces , an average case - polynomial time algorithm for graph canonicalization. - - McCusker, J. P. (2015). WebSig: A Digital Signature Framework for the Web. - Rensselaer Polytechnic Institute, Troy, NY. - http://gradworks.umi.com/3727015.pdf - """ - - def __init__(self, **kwargs): - super(IsomorphicGraph, self).__init__(**kwargs) - - def __eq__(self, other): - """Graph isomorphism testing.""" - if not isinstance(other, IsomorphicGraph): - return False - elif len(self) != len(other): - return False - return self.internal_hash() == other.internal_hash() - - def __ne__(self, other): - """Negative graph isomorphism testing.""" - return not self.__eq__(other) - - def __hash__(self): - return super(IsomorphicGraph, self).__hash__() - - def graph_digest(self, stats=None): - """Synonym for IsomorphicGraph.internal_hash.""" - return self.internal_hash(stats=stats) - - def internal_hash(self, stats=None): - """ - This is defined instead of __hash__ to avoid a circular recursion - scenario with the Memory store for rdflib which requires a hash lookup - in order to return a generator of triples. - """ - return _TripleCanonicalizer(self).to_hash(stats=stats) - - -HashFunc = Callable[[str], int] -ColorItem = Tuple[Union[int, str], URIRef, Union[int, str]] -ColorItemTuple = Tuple[ColorItem, ...] -HashCache = Optional[Dict[ColorItemTuple, str]] -Stats = Dict[str, Union[int, str]] - - -class Color: - def __init__( - self, - nodes: List[IdentifiedNode], - hashfunc: HashFunc, - color: ColorItemTuple = (), - hash_cache: HashCache = None, - ): - if hash_cache is None: - hash_cache = {} - self._hash_cache = hash_cache - self.color = color - self.nodes = nodes - self.hashfunc = hashfunc - self._hash_color = None - - def __str__(self): - nodes, color = self.key() - return "Color %s (%s nodes)" % (color, nodes) - - def key(self): - return (len(self.nodes), self.hash_color()) - - def hash_color(self, color: Optional[Tuple[ColorItem, ...]] = None) -> str: - if color is None: - color = self.color - if color in self._hash_cache: - return self._hash_cache[color] - - def stringify(x): - if isinstance(x, Node): - return x.n3() - else: - return str(x) - - if isinstance(color, Node): - return stringify(color) - value = 0 - for triple in color: - value += self.hashfunc(" ".join([stringify(x) for x in triple])) - val: str = "%x" % value - self._hash_cache[color] = val - return val - - def distinguish(self, W: Color, graph: Graph): # noqa: N803 - colors: Dict[str, Color] = {} - for n in self.nodes: - new_color: Tuple[ColorItem, ...] = list(self.color) # type: ignore[assignment] - for node in W.nodes: - new_color += [ # type: ignore[operator] - (1, p, W.hash_color()) for s, p, o in graph.triples((n, None, node)) - ] - new_color += [ # type: ignore[operator] - (W.hash_color(), p, 3) for s, p, o in graph.triples((node, None, n)) - ] - new_color = tuple(new_color) - new_hash_color = self.hash_color(new_color) - - if new_hash_color not in colors: - c = Color([], self.hashfunc, new_color, hash_cache=self._hash_cache) - colors[new_hash_color] = c - colors[new_hash_color].nodes.append(n) - return colors.values() - - def discrete(self): - return len(self.nodes) == 1 - - def copy(self): - return Color( - self.nodes[:], self.hashfunc, self.color, hash_cache=self._hash_cache - ) - - -_HashT = Callable[[], "HASH"] - - -class _TripleCanonicalizer: - def __init__(self, graph: Graph, hashfunc: _HashT = sha256): - self.graph = graph - - def _hashfunc(s: str): - h = hashfunc() - h.update(str(s).encode("utf8")) - return int(h.hexdigest(), 16) - - self._hash_cache: HashCache = {} - self.hashfunc = _hashfunc - - def _discrete(self, coloring: List[Color]) -> bool: - return len([c for c in coloring if not c.discrete()]) == 0 - - def _initial_color(self) -> List[Color]: - """Finds an initial color for the graph. - - Finds an initial color of the graph by finding all blank nodes and - non-blank nodes that are adjacent. Nodes that are not adjacent to blank - nodes are not included, as they are a) already colored (by URI or literal) - and b) do not factor into the color of any blank node. - """ - bnodes: Set[BNode] = set() - others = set() - self._neighbors = defaultdict(set) - for s, p, o in self.graph: - nodes = set([s, p, o]) - b = set([x for x in nodes if isinstance(x, BNode)]) - if len(b) > 0: - others |= nodes - b - bnodes |= b - if isinstance(s, BNode): - self._neighbors[s].add(o) - if isinstance(o, BNode): - self._neighbors[o].add(s) - if isinstance(p, BNode): - self._neighbors[p].add(s) - self._neighbors[p].add(p) - if len(bnodes) > 0: - return [Color(list(bnodes), self.hashfunc, hash_cache=self._hash_cache)] + [ - # type error: List item 0 has incompatible type "Union[IdentifiedNode, Literal]"; expected "IdentifiedNode" - # type error: Argument 3 to "Color" has incompatible type "Union[IdentifiedNode, Literal]"; expected "Tuple[Tuple[Union[int, str], URIRef, Union[int, str]], ...]" - Color([x], self.hashfunc, x, hash_cache=self._hash_cache) # type: ignore[list-item, arg-type] - for x in others - ] - else: - return [] - - def _individuate(self, color, individual): - new_color = list(color.color) - new_color.append((len(color.nodes),)) - - color.nodes.remove(individual) - c = Color( - [individual], self.hashfunc, tuple(new_color), hash_cache=self._hash_cache - ) - return c - - def _get_candidates(self, coloring: List[Color]) -> Iterator[Tuple[Node, Color]]: - for c in [c for c in coloring if not c.discrete()]: - for node in c.nodes: - yield node, c - - def _refine(self, coloring: List[Color], sequence: List[Color]) -> List[Color]: - sequence = sorted(sequence, key=lambda x: x.key(), reverse=True) - coloring = coloring[:] - while len(sequence) > 0 and not self._discrete(coloring): - W = sequence.pop() # noqa: N806 - for c in coloring[:]: - if len(c.nodes) > 1 or isinstance(c.nodes[0], BNode): - colors = sorted( - c.distinguish(W, self.graph), - key=lambda x: x.key(), - reverse=True, - ) - coloring.remove(c) - coloring.extend(colors) - try: - si = sequence.index(c) - sequence = sequence[:si] + colors + sequence[si + 1 :] - except ValueError: - sequence = colors[1:] + sequence - combined_colors: List[Color] = [] - combined_color_map: Dict[str, Color] = dict() - for color in coloring: - color_hash = color.hash_color() - # This is a hash collision, and be combined into a single color for individuation. - if color_hash in combined_color_map: - combined_color_map[color_hash].nodes.extend(color.nodes) - else: - combined_colors.append(color) - combined_color_map[color_hash] = color - return combined_colors - - @_runtime("to_hash_runtime") - def to_hash(self, stats: Optional[Stats] = None): - result = 0 - for triple in self.canonical_triples(stats=stats): - result += self.hashfunc(" ".join([x.n3() for x in triple])) - if stats is not None: - stats["graph_digest"] = "%x" % result - return result - - def _experimental_path(self, coloring: List[Color]) -> List[Color]: - coloring = [c.copy() for c in coloring] - while not self._discrete(coloring): - color = [x for x in coloring if not x.discrete()][0] - node = color.nodes[0] - new_color = self._individuate(color, node) - coloring.append(new_color) - coloring = self._refine(coloring, [new_color]) - return coloring - - def _create_generator( - self, - colorings: List[List[Color]], - groupings: Optional[Dict[Node, Set[Node]]] = None, - ) -> Dict[Node, Set[Node]]: - if not groupings: - groupings = defaultdict(set) - for group in zip(*colorings): - g = set([c.nodes[0] for c in group]) - for n in group: - g |= groupings[n] - for n in g: - groupings[n] = g - return groupings - - @_call_count("individuations") - def _traces( - self, - coloring: List[Color], - stats: Optional[Stats] = None, - depth: List[int] = [0], - ) -> List[Color]: - if stats is not None and "prunings" not in stats: - stats["prunings"] = 0 - depth[0] += 1 - candidates = self._get_candidates(coloring) - best: List[List[Color]] = [] - best_score = None - best_experimental_score = None - last_coloring = None - generator: Dict[Node, Set[Node]] = defaultdict(set) - visited: Set[Node] = set() - for candidate, color in candidates: - if candidate in generator: - v = generator[candidate] & visited - if len(v) > 0: - visited.add(candidate) - continue - visited.add(candidate) - coloring_copy: List[Color] = [] - color_copy = None - for c in coloring: - c_copy = c.copy() - coloring_copy.append(c_copy) - if c == color: - color_copy = c_copy - new_color = self._individuate(color_copy, candidate) - coloring_copy.append(new_color) - refined_coloring = self._refine(coloring_copy, [new_color]) - color_score = tuple([c.key() for c in refined_coloring]) - experimental = self._experimental_path(coloring_copy) - experimental_score = set([c.key() for c in experimental]) - if last_coloring: - generator = self._create_generator( # type: ignore[unreachable] - [last_coloring, experimental], generator - ) - last_coloring = experimental - if best_score is None or best_score < color_score: # type: ignore[unreachable] - best = [refined_coloring] - best_score = color_score - best_experimental_score = experimental_score - elif best_score > color_score: # type: ignore[unreachable] - # prune this branch. - if stats is not None: - stats["prunings"] += 1 - elif experimental_score != best_experimental_score: - best.append(refined_coloring) - else: - # prune this branch. - if stats is not None: - stats["prunings"] += 1 - discrete: List[List[Color]] = [x for x in best if self._discrete(x)] - if len(discrete) == 0: - best_score = None - best_depth = None - for coloring in best: - d = [depth[0]] - new_color = self._traces(coloring, stats=stats, depth=d) - color_score = tuple([c.key() for c in refined_coloring]) - if best_score is None or color_score > best_score: # type: ignore[unreachable] - discrete = [new_color] - best_score = color_score - best_depth = d[0] - depth[0] = best_depth # type: ignore[assignment] - return discrete[0] - - def canonical_triples(self, stats: Optional[Stats] = None): - if stats is not None: - start_coloring = datetime.now() - coloring = self._initial_color() - if stats is not None: - stats["triple_count"] = len(self.graph) - stats["adjacent_nodes"] = max(0, len(coloring) - 1) - coloring = self._refine(coloring, coloring[:]) - if stats is not None: - stats["initial_coloring_runtime"] = _total_seconds( - datetime.now() - start_coloring - ) - stats["initial_color_count"] = len(coloring) - - if not self._discrete(coloring): - depth = [0] - coloring = self._traces(coloring, stats=stats, depth=depth) - if stats is not None: - stats["tree_depth"] = depth[0] - elif stats is not None: - stats["individuations"] = 0 - stats["tree_depth"] = 0 - if stats is not None: - stats["color_count"] = len(coloring) - - bnode_labels: Dict[Node, str] = dict( - [(c.nodes[0], c.hash_color()) for c in coloring] - ) - if stats is not None: - stats["canonicalize_triples_runtime"] = _total_seconds( - datetime.now() - start_coloring - ) - for triple in self.graph: - result = tuple(self._canonicalize_bnodes(triple, bnode_labels)) - yield result - - def _canonicalize_bnodes( - self, - triple: _TripleType, - labels: Dict[Node, str], - ): - for term in triple: - if isinstance(term, BNode): - yield BNode(value="cb%s" % labels[term]) - else: - yield term - - -def to_isomorphic(graph: Graph) -> IsomorphicGraph: - if isinstance(graph, IsomorphicGraph): - return graph - result = IsomorphicGraph() - if hasattr(graph, "identifier"): - result = IsomorphicGraph(identifier=graph.identifier) - result += graph - return result - - -def isomorphic(graph1: Graph, graph2: Graph) -> bool: - """Compare graph for equality. - - Uses an algorithm to compute unique hashes which takes bnodes into account. - - Examples:: - - >>> g1 = Graph().parse(format='n3', data=''' - ... @prefix : . - ... :rel . - ... :rel . - ... :rel [ :label "A bnode." ] . - ... ''') - >>> g2 = Graph().parse(format='n3', data=''' - ... @prefix ns: . - ... ns:rel [ ns:label "A bnode." ] . - ... ns:rel , - ... . - ... ''') - >>> isomorphic(g1, g2) - True - - >>> g3 = Graph().parse(format='n3', data=''' - ... @prefix : . - ... :rel . - ... :rel . - ... :rel . - ... ''') - >>> isomorphic(g1, g3) - False - """ - gd1 = _TripleCanonicalizer(graph1).to_hash() - gd2 = _TripleCanonicalizer(graph2).to_hash() - return gd1 == gd2 - - -def to_canonical_graph( - g1: Graph, stats: Optional[Stats] = None -) -> ReadOnlyGraphAggregate: - """Creates a canonical, read-only graph. - - Creates a canonical, read-only graph where all bnode id:s are based on - deterministical SHA-256 checksums, correlated with the graph contents. - """ - graph = Graph() - graph += _TripleCanonicalizer(g1).canonical_triples(stats=stats) - return ReadOnlyGraphAggregate([graph]) - - -def graph_diff(g1: Graph, g2: Graph) -> Tuple[Graph, Graph, Graph]: - """Returns three sets of triples: "in both", "in first" and "in second".""" - # bnodes have deterministic values in canonical graphs: - cg1 = to_canonical_graph(g1) - cg2 = to_canonical_graph(g2) - in_both = cg1 * cg2 - in_first = cg1 - cg2 - in_second = cg2 - cg1 - return (in_both, in_first, in_second) - - -_MOCK_BNODE = BNode() - - -def similar(g1: Graph, g2: Graph): - """Checks if the two graphs are "similar". - - Checks if the two graphs are "similar", by comparing sorted triples where - all bnodes have been replaced by a singular mock bnode (the - ``_MOCK_BNODE``). - - This is a much cheaper, but less reliable, alternative to the comparison - algorithm in ``isomorphic``. - """ - return all(t1 == t2 for (t1, t2) in _squashed_graphs_triples(g1, g2)) - - -def _squashed_graphs_triples(g1: Graph, g2: Graph): - for t1, t2 in zip(sorted(_squash_graph(g1)), sorted(_squash_graph(g2))): - yield t1, t2 - - -def _squash_graph(graph: Graph): - return (_squash_bnodes(triple) for triple in graph) - - -def _squash_bnodes(triple): - return tuple((isinstance(t, BNode) and _MOCK_BNODE) or t for t in triple) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/compat.py b/extensions/.local/lib/python3.11/site-packages/rdflib/compat.py deleted file mode 100644 index ddb55eb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/compat.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -Utility functions and objects to ease Python 2/3 compatibility, -and different versions of support libraries. -""" - -from __future__ import annotations - -import codecs -import re -import warnings -from typing import Match - - -def cast_bytes(s, enc="utf-8"): - if isinstance(s, str): - return s.encode(enc) - return s - - -def ascii(stream): - return codecs.getreader("ascii")(stream) - - -def bopen(*args, **kwargs): - # type error: No overload variant of "open" matches argument types "Tuple[Any, ...]", "str", "Dict[str, Any]" - return open(*args, mode="rb", **kwargs) # type: ignore[call-overload] - - -long_type = int - - -def sign(n): - if n < 0: - return -1 - if n > 0: - return 1 - return 0 - - -r_unicodeEscape = re.compile(r"(\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})") # noqa: N816 - - -def _unicodeExpand(s): # noqa: N802 - return r_unicodeEscape.sub(lambda m: chr(int(m.group(0)[2:], 16)), s) - - -def decodeStringEscape(s): # noqa: N802 - warnings.warn( - DeprecationWarning( - "rdflib.compat.decodeStringEscape() is deprecated, " - "it will be removed in rdflib 7.0.0. " - "This function is not used anywhere in rdflib anymore " - "and the utility that it does provide is not implemented correctly." - ) - ) - r""" - s is byte-string - replace \ escapes in string - """ - - s = s.replace("\\t", "\t") - s = s.replace("\\n", "\n") - s = s.replace("\\r", "\r") - s = s.replace("\\b", "\b") - s = s.replace("\\f", "\f") - s = s.replace('\\"', '"') - s = s.replace("\\'", "'") - s = s.replace("\\\\", "\\") - - return s - # return _unicodeExpand(s) # hmm - string escape doesn't do unicode escaping - - -_string_escape_map = { - "t": "\t", - "b": "\b", - "n": "\n", - "r": "\r", - "f": "\f", - '"': '"', - "'": "'", - "\\": "\\", -} - - -def _turtle_escape_subber(match: Match[str]) -> str: - smatch, umatch = match.groups() - if smatch is not None: - return _string_escape_map[smatch] - else: - return chr(int(umatch[1:], 16)) - - -_turtle_escape_pattern = re.compile( - r"""\\(?:([tbnrf"'\\])|(u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8}))""", -) - - -def decodeUnicodeEscape(escaped: str) -> str: # noqa: N802 - if "\\" not in escaped: - # Most of times, there are no backslashes in strings. - return escaped - return _turtle_escape_pattern.sub(_turtle_escape_subber, escaped) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/container.py b/extensions/.local/lib/python3.11/site-packages/rdflib/container.py deleted file mode 100644 index 6ee9284..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/container.py +++ /dev/null @@ -1,278 +0,0 @@ -import warnings -from random import randint - -from rdflib.namespace import RDF -from rdflib.term import BNode, URIRef - -__all__ = ["Container", "Bag", "Seq", "Alt", "NoElementException"] - - -class Container: - """A class for constructing RDF containers, as per https://www.w3.org/TR/rdf11-mt/#rdf-containers - - Basic usage, creating a ``Bag`` and adding to it:: - - >>> from rdflib import Graph, BNode, Literal, Bag - >>> g = Graph() - >>> b = Bag(g, BNode(), [Literal("One"), Literal("Two"), Literal("Three")]) - >>> print(g.serialize(format="turtle")) - @prefix rdf: . - - [] a rdf:Bag ; - rdf:_1 "One" ; - rdf:_2 "Two" ; - rdf:_3 "Three" . - - - - >>> # print out an item using an index reference - >>> print(b[2]) - Two - - >>> # add a new item - >>> b.append(Literal("Hello")) # doctest: +ELLIPSIS - - >>> print(g.serialize(format="turtle")) - @prefix rdf: . - - [] a rdf:Bag ; - rdf:_1 "One" ; - rdf:_2 "Two" ; - rdf:_3 "Three" ; - rdf:_4 "Hello" . - - - - """ - - def __init__(self, graph, uri, seq=[], rtype="Bag"): - """Creates a Container - - :param graph: a Graph instance - :param uri: URI or Blank Node of the Container - :param seq: the elements of the Container - :param rtype: the type of Container, one of "Bag", "Seq" or "Alt" - """ - - self.graph = graph - self.uri = uri or BNode() - self._len = 0 - self._rtype = rtype # rdf:Bag or rdf:Seq or rdf:Alt - - self.append_multiple(seq) - - # adding triple corresponding to container type - self.graph.add((self.uri, RDF.type, RDF[self._rtype])) - - def n3(self): - items = [] - for i in range(len(self)): - v = self[i + 1] - items.append(v) - - return "( %s )" % " ".join([a.n3() for a in items]) - - def _get_container(self): - """Returns the URI of the container""" - - return self.uri - - def __len__(self): - """Number of items in container""" - - return self._len - - def type_of_conatiner(self): - warnings.warn( - "rdflib.container.Container.type_of_conatiner is deprecated. " - "Use type_of_container method instead.", - DeprecationWarning, - stacklevel=2, - ) - return self._rtype - - def type_of_container(self): - return self._rtype - - def index(self, item): - """Returns the 1-based numerical index of the item in the container""" - - pred = self.graph.predicates(self.uri, item) - if not pred: - raise ValueError("%s is not in %s" % (item, "container")) - li_index = URIRef(str(RDF) + "_") - - i = None - for p in pred: - i = int(p.replace(li_index, "")) - return i - - def __getitem__(self, key): - """Returns item of the container at index key""" - - c = self._get_container() - - assert isinstance(key, int) - elem_uri = str(RDF) + "_" + str(key) - if key <= 0 or key > len(self): - raise KeyError(key) - v = self.graph.value(c, URIRef(elem_uri)) - if v: - return v - else: - raise KeyError(key) - - def __setitem__(self, key, value): - """Sets the item at index key or predicate rdf:_key of the container to value""" - - assert isinstance(key, int) - - c = self._get_container() - elem_uri = str(RDF) + "_" + str(key) - if key <= 0 or key > len(self): - raise KeyError(key) - - self.graph.set((c, URIRef(elem_uri), value)) - - def __delitem__(self, key): - """Removing the item with index key or predicate rdf:_key""" - - assert isinstance(key, int) - if key <= 0 or key > len(self): - raise KeyError(key) - - graph = self.graph - container = self.uri - elem_uri = str(RDF) + "_" + str(key) - graph.remove((container, URIRef(elem_uri), None)) - for j in range(key + 1, len(self) + 1): - elem_uri = str(RDF) + "_" + str(j) - v = graph.value(container, URIRef(elem_uri)) - graph.remove((container, URIRef(elem_uri), v)) - elem_uri = str(RDF) + "_" + str(j - 1) - graph.add((container, URIRef(elem_uri), v)) - - self._len -= 1 - - def items(self): - """Returns a list of all items in the container""" - - l_ = [] - container = self.uri - i = 1 - while True: - elem_uri = str(RDF) + "_" + str(i) - - if (container, URIRef(elem_uri), None) in self.graph: - i += 1 - l_.append(self.graph.value(container, URIRef(elem_uri))) - else: - break - return l_ - - def end(self): # - # find end index (1-based) of container - - container = self.uri - i = 1 - while True: - elem_uri = str(RDF) + "_" + str(i) - - if (container, URIRef(elem_uri), None) in self.graph: - i += 1 - else: - return i - 1 - - def append(self, item): - """Adding item to the end of the container""" - - end = self.end() - elem_uri = str(RDF) + "_" + str(end + 1) - container = self.uri - self.graph.add((container, URIRef(elem_uri), item)) - self._len += 1 - - return self - - def append_multiple(self, other): - """Adding multiple elements to the container to the end which are in python list other""" - - end = self.end() # it should return the last index - - container = self.uri - for item in other: - end += 1 - self._len += 1 - elem_uri = str(RDF) + "_" + str(end) - self.graph.add((container, URIRef(elem_uri), item)) - - return self - - def clear(self): - """Removing all elements from the container""" - - container = self.uri - graph = self.graph - i = 1 - while True: - elem_uri = str(RDF) + "_" + str(i) - if (container, URIRef(elem_uri), None) in self.graph: - graph.remove((container, URIRef(elem_uri), None)) - i += 1 - else: - break - self._len = 0 - return self - - -class Bag(Container): - """Unordered container (no preference order of elements)""" - - def __init__(self, graph, uri, seq=[]): - Container.__init__(self, graph, uri, seq, "Bag") - - -class Alt(Container): - def __init__(self, graph, uri, seq=[]): - Container.__init__(self, graph, uri, seq, "Alt") - - def anyone(self): - if len(self) == 0: - raise NoElementException() - else: - p = randint(1, len(self)) - item = self.__getitem__(p) - return item - - -class Seq(Container): - def __init__(self, graph, uri, seq=[]): - Container.__init__(self, graph, uri, seq, "Seq") - - def add_at_position(self, pos, item): - assert isinstance(pos, int) - if pos <= 0 or pos > len(self) + 1: - raise ValueError("Invalid Position for inserting element in rdf:Seq") - - if pos == len(self) + 1: - self.append(item) - else: - for j in range(len(self), pos - 1, -1): - container = self._get_container() - elem_uri = str(RDF) + "_" + str(j) - v = self.graph.value(container, URIRef(elem_uri)) - self.graph.remove((container, URIRef(elem_uri), v)) - elem_uri = str(RDF) + "_" + str(j + 1) - self.graph.add((container, URIRef(elem_uri), v)) - elem_uri_pos = str(RDF) + "_" + str(pos) - self.graph.add((container, URIRef(elem_uri_pos), item)) - self._len += 1 - return self - - -class NoElementException(Exception): # noqa: N818 - def __init__(self, message="rdf:Alt Container is empty"): - self.message = message - - def __str__(self): - return self.message diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/events.py b/extensions/.local/lib/python3.11/site-packages/rdflib/events.py deleted file mode 100644 index 61f3454..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/events.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Dirt Simple Events - -A Dispatcher (or a subclass of Dispatcher) stores event handlers that -are 'fired' simple event objects when interesting things happen. - -Create a dispatcher: - - >>> d = Dispatcher() - -Now create a handler for the event and subscribe it to the dispatcher -to handle Event events. A handler is a simple function or method that -accepts the event as an argument: - - >>> def handler1(event): print(repr(event)) - >>> d.subscribe(Event, handler1) # doctest: +ELLIPSIS - - -Now dispatch a new event into the dispatcher, and see handler1 get -fired: - - >>> d.dispatch(Event(foo='bar', data='yours', used_by='the event handlers')) - -""" - -from __future__ import annotations - -from typing import Any, Dict, Optional - -__all__ = ["Event", "Dispatcher"] - - -class Event: - """ - An event is a container for attributes. The source of an event - creates this object, or a subclass, gives it any kind of data that - the events handlers need to handle the event, and then calls - notify(event). - - The target of an event registers a function to handle the event it - is interested with subscribe(). When a sources calls - notify(event), each subscriber to that event will be called in no - particular order. - """ - - def __init__(self, **kw): - self.__dict__.update(kw) - - def __repr__(self): - attrs = sorted(self.__dict__.keys()) - return "" % ([a for a in attrs],) - - -class Dispatcher: - """ - An object that can dispatch events to a privately managed group of - subscribers. - """ - - _dispatch_map: Optional[Dict[Any, Any]] = None - - def set_map(self, amap: Dict[Any, Any]): - self._dispatch_map = amap - return self - - def get_map(self): - return self._dispatch_map - - def subscribe(self, event_type, handler): - """Subscribe the given handler to an event_type. Handlers - are called in the order they are subscribed. - """ - if self._dispatch_map is None: - self.set_map({}) - # type error: error: Item "None" of "Optional[Dict[Any, Any]]" has no attribute "get" - lst = self._dispatch_map.get(event_type, None) # type: ignore[union-attr] - if lst is None: - lst = [handler] - else: - lst.append(handler) - # type error: Unsupported target for indexed assignment ("Optional[Dict[Any, Any]]") - self._dispatch_map[event_type] = lst # type: ignore[index] - return self - - def dispatch(self, event): - """Dispatch the given event to the subscribed handlers for - the event's type""" - if self._dispatch_map is not None: - lst = self._dispatch_map.get(type(event), None) - if lst is None: - raise ValueError("unknown event type: %s" % type(event)) - for l_ in lst: - l_(event) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/exceptions.py b/extensions/.local/lib/python3.11/site-packages/rdflib/exceptions.py deleted file mode 100644 index cbe68fb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/exceptions.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -TODO: -""" - -from __future__ import annotations - -__all__ = [ - "Error", - "ParserError", - "UniquenessError", -] - - -from typing import Any, Optional - - -class Error(Exception): - """Base class for rdflib exceptions.""" - - def __init__(self, msg: Optional[str] = None): - Exception.__init__(self, msg) - self.msg = msg - - -class ParserError(Error): - """RDF Parser error.""" - - def __init__(self, msg: str): - Error.__init__(self, msg) - self.msg: str = msg - - def __str__(self) -> str: - return self.msg - - -class UniquenessError(Error): - """A uniqueness assumption was made in the context, and that is not true""" - - def __init__(self, values: Any): - Error.__init__( - self, - "\ -Uniqueness assumption is not fulfilled. Multiple values are: %s" - % values, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/cmdlineutils.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/cmdlineutils.py deleted file mode 100644 index 85fd85f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/cmdlineutils.py +++ /dev/null @@ -1,77 +0,0 @@ -from __future__ import annotations - -import codecs -import getopt -import sys -import time -from typing import TextIO, Union - -import rdflib -from rdflib.util import guess_format - - -def _help(): - sys.stderr.write( - """ -program.py [-f ] [-o ] [files...] -Read RDF files given on STDOUT - does something to the resulting graph -If no files are given, read from stdin --o specifies file for output, if not given stdout is used --f specifies parser to use, if not given it is guessed from extension - -""" - ) - - -def main(target, _help=_help, options="", stdin=True): - """ - A main function for tools that read RDF from files given on commandline - or from STDIN (if stdin parameter is true) - """ - - args, files = getopt.getopt(sys.argv[1:], "hf:o:" + options) - dargs = dict(args) - - if "-h" in dargs: - _help() - sys.exit(-1) - - g = rdflib.Graph() - - if "-f" in dargs: - f = dargs["-f"] - else: - f = None - - out: Union[TextIO, codecs.StreamReaderWriter] - if "-o" in dargs: - sys.stderr.write("Output to %s\n" % dargs["-o"]) - out = codecs.open(dargs["-o"], "w", "utf-8") - else: - out = sys.stdout - - start = time.time() - if len(files) == 0 and stdin: - sys.stderr.write("Reading from stdin as %s..." % f) - g.parse(sys.stdin, format=f) - sys.stderr.write("[done]\n") - else: - size = 0 - for x in files: - if f is None: - f = guess_format(x) - start1 = time.time() - sys.stderr.write("Loading %s as %s... " % (x, f)) - g.parse(x, format=f) - sys.stderr.write( - "done.\t(%d triples\t%.2f seconds)\n" - % (len(g) - size, time.time() - start1) - ) - size = len(g) - - sys.stderr.write( - "Loaded a total of %d triples in %.2f seconds.\n" - % (len(g), time.time() - start) - ) - - target(g, out, args) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/describer.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/describer.py deleted file mode 100644 index f0df706..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/describer.py +++ /dev/null @@ -1,257 +0,0 @@ -""" -A Describer is a stateful utility for creating RDF statements in a -semi-declarative manner. It has methods for creating literal values, rel and -rev resource relations (somewhat resembling RDFa). - -The `Describer.rel` and `Describer.rev` methods return a context manager which sets the current -about to the referenced resource for the context scope (for use with the -``with`` statement). - -Full example in the ``to_rdf`` method below:: - - >>> import datetime - >>> from rdflib.graph import Graph - >>> from rdflib.namespace import Namespace, RDFS, FOAF - >>> - >>> ORG_URI = "http://example.org/" - >>> - >>> CV = Namespace("http://purl.org/captsolo/resume-rdf/0.2/cv#") - >>> - >>> class Person: - ... def __init__(self): - ... self.first_name = "Some" - ... self.last_name = "Body" - ... self.username = "some1" - ... self.presentation = "Just a Python & RDF hacker." - ... self.image = "/images/persons/" + self.username + ".jpg" - ... self.site = "http://example.net/" - ... self.start_date = datetime.date(2009, 9, 4) - ... def get_full_name(self): - ... return " ".join([self.first_name, self.last_name]) - ... def get_absolute_url(self): - ... return "/persons/" + self.username - ... def get_thumbnail_url(self): - ... return self.image.replace('.jpg', '-thumb.jpg') - ... - ... def to_rdf(self): - ... graph = Graph() - ... graph.bind('foaf', FOAF) - ... graph.bind('cv', CV) - ... lang = 'en' - ... d = Describer(graph, base=ORG_URI) - ... d.about(self.get_absolute_url()+'#person') - ... d.rdftype(FOAF.Person) - ... d.value(FOAF.name, self.get_full_name()) - ... d.value(FOAF.givenName, self.first_name) - ... d.value(FOAF.familyName, self.last_name) - ... d.rel(FOAF.homepage, self.site) - ... d.value(RDFS.comment, self.presentation, lang=lang) - ... with d.rel(FOAF.depiction, self.image): - ... d.rdftype(FOAF.Image) - ... d.rel(FOAF.thumbnail, self.get_thumbnail_url()) - ... with d.rev(CV.aboutPerson): - ... d.rdftype(CV.CV) - ... with d.rel(CV.hasWorkHistory): - ... d.value(CV.startDate, self.start_date) - ... d.rel(CV.employedIn, ORG_URI+"#company") - ... return graph - ... - >>> person_graph = Person().to_rdf() - >>> expected = Graph().parse(data=''' - ... - ... - ... Some Body - ... Some - ... Body - ... - ... - ... - ... - ... - ... - ... Just a Python & RDF hacker. - ... - ... - ... - ... - ... - ... - ... - ... - ... 2009-09-04 - ... - ... - ... - ... - ... - ... ''', format="xml") - >>> - >>> from rdflib.compare import isomorphic - >>> isomorphic(person_graph, expected) #doctest: +SKIP - True -""" - -from contextlib import contextmanager - -from rdflib.graph import Graph -from rdflib.namespace import RDF -from rdflib.term import BNode, Identifier, Literal, URIRef - - -class Describer: - def __init__(self, graph=None, about=None, base=None): - if graph is None: - graph = Graph() - self.graph = graph - self.base = base - self._subjects = [] - self.about(about or None) - - def about(self, subject, **kws): - """ - Sets the current subject. Will convert the given object into an - ``URIRef`` if it's not an ``Identifier``. - - Usage:: - - >>> d = Describer() - >>> d._current() #doctest: +ELLIPSIS - rdflib.term.BNode(...) - >>> d.about("http://example.org/") - >>> d._current() - rdflib.term.URIRef('http://example.org/') - - """ - kws.setdefault("base", self.base) - subject = cast_identifier(subject, **kws) - if self._subjects: - self._subjects[-1] = subject - else: - self._subjects.append(subject) - - def value(self, p, v, **kws): - """ - Set a literal value for the given property. Will cast the value to an - ``Literal`` if a plain literal is given. - - Usage:: - - >>> from rdflib import URIRef - >>> from rdflib.namespace import RDF, RDFS - >>> d = Describer(about="http://example.org/") - >>> d.value(RDFS.label, "Example") - >>> d.graph.value(URIRef('http://example.org/'), RDFS.label) - rdflib.term.Literal('Example') - - """ - v = cast_value(v, **kws) - self.graph.add((self._current(), p, v)) - - def rel(self, p, o=None, **kws): - """Set an object for the given property. Will convert the given object - into an ``URIRef`` if it's not an ``Identifier``. If none is given, a - new ``BNode`` is used. - - Returns a context manager for use in a ``with`` block, within which the - given object is used as current subject. - - Usage:: - - >>> from rdflib import URIRef - >>> from rdflib.namespace import RDF, RDFS - >>> d = Describer(about="/", base="http://example.org/") - >>> _ctxt = d.rel(RDFS.seeAlso, "/about") - >>> d.graph.value(URIRef('http://example.org/'), RDFS.seeAlso) - rdflib.term.URIRef('http://example.org/about') - - >>> with d.rel(RDFS.seeAlso, "/more"): - ... d.value(RDFS.label, "More") - >>> (URIRef('http://example.org/'), RDFS.seeAlso, - ... URIRef('http://example.org/more')) in d.graph - True - >>> d.graph.value(URIRef('http://example.org/more'), RDFS.label) - rdflib.term.Literal('More') - - """ - - kws.setdefault("base", self.base) - p = cast_identifier(p) - o = cast_identifier(o, **kws) - self.graph.add((self._current(), p, o)) - return self._subject_stack(o) - - def rev(self, p, s=None, **kws): - """ - Same as ``rel``, but uses current subject as *object* of the relation. - The given resource is still used as subject in the returned context - manager. - - Usage:: - - >>> from rdflib import URIRef - >>> from rdflib.namespace import RDF, RDFS - >>> d = Describer(about="http://example.org/") - >>> with d.rev(RDFS.seeAlso, "http://example.net/"): - ... d.value(RDFS.label, "Net") - >>> (URIRef('http://example.net/'), RDFS.seeAlso, - ... URIRef('http://example.org/')) in d.graph - True - >>> d.graph.value(URIRef('http://example.net/'), RDFS.label) - rdflib.term.Literal('Net') - - """ - kws.setdefault("base", self.base) - p = cast_identifier(p) - s = cast_identifier(s, **kws) - self.graph.add((s, p, self._current())) - return self._subject_stack(s) - - def rdftype(self, t): - """ - Shorthand for setting rdf:type of the current subject. - - Usage:: - - >>> from rdflib import URIRef - >>> from rdflib.namespace import RDF, RDFS - >>> d = Describer(about="http://example.org/") - >>> d.rdftype(RDFS.Resource) - >>> (URIRef('http://example.org/'), - ... RDF.type, RDFS.Resource) in d.graph - True - - """ - self.graph.add((self._current(), RDF.type, t)) - - def _current(self): - return self._subjects[-1] - - @contextmanager - def _subject_stack(self, subject): - self._subjects.append(subject) - yield None - self._subjects.pop() - - -def cast_value(v, **kws): - if not isinstance(v, Literal): - v = Literal(v, **kws) - return v - - -def cast_identifier(ref, **kws): - ref = ref or BNode() - if not isinstance(ref, Identifier): - ref = URIRef(ref, **kws) - return ref diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/external_graph_libs.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/external_graph_libs.py deleted file mode 100644 index 4246977..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/external_graph_libs.py +++ /dev/null @@ -1,355 +0,0 @@ -"""Convert (to and) from rdflib graphs to other well known graph libraries. - -Currently the following libraries are supported: -- networkx: MultiDiGraph, DiGraph, Graph -- graph_tool: Graph - -Doctests in this file are all skipped, as we can't run them conditionally if -networkx or graph_tool are available and they would err otherwise. -see ../../test/test_extras_external_graph_libs.py for conditional tests -""" - -from __future__ import annotations - -import logging -from typing import TYPE_CHECKING, Any, Dict, List - -if TYPE_CHECKING: - from rdflib.graph import Graph - - -logger = logging.getLogger(__name__) - - -def _identity(x): - return x - - -def _rdflib_to_networkx_graph( - graph: Graph, - nxgraph, - calc_weights: bool, - edge_attrs, - transform_s=_identity, - transform_o=_identity, -): - """Helper method for multidigraph, digraph and graph. - - Modifies nxgraph in-place! - - Arguments: - graph: an rdflib.Graph. - nxgraph: a networkx.Graph/DiGraph/MultiDigraph. - calc_weights: If True adds a 'weight' attribute to each edge according - to the count of s,p,o triples between s and o, which is meaningful - for Graph/DiGraph. - edge_attrs: Callable to construct edge data from s, p, o. - 'triples' attribute is handled specially to be merged. - 'weight' should not be generated if calc_weights==True. - (see invokers below!) - transform_s: Callable to transform node generated from s. - transform_o: Callable to transform node generated from o. - """ - assert callable(edge_attrs) - assert callable(transform_s) - assert callable(transform_o) - import networkx as nx - - for s, p, o in graph: - ts, to = transform_s(s), transform_o(o) # apply possible transformations - data = nxgraph.get_edge_data(ts, to) - if data is None or isinstance(nxgraph, nx.MultiDiGraph): - # no edge yet, set defaults - data = edge_attrs(s, p, o) - if calc_weights: - data["weight"] = 1 - nxgraph.add_edge(ts, to, **data) - else: - # already have an edge, just update attributes - if calc_weights: - data["weight"] += 1 - if "triples" in data: - d = edge_attrs(s, p, o) - data["triples"].extend(d["triples"]) - - -def rdflib_to_networkx_multidigraph( - graph: Graph, edge_attrs=lambda s, p, o: {"key": p}, **kwds -): - r"""Converts the given graph into a networkx.MultiDiGraph. - - The subjects and objects are the later nodes of the MultiDiGraph. - The predicates are used as edge keys (to identify multi-edges). - - :Parameters: - - - graph: a rdflib.Graph. - - edge_attrs: Callable to construct later edge_attributes. It receives - 3 variables (s, p, o) and should construct a dictionary that is - passed to networkx's add_edge(s, o, \*\*attrs) function. - - By default this will include setting the MultiDiGraph key=p here. - If you don't want to be able to re-identify the edge later on, you - can set this to ``lambda s, p, o: {}``. In this case MultiDiGraph's - default (increasing ints) will be used. - - Returns: - networkx.MultiDiGraph - - >>> from rdflib import Graph, URIRef, Literal - >>> g = Graph() - >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l') - >>> p, q = URIRef('p'), URIRef('q') - >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)] - >>> for t in edges: - ... g.add(t) - ... - >>> mdg = rdflib_to_networkx_multidigraph(g) - >>> len(mdg.edges()) - 4 - >>> mdg.has_edge(a, b) - True - >>> mdg.has_edge(a, b, key=p) - True - >>> mdg.has_edge(a, b, key=q) - True - - >>> mdg = rdflib_to_networkx_multidigraph(g, edge_attrs=lambda s,p,o: {}) - >>> mdg.has_edge(a, b, key=0) - True - >>> mdg.has_edge(a, b, key=1) - True - """ - import networkx as nx - - mdg = nx.MultiDiGraph() - _rdflib_to_networkx_graph(graph, mdg, False, edge_attrs, **kwds) - return mdg - - -def rdflib_to_networkx_digraph( - graph: Graph, - calc_weights: bool = True, - edge_attrs=lambda s, p, o: {"triples": [(s, p, o)]}, - **kwds, -): - r"""Converts the given graph into a networkx.DiGraph. - - As an rdflib.Graph() can contain multiple edges between nodes, by default - adds the a 'triples' attribute to the single DiGraph edge with a list of - all triples between s and o. - Also by default calculates the edge weight as the length of triples. - - :Parameters: - - - ``graph``: a rdflib.Graph. - - ``calc_weights``: If true calculate multi-graph edge-count as edge 'weight' - - ``edge_attrs``: Callable to construct later edge_attributes. It receives - 3 variables (s, p, o) and should construct a dictionary that is passed to - networkx's add_edge(s, o, \*\*attrs) function. - - By default this will include setting the 'triples' attribute here, - which is treated specially by us to be merged. Other attributes of - multi-edges will only contain the attributes of the first edge. - If you don't want the 'triples' attribute for tracking, set this to - ``lambda s, p, o: {}``. - - Returns: networkx.DiGraph - - >>> from rdflib import Graph, URIRef, Literal - >>> g = Graph() - >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l') - >>> p, q = URIRef('p'), URIRef('q') - >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)] - >>> for t in edges: - ... g.add(t) - ... - >>> dg = rdflib_to_networkx_digraph(g) - >>> dg[a][b]['weight'] - 2 - >>> sorted(dg[a][b]['triples']) == [(a, p, b), (a, q, b)] - True - >>> len(dg.edges()) - 3 - >>> dg.size() - 3 - >>> dg.size(weight='weight') - 4.0 - - >>> dg = rdflib_to_networkx_graph(g, False, edge_attrs=lambda s,p,o:{}) - >>> 'weight' in dg[a][b] - False - >>> 'triples' in dg[a][b] - False - - """ - import networkx as nx - - dg = nx.DiGraph() - _rdflib_to_networkx_graph(graph, dg, calc_weights, edge_attrs, **kwds) - return dg - - -def rdflib_to_networkx_graph( - graph: Graph, - calc_weights: bool = True, - edge_attrs=lambda s, p, o: {"triples": [(s, p, o)]}, - **kwds, -): - r"""Converts the given graph into a networkx.Graph. - - As an rdflib.Graph() can contain multiple directed edges between nodes, by - default adds the a 'triples' attribute to the single DiGraph edge with a - list of triples between s and o in graph. - Also by default calculates the edge weight as the len(triples). - - :Parameters: - - - graph: a rdflib.Graph. - - calc_weights: If true calculate multi-graph edge-count as edge 'weight' - - edge_attrs: Callable to construct later edge_attributes. It receives - 3 variables (s, p, o) and should construct a dictionary that is - passed to networkx's add_edge(s, o, \*\*attrs) function. - - By default this will include setting the 'triples' attribute here, - which is treated specially by us to be merged. Other attributes of - multi-edges will only contain the attributes of the first edge. - If you don't want the 'triples' attribute for tracking, set this to - ``lambda s, p, o: {}``. - - Returns: - networkx.Graph - - >>> from rdflib import Graph, URIRef, Literal - >>> g = Graph() - >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l') - >>> p, q = URIRef('p'), URIRef('q') - >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)] - >>> for t in edges: - ... g.add(t) - ... - >>> ug = rdflib_to_networkx_graph(g) - >>> ug[a][b]['weight'] - 3 - >>> sorted(ug[a][b]['triples']) == [(a, p, b), (a, q, b), (b, p, a)] - True - >>> len(ug.edges()) - 2 - >>> ug.size() - 2 - >>> ug.size(weight='weight') - 4.0 - - >>> ug = rdflib_to_networkx_graph(g, False, edge_attrs=lambda s,p,o:{}) - >>> 'weight' in ug[a][b] - False - >>> 'triples' in ug[a][b] - False - """ - import networkx as nx - - g = nx.Graph() - _rdflib_to_networkx_graph(graph, g, calc_weights, edge_attrs, **kwds) - return g - - -def rdflib_to_graphtool( - graph: Graph, - v_prop_names: List[str] = ["term"], - e_prop_names: List[str] = ["term"], - transform_s=lambda s, p, o: {"term": s}, - transform_p=lambda s, p, o: {"term": p}, - transform_o=lambda s, p, o: {"term": o}, -): - """Converts the given graph into a graph_tool.Graph(). - - The subjects and objects are the later vertices of the Graph. - The predicates become edges. - - :Parameters: - - graph: a rdflib.Graph. - - v_prop_names: a list of names for the vertex properties. The default is set - to ['term'] (see transform_s, transform_o below). - - e_prop_names: a list of names for the edge properties. - - transform_s: callable with s, p, o input. Should return a dictionary - containing a value for each name in v_prop_names. By default is set - to {'term': s} which in combination with v_prop_names = ['term'] - adds s as 'term' property to the generated vertex for s. - - transform_p: similar to transform_s, but wrt. e_prop_names. By default - returns {'term': p} which adds p as a property to the generated - edge between the vertex for s and the vertex for o. - - transform_o: similar to transform_s. - - Returns: graph_tool.Graph() - - >>> from rdflib import Graph, URIRef, Literal - >>> g = Graph() - >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l') - >>> p, q = URIRef('p'), URIRef('q') - >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)] - >>> for t in edges: - ... g.add(t) - ... - >>> mdg = rdflib_to_graphtool(g) - >>> len(list(mdg.edges())) - 4 - >>> from graph_tool import util as gt_util - >>> vpterm = mdg.vertex_properties['term'] - >>> va = gt_util.find_vertex(mdg, vpterm, a)[0] - >>> vb = gt_util.find_vertex(mdg, vpterm, b)[0] - >>> vl = gt_util.find_vertex(mdg, vpterm, l)[0] - >>> (va, vb) in [(e.source(), e.target()) for e in list(mdg.edges())] - True - >>> epterm = mdg.edge_properties['term'] - >>> len(list(gt_util.find_edge(mdg, epterm, p))) == 3 - True - >>> len(list(gt_util.find_edge(mdg, epterm, q))) == 1 - True - - >>> mdg = rdflib_to_graphtool( - ... g, - ... e_prop_names=[str('name')], - ... transform_p=lambda s, p, o: {str('name'): unicode(p)}) - >>> epterm = mdg.edge_properties['name'] - >>> len(list(gt_util.find_edge(mdg, epterm, unicode(p)))) == 3 - True - >>> len(list(gt_util.find_edge(mdg, epterm, unicode(q)))) == 1 - True - - """ - # pytype error: Can't find module 'graph_tool'. - import graph_tool as gt # pytype: disable=import-error - - g = gt.Graph() - - vprops = [(vpn, g.new_vertex_property("object")) for vpn in v_prop_names] - for vpn, vprop in vprops: - g.vertex_properties[vpn] = vprop - eprops = [(epn, g.new_edge_property("object")) for epn in e_prop_names] - for epn, eprop in eprops: - g.edge_properties[epn] = eprop - node_to_vertex: Dict[Any, Any] = {} - for s, p, o in graph: - sv = node_to_vertex.get(s) - if sv is None: - v = g.add_vertex() - node_to_vertex[s] = v - tmp_props = transform_s(s, p, o) - for vpn, vprop in vprops: - vprop[v] = tmp_props[vpn] - sv = v - - ov = node_to_vertex.get(o) - if ov is None: - v = g.add_vertex() - node_to_vertex[o] = v - tmp_props = transform_o(s, p, o) - for vpn, vprop in vprops: - vprop[v] = tmp_props[vpn] - ov = v - - e = g.add_edge(sv, ov) - tmp_props = transform_p(s, p, o) - for epn, eprop in eprops: - eprop[e] = tmp_props[epn] - return g diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/infixowl.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/infixowl.py deleted file mode 100644 index b80fb0c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/infixowl.py +++ /dev/null @@ -1,2353 +0,0 @@ -"""RDFLib Python binding for OWL Abstract Syntax - -OWL Constructor DL Syntax Manchester OWL Syntax Example -==================================================================================== -intersectionOf C ∩ D C AND D Human AND Male -unionOf C ∪ D C OR D Man OR Woman -complementOf ¬ C NOT C NOT Male -oneOf {a} ∪ {b}... {a b ...} {England Italy Spain} -someValuesFrom ∃ R C R SOME C hasColleague SOME Professor -allValuesFrom ∀ R C R ONLY C hasColleague ONLY Professor -minCardinality ≥ N R R MIN 3 hasColleague MIN 3 -maxCardinality ≤ N R R MAX 3 hasColleague MAX 3 -cardinality = N R R EXACTLY 3 hasColleague EXACTLY 3 -hasValue ∃ R {a} R VALUE a hasColleague VALUE Matthew - -see: http://www.w3.org/TR/owl-semantics/syntax.html - http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf - -3.2.3 Axioms for complete classes without using owl:equivalentClass - -Named class description of type 2 (with owl:oneOf) or type 4-6 -(with owl:intersectionOf, owl:unionOf or owl:complementOf - -Uses Manchester Syntax for __repr__ - ->>> exNs = Namespace("http://example.com/") ->>> g = Graph() ->>> g.bind("ex", exNs, override=False) - -Now we have an empty graph, we can construct OWL classes in it -using the Python classes defined in this module - ->>> a = Class(exNs.Opera, graph=g) - -Now we can assert rdfs:subClassOf and owl:equivalentClass relationships -(in the underlying graph) with other classes using the 'subClassOf' -and 'equivalentClass' descriptors which can be set to a list -of objects for the corresponding predicates. - ->>> a.subClassOf = [exNs.MusicalWork] - -We can then access the rdfs:subClassOf relationships - ->>> print(list(a.subClassOf)) -[Class: ex:MusicalWork ] - -This can also be used against already populated graphs: - ->>> owlGraph = Graph().parse(str(OWL)) ->>> list(Class(OWL.Class, graph=owlGraph).subClassOf) -[Class: rdfs:Class ] - -Operators are also available. For instance we can add ex:Opera to the extension -of the ex:CreativeWork class via the '+=' operator - ->>> a -Class: ex:Opera SubClassOf: ex:MusicalWork ->>> b = Class(exNs.CreativeWork, graph=g) ->>> b += a ->>> print(sorted(a.subClassOf, key=lambda c:c.identifier)) -[Class: ex:CreativeWork , Class: ex:MusicalWork ] - -And we can then remove it from the extension as well - ->>> b -= a ->>> a -Class: ex:Opera SubClassOf: ex:MusicalWork - -Boolean class constructions can also be created with Python operators. -For example, The | operator can be used to construct a class consisting of a -owl:unionOf the operands: - ->>> c = a | b | Class(exNs.Work, graph=g) ->>> c -( ex:Opera OR ex:CreativeWork OR ex:Work ) - -Boolean class expressions can also be operated as lists (using python list -operators) - ->>> del c[c.index(Class(exNs.Work, graph=g))] ->>> c -( ex:Opera OR ex:CreativeWork ) - -The '&' operator can be used to construct class intersection: - ->>> woman = Class(exNs.Female, graph=g) & Class(exNs.Human, graph=g) ->>> woman.identifier = exNs.Woman ->>> woman -( ex:Female AND ex:Human ) ->>> len(woman) -2 - -Enumerated classes can also be manipulated - ->>> contList = [Class(exNs.Africa, graph=g), Class(exNs.NorthAmerica, graph=g)] ->>> EnumeratedClass(members=contList, graph=g) -{ ex:Africa ex:NorthAmerica } - -owl:Restrictions can also be instantiated: - ->>> Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human) -( ex:hasParent ONLY ex:Human ) - -Restrictions can also be created using Manchester OWL syntax in 'colloquial' -Python ->>> exNs.hasParent @ some @ Class(exNs.Physician, graph=g) -( ex:hasParent SOME ex:Physician ) - ->>> Property(exNs.hasParent, graph=g) @ max @ Literal(1) -( ex:hasParent MAX 1 ) - ->>> print(g.serialize(format='pretty-xml')) # doctest: +SKIP - -""" - -from __future__ import annotations - -import itertools -import logging -from typing import Iterable, Union - -from rdflib.collection import Collection -from rdflib.graph import Graph, _ObjectType -from rdflib.namespace import OWL, RDF, RDFS, XSD, Namespace, NamespaceManager -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable -from rdflib.util import first - -logger = logging.getLogger(__name__) - - -""" -From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 - -Python has the wonderful "in" operator and it would be nice to have additional -infix operator like this. This recipe shows how (almost) arbitrary infix -operators can be defined. - -""" - -__all__ = [ - "ACE_NS", - "AllClasses", - "AllDifferent", - "AllProperties", - "AnnotatableTerms", - "BooleanClass", - "CLASS_RELATIONS", - "Callable", - "CastClass", - "Class", - "ClassNamespaceFactory", - "CommonNSBindings", - "ComponentTerms", - "DeepClassClear", - "EnumeratedClass", - "GetIdentifiedClasses", - "Individual", - "Infix", - "MalformedClass", - "MalformedClassError", - "OWLRDFListProxy", - "Ontology", - "Property", - "PropertyAbstractSyntax", - "Restriction", - "classOrIdentifier", - "classOrTerm", - "exactly", - "generateQName", - "manchesterSyntax", - "max", - "min", - "nsBinds", - "only", - "propertyOrIdentifier", - "some", - "value", -] - -# definition of an Infix operator class -# this recipe also works in jython -# calling sequence for the infix is: -# x @ op @ y - - -class Infix: - def __init__(self, function): - self.function = function - - def __rlshift__(self, other): - return Infix(lambda x, self=self, other=other: self.function(other, x)) - - def __rshift__(self, other): - return self.function(other) - - def __rmatmul__(self, other): - return Infix(lambda x, self=self, other=other: self.function(other, x)) - - def __matmul__(self, other): - return self.function(other) - - def __call__(self, value1, value2): - return self.function(value1, value2) # pragma: no cover - - -nsBinds = { # noqa: N816 - "skos": "http://www.w3.org/2004/02/skos/core#", - "rdf": RDF, - "rdfs": RDFS, - "owl": OWL, - "list": URIRef("http://www.w3.org/2000/10/swap/list#"), - "dc": "http://purl.org/dc/elements/1.1/", -} - - -def generateQName(graph, uri): # noqa: N802 - prefix, uri, localname = graph.compute_qname(classOrIdentifier(uri)) - return ":".join([prefix, localname]) - - -def classOrTerm(thing): # noqa: N802 - if isinstance(thing, Class): - return thing.identifier - else: - assert isinstance(thing, (URIRef, BNode, Literal)) - return thing - - -def classOrIdentifier(thing): # noqa: N802 - if isinstance(thing, (Property, Class)): - return thing.identifier - else: - assert isinstance(thing, (URIRef, BNode)), ( - "Expecting a Class, Property, URIRef, or BNode.. not a %s" % thing - ) - return thing - - -def propertyOrIdentifier(thing): # noqa: N802 - if isinstance(thing, Property): - return thing.identifier - else: - assert isinstance(thing, URIRef) - return thing - - -def manchesterSyntax( # noqa: N802 - thing, store, boolean=None, transientList=False # noqa: N803 -): - """ - Core serialization - thing is a Class and is processed as a subject - store is an RDFLib Graph to be queried about thing - """ - assert thing is not None - if boolean: - if transientList: - livechildren = iter(thing) - children = [manchesterSyntax(child, store) for child in thing] - else: - livechildren = iter(Collection(store, thing)) - children = [ - manchesterSyntax(child, store) for child in Collection(store, thing) - ] - if boolean == OWL.intersectionOf: - childlist = [] - named = [] - for child in livechildren: - if isinstance(child, URIRef): - named.append(child) - else: - childlist.append(child) - if named: - - def castToQName(x): # noqa: N802 - prefix, uri, localname = store.compute_qname(x) - return ":".join([prefix, localname]) - - if len(named) > 1: - prefix = "( " + " AND ".join(map(castToQName, named)) + " )" - else: - prefix = manchesterSyntax(named[0], store) - if childlist: - return ( - str(prefix) - + " THAT " - + " AND ".join( - [str(manchesterSyntax(x, store)) for x in childlist] - ) - ) - else: - return prefix - else: - return "( " + " AND ".join([str(c) for c in children]) + " )" - elif boolean == OWL.unionOf: - return "( " + " OR ".join([str(c) for c in children]) + " )" - elif boolean == OWL.oneOf: - return "{ " + " ".join([str(c) for c in children]) + " }" - else: - assert boolean == OWL.complementOf - elif OWL.Restriction in store.objects(subject=thing, predicate=RDF.type): - prop = list(store.objects(subject=thing, predicate=OWL.onProperty))[0] - prefix, uri, localname = store.compute_qname(prop) - propstring = ":".join([prefix, localname]) - label = first(store.objects(subject=prop, predicate=RDFS.label)) - if label: - propstring = "'%s'" % label - for onlyclass in store.objects(subject=thing, predicate=OWL.allValuesFrom): - return "( %s ONLY %s )" % (propstring, manchesterSyntax(onlyclass, store)) - for val in store.objects(subject=thing, predicate=OWL.hasValue): - return "( %s VALUE %s )" % (propstring, manchesterSyntax(val, store)) - for someclass in store.objects(subject=thing, predicate=OWL.someValuesFrom): - return "( %s SOME %s )" % (propstring, manchesterSyntax(someclass, store)) - cardlookup = { - OWL.maxCardinality: "MAX", - OWL.minCardinality: "MIN", - OWL.cardinality: "EQUALS", - } - for _s, p, o in store.triples_choices((thing, list(cardlookup.keys()), None)): - return "( %s %s %s )" % (propstring, cardlookup[p], o) - # is thing a complement of anything - compl = list(store.objects(subject=thing, predicate=OWL.complementOf)) - if compl: - return "( NOT %s )" % (manchesterSyntax(compl[0], store)) - else: - prolog = "\n".join(["PREFIX %s: <%s>" % (k, nsBinds[k]) for k in nsBinds]) - qstr = ( - prolog - + "\nSELECT ?p ?bool WHERE {?class a owl:Class; ?p ?bool ." - + "?bool rdf:first ?foo }" - ) - initb = {Variable("?class"): thing} - for boolprop, col in store.query(qstr, processor="sparql", initBindings=initb): - if not isinstance(thing, URIRef): - return manchesterSyntax(col, store, boolean=boolprop) - try: - prefix, uri, localname = store.compute_qname(thing) - qname = ":".join([prefix, localname]) - except Exception: - if isinstance(thing, BNode): - return thing.n3() - # Expect the unexpected - return thing.identifier if not isinstance(thing, str) else thing - label = first(Class(thing, graph=store).label) - if label: - return label - else: - return qname - - -def GetIdentifiedClasses(graph): # noqa: N802 - for c in graph.subjects(predicate=RDF.type, object=OWL.Class): - if isinstance(c, URIRef): - yield Class(c) - - -class TermDeletionHelper: - def __init__(self, prop): - self.prop = prop - - def __call__(self, f): - def _remover(inst): - inst.graph.remove((inst.identifier, self.prop, None)) - - return _remover - - -class Individual: - """ - A typed individual, the base class of the InfixOWL classes. - - """ - - factoryGraph = Graph() # noqa: N815 - - def serialize(self, graph): - for fact in self.factoryGraph.triples((self.identifier, None, None)): - graph.add(fact) - - def __init__(self, identifier=None, graph=None): - self.__identifier = identifier is not None and identifier or BNode() - if graph is None: - self.graph = self.factoryGraph - else: - self.graph = graph - self.qname = None - if not isinstance(self.identifier, BNode): - try: - prefix, uri, localname = self.graph.compute_qname(self.identifier) - self.qname = ":".join([prefix, localname]) - except Exception: # pragma: no cover - pass # pragma: no cover - - def clearInDegree(self): # noqa: N802 - """ - Remove references to this individual as an object in the - backing store. - """ - self.graph.remove((None, None, self.identifier)) - - def clearOutDegree(self): # noqa: N802 - """ - Remove all statements to this individual as a subject in the - backing store. Note that this only removes the statements - themselves, not the blank node closure so there is a chance - that this will cause orphaned blank nodes to remain in the - graph. - """ - self.graph.remove((self.identifier, None, None)) - - def delete(self): - """ - Delete the individual from the graph, clearing the in and - out degrees. - """ - self.clearInDegree() - self.clearOutDegree() - - def replace(self, other): - """ - Replace the individual in the graph with the given other, - causing all triples that refer to it to be changed and then - delete the individual. - - >>> g = Graph() - >>> b = Individual(OWL.Restriction, g) - >>> b.type = RDFS.Resource - >>> len(list(b.type)) - 1 - >>> del b.type - >>> len(list(b.type)) - 0 - """ - for s, p, _o in self.graph.triples((None, None, self.identifier)): - self.graph.add((s, p, classOrIdentifier(other))) - self.delete() - - def _get_type(self) -> Iterable[_ObjectType]: - for _t in self.graph.objects(subject=self.identifier, predicate=RDF.type): - yield _t - - def _set_type(self, kind: Union[Individual, Identifier, Iterable[_ObjectType]]): - if not kind: - return - if isinstance(kind, (Individual, Identifier)): - self.graph.add((self.identifier, RDF.type, classOrIdentifier(kind))) - else: - for c in kind: - assert isinstance(c, (Individual, Identifier)) - self.graph.add((self.identifier, RDF.type, classOrIdentifier(c))) - - @TermDeletionHelper(RDF.type) - def _delete_type(self): - """ - >>> g = Graph() - >>> b = Individual(OWL.Restriction, g) - >>> b.type = RDFS.Resource - >>> len(list(b.type)) - 1 - >>> del b.type - >>> len(list(b.type)) - 0 - """ - pass # pragma: no cover - - type = property(_get_type, _set_type, _delete_type) - - def _get_identifier(self) -> Identifier: - return self.__identifier - - def _set_identifier(self, i: Identifier): - assert i - if i != self.__identifier: - oldstatements_out = [ - (p, o) - for s, p, o in self.graph.triples((self.__identifier, None, None)) - ] - oldstatements_in = [ - (s, p) - for s, p, o in self.graph.triples((None, None, self.__identifier)) - ] - for p1, o1 in oldstatements_out: - self.graph.remove((self.__identifier, p1, o1)) - for s1, p1 in oldstatements_in: - self.graph.remove((s1, p1, self.__identifier)) - self.__identifier = i - self.graph.addN([(i, p1, o1, self.graph) for p1, o1 in oldstatements_out]) - self.graph.addN([(s1, p1, i, self.graph) for s1, p1 in oldstatements_in]) - if not isinstance(i, BNode): - try: - prefix, uri, localname = self.graph.compute_qname(i) - self.qname = ":".join([prefix, localname]) - except Exception: # pragma: no cover - pass # pragma: no cover - - identifier = property(_get_identifier, _set_identifier) - - def _get_sameAs(self) -> Iterable[_ObjectType]: # noqa: N802 - for _t in self.graph.objects(subject=self.identifier, predicate=OWL.sameAs): - yield _t - - def _set_sameAs( # noqa: N802 - self, term: Union[Individual, Identifier, Iterable[_ObjectType]] - ): - # if not kind: - # return - if isinstance(term, (Individual, Identifier)): - self.graph.add((self.identifier, OWL.sameAs, classOrIdentifier(term))) - else: - for c in term: - assert isinstance(c, (Individual, Identifier)) - self.graph.add((self.identifier, OWL.sameAs, classOrIdentifier(c))) - - @TermDeletionHelper(OWL.sameAs) - def _delete_sameAs(self): # noqa: N802 - pass # pragma: no cover - - sameAs = property(_get_sameAs, _set_sameAs, _delete_sameAs) # noqa: N815 - - -ACE_NS = Namespace("http://attempto.ifi.uzh.ch/ace_lexicon#") - - -class AnnotatableTerms(Individual): - """ - Terms in an OWL ontology with rdfs:label and rdfs:comment - - - ## Interface with ATTEMPTO (http://attempto.ifi.uzh.ch/site) - - ### Verbalisation of OWL entity IRIS - - #### How are OWL entity IRIs verbalized? - - The OWL verbalizer maps OWL entity IRIs to ACE content words such - that - - - OWL individuals map to ACE proper names (PN) - - OWL classes map to ACE common nouns (CN) - - OWL properties map to ACE transitive verbs (TV) - - There are 6 morphological categories that determine the surface form - of an IRI: - - - singular form of a proper name (e.g. John) - - singular form of a common noun (e.g. man) - - plural form of a common noun (e.g. men) - - singular form of a transitive verb (e.g. mans) - - plural form of a transitive verb (e.g. man) - - past participle form a transitive verb (e.g. manned) - - The user has full control over the eventual surface forms of the IRIs - but has to choose them in terms of the above categories. - Furthermore, - - - the surface forms must be legal ACE content words (e.g. they - should not contain punctuation symbols); - - the mapping of IRIs to surface forms must be bidirectional - within the same word class, in order to be able to (if needed) - parse the verbalization back into OWL in a semantics preserving - way. - - ### Using the lexicon - - It is possible to specify the mapping of IRIs to surface forms using - the following annotation properties: - - .. code-block:: none - - http://attempto.ifi.uzh.ch/ace_lexicon#PN_sg - http://attempto.ifi.uzh.ch/ace_lexicon#CN_sg - http://attempto.ifi.uzh.ch/ace_lexicon#CN_pl - http://attempto.ifi.uzh.ch/ace_lexicon#TV_sg - http://attempto.ifi.uzh.ch/ace_lexicon#TV_pl - http://attempto.ifi.uzh.ch/ace_lexicon#TV_vbg - - For example, the following axioms state that if the IRI "#man" is used - as a plural common noun, then the wordform men must be used by the - verbalizer. If, however, it is used as a singular transitive verb, - then mans must be used. - - .. code-block:: none - - - - #man - men - - - - - #man - mans - - - """ - - def __init__( - self, - identifier, - graph=None, - nameAnnotation=None, # noqa: N803 - nameIsLabel=False, # noqa: N803 - ): - super(AnnotatableTerms, self).__init__(identifier, graph) - if nameAnnotation: - self.setupACEAnnotations() - self.PN_sgprop.extent = [ - (self.identifier, self.handleAnnotation(nameAnnotation)) - ] - if nameIsLabel: - self.label = [nameAnnotation] - - def handleAnnotation(self, val): # noqa: N802 - return val if isinstance(val, Literal) else Literal(val) - - def setupACEAnnotations(self): # noqa: N802 - self.graph.bind("ace", ACE_NS, override=False) - - # PN_sg singular form of a proper name () - self.PN_sgprop = Property( - ACE_NS.PN_sg, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - # CN_sg singular form of a common noun - self.CN_sgprop = Property( - ACE_NS.CN_sg, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - # CN_pl plural form of a common noun - self.CN_plprop = Property( - ACE_NS.CN_pl, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - # singular form of a transitive verb - self.tv_sgprop = Property( - ACE_NS.TV_sg, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - # plural form of a transitive verb - self.tv_plprop = Property( - ACE_NS.TV_pl, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - # past participle form a transitive verb - self.tv_vbgprop = Property( - ACE_NS.TV_vbg, baseType=OWL.AnnotationProperty, graph=self.graph - ) - - def _get_comment(self): - for comment in self.graph.objects( - subject=self.identifier, predicate=RDFS.comment - ): - yield comment - - def _set_comment(self, comment): - if not comment: - return - if isinstance(comment, Identifier): - self.graph.add((self.identifier, RDFS.comment, comment)) - else: - for c in comment: - self.graph.add((self.identifier, RDFS.comment, c)) - - @TermDeletionHelper(RDFS.comment) - def _del_comment(self): - pass # pragma: no cover - - comment = property(_get_comment, _set_comment, _del_comment) - - def _get_seealso(self): - for seealso in self.graph.objects( - subject=self.identifier, predicate=RDFS.seeAlso - ): - yield seealso - - def _set_seealso(self, seealsos): - if not seealsos: - return - for s in seealsos: - self.graph.add((self.identifier, RDFS.seeAlso, s)) - - @TermDeletionHelper(RDFS.seeAlso) - def _del_seealso(self): - pass # pragma: no cover - - seeAlso = property(_get_seealso, _set_seealso, _del_seealso) # noqa: N815 - - def _get_label(self): - for label in self.graph.objects(subject=self.identifier, predicate=RDFS.label): - yield label - - def _set_label(self, label): - if not label: - return - if isinstance(label, Identifier): - self.graph.add((self.identifier, RDFS.label, label)) - else: - for l_ in label: - self.graph.add((self.identifier, RDFS.label, l_)) - - @TermDeletionHelper(RDFS.label) - def _delete_label(self): - """ - >>> g = Graph() - >>> b = Individual(OWL.Restriction,g) - >>> b.label = Literal('boo') - >>> len(list(b.label)) - 1 - >>> del b.label - >>> len(list(b.label)) - 0 - """ - pass # pragma: no cover - - label = property(_get_label, _set_label, _delete_label) - - -class Ontology(AnnotatableTerms): - """The owl ontology metadata""" - - def __init__(self, identifier=None, imports=None, comment=None, graph=None): - super(Ontology, self).__init__(identifier, graph) - self.imports = [] if imports is None else imports - self.comment = [] if comment is None else comment - if (self.identifier, RDF.type, OWL.Ontology) not in self.graph: - self.graph.add((self.identifier, RDF.type, OWL.Ontology)) - - def setVersion(self, version): # noqa: N802 - self.graph.set((self.identifier, OWL.versionInfo, version)) - - def _get_imports(self): - for owl in self.graph.objects( - subject=self.identifier, predicate=OWL["imports"] - ): - yield owl - - def _set_imports(self, other): - if not other: - return - for o in other: - self.graph.add((self.identifier, OWL["imports"], o)) - - @TermDeletionHelper(OWL["imports"]) - def _del_imports(self): - pass # pragma: no cover - - imports = property(_get_imports, _set_imports, _del_imports) - - -def AllClasses(graph): # noqa: N802 - for c in set(graph.subjects(predicate=RDF.type, object=OWL.Class)): - yield Class(c) - - -def AllProperties(graph): # noqa: N802 - prevprops = set() - for s, _p, o in graph.triples_choices( - ( - None, - RDF.type, - [ - OWL.SymmetricProperty, - OWL.FunctionalProperty, - OWL.InverseFunctionalProperty, - OWL.TransitiveProperty, - OWL.DatatypeProperty, - OWL.ObjectProperty, - OWL.AnnotationProperty, - ], - ) - ): - if o in [ - OWL.SymmetricProperty, - OWL.InverseFunctionalProperty, - OWL.TransitiveProperty, - OWL.ObjectProperty, - ]: - bType = OWL.ObjectProperty # noqa: N806 - else: - bType = OWL.DatatypeProperty # noqa: N806 - if s not in prevprops: - prevprops.add(s) - yield Property(s, graph=graph, baseType=bType) - - -class ClassNamespaceFactory(Namespace): - def term(self, name): - return Class(URIRef(self + name)) - - def __getitem__(self, key, default=None): - return self.term(key) - - def __getattr__(self, name): - if name.startswith("__"): # ignore any special Python names! - raise AttributeError - else: - return self.term(name) - - -CLASS_RELATIONS = set( - Namespace("http://www.w3.org/2002/07/owl#resourceProperties") -).difference( - [ - OWL.onProperty, - OWL.allValuesFrom, - OWL.hasValue, - OWL.someValuesFrom, - OWL.inverseOf, - OWL.imports, - OWL.versionInfo, - OWL.backwardCompatibleWith, - OWL.incompatibleWith, - OWL.unionOf, - OWL.intersectionOf, - OWL.oneOf, - ] -) - - -def ComponentTerms(cls): # noqa: N802 - """ - Takes a Class instance and returns a generator over the classes that - are involved in its definition, ignoring unnamed classes - """ - if OWL.Restriction in cls.type: - try: - cls = CastClass(cls, Individual.factoryGraph) - for _s, _p, inner_class_id in cls.factoryGraph.triples_choices( - (cls.identifier, [OWL.allValuesFrom, OWL.someValuesFrom], None) - ): - inner_class = Class(inner_class_id, skipOWLClassMembership=True) - if isinstance(inner_class_id, BNode): - for _c in ComponentTerms(inner_class): - yield _c - else: - yield inner_class - except Exception: # pragma: no cover - pass # pragma: no cover - else: - cls = CastClass(cls, Individual.factoryGraph) - if isinstance(cls, BooleanClass): - for _cls in cls: - _cls = Class(_cls, skipOWLClassMembership=True) - if isinstance(_cls.identifier, BNode): - for _c in ComponentTerms(_cls): - yield _c - else: - yield _cls - else: - for inner_class in cls.subClassOf: - if isinstance(inner_class.identifier, BNode): - for _c in ComponentTerms(inner_class): - yield _c - else: - yield inner_class - for _s, _p, o in cls.factoryGraph.triples_choices( - (classOrIdentifier(cls), CLASS_RELATIONS, None) - ): - if isinstance(o, BNode): - for _c in ComponentTerms(CastClass(o, Individual.factoryGraph)): - yield _c - else: - yield inner_class - - -def DeepClassClear(class_to_prune): # noqa: N802 - """ - Recursively clear the given class, continuing - where any related class is an anonymous class - - >>> EX = Namespace("http://example.com/") - >>> g = Graph() - >>> g.bind("ex", EX, override=False) - >>> Individual.factoryGraph = g - >>> classB = Class(EX.B) - >>> classC = Class(EX.C) - >>> classD = Class(EX.D) - >>> classE = Class(EX.E) - >>> classF = Class(EX.F) - >>> anonClass = EX.someProp @ some @ classD - >>> classF += anonClass - >>> list(anonClass.subClassOf) - [Class: ex:F ] - >>> classA = classE | classF | anonClass - >>> classB += classA - >>> classA.equivalentClass = [Class()] - >>> classB.subClassOf = [EX.someProp @ some @ classC] - >>> classA - ( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) ) - >>> DeepClassClear(classA) - >>> classA - ( ) - >>> list(anonClass.subClassOf) - [] - >>> classB - Class: ex:B SubClassOf: ( ex:someProp SOME ex:C ) - - >>> otherClass = classD | anonClass - >>> otherClass - ( ex:D OR ( ex:someProp SOME ex:D ) ) - >>> DeepClassClear(otherClass) - >>> otherClass - ( ) - >>> otherClass.delete() - >>> list(g.triples((otherClass.identifier, None, None))) - [] - """ - - def deepClearIfBNode(_class): # noqa: N802 - if isinstance(classOrIdentifier(_class), BNode): - DeepClassClear(_class) - - class_to_prune = CastClass(class_to_prune, Individual.factoryGraph) - for c in class_to_prune.subClassOf: - deepClearIfBNode(c) - class_to_prune.graph.remove((class_to_prune.identifier, RDFS.subClassOf, None)) - for c in class_to_prune.equivalentClass: - deepClearIfBNode(c) - class_to_prune.graph.remove((class_to_prune.identifier, OWL.equivalentClass, None)) - inverse_class = class_to_prune.complementOf - if inverse_class: - class_to_prune.graph.remove((class_to_prune.identifier, OWL.complementOf, None)) - deepClearIfBNode(inverse_class) - if isinstance(class_to_prune, BooleanClass): - for c in class_to_prune: - deepClearIfBNode(c) - class_to_prune.clear() - class_to_prune.graph.remove( - (class_to_prune.identifier, class_to_prune._operator, None) - ) - - -class MalformedClass(ValueError): # noqa: N818 - """ - .. deprecated:: TODO-NEXT-VERSION - This class will be removed in version ``7.0.0``. - """ - - pass - - -class MalformedClassError(MalformedClass): - def __init__(self, msg): - self.msg = msg - - def __repr__(self): - return self.msg - - -def CastClass(c, graph=None): # noqa: N802 - graph = graph is None and c.factoryGraph or graph - for kind in graph.objects(subject=classOrIdentifier(c), predicate=RDF.type): - if kind == OWL.Restriction: - kwargs = {"identifier": classOrIdentifier(c), "graph": graph} - for _s, p, o in graph.triples((classOrIdentifier(c), None, None)): - if p != RDF.type: - if p == OWL.onProperty: - kwargs["onProperty"] = o - else: - if p not in Restriction.restrictionKinds: - continue - kwargs[str(p.split(str(OWL))[-1])] = o - if not set( - [str(i.split(str(OWL))[-1]) for i in Restriction.restrictionKinds] - ).intersection(kwargs): - raise MalformedClassError("Malformed owl:Restriction") - return Restriction(**kwargs) - else: - for _s, p, _o in graph.triples_choices( - ( - classOrIdentifier(c), - [OWL.intersectionOf, OWL.unionOf, OWL.oneOf], - None, - ) - ): - if p == OWL.oneOf: - return EnumeratedClass(classOrIdentifier(c), graph=graph) - else: - return BooleanClass(classOrIdentifier(c), operator=p, graph=graph) - # assert (classOrIdentifier(c),RDF.type,OWL.Class) in graph - return Class(classOrIdentifier(c), graph=graph, skipOWLClassMembership=True) - - -class Class(AnnotatableTerms): - """ - 'General form' for classes: - - The Manchester Syntax (supported in Protege) is used as the basis for the - form of this class - - See: http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf: - - [Annotation] - ‘Class:’ classID {Annotation - ( (‘SubClassOf:’ ClassExpression) - | (‘EquivalentTo’ ClassExpression) - | (’DisjointWith’ ClassExpression)) } - - Appropriate excerpts from OWL Reference: - - ".. Subclass axioms provide us with partial definitions: they represent - necessary but not sufficient conditions for establishing class - membership of an individual." - - ".. A class axiom may contain (multiple) owl:equivalentClass statements" - - "..A class axiom may also contain (multiple) owl:disjointWith statements.." - - "..An owl:complementOf property links a class to precisely one class - description." - - """ - - def _serialize(self, graph): - for cl in self.subClassOf: - CastClass(cl, self.graph).serialize(graph) - for cl in self.equivalentClass: - CastClass(cl, self.graph).serialize(graph) - for cl in self.disjointWith: - CastClass(cl, self.graph).serialize(graph) - if self.complementOf: - CastClass(self.complementOf, self.graph).serialize(graph) - - def serialize(self, graph): - for fact in self.graph.triples((self.identifier, None, None)): - graph.add(fact) - self._serialize(graph) - - def setupNounAnnotations(self, noun_annotations): # noqa: N802 - if isinstance(noun_annotations, tuple): - cn_sgprop, cn_plprop = noun_annotations - else: - cn_sgprop = noun_annotations - cn_plprop = noun_annotations - - if cn_sgprop: - self.CN_sgprop.extent = [ - (self.identifier, self.handleAnnotation(cn_sgprop)) - ] - if cn_plprop: - self.CN_plprop.extent = [ - (self.identifier, self.handleAnnotation(cn_plprop)) - ] - - def __init__( - self, - identifier=None, - subClassOf=None, # noqa: N803 - equivalentClass=None, # noqa: N803 - disjointWith=None, # noqa: N803 - complementOf=None, # noqa: N803 - graph=None, - skipOWLClassMembership=False, # noqa: N803 - comment=None, - nounAnnotations=None, # noqa: N803 - nameAnnotation=None, # noqa: N803 - nameIsLabel=False, # noqa: N803 - ): - super(Class, self).__init__(identifier, graph, nameAnnotation, nameIsLabel) - - if nounAnnotations: - self.setupNounAnnotations(nounAnnotations) - if ( - not skipOWLClassMembership - and (self.identifier, RDF.type, OWL.Class) not in self.graph - and (self.identifier, RDF.type, OWL.Restriction) not in self.graph - ): - self.graph.add((self.identifier, RDF.type, OWL.Class)) - - self.subClassOf = [] if subClassOf is None else subClassOf - self.equivalentClass = [] if equivalentClass is None else equivalentClass - self.disjointWith = [] if disjointWith is None else disjointWith - if complementOf: - self.complementOf = complementOf - self.comment = [] if comment is None else comment - - def _get_extent(self, graph=None): - for member in (graph is None and self.graph or graph).subjects( - predicate=RDF.type, object=self.identifier - ): - yield member - - def _set_extent(self, other): - if not other: - return - for m in other: - self.graph.add((classOrIdentifier(m), RDF.type, self.identifier)) - - @TermDeletionHelper(RDF.type) - def _del_type(self): - pass # pragma: no cover - - extent = property(_get_extent, _set_extent, _del_type) - - def _get_annotation(self, term=RDFS.label): - for annotation in self.graph.objects(subject=self.identifier, predicate=term): - yield annotation - - annotation = property(_get_annotation, lambda x: x) # type: ignore[arg-type,misc] - - def _get_extentquery(self): - return (Variable("CLASS"), RDF.type, self.identifier) - - def _set_extentquery(self, other): - pass # pragma: no cover - - extentQuery = property(_get_extentquery, _set_extentquery) # noqa: N815 - - def __hash__(self): - """ - >>> b = Class(OWL.Restriction) - >>> c = Class(OWL.Restriction) - >>> len(set([b,c])) - 1 - """ - return hash(self.identifier) - - def __eq__(self, other): - assert isinstance(other, Class), repr(other) - return self.identifier == other.identifier - - def __iadd__(self, other): - assert isinstance(other, Class) - other.subClassOf = [self] - return self - - def __isub__(self, other): - assert isinstance(other, Class) - self.graph.remove((classOrIdentifier(other), RDFS.subClassOf, self.identifier)) - return self - - def __invert__(self): - """ - Shorthand for Manchester syntax's not operator - """ - return Class(complementOf=self) - - def __or__(self, other): - """ - Construct an anonymous class description consisting of the union of - this class and 'other' and return it - """ - return BooleanClass( - operator=OWL.unionOf, members=[self, other], graph=self.graph - ) - - def __and__(self, other): - """ - Construct an anonymous class description consisting of the - intersection of this class and 'other' and return it - - Chaining 3 intersections - - >>> exNs = Namespace("http://example.com/") - >>> g = Graph() - >>> g.bind("ex", exNs, override=False) - >>> female = Class(exNs.Female, graph=g) - >>> human = Class(exNs.Human, graph=g) - >>> youngPerson = Class(exNs.YoungPerson, graph=g) - >>> youngWoman = female & human & youngPerson - >>> youngWoman # doctest: +SKIP - ex:YoungPerson THAT ( ex:Female AND ex:Human ) - >>> isinstance(youngWoman, BooleanClass) - True - >>> isinstance(youngWoman.identifier, BNode) - True - """ - return BooleanClass( - operator=OWL.intersectionOf, members=[self, other], graph=self.graph - ) - - def _get_subclassof(self): - for anc in self.graph.objects( - subject=self.identifier, predicate=RDFS.subClassOf - ): - yield Class(anc, graph=self.graph, skipOWLClassMembership=True) - - def _set_subclassof(self, other): - if not other: - return - for sc in other: - self.graph.add((self.identifier, RDFS.subClassOf, classOrIdentifier(sc))) - - @TermDeletionHelper(RDFS.subClassOf) - def _del_subclassof(self): - pass # pragma: no cover - - subClassOf = property( # noqa: N815 - _get_subclassof, _set_subclassof, _del_subclassof - ) - - def _get_equivalentclass(self): - for ec in self.graph.objects( - subject=self.identifier, predicate=OWL.equivalentClass - ): - yield Class(ec, graph=self.graph) - - def _set_equivalentclass(self, other): - if not other: - return - for sc in other: - self.graph.add( - (self.identifier, OWL.equivalentClass, classOrIdentifier(sc)) - ) - - @TermDeletionHelper(OWL.equivalentClass) - def _del_equivalentclass(self): - pass # pragma: no cover - - equivalentClass = property( # noqa: N815 - _get_equivalentclass, _set_equivalentclass, _del_equivalentclass - ) - - def _get_disjointwith(self): - for dc in self.graph.objects( - subject=self.identifier, predicate=OWL.disjointWith - ): - yield Class(dc, graph=self.graph) - - def _set_disjointwith(self, other): - if not other: - return - for c in other: - self.graph.add((self.identifier, OWL.disjointWith, classOrIdentifier(c))) - - @TermDeletionHelper(OWL.disjointWith) - def _del_disjointwith(self): - pass # pragma: no cover - - disjointWith = property( # noqa: N815 - _get_disjointwith, _set_disjointwith, _del_disjointwith - ) - - def _get_complementof(self): - comp = list( - self.graph.objects(subject=self.identifier, predicate=OWL.complementOf) - ) - if not comp: - return None - elif len(comp) == 1: - return Class(comp[0], graph=self.graph) - else: - raise Exception(len(comp)) - - def _set_complementof(self, other): - if not other: - return - self.graph.add((self.identifier, OWL.complementOf, classOrIdentifier(other))) - - @TermDeletionHelper(OWL.complementOf) - def _del_complementof(self): - pass # pragma: no cover - - complementOf = property( # noqa: N815 - _get_complementof, _set_complementof, _del_complementof - ) - - def _get_parents(self): - """ - computed attributes that returns a generator over taxonomic 'parents' - by disjunction, conjunction, and subsumption - - >>> from rdflib.util import first - >>> exNs = Namespace('http://example.com/') - >>> g = Graph() - >>> g.bind("ex", exNs, override=False) - >>> Individual.factoryGraph = g - >>> brother = Class(exNs.Brother) - >>> sister = Class(exNs.Sister) - >>> sibling = brother | sister - >>> sibling.identifier = exNs.Sibling - >>> sibling - ( ex:Brother OR ex:Sister ) - >>> first(brother.parents) - Class: ex:Sibling EquivalentTo: ( ex:Brother OR ex:Sister ) - >>> parent = Class(exNs.Parent) - >>> male = Class(exNs.Male) - >>> father = parent & male - >>> father.identifier = exNs.Father - >>> list(father.parents) - [Class: ex:Parent , Class: ex:Male ] - - """ - for parent in itertools.chain(self.subClassOf, self.equivalentClass): - yield parent - - link = first(self.factoryGraph.subjects(RDF.first, self.identifier)) - if link: - siblingslist = list(self.factoryGraph.transitive_subjects(RDF.rest, link)) - if siblingslist: - collectionhead = siblingslist[-1] - else: - collectionhead = link - for disjointclass in self.factoryGraph.subjects( - OWL.unionOf, collectionhead - ): - if isinstance(disjointclass, URIRef): - yield Class(disjointclass, skipOWLClassMembership=True) - for rdf_list in self.factoryGraph.objects(self.identifier, OWL.intersectionOf): - for member in OWLRDFListProxy([rdf_list], graph=self.factoryGraph): - if isinstance(member, URIRef): - yield Class(member, skipOWLClassMembership=True) - - parents = property(_get_parents) - - def isPrimitive(self): # noqa: N802 - if (self.identifier, RDF.type, OWL.Restriction) in self.graph: - return False - # sc = list(self.subClassOf) - ec = list(self.equivalentClass) - for _boolclass, p, rdf_list in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - (self.identifier, [OWL.intersectionOf, OWL.unionOf], None) # type: ignore[arg-type] - ): - ec.append(manchesterSyntax(rdf_list, self.graph, boolean=p)) - for _e in ec: - return False - if self.complementOf: - return False - return True - - def subSumpteeIds(self): # noqa: N802 - for s in self.graph.subjects(predicate=RDFS.subClassOf, object=self.identifier): - yield s - - # def __iter__(self): - # for s in self.graph.subjects( - # predicate=RDFS.subClassOf,object=self.identifier): - # yield Class(s,skipOWLClassMembership=True) - - def __repr__(self): - return self.manchesterClass(full=False, normalization=True) - - def manchesterClass(self, full=False, normalization=True): # noqa: N802 - """ - Returns the Manchester Syntax equivalent for this class - """ - exprs = [] - sc = list(self.subClassOf) - ec = list(self.equivalentClass) - for _boolclass, p, rdf_list in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - (self.identifier, [OWL.intersectionOf, OWL.unionOf], None) # type: ignore[arg-type] - ): - ec.append(manchesterSyntax(rdf_list, self.graph, boolean=p)) - dc = list(self.disjointWith) - c = self.complementOf - if c: - dc.append(c) - klasskind = "" - label = list(self.graph.objects(self.identifier, RDFS.label)) - # type error: Incompatible types in assignment (expression has type "str", variable has type "List[Node]") - # type error: Unsupported operand types for + ("str" and "Node") - label = label and "(" + label[0] + ")" or "" # type: ignore[assignment, operator] - if sc: - if full: - scjoin = "\n " - else: - scjoin = ", " - nec_statements = [ - isinstance(s, Class) - and isinstance(self.identifier, BNode) - and repr(CastClass(s, self.graph)) - or - # repr(BooleanClass(classOrIdentifier(s), - # operator=None, - # graph=self.graph)) or - manchesterSyntax(classOrIdentifier(s), self.graph) - for s in sc - ] - if nec_statements: - klasskind = "Primitive Type %s" % label - exprs.append( - "SubClassOf: %s" % scjoin.join([str(n) for n in nec_statements]) - ) - if full: - exprs[-1] = "\n " + exprs[-1] - if ec: - nec_suff_statements = [ - isinstance(s, str) - and s - or manchesterSyntax(classOrIdentifier(s), self.graph) - for s in ec - ] - if nec_suff_statements: - klasskind = "A Defined Class %s" % label - exprs.append("EquivalentTo: %s" % ", ".join(nec_suff_statements)) - if full: - exprs[-1] = "\n " + exprs[-1] - if dc: - exprs.append( - "DisjointWith %s\n" - % "\n ".join( - [manchesterSyntax(classOrIdentifier(s), self.graph) for s in dc] - ) - ) - if full: - exprs[-1] = "\n " + exprs[-1] - descr = list(self.graph.objects(self.identifier, RDFS.comment)) - if full and normalization: - klassdescr = ( - klasskind - and "\n ## %s ##" % klasskind - + (descr and "\n %s" % descr[0] or "") - + " . ".join(exprs) - or " . ".join(exprs) - ) - else: - klassdescr = ( - full - and (descr and "\n %s" % descr[0] or "") - or "" + " . ".join(exprs) - ) - return ( - isinstance(self.identifier, BNode) - and "Some Class " - or "Class: %s " % self.qname - ) + klassdescr - - -class OWLRDFListProxy: - def __init__(self, rdf_list, members=None, graph=None): - if graph: - self.graph = graph - members = [] if members is None else members - if rdf_list: - self._rdfList = Collection(self.graph, rdf_list[0]) - for member in members: - if member not in self._rdfList: - self._rdfList.append(classOrIdentifier(member)) - else: - self._rdfList = Collection( - self.graph, BNode(), [classOrIdentifier(m) for m in members] - ) - # type error: "OWLRDFListProxy" has no attribute "identifier" - # type error: "OWLRDFListProxy" has no attribute "_operator" - self.graph.add((self.identifier, self._operator, self._rdfList.uri)) # type: ignore[attr-defined] - - def __eq__(self, other): - """ - Equivalence of boolean class constructors is determined by - equivalence of its members - """ - assert isinstance(other, Class), repr(other) + repr(type(other)) - if isinstance(other, BooleanClass): - length = len(self) - if length != len(other): - return False - else: - for idx in range(length): - if self[idx] != other[idx]: - return False - return True - else: - # type error: "OWLRDFListProxy" has no attribute "identifier" - return self.identifier == other.identifier # type: ignore[attr-defined] - - # Redirect python list accessors to the underlying Collection instance - def __len__(self): - return len(self._rdfList) - - def index(self, item): - return self._rdfList.index(classOrIdentifier(item)) - - def __getitem__(self, key): - return self._rdfList[key] - - def __setitem__(self, key, value): - self._rdfList[key] = classOrIdentifier(value) - - def __delitem__(self, key): - del self._rdfList[key] - - def clear(self): - self._rdfList.clear() - - def __iter__(self): - for item in self._rdfList: - yield item - - def __contains__(self, item): - for i in self._rdfList: - if i == classOrIdentifier(item): - return 1 - return 0 - - def append(self, item): - self._rdfList.append(item) - - def __iadd__(self, other): - self._rdfList.append(classOrIdentifier(other)) - return self - - -class EnumeratedClass(OWLRDFListProxy, Class): - """ - Class for owl:oneOf forms: - - OWL Abstract Syntax is used - - axiom ::= 'EnumeratedClass(' - classID ['Deprecated'] { annotation } { individualID } ')' - - >>> exNs = Namespace("http://example.com/") - >>> g = Graph() - >>> g.bind("ex", exNs, override=False) - >>> Individual.factoryGraph = g - >>> ogbujiBros = EnumeratedClass(exNs.ogbujicBros, - ... members=[exNs.chime, - ... exNs.uche, - ... exNs.ejike]) - >>> ogbujiBros # doctest: +SKIP - { ex:chime ex:uche ex:ejike } - >>> col = Collection(g, first( - ... g.objects(predicate=OWL.oneOf, subject=ogbujiBros.identifier))) - >>> sorted([g.qname(item) for item in col]) - ['ex:chime', 'ex:ejike', 'ex:uche'] - >>> print(g.serialize(format='n3')) # doctest: +SKIP - @prefix ex: . - @prefix owl: . - @prefix rdf: . - - ex:ogbujicBros a owl:Class; - owl:oneOf ( ex:chime ex:uche ex:ejike ) . - - - """ - - _operator = OWL.oneOf - - def isPrimitive(self): # noqa: N802 - return False - - def __init__(self, identifier=None, members=None, graph=None): - Class.__init__(self, identifier, graph=graph) - members = [] if members is None else members - rdfList = list( # noqa: N806 - self.graph.objects(predicate=OWL.oneOf, subject=self.identifier) - ) - OWLRDFListProxy.__init__(self, rdfList, members) - - def __repr__(self): - """ - Returns the Manchester Syntax equivalent for this class - """ - return manchesterSyntax(self._rdfList.uri, self.graph, boolean=self._operator) - - def serialize(self, graph): - clonedlist = Collection(graph, BNode()) - for cl in self._rdfList: - clonedlist.append(cl) - CastClass(cl, self.graph).serialize(graph) - - graph.add((self.identifier, self._operator, clonedlist.uri)) - for s, p, o in self.graph.triples((self.identifier, None, None)): - if p != self._operator: - graph.add((s, p, o)) - self._serialize(graph) - - -BooleanPredicates = [OWL.intersectionOf, OWL.unionOf] - - -class BooleanClassExtentHelper: - """ - >>> testGraph = Graph() - >>> Individual.factoryGraph = testGraph - >>> EX = Namespace("http://example.com/") - >>> testGraph.bind("ex", EX, override=False) - >>> fire = Class(EX.Fire) - >>> water = Class(EX.Water) - >>> testClass = BooleanClass(members=[fire, water]) - >>> testClass2 = BooleanClass( - ... operator=OWL.unionOf, members=[fire, water]) - >>> for c in BooleanClass.getIntersections(): - ... print(c) # doctest: +SKIP - ( ex:Fire AND ex:Water ) - >>> for c in BooleanClass.getUnions(): - ... print(c) #doctest: +SKIP - ( ex:Fire OR ex:Water ) - """ - - def __init__(self, operator): - self.operator = operator - - def __call__(self, f): - def _getExtent(): # noqa: N802 - for c in Individual.factoryGraph.subjects(self.operator): - yield BooleanClass(c, operator=self.operator) - - return _getExtent - - -class Callable: - def __init__(self, anycallable): - self._callfn = anycallable - - def __call__(self, *args, **kwargs): - return self._callfn(*args, **kwargs) - - -class BooleanClass(OWLRDFListProxy, Class): - """ - See: http://www.w3.org/TR/owl-ref/#Boolean - - owl:complementOf is an attribute of Class, however - - """ - - @BooleanClassExtentHelper(OWL.intersectionOf) - @Callable - def getIntersections(): # type: ignore[misc] # noqa: N802 - pass # pragma: no cover - - getIntersections = Callable(getIntersections) # noqa: N815 - - @BooleanClassExtentHelper(OWL.unionOf) - @Callable - def getUnions(): # type: ignore[misc] # noqa: N802 - pass # pragma: no cover - - getUnions = Callable(getUnions) # noqa: N815 - - def __init__( - self, identifier=None, operator=OWL.intersectionOf, members=None, graph=None - ): - if operator is None: - props = [] - for _s, p, _o in graph.triples_choices( - (identifier, [OWL.intersectionOf, OWL.unionOf], None) - ): - props.append(p) - operator = p - assert len(props) == 1, repr(props) - Class.__init__(self, identifier, graph=graph) - assert operator in [OWL.intersectionOf, OWL.unionOf], str(operator) - self._operator = operator - rdf_list = list(self.graph.objects(predicate=operator, subject=self.identifier)) - assert ( - not members or not rdf_list - ), "This is a previous boolean class description." - OWLRDFListProxy.__init__(self, rdf_list, members) - - def copy(self): - """ - Create a copy of this class - """ - copy_of_class = BooleanClass( - operator=self._operator, members=list(self), graph=self.graph - ) - return copy_of_class - - def serialize(self, graph): - clonedlist = Collection(graph, BNode()) - for cl in self._rdfList: - clonedlist.append(cl) - CastClass(cl, self.graph).serialize(graph) - - graph.add((self.identifier, self._operator, clonedlist.uri)) - - for s, p, o in self.graph.triples((self.identifier, None, None)): - if p != self._operator: - graph.add((s, p, o)) - self._serialize(graph) - - def isPrimitive(self): # noqa: N802 - return False - - def changeOperator(self, newOperator): # noqa: N802, N803 - """ - Converts a unionOf / intersectionOf class expression into one - that instead uses the given operator - - >>> testGraph = Graph() - >>> Individual.factoryGraph = testGraph - >>> EX = Namespace("http://example.com/") - >>> testGraph.bind("ex", EX, override=False) - >>> fire = Class(EX.Fire) - >>> water = Class(EX.Water) - >>> testClass = BooleanClass(members=[fire,water]) - >>> testClass - ( ex:Fire AND ex:Water ) - >>> testClass.changeOperator(OWL.unionOf) - >>> testClass - ( ex:Fire OR ex:Water ) - >>> try: - ... testClass.changeOperator(OWL.unionOf) - ... except Exception as e: - ... print(e) # doctest: +SKIP - The new operator is already being used! - - """ - assert newOperator != self._operator, "The new operator is already being used!" - self.graph.remove((self.identifier, self._operator, self._rdfList.uri)) - self.graph.add((self.identifier, newOperator, self._rdfList.uri)) - self._operator = newOperator - - def __repr__(self): - """ - Returns the Manchester Syntax equivalent for this class - """ - return manchesterSyntax( - self._rdfList.uri if isinstance(self._rdfList, Collection) else BNode(), - self.graph, - boolean=self._operator, - ) - - def __or__(self, other): - """ - Adds other to the list and returns self - """ - assert self._operator == OWL.unionOf - self._rdfList.append(classOrIdentifier(other)) - return self - - -def AllDifferent(members): # noqa: N802 - """ - TODO: implement this function - - DisjointClasses(' description description { description } ')' - - """ - pass # pragma: no cover - - -class Restriction(Class): - """ - restriction ::= 'restriction(' - datavaluedPropertyID dataRestrictionComponent - { dataRestrictionComponent } ')' - | 'restriction(' individualvaluedPropertyID - individualRestrictionComponent - { individualRestrictionComponent } ')' - - """ - - restrictionKinds = [ # noqa: N815 - OWL.allValuesFrom, - OWL.someValuesFrom, - OWL.hasValue, - OWL.cardinality, - OWL.maxCardinality, - OWL.minCardinality, - ] - - def __init__( - self, - onProperty, # noqa: N803 - graph=None, - allValuesFrom=None, # noqa: N803 - someValuesFrom=None, # noqa: N803 - value=None, - cardinality=None, - maxCardinality=None, # noqa: N803 - minCardinality=None, # noqa: N803 - identifier=None, - ): - graph = Graph() if graph is None else graph - super(Restriction, self).__init__( - identifier, graph=graph, skipOWLClassMembership=True - ) - if ( - self.identifier, - OWL.onProperty, - propertyOrIdentifier(onProperty), - ) not in graph: - graph.add( - (self.identifier, OWL.onProperty, propertyOrIdentifier(onProperty)) - ) - self.onProperty = onProperty - restr_types = [ - (allValuesFrom, OWL.allValuesFrom), - (someValuesFrom, OWL.someValuesFrom), - (value, OWL.hasValue), - (cardinality, OWL.cardinality), - (maxCardinality, OWL.maxCardinality), - (minCardinality, OWL.minCardinality), - ] - valid_restr_props = [(i, oterm) for (i, oterm) in restr_types if i is not None] - if not len(valid_restr_props): - raise ValueError( - "Missing value. One of: allValuesFrom, someValuesFrom," - "value, cardinality, maxCardinality or minCardinality" - "must have a value." - ) - restriction_range, restriction_type = valid_restr_props.pop() - self.restrictionType = restriction_type - if isinstance(restriction_range, Identifier): - self.restrictionRange = restriction_range - elif isinstance(restriction_range, Class): - self.restrictionRange = classOrIdentifier(restriction_range) - else: - # error: Incompatible types in assignment (expression has type "Optional[Identifier]", variable has type "Identifier") - self.restrictionRange = first( # type: ignore[assignment] - # type error: Argument 1 to "first" has incompatible type "Generator[Node, None, None]"; expected "Iterable[Identifier]" - self.graph.objects(self.identifier, restriction_type) # type: ignore[arg-type] - ) - if ( - self.identifier, - restriction_type, - self.restrictionRange, - ) not in self.graph: - self.graph.add((self.identifier, restriction_type, self.restrictionRange)) - assert self.restrictionRange is not None, Class(self.identifier) - if (self.identifier, RDF.type, OWL.Restriction) not in self.graph: - self.graph.add((self.identifier, RDF.type, OWL.Restriction)) - self.graph.remove((self.identifier, RDF.type, OWL.Class)) - - def serialize(self, graph): - """ - >>> g1 = Graph() - >>> g2 = Graph() - >>> EX = Namespace("http://example.com/") - >>> g1.bind("ex", EX, override=False) - >>> g2.bind("ex", EX, override=False) - >>> Individual.factoryGraph = g1 - >>> prop = Property(EX.someProp, baseType=OWL.DatatypeProperty) - >>> restr1 = (Property( - ... EX.someProp, - ... baseType=OWL.DatatypeProperty)) @ some @ (Class(EX.Foo)) - >>> restr1 # doctest: +SKIP - ( ex:someProp SOME ex:Foo ) - >>> restr1.serialize(g2) - >>> Individual.factoryGraph = g2 - >>> list(Property( - ... EX.someProp,baseType=None).type - ... ) #doctest: +NORMALIZE_WHITESPACE +SKIP - [rdflib.term.URIRef( - 'http://www.w3.org/2002/07/owl#DatatypeProperty')] - """ - Property(self.onProperty, graph=self.graph, baseType=None).serialize(graph) - for s, p, o in self.graph.triples((self.identifier, None, None)): - graph.add((s, p, o)) - if p in [OWL.allValuesFrom, OWL.someValuesFrom]: - CastClass(o, self.graph).serialize(graph) - - def isPrimitive(self): # noqa: N802 - return False - - def __hash__(self): - return hash((self.onProperty, self.restrictionRange)) - - def __eq__(self, other): - """ - Equivalence of restrictions is determined by equivalence of the - property in question and the restriction 'range' - """ - assert isinstance(other, Class), repr(other) + repr(type(other)) - if isinstance(other, Restriction): - return ( - other.onProperty == self.onProperty - # type error: "Restriction" has no attribute "restriction_range"; maybe "restrictionRange"? - and other.restriction_range == self.restrictionRange # type: ignore[attr-defined] - ) - else: - return False - - def _get_onproperty(self): - return list( - self.graph.objects(subject=self.identifier, predicate=OWL.onProperty) - )[0] - - def _set_onproperty(self, prop): - if not prop: - return - triple = (self.identifier, OWL.onProperty, propertyOrIdentifier(prop)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.onProperty) - def _del_onproperty(self): - pass # pragma: no cover - - onProperty = property( # noqa: N815 - _get_onproperty, _set_onproperty, _del_onproperty - ) - - def _get_allvaluesfrom(self): - for i in self.graph.objects( - subject=self.identifier, predicate=OWL.allValuesFrom - ): - return Class(i, graph=self.graph) - return None - - def _set_allvaluesfrom(self, other): - if not other: - return - triple = (self.identifier, OWL.allValuesFrom, classOrIdentifier(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.allValuesFrom) - def _del_allvaluesfrom(self): - pass # pragma: no cover - - allValuesFrom = property( # noqa: N815 - _get_allvaluesfrom, _set_allvaluesfrom, _del_allvaluesfrom - ) - - def _get_somevaluesfrom(self): - for i in self.graph.objects( - subject=self.identifier, predicate=OWL.someValuesFrom - ): - return Class(i, graph=self.graph) - return None - - def _set_somevaluesfrom(self, other): - if not other: - return - triple = (self.identifier, OWL.someValuesFrom, classOrIdentifier(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.someValuesFrom) - def _del_somevaluesfrom(self): - pass # pragma: no cover - - someValuesFrom = property( # noqa: N815 - _get_somevaluesfrom, _set_somevaluesfrom, _del_somevaluesfrom - ) - - def _get_hasvalue(self): - for i in self.graph.objects(subject=self.identifier, predicate=OWL.hasValue): - return Class(i, graph=self.graph) - return None - - def _set_hasvalue(self, other): - if not other: - return - triple = (self.identifier, OWL.hasValue, classOrIdentifier(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.hasValue) - def _del_hasvalue(self): - pass # pragma: no cover - - hasValue = property(_get_hasvalue, _set_hasvalue, _del_hasvalue) # noqa: N815 - - def _get_cardinality(self): - for i in self.graph.objects(subject=self.identifier, predicate=OWL.cardinality): - return Class(i, graph=self.graph) - return None - - def _set_cardinality(self, other): - if not other: - return - triple = (self.identifier, OWL.cardinality, classOrTerm(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.cardinality) - def _del_cardinality(self): - pass # pragma: no cover - - cardinality = property(_get_cardinality, _set_cardinality, _del_cardinality) - - def _get_maxcardinality(self): - for i in self.graph.objects( - subject=self.identifier, predicate=OWL.maxCardinality - ): - return Class(i, graph=self.graph) - return None - - def _set_maxcardinality(self, other): - if not other: - return - triple = (self.identifier, OWL.maxCardinality, classOrTerm(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.maxCardinality) - def _del_maxcardinality(self): - pass # pragma: no cover - - maxCardinality = property( # noqa: N815 - _get_maxcardinality, _set_maxcardinality, _del_maxcardinality - ) - - def _get_mincardinality(self): - for i in self.graph.objects( - subject=self.identifier, predicate=OWL.minCardinality - ): - return Class(i, graph=self.graph) - return None - - def _set_mincardinality(self, other): - if not other: - return - triple = (self.identifier, OWL.minCardinality, classOrIdentifier(other)) - if triple in self.graph: - return - else: - self.graph.set(triple) - - @TermDeletionHelper(OWL.minCardinality) - def _del_mincardinality(self): - pass # pragma: no cover - - minCardinality = property( # noqa: N815 - _get_mincardinality, _set_mincardinality, _del_mincardinality - ) - - def restrictionKind(self): # noqa: N802 - for s, p, o in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - (self.identifier, self.restrictionKinds, None) # type: ignore[arg-type] - ): - # type error: "Node" has no attribute "split" - return p.split(str(OWL))[-1] # type: ignore[attr-defined] - return None - - def __repr__(self): - """ - Returns the Manchester Syntax equivalent for this restriction - """ - return manchesterSyntax(self.identifier, self.graph) - - -# Infix Operators # - - -some = Infix( - lambda prop, _class: Restriction(prop, graph=_class.graph, someValuesFrom=_class) -) -only = Infix( - lambda prop, _class: Restriction(prop, graph=_class.graph, allValuesFrom=_class) -) -max = Infix( - lambda prop, _class: Restriction(prop, graph=prop.graph, maxCardinality=_class) -) -min = Infix( - lambda prop, _class: Restriction(prop, graph=prop.graph, minCardinality=_class) -) -exactly = Infix( - lambda prop, _class: Restriction(prop, graph=prop.graph, cardinality=_class) -) -value = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, value=_class)) - -# Unused -PropertyAbstractSyntax = """ -%s( %s { %s } -%s -{ 'super(' datavaluedPropertyID ')'} ['Functional'] -{ domain( %s ) } { range( %s ) } )""" - - -class Property(AnnotatableTerms): - """ - axiom ::= 'DatatypeProperty(' datavaluedPropertyID ['Deprecated'] - { annotation } - { 'super(' datavaluedPropertyID ')'} ['Functional'] - { 'domain(' description ')' } { 'range(' dataRange ')' } ')' - | 'ObjectProperty(' individualvaluedPropertyID ['Deprecated'] - { annotation } - { 'super(' individualvaluedPropertyID ')' } - [ 'inverseOf(' individualvaluedPropertyID ')' ] [ 'Symmetric' ] - [ 'Functional' | 'InverseFunctional' | - 'Functional' 'InverseFunctional' | - 'Transitive' ] - { 'domain(' description ')' } { 'range(' description ')' } ') - - """ - - def setupVerbAnnotations(self, verb_annotations): # noqa: N802 - """ - - OWL properties map to ACE transitive verbs (TV) - - There are 6 morphological categories that determine the surface form - of an IRI: - - singular form of a transitive verb (e.g. mans) - plural form of a transitive verb (e.g. man) - past participle form a transitive verb (e.g. manned) - - http://attempto.ifi.uzh.ch/ace_lexicon#TV_sg - http://attempto.ifi.uzh.ch/ace_lexicon#TV_pl - http://attempto.ifi.uzh.ch/ace_lexicon#TV_vbg - - """ - - if isinstance(verb_annotations, tuple): - tv_sgprop, tv_plprop, tv_vbg = verb_annotations - else: - tv_sgprop = verb_annotations - tv_plprop = verb_annotations - tv_vbg = verb_annotations - if tv_sgprop: - self.tv_sgprop.extent = [ - (self.identifier, self.handleAnnotation(tv_sgprop)) - ] - if tv_plprop: - self.tv_plprop.extent = [ - (self.identifier, self.handleAnnotation(tv_plprop)) - ] - if tv_vbg: - self.tv_vbgprop.extent = [(self.identifier, self.handleAnnotation(tv_vbg))] - - def __init__( - self, - identifier=None, - graph=None, - baseType=OWL.ObjectProperty, # noqa: N803 - subPropertyOf=None, # noqa: N803 - domain=None, - range=None, - inverseOf=None, # noqa: N803 - otherType=None, # noqa: N803 - equivalentProperty=None, # noqa: N803 - comment=None, - verbAnnotations=None, # noqa: N803 - nameAnnotation=None, # noqa: N803 - nameIsLabel=False, # noqa: N803 - ): - super(Property, self).__init__(identifier, graph, nameAnnotation, nameIsLabel) - if verbAnnotations: - self.setupVerbAnnotations(verbAnnotations) - - assert not isinstance(self.identifier, BNode) - if baseType is None: - # None give, determine via introspection - self._baseType = first(Individual(self.identifier, graph=self.graph).type) - else: - if (self.identifier, RDF.type, baseType) not in self.graph: - self.graph.add((self.identifier, RDF.type, baseType)) - self._baseType = baseType - self.subPropertyOf = subPropertyOf - self.inverseOf = inverseOf - self.domain = domain - self.range = range - self.comment = [] if comment is None else comment - - def serialize(self, graph): - for fact in self.graph.triples((self.identifier, None, None)): - graph.add(fact) - for p in itertools.chain(self.subPropertyOf, self.inverseOf): - p.serialize(graph) - for c in itertools.chain(self.domain, self.range): - CastClass(c, self.graph).serialize(graph) - - def _get_extent(self, graph=None): - for triple in (graph is None and self.graph or graph).triples( - (None, self.identifier, None) - ): - yield triple - - def _set_extent(self, other): - if not other: - return - for subj, obj in other: - self.graph.add((subj, self.identifier, obj)) - - extent = property(_get_extent, _set_extent) - - def __repr__(self): - rt = [] - if OWL.ObjectProperty in self.type: - rt.append( - "ObjectProperty( %s annotation(%s)" - % (self.qname, first(self.comment) and first(self.comment) or "") - ) - if first(self.inverseOf): - # type error: Item "None" of "Optional[Any]" has no attribute "inverseOf" - two_link_inverse = first(first(self.inverseOf).inverseOf) # type: ignore[union-attr] - if two_link_inverse and two_link_inverse.identifier == self.identifier: - # type error: Item "None" of "Optional[Any]" has no attribute "qname" - inverserepr = first(self.inverseOf).qname # type: ignore[union-attr] - else: - inverserepr = repr(first(self.inverseOf)) - rt.append( - " inverseOf( %s )%s" - % ( - inverserepr, - OWL.SymmetricProperty in self.type and " Symmetric" or "", - ) - ) - for _s, _p, roletype in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, URIRef, List[URIRef]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - ( # type: ignore[arg-type] - self.identifier, - RDF.type, - [ - OWL.FunctionalProperty, - OWL.InverseFunctionalProperty, - OWL.TransitiveProperty, - ], - ) - ): - # type error: "Node" has no attribute "split" - rt.append(str(roletype.split(str(OWL))[-1])) # type: ignore[attr-defined] - else: - rt.append( - "DatatypeProperty( %s %s" - % (self.qname, first(self.comment) and first(self.comment) or "") - ) - for _s, _p, roletype in self.graph.triples( - (self.identifier, RDF.type, OWL.FunctionalProperty) - ): - rt.append(" Functional") - - def canonicalName(term, g): # noqa: N802 - normalized_name = classOrIdentifier(term) - if isinstance(normalized_name, BNode): - return term - elif normalized_name.startswith(XSD): - return str(term) - elif first( - g.triples_choices( - (normalized_name, [OWL.unionOf, OWL.intersectionOf], None) - ) - ): - return repr(term) - else: - return str(term.qname) - - rt.append( - " ".join( - [ - " super( %s )" % canonicalName(super_property, self.graph) - for super_property in self.subPropertyOf - ] - ) - ) - rt.append( - " ".join( - [ - " domain( %s )" % canonicalName(domain, self.graph) - for domain in self.domain - ] - ) - ) - rt.append( - " ".join( - [ - " range( %s )" % canonicalName(range, self.graph) - for range in self.range - ] - ) - ) - # type error: Incompatible types in assignment (expression has type "str", variable has type "List[str]") - rt = "\n".join([expr for expr in rt if expr]) # type: ignore[assignment] - rt += "\n)" - return rt - - def _get_subpropertyof(self): - for anc in self.graph.objects( - subject=self.identifier, predicate=RDFS.subPropertyOf - ): - yield Property(anc, graph=self.graph, baseType=None) - - def _set_subpropertyof(self, other): - if not other: - return - for subproperty in other: - self.graph.add( - (self.identifier, RDFS.subPropertyOf, classOrIdentifier(subproperty)) - ) - - @TermDeletionHelper(RDFS.subPropertyOf) - def _del_subpropertyof(self): - pass # pragma: no cover - - subPropertyOf = property( # noqa: N815 - _get_subpropertyof, _set_subpropertyof, _del_subpropertyof - ) - - def _get_inverseof(self): - for anc in self.graph.objects(subject=self.identifier, predicate=OWL.inverseOf): - yield Property(anc, graph=self.graph, baseType=None) - - def _set_inverseof(self, other): - if not other: - return - self.graph.add((self.identifier, OWL.inverseOf, classOrIdentifier(other))) - - @TermDeletionHelper(OWL.inverseOf) - def _del_inverseof(self): - pass # pragma: no cover - - inverseOf = property(_get_inverseof, _set_inverseof, _del_inverseof) # noqa: N815 - - def _get_domain(self): - for dom in self.graph.objects(subject=self.identifier, predicate=RDFS.domain): - yield Class(dom, graph=self.graph) - - def _set_domain(self, other): - if not other: - return - if isinstance(other, (Individual, Identifier)): - self.graph.add((self.identifier, RDFS.domain, classOrIdentifier(other))) - else: - for dom in other: - self.graph.add((self.identifier, RDFS.domain, classOrIdentifier(dom))) - - @TermDeletionHelper(RDFS.domain) - def _del_domain(self): - pass # pragma: no cover - - domain = property(_get_domain, _set_domain, _del_domain) - - def _get_range(self): - for ran in self.graph.objects(subject=self.identifier, predicate=RDFS.range): - yield Class(ran, graph=self.graph) - - def _set_range(self, ranges): - if not ranges: - return - if isinstance(ranges, (Individual, Identifier)): - self.graph.add((self.identifier, RDFS.range, classOrIdentifier(ranges))) - else: - for range in ranges: - self.graph.add((self.identifier, RDFS.range, classOrIdentifier(range))) - - @TermDeletionHelper(RDFS.range) - def _del_range(self): - pass # pragma: no cover - - range = property(_get_range, _set_range, _del_range) - - def replace(self, other): - # extension = [] - for s, _p, o in self.extent: - self.graph.add((s, propertyOrIdentifier(other), o)) - self.graph.remove((None, self.identifier, None)) - - -def CommonNSBindings(graph, additionalNS=None): # noqa: N802, N803 - """ - Takes a graph and binds the common namespaces (rdf,rdfs, & owl) - """ - additional_ns = {} if additionalNS is None else additionalNS - namespace_manager = NamespaceManager(graph) - namespace_manager.bind("rdfs", RDFS) - namespace_manager.bind("rdf", RDF) - namespace_manager.bind("owl", OWL) - for prefix, uri in list(additional_ns.items()): - namespace_manager.bind(prefix, uri, override=False) - graph.namespace_manager = namespace_manager diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/shacl.py b/extensions/.local/lib/python3.11/site-packages/rdflib/extras/shacl.py deleted file mode 100644 index 1a5094c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/extras/shacl.py +++ /dev/null @@ -1,212 +0,0 @@ -""" -Utilities for interacting with SHACL Shapes Graphs more easily. -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Optional, Union - -from rdflib import BNode, Graph, Literal, URIRef, paths -from rdflib.collection import Collection -from rdflib.namespace import RDF, SH -from rdflib.paths import Path -from rdflib.term import Node - -if TYPE_CHECKING: - from rdflib.term import IdentifiedNode - - -class SHACLPathError(Exception): - pass - - -# Map the variable length path operators to the corresponding SHACL path predicates -_PATH_MOD_TO_PRED = { - paths.ZeroOrMore: SH.zeroOrMorePath, - paths.OneOrMore: SH.oneOrMorePath, - paths.ZeroOrOne: SH.zeroOrOnePath, -} - - -# This implementation is roughly based on -# pyshacl.helper.sparql_query_helper::SPARQLQueryHelper._shacl_path_to_sparql_path -def parse_shacl_path( - shapes_graph: Graph, - path_identifier: Node, -) -> Union[URIRef, Path]: - """ - Parse a valid SHACL path (e.g. the object of a triple with predicate sh:path) - from a :class:`~rdflib.graph.Graph` as a :class:`~rdflib.term.URIRef` if the path - is simply a predicate or a :class:`~rdflib.paths.Path` otherwise. - - :param shapes_graph: A :class:`~rdflib.graph.Graph` containing the path to be parsed - :param path_identifier: A :class:`~rdflib.term.Node` of the path - :return: A :class:`~rdflib.term.URIRef` or a :class:`~rdflib.paths.Path` - """ - path: Optional[Union[URIRef, Path]] = None - - # Literals are not allowed. - if isinstance(path_identifier, Literal): - raise TypeError("Literals are not a valid SHACL path.") - - # If a path is a URI, that's the whole path. - elif isinstance(path_identifier, URIRef): - if path_identifier == RDF.nil: - raise SHACLPathError( - "A list of SHACL Paths must contain at least two path items." - ) - path = path_identifier - - # Handle Sequence Paths - elif shapes_graph.value(path_identifier, RDF.first) is not None: - sequence = list(shapes_graph.items(path_identifier)) - if len(sequence) < 2: - raise SHACLPathError( - "A list of SHACL Sequence Paths must contain at least two path items." - ) - path = paths.SequencePath( - *(parse_shacl_path(shapes_graph, path) for path in sequence) - ) - - # Handle sh:inversePath - elif inverse_path := shapes_graph.value(path_identifier, SH.inversePath): - path = paths.InvPath(parse_shacl_path(shapes_graph, inverse_path)) - - # Handle sh:alternativePath - elif alternative_path := shapes_graph.value(path_identifier, SH.alternativePath): - alternatives = list(shapes_graph.items(alternative_path)) - if len(alternatives) < 2: - raise SHACLPathError( - "List of SHACL alternate paths must have at least two path items." - ) - path = paths.AlternativePath( - *( - parse_shacl_path(shapes_graph, alternative) - for alternative in alternatives - ) - ) - - # Handle sh:zeroOrMorePath - elif zero_or_more_path := shapes_graph.value(path_identifier, SH.zeroOrMorePath): - path = paths.MulPath(parse_shacl_path(shapes_graph, zero_or_more_path), "*") - - # Handle sh:oneOrMorePath - elif one_or_more_path := shapes_graph.value(path_identifier, SH.oneOrMorePath): - path = paths.MulPath(parse_shacl_path(shapes_graph, one_or_more_path), "+") - - # Handle sh:zeroOrOnePath - elif zero_or_one_path := shapes_graph.value(path_identifier, SH.zeroOrOnePath): - path = paths.MulPath(parse_shacl_path(shapes_graph, zero_or_one_path), "?") - - # Raise error if none of the above options were found - elif path is None: - raise SHACLPathError(f"Cannot parse {repr(path_identifier)} as a SHACL Path.") - - return path - - -def _build_path_component( - graph: Graph, path_component: URIRef | Path -) -> IdentifiedNode: - """ - Helper method that implements the recursive component of SHACL path - triple construction. - - :param graph: A :class:`~rdflib.graph.Graph` into which to insert triples - :param graph_component: A :class:`~rdflib.term.URIRef` or - :class:`~rdflib.paths.Path` that is part of a path expression - :return: The :class:`~rdflib.term.IdentifiedNode of the resource in the - graph that corresponds to the provided path_component - """ - # Literals or other types are not allowed - if not isinstance(path_component, (URIRef, Path)): - raise TypeError( - f"Objects of type {type(path_component)} are not valid " - + "components of a SHACL path." - ) - - # If the path component is a URI, return it - elif isinstance(path_component, URIRef): - return path_component - # Otherwise, the path component is represented as a blank node - bnode = BNode() - - # Handle Sequence Paths - if isinstance(path_component, paths.SequencePath): - # Sequence paths are a Collection directly with at least two items - if len(path_component.args) < 2: - raise SHACLPathError( - "A list of SHACL Sequence Paths must contain at least two path items." - ) - Collection( - graph, - bnode, - [_build_path_component(graph, arg) for arg in path_component.args], - ) - - # Handle Inverse Paths - elif isinstance(path_component, paths.InvPath): - graph.add( - (bnode, SH.inversePath, _build_path_component(graph, path_component.arg)) - ) - - # Handle Alternative Paths - elif isinstance(path_component, paths.AlternativePath): - # Alternative paths are a Collection but referenced by sh:alternativePath - # with at least two items - if len(path_component.args) < 2: - raise SHACLPathError( - "List of SHACL alternate paths must have at least two path items." - ) - coll = Collection( - graph, - BNode(), - [_build_path_component(graph, arg) for arg in path_component.args], - ) - graph.add((bnode, SH.alternativePath, coll.uri)) - - # Handle Variable Length Paths - elif isinstance(path_component, paths.MulPath): - # Get the predicate corresponding to the path modifiier - pred = _PATH_MOD_TO_PRED.get(path_component.mod) - if pred is None: - raise SHACLPathError(f"Unknown path modifier {path_component.mod}") - graph.add((bnode, pred, _build_path_component(graph, path_component.path))) - - # Return the blank node created for the provided path_component - return bnode - - -def build_shacl_path( - path: URIRef | Path, target_graph: Graph | None = None -) -> tuple[IdentifiedNode, Graph | None]: - """ - Build the SHACL Path triples for a path given by a :class:`~rdflib.term.URIRef` for - simple paths or a :class:`~rdflib.paths.Path` for complex paths. - - Returns an :class:`~rdflib.term.IdentifiedNode` for the path (which should be - the object of a triple with predicate sh:path) and the graph into which any - new triples were added. - - :param path: A :class:`~rdflib.term.URIRef` or a :class:`~rdflib.paths.Path` - :param target_graph: Optionally, a :class:`~rdflib.graph.Graph` into which to put - constructed triples. If not provided, a new graph will be created - :return: A (path_identifier, graph) tuple where: - - path_identifier: If path is a :class:`~rdflib.term.URIRef`, this is simply - the provided path. If path is a :class:`~rdflib.paths.Path`, this is - the :class:`~rdflib.term.BNode` corresponding to the root of the SHACL - path expression added to the graph. - - graph: None if path is a :class:`~rdflib.term.URIRef` (as no new triples - are constructed). If path is a :class:`~rdflib.paths.Path`, this is either the - target_graph provided or a new graph into which the path triples were added. - """ - # If a path is a URI, that's the whole path. No graph needs to be constructed. - if isinstance(path, URIRef): - return path, None - - # Create a graph if one was not provided - if target_graph is None: - target_graph = Graph() - - # Recurse through the path to build the graph representation - return _build_path_component(target_graph, path), target_graph diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/graph.py b/extensions/.local/lib/python3.11/site-packages/rdflib/graph.py deleted file mode 100644 index 857491a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/graph.py +++ /dev/null @@ -1,3099 +0,0 @@ -"""\ - -RDFLib defines the following kinds of Graphs: - -* :class:`~rdflib.graph.Graph` -* :class:`~rdflib.graph.QuotedGraph` -* :class:`~rdflib.graph.ConjunctiveGraph` -* :class:`~rdflib.graph.Dataset` - -Graph ------ - -An RDF graph is a set of RDF triples. Graphs support the python ``in`` -operator, as well as iteration and some operations like union, -difference and intersection. - -see :class:`~rdflib.graph.Graph` - -Conjunctive Graph ------------------ - -.. warning:: - ConjunctiveGraph is deprecated, use :class:`~rdflib.graph.Dataset` instead. - -A Conjunctive Graph is the most relevant collection of graphs that are -considered to be the boundary for closed world assumptions. This -boundary is equivalent to that of the store instance (which is itself -uniquely identified and distinct from other instances of -:class:`~rdflib.store.Store` that signify other Conjunctive Graphs). It is -equivalent to all the named graphs within it and associated with a -``_default_`` graph which is automatically assigned a -:class:`~rdflib.term.BNode` for an identifier - if one isn't given. - -see :class:`~rdflib.graph.ConjunctiveGraph` - -Quoted graph ------------- - -The notion of an RDF graph [14] is extended to include the concept of -a formula node. A formula node may occur wherever any other kind of -node can appear. Associated with a formula node is an RDF graph that -is completely disjoint from all other graphs; i.e. has no nodes in -common with any other graph. (It may contain the same labels as other -RDF graphs; because this is, by definition, a separate graph, -considerations of tidiness do not apply between the graph at a formula -node and any other graph.) - -This is intended to map the idea of "{ N3-expression }" that is used -by N3 into an RDF graph upon which RDF semantics is defined. - -see :class:`~rdflib.graph.QuotedGraph` - -Dataset -------- - -The RDF 1.1 Dataset, a small extension to the Conjunctive Graph. The -primary term is "graphs in the datasets" and not "contexts with quads" -so there is a separate method to set/retrieve a graph in a dataset and -to operate with dataset graphs. As a consequence of this approach, -dataset graphs cannot be identified with blank nodes, a name is always -required (RDFLib will automatically add a name if one is not provided -at creation time). This implementation includes a convenience method -to directly add a single quad to a dataset graph. - -see :class:`~rdflib.graph.Dataset` - -Working with graphs -=================== - -Instantiating Graphs with default store (Memory) and default identifier -(a BNode): - - >>> g = Graph() - >>> g.store.__class__ - - >>> g.identifier.__class__ - - -Instantiating Graphs with a Memory store and an identifier - -: - - >>> g = Graph('Memory', URIRef("https://rdflib.github.io")) - >>> g.identifier - rdflib.term.URIRef('https://rdflib.github.io') - >>> str(g) # doctest: +NORMALIZE_WHITESPACE - " a rdfg:Graph;rdflib:storage - [a rdflib:Store;rdfs:label 'Memory']." - -Creating a ConjunctiveGraph - The top level container for all named Graphs -in a "database": - - >>> g = ConjunctiveGraph() - >>> str(g.default_context) - "[a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label 'Memory']]." - -Adding / removing reified triples to Graph and iterating over it directly or -via triple pattern: - - >>> g = Graph() - >>> statementId = BNode() - >>> print(len(g)) - 0 - >>> g.add((statementId, RDF.type, RDF.Statement)) # doctest: +ELLIPSIS - )> - >>> g.add((statementId, RDF.subject, - ... URIRef("https://rdflib.github.io/store/ConjunctiveGraph"))) # doctest: +ELLIPSIS - )> - >>> g.add((statementId, RDF.predicate, namespace.RDFS.label)) # doctest: +ELLIPSIS - )> - >>> g.add((statementId, RDF.object, Literal("Conjunctive Graph"))) # doctest: +ELLIPSIS - )> - >>> print(len(g)) - 4 - >>> for s, p, o in g: - ... print(type(s)) - ... - - - - - - >>> for s, p, o in g.triples((None, RDF.object, None)): - ... print(o) - ... - Conjunctive Graph - >>> g.remove((statementId, RDF.type, RDF.Statement)) # doctest: +ELLIPSIS - )> - >>> print(len(g)) - 3 - -``None`` terms in calls to :meth:`~rdflib.graph.Graph.triples` can be -thought of as "open variables". - -Graph support set-theoretic operators, you can add/subtract graphs, as -well as intersection (with multiplication operator g1*g2) and xor (g1 -^ g2). - -Note that BNode IDs are kept when doing set-theoretic operations, this -may or may not be what you want. Two named graphs within the same -application probably want share BNode IDs, two graphs with data from -different sources probably not. If your BNode IDs are all generated -by RDFLib they are UUIDs and unique. - - >>> g1 = Graph() - >>> g2 = Graph() - >>> u = URIRef("http://example.com/foo") - >>> g1.add([u, namespace.RDFS.label, Literal("foo")]) # doctest: +ELLIPSIS - )> - >>> g1.add([u, namespace.RDFS.label, Literal("bar")]) # doctest: +ELLIPSIS - )> - >>> g2.add([u, namespace.RDFS.label, Literal("foo")]) # doctest: +ELLIPSIS - )> - >>> g2.add([u, namespace.RDFS.label, Literal("bing")]) # doctest: +ELLIPSIS - )> - >>> len(g1 + g2) # adds bing as label - 3 - >>> len(g1 - g2) # removes foo - 1 - >>> len(g1 * g2) # only foo - 1 - >>> g1 += g2 # now g1 contains everything - - -Graph Aggregation - ConjunctiveGraphs and ReadOnlyGraphAggregate within -the same store: - - >>> store = plugin.get("Memory", Store)() - >>> g1 = Graph(store) - >>> g2 = Graph(store) - >>> g3 = Graph(store) - >>> stmt1 = BNode() - >>> stmt2 = BNode() - >>> stmt3 = BNode() - >>> g1.add((stmt1, RDF.type, RDF.Statement)) # doctest: +ELLIPSIS - )> - >>> g1.add((stmt1, RDF.subject, - ... URIRef('https://rdflib.github.io/store/ConjunctiveGraph'))) # doctest: +ELLIPSIS - )> - >>> g1.add((stmt1, RDF.predicate, namespace.RDFS.label)) # doctest: +ELLIPSIS - )> - >>> g1.add((stmt1, RDF.object, Literal('Conjunctive Graph'))) # doctest: +ELLIPSIS - )> - >>> g2.add((stmt2, RDF.type, RDF.Statement)) # doctest: +ELLIPSIS - )> - >>> g2.add((stmt2, RDF.subject, - ... URIRef('https://rdflib.github.io/store/ConjunctiveGraph'))) # doctest: +ELLIPSIS - )> - >>> g2.add((stmt2, RDF.predicate, RDF.type)) # doctest: +ELLIPSIS - )> - >>> g2.add((stmt2, RDF.object, namespace.RDFS.Class)) # doctest: +ELLIPSIS - )> - >>> g3.add((stmt3, RDF.type, RDF.Statement)) # doctest: +ELLIPSIS - )> - >>> g3.add((stmt3, RDF.subject, - ... URIRef('https://rdflib.github.io/store/ConjunctiveGraph'))) # doctest: +ELLIPSIS - )> - >>> g3.add((stmt3, RDF.predicate, namespace.RDFS.comment)) # doctest: +ELLIPSIS - )> - >>> g3.add((stmt3, RDF.object, Literal( - ... 'The top-level aggregate graph - The sum ' + - ... 'of all named graphs within a Store'))) # doctest: +ELLIPSIS - )> - >>> len(list(ConjunctiveGraph(store).subjects(RDF.type, RDF.Statement))) - 3 - >>> len(list(ReadOnlyGraphAggregate([g1,g2]).subjects( - ... RDF.type, RDF.Statement))) - 2 - -ConjunctiveGraphs have a :meth:`~rdflib.graph.ConjunctiveGraph.quads` method -which returns quads instead of triples, where the fourth item is the Graph -(or subclass thereof) instance in which the triple was asserted: - - >>> uniqueGraphNames = set( - ... [graph.identifier for s, p, o, graph in ConjunctiveGraph(store - ... ).quads((None, RDF.predicate, None))]) - >>> len(uniqueGraphNames) - 3 - >>> unionGraph = ReadOnlyGraphAggregate([g1, g2]) - >>> uniqueGraphNames = set( - ... [graph.identifier for s, p, o, graph in unionGraph.quads( - ... (None, RDF.predicate, None))]) - >>> len(uniqueGraphNames) - 2 - -Parsing N3 from a string - - >>> g2 = Graph() - >>> src = ''' - ... @prefix rdf: . - ... @prefix rdfs: . - ... [ a rdf:Statement ; - ... rdf:subject ; - ... rdf:predicate rdfs:label; - ... rdf:object "Conjunctive Graph" ] . - ... ''' - >>> g2 = g2.parse(data=src, format="n3") - >>> print(len(g2)) - 4 - -Using Namespace class: - - >>> RDFLib = Namespace("https://rdflib.github.io/") - >>> RDFLib.ConjunctiveGraph - rdflib.term.URIRef('https://rdflib.github.io/ConjunctiveGraph') - >>> RDFLib["Graph"] - rdflib.term.URIRef('https://rdflib.github.io/Graph') - -""" - -from __future__ import annotations - -import logging -import pathlib -import random -import warnings -from io import BytesIO -from typing import ( - IO, - TYPE_CHECKING, - Any, - BinaryIO, - Callable, - Dict, - Generator, - Iterable, - List, - Mapping, - NoReturn, - Optional, - Set, - TextIO, - Tuple, - Type, - TypeVar, - Union, - cast, - overload, -) -from urllib.parse import urlparse -from urllib.request import url2pathname - -import rdflib.exceptions as exceptions -import rdflib.namespace as namespace # noqa: F401 # This is here because it is used in a docstring. -import rdflib.plugin as plugin -import rdflib.query as query -import rdflib.util # avoid circular dependency -from rdflib.collection import Collection -from rdflib.exceptions import ParserError -from rdflib.namespace import RDF, Namespace, NamespaceManager -from rdflib.parser import InputSource, Parser, create_input_source -from rdflib.paths import Path -from rdflib.resource import Resource -from rdflib.serializer import Serializer -from rdflib.store import Store -from rdflib.term import ( - BNode, - Genid, - IdentifiedNode, - Identifier, - Literal, - Node, - RDFLibGenid, - URIRef, -) - -if TYPE_CHECKING: - import typing_extensions as te - - import rdflib.query - from rdflib.plugins.sparql.sparql import Query, Update - -_SubjectType = Node -_PredicateType = Node -_ObjectType = Node -_ContextIdentifierType = IdentifiedNode - -_TripleType = Tuple["_SubjectType", "_PredicateType", "_ObjectType"] -_QuadType = Tuple["_SubjectType", "_PredicateType", "_ObjectType", "_ContextType"] -_OptionalQuadType = Tuple[ - "_SubjectType", "_PredicateType", "_ObjectType", Optional["_ContextType"] -] -_TripleOrOptionalQuadType = Union["_TripleType", "_OptionalQuadType"] -_OptionalIdentifiedQuadType = Tuple[ - "_SubjectType", "_PredicateType", "_ObjectType", Optional["_ContextIdentifierType"] -] -_TriplePatternType = Tuple[ - Optional["_SubjectType"], Optional["_PredicateType"], Optional["_ObjectType"] -] -_TriplePathPatternType = Tuple[Optional["_SubjectType"], Path, Optional["_ObjectType"]] -_QuadPatternType = Tuple[ - Optional["_SubjectType"], - Optional["_PredicateType"], - Optional["_ObjectType"], - Optional["_ContextType"], -] -_QuadPathPatternType = Tuple[ - Optional["_SubjectType"], - Path, - Optional["_ObjectType"], - Optional["_ContextType"], -] -_TripleOrQuadPatternType = Union["_TriplePatternType", "_QuadPatternType"] -_TripleOrQuadPathPatternType = Union["_TriplePathPatternType", "_QuadPathPatternType"] -_TripleSelectorType = Tuple[ - Optional["_SubjectType"], - Optional[Union["Path", "_PredicateType"]], - Optional["_ObjectType"], -] -_QuadSelectorType = Tuple[ - Optional["_SubjectType"], - Optional[Union["Path", "_PredicateType"]], - Optional["_ObjectType"], - Optional["_ContextType"], -] -_TripleOrQuadSelectorType = Union["_TripleSelectorType", "_QuadSelectorType"] -_TriplePathType = Tuple["_SubjectType", Path, "_ObjectType"] -_TripleOrTriplePathType = Union["_TripleType", "_TriplePathType"] - -_GraphT = TypeVar("_GraphT", bound="Graph") -_ConjunctiveGraphT = TypeVar("_ConjunctiveGraphT", bound="ConjunctiveGraph") -_DatasetT = TypeVar("_DatasetT", bound="Dataset") - -# type error: Function "Type[Literal]" could always be true in boolean contex -assert Literal # type: ignore[truthy-function] # avoid warning -# type error: Function "Type[Namespace]" could always be true in boolean context -assert Namespace # type: ignore[truthy-function] # avoid warning - -if TYPE_CHECKING: - from rdflib._type_checking import _NamespaceSetString - -logger = logging.getLogger(__name__) - - -__all__ = [ - "Graph", - "ConjunctiveGraph", - "QuotedGraph", - "Seq", - "ModificationException", - "Dataset", - "UnSupportedAggregateOperation", - "ReadOnlyGraphAggregate", - "BatchAddGraph", - "_ConjunctiveGraphT", - "_ContextIdentifierType", - "_DatasetT", - "_GraphT", - "_ObjectType", - "_OptionalIdentifiedQuadType", - "_OptionalQuadType", - "_PredicateType", - "_QuadPathPatternType", - "_QuadPatternType", - "_QuadSelectorType", - "_QuadType", - "_SubjectType", - "_TripleOrOptionalQuadType", - "_TripleOrTriplePathType", - "_TripleOrQuadPathPatternType", - "_TripleOrQuadPatternType", - "_TripleOrQuadSelectorType", - "_TriplePathPatternType", - "_TriplePathType", - "_TriplePatternType", - "_TripleSelectorType", - "_TripleType", -] - -# : Transitive closure arg type. -_TCArgT = TypeVar("_TCArgT") - - -class Graph(Node): - """An RDF Graph: a Python object containing nodes and relations between them as - RDF 'triples'. - - This is the central RDFLib object class and Graph objects are almost always present - it all uses of RDFLib. - - The basic use is to create a Graph and iterate through or query its content, e.g.: - - >>> from rdflib import Graph, URIRef - >>> g = Graph() - - >>> g.add(( - ... URIRef("http://example.com/s1"), # subject - ... URIRef("http://example.com/p1"), # predicate - ... URIRef("http://example.com/o1"), # object - ... )) # doctest: +ELLIPSIS - )> - - >>> g.add(( - ... URIRef("http://example.com/s2"), # subject - ... URIRef("http://example.com/p2"), # predicate - ... URIRef("http://example.com/o2"), # object - ... )) # doctest: +ELLIPSIS - )> - - >>> for triple in sorted(g): # simple looping - ... print(triple) - (rdflib.term.URIRef('http://example.com/s1'), rdflib.term.URIRef('http://example.com/p1'), rdflib.term.URIRef('http://example.com/o1')) - (rdflib.term.URIRef('http://example.com/s2'), rdflib.term.URIRef('http://example.com/p2'), rdflib.term.URIRef('http://example.com/o2')) - - >>> # get the object of the triple with subject s1 and predicate p1 - >>> o = g.value( - ... subject=URIRef("http://example.com/s1"), - ... predicate=URIRef("http://example.com/p1") - ... ) - - - The constructor accepts one argument, the "store" that will be used to store the - graph data with the default being the `Memory ` - (in memory) Store. Other Stores that persist content to disk using various file - databases or Stores that use remote servers (SPARQL systems) are supported. See - the :doc:`rdflib.plugins.stores` package for Stores currently shipped with RDFLib. - Other Stores not shipped with RDFLib can be added, such as - `HDT `_. - - Stores can be context-aware or unaware. Unaware stores take up - (some) less space but cannot support features that require - context, such as true merging/demerging of sub-graphs and - provenance. - - Even if used with a context-aware store, Graph will only expose the quads which - belong to the default graph. To access the rest of the data the - `Dataset` class can be used instead. - - The Graph constructor can take an identifier which identifies the Graph - by name. If none is given, the graph is assigned a BNode for its - identifier. - - For more on Named Graphs, see the RDFLib `Dataset` class and the TriG Specification, - https://www.w3.org/TR/trig/. - """ - - context_aware: bool - formula_aware: bool - default_union: bool - base: Optional[str] - - def __init__( - self, - store: Union[Store, str] = "default", - identifier: Optional[Union[_ContextIdentifierType, str]] = None, - namespace_manager: Optional[NamespaceManager] = None, - base: Optional[str] = None, - bind_namespaces: _NamespaceSetString = "rdflib", - ): - super(Graph, self).__init__() - self.base = base - self.__identifier: _ContextIdentifierType - self.__identifier = identifier or BNode() # type: ignore[assignment] - if not isinstance(self.__identifier, IdentifiedNode): - self.__identifier = URIRef(self.__identifier) # type: ignore[unreachable] - self.__store: Store - if not isinstance(store, Store): - # TODO: error handling - self.__store = store = plugin.get(store, Store)() - else: - self.__store = store - self.__namespace_manager = namespace_manager - self._bind_namespaces = bind_namespaces - self.context_aware = False - self.formula_aware = False - self.default_union = False - - @property - def store(self) -> Store: - return self.__store - - @property - def identifier(self) -> _ContextIdentifierType: - return self.__identifier - - @property - def namespace_manager(self) -> NamespaceManager: - """ - this graph's namespace-manager - """ - if self.__namespace_manager is None: - self.__namespace_manager = NamespaceManager(self, self._bind_namespaces) - return self.__namespace_manager - - @namespace_manager.setter - def namespace_manager(self, nm: NamespaceManager) -> None: - self.__namespace_manager = nm - - def __repr__(self) -> str: - return "" % (self.identifier, type(self)) - - def __str__(self) -> str: - if isinstance(self.identifier, URIRef): - return ( - "%s a rdfg:Graph;rdflib:storage " + "[a rdflib:Store;rdfs:label '%s']." - ) % (self.identifier.n3(), self.store.__class__.__name__) - else: - return ( - "[a rdfg:Graph;rdflib:storage " + "[a rdflib:Store;rdfs:label '%s']]." - ) % self.store.__class__.__name__ - - def toPython(self: _GraphT) -> _GraphT: # noqa: N802 - return self - - def destroy(self: _GraphT, configuration: str) -> _GraphT: - """Destroy the store identified by ``configuration`` if supported""" - self.__store.destroy(configuration) - return self - - # Transactional interfaces (optional) - def commit(self: _GraphT) -> _GraphT: - """Commits active transactions""" - self.__store.commit() - return self - - def rollback(self: _GraphT) -> _GraphT: - """Rollback active transactions""" - self.__store.rollback() - return self - - def open(self, configuration: str, create: bool = False) -> Optional[int]: - """Open the graph store - - Might be necessary for stores that require opening a connection to a - database or acquiring some resource. - """ - return self.__store.open(configuration, create) - - def close(self, commit_pending_transaction: bool = False) -> None: - """Close the graph store - - Might be necessary for stores that require closing a connection to a - database or releasing some resource. - """ - return self.__store.close(commit_pending_transaction=commit_pending_transaction) - - def add(self: _GraphT, triple: _TripleType) -> _GraphT: - """Add a triple with self as context""" - s, p, o = triple - assert isinstance(s, Node), "Subject %s must be an rdflib term" % (s,) - assert isinstance(p, Node), "Predicate %s must be an rdflib term" % (p,) - assert isinstance(o, Node), "Object %s must be an rdflib term" % (o,) - self.__store.add((s, p, o), self, quoted=False) - return self - - def addN(self: _GraphT, quads: Iterable[_QuadType]) -> _GraphT: # noqa: N802 - """Add a sequence of triple with context""" - - self.__store.addN( - (s, p, o, c) - for s, p, o, c in quads - if isinstance(c, Graph) - and c.identifier is self.identifier - and _assertnode(s, p, o) - ) - return self - - def remove(self: _GraphT, triple: _TriplePatternType) -> _GraphT: - """Remove a triple from the graph - - If the triple does not provide a context attribute, removes the triple - from all contexts. - """ - self.__store.remove(triple, context=self) - return self - - @overload - def triples( - self, - triple: _TriplePatternType, - ) -> Generator[_TripleType, None, None]: ... - - @overload - def triples( - self, - triple: _TriplePathPatternType, - ) -> Generator[_TriplePathType, None, None]: ... - - @overload - def triples( - self, - triple: _TripleSelectorType, - ) -> Generator[_TripleOrTriplePathType, None, None]: ... - - def triples( - self, - triple: _TripleSelectorType, - ) -> Generator[_TripleOrTriplePathType, None, None]: - """Generator over the triple store - - Returns triples that match the given triple pattern. If triple pattern - does not provide a context, all contexts will be searched. - """ - s, p, o = triple - if isinstance(p, Path): - for _s, _o in p.eval(self, s, o): - yield _s, p, _o - else: - for (_s, _p, _o), cg in self.__store.triples((s, p, o), context=self): - yield _s, _p, _o - - def __getitem__(self, item): - """ - A graph can be "sliced" as a shortcut for the triples method - The python slice syntax is (ab)used for specifying triples. - A generator over matches is returned, - the returned tuples include only the parts not given - - >>> import rdflib - >>> g = rdflib.Graph() - >>> g.add((rdflib.URIRef("urn:bob"), namespace.RDFS.label, rdflib.Literal("Bob"))) # doctest: +ELLIPSIS - )> - - >>> list(g[rdflib.URIRef("urn:bob")]) # all triples about bob - [(rdflib.term.URIRef('http://www.w3.org/2000/01/rdf-schema#label'), rdflib.term.Literal('Bob'))] - - >>> list(g[:namespace.RDFS.label]) # all label triples - [(rdflib.term.URIRef('urn:bob'), rdflib.term.Literal('Bob'))] - - >>> list(g[::rdflib.Literal("Bob")]) # all triples with bob as object - [(rdflib.term.URIRef('urn:bob'), rdflib.term.URIRef('http://www.w3.org/2000/01/rdf-schema#label'))] - - Combined with SPARQL paths, more complex queries can be - written concisely: - - Name of all Bobs friends: - - g[bob : FOAF.knows/FOAF.name ] - - Some label for Bob: - - g[bob : DC.title|FOAF.name|RDFS.label] - - All friends and friends of friends of Bob - - g[bob : FOAF.knows * "+"] - - etc. - - .. versionadded:: 4.0 - - """ - - if isinstance(item, slice): - s, p, o = item.start, item.stop, item.step - if s is None and p is None and o is None: - return self.triples((s, p, o)) - elif s is None and p is None: - return self.subject_predicates(o) - elif s is None and o is None: - return self.subject_objects(p) - elif p is None and o is None: - return self.predicate_objects(s) - elif s is None: - return self.subjects(p, o) - elif p is None: - return self.predicates(s, o) - elif o is None: - return self.objects(s, p) - else: - # all given - return (s, p, o) in self - - elif isinstance(item, (Path, Node)): - # type error: Argument 1 to "predicate_objects" of "Graph" has incompatible type "Union[Path, Node]"; expected "Optional[Node]" - return self.predicate_objects(item) # type: ignore[arg-type] - - else: - raise TypeError( - "You can only index a graph by a single rdflib term or path, or a slice of rdflib terms." - ) - - def __len__(self) -> int: - """Returns the number of triples in the graph - - If context is specified then the number of triples in the context is - returned instead. - """ - # type error: Unexpected keyword argument "context" for "__len__" of "Store" - return self.__store.__len__(context=self) # type: ignore[call-arg] - - def __iter__(self) -> Generator[_TripleType, None, None]: - """Iterates over all triples in the store""" - return self.triples((None, None, None)) - - def __contains__(self, triple: _TripleSelectorType) -> bool: - """Support for 'triple in graph' syntax""" - for triple in self.triples(triple): - return True - return False - - def __hash__(self) -> int: - return hash(self.identifier) - - def __cmp__(self, other) -> int: - if other is None: - return -1 - elif isinstance(other, Graph): - return (self.identifier > other.identifier) - ( - self.identifier < other.identifier - ) - else: - # Note if None is considered equivalent to owl:Nothing - # Then perhaps a graph with length 0 should be considered - # equivalent to None (if compared to it)? - return 1 - - def __eq__(self, other) -> bool: - return isinstance(other, Graph) and self.identifier == other.identifier - - def __lt__(self, other) -> bool: - return (other is None) or ( - isinstance(other, Graph) and self.identifier < other.identifier - ) - - def __le__(self, other: Graph) -> bool: - return self < other or self == other - - def __gt__(self, other) -> bool: - return (isinstance(other, Graph) and self.identifier > other.identifier) or ( - other is not None - ) - - def __ge__(self, other: Graph) -> bool: - return self > other or self == other - - def __iadd__(self: _GraphT, other: Iterable[_TripleType]) -> _GraphT: - """Add all triples in Graph other to Graph. - BNode IDs are not changed.""" - self.addN((s, p, o, self) for s, p, o in other) - return self - - def __isub__(self: _GraphT, other: Iterable[_TripleType]) -> _GraphT: - """Subtract all triples in Graph other from Graph. - BNode IDs are not changed.""" - for triple in other: - self.remove(triple) - return self - - def __add__(self, other: Graph) -> Graph: - """Set-theoretic union - BNode IDs are not changed.""" - try: - retval = type(self)() - except TypeError: - retval = Graph() - for prefix, uri in set(list(self.namespaces()) + list(other.namespaces())): - retval.bind(prefix, uri) - for x in self: - retval.add(x) - for y in other: - retval.add(y) - return retval - - def __mul__(self, other: Graph) -> Graph: - """Set-theoretic intersection. - BNode IDs are not changed.""" - try: - retval = type(self)() - except TypeError: - retval = Graph() - for x in other: - if x in self: - retval.add(x) - return retval - - def __sub__(self, other: Graph) -> Graph: - """Set-theoretic difference. - BNode IDs are not changed.""" - try: - retval = type(self)() - except TypeError: - retval = Graph() - for x in self: - if x not in other: - retval.add(x) - return retval - - def __xor__(self, other: Graph) -> Graph: - """Set-theoretic XOR. - BNode IDs are not changed.""" - return (self - other) + (other - self) - - __or__ = __add__ - __and__ = __mul__ - - # Conv. methods - - def set( - self: _GraphT, triple: Tuple[_SubjectType, _PredicateType, _ObjectType] - ) -> _GraphT: - """Convenience method to update the value of object - - Remove any existing triples for subject and predicate before adding - (subject, predicate, object). - """ - (subject, predicate, object_) = triple - assert ( - subject is not None - ), "s can't be None in .set([s,p,o]), as it would remove (*, p, *)" - assert ( - predicate is not None - ), "p can't be None in .set([s,p,o]), as it would remove (s, *, *)" - self.remove((subject, predicate, None)) - self.add((subject, predicate, object_)) - return self - - def subjects( - self, - predicate: Union[None, Path, _PredicateType] = None, - object: Optional[Union[_ObjectType, List[_ObjectType]]] = None, - unique: bool = False, - ) -> Generator[_SubjectType, None, None]: - """A generator of (optionally unique) subjects with the given - predicate and object(s)""" - # if the object is a list of Nodes, yield results from subject() call for each - if isinstance(object, list): - for obj in object: - for s in self.subjects(predicate, obj, unique): - yield s - else: - if not unique: - for s, p, o in self.triples((None, predicate, object)): - yield s - else: - subs = set() - for s, p, o in self.triples((None, predicate, object)): - if s not in subs: - yield s - try: - subs.add(s) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def predicates( - self, - subject: Optional[_SubjectType] = None, - object: Optional[_ObjectType] = None, - unique: bool = False, - ) -> Generator[_PredicateType, None, None]: - """A generator of (optionally unique) predicates with the given - subject and object""" - if not unique: - for s, p, o in self.triples((subject, None, object)): - yield p - else: - preds = set() - for s, p, o in self.triples((subject, None, object)): - if p not in preds: - yield p - try: - preds.add(p) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def objects( - self, - subject: Optional[Union[_SubjectType, List[_SubjectType]]] = None, - predicate: Union[None, Path, _PredicateType] = None, - unique: bool = False, - ) -> Generator[_ObjectType, None, None]: - """A generator of (optionally unique) objects with the given - subject(s) and predicate""" - if isinstance(subject, list): - for subj in subject: - for o in self.objects(subj, predicate, unique): - yield o - else: - if not unique: - for s, p, o in self.triples((subject, predicate, None)): - yield o - else: - objs = set() - for s, p, o in self.triples((subject, predicate, None)): - if o not in objs: - yield o - try: - objs.add(o) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def subject_predicates( - self, object: Optional[_ObjectType] = None, unique: bool = False - ) -> Generator[Tuple[_SubjectType, _PredicateType], None, None]: - """A generator of (optionally unique) (subject, predicate) tuples - for the given object""" - if not unique: - for s, p, o in self.triples((None, None, object)): - yield s, p - else: - subj_preds = set() - for s, p, o in self.triples((None, None, object)): - if (s, p) not in subj_preds: - yield s, p - try: - subj_preds.add((s, p)) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def subject_objects( - self, - predicate: Union[None, Path, _PredicateType] = None, - unique: bool = False, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - """A generator of (optionally unique) (subject, object) tuples - for the given predicate""" - if not unique: - for s, p, o in self.triples((None, predicate, None)): - yield s, o - else: - subj_objs = set() - for s, p, o in self.triples((None, predicate, None)): - if (s, o) not in subj_objs: - yield s, o - try: - subj_objs.add((s, o)) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def predicate_objects( - self, subject: Optional[_SubjectType] = None, unique: bool = False - ) -> Generator[Tuple[_PredicateType, _ObjectType], None, None]: - """A generator of (optionally unique) (predicate, object) tuples - for the given subject""" - if not unique: - for s, p, o in self.triples((subject, None, None)): - yield p, o - else: - pred_objs = set() - for s, p, o in self.triples((subject, None, None)): - if (p, o) not in pred_objs: - yield p, o - try: - pred_objs.add((p, o)) - except MemoryError as e: - logger.error( - f"{e}. Consider not setting parameter 'unique' to True" - ) - raise - - def triples_choices( - self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], - context: Optional[_ContextType] = None, - ) -> Generator[_TripleType, None, None]: - subject, predicate, object_ = triple - # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - # type error note: unpacking discards type info - for (s, p, o), cg in self.store.triples_choices( - (subject, predicate, object_), context=self # type: ignore[arg-type] - ): - yield s, p, o - - @overload - def value( - self, - subject: None = ..., - predicate: None = ..., - object: Optional[_ObjectType] = ..., - default: Optional[Node] = ..., - any: bool = ..., - ) -> None: ... - - @overload - def value( - self, - subject: Optional[_SubjectType] = ..., - predicate: None = ..., - object: None = ..., - default: Optional[Node] = ..., - any: bool = ..., - ) -> None: ... - - @overload - def value( - self, - subject: None = ..., - predicate: Optional[_PredicateType] = ..., - object: None = ..., - default: Optional[Node] = ..., - any: bool = ..., - ) -> None: ... - - @overload - def value( - self, - subject: Optional[_SubjectType] = ..., - predicate: Optional[_PredicateType] = ..., - object: Optional[_ObjectType] = ..., - default: Optional[Node] = ..., - any: bool = ..., - ) -> Optional[Node]: ... - - def value( - self, - subject: Optional[_SubjectType] = None, - predicate: Optional[_PredicateType] = RDF.value, - object: Optional[_ObjectType] = None, - default: Optional[Node] = None, - any: bool = True, - ) -> Optional[Node]: - """Get a value for a pair of two criteria - - Exactly one of subject, predicate, object must be None. Useful if one - knows that there may only be one value. - - It is one of those situations that occur a lot, hence this - 'macro' like utility - - Parameters: - - - subject, predicate, object: exactly one must be None - - default: value to be returned if no values found - - any: if True, return any value in the case there is more than one, - else, raise UniquenessError - """ - retval = default - - if ( - (subject is None and predicate is None) - or (subject is None and object is None) - or (predicate is None and object is None) - ): - return None - - if object is None: - values = self.objects(subject, predicate) - if subject is None: - values = self.subjects(predicate, object) - if predicate is None: - values = self.predicates(subject, object) - - try: - retval = next(values) - except StopIteration: - retval = default - else: - if any is False: - try: - next(values) - msg = ( - "While trying to find a value for (%s, %s, %s) the" - " following multiple values where found:\n" - % (subject, predicate, object) - ) - triples = self.store.triples((subject, predicate, object), None) - for (s, p, o), contexts in triples: - msg += "(%s, %s, %s)\n (contexts: %s)\n" % ( - s, - p, - o, - list(contexts), - ) - raise exceptions.UniquenessError(msg) - except StopIteration: - pass - return retval - - def items(self, list: Node) -> Generator[Node, None, None]: - """Generator over all items in the resource specified by list - - list is an RDF collection. - """ - chain = set([list]) - while list: - item = self.value(list, RDF.first) - if item is not None: - yield item - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Node") - list = self.value(list, RDF.rest) # type: ignore[assignment] - if list in chain: - raise ValueError("List contains a recursive rdf:rest reference") - chain.add(list) - - def transitiveClosure( # noqa: N802 - self, - func: Callable[[_TCArgT, Graph], Iterable[_TCArgT]], - arg: _TCArgT, - seen: Optional[Dict[_TCArgT, int]] = None, - ): - """ - Generates transitive closure of a user-defined - function against the graph - - >>> from rdflib.collection import Collection - >>> g = Graph() - >>> a = BNode("foo") - >>> b = BNode("bar") - >>> c = BNode("baz") - >>> g.add((a,RDF.first,RDF.type)) # doctest: +ELLIPSIS - )> - >>> g.add((a,RDF.rest,b)) # doctest: +ELLIPSIS - )> - >>> g.add((b,RDF.first,namespace.RDFS.label)) # doctest: +ELLIPSIS - )> - >>> g.add((b,RDF.rest,c)) # doctest: +ELLIPSIS - )> - >>> g.add((c,RDF.first,namespace.RDFS.comment)) # doctest: +ELLIPSIS - )> - >>> g.add((c,RDF.rest,RDF.nil)) # doctest: +ELLIPSIS - )> - >>> def topList(node,g): - ... for s in g.subjects(RDF.rest, node): - ... yield s - >>> def reverseList(node,g): - ... for f in g.objects(node, RDF.first): - ... print(f) - ... for s in g.subjects(RDF.rest, node): - ... yield s - - >>> [rt for rt in g.transitiveClosure( - ... topList,RDF.nil)] # doctest: +NORMALIZE_WHITESPACE - [rdflib.term.BNode('baz'), - rdflib.term.BNode('bar'), - rdflib.term.BNode('foo')] - - >>> [rt for rt in g.transitiveClosure( - ... reverseList,RDF.nil)] # doctest: +NORMALIZE_WHITESPACE - http://www.w3.org/2000/01/rdf-schema#comment - http://www.w3.org/2000/01/rdf-schema#label - http://www.w3.org/1999/02/22-rdf-syntax-ns#type - [rdflib.term.BNode('baz'), - rdflib.term.BNode('bar'), - rdflib.term.BNode('foo')] - - """ - if seen is None: - seen = {} - elif arg in seen: - return - seen[arg] = 1 - for rt in func(arg, self): - yield rt - for rt_2 in self.transitiveClosure(func, rt, seen): - yield rt_2 - - def transitive_objects( - self, - subject: Optional[_SubjectType], - predicate: Optional[_PredicateType], - remember: Optional[Dict[Optional[_SubjectType], int]] = None, - ) -> Generator[Optional[_SubjectType], None, None]: - """Transitively generate objects for the ``predicate`` relationship - - Generated objects belong to the depth first transitive closure of the - ``predicate`` relationship starting at ``subject``. - """ - if remember is None: - remember = {} - if subject in remember: - return - remember[subject] = 1 - yield subject - for object in self.objects(subject, predicate): - for o in self.transitive_objects(object, predicate, remember): - yield o - - def transitive_subjects( - self, - predicate: Optional[_PredicateType], - object: Optional[_ObjectType], - remember: Optional[Dict[Optional[_ObjectType], int]] = None, - ) -> Generator[Optional[_ObjectType], None, None]: - """Transitively generate subjects for the ``predicate`` relationship - - Generated subjects belong to the depth first transitive closure of the - ``predicate`` relationship starting at ``object``. - """ - if remember is None: - remember = {} - if object in remember: - return - remember[object] = 1 - yield object - for subject in self.subjects(predicate, object): - for s in self.transitive_subjects(predicate, subject, remember): - yield s - - def qname(self, uri: str) -> str: - return self.namespace_manager.qname(uri) - - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: - return self.namespace_manager.compute_qname(uri, generate) - - def bind( - self, - prefix: Optional[str], - namespace: Any, # noqa: F811 - override: bool = True, - replace: bool = False, - ) -> None: - """Bind prefix to namespace - - If override is True will bind namespace to given prefix even - if namespace was already bound to a different prefix. - - if replace, replace any existing prefix with the new namespace - - for example: graph.bind("foaf", "http://xmlns.com/foaf/0.1/") - - """ - # TODO FIXME: This method's behaviour should be simplified and made - # more robust. If the method cannot do what it is asked it should raise - # an exception, it is also unclear why this method has all the - # different modes. It seems to just make it more complex to use, maybe - # it should be clarified when someone will need to use override=False - # and replace=False. And also why silent failure here is preferred over - # raising an exception. - return self.namespace_manager.bind( - prefix, namespace, override=override, replace=replace - ) - - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: - """Generator over all the prefix, namespace tuples""" - for prefix, namespace in self.namespace_manager.namespaces(): # noqa: F402 - yield prefix, namespace - - def absolutize(self, uri: str, defrag: int = 1) -> URIRef: - """Turn uri into an absolute URI if it's not one already""" - return self.namespace_manager.absolutize(uri, defrag) - - # no destination and non-None positional encoding - @overload - def serialize( - self, - destination: None, - format: str, - base: Optional[str], - encoding: str, - **args: Any, - ) -> bytes: ... - - # no destination and non-None keyword encoding - @overload - def serialize( - self, - destination: None = ..., - format: str = ..., - base: Optional[str] = ..., - *, - encoding: str, - **args: Any, - ) -> bytes: ... - - # no destination and None encoding - @overload - def serialize( - self, - destination: None = ..., - format: str = ..., - base: Optional[str] = ..., - encoding: None = ..., - **args: Any, - ) -> str: ... - - # non-None destination - @overload - def serialize( - self, - destination: Union[str, pathlib.PurePath, IO[bytes]], - format: str = ..., - base: Optional[str] = ..., - encoding: Optional[str] = ..., - **args: Any, - ) -> Graph: ... - - # fallback - @overload - def serialize( - self, - destination: Optional[Union[str, pathlib.PurePath, IO[bytes]]] = ..., - format: str = ..., - base: Optional[str] = ..., - encoding: Optional[str] = ..., - **args: Any, - ) -> Union[bytes, str, Graph]: ... - - def serialize( - self: _GraphT, - destination: Optional[Union[str, pathlib.PurePath, IO[bytes]]] = None, - format: str = "turtle", - base: Optional[str] = None, - encoding: Optional[str] = None, - **args: Any, - ) -> Union[bytes, str, _GraphT]: - """ - Serialize the graph. - - :param destination: - The destination to serialize the graph to. This can be a path as a - :class:`str` or :class:`~pathlib.PurePath` object, or it can be a - :class:`~typing.IO` ``[bytes]`` like object. If this parameter is not - supplied the serialized graph will be returned. - :param format: - The format that the output should be written in. This value - references a :class:`~rdflib.serializer.Serializer` plugin. Format - support can be extended with plugins, but ``"xml"``, ``"n3"``, - ``"turtle"``, ``"nt"``, ``"pretty-xml"``, ``"trix"``, ``"trig"``, - ``"nquads"``, ``"json-ld"`` and ``"hext"`` are built in. Defaults to - ``"turtle"``. - :param base: - The base IRI for formats that support it. For the turtle format this - will be used as the ``@base`` directive. - :param encoding: Encoding of output. - :param args: - Additional arguments to pass to the - :class:`~rdflib.serializer.Serializer` that will be used. - :return: The serialized graph if ``destination`` is `None`. The - serialized graph is returned as `str` if no encoding is specified, - and as `bytes` if an encoding is specified. - :rtype: :class:`bytes` if ``destination`` is `None` and ``encoding`` is not `None`. - :rtype: :class:`str` if ``destination`` is `None` and ``encoding`` is `None`. - :return: ``self`` (i.e. the :class:`~rdflib.graph.Graph` instance) if - ``destination`` is not `None`. - :rtype: :class:`~rdflib.graph.Graph` if ``destination`` is not `None`. - """ - - # if base is not given as attribute use the base set for the graph - if base is None: - base = self.base - - serializer = plugin.get(format, Serializer)(self) - stream: IO[bytes] - if destination is None: - stream = BytesIO() - if encoding is None: - serializer.serialize(stream, base=base, encoding="utf-8", **args) - return stream.getvalue().decode("utf-8") - else: - serializer.serialize(stream, base=base, encoding=encoding, **args) - return stream.getvalue() - if hasattr(destination, "write"): - stream = cast(IO[bytes], destination) - serializer.serialize(stream, base=base, encoding=encoding, **args) - else: - if isinstance(destination, pathlib.PurePath): - os_path = str(destination) - else: - location = cast(str, destination) - scheme, netloc, path, params, _query, fragment = urlparse(location) - if scheme == "file": - if netloc != "": - raise ValueError( - f"the file URI {location!r} has an authority component which is not supported" - ) - os_path = url2pathname(path) - else: - os_path = location - with open(os_path, "wb") as stream: - serializer.serialize(stream, base=base, encoding=encoding, **args) - return self - - def print( - self, - format: str = "turtle", - encoding: str = "utf-8", - out: Optional[TextIO] = None, - ) -> None: - print( - self.serialize(None, format=format, encoding=encoding).decode(encoding), - file=out, - flush=True, - ) - - def parse( - self, - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ] = None, - publicID: Optional[str] = None, # noqa: N803 - format: Optional[str] = None, - location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, - **args: Any, - ) -> Graph: - """ - Parse an RDF source adding the resulting triples to the Graph. - - The source is specified using one of source, location, file or data. - - .. caution:: - - This method can access directly or indirectly requested network or - file resources, for example, when parsing JSON-LD documents with - ``@context`` directives that point to a network location. - - When processing untrusted or potentially malicious documents, - measures should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - - :param source: An `xml.sax.xmlreader.InputSource`, file-like object, - `pathlib.Path` like object, or string. In the case of a string the string - is the location of the source. - :param location: A string indicating the relative or absolute URL of the - source. `Graph`'s absolutize method is used if a relative location - is specified. - :param file: A file-like object. - :param data: A string containing the data to be parsed. - :param format: Used if format can not be determined from source, e.g. - file extension or Media Type. Defaults to text/turtle. Format - support can be extended with plugins, but "xml", "n3" (use for - turtle), "nt" & "trix" are built in. - :param publicID: the logical URI to use as the document base. If None - specified the document location is used (at least in the case where - there is a document location). This is used as the base URI when - resolving relative URIs in the source document, as defined in `IETF - RFC 3986 - `_, - given the source document does not define a base URI. - :return: ``self``, i.e. the :class:`~rdflib.graph.Graph` instance. - - Examples: - - >>> my_data = ''' - ... - ... - ... Example - ... This is really just an example. - ... - ... - ... ''' - >>> import os, tempfile - >>> fd, file_name = tempfile.mkstemp() - >>> f = os.fdopen(fd, "w") - >>> dummy = f.write(my_data) # Returns num bytes written - >>> f.close() - - >>> g = Graph() - >>> result = g.parse(data=my_data, format="application/rdf+xml") - >>> len(g) - 2 - - >>> g = Graph() - >>> result = g.parse(location=file_name, format="application/rdf+xml") - >>> len(g) - 2 - - >>> g = Graph() - >>> with open(file_name, "r") as f: - ... result = g.parse(f, format="application/rdf+xml") - >>> len(g) - 2 - - >>> os.remove(file_name) - - >>> # default turtle parsing - >>> result = g.parse(data=" .") - >>> len(g) - 3 - - """ - - source = create_input_source( - source=source, - publicID=publicID, - location=location, - file=file, - data=data, - format=format, - ) - if format is None: - format = source.content_type - could_not_guess_format = False - if format is None: - if ( - hasattr(source, "file") - and getattr(source.file, "name", None) - and isinstance(source.file.name, str) - ): - format = rdflib.util.guess_format(source.file.name) - if format is None: - format = "turtle" - could_not_guess_format = True - try: - parser = plugin.get(format, Parser)() - except plugin.PluginException: - # Handle the case when a URLInputSource returns RDF but with the headers - # as a format that does not exist in the plugin system. - # Use guess_format to guess the format based on the input's file suffix. - format = rdflib.util.guess_format( - source if not isinstance(source, InputSource) else str(source) - ) - if format is None: - raise - parser = plugin.get(format, Parser)() - try: - # TODO FIXME: Parser.parse should have **kwargs argument. - parser.parse(source, self, **args) - except SyntaxError as se: - if could_not_guess_format: - raise ParserError( - "Could not guess RDF format for %r from file extension so tried Turtle but failed." - "You can explicitly specify format using the format argument." - % source - ) - else: - raise se - finally: - if source.auto_close: - source.close() - return self - - def query( - self, - query_object: Union[str, Query], - processor: Union[str, query.Processor] = "sparql", - result: Union[str, Type[query.Result]] = "sparql", - initNs: Optional[Mapping[str, Any]] = None, # noqa: N803 - initBindings: Optional[Mapping[str, Identifier]] = None, # noqa: N803 - use_store_provided: bool = True, - **kwargs: Any, - ) -> query.Result: - """ - Query this graph. - - A type of 'prepared queries' can be realised by providing initial - variable bindings with initBindings - - Initial namespaces are used to resolve prefixes used in the query, if - none are given, the namespaces from the graph's namespace manager are - used. - - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - - :returntype: :class:`~rdflib.query.Result` - - """ - - initBindings = initBindings or {} # noqa: N806 - initNs = initNs or dict(self.namespaces()) # noqa: N806 - - if self.default_union: - query_graph = "__UNION__" - elif isinstance(self, ConjunctiveGraph): - query_graph = self.default_context.identifier - else: - query_graph = self.identifier - if hasattr(self.store, "query") and use_store_provided: - try: - return self.store.query( - query_object, - initNs, - initBindings, - query_graph, - **kwargs, - ) - except NotImplementedError: - pass # store has no own implementation - - if not isinstance(result, query.Result): - result = plugin.get(cast(str, result), query.Result) - if not isinstance(processor, query.Processor): - processor = plugin.get(processor, query.Processor)(self) - - # type error: Argument 1 to "Result" has incompatible type "Mapping[str, Any]"; expected "str" - return result(processor.query(query_object, initBindings, initNs, **kwargs)) # type: ignore[arg-type] - - def update( - self, - update_object: Union[Update, str], - processor: Union[str, rdflib.query.UpdateProcessor] = "sparql", - initNs: Optional[Mapping[str, Any]] = None, # noqa: N803 - initBindings: Optional[Mapping[str, Identifier]] = None, # noqa: N803 - use_store_provided: bool = True, - **kwargs: Any, - ) -> None: - """ - Update this graph with the given update query. - - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - """ - initBindings = initBindings or {} # noqa: N806 - initNs = initNs or dict(self.namespaces()) # noqa: N806 - - if self.default_union: - query_graph = "__UNION__" - elif isinstance(self, ConjunctiveGraph): - query_graph = self.default_context.identifier - else: - query_graph = self.identifier - - if hasattr(self.store, "update") and use_store_provided: - try: - return self.store.update( - update_object, - initNs, - initBindings, - query_graph, - **kwargs, - ) - except NotImplementedError: - pass # store has no own implementation - - if not isinstance(processor, query.UpdateProcessor): - processor = plugin.get(processor, query.UpdateProcessor)(self) - - return processor.update(update_object, initBindings, initNs, **kwargs) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - """Return an n3 identifier for the Graph""" - return "[%s]" % self.identifier.n3(namespace_manager=namespace_manager) - - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: - return ( - Graph, - ( - self.store, - self.identifier, - ), - ) - - def isomorphic(self, other: Graph) -> bool: - """ - does a very basic check if these graphs are the same - If no BNodes are involved, this is accurate. - - See rdflib.compare for a correct implementation of isomorphism checks - """ - # TODO: this is only an approximation. - if len(self) != len(other): - return False - for s, p, o in self: - if not isinstance(s, BNode) and not isinstance(o, BNode): - if not (s, p, o) in other: # noqa: E713 - return False - for s, p, o in other: - if not isinstance(s, BNode) and not isinstance(o, BNode): - if not (s, p, o) in self: # noqa: E713 - return False - # TODO: very well could be a false positive at this point yet. - return True - - def connected(self) -> bool: - """Check if the Graph is connected - - The Graph is considered undirectional. - - Performs a search on the Graph, starting from a random node. Then - iteratively goes depth-first through the triplets where the node is - subject and object. Return True if all nodes have been visited and - False if it cannot continue and there are still unvisited nodes left. - """ - all_nodes = list(self.all_nodes()) - discovered = [] - - # take a random one, could also always take the first one, doesn't - # really matter. - if not all_nodes: - return False - - visiting = [all_nodes[random.randrange(len(all_nodes))]] - while visiting: - x = visiting.pop() - if x not in discovered: - discovered.append(x) - for new_x in self.objects(subject=x): - if new_x not in discovered and new_x not in visiting: - visiting.append(new_x) - for new_x in self.subjects(object=x): - if new_x not in discovered and new_x not in visiting: - visiting.append(new_x) - - # optimisation by only considering length, since no new objects can - # be introduced anywhere. - if len(all_nodes) == len(discovered): - return True - else: - return False - - def all_nodes(self) -> Set[Node]: - res = set(self.objects()) - res.update(self.subjects()) - return res - - def collection(self, identifier: _SubjectType) -> Collection: - """Create a new ``Collection`` instance. - - Parameters: - - - ``identifier``: a URIRef or BNode instance. - - Example:: - - >>> graph = Graph() - >>> uri = URIRef("http://example.org/resource") - >>> collection = graph.collection(uri) - >>> assert isinstance(collection, Collection) - >>> assert collection.uri is uri - >>> assert collection.graph is graph - >>> collection += [ Literal(1), Literal(2) ] - """ - - return Collection(self, identifier) - - def resource(self, identifier: Union[Node, str]) -> Resource: - """Create a new ``Resource`` instance. - - Parameters: - - - ``identifier``: a URIRef or BNode instance. - - Example:: - - >>> graph = Graph() - >>> uri = URIRef("http://example.org/resource") - >>> resource = graph.resource(uri) - >>> assert isinstance(resource, Resource) - >>> assert resource.identifier is uri - >>> assert resource.graph is graph - - """ - if not isinstance(identifier, Node): - identifier = URIRef(identifier) - return Resource(self, identifier) - - def _process_skolem_tuples( - self, target: Graph, func: Callable[[_TripleType], _TripleType] - ) -> None: - for t in self.triples((None, None, None)): - target.add(func(t)) - - def skolemize( - self, - new_graph: Optional[Graph] = None, - bnode: Optional[BNode] = None, - authority: Optional[str] = None, - basepath: Optional[str] = None, - ) -> Graph: - def do_skolemize(bnode: BNode, t: _TripleType) -> _TripleType: - (s, p, o) = t - if s == bnode: - if TYPE_CHECKING: - assert isinstance(s, BNode) - s = s.skolemize(authority=authority, basepath=basepath) - if o == bnode: - if TYPE_CHECKING: - assert isinstance(o, BNode) - o = o.skolemize(authority=authority, basepath=basepath) - return s, p, o - - def do_skolemize2(t: _TripleType) -> _TripleType: - (s, p, o) = t - if isinstance(s, BNode): - s = s.skolemize(authority=authority, basepath=basepath) - if isinstance(o, BNode): - o = o.skolemize(authority=authority, basepath=basepath) - return s, p, o - - retval = Graph() if new_graph is None else new_graph - - if bnode is None: - self._process_skolem_tuples(retval, do_skolemize2) - elif isinstance(bnode, BNode): - # type error: Argument 1 to "do_skolemize" has incompatible type "Optional[BNode]"; expected "BNode" - self._process_skolem_tuples(retval, lambda t: do_skolemize(bnode, t)) # type: ignore[arg-type, unused-ignore] - - return retval - - def de_skolemize( - self, new_graph: Optional[Graph] = None, uriref: Optional[URIRef] = None - ) -> Graph: - def do_de_skolemize(uriref: URIRef, t: _TripleType) -> _TripleType: - (s, p, o) = t - if s == uriref: - if TYPE_CHECKING: - assert isinstance(s, URIRef) - s = s.de_skolemize() - if o == uriref: - if TYPE_CHECKING: - assert isinstance(o, URIRef) - o = o.de_skolemize() - return s, p, o - - def do_de_skolemize2(t: _TripleType) -> _TripleType: - (s, p, o) = t - - if RDFLibGenid._is_rdflib_skolem(s): - # type error: Argument 1 to "RDFLibGenid" has incompatible type "Node"; expected "str" - s = RDFLibGenid(s).de_skolemize() # type: ignore[arg-type] - elif Genid._is_external_skolem(s): - # type error: Argument 1 to "Genid" has incompatible type "Node"; expected "str" - s = Genid(s).de_skolemize() # type: ignore[arg-type] - - if RDFLibGenid._is_rdflib_skolem(o): - # type error: Argument 1 to "RDFLibGenid" has incompatible type "Node"; expected "str" - o = RDFLibGenid(o).de_skolemize() # type: ignore[arg-type] - elif Genid._is_external_skolem(o): - # type error: Argument 1 to "Genid" has incompatible type "Node"; expected "str" - o = Genid(o).de_skolemize() # type: ignore[arg-type] - - return s, p, o - - retval = Graph() if new_graph is None else new_graph - - if uriref is None: - self._process_skolem_tuples(retval, do_de_skolemize2) - elif isinstance(uriref, Genid): - # type error: Argument 1 to "do_de_skolemize" has incompatible type "Optional[URIRef]"; expected "URIRef" - self._process_skolem_tuples(retval, lambda t: do_de_skolemize(uriref, t)) # type: ignore[arg-type, unused-ignore] - - return retval - - def cbd( - self, resource: _SubjectType, *, target_graph: Optional[Graph] = None - ) -> Graph: - """Retrieves the Concise Bounded Description of a Resource from a Graph - - Concise Bounded Description (CBD) is defined in [1] as: - - Given a particular node (the starting node) in a particular RDF graph (the source graph), a subgraph of that - particular graph, taken to comprise a concise bounded description of the resource denoted by the starting node, - can be identified as follows: - - 1. Include in the subgraph all statements in the source graph where the subject of the statement is the - starting node; - - 2. Recursively, for all statements identified in the subgraph thus far having a blank node object, include - in the subgraph all statements in the source graph where the subject of the statement is the blank node - in question and which are not already included in the subgraph. - - 3. Recursively, for all statements included in the subgraph thus far, for all reifications of each statement - in the source graph, include the concise bounded description beginning from the rdf:Statement node of - each reification. - - This results in a subgraph where the object nodes are either URI references, literals, or blank nodes not - serving as the subject of any statement in the graph. - - [1] https://www.w3.org/Submission/CBD/ - - :param resource: a URIRef object, of the Resource for queried for - :param target_graph: Optionally, a graph to add the CBD to; otherwise, a new graph is created for the CBD - :return: a Graph, subgraph of self if no graph was provided otherwise the provided graph - - """ - if target_graph is None: - subgraph = Graph() - else: - subgraph = target_graph - - def add_to_cbd(uri: _SubjectType) -> None: - for s, p, o in self.triples((uri, None, None)): - subgraph.add((s, p, o)) - # recurse 'down' through ll Blank Nodes - if type(o) is BNode and (o, None, None) not in subgraph: - add_to_cbd(o) - - # for Rule 3 (reification) - # for any rdf:Statement in the graph with the given URI as the object of rdf:subject, - # get all triples with that rdf:Statement instance as subject - - # find any subject s where the predicate is rdf:subject and this uri is the object - # (these subjects are of type rdf:Statement, given the domain of rdf:subject) - for s, p, o in self.triples((None, RDF.subject, uri)): - # find all triples with s as the subject and add these to the subgraph - for s2, p2, o2 in self.triples((s, None, None)): - subgraph.add((s2, p2, o2)) - - add_to_cbd(resource) - - return subgraph - - -_ContextType = Graph - - -class ConjunctiveGraph(Graph): - """A ConjunctiveGraph is an (unnamed) aggregation of all the named - graphs in a store. - - .. warning:: - ConjunctiveGraph is deprecated, use :class:`~rdflib.graph.Dataset` instead. - - It has a ``default`` graph, whose name is associated with the - graph throughout its life. :meth:`__init__` can take an identifier - to use as the name of this default graph or it will assign a - BNode. - - All methods that add triples work against this default graph. - - All queries are carried out against the union of all graphs. - """ - - default_context: _ContextType - - def __init__( - self, - store: Union[Store, str] = "default", - identifier: Optional[Union[IdentifiedNode, str]] = None, - default_graph_base: Optional[str] = None, - ): - super(ConjunctiveGraph, self).__init__(store, identifier=identifier) - - if type(self) is ConjunctiveGraph: - warnings.warn( - "ConjunctiveGraph is deprecated, use Dataset instead.", - DeprecationWarning, - stacklevel=2, - ) - - assert self.store.context_aware, ( - "ConjunctiveGraph must be backed by" " a context aware store." - ) - self.context_aware = True - self.default_union = True # Conjunctive! - self.default_context: _ContextType = Graph( - store=self.store, identifier=identifier or BNode(), base=default_graph_base - ) - - def __str__(self) -> str: - pattern = ( - "[a rdflib:ConjunctiveGraph;rdflib:storage " - "[a rdflib:Store;rdfs:label '%s']]" - ) - return pattern % self.store.__class__.__name__ - - @overload - def _spoc( - self, - triple_or_quad: _QuadType, - default: bool = False, - ) -> _QuadType: ... - - @overload - def _spoc( - self, - triple_or_quad: Union[_TripleType, _OptionalQuadType], - default: bool = False, - ) -> _OptionalQuadType: ... - - @overload - def _spoc( - self, - triple_or_quad: None, - default: bool = False, - ) -> Tuple[None, None, None, Optional[Graph]]: ... - - @overload - def _spoc( - self, - triple_or_quad: Optional[_TripleOrQuadPatternType], - default: bool = False, - ) -> _QuadPatternType: ... - - @overload - def _spoc( - self, - triple_or_quad: _TripleOrQuadSelectorType, - default: bool = False, - ) -> _QuadSelectorType: ... - - @overload - def _spoc( - self, - triple_or_quad: Optional[_TripleOrQuadSelectorType], - default: bool = False, - ) -> _QuadSelectorType: ... - - def _spoc( - self, - triple_or_quad: Optional[_TripleOrQuadSelectorType], - default: bool = False, - ) -> _QuadSelectorType: - """ - helper method for having methods that support - either triples or quads - """ - if triple_or_quad is None: - return (None, None, None, self.default_context if default else None) - if len(triple_or_quad) == 3: - c = self.default_context if default else None - # type error: Too many values to unpack (3 expected, 4 provided) - (s, p, o) = triple_or_quad # type: ignore[misc, unused-ignore] - elif len(triple_or_quad) == 4: - # type error: Need more than 3 values to unpack (4 expected) - (s, p, o, c) = triple_or_quad # type: ignore[misc, unused-ignore] - c = self._graph(c) - return s, p, o, c - - def __contains__(self, triple_or_quad: _TripleOrQuadSelectorType) -> bool: - """Support for 'triple/quad in graph' syntax""" - s, p, o, c = self._spoc(triple_or_quad) - for t in self.triples((s, p, o), context=c): - return True - return False - - def add( - self: _ConjunctiveGraphT, - triple_or_quad: _TripleOrOptionalQuadType, - ) -> _ConjunctiveGraphT: - """ - Add a triple or quad to the store. - - if a triple is given it is added to the default context - """ - - s, p, o, c = self._spoc(triple_or_quad, default=True) - - _assertnode(s, p, o) - - # type error: Argument "context" to "add" of "Store" has incompatible type "Optional[Graph]"; expected "Graph" - self.store.add((s, p, o), context=c, quoted=False) # type: ignore[arg-type] - return self - - @overload - def _graph(self, c: Union[Graph, _ContextIdentifierType, str]) -> Graph: ... - - @overload - def _graph(self, c: None) -> None: ... - - def _graph( - self, c: Optional[Union[Graph, _ContextIdentifierType, str]] - ) -> Optional[Graph]: - if c is None: - return None - if not isinstance(c, Graph): - return self.get_context(c) - else: - return c - - def addN( # noqa: N802 - self: _ConjunctiveGraphT, quads: Iterable[_QuadType] - ) -> _ConjunctiveGraphT: - """Add a sequence of triples with context""" - - self.store.addN( - (s, p, o, self._graph(c)) for s, p, o, c in quads if _assertnode(s, p, o) - ) - return self - - # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "Tuple[Optional[Node], Optional[Node], Optional[Node]]" - def remove(self: _ConjunctiveGraphT, triple_or_quad: _TripleOrOptionalQuadType) -> _ConjunctiveGraphT: # type: ignore[override] - """ - Removes a triple or quads - - if a triple is given it is removed from all contexts - - a quad is removed from the given context only - - """ - s, p, o, c = self._spoc(triple_or_quad) - - self.store.remove((s, p, o), context=c) - return self - - @overload - def triples( - self, - triple_or_quad: _TripleOrQuadPatternType, - context: Optional[_ContextType] = ..., - ) -> Generator[_TripleType, None, None]: ... - - @overload - def triples( - self, - triple_or_quad: _TripleOrQuadPathPatternType, - context: Optional[_ContextType] = ..., - ) -> Generator[_TriplePathType, None, None]: ... - - @overload - def triples( - self, - triple_or_quad: _TripleOrQuadSelectorType, - context: Optional[_ContextType] = ..., - ) -> Generator[_TripleOrTriplePathType, None, None]: ... - - def triples( - self, - triple_or_quad: _TripleOrQuadSelectorType, - context: Optional[_ContextType] = None, - ) -> Generator[_TripleOrTriplePathType, None, None]: - """ - Iterate over all the triples in the entire conjunctive graph - - For legacy reasons, this can take the context to query either - as a fourth element of the quad, or as the explicit context - keyword parameter. The kw param takes precedence. - """ - - s, p, o, c = self._spoc(triple_or_quad) - context = self._graph(context or c) - - if self.default_union: - if context == self.default_context: - context = None - else: - if context is None: - context = self.default_context - - if isinstance(p, Path): - if context is None: - context = self - - for s, o in p.eval(context, s, o): - yield s, p, o - else: - for (s, p, o), cg in self.store.triples((s, p, o), context=context): - yield s, p, o - - def quads( - self, triple_or_quad: Optional[_TripleOrQuadPatternType] = None - ) -> Generator[_OptionalQuadType, None, None]: - """Iterate over all the quads in the entire conjunctive graph""" - - s, p, o, c = self._spoc(triple_or_quad) - - for (s, p, o), cg in self.store.triples((s, p, o), context=c): - for ctx in cg: - yield s, p, o, ctx - - def triples_choices( - self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], - context: Optional[_ContextType] = None, - ) -> Generator[_TripleType, None, None]: - """Iterate over all the triples in the entire conjunctive graph""" - s, p, o = triple - if context is None: - if not self.default_union: - context = self.default_context - else: - context = self._graph(context) - # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - # type error note: unpacking discards type info - for (s1, p1, o1), cg in self.store.triples_choices((s, p, o), context=context): # type: ignore[arg-type] - yield s1, p1, o1 - - def __len__(self) -> int: - """Number of triples in the entire conjunctive graph""" - return self.store.__len__() - - def contexts( - self, triple: Optional[_TripleType] = None - ) -> Generator[_ContextType, None, None]: - """Iterate over all contexts in the graph - - If triple is specified, iterate over all contexts the triple is in. - """ - for context in self.store.contexts(triple): - if isinstance(context, Graph): - # TODO: One of these should never happen and probably - # should raise an exception rather than smoothing over - # the weirdness - see #225 - yield context - else: - # type error: Statement is unreachable - yield self.get_context(context) # type: ignore[unreachable] - - def get_graph(self, identifier: _ContextIdentifierType) -> Union[Graph, None]: - """Returns the graph identified by given identifier""" - return [x for x in self.contexts() if x.identifier == identifier][0] - - def get_context( - self, - identifier: Optional[Union[_ContextIdentifierType, str]], - quoted: bool = False, - base: Optional[str] = None, - ) -> Graph: - """Return a context graph for the given identifier - - identifier must be a URIRef or BNode. - """ - return Graph( - store=self.store, - identifier=identifier, - namespace_manager=self.namespace_manager, - base=base, - ) - - def remove_context(self, context: _ContextType) -> None: - """Removes the given context from the graph""" - self.store.remove((None, None, None), context) - - def context_id(self, uri: str, context_id: Optional[str] = None) -> URIRef: - """URI#context""" - uri = uri.split("#", 1)[0] - if context_id is None: - context_id = "#context" - return URIRef(context_id, base=uri) - - def parse( - self, - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ] = None, - publicID: Optional[str] = None, # noqa: N803 - format: Optional[str] = None, - location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, - **args: Any, - ) -> Graph: - """ - Parse source adding the resulting triples to its own context (sub graph - of this graph). - - See :meth:`rdflib.graph.Graph.parse` for documentation on arguments. - - If the source is in a format that does not support named graphs its triples - will be added to the default graph - (i.e. :attr:`ConjunctiveGraph.default_context`). - - :Returns: - - The graph into which the source was parsed. In the case of n3 it returns - the root context. - - .. caution:: - - This method can access directly or indirectly requested network or - file resources, for example, when parsing JSON-LD documents with - ``@context`` directives that point to a network location. - - When processing untrusted or potentially malicious documents, - measures should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - - *Changed in 7.0*: The ``publicID`` argument is no longer used as the - identifier (i.e. name) of the default graph as was the case before - version 7.0. In the case of sources that do not support named graphs, - the ``publicID`` parameter will also not be used as the name for the - graph that the data is loaded into, and instead the triples from sources - that do not support named graphs will be loaded into the default graph - (i.e. :attr:`ConjunctiveGraph.default_context`). - """ - - source = create_input_source( - source=source, - publicID=publicID, - location=location, - file=file, - data=data, - format=format, - ) - - # NOTE on type hint: `xml.sax.xmlreader.InputSource.getPublicId` has no - # type annotations but given that systemId should be a string, and - # given that there is no specific mention of type for publicId, it - # seems reasonable to assume it should also be a string. Furthermore, - # create_input_source will ensure that publicId is not None, though it - # would be good if this guarantee was made more explicit i.e. by type - # hint on InputSource (TODO/FIXME). - - context = self.default_context - context.parse(source, publicID=publicID, format=format, **args) - # TODO: FIXME: This should not return context, but self. - return context - - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: - return ConjunctiveGraph, (self.store, self.identifier) - - -DATASET_DEFAULT_GRAPH_ID = URIRef("urn:x-rdflib:default") - - -class Dataset(ConjunctiveGraph): - """ - An RDFLib Dataset is an object that stores multiple Named Graphs - instances of - RDFLib Graph identified by IRI - within it and allows whole-of-dataset or single - Graph use. - - RDFLib's Dataset class is based on the `RDF 1.2. 'Dataset' definition - `_: - - .. - - An RDF dataset is a collection of RDF graphs, and comprises: - - - Exactly one default graph, being an RDF graph. The default graph does not - have a name and MAY be empty. - - Zero or more named graphs. Each named graph is a pair consisting of an IRI or - a blank node (the graph name), and an RDF graph. Graph names are unique - within an RDF dataset. - - Accordingly, a Dataset allows for `Graph` objects to be added to it with - :class:`rdflib.term.URIRef` or :class:`rdflib.term.BNode` identifiers and always - creats a default graph with the :class:`rdflib.term.URIRef` identifier - :code:`urn:x-rdflib:default`. - - Dataset extends Graph's Subject, Predicate, Object (s, p, o) 'triple' - structure to include a graph identifier - archaically called Context - producing - 'quads' of s, p, o, g. - - Triples, or quads, can be added to a Dataset. Triples, or quads with the graph - identifer :code:`urn:x-rdflib:default` go into the default graph. - - .. note:: Dataset builds on the `ConjunctiveGraph` class but that class's direct - use is now deprecated (since RDFLib 7.x) and it should not be used. - `ConjunctiveGraph` will be removed from future RDFLib versions. - - Examples of usage and see also the examples/datast.py file: - - >>> # Create a new Dataset - >>> ds = Dataset() - >>> # simple triples goes to default graph - >>> ds.add(( - ... URIRef("http://example.org/a"), - ... URIRef("http://www.example.org/b"), - ... Literal("foo") - ... )) # doctest: +ELLIPSIS - )> - >>> - >>> # Create a graph in the dataset, if the graph name has already been - >>> # used, the corresponding graph will be returned - >>> # (ie, the Dataset keeps track of the constituent graphs) - >>> g = ds.graph(URIRef("http://www.example.com/gr")) - >>> - >>> # add triples to the new graph as usual - >>> g.add(( - ... URIRef("http://example.org/x"), - ... URIRef("http://example.org/y"), - ... Literal("bar") - ... )) # doctest: +ELLIPSIS - )> - >>> # alternatively: add a quad to the dataset -> goes to the graph - >>> ds.add(( - ... URIRef("http://example.org/x"), - ... URIRef("http://example.org/z"), - ... Literal("foo-bar"), - ... g - ... )) # doctest: +ELLIPSIS - )> - >>> - >>> # querying triples return them all regardless of the graph - >>> for t in ds.triples((None,None,None)): # doctest: +SKIP - ... print(t) # doctest: +NORMALIZE_WHITESPACE - (rdflib.term.URIRef("http://example.org/a"), - rdflib.term.URIRef("http://www.example.org/b"), - rdflib.term.Literal("foo")) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/z"), - rdflib.term.Literal("foo-bar")) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/y"), - rdflib.term.Literal("bar")) - >>> - >>> # querying quads() return quads; the fourth argument can be unrestricted - >>> # (None) or restricted to a graph - >>> for q in ds.quads((None, None, None, None)): # doctest: +SKIP - ... print(q) # doctest: +NORMALIZE_WHITESPACE - (rdflib.term.URIRef("http://example.org/a"), - rdflib.term.URIRef("http://www.example.org/b"), - rdflib.term.Literal("foo"), - None) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/y"), - rdflib.term.Literal("bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/z"), - rdflib.term.Literal("foo-bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - >>> - >>> # unrestricted looping is equivalent to iterating over the entire Dataset - >>> for q in ds: # doctest: +SKIP - ... print(q) # doctest: +NORMALIZE_WHITESPACE - (rdflib.term.URIRef("http://example.org/a"), - rdflib.term.URIRef("http://www.example.org/b"), - rdflib.term.Literal("foo"), - None) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/y"), - rdflib.term.Literal("bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/z"), - rdflib.term.Literal("foo-bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - >>> - >>> # resticting iteration to a graph: - >>> for q in ds.quads((None, None, None, g)): # doctest: +SKIP - ... print(q) # doctest: +NORMALIZE_WHITESPACE - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/y"), - rdflib.term.Literal("bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - (rdflib.term.URIRef("http://example.org/x"), - rdflib.term.URIRef("http://example.org/z"), - rdflib.term.Literal("foo-bar"), - rdflib.term.URIRef("http://www.example.com/gr")) - >>> # Note that in the call above - - >>> # ds.quads((None,None,None,"http://www.example.com/gr")) - >>> # would have been accepted, too - >>> - >>> # graph names in the dataset can be queried: - >>> for c in ds.graphs(): # doctest: +SKIP - ... print(c.identifier) # doctest: - urn:x-rdflib:default - http://www.example.com/gr - >>> # A graph can be created without specifying a name; a skolemized genid - >>> # is created on the fly - >>> h = ds.graph() - >>> for c in ds.graphs(): # doctest: +SKIP - ... print(c) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - DEFAULT - https://rdflib.github.io/.well-known/genid/rdflib/N... - http://www.example.com/gr - >>> # Note that the Dataset.graphs() call returns names of empty graphs, - >>> # too. This can be restricted: - >>> for c in ds.graphs(empty=False): # doctest: +SKIP - ... print(c) # doctest: +NORMALIZE_WHITESPACE - DEFAULT - http://www.example.com/gr - >>> - >>> # a graph can also be removed from a dataset via ds.remove_graph(g) - - ... versionadded:: 4.0 - """ - - def __init__( - self, - store: Union[Store, str] = "default", - default_union: bool = False, - default_graph_base: Optional[str] = None, - ): - super(Dataset, self).__init__(store=store, identifier=None) - - if not self.store.graph_aware: - raise Exception("DataSet must be backed by a graph-aware store!") - self.default_context = Graph( - store=self.store, - identifier=DATASET_DEFAULT_GRAPH_ID, - base=default_graph_base, - ) - - self.default_union = default_union - - def __str__(self) -> str: - pattern = ( - "[a rdflib:Dataset;rdflib:storage " "[a rdflib:Store;rdfs:label '%s']]" - ) - return pattern % self.store.__class__.__name__ - - # type error: Return type "Tuple[Type[Dataset], Tuple[Store, bool]]" of "__reduce__" incompatible with return type "Tuple[Type[Graph], Tuple[Store, IdentifiedNode]]" in supertype "ConjunctiveGraph" - # type error: Return type "Tuple[Type[Dataset], Tuple[Store, bool]]" of "__reduce__" incompatible with return type "Tuple[Type[Graph], Tuple[Store, IdentifiedNode]]" in supertype "Graph" - def __reduce__(self) -> Tuple[Type[Dataset], Tuple[Store, bool]]: # type: ignore[override] - return (type(self), (self.store, self.default_union)) - - def __getstate__(self) -> Tuple[Store, _ContextIdentifierType, _ContextType, bool]: - return self.store, self.identifier, self.default_context, self.default_union - - def __setstate__( - self, state: Tuple[Store, _ContextIdentifierType, _ContextType, bool] - ) -> None: - # type error: Property "store" defined in "Graph" is read-only - # type error: Property "identifier" defined in "Graph" is read-only - self.store, self.identifier, self.default_context, self.default_union = state # type: ignore[misc] - - def graph( - self, - identifier: Optional[Union[_ContextIdentifierType, _ContextType, str]] = None, - base: Optional[str] = None, - ) -> Graph: - if identifier is None: - from rdflib.term import _SKOLEM_DEFAULT_AUTHORITY, rdflib_skolem_genid - - self.bind( - "genid", - _SKOLEM_DEFAULT_AUTHORITY + rdflib_skolem_genid, - override=False, - ) - identifier = BNode().skolemize() - - g = self._graph(identifier) - g.base = base - - self.store.add_graph(g) - return g - - def parse( - self, - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ] = None, - publicID: Optional[str] = None, # noqa: N803 - format: Optional[str] = None, - location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, - **args: Any, - ) -> Graph: - """ - Parse an RDF source adding the resulting triples to the Graph. - - See :meth:`rdflib.graph.Graph.parse` for documentation on arguments. - - The source is specified using one of source, location, file or data. - - If the source is in a format that does not support named graphs its triples - will be added to the default graph - (i.e. :attr:`.Dataset.default_context`). - - .. caution:: - - This method can access directly or indirectly requested network or - file resources, for example, when parsing JSON-LD documents with - ``@context`` directives that point to a network location. - - When processing untrusted or potentially malicious documents, - measures should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - - *Changed in 7.0*: The ``publicID`` argument is no longer used as the - identifier (i.e. name) of the default graph as was the case before - version 7.0. In the case of sources that do not support named graphs, - the ``publicID`` parameter will also not be used as the name for the - graph that the data is loaded into, and instead the triples from sources - that do not support named graphs will be loaded into the default graph - (i.e. :attr:`.Dataset.default_context`). - """ - - c = ConjunctiveGraph.parse( - self, source, publicID, format, location, file, data, **args - ) - self.graph(c) - return c - - def add_graph( - self, g: Optional[Union[_ContextIdentifierType, _ContextType, str]] - ) -> Graph: - """alias of graph for consistency""" - return self.graph(g) - - def remove_graph( - self: _DatasetT, g: Optional[Union[_ContextIdentifierType, _ContextType, str]] - ) -> _DatasetT: - if not isinstance(g, Graph): - g = self.get_context(g) - - self.store.remove_graph(g) - if g is None or g == self.default_context: - # default graph cannot be removed - # only triples deleted, so add it back in - self.store.add_graph(self.default_context) - return self - - def contexts( - self, triple: Optional[_TripleType] = None - ) -> Generator[_ContextType, None, None]: - default = False - for c in super(Dataset, self).contexts(triple): - default |= c.identifier == DATASET_DEFAULT_GRAPH_ID - yield c - if not default: - yield self.graph(DATASET_DEFAULT_GRAPH_ID) - - graphs = contexts - - # type error: Return type "Generator[Tuple[Node, Node, Node, Optional[Node]], None, None]" of "quads" incompatible with return type "Generator[Tuple[Node, Node, Node, Optional[Graph]], None, None]" in supertype "ConjunctiveGraph" - def quads( # type: ignore[override] - self, quad: Optional[_TripleOrQuadPatternType] = None - ) -> Generator[_OptionalIdentifiedQuadType, None, None]: - for s, p, o, c in super(Dataset, self).quads(quad): - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - if c.identifier == self.default_context: # type: ignore[union-attr] - yield s, p, o, None - else: - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" [union-attr] - yield s, p, o, c.identifier # type: ignore[union-attr] - - # type error: Return type "Generator[Tuple[Node, URIRef, Node, Optional[IdentifiedNode]], None, None]" of "__iter__" incompatible with return type "Generator[Tuple[IdentifiedNode, IdentifiedNode, Union[IdentifiedNode, Literal]], None, None]" in supertype "Graph" - def __iter__( # type: ignore[override] - self, - ) -> Generator[_OptionalIdentifiedQuadType, None, None]: - """Iterates over all quads in the store""" - return self.quads((None, None, None, None)) - - -class QuotedGraph(Graph): - """ - Quoted Graphs are intended to implement Notation 3 formulae. They are - associated with a required identifier that the N3 parser *must* provide - in order to maintain consistent formulae identification for scenarios - such as implication and other such processing. - """ - - def __init__( - self, - store: Union[Store, str], - identifier: Optional[Union[_ContextIdentifierType, str]], - ): - super(QuotedGraph, self).__init__(store, identifier) - - def add(self: _GraphT, triple: _TripleType) -> _GraphT: - """Add a triple with self as context""" - s, p, o = triple - assert isinstance(s, Node), "Subject %s must be an rdflib term" % (s,) - assert isinstance(p, Node), "Predicate %s must be an rdflib term" % (p,) - assert isinstance(o, Node), "Object %s must be an rdflib term" % (o,) - - self.store.add((s, p, o), self, quoted=True) - return self - - def addN(self: _GraphT, quads: Iterable[_QuadType]) -> _GraphT: # noqa: N802 - """Add a sequence of triple with context""" - - self.store.addN( - (s, p, o, c) - for s, p, o, c in quads - if isinstance(c, QuotedGraph) - and c.identifier is self.identifier - and _assertnode(s, p, o) - ) - return self - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - """Return an n3 identifier for the Graph""" - return "{%s}" % self.identifier.n3(namespace_manager=namespace_manager) - - def __str__(self) -> str: - identifier = self.identifier.n3() - label = self.store.__class__.__name__ - pattern = ( - "{this rdflib.identifier %s;rdflib:storage " - "[a rdflib:Store;rdfs:label '%s']}" - ) - return pattern % (identifier, label) - - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: - return QuotedGraph, (self.store, self.identifier) - - -# Make sure QuotedGraph is ordered correctly -# wrt to other Terms. -# this must be done here, as the QuotedGraph cannot be -# circularily imported in term.py -rdflib.term._ORDERING[QuotedGraph] = 11 - - -class Seq: - """Wrapper around an RDF Seq resource - - It implements a container type in Python with the order of the items - returned corresponding to the Seq content. It is based on the natural - ordering of the predicate names _1, _2, _3, etc, which is the - 'implementation' of a sequence in RDF terms. - """ - - def __init__(self, graph: Graph, subject: _SubjectType): - """Parameters: - - - graph: - the graph containing the Seq - - - subject: - the subject of a Seq. Note that the init does not - check whether this is a Seq, this is done in whoever - creates this instance! - """ - - self._list: List[Tuple[int, _ObjectType]] - _list = self._list = list() - LI_INDEX = URIRef(str(RDF) + "_") # noqa: N806 - for p, o in graph.predicate_objects(subject): - # type error: "Node" has no attribute "startswith" - if p.startswith(LI_INDEX): # type: ignore[attr-defined] # != RDF.Seq: - # type error: "Node" has no attribute "replace" - i = int(p.replace(LI_INDEX, "")) # type: ignore[attr-defined] - _list.append((i, o)) - - # here is the trick: the predicates are _1, _2, _3, etc. Ie, - # by sorting the keys (by integer) we have what we want! - _list.sort() - - def toPython(self) -> Seq: # noqa: N802 - return self - - def __iter__(self) -> Generator[_ObjectType, None, None]: - """Generator over the items in the Seq""" - for _, item in self._list: - yield item - - def __len__(self) -> int: - """Length of the Seq""" - return len(self._list) - - def __getitem__(self, index) -> _ObjectType: - """Item given by index from the Seq""" - index, item = self._list.__getitem__(index) - return item - - -class ModificationException(Exception): # noqa: N818 - def __init__(self) -> None: - pass - - def __str__(self) -> str: - return ( - "Modifications and transactional operations not allowed on " - "ReadOnlyGraphAggregate instances" - ) - - -class UnSupportedAggregateOperation(Exception): # noqa: N818 - def __init__(self) -> None: - pass - - def __str__(self) -> str: - return "This operation is not supported by ReadOnlyGraphAggregate " "instances" - - -class ReadOnlyGraphAggregate(ConjunctiveGraph): - """Utility class for treating a set of graphs as a single graph - - Only read operations are supported (hence the name). Essentially a - ConjunctiveGraph over an explicit subset of the entire store. - """ - - def __init__(self, graphs: List[Graph], store: Union[str, Store] = "default"): - if store is not None: - super(ReadOnlyGraphAggregate, self).__init__(store) - Graph.__init__(self, store) - self.__namespace_manager = None - - assert ( - isinstance(graphs, list) - and graphs - and [g for g in graphs if isinstance(g, Graph)] - ), "graphs argument must be a list of Graphs!!" - self.graphs = graphs - - def __repr__(self) -> str: - return "" % len(self.graphs) - - def destroy(self, configuration: str) -> NoReturn: - raise ModificationException() - - # Transactional interfaces (optional) - def commit(self) -> NoReturn: - raise ModificationException() - - def rollback(self) -> NoReturn: - raise ModificationException() - - def open(self, configuration: str, create: bool = False) -> None: - # TODO: is there a use case for this method? - for graph in self.graphs: - # type error: Too many arguments for "open" of "Graph" - # type error: Argument 1 to "open" of "Graph" has incompatible type "ReadOnlyGraphAggregate"; expected "str" [arg-type] - # type error: Argument 2 to "open" of "Graph" has incompatible type "str"; expected "bool" [arg-type] - graph.open(self, configuration, create) # type: ignore[call-arg, arg-type] - - # type error: Signature of "close" incompatible with supertype "Graph" - def close(self) -> None: # type: ignore[override] - for graph in self.graphs: - graph.close() - - def add(self, triple: _TripleOrOptionalQuadType) -> NoReturn: - raise ModificationException() - - def addN(self, quads: Iterable[_QuadType]) -> NoReturn: # noqa: N802 - raise ModificationException() - - # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "Tuple[Optional[Node], Optional[Node], Optional[Node]]" - def remove(self, triple: _TripleOrOptionalQuadType) -> NoReturn: # type: ignore[override] - raise ModificationException() - - # type error: Signature of "triples" incompatible with supertype "ConjunctiveGraph" - @overload # type: ignore[override] - def triples( - self, - triple: _TriplePatternType, - ) -> Generator[_TripleType, None, None]: ... - - @overload - def triples( - self, - triple: _TriplePathPatternType, - ) -> Generator[_TriplePathType, None, None]: ... - - @overload - def triples( - self, - triple: _TripleSelectorType, - ) -> Generator[_TripleOrTriplePathType, None, None]: ... - - def triples( - self, - triple: _TripleSelectorType, - ) -> Generator[_TripleOrTriplePathType, None, None]: - s, p, o = triple - for graph in self.graphs: - if isinstance(p, Path): - for s, o in p.eval(self, s, o): - yield s, p, o - else: - for s1, p1, o1 in graph.triples((s, p, o)): - yield s1, p1, o1 - - def __contains__(self, triple_or_quad: _TripleOrQuadSelectorType) -> bool: - context = None - if len(triple_or_quad) == 4: - # type error: Tuple index out of range - context = triple_or_quad[3] # type: ignore [misc, unused-ignore] - for graph in self.graphs: - if context is None or graph.identifier == context.identifier: - if triple_or_quad[:3] in graph: - return True - return False - - # type error: Signature of "quads" incompatible with supertype "ConjunctiveGraph" - def quads( # type: ignore[override] - self, triple_or_quad: _TripleOrQuadSelectorType - ) -> Generator[ - Tuple[_SubjectType, Union[Path, _PredicateType], _ObjectType, _ContextType], - None, - None, - ]: - """Iterate over all the quads in the entire aggregate graph""" - c = None - if len(triple_or_quad) == 4: - # type error: Need more than 3 values to unpack (4 expected) - s, p, o, c = triple_or_quad # type: ignore[misc, unused-ignore] - else: - # type error: Too many values to unpack (3 expected, 4 provided) - s, p, o = triple_or_quad # type: ignore[misc, unused-ignore] - - if c is not None: - for graph in [g for g in self.graphs if g == c]: - for s1, p1, o1 in graph.triples((s, p, o)): - yield s1, p1, o1, graph - else: - for graph in self.graphs: - for s1, p1, o1 in graph.triples((s, p, o)): - yield s1, p1, o1, graph - - def __len__(self) -> int: - return sum(len(g) for g in self.graphs) - - def __hash__(self) -> NoReturn: - raise UnSupportedAggregateOperation() - - def __cmp__(self, other) -> int: - if other is None: - return -1 - elif isinstance(other, Graph): - return -1 - elif isinstance(other, ReadOnlyGraphAggregate): - return (self.graphs > other.graphs) - (self.graphs < other.graphs) - else: - return -1 - - def __iadd__(self: _GraphT, other: Iterable[_TripleType]) -> NoReturn: - raise ModificationException() - - def __isub__(self: _GraphT, other: Iterable[_TripleType]) -> NoReturn: - raise ModificationException() - - # Conv. methods - - def triples_choices( - self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], - context: Optional[_ContextType] = None, - ) -> Generator[_TripleType, None, None]: - subject, predicate, object_ = triple - for graph in self.graphs: - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - # type error note: unpacking discards type info - choices = graph.triples_choices((subject, predicate, object_)) # type: ignore[arg-type] - for s, p, o in choices: - yield s, p, o - - def qname(self, uri: str) -> str: - if hasattr(self, "namespace_manager") and self.namespace_manager: - return self.namespace_manager.qname(uri) - raise UnSupportedAggregateOperation() - - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: - if hasattr(self, "namespace_manager") and self.namespace_manager: - return self.namespace_manager.compute_qname(uri, generate) - raise UnSupportedAggregateOperation() - - # type error: Signature of "bind" incompatible with supertype "Graph" - def bind( # type: ignore[override] - self, prefix: Optional[str], namespace: Any, override: bool = True # noqa: F811 - ) -> NoReturn: - raise UnSupportedAggregateOperation() - - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: - if hasattr(self, "namespace_manager"): - for prefix, namespace in self.namespace_manager.namespaces(): - yield prefix, namespace - else: - for graph in self.graphs: - for prefix, namespace in graph.namespaces(): - yield prefix, namespace - - def absolutize(self, uri: str, defrag: int = 1) -> NoReturn: - raise UnSupportedAggregateOperation() - - # type error: Signature of "parse" incompatible with supertype "ConjunctiveGraph" - def parse( # type: ignore[override] - self, - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ], - publicID: Optional[str] = None, # noqa: N803 - format: Optional[str] = None, - **args: Any, - ) -> NoReturn: - raise ModificationException() - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> NoReturn: - raise UnSupportedAggregateOperation() - - def __reduce__(self) -> NoReturn: - raise UnSupportedAggregateOperation() - - -@overload -def _assertnode(*terms: Node) -> te.Literal[True]: ... - - -@overload -def _assertnode(*terms: Any) -> bool: ... - - -def _assertnode(*terms: Any) -> bool: - for t in terms: - assert isinstance(t, Node), "Term %s must be an rdflib term" % (t,) - return True - - -class BatchAddGraph: - """ - Wrapper around graph that turns batches of calls to Graph's add - (and optionally, addN) into calls to batched calls to addN`. - - :Parameters: - - - graph: The graph to wrap - - batch_size: The maximum number of triples to buffer before passing to - Graph's addN - - batch_addn: If True, then even calls to `addN` will be batched according to - batch_size - - graph: The wrapped graph - count: The number of triples buffered since initialization or the last call to reset - batch: The current buffer of triples - - """ - - def __init__(self, graph: Graph, batch_size: int = 1000, batch_addn: bool = False): - if not batch_size or batch_size < 2: - raise ValueError("batch_size must be a positive number") - self.graph = graph - self.__graph_tuple = (graph,) - self.__batch_size = batch_size - self.__batch_addn = batch_addn - self.reset() - - def reset(self) -> BatchAddGraph: - """ - Manually clear the buffered triples and reset the count to zero - """ - self.batch: List[_QuadType] = [] - self.count = 0 - return self - - def add( - self, - triple_or_quad: Union[ - _TripleType, - _QuadType, - ], - ) -> BatchAddGraph: - """ - Add a triple to the buffer - - :param triple: The triple to add - """ - if len(self.batch) >= self.__batch_size: - self.graph.addN(self.batch) - self.batch = [] - self.count += 1 - if len(triple_or_quad) == 3: - # type error: Argument 1 to "append" of "list" has incompatible type "Tuple[Node, ...]"; expected "Tuple[Node, Node, Node, Graph]" - self.batch.append(triple_or_quad + self.__graph_tuple) # type: ignore[arg-type, unused-ignore] - else: - # type error: Argument 1 to "append" of "list" has incompatible type "Union[Tuple[Node, Node, Node], Tuple[Node, Node, Node, Graph]]"; expected "Tuple[Node, Node, Node, Graph]" - self.batch.append(triple_or_quad) # type: ignore[arg-type, unused-ignore] - return self - - def addN(self, quads: Iterable[_QuadType]) -> BatchAddGraph: # noqa: N802 - if self.__batch_addn: - for q in quads: - self.add(q) - else: - self.graph.addN(quads) - return self - - def __enter__(self) -> BatchAddGraph: - self.reset() - return self - - def __exit__(self, *exc) -> None: - if exc[0] is None: - self.graph.addN(self.batch) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_BRICK.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_BRICK.py deleted file mode 100644 index 20c60fc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_BRICK.py +++ /dev/null @@ -1,1592 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class BRICK(DefinedNamespace): - """ - Brick Ontology classes, properties and entity properties. See https://brickschema.org/ - for more information. - - Generated from: https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl - Date: 2021-09-22T14:32:56 - """ - - # http://www.w3.org/2002/07/owl#Class - AED: URIRef - AHU: URIRef # Assembly consisting of sections containing a fan or fans and other necessary equipment to perform one or more of the following functions: circulating, filtration, heating, cooling, heat recovery, humidifying, dehumidifying, and mixing of air. Is usually connected to an air-distribution system. - Ablutions_Room: URIRef # A room for performing cleansing rituals before prayer - Absorption_Chiller: URIRef # A chiller that utilizes a thermal or/and chemical process to produce the refrigeration effect necessary to provide chilled water. There is no mechanical compression of the refrigerant taking place within the machine, as occurs within more traditional vapor compression type chillers. - Acceleration_Time_Setpoint: URIRef - Access_Control_Equipment: URIRef - Access_Reader: URIRef - Active_Chilled_Beam: URIRef # A Chilled Beam with an integral primary air connection that induces air flow through the device. - Active_Power_Sensor: URIRef # Measures the portion of power that, averaged over a complete cycle of the AC waveform, results in net transfer of energy in one direction - Adjust_Sensor: URIRef # Measures user-provided adjustment of some value - Air: URIRef # the invisible gaseous substance surrounding the earth, a mixture mainly of oxygen and nitrogen. - Air_Alarm: URIRef - Air_Differential_Pressure_Sensor: ( - URIRef # Measures the difference in pressure between two regions of air - ) - Air_Differential_Pressure_Setpoint: URIRef # Sets the target air differential pressure between an upstream and downstream point in a air duct or conduit - Air_Diffuser: URIRef # A device that is a component of the air distribution system that controls the delivery of conditioned and/or ventilating air into a room - Air_Enthalpy_Sensor: URIRef # Measures the total heat content of air - Air_Flow_Deadband_Setpoint: URIRef # Sets the size of a deadband of air flow - Air_Flow_Demand_Setpoint: URIRef # Sets the rate of air flow required for a process - Air_Flow_Loss_Alarm: URIRef # An alarm that indicates loss in air flow. - Air_Flow_Sensor: URIRef # Measures the rate of flow of air - Air_Flow_Setpoint: URIRef # Sets air flow - Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Air_Flow_Setpoint. - Air_Grains_Sensor: URIRef # Measures the mass of water vapor in air - Air_Handler_Unit: URIRef # Assembly consisting of sections containing a fan or fans and other necessary equipment to perform one or more of the following functions: circulating, filtration, heating, cooling, heat recovery, humidifying, dehumidifying, and mixing of air. Is usually connected to an air-distribution system. - Air_Handling_Unit: URIRef - Air_Humidity_Setpoint: URIRef - Air_Loop: URIRef # The set of connected equipment serving one path of air - Air_Plenum: URIRef # A component of the HVAC the receives air from the air handling unit or room to distribute or exhaust to or from the building - Air_Quality_Sensor: URIRef # A sensor which provides a measure of air quality - Air_Static_Pressure_Step_Parameter: URIRef - Air_System: URIRef # The equipment, distribution systems and terminals that introduce or exhaust, either collectively or individually, the air into and from the building - Air_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the temperature of air. - Air_Temperature_Integral_Time_Parameter: URIRef - Air_Temperature_Sensor: URIRef # Measures the temperature of air - Air_Temperature_Setpoint: URIRef # Sets temperature of air - Air_Temperature_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Air_Temperature_Setpoint. - Air_Temperature_Step_Parameter: URIRef - Air_Wet_Bulb_Temperature_Sensor: URIRef - Alarm: URIRef # Alarm points are signals (either audible or visual) that alert an operator to an off-normal condition which requires some form of corrective action - Alarm_Delay_Parameter: URIRef # A parameter determining how long to delay an alarm after sufficient conditions have been met - Angle_Sensor: URIRef # Measues the planar angle of some phenomenon - Auditorium: URIRef # A space for performances or larger gatherings - Automated_External_Defibrillator: URIRef - Automatic_Mode_Command: URIRef # Controls whether or not a device or controller is operating in "Automatic" mode - Availability_Status: URIRef # Indicates if a piece of equipment, system, or functionality is available for operation - Average_Cooling_Demand_Sensor: URIRef # Measures the average power consumed by a cooling process as the amount of power consumed over some interval - Average_Discharge_Air_Flow_Sensor: ( - URIRef # The computed average flow of discharge air over some interval - ) - Average_Exhaust_Air_Static_Pressure_Sensor: URIRef # The computed average static pressure of air in exhaust regions of an HVAC system over some period of time - Average_Heating_Demand_Sensor: URIRef # Measures the average power consumed by a heating process as the amount of power consumed over some interval - Average_Supply_Air_Flow_Sensor: ( - URIRef # The computed average flow of supply air over some interval - ) - Average_Zone_Air_Temperature_Sensor: URIRef # The computed average temperature of air in a zone, over some period of time - Baseboard_Radiator: URIRef # Steam, hydronic, or electric heating device located at or near the floor. - Basement: URIRef # The floor of a building which is partly or entirely below ground level. - Battery: URIRef # A container that stores chemical energy that can be converted into electricity and used as a source of power - Battery_Energy_Storage_System: URIRef # A collection of batteries that provides energy storage, along with their supporting equipment - Battery_Room: URIRef # A room used to hold batteries for backup power - Battery_Voltage_Sensor: URIRef # Measures the capacity of a battery - Bench_Space: URIRef # For areas of play in a stadium, the area for partcipants and referees by the side of the field - Blowdown_Water: URIRef # Water expelled from a system to remove mineral build up - Boiler: URIRef # A closed, pressure vessel that uses fuel or electricity for heating water or other fluids to supply steam or hot water for heating, humidification, or other applications. - Booster_Fan: URIRef # Fan activated to increase airflow beyond what is provided by the default configuration - Box_Mode_Command: URIRef - Break_Room: URIRef # A space for people to relax while not working - Breaker_Panel: URIRef # Breaker Panel distributes power into various end-uses. - Breakroom: URIRef # A space for people to relax while not working - Broadcast_Room: ( - URIRef # A space to organize and manage a broadcast. Separate from studio - ) - Building: URIRef # An independent unit of the built environment with a characteristic spatial structure, intended to serve at least one function or user activity [ISO 12006-2:2013] - Building_Air: URIRef # air contained within a building - Building_Air_Humidity_Setpoint: URIRef # Setpoint for humidity in a building - Building_Air_Static_Pressure_Sensor: ( - URIRef # The static pressure of air within a building - ) - Building_Air_Static_Pressure_Setpoint: ( - URIRef # Sets static pressure of the entire building - ) - Building_Chilled_Water_Meter: URIRef # A meter that measures the usage or consumption of chilled water of a whole building - Building_Electrical_Meter: URIRef # A meter that measures the usage or consumption of electricity of a whole building - Building_Gas_Meter: URIRef # A meter that measures the usage or consumption of gas of a whole building - Building_Hot_Water_Meter: URIRef # A meter that measures the usage or consumption of hot water of a whole building - Building_Meter: URIRef # A meter that measures usage or consumption of some media for a whole building - Building_Water_Meter: URIRef # A meter that measures the usage or consumption of water of a whole building - Bus_Riser: URIRef # Bus Risers are commonly fed from a switchgear and rise up through a series of floors to the main power distribution source for each floor. - Bypass_Air: URIRef # air in a bypass duct, used to relieve static pressure - Bypass_Air_Flow_Sensor: URIRef # Measures the rate of flow of bypass air - Bypass_Air_Humidity_Setpoint: URIRef # Humidity setpoint for bypass air - Bypass_Command: URIRef - Bypass_Valve: URIRef # A type of valve installed in a bypass pipeline - Bypass_Water: URIRef # Water that circumvents a piece of equipment or system - Bypass_Water_Flow_Sensor: URIRef # Measures the rate of flow of bypass water - Bypass_Water_Flow_Setpoint: URIRef # Sets the target flow rate of bypass water - CAV: URIRef - CO: URIRef # Carbon Monoxide in the vapor phase - CO2: URIRef # Carbon Dioxide in the vapor phase - CO2_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the presence of carbon dioxide. - CO2_Differential_Sensor: ( - URIRef # Measures the difference between CO2 levels of inside and outside air - ) - CO2_Level_Sensor: URIRef # Measures the concentration of CO2 in air - CO2_Sensor: URIRef # Measures properties of CO2 in air - CO2_Setpoint: URIRef # Sets some property of CO2 - CO_Differential_Sensor: URIRef - CO_Level_Sensor: URIRef # Measures the concentration of CO - CO_Sensor: URIRef # Measures properties of CO - CRAC: URIRef - Cafeteria: URIRef # A space to serve food and beverages - Camera: URIRef - Capacity_Sensor: URIRef - Ceiling_Fan: URIRef # A fan installed on the ceiling of a room for the purpose of air circulation - Centrifugal_Chiller: URIRef # A chiller that uses the vapor compression cycle to chill water. It throws off the heat collected from the chilled water plus the heat from the compressor to a water loop - Change_Filter_Alarm: URIRef # An alarm that indicates that a filter must be changed - Chilled_Beam: URIRef # A device with an integrated coil that performs sensible heating of a space via circulation of room air. Chilled Beams are not designed to perform latent cooling; see Induction Units. Despite their name, Chilled Beams may perform heating or cooling of a space depending on their configuration. - Chilled_Water: URIRef # water used as a cooling medium (particularly in air-conditioning systems or in processes) at below ambient temperature. - Chilled_Water_Coil: URIRef # A cooling element made of pipe or tube that removes heat from equipment, machines or airflows that is filled with chilled water. - Chilled_Water_Differential_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of differential pressure of chilled water - ) - Chilled_Water_Differential_Pressure_Integral_Time_Parameter: URIRef - Chilled_Water_Differential_Pressure_Load_Shed_Reset_Status: URIRef - Chilled_Water_Differential_Pressure_Load_Shed_Setpoint: URIRef - Chilled_Water_Differential_Pressure_Load_Shed_Status: URIRef - Chilled_Water_Differential_Pressure_Proportional_Band_Parameter: URIRef - Chilled_Water_Differential_Pressure_Sensor: URIRef # Measures the difference in water pressure on either side of a chilled water valve - Chilled_Water_Differential_Pressure_Setpoint: URIRef # Sets the target water differential pressure between an upstream and downstream point in a water pipe or conduit used to carry chilled water - Chilled_Water_Differential_Pressure_Step_Parameter: URIRef - Chilled_Water_Differential_Temperature_Sensor: URIRef # Measures the difference in temperature between the entering water to the chiller or other water cooling device and leaving water from the same chiller or other water cooling device - Chilled_Water_Discharge_Flow_Sensor: ( - URIRef # Measures the rate of flow of chilled discharge water - ) - Chilled_Water_Discharge_Flow_Setpoint: ( - URIRef # Sets the target flow rate of chilled discharge water - ) - Chilled_Water_Flow_Sensor: ( - URIRef # Measures the rate of flow in a chilled water circuit - ) - Chilled_Water_Flow_Setpoint: URIRef # Sets the target flow rate of chilled water - Chilled_Water_Loop: URIRef # A collection of equipment that transport and regulate chilled water among each other - Chilled_Water_Meter: ( - URIRef # A meter that measures the usage or consumption of chilled water - ) - Chilled_Water_Pump: URIRef # A pump that performs work on chilled water; typically part of a chilled water system - Chilled_Water_Pump_Differential_Pressure_Deadband_Setpoint: URIRef # Sets the size of a deadband of differential pressure of chilled water in a chilled water pump - Chilled_Water_Return_Flow_Sensor: ( - URIRef # Measures the rate of flow of chilled return water - ) - Chilled_Water_Return_Temperature_Sensor: URIRef # Measures the temperature of chilled water that is returned to a cooling tower - Chilled_Water_Static_Pressure_Setpoint: ( - URIRef # Sets static pressure of chilled water - ) - Chilled_Water_Supply_Flow_Sensor: ( - URIRef # Measures the rate of flow of chilled supply water - ) - Chilled_Water_Supply_Flow_Setpoint: ( - URIRef # Sets the target flow rate of chilled supply water - ) - Chilled_Water_Supply_Temperature_Sensor: URIRef # Measures the temperature of chilled water that is supplied from a chiller - Chilled_Water_System: URIRef # The equipment, devices and conduits that handle the production and distribution of chilled water in a building - Chilled_Water_System_Enable_Command: ( - URIRef # Enables operation of the chilled water system - ) - Chilled_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of chilled water - ) - Chilled_Water_Temperature_Setpoint: URIRef # Sets the temperature of chilled water - Chilled_Water_Valve: URIRef # A valve that modulates the flow of chilled water - Chiller: URIRef # Refrigerating machine used to transfer heat between fluids. Chillers are either direct expansion with a compressor or absorption type. - Class: URIRef - Close_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Close_Setpoint. - Coil: URIRef # Cooling or heating element made of pipe or tube that may or may not be finned and formed into helical or serpentine shape (ASHRAE Dictionary) - Cold_Box: URIRef # in a gas separation unit, the insulated section that contains the low-temperature heat exchangers and distillation columns. - Coldest_Zone_Air_Temperature_Sensor: URIRef # The zone temperature that is coldest; drives the supply temperature of hot air. A computed value rather than a physical sensor. Also referred to as a 'Lowest Zone Air Temperature Sensor' - Collection: URIRef - Collection_Basin_Water: URIRef # Water transiently collected and directed to the sump or pump suction line, typically integral with a cooling tower - Collection_Basin_Water_Heater: URIRef # Basin heaters prevent cold water basin freeze-up, e.g. in cooling towers, closed circuit fluid coolers, or evaporative condensers - Collection_Basin_Water_Level_Alarm: URIRef # An alarm that indicates a high or low level of water in the collection basin, e.g. within a Cooling_Tower - Collection_Basin_Water_Level_Sensor: URIRef # Measures the level of the water in the collection basin, e.g. within a Cooling_Tower - Collection_Basin_Water_Temperature_Sensor: URIRef # Measures the temperature of the water in the collection basin, e.g. within a Cooling_Tower - Command: URIRef # A Command is an output point that directly determines the behavior of equipment and/or affects relevant operational points. - Common_Space: ( - URIRef # A class of spaces that are used by multiple people at the same time - ) - Communication_Loss_Alarm: URIRef # An alarm that indicates a loss of communication e.g. with a device or controller - Compressor: URIRef # (1) device for mechanically increasing the pressure of a gas. (2) often described as being either open, hermetic, or semihermetic to describe how the compressor and motor drive is situated in relation to the gas or vapor being compressed. Types include centrifugal, axial flow, reciprocating, rotary screw, rotary vane, scroll, or diaphragm. 1. device for mechanically increasing the pressure of a gas. 2. specific machine, with or without accessories, for compressing refrigerant vapor. - Computer_Room_Air_Conditioning: URIRef # A device that monitors and maintains the temperature, air distribution and humidity in a network room or data center. - Concession: URIRef # A space to sell food and beverages. Usually embedded in a larger space and does not include a space where people consume their purchases - Condensate_Leak_Alarm: ( - URIRef # An alarm that indicates a leak of condensate from a cooling system - ) - Condenser: URIRef # A heat exchanger in which the primary heat transfer vapor changes its state to a liquid phase. - Condenser_Heat_Exchanger: URIRef # A heat exchanger in which the primary heat transfer vapor changes its state to a liquid phase. - Condenser_Water: URIRef # Water used used to remove heat through condensation - Condenser_Water_Bypass_Valve: ( - URIRef # A valve installed in a bypass line of a condenser water loop - ) - Condenser_Water_Isolation_Valve: ( - URIRef # An isolation valve installed in the condenser water loop - ) - Condenser_Water_Pump: URIRef # A pump that is part of a condenser system; the pump circulates condenser water from the chiller back to the cooling tower - Condenser_Water_System: URIRef # A heat rejection system consisting of (typically) cooling towers, condenser water pumps, chillers and the piping connecting the components - Condenser_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of condenser water - ) - Condenser_Water_Valve: URIRef # A valve that modulates the flow of condenser water - Condensing_Natural_Gas_Boiler: URIRef # A closed, pressure vessel that uses natural gas and heat exchanger that capture and reuse any latent heat for heating water or other fluids to supply steam or hot water for heating, humidification, or other applications. - Conductivity_Sensor: URIRef # Measures electrical conductance - Conference_Room: URIRef # A space dedicated in which to hold a meetings - Constant_Air_Volume_Box: URIRef # A terminal unit for which supply air flow rate is constant and the supply air temperature is varied to meet thermal load - Contact_Sensor: URIRef # Senses or detects contact, such as for determining if a door is closed. - Control_Room: URIRef # A space from which operations are managed - Cooling_Coil: URIRef # A cooling element made of pipe or tube that removes heat from equipment, machines or airflows. Typically filled with either refrigerant or cold water. - Cooling_Command: URIRef # Controls the amount of cooling to be delivered (typically as a proportion of total cooling output) - Cooling_Demand_Sensor: URIRef # Measures the amount of power consumed by a cooling process; typically found by multiplying the tonnage of a unit (e.g. RTU) by the efficiency rating in kW/ton - Cooling_Demand_Setpoint: URIRef # Sets the rate required for cooling - Cooling_Discharge_Air_Flow_Setpoint: URIRef # Sets discharge air flow for cooling - Cooling_Discharge_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of cooling discharge air - ) - Cooling_Discharge_Air_Temperature_Integral_Time_Parameter: URIRef - Cooling_Discharge_Air_Temperature_Proportional_Band_Parameter: URIRef - Cooling_Start_Stop_Status: URIRef - Cooling_Supply_Air_Flow_Setpoint: URIRef # Sets supply air flow rate for cooling - Cooling_Supply_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of supply air for cooling - ) - Cooling_Supply_Air_Temperature_Integral_Time_Parameter: URIRef - Cooling_Supply_Air_Temperature_Proportional_Band_Parameter: URIRef - Cooling_Temperature_Setpoint: URIRef # Sets temperature for cooling - Cooling_Tower: URIRef # A cooling tower is a heat rejection device that rejects waste heat to the atmosphere through the cooling of a water stream to a lower temperature. Cooling towers may either use the evaporation of water to remove process heat and cool the working fluid to near the wet-bulb air temperature or, in the case of closed circuit dry cooling towers, rely solely on air to cool the working fluid to near the dry-bulb air temperature. - Cooling_Tower_Fan: URIRef # A fan that pulls air through a cooling tower and across the louvers where the water falls to aid in heat exchange by the process of evaporation - Cooling_Valve: URIRef # A valve that controls air temperature by modulating the amount of cold water flowing through a cooling coil - Copy_Room: URIRef # A room set aside for common office equipment, including printers and copiers - Core_Temperature_Sensor: URIRef # Measures the internal temperature of the radiant layer at the heat source or sink level of the radiant heating and cooling HVAC system. - Core_Temperature_Setpoint: URIRef # Sets temperature for the core, i.e. the temperature at the heat source or sink level, of the radiant panel. - Cubicle: URIRef # A smaller space set aside for an individual, but not with a door and without full-height walls - Current_Imbalance_Sensor: URIRef # A sensor which measures the current difference (imbalance) between phases of an electrical system - Current_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Current_Setpoint. - Current_Output_Sensor: URIRef # Senses the amperes of electrical current produced as output by a device - Current_Sensor: ( - URIRef # Senses the amperes of electrical current passing through the sensor - ) - Curtailment_Override_Command: URIRef - Cycle_Alarm: URIRef # An alarm that indicates off-normal conditions associated with HVAC cycles - DC_Bus_Voltage_Sensor: URIRef # Measures the voltage across a DC bus - DOAS: URIRef # See Dedicated_Outdoor_Air_System_Unit - Damper: URIRef # Element inserted into an air-distribution system or element of an air-distribution system permitting modification of the air resistance of the system and consequently changing the airflow rate or shutting off the airflow. - Damper_Command: URIRef # Controls properties of dampers - Damper_Position_Command: ( - URIRef # Controls the position (the degree of openness) of a damper - ) - Damper_Position_Sensor: URIRef # Measures the current position of a damper in terms of the percent of fully open - Damper_Position_Setpoint: URIRef # Sets the position of damper - Deadband_Setpoint: URIRef # Sets the size of a deadband - Deceleration_Time_Setpoint: URIRef - Dedicated_Outdoor_Air_System_Unit: URIRef # A device that conditions and delivers 100% outdoor air to its assigned spaces. It decouples air-conditioning of the outdoor air, usually used to provide minimum outdoor air ventilation, from conditioning of the internal loads. - Dehumidification_Start_Stop_Status: URIRef - Deionised_Water_Conductivity_Sensor: ( - URIRef # Measures the electrical conductance of deionised water - ) - Deionised_Water_Level_Sensor: ( - URIRef # Measures the height/level of deionised water in some container - ) - Deionized_Water: URIRef # Water which has been purified by removing its ions (constituting the majority of non-particulate contaminants) - Deionized_Water_Alarm: URIRef # An alarm that indicates deionized water leaks. - Delay_Parameter: URIRef # A parameter determining how long to delay a subsequent action to take place after a received signal - Demand_Sensor: URIRef # Measures the amount of power consumed by the use of some process; typically found by multiplying the tonnage of a unit (e.g. RTU) by the efficiency rating in kW/ton - Demand_Setpoint: URIRef # Sets the rate required for a process - Derivative_Gain_Parameter: URIRef - Derivative_Time_Parameter: URIRef - Detention_Room: ( - URIRef # A space for the temporary involuntary confinement of people - ) - Dew_Point_Setpoint: URIRef # Sets dew point - Dewpoint_Sensor: URIRef # Senses the dewpoint temperature . Dew point is the temperature to which air must be cooled to become saturated with water vapor - Differential_Air_Temperature_Setpoint: ( - URIRef # Sets temperature of differential air - ) - Differential_Pressure_Bypass_Valve: URIRef # A 2-way, self contained proportional valve with an integral differential pressure adjustment setting. - Differential_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of differential pressure - ) - Differential_Pressure_Integral_Time_Parameter: URIRef - Differential_Pressure_Load_Shed_Status: URIRef - Differential_Pressure_Proportional_Band: URIRef - Differential_Pressure_Sensor: ( - URIRef # Measures the difference between two applied pressures - ) - Differential_Pressure_Setpoint: URIRef # Sets differential pressure - Differential_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Differential_Pressure_Setpoint. - Differential_Pressure_Step_Parameter: URIRef - Differential_Speed_Sensor: URIRef - Differential_Speed_Setpoint: URIRef # Sets differential speed - Differential_Supply_Return_Water_Temperature_Sensor: URIRef # Measures the difference in temperature between return and supply water of water a circuit - Dimmer: URIRef # A switch providing continuous control over all or part of a lighting installation; typically potentiometer-based - Direct_Expansion_Cooling_Coil: URIRef - Direct_Expansion_Heating_Coil: URIRef - Direction_Command: URIRef # Commands that affect the direction of some phenomenon - Direction_Sensor: ( - URIRef # Measures the direction in degrees in which a phenomenon is occurring - ) - Direction_Status: URIRef # Indicates which direction a device is operating in - Disable_Command: URIRef # Commands that disable functionality - Disable_Differential_Enthalpy_Command: ( - URIRef # Disables the use of differential enthalpy control - ) - Disable_Differential_Temperature_Command: ( - URIRef # Disables the use of differential temperature control - ) - Disable_Fixed_Enthalpy_Command: URIRef # Disables the use of fixed enthalpy control - Disable_Fixed_Temperature_Command: ( - URIRef # Disables the use of fixed temperature temperature - ) - Disable_Hot_Water_System_Outside_Air_Temperature_Setpoint: URIRef # Disables hot water system when outside air temperature reaches the indicated value - Disable_Status: URIRef # Indicates if functionality has been disabled - Discharge_Air: URIRef # the air exiting the registers (vents). - Discharge_Air_Dewpoint_Sensor: URIRef # Measures dewpoint of discharge air - Discharge_Air_Duct_Pressure_Status: ( - URIRef # Indicates if air pressure in discharge duct is within expected bounds - ) - Discharge_Air_Flow_Demand_Setpoint: ( - URIRef # Sets the rate of discharge air flow required for a process - ) - Discharge_Air_Flow_High_Reset_Setpoint: URIRef - Discharge_Air_Flow_Low_Reset_Setpoint: URIRef - Discharge_Air_Flow_Reset_Setpoint: URIRef # Setpoints used in Reset strategies - Discharge_Air_Flow_Sensor: URIRef # Measures the rate of flow of discharge air - Discharge_Air_Flow_Setpoint: URIRef # Sets discharge air flow - Discharge_Air_Humidity_Sensor: ( - URIRef # Measures the relative humidity of discharge air - ) - Discharge_Air_Humidity_Setpoint: URIRef # Humidity setpoint for discharge air - Discharge_Air_Smoke_Detection_Alarm: URIRef - Discharge_Air_Static_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of static pressure of discharge air - ) - Discharge_Air_Static_Pressure_Integral_Time_Parameter: URIRef - Discharge_Air_Static_Pressure_Proportional_Band_Parameter: URIRef - Discharge_Air_Static_Pressure_Sensor: ( - URIRef # The static pressure of air within discharge regions of an HVAC system - ) - Discharge_Air_Static_Pressure_Setpoint: ( - URIRef # Sets static pressure of discharge air - ) - Discharge_Air_Static_Pressure_Step_Parameter: URIRef - Discharge_Air_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the temperature of discharge air. - Discharge_Air_Temperature_Cooling_Setpoint: ( - URIRef # Sets temperature of discharge air for cooling - ) - Discharge_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of discharge air - ) - Discharge_Air_Temperature_Heating_Setpoint: ( - URIRef # Sets temperature of discharge air for heating - ) - Discharge_Air_Temperature_High_Reset_Setpoint: URIRef - Discharge_Air_Temperature_Low_Reset_Setpoint: URIRef - Discharge_Air_Temperature_Proportional_Band_Parameter: URIRef - Discharge_Air_Temperature_Reset_Differential_Setpoint: URIRef - Discharge_Air_Temperature_Sensor: ( - URIRef # Measures the temperature of discharge air - ) - Discharge_Air_Temperature_Setpoint: URIRef # Sets temperature of discharge air - Discharge_Air_Temperature_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Discharge_Air_Temperature_Setpoint. - Discharge_Air_Temperature_Step_Parameter: URIRef - Discharge_Air_Velocity_Pressure_Sensor: URIRef - Discharge_Chilled_Water: URIRef - Discharge_Fan: URIRef # Fan moving air discharged from HVAC vents - Discharge_Hot_Water: URIRef - Discharge_Water: URIRef - Discharge_Water_Differential_Pressure_Deadband_Setpoint: URIRef # Sets the size of a deadband of differential pressure of discharge water - Discharge_Water_Differential_Pressure_Integral_Time_Parameter: URIRef - Discharge_Water_Differential_Pressure_Proportional_Band_Parameter: URIRef - Discharge_Water_Flow_Sensor: URIRef # Measures the rate of flow of discharge water - Discharge_Water_Flow_Setpoint: ( - URIRef # Sets the target flow rate of discharge water - ) - Discharge_Water_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with temperature of the discharge water. - Discharge_Water_Temperature_Proportional_Band_Parameter: URIRef - Discharge_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of discharge water - ) - Discharge_Water_Temperature_Setpoint: URIRef # Sets temperature of discharge water - Disconnect_Switch: URIRef # Building power is most commonly provided by utility company through a master disconnect switch (sometimes called a service disconnect) in the main electrical room of a building. The Utility Company provided master disconnect switch often owns or restricts access to this switch. There can also be other cases where a disconnect is placed into an electrical system to allow service cut-off to a portion of the building. - Displacement_Flow_Air_Diffuser: URIRef # An air diffuser that is designed for low discharge air speeds to minimize turbulence and induction of room air. This diffuser is used with displacement ventilation systems. - Distribution_Frame: URIRef # A class of spaces where the cables carrying signals meet and connect, e.g. a wiring closet or a broadcast downlink room - Domestic_Hot_Water_Supply_Temperature_Sensor: URIRef # Measures the temperature of domestic water supplied by a hot water system - Domestic_Hot_Water_Supply_Temperature_Setpoint: ( - URIRef # Sets temperature of supplying part of domestic hot water - ) - Domestic_Hot_Water_System: URIRef # The equipment, devices and conduits that handle the production and distribution of domestic hot water in a building - Domestic_Hot_Water_System_Enable_Command: ( - URIRef # Enables operation of the domestic hot water system - ) - Domestic_Hot_Water_Temperature_Setpoint: ( - URIRef # Sets temperature of domestic hot water - ) - Domestic_Hot_Water_Valve: ( - URIRef # A valve regulating the flow of domestic hot water - ) - Domestic_Water: ( - URIRef # Tap water for drinking, washing, cooking, and flushing of toliets - ) - Domestic_Water_Loop: URIRef - Drench_Hose: URIRef - Drive_Ready_Status: URIRef # Indicates if a hard drive or other storage device is ready to be used, e.g. in the context of RAID - Duration_Sensor: URIRef # Measures the duration of a phenomenon or event - ESS_Panel: URIRef # See Embedded_Surface_System_Panel - EconCycle_Start_Stop_Status: URIRef - Economizer: URIRef # Device that, on proper variable sensing, initiates control signals or actions to conserve energy. A control system that reduces the mechanical heating and cooling requirement. - Economizer_Damper: URIRef # A damper that is part of an economizer that is used to module the flow of air - Effective_Air_Temperature_Cooling_Setpoint: URIRef - Effective_Air_Temperature_Heating_Setpoint: URIRef - Effective_Air_Temperature_Setpoint: URIRef - Effective_Discharge_Air_Temperature_Setpoint: URIRef - Effective_Return_Air_Temperature_Setpoint: URIRef - Effective_Room_Air_Temperature_Setpoint: URIRef - Effective_Supply_Air_Temperature_Setpoint: URIRef - Effective_Zone_Air_Temperature_Setpoint: URIRef - Electric_Baseboard_Radiator: ( - URIRef # Electric heating device located at or near the floor - ) - Electric_Boiler: URIRef # A closed, pressure vessel that uses electricity for heating water or other fluids to supply steam or hot water for heating, humidification, or other applications. - Electric_Radiator: URIRef # Electric heating device - Electrical_Equipment: URIRef - Electrical_Meter: ( - URIRef # A meter that measures the usage or consumption of electricity - ) - Electrical_Power_Sensor: ( - URIRef # Measures the amount of instantaneous electric power consumed - ) - Electrical_Room: URIRef # A class of service rooms that house electrical equipment for a building - Electrical_System: URIRef # Devices that serve or are part of the electrical subsystem in the building - Elevator: URIRef # A device that provides vertical transportation between floors, levels or decks of a building, vessel or other structure - Elevator_Shaft: ( - URIRef # The vertical space in which an elevator ascends and descends - ) - Elevator_Space: ( - URIRef # The vertical space in which an elevator ascends and descends - ) - Embedded_Surface_System_Panel: URIRef # Radiant panel heating and cooling system where the energy heat source or sink is embedded in a radiant layer which is thermally insulated from the building structure. - Embedded_Temperature_Sensor: URIRef # Measures the internal temperature of the radiant layer of the radiant heating and cooling HVAC system. - Embedded_Temperature_Setpoint: URIRef # Sets temperature for the internal material, e.g. concrete slab, of the radiant panel. - Emergency_Air_Flow_System: URIRef - Emergency_Air_Flow_System_Status: URIRef - Emergency_Alarm: URIRef # Alarms that indicate off-normal conditions associated with emergency systems - Emergency_Generator_Alarm: URIRef # An alarm that indicates off-normal conditions associated with an emergency generator - Emergency_Generator_Status: URIRef # Indicates if an emergency generator is active - Emergency_Phone: URIRef - Emergency_Power_Off_System: URIRef # A system that can power down a single piece of equipment or a single system from a single point - Emergency_Power_Off_System_Activated_By_High_Temperature_Status: URIRef - Emergency_Power_Off_System_Activated_By_Leak_Detection_System_Status: URIRef - Emergency_Power_Off_System_Status: URIRef - Emergency_Push_Button_Status: ( - URIRef # Indicates if an emergency button has been pushed - ) - Emergency_Wash_Station: URIRef - Employee_Entrance_Lobby: URIRef # An open space near an entrance that is typically only used for employees - Enable_Command: URIRef # Commands that enable functionality - Enable_Differential_Enthalpy_Command: ( - URIRef # Enables the use of differential enthalpy control - ) - Enable_Differential_Temperature_Command: ( - URIRef # Enables the use of differential temperature control - ) - Enable_Fixed_Enthalpy_Command: URIRef # Enables the use of fixed enthalpy control - Enable_Fixed_Temperature_Command: ( - URIRef # Enables the use of fixed temperature control - ) - Enable_Hot_Water_System_Outside_Air_Temperature_Setpoint: URIRef # Enables hot water system when outside air temperature reaches the indicated value - Enable_Status: ( - URIRef # Indicates if a system or piece of functionality has been enabled - ) - Enclosed_Office: URIRef # A space for individuals to work with walls and a door - Energy_Generation_System: ( - URIRef # A collection of devices that generates electricity - ) - Energy_Sensor: URIRef # Measures energy consumption - Energy_Storage: ( - URIRef # Devices or equipment that store energy in its various forms - ) - Energy_Storage_System: URIRef # A collection of devices that stores electricity - Energy_System: URIRef # A collection of devices that generates, stores or transports electricity - Energy_Usage_Sensor: ( - URIRef # Measures the total amount of energy used over some period of time - ) - Energy_Zone: URIRef # A space or group of spaces that are managed or monitored as one unit for energy purposes - Entering_Water: URIRef # Water that is entering a piece of equipment or system - Entering_Water_Flow_Sensor: URIRef # Measures the rate of flow of water entering a piece of equipment or system - Entering_Water_Flow_Setpoint: URIRef # Sets the target flow rate of entering water - Entering_Water_Temperature_Sensor: URIRef # Measures the temperature of water entering a piece of equipment or system - Entering_Water_Temperature_Setpoint: URIRef # Sets temperature of entering water - Enthalpy_Sensor: URIRef # Measures the total heat content of some substance - Enthalpy_Setpoint: URIRef # Sets enthalpy - Entrance: URIRef # The location and space of a building where people enter and exit the building - Environment_Box: URIRef # (also known as climatic chamber), enclosed space designed to create a particular environment. - Equipment: URIRef # devices that serve all or part of the building and may include electric power, lighting, transportation, or service water heating, including, but not limited to, furnaces, boilers, air conditioners, heat pumps, chillers, water heaters, lamps, luminaires, ballasts, elevators, escalators, or other devices or installations. - Equipment_Room: URIRef # A telecommunications room where equipment that serves the building is stored - Evaporative_Heat_Exchanger: URIRef - Even_Month_Status: URIRef - Exercise_Room: URIRef # An indoor room used for exercise and physical activities - Exhaust_Air: URIRef # air that must be removed from a space due to contaminants, regardless of pressurization - Exhaust_Air_Dewpoint_Sensor: URIRef # Measures dewpoint of exhaust air - Exhaust_Air_Differential_Pressure_Sensor: URIRef # Measures the difference in pressure between an upstream and downstream of an air duct or other air conduit used to exhaust air from the building - Exhaust_Air_Differential_Pressure_Setpoint: URIRef # Sets the target air differential pressure between an upstream and downstream point in a exhaust air duct or conduit - Exhaust_Air_Flow_Integral_Time_Parameter: URIRef - Exhaust_Air_Flow_Proportional_Band_Parameter: URIRef - Exhaust_Air_Flow_Sensor: URIRef # Measures the rate of flow of exhaust air - Exhaust_Air_Flow_Setpoint: URIRef # Sets exhaust air flow rate - Exhaust_Air_Humidity_Sensor: URIRef # Measures the relative humidity of exhaust air - Exhaust_Air_Humidity_Setpoint: URIRef # Humidity setpoint for exhaust air - Exhaust_Air_Stack_Flow_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of exhaust air stack flow - ) - Exhaust_Air_Stack_Flow_Integral_Time_Parameter: URIRef - Exhaust_Air_Stack_Flow_Proportional_Band_Parameter: URIRef - Exhaust_Air_Stack_Flow_Sensor: ( - URIRef # Measures the rate of flow of air in the exhaust air stack - ) - Exhaust_Air_Stack_Flow_Setpoint: URIRef # Sets exhaust air stack flow rate - Exhaust_Air_Static_Pressure_Proportional_Band_Parameter: URIRef - Exhaust_Air_Static_Pressure_Sensor: ( - URIRef # The static pressure of air within exhaust regions of an HVAC system - ) - Exhaust_Air_Static_Pressure_Setpoint: URIRef # Sets static pressure of exhaust air - Exhaust_Air_Temperature_Sensor: URIRef # Measures the temperature of exhaust air - Exhaust_Air_Velocity_Pressure_Sensor: URIRef - Exhaust_Damper: URIRef # A damper that modulates the flow of exhaust air - Exhaust_Fan: URIRef # Fan moving exhaust air -- air that must be removed from a space due to contaminants - Exhaust_Fan_Disable_Command: URIRef # Disables operation of the exhaust fan - Exhaust_Fan_Enable_Command: URIRef # Enables operation of the exhaust fan - Eye_Wash_Station: URIRef - FCU: URIRef # See Fan_Coil_Unit - Failure_Alarm: URIRef # Alarms that indicate the failure of devices, equipment, systems and control loops - Fan: URIRef # Any device with two or more blades or vanes attached to a rotating shaft used to produce an airflow for the purpose of comfort, ventilation, exhaust, heating, cooling, or any other gaseous transport. - Fan_Coil_Unit: URIRef # Terminal device consisting of a heating and/or cooling heat exchanger or 'coil' and fan that is used to control the temperature in the space where it is installed - Fan_On_Off_Status: URIRef - Fan_Status: URIRef # Indicates properties of fans - Fan_VFD: URIRef # Variable-frequency drive for fans - Fault_Reset_Command: URIRef # Clears a fault status - Fault_Status: ( - URIRef # Indicates the presence of a fault in a device, system or control loop - ) - Field_Of_Play: URIRef # The area of a stadium where athletic events occur, e.g. the soccer pitch - Filter: URIRef # Device to remove gases from a mixture of gases or to remove solid material from a fluid - Filter_Differential_Pressure_Sensor: ( - URIRef # Measures the difference in pressure on either side of a filter - ) - Filter_Reset_Command: URIRef - Filter_Status: URIRef # Indicates if a filter needs to be replaced - Final_Filter: URIRef # The last, high-efficiency filter installed in a sequence to remove the finest particulates from the substance being filtered - Fire_Control_Panel: URIRef # A panel-mounted device that provides status and control of a fire safety system - Fire_Safety_Equipment: URIRef - Fire_Safety_System: URIRef # A system containing devices and equipment that monitor, detect and suppress fire hazards - Fire_Sensor: URIRef # Measures the presence of fire - Fire_Zone: URIRef # combustion chamber in a furnace or boiler. - First_Aid_Kit: URIRef - First_Aid_Room: URIRef # A room for a person with minor injuries can be treated or temporarily treated until transferred to a more advanced medical facility - Floor: URIRef # A level, typically representing a horizontal aggregation of spaces that are vertically bound. (referring to IFC) - Flow_Sensor: URIRef # Measures the rate of flow of some substance - Flow_Setpoint: URIRef # Sets flow - Fluid: URIRef # substance, as a liquid or gas, that is capable of flowing and that changes shape when acted on by a force. - Food_Service_Room: URIRef # A space used in the production, storage, serving, or cleanup of food and beverages - Formaldehyde_Level_Sensor: ( - URIRef # Measures the concentration of formaldehyde in air - ) - Freeze_Status: ( - URIRef # Indicates if a substance contained within a vessel has frozen - ) - Freezer: URIRef # cold chamber usually kept at a temperature of 22°F to 31°F (–5°C to –1°C), with high-volume air circulation. - Frequency_Command: URIRef # Controls the frequency of a device's operation (e.g. rotational frequency) - Frequency_Sensor: URIRef # Measures the frequency of a phenomenon or aspect of a phenomenon, e.g. the frequency of a fan turning - Fresh_Air_Fan: URIRef # Fan moving fresh air -- air that is supplied into the building from the outdoors - Fresh_Air_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Fresh_Air_Setpoint. - Frost: URIRef # frost formed on the cold surface (tubes, plates) of a cooling coil. - Frost_Sensor: ( - URIRef # Senses the presence of frost or conditions that may cause frost - ) - Fuel_Oil: URIRef # Petroleum based oil burned for energy - Fume_Hood: URIRef # A fume-collection device mounted over a work space, table, or shelf and serving to conduct unwanted gases away from the area enclosed. - Fume_Hood_Air_Flow_Sensor: URIRef # Measures the rate of flow of air in a fume hood - Furniture: URIRef # Movable objects intended to support various human activities such as seating, eating and sleeping - Gain_Parameter: URIRef - Gas: URIRef # state of matter in which substances exist in the form of nonaggregated molecules and which, within acceptable limits of accuracy, satisfy the ideal gas laws; usually a highly superheated vapor. See [[state]]. - Gas_Distribution: URIRef # Utilize a gas distribution source to represent how gas is distributed across multiple destinations - Gas_Meter: URIRef # A meter that measures the usage or consumption of gas - Gas_Sensor: URIRef # Measures gas concentration (other than CO2) - Gas_System: URIRef - Gas_Valve: URIRef - Gasoline: URIRef # Petroleum derived liquid used as a fuel source - Gatehouse: URIRef # The standalone building used to manage the entrance to a campus or building grounds - Generator_Room: ( - URIRef # A room for electrical equipment, specifically electrical generators. - ) - Glycol: URIRef - HVAC_Equipment: URIRef # See Heating_Ventilation_Air_Conditioning_System - HVAC_System: URIRef # See Heating_Ventilation_Air_Conditioning_System - HVAC_Zone: URIRef # a space or group of spaces, within a building with heating, cooling, and ventilating requirements, that are sufficiently similar so that desired conditions (e.g., temperature) can be maintained throughout using a single sensor (e.g., thermostat or temperature sensor). - HX: URIRef # See Heat_Exchanger - Hail: ( - URIRef # pellets of frozen rain which fall in showers from cumulonimbus clouds. - ) - Hail_Sensor: URIRef # Measures hail in terms of its size and damage potential - Hallway: URIRef # A common space, used to connect other parts of a building - Hazardous_Materials_Storage: URIRef # A storage space set aside (usually with restricted access) for the storage of materials that can be hazardous to living beings or the environment - Heat_Exchanger: URIRef # A heat exchanger is a piece of equipment built for efficient heat transfer from one medium to another. The media may be separated by a solid wall to prevent mixing or they may be in direct contact (BEDES) - Heat_Exchanger_Supply_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of water supplied by a heat exchanger - ) - Heat_Exchanger_System_Enable_Status: ( - URIRef # Indicates if the heat exchanger system has been enabled - ) - Heat_Recovery_Hot_Water_System: URIRef - Heat_Sensor: URIRef # Measures heat - Heat_Wheel: URIRef # A rotary heat exchanger positioned within the supply and exhaust air streams of an air handling system in order to recover heat energy - Heat_Wheel_VFD: URIRef # A VFD that drives a heat wheel - Heating_Coil: URIRef # A heating element typically made of pipe, tube or wire that emits heat. Typically filled with hot water, or, in the case of wire, uses electricity. - Heating_Command: URIRef # Controls the amount of heating to be delivered (typically as a proportion of total heating output) - Heating_Demand_Sensor: URIRef # Measures the amount of power consumed by a heating process; typically found by multiplying the tonnage of a unit (e.g. RTU) by the efficiency rating in kW/ton - Heating_Demand_Setpoint: URIRef # Sets the rate required for heating - Heating_Discharge_Air_Flow_Setpoint: URIRef # Sets discharge air flow for heating - Heating_Discharge_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of heating discharge air - ) - Heating_Discharge_Air_Temperature_Integral_Time_Parameter: URIRef - Heating_Discharge_Air_Temperature_Proportional_Band_Parameter: URIRef - Heating_Start_Stop_Status: URIRef - Heating_Supply_Air_Flow_Setpoint: URIRef # Sets supply air flow rate for heating - Heating_Supply_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of supply air for heating - ) - Heating_Supply_Air_Temperature_Integral_Time_Parameter: URIRef - Heating_Supply_Air_Temperature_Proportional_Band_Parameter: URIRef - Heating_Temperature_Setpoint: URIRef # Sets temperature for heating - Heating_Thermal_Power_Sensor: URIRef - Heating_Valve: URIRef # A valve that controls air temperature by modulating the amount of hot water flowing through a heating coil - Heating_Ventilation_Air_Conditioning_System: URIRef # The equipment, distribution systems and terminals that provide, either collectively or individually, the processes of heating, ventilating or air conditioning to a building or portion of a building - High_CO2_Alarm: ( - URIRef # A device that indicates high concentration of carbon dioxide. - ) - High_Discharge_Air_Temperature_Alarm: ( - URIRef # An alarm that indicates that discharge air temperature is too high - ) - High_Head_Pressure_Alarm: URIRef # An alarm that indicates a high pressure generated on the output side of a gas compressor in a refrigeration or air conditioning system. - High_Humidity_Alarm: ( - URIRef # An alarm that indicates high concentration of water vapor in the air. - ) - High_Humidity_Alarm_Parameter: URIRef # A parameter determining the humidity level at which to trigger a high humidity alarm - High_Outside_Air_Lockout_Temperature_Differential_Parameter: ( - URIRef # The upper bound of the outside air temperature lockout range - ) - High_Return_Air_Temperature_Alarm: ( - URIRef # An alarm that indicates that return air temperature is too high - ) - High_Static_Pressure_Cutout_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a High_Static_Pressure_Cutout_Setpoint. - High_Temperature_Alarm: URIRef # An alarm that indicates high temperature. - High_Temperature_Alarm_Parameter: URIRef # A parameter determining the temperature level at which to trigger a high temperature alarm - High_Temperature_Hot_Water_Return_Temperature_Sensor: URIRef # Measures the temperature of high-temperature hot water returned to a hot water system - High_Temperature_Hot_Water_Supply_Temperature_Sensor: URIRef # Measures the temperature of high-temperature hot water supplied by a hot water system - Hold_Status: URIRef - Hospitality_Box: URIRef # A room at a stadium, usually overlooking the field of play, that is physical separate from the other seating at the venue - Hot_Box: URIRef # hot air chamber forming part of an air handler. - Hot_Water: URIRef # Hot water used for HVAC heating or supply to hot taps - Hot_Water_Baseboard_Radiator: ( - URIRef # Hydronic heating device located at or near the floor - ) - Hot_Water_Coil: URIRef # A heating element typically made of pipe, tube or wire that emits heat that is filled with hot water. - Hot_Water_Differential_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of differential pressure of hot water - ) - Hot_Water_Differential_Pressure_Integral_Time_Parameter: URIRef - Hot_Water_Differential_Pressure_Load_Shed_Reset_Status: URIRef - Hot_Water_Differential_Pressure_Load_Shed_Status: URIRef - Hot_Water_Differential_Pressure_Proportional_Band_Parameter: URIRef - Hot_Water_Differential_Pressure_Sensor: URIRef # Measures the difference in water pressure on either side of a hot water valve - Hot_Water_Differential_Pressure_Setpoint: URIRef # Sets the target water differential pressure between an upstream and downstream point in a water pipe or conduit used to carry hot water - Hot_Water_Differential_Temperature_Sensor: URIRef # Measures the difference in temperature between the entering water to the boiler or other water heating device and leaving water from the same boiler or other water heating device - Hot_Water_Discharge_Flow_Sensor: ( - URIRef # Measures the rate of flow of hot discharge water - ) - Hot_Water_Discharge_Flow_Setpoint: ( - URIRef # Sets the target flow rate of hot discharge water - ) - Hot_Water_Discharge_Temperature_Load_Shed_Status: URIRef - Hot_Water_Flow_Sensor: URIRef # Measures the rate of flow in a hot water circuit - Hot_Water_Flow_Setpoint: URIRef # Sets the target flow rate of hot water - Hot_Water_Loop: URIRef # A collection of equipment that transport and regulate hot water among each other - Hot_Water_Meter: ( - URIRef # A meter that measures the usage or consumption of hot water - ) - Hot_Water_Pump: URIRef # A pump that performs work on hot water; typically part of a hot water system - Hot_Water_Radiator: URIRef # Radiator that uses hot water - Hot_Water_Return_Flow_Sensor: ( - URIRef # Measures the rate of flow of hot return water - ) - Hot_Water_Return_Temperature_Sensor: ( - URIRef # Measures the temperature of water returned to a hot water system - ) - Hot_Water_Static_Pressure_Setpoint: URIRef # Sets static pressure of hot air - Hot_Water_Supply_Flow_Sensor: ( - URIRef # Measures the rate of flow of hot supply water - ) - Hot_Water_Supply_Flow_Setpoint: ( - URIRef # Sets the target flow rate of hot supply water - ) - Hot_Water_Supply_Temperature_High_Reset_Setpoint: URIRef - Hot_Water_Supply_Temperature_Load_Shed_Status: URIRef - Hot_Water_Supply_Temperature_Low_Reset_Setpoint: URIRef - Hot_Water_Supply_Temperature_Sensor: ( - URIRef # Measures the temperature of water supplied by a hot water system - ) - Hot_Water_System: URIRef # The equipment, devices and conduits that handle the production and distribution of hot water in a building - Hot_Water_System_Enable_Command: URIRef # Enables operation of the hot water system - Hot_Water_Temperature_Setpoint: URIRef # Sets the temperature of hot water - Hot_Water_Usage_Sensor: URIRef # Measures the amount of hot water that is consumed, over some period of time - Hot_Water_Valve: URIRef # A valve regulating the flow of hot water - Humidification_Start_Stop_Status: URIRef - Humidifier: URIRef # A device that adds moisture to air or other gases - Humidifier_Fault_Status: URIRef # Indicates the presence of a fault in a humidifier - Humidify_Command: URIRef - Humidity_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the concentration of water vapor in the air. - Humidity_Parameter: ( - URIRef # Parameters relevant to humidity-related systems and points - ) - Humidity_Sensor: URIRef # Measures the concentration of water vapor in air - Humidity_Setpoint: URIRef # Sets humidity - Humidity_Tolerance_Parameter: URIRef # A parameter determining the difference between upper and lower limits of humidity. - IDF: URIRef # An room for an intermediate distribution frame, where cables carrying signals from the main distribution frame terminate and then feed out to endpoints - Ice: URIRef # Water in its solid form - Ice_Tank_Leaving_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of water leaving an ice tank - ) - Illuminance_Sensor: ( - URIRef # Measures the total luminous flux incident on a surface, per unit area - ) - Imbalance_Sensor: URIRef # A sensor which measures difference (imbalance) between phases of an electrical system - Induction_Unit: URIRef # A device with an primary air connection and integrated coil and condensate pan that performs sensible and latent cooling of a space. Essentially an Active Chilled Beam with a built in condensate pan. - Information_Area: URIRef # An information booth or kiosk where visitors would look for information - Inside_Face_Surface_Temperature_Sensor: URIRef # Measures the inside surface (relative to the space) of the radiant panel of the radiant heating and cooling HVAC system. - Inside_Face_Surface_Temperature_Setpoint: URIRef # Sets temperature for the inside face surface temperature of the radiant panel. - Intake_Air_Filter: URIRef # Filters air intake - Intake_Air_Temperature_Sensor: ( - URIRef # Measures air at the interface between the building and the outside - ) - Integral_Gain_Parameter: URIRef - Integral_Time_Parameter: URIRef - Intercom_Equipment: URIRef - Interface: ( - URIRef # A device that provides an occupant control over a lighting system - ) - Intrusion_Detection_Equipment: URIRef - Inverter: URIRef # A device that changes direct current into alternating current - Isolation_Valve: URIRef # A valve that stops the flow of a fluid, usually for maintenance or safety purposes - Janitor_Room: ( - URIRef # A room set aside for the storage of cleaning equipment and supplies - ) - Jet_Nozzle_Air_Diffuser: URIRef # An air diffuser that is designed to produce high velocity discharge air stream to throw the air over a large distance or target the air stream to a localize area - Laboratory: URIRef # facility acceptable to the local, national, or international recognized authority having jurisdiction and which provides uniform testing and examination procedures and standards for meeting design, manufacturing, and factory testing requirements. - Laminar_Flow_Air_Diffuser: URIRef # An air diffuser that is designed for low discharge air speeds to provide uniform and unidirectional air pattern which minimizes room air entrainment - Last_Fault_Code_Status: URIRef # Indicates the last fault code that occurred - Lead_Lag_Command: URIRef # Enables lead/lag operation - Lead_Lag_Status: URIRef # Indicates if lead/lag operation is enabled - Lead_On_Off_Command: URIRef # Controls the active/inactive status of the "lead" part of a lead/lag system - Leak_Alarm: ( - URIRef # An alarm that indicates leaks occurred in systems containing fluids - ) - Leaving_Water: URIRef # Water that is leaving a piece of equipment or system - Leaving_Water_Flow_Sensor: URIRef # Measures the rate of flow of water that is leaving a piece of equipment or system - Leaving_Water_Flow_Setpoint: URIRef # Sets the target flow rate of leaving water - Leaving_Water_Temperature_Sensor: URIRef # Measures the temperature of water leaving a piece of equipment or system - Leaving_Water_Temperature_Setpoint: URIRef # Sets temperature of leaving water - Library: URIRef # A place for the storage and/or consumption of physical media, e.g. books, periodicals, and DVDs/CDs - Lighting: URIRef - Lighting_Equipment: URIRef - Lighting_System: URIRef # The equipment, devices and interfaces that serve or are a part of the lighting subsystem in a building - Lighting_Zone: URIRef - Limit: URIRef # A parameter that places an upper or lower bound on the range of permitted values of another point - Liquid: URIRef # state of matter intermediate between crystalline substances and gases in which the volume of a substance, but not the shape, remains relatively constant. - Liquid_CO2: URIRef # Carbon Dioxide in the liquid phase - Liquid_Detection_Alarm: URIRef - Load_Current_Sensor: URIRef # Measures the current consumed by a load - Load_Parameter: URIRef - Load_Setpoint: URIRef - Load_Shed_Command: ( - URIRef # Controls load shedding behavior provided by a control system - ) - Load_Shed_Differential_Pressure_Setpoint: URIRef - Load_Shed_Setpoint: URIRef - Load_Shed_Status: URIRef # Indicates if a load shedding policy is in effect - Loading_Dock: URIRef # A part of a facility where delivery trucks can load and unload. Usually partially enclosed with specific traffic lanes leading to the dock - Lobby: URIRef # A space just after the entrance to a building or other space of a building, where visitors can wait - Locally_On_Off_Status: URIRef - Location: URIRef - Lockout_Status: URIRef # Indicates if a piece of equipment, system, or functionality has been locked out from operation - Lockout_Temperature_Differential_Parameter: URIRef - Loop: URIRef # A collection of connected equipment; part of a System - Lounge: URIRef # A room for lesiure activities or relaxing - Louver: URIRef # Device consisting of an assembly of parallel sloping vanes, intended to permit the passage of air while providing a measure of protection against environmental influences - Low_Freeze_Protect_Temperature_Parameter: URIRef - Low_Humidity_Alarm: ( - URIRef # An alarm that indicates low concentration of water vapor in the air. - ) - Low_Humidity_Alarm_Parameter: URIRef # A parameter determining the humidity level at which to trigger a low humidity alarm - Low_Outside_Air_Lockout_Temperature_Differential_Parameter: ( - URIRef # The lower bound of the outside air temperature lockout range - ) - Low_Outside_Air_Temperature_Enable_Differential_Sensor: URIRef - Low_Outside_Air_Temperature_Enable_Setpoint: URIRef - Low_Return_Air_Temperature_Alarm: ( - URIRef # An alarm that indicates that return air temperature is too low - ) - Low_Suction_Pressure_Alarm: URIRef # An alarm that indicates a low suction pressure in the compressor in a refrigeration or air conditioning system. - Low_Temperature_Alarm: URIRef # An alarm that indicates low temperature. - Low_Temperature_Alarm_Parameter: URIRef # A parameter determining the temperature level at which to trigger a low temperature alarm - Lowest_Exhaust_Air_Static_Pressure_Sensor: URIRef # The lowest observed static pressure of air in exhaust regions of an HVAC system over some period of time - Luminaire: URIRef # A complete lighting unit consisting of a lamp or lamps and ballast(s) (when applicable) together with the parts designed to distribute the light, to position and protect the lamps, and to connect the lamps to the power supply. - Luminaire_Driver: URIRef # A power source for a luminaire - Luminance_Alarm: URIRef - Luminance_Command: ( - URIRef # Controls the amount of luminance delivered by a lighting system - ) - Luminance_Sensor: URIRef # Measures the luminous intensity per unit area of light travelling in a given direction - Luminance_Setpoint: URIRef # Sets luminance - MAU: URIRef # See Makeup_Air_Unit - MDF: URIRef # A room for the Main Distribution Frame, the central place of a building where cables carrying signals meet and connect to the outside world - Mail_Room: URIRef # A room where mail is received and sorted for distribution to the rest of the building - Maintenance_Mode_Command: URIRef # Controls whether or not a device or controller is operating in "Maintenance" mode - Maintenance_Required_Alarm: URIRef # An alarm that indicates that repair/maintenance is required on an associated device or equipment - Majlis: URIRef # In Arab countries, an Majlis is a private lounge where visitors are received and entertained - Makeup_Air_Unit: URIRef # A device designed to condition ventilation air introduced into a space or to replace air exhausted from a process or general area exhaust. The device may be used to prevent negative pressure within buildings or to reduce airborne contaminants in a space. - Makeup_Water: URIRef # Water used used to makeup water loss through leaks, evaporation, or blowdown - Makeup_Water_Valve: URIRef # A valve regulating the flow of makeup water into a water holding tank, e.g. a cooling tower, hot water tank - Manual_Auto_Status: ( - URIRef # Indicates if a system is under manual or automatic operation - ) - Massage_Room: URIRef # Usually adjunct to an athletic facility, a private/semi-private space where massages are performed - Max_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Air_Flow_Setpoint. - Max_Air_Temperature_Setpoint: URIRef # Setpoint for maximum air temperature - Max_Chilled_Water_Differential_Pressure_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Chilled_Water_Differential_Pressure_Setpoint. - Max_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Cooling_Discharge_Air_Flow_Setpoint. - Max_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Cooling_Supply_Air_Flow_Setpoint. - Max_Discharge_Air_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Discharge_Air_Static_Pressure_Setpoint. - Max_Discharge_Air_Temperature_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Discharge_Air_Temperature_Setpoint. - Max_Frequency_Command: URIRef # Sets the maximum permitted frequency - Max_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Heating_Discharge_Air_Flow_Setpoint. - Max_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Heating_Supply_Air_Flow_Setpoint. - Max_Hot_Water_Differential_Pressure_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Hot_Water_Differential_Pressure_Setpoint. - Max_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Setpoint. - Max_Load_Setpoint: URIRef - Max_Occupied_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Occupied_Cooling_Discharge_Air_Flow_Setpoint. - Max_Occupied_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Occupied_Cooling_Supply_Air_Flow_Setpoint. - Max_Occupied_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Occupied_Heating_Discharge_Air_Flow_Setpoint. - Max_Occupied_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Occupied_Heating_Supply_Air_Flow_Setpoint. - Max_Position_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Position_Setpoint. - Max_Speed_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Speed_Setpoint. - Max_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Static_Pressure_Setpoint. - Max_Supply_Air_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Supply_Air_Static_Pressure_Setpoint. - Max_Temperature_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Temperature_Setpoint. - Max_Unoccupied_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Unoccupied_Cooling_Discharge_Air_Flow_Setpoint. - Max_Unoccupied_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Unoccupied_Cooling_Supply_Air_Flow_Setpoint. - Max_Unoccupied_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Unoccupied_Heating_Discharge_Air_Flow_Setpoint. - Max_Unoccupied_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places an upper bound on the range of permitted values of a Unoccupied_Heating_Supply_Air_Flow_Setpoint. - Max_Water_Level_Alarm: ( - URIRef # Alarm indicating that the maximum water level was reached - ) - Max_Water_Temperature_Setpoint: URIRef # Setpoint for max water temperature - Measurable: URIRef - Mechanical_Room: ( - URIRef # A class of service rooms where mechanical equipment (HVAC) operates - ) - Media_Hot_Desk: URIRef # A non-enclosed space used by members of the media temporarily to cover an event while they are present at a venue - Media_Production_Room: URIRef # A enclosed space used by media professionals for the production of media - Media_Room: URIRef # A class of spaces related to the creation of media - Medical_Room: URIRef # A class of rooms used for medical purposes - Medium_Temperature_Hot_Water_Differential_Pressure_Load_Shed_Reset_Status: URIRef - Medium_Temperature_Hot_Water_Differential_Pressure_Load_Shed_Setpoint: URIRef - Medium_Temperature_Hot_Water_Differential_Pressure_Load_Shed_Status: URIRef - Medium_Temperature_Hot_Water_Differential_Pressure_Sensor: URIRef # Measures the difference in water pressure between sections of a medium temperature hot water system - Medium_Temperature_Hot_Water_Differential_Pressure_Setpoint: URIRef - Medium_Temperature_Hot_Water_Discharge_Temperature_High_Reset_Setpoint: URIRef - Medium_Temperature_Hot_Water_Discharge_Temperature_Low_Reset_Setpoint: URIRef - Medium_Temperature_Hot_Water_Return_Temperature_Sensor: URIRef # Measures the temperature of medium-temperature hot water returned to a hot water system - Medium_Temperature_Hot_Water_Supply_Temperature_High_Reset_Setpoint: URIRef - Medium_Temperature_Hot_Water_Supply_Temperature_Load_Shed_Setpoint: URIRef - Medium_Temperature_Hot_Water_Supply_Temperature_Load_Shed_Status: URIRef - Medium_Temperature_Hot_Water_Supply_Temperature_Low_Reset_Setpoint: URIRef - Medium_Temperature_Hot_Water_Supply_Temperature_Sensor: URIRef # Measures the temperature of medium-temperature hot water supplied by a hot water system - Meter: URIRef # A device that measure usage or consumption of some media --- typically a form energy or power. - Methane_Level_Sensor: URIRef # Measures the concentration of methane in air - Min_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Air_Flow_Setpoint. - Min_Air_Temperature_Setpoint: URIRef # Setpoint for minimum air temperature - Min_Chilled_Water_Differential_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Chilled_Water_Differential_Pressure_Setpoint. - Min_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Cooling_Discharge_Air_Flow_Setpoint. - Min_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Cooling_Supply_Air_Flow_Setpoint. - Min_Discharge_Air_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Discharge_Air_Static_Pressure_Setpoint. - Min_Discharge_Air_Temperature_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Discharge_Air_Temperature_Setpoint. - Min_Fresh_Air_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Fresh_Air_Setpoint. - Min_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Heating_Discharge_Air_Flow_Setpoint. - Min_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Heating_Supply_Air_Flow_Setpoint. - Min_Hot_Water_Differential_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Hot_Water_Differential_Pressure_Setpoint. - Min_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Setpoint. - Min_Occupied_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Occupied_Cooling_Discharge_Air_Flow_Setpoint. - Min_Occupied_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Occupied_Cooling_Supply_Air_Flow_Setpoint. - Min_Occupied_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Occupied_Heating_Discharge_Air_Flow_Setpoint. - Min_Occupied_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Occupied_Heating_Supply_Air_Flow_Setpoint. - Min_Outside_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Outside_Air_Flow_Setpoint. - Min_Position_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Position_Setpoint. - Min_Speed_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Speed_Setpoint. - Min_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Static_Pressure_Setpoint. - Min_Supply_Air_Static_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Supply_Air_Static_Pressure_Setpoint. - Min_Temperature_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Temperature_Setpoint. - Min_Unoccupied_Cooling_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Unoccupied_Cooling_Discharge_Air_Flow_Setpoint. - Min_Unoccupied_Cooling_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Unoccupied_Cooling_Supply_Air_Flow_Setpoint. - Min_Unoccupied_Heating_Discharge_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Unoccupied_Heating_Discharge_Air_Flow_Setpoint. - Min_Unoccupied_Heating_Supply_Air_Flow_Setpoint_Limit: URIRef # A parameter that places a lower bound on the range of permitted values of a Unoccupied_Heating_Supply_Air_Flow_Setpoint. - Min_Water_Level_Alarm: ( - URIRef # Alarm indicating that the minimum water level was reached - ) - Min_Water_Temperature_Setpoint: URIRef # Setpoint for min water temperature - Mixed_Air: URIRef # (1) air that contains two or more streams of air. (2) combined outdoor air and recirculated air. - Mixed_Air_Filter: URIRef # A filter that is applied to the mixture of recirculated and outside air - Mixed_Air_Flow_Sensor: URIRef # Measures the rate of flow of mixed air - Mixed_Air_Humidity_Sensor: URIRef # Measures the humidity of mixed air - Mixed_Air_Humidity_Setpoint: URIRef # Humidity setpoint for mixed air - Mixed_Air_Temperature_Sensor: URIRef # Measures the temperature of mixed air - Mixed_Air_Temperature_Setpoint: URIRef # Sets temperature of mixed air - Mixed_Damper: URIRef # A damper that modulates the flow of the mixed outside and return air streams - Mode_Command: URIRef # Controls the operating mode of a device or controller - Mode_Status: ( - URIRef # Indicates which mode a system, device or control loop is currently in - ) - Motion_Sensor: URIRef # Detects the presence of motion in some area - Motor: URIRef # A machine in which power is applied to do work by the conversion of various forms of energy into mechanical force and motion. - Motor_Control_Center: URIRef # The Motor Control Center is a specialized type of switchgear which provides electrical power to major mechanical systems in the building such as HVAC components. - Motor_Current_Sensor: URIRef # Measures the current consumed by a motor - Motor_Direction_Status: URIRef # Indicates which direction a motor is operating in, e.g. forward or reverse - Motor_On_Off_Status: URIRef - Motor_Speed_Sensor: URIRef - Motor_Torque_Sensor: URIRef # Measures the torque, or rotating power, of a motor - NO2_Level_Sensor: URIRef # Measures the concentration of NO2 in air - NVR: URIRef - Natural_Gas: URIRef # Fossil fuel energy source consisting largely of methane and other hydrocarbons - Natural_Gas_Boiler: URIRef # A closed, pressure vessel that uses natural gas for heating water or other fluids to supply steam or hot water for heating, humidification, or other applications. - Network_Video_Recorder: URIRef - No_Water_Alarm: ( - URIRef # Alarm indicating that there is no water in the equipment or system - ) - Noncondensing_Natural_Gas_Boiler: URIRef # A closed, pressure vessel that uses natural gas with no system to capture latent heat for heating water or other fluids to supply steam or hot water for heating, humidification, or other applications. - Occupancy_Command: URIRef # Controls whether or not a device or controller is operating in "Occupied" mode - Occupancy_Sensor: URIRef # Detects occupancy of some space or area - Occupancy_Status: URIRef # Indicates if a room or space is occupied - Occupied_Air_Temperature_Setpoint: URIRef - Occupied_Cooling_Discharge_Air_Flow_Setpoint: ( - URIRef # Sets discharge air flow for cooling when occupied - ) - Occupied_Cooling_Supply_Air_Flow_Setpoint: ( - URIRef # Sets supply air flow rate for cooling when occupied - ) - Occupied_Cooling_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature for cooling when occupied - ) - Occupied_Discharge_Air_Flow_Setpoint: ( - URIRef # Sets discharge air flow when occupied - ) - Occupied_Discharge_Air_Temperature_Setpoint: URIRef - Occupied_Heating_Discharge_Air_Flow_Setpoint: ( - URIRef # Sets discharge air flow for heating when occupied - ) - Occupied_Heating_Supply_Air_Flow_Setpoint: ( - URIRef # Sets supply air flow rate for heating when occupied - ) - Occupied_Heating_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature for heating when occupied - ) - Occupied_Mode_Status: ( - URIRef # Indicates if a system, device or control loop is in "Occupied" mode - ) - Occupied_Return_Air_Temperature_Setpoint: URIRef - Occupied_Room_Air_Temperature_Setpoint: URIRef - Occupied_Supply_Air_Flow_Setpoint: URIRef # Sets supply air flow rate when occupied - Occupied_Supply_Air_Temperature_Setpoint: URIRef - Occupied_Zone_Air_Temperature_Setpoint: URIRef - Off_Command: URIRef # An Off Command controls or reports the binary 'off' status of a control loop, relay or equipment activity. It can only be used to stop/deactivate an associated equipment or process, or determine that the related entity is 'off' - Off_Status: URIRef # Indicates if a control loop, relay or equipment is off - Office: URIRef # A class of rooms dedicated for work or study - Office_Kitchen: URIRef # A common space, usually near or in a breakroom, where minor food preparation occurs - Oil: URIRef # a viscous liquid derived from petroleum, especially for use as a fuel or lubricant. - On_Command: URIRef # An On Command controls or reports the binary 'on' status of a control loop, relay or equipment activity. It can only be used to start/activate an associated equipment or process, or determine that the related entity is 'on' - On_Off_Command: URIRef # An On/Off Command controls or reports the binary status of a control loop, relay or equipment activity - On_Off_Status: ( - URIRef # Indicates the on/off status of a control loop, relay or equipment - ) - On_Status: URIRef # Indicates if a control loop, relay or equipment is on - On_Timer_Sensor: URIRef # Measures the duration for which a device was in an active or "on" state - Open_Close_Status: ( - URIRef # Indicates the open/close status of a device such as a damper or valve - ) - Open_Heating_Valve_Outside_Air_Temperature_Setpoint: URIRef - Open_Office: URIRef # An open space used for work or study by multiple people. Usuaully subdivided into cubicles or desks - Operating_Mode_Status: URIRef # Indicates the current operating mode of a system, device or control loop - Outdoor_Area: URIRef # A class of spaces that exist outside of a building - Output_Frequency_Sensor: URIRef - Output_Voltage_Sensor: ( - URIRef # Measures the voltage output by some process or device - ) - Outside: URIRef - Outside_Air: URIRef # air external to a defined zone (e.g., corridors). - Outside_Air_CO2_Sensor: URIRef # Measures the concentration of CO2 in outside air - Outside_Air_CO_Sensor: URIRef # Measures the concentration of CO in outside air - Outside_Air_Dewpoint_Sensor: ( - URIRef # Senses the dewpoint temperature of outside air - ) - Outside_Air_Enthalpy_Sensor: ( - URIRef # Measures the total heat content of outside air - ) - Outside_Air_Flow_Sensor: ( - URIRef # Measures the rate of flow of outside air into the system - ) - Outside_Air_Flow_Setpoint: URIRef # Sets outside air flow rate - Outside_Air_Grains_Sensor: URIRef # Measures the mass of water vapor in outside air - Outside_Air_Humidity_Sensor: URIRef # Measures the relative humidity of outside air - Outside_Air_Humidity_Setpoint: URIRef # Humidity setpoint for outside air - Outside_Air_Lockout_Temperature_Differential_Parameter: URIRef - Outside_Air_Lockout_Temperature_Setpoint: URIRef - Outside_Air_Temperature_Enable_Differential_Sensor: URIRef - Outside_Air_Temperature_High_Reset_Setpoint: URIRef - Outside_Air_Temperature_Low_Reset_Setpoint: URIRef - Outside_Air_Temperature_Sensor: URIRef # Measures the temperature of outside air - Outside_Air_Temperature_Setpoint: URIRef # Sets temperature of outside air - Outside_Air_Wet_Bulb_Temperature_Sensor: ( - URIRef # A sensor measuring the wet-bulb temperature of outside air - ) - Outside_Damper: URIRef # A damper that modulates the flow of outside air - Outside_Face_Surface_Temperature_Sensor: URIRef # Measures the outside surface (relative to the space) of the radiant panel of a radiant heating and cooling HVAC system. - Outside_Face_Surface_Temperature_Setpoint: URIRef # Sets temperature for the outside face surface temperature of the radiant panel. - Outside_Illuminance_Sensor: ( - URIRef # Measures the total luminous flux incident on an outside, per unit area - ) - Overload_Alarm: ( - URIRef # An alarm that can indicate when a full-load current is exceeded. - ) - Overridden_Off_Status: URIRef # Indicates if a control loop, relay or equipment has been turned off when it would otherwise be scheduled to be on - Overridden_On_Status: URIRef # Indicates if a control loop, relay or equipment has been turned on when it would otherwise be scheduled to be off - Overridden_Status: URIRef # Indicates if the expected operating status of an equipment or control loop has been overridden - Override_Command: URIRef # Controls or reports whether or not a device or control loop is in 'override' - Ozone_Level_Sensor: URIRef # Measures the concentration of ozone in air - PAU: URIRef # A type of AHU, use to pre-treat the outdoor air before feed to AHU - PID_Parameter: URIRef - PIR_Sensor: URIRef # Detects the presence of motion in some area using the differential change in infrared intensity between two or more receptors - PM10_Level_Sensor: URIRef # Detects level of particulates of size 10 microns - PM10_Sensor: URIRef # Detects matter of size 10 microns - PM1_Level_Sensor: URIRef # Detects level of particulates of size 1 microns - PM1_Sensor: URIRef # Detects matter of size 1 micron - PVT_Panel: URIRef # A type of solar panels that convert solar radiation into usable thermal and electrical energy - PV_Array: URIRef - PV_Current_Output_Sensor: URIRef # See Photovoltaic_Current_Output_Sensor - PV_Generation_System: ( - URIRef # A collection of photovoltaic devices that generates energy - ) - PV_Panel: URIRef # An integrated assembly of interconnected photovoltaic cells designed to deliver a selected level of working voltage and current at its output terminals packaged for protection against environment degradation and suited for incorporation in photovoltaic power systems. - Parameter: URIRef # Parameter points are configuration settings used to guide the operation of equipment and control systems; for example they may provide bounds on valid setpoint values - Parking_Level: URIRef # A floor of a parking structure - Parking_Space: URIRef # An area large enough to park an individual vehicle - Parking_Structure: ( - URIRef # A building or part of a building devoted to vehicle parking - ) - Particulate_Matter_Sensor: URIRef # Detects pollutants in the ambient air - Passive_Chilled_Beam: URIRef # A chilled beam that does not have an integral air supply and instead relies on natural convection to draw air through the device. - Peak_Power_Demand_Sensor: ( - URIRef # The peak power consumed by a process over some period of time - ) - Photovoltaic_Array: URIRef # A collection of photovoltaic panels - Photovoltaic_Current_Output_Sensor: URIRef # Senses the amperes of electrical current produced as output by a photovoltaic device - Piezoelectric_Sensor: URIRef # Senses changes pressure, acceleration, temperature, force or strain via the piezoelectric effect - PlugStrip: URIRef # A device containing a block of electrical sockets allowing multiple electrical devices to be powered from a single electrical socket. - Plumbing_Room: URIRef # A service room devoted to the operation and routing of water in a building. Usually distinct from the HVAC subsystems. - Point: URIRef - Portfolio: URIRef # A collection of sites - Position_Command: URIRef # Controls or reports the position of some object - Position_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Position_Setpoint. - Position_Sensor: URIRef # Measures the current position of a component in terms of a fraction of its full range of motion - Potable_Water: URIRef # Water that is safe to drink - Power_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with electrical power. - Power_Loss_Alarm: URIRef # An alarm that indicates a power failure. - Power_Sensor: URIRef # Measures the amount of instantaneous power consumed - Prayer_Room: URIRef # A room set aside for prayer - Pre_Filter: URIRef # A filter installed in front of a more efficient filter to extend the life of the more expensive higher efficiency filter - Pre_Filter_Status: URIRef # Indicates if a prefilter needs to be replaced - Preheat_Demand_Setpoint: URIRef # Sets the rate required for preheat - Preheat_Discharge_Air_Temperature_Sensor: ( - URIRef # Measures the temperature of discharge air before heating is applied - ) - Preheat_Hot_Water_System: URIRef - Preheat_Hot_Water_Valve: URIRef - Preheat_Supply_Air_Temperature_Sensor: ( - URIRef # Measures the temperature of supply air before it is heated - ) - Pressure_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with pressure. - Pressure_Sensor: URIRef # Measure the amount of force acting on a unit area - Pressure_Setpoint: URIRef # Sets pressure - Pressure_Status: URIRef # Indicates if pressure is within expected bounds - Private_Office: ( - URIRef # An office devoted to a single individual, with walls and door - ) - Proportional_Band_Parameter: URIRef - Proportional_Gain_Parameter: URIRef - Pump: URIRef # Machine for imparting energy to a fluid, causing it to do work, drawing a fluid into itself through an entrance port, and forcing the fluid out through an exhaust port. - Pump_Command: URIRef # Controls or reports the speed of a pump (typically as a proportion of its full pumping capacity) - Pump_On_Off_Status: URIRef - Pump_Room: URIRef # A mechanical room that houses pumps - Pump_VFD: URIRef # Variable-frequency drive for pumps - Quantity: URIRef - RC_Panel: URIRef # See Radiant_Ceiling_Panel - RTU: URIRef # see Rooftop_Unit - RVAV: URIRef # See Variable_Air_Volume_Box_With_Reheat - Radiant_Ceiling_Panel: URIRef # Radiant panel heating and cooling system that are usually made from metal and suspended under the ceiling or insulated from the building structure. - Radiant_Panel: URIRef # A temperature-controlled surface that provides fifty percent (50%) or more of the design heat transfer by thermal radiation. - Radiant_Panel_Temperature_Sensor: URIRef # Measures the temperature of the radiant panel of the radiant heating and cooling HVAC system. - Radiant_Panel_Temperature_Setpoint: URIRef # Sets temperature of radiant panel. - Radiation_Hot_Water_System: URIRef - Radiator: URIRef # Heat exchangers designed to transfer thermal energy from one medium to another - Radioactivity_Concentration_Sensor: ( - URIRef # Measures the concentration of radioactivity - ) - Radon_Concentration_Sensor: ( - URIRef # Measures the concentration of radioactivity due to radon - ) - Rain_Duration_Sensor: ( - URIRef # Measures the duration of precipitation within some time frame - ) - Rain_Sensor: URIRef # Measures the amount of precipitation fallen - Rated_Speed_Setpoint: URIRef # Sets rated speed - Reactive_Power_Sensor: URIRef # Measures the portion of power that, averaged over a complete cycle of the AC waveform, is due to stored energy which returns to the source in each cycle - Reception: URIRef # A space, usually in a lobby, where visitors to a building or space can go to after arriving at a building and inform building staff that they have arrived - Region: URIRef # A unit of geographic space, usually contiguous or somehow related to a geopolitical feature - Reheat_Hot_Water_System: URIRef - Reheat_Valve: URIRef # A valve that controls air temperature by modulating the amount of hot water flowing through a reheat coil - Relative_Humidity_Sensor: URIRef # Measures the present state of absolute humidity relative to a maximum humidity given the same temperature - Relief_Damper: URIRef # A damper that is a component of a Relief Air System, ensuring building doesn't become over-pressurised - Relief_Fan: URIRef # A fan that is a component of a Relief Air System, ensuring building doesn't become over-pressurised - Remotely_On_Off_Status: URIRef - Reset_Command: ( - URIRef # Commands that reset a flag, property or value to its default - ) - Reset_Setpoint: URIRef # Setpoints used in reset strategies - Rest_Room: URIRef # A room that provides toilets and washbowls. Alternate spelling of Restroom - Restroom: URIRef # A room that provides toilets and washbowls. - Retail_Room: URIRef # A space set aside for retail in a larger establishment, e.g. a gift shop in a hospital - Return_Air: URIRef # air removed from a space to be recirculated or exhausted. Air extracted from a space and totally or partially returned to an air conditioner, furnace, or other heating, cooling, or ventilating system. - Return_Air_CO2_Sensor: URIRef # Measures the concentration of CO2 in return air - Return_Air_CO2_Setpoint: URIRef # Sets some property of CO2 in Return Air - Return_Air_CO_Sensor: URIRef # Measures the concentration of CO in return air - Return_Air_Dewpoint_Sensor: URIRef # Senses the dewpoint temperature of return air - Return_Air_Differential_Pressure_Sensor: ( - URIRef # Measures the difference in pressure between the return and supply side - ) - Return_Air_Differential_Pressure_Setpoint: URIRef # Sets the target air differential pressure between an upstream and downstream point in a return air duct or conduit - Return_Air_Enthalpy_Sensor: URIRef # Measures the total heat content of return air - Return_Air_Filter: URIRef # Filters return air - Return_Air_Flow_Sensor: URIRef # Measures the rate of flow of return air - Return_Air_Grains_Sensor: URIRef # Measures the mass of water vapor in return air - Return_Air_Humidity_Sensor: URIRef # Measures the relative humidity of return air - Return_Air_Humidity_Setpoint: URIRef # Humidity setpoint for return air - Return_Air_Plenum: URIRef # A component of the HVAC the receives air from the room to recirculate or exhaust to or from the building - Return_Air_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the temperature of return air. - Return_Air_Temperature_High_Reset_Setpoint: URIRef - Return_Air_Temperature_Low_Reset_Setpoint: URIRef - Return_Air_Temperature_Sensor: URIRef # Measures the temperature of return air - Return_Air_Temperature_Setpoint: URIRef # The target temperature for return air, often used as an approximation of zone air temperature - Return_Chilled_Water_Temperature_Setpoint: URIRef # Sets the temperature of return (downstream of the chilled water load) chilled water - Return_Condenser_Water: URIRef # In a condenser water loop, this is water being brought away from the condenser side of a heat-rejection device (e.g. chiller). It is the 'warm' side. - Return_Condenser_Water_Flow_Sensor: ( - URIRef # Measures the flow of the return condenser water - ) - Return_Condenser_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of the return condenser water - ) - Return_Condenser_Water_Temperature_Setpoint: ( - URIRef # The temperature setpoint for the return condenser water - ) - Return_Damper: URIRef # A damper that modulates the flow of return air - Return_Fan: URIRef # Fan moving return air -- air that is circulated from the building back into the HVAC system - Return_Heating_Valve: ( - URIRef # A valve installed on the return side of a heat exchanger - ) - Return_Hot_Water: URIRef - Return_Hot_Water_Temperature_Setpoint: URIRef # Sets the temperature of return (downstream of the hot water load) hot water - Return_Water: ( - URIRef # The water is a system after it is used in a heat transfer cycle - ) - Return_Water_Flow_Sensor: URIRef - Return_Water_Temperature_Sensor: URIRef # Measures the temperature of return water - Return_Water_Temperature_Setpoint: URIRef # Sets the temperature of return water - Riser: URIRef # A vertical shaft indented for installing building infrastructure e.g., electrical wire, network communication wire, plumbing, etc - Rooftop: URIRef - Rooftop_Unit: URIRef # Packaged air conditioner mounted on a roof, the conditioned air being discharged directly into the rooms below or through a duct system. - Room: URIRef # Base class for all more specific room types. - Room_Air_Temperature_Setpoint: URIRef # Sets temperature of room air - Run_Enable_Command: URIRef - Run_Request_Status: ( - URIRef # Indicates if a request has been filed to start a device or equipment - ) - Run_Status: URIRef - Run_Time_Sensor: URIRef # Measures the duration for which a device was in an active or "on" state - Safety_Equipment: URIRef - Safety_Shower: URIRef - Safety_System: URIRef - Sash_Position_Sensor: URIRef # Measures the current position of a sash in terms of the percent of fully open - Schedule_Temperature_Setpoint: ( - URIRef # The current setpoint as indicated by the schedule - ) - Security_Equipment: URIRef - Security_Service_Room: ( - URIRef # A class of spaces used by the security staff of a facility - ) - Sensor: URIRef # A Sensor is an input point that represents the value of a device or instrument designed to detect and measure a variable (ASHRAE Dictionary). - Server_Room: URIRef - Service_Room: URIRef # A class of spaces related to the operations of building subsystems, e.g. HVAC, electrical, IT, plumbing, etc - Setpoint: ( - URIRef # A Setpoint is an input value at which the desired property is set - ) - Shading_System: URIRef # Devices that can control daylighting through various means - Shared_Office: URIRef # An office used by multiple people - Short_Cycle_Alarm: URIRef # An alarm that indicates a short cycle occurred. A short cycle occurs when a cooling cycle is prevented from completing its full cycle - Shower: URIRef # A space containing showers, usually adjacent to an athletic or execise area - Site: URIRef # A geographic region containing 0 or more buildings. Typically used as the encapsulating location for a collection of Brick entities through the hasSite/isSiteOf relationships - Smoke_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with smoke. - Smoke_Detection_Alarm: URIRef - Solar_Azimuth_Angle_Sensor: URIRef # Measures the azimuth angle of the sun - Solar_Radiance_Sensor: URIRef # The amount of light that passes through or is emitted from the sun and falls within a given solid angle in a specified direction - Solar_Thermal_Collector: URIRef # A type of solar panels that converts solar radiation into thermal energy. - Solar_Zenith_Angle_Sensor: URIRef # Measures the zenith angle of the sun - Solid: URIRef # one of the three states or phases of matter characterized by stability of dimensions, relative incompressibility, and molecular motion held to limited oscillation. - Space: URIRef # A part of the physical world or a virtual world whose 3D spatial extent is bounded actually or theoretically, and provides for certain functions within the zone it is contained in. - Space_Heater: URIRef # A heater used to warm the air in an enclosed area, such as a room or office - Speed_Reset_Command: URIRef - Speed_Sensor: URIRef # Measures the magnitude of velocity of some form of movement - Speed_Setpoint: URIRef # Sets speed - Speed_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Speed_Setpoint. - Speed_Status: ( - URIRef # Indicates the operating speed of a device or equipment, e.g. fan - ) - Sports_Service_Room: URIRef # A class of spaces used in the support of sports - Stage_Enable_Command: URIRef # A point representing a discrete stage which the equipment should be operating at. The desired stage number should be identified by an entity property - Stage_Riser: URIRef # A low platform in a space or on a stage - Stages_Status: URIRef # Indicates which stage a control loop or equipment is in - Staircase: URIRef # A vertical space containing stairs - Standby_CRAC: URIRef # A CRAC that is activated as part of a lead/lag operation or when an alarm occurs in a primary unit - Standby_Fan: URIRef # Fan that is activated as part of a lead/lag operation or when a primary fan raises an alarm - Standby_Glycool_Unit_On_Off_Status: ( - URIRef # Indicates the on/off status of a standby glycool unit - ) - Standby_Load_Shed_Command: URIRef - Standby_Unit_On_Off_Status: URIRef # Indicates the on/off status of a standby unit - Start_Stop_Command: URIRef # A Start/Stop Command controls or reports the active/inactive status of a control sequence - Start_Stop_Status: URIRef # Indicates the active/inactive status of a control loop (but not equipment activities or relays -- use On/Off for this purpose) - Static_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of static pressure - ) - Static_Pressure_Integral_Time_Parameter: URIRef - Static_Pressure_Proportional_Band_Parameter: URIRef - Static_Pressure_Sensor: URIRef # Measures resistance to airflow in a heating and cooling system's components and duct work - Static_Pressure_Setpoint: URIRef # Sets static pressure - Static_Pressure_Setpoint_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Static_Pressure_Setpoint. - Static_Pressure_Step_Parameter: URIRef - Status: URIRef # A Status is input point that reports the current operating mode, state, position, or condition of an item. Statuses are observations and should be considered 'read-only' - Steam: URIRef # water in the vapor phase. - Steam_Baseboard_Radiator: ( - URIRef # Steam heating device located at or near the floor - ) - Steam_Distribution: URIRef # Utilize a steam distribution source to represent how steam is distributed across multiple destinations - Steam_On_Off_Command: URIRef - Steam_Radiator: URIRef # Radiator that uses steam - Steam_System: URIRef # The equipment, devices and conduits that handle the production and distribution of steam in a building - Steam_Usage_Sensor: URIRef # Measures the amount of steam that is consumed or used, over some period of time - Steam_Valve: URIRef - Step_Parameter: URIRef - Storage_Room: URIRef # A class of spaces used for storage - Storey: URIRef - Studio: URIRef # A room used for the production or media, usually with either a specialized set or a specialized sound booth for recording - Substance: URIRef - Supply_Air: URIRef # (1) air delivered by mechanical or natural ventilation to a space, composed of any combination of outdoor air, recirculated air, or transfer air. (2) air entering a space from an air-conditioning, heating, or ventilating apparatus for the purpose of comfort conditioning. Supply air is generally filtered, fan forced, and either heated, cooled, humidified, or dehumidified as necessary to maintain specified conditions. Only the quantity of outdoor air within the supply airflow may be used as replacement air. - Supply_Air_Differential_Pressure_Sensor: URIRef # Measures the difference in pressure between an upstream and downstream of an air duct or other air conduit used to supply air into the building - Supply_Air_Differential_Pressure_Setpoint: URIRef # Sets the target air differential pressure between an upstream and downstream point in a supply air duct or conduit - Supply_Air_Duct_Pressure_Status: ( - URIRef # Indicates if air pressure in supply duct is within expected bounds - ) - Supply_Air_Flow_Demand_Setpoint: ( - URIRef # Sets the rate of supply air flow required for a process - ) - Supply_Air_Flow_Sensor: URIRef # Measures the rate of flow of supply air - Supply_Air_Flow_Setpoint: URIRef # Sets supply air flow rate - Supply_Air_Humidity_Sensor: URIRef # Measures the relative humidity of supply air - Supply_Air_Humidity_Setpoint: URIRef # Humidity setpoint for supply air - Supply_Air_Integral_Gain_Parameter: URIRef - Supply_Air_Plenum: URIRef # A component of the HVAC the receives air from the air handling unit to distribute to the building - Supply_Air_Proportional_Gain_Parameter: URIRef - Supply_Air_Static_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of static pressure of supply air - ) - Supply_Air_Static_Pressure_Integral_Time_Parameter: URIRef - Supply_Air_Static_Pressure_Proportional_Band_Parameter: URIRef - Supply_Air_Static_Pressure_Sensor: ( - URIRef # The static pressure of air within supply regions of an HVAC system - ) - Supply_Air_Static_Pressure_Setpoint: URIRef # Sets static pressure of supply air - Supply_Air_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with the temperature of supply air. - Supply_Air_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of supply air - ) - Supply_Air_Temperature_High_Reset_Setpoint: URIRef - Supply_Air_Temperature_Low_Reset_Setpoint: URIRef - Supply_Air_Temperature_Proportional_Band_Parameter: URIRef - Supply_Air_Temperature_Reset_Differential_Setpoint: URIRef - Supply_Air_Temperature_Sensor: URIRef # Measures the temperature of supply air - Supply_Air_Temperature_Setpoint: URIRef # Temperature setpoint for supply air - Supply_Air_Temperature_Step_Parameter: URIRef - Supply_Air_Velocity_Pressure_Sensor: URIRef - Supply_Chilled_Water: URIRef - Supply_Chilled_Water_Temperature_Setpoint: ( - URIRef # Temperature setpoint for supply chilled water - ) - Supply_Condenser_Water: URIRef # In a condenser water loop, this is water being brought to the condenser side of a heat-rejection device (e.g. chiller). It is the 'cold' side. - Supply_Condenser_Water_Flow_Sensor: ( - URIRef # Measures the flow of the supply condenser water - ) - Supply_Condenser_Water_Temperature_Sensor: ( - URIRef # Measures the temperature of the supply condenser water - ) - Supply_Condenser_Water_Temperature_Setpoint: ( - URIRef # The temperature setpoint for the supply condenser water - ) - Supply_Fan: URIRef # Fan moving supply air -- air that is supplied from the HVAC system into the building - Supply_Hot_Water: URIRef - Supply_Hot_Water_Temperature_Setpoint: ( - URIRef # Temperature setpoint for supply hot water - ) - Supply_Water: URIRef - Supply_Water_Differential_Pressure_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of differential pressure of supply water - ) - Supply_Water_Differential_Pressure_Integral_Time_Parameter: URIRef - Supply_Water_Differential_Pressure_Proportional_Band_Parameter: URIRef - Supply_Water_Flow_Sensor: URIRef # Measures the rate of flow of hot supply water - Supply_Water_Flow_Setpoint: URIRef # Sets the flow rate of hot supply water - Supply_Water_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with temperature of the supply water. - Supply_Water_Temperature_Deadband_Setpoint: ( - URIRef # Sets the size of a deadband of temperature of supply water - ) - Supply_Water_Temperature_Integral_Time_Parameter: URIRef - Supply_Water_Temperature_Proportional_Band_Parameter: URIRef - Supply_Water_Temperature_Setpoint: URIRef # Sets temperature of supply water - Surveillance_Camera: URIRef - Switch: URIRef # A switch used to operate all or part of a lighting installation - Switch_Room: URIRef # A telecommuncations room housing network switches - Switchgear: URIRef # A main disconnect or service disconnect feeds power to a switchgear, which then distributes power to the rest of the building through smaller amperage-rated disconnects. - System: URIRef # A System is a combination of equipment and auxiliary devices (e.g., controls, accessories, interconnecting means, and termi­nal elements) by which energy is transformed so it performs a specific function such as HVAC, service water heating, or lighting. (ASHRAE Dictionary). - System_Enable_Command: URIRef # Enables operation of a system - System_Shutdown_Status: URIRef # Indicates if a system has been shutdown - System_Status: URIRef # Indicates properties of the activity of a system - TABS_Panel: URIRef # See Thermally_Activated_Building_System_Panel - TETRA_Room: URIRef # A room used for local two-way radio networks, e.g. the portable radios carried by facilities staff - TVOC_Level_Sensor: URIRef # A sensor measuring the level of all VOCs in air - TVOC_Sensor: URIRef - Team_Room: URIRef # An office used by multiple team members for specific work tasks. Distinct from Conference Room - Telecom_Room: ( - URIRef # A class of spaces used to support telecommuncations and IT equipment - ) - Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with temperature. - Temperature_Deadband_Setpoint: URIRef # Sets the size of a deadband of temperature - Temperature_Differential_Reset_Setpoint: URIRef - Temperature_High_Reset_Setpoint: URIRef - Temperature_Low_Reset_Setpoint: URIRef - Temperature_Parameter: ( - URIRef # Parameters relevant to temperature-related systems and points - ) - Temperature_Sensor: URIRef # Measures temperature: the physical property of matter that quantitatively expresses the common notions of hot and cold - Temperature_Setpoint: URIRef # Sets temperature - Temperature_Step_Parameter: URIRef - Temperature_Tolerance_Parameter: URIRef # A parameter determining the difference between upper and lower limits of temperature. - Temporary_Occupancy_Status: URIRef # For systems that differentiate between scheduled occupied/unoccupied mode, this indicates if a space is temporarily occupied when it would otherwise be unoccupied - Terminal_Unit: URIRef # A device that regulates the volumetric flow rate and/or the temperature of the controlled medium. - Thermal_Power_Meter: URIRef # A standalone thermal power meter - Thermal_Power_Sensor: URIRef - Thermally_Activated_Building_System_Panel: URIRef # Radiant panel heating and cooling system where the energy heat source or sink is embedded in the building structure such as in slabs and walls. - Thermostat: URIRef # An automatic control device used to maintain temperature at a fixed or adjustable setpoint. - Ticketing_Booth: URIRef # A room or space used to sell or distribute tickets to events at a venue - Time_Parameter: URIRef - Time_Setpoint: URIRef - Tolerance_Parameter: URIRef # difference between upper and lower limits of size for a given nominal dimension or value. - Torque_Sensor: URIRef # Measures torque, the tendency of a force to rotate an object about some axis - Touchpanel: URIRef # A switch used to operate all or part of a lighting installation that uses a touch-based mechanism (typically resistive or capacitive) rather than a mechanical actuator - Trace_Heat_Sensor: URIRef # Measures the surface temperature of pipelines carrying temperature-sensitive products; typically used to avoid frosting/freezing - Transformer: URIRef # A Transformer is usually fed by a high-voltage source and then steps down the voltage to a lower-voltage feed for low-voltage application (such as lights). Transformers also can step up voltage, but this generally does not apply to in building distribution. - Transformer_Room: URIRef # An electrical room where electricity enters and is transformed to different voltages and currents by the equipment contained in the room - Tunnel: URIRef # An enclosed space that connects buildings. Often underground - Underfloor_Air_Plenum: URIRef # An open space between a structural concrete slab and the underside of a raised access floor system that connects to an air handling unit to receive conditioned and/or ventilating air before delivery to the room(s) - Underfloor_Air_Plenum_Static_Pressure_Sensor: URIRef # Measures the outward push of air against the plenum surfaces and used to measure the resistance when air moves through the plenum - Underfloor_Air_Plenum_Static_Pressure_Setpoint: ( - URIRef # Sets the underfloor air plenum static pressure - ) - Underfloor_Air_Temperature_Sensor: ( - URIRef # Measures the temperature of underfloor air - ) - Unit_Failure_Alarm: ( - URIRef # An alarm that indicates the failure of an equipment or device - ) - Unoccupied_Air_Temperature_Cooling_Setpoint: ( - URIRef # Sets temperature of air when unoccupied for cooling - ) - Unoccupied_Air_Temperature_Heating_Setpoint: ( - URIRef # Sets temperature of air when unoccupied for heating - ) - Unoccupied_Air_Temperature_Setpoint: ( - URIRef # Sets temperature of air when unoccupied - ) - Unoccupied_Cooling_Discharge_Air_Flow_Setpoint: ( - URIRef # Sets discharge air flow for cooling when unoccupied - ) - Unoccupied_Discharge_Air_Temperature_Setpoint: URIRef - Unoccupied_Load_Shed_Command: URIRef - Unoccupied_Return_Air_Temperature_Setpoint: URIRef - Unoccupied_Room_Air_Temperature_Setpoint: URIRef - Unoccupied_Supply_Air_Temperature_Setpoint: URIRef - Unoccupied_Zone_Air_Temperature_Setpoint: URIRef - Usage_Sensor: URIRef # Measures the amount of some substance that is consumed or used, over some period of time - VAV: URIRef # See Variable_Air_Volume_Box - VFD: URIRef # Electronic device that varies its output frequency to vary the rotating speed of a motor, given a fixed input frequency. Used with fans or pumps to vary the flow in the system as a function of a maintained pressure. - VFD_Enable_Command: URIRef # Enables operation of a variable frequency drive - Valve: URIRef # A device that regulates, directs or controls the flow of a fluid by opening, closing or partially obstructing various passageways - Valve_Command: URIRef # Controls or reports the openness of a valve (typically as a proportion of its full range of motion) - Valve_Position_Sensor: URIRef # Measures the current position of a valve in terms of the percent of fully open - Variable_Air_Volume_Box: URIRef # A device that regulates the volume and temperature of air delivered to a zone by opening or closing a damper - Variable_Air_Volume_Box_With_Reheat: URIRef # A VAV box with a reheat coil mounted on the discharge end of the unit that can heat the air delivered to a zone - Variable_Frequency_Drive: URIRef # Electronic device that varies its output frequency to vary the rotating speed of a motor, given a fixed input frequency. Used with fans or pumps to vary the flow in the system as a function of a maintained pressure. - Velocity_Pressure_Sensor: ( - URIRef # Measures the difference between total pressure and static pressure - ) - Velocity_Pressure_Setpoint: URIRef # Sets static veloicty pressure - Vent_Operating_Mode_Status: URIRef # Indicates the current operating mode of a vent - Ventilation_Air_Flow_Ratio_Limit: URIRef # A parameter that places a lower or upper bound on the range of permitted values of a Ventilation_Air_Flow_Ratio_Setpoint. - Ventilation_Air_System: URIRef # The equipment, devices, and conduits that handle the introduction and distribution of ventilation air in the building - Vertical_Space: ( - URIRef # A class of spaces used to connect multiple floors or levels.. - ) - Video_Intercom: URIRef - Video_Surveillance_Equipment: URIRef - Visitor_Lobby: URIRef # A lobby for visitors to the building. Sometimes used to distinguish from an employee entrance looby - Voltage_Imbalance_Sensor: URIRef # A sensor which measures the voltage difference (imbalance) between phases of an electrical system - Voltage_Sensor: URIRef # Measures the voltage of an electrical device or object - Wardrobe: URIRef # Storage for clothing, costumes, or uniforms - Warm_Cool_Adjust_Sensor: URIRef # User provided adjustment of zone temperature, typically in the range of +/- 5 degrees - Warmest_Zone_Air_Temperature_Sensor: URIRef # The zone temperature that is warmest; drives the supply temperature of cold air. A computed value rather than a physical sensor. Also referred to as a 'Highest Zone Air Temperature Sensor' - Waste_Storage: URIRef # A room used for storing waste such as trash or recycling - Water: URIRef # transparent, odorless, tasteless liquid; a compound of hydrogen and oxygen (H2O), containing 11.188% hydrogen and 88.812% oxygen by mass; freezing at 32°F (0°C); boiling near 212°F (100°C). - Water_Alarm: URIRef # Alarm that indicates an undesirable event with a pipe, container, or equipment carrying water e.g. water leak - Water_Differential_Pressure_Setpoint: URIRef # Sets the target water differential pressure between an upstream and downstream point in a water pipe or conduit - Water_Differential_Temperature_Sensor: URIRef # Measures the difference in water temperature between an upstream and downstream point in a pipe or conduit - Water_Differential_Temperature_Setpoint: URIRef # Sets the target differential temperature between the start and end of a heat transfer cycle in a water circuit - Water_Distribution: URIRef # Utilize a water distribution source to represent how water is distributed across multiple destinations (pipes) - Water_Flow_Sensor: URIRef # Measures the rate of flow of water - Water_Flow_Setpoint: URIRef # Sets the target flow rate of water - Water_Heater: URIRef # An apparatus for heating and usually storing hot water - Water_Level_Alarm: ( - URIRef # An alarm that indicates a high or low water level e.g. in a basin - ) - Water_Level_Sensor: URIRef # Measures the height/level of water in some container - Water_Loop: URIRef # A collection of equipment that transport and regulate water among each other - Water_Loss_Alarm: ( - URIRef # An alarm that indicates a loss of water e.g. during transport - ) - Water_Meter: URIRef # A meter that measures the usage or consumption of water - Water_Pump: URIRef # A pump that performs work on water - Water_System: URIRef # The equipment, devices and conduits that handle the production and distribution of water in a building - Water_Tank: URIRef # A space used to hold water - Water_Temperature_Alarm: URIRef # An alarm that indicates the off-normal conditions associated with temperature of water. - Water_Temperature_Sensor: URIRef # Measures the temperature of water - Water_Temperature_Setpoint: URIRef # Sets temperature of water - Water_Usage_Sensor: URIRef # Measures the amount of water that is consumed, over some period of time - Water_Valve: URIRef # A valve that modulates the flow of water - Weather_Station: URIRef # A dedicated weather measurement station - Wind_Direction_Sensor: ( - URIRef # Measures the direction of wind in degrees relative to North - ) - Wind_Speed_Sensor: ( - URIRef # Measured speed of wind, caused by air moving from high to low pressure - ) - Wing: URIRef # A wing is part of a building – or any feature of a building – that is subordinate to the main, central structure. - Workshop: URIRef # A space used to house equipment that can be used to repair or fabricate things - Zone: URIRef # (1) a separately controlled heated or cooled space. (2) one occupied space or several occupied spaces with similar occupancy category, occupant density, zone air distribution effectiveness, and zone primary airflow per unit area. (3) space or group of spaces within a building for which the heating, cooling, or lighting requirements are sufficiently similar that desired conditions can be maintained throughout by a single controlling device. - Zone_Air: URIRef # air inside a defined zone (e.g., corridors). - Zone_Air_Cooling_Temperature_Setpoint: ( - URIRef # The upper (cooling) setpoint for zone air temperature - ) - Zone_Air_Dewpoint_Sensor: URIRef # Measures dewpoint of zone air - Zone_Air_Heating_Temperature_Setpoint: ( - URIRef # The lower (heating) setpoint for zone air temperature - ) - Zone_Air_Humidity_Sensor: URIRef # Measures the relative humidity of zone air - Zone_Air_Humidity_Setpoint: URIRef # Humidity setpoint for zone air - Zone_Air_Temperature_Sensor: URIRef # Measures the temperature of air in a zone - Zone_Air_Temperature_Setpoint: URIRef # Sets temperature of zone air - Zone_Standby_Load_Shed_Command: URIRef - Zone_Unoccupied_Load_Shed_Command: URIRef - - # http://www.w3.org/2002/07/owl#Property - feeds: URIRef # The subject is upstream of the object in the context of some sequential process; some media is passed between them - feedsAir: URIRef # Passes air - hasAddress: URIRef # To specify the address of a building. - hasAssociatedTag: URIRef # The class is associated with the given tag - hasInputSubstance: URIRef # The subject receives the given substance as an input to its internal process - hasLocation: ( - URIRef # Subject is physically located in the location given by the object - ) - hasOutputSubstance: URIRef # The subject produces or exports the given substance from its internal process - hasPart: URIRef # The subject is composed in part of the entity given by the object - hasPoint: URIRef # The subject has a source of telemetry identified by the object. In some systems the source of telemetry may be represented as a digital/analog input/output point - hasQUDTReference: URIRef # Points to the relevant QUDT definition - hasTag: URIRef # The subject has the given tag - hasTimeseriesId: URIRef # The unique identifier (primary key) for this TimeseriesReference in some database - hasUnit: URIRef # The QUDT unit associated with this Brick entity (usually a Brick Point instance or Entity Property) - isAssociatedWith: URIRef # The tag is associated with the given class - isFedBy: URIRef - isLocationOf: URIRef # Subject is the physical location encapsulating the object - isMeasuredBy: URIRef - isPartOf: URIRef - isPointOf: URIRef # The subject is a source of telemetry related to the object. In some systems the source of telemetry may be represented as a digital/analog input/output point - isRegulatedBy: URIRef - isTagOf: URIRef - latitude: URIRef - longitude: URIRef - measures: URIRef # The subject measures a quantity or substance given by the object - regulates: URIRef # The subject contributes to or performs the regulation of the substance given by the object - storedAt: ( - URIRef # A reference to where the data for this TimeseriesReference is stored - ) - timeseries: URIRef # Relates a Brick point to the TimeseriesReference that indicates where and how the data for this point is stored - value: URIRef # The basic value of an entity property - - # https://brickschema.org/schema/Brick#EntityProperty - aggregate: URIRef # Description of how the dta for this point is aggregated - area: URIRef # Entity has 2-dimensional area - azimuth: URIRef # (Horizontal) angle between a projected vector and a reference vector (typically a compass bearing). The projected vector usually indicates the direction of a face or plane. - buildingPrimaryFunction: URIRef # Enumerated string applied to a site record to indicate the building's primary function. The list of primary functions is derived from the US Energy Star program (adopted from Project Haystack) - buildingThermalTransmittance: URIRef # The area-weighted average heat transfer coefficient (commonly referred to as a U-value) for a building envelope - conversionEfficiency: URIRef # The percent efficiency of the conversion process (usually to power or energy) carried out by the entity - coolingCapacity: URIRef # Measurement of a chiller ability to remove heat (adopted from Project Haystack) - coordinates: URIRef # The location of an entity in latitude/longitude - currentFlowType: URIRef # The current flow type of the entity - electricalPhaseCount: URIRef # Entity has these phases - electricalPhases: URIRef # Entity has these electrical AC phases - grossArea: URIRef # Entity has gross 2-dimensional area - measuredModuleConversionEfficiency: URIRef # The measured percentage of sunlight that is converted into usable power - measuredPowerOutput: URIRef # The nominal measured power output of the entity - netArea: URIRef # Entity has net 2-dimensional area - operationalStage: URIRef # The associated operational stage - operationalStageCount: ( - URIRef # The number of operational stages supported by this eqiupment - ) - panelArea: URIRef # Surface area of a panel, such as a PV panel - powerComplexity: URIRef # Entity has this power complexity - powerFlow: URIRef # Entity has this power flow relative to the building' - ratedModuleConversionEfficiency: URIRef # The *rated* percentage of sunlight that is converted into usable power, as measured using Standard Test Conditions (STC): 1000 W/sqm irradiance, 25 degC panel temperature, no wind - ratedPowerOutput: URIRef # The nominal rated power output of the entity - temperatureCoefficientofPmax: URIRef # The % change in power output for every degree celsius that the entity is hotter than 25 degrees celsius - thermalTransmittance: URIRef # The area-weighted average heat transfer coefficient (commonly referred to as a U-value) - tilt: URIRef # The direction an entity is facing in degrees above the horizon - volume: URIRef # Entity has 3-dimensional volume - yearBuilt: URIRef # Four digit year that a building was first built. (adopted from Project Haystack) - - _extras = ["PM2.5_Sensor", "PM2.5_Level_Sensor"] - - _NS = Namespace("https://brickschema.org/schema/Brick#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_CSVW.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_CSVW.py deleted file mode 100644 index 73eb661..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_CSVW.py +++ /dev/null @@ -1,118 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class CSVW(DefinedNamespace): - """ - CSVW Namespace Vocabulary Terms - - This document describes the RDFS vocabulary description used in the Metadata Vocabulary for Tabular Data - [[tabular-metadata]] along with the default JSON-LD Context. - - Generated from: http://www.w3.org/ns/csvw - Date: 2020-05-26 14:19:58.184766 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - aboutUrl: URIRef # A URI template property that MAY be used to indicate what a cell contains information about. - base: URIRef # An atomic property that contains a single string: a term defined in the default context representing a built-in datatype URL, as listed above. - column: URIRef # An array property of column descriptions as described in section 5.6 Columns. - columnReference: URIRef # A column reference property that holds either a single reference to a column description object within this schema, or an array of references. These form the referencing columns for the foreign key definition. - commentPrefix: URIRef # An atomic property that sets the comment prefix flag to the single provided value, which MUST be a string. - datatype: URIRef # An object property that contains either a single string that is the main datatype of the values of the cell or a datatype description object. If the value of this property is a string, it MUST be one of the built-in datatypes defined in section 5.11.1 Built-in Datatypes or an absolute URL; if it is an object then it describes a more specialised datatype. - decimalChar: URIRef # A string whose value is used to represent a decimal point within the number. - default: URIRef # An atomic property holding a single string that is used to create a default value for the cell in cases where the original string value is an empty string. - delimiter: URIRef # An atomic property that sets the delimiter flag to the single provided value, which MUST be a string. - describes: URIRef # From IANA describes: The relationship A 'describes' B asserts that resource A provides a description of resource B. There are no constraints on the format or representation of either A or B, neither are there any further constraints on either resource. - dialect: URIRef # An object property that provides a single dialect description. If provided, dialect provides hints to processors about how to parse the referenced files to create tabular data models for the tables in the group. - doubleQuote: URIRef # A boolean atomic property that, if `true`, sets the escape character flag to `"`. - encoding: URIRef # An atomic property that sets the encoding flag to the single provided string value, which MUST be a defined in [[encoding]]. The default is "utf-8". - foreignKey: URIRef # For a Table: a list of foreign keys on the table. For a Schema: an array property of foreign key definitions that define how the values from specified columns within this table link to rows within this table or other tables. - format: URIRef # An atomic property that contains either a single string or an object that defines the format of a value of this type, used when parsing a string value as described in Parsing Cells in [[tabular-data-model]]. - groupChar: URIRef # A string whose value is used to group digits within the number. - header: URIRef # A boolean atomic property that, if `true`, sets the header row count flag to `1`, and if `false` to `0`, unless headerRowCount is provided, in which case the value provided for the header property is ignored. - headerRowCount: URIRef # An numeric atomic property that sets the header row count flag to the single provided value, which must be a non-negative integer. - lang: URIRef # An atomic property giving a single string language code as defined by [[BCP47]]. - length: URIRef # The exact length of the value of the cell. - lineTerminators: URIRef # An atomic property that sets the line terminators flag to either an array containing the single provided string value, or the provided array. - maxExclusive: URIRef # An atomic property that contains a single number that is the maximum valid value (exclusive). - maxInclusive: URIRef # An atomic property that contains a single number that is the maximum valid value (inclusive). - maxLength: URIRef # A numeric atomic property that contains a single integer that is the maximum length of the value. - minExclusive: URIRef # An atomic property that contains a single number that is the minimum valid value (exclusive). - minInclusive: URIRef # An atomic property that contains a single number that is the minimum valid value (inclusive). - minLength: URIRef # An atomic property that contains a single integer that is the minimum length of the value. - name: URIRef # An atomic property that gives a single canonical name for the column. The value of this property becomes the name annotation for the described column. - note: URIRef # An array property that provides an array of objects representing arbitrary annotations on the annotated tabular data model. - null: URIRef # An atomic property giving the string or strings used for null values within the data. If the string value of the cell is equal to any one of these values, the cell value is `null`. - ordered: URIRef # A boolean atomic property taking a single value which indicates whether a list that is the value of the cell is ordered (if `true`) or unordered (if `false`). - pattern: URIRef # A regular expression string, in the syntax and interpreted as defined by [[ECMASCRIPT]]. - primaryKey: URIRef # For Schema: A column reference property that holds either a single reference to a column description object or an array of references. For Row: a possibly empty list of cells whose values together provide a unique identifier for this row. This is similar to the name of a column. - propertyUrl: URIRef # An URI template property that MAY be used to create a URI for a property if the table is mapped to another format. - quoteChar: URIRef # An atomic property that sets the quote character flag to the single provided value, which must be a string or `null`. - reference: URIRef # An object property that identifies a **referenced table** and a set of **referenced columns** within that table. - referencedRow: URIRef # A possibly empty list of pairs of a foreign key and a row in a table within the same group of tables. - required: URIRef # A boolean atomic property taking a single value which indicates whether the cell must have a non-null value. The default is `false`. - resource: URIRef # A link property holding a URL that is the identifier for a specific table that is being referenced. - row: URIRef # Relates a Table to each Row output. - rowTitle: URIRef # A column reference property that holds either a single reference to a column description object or an array of references. - rownum: URIRef # The position of the row amongst the rows of the Annotated Tabl, starting from 1 - schemaReference: URIRef # A link property holding a URL that is the identifier for a schema that is being referenced. - scriptFormat: URIRef # A link property giving the single URL for the format that is used by the script or template. - separator: URIRef # An atomic property that MUST have a single string value that is the character used to separate items in the string value of the cell. - skipBlankRows: URIRef # An boolean atomic property that sets the `skip blank rows` flag to the single provided boolean value. - skipColumns: URIRef # An numeric atomic property that sets the `skip columns` flag to the single provided numeric value, which MUST be a non-negative integer. - skipInitialSpace: URIRef # A boolean atomic property that, if `true`, sets the trim flag to "start". If `false`, to `false`. - skipRows: URIRef # An numeric atomic property that sets the `skip rows` flag to the single provided numeric value, which MUST be a non-negative integer. - source: URIRef # A single string atomic property that provides, if specified, the format to which the tabular data should be transformed prior to the transformation using the script or template. - suppressOutput: URIRef # A boolean atomic property. If `true`, suppresses any output that would be generated when converting a table or cells within a column. - table: URIRef # Relates an Table group to annotated tables. - tableDirection: URIRef # One of `rtl`, `ltr` or `auto`. Indicates whether the tables in the group should be displayed with the first column on the right, on the left, or based on the first character in the table that has a specific direction. - tableSchema: URIRef # An object property that provides a single schema description as described in section 5.5 Schemas, used as the default for all the tables in the group - targetFormat: URIRef # A link property giving the single URL for the format that will be created through the transformation. - textDirection: URIRef # An atomic property that must have a single value that is one of `rtl` or `ltr` (the default). - title: URIRef # For a Transformation A natural language property that describes the format that will be generated from the transformation. For a Column: A natural language property that provides possible alternative names for the column. - transformations: URIRef # An array property of transformation definitions that provide mechanisms to transform the tabular data into other formats. - trim: URIRef # An atomic property that, if the boolean `true`, sets the trim flag to `true` and if the boolean `false` to `false`. If the value provided is a string, sets the trim flag to the provided value, which must be one of "true", "false", "start" or "end". - url: URIRef # For a Table: This link property gives the single URL of the CSV file that the table is held in, relative to the location of the metadata document. For a Transformation: A link property giving the single URL of the file that the script or template is held in, relative to the location of the metadata document. - valueUrl: URIRef # An URI template property that is used to map the values of cells into URLs. - virtual: URIRef # A boolean atomic property taking a single value which indicates whether the column is a virtual column not present in the original source - - # http://www.w3.org/2000/01/rdf-schema#Class - Cell: URIRef # A Cell represents a cell at the intersection of a Row and a Column within a Table. - Column: ( - URIRef # A Column represents a vertical arrangement of Cells within a Table. - ) - Datatype: URIRef # Describes facets of a datatype. - Dialect: URIRef # A Dialect Description provides hints to parsers about how to parse a linked file. - Direction: URIRef # The class of table/text directions. - ForeignKey: URIRef # Describes relationships between Columns in one or more Tables. - NumericFormat: URIRef # If the datatype is a numeric type, the format property indicates the expected format for that number. Its value must be either a single string or an object with one or more properties. - Row: URIRef # A Row represents a horizontal arrangement of cells within a Table. - Schema: URIRef # A Schema is a definition of a tabular format that may be common to multiple tables. - Table: URIRef # An annotated table is a table that is annotated with additional metadata. - TableGroup: URIRef # A Group of Tables comprises a set of Annotated Tables and a set of annotations that relate to those Tables. - TableReference: URIRef # An object property that identifies a referenced table and a set of referenced columns within that table. - Transformation: URIRef # A Transformation Definition is a definition of how tabular data can be transformed into another format. - - # http://www.w3.org/2000/01/rdf-schema#Datatype - JSON: URIRef # A literal containing JSON. - uriTemplate: URIRef # - - # http://www.w3.org/ns/csvw#Direction - auto: URIRef # Indicates whether the tables in the group should be displayed based on the first character in the table that has a specific direction. - inherit: URIRef # For `textDirection`, indicates that the direction is inherited from the `tableDirection` annotation of the `table`. - ltr: URIRef # Indicates whether the tables in the group should be displayed with the first column on the right. - rtl: URIRef # Indicates whether the tables in the group should be displayed with the first column on the left. - - # http://www.w3.org/ns/prov#Role - csvEncodedTabularData: ( - URIRef # Describes the role of a CSV file in the tabular data mapping. - ) - tabularMetadata: ( - URIRef # Describes the role of a Metadata file in the tabular data mapping. - ) - - _NS = Namespace("http://www.w3.org/ns/csvw#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DC.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DC.py deleted file mode 100644 index fa175c2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DC.py +++ /dev/null @@ -1,37 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DC(DefinedNamespace): - """ - Dublin Core Metadata Element Set, Version 1.1 - - Generated from: https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dublin_core_elements.ttl - Date: 2020-05-26 14:19:58.671906 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - contributor: ( - URIRef # An entity responsible for making contributions to the resource. - ) - coverage: URIRef # The spatial or temporal topic of the resource, spatial applicability of the resource, or jurisdiction under which the resource is relevant. - creator: URIRef # An entity primarily responsible for making the resource. - date: URIRef # A point or period of time associated with an event in the lifecycle of the resource. - description: URIRef # An account of the resource. - format: URIRef # The file format, physical medium, or dimensions of the resource. - identifier: ( - URIRef # An unambiguous reference to the resource within a given context. - ) - language: URIRef # A language of the resource. - publisher: URIRef # An entity responsible for making the resource available. - relation: URIRef # A related resource. - rights: URIRef # Information about rights held in and over the resource. - source: URIRef # A related resource from which the described resource is derived. - subject: URIRef # The topic of the resource. - title: URIRef # A name given to the resource. - type: URIRef # The nature or genre of the resource. - - _NS = Namespace("http://purl.org/dc/elements/1.1/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAM.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAM.py deleted file mode 100644 index 4d55067..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAM.py +++ /dev/null @@ -1,24 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DCAM(DefinedNamespace): - """ - Metadata terms for vocabulary description - - Generated from: https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dublin_core_abstract_model.ttl - Date: 2020-05-26 14:20:00.970966 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - domainIncludes: URIRef # A suggested class for subjects of this property. - memberOf: URIRef # A relationship between a resource and a vocabulary encoding scheme which indicates that the resource is a member of a set. - rangeIncludes: URIRef # A suggested class for values of this property. - - # http://www.w3.org/2000/01/rdf-schema#Class - VocabularyEncodingScheme: URIRef # An enumerated set of resources. - - _NS = Namespace("http://purl.org/dc/dcam/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAT.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAT.py deleted file mode 100644 index 8abcf1f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCAT.py +++ /dev/null @@ -1,71 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DCAT(DefinedNamespace): - """ - The data catalog vocabulary - - DCAT is an RDF vocabulary designed to facilitate interoperability between data catalogs published on the Web. - By using DCAT to describe datasets in data catalogs, publishers increase discoverability and enable - applications easily to consume metadata from multiple catalogs. It further enables decentralized publishing of - catalogs and facilitates federated dataset search across sites. Aggregated DCAT metadata can serve as a - manifest file to facilitate digital preservation. DCAT is defined at http://www.w3.org/TR/vocab-dcat/. Any - variance between that normative document and this schema is an error in this schema. - - Generated from: https://www.w3.org/ns/dcat2.ttl - Date: 2020-05-26 14:19:59.985854 - - """ - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - accessURL: URIRef # A URL of a resource that gives access to a distribution of the dataset. E.g. landing page, feed, SPARQL endpoint. Use for all cases except a simple download link, in which case downloadURL is preferred. - bbox: URIRef # The geographic bounding box of a resource. - byteSize: URIRef # The size of a distribution in bytes. - centroid: URIRef # The geographic center (centroid) of a resource. - compressFormat: URIRef # The compression format of the distribution in which the data is contained in a compressed form, e.g. to reduce the size of the downloadable file. - contactPoint: URIRef # Relevant contact information for the catalogued resource. Use of vCard is recommended. - dataset: URIRef # A collection of data that is listed in the catalog. - distribution: URIRef # An available distribution of the dataset. - downloadURL: URIRef # The URL of the downloadable file in a given format. E.g. CSV file or RDF file. The format is indicated by the distribution's dct:format and/or dcat:mediaType. - endDate: URIRef # The end of the period. - keyword: URIRef # A keyword or tag describing a resource. - landingPage: URIRef # A Web page that can be navigated to in a Web browser to gain access to the catalog, a dataset, its distributions and/or additional information. - mediaType: URIRef # The media type of the distribution as defined by IANA. - packageFormat: URIRef # The package format of the distribution in which one or more data files are grouped together, e.g. to enable a set of related files to be downloaded together. - record: URIRef # A record describing the registration of a single dataset or data service that is part of the catalog. - startDate: URIRef # The start of the period - theme: ( - URIRef # A main category of the resource. A resource can have multiple themes. - ) - themeTaxonomy: URIRef # The knowledge organization system (KOS) used to classify catalog's datasets. - - # http://www.w3.org/2000/01/rdf-schema#Class - Catalog: URIRef # A curated collection of metadata about resources (e.g., datasets and data services in the context of a data catalog). - CatalogRecord: URIRef # A record in a data catalog, describing the registration of a single dataset or data service. - Dataset: URIRef # A collection of data, published or curated by a single source, and available for access or download in one or more representations. - Distribution: URIRef # A specific representation of a dataset. A dataset might be available in multiple serializations that may differ in various ways, including natural language, media-type or format, schematic organization, temporal and spatial resolution, level of detail or profiles (which might specify any or all of the above). - - # http://www.w3.org/2002/07/owl#Class - DataService: URIRef # A site or end-point providing operations related to the discovery of, access to, or processing functions on, data or related resources. - Relationship: URIRef # An association class for attaching additional information to a relationship between DCAT Resources. - Resource: URIRef # Resource published or curated by a single agent. - Role: URIRef # A role is the function of a resource or agent with respect to another resource, in the context of resource attribution or resource relationships. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - spatialResolutionInMeters: URIRef # mínima separacíon espacial disponible en un conjunto de datos, medida en metros. - temporalResolution: URIRef # minimum time period resolvable in a dataset. - - # http://www.w3.org/2002/07/owl#ObjectProperty - accessService: URIRef # A site or end-point that gives access to the distribution of the dataset. - catalog: URIRef # A catalog whose contents are of interest in the context of this catalog. - endpointDescription: URIRef # A description of the service end-point, including its operations, parameters etc. - endpointURL: URIRef # The root location or primary endpoint of the service (a web-resolvable IRI). - hadRole: URIRef # The function of an entity or agent with respect to another entity or resource. - qualifiedRelation: ( - URIRef # Link to a description of a relationship with another resource. - ) - servesDataset: URIRef # A collection of data that this DataService can distribute. - service: URIRef # A site or endpoint that is listed in the catalog. - - _NS = Namespace("http://www.w3.org/ns/dcat#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCMITYPE.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCMITYPE.py deleted file mode 100644 index d6b0ac9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCMITYPE.py +++ /dev/null @@ -1,30 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DCMITYPE(DefinedNamespace): - """ - DCMI Type Vocabulary - - Generated from: https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dublin_core_type.ttl - Date: 2020-05-26 14:19:59.084150 - - """ - - _fail = True - - # http://www.w3.org/2000/01/rdf-schema#Class - Collection: URIRef # An aggregation of resources. - Dataset: URIRef # Data encoded in a defined structure. - Event: URIRef # A non-persistent, time-based occurrence. - Image: URIRef # A visual representation other than text. - InteractiveResource: URIRef # A resource requiring interaction from the user to be understood, executed, or experienced. - MovingImage: URIRef # A series of visual representations imparting an impression of motion when shown in succession. - PhysicalObject: URIRef # An inanimate, three-dimensional object or substance. - Service: URIRef # A system that provides one or more functions. - Software: URIRef # A computer program in source or compiled form. - Sound: URIRef # A resource primarily intended to be heard. - StillImage: URIRef # A static visual representation. - Text: URIRef # A resource consisting primarily of words for reading. - - _NS = Namespace("http://purl.org/dc/dcmitype/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCTERMS.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCTERMS.py deleted file mode 100644 index d3548f4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DCTERMS.py +++ /dev/null @@ -1,139 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DCTERMS(DefinedNamespace): - """ - DCMI Metadata Terms - other - - Generated from: https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dublin_core_terms.ttl - Date: 2020-05-26 14:20:00.590514 - - """ - - _fail = True - - # http://purl.org/dc/dcam/VocabularyEncodingScheme - DCMIType: URIRef # The set of classes specified by the DCMI Type Vocabulary, used to categorize the nature or genre of the resource. - DDC: URIRef # The set of conceptual resources specified by the Dewey Decimal Classification. - IMT: URIRef # The set of media types specified by the Internet Assigned Numbers Authority. - LCC: URIRef # The set of conceptual resources specified by the Library of Congress Classification. - LCSH: URIRef # The set of labeled concepts specified by the Library of Congress Subject Headings. - MESH: ( - URIRef # The set of labeled concepts specified by the Medical Subject Headings. - ) - NLM: URIRef # The set of conceptual resources specified by the National Library of Medicine Classification. - TGN: URIRef # The set of places specified by the Getty Thesaurus of Geographic Names. - UDC: URIRef # The set of conceptual resources specified by the Universal Decimal Classification. - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - abstract: URIRef # A summary of the resource. - accessRights: URIRef # Information about who access the resource or an indication of its security status. - accrualMethod: URIRef # The method by which items are added to a collection. - accrualPeriodicity: ( - URIRef # The frequency with which items are added to a collection. - ) - accrualPolicy: URIRef # The policy governing the addition of items to a collection. - alternative: URIRef # An alternative name for the resource. - audience: URIRef # A class of agents for whom the resource is intended or useful. - available: URIRef # Date that the resource became or will become available. - bibliographicCitation: URIRef # A bibliographic reference for the resource. - conformsTo: ( - URIRef # An established standard to which the described resource conforms. - ) - contributor: ( - URIRef # An entity responsible for making contributions to the resource. - ) - coverage: URIRef # The spatial or temporal topic of the resource, spatial applicability of the resource, or jurisdiction under which the resource is relevant. - created: URIRef # Date of creation of the resource. - creator: URIRef # An entity responsible for making the resource. - date: URIRef # A point or period of time associated with an event in the lifecycle of the resource. - dateAccepted: URIRef # Date of acceptance of the resource. - dateCopyrighted: URIRef # Date of copyright of the resource. - dateSubmitted: URIRef # Date of submission of the resource. - description: URIRef # An account of the resource. - educationLevel: URIRef # A class of agents, defined in terms of progression through an educational or training context, for which the described resource is intended. - extent: URIRef # The size or duration of the resource. - format: URIRef # The file format, physical medium, or dimensions of the resource. - hasFormat: URIRef # A related resource that is substantially the same as the pre-existing described resource, but in another format. - hasPart: URIRef # A related resource that is included either physically or logically in the described resource. - hasVersion: URIRef # A related resource that is a version, edition, or adaptation of the described resource. - identifier: ( - URIRef # An unambiguous reference to the resource within a given context. - ) - instructionalMethod: URIRef # A process, used to engender knowledge, attitudes and skills, that the described resource is designed to support. - isFormatOf: URIRef # A pre-existing related resource that is substantially the same as the described resource, but in another format. - isPartOf: URIRef # A related resource in which the described resource is physically or logically included. - isReferencedBy: URIRef # A related resource that references, cites, or otherwise points to the described resource. - isReplacedBy: URIRef # A related resource that supplants, displaces, or supersedes the described resource. - isRequiredBy: URIRef # A related resource that requires the described resource to support its function, delivery, or coherence. - isVersionOf: URIRef # A related resource of which the described resource is a version, edition, or adaptation. - issued: URIRef # Date of formal issuance of the resource. - language: URIRef # A language of the resource. - license: URIRef # A legal document giving official permission to do something with the resource. - mediator: URIRef # An entity that mediates access to the resource. - medium: URIRef # The material or physical carrier of the resource. - modified: URIRef # Date on which the resource was changed. - provenance: URIRef # A statement of any changes in ownership and custody of the resource since its creation that are significant for its authenticity, integrity, and interpretation. - publisher: URIRef # An entity responsible for making the resource available. - references: URIRef # A related resource that is referenced, cited, or otherwise pointed to by the described resource. - relation: URIRef # A related resource. - replaces: URIRef # A related resource that is supplanted, displaced, or superseded by the described resource. - requires: URIRef # A related resource that is required by the described resource to support its function, delivery, or coherence. - rights: URIRef # Information about rights held in and over the resource. - rightsHolder: ( - URIRef # A person or organization owning or managing rights over the resource. - ) - source: URIRef # A related resource from which the described resource is derived. - spatial: URIRef # Spatial characteristics of the resource. - subject: URIRef # A topic of the resource. - tableOfContents: URIRef # A list of subunits of the resource. - temporal: URIRef # Temporal characteristics of the resource. - title: URIRef # A name given to the resource. - type: URIRef # The nature or genre of the resource. - valid: URIRef # Date (often a range) of validity of a resource. - - # http://www.w3.org/2000/01/rdf-schema#Class - Agent: URIRef # A resource that acts or has the power to act. - AgentClass: URIRef # A group of agents. - BibliographicResource: URIRef # A book, article, or other documentary resource. - FileFormat: URIRef # A digital resource format. - Frequency: URIRef # A rate at which something recurs. - Jurisdiction: ( - URIRef # The extent or range of judicial, law enforcement, or other authority. - ) - LicenseDocument: URIRef # A legal document giving official permission to do something with a resource. - LinguisticSystem: URIRef # A system of signs, symbols, sounds, gestures, or rules used in communication. - Location: URIRef # A spatial region or named place. - LocationPeriodOrJurisdiction: URIRef # A location, period of time, or jurisdiction. - MediaType: URIRef # A file format or physical medium. - MediaTypeOrExtent: URIRef # A media type or extent. - MethodOfAccrual: URIRef # A method by which resources are added to a collection. - MethodOfInstruction: ( - URIRef # A process that is used to engender knowledge, attitudes, and skills. - ) - PeriodOfTime: URIRef # An interval of time that is named or defined by its start and end dates. - PhysicalMedium: URIRef # A physical material or carrier. - PhysicalResource: URIRef # A material thing. - Policy: URIRef # A plan or course of action by an authority, intended to influence and determine decisions, actions, and other matters. - ProvenanceStatement: URIRef # Any changes in ownership and custody of a resource since its creation that are significant for its authenticity, integrity, and interpretation. - RightsStatement: URIRef # A statement about the intellectual property rights (IPR) held in or over a resource, a legal document giving official permission to do something with a resource, or a statement about access rights. - SizeOrDuration: URIRef # A dimension or extent, or a time taken to play or execute. - Standard: URIRef # A reference point against which other things can be evaluated or compared. - - # http://www.w3.org/2000/01/rdf-schema#Datatype - Box: URIRef # The set of regions in space defined by their geographic coordinates according to the DCMI Box Encoding Scheme. - ISO3166: URIRef # The set of codes listed in ISO 3166-1 for the representation of names of countries. - Period: URIRef # The set of time intervals defined by their limits according to the DCMI Period Encoding Scheme. - Point: URIRef # The set of points in space defined by their geographic coordinates according to the DCMI Point Encoding Scheme. - RFC1766: URIRef # The set of tags, constructed according to RFC 1766, for the identification of languages. - RFC3066: URIRef # The set of tags constructed according to RFC 3066 for the identification of languages. - RFC4646: URIRef # The set of tags constructed according to RFC 4646 for the identification of languages. - RFC5646: URIRef # The set of tags constructed according to RFC 5646 for the identification of languages. - URI: URIRef # The set of identifiers constructed according to the generic syntax for Uniform Resource Identifiers as specified by the Internet Engineering Task Force. - W3CDTF: URIRef # The set of dates and times constructed according to the W3C Date and Time Formats Specification. - - # Valid non-python identifiers - _extras = ["ISO639-2", "ISO639-3"] - - _NS = Namespace("http://purl.org/dc/terms/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DOAP.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DOAP.py deleted file mode 100644 index d8b6528..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_DOAP.py +++ /dev/null @@ -1,84 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class DOAP(DefinedNamespace): - """ - Description of a Project (DOAP) vocabulary - - The Description of a Project (DOAP) vocabulary, described using W3C RDF Schema and the Web Ontology Language. - - Generated from: http://usefulinc.com/ns/doap - Date: 2024-08-01 13:03:22.175167 - """ - - _NS = Namespace("http://usefulinc.com/ns/doap#") - - _fail = True - - ArchRepository: URIRef # GNU Arch source code repository. Dépôt GNU Arch du code source. Repositorio GNU Arch del código fuente. GNU Arch Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů GNU Arch. Repositório GNU Arch do código fonte. - BKRepository: URIRef # BitKeeper source code repository. Dépôt BitKeeper du code source. Repositorio BitKeeper del código fuente. BitKeeper Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů BitKeeper. Repositório BitKeeper do código fonte. - BazaarBranch: ( - URIRef # Bazaar source code branch. Código fonte da ramificação Bazaar. - ) - CVSRepository: URIRef # CVS source code repository. Dépôt CVS du code source. Repositorio CVS del código fuente. CVS Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů CVS. Repositório CVS do código fonte. - DarcsRepository: URIRef # darcs source code repository. Dépôt darcs du code source. Repositorio darcs del código fuente. Repositório darcs do código fonte. - GitBranch: URIRef # Git source code branch. Código fonte da ramificação Git. - GitRepository: URIRef # Git source code repository. Dépôt Git du code source. Repositorio Git del código fuente. Git Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů Git. Repositório Git do código fonte. - HgRepository: URIRef # Mercurial source code repository. Repositório Mercurial do código fonte. - Project: URIRef # A project. Un projet. Un proyecto. Ein Projekt. Projekt. Projeto. - Repository: URIRef # Source code repository. Dépôt du code source. Repositorio del código fuente. Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů. Repositório do código fonte. - SVNRepository: URIRef # Subversion source code repository. Dépôt Subversion du code source. Repositorio Subversion del código fuente. Subversion Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů Subversion. Repositório Subversion do código fonte. - Specification: URIRef # A specification of a system's aspects, technical or otherwise. A especificação de aspetos, técnicas ou outros do sistema. - Version: URIRef # Version information of a project release. Détails sur une version d'une release d'un projet. Información sobre la versión de un release del proyecto. Versionsinformation eines Projekt Releases. Informace o uvolnÄ›né verzi projektu. Informação sobre a versão do projeto lançado. - audience: ( - URIRef # Description of target user base Descrição do utilizador base alvo - ) - blog: URIRef # URI of a blog related to a project URI de um blog relacionado com um projeto - browse: URIRef # Web browser interface to repository. Interface web au dépôt. Interface web del repositorio. Web-Browser Interface für das Repository. Webové rozhraní pro prohlížení úložiÅ¡tÄ›. Interface web do repositório. - category: URIRef # A category of project. Une catégorie de projet. Una categoría de proyecto. Eine Kategorie eines Projektes. Kategorie projektu. Uma categoría de projeto. - created: URIRef # Date when something was created, in YYYY-MM-DD form. e.g. 2004-04-05 Date à laquelle a été créé quelque chose, au format AAAA-MM-JJ (par ex. 2004-04-05) Fecha en la que algo fue creado, en formato AAAA-MM-DD. e.g. 2004-04-05 Erstellungsdatum von Irgendwas, angegeben im YYYY-MM-DD Format, z.B. 2004-04-05. Datum, kdy bylo nÄ›co vytvoÅ™eno ve formátu RRRR-MM-DD, napÅ™. 2004-04-05 Data em que algo foi criado, no formato AAAA-MM-DD. e.g. 2004-04-05 - description: URIRef # Plain text description of a project, of 2-4 sentences in length. Texte descriptif d'un projet, long de 2 à 4 phrases. Descripción en texto plano de un proyecto, de 2 a 4 enunciados de longitud. Beschreibung eines Projekts als einfacher Text mit der Länge von 2 bis 4 Sätzen. ÄŒistÄ› textový, 2 až 4 vÄ›ty dlouhý popis projektu. Descrição de um projeto em texto apenas, com 2 a 4 frases de comprimento. - developer: URIRef # Developer of software for the project. Développeur pour le projet. Desarrollador de software para el proyecto. Software-Entwickler für das Projekt. Vývojář softwaru projektu. Programador de software para o projeto. - documentation: ( - URIRef # Documentation of the project. Aide pour l’utilisation de ce projet. - ) - documenter: URIRef # Contributor of documentation to the project. Collaborateur à la documentation du projet. Proveedor de documentación para el proyecto. Mitarbeiter an der Dokumentation des Projektes. Spoluautor dokumentace projektu. Contribuidor para a documentação do projeto. - helper: URIRef # Project contributor. Collaborateur au projet. Colaborador del proyecto. Projekt-Mitarbeiter. Spoluautor projektu. Ajudante ou colaborador do projeto. - homepage: URIRef # URL of a project's homepage, associated with exactly one project. L'URL de la page web d'un projet, associée avec un unique projet. El URL de la página de un proyecto, asociada con exactamente un proyecto. URL der Projekt-Homepage, verbunden mit genau einem Projekt. URL adresa domovské stránky projektu asociované s právÄ› jedním projektem. O URL da página de um projeto, asociada com exactamente um projeto. - implements: URIRef # A specification that a project implements. Could be a standard, API or legally defined level of conformance. Uma especificação que um projeto implementa. Pode ser uma padrão, API ou um nível de conformidade definida legalmente. - language: URIRef # BCP47 language code a project has been translated into Código de idioma BCP47 do projeto para o qual foi traduzido - license: URIRef # The URI of an RDF description of the license the software is distributed under. E.g. a SPDX reference L'URI d'une description RDF de la licence sous laquelle le programme est distribué. El URI de una descripción RDF de la licencia bajo la cuál se distribuye el software. Die URI einer RDF-Beschreibung einer Lizenz unter der die Software herausgegeben wird. z.B. eine SPDX Referenz URI adresa RDF popisu licence, pod kterou je software distribuován. O URI de uma descrição RDF da licença do software sob a qual é distribuída. Ex.: referência SPDX - location: URIRef # Location of a repository. Emplacement d'un dépôt. lugar de un repositorio. Lokation eines Repositorys. UmístÄ›ní úložiÅ¡tÄ›. Localização de um repositório. - maintainer: URIRef # Maintainer of a project, a project leader. Développeur principal d'un projet, un meneur du projet. Desarrollador principal de un proyecto, un líder de proyecto. Hauptentwickler eines Projektes, der Projektleiter Správce projektu, vedoucí projektu. Programador principal de um projeto, um líder de projeto. - module: URIRef # Module name of a Subversion, CVS, BitKeeper or Arch repository. Nom du module d'un dépôt Subversion, CVS, BitKeeper ou Arch. Nombre del módulo de un repositorio Subversion, CVS, BitKeeper o Arch. Modul-Name eines Subversion, CVS, BitKeeper oder Arch Repositorys. Jméno modulu v CVS, BitKeeper nebo Arch úložiÅ¡ti. Nome do módulo de um repositório Subversion, CVS, BitKeeper ou Arch. - name: URIRef # A name of something. Le nom de quelque chose. El nombre de algo. Der Name von Irgendwas Jméno nÄ›Äeho. O nome de alguma coisa. - os: URIRef # Operating system that a project is limited to. Omit this property if the project is not OS-specific. Système d'exploitation auquel est limité le projet. Omettez cette propriété si le projet n'est pas limité à un système d'exploitation. Sistema opertivo al cuál está limitado el proyecto. Omita esta propiedad si el proyecto no es específico de un sistema opertaivo en particular. Betriebssystem auf dem das Projekt eingesetzt werden kann. Diese Eigenschaft kann ausgelassen werden, wenn das Projekt nicht BS-spezifisch ist. OperaÄní systém, na jehož použití je projekt limitován. Vynechejte tuto vlastnost, pokud je projekt nezávislý na operaÄním systému. Sistema operativo a que o projeto está limitado. Omita esta propriedade se o projeto não é condicionado pelo SO usado. - platform: URIRef # Indicator of software platform (non-OS specific), e.g. Java, Firefox, ECMA CLR Indicador da plataforma do software (não específico a nenhum SO), ex.: Java, Firefox, ECMA CLR - release: URIRef # A project release. Une release (révision) d'un projet. Un release (versión) de un proyecto. Ein Release (Version) eines Projekts. Relase (verze) projektu. A publicação de um projeto. - repository: URIRef # Source code repository. Dépôt du code source. Repositorio del código fuente. Quellcode-Versionierungssystem. ÚložiÅ¡tÄ› zdrojových kódů. Repositório do código fonte. - repositoryOf: URIRef # The project that uses a repository. - revision: URIRef # Revision identifier of a software release. Identifiant de révision d'une release du programme. Indentificador de la versión de un release de software. Versionsidentifikator eines Software-Releases. Identifikátor zpřístupnÄ›né revize softwaru. Identificador do lançamento da revisão do software. - screenshots: URIRef # Web page with screenshots of project. Page web avec des captures d'écran du projet. Página web con capturas de pantalla del proyecto. Web-Seite mit Screenshots eines Projektes. Webová stránka projektu se snímky obrazovky. Página web com as capturas de ecrãn do projeto. - shortdesc: URIRef # Short (8 or 9 words) plain text description of a project. Texte descriptif concis (8 ou 9 mots) d'un projet. Descripción corta (8 o 9 palabras) en texto plano de un proyecto. Kurzbeschreibung (8 oder 9 Wörter) eines Projekts als einfacher Text. Krátký (8 nebo 9 slov) ÄistÄ› textový popis projektu. Descrição curta (com 8 ou 9 palavras) de um projeto em texto apenas. - tester: URIRef # A tester or other quality control contributor. Un testeur ou un collaborateur au contrôle qualité. Un tester u otro proveedor de control de calidad. Ein Tester oder anderer Mitarbeiter der Qualitätskontrolle. Tester nebo jiný spoluautor kontrolující kvalitu. Um controlador ou outro contribuidor para o controlo de qualidade. - translator: URIRef # Contributor of translations to the project. Collaborateur à la traduction du projet. Proveedor de traducciones al proyecto. Mitarbeiter an den Übersetzungen des Projektes. Spoluautor pÅ™ekladu projektu. Contribuidor das traduções para o projeto. - vendor: URIRef # Vendor organization: commercial, free or otherwise - wiki: URIRef # URL of Wiki for collaborative discussion of project. L'URL du Wiki pour la discussion collaborative sur le projet. URL del Wiki para discusión colaborativa del proyecto. Wiki-URL für die kollaborative Dikussion eines Projektes. URL adresa wiki projektu pro spoleÄné diskuse. URL da Wiki para discussão em grupo do projeto. - - # Valid non-python identifiers - _extras = [ - "anon-root", # Repository for anonymous access. Dépôt pour accès anonyme. Repositorio para acceso anónimo. Repository für anonymen Zugriff ÚložiÅ¡tÄ› pro anonymní přístup. Repositório para acesso anónimo. - "bug-database", # Bug tracker for a project. Suivi des bugs pour un projet. Bug tracker para un proyecto. Fehlerdatenbank eines Projektes. Správa chyb projektu. Bug tracker para um projeto. - "developer-forum", # A forum or community for developers of this project. - "download-mirror", # Mirror of software download web page. Miroir de la page de téléchargement du programme. Mirror de la página web de descarga. Spiegel der Seite von die Projekt-Software heruntergeladen werden kann. Zrcadlo stránky pro stažení softwaru. Mirror da página web para fazer download. - "download-page", # Web page from which the project software can be downloaded. Page web à partir de laquelle on peut télécharger le programme. Página web de la cuál se puede bajar el software. Web-Seite von der die Projekt-Software heruntergeladen werden kann. Webová stránka, na které lze stáhnout projektový software. Página web da qual o projeto de software pode ser descarregado. - "file-release", # URI of download associated with this release. URI adresa stažení asociované s revizí. URI para download associado com a publicação. - "mailing-list", # Mailing list home page or email address. Page web de la liste de diffusion, ou adresse de courriel. Página web de la lista de correo o dirección de correo. Homepage der Mailing Liste oder E-Mail Adresse. Domovská stránka nebo e–mailová adresa e–mailové diskuse. Página web da lista de distribuição de e-mail ou dos endereços. - "old-homepage", # URL of a project's past homepage, associated with exactly one project. L'URL d'une ancienne page web d'un projet, associée avec un unique projet. El URL de la antigua página de un proyecto, asociada con exactamente un proyecto. URL der letzten Projekt-Homepage, verbunden mit genau einem Projekt. URL adresa pÅ™edeÅ¡lé domovské stránky projektu asociované s právÄ› jedním projektem. O URL antigo da página de um projeto, associada com exactamente um projeto. - "programming-language", # Programming language a project is implemented in or intended for use with. Langage de programmation avec lequel un projet est implémenté, ou avec lequel il est prévu de l'utiliser. Lenguaje de programación en el que un proyecto es implementado o con el cuál pretende usarse. Programmiersprache in der ein Projekt implementiert ist oder intendiert wird zu benutzen. Programovací jazyk, ve kterém je projekt implementován nebo pro který je zamýšlen k použití. Linguagem de programação que o projeto usa ou é para ser utilizada. - "security-contact", # The Agent that should be contacted if security issues are found with the project. - "security-policy", # URL of the security policy of a project. - "service-endpoint", # The URI of a web service endpoint where software as a service may be accessed - "support-forum", # A forum or community that supports this project. - ] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_FOAF.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_FOAF.py deleted file mode 100644 index 18aa4af..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_FOAF.py +++ /dev/null @@ -1,105 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class FOAF(DefinedNamespace): - """ - Friend of a Friend (FOAF) vocabulary - - The Friend of a Friend (FOAF) RDF vocabulary, described using W3C RDF Schema and the Web Ontology Language. - - Generated from: http://xmlns.com/foaf/spec/index.rdf - Date: 2020-05-26 14:20:01.597998 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - account: URIRef # Indicates an account held by this agent. - accountName: ( - URIRef # Indicates the name (identifier) associated with this online account. - ) - accountServiceHomepage: ( - URIRef # Indicates a homepage of the service provide for this online account. - ) - age: URIRef # The age in years of some agent. - based_near: URIRef # A location that something is based near, for some broadly human notion of near. - birthday: URIRef # The birthday of this Agent, represented in mm-dd string form, eg. '12-31'. - currentProject: URIRef # A current project this person works on. - depiction: URIRef # A depiction of some thing. - depicts: URIRef # A thing depicted in this representation. - dnaChecksum: URIRef # A checksum for the DNA of some thing. Joke. - familyName: URIRef # The family name of some person. - family_name: URIRef # The family name of some person. - firstName: URIRef # The first name of a person. - focus: URIRef # The underlying or 'focal' entity associated with some SKOS-described concept. - fundedBy: URIRef # An organization funding a project or person. - geekcode: URIRef # A textual geekcode for this person, see http://www.geekcode.com/geek.html - gender: URIRef # The gender of this Agent (typically but not necessarily 'male' or 'female'). - givenName: URIRef # The given name of some person. - givenname: URIRef # The given name of some person. - holdsAccount: URIRef # Indicates an account held by this agent. - img: URIRef # An image that can be used to represent some thing (ie. those depictions which are particularly representative of something, eg. one's photo on a homepage). - interest: URIRef # A page about a topic of interest to this person. - knows: URIRef # A person known by this person (indicating some level of reciprocated interaction between the parties). - lastName: URIRef # The last name of a person. - made: URIRef # Something that was made by this agent. - maker: URIRef # An agent that made this thing. - member: URIRef # Indicates a member of a Group - membershipClass: ( - URIRef # Indicates the class of individuals that are a member of a Group - ) - myersBriggs: URIRef # A Myers Briggs (MBTI) personality classification. - name: URIRef # A name for some thing. - nick: URIRef # A short informal nickname characterising an agent (includes login identifiers, IRC and other chat nicknames). - page: URIRef # A page or document about this thing. - pastProject: URIRef # A project this person has previously worked on. - phone: URIRef # A phone, specified using fully qualified tel: URI scheme (refs: http://www.w3.org/Addressing/schemes.html#tel). - plan: URIRef # A .plan comment, in the tradition of finger and '.plan' files. - primaryTopic: URIRef # The primary topic of some page or document. - publications: URIRef # A link to the publications of this person. - schoolHomepage: URIRef # A homepage of a school attended by the person. - sha1: URIRef # A sha1sum hash, in hex. - skypeID: URIRef # A Skype ID - status: URIRef # A string expressing what the user is happy for the general public (normally) to know about their current activity. - surname: URIRef # The surname of some person. - theme: URIRef # A theme. - thumbnail: URIRef # A derived thumbnail image. - tipjar: URIRef # A tipjar document for this agent, describing means for payment and reward. - title: URIRef # Title (Mr, Mrs, Ms, Dr. etc) - topic: URIRef # A topic of some page or document. - topic_interest: URIRef # A thing of interest to this person. - workInfoHomepage: URIRef # A work info homepage of some person; a page about their work for some organization. - workplaceHomepage: URIRef # A workplace homepage of some person; the homepage of an organization they work for. - - # http://www.w3.org/2000/01/rdf-schema#Class - Agent: URIRef # An agent (eg. person, group, software or physical artifact). - Document: URIRef # A document. - Group: URIRef # A class of Agents. - Image: URIRef # An image. - LabelProperty: URIRef # A foaf:LabelProperty is any RDF property with textual values that serve as labels. - OnlineAccount: URIRef # An online account. - OnlineChatAccount: URIRef # An online chat account. - OnlineEcommerceAccount: URIRef # An online e-commerce account. - OnlineGamingAccount: URIRef # An online gaming account. - Organization: URIRef # An organization. - Person: URIRef # A person. - PersonalProfileDocument: URIRef # A personal profile RDF document. - Project: URIRef # A project (a collective endeavour of some kind). - - # http://www.w3.org/2002/07/owl#InverseFunctionalProperty - aimChatID: URIRef # An AIM chat ID - homepage: URIRef # A homepage for some thing. - icqChatID: URIRef # An ICQ chat ID - isPrimaryTopicOf: URIRef # A document that this thing is the primary topic of. - jabberID: URIRef # A jabber ID for something. - logo: URIRef # A logo representing some thing. - mbox: URIRef # A personal mailbox, ie. an Internet mailbox associated with exactly one owner, the first owner of this mailbox. This is a 'static inverse functional property', in that there is (across time and change) at most one individual that ever has any particular value for foaf:mbox. - mbox_sha1sum: URIRef # The sha1sum of the URI of an Internet mailbox associated with exactly one owner, the first owner of the mailbox. - msnChatID: URIRef # An MSN chat ID - openid: URIRef # An OpenID for an Agent. - weblog: URIRef # A weblog of some thing (whether person, group, company etc.). - yahooChatID: URIRef # A Yahoo chat ID - - _NS = Namespace("http://xmlns.com/foaf/0.1/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_GEO.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_GEO.py deleted file mode 100644 index d7168d6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_GEO.py +++ /dev/null @@ -1,111 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class GEO(DefinedNamespace): - """ - An RDF/OWL vocabulary for representing spatial information - - Generated from: http://schemas.opengis.net/geosparql/1.0/geosparql_vocab_all.rdf - Date: 2021-12-27 17:38:15.101187 - - .. code-block:: Turtle - - dc:creator "Open Geospatial Consortium"^^xsd:string - dc:date "2012-04-30"^^xsd:date - dc:source - "OGC GeoSPARQL – A Geographic Query Language for RDF Data OGC 11-052r5"^^xsd:string - rdfs:seeAlso - - - owl:imports dc: - - - - owl:versionInfo "OGC GeoSPARQL 1.0"^^xsd:string - """ - - # http://www.w3.org/2000/01/rdf-schema#Datatype - dggsLiteral: URIRef # A DGGS serialization of a geometry object. - geoJSONLiteral: URIRef # A GeoJSON serialization of a geometry object. - gmlLiteral: URIRef # A GML serialization of a geometry object. - kmlLiteral: URIRef # A KML serialization of a geometry object. - wktLiteral: URIRef # A Well-known Text serialization of a geometry object. - - # http://www.w3.org/2002/07/owl#Class - Feature: URIRef # This class represents the top-level feature type. This class is equivalent to GFI_Feature defined in ISO 19156:2011, and it is superclass of all feature types. - FeatureCollection: URIRef # A collection of individual Features. - Geometry: URIRef # The class represents the top-level geometry type. This class is equivalent to the UML class GM_Object defined in ISO 19107, and it is superclass of all geometry types. - GeometryCollection: URIRef # A collection of individual Geometries. - SpatialObject: URIRef # The class spatial-object represents everything that can have a spatial representation. It is superclass of feature and geometry. - SpatialObjectCollection: URIRef # A collection of individual Spatial Objects. This is the superclass of Feature Collection and Geometry Collection. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - asGML: URIRef # The GML serialization of a geometry - asWKT: URIRef # The WKT serialization of a geometry - asGeoJSON: URIRef # The GeoJSON serialization of a geometry - asKML: URIRef # The KML serialization of a geometry - asDGGS: URIRef # The DGGS serialization of a geometry - coordinateDimension: URIRef # The number of measurements or axes needed to describe the position of this geometry in a coordinate system. - dimension: URIRef # The topological dimension of this geometric object, which must be less than or equal to the coordinate dimension. In non-homogeneous collections, this will return the largest topological dimension of the contained objects. - hasMetricArea: URIRef # The area of a Spatial Object in square meters. - hasMetricLength: URIRef # The length of a Spatial Object in meters. - hasMetricPerimeterLength: ( - URIRef # The length of the perimeter of a Spatial Object in meters. - ) - hasMetricSpatialAccuracy: URIRef # The spatial resolution of a Geometry in meters. - hasMetricSpatialResolution: ( - URIRef # The spatial resolution of a Geometry in meters. - ) - hasMetricSize: URIRef # Subproperties of this property are used to indicate the size of a Spatial Object as a measurement or estimate of one or more dimensions of the Spatial Object's spatial presence. Units are always metric (meter, square meter or cubic meter) - hasMetricVolume: URIRef # The volume of a Spatial Object in cubic meters. - hasSerialization: ( - URIRef # Connects a geometry object with its text-based serialization. - ) - isEmpty: URIRef # (true) if this geometric object is the empty Geometry. If true, then this geometric object represents the empty point set for the coordinate space. - isSimple: URIRef # (true) if this geometric object has no anomalous geometric points, such as self intersection or self tangency. - spatialDimension: URIRef # The number of measurements or axes needed to describe the spatial position of this geometry in a coordinate system. - - # http://www.w3.org/2002/07/owl#ObjectProperty - defaultGeometry: URIRef # The default geometry to be used in spatial calculations. It is Usually the most detailed geometry. - ehContains: URIRef # Exists if the subject SpatialObject spatially contains the object SpatialObject. DE-9IM: T*TFF*FF* - ehCoveredBy: URIRef # Exists if the subject SpatialObject is spatially covered by the object SpatialObject. DE-9IM: TFF*TFT** - ehCovers: URIRef # Exists if the subject SpatialObject spatially covers the object SpatialObject. DE-9IM: T*TFT*FF* - ehDisjoint: URIRef # Exists if the subject SpatialObject is spatially disjoint from the object SpatialObject. DE-9IM: FF*FF**** - ehEquals: URIRef # Exists if the subject SpatialObject spatially equals the object SpatialObject. DE-9IM: TFFFTFFFT - ehInside: URIRef # Exists if the subject SpatialObject is spatially inside the object SpatialObject. DE-9IM: TFF*FFT** - ehMeet: URIRef # Exists if the subject SpatialObject spatially meets the object SpatialObject. DE-9IM: FT******* ^ F**T***** ^ F***T**** - ehOverlap: URIRef # Exists if the subject SpatialObject spatially overlaps the object SpatialObject. DE-9IM: T*T***T** - hasArea: URIRef # The area of a Spatial Object. - hasBoundingBox: ( - URIRef # The minimum or smallest bounding or enclosing box of a given Feature. - ) - hasCentroid: URIRef # The arithmetic mean position of all the geometry points of a given Feature. - hasDefaultGeometry: URIRef # The default geometry to be used in spatial calculations, usually the most detailed geometry. - hasGeometry: URIRef # A spatial representation for a given feature. - hasLength: URIRef # The length of a Spatial Object. - hasPerimeterLength: URIRef # The length of the perimeter of a Spatial Object. - hasSize: URIRef # Subproperties of this property are used to indicate the size of a Spatial Object as a measurement or estimate of one or more dimensions of the Spatial Object's spatial presence. - hasSpatialAccuracy: ( - URIRef # The positional accuracy of the coordinates of a Geometry. - ) - hasSpatialResolution: URIRef # The spatial resolution of a Geometry. - hasVolume: URIRef # he volume of a three-dimensional Spatial Object. - rcc8dc: URIRef # Exists if the subject SpatialObject is spatially disjoint from the object SpatialObject. DE-9IM: FFTFFTTTT - rcc8ec: URIRef # Exists if the subject SpatialObject spatially meets the object SpatialObject. DE-9IM: FFTFTTTTT - rcc8eq: URIRef # Exists if the subject SpatialObject spatially equals the object SpatialObject. DE-9IM: TFFFTFFFT - rcc8ntpp: URIRef # Exists if the subject SpatialObject is spatially inside the object SpatialObject. DE-9IM: TFFTFFTTT - rcc8ntppi: URIRef # Exists if the subject SpatialObject spatially contains the object SpatialObject. DE-9IM: TTTFFTFFT - rcc8po: URIRef # Exists if the subject SpatialObject spatially overlaps the object SpatialObject. DE-9IM: TTTTTTTTT - rcc8tpp: URIRef # Exists if the subject SpatialObject is spatially covered by the object SpatialObject. DE-9IM: TFFTTFTTT - rcc8tppi: URIRef # Exists if the subject SpatialObject spatially covers the object SpatialObject. DE-9IM: TTTFTTFFT - sfContains: URIRef # Exists if the subject SpatialObject spatially contains the object SpatialObject. DE-9IM: T*****FF* - sfCrosses: URIRef # Exists if the subject SpatialObject spatially crosses the object SpatialObject. DE-9IM: T*T****** - sfDisjoint: URIRef # Exists if the subject SpatialObject is spatially disjoint from the object SpatialObject. DE-9IM: FF*FF**** - sfEquals: URIRef # Exists if the subject SpatialObject spatially equals the object SpatialObject. DE-9IM: TFFFTFFFT - sfIntersects: URIRef # Exists if the subject SpatialObject is not spatially disjoint from the object SpatialObject. DE-9IM: T******** ^ *T******* ^ ***T***** ^ ****T**** - sfOverlaps: URIRef # Exists if the subject SpatialObject spatially overlaps the object SpatialObject. DE-9IM: T*T***T** - sfTouches: URIRef # Exists if the subject SpatialObject spatially touches the object SpatialObject. DE-9IM: FT******* ^ F**T***** ^ F***T**** - sfWithin: URIRef # Exists if the subject SpatialObject is spatially within the object SpatialObject. DE-9IM: T*F**F*** - - _NS = Namespace("http://www.opengis.net/ont/geosparql#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ODRL2.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ODRL2.py deleted file mode 100644 index acb0b5b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ODRL2.py +++ /dev/null @@ -1,283 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class ODRL2(DefinedNamespace): - """ - ODRL Version 2.2 - - The ODRL Vocabulary and Expression defines a set of concepts and terms (the vocabulary) and encoding mechanism - (the expression) for permissions and obligations statements describing digital content usage based on the ODRL - Information Model. - - Generated from: https://www.w3.org/ns/odrl/2/ODRL22.ttl - Date: 2020-05-26 14:20:02.352356 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - action: URIRef # The operation relating to the Asset for which the Rule is being subjected. - andSequence: URIRef # The relation is satisfied when each of the Constraints are satisfied in the order specified. - assignee: URIRef # The Party is the recipient of the Rule. - assigneeOf: URIRef # Identifies an ODRL Policy for which the identified Party undertakes the assignee functional role. - assigner: URIRef # The Party is the issuer of the Rule. - assignerOf: URIRef # Identifies an ODRL Policy for which the identified Party undertakes the assigner functional role. - attributedParty: URIRef # The Party to be attributed. - attributingParty: URIRef # The Party who undertakes the attribution. - compensatedParty: URIRef # The Party is the recipient of the compensation. - compensatingParty: URIRef # The Party that is the provider of the compensation. - conflict: URIRef # The conflict-resolution strategy for a Policy. - consentedParty: URIRef # The Party who obtains the consent. - consentingParty: URIRef # The Party to obtain consent from. - consequence: URIRef # Relates a Duty to another Duty, the latter being a consequence of not fulfilling the former. - constraint: URIRef # Constraint applied to a Rule - contractedParty: URIRef # The Party who is being contracted. - contractingParty: URIRef # The Party who is offering the contract. - dataType: URIRef # The datatype of the value of the rightOperand or rightOperandReference of a Constraint. - duty: URIRef # Relates an individual Duty to a Permission. - failure: URIRef # Failure is an abstract property that defines the violation (or unmet) relationship between Rules. - function: URIRef # Function is an abstract property whose sub-properties define the functional roles which may be fulfilled by a party in relation to a Rule. - hasPolicy: URIRef # Identifies an ODRL Policy for which the identified Asset is the target Asset to all the Rules. - implies: URIRef # An Action asserts that another Action is not prohibited to enable its operational semantics. - includedIn: URIRef # An Action transitively asserts that another Action that encompasses its operational semantics. - informedParty: URIRef # The Party to be informed of all uses. - informingParty: URIRef # The Party who provides the inform use data. - inheritAllowed: URIRef # Indicates if the Policy entity can be inherited. - inheritFrom: URIRef # Relates a (child) policy to another (parent) policy from which terms are inherited. - inheritRelation: URIRef # Identifies the type of inheritance. - leftOperand: URIRef # The left operand in a constraint expression. - obligation: URIRef # Relates an individual Duty to a Policy. - operand: URIRef # Operand is an abstract property for a logical relationship. - operator: URIRef # The operator function applied to operands of a Constraint - output: URIRef # The output property specifies the Asset which is created from the output of the Action. - partOf: URIRef # Identifies an Asset/PartyCollection that the Asset/Party is a member of. - payeeParty: URIRef # The Party is the recipient of the payment. - permission: URIRef # Relates an individual Permission to a Policy. - profile: URIRef # The identifier(s) of an ODRL Profile that the Policy conforms to. - prohibition: URIRef # Relates an individual Prohibition to a Policy. - proximity: URIRef # An value indicating the closeness or nearness. - refinement: URIRef # Constraint used to refine the semantics of an Action, or Party/Asset Collection - relation: URIRef # Relation is an abstract property which creates an explicit link between an Action and an Asset. - remedy: URIRef # Relates an individual remedy Duty to a Prohibition. - rightOperand: URIRef # The value of the right operand in a constraint expression. - rightOperandReference: URIRef # A reference to a web resource providing the value for the right operand of a Constraint. - scope: URIRef # The identifier of a scope that provides context to the extent of the entity. - source: URIRef # Reference to a Asset/PartyCollection - status: URIRef # the value generated from the leftOperand action or a value related to the leftOperand set as the reference for the comparison. - target: URIRef # The target property indicates the Asset that is the primary subject to which the Rule action directly applies. - timedCount: URIRef # The number of seconds after which timed metering use of the asset begins. - trackedParty: URIRef # The Party whose usage is being tracked. - trackingParty: URIRef # The Party who is tracking usage. - uid: URIRef # An unambiguous identifier - undefined: ( - URIRef # Relates the strategy used for handling undefined actions to a Policy. - ) - unit: URIRef # The unit of measurement of the value of the rightOperand or rightOperandReference of a Constraint. - xone: URIRef # The relation is satisfied when only one, and not more, of the Constraints is satisfied - - # http://www.w3.org/2002/07/owl#NamedIndividual - All: URIRef # Specifies that the scope of the relationship is all of the collective individuals within a context. - All2ndConnections: URIRef # Specifies that the scope of the relationship is all of the second-level connections to the Party. - AllConnections: URIRef # Specifies that the scope of the relationship is all of the first-level connections of the Party. - AllGroups: URIRef # Specifies that the scope of the relationship is all of the group connections of the Party. - Group: URIRef # Specifies that the scope of the relationship is the defined group with multiple individual members. - Individual: URIRef # Specifies that the scope of the relationship is the single Party individual. - absolutePosition: URIRef # A point in space or time defined with absolute coordinates for the positioning of the target Asset. - absoluteSize: URIRef # Measure(s) of one or two axes for 2D-objects or measure(s) of one to tree axes for 3D-objects of the target Asset. - absoluteSpatialPosition: URIRef # The absolute spatial positions of four corners of a rectangle on a 2D-canvas or the eight corners of a cuboid in a 3D-space for the target Asset to fit. - absoluteTemporalPosition: URIRef # The absolute temporal positions in a media stream the target Asset has to fit. - count: URIRef # Numeric count of executions of the action of the Rule. - dateTime: URIRef # The date (and optional time and timezone) of exercising the action of the Rule. Right operand value MUST be an xsd:date or xsd:dateTime as defined by [[xmlschema11-2]]. - delayPeriod: URIRef # A time delay period prior to exercising the action of the Rule. The point in time triggering this period MAY be defined by another temporal Constraint combined by a Logical Constraint (utilising the odrl:andSequence operand). Right operand value MUST be an xsd:duration as defined by [[xmlschema11-2]]. - deliveryChannel: ( - URIRef # The delivery channel used for exercising the action of the Rule. - ) - device: URIRef # An identified device used for exercising the action of the Rule. - elapsedTime: URIRef # A continuous elapsed time period which may be used for exercising of the action of the Rule. Right operand value MUST be an xsd:duration as defined by [[xmlschema11-2]]. - eq: URIRef # Indicating that a given value equals the right operand of the Constraint. - event: URIRef # An identified event setting a context for exercising the action of the Rule. - fileFormat: URIRef # A transformed file format of the target Asset. - gt: URIRef # Indicating that a given value is greater than the right operand of the Constraint. - gteq: URIRef # Indicating that a given value is greater than or equal to the right operand of the Constraint. - hasPart: URIRef # A set-based operator indicating that a given value contains the right operand of the Constraint. - ignore: URIRef # The Action is to be ignored and is not part of the policy – and the policy remains valid. - industry: URIRef # A defined industry sector setting a context for exercising the action of the Rule. - invalid: URIRef # The policy is void. - isA: URIRef # A set-based operator indicating that a given value is an instance of the right operand of the Constraint. - isAllOf: URIRef # A set-based operator indicating that a given value is all of the right operand of the Constraint. - isAnyOf: URIRef # A set-based operator indicating that a given value is any of the right operand of the Constraint. - isNoneOf: URIRef # A set-based operator indicating that a given value is none of the right operand of the Constraint. - isPartOf: URIRef # A set-based operator indicating that a given value is contained by the right operand of the Constraint. - language: URIRef # A natural language used by the target Asset. - lt: URIRef # Indicating that a given value is less than the right operand of the Constraint. - lteq: URIRef # Indicating that a given value is less than or equal to the right operand of the Constraint. - media: URIRef # Category of a media asset setting a context for exercising the action of the Rule. - meteredTime: URIRef # An accumulated amount of one to many metered time periods which were used for exercising the action of the Rule. Right operand value MUST be an xsd:duration as defined by [[xmlschema11-2]]. - neq: URIRef # Indicating that a given value is not equal to the right operand of the Constraint. - payAmount: URIRef # The amount of a financial payment. Right operand value MUST be an xsd:decimal. - percentage: URIRef # A percentage amount of the target Asset relevant for exercising the action of the Rule. Right operand value MUST be an xsd:decimal from 0 to 100. - perm: URIRef # Permissions take preference over prohibitions. - policyUsage: ( - URIRef # Indicates the actual datetime the action of the Rule was exercised. - ) - product: URIRef # Category of product or service setting a context for exercising the action of the Rule. - prohibit: URIRef # Prohibitions take preference over permissions. - purpose: URIRef # A defined purpose for exercising the action of the Rule. - recipient: URIRef # The party receiving the result/outcome of exercising the action of the Rule. - relativePosition: URIRef # A point in space or time defined with coordinates relative to full measures the positioning of the target Asset. - relativeSize: URIRef # Measure(s) of one or two axes for 2D-objects or measure(s) of one to tree axes for 3D-objects - expressed as percentages of full values - of the target Asset. - relativeSpatialPosition: URIRef # The relative spatial positions - expressed as percentages of full values - of four corners of a rectangle on a 2D-canvas or the eight corners of a cuboid in a 3D-space of the target Asset. - relativeTemporalPosition: URIRef # A point in space or time defined with coordinates relative to full measures the positioning of the target Asset. - resolution: URIRef # Resolution of the rendition of the target Asset. - spatial: URIRef # A named and identified geospatial area with defined borders which is used for exercising the action of the Rule. An IRI MUST be used to represent this value. - spatialCoordinates: URIRef # A set of coordinates setting the borders of a geospatial area used for exercising the action of the Rule. The coordinates MUST include longitude and latitude, they MAY include altitude and the geodetic datum. - support: URIRef # The Action is to be supported as part of the policy – and the policy remains valid. - system: URIRef # An identified computing system used for exercising the action of the Rule. - systemDevice: URIRef # An identified computing system or computing device used for exercising the action of the Rule. - timeInterval: URIRef # A recurring period of time before the next execution of the action of the Rule. Right operand value MUST be an xsd:duration as defined by [[xmlschema11-2]]. - unitOfCount: URIRef # The unit of measure used for counting the executions of the action of the Rule. - version: URIRef # The version of the target Asset. - virtualLocation: URIRef # An identified location of the IT communication space which is relevant for exercising the action of the Rule. - - # http://www.w3.org/2004/02/skos/core#Collection - - # http://www.w3.org/2004/02/skos/core#Concept - Action: URIRef # An operation on an Asset. - Agreement: URIRef # A Policy that grants the assignee a Rule over an Asset from an assigner. - Assertion: URIRef # A Policy that asserts a Rule over an Asset from parties. - Asset: URIRef # A resource or a collection of resources that are the subject of a Rule. - AssetCollection: URIRef # An Asset that is collection of individual resources - AssetScope: URIRef # Scopes for Asset Scope expressions. - ConflictTerm: URIRef # Used to establish strategies to resolve conflicts that arise from the merging of Policies or conflicts between Permissions and Prohibitions in the same Policy. - Constraint: URIRef # A boolean expression that refines the semantics of an Action and Party/Asset Collection or declare the conditions applicable to a Rule. - Duty: URIRef # The obligation to perform an Action - LeftOperand: URIRef # Left operand for a constraint expression. - LogicalConstraint: URIRef # A logical expression that refines the semantics of an Action and Party/Asset Collection or declare the conditions applicable to a Rule. - Offer: URIRef # A Policy that proposes a Rule over an Asset from an assigner. - Operator: URIRef # Operator for constraint expression. - Party: ( - URIRef # An entity or a collection of entities that undertake Roles in a Rule. - ) - PartyCollection: URIRef # A Party that is a group of individual entities - PartyScope: URIRef # Scopes for Party Scope expressions. - Permission: URIRef # The ability to perform an Action over an Asset. - Policy: URIRef # A non-empty group of Permissions and/or Prohibitions. - Privacy: URIRef # A Policy that expresses a Rule over an Asset containing personal information. - Prohibition: URIRef # The inability to perform an Action over an Asset. - Request: URIRef # A Policy that proposes a Rule over an Asset from an assignee. - RightOperand: URIRef # Right operand for constraint expression. - Rule: URIRef # An abstract concept that represents the common characteristics of Permissions, Prohibitions, and Duties. - Set: URIRef # A Policy that expresses a Rule over an Asset. - Ticket: ( - URIRef # A Policy that grants the holder a Rule over an Asset from an assigner. - ) - UndefinedTerm: URIRef # Is used to indicate how to support Actions that are not part of any vocabulary or profile in the policy expression system. - acceptTracking: URIRef # To accept that the use of the Asset may be tracked. - adHocShare: URIRef # The act of sharing the asset to parties in close proximity to the owner. - aggregate: ( - URIRef # To use the Asset or parts of it as part of a composite collection. - ) - annotate: URIRef # To add explanatory notations/commentaries to the Asset without modifying the Asset in any other way. - anonymize: URIRef # To anonymize all or parts of the Asset. - append: URIRef # The act of adding to the end of an asset. - appendTo: URIRef # The act of appending data to the Asset without modifying the Asset in any other way. - archive: URIRef # To store the Asset (in a non-transient form). - attachPolicy: URIRef # The act of keeping the policy notice with the asset. - attachSource: ( - URIRef # The act of attaching the source of the asset and its derivatives. - ) - attribute: URIRef # To attribute the use of the Asset. - commercialize: URIRef # The act of using the asset in a business environment. - compensate: URIRef # To compensate by transfer of some amount of value, if defined, for using or selling the Asset. - concurrentUse: URIRef # To create multiple copies of the Asset that are being concurrently used. - copy: URIRef # The act of making an exact reproduction of the asset. - core: URIRef # Identifier for the ODRL Core Profile - delete: ( - URIRef # To permanently remove all copies of the Asset after it has been used. - ) - derive: URIRef # To create a new derivative Asset from this Asset and to edit or modify the derivative. - digitize: URIRef # To produce a digital copy of (or otherwise digitize) the Asset from its analogue form. - display: URIRef # To create a static and transient rendition of an Asset. - distribute: URIRef # To supply the Asset to third-parties. - ensureExclusivity: URIRef # To ensure that the Rule on the Asset is exclusive. - execute: URIRef # To run the computer program Asset. - export: URIRef # The act of transforming the asset into a new form. - extract: URIRef # To extract parts of the Asset and to use it as a new Asset. - extractChar: URIRef # The act of extracting (replicating) unchanged characters from the asset. - extractPage: ( - URIRef # The act of extracting (replicating) unchanged pages from the asset. - ) - extractWord: ( - URIRef # The act of extracting (replicating) unchanged words from the asset. - ) - give: URIRef # To transfer the ownership of the Asset to a third party without compensation and while deleting the original asset. - grantUse: URIRef # To grant the use of the Asset to third parties. - include: URIRef # To include other related assets in the Asset. - index: URIRef # To record the Asset in an index. - inform: URIRef # To inform that an action has been performed on or in relation to the Asset. - install: URIRef # To load the computer program Asset onto a storage device which allows operating or running the Asset. - lease: URIRef # The act of making available the asset to a third-party for a fixed period of time with exchange of value. - lend: URIRef # The act of making available the asset to a third-party for a fixed period of time without exchange of value. - license: URIRef # The act of granting the right to use the asset to a third-party. - modify: URIRef # To change existing content of the Asset. A new asset is not created by this action. - move: URIRef # To move the Asset from one digital location to another including deleting the original copy. - nextPolicy: URIRef # To grant the specified Policy to a third party for their use of the Asset. - obtainConsent: URIRef # To obtain verifiable consent to perform the requested action in relation to the Asset. - pay: URIRef # The act of paying a financial amount to a party for use of the asset. - play: URIRef # To create a sequential and transient rendition of an Asset. - present: URIRef # To publicly perform the Asset. - preview: URIRef # The act of providing a short preview of the asset. - print: URIRef # To create a tangible and permanent rendition of an Asset. - read: URIRef # To obtain data from the Asset. - reproduce: URIRef # To make duplicate copies the Asset in any material form. - reviewPolicy: URIRef # To review the Policy applicable to the Asset. - secondaryUse: URIRef # The act of using the asset for a purpose other than the purpose it was intended for. - sell: URIRef # To transfer the ownership of the Asset to a third party with compensation and while deleting the original asset. - share: URIRef # The act of the non-commercial reproduction and distribution of the asset to third-parties. - shareAlike: URIRef # The act of distributing any derivative asset under the same terms as the original asset. - stream: URIRef # To deliver the Asset in real-time. - synchronize: URIRef # To use the Asset in timed relations with media (audio/visual) elements of another Asset. - textToSpeech: URIRef # To have a text Asset read out loud. - transfer: URIRef # To transfer the ownership of the Asset in perpetuity. - transform: URIRef # To convert the Asset into a different format. - translate: URIRef # To translate the original natural language of an Asset into another natural language. - uninstall: URIRef # To unload and delete the computer program Asset from a storage device and disable its readiness for operation. - use: URIRef # To use the Asset - watermark: URIRef # To apply a watermark to the Asset. - write: URIRef # The act of writing to the Asset. - writeTo: URIRef # The act of adding data to the Asset. - - # Valid non-python identifiers - _extras = [ - "and", - "or", - "#actionConcepts", - "#actions", - "#actionsCommon", - "#assetConcepts", - "#assetParty", - "#assetRelations", - "#assetRelationsCommon", - "#conflictConcepts", - "#constraintLeftOperandCommon", - "#constraintLogicalOperands", - "#constraintRelationalOperators", - "#constraintRightOpCommon", - "#constraints", - "#deprecatedTerms", - "#duties", - "#logicalConstraints", - "#partyConcepts", - "#partyRoles", - "#partyRolesCommon", - "#permissions", - "#policyConcepts", - "#policySubClasses", - "#policySubClassesCommon", - "#prohibitions", - "#ruleConcepts", - ] - - _NS = Namespace("http://www.w3.org/ns/odrl/2/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ORG.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ORG.py deleted file mode 100644 index 1d6e187..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_ORG.py +++ /dev/null @@ -1,70 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class ORG(DefinedNamespace): - """ - Core organization ontology - - Vocabulary for describing organizational structures, specializable to a broad variety of types of - organization. - - Generated from: http://www.w3.org/ns/org# - Date: 2020-05-26 14:20:02.908408 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - basedAt: URIRef # Indicates the site at which a person is based. We do not restrict the possibility that a person is based at multiple sites. - changedBy: URIRef # Indicates a change event which resulted in a change to this organization. Depending on the event the organization may or may not have continued to exist after the event. Inverse of `org:originalOrganization`. - classification: URIRef # Indicates a classification for this Organization within some classification scheme. Extension vocabularies may wish to specialize this property to have a range corresponding to a specific `skos:ConceptScheme`. This property is under discussion and may be revised or removed - in many cases organizations are best categorized by defining a sub-class hierarchy in an extension vocabulary. - hasMember: URIRef # Indicates a person who is a member of the subject Organization. Inverse of `org:memberOf`, see that property for further clarification. Provided for compatibility with `foaf:member`. - hasMembership: URIRef # Indicates a membership relationship that the Agent plays. Inverse of `org:member`. - hasPost: URIRef # Indicates a Post which exists within the Organization. - hasPrimarySite: URIRef # Indicates a primary site for the Organization, this is the default means by which an Organization can be contacted and is not necessarily the formal headquarters. - hasRegisteredSite: URIRef # Indicates the legally registered site for the organization, in many legal jurisdictions there is a requirement that FormalOrganizations such as Companies or Charities have such a primary designed site. - hasSite: URIRef # Indicates a site at which the Organization has some presence even if only indirect (e.g. virtual office or a professional service which is acting as the registered address for a company). Inverse of `org:siteOf`. - hasSubOrganization: URIRef # Represents hierarchical containment of Organizations or Organizational Units; indicates an organization which is a sub-part or child of this organization. Inverse of `org:subOrganizationOf`. - hasUnit: URIRef # Indicates a unit which is part of this Organization, e.g. a Department within a larger FormalOrganization. Inverse of `org:unitOf`. - headOf: URIRef # Indicates that a person is the leader or formal head of the Organization. This will normally mean that they are the root of the `org:reportsTo` (acyclic) graph, though an organization may have more than one head. - heldBy: URIRef # Indicates an Agent which holds a Post. - holds: URIRef # Indicates a Post held by some Agent. - identifier: URIRef # Gives an identifier, such as a company registration number, that can be used to used to uniquely identify the organization. Many different national and international identier schemes are available. The org ontology is neutral to which schemes are used. The particular identifier scheme should be indicated by the datatype of the identifier value. Using datatypes to distinguish the notation scheme used is consistent with recommended best practice for `skos:notation` of which this property is a specialization. - linkedTo: URIRef # Indicates an arbitrary relationship between two organizations. Specializations of this can be used to, for example, denote funding or supply chain relationships. - location: URIRef # Gives a location description for a person within the organization, for example a _Mail Stop_ for internal posting purposes. - member: URIRef # Indicates the Person (or other Agent including Organization) involved in the Membership relationship. Inverse of `org:hasMembership` - memberDuring: URIRef # Optional property to indicate the interval for which the membership is/was valid. - memberOf: URIRef # Indicates that a person is a member of the Organization with no indication of the nature of that membership or the role played. Note that the choice of property name is not meant to limit the property to only formal membership arrangements, it is also intended to cover related concepts such as affilliation or other involvement in the organization. Extensions can specialize this relationship to indicate particular roles within the organization or more nuanced relationships to the organization. Has an optional inverse, `org:hasmember`. - organization: URIRef # Indicates Organization in which the Agent is a member. - originalOrganization: URIRef # Indicates one or more organizations that existed before the change event. Depending on the event they may or may not have continued to exist after the event. Inverse of `org:changedBy`. - postIn: URIRef # Indicates the Organization in which the Post exists. - purpose: URIRef # Indicates the purpose of this Organization. There can be many purposes at different levels of abstraction but the nature of an organization is to have a reason for existence and this property is a means to document that reason. An Organization may have multiple purposes. It is recommended that the purpose be denoted by a controlled term or code list, ideally a `skos:Concept`. However, the range is left open to allow for other types of descriptive schemes. It is expected that specializations or application profiles of this vocabulary will constrain the range of the purpose. Alternative names: _remit_ _responsibility_ (esp. if applied to OrganizationalUnits such as Government Departments). - remuneration: URIRef # Indicates a salary or other reward associated with the role. Typically this will be denoted using an existing representation scheme such as `gr:PriceSpecification` but the range is left open to allow applications to specialize it (e.g. to remunerationInGBP). - reportsTo: URIRef # Indicates a reporting relationship as might be depicted on an organizational chart. The precise semantics of the reporting relationship will vary by organization but is intended to encompass both direct supervisory relationships (e.g. carrying objective and salary setting authority) and more general reporting or accountability relationships (e.g. so called _dotted line_ reporting). - resultedFrom: URIRef # Indicates an event which resulted in this organization. Inverse of `org:resultingOrganization`. - resultingOrganization: URIRef # Indicates an organization which was created or changed as a result of the event. Inverse of `org:resultedFrom`. - role: URIRef # Indicates the Role that the Agent plays in a Membership relationship with an Organization. - roleProperty: URIRef # This is a metalevel property which is used to annotate an `org:Role` instance with a sub-property of `org:memberOf` that can be used to directly indicate the role for easy of query. The intended semantics is a Membership relation involving the Role implies the existence of a direct property relationship through an inference rule of the form: `{ [] org:member ?p; org:organization ?o; org:role [org:roleProperty ?r] } -> {?p ?r ?o}`. - siteAddress: URIRef # Indicates an address for the site in a suitable encoding. Use of vCard (using the http://www.w3.org/TR/vcard-rdf/ vocabulary) is encouraged but the range is left open to allow other encodings to be used. The address may include email, telephone, and geo-location information and is not restricted to a physical address. - siteOf: URIRef # Indicates an Organization which has some presence at the given site. This is the inverse of `org:hasSite`. - subOrganizationOf: URIRef # Represents hierarchical containment of Organizations or OrganizationalUnits; indicates an Organization which contains this Organization. Inverse of `org:hasSubOrganization`. - transitiveSubOrganizationOf: URIRef # The transitive closure of subOrganizationOf, giving a representation of all organizations that contain this one. Note that technically this is a super property of the transitive closure so it could contain additional assertions but such usage is discouraged. - unitOf: URIRef # Indicates an Organization of which this Unit is a part, e.g. a Department within a larger FormalOrganization. This is the inverse of `org:hasUnit`. - - # http://www.w3.org/2000/01/rdf-schema#Class - ChangeEvent: URIRef # Represents an event which resulted in a major change to an organization such as a merger or complete restructuring. It is intended for situations where the resulting organization is sufficient distinct from the original organizations that it has a distinct identity and distinct URI. Extension vocabularies should define sub-classes of this to denote particular categories of event. The instant or interval at which the event occurred should be given by `prov:startAtTime` and `prov:endedAtTime`, a description should be given by `dct:description`. - FormalOrganization: URIRef # An Organization which is recognized in the world at large, in particular in legal jurisdictions, with associated rights and responsibilities. Examples include a Corporation, Charity, Government or Church. Note that this is a super class of `gr:BusinessEntity` and it is recommended to use the GoodRelations vocabulary to denote Business classifications such as DUNS or NAICS. - Membership: URIRef # Indicates the nature of an Agent's membership of an organization. Represents an n-ary relation between an Agent, an Organization and a Role. It is possible to directly indicate membership, independent of the specific Role, through use of the `org:memberOf` property. - Organization: URIRef # Represents a collection of people organized together into a community or other social, commercial or political structure. The group has some common purpose or reason for existence which goes beyond the set of people belonging to it and can act as an Agent. Organizations are often decomposable into hierarchical structures. It is recommended that SKOS lexical labels should be used to label the Organization. In particular `skos:prefLabel` for the primary (possibly legally recognized name), `skos:altLabel` for alternative names (trading names, colloquial names) and `skos:notation` to denote a code from a code list. Alternative names: _Collective_ _Body_ _Org_ _Group_ - OrganizationalCollaboration: URIRef # A collaboration between two or more Organizations such as a project. It meets the criteria for being an Organization in that it has an identity and defining purpose independent of its particular members but is neither a formally recognized legal entity nor a sub-unit within some larger organization. Might typically have a shorter lifetime than the Organizations within it, but not necessarily. All members are `org:Organization`s rather than individuals and those Organizations can play particular roles within the venture. Alternative names: _Project_ _Venture_ _Endeavour_ _Consortium_ _Endeavour_ - OrganizationalUnit: URIRef # An Organization such as a University Support Unit which is part of some larger FormalOrganization and only has full recognition within the context of that FormalOrganization, it is not a Legal Entity in its own right. Units can be large and complex containing other Units and even FormalOrganizations. Alternative names: _OU_ _Unit_ _Department_ - Post: URIRef # A Post represents some position within an organization that exists independently of the person or persons filling it. Posts may be used to represent situations where a person is a member of an organization ex officio (for example the Secretary of State for Scotland is part of UK Cabinet by virtue of being Secretary of State for Scotland, not as an individual person). A post can be held by multiple people and hence can be treated as a organization in its own right. - Role: URIRef # Denotes a role that a Person or other Agent can take in an organization. Instances of this class describe the abstract role; to denote a specific instance of a person playing that role in a specific organization use an instance of `org:Membership`. It is common for roles to be arranged in some taxonomic structure and we use SKOS to represent that. The normal SKOS lexical properties should be used when labelling the Role. Additional descriptive properties for the Role, such as a Salary band, may be added by extension vocabularies. - Site: URIRef # An office or other premise at which the organization is located. Many organizations are spread across multiple sites and many sites will host multiple locations. In most cases a Site will be a physical location. However, we don't exclude the possibility of non-physical sites such as a virtual office with an associated post box and phone reception service. Extensions may provide subclasses to denote particular types of site. - - # http://www.w3.org/ns/org#Role - Head: URIRef # head - - _NS = Namespace("http://www.w3.org/ns/org#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_OWL.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_OWL.py deleted file mode 100644 index 47ad4e5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_OWL.py +++ /dev/null @@ -1,140 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class OWL(DefinedNamespace): - """ - The OWL 2 Schema vocabulary (OWL 2) - - This ontology partially describes the built-in classes and properties that together form the basis of - the RDF/XML syntax of OWL 2. The content of this ontology is based on Tables 6.1 and 6.2 in Section 6.4 - of the OWL 2 RDF-Based Semantics specification, available at http://www.w3.org/TR/owl2-rdf-based- - semantics/. Please note that those tables do not include the different annotations (labels, comments and - rdfs:isDefinedBy links) used in this file. Also note that the descriptions provided in this ontology do not - provide a complete and correct formal description of either the syntax or the semantics of the introduced - terms (please see the OWL 2 recommendations for the complete and normative specifications). Furthermore, - the information provided by this ontology may be misleading if not used with care. This ontology SHOULD NOT - be imported into OWL ontologies. Importing this file into an OWL 2 DL ontology will cause it to become - an OWL 2 Full ontology and may have other, unexpected, consequences. - - Generated from: http://www.w3.org/2002/07/owl# - Date: 2020-05-26 14:20:03.193795 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - allValuesFrom: URIRef # The property that determines the class that a universal property restriction refers to. - annotatedProperty: URIRef # The property that determines the predicate of an annotated axiom or annotated annotation. - annotatedSource: URIRef # The property that determines the subject of an annotated axiom or annotated annotation. - annotatedTarget: URIRef # The property that determines the object of an annotated axiom or annotated annotation. - assertionProperty: URIRef # The property that determines the predicate of a negative property assertion. - cardinality: URIRef # The property that determines the cardinality of an exact cardinality restriction. - complementOf: URIRef # The property that determines that a given class is the complement of another class. - datatypeComplementOf: URIRef # The property that determines that a given data range is the complement of another data range with respect to the data domain. - differentFrom: ( - URIRef # The property that determines that two given individuals are different. - ) - disjointUnionOf: URIRef # The property that determines that a given class is equivalent to the disjoint union of a collection of other classes. - disjointWith: ( - URIRef # The property that determines that two given classes are disjoint. - ) - distinctMembers: URIRef # The property that determines the collection of pairwise different individuals in a owl:AllDifferent axiom. - equivalentClass: URIRef # The property that determines that two given classes are equivalent, and that is used to specify datatype definitions. - equivalentProperty: ( - URIRef # The property that determines that two given properties are equivalent. - ) - hasKey: URIRef # The property that determines the collection of properties that jointly build a key. - hasSelf: URIRef # The property that determines the property that a self restriction refers to. - hasValue: URIRef # The property that determines the individual that a has-value restriction refers to. - intersectionOf: URIRef # The property that determines the collection of classes or data ranges that build an intersection. - inverseOf: ( - URIRef # The property that determines that two given properties are inverse. - ) - maxCardinality: URIRef # The property that determines the cardinality of a maximum cardinality restriction. - maxQualifiedCardinality: URIRef # The property that determines the cardinality of a maximum qualified cardinality restriction. - members: URIRef # The property that determines the collection of members in either a owl:AllDifferent, owl:AllDisjointClasses or owl:AllDisjointProperties axiom. - minCardinality: URIRef # The property that determines the cardinality of a minimum cardinality restriction. - minQualifiedCardinality: URIRef # The property that determines the cardinality of a minimum qualified cardinality restriction. - onClass: URIRef # The property that determines the class that a qualified object cardinality restriction refers to. - onDataRange: URIRef # The property that determines the data range that a qualified data cardinality restriction refers to. - onDatatype: URIRef # The property that determines the datatype that a datatype restriction refers to. - onProperties: URIRef # The property that determines the n-tuple of properties that a property restriction on an n-ary data range refers to. - onProperty: URIRef # The property that determines the property that a property restriction refers to. - oneOf: URIRef # The property that determines the collection of individuals or data values that build an enumeration. - propertyChainAxiom: URIRef # The property that determines the n-tuple of properties that build a sub property chain of a given property. - propertyDisjointWith: ( - URIRef # The property that determines that two given properties are disjoint. - ) - qualifiedCardinality: URIRef # The property that determines the cardinality of an exact qualified cardinality restriction. - sameAs: URIRef # The property that determines that two given individuals are equal. - someValuesFrom: URIRef # The property that determines the class that an existential property restriction refers to. - sourceIndividual: URIRef # The property that determines the subject of a negative property assertion. - targetIndividual: URIRef # The property that determines the object of a negative object property assertion. - targetValue: URIRef # The property that determines the value of a negative data property assertion. - unionOf: URIRef # The property that determines the collection of classes or data ranges that build a union. - withRestrictions: URIRef # The property that determines the collection of facet-value pairs that define a datatype restriction. - - # http://www.w3.org/2000/01/rdf-schema#Class - AllDifferent: URIRef # The class of collections of pairwise different individuals. - AllDisjointClasses: URIRef # The class of collections of pairwise disjoint classes. - AllDisjointProperties: ( - URIRef # The class of collections of pairwise disjoint properties. - ) - Annotation: URIRef # The class of annotated annotations for which the RDF serialization consists of an annotated subject, predicate and object. - AnnotationProperty: URIRef # The class of annotation properties. - AsymmetricProperty: URIRef # The class of asymmetric properties. - Axiom: URIRef # The class of annotated axioms for which the RDF serialization consists of an annotated subject, predicate and object. - Class: URIRef # The class of OWL classes. - DataRange: URIRef # The class of OWL data ranges, which are special kinds of datatypes. Note: The use of the IRI owl:DataRange has been deprecated as of OWL 2. The IRI rdfs:Datatype SHOULD be used instead. - DatatypeProperty: URIRef # The class of data properties. - DeprecatedClass: URIRef # The class of deprecated classes. - DeprecatedProperty: URIRef # The class of deprecated properties. - FunctionalProperty: URIRef # The class of functional properties. - InverseFunctionalProperty: URIRef # The class of inverse-functional properties. - IrreflexiveProperty: URIRef # The class of irreflexive properties. - NamedIndividual: URIRef # The class of named individuals. - NegativePropertyAssertion: URIRef # The class of negative property assertions. - ObjectProperty: URIRef # The class of object properties. - Ontology: URIRef # The class of ontologies. - OntologyProperty: URIRef # The class of ontology properties. - ReflexiveProperty: URIRef # The class of reflexive properties. - Restriction: URIRef # The class of property restrictions. - SymmetricProperty: URIRef # The class of symmetric properties. - TransitiveProperty: URIRef # The class of transitive properties. - - # http://www.w3.org/2002/07/owl#AnnotationProperty - backwardCompatibleWith: URIRef # The annotation property that indicates that a given ontology is backward compatible with another ontology. - deprecated: URIRef # The annotation property that indicates that a given entity has been deprecated. - incompatibleWith: URIRef # The annotation property that indicates that a given ontology is incompatible with another ontology. - priorVersion: URIRef # The annotation property that indicates the predecessor ontology of a given ontology. - versionInfo: URIRef # The annotation property that provides version information for an ontology or another OWL construct. - - # http://www.w3.org/2002/07/owl#Class - Nothing: URIRef # This is the empty class. - Thing: URIRef # The class of OWL individuals. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - bottomDataProperty: URIRef # The data property that does not relate any individual to any data value. - topDataProperty: ( - URIRef # The data property that relates every individual to every data value. - ) - - # http://www.w3.org/2002/07/owl#ObjectProperty - bottomObjectProperty: ( - URIRef # The object property that does not relate any two individuals. - ) - topObjectProperty: URIRef # The object property that relates every two individuals. - - # http://www.w3.org/2002/07/owl#OntologyProperty - imports: URIRef # The property that is used for importing other ontologies into a given ontology. - versionIRI: URIRef # The property that identifies the version IRI of an ontology. - - # http://www.w3.org/2000/01/rdf-schema#Datatype - # NOTE: the following two elements don't appear in the OWL RDF documents but are defined in the OWL2 Recommentation - # at https://www.w3.org/TR/owl2-syntax/#Datatype_Maps - rational: URIRef # The value space is the set of all rational numbers. The lexical form is numerator '/' denominator, where both are integers. - real: URIRef # The value space is the set of all real numbers. Does not directly provide any lexical forms. - - _NS = Namespace("http://www.w3.org/2002/07/owl#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROF.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROF.py deleted file mode 100644 index b0e26da..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROF.py +++ /dev/null @@ -1,39 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class PROF(DefinedNamespace): - """ - Profiles Vocabulary - - This vocabulary is for describing relationships between standards/specifications, profiles of them and - supporting artifacts such as validating resources. This model starts with - [http://dublincore.org/2012/06/14/dcterms#Standard](dct:Standard) entities which can either be Base - Specifications (a standard not profiling any other Standard) or Profiles (Standards which do profile others). - Base Specifications or Profiles can have Resource Descriptors associated with them that defines implementing - rules for the it. Resource Descriptors must indicate the role they play (to guide, to validate etc.) and the - formalism they adhere to (dct:format) to allow for content negotiation. A vocabulary of Resource Roles are - provided alongside this vocabulary but that list is extensible. - - Generated from: https://www.w3.org/ns/dx/prof/profilesont.ttl - Date: 2020-05-26 14:20:03.542924 - - """ - - # http://www.w3.org/2002/07/owl#Class - Profile: URIRef # A named set of constraints on one or more identified base specifications or other profiles, including the identification of any implementing subclasses of datatypes, semantic interpretations, vocabularies, options and parameters of those base specifications necessary to accomplish a particular function. This definition includes what are often called "application profiles", "metadata application profiles", or "metadata profiles". - ResourceDescriptor: URIRef # A resource that defines an aspect - a particular part or feature - of a Profile - ResourceRole: URIRef # The role that an Resource plays - - # http://www.w3.org/2002/07/owl#DatatypeProperty - hasToken: URIRef # A preferred alternative identifier for the Profile - - # http://www.w3.org/2002/07/owl#ObjectProperty - hasArtifact: URIRef # The URL of a downloadable file with particulars such as its format and role indicated by a Resource Descriptor - hasResource: URIRef # A resource which describes the nature of an artifact and the role it plays in relation to a profile - hasRole: URIRef # The function of the described artifactresource in the expression of the Profile, such as a specification, guidance documentation, SHACL file etc. - isInheritedFrom: URIRef # This property indicates a Resource Descriptor described by this Profile’s base specification that is to be considered a Resource Descriptor for this Profile also - isProfileOf: URIRef # A Profile is a profile of a dct:Standard (or a Base Specification or another Profile) - isTransitiveProfileOf: URIRef # A base specification an Profile conforms to - - _NS = Namespace("http://www.w3.org/ns/dx/prof/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROV.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROV.py deleted file mode 100644 index 6a7970d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_PROV.py +++ /dev/null @@ -1,250 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class PROV(DefinedNamespace): - """ - W3C PROVenance Interchange Ontology (PROV-O) - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). If - you wish to make comments regarding this document, please send them to public-prov-comments@w3.org (subscribe - public-prov-comments-request@w3.org, archives http://lists.w3.org/Archives/Public/public-prov-comments/). All - feedback is welcome. - - PROV Access and Query Ontology - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). If - you wish to make comments regarding this document, please send them to public-prov-comments@w3.org (subscribe - public-prov-comments-request@w3.org, archives http://lists.w3.org/Archives/Public/public-prov-comments/). All - feedback is welcome. - - Dublin Core extensions of the W3C PROVenance Interchange Ontology (PROV-O) - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). If - you wish to make comments regarding this document, please send them to public-prov-comments@w3.org (subscribe - public-prov-comments-request@w3.org, archives http://lists.w3.org/Archives/Public/public-prov-comments/). All - feedback is welcome. - - W3C PROV Linking Across Provenance Bundles Ontology (PROV-LINKS) - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). If - you wish to make comments regarding this document, please send them to public-prov-comments@w3.org (subscribe - public-prov-comments-request@w3.org, archives http://lists.w3.org/Archives/Public/public-prov-comments/ ). All - feedback is welcome. - - W3C PROVenance Interchange Ontology (PROV-O) Dictionary Extension - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). - If you wish to make comments regarding this document, please send them to public-prov-comments@w3.org - (subscribe public-prov-comments-request@w3.org, archives http://lists.w3.org/Archives/Public/public-prov- - comments/). All feedback is welcome. - - W3C PROVenance Interchange - - This document is published by the Provenance Working Group (http://www.w3.org/2011/prov/wiki/Main_Page). If - you wish to make comments regarding this document, please send them to public-prov-comments@w3.org (subscribe - public-prov-comments-request@w3.org, archives http://lists.w3.org/ Archives/Public/public-prov-comments/). All - feedback is welcome. - - Generated from: http://www.w3.org/ns/prov - Date: 2020-05-26 14:20:04.650279 - - """ - - _fail = True - - # http://www.w3.org/2000/01/rdf-schema#Resource - activityOfInfluence: URIRef # activityOfInfluence - agentOfInfluence: URIRef # agentOfInfluence - contributed: URIRef # contributed - ended: URIRef # ended - entityOfInfluence: URIRef # entityOfInfluence - generalizationOf: URIRef # generalizationOf - generatedAsDerivation: URIRef # generatedAsDerivation - hadDelegate: URIRef # hadDelegate - hadDerivation: URIRef # hadDerivation - hadInfluence: URIRef # hadInfluence - hadRevision: URIRef # hadRevision - informed: URIRef # informed - locationOf: URIRef # locationOf - qualifiedAssociationOf: URIRef # qualifiedAssociationOf - qualifiedAttributionOf: URIRef # qualifiedAttributionOf - qualifiedCommunicationOf: URIRef # qualifiedCommunicationOf - qualifiedDelegationOf: URIRef # qualifiedDelegationOf - qualifiedDerivationOf: URIRef # qualifiedDerivationOf - qualifiedEndOf: URIRef # qualifiedEndOf - qualifiedGenerationOf: URIRef # qualifiedGenerationOf - qualifiedInfluenceOf: URIRef # qualifiedInfluenceOf - qualifiedInvalidationOf: URIRef # qualifiedInvalidationOf - qualifiedQuotationOf: URIRef # qualifiedQuotationOf - qualifiedSourceOf: URIRef # qualifiedSourceOf - qualifiedStartOf: URIRef # qualifiedStartOf - qualifiedUsingActivity: URIRef # qualifiedUsingActivity - quotedAs: URIRef # quotedAs - revisedEntity: URIRef # revisedEntity - started: URIRef # started - wasActivityOfInfluence: URIRef # wasActivityOfInfluence - wasAssociateFor: URIRef # wasAssociateFor - wasMemberOf: URIRef # wasMemberOf - wasPlanOf: URIRef # wasPlanOf - wasPrimarySourceOf: URIRef # wasPrimarySourceOf - wasRoleIn: URIRef # wasRoleIn - wasUsedBy: URIRef # wasUsedBy - wasUsedInDerivation: URIRef # wasUsedInDerivation - - # http://www.w3.org/2002/07/owl#AnnotationProperty - aq: URIRef # - category: URIRef # Classify prov-o terms into three categories, including 'starting-point', 'qualifed', and 'extended'. This classification is used by the prov-o html document to gently introduce prov-o terms to its users. - component: URIRef # Classify prov-o terms into six components according to prov-dm, including 'agents-responsibility', 'alternate', 'annotations', 'collections', 'derivations', and 'entities-activities'. This classification is used so that readers of prov-o specification can find its correspondence with the prov-dm specification. - constraints: URIRef # A reference to the principal section of the PROV-CONSTRAINTS document that describes this concept. - definition: URIRef # A definition quoted from PROV-DM or PROV-CONSTRAINTS that describes the concept expressed with this OWL term. - dm: URIRef # A reference to the principal section of the PROV-DM document that describes this concept. - editorialNote: URIRef # A note by the OWL development team about how this term expresses the PROV-DM concept, or how it should be used in context of semantic web or linked data. - editorsDefinition: URIRef # When the prov-o term does not have a definition drawn from prov-dm, and the prov-o editor provides one. - inverse: URIRef # PROV-O does not define all property inverses. The directionalities defined in PROV-O should be given preference over those not defined. However, if users wish to name the inverse of a PROV-O property, the local name given by prov:inverse should be used. - n: URIRef # A reference to the principal section of the PROV-M document that describes this concept. - order: URIRef # The position that this OWL term should be listed within documentation. The scope of the documentation (e.g., among all terms, among terms within a prov:category, among properties applying to a particular class, etc.) is unspecified. - qualifiedForm: URIRef # This annotation property links a subproperty of prov:wasInfluencedBy with the subclass of prov:Influence and the qualifying property that are used to qualify it. Example annotation: prov:wasGeneratedBy prov:qualifiedForm prov:qualifiedGeneration, prov:Generation . Then this unqualified assertion: :entity1 prov:wasGeneratedBy :activity1 . can be qualified by adding: :entity1 prov:qualifiedGeneration :entity1Gen . :entity1Gen a prov:Generation, prov:Influence; prov:activity :activity1; :customValue 1337 . Note how the value of the unqualified influence (prov:wasGeneratedBy :activity1) is mirrored as the value of the prov:activity (or prov:entity, or prov:agent) property on the influence class. - sharesDefinitionWith: URIRef # - specializationOf: URIRef # specializationOf - todo: URIRef # - unqualifiedForm: URIRef # Classes and properties used to qualify relationships are annotated with prov:unqualifiedForm to indicate the property used to assert an unqualified provenance relation. - wasRevisionOf: URIRef # A revision is a derivation that revises an entity into a revised version. - - # http://www.w3.org/2002/07/owl#Class - Accept: URIRef # Accept - Activity: URIRef # Activity - ActivityInfluence: URIRef # ActivityInfluence provides additional descriptions of an Activity's binary influence upon any other kind of resource. Instances of ActivityInfluence use the prov:activity property to cite the influencing Activity. - Agent: URIRef # Agent - AgentInfluence: URIRef # AgentInfluence provides additional descriptions of an Agent's binary influence upon any other kind of resource. Instances of AgentInfluence use the prov:agent property to cite the influencing Agent. - Association: URIRef # An instance of prov:Association provides additional descriptions about the binary prov:wasAssociatedWith relation from an prov:Activity to some prov:Agent that had some responsibility for it. For example, :baking prov:wasAssociatedWith :baker; prov:qualifiedAssociation [ a prov:Association; prov:agent :baker; :foo :bar ]. - Attribution: URIRef # An instance of prov:Attribution provides additional descriptions about the binary prov:wasAttributedTo relation from an prov:Entity to some prov:Agent that had some responsible for it. For example, :cake prov:wasAttributedTo :baker; prov:qualifiedAttribution [ a prov:Attribution; prov:entity :baker; :foo :bar ]. - Bundle: URIRef # Note that there are kinds of bundles (e.g. handwritten letters, audio recordings, etc.) that are not expressed in PROV-O, but can be still be described by PROV-O. - Collection: URIRef # Collection - Communication: URIRef # An instance of prov:Communication provides additional descriptions about the binary prov:wasInformedBy relation from an informed prov:Activity to the prov:Activity that informed it. For example, :you_jumping_off_bridge prov:wasInformedBy :everyone_else_jumping_off_bridge; prov:qualifiedCommunication [ a prov:Communication; prov:activity :everyone_else_jumping_off_bridge; :foo :bar ]. - Contribute: URIRef # Contribute - Contributor: URIRef # Contributor - Copyright: URIRef # Copyright - Create: URIRef # Create - Creator: URIRef # Creator - Delegation: URIRef # An instance of prov:Delegation provides additional descriptions about the binary prov:actedOnBehalfOf relation from a performing prov:Agent to some prov:Agent for whom it was performed. For example, :mixing prov:wasAssociatedWith :toddler . :toddler prov:actedOnBehalfOf :mother; prov:qualifiedDelegation [ a prov:Delegation; prov:entity :mother; :foo :bar ]. - Derivation: URIRef # The more specific forms of prov:Derivation (i.e., prov:Revision, prov:Quotation, prov:PrimarySource) should be asserted if they apply. - Dictionary: URIRef # This concept allows for the provenance of the dictionary, but also of its constituents to be expressed. Such a notion of dictionary corresponds to a wide variety of concrete data structures, such as a maps or associative arrays. - DirectQueryService: URIRef # Type for a generic provenance query service. Mainly for use in RDF provenance query service descriptions, to facilitate discovery in linked data environments. - EmptyDictionary: URIRef # Empty Dictionary - End: URIRef # An instance of prov:End provides additional descriptions about the binary prov:wasEndedBy relation from some ended prov:Activity to an prov:Entity that ended it. For example, :ball_game prov:wasEndedBy :buzzer; prov:qualifiedEnd [ a prov:End; prov:entity :buzzer; :foo :bar; prov:atTime '2012-03-09T08:05:08-05:00'^^xsd:dateTime ]. - Entity: URIRef # Entity - EntityInfluence: URIRef # It is not recommended that the type EntityInfluence be asserted without also asserting one of its more specific subclasses. - Generation: URIRef # An instance of prov:Generation provides additional descriptions about the binary prov:wasGeneratedBy relation from a generated prov:Entity to the prov:Activity that generated it. For example, :cake prov:wasGeneratedBy :baking; prov:qualifiedGeneration [ a prov:Generation; prov:activity :baking; :foo :bar ]. - Influence: URIRef # Because prov:Influence is a broad relation, its most specific subclasses (e.g. prov:Communication, prov:Delegation, prov:End, prov:Revision, etc.) should be used when applicable. - Insertion: URIRef # Insertion - InstantaneousEvent: URIRef # An instantaneous event, or event for short, happens in the world and marks a change in the world, in its activities and in its entities. The term 'event' is commonly used in process algebra with a similar meaning. Events represent communications or interactions; they are assumed to be atomic and instantaneous. - Invalidation: URIRef # An instance of prov:Invalidation provides additional descriptions about the binary prov:wasInvalidatedBy relation from an invalidated prov:Entity to the prov:Activity that invalidated it. For example, :uncracked_egg prov:wasInvalidatedBy :baking; prov:qualifiedInvalidation [ a prov:Invalidation; prov:activity :baking; :foo :bar ]. - KeyEntityPair: URIRef # Key-Entity Pair - Location: URIRef # Location - Modify: URIRef # Modify - Organization: URIRef # Organization - Person: URIRef # Person - Plan: URIRef # There exist no prescriptive requirement on the nature of plans, their representation, the actions or steps they consist of, or their intended goals. Since plans may evolve over time, it may become necessary to track their provenance, so plans themselves are entities. Representing the plan explicitly in the provenance can be useful for various tasks: for example, to validate the execution as represented in the provenance record, to manage expectation failures, or to provide explanations. - PrimarySource: URIRef # An instance of prov:PrimarySource provides additional descriptions about the binary prov:hadPrimarySource relation from some secondary prov:Entity to an earlier, primary prov:Entity. For example, :blog prov:hadPrimarySource :newsArticle; prov:qualifiedPrimarySource [ a prov:PrimarySource; prov:entity :newsArticle; :foo :bar ] . - Publish: URIRef # Publish - Publisher: URIRef # Publisher - Quotation: URIRef # An instance of prov:Quotation provides additional descriptions about the binary prov:wasQuotedFrom relation from some taken prov:Entity from an earlier, larger prov:Entity. For example, :here_is_looking_at_you_kid prov:wasQuotedFrom :casablanca_script; prov:qualifiedQuotation [ a prov:Quotation; prov:entity :casablanca_script; :foo :bar ]. - Removal: URIRef # Removal - Replace: URIRef # Replace - Revision: URIRef # An instance of prov:Revision provides additional descriptions about the binary prov:wasRevisionOf relation from some newer prov:Entity to an earlier prov:Entity. For example, :draft_2 prov:wasRevisionOf :draft_1; prov:qualifiedRevision [ a prov:Revision; prov:entity :draft_1; :foo :bar ]. - RightsAssignment: URIRef # RightsAssignment - RightsHolder: URIRef # RightsHolder - Role: URIRef # Role - ServiceDescription: URIRef # Type for a generic provenance query service. Mainly for use in RDF provenance query service descriptions, to facilitate discovery in linked data environments. - SoftwareAgent: URIRef # SoftwareAgent - Start: URIRef # An instance of prov:Start provides additional descriptions about the binary prov:wasStartedBy relation from some started prov:Activity to an prov:Entity that started it. For example, :foot_race prov:wasStartedBy :bang; prov:qualifiedStart [ a prov:Start; prov:entity :bang; :foo :bar; prov:atTime '2012-03-09T08:05:08-05:00'^^xsd:dateTime ] . - Submit: URIRef # Submit - Usage: URIRef # An instance of prov:Usage provides additional descriptions about the binary prov:used relation from some prov:Activity to an prov:Entity that it used. For example, :keynote prov:used :podium; prov:qualifiedUsage [ a prov:Usage; prov:entity :podium; :foo :bar ]. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - atTime: URIRef # The time at which an InstantaneousEvent occurred, in the form of xsd:dateTime. - endedAtTime: ( - URIRef # The time at which an activity ended. See also prov:startedAtTime. - ) - generatedAtTime: URIRef # The time at which an entity was completely created and is available for use. - invalidatedAtTime: ( - URIRef # The time at which an entity was invalidated (i.e., no longer usable). - ) - provenanceUriTemplate: URIRef # Relates a provenance service to a URI template string for constructing provenance-URIs. - removedKey: URIRef # removedKey - startedAtTime: ( - URIRef # The time at which an activity started. See also prov:endedAtTime. - ) - value: URIRef # value - - # http://www.w3.org/2002/07/owl#FunctionalProperty - pairEntity: URIRef # pairKey - pairKey: URIRef # pairKey - - # http://www.w3.org/2002/07/owl#NamedIndividual - EmptyCollection: URIRef # EmptyCollection - - # http://www.w3.org/2002/07/owl#ObjectProperty - actedOnBehalfOf: URIRef # An object property to express the accountability of an agent towards another agent. The subordinate agent acted on behalf of the responsible agent in an actual activity. - activity: URIRef # activity - agent: URIRef # agent - alternateOf: URIRef # alternateOf - asInBundle: URIRef # prov:asInBundle is used to specify which bundle the general entity of a prov:mentionOf property is described. When :x prov:mentionOf :y and :y is described in Bundle :b, the triple :x prov:asInBundle :b is also asserted to cite the Bundle in which :y was described. - atLocation: URIRef # The Location of any resource. - derivedByInsertionFrom: URIRef # derivedByInsertionFrom - derivedByRemovalFrom: URIRef # derivedByRemovalFrom - describesService: URIRef # relates a generic provenance query service resource (type prov:ServiceDescription) to a specific query service description (e.g. a prov:DirectQueryService or a sd:Service). - dictionary: URIRef # dictionary - entity: URIRef # entity - generated: URIRef # generated - hadActivity: URIRef # The _optional_ Activity of an Influence, which used, generated, invalidated, or was the responsibility of some Entity. This property is _not_ used by ActivityInfluence (use prov:activity instead). - hadDictionaryMember: URIRef # hadDictionaryMember - hadGeneration: ( - URIRef # The _optional_ Generation involved in an Entity's Derivation. - ) - hadMember: URIRef # hadMember - hadPlan: URIRef # The _optional_ Plan adopted by an Agent in Association with some Activity. Plan specifications are out of the scope of this specification. - hadPrimarySource: URIRef # hadPrimarySource - hadRole: URIRef # This property has multiple RDFS domains to suit multiple OWL Profiles. See PROV-O OWL Profile. - hadUsage: URIRef # The _optional_ Usage involved in an Entity's Derivation. - has_anchor: ( - URIRef # Indicates anchor URI for a potentially dynamic resource instance. - ) - has_provenance: URIRef # Indicates a provenance-URI for a resource; the resource identified by this property presents a provenance record about its subject or anchor resource. - has_query_service: URIRef # Indicates a provenance query service that can access provenance related to its subject or anchor resource. - influenced: URIRef # influenced - influencer: URIRef # Subproperties of prov:influencer are used to cite the object of an unqualified PROV-O triple whose predicate is a subproperty of prov:wasInfluencedBy (e.g. prov:used, prov:wasGeneratedBy). prov:influencer is used much like rdf:object is used. - insertedKeyEntityPair: URIRef # insertedKeyEntityPair - invalidated: URIRef # invalidated - mentionOf: URIRef # prov:mentionOf is used to specialize an entity as described in another bundle. It is to be used in conjunction with prov:asInBundle. prov:asInBundle is used to cite the Bundle in which the generalization was mentioned. - pingback: URIRef # Relates a resource to a provenance pingback service that may receive additional provenance links about the resource. - qualifiedAssociation: URIRef # If this Activity prov:wasAssociatedWith Agent :ag, then it can qualify the Association using prov:qualifiedAssociation [ a prov:Association; prov:agent :ag; :foo :bar ]. - qualifiedAttribution: URIRef # If this Entity prov:wasAttributedTo Agent :ag, then it can qualify how it was influenced using prov:qualifiedAttribution [ a prov:Attribution; prov:agent :ag; :foo :bar ]. - qualifiedCommunication: URIRef # If this Activity prov:wasInformedBy Activity :a, then it can qualify how it was influenced using prov:qualifiedCommunication [ a prov:Communication; prov:activity :a; :foo :bar ]. - qualifiedDelegation: URIRef # If this Agent prov:actedOnBehalfOf Agent :ag, then it can qualify how with prov:qualifiedResponsibility [ a prov:Responsibility; prov:agent :ag; :foo :bar ]. - qualifiedDerivation: URIRef # If this Entity prov:wasDerivedFrom Entity :e, then it can qualify how it was derived using prov:qualifiedDerivation [ a prov:Derivation; prov:entity :e; :foo :bar ]. - qualifiedEnd: URIRef # If this Activity prov:wasEndedBy Entity :e1, then it can qualify how it was ended using prov:qualifiedEnd [ a prov:End; prov:entity :e1; :foo :bar ]. - qualifiedGeneration: URIRef # If this Activity prov:generated Entity :e, then it can qualify how it performed the Generation using prov:qualifiedGeneration [ a prov:Generation; prov:entity :e; :foo :bar ]. - qualifiedInfluence: URIRef # Because prov:qualifiedInfluence is a broad relation, the more specific relations (qualifiedCommunication, qualifiedDelegation, qualifiedEnd, etc.) should be used when applicable. - qualifiedInsertion: URIRef # qualifiedInsertion - qualifiedInvalidation: URIRef # If this Entity prov:wasInvalidatedBy Activity :a, then it can qualify how it was invalidated using prov:qualifiedInvalidation [ a prov:Invalidation; prov:activity :a; :foo :bar ]. - qualifiedPrimarySource: URIRef # If this Entity prov:hadPrimarySource Entity :e, then it can qualify how using prov:qualifiedPrimarySource [ a prov:PrimarySource; prov:entity :e; :foo :bar ]. - qualifiedQuotation: URIRef # If this Entity prov:wasQuotedFrom Entity :e, then it can qualify how using prov:qualifiedQuotation [ a prov:Quotation; prov:entity :e; :foo :bar ]. - qualifiedRemoval: URIRef # qualifiedRemoval - qualifiedRevision: URIRef # If this Entity prov:wasRevisionOf Entity :e, then it can qualify how it was revised using prov:qualifiedRevision [ a prov:Revision; prov:entity :e; :foo :bar ]. - qualifiedStart: URIRef # If this Activity prov:wasStartedBy Entity :e1, then it can qualify how it was started using prov:qualifiedStart [ a prov:Start; prov:entity :e1; :foo :bar ]. - qualifiedUsage: URIRef # If this Activity prov:used Entity :e, then it can qualify how it used it using prov:qualifiedUsage [ a prov:Usage; prov:entity :e; :foo :bar ]. - used: URIRef # A prov:Entity that was used by this prov:Activity. For example, :baking prov:used :spoon, :egg, :oven . - wasAssociatedWith: URIRef # An prov:Agent that had some (unspecified) responsibility for the occurrence of this prov:Activity. - wasAttributedTo: URIRef # Attribution is the ascribing of an entity to an agent. - wasDerivedFrom: URIRef # The more specific subproperties of prov:wasDerivedFrom (i.e., prov:wasQuotedFrom, prov:wasRevisionOf, prov:hadPrimarySource) should be used when applicable. - wasEndedBy: URIRef # End is when an activity is deemed to have ended. An end may refer to an entity, known as trigger, that terminated the activity. - wasGeneratedBy: URIRef # wasGeneratedBy - wasInfluencedBy: URIRef # This property has multiple RDFS domains to suit multiple OWL Profiles. See PROV-O OWL Profile. - wasInformedBy: URIRef # An activity a2 is dependent on or informed by another activity a1, by way of some unspecified entity that is generated by a1 and used by a2. - wasInvalidatedBy: URIRef # wasInvalidatedBy - wasQuotedFrom: URIRef # An entity is derived from an original entity by copying, or 'quoting', some or all of it. - wasStartedBy: URIRef # Start is when an activity is deemed to have started. A start may refer to an entity, known as trigger, that initiated the activity. - - _NS = Namespace("http://www.w3.org/ns/prov#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_QB.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_QB.py deleted file mode 100644 index 6494fd5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_QB.py +++ /dev/null @@ -1,63 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class QB(DefinedNamespace): - """ - Vocabulary for multi-dimensional (e.g. statistical) data publishing - - This vocabulary allows multi-dimensional data, such as statistics, to be published in RDF. It is based on the - core information model from SDMX (and thus also DDI). - - Generated from: http://purl.org/linked-data/cube# - Date: 2020-05-26 14:20:05.485176 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - attribute: URIRef # An alternative to qb:componentProperty which makes explicit that the component is a attribute - codeList: URIRef # gives the code list associated with a CodedProperty - component: URIRef # indicates a component specification which is included in the structure of the dataset - componentAttachment: URIRef # Indicates the level at which the component property should be attached, this might an qb:DataSet, qb:Slice or qb:Observation, or a qb:MeasureProperty. - componentProperty: URIRef # indicates a ComponentProperty (i.e. attribute/dimension) expected on a DataSet, or a dimension fixed in a SliceKey - componentRequired: URIRef # Indicates whether a component property is required (true) or optional (false) in the context of a DSD. Only applicable to components correspond to an attribute. Defaults to false (optional). - concept: URIRef # gives the concept which is being measured or indicated by a ComponentProperty - dataSet: URIRef # indicates the data set of which this observation is a part - dimension: URIRef # An alternative to qb:componentProperty which makes explicit that the component is a dimension - hierarchyRoot: URIRef # Specifies a root of the hierarchy. A hierarchy may have multiple roots but must have at least one. - measure: URIRef # An alternative to qb:componentProperty which makes explicit that the component is a measure - measureDimension: URIRef # An alternative to qb:componentProperty which makes explicit that the component is a measure dimension - measureType: URIRef # Generic measure dimension, the value of this dimension indicates which measure (from the set of measures in the DSD) is being given by the obsValue (or other primary measure) - observation: ( - URIRef # indicates a observation contained within this slice of the data set - ) - observationGroup: URIRef # Indicates a group of observations. The domain of this property is left open so that a group may be attached to different resources and need not be restricted to a single DataSet - order: URIRef # indicates a priority order for the components of sets with this structure, used to guide presentations - lower order numbers come before higher numbers, un-numbered components come last - parentChildProperty: URIRef # Specifies a property which relates a parent concept in the hierarchy to a child concept. - slice: URIRef # Indicates a subset of a DataSet defined by fixing a subset of the dimensional values - sliceKey: URIRef # indicates a slice key which is used for slices in this dataset - sliceStructure: URIRef # indicates the sub-key corresponding to this slice - structure: URIRef # indicates the structure to which this data set conforms - - # http://www.w3.org/2000/01/rdf-schema#Class - Attachable: URIRef # Abstract superclass for everything that can have attributes and dimensions - AttributeProperty: URIRef # The class of components which represent attributes of observations in the cube, e.g. unit of measurement - CodedProperty: URIRef # Superclass of all coded ComponentProperties - ComponentProperty: URIRef # Abstract super-property of all properties representing dimensions, attributes or measures - ComponentSet: URIRef # Abstract class of things which reference one or more ComponentProperties - ComponentSpecification: URIRef # Used to define properties of a component (attribute, dimension etc) which are specific to its usage in a DSD. - DataSet: URIRef # Represents a collection of observations, possibly organized into various slices, conforming to some common dimensional structure. - DataStructureDefinition: URIRef # Defines the structure of a DataSet or slice - DimensionProperty: ( - URIRef # The class of components which represent the dimensions of the cube - ) - HierarchicalCodeList: URIRef # Represents a generalized hierarchy of concepts which can be used for coding. The hierarchy is defined by one or more roots together with a property which relates concepts in the hierarchy to their child concept . The same concepts may be members of multiple hierarchies provided that different qb:parentChildProperty values are used for each hierarchy. - MeasureProperty: URIRef # The class of components which represent the measured value of the phenomenon being observed - Observation: URIRef # A single observation in the cube, may have one or more associated measured values - ObservationGroup: URIRef # A, possibly arbitrary, group of observations. - Slice: URIRef # Denotes a subset of a DataSet defined by fixing a subset of the dimensional values, component properties on the Slice - SliceKey: URIRef # Denotes a subset of the component properties of a DataSet which are fixed in the corresponding slices - - _NS = Namespace("http://purl.org/linked-data/cube#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDF.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDF.py deleted file mode 100644 index ef1fde5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDF.py +++ /dev/null @@ -1,51 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class RDF(DefinedNamespace): - """ - The RDF Concepts Vocabulary (RDF) - - This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts. - - Generated from: http://www.w3.org/1999/02/22-rdf-syntax-ns# - Date: 2020-05-26 14:20:05.642859 - - dc:date "2019-12-16" - - """ - - _fail = True - _underscore_num = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#List - nil: URIRef # The empty list, with no items in it. If the rest of a list is nil then the list has no more items in it. - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - direction: URIRef # The base direction component of a CompoundLiteral. - first: URIRef # The first item in the subject RDF list. - language: URIRef # The language component of a CompoundLiteral. - object: URIRef # The object of the subject RDF statement. - predicate: URIRef # The predicate of the subject RDF statement. - rest: URIRef # The rest of the subject RDF list after the first item. - subject: URIRef # The subject of the subject RDF statement. - type: URIRef # The subject is an instance of a class. - value: URIRef # Idiomatic property used for structured values. - - # http://www.w3.org/2000/01/rdf-schema#Class - Alt: URIRef # The class of containers of alternatives. - Bag: URIRef # The class of unordered containers. - CompoundLiteral: URIRef # A class representing a compound literal. - List: URIRef # The class of RDF Lists. - Property: URIRef # The class of RDF properties. - Seq: URIRef # The class of ordered containers. - Statement: URIRef # The class of RDF statements. - - # http://www.w3.org/2000/01/rdf-schema#Datatype - HTML: URIRef # The datatype of RDF literals storing fragments of HTML content - JSON: URIRef # The datatype of RDF literals storing JSON content. - PlainLiteral: URIRef # The class of plain (i.e. untyped) literal values, as used in RIF and OWL 2 - XMLLiteral: URIRef # The datatype of XML literal values. - langString: URIRef # The datatype of language-tagged string values - - _NS = Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDFS.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDFS.py deleted file mode 100644 index 273b114..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_RDFS.py +++ /dev/null @@ -1,35 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class RDFS(DefinedNamespace): - """ - The RDF Schema vocabulary (RDFS) - - Generated from: http://www.w3.org/2000/01/rdf-schema# - Date: 2020-05-26 14:20:05.794866 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - comment: URIRef # A description of the subject resource. - domain: URIRef # A domain of the subject property. - isDefinedBy: URIRef # The definition of the subject resource. - label: URIRef # A human-readable name for the subject. - member: URIRef # A member of the subject resource. - range: URIRef # A range of the subject property. - seeAlso: URIRef # Further information about the subject resource. - subClassOf: URIRef # The subject is a subclass of a class. - subPropertyOf: URIRef # The subject is a subproperty of a property. - - # http://www.w3.org/2000/01/rdf-schema#Class - Class: URIRef # The class of classes. - Container: URIRef # The class of RDF containers. - ContainerMembershipProperty: URIRef # The class of container membership properties, rdf:_1, rdf:_2, ..., all of which are sub-properties of 'member'. - Datatype: URIRef # The class of RDF datatypes. - Literal: URIRef # The class of literal values, eg. textual strings and integers. - Resource: URIRef # The class resource, everything. - - _NS = Namespace("http://www.w3.org/2000/01/rdf-schema#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SDO.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SDO.py deleted file mode 100644 index 634fe43..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SDO.py +++ /dev/null @@ -1,3278 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class SDO(DefinedNamespace): - """ - schema.org namespace elements - - 3DModel, True, False & yield are not available as they collde with Python terms - - Generated from: https://schema.org/version/latest/schemaorg-current-https.jsonld - Date: 2021-12-01 - By: Nicholas J. Car - """ - - _NS = Namespace("https://schema.org/") - - # 3DModel: URIRef # A 3D model represents some kind of 3D content, which may have [[encoding]]s in one or more [[MediaObject]]s. Many 3D formats are available (e.g. see [Wikipedia](https://en.wikipedia.org/wiki/Category:3D_graphics_file_formats)); specific encoding formats can be represented using the [[encodingFormat]] property applied to the relevant [[MediaObject]]. For the case of a single file published after Zip compression, the convention of appending '+zip' to the [[encodingFormat]] can be used. Geospatial, AR/VR, artistic/animation, gaming, engineering and scientific content can all be represented using [[3DModel]]. - AMRadioChannel: URIRef # A radio channel that uses AM. - APIReference: ( - URIRef # Reference documentation for application programming interfaces (APIs). - ) - Abdomen: URIRef # Abdomen clinical examination. - AboutPage: URIRef # Web page type: About page. - AcceptAction: URIRef # The act of committing to/adopting an object.\n\nRelated actions:\n\n* [[RejectAction]]: The antonym of AcceptAction. - Accommodation: URIRef # An accommodation is a place that can accommodate human beings, e.g. a hotel room, a camping pitch, or a meeting room. Many accommodations are for overnight stays, but this is not a mandatory requirement. For more specific types of accommodations not defined in schema.org, one can use additionalType with external vocabularies.

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - AccountingService: URIRef # Accountancy business.\n\nAs a [[LocalBusiness]] it can be described as a [[provider]] of one or more [[Service]]\(s). - AchieveAction: URIRef # The act of accomplishing something via previous efforts. It is an instantaneous action rather than an ongoing process. - Action: URIRef # An action performed by a direct agent and indirect participants upon a direct object. Optionally happens at a location with the help of an inanimate instrument. The execution of the action may produce a result. Specific action sub-type documentation specifies the exact expectation of each argument/role.\n\nSee also [blog post](http://blog.schema.org/2014/04/announcing-schemaorg-actions.html) and [Actions overview document](https://schema.org/docs/actions.html). - ActionAccessSpecification: URIRef # A set of requirements that a must be fulfilled in order to perform an Action. - ActionStatusType: URIRef # The status of an Action. - ActivateAction: URIRef # The act of starting or activating a device or application (e.g. starting a timer or turning on a flashlight). - ActivationFee: URIRef # Represents the activation fee part of the total price for an offered product, for example a cellphone contract. - ActiveActionStatus: URIRef # An in-progress action (e.g, while watching the movie, or driving to a location). - ActiveNotRecruiting: URIRef # Active, but not recruiting new participants. - AddAction: URIRef # The act of editing by adding an object to a collection. - AdministrativeArea: URIRef # A geographical region, typically under the jurisdiction of a particular government. - AdultEntertainment: URIRef # An adult entertainment establishment. - AdvertiserContentArticle: URIRef # An [[Article]] that an external entity has paid to place or to produce to its specifications. Includes [advertorials](https://en.wikipedia.org/wiki/Advertorial), sponsored content, native advertising and other paid content. - AerobicActivity: URIRef # Physical activity of relatively low intensity that depends primarily on the aerobic energy-generating process; during activity, the aerobic metabolism uses oxygen to adequately meet energy demands during exercise. - AggregateOffer: URIRef # When a single product is associated with multiple offers (for example, the same pair of shoes is offered by different merchants), then AggregateOffer can be used.\n\nNote: AggregateOffers are normally expected to associate multiple offers that all share the same defined [[businessFunction]] value, or default to http://purl.org/goodrelations/v1#Sell if businessFunction is not explicitly defined. - AggregateRating: URIRef # The average rating based on multiple ratings or reviews. - AgreeAction: URIRef # The act of expressing a consistency of opinion with the object. An agent agrees to/about an object (a proposition, topic or theme) with participants. - Airline: URIRef # An organization that provides flights for passengers. - Airport: URIRef # An airport. - AlbumRelease: URIRef # AlbumRelease. - AlignmentObject: URIRef # An intangible item that describes an alignment between a learning resource and a node in an educational framework. Should not be used where the nature of the alignment can be described using a simple property, for example to express that a resource [[teaches]] or [[assesses]] a competency. - AllWheelDriveConfiguration: URIRef # All-wheel Drive is a transmission layout where the engine drives all four wheels. - AllergiesHealthAspect: ( - URIRef # Content about the allergy-related aspects of a health topic. - ) - AllocateAction: URIRef # The act of organizing tasks/objects/events by associating resources to it. - AmpStory: URIRef # A creative work with a visual storytelling format intended to be viewed online, particularly on mobile devices. - AmusementPark: URIRef # An amusement park. - AnaerobicActivity: URIRef # Physical activity that is of high-intensity which utilizes the anaerobic metabolism of the body. - AnalysisNewsArticle: URIRef # An AnalysisNewsArticle is a [[NewsArticle]] that, while based on factual reporting, incorporates the expertise of the author/producer, offering interpretations and conclusions. - AnatomicalStructure: URIRef # Any part of the human body, typically a component of an anatomical system. Organs, tissues, and cells are all anatomical structures. - AnatomicalSystem: URIRef # An anatomical system is a group of anatomical structures that work together to perform a certain task. Anatomical systems, such as organ systems, are one organizing principle of anatomy, and can includes circulatory, digestive, endocrine, integumentary, immune, lymphatic, muscular, nervous, reproductive, respiratory, skeletal, urinary, vestibular, and other systems. - Anesthesia: URIRef # A specific branch of medical science that pertains to study of anesthetics and their application. - AnimalShelter: URIRef # Animal shelter. - Answer: URIRef # An answer offered to a question; perhaps correct, perhaps opinionated or wrong. - Apartment: URIRef # An apartment (in American English) or flat (in British English) is a self-contained housing unit (a type of residential real estate) that occupies only part of a building (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Apartment). - ApartmentComplex: URIRef # Residence type: Apartment complex. - Appearance: URIRef # Appearance assessment with clinical examination. - AppendAction: URIRef # The act of inserting at the end if an ordered collection. - ApplyAction: URIRef # The act of registering to an organization/service without the guarantee to receive it.\n\nRelated actions:\n\n* [[RegisterAction]]: Unlike RegisterAction, ApplyAction has no guarantees that the application will be accepted. - ApprovedIndication: URIRef # An indication for a medical therapy that has been formally specified or approved by a regulatory body that regulates use of the therapy; for example, the US FDA approves indications for most drugs in the US. - Aquarium: URIRef # Aquarium. - ArchiveComponent: URIRef # An intangible type to be applied to any archive content, carrying with it a set of properties required to describe archival items and collections. - ArchiveOrganization: URIRef # An organization with archival holdings. An organization which keeps and preserves archival material and typically makes it accessible to the public. - ArriveAction: URIRef # The act of arriving at a place. An agent arrives at a destination from a fromLocation, optionally with participants. - ArtGallery: URIRef # An art gallery. - Artery: URIRef # A type of blood vessel that specifically carries blood away from the heart. - Article: URIRef # An article, such as a news article or piece of investigative report. Newspapers and magazines have articles of many different types and this is intended to cover them all.\n\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html). - AskAction: URIRef # The act of posing a question / favor to someone.\n\nRelated actions:\n\n* [[ReplyAction]]: Appears generally as a response to AskAction. - AskPublicNewsArticle: URIRef # A [[NewsArticle]] expressing an open call by a [[NewsMediaOrganization]] asking the public for input, insights, clarifications, anecdotes, documentation, etc., on an issue, for reporting purposes. - AssessAction: URIRef # The act of forming one's opinion, reaction or sentiment. - AssignAction: URIRef # The act of allocating an action/event/task to some destination (someone or something). - Atlas: URIRef # A collection or bound volume of maps, charts, plates or tables, physical or in media form illustrating any subject. - Attorney: URIRef # Professional service: Attorney. \n\nThis type is deprecated - [[LegalService]] is more inclusive and less ambiguous. - Audience: URIRef # Intended audience for an item, i.e. the group for whom the item was created. - AudioObject: URIRef # An audio file. - AudioObjectSnapshot: URIRef # A specific and exact (byte-for-byte) version of an [[AudioObject]]. Two byte-for-byte identical files, for the purposes of this type, considered identical. If they have different embedded metadata the files will differ. Different external facts about the files, e.g. creator or dateCreated that aren't represented in their actual content, do not affect this notion of identity. - Audiobook: URIRef # An audiobook. - AudiobookFormat: URIRef # Book format: Audiobook. This is an enumerated value for use with the bookFormat property. There is also a type 'Audiobook' in the bib extension which includes Audiobook specific properties. - AuthoritativeLegalValue: URIRef # Indicates that the publisher gives some special status to the publication of the document. ("The Queens Printer" version of a UK Act of Parliament, or the PDF version of a Directive published by the EU Office of Publications). Something "Authoritative" is considered to be also [[OfficialLegalValue]]". - AuthorizeAction: URIRef # The act of granting permission to an object. - AutoBodyShop: URIRef # Auto body shop. - AutoDealer: URIRef # An car dealership. - AutoPartsStore: URIRef # An auto parts store. - AutoRental: URIRef # A car rental business. - AutoRepair: URIRef # Car repair business. - AutoWash: URIRef # A car wash business. - AutomatedTeller: URIRef # ATM/cash machine. - AutomotiveBusiness: URIRef # Car repair, sales, or parts. - Ayurvedic: URIRef # A system of medicine that originated in India over thousands of years and that focuses on integrating and balancing the body, mind, and spirit. - BackOrder: URIRef # Indicates that the item is available on back order. - BackgroundNewsArticle: URIRef # A [[NewsArticle]] providing historical context, definition and detail on a specific topic (aka "explainer" or "backgrounder"). For example, an in-depth article or frequently-asked-questions ([FAQ](https://en.wikipedia.org/wiki/FAQ)) document on topics such as Climate Change or the European Union. Other kinds of background material from a non-news setting are often described using [[Book]] or [[Article]], in particular [[ScholarlyArticle]]. See also [[NewsArticle]] for related vocabulary from a learning/education perspective. - Bacteria: URIRef # Pathogenic bacteria that cause bacterial infection. - Bakery: URIRef # A bakery. - Balance: URIRef # Physical activity that is engaged to help maintain posture and balance. - BankAccount: URIRef # A product or service offered by a bank whereby one may deposit, withdraw or transfer money and in some cases be paid interest. - BankOrCreditUnion: URIRef # Bank or credit union. - BarOrPub: URIRef # A bar or pub. - Barcode: URIRef # An image of a visual machine-readable code such as a barcode or QR code. - BasicIncome: URIRef # BasicIncome: this is a benefit for basic income. - Beach: URIRef # Beach. - BeautySalon: URIRef # Beauty salon. - BedAndBreakfast: URIRef # Bed and breakfast.

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - BedDetails: URIRef # An entity holding detailed information about the available bed types, e.g. the quantity of twin beds for a hotel room. For the single case of just one bed of a certain type, you can use bed directly with a text. See also [[BedType]] (under development). - BedType: URIRef # A type of bed. This is used for indicating the bed or beds available in an accommodation. - BefriendAction: URIRef # The act of forming a personal connection with someone (object) mutually/bidirectionally/symmetrically.\n\nRelated actions:\n\n* [[FollowAction]]: Unlike FollowAction, BefriendAction implies that the connection is reciprocal. - BenefitsHealthAspect: URIRef # Content about the benefits and advantages of usage or utilization of topic. - BikeStore: URIRef # A bike store. - BioChemEntity: URIRef # Any biological, chemical, or biochemical thing. For example: a protein; a gene; a chemical; a synthetic chemical. - Blog: URIRef # A [blog](https://en.wikipedia.org/wiki/Blog), sometimes known as a "weblog". Note that the individual posts ([[BlogPosting]]s) in a [[Blog]] are often colloqually referred to by the same term. - BlogPosting: URIRef # A blog post. - BloodTest: URIRef # A medical test performed on a sample of a patient's blood. - BoardingPolicyType: URIRef # A type of boarding policy used by an airline. - BoatReservation: URIRef # A reservation for boat travel. Note: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - BoatTerminal: URIRef # A terminal for boats, ships, and other water vessels. - BoatTrip: URIRef # A trip on a commercial ferry line. - BodyMeasurementArm: URIRef # Arm length (measured between arms/shoulder line intersection and the prominent wrist bone). Used, for example, to fit shirts. - BodyMeasurementBust: ( - URIRef # Maximum girth of bust. Used, for example, to fit women's suits. - ) - BodyMeasurementChest: ( - URIRef # Maximum girth of chest. Used, for example, to fit men's suits. - ) - BodyMeasurementFoot: URIRef # Foot length (measured between end of the most prominent toe and the most prominent part of the heel). Used, for example, to measure socks. - BodyMeasurementHand: URIRef # Maximum hand girth (measured over the knuckles of the open right hand excluding thumb, fingers together). Used, for example, to fit gloves. - BodyMeasurementHead: ( - URIRef # Maximum girth of head above the ears. Used, for example, to fit hats. - ) - BodyMeasurementHeight: URIRef # Body height (measured between crown of head and soles of feet). Used, for example, to fit jackets. - BodyMeasurementHips: URIRef # Girth of hips (measured around the buttocks). Used, for example, to fit skirts. - BodyMeasurementInsideLeg: URIRef # Inside leg (measured between crotch and soles of feet). Used, for example, to fit pants. - BodyMeasurementNeck: URIRef # Girth of neck. Used, for example, to fit shirts. - BodyMeasurementTypeEnumeration: URIRef # Enumerates types (or dimensions) of a person's body measurements, for example for fitting of clothes. - BodyMeasurementUnderbust: URIRef # Girth of body just below the bust. Used, for example, to fit women's swimwear. - BodyMeasurementWaist: URIRef # Girth of natural waistline (between hip bones and lower ribs). Used, for example, to fit pants. - BodyMeasurementWeight: ( - URIRef # Body weight. Used, for example, to measure pantyhose. - ) - BodyOfWater: URIRef # A body of water, such as a sea, ocean, or lake. - Bone: URIRef # Rigid connective tissue that comprises up the skeletal structure of the human body. - Book: URIRef # A book. - BookFormatType: URIRef # The publication format of the book. - BookSeries: URIRef # A series of books. Included books can be indicated with the hasPart property. - BookStore: URIRef # A bookstore. - BookmarkAction: URIRef # An agent bookmarks/flags/labels/tags/marks an object. - Boolean: URIRef # Boolean: True or False. - BorrowAction: URIRef # The act of obtaining an object under an agreement to return it at a later date. Reciprocal of LendAction.\n\nRelated actions:\n\n* [[LendAction]]: Reciprocal of BorrowAction. - BowlingAlley: URIRef # A bowling alley. - BrainStructure: URIRef # Any anatomical structure which pertains to the soft nervous tissue functioning as the coordinating center of sensation and intellectual and nervous activity. - Brand: URIRef # A brand is a name used by an organization or business person for labeling a product, product group, or similar. - BreadcrumbList: URIRef # A BreadcrumbList is an ItemList consisting of a chain of linked Web pages, typically described using at least their URL and their name, and typically ending with the current page.\n\nThe [[position]] property is used to reconstruct the order of the items in a BreadcrumbList The convention is that a breadcrumb list has an [[itemListOrder]] of [[ItemListOrderAscending]] (lower values listed first), and that the first items in this list correspond to the "top" or beginning of the breadcrumb trail, e.g. with a site or section homepage. The specific values of 'position' are not assigned meaning for a BreadcrumbList, but they should be integers, e.g. beginning with '1' for the first item in the list. - Brewery: URIRef # Brewery. - Bridge: URIRef # A bridge. - BroadcastChannel: URIRef # A unique instance of a BroadcastService on a CableOrSatelliteService lineup. - BroadcastEvent: URIRef # An over the air or online broadcast event. - BroadcastFrequencySpecification: URIRef # The frequency in MHz and the modulation used for a particular BroadcastService. - BroadcastRelease: URIRef # BroadcastRelease. - BroadcastService: URIRef # A delivery service through which content is provided via broadcast over the air or online. - BrokerageAccount: URIRef # An account that allows an investor to deposit funds and place investment orders with a licensed broker or brokerage firm. - BuddhistTemple: URIRef # A Buddhist temple. - BusOrCoach: URIRef # A bus (also omnibus or autobus) is a road vehicle designed to carry passengers. Coaches are luxury busses, usually in service for long distance travel. - BusReservation: URIRef # A reservation for bus travel. \n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - BusStation: URIRef # A bus station. - BusStop: URIRef # A bus stop. - BusTrip: URIRef # A trip on a commercial bus line. - BusinessAudience: URIRef # A set of characteristics belonging to businesses, e.g. who compose an item's target audience. - BusinessEntityType: URIRef # A business entity type is a conceptual entity representing the legal form, the size, the main line of business, the position in the value chain, or any combination thereof, of an organization or business person.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#Business\n* http://purl.org/goodrelations/v1#Enduser\n* http://purl.org/goodrelations/v1#PublicInstitution\n* http://purl.org/goodrelations/v1#Reseller - BusinessEvent: URIRef # Event type: Business event. - BusinessFunction: URIRef # The business function specifies the type of activity or access (i.e., the bundle of rights) offered by the organization or business person through the offer. Typical are sell, rental or lease, maintenance or repair, manufacture / produce, recycle / dispose, engineering / construction, or installation. Proprietary specifications of access rights are also instances of this class.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#ConstructionInstallation\n* http://purl.org/goodrelations/v1#Dispose\n* http://purl.org/goodrelations/v1#LeaseOut\n* http://purl.org/goodrelations/v1#Maintain\n* http://purl.org/goodrelations/v1#ProvideService\n* http://purl.org/goodrelations/v1#Repair\n* http://purl.org/goodrelations/v1#Sell\n* http://purl.org/goodrelations/v1#Buy - BusinessSupport: ( - URIRef # BusinessSupport: this is a benefit for supporting businesses. - ) - BuyAction: URIRef # The act of giving money to a seller in exchange for goods or services rendered. An agent buys an object, product, or service from a seller for a price. Reciprocal of SellAction. - CDCPMDRecord: URIRef # A CDCPMDRecord is a data structure representing a record in a CDC tabular data format used for hospital data reporting. See [documentation](/docs/cdc-covid.html) for details, and the linked CDC materials for authoritative definitions used as the source here. - CDFormat: URIRef # CDFormat. - CT: URIRef # X-ray computed tomography imaging. - CableOrSatelliteService: URIRef # A service which provides access to media programming like TV or radio. Access may be via cable or satellite. - CafeOrCoffeeShop: URIRef # A cafe or coffee shop. - Campground: URIRef # A camping site, campsite, or [[Campground]] is a place used for overnight stay in the outdoors, typically containing individual [[CampingPitch]] locations. \n\n In British English a campsite is an area, usually divided into a number of pitches, where people can camp overnight using tents or camper vans or caravans; this British English use of the word is synonymous with the American English expression campground. In American English the term campsite generally means an area where an individual, family, group, or military unit can pitch a tent or park a camper; a campground may contain many campsites (Source: Wikipedia see [https://en.wikipedia.org/wiki/Campsite](https://en.wikipedia.org/wiki/Campsite)).\n\n See also the dedicated [document on the use of schema.org for marking up hotels and other forms of accommodations](/docs/hotels.html). - CampingPitch: URIRef # A [[CampingPitch]] is an individual place for overnight stay in the outdoors, typically being part of a larger camping site, or [[Campground]].\n\n In British English a campsite, or campground, is an area, usually divided into a number of pitches, where people can camp overnight using tents or camper vans or caravans; this British English use of the word is synonymous with the American English expression campground. In American English the term campsite generally means an area where an individual, family, group, or military unit can pitch a tent or park a camper; a campground may contain many campsites. (Source: Wikipedia see [https://en.wikipedia.org/wiki/Campsite](https://en.wikipedia.org/wiki/Campsite)).\n\n See also the dedicated [document on the use of schema.org for marking up hotels and other forms of accommodations](/docs/hotels.html). - Canal: URIRef # A canal, like the Panama Canal. - CancelAction: URIRef # The act of asserting that a future event/action is no longer going to happen.\n\nRelated actions:\n\n* [[ConfirmAction]]: The antonym of CancelAction. - Car: URIRef # A car is a wheeled, self-powered motor vehicle used for transportation. - CarUsageType: URIRef # A value indicating a special usage of a car, e.g. commercial rental, driving school, or as a taxi. - Cardiovascular: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of heart and vasculature. - CardiovascularExam: ( - URIRef # Cardiovascular system assessment withclinical examination. - ) - CaseSeries: URIRef # A case series (also known as a clinical series) is a medical research study that tracks patients with a known exposure given similar treatment or examines their medical records for exposure and outcome. A case series can be retrospective or prospective and usually involves a smaller number of patients than the more powerful case-control studies or randomized controlled trials. Case series may be consecutive or non-consecutive, depending on whether all cases presenting to the reporting authors over a period of time were included, or only a selection. - Casino: URIRef # A casino. - CassetteFormat: URIRef # CassetteFormat. - CategoryCode: URIRef # A Category Code. - CategoryCodeSet: URIRef # A set of Category Code values. - CatholicChurch: URIRef # A Catholic church. - CausesHealthAspect: URIRef # Information about the causes and main actions that gave rise to the topic. - Cemetery: URIRef # A graveyard. - Chapter: URIRef # One of the sections into which a book is divided. A chapter usually has a section number or a name. - CharitableIncorporatedOrganization: URIRef # CharitableIncorporatedOrganization: Non-profit type referring to a Charitable Incorporated Organization (UK). - CheckAction: URIRef # An agent inspects, determines, investigates, inquires, or examines an object's accuracy, quality, condition, or state. - CheckInAction: URIRef # The act of an agent communicating (service provider, social media, etc) their arrival by registering/confirming for a previously reserved service (e.g. flight check in) or at a place (e.g. hotel), possibly resulting in a result (boarding pass, etc).\n\nRelated actions:\n\n* [[CheckOutAction]]: The antonym of CheckInAction.\n* [[ArriveAction]]: Unlike ArriveAction, CheckInAction implies that the agent is informing/confirming the start of a previously reserved service.\n* [[ConfirmAction]]: Unlike ConfirmAction, CheckInAction implies that the agent is informing/confirming the *start* of a previously reserved service rather than its validity/existence. - CheckOutAction: URIRef # The act of an agent communicating (service provider, social media, etc) their departure of a previously reserved service (e.g. flight check in) or place (e.g. hotel).\n\nRelated actions:\n\n* [[CheckInAction]]: The antonym of CheckOutAction.\n* [[DepartAction]]: Unlike DepartAction, CheckOutAction implies that the agent is informing/confirming the end of a previously reserved service.\n* [[CancelAction]]: Unlike CancelAction, CheckOutAction implies that the agent is informing/confirming the end of a previously reserved service. - CheckoutPage: URIRef # Web page type: Checkout page. - ChemicalSubstance: URIRef # A chemical substance is 'a portion of matter of constant composition, composed of molecular entities of the same type or of different types' (source: [ChEBI:59999](https://www.ebi.ac.uk/chebi/searchId.do?chebiId=59999)). - ChildCare: URIRef # A Childcare center. - ChildrensEvent: URIRef # Event type: Children's event. - Chiropractic: URIRef # A system of medicine focused on the relationship between the body's structure, mainly the spine, and its functioning. - ChooseAction: URIRef # The act of expressing a preference from a set of options or a large or unbounded set of choices/options. - Church: URIRef # A church. - City: URIRef # A city or town. - CityHall: URIRef # A city hall. - CivicStructure: URIRef # A public structure, such as a town hall or concert hall. - Claim: URIRef # A [[Claim]] in Schema.org represents a specific, factually-oriented claim that could be the [[itemReviewed]] in a [[ClaimReview]]. The content of a claim can be summarized with the [[text]] property. Variations on well known claims can have their common identity indicated via [[sameAs]] links, and summarized with a [[name]]. Ideally, a [[Claim]] description includes enough contextual information to minimize the risk of ambiguity or inclarity. In practice, many claims are better understood in the context in which they appear or the interpretations provided by claim reviews. Beyond [[ClaimReview]], the Claim type can be associated with related creative works - for example a [[ScholarlyArticle]] or [[Question]] might be [[about]] some [[Claim]]. At this time, Schema.org does not define any types of relationship between claims. This is a natural area for future exploration. - ClaimReview: URIRef # A fact-checking review of claims made (or reported) in some creative work (referenced via itemReviewed). - Class: URIRef # A class, also often called a 'Type'; equivalent to rdfs:Class. - CleaningFee: URIRef # Represents the cleaning fee part of the total price for an offered product, for example a vacation rental. - Clinician: URIRef # Medical clinicians, including practicing physicians and other medical professionals involved in clinical practice. - Clip: URIRef # A short TV or radio program or a segment/part of a program. - ClothingStore: URIRef # A clothing store. - CoOp: URIRef # Play mode: CoOp. Co-operative games, where you play on the same team with friends. - Code: URIRef # Computer programming source code. Example: Full (compile ready) solutions, code snippet samples, scripts, templates. - CohortStudy: URIRef # Also known as a panel study. A cohort study is a form of longitudinal study used in medicine and social science. It is one type of study design and should be compared with a cross-sectional study. A cohort is a group of people who share a common characteristic or experience within a defined period (e.g., are born, leave school, lose their job, are exposed to a drug or a vaccine, etc.). The comparison group may be the general population from which the cohort is drawn, or it may be another cohort of persons thought to have had little or no exposure to the substance under investigation, but otherwise similar. Alternatively, subgroups within the cohort may be compared with each other. - Collection: URIRef # A collection of items e.g. creative works or products. - CollectionPage: URIRef # Web page type: Collection page. - CollegeOrUniversity: ( - URIRef # A college, university, or other third-level educational institution. - ) - ComedyClub: URIRef # A comedy club. - ComedyEvent: URIRef # Event type: Comedy event. - ComicCoverArt: URIRef # The artwork on the cover of a comic. - ComicIssue: URIRef # Individual comic issues are serially published as part of a larger series. For the sake of consistency, even one-shot issues belong to a series comprised of a single issue. All comic issues can be uniquely identified by: the combination of the name and volume number of the series to which the issue belongs; the issue number; and the variant description of the issue (if any). - ComicSeries: URIRef # A sequential publication of comic stories under a unifying title, for example "The Amazing Spider-Man" or "Groo the Wanderer". - ComicStory: URIRef # The term "story" is any indivisible, re-printable unit of a comic, including the interior stories, covers, and backmatter. Most comics have at least two stories: a cover (ComicCoverArt) and an interior story. - Comment: URIRef # A comment on an item - for example, a comment on a blog post. The comment's content is expressed via the [[text]] property, and its topic via [[about]], properties shared with all CreativeWorks. - CommentAction: URIRef # The act of generating a comment about a subject. - CommentPermission: URIRef # Permission to add comments to the document. - CommunicateAction: URIRef # The act of conveying information to another person via a communication medium (instrument) such as speech, email, or telephone conversation. - CommunityHealth: URIRef # A field of public health focusing on improving health characteristics of a defined population in relation with their geographical or environment areas. - CompilationAlbum: URIRef # CompilationAlbum. - CompleteDataFeed: URIRef # A [[CompleteDataFeed]] is a [[DataFeed]] whose standard representation includes content for every item currently in the feed. This is the equivalent of Atom's element as defined in Feed Paging and Archiving [RFC 5005](https://tools.ietf.org/html/rfc5005), For example (and as defined for Atom), when using data from a feed that represents a collection of items that varies over time (e.g. "Top Twenty Records") there is no need to have newer entries mixed in alongside older, obsolete entries. By marking this feed as a CompleteDataFeed, old entries can be safely discarded when the feed is refreshed, since we can assume the feed has provided descriptions for all current items. - Completed: URIRef # Completed. - CompletedActionStatus: URIRef # An action that has already taken place. - CompoundPriceSpecification: URIRef # A compound price specification is one that bundles multiple prices that all apply in combination for different dimensions of consumption. Use the name property of the attached unit price specification for indicating the dimension of a price component (e.g. "electricity" or "final cleaning"). - ComputerLanguage: URIRef # This type covers computer programming languages such as Scheme and Lisp, as well as other language-like computer representations. Natural languages are best represented with the [[Language]] type. - ComputerStore: URIRef # A computer store. - ConfirmAction: URIRef # The act of notifying someone that a future event/action is going to happen as expected.\n\nRelated actions:\n\n* [[CancelAction]]: The antonym of ConfirmAction. - Consortium: URIRef # A Consortium is a membership [[Organization]] whose members are typically Organizations. - ConsumeAction: URIRef # The act of ingesting information/resources/food. - ContactPage: URIRef # Web page type: Contact page. - ContactPoint: ( - URIRef # A contact point—for example, a Customer Complaints department. - ) - ContactPointOption: URIRef # Enumerated options related to a ContactPoint. - ContagiousnessHealthAspect: URIRef # Content about contagion mechanisms and contagiousness information over the topic. - Continent: URIRef # One of the continents (for example, Europe or Africa). - ControlAction: URIRef # An agent controls a device or application. - ConvenienceStore: URIRef # A convenience store. - Conversation: URIRef # One or more messages between organizations or people on a particular topic. Individual messages can be linked to the conversation with isPartOf or hasPart properties. - CookAction: URIRef # The act of producing/preparing food. - Corporation: URIRef # Organization: A business corporation. - CorrectionComment: URIRef # A [[comment]] that corrects [[CreativeWork]]. - Country: URIRef # A country. - Course: URIRef # A description of an educational course which may be offered as distinct instances at which take place at different times or take place at different locations, or be offered through different media or modes of study. An educational course is a sequence of one or more educational events and/or creative works which aims to build knowledge, competence or ability of learners. - CourseInstance: URIRef # An instance of a [[Course]] which is distinct from other instances because it is offered at a different time or location or through different media or modes of study or to a specific section of students. - Courthouse: URIRef # A courthouse. - CoverArt: URIRef # The artwork on the outer surface of a CreativeWork. - CovidTestingFacility: URIRef # A CovidTestingFacility is a [[MedicalClinic]] where testing for the COVID-19 Coronavirus disease is available. If the facility is being made available from an established [[Pharmacy]], [[Hotel]], or other non-medical organization, multiple types can be listed. This makes it easier to re-use existing schema.org information about that place e.g. contact info, address, opening hours. Note that in an emergency, such information may not always be reliable. - CreateAction: URIRef # The act of deliberately creating/producing/generating/building a result out of the agent. - CreativeWork: URIRef # The most generic kind of creative work, including books, movies, photographs, software programs, etc. - CreativeWorkSeason: URIRef # A media season e.g. tv, radio, video game etc. - CreativeWorkSeries: URIRef # A CreativeWorkSeries in schema.org is a group of related items, typically but not necessarily of the same kind. CreativeWorkSeries are usually organized into some order, often chronological. Unlike [[ItemList]] which is a general purpose data structure for lists of things, the emphasis with CreativeWorkSeries is on published materials (written e.g. books and periodicals, or media such as tv, radio and games).\n\nSpecific subtypes are available for describing [[TVSeries]], [[RadioSeries]], [[MovieSeries]], [[BookSeries]], [[Periodical]] and [[VideoGameSeries]]. In each case, the [[hasPart]] / [[isPartOf]] properties can be used to relate the CreativeWorkSeries to its parts. The general CreativeWorkSeries type serves largely just to organize these more specific and practical subtypes.\n\nIt is common for properties applicable to an item from the series to be usefully applied to the containing group. Schema.org attempts to anticipate some of these cases, but publishers should be free to apply properties of the series parts to the series as a whole wherever they seem appropriate. - CreditCard: URIRef # A card payment method of a particular brand or name. Used to mark up a particular payment method and/or the financial product/service that supplies the card account.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#AmericanExpress\n* http://purl.org/goodrelations/v1#DinersClub\n* http://purl.org/goodrelations/v1#Discover\n* http://purl.org/goodrelations/v1#JCB\n* http://purl.org/goodrelations/v1#MasterCard\n* http://purl.org/goodrelations/v1#VISA - Crematorium: URIRef # A crematorium. - CriticReview: URIRef # A [[CriticReview]] is a more specialized form of Review written or published by a source that is recognized for its reviewing activities. These can include online columns, travel and food guides, TV and radio shows, blogs and other independent Web sites. [[CriticReview]]s are typically more in-depth and professionally written. For simpler, casually written user/visitor/viewer/customer reviews, it is more appropriate to use the [[UserReview]] type. Review aggregator sites such as Metacritic already separate out the site's user reviews from selected critic reviews that originate from third-party sources. - CrossSectional: URIRef # Studies carried out on pre-existing data (usually from 'snapshot' surveys), such as that collected by the Census Bureau. Sometimes called Prevalence Studies. - CssSelectorType: URIRef # Text representing a CSS selector. - CurrencyConversionService: ( - URIRef # A service to convert funds from one currency to another currency. - ) - DDxElement: URIRef # An alternative, closely-related condition typically considered later in the differential diagnosis process along with the signs that are used to distinguish it. - DJMixAlbum: URIRef # DJMixAlbum. - DVDFormat: URIRef # DVDFormat. - DamagedCondition: URIRef # Indicates that the item is damaged. - DanceEvent: URIRef # Event type: A social dance. - DanceGroup: URIRef # A dance group—for example, the Alvin Ailey Dance Theater or Riverdance. - DataCatalog: URIRef # A collection of datasets. - DataDownload: URIRef # A dataset in downloadable form. - DataFeed: URIRef # A single feed providing structured information about one or more entities or topics. - DataFeedItem: URIRef # A single item within a larger data feed. - DataType: URIRef # The basic data types such as Integers, Strings, etc. - Dataset: ( - URIRef # A body of structured information describing some topic(s) of interest. - ) - Date: URIRef # A date value in [ISO 8601 date format](http://en.wikipedia.org/wiki/ISO_8601). - DateTime: URIRef # A combination of date and time of day in the form [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] (see Chapter 5.4 of ISO 8601). - DatedMoneySpecification: URIRef # A DatedMoneySpecification represents monetary values with optional start and end dates. For example, this could represent an employee's salary over a specific period of time. __Note:__ This type has been superseded by [[MonetaryAmount]] use of that type is recommended - DayOfWeek: URIRef # The day of the week, e.g. used to specify to which day the opening hours of an OpeningHoursSpecification refer. Originally, URLs from [GoodRelations](http://purl.org/goodrelations/v1) were used (for [[Monday]], [[Tuesday]], [[Wednesday]], [[Thursday]], [[Friday]], [[Saturday]], [[Sunday]] plus a special entry for [[PublicHolidays]]); these have now been integrated directly into schema.org. - DaySpa: URIRef # A day spa. - DeactivateAction: URIRef # The act of stopping or deactivating a device or application (e.g. stopping a timer or turning off a flashlight). - DecontextualizedContent: URIRef # Content coded 'missing context' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'missing context': Presenting unaltered video in an inaccurate manner that misrepresents the footage. For example, using incorrect dates or locations, altering the transcript or sharing brief clips from a longer video to mislead viewers. (A video rated 'original' can also be missing context.) For an [[ImageObject]] to be 'missing context': Presenting unaltered images in an inaccurate manner to misrepresent the image and mislead the viewer. For example, a common tactic is using an unaltered image but saying it came from a different time or place. (An image rated 'original' can also be missing context.) For an [[ImageObject]] with embedded text to be 'missing context': An unaltered image presented in an inaccurate manner to misrepresent the image and mislead the viewer. For example, a common tactic is using an unaltered image but saying it came from a different time or place. (An 'original' image with inaccurate text would generally fall in this category.) For an [[AudioObject]] to be 'missing context': Unaltered audio presented in an inaccurate manner that misrepresents it. For example, using incorrect dates or locations, or sharing brief clips from a longer recording to mislead viewers. (Audio rated “original†can also be missing context.) - DefenceEstablishment: ( - URIRef # A defence establishment, such as an army or navy base. - ) - DefinedRegion: URIRef # A DefinedRegion is a geographic area defined by potentially arbitrary (rather than political, administrative or natural geographical) criteria. Properties are provided for defining a region by reference to sets of postal codes. Examples: a delivery destination when shopping. Region where regional pricing is configured. Requirement 1: Country: US States: "NY", "CA" Requirement 2: Country: US PostalCode Set: { [94000-94585], [97000, 97999], [13000, 13599]} { [12345, 12345], [78945, 78945], } Region = state, canton, prefecture, autonomous community... - DefinedTerm: URIRef # A word, name, acronym, phrase, etc. with a formal definition. Often used in the context of category or subject classification, glossaries or dictionaries, product or creative work types, etc. Use the name property for the term being defined, use termCode if the term has an alpha-numeric code allocated, use description to provide the definition of the term. - DefinedTermSet: URIRef # A set of defined terms for example a set of categories or a classification scheme, a glossary, dictionary or enumeration. - DefinitiveLegalValue: URIRef # Indicates a document for which the text is conclusively what the law says and is legally binding. (e.g. The digitally signed version of an Official Journal.) Something "Definitive" is considered to be also [[AuthoritativeLegalValue]]. - DeleteAction: ( - URIRef # The act of editing a recipient by removing one of its objects. - ) - DeliveryChargeSpecification: URIRef # The price for the delivery of an offer using a particular delivery method. - DeliveryEvent: URIRef # An event involving the delivery of an item. - DeliveryMethod: URIRef # A delivery method is a standardized procedure for transferring the product or service to the destination of fulfillment chosen by the customer. Delivery methods are characterized by the means of transportation used, and by the organization or group that is the contracting party for the sending organization or person.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#DeliveryModeDirectDownload\n* http://purl.org/goodrelations/v1#DeliveryModeFreight\n* http://purl.org/goodrelations/v1#DeliveryModeMail\n* http://purl.org/goodrelations/v1#DeliveryModeOwnFleet\n* http://purl.org/goodrelations/v1#DeliveryModePickUp\n* http://purl.org/goodrelations/v1#DHL\n* http://purl.org/goodrelations/v1#FederalExpress\n* http://purl.org/goodrelations/v1#UPS - DeliveryTimeSettings: URIRef # A DeliveryTimeSettings represents re-usable pieces of shipping information, relating to timing. It is designed for publication on an URL that may be referenced via the [[shippingSettingsLink]] property of a [[OfferShippingDetails]]. Several occurrences can be published, distinguished (and identified/referenced) by their different values for [[transitTimeLabel]]. - Demand: URIRef # A demand entity represents the public, not necessarily binding, not necessarily exclusive, announcement by an organization or person to seek a certain type of goods or services. For describing demand using this type, the very same properties used for Offer apply. - DemoAlbum: URIRef # DemoAlbum. - Dentist: URIRef # A dentist. - Dentistry: URIRef # A branch of medicine that is involved in the dental care. - DepartAction: URIRef # The act of departing from a place. An agent departs from an fromLocation for a destination, optionally with participants. - DepartmentStore: URIRef # A department store. - DepositAccount: URIRef # A type of Bank Account with a main purpose of depositing funds to gain interest or other benefits. - Dermatologic: URIRef # Something relating to or practicing dermatology. - Dermatology: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of skin. - DiabeticDiet: URIRef # A diet appropriate for people with diabetes. - Diagnostic: URIRef # A medical device used for diagnostic purposes. - DiagnosticLab: URIRef # A medical laboratory that offers on-site or off-site diagnostic services. - DiagnosticProcedure: URIRef # A medical procedure intended primarily for diagnostic, as opposed to therapeutic, purposes. - Diet: URIRef # A strategy of regulating the intake of food to achieve or maintain a specific health-related goal. - DietNutrition: URIRef # Dietetic and nutrition as a medical specialty. - DietarySupplement: URIRef # A product taken by mouth that contains a dietary ingredient intended to supplement the diet. Dietary ingredients may include vitamins, minerals, herbs or other botanicals, amino acids, and substances such as enzymes, organ tissues, glandulars and metabolites. - DigitalAudioTapeFormat: URIRef # DigitalAudioTapeFormat. - DigitalDocument: URIRef # An electronic file or document. - DigitalDocumentPermission: URIRef # A permission for a particular person or group to access a particular file. - DigitalDocumentPermissionType: URIRef # A type of permission which can be granted for accessing a digital document. - DigitalFormat: URIRef # DigitalFormat. - DisabilitySupport: ( - URIRef # DisabilitySupport: this is a benefit for disability support. - ) - DisagreeAction: URIRef # The act of expressing a difference of opinion with the object. An agent disagrees to/about an object (a proposition, topic or theme) with participants. - Discontinued: URIRef # Indicates that the item has been discontinued. - DiscoverAction: URIRef # The act of discovering/finding an object. - DiscussionForumPosting: URIRef # A posting to a discussion forum. - DislikeAction: URIRef # The act of expressing a negative sentiment about the object. An agent dislikes an object (a proposition, topic or theme) with participants. - Distance: URIRef # Properties that take Distances as values are of the form '<Number> <Length unit of measure>'. E.g., '7 ft'. - DistanceFee: URIRef # Represents the distance fee (e.g., price per km or mile) part of the total price for an offered product, for example a car rental. - Distillery: URIRef # A distillery. - DonateAction: URIRef # The act of providing goods, services, or money without compensation, often for philanthropic reasons. - DoseSchedule: URIRef # A specific dosing schedule for a drug or supplement. - DoubleBlindedTrial: URIRef # A trial design in which neither the researcher nor the patient knows the details of the treatment the patient was randomly assigned to. - DownloadAction: URIRef # The act of downloading an object. - Downpayment: URIRef # Represents the downpayment (up-front payment) price component of the total price for an offered product that has additional installment payments. - DrawAction: URIRef # The act of producing a visual/graphical representation of an object, typically with a pen/pencil and paper as instruments. - Drawing: URIRef # A picture or diagram made with a pencil, pen, or crayon rather than paint. - DrinkAction: URIRef # The act of swallowing liquids. - DriveWheelConfigurationValue: ( - URIRef # A value indicating which roadwheels will receive torque. - ) - DrivingSchoolVehicleUsage: ( - URIRef # Indicates the usage of the vehicle for driving school. - ) - Drug: URIRef # A chemical or biologic substance, used as a medical therapy, that has a physiological effect on an organism. Here the term drug is used interchangeably with the term medicine although clinical knowledge make a clear difference between them. - DrugClass: URIRef # A class of medical drugs, e.g., statins. Classes can represent general pharmacological class, common mechanisms of action, common physiological effects, etc. - DrugCost: URIRef # The cost per unit of a medical drug. Note that this type is not meant to represent the price in an offer of a drug for sale; see the Offer type for that. This type will typically be used to tag wholesale or average retail cost of a drug, or maximum reimbursable cost. Costs of medical drugs vary widely depending on how and where they are paid for, so while this type captures some of the variables, costs should be used with caution by consumers of this schema's markup. - DrugCostCategory: URIRef # Enumerated categories of medical drug costs. - DrugLegalStatus: URIRef # The legal availability status of a medical drug. - DrugPregnancyCategory: URIRef # Categories that represent an assessment of the risk of fetal injury due to a drug or pharmaceutical used as directed by the mother during pregnancy. - DrugPrescriptionStatus: URIRef # Indicates whether this drug is available by prescription or over-the-counter. - DrugStrength: URIRef # A specific strength in which a medical drug is available in a specific country. - DryCleaningOrLaundry: URIRef # A dry-cleaning business. - Duration: URIRef # Quantity: Duration (use [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601)). - EBook: URIRef # Book format: Ebook. - EPRelease: URIRef # EPRelease. - EUEnergyEfficiencyCategoryA: URIRef # Represents EU Energy Efficiency Class A as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryA1Plus: URIRef # Represents EU Energy Efficiency Class A+ as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryA2Plus: URIRef # Represents EU Energy Efficiency Class A++ as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryA3Plus: URIRef # Represents EU Energy Efficiency Class A+++ as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryB: URIRef # Represents EU Energy Efficiency Class B as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryC: URIRef # Represents EU Energy Efficiency Class C as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryD: URIRef # Represents EU Energy Efficiency Class D as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryE: URIRef # Represents EU Energy Efficiency Class E as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryF: URIRef # Represents EU Energy Efficiency Class F as defined in EU energy labeling regulations. - EUEnergyEfficiencyCategoryG: URIRef # Represents EU Energy Efficiency Class G as defined in EU energy labeling regulations. - EUEnergyEfficiencyEnumeration: URIRef # Enumerates the EU energy efficiency classes A-G as well as A+, A++, and A+++ as defined in EU directive 2017/1369. - Ear: URIRef # Ear function assessment with clinical examination. - EatAction: URIRef # The act of swallowing solid objects. - EditedOrCroppedContent: URIRef # Content coded 'edited or cropped content' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'edited or cropped content': The video has been edited or rearranged. This category applies to time edits, including editing multiple videos together to alter the story being told or editing out large portions from a video. For an [[ImageObject]] to be 'edited or cropped content': Presenting a part of an image from a larger whole to mislead the viewer. For an [[ImageObject]] with embedded text to be 'edited or cropped content': Presenting a part of an image from a larger whole to mislead the viewer. For an [[AudioObject]] to be 'edited or cropped content': The audio has been edited or rearranged. This category applies to time edits, including editing multiple audio clips together to alter the story being told or editing out large portions from the recording. - EducationEvent: URIRef # Event type: Education event. - EducationalAudience: URIRef # An EducationalAudience. - EducationalOccupationalCredential: URIRef # An educational or occupational credential. A diploma, academic degree, certification, qualification, badge, etc., that may be awarded to a person or other entity that meets the requirements defined by the credentialer. - EducationalOccupationalProgram: URIRef # A program offered by an institution which determines the learning progress to achieve an outcome, usually a credential like a degree or certificate. This would define a discrete set of opportunities (e.g., job, courses) that together constitute a program with a clear start, end, set of requirements, and transition to a new occupational opportunity (e.g., a job), or sometimes a higher educational opportunity (e.g., an advanced degree). - EducationalOrganization: URIRef # An educational organization. - EffectivenessHealthAspect: ( - URIRef # Content about the effectiveness-related aspects of a health topic. - ) - Electrician: URIRef # An electrician. - ElectronicsStore: URIRef # An electronics store. - ElementarySchool: URIRef # An elementary school. - EmailMessage: URIRef # An email message. - Embassy: URIRef # An embassy. - Emergency: URIRef # A specific branch of medical science that deals with the evaluation and initial treatment of medical conditions caused by trauma or sudden illness. - EmergencyService: URIRef # An emergency service, such as a fire station or ER. - EmployeeRole: URIRef # A subclass of OrganizationRole used to describe employee relationships. - EmployerAggregateRating: URIRef # An aggregate rating of an Organization related to its role as an employer. - EmployerReview: URIRef # An [[EmployerReview]] is a review of an [[Organization]] regarding its role as an employer, written by a current or former employee of that organization. - EmploymentAgency: URIRef # An employment agency. - Endocrine: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of endocrine glands and their secretions. - EndorseAction: ( - URIRef # An agent approves/certifies/likes/supports/sanction an object. - ) - EndorsementRating: URIRef # An EndorsementRating is a rating that expresses some level of endorsement, for example inclusion in a "critic's pick" blog, a "Like" or "+1" on a social network. It can be considered the [[result]] of an [[EndorseAction]] in which the [[object]] of the action is rated positively by some [[agent]]. As is common elsewhere in schema.org, it is sometimes more useful to describe the results of such an action without explicitly describing the [[Action]]. An [[EndorsementRating]] may be part of a numeric scale or organized system, but this is not required: having an explicit type for indicating a positive, endorsement rating is particularly useful in the absence of numeric scales as it helps consumers understand that the rating is broadly positive. - Energy: URIRef # Properties that take Energy as values are of the form '<Number> <Energy unit of measure>'. - EnergyConsumptionDetails: URIRef # EnergyConsumptionDetails represents information related to the energy efficiency of a product that consumes energy. The information that can be provided is based on international regulations such as for example [EU directive 2017/1369](https://eur-lex.europa.eu/eli/reg/2017/1369/oj) for energy labeling and the [Energy labeling rule](https://www.ftc.gov/enforcement/rules/rulemaking-regulatory-reform-proceedings/energy-water-use-labeling-consumer) under the Energy Policy and Conservation Act (EPCA) in the US. - EnergyEfficiencyEnumeration: URIRef # Enumerates energy efficiency levels (also known as "classes" or "ratings") and certifications that are part of several international energy efficiency standards. - EnergyStarCertified: URIRef # Represents EnergyStar certification. - EnergyStarEnergyEfficiencyEnumeration: ( - URIRef # Used to indicate whether a product is EnergyStar certified. - ) - EngineSpecification: URIRef # Information about the engine of the vehicle. A vehicle can have multiple engines represented by multiple engine specification entities. - EnrollingByInvitation: URIRef # Enrolling participants by invitation only. - EntertainmentBusiness: URIRef # A business providing entertainment. - EntryPoint: URIRef # An entry point, within some Web-based protocol. - Enumeration: URIRef # Lists or enumerations—for example, a list of cuisines or music genres, etc. - Episode: URIRef # A media episode (e.g. TV, radio, video game) which can be part of a series or season. - Event: URIRef # An event happening at a certain time and location, such as a concert, lecture, or festival. Ticketing information may be added via the [[offers]] property. Repeated events may be structured as separate Event objects. - EventAttendanceModeEnumeration: URIRef # An EventAttendanceModeEnumeration value is one of potentially several modes of organising an event, relating to whether it is online or offline. - EventCancelled: URIRef # The event has been cancelled. If the event has multiple startDate values, all are assumed to be cancelled. Either startDate or previousStartDate may be used to specify the event's cancelled date(s). - EventMovedOnline: URIRef # Indicates that the event was changed to allow online participation. See [[eventAttendanceMode]] for specifics of whether it is now fully or partially online. - EventPostponed: URIRef # The event has been postponed and no new date has been set. The event's previousStartDate should be set. - EventRescheduled: URIRef # The event has been rescheduled. The event's previousStartDate should be set to the old date and the startDate should be set to the event's new date. (If the event has been rescheduled multiple times, the previousStartDate property may be repeated). - EventReservation: URIRef # A reservation for an event like a concert, sporting event, or lecture.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - EventScheduled: URIRef # The event is taking place or has taken place on the startDate as scheduled. Use of this value is optional, as it is assumed by default. - EventSeries: URIRef # A series of [[Event]]s. Included events can relate with the series using the [[superEvent]] property. An EventSeries is a collection of events that share some unifying characteristic. For example, "The Olympic Games" is a series, which is repeated regularly. The "2012 London Olympics" can be presented both as an [[Event]] in the series "Olympic Games", and as an [[EventSeries]] that included a number of sporting competitions as Events. The nature of the association between the events in an [[EventSeries]] can vary, but typical examples could include a thematic event series (e.g. topical meetups or classes), or a series of regular events that share a location, attendee group and/or organizers. EventSeries has been defined as a kind of Event to make it easy for publishers to use it in an Event context without worrying about which kinds of series are really event-like enough to call an Event. In general an EventSeries may seem more Event-like when the period of time is compact and when aspects such as location are fixed, but it may also sometimes prove useful to describe a longer-term series as an Event. - EventStatusType: URIRef # EventStatusType is an enumeration type whose instances represent several states that an Event may be in. - EventVenue: URIRef # An event venue. - EvidenceLevelA: URIRef # Data derived from multiple randomized clinical trials or meta-analyses. - EvidenceLevelB: ( - URIRef # Data derived from a single randomized trial, or nonrandomized studies. - ) - EvidenceLevelC: ( - URIRef # Only consensus opinion of experts, case studies, or standard-of-care. - ) - ExchangeRateSpecification: URIRef # A structured value representing exchange rate. - ExchangeRefund: URIRef # Specifies that a refund can be done as an exchange for the same product. - ExerciseAction: URIRef # The act of participating in exertive activity for the purposes of improving health and fitness. - ExerciseGym: URIRef # A gym. - ExercisePlan: URIRef # Fitness-related activity designed for a specific health-related purpose, including defined exercise routines as well as activity prescribed by a clinician. - ExhibitionEvent: URIRef # Event type: Exhibition event, e.g. at a museum, library, archive, tradeshow, ... - Eye: URIRef # Eye or ophtalmological function assessment with clinical examination. - FAQPage: URIRef # A [[FAQPage]] is a [[WebPage]] presenting one or more "[Frequently asked questions](https://en.wikipedia.org/wiki/FAQ)" (see also [[QAPage]]). - FDAcategoryA: URIRef # A designation by the US FDA signifying that adequate and well-controlled studies have failed to demonstrate a risk to the fetus in the first trimester of pregnancy (and there is no evidence of risk in later trimesters). - FDAcategoryB: URIRef # A designation by the US FDA signifying that animal reproduction studies have failed to demonstrate a risk to the fetus and there are no adequate and well-controlled studies in pregnant women. - FDAcategoryC: URIRef # A designation by the US FDA signifying that animal reproduction studies have shown an adverse effect on the fetus and there are no adequate and well-controlled studies in humans, but potential benefits may warrant use of the drug in pregnant women despite potential risks. - FDAcategoryD: URIRef # A designation by the US FDA signifying that there is positive evidence of human fetal risk based on adverse reaction data from investigational or marketing experience or studies in humans, but potential benefits may warrant use of the drug in pregnant women despite potential risks. - FDAcategoryX: URIRef # A designation by the US FDA signifying that studies in animals or humans have demonstrated fetal abnormalities and/or there is positive evidence of human fetal risk based on adverse reaction data from investigational or marketing experience, and the risks involved in use of the drug in pregnant women clearly outweigh potential benefits. - FDAnotEvaluated: URIRef # A designation that the drug in question has not been assigned a pregnancy category designation by the US FDA. - FMRadioChannel: URIRef # A radio channel that uses FM. - FailedActionStatus: URIRef # An action that failed to complete. The action's error property and the HTTP return code contain more information about the failure. - # False: URIRef # The boolean value false. - FastFoodRestaurant: URIRef # A fast-food restaurant. - Female: URIRef # The female gender. - Festival: URIRef # Event type: Festival. - FilmAction: URIRef # The act of capturing sound and moving images on film, video, or digitally. - FinancialProduct: URIRef # A product provided to consumers and businesses by financial institutions such as banks, insurance companies, brokerage firms, consumer finance companies, and investment companies which comprise the financial services industry. - FinancialService: URIRef # Financial services business. - FindAction: URIRef # The act of finding an object.\n\nRelated actions:\n\n* [[SearchAction]]: FindAction is generally lead by a SearchAction, but not necessarily. - FireStation: URIRef # A fire station. With firemen. - Flexibility: URIRef # Physical activity that is engaged in to improve joint and muscle flexibility. - Flight: URIRef # An airline flight. - FlightReservation: URIRef # A reservation for air travel.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - Float: URIRef # Data type: Floating number. - FloorPlan: URIRef # A FloorPlan is an explicit representation of a collection of similar accommodations, allowing the provision of common information (room counts, sizes, layout diagrams) and offers for rental or sale. In typical use, some [[ApartmentComplex]] has an [[accommodationFloorPlan]] which is a [[FloorPlan]]. A FloorPlan is always in the context of a particular place, either a larger [[ApartmentComplex]] or a single [[Apartment]]. The visual/spatial aspects of a floor plan (i.e. room layout, [see wikipedia](https://en.wikipedia.org/wiki/Floor_plan)) can be indicated using [[image]]. - Florist: URIRef # A florist. - FollowAction: URIRef # The act of forming a personal connection with someone/something (object) unidirectionally/asymmetrically to get updates polled from.\n\nRelated actions:\n\n* [[BefriendAction]]: Unlike BefriendAction, FollowAction implies that the connection is *not* necessarily reciprocal.\n* [[SubscribeAction]]: Unlike SubscribeAction, FollowAction implies that the follower acts as an active agent constantly/actively polling for updates.\n* [[RegisterAction]]: Unlike RegisterAction, FollowAction implies that the agent is interested in continuing receiving updates from the object.\n* [[JoinAction]]: Unlike JoinAction, FollowAction implies that the agent is interested in getting updates from the object.\n* [[TrackAction]]: Unlike TrackAction, FollowAction refers to the polling of updates of all aspects of animate objects rather than the location of inanimate objects (e.g. you track a package, but you don't follow it). - FoodEstablishment: URIRef # A food-related business. - FoodEstablishmentReservation: URIRef # A reservation to dine at a food-related business.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. - FoodEvent: URIRef # Event type: Food event. - FoodService: URIRef # A food service, like breakfast, lunch, or dinner. - FourWheelDriveConfiguration: URIRef # Four-wheel drive is a transmission layout where the engine primarily drives two wheels with a part-time four-wheel drive capability. - FreeReturn: ( - URIRef # Specifies that product returns are free of charge for the customer. - ) - Friday: URIRef # The day of the week between Thursday and Saturday. - FrontWheelDriveConfiguration: URIRef # Front-wheel drive is a transmission layout where the engine drives the front wheels. - FullRefund: URIRef # Specifies that a refund can be done in the full amount the customer paid for the product - FundingAgency: URIRef # A FundingAgency is an organization that implements one or more [[FundingScheme]]s and manages the granting process (via [[Grant]]s, typically [[MonetaryGrant]]s). A funding agency is not always required for grant funding, e.g. philanthropic giving, corporate sponsorship etc. Examples of funding agencies include ERC, REA, NIH, Bill and Melinda Gates Foundation... - FundingScheme: URIRef # A FundingScheme combines organizational, project and policy aspects of grant-based funding that sets guidelines, principles and mechanisms to support other kinds of projects and activities. Funding is typically organized via [[Grant]] funding. Examples of funding schemes: Swiss Priority Programmes (SPPs); EU Framework 7 (FP7); Horizon 2020; the NIH-R01 Grant Program; Wellcome institutional strategic support fund. For large scale public sector funding, the management and administration of grant awards is often handled by other, dedicated, organizations - [[FundingAgency]]s such as ERC, REA, ... - Fungus: URIRef # Pathogenic fungus. - FurnitureStore: URIRef # A furniture store. - Game: URIRef # The Game type represents things which are games. These are typically rule-governed recreational activities, e.g. role-playing games in which players assume the role of characters in a fictional setting. - GamePlayMode: ( - URIRef # Indicates whether this game is multi-player, co-op or single-player. - ) - GameServer: URIRef # Server that provides game interaction in a multiplayer game. - GameServerStatus: URIRef # Status of a game server. - GardenStore: URIRef # A garden store. - GasStation: URIRef # A gas station. - Gastroenterologic: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of digestive system. - GatedResidenceCommunity: URIRef # Residence type: Gated community. - GenderType: URIRef # An enumeration of genders. - Gene: URIRef # A discrete unit of inheritance which affects one or more biological traits (Source: [https://en.wikipedia.org/wiki/Gene](https://en.wikipedia.org/wiki/Gene)). Examples include FOXP2 (Forkhead box protein P2), SCARNA21 (small Cajal body-specific RNA 21), A- (agouti genotype). - GeneralContractor: URIRef # A general contractor. - Genetic: URIRef # A specific branch of medical science that pertains to hereditary transmission and the variation of inherited characteristics and disorders. - Genitourinary: ( - URIRef # Genitourinary system function assessment with clinical examination. - ) - GeoCircle: URIRef # A GeoCircle is a GeoShape representing a circular geographic area. As it is a GeoShape it provides the simple textual property 'circle', but also allows the combination of postalCode alongside geoRadius. The center of the circle can be indicated via the 'geoMidpoint' property, or more approximately using 'address', 'postalCode'. - GeoCoordinates: URIRef # The geographic coordinates of a place or event. - GeoShape: URIRef # The geographic shape of a place. A GeoShape can be described using several properties whose values are based on latitude/longitude pairs. Either whitespace or commas can be used to separate latitude and longitude; whitespace should be used when writing a list of several such points. - GeospatialGeometry: URIRef # (Eventually to be defined as) a supertype of GeoShape designed to accommodate definitions from Geo-Spatial best practices. - Geriatric: URIRef # A specific branch of medical science that is concerned with the diagnosis and treatment of diseases, debilities and provision of care to the aged. - GettingAccessHealthAspect: URIRef # Content that discusses practical and policy aspects for getting access to specific kinds of healthcare (e.g. distribution mechanisms for vaccines). - GiveAction: URIRef # The act of transferring ownership of an object to a destination. Reciprocal of TakeAction.\n\nRelated actions:\n\n* [[TakeAction]]: Reciprocal of GiveAction.\n* [[SendAction]]: Unlike SendAction, GiveAction implies that ownership is being transferred (e.g. I may send my laptop to you, but that doesn't mean I'm giving it to you). - GlutenFreeDiet: URIRef # A diet exclusive of gluten. - GolfCourse: URIRef # A golf course. - GovernmentBenefitsType: URIRef # GovernmentBenefitsType enumerates several kinds of government benefits to support the COVID-19 situation. Note that this structure may not capture all benefits offered. - GovernmentBuilding: URIRef # A government building. - GovernmentOffice: ( - URIRef # A government office—for example, an IRS or DMV office. - ) - GovernmentOrganization: URIRef # A governmental organization or agency. - GovernmentPermit: URIRef # A permit issued by a government agency. - GovernmentService: URIRef # A service provided by a government organization, e.g. food stamps, veterans benefits, etc. - Grant: URIRef # A grant, typically financial or otherwise quantifiable, of resources. Typically a [[funder]] sponsors some [[MonetaryAmount]] to an [[Organization]] or [[Person]], sometimes not necessarily via a dedicated or long-lived [[Project]], resulting in one or more outputs, or [[fundedItem]]s. For financial sponsorship, indicate the [[funder]] of a [[MonetaryGrant]]. For non-financial support, indicate [[sponsor]] of [[Grant]]s of resources (e.g. office space). Grants support activities directed towards some agreed collective goals, often but not always organized as [[Project]]s. Long-lived projects are sometimes sponsored by a variety of grants over time, but it is also common for a project to be associated with a single grant. The amount of a [[Grant]] is represented using [[amount]] as a [[MonetaryAmount]]. - GraphicNovel: URIRef # Book format: GraphicNovel. May represent a bound collection of ComicIssue instances. - GroceryStore: URIRef # A grocery store. - GroupBoardingPolicy: ( - URIRef # The airline boards by groups based on check-in time, priority, etc. - ) - Guide: URIRef # [[Guide]] is a page or article that recommend specific products or services, or aspects of a thing for a user to consider. A [[Guide]] may represent a Buying Guide and detail aspects of products or services for a user to consider. A [[Guide]] may represent a Product Guide and recommend specific products or services. A [[Guide]] may represent a Ranked List and recommend specific products or services with ranking. - Gynecologic: URIRef # A specific branch of medical science that pertains to the health care of women, particularly in the diagnosis and treatment of disorders affecting the female reproductive system. - HVACBusiness: URIRef # A business that provide Heating, Ventilation and Air Conditioning services. - Hackathon: URIRef # A [hackathon](https://en.wikipedia.org/wiki/Hackathon) event. - HairSalon: URIRef # A hair salon. - HalalDiet: URIRef # A diet conforming to Islamic dietary practices. - Hardcover: URIRef # Book format: Hardcover. - HardwareStore: URIRef # A hardware store. - Head: URIRef # Head assessment with clinical examination. - HealthAndBeautyBusiness: URIRef # Health and beauty. - HealthAspectEnumeration: URIRef # HealthAspectEnumeration enumerates several aspects of health content online, each of which might be described using [[hasHealthAspect]] and [[HealthTopicContent]]. - HealthCare: URIRef # HealthCare: this is a benefit for health care. - HealthClub: URIRef # A health club. - HealthInsurancePlan: ( - URIRef # A US-style health insurance plan, including PPOs, EPOs, and HMOs. - ) - HealthPlanCostSharingSpecification: URIRef # A description of costs to the patient under a given network or formulary. - HealthPlanFormulary: URIRef # For a given health insurance plan, the specification for costs and coverage of prescription drugs. - HealthPlanNetwork: URIRef # A US-style health insurance plan network. - HealthTopicContent: URIRef # [[HealthTopicContent]] is [[WebContent]] that is about some aspect of a health topic, e.g. a condition, its symptoms or treatments. Such content may be comprised of several parts or sections and use different types of media. Multiple instances of [[WebContent]] (and hence [[HealthTopicContent]]) can be related using [[hasPart]] / [[isPartOf]] where there is some kind of content hierarchy, and their content described with [[about]] and [[mentions]] e.g. building upon the existing [[MedicalCondition]] vocabulary. - HearingImpairedSupported: ( - URIRef # Uses devices to support users with hearing impairments. - ) - Hematologic: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of blood and blood producing organs. - HighSchool: URIRef # A high school. - HinduDiet: URIRef # A diet conforming to Hindu dietary practices, in particular, beef-free. - HinduTemple: URIRef # A Hindu temple. - HobbyShop: ( - URIRef # A store that sells materials useful or necessary for various hobbies. - ) - HomeAndConstructionBusiness: URIRef # A construction business.\n\nA HomeAndConstructionBusiness is a [[LocalBusiness]] that provides services around homes and buildings.\n\nAs a [[LocalBusiness]] it can be described as a [[provider]] of one or more [[Service]]\(s). - HomeGoodsStore: URIRef # A home goods store. - Homeopathic: URIRef # A system of medicine based on the principle that a disease can be cured by a substance that produces similar symptoms in healthy people. - Hospital: URIRef # A hospital. - Hostel: URIRef # A hostel - cheap accommodation, often in shared dormitories.

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - Hotel: URIRef # A hotel is an establishment that provides lodging paid on a short-term basis (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Hotel).

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - HotelRoom: URIRef # A hotel room is a single room in a hotel.

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - House: URIRef # A house is a building or structure that has the ability to be occupied for habitation by humans or other creatures (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/House). - HousePainter: URIRef # A house painting service. - HowItWorksHealthAspect: URIRef # Content that discusses and explains how a particular health-related topic works, e.g. in terms of mechanisms and underlying science. - HowOrWhereHealthAspect: URIRef # Information about how or where to find a topic. Also may contain location data that can be used for where to look for help if the topic is observed. - HowTo: URIRef # Instructions that explain how to achieve a result by performing a sequence of steps. - HowToDirection: URIRef # A direction indicating a single action to do in the instructions for how to achieve a result. - HowToItem: URIRef # An item used as either a tool or supply when performing the instructions for how to to achieve a result. - HowToSection: URIRef # A sub-grouping of steps in the instructions for how to achieve a result (e.g. steps for making a pie crust within a pie recipe). - HowToStep: URIRef # A step in the instructions for how to achieve a result. It is an ordered list with HowToDirection and/or HowToTip items. - HowToSupply: URIRef # A supply consumed when performing the instructions for how to achieve a result. - HowToTip: URIRef # An explanation in the instructions for how to achieve a result. It provides supplementary information about a technique, supply, author's preference, etc. It can explain what could be done, or what should not be done, but doesn't specify what should be done (see HowToDirection). - HowToTool: URIRef # A tool used (but not consumed) when performing instructions for how to achieve a result. - HyperToc: URIRef # A HyperToc represents a hypertext table of contents for complex media objects, such as [[VideoObject]], [[AudioObject]]. Items in the table of contents are indicated using the [[tocEntry]] property, and typed [[HyperTocEntry]]. For cases where the same larger work is split into multiple files, [[associatedMedia]] can be used on individual [[HyperTocEntry]] items. - HyperTocEntry: URIRef # A HyperToEntry is an item within a [[HyperToc]], which represents a hypertext table of contents for complex media objects, such as [[VideoObject]], [[AudioObject]]. The media object itself is indicated using [[associatedMedia]]. Each section of interest within that content can be described with a [[HyperTocEntry]], with associated [[startOffset]] and [[endOffset]]. When several entries are all from the same file, [[associatedMedia]] is used on the overarching [[HyperTocEntry]]; if the content has been split into multiple files, they can be referenced using [[associatedMedia]] on each [[HyperTocEntry]]. - IceCreamShop: URIRef # An ice cream shop. - IgnoreAction: URIRef # The act of intentionally disregarding the object. An agent ignores an object. - ImageGallery: URIRef # Web page type: Image gallery page. - ImageObject: URIRef # An image file. - ImageObjectSnapshot: URIRef # A specific and exact (byte-for-byte) version of an [[ImageObject]]. Two byte-for-byte identical files, for the purposes of this type, considered identical. If they have different embedded metadata (e.g. XMP, EXIF) the files will differ. Different external facts about the files, e.g. creator or dateCreated that aren't represented in their actual content, do not affect this notion of identity. - ImagingTest: ( - URIRef # Any medical imaging modality typically used for diagnostic purposes. - ) - InForce: URIRef # Indicates that a legislation is in force. - InStock: URIRef # Indicates that the item is in stock. - InStoreOnly: ( - URIRef # Indicates that the item is available only at physical locations. - ) - IndividualProduct: URIRef # A single, identifiable product instance (e.g. a laptop with a particular serial number). - Infectious: URIRef # Something in medical science that pertains to infectious diseases i.e caused by bacterial, viral, fungal or parasitic infections. - InfectiousAgentClass: URIRef # Classes of agents or pathogens that transmit infectious diseases. Enumerated type. - InfectiousDisease: URIRef # An infectious disease is a clinically evident human disease resulting from the presence of pathogenic microbial agents, like pathogenic viruses, pathogenic bacteria, fungi, protozoa, multicellular parasites, and prions. To be considered an infectious disease, such pathogens are known to be able to cause this disease. - InformAction: URIRef # The act of notifying someone of information pertinent to them, with no expectation of a response. - IngredientsHealthAspect: ( - URIRef # Content discussing ingredients-related aspects of a health topic. - ) - InsertAction: ( - URIRef # The act of adding at a specific location in an ordered collection. - ) - InstallAction: URIRef # The act of installing an application. - Installment: URIRef # Represents the installment pricing component of the total price for an offered product. - InsuranceAgency: URIRef # An Insurance agency. - Intangible: URIRef # A utility class that serves as the umbrella for a number of 'intangible' things such as quantities, structured values, etc. - Integer: URIRef # Data type: Integer. - InteractAction: ( - URIRef # The act of interacting with another person or organization. - ) - InteractionCounter: URIRef # A summary of how users have interacted with this CreativeWork. In most cases, authors will use a subtype to specify the specific type of interaction. - InternationalTrial: URIRef # An international trial. - InternetCafe: URIRef # An internet cafe. - InvestmentFund: URIRef # A company or fund that gathers capital from a number of investors to create a pool of money that is then re-invested into stocks, bonds and other assets. - InvestmentOrDeposit: URIRef # A type of financial product that typically requires the client to transfer funds to a financial service in return for potential beneficial financial return. - InviteAction: URIRef # The act of asking someone to attend an event. Reciprocal of RsvpAction. - Invoice: URIRef # A statement of the money due for goods or services; a bill. - InvoicePrice: URIRef # Represents the invoice price of an offered product. - ItemAvailability: URIRef # A list of possible product availability options. - ItemList: URIRef # A list of items of any sort—for example, Top 10 Movies About Weathermen, or Top 100 Party Songs. Not to be confused with HTML lists, which are often used only for formatting. - ItemListOrderAscending: ( - URIRef # An ItemList ordered with lower values listed first. - ) - ItemListOrderDescending: ( - URIRef # An ItemList ordered with higher values listed first. - ) - ItemListOrderType: URIRef # Enumerated for values for itemListOrder for indicating how an ordered ItemList is organized. - ItemListUnordered: URIRef # An ItemList ordered with no explicit order. - ItemPage: URIRef # A page devoted to a single item, such as a particular product or hotel. - JewelryStore: URIRef # A jewelry store. - JobPosting: ( - URIRef # A listing that describes a job opening in a certain organization. - ) - JoinAction: URIRef # An agent joins an event/group with participants/friends at a location.\n\nRelated actions:\n\n* [[RegisterAction]]: Unlike RegisterAction, JoinAction refers to joining a group/team of people.\n* [[SubscribeAction]]: Unlike SubscribeAction, JoinAction does not imply that you'll be receiving updates.\n* [[FollowAction]]: Unlike FollowAction, JoinAction does not imply that you'll be polling for updates. - Joint: URIRef # The anatomical location at which two or more bones make contact. - KosherDiet: URIRef # A diet conforming to Jewish dietary practices. - LaboratoryScience: URIRef # A medical science pertaining to chemical, hematological, immunologic, microscopic, or bacteriological diagnostic analyses or research. - LakeBodyOfWater: URIRef # A lake (for example, Lake Pontrachain). - Landform: URIRef # A landform or physical feature. Landform elements include mountains, plains, lakes, rivers, seascape and oceanic waterbody interface features such as bays, peninsulas, seas and so forth, including sub-aqueous terrain features such as submersed mountain ranges, volcanoes, and the great ocean basins. - LandmarksOrHistoricalBuildings: URIRef # An historical landmark or building. - Language: URIRef # Natural languages such as Spanish, Tamil, Hindi, English, etc. Formal language code tags expressed in [BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) can be used via the [[alternateName]] property. The Language type previously also covered programming languages such as Scheme and Lisp, which are now best represented using [[ComputerLanguage]]. - LaserDiscFormat: URIRef # LaserDiscFormat. - LearningResource: URIRef # The LearningResource type can be used to indicate [[CreativeWork]]s (whether physical or digital) that have a particular and explicit orientation towards learning, education, skill acquisition, and other educational purposes. [[LearningResource]] is expected to be used as an addition to a primary type such as [[Book]], [[VideoObject]], [[Product]] etc. [[EducationEvent]] serves a similar purpose for event-like things (e.g. a [[Trip]]). A [[LearningResource]] may be created as a result of an [[EducationEvent]], for example by recording one. - LeaveAction: URIRef # An agent leaves an event / group with participants/friends at a location.\n\nRelated actions:\n\n* [[JoinAction]]: The antonym of LeaveAction.\n* [[UnRegisterAction]]: Unlike UnRegisterAction, LeaveAction implies leaving a group/team of people rather than a service. - LeftHandDriving: URIRef # The steering position is on the left side of the vehicle (viewed from the main direction of driving). - LegalForceStatus: ( - URIRef # A list of possible statuses for the legal force of a legislation. - ) - LegalService: URIRef # A LegalService is a business that provides legally-oriented services, advice and representation, e.g. law firms.\n\nAs a [[LocalBusiness]] it can be described as a [[provider]] of one or more [[Service]]\(s). - LegalValueLevel: ( - URIRef # A list of possible levels for the legal validity of a legislation. - ) - Legislation: URIRef # A legal document such as an act, decree, bill, etc. (enforceable or not) or a component of a legal act (like an article). - LegislationObject: URIRef # A specific object or file containing a Legislation. Note that the same Legislation can be published in multiple files. For example, a digitally signed PDF, a plain PDF and an HTML version. - LegislativeBuilding: ( - URIRef # A legislative building—for example, the state capitol. - ) - LeisureTimeActivity: URIRef # Any physical activity engaged in for recreational purposes. Examples may include ballroom dancing, roller skating, canoeing, fishing, etc. - LendAction: URIRef # The act of providing an object under an agreement that it will be returned at a later date. Reciprocal of BorrowAction.\n\nRelated actions:\n\n* [[BorrowAction]]: Reciprocal of LendAction. - Library: URIRef # A library. - LibrarySystem: URIRef # A [[LibrarySystem]] is a collaborative system amongst several libraries. - LifestyleModification: URIRef # A process of care involving exercise, changes to diet, fitness routines, and other lifestyle changes aimed at improving a health condition. - Ligament: URIRef # A short band of tough, flexible, fibrous connective tissue that functions to connect multiple bones, cartilages, and structurally support joints. - LikeAction: URIRef # The act of expressing a positive sentiment about the object. An agent likes an object (a proposition, topic or theme) with participants. - LimitedAvailability: URIRef # Indicates that the item has limited availability. - LimitedByGuaranteeCharity: URIRef # LimitedByGuaranteeCharity: Non-profit type referring to a charitable company that is limited by guarantee (UK). - LinkRole: URIRef # A Role that represents a Web link e.g. as expressed via the 'url' property. Its linkRelationship property can indicate URL-based and plain textual link types e.g. those in IANA link registry or others such as 'amphtml'. This structure provides a placeholder where details from HTML's link element can be represented outside of HTML, e.g. in JSON-LD feeds. - LiquorStore: URIRef # A shop that sells alcoholic drinks such as wine, beer, whisky and other spirits. - ListItem: URIRef # An list item, e.g. a step in a checklist or how-to description. - ListPrice: URIRef # Represents the list price (the price a product is actually advertised for) of an offered product. - ListenAction: URIRef # The act of consuming audio content. - LiteraryEvent: URIRef # Event type: Literary event. - LiveAlbum: URIRef # LiveAlbum. - LiveBlogPosting: URIRef # A [[LiveBlogPosting]] is a [[BlogPosting]] intended to provide a rolling textual coverage of an ongoing event through continuous updates. - LivingWithHealthAspect: ( - URIRef # Information about coping or life related to the topic. - ) - LoanOrCredit: URIRef # A financial product for the loaning of an amount of money, or line of credit, under agreed terms and charges. - LocalBusiness: URIRef # A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc. - LocationFeatureSpecification: URIRef # Specifies a location feature by providing a structured value representing a feature of an accommodation as a property-value pair of varying degrees of formality. - LockerDelivery: ( - URIRef # A DeliveryMethod in which an item is made available via locker. - ) - Locksmith: URIRef # A locksmith. - LodgingBusiness: URIRef # A lodging business, such as a motel, hotel, or inn. - LodgingReservation: URIRef # A reservation for lodging at a hotel, motel, inn, etc.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. - Longitudinal: URIRef # Unlike cross-sectional studies, longitudinal studies track the same people, and therefore the differences observed in those people are less likely to be the result of cultural differences across generations. Longitudinal studies are also used in medicine to uncover predictors of certain diseases. - LoseAction: URIRef # The act of being defeated in a competitive activity. - LowCalorieDiet: URIRef # A diet focused on reduced calorie intake. - LowFatDiet: URIRef # A diet focused on reduced fat and cholesterol intake. - LowLactoseDiet: URIRef # A diet appropriate for people with lactose intolerance. - LowSaltDiet: URIRef # A diet focused on reduced sodium intake. - Lung: URIRef # Lung and respiratory system clinical examination. - LymphaticVessel: URIRef # A type of blood vessel that specifically carries lymph fluid unidirectionally toward the heart. - MRI: URIRef # Magnetic resonance imaging. - MSRP: URIRef # Represents the manufacturer suggested retail price ("MSRP") of an offered product. - Male: URIRef # The male gender. - Manuscript: URIRef # A book, document, or piece of music written by hand rather than typed or printed. - Map: URIRef # A map. - MapCategoryType: URIRef # An enumeration of several kinds of Map. - MarryAction: URIRef # The act of marrying a person. - Mass: URIRef # Properties that take Mass as values are of the form '<Number> <Mass unit of measure>'. E.g., '7 kg'. - MathSolver: URIRef # A math solver which is capable of solving a subset of mathematical problems. - MaximumDoseSchedule: URIRef # The maximum dosing schedule considered safe for a drug or supplement as recommended by an authority or by the drug/supplement's manufacturer. Capture the recommending authority in the recognizingAuthority property of MedicalEntity. - MayTreatHealthAspect: URIRef # Related topics may be treated by a Topic. - MeasurementTypeEnumeration: URIRef # Enumeration of common measurement types (or dimensions), for example "chest" for a person, "inseam" for pants, "gauge" for screws, or "wheel" for bicycles. - MediaGallery: URIRef # Web page type: Media gallery page. A mixed-media page that can contains media such as images, videos, and other multimedia. - MediaManipulationRatingEnumeration: URIRef # Codes for use with the [[mediaAuthenticityCategory]] property, indicating the authenticity of a media object (in the context of how it was published or shared). In general these codes are not mutually exclusive, although some combinations (such as 'original' versus 'transformed', 'edited' and 'staged') would be contradictory if applied in the same [[MediaReview]]. Note that the application of these codes is with regard to a piece of media shared or published in a particular context. - MediaObject: URIRef # A media object, such as an image, video, or audio object embedded in a web page or a downloadable dataset i.e. DataDownload. Note that a creative work may have many media objects associated with it on the same web page. For example, a page about a single song (MusicRecording) may have a music video (VideoObject), and a high and low bandwidth audio stream (2 AudioObject's). - MediaReview: URIRef # A [[MediaReview]] is a more specialized form of Review dedicated to the evaluation of media content online, typically in the context of fact-checking and misinformation. For more general reviews of media in the broader sense, use [[UserReview]], [[CriticReview]] or other [[Review]] types. This definition is a work in progress. While the [[MediaManipulationRatingEnumeration]] list reflects significant community review amongst fact-checkers and others working to combat misinformation, the specific structures for representing media objects, their versions and publication context, is still evolving. Similarly, best practices for the relationship between [[MediaReview]] and [[ClaimReview]] markup has not yet been finalized. - MediaReviewItem: URIRef # Represents an item or group of closely related items treated as a unit for the sake of evaluation in a [[MediaReview]]. Authorship etc. apply to the items rather than to the curation/grouping or reviewing party. - MediaSubscription: URIRef # A subscription which allows a user to access media including audio, video, books, etc. - MedicalAudience: URIRef # Target audiences for medical web pages. - MedicalAudienceType: ( - URIRef # Target audiences types for medical web pages. Enumerated type. - ) - MedicalBusiness: URIRef # A particular physical or virtual business of an organization for medical purposes. Examples of MedicalBusiness include differents business run by health professionals. - MedicalCause: URIRef # The causative agent(s) that are responsible for the pathophysiologic process that eventually results in a medical condition, symptom or sign. In this schema, unless otherwise specified this is meant to be the proximate cause of the medical condition, symptom or sign. The proximate cause is defined as the causative agent that most directly results in the medical condition, symptom or sign. For example, the HIV virus could be considered a cause of AIDS. Or in a diagnostic context, if a patient fell and sustained a hip fracture and two days later sustained a pulmonary embolism which eventuated in a cardiac arrest, the cause of the cardiac arrest (the proximate cause) would be the pulmonary embolism and not the fall. Medical causes can include cardiovascular, chemical, dermatologic, endocrine, environmental, gastroenterologic, genetic, hematologic, gynecologic, iatrogenic, infectious, musculoskeletal, neurologic, nutritional, obstetric, oncologic, otolaryngologic, pharmacologic, psychiatric, pulmonary, renal, rheumatologic, toxic, traumatic, or urologic causes; medical conditions can be causes as well. - MedicalClinic: URIRef # A facility, often associated with a hospital or medical school, that is devoted to the specific diagnosis and/or healthcare. Previously limited to outpatients but with evolution it may be open to inpatients as well. - MedicalCode: URIRef # A code for a medical entity. - MedicalCondition: URIRef # Any condition of the human body that affects the normal functioning of a person, whether physically or mentally. Includes diseases, injuries, disabilities, disorders, syndromes, etc. - MedicalConditionStage: ( - URIRef # A stage of a medical condition, such as 'Stage IIIa'. - ) - MedicalContraindication: URIRef # A condition or factor that serves as a reason to withhold a certain medical therapy. Contraindications can be absolute (there are no reasonable circumstances for undertaking a course of action) or relative (the patient is at higher risk of complications, but that these risks may be outweighed by other considerations or mitigated by other measures). - MedicalDevice: URIRef # Any object used in a medical capacity, such as to diagnose or treat a patient. - MedicalDevicePurpose: URIRef # Categories of medical devices, organized by the purpose or intended use of the device. - MedicalEntity: URIRef # The most generic type of entity related to health and the practice of medicine. - MedicalEnumeration: URIRef # Enumerations related to health and the practice of medicine: A concept that is used to attribute a quality to another concept, as a qualifier, a collection of items or a listing of all of the elements of a set in medicine practice. - MedicalEvidenceLevel: ( - URIRef # Level of evidence for a medical guideline. Enumerated type. - ) - MedicalGuideline: URIRef # Any recommendation made by a standard society (e.g. ACC/AHA) or consensus statement that denotes how to diagnose and treat a particular condition. Note: this type should be used to tag the actual guideline recommendation; if the guideline recommendation occurs in a larger scholarly article, use MedicalScholarlyArticle to tag the overall article, not this type. Note also: the organization making the recommendation should be captured in the recognizingAuthority base property of MedicalEntity. - MedicalGuidelineContraindication: URIRef # A guideline contraindication that designates a process as harmful and where quality of the data supporting the contraindication is sound. - MedicalGuidelineRecommendation: URIRef # A guideline recommendation that is regarded as efficacious and where quality of the data supporting the recommendation is sound. - MedicalImagingTechnique: URIRef # Any medical imaging modality typically used for diagnostic purposes. Enumerated type. - MedicalIndication: URIRef # A condition or factor that indicates use of a medical therapy, including signs, symptoms, risk factors, anatomical states, etc. - MedicalIntangible: URIRef # A utility class that serves as the umbrella for a number of 'intangible' things in the medical space. - MedicalObservationalStudy: URIRef # An observational study is a type of medical study that attempts to infer the possible effect of a treatment through observation of a cohort of subjects over a period of time. In an observational study, the assignment of subjects into treatment groups versus control groups is outside the control of the investigator. This is in contrast with controlled studies, such as the randomized controlled trials represented by MedicalTrial, where each subject is randomly assigned to a treatment group or a control group before the start of the treatment. - MedicalObservationalStudyDesign: ( - URIRef # Design models for observational medical studies. Enumerated type. - ) - MedicalOrganization: URIRef # A medical organization (physical or not), such as hospital, institution or clinic. - MedicalProcedure: URIRef # A process of care used in either a diagnostic, therapeutic, preventive or palliative capacity that relies on invasive (surgical), non-invasive, or other techniques. - MedicalProcedureType: ( - URIRef # An enumeration that describes different types of medical procedures. - ) - MedicalResearcher: URIRef # Medical researchers. - MedicalRiskCalculator: URIRef # A complex mathematical calculation requiring an online calculator, used to assess prognosis. Note: use the url property of Thing to record any URLs for online calculators. - MedicalRiskEstimator: URIRef # Any rule set or interactive tool for estimating the risk of developing a complication or condition. - MedicalRiskFactor: URIRef # A risk factor is anything that increases a person's likelihood of developing or contracting a disease, medical condition, or complication. - MedicalRiskScore: URIRef # A simple system that adds up the number of risk factors to yield a score that is associated with prognosis, e.g. CHAD score, TIMI risk score. - MedicalScholarlyArticle: URIRef # A scholarly article in the medical domain. - MedicalSign: URIRef # Any physical manifestation of a person's medical condition discoverable by objective diagnostic tests or physical examination. - MedicalSignOrSymptom: URIRef # Any feature associated or not with a medical condition. In medicine a symptom is generally subjective while a sign is objective. - MedicalSpecialty: URIRef # Any specific branch of medical science or practice. Medical specialities include clinical specialties that pertain to particular organ systems and their respective disease states, as well as allied health specialties. Enumerated type. - MedicalStudy: URIRef # A medical study is an umbrella type covering all kinds of research studies relating to human medicine or health, including observational studies and interventional trials and registries, randomized, controlled or not. When the specific type of study is known, use one of the extensions of this type, such as MedicalTrial or MedicalObservationalStudy. Also, note that this type should be used to mark up data that describes the study itself; to tag an article that publishes the results of a study, use MedicalScholarlyArticle. Note: use the code property of MedicalEntity to store study IDs, e.g. clinicaltrials.gov ID. - MedicalStudyStatus: URIRef # The status of a medical study. Enumerated type. - MedicalSymptom: URIRef # Any complaint sensed and expressed by the patient (therefore defined as subjective) like stomachache, lower-back pain, or fatigue. - MedicalTest: ( - URIRef # Any medical test, typically performed for diagnostic purposes. - ) - MedicalTestPanel: URIRef # Any collection of tests commonly ordered together. - MedicalTherapy: URIRef # Any medical intervention designed to prevent, treat, and cure human diseases and medical conditions, including both curative and palliative therapies. Medical therapies are typically processes of care relying upon pharmacotherapy, behavioral therapy, supportive therapy (with fluid or nutrition for example), or detoxification (e.g. hemodialysis) aimed at improving or preventing a health condition. - MedicalTrial: URIRef # A medical trial is a type of medical study that uses scientific process used to compare the safety and efficacy of medical therapies or medical procedures. In general, medical trials are controlled and subjects are allocated at random to the different treatment and/or control groups. - MedicalTrialDesign: URIRef # Design models for medical trials. Enumerated type. - MedicalWebPage: URIRef # A web page that provides medical information. - MedicineSystem: URIRef # Systems of medical practice. - MeetingRoom: URIRef # A meeting room, conference room, or conference hall is a room provided for singular events such as business conferences and meetings (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Conference_hall).

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - MensClothingStore: URIRef # A men's clothing store. - Menu: URIRef # A structured representation of food or drink items available from a FoodEstablishment. - MenuItem: URIRef # A food or drink item listed in a menu or menu section. - MenuSection: URIRef # A sub-grouping of food or drink items in a menu. E.g. courses (such as 'Dinner', 'Breakfast', etc.), specific type of dishes (such as 'Meat', 'Vegan', 'Drinks', etc.), or some other classification made by the menu provider. - MerchantReturnEnumeration: ( - URIRef # Enumerates several kinds of product return policies. - ) - MerchantReturnFiniteReturnWindow: ( - URIRef # Specifies that there is a finite window for product returns. - ) - MerchantReturnNotPermitted: ( - URIRef # Specifies that product returns are not permitted. - ) - MerchantReturnPolicy: URIRef # A MerchantReturnPolicy provides information about product return policies associated with an [[Organization]], [[Product]], or [[Offer]]. - MerchantReturnPolicySeasonalOverride: ( - URIRef # A seasonal override of a return policy, for example used for holidays. - ) - MerchantReturnUnlimitedWindow: ( - URIRef # Specifies that there is an unlimited window for product returns. - ) - MerchantReturnUnspecified: ( - URIRef # Specifies that a product return policy is not provided. - ) - Message: ( - URIRef # A single message from a sender to one or more organizations or people. - ) - MiddleSchool: URIRef # A middle school (typically for children aged around 11-14, although this varies somewhat). - Midwifery: URIRef # A nurse-like health profession that deals with pregnancy, childbirth, and the postpartum period (including care of the newborn), besides sexual and reproductive health of women throughout their lives. - MinimumAdvertisedPrice: URIRef # Represents the minimum advertised price ("MAP") (as dictated by the manufacturer) of an offered product. - MisconceptionsHealthAspect: URIRef # Content about common misconceptions and myths that are related to a topic. - MixedEventAttendanceMode: URIRef # MixedEventAttendanceMode - an event that is conducted as a combination of both offline and online modes. - MixtapeAlbum: URIRef # MixtapeAlbum. - MobileApplication: URIRef # A software application designed specifically to work well on a mobile device such as a telephone. - MobilePhoneStore: ( - URIRef # A store that sells mobile phones and related accessories. - ) - MolecularEntity: URIRef # Any constitutionally or isotopically distinct atom, molecule, ion, ion pair, radical, radical ion, complex, conformer etc., identifiable as a separately distinguishable entity. - Monday: URIRef # The day of the week between Sunday and Tuesday. - MonetaryAmount: URIRef # A monetary value or range. This type can be used to describe an amount of money such as $50 USD, or a range as in describing a bank account being suitable for a balance between £1,000 and £1,000,000 GBP, or the value of a salary, etc. It is recommended to use [[PriceSpecification]] Types to describe the price of an Offer, Invoice, etc. - MonetaryAmountDistribution: ( - URIRef # A statistical distribution of monetary amounts. - ) - MonetaryGrant: URIRef # A monetary grant. - MoneyTransfer: URIRef # The act of transferring money from one place to another place. This may occur electronically or physically. - MortgageLoan: URIRef # A loan in which property or real estate is used as collateral. (A loan securitized against some real estate). - Mosque: URIRef # A mosque. - Motel: URIRef # A motel.

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - Motorcycle: URIRef # A motorcycle or motorbike is a single-track, two-wheeled motor vehicle. - MotorcycleDealer: URIRef # A motorcycle dealer. - MotorcycleRepair: URIRef # A motorcycle repair shop. - MotorizedBicycle: URIRef # A motorized bicycle is a bicycle with an attached motor used to power the vehicle, or to assist with pedaling. - Mountain: URIRef # A mountain, like Mount Whitney or Mount Everest. - MoveAction: URIRef # The act of an agent relocating to a place.\n\nRelated actions:\n\n* [[TransferAction]]: Unlike TransferAction, the subject of the move is a living Person or Organization rather than an inanimate object. - Movie: URIRef # A movie. - MovieClip: URIRef # A short segment/part of a movie. - MovieRentalStore: URIRef # A movie rental store. - MovieSeries: URIRef # A series of movies. Included movies can be indicated with the hasPart property. - MovieTheater: URIRef # A movie theater. - MovingCompany: URIRef # A moving company. - MultiCenterTrial: URIRef # A trial that takes place at multiple centers. - MultiPlayer: URIRef # Play mode: MultiPlayer. Requiring or allowing multiple human players to play simultaneously. - MulticellularParasite: URIRef # Multicellular parasite that causes an infection. - Muscle: URIRef # A muscle is an anatomical structure consisting of a contractile form of tissue that animals use to effect movement. - Musculoskeletal: URIRef # A specific branch of medical science that pertains to diagnosis and treatment of disorders of muscles, ligaments and skeletal system. - MusculoskeletalExam: URIRef # Musculoskeletal system clinical examination. - Museum: URIRef # A museum. - MusicAlbum: URIRef # A collection of music tracks. - MusicAlbumProductionType: URIRef # Classification of the album by it's type of content: soundtrack, live album, studio album, etc. - MusicAlbumReleaseType: ( - URIRef # The kind of release which this album is: single, EP or album. - ) - MusicComposition: URIRef # A musical composition. - MusicEvent: URIRef # Event type: Music event. - MusicGroup: URIRef # A musical group, such as a band, an orchestra, or a choir. Can also be a solo musician. - MusicPlaylist: URIRef # A collection of music tracks in playlist form. - MusicRecording: URIRef # A music recording (track), usually a single song. - MusicRelease: URIRef # A MusicRelease is a specific release of a music album. - MusicReleaseFormatType: URIRef # Format of this release (the type of recording media used, ie. compact disc, digital media, LP, etc.). - MusicStore: URIRef # A music store. - MusicVenue: URIRef # A music venue. - MusicVideoObject: URIRef # A music video file. - NGO: URIRef # Organization: Non-governmental Organization. - NLNonprofitType: URIRef # NLNonprofitType: Non-profit organization type originating from the Netherlands. - NailSalon: URIRef # A nail salon. - Neck: URIRef # Neck assessment with clinical examination. - Nerve: URIRef # A common pathway for the electrochemical nerve impulses that are transmitted along each of the axons. - Neuro: URIRef # Neurological system clinical examination. - Neurologic: URIRef # A specific branch of medical science that studies the nerves and nervous system and its respective disease states. - NewCondition: URIRef # Indicates that the item is new. - NewsArticle: URIRef # A NewsArticle is an article whose content reports news, or provides background context and supporting materials for understanding the news. A more detailed overview of [schema.org News markup](/docs/news.html) is also available. - NewsMediaOrganization: ( - URIRef # A News/Media organization such as a newspaper or TV station. - ) - Newspaper: URIRef # A publication containing information about varied topics that are pertinent to general information, a geographic area, or a specific subject matter (i.e. business, culture, education). Often published daily. - NightClub: URIRef # A nightclub or discotheque. - NoninvasiveProcedure: ( - URIRef # A type of medical procedure that involves noninvasive techniques. - ) - Nonprofit501a: URIRef # Nonprofit501a: Non-profit type referring to Farmers’ Cooperative Associations. - Nonprofit501c1: URIRef # Nonprofit501c1: Non-profit type referring to Corporations Organized Under Act of Congress, including Federal Credit Unions and National Farm Loan Associations. - Nonprofit501c10: URIRef # Nonprofit501c10: Non-profit type referring to Domestic Fraternal Societies and Associations. - Nonprofit501c11: URIRef # Nonprofit501c11: Non-profit type referring to Teachers' Retirement Fund Associations. - Nonprofit501c12: URIRef # Nonprofit501c12: Non-profit type referring to Benevolent Life Insurance Associations, Mutual Ditch or Irrigation Companies, Mutual or Cooperative Telephone Companies. - Nonprofit501c13: ( - URIRef # Nonprofit501c13: Non-profit type referring to Cemetery Companies. - ) - Nonprofit501c14: URIRef # Nonprofit501c14: Non-profit type referring to State-Chartered Credit Unions, Mutual Reserve Funds. - Nonprofit501c15: URIRef # Nonprofit501c15: Non-profit type referring to Mutual Insurance Companies or Associations. - Nonprofit501c16: URIRef # Nonprofit501c16: Non-profit type referring to Cooperative Organizations to Finance Crop Operations. - Nonprofit501c17: URIRef # Nonprofit501c17: Non-profit type referring to Supplemental Unemployment Benefit Trusts. - Nonprofit501c18: URIRef # Nonprofit501c18: Non-profit type referring to Employee Funded Pension Trust (created before 25 June 1959). - Nonprofit501c19: URIRef # Nonprofit501c19: Non-profit type referring to Post or Organization of Past or Present Members of the Armed Forces. - Nonprofit501c2: URIRef # Nonprofit501c2: Non-profit type referring to Title-holding Corporations for Exempt Organizations. - Nonprofit501c20: URIRef # Nonprofit501c20: Non-profit type referring to Group Legal Services Plan Organizations. - Nonprofit501c21: URIRef # Nonprofit501c21: Non-profit type referring to Black Lung Benefit Trusts. - Nonprofit501c22: URIRef # Nonprofit501c22: Non-profit type referring to Withdrawal Liability Payment Funds. - Nonprofit501c23: ( - URIRef # Nonprofit501c23: Non-profit type referring to Veterans Organizations. - ) - Nonprofit501c24: URIRef # Nonprofit501c24: Non-profit type referring to Section 4049 ERISA Trusts. - Nonprofit501c25: URIRef # Nonprofit501c25: Non-profit type referring to Real Property Title-Holding Corporations or Trusts with Multiple Parents. - Nonprofit501c26: URIRef # Nonprofit501c26: Non-profit type referring to State-Sponsored Organizations Providing Health Coverage for High-Risk Individuals. - Nonprofit501c27: URIRef # Nonprofit501c27: Non-profit type referring to State-Sponsored Workers' Compensation Reinsurance Organizations. - Nonprofit501c28: URIRef # Nonprofit501c28: Non-profit type referring to National Railroad Retirement Investment Trusts. - Nonprofit501c3: URIRef # Nonprofit501c3: Non-profit type referring to Religious, Educational, Charitable, Scientific, Literary, Testing for Public Safety, to Foster National or International Amateur Sports Competition, or Prevention of Cruelty to Children or Animals Organizations. - Nonprofit501c4: URIRef # Nonprofit501c4: Non-profit type referring to Civic Leagues, Social Welfare Organizations, and Local Associations of Employees. - Nonprofit501c5: URIRef # Nonprofit501c5: Non-profit type referring to Labor, Agricultural and Horticultural Organizations. - Nonprofit501c6: URIRef # Nonprofit501c6: Non-profit type referring to Business Leagues, Chambers of Commerce, Real Estate Boards. - Nonprofit501c7: URIRef # Nonprofit501c7: Non-profit type referring to Social and Recreational Clubs. - Nonprofit501c8: URIRef # Nonprofit501c8: Non-profit type referring to Fraternal Beneficiary Societies and Associations. - Nonprofit501c9: URIRef # Nonprofit501c9: Non-profit type referring to Voluntary Employee Beneficiary Associations. - Nonprofit501d: URIRef # Nonprofit501d: Non-profit type referring to Religious and Apostolic Associations. - Nonprofit501e: URIRef # Nonprofit501e: Non-profit type referring to Cooperative Hospital Service Organizations. - Nonprofit501f: URIRef # Nonprofit501f: Non-profit type referring to Cooperative Service Organizations. - Nonprofit501k: ( - URIRef # Nonprofit501k: Non-profit type referring to Child Care Organizations. - ) - Nonprofit501n: ( - URIRef # Nonprofit501n: Non-profit type referring to Charitable Risk Pools. - ) - Nonprofit501q: URIRef # Nonprofit501q: Non-profit type referring to Credit Counseling Organizations. - Nonprofit527: ( - URIRef # Nonprofit527: Non-profit type referring to Political organizations. - ) - NonprofitANBI: URIRef # NonprofitANBI: Non-profit type referring to a Public Benefit Organization (NL). - NonprofitSBBI: URIRef # NonprofitSBBI: Non-profit type referring to a Social Interest Promoting Institution (NL). - NonprofitType: URIRef # NonprofitType enumerates several kinds of official non-profit types of which a non-profit organization can be. - Nose: URIRef # Nose function assessment with clinical examination. - NotInForce: URIRef # Indicates that a legislation is currently not in force. - NotYetRecruiting: URIRef # Not yet recruiting. - Notary: URIRef # A notary. - NoteDigitalDocument: URIRef # A file containing a note, primarily for the author. - Number: URIRef # Data type: Number.\n\nUsage guidelines:\n\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - Nursing: URIRef # A health profession of a person formally educated and trained in the care of the sick or infirm person. - NutritionInformation: URIRef # Nutritional information about the recipe. - OTC: URIRef # The character of a medical substance, typically a medicine, of being available over the counter or not. - Observation: URIRef # Instances of the class [[Observation]] are used to specify observations about an entity (which may or may not be an instance of a [[StatisticalPopulation]]), at a particular time. The principal properties of an [[Observation]] are [[observedNode]], [[measuredProperty]], [[measuredValue]] (or [[median]], etc.) and [[observationDate]] ([[measuredProperty]] properties can, but need not always, be W3C RDF Data Cube "measure properties", as in the [lifeExpectancy example](https://www.w3.org/TR/vocab-data-cube/#dsd-example)). See also [[StatisticalPopulation]], and the [data and datasets](/docs/data-and-datasets.html) overview for more details. - Observational: URIRef # An observational study design. - Obstetric: URIRef # A specific branch of medical science that specializes in the care of women during the prenatal and postnatal care and with the delivery of the child. - Occupation: URIRef # A profession, may involve prolonged training and/or a formal qualification. - OccupationalActivity: URIRef # Any physical activity engaged in for job-related purposes. Examples may include waiting tables, maid service, carrying a mailbag, picking fruits or vegetables, construction work, etc. - OccupationalExperienceRequirements: URIRef # Indicates employment-related experience requirements, e.g. [[monthsOfExperience]]. - OccupationalTherapy: URIRef # A treatment of people with physical, emotional, or social problems, using purposeful activity to help them overcome or learn to deal with their problems. - OceanBodyOfWater: URIRef # An ocean (for example, the Pacific). - Offer: URIRef # An offer to transfer some rights to an item or to provide a service — for example, an offer to sell tickets to an event, to rent the DVD of a movie, to stream a TV show over the internet, to repair a motorcycle, or to loan a book.\n\nNote: As the [[businessFunction]] property, which identifies the form of offer (e.g. sell, lease, repair, dispose), defaults to http://purl.org/goodrelations/v1#Sell; an Offer without a defined businessFunction value can be assumed to be an offer to sell.\n\nFor [GTIN](http://www.gs1.org/barcodes/technical/idkeys/gtin)-related fields, see [Check Digit calculator](http://www.gs1.org/barcodes/support/check_digit_calculator) and [validation guide](http://www.gs1us.org/resources/standards/gtin-validation-guide) from [GS1](http://www.gs1.org/). - OfferCatalog: URIRef # An OfferCatalog is an ItemList that contains related Offers and/or further OfferCatalogs that are offeredBy the same provider. - OfferForLease: URIRef # An [[OfferForLease]] in Schema.org represents an [[Offer]] to lease out something, i.e. an [[Offer]] whose [[businessFunction]] is [lease out](http://purl.org/goodrelations/v1#LeaseOut.). See [Good Relations](https://en.wikipedia.org/wiki/GoodRelations) for background on the underlying concepts. - OfferForPurchase: URIRef # An [[OfferForPurchase]] in Schema.org represents an [[Offer]] to sell something, i.e. an [[Offer]] whose [[businessFunction]] is [sell](http://purl.org/goodrelations/v1#Sell.). See [Good Relations](https://en.wikipedia.org/wiki/GoodRelations) for background on the underlying concepts. - OfferItemCondition: URIRef # A list of possible conditions for the item. - OfferShippingDetails: URIRef # OfferShippingDetails represents information about shipping destinations. Multiple of these entities can be used to represent different shipping rates for different destinations: One entity for Alaska/Hawaii. A different one for continental US.A different one for all France. Multiple of these entities can be used to represent different shipping costs and delivery times. Two entities that are identical but differ in rate and time: e.g. Cheaper and slower: $5 in 5-7days or Fast and expensive: $15 in 1-2 days. - OfficeEquipmentStore: URIRef # An office equipment store. - OfficialLegalValue: URIRef # All the documents published by an official publisher should have at least the legal value level "OfficialLegalValue". This indicates that the document was published by an organisation with the public task of making it available (e.g. a consolidated version of a EU directive published by the EU Office of Publications). - OfflineEventAttendanceMode: URIRef # OfflineEventAttendanceMode - an event that is primarily conducted offline. - OfflinePermanently: URIRef # Game server status: OfflinePermanently. Server is offline and not available. - OfflineTemporarily: URIRef # Game server status: OfflineTemporarily. Server is offline now but it can be online soon. - OnDemandEvent: URIRef # A publication event e.g. catch-up TV or radio podcast, during which a program is available on-demand. - OnSitePickup: URIRef # A DeliveryMethod in which an item is collected on site, e.g. in a store or at a box office. - Oncologic: URIRef # A specific branch of medical science that deals with benign and malignant tumors, including the study of their development, diagnosis, treatment and prevention. - OneTimePayments: URIRef # OneTimePayments: this is a benefit for one-time payments for individuals. - Online: URIRef # Game server status: Online. Server is available. - OnlineEventAttendanceMode: URIRef # OnlineEventAttendanceMode - an event that is primarily conducted online. - OnlineFull: URIRef # Game server status: OnlineFull. Server is online but unavailable. The maximum number of players has reached. - OnlineOnly: URIRef # Indicates that the item is available only online. - OpenTrial: URIRef # A trial design in which the researcher knows the full details of the treatment, and so does the patient. - OpeningHoursSpecification: URIRef # A structured value providing information about the opening hours of a place or a certain service inside a place.\n\n The place is __open__ if the [[opens]] property is specified, and __closed__ otherwise.\n\nIf the value for the [[closes]] property is less than the value for the [[opens]] property then the hour range is assumed to span over the next day. - OpinionNewsArticle: URIRef # An [[OpinionNewsArticle]] is a [[NewsArticle]] that primarily expresses opinions rather than journalistic reporting of news and events. For example, a [[NewsArticle]] consisting of a column or [[Blog]]/[[BlogPosting]] entry in the Opinions section of a news publication. - Optician: URIRef # A store that sells reading glasses and similar devices for improving vision. - Optometric: URIRef # The science or practice of testing visual acuity and prescribing corrective lenses. - Order: URIRef # An order is a confirmation of a transaction (a receipt), which can contain multiple line items, each represented by an Offer that has been accepted by the customer. - OrderAction: ( - URIRef # An agent orders an object/product/service to be delivered/sent. - ) - OrderCancelled: URIRef # OrderStatus representing cancellation of an order. - OrderDelivered: URIRef # OrderStatus representing successful delivery of an order. - OrderInTransit: URIRef # OrderStatus representing that an order is in transit. - OrderItem: URIRef # An order item is a line of an order. It includes the quantity and shipping details of a bought offer. - OrderPaymentDue: URIRef # OrderStatus representing that payment is due on an order. - OrderPickupAvailable: ( - URIRef # OrderStatus representing availability of an order for pickup. - ) - OrderProblem: ( - URIRef # OrderStatus representing that there is a problem with the order. - ) - OrderProcessing: ( - URIRef # OrderStatus representing that an order is being processed. - ) - OrderReturned: URIRef # OrderStatus representing that an order has been returned. - OrderStatus: URIRef # Enumerated status values for Order. - Organization: ( - URIRef # An organization such as a school, NGO, corporation, club, etc. - ) - OrganizationRole: ( - URIRef # A subclass of Role used to describe roles within organizations. - ) - OrganizeAction: URIRef # The act of manipulating/administering/supervising/controlling one or more objects. - OriginalMediaContent: URIRef # Content coded 'as original media content' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'original': No evidence the footage has been misleadingly altered or manipulated, though it may contain false or misleading claims. For an [[ImageObject]] to be 'original': No evidence the image has been misleadingly altered or manipulated, though it may still contain false or misleading claims. For an [[ImageObject]] with embedded text to be 'original': No evidence the image has been misleadingly altered or manipulated, though it may still contain false or misleading claims. For an [[AudioObject]] to be 'original': No evidence the audio has been misleadingly altered or manipulated, though it may contain false or misleading claims. - OriginalShippingFees: URIRef # Specifies that the customer must pay the original shipping costs when returning a product. - Osteopathic: URIRef # A system of medicine focused on promoting the body's innate ability to heal itself. - Otolaryngologic: URIRef # A specific branch of medical science that is concerned with the ear, nose and throat and their respective disease states. - OutOfStock: URIRef # Indicates that the item is out of stock. - OutletStore: URIRef # An outlet store. - OverviewHealthAspect: URIRef # Overview of the content. Contains a summarized view of the topic with the most relevant information for an introduction. - OwnershipInfo: URIRef # A structured value providing information about when a certain organization or person owned a certain product. - PET: URIRef # Positron emission tomography imaging. - PaidLeave: URIRef # PaidLeave: this is a benefit for paid leave. - PaintAction: URIRef # The act of producing a painting, typically with paint and canvas as instruments. - Painting: URIRef # A painting. - PalliativeProcedure: URIRef # A medical procedure intended primarily for palliative purposes, aimed at relieving the symptoms of an underlying health condition. - Paperback: URIRef # Book format: Paperback. - ParcelDelivery: URIRef # The delivery of a parcel either via the postal service or a commercial service. - ParcelService: URIRef # A private parcel service as the delivery mode available for a certain offer.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#DHL\n* http://purl.org/goodrelations/v1#FederalExpress\n* http://purl.org/goodrelations/v1#UPS - ParentAudience: URIRef # A set of characteristics describing parents, who can be interested in viewing some content. - ParentalSupport: URIRef # ParentalSupport: this is a benefit for parental support. - Park: URIRef # A park. - ParkingFacility: URIRef # A parking lot or other parking facility. - ParkingMap: URIRef # A parking map. - PartiallyInForce: URIRef # Indicates that parts of the legislation are in force, and parts are not. - Pathology: URIRef # A specific branch of medical science that is concerned with the study of the cause, origin and nature of a disease state, including its consequences as a result of manifestation of the disease. In clinical care, the term is used to designate a branch of medicine using laboratory tests to diagnose and determine the prognostic significance of illness. - PathologyTest: URIRef # A medical test performed by a laboratory that typically involves examination of a tissue sample by a pathologist. - Patient: URIRef # A patient is any person recipient of health care services. - PatientExperienceHealthAspect: URIRef # Content about the real life experience of patients or people that have lived a similar experience about the topic. May be forums, topics, Q-and-A and related material. - PawnShop: URIRef # A shop that will buy, or lend money against the security of, personal possessions. - PayAction: URIRef # An agent pays a price to a participant. - PaymentAutomaticallyApplied: ( - URIRef # An automatic payment system is in place and will be used. - ) - PaymentCard: URIRef # A payment method using a credit, debit, store or other card to associate the payment with an account. - PaymentChargeSpecification: ( - URIRef # The costs of settling the payment using a particular payment method. - ) - PaymentComplete: URIRef # The payment has been received and processed. - PaymentDeclined: ( - URIRef # The payee received the payment, but it was declined for some reason. - ) - PaymentDue: URIRef # The payment is due, but still within an acceptable time to be received. - PaymentMethod: URIRef # A payment method is a standardized procedure for transferring the monetary amount for a purchase. Payment methods are characterized by the legal and technical structures used, and by the organization or group carrying out the transaction.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#ByBankTransferInAdvance\n* http://purl.org/goodrelations/v1#ByInvoice\n* http://purl.org/goodrelations/v1#Cash\n* http://purl.org/goodrelations/v1#CheckInAdvance\n* http://purl.org/goodrelations/v1#COD\n* http://purl.org/goodrelations/v1#DirectDebit\n* http://purl.org/goodrelations/v1#GoogleCheckout\n* http://purl.org/goodrelations/v1#PayPal\n* http://purl.org/goodrelations/v1#PaySwarm - PaymentPastDue: URIRef # The payment is due and considered late. - PaymentService: URIRef # A Service to transfer funds from a person or organization to a beneficiary person or organization. - PaymentStatusType: URIRef # A specific payment status. For example, PaymentDue, PaymentComplete, etc. - Pediatric: URIRef # A specific branch of medical science that specializes in the care of infants, children and adolescents. - PeopleAudience: URIRef # A set of characteristics belonging to people, e.g. who compose an item's target audience. - PercutaneousProcedure: URIRef # A type of medical procedure that involves percutaneous techniques, where access to organs or tissue is achieved via needle-puncture of the skin. For example, catheter-based procedures like stent delivery. - PerformAction: URIRef # The act of participating in performance arts. - PerformanceRole: URIRef # A PerformanceRole is a Role that some entity places with regard to a theatrical performance, e.g. in a Movie, TVSeries etc. - PerformingArtsTheater: URIRef # A theater or other performing art center. - PerformingGroup: ( - URIRef # A performance group, such as a band, an orchestra, or a circus. - ) - Periodical: URIRef # A publication in any medium issued in successive parts bearing numerical or chronological designations and intended, such as a magazine, scholarly journal, or newspaper to continue indefinitely.\n\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html). - Permit: URIRef # A permit issued by an organization, e.g. a parking pass. - Person: URIRef # A person (alive, dead, undead, or fictional). - PetStore: URIRef # A pet store. - Pharmacy: URIRef # A pharmacy or drugstore. - PharmacySpecialty: URIRef # The practice or art and science of preparing and dispensing drugs and medicines. - Photograph: URIRef # A photograph. - PhotographAction: ( - URIRef # The act of capturing still images of objects using a camera. - ) - PhysicalActivity: URIRef # Any bodily activity that enhances or maintains physical fitness and overall health and wellness. Includes activity that is part of daily living and routine, structured exercise, and exercise prescribed as part of a medical treatment or recovery plan. - PhysicalActivityCategory: URIRef # Categories of physical activity, organized by physiologic classification. - PhysicalExam: ( - URIRef # A type of physical examination of a patient performed by a physician. - ) - PhysicalTherapy: URIRef # A process of progressive physical care and rehabilitation aimed at improving a health condition. - Physician: URIRef # A doctor's office. - Physiotherapy: URIRef # The practice of treatment of disease, injury, or deformity by physical methods such as massage, heat treatment, and exercise rather than by drugs or surgery.. - Place: URIRef # Entities that have a somewhat fixed, physical extension. - PlaceOfWorship: URIRef # Place of worship, such as a church, synagogue, or mosque. - PlaceboControlledTrial: URIRef # A placebo-controlled trial design. - PlanAction: URIRef # The act of planning the execution of an event/task/action/reservation/plan to a future date. - PlasticSurgery: URIRef # A specific branch of medical science that pertains to therapeutic or cosmetic repair or re-formation of missing, injured or malformed tissues or body parts by manual and instrumental means. - Play: URIRef # A play is a form of literature, usually consisting of dialogue between characters, intended for theatrical performance rather than just reading. Note: A performance of a Play would be a [[TheaterEvent]] or [[BroadcastEvent]] - the *Play* being the [[workPerformed]]. - PlayAction: URIRef # The act of playing/exercising/training/performing for enjoyment, leisure, recreation, Competition or exercise.\n\nRelated actions:\n\n* [[ListenAction]]: Unlike ListenAction (which is under ConsumeAction), PlayAction refers to performing for an audience or at an event, rather than consuming music.\n* [[WatchAction]]: Unlike WatchAction (which is under ConsumeAction), PlayAction refers to showing/displaying for an audience or at an event, rather than consuming visual content. - Playground: URIRef # A playground. - Plumber: URIRef # A plumbing service. - PodcastEpisode: URIRef # A single episode of a podcast series. - PodcastSeason: URIRef # A single season of a podcast. Many podcasts do not break down into separate seasons. In that case, PodcastSeries should be used. - PodcastSeries: URIRef # A podcast is an episodic series of digital audio or video files which a user can download and listen to. - Podiatric: URIRef # Podiatry is the care of the human foot, especially the diagnosis and treatment of foot disorders. - PoliceStation: URIRef # A police station. - Pond: URIRef # A pond. - PostOffice: URIRef # A post office. - PostalAddress: URIRef # The mailing address. - PostalCodeRangeSpecification: URIRef # Indicates a range of postalcodes, usually defined as the set of valid codes between [[postalCodeBegin]] and [[postalCodeEnd]], inclusively. - Poster: URIRef # A large, usually printed placard, bill, or announcement, often illustrated, that is posted to advertise or publicize something. - PotentialActionStatus: URIRef # A description of an action that is supported. - PreOrder: URIRef # Indicates that the item is available for pre-order. - PreOrderAction: URIRef # An agent orders a (not yet released) object/product/service to be delivered/sent. - PreSale: URIRef # Indicates that the item is available for ordering and delivery before general availability. - PregnancyHealthAspect: ( - URIRef # Content discussing pregnancy-related aspects of a health topic. - ) - PrependAction: ( - URIRef # The act of inserting at the beginning if an ordered collection. - ) - Preschool: URIRef # A preschool. - PrescriptionOnly: URIRef # Available by prescription only. - PresentationDigitalDocument: ( - URIRef # A file containing slides or used for a presentation. - ) - PreventionHealthAspect: URIRef # Information about actions or measures that can be taken to avoid getting the topic or reaching a critical situation related to the topic. - PreventionIndication: ( - URIRef # An indication for preventing an underlying condition, symptom, etc. - ) - PriceComponentTypeEnumeration: URIRef # Enumerates different price components that together make up the total price for an offered product. - PriceSpecification: URIRef # A structured value representing a price or price range. Typically, only the subclasses of this type are used for markup. It is recommended to use [[MonetaryAmount]] to describe independent amounts of money such as a salary, credit card limits, etc. - PriceTypeEnumeration: URIRef # Enumerates different price types, for example list price, invoice price, and sale price. - PrimaryCare: URIRef # The medical care by a physician, or other health-care professional, who is the patient's first contact with the health-care system and who may recommend a specialist if necessary. - Prion: URIRef # A prion is an infectious agent composed of protein in a misfolded form. - Product: URIRef # Any offered product or service. For example: a pair of shoes; a concert ticket; the rental of a car; a haircut; or an episode of a TV show streamed online. - ProductCollection: URIRef # A set of products (either [[ProductGroup]]s or specific variants) that are listed together e.g. in an [[Offer]]. - ProductGroup: URIRef # A ProductGroup represents a group of [[Product]]s that vary only in certain well-described ways, such as by [[size]], [[color]], [[material]] etc. While a ProductGroup itself is not directly offered for sale, the various varying products that it represents can be. The ProductGroup serves as a prototype or template, standing in for all of the products who have an [[isVariantOf]] relationship to it. As such, properties (including additional types) can be applied to the ProductGroup to represent characteristics shared by each of the (possibly very many) variants. Properties that reference a ProductGroup are not included in this mechanism; neither are the following specific properties [[variesBy]], [[hasVariant]], [[url]]. - ProductModel: URIRef # A datasheet or vendor specification of a product (in the sense of a prototypical description). - ProfessionalService: URIRef # Original definition: "provider of professional services."\n\nThe general [[ProfessionalService]] type for local businesses was deprecated due to confusion with [[Service]]. For reference, the types that it included were: [[Dentist]], [[AccountingService]], [[Attorney]], [[Notary]], as well as types for several kinds of [[HomeAndConstructionBusiness]]: [[Electrician]], [[GeneralContractor]], [[HousePainter]], [[Locksmith]], [[Plumber]], [[RoofingContractor]]. [[LegalService]] was introduced as a more inclusive supertype of [[Attorney]]. - ProfilePage: URIRef # Web page type: Profile page. - PrognosisHealthAspect: ( - URIRef # Typical progression and happenings of life course of the topic. - ) - ProgramMembership: URIRef # Used to describe membership in a loyalty programs (e.g. "StarAliance"), traveler clubs (e.g. "AAA"), purchase clubs ("Safeway Club"), etc. - Project: URIRef # An enterprise (potentially individual but typically collaborative), planned to achieve a particular aim. Use properties from [[Organization]], [[subOrganization]]/[[parentOrganization]] to indicate project sub-structures. - PronounceableText: URIRef # Data type: PronounceableText. - Property: URIRef # A property, used to indicate attributes and relationships of some Thing; equivalent to rdf:Property. - PropertyValue: URIRef # A property-value pair, e.g. representing a feature of a product or place. Use the 'name' property for the name of the property. If there is an additional human-readable version of the value, put that into the 'description' property.\n\n Always use specific schema.org properties when a) they exist and b) you can populate them. Using PropertyValue as a substitute will typically not trigger the same effect as using the original, specific property. - PropertyValueSpecification: URIRef # A Property value specification. - Protein: URIRef # Protein is here used in its widest possible definition, as classes of amino acid based molecules. Amyloid-beta Protein in human (UniProt P05067), eukaryota (e.g. an OrthoDB group) or even a single molecule that one can point to are all of type schema:Protein. A protein can thus be a subclass of another protein, e.g. schema:Protein as a UniProt record can have multiple isoforms inside it which would also be schema:Protein. They can be imagined, synthetic, hypothetical or naturally occurring. - Protozoa: URIRef # Single-celled organism that causes an infection. - Psychiatric: URIRef # A specific branch of medical science that is concerned with the study, treatment, and prevention of mental illness, using both medical and psychological therapies. - PsychologicalTreatment: URIRef # A process of care relying upon counseling, dialogue and communication aimed at improving a mental health condition without use of drugs. - PublicHealth: URIRef # Branch of medicine that pertains to the health services to improve and protect community health, especially epidemiology, sanitation, immunization, and preventive medicine. - PublicHolidays: URIRef # This stands for any day that is a public holiday; it is a placeholder for all official public holidays in some particular location. While not technically a "day of the week", it can be used with [[OpeningHoursSpecification]]. In the context of an opening hours specification it can be used to indicate opening hours on public holidays, overriding general opening hours for the day of the week on which a public holiday occurs. - PublicSwimmingPool: URIRef # A public swimming pool. - PublicToilet: URIRef # A public toilet is a room or small building containing one or more toilets (and possibly also urinals) which is available for use by the general public, or by customers or employees of certain businesses. - PublicationEvent: URIRef # A PublicationEvent corresponds indifferently to the event of publication for a CreativeWork of any type e.g. a broadcast event, an on-demand event, a book/journal publication via a variety of delivery media. - PublicationIssue: URIRef # A part of a successively published publication such as a periodical or publication volume, often numbered, usually containing a grouping of works such as articles.\n\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html). - PublicationVolume: URIRef # A part of a successively published publication such as a periodical or multi-volume work, often numbered. It may represent a time span, such as a year.\n\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html). - Pulmonary: URIRef # A specific branch of medical science that pertains to the study of the respiratory system and its respective disease states. - QAPage: URIRef # A QAPage is a WebPage focussed on a specific Question and its Answer(s), e.g. in a question answering site or documenting Frequently Asked Questions (FAQs). - QualitativeValue: URIRef # A predefined value for a product characteristic, e.g. the power cord plug type 'US' or the garment sizes 'S', 'M', 'L', and 'XL'. - QuantitativeValue: URIRef # A point value or interval for product characteristics and other purposes. - QuantitativeValueDistribution: URIRef # A statistical distribution of values. - Quantity: URIRef # Quantities such as distance, time, mass, weight, etc. Particular instances of say Mass are entities like '3 Kg' or '4 milligrams'. - Question: URIRef # A specific question - e.g. from a user seeking answers online, or collected in a Frequently Asked Questions (FAQ) document. - Quiz: URIRef # Quiz: A test of knowledge, skills and abilities. - Quotation: URIRef # A quotation. Often but not necessarily from some written work, attributable to a real world author and - if associated with a fictional character - to any fictional Person. Use [[isBasedOn]] to link to source/origin. The [[recordedIn]] property can be used to reference a Quotation from an [[Event]]. - QuoteAction: URIRef # An agent quotes/estimates/appraises an object/product/service with a price at a location/store. - RVPark: URIRef # A place offering space for "Recreational Vehicles", Caravans, mobile homes and the like. - RadiationTherapy: URIRef # A process of care using radiation aimed at improving a health condition. - RadioBroadcastService: URIRef # A delivery service through which radio content is provided via broadcast over the air or online. - RadioChannel: URIRef # A unique instance of a radio BroadcastService on a CableOrSatelliteService lineup. - RadioClip: URIRef # A short radio program or a segment/part of a radio program. - RadioEpisode: URIRef # A radio episode which can be part of a series or season. - RadioSeason: ( - URIRef # Season dedicated to radio broadcast and associated online delivery. - ) - RadioSeries: URIRef # CreativeWorkSeries dedicated to radio broadcast and associated online delivery. - RadioStation: URIRef # A radio station. - Radiography: URIRef # Radiography is an imaging technique that uses electromagnetic radiation other than visible light, especially X-rays, to view the internal structure of a non-uniformly composed and opaque object such as the human body. - RandomizedTrial: URIRef # A randomized trial design. - Rating: ( - URIRef # A rating is an evaluation on a numeric scale, such as 1 to 5 stars. - ) - ReactAction: URIRef # The act of responding instinctively and emotionally to an object, expressing a sentiment. - ReadAction: URIRef # The act of consuming written content. - ReadPermission: URIRef # Permission to read or view the document. - RealEstateAgent: URIRef # A real-estate agent. - RealEstateListing: URIRef # A [[RealEstateListing]] is a listing that describes one or more real-estate [[Offer]]s (whose [[businessFunction]] is typically to lease out, or to sell). The [[RealEstateListing]] type itself represents the overall listing, as manifested in some [[WebPage]]. - RearWheelDriveConfiguration: URIRef # Real-wheel drive is a transmission layout where the engine drives the rear wheels. - ReceiveAction: URIRef # The act of physically/electronically taking delivery of an object that has been transferred from an origin to a destination. Reciprocal of SendAction.\n\nRelated actions:\n\n* [[SendAction]]: The reciprocal of ReceiveAction.\n* [[TakeAction]]: Unlike TakeAction, ReceiveAction does not imply that the ownership has been transfered (e.g. I can receive a package, but it does not mean the package is now mine). - Recipe: URIRef # A recipe. For dietary restrictions covered by the recipe, a few common restrictions are enumerated via [[suitableForDiet]]. The [[keywords]] property can also be used to add more detail. - Recommendation: URIRef # [[Recommendation]] is a type of [[Review]] that suggests or proposes something as the best option or best course of action. Recommendations may be for products or services, or other concrete things, as in the case of a ranked list or product guide. A [[Guide]] may list multiple recommendations for different categories. For example, in a [[Guide]] about which TVs to buy, the author may have several [[Recommendation]]s. - RecommendedDoseSchedule: URIRef # A recommended dosing schedule for a drug or supplement as prescribed or recommended by an authority or by the drug/supplement's manufacturer. Capture the recommending authority in the recognizingAuthority property of MedicalEntity. - Recruiting: URIRef # Recruiting participants. - RecyclingCenter: URIRef # A recycling center. - RefundTypeEnumeration: ( - URIRef # Enumerates several kinds of product return refund types. - ) - RefurbishedCondition: URIRef # Indicates that the item is refurbished. - RegisterAction: URIRef # The act of registering to be a user of a service, product or web page.\n\nRelated actions:\n\n* [[JoinAction]]: Unlike JoinAction, RegisterAction implies you are registering to be a user of a service, *not* a group/team of people.\n* [FollowAction]]: Unlike FollowAction, RegisterAction doesn't imply that the agent is expecting to poll for updates from the object.\n* [[SubscribeAction]]: Unlike SubscribeAction, RegisterAction doesn't imply that the agent is expecting updates from the object. - Registry: URIRef # A registry-based study design. - ReimbursementCap: URIRef # The drug's cost represents the maximum reimbursement paid by an insurer for the drug. - RejectAction: URIRef # The act of rejecting to/adopting an object.\n\nRelated actions:\n\n* [[AcceptAction]]: The antonym of RejectAction. - RelatedTopicsHealthAspect: ( - URIRef # Other prominent or relevant topics tied to the main topic. - ) - RemixAlbum: URIRef # RemixAlbum. - Renal: URIRef # A specific branch of medical science that pertains to the study of the kidneys and its respective disease states. - RentAction: URIRef # The act of giving money in return for temporary use, but not ownership, of an object such as a vehicle or property. For example, an agent rents a property from a landlord in exchange for a periodic payment. - RentalCarReservation: URIRef # A reservation for a rental car.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. - RentalVehicleUsage: URIRef # Indicates the usage of the vehicle as a rental car. - RepaymentSpecification: URIRef # A structured value representing repayment. - ReplaceAction: URIRef # The act of editing a recipient by replacing an old object with a new object. - ReplyAction: URIRef # The act of responding to a question/message asked/sent by the object. Related to [[AskAction]]\n\nRelated actions:\n\n* [[AskAction]]: Appears generally as an origin of a ReplyAction. - Report: ( - URIRef # A Report generated by governmental or non-governmental organization. - ) - ReportageNewsArticle: URIRef # The [[ReportageNewsArticle]] type is a subtype of [[NewsArticle]] representing news articles which are the result of journalistic news reporting conventions. In practice many news publishers produce a wide variety of article types, many of which might be considered a [[NewsArticle]] but not a [[ReportageNewsArticle]]. For example, opinion pieces, reviews, analysis, sponsored or satirical articles, or articles that combine several of these elements. The [[ReportageNewsArticle]] type is based on a stricter ideal for "news" as a work of journalism, with articles based on factual information either observed or verified by the author, or reported and verified from knowledgeable sources. This often includes perspectives from multiple viewpoints on a particular issue (distinguishing news reports from public relations or propaganda). News reports in the [[ReportageNewsArticle]] sense de-emphasize the opinion of the author, with commentary and value judgements typically expressed elsewhere. A [[ReportageNewsArticle]] which goes deeper into analysis can also be marked with an additional type of [[AnalysisNewsArticle]]. - ReportedDoseSchedule: URIRef # A patient-reported or observed dosing schedule for a drug or supplement. - ResearchOrganization: ( - URIRef # A Research Organization (e.g. scientific institute, research company). - ) - ResearchProject: URIRef # A Research project. - Researcher: URIRef # Researchers. - Reservation: URIRef # Describes a reservation for travel, dining or an event. Some reservations require tickets. \n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, restaurant reservations, flights, or rental cars, use [[Offer]]. - ReservationCancelled: URIRef # The status for a previously confirmed reservation that is now cancelled. - ReservationConfirmed: URIRef # The status of a confirmed reservation. - ReservationHold: URIRef # The status of a reservation on hold pending an update like credit card number or flight changes. - ReservationPackage: URIRef # A group of multiple reservations with common values for all sub-reservations. - ReservationPending: URIRef # The status of a reservation when a request has been sent, but not confirmed. - ReservationStatusType: URIRef # Enumerated status values for Reservation. - ReserveAction: URIRef # Reserving a concrete object.\n\nRelated actions:\n\n* [[ScheduleAction]]: Unlike ScheduleAction, ReserveAction reserves concrete objects (e.g. a table, a hotel) towards a time slot / spatial allocation. - Reservoir: URIRef # A reservoir of water, typically an artificially created lake, like the Lake Kariba reservoir. - Residence: URIRef # The place where a person lives. - Resort: URIRef # A resort is a place used for relaxation or recreation, attracting visitors for holidays or vacations. Resorts are places, towns or sometimes commercial establishment operated by a single company (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Resort).

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - RespiratoryTherapy: URIRef # The therapy that is concerned with the maintenance or improvement of respiratory function (as in patients with pulmonary disease). - Restaurant: URIRef # A restaurant. - RestockingFees: URIRef # Specifies that the customer must pay a restocking fee when returning a product - RestrictedDiet: URIRef # A diet restricted to certain foods or preparations for cultural, religious, health or lifestyle reasons. - ResultsAvailable: URIRef # Results are available. - ResultsNotAvailable: URIRef # Results are not available. - ResumeAction: URIRef # The act of resuming a device or application which was formerly paused (e.g. resume music playback or resume a timer). - Retail: URIRef # The drug's cost represents the retail cost of the drug. - ReturnAction: URIRef # The act of returning to the origin that which was previously received (concrete objects) or taken (ownership). - ReturnAtKiosk: URIRef # Specifies that product returns must be made at a kiosk. - ReturnByMail: URIRef # Specifies that product returns must to be done by mail. - ReturnFeesCustomerResponsibility: URIRef # Specifies that product returns must be paid for, and are the responsibility of, the customer. - ReturnFeesEnumeration: ( - URIRef # Enumerates several kinds of policies for product return fees. - ) - ReturnInStore: URIRef # Specifies that product returns must be made in a store. - ReturnLabelCustomerResponsibility: URIRef # Indicated that creating a return label is the responsibility of the customer. - ReturnLabelDownloadAndPrint: URIRef # Indicated that a return label must be downloaded and printed by the customer. - ReturnLabelInBox: URIRef # Specifies that a return label will be provided by the seller in the shipping box. - ReturnLabelSourceEnumeration: ( - URIRef # Enumerates several types of return labels for product returns. - ) - ReturnMethodEnumeration: ( - URIRef # Enumerates several types of product return methods. - ) - ReturnShippingFees: URIRef # Specifies that the customer must pay the return shipping costs when returning a product - Review: ( - URIRef # A review of an item - for example, of a restaurant, movie, or store. - ) - ReviewAction: URIRef # The act of producing a balanced opinion about the object for an audience. An agent reviews an object with participants resulting in a review. - ReviewNewsArticle: URIRef # A [[NewsArticle]] and [[CriticReview]] providing a professional critic's assessment of a service, product, performance, or artistic or literary work. - Rheumatologic: URIRef # A specific branch of medical science that deals with the study and treatment of rheumatic, autoimmune or joint diseases. - RightHandDriving: URIRef # The steering position is on the right side of the vehicle (viewed from the main direction of driving). - RisksOrComplicationsHealthAspect: URIRef # Information about the risk factors and possible complications that may follow a topic. - RiverBodyOfWater: URIRef # A river (for example, the broad majestic Shannon). - Role: URIRef # Represents additional information about a relationship or property. For example a Role can be used to say that a 'member' role linking some SportsTeam to a player occurred during a particular time period. Or that a Person's 'actor' role in a Movie was for some particular characterName. Such properties can be attached to a Role entity, which is then associated with the main entities using ordinary properties like 'member' or 'actor'.\n\nSee also [blog post](http://blog.schema.org/2014/06/introducing-role.html). - RoofingContractor: URIRef # A roofing contractor. - Room: URIRef # A room is a distinguishable space within a structure, usually separated from other spaces by interior walls. (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Room).

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - RsvpAction: URIRef # The act of notifying an event organizer as to whether you expect to attend the event. - RsvpResponseMaybe: URIRef # The invitee may or may not attend. - RsvpResponseNo: URIRef # The invitee will not attend. - RsvpResponseType: URIRef # RsvpResponseType is an enumeration type whose instances represent responding to an RSVP request. - RsvpResponseYes: URIRef # The invitee will attend. - SRP: URIRef # Represents the suggested retail price ("SRP") of an offered product. - SafetyHealthAspect: ( - URIRef # Content about the safety-related aspects of a health topic. - ) - SaleEvent: URIRef # Event type: Sales event. - SalePrice: URIRef # Represents a sale price (usually active for a limited period) of an offered product. - SatireOrParodyContent: URIRef # Content coded 'satire or parody content' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'satire or parody content': A video that was created as political or humorous commentary and is presented in that context. (Reshares of satire/parody content that do not include relevant context are more likely to fall under the “missing context†rating.) For an [[ImageObject]] to be 'satire or parody content': An image that was created as political or humorous commentary and is presented in that context. (Reshares of satire/parody content that do not include relevant context are more likely to fall under the “missing context†rating.) For an [[ImageObject]] with embedded text to be 'satire or parody content': An image that was created as political or humorous commentary and is presented in that context. (Reshares of satire/parody content that do not include relevant context are more likely to fall under the “missing context†rating.) For an [[AudioObject]] to be 'satire or parody content': Audio that was created as political or humorous commentary and is presented in that context. (Reshares of satire/parody content that do not include relevant context are more likely to fall under the “missing context†rating.) - SatiricalArticle: URIRef # An [[Article]] whose content is primarily [[satirical]](https://en.wikipedia.org/wiki/Satire) in nature, i.e. unlikely to be literally true. A satirical article is sometimes but not necessarily also a [[NewsArticle]]. [[ScholarlyArticle]]s are also sometimes satirized. - Saturday: URIRef # The day of the week between Friday and Sunday. - Schedule: URIRef # A schedule defines a repeating time period used to describe a regularly occurring [[Event]]. At a minimum a schedule will specify [[repeatFrequency]] which describes the interval between occurences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the day(s) of the week or month when the recurring event will take place, in addition to its start and end time. Schedules may also have start and end dates to indicate when they are active, e.g. to define a limited calendar of events. - ScheduleAction: URIRef # Scheduling future actions, events, or tasks.\n\nRelated actions:\n\n* [[ReserveAction]]: Unlike ReserveAction, ScheduleAction allocates future actions (e.g. an event, a task, etc) towards a time slot / spatial allocation. - ScholarlyArticle: URIRef # A scholarly article. - School: URIRef # A school. - SchoolDistrict: URIRef # A School District is an administrative area for the administration of schools. - ScreeningEvent: URIRef # A screening of a movie or other video. - ScreeningHealthAspect: ( - URIRef # Content about how to screen or further filter a topic. - ) - Sculpture: URIRef # A piece of sculpture. - SeaBodyOfWater: URIRef # A sea (for example, the Caspian sea). - SearchAction: URIRef # The act of searching for an object.\n\nRelated actions:\n\n* [[FindAction]]: SearchAction generally leads to a FindAction, but not necessarily. - SearchResultsPage: URIRef # Web page type: Search results page. - Season: URIRef # A media season e.g. tv, radio, video game etc. - Seat: URIRef # Used to describe a seat, such as a reserved seat in an event reservation. - SeatingMap: URIRef # A seating map. - SeeDoctorHealthAspect: URIRef # Information about questions that may be asked, when to see a professional, measures before seeing a doctor or content about the first consultation. - SeekToAction: URIRef # This is the [[Action]] of navigating to a specific [[startOffset]] timestamp within a [[VideoObject]], typically represented with a URL template structure. - SelfCareHealthAspect: URIRef # Self care actions or measures that can be taken to sooth, health or avoid a topic. This may be carried at home and can be carried/managed by the person itself. - SelfStorage: URIRef # A self-storage facility. - SellAction: URIRef # The act of taking money from a buyer in exchange for goods or services rendered. An agent sells an object, product, or service to a buyer for a price. Reciprocal of BuyAction. - SendAction: URIRef # The act of physically/electronically dispatching an object for transfer from an origin to a destination.Related actions:\n\n* [[ReceiveAction]]: The reciprocal of SendAction.\n* [[GiveAction]]: Unlike GiveAction, SendAction does not imply the transfer of ownership (e.g. I can send you my laptop, but I'm not necessarily giving it to you). - Series: URIRef # A Series in schema.org is a group of related items, typically but not necessarily of the same kind. See also [[CreativeWorkSeries]], [[EventSeries]]. - Service: URIRef # A service provided by an organization, e.g. delivery service, print services, etc. - ServiceChannel: URIRef # A means for accessing a service, e.g. a government office location, web site, or phone number. - ShareAction: URIRef # The act of distributing content to people for their amusement or edification. - SheetMusic: URIRef # Printed music, as opposed to performed or recorded music. - ShippingDeliveryTime: URIRef # ShippingDeliveryTime provides various pieces of information about delivery times for shipping. - ShippingRateSettings: URIRef # A ShippingRateSettings represents re-usable pieces of shipping information. It is designed for publication on an URL that may be referenced via the [[shippingSettingsLink]] property of an [[OfferShippingDetails]]. Several occurrences can be published, distinguished and matched (i.e. identified/referenced) by their different values for [[shippingLabel]]. - ShoeStore: URIRef # A shoe store. - ShoppingCenter: URIRef # A shopping center or mall. - ShortStory: URIRef # Short story or tale. A brief work of literature, usually written in narrative prose. - SideEffectsHealthAspect: ( - URIRef # Side effects that can be observed from the usage of the topic. - ) - SingleBlindedTrial: URIRef # A trial design in which the researcher knows which treatment the patient was randomly assigned to but the patient does not. - SingleCenterTrial: URIRef # A trial that takes place at a single center. - SingleFamilyResidence: URIRef # Residence type: Single-family home. - SinglePlayer: URIRef # Play mode: SinglePlayer. Which is played by a lone player. - SingleRelease: URIRef # SingleRelease. - SiteNavigationElement: URIRef # A navigation element of the page. - SizeGroupEnumeration: ( - URIRef # Enumerates common size groups for various product categories. - ) - SizeSpecification: URIRef # Size related properties of a product, typically a size code ([[name]]) and optionally a [[sizeSystem]], [[sizeGroup]], and product measurements ([[hasMeasurement]]). In addition, the intended audience can be defined through [[suggestedAge]], [[suggestedGender]], and suggested body measurements ([[suggestedMeasurement]]). - SizeSystemEnumeration: URIRef # Enumerates common size systems for different categories of products, for example "EN-13402" or "UK" for wearables or "Imperial" for screws. - SizeSystemImperial: URIRef # Imperial size system. - SizeSystemMetric: URIRef # Metric size system. - SkiResort: URIRef # A ski resort. - Skin: URIRef # Skin assessment with clinical examination. - SocialEvent: URIRef # Event type: Social event. - SocialMediaPosting: URIRef # A post to a social media platform, including blog posts, tweets, Facebook posts, etc. - SoftwareApplication: URIRef # A software application. - SoftwareSourceCode: URIRef # Computer programming source code. Example: Full (compile ready) solutions, code snippet samples, scripts, templates. - SoldOut: URIRef # Indicates that the item has sold out. - SolveMathAction: URIRef # The action that takes in a math expression and directs users to a page potentially capable of solving/simplifying that expression. - SomeProducts: ( - URIRef # A placeholder for multiple similar products of the same kind. - ) - SoundtrackAlbum: URIRef # SoundtrackAlbum. - SpeakableSpecification: URIRef # A SpeakableSpecification indicates (typically via [[xpath]] or [[cssSelector]]) sections of a document that are highlighted as particularly [[speakable]]. Instances of this type are expected to be used primarily as values of the [[speakable]] property. - SpecialAnnouncement: URIRef # A SpecialAnnouncement combines a simple date-stamped textual information update with contextualized Web links and other structured data. It represents an information update made by a locally-oriented organization, for example schools, pharmacies, healthcare providers, community groups, police, local government. For work in progress guidelines on Coronavirus-related markup see [this doc](https://docs.google.com/document/d/14ikaGCKxo50rRM7nvKSlbUpjyIk2WMQd3IkB1lItlrM/edit#). The motivating scenario for SpecialAnnouncement is the [Coronavirus pandemic](https://en.wikipedia.org/wiki/2019%E2%80%9320_coronavirus_pandemic), and the initial vocabulary is oriented to this urgent situation. Schema.org expect to improve the markup iteratively as it is deployed and as feedback emerges from use. In addition to our usual [Github entry](https://github.com/schemaorg/schemaorg/issues/2490), feedback comments can also be provided in [this document](https://docs.google.com/document/d/1fpdFFxk8s87CWwACs53SGkYv3aafSxz_DTtOQxMrBJQ/edit#). While this schema is designed to communicate urgent crisis-related information, it is not the same as an emergency warning technology like [CAP](https://en.wikipedia.org/wiki/Common_Alerting_Protocol), although there may be overlaps. The intent is to cover the kinds of everyday practical information being posted to existing websites during an emergency situation. Several kinds of information can be provided: We encourage the provision of "name", "text", "datePosted", "expires" (if appropriate), "category" and "url" as a simple baseline. It is important to provide a value for "category" where possible, most ideally as a well known URL from Wikipedia or Wikidata. In the case of the 2019-2020 Coronavirus pandemic, this should be "https://en.wikipedia.org/w/index.php?title=2019-20\_coronavirus\_pandemic" or "https://www.wikidata.org/wiki/Q81068910". For many of the possible properties, values can either be simple links or an inline description, depending on whether a summary is available. For a link, provide just the URL of the appropriate page as the property's value. For an inline description, use a [[WebContent]] type, and provide the url as a property of that, alongside at least a simple "[[text]]" summary of the page. It is unlikely that a single SpecialAnnouncement will need all of the possible properties simultaneously. We expect that in many cases the page referenced might contain more specialized structured data, e.g. contact info, [[openingHours]], [[Event]], [[FAQPage]] etc. By linking to those pages from a [[SpecialAnnouncement]] you can help make it clearer that the events are related to the situation (e.g. Coronavirus) indicated by the [[category]] property of the [[SpecialAnnouncement]]. Many [[SpecialAnnouncement]]s will relate to particular regions and to identifiable local organizations. Use [[spatialCoverage]] for the region, and [[announcementLocation]] to indicate specific [[LocalBusiness]]es and [[CivicStructure]]s. If the announcement affects both a particular region and a specific location (for example, a library closure that serves an entire region), use both [[spatialCoverage]] and [[announcementLocation]]. The [[about]] property can be used to indicate entities that are the focus of the announcement. We now recommend using [[about]] only for representing non-location entities (e.g. a [[Course]] or a [[RadioStation]]). For places, use [[announcementLocation]] and [[spatialCoverage]]. Consumers of this markup should be aware that the initial design encouraged the use of /about for locations too. The basic content of [[SpecialAnnouncement]] is similar to that of an [RSS](https://en.wikipedia.org/wiki/RSS) or [Atom](https://en.wikipedia.org/wiki/Atom_(Web_standard)) feed. For publishers without such feeds, basic feed-like information can be shared by posting [[SpecialAnnouncement]] updates in a page, e.g. using JSON-LD. For sites with Atom/RSS functionality, you can point to a feed with the [[webFeed]] property. This can be a simple URL, or an inline [[DataFeed]] object, with [[encodingFormat]] providing media type information e.g. "application/rss+xml" or "application/atom+xml". - Specialty: URIRef # Any branch of a field in which people typically develop specific expertise, usually after significant study, time, and effort. - SpeechPathology: URIRef # The scientific study and treatment of defects, disorders, and malfunctions of speech and voice, as stuttering, lisping, or lalling, and of language disturbances, as aphasia or delayed language acquisition. - SpokenWordAlbum: URIRef # SpokenWordAlbum. - SportingGoodsStore: URIRef # A sporting goods store. - SportsActivityLocation: URIRef # A sports location, such as a playing field. - SportsClub: URIRef # A sports club. - SportsEvent: URIRef # Event type: Sports event. - SportsOrganization: URIRef # Represents the collection of all sports organizations, including sports teams, governing bodies, and sports associations. - SportsTeam: URIRef # Organization: Sports team. - SpreadsheetDigitalDocument: URIRef # A spreadsheet file. - StadiumOrArena: URIRef # A stadium. - StagedContent: URIRef # Content coded 'staged content' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'staged content': A video that has been created using actors or similarly contrived. For an [[ImageObject]] to be 'staged content': An image that was created using actors or similarly contrived, such as a screenshot of a fake tweet. For an [[ImageObject]] with embedded text to be 'staged content': An image that was created using actors or similarly contrived, such as a screenshot of a fake tweet. For an [[AudioObject]] to be 'staged content': Audio that has been created using actors or similarly contrived. - StagesHealthAspect: URIRef # Stages that can be observed from a topic. - State: URIRef # A state or province of a country. - Statement: URIRef # A statement about something, for example a fun or interesting fact. If known, the main entity this statement is about, can be indicated using mainEntity. For more formal claims (e.g. in Fact Checking), consider using [[Claim]] instead. Use the [[text]] property to capture the text of the statement. - StatisticalPopulation: URIRef # A StatisticalPopulation is a set of instances of a certain given type that satisfy some set of constraints. The property [[populationType]] is used to specify the type. Any property that can be used on instances of that type can appear on the statistical population. For example, a [[StatisticalPopulation]] representing all [[Person]]s with a [[homeLocation]] of East Podunk California, would be described by applying the appropriate [[homeLocation]] and [[populationType]] properties to a [[StatisticalPopulation]] item that stands for that set of people. The properties [[numConstraints]] and [[constrainingProperty]] are used to specify which of the populations properties are used to specify the population. Note that the sense of "population" used here is the general sense of a statistical population, and does not imply that the population consists of people. For example, a [[populationType]] of [[Event]] or [[NewsArticle]] could be used. See also [[Observation]], and the [data and datasets](/docs/data-and-datasets.html) overview for more details. - StatusEnumeration: URIRef # Lists or enumerations dealing with status types. - SteeringPositionValue: URIRef # A value indicating a steering position. - Store: URIRef # A retail good store. - StoreCreditRefund: URIRef # Specifies that the customer receives a store credit as refund when returning a product - StrengthTraining: URIRef # Physical activity that is engaged in to improve muscle and bone strength. Also referred to as resistance training. - StructuredValue: URIRef # Structured values are used when the value of a property has a more complex structure than simply being a textual value or a reference to another thing. - StudioAlbum: URIRef # StudioAlbum. - SubscribeAction: URIRef # The act of forming a personal connection with someone/something (object) unidirectionally/asymmetrically to get updates pushed to.\n\nRelated actions:\n\n* [[FollowAction]]: Unlike FollowAction, SubscribeAction implies that the subscriber acts as a passive agent being constantly/actively pushed for updates.\n* [[RegisterAction]]: Unlike RegisterAction, SubscribeAction implies that the agent is interested in continuing receiving updates from the object.\n* [[JoinAction]]: Unlike JoinAction, SubscribeAction implies that the agent is interested in continuing receiving updates from the object. - Subscription: URIRef # Represents the subscription pricing component of the total price for an offered product. - Substance: URIRef # Any matter of defined composition that has discrete existence, whose origin may be biological, mineral or chemical. - SubwayStation: URIRef # A subway station. - Suite: URIRef # A suite in a hotel or other public accommodation, denotes a class of luxury accommodations, the key feature of which is multiple rooms (Source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Suite_(hotel)).

See also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations. - Sunday: URIRef # The day of the week between Saturday and Monday. - SuperficialAnatomy: URIRef # Anatomical features that can be observed by sight (without dissection), including the form and proportions of the human body as well as surface landmarks that correspond to deeper subcutaneous structures. Superficial anatomy plays an important role in sports medicine, phlebotomy, and other medical specialties as underlying anatomical structures can be identified through surface palpation. For example, during back surgery, superficial anatomy can be used to palpate and count vertebrae to find the site of incision. Or in phlebotomy, superficial anatomy can be used to locate an underlying vein; for example, the median cubital vein can be located by palpating the borders of the cubital fossa (such as the epicondyles of the humerus) and then looking for the superficial signs of the vein, such as size, prominence, ability to refill after depression, and feel of surrounding tissue support. As another example, in a subluxation (dislocation) of the glenohumeral joint, the bony structure becomes pronounced with the deltoid muscle failing to cover the glenohumeral joint allowing the edges of the scapula to be superficially visible. Here, the superficial anatomy is the visible edges of the scapula, implying the underlying dislocation of the joint (the related anatomical structure). - Surgical: URIRef # A specific branch of medical science that pertains to treating diseases, injuries and deformities by manual and instrumental means. - SurgicalProcedure: URIRef # A medical procedure involving an incision with instruments; performed for diagnose, or therapeutic purposes. - SuspendAction: URIRef # The act of momentarily pausing a device or application (e.g. pause music playback or pause a timer). - Suspended: URIRef # Suspended. - SymptomsHealthAspect: URIRef # Symptoms or related symptoms of a Topic. - Synagogue: URIRef # A synagogue. - TVClip: URIRef # A short TV program or a segment/part of a TV program. - TVEpisode: URIRef # A TV episode which can be part of a series or season. - TVSeason: URIRef # Season dedicated to TV broadcast and associated online delivery. - TVSeries: URIRef # CreativeWorkSeries dedicated to TV broadcast and associated online delivery. - Table: URIRef # A table on a Web page. - TakeAction: URIRef # The act of gaining ownership of an object from an origin. Reciprocal of GiveAction.\n\nRelated actions:\n\n* [[GiveAction]]: The reciprocal of TakeAction.\n* [[ReceiveAction]]: Unlike ReceiveAction, TakeAction implies that ownership has been transfered. - TattooParlor: URIRef # A tattoo parlor. - Taxi: URIRef # A taxi. - TaxiReservation: URIRef # A reservation for a taxi.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - TaxiService: URIRef # A service for a vehicle for hire with a driver for local travel. Fares are usually calculated based on distance traveled. - TaxiStand: URIRef # A taxi stand. - TaxiVehicleUsage: URIRef # Indicates the usage of the car as a taxi. - Taxon: URIRef # A set of organisms asserted to represent a natural cohesive biological unit. - TechArticle: URIRef # A technical article - Example: How-to (task) topics, step-by-step, procedural troubleshooting, specifications, etc. - TelevisionChannel: URIRef # A unique instance of a television BroadcastService on a CableOrSatelliteService lineup. - TelevisionStation: URIRef # A television station. - TennisComplex: URIRef # A tennis complex. - Terminated: URIRef # Terminated. - Text: URIRef # Data type: Text. - TextDigitalDocument: URIRef # A file composed primarily of text. - TheaterEvent: URIRef # Event type: Theater performance. - TheaterGroup: URIRef # A theater group or company, for example, the Royal Shakespeare Company or Druid Theatre. - Therapeutic: URIRef # A medical device used for therapeutic purposes. - TherapeuticProcedure: URIRef # A medical procedure intended primarily for therapeutic purposes, aimed at improving a health condition. - Thesis: URIRef # A thesis or dissertation document submitted in support of candidature for an academic degree or professional qualification. - Thing: URIRef # The most generic type of item. - Throat: URIRef # Throat assessment with clinical examination. - Thursday: URIRef # The day of the week between Wednesday and Friday. - Ticket: URIRef # Used to describe a ticket to an event, a flight, a bus ride, etc. - TieAction: URIRef # The act of reaching a draw in a competitive activity. - Time: URIRef # A point in time recurring on multiple days in the form hh:mm:ss[Z|(+|-)hh:mm] (see [XML schema for details](http://www.w3.org/TR/xmlschema-2/#time)). - TipAction: URIRef # The act of giving money voluntarily to a beneficiary in recognition of services rendered. - TireShop: URIRef # A tire shop. - TollFree: URIRef # The associated telephone number is toll free. - TouristAttraction: URIRef # A tourist attraction. In principle any Thing can be a [[TouristAttraction]], from a [[Mountain]] and [[LandmarksOrHistoricalBuildings]] to a [[LocalBusiness]]. This Type can be used on its own to describe a general [[TouristAttraction]], or be used as an [[additionalType]] to add tourist attraction properties to any other type. (See examples below) - TouristDestination: URIRef # A tourist destination. In principle any [[Place]] can be a [[TouristDestination]] from a [[City]], Region or [[Country]] to an [[AmusementPark]] or [[Hotel]]. This Type can be used on its own to describe a general [[TouristDestination]], or be used as an [[additionalType]] to add tourist relevant properties to any other [[Place]]. A [[TouristDestination]] is defined as a [[Place]] that contains, or is colocated with, one or more [[TouristAttraction]]s, often linked by a similar theme or interest to a particular [[touristType]]. The [UNWTO](http://www2.unwto.org/) defines Destination (main destination of a tourism trip) as the place visited that is central to the decision to take the trip. (See examples below). - TouristInformationCenter: URIRef # A tourist information center. - TouristTrip: URIRef # A tourist trip. A created itinerary of visits to one or more places of interest ([[TouristAttraction]]/[[TouristDestination]]) often linked by a similar theme, geographic area, or interest to a particular [[touristType]]. The [UNWTO](http://www2.unwto.org/) defines tourism trip as the Trip taken by visitors. (See examples below). - Toxicologic: URIRef # A specific branch of medical science that is concerned with poisons, their nature, effects and detection and involved in the treatment of poisoning. - ToyStore: URIRef # A toy store. - TrackAction: URIRef # An agent tracks an object for updates.\n\nRelated actions:\n\n* [[FollowAction]]: Unlike FollowAction, TrackAction refers to the interest on the location of innanimates objects.\n* [[SubscribeAction]]: Unlike SubscribeAction, TrackAction refers to the interest on the location of innanimate objects. - TradeAction: URIRef # The act of participating in an exchange of goods and services for monetary compensation. An agent trades an object, product or service with a participant in exchange for a one time or periodic payment. - TraditionalChinese: URIRef # A system of medicine based on common theoretical concepts that originated in China and evolved over thousands of years, that uses herbs, acupuncture, exercise, massage, dietary therapy, and other methods to treat a wide range of conditions. - TrainReservation: URIRef # A reservation for train travel.\n\nNote: This type is for information about actual reservations, e.g. in confirmation emails or HTML pages with individual confirmations of reservations. For offers of tickets, use [[Offer]]. - TrainStation: URIRef # A train station. - TrainTrip: URIRef # A trip on a commercial train line. - TransferAction: URIRef # The act of transferring/moving (abstract or concrete) animate or inanimate objects from one place to another. - TransformedContent: URIRef # Content coded 'transformed content' in a [[MediaReview]], considered in the context of how it was published or shared. For a [[VideoObject]] to be 'transformed content': or all of the video has been manipulated to transform the footage itself. This category includes using tools like the Adobe Suite to change the speed of the video, add or remove visual elements or dub audio. Deepfakes are also a subset of transformation. For an [[ImageObject]] to be transformed content': Adding or deleting visual elements to give the image a different meaning with the intention to mislead. For an [[ImageObject]] with embedded text to be 'transformed content': Adding or deleting visual elements to give the image a different meaning with the intention to mislead. For an [[AudioObject]] to be 'transformed content': Part or all of the audio has been manipulated to alter the words or sounds, or the audio has been synthetically generated, such as to create a sound-alike voice. - TransitMap: URIRef # A transit map. - TravelAction: URIRef # The act of traveling from an fromLocation to a destination by a specified mode of transport, optionally with participants. - TravelAgency: URIRef # A travel agency. - TreatmentIndication: ( - URIRef # An indication for treating an underlying condition, symptom, etc. - ) - TreatmentsHealthAspect: URIRef # Treatments or related therapies for a Topic. - Trip: URIRef # A trip or journey. An itinerary of visits to one or more places. - TripleBlindedTrial: URIRef # A trial design in which neither the researcher, the person administering the therapy nor the patient knows the details of the treatment the patient was randomly assigned to. - # True: URIRef # The boolean value true. - Tuesday: URIRef # The day of the week between Monday and Wednesday. - TypeAndQuantityNode: URIRef # A structured value indicating the quantity, unit of measurement, and business function of goods included in a bundle offer. - TypesHealthAspect: URIRef # Categorization and other types related to a topic. - UKNonprofitType: URIRef # UKNonprofitType: Non-profit organization type originating from the United Kingdom. - UKTrust: URIRef # UKTrust: Non-profit type referring to a UK trust. - URL: URIRef # Data type: URL. - USNonprofitType: URIRef # USNonprofitType: Non-profit organization type originating from the United States. - Ultrasound: URIRef # Ultrasound imaging. - UnRegisterAction: URIRef # The act of un-registering from a service.\n\nRelated actions:\n\n* [[RegisterAction]]: antonym of UnRegisterAction.\n* [[LeaveAction]]: Unlike LeaveAction, UnRegisterAction implies that you are unregistering from a service you werer previously registered, rather than leaving a team/group of people. - UnemploymentSupport: ( - URIRef # UnemploymentSupport: this is a benefit for unemployment support. - ) - UnincorporatedAssociationCharity: URIRef # UnincorporatedAssociationCharity: Non-profit type referring to a charitable company that is not incorporated (UK). - UnitPriceSpecification: URIRef # The price asked for a given offer by the respective organization or person. - UnofficialLegalValue: URIRef # Indicates that a document has no particular or special standing (e.g. a republication of a law by a private publisher). - UpdateAction: ( - URIRef # The act of managing by changing/editing the state of the object. - ) - Urologic: URIRef # A specific branch of medical science that is concerned with the diagnosis and treatment of diseases pertaining to the urinary tract and the urogenital system. - UsageOrScheduleHealthAspect: ( - URIRef # Content about how, when, frequency and dosage of a topic. - ) - UseAction: URIRef # The act of applying an object to its intended purpose. - UsedCondition: URIRef # Indicates that the item is used. - UserBlocks: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserCheckins: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserComments: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserDownloads: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserInteraction: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserLikes: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserPageVisits: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserPlays: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserPlusOnes: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - UserReview: URIRef # A review created by an end-user (e.g. consumer, purchaser, attendee etc.), in contrast with [[CriticReview]]. - UserTweets: URIRef # UserInteraction and its subtypes is an old way of talking about users interacting with pages. It is generally better to use [[Action]]-based vocabulary, alongside types such as [[Comment]]. - VeganDiet: URIRef # A diet exclusive of all animal products. - VegetarianDiet: URIRef # A diet exclusive of animal meat. - Vehicle: URIRef # A vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space. - Vein: URIRef # A type of blood vessel that specifically carries blood to the heart. - VenueMap: URIRef # A venue map (e.g. for malls, auditoriums, museums, etc.). - Vessel: URIRef # A component of the human body circulatory system comprised of an intricate network of hollow tubes that transport blood throughout the entire body. - VeterinaryCare: URIRef # A vet's office. - VideoGallery: URIRef # Web page type: Video gallery page. - VideoGame: URIRef # A video game is an electronic game that involves human interaction with a user interface to generate visual feedback on a video device. - VideoGameClip: URIRef # A short segment/part of a video game. - VideoGameSeries: URIRef # A video game series. - VideoObject: URIRef # A video file. - VideoObjectSnapshot: URIRef # A specific and exact (byte-for-byte) version of a [[VideoObject]]. Two byte-for-byte identical files, for the purposes of this type, considered identical. If they have different embedded metadata the files will differ. Different external facts about the files, e.g. creator or dateCreated that aren't represented in their actual content, do not affect this notion of identity. - ViewAction: URIRef # The act of consuming static visual content. - VinylFormat: URIRef # VinylFormat. - VirtualLocation: URIRef # An online or virtual location for attending events. For example, one may attend an online seminar or educational event. While a virtual location may be used as the location of an event, virtual locations should not be confused with physical locations in the real world. - Virus: URIRef # Pathogenic virus that causes viral infection. - VisualArtsEvent: URIRef # Event type: Visual arts event. - VisualArtwork: URIRef # A work of art that is primarily visual in character. - VitalSign: URIRef # Vital signs are measures of various physiological functions in order to assess the most basic body functions. - Volcano: URIRef # A volcano, like Fuji san. - VoteAction: URIRef # The act of expressing a preference from a fixed/finite/structured set of choices/options. - WPAdBlock: URIRef # An advertising section of the page. - WPFooter: URIRef # The footer section of the page. - WPHeader: URIRef # The header section of the page. - WPSideBar: URIRef # A sidebar section of the page. - WantAction: URIRef # The act of expressing a desire about the object. An agent wants an object. - WarrantyPromise: URIRef # A structured value representing the duration and scope of services that will be provided to a customer free of charge in case of a defect or malfunction of a product. - WarrantyScope: URIRef # A range of of services that will be provided to a customer free of charge in case of a defect or malfunction of a product.\n\nCommonly used values:\n\n* http://purl.org/goodrelations/v1#Labor-BringIn\n* http://purl.org/goodrelations/v1#PartsAndLabor-BringIn\n* http://purl.org/goodrelations/v1#PartsAndLabor-PickUp - WatchAction: URIRef # The act of consuming dynamic/moving visual content. - Waterfall: URIRef # A waterfall, like Niagara. - WearAction: URIRef # The act of dressing oneself in clothing. - WearableMeasurementBack: ( - URIRef # Measurement of the back section, for example of a jacket - ) - WearableMeasurementChestOrBust: ( - URIRef # Measurement of the chest/bust section, for example of a suit - ) - WearableMeasurementCollar: ( - URIRef # Measurement of the collar, for example of a shirt - ) - WearableMeasurementCup: URIRef # Measurement of the cup, for example of a bra - WearableMeasurementHeight: ( - URIRef # Measurement of the height, for example the heel height of a shoe - ) - WearableMeasurementHips: ( - URIRef # Measurement of the hip section, for example of a skirt - ) - WearableMeasurementInseam: URIRef # Measurement of the inseam, for example of pants - WearableMeasurementLength: URIRef # Represents the length, for example of a dress - WearableMeasurementOutsideLeg: ( - URIRef # Measurement of the outside leg, for example of pants - ) - WearableMeasurementSleeve: ( - URIRef # Measurement of the sleeve length, for example of a shirt - ) - WearableMeasurementTypeEnumeration: ( - URIRef # Enumerates common types of measurement for wearables products. - ) - WearableMeasurementWaist: ( - URIRef # Measurement of the waist section, for example of pants - ) - WearableMeasurementWidth: URIRef # Measurement of the width, for example of shoes - WearableSizeGroupBig: URIRef # Size group "Big" for wearables. - WearableSizeGroupBoys: URIRef # Size group "Boys" for wearables. - WearableSizeGroupEnumeration: URIRef # Enumerates common size groups (also known as "size types") for wearable products. - WearableSizeGroupExtraShort: URIRef # Size group "Extra Short" for wearables. - WearableSizeGroupExtraTall: URIRef # Size group "Extra Tall" for wearables. - WearableSizeGroupGirls: URIRef # Size group "Girls" for wearables. - WearableSizeGroupHusky: URIRef # Size group "Husky" (or "Stocky") for wearables. - WearableSizeGroupInfants: URIRef # Size group "Infants" for wearables. - WearableSizeGroupJuniors: URIRef # Size group "Juniors" for wearables. - WearableSizeGroupMaternity: URIRef # Size group "Maternity" for wearables. - WearableSizeGroupMens: URIRef # Size group "Mens" for wearables. - WearableSizeGroupMisses: ( - URIRef # Size group "Misses" (also known as "Missy") for wearables. - ) - WearableSizeGroupPetite: URIRef # Size group "Petite" for wearables. - WearableSizeGroupPlus: URIRef # Size group "Plus" for wearables. - WearableSizeGroupRegular: URIRef # Size group "Regular" for wearables. - WearableSizeGroupShort: URIRef # Size group "Short" for wearables. - WearableSizeGroupTall: URIRef # Size group "Tall" for wearables. - WearableSizeGroupWomens: URIRef # Size group "Womens" for wearables. - WearableSizeSystemAU: URIRef # Australian size system for wearables. - WearableSizeSystemBR: URIRef # Brazilian size system for wearables. - WearableSizeSystemCN: URIRef # Chinese size system for wearables. - WearableSizeSystemContinental: URIRef # Continental size system for wearables. - WearableSizeSystemDE: URIRef # German size system for wearables. - WearableSizeSystemEN13402: ( - URIRef # EN 13402 (joint European standard for size labelling of clothes). - ) - WearableSizeSystemEnumeration: ( - URIRef # Enumerates common size systems specific for wearable products - ) - WearableSizeSystemEurope: URIRef # European size system for wearables. - WearableSizeSystemFR: URIRef # French size system for wearables. - WearableSizeSystemGS1: URIRef # GS1 (formerly NRF) size system for wearables. - WearableSizeSystemIT: URIRef # Italian size system for wearables. - WearableSizeSystemJP: URIRef # Japanese size system for wearables. - WearableSizeSystemMX: URIRef # Mexican size system for wearables. - WearableSizeSystemUK: URIRef # United Kingdom size system for wearables. - WearableSizeSystemUS: URIRef # United States size system for wearables. - WebAPI: URIRef # An application programming interface accessible over Web/Internet technologies. - WebApplication: URIRef # Web applications. - WebContent: URIRef # WebContent is a type representing all [[WebPage]], [[WebSite]] and [[WebPageElement]] content. It is sometimes the case that detailed distinctions between Web pages, sites and their parts is not always important or obvious. The [[WebContent]] type makes it easier to describe Web-addressable content without requiring such distinctions to always be stated. (The intent is that the existing types [[WebPage]], [[WebSite]] and [[WebPageElement]] will eventually be declared as subtypes of [[WebContent]]). - WebPage: URIRef # A web page. Every web page is implicitly assumed to be declared to be of type WebPage, so the various properties about that webpage, such as breadcrumb may be used. We recommend explicit declaration if these properties are specified, but if they are found outside of an itemscope, they will be assumed to be about the page. - WebPageElement: URIRef # A web page element, like a table or an image. - WebSite: URIRef # A WebSite is a set of related web pages and other items typically served from a single web domain and accessible via URLs. - Wednesday: URIRef # The day of the week between Tuesday and Thursday. - WesternConventional: URIRef # The conventional Western system of medicine, that aims to apply the best available evidence gained from the scientific method to clinical decision making. Also known as conventional or Western medicine. - Wholesale: ( - URIRef # The drug's cost represents the wholesale acquisition cost of the drug. - ) - WholesaleStore: URIRef # A wholesale store. - WinAction: URIRef # The act of achieving victory in a competitive activity. - Winery: URIRef # A winery. - Withdrawn: URIRef # Withdrawn. - WorkBasedProgram: URIRef # A program with both an educational and employment component. Typically based at a workplace and structured around work-based learning, with the aim of instilling competencies related to an occupation. WorkBasedProgram is used to distinguish programs such as apprenticeships from school, college or other classroom based educational programs. - WorkersUnion: URIRef # A Workers Union (also known as a Labor Union, Labour Union, or Trade Union) is an organization that promotes the interests of its worker members by collectively bargaining with management, organizing, and political lobbying. - WriteAction: URIRef # The act of authoring written creative content. - WritePermission: URIRef # Permission to write or edit the document. - XPathType: URIRef # Text representing an XPath (typically but not necessarily version 1.0). - XRay: URIRef # X-ray imaging. - ZoneBoardingPolicy: URIRef # The airline boards by zones of the plane. - Zoo: URIRef # A zoo. - about: URIRef # The subject matter of the content. - abridged: URIRef # Indicates whether the book is an abridged edition. - abstract: ( - URIRef # An abstract is a short description that summarizes a [[CreativeWork]]. - ) - accelerationTime: URIRef # The time needed to accelerate the vehicle from a given start velocity to a given target velocity.\n\nTypical unit code(s): SEC for seconds\n\n* Note: There are unfortunately no standard unit codes for seconds/0..100 km/h or seconds/0..60 mph. Simply use "SEC" for seconds and indicate the velocities in the [[name]] of the [[QuantitativeValue]], or use [[valueReference]] with a [[QuantitativeValue]] of 0..60 mph or 0..100 km/h to specify the reference speeds. - acceptedAnswer: URIRef # The answer(s) that has been accepted as best, typically on a Question/Answer site. Sites vary in their selection mechanisms, e.g. drawing on community opinion and/or the view of the Question author. - acceptedOffer: URIRef # The offer(s) -- e.g., product, quantity and price combinations -- included in the order. - acceptedPaymentMethod: ( - URIRef # The payment method(s) accepted by seller for this offer. - ) - acceptsReservations: URIRef # Indicates whether a FoodEstablishment accepts reservations. Values can be Boolean, an URL at which reservations can be made or (for backwards compatibility) the strings ```Yes``` or ```No```. - accessCode: URIRef # Password, PIN, or access code needed for delivery (e.g. from a locker). - accessMode: URIRef # The human sensory perceptual system or cognitive faculty through which a person may process or perceive information. Expected values include: auditory, tactile, textual, visual, colorDependent, chartOnVisual, chemOnVisual, diagramOnVisual, mathOnVisual, musicOnVisual, textOnVisual. - accessModeSufficient: URIRef # A list of single or combined accessModes that are sufficient to understand all the intellectual content of a resource. Expected values include: auditory, tactile, textual, visual. - accessibilityAPI: URIRef # Indicates that the resource is compatible with the referenced accessibility API ([WebSchemas wiki lists possible values](http://www.w3.org/wiki/WebSchemas/Accessibility)). - accessibilityControl: URIRef # Identifies input methods that are sufficient to fully control the described resource ([WebSchemas wiki lists possible values](http://www.w3.org/wiki/WebSchemas/Accessibility)). - accessibilityFeature: URIRef # Content features of the resource, such as accessible media, alternatives and supported enhancements for accessibility ([WebSchemas wiki lists possible values](http://www.w3.org/wiki/WebSchemas/Accessibility)). - accessibilityHazard: URIRef # A characteristic of the described resource that is physiologically dangerous to some users. Related to WCAG 2.0 guideline 2.3 ([WebSchemas wiki lists possible values](http://www.w3.org/wiki/WebSchemas/Accessibility)). - accessibilitySummary: URIRef # A human-readable summary of specific accessibility features or deficiencies, consistent with the other accessibility metadata but expressing subtleties such as "short descriptions are present but long descriptions will be needed for non-visual users" or "short descriptions are present and no long descriptions are needed." - accommodationCategory: URIRef # Category of an [[Accommodation]], following real estate conventions e.g. RESO (see [PropertySubType](https://ddwiki.reso.org/display/DDW17/PropertySubType+Field), and [PropertyType](https://ddwiki.reso.org/display/DDW17/PropertyType+Field) fields for suggested values). - accommodationFloorPlan: URIRef # A floorplan of some [[Accommodation]]. - accountId: URIRef # The identifier for the account the payment will be applied to. - accountMinimumInflow: URIRef # A minimum amount that has to be paid in every month. - accountOverdraftLimit: URIRef # An overdraft is an extension of credit from a lending institution when an account reaches zero. An overdraft allows the individual to continue withdrawing money even if the account has no funds in it. Basically the bank allows people to borrow a set amount of money. - accountablePerson: ( - URIRef # Specifies the Person that is legally accountable for the CreativeWork. - ) - acquireLicensePage: URIRef # Indicates a page documenting how licenses can be purchased or otherwise acquired, for the current item. - acquiredFrom: ( - URIRef # The organization or person from which the product was acquired. - ) - acrissCode: URIRef # The ACRISS Car Classification Code is a code used by many car rental companies, for classifying vehicles. ACRISS stands for Association of Car Rental Industry Systems and Standards. - actionAccessibilityRequirement: URIRef # A set of requirements that a must be fulfilled in order to perform an Action. If more than one value is specied, fulfilling one set of requirements will allow the Action to be performed. - actionApplication: URIRef # An application that can complete the request. - actionOption: ( - URIRef # A sub property of object. The options subject to this action. - ) - actionPlatform: URIRef # The high level platform(s) where the Action can be performed for the given URL. To specify a specific application or operating system instance, use actionApplication. - actionStatus: URIRef # Indicates the current disposition of the Action. - actionableFeedbackPolicy: URIRef # For a [[NewsMediaOrganization]] or other news-related [[Organization]], a statement about public engagement activities (for news media, the newsroom’s), including involving the public - digitally or otherwise -- in coverage decisions, reporting and activities after publication. - activeIngredient: URIRef # An active ingredient, typically chemical compounds and/or biologic substances. - activityDuration: URIRef # Length of time to engage in the activity. - activityFrequency: URIRef # How often one should engage in the activity. - actor: URIRef # An actor, e.g. in tv, radio, movie, video games etc., or in an event. Actors can be associated with individual items or with a series, episode, clip. - actors: URIRef # An actor, e.g. in tv, radio, movie, video games etc. Actors can be associated with individual items or with a series, episode, clip. - addOn: URIRef # An additional offer that can only be obtained in combination with the first base offer (e.g. supplements and extensions that are available for a surcharge). - additionalName: ( - URIRef # An additional name for a Person, can be used for a middle name. - ) - additionalNumberOfGuests: URIRef # If responding yes, the number of guests who will attend in addition to the invitee. - additionalProperty: URIRef # A property-value pair representing an additional characteristics of the entitity, e.g. a product feature or another characteristic for which there is no matching property in schema.org.\n\nNote: Publishers should be aware that applications designed to use specific schema.org properties (e.g. https://schema.org/width, https://schema.org/color, https://schema.org/gtin13, ...) will typically expect such data to be provided using those properties, rather than using the generic property/value mechanism. - additionalType: URIRef # An additional type for the item, typically used for adding more specific types from external vocabularies in microdata syntax. This is a relationship between something and a class that the thing is in. In RDFa syntax, it is better to use the native RDFa syntax - the 'typeof' attribute - for multiple types. Schema.org tools may have only weaker understanding of extra types, in particular those defined externally. - additionalVariable: URIRef # Any additional component of the exercise prescription that may need to be articulated to the patient. This may include the order of exercises, the number of repetitions of movement, quantitative distance, progressions over time, etc. - address: URIRef # Physical address of the item. - addressCountry: URIRef # The country. For example, USA. You can also provide the two-letter [ISO 3166-1 alpha-2 country code](http://en.wikipedia.org/wiki/ISO_3166-1). - addressLocality: URIRef # The locality in which the street address is, and which is in the region. For example, Mountain View. - addressRegion: URIRef # The region in which the locality is, and which is in the country. For example, California or another appropriate first-level [Administrative division](https://en.wikipedia.org/wiki/List_of_administrative_divisions_by_country) - administrationRoute: ( - URIRef # A route by which this drug may be administered, e.g. 'oral'. - ) - advanceBookingRequirement: URIRef # The amount of time that is required between accepting the offer and the actual usage of the resource or service. - adverseOutcome: URIRef # A possible complication and/or side effect of this therapy. If it is known that an adverse outcome is serious (resulting in death, disability, or permanent damage; requiring hospitalization; or is otherwise life-threatening or requires immediate medical attention), tag it as a seriouseAdverseOutcome instead. - affectedBy: URIRef # Drugs that affect the test's results. - affiliation: URIRef # An organization that this person is affiliated with. For example, a school/university, a club, or a team. - afterMedia: URIRef # A media object representing the circumstances after performing this direction. - agent: URIRef # The direct performer or driver of the action (animate or inanimate). e.g. *John* wrote a book. - aggregateRating: URIRef # The overall rating, based on a collection of reviews or ratings, of the item. - aircraft: URIRef # The kind of aircraft (e.g., "Boeing 747"). - album: URIRef # A music album. - albumProductionType: URIRef # Classification of the album by it's type of content: soundtrack, live album, studio album, etc. - albumRelease: URIRef # A release of this album. - albumReleaseType: ( - URIRef # The kind of release which this album is: single, EP or album. - ) - albums: URIRef # A collection of music albums. - alcoholWarning: URIRef # Any precaution, guidance, contraindication, etc. related to consumption of alcohol while taking this drug. - algorithm: URIRef # The algorithm or rules to follow to compute the score. - alignmentType: URIRef # A category of alignment between the learning resource and the framework node. Recommended values include: 'requires', 'textComplexity', 'readingLevel', and 'educationalSubject'. - alternateName: URIRef # An alias for the item. - alternativeHeadline: URIRef # A secondary title of the CreativeWork. - alternativeOf: URIRef # Another gene which is a variation of this one. - alumni: URIRef # Alumni of an organization. - alumniOf: URIRef # An organization that the person is an alumni of. - amenityFeature: URIRef # An amenity feature (e.g. a characteristic or service) of the Accommodation. This generic property does not make a statement about whether the feature is included in an offer for the main accommodation or available at extra costs. - amount: URIRef # The amount of money. - amountOfThisGood: URIRef # The quantity of the goods included in the offer. - announcementLocation: URIRef # Indicates a specific [[CivicStructure]] or [[LocalBusiness]] associated with the SpecialAnnouncement. For example, a specific testing facility or business with special opening hours. For a larger geographic region like a quarantine of an entire region, use [[spatialCoverage]]. - annualPercentageRate: URIRef # The annual rate that is charged for borrowing (or made by investing), expressed as a single percentage number that represents the actual yearly cost of funds over the term of a loan. This includes any fees or additional costs associated with the transaction. - answerCount: URIRef # The number of answers this question has received. - answerExplanation: URIRef # A step-by-step or full explanation about Answer. Can outline how this Answer was achieved or contain more broad clarification or statement about it. - antagonist: URIRef # The muscle whose action counteracts the specified muscle. - appearance: ( - URIRef # Indicates an occurence of a [[Claim]] in some [[CreativeWork]]. - ) - applicableLocation: URIRef # The location in which the status applies. - applicantLocationRequirements: URIRef # The location(s) applicants can apply from. This is usually used for telecommuting jobs where the applicant does not need to be in a physical office. Note: This should not be used for citizenship or work visa requirements. - application: URIRef # An application that can complete the request. - applicationCategory: ( - URIRef # Type of software application, e.g. 'Game, Multimedia'. - ) - applicationContact: ( - URIRef # Contact details for further information relevant to this job posting. - ) - applicationDeadline: URIRef # The date at which the program stops collecting applications for the next enrollment cycle. - applicationStartDate: URIRef # The date at which the program begins collecting applications for the next enrollment cycle. - applicationSubCategory: ( - URIRef # Subcategory of the application, e.g. 'Arcade Game'. - ) - applicationSuite: URIRef # The name of the application suite to which the application belongs (e.g. Excel belongs to Office). - appliesToDeliveryMethod: URIRef # The delivery method(s) to which the delivery charge or payment charge specification applies. - appliesToPaymentMethod: URIRef # The payment method(s) to which the payment charge specification applies. - archiveHeld: URIRef # Collection, [fonds](https://en.wikipedia.org/wiki/Fonds), or item held, kept or maintained by an [[ArchiveOrganization]]. - archivedAt: URIRef # Indicates a page or other link involved in archival of a [[CreativeWork]]. In the case of [[MediaReview]], the items in a [[MediaReviewItem]] may often become inaccessible, but be archived by archival, journalistic, activist, or law enforcement organizations. In such cases, the referenced page may not directly publish the content. - area: ( - URIRef # The area within which users can expect to reach the broadcast service. - ) - areaServed: ( - URIRef # The geographic area where a service or offered item is provided. - ) - arrivalAirport: URIRef # The airport where the flight terminates. - arrivalBoatTerminal: URIRef # The terminal or port from which the boat arrives. - arrivalBusStop: URIRef # The stop or station from which the bus arrives. - arrivalGate: URIRef # Identifier of the flight's arrival gate. - arrivalPlatform: URIRef # The platform where the train arrives. - arrivalStation: URIRef # The station where the train trip ends. - arrivalTerminal: URIRef # Identifier of the flight's arrival terminal. - arrivalTime: URIRef # The expected arrival time. - artEdition: URIRef # The number of copies when multiple copies of a piece of artwork are produced - e.g. for a limited edition of 20 prints, 'artEdition' refers to the total number of copies (in this example "20"). - artMedium: URIRef # The material used. (e.g. Oil, Watercolour, Acrylic, Linoprint, Marble, Cyanotype, Digital, Lithograph, DryPoint, Intaglio, Pastel, Woodcut, Pencil, Mixed Media, etc.) - arterialBranch: URIRef # The branches that comprise the arterial structure. - artform: URIRef # e.g. Painting, Drawing, Sculpture, Print, Photograph, Assemblage, Collage, etc. - articleBody: URIRef # The actual body of the article. - articleSection: URIRef # Articles may belong to one or more 'sections' in a magazine or newspaper, such as Sports, Lifestyle, etc. - artist: URIRef # The primary artist for a work in a medium other than pencils or digital line art--for example, if the primary artwork is done in watercolors or digital paints. - artworkSurface: URIRef # The supporting materials for the artwork, e.g. Canvas, Paper, Wood, Board, etc. - aspect: URIRef # An aspect of medical practice that is considered on the page, such as 'diagnosis', 'treatment', 'causes', 'prognosis', 'etiology', 'epidemiology', etc. - assembly: URIRef # Library file name e.g., mscorlib.dll, system.web.dll. - assemblyVersion: ( - URIRef # Associated product/technology version. e.g., .NET Framework 4.5. - ) - assesses: URIRef # The item being described is intended to assess the competency or learning outcome defined by the referenced term. - associatedAnatomy: URIRef # The anatomy of the underlying organ system or structures associated with this entity. - associatedArticle: URIRef # A NewsArticle associated with the Media Object. - associatedClaimReview: URIRef # An associated [[ClaimReview]], related by specific common content, topic or claim. The expectation is that this property would be most typically used in cases where a single activity is conducting both claim reviews and media reviews, in which case [[relatedMediaReview]] would commonly be used on a [[ClaimReview]], while [[relatedClaimReview]] would be used on [[MediaReview]]. - associatedDisease: URIRef # Disease associated to this BioChemEntity. Such disease can be a MedicalCondition or a URL. If you want to add an evidence supporting the association, please use PropertyValue. - associatedMedia: URIRef # A media object that encodes this CreativeWork. This property is a synonym for encoding. - associatedMediaReview: URIRef # An associated [[MediaReview]], related by specific common content, topic or claim. The expectation is that this property would be most typically used in cases where a single activity is conducting both claim reviews and media reviews, in which case [[relatedMediaReview]] would commonly be used on a [[ClaimReview]], while [[relatedClaimReview]] would be used on [[MediaReview]]. - associatedPathophysiology: URIRef # If applicable, a description of the pathophysiology associated with the anatomical system, including potential abnormal changes in the mechanical, physical, and biochemical functions of the system. - associatedReview: URIRef # An associated [[Review]]. - athlete: URIRef # A person that acts as performing member of a sports team; a player as opposed to a coach. - attendee: URIRef # A person or organization attending the event. - attendees: URIRef # A person attending the event. - audience: ( - URIRef # An intended audience, i.e. a group for whom something was created. - ) - audienceType: URIRef # The target group associated with a given audience (e.g. veterans, car owners, musicians, etc.). - audio: URIRef # An embedded audio object. - authenticator: URIRef # The Organization responsible for authenticating the user's subscription. For example, many media apps require a cable/satellite provider to authenticate your subscription before playing media. - author: URIRef # The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably. - availability: URIRef # The availability of this item—for example In stock, Out of stock, Pre-order, etc. - availabilityEnds: URIRef # The end of the availability of the product or service included in the offer. - availabilityStarts: URIRef # The beginning of the availability of the product or service included in the offer. - availableAtOrFrom: URIRef # The place(s) from which the offer can be obtained (e.g. store locations). - availableChannel: URIRef # A means of accessing the service (e.g. a phone bank, a web site, a location, etc.). - availableDeliveryMethod: URIRef # The delivery method(s) available for this offer. - availableFrom: ( - URIRef # When the item is available for pickup from the store, locker, etc. - ) - availableIn: URIRef # The location in which the strength is available. - availableLanguage: URIRef # A language someone may use with or at the item, service or place. Please use one of the language codes from the [IETF BCP 47 standard](http://tools.ietf.org/html/bcp47). See also [[inLanguage]] - availableOnDevice: URIRef # Device required to run the application. Used in cases where a specific make/model is required to run the application. - availableService: URIRef # A medical service available from this provider. - availableStrength: URIRef # An available dosage strength for the drug. - availableTest: URIRef # A diagnostic test or procedure offered by this lab. - availableThrough: ( - URIRef # After this date, the item will no longer be available for pickup. - ) - award: URIRef # An award won by or for this item. - awards: URIRef # Awards won by or for this item. - awayTeam: URIRef # The away team in a sports event. - backstory: URIRef # For an [[Article]], typically a [[NewsArticle]], the backstory property provides a textual summary giving a brief explanation of why and how an article was created. In a journalistic setting this could include information about reporting process, methods, interviews, data sources, etc. - bankAccountType: URIRef # The type of a bank account. - baseSalary: ( - URIRef # The base salary of the job or of an employee in an EmployeeRole. - ) - bccRecipient: ( - URIRef # A sub property of recipient. The recipient blind copied on a message. - ) - bed: URIRef # The type of bed or beds included in the accommodation. For the single case of just one bed of a certain type, you use bed directly with a text. If you want to indicate the quantity of a certain kind of bed, use an instance of BedDetails. For more detailed information, use the amenityFeature property. - beforeMedia: URIRef # A media object representing the circumstances before performing this direction. - beneficiaryBank: URIRef # A bank or bank’s branch, financial institution or international financial institution operating the beneficiary’s bank account or releasing funds for the beneficiary. - benefits: URIRef # Description of benefits associated with the job. - benefitsSummaryUrl: URIRef # The URL that goes directly to the summary of benefits and coverage for the specific standard plan or plan variation. - bestRating: URIRef # The highest value allowed in this rating system. If bestRating is omitted, 5 is assumed. - billingAddress: URIRef # The billing address for the order. - billingDuration: URIRef # Specifies for how long this price (or price component) will be billed. Can be used, for example, to model the contractual duration of a subscription or payment plan. Type can be either a Duration or a Number (in which case the unit of measurement, for example month, is specified by the unitCode property). - billingIncrement: URIRef # This property specifies the minimal quantity and rounding increment that will be the basis for the billing. The unit of measurement is specified by the unitCode property. - billingPeriod: URIRef # The time interval used to compute the invoice. - billingStart: URIRef # Specifies after how much time this price (or price component) becomes valid and billing starts. Can be used, for example, to model a price increase after the first year of a subscription. The unit of measurement is specified by the unitCode property. - bioChemInteraction: ( - URIRef # A BioChemEntity that is known to interact with this item. - ) - bioChemSimilarity: URIRef # A similar BioChemEntity, e.g., obtained by fingerprint similarity algorithms. - biologicalRole: ( - URIRef # A role played by the BioChemEntity within a biological context. - ) - biomechnicalClass: URIRef # The biomechanical properties of the bone. - birthDate: URIRef # Date of birth. - birthPlace: URIRef # The place where the person was born. - bitrate: URIRef # The bitrate of the media object. - blogPost: URIRef # A posting that is part of this blog. - blogPosts: URIRef # Indicates a post that is part of a [[Blog]]. Note that historically, what we term a "Blog" was once known as a "weblog", and that what we term a "BlogPosting" is now often colloquially referred to as a "blog". - bloodSupply: ( - URIRef # The blood vessel that carries blood from the heart to the muscle. - ) - boardingGroup: ( - URIRef # The airline-specific indicator of boarding order / preference. - ) - boardingPolicy: URIRef # The type of boarding policy used by the airline (e.g. zone-based or group-based). - bodyLocation: URIRef # Location in the body of the anatomical structure. - bodyType: URIRef # Indicates the design and body style of the vehicle (e.g. station wagon, hatchback, etc.). - bookEdition: URIRef # The edition of the book. - bookFormat: URIRef # The format of the book. - bookingAgent: URIRef # 'bookingAgent' is an out-dated term indicating a 'broker' that serves as a booking agent. - bookingTime: URIRef # The date and time the reservation was booked. - borrower: URIRef # A sub property of participant. The person that borrows the object being lent. - box: URIRef # A box is the area enclosed by the rectangle formed by two points. The first point is the lower corner, the second point is the upper corner. A box is expressed as two points separated by a space character. - branch: URIRef # The branches that delineate from the nerve bundle. Not to be confused with [[branchOf]]. - branchCode: URIRef # A short textual code (also called "store code") that uniquely identifies a place of business. The code is typically assigned by the parentOrganization and used in structured URLs.\n\nFor example, in the URL http://www.starbucks.co.uk/store-locator/etc/detail/3047 the code "3047" is a branchCode for a particular branch. - branchOf: URIRef # The larger organization that this local business is a branch of, if any. Not to be confused with (anatomical)[[branch]]. - brand: URIRef # The brand(s) associated with a product or service, or the brand(s) maintained by an organization or business person. - breadcrumb: URIRef # A set of links that can help a user understand and navigate a website hierarchy. - breastfeedingWarning: URIRef # Any precaution, guidance, contraindication, etc. related to this drug's use by breastfeeding mothers. - broadcastAffiliateOf: ( - URIRef # The media network(s) whose content is broadcast on this station. - ) - broadcastChannelId: URIRef # The unique address by which the BroadcastService can be identified in a provider lineup. In US, this is typically a number. - broadcastDisplayName: URIRef # The name displayed in the channel guide. For many US affiliates, it is the network name. - broadcastFrequency: URIRef # The frequency used for over-the-air broadcasts. Numeric values or simple ranges e.g. 87-99. In addition a shortcut idiom is supported for frequences of AM and FM radio channels, e.g. "87 FM". - broadcastFrequencyValue: URIRef # The frequency in MHz for a particular broadcast. - broadcastOfEvent: ( - URIRef # The event being broadcast such as a sporting event or awards ceremony. - ) - broadcastServiceTier: URIRef # The type of service required to have access to the channel (e.g. Standard or Premium). - broadcastSignalModulation: URIRef # The modulation (e.g. FM, AM, etc) used by a particular broadcast service. - broadcastSubChannel: URIRef # The subchannel used for the broadcast. - broadcastTimezone: URIRef # The timezone in [ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601) for which the service bases its broadcasts - broadcaster: URIRef # The organization owning or operating the broadcast service. - broker: URIRef # An entity that arranges for an exchange between a buyer and a seller. In most cases a broker never acquires or releases ownership of a product or service involved in an exchange. If it is not clear whether an entity is a broker, seller, or buyer, the latter two terms are preferred. - browserRequirements: URIRef # Specifies browser requirements in human-readable text. For example, 'requires HTML5 support'. - busName: URIRef # The name of the bus (e.g. Bolt Express). - busNumber: URIRef # The unique identifier for the bus. - businessDays: URIRef # Days of the week when the merchant typically operates, indicated via opening hours markup. - businessFunction: URIRef # The business function (e.g. sell, lease, repair, dispose) of the offer or component of a bundle (TypeAndQuantityNode). The default is http://purl.org/goodrelations/v1#Sell. - buyer: URIRef # A sub property of participant. The participant/person/organization that bought the object. - byArtist: URIRef # The artist that performed this album or recording. - byDay: URIRef # Defines the day(s) of the week on which a recurring [[Event]] takes place. May be specified using either [[DayOfWeek]], or alternatively [[Text]] conforming to iCal's syntax for byDay recurrence rules. - byMonth: URIRef # Defines the month(s) of the year on which a recurring [[Event]] takes place. Specified as an [[Integer]] between 1-12. January is 1. - byMonthDay: URIRef # Defines the day(s) of the month on which a recurring [[Event]] takes place. Specified as an [[Integer]] between 1-31. - byMonthWeek: URIRef # Defines the week(s) of the month on which a recurring Event takes place. Specified as an Integer between 1-5. For clarity, byMonthWeek is best used in conjunction with byDay to indicate concepts like the first and third Mondays of a month. - callSign: URIRef # A [callsign](https://en.wikipedia.org/wiki/Call_sign), as used in broadcasting and radio communications to identify people, radio and TV stations, or vehicles. - calories: URIRef # The number of calories. - candidate: URIRef # A sub property of object. The candidate subject of this action. - caption: URIRef # The caption for this object. For downloadable machine formats (closed caption, subtitles etc.) use MediaObject and indicate the [[encodingFormat]]. - carbohydrateContent: URIRef # The number of grams of carbohydrates. - cargoVolume: URIRef # The available volume for cargo or luggage. For automobiles, this is usually the trunk volume.\n\nTypical unit code(s): LTR for liters, FTQ for cubic foot/feet\n\nNote: You can use [[minValue]] and [[maxValue]] to indicate ranges. - carrier: URIRef # 'carrier' is an out-dated term indicating the 'provider' for parcel delivery and flights. - carrierRequirements: URIRef # Specifies specific carrier(s) requirements for the application (e.g. an application may only work on a specific carrier network). - cashBack: URIRef # A cardholder benefit that pays the cardholder a small percentage of their net expenditures. - catalog: URIRef # A data catalog which contains this dataset. - catalogNumber: URIRef # The catalog number for the release. - category: URIRef # A category for the item. Greater signs or slashes can be used to informally indicate a category hierarchy. - causeOf: URIRef # The condition, complication, symptom, sign, etc. caused. - ccRecipient: ( - URIRef # A sub property of recipient. The recipient copied on a message. - ) - character: URIRef # Fictional person connected with a creative work. - characterAttribute: URIRef # A piece of data that represents a particular aspect of a fictional character (skill, power, character points, advantage, disadvantage). - characterName: URIRef # The name of a character played in some acting or performing role, i.e. in a PerformanceRole. - cheatCode: URIRef # Cheat codes to the game. - checkinTime: URIRef # The earliest someone may check into a lodging establishment. - checkoutTime: URIRef # The latest someone may check out of a lodging establishment. - chemicalComposition: URIRef # The chemical composition describes the identity and relative ratio of the chemical elements that make up the substance. - chemicalRole: ( - URIRef # A role played by the BioChemEntity within a chemical context. - ) - childMaxAge: URIRef # Maximal age of the child. - childMinAge: URIRef # Minimal age of the child. - childTaxon: URIRef # Closest child taxa of the taxon in question. - children: URIRef # A child of the person. - cholesterolContent: URIRef # The number of milligrams of cholesterol. - circle: URIRef # A circle is the circular region of a specified radius centered at a specified latitude and longitude. A circle is expressed as a pair followed by a radius in meters. - citation: URIRef # A citation or reference to another creative work, such as another publication, web page, scholarly article, etc. - claimInterpreter: URIRef # For a [[Claim]] interpreted from [[MediaObject]] content sed to indicate a claim contained, implied or refined from the content of a [[MediaObject]]. - claimReviewed: ( - URIRef # A short summary of the specific claims reviewed in a ClaimReview. - ) - clincalPharmacology: URIRef # Description of the absorption and elimination of drugs, including their concentration (pharmacokinetics, pK) and biological effects (pharmacodynamics, pD). - clinicalPharmacology: URIRef # Description of the absorption and elimination of drugs, including their concentration (pharmacokinetics, pK) and biological effects (pharmacodynamics, pD). - clipNumber: URIRef # Position of the clip within an ordered group of clips. - closes: URIRef # The closing hour of the place or service on the given day(s) of the week. - coach: URIRef # A person that acts in a coaching role for a sports team. - code: URIRef # A medical code for the entity, taken from a controlled vocabulary or ontology such as ICD-9, DiseasesDB, MeSH, SNOMED-CT, RxNorm, etc. - codeRepository: URIRef # Link to the repository where the un-compiled, human readable code and related code is located (SVN, github, CodePlex). - codeSampleType: URIRef # What type of code sample: full (compile ready) solution, code snippet, inline code, scripts, template. - codeValue: URIRef # A short textual code that uniquely identifies the value. - codingSystem: URIRef # The coding system, e.g. 'ICD-10'. - colleague: URIRef # A colleague of the person. - colleagues: URIRef # A colleague of the person. - collection: URIRef # A sub property of object. The collection target of the action. - collectionSize: URIRef # The number of items in the [[Collection]]. - color: URIRef # The color of the product. - colorist: URIRef # The individual who adds color to inked drawings. - comment: URIRef # Comments, typically from users. - commentCount: URIRef # The number of comments this CreativeWork (e.g. Article, Question or Answer) has received. This is most applicable to works published in Web sites with commenting system; additional comments may exist elsewhere. - commentText: URIRef # The text of the UserComment. - commentTime: URIRef # The time at which the UserComment was made. - competencyRequired: URIRef # Knowledge, skill, ability or personal attribute that must be demonstrated by a person or other entity in order to do something such as earn an Educational Occupational Credential or understand a LearningResource. - competitor: URIRef # A competitor in a sports event. - composer: URIRef # The person or organization who wrote a composition, or who is the composer of a work performed at some event. - comprisedOf: URIRef # Specifying something physically contained by something else. Typically used here for the underlying anatomical structures, such as organs, that comprise the anatomical system. - conditionsOfAccess: URIRef # Conditions that affect the availability of, or method(s) of access to, an item. Typically used for real world items such as an [[ArchiveComponent]] held by an [[ArchiveOrganization]]. This property is not suitable for use as a general Web access control mechanism. It is expressed only in natural language.\n\nFor example "Available by appointment from the Reading Room" or "Accessible only from logged-in accounts ". - confirmationNumber: ( - URIRef # A number that confirms the given order or payment has been received. - ) - connectedTo: ( - URIRef # Other anatomical structures to which this structure is connected. - ) - constrainingProperty: URIRef # Indicates a property used as a constraint to define a [[StatisticalPopulation]] with respect to the set of entities corresponding to an indicated type (via [[populationType]]). - contactOption: URIRef # An option available on this contact point (e.g. a toll-free number or support for hearing-impaired callers). - contactPoint: URIRef # A contact point for a person or organization. - contactPoints: URIRef # A contact point for a person or organization. - contactType: URIRef # A person or organization can have different contact points, for different purposes. For example, a sales contact point, a PR contact point and so on. This property is used to specify the kind of contact point. - contactlessPayment: URIRef # A secure method for consumers to purchase products or services via debit, credit or smartcards by using RFID or NFC technology. - containedIn: URIRef # The basic containment relation between a place and one that contains it. - containedInPlace: URIRef # The basic containment relation between a place and one that contains it. - containsPlace: URIRef # The basic containment relation between a place and another that it contains. - containsSeason: URIRef # A season that is part of the media series. - contentLocation: URIRef # The location depicted or described in the content. For example, the location in a photograph or painting. - contentRating: ( - URIRef # Official rating of a piece of content—for example,'MPAA PG-13'. - ) - contentReferenceTime: URIRef # The specific time described by a creative work, for works (e.g. articles, video objects etc.) that emphasise a particular moment within an Event. - contentSize: URIRef # File size in (mega/kilo) bytes. - contentType: URIRef # The supported content type(s) for an EntryPoint response. - contentUrl: URIRef # Actual bytes of the media object, for example the image file or video file. - contraindication: URIRef # A contraindication for this therapy. - contributor: URIRef # A secondary contributor to the CreativeWork or Event. - cookTime: URIRef # The time it takes to actually cook the dish, in [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601). - cookingMethod: URIRef # The method of cooking, such as Frying, Steaming, ... - copyrightHolder: ( - URIRef # The party holding the legal copyright to the CreativeWork. - ) - copyrightNotice: URIRef # Text of a notice appropriate for describing the copyright aspects of this Creative Work, ideally indicating the owner of the copyright for the Work. - copyrightYear: URIRef # The year during which the claimed copyright for the CreativeWork was first asserted. - correction: URIRef # Indicates a correction to a [[CreativeWork]], either via a [[CorrectionComment]], textually or in another document. - correctionsPolicy: URIRef # For an [[Organization]] (e.g. [[NewsMediaOrganization]]), a statement describing (in news media, the newsroom’s) disclosure and correction policy for errors. - costCategory: URIRef # The category of cost, such as wholesale, retail, reimbursement cap, etc. - costCurrency: URIRef # The currency (in 3-letter of the drug cost. See: http://en.wikipedia.org/wiki/ISO_4217. - costOrigin: URIRef # Additional details to capture the origin of the cost data. For example, 'Medicare Part B'. - costPerUnit: URIRef # The cost per unit of the drug. - countriesNotSupported: URIRef # Countries for which the application is not supported. You can also provide the two-letter ISO 3166-1 alpha-2 country code. - countriesSupported: URIRef # Countries for which the application is supported. You can also provide the two-letter ISO 3166-1 alpha-2 country code. - countryOfAssembly: URIRef # The place where the product was assembled. - countryOfLastProcessing: URIRef # The place where the item (typically [[Product]]) was last processed and tested before importation. - countryOfOrigin: URIRef # The country of origin of something, including products as well as creative works such as movie and TV content. In the case of TV and movie, this would be the country of the principle offices of the production company or individual responsible for the movie. For other kinds of [[CreativeWork]] it is difficult to provide fully general guidance, and properties such as [[contentLocation]] and [[locationCreated]] may be more applicable. In the case of products, the country of origin of the product. The exact interpretation of this may vary by context and product type, and cannot be fully enumerated here. - course: ( - URIRef # A sub property of location. The course where this action was taken. - ) - courseCode: URIRef # The identifier for the [[Course]] used by the course [[provider]] (e.g. CS101 or 6.001). - courseMode: URIRef # The medium or means of delivery of the course instance or the mode of study, either as a text label (e.g. "online", "onsite" or "blended"; "synchronous" or "asynchronous"; "full-time" or "part-time") or as a URL reference to a term from a controlled vocabulary (e.g. https://ceds.ed.gov/element/001311#Asynchronous ). - coursePrerequisites: URIRef # Requirements for taking the Course. May be completion of another [[Course]] or a textual description like "permission of instructor". Requirements may be a pre-requisite competency, referenced using [[AlignmentObject]]. - courseWorkload: URIRef # The amount of work expected of students taking the course, often provided as a figure per week or per month, and may be broken down by type. For example, "2 hours of lectures, 1 hour of lab work and 3 hours of independent study per week". - coverageEndTime: URIRef # The time when the live blog will stop covering the Event. Note that coverage may continue after the Event concludes. - coverageStartTime: URIRef # The time when the live blog will begin covering the Event. Note that coverage may begin before the Event's start time. The LiveBlogPosting may also be created before coverage begins. - creativeWorkStatus: URIRef # The status of a creative work in terms of its stage in a lifecycle. Example terms include Incomplete, Draft, Published, Obsolete. Some organizations define a set of terms for the stages of their publication lifecycle. - creator: URIRef # The creator/author of this CreativeWork. This is the same as the Author property for CreativeWork. - credentialCategory: URIRef # The category or type of credential being described, for example "degreeâ€, “certificateâ€, “badgeâ€, or more specific term. - creditText: URIRef # Text that can be used to credit person(s) and/or organization(s) associated with a published Creative Work. - creditedTo: URIRef # The group the release is credited to if different than the byArtist. For example, Red and Blue is credited to "Stefani Germanotta Band", but by Lady Gaga. - cssSelector: URIRef # A CSS selector, e.g. of a [[SpeakableSpecification]] or [[WebPageElement]]. In the latter case, multiple matches within a page can constitute a single conceptual "Web page element". - currenciesAccepted: URIRef # The currency accepted.\n\nUse standard formats: [ISO 4217 currency format](http://en.wikipedia.org/wiki/ISO_4217) e.g. "USD"; [Ticker symbol](https://en.wikipedia.org/wiki/List_of_cryptocurrencies) for cryptocurrencies e.g. "BTC"; well known names for [Local Exchange Tradings Systems](https://en.wikipedia.org/wiki/Local_exchange_trading_system) (LETS) and other currency types e.g. "Ithaca HOUR". - currency: URIRef # The currency in which the monetary amount is expressed.\n\nUse standard formats: [ISO 4217 currency format](http://en.wikipedia.org/wiki/ISO_4217) e.g. "USD"; [Ticker symbol](https://en.wikipedia.org/wiki/List_of_cryptocurrencies) for cryptocurrencies e.g. "BTC"; well known names for [Local Exchange Tradings Systems](https://en.wikipedia.org/wiki/Local_exchange_trading_system) (LETS) and other currency types e.g. "Ithaca HOUR". - currentExchangeRate: URIRef # The current price of a currency. - customer: URIRef # Party placing the order or paying the invoice. - customerRemorseReturnFees: URIRef # The type of return fees if the product is returned due to customer remorse. - customerRemorseReturnLabelSource: URIRef # The method (from an enumeration) by which the customer obtains a return shipping label for a product returned due to customer remorse. - customerRemorseReturnShippingFeesAmount: URIRef # The amount of shipping costs if a product is returned due to customer remorse. Applicable when property [[customerRemorseReturnFees]] equals [[ReturnShippingFees]]. - cutoffTime: URIRef # Order cutoff time allows merchants to describe the time after which they will no longer process orders received on that day. For orders processed after cutoff time, one day gets added to the delivery time estimate. This property is expected to be most typically used via the [[ShippingRateSettings]] publication pattern. The time is indicated using the ISO-8601 Time format, e.g. "23:30:00-05:00" would represent 6:30 pm Eastern Standard Time (EST) which is 5 hours behind Coordinated Universal Time (UTC). - cvdCollectionDate: ( - URIRef # collectiondate - Date for which patient counts are reported. - ) - cvdFacilityCounty: URIRef # Name of the County of the NHSN facility that this data record applies to. Use [[cvdFacilityId]] to identify the facility. To provide other details, [[healthcareReportingData]] can be used on a [[Hospital]] entry. - cvdFacilityId: URIRef # Identifier of the NHSN facility that this data record applies to. Use [[cvdFacilityCounty]] to indicate the county. To provide other details, [[healthcareReportingData]] can be used on a [[Hospital]] entry. - cvdNumBeds: URIRef # numbeds - HOSPITAL INPATIENT BEDS: Inpatient beds, including all staffed, licensed, and overflow (surge) beds used for inpatients. - cvdNumBedsOcc: URIRef # numbedsocc - HOSPITAL INPATIENT BED OCCUPANCY: Total number of staffed inpatient beds that are occupied. - cvdNumC19Died: URIRef # numc19died - DEATHS: Patients with suspected or confirmed COVID-19 who died in the hospital, ED, or any overflow location. - cvdNumC19HOPats: URIRef # numc19hopats - HOSPITAL ONSET: Patients hospitalized in an NHSN inpatient care location with onset of suspected or confirmed COVID-19 14 or more days after hospitalization. - cvdNumC19HospPats: URIRef # numc19hosppats - HOSPITALIZED: Patients currently hospitalized in an inpatient care location who have suspected or confirmed COVID-19. - cvdNumC19MechVentPats: URIRef # numc19mechventpats - HOSPITALIZED and VENTILATED: Patients hospitalized in an NHSN inpatient care location who have suspected or confirmed COVID-19 and are on a mechanical ventilator. - cvdNumC19OFMechVentPats: URIRef # numc19ofmechventpats - ED/OVERFLOW and VENTILATED: Patients with suspected or confirmed COVID-19 who are in the ED or any overflow location awaiting an inpatient bed and on a mechanical ventilator. - cvdNumC19OverflowPats: URIRef # numc19overflowpats - ED/OVERFLOW: Patients with suspected or confirmed COVID-19 who are in the ED or any overflow location awaiting an inpatient bed. - cvdNumICUBeds: URIRef # numicubeds - ICU BEDS: Total number of staffed inpatient intensive care unit (ICU) beds. - cvdNumICUBedsOcc: URIRef # numicubedsocc - ICU BED OCCUPANCY: Total number of staffed inpatient ICU beds that are occupied. - cvdNumTotBeds: URIRef # numtotbeds - ALL HOSPITAL BEDS: Total number of all Inpatient and outpatient beds, including all staffed,ICU, licensed, and overflow (surge) beds used for inpatients or outpatients. - cvdNumVent: URIRef # numvent - MECHANICAL VENTILATORS: Total number of ventilators available. - cvdNumVentUse: URIRef # numventuse - MECHANICAL VENTILATORS IN USE: Total number of ventilators in use. - dataFeedElement: ( - URIRef # An item within in a data feed. Data feeds may have many elements. - ) - dataset: URIRef # A dataset contained in this catalog. - datasetTimeInterval: URIRef # The range of temporal applicability of a dataset, e.g. for a 2011 census dataset, the year 2011 (in ISO 8601 time interval format). - dateCreated: URIRef # The date on which the CreativeWork was created or the item was added to a DataFeed. - dateDeleted: URIRef # The datetime the item was removed from the DataFeed. - dateIssued: URIRef # The date the ticket was issued. - dateModified: URIRef # The date on which the CreativeWork was most recently modified or when the item's entry was modified within a DataFeed. - datePosted: URIRef # Publication date of an online listing. - datePublished: URIRef # Date of first broadcast/publication. - dateRead: URIRef # The date/time at which the message has been read by the recipient if a single recipient exists. - dateReceived: ( - URIRef # The date/time the message was received if a single recipient exists. - ) - dateSent: URIRef # The date/time at which the message was sent. - dateVehicleFirstRegistered: URIRef # The date of the first registration of the vehicle with the respective public authorities. - dateline: URIRef # A [dateline](https://en.wikipedia.org/wiki/Dateline) is a brief piece of text included in news articles that describes where and when the story was written or filed though the date is often omitted. Sometimes only a placename is provided. Structured representations of dateline-related information can also be expressed more explicitly using [[locationCreated]] (which represents where a work was created e.g. where a news report was written). For location depicted or described in the content, use [[contentLocation]]. Dateline summaries are oriented more towards human readers than towards automated processing, and can vary substantially. Some examples: "BEIRUT, Lebanon, June 2.", "Paris, France", "December 19, 2017 11:43AM Reporting from Washington", "Beijing/Moscow", "QUEZON CITY, Philippines". - dayOfWeek: URIRef # The day of the week for which these opening hours are valid. - deathDate: URIRef # Date of death. - deathPlace: URIRef # The place where the person died. - defaultValue: URIRef # The default value of the input. For properties that expect a literal, the default is a literal value, for properties that expect an object, it's an ID reference to one of the current values. - deliveryAddress: URIRef # Destination address. - deliveryLeadTime: URIRef # The typical delay between the receipt of the order and the goods either leaving the warehouse or being prepared for pickup, in case the delivery method is on site pickup. - deliveryMethod: URIRef # A sub property of instrument. The method of delivery. - deliveryStatus: URIRef # New entry added as the package passes through each leg of its journey (from shipment to final delivery). - deliveryTime: URIRef # The total delay between the receipt of the order and the goods reaching the final customer. - department: URIRef # A relationship between an organization and a department of that organization, also described as an organization (allowing different urls, logos, opening hours). For example: a store with a pharmacy, or a bakery with a cafe. - departureAirport: URIRef # The airport where the flight originates. - departureBoatTerminal: URIRef # The terminal or port from which the boat departs. - departureBusStop: URIRef # The stop or station from which the bus departs. - departureGate: URIRef # Identifier of the flight's departure gate. - departurePlatform: URIRef # The platform from which the train departs. - departureStation: URIRef # The station from which the train departs. - departureTerminal: URIRef # Identifier of the flight's departure terminal. - departureTime: URIRef # The expected departure time. - dependencies: URIRef # Prerequisites needed to fulfill steps in article. - depth: URIRef # The depth of the item. - description: URIRef # A description of the item. - device: URIRef # Device required to run the application. Used in cases where a specific make/model is required to run the application. - diagnosis: URIRef # One or more alternative conditions considered in the differential diagnosis process as output of a diagnosis process. - diagram: URIRef # An image containing a diagram that illustrates the structure and/or its component substructures and/or connections with other structures. - diet: URIRef # A sub property of instrument. The diet used in this action. - dietFeatures: URIRef # Nutritional information specific to the dietary plan. May include dietary recommendations on what foods to avoid, what foods to consume, and specific alterations/deviations from the USDA or other regulatory body's approved dietary guidelines. - differentialDiagnosis: URIRef # One of a set of differential diagnoses for the condition. Specifically, a closely-related or competing diagnosis typically considered later in the cognitive process whereby this medical condition is distinguished from others most likely responsible for a similar collection of signs and symptoms to reach the most parsimonious diagnosis or diagnoses in a patient. - directApply: URIRef # Indicates whether an [[url]] that is associated with a [[JobPosting]] enables direct application for the job, via the posting website. A job posting is considered to have directApply of [[True]] if an application process for the specified job can be directly initiated via the url(s) given (noting that e.g. multiple internet domains might nevertheless be involved at an implementation level). A value of [[False]] is appropriate if there is no clear path to applying directly online for the specified job, navigating directly from the JobPosting url(s) supplied. - director: URIRef # A director of e.g. tv, radio, movie, video gaming etc. content, or of an event. Directors can be associated with individual items or with a series, episode, clip. - directors: URIRef # A director of e.g. tv, radio, movie, video games etc. content. Directors can be associated with individual items or with a series, episode, clip. - disambiguatingDescription: URIRef # A sub property of description. A short description of the item used to disambiguate from other, similar items. Information from other properties (in particular, name) may be necessary for the description to be useful for disambiguation. - discount: URIRef # Any discount applied (to an Order). - discountCode: URIRef # Code used to redeem a discount. - discountCurrency: URIRef # The currency of the discount.\n\nUse standard formats: [ISO 4217 currency format](http://en.wikipedia.org/wiki/ISO_4217) e.g. "USD"; [Ticker symbol](https://en.wikipedia.org/wiki/List_of_cryptocurrencies) for cryptocurrencies e.g. "BTC"; well known names for [Local Exchange Tradings Systems](https://en.wikipedia.org/wiki/Local_exchange_trading_system) (LETS) and other currency types e.g. "Ithaca HOUR". - discusses: URIRef # Specifies the CreativeWork associated with the UserComment. - discussionUrl: ( - URIRef # A link to the page containing the comments of the CreativeWork. - ) - diseasePreventionInfo: URIRef # Information about disease prevention. - diseaseSpreadStatistics: URIRef # Statistical information about the spread of a disease, either as [[WebContent]], or described directly as a [[Dataset]], or the specific [[Observation]]s in the dataset. When a [[WebContent]] URL is provided, the page indicated might also contain more such markup. - dissolutionDate: URIRef # The date that this organization was dissolved. - distance: URIRef # The distance travelled, e.g. exercising or travelling. - distinguishingSign: URIRef # One of a set of signs and symptoms that can be used to distinguish this diagnosis from others in the differential diagnosis. - distribution: URIRef # A downloadable form of this dataset, at a specific location, in a specific format. - diversityPolicy: URIRef # Statement on diversity policy by an [[Organization]] e.g. a [[NewsMediaOrganization]]. For a [[NewsMediaOrganization]], a statement describing the newsroom’s diversity policy on both staffing and sources, typically providing staffing data. - diversityStaffingReport: URIRef # For an [[Organization]] (often but not necessarily a [[NewsMediaOrganization]]), a report on staffing diversity issues. In a news context this might be for example ASNE or RTDNA (US) reports, or self-reported. - documentation: ( - URIRef # Further documentation describing the Web API in more detail. - ) - doesNotShip: URIRef # Indicates when shipping to a particular [[shippingDestination]] is not available. - domainIncludes: URIRef # Relates a property to a class that is (one of) the type(s) the property is expected to be used on. - domiciledMortgage: URIRef # Whether borrower is a resident of the jurisdiction where the property is located. - doorTime: URIRef # The time admission will commence. - dosageForm: URIRef # A dosage form in which this drug/supplement is available, e.g. 'tablet', 'suspension', 'injection'. - doseSchedule: URIRef # A dosing schedule for the drug for a given population, either observed, recommended, or maximum dose based on the type used. - doseUnit: URIRef # The unit of the dose, e.g. 'mg'. - doseValue: URIRef # The value of the dose, e.g. 500. - downPayment: URIRef # a type of payment made in cash during the onset of the purchase of an expensive good/service. The payment typically represents only a percentage of the full purchase price. - downloadUrl: URIRef # If the file can be downloaded, URL to download the binary. - downvoteCount: URIRef # The number of downvotes this question, answer or comment has received from the community. - drainsTo: URIRef # The vasculature that the vein drains into. - driveWheelConfiguration: URIRef # The drive wheel configuration, i.e. which roadwheels will receive torque from the vehicle's engine via the drivetrain. - dropoffLocation: URIRef # Where a rental car can be dropped off. - dropoffTime: URIRef # When a rental car can be dropped off. - drug: URIRef # Specifying a drug or medicine used in a medication procedure. - drugClass: URIRef # The class of drug this belongs to (e.g., statins). - drugUnit: URIRef # The unit in which the drug is measured, e.g. '5 mg tablet'. - duns: URIRef # The Dun & Bradstreet DUNS number for identifying an organization or business person. - duplicateTherapy: URIRef # A therapy that duplicates or overlaps this one. - duration: URIRef # The duration of the item (movie, audio recording, event, etc.) in [ISO 8601 date format](http://en.wikipedia.org/wiki/ISO_8601). - durationOfWarranty: URIRef # The duration of the warranty promise. Common unitCode values are ANN for year, MON for months, or DAY for days. - duringMedia: URIRef # A media object representing the circumstances while performing this direction. - earlyPrepaymentPenalty: URIRef # The amount to be paid as a penalty in the event of early payment of the loan. - editEIDR: URIRef # An [EIDR](https://eidr.org/) (Entertainment Identifier Registry) [[identifier]] representing a specific edit / edition for a work of film or television. For example, the motion picture known as "Ghostbusters" whose [[titleEIDR]] is "10.5240/7EC7-228A-510A-053E-CBB8-J", has several edits e.g. "10.5240/1F2A-E1C5-680A-14C6-E76B-I" and "10.5240/8A35-3BEE-6497-5D12-9E4F-3". Since schema.org types like [[Movie]] and [[TVEpisode]] can be used for both works and their multiple expressions, it is possible to use [[titleEIDR]] alone (for a general description), or alongside [[editEIDR]] for a more edit-specific description. - editor: URIRef # Specifies the Person who edited the CreativeWork. - eduQuestionType: URIRef # For questions that are part of learning resources (e.g. Quiz), eduQuestionType indicates the format of question being given. Example: "Multiple choice", "Open ended", "Flashcard". - educationRequirements: ( - URIRef # Educational background needed for the position or Occupation. - ) - educationalAlignment: URIRef # An alignment to an established educational framework. This property should not be used where the nature of the alignment can be described using a simple property, for example to express that a resource [[teaches]] or [[assesses]] a competency. - educationalCredentialAwarded: URIRef # A description of the qualification, award, certificate, diploma or other educational credential awarded as a consequence of successful completion of this course or program. - educationalFramework: ( - URIRef # The framework to which the resource being described is aligned. - ) - educationalLevel: URIRef # The level in terms of progression through an educational or training context. Examples of educational levels include 'beginner', 'intermediate' or 'advanced', and formal sets of level indicators. - educationalProgramMode: URIRef # Similar to courseMode, The medium or means of delivery of the program as a whole. The value may either be a text label (e.g. "online", "onsite" or "blended"; "synchronous" or "asynchronous"; "full-time" or "part-time") or a URL reference to a term from a controlled vocabulary (e.g. https://ceds.ed.gov/element/001311#Asynchronous ). - educationalRole: URIRef # An educationalRole of an EducationalAudience. - educationalUse: URIRef # The purpose of a work in the context of education; for example, 'assignment', 'group work'. - elevation: URIRef # The elevation of a location ([WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System)). Values may be of the form 'NUMBER UNIT_OF_MEASUREMENT' (e.g., '1,000 m', '3,200 ft') while numbers alone should be assumed to be a value in meters. - eligibilityToWorkRequirement: URIRef # The legal requirements such as citizenship, visa and other documentation required for an applicant to this job. - eligibleCustomerType: ( - URIRef # The type(s) of customers for which the given offer is valid. - ) - eligibleDuration: URIRef # The duration for which the given offer is valid. - eligibleQuantity: URIRef # The interval and unit of measurement of ordering quantities for which the offer or price specification is valid. This allows e.g. specifying that a certain freight charge is valid only for a certain quantity. - eligibleRegion: URIRef # The ISO 3166-1 (ISO 3166-1 alpha-2) or ISO 3166-2 code, the place, or the GeoShape for the geo-political region(s) for which the offer or delivery charge specification is valid.\n\nSee also [[ineligibleRegion]]. - eligibleTransactionVolume: URIRef # The transaction volume, in a monetary unit, for which the offer or price specification is valid, e.g. for indicating a minimal purchasing volume, to express free shipping above a certain order volume, or to limit the acceptance of credit cards to purchases to a certain minimal amount. - email: URIRef # Email address. - embedUrl: URIRef # A URL pointing to a player for a specific video. In general, this is the information in the ```src``` element of an ```embed``` tag and should not be the same as the content of the ```loc``` tag. - embeddedTextCaption: URIRef # Represents textual captioning from a [[MediaObject]], e.g. text of a 'meme'. - emissionsCO2: URIRef # The CO2 emissions in g/km. When used in combination with a QuantitativeValue, put "g/km" into the unitText property of that value, since there is no UN/CEFACT Common Code for "g/km". - employee: URIRef # Someone working for this organization. - employees: URIRef # People working for this organization. - employerOverview: URIRef # A description of the employer, career opportunities and work environment for this position. - employmentType: URIRef # Type of employment (e.g. full-time, part-time, contract, temporary, seasonal, internship). - employmentUnit: URIRef # Indicates the department, unit and/or facility where the employee reports and/or in which the job is to be performed. - encodesBioChemEntity: URIRef # Another BioChemEntity encoded by this one. - encodesCreativeWork: URIRef # The CreativeWork encoded by this media object. - encoding: URIRef # A media object that encodes this CreativeWork. This property is a synonym for associatedMedia. - encodingFormat: URIRef # Media type typically expressed using a MIME format (see [IANA site](http://www.iana.org/assignments/media-types/media-types.xhtml) and [MDN reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)) e.g. application/zip for a SoftwareApplication binary, audio/mpeg for .mp3 etc.). In cases where a [[CreativeWork]] has several media type representations, [[encoding]] can be used to indicate each [[MediaObject]] alongside particular [[encodingFormat]] information. Unregistered or niche encoding and file formats can be indicated instead via the most appropriate URL, e.g. defining Web page or a Wikipedia/Wikidata entry. - encodingType: URIRef # The supported encoding type(s) for an EntryPoint request. - encodings: URIRef # A media object that encodes this CreativeWork. - endDate: URIRef # The end date and time of the item (in [ISO 8601 date format](http://en.wikipedia.org/wiki/ISO_8601)). - endOffset: URIRef # The end time of the clip expressed as the number of seconds from the beginning of the work. - endTime: URIRef # The endTime of something. For a reserved event or service (e.g. FoodEstablishmentReservation), the time that it is expected to end. For actions that span a period of time, when the action was performed. e.g. John wrote a book from January to *December*. For media, including audio and video, it's the time offset of the end of a clip within a larger file.\n\nNote that Event uses startDate/endDate instead of startTime/endTime, even when describing dates with times. This situation may be clarified in future revisions. - endorsee: URIRef # A sub property of participant. The person/organization being supported. - endorsers: URIRef # People or organizations that endorse the plan. - energyEfficiencyScaleMax: URIRef # Specifies the most energy efficient class on the regulated EU energy consumption scale for the product category a product belongs to. For example, energy consumption for televisions placed on the market after January 1, 2020 is scaled from D to A+++. - energyEfficiencyScaleMin: URIRef # Specifies the least energy efficient class on the regulated EU energy consumption scale for the product category a product belongs to. For example, energy consumption for televisions placed on the market after January 1, 2020 is scaled from D to A+++. - engineDisplacement: URIRef # The volume swept by all of the pistons inside the cylinders of an internal combustion engine in a single movement. \n\nTypical unit code(s): CMQ for cubic centimeter, LTR for liters, INQ for cubic inches\n* Note 1: You can link to information about how the given value has been determined using the [[valueReference]] property.\n* Note 2: You can use [[minValue]] and [[maxValue]] to indicate ranges. - enginePower: URIRef # The power of the vehicle's engine. Typical unit code(s): KWT for kilowatt, BHP for brake horsepower, N12 for metric horsepower (PS, with 1 PS = 735,49875 W)\n\n* Note 1: There are many different ways of measuring an engine's power. For an overview, see [http://en.wikipedia.org/wiki/Horsepower#Engine_power_test_codes](http://en.wikipedia.org/wiki/Horsepower#Engine_power_test_codes).\n* Note 2: You can link to information about how the given value has been determined using the [[valueReference]] property.\n* Note 3: You can use [[minValue]] and [[maxValue]] to indicate ranges. - engineType: URIRef # The type of engine or engines powering the vehicle. - entertainmentBusiness: URIRef # A sub property of location. The entertainment business where the action occurred. - epidemiology: URIRef # The characteristics of associated patients, such as age, gender, race etc. - episode: ( - URIRef # An episode of a tv, radio or game media within a series or season. - ) - episodeNumber: ( - URIRef # Position of the episode within an ordered group of episodes. - ) - episodes: URIRef # An episode of a TV/radio series or season. - equal: URIRef # This ordering relation for qualitative values indicates that the subject is equal to the object. - error: URIRef # For failed actions, more information on the cause of the failure. - estimatedCost: URIRef # The estimated cost of the supply or supplies consumed when performing instructions. - estimatedFlightDuration: URIRef # The estimated time the flight will take. - estimatedSalary: URIRef # An estimated salary for a job posting or occupation, based on a variety of variables including, but not limited to industry, job title, and location. Estimated salaries are often computed by outside organizations rather than the hiring organization, who may not have committed to the estimated value. - estimatesRiskOf: ( - URIRef # The condition, complication, or symptom whose risk is being estimated. - ) - ethicsPolicy: URIRef # Statement about ethics policy, e.g. of a [[NewsMediaOrganization]] regarding journalistic and publishing practices, or of a [[Restaurant]], a page describing food source policies. In the case of a [[NewsMediaOrganization]], an ethicsPolicy is typically a statement describing the personal, organizational, and corporate standards of behavior expected by the organization. - event: URIRef # Upcoming or past event associated with this place, organization, or action. - eventAttendanceMode: URIRef # The eventAttendanceMode of an event indicates whether it occurs online, offline, or a mix. - eventSchedule: URIRef # Associates an [[Event]] with a [[Schedule]]. There are circumstances where it is preferable to share a schedule for a series of repeating events rather than data on the individual events themselves. For example, a website or application might prefer to publish a schedule for a weekly gym class rather than provide data on every event. A schedule could be processed by applications to add forthcoming events to a calendar. An [[Event]] that is associated with a [[Schedule]] using this property should not have [[startDate]] or [[endDate]] properties. These are instead defined within the associated [[Schedule]], this avoids any ambiguity for clients using the data. The property might have repeated values to specify different schedules, e.g. for different months or seasons. - eventStatus: URIRef # An eventStatus of an event represents its status; particularly useful when an event is cancelled or rescheduled. - events: ( - URIRef # Upcoming or past events associated with this place or organization. - ) - evidenceLevel: URIRef # Strength of evidence of the data used to formulate the guideline (enumerated). - evidenceOrigin: URIRef # Source of the data used to formulate the guidance, e.g. RCT, consensus opinion, etc. - exampleOfWork: URIRef # A creative work that this work is an example/instance/realization/derivation of. - exceptDate: URIRef # Defines a [[Date]] or [[DateTime]] during which a scheduled [[Event]] will not take place. The property allows exceptions to a [[Schedule]] to be specified. If an exception is specified as a [[DateTime]] then only the event that would have started at that specific date and time should be excluded from the schedule. If an exception is specified as a [[Date]] then any event that is scheduled for that 24 hour period should be excluded from the schedule. This allows a whole day to be excluded from the schedule without having to itemise every scheduled event. - exchangeRateSpread: URIRef # The difference between the price at which a broker or other intermediary buys and sells foreign currency. - executableLibraryName: ( - URIRef # Library file name e.g., mscorlib.dll, system.web.dll. - ) - exerciseCourse: ( - URIRef # A sub property of location. The course where this action was taken. - ) - exercisePlan: ( - URIRef # A sub property of instrument. The exercise plan used on this action. - ) - exerciseRelatedDiet: ( - URIRef # A sub property of instrument. The diet used in this action. - ) - exerciseType: URIRef # Type(s) of exercise or activity, such as strength training, flexibility training, aerobics, cardiac rehabilitation, etc. - exifData: URIRef # exif data for this object. - expectedArrivalFrom: URIRef # The earliest date the package may arrive. - expectedArrivalUntil: URIRef # The latest date the package may arrive. - expectedPrognosis: URIRef # The likely outcome in either the short term or long term of the medical condition. - expectsAcceptanceOf: URIRef # An Offer which must be accepted before the user can perform the Action. For example, the user may need to buy a movie before being able to watch it. - experienceInPlaceOfEducation: URIRef # Indicates whether a [[JobPosting]] will accept experience (as indicated by [[OccupationalExperienceRequirements]]) in place of its formal educational qualifications (as indicated by [[educationRequirements]]). If true, indicates that satisfying one of these requirements is sufficient. - experienceRequirements: URIRef # Description of skills and experience needed for the position or Occupation. - expertConsiderations: URIRef # Medical expert advice related to the plan. - expires: URIRef # Date the content expires and is no longer useful or available. For example a [[VideoObject]] or [[NewsArticle]] whose availability or relevance is time-limited, or a [[ClaimReview]] fact check whose publisher wants to indicate that it may no longer be relevant (or helpful to highlight) after some date. - expressedIn: URIRef # Tissue, organ, biological sample, etc in which activity of this gene has been observed experimentally. For example brain, digestive system. - familyName: URIRef # Family name. In the U.S., the last name of a Person. - fatContent: URIRef # The number of grams of fat. - faxNumber: URIRef # The fax number. - featureList: URIRef # Features or modules provided by this application (and possibly required by other applications). - feesAndCommissionsSpecification: URIRef # Description of fees, commissions, and other terms applied either to a class of financial product, or by a financial service organization. - fiberContent: URIRef # The number of grams of fiber. - fileFormat: URIRef # Media type, typically MIME format (see [IANA site](http://www.iana.org/assignments/media-types/media-types.xhtml)) of the content e.g. application/zip of a SoftwareApplication binary. In cases where a CreativeWork has several media type representations, 'encoding' can be used to indicate each MediaObject alongside particular fileFormat information. Unregistered or niche file formats can be indicated instead via the most appropriate URL, e.g. defining Web page or a Wikipedia entry. - fileSize: URIRef # Size of the application / package (e.g. 18MB). In the absence of a unit (MB, KB etc.), KB will be assumed. - financialAidEligible: URIRef # A financial aid type or program which students may use to pay for tuition or fees associated with the program. - firstAppearance: URIRef # Indicates the first known occurence of a [[Claim]] in some [[CreativeWork]]. - firstPerformance: URIRef # The date and place the work was first performed. - flightDistance: URIRef # The distance of the flight. - flightNumber: URIRef # The unique identifier for a flight including the airline IATA code. For example, if describing United flight 110, where the IATA code for United is 'UA', the flightNumber is 'UA110'. - floorLevel: URIRef # The floor level for an [[Accommodation]] in a multi-storey building. Since counting systems [vary internationally](https://en.wikipedia.org/wiki/Storey#Consecutive_number_floor_designations), the local system should be used where possible. - floorLimit: URIRef # A floor limit is the amount of money above which credit card transactions must be authorized. - floorSize: URIRef # The size of the accommodation, e.g. in square meter or squarefoot. Typical unit code(s): MTK for square meter, FTK for square foot, or YDK for square yard - followee: ( - URIRef # A sub property of object. The person or organization being followed. - ) - follows: URIRef # The most generic uni-directional social relation. - followup: ( - URIRef # Typical or recommended followup care after the procedure is performed. - ) - foodEstablishment: URIRef # A sub property of location. The specific food establishment where the action occurred. - foodEvent: URIRef # A sub property of location. The specific food event where the action occurred. - foodWarning: URIRef # Any precaution, guidance, contraindication, etc. related to consumption of specific foods while taking this drug. - founder: URIRef # A person who founded this organization. - founders: URIRef # A person who founded this organization. - foundingDate: URIRef # The date that this organization was founded. - foundingLocation: URIRef # The place where the Organization was founded. - free: URIRef # A flag to signal that the item, event, or place is accessible for free. - freeShippingThreshold: URIRef # A monetary value above which (or equal to) the shipping rate becomes free. Intended to be used via an [[OfferShippingDetails]] with [[shippingSettingsLink]] matching this [[ShippingRateSettings]]. - frequency: URIRef # How often the dose is taken, e.g. 'daily'. - fromLocation: URIRef # A sub property of location. The original location of the object or the agent before the action. - fuelCapacity: URIRef # The capacity of the fuel tank or in the case of electric cars, the battery. If there are multiple components for storage, this should indicate the total of all storage of the same type.\n\nTypical unit code(s): LTR for liters, GLL of US gallons, GLI for UK / imperial gallons, AMH for ampere-hours (for electrical vehicles). - fuelConsumption: URIRef # The amount of fuel consumed for traveling a particular distance or temporal duration with the given vehicle (e.g. liters per 100 km).\n\n* Note 1: There are unfortunately no standard unit codes for liters per 100 km. Use [[unitText]] to indicate the unit of measurement, e.g. L/100 km.\n* Note 2: There are two ways of indicating the fuel consumption, [[fuelConsumption]] (e.g. 8 liters per 100 km) and [[fuelEfficiency]] (e.g. 30 miles per gallon). They are reciprocal.\n* Note 3: Often, the absolute value is useful only when related to driving speed ("at 80 km/h") or usage pattern ("city traffic"). You can use [[valueReference]] to link the value for the fuel consumption to another value. - fuelEfficiency: URIRef # The distance traveled per unit of fuel used; most commonly miles per gallon (mpg) or kilometers per liter (km/L).\n\n* Note 1: There are unfortunately no standard unit codes for miles per gallon or kilometers per liter. Use [[unitText]] to indicate the unit of measurement, e.g. mpg or km/L.\n* Note 2: There are two ways of indicating the fuel consumption, [[fuelConsumption]] (e.g. 8 liters per 100 km) and [[fuelEfficiency]] (e.g. 30 miles per gallon). They are reciprocal.\n* Note 3: Often, the absolute value is useful only when related to driving speed ("at 80 km/h") or usage pattern ("city traffic"). You can use [[valueReference]] to link the value for the fuel economy to another value. - fuelType: URIRef # The type of fuel suitable for the engine or engines of the vehicle. If the vehicle has only one engine, this property can be attached directly to the vehicle. - functionalClass: URIRef # The degree of mobility the joint allows. - fundedItem: URIRef # Indicates an item funded or sponsored through a [[Grant]]. - funder: URIRef # A person or organization that supports (sponsors) something through some kind of financial contribution. - game: URIRef # Video game which is played on this server. - gameItem: URIRef # An item is an object within the game world that can be collected by a player or, occasionally, a non-player character. - gameLocation: URIRef # Real or fictional location of the game (or part of game). - gamePlatform: URIRef # The electronic systems used to play video games. - gameServer: URIRef # The server on which it is possible to play the game. - gameTip: URIRef # Links to tips, tactics, etc. - gender: URIRef # Gender of something, typically a [[Person]], but possibly also fictional characters, animals, etc. While https://schema.org/Male and https://schema.org/Female may be used, text strings are also acceptable for people who do not identify as a binary gender. The [[gender]] property can also be used in an extended sense to cover e.g. the gender of sports teams. As with the gender of individuals, we do not try to enumerate all possibilities. A mixed-gender [[SportsTeam]] can be indicated with a text value of "Mixed". - genre: URIRef # Genre of the creative work, broadcast channel or group. - geo: URIRef # The geo coordinates of the place. - geoContains: URIRef # Represents a relationship between two geometries (or the places they represent), relating a containing geometry to a contained geometry. "a contains b iff no points of b lie in the exterior of a, and at least one point of the interior of b lies in the interior of a". As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoCoveredBy: URIRef # Represents a relationship between two geometries (or the places they represent), relating a geometry to another that covers it. As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoCovers: URIRef # Represents a relationship between two geometries (or the places they represent), relating a covering geometry to a covered geometry. "Every point of b is a point of (the interior or boundary of) a". As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoCrosses: URIRef # Represents a relationship between two geometries (or the places they represent), relating a geometry to another that crosses it: "a crosses b: they have some but not all interior points in common, and the dimension of the intersection is less than that of at least one of them". As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoDisjoint: URIRef # Represents spatial relations in which two geometries (or the places they represent) are topologically disjoint: they have no point in common. They form a set of disconnected geometries." (a symmetric relationship, as defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM)) - geoEquals: URIRef # Represents spatial relations in which two geometries (or the places they represent) are topologically equal, as defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). "Two geometries are topologically equal if their interiors intersect and no part of the interior or boundary of one geometry intersects the exterior of the other" (a symmetric relationship) - geoIntersects: URIRef # Represents spatial relations in which two geometries (or the places they represent) have at least one point in common. As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoMidpoint: URIRef # Indicates the GeoCoordinates at the centre of a GeoShape e.g. GeoCircle. - geoOverlaps: URIRef # Represents a relationship between two geometries (or the places they represent), relating a geometry to another that geospatially overlaps it, i.e. they have some but not all points in common. As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geoRadius: URIRef # Indicates the approximate radius of a GeoCircle (metres unless indicated otherwise via Distance notation). - geoTouches: URIRef # Represents spatial relations in which two geometries (or the places they represent) touch: they have at least one boundary point in common, but no interior points." (a symmetric relationship, as defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM) ) - geoWithin: URIRef # Represents a relationship between two geometries (or the places they represent), relating a geometry to one that contains it, i.e. it is inside (i.e. within) its interior. As defined in [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM). - geographicArea: URIRef # The geographic area associated with the audience. - gettingTestedInfo: URIRef # Information about getting tested (for a [[MedicalCondition]]), e.g. in the context of a pandemic. - givenName: URIRef # Given name. In the U.S., the first name of a Person. - globalLocationNumber: URIRef # The [Global Location Number](http://www.gs1.org/gln) (GLN, sometimes also referred to as International Location Number or ILN) of the respective organization, person, or place. The GLN is a 13-digit number used to identify parties and physical locations. - governmentBenefitsInfo: URIRef # governmentBenefitsInfo provides information about government benefits associated with a SpecialAnnouncement. - gracePeriod: URIRef # The period of time after any due date that the borrower has to fulfil its obligations before a default (failure to pay) is deemed to have occurred. - grantee: URIRef # The person, organization, contact point, or audience that has been granted this permission. - greater: URIRef # This ordering relation for qualitative values indicates that the subject is greater than the object. - greaterOrEqual: URIRef # This ordering relation for qualitative values indicates that the subject is greater than or equal to the object. - gtin: URIRef # A Global Trade Item Number ([GTIN](https://www.gs1.org/standards/id-keys/gtin)). GTINs identify trade items, including products and services, using numeric identification codes. The [[gtin]] property generalizes the earlier [[gtin8]], [[gtin12]], [[gtin13]], and [[gtin14]] properties. The GS1 [digital link specifications](https://www.gs1.org/standards/Digital-Link/) express GTINs as URLs. A correct [[gtin]] value should be a valid GTIN, which means that it should be an all-numeric string of either 8, 12, 13 or 14 digits, or a "GS1 Digital Link" URL based on such a string. The numeric component should also have a [valid GS1 check digit](https://www.gs1.org/services/check-digit-calculator) and meet the other rules for valid GTINs. See also [GS1's GTIN Summary](http://www.gs1.org/barcodes/technical/idkeys/gtin) and [Wikipedia](https://en.wikipedia.org/wiki/Global_Trade_Item_Number) for more details. Left-padding of the gtin values is not required or encouraged. - gtin12: URIRef # The GTIN-12 code of the product, or the product to which the offer refers. The GTIN-12 is the 12-digit GS1 Identification Key composed of a U.P.C. Company Prefix, Item Reference, and Check Digit used to identify trade items. See [GS1 GTIN Summary](http://www.gs1.org/barcodes/technical/idkeys/gtin) for more details. - gtin13: URIRef # The GTIN-13 code of the product, or the product to which the offer refers. This is equivalent to 13-digit ISBN codes and EAN UCC-13. Former 12-digit UPC codes can be converted into a GTIN-13 code by simply adding a preceding zero. See [GS1 GTIN Summary](http://www.gs1.org/barcodes/technical/idkeys/gtin) for more details. - gtin14: URIRef # The GTIN-14 code of the product, or the product to which the offer refers. See [GS1 GTIN Summary](http://www.gs1.org/barcodes/technical/idkeys/gtin) for more details. - gtin8: URIRef # The GTIN-8 code of the product, or the product to which the offer refers. This code is also known as EAN/UCC-8 or 8-digit EAN. See [GS1 GTIN Summary](http://www.gs1.org/barcodes/technical/idkeys/gtin) for more details. - guideline: URIRef # A medical guideline related to this entity. - guidelineDate: URIRef # Date on which this guideline's recommendation was made. - guidelineSubject: URIRef # The medical conditions, treatments, etc. that are the subject of the guideline. - handlingTime: URIRef # The typical delay between the receipt of the order and the goods either leaving the warehouse or being prepared for pickup, in case the delivery method is on site pickup. Typical properties: minValue, maxValue, unitCode (d for DAY). This is by common convention assumed to mean business days (if a unitCode is used, coded as "d"), i.e. only counting days when the business normally operates. - hasBioChemEntityPart: URIRef # Indicates a BioChemEntity that (in some sense) has this BioChemEntity as a part. - hasBioPolymerSequence: URIRef # A symbolic representation of a BioChemEnity. For example, a nucleotide sequence of a Gene or an amino acid sequence of a Protein. - hasBroadcastChannel: URIRef # A broadcast channel of a broadcast service. - hasCategoryCode: URIRef # A Category code contained in this code set. - hasCourse: URIRef # A course or class that is one of the learning opportunities that constitute an educational / occupational program. No information is implied about whether the course is mandatory or optional; no guarantee is implied about whether the course will be available to everyone on the program. - hasCourseInstance: URIRef # An offering of the course at a specific time and place or through specific media or mode of study or to a specific section of students. - hasCredential: URIRef # A credential awarded to the Person or Organization. - hasDefinedTerm: URIRef # A Defined Term contained in this term set. - hasDeliveryMethod: URIRef # Method used for delivery or shipping. - hasDigitalDocumentPermission: URIRef # A permission related to the access to this document (e.g. permission to read or write an electronic document). For a public document, specify a grantee with an Audience with audienceType equal to "public". - hasDriveThroughService: URIRef # Indicates whether some facility (e.g. [[FoodEstablishment]], [[CovidTestingFacility]]) offers a service that can be used by driving through in a car. In the case of [[CovidTestingFacility]] such facilities could potentially help with social distancing from other potentially-infected users. - hasEnergyConsumptionDetails: URIRef # Defines the energy efficiency Category (also known as "class" or "rating") for a product according to an international energy efficiency standard. - hasEnergyEfficiencyCategory: URIRef # Defines the energy efficiency Category (which could be either a rating out of range of values or a yes/no certification) for a product according to an international energy efficiency standard. - hasHealthAspect: URIRef # Indicates the aspect or aspects specifically addressed in some [[HealthTopicContent]]. For example, that the content is an overview, or that it talks about treatment, self-care, treatments or their side-effects. - hasMap: URIRef # A URL to a map of the place. - hasMeasurement: URIRef # A product measurement, for example the inseam of pants, the wheel size of a bicycle, or the gauge of a screw. Usually an exact measurement, but can also be a range of measurements for adjustable products, for example belts and ski bindings. - hasMenu: URIRef # Either the actual menu as a structured representation, as text, or a URL of the menu. - hasMenuItem: URIRef # A food or drink item contained in a menu or menu section. - hasMenuSection: URIRef # A subgrouping of the menu (by dishes, course, serving time period, etc.). - hasMerchantReturnPolicy: ( - URIRef # Specifies a MerchantReturnPolicy that may be applicable. - ) - hasMolecularFunction: URIRef # Molecular function performed by this BioChemEntity; please use PropertyValue if you want to include any evidence. - hasOccupation: URIRef # The Person's occupation. For past professions, use Role for expressing dates. - hasOfferCatalog: URIRef # Indicates an OfferCatalog listing for this Organization, Person, or Service. - hasPOS: URIRef # Points-of-Sales operated by the organization or person. - hasPart: URIRef # Indicates an item or CreativeWork that is part of this item, or CreativeWork (in some sense). - hasRepresentation: URIRef # A common representation such as a protein sequence or chemical structure for this entity. For images use schema.org/image. - hasVariant: URIRef # Indicates a [[Product]] that is a member of this [[ProductGroup]] (or [[ProductModel]]). - headline: URIRef # Headline of the article. - healthCondition: URIRef # Specifying the health condition(s) of a patient, medical study, or other target audience. - healthPlanCoinsuranceOption: URIRef # Whether the coinsurance applies before or after deductible, etc. TODO: Is this a closed set? - healthPlanCoinsuranceRate: URIRef # Whether The rate of coinsurance expressed as a number between 0.0 and 1.0. - healthPlanCopay: URIRef # Whether The copay amount. - healthPlanCopayOption: URIRef # Whether the copay is before or after deductible, etc. TODO: Is this a closed set? - healthPlanCostSharing: URIRef # Whether The costs to the patient for services under this network or formulary. - healthPlanDrugOption: URIRef # TODO. - healthPlanDrugTier: ( - URIRef # The tier(s) of drugs offered by this formulary or insurance plan. - ) - healthPlanId: URIRef # The 14-character, HIOS-generated Plan ID number. (Plan IDs must be unique, even across different markets.) - healthPlanMarketingUrl: URIRef # The URL that goes directly to the plan brochure for the specific standard plan or plan variation. - healthPlanNetworkId: URIRef # Name or unique ID of network. (Networks are often reused across different insurance plans). - healthPlanNetworkTier: URIRef # The tier(s) for this network. - healthPlanPharmacyCategory: ( - URIRef # The category or type of pharmacy associated with this cost sharing. - ) - healthcareReportingData: URIRef # Indicates data describing a hospital, e.g. a CDC [[CDCPMDRecord]] or as some kind of [[Dataset]]. - height: URIRef # The height of the item. - highPrice: URIRef # The highest price of all offers available.\n\nUsage guidelines:\n\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - hiringOrganization: URIRef # Organization offering the job position. - holdingArchive: URIRef # [[ArchiveOrganization]] that holds, keeps or maintains the [[ArchiveComponent]]. - homeLocation: URIRef # A contact location for a person's residence. - homeTeam: URIRef # The home team in a sports event. - honorificPrefix: ( - URIRef # An honorific prefix preceding a Person's name such as Dr/Mrs/Mr. - ) - honorificSuffix: ( - URIRef # An honorific suffix following a Person's name such as M.D. /PhD/MSCSW. - ) - hospitalAffiliation: ( - URIRef # A hospital with which the physician or office is affiliated. - ) - hostingOrganization: URIRef # The organization (airline, travelers' club, etc.) the membership is made with. - hoursAvailable: ( - URIRef # The hours during which this service or contact is available. - ) - howPerformed: URIRef # How the procedure is performed. - httpMethod: URIRef # An HTTP method that specifies the appropriate HTTP method for a request to an HTTP EntryPoint. Values are capitalized strings as used in HTTP. - iataCode: URIRef # IATA identifier for an airline or airport. - icaoCode: URIRef # ICAO identifier for an airport. - identifier: URIRef # The identifier property represents any kind of identifier for any kind of [[Thing]], such as ISBNs, GTIN codes, UUIDs etc. Schema.org provides dedicated properties for representing many of these, either as textual strings or as URL (URI) links. See [background notes](/docs/datamodel.html#identifierBg) for more details. - identifyingExam: URIRef # A physical examination that can identify this sign. - identifyingTest: URIRef # A diagnostic test that can identify this sign. - illustrator: URIRef # The illustrator of the book. - image: URIRef # An image of the item. This can be a [[URL]] or a fully described [[ImageObject]]. - imagingTechnique: URIRef # Imaging technique used. - inAlbum: URIRef # The album to which this recording belongs. - inBroadcastLineup: URIRef # The CableOrSatelliteService offering the channel. - inChI: URIRef # Non-proprietary identifier for molecular entity that can be used in printed and electronic data sources thus enabling easier linking of diverse data compilations. - inChIKey: URIRef # InChIKey is a hashed version of the full InChI (using the SHA-256 algorithm). - inCodeSet: URIRef # A [[CategoryCodeSet]] that contains this category code. - inDefinedTermSet: URIRef # A [[DefinedTermSet]] that contains this term. - inLanguage: URIRef # The language of the content or performance or used in an action. Please use one of the language codes from the [IETF BCP 47 standard](http://tools.ietf.org/html/bcp47). See also [[availableLanguage]]. - inPlaylist: URIRef # The playlist to which this recording belongs. - inProductGroupWithID: URIRef # Indicates the [[productGroupID]] for a [[ProductGroup]] that this product [[isVariantOf]]. - inStoreReturnsOffered: URIRef # Are in-store returns offered? (for more advanced return methods use the [[returnMethod]] property) - inSupportOf: ( - URIRef # Qualification, candidature, degree, application that Thesis supports. - ) - incentiveCompensation: ( - URIRef # Description of bonus and commission compensation aspects of the job. - ) - incentives: ( - URIRef # Description of bonus and commission compensation aspects of the job. - ) - includedComposition: URIRef # Smaller compositions included in this work (e.g. a movement in a symphony). - includedDataCatalog: URIRef # A data catalog which contains this dataset (this property was previously 'catalog', preferred name is now 'includedInDataCatalog'). - includedInDataCatalog: URIRef # A data catalog which contains this dataset. - includedInHealthInsurancePlan: URIRef # The insurance plans that cover this drug. - includedRiskFactor: URIRef # A modifiable or non-modifiable risk factor included in the calculation, e.g. age, coexisting condition. - includesAttraction: URIRef # Attraction located at destination. - includesHealthPlanFormulary: URIRef # Formularies covered by this plan. - includesHealthPlanNetwork: URIRef # Networks covered by this plan. - includesObject: URIRef # This links to a node or nodes indicating the exact quantity of the products included in an [[Offer]] or [[ProductCollection]]. - increasesRiskOf: ( - URIRef # The condition, complication, etc. influenced by this factor. - ) - industry: URIRef # The industry associated with the job position. - ineligibleRegion: URIRef # The ISO 3166-1 (ISO 3166-1 alpha-2) or ISO 3166-2 code, the place, or the GeoShape for the geo-political region(s) for which the offer or delivery charge specification is not valid, e.g. a region where the transaction is not allowed.\n\nSee also [[eligibleRegion]]. - infectiousAgent: ( - URIRef # The actual infectious agent, such as a specific bacterium. - ) - infectiousAgentClass: URIRef # The class of infectious agent (bacteria, prion, etc.) that causes the disease. - ingredients: ( - URIRef # A single ingredient used in the recipe, e.g. sugar, flour or garlic. - ) - inker: URIRef # The individual who traces over the pencil drawings in ink after pencils are complete. - insertion: URIRef # The place of attachment of a muscle, or what the muscle moves. - installUrl: URIRef # URL at which the app may be installed, if different from the URL of the item. - instructor: URIRef # A person assigned to instruct or provide instructional assistance for the [[CourseInstance]]. - instrument: URIRef # The object that helped the agent perform the action. e.g. John wrote a book with *a pen*. - intensity: URIRef # Quantitative measure gauging the degree of force involved in the exercise, for example, heartbeats per minute. May include the velocity of the movement. - interactingDrug: URIRef # Another drug that is known to interact with this drug in a way that impacts the effect of this drug or causes a risk to the patient. Note: disease interactions are typically captured as contraindications. - interactionCount: URIRef # This property is deprecated, alongside the UserInteraction types on which it depended. - interactionService: ( - URIRef # The WebSite or SoftwareApplication where the interactions took place. - ) - interactionStatistic: URIRef # The number of interactions for the CreativeWork using the WebSite or SoftwareApplication. The most specific child type of InteractionCounter should be used. - interactionType: URIRef # The Action representing the type of interaction. For up votes, +1s, etc. use [[LikeAction]]. For down votes use [[DislikeAction]]. Otherwise, use the most specific Action. - interactivityType: URIRef # The predominant mode of learning supported by the learning resource. Acceptable values are 'active', 'expositive', or 'mixed'. - interestRate: URIRef # The interest rate, charged or paid, applicable to the financial product. Note: This is different from the calculated annualPercentageRate. - interpretedAsClaim: URIRef # Used to indicate a specific claim contained, implied, translated or refined from the content of a [[MediaObject]] or other [[CreativeWork]]. The interpreting party can be indicated using [[claimInterpreter]]. - inventoryLevel: ( - URIRef # The current approximate inventory level for the item or items. - ) - inverseOf: URIRef # Relates a property to a property that is its inverse. Inverse properties relate the same pairs of items to each other, but in reversed direction. For example, the 'alumni' and 'alumniOf' properties are inverseOf each other. Some properties don't have explicit inverses; in these situations RDFa and JSON-LD syntax for reverse properties can be used. - isAcceptingNewPatients: URIRef # Whether the provider is accepting new patients. - isAccessibleForFree: URIRef # A flag to signal that the item, event, or place is accessible for free. - isAccessoryOrSparePartFor: URIRef # A pointer to another product (or multiple products) for which this product is an accessory or spare part. - isAvailableGenerically: ( - URIRef # True if the drug is available in a generic form (regardless of name). - ) - isBasedOn: URIRef # A resource from which this work is derived or from which it is a modification or adaption. - isBasedOnUrl: URIRef # A resource that was used in the creation of this resource. This term can be repeated for multiple sources. For example, http://example.com/great-multiplication-intro.html. - isConsumableFor: URIRef # A pointer to another product (or multiple products) for which this product is a consumable. - isEncodedByBioChemEntity: URIRef # Another BioChemEntity encoding by this one. - isFamilyFriendly: URIRef # Indicates whether this content is family friendly. - isGift: URIRef # Was the offer accepted as a gift for someone other than the buyer. - isInvolvedInBiologicalProcess: URIRef # Biological process this BioChemEntity is involved in; please use PropertyValue if you want to include any evidence. - isLiveBroadcast: URIRef # True if the broadcast is of a live event. - isLocatedInSubcellularLocation: URIRef # Subcellular location where this BioChemEntity is located; please use PropertyValue if you want to include any evidence. - isPartOf: URIRef # Indicates an item or CreativeWork that this item, or CreativeWork (in some sense), is part of. - isPartOfBioChemEntity: URIRef # Indicates a BioChemEntity that is (in some sense) a part of this BioChemEntity. - isPlanForApartment: ( - URIRef # Indicates some accommodation that this floor plan describes. - ) - isProprietary: URIRef # True if this item's name is a proprietary/brand name (vs. generic name). - isRelatedTo: ( - URIRef # A pointer to another, somehow related product (or multiple products). - ) - isResizable: URIRef # Whether the 3DModel allows resizing. For example, room layout applications often do not allow 3DModel elements to be resized to reflect reality. - isSimilarTo: URIRef # A pointer to another, functionally similar product (or multiple products). - isUnlabelledFallback: URIRef # This can be marked 'true' to indicate that some published [[DeliveryTimeSettings]] or [[ShippingRateSettings]] are intended to apply to all [[OfferShippingDetails]] published by the same merchant, when referenced by a [[shippingSettingsLink]] in those settings. It is not meaningful to use a 'true' value for this property alongside a transitTimeLabel (for [[DeliveryTimeSettings]]) or shippingLabel (for [[ShippingRateSettings]]), since this property is for use with unlabelled settings. - isVariantOf: URIRef # Indicates the kind of product that this is a variant of. In the case of [[ProductModel]], this is a pointer (from a ProductModel) to a base product from which this product is a variant. It is safe to infer that the variant inherits all product features from the base model, unless defined locally. This is not transitive. In the case of a [[ProductGroup]], the group description also serves as a template, representing a set of Products that vary on explicitly defined, specific dimensions only (so it defines both a set of variants, as well as which values distinguish amongst those variants). When used with [[ProductGroup]], this property can apply to any [[Product]] included in the group. - isbn: URIRef # The ISBN of the book. - isicV4: URIRef # The International Standard of Industrial Classification of All Economic Activities (ISIC), Revision 4 code for a particular organization, business person, or place. - isrcCode: URIRef # The International Standard Recording Code for the recording. - issn: URIRef # The International Standard Serial Number (ISSN) that identifies this serial publication. You can repeat this property to identify different formats of, or the linking ISSN (ISSN-L) for, this serial publication. - issueNumber: ( - URIRef # Identifies the issue of publication; for example, "iii" or "2". - ) - issuedBy: URIRef # The organization issuing the ticket or permit. - issuedThrough: URIRef # The service through with the permit was granted. - iswcCode: ( - URIRef # The International Standard Musical Work Code for the composition. - ) - item: URIRef # An entity represented by an entry in a list or data feed (e.g. an 'artist' in a list of 'artists')’. - itemCondition: URIRef # A predefined value from OfferItemCondition specifying the condition of the product or service, or the products or services included in the offer. Also used for product return policies to specify the condition of products accepted for returns. - itemDefectReturnFees: ( - URIRef # The type of return fees for returns of defect products. - ) - itemDefectReturnLabelSource: URIRef # The method (from an enumeration) by which the customer obtains a return shipping label for a defect product. - itemDefectReturnShippingFeesAmount: URIRef # Amount of shipping costs for defect product returns. Applicable when property [[itemDefectReturnFees]] equals [[ReturnShippingFees]]. - itemListElement: URIRef # For itemListElement values, you can use simple strings (e.g. "Peter", "Paul", "Mary"), existing entities, or use ListItem.\n\nText values are best if the elements in the list are plain strings. Existing entities are best for a simple, unordered list of existing things in your data. ListItem is used with ordered lists when you want to provide additional context about the element in that list or when the same item might be in different places in different lists.\n\nNote: The order of elements in your mark-up is not sufficient for indicating the order or elements. Use ListItem with a 'position' property in such cases. - itemListOrder: URIRef # Type of ordering (e.g. Ascending, Descending, Unordered). - itemLocation: URIRef # Current location of the item. - itemOffered: URIRef # An item being offered (or demanded). The transactional nature of the offer or demand is documented using [[businessFunction]], e.g. sell, lease etc. While several common expected types are listed explicitly in this definition, others can be used. Using a second type, such as Product or a subtype of Product, can clarify the nature of the offer. - itemReviewed: URIRef # The item that is being reviewed/rated. - itemShipped: URIRef # Item(s) being shipped. - itinerary: URIRef # Destination(s) ( [[Place]] ) that make up a trip. For a trip where destination order is important use [[ItemList]] to specify that order (see examples). - iupacName: URIRef # Systematic method of naming chemical compounds as recommended by the International Union of Pure and Applied Chemistry (IUPAC). - jobBenefits: URIRef # Description of benefits associated with the job. - jobImmediateStart: URIRef # An indicator as to whether a position is available for an immediate start. - jobLocation: URIRef # A (typically single) geographic location associated with the job position. - jobLocationType: URIRef # A description of the job location (e.g TELECOMMUTE for telecommute jobs). - jobStartDate: URIRef # The date on which a successful applicant for this job would be expected to start work. Choose a specific date in the future or use the jobImmediateStart property to indicate the position is to be filled as soon as possible. - jobTitle: URIRef # The job title of the person (for example, Financial Manager). - jurisdiction: URIRef # Indicates a legal jurisdiction, e.g. of some legislation, or where some government service is based. - keywords: URIRef # Keywords or tags used to describe this content. Multiple entries in a keywords list are typically delimited by commas. - knownVehicleDamages: ( - URIRef # A textual description of known damages, both repaired and unrepaired. - ) - knows: URIRef # The most generic bi-directional social/work relation. - knowsAbout: URIRef # Of a [[Person]], and less typically of an [[Organization]], to indicate a topic that is known about - suggesting possible expertise but not implying it. We do not distinguish skill levels here, or relate this to educational content, events, objectives or [[JobPosting]] descriptions. - knowsLanguage: URIRef # Of a [[Person]], and less typically of an [[Organization]], to indicate a known language. We do not distinguish skill levels or reading/writing/speaking/signing here. Use language codes from the [IETF BCP 47 standard](http://tools.ietf.org/html/bcp47). - labelDetails: URIRef # Link to the drug's label details. - landlord: ( - URIRef # A sub property of participant. The owner of the real estate property. - ) - language: URIRef # A sub property of instrument. The language used on this action. - lastReviewed: URIRef # Date on which the content on this web page was last reviewed for accuracy and/or completeness. - latitude: URIRef # The latitude of a location. For example ```37.42242``` ([WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System)). - layoutImage: URIRef # A schematic image showing the floorplan layout. - learningResourceType: URIRef # The predominant type or kind characterizing the learning resource. For example, 'presentation', 'handout'. - leaseLength: URIRef # Length of the lease for some [[Accommodation]], either particular to some [[Offer]] or in some cases intrinsic to the property. - legalName: URIRef # The official name of the organization, e.g. the registered company name. - legalStatus: URIRef # The drug or supplement's legal status, including any controlled substance schedules that apply. - legislationApplies: URIRef # Indicates that this legislation (or part of a legislation) somehow transfers another legislation in a different legislative context. This is an informative link, and it has no legal value. For legally-binding links of transposition, use the legislationTransposes property. For example an informative consolidated law of a European Union's member state "applies" the consolidated version of the European Directive implemented in it. - legislationChanges: URIRef # Another legislation that this legislation changes. This encompasses the notions of amendment, replacement, correction, repeal, or other types of change. This may be a direct change (textual or non-textual amendment) or a consequential or indirect change. The property is to be used to express the existence of a change relationship between two acts rather than the existence of a consolidated version of the text that shows the result of the change. For consolidation relationships, use the legislationConsolidates property. - legislationConsolidates: URIRef # Indicates another legislation taken into account in this consolidated legislation (which is usually the product of an editorial process that revises the legislation). This property should be used multiple times to refer to both the original version or the previous consolidated version, and to the legislations making the change. - legislationDate: URIRef # The date of adoption or signature of the legislation. This is the date at which the text is officially aknowledged to be a legislation, even though it might not even be published or in force. - legislationDateVersion: URIRef # The point-in-time at which the provided description of the legislation is valid (e.g. : when looking at the law on the 2016-04-07 (= dateVersion), I get the consolidation of 2015-04-12 of the "National Insurance Contributions Act 2015") - legislationIdentifier: URIRef # An identifier for the legislation. This can be either a string-based identifier, like the CELEX at EU level or the NOR in France, or a web-based, URL/URI identifier, like an ELI (European Legislation Identifier) or an URN-Lex. - legislationJurisdiction: ( - URIRef # The jurisdiction from which the legislation originates. - ) - legislationLegalForce: URIRef # Whether the legislation is currently in force, not in force, or partially in force. - legislationLegalValue: URIRef # The legal value of this legislation file. The same legislation can be written in multiple files with different legal values. Typically a digitally signed PDF have a "stronger" legal value than the HTML file of the same act. - legislationPassedBy: URIRef # The person or organization that originally passed or made the law : typically parliament (for primary legislation) or government (for secondary legislation). This indicates the "legal author" of the law, as opposed to its physical author. - legislationResponsible: URIRef # An individual or organization that has some kind of responsibility for the legislation. Typically the ministry who is/was in charge of elaborating the legislation, or the adressee for potential questions about the legislation once it is published. - legislationTransposes: URIRef # Indicates that this legislation (or part of legislation) fulfills the objectives set by another legislation, by passing appropriate implementation measures. Typically, some legislations of European Union's member states or regions transpose European Directives. This indicates a legally binding link between the 2 legislations. - legislationType: URIRef # The type of the legislation. Examples of values are "law", "act", "directive", "decree", "regulation", "statutory instrument", "loi organique", "règlement grand-ducal", etc., depending on the country. - leiCode: URIRef # An organization identifier that uniquely identifies a legal entity as defined in ISO 17442. - lender: URIRef # A sub property of participant. The person that lends the object being borrowed. - lesser: URIRef # This ordering relation for qualitative values indicates that the subject is lesser than the object. - lesserOrEqual: URIRef # This ordering relation for qualitative values indicates that the subject is lesser than or equal to the object. - letterer: URIRef # The individual who adds lettering, including speech balloons and sound effects, to artwork. - license: URIRef # A license document that applies to this content, typically indicated by URL. - line: URIRef # A line is a point-to-point path consisting of two or more points. A line is expressed as a series of two or more point objects separated by space. - linkRelationship: URIRef # Indicates the relationship type of a Web link. - liveBlogUpdate: URIRef # An update to the LiveBlog. - loanMortgageMandateAmount: URIRef # Amount of mortgage mandate that can be converted into a proper mortgage at a later stage. - loanPaymentAmount: URIRef # The amount of money to pay in a single payment. - loanPaymentFrequency: URIRef # Frequency of payments due, i.e. number of months between payments. This is defined as a frequency, i.e. the reciprocal of a period of time. - loanRepaymentForm: URIRef # A form of paying back money previously borrowed from a lender. Repayment usually takes the form of periodic payments that normally include part principal plus interest in each payment. - loanTerm: URIRef # The duration of the loan or credit agreement. - loanType: URIRef # The type of a loan or credit. - location: URIRef # The location of, for example, where an event is happening, where an organization is located, or where an action takes place. - locationCreated: URIRef # The location where the CreativeWork was created, which may not be the same as the location depicted in the CreativeWork. - lodgingUnitDescription: URIRef # A full description of the lodging unit. - lodgingUnitType: URIRef # Textual description of the unit type (including suite vs. room, size of bed, etc.). - logo: URIRef # An associated logo. - longitude: URIRef # The longitude of a location. For example ```-122.08585``` ([WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System)). - loser: URIRef # A sub property of participant. The loser of the action. - lowPrice: URIRef # The lowest price of all offers available.\n\nUsage guidelines:\n\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - lyricist: URIRef # The person who wrote the words. - lyrics: URIRef # The words in the song. - mainContentOfPage: ( - URIRef # Indicates if this web page element is the main subject of the page. - ) - mainEntity: URIRef # Indicates the primary entity described in some page or other CreativeWork. - mainEntityOfPage: URIRef # Indicates a page (or other CreativeWork) for which this thing is the main entity being described. See [background notes](/docs/datamodel.html#mainEntityBackground) for details. - maintainer: URIRef # A maintainer of a [[Dataset]], software package ([[SoftwareApplication]]), or other [[Project]]. A maintainer is a [[Person]] or [[Organization]] that manages contributions to, and/or publication of, some (typically complex) artifact. It is common for distributions of software and data to be based on "upstream" sources. When [[maintainer]] is applied to a specific version of something e.g. a particular version or packaging of a [[Dataset]], it is always possible that the upstream source has a different maintainer. The [[isBasedOn]] property can be used to indicate such relationships between datasets to make the different maintenance roles clear. Similarly in the case of software, a package may have dedicated maintainers working on integration into software distributions such as Ubuntu, as well as upstream maintainers of the underlying work. - makesOffer: URIRef # A pointer to products or services offered by the organization or person. - manufacturer: URIRef # The manufacturer of the product. - map: URIRef # A URL to a map of the place. - mapType: URIRef # Indicates the kind of Map, from the MapCategoryType Enumeration. - maps: URIRef # A URL to a map of the place. - marginOfError: URIRef # A marginOfError for an [[Observation]]. - masthead: URIRef # For a [[NewsMediaOrganization]], a link to the masthead page or a page listing top editorial management. - material: URIRef # A material that something is made from, e.g. leather, wool, cotton, paper. - materialExtent: URIRef # The quantity of the materials being described or an expression of the physical space they occupy. - mathExpression: URIRef # A mathematical expression (e.g. 'x^2-3x=0') that may be solved for a specific variable, simplified, or transformed. This can take many formats, e.g. LaTeX, Ascii-Math, or math as you would write with a keyboard. - maxPrice: URIRef # The highest price if the price is a range. - maxValue: URIRef # The upper value of some characteristic or property. - maximumAttendeeCapacity: ( - URIRef # The total number of individuals that may attend an event or venue. - ) - maximumEnrollment: ( - URIRef # The maximum number of students who may be enrolled in the program. - ) - maximumIntake: URIRef # Recommended intake of this supplement for a given population as defined by a specific recommending authority. - maximumPhysicalAttendeeCapacity: URIRef # The maximum physical attendee capacity of an [[Event]] whose [[eventAttendanceMode]] is [[OfflineEventAttendanceMode]] (or the offline aspects, in the case of a [[MixedEventAttendanceMode]]). - maximumVirtualAttendeeCapacity: URIRef # The maximum physical attendee capacity of an [[Event]] whose [[eventAttendanceMode]] is [[OnlineEventAttendanceMode]] (or the online aspects, in the case of a [[MixedEventAttendanceMode]]). - mealService: URIRef # Description of the meals that will be provided or available for purchase. - measuredProperty: URIRef # The measuredProperty of an [[Observation]], either a schema.org property, a property from other RDF-compatible systems e.g. W3C RDF Data Cube, or schema.org extensions such as [GS1's](https://www.gs1.org/voc/?show=properties). - measuredValue: URIRef # The measuredValue of an [[Observation]]. - measurementTechnique: URIRef # A technique or technology used in a [[Dataset]] (or [[DataDownload]], [[DataCatalog]]), corresponding to the method used for measuring the corresponding variable(s) (described using [[variableMeasured]]). This is oriented towards scientific and scholarly dataset publication but may have broader applicability; it is not intended as a full representation of measurement, but rather as a high level summary for dataset discovery. For example, if [[variableMeasured]] is: molecule concentration, [[measurementTechnique]] could be: "mass spectrometry" or "nmr spectroscopy" or "colorimetry" or "immunofluorescence". If the [[variableMeasured]] is "depression rating", the [[measurementTechnique]] could be "Zung Scale" or "HAM-D" or "Beck Depression Inventory". If there are several [[variableMeasured]] properties recorded for some given data object, use a [[PropertyValue]] for each [[variableMeasured]] and attach the corresponding [[measurementTechnique]]. - mechanismOfAction: URIRef # The specific biochemical interaction through which this drug or supplement produces its pharmacological effect. - mediaAuthenticityCategory: URIRef # Indicates a MediaManipulationRatingEnumeration classification of a media object (in the context of how it was published or shared). - mediaItemAppearance: URIRef # In the context of a [[MediaReview]], indicates specific media item(s) that are grouped using a [[MediaReviewItem]]. - median: URIRef # The median value. - medicalAudience: URIRef # Medical audience for page. - medicalSpecialty: URIRef # A medical specialty of the provider. - medicineSystem: URIRef # The system of medicine that includes this MedicalEntity, for example 'evidence-based', 'homeopathic', 'chiropractic', etc. - meetsEmissionStandard: ( - URIRef # Indicates that the vehicle meets the respective emission standard. - ) - member: URIRef # A member of an Organization or a ProgramMembership. Organizations can be members of organizations; ProgramMembership is typically for individuals. - memberOf: URIRef # An Organization (or ProgramMembership) to which this Person or Organization belongs. - members: URIRef # A member of this organization. - membershipNumber: URIRef # A unique identifier for the membership. - membershipPointsEarned: URIRef # The number of membership points earned by the member. If necessary, the unitText can be used to express the units the points are issued in. (e.g. stars, miles, etc.) - memoryRequirements: URIRef # Minimum memory requirements. - mentions: URIRef # Indicates that the CreativeWork contains a reference to, but is not necessarily about a concept. - menu: URIRef # Either the actual menu as a structured representation, as text, or a URL of the menu. - menuAddOn: URIRef # Additional menu item(s) such as a side dish of salad or side order of fries that can be added to this menu item. Additionally it can be a menu section containing allowed add-on menu items for this menu item. - merchant: URIRef # 'merchant' is an out-dated term for 'seller'. - merchantReturnDays: URIRef # Specifies either a fixed return date or the number of days (from the delivery date) that a product can be returned. Used when the [[returnPolicyCategory]] property is specified as [[MerchantReturnFiniteReturnWindow]]. - merchantReturnLink: ( - URIRef # Specifies a Web page or service by URL, for product returns. - ) - messageAttachment: URIRef # A CreativeWork attached to the message. - mileageFromOdometer: URIRef # The total distance travelled by the particular vehicle since its initial production, as read from its odometer.\n\nTypical unit code(s): KMT for kilometers, SMI for statute miles - minPrice: URIRef # The lowest price if the price is a range. - minValue: URIRef # The lower value of some characteristic or property. - minimumPaymentDue: URIRef # The minimum payment required at this time. - missionCoveragePrioritiesPolicy: URIRef # For a [[NewsMediaOrganization]], a statement on coverage priorities, including any public agenda or stance on issues. - model: URIRef # The model of the product. Use with the URL of a ProductModel or a textual representation of the model identifier. The URL of the ProductModel can be from an external source. It is recommended to additionally provide strong product identifiers via the gtin8/gtin13/gtin14 and mpn properties. - modelDate: URIRef # The release date of a vehicle model (often used to differentiate versions of the same make and model). - modifiedTime: URIRef # The date and time the reservation was modified. - molecularFormula: URIRef # The empirical formula is the simplest whole number ratio of all the atoms in a molecule. - molecularWeight: URIRef # This is the molecular weight of the entity being described, not of the parent. Units should be included in the form '<Number> <unit>', for example '12 amu' or as '<QuantitativeValue>. - monoisotopicMolecularWeight: URIRef # The monoisotopic mass is the sum of the masses of the atoms in a molecule using the unbound, ground-state, rest mass of the principal (most abundant) isotope for each element instead of the isotopic average mass. Please include the units the form '<Number> <unit>', for example '770.230488 g/mol' or as '<QuantitativeValue>. - monthlyMinimumRepaymentAmount: URIRef # The minimum payment is the lowest amount of money that one is required to pay on a credit card statement each month. - monthsOfExperience: URIRef # Indicates the minimal number of months of experience required for a position. - mpn: URIRef # The Manufacturer Part Number (MPN) of the product, or the product to which the offer refers. - multipleValues: URIRef # Whether multiple values are allowed for the property. Default is false. - muscleAction: URIRef # The movement the muscle generates. - musicArrangement: URIRef # An arrangement derived from the composition. - musicBy: URIRef # The composer of the soundtrack. - musicCompositionForm: ( - URIRef # The type of composition (e.g. overture, sonata, symphony, etc.). - ) - musicGroupMember: URIRef # A member of a music group—for example, John, Paul, George, or Ringo. - musicReleaseFormat: URIRef # Format of this release (the type of recording media used, ie. compact disc, digital media, LP, etc.). - musicalKey: URIRef # The key, mode, or scale this composition uses. - naics: URIRef # The North American Industry Classification System (NAICS) code for a particular organization or business person. - name: URIRef # The name of the item. - namedPosition: URIRef # A position played, performed or filled by a person or organization, as part of an organization. For example, an athlete in a SportsTeam might play in the position named 'Quarterback'. - nationality: URIRef # Nationality of the person. - naturalProgression: URIRef # The expected progression of the condition if it is not treated and allowed to progress naturally. - negativeNotes: URIRef # Indicates, in the context of a [[Review]] (e.g. framed as 'pro' vs 'con' considerations), negative considerations - either as unstructured text, or a list. - nerve: URIRef # The underlying innervation associated with the muscle. - nerveMotor: ( - URIRef # The neurological pathway extension that involves muscle control. - ) - netWorth: URIRef # The total financial value of the person as calculated by subtracting assets from liabilities. - newsUpdatesAndGuidelines: URIRef # Indicates a page with news updates and guidelines. This could often be (but is not required to be) the main page containing [[SpecialAnnouncement]] markup on a site. - nextItem: URIRef # A link to the ListItem that follows the current one. - noBylinesPolicy: URIRef # For a [[NewsMediaOrganization]] or other news-related [[Organization]], a statement explaining when authors of articles are not named in bylines. - nonEqual: URIRef # This ordering relation for qualitative values indicates that the subject is not equal to the object. - nonProprietaryName: URIRef # The generic name of this drug or supplement. - nonprofitStatus: URIRef # nonprofit Status indicates the legal status of a non-profit organization in its primary place of business. - normalRange: ( - URIRef # Range of acceptable values for a typical patient, when applicable. - ) - nsn: URIRef # Indicates the [NATO stock number](https://en.wikipedia.org/wiki/NATO_Stock_Number) (nsn) of a [[Product]]. - numAdults: URIRef # The number of adults staying in the unit. - numChildren: URIRef # The number of children staying in the unit. - numConstraints: URIRef # Indicates the number of constraints (not counting [[populationType]]) defined for a particular [[StatisticalPopulation]]. This helps applications understand if they have access to a sufficiently complete description of a [[StatisticalPopulation]]. - numTracks: URIRef # The number of tracks in this album or playlist. - numberOfAccommodationUnits: URIRef # Indicates the total (available plus unavailable) number of accommodation units in an [[ApartmentComplex]], or the number of accommodation units for a specific [[FloorPlan]] (within its specific [[ApartmentComplex]]). See also [[numberOfAvailableAccommodationUnits]]. - numberOfAirbags: URIRef # The number or type of airbags in the vehicle. - numberOfAvailableAccommodationUnits: URIRef # Indicates the number of available accommodation units in an [[ApartmentComplex]], or the number of accommodation units for a specific [[FloorPlan]] (within its specific [[ApartmentComplex]]). See also [[numberOfAccommodationUnits]]. - numberOfAxles: URIRef # The number of axles.\n\nTypical unit code(s): C62 - numberOfBathroomsTotal: URIRef # The total integer number of bathrooms in a some [[Accommodation]], following real estate conventions as [documented in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsTotalInteger+Field): "The simple sum of the number of bathrooms. For example for a property with two Full Bathrooms and one Half Bathroom, the Bathrooms Total Integer will be 3.". See also [[numberOfRooms]]. - numberOfBedrooms: URIRef # The total integer number of bedrooms in a some [[Accommodation]], [[ApartmentComplex]] or [[FloorPlan]]. - numberOfBeds: URIRef # The quantity of the given bed type available in the HotelRoom, Suite, House, or Apartment. - numberOfCredits: URIRef # The number of credits or units awarded by a Course or required to complete an EducationalOccupationalProgram. - numberOfDoors: URIRef # The number of doors.\n\nTypical unit code(s): C62 - numberOfEmployees: ( - URIRef # The number of employees in an organization e.g. business. - ) - numberOfEpisodes: URIRef # The number of episodes in this season or series. - numberOfForwardGears: URIRef # The total number of forward gears available for the transmission system of the vehicle.\n\nTypical unit code(s): C62 - numberOfFullBathrooms: URIRef # Number of full bathrooms - The total number of full and ¾ bathrooms in an [[Accommodation]]. This corresponds to the [BathroomsFull field in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsFull+Field). - numberOfItems: URIRef # The number of items in an ItemList. Note that some descriptions might not fully describe all items in a list (e.g., multi-page pagination); in such cases, the numberOfItems would be for the entire list. - numberOfLoanPayments: URIRef # The number of payments contractually required at origination to repay the loan. For monthly paying loans this is the number of months from the contractual first payment date to the maturity date. - numberOfPages: URIRef # The number of pages in the book. - numberOfPartialBathrooms: URIRef # Number of partial bathrooms - The total number of half and ¼ bathrooms in an [[Accommodation]]. This corresponds to the [BathroomsPartial field in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsPartial+Field). - numberOfPlayers: URIRef # Indicate how many people can play this game (minimum, maximum, or range). - numberOfPreviousOwners: URIRef # The number of owners of the vehicle, including the current one.\n\nTypical unit code(s): C62 - numberOfRooms: URIRef # The number of rooms (excluding bathrooms and closets) of the accommodation or lodging business. Typical unit code(s): ROM for room or C62 for no unit. The type of room can be put in the unitText property of the QuantitativeValue. - numberOfSeasons: URIRef # The number of seasons in this series. - numberedPosition: URIRef # A number associated with a role in an organization, for example, the number on an athlete's jersey. - nutrition: URIRef # Nutrition information about the recipe or menu item. - object: URIRef # The object upon which the action is carried out, whose state is kept intact or changed. Also known as the semantic roles patient, affected or undergoer (which change their state) or theme (which doesn't). e.g. John read *a book*. - observationDate: URIRef # The observationDate of an [[Observation]]. - observedNode: URIRef # The observedNode of an [[Observation]], often a [[StatisticalPopulation]]. - occupancy: URIRef # The allowed total occupancy for the accommodation in persons (including infants etc). For individual accommodations, this is not necessarily the legal maximum but defines the permitted usage as per the contractual agreement (e.g. a double room used by a single person). Typical unit code(s): C62 for person - occupationLocation: URIRef # The region/country for which this occupational description is appropriate. Note that educational requirements and qualifications can vary between jurisdictions. - occupationalCategory: URIRef # A category describing the job, preferably using a term from a taxonomy such as [BLS O*NET-SOC](http://www.onetcenter.org/taxonomy.html), [ISCO-08](https://www.ilo.org/public/english/bureau/stat/isco/isco08/) or similar, with the property repeated for each applicable value. Ideally the taxonomy should be identified, and both the textual label and formal code for the category should be provided.\n Note: for historical reasons, any textual label and formal code provided as a literal may be assumed to be from O*NET-SOC. - occupationalCredentialAwarded: URIRef # A description of the qualification, award, certificate, diploma or other occupational credential awarded as a consequence of successful completion of this course or program. - offerCount: URIRef # The number of offers for the product. - offeredBy: URIRef # A pointer to the organization or person making the offer. - offers: URIRef # An offer to provide this item—for example, an offer to sell a product, rent the DVD of a movie, perform a service, or give away tickets to an event. Use [[businessFunction]] to indicate the kind of transaction offered, i.e. sell, lease, etc. This property can also be used to describe a [[Demand]]. While this property is listed as expected on a number of common types, it can be used in others. In that case, using a second type, such as Product or a subtype of Product, can clarify the nature of the offer. - offersPrescriptionByMail: URIRef # Whether prescriptions can be delivered by mail. - openingHours: URIRef # The general opening hours for a business. Opening hours can be specified as a weekly time range, starting with days, then times per day. Multiple days can be listed with commas ',' separating each day. Day or time ranges are specified using a hyphen '-'.\n\n* Days are specified using the following two-letter combinations: ```Mo```, ```Tu```, ```We```, ```Th```, ```Fr```, ```Sa```, ```Su```.\n* Times are specified using 24:00 format. For example, 3pm is specified as ```15:00```, 10am as ```10:00```. \n* Here is an example: <time itemprop="openingHours" datetime="Tu,Th 16:00-20:00">Tuesdays and Thursdays 4-8pm</time>.\n* If a business is open 7 days a week, then it can be specified as <time itemprop="openingHours" datetime="Mo-Su">Monday through Sunday, all day</time>. - openingHoursSpecification: URIRef # The opening hours of a certain place. - opens: URIRef # The opening hour of the place or service on the given day(s) of the week. - operatingSystem: ( - URIRef # Operating systems supported (Windows 7, OSX 10.6, Android 1.6). - ) - opponent: URIRef # A sub property of participant. The opponent on this action. - option: URIRef # A sub property of object. The options subject to this action. - orderDate: URIRef # Date order was placed. - orderDelivery: ( - URIRef # The delivery of the parcel related to this order or order item. - ) - orderItemNumber: URIRef # The identifier of the order item. - orderItemStatus: URIRef # The current status of the order item. - orderNumber: URIRef # The identifier of the transaction. - orderQuantity: URIRef # The number of the item ordered. If the property is not set, assume the quantity is one. - orderStatus: URIRef # The current status of the order. - orderedItem: URIRef # The item ordered. - organizer: URIRef # An organizer of an Event. - originAddress: URIRef # Shipper's address. - originalMediaContextDescription: URIRef # Describes, in a [[MediaReview]] when dealing with [[DecontextualizedContent]], background information that can contribute to better interpretation of the [[MediaObject]]. - originalMediaLink: URIRef # Link to the page containing an original version of the content, or directly to an online copy of the original [[MediaObject]] content, e.g. video file. - originatesFrom: URIRef # The vasculature the lymphatic structure originates, or afferents, from. - overdosage: URIRef # Any information related to overdose on a drug, including signs or symptoms, treatments, contact information for emergency response. - ownedFrom: URIRef # The date and time of obtaining the product. - ownedThrough: URIRef # The date and time of giving up ownership on the product. - ownershipFundingInfo: URIRef # For an [[Organization]] (often but not necessarily a [[NewsMediaOrganization]]), a description of organizational ownership structure; funding and grants. In a news/media setting, this is with particular reference to editorial independence. Note that the [[funder]] is also available and can be used to make basic funder information machine-readable. - owns: URIRef # Products owned by the organization or person. - pageEnd: URIRef # The page on which the work ends; for example "138" or "xvi". - pageStart: URIRef # The page on which the work starts; for example "135" or "xiii". - pagination: URIRef # Any description of pages that is not separated into pageStart and pageEnd; for example, "1-6, 9, 55" or "10-12, 46-49". - parent: URIRef # A parent of this person. - parentItem: URIRef # The parent of a question, answer or item in general. - parentOrganization: URIRef # The larger organization that this organization is a [[subOrganization]] of, if any. - parentService: URIRef # A broadcast service to which the broadcast service may belong to such as regional variations of a national channel. - parentTaxon: URIRef # Closest parent taxon of the taxon in question. - parents: URIRef # A parents of the person. - partOfEpisode: URIRef # The episode to which this clip belongs. - partOfInvoice: URIRef # The order is being paid as part of the referenced Invoice. - partOfOrder: ( - URIRef # The overall order the items in this delivery were included in. - ) - partOfSeason: URIRef # The season to which this episode belongs. - partOfSeries: URIRef # The series to which this episode or season belongs. - partOfSystem: ( - URIRef # The anatomical or organ system that this structure is part of. - ) - partOfTVSeries: URIRef # The TV series to which this episode or season belongs. - partOfTrip: URIRef # Identifies that this [[Trip]] is a subTrip of another Trip. For example Day 1, Day 2, etc. of a multi-day trip. - participant: URIRef # Other co-agents that participated in the action indirectly. e.g. John wrote a book with *Steve*. - partySize: URIRef # Number of people the reservation should accommodate. - passengerPriorityStatus: URIRef # The priority status assigned to a passenger for security or boarding (e.g. FastTrack or Priority). - passengerSequenceNumber: ( - URIRef # The passenger's sequence number as assigned by the airline. - ) - pathophysiology: URIRef # Changes in the normal mechanical, physical, and biochemical functions that are associated with this activity or condition. - pattern: URIRef # A pattern that something has, for example 'polka dot', 'striped', 'Canadian flag'. Values are typically expressed as text, although links to controlled value schemes are also supported. - payload: URIRef # The permitted weight of passengers and cargo, EXCLUDING the weight of the empty vehicle.\n\nTypical unit code(s): KGM for kilogram, LBR for pound\n\n* Note 1: Many databases specify the permitted TOTAL weight instead, which is the sum of [[weight]] and [[payload]]\n* Note 2: You can indicate additional information in the [[name]] of the [[QuantitativeValue]] node.\n* Note 3: You may also link to a [[QualitativeValue]] node that provides additional information using [[valueReference]].\n* Note 4: Note that you can use [[minValue]] and [[maxValue]] to indicate ranges. - paymentAccepted: URIRef # Cash, Credit Card, Cryptocurrency, Local Exchange Tradings System, etc. - paymentDue: URIRef # The date that payment is due. - paymentDueDate: URIRef # The date that payment is due. - paymentMethod: ( - URIRef # The name of the credit card or other method of payment for the order. - ) - paymentMethodId: URIRef # An identifier for the method of payment used (e.g. the last 4 digits of the credit card). - paymentStatus: ( - URIRef # The status of payment; whether the invoice has been paid or not. - ) - paymentUrl: URIRef # The URL for sending a payment. - penciler: URIRef # The individual who draws the primary narrative artwork. - percentile10: URIRef # The 10th percentile value. - percentile25: URIRef # The 25th percentile value. - percentile75: URIRef # The 75th percentile value. - percentile90: URIRef # The 90th percentile value. - performTime: URIRef # The length of time it takes to perform instructions or a direction (not including time to prepare the supplies), in [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601). - performer: URIRef # A performer at the event—for example, a presenter, musician, musical group or actor. - performerIn: URIRef # Event that this person is a performer or participant in. - performers: URIRef # The main performer or performers of the event—for example, a presenter, musician, or actor. - permissionType: ( - URIRef # The type of permission granted the person, organization, or audience. - ) - permissions: URIRef # Permission(s) required to run the app (for example, a mobile app may require full internet access or may run only on wifi). - permitAudience: URIRef # The target audience for this permit. - permittedUsage: ( - URIRef # Indications regarding the permitted usage of the accommodation. - ) - petsAllowed: URIRef # Indicates whether pets are allowed to enter the accommodation or lodging business. More detailed information can be put in a text value. - phoneticText: URIRef # Representation of a text [[textValue]] using the specified [[speechToTextMarkup]]. For example the city name of Houston in IPA: /ˈhjuËstÉ™n/. - photo: URIRef # A photograph of this place. - photos: URIRef # Photographs of this place. - physicalRequirement: URIRef # A description of the types of physical activity associated with the job. Defined terms such as those in O*net may be used, but note that there is no way to specify the level of ability as well as its nature when using a defined term. - physiologicalBenefits: ( - URIRef # Specific physiologic benefits associated to the plan. - ) - pickupLocation: URIRef # Where a taxi will pick up a passenger or a rental car can be picked up. - pickupTime: ( - URIRef # When a taxi will pickup a passenger or a rental car can be picked up. - ) - playMode: URIRef # Indicates whether this game is multi-player, co-op or single-player. The game can be marked as multi-player, co-op and single-player at the same time. - playerType: URIRef # Player type required—for example, Flash or Silverlight. - playersOnline: URIRef # Number of players on the server. - polygon: URIRef # A polygon is the area enclosed by a point-to-point path for which the starting and ending points are the same. A polygon is expressed as a series of four or more space delimited points where the first and final points are identical. - populationType: URIRef # Indicates the populationType common to all members of a [[StatisticalPopulation]]. - position: URIRef # The position of an item in a series or sequence of items. - positiveNotes: URIRef # Indicates, in the context of a [[Review]] (e.g. framed as 'pro' vs 'con' considerations), positive considerations - either as unstructured text, or a list. - possibleComplication: URIRef # A possible unexpected and unfavorable evolution of a medical condition. Complications may include worsening of the signs or symptoms of the disease, extension of the condition to other organ systems, etc. - possibleTreatment: ( - URIRef # A possible treatment to address this condition, sign or symptom. - ) - postOfficeBoxNumber: URIRef # The post office box number for PO box addresses. - postOp: URIRef # A description of the postoperative procedures, care, and/or followups for this device. - postalCode: URIRef # The postal code. For example, 94043. - postalCodeBegin: URIRef # First postal code in a range (included). - postalCodeEnd: URIRef # Last postal code in the range (included). Needs to be after [[postalCodeBegin]]. - postalCodePrefix: URIRef # A defined range of postal codes indicated by a common textual prefix. Used for non-numeric systems such as UK. - postalCodeRange: URIRef # A defined range of postal codes. - potentialAction: URIRef # Indicates a potential Action, which describes an idealized action in which this thing would play an 'object' role. - potentialUse: URIRef # Intended use of the BioChemEntity by humans. - preOp: URIRef # A description of the workup, testing, and other preparations required before implanting this device. - predecessorOf: URIRef # A pointer from a previous, often discontinued variant of the product to its newer variant. - pregnancyCategory: URIRef # Pregnancy category of this drug. - pregnancyWarning: URIRef # Any precaution, guidance, contraindication, etc. related to this drug's use during pregnancy. - prepTime: URIRef # The length of time it takes to prepare the items to be used in instructions or a direction, in [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601). - preparation: URIRef # Typical preparation that a patient must undergo before having the procedure performed. - prescribingInfo: URIRef # Link to prescribing information for the drug. - prescriptionStatus: URIRef # Indicates the status of drug prescription eg. local catalogs classifications or whether the drug is available by prescription or over-the-counter, etc. - previousItem: URIRef # A link to the ListItem that preceeds the current one. - previousStartDate: URIRef # Used in conjunction with eventStatus for rescheduled or cancelled events. This property contains the previously scheduled start date. For rescheduled events, the startDate property should be used for the newly scheduled start date. In the (rare) case of an event that has been postponed and rescheduled multiple times, this field may be repeated. - price: URIRef # The offer price of a product, or of a price component when attached to PriceSpecification and its subtypes.\n\nUsage guidelines:\n\n* Use the [[priceCurrency]] property (with standard formats: [ISO 4217 currency format](http://en.wikipedia.org/wiki/ISO_4217) e.g. "USD"; [Ticker symbol](https://en.wikipedia.org/wiki/List_of_cryptocurrencies) for cryptocurrencies e.g. "BTC"; well known names for [Local Exchange Tradings Systems](https://en.wikipedia.org/wiki/Local_exchange_trading_system) (LETS) and other currency types e.g. "Ithaca HOUR") instead of including [ambiguous symbols](http://en.wikipedia.org/wiki/Dollar_sign#Currencies_that_use_the_dollar_or_peso_sign) such as '$' in the value.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator.\n* Note that both [RDFa](http://www.w3.org/TR/xhtml-rdfa-primer/#using-the-content-attribute) and Microdata syntax allow the use of a "content=" attribute for publishing simple machine-readable values alongside more human-friendly formatting.\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols. - priceComponent: URIRef # This property links to all [[UnitPriceSpecification]] nodes that apply in parallel for the [[CompoundPriceSpecification]] node. - priceComponentType: URIRef # Identifies a price component (for example, a line item on an invoice), part of the total price for an offer. - priceCurrency: URIRef # The currency of the price, or a price component when attached to [[PriceSpecification]] and its subtypes.\n\nUse standard formats: [ISO 4217 currency format](http://en.wikipedia.org/wiki/ISO_4217) e.g. "USD"; [Ticker symbol](https://en.wikipedia.org/wiki/List_of_cryptocurrencies) for cryptocurrencies e.g. "BTC"; well known names for [Local Exchange Tradings Systems](https://en.wikipedia.org/wiki/Local_exchange_trading_system) (LETS) and other currency types e.g. "Ithaca HOUR". - priceRange: URIRef # The price range of the business, for example ```$$$```. - priceSpecification: URIRef # One or more detailed price specifications, indicating the unit price and delivery or payment charges. - priceType: URIRef # Defines the type of a price specified for an offered product, for example a list price, a (temporary) sale price or a manufacturer suggested retail price. If multiple prices are specified for an offer the [[priceType]] property can be used to identify the type of each such specified price. The value of priceType can be specified as a value from enumeration PriceTypeEnumeration or as a free form text string for price types that are not already predefined in PriceTypeEnumeration. - priceValidUntil: URIRef # The date after which the price is no longer available. - primaryImageOfPage: URIRef # Indicates the main image on the page. - primaryPrevention: URIRef # A preventative therapy used to prevent an initial occurrence of the medical condition, such as vaccination. - printColumn: URIRef # The number of the column in which the NewsArticle appears in the print edition. - printEdition: ( - URIRef # The edition of the print product in which the NewsArticle appears. - ) - printPage: URIRef # If this NewsArticle appears in print, this field indicates the name of the page on which the article is found. Please note that this field is intended for the exact page name (e.g. A5, B18). - printSection: URIRef # If this NewsArticle appears in print, this field indicates the print section in which the article appeared. - procedure: URIRef # A description of the procedure involved in setting up, using, and/or installing the device. - procedureType: URIRef # The type of procedure, for example Surgical, Noninvasive, or Percutaneous. - processingTime: ( - URIRef # Estimated processing time for the service using this channel. - ) - processorRequirements: ( - URIRef # Processor architecture required to run the application (e.g. IA64). - ) - producer: URIRef # The person or organization who produced the work (e.g. music album, movie, tv/radio series etc.). - produces: URIRef # The tangible thing generated by the service, e.g. a passport, permit, etc. - productGroupID: URIRef # Indicates a textual identifier for a ProductGroup. - productID: URIRef # The product identifier, such as ISBN. For example: ``` meta itemprop="productID" content="isbn:123-456-789" ```. - productSupported: URIRef # The product or service this support contact point is related to (such as product support for a particular product line). This can be a specific product or product line (e.g. "iPhone") or a general category of products or services (e.g. "smartphones"). - productionCompany: URIRef # The production company or studio responsible for the item e.g. series, video game, episode etc. - productionDate: URIRef # The date of production of the item, e.g. vehicle. - proficiencyLevel: URIRef # Proficiency needed for this content; expected values: 'Beginner', 'Expert'. - programMembershipUsed: URIRef # Any membership in a frequent flyer, hotel loyalty program, etc. being applied to the reservation. - programName: URIRef # The program providing the membership. - programPrerequisites: URIRef # Prerequisites for enrolling in the program. - programType: URIRef # The type of educational or occupational program. For example, classroom, internship, alternance, etc.. - programmingLanguage: URIRef # The computer programming language. - programmingModel: URIRef # Indicates whether API is managed or unmanaged. - propertyID: URIRef # A commonly used identifier for the characteristic represented by the property, e.g. a manufacturer or a standard code for a property. propertyID can be (1) a prefixed string, mainly meant to be used with standards for product properties; (2) a site-specific, non-prefixed string (e.g. the primary key of the property or the vendor-specific id of the property), or (3) a URL indicating the type of the property, either pointing to an external vocabulary, or a Web resource that describes the property (e.g. a glossary entry). Standards bodies should promote a standard prefix for the identifiers of properties from their standards. - proprietaryName: URIRef # Proprietary name given to the diet plan, typically by its originator or creator. - proteinContent: URIRef # The number of grams of protein. - provider: URIRef # The service provider, service operator, or service performer; the goods producer. Another party (a seller) may offer those services or goods on behalf of the provider. A provider may also serve as the seller. - providerMobility: URIRef # Indicates the mobility of a provided service (e.g. 'static', 'dynamic'). - providesBroadcastService: URIRef # The BroadcastService offered on this channel. - providesService: URIRef # The service provided by this channel. - publicAccess: URIRef # A flag to signal that the [[Place]] is open to public visitors. If this property is omitted there is no assumed default boolean value - publicTransportClosuresInfo: URIRef # Information about public transport closures. - publication: URIRef # A publication event associated with the item. - publicationType: URIRef # The type of the medical article, taken from the US NLM MeSH publication type catalog. See also [MeSH documentation](http://www.nlm.nih.gov/mesh/pubtypes.html). - publishedBy: URIRef # An agent associated with the publication event. - publishedOn: URIRef # A broadcast service associated with the publication event. - publisher: URIRef # The publisher of the creative work. - publisherImprint: URIRef # The publishing division which published the comic. - publishingPrinciples: URIRef # The publishingPrinciples property indicates (typically via [[URL]]) a document describing the editorial principles of an [[Organization]] (or individual e.g. a [[Person]] writing a blog) that relate to their activities as a publisher, e.g. ethics or diversity policies. When applied to a [[CreativeWork]] (e.g. [[NewsArticle]]) the principles are those of the party primarily responsible for the creation of the [[CreativeWork]]. While such policies are most typically expressed in natural language, sometimes related information (e.g. indicating a [[funder]]) can be expressed using schema.org terminology. - purchaseDate: ( - URIRef # The date the item e.g. vehicle was purchased by the current owner. - ) - qualifications: ( - URIRef # Specific qualifications required for this role or Occupation. - ) - quarantineGuidelines: ( - URIRef # Guidelines about quarantine rules, e.g. in the context of a pandemic. - ) - query: URIRef # A sub property of instrument. The query used on this action. - quest: URIRef # The task that a player-controlled character, or group of characters may complete in order to gain a reward. - question: URIRef # A sub property of object. A question. - rangeIncludes: URIRef # Relates a property to a class that constitutes (one of) the expected type(s) for values of the property. - ratingCount: URIRef # The count of total number of ratings. - ratingExplanation: URIRef # A short explanation (e.g. one to two sentences) providing background context and other information that led to the conclusion expressed in the rating. This is particularly applicable to ratings associated with "fact check" markup using [[ClaimReview]]. - ratingValue: URIRef # The rating for the content.\n\nUsage guidelines:\n\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - readBy: URIRef # A person who reads (performs) the audiobook. - readonlyValue: URIRef # Whether or not a property is mutable. Default is false. Specifying this for a property that also has a value makes it act similar to a "hidden" input in an HTML form. - realEstateAgent: URIRef # A sub property of participant. The real estate agent involved in the action. - recipe: URIRef # A sub property of instrument. The recipe/instructions used to perform the action. - recipeCategory: ( - URIRef # The category of the recipe—for example, appetizer, entree, etc. - ) - recipeCuisine: ( - URIRef # The cuisine of the recipe (for example, French or Ethiopian). - ) - recipeIngredient: ( - URIRef # A single ingredient used in the recipe, e.g. sugar, flour or garlic. - ) - recipeInstructions: URIRef # A step in making the recipe, in the form of a single item (document, video, etc.) or an ordered list with HowToStep and/or HowToSection items. - recipeYield: URIRef # The quantity produced by the recipe (for example, number of people served, number of servings, etc). - recipient: URIRef # A sub property of participant. The participant who is at the receiving end of the action. - recognizedBy: URIRef # An organization that acknowledges the validity, value or utility of a credential. Note: recognition may include a process of quality assurance or accreditation. - recognizingAuthority: URIRef # If applicable, the organization that officially recognizes this entity as part of its endorsed system of medicine. - recommendationStrength: ( - URIRef # Strength of the guideline's recommendation (e.g. 'class I'). - ) - recommendedIntake: URIRef # Recommended intake of this supplement for a given population as defined by a specific recommending authority. - recordLabel: URIRef # The label that issued the release. - recordedAs: URIRef # An audio recording of the work. - recordedAt: URIRef # The Event where the CreativeWork was recorded. The CreativeWork may capture all or part of the event. - recordedIn: URIRef # The CreativeWork that captured all or part of this Event. - recordingOf: URIRef # The composition this track is a recording of. - recourseLoan: URIRef # The only way you get the money back in the event of default is the security. Recourse is where you still have the opportunity to go back to the borrower for the rest of the money. - referenceQuantity: URIRef # The reference quantity for which a certain price applies, e.g. 1 EUR per 4 kWh of electricity. This property is a replacement for unitOfMeasurement for the advanced cases where the price does not relate to a standard unit. - referencesOrder: URIRef # The Order(s) related to this Invoice. One or more Orders may be combined into a single Invoice. - refundType: URIRef # A refund type, from an enumerated list. - regionDrained: URIRef # The anatomical or organ system drained by this vessel; generally refers to a specific part of an organ. - regionsAllowed: URIRef # The regions where the media is allowed. If not specified, then it's assumed to be allowed everywhere. Specify the countries in [ISO 3166 format](http://en.wikipedia.org/wiki/ISO_3166). - relatedAnatomy: URIRef # Anatomical systems or structures that relate to the superficial anatomy. - relatedCondition: URIRef # A medical condition associated with this anatomy. - relatedDrug: URIRef # Any other drug related to this one, for example commonly-prescribed alternatives. - relatedLink: URIRef # A link related to this web page, for example to other related web pages. - relatedStructure: URIRef # Related anatomical structure(s) that are not part of the system but relate or connect to it, such as vascular bundles associated with an organ system. - relatedTherapy: URIRef # A medical therapy related to this anatomy. - relatedTo: URIRef # The most generic familial relation. - releaseDate: URIRef # The release date of a product or product model. This can be used to distinguish the exact variant of a product. - releaseNotes: URIRef # Description of what changed in this version. - releaseOf: URIRef # The album this is a release of. - releasedEvent: URIRef # The place and time the release was issued, expressed as a PublicationEvent. - relevantOccupation: URIRef # The Occupation for the JobPosting. - relevantSpecialty: ( - URIRef # If applicable, a medical specialty in which this entity is relevant. - ) - remainingAttendeeCapacity: ( - URIRef # The number of attendee places for an event that remain unallocated. - ) - renegotiableLoan: URIRef # Whether the terms for payment of interest can be renegotiated during the life of the loan. - repeatCount: ( - URIRef # Defines the number of times a recurring [[Event]] will take place - ) - repeatFrequency: URIRef # Defines the frequency at which [[Event]]s will occur according to a schedule [[Schedule]]. The intervals between events should be defined as a [[Duration]] of time. - repetitions: URIRef # Number of times one should repeat the activity. - replacee: URIRef # A sub property of object. The object that is being replaced. - replacer: URIRef # A sub property of object. The object that replaces. - replyToUrl: ( - URIRef # The URL at which a reply may be posted to the specified UserComment. - ) - reportNumber: URIRef # The number or other unique designator assigned to a Report by the publishing organization. - representativeOfPage: URIRef # Indicates whether this image is representative of the content of the page. - requiredCollateral: URIRef # Assets required to secure loan or credit repayments. It may take form of third party pledge, goods, financial instruments (cash, securities, etc.) - requiredGender: URIRef # Audiences defined by a person's gender. - requiredMaxAge: URIRef # Audiences defined by a person's maximum age. - requiredMinAge: URIRef # Audiences defined by a person's minimum age. - requiredQuantity: URIRef # The required quantity of the item(s). - requirements: URIRef # Component dependency requirements for application. This includes runtime environments and shared libraries that are not included in the application distribution package, but required to run the application (Examples: DirectX, Java or .NET runtime). - requiresSubscription: URIRef # Indicates if use of the media require a subscription (either paid or free). Allowed values are ```true``` or ```false``` (note that an earlier version had 'yes', 'no'). - reservationFor: ( - URIRef # The thing -- flight, event, restaurant,etc. being reserved. - ) - reservationId: URIRef # A unique identifier for the reservation. - reservationStatus: URIRef # The current status of the reservation. - reservedTicket: URIRef # A ticket associated with the reservation. - responsibilities: ( - URIRef # Responsibilities associated with this role or Occupation. - ) - restPeriods: URIRef # How often one should break from the activity. - restockingFee: URIRef # Use [[MonetaryAmount]] to specify a fixed restocking fee for product returns, or use [[Number]] to specify a percentage of the product price paid by the customer. - result: URIRef # The result produced in the action. e.g. John wrote *a book*. - resultComment: URIRef # A sub property of result. The Comment created or sent as a result of this action. - resultReview: URIRef # A sub property of result. The review that resulted in the performing of the action. - returnFees: ( - URIRef # The type of return fees for purchased products (for any return reason) - ) - returnLabelSource: URIRef # The method (from an enumeration) by which the customer obtains a return shipping label for a product returned for any reason. - returnMethod: ( - URIRef # The type of return method offered, specified from an enumeration. - ) - returnPolicyCategory: ( - URIRef # Specifies an applicable return policy (from an enumeration). - ) - returnPolicyCountry: URIRef # The country where the product has to be sent to for returns, for example "Ireland" using the [[name]] property of [[Country]]. You can also provide the two-letter [ISO 3166-1 alpha-2 country code](http://en.wikipedia.org/wiki/ISO_3166-1). Note that this can be different from the country where the product was originally shipped from or sent too. - returnPolicySeasonalOverride: URIRef # Seasonal override of a return policy. - returnShippingFeesAmount: URIRef # Amount of shipping costs for product returns (for any reason). Applicable when property [[returnFees]] equals [[ReturnShippingFees]]. - review: URIRef # A review of the item. - reviewAspect: URIRef # This Review or Rating is relevant to this part or facet of the itemReviewed. - reviewBody: URIRef # The actual body of the review. - reviewCount: URIRef # The count of total number of reviews. - reviewRating: URIRef # The rating given in this review. Note that reviews can themselves be rated. The ```reviewRating``` applies to rating given by the review. The [[aggregateRating]] property applies to the review itself, as a creative work. - reviewedBy: URIRef # People or organizations that have reviewed the content on this web page for accuracy and/or completeness. - reviews: URIRef # Review of the item. - riskFactor: URIRef # A modifiable or non-modifiable factor that increases the risk of a patient contracting this condition, e.g. age, coexisting condition. - risks: URIRef # Specific physiologic risks associated to the diet plan. - roleName: URIRef # A role played, performed or filled by a person or organization. For example, the team of creators for a comic book might fill the roles named 'inker', 'penciller', and 'letterer'; or an athlete in a SportsTeam might play in the position named 'Quarterback'. - roofLoad: URIRef # The permitted total weight of cargo and installations (e.g. a roof rack) on top of the vehicle.\n\nTypical unit code(s): KGM for kilogram, LBR for pound\n\n* Note 1: You can indicate additional information in the [[name]] of the [[QuantitativeValue]] node.\n* Note 2: You may also link to a [[QualitativeValue]] node that provides additional information using [[valueReference]]\n* Note 3: Note that you can use [[minValue]] and [[maxValue]] to indicate ranges. - rsvpResponse: URIRef # The response (yes, no, maybe) to the RSVP. - runsTo: URIRef # The vasculature the lymphatic structure runs, or efferents, to. - runtime: URIRef # Runtime platform or script interpreter dependencies (Example - Java v1, Python2.3, .Net Framework 3.0). - runtimePlatform: URIRef # Runtime platform or script interpreter dependencies (Example - Java v1, Python2.3, .Net Framework 3.0). - rxcui: URIRef # The RxCUI drug identifier from RXNORM. - safetyConsideration: URIRef # Any potential safety concern associated with the supplement. May include interactions with other drugs and foods, pregnancy, breastfeeding, known adverse reactions, and documented efficacy of the supplement. - salaryCurrency: URIRef # The currency (coded using [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) ) used for the main salary information in this job posting or for this employee. - salaryUponCompletion: URIRef # The expected salary upon completing the training. - sameAs: URIRef # URL of a reference Web page that unambiguously indicates the item's identity. E.g. the URL of the item's Wikipedia page, Wikidata entry, or official website. - sampleType: URIRef # What type of code sample: full (compile ready) solution, code snippet, inline code, scripts, template. - saturatedFatContent: URIRef # The number of grams of saturated fat. - scheduleTimezone: URIRef # Indicates the timezone for which the time(s) indicated in the [[Schedule]] are given. The value provided should be among those listed in the IANA Time Zone Database. - scheduledPaymentDate: URIRef # The date the invoice is scheduled to be paid. - scheduledTime: URIRef # The time the object is scheduled to. - schemaVersion: URIRef # Indicates (by URL or string) a particular version of a schema used in some CreativeWork. This property was created primarily to indicate the use of a specific schema.org release, e.g. ```10.0``` as a simple string, or more explicitly via URL, ```https://schema.org/docs/releases.html#v10.0```. There may be situations in which other schemas might usefully be referenced this way, e.g. ```http://dublincore.org/specifications/dublin-core/dces/1999-07-02/``` but this has not been carefully explored in the community. - schoolClosuresInfo: URIRef # Information about school closures. - screenCount: URIRef # The number of screens in the movie theater. - screenshot: URIRef # A link to a screenshot image of the app. - sdDatePublished: URIRef # Indicates the date on which the current structured data was generated / published. Typically used alongside [[sdPublisher]] - sdLicense: URIRef # A license document that applies to this structured data, typically indicated by URL. - sdPublisher: URIRef # Indicates the party responsible for generating and publishing the current structured data markup, typically in cases where the structured data is derived automatically from existing published content but published on a different site. For example, student projects and open data initiatives often re-publish existing content with more explicitly structured metadata. The [[sdPublisher]] property helps make such practices more explicit. - season: URIRef # A season in a media series. - seasonNumber: URIRef # Position of the season within an ordered group of seasons. - seasons: URIRef # A season in a media series. - seatNumber: URIRef # The location of the reserved seat (e.g., 27). - seatRow: URIRef # The row location of the reserved seat (e.g., B). - seatSection: URIRef # The section location of the reserved seat (e.g. Orchestra). - seatingCapacity: URIRef # The number of persons that can be seated (e.g. in a vehicle), both in terms of the physical space available, and in terms of limitations set by law.\n\nTypical unit code(s): C62 for persons - seatingType: URIRef # The type/class of the seat. - secondaryPrevention: URIRef # A preventative therapy used to prevent reoccurrence of the medical condition after an initial episode of the condition. - securityClearanceRequirement: ( - URIRef # A description of any security clearance requirements of the job. - ) - securityScreening: ( - URIRef # The type of security screening the passenger is subject to. - ) - seeks: URIRef # A pointer to products or services sought by the organization or person (demand). - seller: URIRef # An entity which offers (sells / leases / lends / loans) the services / goods. A seller may also be a provider. - sender: URIRef # A sub property of participant. The participant who is at the sending end of the action. - sensoryRequirement: URIRef # A description of any sensory requirements and levels necessary to function on the job, including hearing and vision. Defined terms such as those in O*net may be used, but note that there is no way to specify the level of ability as well as its nature when using a defined term. - sensoryUnit: URIRef # The neurological pathway extension that inputs and sends information to the brain or spinal cord. - serialNumber: URIRef # The serial number or any alphanumeric identifier of a particular product. When attached to an offer, it is a shortcut for the serial number of the product included in the offer. - seriousAdverseOutcome: URIRef # A possible serious complication and/or serious side effect of this therapy. Serious adverse outcomes include those that are life-threatening; result in death, disability, or permanent damage; require hospitalization or prolong existing hospitalization; cause congenital anomalies or birth defects; or jeopardize the patient and may require medical or surgical intervention to prevent one of the outcomes in this definition. - serverStatus: URIRef # Status of a game server. - servesCuisine: URIRef # The cuisine of the restaurant. - serviceArea: URIRef # The geographic area where the service is provided. - serviceAudience: URIRef # The audience eligible for this service. - serviceLocation: URIRef # The location (e.g. civic structure, local business, etc.) where a person can go to access the service. - serviceOperator: URIRef # The operating organization, if different from the provider. This enables the representation of services that are provided by an organization, but operated by another organization like a subcontractor. - serviceOutput: URIRef # The tangible thing generated by the service, e.g. a passport, permit, etc. - servicePhone: URIRef # The phone number to use to access the service. - servicePostalAddress: URIRef # The address for accessing the service by mail. - serviceSmsNumber: URIRef # The number to access the service by text message. - serviceType: URIRef # The type of service being offered, e.g. veterans' benefits, emergency relief, etc. - serviceUrl: URIRef # The website to access the service. - servingSize: URIRef # The serving size, in terms of the number of volume or mass. - sha256: URIRef # The [SHA-2](https://en.wikipedia.org/wiki/SHA-2) SHA256 hash of the content of the item. For example, a zero-length input has value 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' - sharedContent: URIRef # A CreativeWork such as an image, video, or audio clip shared as part of this posting. - shippingDestination: URIRef # indicates (possibly multiple) shipping destinations. These can be defined in several ways e.g. postalCode ranges. - shippingDetails: URIRef # Indicates information about the shipping policies and options associated with an [[Offer]]. - shippingLabel: URIRef # Label to match an [[OfferShippingDetails]] with a [[ShippingRateSettings]] (within the context of a [[shippingSettingsLink]] cross-reference). - shippingRate: URIRef # The shipping rate is the cost of shipping to the specified destination. Typically, the maxValue and currency values (of the [[MonetaryAmount]]) are most appropriate. - shippingSettingsLink: URIRef # Link to a page containing [[ShippingRateSettings]] and [[DeliveryTimeSettings]] details. - sibling: URIRef # A sibling of the person. - siblings: URIRef # A sibling of the person. - signDetected: URIRef # A sign detected by the test. - signOrSymptom: URIRef # A sign or symptom of this condition. Signs are objective or physically observable manifestations of the medical condition while symptoms are the subjective experience of the medical condition. - significance: URIRef # The significance associated with the superficial anatomy; as an example, how characteristics of the superficial anatomy can suggest underlying medical conditions or courses of treatment. - significantLink: URIRef # One of the more significant URLs on the page. Typically, these are the non-navigation links that are clicked on the most. - significantLinks: URIRef # The most significant URLs on the page. Typically, these are the non-navigation links that are clicked on the most. - size: URIRef # A standardized size of a product or creative work, specified either through a simple textual string (for example 'XL', '32Wx34L'), a QuantitativeValue with a unitCode, or a comprehensive and structured [[SizeSpecification]]; in other cases, the [[width]], [[height]], [[depth]] and [[weight]] properties may be more applicable. - sizeGroup: URIRef # The size group (also known as "size type") for a product's size. Size groups are common in the fashion industry to define size segments and suggested audiences for wearable products. Multiple values can be combined, for example "men's big and tall", "petite maternity" or "regular" - sizeSystem: URIRef # The size system used to identify a product's size. Typically either a standard (for example, "GS1" or "ISO-EN13402"), country code (for example "US" or "JP"), or a measuring system (for example "Metric" or "Imperial"). - skills: URIRef # A statement of knowledge, skill, ability, task or any other assertion expressing a competency that is desired or required to fulfill this role or to work in this occupation. - sku: URIRef # The Stock Keeping Unit (SKU), i.e. a merchant-specific identifier for a product or service, or the product to which the offer refers. - slogan: URIRef # A slogan or motto associated with the item. - smiles: URIRef # A specification in form of a line notation for describing the structure of chemical species using short ASCII strings. Double bond stereochemistry \ indicators may need to be escaped in the string in formats where the backslash is an escape character. - smokingAllowed: URIRef # Indicates whether it is allowed to smoke in the place, e.g. in the restaurant, hotel or hotel room. - sodiumContent: URIRef # The number of milligrams of sodium. - softwareAddOn: URIRef # Additional content for a software application. - softwareHelp: URIRef # Software application help. - softwareRequirements: URIRef # Component dependency requirements for application. This includes runtime environments and shared libraries that are not included in the application distribution package, but required to run the application (Examples: DirectX, Java or .NET runtime). - softwareVersion: URIRef # Version of the software instance. - sourceOrganization: ( - URIRef # The Organization on whose behalf the creator was working. - ) - sourcedFrom: URIRef # The neurological pathway that originates the neurons. - spatial: URIRef # The "spatial" property can be used in cases when more specific properties (e.g. [[locationCreated]], [[spatialCoverage]], [[contentLocation]]) are not known to be appropriate. - spatialCoverage: URIRef # The spatialCoverage of a CreativeWork indicates the place(s) which are the focus of the content. It is a subproperty of contentLocation intended primarily for more technical and detailed materials. For example with a Dataset, it indicates areas that the dataset describes: a dataset of New York weather would have spatialCoverage which was the place: the state of New York. - speakable: URIRef # Indicates sections of a Web page that are particularly 'speakable' in the sense of being highlighted as being especially appropriate for text-to-speech conversion. Other sections of a page may also be usefully spoken in particular circumstances; the 'speakable' property serves to indicate the parts most likely to be generally useful for speech. The *speakable* property can be repeated an arbitrary number of times, with three kinds of possible 'content-locator' values: 1.) *id-value* URL references - uses *id-value* of an element in the page being annotated. The simplest use of *speakable* has (potentially relative) URL values, referencing identified sections of the document concerned. 2.) CSS Selectors - addresses content in the annotated page, eg. via class attribute. Use the [[cssSelector]] property. 3.) XPaths - addresses content via XPaths (assuming an XML view of the content). Use the [[xpath]] property. For more sophisticated markup of speakable sections beyond simple ID references, either CSS selectors or XPath expressions to pick out document section(s) as speakable. For this we define a supporting type, [[SpeakableSpecification]] which is defined to be a possible value of the *speakable* property. - specialCommitments: URIRef # Any special commitments associated with this job posting. Valid entries include VeteranCommit, MilitarySpouseCommit, etc. - specialOpeningHoursSpecification: URIRef # The special opening hours of a certain place.\n\nUse this to explicitly override general opening hours brought in scope by [[openingHoursSpecification]] or [[openingHours]]. - specialty: URIRef # One of the domain specialities to which this web page's content applies. - speechToTextMarkup: URIRef # Form of markup used. eg. [SSML](https://www.w3.org/TR/speech-synthesis11) or [IPA](https://www.wikidata.org/wiki/Property:P898). - speed: URIRef # The speed range of the vehicle. If the vehicle is powered by an engine, the upper limit of the speed range (indicated by [[maxValue]] should be the maximum speed achievable under regular conditions.\n\nTypical unit code(s): KMH for km/h, HM for mile per hour (0.447 04 m/s), KNT for knot\n\n*Note 1: Use [[minValue]] and [[maxValue]] to indicate the range. Typically, the minimal value is zero.\n* Note 2: There are many different ways of measuring the speed range. You can link to information about how the given value has been determined using the [[valueReference]] property. - spokenByCharacter: URIRef # The (e.g. fictional) character, Person or Organization to whom the quotation is attributed within the containing CreativeWork. - sponsor: URIRef # A person or organization that supports a thing through a pledge, promise, or financial contribution. e.g. a sponsor of a Medical Study or a corporate sponsor of an event. - sport: URIRef # A type of sport (e.g. Baseball). - sportsActivityLocation: URIRef # A sub property of location. The sports activity location where this action occurred. - sportsEvent: URIRef # A sub property of location. The sports event where this action occurred. - sportsTeam: URIRef # A sub property of participant. The sports team that participated on this action. - spouse: URIRef # The person's spouse. - stage: URIRef # The stage of the condition, if applicable. - stageAsNumber: URIRef # The stage represented as a number, e.g. 3. - starRating: URIRef # An official rating for a lodging business or food establishment, e.g. from national associations or standards bodies. Use the author property to indicate the rating organization, e.g. as an Organization with name such as (e.g. HOTREC, DEHOGA, WHR, or Hotelstars). - startDate: URIRef # The start date and time of the item (in [ISO 8601 date format](http://en.wikipedia.org/wiki/ISO_8601)). - startOffset: URIRef # The start time of the clip expressed as the number of seconds from the beginning of the work. - startTime: URIRef # The startTime of something. For a reserved event or service (e.g. FoodEstablishmentReservation), the time that it is expected to start. For actions that span a period of time, when the action was performed. e.g. John wrote a book from *January* to December. For media, including audio and video, it's the time offset of the start of a clip within a larger file.\n\nNote that Event uses startDate/endDate instead of startTime/endTime, even when describing dates with times. This situation may be clarified in future revisions. - status: URIRef # The status of the study (enumerated). - steeringPosition: URIRef # The position of the steering wheel or similar device (mostly for cars). - step: URIRef # A single step item (as HowToStep, text, document, video, etc.) or a HowToSection. - stepValue: URIRef # The stepValue attribute indicates the granularity that is expected (and required) of the value in a PropertyValueSpecification. - steps: URIRef # A single step item (as HowToStep, text, document, video, etc.) or a HowToSection (originally misnamed 'steps'; 'step' is preferred). - storageRequirements: URIRef # Storage requirements (free space required). - streetAddress: URIRef # The street address. For example, 1600 Amphitheatre Pkwy. - strengthUnit: URIRef # The units of an active ingredient's strength, e.g. mg. - strengthValue: URIRef # The value of an active ingredient's strength, e.g. 325. - structuralClass: ( - URIRef # The name given to how bone physically connects to each other. - ) - study: URIRef # A medical study or trial related to this entity. - studyDesign: URIRef # Specifics about the observational study design (enumerated). - studyLocation: URIRef # The location in which the study is taking/took place. - studySubject: URIRef # A subject of the study, i.e. one of the medical conditions, therapies, devices, drugs, etc. investigated by the study. - subEvent: URIRef # An Event that is part of this event. For example, a conference event includes many presentations, each of which is a subEvent of the conference. - subEvents: URIRef # Events that are a part of this event. For example, a conference event includes many presentations, each subEvents of the conference. - subOrganization: URIRef # A relationship between two organizations where the first includes the second, e.g., as a subsidiary. See also: the more specific 'department' property. - subReservation: URIRef # The individual reservations included in the package. Typically a repeated property. - subStageSuffix: URIRef # The substage, e.g. 'a' for Stage IIIa. - subStructure: ( - URIRef # Component (sub-)structure(s) that comprise this anatomical structure. - ) - subTest: URIRef # A component test of the panel. - subTrip: URIRef # Identifies a [[Trip]] that is a subTrip of this Trip. For example Day 1, Day 2, etc. of a multi-day trip. - subjectOf: URIRef # A CreativeWork or Event about this Thing. - subtitleLanguage: URIRef # Languages in which subtitles/captions are available, in [IETF BCP 47 standard format](http://tools.ietf.org/html/bcp47). - successorOf: URIRef # A pointer from a newer variant of a product to its previous, often discontinued predecessor. - sugarContent: URIRef # The number of grams of sugar. - suggestedAge: URIRef # The age or age range for the intended audience or person, for example 3-12 months for infants, 1-5 years for toddlers. - suggestedAnswer: URIRef # An answer (possibly one of several, possibly incorrect) to a Question, e.g. on a Question/Answer site. - suggestedGender: URIRef # The suggested gender of the intended person or audience, for example "male", "female", or "unisex". - suggestedMaxAge: ( - URIRef # Maximum recommended age in years for the audience or user. - ) - suggestedMeasurement: URIRef # A suggested range of body measurements for the intended audience or person, for example inseam between 32 and 34 inches or height between 170 and 190 cm. Typically found on a size chart for wearable products. - suggestedMinAge: ( - URIRef # Minimum recommended age in years for the audience or user. - ) - suitableForDiet: URIRef # Indicates a dietary restriction or guideline for which this recipe or menu item is suitable, e.g. diabetic, halal etc. - superEvent: URIRef # An event that this event is a part of. For example, a collection of individual music performances might each have a music festival as their superEvent. - supersededBy: URIRef # Relates a term (i.e. a property, class or enumeration) to one that supersedes it. - supply: URIRef # A sub-property of instrument. A supply consumed when performing instructions or a direction. - supplyTo: URIRef # The area to which the artery supplies blood. - supportingData: URIRef # Supporting data for a SoftwareApplication. - surface: URIRef # A material used as a surface in some artwork, e.g. Canvas, Paper, Wood, Board, etc. - target: URIRef # Indicates a target EntryPoint for an Action. - targetCollection: ( - URIRef # A sub property of object. The collection target of the action. - ) - targetDescription: ( - URIRef # The description of a node in an established educational framework. - ) - targetName: URIRef # The name of a node in an established educational framework. - targetPlatform: ( - URIRef # Type of app development: phone, Metro style, desktop, XBox, etc. - ) - targetPopulation: URIRef # Characteristics of the population for which this is intended, or which typically uses it, e.g. 'adults'. - targetProduct: URIRef # Target Operating System / Product to which the code applies. If applies to several versions, just the product name can be used. - targetUrl: URIRef # The URL of a node in an established educational framework. - taxID: URIRef # The Tax / Fiscal ID of the organization or person, e.g. the TIN in the US or the CIF/NIF in Spain. - taxonRank: URIRef # The taxonomic rank of this taxon given preferably as a URI from a controlled vocabulary – (typically the ranks from TDWG TaxonRank ontology or equivalent Wikidata URIs). - taxonomicRange: URIRef # The taxonomic grouping of the organism that expresses, encodes, or in someway related to the BioChemEntity. - teaches: URIRef # The item being described is intended to help a person learn the competency or learning outcome defined by the referenced term. - telephone: URIRef # The telephone number. - temporal: URIRef # The "temporal" property can be used in cases where more specific properties (e.g. [[temporalCoverage]], [[dateCreated]], [[dateModified]], [[datePublished]]) are not known to be appropriate. - temporalCoverage: URIRef # The temporalCoverage of a CreativeWork indicates the period that the content applies to, i.e. that it describes, either as a DateTime or as a textual string indicating a time period in [ISO 8601 time interval format](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals). In the case of a Dataset it will typically indicate the relevant time period in a precise notation (e.g. for a 2011 census dataset, the year 2011 would be written "2011/2012"). Other forms of content e.g. ScholarlyArticle, Book, TVSeries or TVEpisode may indicate their temporalCoverage in broader terms - textually or via well-known URL. Written works such as books may sometimes have precise temporal coverage too, e.g. a work set in 1939 - 1945 can be indicated in ISO 8601 interval format format via "1939/1945". Open-ended date ranges can be written with ".." in place of the end date. For example, "2015-11/.." indicates a range beginning in November 2015 and with no specified final date. This is tentative and might be updated in future when ISO 8601 is officially updated. - termCode: URIRef # A code that identifies this [[DefinedTerm]] within a [[DefinedTermSet]] - termDuration: URIRef # The amount of time in a term as defined by the institution. A term is a length of time where students take one or more classes. Semesters and quarters are common units for term. - termsOfService: URIRef # Human-readable terms of service documentation. - termsPerYear: URIRef # The number of times terms of study are offered per year. Semesters and quarters are common units for term. For example, if the student can only take 2 semesters for the program in one year, then termsPerYear should be 2. - text: URIRef # The textual content of this CreativeWork. - textValue: URIRef # Text value being annotated. - thumbnail: URIRef # Thumbnail image for an image or video. - thumbnailUrl: URIRef # A thumbnail image relevant to the Thing. - tickerSymbol: URIRef # The exchange traded instrument associated with a Corporation object. The tickerSymbol is expressed as an exchange and an instrument name separated by a space character. For the exchange component of the tickerSymbol attribute, we recommend using the controlled vocabulary of Market Identifier Codes (MIC) specified in ISO15022. - ticketNumber: URIRef # The unique identifier for the ticket. - ticketToken: URIRef # Reference to an asset (e.g., Barcode, QR code image or PDF) usable for entrance. - ticketedSeat: URIRef # The seat associated with the ticket. - timeOfDay: ( - URIRef # The time of day the program normally runs. For example, "evenings". - ) - timeRequired: URIRef # Approximate or typical time it takes to work with or through this learning resource for the typical intended target audience, e.g. 'PT30M', 'PT1H25M'. - timeToComplete: URIRef # The expected length of time to complete the program if attending full-time. - tissueSample: URIRef # The type of tissue sample required for the test. - title: URIRef # The title of the job. - titleEIDR: URIRef # An [EIDR](https://eidr.org/) (Entertainment Identifier Registry) [[identifier]] representing at the most general/abstract level, a work of film or television. For example, the motion picture known as "Ghostbusters" has a titleEIDR of "10.5240/7EC7-228A-510A-053E-CBB8-J". This title (or work) may have several variants, which EIDR calls "edits". See [[editEIDR]]. Since schema.org types like [[Movie]] and [[TVEpisode]] can be used for both works and their multiple expressions, it is possible to use [[titleEIDR]] alone (for a general description), or alongside [[editEIDR]] for a more edit-specific description. - toLocation: URIRef # A sub property of location. The final location of the object or the agent after the action. - toRecipient: URIRef # A sub property of recipient. The recipient who was directly sent the message. - tocContinuation: URIRef # A [[HyperTocEntry]] can have a [[tocContinuation]] indicated, which is another [[HyperTocEntry]] that would be the default next item to play or render. - tocEntry: URIRef # Indicates a [[HyperTocEntry]] in a [[HyperToc]]. - tongueWeight: URIRef # The permitted vertical load (TWR) of a trailer attached to the vehicle. Also referred to as Tongue Load Rating (TLR) or Vertical Load Rating (VLR)\n\nTypical unit code(s): KGM for kilogram, LBR for pound\n\n* Note 1: You can indicate additional information in the [[name]] of the [[QuantitativeValue]] node.\n* Note 2: You may also link to a [[QualitativeValue]] node that provides additional information using [[valueReference]].\n* Note 3: Note that you can use [[minValue]] and [[maxValue]] to indicate ranges. - tool: URIRef # A sub property of instrument. An object used (but not consumed) when performing instructions or a direction. - torque: URIRef # The torque (turning force) of the vehicle's engine.\n\nTypical unit code(s): NU for newton metre (N m), F17 for pound-force per foot, or F48 for pound-force per inch\n\n* Note 1: You can link to information about how the given value has been determined (e.g. reference RPM) using the [[valueReference]] property.\n* Note 2: You can use [[minValue]] and [[maxValue]] to indicate ranges. - totalJobOpenings: URIRef # The number of positions open for this job posting. Use a positive integer. Do not use if the number of positions is unclear or not known. - totalPaymentDue: URIRef # The total amount due. - totalPrice: URIRef # The total price for the reservation or ticket, including applicable taxes, shipping, etc.\n\nUsage guidelines:\n\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - totalTime: URIRef # The total time required to perform instructions or a direction (including time to prepare the supplies), in [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601). - tourBookingPage: URIRef # A page providing information on how to book a tour of some [[Place]], such as an [[Accommodation]] or [[ApartmentComplex]] in a real estate setting, as well as other kinds of tours as appropriate. - touristType: URIRef # Attraction suitable for type(s) of tourist. eg. Children, visitors from a particular country, etc. - track: URIRef # A music recording (track)—usually a single song. If an ItemList is given, the list should contain items of type MusicRecording. - trackingNumber: URIRef # Shipper tracking number. - trackingUrl: URIRef # Tracking url for the parcel delivery. - tracks: URIRef # A music recording (track)—usually a single song. - trailer: URIRef # The trailer of a movie or tv/radio series, season, episode, etc. - trailerWeight: URIRef # The permitted weight of a trailer attached to the vehicle.\n\nTypical unit code(s): KGM for kilogram, LBR for pound\n* Note 1: You can indicate additional information in the [[name]] of the [[QuantitativeValue]] node.\n* Note 2: You may also link to a [[QualitativeValue]] node that provides additional information using [[valueReference]].\n* Note 3: Note that you can use [[minValue]] and [[maxValue]] to indicate ranges. - trainName: URIRef # The name of the train (e.g. The Orient Express). - trainNumber: URIRef # The unique identifier for the train. - trainingSalary: URIRef # The estimated salary earned while in the program. - transFatContent: URIRef # The number of grams of trans fat. - transcript: URIRef # If this MediaObject is an AudioObject or VideoObject, the transcript of that object. - transitTime: URIRef # The typical delay the order has been sent for delivery and the goods reach the final customer. Typical properties: minValue, maxValue, unitCode (d for DAY). - transitTimeLabel: URIRef # Label to match an [[OfferShippingDetails]] with a [[DeliveryTimeSettings]] (within the context of a [[shippingSettingsLink]] cross-reference). - translationOfWork: URIRef # The work that this work has been translated from. e.g. 物ç§èµ·æº is a translationOf “On the Origin of Species†- translator: URIRef # Organization or person who adapts a creative work to different languages, regional differences and technical requirements of a target market, or that translates during some event. - transmissionMethod: URIRef # How the disease spreads, either as a route or vector, for example 'direct contact', 'Aedes aegypti', etc. - travelBans: ( - URIRef # Information about travel bans, e.g. in the context of a pandemic. - ) - trialDesign: URIRef # Specifics about the trial design (enumerated). - tributary: URIRef # The anatomical or organ system that the vein flows into; a larger structure that the vein connects to. - typeOfBed: URIRef # The type of bed to which the BedDetail refers, i.e. the type of bed available in the quantity indicated by quantity. - typeOfGood: URIRef # The product that this structured value is referring to. - typicalAgeRange: URIRef # The typical expected age range, e.g. '7-9', '11-'. - typicalCreditsPerTerm: URIRef # The number of credits or units a full-time student would be expected to take in 1 term however 'term' is defined by the institution. - typicalTest: URIRef # A medical test typically performed given this condition. - underName: URIRef # The person or organization the reservation or ticket is for. - unitCode: URIRef # The unit of measurement given using the UN/CEFACT Common Code (3 characters) or a URL. Other codes than the UN/CEFACT Common Code may be used with a prefix followed by a colon. - unitText: URIRef # A string or text indicating the unit of measurement. Useful if you cannot provide a standard unit code for unitCode. - unnamedSourcesPolicy: URIRef # For an [[Organization]] (typically a [[NewsMediaOrganization]]), a statement about policy on use of unnamed sources and the decision process required. - unsaturatedFatContent: URIRef # The number of grams of unsaturated fat. - uploadDate: URIRef # Date when this media object was uploaded to this site. - upvoteCount: URIRef # The number of upvotes this question, answer or comment has received from the community. - url: URIRef # URL of the item. - urlTemplate: URIRef # An url template (RFC6570) that will be used to construct the target of the execution of the action. - usageInfo: URIRef # The schema.org [[usageInfo]] property indicates further information about a [[CreativeWork]]. This property is applicable both to works that are freely available and to those that require payment or other transactions. It can reference additional information e.g. community expectations on preferred linking and citation conventions, as well as purchasing details. For something that can be commercially licensed, usageInfo can provide detailed, resource-specific information about licensing options. This property can be used alongside the license property which indicates license(s) applicable to some piece of content. The usageInfo property can provide information about other licensing options, e.g. acquiring commercial usage rights for an image that is also available under non-commercial creative commons licenses. - usedToDiagnose: URIRef # A condition the test is used to diagnose. - userInteractionCount: URIRef # The number of interactions for the CreativeWork using the WebSite or SoftwareApplication. - usesDevice: URIRef # Device used to perform the test. - usesHealthPlanIdStandard: URIRef # The standard for interpreting thePlan ID. The preferred is "HIOS". See the Centers for Medicare & Medicaid Services for more details. - utterances: URIRef # Text of an utterances (spoken words, lyrics etc.) that occurs at a certain section of a media object, represented as a [[HyperTocEntry]]. - validFor: URIRef # The duration of validity of a permit or similar thing. - validFrom: URIRef # The date when the item becomes valid. - validIn: URIRef # The geographic area where a permit or similar thing is valid. - validThrough: URIRef # The date after when the item is not valid. For example the end of an offer, salary period, or a period of opening hours. - validUntil: URIRef # The date when the item is no longer valid. - value: URIRef # The value of the quantitative value or property value node.\n\n* For [[QuantitativeValue]] and [[MonetaryAmount]], the recommended type for values is 'Number'.\n* For [[PropertyValue]], it can be 'Text;', 'Number', 'Boolean', or 'StructuredValue'.\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similiar Unicode symbols.\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator. - valueAddedTaxIncluded: URIRef # Specifies whether the applicable value-added tax (VAT) is included in the price specification or not. - valueMaxLength: URIRef # Specifies the allowed range for number of characters in a literal value. - valueMinLength: URIRef # Specifies the minimum allowed range for number of characters in a literal value. - valueName: URIRef # Indicates the name of the PropertyValueSpecification to be used in URL templates and form encoding in a manner analogous to HTML's input@name. - valuePattern: URIRef # Specifies a regular expression for testing literal values according to the HTML spec. - valueReference: URIRef # A secondary value that provides additional information on the original value, e.g. a reference temperature or a type of measurement. - valueRequired: URIRef # Whether the property must be filled in to complete the action. Default is false. - variableMeasured: URIRef # The variableMeasured property can indicate (repeated as necessary) the variables that are measured in some dataset, either described as text or as pairs of identifier and description using PropertyValue. - variantCover: URIRef # A description of the variant cover for the issue, if the issue is a variant printing. For example, "Bryan Hitch Variant Cover" or "2nd Printing Variant". - variesBy: URIRef # Indicates the property or properties by which the variants in a [[ProductGroup]] vary, e.g. their size, color etc. Schema.org properties can be referenced by their short name e.g. "color"; terms defined elsewhere can be referenced with their URIs. - vatID: URIRef # The Value-added Tax ID of the organization or person. - vehicleConfiguration: URIRef # A short text indicating the configuration of the vehicle, e.g. '5dr hatchback ST 2.5 MT 225 hp' or 'limited edition'. - vehicleEngine: URIRef # Information about the engine or engines of the vehicle. - vehicleIdentificationNumber: URIRef # The Vehicle Identification Number (VIN) is a unique serial number used by the automotive industry to identify individual motor vehicles. - vehicleInteriorColor: ( - URIRef # The color or color combination of the interior of the vehicle. - ) - vehicleInteriorType: URIRef # The type or material of the interior of the vehicle (e.g. synthetic fabric, leather, wood, etc.). While most interior types are characterized by the material used, an interior type can also be based on vehicle usage or target audience. - vehicleModelDate: URIRef # The release date of a vehicle model (often used to differentiate versions of the same make and model). - vehicleSeatingCapacity: URIRef # The number of passengers that can be seated in the vehicle, both in terms of the physical space available, and in terms of limitations set by law.\n\nTypical unit code(s): C62 for persons. - vehicleSpecialUsage: URIRef # Indicates whether the vehicle has been used for special purposes, like commercial rental, driving school, or as a taxi. The legislation in many countries requires this information to be revealed when offering a car for sale. - vehicleTransmission: URIRef # The type of component used for transmitting the power from a rotating power source to the wheels or other relevant component(s) ("gearbox" for cars). - vendor: URIRef # 'vendor' is an earlier term for 'seller'. - verificationFactCheckingPolicy: URIRef # Disclosure about verification and fact-checking processes for a [[NewsMediaOrganization]] or other fact-checking [[Organization]]. - version: URIRef # The version of the CreativeWork embodied by a specified resource. - video: URIRef # An embedded video object. - videoFormat: URIRef # The type of screening or video broadcast used (e.g. IMAX, 3D, SD, HD, etc.). - videoFrameSize: URIRef # The frame size of the video. - videoQuality: URIRef # The quality of the video. - volumeNumber: URIRef # Identifies the volume of publication or multi-part work; for example, "iii" or "2". - warning: URIRef # Any FDA or other warnings about the drug (text or URL). - warranty: URIRef # The warranty promise(s) included in the offer. - warrantyPromise: URIRef # The warranty promise(s) included in the offer. - warrantyScope: URIRef # The scope of the warranty promise. - webCheckinTime: ( - URIRef # The time when a passenger can check into the flight online. - ) - webFeed: URIRef # The URL for a feed, e.g. associated with a podcast series, blog, or series of date-stamped updates. This is usually RSS or Atom. - weight: URIRef # The weight of the product or person. - weightTotal: URIRef # The permitted total weight of the loaded vehicle, including passengers and cargo and the weight of the empty vehicle.\n\nTypical unit code(s): KGM for kilogram, LBR for pound\n\n* Note 1: You can indicate additional information in the [[name]] of the [[QuantitativeValue]] node.\n* Note 2: You may also link to a [[QualitativeValue]] node that provides additional information using [[valueReference]].\n* Note 3: Note that you can use [[minValue]] and [[maxValue]] to indicate ranges. - wheelbase: URIRef # The distance between the centers of the front and rear wheels.\n\nTypical unit code(s): CMT for centimeters, MTR for meters, INH for inches, FOT for foot/feet - width: URIRef # The width of the item. - winner: URIRef # A sub property of participant. The winner of the action. - wordCount: URIRef # The number of words in the text of the Article. - workExample: URIRef # Example/instance/realization/derivation of the concept of this creative work. eg. The paperback edition, first edition, or eBook. - workFeatured: URIRef # A work featured in some event, e.g. exhibited in an ExhibitionEvent. Specific subproperties are available for workPerformed (e.g. a play), or a workPresented (a Movie at a ScreeningEvent). - workHours: URIRef # The typical working hours for this job (e.g. 1st shift, night shift, 8am-5pm). - workLocation: URIRef # A contact location for a person's place of work. - workPerformed: URIRef # A work performed in some event, for example a play performed in a TheaterEvent. - workPresented: URIRef # The movie presented during this event. - workTranslation: URIRef # A work that is a translation of the content of this work. e.g. 西éŠè¨˜ has an English workTranslation “Journey to the Westâ€,a German workTranslation “Monkeys Pilgerfahrt†and a Vietnamese translation Tây du ký bình khảo. - workload: URIRef # Quantitative measure of the physiologic output of the exercise; also referred to as energy expenditure. - worksFor: URIRef # Organizations that the person works for. - worstRating: URIRef # The lowest value allowed in this rating system. If worstRating is omitted, 1 is assumed. - xpath: URIRef # An XPath, e.g. of a [[SpeakableSpecification]] or [[WebPageElement]]. In the latter case, multiple matches within a page can constitute a single conceptual "Web page element". - yearBuilt: URIRef # The year an [[Accommodation]] was constructed. This corresponds to the [YearBuilt field in RESO](https://ddwiki.reso.org/display/DDW17/YearBuilt+Field). - yearlyRevenue: URIRef # The size of the business in annual revenue. - yearsInOperation: URIRef # The age of the business. - # yield: URIRef # The quantity that results by performing instructions. For example, a paper airplane, 10 personalized candles. diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SH.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SH.py deleted file mode 100644 index 5bcbbbb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SH.py +++ /dev/null @@ -1,293 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class SH(DefinedNamespace): - """ - W3C Shapes Constraint Language (SHACL) Vocabulary - - This vocabulary defines terms used in SHACL, the W3C Shapes Constraint Language. - - Generated from: https://www.w3.org/ns/shacl.ttl - Date: 2020-05-26 14:20:08.041103 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - alternativePath: URIRef # The (single) value of this property must be a list of path elements, representing the elements of alternative paths. - annotationProperty: URIRef # The annotation property that shall be set. - annotationValue: URIRef # The (default) values of the annotation property. - annotationVarName: URIRef # The name of the SPARQL variable from the SELECT clause that shall be used for the values. - ask: URIRef # The SPARQL ASK query to execute. - closed: URIRef # If set to true then the shape is closed. - condition: URIRef # The shapes that the focus nodes need to conform to before a rule is executed on them. - conforms: URIRef # True if the validation did not produce any validation results, and false otherwise. - construct: URIRef # The SPARQL CONSTRUCT query to execute. - datatype: URIRef # Specifies an RDF datatype that all value nodes must have. - deactivated: URIRef # If set to true then all nodes conform to this. - declare: URIRef # Links a resource with its namespace prefix declarations. - defaultValue: URIRef # A default value for a property, for example for user interface tools to pre-populate input fields. - description: URIRef # Human-readable descriptions for the property in the context of the surrounding shape. - detail: URIRef # Links a result with other results that provide more details, for example to describe violations against nested shapes. - disjoint: URIRef # Specifies a property where the set of values must be disjoint with the value nodes. - entailment: URIRef # An entailment regime that indicates what kind of inferencing is required by a shapes graph. - equals: URIRef # Specifies a property that must have the same values as the value nodes. - expression: URIRef # The node expression that must return true for the value nodes. - filterShape: ( - URIRef # The shape that all input nodes of the expression need to conform to. - ) - flags: ( - URIRef # An optional flag to be used with regular expression pattern matching. - ) - focusNode: URIRef # The focus node that was validated when the result was produced. - group: URIRef # Can be used to link to a property group to indicate that a property shape belongs to a group of related property shapes. - hasValue: URIRef # Specifies a value that must be among the value nodes. - ignoredProperties: URIRef # An optional RDF list of properties that are also permitted in addition to those explicitly enumerated via sh:property/sh:path. - intersection: URIRef # A list of node expressions that shall be intersected. - inversePath: URIRef # The (single) value of this property represents an inverse path (object to subject). - js: URIRef # Constraints expressed in JavaScript. - jsFunctionName: URIRef # The name of the JavaScript function to execute. - jsLibrary: URIRef # Declares which JavaScript libraries are needed to execute this. - jsLibraryURL: URIRef # Declares the URLs of a JavaScript library. This should be the absolute URL of a JavaScript file. Implementations may redirect those to local files. - labelTemplate: URIRef # Outlines how human-readable labels of instances of the associated Parameterizable shall be produced. The values can contain {?paramName} as placeholders for the actual values of the given parameter. - languageIn: ( - URIRef # Specifies a list of language tags that all value nodes must have. - ) - lessThan: URIRef # Specifies a property that must have smaller values than the value nodes. - lessThanOrEquals: URIRef # Specifies a property that must have smaller or equal values than the value nodes. - maxCount: ( - URIRef # Specifies the maximum number of values in the set of value nodes. - ) - maxExclusive: URIRef # Specifies the maximum exclusive value of each value node. - maxInclusive: URIRef # Specifies the maximum inclusive value of each value node. - maxLength: URIRef # Specifies the maximum string length of each value node. - message: URIRef # A human-readable message (possibly with placeholders for variables) explaining the cause of the result. - minCount: ( - URIRef # Specifies the minimum number of values in the set of value nodes. - ) - minExclusive: URIRef # Specifies the minimum exclusive value of each value node. - minInclusive: URIRef # Specifies the minimum inclusive value of each value node. - minLength: URIRef # Specifies the minimum string length of each value node. - name: URIRef # Human-readable labels for the property in the context of the surrounding shape. - namespace: URIRef # The namespace associated with a prefix in a prefix declaration. - node: URIRef # Specifies the node shape that all value nodes must conform to. - nodeKind: URIRef # Specifies the node kind (e.g. IRI or literal) each value node. - nodeValidator: URIRef # The validator(s) used to evaluate a constraint in the context of a node shape. - nodes: URIRef # The node expression producing the input nodes of a filter shape expression. - object: ( - URIRef # An expression producing the nodes that shall be inferred as objects. - ) - oneOrMorePath: URIRef # The (single) value of this property represents a path that is matched one or more times. - optional: URIRef # Indicates whether a parameter is optional. - order: URIRef # Specifies the relative order of this compared to its siblings. For example use 0 for the first, 1 for the second. - parameter: URIRef # The parameters of a function or constraint component. - path: URIRef # Specifies the property path of a property shape. - pattern: URIRef # Specifies a regular expression pattern that the string representations of the value nodes must match. - predicate: URIRef # An expression producing the properties that shall be inferred as predicates. - prefix: URIRef # The prefix of a prefix declaration. - prefixes: URIRef # The prefixes that shall be applied before parsing the associated SPARQL query. - property: URIRef # Links a shape to its property shapes. - propertyValidator: URIRef # The validator(s) used to evaluate a constraint in the context of a property shape. - qualifiedMaxCount: ( - URIRef # The maximum number of value nodes that can conform to the shape. - ) - qualifiedMinCount: ( - URIRef # The minimum number of value nodes that must conform to the shape. - ) - qualifiedValueShape: ( - URIRef # The shape that a specified number of values must conform to. - ) - qualifiedValueShapesDisjoint: URIRef # Can be used to mark the qualified value shape to be disjoint with its sibling shapes. - result: URIRef # The validation results contained in a validation report. - resultAnnotation: URIRef # Links a SPARQL validator with zero or more sh:ResultAnnotation instances, defining how to derive additional result properties based on the variables of the SELECT query. - resultMessage: URIRef # Human-readable messages explaining the cause of the result. - resultPath: URIRef # The path of a validation result, based on the path of the validated property shape. - resultSeverity: URIRef # The severity of the result, e.g. warning. - returnType: ( - URIRef # The expected type of values returned by the associated function. - ) - rule: URIRef # The rules linked to a shape. - select: URIRef # The SPARQL SELECT query to execute. - severity: URIRef # Defines the severity that validation results produced by a shape must have. Defaults to sh:Violation. - shapesGraph: ( - URIRef # Shapes graphs that should be used when validating this data graph. - ) - shapesGraphWellFormed: URIRef # If true then the validation engine was certain that the shapes graph has passed all SHACL syntax requirements during the validation process. - sourceConstraint: ( - URIRef # The constraint that was validated when the result was produced. - ) - sourceConstraintComponent: ( - URIRef # The constraint component that is the source of the result. - ) - sourceShape: URIRef # The shape that is was validated when the result was produced. - sparql: URIRef # Links a shape with SPARQL constraints. - subject: URIRef # An expression producing the resources that shall be inferred as subjects. - suggestedShapesGraph: URIRef # Suggested shapes graphs for this ontology. The values of this property may be used in the absence of specific sh:shapesGraph statements. - target: URIRef # Links a shape to a target specified by an extension language, for example instances of sh:SPARQLTarget. - targetClass: URIRef # Links a shape to a class, indicating that all instances of the class must conform to the shape. - targetNode: URIRef # Links a shape to individual nodes, indicating that these nodes must conform to the shape. - targetObjectsOf: URIRef # Links a shape to a property, indicating that all all objects of triples that have the given property as their predicate must conform to the shape. - targetSubjectsOf: URIRef # Links a shape to a property, indicating that all subjects of triples that have the given property as their predicate must conform to the shape. - union: URIRef # A list of node expressions that shall be used together. - uniqueLang: URIRef # Specifies whether all node values must have a unique (or no) language tag. - update: URIRef # The SPARQL UPDATE to execute. - validator: URIRef # The validator(s) used to evaluate constraints of either node or property shapes. - value: URIRef # An RDF node that has caused the result. - xone: URIRef # Specifies a list of shapes so that the value nodes must conform to exactly one of the shapes. - zeroOrMorePath: URIRef # The (single) value of this property represents a path that is matched zero or more times. - zeroOrOnePath: URIRef # The (single) value of this property represents a path that is matched zero or one times. - - # http://www.w3.org/2000/01/rdf-schema#Class - AbstractResult: URIRef # The base class of validation results, typically not instantiated directly. - ConstraintComponent: URIRef # The class of constraint components. - Function: URIRef # The class of SHACL functions. - JSConstraint: URIRef # The class of constraints backed by a JavaScript function. - JSExecutable: URIRef # Abstract base class of resources that declare an executable JavaScript. - JSFunction: URIRef # The class of SHACL functions that execute a JavaScript function when called. - JSLibrary: URIRef # Represents a JavaScript library, typically identified by one or more URLs of files to include. - JSRule: URIRef # The class of SHACL rules expressed using JavaScript. - JSTarget: URIRef # The class of targets that are based on JavaScript functions. - JSTargetType: URIRef # The (meta) class for parameterizable targets that are based on JavaScript functions. - JSValidator: URIRef # A SHACL validator based on JavaScript. This can be used to declare SHACL constraint components that perform JavaScript-based validation when used. - NodeKind: URIRef # The class of all node kinds, including sh:BlankNode, sh:IRI, sh:Literal or the combinations of these: sh:BlankNodeOrIRI, sh:BlankNodeOrLiteral, sh:IRIOrLiteral. - NodeShape: URIRef # A node shape is a shape that specifies constraint that need to be met with respect to focus nodes. - Parameter: URIRef # The class of parameter declarations, consisting of a path predicate and (possibly) information about allowed value type, cardinality and other characteristics. - Parameterizable: URIRef # Superclass of components that can take parameters, especially functions and constraint components. - PrefixDeclaration: URIRef # The class of prefix declarations, consisting of pairs of a prefix with a namespace. - PropertyGroup: URIRef # Instances of this class represent groups of property shapes that belong together. - PropertyShape: URIRef # A property shape is a shape that specifies constraints on the values of a focus node for a given property or path. - ResultAnnotation: URIRef # A class of result annotations, which define the rules to derive the values of a given annotation property as extra values for a validation result. - Rule: URIRef # The class of SHACL rules. Never instantiated directly. - SPARQLAskExecutable: ( - URIRef # The class of SPARQL executables that are based on an ASK query. - ) - SPARQLAskValidator: URIRef # The class of validators based on SPARQL ASK queries. The queries are evaluated for each value node and are supposed to return true if the given node conforms. - SPARQLConstraint: URIRef # The class of constraints based on SPARQL SELECT queries. - SPARQLConstructExecutable: ( - URIRef # The class of SPARQL executables that are based on a CONSTRUCT query. - ) - SPARQLExecutable: URIRef # The class of resources that encapsulate a SPARQL query. - SPARQLFunction: ( - URIRef # A function backed by a SPARQL query - either ASK or SELECT. - ) - SPARQLRule: URIRef # The class of SHACL rules based on SPARQL CONSTRUCT queries. - SPARQLSelectExecutable: ( - URIRef # The class of SPARQL executables based on a SELECT query. - ) - SPARQLSelectValidator: URIRef # The class of validators based on SPARQL SELECT queries. The queries are evaluated for each focus node and are supposed to produce bindings for all focus nodes that do not conform. - SPARQLTarget: URIRef # The class of targets that are based on SPARQL queries. - SPARQLTargetType: URIRef # The (meta) class for parameterizable targets that are based on SPARQL queries. - SPARQLUpdateExecutable: ( - URIRef # The class of SPARQL executables based on a SPARQL UPDATE. - ) - Severity: URIRef # The class of validation result severity levels, including violation and warning levels. - Shape: URIRef # A shape is a collection of constraints that may be targeted for certain nodes. - Target: URIRef # The base class of targets such as those based on SPARQL queries. - TargetType: URIRef # The (meta) class for parameterizable targets. Instances of this are instantiated as values of the sh:target property. - TripleRule: URIRef # A rule based on triple (subject, predicate, object) pattern. - ValidationReport: URIRef # The class of SHACL validation reports. - ValidationResult: URIRef # The class of validation results. - Validator: URIRef # The class of validators, which provide instructions on how to process a constraint definition. This class serves as base class for the SPARQL-based validators and other possible implementations. - - # http://www.w3.org/2000/01/rdf-schema#Resource - this: URIRef # A node expression that represents the current focus node. - - # http://www.w3.org/ns/shacl#ConstraintComponent - AndConstraintComponent: URIRef # A constraint component that can be used to test whether a value node conforms to all members of a provided list of shapes. - ClassConstraintComponent: URIRef # A constraint component that can be used to verify that each value node is an instance of a given type. - ClosedConstraintComponent: URIRef # A constraint component that can be used to indicate that focus nodes must only have values for those properties that have been explicitly enumerated via sh:property/sh:path. - DatatypeConstraintComponent: URIRef # A constraint component that can be used to restrict the datatype of all value nodes. - DisjointConstraintComponent: URIRef # A constraint component that can be used to verify that the set of value nodes is disjoint with the the set of nodes that have the focus node as subject and the value of a given property as predicate. - EqualsConstraintComponent: URIRef # A constraint component that can be used to verify that the set of value nodes is equal to the set of nodes that have the focus node as subject and the value of a given property as predicate. - ExpressionConstraintComponent: URIRef # A constraint component that can be used to verify that a given node expression produces true for all value nodes. - HasValueConstraintComponent: URIRef # A constraint component that can be used to verify that one of the value nodes is a given RDF node. - InConstraintComponent: URIRef # A constraint component that can be used to exclusively enumerate the permitted value nodes. - JSConstraintComponent: URIRef # A constraint component with the parameter sh:js linking to a sh:JSConstraint containing a sh:script. - LanguageInConstraintComponent: URIRef # A constraint component that can be used to enumerate language tags that all value nodes must have. - LessThanConstraintComponent: URIRef # A constraint component that can be used to verify that each value node is smaller than all the nodes that have the focus node as subject and the value of a given property as predicate. - LessThanOrEqualsConstraintComponent: URIRef # A constraint component that can be used to verify that every value node is smaller than all the nodes that have the focus node as subject and the value of a given property as predicate. - MaxCountConstraintComponent: URIRef # A constraint component that can be used to restrict the maximum number of value nodes. - MaxExclusiveConstraintComponent: URIRef # A constraint component that can be used to restrict the range of value nodes with a maximum exclusive value. - MaxInclusiveConstraintComponent: URIRef # A constraint component that can be used to restrict the range of value nodes with a maximum inclusive value. - MaxLengthConstraintComponent: URIRef # A constraint component that can be used to restrict the maximum string length of value nodes. - MinCountConstraintComponent: URIRef # A constraint component that can be used to restrict the minimum number of value nodes. - MinExclusiveConstraintComponent: URIRef # A constraint component that can be used to restrict the range of value nodes with a minimum exclusive value. - MinInclusiveConstraintComponent: URIRef # A constraint component that can be used to restrict the range of value nodes with a minimum inclusive value. - MinLengthConstraintComponent: URIRef # A constraint component that can be used to restrict the minimum string length of value nodes. - NodeConstraintComponent: URIRef # A constraint component that can be used to verify that all value nodes conform to the given node shape. - NodeKindConstraintComponent: URIRef # A constraint component that can be used to restrict the RDF node kind of each value node. - NotConstraintComponent: URIRef # A constraint component that can be used to verify that value nodes do not conform to a given shape. - OrConstraintComponent: URIRef # A constraint component that can be used to restrict the value nodes so that they conform to at least one out of several provided shapes. - PatternConstraintComponent: URIRef # A constraint component that can be used to verify that every value node matches a given regular expression. - PropertyConstraintComponent: URIRef # A constraint component that can be used to verify that all value nodes conform to the given property shape. - QualifiedMaxCountConstraintComponent: URIRef # A constraint component that can be used to verify that a specified maximum number of value nodes conforms to a given shape. - QualifiedMinCountConstraintComponent: URIRef # A constraint component that can be used to verify that a specified minimum number of value nodes conforms to a given shape. - SPARQLConstraintComponent: URIRef # A constraint component that can be used to define constraints based on SPARQL queries. - UniqueLangConstraintComponent: URIRef # A constraint component that can be used to specify that no pair of value nodes may use the same language tag. - XoneConstraintComponent: URIRef # A constraint component that can be used to restrict the value nodes so that they conform to exactly one out of several provided shapes. - - # http://www.w3.org/ns/shacl#NodeKind - BlankNode: URIRef # The node kind of all blank nodes. - BlankNodeOrIRI: URIRef # The node kind of all blank nodes or IRIs. - BlankNodeOrLiteral: URIRef # The node kind of all blank nodes or literals. - IRI: URIRef # The node kind of all IRIs. - IRIOrLiteral: URIRef # The node kind of all IRIs or literals. - Literal: URIRef # The node kind of all literals. - - # http://www.w3.org/ns/shacl#Parameter - - # http://www.w3.org/ns/shacl#Severity - Info: URIRef # The severity for an informational validation result. - Violation: URIRef # The severity for a violation validation result. - Warning: URIRef # The severity for a warning validation result. - - # Valid non-python identifiers - _extras = [ - "and", - "class", - "in", - "not", - "or", - "AndConstraintComponent-and", - "ClassConstraintComponent-class", - "ClosedConstraintComponent-closed", - "ClosedConstraintComponent-ignoredProperties", - "DatatypeConstraintComponent-datatype", - "DisjointConstraintComponent-disjoint", - "EqualsConstraintComponent-equals", - "ExpressionConstraintComponent-expression", - "HasValueConstraintComponent-hasValue", - "InConstraintComponent-in", - "JSConstraint-js", - "LanguageInConstraintComponent-languageIn", - "LessThanConstraintComponent-lessThan", - "LessThanOrEqualsConstraintComponent-lessThanOrEquals", - "MaxCountConstraintComponent-maxCount", - "MaxExclusiveConstraintComponent-maxExclusive", - "MaxInclusiveConstraintComponent-maxInclusive", - "MaxLengthConstraintComponent-maxLength", - "MinCountConstraintComponent-minCount", - "MinExclusiveConstraintComponent-minExclusive", - "MinInclusiveConstraintComponent-minInclusive", - "MinLengthConstraintComponent-minLength", - "NodeConstraintComponent-node", - "NodeKindConstraintComponent-nodeKind", - "NotConstraintComponent-not", - "OrConstraintComponent-or", - "PatternConstraintComponent-flags", - "PatternConstraintComponent-pattern", - "PropertyConstraintComponent-property", - "QualifiedMaxCountConstraintComponent-qualifiedMaxCount", - "QualifiedMaxCountConstraintComponent-qualifiedValueShape", - "QualifiedMaxCountConstraintComponent-qualifiedValueShapesDisjoint", - "QualifiedMinCountConstraintComponent-qualifiedMinCount", - "QualifiedMinCountConstraintComponent-qualifiedValueShape", - "QualifiedMinCountConstraintComponent-qualifiedValueShapesDisjoint", - "SPARQLConstraintComponent-sparql", - "UniqueLangConstraintComponent-uniqueLang", - "XoneConstraintComponent-xone", - ] - - _NS = Namespace("http://www.w3.org/ns/shacl#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SKOS.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SKOS.py deleted file mode 100644 index e87df6f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SKOS.py +++ /dev/null @@ -1,66 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class SKOS(DefinedNamespace): - """ - SKOS Vocabulary - - An RDF vocabulary for describing the basic structure and content of concept schemes such as thesauri, - classification schemes, subject heading lists, taxonomies, 'folksonomies', other types of controlled - vocabulary, and also concept schemes embedded in glossaries and terminologies. - - Generated from: https://www.w3.org/2009/08/skos-reference/skos.rdf - Date: 2020-05-26 14:20:08.489187 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - altLabel: URIRef # An alternative lexical label for a resource. - broadMatch: URIRef # skos:broadMatch is used to state a hierarchical mapping link between two conceptual resources in different concept schemes. - broader: URIRef # Relates a concept to a concept that is more general in meaning. - broaderTransitive: ( - URIRef # skos:broaderTransitive is a transitive superproperty of skos:broader. - ) - changeNote: URIRef # A note about a modification to a concept. - closeMatch: URIRef # skos:closeMatch is used to link two concepts that are sufficiently similar that they can be used interchangeably in some information retrieval applications. In order to avoid the possibility of "compound errors" when combining mappings across more than two concept schemes, skos:closeMatch is not declared to be a transitive property. - definition: URIRef # A statement or formal explanation of the meaning of a concept. - editorialNote: ( - URIRef # A note for an editor, translator or maintainer of the vocabulary. - ) - exactMatch: URIRef # skos:exactMatch is used to link two concepts, indicating a high degree of confidence that the concepts can be used interchangeably across a wide range of information retrieval applications. skos:exactMatch is a transitive property, and is a sub-property of skos:closeMatch. - example: URIRef # An example of the use of a concept. - hasTopConcept: URIRef # Relates, by convention, a concept scheme to a concept which is topmost in the broader/narrower concept hierarchies for that scheme, providing an entry point to these hierarchies. - hiddenLabel: URIRef # A lexical label for a resource that should be hidden when generating visual displays of the resource, but should still be accessible to free text search operations. - historyNote: URIRef # A note about the past state/use/meaning of a concept. - inScheme: URIRef # Relates a resource (for example a concept) to a concept scheme in which it is included. - mappingRelation: URIRef # Relates two concepts coming, by convention, from different schemes, and that have comparable meanings - member: URIRef # Relates a collection to one of its members. - memberList: ( - URIRef # Relates an ordered collection to the RDF list containing its members. - ) - narrowMatch: URIRef # skos:narrowMatch is used to state a hierarchical mapping link between two conceptual resources in different concept schemes. - narrower: URIRef # Relates a concept to a concept that is more specific in meaning. - narrowerTransitive: URIRef # skos:narrowerTransitive is a transitive superproperty of skos:narrower. - notation: URIRef # A notation, also known as classification code, is a string of characters such as "T58.5" or "303.4833" used to uniquely identify a concept within the scope of a given concept scheme. - note: URIRef # A general note, for any purpose. - prefLabel: ( - URIRef # The preferred lexical label for a resource, in a given language. - ) - related: URIRef # Relates a concept to a concept with which there is an associative semantic relationship. - relatedMatch: URIRef # skos:relatedMatch is used to state an associative mapping link between two conceptual resources in different concept schemes. - scopeNote: ( - URIRef # A note that helps to clarify the meaning and/or the use of a concept. - ) - semanticRelation: URIRef # Links a concept to a concept related by meaning. - topConceptOf: URIRef # Relates a concept to the concept scheme that it is a top level concept of. - - # http://www.w3.org/2002/07/owl#Class - Collection: URIRef # A meaningful collection of concepts. - Concept: URIRef # An idea or notion; a unit of thought. - ConceptScheme: URIRef # A set of concepts, optionally including statements about semantic relationships between those concepts. - OrderedCollection: URIRef # An ordered collection of concepts, where both the grouping and the ordering are meaningful. - - _NS = Namespace("http://www.w3.org/2004/02/skos/core#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SOSA.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SOSA.py deleted file mode 100644 index 9f281d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SOSA.py +++ /dev/null @@ -1,68 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class SOSA(DefinedNamespace): - """ - Sensor, Observation, Sample, and Actuator (SOSA) Ontology - - This ontology is based on the SSN Ontology by the W3C Semantic Sensor Networks Incubator Group (SSN-XG), - together with considerations from the W3C/OGC Spatial Data on the Web Working Group. - - Generated from: http://www.w3.org/ns/sosa/ - Date: 2020-05-26 14:20:08.792504 - - """ - - # http://www.w3.org/2000/01/rdf-schema#Class - ActuatableProperty: URIRef # An actuatable quality (property, characteristic) of a FeatureOfInterest. - Actuation: URIRef # An Actuation carries out an (Actuation) Procedure to change the state of the world using an Actuator. - Actuator: URIRef # A device that is used by, or implements, an (Actuation) Procedure that changes the state of the world. - FeatureOfInterest: URIRef # The thing whose property is being estimated or calculated in the course of an Observation to arrive at a Result or whose property is being manipulated by an Actuator, or which is being sampled or transformed in an act of Sampling. - ObservableProperty: URIRef # An observable quality (property, characteristic) of a FeatureOfInterest. - Observation: URIRef # Act of carrying out an (Observation) Procedure to estimate or calculate a value of a property of a FeatureOfInterest. Links to a Sensor to describe what made the Observation and how; links to an ObservableProperty to describe what the result is an estimate of, and to a FeatureOfInterest to detail what that property was associated with. - ObservationCollection: URIRef # Collection of one or more observations, whose members share a common value for one or more property - Platform: URIRef # A Platform is an entity that hosts other entities, particularly Sensors, Actuators, Samplers, and other Platforms. - Procedure: URIRef # A workflow, protocol, plan, algorithm, or computational method specifying how to make an Observation, create a Sample, or make a change to the state of the world (via an Actuator). A Procedure is re-usable, and might be involved in many Observations, Samplings, or Actuations. It explains the steps to be carried out to arrive at reproducible results. - Result: URIRef # The Result of an Observation, Actuation, or act of Sampling. To store an observation's simple result value one can use the hasSimpleResult property. - Sample: URIRef # Feature which is intended to be representative of a FeatureOfInterest on which Observations may be made. - Sampler: URIRef # A device that is used by, or implements, a Sampling Procedure to create or transform one or more samples. - Sampling: URIRef # An act of Sampling carries out a sampling Procedure to create or transform one or more samples. - Sensor: URIRef # Device, agent (including humans), or software (simulation) involved in, or implementing, a Procedure. Sensors respond to a stimulus, e.g., a change in the environment, or input data composed from the results of prior Observations, and generate a Result. Sensors can be hosted by Platforms. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - hasSimpleResult: ( - URIRef # The simple value of an Observation or Actuation or act of Sampling. - ) - resultTime: URIRef # The result time is the instant of time when the Observation, Actuation or Sampling activity was completed. - - # http://www.w3.org/2002/07/owl#ObjectProperty - actsOnProperty: URIRef # Relation between an Actuation and the property of a FeatureOfInterest it is acting upon. - hasFeatureOfInterest: URIRef # A relation between an Observation and the entity whose quality was observed, or between an Actuation and the entity whose property was modified, or between an act of Sampling and the entity that was sampled. - hasMember: URIRef # Link to a member of a collection of observations that share the same value for one or more of the characteristic properties - hasOriginalSample: URIRef # link to the original sample that is related to the context sample through a chain of isSampleOf relations - hasResult: URIRef # Relation linking an Observation or Actuation or act of Sampling and a Result or Sample. - hasSample: URIRef # Relation between a FeatureOfInterest and the Sample used to represent it. - hasSampledFeature: URIRef # link to the ultimate feature of interest of the context sample - i.e. the end of a chain of isSampleOf relations - hasUltimateFeatureOfInterest: URIRef # link to the ultimate feature of interest of an observation or act of sampling. This is useful when the proximate feature of interest is a sample of the ultimate feature of interest, directly or trasntitively. - hosts: URIRef # Relation between a Platform and a Sensor, Actuator, Sampler, or Platform, hosted or mounted on it. - isActedOnBy: URIRef # Relation between an ActuatableProperty of a FeatureOfInterest and an Actuation changing its state. - isFeatureOfInterestOf: URIRef # A relation between a FeatureOfInterest and an Observation about it, an Actuation acting on it, or an act of Sampling that sampled it. - isHostedBy: URIRef # Relation between a Sensor, Actuator, Sampler, or Platform, and the Platform that it is mounted on or hosted by. - isObservedBy: URIRef # Relation between an ObservableProperty and the Sensor able to observe it. - isResultOf: URIRef # Relation linking a Result to the Observation or Actuation or act of Sampling that created or caused it. - isSampleOf: URIRef # Relation from a Sample to the FeatureOfInterest that it is intended to be representative of. - madeActuation: URIRef # Relation between an Actuator and the Actuation it has made. - madeByActuator: URIRef # Relation linking an Actuation to the Actuator that made that Actuation. - madeBySampler: URIRef # Relation linking an act of Sampling to the Sampler (sampling device or entity) that made it. - madeBySensor: URIRef # Relation between an Observation and the Sensor which made the Observation. - madeObservation: ( - URIRef # Relation between a Sensor and an Observation made by the Sensor. - ) - madeSampling: URIRef # Relation between a Sampler (sampling device or entity) and the Sampling act it performed. - observedProperty: URIRef # Relation linking an Observation to the property that was observed. The ObservableProperty should be a property of the FeatureOfInterest (linked by hasFeatureOfInterest) of this Observation. - observes: URIRef # Relation between a Sensor and an ObservableProperty that it is capable of sensing. - phenomenonTime: URIRef # The time that the Result of an Observation, Actuation or Sampling applies to the FeatureOfInterest. Not necessarily the same as the resultTime. May be an Interval or an Instant, or some other compound TemporalEntity. - usedProcedure: URIRef # A relation to link to a re-usable Procedure used in making an Observation, an Actuation, or a Sample, typically through a Sensor, Actuator or Sampler. - - _NS = Namespace("http://www.w3.org/ns/sosa/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SSN.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SSN.py deleted file mode 100644 index 5f18511..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_SSN.py +++ /dev/null @@ -1,46 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class SSN(DefinedNamespace): - """ - Semantic Sensor Network Ontology - - This ontology describes sensors, actuators and observations, and related concepts. It does not describe domain - concepts, time, locations, etc. these are intended to be included from other ontologies via OWL imports. - - Generated from: http://www.w3.org/ns/ssn/ - Date: 2020-05-26 14:20:09.068204 - - """ - - # http://www.w3.org/2002/07/owl#Class - Deployment: URIRef # Describes the Deployment of one or more Systems for a particular purpose. Deployment may be done on a Platform. - Input: URIRef # Any information that is provided to a Procedure for its use. - Output: URIRef # Any information that is reported from a Procedure. - Property: URIRef # A quality of an entity. An aspect of an entity that is intrinsic to and cannot exist without the entity. - Stimulus: URIRef # An event in the real world that 'triggers' the Sensor. The properties associated to the Stimulus may be different to the eventual observed ObservableProperty. It is the event, not the object, that triggers the Sensor. - System: URIRef # System is a unit of abstraction for pieces of infrastructure that implement Procedures. A System may have components, its subsystems, which are other systems. - - # http://www.w3.org/2002/07/owl#FunctionalProperty - wasOriginatedBy: ( - URIRef # Relation between an Observation and the Stimulus that originated it. - ) - - # http://www.w3.org/2002/07/owl#ObjectProperty - deployedOnPlatform: URIRef # Relation between a Deployment and the Platform on which the Systems are deployed. - deployedSystem: URIRef # Relation between a Deployment and a deployed System. - detects: URIRef # A relation from a Sensor to the Stimulus that the Sensor detects. The Stimulus itself will be serving as a proxy for some ObservableProperty. - forProperty: URIRef # A relation between some aspect of an entity and a Property. - hasDeployment: URIRef # Relation between a System and a Deployment, recording that the System is deployed in that Deployment. - hasInput: URIRef # Relation between a Procedure and an Input to it. - hasOutput: URIRef # Relation between a Procedure and an Output of it. - hasProperty: URIRef # Relation between an entity and a Property of that entity. - hasSubSystem: URIRef # Relation between a System and its component parts. - implementedBy: URIRef # Relation between a Procedure (an algorithm, procedure or method) and an entity that implements that Procedure in some executable way. - implements: URIRef # Relation between an entity that implements a Procedure in some executable way and the Procedure (an algorithm, procedure or method). - inDeployment: URIRef # Relation between a Platform and a Deployment, meaning that the deployedSystems of the Deployment are hosted on the Platform. - isPropertyOf: URIRef # Relation between a Property and the entity it belongs to. - isProxyFor: URIRef # A relation from a Stimulus to the Property that the Stimulus is serving as a proxy for. - - _NS = Namespace("http://www.w3.org/ns/ssn/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_TIME.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_TIME.py deleted file mode 100644 index 0370180..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_TIME.py +++ /dev/null @@ -1,135 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class TIME(DefinedNamespace): - """ - OWL-Time - - Generated from: http://www.w3.org/2006/time# - Date: 2020-05-26 14:20:10.531265 - - """ - - # http://www.w3.org/2000/01/rdf-schema#Datatype - generalDay: URIRef # Day of month - formulated as a text string with a pattern constraint to reproduce the same lexical form as gDay, except that values up to 99 are permitted, in order to support calendars with more than 31 days in a month. Note that the value-space is not defined, so a generic OWL2 processor cannot compute ordering relationships of values of this type. - generalMonth: URIRef # Month of year - formulated as a text string with a pattern constraint to reproduce the same lexical form as gMonth, except that values up to 20 are permitted, in order to support calendars with more than 12 months in the year. Note that the value-space is not defined, so a generic OWL2 processor cannot compute ordering relationships of values of this type. - generalYear: URIRef # Year number - formulated as a text string with a pattern constraint to reproduce the same lexical form as gYear, but not restricted to values from the Gregorian calendar. Note that the value-space is not defined, so a generic OWL2 processor cannot compute ordering relationships of values of this type. - - # http://www.w3.org/2002/07/owl#Class - DateTimeDescription: URIRef # Description of date and time structured with separate values for the various elements of a calendar-clock system. The temporal reference system is fixed to Gregorian Calendar, and the range of year, month, day properties restricted to corresponding XML Schema types xsd:gYear, xsd:gMonth and xsd:gDay, respectively. - DateTimeInterval: URIRef # DateTimeInterval is a subclass of ProperInterval, defined using the multi-element DateTimeDescription. - DayOfWeek: URIRef # The day of week - Duration: URIRef # Duration of a temporal extent expressed as a number scaled by a temporal unit - DurationDescription: URIRef # Description of temporal extent structured with separate values for the various elements of a calendar-clock system. The temporal reference system is fixed to Gregorian Calendar, and the range of each of the numeric properties is restricted to xsd:decimal - GeneralDateTimeDescription: URIRef # Description of date and time structured with separate values for the various elements of a calendar-clock system - GeneralDurationDescription: URIRef # Description of temporal extent structured with separate values for the various elements of a calendar-clock system. - Instant: URIRef # A temporal entity with zero extent or duration - Interval: URIRef # A temporal entity with an extent or duration - MonthOfYear: URIRef # The month of the year - ProperInterval: URIRef # A temporal entity with non-zero extent or duration, i.e. for which the value of the beginning and end are different - TRS: URIRef # A temporal reference system, such as a temporal coordinate system (with an origin, direction, and scale), a calendar-clock combination, or a (possibly hierarchical) ordinal system. This is a stub class, representing the set of all temporal reference systems. - TemporalDuration: URIRef # Time extent; duration of a time interval separate from its particular start position - TemporalEntity: URIRef # A temporal interval or instant. - TemporalPosition: URIRef # A position on a time-line - TemporalUnit: URIRef # A standard duration, which provides a scale factor for a time extent, or the granularity or precision for a time position. - TimePosition: URIRef # A temporal position described using either a (nominal) value from an ordinal reference system, or a (numeric) value in a temporal coordinate system. - TimeZone: URIRef # A Time Zone specifies the amount by which the local time is offset from UTC. A time zone is usually denoted geographically (e.g. Australian Eastern Daylight Time), with a constant value in a given region. The region where it applies and the offset from UTC are specified by a locally recognised governing authority. - - # http://www.w3.org/2002/07/owl#DatatypeProperty - day: URIRef # Day position in a calendar-clock system. The range of this property is not specified, so can be replaced by any specific representation of a calendar day from any calendar. - dayOfYear: URIRef # The number of the day within the year - days: URIRef # length of, or element of the length of, a temporal extent expressed in days - hasXSDDuration: URIRef # Extent of a temporal entity, expressed using xsd:duration - hour: URIRef # Hour position in a calendar-clock system. - hours: URIRef # length of, or element of the length of, a temporal extent expressed in hours - inXSDDate: URIRef # Position of an instant, expressed using xsd:date - inXSDDateTimeStamp: ( - URIRef # Position of an instant, expressed using xsd:dateTimeStamp - ) - inXSDgYear: URIRef # Position of an instant, expressed using xsd:gYear - inXSDgYearMonth: URIRef # Position of an instant, expressed using xsd:gYearMonth - minute: URIRef # Minute position in a calendar-clock system. - minutes: URIRef # length, or element of, a temporal extent expressed in minutes - month: URIRef # Month position in a calendar-clock system. The range of this property is not specified, so can be replaced by any specific representation of a calendar month from any calendar. - months: URIRef # length of, or element of the length of, a temporal extent expressed in months - nominalPosition: URIRef # The (nominal) value indicating temporal position in an ordinal reference system - numericDuration: URIRef # Value of a temporal extent expressed as a decimal number scaled by a temporal unit - numericPosition: URIRef # The (numeric) value indicating position within a temporal coordinate system - second: URIRef # Second position in a calendar-clock system. - seconds: URIRef # length of, or element of the length of, a temporal extent expressed in seconds - week: URIRef # Week number within the year. - weeks: URIRef # length of, or element of the length of, a temporal extent expressed in weeks - year: URIRef # Year position in a calendar-clock system. The range of this property is not specified, so can be replaced by any specific representation of a calendar year from any calendar. - years: URIRef # length of, or element of the length of, a temporal extent expressed in years - - # http://www.w3.org/2002/07/owl#DeprecatedClass - January: URIRef # January - Year: URIRef # Year duration - - # http://www.w3.org/2002/07/owl#DeprecatedProperty - inXSDDateTime: URIRef # Position of an instant, expressed using xsd:dateTime - xsdDateTime: URIRef # Value of DateTimeInterval expressed as a compact value. - - # http://www.w3.org/2002/07/owl#FunctionalProperty - hasTRS: URIRef # The temporal reference system used by a temporal position or extent description. - - # http://www.w3.org/2002/07/owl#ObjectProperty - after: URIRef # Gives directionality to time. If a temporal entity T1 is after another temporal entity T2, then the beginning of T1 is after the end of T2. - dayOfWeek: ( - URIRef # The day of week, whose value is a member of the class time:DayOfWeek - ) - hasBeginning: URIRef # Beginning of a temporal entity. - hasDateTimeDescription: URIRef # Value of DateTimeInterval expressed as a structured value. The beginning and end of the interval coincide with the limits of the shortest element in the description. - hasDuration: URIRef # Duration of a temporal entity, event or activity, or thing, expressed as a scaled value - hasDurationDescription: URIRef # Duration of a temporal entity, expressed using a structured description - hasEnd: URIRef # End of a temporal entity. - hasTemporalDuration: URIRef # Duration of a temporal entity. - hasTime: URIRef # Supports the association of a temporal entity (instant or interval) to any thing - inDateTime: ( - URIRef # Position of an instant, expressed using a structured description - ) - inTemporalPosition: URIRef # Position of a time instant - inTimePosition: URIRef # Position of a time instant expressed as a TimePosition - inside: URIRef # An instant that falls inside the interval. It is not intended to include beginnings and ends of intervals. - intervalAfter: URIRef # If a proper interval T1 is intervalAfter another proper interval T2, then the beginning of T1 is after the end of T2. - intervalBefore: URIRef # If a proper interval T1 is intervalBefore another proper interval T2, then the end of T1 is before the beginning of T2. - intervalContains: URIRef # If a proper interval T1 is intervalContains another proper interval T2, then the beginning of T1 is before the beginning of T2, and the end of T1 is after the end of T2. - intervalDisjoint: URIRef # If a proper interval T1 is intervalDisjoint another proper interval T2, then the beginning of T1 is after the end of T2, or the end of T1 is before the beginning of T2, i.e. the intervals do not overlap in any way, but their ordering relationship is not known. - intervalDuring: URIRef # If a proper interval T1 is intervalDuring another proper interval T2, then the beginning of T1 is after the beginning of T2, and the end of T1 is before the end of T2. - intervalEquals: URIRef # If a proper interval T1 is intervalEquals another proper interval T2, then the beginning of T1 is coincident with the beginning of T2, and the end of T1 is coincident with the end of T2. - intervalFinishedBy: URIRef # If a proper interval T1 is intervalFinishedBy another proper interval T2, then the beginning of T1 is before the beginning of T2, and the end of T1 is coincident with the end of T2. - intervalFinishes: URIRef # If a proper interval T1 is intervalFinishes another proper interval T2, then the beginning of T1 is after the beginning of T2, and the end of T1 is coincident with the end of T2. - intervalIn: URIRef # If a proper interval T1 is intervalIn another proper interval T2, then the beginning of T1 is after the beginning of T2 or is coincident with the beginning of T2, and the end of T1 is before the end of T2, or is coincident with the end of T2, except that end of T1 may not be coincident with the end of T2 if the beginning of T1 is coincident with the beginning of T2. - intervalMeets: URIRef # If a proper interval T1 is intervalMeets another proper interval T2, then the end of T1 is coincident with the beginning of T2. - intervalMetBy: URIRef # If a proper interval T1 is intervalMetBy another proper interval T2, then the beginning of T1 is coincident with the end of T2. - intervalOverlappedBy: URIRef # If a proper interval T1 is intervalOverlappedBy another proper interval T2, then the beginning of T1 is after the beginning of T2, the beginning of T1 is before the end of T2, and the end of T1 is after the end of T2. - intervalOverlaps: URIRef # If a proper interval T1 is intervalOverlaps another proper interval T2, then the beginning of T1 is before the beginning of T2, the end of T1 is after the beginning of T2, and the end of T1 is before the end of T2. - intervalStartedBy: URIRef # If a proper interval T1 is intervalStarted another proper interval T2, then the beginning of T1 is coincident with the beginning of T2, and the end of T1 is after the end of T2. - intervalStarts: URIRef # If a proper interval T1 is intervalStarts another proper interval T2, then the beginning of T1 is coincident with the beginning of T2, and the end of T1 is before the end of T2. - monthOfYear: URIRef # The month of the year, whose value is a member of the class time:MonthOfYear - timeZone: URIRef # The time zone for clock elements in the temporal position - unitType: URIRef # The temporal unit which provides the precision of a date-time value or scale of a temporal extent - - # http://www.w3.org/2002/07/owl#TransitiveProperty - before: URIRef # Gives directionality to time. If a temporal entity T1 is before another temporal entity T2, then the end of T1 is before the beginning of T2. Thus, "before" can be considered to be basic to instants and derived for intervals. - - # http://www.w3.org/2006/time#DayOfWeek - Friday: URIRef # Friday - Monday: URIRef # Monday - Saturday: URIRef # Saturday - Sunday: URIRef # Sunday - Thursday: URIRef # Thursday - Tuesday: URIRef # Tuesday - Wednesday: URIRef # Wednesday - - # http://www.w3.org/2006/time#TemporalUnit - unitDay: URIRef # day - unitHour: URIRef # hour - unitMinute: URIRef # minute - unitMonth: URIRef # month - unitSecond: URIRef # second - unitWeek: URIRef # week - unitYear: URIRef # year - - _NS = Namespace("http://www.w3.org/2006/time#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VANN.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VANN.py deleted file mode 100644 index 95ee40d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VANN.py +++ /dev/null @@ -1,27 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class VANN(DefinedNamespace): - """ - VANN: A vocabulary for annotating vocabulary descriptions - - This document describes a vocabulary for annotating descriptions of vocabularies with examples and usage - notes. - - Generated from: https://vocab.org/vann/vann-vocab-20100607.rdf - Date: 2020-05-26 14:21:15.580430 - - """ - - _fail = True - - # http://www.w3.org/2002/07/owl#AnnotationProperty - changes: URIRef # A reference to a resource that describes changes between this version of a vocabulary and the previous. - example: URIRef # A reference to a resource that provides an example of how this resource can be used. - preferredNamespacePrefix: URIRef # The preferred namespace prefix to use when using terms from this vocabulary in an XML document. - preferredNamespaceUri: URIRef # The preferred namespace URI to use when using terms from this vocabulary in an XML document. - termGroup: URIRef # A group of related terms in a vocabulary. - usageNote: URIRef # A reference to a resource that provides information on how this resource is to be used. - - _NS = Namespace("http://purl.org/vocab/vann/") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VOID.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VOID.py deleted file mode 100644 index 5905e78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_VOID.py +++ /dev/null @@ -1,65 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class VOID(DefinedNamespace): - """ - Vocabulary of Interlinked Datasets (VoID) - - The Vocabulary of Interlinked Datasets (VoID) is an RDF Schema vocabulary for expressing metadata about RDF - datasets. It is intended as a bridge between the publishers and users of RDF data, with applications ranging - from data discovery to cataloging and archiving of datasets. This document provides a formal definition of the - new RDF classes and properties introduced for VoID. It is a companion to the main specification document for - VoID, Describing Linked Datasets with the VoID Vocabulary. - - Generated from: http://rdfs.org/ns/void# - Date: 2020-05-26 14:20:11.911298 - - """ - - _fail = True - - # http://www.w3.org/1999/02/22-rdf-syntax-ns#Property - classPartition: URIRef # A subset of a void:Dataset that contains only the entities of a certain rdfs:Class. - classes: URIRef # The total number of distinct classes in a void:Dataset. In other words, the number of distinct resources occurring as objects of rdf:type triples in the dataset. - dataDump: URIRef # An RDF dump, partial or complete, of a void:Dataset. - distinctObjects: URIRef # The total number of distinct objects in a void:Dataset. In other words, the number of distinct resources that occur in the object position of triples in the dataset. Literals are included in this count. - distinctSubjects: URIRef # The total number of distinct subjects in a void:Dataset. In other words, the number of distinct resources that occur in the subject position of triples in the dataset. - documents: URIRef # The total number of documents, for datasets that are published as a set of individual documents, such as RDF/XML documents or RDFa-annotated web pages. Non-RDF documents, such as web pages in HTML or images, are usually not included in this count. This property is intended for datasets where the total number of triples or entities is hard to determine. void:triples or void:entities should be preferred where practical. - entities: ( - URIRef # The total number of entities that are described in a void:Dataset. - ) - exampleResource: URIRef # example resource of dataset - feature: URIRef # feature - inDataset: URIRef # Points to the void:Dataset that a document is a part of. - linkPredicate: URIRef # a link predicate - objectsTarget: URIRef # The dataset describing the objects of the triples contained in the Linkset. - openSearchDescription: URIRef # An OpenSearch description document for a free-text search service over a void:Dataset. - properties: URIRef # The total number of distinct properties in a void:Dataset. In other words, the number of distinct resources that occur in the predicate position of triples in the dataset. - property: URIRef # The rdf:Property that is the predicate of all triples in a property-based partition. - propertyPartition: URIRef # A subset of a void:Dataset that contains only the triples of a certain rdf:Property. - rootResource: URIRef # A top concept or entry point for a void:Dataset that is structured in a tree-like fashion. All resources in a dataset can be reached by following links from its root resources in a small number of steps. - sparqlEndpoint: URIRef # has a SPARQL endpoint at - subjectsTarget: URIRef # The dataset describing the subjects of triples contained in the Linkset. - subset: URIRef # has subset - target: URIRef # One of the two datasets linked by the Linkset. - triples: URIRef # The total number of triples contained in a void:Dataset. - uriLookupEndpoint: ( - URIRef # Defines a simple URI look-up protocol for accessing a dataset. - ) - uriRegexPattern: ( - URIRef # Defines a regular expression pattern matching URIs in the dataset. - ) - uriSpace: URIRef # A URI that is a common string prefix of all the entity URIs in a void:Dataset. - vocabulary: URIRef # A vocabulary that is used in the dataset. - - # http://www.w3.org/2000/01/rdf-schema#Class - Dataset: URIRef # A set of RDF triples that are published, maintained or aggregated by a single provider. - DatasetDescription: URIRef # A web resource whose foaf:primaryTopic or foaf:topics include void:Datasets. - Linkset: URIRef # A collection of RDF links between two void:Datasets. - TechnicalFeature: URIRef # A technical feature of a void:Dataset, such as a supported RDF serialization format. - - # Valid non-python identifiers - _extras = ["class"] - - _NS = Namespace("http://rdfs.org/ns/void#") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_WGS.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_WGS.py deleted file mode 100644 index 1416154..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_WGS.py +++ /dev/null @@ -1,25 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class WGS(DefinedNamespace): - """ - Basic Geo (WGS84 lat/long) Vocabulary - - The HTML Specification for the vocabulary can be found - here . - """ - - _NS = Namespace("https://www.w3.org/2003/01/geo/wgs84_pos#") - - # http://www.w3.org/2000/01/rdf-schema#Class - SpatialThing: URIRef - Point: URIRef - - # http://www.w3.org/2002/07/owl#DatatypeProperty - alt: URIRef - - lat: URIRef # http://www.w3.org/2003/01/geo/wgs84_pos#lat - lat_long: URIRef - location: URIRef - long: URIRef diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_XSD.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_XSD.py deleted file mode 100644 index f12524f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/_XSD.py +++ /dev/null @@ -1,103 +0,0 @@ -from rdflib.namespace import DefinedNamespace, Namespace -from rdflib.term import URIRef - - -class XSD(DefinedNamespace): - """ - W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes - - Generated from: ../schemas/datatypes.xsd - Date: 2021-09-05 20:37+10 - - """ - - _NS = Namespace("http://www.w3.org/2001/XMLSchema#") - - ENTITIES: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#ENTITIES - ENTITY: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#ENTITY - ID: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#ID - IDREF: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#IDREF - IDREFS: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#IDREFS - NCName: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#NCName - NMTOKEN: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#NMTOKEN - NMTOKENS: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#NMTOKENS - NOTATION: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#NOTATIONNOTATION cannot be used directly in a schema; rather a type - Name: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#Name - QName: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#QName - anyURI: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#anyURI - base64Binary: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#base64Binary - boolean: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#boolean - byte: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#byte - date: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#date - dateTime: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#dateTime - dateTimeStamp: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#dateTimeStamp - dayTimeDuration: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#dayTimeDuration - decimal: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#decimal - double: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#double - duration: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#duration - float: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#float - gDay: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#gDay - gMonth: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#gMonth - gMonthDay: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#gMonthDay - gYear: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#gYear - gYearMonth: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#gYearMonth - hexBinary: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#binary - int: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#int - integer: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#integer - language: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#language - long: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#long - negativeInteger: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#negativeInteger - nonNegativeInteger: ( - URIRef # see: http://www.w3.org/TR/xmlschema11-2/#nonNegativeInteger - ) - nonPositiveInteger: ( - URIRef # see: http://www.w3.org/TR/xmlschema11-2/#nonPositiveInteger - ) - normalizedString: ( - URIRef # see: http://www.w3.org/TR/xmlschema11-2/#normalizedString - ) - positiveInteger: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#positiveInteger - short: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#short - string: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#string - time: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#time - token: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#token - unsignedByte: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#unsignedByte - unsignedInt: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#unsignedInt - unsignedLong: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#unsignedLong - unsignedShort: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#unsignedShort - yearMonthDuration: ( - URIRef # see: http://www.w3.org/TR/xmlschema11-2/#yearMonthDuration - ) - - # fundamental facets - https://www.w3.org/TR/xmlschema11-2/#rf-fund-facets - ordered: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-ordered - bounded: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-bounded - cardinality: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-cardinality - numeric: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-numeric - - # constraining facets - https://www.w3.org/TR/xmlschema11-2/#rf-facets - length: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-length - minLength: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-minLength - maxLength: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-maxLength - pattern: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-pattern - enumeration: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-enumeration - whiteSpace: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-whiteSpace - maxExclusive: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-maxExclusive - maxInclusive: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-maxInclusive - minExclusive: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-minExclusive - minInclusive: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-minInclusive - totalDigits: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-totalDigits - fractionDigits: URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-fractionDigits - Assertions: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#rf-assertions - explicitTimezone: ( - URIRef # see: http://www.w3.org/TR/xmlschema11-2/#rf-explicitTimezone - ) - - # The Seven-property Model - https://www.w3.org/TR/xmlschema11-2/#theSevenPropertyModel - year: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-http://www.w3.org/TR/xmlschema11-2/#rf-whiteSpace - month: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-month - day: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-day - hour: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-hour - minute: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-minute - second: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-second - timezoneOffset: URIRef # see: https://www.w3.org/TR/xmlschema11-2/#vp-dt-timezone diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/__init__.py deleted file mode 100644 index cd2946a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/namespace/__init__.py +++ /dev/null @@ -1,1025 +0,0 @@ -""" -=================== -Namespace Utilities -=================== - -RDFLib provides mechanisms for managing Namespaces. - -In particular, there is a :class:`~rdflib.namespace.Namespace` class -that takes as its argument the base URI of the namespace. - -.. code-block:: pycon - - >>> from rdflib.namespace import Namespace - >>> RDFS = Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#") - -Fully qualified URIs in the namespace can be constructed either by attribute -or by dictionary access on Namespace instances: - -.. code-block:: pycon - - >>> RDFS.seeAlso - rdflib.term.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#seeAlso') - >>> RDFS['seeAlso'] - rdflib.term.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#seeAlso') - - -Automatic handling of unknown predicates ------------------------------------------ - -As a programming convenience, a namespace binding is automatically -created when :class:`rdflib.term.URIRef` predicates are added to the graph. - -Importable namespaces ------------------------ - -The following namespaces are available by directly importing from rdflib: - -* BRICK -* CSVW -* DC -* DCAT -* DCMITYPE -* DCTERMS -* DCAM -* DOAP -* FOAF -* ODRL2 -* ORG -* OWL -* PROF -* PROV -* QB -* RDF -* RDFS -* SDO -* SH -* SKOS -* SOSA -* SSN -* TIME -* VANN -* VOID -* WGS -* XSD - -.. code-block:: pycon - - >>> from rdflib.namespace import RDFS - >>> RDFS.seeAlso - rdflib.term.URIRef('http://www.w3.org/2000/01/rdf-schema#seeAlso') -""" - -from __future__ import annotations - -import logging -import warnings - -try: - # Python >= 3.14 - from annotationlib import ( - get_annotations, # type: ignore[attr-defined,unused-ignore] - ) -except ImportError: # pragma: no cover - try: - # Python >= 3.10 - from inspect import get_annotations # type: ignore[attr-defined,unused-ignore] - except ImportError: - - def get_annotations(thing: Any) -> dict: - return thing.__annotations__ - - -from functools import lru_cache -from pathlib import Path -from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Set, Tuple, Union -from unicodedata import category -from urllib.parse import urldefrag, urljoin - -from rdflib.term import URIRef, Variable, _is_valid_uri - -if TYPE_CHECKING: - from rdflib.graph import Graph - from rdflib.store import Store - - -__all__ = [ - "is_ncname", - "split_uri", - "Namespace", - "ClosedNamespace", - "DefinedNamespace", - "NamespaceManager", - "BRICK", - "CSVW", - "DC", - "DCAM", - "DCAT", - "DCMITYPE", - "DCTERMS", - "DOAP", - "FOAF", - "GEO", - "ODRL2", - "ORG", - "OWL", - "PROF", - "PROV", - "QB", - "RDF", - "RDFS", - "SDO", - "SH", - "SKOS", - "SOSA", - "SSN", - "TIME", - "VANN", - "VOID", - "WGS", - "XSD", -] - -logger = logging.getLogger(__name__) - - -class Namespace(str): - """ - Utility class for quickly generating URIRefs with a common prefix - - >>> from rdflib.namespace import Namespace - >>> n = Namespace("http://example.org/") - >>> n.Person # as attribute - rdflib.term.URIRef('http://example.org/Person') - >>> n['first-name'] # as item - for things that are not valid python identifiers - rdflib.term.URIRef('http://example.org/first-name') - >>> n.Person in n - True - >>> n2 = Namespace("http://example2.org/") - >>> n.Person in n2 - False - """ - - def __new__(cls, value: Union[str, bytes]) -> Namespace: - try: - rt = str.__new__(cls, value) - except UnicodeDecodeError: - rt = str.__new__(cls, value, "utf-8") # type: ignore[arg-type] - return rt - - # type error: Signature of "title" incompatible with supertype "str" - @property - def title(self) -> URIRef: # type: ignore[override] - # Override for DCTERMS.title to return a URIRef instead of str.title method - return URIRef(self + "title") - - def term(self, name: str) -> URIRef: - # need to handle slices explicitly because of __getitem__ override - return URIRef(self + (name if isinstance(name, str) else "")) - - def __getitem__(self, key: str) -> URIRef: # type: ignore[override] - return self.term(key) - - def __getattr__(self, name: str) -> URIRef: - if name.startswith("__"): # ignore any special Python names! - raise AttributeError - return self.term(name) - - def __repr__(self) -> str: - return f"Namespace({super().__repr__()})" - - def __contains__(self, ref: str) -> bool: # type: ignore[override] - """Allows to check if a URI is within (starts with) this Namespace. - - >>> from rdflib import URIRef - >>> namespace = Namespace('http://example.org/') - >>> uri = URIRef('http://example.org/foo') - >>> uri in namespace - True - >>> person_class = namespace['Person'] - >>> person_class in namespace - True - >>> obj = URIRef('http://not.example.org/bar') - >>> obj in namespace - False - """ - return ref.startswith(self) # test namespace membership with "ref in ns" syntax - - -class URIPattern(str): - """ - Utility class for creating URIs according to some pattern - This supports either new style formatting with .format - or old-style with % operator - - >>> u=URIPattern("http://example.org/%s/%d/resource") - >>> u%('books', 12345) - rdflib.term.URIRef('http://example.org/books/12345/resource') - - """ - - def __new__(cls, value: Union[str, bytes]) -> URIPattern: - try: - rt = str.__new__(cls, value) - except UnicodeDecodeError: - if TYPE_CHECKING: - assert isinstance(value, bytes) - rt = str.__new__(cls, value, "utf-8") - return rt - - def __mod__(self, *args, **kwargs) -> URIRef: - return URIRef(super().__mod__(*args, **kwargs)) - - def format(self, *args, **kwargs) -> URIRef: - return URIRef(super().format(*args, **kwargs)) - - def __repr__(self) -> str: - return f"URIPattern({super().__repr__()})" - - -# _DFNS_RESERVED_ATTRS are attributes for which DefinedNamespaceMeta should -# always raise AttributeError if they are not defined and which should not be -# considered part of __dir__ results. These should be all annotations on -# `DefinedNamespaceMeta`. -_DFNS_RESERVED_ATTRS: Set[str] = { - "__slots__", - "_NS", - "_warn", - "_fail", - "_extras", - "_underscore_num", -} - -# Some libraries probe classes for certain attributes or items. -# This is a list of those attributes and items that should be ignored. -_IGNORED_ATTR_LOOKUP: Set[str] = { - "_pytestfixturefunction", # pytest tries to look this up on Defined namespaces - "_partialmethod", # sphinx tries to look this up during autodoc generation -} - - -class DefinedNamespaceMeta(type): - """Utility metaclass for generating URIRefs with a common prefix.""" - - __slots__: Tuple[str, ...] = tuple() - - _NS: Namespace - _warn: bool = True - _fail: bool = False # True means mimic ClosedNamespace - _extras: List[str] = [] # List of non-pythonesque items - _underscore_num: bool = False # True means pass "_n" constructs - - @lru_cache(maxsize=None) - def __getitem__(cls, name: str, default=None) -> URIRef: - name = str(name) - - if name in _DFNS_RESERVED_ATTRS: - raise KeyError( - f"DefinedNamespace like object has no access item named {name!r}" - ) - elif name in _IGNORED_ATTR_LOOKUP: - raise KeyError() - if (cls._warn or cls._fail) and name not in cls: - if cls._fail: - raise AttributeError(f"term '{name}' not in namespace '{cls._NS}'") - else: - warnings.warn( - f"Code: {name} is not defined in namespace {cls.__name__}", - stacklevel=3, - ) - return cls._NS[name] - - def __getattr__(cls, name: str): - if name in _IGNORED_ATTR_LOOKUP: - raise AttributeError() - elif name in _DFNS_RESERVED_ATTRS: - raise AttributeError( - f"DefinedNamespace like object has no attribute {name!r}" - ) - elif name.startswith("__"): - return super(DefinedNamespaceMeta, cls).__getattribute__(name) - return cls.__getitem__(name) - - def __repr__(cls) -> str: - try: - ns_repr = repr(cls._NS) - except AttributeError: - ns_repr = "" - return f"Namespace({ns_repr})" - - def __str__(cls) -> str: - try: - return str(cls._NS) - except AttributeError: - return "" - - def __add__(cls, other: str) -> URIRef: - return cls.__getitem__(other) - - def __contains__(cls, item: str) -> bool: - """Determine whether a URI or an individual item belongs to this namespace""" - try: - this_ns = cls._NS - except AttributeError: - return False - item_str = str(item) - if item_str.startswith(str(this_ns)): - item_str = item_str[len(str(this_ns)) :] - return any( - item_str in get_annotations(c) - or item_str in c._extras - or (cls._underscore_num and item_str[0] == "_" and item_str[1:].isdigit()) - for c in cls.mro() - if issubclass(c, DefinedNamespace) - ) - - def __dir__(cls) -> Iterable[str]: - attrs = {str(x) for x in get_annotations(cls)} - # Removing these as they should not be considered part of the namespace. - attrs.difference_update(_DFNS_RESERVED_ATTRS) - values = {cls[str(x)] for x in attrs} - return values - - def as_jsonld_context(self, pfx: str) -> dict: # noqa: N804 - """Returns this DefinedNamespace as a JSON-LD 'context' object""" - terms = {pfx: str(self._NS)} - for key, term in get_annotations(self).items(): - if issubclass(term, URIRef): - terms[key] = f"{pfx}:{key}" - - return {"@context": terms} - - -class DefinedNamespace(metaclass=DefinedNamespaceMeta): - """ - A Namespace with an enumerated list of members. - Warnings are emitted if unknown members are referenced if _warn is True - """ - - __slots__: Tuple[str, ...] = tuple() - - def __init__(self): - raise TypeError("namespace may not be instantiated") - - -class ClosedNamespace(Namespace): - """ - A namespace with a closed list of members - - Trying to create terms not listed is an error - """ - - __uris: Dict[str, URIRef] - - def __new__(cls, uri: str, terms: List[str]): - rt = super().__new__(cls, uri) - rt.__uris = {t: URIRef(rt + t) for t in terms} # type: ignore[attr-defined] - return rt - - @property - def uri(self) -> str: # Back-compat - return str(self) - - def term(self, name: str) -> URIRef: - uri = self.__uris.get(name) - if uri is None: - raise KeyError(f"term '{name}' not in namespace '{self}'") - return uri - - def __getitem__(self, key: str) -> URIRef: # type: ignore[override] - return self.term(key) - - def __getattr__(self, name: str) -> URIRef: - if name.startswith("__"): # ignore any special Python names! - raise AttributeError - else: - try: - return self.term(name) - except KeyError as e: - raise AttributeError(e) - - def __repr__(self) -> str: - return f"{self.__module__}.{self.__class__.__name__}({str(self)!r})" - - def __dir__(self) -> List[str]: - return list(self.__uris) - - def __contains__(self, ref: str) -> bool: # type: ignore[override] - return ( - ref in self.__uris.values() - ) # test namespace membership with "ref in ns" syntax - - def _ipython_key_completions_(self) -> List[str]: - return dir(self) - - -XMLNS = Namespace("http://www.w3.org/XML/1998/namespace") - -if TYPE_CHECKING: - from rdflib._type_checking import _NamespaceSetString - -_with_bind_override_fix = True - - -class NamespaceManager: - """Class for managing prefix => namespace mappings - - This class requires an RDFlib Graph as an input parameter and may optionally have - the parameter bind_namespaces set. This second parameter selects a strategy which - is one of the following: - - * core: - * binds several core RDF prefixes only - * owl, rdf, rdfs, xsd, xml from the NAMESPACE_PREFIXES_CORE object - * rdflib: - * binds all the namespaces shipped with RDFLib as DefinedNamespace instances - * all the core namespaces and all the following: brick, csvw, dc, dcat - * dcmitype, dcterms, dcam, doap, foaf, geo, odrl, org, prof, prov, qb, schema - * sh, skos, sosa, ssn, time, vann, void - * see the NAMESPACE_PREFIXES_RDFLIB object for the up-to-date list - * this is default - * none: - * binds no namespaces to prefixes - * note this is NOT default behaviour - * cc: - * using prefix bindings from prefix.cc which is a online prefixes database - * not implemented yet - this is aspirational - - .. attention:: - - The namespaces bound for specific values of ``bind_namespaces`` - constitute part of RDFLib's public interface, so changes to them should - only be additive within the same minor version. Removing values, or - removing namespaces that are bound by default, constitutes a breaking - change. - - See the - Sample usage - - .. code-block:: pycon - - >>> import rdflib - >>> from rdflib import Graph - >>> from rdflib.namespace import Namespace, NamespaceManager - >>> EX = Namespace('http://example.com/') - >>> namespace_manager = NamespaceManager(Graph()) - >>> namespace_manager.bind('ex', EX, override=False) - >>> g = Graph() - >>> g.namespace_manager = namespace_manager - >>> all_ns = [n for n in g.namespace_manager.namespaces()] - >>> assert ('ex', rdflib.term.URIRef('http://example.com/')) in all_ns - >>> - """ - - def __init__(self, graph: Graph, bind_namespaces: _NamespaceSetString = "rdflib"): - self.graph = graph - self.__cache: Dict[str, Tuple[str, URIRef, str]] = {} - self.__cache_strict: Dict[str, Tuple[str, URIRef, str]] = {} - self.__log = None - self.__strie: Dict[str, Any] = {} - self.__trie: Dict[str, Any] = {} - # This type declaration is here becuase there is no common base class - # for all namespaces and without it the inferred type of ns is not - # compatible with all prefixes. - ns: Any - # bind Namespaces as per options. - # default is core - if bind_namespaces == "none": - # binds no namespaces to prefixes - # note this is NOT default - pass - elif bind_namespaces == "rdflib": - # bind all the Namespaces shipped with RDFLib - for prefix, ns in _NAMESPACE_PREFIXES_RDFLIB.items(): - self.bind(prefix, ns) - # ... don't forget the core ones too - for prefix, ns in _NAMESPACE_PREFIXES_CORE.items(): - self.bind(prefix, ns) - elif bind_namespaces == "cc": - # bind any prefix that can be found with lookups to prefix.cc - # first bind core and rdflib ones - # work out remainder - namespaces without prefixes - # only look those ones up - raise NotImplementedError("Haven't got to this option yet") - elif bind_namespaces == "core": - # bind a few core RDF namespaces - default - for prefix, ns in _NAMESPACE_PREFIXES_CORE.items(): - self.bind(prefix, ns) - else: - raise ValueError(f"unsupported namespace set {bind_namespaces}") - - def __contains__(self, ref: str) -> bool: - # checks if a reference is in any of the managed namespaces with syntax - # "ref in manager". Note that we don't use "ref in ns", as - # NamespaceManager.namespaces() returns Iterator[Tuple[str, URIRef]] - # rather than Iterator[Tuple[str, Namespace]] - return any(ref.startswith(ns) for prefix, ns in self.namespaces()) - - def reset(self) -> None: - self.__cache = {} - self.__strie = {} - self.__trie = {} - for p, n in self.namespaces(): # repopulate the trie - insert_trie(self.__trie, str(n)) - - @property - def store(self) -> Store: - return self.graph.store - - def qname(self, uri: str) -> str: - prefix, namespace, name = self.compute_qname(uri) - if prefix == "": - return name - else: - return ":".join((prefix, name)) - - def curie(self, uri: str, generate: bool = True) -> str: - """ - From a URI, generate a valid CURIE. - - Result is guaranteed to contain a colon separating the prefix from the - name, even if the prefix is an empty string. - - .. warning:: - - When ``generate`` is `True` (which is the default) and there is no - matching namespace for the URI in the namespace manager then a new - namespace will be added with prefix ``ns{index}``. - - Thus, when ``generate`` is `True`, this function is not a pure - function because of this side-effect. - - This default behaviour is chosen so that this function operates - similarly to `NamespaceManager.qname`. - - :param uri: URI to generate CURIE for. - :param generate: Whether to add a prefix for the namespace if one doesn't - already exist. Default: `True`. - :return: CURIE for the URI. - :raises KeyError: If generate is `False` and the namespace doesn't already have - a prefix. - """ - prefix, namespace, name = self.compute_qname(uri, generate=generate) - return ":".join((prefix, name)) - - def qname_strict(self, uri: str) -> str: - prefix, namespace, name = self.compute_qname_strict(uri) - if prefix == "": - return name - else: - return ":".join((prefix, name)) - - def normalizeUri(self, rdfTerm: str) -> str: # noqa: N802, N803 - """ - Takes an RDF Term and 'normalizes' it into a QName (using the - registered prefix) or (unlike compute_qname) the Notation 3 - form for URIs: <...URI...> - """ - try: - namespace, name = split_uri(rdfTerm) - if namespace not in self.__strie: - insert_strie(self.__strie, self.__trie, str(namespace)) - namespace = URIRef(str(namespace)) - except Exception: - if isinstance(rdfTerm, Variable): - return "?%s" % rdfTerm - else: - return "<%s>" % rdfTerm - prefix = self.store.prefix(namespace) - if prefix is None and isinstance(rdfTerm, Variable): - return "?%s" % rdfTerm - elif prefix is None: - return "<%s>" % rdfTerm - else: - qNameParts = self.compute_qname(rdfTerm) # noqa: N806 - return ":".join([qNameParts[0], qNameParts[-1]]) - - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: - prefix: Optional[str] - if uri not in self.__cache: - if not _is_valid_uri(uri): - raise ValueError( - '"{}" does not look like a valid URI, cannot serialize this. Did you want to urlencode it?'.format( - uri - ) - ) - - try: - namespace, name = split_uri(uri) - except ValueError as e: - namespace = URIRef(uri) - prefix = self.store.prefix(namespace) - name = "" # empty prefix case, safe since not prefix is error - if not prefix: - raise e - if namespace not in self.__strie: - insert_strie(self.__strie, self.__trie, namespace) - - if self.__strie[namespace]: - pl_namespace = get_longest_namespace(self.__strie[namespace], uri) - if pl_namespace is not None: - namespace = pl_namespace - name = uri[len(namespace) :] - - namespace = URIRef(namespace) - prefix = self.store.prefix(namespace) # warning multiple prefixes problem - - if prefix is None: - if not generate: - raise KeyError( - "No known prefix for {} and generate=False".format(namespace) - ) - num = 1 - while 1: - prefix = "ns%s" % num - if not self.store.namespace(prefix): - break - num += 1 - self.bind(prefix, namespace) - self.__cache[uri] = (prefix, namespace, name) - return self.__cache[uri] - - def compute_qname_strict( - self, uri: str, generate: bool = True - ) -> Tuple[str, str, str]: - # code repeated to avoid branching on strict every time - # if output needs to be strict (e.g. for xml) then - # only the strict output should bear the overhead - namespace: str - prefix: Optional[str] - prefix, namespace, name = self.compute_qname(uri, generate) - if is_ncname(str(name)): - return prefix, namespace, name - else: - if uri not in self.__cache_strict: - try: - namespace, name = split_uri(uri, NAME_START_CATEGORIES) - except ValueError: - message = ( - "This graph cannot be serialized to a strict format " - "because there is no valid way to shorten {}".format(uri) - ) - raise ValueError(message) - # omitted for strict since NCNames cannot be empty - # namespace = URIRef(uri) - # prefix = self.store.prefix(namespace) - # if not prefix: - # raise e - - if namespace not in self.__strie: - insert_strie(self.__strie, self.__trie, namespace) - - # omitted for strict - # if self.__strie[namespace]: - # pl_namespace = get_longest_namespace(self.__strie[namespace], uri) - # if pl_namespace is not None: - # namespace = pl_namespace - # name = uri[len(namespace):] - - namespace = URIRef(namespace) - prefix = self.store.prefix( - namespace - ) # warning multiple prefixes problem - - if prefix is None: - if not generate: - raise KeyError( - "No known prefix for {} and generate=False".format( - namespace - ) - ) - num = 1 - while 1: - prefix = "ns%s" % num - if not self.store.namespace(prefix): - break - num += 1 - self.bind(prefix, namespace) - self.__cache_strict[uri] = (prefix, namespace, name) - - return self.__cache_strict[uri] - - def expand_curie(self, curie: str) -> URIRef: - """ - Expand a CURIE of the form , e.g. "rdf:type" - into its full expression: - - >>> import rdflib - >>> g = rdflib.Graph() - >>> g.namespace_manager.expand_curie("rdf:type") - rdflib.term.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') - - Raises exception if a namespace is not bound to the prefix. - - """ - if not type(curie) is str: # noqa: E714 - raise TypeError(f"Argument must be a string, not {type(curie).__name__}.") - parts = curie.split(":", 1) - if len(parts) != 2: - raise ValueError( - "Malformed curie argument, format should be e.g. “foaf:nameâ€." - ) - ns = self.store.namespace(parts[0]) - if ns is not None: - return URIRef(f"{str(ns)}{parts[1]}") - else: - raise ValueError( - f"Prefix \"{curie.split(':')[0]}\" not bound to any namespace." - ) - - def _store_bind(self, prefix: str, namespace: URIRef, override: bool) -> None: - if not _with_bind_override_fix: - return self.store.bind(prefix, namespace) - try: - return self.store.bind(prefix, namespace, override=override) - except TypeError as error: - if "override" in str(error): - logger.debug( - "caught a TypeError, " - "retrying call to %s.bind without override, " - "see https://github.com/RDFLib/rdflib/issues/1880 for more info", - type(self.store), - exc_info=True, - ) - return self.store.bind(prefix, namespace) - - def bind( - self, - prefix: Optional[str], - namespace: Any, - override: bool = True, - replace: bool = False, - ) -> None: - """Bind a given namespace to the prefix - - If override, rebind, even if the given namespace is already - bound to another prefix. - - If replace, replace any existing prefix with the new namespace - - """ - - namespace = URIRef(str(namespace)) - # When documenting explain that override only applies in what cases - if prefix is None: - prefix = "" - elif " " in prefix: - raise KeyError("Prefixes may not contain spaces.") - - bound_namespace = self.store.namespace(prefix) - - # Check if the bound_namespace contains a URI - # and if so convert it into a URIRef for comparison - # This is to prevent duplicate namespaces with the - # same URI - if bound_namespace: - bound_namespace = URIRef(bound_namespace) - if bound_namespace and bound_namespace != namespace: - if replace: - self._store_bind(prefix, namespace, override=override) - insert_trie(self.__trie, str(namespace)) - return - # prefix already in use for different namespace - # - # append number to end of prefix until we find one - # that's not in use. - if not prefix: - prefix = "default" - - num = 1 - while 1: - new_prefix = "%s%s" % (prefix, num) - tnamespace = self.store.namespace(new_prefix) - if tnamespace and namespace == URIRef(tnamespace): - # the prefix is already bound to the correct - # namespace - return - if not self.store.namespace(new_prefix): - break - num += 1 - self._store_bind(new_prefix, namespace, override=override) - else: - bound_prefix = self.store.prefix(namespace) - if bound_prefix is None: - self._store_bind(prefix, namespace, override=override) - elif bound_prefix == prefix: - pass # already bound - else: - if override or bound_prefix.startswith("_"): # or a generated prefix - self._store_bind(prefix, namespace, override=override) - - insert_trie(self.__trie, str(namespace)) - - def namespaces(self) -> Iterable[Tuple[str, URIRef]]: - for prefix, namespace in self.store.namespaces(): - namespace = URIRef(namespace) - yield prefix, namespace - - def absolutize(self, uri: str, defrag: int = 1) -> URIRef: - base = Path.cwd().as_uri() - result = urljoin("%s/" % base, uri, allow_fragments=not defrag) - if defrag: - result = urldefrag(result)[0] - if not defrag: - if uri and uri[-1] == "#" and result[-1] != "#": - result = "%s#" % result - return URIRef(result) - - -# From: http://www.w3.org/TR/REC-xml#NT-CombiningChar -# -# * Name start characters must have one of the categories Ll, Lu, Lo, -# Lt, Nl. -# -# * Name characters other than Name-start characters must have one of -# the categories Mc, Me, Mn, Lm, or Nd. -# -# * Characters in the compatibility area (i.e. with character code -# greater than #xF900 and less than #xFFFE) are not allowed in XML -# names. -# -# * Characters which have a font or compatibility decomposition -# (i.e. those with a "compatibility formatting tag" in field 5 of the -# database -- marked by field 5 beginning with a "<") are not allowed. -# -# * The following characters are treated as name-start characters rather -# than name characters, because the property file classifies them as -# Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6. -# -# * Characters #x20DD-#x20E0 are excluded (in accordance with Unicode -# 2.0, section 5.14). -# -# * Character #x00B7 is classified as an extender, because the property -# list so identifies it. -# -# * Character #x0387 is added as a name character, because #x00B7 is its -# canonical equivalent. -# -# * Characters ':' and '_' are allowed as name-start characters. -# -# * Characters '-' and '.' are allowed as name characters. - - -NAME_START_CATEGORIES = ["Ll", "Lu", "Lo", "Lt", "Nl"] -SPLIT_START_CATEGORIES = NAME_START_CATEGORIES + ["Nd"] -NAME_CATEGORIES = NAME_START_CATEGORIES + ["Mc", "Me", "Mn", "Lm", "Nd"] -ALLOWED_NAME_CHARS = ["\u00B7", "\u0387", "-", ".", "_", "%", "(", ")"] - - -# http://www.w3.org/TR/REC-xml-names/#NT-NCName -# [4] NCName ::= (Letter | '_') (NCNameChar)* /* An XML Name, minus -# the ":" */ -# [5] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar -# | Extender - - -def is_ncname(name: str) -> int: - if name: - first = name[0] - if first == "_" or category(first) in NAME_START_CATEGORIES: - for i in range(1, len(name)): - c = name[i] - if not category(c) in NAME_CATEGORIES: # noqa: E713 - if c in ALLOWED_NAME_CHARS: - continue - return 0 - # if in compatibility area - # if decomposition(c)!='': - # return 0 - - return 1 - - return 0 - - -def split_uri( - uri: str, split_start: List[str] = SPLIT_START_CATEGORIES -) -> Tuple[str, str]: - if uri.startswith(XMLNS): - return (XMLNS, uri.split(XMLNS)[1]) - length = len(uri) - for i in range(0, length): - c = uri[-i - 1] - if not category(c) in NAME_CATEGORIES: # noqa: E713 - if c in ALLOWED_NAME_CHARS: - continue - for j in range(-1 - i, length): - if category(uri[j]) in split_start or uri[j] == "_": - # _ prevents early split, roundtrip not generate - ns = uri[:j] - if not ns: - break - ln = uri[j:] - return (ns, ln) - break - raise ValueError("Can't split '{}'".format(uri)) - - -def insert_trie( - trie: Dict[str, Any], value: str -) -> Dict[str, Any]: # aka get_subtrie_or_insert - """Insert a value into the trie if it is not already contained in the trie. - Return the subtree for the value regardless of whether it is a new value - or not.""" - if value in trie: - return trie[value] - multi_check = False - for key in tuple(trie.keys()): - if len(value) > len(key) and value.startswith(key): - return insert_trie(trie[key], value) - elif key.startswith(value): # we know the value is not in the trie - if not multi_check: - trie[value] = {} - multi_check = True # there can be multiple longer existing prefixes - dict_ = trie.pop( - key - ) # does not break strie since key<->dict_ remains unchanged - trie[value][key] = dict_ - if value not in trie: - trie[value] = {} - return trie[value] - - -def insert_strie(strie: Dict[str, Any], trie: Dict[str, Any], value: str) -> None: - if value not in strie: - strie[value] = insert_trie(trie, value) - - -def get_longest_namespace(trie: Dict[str, Any], value: str) -> Optional[str]: - for key in trie: - if value.startswith(key): - out = get_longest_namespace(trie[key], value) - if out is None: - return key - else: - return out - return None - - -from rdflib.namespace._BRICK import BRICK -from rdflib.namespace._CSVW import CSVW -from rdflib.namespace._DC import DC -from rdflib.namespace._DCAM import DCAM -from rdflib.namespace._DCAT import DCAT -from rdflib.namespace._DCMITYPE import DCMITYPE -from rdflib.namespace._DCTERMS import DCTERMS -from rdflib.namespace._DOAP import DOAP -from rdflib.namespace._FOAF import FOAF -from rdflib.namespace._GEO import GEO -from rdflib.namespace._ODRL2 import ODRL2 -from rdflib.namespace._ORG import ORG -from rdflib.namespace._OWL import OWL -from rdflib.namespace._PROF import PROF -from rdflib.namespace._PROV import PROV -from rdflib.namespace._QB import QB -from rdflib.namespace._RDF import RDF -from rdflib.namespace._RDFS import RDFS -from rdflib.namespace._SDO import SDO -from rdflib.namespace._SH import SH -from rdflib.namespace._SKOS import SKOS -from rdflib.namespace._SOSA import SOSA -from rdflib.namespace._SSN import SSN -from rdflib.namespace._TIME import TIME -from rdflib.namespace._VANN import VANN -from rdflib.namespace._VOID import VOID -from rdflib.namespace._WGS import WGS -from rdflib.namespace._XSD import XSD - -# prefixes for the core Namespaces shipped with RDFLib -_NAMESPACE_PREFIXES_CORE = { - "owl": OWL, - "rdf": RDF, - "rdfs": RDFS, - "xsd": XSD, - # Namespace binding for XML - needed for RDF/XML - "xml": XMLNS, -} - - -# prefixes for all the non-core Namespaces shipped with RDFLib -_NAMESPACE_PREFIXES_RDFLIB = { - "brick": BRICK, - "csvw": CSVW, - "dc": DC, - "dcat": DCAT, - "dcmitype": DCMITYPE, - "dcterms": DCTERMS, - "dcam": DCAM, - "doap": DOAP, - "foaf": FOAF, - "geo": GEO, - "odrl": ODRL2, - "org": ORG, - "prof": PROF, - "prov": PROV, - "qb": QB, - "schema": SDO, - "sh": SH, - "skos": SKOS, - "sosa": SOSA, - "ssn": SSN, - "time": TIME, - "vann": VANN, - "void": VOID, - "wgs": WGS, -} diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/parser.py b/extensions/.local/lib/python3.11/site-packages/rdflib/parser.py deleted file mode 100644 index 1c652ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/parser.py +++ /dev/null @@ -1,803 +0,0 @@ -""" -Parser plugin interface. - -This module defines the parser plugin interface and contains other -related parser support code. - -The module is mainly useful for those wanting to write a parser that -can plugin to rdflib. If you are wanting to invoke a parser you likely -want to do so through the Graph class parse method. - -""" - -from __future__ import annotations - -import codecs -import os -import pathlib -import sys -from io import BufferedIOBase, BytesIO, RawIOBase, StringIO, TextIOBase, TextIOWrapper -from typing import ( - IO, - TYPE_CHECKING, - Any, - BinaryIO, - List, - Optional, - TextIO, - Tuple, - Union, - cast, -) -from urllib.parse import urljoin -from urllib.request import Request, url2pathname -from xml.sax import xmlreader - -import rdflib.util -from rdflib import __version__ -from rdflib._networking import _urlopen -from rdflib.namespace import Namespace -from rdflib.term import URIRef - -if TYPE_CHECKING: - from email.message import Message - from io import BufferedReader - from urllib.response import addinfourl - - from typing_extensions import Buffer - - from rdflib.graph import Graph - - -__all__ = [ - "Parser", - "InputSource", - "StringInputSource", - "URLInputSource", - "FileInputSource", - "PythonInputSource", -] - - -class Parser: - __slots__ = () - - def __init__(self): - pass - - def parse(self, source: InputSource, sink: Graph) -> None: - pass - - -class BytesIOWrapper(BufferedIOBase): - __slots__ = ( - "wrapped", - "enc_str", - "text_str", - "encoding", - "encoder", - "has_read1", - "has_seek", - "_name", - "_fileno", - "_isatty", - "_leftover", - "_bytes_per_char", - "_text_bytes_offset", - ) - - def __init__(self, wrapped: Union[str, StringIO, TextIOBase], encoding="utf-8"): - super(BytesIOWrapper, self).__init__() - self.wrapped = wrapped - self.encoding = encoding - self.encoder = codecs.getencoder(self.encoding) - self.enc_str: Optional[Union[BytesIO, BufferedIOBase]] = None - self.text_str: Optional[Union[StringIO, TextIOBase]] = None - self.has_read1: Optional[bool] = None - self.has_seek: Optional[bool] = None - self._name: Optional[str] = None - self._fileno: Optional[Union[int, BaseException]] = None - self._isatty: Optional[Union[bool, BaseException]] = None - self._leftover: bytes = b"" - self._text_bytes_offset: int = 0 - norm_encoding = encoding.lower().replace("_", "-") - if norm_encoding in ("utf-8", "utf8", "u8", "cp65001"): - # utf-8 has a variable number of bytes per character, 1-4 - self._bytes_per_char: int = 1 # assume average of 1 byte per character - elif norm_encoding in ( - "latin1", - "latin-1", - "iso-8859-1", - "iso8859-1", - "ascii", - "us-ascii", - ): - # these are all 1-byte-per-character encodings - self._bytes_per_char = 1 - elif norm_encoding.startswith("utf-16") or norm_encoding.startswith("utf16"): - # utf-16 has a variable number of bytes per character, 2-3 - self._bytes_per_char = 2 # assume average of 2 bytes per character - elif norm_encoding.startswith("utf-32") or norm_encoding.startswith("utf32"): - # utf-32 is fixed length with 4 bytes per character - self._bytes_per_char = 4 - else: - # not sure, just assume it is 2 bytes per character - self._bytes_per_char = 2 - - def _init(self): - name: Optional[str] = None - if isinstance(self.wrapped, str): - b, blen = self.encoder(self.wrapped) - self.enc_str = BytesIO(b) - name = "string" - elif isinstance(self.wrapped, TextIOWrapper): - inner = self.wrapped.buffer - # type error: TextIOWrapper.buffer cannot be a BytesIOWrapper - if isinstance(inner, BytesIOWrapper): # type: ignore[unreachable] - raise Exception( - "BytesIOWrapper cannot be wrapped in TextIOWrapper, " - "then wrapped in another BytesIOWrapper" - ) - else: - self.enc_str = cast(BufferedIOBase, inner) - elif isinstance(self.wrapped, (TextIOBase, StringIO)): - self.text_str = self.wrapped - use_stream: Union[BytesIO, StringIO, BufferedIOBase, TextIOBase] - if self.enc_str is not None: - use_stream = self.enc_str - elif self.text_str is not None: - use_stream = self.text_str - else: - raise Exception("No stream to read from") - if name is None: - try: - name = use_stream.name # type: ignore[union-attr] - except AttributeError: - name = "stream" - self.has_read1 = hasattr(use_stream, "read1") - try: - self.has_seek = use_stream.seekable() - except AttributeError: - self.has_seek = hasattr(use_stream, "seek") - - self._name = name - - def _check_fileno(self): - use_stream: Union[BytesIO, StringIO, BufferedIOBase, TextIOBase] - if self.enc_str is None and self.text_str is None: - self._init() - if self.enc_str is not None: - use_stream = self.enc_str - elif self.text_str is not None: - use_stream = self.text_str - try: - self._fileno = use_stream.fileno() - except OSError as e: - self._fileno = e - except AttributeError: - self._fileno = -1 - - def _check_isatty(self): - use_stream: Union[BytesIO, StringIO, BufferedIOBase, TextIOBase] - if self.enc_str is None and self.text_str is None: - self._init() - if self.enc_str is not None: - use_stream = self.enc_str - elif self.text_str is not None: - use_stream = self.text_str - try: - self._isatty = use_stream.isatty() - except OSError as e: - self._isatty = e - except AttributeError: - self._isatty = False - - @property - def name(self) -> Any: - if self._name is None: - self._init() - return self._name - - @property - def closed(self) -> bool: - if self.enc_str is None and self.text_str is None: - return False - closed: Optional[bool] = None - if self.enc_str is not None: - try: - closed = self.enc_str.closed - except AttributeError: - closed = None - elif self.text_str is not None: - try: - closed = self.text_str.closed - except AttributeError: - closed = None - return False if closed is None else closed - - def readable(self) -> bool: - return True - - def writable(self) -> bool: - return False - - def truncate(self, size: Optional[int] = None) -> int: - raise NotImplementedError("Cannot truncate on BytesIOWrapper") - - def isatty(self) -> bool: - if self._isatty is None: - self._check_isatty() - if isinstance(self._isatty, BaseException): - raise self._isatty - else: - return bool(self._isatty) - - def fileno(self) -> int: - if self._fileno is None: - self._check_fileno() - if isinstance(self._fileno, BaseException): - raise self._fileno - else: - return -1 if self._fileno is None else self._fileno - - def close(self): - if self.enc_str is None and self.text_str is None: - return - if self.enc_str is not None: - try: - self.enc_str.close() - except AttributeError: - pass - elif self.text_str is not None: - try: - self.text_str.close() - except AttributeError: - pass - - def flush(self): - return # Does nothing on read-only streams - - def _read_bytes_from_text_stream(self, size: Optional[int] = -1, /) -> bytes: - if TYPE_CHECKING: - assert self.text_str is not None - if size is None or size < 0: - try: - ret_str: str = self.text_str.read() - except EOFError: - ret_str = "" - ret_encoded, enc_len = self.encoder(ret_str) - if self._leftover: - ret_bytes = self._leftover + ret_encoded - self._leftover = b"" - else: - ret_bytes = ret_encoded - elif size == len(self._leftover): - ret_bytes = self._leftover - self._leftover = b"" - elif size < len(self._leftover): - ret_bytes = self._leftover[:size] - self._leftover = self._leftover[size:] - else: - d, m = divmod(size, self._bytes_per_char) - get_per_loop = int(d) + (1 if m > 0 else 0) - got_bytes: bytes = self._leftover - while len(got_bytes) < size: - try: - got_str: str = self.text_str.read(get_per_loop) - except EOFError: - got_str = "" - if len(got_str) < 1: - break - ret_encoded, enc_len = self.encoder(got_str) - got_bytes += ret_encoded - if len(got_bytes) == size: - self._leftover = b"" - ret_bytes = got_bytes - else: - ret_bytes = got_bytes[:size] - self._leftover = got_bytes[size:] - del got_bytes - self._text_bytes_offset += len(ret_bytes) - return ret_bytes - - def read(self, size: Optional[int] = -1, /) -> bytes: - """ - Read at most size bytes, returned as a bytes object. - - If the size argument is negative or omitted read until EOF is reached. - Return an empty bytes object if already at EOF. - """ - if size is not None and size == 0: - return b"" - if self.enc_str is None and self.text_str is None: - self._init() - if self.enc_str is not None: - ret_bytes = self.enc_str.read(size) - else: - ret_bytes = self._read_bytes_from_text_stream(size) - return ret_bytes - - def read1(self, size: Optional[int] = -1, /) -> bytes: - """ - Read at most size bytes, with at most one call to the underlying raw stream’s - read() or readinto() method. Returned as a bytes object. - - If the size argument is negative or omitted, read until EOF is reached. - Return an empty bytes object at EOF. - """ - if (self.enc_str is None and self.text_str is None) or self.has_read1 is None: - self._init() - if not self.has_read1: - raise NotImplementedError() - if self.enc_str is not None: - if size is None or size < 0: - return self.enc_str.read1() - return self.enc_str.read1(size) - raise NotImplementedError("read1() not supported for TextIO in BytesIOWrapper") - - def readinto(self, b: Buffer, /) -> int: - """ - Read len(b) bytes into buffer b. - - Returns number of bytes read (0 for EOF), or error if the object - is set not to block and has no data to read. - """ - if TYPE_CHECKING: - assert isinstance(b, (memoryview, bytearray)) - if len(b) == 0: - return 0 - if self.enc_str is None and self.text_str is None: - self._init() - if self.enc_str is not None: - return self.enc_str.readinto(b) - else: - size = len(b) - read_data: bytes = self._read_bytes_from_text_stream(size) - read_len = len(read_data) - if read_len == 0: - return 0 - b[:read_len] = read_data - return read_len - - def readinto1(self, b: Buffer, /) -> int: - """ - Read len(b) bytes into buffer b, with at most one call to the underlying raw - stream's read() or readinto() method. - - Returns number of bytes read (0 for EOF), or error if the object - is set not to block and has no data to read. - """ - if TYPE_CHECKING: - assert isinstance(b, (memoryview, bytearray)) - if (self.enc_str is None and self.text_str is None) or self.has_read1 is None: - self._init() - if not self.has_read1: - raise NotImplementedError() - if self.enc_str is not None: - return self.enc_str.readinto1(b) - raise NotImplementedError( - "readinto1() not supported for TextIO in BytesIOWrapper" - ) - - def seek(self, offset: int, whence: int = 0, /) -> int: - if self.has_seek is not None and not self.has_seek: - raise NotImplementedError() - if (self.enc_str is None and self.text_str is None) or self.has_seek is None: - self._init() - - if not whence == 0: - raise NotImplementedError("Only SEEK_SET is supported on BytesIOWrapper") - if offset != 0: - raise NotImplementedError( - "Only seeking to zero is supported on BytesIOWrapper" - ) - if self.enc_str is not None: - self.enc_str.seek(offset, whence) - elif self.text_str is not None: - self.text_str.seek(offset, whence) - self._text_bytes_offset = 0 - self._leftover = b"" - return 0 - - def seekable(self): - if (self.enc_str is None and self.text_str is None) or self.has_seek is None: - self._init() - return self.has_seek - - def tell(self) -> int: - if self.has_seek is not None and not self.has_seek: - raise NotImplementedError("Cannot tell() pos because file is not seekable.") - if self.enc_str is not None: - try: - self._text_bytes_offset = self.enc_str.tell() - except AttributeError: - pass - return self._text_bytes_offset - - def write(self, b, /): - raise NotImplementedError("Cannot write to a BytesIOWrapper") - - -class InputSource(xmlreader.InputSource): - """ - TODO: - """ - - def __init__(self, system_id: Optional[str] = None): - xmlreader.InputSource.__init__(self, system_id=system_id) - self.content_type: Optional[str] = None - self.auto_close = False # see Graph.parse(), true if opened by us - - def close(self) -> None: - c = self.getCharacterStream() - if c and hasattr(c, "close"): - try: - c.close() - except Exception: - pass - f = self.getByteStream() - if f and hasattr(f, "close"): - try: - f.close() - except Exception: - pass - - -class PythonInputSource(InputSource): - """ - Constructs an RDFLib Parser InputSource from a Python data structure, - for example, loaded from JSON with json.load or json.loads: - - >>> import json - >>> as_string = \"\"\"{ - ... "@context" : {"ex" : "http://example.com/ns#"}, - ... "@graph": [{"@type": "ex:item", "@id": "#example"}] - ... }\"\"\" - >>> as_python = json.loads(as_string) - >>> source = create_input_source(data=as_python) - >>> isinstance(source, PythonInputSource) - True - """ - - def __init__(self, data: Any, system_id: Optional[str] = None): - self.content_type = None - self.auto_close = False # see Graph.parse(), true if opened by us - self.public_id: Optional[str] = None - self.system_id: Optional[str] = system_id - self.data = data - - def getPublicId(self) -> Optional[str]: # noqa: N802 - return self.public_id - - def setPublicId(self, public_id: Optional[str]) -> None: # noqa: N802 - self.public_id = public_id - - def getSystemId(self) -> Optional[str]: # noqa: N802 - return self.system_id - - def setSystemId(self, system_id: Optional[str]) -> None: # noqa: N802 - self.system_id = system_id - - def close(self) -> None: - self.data = None - - -class StringInputSource(InputSource): - """ - Constructs an RDFLib Parser InputSource from a Python String or Bytes - """ - - def __init__( - self, - value: Union[str, bytes], - encoding: str = "utf-8", - system_id: Optional[str] = None, - ): - super(StringInputSource, self).__init__(system_id) - stream: Union[BinaryIO, TextIO] - if isinstance(value, str): - stream = StringIO(value) - self.setCharacterStream(stream) - self.setEncoding(encoding) - b_stream = BytesIOWrapper(value, encoding) - self.setByteStream(b_stream) - else: - stream = BytesIO(value) - self.setByteStream(stream) - c_stream = TextIOWrapper(stream, encoding) - self.setCharacterStream(c_stream) - self.setEncoding(c_stream.encoding) - - -headers = { - "User-agent": "rdflib-%s (https://rdflib.github.io/; eikeon@eikeon.com)" - % __version__ -} - - -class URLInputSource(InputSource): - """ - Constructs an RDFLib Parser InputSource from a URL to read it from the Web. - """ - - links: List[str] - - @classmethod - def getallmatchingheaders(cls, message: Message, name) -> List[str]: - # This is reimplemented here, because the method - # getallmatchingheaders from HTTPMessage is broken since Python 3.0 - name = name.lower() - return [val for key, val in message.items() if key.lower() == name] - - @classmethod - def get_links(cls, response: addinfourl) -> List[str]: - linkslines = cls.getallmatchingheaders(response.headers, "Link") - retarray: List[str] = [] - for linksline in linkslines: - links = [linkstr.strip() for linkstr in linksline.split(",")] - for link in links: - retarray.append(link) - return retarray - - def get_alternates(self, type_: Optional[str] = None) -> List[str]: - typestr: Optional[str] = f'type="{type_}"' if type_ else None - relstr = 'rel="alternate"' - alts = [] - for link in self.links: - parts = [p.strip() for p in link.split(";")] - if relstr not in parts: - continue - if typestr: - if typestr in parts: - alts.append(parts[0].strip("<>")) - else: - alts.append(parts[0].strip("<>")) - return alts - - def __init__(self, system_id: Optional[str] = None, format: Optional[str] = None): - super(URLInputSource, self).__init__(system_id) - self.url = system_id - - # copy headers to change - myheaders = dict(headers) - if format == "xml": - myheaders["Accept"] = "application/rdf+xml, */*;q=0.1" - elif format == "n3": - myheaders["Accept"] = "text/n3, */*;q=0.1" - elif format in ["turtle", "ttl"]: - myheaders["Accept"] = "text/turtle, application/x-turtle, */*;q=0.1" - elif format == "nt": - myheaders["Accept"] = "text/plain, */*;q=0.1" - elif format == "trig": - myheaders["Accept"] = "application/trig, */*;q=0.1" - elif format == "trix": - myheaders["Accept"] = "application/trix, */*;q=0.1" - elif format == "json-ld": - myheaders["Accept"] = ( - "application/ld+json, application/json;q=0.9, */*;q=0.1" - ) - else: - # if format not given, create an Accept header from all registered - # parser Media Types - from rdflib.parser import Parser - from rdflib.plugin import plugins - - acc = [] - for p in plugins(kind=Parser): # only get parsers - if "/" in p.name: # all Media Types known have a / in them - acc.append(p.name) - - myheaders["Accept"] = ", ".join(acc) - - req = Request(system_id, None, myheaders) # type: ignore[arg-type] - - response: addinfourl = _urlopen(req) - self.url = response.geturl() # in case redirections took place - self.links = self.get_links(response) - if format in ("json-ld", "application/ld+json"): - alts = self.get_alternates(type_="application/ld+json") - for link in alts: - full_link = urljoin(self.url, link) - if full_link != self.url and full_link != system_id: - response = _urlopen(Request(full_link)) - self.url = response.geturl() # in case redirections took place - break - - self.setPublicId(self.url) - content_types = self.getallmatchingheaders(response.headers, "content-type") - self.content_type = content_types[0] if content_types else None - if self.content_type is not None: - self.content_type = self.content_type.split(";", 1)[0] - self.setByteStream(response) - # TODO: self.setEncoding(encoding) - self.response_info = response.info() # a mimetools.Message instance - - def __repr__(self) -> str: - # type error: Incompatible return value type (got "Optional[str]", expected "str") - return self.url # type: ignore[return-value] - - -class FileInputSource(InputSource): - def __init__( - self, - file: Union[BinaryIO, TextIO, TextIOBase, RawIOBase, BufferedIOBase], - /, - encoding: Optional[str] = None, - ): - base = pathlib.Path.cwd().as_uri() - system_id = URIRef(pathlib.Path(file.name).absolute().as_uri(), base=base) # type: ignore[union-attr] - super(FileInputSource, self).__init__(system_id) - self.file = file - if isinstance(file, TextIOBase): # Python3 unicode fp - self.setCharacterStream(file) - self.setEncoding(file.encoding) - try: - b = file.buffer # type: ignore[attr-defined] - self.setByteStream(b) - except (AttributeError, LookupError): - self.setByteStream(BytesIOWrapper(file, encoding=file.encoding)) - else: - if TYPE_CHECKING: - assert isinstance(file, BufferedReader) - self.setByteStream(file) - if encoding is not None: - self.setEncoding(encoding) - self.setCharacterStream(TextIOWrapper(file, encoding=encoding)) - else: - # We cannot set characterStream here because - # we do not know the Raw Bytes File encoding. - pass - - def __repr__(self) -> str: - return repr(self.file) - - -def create_input_source( - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ] = None, - publicID: Optional[str] = None, # noqa: N803 - location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes, dict]] = None, - format: Optional[str] = None, -) -> InputSource: - """ - Return an appropriate InputSource instance for the given - parameters. - """ - - # test that exactly one of source, location, file, and data is not None. - non_empty_arguments = list( - filter( - lambda v: v is not None, - [source, location, file, data], - ) - ) - - if len(non_empty_arguments) != 1: - raise ValueError( - "exactly one of source, location, file or data must be given", - ) - - input_source = None - - if source is not None: - if TYPE_CHECKING: - assert file is None - assert data is None - assert location is None - if isinstance(source, InputSource): - input_source = source - else: - if isinstance(source, str): - location = source - elif isinstance(source, pathlib.PurePath): - location = str(source) - elif isinstance(source, bytes): - data = source - elif hasattr(source, "read") and not isinstance(source, Namespace): - f = source - input_source = InputSource() - if hasattr(source, "encoding"): - input_source.setCharacterStream(source) - input_source.setEncoding(source.encoding) - try: - b = source.buffer # type: ignore[union-attr] - input_source.setByteStream(b) - except (AttributeError, LookupError): - input_source.setByteStream(source) - else: - input_source.setByteStream(f) - if f is sys.stdin: - input_source.setSystemId("file:///dev/stdin") - elif hasattr(f, "name"): - input_source.setSystemId(f.name) - else: - raise Exception( - "Unexpected type '%s' for source '%s'" % (type(source), source) - ) - - absolute_location = None # Further to fix for issue 130 - - auto_close = False # make sure we close all file handles we open - - if location is not None: - if TYPE_CHECKING: - assert file is None - assert data is None - assert source is None - ( - absolute_location, - auto_close, - file, - input_source, - ) = _create_input_source_from_location( - file=file, - format=format, - input_source=input_source, - location=location, - ) - - if file is not None: - if TYPE_CHECKING: - assert location is None - assert data is None - assert source is None - input_source = FileInputSource(file) - - if data is not None: - if TYPE_CHECKING: - assert location is None - assert file is None - assert source is None - if isinstance(data, dict): - input_source = PythonInputSource(data) - auto_close = True - elif isinstance(data, (str, bytes, bytearray)): - input_source = StringInputSource(data) - auto_close = True - else: - raise RuntimeError(f"parse data can only str, or bytes. not: {type(data)}") - - if input_source is None: - raise Exception("could not create InputSource") - else: - input_source.auto_close |= auto_close - if publicID is not None: # Further to fix for issue 130 - input_source.setPublicId(publicID) - # Further to fix for issue 130 - elif input_source.getPublicId() is None: - input_source.setPublicId(absolute_location or "") - return input_source - - -def _create_input_source_from_location( - file: Optional[Union[BinaryIO, TextIO]], - format: Optional[str], - input_source: Optional[InputSource], - location: str, -) -> Tuple[URIRef, bool, Optional[Union[BinaryIO, TextIO]], Optional[InputSource]]: - # Fix for Windows problem https://github.com/RDFLib/rdflib/issues/145 and - # https://github.com/RDFLib/rdflib/issues/1430 - # NOTE: using pathlib.Path.exists on a URL fails on windows as it is not a - # valid path. However os.path.exists() returns false for a URL on windows - # which is why it is being used instead. - if os.path.exists(location): - location = pathlib.Path(location).absolute().as_uri() - - base = pathlib.Path.cwd().as_uri() - - absolute_location = URIRef(rdflib.util._iri2uri(location), base=base) - - if absolute_location.startswith("file:///"): - filename = url2pathname(absolute_location.replace("file:///", "/")) - file = open(filename, "rb") - else: - input_source = URLInputSource(absolute_location, format) - - auto_close = True - # publicID = publicID or absolute_location # Further to fix - # for issue 130 - - return absolute_location, auto_close, file, input_source diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/paths.py b/extensions/.local/lib/python3.11/site-packages/rdflib/paths.py deleted file mode 100644 index 3692bad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/paths.py +++ /dev/null @@ -1,611 +0,0 @@ -r""" - -This module implements the SPARQL 1.1 Property path operators, as -defined in: - -http://www.w3.org/TR/sparql11-query/#propertypaths - -In SPARQL the syntax is as follows: - -+--------------------+-------------------------------------------------+ -|Syntax | Matches | -+====================+=================================================+ -|iri | An IRI. A path of length one. | -+--------------------+-------------------------------------------------+ -|^elt | Inverse path (object to subject). | -+--------------------+-------------------------------------------------+ -|elt1 / elt2 | A sequence path of elt1 followed by elt2. | -+--------------------+-------------------------------------------------+ -|elt1 | elt2 | A alternative path of elt1 or elt2 | -| | (all possibilities are tried). | -+--------------------+-------------------------------------------------+ -|elt* | A path that connects the subject and object | -| | of the path by zero or more matches of elt. | -+--------------------+-------------------------------------------------+ -|elt+ | A path that connects the subject and object | -| | of the path by one or more matches of elt. | -+--------------------+-------------------------------------------------+ -|elt? | A path that connects the subject and object | -| | of the path by zero or one matches of elt. | -+--------------------+-------------------------------------------------+ -|!iri or | Negated property set. An IRI which is not one of| -|!(iri\ :sub:`1`\ \| | iri\ :sub:`1`...iri\ :sub:`n`. | -|... \|iri\ :sub:`n`)| !iri is short for !(iri). | -+--------------------+-------------------------------------------------+ -|!^iri or | Negated property set where the excluded matches | -|!(^iri\ :sub:`1`\ \|| are based on reversed path. That is, not one of | -|...\|^iri\ :sub:`n`)| iri\ :sub:`1`...iri\ :sub:`n` as reverse paths. | -| | !^iri is short for !(^iri). | -+--------------------+-------------------------------------------------+ -|!(iri\ :sub:`1`\ \| | A combination of forward and reverse | -|...\|iri\ :sub:`j`\ | properties in a negated property set. | -|\|^iri\ :sub:`j+1`\ | | -|\|... \|^iri\ | | -|:sub:`n`)| | | -+--------------------+-------------------------------------------------+ -|(elt) | A group path elt, brackets control precedence. | -+--------------------+-------------------------------------------------+ - -This module is used internally by the SPARQL engine, but the property paths -can also be used to query RDFLib Graphs directly. - -Where possible the SPARQL syntax is mapped to Python operators, and property -path objects can be constructed from existing URIRefs. - ->>> from rdflib import Graph, Namespace ->>> from rdflib.namespace import FOAF - ->>> ~FOAF.knows -Path(~http://xmlns.com/foaf/0.1/knows) - ->>> FOAF.knows/FOAF.name -Path(http://xmlns.com/foaf/0.1/knows / http://xmlns.com/foaf/0.1/name) - ->>> FOAF.name|FOAF.givenName -Path(http://xmlns.com/foaf/0.1/name | http://xmlns.com/foaf/0.1/givenName) - -Modifiers (?, \*, +) are done using \* (the multiplication operator) and -the strings '\*', '?', '+', also defined as constants in this file. - ->>> FOAF.knows*OneOrMore -Path(http://xmlns.com/foaf/0.1/knows+) - -The path objects can also be used with the normal graph methods. - -First some example data: - ->>> g=Graph() - ->>> g=g.parse(data=''' -... @prefix : . -... -... :a :p1 :c ; :p2 :f . -... :c :p2 :e ; :p3 :g . -... :g :p3 :h ; :p2 :j . -... :h :p3 :a ; :p2 :g . -... -... :q :px :q . -... -... ''', format='n3') # doctest: +ELLIPSIS - ->>> e = Namespace('ex:') - -Graph contains: - ->>> (e.a, e.p1/e.p2, e.e) in g -True - -Graph generator functions, triples, subjects, objects, etc. : - ->>> list(g.objects(e.c, (e.p3*OneOrMore)/e.p2)) # doctest: +NORMALIZE_WHITESPACE -[rdflib.term.URIRef('ex:j'), rdflib.term.URIRef('ex:g'), - rdflib.term.URIRef('ex:f')] - -A more complete set of tests: - ->>> list(eval_path(g, (None, e.p1/e.p2, None)))==[(e.a, e.e)] -True ->>> list(eval_path(g, (e.a, e.p1|e.p2, None)))==[(e.a,e.c), (e.a,e.f)] -True ->>> list(eval_path(g, (e.c, ~e.p1, None))) == [ (e.c, e.a) ] -True ->>> list(eval_path(g, (e.a, e.p1*ZeroOrOne, None))) == [(e.a, e.a), (e.a, e.c)] -True ->>> list(eval_path(g, (e.c, e.p3*OneOrMore, None))) == [ -... (e.c, e.g), (e.c, e.h), (e.c, e.a)] -True ->>> list(eval_path(g, (e.c, e.p3*ZeroOrMore, None))) == [(e.c, e.c), -... (e.c, e.g), (e.c, e.h), (e.c, e.a)] -True ->>> list(eval_path(g, (e.a, -e.p1, None))) == [(e.a, e.f)] -True ->>> list(eval_path(g, (e.a, -(e.p1|e.p2), None))) == [] -True ->>> list(eval_path(g, (e.g, -~e.p2, None))) == [(e.g, e.j)] -True ->>> list(eval_path(g, (e.e, ~(e.p1/e.p2), None))) == [(e.e, e.a)] -True ->>> list(eval_path(g, (e.a, e.p1/e.p3/e.p3, None))) == [(e.a, e.h)] -True - ->>> list(eval_path(g, (e.q, e.px*OneOrMore, None))) -[(rdflib.term.URIRef('ex:q'), rdflib.term.URIRef('ex:q'))] - ->>> list(eval_path(g, (None, e.p1|e.p2, e.c))) -[(rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:c'))] - ->>> list(eval_path(g, (None, ~e.p1, e.a))) == [ (e.c, e.a) ] -True ->>> list(eval_path(g, (None, e.p1*ZeroOrOne, e.c))) # doctest: +NORMALIZE_WHITESPACE -[(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:c')), - (rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:c'))] - ->>> list(eval_path(g, (None, e.p3*OneOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE -[(rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a'))] - ->>> list(eval_path(g, (None, e.p3*ZeroOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE -[(rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a'))] - ->>> list(eval_path(g, (None, -e.p1, e.f))) == [(e.a, e.f)] -True ->>> list(eval_path(g, (None, -(e.p1|e.p2), e.c))) == [] -True ->>> list(eval_path(g, (None, -~e.p2, e.j))) == [(e.g, e.j)] -True ->>> list(eval_path(g, (None, ~(e.p1/e.p2), e.a))) == [(e.e, e.a)] -True ->>> list(eval_path(g, (None, e.p1/e.p3/e.p3, e.h))) == [(e.a, e.h)] -True - ->>> list(eval_path(g, (e.q, e.px*OneOrMore, None))) -[(rdflib.term.URIRef('ex:q'), rdflib.term.URIRef('ex:q'))] - ->>> list(eval_path(g, (e.c, (e.p2|e.p3)*ZeroOrMore, e.j))) -[(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:j'))] - -No vars specified: - ->>> sorted(list(eval_path(g, (None, e.p3*OneOrMore, None)))) #doctest: +NORMALIZE_WHITESPACE -[(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:g')), - (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:h')), - (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')), - (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:h')), - (rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a'))] - -""" - -from __future__ import annotations - -import warnings -from abc import ABC, abstractmethod -from functools import total_ordering -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generator, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) - -from rdflib.term import Node, URIRef - -if TYPE_CHECKING: - from rdflib._type_checking import _MulPathMod - from rdflib.graph import Graph, _ObjectType, _PredicateType, _SubjectType - from rdflib.namespace import NamespaceManager - - -# property paths - -ZeroOrMore = "*" -OneOrMore = "+" -ZeroOrOne = "?" - - -def _n3( - arg: Union[URIRef, Path], namespace_manager: Optional[NamespaceManager] = None -) -> str: - if isinstance(arg, (SequencePath, AlternativePath)) and len(arg.args) > 1: - return "(%s)" % arg.n3(namespace_manager) - return arg.n3(namespace_manager) - - -@total_ordering -class Path(ABC): - __or__: Callable[[Path, Union[URIRef, Path]], AlternativePath] - __invert__: Callable[[Path], InvPath] - __neg__: Callable[[Path], NegatedPath] - __truediv__: Callable[[Path, Union[URIRef, Path]], SequencePath] - __mul__: Callable[[Path, str], MulPath] - - @abstractmethod - def eval( - self, - graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Iterator[Tuple[_SubjectType, _ObjectType]]: ... - - @abstractmethod - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: ... - - def __hash__(self): - return hash(repr(self)) - - def __eq__(self, other): - return repr(self) == repr(other) - - def __lt__(self, other: Any) -> bool: - if not isinstance(other, (Path, Node)): - raise TypeError( - "unorderable types: %s() < %s()" % (repr(self), repr(other)) - ) - return repr(self) < repr(other) - - -class InvPath(Path): - def __init__(self, arg: Union[Path, URIRef]): - self.arg = arg - - def eval( - self, - graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_ObjectType, _SubjectType], None, None]: - for s, o in eval_path(graph, (obj, self.arg, subj)): - yield o, s - - def __repr__(self) -> str: - return "Path(~%s)" % (self.arg,) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - return "^%s" % _n3(self.arg, namespace_manager) - - -class SequencePath(Path): - def __init__(self, *args: Union[Path, URIRef]): - self.args: List[Union[Path, URIRef]] = [] - for a in args: - if isinstance(a, SequencePath): - self.args += a.args - else: - self.args.append(a) - - def eval( - self, - graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - def _eval_seq( - paths: List[Union[Path, URIRef]], - subj: Optional[_SubjectType], - obj: Optional[_ObjectType], - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - if paths[1:]: - for s, o in eval_path(graph, (subj, paths[0], None)): - for r in _eval_seq(paths[1:], o, obj): - yield s, r[1] - - else: - for s, o in eval_path(graph, (subj, paths[0], obj)): - yield s, o - - def _eval_seq_bw( - paths: List[Union[Path, URIRef]], - subj: Optional[_SubjectType], - obj: _ObjectType, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - if paths[:-1]: - for s, o in eval_path(graph, (None, paths[-1], obj)): - for r in _eval_seq(paths[:-1], subj, s): - yield r[0], o - - else: - for s, o in eval_path(graph, (subj, paths[0], obj)): - yield s, o - - if subj: - return _eval_seq(self.args, subj, obj) - elif obj: - return _eval_seq_bw(self.args, subj, obj) - else: # no vars bound, we can start anywhere - return _eval_seq(self.args, subj, obj) - - def __repr__(self) -> str: - return "Path(%s)" % " / ".join(str(x) for x in self.args) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - return "/".join(_n3(a, namespace_manager) for a in self.args) - - -class AlternativePath(Path): - def __init__(self, *args: Union[Path, URIRef]): - self.args: List[Union[Path, URIRef]] = [] - for a in args: - if isinstance(a, AlternativePath): - self.args += a.args - else: - self.args.append(a) - - def eval( - self, - graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - for x in self.args: - for y in eval_path(graph, (subj, x, obj)): - yield y - - def __repr__(self) -> str: - return "Path(%s)" % " | ".join(str(x) for x in self.args) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - return "|".join(_n3(a, namespace_manager) for a in self.args) - - -class MulPath(Path): - def __init__(self, path: Union[Path, URIRef], mod: _MulPathMod): - self.path = path - self.mod = mod - - if mod == ZeroOrOne: - self.zero = True - self.more = False - elif mod == ZeroOrMore: - self.zero = True - self.more = True - elif mod == OneOrMore: - self.zero = False - self.more = True - else: - raise Exception("Unknown modifier %s" % mod) - - def eval( - self, - graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - first: bool = True, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - if self.zero and first: - if subj and obj: - if subj == obj: - yield subj, obj - elif subj: - yield subj, subj - elif obj: - yield obj, obj - - def _fwd( - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - seen: Optional[Set[_SubjectType]] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add" - # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node" - seen.add(subj) # type: ignore[union-attr, arg-type] - - for s, o in eval_path(graph, (subj, self.path, None)): - if not obj or o == obj: - yield s, o - if self.more: - # type error: Unsupported right operand type for in ("Optional[Set[Node]]") - if o in seen: # type: ignore[operator] - continue - for s2, o2 in _fwd(o, obj, seen): - yield s, o2 - - def _bwd( - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - seen: Optional[Set[_ObjectType]] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add" - # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node" - seen.add(obj) # type: ignore[union-attr, arg-type] - - for s, o in eval_path(graph, (None, self.path, obj)): - if not subj or subj == s: - yield s, o - if self.more: - # type error: Unsupported right operand type for in ("Optional[Set[Node]]") - if s in seen: # type: ignore[operator] - continue - - for s2, o2 in _bwd(None, s, seen): - yield s2, o - - def _all_fwd_paths() -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - if self.zero: - seen1 = set() - # According to the spec, ALL nodes are possible solutions - # (even literals) - # we cannot do this without going through ALL triples - # unless we keep an index of all terms somehow - # but let's just hope this query doesn't happen very often... - for s, o in graph.subject_objects(None): - if s not in seen1: - seen1.add(s) - yield s, s - if o not in seen1: - seen1.add(o) - yield o, o - - seen = set() - for s, o in eval_path(graph, (None, self.path, None)): - if not self.more: - yield s, o - else: - if s not in seen: - seen.add(s) - f = list(_fwd(s, None, set())) - for s1, o1 in f: - assert s1 == s - yield s1, o1 - - done = set() # the spec does, by defn, not allow duplicates - if subj: - for x in _fwd(subj, obj, set()): - if x not in done: - done.add(x) - yield x - elif obj: - for x in _bwd(subj, obj, set()): - if x not in done: - done.add(x) - yield x - else: - for x in _all_fwd_paths(): - if x not in done: - done.add(x) - yield x - - def __repr__(self) -> str: - return "Path(%s%s)" % (self.path, self.mod) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - return "%s%s" % (_n3(self.path, namespace_manager), self.mod) - - -class NegatedPath(Path): - def __init__(self, arg: Union[AlternativePath, InvPath, URIRef]): - self.args: List[Union[URIRef, Path]] - if isinstance(arg, (URIRef, InvPath)): - self.args = [arg] - elif isinstance(arg, AlternativePath): - self.args = arg.args - else: - raise Exception( - "Can only negate URIRefs, InvPaths or " - + "AlternativePaths, not: %s" % (arg,) - ) - - def eval(self, graph, subj=None, obj=None): - for s, p, o in graph.triples((subj, None, obj)): - for a in self.args: - if isinstance(a, URIRef): - if p == a: - break - elif isinstance(a, InvPath): - if (o, a.arg, s) in graph: - break - else: - raise Exception("Invalid path in NegatedPath: %s" % a) - else: - yield s, o - - def __repr__(self) -> str: - return "Path(! %s)" % ",".join(str(x) for x in self.args) - - def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: - return "!(%s)" % ("|".join(_n3(arg, namespace_manager) for arg in self.args)) - - -class PathList(list): - pass - - -def path_alternative(self: Union[URIRef, Path], other: Union[URIRef, Path]): - """ - alternative path - """ - if not isinstance(other, (URIRef, Path)): - raise Exception("Only URIRefs or Paths can be in paths!") - return AlternativePath(self, other) - - -def path_sequence(self: Union[URIRef, Path], other: Union[URIRef, Path]): - """ - sequence path - """ - if not isinstance(other, (URIRef, Path)): - raise Exception("Only URIRefs or Paths can be in paths!") - return SequencePath(self, other) - - -def evalPath( # noqa: N802 - graph: Graph, - t: Tuple[ - Optional[_SubjectType], - Union[None, Path, _PredicateType], - Optional[_ObjectType], - ], -) -> Iterator[Tuple[_SubjectType, _ObjectType]]: - warnings.warn( - DeprecationWarning( - "rdflib.path.evalPath() is deprecated, use the (snake-cased) eval_path(). " - "The mixed-case evalPath() function name is incompatible with PEP8 " - "recommendations and will be replaced by eval_path() in rdflib 7.0.0." - ) - ) - return eval_path(graph, t) - - -def eval_path( - graph: Graph, - t: Tuple[ - Optional[_SubjectType], - Union[None, Path, _PredicateType], - Optional[_ObjectType], - ], -) -> Iterator[Tuple[_SubjectType, _ObjectType]]: - return ((s, o) for s, p, o in graph.triples(t)) - - -def mul_path(p: Union[URIRef, Path], mul: _MulPathMod) -> MulPath: - """ - cardinality path - """ - return MulPath(p, mul) - - -def inv_path(p: Union[URIRef, Path]) -> InvPath: - """ - inverse path - """ - return InvPath(p) - - -def neg_path(p: Union[URIRef, AlternativePath, InvPath]) -> NegatedPath: - """ - negated path - """ - return NegatedPath(p) - - -if __name__ == "__main__": - pass -else: - # monkey patch - # (these cannot be directly in terms.py - # as it would introduce circular imports) - - URIRef.__or__ = path_alternative - # ignore typing here as URIRef inherits from str, - # which has an incompatible definition of __mul__. - URIRef.__mul__ = mul_path # type: ignore - URIRef.__invert__ = inv_path - URIRef.__neg__ = neg_path - URIRef.__truediv__ = path_sequence - - Path.__invert__ = inv_path - # type error: Incompatible types in assignment (expression has type "Callable[[Union[URIRef, AlternativePath, InvPath]], NegatedPath]", variable has type "Callable[[Path], NegatedPath]") - Path.__neg__ = neg_path # type: ignore[assignment] - # type error: Incompatible types in assignment (expression has type "Callable[[Union[URIRef, Path], Literal['*', '+', '?']], MulPath]", variable has type "Callable[[Path, str], MulPath]") - Path.__mul__ = mul_path # type: ignore[assignment] - Path.__or__ = path_alternative - Path.__truediv__ = path_sequence diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugin.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugin.py deleted file mode 100644 index 23699e6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugin.py +++ /dev/null @@ -1,629 +0,0 @@ -""" -Plugin support for rdf. - -There are a number of plugin points for rdf: parser, serializer, -store, query processor, and query result. Plugins can be registered -either through setuptools entry_points or by calling -rdf.plugin.register directly. - -If you have a package that uses a setuptools based setup.py you can add the -following to your setup:: - - entry_points = { - 'rdf.plugins.parser': [ - 'nt = rdf.plugins.parsers.ntriples:NTParser', - ], - 'rdf.plugins.serializer': [ - 'nt = rdf.plugins.serializers.NTSerializer:NTSerializer', - ], - } - -See the `setuptools dynamic discovery of services and plugins`__ for more -information. - -.. __: http://peak.telecommunity.com/DevCenter/setuptools#dynamic-discovery-of-services-and-plugins - -""" - -from __future__ import annotations - -from importlib.metadata import EntryPoint, entry_points -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Generic, - Iterator, - Optional, - Tuple, - Type, - TypeVar, - overload, -) - -import rdflib.plugins.stores.berkeleydb -from rdflib.exceptions import Error -from rdflib.parser import Parser -from rdflib.query import ( - Processor, - Result, - ResultParser, - ResultSerializer, - UpdateProcessor, -) -from rdflib.serializer import Serializer -from rdflib.store import Store - -__all__ = [ - "register", - "get", - "plugins", - "PluginException", - "Plugin", - "PluginT", - "PKGPlugin", -] - -rdflib_entry_points = { - "rdf.plugins.store": Store, - "rdf.plugins.serializer": Serializer, - "rdf.plugins.parser": Parser, - "rdf.plugins.resultparser": ResultParser, - "rdf.plugins.resultserializer": ResultSerializer, - "rdf.plugins.queryprocessor": Processor, - "rdf.plugins.queryresult": Result, - "rdf.plugins.updateprocessor": UpdateProcessor, -} - -_plugins: Dict[Tuple[str, Type[Any]], Plugin] = {} - - -class PluginException(Error): # noqa: N818 - pass - - -#: A generic type variable for plugins -PluginT = TypeVar("PluginT") - - -class Plugin(Generic[PluginT]): - def __init__( - self, name: str, kind: Type[PluginT], module_path: str, class_name: str - ): - self.name = name - self.kind = kind - self.module_path = module_path - self.class_name = class_name - self._class: Optional[Type[PluginT]] = None - - def getClass(self) -> Type[PluginT]: # noqa: N802 - if self._class is None: - module = __import__(self.module_path, globals(), locals(), [""]) - self._class = getattr(module, self.class_name) - return self._class - - -class PKGPlugin(Plugin[PluginT]): - def __init__(self, name: str, kind: Type[PluginT], ep: EntryPoint): - self.name = name - self.kind = kind - self.ep = ep - self._class: Optional[Type[PluginT]] = None - - def getClass(self) -> Type[PluginT]: # noqa: N802 - if self._class is None: - self._class = self.ep.load() - return self._class - - -def register(name: str, kind: Type[Any], module_path, class_name): - """ - Register the plugin for (name, kind). The module_path and - class_name should be the path to a plugin class. - """ - p = Plugin(name, kind, module_path, class_name) - _plugins[(name, kind)] = p - - -def get(name: str, kind: Type[PluginT]) -> Type[PluginT]: - """ - Return the class for the specified (name, kind). Raises a - PluginException if unable to do so. - """ - try: - p: Plugin[PluginT] = _plugins[(name, kind)] - except KeyError: - raise PluginException("No plugin registered for (%s, %s)" % (name, kind)) - return p.getClass() - - -all_entry_points = entry_points() -if hasattr(all_entry_points, "select"): - for entry_point, kind in rdflib_entry_points.items(): - for ep in all_entry_points.select(group=entry_point): - _plugins[(ep.name, kind)] = PKGPlugin(ep.name, kind, ep) -else: - # Prior to Python 3.10, this returns a dict instead of the selection interface, which is slightly slower - if TYPE_CHECKING: - assert isinstance(all_entry_points, dict) - for entry_point, kind in rdflib_entry_points.items(): - for ep in all_entry_points.get(entry_point, []): - _plugins[(ep.name, kind)] = PKGPlugin(ep.name, kind, ep) - - -@overload -def plugins( - name: Optional[str] = ..., kind: Type[PluginT] = ... -) -> Iterator[Plugin[PluginT]]: ... - - -@overload -def plugins(name: Optional[str] = ..., kind: None = ...) -> Iterator[Plugin]: ... - - -def plugins( - name: Optional[str] = None, kind: Optional[Type[PluginT]] = None -) -> Iterator[Plugin[PluginT]]: - """ - A generator of the plugins. - - Pass in name and kind to filter... else leave None to match all. - """ - for p in _plugins.values(): - if (name is None or name == p.name) and (kind is None or kind == p.kind): - yield p - - -# Register Stores - -if rdflib.plugins.stores.berkeleydb.has_bsddb: - # Checks for BerkeleyDB before registering it - register( - "BerkeleyDB", - Store, - "rdflib.plugins.stores.berkeleydb", - "BerkeleyDB", - ) -register( - "default", - Store, - "rdflib.plugins.stores.memory", - "Memory", -) -register( - "Memory", - Store, - "rdflib.plugins.stores.memory", - "Memory", -) -register( - "SimpleMemory", - Store, - "rdflib.plugins.stores.memory", - "SimpleMemory", -) -register( - "Auditable", - Store, - "rdflib.plugins.stores.auditable", - "AuditableStore", -) -register( - "Concurrent", - Store, - "rdflib.plugins.stores.concurrent", - "ConcurrentStore", -) - -register( - "SPARQLStore", - Store, - "rdflib.plugins.stores.sparqlstore", - "SPARQLStore", -) -register( - "SPARQLUpdateStore", - Store, - "rdflib.plugins.stores.sparqlstore", - "SPARQLUpdateStore", -) - -# Register Triple Serializers -register( - "application/rdf+xml", - Serializer, - "rdflib.plugins.serializers.rdfxml", - "XMLSerializer", -) -register( - "xml", - Serializer, - "rdflib.plugins.serializers.rdfxml", - "XMLSerializer", -) -register( - "pretty-xml", - Serializer, - "rdflib.plugins.serializers.rdfxml", - "PrettyXMLSerializer", -) -register( - "text/n3", - Serializer, - "rdflib.plugins.serializers.n3", - "N3Serializer", -) -register( - "n3", - Serializer, - "rdflib.plugins.serializers.n3", - "N3Serializer", -) -register( - "text/turtle", - Serializer, - "rdflib.plugins.serializers.turtle", - "TurtleSerializer", -) -register( - "turtle", - Serializer, - "rdflib.plugins.serializers.turtle", - "TurtleSerializer", -) -register( - "ttl", - Serializer, - "rdflib.plugins.serializers.turtle", - "TurtleSerializer", -) -register( - "longturtle", - Serializer, - "rdflib.plugins.serializers.longturtle", - "LongTurtleSerializer", -) -register( - "application/n-triples", - Serializer, - "rdflib.plugins.serializers.nt", - "NTSerializer", -) -register( - "ntriples", - Serializer, - "rdflib.plugins.serializers.nt", - "NTSerializer", -) -register( - "nt", - Serializer, - "rdflib.plugins.serializers.nt", - "NTSerializer", -) -register( - "nt11", - Serializer, - "rdflib.plugins.serializers.nt", - "NT11Serializer", -) -register( - "json-ld", - Serializer, - "rdflib.plugins.serializers.jsonld", - "JsonLDSerializer", -) -register( - "application/ld+json", - Serializer, - "rdflib.plugins.serializers.jsonld", - "JsonLDSerializer", -) - -# Register Quad Serializers -register( - "application/n-quads", - Serializer, - "rdflib.plugins.serializers.nquads", - "NQuadsSerializer", -) -register( - "nquads", - Serializer, - "rdflib.plugins.serializers.nquads", - "NQuadsSerializer", -) -register( - "application/trix", - Serializer, - "rdflib.plugins.serializers.trix", - "TriXSerializer", -) -register( - "trix", - Serializer, - "rdflib.plugins.serializers.trix", - "TriXSerializer", -) -register( - "application/trig", - Serializer, - "rdflib.plugins.serializers.trig", - "TrigSerializer", -) -register( - "trig", - Serializer, - "rdflib.plugins.serializers.trig", - "TrigSerializer", -) -register( - "hext", - Serializer, - "rdflib.plugins.serializers.hext", - "HextuplesSerializer", -) -register( - "patch", - Serializer, - "rdflib.plugins.serializers.patch", - "PatchSerializer", -) - -# Register Triple Parsers -register( - "application/rdf+xml", - Parser, - "rdflib.plugins.parsers.rdfxml", - "RDFXMLParser", -) -register( - "xml", - Parser, - "rdflib.plugins.parsers.rdfxml", - "RDFXMLParser", -) -register( - "text/n3", - Parser, - "rdflib.plugins.parsers.notation3", - "N3Parser", -) -register( - "n3", - Parser, - "rdflib.plugins.parsers.notation3", - "N3Parser", -) -register( - "text/turtle", - Parser, - "rdflib.plugins.parsers.notation3", - "TurtleParser", -) -register( - "turtle", - Parser, - "rdflib.plugins.parsers.notation3", - "TurtleParser", -) -register( - "ttl", - Parser, - "rdflib.plugins.parsers.notation3", - "TurtleParser", -) -register( - "application/n-triples", - Parser, - "rdflib.plugins.parsers.ntriples", - "NTParser", -) -register( - "ntriples", - Parser, - "rdflib.plugins.parsers.ntriples", - "NTParser", -) -register( - "nt", - Parser, - "rdflib.plugins.parsers.ntriples", - "NTParser", -) -register( - "nt11", - Parser, - "rdflib.plugins.parsers.ntriples", - "NTParser", -) -register( - "application/ld+json", - Parser, - "rdflib.plugins.parsers.jsonld", - "JsonLDParser", -) -register( - "json-ld", - Parser, - "rdflib.plugins.parsers.jsonld", - "JsonLDParser", -) - -# Register Quad Parsers -register( - "application/n-quads", - Parser, - "rdflib.plugins.parsers.nquads", - "NQuadsParser", -) -register( - "nquads", - Parser, - "rdflib.plugins.parsers.nquads", - "NQuadsParser", -) -register( - "application/trix", - Parser, - "rdflib.plugins.parsers.trix", - "TriXParser", -) -register( - "trix", - Parser, - "rdflib.plugins.parsers.trix", - "TriXParser", -) -register( - "application/trig", - Parser, - "rdflib.plugins.parsers.trig", - "TrigParser", -) -register( - "trig", - Parser, - "rdflib.plugins.parsers.trig", - "TrigParser", -) -register( - "hext", - Parser, - "rdflib.plugins.parsers.hext", - "HextuplesParser", -) - -# Register RDF Patch Parsers -register( - "patch", - Parser, - "rdflib.plugins.parsers.patch", - "RDFPatchParser", -) - -# Register SPARQL Processors -register( - "sparql", - Result, - "rdflib.plugins.sparql.processor", - "SPARQLResult", -) -register( - "sparql", - Processor, - "rdflib.plugins.sparql.processor", - "SPARQLProcessor", -) -register( - "sparql", - UpdateProcessor, - "rdflib.plugins.sparql.processor", - "SPARQLUpdateProcessor", -) - -# Register SPARQL Result Serializers -register( - "xml", - ResultSerializer, - "rdflib.plugins.sparql.results.xmlresults", - "XMLResultSerializer", -) -register( - "application/sparql-results+xml", - ResultSerializer, - "rdflib.plugins.sparql.results.xmlresults", - "XMLResultSerializer", -) -register( - "txt", - ResultSerializer, - "rdflib.plugins.sparql.results.txtresults", - "TXTResultSerializer", -) -register( - "json", - ResultSerializer, - "rdflib.plugins.sparql.results.jsonresults", - "JSONResultSerializer", -) -register( - "application/sparql-results+json", - ResultSerializer, - "rdflib.plugins.sparql.results.jsonresults", - "JSONResultSerializer", -) -register( - "csv", - ResultSerializer, - "rdflib.plugins.sparql.results.csvresults", - "CSVResultSerializer", -) -register( - "text/csv", - ResultSerializer, - "rdflib.plugins.sparql.results.csvresults", - "CSVResultSerializer", -) - -# Register SPARQL Result Parsers -register( - "xml", - ResultParser, - "rdflib.plugins.sparql.results.xmlresults", - "XMLResultParser", -) -register( - "application/sparql-results+xml", - ResultParser, - "rdflib.plugins.sparql.results.xmlresults", - "XMLResultParser", -) -register( - "application/sparql-results+xml; charset=UTF-8", - ResultParser, - "rdflib.plugins.sparql.results.xmlresults", - "XMLResultParser", -) -register( - "application/rdf+xml", - ResultParser, - "rdflib.plugins.sparql.results.graph", - "GraphResultParser", -) -register( - "json", - ResultParser, - "rdflib.plugins.sparql.results.jsonresults", - "JSONResultParser", -) -register( - "application/sparql-results+json", - ResultParser, - "rdflib.plugins.sparql.results.jsonresults", - "JSONResultParser", -) -register( - "csv", - ResultParser, - "rdflib.plugins.sparql.results.csvresults", - "CSVResultParser", -) -register( - "text/csv", - ResultParser, - "rdflib.plugins.sparql.results.csvresults", - "CSVResultParser", -) -register( - "tsv", - ResultParser, - "rdflib.plugins.sparql.results.tsvresults", - "TSVResultParser", -) -register( - "text/tab-separated-values", - ResultParser, - "rdflib.plugins.sparql.results.tsvresults", - "TSVResultParser", -) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/__init__.py deleted file mode 100644 index 4622bb0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -Default plugins for rdflib. - -This is a namespace package and contains the default plugins for -rdflib. - -""" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/RDFVOC.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/RDFVOC.py deleted file mode 100644 index 33f9c87..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/RDFVOC.py +++ /dev/null @@ -1,19 +0,0 @@ -from rdflib.namespace import RDF # noqa: N999 -from rdflib.term import URIRef - - -class RDFVOC(RDF): - _underscore_num = True - _fail = True - - # http://www.w3.org/TR/rdf-syntax-grammar/#eventterm-attribute-URI - # A mapping from unqualified terms to their qualified version. - RDF: URIRef - Description: URIRef - ID: URIRef - about: URIRef - parseType: URIRef # noqa: N815 - resource: URIRef - li: URIRef - nodeID: URIRef # noqa: N815 - datatype: URIRef diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/__init__.py deleted file mode 100644 index 8062daa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" - -""" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/hext.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/hext.py deleted file mode 100644 index 99aa476..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/hext.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -This is a rdflib plugin for parsing Hextuple files, which are Newline-Delimited JSON -(ndjson) files, into Conjunctive. The store that backs the graph *must* be able to -handle contexts, i.e. multiple graphs. -""" - -from __future__ import annotations - -import json -import warnings -from io import TextIOWrapper -from typing import TYPE_CHECKING, Any, BinaryIO, List, Optional, TextIO, Union - -from rdflib.graph import ConjunctiveGraph, Dataset, Graph -from rdflib.parser import InputSource, Parser -from rdflib.term import BNode, Literal, URIRef - -try: - import orjson - - _HAS_ORJSON = True -except ImportError: - orjson = None # type: ignore[assignment, unused-ignore] - _HAS_ORJSON = False - -if TYPE_CHECKING: - from io import BufferedReader - -__all__ = ["HextuplesParser"] - - -class HextuplesParser(Parser): - """ - An RDFLib parser for Hextuples - """ - - def __init__(self): - super(HextuplesParser, self).__init__() - self.default_context: Optional[Graph] = None - self.skolemize = False - - def _parse_hextuple( - self, ds: Union[Dataset, ConjunctiveGraph], tup: List[Union[str, None]] - ) -> None: - # all values check - # subject, predicate, value, datatype cannot be None - # language and graph may be None - if tup[0] is None or tup[1] is None or tup[2] is None or tup[3] is None: - raise ValueError( - f"subject, predicate, value, datatype cannot be None. Given: {tup}" - ) - - # 1 - subject - s: Union[URIRef, BNode] - if tup[0].startswith("_"): - s = BNode(value=tup[0].replace("_:", "")) - if self.skolemize: - s = s.skolemize() - else: - s = URIRef(tup[0]) - - # 2 - predicate - p = URIRef(tup[1]) - - # 3 - value - o: Union[URIRef, BNode, Literal] - if tup[3] == "globalId": - o = URIRef(tup[2]) - elif tup[3] == "localId": - o = BNode(value=tup[2].replace("_:", "")) - if self.skolemize: - o = o.skolemize() - else: # literal - if tup[4] is None: - o = Literal(tup[2], datatype=URIRef(tup[3])) - else: - o = Literal(tup[2], lang=tup[4]) - - # 6 - context - if tup[5] is not None: - c = ( - BNode(tup[5].replace("_:", "")) - if tup[5].startswith("_:") - else URIRef(tup[5]) - ) - if isinstance(c, BNode) and self.skolemize: - c = c.skolemize() - - ds.get_context(c).add((s, p, o)) - elif self.default_context is not None: - self.default_context.add((s, p, o)) - else: - raise Exception("No context to parse into!") - - # type error: Signature of "parse" incompatible with supertype "Parser" - def parse(self, source: InputSource, graph: Graph, skolemize: bool = False, **kwargs: Any) -> None: # type: ignore[override] - if kwargs.get("encoding") not in [None, "utf-8"]: - warnings.warn( - f"Hextuples files are always utf-8 encoded, " - f"I was passed: {kwargs.get('encoding')}, " - "but I'm still going to use utf-8" - ) - - assert ( - graph.store.context_aware - ), "Hextuples Parser needs a context-aware store!" - - self.skolemize = skolemize - # Set default_union to True to mimic ConjunctiveGraph behavior - ds = Dataset(store=graph.store, default_union=True) - ds_default = ds.default_context # the DEFAULT_DATASET_GRAPH_ID - if isinstance(graph, (Dataset, ConjunctiveGraph)): - self.default_context = graph.default_context - elif graph.identifier is not None: - if graph.identifier == ds_default.identifier: - self.default_context = graph - else: - self.default_context = ds.get_context(graph.identifier) - else: - # mypy thinks this is unreachable, but graph.identifier can be None - self.default_context = ds_default # type: ignore[unreachable] - if self.default_context is not ds_default: - ds.default_context = self.default_context - ds.remove_graph(ds_default) # remove the original unused default graph - - try: - text_stream: Optional[TextIO] = source.getCharacterStream() - except (AttributeError, LookupError): - text_stream = None - try: - binary_stream: Optional[BinaryIO] = source.getByteStream() - except (AttributeError, LookupError): - binary_stream = None - - if text_stream is None and binary_stream is None: - raise ValueError( - f"Source does not have a character stream or a byte stream and cannot be used {type(source)}" - ) - if TYPE_CHECKING: - assert text_stream is not None or binary_stream is not None - use_stream: Union[TextIO, BinaryIO] - if _HAS_ORJSON: - if binary_stream is not None: - use_stream = binary_stream - else: - if TYPE_CHECKING: - assert isinstance(text_stream, TextIOWrapper) - use_stream = text_stream - loads = orjson.loads - else: - if text_stream is not None: - use_stream = text_stream - else: - if TYPE_CHECKING: - assert isinstance(binary_stream, BufferedReader) - use_stream = TextIOWrapper(binary_stream, encoding="utf-8") - loads = json.loads - - for line in use_stream: # type: Union[str, bytes] - if len(line) == 0 or line.isspace(): - # Skipping empty lines because this is what was being done before for the first and last lines, albeit in an rather indirect way. - # The result is that we accept input that would otherwise be invalid. - # Possibly we should just let this result in an error. - continue - # this complex handing is because the 'value' component is - # allowed to be "" but not None - # all other "" values are treated as None - raw_line: List[str] = loads(line) - hex_tuple_line = [x if x != "" else None for x in raw_line] - if raw_line[2] == "": - hex_tuple_line[2] = "" - self._parse_hextuple(ds, hex_tuple_line) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/jsonld.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/jsonld.py deleted file mode 100644 index e103e70..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/jsonld.py +++ /dev/null @@ -1,712 +0,0 @@ -""" -This parser will interpret a JSON-LD document as an RDF Graph. See: - - http://json-ld.org/ - -Example usage:: - - >>> from rdflib import Graph, URIRef, Literal - >>> test_json = ''' - ... { - ... "@context": { - ... "dc": "http://purl.org/dc/terms/", - ... "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - ... "rdfs": "http://www.w3.org/2000/01/rdf-schema#" - ... }, - ... "@id": "http://example.org/about", - ... "dc:title": { - ... "@language": "en", - ... "@value": "Someone's Homepage" - ... } - ... } - ... ''' - >>> g = Graph().parse(data=test_json, format='json-ld') - >>> list(g) == [(URIRef('http://example.org/about'), - ... URIRef('http://purl.org/dc/terms/title'), - ... Literal("Someone's Homepage", lang='en'))] - True - -""" - -# From: https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/parser.py - -# NOTE: This code reads the entire JSON object into memory before parsing, but -# we should consider streaming the input to deal with arbitrarily large graphs. -from __future__ import annotations - -import secrets -import warnings -from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Union - -import rdflib.parser -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.namespace import RDF, XSD -from rdflib.parser import InputSource, URLInputSource -from rdflib.term import BNode, IdentifiedNode, Literal, Node, URIRef - -from ..shared.jsonld.context import UNDEF, Context, Term -from ..shared.jsonld.keys import ( - CONTEXT, - GRAPH, - ID, - INCLUDED, - INDEX, - JSON, - LANG, - LIST, - NEST, - NONE, - REV, - SET, - TYPE, - VALUE, - VOCAB, -) -from ..shared.jsonld.util import ( - _HAS_ORJSON, - VOCAB_DELIMS, - context_from_urlinputsource, - json, - orjson, - source_to_json, -) - -__all__ = ["JsonLDParser", "to_rdf"] - -TYPE_TERM = Term(str(RDF.type), TYPE, VOCAB) # type: ignore[call-arg] - -ALLOW_LISTS_OF_LISTS = True # NOTE: Not allowed in JSON-LD 1.0 - - -class JsonLDParser(rdflib.parser.Parser): - def __init__(self): - super(JsonLDParser, self).__init__() - - def parse( - self, - source: InputSource, - sink: Graph, - version: float = 1.1, - skolemize: bool = False, - encoding: Optional[str] = "utf-8", - base: Optional[str] = None, - context: Optional[ - Union[ - List[Union[Dict[str, Any], str, None]], - Dict[str, Any], - str, - ] - ] = None, - generalized_rdf: Optional[bool] = False, - extract_all_scripts: Optional[bool] = False, - **kwargs: Any, - ) -> None: - """Parse JSON-LD from a source document. - - The source document can be JSON or HTML with embedded JSON script - elements (type attribute = "application/ld+json"). To process as HTML - ``source.content_type`` must be set to "text/html" or - "application/xhtml+xml". - - :param source: InputSource with JSON-formatted data (JSON or HTML) - - :param sink: Graph to receive the parsed triples - - :param version: parse as JSON-LD version, defaults to 1.1 - - :param encoding: character encoding of the JSON (should be "utf-8" - or "utf-16"), defaults to "utf-8" - - :param base: JSON-LD `Base IRI `_, defaults to None - - :param context: JSON-LD `Context `_, defaults to None - - :param generalized_rdf: parse as `Generalized RDF `_, defaults to False - - :param extract_all_scripts: if source is an HTML document then extract - all script elements, defaults to False (extract only the first - script element). This is ignored if ``source.system_id`` contains - a fragment identifier, in which case only the script element with - matching id attribute is extracted. - - """ - if encoding not in ("utf-8", "utf-16"): - warnings.warn( - "JSON should be encoded as unicode. " - "Given encoding was: %s" % encoding - ) - - if not base: - base = sink.absolutize(source.getPublicId() or source.getSystemId() or "") - - context_data = context - if not context_data and hasattr(source, "url") and hasattr(source, "links"): - if TYPE_CHECKING: - assert isinstance(source, URLInputSource) - context_data = context_from_urlinputsource(source) - - try: - version = float(version) - except ValueError: - version = 1.1 - - # Get the optional fragment identifier - try: - fragment_id = URIRef(source.getSystemId()).fragment - except Exception: - fragment_id = None - - data, html_base = source_to_json(source, fragment_id, extract_all_scripts) - if html_base is not None: - base = URIRef(html_base, base=base) - - # NOTE: A ConjunctiveGraph parses into a Graph sink, so no sink will be - # context_aware. Keeping this check in case RDFLib is changed, or - # someone passes something context_aware to this parser directly. - conj_sink: Graph - if not sink.context_aware: - conj_sink = ConjunctiveGraph(store=sink.store, identifier=sink.identifier) - else: - conj_sink = sink - - to_rdf( - data, - conj_sink, - base, - context_data, - version, - bool(generalized_rdf), - skolemize=skolemize, - ) - - -def to_rdf( - data: Any, - dataset: Graph, - base: Optional[str] = None, - context_data: Optional[ - Union[ - List[Union[Dict[str, Any], str, None]], - Dict[str, Any], - str, - ] - ] = None, - version: Optional[float] = None, - generalized_rdf: bool = False, - allow_lists_of_lists: Optional[bool] = None, - skolemize: bool = False, -): - # TODO: docstring w. args and return value - context = Context(base=base, version=version) - if context_data: - context.load(context_data) - parser = Parser( - generalized_rdf=generalized_rdf, - allow_lists_of_lists=allow_lists_of_lists, - skolemize=skolemize, - ) - return parser.parse(data, context, dataset) - - -class Parser: - def __init__( - self, - generalized_rdf: bool = False, - allow_lists_of_lists: Optional[bool] = None, - skolemize: bool = False, - ): - self.skolemize = skolemize - self.generalized_rdf = generalized_rdf - self.allow_lists_of_lists = ( - allow_lists_of_lists - if allow_lists_of_lists is not None - else ALLOW_LISTS_OF_LISTS - ) - self.invalid_uri_to_bnode: dict[str, BNode] = {} - - def parse(self, data: Any, context: Context, dataset: Graph) -> Graph: - topcontext = False - resources: Union[Dict[str, Any], List[Any]] - if isinstance(data, list): - resources = data - elif isinstance(data, dict): - local_context = data.get(CONTEXT) - if local_context: - context.load(local_context, context.base) - topcontext = True - resources = data - # type error: Subclass of "Dict[str, Any]" and "List[Any]" cannot exist: would have incompatible method signatures - if not isinstance(resources, list): # type: ignore[unreachable] - resources = [resources] - - if context.vocab: - dataset.bind(None, context.vocab) - for name, term in context.terms.items(): - if term.id and term.id.endswith(VOCAB_DELIMS): - dataset.bind(name, term.id) - - # type error: "Graph" has no attribute "default_context" - graph = dataset.default_context if dataset.context_aware else dataset # type: ignore[attr-defined] - - for node in resources: - self._add_to_graph(dataset, graph, context, node, topcontext) - - return graph - - def _add_to_graph( - self, - dataset: Graph, - graph: Graph, - context: Context, - node: Any, - topcontext: bool = False, - ) -> Optional[Node]: - if not isinstance(node, dict) or context.get_value(node): - # type error: Return value expected - return # type: ignore[return-value] - - if CONTEXT in node and not topcontext: - local_context = node[CONTEXT] - if local_context: - context = context.subcontext(local_context) - else: - context = Context(base=context.doc_base) - - # type error: Incompatible types in assignment (expression has type "Optional[Context]", variable has type "Context") - context = context.get_context_for_type(node) # type: ignore[assignment] - - id_val = context.get_id(node) - - if id_val is None: - nested_id = self._get_nested_id(context, node) - if nested_id is not None and len(nested_id) > 0: - id_val = nested_id - - if isinstance(id_val, str): - subj = self._to_rdf_id(context, id_val) - else: - subj = BNode() - if self.skolemize: - subj = subj.skolemize() - - if subj is None: - return None - - # NOTE: crude way to signify that this node might represent a named graph - no_id = id_val is None - - for key, obj in node.items(): - if key == CONTEXT or key in context.get_keys(ID): - continue - - if key == REV or key in context.get_keys(REV): - for rkey, robj in obj.items(): - self._key_to_graph( - dataset, - graph, - context, - subj, - rkey, - robj, - reverse=True, - no_id=no_id, - ) - else: - self._key_to_graph(dataset, graph, context, subj, key, obj, no_id=no_id) - - return subj - - # type error: Missing return statement - def _get_nested_id(self, context: Context, node: Dict[str, Any]) -> Optional[str]: # type: ignore[return] - for key, obj in node.items(): - if context.version >= 1.1 and key in context.get_keys(NEST): - term = context.terms.get(key) - if term and term.id is None: - continue - objs = obj if isinstance(obj, list) else [obj] - for obj in objs: - if not isinstance(obj, dict): - continue - id_val = context.get_id(obj) - if not id_val: - subcontext = context.get_context_for_term( - context.terms.get(key) - ) - id_val = self._get_nested_id(subcontext, obj) - if isinstance(id_val, str): - return id_val - - def _key_to_graph( - self, - dataset: Graph, - graph: Graph, - context: Context, - subj: Node, - key: str, - obj: Any, - reverse: bool = False, - no_id: bool = False, - ) -> None: - if isinstance(obj, list): - obj_nodes = obj - else: - obj_nodes = [obj] - - term = context.terms.get(key) - if term: - term_id = term.id - if term.type == JSON: - obj_nodes = [self._to_typed_json_value(obj)] - elif LIST in term.container: - obj_nodes = [self._expand_nested_list(obj_nodes)] - elif isinstance(obj, dict): - obj_nodes = self._parse_container(context, term, obj) - else: - term_id = None - - if TYPE in (key, term_id): - term = TYPE_TERM - - if GRAPH in (key, term_id): - if dataset.context_aware and not no_id: - if TYPE_CHECKING: - assert isinstance(dataset, ConjunctiveGraph) - # type error: Argument 1 to "get_context" of "ConjunctiveGraph" has incompatible type "Node"; expected "Union[IdentifiedNode, str, None]" - subgraph = dataset.get_context(subj) # type: ignore[arg-type] - else: - subgraph = graph - for onode in obj_nodes: - self._add_to_graph(dataset, subgraph, context, onode) - return - - if SET in (key, term_id): - for onode in obj_nodes: - self._add_to_graph(dataset, graph, context, onode) - return - - if INCLUDED in (key, term_id): - for onode in obj_nodes: - self._add_to_graph(dataset, graph, context, onode) - return - - if context.version >= 1.1 and key in context.get_keys(NEST): - term = context.terms.get(key) - if term and term.id is None: - return - objs = obj if isinstance(obj, list) else [obj] - for obj in objs: - if not isinstance(obj, dict): - continue - for nkey, nobj in obj.items(): - # NOTE: we've already captured subject - if nkey in context.get_keys(ID): - continue - subcontext = context.get_context_for_type(obj) - # type error: Argument 3 to "_key_to_graph" of "Parser" has incompatible type "Optional[Context]"; expected "Context" - self._key_to_graph(dataset, graph, subcontext, subj, nkey, nobj) # type: ignore[arg-type] - return - - pred_uri = term.id if term else context.expand(key) - - context = context.get_context_for_term(term) - - # Flatten deep nested lists - def flatten(n: Iterable[Any]) -> List[Any]: - flattened = [] - for obj in n: - if isinstance(obj, dict): - objs = context.get_set(obj) - if objs is not None: - obj = objs - if isinstance(obj, list): - flattened += flatten(obj) - continue - flattened.append(obj) - return flattened - - obj_nodes = flatten(obj_nodes) - - if not pred_uri: - return - - if term and term.reverse: - reverse = not reverse - - pred: IdentifiedNode - bid = self._get_bnodeid(pred_uri) - if bid: - if not self.generalized_rdf: - return - pred = BNode(bid) - if self.skolemize: - pred = pred.skolemize() - else: - pred = URIRef(pred_uri) - - for obj_node in obj_nodes: - obj = self._to_object(dataset, graph, context, term, obj_node) - if obj is None: - continue - if reverse: - graph.add((obj, pred, subj)) - else: - graph.add((subj, pred, obj)) - - def _parse_container( - self, context: Context, term: Term, obj: Dict[str, Any] - ) -> List[Any]: - if LANG in term.container: - obj_nodes = [] - for lang, values in obj.items(): - if not isinstance(values, list): - values = [values] - if lang in context.get_keys(NONE): - obj_nodes += values - else: - for v in values: - obj_nodes.append((v, lang)) - return obj_nodes - - v11 = context.version >= 1.1 - - if v11 and GRAPH in term.container and ID in term.container: - return [ - ( - dict({GRAPH: o}) - if k in context.get_keys(NONE) - else dict({ID: k, GRAPH: o}) if isinstance(o, dict) else o - ) - for k, o in obj.items() - ] - - elif v11 and GRAPH in term.container and INDEX in term.container: - return [dict({GRAPH: o}) for k, o in obj.items()] - - elif v11 and GRAPH in term.container: - return [dict({GRAPH: obj})] - - elif v11 and ID in term.container: - return [ - ( - dict({ID: k}, **o) - if isinstance(o, dict) and k not in context.get_keys(NONE) - else o - ) - for k, o in obj.items() - ] - - elif v11 and TYPE in term.container: - return [ - ( - self._add_type( - context, - ( - {ID: context.expand(o) if term.type == VOCAB else o} - if isinstance(o, str) - else o - ), - k, - ) - if isinstance(o, (dict, str)) and k not in context.get_keys(NONE) - else o - ) - for k, o in obj.items() - ] - - elif INDEX in term.container: - obj_nodes = [] - for key, nodes in obj.items(): - if not isinstance(nodes, list): - nodes = [nodes] - for node in nodes: - if v11 and term.index and key not in context.get_keys(NONE): - if not isinstance(node, dict): - node = {ID: node} - values = node.get(term.index, []) - if not isinstance(values, list): - values = [values] - values.append(key) - node[term.index] = values - obj_nodes.append(node) - return obj_nodes - - return [obj] - - @staticmethod - def _add_type(context: Context, o: Dict[str, Any], k: str) -> Dict[str, Any]: - otype = context.get_type(o) or [] - if otype and not isinstance(otype, list): - otype = [otype] - otype.append(k) - o[TYPE] = otype - return o - - def _to_object( - self, - dataset: Graph, - graph: Graph, - context: Context, - term: Optional[Term], - node: Any, - inlist: bool = False, - ) -> Optional[Node]: - if isinstance(node, tuple): - value, lang = node - if value is None: - # type error: Return value expected - return # type: ignore[return-value] - if lang and " " in lang: - # type error: Return value expected - return # type: ignore[return-value] - return Literal(value, lang=lang) - - if isinstance(node, dict): - node_list = context.get_list(node) - if node_list is not None: - if inlist and not self.allow_lists_of_lists: - # type error: Return value expected - return # type: ignore[return-value] - listref = self._add_list(dataset, graph, context, term, node_list) - if listref: - return listref - - else: # expand compacted value - if term and term.type: - if term.type == JSON: - node = self._to_typed_json_value(node) - elif node is None: - # type error: Return value expected - return # type: ignore[return-value] - elif term.type == ID and isinstance(node, str): - node = {ID: context.resolve(node)} - elif term.type == VOCAB and isinstance(node, str): - node = {ID: context.expand(node) or context.resolve_iri(node)} - else: - node = {TYPE: term.type, VALUE: node} - else: - if node is None: - # type error: Return value expected - return # type: ignore[return-value] - if isinstance(node, float): - return Literal(node, datatype=XSD.double) - - if term and term.language is not UNDEF: - lang = term.language - else: - lang = context.language - return Literal(node, lang=lang) - - lang = context.get_language(node) - datatype = not lang and context.get_type(node) or None - value = context.get_value(node) - # type error: Unsupported operand types for in ("Optional[Any]" and "Generator[str, None, None]") - if datatype in context.get_keys(JSON): # type: ignore[operator] - node = self._to_typed_json_value(value) - datatype = context.get_type(node) - value = context.get_value(node) - - if lang or context.get_key(VALUE) in node or VALUE in node: - if value is None: - return None - if lang: - if " " in lang: - # type error: Return value expected - return # type: ignore[return-value] - return Literal(value, lang=lang) - elif datatype: - return Literal(value, datatype=context.expand(datatype)) - else: - return Literal(value) - else: - return self._add_to_graph(dataset, graph, context, node) - - def _to_rdf_id(self, context: Context, id_val: str) -> Optional[IdentifiedNode]: - bid = self._get_bnodeid(id_val) - if bid: - b = BNode(bid) - if self.skolemize: - return b.skolemize() - return b - else: - uri = context.resolve(id_val) - if not self.generalized_rdf and ":" not in uri: - return None - node: IdentifiedNode = URIRef(uri) - if not str(node): - if id_val not in self.invalid_uri_to_bnode: - self.invalid_uri_to_bnode[id_val] = BNode(secrets.token_urlsafe(20)) - node = self.invalid_uri_to_bnode[id_val] - return node - - def _get_bnodeid(self, ref: str) -> Optional[str]: - if not ref.startswith("_:"): - # type error: Return value expected - return # type: ignore[return-value] - bid = ref.split("_:", 1)[-1] - return bid or None - - def _add_list( - self, - dataset: Graph, - graph: Graph, - context: Context, - term: Optional[Term], - node_list: Any, - ) -> IdentifiedNode: - if not isinstance(node_list, list): - node_list = [node_list] - - first_subj: Union[URIRef, BNode] = BNode() - if self.skolemize and isinstance(first_subj, BNode): - first_subj = first_subj.skolemize() - - rest: Union[URIRef, BNode, None] - subj, rest = first_subj, None - - for node in node_list: - if node is None: - continue - - if rest: - # type error: Statement is unreachable - graph.add((subj, RDF.rest, rest)) # type: ignore[unreachable] - subj = rest - - obj = self._to_object(dataset, graph, context, term, node, inlist=True) - - if obj is None: - continue - - graph.add((subj, RDF.first, obj)) - rest = BNode() - if self.skolemize and isinstance(rest, BNode): - rest = rest.skolemize() - - if rest: - graph.add((subj, RDF.rest, RDF.nil)) - return first_subj - else: - return RDF.nil - - @staticmethod - def _to_typed_json_value(value: Any) -> Dict[str, str]: - if _HAS_ORJSON: - val_string: str = orjson.dumps( - value, - option=orjson.OPT_SORT_KEYS | orjson.OPT_NON_STR_KEYS, - ).decode("utf-8") - else: - val_string = json.dumps( - value, separators=(",", ":"), sort_keys=True, ensure_ascii=False - ) - return { - TYPE: RDF.JSON, - VALUE: val_string, - } - - @classmethod - def _expand_nested_list(cls, obj_nodes: List[Any]) -> Dict[str, List[Any]]: - result = [ - cls._expand_nested_list(o) if isinstance(o, list) else o for o in obj_nodes - ] - return {LIST: result} diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/notation3.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/notation3.py deleted file mode 100644 index 4df892e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/notation3.py +++ /dev/null @@ -1,2056 +0,0 @@ -""" -notation3.py - Standalone Notation3 Parser -Derived from CWM, the Closed World Machine - -Authors of the original suite: - -* Dan Connolly <@@> -* Tim Berners-Lee <@@> -* Yosi Scharf <@@> -* Joseph M. Reagle Jr. -* Rich Salz - -http://www.w3.org/2000/10/swap/notation3.py - -Copyright 2000-2007, World Wide Web Consortium. -Copyright 2001, MIT. -Copyright 2001, Zolera Systems Inc. - -License: W3C Software License -http://www.w3.org/Consortium/Legal/copyright-software - -Modified by Sean B. Palmer -Copyright 2007, Sean B. Palmer. - -Modified to work with rdflib by Gunnar Aastrand Grimnes -Copyright 2010, Gunnar A. Grimnes - -""" - -from __future__ import annotations - -import codecs -import os -import re -import sys - -# importing typing for `typing.List` because `List`` is used for something else -import typing -from decimal import Decimal -from typing import ( - IO, - TYPE_CHECKING, - Any, - Callable, - Dict, - Match, - MutableSequence, - NoReturn, - Optional, - Pattern, - Set, - Tuple, - TypeVar, - Union, -) -from uuid import uuid4 - -from rdflib.compat import long_type -from rdflib.exceptions import ParserError -from rdflib.graph import Dataset, Graph, QuotedGraph -from rdflib.term import ( - _XSD_PFX, - BNode, - IdentifiedNode, - Identifier, - Literal, - Node, - URIRef, - Variable, - _unique_id, -) - -__all__ = [ - "BadSyntax", - "N3Parser", - "TurtleParser", - "splitFragP", - "join", - "base", - "runNamespace", - "uniqueURI", - "hexify", - "Formula", - "RDFSink", - "SinkParser", -] - -from rdflib.parser import Parser - -if TYPE_CHECKING: - from rdflib.parser import InputSource - -_AnyT = TypeVar("_AnyT") - - -def splitFragP(uriref: str, punc: int = 0) -> Tuple[str, str]: - """split a URI reference before the fragment - - Punctuation is kept. - - e.g. - - >>> splitFragP("abc#def") - ('abc', '#def') - - >>> splitFragP("abcdef") - ('abcdef', '') - - """ - - i = uriref.rfind("#") - if i >= 0: - return uriref[:i], uriref[i:] - else: - return uriref, "" - - -_StrT = TypeVar("_StrT", bound=str) - - -def join(here: str, there: str) -> str: - """join an absolute URI and URI reference - (non-ascii characters are supported/doctested; - haven't checked the details of the IRI spec though) - - ``here`` is assumed to be absolute. - ``there`` is URI reference. - - >>> join('http://example/x/y/z', '../abc') - 'http://example/x/abc' - - Raise ValueError if there uses relative path - syntax but here has no hierarchical path. - - >>> join('mid:foo@example', '../foo') # doctest: +NORMALIZE_WHITESPACE - Traceback (most recent call last): - raise ValueError(here) - ValueError: Base has no slash - after colon - with relative '../foo'. - - >>> join('http://example/x/y/z', '') - 'http://example/x/y/z' - - >>> join('mid:foo@example', '#foo') - 'mid:foo@example#foo' - - We grok IRIs - - >>> len('Andr\\xe9') - 5 - - >>> join('http://example.org/', '#Andr\\xe9') - 'http://example.org/#Andr\\xe9' - """ - - # assert(here.find("#") < 0), \ - # "Base may not contain hash: '%s'" % here # why must caller splitFrag? - - slashl = there.find("/") - colonl = there.find(":") - - # join(base, 'foo:/') -- absolute - if colonl >= 0 and (slashl < 0 or colonl < slashl): - return there - - bcolonl = here.find(":") - assert bcolonl >= 0, ( - "Base uri '%s' is not absolute" % here - ) # else it's not absolute - - path, frag = splitFragP(there) - if not path: - return here + frag - - # join('mid:foo@example', '../foo') bzzt - if here[bcolonl + 1 : bcolonl + 2] != "/": - raise ValueError( - "Base <%s> has no slash after " - "colon - with relative '%s'." % (here, there) - ) - - if here[bcolonl + 1 : bcolonl + 3] == "//": - bpath = here.find("/", bcolonl + 3) - else: - bpath = bcolonl + 1 - - # join('http://xyz', 'foo') - if bpath < 0: - bpath = len(here) - here = here + "/" - - # join('http://xyz/', '//abc') => 'http://abc' - if there[:2] == "//": - return here[: bcolonl + 1] + there - - # join('http://xyz/', '/abc') => 'http://xyz/abc' - if there[:1] == "/": - return here[:bpath] + there - - slashr = here.rfind("/") - - while 1: - if path[:2] == "./": - path = path[2:] - if path == ".": - path = "" - elif path[:3] == "../" or path == "..": - path = path[3:] - i = here.rfind("/", bpath, slashr) - if i >= 0: - here = here[: i + 1] - slashr = i - else: - break - - return here[: slashr + 1] + path + frag - - -def base() -> str: - """The base URI for this process - the Web equiv of cwd - - Relative or absolute unix-standard filenames parsed relative to - this yield the URI of the file. - If we had a reliable way of getting a computer name, - we should put it in the hostname just to prevent ambiguity - - """ - # return "file://" + hostname + os.getcwd() + "/" - return "file://" + _fixslash(os.getcwd()) + "/" - - -def _fixslash(s: str) -> str: - """Fix windowslike filename to unixlike - (#ifdef WINDOWS)""" - s = s.replace("\\", "/") - if s[0] != "/" and s[1] == ":": - s = s[2:] # @@@ Hack when drive letter present - return s - - -CONTEXT = 0 -PRED = 1 -SUBJ = 2 -OBJ = 3 - -PARTS = PRED, SUBJ, OBJ -ALL4 = CONTEXT, PRED, SUBJ, OBJ - -SYMBOL = 0 -FORMULA = 1 -LITERAL = 2 -LITERAL_DT = 21 -LITERAL_LANG = 22 -ANONYMOUS = 3 -XMLLITERAL = 25 - -Logic_NS = "http://www.w3.org/2000/10/swap/log#" -NODE_MERGE_URI = Logic_NS + "is" # Pseudo-property indicating node merging -forSomeSym = Logic_NS + "forSome" -forAllSym = Logic_NS + "forAll" - -RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" -RDF_NS_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -OWL_NS = "http://www.w3.org/2002/07/owl#" -DAML_sameAs_URI = OWL_NS + "sameAs" -parsesTo_URI = Logic_NS + "parsesTo" -RDF_spec = "http://www.w3.org/TR/REC-rdf-syntax/" - -List_NS = RDF_NS_URI # From 20030808 -_Old_Logic_NS = "http://www.w3.org/2000/10/swap/log.n3#" - -N3_first = (SYMBOL, List_NS + "first") -N3_rest = (SYMBOL, List_NS + "rest") -N3_li = (SYMBOL, List_NS + "li") -N3_nil = (SYMBOL, List_NS + "nil") -N3_List = (SYMBOL, List_NS + "List") -N3_Empty = (SYMBOL, List_NS + "Empty") - - -runNamespaceValue: Optional[str] = None - - -def runNamespace() -> str: - """Returns a URI suitable as a namespace for run-local objects""" - # @@@ include hostname (privacy?) (hash it?) - global runNamespaceValue - if runNamespaceValue is None: - runNamespaceValue = join(base(), _unique_id()) + "#" - return runNamespaceValue - - -nextu = 0 - - -def uniqueURI() -> str: - """A unique URI""" - global nextu - nextu += 1 - return runNamespace() + "u_" + str(nextu) - - -tracking = False -chatty_flag = 50 - -# from why import BecauseOfData, becauseSubexpression - - -def BecauseOfData(*args: Any, **kargs: Any) -> None: - # print args, kargs - pass - - -def becauseSubexpression(*args: Any, **kargs: Any) -> None: - # print args, kargs - pass - - -N3_forSome_URI = forSomeSym -N3_forAll_URI = forAllSym - -# Magic resources we know about - -ADDED_HASH = "#" # Stop where we use this in case we want to remove it! -# This is the hash on namespace URIs - -RDF_type = (SYMBOL, RDF_type_URI) -DAML_sameAs = (SYMBOL, DAML_sameAs_URI) - -LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies" - -BOOLEAN_DATATYPE = _XSD_PFX + "boolean" -DECIMAL_DATATYPE = _XSD_PFX + "decimal" -DOUBLE_DATATYPE = _XSD_PFX + "double" -FLOAT_DATATYPE = _XSD_PFX + "float" -INTEGER_DATATYPE = _XSD_PFX + "integer" - -option_noregen = 0 # If set, do not regenerate genids on output - -# @@ I18n - the notname chars need extending for well known unicode non-text -# characters. The XML spec switched to assuming unknown things were name -# characters. -# _namechars = string.lowercase + string.uppercase + string.digits + '_-' -_notQNameChars = set("\t\r\n !\"#$&'()*,+/;<=>?@[\\]^`{|}~") # else valid qname :-/ -_notKeywordsChars = _notQNameChars | {"."} -_notNameChars = _notQNameChars | {":"} # Assume anything else valid name :-/ -_rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" - -hexChars = set("ABCDEFabcdef0123456789") -escapeChars = set("(_~.-!$&'()*+,;=/?#@%)") # valid for \ escapes in localnames -numberChars = set("0123456789-") -numberCharsPlus = numberChars | {"+", "."} - - -def unicodeExpand(m: Match) -> str: - try: - return chr(int(m.group(1), 16)) - except Exception: - raise Exception("Invalid unicode code point: " + m.group(1)) - - -unicodeEscape4 = re.compile(r"\\u([0-9a-fA-F]{4})") -unicodeEscape8 = re.compile(r"\\U([0-9a-fA-F]{8})") - - -N3CommentCharacter = "#" # For unix script # ! compatibility - -# Parse string to sink -# -# Regular expressions: -eol = re.compile(r"[ \t]*(#[^\n]*)?\r?\n") # end of line, poss. w/comment -eof = re.compile(r"[ \t]*(#[^\n]*)?$") # end of file, poss. w/comment -ws = re.compile(r"[ \t]*") # Whitespace not including NL -signed_integer = re.compile(r"[-+]?[0-9]+") # integer -integer_syntax = re.compile(r"[-+]?[0-9]+") -decimal_syntax = re.compile(r"[-+]?[0-9]*\.[0-9]+") -exponent_syntax = re.compile( - r"[-+]?(?:[0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)(?:e|E)[-+]?[0-9]+" -) -digitstring = re.compile(r"[0-9]+") # Unsigned integer -interesting = re.compile(r"""[\\\r\n\"\']""") -langcode = re.compile(r"[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*") - - -class SinkParser: - def __init__( - self, - store: RDFSink, - openFormula: Optional[Formula] = None, - thisDoc: str = "", - baseURI: Optional[str] = None, - genPrefix: str = "", - why: Optional[Callable[[], None]] = None, - turtle: bool = False, - ): - """note: namespace names should *not* end in # ; - the # will get added during qname processing""" - - self._bindings = {} - if thisDoc != "": - assert ":" in thisDoc, "Document URI not absolute: <%s>" % thisDoc - self._bindings[""] = thisDoc + "#" # default - - self._store = store - if genPrefix: - # TODO FIXME: there is no function named setGenPrefix - store.setGenPrefix(genPrefix) # type: ignore[attr-defined] # pass it on - - self._thisDoc = thisDoc - self.lines = 0 # for error handling - self.startOfLine = 0 # For calculating character number - self._genPrefix = genPrefix - self.keywords = ["a", "this", "bind", "has", "is", "of", "true", "false"] - self.keywordsSet = 0 # Then only can others be considered qnames - self._anonymousNodes: Dict[str, BNode] = {} - # Dict of anon nodes already declared ln: Term - self._variables: Dict[str, Variable] = {} - self._parentVariables: Dict[str, Variable] = {} - self._reason = why # Why the parser was asked to parse this - - self.turtle = turtle # raise exception when encountering N3 extensions - # Turtle allows single or double quotes around strings, whereas N3 - # only allows double quotes. - self.string_delimiters = ('"', "'") if turtle else ('"',) - - self._reason2: Optional[Callable[..., None]] = None # Why these triples - # was: diag.tracking - if tracking: - # type error: "BecauseOfData" does not return a value - self._reason2 = BecauseOfData( # type: ignore[func-returns-value] - store.newSymbol(thisDoc), because=self._reason - ) - - self._baseURI: Optional[str] - if baseURI: - self._baseURI = baseURI - else: - if thisDoc: - self._baseURI = thisDoc - else: - self._baseURI = None - - assert not self._baseURI or ":" in self._baseURI - - if not self._genPrefix: - if self._thisDoc: - self._genPrefix = self._thisDoc + "#_g" - else: - self._genPrefix = uniqueURI() - - self._formula: Optional[Formula] - if openFormula is None and not turtle: - if self._thisDoc: - # TODO FIXME: store.newFormula does not take any arguments - self._formula = store.newFormula(thisDoc + "#_formula") # type: ignore[call-arg] - else: - self._formula = store.newFormula() - else: - self._formula = openFormula - - self._context: Optional[Formula] = self._formula - self._parentContext: Optional[Formula] = None - - def here(self, i: int) -> str: - """String generated from position in file - - This is for repeatability when referring people to bnodes in a document. - This has diagnostic uses less formally, as it should point one to which - bnode the arbitrary identifier actually is. It gives the - line and character number of the '[' charcacter or path character - which introduced the blank node. The first blank node is boringly - _L1C1. It used to be used only for tracking, but for tests in general - it makes the canonical ordering of bnodes repeatable.""" - - return "%s_L%iC%i" % (self._genPrefix, self.lines, i - self.startOfLine + 1) - - def formula(self) -> Optional[Formula]: - return self._formula - - def loadStream(self, stream: Union[IO[str], IO[bytes]]) -> Optional[Formula]: - return self.loadBuf(stream.read()) # Not ideal - - def loadBuf(self, buf: Union[str, bytes]) -> Optional[Formula]: - """Parses a buffer and returns its top level formula""" - self.startDoc() - - self.feed(buf) - return self.endDoc() # self._formula - - def feed(self, octets: Union[str, bytes]) -> None: - """Feed an octet stream to the parser - - if BadSyntax is raised, the string - passed in the exception object is the - remainder after any statements have been parsed. - So if there is more data to feed to the - parser, it should be straightforward to recover.""" - - if not isinstance(octets, str): - s = octets.decode("utf-8") - # NB already decoded, so \ufeff - if len(s) > 0 and s[0] == codecs.BOM_UTF8.decode("utf-8"): - s = s[1:] - else: - s = octets - - i = 0 - while i >= 0: - j = self.skipSpace(s, i) - if j < 0: - return - - i = self.directiveOrStatement(s, j) - if i < 0: - # print("# next char: %s" % s[j]) - self.BadSyntax(s, j, "expected directive or statement") - - def directiveOrStatement(self, argstr: str, h: int) -> int: - i = self.skipSpace(argstr, h) - if i < 0: - return i # EOF - - if self.turtle: - j = self.sparqlDirective(argstr, i) - if j >= 0: - return j - - j = self.directive(argstr, i) - if j >= 0: - return self.checkDot(argstr, j) - - j = self.statement(argstr, i) - if j >= 0: - return self.checkDot(argstr, j) - - return j - - # @@I18N - # _namechars = string.lowercase + string.uppercase + string.digits + '_-' - - def tok(self, tok: str, argstr: str, i: int, colon: bool = False) -> int: - """Check for keyword. Space must have been stripped on entry and - we must not be at end of file. - - if colon, then keyword followed by colon is ok - (@prefix: is ok, rdf:type shortcut a must be followed by ws) - """ - - assert tok[0] not in _notNameChars # not for punctuation - if argstr[i] == "@": - i += 1 - else: - if tok not in self.keywords: - return -1 # No, this has neither keywords declaration nor "@" - - i_plus_len_tok = i + len(tok) - if ( - argstr[i:i_plus_len_tok] == tok - and (argstr[i_plus_len_tok] in _notKeywordsChars) - or (colon and argstr[i_plus_len_tok] == ":") - ): - return i_plus_len_tok - else: - return -1 - - def sparqlTok(self, tok: str, argstr: str, i: int) -> int: - """Check for SPARQL keyword. Space must have been stripped on entry - and we must not be at end of file. - Case insensitive and not preceded by @ - """ - - assert tok[0] not in _notNameChars # not for punctuation - - len_tok = len(tok) - if argstr[i : i + len_tok].lower() == tok.lower() and ( - argstr[i + len_tok] in _notQNameChars - ): - i += len_tok - return i - else: - return -1 - - def directive(self, argstr: str, i: int) -> int: - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - res: typing.List[str] = [] - - j = self.tok("bind", argstr, i) # implied "#". Obsolete. - if j > 0: - self.BadSyntax(argstr, i, "keyword bind is obsolete: use @prefix") - - j = self.tok("keywords", argstr, i) - if j > 0: - if self.turtle: - self.BadSyntax(argstr, i, "Found 'keywords' when in Turtle mode.") - - i = self.commaSeparatedList(argstr, j, res, self.bareWord) - if i < 0: - self.BadSyntax( - argstr, i, "'@keywords' needs comma separated list of words" - ) - self.setKeywords(res[:]) - return i - - j = self.tok("forAll", argstr, i) - if j > 0: - if self.turtle: - self.BadSyntax(argstr, i, "Found 'forAll' when in Turtle mode.") - - i = self.commaSeparatedList(argstr, j, res, self.uri_ref2) - if i < 0: - self.BadSyntax(argstr, i, "Bad variable list after @forAll") - for x in res: - # self._context.declareUniversal(x) - if x not in self._variables or x in self._parentVariables: - # type error: Item "None" of "Optional[Formula]" has no attribute "newUniversal" - self._variables[x] = self._context.newUniversal(x) # type: ignore[union-attr] - return i - - j = self.tok("forSome", argstr, i) - if j > 0: - if self.turtle: - self.BadSyntax(argstr, i, "Found 'forSome' when in Turtle mode.") - - i = self.commaSeparatedList(argstr, j, res, self.uri_ref2) - if i < 0: - self.BadSyntax(argstr, i, "Bad variable list after @forSome") - for x in res: - # type error: Item "None" of "Optional[Formula]" has no attribute "declareExistential" - self._context.declareExistential(x) # type: ignore[union-attr] - return i - - j = self.tok("prefix", argstr, i, colon=True) # no implied "#" - if j >= 0: - t: typing.List[Union[Identifier, Tuple[str, str]]] = [] - i = self.qname(argstr, j, t) - if i < 0: - self.BadSyntax(argstr, j, "expected qname after @prefix") - j = self.uri_ref2(argstr, i, t) - if j < 0: - self.BadSyntax(argstr, i, "expected after @prefix _qname_") - ns: str = self.uriOf(t[1]) - - if self._baseURI: - ns = join(self._baseURI, ns) - elif ":" not in ns: - self.BadSyntax( - argstr, - j, - f"With no base URI, cannot use relative URI in @prefix <{ns}>", - ) - assert ":" in ns # must be absolute - self._bindings[t[0][0]] = ns - self.bind(t[0][0], hexify(ns)) - return j - - j = self.tok("base", argstr, i) # Added 2007/7/7 - if j >= 0: - t = [] - i = self.uri_ref2(argstr, j, t) - if i < 0: - self.BadSyntax(argstr, j, "expected after @base ") - ns = self.uriOf(t[0]) - - if self._baseURI: - ns = join(self._baseURI, ns) - else: - self.BadSyntax( - argstr, - j, - "With no previous base URI, cannot use " - + "relative URI in @base <" - + ns - + ">", - ) - assert ":" in ns # must be absolute - self._baseURI = ns - return i - - return -1 # Not a directive, could be something else. - - def sparqlDirective(self, argstr: str, i: int) -> int: - """ - turtle and trig support BASE/PREFIX without @ and without - terminating . - """ - - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - - j = self.sparqlTok("PREFIX", argstr, i) - if j >= 0: - t: typing.List[Any] = [] - i = self.qname(argstr, j, t) - if i < 0: - self.BadSyntax(argstr, j, "expected qname after @prefix") - j = self.uri_ref2(argstr, i, t) - if j < 0: - self.BadSyntax(argstr, i, "expected after @prefix _qname_") - ns = self.uriOf(t[1]) - - if self._baseURI: - ns = join(self._baseURI, ns) - elif ":" not in ns: - self.BadSyntax( - argstr, - j, - "With no base URI, cannot use " - + "relative URI in @prefix <" - + ns - + ">", - ) - assert ":" in ns # must be absolute - self._bindings[t[0][0]] = ns - self.bind(t[0][0], hexify(ns)) - return j - - j = self.sparqlTok("BASE", argstr, i) - if j >= 0: - t = [] - i = self.uri_ref2(argstr, j, t) - if i < 0: - self.BadSyntax(argstr, j, "expected after @base ") - ns = self.uriOf(t[0]) - - if self._baseURI: - ns = join(self._baseURI, ns) - else: - self.BadSyntax( - argstr, - j, - "With no previous base URI, cannot use " - + "relative URI in @base <" - + ns - + ">", - ) - assert ":" in ns # must be absolute - self._baseURI = ns - return i - - return -1 # Not a directive, could be something else. - - def bind(self, qn: str, uri: bytes) -> None: - assert isinstance(uri, bytes), "Any unicode must be %x-encoded already" - if qn == "": - self._store.setDefaultNamespace(uri) - else: - self._store.bind(qn, uri) - - def setKeywords(self, k: Optional[typing.List[str]]) -> None: - """Takes a list of strings""" - if k is None: - self.keywordsSet = 0 - else: - self.keywords = k - self.keywordsSet = 1 - - def startDoc(self) -> None: - # was: self._store.startDoc() - self._store.startDoc(self._formula) - - def endDoc(self) -> Optional[Formula]: - """Signal end of document and stop parsing. returns formula""" - self._store.endDoc(self._formula) # don't canonicalize yet - return self._formula - - def makeStatement(self, quadruple) -> None: - # $$$$$$$$$$$$$$$$$$$$$ - # print "# Parser output: ", `quadruple` - self._store.makeStatement(quadruple, why=self._reason2) - - def statement(self, argstr: str, i: int) -> int: - r: typing.List[Any] = [] - i = self.object(argstr, i, r) # Allow literal for subject - extends RDF - if i < 0: - return i - - j = self.property_list(argstr, i, r[0]) - - if j < 0: - self.BadSyntax(argstr, i, "expected propertylist") - return j - - def subject(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - return self.item(argstr, i, res) - - def verb(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - """has _prop_ - is _prop_ of - a - = - _prop_ - >- prop -> - <- prop -< - _operator_""" - - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - - r: typing.List[Any] = [] - - j = self.tok("has", argstr, i) - if j >= 0: - if self.turtle: - self.BadSyntax(argstr, i, "Found 'has' keyword in Turtle mode") - - i = self.prop(argstr, j, r) - if i < 0: - self.BadSyntax(argstr, j, "expected property after 'has'") - res.append(("->", r[0])) - return i - - j = self.tok("is", argstr, i) - if j >= 0: - if self.turtle: - self.BadSyntax(argstr, i, "Found 'is' keyword in Turtle mode") - - i = self.prop(argstr, j, r) - if i < 0: - self.BadSyntax(argstr, j, "expected after 'is'") - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax( - argstr, i, "End of file found, expected property after 'is'" - ) - i = j - j = self.tok("of", argstr, i) - if j < 0: - self.BadSyntax(argstr, i, "expected 'of' after 'is' ") - res.append(("<-", r[0])) - return j - - j = self.tok("a", argstr, i) - if j >= 0: - res.append(("->", RDF_type)) - return j - - if argstr[i : i + 2] == "<=": - if self.turtle: - self.BadSyntax(argstr, i, "Found '<=' in Turtle mode. ") - - res.append(("<-", self._store.newSymbol(Logic_NS + "implies"))) - return i + 2 - - if argstr[i] == "=": - if self.turtle: - self.BadSyntax(argstr, i, "Found '=' in Turtle mode") - if argstr[i + 1] == ">": - res.append(("->", self._store.newSymbol(Logic_NS + "implies"))) - return i + 2 - res.append(("->", DAML_sameAs)) - return i + 1 - - if argstr[i : i + 2] == ":=": - if self.turtle: - self.BadSyntax(argstr, i, "Found ':=' in Turtle mode") - - # patch file relates two formulae, uses this @@ really? - res.append(("->", Logic_NS + "becomes")) - return i + 2 - - j = self.prop(argstr, i, r) - if j >= 0: - res.append(("->", r[0])) - return j - - if argstr[i : i + 2] == ">-" or argstr[i : i + 2] == "<-": - self.BadSyntax(argstr, j, ">- ... -> syntax is obsolete.") - - return -1 - - def prop(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - return self.item(argstr, i, res) - - def item(self, argstr: str, i, res: MutableSequence[Any]) -> int: - return self.path(argstr, i, res) - - def blankNode(self, uri: Optional[str] = None) -> BNode: - return self._store.newBlankNode(self._context, uri, why=self._reason2) - - def path(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - """Parse the path production.""" - j = self.nodeOrLiteral(argstr, i, res) - if j < 0: - return j # nope - - while argstr[j] in {"!", "^"}: # no spaces, must follow exactly (?) - ch = argstr[j] - subj = res.pop() - obj = self.blankNode(uri=self.here(j)) - j = self.node(argstr, j + 1, res) - if j < 0: - self.BadSyntax(argstr, j, "EOF found in middle of path syntax") - pred = res.pop() - if ch == "^": # Reverse traverse - self.makeStatement((self._context, pred, obj, subj)) - else: - self.makeStatement((self._context, pred, subj, obj)) - res.append(obj) - return j - - def anonymousNode(self, ln: str) -> BNode: - """Remember or generate a term for one of these _: anonymous nodes""" - term = self._anonymousNodes.get(ln, None) - if term is not None: - return term - term = self._store.newBlankNode(self._context, why=self._reason2) - self._anonymousNodes[ln] = term - return term - - def node( - self, - argstr: str, - i: int, - res: MutableSequence[Any], - subjectAlready: Optional[Node] = None, - ) -> int: - """Parse the production. - Space is now skipped once at the beginning - instead of in multiple calls to self.skipSpace(). - """ - subj: Optional[Node] = subjectAlready - - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - i = j - ch = argstr[i] # Quick 1-character checks first: - - if ch == "[": - bnodeID = self.here(i) - j = self.skipSpace(argstr, i + 1) - if j < 0: - self.BadSyntax(argstr, i, "EOF after '['") - # Hack for "is" binding name to anon node - if argstr[j] == "=": - if self.turtle: - self.BadSyntax( - argstr, j, "Found '[=' or '[ =' when in turtle mode." - ) - i = j + 1 - objs: typing.List[Node] = [] - j = self.objectList(argstr, i, objs) - if j >= 0: - subj = objs[0] - if len(objs) > 1: - for obj in objs: - self.makeStatement((self._context, DAML_sameAs, subj, obj)) - j = self.skipSpace(argstr, j) - if j < 0: - self.BadSyntax( - argstr, i, "EOF when objectList expected after [ = " - ) - if argstr[j] == ";": - j += 1 - else: - self.BadSyntax(argstr, i, "objectList expected after [= ") - - if subj is None: - subj = self.blankNode(uri=bnodeID) - - i = self.property_list(argstr, j, subj) - if i < 0: - self.BadSyntax(argstr, j, "property_list expected") - - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax( - argstr, i, "EOF when ']' expected after [ " - ) - if argstr[j] != "]": - self.BadSyntax(argstr, j, "']' expected") - res.append(subj) - return j + 1 - - if not self.turtle and ch == "{": - # if self.turtle: - # self.BadSyntax(argstr, i, - # "found '{' while in Turtle mode, Formulas not supported!") - ch2 = argstr[i + 1] - if ch2 == "$": - # a set - i += 1 - j = i + 1 - List = [] - first_run = True - while 1: - i = self.skipSpace(argstr, j) - if i < 0: - self.BadSyntax(argstr, i, "needed '$}', found end.") - if argstr[i : i + 2] == "$}": - j = i + 2 - break - - if not first_run: - if argstr[i] == ",": - i += 1 - else: - self.BadSyntax(argstr, i, "expected: ','") - else: - first_run = False - - item: typing.List[Any] = [] - j = self.item(argstr, i, item) # @@@@@ should be path, was object - if j < 0: - self.BadSyntax(argstr, i, "expected item in set or '$}'") - List.append(self._store.intern(item[0])) - res.append(self._store.newSet(List, self._context)) - return j - else: - # parse a formula - j = i + 1 - oldParentContext = self._parentContext - self._parentContext = self._context - parentAnonymousNodes = self._anonymousNodes - grandParentVariables = self._parentVariables - self._parentVariables = self._variables - self._anonymousNodes = {} - self._variables = self._variables.copy() - reason2 = self._reason2 - self._reason2 = becauseSubexpression - if subj is None: - # type error: Incompatible types in assignment (expression has type "Formula", variable has type "Optional[Node]") - subj = self._store.newFormula() # type: ignore[assignment] - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Optional[Formula]") - self._context = subj # type: ignore[assignment] - - while 1: - i = self.skipSpace(argstr, j) - if i < 0: - self.BadSyntax(argstr, i, "needed '}', found end.") - - if argstr[i] == "}": - j = i + 1 - break - - j = self.directiveOrStatement(argstr, i) - if j < 0: - self.BadSyntax(argstr, i, "expected statement or '}'") - - self._anonymousNodes = parentAnonymousNodes - self._variables = self._parentVariables - self._parentVariables = grandParentVariables - self._context = self._parentContext - self._reason2 = reason2 - self._parentContext = oldParentContext - # type error: Item "Node" of "Optional[Node]" has no attribute "close" - res.append( - subj.close() # type: ignore[union-attr] - ) # No use until closed - return j - - if ch == "(": - thing_type: Callable[ - [typing.List[Any], Optional[Formula]], Union[Set[Any], IdentifiedNode] - ] - thing_type = self._store.newList - ch2 = argstr[i + 1] - if ch2 == "$": - thing_type = self._store.newSet - i += 1 - j = i + 1 - - List = [] - while 1: - i = self.skipSpace(argstr, j) - if i < 0: - self.BadSyntax(argstr, i, "needed ')', found end.") - if argstr[i] == ")": - j = i + 1 - break - - item = [] - j = self.item(argstr, i, item) # @@@@@ should be path, was object - if j < 0: - self.BadSyntax(argstr, i, "expected item in list or ')'") - List.append(self._store.intern(item[0])) - res.append(thing_type(List, self._context)) - return j - - j = self.tok("this", argstr, i) # This context - if j >= 0: - self.BadSyntax( - argstr, - i, - "Keyword 'this' was ancient N3. Now use " - + "@forSome and @forAll keywords.", - ) - - # booleans - j = self.tok("true", argstr, i) - if j >= 0: - res.append(True) - return j - j = self.tok("false", argstr, i) - if j >= 0: - res.append(False) - return j - - if subj is None: # If this can be a named node, then check for a name. - j = self.uri_ref2(argstr, i, res) - if j >= 0: - return j - - return -1 - - def property_list(self, argstr: str, i: int, subj: Node) -> int: - """Parse property list - Leaves the terminating punctuation in the buffer - """ - while 1: - while 1: # skip repeat ; - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax( - argstr, i, "EOF found when expected verb in property list" - ) - if argstr[j] != ";": - break - i = j + 1 - - if argstr[j : j + 2] == ":-": - if self.turtle: - self.BadSyntax(argstr, j, "Found in ':-' in Turtle mode") - i = j + 2 - res: typing.List[Any] = [] - j = self.node(argstr, i, res, subj) - if j < 0: - self.BadSyntax(argstr, i, "bad {} or () or [] node after :- ") - i = j - continue - i = j - v: typing.List[Any] = [] - j = self.verb(argstr, i, v) - if j <= 0: - return i # void but valid - - objs: typing.List[Any] = [] - i = self.objectList(argstr, j, objs) - if i < 0: - self.BadSyntax(argstr, j, "objectList expected") - for obj in objs: - dira, sym = v[0] - if dira == "->": - self.makeStatement((self._context, sym, subj, obj)) - else: - self.makeStatement((self._context, sym, obj, subj)) - - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax(argstr, j, "EOF found in list of objects") - if argstr[i] != ";": - return i - i += 1 # skip semicolon and continue - - def commaSeparatedList( - self, - argstr: str, - j: int, - res: MutableSequence[Any], - what: Callable[[str, int, MutableSequence[Any]], int], - ) -> int: - """return value: -1 bad syntax; >1 new position in argstr - res has things found appended - """ - i = self.skipSpace(argstr, j) - if i < 0: - self.BadSyntax(argstr, i, "EOF found expecting comma sep list") - if argstr[i] == ".": - return j # empty list is OK - i = what(argstr, i, res) - if i < 0: - return -1 - - while 1: - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - ch = argstr[j] - if ch != ",": - if ch != ".": - return -1 - return j # Found but not swallowed "." - i = what(argstr, j + 1, res) - if i < 0: - self.BadSyntax(argstr, i, "bad list content") - - def objectList(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - i = self.object(argstr, i, res) - if i < 0: - return -1 - while 1: - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax(argstr, j, "EOF found after object") - if argstr[j] != ",": - return j # Found something else! - i = self.object(argstr, j + 1, res) - if i < 0: - return i - - def checkDot(self, argstr: str, i: int) -> int: - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - ch = argstr[j] - if ch == ".": - return j + 1 # skip - if ch == "}": - return j # don't skip it - if ch == "]": - return j - self.BadSyntax(argstr, j, "expected '.' or '}' or ']' at end of statement") - - def uri_ref2(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - """Generate uri from n3 representation. - - Note that the RDF convention of directly concatenating - NS and local name is now used though I prefer inserting a '#' - to make the namesapces look more like what XML folks expect. - """ - qn: typing.List[Any] = [] - j = self.qname(argstr, i, qn) - if j >= 0: - pfx, ln = qn[0] - if pfx is None: - assert 0, "not used?" - ns = self._baseURI + ADDED_HASH # type: ignore[unreachable] - else: - try: - ns = self._bindings[pfx] - except KeyError: - if pfx == "_": # Magic prefix 2001/05/30, can be changed - res.append(self.anonymousNode(ln)) - return j - if not self.turtle and pfx == "": - ns = join(self._baseURI or "", "#") - else: - self.BadSyntax(argstr, i, 'Prefix "%s:" not bound' % (pfx)) - symb = self._store.newSymbol(ns + ln) - res.append(self._variables.get(symb, symb)) - return j - - i = self.skipSpace(argstr, i) - if i < 0: - return -1 - - if argstr[i] == "?": - v: typing.List[Any] = [] - j = self.variable(argstr, i, v) - if j > 0: # Forget variables as a class, only in context. - res.append(v[0]) - return j - return -1 - - elif argstr[i] == "<": - st = i + 1 - i = argstr.find(">", st) - if i >= 0: - uref = argstr[st:i] # the join should dealt with "": - - # expand unicode escapes - uref = unicodeEscape8.sub(unicodeExpand, uref) - uref = unicodeEscape4.sub(unicodeExpand, uref) - - if self._baseURI: - uref = join(self._baseURI, uref) # was: uripath.join - else: - assert ( - ":" in uref - ), "With no base URI, cannot deal with relative URIs" - if argstr[i - 1] == "#" and not uref[-1:] == "#": - uref += "#" # She meant it! Weirdness in urlparse? - symb = self._store.newSymbol(uref) - res.append(self._variables.get(symb, symb)) - return i + 1 - self.BadSyntax(argstr, j, "unterminated URI reference") - - elif self.keywordsSet: - v = [] - j = self.bareWord(argstr, i, v) - if j < 0: - return -1 # Forget variables as a class, only in context. - if v[0] in self.keywords: - self.BadSyntax(argstr, i, 'Keyword "%s" not allowed here.' % v[0]) - res.append(self._store.newSymbol(self._bindings[""] + v[0])) - return j - else: - return -1 - - def skipSpace(self, argstr: str, i: int) -> int: - """Skip white space, newlines and comments. - return -1 if EOF, else position of first non-ws character""" - - # Most common case is a non-commented line starting with few spaces and tabs. - try: - while True: - ch = argstr[i] - if ch in {" ", "\t"}: - i += 1 - continue - elif ch not in {"#", "\r", "\n"}: - return i - break - except IndexError: - return -1 - - while 1: - m = eol.match(argstr, i) - if m is None: - break - self.lines += 1 - self.startOfLine = i = m.end() # Point to first character unmatched - m = ws.match(argstr, i) - if m is not None: - i = m.end() - m = eof.match(argstr, i) - return i if m is None else -1 - - def variable(self, argstr: str, i: int, res) -> int: - """?abc -> variable(:abc)""" - - j = self.skipSpace(argstr, i) - if j < 0: - return -1 - - if argstr[j] != "?": - return -1 - j += 1 - i = j - if argstr[j] in numberChars: - self.BadSyntax(argstr, j, "Variable name can't start with '%s'" % argstr[j]) - len_argstr = len(argstr) - while i < len_argstr and argstr[i] not in _notKeywordsChars: - i += 1 - if self._parentContext is None: - varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i]) # type: ignore[operator] - if varURI not in self._variables: - # type error: Item "None" of "Optional[Formula]" has no attribute "newUniversal" - self._variables[varURI] = self._context.newUniversal( # type: ignore[union-attr] - varURI, why=self._reason2 - ) - res.append(self._variables[varURI]) - return i - # @@ was: - # self.BadSyntax(argstr, j, - # "Can't use ?xxx syntax for variable in outermost level: %s" - # % argstr[j-1:i]) - varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i]) # type: ignore[operator] - if varURI not in self._parentVariables: - self._parentVariables[varURI] = self._parentContext.newUniversal( - varURI, why=self._reason2 - ) - res.append(self._parentVariables[varURI]) - return i - - def bareWord(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - """abc -> :abc""" - j = self.skipSpace(argstr, i) - if j < 0: - return -1 - - if argstr[j] in numberChars or argstr[j] in _notKeywordsChars: - return -1 - i = j - len_argstr = len(argstr) - while i < len_argstr and argstr[i] not in _notKeywordsChars: - i += 1 - res.append(argstr[j:i]) - return i - - def qname( - self, - argstr: str, - i: int, - res: MutableSequence[Union[Identifier, Tuple[str, str]]], - ) -> int: - """ - xyz:def -> ('xyz', 'def') - If not in keywords and keywordsSet: def -> ('', 'def') - :def -> ('', 'def') - """ - - i = self.skipSpace(argstr, i) - if i < 0: - return -1 - - c = argstr[i] - if c in numberCharsPlus: - return -1 - len_argstr = len(argstr) - if c not in _notNameChars: - j = i - i += 1 - - try: - while argstr[i] not in _notNameChars: - i += 1 - except IndexError: - pass # Very rare. - - if argstr[i - 1] == ".": # qname cannot end with "." - i -= 1 - if i == j: - return -1 - ln = argstr[j:i] - - else: # First character is non-alpha - ln = "" # Was: None - TBL (why? useful?) - - if i < len_argstr and argstr[i] == ":": - pfx = ln - # bnodes names have different rules - if pfx == "_": - allowedChars = _notNameChars - else: - allowedChars = _notQNameChars - - i += 1 - lastslash = False - start = i - ln = "" - while i < len_argstr: - c = argstr[i] - if c == "\\" and not lastslash: # Very rare. - lastslash = True - if start < i: - ln += argstr[start:i] - start = i + 1 - elif c not in allowedChars or lastslash: # Most common case is "a-zA-Z" - if lastslash: - if c not in escapeChars: - raise BadSyntax( - self._thisDoc, - self.lines, - argstr, - i, - "illegal escape " + c, - ) - elif c == "%": # Very rare. - if ( - argstr[i + 1] not in hexChars - or argstr[i + 2] not in hexChars - ): - raise BadSyntax( - self._thisDoc, - self.lines, - argstr, - i, - "illegal hex escape " + c, - ) - lastslash = False - else: - break - i += 1 - - if lastslash: - raise BadSyntax( - self._thisDoc, self.lines, argstr, i, "qname cannot end with \\" - ) - - if argstr[i - 1] == ".": - # localname cannot end in . - if len(ln) == 0 and start == i: - return -1 - i -= 1 - - if start < i: - ln += argstr[start:i] - - res.append((pfx, ln)) - return i - - else: # delimiter was not ":" - if ln and self.keywordsSet and ln not in self.keywords: - res.append(("", ln)) - return i - return -1 - - def object( - self, - argstr: str, - i: int, - res: MutableSequence[Any], - ) -> int: - j = self.subject(argstr, i, res) - if j >= 0: - return j - else: - j = self.skipSpace(argstr, i) - if j < 0: - return -1 - else: - i = j - - ch = argstr[i] - if ch in self.string_delimiters: - ch_three = ch * 3 - if argstr[i : i + 3] == ch_three: - delim = ch_three - i += 3 - else: - delim = ch - i += 1 - - j, s = self.strconst(argstr, i, delim) - - res.append(self._store.newLiteral(s)) # type: ignore[call-arg] # TODO FIXME - return j - else: - return -1 - - def nodeOrLiteral(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: - j = self.node(argstr, i, res) - startline = self.lines # Remember where for error messages - if j >= 0: - return j - else: - j = self.skipSpace(argstr, i) - if j < 0: - return -1 - else: - i = j - - ch = argstr[i] - if ch in numberCharsPlus: - m = exponent_syntax.match(argstr, i) - if m: - j = m.end() - res.append(float(argstr[i:j])) - return j - - m = decimal_syntax.match(argstr, i) - if m: - j = m.end() - res.append(Decimal(argstr[i:j])) - return j - - m = integer_syntax.match(argstr, i) - if m: - j = m.end() - res.append(long_type(argstr[i:j])) - return j - - # return -1 ## or fall through? - - ch_three = ch * 3 - if ch in self.string_delimiters: - if argstr[i : i + 3] == ch_three: - delim = ch_three - i += 3 - else: - delim = ch - i += 1 - - dt = None - j, s = self.strconst(argstr, i, delim) - lang = None - if argstr[j] == "@": # Language? - m = langcode.match(argstr, j + 1) - if m is None: - raise BadSyntax( - self._thisDoc, - startline, - argstr, - i, - "Bad language code syntax on string " + "literal, after @", - ) - i = m.end() - lang = argstr[j + 1 : i] - j = i - if argstr[j : j + 2] == "^^": - res2: typing.List[Any] = [] - j = self.uri_ref2(argstr, j + 2, res2) # Read datatype URI - dt = res2[0] - res.append(self._store.newLiteral(s, dt, lang)) - return j - else: - return -1 - - def uriOf(self, sym: Union[Identifier, Tuple[str, str]]) -> str: - if isinstance(sym, tuple): - return sym[1] # old system for --pipe - # return sym.uriref() # cwm api - return sym - - def strconst(self, argstr: str, i: int, delim: str) -> Tuple[int, str]: - """parse an N3 string constant delimited by delim. - return index, val - """ - delim1 = delim[0] - delim2, delim3, delim4, delim5 = delim1 * 2, delim1 * 3, delim1 * 4, delim1 * 5 - - j = i - ustr = "" # Empty unicode string - startline = self.lines # Remember where for error messages - len_argstr = len(argstr) - while j < len_argstr: - if argstr[j] == delim1: - if delim == delim1: # done when delim is " or ' - i = j + 1 - return i, ustr - if ( - delim == delim3 - ): # done when delim is """ or ''' and, respectively ... - if argstr[j : j + 5] == delim5: # ... we have "" or '' before - i = j + 5 - ustr += delim2 - return i, ustr - if argstr[j : j + 4] == delim4: # ... we have " or ' before - i = j + 4 - ustr += delim1 - return i, ustr - if argstr[j : j + 3] == delim3: # current " or ' is part of delim - i = j + 3 - return i, ustr - - # we are inside of the string and current char is " or ' - j += 1 - ustr += delim1 - continue - - m = interesting.search(argstr, j) # was argstr[j:]. - # Note for pos param to work, MUST be compiled ... re bug? - assert m, "Quote expected in string at ^ in %s^%s" % ( - argstr[j - 20 : j], - argstr[j : j + 20], - ) # at least need a quote - - i = m.start() - try: - ustr += argstr[j:i] - except UnicodeError: - err = "" - for c in argstr[j:i]: - err = err + (" %02x" % ord(c)) - streason = sys.exc_info()[1].__str__() - raise BadSyntax( - self._thisDoc, - startline, - argstr, - j, - "Unicode error appending characters" - + " %s to string, because\n\t%s" % (err, streason), - ) - - # print "@@@ i = ",i, " j=",j, "m.end=", m.end() - - ch = argstr[i] - if ch == delim1: - j = i - continue - elif ch in {'"', "'"} and ch != delim1: - ustr += ch - j = i + 1 - continue - elif ch in {"\r", "\n"}: - if delim == delim1: - raise BadSyntax( - self._thisDoc, - startline, - argstr, - i, - "newline found in string literal", - ) - self.lines += 1 - ustr += ch - j = i + 1 - self.startOfLine = j - - elif ch == "\\": - j = i + 1 - ch = argstr[j] # Will be empty if string ends - if not ch: - raise BadSyntax( - self._thisDoc, - startline, - argstr, - i, - "unterminated string literal (2)", - ) - k = "abfrtvn\\\"'".find(ch) - if k >= 0: - uch = "\a\b\f\r\t\v\n\\\"'"[k] - ustr += uch - j += 1 - elif ch == "u": - j, ch = self.uEscape(argstr, j + 1, startline) - ustr += ch - elif ch == "U": - j, ch = self.UEscape(argstr, j + 1, startline) - ustr += ch - else: - self.BadSyntax(argstr, i, "bad escape") - - self.BadSyntax(argstr, i, "unterminated string literal") - - def _unicodeEscape( - self, - argstr: str, - i: int, - startline: int, - reg: Pattern[str], - n: int, - prefix: str, - ) -> Tuple[int, str]: - if len(argstr) < i + n: - raise BadSyntax( - self._thisDoc, startline, argstr, i, "unterminated string literal(3)" - ) - try: - return i + n, reg.sub(unicodeExpand, "\\" + prefix + argstr[i : i + n]) - except Exception: - raise BadSyntax( - self._thisDoc, - startline, - argstr, - i, - "bad string literal hex escape: " + argstr[i : i + n], - ) - - def uEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]: - return self._unicodeEscape(argstr, i, startline, unicodeEscape4, 4, "u") - - def UEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]: - return self._unicodeEscape(argstr, i, startline, unicodeEscape8, 8, "U") - - def BadSyntax(self, argstr: str, i: int, msg: str) -> NoReturn: - raise BadSyntax(self._thisDoc, self.lines, argstr, i, msg) - - -# If we are going to do operators then they should generate -# [ is operator:plus of ( \1 \2 ) ] - - -class BadSyntax(SyntaxError): # noqa: N818 - def __init__(self, uri: str, lines: int, argstr: str, i: int, why: str): - self._str = argstr.encode("utf-8") # Better go back to strings for errors - self._i = i - self._why = why - self.lines = lines - self._uri = uri - - def __str__(self) -> str: - argstr = self._str - i = self._i - st = 0 - if i > 60: - pre = "..." - st = i - 60 - else: - pre = "" - if len(argstr) - i > 60: - post = "..." - else: - post = "" - - # type error: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior - return 'at line %i of <%s>:\nBad syntax (%s) at ^ in:\n"%s%s^%s%s"' % ( - self.lines + 1, # type: ignore[str-bytes-safe] - self._uri, - self._why, - pre, - argstr[st:i], - argstr[i : i + 60], - post, - ) - - @property - def message(self) -> str: - return str(self) - - -############################################################################### -class Formula: - number = 0 - - def __init__(self, parent: Graph): - self.uuid = uuid4().hex - self.counter = 0 - Formula.number += 1 - self.number = Formula.number - self.existentials: Dict[str, BNode] = {} - self.universals: Dict[str, BNode] = {} - - self.quotedgraph = QuotedGraph(store=parent.store, identifier=self.id()) - - def __str__(self) -> str: - return "_:Formula%s" % self.number - - def id(self) -> BNode: - return BNode("_:Formula%s" % self.number) - - def newBlankNode( - self, uri: Optional[str] = None, why: Optional[Any] = None - ) -> BNode: - if uri is None: - self.counter += 1 - bn = BNode("f%sb%s" % (self.uuid, self.counter)) - else: - bn = BNode(uri.split("#").pop().replace("_", "b")) - return bn - - def newUniversal(self, uri: str, why: Optional[Any] = None) -> Variable: - return Variable(uri.split("#").pop()) - - def declareExistential(self, x: str) -> None: - self.existentials[x] = self.newBlankNode() - - def close(self) -> QuotedGraph: - return self.quotedgraph - - -r_hibyte = re.compile(r"([\x80-\xff])") - - -class RDFSink: - def __init__(self, graph: Graph): - self.rootFormula: Optional[Formula] = None - self.uuid = uuid4().hex - self.counter = 0 - self.graph = graph - - def newFormula(self) -> Formula: - fa = getattr(self.graph.store, "formula_aware", False) - if not fa: - raise ParserError( - "Cannot create formula parser with non-formula-aware store." - ) - f = Formula(self.graph) - return f - - def newGraph(self, identifier: Identifier) -> Graph: - return Graph(self.graph.store, identifier) - - def newSymbol(self, *args: str) -> URIRef: - return URIRef(args[0]) - - def newBlankNode( - self, - arg: Optional[Union[Formula, Graph, Any]] = None, - uri: Optional[str] = None, - why: Optional[Callable[[], None]] = None, - ) -> BNode: - if isinstance(arg, Formula): - return arg.newBlankNode(uri) - elif isinstance(arg, Graph) or arg is None: - self.counter += 1 - bn = BNode("n%sb%s" % (self.uuid, self.counter)) - else: - bn = BNode(str(arg[0]).split("#").pop().replace("_", "b")) - return bn - - def newLiteral(self, s: str, dt: Optional[URIRef], lang: Optional[str]) -> Literal: - if dt: - return Literal(s, datatype=dt) - else: - return Literal(s, lang=lang) - - def newList(self, n: typing.List[Any], f: Optional[Formula]) -> IdentifiedNode: - nil = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil") - if not n: - return nil - - first = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") - rest = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") - af = a = self.newBlankNode(f) - - for ne in n[:-1]: - self.makeStatement((f, first, a, ne)) - an = self.newBlankNode(f) - self.makeStatement((f, rest, a, an)) - a = an - self.makeStatement((f, first, a, n[-1])) - self.makeStatement((f, rest, a, nil)) - return af - - def newSet(self, *args: _AnyT) -> Set[_AnyT]: - return set(args) - - def setDefaultNamespace(self, *args: bytes) -> str: - return ":".join(repr(n) for n in args) - - def makeStatement( - self, - quadruple: Tuple[Optional[Union[Formula, Graph]], Node, Node, Node], - why: Optional[Any] = None, - ) -> None: - f, p, s, o = quadruple - - if hasattr(p, "formula"): - raise ParserError("Formula used as predicate") - - # type error: Argument 1 to "normalise" of "RDFSink" has incompatible type "Union[Formula, Graph, None]"; expected "Optional[Formula]" - s = self.normalise(f, s) # type: ignore[arg-type] - p = self.normalise(f, p) # type: ignore[arg-type] - o = self.normalise(f, o) # type: ignore[arg-type] - - if f == self.rootFormula: - # print s, p, o, '.' - self.graph.add((s, p, o)) - elif isinstance(f, Formula): - f.quotedgraph.add((s, p, o)) - else: - # type error: Item "None" of "Optional[Graph]" has no attribute "add" - f.add((s, p, o)) # type: ignore[union-attr] - - # return str(quadruple) - - def normalise( - self, - f: Optional[Formula], - n: Union[Tuple[int, str], bool, int, Decimal, float, _AnyT], - ) -> Union[URIRef, Literal, BNode, _AnyT]: - if isinstance(n, tuple): - return URIRef(str(n[1])) - - if isinstance(n, bool): - s = Literal(str(n).lower(), datatype=BOOLEAN_DATATYPE) - return s - - if isinstance(n, int) or isinstance(n, long_type): - s = Literal(str(n), datatype=INTEGER_DATATYPE) - return s - - if isinstance(n, Decimal): - value = str(n) - if value == "-0": - value = "0" - s = Literal(value, datatype=DECIMAL_DATATYPE) - return s - - if isinstance(n, float): - s = Literal(str(n), datatype=DOUBLE_DATATYPE) - return s - - if isinstance(f, Formula): - if n in f.existentials: - if TYPE_CHECKING: - assert isinstance(n, URIRef) - return f.existentials[n] - - # if isinstance(n, Var): - # if f.universals.has_key(n): - # return f.universals[n] - # f.universals[n] = f.newBlankNode() - # return f.universals[n] - # type error: Incompatible return value type (got "Union[int, _AnyT]", expected "Union[URIRef, Literal, BNode, _AnyT]") [return-value] - return n # type: ignore[return-value] - - def intern(self, something: _AnyT) -> _AnyT: - return something - - def bind(self, pfx, uri) -> None: - pass # print pfx, ':', uri - - def startDoc(self, formula: Optional[Formula]) -> None: - self.rootFormula = formula - - def endDoc(self, formula: Optional[Formula]) -> None: - pass - - -################################################### -# -# Utilities -# - - -def hexify(ustr: str) -> bytes: - """Use URL encoding to return an ASCII string - corresponding to the given UTF8 string - - >>> hexify("http://example/a b") - b'http://example/a%20b' - - """ - # s1=ustr.encode('utf-8') - s = "" - for ch in ustr: # .encode('utf-8'): - if ord(ch) > 126 or ord(ch) < 33: - ch = "%%%02X" % ord(ch) - else: - ch = "%c" % ord(ch) - s = s + ch - return s.encode("latin-1") - - -class TurtleParser(Parser): - """ - An RDFLib parser for Turtle - - See http://www.w3.org/TR/turtle/ - """ - - def __init__(self): - pass - - def parse( - self, - source: InputSource, - graph: Graph, - encoding: Optional[str] = "utf-8", - turtle: bool = True, - ) -> None: - if encoding not in [None, "utf-8"]: - raise ParserError( - "N3/Turtle files are always utf-8 encoded, I was passed: %s" % encoding - ) - - sink = RDFSink(graph) - - baseURI = graph.absolutize(source.getPublicId() or source.getSystemId() or "") - p = SinkParser(sink, baseURI=baseURI, turtle=turtle) - # N3 parser prefers str stream - stream = source.getCharacterStream() - if not stream: - stream = source.getByteStream() - p.loadStream(stream) - - for prefix, namespace in p._bindings.items(): - graph.bind(prefix, namespace) - - -class N3Parser(TurtleParser): - """ - An RDFLib parser for Notation3 - - See http://www.w3.org/DesignIssues/Notation3.html - - """ - - def __init__(self): - pass - - # type error: Signature of "parse" incompatible with supertype "TurtleParser" - def parse( # type: ignore[override] - self, source: InputSource, graph: Graph, encoding: Optional[str] = "utf-8" - ) -> None: - # we're currently being handed a Graph, not a ConjunctiveGraph - # context-aware is this implied by formula_aware - ca = getattr(graph.store, "context_aware", False) - fa = getattr(graph.store, "formula_aware", False) - if not ca: - raise ParserError("Cannot parse N3 into non-context-aware store.") - elif not fa: - raise ParserError("Cannot parse N3 into non-formula-aware store.") - - conj_graph = Dataset(store=graph.store) - conj_graph.default_context = graph # TODO: CG __init__ should have a - # default_context arg - # TODO: update N3Processor so that it can use conj_graph as the sink - conj_graph.namespace_manager = graph.namespace_manager - - TurtleParser.parse(self, source, conj_graph, encoding, turtle=False) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/nquads.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/nquads.py deleted file mode 100644 index 60b793b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/nquads.py +++ /dev/null @@ -1,133 +0,0 @@ -""" -This is a rdflib plugin for parsing NQuad files into Conjunctive -graphs that can be used and queried. The store that backs the graph -*must* be able to handle contexts. - ->>> from rdflib import ConjunctiveGraph, URIRef, Namespace ->>> g = ConjunctiveGraph() ->>> data = open("test/data/nquads.rdflib/example.nquads", "rb") ->>> g.parse(data, format="nquads") # doctest:+ELLIPSIS -)> ->>> assert len(g.store) == 449 ->>> # There should be 16 separate contexts ->>> assert len([x for x in g.store.contexts()]) == 16 ->>> # is the name of entity E10009 "Arco Publications"? ->>> # (in graph http://bibliographica.org/entity/E10009) ->>> # Looking for: ->>> # ->>> # ->>> # "Arco Publications" ->>> # ->>> s = URIRef("http://bibliographica.org/entity/E10009") ->>> FOAF = Namespace("http://xmlns.com/foaf/0.1/") ->>> assert(g.value(s, FOAF.name).eq("Arco Publications")) -""" - -from __future__ import annotations - -from codecs import getreader -from typing import Any, MutableMapping, Optional - -from rdflib.exceptions import ParserError as ParseError -from rdflib.graph import ConjunctiveGraph, Dataset, Graph -from rdflib.parser import InputSource - -# Build up from the NTriples parser: -from rdflib.plugins.parsers.ntriples import W3CNTriplesParser, r_tail, r_wspace -from rdflib.term import BNode - -__all__ = ["NQuadsParser"] - -_BNodeContextType = MutableMapping[str, BNode] - - -class NQuadsParser(W3CNTriplesParser): - - # type error: Signature of "parse" incompatible with supertype "W3CNTriplesParser" - def parse( # type: ignore[override] - self, - inputsource: InputSource, - sink: Graph, - bnode_context: Optional[_BNodeContextType] = None, - skolemize: bool = False, - **kwargs: Any, - ): - """ - Parse inputsource as an N-Quads file. - - :type inputsource: `rdflib.parser.InputSource` - :param inputsource: the source of N-Quads-formatted data - :type sink: `rdflib.graph.Graph` - :param sink: where to send parsed triples - :type bnode_context: `dict`, optional - :param bnode_context: a dict mapping blank node identifiers to `~rdflib.term.BNode` instances. - See `.W3CNTriplesParser.parse` - """ - assert ( - sink.store.context_aware - ), "NQuadsParser must be given a context-aware store." - # Set default_union to True to mimic ConjunctiveGraph behavior - ds = Dataset(store=sink.store, default_union=True) - ds_default = ds.default_context # the DEFAULT_DATASET_GRAPH_ID - new_default_context = None - if isinstance(sink, (Dataset, ConjunctiveGraph)): - new_default_context = sink.default_context - elif sink.identifier is not None: - if sink.identifier == ds_default.identifier: - new_default_context = sink - else: - new_default_context = ds.get_context(sink.identifier) - - if new_default_context is not None: - ds.default_context = new_default_context - ds.remove_graph(ds_default) # remove the original unused default graph - # type error: Incompatible types in assignment (expression has type "ConjunctiveGraph", base class "W3CNTriplesParser" defined the type as "Union[DummySink, NTGraphSink]") - self.sink: Dataset = ds # type: ignore[assignment] - self.skolemize = skolemize - - source = inputsource.getCharacterStream() - if not source: - source = inputsource.getByteStream() - source = getreader("utf-8")(source) - - if not hasattr(source, "read"): - raise ParseError("Item to parse must be a file-like object.") - - self.file = source - self.buffer = "" - while True: - self.line = __line = self.readline() - if self.line is None: - break - try: - self.parseline(bnode_context) - except ParseError as msg: - raise ParseError("Invalid line (%s):\n%r" % (msg, __line)) - - return self.sink - - def parseline(self, bnode_context: Optional[_BNodeContextType] = None) -> None: - self.eat(r_wspace) - if (not self.line) or self.line.startswith("#"): - return # The line is empty or a comment - - subject = self.subject(bnode_context) - self.eat(r_wspace) - - predicate = self.predicate() - self.eat(r_wspace) - - obj = self.object(bnode_context) - self.eat(r_wspace) - - context = self.uriref() or self.nodeid(bnode_context) - self.eat(r_tail) - - if self.line: - raise ParseError("Trailing garbage") - # Must have a context aware store - add on a normal Graph - # discards anything where the ctx != graph.identifier - if context: - self.sink.get_context(context).add((subject, predicate, obj)) - else: - self.sink.default_context.add((subject, predicate, obj)) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/ntriples.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/ntriples.py deleted file mode 100644 index 933e99f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/ntriples.py +++ /dev/null @@ -1,385 +0,0 @@ -"""\ -N-Triples Parser -License: GPL 2, W3C, BSD, or MIT -Author: Sean B. Palmer, inamidst.com -""" - -from __future__ import annotations - -import codecs -import re -from io import BytesIO, StringIO, TextIOBase -from typing import ( - IO, - TYPE_CHECKING, - Any, - Match, - MutableMapping, - Optional, - Pattern, - TextIO, - Union, -) - -from rdflib.compat import _string_escape_map, decodeUnicodeEscape -from rdflib.exceptions import ParserError as ParseError -from rdflib.parser import InputSource, Parser -from rdflib.term import BNode as bNode -from rdflib.term import Literal, URIRef -from rdflib.term import URIRef as URI # noqa: N814 - -if TYPE_CHECKING: - import typing_extensions as te - - from rdflib.graph import Graph, _ObjectType, _PredicateType, _SubjectType - -__all__ = [ - "unquote", - "uriquote", - "W3CNTriplesParser", - "NTGraphSink", - "NTParser", - "DummySink", -] - -uriref = r'<([^:]+:[^\s"<>]*)>' -literal = r'"([^"\\]*(?:\\.[^"\\]*)*)"' -litinfo = r"(?:@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)|\^\^" + uriref + r")?" - -r_line = re.compile(r"([^\r\n]*)(?:\r\n|\r|\n)") -r_wspace = re.compile(r"[ \t]*") -r_wspaces = re.compile(r"[ \t]+") -r_tail = re.compile(r"[ \t]*\.[ \t]*(#.*)?") -r_uriref = re.compile(uriref) -r_nodeid = re.compile(r"_:([A-Za-z0-9_:]([-A-Za-z0-9_:\.]*[-A-Za-z0-9_:])?)") -r_literal = re.compile(literal + litinfo) - -bufsiz = 2048 -validate = False - - -class DummySink: - def __init__(self): - self.length = 0 - - def triple(self, s, p, o): - self.length += 1 - print(s, p, o) - - -r_safe = re.compile(r"([\x20\x21\x23-\x5B\x5D-\x7E]+)") -r_quot = re.compile(r"""\\([tbnrf"'\\])""") -r_uniquot = re.compile(r"\\u([0-9A-Fa-f]{4})|\\U([0-9A-Fa-f]{8})") - - -def unquote(s: str) -> str: - """Unquote an N-Triples string.""" - if not validate: - if isinstance(s, str): # nquads - s = decodeUnicodeEscape(s) - else: - s = s.decode("unicode-escape") # type: ignore[unreachable] - - return s - else: - result = [] - while s: - m = r_safe.match(s) - if m: - s = s[m.end() :] - result.append(m.group(1)) - continue - - m = r_quot.match(s) - if m: - s = s[2:] - result.append(_string_escape_map[m.group(1)]) - continue - - m = r_uniquot.match(s) - if m: - s = s[m.end() :] - u, U = m.groups() # noqa: N806 - codepoint = int(u or U, 16) - if codepoint > 0x10FFFF: - raise ParseError("Disallowed codepoint: %08X" % codepoint) - result.append(chr(codepoint)) - elif s.startswith("\\"): - raise ParseError("Illegal escape at: %s..." % s[:10]) - else: - raise ParseError("Illegal literal character: %r" % s[0]) - return "".join(result) - - -r_hibyte = re.compile(r"([\x80-\xFF])") - - -def uriquote(uri: str) -> str: - if not validate: - return uri - else: - return r_hibyte.sub(lambda m: "%%%02X" % ord(m.group(1)), uri) - - -_BNodeContextType = MutableMapping[str, bNode] - - -class W3CNTriplesParser: - """An N-Triples Parser. - This is a legacy-style Triples parser for NTriples provided by W3C - Usage:: - - p = W3CNTriplesParser(sink=MySink()) - sink = p.parse(f) # file; use parsestring for a string - - To define a context in which blank node identifiers refer to the same blank node - across instances of NTriplesParser, pass the same dict as ``bnode_context`` to each - instance. By default, a new blank node context is created for each instance of - `W3CNTriplesParser`. - """ - - __slots__ = ("_bnode_ids", "sink", "buffer", "file", "line", "skolemize") - - def __init__( - self, - sink: Optional[Union[DummySink, NTGraphSink]] = None, - bnode_context: Optional[_BNodeContextType] = None, - ): - self.skolemize = False - - if bnode_context is not None: - self._bnode_ids = bnode_context - else: - self._bnode_ids = {} - - self.sink: Union[DummySink, NTGraphSink] - if sink is not None: - self.sink = sink - else: - self.sink = DummySink() - - self.buffer: Optional[str] = None - self.file: Optional[Union[TextIO, codecs.StreamReader]] = None - self.line: Optional[str] = "" - - def parse( - self, - f: Union[TextIO, IO[bytes], codecs.StreamReader], - bnode_context: Optional[_BNodeContextType] = None, - skolemize: bool = False, - ) -> Union[DummySink, NTGraphSink]: - """ - Parse f as an N-Triples file. - - :type f: :term:`file object` - :param f: the N-Triples source - :type bnode_context: `dict`, optional - :param bnode_context: a dict mapping blank node identifiers (e.g., ``a`` in ``_:a``) - to `~rdflib.term.BNode` instances. An empty dict can be - passed in to define a distinct context for a given call to - `parse`. - """ - - if not hasattr(f, "read"): - raise ParseError("Item to parse must be a file-like object.") - - if not hasattr(f, "encoding") and not hasattr(f, "charbuffer"): - # someone still using a bytestream here? - f = codecs.getreader("utf-8")(f) - - self.skolemize = skolemize - self.file = f # type: ignore[assignment] - self.buffer = "" - while True: - self.line = self.readline() - if self.line is None: - break - try: - self.parseline(bnode_context=bnode_context) - except ParseError: - raise ParseError("Invalid line: {}".format(self.line)) - return self.sink - - def parsestring(self, s: Union[bytes, bytearray, str], **kwargs) -> None: - """Parse s as an N-Triples string.""" - if not isinstance(s, (str, bytes, bytearray)): - raise ParseError("Item to parse must be a string instance.") - f: Union[codecs.StreamReader, StringIO] - if isinstance(s, (bytes, bytearray)): - f = codecs.getreader("utf-8")(BytesIO(s)) - else: - f = StringIO(s) - self.parse(f, **kwargs) - - def readline(self) -> Optional[str]: - """Read an N-Triples line from buffered input.""" - # N-Triples lines end in either CRLF, CR, or LF - # Therefore, we can't just use f.readline() - if not self.buffer: - # type error: Item "None" of "Union[TextIO, StreamReader, None]" has no attribute "read" - buffer = self.file.read(bufsiz) # type: ignore[union-attr] - if not buffer: - return None - self.buffer = buffer - - while True: - m = r_line.match(self.buffer) - if m: # the more likely prospect - self.buffer = self.buffer[m.end() :] - return m.group(1) - else: - # type error: Item "None" of "Union[TextIO, StreamReader, None]" has no attribute "read" - buffer = self.file.read(bufsiz) # type: ignore[union-attr] - if not buffer and not self.buffer.isspace(): - # Last line does not need to be terminated with a newline - buffer += "\n" - elif not buffer: - return None - self.buffer += buffer - - def parseline(self, bnode_context: Optional[_BNodeContextType] = None) -> None: - self.eat(r_wspace) - if (not self.line) or self.line.startswith("#"): - return # The line is empty or a comment - - subject = self.subject(bnode_context) - self.eat(r_wspaces) - - predicate = self.predicate() - self.eat(r_wspaces) - - object_ = self.object(bnode_context) - self.eat(r_tail) - - if self.line: - raise ParseError("Trailing garbage: {}".format(self.line)) - self.sink.triple(subject, predicate, object_) - - def peek(self, token: str) -> bool: - return self.line.startswith(token) # type: ignore[union-attr] - - def eat(self, pattern: Pattern[str]) -> Match[str]: - m = pattern.match(self.line) # type: ignore[arg-type] - if not m: # @@ Why can't we get the original pattern? - # print(dir(pattern)) - # print repr(self.line), type(self.line) - raise ParseError("Failed to eat %s at %s" % (pattern.pattern, self.line)) - self.line = self.line[m.end() :] # type: ignore[index] - return m - - def subject(self, bnode_context=None) -> Union[bNode, URIRef]: - # @@ Consider using dictionary cases - subj = self.uriref() or self.nodeid(bnode_context) - if not subj: - raise ParseError("Subject must be uriref or nodeID") - return subj - - def predicate(self) -> Union[bNode, URIRef]: - pred = self.uriref() - if not pred: - raise ParseError("Predicate must be uriref") - return pred - - def object( - self, bnode_context: Optional[_BNodeContextType] = None - ) -> Union[URI, bNode, Literal]: - objt = self.uriref() or self.nodeid(bnode_context) or self.literal() - if objt is False: - raise ParseError("Unrecognised object type") - return objt - - def uriref(self) -> Union[te.Literal[False], URI]: - if self.peek("<"): - uri = self.eat(r_uriref).group(1) - uri = unquote(uri) - uri = uriquote(uri) - return URI(uri) - return False - - def nodeid( - self, bnode_context: Optional[_BNodeContextType] = None - ) -> Union[te.Literal[False], bNode, URI]: - if self.peek("_"): - if self.skolemize: - bnode_id = self.eat(r_nodeid).group(1) - return bNode(bnode_id).skolemize() - - else: - # Fix for https://github.com/RDFLib/rdflib/issues/204 - if bnode_context is None: - bnode_context = self._bnode_ids - bnode_id = self.eat(r_nodeid).group(1) - new_id = bnode_context.get(bnode_id, None) - if new_id is not None: - # Re-map to id specific to this doc - return bNode(new_id) - else: - # Replace with freshly-generated document-specific BNode id - bnode = bNode() - # Store the mapping - bnode_context[bnode_id] = bnode - return bnode - return False - - def literal(self) -> Union[te.Literal[False], Literal]: - if self.peek('"'): - lit, lang, dtype = self.eat(r_literal).groups() - if lang: - lang = lang - else: - lang = None - if dtype: - dtype = unquote(dtype) - dtype = uriquote(dtype) - dtype = URI(dtype) - else: - dtype = None - if lang and dtype: - raise ParseError("Can't have both a language and a datatype") - lit = unquote(lit) - return Literal(lit, lang, dtype) - return False - - -class NTGraphSink: - __slots__ = ("g",) - - def __init__(self, graph: Graph): - self.g = graph - - def triple(self, s: _SubjectType, p: _PredicateType, o: _ObjectType) -> None: - self.g.add((s, p, o)) - - -class NTParser(Parser): - """parser for the ntriples format, often stored with the .nt extension - - See http://www.w3.org/TR/rdf-testcases/#ntriples""" - - __slots__ = () - - @classmethod - def parse(cls, source: InputSource, sink: Graph, **kwargs: Any) -> None: - """ - Parse the NT format - - :type source: `rdflib.parser.InputSource` - :param source: the source of NT-formatted data - :type sink: `rdflib.graph.Graph` - :param sink: where to send parsed triples - :param kwargs: Additional arguments to pass to `.W3CNTriplesParser.parse` - """ - f: Union[TextIO, IO[bytes], codecs.StreamReader] - f = source.getCharacterStream() - if not f: - b = source.getByteStream() - # TextIOBase includes: StringIO and TextIOWrapper - if isinstance(b, TextIOBase): - # f is not really a ByteStream, but a CharacterStream - f = b # type: ignore[assignment] - else: - # since N-Triples 1.1 files can and should be utf-8 encoded - f = codecs.getreader("utf-8")(b) - parser = W3CNTriplesParser(NTGraphSink(sink)) - parser.parse(f, **kwargs) - f.close() diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/patch.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/patch.py deleted file mode 100644 index 5e8f12d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/patch.py +++ /dev/null @@ -1,183 +0,0 @@ -from __future__ import annotations - -from codecs import getreader -from enum import Enum -from typing import TYPE_CHECKING, Any, MutableMapping, Optional, Union - -from rdflib.exceptions import ParserError as ParseError -from rdflib.graph import Dataset -from rdflib.parser import InputSource -from rdflib.plugins.parsers.nquads import NQuadsParser - -# Build up from the NTriples parser: -from rdflib.plugins.parsers.ntriples import r_nodeid, r_tail, r_uriref, r_wspace -from rdflib.term import BNode, URIRef - -if TYPE_CHECKING: - import typing_extensions as te - -__all__ = ["RDFPatchParser", "Operation"] - -_BNodeContextType = MutableMapping[str, BNode] - - -class Operation(Enum): - """ - Enum of RDF Patch operations. - - Operations: - - `AddTripleOrQuad` (A): Adds a triple or quad. - - `DeleteTripleOrQuad` (D): Deletes a triple or quad. - - `AddPrefix` (PA): Adds a prefix. - - `DeletePrefix` (PD): Deletes a prefix. - - `TransactionStart` (TX): Starts a transaction. - - `TransactionCommit` (TC): Commits a transaction. - - `TransactionAbort` (TA): Aborts a transaction. - - `Header` (H): Specifies a header. - """ - - AddTripleOrQuad = "A" - DeleteTripleOrQuad = "D" - AddPrefix = "PA" - DeletePrefix = "PD" - TransactionStart = "TX" - TransactionCommit = "TC" - TransactionAbort = "TA" - Header = "H" - - -class RDFPatchParser(NQuadsParser): - def parse( # type: ignore[override] - self, - inputsource: InputSource, - sink: Dataset, - bnode_context: Optional[_BNodeContextType] = None, - skolemize: bool = False, - **kwargs: Any, - ) -> Dataset: - """ - Parse inputsource as an RDF Patch file. - - :type inputsource: `rdflib.parser.InputSource` - :param inputsource: the source of RDF Patch formatted data - :type sink: `rdflib.graph.Dataset` - :param sink: where to send parsed data - :type bnode_context: `dict`, optional - :param bnode_context: a dict mapping blank node identifiers to `~rdflib.term.BNode` instances. - See `.W3CNTriplesParser.parse` - """ - assert sink.store.context_aware, ( - "RDFPatchParser must be given" " a context aware store." - ) - # type error: Incompatible types in assignment (expression has type "ConjunctiveGraph", base class "W3CNTriplesParser" defined the type as "Union[DummySink, NTGraphSink]") - self.sink: Dataset = Dataset(store=sink.store) - self.skolemize = skolemize - - source = inputsource.getCharacterStream() - if not source: - source = inputsource.getByteStream() - source = getreader("utf-8")(source) - - if not hasattr(source, "read"): - raise ParseError("Item to parse must be a file-like object.") - - self.file = source - self.buffer = "" - while True: - self.line = __line = self.readline() - if self.line is None: - break - try: - self.parsepatch(bnode_context) - except ParseError as msg: - raise ParseError("Invalid line (%s):\n%r" % (msg, __line)) - return self.sink - - def parsepatch(self, bnode_context: Optional[_BNodeContextType] = None) -> None: - self.eat(r_wspace) - # From spec: "No comments should be included (comments start # and run to end - # of line)." - if (not self.line) or self.line.startswith("#"): - return # The line is empty or a comment - - # if header, transaction, skip - operation = self.operation() - self.eat(r_wspace) - - if operation in [Operation.AddTripleOrQuad, Operation.DeleteTripleOrQuad]: - self.add_or_remove_triple_or_quad(operation, bnode_context) - elif operation == Operation.AddPrefix: - self.add_prefix() - elif operation == Operation.DeletePrefix: - self.delete_prefix() - - def add_or_remove_triple_or_quad( - self, operation, bnode_context: Optional[_BNodeContextType] = None - ) -> None: - self.eat(r_wspace) - if (not self.line) or self.line.startswith("#"): - return # The line is empty or a comment - - subject = self.labeled_bnode() or self.subject(bnode_context) - self.eat(r_wspace) - - predicate = self.predicate() - self.eat(r_wspace) - - obj = self.labeled_bnode() or self.object(bnode_context) - self.eat(r_wspace) - - context = self.labeled_bnode() or self.uriref() or self.nodeid(bnode_context) - self.eat(r_tail) - - if self.line: - raise ParseError("Trailing garbage") - # Must have a context aware store - add on a normal Graph - # discards anything where the ctx != graph.identifier - if operation == Operation.AddTripleOrQuad: - if context: - self.sink.get_context(context).add((subject, predicate, obj)) - else: - self.sink.default_context.add((subject, predicate, obj)) - elif operation == Operation.DeleteTripleOrQuad: - if context: - self.sink.get_context(context).remove((subject, predicate, obj)) - else: - self.sink.default_context.remove((subject, predicate, obj)) - - def add_prefix(self): - # Extract prefix and URI from the line - prefix, ns, _ = self.line.replace('"', "").replace("'", "").split(" ") # type: ignore[union-attr] - ns_stripped = ns.strip("<>") - self.sink.bind(prefix, ns_stripped) - - def delete_prefix(self): - prefix, _, _ = self.line.replace('"', "").replace("'", "").split(" ") # type: ignore[union-attr] - self.sink.namespace_manager.bind(prefix, None, replace=True) - - def operation(self) -> Operation: - for op in Operation: - if self.line.startswith(op.value): # type: ignore[union-attr] - self.eat_op(op.value) - return op - raise ValueError( - f'Invalid or no Operation found in line: "{self.line}". Valid Operations ' - f"codes are {', '.join([op.value for op in Operation])}" - ) - - def eat_op(self, op: str) -> None: - self.line = self.line.lstrip(op) # type: ignore[union-attr] - - def nodeid( - self, bnode_context: Optional[_BNodeContextType] = None - ) -> Union[te.Literal[False], BNode, URIRef]: - if self.peek("_"): - return BNode(self.eat(r_nodeid).group(1)) - return False - - def labeled_bnode(self): - if self.peek("<_"): - plain_uri = self.eat(r_uriref).group(1) - bnode_id = r_nodeid.match(plain_uri).group(1) # type: ignore[union-attr] - return BNode(bnode_id) - return False diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/rdfxml.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/rdfxml.py deleted file mode 100644 index e0f6e05..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/rdfxml.py +++ /dev/null @@ -1,651 +0,0 @@ -""" -An RDF/XML parser for RDFLib -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Dict, List, NoReturn, Optional, Tuple -from urllib.parse import urldefrag, urljoin -from xml.sax import handler, make_parser, xmlreader -from xml.sax.handler import ErrorHandler -from xml.sax.saxutils import escape, quoteattr - -from rdflib.exceptions import Error, ParserError -from rdflib.graph import Graph -from rdflib.namespace import RDF, is_ncname -from rdflib.parser import InputSource, Parser -from rdflib.plugins.parsers.RDFVOC import RDFVOC -from rdflib.term import BNode, Identifier, Literal, URIRef - -if TYPE_CHECKING: - # from xml.sax.expatreader import ExpatLocator - from xml.sax.xmlreader import AttributesImpl, Locator - - from rdflib.graph import _ObjectType, _SubjectType, _TripleType - -__all__ = ["create_parser", "BagID", "ElementHandler", "RDFXMLHandler", "RDFXMLParser"] - -RDFNS = RDFVOC - -# http://www.w3.org/TR/rdf-syntax-grammar/#eventterm-attribute-URI -# A mapping from unqualified terms to their qualified version. -UNQUALIFIED = { - "about": RDFVOC.about, - "ID": RDFVOC.ID, - "type": RDFVOC.type, - "resource": RDFVOC.resource, - "parseType": RDFVOC.parseType, -} - -# http://www.w3.org/TR/rdf-syntax-grammar/#coreSyntaxTerms -CORE_SYNTAX_TERMS = [ - RDFVOC.RDF, - RDFVOC.ID, - RDFVOC.about, - RDFVOC.parseType, - RDFVOC.resource, - RDFVOC.nodeID, - RDFVOC.datatype, -] - -# http://www.w3.org/TR/rdf-syntax-grammar/#syntaxTerms -SYNTAX_TERMS = CORE_SYNTAX_TERMS + [RDFVOC.Description, RDFVOC.li] - -# http://www.w3.org/TR/rdf-syntax-grammar/#oldTerms -OLD_TERMS = [ - URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#aboutEach"), - URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#aboutEachPrefix"), - URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#bagID"), -] - -NODE_ELEMENT_EXCEPTIONS = ( - CORE_SYNTAX_TERMS - + [ - RDFVOC.li, - ] - + OLD_TERMS -) -NODE_ELEMENT_ATTRIBUTES = [RDFVOC.ID, RDFVOC.nodeID, RDFVOC.about] - -PROPERTY_ELEMENT_EXCEPTIONS = ( - CORE_SYNTAX_TERMS - + [ - RDFVOC.Description, - ] - + OLD_TERMS -) -PROPERTY_ATTRIBUTE_EXCEPTIONS = ( - CORE_SYNTAX_TERMS + [RDFVOC.Description, RDFVOC.li] + OLD_TERMS -) -PROPERTY_ELEMENT_ATTRIBUTES = [RDFVOC.ID, RDFVOC.resource, RDFVOC.nodeID] - -XMLNS = "http://www.w3.org/XML/1998/namespace" -BASE = (XMLNS, "base") -LANG = (XMLNS, "lang") - - -class BagID(URIRef): - __slots__ = ["li"] - - def __init__(self, val): - # type error: Too many arguments for "__init__" of "object" - super(URIRef, self).__init__(val) # type: ignore[call-arg] - self.li = 0 - - def next_li(self): - self.li += 1 - # type error: Type expected within [...] - return RDFNS["_%s" % self.li] # type: ignore[misc] - - -class ElementHandler: - __slots__ = [ - "start", - "char", - "end", - "li", - "id", - "base", - "subject", - "predicate", - "object", - "list", - "language", - "datatype", - "declared", - "data", - ] - - def __init__(self): - self.start = None - self.char = None - self.end = None - self.li = 0 - self.id = None - self.base = None - self.subject = None - self.object = None - self.list = None - self.language = None - self.datatype = None - self.declared = None - self.data = None - - def next_li(self): - self.li += 1 - return RDFVOC["_%s" % self.li] - - -class RDFXMLHandler(handler.ContentHandler): - def __init__(self, store: Graph): - self.store = store - self.preserve_bnode_ids = False - self.reset() - - def reset(self) -> None: - document_element = ElementHandler() - document_element.start = self.document_element_start - document_element.end = lambda name, qname: None - self.stack: List[Optional[ElementHandler]] = [ - None, - document_element, - ] - self.ids: Dict[str, int] = {} # remember IDs we have already seen - self.bnode: Dict[str, Identifier] = {} - self._ns_contexts: List[Dict[str, Optional[str]]] = [ - {} - ] # contains uri -> prefix dicts - self._current_context: Dict[str, Optional[str]] = self._ns_contexts[-1] - - # ContentHandler methods - - def setDocumentLocator(self, locator: Locator): - self.locator = locator - - def startDocument(self) -> None: - pass - - def startPrefixMapping(self, prefix: Optional[str], namespace: str) -> None: - self._ns_contexts.append(self._current_context.copy()) - self._current_context[namespace] = prefix - self.store.bind(prefix, namespace or "", override=False) - - def endPrefixMapping(self, prefix: Optional[str]) -> None: - self._current_context = self._ns_contexts[-1] - del self._ns_contexts[-1] - - def startElementNS( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl - ) -> None: - stack = self.stack - stack.append(ElementHandler()) - current = self.current - parent = self.parent - # type error: No overlaod for "get" of "AttributesImpl" mactches tuple (str, str) - base = attrs.get(BASE, None) # type: ignore[call-overload, unused-ignore] - if base is not None: - base, frag = urldefrag(base) - if parent and parent.base: - base = urljoin(parent.base, base) - else: - systemId = self.locator.getPublicId() or self.locator.getSystemId() - if systemId: - base = urljoin(systemId, base) - else: - if parent: - base = parent.base - if base is None: - systemId = self.locator.getPublicId() or self.locator.getSystemId() - if systemId: - base, frag = urldefrag(systemId) - current.base = base - # type error: No overlaod for "get" of "AttributesImpl" mactches tuple (str, str) - language = attrs.get(LANG, None) # type: ignore[call-overload, unused-ignore] - if language is None: - if parent: - language = parent.language - current.language = language - current.start(name, qname, attrs) - - def endElementNS(self, name: Tuple[Optional[str], str], qname) -> None: - self.current.end(name, qname) - self.stack.pop() - - def characters(self, content: str) -> None: - char = self.current.char - if char: - char(content) - - def ignorableWhitespace(self, content) -> None: - pass - - def processingInstruction(self, target, data) -> None: - pass - - def add_reified(self, sid: Identifier, spo: _TripleType): - s, p, o = spo - self.store.add((sid, RDF.type, RDF.Statement)) - self.store.add((sid, RDF.subject, s)) - self.store.add((sid, RDF.predicate, p)) - self.store.add((sid, RDF.object, o)) - - def error(self, message: str) -> NoReturn: - locator = self.locator - info = "%s:%s:%s: " % ( - locator.getSystemId(), - locator.getLineNumber(), - locator.getColumnNumber(), - ) - raise ParserError(info + message) - - def get_current(self) -> Optional[ElementHandler]: - return self.stack[-2] - - # Create a read only property called current so that self.current - # give the current element handler. - current = property(get_current) - - def get_next(self) -> Optional[ElementHandler]: - return self.stack[-1] - - # Create a read only property that gives the element handler to be - # used for the next element. - next = property(get_next) - - def get_parent(self) -> Optional[ElementHandler]: - return self.stack[-3] - - # Create a read only property that gives the current parent - # element handler - parent = property(get_parent) - - def absolutize(self, uri: str) -> URIRef: - # type error: Argument "allow_fragments" to "urljoin" has incompatible type "int"; expected "bool" - result = urljoin(self.current.base, uri, allow_fragments=1) # type: ignore[arg-type] - if uri and uri[-1] == "#" and result[-1] != "#": - result = "%s#" % result - return URIRef(result) - - def convert( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl - ) -> Tuple[URIRef, Dict[URIRef, str]]: - if name[0] is None: - # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[Optional[str], str]") - name = URIRef(name[1]) # type: ignore[assignment] - else: - # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[Optional[str], str]") - # type error: Argument 1 to "join" of "str" has incompatible type "Tuple[Optional[str], str]"; expected "Iterable[str]" - name = URIRef("".join(name)) # type: ignore[assignment, arg-type] - atts = {} - for n, v in attrs.items(): - # mypy error: mypy thinks n[0]==None is unreachable - if n[0] is None: - att = n[1] # type: ignore[unreachable, unused-ignore] - else: - att = "".join(n) - if att.startswith(XMLNS) or att[0:3].lower() == "xml": - pass - elif att in UNQUALIFIED: - # if not RDFNS[att] in atts: - # type error: Variable "att" is not valid as a type - atts[RDFNS[att]] = v # type: ignore[misc, valid-type] - else: - atts[URIRef(att)] = v - # type error: Incompatible return value type (got "Tuple[Tuple[Optional[str], str], Dict[Any, Any]]", expected "Tuple[URIRef, Dict[URIRef, str]]") - return name, atts # type: ignore[return-value] - - def document_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl - ) -> None: - if name[0] and URIRef("".join(name)) == RDFVOC.RDF: - next = self.next - next.start = self.node_element_start - next.end = self.node_element_end - else: - self.node_element_start(name, qname, attrs) - # self.current.end = self.node_element_end - # TODO... set end to something that sets start such that - # another element will cause error - - def node_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl - ) -> None: - # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[str, str]") - name, atts = self.convert(name, qname, attrs) # type: ignore[assignment] - current = self.current - absolutize = self.absolutize - - next = self.next - next.start = self.property_element_start - next.end = self.property_element_end - - if name in NODE_ELEMENT_EXCEPTIONS: - # type error: Not all arguments converted during string formatting - self.error("Invalid node element URI: %s" % name) # type: ignore[str-format] - subject: _SubjectType - if RDFVOC.ID in atts: - if RDFVOC.about in atts or RDFVOC.nodeID in atts: - self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID") - - id = atts[RDFVOC.ID] - if not is_ncname(id): - self.error("rdf:ID value is not a valid NCName: %s" % id) - subject = absolutize("#%s" % id) - if subject in self.ids: - self.error("two elements cannot use the same ID: '%s'" % subject) - self.ids[subject] = 1 # IDs can only appear once within a document - elif RDFVOC.nodeID in atts: - if RDFVOC.ID in atts or RDFVOC.about in atts: - self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID") - nodeID = atts[RDFVOC.nodeID] - if not is_ncname(nodeID): - self.error("rdf:nodeID value is not a valid NCName: %s" % nodeID) - if self.preserve_bnode_ids is False: - if nodeID in self.bnode: - subject = self.bnode[nodeID] - else: - subject = BNode() - self.bnode[nodeID] = subject - else: - subject = BNode(nodeID) - elif RDFVOC.about in atts: - if RDFVOC.ID in atts or RDFVOC.nodeID in atts: - self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID") - subject = absolutize(atts[RDFVOC.about]) - else: - subject = BNode() - - if name != RDFVOC.Description: # S1 - # error: Argument 1 has incompatible type "Tuple[str, str]"; expected "str" - self.store.add((subject, RDF.type, absolutize(name))) # type: ignore[arg-type] - - object: _ObjectType - language = current.language - for att in atts: - if not att.startswith(str(RDFNS)): - predicate = absolutize(att) - try: - object = Literal(atts[att], language) - except Error as e: - # type error: Argument 1 to "error" of "RDFXMLHandler" has incompatible type "Optional[str]"; expected "str" - self.error(e.msg) # type: ignore[arg-type] - elif att == RDF.type: # S2 - predicate = RDF.type - object = absolutize(atts[RDF.type]) - elif att in NODE_ELEMENT_ATTRIBUTES: - continue - elif att in PROPERTY_ATTRIBUTE_EXCEPTIONS: # S3 - self.error("Invalid property attribute URI: %s" % att) - # type error: Statement is unreachable - continue # type: ignore[unreachable] # for when error does not throw an exception - else: - predicate = absolutize(att) - try: - object = Literal(atts[att], language) - except Error as e: - # type error: Argument 1 to "error" of "RDFXMLHandler" has incompatible type "Optional[str]"; expected "str" - self.error(e.msg) # type: ignore[arg-type] - self.store.add((subject, predicate, object)) - - current.subject = subject - - def node_element_end(self, name: Tuple[str, str], qname) -> None: - # repeat node-elements are only allowed - # at at top-level - - if self.parent.object and self.current != self.stack[2]: - self.error( - "Repeat node-elements inside property elements: %s" % "".join(name) - ) - - self.parent.object = self.current.subject - - def property_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl - ) -> None: - # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[str, str]") - name, atts = self.convert(name, qname, attrs) # type: ignore[assignment] - current = self.current - absolutize = self.absolutize - - next = self.next - object: Optional[_ObjectType] = None - current.data = None - current.list = None - - # type error: "Tuple[str, str]" has no attribute "startswith" - if not name.startswith(str(RDFNS)): # type: ignore[attr-defined] - # type error: Argument 1 has incompatible type "Tuple[str, str]"; expected "str" - current.predicate = absolutize(name) # type: ignore[arg-type] - elif name == RDFVOC.li: - current.predicate = current.next_li() - elif name in PROPERTY_ELEMENT_EXCEPTIONS: - # type error: Not all arguments converted during string formatting - self.error("Invalid property element URI: %s" % name) # type: ignore[str-format] - else: - # type error: Argument 1 has incompatible type "Tuple[str, str]"; expected "str" - current.predicate = absolutize(name) # type: ignore[arg-type] - - id = atts.get(RDFVOC.ID, None) - if id is not None: - if not is_ncname(id): - self.error("rdf:ID value is not a value NCName: %s" % id) - current.id = absolutize("#%s" % id) - else: - current.id = None - - resource = atts.get(RDFVOC.resource, None) - nodeID = atts.get(RDFVOC.nodeID, None) - parse_type = atts.get(RDFVOC.parseType, None) - if resource is not None and nodeID is not None: - self.error("Property element cannot have both rdf:nodeID and rdf:resource") - if resource is not None: - object = absolutize(resource) - next.start = self.node_element_start - next.end = self.node_element_end - elif nodeID is not None: - if not is_ncname(nodeID): - self.error("rdf:nodeID value is not a valid NCName: %s" % nodeID) - if self.preserve_bnode_ids is False: - if nodeID in self.bnode: - object = self.bnode[nodeID] - else: - subject = BNode() - self.bnode[nodeID] = subject - object = subject - else: - object = subject = BNode(nodeID) - next.start = self.node_element_start - next.end = self.node_element_end - else: - if parse_type is not None: - for att in atts: - if att != RDFVOC.parseType and att != RDFVOC.ID: - self.error("Property attr '%s' now allowed here" % att) - if parse_type == "Resource": - current.subject = object = BNode() - current.char = self.property_element_char - next.start = self.property_element_start - next.end = self.property_element_end - elif parse_type == "Collection": - current.char = None - object = current.list = RDF.nil # BNode() - # self.parent.subject - next.start = self.node_element_start - next.end = self.list_node_element_end - else: # if parse_type=="Literal": - # All other values are treated as Literal - # See: http://www.w3.org/TR/rdf-syntax-grammar/ - # parseTypeOtherPropertyElt - object = Literal("", datatype=RDFVOC.XMLLiteral) - current.char = self.literal_element_char - current.declared = {XMLNS: "xml"} - next.start = self.literal_element_start - next.char = self.literal_element_char - next.end = self.literal_element_end - current.object = object - return - else: - object = None - current.char = self.property_element_char - next.start = self.node_element_start - next.end = self.node_element_end - - datatype = current.datatype = atts.get(RDFVOC.datatype, None) - language = current.language - if datatype is not None: - # TODO: check that there are no atts other than datatype and id - datatype = absolutize(datatype) - else: - for att in atts: - if not att.startswith(str(RDFNS)): - predicate = absolutize(att) - elif att in PROPERTY_ELEMENT_ATTRIBUTES: - continue - elif att in PROPERTY_ATTRIBUTE_EXCEPTIONS: - self.error("""Invalid property attribute URI: %s""" % att) - else: - predicate = absolutize(att) - o: _ObjectType - if att == RDF.type: - o = URIRef(atts[att]) - else: - if datatype is not None: - # type error: Statement is unreachable - language = None # type: ignore[unreachable] - o = Literal(atts[att], language, datatype) - - if object is None: - object = BNode() - self.store.add((object, predicate, o)) - if object is None: - current.data = "" - current.object = None - else: - current.data = None - current.object = object - - def property_element_char(self, data: str) -> None: - current = self.current - if current.data is not None: - current.data += data - - def property_element_end(self, name: Tuple[str, str], qname) -> None: - current = self.current - if current.data is not None and current.object is None: - literalLang = current.language - if current.datatype is not None: - literalLang = None - current.object = Literal(current.data, literalLang, current.datatype) - current.data = None - if self.next.end == self.list_node_element_end: - if current.object != RDF.nil: - self.store.add((current.list, RDF.rest, RDF.nil)) - if current.object is not None: - self.store.add((self.parent.subject, current.predicate, current.object)) - if current.id is not None: - self.add_reified( - current.id, (self.parent.subject, current.predicate, current.object) - ) - current.subject = None - - def list_node_element_end(self, name: Tuple[str, str], qname) -> None: - current = self.current - if self.parent.list == RDF.nil: - list = BNode() - # Removed between 20030123 and 20030905 - # self.store.add((list, RDF.type, LIST)) - self.parent.list = list - self.store.add((self.parent.list, RDF.first, current.subject)) - self.parent.object = list - self.parent.char = None - else: - list = BNode() - # Removed between 20030123 and 20030905 - # self.store.add((list, RDF.type, LIST)) - self.store.add((self.parent.list, RDF.rest, list)) - self.store.add((list, RDF.first, current.subject)) - self.parent.list = list - - def literal_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl - ) -> None: - current = self.current - self.next.start = self.literal_element_start - self.next.char = self.literal_element_char - self.next.end = self.literal_element_end - current.declared = self.parent.declared.copy() - if name[0]: - prefix = self._current_context[name[0]] - if prefix: - current.object = "<%s:%s" % (prefix, name[1]) - else: - current.object = "<%s" % name[1] - if not name[0] in current.declared: # noqa: E713 - current.declared[name[0]] = prefix - if prefix: - current.object += ' xmlns:%s="%s"' % (prefix, name[0]) - else: - current.object += ' xmlns="%s"' % name[0] - else: - current.object = "<%s" % name[1] - # type error: Incompatible types in assignment (expression has type "str", variable has type "Tuple[str, str]") - for name, value in attrs.items(): # type: ignore[assignment, unused-ignore] - if name[0]: - if not name[0] in current.declared: # noqa: E713 - current.declared[name[0]] = self._current_context[name[0]] - name = current.declared[name[0]] + ":" + name[1] - else: - # type error: Incompatible types in assignment (expression has type "str", variable has type "Tuple[str, str]") - name = name[1] # type: ignore[assignment] - current.object += " %s=%s" % (name, quoteattr(value)) - current.object += ">" - - def literal_element_char(self, data: str) -> None: - self.current.object += escape(data) - - def literal_element_end(self, name: Tuple[str, str], qname) -> None: - if name[0]: - prefix = self._current_context[name[0]] - if prefix: - end = "" % (prefix, name[1]) - else: - end = "" % name[1] - else: - end = "" % name[1] - self.parent.object += self.current.object + end - - -def create_parser(target: InputSource, store: Graph) -> xmlreader.XMLReader: - parser = make_parser() - try: - # Workaround for bug in expatreader.py. Needed when - # expatreader is trying to guess a prefix. - parser.start_namespace_decl("xml", "http://www.w3.org/XML/1998/namespace") # type: ignore[attr-defined] - except AttributeError: - pass # Not present in Jython (at least) - parser.setFeature(handler.feature_namespaces, 1) - rdfxml = RDFXMLHandler(store) - # type error: Argument 1 to "setDocumentLocator" of "RDFXMLHandler" has incompatible type "InputSource"; expected "Locator" - rdfxml.setDocumentLocator(target) # type: ignore[arg-type] - # rdfxml.setDocumentLocator(_Locator(self.url, self.parser)) - parser.setContentHandler(rdfxml) - parser.setErrorHandler(ErrorHandler()) - return parser - - -class RDFXMLParser(Parser): - def __init__(self): - pass - - def parse(self, source: InputSource, sink: Graph, **args: Any) -> None: - self._parser = create_parser(source, sink) - content_handler = self._parser.getContentHandler() - preserve_bnode_ids = args.get("preserve_bnode_ids", None) - if preserve_bnode_ids is not None: - # type error: ContentHandler has no attribute "preserve_bnode_ids" - content_handler.preserve_bnode_ids = preserve_bnode_ids # type: ignore[attr-defined, unused-ignore] - # # We're only using it once now - # content_handler.reset() - # self._parser.reset() - self._parser.parse(source) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trig.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trig.py deleted file mode 100644 index 9ed6e8b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trig.py +++ /dev/null @@ -1,177 +0,0 @@ -from __future__ import annotations - -from typing import Any, MutableSequence - -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.parser import InputSource, Parser - -from .notation3 import RDFSink, SinkParser - - -def becauseSubGraph(*args, **kwargs): # noqa: N802 - pass - - -class TrigSinkParser(SinkParser): - def directiveOrStatement(self, argstr: str, h: int) -> int: # noqa: N802 - # import pdb; pdb.set_trace() - - i = self.skipSpace(argstr, h) - if i < 0: - return i # EOF - - j = self.graph(argstr, i) - if j >= 0: - return j - - j = self.sparqlDirective(argstr, i) - if j >= 0: - return j - - j = self.directive(argstr, i) - if j >= 0: - return self.checkDot(argstr, j) - - j = self.statement(argstr, i) - if j >= 0: - return self.checkDot(argstr, j) - - return j - - def labelOrSubject( # noqa: N802 - self, argstr: str, i: int, res: MutableSequence[Any] - ) -> int: - j = self.skipSpace(argstr, i) - if j < 0: - return j # eof - i = j - - j = self.uri_ref2(argstr, i, res) - if j >= 0: - return j - - if argstr[i] == "[": - j = self.skipSpace(argstr, i + 1) - if j < 0: - self.BadSyntax(argstr, i, "Expected ] got EOF") - if argstr[j] == "]": - res.append(self.blankNode()) - return j + 1 - return -1 - - def graph(self, argstr: str, i: int) -> int: - """ - Parse trig graph, i.e. - - = { .. triples .. } - - return -1 if it doesn't look like a graph-decl - raise Exception if it looks like a graph, but isn't. - """ - - need_graphid = False - # import pdb; pdb.set_trace() - j = self.sparqlTok("GRAPH", argstr, i) # optional GRAPH keyword - if j >= 0: - i = j - need_graphid = True - - r: MutableSequence[Any] = [] - j = self.labelOrSubject(argstr, i, r) - if j >= 0: - graph = r[0] - i = j - elif need_graphid: - self.BadSyntax(argstr, i, "GRAPH keyword must be followed by graph name") - else: - graph = self._store.graph.identifier # hack - - j = self.skipSpace(argstr, i) - if j < 0: - self.BadSyntax(argstr, i, "EOF found when expected graph") - - if argstr[j : j + 1] == "=": # optional = for legacy support - i = self.skipSpace(argstr, j + 1) - if i < 0: - self.BadSyntax(argstr, i, "EOF found when expecting '{'") - else: - i = j - - if argstr[i : i + 1] != "{": - return -1 # the node wasn't part of a graph - - j = i + 1 - - if self._context is not None: - self.BadSyntax(argstr, i, "Nested graphs are not allowed") - - oldParentContext = self._parentContext # noqa: N806 - self._parentContext = self._context - reason2 = self._reason2 - self._reason2 = becauseSubGraph - # type error: Incompatible types in assignment (expression has type "Graph", variable has type "Optional[Formula]") - self._context = self._store.newGraph(graph) # type: ignore[assignment] - - while 1: - i = self.skipSpace(argstr, j) - if i < 0: - self.BadSyntax(argstr, i, "needed '}', found end.") - - if argstr[i : i + 1] == "}": - j = i + 1 - break - - j = self.directiveOrStatement(argstr, i) - if j < 0: - self.BadSyntax(argstr, i, "expected statement or '}'") - - self._context = self._parentContext - self._reason2 = reason2 - self._parentContext = oldParentContext - # res.append(subj.close()) # No use until closed - return j - - -class TrigParser(Parser): - """ - An RDFLib parser for TriG - - """ - - def __init__(self): - pass - - def parse(self, source: InputSource, graph: Graph, encoding: str = "utf-8") -> None: - if encoding not in [None, "utf-8"]: - raise Exception( - # type error: Unsupported left operand type for % ("Tuple[str, str]") - ("TriG files are always utf-8 encoded, ", "I was passed: %s") # type: ignore[operator] - % encoding - ) - - # we're currently being handed a Graph, not a ConjunctiveGraph - assert graph.store.context_aware, "TriG Parser needs a context-aware store!" - - conj_graph = ConjunctiveGraph(store=graph.store, identifier=graph.identifier) - conj_graph.default_context = graph # TODO: CG __init__ should have a - # default_context arg - # TODO: update N3Processor so that it can use conj_graph as the sink - conj_graph.namespace_manager = graph.namespace_manager - - sink = RDFSink(conj_graph) - - baseURI = conj_graph.absolutize( # noqa: N806 - source.getPublicId() or source.getSystemId() or "" - ) - p = TrigSinkParser(sink, baseURI=baseURI, turtle=True) - - stream = source.getCharacterStream() # try to get str stream first - if not stream: - # fallback to get the bytes stream - stream = source.getByteStream() - p.loadStream(stream) - - for prefix, namespace in p._bindings.items(): - conj_graph.bind(prefix, namespace) - - # return ??? diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trix.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trix.py deleted file mode 100644 index 833e185..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/parsers/trix.py +++ /dev/null @@ -1,296 +0,0 @@ -""" -A TriX parser for RDFLib -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Dict, List, NoReturn, Optional, Tuple -from xml.sax import handler, make_parser -from xml.sax.handler import ErrorHandler - -from rdflib.exceptions import ParserError -from rdflib.graph import Graph -from rdflib.namespace import Namespace -from rdflib.parser import InputSource, Parser -from rdflib.store import Store -from rdflib.term import BNode, Identifier, Literal, URIRef - -if TYPE_CHECKING: - # from xml.sax.expatreader import ExpatLocator - from xml.sax.xmlreader import AttributesImpl, Locator, XMLReader - -__all__ = ["create_parser", "TriXHandler", "TriXParser"] - - -TRIXNS = Namespace("http://www.w3.org/2004/03/trix/trix-1/") -XMLNS = Namespace("http://www.w3.org/XML/1998/namespace") - - -class TriXHandler(handler.ContentHandler): - """An Sax Handler for TriX. See http://sw.nokia.com/trix/""" - - lang: Optional[str] - datatype: Optional[str] - - def __init__(self, store: Store): - self.store = store - self.preserve_bnode_ids = False - self.reset() - - def reset(self) -> None: - self.bnode: Dict[str, BNode] = {} - self.graph: Optional[Graph] = None - self.triple: Optional[List[Identifier]] = None - self.state = 0 - self.lang = None - self.datatype = None - - # ContentHandler methods - - def setDocumentLocator(self, locator: Locator): - self.locator = locator - - def startDocument(self) -> None: - pass - - def startPrefixMapping(self, prefix: Optional[str], namespace: str) -> None: - pass - - def endPrefixMapping(self, prefix: Optional[str]) -> None: - pass - - def startElementNS( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl - ) -> None: - if name[0] != str(TRIXNS): - self.error( - "Only elements in the TriX namespace are allowed. %s!=%s" - % (name[0], TRIXNS) - ) - - if name[1].lower() == "trix": - if self.state == 0: - self.state = 1 - else: - self.error("Unexpected TriX element") - - elif name[1] == "graph": - if self.state == 1: - self.state = 2 - else: - self.error("Unexpected graph element") - - elif name[1] == "uri": - if self.state == 2: - # the context uri - self.state = 3 - elif self.state == 4: - # part of a triple - pass - else: - self.error("Unexpected uri element") - - elif name[1] == "triple": - if self.state == 2: - if self.graph is None: - # anonymous graph, create one with random bnode id - self.graph = Graph(store=self.store) - # start of a triple - self.triple = [] - self.state = 4 - else: - self.error("Unexpected triple element") - - elif name[1] == "typedLiteral": - if self.state == 4: - # part of triple - self.lang = None - self.datatype = None - - try: - self.lang = attrs.getValue((str(XMLNS), "lang")) # type: ignore[arg-type, unused-ignore] - except Exception: - # language not required - ignore - pass - try: - self.datatype = attrs.getValueByQName("datatype") # type: ignore[arg-type, unused-ignore] - except KeyError: - self.error("No required attribute 'datatype'") - else: - self.error("Unexpected typedLiteral element") - - elif name[1] == "plainLiteral": - if self.state == 4: - # part of triple - self.lang = None - self.datatype = None - try: - # type error: Argument 1 to "getValue" of "AttributesImpl" has incompatible type "Tuple[str, str]"; expected "str" - self.lang = attrs.getValue((str(XMLNS), "lang")) # type: ignore[arg-type, unused-ignore] - except Exception: - # language not required - ignore - pass - - else: - self.error("Unexpected plainLiteral element") - - elif name[1] == "id": - if self.state == 2: - # the context uri - self.state = 3 - - elif self.state == 4: - # part of triple - pass - else: - self.error("Unexpected id element") - - else: - self.error("Unknown element %s in TriX namespace" % name[1]) - - self.chars = "" - - def endElementNS(self, name: Tuple[Optional[str], str], qname) -> None: - if TYPE_CHECKING: - assert self.triple is not None - if name[0] != str(TRIXNS): - self.error( - "Only elements in the TriX namespace are allowed. %s!=%s" - % (name[0], TRIXNS) - ) - - if name[1] == "uri": - if self.state == 3: - self.graph = Graph( - store=self.store, identifier=URIRef(self.chars.strip()) - ) - self.state = 2 - elif self.state == 4: - self.triple += [URIRef(self.chars.strip())] - else: - self.error( - "Illegal internal self.state - This should never " - + "happen if the SAX parser ensures XML syntax correctness" - ) - - elif name[1] == "id": - if self.state == 3: - self.graph = Graph( - self.store, identifier=self.get_bnode(self.chars.strip()) - ) - self.state = 2 - elif self.state == 4: - self.triple += [self.get_bnode(self.chars.strip())] - else: - self.error( - "Illegal internal self.state - This should never " - + "happen if the SAX parser ensures XML syntax correctness" - ) - - elif name[1] == "plainLiteral" or name[1] == "typedLiteral": - if self.state == 4: - self.triple += [ - Literal(self.chars, lang=self.lang, datatype=self.datatype) - ] - else: - self.error( - "This should never happen if the SAX parser " - + "ensures XML syntax correctness" - ) - - elif name[1] == "triple": - if self.state == 4: - if len(self.triple) != 3: - self.error( - "Triple has wrong length, got %d elements: %s" - % (len(self.triple), self.triple) - ) - # type error: Item "None" of "Optional[Graph]" has no attribute "add" - # type error: Argument 1 to "add" of "Graph" has incompatible type "List[Identifier]"; expected "Tuple[Node, Node, Node]" - self.graph.add(self.triple) # type: ignore[union-attr, arg-type] - # self.store.store.add(self.triple,context=self.graph) - # self.store.addN([self.triple+[self.graph]]) - self.state = 2 - else: - self.error( - "This should never happen if the SAX parser " - + "ensures XML syntax correctness" - ) - - elif name[1] == "graph": - self.graph = None - self.state = 1 - - elif name[1].lower() == "trix": - self.state = 0 - - else: - self.error("Unexpected close element") - - def get_bnode(self, label: str) -> BNode: - if self.preserve_bnode_ids: - bn = BNode(label) - else: - if label in self.bnode: - bn = self.bnode[label] - else: - bn = BNode(label) - self.bnode[label] = bn - return bn - - def characters(self, content: str) -> None: - self.chars += content - - def ignorableWhitespace(self, content) -> None: - pass - - def processingInstruction(self, target, data) -> None: - pass - - def error(self, message: str) -> NoReturn: - locator = self.locator - info = "%s:%s:%s: " % ( - locator.getSystemId(), - locator.getLineNumber(), - locator.getColumnNumber(), - ) - raise ParserError(info + message) - - -def create_parser(store: Store) -> XMLReader: - parser = make_parser() - try: - # Workaround for bug in expatreader.py. Needed when - # expatreader is trying to guess a prefix. - # type error: "XMLReader" has no attribute "start_namespace_decl" - parser.start_namespace_decl("xml", "http://www.w3.org/XML/1998/namespace") # type: ignore[attr-defined] - except AttributeError: - pass # Not present in Jython (at least) - parser.setFeature(handler.feature_namespaces, 1) - trix = TriXHandler(store) - parser.setContentHandler(trix) - parser.setErrorHandler(ErrorHandler()) - return parser - - -class TriXParser(Parser): - """A parser for TriX. See http://sw.nokia.com/trix/""" - - def __init__(self): - pass - - def parse(self, source: InputSource, sink: Graph, **args: Any) -> None: - assert ( - sink.store.context_aware - ), "TriXParser must be given a context aware store." - - self._parser = create_parser(sink.store) - content_handler = self._parser.getContentHandler() - preserve_bnode_ids = args.get("preserve_bnode_ids", None) - if preserve_bnode_ids is not None: - # type error: ContentHandler has no attribute "preserve_bnode_ids" - content_handler.preserve_bnode_ids = preserve_bnode_ids # type: ignore[attr-defined, unused-ignore] - # We're only using it once now - # content_handler.reset() - # self._parser.reset() - self._parser.parse(source) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/hext.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/hext.py deleted file mode 100644 index 898308a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/hext.py +++ /dev/null @@ -1,207 +0,0 @@ -""" -HextuplesSerializer RDF graph serializer for RDFLib. -See for details about the format. -""" - -from __future__ import annotations - -import json -import warnings -from typing import IO, Any, Callable, List, Optional, Type, Union, cast - -from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, ConjunctiveGraph, Dataset, Graph -from rdflib.namespace import RDF, XSD -from rdflib.serializer import Serializer -from rdflib.term import BNode, IdentifiedNode, Literal, URIRef - -try: - import orjson - - _HAS_ORJSON = True -except ImportError: - orjson = None # type: ignore[assignment, unused-ignore] - _HAS_ORJSON = False - -__all__ = ["HextuplesSerializer"] - - -class HextuplesSerializer(Serializer): - """ - Serializes RDF graphs to NTriples format. - """ - - contexts: List[Union[Graph, IdentifiedNode]] - dumps: Callable - - def __new__(cls, store: Union[Graph, Dataset, ConjunctiveGraph]): - if _HAS_ORJSON: - cls.str_local_id: Union[str, Any] = orjson.Fragment(b'"localId"') - cls.str_global_id: Union[str, Any] = orjson.Fragment(b'"globalId"') - cls.empty: Union[str, Any] = orjson.Fragment(b'""') - cls.lang_str: Union[str, Any] = orjson.Fragment( - b'"' + RDF.langString.encode("utf-8") + b'"' - ) - cls.xsd_string: Union[str, Any] = orjson.Fragment( - b'"' + XSD.string.encode("utf-8") + b'"' - ) - else: - cls.str_local_id = "localId" - cls.str_global_id = "globalId" - cls.empty = "" - cls.lang_str = f"{RDF.langString}" - cls.xsd_string = f"{XSD.string}" - return super(cls, cls).__new__(cls) - - def __init__(self, store: Union[Graph, Dataset, ConjunctiveGraph]): - self.default_context: Optional[Union[Graph, IdentifiedNode]] - self.graph_type: Union[Type[Graph], Type[Dataset], Type[ConjunctiveGraph]] - if isinstance(store, (Dataset, ConjunctiveGraph)): - self.graph_type = ( - Dataset if isinstance(store, Dataset) else ConjunctiveGraph - ) - self.contexts = list(store.contexts()) - if store.default_context: - self.default_context = store.default_context - self.contexts.append(store.default_context) - else: - self.default_context = None - else: - self.graph_type = Graph - self.contexts = [store] - self.default_context = None - - Serializer.__init__(self, store) - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = "utf-8", - **kwargs: Any, - ) -> None: - if base is not None: - warnings.warn( - "base has no meaning for Hextuples serialization. " - "I will ignore this value" - ) - - if encoding not in [None, "utf-8"]: - warnings.warn( - f"Hextuples files are always utf-8 encoded. " - f"I was passed: {encoding}, " - "but I'm still going to use utf-8 anyway!" - ) - - if self.store.formula_aware is True: - raise Exception( - "Hextuple serialization can't (yet) handle formula-aware stores" - ) - context: Union[Graph, IdentifiedNode] - context_str: Union[bytes, str] - for context in self.contexts: - for triple in context: - # Generate context string just once, because it doesn't change - # for every triple in this context - context_str = cast( - Union[str, bytes], - ( - self.empty - if self.graph_type is Graph - else ( - orjson.Fragment('"' + self._context_str(context) + '"') - if _HAS_ORJSON - else self._context_str(context) - ) - ), - ) - hl = self._hex_line(triple, context_str) - if hl is not None: - stream.write(hl if _HAS_ORJSON else hl.encode()) - - def _hex_line(self, triple, context_str: Union[bytes, str]): - if isinstance( - triple[0], (URIRef, BNode) - ): # exclude QuotedGraph and other objects - # value - value = ( - triple[2] - if isinstance(triple[2], Literal) - else self._iri_or_bn(triple[2]) - ) - - # datatype - if isinstance(triple[2], URIRef): - # datatype = "http://www.w3.org/1999/02/22-rdf-syntax-ns#namedNode" - datatype = self.str_global_id - elif isinstance(triple[2], BNode): - # datatype = "http://www.w3.org/1999/02/22-rdf-syntax-ns#blankNode" - datatype = self.str_local_id - elif isinstance(triple[2], Literal): - if triple[2].datatype is not None: - datatype = f"{triple[2].datatype}" - else: - if triple[2].language is not None: # language - datatype = self.lang_str - else: - datatype = self.xsd_string - else: - return None # can't handle non URI, BN or Literal Object (QuotedGraph) - - # language - if isinstance(triple[2], Literal): - if triple[2].language is not None: - language = f"{triple[2].language}" - else: - language = self.empty - else: - language = self.empty - line_list = [ - self._iri_or_bn(triple[0]), - triple[1], - value, - datatype, - language, - context_str, - ] - outline: Union[str, bytes] - if _HAS_ORJSON: - outline = orjson.dumps(line_list, option=orjson.OPT_APPEND_NEWLINE) - else: - outline = json.dumps(line_list) + "\n" - return outline - else: # do not return anything for non-IRIs or BNs, e.g. QuotedGraph, Subjects - return None - - def _iri_or_bn(self, i_): - if isinstance(i_, URIRef): - return f"{i_}" - elif isinstance(i_, BNode): - return f"{i_.n3()}" - else: - return None - - def _context_str(self, context: Union[Graph, IdentifiedNode]) -> str: - context_identifier: IdentifiedNode = ( - context.identifier if isinstance(context, Graph) else context - ) - if context_identifier == DATASET_DEFAULT_GRAPH_ID: - return "" - if self.default_context is not None: - if ( - isinstance(self.default_context, IdentifiedNode) - and context_identifier == self.default_context - ): - return "" - elif ( - isinstance(self.default_context, Graph) - and context_identifier == self.default_context.identifier - ): - return "" - if self.graph_type is Graph: - # Only emit a context name when serializing a Dataset or ConjunctiveGraph - return "" - return ( - f"{context_identifier}" - if isinstance(context_identifier, URIRef) - else context_identifier.n3() - ) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/jsonld.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/jsonld.py deleted file mode 100644 index 0afe830..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/jsonld.py +++ /dev/null @@ -1,433 +0,0 @@ -""" -This serialiser will output an RDF Graph as a JSON-LD formatted document. See: - - http://json-ld.org/ - -Example usage:: - - >>> from rdflib import Graph - >>> testrdf = ''' - ... @prefix dc: . - ... - ... dc:title "Someone's Homepage"@en . - ... ''' - - >>> g = Graph().parse(data=testrdf, format='n3') - - >>> print(g.serialize(format='json-ld', indent=2)) - [ - { - "@id": "http://example.org/about", - "http://purl.org/dc/terms/title": [ - { - "@language": "en", - "@value": "Someone's Homepage" - } - ] - } - ] - -""" - -# From: https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/serializer.py - -# NOTE: This code writes the entire JSON object into memory before serialising, -# but we should consider streaming the output to deal with arbitrarily large -# graphs. - -from __future__ import annotations - -import warnings -from typing import IO, Any, Dict, List, Optional - -from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, Graph, _ObjectType -from rdflib.namespace import RDF, XSD -from rdflib.serializer import Serializer -from rdflib.term import BNode, IdentifiedNode, Identifier, Literal, URIRef - -from ..shared.jsonld.context import UNDEF, Context -from ..shared.jsonld.keys import CONTEXT, GRAPH, ID, LANG, LIST, SET, VOCAB -from ..shared.jsonld.util import _HAS_ORJSON, json, orjson - -__all__ = ["JsonLDSerializer", "from_rdf"] - - -PLAIN_LITERAL_TYPES = {XSD.boolean, XSD.integer, XSD.double, XSD.string} - - -class JsonLDSerializer(Serializer): - def __init__(self, store: Graph): - super(JsonLDSerializer, self).__init__(store) - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - # TODO: docstring w. args and return value - encoding = encoding or "utf-8" - if encoding not in ("utf-8", "utf-16"): - warnings.warn( - "JSON should be encoded as unicode. " f"Given encoding was: {encoding}" - ) - - context_data = kwargs.get("context") - use_native_types = (kwargs.get("use_native_types", False),) - use_rdf_type = kwargs.get("use_rdf_type", False) - auto_compact = kwargs.get("auto_compact", False) - - indent = kwargs.get("indent", 2) - separators = kwargs.get("separators", (",", ": ")) - sort_keys = kwargs.get("sort_keys", True) - ensure_ascii = kwargs.get("ensure_ascii", False) - - obj = from_rdf( - self.store, - context_data, - base, - use_native_types, - use_rdf_type, - auto_compact=auto_compact, - ) - if _HAS_ORJSON: - option: int = orjson.OPT_NON_STR_KEYS - if indent is not None: - option |= orjson.OPT_INDENT_2 - if sort_keys: - option |= orjson.OPT_SORT_KEYS - if ensure_ascii: - warnings.warn("Cannot use ensure_ascii with orjson") - data_bytes = orjson.dumps(obj, option=option) - stream.write(data_bytes) - else: - data = json.dumps( - obj, - indent=indent, - separators=separators, - sort_keys=sort_keys, - ensure_ascii=ensure_ascii, - ) - stream.write(data.encode(encoding, "replace")) - - -def from_rdf( - graph, - context_data=None, - base=None, - use_native_types=False, - use_rdf_type=False, - auto_compact=False, - startnode=None, - index=False, -): - # TODO: docstring w. args and return value - # TODO: support for index and startnode - - if not context_data and auto_compact: - context_data = dict( - (pfx, str(ns)) - for (pfx, ns) in graph.namespaces() - if pfx and str(ns) != "http://www.w3.org/XML/1998/namespace" - ) - - if isinstance(context_data, Context): - context = context_data - context_data = context.to_dict() - else: - context = Context(context_data, base=base) - - converter = Converter(context, use_native_types, use_rdf_type) - result = converter.convert(graph) - - if converter.context.active: - if isinstance(result, list): - result = {context.get_key(GRAPH): result} - result[CONTEXT] = context_data - - return result - - -class Converter: - def __init__(self, context: Context, use_native_types: bool, use_rdf_type: bool): - self.context = context - self.use_native_types = context.active or use_native_types - self.use_rdf_type = use_rdf_type - - def convert(self, graph: Graph): - # TODO: bug in rdflib dataset parsing (nquads et al): - # plain triples end up in separate unnamed graphs (rdflib issue #436) - if graph.context_aware: - # type error: "Graph" has no attribute "contexts" - all_contexts = list(graph.contexts()) # type: ignore[attr-defined] - has_dataset_default_id = any( - c.identifier == DATASET_DEFAULT_GRAPH_ID for c in all_contexts - ) - if ( - has_dataset_default_id - # # type error: "Graph" has no attribute "contexts" - and graph.default_context.identifier == DATASET_DEFAULT_GRAPH_ID # type: ignore[attr-defined] - ): - default_graph = graph.default_context # type: ignore[attr-defined] - else: - default_graph = Graph() - graphs = [default_graph] - default_graph_id = default_graph.identifier - - for g in all_contexts: - if g in graphs: - continue - if isinstance(g.identifier, URIRef): - graphs.append(g) - else: - default_graph += g - else: - graphs = [graph] - default_graph_id = graph.identifier - - context = self.context - - objs: List[Any] = [] - for g in graphs: - obj = {} - graphname = None - - if isinstance(g.identifier, URIRef): - if g.identifier != default_graph_id: - graphname = context.shrink_iri(g.identifier) - obj[context.id_key] = graphname - - nodes = self.from_graph(g) - - if not graphname and len(nodes) == 1: - obj.update(nodes[0]) - else: - if not nodes: - continue - obj[context.graph_key] = nodes - - if objs and objs[0].get(context.get_key(ID)) == graphname: - objs[0].update(obj) - else: - objs.append(obj) - - if len(graphs) == 1 and len(objs) == 1 and not self.context.active: - default = objs[0] - items = default.get(context.graph_key) - if len(default) == 1 and items: - objs = items - elif len(objs) == 1 and self.context.active: - objs = objs[0] - - return objs - - def from_graph(self, graph: Graph): - nodemap: Dict[Any, Any] = {} - - for s in set(graph.subjects()): - ## only iri:s and unreferenced (rest will be promoted to top if needed) - if isinstance(s, URIRef) or ( - isinstance(s, BNode) and not any(graph.subjects(None, s)) - ): - self.process_subject(graph, s, nodemap) - - return list(nodemap.values()) - - def process_subject(self, graph: Graph, s: IdentifiedNode, nodemap): - if isinstance(s, URIRef): - node_id = self.context.shrink_iri(s) - elif isinstance(s, BNode): - node_id = s.n3() - else: - # This does not seem right, this probably should be an error. - node_id = None - - # used_as_object = any(graph.subjects(None, s)) - if node_id in nodemap: - return None - - node = {} - node[self.context.id_key] = node_id - nodemap[node_id] = node - - for p, o in graph.predicate_objects(s): - # type error: Argument 3 to "add_to_node" of "Converter" has incompatible type "Node"; expected "IdentifiedNode" - # type error: Argument 4 to "add_to_node" of "Converter" has incompatible type "Node"; expected "Identifier" - self.add_to_node(graph, s, p, o, node, nodemap) # type: ignore[arg-type] - - return node - - def add_to_node( - self, - graph: Graph, - s: IdentifiedNode, - p: IdentifiedNode, - o: Identifier, - s_node: Dict[str, Any], - nodemap, - ): - context = self.context - - if isinstance(o, Literal): - datatype = str(o.datatype) if o.datatype else None - language = o.language - term = context.find_term(str(p), datatype, language=language) - else: - containers = [LIST, None] if graph.value(o, RDF.first) else [None] - for container in containers: - for coercion in (ID, VOCAB, UNDEF): - # type error: Argument 2 to "find_term" of "Context" has incompatible type "object"; expected "Union[str, Defined, None]" - # type error: Argument 3 to "find_term" of "Context" has incompatible type "Optional[str]"; expected "Union[Defined, str]" - term = context.find_term(str(p), coercion, container) # type: ignore[arg-type] - if term: - break - if term: - break - - node = None - use_set = not context.active - - if term: - p_key = term.name - - if term.type: - node = self.type_coerce(o, term.type) - # type error: "Identifier" has no attribute "language" - elif term.language and o.language == term.language: # type: ignore[attr-defined] - node = str(o) - # type error: Right operand of "and" is never evaluated - elif context.language and (term.language is None and o.language is None): # type: ignore[unreachable] - node = str(o) # type: ignore[unreachable] - - if LIST in term.container: - node = [ - self.type_coerce(v, term.type) - or self.to_raw_value(graph, s, v, nodemap) - for v in self.to_collection(graph, o) - ] - elif LANG in term.container and language: - value = s_node.setdefault(p_key, {}) - values = value.get(language) - node = str(o) - if values or SET in term.container: - if not isinstance(values, list): - value[language] = values = [values] - values.append(node) - else: - value[language] = node - return - elif SET in term.container: - use_set = True - - else: - p_key = context.to_symbol(p) - # TODO: for coercing curies - quite clumsy; unify to_symbol and find_term? - key_term = context.terms.get(p_key) - if key_term and (key_term.type or key_term.container): - p_key = p - if not term and p == RDF.type and not self.use_rdf_type: - if isinstance(o, URIRef): - node = context.to_symbol(o) - p_key = context.type_key - - if node is None: - node = self.to_raw_value(graph, s, o, nodemap) - - value = s_node.get(p_key) - if value: - if not isinstance(value, list): - value = [value] - value.append(node) - elif use_set: - value = [node] - else: - value = node - s_node[p_key] = value - - def type_coerce(self, o: Identifier, coerce_type: str): - if coerce_type == ID: - if isinstance(o, URIRef): - return self.context.shrink_iri(o) - elif isinstance(o, BNode): - return o.n3() - else: - return o - elif coerce_type == VOCAB and isinstance(o, URIRef): - return self.context.to_symbol(o) - elif isinstance(o, Literal) and str(o.datatype) == coerce_type: - return o - else: - return None - - def to_raw_value( - self, graph: Graph, s: IdentifiedNode, o: Identifier, nodemap: Dict[str, Any] - ): - context = self.context - coll = self.to_collection(graph, o) - if coll is not None: - coll = [ - self.to_raw_value(graph, s, lo, nodemap) - for lo in self.to_collection(graph, o) - ] - return {context.list_key: coll} - elif isinstance(o, BNode): - embed = ( - False # TODO: self.context.active or using startnode and only one ref - ) - onode = self.process_subject(graph, o, nodemap) - if onode: - if embed and not any(s2 for s2 in graph.subjects(None, o) if s2 != s): - return onode - else: - nodemap[onode[context.id_key]] = onode - return {context.id_key: o.n3()} - elif isinstance(o, URIRef): - # TODO: embed if o != startnode (else reverse) - return {context.id_key: context.shrink_iri(o)} - elif isinstance(o, Literal): - # TODO: if compact - native = self.use_native_types and o.datatype in PLAIN_LITERAL_TYPES - if native: - v = o.toPython() - else: - v = str(o) - if o.datatype: - if native and self.context.active: - return v - return { - context.type_key: context.to_symbol(o.datatype), - context.value_key: v, - } - elif o.language and o.language != context.language: - return {context.lang_key: o.language, context.value_key: v} - # type error: Right operand of "and" is never evaluated - elif not context.active or context.language and not o.language: # type: ignore[unreachable] - return {context.value_key: v} - else: - return v - - def to_collection(self, graph: Graph, l_: Identifier): - if l_ != RDF.nil and not graph.value(l_, RDF.first): - return None - list_nodes: List[Optional[_ObjectType]] = [] - chain = set([l_]) - while l_: - if l_ == RDF.nil: - return list_nodes - if isinstance(l_, URIRef): - return None - first, rest = None, None - for p, o in graph.predicate_objects(l_): - if not first and p == RDF.first: - first = o - elif not rest and p == RDF.rest: - rest = o - elif p != RDF.type or o != RDF.List: - return None - list_nodes.append(first) - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Identifier") - l_ = rest # type: ignore[assignment] - if l_ in chain: - return None - chain.add(l_) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/longturtle.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/longturtle.py deleted file mode 100644 index 8de1e52..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/longturtle.py +++ /dev/null @@ -1,326 +0,0 @@ -""" -LongTurtle RDF graph serializer for RDFLib. -See for syntax specification. - -This variant, longturtle as opposed to just turtle, makes some small format changes -to turtle - the original turtle serializer. It: - -* uses PREFIX instead of @prefix -* uses BASE instead of @base -* adds a new line at RDF.type, or 'a' -* adds a newline and an indent for all triples with more than one object (object list) -* adds a new line and ';' for the last triple in a set with '.' - on the start of the next line -* uses default encoding (encode()) is used instead of "latin-1" - -- Nicholas Car, 2023 -""" - -from __future__ import annotations - -from typing import IO, Any, Optional - -from rdflib.compare import to_canonical_graph -from rdflib.exceptions import Error -from rdflib.graph import Graph -from rdflib.namespace import RDF -from rdflib.term import BNode, Literal, URIRef - -from .turtle import RecursiveSerializer - -__all__ = ["LongTurtleSerializer"] - -SUBJECT = 0 -VERB = 1 -OBJECT = 2 - -_GEN_QNAME_FOR_DT = False -_SPACIOUS_OUTPUT = False - - -class LongTurtleSerializer(RecursiveSerializer): - short_name = "longturtle" - indentString = " " - - def __init__(self, store): - self._ns_rewrite = {} - store = to_canonical_graph(store) - content = store.serialize(format="application/n-triples") - lines = content.split("\n") - lines.sort() - graph = Graph() - graph.parse( - data="\n".join(lines), format="application/n-triples", skolemize=True - ) - graph = graph.de_skolemize() - super(LongTurtleSerializer, self).__init__(graph) - self.keywords = {RDF.type: "a"} - self.reset() - self.stream = None - self._spacious: bool = _SPACIOUS_OUTPUT - - def addNamespace(self, prefix, namespace): - # Turtle does not support prefixes that start with _ - # if they occur in the graph, rewrite to p_blah - # this is more complicated since we need to make sure p_blah - # does not already exist. And we register namespaces as we go, i.e. - # we may first see a triple with prefix _9 - rewrite it to p_9 - # and then later find a triple with a "real" p_9 prefix - - # so we need to keep track of ns rewrites we made so far. - - if (prefix > "" and prefix[0] == "_") or self.namespaces.get( - prefix, namespace - ) != namespace: - if prefix not in self._ns_rewrite: - p = "p" + prefix - while p in self.namespaces: - p = "p" + p - self._ns_rewrite[prefix] = p - - prefix = self._ns_rewrite.get(prefix, prefix) - - super(LongTurtleSerializer, self).addNamespace(prefix, namespace) - return prefix - - def reset(self): - super(LongTurtleSerializer, self).reset() - self._shortNames = {} - self._started = False - self._ns_rewrite = {} - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - spacious: Optional[bool] = None, - **kwargs: Any, - ) -> None: - self.reset() - self.stream = stream - # if base is given here, use, if not and a base is set for the graph use that - if base is not None: - self.base = base - elif self.store.base is not None: - self.base = self.store.base - - if spacious is not None: - self._spacious = spacious - - self.preprocess() - subjects_list = self.orderSubjects() - - self.startDocument() - - firstTime = True - for subject in subjects_list: - if self.isDone(subject): - continue - if firstTime: - firstTime = False - if self.statement(subject) and not firstTime: - self.write("\n") - - self.endDocument() - - self.base = None - - def preprocessTriple(self, triple): - super(LongTurtleSerializer, self).preprocessTriple(triple) - for i, node in enumerate(triple): - if node in self.keywords: - continue - # Don't use generated prefixes for subjects and objects - self.getQName(node, gen_prefix=(i == VERB)) - if isinstance(node, Literal) and node.datatype: - self.getQName(node.datatype, gen_prefix=_GEN_QNAME_FOR_DT) - p = triple[1] - if isinstance(p, BNode): # hmm - when is P ever a bnode? - self._references[p] += 1 - - def getQName(self, uri, gen_prefix=True): - if not isinstance(uri, URIRef): - return None - - try: - parts = self.store.compute_qname(uri, generate=gen_prefix) - except Exception: - # is the uri a namespace in itself? - pfx = self.store.store.prefix(uri) - - if pfx is not None: - parts = (pfx, uri, "") - else: - # nothing worked - return None - - prefix, namespace, local = parts - - # QName cannot end with . - if local.endswith("."): - return None - - prefix = self.addNamespace(prefix, namespace) - - return "%s:%s" % (prefix, local) - - def startDocument(self): - self._started = True - ns_list = sorted(self.namespaces.items()) - - if self.base: - self.write(self.indent() + "BASE <%s>\n" % self.base) - for prefix, uri in ns_list: - self.write(self.indent() + "PREFIX %s: <%s>\n" % (prefix, uri)) - if ns_list and self._spacious: - self.write("\n") - - def endDocument(self): - if self._spacious: - self.write("\n") - - def statement(self, subject): - self.subjectDone(subject) - return self.s_squared(subject) or self.s_default(subject) - - def s_default(self, subject): - self.write("\n" + self.indent()) - self.path(subject, SUBJECT) - self.write("\n" + self.indent()) - self.predicateList(subject) - self.write("\n.") - return True - - def s_squared(self, subject): - if (self._references[subject] > 0) or not isinstance(subject, BNode): - return False - self.write("\n" + self.indent() + "[]") - self.predicateList(subject, newline=False) - self.write("\n.") - return True - - def path(self, node, position, newline=False): - if not ( - self.p_squared(node, position) or self.p_default(node, position, newline) - ): - raise Error("Cannot serialize node '%s'" % (node,)) - - def p_default(self, node, position, newline=False): - if position != SUBJECT and not newline: - self.write(" ") - self.write(self.label(node, position)) - return True - - def label(self, node, position): - if node == RDF.nil: - return "()" - if position is VERB and node in self.keywords: - return self.keywords[node] - if isinstance(node, Literal): - return node._literal_n3( - use_plain=True, - qname_callback=lambda dt: self.getQName(dt, _GEN_QNAME_FOR_DT), - ) - else: - node = self.relativize(node) - - return self.getQName(node, position == VERB) or node.n3() - - def p_squared( - self, - node, - position, - ): - if ( - not isinstance(node, BNode) - or node in self._serialized - or self._references[node] > 1 - or position == SUBJECT - ): - return False - - if self.isValidList(node): - # this is a list - self.depth += 2 - self.write(" (\n") - self.depth -= 2 - self.doList(node) - self.write("\n" + self.indent() + ")") - else: - # this is a Blank Node - self.subjectDone(node) - self.write("\n" + self.indent(1) + "[\n") - self.depth += 1 - self.predicateList(node) - self.depth -= 1 - self.write("\n" + self.indent(1) + "]") - - return True - - def isValidList(self, l_): - """ - Checks if l is a valid RDF list, i.e. no nodes have other properties. - """ - try: - if self.store.value(l_, RDF.first) is None: - return False - except Exception: - return False - while l_: - if l_ != RDF.nil and len(list(self.store.predicate_objects(l_))) != 2: - return False - l_ = self.store.value(l_, RDF.rest) - return True - - def doList(self, l_): - i = 0 - while l_: - item = self.store.value(l_, RDF.first) - if item is not None: - if i == 0: - self.write(self.indent(1)) - else: - self.write("\n" + self.indent(1)) - self.path(item, OBJECT, newline=True) - self.subjectDone(l_) - l_ = self.store.value(l_, RDF.rest) - i += 1 - - def predicateList(self, subject, newline=False): - properties = self.buildPredicateHash(subject) - propList = self.sortProperties(properties) - if len(propList) == 0: - return - self.write(self.indent(1)) - self.verb(propList[0], newline=True) - self.objectList(properties[propList[0]]) - for predicate in propList[1:]: - self.write(" ;\n" + self.indent(1)) - self.verb(predicate, newline=True) - self.objectList(properties[predicate]) - self.write(" ;") - - def verb(self, node, newline=False): - self.path(node, VERB, newline) - - def objectList(self, objects): - count = len(objects) - if count == 0: - return - depthmod = (count == 1) and 0 or 1 - self.depth += depthmod - first_nl = False - if count > 1: - if not isinstance(objects[0], BNode): - self.write("\n" + self.indent(1)) - else: - self.write(" ") - first_nl = True - self.path(objects[0], OBJECT, newline=first_nl) - for obj in objects[1:]: - self.write(" ,") - if not isinstance(obj, BNode): - self.write("\n" + self.indent(1)) - self.path(obj, OBJECT, newline=True) - self.depth -= depthmod diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/n3.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/n3.py deleted file mode 100644 index d8036bb..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/n3.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Notation 3 (N3) RDF graph serializer for RDFLib. -""" - -from rdflib.graph import Graph -from rdflib.namespace import OWL, Namespace -from rdflib.plugins.serializers.turtle import OBJECT, SUBJECT, TurtleSerializer - -__all__ = ["N3Serializer"] - -SWAP_LOG = Namespace("http://www.w3.org/2000/10/swap/log#") - - -class N3Serializer(TurtleSerializer): - short_name = "n3" - - def __init__(self, store: Graph, parent=None): - super(N3Serializer, self).__init__(store) - self.keywords.update({OWL.sameAs: "=", SWAP_LOG.implies: "=>"}) - self.parent = parent - - def reset(self): - super(N3Serializer, self).reset() - self._stores = {} - - def endDocument(self): # noqa: N802 - if not self.parent: - super(N3Serializer, self).endDocument() - - def indent(self, modifier=0): - indent = super(N3Serializer, self).indent(modifier) - if self.parent is not None: - indent += self.parent.indent() # modifier) - return indent - - def preprocessTriple(self, triple): # noqa: N802 - super(N3Serializer, self).preprocessTriple(triple) - if isinstance(triple[0], Graph): - for t in triple[0]: - self.preprocessTriple(t) - if isinstance(triple[1], Graph): - for t in triple[1]: - self.preprocessTriple(t) - if isinstance(triple[2], Graph): - for t in triple[2]: - self.preprocessTriple(t) - - def getQName(self, uri, gen_prefix=True): # noqa: N802 - qname = None - if self.parent is not None: - qname = self.parent.getQName(uri, gen_prefix) - if qname is None: - qname = super(N3Serializer, self).getQName(uri, gen_prefix) - return qname - - def statement(self, subject): - self.subjectDone(subject) - properties = self.buildPredicateHash(subject) - if len(properties) == 0: - return False - return self.s_clause(subject) or super(N3Serializer, self).statement(subject) - - def path(self, node, position, newline=False): - if not self.p_clause(node, position): - super(N3Serializer, self).path(node, position, newline) - - def s_clause(self, subject): - if isinstance(subject, Graph): - self.write("\n" + self.indent()) - self.p_clause(subject, SUBJECT) - self.predicateList(subject) - self.write(" .") - return True - else: - return False - - def p_clause(self, node, position): - if isinstance(node, Graph): - self.subjectDone(node) - if position is OBJECT: - self.write(" ") - self.write("{") - self.depth += 1 - serializer = N3Serializer(node, parent=self) - # type error: Argument 1 to "serialize" of "TurtleSerializer" has incompatible type "Optional[IO[bytes]]"; expected "IO[bytes]" - serializer.serialize(self.stream) # type: ignore[arg-type] - self.depth -= 1 - self.write(self.indent() + "}") - return True - else: - return False diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nquads.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nquads.py deleted file mode 100644 index b74b9ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nquads.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import warnings -from typing import IO, Any, Optional - -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.plugins.serializers.nt import _quoteLiteral -from rdflib.serializer import Serializer -from rdflib.term import Literal - -__all__ = ["NQuadsSerializer"] - - -class NQuadsSerializer(Serializer): - def __init__(self, store: Graph): - if not store.context_aware: - raise Exception( - "NQuads serialization only makes " "sense for context-aware stores!" - ) - - super(NQuadsSerializer, self).__init__(store) - self.store: ConjunctiveGraph - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - if base is not None: - warnings.warn("NQuadsSerializer does not support base.") - if encoding is not None and encoding.lower() != self.encoding.lower(): - warnings.warn( - "NQuadsSerializer does not use custom encoding. " - f"Given encoding was: {encoding}" - ) - encoding = self.encoding - for context in self.store.contexts(): - for triple in context: - stream.write( - _nq_row(triple, context.identifier).encode(encoding, "replace") - ) - stream.write("\n".encode("latin-1")) - - -def _nq_row(triple, context): - if isinstance(triple[2], Literal): - return "%s %s %s %s .\n" % ( - triple[0].n3(), - triple[1].n3(), - _quoteLiteral(triple[2]), - context.n3(), - ) - else: - return "%s %s %s %s .\n" % ( - triple[0].n3(), - triple[1].n3(), - triple[2].n3(), - context.n3(), - ) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nt.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nt.py deleted file mode 100644 index 1b0343b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/nt.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import annotations - -import codecs -import warnings -from typing import IO, TYPE_CHECKING, Any, Optional, Tuple, Union - -from rdflib.graph import Graph -from rdflib.serializer import Serializer -from rdflib.term import Literal - -if TYPE_CHECKING: - from rdflib.graph import _TripleType - -""" -N-Triples RDF graph serializer for RDFLib. -See for details about the -format. -""" - -__all__ = ["NTSerializer"] - - -class NTSerializer(Serializer): - """ - Serializes RDF graphs to NTriples format. - """ - - def __init__(self, store: Graph): - Serializer.__init__(self, store) - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = "utf-8", - **kwargs: Any, - ) -> None: - if base is not None: - warnings.warn("NTSerializer does not support base.") - if encoding != "utf-8": - warnings.warn( - "NTSerializer always uses UTF-8 encoding. " - f"Given encoding was: {encoding}" - ) - - for triple in self.store: - stream.write(_nt_row(triple).encode()) - - -class NT11Serializer(NTSerializer): - """ - Serializes RDF graphs to RDF 1.1 NTriples format. - - Exactly like nt - only utf8 encoded. - """ - - def __init__(self, store: Graph): - Serializer.__init__(self, store) # default to utf-8 - - -def _nt_row(triple: _TripleType) -> str: - if isinstance(triple[2], Literal): - return "%s %s %s .\n" % ( - triple[0].n3(), - triple[1].n3(), - _quoteLiteral(triple[2]), - ) - else: - return "%s %s %s .\n" % (triple[0].n3(), triple[1].n3(), triple[2].n3()) - - -def _quoteLiteral(l_: Literal) -> str: # noqa: N802 - """ - a simpler version of term.Literal.n3() - """ - - encoded = _quote_encode(l_) - - if l_.language: - if l_.datatype: - raise Exception("Literal has datatype AND language!") - return "%s@%s" % (encoded, l_.language) - elif l_.datatype: - return "%s^^<%s>" % (encoded, l_.datatype) - else: - return "%s" % encoded - - -def _quote_encode(l_: str) -> str: - return '"%s"' % l_.replace("\\", "\\\\").replace("\n", "\\n").replace( - '"', '\\"' - ).replace("\r", "\\r") - - -def _nt_unicode_error_resolver( - err: UnicodeError, -) -> Tuple[Union[str, bytes], int]: - """ - Do unicode char replaces as defined in https://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#ntrip_strings - """ - - def _replace_single(c): - c = ord(c) - fmt = "\\u%04X" if c <= 0xFFFF else "\\U%08X" - return fmt % c - - # type error: "UnicodeError" has no attribute "object" - # type error: "UnicodeError" has no attribute "start" - # type error: "UnicodeError" has no attribute "end" - string = err.object[err.start : err.end] # type: ignore[attr-defined] - # type error: "UnicodeError" has no attribute "end" - return "".join(_replace_single(c) for c in string), err.end # type: ignore[attr-defined] - - -codecs.register_error("_rdflib_nt_escape", _nt_unicode_error_resolver) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/patch.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/patch.py deleted file mode 100644 index 1bc5ff4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/patch.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -import warnings -from typing import IO, Any, Optional -from uuid import uuid4 - -from rdflib import Dataset -from rdflib.plugins.serializers.nquads import _nq_row -from rdflib.plugins.serializers.nt import _nt_row -from rdflib.serializer import Serializer - -add_remove_methods = {"add": "A", "remove": "D"} - - -class PatchSerializer(Serializer): - """ - Creates an RDF patch file to add and remove triples/quads. - Can either: - - Create an add or delete patch for a single Dataset. - - Create a patch to represent the difference between two Datasets. - """ - - def __init__( - self, - store: Dataset, - ): - self.store: Dataset = store - super().__init__(store) - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - """ - Serialize the store to the given stream. - :param stream: The stream to serialize to. - :param base: The base URI to use for the serialization. - :param encoding: The encoding to use for the serialization. - :param kwargs: Additional keyword arguments. - Supported keyword arguments: - - operation: The operation to perform. Either 'add' or 'remove'. - - target: The target Dataset to compare against. - NB: Only one of 'operation' or 'target' should be provided. - - header_id: The header ID to use. - - header_prev: The previous header ID to use. - """ - operation = kwargs.get("operation") - target = kwargs.get("target") - header_id = kwargs.get("header_id") - header_prev = kwargs.get("header_prev") - if not header_id: - header_id = f"uuid:{uuid4()}" - encoding = self.encoding - if base is not None: - warnings.warn("PatchSerializer does not support base.") - if encoding is not None and encoding.lower() != self.encoding.lower(): - warnings.warn( - "PatchSerializer does not use custom encoding. " - f"Given encoding was: {encoding}" - ) - - def write_header(): - stream.write(f"H id <{header_id}> .\n".encode(encoding, "replace")) - if header_prev: - stream.write(f"H prev <{header_prev}>\n".encode(encoding, "replace")) - stream.write("TX .\n".encode(encoding, "replace")) - - def write_triples(contexts, op_code, use_passed_contexts=False): - for context in contexts: - if not use_passed_contexts: - context = self.store.get_context(context.identifier) - for triple in context: - stream.write( - self._patch_row(triple, context.identifier, op_code).encode( - encoding, "replace" - ) - ) - - if operation: - assert operation in add_remove_methods, f"Invalid operation: {operation}" - elif not target: - # No operation specified and no target specified - # Fall back to default operation of "add" to prevent a no-op - operation = "add" - write_header() - if operation: - operation_code = add_remove_methods.get(operation) - write_triples(self.store.contexts(), operation_code) - elif target: - to_add, to_remove = self._diff(target) - write_triples(to_add.contexts(), "A", use_passed_contexts=True) - write_triples(to_remove.contexts(), "D", use_passed_contexts=True) - - stream.write("TC .\n".encode(encoding, "replace")) - - def _diff(self, target): - rows_to_add = target - self.store - rows_to_remove = self.store - target - return rows_to_add, rows_to_remove - - def _patch_row(self, triple, context_id, operation): - if context_id == self.store.default_context.identifier: - return f"{operation} {_nt_row(triple)}" - else: - return f"{operation} {_nq_row(triple, context_id)}" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/rdfxml.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/rdfxml.py deleted file mode 100644 index 8ae7d78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/rdfxml.py +++ /dev/null @@ -1,391 +0,0 @@ -from __future__ import annotations - -import xml.dom.minidom -from typing import IO, Any, Dict, Generator, Optional, Set, Tuple -from xml.sax.saxutils import escape, quoteattr - -from rdflib.collection import Collection -from rdflib.graph import Graph -from rdflib.namespace import RDF, RDFS, Namespace # , split_uri -from rdflib.plugins.parsers.RDFVOC import RDFVOC -from rdflib.plugins.serializers.xmlwriter import XMLWriter -from rdflib.serializer import Serializer -from rdflib.term import BNode, IdentifiedNode, Identifier, Literal, Node, URIRef -from rdflib.util import first, more_than - -from .xmlwriter import ESCAPE_ENTITIES - -__all__ = ["fix", "XMLSerializer", "PrettyXMLSerializer"] - - -class XMLSerializer(Serializer): - def __init__(self, store: Graph): - super(XMLSerializer, self).__init__(store) - - def __bindings(self) -> Generator[Tuple[str, URIRef], None, None]: - store = self.store - nm = store.namespace_manager - bindings: Dict[str, URIRef] = {} - - for predicate in set(store.predicates()): - # type error: Argument 1 to "compute_qname_strict" of "NamespaceManager" has incompatible type "Node"; expected "str" - prefix, namespace, name = nm.compute_qname_strict(predicate) # type: ignore[arg-type] - bindings[prefix] = URIRef(namespace) - - RDFNS = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#") # noqa: N806 - - if "rdf" in bindings: - assert bindings["rdf"] == RDFNS - else: - bindings["rdf"] = RDFNS - - for prefix, namespace in bindings.items(): - yield prefix, namespace - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - # if base is given here, use that, if not and a base is set for the graph use that - if base is not None: - self.base = base - elif self.store.base is not None: - self.base = self.store.base - self.__stream = stream - self.__serialized: Dict[Identifier, int] = {} - encoding = self.encoding - self.write = write = lambda uni: stream.write(uni.encode(encoding, "replace")) - - # startDocument - write('\n' % self.encoding) - - # startRDF - write("\n") - - # write out triples by subject - for subject in self.store.subjects(): - # type error: Argument 1 to "subject" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - self.subject(subject, 1) # type: ignore[arg-type] - - # endRDF - write("\n") - - # Set to None so that the memory can get garbage collected. - # self.__serialized = None - del self.__serialized - - def subject(self, subject: Identifier, depth: int = 1) -> None: - if subject not in self.__serialized: - self.__serialized[subject] = 1 - - if isinstance(subject, (BNode, URIRef)): - write = self.write - indent = " " * depth - element_name = "rdf:Description" - - if isinstance(subject, BNode): - write('%s<%s rdf:nodeID="%s"' % (indent, element_name, subject)) - else: - uri = quoteattr(self.relativize(subject)) - write("%s<%s rdf:about=%s" % (indent, element_name, uri)) - - if (subject, None, None) in self.store: - write(">\n") - - for predicate, object in self.store.predicate_objects(subject): - # type error: Argument 1 to "predicate" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - # type error: Argument 2 to "predicate" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - self.predicate(predicate, object, depth + 1) # type: ignore[arg-type] - write("%s\n" % (indent, element_name)) - - else: - write("/>\n") - - def predicate( - self, predicate: Identifier, object: Identifier, depth: int = 1 - ) -> None: - write = self.write - indent = " " * depth - qname = self.store.namespace_manager.qname_strict(predicate) - - if isinstance(object, Literal): - attributes = "" - - if object.language: - attributes += ' xml:lang="%s"' % object.language - - if object.datatype: - attributes += ' rdf:datatype="%s"' % object.datatype - - write( - "%s<%s%s>%s\n" - % (indent, qname, attributes, escape(object, ESCAPE_ENTITIES), qname) - ) - else: - if isinstance(object, BNode): - write('%s<%s rdf:nodeID="%s"/>\n' % (indent, qname, object)) - else: - write( - "%s<%s rdf:resource=%s/>\n" - % (indent, qname, quoteattr(self.relativize(object))) - ) - - -XMLLANG = "http://www.w3.org/XML/1998/namespacelang" -XMLBASE = "http://www.w3.org/XML/1998/namespacebase" -OWL_NS = Namespace("http://www.w3.org/2002/07/owl#") - - -# TODO: -def fix(val: str) -> str: - "strip off _: from nodeIDs... as they are not valid NCNames" - if val.startswith("_:"): - return val[2:] - else: - return val - - -class PrettyXMLSerializer(Serializer): - def __init__(self, store: Graph, max_depth=3): - super(PrettyXMLSerializer, self).__init__(store) - self.forceRDFAbout: Set[URIRef] = set() - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - self.__serialized: Dict[Identifier, int] = {} - store = self.store - # if base is given here, use that, if not and a base is set for the graph use that - if base is not None: - self.base = base - elif store.base is not None: - self.base = store.base - self.max_depth = kwargs.get("max_depth", 3) - assert self.max_depth > 0, "max_depth must be greater than 0" - - self.nm = nm = store.namespace_manager - self.writer = writer = XMLWriter(stream, nm, encoding) - namespaces = {} - - possible: Set[Node] = set(store.predicates()).union( - store.objects(None, RDF.type) - ) - - for predicate in possible: - # type error: Argument 1 to "compute_qname_strict" of "NamespaceManager" has incompatible type "Node"; expected "str" - prefix, namespace, local = nm.compute_qname_strict(predicate) # type: ignore[arg-type] - namespaces[prefix] = namespace - - namespaces["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" - - writer.push(RDFVOC.RDF) - - if "xml_base" in kwargs: - writer.attribute(XMLBASE, kwargs["xml_base"]) - elif self.base: - writer.attribute(XMLBASE, self.base) - - writer.namespaces(namespaces.items()) - - subject: IdentifiedNode - # Write out subjects that can not be inline - # type error: Incompatible types in assignment (expression has type "Node", variable has type "IdentifiedNode") - for subject in store.subjects(): # type: ignore[assignment] - if (None, None, subject) in store: - if (subject, None, subject) in store: - self.subject(subject, 1) - else: - self.subject(subject, 1) - - # write out anything that has not yet been reached - # write out BNodes last (to ensure they can be inlined where possible) - bnodes = set() - - # type error: Incompatible types in assignment (expression has type "Node", variable has type "IdentifiedNode") - for subject in store.subjects(): # type: ignore[assignment] - if isinstance(subject, BNode): - bnodes.add(subject) - continue - self.subject(subject, 1) - - # now serialize only those BNodes that have not been serialized yet - for bnode in bnodes: - if bnode not in self.__serialized: - self.subject(subject, 1) - - writer.pop(RDFVOC.RDF) - stream.write("\n".encode("latin-1")) - - # Set to None so that the memory can get garbage collected. - self.__serialized = None # type: ignore[assignment] - - def subject(self, subject: Identifier, depth: int = 1): - store = self.store - writer = self.writer - - if subject in self.forceRDFAbout: - writer.push(RDFVOC.Description) - writer.attribute(RDFVOC.about, self.relativize(subject)) - writer.pop(RDFVOC.Description) - self.forceRDFAbout.remove(subject) # type: ignore[arg-type] - - elif subject not in self.__serialized: - self.__serialized[subject] = 1 - type = first(store.objects(subject, RDF.type)) - - try: - # type error: Argument 1 to "qname" of "NamespaceManager" has incompatible type "Optional[Node]"; expected "str" - self.nm.qname(type) # type: ignore[arg-type] - except Exception: - type = None - - element = type or RDFVOC.Description - # type error: Argument 1 to "push" of "XMLWriter" has incompatible type "Node"; expected "str" - writer.push(element) # type: ignore[arg-type] - - if isinstance(subject, BNode): - - def subj_as_obj_more_than(ceil): - return True - # more_than(store.triples((None, None, subject)), ceil) - - # here we only include BNode labels if they are referenced - # more than once (this reduces the use of redundant BNode - # identifiers) - if subj_as_obj_more_than(1): - writer.attribute(RDFVOC.nodeID, fix(subject)) - - else: - writer.attribute(RDFVOC.about, self.relativize(subject)) - - if (subject, None, None) in store: - for predicate, object in store.predicate_objects(subject): - if not (predicate == RDF.type and object == type): - # type error: Argument 1 to "predicate" of "PrettyXMLSerializer" has incompatible type "Node"; expected "Identifier" - # type error: Argument 2 to "predicate" of "PrettyXMLSerializer" has incompatible type "Node"; expected "Identifier" - self.predicate(predicate, object, depth + 1) # type: ignore[arg-type] - - # type error: Argument 1 to "pop" of "XMLWriter" has incompatible type "Node"; expected "Optional[str]" - writer.pop(element) # type: ignore[arg-type] - - elif subject in self.forceRDFAbout: - # TODO FIXME?: this looks like a duplicate of first condition - writer.push(RDFVOC.Description) - writer.attribute(RDFVOC.about, self.relativize(subject)) - writer.pop(RDFVOC.Description) - self.forceRDFAbout.remove(subject) # type: ignore[arg-type] - - def predicate( - self, predicate: Identifier, object: Identifier, depth: int = 1 - ) -> None: - writer = self.writer - store = self.store - writer.push(predicate) - - if isinstance(object, Literal): - if object.language: - writer.attribute(XMLLANG, object.language) - - if object.datatype == RDF.XMLLiteral and isinstance( - object.value, xml.dom.minidom.Document - ): - writer.attribute(RDFVOC.parseType, "Literal") - writer.text("") - writer.stream.write(object) - else: - if object.datatype: - writer.attribute(RDFVOC.datatype, object.datatype) - writer.text(object) - - elif ( - object in self.__serialized - or not (object, None, None) in store # noqa: E713 - ): - if isinstance(object, BNode): - if more_than(store.triples((None, None, object)), 0): - writer.attribute(RDFVOC.nodeID, fix(object)) - else: - writer.attribute(RDFVOC.resource, self.relativize(object)) - - else: - if first(store.objects(object, RDF.first)): # may not have type - # RDF.List - - self.__serialized[object] = 1 - - # Warn that any assertions on object other than - # RDF.first and RDF.rest are ignored... including RDF.List - import warnings - - warnings.warn( - "Assertions on %s other than RDF.first " % repr(object) - + "and RDF.rest are ignored ... including RDF.List", - UserWarning, - stacklevel=2, - ) - writer.attribute(RDFVOC.parseType, "Collection") - - col = Collection(store, object) - - for item in col: - if isinstance(item, URIRef): - self.forceRDFAbout.add(item) - # type error: Argument 1 to "subject" of "PrettyXMLSerializer" has incompatible type "Node"; expected "Identifier" - self.subject(item) # type: ignore[arg-type] - - if not isinstance(item, URIRef): - # type error: Invalid index type "Node" for "Dict[Identifier, int]"; expected type "Identifier" - self.__serialized[item] = 1 # type: ignore[index] - else: - if first( - store.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Identifier, URIRef, List[URIRef]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - (object, RDF.type, [OWL_NS.Class, RDFS.Class]) # type: ignore[arg-type] - ) - ) and isinstance(object, URIRef): - writer.attribute(RDFVOC.resource, self.relativize(object)) - - elif depth <= self.max_depth: - self.subject(object, depth + 1) - - elif isinstance(object, BNode): - if ( - object not in self.__serialized - and (object, None, None) in store - and len(list(store.subjects(object=object))) == 1 - ): - # inline blank nodes if they haven't been serialized yet - # and are only referenced once (regardless of depth) - self.subject(object, depth + 1) - else: - writer.attribute(RDFVOC.nodeID, fix(object)) - - else: - writer.attribute(RDFVOC.resource, self.relativize(object)) - - writer.pop(predicate) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trig.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trig.py deleted file mode 100644 index 95b5e42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trig.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -Trig RDF graph serializer for RDFLib. -See for syntax specification. -""" - -from __future__ import annotations - -from typing import IO, TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union - -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.plugins.serializers.turtle import TurtleSerializer -from rdflib.term import BNode, Node - -if TYPE_CHECKING: - from rdflib.graph import _ContextType, _SubjectType - -__all__ = ["TrigSerializer"] - - -class TrigSerializer(TurtleSerializer): - short_name = "trig" - indentString = 4 * " " - - def __init__(self, store: Union[Graph, ConjunctiveGraph]): - self.default_context: Optional[Node] - if store.context_aware: - if TYPE_CHECKING: - assert isinstance(store, ConjunctiveGraph) - self.contexts = list(store.contexts()) - self.default_context = store.default_context.identifier - if store.default_context: - self.contexts.append(store.default_context) - else: - self.contexts = [store] - self.default_context = None - - super(TrigSerializer, self).__init__(store) - - def preprocess(self) -> None: - for context in self.contexts: - # do not write unnecessary prefix (ex: for an empty default graph) - if len(context) == 0: - continue - self.store = context - # Don't generate a new prefix for a graph URI if one already exists - self.getQName(context.identifier, False) - self._subjects = {} - - for triple in context: - self.preprocessTriple(triple) - - for subject in self._subjects.keys(): - self._references[subject] += 1 - - self._contexts[context] = (self.orderSubjects(), self._subjects) - - def reset(self) -> None: - super(TrigSerializer, self).reset() - self._contexts: Dict[ - _ContextType, - Tuple[List[_SubjectType], Dict[_SubjectType, bool]], - ] = {} - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - spacious: Optional[bool] = None, - **kwargs: Any, - ) -> None: - self.reset() - self.stream = stream - # if base is given here, use that, if not and a base is set for the graph use that - if base is not None: - self.base = base - elif self.store.base is not None: - self.base = self.store.base - - if spacious is not None: - self._spacious = spacious - - self.preprocess() - - self.startDocument() - - firstTime = True - for store, (ordered_subjects, subjects) in self._contexts.items(): - if not ordered_subjects: - continue - - self._serialized = {} - self.store = store - self._subjects = subjects - - if self.default_context and store.identifier == self.default_context: - self.write(self.indent() + "\n{") - else: - iri: Optional[str] - if isinstance(store.identifier, BNode): - iri = store.identifier.n3() - else: - # Show the full graph URI if a prefix for it doesn't already exist - iri = self.getQName(store.identifier, False) - if iri is None: - iri = store.identifier.n3() - self.write(self.indent() + "\n%s {" % iri) - - self.depth += 1 - for subject in ordered_subjects: - if self.isDone(subject): - continue - if firstTime: - firstTime = False - if self.statement(subject) and not firstTime: - self.write("\n") - self.depth -= 1 - self.write("}\n") - - self.endDocument() - stream.write("\n".encode("latin-1")) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trix.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trix.py deleted file mode 100644 index 95730e8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/trix.py +++ /dev/null @@ -1,91 +0,0 @@ -from __future__ import annotations - -from typing import IO, Any, Optional - -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.namespace import Namespace -from rdflib.plugins.serializers.xmlwriter import XMLWriter -from rdflib.serializer import Serializer -from rdflib.term import BNode, Literal, URIRef - -__all__ = ["TriXSerializer"] - -# TODO: Move this somewhere central -TRIXNS = Namespace("http://www.w3.org/2004/03/trix/trix-1/") -XMLNS = Namespace("http://www.w3.org/XML/1998/namespace") - - -class TriXSerializer(Serializer): - def __init__(self, store: Graph): - super(TriXSerializer, self).__init__(store) - if not store.context_aware: - raise Exception( - "TriX serialization only makes sense for context-aware stores" - ) - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - nm = self.store.namespace_manager - - self.writer = XMLWriter(stream, nm, encoding, extra_ns={"": TRIXNS}) - - self.writer.push(TRIXNS["TriX"]) - # if base is given here, use that, if not and a base is set for the graph use that - if base is None and self.store.base is not None: - base = self.store.base - if base is not None: - self.writer.attribute("http://www.w3.org/XML/1998/namespacebase", base) - self.writer.namespaces() - - if isinstance(self.store, ConjunctiveGraph): - for subgraph in self.store.contexts(): - self._writeGraph(subgraph) - elif isinstance(self.store, Graph): - self._writeGraph(self.store) - else: - raise Exception(f"Unknown graph type: {type(self.store)}") - - self.writer.pop() - stream.write("\n".encode("latin-1")) - - def _writeGraph(self, graph): # noqa: N802 - self.writer.push(TRIXNS["graph"]) - if graph.base: - self.writer.attribute( - "http://www.w3.org/XML/1998/namespacebase", graph.base - ) - if isinstance(graph.identifier, URIRef): - self.writer.element(TRIXNS["uri"], content=str(graph.identifier)) - - for triple in graph.triples((None, None, None)): - self._writeTriple(triple) - self.writer.pop() - - def _writeTriple(self, triple): # noqa: N802 - self.writer.push(TRIXNS["triple"]) - for component in triple: - if isinstance(component, URIRef): - self.writer.element(TRIXNS["uri"], content=str(component)) - elif isinstance(component, BNode): - self.writer.element(TRIXNS["id"], content=str(component)) - elif isinstance(component, Literal): - if component.datatype: - self.writer.element( - TRIXNS["typedLiteral"], - content=str(component), - attributes={TRIXNS["datatype"]: str(component.datatype)}, - ) - elif component.language: - self.writer.element( - TRIXNS["plainLiteral"], - content=str(component), - attributes={XMLNS["lang"]: str(component.language)}, - ) - else: - self.writer.element(TRIXNS["plainLiteral"], content=str(component)) - self.writer.pop() diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/turtle.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/turtle.py deleted file mode 100644 index d1dfcf4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/turtle.py +++ /dev/null @@ -1,453 +0,0 @@ -""" -Turtle RDF graph serializer for RDFLib. -See for syntax specification. -""" - -from __future__ import annotations - -from collections import defaultdict -from typing import ( - IO, - TYPE_CHECKING, - Any, - DefaultDict, - Dict, - List, - Mapping, - Optional, - Sequence, - Tuple, -) - -from rdflib.exceptions import Error -from rdflib.graph import Graph -from rdflib.namespace import RDF, RDFS -from rdflib.serializer import Serializer -from rdflib.term import BNode, Literal, Node, URIRef - -if TYPE_CHECKING: - from rdflib.graph import _PredicateType, _SubjectType, _TripleType - -__all__ = ["RecursiveSerializer", "TurtleSerializer"] - - -class RecursiveSerializer(Serializer): - topClasses = [RDFS.Class] - predicateOrder = [RDF.type, RDFS.label] - maxDepth = 10 - indentString = " " - roundtrip_prefixes: Tuple[Any, ...] = () - - def __init__(self, store: Graph): - super(RecursiveSerializer, self).__init__(store) - self.stream: Optional[IO[bytes]] = None - self.reset() - - def addNamespace(self, prefix: str, uri: URIRef) -> None: - if prefix in self.namespaces and self.namespaces[prefix] != uri: - raise Exception( - "Trying to override namespace prefix %s => %s, but it's already bound to %s" - % (prefix, uri, self.namespaces[prefix]) - ) - self.namespaces[prefix] = uri - - def checkSubject(self, subject: _SubjectType) -> bool: - """Check to see if the subject should be serialized yet""" - if ( - (self.isDone(subject)) - or (subject not in self._subjects) - or ((subject in self._topLevels) and (self.depth > 1)) - or (isinstance(subject, URIRef) and (self.depth >= self.maxDepth)) - ): - return False - return True - - def isDone(self, subject: _SubjectType) -> bool: - """Return true if subject is serialized""" - return subject in self._serialized - - def orderSubjects(self) -> List[_SubjectType]: - seen: Dict[_SubjectType, bool] = {} - subjects: List[_SubjectType] = [] - - for classURI in self.topClasses: - members = list(self.store.subjects(RDF.type, classURI)) - members.sort() - - subjects.extend(members) - for member in members: - self._topLevels[member] = True - seen[member] = True - - recursable = [ - (isinstance(subject, BNode), self._references[subject], subject) - for subject in self._subjects - if subject not in seen - ] - - recursable.sort() - subjects.extend([subject for (isbnode, refs, subject) in recursable]) - - return subjects - - def preprocess(self) -> None: - for triple in self.store.triples((None, None, None)): - self.preprocessTriple(triple) - - def preprocessTriple(self, spo: _TripleType) -> None: - s, p, o = spo - self._references[o] += 1 - self._subjects[s] = True - - def reset(self) -> None: - self.depth = 0 - # Typed none because nothing is using it ... - self.lists: Dict[None, None] = {} - self.namespaces: Dict[str, URIRef] = {} - self._references: DefaultDict[Node, int] = defaultdict(int) - self._serialized: Dict[_SubjectType, bool] = {} - self._subjects: Dict[_SubjectType, bool] = {} - self._topLevels: Dict[_SubjectType, bool] = {} - - if self.roundtrip_prefixes: - if hasattr(self.roundtrip_prefixes, "__iter__"): - for prefix, ns in self.store.namespaces(): - if prefix in self.roundtrip_prefixes: - self.addNamespace(prefix, ns) - else: - for prefix, ns in self.store.namespaces(): - self.addNamespace(prefix, ns) - - def buildPredicateHash( - self, subject: _SubjectType - ) -> Mapping[_PredicateType, List[Node]]: - """ - Build a hash key by predicate to a list of objects for the given - subject - """ - properties: Dict[_PredicateType, List[Node]] = {} - for s, p, o in self.store.triples((subject, None, None)): - oList = properties.get(p, []) - oList.append(o) - properties[p] = oList - return properties - - def sortProperties( - self, properties: Mapping[_PredicateType, List[Node]] - ) -> List[_PredicateType]: - """Take a hash from predicate uris to lists of values. - Sort the lists of values. Return a sorted list of properties.""" - # Sort object lists - for prop, objects in properties.items(): - objects.sort() - - # Make sorted list of properties - propList: List[_PredicateType] = [] - seen: Dict[_PredicateType, bool] = {} - for prop in self.predicateOrder: - if (prop in properties) and (prop not in seen): - propList.append(prop) - seen[prop] = True - props = list(properties.keys()) - props.sort() - for prop in props: - if prop not in seen: - propList.append(prop) - seen[prop] = True - return propList - - def subjectDone(self, subject: _SubjectType) -> None: - """Mark a subject as done.""" - self._serialized[subject] = True - - def indent(self, modifier: int = 0) -> str: - """Returns indent string multiplied by the depth""" - return (self.depth + modifier) * self.indentString - - def write(self, text: str) -> None: - """Write text in given encoding.""" - # type error: Item "None" of "Optional[IO[bytes]]" has no attribute "write" - self.stream.write(text.encode(self.encoding, "replace")) # type: ignore[union-attr] - - -SUBJECT = 0 -VERB = 1 -OBJECT = 2 - -_GEN_QNAME_FOR_DT = False -_SPACIOUS_OUTPUT = False - - -class TurtleSerializer(RecursiveSerializer): - short_name = "turtle" - indentString = " " - - def __init__(self, store: Graph): - self._ns_rewrite: Dict[str, str] = {} - super(TurtleSerializer, self).__init__(store) - self.keywords: Dict[Node, str] = {RDF.type: "a"} - self.reset() - self.stream = None - self._spacious = _SPACIOUS_OUTPUT - - # type error: Return type "str" of "addNamespace" incompatible with return type "None" in supertype "RecursiveSerializer" - def addNamespace(self, prefix: str, namespace: URIRef) -> str: # type: ignore[override] - # Turtle does not support prefix that start with _ - # if they occur in the graph, rewrite to p_blah - # this is more complicated since we need to make sure p_blah - # does not already exist. And we register namespaces as we go, i.e. - # we may first see a triple with prefix _9 - rewrite it to p_9 - # and then later find a triple with a "real" p_9 prefix - - # so we need to keep track of ns rewrites we made so far. - - if (prefix > "" and prefix[0] == "_") or self.namespaces.get( - prefix, namespace - ) != namespace: - if prefix not in self._ns_rewrite: - p = "p" + prefix - while p in self.namespaces: - p = "p" + p - self._ns_rewrite[prefix] = p - - prefix = self._ns_rewrite.get(prefix, prefix) - - super(TurtleSerializer, self).addNamespace(prefix, namespace) - return prefix - - def reset(self) -> None: - super(TurtleSerializer, self).reset() - # typing as Dict[None, None] because nothing seems to be using it - self._shortNames: Dict[None, None] = {} - self._started = False - self._ns_rewrite = {} - - def serialize( - self, - stream: IO[bytes], - base: Optional[str] = None, - encoding: Optional[str] = None, - spacious: Optional[bool] = None, - **kwargs: Any, - ) -> None: - self.reset() - self.stream = stream - # if base is given here, use that, if not and a base is set for the graph use that - if base is not None: - self.base = base - elif self.store.base is not None: - self.base = self.store.base - - if spacious is not None: - self._spacious = spacious - - self.preprocess() - subjects_list = self.orderSubjects() - - self.startDocument() - - firstTime = True - for subject in subjects_list: - if self.isDone(subject): - continue - if firstTime: - firstTime = False - if self.statement(subject) and not firstTime: - self.write("\n") - - self.endDocument() - stream.write("\n".encode("latin-1")) - - self.base = None - - def preprocessTriple(self, triple: _TripleType) -> None: - super(TurtleSerializer, self).preprocessTriple(triple) - for i, node in enumerate(triple): - if i == VERB and node in self.keywords: - # predicate is a keyword - continue - # Don't use generated prefixes for subjects and objects - self.getQName(node, gen_prefix=(i == VERB)) - if isinstance(node, Literal) and node.datatype: - self.getQName(node.datatype, gen_prefix=_GEN_QNAME_FOR_DT) - p = triple[1] - if isinstance(p, BNode): # hmm - when is P ever a bnode? - self._references[p] += 1 - - # TODO: Rename to get_pname - def getQName(self, uri: Node, gen_prefix: bool = True) -> Optional[str]: - if not isinstance(uri, URIRef): - return None - - parts = None - - try: - parts = self.store.compute_qname(uri, generate=gen_prefix) - except Exception: - # is the uri a namespace in itself? - pfx = self.store.store.prefix(uri) - - if pfx is not None: - parts = (pfx, uri, "") - else: - # nothing worked - return None - - prefix, namespace, local = parts - - local = local.replace(r"(", r"\(").replace(r")", r"\)") - - # QName cannot end with . - if local.endswith("."): - return None - - prefix = self.addNamespace(prefix, namespace) - - return "%s:%s" % (prefix, local) - - def startDocument(self) -> None: - self._started = True - ns_list = sorted(self.namespaces.items()) - - if self.base: - self.write(self.indent() + "@base <%s> .\n" % self.base) - for prefix, uri in ns_list: - self.write(self.indent() + "@prefix %s: <%s> .\n" % (prefix, uri)) - if ns_list and self._spacious: - self.write("\n") - - def endDocument(self) -> None: - if self._spacious: - self.write("\n") - - def statement(self, subject: _SubjectType) -> bool: - self.subjectDone(subject) - return self.s_squared(subject) or self.s_default(subject) - - def s_default(self, subject: _SubjectType) -> bool: - self.write("\n" + self.indent()) - self.path(subject, SUBJECT) - self.predicateList(subject) - self.write(" .") - return True - - def s_squared(self, subject: _SubjectType) -> bool: - if (self._references[subject] > 0) or not isinstance(subject, BNode): - return False - self.write("\n" + self.indent() + "[]") - self.predicateList(subject) - self.write(" .") - return True - - def path(self, node: Node, position: int, newline: bool = False) -> None: - if not ( - self.p_squared(node, position, newline) - or self.p_default(node, position, newline) - ): - raise Error("Cannot serialize node '%s'" % (node,)) - - def p_default(self, node: Node, position: int, newline: bool = False) -> bool: - if position != SUBJECT and not newline: - self.write(" ") - self.write(self.label(node, position)) - return True - - def label(self, node: Node, position: int) -> str: - if node == RDF.nil: - return "()" - if position is VERB and node in self.keywords: - return self.keywords[node] - if isinstance(node, Literal): - return node._literal_n3( - use_plain=True, - qname_callback=lambda dt: self.getQName(dt, _GEN_QNAME_FOR_DT), - ) - else: - node = self.relativize(node) # type: ignore[type-var] - - return self.getQName(node, position == VERB) or node.n3() - - def p_squared(self, node: Node, position: int, newline: bool = False) -> bool: - if ( - not isinstance(node, BNode) - or node in self._serialized - or self._references[node] > 1 - or position == SUBJECT - ): - return False - - if not newline: - self.write(" ") - - if self.isValidList(node): - # this is a list - self.write("(") - self.depth += 1 # 2 - self.doList(node) - self.depth -= 1 # 2 - self.write(" )") - else: - self.subjectDone(node) - self.depth += 2 - # self.write('[\n' + self.indent()) - self.write("[") - self.depth -= 1 - # self.predicateList(node, newline=True) - self.predicateList(node, newline=False) - # self.write('\n' + self.indent() + ']') - self.write(" ]") - self.depth -= 1 - - return True - - def isValidList(self, l_: Node) -> bool: - """ - Checks if l is a valid RDF list, i.e. no nodes have other properties. - """ - try: - if self.store.value(l_, RDF.first) is None: - return False - except Exception: - return False - while l_: - if l_ != RDF.nil and len(list(self.store.predicate_objects(l_))) != 2: - return False - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Node") - l_ = self.store.value(l_, RDF.rest) # type: ignore[assignment] - return True - - def doList(self, l_: Node) -> None: - while l_: - item = self.store.value(l_, RDF.first) - if item is not None: - self.path(item, OBJECT) - self.subjectDone(l_) - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Node") - l_ = self.store.value(l_, RDF.rest) # type: ignore[assignment] - - def predicateList(self, subject: Node, newline: bool = False) -> None: - properties = self.buildPredicateHash(subject) - propList = self.sortProperties(properties) - if len(propList) == 0: - return - self.verb(propList[0], newline=newline) - self.objectList(properties[propList[0]]) - for predicate in propList[1:]: - self.write(" ;\n" + self.indent(1)) - self.verb(predicate, newline=True) - self.objectList(properties[predicate]) - - def verb(self, node: Node, newline: bool = False) -> None: - self.path(node, VERB, newline) - - def objectList(self, objects: Sequence[Node]) -> None: - count = len(objects) - if count == 0: - return - depthmod = (count == 1) and 0 or 1 - self.depth += depthmod - self.path(objects[0], OBJECT) - for obj in objects[1:]: - self.write(",\n" + self.indent(1)) - self.path(obj, OBJECT, newline=True) - self.depth -= depthmod diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/xmlwriter.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/xmlwriter.py deleted file mode 100644 index 8c00521..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/serializers/xmlwriter.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import annotations - -import codecs -from typing import IO, TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple -from xml.sax.saxutils import escape, quoteattr - -from rdflib.term import URIRef - -if TYPE_CHECKING: - from rdflib.namespace import Namespace, NamespaceManager - - -__all__ = ["XMLWriter"] - -ESCAPE_ENTITIES = {"\r": " "} - - -class XMLWriter: - def __init__( - self, - stream: IO[bytes], - namespace_manager: NamespaceManager, - encoding: Optional[str] = None, - decl: int = 1, - extra_ns: Optional[Dict[str, Namespace]] = None, - ): - encoding = encoding or "utf-8" - encoder, decoder, stream_reader, stream_writer = codecs.lookup(encoding) - # NOTE on type ignores: this is mainly because the variable is being re-used. - # type error: Incompatible types in assignment (expression has type "StreamWriter", variable has type "IO[bytes]") - self.stream = stream = stream_writer(stream) # type: ignore[assignment] - if decl: - # type error: No overload variant of "write" of "IO" matches argument type "str" - stream.write('' % encoding) # type: ignore[call-overload] - self.element_stack: List[str] = [] - self.nm = namespace_manager - self.extra_ns = extra_ns or {} - self.closed = True - - def __get_indent(self) -> str: - return " " * len(self.element_stack) - - indent = property(__get_indent) - - def __close_start_tag(self) -> None: - if not self.closed: # TODO: - self.closed = True - self.stream.write(">") - - def push(self, uri: str) -> None: - self.__close_start_tag() - write = self.stream.write - write("\n") - write(self.indent) - write("<%s" % self.qname(uri)) - self.element_stack.append(uri) - self.closed = False - self.parent = False - - def pop(self, uri: Optional[str] = None) -> None: - top = self.element_stack.pop() - if uri: - assert uri == top - write = self.stream.write - if not self.closed: - self.closed = True - write("/>") - else: - if self.parent: - write("\n") - write(self.indent) - write("" % self.qname(top)) - self.parent = True - - def element( - self, uri: str, content: str, attributes: Dict[URIRef, str] = {} - ) -> None: - """Utility method for adding a complete simple element""" - self.push(uri) - for k, v in attributes.items(): - self.attribute(k, v) - self.text(content) - self.pop() - - def namespaces(self, namespaces: Iterable[Tuple[str, str]] = None) -> None: - if not namespaces: - namespaces = self.nm.namespaces() - - write = self.stream.write - write("\n") - for prefix, namespace in namespaces: - if prefix: - write(' xmlns:%s="%s"\n' % (prefix, namespace)) - # Allow user-provided namespace bindings to prevail - elif prefix not in self.extra_ns: - write(' xmlns="%s"\n' % namespace) - - for prefix, namespace in self.extra_ns.items(): - if prefix: - write(' xmlns:%s="%s"\n' % (prefix, namespace)) - else: - write(' xmlns="%s"\n' % namespace) - - def attribute(self, uri: str, value: str) -> None: - write = self.stream.write - write(" %s=%s" % (self.qname(uri), quoteattr(value))) - - def text(self, text: str) -> None: - self.__close_start_tag() - if "<" in text and ">" in text and "]]>" not in text: - self.stream.write("") - else: - self.stream.write(escape(text, ESCAPE_ENTITIES)) - - def qname(self, uri: str) -> str: - """Compute qname for a uri using our extra namespaces, - or the given namespace manager""" - - for pre, ns in self.extra_ns.items(): - if uri.startswith(ns): - if pre != "": - return ":".join([pre, uri[len(ns) :]]) - else: - return uri[len(ns) :] - - return self.nm.qname_strict(uri) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/context.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/context.py deleted file mode 100644 index e6b6688..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/context.py +++ /dev/null @@ -1,676 +0,0 @@ -""" -Implementation of the JSON-LD Context structure. See: - - http://json-ld.org/ - -""" - -# https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/context.py -from __future__ import annotations - -from collections import namedtuple -from typing import ( - TYPE_CHECKING, - Any, - Collection, - Dict, - Generator, - List, - Optional, - Set, - Tuple, - Union, -) -from urllib.parse import urljoin, urlsplit - -from rdflib.namespace import RDF - -from .errors import ( - INVALID_CONTEXT_ENTRY, - INVALID_REMOTE_CONTEXT, - RECURSIVE_CONTEXT_INCLUSION, -) -from .keys import ( - BASE, - CONTAINER, - CONTEXT, - GRAPH, - ID, - IMPORT, - INCLUDED, - INDEX, - JSON, - LANG, - LIST, - NEST, - NONE, - PREFIX, - PROPAGATE, - PROTECTED, - REV, - SET, - TYPE, - VALUE, - VERSION, - VOCAB, -) -from .util import norm_url, source_to_json, split_iri - -NODE_KEYS = {GRAPH, ID, INCLUDED, JSON, LIST, NEST, NONE, REV, SET, TYPE, VALUE, LANG} - - -class Defined(int): - pass - - -UNDEF = Defined(0) - -# From -URI_GEN_DELIMS = (":", "/", "?", "#", "[", "]", "@") - -_ContextSourceType = Union[ - List[Union[Dict[str, Any], str, None]], Dict[str, Any], str, None -] - - -class Context: - def __init__( - self, - source: _ContextSourceType = None, - base: Optional[str] = None, - version: Optional[float] = 1.1, - ): - self.version: float = version or 1.1 - self.language = None - self.vocab: Optional[str] = None - self._base: Optional[str] - self.base = base - self.doc_base = base - self.terms: Dict[str, Any] = {} - # _alias maps NODE_KEY to list of aliases - self._alias: Dict[str, List[str]] = {} - self._lookup: Dict[Tuple[str, Any, Union[Defined, str], bool], Term] = {} - self._prefixes: Dict[str, Any] = {} - self.active = False - self.parent: Optional[Context] = None - self.propagate = True - self._context_cache: Dict[str, Any] = {} - if source: - self.load(source) - - @property - def base(self) -> Optional[str]: - return self._base - - @base.setter - def base(self, base: Optional[str]): - if base: - hash_index = base.find("#") - if hash_index > -1: - base = base[0:hash_index] - self._base = ( - self.resolve_iri(base) - if (hasattr(self, "_base") and base is not None) - else base - ) - self._basedomain = "%s://%s" % urlsplit(base)[0:2] if base else None - - def subcontext(self, source: Any, propagate: bool = True) -> Context: - # IMPROVE: to optimize, implement SubContext with parent fallback support - parent = self.parent if self.propagate is False else self - # type error: Item "None" of "Optional[Context]" has no attribute "_subcontext" - return parent._subcontext(source, propagate) # type: ignore[union-attr] - - def _subcontext(self, source: Any, propagate: bool) -> Context: - ctx = Context(version=self.version) - ctx.propagate = propagate - ctx.parent = self - ctx.language = self.language - ctx.vocab = self.vocab - ctx.base = self.base - ctx.doc_base = self.doc_base - ctx._alias = {k: l[:] for k, l in self._alias.items()} # noqa: E741 - ctx.terms = self.terms.copy() - ctx._lookup = self._lookup.copy() - ctx._prefixes = self._prefixes.copy() - ctx._context_cache = self._context_cache - ctx.load(source) - return ctx - - def _clear(self) -> None: - self.language = None - self.vocab = None - self.terms = {} - self._alias = {} - self._lookup = {} - self._prefixes = {} - self.active = False - self.propagate = True - - def get_context_for_term(self, term: Optional[Term]) -> Context: - if term and term.context is not UNDEF: - return self._subcontext(term.context, propagate=True) - return self - - def get_context_for_type(self, node: Any) -> Optional[Context]: - if self.version >= 1.1: - rtype = self.get_type(node) if isinstance(node, dict) else None - if not isinstance(rtype, list): - rtype = [rtype] if rtype else [] - - typeterm = None - for rt in rtype: - try: - typeterm = self.terms.get(rt) - except TypeError: - # extra lenience, triggers if type is set to a literal - pass - if typeterm is not None: - break - - if typeterm and typeterm.context: - subcontext = self.subcontext(typeterm.context, propagate=False) - if subcontext: - return subcontext - - return self.parent if self.propagate is False else self - - def get_id(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, ID) - - def get_type(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, TYPE) - - def get_language(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, LANG) - - def get_value(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, VALUE) - - def get_graph(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, GRAPH) - - def get_list(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, LIST) - - def get_set(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, SET) - - def get_rev(self, obj: Dict[str, Any]) -> Any: - return self._get(obj, REV) - - def _get(self, obj: Dict[str, Any], key: str) -> Any: - for alias in self._alias.get(key, []): - if alias in obj: - return obj.get(alias) - return obj.get(key) - - # type error: Missing return statement - def get_key(self, key: str) -> str: # type: ignore[return] - for alias in self.get_keys(key): - return alias - - def get_keys(self, key: str) -> Generator[str, None, None]: - if key in self._alias: - for alias in self._alias[key]: - yield alias - yield key - - lang_key = property(lambda self: self.get_key(LANG)) - id_key = property(lambda self: self.get_key(ID)) - type_key = property(lambda self: self.get_key(TYPE)) - value_key = property(lambda self: self.get_key(VALUE)) - list_key = property(lambda self: self.get_key(LIST)) - rev_key = property(lambda self: self.get_key(REV)) - graph_key = property(lambda self: self.get_key(GRAPH)) - - def add_term( - self, - name: str, - idref: str, - coercion: Union[Defined, str] = UNDEF, - container: Union[Collection[Any], str, Defined] = UNDEF, - index: Optional[Union[str, Defined]] = None, - language: Optional[Union[str, Defined]] = UNDEF, - reverse: bool = False, - context: Any = UNDEF, - prefix: Optional[bool] = None, - protected: bool = False, - ): - if self.version < 1.1 or prefix is None: - prefix = isinstance(idref, str) and idref.endswith(URI_GEN_DELIMS) - - if not self._accept_term(name): - return - - if self.version >= 1.1: - existing = self.terms.get(name) - if existing and existing.protected: - return - - if isinstance(container, (list, set, tuple)): - container = set(container) - elif container is not UNDEF: - container = set([container]) - else: - container = set() - - term = Term( - idref, - name, - coercion, - container, - index, - language, - reverse, - context, - prefix, - protected, - ) - - self.terms[name] = term - - container_key: Union[Defined, str] - for container_key in (LIST, LANG, SET): # , INDEX, ID, GRAPH): - if container_key in container: - break - else: - container_key = UNDEF - - self._lookup[(idref, coercion or language, container_key, reverse)] = term - - if term.prefix is True: - self._prefixes[idref] = name - - def find_term( - self, - idref: str, - coercion: Optional[Union[str, Defined]] = None, - container: Union[Defined, str] = UNDEF, - language: Optional[str] = None, - reverse: bool = False, - ): - lu = self._lookup - - if coercion is None: - coercion = language - - if coercion is not UNDEF and container: - found = lu.get((idref, coercion, container, reverse)) - if found: - return found - - if coercion is not UNDEF: - found = lu.get((idref, coercion, UNDEF, reverse)) - if found: - return found - - if container: - found = lu.get((idref, coercion, container, reverse)) - if found: - return found - elif language: - found = lu.get((idref, UNDEF, LANG, reverse)) - if found: - return found - else: - found = lu.get((idref, coercion or UNDEF, SET, reverse)) - if found: - return found - - return lu.get((idref, UNDEF, UNDEF, reverse)) - - def resolve(self, curie_or_iri: str) -> str: - iri = self.expand(curie_or_iri, False) - # type error: Argument 1 to "isblank" of "Context" has incompatible type "Optional[str]"; expected "str" - if self.isblank(iri): # type: ignore[arg-type] - # type error: Incompatible return value type (got "Optional[str]", expected "str") - return iri # type: ignore[return-value] - # type error: Unsupported right operand type for in ("Optional[str]") - if " " in iri: # type: ignore[operator] - return "" - # type error: Argument 1 to "resolve_iri" of "Context" has incompatible type "Optional[str]"; expected "str" - return self.resolve_iri(iri) # type: ignore[arg-type] - - def resolve_iri(self, iri: str) -> str: - # type error: Argument 1 to "norm_url" has incompatible type "Optional[str]"; expected "str" - return norm_url(self._base, iri) # type: ignore[arg-type] - - def isblank(self, ref: str) -> bool: - return ref.startswith("_:") - - def expand(self, term_curie_or_iri: Any, use_vocab: bool = True) -> Optional[str]: - if not isinstance(term_curie_or_iri, str): - return term_curie_or_iri - - if not self._accept_term(term_curie_or_iri): - return "" - - if use_vocab: - term = self.terms.get(term_curie_or_iri) - if term: - return term.id - - is_term, pfx, local = self._prep_expand(term_curie_or_iri) - if pfx == "_": - return term_curie_or_iri - - if pfx is not None: - ns = self.terms.get(pfx) - if ns and ns.prefix and ns.id: - return ns.id + local - elif is_term and use_vocab: - if self.vocab: - return self.vocab + term_curie_or_iri - return None - - return self.resolve_iri(term_curie_or_iri) - - def shrink_iri(self, iri: str) -> str: - ns, name = split_iri(str(iri)) - pfx = self._prefixes.get(ns) - if pfx: - # type error: Argument 1 to "join" of "str" has incompatible type "Tuple[Any, Optional[str]]"; expected "Iterable[str]" - return ":".join((pfx, name)) # type: ignore[arg-type] - elif self._base: - if str(iri) == self._base: - return "" - # type error: Argument 1 to "startswith" of "str" has incompatible type "Optional[str]"; expected "Union[str, Tuple[str, ...]]" - elif iri.startswith(self._basedomain): # type: ignore[arg-type] - # type error: Argument 1 to "len" has incompatible type "Optional[str]"; expected "Sized" - return iri[len(self._basedomain) :] # type: ignore[arg-type] - return iri - - def to_symbol(self, iri: str) -> Optional[str]: - iri = str(iri) - term = self.find_term(iri) - if term: - return term.name - ns, name = split_iri(iri) - if ns == self.vocab: - return name - pfx = self._prefixes.get(ns) - if pfx: - # type error: Argument 1 to "join" of "str" has incompatible type "Tuple[Any, Optional[str]]"; expected "Iterable[str]" - return ":".join((pfx, name)) # type: ignore[arg-type] - return iri - - def load( - self, - source: _ContextSourceType, - base: Optional[str] = None, - referenced_contexts: Set[Any] = None, - ): - self.active = True - sources: List[Tuple[Optional[str], Union[Dict[str, Any], str, None]]] = [] - # "Union[List[Union[Dict[str, Any], str]], List[Dict[str, Any]], List[str]]" : expression - # "Union[List[Dict[str, Any]], Dict[str, Any], List[str], str]" : variable - source = source if isinstance(source, list) else [source] - referenced_contexts = referenced_contexts or set() - self._prep_sources(base, source, sources, referenced_contexts) - for source_url, source in sources: - if source is None: - self._clear() - else: - # type error: Argument 1 to "_read_source" of "Context" has incompatible type "Union[Dict[str, Any], str]"; expected "Dict[str, Any]" - self._read_source(source, source_url, referenced_contexts) # type: ignore[arg-type] - - def _accept_term(self, key: str) -> bool: - if self.version < 1.1: - return True - if key and len(key) > 1 and key[0] == "@" and key[1].isalnum(): - return key in NODE_KEYS - else: - return True - - def _prep_sources( - self, - base: Optional[str], - inputs: Union[List[Union[Dict[str, Any], str, None]], List[str]], - sources: List[Tuple[Optional[str], Union[Dict[str, Any], str, None]]], - referenced_contexts: Set[str], - in_source_url: Optional[str] = None, - ): - for source in inputs: - source_url = in_source_url - new_base = base - if isinstance(source, str): - source_url = source - source_doc_base = base or self.doc_base - new_ctx = self._fetch_context( - source, source_doc_base, referenced_contexts - ) - if new_ctx is None: - continue - else: - if base: - if TYPE_CHECKING: - # if base is not None, then source_doc_base won't be - # none due to how it is assigned. - assert source_doc_base is not None - new_base = urljoin(source_doc_base, source_url) - source = new_ctx - - if isinstance(source, dict): - if CONTEXT in source: - source = source[CONTEXT] - # type ignore: Incompatible types in assignment (expression has type "List[Union[Dict[str, Any], str, None]]", variable has type "Union[Dict[str, Any], str, None]") - source = source if isinstance(source, list) else [source] # type: ignore[assignment] - - if isinstance(source, list): - # type error: Statement is unreachable - self._prep_sources( # type: ignore[unreachable] - new_base, source, sources, referenced_contexts, source_url - ) - else: - sources.append((source_url, source)) - - def _fetch_context( - self, source: str, base: Optional[str], referenced_contexts: Set[str] - ): - # type error: Value of type variable "AnyStr" of "urljoin" cannot be "Optional[str]" - source_url = urljoin(base, source) # type: ignore[type-var] - - if source_url in referenced_contexts: - raise RECURSIVE_CONTEXT_INCLUSION - - # type error: Argument 1 to "add" of "set" has incompatible type "Optional[str]"; expected "str" - referenced_contexts.add(source_url) # type: ignore[arg-type] - - if source_url in self._context_cache: - return self._context_cache[source_url] - - # type error: Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str") - source_json, _ = source_to_json(source_url) - if source_json and CONTEXT not in source_json: - raise INVALID_REMOTE_CONTEXT - - # type error: Invalid index type "Optional[str]" for "Dict[str, Any]"; expected type "str" - self._context_cache[source_url] = source_json # type: ignore[index] - - return source_json - - def _read_source( - self, - source: Dict[str, Any], - source_url: Optional[str] = None, - referenced_contexts: Optional[Set[str]] = None, - ): - imports = source.get(IMPORT) - if imports: - if not isinstance(imports, str): - raise INVALID_CONTEXT_ENTRY - - imported = self._fetch_context( - imports, self.base, referenced_contexts or set() - ) - if not isinstance(imported, dict): - raise INVALID_CONTEXT_ENTRY - - imported = imported[CONTEXT] - imported.update(source) - source = imported - - self.vocab = source.get(VOCAB, self.vocab) - self.version = source.get(VERSION, self.version) - protected = source.get(PROTECTED, False) - - for key, value in source.items(): - if key in {VOCAB, VERSION, IMPORT, PROTECTED}: - continue - elif key == PROPAGATE and isinstance(value, bool): - self.propagate = value - elif key == LANG: - self.language = value - elif key == BASE: - if not source_url and not imports: - self.base = value - else: - self._read_term(source, key, value, protected) - - def _read_term( - self, - source: Dict[str, Any], - name: str, - dfn: Union[Dict[str, Any], str], - protected: bool = False, - ) -> None: - idref = None - if isinstance(dfn, dict): - # term = self._create_term(source, key, value) - rev = dfn.get(REV) - protected = dfn.get(PROTECTED, protected) - - coercion = dfn.get(TYPE, UNDEF) - if coercion and coercion not in (ID, TYPE, VOCAB): - coercion = self._rec_expand(source, coercion) - - idref = rev or dfn.get(ID, UNDEF) - if idref == TYPE: - idref = str(RDF.type) - coercion = VOCAB - elif idref is not UNDEF: - idref = self._rec_expand(source, idref) - elif ":" in name: - idref = self._rec_expand(source, name) - elif self.vocab: - idref = self.vocab + name - - context = dfn.get(CONTEXT, UNDEF) - - self.add_term( - name, - idref, - coercion, - dfn.get(CONTAINER, UNDEF), - dfn.get(INDEX, UNDEF), - dfn.get(LANG, UNDEF), - bool(rev), - context, - dfn.get(PREFIX), - protected=protected, - ) - else: - if isinstance(dfn, str): - if not self._accept_term(dfn): - return - idref = self._rec_expand(source, dfn) - # type error: Argument 2 to "add_term" of "Context" has incompatible type "Optional[str]"; expected "str" - self.add_term(name, idref, protected=protected) # type: ignore[arg-type] - - if idref in NODE_KEYS: - self._alias.setdefault(idref, []).append(name) - else: - # undo aliases that may have been inherited from parent context - for v in self._alias.values(): - if name in v: - v.remove(name) - - def _rec_expand( - self, source: Dict[str, Any], expr: Optional[str], prev: Optional[str] = None - ) -> Optional[str]: - if expr == prev or expr in NODE_KEYS: - return expr - - nxt: Optional[str] - # type error: Argument 1 to "_prep_expand" of "Context" has incompatible type "Optional[str]"; expected "str" - is_term, pfx, nxt = self._prep_expand(expr) # type: ignore[arg-type] - if pfx: - iri = self._get_source_id(source, pfx) - if iri is None: - if pfx + ":" == self.vocab: - return expr - else: - term = self.terms.get(pfx) - if term: - iri = term.id - - if iri is None: - nxt = expr - else: - nxt = iri + nxt - else: - nxt = self._get_source_id(source, nxt) or nxt - if ":" not in nxt and self.vocab: - return self.vocab + nxt - - return self._rec_expand(source, nxt, expr) - - def _prep_expand(self, expr: str) -> Tuple[bool, Optional[str], str]: - if ":" not in expr: - return True, None, expr - pfx, local = expr.split(":", 1) - if not local.startswith("//"): - return False, pfx, local - else: - return False, None, expr - - def _get_source_id(self, source: Dict[str, Any], key: str) -> Optional[str]: - # .. from source dict or if already defined - term = source.get(key) - if term is None: - dfn = self.terms.get(key) - if dfn: - term = dfn.id - elif isinstance(term, dict): - term = term.get(ID) - return term - - def _term_dict(self, term: Term) -> Union[Dict[str, Any], str]: - tdict: Dict[str, Any] = {} - if term.type != UNDEF: - tdict[TYPE] = self.shrink_iri(term.type) - if term.container: - tdict[CONTAINER] = list(term.container) - if term.language != UNDEF: - tdict[LANG] = term.language - if term.reverse: - tdict[REV] = term.id - else: - tdict[ID] = term.id - if tdict.keys() == {ID}: - return tdict[ID] - return tdict - - def to_dict(self) -> Dict[str, Any]: - """ - Returns a dictionary representation of the context that can be - serialized to JSON. - - :return: a dictionary representation of the context. - """ - r = {v: k for (k, v) in self._prefixes.items()} - r.update({term.name: self._term_dict(term) for term in self._lookup.values()}) - if self.base: - r[BASE] = self.base - if self.language: - r[LANG] = self.language - return r - - -Term = namedtuple( - "Term", - "id, name, type, container, index, language, reverse, context," "prefix, protected", -) - -Term.__new__.__defaults__ = (UNDEF, UNDEF, UNDEF, UNDEF, False, UNDEF, False, False) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/errors.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/errors.py deleted file mode 100644 index 6ba6e4b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/errors.py +++ /dev/null @@ -1,9 +0,0 @@ -# https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/errors.py -class JSONLDException(ValueError): # noqa: N818 - pass - - -# http://www.w3.org/TR/json-ld-api/#idl-def-JsonLdErrorCode.{code-message} -RECURSIVE_CONTEXT_INCLUSION = JSONLDException("recursive context inclusion") -INVALID_REMOTE_CONTEXT = JSONLDException("invalid remote context") -INVALID_CONTEXT_ENTRY = JSONLDException("invalid context entry") diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/keys.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/keys.py deleted file mode 100644 index 6b998ad..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/keys.py +++ /dev/null @@ -1,24 +0,0 @@ -# https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/keys.py -BASE = "@base" -CONTAINER = "@container" -CONTEXT = "@context" -# DIRECTION = u'@direction' -GRAPH = "@graph" -ID = "@id" -IMPORT = "@import" -INCLUDED = "@included" -INDEX = "@index" -JSON = "@json" -LANG = LANGUAGE = "@language" -LIST = "@list" -NEST = "@nest" -NONE = "@none" -PREFIX = "@prefix" -PROPAGATE = "@propagate" -PROTECTED = "@protected" -REV = REVERSE = "@reverse" -SET = "@set" -TYPE = "@type" -VALUE = "@value" -VERSION = "@version" -VOCAB = "@vocab" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/util.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/util.py deleted file mode 100644 index 097a90b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/shared/jsonld/util.py +++ /dev/null @@ -1,355 +0,0 @@ -# https://github.com/RDFLib/rdflib-jsonld/blob/feature/json-ld-1.1/rdflib_jsonld/util.py -from __future__ import annotations - -import json -import pathlib -from html.parser import HTMLParser -from io import StringIO, TextIOBase, TextIOWrapper -from typing import IO, TYPE_CHECKING, Any, Dict, List, Optional, TextIO, Tuple, Union - -if TYPE_CHECKING: - import json -else: - try: - import json - - assert json # workaround for pyflakes issue #13 - except ImportError: - import simplejson as json - -from posixpath import normpath, sep -from typing import TYPE_CHECKING, cast -from urllib.parse import urljoin, urlsplit, urlunsplit - -try: - import orjson - - _HAS_ORJSON = True -except ImportError: - orjson = None # type: ignore[assignment, unused-ignore] - _HAS_ORJSON = False - - -from rdflib.parser import ( - BytesIOWrapper, - InputSource, - PythonInputSource, - StringInputSource, - URLInputSource, - create_input_source, -) - - -def source_to_json( - source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] - ], - fragment_id: Optional[str] = None, - extract_all_scripts: Optional[bool] = False, -) -> Tuple[Union[Dict, List[Dict]], Any]: - """Extract JSON from a source document. - - The source document can be JSON or HTML with embedded JSON script elements (type attribute = "application/ld+json"). - To process as HTML ``source.content_type`` must be set to "text/html" or "application/xhtml+xml". - - :param source: the input source document (JSON or HTML) - - :param fragment_id: if source is an HTML document then extract only the script element with matching id attribute, defaults to None - - :param extract_all_scripts: if source is an HTML document then extract all script elements (unless fragment_id is provided), defaults to False (extract only the first script element) - - :return: Tuple with the extracted JSON document and value of the HTML base element - """ - - if isinstance(source, PythonInputSource): - return source.data, None - - if isinstance(source, StringInputSource): - # A StringInputSource is assumed to be never a HTMLJSON doc - html_base: Any = None - # We can get the original string from the StringInputSource - # It's hidden in the BytesIOWrapper 'wrapped' attribute - b_stream = source.getByteStream() - original_string: Optional[str] = None - json_dict: Union[Dict, List[Dict]] - if isinstance(b_stream, BytesIOWrapper): - wrapped_inner = cast(Union[str, StringIO, TextIOBase], b_stream.wrapped) - if isinstance(wrapped_inner, str): - original_string = wrapped_inner - elif isinstance(wrapped_inner, StringIO): - original_string = wrapped_inner.getvalue() - if _HAS_ORJSON: - if original_string is not None: - json_dict = orjson.loads(original_string) - elif isinstance(b_stream, BytesIOWrapper): - # use the CharacterStream instead - c_stream = source.getCharacterStream() - json_dict = orjson.loads(c_stream.read()) - else: - # orjson assumes its in utf-8 encoding so - # don't bother to check the source.getEncoding() - json_dict = orjson.loads(b_stream.read()) - else: - if original_string is not None: - json_dict = json.loads(original_string) - else: - json_dict = json.load(source.getCharacterStream()) - return json_dict, html_base - - # TODO: conneg for JSON (fix support in rdflib's URLInputSource!) - source = create_input_source(source, format="json-ld") - try: - content_type = source.content_type - except (AttributeError, LookupError): - content_type = None - - is_html = content_type is not None and content_type.lower() in ( - "text/html", - "application/xhtml+xml", - ) - if is_html: - html_docparser: Optional[HTMLJSONParser] = HTMLJSONParser( - fragment_id=fragment_id, extract_all_scripts=extract_all_scripts - ) - else: - html_docparser = None - try: - b_stream = source.getByteStream() - except (AttributeError, LookupError): - b_stream = None - try: - c_stream = source.getCharacterStream() - except (AttributeError, LookupError): - c_stream = None - if b_stream is None and c_stream is None: - raise ValueError( - f"Source does not have a character stream or a byte stream and cannot be used {type(source)}" - ) - try: - b_encoding: Optional[str] = None if b_stream is None else source.getEncoding() - except (AttributeError, LookupError): - b_encoding = None - underlying_string: Optional[str] = None - if b_stream is not None and isinstance(b_stream, BytesIOWrapper): - # Try to find an underlying wrapped Unicode string to use? - wrapped_inner = b_stream.wrapped - if isinstance(wrapped_inner, str): - underlying_string = wrapped_inner - elif isinstance(wrapped_inner, StringIO): - underlying_string = wrapped_inner.getvalue() - try: - if is_html and html_docparser is not None: - # Offload parsing to the HTMLJSONParser - if underlying_string is not None: - html_string: str = underlying_string - elif c_stream is not None: - html_string = c_stream.read() - else: - if TYPE_CHECKING: - assert b_stream is not None - if b_encoding is None: - b_encoding = "utf-8" - html_string = TextIOWrapper(b_stream, encoding=b_encoding).read() - html_docparser.feed(html_string) - json_dict, html_base = html_docparser.get_json(), html_docparser.get_base() - elif _HAS_ORJSON: - html_base = None - if underlying_string is not None: - json_dict = orjson.loads(underlying_string) - elif ( - (b_stream is not None and isinstance(b_stream, BytesIOWrapper)) - or b_stream is None - ) and c_stream is not None: - # use the CharacterStream instead - json_dict = orjson.loads(c_stream.read()) - else: - if TYPE_CHECKING: - assert b_stream is not None - # b_stream is not None - json_dict = orjson.loads(b_stream.read()) - else: - html_base = None - if underlying_string is not None: - return json.loads(underlying_string) - if c_stream is not None: - use_stream = c_stream - else: - if TYPE_CHECKING: - assert b_stream is not None - # b_stream is not None - if b_encoding is None: - b_encoding = "utf-8" - use_stream = TextIOWrapper(b_stream, encoding=b_encoding) - json_dict = json.load(use_stream) - return json_dict, html_base - finally: - if b_stream is not None: - try: - b_stream.close() - except AttributeError: - pass - if c_stream is not None: - try: - c_stream.close() - except AttributeError: - pass - - -VOCAB_DELIMS = ("#", "/", ":") - - -def split_iri(iri: str) -> Tuple[str, Optional[str]]: - for delim in VOCAB_DELIMS: - at = iri.rfind(delim) - if at > -1: - return iri[: at + 1], iri[at + 1 :] - return iri, None - - -def norm_url(base: str, url: str) -> str: - """ - >>> norm_url('http://example.org/', '/one') - 'http://example.org/one' - >>> norm_url('http://example.org/', '/one#') - 'http://example.org/one#' - >>> norm_url('http://example.org/one', 'two') - 'http://example.org/two' - >>> norm_url('http://example.org/one/', 'two') - 'http://example.org/one/two' - >>> norm_url('http://example.org/', 'http://example.net/one') - 'http://example.net/one' - >>> norm_url('http://example.org/', 'http://example.org//one') - 'http://example.org//one' - """ - if "://" in url: - return url - - # Fix for URNs - parsed_base = urlsplit(base) - parsed_url = urlsplit(url) - if parsed_url.scheme: - # Assume full URL - return url - if parsed_base.scheme in ("urn", "urn-x"): - # No scheme -> assume relative and join paths - base_path_parts = parsed_base.path.split("/", 1) - base_path = "/" + (base_path_parts[1] if len(base_path_parts) > 1 else "") - joined_path = urljoin(base_path, parsed_url.path) - fragment = f"#{parsed_url.fragment}" if parsed_url.fragment else "" - result = f"{parsed_base.scheme}:{base_path_parts[0]}{joined_path}{fragment}" - else: - parts = urlsplit(urljoin(base, url)) - path = normpath(parts[2]) - if sep != "/": - path = "/".join(path.split(sep)) - if parts[2].endswith("/") and not path.endswith("/"): - path += "/" - result = urlunsplit(parts[0:2] + (path,) + parts[3:]) - if url.endswith("#") and not result.endswith("#"): - result += "#" - return result - - -# type error: Missing return statement -def context_from_urlinputsource(source: URLInputSource) -> Optional[str]: # type: ignore[return] - """ - Please note that JSON-LD documents served with the application/ld+json media type - MUST have all context information, including references to external contexts, - within the body of the document. Contexts linked via a - http://www.w3.org/ns/json-ld#context HTTP Link Header MUST be - ignored for such documents. - """ - if source.content_type != "application/ld+json": - try: - # source.links is the new way of getting Link headers from URLInputSource - links = source.links - except AttributeError: - # type error: Return value expected - return # type: ignore[return-value] - for link in links: - if ' rel="http://www.w3.org/ns/json-ld#context"' in link: - i, j = link.index("<"), link.index(">") - if i > -1 and j > -1: - # type error: Value of type variable "AnyStr" of "urljoin" cannot be "Optional[str]" - return urljoin(source.url, link[i + 1 : j]) # type: ignore[type-var] - - -__all__ = [ - "json", - "source_to_json", - "split_iri", - "norm_url", - "context_from_urlinputsource", - "orjson", - "_HAS_ORJSON", -] - - -class HTMLJSONParser(HTMLParser): - def __init__( - self, - fragment_id: Optional[str] = None, - extract_all_scripts: Optional[bool] = False, - ): - super().__init__() - self.fragment_id = fragment_id - self.json: List[Dict] = [] - self.contains_json = False - self.fragment_id_does_not_match = False - self.base = None - self.extract_all_scripts = extract_all_scripts - self.script_count = 0 - - def handle_starttag(self, tag, attrs): - self.contains_json = False - self.fragment_id_does_not_match = False - - # Only set self. contains_json to True if the - # type is 'application/ld+json' - if tag == "script": - for attr, value in attrs: - if attr == "type" and value == "application/ld+json": - self.contains_json = True - elif attr == "id" and self.fragment_id and value != self.fragment_id: - self.fragment_id_does_not_match = True - - elif tag == "base": - for attr, value in attrs: - if attr == "href": - self.base = value - - def handle_data(self, data): - # Only do something when we know the context is a - # script element containing application/ld+json - - if self.contains_json is True and self.fragment_id_does_not_match is False: - - if not self.extract_all_scripts and self.script_count > 0: - return - - if data.strip() == "": - # skip empty data elements - return - - # Try to parse the json - if _HAS_ORJSON: - # orjson can load a unicode string - # if that's the only thing we have, - # its not worth encoding it to bytes - parsed = orjson.loads(data) - else: - parsed = json.loads(data) - - # Add to the result document - if isinstance(parsed, list): - self.json.extend(parsed) - else: - self.json.append(parsed) - - self.script_count += 1 - - def get_json(self) -> List[Dict]: - return self.json - - def get_base(self): - return self.base diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/__init__.py deleted file mode 100644 index 0ab7f80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/__init__.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -SPARQL implementation for RDFLib - -.. versionadded:: 4.0 -""" - -from importlib.metadata import entry_points -from typing import TYPE_CHECKING - -SPARQL_LOAD_GRAPHS = True -""" -If True, using FROM and FROM NAMED -will load/parse more data -""" - - -SPARQL_DEFAULT_GRAPH_UNION = True -""" -If True - the default graph in the RDF Dataset is the union of all -named graphs (like RDFLib's ConjunctiveGraph) -""" - - -CUSTOM_EVALS = {} -""" -Custom evaluation functions - -These must be functions taking (ctx, part) and raise -NotImplementedError if they cannot handle a certain part -""" - - -PLUGIN_ENTRY_POINT = "rdf.plugins.sparqleval" - - -from . import operators, parser, parserutils -from .processor import prepareQuery, prepareUpdate, processUpdate - -assert parser -assert operators -assert parserutils - - -all_entry_points = entry_points() -if hasattr(all_entry_points, "select"): - for ep in all_entry_points.select(group=PLUGIN_ENTRY_POINT): - CUSTOM_EVALS[ep.name] = ep.load() -else: - # Prior to Python 3.10, this returns a dict instead of the selection interface - if TYPE_CHECKING: - assert isinstance(all_entry_points, dict) - for ep in all_entry_points.get(PLUGIN_ENTRY_POINT, []): - CUSTOM_EVALS[ep.name] = ep.load() - -__all__ = [ - "prepareQuery", - "prepareUpdate", - "processUpdate", - "operators", - "parser", - "parserutils", - "CUSTOM_EVALS", -] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/aggregates.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/aggregates.py deleted file mode 100644 index 12972e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/aggregates.py +++ /dev/null @@ -1,316 +0,0 @@ -""" -Aggregation functions -""" - -from __future__ import annotations - -from decimal import Decimal -from typing import ( - Any, - Callable, - Dict, - Iterable, - List, - Mapping, - MutableMapping, - Optional, - Set, - Tuple, - TypeVar, - Union, - overload, -) - -from rdflib.namespace import XSD -from rdflib.plugins.sparql.datatypes import type_promotion -from rdflib.plugins.sparql.evalutils import _eval, _val -from rdflib.plugins.sparql.operators import numeric -from rdflib.plugins.sparql.parserutils import CompValue -from rdflib.plugins.sparql.sparql import FrozenBindings, NotBoundError, SPARQLTypeError -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - - -class Accumulator: - """abstract base class for different aggregation functions""" - - def __init__(self, aggregation: CompValue): - self.get_value: Callable[[], Optional[Literal]] - self.update: Callable[[FrozenBindings, Aggregator], None] - self.var = aggregation.res - self.expr = aggregation.vars - if not aggregation.distinct: - # type error: Cannot assign to a method - self.use_row = self.dont_care # type: ignore[method-assign] - self.distinct = False - else: - self.distinct = aggregation.distinct - self.seen: Set[Any] = set() - - def dont_care(self, row: FrozenBindings) -> bool: - """skips distinct test""" - return True - - def use_row(self, row: FrozenBindings) -> bool: - """tests distinct with set""" - return _eval(self.expr, row) not in self.seen - - def set_value(self, bindings: MutableMapping[Variable, Identifier]) -> None: - """sets final value in bindings""" - # type error: Incompatible types in assignment (expression has type "Optional[Literal]", target has type "Identifier") - bindings[self.var] = self.get_value() # type: ignore[assignment] - - -class Counter(Accumulator): - def __init__(self, aggregation: CompValue): - super(Counter, self).__init__(aggregation) - self.value = 0 - if self.expr == "*": - # cannot eval "*" => always use the full row - # type error: Cannot assign to a method - self.eval_row = self.eval_full_row # type: ignore[assignment] - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - val = self.eval_row(row) - except NotBoundError: - # skip UNDEF - return - self.value += 1 - if self.distinct: - self.seen.add(val) - - def get_value(self) -> Literal: - return Literal(self.value) - - def eval_row(self, row: FrozenBindings) -> Identifier: - return _eval(self.expr, row) - - def eval_full_row(self, row: FrozenBindings) -> FrozenBindings: - return row - - def use_row(self, row: FrozenBindings) -> bool: - try: - return self.eval_row(row) not in self.seen - except NotBoundError: - # happens when counting zero optional nodes. See issue #2229 - return False - - -@overload -def type_safe_numbers(*args: int) -> Tuple[int]: ... - - -@overload -def type_safe_numbers( - *args: Union[Decimal, float, int] -) -> Tuple[Union[float, int]]: ... - - -def type_safe_numbers(*args: Union[Decimal, float, int]) -> Iterable[Union[float, int]]: - if any(isinstance(arg, float) for arg in args) and any( - isinstance(arg, Decimal) for arg in args - ): - return map(float, args) - # type error: Incompatible return value type (got "Tuple[Union[Decimal, float, int], ...]", expected "Iterable[Union[float, int]]") - # NOTE on type error: if args contains a Decimal it will nopt get here. - return args # type: ignore[return-value] - - -class Sum(Accumulator): - def __init__(self, aggregation: CompValue): - super(Sum, self).__init__(aggregation) - self.value = 0 - self.datatype: Optional[str] = None - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - value = _eval(self.expr, row) - dt = self.datatype - if dt is None: - dt = value.datatype - else: - # type error: Argument 1 to "type_promotion" has incompatible type "str"; expected "URIRef" - dt = type_promotion(dt, value.datatype) # type: ignore[arg-type] - self.datatype = dt - self.value = sum(type_safe_numbers(self.value, numeric(value))) - if self.distinct: - self.seen.add(value) - except NotBoundError: - # skip UNDEF - pass - - def get_value(self) -> Literal: - return Literal(self.value, datatype=self.datatype) - - -class Average(Accumulator): - def __init__(self, aggregation: CompValue): - super(Average, self).__init__(aggregation) - self.counter = 0 - self.sum = 0 - self.datatype: Optional[str] = None - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - value = _eval(self.expr, row) - dt = self.datatype - self.sum = sum(type_safe_numbers(self.sum, numeric(value))) - if dt is None: - dt = value.datatype - else: - # type error: Argument 1 to "type_promotion" has incompatible type "str"; expected "URIRef" - dt = type_promotion(dt, value.datatype) # type: ignore[arg-type] - self.datatype = dt - if self.distinct: - self.seen.add(value) - self.counter += 1 - # skip UNDEF or BNode => SPARQLTypeError - except NotBoundError: - pass - except SPARQLTypeError: - pass - - def get_value(self) -> Literal: - if self.counter == 0: - return Literal(0) - if self.datatype in (XSD.float, XSD.double): - return Literal(self.sum / self.counter) - else: - return Literal(Decimal(self.sum) / Decimal(self.counter)) - - -class Extremum(Accumulator): - """abstract base class for Minimum and Maximum""" - - def __init__(self, aggregation: CompValue): - self.compare: Callable[[Any, Any], Any] - super(Extremum, self).__init__(aggregation) - self.value: Any = None - # DISTINCT would not change the value for MIN or MAX - # type error: Cannot assign to a method - self.use_row = self.dont_care # type: ignore[method-assign] - - def set_value(self, bindings: MutableMapping[Variable, Identifier]) -> None: - if self.value is not None: - # simply do not set if self.value is still None - bindings[self.var] = Literal(self.value) - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - if self.value is None: - self.value = _eval(self.expr, row) - else: - # self.compare is implemented by Minimum/Maximum - self.value = self.compare(self.value, _eval(self.expr, row)) - # skip UNDEF or BNode => SPARQLTypeError - except NotBoundError: - pass - except SPARQLTypeError: - pass - - -_ValueT = TypeVar("_ValueT", Variable, BNode, URIRef, Literal) - - -class Minimum(Extremum): - def compare(self, val1: _ValueT, val2: _ValueT) -> _ValueT: - return min(val1, val2, key=_val) - - -class Maximum(Extremum): - def compare(self, val1: _ValueT, val2: _ValueT) -> _ValueT: - return max(val1, val2, key=_val) - - -class Sample(Accumulator): - """takes the first eligible value""" - - def __init__(self, aggregation): - super(Sample, self).__init__(aggregation) - # DISTINCT would not change the value - # type error: Cannot assign to a method - self.use_row = self.dont_care # type: ignore[method-assign] - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - # set the value now - aggregator.bindings[self.var] = _eval(self.expr, row) - # and skip this accumulator for future rows - del aggregator.accumulators[self.var] - except NotBoundError: - pass - - def get_value(self) -> None: - # set None if no value was set - return None - - -class GroupConcat(Accumulator): - value: List[Literal] - - def __init__(self, aggregation: CompValue): - super(GroupConcat, self).__init__(aggregation) - # only GROUPCONCAT needs to have a list as accumulator - self.value = [] - if aggregation.separator is None: - self.separator = " " - else: - self.separator = aggregation.separator - - def update(self, row: FrozenBindings, aggregator: Aggregator) -> None: - try: - value = _eval(self.expr, row) - # skip UNDEF - if isinstance(value, NotBoundError): - return - self.value.append(value) - if self.distinct: - self.seen.add(value) - # skip UNDEF - # NOTE: It seems like this is not the way undefined values occur, they - # come through not as exceptions but as values. This is left here - # however as it may occur in some cases. - # TODO: Consider removing this. - except NotBoundError: - pass - - def get_value(self) -> Literal: - return Literal(self.separator.join(str(v) for v in self.value)) - - -class Aggregator: - """combines different Accumulator objects""" - - accumulator_classes = { - "Aggregate_Count": Counter, - "Aggregate_Sample": Sample, - "Aggregate_Sum": Sum, - "Aggregate_Avg": Average, - "Aggregate_Min": Minimum, - "Aggregate_Max": Maximum, - "Aggregate_GroupConcat": GroupConcat, - } - - def __init__(self, aggregations: List[CompValue]): - self.bindings: Dict[Variable, Identifier] = {} - self.accumulators: Dict[str, Accumulator] = {} - for a in aggregations: - accumulator_class = self.accumulator_classes.get(a.name) - if accumulator_class is None: - raise Exception("Unknown aggregate function " + a.name) - self.accumulators[a.res] = accumulator_class(a) - - def update(self, row: FrozenBindings) -> None: - """update all own accumulators""" - # SAMPLE accumulators may delete themselves - # => iterate over list not generator - - for acc in list(self.accumulators.values()): - if acc.use_row(row): - acc.update(row, self) - - def get_bindings(self) -> Mapping[Variable, Identifier]: - """calculate and set last values""" - for acc in self.accumulators.values(): - acc.set_value(self.bindings) - return self.bindings diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/algebra.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/algebra.py deleted file mode 100644 index 5cb22d2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/algebra.py +++ /dev/null @@ -1,1696 +0,0 @@ -""" -Converting the 'parse-tree' output of pyparsing to a SPARQL Algebra expression - -http://www.w3.org/TR/sparql11-query/#sparqlQuery - -""" - -from __future__ import annotations - -import collections -import functools -import operator -import typing -from functools import reduce -from typing import ( - Any, - Callable, - DefaultDict, - Dict, - Iterable, - List, - Mapping, - Optional, - Set, - Tuple, - overload, -) - -from pyparsing import ParseResults - -from rdflib.paths import ( - AlternativePath, - InvPath, - MulPath, - NegatedPath, - Path, - SequencePath, -) -from rdflib.plugins.sparql.operators import TrueFilter, and_ -from rdflib.plugins.sparql.operators import simplify as simplifyFilters -from rdflib.plugins.sparql.parserutils import CompValue, Expr -from rdflib.plugins.sparql.sparql import Prologue, Query, Update - -# --------------------------- -# Some convenience methods -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - - -def OrderBy(p: CompValue, expr: List[CompValue]) -> CompValue: - return CompValue("OrderBy", p=p, expr=expr) - - -def ToMultiSet(p: typing.Union[List[Dict[Variable, str]], CompValue]) -> CompValue: - return CompValue("ToMultiSet", p=p) - - -def Union(p1: CompValue, p2: CompValue) -> CompValue: - return CompValue("Union", p1=p1, p2=p2) - - -def Join(p1: CompValue, p2: Optional[CompValue]) -> CompValue: - return CompValue("Join", p1=p1, p2=p2) - - -def Minus(p1: CompValue, p2: CompValue) -> CompValue: - return CompValue("Minus", p1=p1, p2=p2) - - -def Graph(term: Identifier, graph: CompValue) -> CompValue: - return CompValue("Graph", term=term, p=graph) - - -def BGP( - triples: Optional[List[Tuple[Identifier, Identifier, Identifier]]] = None -) -> CompValue: - return CompValue("BGP", triples=triples or []) - - -def LeftJoin(p1: CompValue, p2: CompValue, expr) -> CompValue: - return CompValue("LeftJoin", p1=p1, p2=p2, expr=expr) - - -def Filter(expr: Expr, p: CompValue) -> CompValue: - return CompValue("Filter", expr=expr, p=p) - - -def Extend( - p: CompValue, expr: typing.Union[Identifier, Expr], var: Variable -) -> CompValue: - return CompValue("Extend", p=p, expr=expr, var=var) - - -def Values(res: List[Dict[Variable, str]]) -> CompValue: - return CompValue("values", res=res) - - -def Project(p: CompValue, PV: List[Variable]) -> CompValue: - return CompValue("Project", p=p, PV=PV) - - -def Group(p: CompValue, expr: Optional[List[Variable]] = None) -> CompValue: - return CompValue("Group", p=p, expr=expr) - - -def _knownTerms( - triple: Tuple[Identifier, Identifier, Identifier], - varsknown: Set[typing.Union[BNode, Variable]], - varscount: Dict[Identifier, int], -) -> Tuple[int, int, bool]: - return ( - len( - [ - x - for x in triple - if x not in varsknown and isinstance(x, (Variable, BNode)) - ] - ), - -sum(varscount.get(x, 0) for x in triple), - not isinstance(triple[2], Literal), - ) - - -def reorderTriples( - l_: Iterable[Tuple[Identifier, Identifier, Identifier]] -) -> List[Tuple[Identifier, Identifier, Identifier]]: - """ - Reorder triple patterns so that we execute the - ones with most bindings first - """ - - def _addvar(term: str, varsknown: Set[typing.Union[Variable, BNode]]): - if isinstance(term, (Variable, BNode)): - varsknown.add(term) - - # NOTE on type errors: most of these are because the same variable is used - # for different types. - - # type error: List comprehension has incompatible type List[Tuple[None, Tuple[Identifier, Identifier, Identifier]]]; expected List[Tuple[Identifier, Identifier, Identifier]] - l_ = [(None, x) for x in l_] # type: ignore[misc] - varsknown: Set[typing.Union[BNode, Variable]] = set() - varscount: Dict[Identifier, int] = collections.defaultdict(int) - for t in l_: - for c in t[1]: - if isinstance(c, (Variable, BNode)): - varscount[c] += 1 - i = 0 - - # Done in steps, sort by number of bound terms - # the top block of patterns with the most bound terms is kept - # the rest is resorted based on the vars bound after the first - # block is evaluated - - # we sort by decorate/undecorate, since we need the value of the sort keys - - while i < len(l_): - # type error: Generator has incompatible item type "Tuple[Any, Identifier]"; expected "Tuple[Identifier, Identifier, Identifier]" - # type error: Argument 1 to "_knownTerms" has incompatible type "Identifier"; expected "Tuple[Identifier, Identifier, Identifier]" - l_[i:] = sorted((_knownTerms(x[1], varsknown, varscount), x[1]) for x in l_[i:]) # type: ignore[misc,arg-type] - # type error: Incompatible types in assignment (expression has type "str", variable has type "Tuple[Identifier, Identifier, Identifier]") - t = l_[i][0][0] # type: ignore[assignment] # top block has this many terms bound - j = 0 - while i + j < len(l_) and l_[i + j][0][0] == t: - for c in l_[i + j][1]: - _addvar(c, varsknown) - j += 1 - i += 1 - - # type error: List comprehension has incompatible type List[Identifier]; expected List[Tuple[Identifier, Identifier, Identifier]] - return [x[1] for x in l_] # type: ignore[misc] - - -def triples( - l: typing.Union[ # noqa: E741 - List[List[Identifier]], List[Tuple[Identifier, Identifier, Identifier]] - ] -) -> List[Tuple[Identifier, Identifier, Identifier]]: - _l = reduce(lambda x, y: x + y, l) - if (len(_l) % 3) != 0: - raise Exception("these aint triples") - return reorderTriples((_l[x], _l[x + 1], _l[x + 2]) for x in range(0, len(_l), 3)) - - -# type error: Missing return statement -def translatePName( # type: ignore[return] - p: typing.Union[CompValue, str], prologue: Prologue -) -> Optional[Identifier]: - """ - Expand prefixed/relative URIs - """ - if isinstance(p, CompValue): - if p.name == "pname": - # type error: Incompatible return value type (got "Union[CompValue, str, None]", expected "Optional[Identifier]") - return prologue.absolutize(p) # type: ignore[return-value] - if p.name == "literal": - # type error: Argument "datatype" to "Literal" has incompatible type "Union[CompValue, str, None]"; expected "Optional[str]" - return Literal( - p.string, lang=p.lang, datatype=prologue.absolutize(p.datatype) # type: ignore[arg-type] - ) - elif isinstance(p, URIRef): - # type error: Incompatible return value type (got "Union[CompValue, str, None]", expected "Optional[Identifier]") - return prologue.absolutize(p) # type: ignore[return-value] - - -@overload -def translatePath(p: URIRef) -> None: ... - - -@overload -def translatePath(p: CompValue) -> Path: ... - - -# type error: Missing return statement -def translatePath(p: typing.Union[CompValue, URIRef]) -> Optional[Path]: # type: ignore[return] - """ - Translate PropertyPath expressions - """ - - if isinstance(p, CompValue): - if p.name == "PathAlternative": - if len(p.part) == 1: - return p.part[0] - else: - return AlternativePath(*p.part) - - elif p.name == "PathSequence": - if len(p.part) == 1: - return p.part[0] - else: - return SequencePath(*p.part) - - elif p.name == "PathElt": - if not p.mod: - return p.part - else: - if isinstance(p.part, list): - if len(p.part) != 1: - raise Exception("Denkfehler!") - - return MulPath(p.part[0], p.mod) - else: - return MulPath(p.part, p.mod) - - elif p.name == "PathEltOrInverse": - if isinstance(p.part, list): - if len(p.part) != 1: - raise Exception("Denkfehler!") - return InvPath(p.part[0]) - else: - return InvPath(p.part) - - elif p.name == "PathNegatedPropertySet": - if isinstance(p.part, list): - return NegatedPath(AlternativePath(*p.part)) - else: - return NegatedPath(p.part) - - -def translateExists( - e: typing.Union[Expr, Literal, Variable, URIRef] -) -> typing.Union[Expr, Literal, Variable, URIRef]: - """ - Translate the graph pattern used by EXISTS and NOT EXISTS - http://www.w3.org/TR/sparql11-query/#sparqlCollectFilters - """ - - def _c(n): - if isinstance(n, CompValue): - if n.name in ("Builtin_EXISTS", "Builtin_NOTEXISTS"): - n.graph = translateGroupGraphPattern(n.graph) - if n.graph.name == "Filter": - # filters inside (NOT) EXISTS can see vars bound outside - n.graph.no_isolated_scope = True - - e = traverse(e, visitPost=_c) - - return e - - -def collectAndRemoveFilters(parts: List[CompValue]) -> Optional[Expr]: - """ - - FILTER expressions apply to the whole group graph pattern in which - they appear. - - http://www.w3.org/TR/sparql11-query/#sparqlCollectFilters - """ - - filters = [] - - i = 0 - while i < len(parts): - p = parts[i] - if p.name == "Filter": - filters.append(translateExists(p.expr)) - parts.pop(i) - else: - i += 1 - - if filters: - # type error: Argument 1 to "and_" has incompatible type "*List[Union[Expr, Literal, Variable]]"; expected "Expr" - return and_(*filters) # type: ignore[arg-type] - - return None - - -def translateGroupOrUnionGraphPattern(graphPattern: CompValue) -> Optional[CompValue]: - A: Optional[CompValue] = None - - for g in graphPattern.graph: - g = translateGroupGraphPattern(g) - if not A: - A = g - else: - A = Union(A, g) - return A - - -def translateGraphGraphPattern(graphPattern: CompValue) -> CompValue: - return Graph(graphPattern.term, translateGroupGraphPattern(graphPattern.graph)) - - -def translateInlineData(graphPattern: CompValue) -> CompValue: - return ToMultiSet(translateValues(graphPattern)) - - -def translateGroupGraphPattern(graphPattern: CompValue) -> CompValue: - """ - http://www.w3.org/TR/sparql11-query/#convertGraphPattern - """ - - if graphPattern.translated: - # This occurs if it is attempted to translate a group graph pattern twice, - # which occurs with nested (NOT) EXISTS filters. Simply return the already - # translated pattern instead. - return graphPattern - if graphPattern.name == "SubSelect": - # The first output from translate cannot be None for a subselect query - # as it can only be None for certain DESCRIBE queries. - # type error: Argument 1 to "ToMultiSet" has incompatible type "Optional[CompValue]"; - # expected "Union[List[Dict[Variable, str]], CompValue]" - return ToMultiSet(translate(graphPattern)[0]) # type: ignore[arg-type] - - if not graphPattern.part: - graphPattern.part = [] # empty { } - - filters = collectAndRemoveFilters(graphPattern.part) - - g: List[CompValue] = [] - for p in graphPattern.part: - if p.name == "TriplesBlock": - # merge adjacent TripleBlocks - if not (g and g[-1].name == "BGP"): - g.append(BGP()) - g[-1]["triples"] += triples(p.triples) - else: - g.append(p) - - G = BGP() - for p in g: - if p.name == "OptionalGraphPattern": - A = translateGroupGraphPattern(p.graph) - if A.name == "Filter": - G = LeftJoin(G, A.p, A.expr) - else: - G = LeftJoin(G, A, TrueFilter) - elif p.name == "MinusGraphPattern": - G = Minus(p1=G, p2=translateGroupGraphPattern(p.graph)) - elif p.name == "GroupOrUnionGraphPattern": - G = Join(p1=G, p2=translateGroupOrUnionGraphPattern(p)) - elif p.name == "GraphGraphPattern": - G = Join(p1=G, p2=translateGraphGraphPattern(p)) - elif p.name == "InlineData": - G = Join(p1=G, p2=translateInlineData(p)) - elif p.name == "ServiceGraphPattern": - G = Join(p1=G, p2=p) - elif p.name in ("BGP", "Extend"): - G = Join(p1=G, p2=p) - elif p.name == "Bind": - # translateExists will translate the expression if it is EXISTS, and otherwise return - # the expression as is. This is needed because EXISTS has a graph pattern - # which must be translated to work properly during evaluation. - G = Extend(G, translateExists(p.expr), p.var) - - else: - raise Exception( - "Unknown part in GroupGraphPattern: %s - %s" % (type(p), p.name) - ) - - if filters: - G = Filter(expr=filters, p=G) - - # Mark this graph pattern as translated - G.translated = True - - return G - - -class StopTraversal(Exception): # noqa: N818 - def __init__(self, rv: bool): - self.rv = rv - - -def _traverse( - e: Any, - visitPre: Callable[[Any], Any] = lambda n: None, - visitPost: Callable[[Any], Any] = lambda n: None, -): - """ - Traverse a parse-tree, visit each node - - if visit functions return a value, replace current node - """ - _e = visitPre(e) - if _e is not None: - return _e - - if e is None: - return None - - if isinstance(e, (list, ParseResults)): - return [_traverse(x, visitPre, visitPost) for x in e] - elif isinstance(e, tuple): - return tuple([_traverse(x, visitPre, visitPost) for x in e]) - - elif isinstance(e, CompValue): - for k, val in e.items(): - e[k] = _traverse(val, visitPre, visitPost) - - _e = visitPost(e) - if _e is not None: - return _e - - return e - - -def _traverseAgg(e, visitor: Callable[[Any, Any], Any] = lambda n, v: None): - """ - Traverse a parse-tree, visit each node - - if visit functions return a value, replace current node - """ - - res = [] - - if isinstance(e, (list, ParseResults, tuple)): - res = [_traverseAgg(x, visitor) for x in e] - elif isinstance(e, CompValue): - for k, val in e.items(): - if val is not None: - res.append(_traverseAgg(val, visitor)) - - return visitor(e, res) - - -def traverse( - tree, - visitPre: Callable[[Any], Any] = lambda n: None, - visitPost: Callable[[Any], Any] = lambda n: None, - complete: Optional[bool] = None, -) -> Any: - """ - Traverse tree, visit each node with visit function - visit function may raise StopTraversal to stop traversal - if complete!=None, it is returned on complete traversal, - otherwise the transformed tree is returned - """ - try: - r = _traverse(tree, visitPre, visitPost) - if complete is not None: - return complete - return r - except StopTraversal as st: - return st.rv - - -def _hasAggregate(x) -> None: - """ - Traverse parse(sub)Tree - return true if any aggregates are used - """ - - if isinstance(x, CompValue): - if x.name.startswith("Aggregate_"): - raise StopTraversal(True) - - -# type error: Missing return statement -def _aggs(e, A) -> Optional[Variable]: # type: ignore[return] - """ - Collect Aggregates in A - replaces aggregates with variable references - """ - - # TODO: nested Aggregates? - - if isinstance(e, CompValue) and e.name.startswith("Aggregate_"): - A.append(e) - aggvar = Variable("__agg_%d__" % len(A)) - e["res"] = aggvar - return aggvar - - -# type error: Missing return statement -def _findVars(x, res: Set[Variable]) -> Optional[CompValue]: # type: ignore[return] - """ - Find all variables in a tree - """ - if isinstance(x, Variable): - res.add(x) - if isinstance(x, CompValue): - if x.name == "Bind": - res.add(x.var) - return x # stop recursion and finding vars in the expr - elif x.name == "SubSelect": - if x.projection: - res.update(v.var or v.evar for v in x.projection) - - return x - - -def _addVars(x, children: List[Set[Variable]]) -> Set[Variable]: - """ - find which variables may be bound by this part of the query - """ - if isinstance(x, Variable): - return set([x]) - elif isinstance(x, CompValue): - if x.name == "RelationalExpression": - x["_vars"] = set() - elif x.name == "Extend": - # vars only used in the expr for a bind should not be included - x["_vars"] = reduce( - operator.or_, - [child for child, part in zip(children, x) if part != "expr"], - set(), - ) - - else: - x["_vars"] = set(reduce(operator.or_, children, set())) - - if x.name == "SubSelect": - if x.projection: - s = set(v.var or v.evar for v in x.projection) - else: - s = set() - - return s - - return x["_vars"] - - return reduce(operator.or_, children, set()) - - -# type error: Missing return statement -def _sample(e: typing.Union[CompValue, List[Expr], Expr, List[str], Variable], v: Optional[Variable] = None) -> Optional[CompValue]: # type: ignore[return] - """ - For each unaggregated variable V in expr - Replace V with Sample(V) - """ - if isinstance(e, CompValue) and e.name.startswith("Aggregate_"): - return e # do not replace vars in aggregates - if isinstance(e, Variable) and v != e: - return CompValue("Aggregate_Sample", vars=e) - - -def _simplifyFilters(e: Any) -> Any: - if isinstance(e, Expr): - return simplifyFilters(e) - - -def translateAggregates( - q: CompValue, M: CompValue -) -> Tuple[CompValue, List[Tuple[Variable, Variable]]]: - E: List[Tuple[Variable, Variable]] = [] - A: List[CompValue] = [] - - # collect/replace aggs in : - # select expr as ?var - if q.projection: - for v in q.projection: - if v.evar: - v.expr = traverse(v.expr, functools.partial(_sample, v=v.evar)) - v.expr = traverse(v.expr, functools.partial(_aggs, A=A)) - - # having clause - if traverse(q.having, _hasAggregate, complete=True): - q.having = traverse(q.having, _sample) - traverse(q.having, functools.partial(_aggs, A=A)) - - # order by - if traverse(q.orderby, _hasAggregate, complete=False): - q.orderby = traverse(q.orderby, _sample) - traverse(q.orderby, functools.partial(_aggs, A=A)) - - # sample all other select vars - # TODO: only allowed for vars in group-by? - if q.projection: - for v in q.projection: - if v.var: - rv = Variable("__agg_%d__" % (len(A) + 1)) - A.append(CompValue("Aggregate_Sample", vars=v.var, res=rv)) - E.append((rv, v.var)) - - return CompValue("AggregateJoin", A=A, p=M), E - - -def translateValues( - v: CompValue, -) -> typing.Union[List[Dict[Variable, str]], CompValue]: - # if len(v.var)!=len(v.value): - # raise Exception("Unmatched vars and values in ValueClause: "+str(v)) - - res: List[Dict[Variable, str]] = [] - if not v.var: - return res - if not v.value: - return res - if not isinstance(v.value[0], list): - for val in v.value: - res.append({v.var[0]: val}) - else: - for vals in v.value: - res.append(dict(zip(v.var, vals))) - - return Values(res) - - -def translate(q: CompValue) -> Tuple[Optional[CompValue], List[Variable]]: - """ - http://www.w3.org/TR/sparql11-query/#convertSolMod - - """ - - _traverse(q, _simplifyFilters) - - q.where = traverse(q.where, visitPost=translatePath) - - # TODO: Var scope test - VS: Set[Variable] = set() - - # All query types have a WHERE clause EXCEPT some DESCRIBE queries - # where only explicit IRIs are provided. - if q.name == "DescribeQuery": - # For DESCRIBE queries, use the vars provided in q.var. - # If there is no WHERE clause, vars should be explicit IRIs to describe. - # If there is a WHERE clause, vars can be any combination of explicit IRIs - # and variables. - VS = set(q.var) - - # If there is no WHERE clause, just return the vars projected - if q.where is None: - return None, list(VS) - - # Otherwise, evaluate the WHERE clause like SELECT DISTINCT - else: - q.modifier = "DISTINCT" - - else: - traverse(q.where, functools.partial(_findVars, res=VS)) - - # depth-first recursive generation of mapped query tree - M = translateGroupGraphPattern(q.where) - - aggregate = False - if q.groupby: - conditions = [] - # convert "GROUP BY (?expr as ?var)" to an Extend - for c in q.groupby.condition: - if isinstance(c, CompValue) and c.name == "GroupAs": - M = Extend(M, c.expr, c.var) - c = c.var - conditions.append(c) - - M = Group(p=M, expr=conditions) - aggregate = True - elif ( - traverse(q.having, _hasAggregate, complete=False) - or traverse(q.orderby, _hasAggregate, complete=False) - or any( - traverse(x.expr, _hasAggregate, complete=False) - for x in q.projection or [] - if x.evar - ) - ): - # if any aggregate is used, implicit group by - M = Group(p=M) - aggregate = True - - if aggregate: - M, aggregateAliases = translateAggregates(q, M) - else: - aggregateAliases = [] - - # Need to remove the aggregate var aliases before joining to VALUES; - # else the variable names won't match up correctly when aggregating. - for alias, var in aggregateAliases: - M = Extend(M, alias, var) - - # HAVING - if q.having: - M = Filter(expr=and_(*q.having.condition), p=M) - - # VALUES - if q.valuesClause: - M = Join(p1=M, p2=ToMultiSet(translateValues(q.valuesClause))) - - if not q.projection: - # select * - - # Find the first child projection in each branch of the mapped query tree, - # then include the variables it projects out in our projected variables. - for child_projection in _find_first_child_projections(M): - VS |= set(child_projection.PV) - - PV = list(VS) - else: - E = list() - PV = list() - for v in q.projection: - if v.var: - if v not in PV: - PV.append(v.var) - elif v.evar: - if v not in PV: - PV.append(v.evar) - - E.append((v.expr, v.evar)) - else: - raise Exception("I expected a var or evar here!") - - for e, v in E: - M = Extend(M, e, v) - - # ORDER BY - if q.orderby: - M = OrderBy( - M, - [ - CompValue("OrderCondition", expr=c.expr, order=c.order) - for c in q.orderby.condition - ], - ) - - # PROJECT - M = Project(M, PV) - - if q.modifier: - if q.modifier == "DISTINCT": - M = CompValue("Distinct", p=M) - elif q.modifier == "REDUCED": - M = CompValue("Reduced", p=M) - - if q.limitoffset: - offset = 0 - if q.limitoffset.offset is not None: - offset = q.limitoffset.offset.toPython() - - if q.limitoffset.limit is not None: - M = CompValue( - "Slice", p=M, start=offset, length=q.limitoffset.limit.toPython() - ) - else: - M = CompValue("Slice", p=M, start=offset) - - return M, PV - - -def _find_first_child_projections(M: CompValue) -> Iterable[CompValue]: - """ - Recursively find the first child instance of a Projection operation in each of - the branches of the query execution plan/tree. - """ - - for child_op in M.values(): - if isinstance(child_op, CompValue): - if child_op.name == "Project": - yield child_op - else: - for child_projection in _find_first_child_projections(child_op): - yield child_projection - - -# type error: Missing return statement -def simplify(n: Any) -> Optional[CompValue]: # type: ignore[return] - """Remove joins to empty BGPs""" - if isinstance(n, CompValue): - if n.name == "Join": - if n.p1.name == "BGP" and len(n.p1.triples) == 0: - return n.p2 - if n.p2.name == "BGP" and len(n.p2.triples) == 0: - return n.p1 - elif n.name == "BGP": - n["triples"] = reorderTriples(n.triples) - return n - - -def analyse(n: Any, children: Any) -> bool: - """ - Some things can be lazily joined. - This propegates whether they can up the tree - and sets lazy flags for all joins - """ - - if isinstance(n, CompValue): - if n.name == "Join": - n["lazy"] = all(children) - return False - elif n.name in ("Slice", "Distinct"): - return False - else: - return all(children) - else: - return True - - -def translatePrologue( - p: ParseResults, - base: Optional[str], - initNs: Optional[Mapping[str, Any]] = None, - prologue: Optional[Prologue] = None, -) -> Prologue: - if prologue is None: - prologue = Prologue() - prologue.base = "" - if base: - prologue.base = base - if initNs: - for k, v in initNs.items(): - prologue.bind(k, v) - - x: CompValue - for x in p: - if x.name == "Base": - prologue.base = x.iri - elif x.name == "PrefixDecl": - prologue.bind(x.prefix, prologue.absolutize(x.iri)) - - return prologue - - -def translateQuads( - quads: CompValue, -) -> Tuple[ - List[Tuple[Identifier, Identifier, Identifier]], - DefaultDict[str, List[Tuple[Identifier, Identifier, Identifier]]], -]: - if quads.triples: - alltriples = triples(quads.triples) - else: - alltriples = [] - - allquads: DefaultDict[str, List[Tuple[Identifier, Identifier, Identifier]]] = ( - collections.defaultdict(list) - ) - - if quads.quadsNotTriples: - for q in quads.quadsNotTriples: - if q.triples: - allquads[q.term] += triples(q.triples) - - return alltriples, allquads - - -def translateUpdate1(u: CompValue, prologue: Prologue) -> CompValue: - if u.name in ("Load", "Clear", "Drop", "Create"): - pass # no translation needed - elif u.name in ("Add", "Move", "Copy"): - pass - elif u.name in ("InsertData", "DeleteData", "DeleteWhere"): - t, q = translateQuads(u.quads) - u["quads"] = q - u["triples"] = t - if u.name in ("DeleteWhere", "DeleteData"): - pass # TODO: check for bnodes in triples - elif u.name == "Modify": - if u.delete: - u.delete["triples"], u.delete["quads"] = translateQuads(u.delete.quads) - if u.insert: - u.insert["triples"], u.insert["quads"] = translateQuads(u.insert.quads) - u["where"] = translateGroupGraphPattern(u.where) - else: - raise Exception("Unknown type of update operation: %s" % u) - - u.prologue = prologue - return u - - -def translateUpdate( - q: CompValue, - base: Optional[str] = None, - initNs: Optional[Mapping[str, Any]] = None, -) -> Update: - """ - Returns a list of SPARQL Update Algebra expressions - """ - - res: List[CompValue] = [] - prologue = None - if not q.request: - # type error: Incompatible return value type (got "List[CompValue]", expected "Update") - return res # type: ignore[return-value] - for p, u in zip(q.prologue, q.request): - prologue = translatePrologue(p, base, initNs, prologue) - - # absolutize/resolve prefixes - u = traverse(u, visitPost=functools.partial(translatePName, prologue=prologue)) - u = _traverse(u, _simplifyFilters) - - u = traverse(u, visitPost=translatePath) - - res.append(translateUpdate1(u, prologue)) - - # type error: Argument 1 to "Update" has incompatible type "Optional[Any]"; expected "Prologue" - return Update(prologue, res) # type: ignore[arg-type] - - -def translateQuery( - q: ParseResults, - base: Optional[str] = None, - initNs: Optional[Mapping[str, Any]] = None, -) -> Query: - """ - Translate a query-parsetree to a SPARQL Algebra Expression - - Return a rdflib.plugins.sparql.sparql.Query object - """ - - # We get in: (prologue, query) - - prologue = translatePrologue(q[0], base, initNs) - - # absolutize/resolve prefixes - q[1] = traverse( - q[1], visitPost=functools.partial(translatePName, prologue=prologue) - ) - - P, PV = translate(q[1]) - datasetClause = q[1].datasetClause - if q[1].name == "ConstructQuery": - template = triples(q[1].template) if q[1].template else None - - res = CompValue(q[1].name, p=P, template=template, datasetClause=datasetClause) - else: - res = CompValue(q[1].name, p=P, datasetClause=datasetClause, PV=PV) - - res = traverse(res, visitPost=simplify) - _traverseAgg(res, visitor=analyse) - _traverseAgg(res, _addVars) - - return Query(prologue, res) - - -class ExpressionNotCoveredException(Exception): # noqa: N818 - pass - - -class _AlgebraTranslator: - """ - Translator of a Query's algebra to its equivalent SPARQL (string). - - Coded as a class to support storage of state during the translation process, - without use of a file. - - Anticipated Usage: - - .. code-block:: python - - translated_query = _AlgebraTranslator(query).translateAlgebra() - - An external convenience function which wraps the above call, - `translateAlgebra`, is supplied, so this class does not need to be - referenced by client code at all in normal use. - """ - - def __init__(self, query_algebra: Query): - self.query_algebra = query_algebra - self.aggr_vars: DefaultDict[Identifier, List[Identifier]] = ( - collections.defaultdict(list) - ) - self._alg_translation: str = "" - - def _replace( - self, - old: str, - new: str, - search_from_match: str = None, - search_from_match_occurrence: int = None, - count: int = 1, - ): - def find_nth(haystack, needle, n): - start = haystack.lower().find(needle) - while start >= 0 and n > 1: - start = haystack.lower().find(needle, start + len(needle)) - n -= 1 - return start - - if search_from_match and search_from_match_occurrence: - position = find_nth( - self._alg_translation, search_from_match, search_from_match_occurrence - ) - filedata_pre = self._alg_translation[:position] - filedata_post = self._alg_translation[position:].replace(old, new, count) - self._alg_translation = filedata_pre + filedata_post - else: - self._alg_translation = self._alg_translation.replace(old, new, count) - - def convert_node_arg( - self, node_arg: typing.Union[Identifier, CompValue, Expr, str] - ) -> str: - if isinstance(node_arg, Identifier): - if node_arg in self.aggr_vars.keys(): - grp_var = self.aggr_vars[node_arg].pop(0).n3() - return grp_var - else: - return node_arg.n3() - elif isinstance(node_arg, CompValue): - return "{" + node_arg.name + "}" - elif isinstance(node_arg, str): - return node_arg - else: - raise ExpressionNotCoveredException( - "The expression {0} might not be covered yet.".format(node_arg) - ) - - def sparql_query_text(self, node): - """ - https://www.w3.org/TR/sparql11-query/#sparqlSyntax - - :param node: - :return: - """ - - if isinstance(node, CompValue): - # 18.2 Query Forms - if node.name == "SelectQuery": - self._alg_translation = "-*-SELECT-*- " + "{" + node.p.name + "}" - - # 18.2 Graph Patterns - elif node.name == "BGP": - # Identifiers or Paths - # Negated path throws a type error. Probably n3() method of negated paths should be fixed - triples = "".join( - triple[0].n3() + " " + triple[1].n3() + " " + triple[2].n3() + "." - for triple in node.triples - ) - self._replace("{BGP}", triples) - # The dummy -*-SELECT-*- is placed during a SelectQuery or Multiset pattern in order to be able - # to match extended variables in a specific Select-clause (see "Extend" below) - self._replace("-*-SELECT-*-", "SELECT", count=-1) - # If there is no "Group By" clause the placeholder will simply be deleted. Otherwise there will be - # no matching {GroupBy} placeholder because it has already been replaced by "group by variables" - self._replace("{GroupBy}", "", count=-1) - self._replace("{Having}", "", count=-1) - elif node.name == "Join": - self._replace( - "{Join}", "{" + node.p1.name + "}{" + node.p2.name + "}" - ) # - elif node.name == "LeftJoin": - self._replace( - "{LeftJoin}", - "{" + node.p1.name + "}OPTIONAL{{" + node.p2.name + "}}", - ) - elif node.name == "Filter": - if isinstance(node.expr, CompValue): - expr = node.expr.name - else: - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - if node.p: - # Filter with p=AggregateJoin = Having - if node.p.name == "AggregateJoin": - self._replace("{Filter}", "{" + node.p.name + "}") - self._replace("{Having}", "HAVING({" + expr + "})") - else: - self._replace( - "{Filter}", "FILTER({" + expr + "}) {" + node.p.name + "}" - ) - else: - self._replace("{Filter}", "FILTER({" + expr + "})") - - elif node.name == "Union": - self._replace( - "{Union}", "{{" + node.p1.name + "}}UNION{{" + node.p2.name + "}}" - ) - elif node.name == "Graph": - expr = "GRAPH " + node.term.n3() + " {{" + node.p.name + "}}" - self._replace("{Graph}", expr) - elif node.name == "Extend": - query_string = self._alg_translation.lower() - select_occurrences = query_string.count("-*-select-*-") - self._replace( - node.var.n3(), - "(" - + self.convert_node_arg(node.expr) - + " as " - + node.var.n3() - + ")", - search_from_match="-*-select-*-", - search_from_match_occurrence=select_occurrences, - ) - self._replace("{Extend}", "{" + node.p.name + "}") - elif node.name == "Minus": - expr = "{" + node.p1.name + "}MINUS{{" + node.p2.name + "}}" - self._replace("{Minus}", expr) - elif node.name == "Group": - group_by_vars = [] - if node.expr: - for var in node.expr: - if isinstance(var, Identifier): - group_by_vars.append(var.n3()) - else: - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - self._replace("{Group}", "{" + node.p.name + "}") - self._replace( - "{GroupBy}", "GROUP BY " + " ".join(group_by_vars) + " " - ) - else: - self._replace("{Group}", "{" + node.p.name + "}") - elif node.name == "AggregateJoin": - self._replace("{AggregateJoin}", "{" + node.p.name + "}") - for agg_func in node.A: - if isinstance(agg_func.res, Identifier): - identifier = agg_func.res.n3() - else: - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - self.aggr_vars[agg_func.res].append(agg_func.vars) - - agg_func_name = agg_func.name.split("_")[1] - distinct = "" - if agg_func.distinct: - distinct = agg_func.distinct + " " - if agg_func_name == "GroupConcat": - self._replace( - identifier, - "GROUP_CONCAT" - + "(" - + distinct - + agg_func.vars.n3() - + ";SEPARATOR=" - + agg_func.separator.n3() - + ")", - ) - else: - self._replace( - identifier, - agg_func_name.upper() - + "(" - + distinct - + self.convert_node_arg(agg_func.vars) - + ")", - ) - # For non-aggregated variables the aggregation function "sample" is automatically assigned. - # However, we do not want to have "sample" wrapped around non-aggregated variables. That is - # why we replace it. If "sample" is used on purpose it will not be replaced as the alias - # must be different from the variable in this case. - self._replace( - "(SAMPLE({0}) as {0})".format( - self.convert_node_arg(agg_func.vars) - ), - self.convert_node_arg(agg_func.vars), - ) - elif node.name == "GroupGraphPatternSub": - self._replace( - "GroupGraphPatternSub", - " ".join([self.convert_node_arg(pattern) for pattern in node.part]), - ) - elif node.name == "TriplesBlock": - self._replace( - "{TriplesBlock}", - "".join( - triple[0].n3() - + " " - + triple[1].n3() - + " " - + triple[2].n3() - + "." - for triple in node.triples - ), - ) - - # 18.2 Solution modifiers - elif node.name == "ToList": - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - elif node.name == "OrderBy": - order_conditions = [] - for c in node.expr: - if isinstance(c.expr, Identifier): - var = c.expr.n3() - if c.order is not None: - cond = c.order + "(" + var + ")" - else: - cond = var - order_conditions.append(cond) - else: - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - self._replace("{OrderBy}", "{" + node.p.name + "}") - self._replace("{OrderConditions}", " ".join(order_conditions) + " ") - elif node.name == "Project": - project_variables = [] - for var in node.PV: - if isinstance(var, Identifier): - project_variables.append(var.n3()) - else: - raise ExpressionNotCoveredException( - "This expression might not be covered yet." - ) - order_by_pattern = "" - if node.p.name == "OrderBy": - order_by_pattern = "ORDER BY {OrderConditions}" - self._replace( - "{Project}", - " ".join(project_variables) - + "{{" - + node.p.name - + "}}" - + "{GroupBy}" - + order_by_pattern - + "{Having}", - ) - elif node.name == "Distinct": - self._replace("{Distinct}", "DISTINCT {" + node.p.name + "}") - elif node.name == "Reduced": - self._replace("{Reduced}", "REDUCED {" + node.p.name + "}") - elif node.name == "Slice": - slice = "OFFSET " + str(node.start) + " LIMIT " + str(node.length) - self._replace("{Slice}", "{" + node.p.name + "}" + slice) - elif node.name == "ToMultiSet": - if node.p.name == "values": - self._replace("{ToMultiSet}", "{{" + node.p.name + "}}") - else: - self._replace( - "{ToMultiSet}", "{-*-SELECT-*- " + "{" + node.p.name + "}" + "}" - ) - - # 18.2 Property Path - - # 17 Expressions and Testing Values - # # 17.3 Operator Mapping - elif node.name == "RelationalExpression": - expr = self.convert_node_arg(node.expr) - op = node.op - if isinstance(list, type(node.other)): - other = ( - "(" - + ", ".join(self.convert_node_arg(expr) for expr in node.other) - + ")" - ) - else: - other = self.convert_node_arg(node.other) - condition = "{left} {operator} {right}".format( - left=expr, operator=op, right=other - ) - self._replace("{RelationalExpression}", condition) - elif node.name == "ConditionalAndExpression": - inner_nodes = " && ".join( - [self.convert_node_arg(expr) for expr in node.other] - ) - self._replace( - "{ConditionalAndExpression}", - self.convert_node_arg(node.expr) + " && " + inner_nodes, - ) - elif node.name == "ConditionalOrExpression": - inner_nodes = " || ".join( - [self.convert_node_arg(expr) for expr in node.other] - ) - self._replace( - "{ConditionalOrExpression}", - "(" + self.convert_node_arg(node.expr) + " || " + inner_nodes + ")", - ) - elif node.name == "MultiplicativeExpression": - left_side = self.convert_node_arg(node.expr) - multiplication = left_side - for i, operator in enumerate(node.op): - multiplication += ( - operator + " " + self.convert_node_arg(node.other[i]) + " " - ) - self._replace("{MultiplicativeExpression}", multiplication) - elif node.name == "AdditiveExpression": - left_side = self.convert_node_arg(node.expr) - addition = left_side - for i, operator in enumerate(node.op): - addition += ( - operator + " " + self.convert_node_arg(node.other[i]) + " " - ) - self._replace("{AdditiveExpression}", addition) - elif node.name == "UnaryNot": - self._replace("{UnaryNot}", "!" + self.convert_node_arg(node.expr)) - - # # 17.4 Function Definitions - # # # 17.4.1 Functional Forms - elif node.name.endswith("BOUND"): - bound_var = self.convert_node_arg(node.arg) - self._replace("{Builtin_BOUND}", "bound(" + bound_var + ")") - elif node.name.endswith("IF"): - arg2 = self.convert_node_arg(node.arg2) - arg3 = self.convert_node_arg(node.arg3) - - if_expression = ( - "IF(" + "{" + node.arg1.name + "}, " + arg2 + ", " + arg3 + ")" - ) - self._replace("{Builtin_IF}", if_expression) - elif node.name.endswith("COALESCE"): - self._replace( - "{Builtin_COALESCE}", - "COALESCE(" - + ", ".join(self.convert_node_arg(arg) for arg in node.arg) - + ")", - ) - elif node.name.endswith("Builtin_EXISTS"): - # The node's name which we get with node.graph.name returns "Join" instead of GroupGraphPatternSub - # According to https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rExistsFunc - # ExistsFunc can only have a GroupGraphPattern as parameter. However, when we print the query algebra - # we get a GroupGraphPatternSub - self._replace( - "{Builtin_EXISTS}", "EXISTS " + "{{" + node.graph.name + "}}" - ) - traverse(node.graph, visitPre=self.sparql_query_text) - return node.graph - elif node.name.endswith("Builtin_NOTEXISTS"): - # The node's name which we get with node.graph.name returns "Join" instead of GroupGraphPatternSub - # According to https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rNotExistsFunc - # NotExistsFunc can only have a GroupGraphPattern as parameter. However, when we print the query algebra - # we get a GroupGraphPatternSub - self._replace( - "{Builtin_NOTEXISTS}", "NOT EXISTS " + "{{" + node.graph.name + "}}" - ) - traverse(node.graph, visitPre=self.sparql_query_text) - return node.graph - # # # # 17.4.1.5 logical-or: Covered in "RelationalExpression" - # # # # 17.4.1.6 logical-and: Covered in "RelationalExpression" - # # # # 17.4.1.7 RDFterm-equal: Covered in "RelationalExpression" - elif node.name.endswith("sameTerm"): - self._replace( - "{Builtin_sameTerm}", - "SAMETERM(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - # # # # IN: Covered in "RelationalExpression" - # # # # NOT IN: Covered in "RelationalExpression" - - # # # 17.4.2 Functions on RDF Terms - elif node.name.endswith("Builtin_isIRI"): - self._replace( - "{Builtin_isIRI}", "isIRI(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_isBLANK"): - self._replace( - "{Builtin_isBLANK}", - "isBLANK(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_isLITERAL"): - self._replace( - "{Builtin_isLITERAL}", - "isLITERAL(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_isNUMERIC"): - self._replace( - "{Builtin_isNUMERIC}", - "isNUMERIC(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_STR"): - self._replace( - "{Builtin_STR}", "STR(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_LANG"): - self._replace( - "{Builtin_LANG}", "LANG(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_DATATYPE"): - self._replace( - "{Builtin_DATATYPE}", - "DATATYPE(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_IRI"): - self._replace( - "{Builtin_IRI}", "IRI(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_BNODE"): - self._replace( - "{Builtin_BNODE}", "BNODE(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("STRDT"): - self._replace( - "{Builtin_STRDT}", - "STRDT(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_STRLANG"): - self._replace( - "{Builtin_STRLANG}", - "STRLANG(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_UUID"): - self._replace("{Builtin_UUID}", "UUID()") - elif node.name.endswith("Builtin_STRUUID"): - self._replace("{Builtin_STRUUID}", "STRUUID()") - - # # # 17.4.3 Functions on Strings - elif node.name.endswith("Builtin_STRLEN"): - self._replace( - "{Builtin_STRLEN}", - "STRLEN(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_SUBSTR"): - args = [self.convert_node_arg(node.arg), node.start] - if node.length: - args.append(node.length) - expr = "SUBSTR(" + ", ".join(args) + ")" - self._replace("{Builtin_SUBSTR}", expr) - elif node.name.endswith("Builtin_UCASE"): - self._replace( - "{Builtin_UCASE}", "UCASE(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_LCASE"): - self._replace( - "{Builtin_LCASE}", "LCASE(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name.endswith("Builtin_STRSTARTS"): - self._replace( - "{Builtin_STRSTARTS}", - "STRSTARTS(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_STRENDS"): - self._replace( - "{Builtin_STRENDS}", - "STRENDS(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_CONTAINS"): - self._replace( - "{Builtin_CONTAINS}", - "CONTAINS(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_STRBEFORE"): - self._replace( - "{Builtin_STRBEFORE}", - "STRBEFORE(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_STRAFTER"): - self._replace( - "{Builtin_STRAFTER}", - "STRAFTER(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("Builtin_ENCODE_FOR_URI"): - self._replace( - "{Builtin_ENCODE_FOR_URI}", - "ENCODE_FOR_URI(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name.endswith("Builtin_CONCAT"): - expr = "CONCAT({vars})".format( - vars=", ".join(self.convert_node_arg(elem) for elem in node.arg) - ) - self._replace("{Builtin_CONCAT}", expr) - elif node.name.endswith("Builtin_LANGMATCHES"): - self._replace( - "{Builtin_LANGMATCHES}", - "LANGMATCHES(" - + self.convert_node_arg(node.arg1) - + ", " - + self.convert_node_arg(node.arg2) - + ")", - ) - elif node.name.endswith("REGEX"): - args = [ - self.convert_node_arg(node.text), - self.convert_node_arg(node.pattern), - ] - expr = "REGEX(" + ", ".join(args) + ")" - self._replace("{Builtin_REGEX}", expr) - elif node.name.endswith("REPLACE"): - self._replace( - "{Builtin_REPLACE}", - "REPLACE(" - + self.convert_node_arg(node.arg) - + ", " - + self.convert_node_arg(node.pattern) - + ", " - + self.convert_node_arg(node.replacement) - + ")", - ) - - # # # 17.4.4 Functions on Numerics - elif node.name == "Builtin_ABS": - self._replace( - "{Builtin_ABS}", "ABS(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_ROUND": - self._replace( - "{Builtin_ROUND}", "ROUND(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_CEIL": - self._replace( - "{Builtin_CEIL}", "CEIL(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_FLOOR": - self._replace( - "{Builtin_FLOOR}", "FLOOR(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_RAND": - self._replace("{Builtin_RAND}", "RAND()") - - # # # 17.4.5 Functions on Dates and Times - elif node.name == "Builtin_NOW": - self._replace("{Builtin_NOW}", "NOW()") - elif node.name == "Builtin_YEAR": - self._replace( - "{Builtin_YEAR}", "YEAR(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_MONTH": - self._replace( - "{Builtin_MONTH}", "MONTH(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_DAY": - self._replace( - "{Builtin_DAY}", "DAY(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_HOURS": - self._replace( - "{Builtin_HOURS}", "HOURS(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_MINUTES": - self._replace( - "{Builtin_MINUTES}", - "MINUTES(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name == "Builtin_SECONDS": - self._replace( - "{Builtin_SECONDS}", - "SECONDS(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name == "Builtin_TIMEZONE": - self._replace( - "{Builtin_TIMEZONE}", - "TIMEZONE(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name == "Builtin_TZ": - self._replace( - "{Builtin_TZ}", "TZ(" + self.convert_node_arg(node.arg) + ")" - ) - - # # # 17.4.6 Hash functions - elif node.name == "Builtin_MD5": - self._replace( - "{Builtin_MD5}", "MD5(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_SHA1": - self._replace( - "{Builtin_SHA1}", "SHA1(" + self.convert_node_arg(node.arg) + ")" - ) - elif node.name == "Builtin_SHA256": - self._replace( - "{Builtin_SHA256}", - "SHA256(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name == "Builtin_SHA384": - self._replace( - "{Builtin_SHA384}", - "SHA384(" + self.convert_node_arg(node.arg) + ")", - ) - elif node.name == "Builtin_SHA512": - self._replace( - "{Builtin_SHA512}", - "SHA512(" + self.convert_node_arg(node.arg) + ")", - ) - - # Other - elif node.name == "values": - columns = [] - for key in node.res[0].keys(): - if isinstance(key, Identifier): - columns.append(key.n3()) - else: - raise ExpressionNotCoveredException( - "The expression {0} might not be covered yet.".format(key) - ) - values = "VALUES (" + " ".join(columns) + ")" - - rows = "" - for elem in node.res: - row = [] - for term in elem.values(): - if isinstance(term, Identifier): - row.append( - term.n3() - ) # n3() is not part of Identifier class but every subclass has it - elif isinstance(term, str): - row.append(term) - else: - raise ExpressionNotCoveredException( - "The expression {0} might not be covered yet.".format( - term - ) - ) - rows += "(" + " ".join(row) + ")" - - self._replace("values", values + "{" + rows + "}") - elif node.name == "ServiceGraphPattern": - self._replace( - "{ServiceGraphPattern}", - "SERVICE " - + self.convert_node_arg(node.term) - + "{" - + node.graph.name - + "}", - ) - traverse(node.graph, visitPre=self.sparql_query_text) - return node.graph - # else: - # raise ExpressionNotCoveredException("The expression {0} might not be covered yet.".format(node.name)) - - def translateAlgebra(self) -> str: - traverse(self.query_algebra.algebra, visitPre=self.sparql_query_text) - return self._alg_translation - - -def translateAlgebra(query_algebra: Query) -> str: - """ - Translates a SPARQL 1.1 algebra tree into the corresponding query string. - - :param query_algebra: An algebra returned by `translateQuery`. - :return: The query form generated from the SPARQL 1.1 algebra tree for - SELECT queries. - """ - query_from_algebra = _AlgebraTranslator( - query_algebra=query_algebra - ).translateAlgebra() - return query_from_algebra - - -def pprintAlgebra(q) -> None: - def pp(p, ind=" "): - # if isinstance(p, list): - # print "[ " - # for x in p: pp(x,ind) - # print "%s ]"%ind - # return - if not isinstance(p, CompValue): - print(p) - return - print("%s(" % (p.name,)) - for k in p: - print( - "%s%s =" - % ( - ind, - k, - ), - end=" ", - ) - pp(p[k], ind + " ") - print("%s)" % ind) - - try: - pp(q.algebra) - except AttributeError: - # it's update, just a list - for x in q: - pp(x) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/datatypes.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/datatypes.py deleted file mode 100644 index bc06525..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/datatypes.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -Utility functions for supporting the XML Schema Datatypes hierarchy -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Dict, List, Optional, Set - -from rdflib.namespace import XSD - -if TYPE_CHECKING: - from rdflib.term import URIRef - - -XSD_DTs: Set[URIRef] = set( - ( - XSD.integer, - XSD.decimal, - XSD.float, - XSD.double, - XSD.string, - XSD.boolean, - XSD.dateTime, - XSD.nonPositiveInteger, - XSD.negativeInteger, - XSD.long, - XSD.int, - XSD.short, - XSD.byte, - XSD.nonNegativeInteger, - XSD.unsignedLong, - XSD.unsignedInt, - XSD.unsignedShort, - XSD.unsignedByte, - XSD.positiveInteger, - XSD.date, - ) -) - -# adding dateTime datatypes - -XSD_DateTime_DTs = set((XSD.dateTime, XSD.date, XSD.time)) - -XSD_Duration_DTs = set((XSD.duration, XSD.dayTimeDuration, XSD.yearMonthDuration)) - -_sub_types: Dict[URIRef, List[URIRef]] = { - XSD.integer: [ - XSD.nonPositiveInteger, - XSD.negativeInteger, - XSD.long, - XSD.int, - XSD.short, - XSD.byte, - XSD.nonNegativeInteger, - XSD.positiveInteger, - XSD.unsignedLong, - XSD.unsignedInt, - XSD.unsignedShort, - XSD.unsignedByte, - ], -} - -_super_types: Dict[URIRef, URIRef] = {} -for superdt in XSD_DTs: - for subdt in _sub_types.get(superdt, []): - _super_types[subdt] = superdt - -# we only care about float, double, integer, decimal -_typePromotionMap: Dict[URIRef, Dict[URIRef, URIRef]] = { - XSD.float: {XSD.integer: XSD.float, XSD.decimal: XSD.float, XSD.double: XSD.double}, - XSD.double: { - XSD.integer: XSD.double, - XSD.float: XSD.double, - XSD.decimal: XSD.double, - }, - XSD.decimal: { - XSD.integer: XSD.decimal, - XSD.float: XSD.float, - XSD.double: XSD.double, - }, - XSD.integer: { - XSD.decimal: XSD.decimal, - XSD.float: XSD.float, - XSD.double: XSD.double, - }, -} - - -def type_promotion(t1: URIRef, t2: Optional[URIRef]) -> URIRef: - if t2 is None: - return t1 - t1 = _super_types.get(t1, t1) - t2 = _super_types.get(t2, t2) - if t1 == t2: - return t1 # matching super-types - try: - if TYPE_CHECKING: - # type assert because mypy is confused and thinks t2 can be None - assert t2 is not None - return _typePromotionMap[t1][t2] - except KeyError: - raise TypeError("Operators cannot combine datatypes %s and %s" % (t1, t2)) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py deleted file mode 100644 index 82fe803..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py +++ /dev/null @@ -1,685 +0,0 @@ -""" -These method recursively evaluate the SPARQL Algebra - -evalQuery is the entry-point, it will setup context and -return the SPARQLResult object - -evalPart is called on each level and will delegate to the right method - -A rdflib.plugins.sparql.sparql.QueryContext is passed along, keeping -information needed for evaluation - -A list of dicts (solution mappings) is returned, apart from GroupBy which may -also return a dict of list of dicts - -""" - -from __future__ import annotations - -import collections -import itertools -import re -from typing import ( - TYPE_CHECKING, - Any, - Deque, - Dict, - Generator, - Iterable, - List, - Mapping, - Optional, - Tuple, - Union, -) -from urllib.parse import urlencode -from urllib.request import Request, urlopen - -from pyparsing import ParseException - -from rdflib.graph import Graph -from rdflib.plugins.sparql import CUSTOM_EVALS, parser -from rdflib.plugins.sparql.aggregates import Aggregator -from rdflib.plugins.sparql.evalutils import ( - _ebv, - _eval, - _fillTemplate, - _join, - _minus, - _val, -) -from rdflib.plugins.sparql.parserutils import CompValue, value -from rdflib.plugins.sparql.sparql import ( - AlreadyBound, - FrozenBindings, - FrozenDict, - Query, - QueryContext, - SPARQLError, -) -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - -if TYPE_CHECKING: - from rdflib.paths import Path - -import json - -try: - import orjson - - _HAS_ORJSON = True -except ImportError: - orjson = None # type: ignore[assignment, unused-ignore] - _HAS_ORJSON = False - -_Triple = Tuple[Identifier, Identifier, Identifier] - - -def evalBGP( - ctx: QueryContext, bgp: List[_Triple] -) -> Generator[FrozenBindings, None, None]: - """ - A basic graph pattern - """ - - if not bgp: - yield ctx.solution() - return - - s, p, o = bgp[0] - - _s = ctx[s] - _p = ctx[p] - _o = ctx[o] - - # type error: Item "None" of "Optional[Graph]" has no attribute "triples" - # type Argument 1 to "triples" of "Graph" has incompatible type "Tuple[Union[str, Path, None], Union[str, Path, None], Union[str, Path, None]]"; expected "Tuple[Optional[Node], Optional[Node], Optional[Node]]" - for ss, sp, so in ctx.graph.triples((_s, _p, _o)): # type: ignore[union-attr, arg-type] - if None in (_s, _p, _o): - c = ctx.push() - else: - c = ctx - - if _s is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[s] = ss # type: ignore[assignment] - - try: - if _p is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[p] = sp # type: ignore[assignment] - except AlreadyBound: - continue - - try: - if _o is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[o] = so # type: ignore[assignment] - except AlreadyBound: - continue - - for x in evalBGP(c, bgp[1:]): - yield x - - -def evalExtend( - ctx: QueryContext, extend: CompValue -) -> Generator[FrozenBindings, None, None]: - # TODO: Deal with dict returned from evalPart from GROUP BY - - for c in evalPart(ctx, extend.p): - try: - e = _eval(extend.expr, c.forget(ctx, _except=extend._vars)) - if isinstance(e, SPARQLError): - raise e - - yield c.merge({extend.var: e}) - - except SPARQLError: - yield c - - -def evalLazyJoin( - ctx: QueryContext, join: CompValue -) -> Generator[FrozenBindings, None, None]: - """ - A lazy join will push the variables bound - in the first part to the second part, - essentially doing the join implicitly - hopefully evaluating much fewer triples - """ - for a in evalPart(ctx, join.p1): - c = ctx.thaw(a) - for b in evalPart(c, join.p2): - yield b.merge(a) # merge, as some bindings may have been forgotten - - -def evalJoin(ctx: QueryContext, join: CompValue) -> Generator[FrozenDict, None, None]: - # TODO: Deal with dict returned from evalPart from GROUP BY - # only ever for join.p1 - - if join.lazy: - return evalLazyJoin(ctx, join) - else: - a = evalPart(ctx, join.p1) - b = set(evalPart(ctx, join.p2)) - return _join(a, b) - - -def evalUnion(ctx: QueryContext, union: CompValue) -> List[Any]: - branch1_branch2 = [] - for x in evalPart(ctx, union.p1): - branch1_branch2.append(x) - for x in evalPart(ctx, union.p2): - branch1_branch2.append(x) - return branch1_branch2 - - -def evalMinus(ctx: QueryContext, minus: CompValue) -> Generator[FrozenDict, None, None]: - a = evalPart(ctx, minus.p1) - b = set(evalPart(ctx, minus.p2)) - return _minus(a, b) - - -def evalLeftJoin( - ctx: QueryContext, join: CompValue -) -> Generator[FrozenBindings, None, None]: - # import pdb; pdb.set_trace() - for a in evalPart(ctx, join.p1): - ok = False - c = ctx.thaw(a) - for b in evalPart(c, join.p2): - if _ebv(join.expr, b.forget(ctx)): - ok = True - yield b - if not ok: - # we've cheated, the ctx above may contain - # vars bound outside our scope - # before we yield a solution without the OPTIONAL part - # check that we would have had no OPTIONAL matches - # even without prior bindings... - p1_vars = join.p1._vars - if p1_vars is None or not any( - _ebv(join.expr, b) - for b in evalPart(ctx.thaw(a.remember(p1_vars)), join.p2) - ): - yield a - - -def evalFilter( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - # TODO: Deal with dict returned from evalPart! - for c in evalPart(ctx, part.p): - if _ebv( - part.expr, - c.forget(ctx, _except=part._vars) if not part.no_isolated_scope else c, - ): - yield c - - -def evalGraph( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - if ctx.dataset is None: - raise Exception( - "Non-conjunctive-graph doesn't know about " - + "graphs. Try a query without GRAPH." - ) - - ctx = ctx.clone() - graph: Union[str, Path, None, Graph] = ctx[part.term] - prev_graph = ctx.graph - if graph is None: - for graph in ctx.dataset.contexts(): - # in SPARQL the default graph is NOT a named graph - if graph == ctx.dataset.default_context: - continue - - c = ctx.pushGraph(graph) - c = c.push() - graphSolution = [{part.term: graph.identifier}] - for x in _join(evalPart(c, part.p), graphSolution): - x.ctx.graph = prev_graph - yield x - - else: - if TYPE_CHECKING: - assert not isinstance(graph, Graph) - # type error: Argument 1 to "get_context" of "ConjunctiveGraph" has incompatible type "Union[str, Path]"; expected "Union[Node, str, None]" - c = ctx.pushGraph(ctx.dataset.get_context(graph)) # type: ignore[arg-type] - for x in evalPart(c, part.p): - x.ctx.graph = prev_graph - yield x - - -def evalValues( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - for r in part.p.res: - c = ctx.push() - try: - for k, v in r.items(): - if v != "UNDEF": - c[k] = v - except AlreadyBound: - continue - - yield c.solution() - - -def evalMultiset(ctx: QueryContext, part: CompValue): - if part.p.name == "values": - return evalValues(ctx, part) - - return evalPart(ctx, part.p) - - -def evalPart(ctx: QueryContext, part: CompValue) -> Any: - # try custom evaluation functions - for name, c in CUSTOM_EVALS.items(): - try: - return c(ctx, part) - except NotImplementedError: - pass # the given custome-function did not handle this part - - if part.name == "BGP": - # Reorder triples patterns by number of bound nodes in the current ctx - # Do patterns with more bound nodes first - triples = sorted( - part.triples, key=lambda t: len([n for n in t if ctx[n] is None]) - ) - - return evalBGP(ctx, triples) - elif part.name == "Filter": - return evalFilter(ctx, part) - elif part.name == "Join": - return evalJoin(ctx, part) - elif part.name == "LeftJoin": - return evalLeftJoin(ctx, part) - elif part.name == "Graph": - return evalGraph(ctx, part) - elif part.name == "Union": - return evalUnion(ctx, part) - elif part.name == "ToMultiSet": - return evalMultiset(ctx, part) - elif part.name == "Extend": - return evalExtend(ctx, part) - elif part.name == "Minus": - return evalMinus(ctx, part) - - elif part.name == "Project": - return evalProject(ctx, part) - elif part.name == "Slice": - return evalSlice(ctx, part) - elif part.name == "Distinct": - return evalDistinct(ctx, part) - elif part.name == "Reduced": - return evalReduced(ctx, part) - - elif part.name == "OrderBy": - return evalOrderBy(ctx, part) - elif part.name == "Group": - return evalGroup(ctx, part) - elif part.name == "AggregateJoin": - return evalAggregateJoin(ctx, part) - - elif part.name == "SelectQuery": - return evalSelectQuery(ctx, part) - elif part.name == "AskQuery": - return evalAskQuery(ctx, part) - elif part.name == "ConstructQuery": - return evalConstructQuery(ctx, part) - - elif part.name == "ServiceGraphPattern": - return evalServiceQuery(ctx, part) - - elif part.name == "DescribeQuery": - return evalDescribeQuery(ctx, part) - - else: - raise Exception("I dont know: %s" % part.name) - - -def evalServiceQuery(ctx: QueryContext, part: CompValue): - res = {} - match = re.match( - "^service <(.*)>[ \n]*{(.*)}[ \n]*$", - # type error: Argument 2 to "get" of "CompValue" has incompatible type "str"; expected "bool" [arg-type] - part.get("service_string", ""), # type: ignore[arg-type] - re.DOTALL | re.I, - ) - - if match: - service_url = match.group(1) - service_query = _buildQueryStringForServiceCall(ctx, match.group(2)) - - query_settings = {"query": service_query, "output": "json"} - headers = { - "accept": "application/sparql-results+json", - "user-agent": "rdflibForAnUser", - } - # GET is easier to cache so prefer that if the query is not to long - if len(service_query) < 600: - response = urlopen( - Request(service_url + "?" + urlencode(query_settings), headers=headers) - ) - else: - response = urlopen( - Request( - service_url, - data=urlencode(query_settings).encode(), - headers=headers, - ) - ) - if response.status == 200: - if _HAS_ORJSON: - json_dict = orjson.loads(response.read()) - else: - json_dict = json.loads(response.read()) - variables = res["vars_"] = json_dict["head"]["vars"] - # or just return the bindings? - res = json_dict["results"]["bindings"] - if len(res) > 0: - for r in res: - # type error: Argument 2 to "_yieldBindingsFromServiceCallResult" has incompatible type "str"; expected "Dict[str, Dict[str, str]]" - for bound in _yieldBindingsFromServiceCallResult(ctx, r, variables): # type: ignore[arg-type] - yield bound - else: - raise Exception( - "Service: %s responded with code: %s", service_url, response.status - ) - - -""" - Build a query string to be used by the service call. - It is supposed to pass in the existing bound solutions. - Re-adds prefixes if added and sets the base. - Wraps it in select if needed. -""" - - -def _buildQueryStringForServiceCall(ctx: QueryContext, service_query: str) -> str: - try: - parser.parseQuery(service_query) - except ParseException: - # This could be because we don't have a select around the service call. - service_query = "SELECT REDUCED * WHERE {" + service_query + "}" - # type error: Item "None" of "Optional[Prologue]" has no attribute "namespace_manager" - for p in ctx.prologue.namespace_manager.store.namespaces(): # type: ignore[union-attr] - service_query = "PREFIX " + p[0] + ":" + p[1].n3() + " " + service_query - # re add the base if one was defined - # type error: Item "None" of "Optional[Prologue]" has no attribute "base" - base = ctx.prologue.base # type: ignore[union-attr] - if base is not None and len(base) > 0: - service_query = "BASE <" + base + "> " + service_query - sol = [v for v in ctx.solution() if isinstance(v, Variable)] - if len(sol) > 0: - variables = " ".join([v.n3() for v in sol]) - variables_bound = " ".join([ctx.get(v).n3() for v in sol]) - service_query = ( - service_query + "VALUES (" + variables + ") {(" + variables_bound + ")}" - ) - return service_query - - -def _yieldBindingsFromServiceCallResult( - ctx: QueryContext, r: Dict[str, Dict[str, str]], variables: List[str] -) -> Generator[FrozenBindings, None, None]: - res_dict: Dict[Variable, Identifier] = {} - for var in variables: - if var in r and r[var]: - var_binding = r[var] - var_type = var_binding["type"] - if var_type == "uri": - res_dict[Variable(var)] = URIRef(var_binding["value"]) - elif var_type == "literal": - res_dict[Variable(var)] = Literal( - var_binding["value"], - datatype=var_binding.get("datatype"), - lang=var_binding.get("xml:lang"), - ) - # This is here because of - # https://www.w3.org/TR/2006/NOTE-rdf-sparql-json-res-20061004/#variable-binding-results - elif var_type == "typed-literal": - res_dict[Variable(var)] = Literal( - var_binding["value"], datatype=URIRef(var_binding["datatype"]) - ) - elif var_type == "bnode": - res_dict[Variable(var)] = BNode(var_binding["value"]) - else: - raise ValueError(f"invalid type {var_type!r} for variable {var!r}") - yield FrozenBindings(ctx, res_dict) - - -def evalGroup(ctx: QueryContext, group: CompValue): - """ - http://www.w3.org/TR/sparql11-query/#defn_algGroup - """ - # grouping should be implemented by evalAggregateJoin - return evalPart(ctx, group.p) - - -def evalAggregateJoin( - ctx: QueryContext, agg: CompValue -) -> Generator[FrozenBindings, None, None]: - # import pdb ; pdb.set_trace() - p = evalPart(ctx, agg.p) - # p is always a Group, we always get a dict back - - group_expr = agg.p.expr - res: Dict[Any, Any] = collections.defaultdict( - lambda: Aggregator(aggregations=agg.A) - ) - - if group_expr is None: - # no grouping, just COUNT in SELECT clause - # get 1 aggregator for counting - aggregator = res[True] - for row in p: - aggregator.update(row) - else: - for row in p: - # determine right group aggregator for row - k = tuple(_eval(e, row, False) for e in group_expr) - res[k].update(row) - - # all rows are done; yield aggregated values - for aggregator in res.values(): - yield FrozenBindings(ctx, aggregator.get_bindings()) - - # there were no matches - if len(res) == 0: - yield FrozenBindings(ctx) - - -def evalOrderBy( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - res = evalPart(ctx, part.p) - - for e in reversed(part.expr): - reverse = bool(e.order and e.order == "DESC") - res = sorted( - res, key=lambda x: _val(value(x, e.expr, variables=True)), reverse=reverse - ) - - return res - - -def evalSlice(ctx: QueryContext, slice: CompValue): - res = evalPart(ctx, slice.p) - - return itertools.islice( - res, - slice.start, - slice.start + slice.length if slice.length is not None else None, - ) - - -def evalReduced( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - """apply REDUCED to result - - REDUCED is not as strict as DISTINCT, but if the incoming rows were sorted - it should produce the same result with limited extra memory and time per - incoming row. - """ - - # This implementation uses a most recently used strategy and a limited - # buffer size. It relates to a LRU caching algorithm: - # https://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used_.28LRU.29 - MAX = 1 - # TODO: add configuration or determine "best" size for most use cases - # 0: No reduction - # 1: compare only with the last row, almost no reduction with - # unordered incoming rows - # N: The greater the buffer size the greater the reduction but more - # memory and time are needed - - # mixed data structure: set for lookup, deque for append/pop/remove - mru_set = set() - mru_queue: Deque[Any] = collections.deque() - - for row in evalPart(ctx, part.p): - if row in mru_set: - # forget last position of row - mru_queue.remove(row) - else: - # row seems to be new - yield row - mru_set.add(row) - if len(mru_set) > MAX: - # drop the least recently used row from buffer - mru_set.remove(mru_queue.pop()) - # put row to the front - mru_queue.appendleft(row) - - -def evalDistinct( - ctx: QueryContext, part: CompValue -) -> Generator[FrozenBindings, None, None]: - res = evalPart(ctx, part.p) - - done = set() - for x in res: - if x not in done: - yield x - done.add(x) - - -def evalProject(ctx: QueryContext, project: CompValue): - res = evalPart(ctx, project.p) - return (row.project(project.PV) for row in res) - - -def evalSelectQuery( - ctx: QueryContext, query: CompValue -) -> Mapping[str, Union[str, List[Variable], Iterable[FrozenDict]]]: - res: Dict[str, Union[str, List[Variable], Iterable[FrozenDict]]] = {} - res["type_"] = "SELECT" - res["bindings"] = evalPart(ctx, query.p) - res["vars_"] = query.PV - return res - - -def evalAskQuery(ctx: QueryContext, query: CompValue) -> Mapping[str, Union[str, bool]]: - res: Dict[str, Union[bool, str]] = {} - res["type_"] = "ASK" - res["askAnswer"] = False - for x in evalPart(ctx, query.p): - res["askAnswer"] = True - break - - return res - - -def evalConstructQuery( - ctx: QueryContext, query: CompValue -) -> Mapping[str, Union[str, Graph]]: - template = query.template - - if not template: - # a construct-where query - template = query.p.p.triples # query->project->bgp ... - - graph = Graph() - - for c in evalPart(ctx, query.p): - graph += _fillTemplate(template, c) - - res: Dict[str, Union[str, Graph]] = {} - res["type_"] = "CONSTRUCT" - res["graph"] = graph - - return res - - -def evalDescribeQuery(ctx: QueryContext, query) -> Dict[str, Union[str, Graph]]: - # Create a result graph and bind namespaces from the graph being queried - graph = Graph() - # type error: Item "None" of "Optional[Graph]" has no attribute "namespaces" - for pfx, ns in ctx.graph.namespaces(): # type: ignore[union-attr] - graph.bind(pfx, ns) - - to_describe = set() - - # Explicit IRIs may be provided to a DESCRIBE query. - # If there is a WHERE clause, explicit IRIs may be provided in - # addition to projected variables. Find those explicit IRIs and - # prepare to describe them. - for iri in query.PV: - if isinstance(iri, URIRef): - to_describe.add(iri) - - # If there is a WHERE clause, evaluate it then find the unique set of - # resources to describe across all bindings and projected variables - if query.p is not None: - bindings = evalPart(ctx, query.p) - to_describe.update(*(set(binding.values()) for binding in bindings)) - - # Get a CBD for all resources identified to describe - for resource in to_describe: - # type error: Item "None" of "Optional[Graph]" has no attribute "cbd" - ctx.graph.cbd(resource, target_graph=graph) # type: ignore[union-attr] - - res: Dict[str, Union[str, Graph]] = {} - res["type_"] = "DESCRIBE" - res["graph"] = graph - - return res - - -def evalQuery( - graph: Graph, - query: Query, - initBindings: Optional[Mapping[str, Identifier]] = None, - base: Optional[str] = None, -) -> Mapping[Any, Any]: - """ - - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - """ - main = query.algebra - - initBindings = dict((Variable(k), v) for k, v in (initBindings or {}).items()) - - ctx = QueryContext( - graph, initBindings=initBindings, datasetClause=main.datasetClause - ) - - ctx.prologue = query.prologue - - return evalPart(ctx, main) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evalutils.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evalutils.py deleted file mode 100644 index 1f737e4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/evalutils.py +++ /dev/null @@ -1,188 +0,0 @@ -from __future__ import annotations - -import collections -from typing import ( - Any, - DefaultDict, - Generator, - Iterable, - Mapping, - Set, - Tuple, - TypeVar, - Union, - overload, -) - -from rdflib.plugins.sparql.operators import EBV -from rdflib.plugins.sparql.parserutils import CompValue, Expr -from rdflib.plugins.sparql.sparql import ( - FrozenBindings, - FrozenDict, - NotBoundError, - QueryContext, - SPARQLError, -) -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - -_ContextType = Union[FrozenBindings, QueryContext] -_FrozenDictT = TypeVar("_FrozenDictT", bound=FrozenDict) - - -def _diff( - a: Iterable[_FrozenDictT], b: Iterable[_FrozenDictT], expr -) -> Set[_FrozenDictT]: - res = set() - - for x in a: - if all(not x.compatible(y) or not _ebv(expr, x.merge(y)) for y in b): - res.add(x) - - return res - - -def _minus( - a: Iterable[_FrozenDictT], b: Iterable[_FrozenDictT] -) -> Generator[_FrozenDictT, None, None]: - for x in a: - if all((not x.compatible(y)) or x.disjointDomain(y) for y in b): - yield x - - -@overload -def _join( - a: Iterable[FrozenBindings], b: Iterable[Mapping[Identifier, Identifier]] -) -> Generator[FrozenBindings, None, None]: ... - - -@overload -def _join( - a: Iterable[FrozenDict], b: Iterable[Mapping[Identifier, Identifier]] -) -> Generator[FrozenDict, None, None]: ... - - -def _join( - a: Iterable[FrozenDict], b: Iterable[Mapping[Identifier, Identifier]] -) -> Generator[FrozenDict, None, None]: - for x in a: - for y in b: - if x.compatible(y): - yield x.merge(y) - - -def _ebv(expr: Union[Literal, Variable, Expr], ctx: FrozenDict) -> bool: - """ - Return true/false for the given expr - Either the expr is itself true/false - or evaluates to something, with the given ctx - - an error is false - """ - - try: - return EBV(expr) - except SPARQLError: - pass - if isinstance(expr, Expr): - try: - return EBV(expr.eval(ctx)) - except SPARQLError: - return False # filter error == False - # type error: Subclass of "Literal" and "CompValue" cannot exist: would have incompatible method signatures - elif isinstance(expr, CompValue): # type: ignore[unreachable] - raise Exception("Weird - filter got a CompValue without evalfn! %r" % expr) - elif isinstance(expr, Variable): - try: - return EBV(ctx[expr]) - except: # noqa: E722 - return False - return False - - -@overload -def _eval( - expr: Union[Literal, URIRef], - ctx: FrozenBindings, - raise_not_bound_error: bool = ..., -) -> Union[Literal, URIRef]: ... - - -@overload -def _eval( - expr: Union[Variable, Expr], - ctx: FrozenBindings, - raise_not_bound_error: bool = ..., -) -> Union[Any, SPARQLError]: ... - - -def _eval( - expr: Union[Literal, URIRef, Variable, Expr], - ctx: FrozenBindings, - raise_not_bound_error: bool = True, -) -> Any: - if isinstance(expr, (Literal, URIRef)): - return expr - if isinstance(expr, Expr): - return expr.eval(ctx) - elif isinstance(expr, Variable): - try: - return ctx[expr] - except KeyError: - if raise_not_bound_error: - raise NotBoundError("Variable %s is not bound" % expr) - else: - return None - elif isinstance(expr, CompValue): # type: ignore[unreachable] - raise Exception("Weird - _eval got a CompValue without evalfn! %r" % expr) - else: - raise Exception("Cannot eval thing: %s (%s)" % (expr, type(expr))) - - -def _filter( - a: Iterable[FrozenDict], expr: Union[Literal, Variable, Expr] -) -> Generator[FrozenDict, None, None]: - for c in a: - if _ebv(expr, c): - yield c - - -def _fillTemplate( - template: Iterable[Tuple[Identifier, Identifier, Identifier]], - solution: _ContextType, -) -> Generator[Tuple[Identifier, Identifier, Identifier], None, None]: - """ - For construct/deleteWhere and friends - - Fill a triple template with instantiated variables - """ - - bnodeMap: DefaultDict[BNode, BNode] = collections.defaultdict(BNode) - for t in template: - s, p, o = t - - _s = solution.get(s) - _p = solution.get(p) - _o = solution.get(o) - - # instantiate new bnodes for each solution - _s, _p, _o = [ - bnodeMap[x] if isinstance(x, BNode) else y for x, y in zip(t, (_s, _p, _o)) - ] - - if _s is not None and _p is not None and _o is not None: - yield (_s, _p, _o) - - -_ValueT = TypeVar("_ValueT", Variable, BNode, URIRef, Literal) - - -def _val(v: _ValueT) -> Tuple[int, _ValueT]: - """utilitity for ordering things""" - if isinstance(v, Variable): - return (0, v) - elif isinstance(v, BNode): - return (1, v) - elif isinstance(v, URIRef): - return (2, v) - elif isinstance(v, Literal): - return (3, v) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/operators.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/operators.py deleted file mode 100644 index e4d19f6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/operators.py +++ /dev/null @@ -1,1261 +0,0 @@ -""" -This contains evaluation functions for expressions - -They get bound as instances-methods to the CompValue objects from parserutils -using setEvalFn - -""" - -from __future__ import annotations - -import datetime as py_datetime # naming conflict with function within this module -import hashlib -import math -import operator as pyop # python operators -import random -import re -import uuid -import warnings -from decimal import ROUND_HALF_DOWN, ROUND_HALF_UP, Decimal, InvalidOperation -from functools import reduce -from typing import Any, Callable, Dict, NoReturn, Optional, Tuple, Union, overload -from urllib.parse import quote - -from pyparsing import ParseResults - -from rdflib.namespace import RDF, XSD -from rdflib.plugins.sparql.datatypes import ( - XSD_DateTime_DTs, - XSD_DTs, - XSD_Duration_DTs, - type_promotion, -) -from rdflib.plugins.sparql.parserutils import CompValue, Expr -from rdflib.plugins.sparql.sparql import ( - FrozenBindings, - QueryContext, - SPARQLError, - SPARQLTypeError, -) -from rdflib.term import ( - BNode, - IdentifiedNode, - Identifier, - Literal, - Node, - URIRef, - Variable, -) -from rdflib.xsd_datetime import Duration, parse_datetime # type: ignore[attr-defined] - - -def Builtin_IRI(expr: Expr, ctx: FrozenBindings) -> URIRef: - """ - http://www.w3.org/TR/sparql11-query/#func-iri - """ - - a = expr.arg - - if isinstance(a, URIRef): - return a - if isinstance(a, Literal): - # type error: Item "None" of "Optional[Prologue]" has no attribute "absolutize" - # type error: Incompatible return value type (got "Union[CompValue, str, None, Any]", expected "URIRef") - return ctx.prologue.absolutize(URIRef(a)) # type: ignore[union-attr,return-value] - - raise SPARQLError("IRI function only accepts URIRefs or Literals/Strings!") - - -def Builtin_isBLANK(expr: Expr, ctx: FrozenBindings) -> Literal: - return Literal(isinstance(expr.arg, BNode)) - - -def Builtin_isLITERAL(expr, ctx) -> Literal: - return Literal(isinstance(expr.arg, Literal)) - - -def Builtin_isIRI(expr, ctx) -> Literal: - return Literal(isinstance(expr.arg, URIRef)) - - -def Builtin_isNUMERIC(expr, ctx) -> Literal: - try: - numeric(expr.arg) - return Literal(True) - except: # noqa: E722 - return Literal(False) - - -def Builtin_BNODE(expr, ctx) -> BNode: - """ - http://www.w3.org/TR/sparql11-query/#func-bnode - """ - - a = expr.arg - - if a is None: - return BNode() - - if isinstance(a, Literal): - return ctx.bnodes[a] # defaultdict does the right thing - - raise SPARQLError("BNode function only accepts no argument or literal/string") - - -def Builtin_ABS(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-abs - """ - - return Literal(abs(numeric(expr.arg))) - - -def Builtin_IF(expr: Expr, ctx): - """ - http://www.w3.org/TR/sparql11-query/#func-if - """ - - return expr.arg2 if EBV(expr.arg1) else expr.arg3 - - -def Builtin_RAND(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#idp2133952 - """ - - return Literal(random.random()) - - -def Builtin_UUID(expr: Expr, ctx) -> URIRef: - """ - http://www.w3.org/TR/sparql11-query/#func-strdt - """ - - return URIRef(uuid.uuid4().urn) - - -def Builtin_STRUUID(expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strdt - """ - - return Literal(str(uuid.uuid4())) - - -def Builtin_MD5(expr: Expr, ctx) -> Literal: - s = string(expr.arg).encode("utf-8") - return Literal(hashlib.md5(s).hexdigest()) - - -def Builtin_SHA1(expr: Expr, ctx) -> Literal: - s = string(expr.arg).encode("utf-8") - return Literal(hashlib.sha1(s).hexdigest()) - - -def Builtin_SHA256(expr: Expr, ctx) -> Literal: - s = string(expr.arg).encode("utf-8") - return Literal(hashlib.sha256(s).hexdigest()) - - -def Builtin_SHA384(expr: Expr, ctx) -> Literal: - s = string(expr.arg).encode("utf-8") - return Literal(hashlib.sha384(s).hexdigest()) - - -def Builtin_SHA512(expr: Expr, ctx) -> Literal: - s = string(expr.arg).encode("utf-8") - return Literal(hashlib.sha512(s).hexdigest()) - - -def Builtin_COALESCE(expr: Expr, ctx): - """ - http://www.w3.org/TR/sparql11-query/#func-coalesce - """ - for x in expr.get("arg", variables=True): - if x is not None and not isinstance(x, (SPARQLError, Variable)): - return x - raise SPARQLError("COALESCE got no arguments that did not evaluate to an error") - - -def Builtin_CEIL(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-ceil - """ - - l_ = expr.arg - return Literal(int(math.ceil(numeric(l_))), datatype=l_.datatype) - - -def Builtin_FLOOR(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-floor - """ - l_ = expr.arg - return Literal(int(math.floor(numeric(l_))), datatype=l_.datatype) - - -def Builtin_ROUND(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-round - """ - - # This used to be just math.bound - # but in py3k bound was changed to - # "round-to-even" behaviour - # this is an ugly work-around - l_ = expr.arg - v = numeric(l_) - v = int(Decimal(v).quantize(1, ROUND_HALF_UP if v > 0 else ROUND_HALF_DOWN)) - return Literal(v, datatype=l_.datatype) - - -def Builtin_REGEX(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-regex - Invokes the XPath fn:matches function to match text against a regular - expression pattern. - The regular expression language is defined in XQuery 1.0 and XPath 2.0 - Functions and Operators section 7.6.1 Regular Expression Syntax - """ - - text = string(expr.text) - pattern = string(expr.pattern) - flags = expr.flags - - cFlag = 0 - if flags: - # Maps XPath REGEX flags (http://www.w3.org/TR/xpath-functions/#flags) - # to Python's re flags - flagMap = dict([("i", re.IGNORECASE), ("s", re.DOTALL), ("m", re.MULTILINE)]) - cFlag = reduce(pyop.or_, [flagMap.get(f, 0) for f in flags]) - - return Literal(bool(re.search(str(pattern), text, cFlag))) - - -def Builtin_REPLACE(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-substr - """ - text = string(expr.arg) - pattern = string(expr.pattern) - replacement = string(expr.replacement) - flags = expr.flags - - # python uses \1, xpath/sparql uses $1 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Literal") - replacement = re.sub("\\$([0-9]*)", r"\\\1", replacement) # type: ignore[assignment] - - cFlag = 0 - if flags: - # Maps XPath REGEX flags (http://www.w3.org/TR/xpath-functions/#flags) - # to Python's re flags - flagMap = dict([("i", re.IGNORECASE), ("s", re.DOTALL), ("m", re.MULTILINE)]) - cFlag = reduce(pyop.or_, [flagMap.get(f, 0) for f in flags]) - - # @@FIXME@@ either datatype OR lang, NOT both - - return Literal( - re.sub(str(pattern), replacement, text, cFlag), - datatype=text.datatype, - lang=text.language, - ) - - -def Builtin_STRDT(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strdt - """ - - return Literal(str(expr.arg1), datatype=expr.arg2) - - -def Builtin_STRLANG(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strlang - """ - - s = string(expr.arg1) - if s.language or s.datatype: - raise SPARQLError("STRLANG expects a simple literal") - - # TODO: normalisation of lang tag to lower-case - # should probably happen in literal __init__ - return Literal(str(s), lang=str(expr.arg2).lower()) - - -def Builtin_CONCAT(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-concat - """ - - # dt/lang passed on only if they all match - - dt = set(x.datatype for x in expr.arg if isinstance(x, Literal)) - # type error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "Set[Optional[str]]") - dt = dt.pop() if len(dt) == 1 else None # type: ignore[assignment] - - lang = set(x.language for x in expr.arg if isinstance(x, Literal)) - # type error: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "Set[Optional[str]]") - lang = lang.pop() if len(lang) == 1 else None # type: ignore[assignment] - - # NOTE on type errors: this is because same variable is used for two incompatibel types - # type error: Argument "datatype" to "Literal" has incompatible type "Set[Any]"; expected "Optional[str]" [arg-type] - # type error: Argument "lang" to "Literal" has incompatible type "Set[Any]"; expected "Optional[str]" - return Literal("".join(string(x) for x in expr.arg), datatype=dt, lang=lang) # type: ignore[arg-type] - - -def _compatibleStrings(a: Literal, b: Literal) -> None: - string(a) - string(b) - - if b.language and a.language != b.language: - raise SPARQLError("incompatible arguments to str functions") - - -def Builtin_STRSTARTS(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strstarts - """ - - a = expr.arg1 - b = expr.arg2 - _compatibleStrings(a, b) - - return Literal(a.startswith(b)) - - -def Builtin_STRENDS(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strends - """ - a = expr.arg1 - b = expr.arg2 - - _compatibleStrings(a, b) - - return Literal(a.endswith(b)) - - -def Builtin_STRBEFORE(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strbefore - """ - - a = expr.arg1 - b = expr.arg2 - _compatibleStrings(a, b) - - i = a.find(b) - if i == -1: - return Literal("") - else: - return Literal(a[:i], lang=a.language, datatype=a.datatype) - - -def Builtin_STRAFTER(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strafter - """ - - a = expr.arg1 - b = expr.arg2 - _compatibleStrings(a, b) - - i = a.find(b) - if i == -1: - return Literal("") - else: - return Literal(a[i + len(b) :], lang=a.language, datatype=a.datatype) - - -def Builtin_CONTAINS(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-strcontains - """ - - a = expr.arg1 - b = expr.arg2 - _compatibleStrings(a, b) - - return Literal(b in a) - - -def Builtin_ENCODE_FOR_URI(expr: Expr, ctx) -> Literal: - return Literal(quote(string(expr.arg).encode("utf-8"), safe="")) - - -def Builtin_SUBSTR(expr: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-substr - """ - - a = string(expr.arg) - - start = numeric(expr.start) - 1 - - length = expr.length - if length is not None: - length = numeric(length) + start - - return Literal(a[start:length], lang=a.language, datatype=a.datatype) - - -def Builtin_STRLEN(e: Expr, ctx) -> Literal: - l_ = string(e.arg) - - return Literal(len(l_)) - - -def Builtin_STR(e: Expr, ctx) -> Literal: - arg = e.arg - if isinstance(arg, SPARQLError): - raise arg - return Literal(str(arg)) # plain literal - - -def Builtin_LCASE(e: Expr, ctx) -> Literal: - l_ = string(e.arg) - - return Literal(l_.lower(), datatype=l_.datatype, lang=l_.language) - - -def Builtin_LANGMATCHES(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-langMatches - - - """ - langTag = string(e.arg1) - langRange = string(e.arg2) - - if str(langTag) == "": - return Literal(False) # nothing matches empty! - - return Literal(_lang_range_check(langRange, langTag)) - - -def Builtin_NOW(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-now - """ - return Literal(ctx.now) - - -def Builtin_YEAR(e: Expr, ctx) -> Literal: - d = date(e.arg) - return Literal(d.year) - - -def Builtin_MONTH(e: Expr, ctx) -> Literal: - d = date(e.arg) - return Literal(d.month) - - -def Builtin_DAY(e: Expr, ctx) -> Literal: - d = date(e.arg) - return Literal(d.day) - - -def Builtin_HOURS(e: Expr, ctx) -> Literal: - d = datetime(e.arg) - return Literal(d.hour) - - -def Builtin_MINUTES(e: Expr, ctx) -> Literal: - d = datetime(e.arg) - return Literal(d.minute) - - -def Builtin_SECONDS(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-seconds - """ - d = datetime(e.arg) - result_value = Decimal(d.second) - if d.microsecond: - result_value += Decimal(d.microsecond) / Decimal(1000000) - return Literal(result_value, datatype=XSD.decimal) - - -def Builtin_TIMEZONE(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-timezone - - :returns: the timezone part of arg as an xsd:dayTimeDuration. - :raises: an error if there is no timezone. - """ - dt = datetime(e.arg) - if not dt.tzinfo: - raise SPARQLError("datatime has no timezone: %r" % dt) - - delta = dt.utcoffset() - - # type error: Item "None" of "Optional[timedelta]" has no attribute "days" - d = delta.days # type: ignore[union-attr] - # type error: Item "None" of "Optional[timedelta]" has no attribute "seconds" - s = delta.seconds # type: ignore[union-attr] - neg = "" - - if d < 0: - s = -24 * 60 * 60 * d - s - d = 0 - neg = "-" - - h = s / (60 * 60) - m = (s - h * 60 * 60) / 60 - s = s - h * 60 * 60 - m * 60 - - tzdelta = "%sP%sT%s%s%s" % ( - neg, - "%dD" % d if d else "", - "%dH" % h if h else "", - "%dM" % m if m else "", - "%dS" % s if not d and not h and not m else "", - ) - - return Literal(tzdelta, datatype=XSD.dayTimeDuration) - - -def Builtin_TZ(e: Expr, ctx) -> Literal: - d = datetime(e.arg) - if not d.tzinfo: - return Literal("") - n = d.tzinfo.tzname(d) - if n is None: - n = "" - elif n == "UTC": - n = "Z" - elif n.startswith("UTC"): - # Replace tzname like "UTC-05:00" with simply "-05:00" to match Jena tz fn - n = n[3:] - return Literal(n) - - -def Builtin_UCASE(e: Expr, ctx) -> Literal: - l_ = string(e.arg) - - return Literal(l_.upper(), datatype=l_.datatype, lang=l_.language) - - -def Builtin_LANG(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-lang - - Returns the language tag of ltrl, if it has one. It returns "" if ltrl has - no language tag. Note that the RDF data model does not include literals - with an empty language tag. - """ - - l_ = literal(e.arg) - return Literal(l_.language or "") - - -def Builtin_DATATYPE(e: Expr, ctx) -> Optional[str]: - l_ = e.arg - if not isinstance(l_, Literal): - raise SPARQLError("Can only get datatype of literal: %r" % l_) - if l_.language: - return RDF.langString - if not l_.datatype and not l_.language: - return XSD.string - return l_.datatype - - -def Builtin_sameTerm(e: Expr, ctx) -> Literal: - a = e.arg1 - b = e.arg2 - return Literal(a == b) - - -def Builtin_BOUND(e: Expr, ctx) -> Literal: - """ - http://www.w3.org/TR/sparql11-query/#func-bound - """ - n = e.get("arg", variables=True) - - return Literal(not isinstance(n, Variable)) - - -def Builtin_EXISTS(e: Expr, ctx: FrozenBindings) -> Literal: - # damn... - from rdflib.plugins.sparql.evaluate import evalPart - - exists = e.name == "Builtin_EXISTS" - - # type error: Incompatible types in assignment (expression has type "QueryContext", variable has type "FrozenBindings") - ctx = ctx.ctx.thaw(ctx) # type: ignore[assignment] # hmm - # type error: Argument 1 to "evalPart" has incompatible type "FrozenBindings"; expected "QueryContext" - for x in evalPart(ctx, e.graph): # type: ignore[arg-type] - return Literal(exists) - return Literal(not exists) - - -_CustomFunction = Callable[[Expr, FrozenBindings], Node] - -_CUSTOM_FUNCTIONS: Dict[URIRef, Tuple[_CustomFunction, bool]] = {} - - -def register_custom_function( - uri: URIRef, func: _CustomFunction, override: bool = False, raw: bool = False -) -> None: - """ - Register a custom SPARQL function. - - By default, the function will be passed the RDF terms in the argument list. - If raw is True, the function will be passed an Expression and a Context. - - The function must return an RDF term, or raise a SparqlError. - """ - if not override and uri in _CUSTOM_FUNCTIONS: - raise ValueError("A function is already registered as %s" % uri.n3()) - _CUSTOM_FUNCTIONS[uri] = (func, raw) - - -def custom_function( - uri: URIRef, override: bool = False, raw: bool = False -) -> Callable[[_CustomFunction], _CustomFunction]: - """ - Decorator version of :func:`register_custom_function`. - """ - - def decorator(func: _CustomFunction) -> _CustomFunction: - register_custom_function(uri, func, override=override, raw=raw) - return func - - return decorator - - -def unregister_custom_function( - uri: URIRef, func: Optional[Callable[..., Any]] = None -) -> None: - """ - The 'func' argument is included for compatibility with existing code. - A previous implementation checked that the function associated with - the given uri was actually 'func', but this is not necessary as the - uri should uniquely identify the function. - """ - if _CUSTOM_FUNCTIONS.get(uri): - del _CUSTOM_FUNCTIONS[uri] - else: - warnings.warn("This function is not registered as %s" % uri.n3()) - - -def Function(e: Expr, ctx: FrozenBindings) -> Node: - """ - Custom functions and casts - """ - pair = _CUSTOM_FUNCTIONS.get(e.iri) - if pair is None: - # no such function is registered - raise SPARQLError("Unknown function %r" % e.iri) - func, raw = pair - if raw: - # function expects expression and context - return func(e, ctx) - else: - # function expects the argument list - try: - return func(*e.expr) - except TypeError as ex: - # wrong argument number - raise SPARQLError(*ex.args) - - -@custom_function(XSD.string, raw=True) -@custom_function(XSD.dateTime, raw=True) -@custom_function(XSD.float, raw=True) -@custom_function(XSD.double, raw=True) -@custom_function(XSD.decimal, raw=True) -@custom_function(XSD.integer, raw=True) -@custom_function(XSD.boolean, raw=True) -def default_cast(e: Expr, ctx: FrozenBindings) -> Literal: # type: ignore[return] - if not e.expr: - raise SPARQLError("Nothing given to cast.") - if len(e.expr) > 1: - raise SPARQLError("Cannot cast more than one thing!") - - x = e.expr[0] - - if e.iri == XSD.string: - if isinstance(x, (URIRef, Literal)): - return Literal(x, datatype=XSD.string) - else: - raise SPARQLError("Cannot cast term %r of type %r" % (x, type(x))) - - if not isinstance(x, Literal): - raise SPARQLError("Can only cast Literals to non-string data-types") - - if x.datatype and not x.datatype in XSD_DTs: # noqa: E713 - raise SPARQLError("Cannot cast literal with unknown datatype: %r" % x.datatype) - - if e.iri == XSD.dateTime: - if x.datatype and x.datatype not in (XSD.dateTime, XSD.string): - raise SPARQLError("Cannot cast %r to XSD:dateTime" % x.datatype) - try: - return Literal(parse_datetime(x), datatype=e.iri) - except: # noqa: E722 - raise SPARQLError("Cannot interpret '%r' as datetime" % x) - - if x.datatype == XSD.dateTime: - raise SPARQLError("Cannot cast XSD.dateTime to %r" % e.iri) - - if e.iri in (XSD.float, XSD.double): - try: - return Literal(float(x), datatype=e.iri) - except: # noqa: E722 - raise SPARQLError("Cannot interpret '%r' as float" % x) - - elif e.iri == XSD.decimal: - if "e" in x or "E" in x: # SPARQL/XSD does not allow exponents in decimals - raise SPARQLError("Cannot interpret '%r' as decimal" % x) - try: - return Literal(Decimal(x), datatype=e.iri) - except: # noqa: E722 - raise SPARQLError("Cannot interpret '%r' as decimal" % x) - - elif e.iri == XSD.integer: - try: - return Literal(int(x), datatype=XSD.integer) - except: # noqa: E722 - raise SPARQLError("Cannot interpret '%r' as int" % x) - - elif e.iri == XSD.boolean: - # # I would argue that any number is True... - # try: - # return Literal(bool(int(x)), datatype=XSD.boolean) - # except: - if x.lower() in ("1", "true"): - return Literal(True) - if x.lower() in ("0", "false"): - return Literal(False) - raise SPARQLError("Cannot interpret '%r' as bool" % x) - - -def UnaryNot(expr: Expr, ctx: FrozenBindings) -> Literal: - return Literal(not EBV(expr.expr)) - - -def UnaryMinus(expr: Expr, ctx: FrozenBindings) -> Literal: - return Literal(-numeric(expr.expr)) - - -def UnaryPlus(expr: Expr, ctx: FrozenBindings) -> Literal: - return Literal(+numeric(expr.expr)) - - -def MultiplicativeExpression( - e: Expr, ctx: Union[QueryContext, FrozenBindings] -) -> Literal: - expr = e.expr - other = e.other - - # because of the way the mul-expr production handled operator precedence - # we sometimes have nothing to do - if other is None: - return expr - try: - res: Union[Decimal, float] - res = Decimal(numeric(expr)) - for op, f in zip(e.op, other): - f = numeric(f) - - if type(f) == float: # noqa: E721 - res = float(res) - - if op == "*": - res *= f - else: - res /= f - except (InvalidOperation, ZeroDivisionError): - raise SPARQLError("divide by 0") - - return Literal(res) - - -# type error: Missing return statement -def AdditiveExpression(e: Expr, ctx: Union[QueryContext, FrozenBindings]) -> Literal: # type: ignore[return] - expr = e.expr - other = e.other - - # because of the way the add-expr production handled operator precedence - # we sometimes have nothing to do - if other is None: - return expr - - # handling arithmetic(addition/subtraction) of dateTime, date, time - # and duration datatypes (if any) - if hasattr(expr, "datatype") and ( - expr.datatype in XSD_DateTime_DTs or expr.datatype in XSD_Duration_DTs - ): - res = dateTimeObjects(expr) - dt = expr.datatype - - for op, term in zip(e.op, other): - # check if operation is datetime,date,time operation over - # another datetime,date,time datatype - if dt in XSD_DateTime_DTs and dt == term.datatype and op == "-": - # checking if there are more than one datetime operands - - # in that case it doesn't make sense for example - # ( dateTime1 - dateTime2 - dateTime3 ) is an invalid operation - if len(other) > 1: - error_message = "Can't evaluate multiple %r arguments" - # type error: Too many arguments for "SPARQLError" - raise SPARQLError(error_message, dt.datatype) # type: ignore[call-arg] - else: - n = dateTimeObjects(term) - res = calculateDuration(res, n) - return res - - # datetime,date,time +/- duration,dayTimeDuration,yearMonthDuration - elif dt in XSD_DateTime_DTs and term.datatype in XSD_Duration_DTs: - n = dateTimeObjects(term) - res = calculateFinalDateTime(res, dt, n, term.datatype, op) - return res - - # duration,dayTimeDuration,yearMonthDuration + datetime,date,time - elif dt in XSD_Duration_DTs and term.datatype in XSD_DateTime_DTs: - if op == "+": - n = dateTimeObjects(term) - res = calculateFinalDateTime(res, dt, n, term.datatype, op) - return res - - # rest are invalid types - else: - raise SPARQLError("Invalid DateTime Operations") - - # handling arithmetic(addition/subtraction) of numeric datatypes (if any) - else: - res = numeric(expr) - - dt = expr.datatype - - for op, term in zip(e.op, other): - n = numeric(term) - if isinstance(n, Decimal) and isinstance(res, float): - n = float(n) - if isinstance(n, float) and isinstance(res, Decimal): - res = float(res) - - dt = type_promotion(dt, term.datatype) - - if op == "+": - res += n - else: - res -= n - - return Literal(res, datatype=dt) - - -def RelationalExpression(e: Expr, ctx: Union[QueryContext, FrozenBindings]) -> Literal: - expr = e.expr - other = e.other - op = e.op - - # because of the way the add-expr production handled operator precedence - # we sometimes have nothing to do - if other is None: - return expr - - ops = dict( - [ - (">", lambda x, y: x.__gt__(y)), - ("<", lambda x, y: x.__lt__(y)), - ("=", lambda x, y: x.eq(y)), - ("!=", lambda x, y: x.neq(y)), - (">=", lambda x, y: x.__ge__(y)), - ("<=", lambda x, y: x.__le__(y)), - ("IN", pyop.contains), - ("NOT IN", lambda x, y: not pyop.contains(x, y)), - ] - ) - - if op in ("IN", "NOT IN"): - res = op == "NOT IN" - - error: Union[bool, SPARQLError] = False - - if other == RDF.nil: - other = [] - - for x in other: - try: - if x == expr: - return Literal(True ^ res) - except SPARQLError as e: - error = e - if not error: - return Literal(False ^ res) - else: - # Note on type error: this is because variable is Union[bool, SPARQLError] - # type error: Exception must be derived from BaseException - raise error # type: ignore[misc] - - if op not in ("=", "!=", "IN", "NOT IN"): - if not isinstance(expr, Literal): - raise SPARQLError( - "Compare other than =, != of non-literals is an error: %r" % expr - ) - if not isinstance(other, Literal): - raise SPARQLError( - "Compare other than =, != of non-literals is an error: %r" % other - ) - else: - if not isinstance(expr, Node): - raise SPARQLError("I cannot compare this non-node: %r" % expr) - if not isinstance(other, Node): - raise SPARQLError("I cannot compare this non-node: %r" % other) - - if isinstance(expr, Literal) and isinstance(other, Literal): - if ( - expr.datatype is not None - and expr.datatype not in XSD_DTs - and other.datatype is not None - and other.datatype not in XSD_DTs - ): - # in SPARQL for non-XSD DT Literals we can only do =,!= - if op not in ("=", "!="): - raise SPARQLError("Can only do =,!= comparisons of non-XSD Literals") - - try: - r = ops[op](expr, other) - if r == NotImplemented: - raise SPARQLError("Error when comparing") - except TypeError as te: - raise SPARQLError(*te.args) - return Literal(r) - - -def ConditionalAndExpression( - e: Expr, ctx: Union[QueryContext, FrozenBindings] -) -> Literal: - # TODO: handle returned errors - - expr = e.expr - other = e.other - - # because of the way the add-expr production handled operator precedence - # we sometimes have nothing to do - if other is None: - return expr - - return Literal(all(EBV(x) for x in [expr] + other)) - - -def ConditionalOrExpression( - e: Expr, ctx: Union[QueryContext, FrozenBindings] -) -> Literal: - # TODO: handle errors - - expr = e.expr - other = e.other - - # because of the way the add-expr production handled operator precedence - # we sometimes have nothing to do - if other is None: - return expr - # A logical-or that encounters an error on only one branch - # will return TRUE if the other branch is TRUE and an error - # if the other branch is FALSE. - error = None - for x in [expr] + other: - try: - if EBV(x): - return Literal(True) - except SPARQLError as e: - error = e - if error: - raise error - return Literal(False) - - -def not_(arg) -> Expr: - return Expr("UnaryNot", UnaryNot, expr=arg) - - -def and_(*args: Expr) -> Expr: - if len(args) == 1: - return args[0] - - return Expr( - "ConditionalAndExpression", - ConditionalAndExpression, - expr=args[0], - other=list(args[1:]), - ) - - -TrueFilter = Expr("TrueFilter", lambda _1, _2: Literal(True)) - - -def simplify(expr: Any) -> Any: - if isinstance(expr, ParseResults) and len(expr) == 1: - return simplify(expr[0]) - - if isinstance(expr, (list, ParseResults)): - return list(map(simplify, expr)) - if not isinstance(expr, CompValue): - return expr - if expr.name.endswith("Expression"): - if expr.other is None: - return simplify(expr.expr) - - for k in expr.keys(): - expr[k] = simplify(expr[k]) - # expr['expr']=simplify(expr.expr) - # expr['other']=simplify(expr.other) - - return expr - - -def literal(s: Literal) -> Literal: - if not isinstance(s, Literal): - raise SPARQLError("Non-literal passed as string: %r" % s) - return s - - -def datetime(e: Literal) -> py_datetime.datetime: - if not isinstance(e, Literal): - raise SPARQLError("Non-literal passed as datetime: %r" % e) - if not e.datatype == XSD.dateTime: - raise SPARQLError("Literal with wrong datatype passed as datetime: %r" % e) - return e.toPython() - - -def date(e: Literal) -> py_datetime.date: - if not isinstance(e, Literal): - raise SPARQLError("Non-literal passed as date: %r" % e) - if e.datatype not in (XSD.date, XSD.dateTime): - raise SPARQLError("Literal with wrong datatype passed as date: %r" % e) - result = e.toPython() - if isinstance(result, py_datetime.datetime): - return result.date() - return result - - -def string(s: Literal) -> Literal: - """ - Make sure the passed thing is a string literal - i.e. plain literal, xsd:string literal or lang-tagged literal - """ - if not isinstance(s, Literal): - raise SPARQLError("Non-literal passes as string: %r" % s) - if s.datatype and s.datatype != XSD.string: - raise SPARQLError("Non-string datatype-literal passes as string: %r" % s) - return s - - -def numeric(expr: Literal) -> Any: - """ - return a number from a literal - http://www.w3.org/TR/xpath20/#promotion - - or TypeError - """ - - if not isinstance(expr, Literal): - raise SPARQLTypeError("%r is not a literal!" % expr) - - if expr.datatype not in ( - XSD.float, - XSD.double, - XSD.decimal, - XSD.integer, - XSD.nonPositiveInteger, - XSD.negativeInteger, - XSD.nonNegativeInteger, - XSD.positiveInteger, - XSD.unsignedLong, - XSD.unsignedInt, - XSD.unsignedShort, - XSD.unsignedByte, - XSD.long, - XSD.int, - XSD.short, - XSD.byte, - ): - raise SPARQLTypeError("%r does not have a numeric datatype!" % expr) - - return expr.toPython() - - -def dateTimeObjects(expr: Literal) -> Any: - """ - return a dataTime/date/time/duration/dayTimeDuration/yearMonthDuration python objects from a literal - - """ - return expr.toPython() - - -# type error: Missing return statement -def isCompatibleDateTimeDatatype( # type: ignore[return] - obj1: Union[py_datetime.date, py_datetime.datetime], - dt1: URIRef, - obj2: Union[Duration, py_datetime.timedelta], - dt2: URIRef, -) -> bool: - """ - Returns a boolean indicating if first object is compatible - with operation(+/-) over second object. - - """ - if dt1 == XSD.date: - if dt2 == XSD.yearMonthDuration: - return True - elif dt2 == XSD.dayTimeDuration or dt2 == XSD.Duration: - # checking if the dayTimeDuration has no Time Component - # else it won't be compatible with Date Literal - if "T" in str(obj2): - return False - else: - return True - - if dt1 == XSD.time: - if dt2 == XSD.yearMonthDuration: - return False - elif dt2 == XSD.dayTimeDuration or dt2 == XSD.Duration: - # checking if the dayTimeDuration has no Date Component - # (by checking if the format is "PT...." ) - # else it won't be compatible with Time Literal - if "T" == str(obj2)[1]: - return True - else: - return False - - if dt1 == XSD.dateTime: - # compatible with all - return True - - -def calculateDuration( - obj1: Union[py_datetime.date, py_datetime.datetime], - obj2: Union[py_datetime.date, py_datetime.datetime], -) -> Literal: - """ - returns the duration Literal between two datetime - - """ - date1 = obj1 - date2 = obj2 - # type error: No overload variant of "__sub__" of "datetime" matches argument type "date" - difference = date1 - date2 # type: ignore[operator] - return Literal(difference, datatype=XSD.duration) - - -def calculateFinalDateTime( - obj1: Union[py_datetime.date, py_datetime.datetime], - dt1: URIRef, - obj2: Union[Duration, py_datetime.timedelta], - dt2: URIRef, - operation: str, -) -> Literal: - """ - Calculates the final dateTime/date/time resultant after addition/ - subtraction of duration/dayTimeDuration/yearMonthDuration - """ - - # checking compatibility of datatypes (duration types and date/time/dateTime) - if isCompatibleDateTimeDatatype(obj1, dt1, obj2, dt2): - # proceed - if operation == "-": - ans = obj1 - obj2 - return Literal(ans, datatype=dt1) - else: - ans = obj1 + obj2 - return Literal(ans, datatype=dt1) - - else: - raise SPARQLError("Incompatible Data types to DateTime Operations") - - -@overload -def EBV(rt: Literal) -> bool: ... - - -@overload -def EBV(rt: Union[Variable, IdentifiedNode, SPARQLError, Expr]) -> NoReturn: ... - - -@overload -def EBV(rt: Union[Identifier, SPARQLError, Expr]) -> Union[bool, NoReturn]: ... - - -def EBV(rt: Union[Identifier, SPARQLError, Expr]) -> bool: - """ - Effective Boolean Value (EBV) - - * If the argument is a typed literal with a datatype of xsd:boolean, - the EBV is the value of that argument. - * If the argument is a plain literal or a typed literal with a - datatype of xsd:string, the EBV is false if the operand value - has zero length; otherwise the EBV is true. - * If the argument is a numeric type or a typed literal with a datatype - derived from a numeric type, the EBV is false if the operand value is - NaN or is numerically equal to zero; otherwise the EBV is true. - * All other arguments, including unbound arguments, produce a type error. - - """ - - if isinstance(rt, Literal): - if rt.datatype == XSD.boolean: - return rt.toPython() - - elif rt.datatype == XSD.string or rt.datatype is None: - return len(rt) > 0 - - else: - pyRT = rt.toPython() - - if isinstance(pyRT, Literal): - # Type error, see: http://www.w3.org/TR/rdf-sparql-query/#ebv - raise SPARQLTypeError( - "http://www.w3.org/TR/rdf-sparql-query/#ebv - ' + \ - 'Could not determine the EBV for : %r" - % rt - ) - else: - return bool(pyRT) - - else: - raise SPARQLTypeError( - "http://www.w3.org/TR/rdf-sparql-query/#ebv - ' + \ - 'Only literals have Boolean values! %r" - % rt - ) - - -def _lang_range_check(range: Literal, lang: Literal) -> bool: - """ - Implementation of the extended filtering algorithm, as defined in point - 3.3.2, of U{RFC 4647}, on - matching language ranges and language tags. - Needed to handle the C{rdf:PlainLiteral} datatype. - @param range: language range - @param lang: language tag - @rtype: boolean - - @author: U{Ivan Herman} - - Taken from `RDFClosure/RestrictedDatatype.py`__ - - .. __:http://dev.w3.org/2004/PythonLib-IH/RDFClosure/RestrictedDatatype.py - - """ - - def _match(r: str, l_: str) -> bool: - """ - Matching of a range and language item: either range is a wildcard - or the two are equal - @param r: language range item - @param l_: language tag item - @rtype: boolean - """ - return r == "*" or r == l_ - - rangeList = range.strip().lower().split("-") - langList = lang.strip().lower().split("-") - if not _match(rangeList[0], langList[0]): - return False - if len(rangeList) > len(langList): - return False - - return all(_match(*x) for x in zip(rangeList, langList)) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parser.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parser.py deleted file mode 100644 index 789d076..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parser.py +++ /dev/null @@ -1,1564 +0,0 @@ -""" -SPARQL 1.1 Parser - -based on pyparsing -""" - -from __future__ import annotations # noqa: I001 - -import re -import sys -from typing import Any, BinaryIO, List -from typing import Optional as OptionalType -from typing import TextIO, Tuple, Union - -from pyparsing import CaselessKeyword as Keyword # watch out :) -from pyparsing import ( - Combine, - Forward, - Group, - Literal, - OneOrMore, - Optional, - ParseResults, - Regex, - Suppress, - ZeroOrMore, - delimitedList, - restOfLine, -) - -import rdflib -from rdflib.compat import decodeUnicodeEscape - -from . import operators as op -from .parserutils import Comp, CompValue, Param, ParamList - -# from pyparsing import Keyword as CaseSensitiveKeyword - - -DEBUG = False - -# ---------------- ACTIONS - - -def neg(literal: rdflib.Literal) -> rdflib.Literal: - return rdflib.Literal(-literal, datatype=literal.datatype) - - -def setLanguage(terms: Tuple[Any, OptionalType[str]]) -> rdflib.Literal: - return rdflib.Literal(terms[0], lang=terms[1]) - - -def setDataType(terms: Tuple[Any, OptionalType[str]]) -> rdflib.Literal: - return rdflib.Literal(terms[0], datatype=terms[1]) - - -def expandTriples(terms: ParseResults) -> List[Any]: - """ - Expand ; and , syntax for repeat predicates, subjects - """ - # import pdb; pdb.set_trace() - last_subject, last_predicate = None, None # Used for ; and , - try: - res: List[Any] = [] - if DEBUG: - print("Terms", terms) - l_ = len(terms) - for i, t in enumerate(terms): - if t == ",": - res.extend([last_subject, last_predicate]) - elif t == ";": - if i + 1 == len(terms) or terms[i + 1] == ";" or terms[i + 1] == ".": - continue # this semicolon is spurious - res.append(last_subject) - elif isinstance(t, list): - # BlankNodePropertyList - # is this bnode the object of previous triples? - if (len(res) % 3) == 2: - res.append(t[0]) - # is this a single [] ? - if len(t) > 1: - res += t # Don't update last_subject/last_predicate - # is this bnode the subject of more triples? - if i + 1 < l_ and terms[i + 1] not in [ - ".", - ",", - ";", - ]: # term might not be a string - last_subject, last_predicate = t[0], None - res.append(t[0]) - elif isinstance(t, ParseResults): - res += t.asList() - elif t != ".": - res.append(t) - if (len(res) % 3) == 1: - last_subject = t - elif (len(res) % 3) == 2: - last_predicate = t - if DEBUG: - print(len(res), t) - if DEBUG: - import json - - print(json.dumps(res, indent=2)) - - return res - # print res - # assert len(res)%3 == 0, \ - # "Length of triple-list is not divisible by 3: %d!"%len(res) - - # return [tuple(res[i:i+3]) for i in range(len(res)/3)] - except: - if DEBUG: - import traceback - - traceback.print_exc() - raise - - -def expandBNodeTriples(terms: ParseResults) -> List[Any]: - """ - expand [ ?p ?o ] syntax for implicit bnodes - """ - # import pdb; pdb.set_trace() - try: - if DEBUG: - print("Bnode terms", terms) - print("1", terms[0]) - print("2", [rdflib.BNode()] + terms.asList()[0]) - return [expandTriples([rdflib.BNode()] + terms.asList()[0])] - except Exception as e: - if DEBUG: - print(">>>>>>>>", e) - raise - - -def expandCollection(terms: ParseResults) -> List[List[Any]]: - """ - expand ( 1 2 3 ) notation for collections - """ - if DEBUG: - print("Collection: ", terms) - - res: List[Any] = [] - other = [] - for x in terms: - if isinstance(x, list): # is this a [ .. ] ? - other += x - x = x[0] - - b = rdflib.BNode() - if res: - res += [res[-3], rdflib.RDF.rest, b, b, rdflib.RDF.first, x] - else: - res += [b, rdflib.RDF.first, x] - res += [b, rdflib.RDF.rest, rdflib.RDF.nil] - - res += other - - if DEBUG: - print("CollectionOut", res) - return [res] - - -# SPARQL Grammar from http://www.w3.org/TR/sparql11-query/#grammar -# ------ TERMINALS -------------- -# [139] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20])* '>' -IRIREF = Combine( - Suppress("<") - + Regex(r'[^<>"{}|^`\\%s]*' % "".join("\\x%02X" % i for i in range(33))) - + Suppress(">") -) -IRIREF.setParseAction(lambda x: rdflib.URIRef(x[0])) - -# [164] P_CHARS_BASE ::= [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] - -if sys.maxunicode == 0xFFFF: - # this is narrow python build (default on windows/osx) - # this means that unicode code points over 0xffff are stored - # as several characters, which in turn means that regex character - # ranges with these characters do not work. - # See - # * http://bugs.python.org/issue12729 - # * http://bugs.python.org/issue12749 - # * http://bugs.python.org/issue3665 - # - # Here we simple skip the [#x10000-#xEFFFF] part - # this means that some SPARQL queries will not parse :( - # We *could* generate a new regex with \U00010000|\U00010001 ... - # but it would be quite long :) - # - # in py3.3 this is fixed - - PN_CHARS_BASE_re = "A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD" -else: - # wide python build - PN_CHARS_BASE_re = "A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\U00010000-\U000EFFFF" - -# [165] PN_CHARS_U ::= PN_CHARS_BASE | '_' -PN_CHARS_U_re = "_" + PN_CHARS_BASE_re - -# [167] PN_CHARS ::= PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] -PN_CHARS_re = "\\-0-9\u00B7\u0300-\u036F\u203F-\u2040" + PN_CHARS_U_re -# PN_CHARS = Regex(u'[%s]'%PN_CHARS_re, flags=re.U) - -# [168] PN_PREFIX ::= PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)? -PN_PREFIX = Regex( - "[%s](?:[%s\\.]*[%s])?" % (PN_CHARS_BASE_re, PN_CHARS_re, PN_CHARS_re), flags=re.U -) - -# [140] PNAME_NS ::= PN_PREFIX? ':' -PNAME_NS = Optional(Param("prefix", PN_PREFIX)) + Suppress(":").leaveWhitespace() - -# [173] PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' ) - -PN_LOCAL_ESC_re = "\\\\[_~\\.\\-!$&\"'()*+,;=/?#@%]" -# PN_LOCAL_ESC = Regex(PN_LOCAL_ESC_re) # regex'd -# PN_LOCAL_ESC.setParseAction(lambda x: x[0][1:]) - -# [172] HEX ::= [0-9] | [A-F] | [a-f] -# HEX = Regex('[0-9A-Fa-f]') # not needed - -# [171] PERCENT ::= '%' HEX HEX -PERCENT_re = "%[0-9a-fA-F]{2}" -# PERCENT = Regex(PERCENT_re) # regex'd -# PERCENT.setParseAction(lambda x: chr(int(x[0][1:], 16))) - -# [170] PLX ::= PERCENT | PN_LOCAL_ESC -PLX_re = "(%s|%s)" % (PN_LOCAL_ESC_re, PERCENT_re) -# PLX = PERCENT | PN_LOCAL_ESC # regex'd - - -# [169] PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )? - -PN_LOCAL = Regex( - """([%(PN_CHARS_U)s:0-9]|%(PLX)s) - (([%(PN_CHARS)s\\.:]|%(PLX)s)* - ([%(PN_CHARS)s:]|%(PLX)s) )?""" - % dict(PN_CHARS_U=PN_CHARS_U_re, PN_CHARS=PN_CHARS_re, PLX=PLX_re), - flags=re.X | re.UNICODE, -) - - -# [141] PNAME_LN ::= PNAME_NS PN_LOCAL -PNAME_LN = PNAME_NS + Param("localname", PN_LOCAL.leaveWhitespace()) - -# [142] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)? -BLANK_NODE_LABEL = Regex( - "_:[0-9%s](?:[\\.%s]*[%s])?" % (PN_CHARS_U_re, PN_CHARS_re, PN_CHARS_re), - flags=re.U, -) -BLANK_NODE_LABEL.setParseAction(lambda x: rdflib.BNode(x[0][2:])) - - -# [166] VARNAME ::= ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )* -VARNAME = Regex( - "[%s0-9][%s0-9\u00B7\u0300-\u036F\u203F-\u2040]*" % (PN_CHARS_U_re, PN_CHARS_U_re), - flags=re.U, -) - -# [143] VAR1 ::= '?' VARNAME -VAR1 = Combine(Suppress("?") + VARNAME) - -# [144] VAR2 ::= '$' VARNAME -VAR2 = Combine(Suppress("$") + VARNAME) - -# [145] LANGTAG ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* -LANGTAG = Combine(Suppress("@") + Regex("[a-zA-Z]+(?:-[a-zA-Z0-9]+)*")) - -# [146] INTEGER ::= [0-9]+ -INTEGER = Regex(r"[0-9]+") -# INTEGER.setResultsName('integer') -INTEGER.setParseAction(lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.integer)) - -# [155] EXPONENT ::= [eE] [+-]? [0-9]+ -EXPONENT_re = "[eE][+-]?[0-9]+" - -# [147] DECIMAL ::= [0-9]* '.' [0-9]+ -DECIMAL = Regex(r"[0-9]*\.[0-9]+") # (?![eE]) -# DECIMAL.setResultsName('decimal') -DECIMAL.setParseAction(lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.decimal)) - -# [148] DOUBLE ::= [0-9]+ '.' [0-9]* EXPONENT | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT -DOUBLE = Regex(r"[0-9]+\.[0-9]*%(e)s|\.([0-9])+%(e)s|[0-9]+%(e)s" % {"e": EXPONENT_re}) -# DOUBLE.setResultsName('double') -DOUBLE.setParseAction(lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.double)) - - -# [149] INTEGER_POSITIVE ::= '+' INTEGER -INTEGER_POSITIVE = Suppress("+") + INTEGER.copy().leaveWhitespace() -INTEGER_POSITIVE.setParseAction( - lambda x: rdflib.Literal("+" + x[0], datatype=rdflib.XSD.integer) -) - -# [150] DECIMAL_POSITIVE ::= '+' DECIMAL -DECIMAL_POSITIVE = Suppress("+") + DECIMAL.copy().leaveWhitespace() - -# [151] DOUBLE_POSITIVE ::= '+' DOUBLE -DOUBLE_POSITIVE = Suppress("+") + DOUBLE.copy().leaveWhitespace() - -# [152] INTEGER_NEGATIVE ::= '-' INTEGER -INTEGER_NEGATIVE = Suppress("-") + INTEGER.copy().leaveWhitespace() -INTEGER_NEGATIVE.setParseAction(lambda x: neg(x[0])) - -# [153] DECIMAL_NEGATIVE ::= '-' DECIMAL -DECIMAL_NEGATIVE = Suppress("-") + DECIMAL.copy().leaveWhitespace() -DECIMAL_NEGATIVE.setParseAction(lambda x: neg(x[0])) - -# [154] DOUBLE_NEGATIVE ::= '-' DOUBLE -DOUBLE_NEGATIVE = Suppress("-") + DOUBLE.copy().leaveWhitespace() -DOUBLE_NEGATIVE.setParseAction(lambda x: neg(x[0])) - -# [160] ECHAR ::= '\' [tbnrf\"'] -# ECHAR = Regex('\\\\[tbnrf"\']') - - -# [158] STRING_LITERAL_LONG1 ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR ) )* "'''" -# STRING_LITERAL_LONG1 = Literal("'''") + ( Optional( Literal("'") | "''" -# ) + ZeroOrMore( ~ Literal("'\\") | ECHAR ) ) + "'''" -STRING_LITERAL_LONG1 = Regex("'''((?:'|'')?(?:[^'\\\\]|\\\\['ntbrf\\\\]))*'''") -STRING_LITERAL_LONG1.setParseAction( - lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][3:-3])) -) - -# [159] STRING_LITERAL_LONG2 ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR ) )* '"""' -# STRING_LITERAL_LONG2 = Literal('"""') + ( Optional( Literal('"') | '""' -# ) + ZeroOrMore( ~ Literal('"\\') | ECHAR ) ) + '"""' -STRING_LITERAL_LONG2 = Regex('"""(?:(?:"|"")?(?:[^"\\\\]|\\\\["ntbrf\\\\]))*"""') -STRING_LITERAL_LONG2.setParseAction( - lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][3:-3])) -) - -# [156] STRING_LITERAL1 ::= "'" ( ([^#x27#x5C#xA#xD]) | ECHAR )* "'" -# STRING_LITERAL1 = Literal("'") + ZeroOrMore( -# Regex(u'[^\u0027\u005C\u000A\u000D]',flags=re.U) | ECHAR ) + "'" - -STRING_LITERAL1 = Regex("'(?:[^'\\n\\r\\\\]|\\\\['ntbrf\\\\])*'(?!')", flags=re.U) -STRING_LITERAL1.setParseAction( - lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][1:-1])) -) - -# [157] STRING_LITERAL2 ::= '"' ( ([^#x22#x5C#xA#xD]) | ECHAR )* '"' -# STRING_LITERAL2 = Literal('"') + ZeroOrMore ( -# Regex(u'[^\u0022\u005C\u000A\u000D]',flags=re.U) | ECHAR ) + '"' - -STRING_LITERAL2 = Regex('"(?:[^"\\n\\r\\\\]|\\\\["ntbrf\\\\])*"(?!")', flags=re.U) -STRING_LITERAL2.setParseAction( - lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][1:-1])) -) - -# [161] NIL ::= '(' WS* ')' -NIL = Literal("(") + ")" -NIL.setParseAction(lambda x: rdflib.RDF.nil) - -# [162] WS ::= #x20 | #x9 | #xD | #xA -# Not needed? -# WS = #x20 | #x9 | #xD | #xA -# [163] ANON ::= '[' WS* ']' -ANON = Literal("[") + "]" -ANON.setParseAction(lambda x: rdflib.BNode()) - -# A = CaseSensitiveKeyword('a') -A = Literal("a") -A.setParseAction(lambda x: rdflib.RDF.type) - - -# ------ NON-TERMINALS -------------- - -# [5] BaseDecl ::= 'BASE' IRIREF -BaseDecl = Comp("Base", Keyword("BASE") + Param("iri", IRIREF)) - -# [6] PrefixDecl ::= 'PREFIX' PNAME_NS IRIREF -PrefixDecl = Comp("PrefixDecl", Keyword("PREFIX") + PNAME_NS + Param("iri", IRIREF)) - -# [4] Prologue ::= ( BaseDecl | PrefixDecl )* -Prologue = Group(ZeroOrMore(BaseDecl | PrefixDecl)) - -# [108] Var ::= VAR1 | VAR2 -Var = VAR1 | VAR2 -Var.setParseAction(lambda x: rdflib.term.Variable(x[0])) - -# [137] PrefixedName ::= PNAME_LN | PNAME_NS -PrefixedName = Comp("pname", PNAME_LN | PNAME_NS) - -# [136] iri ::= IRIREF | PrefixedName -iri = IRIREF | PrefixedName - -# [135] String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2 -String = STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2 | STRING_LITERAL1 | STRING_LITERAL2 - -# [129] RDFLiteral ::= String ( LANGTAG | ( '^^' iri ) )? - -RDFLiteral = Comp( - "literal", - Param("string", String) - + Optional( - Param("lang", LANGTAG.leaveWhitespace()) - | Literal("^^").leaveWhitespace() + Param("datatype", iri).leaveWhitespace() - ), -) - -# [132] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE -NumericLiteralPositive = DOUBLE_POSITIVE | DECIMAL_POSITIVE | INTEGER_POSITIVE - -# [133] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE -NumericLiteralNegative = DOUBLE_NEGATIVE | DECIMAL_NEGATIVE | INTEGER_NEGATIVE - -# [131] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE -NumericLiteralUnsigned = DOUBLE | DECIMAL | INTEGER - -# [130] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative -NumericLiteral = ( - NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative -) - -# [134] BooleanLiteral ::= 'true' | 'false' -BooleanLiteral = Keyword("true").setParseAction(lambda: rdflib.Literal(True)) | Keyword( - "false" -).setParseAction(lambda: rdflib.Literal(False)) - -# [138] BlankNode ::= BLANK_NODE_LABEL | ANON -BlankNode = BLANK_NODE_LABEL | ANON - -# [109] GraphTerm ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL -GraphTerm = iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL - -# [106] VarOrTerm ::= Var | GraphTerm -VarOrTerm = Var | GraphTerm - -# [107] VarOrIri ::= Var | iri -VarOrIri = Var | iri - -# [46] GraphRef ::= 'GRAPH' iri -GraphRef = Keyword("GRAPH") + Param("graphiri", iri) - -# [47] GraphRefAll ::= GraphRef | 'DEFAULT' | 'NAMED' | 'ALL' -GraphRefAll = ( - GraphRef - | Param("graphiri", Keyword("DEFAULT")) - | Param("graphiri", Keyword("NAMED")) - | Param("graphiri", Keyword("ALL")) -) - -# [45] GraphOrDefault ::= 'DEFAULT' | 'GRAPH'? iri -GraphOrDefault = ParamList("graph", Keyword("DEFAULT")) | Optional( - Keyword("GRAPH") -) + ParamList("graph", iri) - -# [65] DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF' -DataBlockValue = iri | RDFLiteral | NumericLiteral | BooleanLiteral | Keyword("UNDEF") - -# [78] Verb ::= VarOrIri | A -Verb = VarOrIri | A - - -# [85] VerbSimple ::= Var -VerbSimple = Var - -# [97] Integer ::= INTEGER -Integer = INTEGER - - -TriplesNode = Forward() -TriplesNodePath = Forward() - -# [104] GraphNode ::= VarOrTerm | TriplesNode -GraphNode = VarOrTerm | TriplesNode - -# [105] GraphNodePath ::= VarOrTerm | TriplesNodePath -GraphNodePath = VarOrTerm | TriplesNodePath - - -# [93] PathMod ::= '?' | '*' | '+' -PathMod = Literal("?") | "*" | "+" - -# [96] PathOneInPropertySet ::= iri | A | '^' ( iri | A ) -PathOneInPropertySet = iri | A | Comp("InversePath", "^" + (iri | A)) - -Path = Forward() - -# [95] PathNegatedPropertySet ::= PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')' -PathNegatedPropertySet = Comp( - "PathNegatedPropertySet", - ParamList("part", PathOneInPropertySet) - | "(" - + Optional( - ParamList("part", PathOneInPropertySet) - + ZeroOrMore("|" + ParamList("part", PathOneInPropertySet)) - ) - + ")", -) - -# [94] PathPrimary ::= iri | A | '!' PathNegatedPropertySet | '(' Path ')' | 'DISTINCT' '(' Path ')' -PathPrimary = ( - iri - | A - | Suppress("!") + PathNegatedPropertySet - | Suppress("(") + Path + Suppress(")") - | Comp("DistinctPath", Keyword("DISTINCT") + "(" + Param("part", Path) + ")") -) - -# [91] PathElt ::= PathPrimary Optional(PathMod) -PathElt = Comp( - "PathElt", - Param("part", PathPrimary) + Optional(Param("mod", PathMod.leaveWhitespace())), -) - -# [92] PathEltOrInverse ::= PathElt | '^' PathElt -PathEltOrInverse = PathElt | Suppress("^") + Comp( - "PathEltOrInverse", Param("part", PathElt) -) - -# [90] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )* -PathSequence = Comp( - "PathSequence", - ParamList("part", PathEltOrInverse) - + ZeroOrMore("/" + ParamList("part", PathEltOrInverse)), -) - - -# [89] PathAlternative ::= PathSequence ( '|' PathSequence )* -PathAlternative = Comp( - "PathAlternative", - ParamList("part", PathSequence) + ZeroOrMore("|" + ParamList("part", PathSequence)), -) - -# [88] Path ::= PathAlternative -Path <<= PathAlternative - -# [84] VerbPath ::= Path -VerbPath = Path - -# [87] ObjectPath ::= GraphNodePath -ObjectPath = GraphNodePath - -# [86] ObjectListPath ::= ObjectPath ( ',' ObjectPath )* -ObjectListPath = ObjectPath + ZeroOrMore("," + ObjectPath) - - -GroupGraphPattern = Forward() - - -# [102] Collection ::= '(' OneOrMore(GraphNode) ')' -Collection = Suppress("(") + OneOrMore(GraphNode) + Suppress(")") -Collection.setParseAction(expandCollection) - -# [103] CollectionPath ::= '(' OneOrMore(GraphNodePath) ')' -CollectionPath = Suppress("(") + OneOrMore(GraphNodePath) + Suppress(")") -CollectionPath.setParseAction(expandCollection) - -# [80] Object ::= GraphNode -Object = GraphNode - -# [79] ObjectList ::= Object ( ',' Object )* -ObjectList = Object + ZeroOrMore("," + Object) - -# [83] PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )* -PropertyListPathNotEmpty = ( - (VerbPath | VerbSimple) - + ObjectListPath - + ZeroOrMore(";" + Optional((VerbPath | VerbSimple) + ObjectListPath)) -) - -# [82] PropertyListPath ::= Optional(PropertyListPathNotEmpty) -PropertyListPath = Optional(PropertyListPathNotEmpty) - -# [77] PropertyListNotEmpty ::= Verb ObjectList ( ';' ( Verb ObjectList )? )* -PropertyListNotEmpty = Verb + ObjectList + ZeroOrMore(";" + Optional(Verb + ObjectList)) - - -# [76] PropertyList ::= Optional(PropertyListNotEmpty) -PropertyList = Optional(PropertyListNotEmpty) - -# [99] BlankNodePropertyList ::= '[' PropertyListNotEmpty ']' -BlankNodePropertyList = Group(Suppress("[") + PropertyListNotEmpty + Suppress("]")) -BlankNodePropertyList.setParseAction(expandBNodeTriples) - -# [101] BlankNodePropertyListPath ::= '[' PropertyListPathNotEmpty ']' -BlankNodePropertyListPath = Group( - Suppress("[") + PropertyListPathNotEmpty + Suppress("]") -) -BlankNodePropertyListPath.setParseAction(expandBNodeTriples) - -# [98] TriplesNode ::= Collection | BlankNodePropertyList -TriplesNode <<= Collection | BlankNodePropertyList - -# [100] TriplesNodePath ::= CollectionPath | BlankNodePropertyListPath -TriplesNodePath <<= CollectionPath | BlankNodePropertyListPath - -# [75] TriplesSameSubject ::= VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList -TriplesSameSubject = VarOrTerm + PropertyListNotEmpty | TriplesNode + PropertyList -TriplesSameSubject.setParseAction(expandTriples) - -# [52] TriplesTemplate ::= TriplesSameSubject ( '.' TriplesTemplate? )? -# NOTE: pyparsing.py handling of recursive rules is limited by python's recursion -# limit. -# (https://docs.python.org/3/library/sys.html#sys.setrecursionlimit) -# To accommodate arbitrary amounts of triples this rule is rewritten to not be -# recursive: -# [52*] TriplesTemplate ::= TriplesSameSubject ( '.' TriplesSameSubject? )* -TriplesTemplate = ParamList("triples", TriplesSameSubject) + ZeroOrMore( - Suppress(".") + Optional(ParamList("triples", TriplesSameSubject)) -) - -# [51] QuadsNotTriples ::= 'GRAPH' VarOrIri '{' Optional(TriplesTemplate) '}' -QuadsNotTriples = Comp( - "QuadsNotTriples", - Keyword("GRAPH") + Param("term", VarOrIri) + "{" + Optional(TriplesTemplate) + "}", -) - -# [50] Quads ::= Optional(TriplesTemplate) ( QuadsNotTriples '.'? Optional(TriplesTemplate) )* -Quads = Comp( - "Quads", - Optional(TriplesTemplate) - + ZeroOrMore( - ParamList("quadsNotTriples", QuadsNotTriples) - + Optional(Suppress(".")) - + Optional(TriplesTemplate) - ), -) - -# [48] QuadPattern ::= '{' Quads '}' -QuadPattern = "{" + Param("quads", Quads) + "}" - -# [49] QuadData ::= '{' Quads '}' -QuadData = "{" + Param("quads", Quads) + "}" - -# [81] TriplesSameSubjectPath ::= VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath -TriplesSameSubjectPath = ( - VarOrTerm + PropertyListPathNotEmpty | TriplesNodePath + PropertyListPath -) -TriplesSameSubjectPath.setParseAction(expandTriples) - -# [55] TriplesBlock ::= TriplesSameSubjectPath ( '.' Optional(TriplesBlock) )? -TriplesBlock = Forward() -TriplesBlock <<= ParamList("triples", TriplesSameSubjectPath) + Optional( - Suppress(".") + Optional(TriplesBlock) -) - - -# [66] MinusGraphPattern ::= 'MINUS' GroupGraphPattern -MinusGraphPattern = Comp( - "MinusGraphPattern", Keyword("MINUS") + Param("graph", GroupGraphPattern) -) - -# [67] GroupOrUnionGraphPattern ::= GroupGraphPattern ( 'UNION' GroupGraphPattern )* -GroupOrUnionGraphPattern = Comp( - "GroupOrUnionGraphPattern", - ParamList("graph", GroupGraphPattern) - + ZeroOrMore(Keyword("UNION") + ParamList("graph", GroupGraphPattern)), -) - - -Expression = Forward() - -# [72] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')' -ExpressionList = NIL | Group(Suppress("(") + delimitedList(Expression) + Suppress(")")) - -# [122] RegexExpression ::= 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')' -RegexExpression = Comp( - "Builtin_REGEX", - Keyword("REGEX") - + "(" - + Param("text", Expression) - + "," - + Param("pattern", Expression) - + Optional("," + Param("flags", Expression)) - + ")", -) -RegexExpression.setEvalFn(op.Builtin_REGEX) - -# [123] SubstringExpression ::= 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')' -SubstringExpression = Comp( - "Builtin_SUBSTR", - Keyword("SUBSTR") - + "(" - + Param("arg", Expression) - + "," - + Param("start", Expression) - + Optional("," + Param("length", Expression)) - + ")", -).setEvalFn(op.Builtin_SUBSTR) - -# [124] StrReplaceExpression ::= 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')' -StrReplaceExpression = Comp( - "Builtin_REPLACE", - Keyword("REPLACE") - + "(" - + Param("arg", Expression) - + "," - + Param("pattern", Expression) - + "," - + Param("replacement", Expression) - + Optional("," + Param("flags", Expression)) - + ")", -).setEvalFn(op.Builtin_REPLACE) - -# [125] ExistsFunc ::= 'EXISTS' GroupGraphPattern -ExistsFunc = Comp( - "Builtin_EXISTS", Keyword("EXISTS") + Param("graph", GroupGraphPattern) -).setEvalFn(op.Builtin_EXISTS) - -# [126] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern -NotExistsFunc = Comp( - "Builtin_NOTEXISTS", - Keyword("NOT") + Keyword("EXISTS") + Param("graph", GroupGraphPattern), -).setEvalFn(op.Builtin_EXISTS) - - -# [127] Aggregate ::= 'COUNT' '(' 'DISTINCT'? ( '*' | Expression ) ')' -# | 'SUM' '(' Optional('DISTINCT') Expression ')' -# | 'MIN' '(' Optional('DISTINCT') Expression ')' -# | 'MAX' '(' Optional('DISTINCT') Expression ')' -# | 'AVG' '(' Optional('DISTINCT') Expression ')' -# | 'SAMPLE' '(' Optional('DISTINCT') Expression ')' -# | 'GROUP_CONCAT' '(' Optional('DISTINCT') Expression ( ';' 'SEPARATOR' '=' String )? ')' - -_Distinct = Optional(Keyword("DISTINCT")) -_AggregateParams = "(" + Param("distinct", _Distinct) + Param("vars", Expression) + ")" - -Aggregate = ( - Comp( - "Aggregate_Count", - Keyword("COUNT") - + "(" - + Param("distinct", _Distinct) - + Param("vars", "*" | Expression) - + ")", - ) - | Comp("Aggregate_Sum", Keyword("SUM") + _AggregateParams) - | Comp("Aggregate_Min", Keyword("MIN") + _AggregateParams) - | Comp("Aggregate_Max", Keyword("MAX") + _AggregateParams) - | Comp("Aggregate_Avg", Keyword("AVG") + _AggregateParams) - | Comp("Aggregate_Sample", Keyword("SAMPLE") + _AggregateParams) - | Comp( - "Aggregate_GroupConcat", - Keyword("GROUP_CONCAT") - + "(" - + Param("distinct", _Distinct) - + Param("vars", Expression) - + Optional(";" + Keyword("SEPARATOR") + "=" + Param("separator", String)) - + ")", - ) -) - -# [121] BuiltInCall ::= Aggregate -# | 'STR' '(' + Expression + ')' -# | 'LANG' '(' + Expression + ')' -# | 'LANGMATCHES' '(' + Expression + ',' + Expression + ')' -# | 'DATATYPE' '(' + Expression + ')' -# | 'BOUND' '(' Var ')' -# | 'IRI' '(' + Expression + ')' -# | 'URI' '(' + Expression + ')' -# | 'BNODE' ( '(' + Expression + ')' | NIL ) -# | 'RAND' NIL -# | 'ABS' '(' + Expression + ')' -# | 'CEIL' '(' + Expression + ')' -# | 'FLOOR' '(' + Expression + ')' -# | 'ROUND' '(' + Expression + ')' -# | 'CONCAT' ExpressionList -# | SubstringExpression -# | 'STRLEN' '(' + Expression + ')' -# | StrReplaceExpression -# | 'UCASE' '(' + Expression + ')' -# | 'LCASE' '(' + Expression + ')' -# | 'ENCODE_FOR_URI' '(' + Expression + ')' -# | 'CONTAINS' '(' + Expression + ',' + Expression + ')' -# | 'STRSTARTS' '(' + Expression + ',' + Expression + ')' -# | 'STRENDS' '(' + Expression + ',' + Expression + ')' -# | 'STRBEFORE' '(' + Expression + ',' + Expression + ')' -# | 'STRAFTER' '(' + Expression + ',' + Expression + ')' -# | 'YEAR' '(' + Expression + ')' -# | 'MONTH' '(' + Expression + ')' -# | 'DAY' '(' + Expression + ')' -# | 'HOURS' '(' + Expression + ')' -# | 'MINUTES' '(' + Expression + ')' -# | 'SECONDS' '(' + Expression + ')' -# | 'TIMEZONE' '(' + Expression + ')' -# | 'TZ' '(' + Expression + ')' -# | 'NOW' NIL -# | 'UUID' NIL -# | 'STRUUID' NIL -# | 'MD5' '(' + Expression + ')' -# | 'SHA1' '(' + Expression + ')' -# | 'SHA256' '(' + Expression + ')' -# | 'SHA384' '(' + Expression + ')' -# | 'SHA512' '(' + Expression + ')' -# | 'COALESCE' ExpressionList -# | 'IF' '(' Expression ',' Expression ',' Expression ')' -# | 'STRLANG' '(' + Expression + ',' + Expression + ')' -# | 'STRDT' '(' + Expression + ',' + Expression + ')' -# | 'sameTerm' '(' + Expression + ',' + Expression + ')' -# | 'isIRI' '(' + Expression + ')' -# | 'isURI' '(' + Expression + ')' -# | 'isBLANK' '(' + Expression + ')' -# | 'isLITERAL' '(' + Expression + ')' -# | 'isNUMERIC' '(' + Expression + ')' -# | RegexExpression -# | ExistsFunc -# | NotExistsFunc - -BuiltInCall = ( - Aggregate - | Comp( - "Builtin_STR", Keyword("STR") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_STR) - | Comp( - "Builtin_LANG", Keyword("LANG") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_LANG) - | Comp( - "Builtin_LANGMATCHES", - Keyword("LANGMATCHES") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_LANGMATCHES) - | Comp( - "Builtin_DATATYPE", Keyword("DATATYPE") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_DATATYPE) - | Comp("Builtin_BOUND", Keyword("BOUND") + "(" + Param("arg", Var) + ")").setEvalFn( - op.Builtin_BOUND - ) - | Comp( - "Builtin_IRI", Keyword("IRI") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_IRI) - | Comp( - "Builtin_URI", Keyword("URI") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_IRI) - | Comp( - "Builtin_BNODE", Keyword("BNODE") + ("(" + Param("arg", Expression) + ")" | NIL) - ).setEvalFn(op.Builtin_BNODE) - | Comp("Builtin_RAND", Keyword("RAND") + NIL).setEvalFn(op.Builtin_RAND) - | Comp( - "Builtin_ABS", Keyword("ABS") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_ABS) - | Comp( - "Builtin_CEIL", Keyword("CEIL") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_CEIL) - | Comp( - "Builtin_FLOOR", Keyword("FLOOR") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_FLOOR) - | Comp( - "Builtin_ROUND", Keyword("ROUND") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_ROUND) - | Comp( - "Builtin_CONCAT", Keyword("CONCAT") + Param("arg", ExpressionList) - ).setEvalFn(op.Builtin_CONCAT) - | SubstringExpression - | Comp( - "Builtin_STRLEN", Keyword("STRLEN") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_STRLEN) - | StrReplaceExpression - | Comp( - "Builtin_UCASE", Keyword("UCASE") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_UCASE) - | Comp( - "Builtin_LCASE", Keyword("LCASE") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_LCASE) - | Comp( - "Builtin_ENCODE_FOR_URI", - Keyword("ENCODE_FOR_URI") + "(" + Param("arg", Expression) + ")", - ).setEvalFn(op.Builtin_ENCODE_FOR_URI) - | Comp( - "Builtin_CONTAINS", - Keyword("CONTAINS") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_CONTAINS) - | Comp( - "Builtin_STRSTARTS", - Keyword("STRSTARTS") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRSTARTS) - | Comp( - "Builtin_STRENDS", - Keyword("STRENDS") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRENDS) - | Comp( - "Builtin_STRBEFORE", - Keyword("STRBEFORE") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRBEFORE) - | Comp( - "Builtin_STRAFTER", - Keyword("STRAFTER") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRAFTER) - | Comp( - "Builtin_YEAR", Keyword("YEAR") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_YEAR) - | Comp( - "Builtin_MONTH", Keyword("MONTH") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_MONTH) - | Comp( - "Builtin_DAY", Keyword("DAY") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_DAY) - | Comp( - "Builtin_HOURS", Keyword("HOURS") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_HOURS) - | Comp( - "Builtin_MINUTES", Keyword("MINUTES") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_MINUTES) - | Comp( - "Builtin_SECONDS", Keyword("SECONDS") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_SECONDS) - | Comp( - "Builtin_TIMEZONE", Keyword("TIMEZONE") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_TIMEZONE) - | Comp( - "Builtin_TZ", Keyword("TZ") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_TZ) - | Comp("Builtin_NOW", Keyword("NOW") + NIL).setEvalFn(op.Builtin_NOW) - | Comp("Builtin_UUID", Keyword("UUID") + NIL).setEvalFn(op.Builtin_UUID) - | Comp("Builtin_STRUUID", Keyword("STRUUID") + NIL).setEvalFn(op.Builtin_STRUUID) - | Comp( - "Builtin_MD5", Keyword("MD5") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_MD5) - | Comp( - "Builtin_SHA1", Keyword("SHA1") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_SHA1) - | Comp( - "Builtin_SHA256", Keyword("SHA256") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_SHA256) - | Comp( - "Builtin_SHA384", Keyword("SHA384") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_SHA384) - | Comp( - "Builtin_SHA512", Keyword("SHA512") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_SHA512) - | Comp( - "Builtin_COALESCE", Keyword("COALESCE") + Param("arg", ExpressionList) - ).setEvalFn(op.Builtin_COALESCE) - | Comp( - "Builtin_IF", - Keyword("IF") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + "," - + Param("arg3", Expression) - + ")", - ).setEvalFn(op.Builtin_IF) - | Comp( - "Builtin_STRLANG", - Keyword("STRLANG") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRLANG) - | Comp( - "Builtin_STRDT", - Keyword("STRDT") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_STRDT) - | Comp( - "Builtin_sameTerm", - Keyword("sameTerm") - + "(" - + Param("arg1", Expression) - + "," - + Param("arg2", Expression) - + ")", - ).setEvalFn(op.Builtin_sameTerm) - | Comp( - "Builtin_isIRI", Keyword("isIRI") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_isIRI) - | Comp( - "Builtin_isURI", Keyword("isURI") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_isIRI) - | Comp( - "Builtin_isBLANK", Keyword("isBLANK") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_isBLANK) - | Comp( - "Builtin_isLITERAL", Keyword("isLITERAL") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_isLITERAL) - | Comp( - "Builtin_isNUMERIC", Keyword("isNUMERIC") + "(" + Param("arg", Expression) + ")" - ).setEvalFn(op.Builtin_isNUMERIC) - | RegexExpression - | ExistsFunc - | NotExistsFunc -) - -# [71] ArgList ::= NIL | '(' 'DISTINCT'? Expression ( ',' Expression )* ')' -ArgList = ( - NIL - | "(" - + Param("distinct", _Distinct) - + delimitedList(ParamList("expr", Expression)) - + ")" -) - -# [128] iriOrFunction ::= iri Optional(ArgList) -iriOrFunction = ( - Comp("Function", Param("iri", iri) + ArgList).setEvalFn(op.Function) -) | iri - -# [70] FunctionCall ::= iri ArgList -FunctionCall = Comp("Function", Param("iri", iri) + ArgList).setEvalFn(op.Function) - - -# [120] BrackettedExpression ::= '(' Expression ')' -BrackettedExpression = Suppress("(") + Expression + Suppress(")") - -# [119] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var -PrimaryExpression = ( - BrackettedExpression - | BuiltInCall - | iriOrFunction - | RDFLiteral - | NumericLiteral - | BooleanLiteral - | Var -) - -# [118] UnaryExpression ::= '!' PrimaryExpression -# | '+' PrimaryExpression -# | '-' PrimaryExpression -# | PrimaryExpression -UnaryExpression = ( - Comp("UnaryNot", "!" + Param("expr", PrimaryExpression)).setEvalFn(op.UnaryNot) - | Comp("UnaryPlus", "+" + Param("expr", PrimaryExpression)).setEvalFn(op.UnaryPlus) - | Comp("UnaryMinus", "-" + Param("expr", PrimaryExpression)).setEvalFn( - op.UnaryMinus - ) - | PrimaryExpression -) - -# [117] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )* -MultiplicativeExpression = Comp( - "MultiplicativeExpression", - Param("expr", UnaryExpression) - + ZeroOrMore( - ParamList("op", "*") + ParamList("other", UnaryExpression) - | ParamList("op", "/") + ParamList("other", UnaryExpression) - ), -).setEvalFn(op.MultiplicativeExpression) - -# [116] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )* - -# NOTE: The second part of this production is there because: -# "In signed numbers, no white space is allowed between the sign and the number. The AdditiveExpression grammar rule allows for this by covering the two cases of an expression followed by a signed number. These produce an addition or subtraction of the unsigned number as appropriate." - -# Here (I think) this is not necessary since pyparsing doesn't separate -# tokenizing and parsing - - -AdditiveExpression = Comp( - "AdditiveExpression", - Param("expr", MultiplicativeExpression) - + ZeroOrMore( - ParamList("op", "+") + ParamList("other", MultiplicativeExpression) - | ParamList("op", "-") + ParamList("other", MultiplicativeExpression) - ), -).setEvalFn(op.AdditiveExpression) - - -# [115] NumericExpression ::= AdditiveExpression -NumericExpression = AdditiveExpression - -# [114] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )? -RelationalExpression = Comp( - "RelationalExpression", - Param("expr", NumericExpression) - + Optional( - Param("op", "=") + Param("other", NumericExpression) - | Param("op", "!=") + Param("other", NumericExpression) - | Param("op", "<") + Param("other", NumericExpression) - | Param("op", ">") + Param("other", NumericExpression) - | Param("op", "<=") + Param("other", NumericExpression) - | Param("op", ">=") + Param("other", NumericExpression) - | Param("op", Keyword("IN")) + Param("other", ExpressionList) - | Param( - "op", - Combine(Keyword("NOT") + Keyword("IN"), adjacent=False, joinString=" "), - ) - + Param("other", ExpressionList) - ), -).setEvalFn(op.RelationalExpression) - - -# [113] ValueLogical ::= RelationalExpression -ValueLogical = RelationalExpression - -# [112] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )* -ConditionalAndExpression = Comp( - "ConditionalAndExpression", - Param("expr", ValueLogical) + ZeroOrMore("&&" + ParamList("other", ValueLogical)), -).setEvalFn(op.ConditionalAndExpression) - -# [111] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )* -ConditionalOrExpression = Comp( - "ConditionalOrExpression", - Param("expr", ConditionalAndExpression) - + ZeroOrMore("||" + ParamList("other", ConditionalAndExpression)), -).setEvalFn(op.ConditionalOrExpression) - -# [110] Expression ::= ConditionalOrExpression -Expression <<= ConditionalOrExpression - - -# [69] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall -Constraint = BrackettedExpression | BuiltInCall | FunctionCall - -# [68] Filter ::= 'FILTER' Constraint -Filter = Comp("Filter", Keyword("FILTER") + Param("expr", Constraint)) - - -# [16] SourceSelector ::= iri -SourceSelector = iri - -# [14] DefaultGraphClause ::= SourceSelector -DefaultGraphClause = SourceSelector - -# [15] NamedGraphClause ::= 'NAMED' SourceSelector -NamedGraphClause = Keyword("NAMED") + Param("named", SourceSelector) - -# [13] DatasetClause ::= 'FROM' ( DefaultGraphClause | NamedGraphClause ) -DatasetClause = Comp( - "DatasetClause", - Keyword("FROM") + (Param("default", DefaultGraphClause) | NamedGraphClause), -) - -# [20] GroupCondition ::= BuiltInCall | FunctionCall | '(' Expression ( 'AS' Var )? ')' | Var -GroupCondition = ( - BuiltInCall - | FunctionCall - | Comp( - "GroupAs", - "(" - + Param("expr", Expression) - + Optional(Keyword("AS") + Param("var", Var)) - + ")", - ) - | Var -) - -# [19] GroupClause ::= 'GROUP' 'BY' GroupCondition+ -GroupClause = Comp( - "GroupClause", - Keyword("GROUP") - + Keyword("BY") - + OneOrMore(ParamList("condition", GroupCondition)), -) - - -_Silent = Optional(Param("silent", Keyword("SILENT"))) - -# [31] Load ::= 'LOAD' 'SILENT'? iri ( 'INTO' GraphRef )? -Load = Comp( - "Load", - Keyword("LOAD") - + _Silent - + Param("iri", iri) - + Optional(Keyword("INTO") + GraphRef), -) - -# [32] Clear ::= 'CLEAR' 'SILENT'? GraphRefAll -Clear = Comp("Clear", Keyword("CLEAR") + _Silent + GraphRefAll) - -# [33] Drop ::= 'DROP' _Silent GraphRefAll -Drop = Comp("Drop", Keyword("DROP") + _Silent + GraphRefAll) - -# [34] Create ::= 'CREATE' _Silent GraphRef -Create = Comp("Create", Keyword("CREATE") + _Silent + GraphRef) - -# [35] Add ::= 'ADD' _Silent GraphOrDefault 'TO' GraphOrDefault -Add = Comp( - "Add", Keyword("ADD") + _Silent + GraphOrDefault + Keyword("TO") + GraphOrDefault -) - -# [36] Move ::= 'MOVE' _Silent GraphOrDefault 'TO' GraphOrDefault -Move = Comp( - "Move", Keyword("MOVE") + _Silent + GraphOrDefault + Keyword("TO") + GraphOrDefault -) - -# [37] Copy ::= 'COPY' _Silent GraphOrDefault 'TO' GraphOrDefault -Copy = Comp( - "Copy", Keyword("COPY") + _Silent + GraphOrDefault + Keyword("TO") + GraphOrDefault -) - -# [38] InsertData ::= 'INSERT DATA' QuadData -InsertData = Comp("InsertData", Keyword("INSERT") + Keyword("DATA") + QuadData) - -# [39] DeleteData ::= 'DELETE DATA' QuadData -DeleteData = Comp("DeleteData", Keyword("DELETE") + Keyword("DATA") + QuadData) - -# [40] DeleteWhere ::= 'DELETE WHERE' QuadPattern -DeleteWhere = Comp("DeleteWhere", Keyword("DELETE") + Keyword("WHERE") + QuadPattern) - -# [42] DeleteClause ::= 'DELETE' QuadPattern -DeleteClause = Comp("DeleteClause", Keyword("DELETE") + QuadPattern) - -# [43] InsertClause ::= 'INSERT' QuadPattern -InsertClause = Comp("InsertClause", Keyword("INSERT") + QuadPattern) - -# [44] UsingClause ::= 'USING' ( iri | 'NAMED' iri ) -UsingClause = Comp( - "UsingClause", - Keyword("USING") + (Param("default", iri) | Keyword("NAMED") + Param("named", iri)), -) - -# [41] Modify ::= ( 'WITH' iri )? ( DeleteClause Optional(InsertClause) | InsertClause ) ZeroOrMore(UsingClause) 'WHERE' GroupGraphPattern -Modify = Comp( - "Modify", - Optional(Keyword("WITH") + Param("withClause", iri)) - + ( - Param("delete", DeleteClause) + Optional(Param("insert", InsertClause)) - | Param("insert", InsertClause) - ) - + ZeroOrMore(ParamList("using", UsingClause)) - + Keyword("WHERE") - + Param("where", GroupGraphPattern), -) - - -# [30] Update1 ::= Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify -Update1 = ( - Load - | Clear - | Drop - | Add - | Move - | Copy - | Create - | InsertData - | DeleteData - | DeleteWhere - | Modify -) - - -# [63] InlineDataOneVar ::= Var '{' ZeroOrMore(DataBlockValue) '}' -InlineDataOneVar = ( - ParamList("var", Var) + "{" + ZeroOrMore(ParamList("value", DataBlockValue)) + "}" -) - -# [64] InlineDataFull ::= ( NIL | '(' ZeroOrMore(Var) ')' ) '{' ( '(' ZeroOrMore(DataBlockValue) ')' | NIL )* '}' -InlineDataFull = ( - (NIL | "(" + ZeroOrMore(ParamList("var", Var)) + ")") - + "{" - + ZeroOrMore( - ParamList( - "value", - Group(Suppress("(") + ZeroOrMore(DataBlockValue) + Suppress(")") | NIL), - ) - ) - + "}" -) - -# [62] DataBlock ::= InlineDataOneVar | InlineDataFull -DataBlock = InlineDataOneVar | InlineDataFull - - -# [28] ValuesClause ::= ( 'VALUES' DataBlock )? -ValuesClause = Optional( - Param("valuesClause", Comp("ValuesClause", Keyword("VALUES") + DataBlock)) -) - - -# [74] ConstructTriples ::= TriplesSameSubject ( '.' Optional(ConstructTriples) )? -ConstructTriples = Forward() -ConstructTriples <<= ParamList("template", TriplesSameSubject) + Optional( - Suppress(".") + Optional(ConstructTriples) -) - -# [73] ConstructTemplate ::= '{' Optional(ConstructTriples) '}' -ConstructTemplate = Suppress("{") + Optional(ConstructTriples) + Suppress("}") - - -# [57] OptionalGraphPattern ::= 'OPTIONAL' GroupGraphPattern -OptionalGraphPattern = Comp( - "OptionalGraphPattern", Keyword("OPTIONAL") + Param("graph", GroupGraphPattern) -) - -# [58] GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern -GraphGraphPattern = Comp( - "GraphGraphPattern", - Keyword("GRAPH") + Param("term", VarOrIri) + Param("graph", GroupGraphPattern), -) - -# [59] ServiceGraphPattern ::= 'SERVICE' _Silent VarOrIri GroupGraphPattern -ServiceGraphPattern = Comp( - "ServiceGraphPattern", - Keyword("SERVICE") - + _Silent - + Param("term", VarOrIri) - + Param("graph", GroupGraphPattern), -) - -# [60] Bind ::= 'BIND' '(' Expression 'AS' Var ')' -Bind = Comp( - "Bind", - Keyword("BIND") - + "(" - + Param("expr", Expression) - + Keyword("AS") - + Param("var", Var) - + ")", -) - -# [61] InlineData ::= 'VALUES' DataBlock -InlineData = Comp("InlineData", Keyword("VALUES") + DataBlock) - -# [56] GraphPatternNotTriples ::= GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData -GraphPatternNotTriples = ( - GroupOrUnionGraphPattern - | OptionalGraphPattern - | MinusGraphPattern - | GraphGraphPattern - | ServiceGraphPattern - | Filter - | Bind - | InlineData -) - -# [54] GroupGraphPatternSub ::= Optional(TriplesBlock) ( GraphPatternNotTriples '.'? Optional(TriplesBlock) )* -GroupGraphPatternSub = Comp( - "GroupGraphPatternSub", - Optional(ParamList("part", Comp("TriplesBlock", TriplesBlock))) - + ZeroOrMore( - ParamList("part", GraphPatternNotTriples) - + Optional(".") - + Optional(ParamList("part", Comp("TriplesBlock", TriplesBlock))) - ), -) - - -# ---------------- -# [22] HavingCondition ::= Constraint -HavingCondition = Constraint - -# [21] HavingClause ::= 'HAVING' HavingCondition+ -HavingClause = Comp( - "HavingClause", - Keyword("HAVING") + OneOrMore(ParamList("condition", HavingCondition)), -) - -# [24] OrderCondition ::= ( ( 'ASC' | 'DESC' ) BrackettedExpression ) -# | ( Constraint | Var ) -OrderCondition = Comp( - "OrderCondition", - Param("order", Keyword("ASC") | Keyword("DESC")) - + Param("expr", BrackettedExpression) - | Param("expr", Constraint | Var), -) - -# [23] OrderClause ::= 'ORDER' 'BY' OneOrMore(OrderCondition) -OrderClause = Comp( - "OrderClause", - Keyword("ORDER") - + Keyword("BY") - + OneOrMore(ParamList("condition", OrderCondition)), -) - -# [26] LimitClause ::= 'LIMIT' INTEGER -LimitClause = Keyword("LIMIT") + Param("limit", INTEGER) - -# [27] OffsetClause ::= 'OFFSET' INTEGER -OffsetClause = Keyword("OFFSET") + Param("offset", INTEGER) - -# [25] LimitOffsetClauses ::= LimitClause Optional(OffsetClause) | OffsetClause Optional(LimitClause) -LimitOffsetClauses = Comp( - "LimitOffsetClauses", - LimitClause + Optional(OffsetClause) | OffsetClause + Optional(LimitClause), -) - -# [18] SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses? -SolutionModifier = ( - Optional(Param("groupby", GroupClause)) - + Optional(Param("having", HavingClause)) - + Optional(Param("orderby", OrderClause)) - + Optional(Param("limitoffset", LimitOffsetClauses)) -) - - -# [9] SelectClause ::= 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '(' Expression 'AS' Var ')' ) )+ | '*' ) -SelectClause = ( - Keyword("SELECT") - + Optional(Param("modifier", Keyword("DISTINCT") | Keyword("REDUCED"))) - + ( - OneOrMore( - ParamList( - "projection", - Comp( - "vars", - Param("var", Var) - | ( - Literal("(") - + Param("expr", Expression) - + Keyword("AS") - + Param("evar", Var) - + ")" - ), - ), - ) - ) - | "*" - ) -) - -# [17] WhereClause ::= 'WHERE'? GroupGraphPattern -WhereClause = Optional(Keyword("WHERE")) + Param("where", GroupGraphPattern) - -# [8] SubSelect ::= SelectClause WhereClause SolutionModifier ValuesClause -SubSelect = Comp( - "SubSelect", SelectClause + WhereClause + SolutionModifier + ValuesClause -) - -# [53] GroupGraphPattern ::= '{' ( SubSelect | GroupGraphPatternSub ) '}' -GroupGraphPattern <<= Suppress("{") + (SubSelect | GroupGraphPatternSub) + Suppress("}") - -# [7] SelectQuery ::= SelectClause DatasetClause* WhereClause SolutionModifier -SelectQuery = Comp( - "SelectQuery", - SelectClause - + ZeroOrMore(ParamList("datasetClause", DatasetClause)) - + WhereClause - + SolutionModifier - + ValuesClause, -) - -# [10] ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier ) -# NOTE: The CONSTRUCT WHERE alternative has unnecessarily many Comp/Param pairs -# to allow it to through the same algebra translation process -ConstructQuery = Comp( - "ConstructQuery", - Keyword("CONSTRUCT") - + ( - ConstructTemplate - + ZeroOrMore(ParamList("datasetClause", DatasetClause)) - + WhereClause - + SolutionModifier - + ValuesClause - | ZeroOrMore(ParamList("datasetClause", DatasetClause)) - + Keyword("WHERE") - + "{" - + Optional( - Param( - "where", - Comp( - "FakeGroupGraphPatten", - ParamList("part", Comp("TriplesBlock", TriplesTemplate)), - ), - ) - ) - + "}" - + SolutionModifier - + ValuesClause - ), -) - -# [12] AskQuery ::= 'ASK' DatasetClause* WhereClause SolutionModifier -AskQuery = Comp( - "AskQuery", - Keyword("ASK") - + ZeroOrMore(ParamList("datasetClause", DatasetClause)) - + WhereClause - + SolutionModifier - + ValuesClause, -) - -# [11] DescribeQuery ::= 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier -DescribeQuery = Comp( - "DescribeQuery", - Keyword("DESCRIBE") - + (OneOrMore(ParamList("var", VarOrIri)) | "*") - + ZeroOrMore(ParamList("datasetClause", DatasetClause)) - + Optional(WhereClause) - + SolutionModifier - + ValuesClause, -) - -# [29] Update ::= Prologue ( Update1 ( ';' Update )? )? -Update = Forward() -Update <<= ParamList("prologue", Prologue) + Optional( - ParamList("request", Update1) + Optional(";" + Update) -) - - -# [2] Query ::= Prologue -# ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery ) -# ValuesClause -# NOTE: ValuesClause was moved to individual queries -Query = Prologue + (SelectQuery | ConstructQuery | DescribeQuery | AskQuery) - -# [3] UpdateUnit ::= Update -UpdateUnit = Comp("Update", Update) - -# [1] QueryUnit ::= Query -QueryUnit = Query - -QueryUnit.ignore("#" + restOfLine) -UpdateUnit.ignore("#" + restOfLine) - - -expandUnicodeEscapes_re: re.Pattern = re.compile( - r"\\u([0-9a-f]{4}(?:[0-9a-f]{4})?)", flags=re.I -) - - -def expandUnicodeEscapes(q: str) -> str: - r""" - The syntax of the SPARQL Query Language is expressed over code points in Unicode [UNICODE]. The encoding is always UTF-8 [RFC3629]. - Unicode code points may also be expressed using an \ uXXXX (U+0 to U+FFFF) or \ UXXXXXXXX syntax (for U+10000 onwards) where X is a hexadecimal digit [0-9A-F] - """ - - def expand(m: re.Match) -> str: - try: - return chr(int(m.group(1), 16)) - except (ValueError, OverflowError) as e: - raise ValueError("Invalid unicode code point: " + m.group(1)) from e - - return expandUnicodeEscapes_re.sub(expand, q) - - -def parseQuery(q: Union[str, bytes, TextIO, BinaryIO]) -> ParseResults: - if hasattr(q, "read"): - q = q.read() - if isinstance(q, bytes): - q = q.decode("utf-8") - - q = expandUnicodeEscapes(q) - return Query.parseString(q, parseAll=True) - - -def parseUpdate(q: Union[str, bytes, TextIO, BinaryIO]) -> CompValue: - if hasattr(q, "read"): - q = q.read() - - if isinstance(q, bytes): - q = q.decode("utf-8") - - q = expandUnicodeEscapes(q) - return UpdateUnit.parseString(q, parseAll=True)[0] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parserutils.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parserutils.py deleted file mode 100644 index 7b85eb6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/parserutils.py +++ /dev/null @@ -1,316 +0,0 @@ -""" - -NOTE: PyParsing setResultName/__call__ provides a very similar solution to this -I didn't realise at the time of writing and I will remove a -lot of this code at some point - -Utility classes for creating an abstract-syntax tree out with pyparsing actions - -Lets you label and group parts of parser production rules - -For example: - -# [5] BaseDecl ::= 'BASE' IRIREF -BaseDecl = Comp('Base', Keyword('BASE') + Param('iri',IRIREF)) - -After parsing, this gives you back an CompValue object, -which is a dict/object with the parameters specified. -So you can access the parameters are attributes or as keys: - -baseDecl.iri - -Comp lets you set an evalFn that is bound to the eval method of -the resulting CompValue - - -""" - -from __future__ import annotations - -from collections import OrderedDict -from types import MethodType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - List, - Mapping, - Optional, - Tuple, - TypeVar, - Union, -) - -from pyparsing import ParserElement, ParseResults, TokenConverter, originalTextFor - -from rdflib.term import BNode, Identifier, Variable - -if TYPE_CHECKING: - from rdflib.plugins.sparql.sparql import FrozenBindings - - -# This is an alternative - -# Comp('Sum')( Param('x')(Number) + '+' + Param('y')(Number) ) - - -def value( - ctx: FrozenBindings, - val: Any, - variables: bool = False, - errors: bool = False, -) -> Any: - """ - utility function for evaluating something... - - Variables will be looked up in the context - Normally, non-bound vars is an error, - set variables=True to return unbound vars - - Normally, an error raises the error, - set errors=True to return error - - """ - - if isinstance(val, Expr): - return val.eval(ctx) # recurse? - elif isinstance(val, CompValue): - raise Exception("What do I do with this CompValue? %s" % val) - - elif isinstance(val, list): - return [value(ctx, x, variables, errors) for x in val] - - elif isinstance(val, (BNode, Variable)): - r = ctx.get(val) - if isinstance(r, SPARQLError) and not errors: - raise r - if r is not None: - return r - - # not bound - if variables: - return val - else: - raise NotBoundError - - elif isinstance(val, ParseResults) and len(val) == 1: - return value(ctx, val[0], variables, errors) - else: - return val - - -class ParamValue: - """ - The result of parsing a Param - This just keeps the name/value - All cleverness is in the CompValue - """ - - def __init__( - self, name: str, tokenList: Union[List[Any], ParseResults], isList: bool - ): - self.isList = isList - self.name = name - if isinstance(tokenList, (list, ParseResults)) and len(tokenList) == 1: - tokenList = tokenList[0] - - self.tokenList = tokenList - - def __str__(self) -> str: - return "Param(%s, %s)" % (self.name, self.tokenList) - - -class Param(TokenConverter): - """ - A pyparsing token for labelling a part of the parse-tree - if isList is true repeat occurrences of ParamList have - their values merged in a list - """ - - def __init__(self, name: str, expr, isList: bool = False): - self.isList = isList - TokenConverter.__init__(self, expr) - self.setName(name) - self.addParseAction(self.postParse2) - - def postParse2(self, tokenList: Union[List[Any], ParseResults]) -> ParamValue: - return ParamValue(self.name, tokenList, self.isList) - - -class ParamList(Param): - """ - A shortcut for a Param with isList=True - """ - - def __init__(self, name: str, expr): - Param.__init__(self, name, expr, True) - - -_ValT = TypeVar("_ValT") - - -class CompValue(OrderedDict): - """ - The result of parsing a Comp - Any included Params are available as Dict keys - or as attributes - - """ - - def __init__(self, name: str, **values): - OrderedDict.__init__(self) - self.name = name - self.update(values) - - def clone(self) -> CompValue: - return CompValue(self.name, **self) - - def __str__(self) -> str: - return self.name + "_" + OrderedDict.__str__(self) - - def __repr__(self) -> str: - return self.name + "_" + dict.__repr__(self) - - def _value( - self, val: _ValT, variables: bool = False, errors: bool = False - ) -> Union[_ValT, Any]: - if self.ctx is not None: - return value(self.ctx, val, variables) - else: - return val - - def __getitem__(self, a): - return self._value(OrderedDict.__getitem__(self, a)) - - # type error: Signature of "get" incompatible with supertype "dict" - # type error: Signature of "get" incompatible with supertype "Mapping" [override] - def get(self, a, variables: bool = False, errors: bool = False): # type: ignore[override] - return self._value(OrderedDict.get(self, a, a), variables, errors) - - def __getattr__(self, a: str) -> Any: - # Hack hack: OrderedDict relies on this - if a in ("_OrderedDict__root", "_OrderedDict__end"): - raise AttributeError() - try: - return self[a] - except KeyError: - # raise AttributeError('no such attribute '+a) - return None - - if TYPE_CHECKING: - # this is here because properties are dynamically set on CompValue - def __setattr__(self, __name: str, __value: Any) -> None: ... - - -class Expr(CompValue): - """ - A CompValue that is evaluatable - """ - - def __init__( - self, - name: str, - evalfn: Optional[Callable[[Any, Any], Any]] = None, - **values, - ): - super(Expr, self).__init__(name, **values) - - self._evalfn = None - if evalfn: - self._evalfn = MethodType(evalfn, self) - - def eval(self, ctx: Any = {}) -> Union[SPARQLError, Any]: - try: - self.ctx: Optional[Union[Mapping, FrozenBindings]] = ctx - # type error: "None" not callable - return self._evalfn(ctx) # type: ignore[misc] - except SPARQLError as e: - return e - finally: - self.ctx = None - - -class Comp(TokenConverter): - """ - A pyparsing token for grouping together things with a label - Any sub-tokens that are not Params will be ignored. - - Returns CompValue / Expr objects - depending on whether evalFn is set. - """ - - def __init__(self, name: str, expr: ParserElement): - self.expr = expr - TokenConverter.__init__(self, expr) - self.setName(name) - self.evalfn: Optional[Callable[[Any, Any], Any]] = None - - def postParse( - self, instring: str, loc: int, tokenList: ParseResults - ) -> Union[Expr, CompValue]: - res: Union[Expr, CompValue] - if self.evalfn: - res = Expr(self.name) - res._evalfn = MethodType(self.evalfn, res) - else: - res = CompValue(self.name) - if self.name == "ServiceGraphPattern": - # Then this must be a service graph pattern and have - # already matched. - # lets assume there is one, for now, then test for two later. - sgp = originalTextFor(self.expr) - service_string = sgp.searchString(instring)[0][0] - res["service_string"] = service_string - - for t in tokenList: - if isinstance(t, ParamValue): - if t.isList: - if t.name not in res: - res[t.name] = [] - res[t.name].append(t.tokenList) - else: - res[t.name] = t.tokenList - # res.append(t.tokenList) - # if isinstance(t,CompValue): - # res.update(t) - return res - - def setEvalFn(self, evalfn: Callable[[Any, Any], Any]) -> Comp: - self.evalfn = evalfn - return self - - -def prettify_parsetree(t: ParseResults, indent: str = "", depth: int = 0) -> str: - out: List[str] = [] - for e in t.asList(): - out.append(_prettify_sub_parsetree(e, indent, depth + 1)) - for k, v in sorted(t.items()): - out.append("%s%s- %s:\n" % (indent, " " * depth, k)) - out.append(_prettify_sub_parsetree(v, indent, depth + 1)) - return "".join(out) - - -def _prettify_sub_parsetree( - t: Union[Identifier, CompValue, set, list, dict, Tuple, bool, None], - indent: str = "", - depth: int = 0, -) -> str: - out: List[str] = [] - if isinstance(t, CompValue): - out.append("%s%s> %s:\n" % (indent, " " * depth, t.name)) - for k, v in t.items(): - out.append("%s%s- %s:\n" % (indent, " " * (depth + 1), k)) - out.append(_prettify_sub_parsetree(v, indent, depth + 2)) - elif isinstance(t, dict): - for k, v in t.items(): - out.append("%s%s- %s:\n" % (indent, " " * (depth + 1), k)) - out.append(_prettify_sub_parsetree(v, indent, depth + 2)) - elif isinstance(t, list): - for e in t: - out.append(_prettify_sub_parsetree(e, indent, depth + 1)) - else: - out.append("%s%s- %r\n" % (indent, " " * depth, t)) - return "".join(out) - - -# hurrah for circular imports -from rdflib.plugins.sparql.sparql import NotBoundError, SPARQLError # noqa: E402 diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/processor.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/processor.py deleted file mode 100644 index de97d80..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/processor.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -Code for tying SPARQL Engine into RDFLib - -These should be automatically registered with RDFLib - -""" - -from __future__ import annotations - -from typing import Any, Mapping, Optional, Union - -from rdflib.graph import Graph -from rdflib.plugins.sparql.algebra import translateQuery, translateUpdate -from rdflib.plugins.sparql.evaluate import evalQuery -from rdflib.plugins.sparql.parser import parseQuery, parseUpdate -from rdflib.plugins.sparql.sparql import Query, Update -from rdflib.plugins.sparql.update import evalUpdate -from rdflib.query import Processor, Result, UpdateProcessor -from rdflib.term import Identifier - - -def prepareQuery( - queryString: str, - initNs: Optional[Mapping[str, Any]] = None, - base: Optional[str] = None, -) -> Query: - """ - Parse and translate a SPARQL Query - """ - if initNs is None: - initNs = {} - ret = translateQuery(parseQuery(queryString), base, initNs) - ret._original_args = (queryString, initNs, base) - return ret - - -def prepareUpdate( - updateString: str, - initNs: Optional[Mapping[str, Any]] = None, - base: Optional[str] = None, -) -> Update: - """ - Parse and translate a SPARQL Update - """ - if initNs is None: - initNs = {} - ret = translateUpdate(parseUpdate(updateString), base, initNs) - ret._original_args = (updateString, initNs, base) - return ret - - -def processUpdate( - graph: Graph, - updateString: str, - initBindings: Optional[Mapping[str, Identifier]] = None, - initNs: Optional[Mapping[str, Any]] = None, - base: Optional[str] = None, -) -> None: - """ - Process a SPARQL Update Request - returns Nothing on success or raises Exceptions on error - """ - evalUpdate( - graph, translateUpdate(parseUpdate(updateString), base, initNs), initBindings - ) - - -class SPARQLResult(Result): - def __init__(self, res: Mapping[str, Any]): - Result.__init__(self, res["type_"]) - self.vars = res.get("vars_") - # type error: Incompatible types in assignment (expression has type "Optional[Any]", variable has type "MutableSequence[Mapping[Variable, Identifier]]") - self.bindings = res.get("bindings") # type: ignore[assignment] - self.askAnswer = res.get("askAnswer") - self.graph = res.get("graph") - - -class SPARQLUpdateProcessor(UpdateProcessor): - def __init__(self, graph): - self.graph = graph - - def update( - self, - strOrQuery: Union[str, Update], - initBindings: Optional[Mapping[str, Identifier]] = None, - initNs: Optional[Mapping[str, Any]] = None, - ) -> None: - """ - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - """ - - if isinstance(strOrQuery, str): - strOrQuery = translateUpdate(parseUpdate(strOrQuery), initNs=initNs) - - return evalUpdate(self.graph, strOrQuery, initBindings) - - -class SPARQLProcessor(Processor): - def __init__(self, graph): - self.graph = graph - - # NOTE on type error: this is because the super type constructor does not - # accept base argument and thie position of the DEBUG argument is - # different. - # type error: Signature of "query" incompatible with supertype "Processor" - def query( # type: ignore[override] - self, - strOrQuery: Union[str, Query], - initBindings: Optional[Mapping[str, Identifier]] = None, - initNs: Optional[Mapping[str, Any]] = None, - base: Optional[str] = None, - DEBUG: bool = False, - ) -> Mapping[str, Any]: - """ - Evaluate a query with the given initial bindings, and initial - namespaces. The given base is used to resolve relative URIs in - the query and will be overridden by any BASE given in the query. - - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - """ - - if isinstance(strOrQuery, str): - strOrQuery = translateQuery(parseQuery(strOrQuery), base, initNs) - - return evalQuery(self.graph, strOrQuery, initBindings, base) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/__init__.py deleted file mode 100644 index 55796d1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Parsers and serializers for SPARQL Result formats -""" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/csvresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/csvresults.py deleted file mode 100644 index 32b3e42..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/csvresults.py +++ /dev/null @@ -1,104 +0,0 @@ -""" - -This module implements a parser and serializer for the CSV SPARQL result -formats - -http://www.w3.org/TR/sparql11-results-csv-tsv/ - -""" - -from __future__ import annotations - -import codecs -import csv -from io import BufferedIOBase, TextIOBase -from typing import IO, Dict, List, Optional, Union, cast - -from rdflib.plugins.sparql.processor import SPARQLResult -from rdflib.query import Result, ResultParser, ResultSerializer -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - - -class CSVResultParser(ResultParser): - def __init__(self): - self.delim = "," - - # type error: Signature of "parse" incompatible with supertype "ResultParser" - def parse(self, source: IO, content_type: Optional[str] = None) -> Result: # type: ignore[override] - r = Result("SELECT") - - # type error: Incompatible types in assignment (expression has type "StreamReader", variable has type "IO[Any]") - if isinstance(source.read(0), bytes): - # if reading from source returns bytes do utf-8 decoding - # type error: Incompatible types in assignment (expression has type "StreamReader", variable has type "IO[Any]") - source = codecs.getreader("utf-8")(source) # type: ignore[assignment] - - reader = csv.reader(source, delimiter=self.delim) - r.vars = [Variable(x) for x in next(reader)] - r.bindings = [] - - for row in reader: - r.bindings.append(self.parseRow(row, r.vars)) - - return r - - def parseRow( - self, row: List[str], v: List[Variable] - ) -> Dict[Variable, Union[BNode, URIRef, Literal]]: - return dict( - (var, val) - for var, val in zip(v, [self.convertTerm(t) for t in row]) - if val is not None - ) - - def convertTerm(self, t: str) -> Optional[Union[BNode, URIRef, Literal]]: - if t == "": - return None - if t.startswith("_:"): - return BNode(t) # or generate new IDs? - if t.startswith("http://") or t.startswith("https://"): # TODO: more? - return URIRef(t) - return Literal(t) - - -class CSVResultSerializer(ResultSerializer): - def __init__(self, result: SPARQLResult): - ResultSerializer.__init__(self, result) - - self.delim = "," - if result.type != "SELECT": - raise Exception("CSVSerializer can only serialize select query results") - - def serialize(self, stream: IO, encoding: str = "utf-8", **kwargs) -> None: - # the serialiser writes bytes in the given encoding - # in py3 csv.writer is unicode aware and writes STRINGS, - # so we encode afterward - - import codecs - - # TODO: Find a better solution for all this casting - writable_stream = cast(Union[TextIOBase, BufferedIOBase], stream) - if isinstance(writable_stream, TextIOBase): - string_stream: TextIOBase = writable_stream - else: - byte_stream = cast(BufferedIOBase, writable_stream) - string_stream = cast(TextIOBase, codecs.getwriter(encoding)(byte_stream)) - - out = csv.writer(string_stream, delimiter=self.delim) - - vs = [self.serializeTerm(v, encoding) for v in self.result.vars] # type: ignore[union-attr] - out.writerow(vs) - for row in self.result.bindings: - out.writerow( - [self.serializeTerm(row.get(v), encoding) for v in self.result.vars] # type: ignore[union-attr] - ) - - def serializeTerm( - self, term: Optional[Identifier], encoding: str - ) -> Union[str, Identifier]: - if term is None: - return "" - elif isinstance(term, BNode): - return f"_:{term}" - else: - return term diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/graph.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/graph.py deleted file mode 100644 index bfd03c0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/graph.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -from typing import IO, Optional - -from rdflib.graph import Graph -from rdflib.query import Result, ResultParser - - -class GraphResultParser(ResultParser): - # type error: Signature of "parse" incompatible with supertype "ResultParser" - def parse(self, source: IO, content_type: Optional[str]) -> Result: # type: ignore[override] - res = Result("CONSTRUCT") # hmm - or describe?type_) - res.graph = Graph() - res.graph.parse(source, format=content_type) - - return res diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/jsonresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/jsonresults.py deleted file mode 100644 index cfc2dc1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/jsonresults.py +++ /dev/null @@ -1,164 +0,0 @@ -"""A Serializer for SPARQL results in JSON: - -http://www.w3.org/TR/rdf-sparql-json-res/ - -Bits and pieces borrowed from: -http://projects.bigasterisk.com/sparqlhttp/ - -Authors: Drew Perttula, Gunnar Aastrand Grimnes - -""" - -from __future__ import annotations - -import json -from typing import IO, Any, Dict, Mapping, MutableSequence, Optional - -from rdflib.query import Result, ResultException, ResultParser, ResultSerializer -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - -try: - import orjson - - _HAS_ORJSON = True -except ImportError: - orjson = None # type: ignore[assignment, unused-ignore] - _HAS_ORJSON = False - - -class JSONResultParser(ResultParser): - # type error: Signature of "parse" incompatible with supertype "ResultParser" - def parse(self, source: IO, content_type: Optional[str] = None) -> Result: # type: ignore[override] - inp = source.read() - if _HAS_ORJSON: - try: - loaded = orjson.loads(inp) - except Exception as e: - raise ResultException(f"Failed to parse result: {e}") - else: - if isinstance(inp, bytes): - inp = inp.decode("utf-8") - loaded = json.loads(inp) - return JSONResult(loaded) - - -class JSONResultSerializer(ResultSerializer): - def __init__(self, result: Result): - ResultSerializer.__init__(self, result) - - # type error: Signature of "serialize" incompatible with supertype "ResultSerializer" - def serialize(self, stream: IO, encoding: str = None) -> None: # type: ignore[override] - res: Dict[str, Any] = {} - if self.result.type == "ASK": - res["head"] = {} - res["boolean"] = self.result.askAnswer - else: - # select - res["results"] = {} - res["head"] = {} - res["head"]["vars"] = self.result.vars - res["results"]["bindings"] = [ - self._bindingToJSON(x) for x in self.result.bindings - ] - if _HAS_ORJSON: - try: - r_bytes = orjson.dumps(res, option=orjson.OPT_NON_STR_KEYS) - except Exception as e: - raise ResultException(f"Failed to serialize result: {e}") - if encoding is not None: - # Note, orjson will always write utf-8 even if - # encoding is specified as something else. - try: - stream.write(r_bytes) - except (TypeError, ValueError): - stream.write(r_bytes.decode("utf-8")) - else: - stream.write(r_bytes.decode("utf-8")) - else: - r_str = json.dumps(res, allow_nan=False, ensure_ascii=False) - if encoding is not None: - try: - stream.write(r_str.encode(encoding)) - except (TypeError, ValueError): - stream.write(r_str) - else: - stream.write(r_str) - - def _bindingToJSON(self, b: Mapping[Variable, Identifier]) -> Dict[Variable, Any]: - res = {} - for var in b: - j = termToJSON(self, b[var]) - if j is not None: - res[var] = termToJSON(self, b[var]) - return res - - -class JSONResult(Result): - def __init__(self, json: Dict[str, Any]): - self.json = json - if "boolean" in json: - type_ = "ASK" - elif "results" in json: - type_ = "SELECT" - else: - raise ResultException("No boolean or results in json!") - - Result.__init__(self, type_) - - if type_ == "ASK": - self.askAnswer = bool(json["boolean"]) - else: - self.bindings = self._get_bindings() - self.vars = [Variable(x) for x in json["head"]["vars"]] - - def _get_bindings(self) -> MutableSequence[Mapping[Variable, Identifier]]: - ret: MutableSequence[Mapping[Variable, Identifier]] = [] - for row in self.json["results"]["bindings"]: - outRow: Dict[Variable, Identifier] = {} - for k, v in row.items(): - outRow[Variable(k)] = parseJsonTerm(v) - ret.append(outRow) - return ret - - -def parseJsonTerm(d: Dict[str, str]) -> Identifier: - """rdflib object (Literal, URIRef, BNode) for the given json-format dict. - - input is like: - { 'type': 'uri', 'value': 'http://famegame.com/2006/01/username' } - { 'type': 'literal', 'value': 'drewp' } - """ - - t = d["type"] - if t == "uri": - return URIRef(d["value"]) - elif t == "literal": - return Literal(d["value"], datatype=d.get("datatype"), lang=d.get("xml:lang")) - elif t == "typed-literal": - return Literal(d["value"], datatype=URIRef(d["datatype"])) - elif t == "bnode": - return BNode(d["value"]) - else: - raise NotImplementedError("json term type %r" % t) - - -def termToJSON( - self: JSONResultSerializer, term: Optional[Identifier] -) -> Optional[Dict[str, str]]: - if isinstance(term, URIRef): - return {"type": "uri", "value": str(term)} - elif isinstance(term, Literal): - r = {"type": "literal", "value": str(term)} - - if term.datatype is not None: - r["datatype"] = str(term.datatype) - if term.language is not None: - r["xml:lang"] = term.language - return r - - elif isinstance(term, BNode): - return {"type": "bnode", "value": str(term)} - elif term is None: - return None - else: - raise ResultException("Unknown term type: %s (%s)" % (term, type(term))) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/rdfresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/rdfresults.py deleted file mode 100644 index c59a40c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/rdfresults.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - -from typing import IO, Any, MutableMapping, Optional, Union - -from rdflib.graph import Graph -from rdflib.namespace import RDF, Namespace -from rdflib.query import Result, ResultParser -from rdflib.term import Node, Variable - -RS = Namespace("http://www.w3.org/2001/sw/DataAccess/tests/result-set#") - - -class RDFResultParser(ResultParser): - def parse(self, source: Union[IO, Graph], **kwargs: Any) -> Result: - return RDFResult(source, **kwargs) - - -class RDFResult(Result): - def __init__(self, source: Union[IO, Graph], **kwargs: Any): - if not isinstance(source, Graph): - graph = Graph() - graph.parse(source, **kwargs) - else: - graph = source - - rs = graph.value(predicate=RDF.type, object=RS.ResultSet) - # there better be only one :) - - if rs is None: - type_ = "CONSTRUCT" - - # use a new graph - g = Graph() - g += graph - - else: - askAnswer = graph.value(rs, RS.boolean) - - if askAnswer is not None: - type_ = "ASK" - else: - type_ = "SELECT" - - Result.__init__(self, type_) - - if type_ == "SELECT": - # type error: Argument 1 to "Variable" has incompatible type "Node"; expected "str" - self.vars = [Variable(v) for v in graph.objects(rs, RS.resultVariable)] # type: ignore[arg-type] - - self.bindings = [] - - for s in graph.objects(rs, RS.solution): - sol: MutableMapping[Variable, Optional[Node]] = {} - for b in graph.objects(s, RS.binding): - # type error: Argument 1 to "Variable" has incompatible type "Optional[Node]"; expected "str" - sol[Variable(graph.value(b, RS.variable))] = graph.value( # type: ignore[arg-type] - b, RS.value - ) - # error: Argument 1 to "append" of "list" has incompatible type "MutableMapping[Variable, Optional[Node]]"; expected "Mapping[Variable, Identifier]" - self.bindings.append(sol) # type: ignore[arg-type] - elif type_ == "ASK": - # type error: Item "Node" of "Optional[Node]" has no attribute "value" - # type error: Item "None" of "Optional[Node]" has no attribute "value" - self.askAnswer = askAnswer.value # type: ignore[union-attr] - # type error: Item "Node" of "Optional[Node]" has no attribute "value" - # type error: Item "None" of "Optional[Node]" has no attribute "value" - if askAnswer.value is None: # type: ignore[union-attr] - raise Exception("Malformed boolean in ask answer!") - elif type_ == "CONSTRUCT": - self.graph = g diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/tsvresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/tsvresults.py deleted file mode 100644 index 54b516d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/tsvresults.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -This implements the Tab Separated SPARQL Result Format - -It is implemented with pyparsing, reusing the elements from the SPARQL Parser -""" - -from __future__ import annotations - -import codecs -import typing -from typing import IO, Union - -from pyparsing import ( - FollowedBy, - LineEnd, - Literal, - Optional, - ParserElement, - Suppress, - ZeroOrMore, -) - -from rdflib.plugins.sparql.parser import ( - BLANK_NODE_LABEL, - IRIREF, - LANGTAG, - STRING_LITERAL1, - STRING_LITERAL2, - BooleanLiteral, - NumericLiteral, - Var, -) -from rdflib.plugins.sparql.parserutils import Comp, CompValue, Param -from rdflib.query import Result, ResultParser -from rdflib.term import BNode, URIRef -from rdflib.term import Literal as RDFLiteral - -ParserElement.setDefaultWhitespaceChars(" \n") - - -String = STRING_LITERAL1 | STRING_LITERAL2 - -RDFLITERAL = Comp( - "literal", - Param("string", String) - + Optional( - Param("lang", LANGTAG.leaveWhitespace()) - | Literal("^^").leaveWhitespace() + Param("datatype", IRIREF).leaveWhitespace() - ), -) - -NONE_VALUE = object() - -EMPTY = FollowedBy(LineEnd()) | FollowedBy("\t") -EMPTY.setParseAction(lambda x: NONE_VALUE) - -TERM = RDFLITERAL | IRIREF | BLANK_NODE_LABEL | NumericLiteral | BooleanLiteral - -ROW = (EMPTY | TERM) + ZeroOrMore(Suppress("\t") + (EMPTY | TERM)) -ROW.parseWithTabs() - -HEADER = Var + ZeroOrMore(Suppress("\t") + Var) -HEADER.parseWithTabs() - - -class TSVResultParser(ResultParser): - # type error: Signature of "parse" incompatible with supertype "ResultParser" [override] - def parse(self, source: IO, content_type: typing.Optional[str] = None) -> Result: # type: ignore[override] - if isinstance(source.read(0), bytes): - # if reading from source returns bytes do utf-8 decoding - # type error: Incompatible types in assignment (expression has type "StreamReader", variable has type "IO[Any]") - source = codecs.getreader("utf-8")(source) # type: ignore[assignment] - - r = Result("SELECT") - - header = source.readline() - - r.vars = list(HEADER.parseString(header.strip(), parseAll=True)) - r.bindings = [] - while True: - line = source.readline() - if not line: - break - line = line.strip("\n") - if line == "": - continue - - row = ROW.parseString(line, parseAll=True) - # type error: Generator has incompatible item type "object"; expected "Identifier" - r.bindings.append(dict(zip(r.vars, (self.convertTerm(x) for x in row)))) # type: ignore[misc] - - return r - - def convertTerm( - self, t: Union[object, RDFLiteral, BNode, CompValue, URIRef] - ) -> typing.Optional[Union[object, BNode, URIRef, RDFLiteral]]: - if t is NONE_VALUE: - return None - if isinstance(t, CompValue): - if t.name == "literal": - return RDFLiteral(t.string, lang=t.lang, datatype=t.datatype) - else: - raise Exception("I dont know how to handle this: %s" % (t,)) - else: - return t diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/txtresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/txtresults.py deleted file mode 100644 index 86d8933..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/txtresults.py +++ /dev/null @@ -1,86 +0,0 @@ -from __future__ import annotations - -from io import StringIO -from typing import IO, List, Optional, Union - -from rdflib.namespace import NamespaceManager -from rdflib.query import ResultSerializer -from rdflib.term import BNode, Literal, URIRef, Variable - - -def _termString( - t: Optional[Union[URIRef, Literal, BNode]], - namespace_manager: Optional[NamespaceManager], -) -> str: - if t is None: - return "-" - if namespace_manager: - if isinstance(t, URIRef): - return namespace_manager.normalizeUri(t) - elif isinstance(t, BNode): - return t.n3() - elif isinstance(t, Literal): - return t._literal_n3(qname_callback=namespace_manager.normalizeUri) - else: - return t.n3() - - -class TXTResultSerializer(ResultSerializer): - """ - A write-only QueryResult serializer for text/ascii tables - """ - - def serialize( - self, - stream: IO, - encoding: str = "utf-8", - *, - namespace_manager: Optional[NamespaceManager] = None, - **kwargs, - ) -> None: - """ - return a text table of query results - """ - - def c(s, w): - """ - center the string s in w wide string - """ - w -= len(s) - h1 = h2 = w // 2 - if w % 2: - h2 += 1 - return " " * h1 + s + " " * h2 - - if self.result.type != "SELECT": - raise Exception("Can only pretty print SELECT results!") - string_stream = StringIO() - if not self.result: - string_stream.write("(no results)\n") - else: - keys: List[Variable] = self.result.vars # type: ignore[assignment] - maxlen = [0] * len(keys) - b = [ - # type error: Value of type "Union[Tuple[Node, Node, Node], bool, ResultRow]" is not indexable - # type error: Argument 1 to "_termString" has incompatible type "Union[Node, Any]"; expected "Union[URIRef, Literal, BNode, None]" [arg-type] - # type error: No overload variant of "__getitem__" of "tuple" matches argument type "Variable" - # NOTE on type error: The problem here is that r can be more types than _termString expects because result can be a result of multiple types. - [_termString(r[k], namespace_manager) for k in keys] # type: ignore[index, arg-type, call-overload] - for r in self.result - ] - for r in b: - for i in range(len(keys)): - maxlen[i] = max(maxlen[i], len(r[i])) - string_stream.write( - "|".join([c(k, maxlen[i]) for i, k in enumerate(keys)]) + "\n" - ) - string_stream.write("-" * (len(maxlen) + sum(maxlen)) + "\n") - for r in sorted(b): - string_stream.write( - "|".join([t + " " * (i - len(t)) for i, t in zip(maxlen, r)]) + "\n" - ) - text_val = string_stream.getvalue() - try: - stream.write(text_val.encode(encoding)) - except (TypeError, ValueError): - stream.write(text_val) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/xmlresults.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/xmlresults.py deleted file mode 100644 index 3cc6b2c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/results/xmlresults.py +++ /dev/null @@ -1,301 +0,0 @@ -"""A Parser for SPARQL results in XML: - -http://www.w3.org/TR/rdf-sparql-XMLres/ - -Bits and pieces borrowed from: -http://projects.bigasterisk.com/sparqlhttp/ - -Authors: Drew Perttula, Gunnar Aastrand Grimnes -""" - -from __future__ import annotations - -import logging -import xml.etree.ElementTree as xml_etree # noqa: N813 -from io import BytesIO -from typing import ( - IO, - TYPE_CHECKING, - Any, - BinaryIO, - Dict, - Optional, - Sequence, - TextIO, - Tuple, - Union, - cast, -) -from xml.dom import XML_NAMESPACE -from xml.sax.saxutils import XMLGenerator -from xml.sax.xmlreader import AttributesNSImpl - -from rdflib.query import Result, ResultException, ResultParser, ResultSerializer -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable - -try: - # https://adamj.eu/tech/2021/12/29/python-type-hints-optional-imports/ - import lxml.etree as lxml_etree - - FOUND_LXML = True -except ImportError: - FOUND_LXML = False - -SPARQL_XML_NAMESPACE = "http://www.w3.org/2005/sparql-results#" -RESULTS_NS_ET = "{%s}" % SPARQL_XML_NAMESPACE - -log = logging.getLogger(__name__) - - -class XMLResultParser(ResultParser): - # TODO FIXME: content_type should be a keyword only arg. - def parse(self, source: IO, content_type: Optional[str] = None) -> Result: # type: ignore[override] - return XMLResult(source) - - -class XMLResult(Result): - def __init__(self, source: IO, content_type: Optional[str] = None): - parser_encoding: Optional[str] = None - if hasattr(source, "encoding"): - if TYPE_CHECKING: - assert isinstance(source, TextIO) - parser_encoding = "utf-8" - source_str = source.read() - source = BytesIO(source_str.encode(parser_encoding)) - else: - if TYPE_CHECKING: - assert isinstance(source, BinaryIO) - - if FOUND_LXML: - lxml_parser = lxml_etree.XMLParser(huge_tree=True, encoding=parser_encoding) - tree = cast( - xml_etree.ElementTree, - lxml_etree.parse(source, parser=lxml_parser), - ) - else: - xml_parser = xml_etree.XMLParser(encoding=parser_encoding) - tree = xml_etree.parse(source, parser=xml_parser) - - boolean = tree.find(RESULTS_NS_ET + "boolean") - results = tree.find(RESULTS_NS_ET + "results") - - if boolean is not None: - type_ = "ASK" - elif results is not None: - type_ = "SELECT" - else: - raise ResultException("No RDF result-bindings or boolean answer found!") - - Result.__init__(self, type_) - - if type_ == "SELECT": - self.bindings = [] - for result in results: # type: ignore[union-attr] - if result.tag != f"{RESULTS_NS_ET}result": - # This is here because with lxml this also gets comments, - # not just elements. Also this should not operate on non - # "result" elements. - continue - r = {} - for binding in result: - if binding.tag != f"{RESULTS_NS_ET}binding": - # This is here because with lxml this also gets - # comments, not just elements. Also this should not - # operate on non "binding" elements. - continue - # type error: error: Argument 1 to "Variable" has incompatible type "Union[str, None, Any]"; expected "str" - # NOTE on type error: Element.get() can return None, and - # this will invariably fail if passed into Variable - # constructor as value - r[Variable(binding.get("name"))] = parseTerm(binding[0]) # type: ignore[arg-type] # FIXME - self.bindings.append(r) - - self.vars = [ - # type error: Argument 1 to "Variable" has incompatible type "Optional[str]"; expected "str" - # NOTE on type error: Element.get() can return None, and this - # will invariably fail if passed into Variable constructor as - # value - Variable(x.get("name")) # type: ignore[arg-type] # FIXME - for x in tree.findall( - "./%shead/%svariable" % (RESULTS_NS_ET, RESULTS_NS_ET) - ) - ] - - else: - self.askAnswer = boolean.text.lower().strip() == "true" # type: ignore[union-attr] - - -def parseTerm(element: xml_etree.Element) -> Union[URIRef, Literal, BNode]: - """rdflib object (Literal, URIRef, BNode) for the given - elementtree element""" - tag, text = element.tag, element.text - if tag == RESULTS_NS_ET + "literal": - if text is None: - text = "" - datatype = None - lang = None - if element.get("datatype", None): - # type error: Argument 1 to "URIRef" has incompatible type "Optional[str]"; expected "str" - datatype = URIRef(element.get("datatype")) # type: ignore[arg-type] - elif element.get("{%s}lang" % XML_NAMESPACE, None): - lang = element.get("{%s}lang" % XML_NAMESPACE) - - ret = Literal(text, datatype=datatype, lang=lang) - - return ret - elif tag == RESULTS_NS_ET + "uri": - # type error: Argument 1 to "URIRef" has incompatible type "Optional[str]"; expected "str" - return URIRef(text) # type: ignore[arg-type] - elif tag == RESULTS_NS_ET + "bnode": - return BNode(text) - else: - raise TypeError("unknown binding type %r" % element) - - -class XMLResultSerializer(ResultSerializer): - def __init__(self, result: Result): - ResultSerializer.__init__(self, result) - - def serialize(self, stream: IO, encoding: str = "utf-8", **kwargs: Any) -> None: - writer = SPARQLXMLWriter(stream, encoding) - if self.result.type == "ASK": - writer.write_header([]) - # type error: Argument 1 to "write_ask" of "SPARQLXMLWriter" has incompatible type "Optional[bool]"; expected "bool" - writer.write_ask(self.result.askAnswer) # type: ignore[arg-type] - else: - # type error: Argument 1 to "write_header" of "SPARQLXMLWriter" has incompatible type "Optional[List[Variable]]"; expected "Sequence[Variable]" - writer.write_header(self.result.vars) # type: ignore[arg-type] - writer.write_results_header() - for b in self.result.bindings: - writer.write_start_result() - for key, val in b.items(): - writer.write_binding(key, val) - - writer.write_end_result() - - writer.close() - - -# TODO: Rewrite with ElementTree? -class SPARQLXMLWriter: - """ - Python saxutils-based SPARQL XML Writer - """ - - def __init__(self, output: IO, encoding: str = "utf-8"): - writer = XMLGenerator(output, encoding) - writer.startDocument() - writer.startPrefixMapping("", SPARQL_XML_NAMESPACE) - writer.startPrefixMapping("xml", XML_NAMESPACE) - writer.startElementNS( - (SPARQL_XML_NAMESPACE, "sparql"), "sparql", AttributesNSImpl({}, {}) - ) - self.writer = writer - self._output = output - self._encoding = encoding - self._results = False - - def write_header(self, allvarsL: Sequence[Variable]) -> None: - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "head"), "head", AttributesNSImpl({}, {}) - ) - for i in range(0, len(allvarsL)): - attr_vals = { - (None, "name"): str(allvarsL[i]), - } - attr_qnames = { - (None, "name"): "name", - } - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "variable"), - "variable", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" [arg-type] - AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type] - ) - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "variable"), "variable") - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "head"), "head") - - def write_ask(self, val: bool) -> None: - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "boolean"), "boolean", AttributesNSImpl({}, {}) - ) - self.writer.characters(str(val).lower()) - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "boolean"), "boolean") - - def write_results_header(self) -> None: - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "results"), "results", AttributesNSImpl({}, {}) - ) - self._results = True - - def write_start_result(self) -> None: - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "result"), "result", AttributesNSImpl({}, {}) - ) - self._resultStarted = True - - def write_end_result(self) -> None: - assert self._resultStarted - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "result"), "result") - self._resultStarted = False - - def write_binding(self, name: Variable, val: Identifier) -> None: - assert self._resultStarted - - attr_vals: Dict[Tuple[Optional[str], str], str] = { - (None, "name"): str(name), - } - attr_qnames: Dict[Tuple[Optional[str], str], str] = { - (None, "name"): "name", - } - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "binding"), - "binding", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" - AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type, unused-ignore] - ) - - if isinstance(val, URIRef): - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "uri"), "uri", AttributesNSImpl({}, {}) - ) - self.writer.characters(val) - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "uri"), "uri") - elif isinstance(val, BNode): - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "bnode"), "bnode", AttributesNSImpl({}, {}) - ) - self.writer.characters(val) - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "bnode"), "bnode") - elif isinstance(val, Literal): - attr_vals = {} - attr_qnames = {} - if val.language: - attr_vals[(XML_NAMESPACE, "lang")] = val.language - attr_qnames[(XML_NAMESPACE, "lang")] = "xml:lang" - elif val.datatype: - attr_vals[(None, "datatype")] = val.datatype - attr_qnames[(None, "datatype")] = "datatype" - - self.writer.startElementNS( - (SPARQL_XML_NAMESPACE, "literal"), - "literal", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[Optional[str], str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[Optional[str], str], str]"; expected "Mapping[Tuple[str, str], str]" - AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type, unused-ignore] - ) - self.writer.characters(val) - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "literal"), "literal") - - else: - raise Exception("Unsupported RDF term: %s" % val) - - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "binding"), "binding") - - def close(self) -> None: - if self._results: - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "results"), "results") - self.writer.endElementNS((SPARQL_XML_NAMESPACE, "sparql"), "sparql") - self.writer.endDocument() diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/sparql.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/sparql.py deleted file mode 100644 index 8249a0e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/sparql.py +++ /dev/null @@ -1,499 +0,0 @@ -from __future__ import annotations - -import collections -import datetime -import itertools -import typing as t -from collections.abc import Mapping, MutableMapping -from typing import ( - TYPE_CHECKING, - Any, - Container, - Dict, - Generator, - Iterable, - List, - Optional, - Tuple, - TypeVar, - Union, -) - -import rdflib.plugins.sparql -from rdflib.graph import ConjunctiveGraph, Dataset, Graph -from rdflib.namespace import NamespaceManager -from rdflib.plugins.sparql.parserutils import CompValue -from rdflib.term import BNode, Identifier, Literal, Node, URIRef, Variable - -if TYPE_CHECKING: - from rdflib.paths import Path - - -_AnyT = TypeVar("_AnyT") - - -class SPARQLError(Exception): - def __init__(self, msg: Optional[str] = None): - Exception.__init__(self, msg) - - -class NotBoundError(SPARQLError): - def __init__(self, msg: Optional[str] = None): - SPARQLError.__init__(self, msg) - - -class AlreadyBound(SPARQLError): # noqa: N818 - """Raised when trying to bind a variable that is already bound!""" - - def __init__(self): - SPARQLError.__init__(self) - - -class SPARQLTypeError(SPARQLError): - def __init__(self, msg: Optional[str]): - SPARQLError.__init__(self, msg) - - -class Bindings(MutableMapping): - """ - - A single level of a stack of variable-value bindings. - Each dict keeps a reference to the dict below it, - any failed lookup is propegated back - - In python 3.3 this could be a collections.ChainMap - """ - - def __init__(self, outer: Optional[Bindings] = None, d=[]): - self._d: Dict[str, str] = dict(d) - self.outer = outer - - def __getitem__(self, key: str) -> str: - if key in self._d: - return self._d[key] - - if not self.outer: - raise KeyError() - return self.outer[key] - - def __contains__(self, key: Any) -> bool: - try: - self[key] - return True - except KeyError: - return False - - def __setitem__(self, key: str, value: Any) -> None: - self._d[key] = value - - def __delitem__(self, key: str) -> None: - raise Exception("DelItem is not implemented!") - - def __len__(self) -> int: - i = 0 - d: Optional[Bindings] = self - while d is not None: - i += len(d._d) - d = d.outer - return i - - def __iter__(self) -> Generator[str, None, None]: - d: Optional[Bindings] = self - while d is not None: - yield from d._d - d = d.outer - - def __str__(self) -> str: - # type error: Generator has incompatible item type "Tuple[Any, str]"; expected "str" - return "Bindings({" + ", ".join((k, self[k]) for k in self) + "})" # type: ignore[misc] - - def __repr__(self) -> str: - return str(self) - - -class FrozenDict(Mapping): - """ - An immutable hashable dict - - Taken from http://stackoverflow.com/a/2704866/81121 - - """ - - def __init__(self, *args: Any, **kwargs: Any): - self._d: Dict[Identifier, Identifier] = dict(*args, **kwargs) - self._hash: Optional[int] = None - - def __iter__(self): - return iter(self._d) - - def __len__(self) -> int: - return len(self._d) - - def __getitem__(self, key: Identifier) -> Identifier: - return self._d[key] - - def __hash__(self) -> int: - # It would have been simpler and maybe more obvious to - # use hash(tuple(sorted(self._d.items()))) from this discussion - # so far, but this solution is O(n). I don't know what kind of - # n we are going to run into, but sometimes it's hard to resist the - # urge to optimize when it will gain improved algorithmic performance. - if self._hash is None: - self._hash = 0 - for key, value in self.items(): - self._hash ^= hash(key) - self._hash ^= hash(value) - return self._hash - - def project(self, vars: Container[Variable]) -> FrozenDict: - return FrozenDict(x for x in self.items() if x[0] in vars) - - def disjointDomain(self, other: t.Mapping[Identifier, Identifier]) -> bool: - return not bool(set(self).intersection(other)) - - def compatible(self, other: t.Mapping[Identifier, Identifier]) -> bool: - for k in self: - try: - if self[k] != other[k]: - return False - except KeyError: - pass - - return True - - def merge(self, other: t.Mapping[Identifier, Identifier]) -> FrozenDict: - res = FrozenDict(itertools.chain(self.items(), other.items())) - - return res - - def __str__(self) -> str: - return str(self._d) - - def __repr__(self) -> str: - return repr(self._d) - - -class FrozenBindings(FrozenDict): - def __init__(self, ctx: QueryContext, *args, **kwargs): - FrozenDict.__init__(self, *args, **kwargs) - self.ctx = ctx - - def __getitem__(self, key: Union[Identifier, str]) -> Identifier: - if not isinstance(key, Node): - key = Variable(key) - - if not isinstance(key, (BNode, Variable)): - return key - - if key not in self._d: - # type error: Value of type "Optional[Dict[Variable, Identifier]]" is not indexable - # type error: Invalid index type "Union[BNode, Variable]" for "Optional[Dict[Variable, Identifier]]"; expected type "Variable" - return self.ctx.initBindings[key] # type: ignore[index] - else: - return self._d[key] - - def project(self, vars: Container[Variable]) -> FrozenBindings: - return FrozenBindings(self.ctx, (x for x in self.items() if x[0] in vars)) - - def merge(self, other: t.Mapping[Identifier, Identifier]) -> FrozenBindings: - res = FrozenBindings(self.ctx, itertools.chain(self.items(), other.items())) - return res - - @property - def now(self) -> datetime.datetime: - return self.ctx.now - - @property - def bnodes(self) -> t.Mapping[Identifier, BNode]: - return self.ctx.bnodes - - @property - def prologue(self) -> Optional[Prologue]: - return self.ctx.prologue - - def forget( - self, before: QueryContext, _except: Optional[Container[Variable]] = None - ) -> FrozenBindings: - """ - return a frozen dict only of bindings made in self - since before - """ - if not _except: - _except = [] - - # bindings from initBindings are newer forgotten - return FrozenBindings( - self.ctx, - ( - x - for x in self.items() - if ( - x[0] in _except - # type error: Unsupported right operand type for in ("Optional[Dict[Variable, Identifier]]") - or x[0] in self.ctx.initBindings # type: ignore[operator] - or before[x[0]] is None - ) - ), - ) - - def remember(self, these) -> FrozenBindings: - """ - return a frozen dict only of bindings in these - """ - return FrozenBindings(self.ctx, (x for x in self.items() if x[0] in these)) - - -class QueryContext: - """ - Query context - passed along when evaluating the query - """ - - def __init__( - self, - graph: Optional[Graph] = None, - bindings: Optional[Union[Bindings, FrozenBindings, List[Any]]] = None, - initBindings: Optional[Mapping[str, Identifier]] = None, - datasetClause=None, - ): - self.initBindings = initBindings - self.bindings = Bindings(d=bindings or []) - if initBindings: - self.bindings.update(initBindings) - - self.graph: Optional[Graph] - self._dataset: Optional[Union[Dataset, ConjunctiveGraph]] - if isinstance(graph, (Dataset, ConjunctiveGraph)): - if datasetClause: - self._dataset = Dataset() - self.graph = Graph() - for d in datasetClause: - if d.default: - from_graph = graph.get_context(d.default) - self.graph += from_graph - if not from_graph: - self.load(d.default, default=True) - elif d.named: - namedGraphs = Graph( - store=self.dataset.store, identifier=d.named - ) - from_named_graphs = graph.get_context(d.named) - namedGraphs += from_named_graphs - if not from_named_graphs: - self.load(d.named, default=False) - else: - self._dataset = graph - if rdflib.plugins.sparql.SPARQL_DEFAULT_GRAPH_UNION: - self.graph = self.dataset - else: - self.graph = self.dataset.default_context - else: - self._dataset = None - self.graph = graph - - self.prologue: Optional[Prologue] = None - self._now: Optional[datetime.datetime] = None - - self.bnodes: t.MutableMapping[Identifier, BNode] = collections.defaultdict( - BNode - ) - - @property - def now(self) -> datetime.datetime: - if self._now is None: - self._now = datetime.datetime.now(datetime.timezone.utc) - return self._now - - def clone( - self, bindings: Optional[Union[FrozenBindings, Bindings, List[Any]]] = None - ) -> QueryContext: - r = QueryContext( - self._dataset if self._dataset is not None else self.graph, - bindings or self.bindings, - initBindings=self.initBindings, - ) - r.prologue = self.prologue - r.graph = self.graph - r.bnodes = self.bnodes - return r - - @property - def dataset(self) -> ConjunctiveGraph: - """ "current dataset""" - if self._dataset is None: - raise Exception( - "You performed a query operation requiring " - + "a dataset (i.e. ConjunctiveGraph), but " - + "operating currently on a single graph." - ) - return self._dataset - - def load( - self, - source: URIRef, - default: bool = False, - into: Optional[Identifier] = None, - **kwargs: Any, - ) -> None: - """ - Load data from the source into the query context's. - - :param source: The source to load from. - :param default: If `True`, triples from the source will be added - to the default graph, otherwise it will be loaded into a - graph with ``source`` URI as its name. - :param into: The name of the graph to load the data into. If - `None`, the source URI will be used as as the name of the - graph. - :param kwargs: Keyword arguments to pass to - :meth:`rdflib.graph.Graph.parse`. - """ - - def _load(graph, source): - try: - return graph.parse(source, format="turtle", **kwargs) - except Exception: - pass - try: - return graph.parse(source, format="xml", **kwargs) - except Exception: - pass - try: - return graph.parse(source, format="n3", **kwargs) - except Exception: - pass - try: - return graph.parse(source, format="nt", **kwargs) - except Exception: - raise Exception( - "Could not load %s as either RDF/XML, N3 or NTriples" % source - ) - - if not rdflib.plugins.sparql.SPARQL_LOAD_GRAPHS: - # we are not loading - if we already know the graph - # being "loaded", just add it to the default-graph - if default: - # Unsupported left operand type for + ("None") - self.graph += self.dataset.get_context(source) # type: ignore[operator] - else: - if default: - _load(self.graph, source) - else: - if into is None: - into = source - _load(self.dataset.get_context(into), source) - - def __getitem__(self, key: Union[str, Path]) -> Optional[Union[str, Path]]: - # in SPARQL BNodes are just labels - if not isinstance(key, (BNode, Variable)): - return key - try: - return self.bindings[key] - except KeyError: - return None - - def get(self, key: str, default: Optional[Any] = None) -> Any: - try: - return self[key] - except KeyError: - return default - - def solution(self, vars: Optional[Iterable[Variable]] = None) -> FrozenBindings: - """ - Return a static copy of the current variable bindings as dict - """ - if vars: - return FrozenBindings( - self, ((k, v) for k, v in self.bindings.items() if k in vars) - ) - else: - return FrozenBindings(self, self.bindings.items()) - - def __setitem__(self, key: str, value: str) -> None: - if key in self.bindings and self.bindings[key] != value: - raise AlreadyBound() - - self.bindings[key] = value - - def pushGraph(self, graph: Optional[Graph]) -> QueryContext: - r = self.clone() - r.graph = graph - return r - - def push(self) -> QueryContext: - r = self.clone(Bindings(self.bindings)) - return r - - def clean(self) -> QueryContext: - return self.clone([]) - - def thaw(self, frozenbindings: FrozenBindings) -> QueryContext: - """ - Create a new read/write query context from the given solution - """ - c = self.clone(frozenbindings) - - return c - - -class Prologue: - """ - A class for holding prefixing bindings and base URI information - """ - - def __init__(self) -> None: - self.base: Optional[str] = None - self.namespace_manager = NamespaceManager(Graph()) # ns man needs a store - - def resolvePName(self, prefix: Optional[str], localname: Optional[str]) -> URIRef: - ns = self.namespace_manager.store.namespace(prefix or "") - if ns is None: - raise Exception("Unknown namespace prefix : %s" % prefix) - return URIRef(ns + (localname or "")) - - def bind(self, prefix: Optional[str], uri: Any) -> None: - self.namespace_manager.bind(prefix, uri, replace=True) - - def absolutize( - self, iri: Optional[Union[CompValue, str]] - ) -> Optional[Union[CompValue, str]]: - """ - Apply BASE / PREFIXes to URIs - (and to datatypes in Literals) - - TODO: Move resolving URIs to pre-processing - """ - - if isinstance(iri, CompValue): - if iri.name == "pname": - return self.resolvePName(iri.prefix, iri.localname) - if iri.name == "literal": - # type error: Argument "datatype" to "Literal" has incompatible type "Union[CompValue, Identifier, None]"; expected "Optional[str]" - return Literal( - iri.string, lang=iri.lang, datatype=self.absolutize(iri.datatype) # type: ignore[arg-type] - ) - elif isinstance(iri, URIRef) and not ":" in iri: # noqa: E713 - return URIRef(iri, base=self.base) - - return iri - - -class Query: - """ - A parsed and translated query - """ - - def __init__(self, prologue: Prologue, algebra: CompValue): - self.prologue = prologue - self.algebra = algebra - self._original_args: Tuple[str, Mapping[str, str], Optional[str]] - - -class Update: - """ - A parsed and translated update - """ - - def __init__(self, prologue: Prologue, algebra: List[CompValue]): - self.prologue = prologue - self.algebra = algebra - self._original_args: Tuple[str, Mapping[str, str], Optional[str]] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/update.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/update.py deleted file mode 100644 index cd22a75..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/sparql/update.py +++ /dev/null @@ -1,353 +0,0 @@ -""" - -Code for carrying out Update Operations - -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Iterator, Mapping, Optional, Sequence - -from rdflib.graph import Graph -from rdflib.plugins.sparql.evaluate import evalBGP, evalPart -from rdflib.plugins.sparql.evalutils import _fillTemplate, _join -from rdflib.plugins.sparql.parserutils import CompValue -from rdflib.plugins.sparql.sparql import FrozenDict, QueryContext, Update -from rdflib.term import Identifier, URIRef, Variable - - -def _graphOrDefault(ctx: QueryContext, g: str) -> Optional[Graph]: - if g == "DEFAULT": - return ctx.graph - else: - return ctx.dataset.get_context(g) - - -def _graphAll(ctx: QueryContext, g: str) -> Sequence[Graph]: - """ - return a list of graphs - """ - if g == "DEFAULT": - # type error: List item 0 has incompatible type "Optional[Graph]"; expected "Graph" - return [ctx.graph] # type: ignore[list-item] - elif g == "NAMED": - return [ - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - c - for c in ctx.dataset.contexts() - if c.identifier != ctx.graph.identifier # type: ignore[union-attr] - ] - elif g == "ALL": - return list(ctx.dataset.contexts()) - else: - return [ctx.dataset.get_context(g)] - - -def evalLoad(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#load - """ - - if TYPE_CHECKING: - assert isinstance(u.iri, URIRef) - - if u.graphiri: - ctx.load(u.iri, default=False, into=u.graphiri) - else: - ctx.load(u.iri, default=True) - - -def evalCreate(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#create - """ - g = ctx.dataset.get_context(u.graphiri) - if len(g) > 0: - raise Exception("Graph %s already exists." % g.identifier) - raise Exception("Create not implemented!") - - -def evalClear(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#clear - """ - for g in _graphAll(ctx, u.graphiri): - g.remove((None, None, None)) - - -def evalDrop(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#drop - """ - if ctx.dataset.store.graph_aware: - for g in _graphAll(ctx, u.graphiri): - ctx.dataset.store.remove_graph(g) - else: - evalClear(ctx, u) - - -def evalInsertData(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#insertData - """ - # add triples - g = ctx.graph - g += u.triples - # add quads - # u.quads is a dict of graphURI=>[triples] - for g in u.quads: - # type error: Argument 1 to "get_context" of "ConjunctiveGraph" has incompatible type "Optional[Graph]"; expected "Union[IdentifiedNode, str, None]" - cg = ctx.dataset.get_context(g) # type: ignore[arg-type] - cg += u.quads[g] - - -def evalDeleteData(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#deleteData - """ - # remove triples - g = ctx.graph - g -= u.triples - - # remove quads - # u.quads is a dict of graphURI=>[triples] - for g in u.quads: - # type error: Argument 1 to "get_context" of "ConjunctiveGraph" has incompatible type "Optional[Graph]"; expected "Union[IdentifiedNode, str, None]" - cg = ctx.dataset.get_context(g) # type: ignore[arg-type] - cg -= u.quads[g] - - -def evalDeleteWhere(ctx: QueryContext, u: CompValue) -> None: - """ - http://www.w3.org/TR/sparql11-update/#deleteWhere - """ - - res: Iterator[FrozenDict] = evalBGP(ctx, u.triples) - for g in u.quads: - cg = ctx.dataset.get_context(g) - c = ctx.pushGraph(cg) - res = _join(res, list(evalBGP(c, u.quads[g]))) - - # type error: Incompatible types in assignment (expression has type "FrozenBindings", variable has type "QueryContext") - for c in res: # type: ignore[assignment] - g = ctx.graph - g -= _fillTemplate(u.triples, c) - - for g in u.quads: - cg = ctx.dataset.get_context(c.get(g)) - cg -= _fillTemplate(u.quads[g], c) - - -def evalModify(ctx: QueryContext, u: CompValue) -> None: - originalctx = ctx - - # Using replaces the dataset for evaluating the where-clause - dg: Optional[Graph] - if u.using: - otherDefault = False - for d in u.using: - if d.default: - if not otherDefault: - # replace current default graph - dg = Graph() - ctx = ctx.pushGraph(dg) - otherDefault = True - - ctx.load(d.default, default=True) - - elif d.named: - g = d.named - ctx.load(g, default=False) - - # "The WITH clause provides a convenience for when an operation - # primarily refers to a single graph. If a graph name is specified - # in a WITH clause, then - for the purposes of evaluating the - # WHERE clause - this will define an RDF Dataset containing a - # default graph with the specified name, but only in the absence - # of USING or USING NAMED clauses. In the presence of one or more - # graphs referred to in USING clauses and/or USING NAMED clauses, - # the WITH clause will be ignored while evaluating the WHERE - # clause." - if not u.using and u.withClause: - g = ctx.dataset.get_context(u.withClause) - ctx = ctx.pushGraph(g) - - res = evalPart(ctx, u.where) - - if u.using: - if otherDefault: - ctx = originalctx # restore original default graph - if u.withClause: - g = ctx.dataset.get_context(u.withClause) - ctx = ctx.pushGraph(g) - - for c in res: - dg = ctx.graph - if u.delete: - # type error: Unsupported left operand type for - ("None") - # type error: Unsupported operand types for - ("Graph" and "Generator[Tuple[Identifier, Identifier, Identifier], None, None]") - dg -= _fillTemplate(u.delete.triples, c) # type: ignore[operator] - - for g, q in u.delete.quads.items(): - cg = ctx.dataset.get_context(c.get(g)) - cg -= _fillTemplate(q, c) - - if u.insert: - # type error: Unsupported left operand type for + ("None") - # type error: Unsupported operand types for + ("Graph" and "Generator[Tuple[Identifier, Identifier, Identifier], None, None]") - dg += _fillTemplate(u.insert.triples, c) # type: ignore[operator] - - for g, q in u.insert.quads.items(): - cg = ctx.dataset.get_context(c.get(g)) - cg += _fillTemplate(q, c) - - -def evalAdd(ctx: QueryContext, u: CompValue) -> None: - """ - - add all triples from src to dst - - http://www.w3.org/TR/sparql11-update/#add - """ - src, dst = u.graph - - srcg = _graphOrDefault(ctx, src) - dstg = _graphOrDefault(ctx, dst) - - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - if srcg.identifier == dstg.identifier: # type: ignore[union-attr] - return - - # type error: Unsupported left operand type for + ("None") - dstg += srcg # type: ignore[operator] - - -def evalMove(ctx: QueryContext, u: CompValue) -> None: - """ - - remove all triples from dst - add all triples from src to dst - remove all triples from src - - http://www.w3.org/TR/sparql11-update/#move - """ - - src, dst = u.graph - - srcg = _graphOrDefault(ctx, src) - dstg = _graphOrDefault(ctx, dst) - - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - if srcg.identifier == dstg.identifier: # type: ignore[union-attr] - return - - # type error: Item "None" of "Optional[Graph]" has no attribute "remove" - dstg.remove((None, None, None)) # type: ignore[union-attr] - - # type error: Unsupported left operand type for + ("None") - dstg += srcg # type: ignore[operator] - - if ctx.dataset.store.graph_aware: - # type error: Argument 1 to "remove_graph" of "Store" has incompatible type "Optional[Graph]"; expected "Graph" - ctx.dataset.store.remove_graph(srcg) # type: ignore[arg-type] - else: - # type error: Item "None" of "Optional[Graph]" has no attribute "remove" - srcg.remove((None, None, None)) # type: ignore[union-attr] - - -def evalCopy(ctx: QueryContext, u: CompValue) -> None: - """ - - remove all triples from dst - add all triples from src to dst - - http://www.w3.org/TR/sparql11-update/#copy - """ - - src, dst = u.graph - - srcg = _graphOrDefault(ctx, src) - dstg = _graphOrDefault(ctx, dst) - - # type error: Item "None" of "Optional[Graph]" has no attribute "remove" - if srcg.identifier == dstg.identifier: # type: ignore[union-attr] - return - - # type error: Item "None" of "Optional[Graph]" has no attribute "remove" - dstg.remove((None, None, None)) # type: ignore[union-attr] - - # type error: Unsupported left operand type for + ("None") - dstg += srcg # type: ignore[operator] - - -def evalUpdate( - graph: Graph, - update: Update, - initBindings: Optional[Mapping[str, Identifier]] = None, -) -> None: - """ - - http://www.w3.org/TR/sparql11-update/#updateLanguage - - 'A request is a sequence of operations [...] Implementations MUST - ensure that operations of a single request are executed in a - fashion that guarantees the same effects as executing them in - lexical order. - - Operations all result either in success or failure. - - If multiple operations are present in a single request, then a - result of failure from any operation MUST abort the sequence of - operations, causing the subsequent operations to be ignored.' - - This will return None on success and raise Exceptions on error - - .. caution:: - - This method can access indirectly requested network endpoints, for - example, query processing will attempt to access network endpoints - specified in ``SERVICE`` directives. - - When processing untrusted or potentially malicious queries, measures - should be taken to restrict network and file access. - - For information on available security measures, see the RDFLib - :doc:`Security Considerations ` - documentation. - - """ - - for u in update.algebra: - initBindings = dict((Variable(k), v) for k, v in (initBindings or {}).items()) - - ctx = QueryContext(graph, initBindings=initBindings) - ctx.prologue = u.prologue - - try: - if u.name == "Load": - evalLoad(ctx, u) - elif u.name == "Clear": - evalClear(ctx, u) - elif u.name == "Drop": - evalDrop(ctx, u) - elif u.name == "Create": - evalCreate(ctx, u) - elif u.name == "Add": - evalAdd(ctx, u) - elif u.name == "Move": - evalMove(ctx, u) - elif u.name == "Copy": - evalCopy(ctx, u) - elif u.name == "InsertData": - evalInsertData(ctx, u) - elif u.name == "DeleteData": - evalDeleteData(ctx, u) - elif u.name == "DeleteWhere": - evalDeleteWhere(ctx, u) - elif u.name == "Modify": - evalModify(ctx, u) - else: - raise Exception("Unknown update operation: %s" % (u,)) - except: # noqa: E722 - if not u.silent: - raise diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/__init__.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/__init__.py deleted file mode 100644 index 2eb4756..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -This package contains modules for additional RDFLib stores -""" diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/auditable.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/auditable.py deleted file mode 100644 index b8fb534..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/auditable.py +++ /dev/null @@ -1,199 +0,0 @@ -""" - -This wrapper intercepts calls through the store interface and implements -thread-safe logging of destructive operations (adds / removes) in reverse. -This is persisted on the store instance and the reverse operations are -executed In order to return the store to the state it was when the transaction -began Since the reverse operations are persisted on the store, the store -itself acts as a transaction. - -Calls to commit or rollback, flush the list of reverse operations This -provides thread-safe atomicity and isolation (assuming concurrent operations -occur with different store instances), but no durability (transactions are -persisted in memory and won't be available to reverse operations after the -system fails): A and I out of ACID. - -""" - -from __future__ import annotations - -import threading -from typing import TYPE_CHECKING, Any, Generator, Iterator, List, Optional, Tuple - -from rdflib.graph import ConjunctiveGraph, Graph -from rdflib.store import Store - -if TYPE_CHECKING: - from rdflib.graph import ( - _ContextIdentifierType, - _ContextType, - _ObjectType, - _PredicateType, - _SubjectType, - _TriplePatternType, - _TripleType, - ) - from rdflib.query import Result - from rdflib.term import URIRef - - -destructiveOpLocks = { # noqa: N816 - "add": None, - "remove": None, -} - - -class AuditableStore(Store): - def __init__(self, store: Store): - self.store = store - self.context_aware = store.context_aware - # NOTE: this store can't be formula_aware as it doesn't have enough - # info to reverse the removal of a quoted statement - self.formula_aware = False # store.formula_aware - self.transaction_aware = True # This is only half true - self.reverseOps: List[ - Tuple[ - Optional[_SubjectType], - Optional[_PredicateType], - Optional[_ObjectType], - Optional[_ContextIdentifierType], - str, - ] - ] = [] - self.rollbackLock = threading.RLock() - - def open(self, configuration: str, create: bool = True) -> Optional[int]: - return self.store.open(configuration, create) - - def close(self, commit_pending_transaction: bool = False) -> None: - self.store.close() - - def destroy(self, configuration: str) -> None: - self.store.destroy(configuration) - - def query(self, *args: Any, **kw: Any) -> Result: - return self.store.query(*args, **kw) - - def add( - self, triple: _TripleType, context: _ContextType, quoted: bool = False - ) -> None: - (s, p, o) = triple - lock = destructiveOpLocks["add"] - lock = lock if lock else threading.RLock() - with lock: - context = ( - context.__class__(self.store, context.identifier) - if context is not None - else None - ) - ctxId = context.identifier if context is not None else None # noqa: N806 - if list(self.store.triples(triple, context)): - return # triple already in store, do nothing - self.reverseOps.append((s, p, o, ctxId, "remove")) - try: - self.reverseOps.remove((s, p, o, ctxId, "add")) - except ValueError: - pass - self.store.add((s, p, o), context, quoted) - - def remove( - self, spo: _TriplePatternType, context: Optional[_ContextType] = None - ) -> None: - subject, predicate, object_ = spo - lock = destructiveOpLocks["remove"] - lock = lock if lock else threading.RLock() - with lock: - # Need to determine which quads will be removed if any term is a - # wildcard - context = ( - context.__class__(self.store, context.identifier) - if context is not None - else None - ) - ctxId = context.identifier if context is not None else None # noqa: N806 - if None in [subject, predicate, object_, context]: - if ctxId: - # type error: Item "None" of "Optional[Graph]" has no attribute "triples" - for s, p, o in context.triples((subject, predicate, object_)): # type: ignore[union-attr] - try: - self.reverseOps.remove((s, p, o, ctxId, "remove")) - except ValueError: - self.reverseOps.append((s, p, o, ctxId, "add")) - else: - for s, p, o, ctx in ConjunctiveGraph(self.store).quads( - (subject, predicate, object_) - ): - try: - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - self.reverseOps.remove((s, p, o, ctx.identifier, "remove")) # type: ignore[union-attr] - except ValueError: - # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" - self.reverseOps.append((s, p, o, ctx.identifier, "add")) # type: ignore[union-attr] - else: - if not list(self.triples((subject, predicate, object_), context)): - return # triple not present in store, do nothing - try: - self.reverseOps.remove( - (subject, predicate, object_, ctxId, "remove") - ) - except ValueError: - self.reverseOps.append((subject, predicate, object_, ctxId, "add")) - self.store.remove((subject, predicate, object_), context) - - def triples( - self, triple: _TriplePatternType, context: Optional[_ContextType] = None - ) -> Iterator[Tuple[_TripleType, Iterator[Optional[_ContextType]]]]: - (su, pr, ob) = triple - context = ( - context.__class__(self.store, context.identifier) - if context is not None - else None - ) - for (s, p, o), cg in self.store.triples((su, pr, ob), context): - yield (s, p, o), cg - - def __len__(self, context: Optional[_ContextType] = None): - context = ( - context.__class__(self.store, context.identifier) - if context is not None - else None - ) - return self.store.__len__(context) - - def contexts( - self, triple: Optional[_TripleType] = None - ) -> Generator[_ContextType, None, None]: - for ctx in self.store.contexts(triple): - yield ctx - - def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: - self.store.bind(prefix, namespace, override=override) - - def prefix(self, namespace: URIRef) -> Optional[str]: - return self.store.prefix(namespace) - - def namespace(self, prefix: str) -> Optional[URIRef]: - return self.store.namespace(prefix) - - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: - return self.store.namespaces() - - def commit(self) -> None: - self.reverseOps = [] - - def rollback(self) -> None: - # Acquire Rollback lock and apply reverse operations in the forward - # order - with self.rollbackLock: - for subject, predicate, obj, context, op in self.reverseOps: - if op == "add": - # type error: Argument 2 to "Graph" has incompatible type "Optional[Node]"; expected "Union[IdentifiedNode, str, None]" - self.store.add( - (subject, predicate, obj), Graph(self.store, context) # type: ignore[arg-type] - ) - else: - self.store.remove( - (subject, predicate, obj), Graph(self.store, context) - ) - - self.reverseOps = [] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/berkeleydb.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/berkeleydb.py deleted file mode 100644 index 872dc36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/berkeleydb.py +++ /dev/null @@ -1,775 +0,0 @@ -from __future__ import annotations - -import logging -from os import mkdir -from os.path import abspath, exists -from threading import Thread -from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Tuple -from urllib.request import pathname2url - -from rdflib.store import NO_STORE, VALID_STORE, Store -from rdflib.term import Identifier, Node, URIRef - -if TYPE_CHECKING: - from rdflib.graph import Graph, _ContextType, _TriplePatternType, _TripleType - - -def bb(u: str) -> bytes: - return u.encode("utf-8") - - -try: - from berkeleydb import db - - has_bsddb = True -except ImportError: - has_bsddb = False - - -if has_bsddb: - # These are passed to bsddb when creating DBs - - # passed to db.DBEnv.set_flags - ENVSETFLAGS = db.DB_CDB_ALLDB - # passed to db.DBEnv.open - ENVFLAGS = db.DB_INIT_MPOOL | db.DB_INIT_CDB | db.DB_THREAD - CACHESIZE = 1024 * 1024 * 50 - - # passed to db.DB.Open() - DBOPENFLAGS = db.DB_THREAD - -logger = logging.getLogger(__name__) - -__all__ = [ - "BerkeleyDB", - "_ToKeyFunc", - "_FromKeyFunc", - "_GetPrefixFunc", - "_ResultsFromKeyFunc", -] - - -_ToKeyFunc = Callable[[Tuple[bytes, bytes, bytes], bytes], bytes] -_FromKeyFunc = Callable[[bytes], Tuple[bytes, bytes, bytes, bytes]] -_GetPrefixFunc = Callable[ - [Tuple[str, str, str], Optional[str]], Generator[str, None, None] -] -_ResultsFromKeyFunc = Callable[ - [bytes, Optional[Node], Optional[Node], Optional[Node], bytes], - Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]], -] - - -class BerkeleyDB(Store): - """\ - A store that allows for on-disk persistent using BerkeleyDB, a fast - key/value DB. - - This store implementation used to be known, previous to rdflib 6.0.0 - as 'Sleepycat' due to that being the then name of the Python wrapper - for BerkeleyDB. - - This store allows for quads as well as triples. See examples of use - in both the `examples.berkeleydb_example` and ``test/test_store/test_store_berkeleydb.py`` - files. - - **NOTE on installation**: - - To use this store, you must have BerkeleyDB installed on your system - separately to Python (``brew install berkeley-db`` on a Mac) and also have - the BerkeleyDB Python wrapper installed (``pip install berkeleydb``). - You may need to install BerkeleyDB Python wrapper like this: - ``YES_I_HAVE_THE_RIGHT_TO_USE_THIS_BERKELEY_DB_VERSION=1 pip install berkeleydb`` - """ - - context_aware = True - formula_aware = True - transaction_aware = False - graph_aware = True - db_env: db.DBEnv = None - - def __init__( - self, - configuration: Optional[str] = None, - identifier: Optional[Identifier] = None, - ): - if not has_bsddb: - raise ImportError("Unable to import berkeleydb, store is unusable.") - self.__open = False - self.__identifier = identifier - super(BerkeleyDB, self).__init__(configuration) - self._loads = self.node_pickler.loads - self._dumps = self.node_pickler.dumps - self.__indicies_info: List[Tuple[Any, _ToKeyFunc, _FromKeyFunc]] - - def __get_identifier(self) -> Optional[Identifier]: - return self.__identifier - - identifier = property(__get_identifier) - - def _init_db_environment( - self, homeDir: str, create: bool = True # noqa: N803 - ) -> db.DBEnv: - if not exists(homeDir): - if create is True: - mkdir(homeDir) - # TODO: implement create method and refactor this to it - self.create(homeDir) - else: - return NO_STORE - db_env = db.DBEnv() - db_env.set_cachesize(0, CACHESIZE) # TODO - # db_env.set_lg_max(1024*1024) - db_env.set_flags(ENVSETFLAGS, 1) - db_env.open(homeDir, ENVFLAGS | db.DB_CREATE) - return db_env - - def is_open(self) -> bool: - return self.__open - - def open(self, path: str, create: bool = True) -> Optional[int]: - if not has_bsddb: - return NO_STORE - homeDir = path # noqa: N806 - - if self.__identifier is None: - self.__identifier = URIRef(pathname2url(abspath(homeDir))) - - db_env = self._init_db_environment(homeDir, create) - if db_env == NO_STORE: - return NO_STORE - self.db_env = db_env - self.__open = True - - dbname = None - dbtype = db.DB_BTREE - # auto-commit ensures that the open-call commits when transactions - # are enabled - - dbopenflags = DBOPENFLAGS - if self.transaction_aware is True: - dbopenflags |= db.DB_AUTO_COMMIT - - if create: - dbopenflags |= db.DB_CREATE - - dbmode = 0o660 - dbsetflags = 0 - - # create and open the DBs - self.__indicies: List[db.DB] = [ - None, - ] * 3 - # NOTE on type ingore: this is because type checker does not like this - # way of initializing, using a temporary variable will solve it. - # type error: error: List item 0 has incompatible type "None"; expected "Tuple[Any, Callable[[Tuple[bytes, bytes, bytes], bytes], bytes], Callable[[bytes], Tuple[bytes, bytes, bytes, bytes]]]" - self.__indicies_info = [ - None, # type: ignore[list-item] - ] * 3 - for i in range(0, 3): - index_name = to_key_func(i)( - ("s".encode("latin-1"), "p".encode("latin-1"), "o".encode("latin-1")), - "c".encode("latin-1"), - ).decode() - index = db.DB(db_env) - index.set_flags(dbsetflags) - index.open(index_name, dbname, dbtype, dbopenflags, dbmode) - self.__indicies[i] = index - self.__indicies_info[i] = (index, to_key_func(i), from_key_func(i)) - - lookup: Dict[ - int, Tuple[db.DB, _GetPrefixFunc, _FromKeyFunc, _ResultsFromKeyFunc] - ] = {} - for i in range(0, 8): - results: List[Tuple[Tuple[int, int], int, int]] = [] - for start in range(0, 3): - score = 1 - len = 0 - for j in range(start, start + 3): - if i & (1 << (j % 3)): - score = score << 1 - len += 1 - else: - break - tie_break = 2 - start - results.append(((score, tie_break), start, len)) - - results.sort() - # NOTE on type error: this is because the variable `score` is - # reused with different type - # type error: Incompatible types in assignment (expression has type "Tuple[int, int]", variable has type "int") - score, start, len = results[-1] # type: ignore[assignment] - - def get_prefix_func(start: int, end: int) -> _GetPrefixFunc: - def get_prefix( - triple: Tuple[str, str, str], context: Optional[str] - ) -> Generator[str, None, None]: - if context is None: - yield "" - else: - yield context - i = start - while i < end: - yield triple[i % 3] - i += 1 - yield "" - - return get_prefix - - lookup[i] = ( - self.__indicies[start], - get_prefix_func(start, start + len), - from_key_func(start), - results_from_key_func(start, self._from_string), - ) - - self.__lookup_dict = lookup - - self.__contexts = db.DB(db_env) - self.__contexts.set_flags(dbsetflags) - self.__contexts.open("contexts", dbname, dbtype, dbopenflags, dbmode) - - self.__namespace = db.DB(db_env) - self.__namespace.set_flags(dbsetflags) - self.__namespace.open("namespace", dbname, dbtype, dbopenflags, dbmode) - - self.__prefix = db.DB(db_env) - self.__prefix.set_flags(dbsetflags) - self.__prefix.open("prefix", dbname, dbtype, dbopenflags, dbmode) - - self.__k2i = db.DB(db_env) - self.__k2i.set_flags(dbsetflags) - self.__k2i.open("k2i", dbname, db.DB_HASH, dbopenflags, dbmode) - - self.__i2k = db.DB(db_env) - self.__i2k.set_flags(dbsetflags) - self.__i2k.open("i2k", dbname, db.DB_RECNO, dbopenflags, dbmode) - - self.__needs_sync = False - t = Thread(target=self.__sync_run) - t.setDaemon(True) - t.start() - self.__sync_thread = t - return VALID_STORE - - def __sync_run(self) -> None: - from time import sleep, time - - try: - min_seconds, max_seconds = 10, 300 - while self.__open: - if self.__needs_sync: - t0 = t1 = time() - self.__needs_sync = False - while self.__open: - sleep(0.1) - if self.__needs_sync: - t1 = time() - self.__needs_sync = False - if time() - t1 > min_seconds or time() - t0 > max_seconds: - self.__needs_sync = False - logger.debug("sync") - self.sync() - break - else: - sleep(1) - except Exception as e: - logger.exception(e) - - def sync(self) -> None: - if self.__open: - for i in self.__indicies: - i.sync() - self.__contexts.sync() - self.__namespace.sync() - self.__prefix.sync() - self.__i2k.sync() - self.__k2i.sync() - - def close(self, commit_pending_transaction: bool = False) -> None: - self.__open = False - self.__sync_thread.join() - for i in self.__indicies: - i.close() - self.__contexts.close() - self.__namespace.close() - self.__prefix.close() - self.__i2k.close() - self.__k2i.close() - self.db_env.close() - - def add( - self, - triple: _TripleType, - context: _ContextType, - quoted: bool = False, - txn: Optional[Any] = None, - ) -> None: - """\ - Add a triple to the store of triples. - """ - (subject, predicate, object) = triple - assert self.__open, "The Store must be open." - assert context != self, "Can not add triple directly to store" - Store.add(self, (subject, predicate, object), context, quoted) - - _to_string = self._to_string - - s = _to_string(subject, txn=txn) - p = _to_string(predicate, txn=txn) - o = _to_string(object, txn=txn) - c = _to_string(context, txn=txn) - - cspo, cpos, cosp = self.__indicies - - value = cspo.get(bb("%s^%s^%s^%s^" % (c, s, p, o)), txn=txn) - if value is None: - self.__contexts.put(bb(c), b"", txn=txn) - - contexts_value = cspo.get( - bb("%s^%s^%s^%s^" % ("", s, p, o)), txn=txn - ) or "".encode("latin-1") - contexts = set(contexts_value.split("^".encode("latin-1"))) - contexts.add(bb(c)) - contexts_value = "^".encode("latin-1").join(contexts) - assert contexts_value is not None - - cspo.put(bb("%s^%s^%s^%s^" % (c, s, p, o)), b"", txn=txn) - cpos.put(bb("%s^%s^%s^%s^" % (c, p, o, s)), b"", txn=txn) - cosp.put(bb("%s^%s^%s^%s^" % (c, o, s, p)), b"", txn=txn) - if not quoted: - cspo.put(bb("%s^%s^%s^%s^" % ("", s, p, o)), contexts_value, txn=txn) - cpos.put(bb("%s^%s^%s^%s^" % ("", p, o, s)), contexts_value, txn=txn) - cosp.put(bb("%s^%s^%s^%s^" % ("", o, s, p)), contexts_value, txn=txn) - - self.__needs_sync = True - - def __remove( - self, - spo: Tuple[bytes, bytes, bytes], - c: bytes, - quoted: bool = False, - txn: Optional[Any] = None, - ) -> None: - s, p, o = spo - cspo, cpos, cosp = self.__indicies - contexts_value = cspo.get( - "^".encode("latin-1").join( - ["".encode("latin-1"), s, p, o, "".encode("latin-1")] - ), - txn=txn, - ) or "".encode("latin-1") - contexts = set(contexts_value.split("^".encode("latin-1"))) - contexts.discard(c) - contexts_value = "^".encode("latin-1").join(contexts) - for i, _to_key, _from_key in self.__indicies_info: - i.delete(_to_key((s, p, o), c), txn=txn) - if not quoted: - if contexts_value: - for i, _to_key, _from_key in self.__indicies_info: - i.put( - _to_key((s, p, o), "".encode("latin-1")), - contexts_value, - txn=txn, - ) - else: - for i, _to_key, _from_key in self.__indicies_info: - try: - i.delete(_to_key((s, p, o), "".encode("latin-1")), txn=txn) - except db.DBNotFoundError: - pass # TODO: is it okay to ignore these? - - # type error: Signature of "remove" incompatible with supertype "Store" - def remove( # type: ignore[override] - self, - spo: _TriplePatternType, - context: Optional[_ContextType], - txn: Optional[Any] = None, - ) -> None: - subject, predicate, object = spo - assert self.__open, "The Store must be open." - Store.remove(self, (subject, predicate, object), context) - _to_string = self._to_string - - if context is not None: - if context == self: - context = None - - if ( - subject is not None - and predicate is not None - and object is not None - and context is not None - ): - s = _to_string(subject, txn=txn) - p = _to_string(predicate, txn=txn) - o = _to_string(object, txn=txn) - c = _to_string(context, txn=txn) - value = self.__indicies[0].get(bb("%s^%s^%s^%s^" % (c, s, p, o)), txn=txn) - if value is not None: - self.__remove((bb(s), bb(p), bb(o)), bb(c), txn=txn) - self.__needs_sync = True - else: - cspo, cpos, cosp = self.__indicies - index, prefix, from_key, results_from_key = self.__lookup( - (subject, predicate, object), context, txn=txn - ) - - cursor = index.cursor(txn=txn) - try: - current = cursor.set_range(prefix) - needs_sync = True - except db.DBNotFoundError: - current = None - needs_sync = False - cursor.close() - while current: - key, value = current - cursor = index.cursor(txn=txn) - try: - cursor.set_range(key) - current = cursor.next - except db.DBNotFoundError: - current = None - cursor.close() - if key.startswith(prefix): - # NOTE on type error: variables are being reused with a - # different type - # type error: Incompatible types in assignment (expression has type "bytes", variable has type "str") - c, s, p, o = from_key(key) # type: ignore[assignment] - if context is None: - contexts_value = index.get(key, txn=txn) or "".encode("latin-1") - # remove triple from all non quoted contexts - contexts = set(contexts_value.split("^".encode("latin-1"))) - # and from the conjunctive index - contexts.add("".encode("latin-1")) - for c in contexts: - for i, _to_key, _ in self.__indicies_info: - # NOTE on type error: variables are being - # reused with a different type - # type error: Argument 1 has incompatible type "Tuple[str, str, str]"; expected "Tuple[bytes, bytes, bytes]" - # type error: Argument 2 has incompatible type "str"; expected "bytes" - i.delete(_to_key((s, p, o), c), txn=txn) # type: ignore[arg-type] - else: - # type error: Argument 1 to "__remove" of "BerkeleyDB" has incompatible type "Tuple[str, str, str]"; expected "Tuple[bytes, bytes, bytes]" - # type error: Argument 2 to "__remove" of "BerkeleyDB" has incompatible type "str"; expected "bytes" - self.__remove((s, p, o), c, txn=txn) # type: ignore[arg-type] - else: - break - - if context is not None: - if subject is None and predicate is None and object is None: - # TODO: also if context becomes empty and not just on - # remove((None, None, None), c) - try: - self.__contexts.delete( - bb(_to_string(context, txn=txn)), txn=txn - ) - except db.DBNotFoundError: - pass - - self.__needs_sync = needs_sync - - def triples( - self, - spo: _TriplePatternType, - context: Optional[_ContextType] = None, - txn: Optional[Any] = None, - ) -> Generator[ - Tuple[_TripleType, Generator[Optional[_ContextType], None, None]], - None, - None, - ]: - """A generator over all the triples matching""" - assert self.__open, "The Store must be open." - - subject, predicate, object = spo - - if context is not None: - if context == self: - context = None - - # _from_string = self._from_string ## UNUSED - index, prefix, from_key, results_from_key = self.__lookup( - (subject, predicate, object), context, txn=txn - ) - - cursor = index.cursor(txn=txn) - try: - current = cursor.set_range(prefix) - except db.DBNotFoundError: - current = None - cursor.close() - while current: - key, value = current - cursor = index.cursor(txn=txn) - try: - cursor.set_range(key) - current = cursor.next - except db.DBNotFoundError: - current = None - cursor.close() - if key and key.startswith(prefix): - contexts_value = index.get(key, txn=txn) - # type error: Incompatible types in "yield" (actual type "Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]]", expected type "Tuple[Tuple[IdentifiedNode, URIRef, Identifier], Iterator[Optional[Graph]]]") - # NOTE on type ignore: this is needed because some context is - # lost in the process of extracting triples from the database. - yield results_from_key(key, subject, predicate, object, contexts_value) # type: ignore[misc] - else: - break - - def __len__(self, context: Optional[_ContextType] = None) -> int: - assert self.__open, "The Store must be open." - if context is not None: - if context == self: - context = None - - if context is None: - prefix = "^".encode("latin-1") - else: - prefix = bb("%s^" % self._to_string(context)) - - index = self.__indicies[0] - cursor = index.cursor() - current = cursor.set_range(prefix) - count = 0 - while current: - key, value = current - if key.startswith(prefix): - count += 1 - current = cursor.next - else: - break - cursor.close() - return count - - def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: - # NOTE on type error: this is because the variables are reused with - # another type. - # type error: Incompatible types in assignment (expression has type "bytes", variable has type "str") - prefix = prefix.encode("utf-8") # type: ignore[assignment] - # type error: Incompatible types in assignment (expression has type "bytes", variable has type "URIRef") - namespace = namespace.encode("utf-8") # type: ignore[assignment] - bound_prefix = self.__prefix.get(namespace) - bound_namespace = self.__namespace.get(prefix) - if override: - if bound_prefix: - self.__namespace.delete(bound_prefix) - if bound_namespace: - self.__prefix.delete(bound_namespace) - self.__prefix[namespace] = prefix - self.__namespace[prefix] = namespace - else: - self.__prefix[bound_namespace or namespace] = bound_prefix or prefix - self.__namespace[bound_prefix or prefix] = bound_namespace or namespace - - def namespace(self, prefix: str) -> Optional[URIRef]: - # NOTE on type error: this is because the variable is reused with - # another type. - # type error: Incompatible types in assignment (expression has type "bytes", variable has type "str") - prefix = prefix.encode("utf-8") # type: ignore[assignment] - ns = self.__namespace.get(prefix, None) - if ns is not None: - return URIRef(ns.decode("utf-8")) - return None - - def prefix(self, namespace: URIRef) -> Optional[str]: - # NOTE on type error: this is because the variable is reused with - # another type. - # type error: Incompatible types in assignment (expression has type "bytes", variable has type "URIRef") - namespace = namespace.encode("utf-8") # type: ignore[assignment] - prefix = self.__prefix.get(namespace, None) - if prefix is not None: - return prefix.decode("utf-8") - return None - - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: - cursor = self.__namespace.cursor() - results = [] - current = cursor.first() - while current: - prefix, namespace = current - results.append((prefix.decode("utf-8"), namespace.decode("utf-8"))) - current = cursor.next - cursor.close() - for prefix, namespace in results: - yield prefix, URIRef(namespace) - - def contexts( - self, triple: Optional[_TripleType] = None - ) -> Generator[_ContextType, None, None]: - _from_string = self._from_string - _to_string = self._to_string - # NOTE on type errors: context is lost because of how data is loaded - # from the DB. - if triple: - s: str - p: str - o: str - # type error: Incompatible types in assignment (expression has type "Node", variable has type "str") - s, p, o = triple # type: ignore[assignment] - # type error: Argument 1 has incompatible type "str"; expected "Node" - s = _to_string(s) # type: ignore[arg-type] - # type error: Argument 1 has incompatible type "str"; expected "Node" - p = _to_string(p) # type: ignore[arg-type] - # type error: Argument 1 has incompatible type "str"; expected "Node" - o = _to_string(o) # type: ignore[arg-type] - contexts = self.__indicies[0].get(bb("%s^%s^%s^%s^" % ("", s, p, o))) - if contexts: - for c in contexts.split("^".encode("latin-1")): - if c: - # type error: Incompatible types in "yield" (actual type "Node", expected type "Graph") - yield _from_string(c) # type: ignore[misc] - else: - index = self.__contexts - cursor = index.cursor() - current = cursor.first() - cursor.close() - while current: - key, value = current - context = _from_string(key) - # type error: Incompatible types in "yield" (actual type "Node", expected type "Graph") - yield context # type: ignore[misc] - cursor = index.cursor() - try: - cursor.set_range(key) - current = cursor.next - except db.DBNotFoundError: - current = None - cursor.close() - - def add_graph(self, graph: Graph) -> None: - self.__contexts.put(bb(self._to_string(graph)), b"") - - def remove_graph(self, graph: Graph): - self.remove((None, None, None), graph) - - def _from_string(self, i: bytes) -> Node: - k = self.__i2k.get(int(i)) - return self._loads(k) - - def _to_string(self, term: Node, txn: Optional[Any] = None) -> str: - k = self._dumps(term) - i = self.__k2i.get(k, txn=txn) - if i is None: - # weird behaviour from bsddb not taking a txn as a keyword argument - # for append - if self.transaction_aware: - i = "%s" % self.__i2k.append(k, txn) - else: - i = "%s" % self.__i2k.append(k) - - self.__k2i.put(k, i.encode(), txn=txn) - else: - i = i.decode() - return i - - def __lookup( - self, - spo: _TriplePatternType, - context: Optional[_ContextType], - txn: Optional[Any] = None, - ) -> Tuple[db.DB, bytes, _FromKeyFunc, _ResultsFromKeyFunc]: - subject, predicate, object = spo - _to_string = self._to_string - # NOTE on type errors: this is because the same variable is used with different types. - if context is not None: - # type error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Graph]") - context = _to_string(context, txn=txn) # type: ignore[assignment] - i = 0 - if subject is not None: - i += 1 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - subject = _to_string(subject, txn=txn) # type: ignore[assignment] - if predicate is not None: - i += 2 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - predicate = _to_string(predicate, txn=txn) # type: ignore[assignment] - if object is not None: - i += 4 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - object = _to_string(object, txn=txn) # type: ignore[assignment] - index, prefix_func, from_key, results_from_key = self.__lookup_dict[i] - # print (subject, predicate, object), context, prefix_func, index - # #DEBUG - # type error: Argument 1 has incompatible type "Tuple[Node, Node, Node]"; expected "Tuple[str, str, str]" - # type error: Argument 2 has incompatible type "Optional[Graph]"; expected "Optional[str]" - prefix = bb("^".join(prefix_func((subject, predicate, object), context))) # type: ignore[arg-type] - return index, prefix, from_key, results_from_key - - -def to_key_func(i: int) -> _ToKeyFunc: - def to_key(triple: Tuple[bytes, bytes, bytes], context: bytes) -> bytes: - "Takes a string; returns key" - return "^".encode("latin-1").join( - ( - context, - triple[i % 3], - triple[(i + 1) % 3], - triple[(i + 2) % 3], - "".encode("latin-1"), - ) - ) # "" to tac on the trailing ^ - - return to_key - - -def from_key_func(i: int) -> _FromKeyFunc: - def from_key(key: bytes) -> Tuple[bytes, bytes, bytes, bytes]: - "Takes a key; returns string" - parts = key.split("^".encode("latin-1")) - return ( - parts[0], - parts[(3 - i + 0) % 3 + 1], - parts[(3 - i + 1) % 3 + 1], - parts[(3 - i + 2) % 3 + 1], - ) - - return from_key - - -def results_from_key_func( - i: int, from_string: Callable[[bytes], Node] -) -> _ResultsFromKeyFunc: - def from_key( - key: bytes, - subject: Optional[Node], - predicate: Optional[Node], - object: Optional[Node], - contexts_value: bytes, - ) -> Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]]: - "Takes a key and subject, predicate, object; returns tuple for yield" - parts = key.split("^".encode("latin-1")) - if subject is None: - # TODO: i & 1: # dis assemble and/or measure to see which is faster - # subject is None or i & 1 - s = from_string(parts[(3 - i + 0) % 3 + 1]) - else: - s = subject - if predicate is None: # i & 2: - p = from_string(parts[(3 - i + 1) % 3 + 1]) - else: - p = predicate - if object is None: # i & 4: - o = from_string(parts[(3 - i + 2) % 3 + 1]) - else: - o = object - return ( - (s, p, o), - (from_string(c) for c in contexts_value.split("^".encode("latin-1")) if c), - ) - - return from_key - - -# TODO: Remove unused -def readable_index(i: int) -> str: - # type error: Unpacking a string is disallowed - s, p, o = "?" * 3 # type: ignore[misc] - if i & 1: - s = "s" - if i & 2: - p = "p" - if i & 4: - o = "o" - return "%s,%s,%s" % (s, p, o) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/concurrent.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/concurrent.py deleted file mode 100644 index 2d05095..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/concurrent.py +++ /dev/null @@ -1,95 +0,0 @@ -from threading import Lock - - -class ResponsibleGenerator: - """A generator that will help clean up when it is done being used.""" - - __slots__ = ["cleanup", "gen"] - - def __init__(self, gen, cleanup): - self.cleanup = cleanup - self.gen = gen - - def __del__(self): - self.cleanup() - - def __iter__(self): - return self - - def __next__(self): - return next(self.gen) - - -class ConcurrentStore: - def __init__(self, store): - self.store = store - - # number of calls to visit still in progress - self.__visit_count = 0 - - # lock for locking down the indices - self.__lock = Lock() - - # lists for keeping track of added and removed triples while - # we wait for the lock - self.__pending_removes = [] - self.__pending_adds = [] - - def add(self, triple): - (s, p, o) = triple - if self.__visit_count == 0: - self.store.add((s, p, o)) - else: - self.__pending_adds.append((s, p, o)) - - def remove(self, triple): - (s, p, o) = triple - if self.__visit_count == 0: - self.store.remove((s, p, o)) - else: - self.__pending_removes.append((s, p, o)) - - def triples(self, triple): - (su, pr, ob) = triple - g = self.store.triples((su, pr, ob)) - pending_removes = self.__pending_removes - self.__begin_read() - for s, p, o in ResponsibleGenerator(g, self.__end_read): - if not (s, p, o) in pending_removes: # noqa: E713 - yield s, p, o - - for s, p, o in self.__pending_adds: - if ( - (su is None or su == s) - and (pr is None or pr == p) - and (ob is None or ob == o) - ): - yield s, p, o - - def __len__(self): - return self.store.__len__() - - def __begin_read(self): - lock = self.__lock - lock.acquire() - self.__visit_count = self.__visit_count + 1 - lock.release() - - def __end_read(self): - lock = self.__lock - lock.acquire() - self.__visit_count = self.__visit_count - 1 - if self.__visit_count == 0: - pending_removes = self.__pending_removes - while pending_removes: - (s, p, o) = pending_removes.pop() - try: - self.store.remove((s, p, o)) - except: # noqa: E722 - # TODO: change to try finally? - print(s, p, o, "Not in store to remove") - pending_adds = self.__pending_adds - while pending_adds: - (s, p, o) = pending_adds.pop() - self.store.add((s, p, o)) - lock.release() diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/memory.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/memory.py deleted file mode 100644 index 7dc7c25..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/memory.py +++ /dev/null @@ -1,737 +0,0 @@ -# -# -from __future__ import annotations - -from typing import ( - TYPE_CHECKING, - Any, - Collection, - Dict, - Generator, - Iterator, - Mapping, - Optional, - Set, - Tuple, - Union, - overload, -) - -from rdflib.store import Store -from rdflib.util import _coalesce - -if TYPE_CHECKING: - from rdflib.graph import ( - Graph, - _ContextType, - _ObjectType, - _PredicateType, - _SubjectType, - _TriplePatternType, - _TripleType, - ) - from rdflib.plugins.sparql.sparql import Query, Update - from rdflib.query import Result - from rdflib.term import Identifier, URIRef - -__all__ = ["SimpleMemory", "Memory"] - -ANY: None = None - - -class SimpleMemory(Store): - """\ - A fast naive in memory implementation of a triple store. - - This triple store uses nested dictionaries to store triples. Each - triple is stored in two such indices as follows spo[s][p][o] = 1 and - pos[p][o][s] = 1. - - Authors: Michel Pelletier, Daniel Krech, Stefan Niederhauser - """ - - def __init__( - self, - configuration: Optional[str] = None, - identifier: Optional[Identifier] = None, - ): - super(SimpleMemory, self).__init__(configuration) - self.identifier = identifier - - # indexed by [subject][predicate][object] - self.__spo: Dict[_SubjectType, Dict[_PredicateType, Dict[_ObjectType, int]]] = ( - {} - ) - - # indexed by [predicate][object][subject] - self.__pos: Dict[_PredicateType, Dict[_ObjectType, Dict[_SubjectType, int]]] = ( - {} - ) - - # indexed by [predicate][object][subject] - self.__osp: Dict[_ObjectType, Dict[_SubjectType, Dict[_PredicateType, int]]] = ( - {} - ) - - self.__namespace: Dict[str, URIRef] = {} - self.__prefix: Dict[URIRef, str] = {} - - def add( - self, - triple: _TripleType, - context: _ContextType, - quoted: bool = False, - ) -> None: - """\ - Add a triple to the store of triples. - """ - # add dictionary entries for spo[s][p][p] = 1 and pos[p][o][s] - # = 1, creating the nested dictionaries where they do not yet - # exits. - subject, predicate, object = triple - spo = self.__spo - try: - po = spo[subject] - except: # noqa: E722 - po = spo[subject] = {} - try: - o = po[predicate] - except: # noqa: E722 - o = po[predicate] = {} - o[object] = 1 - - pos = self.__pos - try: - os = pos[predicate] - except: # noqa: E722 - os = pos[predicate] = {} - try: - s = os[object] - except: # noqa: E722 - s = os[object] = {} - s[subject] = 1 - - osp = self.__osp - try: - sp = osp[object] - except: # noqa: E722 - sp = osp[object] = {} - try: - p = sp[subject] - except: # noqa: E722 - p = sp[subject] = {} - p[predicate] = 1 - - def remove( - self, - triple_pattern: _TriplePatternType, - context: Optional[_ContextType] = None, - ) -> None: - for (subject, predicate, object), c in list(self.triples(triple_pattern)): - del self.__spo[subject][predicate][object] - del self.__pos[predicate][object][subject] - del self.__osp[object][subject][predicate] - - def triples( - self, - triple_pattern: _TriplePatternType, - context: Optional[_ContextType] = None, - ) -> Iterator[Tuple[_TripleType, Iterator[Optional[_ContextType]]]]: - """A generator over all the triples matching""" - subject, predicate, object = triple_pattern - if subject != ANY: # subject is given - spo = self.__spo - if subject in spo: - subjectDictionary = spo[subject] # noqa: N806 - if predicate != ANY: # subject+predicate is given - if predicate in subjectDictionary: - if object != ANY: # subject+predicate+object is given - if object in subjectDictionary[predicate]: - yield (subject, predicate, object), self.__contexts() - else: # given object not found - pass - else: # subject+predicate is given, object unbound - for o in subjectDictionary[predicate].keys(): - yield (subject, predicate, o), self.__contexts() - else: # given predicate not found - pass - else: # subject given, predicate unbound - for p in subjectDictionary.keys(): - if object != ANY: # object is given - if object in subjectDictionary[p]: - yield (subject, p, object), self.__contexts() - else: # given object not found - pass - else: # object unbound - for o in subjectDictionary[p].keys(): - yield (subject, p, o), self.__contexts() - else: # given subject not found - pass - elif predicate != ANY: # predicate is given, subject unbound - pos = self.__pos - if predicate in pos: - predicateDictionary = pos[predicate] # noqa: N806 - if object != ANY: # predicate+object is given, subject unbound - if object in predicateDictionary: - for s in predicateDictionary[object].keys(): - yield (s, predicate, object), self.__contexts() - else: # given object not found - pass - else: # predicate is given, object+subject unbound - for o in predicateDictionary.keys(): - for s in predicateDictionary[o].keys(): - yield (s, predicate, o), self.__contexts() - elif object != ANY: # object is given, subject+predicate unbound - osp = self.__osp - if object in osp: - objectDictionary = osp[object] # noqa: N806 - for s in objectDictionary.keys(): - for p in objectDictionary[s].keys(): - yield (s, p, object), self.__contexts() - else: # subject+predicate+object unbound - spo = self.__spo - for s in spo.keys(): - subjectDictionary = spo[s] # noqa: N806 - for p in subjectDictionary.keys(): - for o in subjectDictionary[p].keys(): - yield (s, p, o), self.__contexts() - - def __len__(self, context: Optional[_ContextType] = None) -> int: - # @@ optimize - i = 0 - for triple in self.triples((None, None, None)): - i += 1 - return i - - def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: - # should be identical to `Memory.bind` - bound_namespace = self.__namespace.get(prefix) - bound_prefix = _coalesce( - self.__prefix.get(namespace), - # type error: error: Argument 1 to "get" of "Mapping" has incompatible type "Optional[URIRef]"; expected "URIRef" - self.__prefix.get(bound_namespace), # type: ignore[arg-type] - ) - if override: - if bound_prefix is not None: - del self.__namespace[bound_prefix] - if bound_namespace is not None: - del self.__prefix[bound_namespace] - self.__prefix[namespace] = prefix - self.__namespace[prefix] = namespace - else: - # type error: Invalid index type "Optional[URIRef]" for "Dict[URIRef, str]"; expected type "URIRef" - self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce( # type: ignore[index] - bound_prefix, default=prefix - ) - # type error: Invalid index type "Optional[str]" for "Dict[str, URIRef]"; expected type "str" - self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce( # type: ignore[index] - bound_namespace, default=namespace - ) - - def namespace(self, prefix: str) -> Optional[URIRef]: - return self.__namespace.get(prefix, None) - - def prefix(self, namespace: URIRef) -> Optional[str]: - return self.__prefix.get(namespace, None) - - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: - for prefix, namespace in self.__namespace.items(): - yield prefix, namespace - - def __contexts(self) -> Generator[_ContextType, None, None]: - # TODO: best way to return empty generator - # type error: Need type annotation for "c" - return (c for c in []) # type: ignore[var-annotated] - - # type error: Missing return statement - def query( # type: ignore[return] - self, - query: Union[Query, str], - initNs: Mapping[str, Any], # noqa: N803 - initBindings: Mapping[str, Identifier], # noqa: N803 - queryGraph: str, # noqa: N803 - **kwargs: Any, - ) -> Result: - super(SimpleMemory, self).query( - query, initNs, initBindings, queryGraph, **kwargs - ) - - def update( - self, - update: Union[Update, str], - initNs: Mapping[str, Any], # noqa: N803 - initBindings: Mapping[str, Identifier], # noqa: N803 - queryGraph: str, # noqa: N803 - **kwargs: Any, - ) -> None: - super(SimpleMemory, self).update( - update, initNs, initBindings, queryGraph, **kwargs - ) - - -class Memory(Store): - """\ - An in memory implementation of a triple store. - - Same as SimpleMemory above, but is Context-aware, Graph-aware, and Formula-aware - Authors: Ashley Sommer - """ - - context_aware = True - formula_aware = True - graph_aware = True - - def __init__( - self, - configuration: Optional[str] = None, - identifier: Optional[Identifier] = None, - ): - super(Memory, self).__init__(configuration) - self.identifier = identifier - - # indexed by [subject][predicate][object] - self.__spo: Dict[_SubjectType, Dict[_PredicateType, Dict[_ObjectType, int]]] = ( - {} - ) - - # indexed by [predicate][object][subject] - self.__pos: Dict[_PredicateType, Dict[_ObjectType, Dict[_SubjectType, int]]] = ( - {} - ) - - # indexed by [predicate][object][subject] - self.__osp: Dict[_ObjectType, Dict[_SubjectType, Dict[_PredicateType, int]]] = ( - {} - ) - - self.__namespace: Dict[str, URIRef] = {} - self.__prefix: Dict[URIRef, str] = {} - self.__context_obj_map: Dict[str, Graph] = {} - self.__tripleContexts: Dict[_TripleType, Dict[Optional[str], bool]] = {} - self.__contextTriples: Dict[Optional[str], Set[_TripleType]] = {None: set()} - # all contexts used in store (unencoded) - self.__all_contexts: Set[Graph] = set() - # default context information for triples - self.__defaultContexts: Optional[Dict[Optional[str], bool]] = None - - def add( - self, - triple: _TripleType, - context: _ContextType, - quoted: bool = False, - ) -> None: - """\ - Add a triple to the store of triples. - """ - # add dictionary entries for spo[s][p][p] = 1 and pos[p][o][s] - # = 1, creating the nested dictionaries where they do not yet - # exits. - Store.add(self, triple, context, quoted=quoted) - if context is not None: - self.__all_contexts.add(context) - subject, predicate, object_ = triple - - spo = self.__spo - try: - po = spo[subject] - except LookupError: - po = spo[subject] = {} - try: - o = po[predicate] - except LookupError: - o = po[predicate] = {} - - try: - _ = o[object_] - # This cannot be reached if (s, p, o) was not inserted before. - triple_exists = True - except KeyError: - o[object_] = 1 - triple_exists = False - self.__add_triple_context(triple, triple_exists, context, quoted) - - if triple_exists: - # No need to insert twice this triple. - return - - pos = self.__pos - try: - os = pos[predicate] - except LookupError: - os = pos[predicate] = {} - try: - s = os[object_] - except LookupError: - s = os[object_] = {} - s[subject] = 1 - - osp = self.__osp - try: - sp = osp[object_] - except LookupError: - sp = osp[object_] = {} - try: - p = sp[subject] - except LookupError: - p = sp[subject] = {} - p[predicate] = 1 - - def remove( - self, - triple_pattern: _TriplePatternType, - context: Optional[_ContextType] = None, - ) -> None: - req_ctx = self.__ctx_to_str(context) - for triple, c in self.triples(triple_pattern, context=context): - subject, predicate, object_ = triple - for ctx in self.__get_context_for_triple(triple): - if context is not None and req_ctx != ctx: - continue - self.__remove_triple_context(triple, ctx) - ctxs = self.__get_context_for_triple(triple, skipQuoted=True) - if None in ctxs and (context is None or len(ctxs) == 1): - # remove from default graph too - self.__remove_triple_context(triple, None) - if len(self.__get_context_for_triple(triple)) == 0: - del self.__spo[subject][predicate][object_] - del self.__pos[predicate][object_][subject] - del self.__osp[object_][subject][predicate] - del self.__tripleContexts[triple] - if ( - req_ctx is not None - and req_ctx in self.__contextTriples - and len(self.__contextTriples[req_ctx]) == 0 - ): - # all triples are removed out of this context - # and it's not the default context so delete it - del self.__contextTriples[req_ctx] - - if ( - triple_pattern == (None, None, None) - and context in self.__all_contexts - and not self.graph_aware - ): - # remove the whole context - self.__all_contexts.remove(context) - - def triples( - self, - triple_pattern: _TriplePatternType, - context: Optional[_ContextType] = None, - ) -> Generator[ - Tuple[_TripleType, Generator[Optional[_ContextType], None, None]], - None, - None, - ]: - """A generator over all the triples matching""" - req_ctx = self.__ctx_to_str(context) - subject, predicate, object_ = triple_pattern - - # all triples case (no triple parts given as pattern) - if subject is None and predicate is None and object_ is None: - # Just dump all known triples from the given graph - if req_ctx not in self.__contextTriples: - return - for triple in self.__contextTriples[req_ctx].copy(): - yield triple, self.__contexts(triple) - - # optimize "triple in graph" case (all parts given) - elif subject is not None and predicate is not None and object_ is not None: - # type error: Incompatible types in assignment (expression has type "Tuple[Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Identifier]]", variable has type "Tuple[IdentifiedNode, IdentifiedNode, Identifier]") - # NOTE on type error: at this point, all elements of triple_pattern - # is not None, so it has the same type as triple - triple = triple_pattern # type: ignore[assignment] - try: - _ = self.__spo[subject][predicate][object_] - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - except KeyError: - return - - elif subject is not None: # subject is given - spo = self.__spo - if subject in spo: - subjectDictionary = spo[subject] # noqa: N806 - if predicate is not None: # subject+predicate is given - if predicate in subjectDictionary: - if object_ is not None: # subject+predicate+object is given - if object_ in subjectDictionary[predicate]: - triple = (subject, predicate, object_) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # given object not found - pass - else: # subject+predicate is given, object unbound - for o in list(subjectDictionary[predicate].keys()): - triple = (subject, predicate, o) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # given predicate not found - pass - else: # subject given, predicate unbound - for p in list(subjectDictionary.keys()): - if object_ is not None: # object is given - if object_ in subjectDictionary[p]: - triple = (subject, p, object_) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # given object not found - pass - else: # object unbound - for o in list(subjectDictionary[p].keys()): - triple = (subject, p, o) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # given subject not found - pass - elif predicate is not None: # predicate is given, subject unbound - pos = self.__pos - if predicate in pos: - predicateDictionary = pos[predicate] # noqa: N806 - if object_ is not None: # predicate+object is given, subject unbound - if object_ in predicateDictionary: - for s in list(predicateDictionary[object_].keys()): - triple = (s, predicate, object_) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # given object not found - pass - else: # predicate is given, object+subject unbound - for o in list(predicateDictionary.keys()): - for s in list(predicateDictionary[o].keys()): - triple = (s, predicate, o) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - elif object_ is not None: # object is given, subject+predicate unbound - osp = self.__osp - if object_ in osp: - objectDictionary = osp[object_] # noqa: N806 - for s in list(objectDictionary.keys()): - for p in list(objectDictionary[s].keys()): - triple = (s, p, object_) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - else: # subject+predicate+object unbound - # Shouldn't get here if all other cases above worked correctly. - spo = self.__spo - for s in list(spo.keys()): - subjectDictionary = spo[s] # noqa: N806 - for p in list(subjectDictionary.keys()): - for o in list(subjectDictionary[p].keys()): - triple = (s, p, o) - if self.__triple_has_context(triple, req_ctx): - yield triple, self.__contexts(triple) - - def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: - # should be identical to `SimpleMemory.bind` - bound_namespace = self.__namespace.get(prefix) - bound_prefix = _coalesce( - self.__prefix.get(namespace), - # type error: error: Argument 1 to "get" of "Mapping" has incompatible type "Optional[URIRef]"; expected "URIRef" - self.__prefix.get(bound_namespace), # type: ignore[arg-type] - ) - if override: - if bound_prefix is not None: - del self.__namespace[bound_prefix] - if bound_namespace is not None: - del self.__prefix[bound_namespace] - self.__prefix[namespace] = prefix - self.__namespace[prefix] = namespace - else: - # type error: Invalid index type "Optional[URIRef]" for "Dict[URIRef, str]"; expected type "URIRef" - self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce( # type: ignore[index] - bound_prefix, default=prefix - ) - # type error: Invalid index type "Optional[str]" for "Dict[str, URIRef]"; expected type "str" - # type error: Incompatible types in assignment (expression has type "Optional[URIRef]", target has type "URIRef") - self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce( # type: ignore[index] - bound_namespace, default=namespace - ) - - def namespace(self, prefix: str) -> Optional[URIRef]: - return self.__namespace.get(prefix, None) - - def prefix(self, namespace: URIRef) -> Optional[str]: - return self.__prefix.get(namespace, None) - - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: - for prefix, namespace in self.__namespace.items(): - yield prefix, namespace - - def contexts( - self, triple: Optional[_TripleType] = None - ) -> Generator[_ContextType, None, None]: - if triple is None or triple == (None, None, None): - return (context for context in self.__all_contexts) - - subj, pred, obj = triple - try: - _ = self.__spo[subj][pred][obj] - return self.__contexts(triple) - except KeyError: - return (_ for _ in []) - - def __len__(self, context: Optional[_ContextType] = None) -> int: - ctx = self.__ctx_to_str(context) - if ctx not in self.__contextTriples: - return 0 - return len(self.__contextTriples[ctx]) - - def add_graph(self, graph: Graph) -> None: - if not self.graph_aware: - Store.add_graph(self, graph) - else: - self.__all_contexts.add(graph) - - def remove_graph(self, graph: Graph) -> None: - if not self.graph_aware: - Store.remove_graph(self, graph) - else: - self.remove((None, None, None), graph) - try: - self.__all_contexts.remove(graph) - except KeyError: - pass # we didn't know this graph, no problem - - # internal utility methods below - def __add_triple_context( - self, - triple: _TripleType, - triple_exists: bool, - context: Optional[_ContextType], - quoted: bool, - ) -> None: - """add the given context to the set of contexts for the triple""" - ctx = self.__ctx_to_str(context) - quoted = bool(quoted) - if triple_exists: - # we know the triple exists somewhere in the store - try: - triple_context = self.__tripleContexts[triple] - except KeyError: - # triple exists with default ctx info - # start with a copy of the default ctx info - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "copy" - triple_context = self.__tripleContexts[triple] = ( - self.__defaultContexts.copy() # type: ignore[union-attr] - ) - - triple_context[ctx] = quoted - - if not quoted: - triple_context[None] = quoted - - else: - # the triple didn't exist before in the store - if quoted: # this context only - triple_context = self.__tripleContexts[triple] = {ctx: quoted} - else: # default context as well - triple_context = self.__tripleContexts[triple] = { - ctx: quoted, - None: quoted, - } - - # if the triple is not quoted add it to the default context - if not quoted: - self.__contextTriples[None].add(triple) - - # always add the triple to given context, making sure it's initialized - if ctx not in self.__contextTriples: - self.__contextTriples[ctx] = set() - self.__contextTriples[ctx].add(triple) - - # if this is the first ever triple in the store, set default ctx info - if self.__defaultContexts is None: - self.__defaultContexts = triple_context - # if the context info is the same as default, no need to store it - if triple_context == self.__defaultContexts: - del self.__tripleContexts[triple] - - def __get_context_for_triple( - self, triple: _TripleType, skipQuoted: bool = False # noqa: N803 - ) -> Collection[Optional[str]]: - """return a list of contexts (str) for the triple, skipping - quoted contexts if skipQuoted==True""" - - ctxs = self.__tripleContexts.get(triple, self.__defaultContexts) - - if not skipQuoted: - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "keys" - return ctxs.keys() # type: ignore[union-attr] - - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "items" - return [ctx for ctx, quoted in ctxs.items() if not quoted] # type: ignore[union-attr] - - def __triple_has_context(self, triple: _TripleType, ctx: Optional[str]) -> bool: - """return True if the triple exists in the given context""" - # type error: Unsupported right operand type for in ("Optional[Dict[Optional[str], bool]]") - return ctx in self.__tripleContexts.get(triple, self.__defaultContexts) # type: ignore[operator] - - def __remove_triple_context(self, triple: _TripleType, ctx): - """remove the context from the triple""" - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "copy" - ctxs = self.__tripleContexts.get(triple, self.__defaultContexts).copy() # type: ignore[union-attr] - del ctxs[ctx] - if ctxs == self.__defaultContexts: - del self.__tripleContexts[triple] - else: - self.__tripleContexts[triple] = ctxs - self.__contextTriples[ctx].remove(triple) - - @overload - def __ctx_to_str(self, ctx: _ContextType) -> str: ... - - @overload - def __ctx_to_str(self, ctx: None) -> None: ... - - def __ctx_to_str(self, ctx: Optional[_ContextType]) -> Optional[str]: - if ctx is None: - return None - try: - # ctx could be a graph. In that case, use its identifier - ctx_str = "{}:{}".format(ctx.identifier.__class__.__name__, ctx.identifier) - self.__context_obj_map[ctx_str] = ctx - return ctx_str - except AttributeError: - # otherwise, ctx should be a URIRef or BNode or str - # NOTE on type errors: This is actually never called with ctx value as str in all unit tests, so this seems like it should just not be here. - # type error: Subclass of "Graph" and "str" cannot exist: would have incompatible method signatures - if isinstance(ctx, str): # type: ignore[unreachable] - # type error: Statement is unreachable - ctx_str = "{}:{}".format(ctx.__class__.__name__, ctx) # type: ignore[unreachable] - if ctx_str in self.__context_obj_map: - return ctx_str - self.__context_obj_map[ctx_str] = ctx - return ctx_str - raise RuntimeError("Cannot use that type of object as a Graph context") - - def __contexts(self, triple: _TripleType) -> Generator[_ContextType, None, None]: - """return a generator for all the non-quoted contexts - (dereferenced) the encoded triple appears in""" - # type error: Argument 2 to "get" of "Mapping" has incompatible type "str"; expected "Optional[Graph]" - return ( - self.__context_obj_map.get(ctx_str, ctx_str) # type: ignore[arg-type] - for ctx_str in self.__get_context_for_triple(triple, skipQuoted=True) - if ctx_str is not None - ) - - # type error: Missing return statement - def query( # type: ignore[return] - self, - query: Union[Query, str], - initNs: Mapping[str, Any], # noqa: N803 - initBindings: Mapping[str, Identifier], # noqa: N803 - queryGraph: str, # noqa: N803 - **kwargs, - ) -> Result: - super(Memory, self).query(query, initNs, initBindings, queryGraph, **kwargs) - - def update( - self, - update: Union[Update, Any], - initNs: Mapping[str, Any], # noqa: N803 - initBindings: Mapping[str, Identifier], # noqa: N803 - queryGraph: str, # noqa: N803 - **kwargs, - ) -> None: - super(Memory, self).update(update, initNs, initBindings, queryGraph, **kwargs) diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/regexmatching.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/regexmatching.py deleted file mode 100644 index 9dc3da2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/regexmatching.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -This wrapper intercepts calls through the store interface which make use of -the REGEXTerm class to represent matches by REGEX instead of literal -comparison. - -Implemented for stores that don't support this and essentially -provides the support by replacing the REGEXTerms by wildcards (None) and -matching against the results from the store it's wrapping. -""" - -import re - -from rdflib.graph import Graph -from rdflib.store import Store - -# Store is capable of doing its own REGEX matching -NATIVE_REGEX = 0 -# Store uses Python's re module internally for REGEX matching -PYTHON_REGEX = 1 - - -class REGEXTerm(str): - """ - REGEXTerm can be used in any term slot and is interpreted as a request to - perform a REGEX match (not a string comparison) using the value - (pre-compiled) for checking rdf:type matches - """ - - def __init__(self, expr): - self.compiledExpr = re.compile(expr) - - def __reduce__(self): - return (REGEXTerm, ("",)) - - -def regexCompareQuad(quad, regexQuad): # noqa: N802, N803 - for index in range(4): - if isinstance(regexQuad[index], REGEXTerm) and not regexQuad[ - index - ].compiledExpr.match(quad[index]): - return False - return True - - -class REGEXMatching(Store): - def __init__(self, storage): - self.storage = storage - self.context_aware = storage.context_aware - # NOTE: this store can't be formula_aware as it doesn't have enough - # info to reverse the removal of a quoted statement. - self.formula_aware = storage.formula_aware - self.transaction_aware = storage.transaction_aware - - def open(self, configuration, create=True): - return self.storage.open(configuration, create) - - def close(self, commit_pending_transaction=False): - self.storage.close() - - def destroy(self, configuration): - self.storage.destroy(configuration) - - def add(self, triple, context, quoted=False): - (subject, predicate, object_) = triple - self.storage.add((subject, predicate, object_), context, quoted) - - def remove(self, triple, context=None): - (subject, predicate, object_) = triple - if ( - isinstance(subject, REGEXTerm) - or isinstance(predicate, REGEXTerm) - or isinstance(object_, REGEXTerm) - or (context is not None and isinstance(context.identifier, REGEXTerm)) - ): - # One or more of the terms is a REGEX expression, so we must - # replace it / them with wildcard(s)and match after we query. - s = not isinstance(subject, REGEXTerm) and subject or None - p = not isinstance(predicate, REGEXTerm) and predicate or None - o = not isinstance(object_, REGEXTerm) and object_ or None - c = ( - (context is not None and not isinstance(context.identifier, REGEXTerm)) - and context - or None - ) - - removeQuadList = [] # noqa: N806 - for (s1, p1, o1), cg in self.storage.triples((s, p, o), c): - for ctx in cg: - ctx = ctx.identifier - if regexCompareQuad( - (s1, p1, o1, ctx), - ( - subject, - predicate, - object_, - context is not None and context.identifier or context, - ), - ): - removeQuadList.append((s1, p1, o1, ctx)) - for s, p, o, c in removeQuadList: - self.storage.remove((s, p, o), c and Graph(self, c) or c) - else: - self.storage.remove((subject, predicate, object_), context) - - def triples(self, triple, context=None): - (subject, predicate, object_) = triple - if ( - isinstance(subject, REGEXTerm) - or isinstance(predicate, REGEXTerm) - or isinstance(object_, REGEXTerm) - or (context is not None and isinstance(context.identifier, REGEXTerm)) - ): - # One or more of the terms is a REGEX expression, so we must - # replace it / them with wildcard(s) and match after we query. - s = not isinstance(subject, REGEXTerm) and subject or None - p = not isinstance(predicate, REGEXTerm) and predicate or None - o = not isinstance(object_, REGEXTerm) and object_ or None - c = ( - (context is not None and not isinstance(context.identifier, REGEXTerm)) - and context - or None - ) - for (s1, p1, o1), cg in self.storage.triples((s, p, o), c): - matchingCtxs = [] # noqa: N806 - for ctx in cg: - if c is None: - if context is None or context.identifier.compiledExpr.match( - ctx.identifier - ): - matchingCtxs.append(ctx) - else: - matchingCtxs.append(ctx) - if matchingCtxs and regexCompareQuad( - (s1, p1, o1, None), (subject, predicate, object_, None) - ): - yield (s1, p1, o1), (c for c in matchingCtxs) - else: - for (s1, p1, o1), cg in self.storage.triples( - (subject, predicate, object_), context - ): - yield (s1, p1, o1), cg - - def __len__(self, context=None): - # NOTE: If the context is a REGEX this could be an expensive - # proposition - return self.storage.__len__(context) - - def contexts(self, triple=None): - # NOTE: There is no way to control REGEX matching for this method at - # this level as it only returns the contexts, not the matching - # triples. - for ctx in self.storage.contexts(triple): - yield ctx - - def remove_context(self, identifier): - self.storage.remove((None, None, None), identifier) - - def bind(self, prefix, namespace, override=True): - self.storage.bind(prefix, namespace, override=override) - - def prefix(self, namespace): - return self.storage.prefix(namespace) - - def namespace(self, prefix): - return self.storage.namespace(prefix) - - def namespaces(self): - return self.storage.namespaces() - - def commit(self): - self.storage.commit() - - def rollback(self): - self.storage.rollback() diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlconnector.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlconnector.py deleted file mode 100644 index e2bb839..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlconnector.py +++ /dev/null @@ -1,192 +0,0 @@ -from __future__ import annotations - -import base64 -import copy -import logging -from io import BytesIO -from typing import TYPE_CHECKING, Optional, Tuple -from urllib.error import HTTPError -from urllib.parse import urlencode -from urllib.request import Request, urlopen - -from rdflib.query import Result -from rdflib.term import BNode - -log = logging.getLogger(__name__) - -if TYPE_CHECKING: - import typing_extensions as te - - -class SPARQLConnectorException(Exception): # noqa: N818 - pass - - -# TODO: Pull in these from the result implementation plugins? -_response_mime_types = { - "xml": "application/sparql-results+xml, application/rdf+xml", - "json": "application/sparql-results+json", - "csv": "text/csv", - "tsv": "text/tab-separated-values", - "application/rdf+xml": "application/rdf+xml", -} - - -class SPARQLConnector: - """ - this class deals with nitty gritty details of talking to a SPARQL server - """ - - def __init__( - self, - query_endpoint: Optional[str] = None, - update_endpoint: Optional[str] = None, - returnFormat: str = "xml", # noqa: N803 - method: te.Literal["GET", "POST", "POST_FORM"] = "GET", - auth: Optional[Tuple[str, str]] = None, - **kwargs, - ): - """ - auth, if present, must be a tuple of (username, password) used for Basic Authentication - - Any additional keyword arguments will be passed to to the request, and can be used to setup timeouts etc. - """ - self._method: str - self.returnFormat = returnFormat - self.query_endpoint = query_endpoint - self.update_endpoint = update_endpoint - self.kwargs = kwargs - self.method = method - if auth is not None: - if type(auth) is not tuple: - raise SPARQLConnectorException("auth must be a tuple") - if len(auth) != 2: - raise SPARQLConnectorException("auth must be a tuple (user, password)") - base64string = base64.b64encode(bytes("%s:%s" % auth, "ascii")) - self.kwargs.setdefault("headers", {}) - self.kwargs["headers"].update( - {"Authorization": "Basic %s" % base64string.decode("utf-8")} - ) - - @property - def method(self) -> str: - return self._method - - @method.setter - def method(self, method: str) -> None: - if method not in ("GET", "POST", "POST_FORM"): - raise SPARQLConnectorException( - 'Method must be "GET", "POST", or "POST_FORM"' - ) - - self._method = method - - def query( - self, - query: str, - default_graph: Optional[str] = None, - named_graph: Optional[str] = None, - ) -> Result: - if not self.query_endpoint: - raise SPARQLConnectorException("Query endpoint not set!") - - params = {} - # this test ensures we don't have a useless (BNode) default graph URI, which calls to Graph().query() will add - if default_graph is not None and type(default_graph) is not BNode: - params["default-graph-uri"] = default_graph - - headers = {"Accept": _response_mime_types[self.returnFormat]} - - args = copy.deepcopy(self.kwargs) - - # merge params/headers dicts - args.setdefault("params", {}) - - args.setdefault("headers", {}) - args["headers"].update(headers) - - if self.method == "GET": - params["query"] = query - args["params"].update(params) - qsa = "?" + urlencode(args["params"]) - try: - res = urlopen( - Request(self.query_endpoint + qsa, headers=args["headers"]) - ) - except Exception as e: # noqa: F841 - raise ValueError( - "You did something wrong formulating either the URI or your SPARQL query" - ) - elif self.method == "POST": - args["headers"].update({"Content-Type": "application/sparql-query"}) - args["params"].update(params) - qsa = "?" + urlencode(args["params"]) - try: - res = urlopen( - Request( - self.query_endpoint + qsa, - data=query.encode(), - headers=args["headers"], - ) - ) - except HTTPError as e: - # type error: Incompatible return value type (got "Tuple[int, str, None]", expected "Result") - return e.code, str(e), None # type: ignore[return-value] - elif self.method == "POST_FORM": - params["query"] = query - args["params"].update(params) - try: - res = urlopen( - Request( - self.query_endpoint, - data=urlencode(args["params"]).encode(), - headers=args["headers"], - ) - ) - except HTTPError as e: - # type error: Incompatible return value type (got "Tuple[int, str, None]", expected "Result") - return e.code, str(e), None # type: ignore[return-value] - else: - raise SPARQLConnectorException("Unknown method %s" % self.method) - return Result.parse( - BytesIO(res.read()), content_type=res.headers["Content-Type"].split(";")[0] - ) - - def update( - self, - query: str, - default_graph: Optional[str] = None, - named_graph: Optional[str] = None, - ) -> None: - if not self.update_endpoint: - raise SPARQLConnectorException("Query endpoint not set!") - - params = {} - - if default_graph is not None: - params["using-graph-uri"] = default_graph - - if named_graph is not None: - params["using-named-graph-uri"] = named_graph - - headers = { - "Accept": _response_mime_types[self.returnFormat], - "Content-Type": "application/sparql-update; charset=UTF-8", - } - - args = copy.deepcopy(self.kwargs) # other QSAs - - args.setdefault("params", {}) - args["params"].update(params) - args.setdefault("headers", {}) - args["headers"].update(headers) - - qsa = "?" + urlencode(args["params"]) - res = urlopen( # noqa: F841 - Request( - self.update_endpoint + qsa, data=query.encode(), headers=args["headers"] - ) - ) - - -__all__ = ["SPARQLConnector", "SPARQLConnectorException"] diff --git a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlstore.py b/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlstore.py deleted file mode 100644 index f9827cf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rdflib/plugins/stores/sparqlstore.py +++ /dev/null @@ -1,999 +0,0 @@ -""" -This is an RDFLib store around Ivan Herman et al.'s SPARQL service wrapper. -This was first done in layer-cake, and then ported to RDFLib - -""" - -from __future__ import annotations - -import collections -import re -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Generator, - Iterable, - Iterator, - List, - Mapping, - Optional, - Tuple, - Union, - overload, -) - -from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, Graph -from rdflib.plugins.stores.regexmatching import NATIVE_REGEX -from rdflib.store import Store -from rdflib.term import BNode, Identifier, Node, URIRef, Variable - -if TYPE_CHECKING: - import typing_extensions as te # noqa: I001 - from rdflib.graph import ( - _TripleType, - _ContextType, - _QuadType, - _TriplePatternType, - _SubjectType, - _PredicateType, - _ObjectType, - _ContextIdentifierType, - ) - from rdflib.plugins.sparql.sparql import Query, Update - from rdflib.query import Result, ResultRow - -from .sparqlconnector import SPARQLConnector - -# Defines some SPARQL keywords -LIMIT = "LIMIT" -OFFSET = "OFFSET" -ORDERBY = "ORDER BY" - -BNODE_IDENT_PATTERN = re.compile(r"(?Px)', r'\g\g', 'xx'), 'xxxx') - self.assertEqual(regex.sub('(?Px)', r'\g\g<1>', 'xx'), 'xxxx') - self.assertEqual(regex.sub('(?Px)', r'\g\g', 'xx'), - 'xxxx') - self.assertEqual(regex.sub('(?Px)', r'\g<1>\g<1>', 'xx'), 'xxxx') - - self.assertEqual(regex.sub('a', r'\t\n\v\r\f\a\b', 'a'), "\t\n\v\r\f\a\b") - self.assertEqual(regex.sub('a', '\t\n\v\r\f\a', 'a'), "\t\n\v\r\f\a") - self.assertEqual(regex.sub('a', '\t\n\v\r\f\a', 'a'), chr(9) + chr(10) - + chr(11) + chr(13) + chr(12) + chr(7)) - - self.assertEqual(regex.sub(r'^\s*', 'X', 'test'), 'Xtest') - - self.assertEqual(regex.sub(r"x", r"\x0A", "x"), "\n") - self.assertEqual(regex.sub(r"x", r"\u000A", "x"), "\n") - self.assertEqual(regex.sub(r"x", r"\U0000000A", "x"), "\n") - self.assertEqual(regex.sub(r"x", r"\N{LATIN CAPITAL LETTER A}", - "x"), "A") - - self.assertEqual(regex.sub(br"x", br"\x0A", b"x"), b"\n") - - def test_bug_449964(self): - # Fails for group followed by other escape. - self.assertEqual(regex.sub(r'(?Px)', r'\g<1>\g<1>\b', 'xx'), - "xx\bxx\b") - - def test_bug_449000(self): - # Test for sub() on escaped characters. - self.assertEqual(regex.sub(r'\r\n', r'\n', 'abc\r\ndef\r\n'), - "abc\ndef\n") - self.assertEqual(regex.sub('\r\n', r'\n', 'abc\r\ndef\r\n'), - "abc\ndef\n") - self.assertEqual(regex.sub(r'\r\n', '\n', 'abc\r\ndef\r\n'), - "abc\ndef\n") - self.assertEqual(regex.sub('\r\n', '\n', 'abc\r\ndef\r\n'), - "abc\ndef\n") - - def test_bug_1661(self): - # Verify that flags do not get silently ignored with compiled patterns - pattern = regex.compile('.') - self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT, - lambda: regex.match(pattern, 'A', regex.I)) - self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT, - lambda: regex.search(pattern, 'A', regex.I)) - self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT, - lambda: regex.findall(pattern, 'A', regex.I)) - self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT, - lambda: regex.compile(pattern, regex.I)) - - def test_bug_3629(self): - # A regex that triggered a bug in the sre-code validator - self.assertEqual(repr(type(regex.compile("(?P)(?(quote))"))), - self.PATTERN_CLASS) - - def test_sub_template_numeric_escape(self): - # Bug 776311 and friends. - self.assertEqual(regex.sub('x', r'\0', 'x'), "\0") - self.assertEqual(regex.sub('x', r'\000', 'x'), "\000") - self.assertEqual(regex.sub('x', r'\001', 'x'), "\001") - self.assertEqual(regex.sub('x', r'\008', 'x'), "\0" + "8") - self.assertEqual(regex.sub('x', r'\009', 'x'), "\0" + "9") - self.assertEqual(regex.sub('x', r'\111', 'x'), "\111") - self.assertEqual(regex.sub('x', r'\117', 'x'), "\117") - - self.assertEqual(regex.sub('x', r'\1111', 'x'), "\1111") - self.assertEqual(regex.sub('x', r'\1111', 'x'), "\111" + "1") - - self.assertEqual(regex.sub('x', r'\00', 'x'), '\x00') - self.assertEqual(regex.sub('x', r'\07', 'x'), '\x07') - self.assertEqual(regex.sub('x', r'\08', 'x'), "\0" + "8") - self.assertEqual(regex.sub('x', r'\09', 'x'), "\0" + "9") - self.assertEqual(regex.sub('x', r'\0a', 'x'), "\0" + "a") - - self.assertEqual(regex.sub('x', r'\400', 'x'), "\u0100") - self.assertEqual(regex.sub('x', r'\777', 'x'), "\u01FF") - self.assertEqual(regex.sub(b'x', br'\400', b'x'), b"\x00") - self.assertEqual(regex.sub(b'x', br'\777', b'x'), b"\xFF") - - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\1', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\8', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\9', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\11', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\18', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\1a', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\90', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\99', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\118', 'x')) # r'\11' + '8' - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\11a', 'x')) - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\181', 'x')) # r'\18' + '1' - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.sub('x', r'\800', 'x')) # r'\80' + '0' - - # In Python 2.3 (etc), these loop endlessly in sre_parser.py. - self.assertEqual(regex.sub('(((((((((((x)))))))))))', r'\11', 'x'), - 'x') - self.assertEqual(regex.sub('((((((((((y))))))))))(.)', r'\118', 'xyz'), - 'xz8') - self.assertEqual(regex.sub('((((((((((y))))))))))(.)', r'\11a', 'xyz'), - 'xza') - - def test_qualified_re_sub(self): - self.assertEqual(regex.sub('a', 'b', 'aaaaa'), 'bbbbb') - self.assertEqual(regex.sub('a', 'b', 'aaaaa', 1), 'baaaa') - - def test_bug_114660(self): - self.assertEqual(regex.sub(r'(\S)\s+(\S)', r'\1 \2', 'hello there'), - 'hello there') - - def test_bug_462270(self): - # Test for empty sub() behaviour, see SF bug #462270 - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.sub('(?V0)x*', '-', 'abxd'), '-a-b--d-') - else: - self.assertEqual(regex.sub('(?V0)x*', '-', 'abxd'), '-a-b-d-') - self.assertEqual(regex.sub('(?V1)x*', '-', 'abxd'), '-a-b--d-') - self.assertEqual(regex.sub('x+', '-', 'abxd'), 'ab-d') - - def test_bug_14462(self): - # chr(255) is a valid identifier in Python 3. - group_name = '\xFF' - self.assertEqual(regex.search(r'(?P<' + group_name + '>a)', - 'abc').group(group_name), 'a') - - def test_symbolic_refs(self): - self.assertRaisesRegex(regex.error, self.MISSING_GT, lambda: - regex.sub('(?Px)', r'\gx)', r'\g<', 'xx')) - self.assertRaisesRegex(regex.error, self.MISSING_LT, lambda: - regex.sub('(?Px)', r'\g', 'xx')) - self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: - regex.sub('(?Px)', r'\g', 'xx')) - self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: - regex.sub('(?Px)', r'\g<1a1>', 'xx')) - self.assertRaisesRegex(IndexError, self.UNKNOWN_GROUP_I, lambda: - regex.sub('(?Px)', r'\g', 'xx')) - - # The new behaviour of unmatched but valid groups is to treat them like - # empty matches in the replacement template, like in Perl. - self.assertEqual(regex.sub('(?Px)|(?Py)', r'\g', 'xx'), '') - self.assertEqual(regex.sub('(?Px)|(?Py)', r'\2', 'xx'), '') - - # The old behaviour was to raise it as an IndexError. - self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: - regex.sub('(?Px)', r'\g<-1>', 'xx')) - - def test_re_subn(self): - self.assertEqual(regex.subn("(?i)b+", "x", "bbbb BBBB"), ('x x', 2)) - self.assertEqual(regex.subn("b+", "x", "bbbb BBBB"), ('x BBBB', 1)) - self.assertEqual(regex.subn("b+", "x", "xyz"), ('xyz', 0)) - self.assertEqual(regex.subn("b*", "x", "xyz"), ('xxxyxzx', 4)) - self.assertEqual(regex.subn("b*", "x", "xyz", 2), ('xxxyz', 2)) - - def test_re_split(self): - self.assertEqual(regex.split(":", ":a:b::c"), ['', 'a', 'b', '', 'c']) - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split(":*", ":a:b::c"), ['', '', 'a', '', - 'b', '', 'c', '']) - self.assertEqual(regex.split("(:*)", ":a:b::c"), ['', ':', '', '', - 'a', ':', '', '', 'b', '::', '', '', 'c', '', '']) - self.assertEqual(regex.split("(?::*)", ":a:b::c"), ['', '', 'a', - '', 'b', '', 'c', '']) - self.assertEqual(regex.split("(:)*", ":a:b::c"), ['', ':', '', - None, 'a', ':', '', None, 'b', ':', '', None, 'c', None, '']) - else: - self.assertEqual(regex.split(":*", ":a:b::c"), ['', 'a', 'b', 'c']) - self.assertEqual(regex.split("(:*)", ":a:b::c"), ['', ':', 'a', - ':', 'b', '::', 'c']) - self.assertEqual(regex.split("(?::*)", ":a:b::c"), ['', 'a', 'b', - 'c']) - self.assertEqual(regex.split("(:)*", ":a:b::c"), ['', ':', 'a', - ':', 'b', ':', 'c']) - self.assertEqual(regex.split("([b:]+)", ":a:b::c"), ['', ':', 'a', - ':b::', 'c']) - self.assertEqual(regex.split("(b)|(:+)", ":a:b::c"), ['', None, ':', - 'a', None, ':', '', 'b', None, '', None, '::', 'c']) - self.assertEqual(regex.split("(?:b)|(?::+)", ":a:b::c"), ['', 'a', '', - '', 'c']) - - self.assertEqual(regex.split("x", "xaxbxc"), ['', 'a', 'b', 'c']) - self.assertEqual([m for m in regex.splititer("x", "xaxbxc")], ['', 'a', - 'b', 'c']) - - self.assertEqual(regex.split("(?r)x", "xaxbxc"), ['c', 'b', 'a', '']) - self.assertEqual([m for m in regex.splititer("(?r)x", "xaxbxc")], ['c', - 'b', 'a', '']) - - self.assertEqual(regex.split("(x)|(y)", "xaxbxc"), ['', 'x', None, 'a', - 'x', None, 'b', 'x', None, 'c']) - self.assertEqual([m for m in regex.splititer("(x)|(y)", "xaxbxc")], - ['', 'x', None, 'a', 'x', None, 'b', 'x', None, 'c']) - - self.assertEqual(regex.split("(?r)(x)|(y)", "xaxbxc"), ['c', 'x', None, - 'b', 'x', None, 'a', 'x', None, '']) - self.assertEqual([m for m in regex.splititer("(?r)(x)|(y)", "xaxbxc")], - ['c', 'x', None, 'b', 'x', None, 'a', 'x', None, '']) - - self.assertEqual(regex.split(r"(?V1)\b", "a b c"), ['', 'a', ' ', 'b', - ' ', 'c', '']) - self.assertEqual(regex.split(r"(?V1)\m", "a b c"), ['', 'a ', 'b ', - 'c']) - self.assertEqual(regex.split(r"(?V1)\M", "a b c"), ['a', ' b', ' c', - '']) - - def test_qualified_re_split(self): - self.assertEqual(regex.split(":", ":a:b::c", 2), ['', 'a', 'b::c']) - self.assertEqual(regex.split(':', 'a:b:c:d', 2), ['a', 'b', 'c:d']) - self.assertEqual(regex.split("(:)", ":a:b::c", 2), ['', ':', 'a', ':', - 'b::c']) - - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split("(:*)", ":a:b::c", 2), ['', ':', '', - '', 'a:b::c']) - else: - self.assertEqual(regex.split("(:*)", ":a:b::c", 2), ['', ':', 'a', - ':', 'b::c']) - - def test_re_findall(self): - self.assertEqual(regex.findall(":+", "abc"), []) - self.assertEqual(regex.findall(":+", "a:b::c:::d"), [':', '::', ':::']) - self.assertEqual(regex.findall("(:+)", "a:b::c:::d"), [':', '::', - ':::']) - self.assertEqual(regex.findall("(:)(:*)", "a:b::c:::d"), [(':', ''), - (':', ':'), (':', '::')]) - - self.assertEqual(regex.findall(r"\((?P.{0,5}?TEST)\)", - "(MY TEST)"), ["MY TEST"]) - self.assertEqual(regex.findall(r"\((?P.{0,3}?TEST)\)", - "(MY TEST)"), ["MY TEST"]) - self.assertEqual(regex.findall(r"\((?P.{0,3}?T)\)", "(MY T)"), - ["MY T"]) - - self.assertEqual(regex.findall(r"[^a]{2}[A-Z]", "\n S"), [' S']) - self.assertEqual(regex.findall(r"[^a]{2,3}[A-Z]", "\n S"), ['\n S']) - self.assertEqual(regex.findall(r"[^a]{2,3}[A-Z]", "\n S"), [' S']) - - self.assertEqual(regex.findall(r"X(Y[^Y]+?){1,2}( |Q)+DEF", - "XYABCYPPQ\nQ DEF"), [('YPPQ\n', ' ')]) - - self.assertEqual(regex.findall(r"(\nTest(\n+.+?){0,2}?)?\n+End", - "\nTest\nxyz\nxyz\nEnd"), [('\nTest\nxyz\nxyz', '\nxyz')]) - - def test_bug_117612(self): - self.assertEqual(regex.findall(r"(a|(b))", "aba"), [('a', ''), ('b', - 'b'), ('a', '')]) - - def test_re_match(self): - self.assertEqual(regex.match('a', 'a')[:], ('a',)) - self.assertEqual(regex.match('(a)', 'a')[:], ('a', 'a')) - self.assertEqual(regex.match(r'(a)', 'a')[0], 'a') - self.assertEqual(regex.match(r'(a)', 'a')[1], 'a') - self.assertEqual(regex.match(r'(a)', 'a').group(1, 1), ('a', 'a')) - - pat = regex.compile('((a)|(b))(c)?') - self.assertEqual(pat.match('a')[:], ('a', 'a', 'a', None, None)) - self.assertEqual(pat.match('b')[:], ('b', 'b', None, 'b', None)) - self.assertEqual(pat.match('ac')[:], ('ac', 'a', 'a', None, 'c')) - self.assertEqual(pat.match('bc')[:], ('bc', 'b', None, 'b', 'c')) - self.assertEqual(pat.match('bc')[:], ('bc', 'b', None, 'b', 'c')) - - # A single group. - m = regex.match('(a)', 'a') - self.assertEqual(m.group(), 'a') - self.assertEqual(m.group(0), 'a') - self.assertEqual(m.group(1), 'a') - self.assertEqual(m.group(1, 1), ('a', 'a')) - - pat = regex.compile('(?:(?Pa)|(?Pb))(?Pc)?') - self.assertEqual(pat.match('a').group(1, 2, 3), ('a', None, None)) - self.assertEqual(pat.match('b').group('a1', 'b2', 'c3'), (None, 'b', - None)) - self.assertEqual(pat.match('ac').group(1, 'b2', 3), ('a', None, 'c')) - - def test_re_groupref_exists(self): - self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', '(a)')[:], - ('(a)', '(', 'a')) - self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', 'a')[:], ('a', - None, 'a')) - self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', 'a)'), None) - self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', '(a'), None) - self.assertEqual(regex.match('^(?:(a)|c)((?(1)b|d))$', 'ab')[:], ('ab', - 'a', 'b')) - self.assertEqual(regex.match('^(?:(a)|c)((?(1)b|d))$', 'cd')[:], ('cd', - None, 'd')) - self.assertEqual(regex.match('^(?:(a)|c)((?(1)|d))$', 'cd')[:], ('cd', - None, 'd')) - self.assertEqual(regex.match('^(?:(a)|c)((?(1)|d))$', 'a')[:], ('a', - 'a', '')) - - # Tests for bug #1177831: exercise groups other than the first group. - p = regex.compile('(?Pa)(?Pb)?((?(g2)c|d))') - self.assertEqual(p.match('abc')[:], ('abc', 'a', 'b', 'c')) - self.assertEqual(p.match('ad')[:], ('ad', 'a', None, 'd')) - self.assertEqual(p.match('abd'), None) - self.assertEqual(p.match('ac'), None) - - def test_re_groupref(self): - self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', '|a|')[:], ('|a|', - '|', 'a')) - self.assertEqual(regex.match(r'^(\|)?([^()]+)\1?$', 'a')[:], ('a', - None, 'a')) - self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', 'a|'), None) - self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', '|a'), None) - self.assertEqual(regex.match(r'^(?:(a)|c)(\1)$', 'aa')[:], ('aa', 'a', - 'a')) - self.assertEqual(regex.match(r'^(?:(a)|c)(\1)?$', 'c')[:], ('c', None, - None)) - - self.assertEqual(regex.findall(r"(?i)(.{1,40}?),(.{1,40}?)(?:;)+(.{1,80}).{1,40}?\3(\ |;)+(.{1,80}?)\1", - "TEST, BEST; LEST ; Lest 123 Test, Best"), [('TEST', ' BEST', - ' LEST', ' ', '123 ')]) - - def test_groupdict(self): - self.assertEqual(regex.match('(?Pfirst) (?Psecond)', - 'first second').groupdict(), {'first': 'first', 'second': 'second'}) - - def test_expand(self): - self.assertEqual(regex.match("(?Pfirst) (?Psecond)", - "first second").expand(r"\2 \1 \g \g"), - 'second first second first') - - def test_repeat_minmax(self): - self.assertEqual(regex.match(r"^(\w){1}$", "abc"), None) - self.assertEqual(regex.match(r"^(\w){1}?$", "abc"), None) - self.assertEqual(regex.match(r"^(\w){1,2}$", "abc"), None) - self.assertEqual(regex.match(r"^(\w){1,2}?$", "abc"), None) - - self.assertEqual(regex.match(r"^(\w){3}$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){1,3}$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){1,4}$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){3,4}?$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){3}?$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){1,3}?$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){1,4}?$", "abc")[1], 'c') - self.assertEqual(regex.match(r"^(\w){3,4}?$", "abc")[1], 'c') - - self.assertEqual(regex.match("^x{1}$", "xxx"), None) - self.assertEqual(regex.match("^x{1}?$", "xxx"), None) - self.assertEqual(regex.match("^x{1,2}$", "xxx"), None) - self.assertEqual(regex.match("^x{1,2}?$", "xxx"), None) - - self.assertEqual(regex.match("^x{1}", "xxx")[0], 'x') - self.assertEqual(regex.match("^x{1}?", "xxx")[0], 'x') - self.assertEqual(regex.match("^x{0,1}", "xxx")[0], 'x') - self.assertEqual(regex.match("^x{0,1}?", "xxx")[0], '') - - self.assertEqual(bool(regex.match("^x{3}$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{1,3}$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{1,4}$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{3,4}?$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{3}?$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{1,3}?$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{1,4}?$", "xxx")), True) - self.assertEqual(bool(regex.match("^x{3,4}?$", "xxx")), True) - - self.assertEqual(regex.match("^x{}$", "xxx"), None) - self.assertEqual(bool(regex.match("^x{}$", "x{}")), True) - - def test_getattr(self): - self.assertEqual(regex.compile("(?i)(a)(b)").pattern, '(?i)(a)(b)') - self.assertEqual(regex.compile("(?i)(a)(b)").flags, regex.I | regex.U | - regex.DEFAULT_VERSION) - self.assertEqual(regex.compile(b"(?i)(a)(b)").flags, regex.A | regex.I - | regex.DEFAULT_VERSION) - self.assertEqual(regex.compile("(?i)(a)(b)").groups, 2) - self.assertEqual(regex.compile("(?i)(a)(b)").groupindex, {}) - - self.assertEqual(regex.compile("(?i)(?Pa)(?Pb)").groupindex, - {'first': 1, 'other': 2}) - - self.assertEqual(regex.match("(a)", "a").pos, 0) - self.assertEqual(regex.match("(a)", "a").endpos, 1) - - self.assertEqual(regex.search("b(c)", "abcdef").pos, 0) - self.assertEqual(regex.search("b(c)", "abcdef").endpos, 6) - self.assertEqual(regex.search("b(c)", "abcdef").span(), (1, 3)) - self.assertEqual(regex.search("b(c)", "abcdef").span(1), (2, 3)) - - self.assertEqual(regex.match("(a)", "a").string, 'a') - self.assertEqual(regex.match("(a)", "a").regs, ((0, 1), (0, 1))) - self.assertEqual(repr(type(regex.match("(a)", "a").re)), - self.PATTERN_CLASS) - - # Issue 14260. - p = regex.compile(r'abc(?Pdef)') - p.groupindex["n"] = 0 - self.assertEqual(p.groupindex["n"], 1) - - def test_special_escapes(self): - self.assertEqual(regex.search(r"\b(b.)\b", "abcd abc bcd bx")[1], 'bx') - self.assertEqual(regex.search(r"\B(b.)\B", "abc bcd bc abxd")[1], 'bx') - self.assertEqual(regex.search(br"\b(b.)\b", b"abcd abc bcd bx", - regex.LOCALE)[1], b'bx') - self.assertEqual(regex.search(br"\B(b.)\B", b"abc bcd bc abxd", - regex.LOCALE)[1], b'bx') - self.assertEqual(regex.search(r"\b(b.)\b", "abcd abc bcd bx", - regex.UNICODE)[1], 'bx') - self.assertEqual(regex.search(r"\B(b.)\B", "abc bcd bc abxd", - regex.UNICODE)[1], 'bx') - - self.assertEqual(regex.search(r"^abc$", "\nabc\n", regex.M)[0], 'abc') - self.assertEqual(regex.search(r"^\Aabc\Z$", "abc", regex.M)[0], 'abc') - self.assertEqual(regex.search(r"^\Aabc\Z$", "\nabc\n", regex.M), None) - - self.assertEqual(regex.search(br"\b(b.)\b", b"abcd abc bcd bx")[1], - b'bx') - self.assertEqual(regex.search(br"\B(b.)\B", b"abc bcd bc abxd")[1], - b'bx') - self.assertEqual(regex.search(br"^abc$", b"\nabc\n", regex.M)[0], - b'abc') - self.assertEqual(regex.search(br"^\Aabc\Z$", b"abc", regex.M)[0], - b'abc') - self.assertEqual(regex.search(br"^\Aabc\Z$", b"\nabc\n", regex.M), - None) - - self.assertEqual(regex.search(r"\d\D\w\W\s\S", "1aa! a")[0], '1aa! a') - self.assertEqual(regex.search(br"\d\D\w\W\s\S", b"1aa! a", - regex.LOCALE)[0], b'1aa! a') - self.assertEqual(regex.search(r"\d\D\w\W\s\S", "1aa! a", - regex.UNICODE)[0], '1aa! a') - - def test_bigcharset(self): - self.assertEqual(regex.match(r"([\u2222\u2223])", "\u2222")[1], - '\u2222') - self.assertEqual(regex.match(r"([\u2222\u2223])", "\u2222", - regex.UNICODE)[1], '\u2222') - self.assertEqual("".join(regex.findall(".", - "e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)), - 'e\xe8\xe9\xea\xeb\u0113\u011b\u0117') - self.assertEqual("".join(regex.findall(r"[e\xe8\xe9\xea\xeb\u0113\u011b\u0117]", - "e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)), - 'e\xe8\xe9\xea\xeb\u0113\u011b\u0117') - self.assertEqual("".join(regex.findall(r"e|\xe8|\xe9|\xea|\xeb|\u0113|\u011b|\u0117", - "e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)), - 'e\xe8\xe9\xea\xeb\u0113\u011b\u0117') - - def test_anyall(self): - self.assertEqual(regex.match("a.b", "a\nb", regex.DOTALL)[0], "a\nb") - self.assertEqual(regex.match("a.*b", "a\n\nb", regex.DOTALL)[0], - "a\n\nb") - - def test_non_consuming(self): - self.assertEqual(regex.match(r"(a(?=\s[^a]))", "a b")[1], 'a') - self.assertEqual(regex.match(r"(a(?=\s[^a]*))", "a b")[1], 'a') - self.assertEqual(regex.match(r"(a(?=\s[abc]))", "a b")[1], 'a') - self.assertEqual(regex.match(r"(a(?=\s[abc]*))", "a bc")[1], 'a') - self.assertEqual(regex.match(r"(a)(?=\s\1)", "a a")[1], 'a') - self.assertEqual(regex.match(r"(a)(?=\s\1*)", "a aa")[1], 'a') - self.assertEqual(regex.match(r"(a)(?=\s(abc|a))", "a a")[1], 'a') - - self.assertEqual(regex.match(r"(a(?!\s[^a]))", "a a")[1], 'a') - self.assertEqual(regex.match(r"(a(?!\s[abc]))", "a d")[1], 'a') - self.assertEqual(regex.match(r"(a)(?!\s\1)", "a b")[1], 'a') - self.assertEqual(regex.match(r"(a)(?!\s(abc|a))", "a b")[1], 'a') - - def test_ignore_case(self): - self.assertEqual(regex.match("abc", "ABC", regex.I)[0], 'ABC') - self.assertEqual(regex.match(b"abc", b"ABC", regex.I)[0], b'ABC') - - self.assertEqual(regex.match(r"(a\s[^a]*)", "a bb", regex.I)[1], - 'a bb') - self.assertEqual(regex.match(r"(a\s[abc])", "a b", regex.I)[1], 'a b') - self.assertEqual(regex.match(r"(a\s[abc]*)", "a bb", regex.I)[1], - 'a bb') - self.assertEqual(regex.match(r"((a)\s\2)", "a a", regex.I)[1], 'a a') - self.assertEqual(regex.match(r"((a)\s\2*)", "a aa", regex.I)[1], - 'a aa') - self.assertEqual(regex.match(r"((a)\s(abc|a))", "a a", regex.I)[1], - 'a a') - self.assertEqual(regex.match(r"((a)\s(abc|a)*)", "a aa", regex.I)[1], - 'a aa') - - # Issue 3511. - self.assertEqual(regex.match(r"[Z-a]", "_").span(), (0, 1)) - self.assertEqual(regex.match(r"(?i)[Z-a]", "_").span(), (0, 1)) - - self.assertEqual(bool(regex.match(r"(?i)nao", "nAo")), True) - self.assertEqual(bool(regex.match(r"(?i)n\xE3o", "n\xC3o")), True) - self.assertEqual(bool(regex.match(r"(?i)n\xE3o", "N\xC3O")), True) - self.assertEqual(bool(regex.match(r"(?i)s", "\u017F")), True) - - def test_case_folding(self): - self.assertEqual(regex.search(r"(?fi)ss", "SS").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)SS", "ss").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)SS", - "\N{LATIN SMALL LETTER SHARP S}").span(), (0, 1)) - self.assertEqual(regex.search(r"(?fi)\N{LATIN SMALL LETTER SHARP S}", - "SS").span(), (0, 2)) - - self.assertEqual(regex.search(r"(?fi)\N{LATIN SMALL LIGATURE ST}", - "ST").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)ST", - "\N{LATIN SMALL LIGATURE ST}").span(), (0, 1)) - self.assertEqual(regex.search(r"(?fi)ST", - "\N{LATIN SMALL LIGATURE LONG S T}").span(), (0, 1)) - - self.assertEqual(regex.search(r"(?fi)SST", - "\N{LATIN SMALL LETTER SHARP S}t").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)SST", - "s\N{LATIN SMALL LIGATURE LONG S T}").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)SST", - "s\N{LATIN SMALL LIGATURE ST}").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)\N{LATIN SMALL LIGATURE ST}", - "SST").span(), (1, 3)) - self.assertEqual(regex.search(r"(?fi)SST", - "s\N{LATIN SMALL LIGATURE ST}").span(), (0, 2)) - - self.assertEqual(regex.search(r"(?fi)FFI", - "\N{LATIN SMALL LIGATURE FFI}").span(), (0, 1)) - self.assertEqual(regex.search(r"(?fi)FFI", - "\N{LATIN SMALL LIGATURE FF}i").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)FFI", - "f\N{LATIN SMALL LIGATURE FI}").span(), (0, 2)) - self.assertEqual(regex.search(r"(?fi)\N{LATIN SMALL LIGATURE FFI}", - "FFI").span(), (0, 3)) - self.assertEqual(regex.search(r"(?fi)\N{LATIN SMALL LIGATURE FF}i", - "FFI").span(), (0, 3)) - self.assertEqual(regex.search(r"(?fi)f\N{LATIN SMALL LIGATURE FI}", - "FFI").span(), (0, 3)) - - sigma = "\u03A3\u03C3\u03C2" - for ch1 in sigma: - for ch2 in sigma: - if not regex.match(r"(?fi)" + ch1, ch2): - self.fail() - - self.assertEqual(bool(regex.search(r"(?iV1)ff", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)ff", "\uFB01\uFB00")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)fi", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)fi", "\uFB01\uFB00")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)fffi", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)f\uFB03", - "\uFB00\uFB01")), True) - self.assertEqual(bool(regex.search(r"(?iV1)ff", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)fi", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)fffi", "\uFB00\uFB01")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)f\uFB03", - "\uFB00\uFB01")), True) - self.assertEqual(bool(regex.search(r"(?iV1)f\uFB01", "\uFB00i")), - True) - self.assertEqual(bool(regex.search(r"(?iV1)f\uFB01", "\uFB00i")), - True) - - self.assertEqual(regex.findall(r"(?iV0)\m(?:word){e<=3}\M(?ne", "affine", - options=["\N{LATIN SMALL LIGATURE FFI}"]).span(), (0, 6)) - self.assertEqual(regex.search(r"(?fi)a\Lne", - "a\N{LATIN SMALL LIGATURE FFI}ne", options=["ffi"]).span(), (0, 4)) - - def test_category(self): - self.assertEqual(regex.match(r"(\s)", " ")[1], ' ') - - def test_not_literal(self): - self.assertEqual(regex.search(r"\s([^a])", " b")[1], 'b') - self.assertEqual(regex.search(r"\s([^a]*)", " bb")[1], 'bb') - - def test_search_coverage(self): - self.assertEqual(regex.search(r"\s(b)", " b")[1], 'b') - self.assertEqual(regex.search(r"a\s", "a ")[0], 'a ') - - def test_re_escape(self): - p = "" - self.assertEqual(regex.escape(p), p) - for i in range(0, 256): - p += chr(i) - self.assertEqual(bool(regex.match(regex.escape(chr(i)), chr(i))), - True) - self.assertEqual(regex.match(regex.escape(chr(i)), chr(i)).span(), - (0, 1)) - - pat = regex.compile(regex.escape(p)) - self.assertEqual(pat.match(p).span(), (0, 256)) - - def test_re_escape_byte(self): - p = b"" - self.assertEqual(regex.escape(p), p) - for i in range(0, 256): - b = bytes([i]) - p += b - self.assertEqual(bool(regex.match(regex.escape(b), b)), True) - self.assertEqual(regex.match(regex.escape(b), b).span(), (0, 1)) - - pat = regex.compile(regex.escape(p)) - self.assertEqual(pat.match(p).span(), (0, 256)) - - def test_constants(self): - if regex.I != regex.IGNORECASE: - self.fail() - if regex.L != regex.LOCALE: - self.fail() - if regex.M != regex.MULTILINE: - self.fail() - if regex.S != regex.DOTALL: - self.fail() - if regex.X != regex.VERBOSE: - self.fail() - - def test_flags(self): - for flag in [regex.I, regex.M, regex.X, regex.S, regex.L]: - self.assertEqual(repr(type(regex.compile('^pattern$', flag))), - self.PATTERN_CLASS) - - def test_sre_character_literals(self): - for i in [0, 8, 16, 32, 64, 127, 128, 255]: - self.assertEqual(bool(regex.match(r"\%03o" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"\%03o0" % i, chr(i) + "0")), - True) - self.assertEqual(bool(regex.match(r"\%03o8" % i, chr(i) + "8")), - True) - self.assertEqual(bool(regex.match(r"\x%02x" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"\x%02x0" % i, chr(i) + "0")), - True) - self.assertEqual(bool(regex.match(r"\x%02xz" % i, chr(i) + "z")), - True) - - self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda: - regex.match(r"\911", "")) - - def test_sre_character_class_literals(self): - for i in [0, 8, 16, 32, 64, 127, 128, 255]: - self.assertEqual(bool(regex.match(r"[\%03o]" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"[\%03o0]" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"[\%03o8]" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"[\x%02x]" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"[\x%02x0]" % i, chr(i))), True) - self.assertEqual(bool(regex.match(r"[\x%02xz]" % i, chr(i))), True) - - self.assertRaisesRegex(regex.error, self.BAD_OCTAL_ESCAPE, lambda: - regex.match(r"[\911]", "")) - - def test_bug_113254(self): - self.assertEqual(regex.match(r'(a)|(b)', 'b').start(1), -1) - self.assertEqual(regex.match(r'(a)|(b)', 'b').end(1), -1) - self.assertEqual(regex.match(r'(a)|(b)', 'b').span(1), (-1, -1)) - - def test_bug_527371(self): - # Bug described in patches 527371/672491. - self.assertEqual(regex.match(r'(a)?a','a').lastindex, None) - self.assertEqual(regex.match(r'(a)(b)?b','ab').lastindex, 1) - self.assertEqual(regex.match(r'(?Pa)(?Pb)?b','ab').lastgroup, - 'a') - self.assertEqual(regex.match("(?Pa(b))", "ab").lastgroup, 'a') - self.assertEqual(regex.match("((a))", "a").lastindex, 1) - - def test_bug_545855(self): - # Bug 545855 -- This pattern failed to cause a compile error as it - # should, instead provoking a TypeError. - self.assertRaisesRegex(regex.error, self.BAD_SET, lambda: - regex.compile('foo[a-')) - - def test_bug_418626(self): - # Bugs 418626 at al. -- Testing Greg Chapman's addition of op code - # SRE_OP_MIN_REPEAT_ONE for eliminating recursion on simple uses of - # pattern '*?' on a long string. - self.assertEqual(regex.match('.*?c', 10000 * 'ab' + 'cd').end(0), - 20001) - self.assertEqual(regex.match('.*?cd', 5000 * 'ab' + 'c' + 5000 * 'ab' + - 'cde').end(0), 20003) - self.assertEqual(regex.match('.*?cd', 20000 * 'abc' + 'de').end(0), - 60001) - # Non-simple '*?' still used to hit the recursion limit, before the - # non-recursive scheme was implemented. - self.assertEqual(regex.search('(a|b)*?c', 10000 * 'ab' + 'cd').end(0), - 20001) - - def test_bug_612074(self): - pat = "[" + regex.escape("\u2039") + "]" - self.assertEqual(regex.compile(pat) and 1, 1) - - def test_stack_overflow(self): - # Nasty cases that used to overflow the straightforward recursive - # implementation of repeated groups. - self.assertEqual(regex.match('(x)*', 50000 * 'x')[1], 'x') - self.assertEqual(regex.match('(x)*y', 50000 * 'x' + 'y')[1], 'x') - self.assertEqual(regex.match('(x)*?y', 50000 * 'x' + 'y')[1], 'x') - - def test_scanner(self): - def s_ident(scanner, token): return token - def s_operator(scanner, token): return "op%s" % token - def s_float(scanner, token): return float(token) - def s_int(scanner, token): return int(token) - - scanner = regex.Scanner([(r"[a-zA-Z_]\w*", s_ident), (r"\d+\.\d*", - s_float), (r"\d+", s_int), (r"=|\+|-|\*|/", s_operator), (r"\s+", - None), ]) - - self.assertEqual(repr(type(scanner.scanner.scanner("").pattern)), - self.PATTERN_CLASS) - - self.assertEqual(scanner.scan("sum = 3*foo + 312.50 + bar"), (['sum', - 'op=', 3, 'op*', 'foo', 'op+', 312.5, 'op+', 'bar'], '')) - - def test_bug_448951(self): - # Bug 448951 (similar to 429357, but with single char match). - # (Also test greedy matches.) - for op in '', '?', '*': - self.assertEqual(regex.match(r'((.%s):)?z' % op, 'z')[:], ('z', - None, None)) - self.assertEqual(regex.match(r'((.%s):)?z' % op, 'a:z')[:], ('a:z', - 'a:', 'a')) - - def test_bug_725106(self): - # Capturing groups in alternatives in repeats. - self.assertEqual(regex.match('^((a)|b)*', 'abc')[:], ('ab', 'b', 'a')) - self.assertEqual(regex.match('^(([ab])|c)*', 'abc')[:], ('abc', 'c', - 'b')) - self.assertEqual(regex.match('^((d)|[ab])*', 'abc')[:], ('ab', 'b', - None)) - self.assertEqual(regex.match('^((a)c|[ab])*', 'abc')[:], ('ab', 'b', - None)) - self.assertEqual(regex.match('^((a)|b)*?c', 'abc')[:], ('abc', 'b', - 'a')) - self.assertEqual(regex.match('^(([ab])|c)*?d', 'abcd')[:], ('abcd', - 'c', 'b')) - self.assertEqual(regex.match('^((d)|[ab])*?c', 'abc')[:], ('abc', 'b', - None)) - self.assertEqual(regex.match('^((a)c|[ab])*?c', 'abc')[:], ('abc', 'b', - None)) - - def test_bug_725149(self): - # Mark_stack_base restoring before restoring marks. - self.assertEqual(regex.match('(a)(?:(?=(b)*)c)*', 'abb')[:], ('a', 'a', - None)) - self.assertEqual(regex.match('(a)((?!(b)*))*', 'abb')[:], ('a', 'a', - None, None)) - - def test_bug_764548(self): - # Bug 764548, regex.compile() barfs on str/unicode subclasses. - class my_unicode(str): pass - pat = regex.compile(my_unicode("abc")) - self.assertEqual(pat.match("xyz"), None) - - def test_finditer(self): - it = regex.finditer(r":+", "a:b::c:::d") - self.assertEqual([item[0] for item in it], [':', '::', ':::']) - - def test_bug_926075(self): - if regex.compile('bug_926075') is regex.compile(b'bug_926075'): - self.fail() - - def test_bug_931848(self): - pattern = "[\u002E\u3002\uFF0E\uFF61]" - self.assertEqual(regex.compile(pattern).split("a.b.c"), ['a', 'b', - 'c']) - - def test_bug_581080(self): - it = regex.finditer(r"\s", "a b") - self.assertEqual(next(it).span(), (1, 2)) - self.assertRaises(StopIteration, lambda: next(it)) - - scanner = regex.compile(r"\s").scanner("a b") - self.assertEqual(scanner.search().span(), (1, 2)) - self.assertEqual(scanner.search(), None) - - def test_bug_817234(self): - it = regex.finditer(r".*", "asdf") - self.assertEqual(next(it).span(), (0, 4)) - self.assertEqual(next(it).span(), (4, 4)) - self.assertRaises(StopIteration, lambda: next(it)) - - def test_empty_array(self): - # SF buf 1647541. - import array - for typecode in 'bBuhHiIlLfd': - a = array.array(typecode) - self.assertEqual(regex.compile(b"bla").match(a), None) - self.assertEqual(regex.compile(b"").match(a)[1 : ], ()) - - def test_inline_flags(self): - # Bug #1700. - upper_char = chr(0x1ea0) # Latin Capital Letter A with Dot Below - lower_char = chr(0x1ea1) # Latin Small Letter A with Dot Below - - p = regex.compile(upper_char, regex.I | regex.U) - self.assertEqual(bool(p.match(lower_char)), True) - - p = regex.compile(lower_char, regex.I | regex.U) - self.assertEqual(bool(p.match(upper_char)), True) - - p = regex.compile('(?i)' + upper_char, regex.U) - self.assertEqual(bool(p.match(lower_char)), True) - - p = regex.compile('(?i)' + lower_char, regex.U) - self.assertEqual(bool(p.match(upper_char)), True) - - p = regex.compile('(?iu)' + upper_char) - self.assertEqual(bool(p.match(lower_char)), True) - - p = regex.compile('(?iu)' + lower_char) - self.assertEqual(bool(p.match(upper_char)), True) - - # Changed to positional flags in regex 2023.12.23. - self.assertEqual(bool(regex.match(r"(?i)a", "A")), True) - self.assertEqual(regex.match(r"a(?i)", "A"), None) - - def test_dollar_matches_twice(self): - # $ matches the end of string, and just before the terminating \n. - pattern = regex.compile('$') - self.assertEqual(pattern.sub('#', 'a\nb\n'), 'a\nb#\n#') - self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a\nb\nc#') - self.assertEqual(pattern.sub('#', '\n'), '#\n#') - - pattern = regex.compile('$', regex.MULTILINE) - self.assertEqual(pattern.sub('#', 'a\nb\n' ), 'a#\nb#\n#') - self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a#\nb#\nc#') - self.assertEqual(pattern.sub('#', '\n'), '#\n#') - - def test_bytes_str_mixing(self): - # Mixing str and bytes is disallowed. - pat = regex.compile('.') - bpat = regex.compile(b'.') - self.assertRaisesRegex(TypeError, self.STR_PAT_ON_BYTES, lambda: - pat.match(b'b')) - self.assertRaisesRegex(TypeError, self.BYTES_PAT_ON_STR, lambda: - bpat.match('b')) - self.assertRaisesRegex(TypeError, self.STR_PAT_BYTES_TEMPL, lambda: - pat.sub(b'b', 'c')) - self.assertRaisesRegex(TypeError, self.STR_PAT_ON_BYTES, lambda: - pat.sub('b', b'c')) - self.assertRaisesRegex(TypeError, self.STR_PAT_ON_BYTES, lambda: - pat.sub(b'b', b'c')) - self.assertRaisesRegex(TypeError, self.BYTES_PAT_ON_STR, lambda: - bpat.sub(b'b', 'c')) - self.assertRaisesRegex(TypeError, self.BYTES_PAT_STR_TEMPL, lambda: - bpat.sub('b', b'c')) - self.assertRaisesRegex(TypeError, self.BYTES_PAT_ON_STR, lambda: - bpat.sub('b', 'c')) - - self.assertRaisesRegex(ValueError, self.BYTES_PAT_UNI_FLAG, lambda: - regex.compile(br'\w', regex.UNICODE)) - self.assertRaisesRegex(ValueError, self.BYTES_PAT_UNI_FLAG, lambda: - regex.compile(br'(?u)\w')) - self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda: - regex.compile(r'\w', regex.UNICODE | regex.ASCII)) - self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda: - regex.compile(r'(?u)\w', regex.ASCII)) - self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda: - regex.compile(r'(?a)\w', regex.UNICODE)) - self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda: - regex.compile(r'(?au)\w')) - - def test_ascii_and_unicode_flag(self): - # String patterns. - for flags in (0, regex.UNICODE): - pat = regex.compile('\xc0', flags | regex.IGNORECASE) - self.assertEqual(bool(pat.match('\xe0')), True) - pat = regex.compile(r'\w', flags) - self.assertEqual(bool(pat.match('\xe0')), True) - - pat = regex.compile('\xc0', regex.ASCII | regex.IGNORECASE) - self.assertEqual(pat.match('\xe0'), None) - pat = regex.compile('(?a)\xc0', regex.IGNORECASE) - self.assertEqual(pat.match('\xe0'), None) - pat = regex.compile(r'\w', regex.ASCII) - self.assertEqual(pat.match('\xe0'), None) - pat = regex.compile(r'(?a)\w') - self.assertEqual(pat.match('\xe0'), None) - - # Bytes patterns. - for flags in (0, regex.ASCII): - pat = regex.compile(b'\xc0', flags | regex.IGNORECASE) - self.assertEqual(pat.match(b'\xe0'), None) - pat = regex.compile(br'\w') - self.assertEqual(pat.match(b'\xe0'), None) - - self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda: - regex.compile(r'(?au)\w')) - - def test_subscripting_match(self): - m = regex.match(r'(?\w)', 'xy') - if not m: - self.fail("Failed: expected match but returned None") - elif not m or m[0] != m.group(0) or m[1] != m.group(1): - self.fail("Failed") - if not m: - self.fail("Failed: expected match but returned None") - elif m[:] != ('x', 'x'): - self.fail("Failed: expected \"('x', 'x')\" but got {} instead".format(ascii(m[:]))) - - def test_new_named_groups(self): - m0 = regex.match(r'(?P\w)', 'x') - m1 = regex.match(r'(?\w)', 'x') - if not (m0 and m1 and m0[:] == m1[:]): - self.fail("Failed") - - def test_properties(self): - self.assertEqual(regex.match(b'(?ai)\xC0', b'\xE0'), None) - self.assertEqual(regex.match(br'(?ai)\xC0', b'\xE0'), None) - self.assertEqual(regex.match(br'(?a)\w', b'\xE0'), None) - self.assertEqual(bool(regex.match(r'\w', '\xE0')), True) - - # Dropped the following test. It's not possible to determine what the - # correct result should be in the general case. -# self.assertEqual(bool(regex.match(br'(?L)\w', b'\xE0')), -# b'\xE0'.isalnum()) - - self.assertEqual(bool(regex.match(br'(?L)\d', b'0')), True) - self.assertEqual(bool(regex.match(br'(?L)\s', b' ')), True) - self.assertEqual(bool(regex.match(br'(?L)\w', b'a')), True) - self.assertEqual(regex.match(br'(?L)\d', b'?'), None) - self.assertEqual(regex.match(br'(?L)\s', b'?'), None) - self.assertEqual(regex.match(br'(?L)\w', b'?'), None) - - self.assertEqual(regex.match(br'(?L)\D', b'0'), None) - self.assertEqual(regex.match(br'(?L)\S', b' '), None) - self.assertEqual(regex.match(br'(?L)\W', b'a'), None) - self.assertEqual(bool(regex.match(br'(?L)\D', b'?')), True) - self.assertEqual(bool(regex.match(br'(?L)\S', b'?')), True) - self.assertEqual(bool(regex.match(br'(?L)\W', b'?')), True) - - self.assertEqual(bool(regex.match(r'\p{Cyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'(?i)\p{Cyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{IsCyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{Script=Cyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{InCyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{Block=Cyrillic}', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:Cyrillic:]]', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:IsCyrillic:]]', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:Script=Cyrillic:]]', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:InCyrillic:]]', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:Block=Cyrillic:]]', - '\N{CYRILLIC CAPITAL LETTER A}')), True) - - self.assertEqual(bool(regex.match(r'\P{Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\P{IsCyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\P{Script=Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\P{InCyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\P{Block=Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{^Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{^IsCyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{^Script=Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{^InCyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'\p{^Block=Cyrillic}', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:^Cyrillic:]]', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:^IsCyrillic:]]', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:^Script=Cyrillic:]]', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:^InCyrillic:]]', - '\N{LATIN CAPITAL LETTER A}')), True) - self.assertEqual(bool(regex.match(r'[[:^Block=Cyrillic:]]', - '\N{LATIN CAPITAL LETTER A}')), True) - - self.assertEqual(bool(regex.match(r'\d', '0')), True) - self.assertEqual(bool(regex.match(r'\s', ' ')), True) - self.assertEqual(bool(regex.match(r'\w', 'A')), True) - self.assertEqual(regex.match(r"\d", "?"), None) - self.assertEqual(regex.match(r"\s", "?"), None) - self.assertEqual(regex.match(r"\w", "?"), None) - self.assertEqual(regex.match(r"\D", "0"), None) - self.assertEqual(regex.match(r"\S", " "), None) - self.assertEqual(regex.match(r"\W", "A"), None) - self.assertEqual(bool(regex.match(r'\D', '?')), True) - self.assertEqual(bool(regex.match(r'\S', '?')), True) - self.assertEqual(bool(regex.match(r'\W', '?')), True) - - self.assertEqual(bool(regex.match(r'\p{L}', 'A')), True) - self.assertEqual(bool(regex.match(r'\p{L}', 'a')), True) - self.assertEqual(bool(regex.match(r'\p{Lu}', 'A')), True) - self.assertEqual(bool(regex.match(r'\p{Ll}', 'a')), True) - - self.assertEqual(bool(regex.match(r'(?i)a', 'a')), True) - self.assertEqual(bool(regex.match(r'(?i)a', 'A')), True) - - self.assertEqual(bool(regex.match(r'\w', '0')), True) - self.assertEqual(bool(regex.match(r'\w', 'a')), True) - self.assertEqual(bool(regex.match(r'\w', '_')), True) - - self.assertEqual(regex.match(r"\X", "\xE0").span(), (0, 1)) - self.assertEqual(regex.match(r"\X", "a\u0300").span(), (0, 2)) - self.assertEqual(regex.findall(r"\X", - "a\xE0a\u0300e\xE9e\u0301"), ['a', '\xe0', 'a\u0300', 'e', - '\xe9', 'e\u0301']) - self.assertEqual(regex.findall(r"\X{3}", - "a\xE0a\u0300e\xE9e\u0301"), ['a\xe0a\u0300', 'e\xe9e\u0301']) - self.assertEqual(regex.findall(r"\X", "\r\r\n\u0301A\u0301"), - ['\r', '\r\n', '\u0301', 'A\u0301']) - - self.assertEqual(bool(regex.match(r'\p{Ll}', 'a')), True) - - chars_u = "-09AZaz_\u0393\u03b3" - chars_b = b"-09AZaz_" - word_set = set("Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc".split()) - - tests = [ - (r"\w", chars_u, "09AZaz_\u0393\u03b3"), - (r"[[:word:]]", chars_u, "09AZaz_\u0393\u03b3"), - (r"\W", chars_u, "-"), - (r"[[:^word:]]", chars_u, "-"), - (r"\d", chars_u, "09"), - (r"[[:digit:]]", chars_u, "09"), - (r"\D", chars_u, "-AZaz_\u0393\u03b3"), - (r"[[:^digit:]]", chars_u, "-AZaz_\u0393\u03b3"), - (r"[[:alpha:]]", chars_u, "AZaz\u0393\u03b3"), - (r"[[:^alpha:]]", chars_u, "-09_"), - (r"[[:alnum:]]", chars_u, "09AZaz\u0393\u03b3"), - (r"[[:^alnum:]]", chars_u, "-_"), - (r"[[:xdigit:]]", chars_u, "09Aa"), - (r"[[:^xdigit:]]", chars_u, "-Zz_\u0393\u03b3"), - (r"\p{InBasicLatin}", "a\xE1", "a"), - (r"\P{InBasicLatin}", "a\xE1", "\xE1"), - (r"(?i)\p{InBasicLatin}", "a\xE1", "a"), - (r"(?i)\P{InBasicLatin}", "a\xE1", "\xE1"), - - (br"(?L)\w", chars_b, b"09AZaz_"), - (br"(?L)[[:word:]]", chars_b, b"09AZaz_"), - (br"(?L)\W", chars_b, b"-"), - (br"(?L)[[:^word:]]", chars_b, b"-"), - (br"(?L)\d", chars_b, b"09"), - (br"(?L)[[:digit:]]", chars_b, b"09"), - (br"(?L)\D", chars_b, b"-AZaz_"), - (br"(?L)[[:^digit:]]", chars_b, b"-AZaz_"), - (br"(?L)[[:alpha:]]", chars_b, b"AZaz"), - (br"(?L)[[:^alpha:]]", chars_b, b"-09_"), - (br"(?L)[[:alnum:]]", chars_b, b"09AZaz"), - (br"(?L)[[:^alnum:]]", chars_b, b"-_"), - (br"(?L)[[:xdigit:]]", chars_b, b"09Aa"), - (br"(?L)[[:^xdigit:]]", chars_b, b"-Zz_"), - - (br"(?a)\w", chars_b, b"09AZaz_"), - (br"(?a)[[:word:]]", chars_b, b"09AZaz_"), - (br"(?a)\W", chars_b, b"-"), - (br"(?a)[[:^word:]]", chars_b, b"-"), - (br"(?a)\d", chars_b, b"09"), - (br"(?a)[[:digit:]]", chars_b, b"09"), - (br"(?a)\D", chars_b, b"-AZaz_"), - (br"(?a)[[:^digit:]]", chars_b, b"-AZaz_"), - (br"(?a)[[:alpha:]]", chars_b, b"AZaz"), - (br"(?a)[[:^alpha:]]", chars_b, b"-09_"), - (br"(?a)[[:alnum:]]", chars_b, b"09AZaz"), - (br"(?a)[[:^alnum:]]", chars_b, b"-_"), - (br"(?a)[[:xdigit:]]", chars_b, b"09Aa"), - (br"(?a)[[:^xdigit:]]", chars_b, b"-Zz_"), - ] - for pattern, chars, expected in tests: - try: - if chars[ : 0].join(regex.findall(pattern, chars)) != expected: - self.fail("Failed: {}".format(pattern)) - except Exception as e: - self.fail("Failed: {} raised {}".format(pattern, ascii(e))) - - self.assertEqual(bool(regex.match(r"\p{NumericValue=0}", "0")), - True) - self.assertEqual(bool(regex.match(r"\p{NumericValue=1/2}", - "\N{VULGAR FRACTION ONE HALF}")), True) - self.assertEqual(bool(regex.match(r"\p{NumericValue=0.5}", - "\N{VULGAR FRACTION ONE HALF}")), True) - - def test_word_class(self): - self.assertEqual(regex.findall(r"\w+", - " \u0939\u093f\u0928\u094d\u0926\u0940,"), - ['\u0939\u093f\u0928\u094d\u0926\u0940']) - self.assertEqual(regex.findall(r"\W+", - " \u0939\u093f\u0928\u094d\u0926\u0940,"), [' ', ',']) - self.assertEqual(regex.split(r"(?V1)\b", - " \u0939\u093f\u0928\u094d\u0926\u0940,"), [' ', - '\u0939\u093f\u0928\u094d\u0926\u0940', ',']) - self.assertEqual(regex.split(r"(?V1)\B", - " \u0939\u093f\u0928\u094d\u0926\u0940,"), ['', ' \u0939', - '\u093f', '\u0928', '\u094d', '\u0926', '\u0940,', '']) - - def test_search_anchor(self): - self.assertEqual(regex.findall(r"\G\w{2}", "abcd ef"), ['ab', 'cd']) - - def test_search_reverse(self): - self.assertEqual(regex.findall(r"(?r).", "abc"), ['c', 'b', 'a']) - self.assertEqual(regex.findall(r"(?r).", "abc", overlapped=True), ['c', - 'b', 'a']) - self.assertEqual(regex.findall(r"(?r)..", "abcde"), ['de', 'bc']) - self.assertEqual(regex.findall(r"(?r)..", "abcde", overlapped=True), - ['de', 'cd', 'bc', 'ab']) - self.assertEqual(regex.findall(r"(?r)(.)(-)(.)", "a-b-c", - overlapped=True), [("b", "-", "c"), ("a", "-", "b")]) - - self.assertEqual([m[0] for m in regex.finditer(r"(?r).", "abc")], ['c', - 'b', 'a']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde", - overlapped=True)], ['de', 'cd', 'bc', 'ab']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r).", "abc")], ['c', - 'b', 'a']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde", - overlapped=True)], ['de', 'cd', 'bc', 'ab']) - - self.assertEqual(regex.findall(r"^|\w+", "foo bar"), ['', 'foo', - 'bar']) - self.assertEqual(regex.findall(r"(?V1)^|\w+", "foo bar"), ['', 'foo', - 'bar']) - self.assertEqual(regex.findall(r"(?r)^|\w+", "foo bar"), ['bar', 'foo', - '']) - self.assertEqual(regex.findall(r"(?rV1)^|\w+", "foo bar"), ['bar', - 'foo', '']) - - self.assertEqual([m[0] for m in regex.finditer(r"^|\w+", "foo bar")], - ['', 'foo', 'bar']) - self.assertEqual([m[0] for m in regex.finditer(r"(?V1)^|\w+", - "foo bar")], ['', 'foo', 'bar']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)^|\w+", - "foo bar")], ['bar', 'foo', '']) - self.assertEqual([m[0] for m in regex.finditer(r"(?rV1)^|\w+", - "foo bar")], ['bar', 'foo', '']) - - self.assertEqual(regex.findall(r"\G\w{2}", "abcd ef"), ['ab', 'cd']) - self.assertEqual(regex.findall(r".{2}(?<=\G.*)", "abcd"), ['ab', 'cd']) - self.assertEqual(regex.findall(r"(?r)\G\w{2}", "abcd ef"), []) - self.assertEqual(regex.findall(r"(?r)\w{2}\G", "abcd ef"), ['ef']) - - self.assertEqual(regex.findall(r"q*", "qqwe"), ['qq', '', '', '']) - self.assertEqual(regex.findall(r"(?V1)q*", "qqwe"), ['qq', '', '', '']) - self.assertEqual(regex.findall(r"(?r)q*", "qqwe"), ['', '', 'qq', '']) - self.assertEqual(regex.findall(r"(?rV1)q*", "qqwe"), ['', '', 'qq', - '']) - - self.assertEqual(regex.findall(".", "abcd", pos=1, endpos=3), ['b', - 'c']) - self.assertEqual(regex.findall(".", "abcd", pos=1, endpos=-1), ['b', - 'c']) - self.assertEqual([m[0] for m in regex.finditer(".", "abcd", pos=1, - endpos=3)], ['b', 'c']) - self.assertEqual([m[0] for m in regex.finditer(".", "abcd", pos=1, - endpos=-1)], ['b', 'c']) - - self.assertEqual([m[0] for m in regex.finditer("(?r).", "abcd", pos=1, - endpos=3)], ['c', 'b']) - self.assertEqual([m[0] for m in regex.finditer("(?r).", "abcd", pos=1, - endpos=-1)], ['c', 'b']) - self.assertEqual(regex.findall("(?r).", "abcd", pos=1, endpos=3), ['c', - 'b']) - self.assertEqual(regex.findall("(?r).", "abcd", pos=1, endpos=-1), - ['c', 'b']) - - self.assertEqual(regex.findall(r"[ab]", "aB", regex.I), ['a', 'B']) - self.assertEqual(regex.findall(r"(?r)[ab]", "aB", regex.I), ['B', 'a']) - - self.assertEqual(regex.findall(r"(?r).{2}", "abc"), ['bc']) - self.assertEqual(regex.findall(r"(?r).{2}", "abc", overlapped=True), - ['bc', 'ab']) - self.assertEqual(regex.findall(r"(\w+) (\w+)", - "first second third fourth fifth"), [('first', 'second'), ('third', - 'fourth')]) - self.assertEqual(regex.findall(r"(?r)(\w+) (\w+)", - "first second third fourth fifth"), [('fourth', 'fifth'), ('second', - 'third')]) - - self.assertEqual([m[0] for m in regex.finditer(r"(?r).{2}", "abc")], - ['bc']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r).{2}", "abc", - overlapped=True)], ['bc', 'ab']) - self.assertEqual([m[0] for m in regex.finditer(r"(\w+) (\w+)", - "first second third fourth fifth")], ['first second', - 'third fourth']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)(\w+) (\w+)", - "first second third fourth fifth")], ['fourth fifth', - 'second third']) - - self.assertEqual(regex.search("abcdef", "abcdef").span(), (0, 6)) - self.assertEqual(regex.search("(?r)abcdef", "abcdef").span(), (0, 6)) - self.assertEqual(regex.search("(?i)abcdef", "ABCDEF").span(), (0, 6)) - self.assertEqual(regex.search("(?ir)abcdef", "ABCDEF").span(), (0, 6)) - - self.assertEqual(regex.sub(r"(.)", r"\1", "abc"), 'abc') - self.assertEqual(regex.sub(r"(?r)(.)", r"\1", "abc"), 'abc') - - def test_atomic(self): - # Issue 433030. - self.assertEqual(regex.search(r"(?>a*)a", "aa"), None) - - def test_possessive(self): - # Single-character non-possessive. - self.assertEqual(regex.search(r"a?a", "a").span(), (0, 1)) - self.assertEqual(regex.search(r"a*a", "aaa").span(), (0, 3)) - self.assertEqual(regex.search(r"a+a", "aaa").span(), (0, 3)) - self.assertEqual(regex.search(r"a{1,3}a", "aaa").span(), (0, 3)) - - # Multiple-character non-possessive. - self.assertEqual(regex.search(r"(?:ab)?ab", "ab").span(), (0, 2)) - self.assertEqual(regex.search(r"(?:ab)*ab", "ababab").span(), (0, 6)) - self.assertEqual(regex.search(r"(?:ab)+ab", "ababab").span(), (0, 6)) - self.assertEqual(regex.search(r"(?:ab){1,3}ab", "ababab").span(), (0, - 6)) - - # Single-character possessive. - self.assertEqual(regex.search(r"a?+a", "a"), None) - self.assertEqual(regex.search(r"a*+a", "aaa"), None) - self.assertEqual(regex.search(r"a++a", "aaa"), None) - self.assertEqual(regex.search(r"a{1,3}+a", "aaa"), None) - - # Multiple-character possessive. - self.assertEqual(regex.search(r"(?:ab)?+ab", "ab"), None) - self.assertEqual(regex.search(r"(?:ab)*+ab", "ababab"), None) - self.assertEqual(regex.search(r"(?:ab)++ab", "ababab"), None) - self.assertEqual(regex.search(r"(?:ab){1,3}+ab", "ababab"), None) - - def test_zerowidth(self): - # Issue 3262. - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split(r"\b", "a b"), ['', 'a', ' ', 'b', - '']) - else: - self.assertEqual(regex.split(r"\b", "a b"), ['a b']) - self.assertEqual(regex.split(r"(?V1)\b", "a b"), ['', 'a', ' ', 'b', - '']) - - # Issue 1647489. - self.assertEqual(regex.findall(r"^|\w+", "foo bar"), ['', 'foo', - 'bar']) - self.assertEqual([m[0] for m in regex.finditer(r"^|\w+", "foo bar")], - ['', 'foo', 'bar']) - self.assertEqual(regex.findall(r"(?r)^|\w+", "foo bar"), ['bar', - 'foo', '']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)^|\w+", - "foo bar")], ['bar', 'foo', '']) - self.assertEqual(regex.findall(r"(?V1)^|\w+", "foo bar"), ['', 'foo', - 'bar']) - self.assertEqual([m[0] for m in regex.finditer(r"(?V1)^|\w+", - "foo bar")], ['', 'foo', 'bar']) - self.assertEqual(regex.findall(r"(?rV1)^|\w+", "foo bar"), ['bar', - 'foo', '']) - self.assertEqual([m[0] for m in regex.finditer(r"(?rV1)^|\w+", - "foo bar")], ['bar', 'foo', '']) - - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split("", "xaxbxc"), ['', 'x', 'a', 'x', - 'b', 'x', 'c', '']) - self.assertEqual([m for m in regex.splititer("", "xaxbxc")], ['', - 'x', 'a', 'x', 'b', 'x', 'c', '']) - else: - self.assertEqual(regex.split("", "xaxbxc"), ['xaxbxc']) - self.assertEqual([m for m in regex.splititer("", "xaxbxc")], - ['xaxbxc']) - - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split("(?r)", "xaxbxc"), ['', 'c', 'x', 'b', - 'x', 'a', 'x', '']) - self.assertEqual([m for m in regex.splititer("(?r)", "xaxbxc")], - ['', 'c', 'x', 'b', 'x', 'a', 'x', '']) - else: - self.assertEqual(regex.split("(?r)", "xaxbxc"), ['xaxbxc']) - self.assertEqual([m for m in regex.splititer("(?r)", "xaxbxc")], - ['xaxbxc']) - - self.assertEqual(regex.split("(?V1)", "xaxbxc"), ['', 'x', 'a', 'x', - 'b', 'x', 'c', '']) - self.assertEqual([m for m in regex.splititer("(?V1)", "xaxbxc")], ['', - 'x', 'a', 'x', 'b', 'x', 'c', '']) - - self.assertEqual(regex.split("(?rV1)", "xaxbxc"), ['', 'c', 'x', 'b', - 'x', 'a', 'x', '']) - self.assertEqual([m for m in regex.splititer("(?rV1)", "xaxbxc")], ['', - 'c', 'x', 'b', 'x', 'a', 'x', '']) - - def test_scoped_and_inline_flags(self): - # Issues 433028, 433024, 433027. - self.assertEqual(regex.search(r"(?i)Ab", "ab").span(), (0, 2)) - self.assertEqual(regex.search(r"(?i:A)b", "ab").span(), (0, 2)) - # Changed to positional flags in regex 2023.12.23. - self.assertEqual(regex.search(r"A(?i)b", "ab"), None) - - self.assertEqual(regex.search(r"(?V0)Ab", "ab"), None) - self.assertEqual(regex.search(r"(?V1)Ab", "ab"), None) - self.assertEqual(regex.search(r"(?-i)Ab", "ab", flags=regex.I), None) - self.assertEqual(regex.search(r"(?-i:A)b", "ab", flags=regex.I), None) - self.assertEqual(regex.search(r"A(?-i)b", "ab", flags=regex.I).span(), - (0, 2)) - - def test_repeated_repeats(self): - # Issue 2537. - self.assertEqual(regex.search(r"(?:a+)+", "aaa").span(), (0, 3)) - self.assertEqual(regex.search(r"(?:(?:ab)+c)+", "abcabc").span(), (0, - 6)) - - # Hg issue 286. - self.assertEqual(regex.search(r"(?:a+){2,}", "aaa").span(), (0, 3)) - - def test_lookbehind(self): - self.assertEqual(regex.search(r"123(?<=a\d+)", "a123").span(), (1, 4)) - self.assertEqual(regex.search(r"123(?<=a\d+)", "b123"), None) - self.assertEqual(regex.search(r"123(?= (3, 7, 0): - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "xy"), - 'y-x-') - else: - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "xy"), - 'y-x') - self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "xy"), 'y-x-') - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "x"), '-x-') - else: - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "x"), '-x') - self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "x"), '-x-') - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "y"), 'y--') - else: - self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "y"), 'y-') - self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "y"), 'y--') - - def test_bug_10328 (self): - # Issue 10328. - pat = regex.compile(r'(?mV0)(?P[ \t]+\r*$)|(?P(?<=[^\n])\Z)') - if sys.version_info >= (3, 7, 0): - self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>', - 'foobar '), ('foobar', 2)) - else: - self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>', - 'foobar '), ('foobar', 1)) - self.assertEqual([m.group() for m in pat.finditer('foobar ')], [' ', - '']) - pat = regex.compile(r'(?mV1)(?P[ \t]+\r*$)|(?P(?<=[^\n])\Z)') - self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>', - 'foobar '), ('foobar', 2)) - self.assertEqual([m.group() for m in pat.finditer('foobar ')], [' ', - '']) - - def test_overlapped(self): - self.assertEqual(regex.findall(r"..", "abcde"), ['ab', 'cd']) - self.assertEqual(regex.findall(r"..", "abcde", overlapped=True), ['ab', - 'bc', 'cd', 'de']) - self.assertEqual(regex.findall(r"(?r)..", "abcde"), ['de', 'bc']) - self.assertEqual(regex.findall(r"(?r)..", "abcde", overlapped=True), - ['de', 'cd', 'bc', 'ab']) - self.assertEqual(regex.findall(r"(.)(-)(.)", "a-b-c", overlapped=True), - [("a", "-", "b"), ("b", "-", "c")]) - - self.assertEqual([m[0] for m in regex.finditer(r"..", "abcde")], ['ab', - 'cd']) - self.assertEqual([m[0] for m in regex.finditer(r"..", "abcde", - overlapped=True)], ['ab', 'bc', 'cd', 'de']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde")], - ['de', 'bc']) - self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde", - overlapped=True)], ['de', 'cd', 'bc', 'ab']) - - self.assertEqual([m.groups() for m in regex.finditer(r"(.)(-)(.)", - "a-b-c", overlapped=True)], [("a", "-", "b"), ("b", "-", "c")]) - self.assertEqual([m.groups() for m in regex.finditer(r"(?r)(.)(-)(.)", - "a-b-c", overlapped=True)], [("b", "-", "c"), ("a", "-", "b")]) - - def test_splititer(self): - self.assertEqual(regex.split(r",", "a,b,,c,"), ['a', 'b', '', 'c', '']) - self.assertEqual([m for m in regex.splititer(r",", "a,b,,c,")], ['a', - 'b', '', 'c', '']) - - def test_grapheme(self): - self.assertEqual(regex.match(r"\X", "\xE0").span(), (0, 1)) - self.assertEqual(regex.match(r"\X", "a\u0300").span(), (0, 2)) - - self.assertEqual(regex.findall(r"\X", - "a\xE0a\u0300e\xE9e\u0301"), ['a', '\xe0', 'a\u0300', 'e', - '\xe9', 'e\u0301']) - self.assertEqual(regex.findall(r"\X{3}", - "a\xE0a\u0300e\xE9e\u0301"), ['a\xe0a\u0300', 'e\xe9e\u0301']) - self.assertEqual(regex.findall(r"\X", "\r\r\n\u0301A\u0301"), - ['\r', '\r\n', '\u0301', 'A\u0301']) - - def test_word_boundary(self): - text = 'The quick ("brown") fox can\'t jump 32.3 feet, right?' - self.assertEqual(regex.split(r'(?V1)\b', text), ['', 'The', ' ', - 'quick', ' ("', 'brown', '") ', 'fox', ' ', 'can', "'", 't', - ' ', 'jump', ' ', '32', '.', '3', ' ', 'feet', ', ', - 'right', '?']) - self.assertEqual(regex.split(r'(?V1w)\b', text), ['', 'The', ' ', - 'quick', ' ', '(', '"', 'brown', '"', ')', ' ', 'fox', ' ', - "can't", ' ', 'jump', ' ', '32.3', ' ', 'feet', ',', ' ', - 'right', '?', '']) - - text = "The fox" - self.assertEqual(regex.split(r'(?V1)\b', text), ['', 'The', ' ', - 'fox', '']) - self.assertEqual(regex.split(r'(?V1w)\b', text), ['', 'The', ' ', - 'fox', '']) - - text = "can't aujourd'hui l'objectif" - self.assertEqual(regex.split(r'(?V1)\b', text), ['', 'can', "'", - 't', ' ', 'aujourd', "'", 'hui', ' ', 'l', "'", 'objectif', - '']) - self.assertEqual(regex.split(r'(?V1w)\b', text), ['', "can't", ' ', - "aujourd'hui", ' ', "l'objectif", '']) - - def test_line_boundary(self): - self.assertEqual(regex.findall(r".+", "Line 1\nLine 2\n"), ["Line 1", - "Line 2"]) - self.assertEqual(regex.findall(r".+", "Line 1\rLine 2\r"), - ["Line 1\rLine 2\r"]) - self.assertEqual(regex.findall(r".+", "Line 1\r\nLine 2\r\n"), - ["Line 1\r", "Line 2\r"]) - self.assertEqual(regex.findall(r"(?w).+", "Line 1\nLine 2\n"), - ["Line 1", "Line 2"]) - self.assertEqual(regex.findall(r"(?w).+", "Line 1\rLine 2\r"), - ["Line 1", "Line 2"]) - self.assertEqual(regex.findall(r"(?w).+", "Line 1\r\nLine 2\r\n"), - ["Line 1", "Line 2"]) - - self.assertEqual(regex.search(r"^abc", "abc").start(), 0) - self.assertEqual(regex.search(r"^abc", "\nabc"), None) - self.assertEqual(regex.search(r"^abc", "\rabc"), None) - self.assertEqual(regex.search(r"(?w)^abc", "abc").start(), 0) - self.assertEqual(regex.search(r"(?w)^abc", "\nabc"), None) - self.assertEqual(regex.search(r"(?w)^abc", "\rabc"), None) - - self.assertEqual(regex.search(r"abc$", "abc").start(), 0) - self.assertEqual(regex.search(r"abc$", "abc\n").start(), 0) - self.assertEqual(regex.search(r"abc$", "abc\r"), None) - self.assertEqual(regex.search(r"(?w)abc$", "abc").start(), 0) - self.assertEqual(regex.search(r"(?w)abc$", "abc\n").start(), 0) - self.assertEqual(regex.search(r"(?w)abc$", "abc\r").start(), 0) - - self.assertEqual(regex.search(r"(?m)^abc", "abc").start(), 0) - self.assertEqual(regex.search(r"(?m)^abc", "\nabc").start(), 1) - self.assertEqual(regex.search(r"(?m)^abc", "\rabc"), None) - self.assertEqual(regex.search(r"(?mw)^abc", "abc").start(), 0) - self.assertEqual(regex.search(r"(?mw)^abc", "\nabc").start(), 1) - self.assertEqual(regex.search(r"(?mw)^abc", "\rabc").start(), 1) - - self.assertEqual(regex.search(r"(?m)abc$", "abc").start(), 0) - self.assertEqual(regex.search(r"(?m)abc$", "abc\n").start(), 0) - self.assertEqual(regex.search(r"(?m)abc$", "abc\r"), None) - self.assertEqual(regex.search(r"(?mw)abc$", "abc").start(), 0) - self.assertEqual(regex.search(r"(?mw)abc$", "abc\n").start(), 0) - self.assertEqual(regex.search(r"(?mw)abc$", "abc\r").start(), 0) - - def test_branch_reset(self): - self.assertEqual(regex.match(r"(?:(a)|(b))(c)", "ac").groups(), ('a', - None, 'c')) - self.assertEqual(regex.match(r"(?:(a)|(b))(c)", "bc").groups(), (None, - 'b', 'c')) - self.assertEqual(regex.match(r"(?:(?a)|(?b))(?c)", - "ac").groups(), ('a', None, 'c')) - self.assertEqual(regex.match(r"(?:(?a)|(?b))(?c)", - "bc").groups(), (None, 'b', 'c')) - - self.assertEqual(regex.match(r"(?a)(?:(?b)|(?c))(?d)", - "abd").groups(), ('a', 'b', None, 'd')) - self.assertEqual(regex.match(r"(?a)(?:(?b)|(?c))(?d)", - "acd").groups(), ('a', None, 'c', 'd')) - self.assertEqual(regex.match(r"(a)(?:(b)|(c))(d)", "abd").groups(), - ('a', 'b', None, 'd')) - - self.assertEqual(regex.match(r"(a)(?:(b)|(c))(d)", "acd").groups(), - ('a', None, 'c', 'd')) - self.assertEqual(regex.match(r"(a)(?|(b)|(b))(d)", "abd").groups(), - ('a', 'b', 'd')) - self.assertEqual(regex.match(r"(?|(?a)|(?b))(c)", "ac").groups(), - ('a', None, 'c')) - self.assertEqual(regex.match(r"(?|(?a)|(?b))(c)", "bc").groups(), - (None, 'b', 'c')) - self.assertEqual(regex.match(r"(?|(?a)|(?b))(c)", "ac").groups(), - ('a', 'c')) - - self.assertEqual(regex.match(r"(?|(?a)|(?b))(c)", "bc").groups(), - ('b', 'c')) - - self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(?d))(e)", - "abe").groups(), ('a', 'b', 'e')) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(?d))(e)", - "cde").groups(), ('d', 'c', 'e')) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(d))(e)", - "abe").groups(), ('a', 'b', 'e')) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(d))(e)", - "cde").groups(), ('d', 'c', 'e')) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(d))(e)", - "abe").groups(), ('a', 'b', 'e')) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(d))(e)", - "cde").groups(), ('c', 'd', 'e')) - - # Hg issue 87: Allow duplicate names of groups - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", - "abe").groups(), ("a", "b", "e")) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", - "abe").capturesdict(), {"a": ["a"], "b": ["b"]}) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", - "cde").groups(), ("d", None, "e")) - self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", - "cde").capturesdict(), {"a": ["c", "d"], "b": []}) - - def test_set(self): - self.assertEqual(regex.match(r"[a]", "a").span(), (0, 1)) - self.assertEqual(regex.match(r"(?i)[a]", "A").span(), (0, 1)) - self.assertEqual(regex.match(r"[a-b]", r"a").span(), (0, 1)) - self.assertEqual(regex.match(r"(?i)[a-b]", r"A").span(), (0, 1)) - - self.assertEqual(regex.sub(r"(?V0)([][])", r"-", "a[b]c"), "a-b-c") - - self.assertEqual(regex.findall(r"[\p{Alpha}]", "a0"), ["a"]) - self.assertEqual(regex.findall(r"(?i)[\p{Alpha}]", "A0"), ["A"]) - - self.assertEqual(regex.findall(r"[a\p{Alpha}]", "ab0"), ["a", "b"]) - self.assertEqual(regex.findall(r"[a\P{Alpha}]", "ab0"), ["a", "0"]) - self.assertEqual(regex.findall(r"(?i)[a\p{Alpha}]", "ab0"), ["a", - "b"]) - self.assertEqual(regex.findall(r"(?i)[a\P{Alpha}]", "ab0"), ["a", - "0"]) - - self.assertEqual(regex.findall(r"[a-b\p{Alpha}]", "abC0"), ["a", - "b", "C"]) - self.assertEqual(regex.findall(r"(?i)[a-b\p{Alpha}]", "AbC0"), ["A", - "b", "C"]) - - self.assertEqual(regex.findall(r"[\p{Alpha}]", "a0"), ["a"]) - self.assertEqual(regex.findall(r"[\P{Alpha}]", "a0"), ["0"]) - self.assertEqual(regex.findall(r"[^\p{Alpha}]", "a0"), ["0"]) - self.assertEqual(regex.findall(r"[^\P{Alpha}]", "a0"), ["a"]) - - self.assertEqual("".join(regex.findall(r"[^\d-h]", "a^b12c-h")), - 'a^bc') - self.assertEqual("".join(regex.findall(r"[^\dh]", "a^b12c-h")), - 'a^bc-') - self.assertEqual("".join(regex.findall(r"[^h\s\db]", "a^b 12c-h")), - 'a^c-') - self.assertEqual("".join(regex.findall(r"[^b\w]", "a b")), ' ') - self.assertEqual("".join(regex.findall(r"[^b\S]", "a b")), ' ') - self.assertEqual("".join(regex.findall(r"[^8\d]", "a 1b2")), 'a b') - - all_chars = "".join(chr(c) for c in range(0x100)) - self.assertEqual(len(regex.findall(r"\p{ASCII}", all_chars)), 128) - self.assertEqual(len(regex.findall(r"\p{Letter}", all_chars)), - 117) - self.assertEqual(len(regex.findall(r"\p{Digit}", all_chars)), 10) - - # Set operators - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}&&\p{Letter}]", - all_chars)), 52) - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}&&\p{Alnum}&&\p{Letter}]", - all_chars)), 52) - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}&&\p{Alnum}&&\p{Digit}]", - all_chars)), 10) - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}&&\p{Cc}]", - all_chars)), 33) - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}&&\p{Graph}]", - all_chars)), 94) - self.assertEqual(len(regex.findall(r"(?V1)[\p{ASCII}--\p{Cc}]", - all_chars)), 95) - self.assertEqual(len(regex.findall(r"[\p{Letter}\p{Digit}]", - all_chars)), 127) - self.assertEqual(len(regex.findall(r"(?V1)[\p{Letter}||\p{Digit}]", - all_chars)), 127) - self.assertEqual(len(regex.findall(r"\p{HexDigit}", all_chars)), - 22) - self.assertEqual(len(regex.findall(r"(?V1)[\p{HexDigit}~~\p{Digit}]", - all_chars)), 12) - self.assertEqual(len(regex.findall(r"(?V1)[\p{Digit}~~\p{HexDigit}]", - all_chars)), 12) - - self.assertEqual(repr(type(regex.compile(r"(?V0)([][-])"))), - self.PATTERN_CLASS) - self.assertEqual(regex.findall(r"(?V1)[[a-z]--[aei]]", "abc"), ["b", - "c"]) - self.assertEqual(regex.findall(r"(?iV1)[[a-z]--[aei]]", "abc"), ["b", - "c"]) - self.assertEqual(regex.findall(r"(?V1)[\w--a]","abc"), ["b", "c"]) - self.assertEqual(regex.findall(r"(?iV1)[\w--a]","abc"), ["b", "c"]) - - def test_various(self): - tests = [ - # Test ?P< and ?P= extensions. - ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with a digit. - ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with an illegal char. - ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with an illegal char. - - # Same tests, for the ?P= form. - ('(?Pa)(?P=foo_123', 'aa', '', regex.error, - self.MISSING_RPAREN), - ('(?Pa)(?P=1)', 'aa', '1', ascii('a')), - ('(?Pa)(?P=0)', 'aa', '', regex.error, - self.BAD_GROUP_NAME), - ('(?Pa)(?P=-1)', 'aa', '', regex.error, - self.BAD_GROUP_NAME), - ('(?Pa)(?P=!)', 'aa', '', regex.error, - self.BAD_GROUP_NAME), - ('(?Pa)(?P=foo_124)', 'aa', '', regex.error, - self.UNKNOWN_GROUP), # Backref to undefined group. - - ('(?Pa)', 'a', '1', ascii('a')), - ('(?Pa)(?P=foo_123)', 'aa', '1', ascii('a')), - - # Mal-formed \g in pattern treated as literal for compatibility. - (r'(?a)\ga)\g<1>', 'aa', '1', ascii('a')), - (r'(?a)\g', 'aa', '', ascii(None)), - (r'(?a)\g', 'aa', '', regex.error, - self.UNKNOWN_GROUP), # Backref to undefined group. - - ('(?a)', 'a', '1', ascii('a')), - (r'(?a)\g', 'aa', '1', ascii('a')), - - # Test octal escapes. - ('\\1', 'a', '', regex.error, self.INVALID_GROUP_REF), # Backreference. - ('[\\1]', '\1', '0', "'\\x01'"), # Character. - ('\\09', chr(0) + '9', '0', ascii(chr(0) + '9')), - ('\\141', 'a', '0', ascii('a')), - ('(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119', 'abcdefghijklk9', - '0,11', ascii(('abcdefghijklk9', 'k'))), - - # Test \0 is handled everywhere. - (r'\0', '\0', '0', ascii('\0')), - (r'[\0a]', '\0', '0', ascii('\0')), - (r'[a\0]', '\0', '0', ascii('\0')), - (r'[^a\0]', '\0', '', ascii(None)), - - # Test various letter escapes. - (r'\a[\b]\f\n\r\t\v', '\a\b\f\n\r\t\v', '0', - ascii('\a\b\f\n\r\t\v')), - (r'[\a][\b][\f][\n][\r][\t][\v]', '\a\b\f\n\r\t\v', '0', - ascii('\a\b\f\n\r\t\v')), - (r'\xff', '\377', '0', ascii(chr(255))), - - # New \x semantics. - (r'\x00ffffffffffffff', '\377', '', ascii(None)), - (r'\x00f', '\017', '', ascii(None)), - (r'\x00fe', '\376', '', ascii(None)), - - (r'\x00ff', '\377', '', ascii(None)), - (r'\t\n\v\r\f\a\g', '\t\n\v\r\f\ag', '0', ascii('\t\n\v\r\f\ag')), - ('\t\n\v\r\f\a\\g', '\t\n\v\r\f\ag', '0', ascii('\t\n\v\r\f\ag')), - (r'\t\n\v\r\f\a', '\t\n\v\r\f\a', '0', ascii(chr(9) + chr(10) + - chr(11) + chr(13) + chr(12) + chr(7))), - (r'[\t][\n][\v][\r][\f][\b]', '\t\n\v\r\f\b', '0', - ascii('\t\n\v\r\f\b')), - - (r"^\w+=(\\[\000-\277]|[^\n\\])*", - "SRC=eval.c g.c blah blah blah \\\\\n\tapes.c", '0', - ascii("SRC=eval.c g.c blah blah blah \\\\")), - - # Test that . only matches \n in DOTALL mode. - ('a.b', 'acb', '0', ascii('acb')), - ('a.b', 'a\nb', '', ascii(None)), - ('a.*b', 'acc\nccb', '', ascii(None)), - ('a.{4,5}b', 'acc\nccb', '', ascii(None)), - ('a.b', 'a\rb', '0', ascii('a\rb')), - # Changed to positional flags in regex 2023.12.23. - ('a.b(?s)', 'a\nb', '', ascii(None)), - ('(?s)a.b', 'a\nb', '0', ascii('a\nb')), - ('a.*(?s)b', 'acc\nccb', '', ascii(None)), - ('(?s)a.*b', 'acc\nccb', '0', ascii('acc\nccb')), - ('(?s)a.{4,5}b', 'acc\nccb', '0', ascii('acc\nccb')), - - (')', '', '', regex.error, self.TRAILING_CHARS), # Unmatched right bracket. - ('', '', '0', "''"), # Empty pattern. - ('abc', 'abc', '0', ascii('abc')), - ('abc', 'xbc', '', ascii(None)), - ('abc', 'axc', '', ascii(None)), - ('abc', 'abx', '', ascii(None)), - ('abc', 'xabcy', '0', ascii('abc')), - ('abc', 'ababc', '0', ascii('abc')), - ('ab*c', 'abc', '0', ascii('abc')), - ('ab*bc', 'abc', '0', ascii('abc')), - - ('ab*bc', 'abbc', '0', ascii('abbc')), - ('ab*bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab+bc', 'abbc', '0', ascii('abbc')), - ('ab+bc', 'abc', '', ascii(None)), - ('ab+bc', 'abq', '', ascii(None)), - ('ab+bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab?bc', 'abbc', '0', ascii('abbc')), - ('ab?bc', 'abc', '0', ascii('abc')), - ('ab?bc', 'abbbbc', '', ascii(None)), - ('ab?c', 'abc', '0', ascii('abc')), - - ('^abc$', 'abc', '0', ascii('abc')), - ('^abc$', 'abcc', '', ascii(None)), - ('^abc', 'abcc', '0', ascii('abc')), - ('^abc$', 'aabc', '', ascii(None)), - ('abc$', 'aabc', '0', ascii('abc')), - ('^', 'abc', '0', ascii('')), - ('$', 'abc', '0', ascii('')), - ('a.c', 'abc', '0', ascii('abc')), - ('a.c', 'axc', '0', ascii('axc')), - ('a.*c', 'axyzc', '0', ascii('axyzc')), - - ('a.*c', 'axyzd', '', ascii(None)), - ('a[bc]d', 'abc', '', ascii(None)), - ('a[bc]d', 'abd', '0', ascii('abd')), - ('a[b-d]e', 'abd', '', ascii(None)), - ('a[b-d]e', 'ace', '0', ascii('ace')), - ('a[b-d]', 'aac', '0', ascii('ac')), - ('a[-b]', 'a-', '0', ascii('a-')), - ('a[\\-b]', 'a-', '0', ascii('a-')), - ('a[b-]', 'a-', '0', ascii('a-')), - ('a[]b', '-', '', regex.error, self.BAD_SET), - - ('a[', '-', '', regex.error, self.BAD_SET), - ('a\\', '-', '', regex.error, self.BAD_ESCAPE), - ('abc)', '-', '', regex.error, self.TRAILING_CHARS), - ('(abc', '-', '', regex.error, self.MISSING_RPAREN), - ('a]', 'a]', '0', ascii('a]')), - ('a[]]b', 'a]b', '0', ascii('a]b')), - ('a[]]b', 'a]b', '0', ascii('a]b')), - ('a[^bc]d', 'aed', '0', ascii('aed')), - ('a[^bc]d', 'abd', '', ascii(None)), - ('a[^-b]c', 'adc', '0', ascii('adc')), - - ('a[^-b]c', 'a-c', '', ascii(None)), - ('a[^]b]c', 'a]c', '', ascii(None)), - ('a[^]b]c', 'adc', '0', ascii('adc')), - ('\\ba\\b', 'a-', '0', ascii('a')), - ('\\ba\\b', '-a', '0', ascii('a')), - ('\\ba\\b', '-a-', '0', ascii('a')), - ('\\by\\b', 'xy', '', ascii(None)), - ('\\by\\b', 'yz', '', ascii(None)), - ('\\by\\b', 'xyz', '', ascii(None)), - ('x\\b', 'xyz', '', ascii(None)), - - ('x\\B', 'xyz', '0', ascii('x')), - ('\\Bz', 'xyz', '0', ascii('z')), - ('z\\B', 'xyz', '', ascii(None)), - ('\\Bx', 'xyz', '', ascii(None)), - ('\\Ba\\B', 'a-', '', ascii(None)), - ('\\Ba\\B', '-a', '', ascii(None)), - ('\\Ba\\B', '-a-', '', ascii(None)), - ('\\By\\B', 'xy', '', ascii(None)), - ('\\By\\B', 'yz', '', ascii(None)), - ('\\By\\b', 'xy', '0', ascii('y')), - - ('\\by\\B', 'yz', '0', ascii('y')), - ('\\By\\B', 'xyz', '0', ascii('y')), - ('ab|cd', 'abc', '0', ascii('ab')), - ('ab|cd', 'abcd', '0', ascii('ab')), - ('()ef', 'def', '0,1', ascii(('ef', ''))), - ('$b', 'b', '', ascii(None)), - ('a\\(b', 'a(b', '', ascii(('a(b',))), - ('a\\(*b', 'ab', '0', ascii('ab')), - ('a\\(*b', 'a((b', '0', ascii('a((b')), - ('a\\\\b', 'a\\b', '0', ascii('a\\b')), - - ('((a))', 'abc', '0,1,2', ascii(('a', 'a', 'a'))), - ('(a)b(c)', 'abc', '0,1,2', ascii(('abc', 'a', 'c'))), - ('a+b+c', 'aabbabc', '0', ascii('abc')), - ('(a+|b)*', 'ab', '0,1', ascii(('ab', 'b'))), - ('(a+|b)+', 'ab', '0,1', ascii(('ab', 'b'))), - ('(a+|b)?', 'ab', '0,1', ascii(('a', 'a'))), - (')(', '-', '', regex.error, self.TRAILING_CHARS), - ('[^ab]*', 'cde', '0', ascii('cde')), - ('abc', '', '', ascii(None)), - ('a*', '', '0', ascii('')), - - ('a|b|c|d|e', 'e', '0', ascii('e')), - ('(a|b|c|d|e)f', 'ef', '0,1', ascii(('ef', 'e'))), - ('abcd*efg', 'abcdefg', '0', ascii('abcdefg')), - ('ab*', 'xabyabbbz', '0', ascii('ab')), - ('ab*', 'xayabbbz', '0', ascii('a')), - ('(ab|cd)e', 'abcde', '0,1', ascii(('cde', 'cd'))), - ('[abhgefdc]ij', 'hij', '0', ascii('hij')), - ('^(ab|cd)e', 'abcde', '', ascii(None)), - ('(abc|)ef', 'abcdef', '0,1', ascii(('ef', ''))), - ('(a|b)c*d', 'abcd', '0,1', ascii(('bcd', 'b'))), - - ('(ab|ab*)bc', 'abc', '0,1', ascii(('abc', 'a'))), - ('a([bc]*)c*', 'abc', '0,1', ascii(('abc', 'bc'))), - ('a([bc]*)(c*d)', 'abcd', '0,1,2', ascii(('abcd', 'bc', 'd'))), - ('a([bc]+)(c*d)', 'abcd', '0,1,2', ascii(('abcd', 'bc', 'd'))), - ('a([bc]*)(c+d)', 'abcd', '0,1,2', ascii(('abcd', 'b', 'cd'))), - ('a[bcd]*dcdcde', 'adcdcde', '0', ascii('adcdcde')), - ('a[bcd]+dcdcde', 'adcdcde', '', ascii(None)), - ('(ab|a)b*c', 'abc', '0,1', ascii(('abc', 'ab'))), - ('((a)(b)c)(d)', 'abcd', '1,2,3,4', ascii(('abc', 'a', 'b', 'd'))), - ('[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', '0', ascii('alpha')), - - ('^a(bc+|b[eh])g|.h$', 'abh', '0,1', ascii(('bh', None))), - ('(bc+d$|ef*g.|h?i(j|k))', 'effgz', '0,1,2', ascii(('effgz', - 'effgz', None))), - ('(bc+d$|ef*g.|h?i(j|k))', 'ij', '0,1,2', ascii(('ij', 'ij', - 'j'))), - ('(bc+d$|ef*g.|h?i(j|k))', 'effg', '', ascii(None)), - ('(bc+d$|ef*g.|h?i(j|k))', 'bcdd', '', ascii(None)), - ('(bc+d$|ef*g.|h?i(j|k))', 'reffgz', '0,1,2', ascii(('effgz', - 'effgz', None))), - ('(((((((((a)))))))))', 'a', '0', ascii('a')), - ('multiple words of text', 'uh-uh', '', ascii(None)), - ('multiple words', 'multiple words, yeah', '0', - ascii('multiple words')), - ('(.*)c(.*)', 'abcde', '0,1,2', ascii(('abcde', 'ab', 'de'))), - - ('\\((.*), (.*)\\)', '(a, b)', '2,1', ascii(('b', 'a'))), - ('[k]', 'ab', '', ascii(None)), - ('a[-]?c', 'ac', '0', ascii('ac')), - ('(abc)\\1', 'abcabc', '1', ascii('abc')), - ('([a-c]*)\\1', 'abcabc', '1', ascii('abc')), - ('^(.+)?B', 'AB', '1', ascii('A')), - ('(a+).\\1$', 'aaaaa', '0,1', ascii(('aaaaa', 'aa'))), - ('^(a+).\\1$', 'aaaa', '', ascii(None)), - ('(abc)\\1', 'abcabc', '0,1', ascii(('abcabc', 'abc'))), - ('([a-c]+)\\1', 'abcabc', '0,1', ascii(('abcabc', 'abc'))), - - ('(a)\\1', 'aa', '0,1', ascii(('aa', 'a'))), - ('(a+)\\1', 'aa', '0,1', ascii(('aa', 'a'))), - ('(a+)+\\1', 'aa', '0,1', ascii(('aa', 'a'))), - ('(a).+\\1', 'aba', '0,1', ascii(('aba', 'a'))), - ('(a)ba*\\1', 'aba', '0,1', ascii(('aba', 'a'))), - ('(aa|a)a\\1$', 'aaa', '0,1', ascii(('aaa', 'a'))), - ('(a|aa)a\\1$', 'aaa', '0,1', ascii(('aaa', 'a'))), - ('(a+)a\\1$', 'aaa', '0,1', ascii(('aaa', 'a'))), - ('([abc]*)\\1', 'abcabc', '0,1', ascii(('abcabc', 'abc'))), - ('(a)(b)c|ab', 'ab', '0,1,2', ascii(('ab', None, None))), - - ('(a)+x', 'aaax', '0,1', ascii(('aaax', 'a'))), - ('([ac])+x', 'aacx', '0,1', ascii(('aacx', 'c'))), - ('([^/]*/)*sub1/', 'd:msgs/tdir/sub1/trial/away.cpp', '0,1', - ascii(('d:msgs/tdir/sub1/', 'tdir/'))), - ('([^.]*)\\.([^:]*):[T ]+(.*)', 'track1.title:TBlah blah blah', - '0,1,2,3', ascii(('track1.title:TBlah blah blah', 'track1', - 'title', 'Blah blah blah'))), - ('([^N]*N)+', 'abNNxyzN', '0,1', ascii(('abNNxyzN', 'xyzN'))), - ('([^N]*N)+', 'abNNxyz', '0,1', ascii(('abNN', 'N'))), - ('([abc]*)x', 'abcx', '0,1', ascii(('abcx', 'abc'))), - ('([abc]*)x', 'abc', '', ascii(None)), - ('([xyz]*)x', 'abcx', '0,1', ascii(('x', ''))), - ('(a)+b|aac', 'aac', '0,1', ascii(('aac', None))), - - # Test symbolic groups. - ('(?Paaa)a', 'aaaa', '', regex.error, self.BAD_GROUP_NAME), - ('(?Paaa)a', 'aaaa', '0,id', ascii(('aaaa', 'aaa'))), - ('(?Paa)(?P=id)', 'aaaa', '0,id', ascii(('aaaa', 'aa'))), - ('(?Paa)(?P=xd)', 'aaaa', '', regex.error, self.UNKNOWN_GROUP), - - # Character properties. - (r"\g", "g", '0', ascii('g')), - (r"\g<1>", "g", '', regex.error, self.INVALID_GROUP_REF), - (r"(.)\g<1>", "gg", '0', ascii('gg')), - (r"(.)\g<1>", "gg", '', ascii(('gg', 'g'))), - (r"\N", "N", '0', ascii('N')), - (r"\N{LATIN SMALL LETTER A}", "a", '0', ascii('a')), - (r"\p", "p", '0', ascii('p')), - (r"\p{Ll}", "a", '0', ascii('a')), - (r"\P", "P", '0', ascii('P')), - (r"\P{Lu}", "p", '0', ascii('p')), - - # All tests from Perl. - ('abc', 'abc', '0', ascii('abc')), - ('abc', 'xbc', '', ascii(None)), - ('abc', 'axc', '', ascii(None)), - ('abc', 'abx', '', ascii(None)), - ('abc', 'xabcy', '0', ascii('abc')), - ('abc', 'ababc', '0', ascii('abc')), - - ('ab*c', 'abc', '0', ascii('abc')), - ('ab*bc', 'abc', '0', ascii('abc')), - ('ab*bc', 'abbc', '0', ascii('abbc')), - ('ab*bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab{0,}bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab+bc', 'abbc', '0', ascii('abbc')), - ('ab+bc', 'abc', '', ascii(None)), - ('ab+bc', 'abq', '', ascii(None)), - ('ab{1,}bc', 'abq', '', ascii(None)), - ('ab+bc', 'abbbbc', '0', ascii('abbbbc')), - - ('ab{1,}bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab{1,3}bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab{3,4}bc', 'abbbbc', '0', ascii('abbbbc')), - ('ab{4,5}bc', 'abbbbc', '', ascii(None)), - ('ab?bc', 'abbc', '0', ascii('abbc')), - ('ab?bc', 'abc', '0', ascii('abc')), - ('ab{0,1}bc', 'abc', '0', ascii('abc')), - ('ab?bc', 'abbbbc', '', ascii(None)), - ('ab?c', 'abc', '0', ascii('abc')), - ('ab{0,1}c', 'abc', '0', ascii('abc')), - - ('^abc$', 'abc', '0', ascii('abc')), - ('^abc$', 'abcc', '', ascii(None)), - ('^abc', 'abcc', '0', ascii('abc')), - ('^abc$', 'aabc', '', ascii(None)), - ('abc$', 'aabc', '0', ascii('abc')), - ('^', 'abc', '0', ascii('')), - ('$', 'abc', '0', ascii('')), - ('a.c', 'abc', '0', ascii('abc')), - ('a.c', 'axc', '0', ascii('axc')), - ('a.*c', 'axyzc', '0', ascii('axyzc')), - - ('a.*c', 'axyzd', '', ascii(None)), - ('a[bc]d', 'abc', '', ascii(None)), - ('a[bc]d', 'abd', '0', ascii('abd')), - ('a[b-d]e', 'abd', '', ascii(None)), - ('a[b-d]e', 'ace', '0', ascii('ace')), - ('a[b-d]', 'aac', '0', ascii('ac')), - ('a[-b]', 'a-', '0', ascii('a-')), - ('a[b-]', 'a-', '0', ascii('a-')), - ('a[b-a]', '-', '', regex.error, self.BAD_CHAR_RANGE), - ('a[]b', '-', '', regex.error, self.BAD_SET), - - ('a[', '-', '', regex.error, self.BAD_SET), - ('a]', 'a]', '0', ascii('a]')), - ('a[]]b', 'a]b', '0', ascii('a]b')), - ('a[^bc]d', 'aed', '0', ascii('aed')), - ('a[^bc]d', 'abd', '', ascii(None)), - ('a[^-b]c', 'adc', '0', ascii('adc')), - ('a[^-b]c', 'a-c', '', ascii(None)), - ('a[^]b]c', 'a]c', '', ascii(None)), - ('a[^]b]c', 'adc', '0', ascii('adc')), - ('ab|cd', 'abc', '0', ascii('ab')), - - ('ab|cd', 'abcd', '0', ascii('ab')), - ('()ef', 'def', '0,1', ascii(('ef', ''))), - ('*a', '-', '', regex.error, self.NOTHING_TO_REPEAT), - ('(*)b', '-', '', regex.error, self.NOTHING_TO_REPEAT), - ('$b', 'b', '', ascii(None)), - ('a\\', '-', '', regex.error, self.BAD_ESCAPE), - ('a\\(b', 'a(b', '', ascii(('a(b',))), - ('a\\(*b', 'ab', '0', ascii('ab')), - ('a\\(*b', 'a((b', '0', ascii('a((b')), - ('a\\\\b', 'a\\b', '0', ascii('a\\b')), - - ('abc)', '-', '', regex.error, self.TRAILING_CHARS), - ('(abc', '-', '', regex.error, self.MISSING_RPAREN), - ('((a))', 'abc', '0,1,2', ascii(('a', 'a', 'a'))), - ('(a)b(c)', 'abc', '0,1,2', ascii(('abc', 'a', 'c'))), - ('a+b+c', 'aabbabc', '0', ascii('abc')), - ('a{1,}b{1,}c', 'aabbabc', '0', ascii('abc')), - ('a**', '-', '', regex.error, self.MULTIPLE_REPEAT), - ('a.+?c', 'abcabc', '0', ascii('abc')), - ('(a+|b)*', 'ab', '0,1', ascii(('ab', 'b'))), - ('(a+|b){0,}', 'ab', '0,1', ascii(('ab', 'b'))), - - ('(a+|b)+', 'ab', '0,1', ascii(('ab', 'b'))), - ('(a+|b){1,}', 'ab', '0,1', ascii(('ab', 'b'))), - ('(a+|b)?', 'ab', '0,1', ascii(('a', 'a'))), - ('(a+|b){0,1}', 'ab', '0,1', ascii(('a', 'a'))), - (')(', '-', '', regex.error, self.TRAILING_CHARS), - ('[^ab]*', 'cde', '0', ascii('cde')), - ('abc', '', '', ascii(None)), - ('a*', '', '0', ascii('')), - ('([abc])*d', 'abbbcd', '0,1', ascii(('abbbcd', 'c'))), - ('([abc])*bcd', 'abcd', '0,1', ascii(('abcd', 'a'))), - - ('a|b|c|d|e', 'e', '0', ascii('e')), - ('(a|b|c|d|e)f', 'ef', '0,1', ascii(('ef', 'e'))), - ('abcd*efg', 'abcdefg', '0', ascii('abcdefg')), - ('ab*', 'xabyabbbz', '0', ascii('ab')), - ('ab*', 'xayabbbz', '0', ascii('a')), - ('(ab|cd)e', 'abcde', '0,1', ascii(('cde', 'cd'))), - ('[abhgefdc]ij', 'hij', '0', ascii('hij')), - ('^(ab|cd)e', 'abcde', '', ascii(None)), - ('(abc|)ef', 'abcdef', '0,1', ascii(('ef', ''))), - ('(a|b)c*d', 'abcd', '0,1', ascii(('bcd', 'b'))), - - ('(ab|ab*)bc', 'abc', '0,1', ascii(('abc', 'a'))), - ('a([bc]*)c*', 'abc', '0,1', ascii(('abc', 'bc'))), - ('a([bc]*)(c*d)', 'abcd', '0,1,2', ascii(('abcd', 'bc', 'd'))), - ('a([bc]+)(c*d)', 'abcd', '0,1,2', ascii(('abcd', 'bc', 'd'))), - ('a([bc]*)(c+d)', 'abcd', '0,1,2', ascii(('abcd', 'b', 'cd'))), - ('a[bcd]*dcdcde', 'adcdcde', '0', ascii('adcdcde')), - ('a[bcd]+dcdcde', 'adcdcde', '', ascii(None)), - ('(ab|a)b*c', 'abc', '0,1', ascii(('abc', 'ab'))), - ('((a)(b)c)(d)', 'abcd', '1,2,3,4', ascii(('abc', 'a', 'b', 'd'))), - ('[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', '0', ascii('alpha')), - - ('^a(bc+|b[eh])g|.h$', 'abh', '0,1', ascii(('bh', None))), - ('(bc+d$|ef*g.|h?i(j|k))', 'effgz', '0,1,2', ascii(('effgz', - 'effgz', None))), - ('(bc+d$|ef*g.|h?i(j|k))', 'ij', '0,1,2', ascii(('ij', 'ij', - 'j'))), - ('(bc+d$|ef*g.|h?i(j|k))', 'effg', '', ascii(None)), - ('(bc+d$|ef*g.|h?i(j|k))', 'bcdd', '', ascii(None)), - ('(bc+d$|ef*g.|h?i(j|k))', 'reffgz', '0,1,2', ascii(('effgz', - 'effgz', None))), - ('((((((((((a))))))))))', 'a', '10', ascii('a')), - ('((((((((((a))))))))))\\10', 'aa', '0', ascii('aa')), - - # Python does not have the same rules for \\41 so this is a syntax error - # ('((((((((((a))))))))))\\41', 'aa', '', ascii(None)), - # ('((((((((((a))))))))))\\41', 'a!', '0', ascii('a!')), - ('((((((((((a))))))))))\\41', '', '', regex.error, - self.INVALID_GROUP_REF), - ('(?i)((((((((((a))))))))))\\41', '', '', regex.error, - self.INVALID_GROUP_REF), - - ('(((((((((a)))))))))', 'a', '0', ascii('a')), - ('multiple words of text', 'uh-uh', '', ascii(None)), - ('multiple words', 'multiple words, yeah', '0', - ascii('multiple words')), - ('(.*)c(.*)', 'abcde', '0,1,2', ascii(('abcde', 'ab', 'de'))), - ('\\((.*), (.*)\\)', '(a, b)', '2,1', ascii(('b', 'a'))), - ('[k]', 'ab', '', ascii(None)), - ('a[-]?c', 'ac', '0', ascii('ac')), - ('(abc)\\1', 'abcabc', '1', ascii('abc')), - ('([a-c]*)\\1', 'abcabc', '1', ascii('abc')), - ('(?i)abc', 'ABC', '0', ascii('ABC')), - - ('(?i)abc', 'XBC', '', ascii(None)), - ('(?i)abc', 'AXC', '', ascii(None)), - ('(?i)abc', 'ABX', '', ascii(None)), - ('(?i)abc', 'XABCY', '0', ascii('ABC')), - ('(?i)abc', 'ABABC', '0', ascii('ABC')), - ('(?i)ab*c', 'ABC', '0', ascii('ABC')), - ('(?i)ab*bc', 'ABC', '0', ascii('ABC')), - ('(?i)ab*bc', 'ABBC', '0', ascii('ABBC')), - ('(?i)ab*?bc', 'ABBBBC', '0', ascii('ABBBBC')), - ('(?i)ab{0,}?bc', 'ABBBBC', '0', ascii('ABBBBC')), - - ('(?i)ab+?bc', 'ABBC', '0', ascii('ABBC')), - ('(?i)ab+bc', 'ABC', '', ascii(None)), - ('(?i)ab+bc', 'ABQ', '', ascii(None)), - ('(?i)ab{1,}bc', 'ABQ', '', ascii(None)), - ('(?i)ab+bc', 'ABBBBC', '0', ascii('ABBBBC')), - ('(?i)ab{1,}?bc', 'ABBBBC', '0', ascii('ABBBBC')), - ('(?i)ab{1,3}?bc', 'ABBBBC', '0', ascii('ABBBBC')), - ('(?i)ab{3,4}?bc', 'ABBBBC', '0', ascii('ABBBBC')), - ('(?i)ab{4,5}?bc', 'ABBBBC', '', ascii(None)), - ('(?i)ab??bc', 'ABBC', '0', ascii('ABBC')), - - ('(?i)ab??bc', 'ABC', '0', ascii('ABC')), - ('(?i)ab{0,1}?bc', 'ABC', '0', ascii('ABC')), - ('(?i)ab??bc', 'ABBBBC', '', ascii(None)), - ('(?i)ab??c', 'ABC', '0', ascii('ABC')), - ('(?i)ab{0,1}?c', 'ABC', '0', ascii('ABC')), - ('(?i)^abc$', 'ABC', '0', ascii('ABC')), - ('(?i)^abc$', 'ABCC', '', ascii(None)), - ('(?i)^abc', 'ABCC', '0', ascii('ABC')), - ('(?i)^abc$', 'AABC', '', ascii(None)), - ('(?i)abc$', 'AABC', '0', ascii('ABC')), - - ('(?i)^', 'ABC', '0', ascii('')), - ('(?i)$', 'ABC', '0', ascii('')), - ('(?i)a.c', 'ABC', '0', ascii('ABC')), - ('(?i)a.c', 'AXC', '0', ascii('AXC')), - ('(?i)a.*?c', 'AXYZC', '0', ascii('AXYZC')), - ('(?i)a.*c', 'AXYZD', '', ascii(None)), - ('(?i)a[bc]d', 'ABC', '', ascii(None)), - ('(?i)a[bc]d', 'ABD', '0', ascii('ABD')), - ('(?i)a[b-d]e', 'ABD', '', ascii(None)), - ('(?i)a[b-d]e', 'ACE', '0', ascii('ACE')), - - ('(?i)a[b-d]', 'AAC', '0', ascii('AC')), - ('(?i)a[-b]', 'A-', '0', ascii('A-')), - ('(?i)a[b-]', 'A-', '0', ascii('A-')), - ('(?i)a[b-a]', '-', '', regex.error, self.BAD_CHAR_RANGE), - ('(?i)a[]b', '-', '', regex.error, self.BAD_SET), - ('(?i)a[', '-', '', regex.error, self.BAD_SET), - ('(?i)a]', 'A]', '0', ascii('A]')), - ('(?i)a[]]b', 'A]B', '0', ascii('A]B')), - ('(?i)a[^bc]d', 'AED', '0', ascii('AED')), - ('(?i)a[^bc]d', 'ABD', '', ascii(None)), - - ('(?i)a[^-b]c', 'ADC', '0', ascii('ADC')), - ('(?i)a[^-b]c', 'A-C', '', ascii(None)), - ('(?i)a[^]b]c', 'A]C', '', ascii(None)), - ('(?i)a[^]b]c', 'ADC', '0', ascii('ADC')), - ('(?i)ab|cd', 'ABC', '0', ascii('AB')), - ('(?i)ab|cd', 'ABCD', '0', ascii('AB')), - ('(?i)()ef', 'DEF', '0,1', ascii(('EF', ''))), - ('(?i)*a', '-', '', regex.error, self.NOTHING_TO_REPEAT), - ('(?i)(*)b', '-', '', regex.error, self.NOTHING_TO_REPEAT), - ('(?i)$b', 'B', '', ascii(None)), - - ('(?i)a\\', '-', '', regex.error, self.BAD_ESCAPE), - ('(?i)a\\(b', 'A(B', '', ascii(('A(B',))), - ('(?i)a\\(*b', 'AB', '0', ascii('AB')), - ('(?i)a\\(*b', 'A((B', '0', ascii('A((B')), - ('(?i)a\\\\b', 'A\\B', '0', ascii('A\\B')), - ('(?i)abc)', '-', '', regex.error, self.TRAILING_CHARS), - ('(?i)(abc', '-', '', regex.error, self.MISSING_RPAREN), - ('(?i)((a))', 'ABC', '0,1,2', ascii(('A', 'A', 'A'))), - ('(?i)(a)b(c)', 'ABC', '0,1,2', ascii(('ABC', 'A', 'C'))), - ('(?i)a+b+c', 'AABBABC', '0', ascii('ABC')), - - ('(?i)a{1,}b{1,}c', 'AABBABC', '0', ascii('ABC')), - ('(?i)a**', '-', '', regex.error, self.MULTIPLE_REPEAT), - ('(?i)a.+?c', 'ABCABC', '0', ascii('ABC')), - ('(?i)a.*?c', 'ABCABC', '0', ascii('ABC')), - ('(?i)a.{0,5}?c', 'ABCABC', '0', ascii('ABC')), - ('(?i)(a+|b)*', 'AB', '0,1', ascii(('AB', 'B'))), - ('(?i)(a+|b){0,}', 'AB', '0,1', ascii(('AB', 'B'))), - ('(?i)(a+|b)+', 'AB', '0,1', ascii(('AB', 'B'))), - ('(?i)(a+|b){1,}', 'AB', '0,1', ascii(('AB', 'B'))), - ('(?i)(a+|b)?', 'AB', '0,1', ascii(('A', 'A'))), - - ('(?i)(a+|b){0,1}', 'AB', '0,1', ascii(('A', 'A'))), - ('(?i)(a+|b){0,1}?', 'AB', '0,1', ascii(('', None))), - ('(?i))(', '-', '', regex.error, self.TRAILING_CHARS), - ('(?i)[^ab]*', 'CDE', '0', ascii('CDE')), - ('(?i)abc', '', '', ascii(None)), - ('(?i)a*', '', '0', ascii('')), - ('(?i)([abc])*d', 'ABBBCD', '0,1', ascii(('ABBBCD', 'C'))), - ('(?i)([abc])*bcd', 'ABCD', '0,1', ascii(('ABCD', 'A'))), - ('(?i)a|b|c|d|e', 'E', '0', ascii('E')), - ('(?i)(a|b|c|d|e)f', 'EF', '0,1', ascii(('EF', 'E'))), - - ('(?i)abcd*efg', 'ABCDEFG', '0', ascii('ABCDEFG')), - ('(?i)ab*', 'XABYABBBZ', '0', ascii('AB')), - ('(?i)ab*', 'XAYABBBZ', '0', ascii('A')), - ('(?i)(ab|cd)e', 'ABCDE', '0,1', ascii(('CDE', 'CD'))), - ('(?i)[abhgefdc]ij', 'HIJ', '0', ascii('HIJ')), - ('(?i)^(ab|cd)e', 'ABCDE', '', ascii(None)), - ('(?i)(abc|)ef', 'ABCDEF', '0,1', ascii(('EF', ''))), - ('(?i)(a|b)c*d', 'ABCD', '0,1', ascii(('BCD', 'B'))), - ('(?i)(ab|ab*)bc', 'ABC', '0,1', ascii(('ABC', 'A'))), - ('(?i)a([bc]*)c*', 'ABC', '0,1', ascii(('ABC', 'BC'))), - - ('(?i)a([bc]*)(c*d)', 'ABCD', '0,1,2', ascii(('ABCD', 'BC', 'D'))), - ('(?i)a([bc]+)(c*d)', 'ABCD', '0,1,2', ascii(('ABCD', 'BC', 'D'))), - ('(?i)a([bc]*)(c+d)', 'ABCD', '0,1,2', ascii(('ABCD', 'B', 'CD'))), - ('(?i)a[bcd]*dcdcde', 'ADCDCDE', '0', ascii('ADCDCDE')), - ('(?i)a[bcd]+dcdcde', 'ADCDCDE', '', ascii(None)), - ('(?i)(ab|a)b*c', 'ABC', '0,1', ascii(('ABC', 'AB'))), - ('(?i)((a)(b)c)(d)', 'ABCD', '1,2,3,4', ascii(('ABC', 'A', 'B', - 'D'))), - ('(?i)[a-zA-Z_][a-zA-Z0-9_]*', 'ALPHA', '0', ascii('ALPHA')), - ('(?i)^a(bc+|b[eh])g|.h$', 'ABH', '0,1', ascii(('BH', None))), - ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'EFFGZ', '0,1,2', ascii(('EFFGZ', - 'EFFGZ', None))), - - ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'IJ', '0,1,2', ascii(('IJ', 'IJ', - 'J'))), - ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'EFFG', '', ascii(None)), - ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'BCDD', '', ascii(None)), - ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'REFFGZ', '0,1,2', ascii(('EFFGZ', - 'EFFGZ', None))), - ('(?i)((((((((((a))))))))))', 'A', '10', ascii('A')), - ('(?i)((((((((((a))))))))))\\10', 'AA', '0', ascii('AA')), - #('(?i)((((((((((a))))))))))\\41', 'AA', '', ascii(None)), - #('(?i)((((((((((a))))))))))\\41', 'A!', '0', ascii('A!')), - ('(?i)(((((((((a)))))))))', 'A', '0', ascii('A')), - ('(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))', 'A', '1', - ascii('A')), - ('(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))', 'C', '1', - ascii('C')), - ('(?i)multiple words of text', 'UH-UH', '', ascii(None)), - - ('(?i)multiple words', 'MULTIPLE WORDS, YEAH', '0', - ascii('MULTIPLE WORDS')), - ('(?i)(.*)c(.*)', 'ABCDE', '0,1,2', ascii(('ABCDE', 'AB', 'DE'))), - ('(?i)\\((.*), (.*)\\)', '(A, B)', '2,1', ascii(('B', 'A'))), - ('(?i)[k]', 'AB', '', ascii(None)), - # ('(?i)abcd', 'ABCD', SUCCEED, 'found+"-"+\\found+"-"+\\\\found', ascii(ABCD-$&-\\ABCD)), - # ('(?i)a(bc)d', 'ABCD', SUCCEED, 'g1+"-"+\\g1+"-"+\\\\g1', ascii(BC-$1-\\BC)), - ('(?i)a[-]?c', 'AC', '0', ascii('AC')), - ('(?i)(abc)\\1', 'ABCABC', '1', ascii('ABC')), - ('(?i)([a-c]*)\\1', 'ABCABC', '1', ascii('ABC')), - ('a(?!b).', 'abad', '0', ascii('ad')), - ('a(?=d).', 'abad', '0', ascii('ad')), - ('a(?=c|d).', 'abad', '0', ascii('ad')), - - ('a(?:b|c|d)(.)', 'ace', '1', ascii('e')), - ('a(?:b|c|d)*(.)', 'ace', '1', ascii('e')), - ('a(?:b|c|d)+?(.)', 'ace', '1', ascii('e')), - ('a(?:b|(c|e){1,2}?|d)+?(.)', 'ace', '1,2', ascii(('c', 'e'))), - - # Lookbehind: split by : but not if it is escaped by -. - ('(?]*?b', 'a>b', '', ascii(None)), - # Bug 490573: minimizing repeat problem. - (r'^a*?$', 'foo', '', ascii(None)), - # Bug 470582: nested groups problem. - (r'^((a)c)?(ab)$', 'ab', '1,2,3', ascii((None, None, 'ab'))), - # Another minimizing repeat problem (capturing groups in assertions). - ('^([ab]*?)(?=(b)?)c', 'abc', '1,2', ascii(('ab', None))), - ('^([ab]*?)(?!(b))c', 'abc', '1,2', ascii(('ab', None))), - ('^([ab]*?)(?(.){0,2})d", "abcd").captures(1), - ['b', 'c']) - self.assertEqual(regex.search(r"(.)+", "a").captures(1), ['a']) - - def test_guards(self): - m = regex.search(r"(X.*?Y\s*){3}(X\s*)+AB:", - "XY\nX Y\nX Y\nXY\nXX AB:") - self.assertEqual(m.span(0, 1, 2), ((3, 21), (12, 15), (16, 18))) - - m = regex.search(r"(X.*?Y\s*){3,}(X\s*)+AB:", - "XY\nX Y\nX Y\nXY\nXX AB:") - self.assertEqual(m.span(0, 1, 2), ((0, 21), (12, 15), (16, 18))) - - m = regex.search(r'\d{4}(\s*\w)?\W*((?!\d)\w){2}', "9999XX") - self.assertEqual(m.span(0, 1, 2), ((0, 6), (-1, -1), (5, 6))) - - m = regex.search(r'A\s*?.*?(\n+.*?\s*?){0,2}\(X', 'A\n1\nS\n1 (X') - self.assertEqual(m.span(0, 1), ((0, 10), (5, 8))) - - m = regex.search(r'Derde\s*:', 'aaaaaa:\nDerde:') - self.assertEqual(m.span(), (8, 14)) - m = regex.search(r'Derde\s*:', 'aaaaa:\nDerde:') - self.assertEqual(m.span(), (7, 13)) - - def test_turkic(self): - # Turkish has dotted and dotless I/i. - pairs = "I=i;I=\u0131;i=\u0130" - - all_chars = set() - matching = set() - for pair in pairs.split(";"): - ch1, ch2 = pair.split("=") - all_chars.update((ch1, ch2)) - matching.add((ch1, ch1)) - matching.add((ch1, ch2)) - matching.add((ch2, ch1)) - matching.add((ch2, ch2)) - - for ch1 in all_chars: - for ch2 in all_chars: - m = regex.match(r"(?i)\A" + ch1 + r"\Z", ch2) - if m: - if (ch1, ch2) not in matching: - self.fail("{} matching {}".format(ascii(ch1), - ascii(ch2))) - else: - if (ch1, ch2) in matching: - self.fail("{} not matching {}".format(ascii(ch1), - ascii(ch2))) - - def test_named_lists(self): - options = ["one", "two", "three"] - self.assertEqual(regex.match(r"333\L444", "333one444", - bar=options).group(), "333one444") - self.assertEqual(regex.match(r"(?i)333\L444", "333TWO444", - bar=options).group(), "333TWO444") - self.assertEqual(regex.match(r"333\L444", "333four444", - bar=options), None) - - options = [b"one", b"two", b"three"] - self.assertEqual(regex.match(br"333\L444", b"333one444", - bar=options).group(), b"333one444") - self.assertEqual(regex.match(br"(?i)333\L444", b"333TWO444", - bar=options).group(), b"333TWO444") - self.assertEqual(regex.match(br"333\L444", b"333four444", - bar=options), None) - - self.assertEqual(repr(type(regex.compile(r"3\L4\L+5", - bar=["one", "two", "three"]))), self.PATTERN_CLASS) - - self.assertEqual(regex.findall(r"^\L", "solid QWERT", - options=set(['good', 'brilliant', '+s\\ol[i}d'])), []) - self.assertEqual(regex.findall(r"^\L", "+solid QWERT", - options=set(['good', 'brilliant', '+solid'])), ['+solid']) - - options = ["STRASSE"] - self.assertEqual(regex.match(r"(?fi)\L", - "stra\N{LATIN SMALL LETTER SHARP S}e", words=options).span(), (0, - 6)) - - options = ["STRASSE", "stress"] - self.assertEqual(regex.match(r"(?fi)\L", - "stra\N{LATIN SMALL LETTER SHARP S}e", words=options).span(), (0, - 6)) - - options = ["stra\N{LATIN SMALL LETTER SHARP S}e"] - self.assertEqual(regex.match(r"(?fi)\L", "STRASSE", - words=options).span(), (0, 7)) - - options = ["kit"] - self.assertEqual(regex.search(r"(?i)\L", "SKITS", - words=options).span(), (1, 4)) - self.assertEqual(regex.search(r"(?i)\L", - "SK\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}TS", - words=options).span(), (1, 4)) - - self.assertEqual(regex.search(r"(?fi)\b(\w+) +\1\b", - " stra\N{LATIN SMALL LETTER SHARP S}e STRASSE ").span(), (1, 15)) - self.assertEqual(regex.search(r"(?fi)\b(\w+) +\1\b", - " STRASSE stra\N{LATIN SMALL LETTER SHARP S}e ").span(), (1, 15)) - - self.assertEqual(regex.search(r"^\L$", "", options=[]).span(), - (0, 0)) - - def test_fuzzy(self): - # Some tests borrowed from TRE library tests. - self.assertEqual(repr(type(regex.compile('(fou){s,e<=1}'))), - self.PATTERN_CLASS) - self.assertEqual(repr(type(regex.compile('(fuu){s}'))), - self.PATTERN_CLASS) - self.assertEqual(repr(type(regex.compile('(fuu){s,e}'))), - self.PATTERN_CLASS) - self.assertEqual(repr(type(regex.compile('(anaconda){1i+1d<1,s<=1}'))), - self.PATTERN_CLASS) - self.assertEqual(repr(type(regex.compile('(anaconda){1i+1d<1,s<=1,e<=10}'))), - self.PATTERN_CLASS) - self.assertEqual(repr(type(regex.compile('(anaconda){s<=1,e<=1,1i+1d<1}'))), - self.PATTERN_CLASS) - - text = 'molasses anaconda foo bar baz smith anderson ' - self.assertEqual(regex.search('(znacnda){s<=1,e<=3,1i+1d<1}', text), - None) - self.assertEqual(regex.search('(znacnda){s<=1,e<=3,1i+1d<2}', - text).span(0, 1), ((9, 17), (9, 17))) - self.assertEqual(regex.search('(ananda){1i+1d<2}', text), None) - self.assertEqual(regex.search(r"(?:\bznacnda){e<=2}", text)[0], - "anaconda") - self.assertEqual(regex.search(r"(?:\bnacnda){e<=2}", text)[0], - "anaconda") - - text = 'anaconda foo bar baz smith anderson' - self.assertEqual(regex.search('(fuu){i<=3,d<=3,e<=5}', text).span(0, - 1), ((0, 0), (0, 0))) - self.assertEqual(regex.search('(?b)(fuu){i<=3,d<=3,e<=5}', - text).span(0, 1), ((9, 10), (9, 10))) - self.assertEqual(regex.search('(fuu){i<=2,d<=2,e<=5}', text).span(0, - 1), ((7, 10), (7, 10))) - self.assertEqual(regex.search('(?e)(fuu){i<=2,d<=2,e<=5}', - text).span(0, 1), ((9, 10), (9, 10))) - self.assertEqual(regex.search('(fuu){i<=3,d<=3,e}', text).span(0, 1), - ((0, 0), (0, 0))) - self.assertEqual(regex.search('(?b)(fuu){i<=3,d<=3,e}', text).span(0, - 1), ((9, 10), (9, 10))) - - self.assertEqual(repr(type(regex.compile('(approximate){s<=3,1i+1d<3}'))), - self.PATTERN_CLASS) - - # No cost limit. - self.assertEqual(regex.search('(foobar){e}', - 'xirefoabralfobarxie').span(0, 1), ((0, 6), (0, 6))) - self.assertEqual(regex.search('(?e)(foobar){e}', - 'xirefoabralfobarxie').span(0, 1), ((0, 3), (0, 3))) - self.assertEqual(regex.search('(?b)(foobar){e}', - 'xirefoabralfobarxie').span(0, 1), ((11, 16), (11, 16))) - - # At most two errors. - self.assertEqual(regex.search('(foobar){e<=2}', - 'xirefoabrzlfd').span(0, 1), ((4, 9), (4, 9))) - self.assertEqual(regex.search('(foobar){e<=2}', 'xirefoabzlfd'), None) - - # At most two inserts or substitutions and max two errors total. - self.assertEqual(regex.search('(foobar){i<=2,s<=2,e<=2}', - 'oobargoobaploowap').span(0, 1), ((5, 11), (5, 11))) - - # Find best whole word match for "foobar". - self.assertEqual(regex.search('\\b(foobar){e}\\b', 'zfoobarz').span(0, - 1), ((0, 8), (0, 8))) - self.assertEqual(regex.search('\\b(foobar){e}\\b', - 'boing zfoobarz goobar woop').span(0, 1), ((0, 6), (0, 6))) - self.assertEqual(regex.search('(?b)\\b(foobar){e}\\b', - 'boing zfoobarz goobar woop').span(0, 1), ((15, 21), (15, 21))) - - # Match whole string, allow only 1 error. - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobar').span(0, 1), - ((0, 6), (0, 6))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoobar').span(0, - 1), ((0, 7), (0, 7))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobarx').span(0, - 1), ((0, 7), (0, 7))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'fooxbar').span(0, - 1), ((0, 7), (0, 7))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foxbar').span(0, 1), - ((0, 6), (0, 6))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'xoobar').span(0, 1), - ((0, 6), (0, 6))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobax').span(0, 1), - ((0, 6), (0, 6))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'oobar').span(0, 1), - ((0, 5), (0, 5))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'fobar').span(0, 1), - ((0, 5), (0, 5))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'fooba').span(0, 1), - ((0, 5), (0, 5))) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoobarx'), None) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobarxx'), None) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'xxfoobar'), None) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoxbar'), None) - self.assertEqual(regex.search('^(foobar){e<=1}$', 'foxbarx'), None) - - # At most one insert, two deletes, and three substitutions. - # Additionally, deletes cost two and substitutes one, and total - # cost must be less than 4. - self.assertEqual(regex.search('(foobar){i<=1,d<=2,s<=3,2d+1s<4}', - '3oifaowefbaoraofuiebofasebfaobfaorfeoaro').span(0, 1), ((6, 13), (6, - 13))) - self.assertEqual(regex.search('(?b)(foobar){i<=1,d<=2,s<=3,2d+1s<4}', - '3oifaowefbaoraofuiebofasebfaobfaorfeoaro').span(0, 1), ((34, 39), - (34, 39))) - - # Partially fuzzy matches. - self.assertEqual(regex.search('foo(bar){e<=1}zap', 'foobarzap').span(0, - 1), ((0, 9), (3, 6))) - self.assertEqual(regex.search('foo(bar){e<=1}zap', 'fobarzap'), None) - self.assertEqual(regex.search('foo(bar){e<=1}zap', 'foobrzap').span(0, - 1), ((0, 8), (3, 5))) - - text = ('www.cnn.com 64.236.16.20\nwww.slashdot.org 66.35.250.150\n' - 'For useful information, use www.slashdot.org\nthis is demo data!\n') - self.assertEqual(regex.search(r'(?s)^.*(dot.org){e}.*$', text).span(0, - 1), ((0, 120), (120, 120))) - self.assertEqual(regex.search(r'(?es)^.*(dot.org){e}.*$', text).span(0, - 1), ((0, 120), (93, 100))) - self.assertEqual(regex.search(r'^.*(dot.org){e}.*$', text).span(0, 1), - ((0, 119), (24, 101))) - - # Behaviour is unexpected, but arguably not wrong. It first finds the - # best match, then the best in what follows, etc. - self.assertEqual(regex.findall(r"\b\L{e<=1}\b", - " book cot dog desk ", words="cat dog".split()), ["cot", "dog"]) - self.assertEqual(regex.findall(r"\b\L{e<=1}\b", - " book dog cot desk ", words="cat dog".split()), [" dog", "cot"]) - self.assertEqual(regex.findall(r"(?e)\b\L{e<=1}\b", - " book dog cot desk ", words="cat dog".split()), ["dog", "cot"]) - self.assertEqual(regex.findall(r"(?r)\b\L{e<=1}\b", - " book cot dog desk ", words="cat dog".split()), ["dog ", "cot"]) - self.assertEqual(regex.findall(r"(?er)\b\L{e<=1}\b", - " book cot dog desk ", words="cat dog".split()), ["dog", "cot"]) - self.assertEqual(regex.findall(r"(?r)\b\L{e<=1}\b", - " book dog cot desk ", words="cat dog".split()), ["cot", "dog"]) - self.assertEqual(regex.findall(br"\b\L{e<=1}\b", - b" book cot dog desk ", words=b"cat dog".split()), [b"cot", b"dog"]) - self.assertEqual(regex.findall(br"\b\L{e<=1}\b", - b" book dog cot desk ", words=b"cat dog".split()), [b" dog", b"cot"]) - self.assertEqual(regex.findall(br"(?e)\b\L{e<=1}\b", - b" book dog cot desk ", words=b"cat dog".split()), [b"dog", b"cot"]) - self.assertEqual(regex.findall(br"(?r)\b\L{e<=1}\b", - b" book cot dog desk ", words=b"cat dog".split()), [b"dog ", b"cot"]) - self.assertEqual(regex.findall(br"(?er)\b\L{e<=1}\b", - b" book cot dog desk ", words=b"cat dog".split()), [b"dog", b"cot"]) - self.assertEqual(regex.findall(br"(?r)\b\L{e<=1}\b", - b" book dog cot desk ", words=b"cat dog".split()), [b"cot", b"dog"]) - - self.assertEqual(regex.search(r"(\w+) (\1{e<=1})", "foo fou").groups(), - ("foo", "fou")) - self.assertEqual(regex.search(r"(?r)(\2{e<=1}) (\w+)", - "foo fou").groups(), ("foo", "fou")) - self.assertEqual(regex.search(br"(\w+) (\1{e<=1})", - b"foo fou").groups(), (b"foo", b"fou")) - - self.assertEqual(regex.findall(r"(?:(?:QR)+){e}", "abcde"), ["abcde", - ""]) - self.assertEqual(regex.findall(r"(?:Q+){e}", "abc"), ["abc", ""]) - - # Hg issue 41: = for fuzzy matches - self.assertEqual(regex.match(r"(?:service detection){0[^()]+)|(?R))*\)", "(ab(cd)ef)")[ - : ], ("(ab(cd)ef)", "ef")) - self.assertEqual(regex.search(r"\(((?>[^()]+)|(?R))*\)", - "(ab(cd)ef)").captures(1), ["ab", "cd", "(cd)", "ef"]) - - self.assertEqual(regex.search(r"(?r)\(((?R)|(?>[^()]+))*\)", - "(ab(cd)ef)")[ : ], ("(ab(cd)ef)", "ab")) - self.assertEqual(regex.search(r"(?r)\(((?R)|(?>[^()]+))*\)", - "(ab(cd)ef)").captures(1), ["ef", "cd", "(cd)", "ab"]) - - self.assertEqual(regex.search(r"\(([^()]+|(?R))*\)", - "some text (a(b(c)d)e) more text")[ : ], ("(a(b(c)d)e)", "e")) - - self.assertEqual(regex.search(r"(?r)\(((?R)|[^()]+)*\)", - "some text (a(b(c)d)e) more text")[ : ], ("(a(b(c)d)e)", "a")) - - self.assertEqual(regex.search(r"(foo(\(((?:(?>[^()]+)|(?2))*)\)))", - "foo(bar(baz)+baz(bop))")[ : ], ("foo(bar(baz)+baz(bop))", - "foo(bar(baz)+baz(bop))", "(bar(baz)+baz(bop))", - "bar(baz)+baz(bop)")) - - self.assertEqual(regex.search(r"(?r)(foo(\(((?:(?2)|(?>[^()]+))*)\)))", - "foo(bar(baz)+baz(bop))")[ : ], ("foo(bar(baz)+baz(bop))", - "foo(bar(baz)+baz(bop))", "(bar(baz)+baz(bop))", - "bar(baz)+baz(bop)")) - - rgx = regex.compile(r"""^\s*(<\s*([a-zA-Z:]+)(?:\s*[a-zA-Z:]*\s*=\s*(?:'[^']*'|"[^"]*"))*\s*(/\s*)?>(?:[^<>]*|(?1))*(?(3)|<\s*/\s*\2\s*>))\s*$""") - self.assertEqual(bool(rgx.search('')), True) - self.assertEqual(bool(rgx.search('')), False) - self.assertEqual(bool(rgx.search('')), True) - self.assertEqual(bool(rgx.search('')), False) - self.assertEqual(bool(rgx.search('')), False) - - self.assertEqual(bool(rgx.search('')), False) - self.assertEqual(bool(rgx.search('')), True) - self.assertEqual(bool(rgx.search('< fooo / >')), True) - # The next regex should and does match. Perl 5.14 agrees. - #self.assertEqual(bool(rgx.search('foo')), False) - self.assertEqual(bool(rgx.search('foo')), False) - - self.assertEqual(bool(rgx.search('foo')), True) - self.assertEqual(bool(rgx.search('foo')), True) - self.assertEqual(bool(rgx.search('')), True) - - def test_copy(self): - # PatternObjects are immutable, therefore there's no need to clone them. - r = regex.compile("a") - self.assertTrue(copy.copy(r) is r) - self.assertTrue(copy.deepcopy(r) is r) - - # MatchObjects are normally mutable because the target string can be - # detached. However, after the target string has been detached, a - # MatchObject becomes immutable, so there's no need to clone it. - m = r.match("a") - self.assertTrue(copy.copy(m) is not m) - self.assertTrue(copy.deepcopy(m) is not m) - - self.assertTrue(m.string is not None) - m2 = copy.copy(m) - m2.detach_string() - self.assertTrue(m.string is not None) - self.assertTrue(m2.string is None) - - # The following behaviour matches that of the re module. - it = regex.finditer(".", "ab") - it2 = copy.copy(it) - self.assertEqual(next(it).group(), "a") - self.assertEqual(next(it2).group(), "b") - - # The following behaviour matches that of the re module. - it = regex.finditer(".", "ab") - it2 = copy.deepcopy(it) - self.assertEqual(next(it).group(), "a") - self.assertEqual(next(it2).group(), "b") - - # The following behaviour is designed to match that of copying 'finditer'. - it = regex.splititer(" ", "a b") - it2 = copy.copy(it) - self.assertEqual(next(it), "a") - self.assertEqual(next(it2), "b") - - # The following behaviour is designed to match that of copying 'finditer'. - it = regex.splititer(" ", "a b") - it2 = copy.deepcopy(it) - self.assertEqual(next(it), "a") - self.assertEqual(next(it2), "b") - - def test_format(self): - self.assertEqual(regex.subf(r"(\w+) (\w+)", "{0} => {2} {1}", - "foo bar"), "foo bar => bar foo") - self.assertEqual(regex.subf(r"(?\w+) (?\w+)", - "{word2} {word1}", "foo bar"), "bar foo") - - self.assertEqual(regex.subfn(r"(\w+) (\w+)", "{0} => {2} {1}", - "foo bar"), ("foo bar => bar foo", 1)) - self.assertEqual(regex.subfn(r"(?\w+) (?\w+)", - "{word2} {word1}", "foo bar"), ("bar foo", 1)) - - self.assertEqual(regex.match(r"(\w+) (\w+)", - "foo bar").expandf("{0} => {2} {1}"), "foo bar => bar foo") - - def test_fullmatch(self): - self.assertEqual(bool(regex.fullmatch(r"abc", "abc")), True) - self.assertEqual(bool(regex.fullmatch(r"abc", "abcx")), False) - self.assertEqual(bool(regex.fullmatch(r"abc", "abcx", endpos=3)), True) - - self.assertEqual(bool(regex.fullmatch(r"abc", "xabc", pos=1)), True) - self.assertEqual(bool(regex.fullmatch(r"abc", "xabcy", pos=1)), False) - self.assertEqual(bool(regex.fullmatch(r"abc", "xabcy", pos=1, - endpos=4)), True) - - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abc")), True) - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abcx")), False) - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abcx", endpos=3)), - True) - - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabc", pos=1)), - True) - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabcy", pos=1)), - False) - self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabcy", pos=1, - endpos=4)), True) - - def test_issue_18468(self): - self.assertTypedEqual(regex.sub('y', 'a', 'xyz'), 'xaz') - self.assertTypedEqual(regex.sub('y', StrSubclass('a'), - StrSubclass('xyz')), 'xaz') - self.assertTypedEqual(regex.sub(b'y', b'a', b'xyz'), b'xaz') - self.assertTypedEqual(regex.sub(b'y', BytesSubclass(b'a'), - BytesSubclass(b'xyz')), b'xaz') - self.assertTypedEqual(regex.sub(b'y', bytearray(b'a'), - bytearray(b'xyz')), b'xaz') - self.assertTypedEqual(regex.sub(b'y', memoryview(b'a'), - memoryview(b'xyz')), b'xaz') - - for string in ":a:b::c", StrSubclass(":a:b::c"): - self.assertTypedEqual(regex.split(":", string), ['', 'a', 'b', '', - 'c']) - if sys.version_info >= (3, 7, 0): - self.assertTypedEqual(regex.split(":*", string), ['', '', 'a', - '', 'b', '', 'c', '']) - self.assertTypedEqual(regex.split("(:*)", string), ['', ':', - '', '', 'a', ':', '', '', 'b', '::', '', '', 'c', '', '']) - else: - self.assertTypedEqual(regex.split(":*", string), ['', 'a', 'b', - 'c']) - self.assertTypedEqual(regex.split("(:*)", string), ['', ':', - 'a', ':', 'b', '::', 'c']) - - for string in (b":a:b::c", BytesSubclass(b":a:b::c"), - bytearray(b":a:b::c"), memoryview(b":a:b::c")): - self.assertTypedEqual(regex.split(b":", string), [b'', b'a', b'b', - b'', b'c']) - if sys.version_info >= (3, 7, 0): - self.assertTypedEqual(regex.split(b":*", string), [b'', b'', - b'a', b'', b'b', b'', b'c', b'']) - self.assertTypedEqual(regex.split(b"(:*)", string), [b'', b':', - b'', b'', b'a', b':', b'', b'', b'b', b'::', b'', b'', b'c', - b'', b'']) - else: - self.assertTypedEqual(regex.split(b":*", string), [b'', b'a', - b'b', b'c']) - self.assertTypedEqual(regex.split(b"(:*)", string), [b'', b':', - b'a', b':', b'b', b'::', b'c']) - - for string in "a:b::c:::d", StrSubclass("a:b::c:::d"): - self.assertTypedEqual(regex.findall(":+", string), [":", "::", - ":::"]) - self.assertTypedEqual(regex.findall("(:+)", string), [":", "::", - ":::"]) - self.assertTypedEqual(regex.findall("(:)(:*)", string), [(":", ""), - (":", ":"), (":", "::")]) - - for string in (b"a:b::c:::d", BytesSubclass(b"a:b::c:::d"), - bytearray(b"a:b::c:::d"), memoryview(b"a:b::c:::d")): - self.assertTypedEqual(regex.findall(b":+", string), [b":", b"::", - b":::"]) - self.assertTypedEqual(regex.findall(b"(:+)", string), [b":", b"::", - b":::"]) - self.assertTypedEqual(regex.findall(b"(:)(:*)", string), [(b":", - b""), (b":", b":"), (b":", b"::")]) - - for string in 'a', StrSubclass('a'): - self.assertEqual(regex.match('a', string).groups(), ()) - self.assertEqual(regex.match('(a)', string).groups(), ('a',)) - self.assertEqual(regex.match('(a)', string).group(0), 'a') - self.assertEqual(regex.match('(a)', string).group(1), 'a') - self.assertEqual(regex.match('(a)', string).group(1, 1), ('a', - 'a')) - - for string in (b'a', BytesSubclass(b'a'), bytearray(b'a'), - memoryview(b'a')): - self.assertEqual(regex.match(b'a', string).groups(), ()) - self.assertEqual(regex.match(b'(a)', string).groups(), (b'a',)) - self.assertEqual(regex.match(b'(a)', string).group(0), b'a') - self.assertEqual(regex.match(b'(a)', string).group(1), b'a') - self.assertEqual(regex.match(b'(a)', string).group(1, 1), (b'a', - b'a')) - - def test_partial(self): - self.assertEqual(regex.match('ab', 'a', partial=True).partial, True) - self.assertEqual(regex.match('ab', 'a', partial=True).span(), (0, 1)) - self.assertEqual(regex.match(r'cats', 'cat', partial=True).partial, - True) - self.assertEqual(regex.match(r'cats', 'cat', partial=True).span(), (0, - 3)) - self.assertEqual(regex.match(r'cats', 'catch', partial=True), None) - self.assertEqual(regex.match(r'abc\w{3}', 'abcdef', - partial=True).partial, False) - self.assertEqual(regex.match(r'abc\w{3}', 'abcdef', - partial=True).span(), (0, 6)) - self.assertEqual(regex.match(r'abc\w{3}', 'abcde', - partial=True).partial, True) - self.assertEqual(regex.match(r'abc\w{3}', 'abcde', - partial=True).span(), (0, 5)) - - self.assertEqual(regex.match(r'\d{4}$', '1234', partial=True).partial, - False) - - self.assertEqual(regex.match(r'\L', 'post', partial=True, - words=['post']).partial, False) - self.assertEqual(regex.match(r'\L', 'post', partial=True, - words=['post']).span(), (0, 4)) - self.assertEqual(regex.match(r'\L', 'pos', partial=True, - words=['post']).partial, True) - self.assertEqual(regex.match(r'\L', 'pos', partial=True, - words=['post']).span(), (0, 3)) - - self.assertEqual(regex.match(r'(?fi)\L', 'POST', partial=True, - words=['po\uFB06']).partial, False) - self.assertEqual(regex.match(r'(?fi)\L', 'POST', partial=True, - words=['po\uFB06']).span(), (0, 4)) - self.assertEqual(regex.match(r'(?fi)\L', 'POS', partial=True, - words=['po\uFB06']).partial, True) - self.assertEqual(regex.match(r'(?fi)\L', 'POS', partial=True, - words=['po\uFB06']).span(), (0, 3)) - self.assertEqual(regex.match(r'(?fi)\L', 'po\uFB06', - partial=True, words=['POS']), None) - - self.assertEqual(regex.match(r'[a-z]*4R$', 'a', partial=True).span(), - (0, 1)) - self.assertEqual(regex.match(r'[a-z]*4R$', 'ab', partial=True).span(), - (0, 2)) - self.assertEqual(regex.match(r'[a-z]*4R$', 'ab4', partial=True).span(), - (0, 3)) - self.assertEqual(regex.match(r'[a-z]*4R$', 'a4', partial=True).span(), - (0, 2)) - self.assertEqual(regex.match(r'[a-z]*4R$', 'a4R', partial=True).span(), - (0, 3)) - self.assertEqual(regex.match(r'[a-z]*4R$', '4a', partial=True), None) - self.assertEqual(regex.match(r'[a-z]*4R$', 'a44', partial=True), None) - - def test_hg_bugs(self): - # Hg issue 28: regex.compile("(?>b)") causes "TypeError: 'Character' - # object is not subscriptable" - self.assertEqual(bool(regex.compile("(?>b)", flags=regex.V1)), True) - - # Hg issue 29: regex.compile("^((?>\w+)|(?>\s+))*$") causes - # "TypeError: 'GreedyRepeat' object is not iterable" - self.assertEqual(bool(regex.compile(r"^((?>\w+)|(?>\s+))*$", - flags=regex.V1)), True) - - # Hg issue 31: atomic and normal groups in recursive patterns - self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)", - "a(bcd(e)f)g(h)"), ['(bcd(e)f)', '(h)']) - self.assertEqual(regex.findall(r"\((?:(?:[^()]+)|(?R))*\)", - "a(bcd(e)f)g(h)"), ['(bcd(e)f)', '(h)']) - self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)", - "a(b(cd)e)f)g)h"), ['(b(cd)e)']) - self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)", - "a(bc(d(e)f)gh"), ['(d(e)f)']) - self.assertEqual(regex.findall(r"(?r)\((?:(?>[^()]+)|(?R))*\)", - "a(bc(d(e)f)gh"), ['(d(e)f)']) - self.assertEqual([m.group() for m in - regex.finditer(r"\((?:[^()]*+|(?0))*\)", "a(b(c(de)fg)h")], - ['(c(de)fg)']) - - # Hg issue 32: regex.search("a(bc)d", "abcd", regex.I|regex.V1) returns - # None - self.assertEqual(regex.search("a(bc)d", "abcd", regex.I | - regex.V1).group(0), "abcd") - - # Hg issue 33: regex.search("([\da-f:]+)$", "E", regex.I|regex.V1) - # returns None - self.assertEqual(regex.search(r"([\da-f:]+)$", "E", regex.I | - regex.V1).group(0), "E") - self.assertEqual(regex.search(r"([\da-f:]+)$", "e", regex.I | - regex.V1).group(0), "e") - - # Hg issue 34: regex.search("^(?=ab(de))(abd)(e)", "abde").groups() - # returns (None, 'abd', 'e') instead of ('de', 'abd', 'e') - self.assertEqual(regex.search("^(?=ab(de))(abd)(e)", "abde").groups(), - ('de', 'abd', 'e')) - - # Hg issue 35: regex.compile("\ ", regex.X) causes "_regex_core.error: - # bad escape" - self.assertEqual(bool(regex.match(r"\ ", " ", flags=regex.X)), True) - - # Hg issue 36: regex.search("^(a|)\1{2}b", "b") returns None - self.assertEqual(regex.search(r"^(a|)\1{2}b", "b").group(0, 1), ('b', - '')) - - # Hg issue 37: regex.search("^(a){0,0}", "abc").group(0,1) returns - # ('a', 'a') instead of ('', None) - self.assertEqual(regex.search("^(a){0,0}", "abc").group(0, 1), ('', - None)) - - # Hg issue 38: regex.search("(?>.*/)b", "a/b") returns None - self.assertEqual(regex.search("(?>.*/)b", "a/b").group(0), "a/b") - - # Hg issue 39: regex.search("((?i)blah)\\s+\\1", "blah BLAH") doesn't - # return None - # Changed to positional flags in regex 2023.12.23. - self.assertEqual(regex.search(r"((?i)blah)\s+\1", "blah BLAH"), None) - - # Hg issue 40: regex.search("(\()?[^()]+(?(1)\)|)", "(abcd").group(0) - # returns "bcd" instead of "abcd" - self.assertEqual(regex.search(r"(\()?[^()]+(?(1)\)|)", - "(abcd").group(0), "abcd") - - # Hg issue 42: regex.search("(a*)*", "a", flags=regex.V1).span(1) - # returns (0, 1) instead of (1, 1) - self.assertEqual(regex.search("(a*)*", "a").span(1), (1, 1)) - self.assertEqual(regex.search("(a*)*", "aa").span(1), (2, 2)) - self.assertEqual(regex.search("(a*)*", "aaa").span(1), (3, 3)) - - # Hg issue 43: regex.compile("a(?#xxx)*") causes "_regex_core.error: - # nothing to repeat" - self.assertEqual(regex.search("a(?#xxx)*", "aaa").group(), "aaa") - - # Hg issue 44: regex.compile("(?=abc){3}abc") causes - # "_regex_core.error: nothing to repeat" - self.assertEqual(regex.search("(?=abc){3}abc", "abcabcabc").span(), (0, - 3)) - - # Hg issue 45: regex.compile("^(?:a(?:(?:))+)+") causes - # "_regex_core.error: nothing to repeat" - self.assertEqual(regex.search("^(?:a(?:(?:))+)+", "a").span(), (0, 1)) - self.assertEqual(regex.search("^(?:a(?:(?:))+)+", "aa").span(), (0, 2)) - - # Hg issue 46: regex.compile("a(?x: b c )d") causes - # "_regex_core.error: missing )" - self.assertEqual(regex.search("a(?x: b c )d", "abcd").group(0), "abcd") - - # Hg issue 47: regex.compile("a#comment\n*", flags=regex.X) causes - # "_regex_core.error: nothing to repeat" - self.assertEqual(regex.search("a#comment\n*", "aaa", - flags=regex.X).group(0), "aaa") - - # Hg issue 48: regex.search("(a(?(1)\\1)){4}", "a"*10, - # flags=regex.V1).group(0,1) returns ('aaaaa', 'a') instead of ('aaaaaaaaaa', 'aaaa') - self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){1}", - "aaaaaaaaaa").span(0, 1), ((0, 1), (0, 1))) - self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){2}", - "aaaaaaaaaa").span(0, 1), ((0, 3), (1, 3))) - self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){3}", - "aaaaaaaaaa").span(0, 1), ((0, 6), (3, 6))) - self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){4}", - "aaaaaaaaaa").span(0, 1), ((0, 10), (6, 10))) - - # Hg issue 49: regex.search("(a)(?<=b(?1))", "baz", regex.V1) returns - # None incorrectly - self.assertEqual(regex.search("(?V1)(a)(?<=b(?1))", "baz").group(0), - "a") - - # Hg issue 50: not all keywords are found by named list with - # overlapping keywords when full Unicode casefolding is required - self.assertEqual(regex.findall(r'(?fi)\L', - 'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05', - keywords=['post','pos']), ['POST', 'Post', 'post', 'po\u017Ft', - 'po\uFB06', 'po\uFB05']) - self.assertEqual(regex.findall(r'(?fi)pos|post', - 'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), ['POS', - 'Pos', 'pos', 'po\u017F', 'po\uFB06', 'po\uFB05']) - self.assertEqual(regex.findall(r'(?fi)post|pos', - 'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), ['POST', - 'Post', 'post', 'po\u017Ft', 'po\uFB06', 'po\uFB05']) - self.assertEqual(regex.findall(r'(?fi)post|another', - 'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), ['POST', - 'Post', 'post', 'po\u017Ft', 'po\uFB06', 'po\uFB05']) - - # Hg issue 51: regex.search("((a)(?1)|(?2))", "a", flags=regex.V1) - # returns None incorrectly - self.assertEqual(regex.search("(?V1)((a)(?1)|(?2))", "a").group(0, 1, - 2), ('a', 'a', None)) - - # Hg issue 52: regex.search("(\\1xx|){6}", "xx", - # flags=regex.V1).span(0,1) returns incorrect value - self.assertEqual(regex.search(r"(?V1)(\1xx|){6}", "xx").span(0, 1), - ((0, 2), (2, 2))) - - # Hg issue 53: regex.search("(a|)+", "a") causes MemoryError - self.assertEqual(regex.search("(a|)+", "a").group(0, 1), ("a", "")) - - # Hg issue 54: regex.search("(a|)*\\d", "a"*80) causes MemoryError - self.assertEqual(regex.search(r"(a|)*\d", "a" * 80), None) - - # Hg issue 55: regex.search("^(?:a?b?)*$", "ac") take a very long time. - self.assertEqual(regex.search("^(?:a?b?)*$", "ac"), None) - - # Hg issue 58: bad named character escape sequences like "\\N{1}" - # treats as "N" - self.assertRaisesRegex(regex.error, self.UNDEF_CHAR_NAME, lambda: - regex.compile("\\N{1}")) - - # Hg issue 59: regex.search("\\Z", "a\na\n") returns None incorrectly - self.assertEqual(regex.search("\\Z", "a\na\n").span(0), (4, 4)) - - # Hg issue 60: regex.search("(q1|.)*(q2|.)*(x(a|bc)*y){2,}", "xayxay") - # returns None incorrectly - self.assertEqual(regex.search("(q1|.)*(q2|.)*(x(a|bc)*y){2,}", - "xayxay").group(0), "xayxay") - - # Hg issue 61: regex.search("[^a]", "A", regex.I).group(0) returns '' - # incorrectly - self.assertEqual(regex.search("(?i)[^a]", "A"), None) - - # Hg issue 63: regex.search("[[:ascii:]]", "\N{KELVIN SIGN}", - # flags=regex.I|regex.V1) doesn't return None - self.assertEqual(regex.search("(?i)[[:ascii:]]", "\N{KELVIN SIGN}"), - None) - - # Hg issue 66: regex.search("((a|b(?1)c){3,5})", "baaaaca", - # flags=regex.V1).groups() returns ('baaaac', 'baaaac') instead of ('aaaa', 'a') - self.assertEqual(regex.search("((a|b(?1)c){3,5})", "baaaaca").group(0, - 1, 2), ('aaaa', 'aaaa', 'a')) - - # Hg issue 71: non-greedy quantifier in lookbehind - self.assertEqual(regex.findall(r"(?<=:\S+ )\w+", ":9 abc :10 def"), - ['abc', 'def']) - self.assertEqual(regex.findall(r"(?<=:\S* )\w+", ":9 abc :10 def"), - ['abc', 'def']) - self.assertEqual(regex.findall(r"(?<=:\S+? )\w+", ":9 abc :10 def"), - ['abc', 'def']) - self.assertEqual(regex.findall(r"(?<=:\S*? )\w+", ":9 abc :10 def"), - ['abc', 'def']) - - # Hg issue 73: conditional patterns - self.assertEqual(regex.search(r"(?:fe)?male", "female").group(), - "female") - self.assertEqual([m.group() for m in - regex.finditer(r"(fe)?male: h(?(1)(er)|(is)) (\w+)", - "female: her dog; male: his cat. asdsasda")], ['female: her dog', - 'male: his cat']) - - # Hg issue 78: "Captures" doesn't work for recursive calls - self.assertEqual(regex.search(r'(?\((?:[^()]++|(?&rec))*\))', - 'aaa(((1+0)+1)+1)bbb').captures('rec'), ['(1+0)', '((1+0)+1)', - '(((1+0)+1)+1)']) - - # Hg issue 80: Escape characters throws an exception - self.assertRaisesRegex(regex.error, self.BAD_ESCAPE, lambda: - regex.sub('x', '\\', 'x'), ) - - # Hg issue 82: error range does not work - fz = "(CAGCCTCCCATTTCAGAATATACATCC){1a(?b))', "ab").spans("x"), [(1, - 2), (0, 2)]) - - # Hg issue 91: match.expand is extremely slow - # Check that the replacement cache works. - self.assertEqual(regex.sub(r'(-)', lambda m: m.expand(r'x'), 'a-b-c'), - 'axbxc') - - # Hg issue 94: Python crashes when executing regex updates - # pattern.findall - rx = regex.compile(r'\bt(est){i<2}', flags=regex.V1) - self.assertEqual(rx.search("Some text"), None) - self.assertEqual(rx.findall("Some text"), []) - - # Hg issue 95: 'pos' for regex.error - self.assertRaisesRegex(regex.error, self.MULTIPLE_REPEAT, lambda: - regex.compile(r'.???')) - - # Hg issue 97: behaviour of regex.escape's special_only is wrong - # - # Hg issue 244: Make `special_only=True` the default in - # `regex.escape()` - self.assertEqual(regex.escape('foo!?', special_only=False), 'foo\\!\\?') - self.assertEqual(regex.escape('foo!?', special_only=True), 'foo!\\?') - self.assertEqual(regex.escape('foo!?'), 'foo!\\?') - - self.assertEqual(regex.escape(b'foo!?', special_only=False), b'foo\\!\\?') - self.assertEqual(regex.escape(b'foo!?', special_only=True), - b'foo!\\?') - self.assertEqual(regex.escape(b'foo!?'), b'foo!\\?') - - # Hg issue 100: strange results from regex.search - self.assertEqual(regex.search('^([^z]*(?:WWWi|W))?$', - 'WWWi').groups(), ('WWWi', )) - self.assertEqual(regex.search('^([^z]*(?:WWWi|w))?$', - 'WWWi').groups(), ('WWWi', )) - self.assertEqual(regex.search('^([^z]*?(?:WWWi|W))?$', - 'WWWi').groups(), ('WWWi', )) - - # Hg issue 101: findall() broken (seems like memory corruption) - pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.UNICODE) - self.assertEqual([x.group() for x in pat.finditer('yxxx')], ['xxx']) - self.assertEqual(pat.findall('yxxx'), ['xxx']) - - raw = 'yxxx' - self.assertEqual([x.group() for x in pat.finditer(raw)], ['xxx']) - self.assertEqual(pat.findall(raw), ['xxx']) - - pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.IGNORECASE | - regex.UNICODE) - self.assertEqual([x.group() for x in pat.finditer('yxxx')], ['xxx']) - self.assertEqual(pat.findall('yxxx'), ['xxx']) - - raw = 'yxxx' - self.assertEqual([x.group() for x in pat.finditer(raw)], ['xxx']) - self.assertEqual(pat.findall(raw), ['xxx']) - - # Hg issue 106: * operator not working correctly with sub() - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.sub('(?V0).*', 'x', 'test'), 'xx') - else: - self.assertEqual(regex.sub('(?V0).*', 'x', 'test'), 'x') - self.assertEqual(regex.sub('(?V1).*', 'x', 'test'), 'xx') - - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.sub('(?V0).*?', '|', 'test'), '|||||||||') - else: - self.assertEqual(regex.sub('(?V0).*?', '|', 'test'), '|t|e|s|t|') - self.assertEqual(regex.sub('(?V1).*?', '|', 'test'), '|||||||||') - - # Hg issue 112: re: OK, but regex: SystemError - self.assertEqual(regex.sub(r'^(@)\n(?!.*?@)(.*)', - r'\1\n==========\n\2', '@\n', flags=regex.DOTALL), '@\n==========\n') - - # Hg issue 109: Edit distance of fuzzy match - self.assertEqual(regex.match(r'(?:cats|cat){e<=1}', - 'caz').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.match(r'(?e)(?:cats|cat){e<=1}', - 'caz').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.match(r'(?b)(?:cats|cat){e<=1}', - 'caz').fuzzy_counts, (1, 0, 0)) - - self.assertEqual(regex.match(r'(?:cat){e<=1}', 'caz').fuzzy_counts, - (1, 0, 0)) - self.assertEqual(regex.match(r'(?e)(?:cat){e<=1}', - 'caz').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.match(r'(?b)(?:cat){e<=1}', - 'caz').fuzzy_counts, (1, 0, 0)) - - self.assertEqual(regex.match(r'(?:cats){e<=2}', 'c ats').fuzzy_counts, - (1, 1, 0)) - self.assertEqual(regex.match(r'(?e)(?:cats){e<=2}', - 'c ats').fuzzy_counts, (0, 1, 0)) - self.assertEqual(regex.match(r'(?b)(?:cats){e<=2}', - 'c ats').fuzzy_counts, (0, 1, 0)) - - self.assertEqual(regex.match(r'(?:cats){e<=2}', - 'c a ts').fuzzy_counts, (0, 2, 0)) - self.assertEqual(regex.match(r'(?e)(?:cats){e<=2}', - 'c a ts').fuzzy_counts, (0, 2, 0)) - self.assertEqual(regex.match(r'(?b)(?:cats){e<=2}', - 'c a ts').fuzzy_counts, (0, 2, 0)) - - self.assertEqual(regex.match(r'(?:cats){e<=1}', 'c ats').fuzzy_counts, - (0, 1, 0)) - self.assertEqual(regex.match(r'(?e)(?:cats){e<=1}', - 'c ats').fuzzy_counts, (0, 1, 0)) - self.assertEqual(regex.match(r'(?b)(?:cats){e<=1}', - 'c ats').fuzzy_counts, (0, 1, 0)) - - # Hg issue 115: Infinite loop when processing backreferences - self.assertEqual(regex.findall(r'\bof ([a-z]+) of \1\b', - 'To make use of one of these modules'), []) - - # Hg issue 125: Reference to entire match (\g<0>) in - # Pattern.sub() doesn't work as of 2014.09.22 release. - self.assertEqual(regex.sub(r'x', r'\g<0>', 'x'), 'x') - - # Unreported issue: no such builtin as 'ascii' in Python 2. - self.assertEqual(bool(regex.match(r'a', 'a', regex.DEBUG)), True) - - # Hg issue 131: nested sets behaviour - self.assertEqual(regex.findall(r'(?V1)[[b-e]--cd]', 'abcdef'), ['b', - 'e']) - self.assertEqual(regex.findall(r'(?V1)[b-e--cd]', 'abcdef'), ['b', - 'e']) - self.assertEqual(regex.findall(r'(?V1)[[bcde]--cd]', 'abcdef'), ['b', - 'e']) - self.assertEqual(regex.findall(r'(?V1)[bcde--cd]', 'abcdef'), ['b', - 'e']) - - # Hg issue 132: index out of range on null property \p{} - self.assertRaisesRegex(regex.error, '^unknown property at position 4$', - lambda: regex.compile(r'\p{}')) - - # Issue 23692. - self.assertEqual(regex.match('(?:()|(?(1)()|z)){2}(?(2)a|z)', - 'a').group(0, 1, 2), ('a', '', '')) - self.assertEqual(regex.match('(?:()|(?(1)()|z)){0,2}(?(2)a|z)', - 'a').group(0, 1, 2), ('a', '', '')) - - # Hg issue 137: Posix character class :punct: does not seem to be - # supported. - - # Posix compatibility as recommended here: - # http://www.unicode.org/reports/tr18/#Compatibility_Properties - - # Posix in Unicode. - chars = ''.join(chr(c) for c in range(0x10000)) - - self.assertEqual(ascii(''.join(regex.findall(r'''[[:alnum:]]+''', - chars))), ascii(''.join(regex.findall(r'''[\p{Alpha}\p{PosixDigit}]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:alpha:]]+''', - chars))), ascii(''.join(regex.findall(r'''\p{Alpha}+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:ascii:]]+''', - chars))), ascii(''.join(regex.findall(r'''[\p{InBasicLatin}]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:blank:]]+''', - chars))), ascii(''.join(regex.findall(r'''[\p{gc=Space_Separator}\t]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:cntrl:]]+''', - chars))), ascii(''.join(regex.findall(r'''\p{gc=Control}+''', chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:digit:]]+''', - chars))), ascii(''.join(regex.findall(r'''[0-9]+''', chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:graph:]]+''', - chars))), ascii(''.join(regex.findall(r'''[^\p{Space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:lower:]]+''', - chars))), ascii(''.join(regex.findall(r'''\p{Lower}+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:print:]]+''', - chars))), ascii(''.join(regex.findall(r'''(?V1)[\p{Graph}\p{Blank}--\p{Cntrl}]+''', chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:punct:]]+''', - chars))), - ascii(''.join(regex.findall(r'''(?V1)[\p{gc=Punctuation}\p{gc=Symbol}--\p{Alpha}]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:space:]]+''', - chars))), ascii(''.join(regex.findall(r'''\p{Whitespace}+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:upper:]]+''', - chars))), ascii(''.join(regex.findall(r'''\p{Upper}+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:word:]]+''', - chars))), ascii(''.join(regex.findall(r'''[\p{Alpha}\p{gc=Mark}\p{Digit}\p{gc=Connector_Punctuation}\p{Join_Control}]+''', - chars)))) - self.assertEqual(ascii(''.join(regex.findall(r'''[[:xdigit:]]+''', - chars))), ascii(''.join(regex.findall(r'''[0-9A-Fa-f]+''', - chars)))) - - # Posix in ASCII. - chars = bytes(range(0x100)) - - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:alnum:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[\p{Alpha}\p{PosixDigit}]+''', - chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:alpha:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)\p{Alpha}+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:ascii:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[\x00-\x7F]+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:blank:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[\p{gc=Space_Separator}\t]+''', - chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:cntrl:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)\p{gc=Control}+''', - chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:digit:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[0-9]+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:graph:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[^\p{Space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:lower:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)\p{Lower}+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:print:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?aV1)[\p{Graph}\p{Blank}--\p{Cntrl}]+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:punct:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?aV1)[\p{gc=Punctuation}\p{gc=Symbol}--\p{Alpha}]+''', - chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:space:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)\p{Whitespace}+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:upper:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)\p{Upper}+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:word:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[\p{Alpha}\p{gc=Mark}\p{Digit}\p{gc=Connector_Punctuation}\p{Join_Control}]+''', chars)))) - self.assertEqual(ascii(b''.join(regex.findall(br'''(?a)[[:xdigit:]]+''', - chars))), ascii(b''.join(regex.findall(br'''(?a)[0-9A-Fa-f]+''', chars)))) - - # Hg issue 138: grapheme anchored search not working properly. - self.assertEqual(ascii(regex.search(r'\X$', 'ab\u2103').group()), - ascii('\u2103')) - - # Hg issue 139: Regular expression with multiple wildcards where first - # should match empty string does not always work. - self.assertEqual(regex.search("([^L]*)([^R]*R)", "LtR").groups(), ('', - 'LtR')) - - # Hg issue 140: Replace with REVERSE and groups has unexpected - # behavior. - self.assertEqual(regex.sub(r'(.)', r'x\1y', 'ab'), 'xayxby') - self.assertEqual(regex.sub(r'(?r)(.)', r'x\1y', 'ab'), 'xayxby') - self.assertEqual(regex.subf(r'(.)', 'x{1}y', 'ab'), 'xayxby') - self.assertEqual(regex.subf(r'(?r)(.)', 'x{1}y', 'ab'), 'xayxby') - - # Hg issue 141: Crash on a certain partial match. - self.assertEqual(regex.fullmatch('(a)*abc', 'ab', - partial=True).span(), (0, 2)) - self.assertEqual(regex.fullmatch('(a)*abc', 'ab', - partial=True).partial, True) - - # Hg issue 143: Partial matches have incorrect span if prefix is '.' - # wildcard. - self.assertEqual(regex.search('OXRG', 'OOGOX', partial=True).span(), - (3, 5)) - self.assertEqual(regex.search('.XRG', 'OOGOX', partial=True).span(), - (3, 5)) - self.assertEqual(regex.search('.{1,3}XRG', 'OOGOX', - partial=True).span(), (1, 5)) - - # Hg issue 144: Latest version problem with matching 'R|R'. - self.assertEqual(regex.match('R|R', 'R').span(), (0, 1)) - - # Hg issue 146: Forced-fail (?!) works improperly in conditional. - self.assertEqual(regex.match(r'(.)(?(1)(?!))', 'xy'), None) - - # Groups cleared after failure. - self.assertEqual(regex.findall(r'(y)?(\d)(?(1)\b\B)', 'ax1y2z3b'), - [('', '1'), ('', '2'), ('', '3')]) - self.assertEqual(regex.findall(r'(y)?+(\d)(?(1)\b\B)', 'ax1y2z3b'), - [('', '1'), ('', '2'), ('', '3')]) - - # Hg issue 147: Fuzzy match can return match points beyond buffer end. - self.assertEqual([m.span() for m in regex.finditer(r'(?i)(?:error){e}', - 'regex failure')], [(0, 5), (5, 10), (10, 13), (13, 13)]) - self.assertEqual([m.span() for m in - regex.finditer(r'(?fi)(?:error){e}', 'regex failure')], [(0, 5), (5, - 10), (10, 13), (13, 13)]) - - # Hg issue 150: Have an option for POSIX-compatible longest match of - # alternates. - self.assertEqual(regex.search(r'(?p)\d+(\w(\d*)?|[eE]([+-]\d+))', - '10b12')[0], '10b12') - self.assertEqual(regex.search(r'(?p)\d+(\w(\d*)?|[eE]([+-]\d+))', - '10E+12')[0], '10E+12') - - self.assertEqual(regex.search(r'(?p)(\w|ae|oe|ue|ss)', 'ae')[0], 'ae') - self.assertEqual(regex.search(r'(?p)one(self)?(selfsufficient)?', - 'oneselfsufficient')[0], 'oneselfsufficient') - - # Hg issue 151: Request: \K. - self.assertEqual(regex.search(r'(ab\Kcd)', 'abcd').group(0, 1), ('cd', - 'abcd')) - self.assertEqual(regex.findall(r'\w\w\K\w\w', 'abcdefgh'), ['cd', - 'gh']) - self.assertEqual(regex.findall(r'(\w\w\K\w\w)', 'abcdefgh'), ['abcd', - 'efgh']) - - self.assertEqual(regex.search(r'(?r)(ab\Kcd)', 'abcd').group(0, 1), - ('ab', 'abcd')) - self.assertEqual(regex.findall(r'(?r)\w\w\K\w\w', 'abcdefgh'), ['ef', - 'ab']) - self.assertEqual(regex.findall(r'(?r)(\w\w\K\w\w)', 'abcdefgh'), - ['efgh', 'abcd']) - - # Hg issue 152: Request: Request: (?(DEFINE)...). - self.assertEqual(regex.search(r'(?(DEFINE)(?\d+)(?\w+))(?&quant) (?&item)', - '5 elephants')[0], '5 elephants') - - self.assertEqual(regex.search(r'(?&routine)(?(DEFINE)(?.))', 'a').group('routine'), None) - self.assertEqual(regex.search(r'(?&routine)(?(DEFINE)(?.))', 'a').captures('routine'), ['a']) - - # Hg issue 153: Request: (*SKIP). - self.assertEqual(regex.search(r'12(*FAIL)|3', '123')[0], '3') - self.assertEqual(regex.search(r'(?r)12(*FAIL)|3', '123')[0], '3') - - self.assertEqual(regex.search(r'\d+(*PRUNE)\d', '123'), None) - self.assertEqual(regex.search(r'\d+(?=(*PRUNE))\d', '123')[0], '123') - self.assertEqual(regex.search(r'\d+(*PRUNE)bcd|[3d]', '123bcd')[0], - '123bcd') - self.assertEqual(regex.search(r'\d+(*PRUNE)bcd|[3d]', '123zzd')[0], - 'd') - self.assertEqual(regex.search(r'\d+?(*PRUNE)bcd|[3d]', '123bcd')[0], - '3bcd') - self.assertEqual(regex.search(r'\d+?(*PRUNE)bcd|[3d]', '123zzd')[0], - 'd') - self.assertEqual(regex.search(r'\d++(?<=3(*PRUNE))zzd|[4d]$', - '123zzd')[0], '123zzd') - self.assertEqual(regex.search(r'\d++(?<=3(*PRUNE))zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'\d++(?<=(*PRUNE)3)zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'\d++(?<=2(*PRUNE)3)zzd|[3d]$', - '124zzd')[0], 'd') - - self.assertEqual(regex.search(r'(?r)\d(*PRUNE)\d+', '123'), None) - self.assertEqual(regex.search(r'(?r)\d(?<=(*PRUNE))\d+', '123')[0], - '123') - self.assertEqual(regex.search(r'(?r)\d+(*PRUNE)bcd|[3d]', - '123bcd')[0], '123bcd') - self.assertEqual(regex.search(r'(?r)\d+(*PRUNE)bcd|[3d]', - '123zzd')[0], 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=3(*PRUNE))zzd|[4d]$', - '123zzd')[0], '123zzd') - self.assertEqual(regex.search(r'(?r)\d++(?<=3(*PRUNE))zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=(*PRUNE)3)zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=2(*PRUNE)3)zzd|[3d]$', - '124zzd')[0], 'd') - - self.assertEqual(regex.search(r'\d+(*SKIP)bcd|[3d]', '123bcd')[0], - '123bcd') - self.assertEqual(regex.search(r'\d+(*SKIP)bcd|[3d]', '123zzd')[0], - 'd') - self.assertEqual(regex.search(r'\d+?(*SKIP)bcd|[3d]', '123bcd')[0], - '3bcd') - self.assertEqual(regex.search(r'\d+?(*SKIP)bcd|[3d]', '123zzd')[0], - 'd') - self.assertEqual(regex.search(r'\d++(?<=3(*SKIP))zzd|[4d]$', - '123zzd')[0], '123zzd') - self.assertEqual(regex.search(r'\d++(?<=3(*SKIP))zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'\d++(?<=(*SKIP)3)zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'\d++(?<=2(*SKIP)3)zzd|[3d]$', - '124zzd')[0], 'd') - - self.assertEqual(regex.search(r'(?r)\d+(*SKIP)bcd|[3d]', '123bcd')[0], - '123bcd') - self.assertEqual(regex.search(r'(?r)\d+(*SKIP)bcd|[3d]', '123zzd')[0], - 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=3(*SKIP))zzd|[4d]$', - '123zzd')[0], '123zzd') - self.assertEqual(regex.search(r'(?r)\d++(?<=3(*SKIP))zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=(*SKIP)3)zzd|[4d]$', - '124zzd')[0], 'd') - self.assertEqual(regex.search(r'(?r)\d++(?<=2(*SKIP)3)zzd|[3d]$', - '124zzd')[0], 'd') - - # Hg issue 154: Segmentation fault 11 when working with an atomic group - text = """June 30, December 31, 2013 2012 -some words follow: -more words and numbers 1,234,567 9,876,542 -more words and numbers 1,234,567 9,876,542""" - self.assertEqual(len(regex.findall(r'(?2014|2013 ?2012)', text)), 1) - - # Hg issue 156: regression on atomic grouping - self.assertEqual(regex.match('1(?>2)', '12').span(), (0, 2)) - - # Hg issue 157: regression: segfault on complex lookaround - self.assertEqual(regex.match(r'(?V1w)(?=(?=[^A-Z]*+[A-Z])(?=[^a-z]*+[a-z]))(?=\D*+\d)(?=\p{Alphanumeric}*+\P{Alphanumeric})\A(?s:.){8,255}+\Z', - 'AAaa11!!')[0], 'AAaa11!!') - - # Hg issue 158: Group issue with (?(DEFINE)...) - TEST_REGEX = regex.compile(r'''(?smx) -(?(DEFINE) - (? - ^,[^,]+, - ) -) - -# Group 2 is defined on this line -^,([^,]+), - -(?:(?!(?&subcat)[\r\n]+(?&subcat)).)+ -''') - - TEST_DATA = ''' -,Cat 1, -,Brand 1, -some -thing -,Brand 2, -other -things -,Cat 2, -,Brand, -Some -thing -''' - - self.assertEqual([m.span(1, 2) for m in - TEST_REGEX.finditer(TEST_DATA)], [((-1, -1), (2, 7)), ((-1, -1), (54, - 59))]) - - # Hg issue 161: Unexpected fuzzy match results - self.assertEqual(regex.search('(abcdefgh){e}', - '******abcdefghijklmnopqrtuvwxyz', regex.BESTMATCH).span(), (6, 14)) - self.assertEqual(regex.search('(abcdefghi){e}', - '******abcdefghijklmnopqrtuvwxyz', regex.BESTMATCH).span(), (6, 15)) - - # Hg issue 163: allow lookarounds in conditionals. - self.assertEqual(regex.match(r'(?:(?=\d)\d+\b|\w+)', '123abc').span(), - (0, 6)) - self.assertEqual(regex.match(r'(?(?=\d)\d+\b|\w+)', '123abc'), None) - self.assertEqual(regex.search(r'(?(?<=love\s)you|(?<=hate\s)her)', - "I love you").span(), (7, 10)) - self.assertEqual(regex.findall(r'(?(?<=love\s)you|(?<=hate\s)her)', - "I love you but I don't hate her either"), ['you', 'her']) - - # Hg issue 180: bug of POSIX matching. - self.assertEqual(regex.search(r'(?p)a*(.*?)', 'aaabbb').group(0, 1), - ('aaabbb', 'bbb')) - self.assertEqual(regex.search(r'(?p)a*(.*)', 'aaabbb').group(0, 1), - ('aaabbb', 'bbb')) - self.assertEqual(regex.sub(r'(?p)a*(.*?)', r'\1', 'aaabbb'), 'bbb') - self.assertEqual(regex.sub(r'(?p)a*(.*)', r'\1', 'aaabbb'), 'bbb') - - # Hg issue 192: Named lists reverse matching doesn't work with - # IGNORECASE and V1 - self.assertEqual(regex.match(r'(?irV0)\L', '21', kw=['1']).span(), - (1, 2)) - self.assertEqual(regex.match(r'(?irV1)\L', '21', kw=['1']).span(), - (1, 2)) - - # Hg issue 193: Alternation and .REVERSE flag. - self.assertEqual(regex.search('a|b', '111a222').span(), (3, 4)) - self.assertEqual(regex.search('(?r)a|b', '111a222').span(), (3, 4)) - - # Hg issue 194: .FULLCASE and Backreference - self.assertEqual(regex.search(r'(?if)<(CLI)><\1>', - '').span(), (0, 10)) - self.assertEqual(regex.search(r'(?if)<(CLI)><\1>', - '').span(), (0, 10)) - self.assertEqual(regex.search(r'(?ifr)<\1><(CLI)>', - '').span(), (0, 10)) - - # Hg issue 195: Pickle (or otherwise serial) the compiled regex - r = regex.compile(r'\L', options=['foo', 'bar']) - p = pickle.dumps(r) - r = pickle.loads(p) - self.assertEqual(r.match('foo').span(), (0, 3)) - - # Hg issue 196: Fuzzy matching on repeated regex not working as - # expected - self.assertEqual(regex.match('(x{6}){e<=1}', 'xxxxxx', - flags=regex.BESTMATCH).span(), (0, 6)) - self.assertEqual(regex.match('(x{6}){e<=1}', 'xxxxx', - flags=regex.BESTMATCH).span(), (0, 5)) - self.assertEqual(regex.match('(x{6}){e<=1}', 'x', - flags=regex.BESTMATCH), None) - self.assertEqual(regex.match('(?r)(x{6}){e<=1}', 'xxxxxx', - flags=regex.BESTMATCH).span(), (0, 6)) - self.assertEqual(regex.match('(?r)(x{6}){e<=1}', 'xxxxx', - flags=regex.BESTMATCH).span(), (0, 5)) - self.assertEqual(regex.match('(?r)(x{6}){e<=1}', 'x', - flags=regex.BESTMATCH), None) - - # Hg issue 197: ValueError in regex.compile - self.assertRaises(regex.error, lambda: - regex.compile(b'00000\\0\\00\\^\50\\00\\U05000000')) - - # Hg issue 198: ValueError in regex.compile - self.assertRaises(regex.error, lambda: regex.compile(b"{e', '22', aa=['121', - '22'])), True) - self.assertEqual(bool(regex.search(r'(?ri)\L', '22', aa=['121', - '22'])), True) - self.assertEqual(bool(regex.search(r'(?fi)\L', '22', aa=['121', - '22'])), True) - self.assertEqual(bool(regex.search(r'(?fri)\L', '22', aa=['121', - '22'])), True) - - # Hg issue 208: Named list, (?ri) flags, Backreference - self.assertEqual(regex.search(r'(?r)\1dog..(?<=(\L))$', 'ccdogcc', - aa=['bcb', 'cc']). span(), (0, 7)) - self.assertEqual(regex.search(r'(?ir)\1dog..(?<=(\L))$', - 'ccdogcc', aa=['bcb', 'cc']). span(), (0, 7)) - - # Hg issue 210: Fuzzy matching and Backreference - self.assertEqual(regex.search(r'(2)(?:\1{5}){e<=1}', - '3222212').span(), (1, 7)) - self.assertEqual(regex.search(r'(\d)(?:\1{5}){e<=1}', - '3222212').span(), (1, 7)) - - # Hg issue 211: Segmentation fault with recursive matches and atomic - # groups - self.assertEqual(regex.match(r'''\A(?P(?>\((?&whole)\)|[+\-]))\Z''', - '((-))').span(), (0, 5)) - self.assertEqual(regex.match(r'''\A(?P(?>\((?&whole)\)|[+\-]))\Z''', - '((-)+)'), None) - - # Hg issue 212: Unexpected matching difference with .*? between re and - # regex - self.assertEqual(regex.match(r"x.*? (.).*\1(.*)\1", - 'x |y| z|').span(), (0, 9)) - self.assertEqual(regex.match(r"\.sr (.*?) (.)(.*)\2(.*)\2(.*)", - r'.sr h |||').span(), (0, 35)) - - # Hg issue 213: Segmentation Fault - a = '"\\xF9\\x80\\xAEqdz\\x95L\\xA7\\x89[\\xFE \\x91)\\xF9]\\xDB\'\\x99\\x09=\\x00\\xFD\\x98\\x22\\xDD\\xF1\\xB6\\xC3 Z\\xB6gv\\xA5x\\x93P\\xE1r\\x14\\x8Cv\\x0C\\xC0w\\x15r\\xFFc%" ' - py_regex_pattern = r'''(?P((?>(?"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)))) (?P((?>(?"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))))''' - self.assertEqual(bool(regex.search(py_regex_pattern, a)), False) - - # Hg Issue 216: Invalid match when using negative lookbehind and pipe - self.assertEqual(bool(regex.match('foo(?<=foo)', 'foo')), True) - self.assertEqual(bool(regex.match('foo(?.*\!\w*\:.*)|(?P.*))', - '!')), False) - - # Hg issue 220: Misbehavior of group capture with OR operand - self.assertEqual(regex.match(r'\w*(ea)\w*|\w*e(?!a)\w*', - 'easier').groups(), ('ea', )) - - # Hg issue 225: BESTMATCH in fuzzy match not working - self.assertEqual(regex.search('(^1234$){i,d}', '12234', - regex.BESTMATCH).span(), (0, 5)) - self.assertEqual(regex.search('(^1234$){i,d}', '12234', - regex.BESTMATCH).fuzzy_counts, (0, 1, 0)) - - self.assertEqual(regex.search('(^1234$){s,i,d}', '12234', - regex.BESTMATCH).span(), (0, 5)) - self.assertEqual(regex.search('(^1234$){s,i,d}', '12234', - regex.BESTMATCH).fuzzy_counts, (0, 1, 0)) - - # Hg issue 226: Error matching at start of string - self.assertEqual(regex.search('(^123$){s,i,d}', 'xxxxxxxx123', - regex.BESTMATCH).span(), (0, 11)) - self.assertEqual(regex.search('(^123$){s,i,d}', 'xxxxxxxx123', - regex.BESTMATCH).fuzzy_counts, (0, 8, 0)) - - # Hg issue 227: Incorrect behavior for ? operator with UNICODE + - # IGNORECASE - self.assertEqual(regex.search(r'a?yz', 'xxxxyz', flags=regex.FULLCASE | - regex.IGNORECASE).span(), (4, 6)) - - # Hg issue 230: Is it a bug of (?(DEFINE)...) - self.assertEqual(regex.findall(r'(?:(?![a-d]).)+', 'abcdefgh'), - ['efgh']) - self.assertEqual(regex.findall(r'''(?(DEFINE)(?P(?:(?![a-d]).)))(?&mydef)+''', - 'abcdefgh'), ['efgh']) - - # Hg issue 238: Not fully re backward compatible - self.assertEqual(regex.findall(r'((\w{1,3})(\.{2,10})){1,3}', - '"Erm....yes. T..T...Thank you for that."'), [('Erm....', 'Erm', - '....'), ('T...', 'T', '...')]) - self.assertEqual(regex.findall(r'((\w{1,3})(\.{2,10})){3}', - '"Erm....yes. T..T...Thank you for that."'), []) - self.assertEqual(regex.findall(r'((\w{1,3})(\.{2,10})){2}', - '"Erm....yes. T..T...Thank you for that."'), [('T...', 'T', '...')]) - self.assertEqual(regex.findall(r'((\w{1,3})(\.{2,10})){1}', - '"Erm....yes. T..T...Thank you for that."'), [('Erm....', 'Erm', - '....'), ('T..', 'T', '..'), ('T...', 'T', '...')]) - - # Hg issue 247: Unexpected result with fuzzy matching and lookahead - # expression - self.assertEqual(regex.search(r'(?:ESTONIA(?!\w)){e<=1}', - 'ESTONIAN WORKERS').group(), 'ESTONIAN') - self.assertEqual(regex.search(r'(?:ESTONIA(?=\W)){e<=1}', - 'ESTONIAN WORKERS').group(), 'ESTONIAN') - - self.assertEqual(regex.search(r'(?:(?.))(?&func)', - 'abc').groups(), (None, )) - self.assertEqual(regex.search(r'(?(DEFINE)(?.))(?&func)', - 'abc').groupdict(), {'func': None}) - self.assertEqual(regex.search(r'(?(DEFINE)(?.))(?&func)', - 'abc').capturesdict(), {'func': ['a']}) - - self.assertEqual(regex.search(r'(?(DEFINE)(?.))(?=(?&func))', - 'abc').groups(), (None, )) - self.assertEqual(regex.search(r'(?(DEFINE)(?.))(?=(?&func))', - 'abc').groupdict(), {'func': None}) - self.assertEqual(regex.search(r'(?(DEFINE)(?.))(?=(?&func))', - 'abc').capturesdict(), {'func': ['a']}) - - self.assertEqual(regex.search(r'(?(DEFINE)(?.)).(?<=(?&func))', - 'abc').groups(), (None, )) - self.assertEqual(regex.search(r'(?(DEFINE)(?.)).(?<=(?&func))', - 'abc').groupdict(), {'func': None}) - self.assertEqual(regex.search(r'(?(DEFINE)(?.)).(?<=(?&func))', - 'abc').capturesdict(), {'func': ['a']}) - - # Hg issue 271: Comment logic different between Re and Regex - self.assertEqual(bool(regex.match(r'ab(?#comment\))cd', 'abcd')), True) - - # Hg issue 276: Partial Matches yield incorrect matches and bounds - self.assertEqual(regex.search(r'[a-z]+ [a-z]*?:', 'foo bar', - partial=True).span(), (0, 7)) - self.assertEqual(regex.search(r'(?r):[a-z]*? [a-z]+', 'foo bar', - partial=True).span(), (0, 7)) - - # Hg issue 291: Include Script Extensions as a supported Unicode property - self.assertEqual(bool(regex.match(r'(?u)\p{Script:Beng}', - '\u09EF')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{Script:Bengali}', - '\u09EF')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{Script_Extensions:Bengali}', - '\u09EF')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{Script_Extensions:Beng}', - '\u09EF')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{Script_Extensions:Cakm}', - '\u09EF')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{Script_Extensions:Sylo}', - '\u09EF')), True) - - # Hg issue #293: scx (Script Extensions) property currently matches - # incorrectly - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Latin}', 'P')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Ahom}', 'P')), False) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Common}', '4')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Caucasian_Albanian}', '4')), - False) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Arabic}', '\u062A')), True) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Balinese}', '\u062A')), - False) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Devanagari}', '\u091C')), - True) - self.assertEqual(bool(regex.match(r'(?u)\p{scx:Batak}', '\u091C')), False) - - # Hg issue 296: Group references are not taken into account when group is reporting the last match - self.assertEqual(regex.fullmatch('(?P.)*(?&x)', 'abc').captures('x'), - ['a', 'b', 'c']) - self.assertEqual(regex.fullmatch('(?P.)*(?&x)', 'abc').group('x'), - 'b') - - self.assertEqual(regex.fullmatch('(?P.)(?P.)(?P.)', - 'abc').captures('x'), ['a', 'b', 'c']) - self.assertEqual(regex.fullmatch('(?P.)(?P.)(?P.)', - 'abc').group('x'), 'c') - - # Hg issue 299: Partial gives misleading results with "open ended" regexp - self.assertEqual(regex.match('(?:ab)*', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)*', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)*?', '', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)*+', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)*+', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)+', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)+', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)+?', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)++', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?:ab)++', 'abab', partial=True).partial, - False) - - self.assertEqual(regex.match('(?r)(?:ab)*', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)*', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)*?', '', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)*+', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)*+', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)+', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)+', 'abab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)+?', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)++', 'ab', partial=True).partial, - False) - self.assertEqual(regex.match('(?r)(?:ab)++', 'abab', partial=True).partial, - False) - - self.assertEqual(regex.match('a*', '', partial=True).partial, False) - self.assertEqual(regex.match('a*?', '', partial=True).partial, False) - self.assertEqual(regex.match('a*+', '', partial=True).partial, False) - self.assertEqual(regex.match('a+', '', partial=True).partial, True) - self.assertEqual(regex.match('a+?', '', partial=True).partial, True) - self.assertEqual(regex.match('a++', '', partial=True).partial, True) - self.assertEqual(regex.match('a+', 'a', partial=True).partial, False) - self.assertEqual(regex.match('a+?', 'a', partial=True).partial, False) - self.assertEqual(regex.match('a++', 'a', partial=True).partial, False) - - self.assertEqual(regex.match('(?r)a*', '', partial=True).partial, False) - self.assertEqual(regex.match('(?r)a*?', '', partial=True).partial, False) - self.assertEqual(regex.match('(?r)a*+', '', partial=True).partial, False) - self.assertEqual(regex.match('(?r)a+', '', partial=True).partial, True) - self.assertEqual(regex.match('(?r)a+?', '', partial=True).partial, True) - self.assertEqual(regex.match('(?r)a++', '', partial=True).partial, True) - self.assertEqual(regex.match('(?r)a+', 'a', partial=True).partial, False) - self.assertEqual(regex.match('(?r)a+?', 'a', partial=True).partial, False) - self.assertEqual(regex.match('(?r)a++', 'a', partial=True).partial, False) - - self.assertEqual(regex.match(r"(?:\s*\w+'*)+", 'whatever', partial=True).partial, - False) - - # Hg issue 300: segmentation fault - pattern = ('(?PGGCGTCACACTTTGCTATGCCATAGCAT[AG]TTTATCCATAAGA' - 'TTAGCGGATCCTACCTGACGCTTTTTATCGCAACTCTCTACTGTTTCTCCATAACAGAACATATTGA' - 'CTATCCGGTATTACCCGGCATGACAGGAGTAAAA){e<=1}' - '(?P[ACGT]{1059}){e<=2}' - '(?PTAATCGTCTTGTTTGATACACAAGGGTCGCATCTGCGGCCCTTTTGCTTTTTTAAG' - 'TTGTAAGGATATGCCATTCTAGA){e<=0}' - '(?P[ACGT]{18}){e<=0}' - '(?PAGATCGG[CT]AGAGCGTCGTGTAGGGAAAGAGTGTGG){e<=1}') - - text = ('GCACGGCGTCACACTTTGCTATGCCATAGCATATTTATCCATAAGATTAGCGGATCCTACC' - 'TGACGCTTTTTATCGCAACTCTCTACTGTTTCTCCATAACAGAACATATTGACTATCCGGTATTACC' - 'CGGCATGACAGGAGTAAAAATGGCTATCGACGAAAACAAACAGAAAGCGTTGGCGGCAGCACTGGGC' - 'CAGATTGAGAAACAATTTGGTAAAGGCTCCATCATGCGCCTGGGTGAAGACCGTTCCATGGATGTGG' - 'AAACCATCTCTACCGGTTCGCTTTCACTGGATATCGCGCTTGGGGCAGGTGGTCTGCCGATGGGCCG' - 'TATCGTCGAAATCTACGGACCGGAATCTTCCGGTAAAACCACGCTGACGCTGCAGGTGATCGCCGCA' - 'GCGCAGCGTGAAGGTAAAACCTGTGCGTTTATCGATGCTGAACACGCGCTGGACCCAATCTACGCAC' - 'GTAAACTGGGCGTCGATATCGACAACCTGCTGTGCTCCCAGCCGGACACCGGCGAGCAGGCACTGGA' - 'AATCTGTGACGCCCTGGCGCGTTCTGGCGCAGTAGACGTTATCGTCGTTGACTCCGTGGCGGCACTG' - 'ACGCCGAAAGCGGAAATCGAAGGCGAAATCGGCGACTCTCATATGGGCCTTGCGGCACGTATGATGA' - 'GCCAGGCGATGCGTAAGCTGGCGGGTAACCTGAAGCAGTCCAACACGCTGCTGATCTTCATCAACCC' - 'CATCCGTATGAAAATTGGTGTGATGTTCGGCAACCCGGAAACCACTTACCGGTGGTAACGCGCTGAA' - 'ATTCTACGCCTCTGTTCGTCTCGACATCCGTTAAATCGGCGCGGTGAAAGAGGGCGAAAACGTGGTG' - 'GGTAGCGAAACCCGCGTGAAAGTGGTGAAGAACAAAATCGCTGCGCCGTTTAAACAGGCTGAATTCC' - 'AGATCCTCTACGGCGAAGGTATCAACTTCTACCCCGAACTGGTTGACCTGGGCGTAAAAGAGAAGCT' - 'GATCGAGAAAGCAGGCGCGTGGTACAGCTACAAAGGTGAGAAGATCGGTCAGGGTAAAGCGAATGCG' - 'ACTGCCTGGCTGAAATTTAACCCGGAAACCGCGAAAGAGATCGAGTGAAAAGTACGTGAGTTGCTGC' - 'TGAGCAACCCGAACTCAACGCCGGATTTCTCTGTAGATGATAGCGAAGGCGTAGCAGAAACTAACGA' - 'AGATTTTTAATCGTCTTGTTTGATACACAAGGGTCGCATCTGCGGCCCTTTTGCTTTTTTAAGTTGT' - 'AAGGATATGCCATTCTAGACAGTTAACACACCAACAAAGATCGGTAGAGCGTCGTGTAGGGAAAGAG' - 'TGTGGTACC') - - m = regex.search(pattern, text, flags=regex.BESTMATCH) - self.assertEqual(m.fuzzy_counts, (0, 1, 0)) - self.assertEqual(m.fuzzy_changes, ([], [1206], [])) - - # Hg issue 306: Fuzzy match parameters not respecting quantifier scope - self.assertEqual(regex.search(r'(?e)(dogf(((oo){e<1})|((00){e<1}))d){e<2}', - 'dogfood').fuzzy_counts, (0, 0, 0)) - self.assertEqual(regex.search(r'(?e)(dogf(((oo){e<1})|((00){e<1}))d){e<2}', - 'dogfoot').fuzzy_counts, (1, 0, 0)) - - # Hg issue 312: \X not matching graphemes with zero-width-joins - self.assertEqual(regex.findall(r'\X', - '\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466'), - ['\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466']) - - # Hg issue 320: Abnormal performance - self.assertEqual(bool(regex.search(r'(?=a)a', 'a')), True) - self.assertEqual(bool(regex.search(r'(?!b)a', 'a')), True) - - # Hg issue 327: .fullmatch() causes MemoryError - self.assertEqual(regex.fullmatch(r'((\d)*?)*?', '123').span(), (0, 3)) - - # Hg issue 329: Wrong group matches when question mark quantifier is used within a look behind - self.assertEqual(regex.search(r'''(?(DEFINE)(?(?THIS_SHOULD_NOT_MATCHx?)|(?right))).*(?<=(?&mydef).*)''', - 'x right').capturesdict(), {'mydef': ['right'], 'wrong': [], 'right': - ['right']}) - - # Hg issue 338: specifying allowed characters when fuzzy-matching - self.assertEqual(bool(regex.match(r'(?:cat){e<=1:[u]}', 'cut')), True) - self.assertEqual(bool(regex.match(r'(?:cat){e<=1:u}', 'cut')), True) - - # Hg issue 353: fuzzy changes negative indexes - self.assertEqual(regex.search(r'(?be)(AGTGTTCCCCGCGCCAGCGGGGATAAACCG){s<=5,i<=5,d<=5,s+i+d<=10}', - 'TTCCCCGCGCCAGCGGGGATAAACCG').fuzzy_changes, ([], [], [0, 1, 3, 5])) - - # Git issue 364: Contradictory values in fuzzy_counts and fuzzy_changes - self.assertEqual(regex.match(r'(?:bc){e}', 'c').fuzzy_counts, (1, 0, - 1)) - self.assertEqual(regex.match(r'(?:bc){e}', 'c').fuzzy_changes, ([0], - [], [1])) - self.assertEqual(regex.match(r'(?e)(?:bc){e}', 'c').fuzzy_counts, (0, - 0, 1)) - self.assertEqual(regex.match(r'(?e)(?:bc){e}', 'c').fuzzy_changes, - ([], [], [0])) - self.assertEqual(regex.match(r'(?b)(?:bc){e}', 'c').fuzzy_counts, (0, - 0, 1)) - self.assertEqual(regex.match(r'(?b)(?:bc){e}', 'c').fuzzy_changes, - ([], [], [0])) - - # Git issue 370: Confusions about Fuzzy matching behavior - self.assertEqual(regex.match('(?e)(?:^(\\$ )?\\d{1,3}(,\\d{3})*(\\.\\d{2})$){e}', - '$ 10,112.111.12').fuzzy_counts, (6, 0, 5)) - self.assertEqual(regex.match('(?e)(?:^(\\$ )?\\d{1,3}(,\\d{3})*(\\.\\d{2})$){s<=1}', - '$ 10,112.111.12').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.match('(?e)(?:^(\\$ )?\\d{1,3}(,\\d{3})*(\\.\\d{2})$){s<=1,i<=1,d<=1}', - '$ 10,112.111.12').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.match('(?e)(?:^(\\$ )?\\d{1,3}(,\\d{3})*(\\.\\d{2})$){s<=3}', - '$ 10,1a2.111.12').fuzzy_counts, (2, 0, 0)) - self.assertEqual(regex.match('(?e)(?:^(\\$ )?\\d{1,3}(,\\d{3})*(\\.\\d{2})$){s<=2}', - '$ 10,1a2.111.12').fuzzy_counts, (2, 0, 0)) - - self.assertEqual(regex.fullmatch(r'(?e)(?:0?,0(?:,0)?){s<=1,d<=1}', - ',0;0').fuzzy_counts, (1, 0, 0)) - self.assertEqual(regex.fullmatch(r'(?e)(?:0??,0(?:,0)?){s<=1,d<=1}', - ',0;0').fuzzy_counts, (1, 0, 0)) - - # Git issue 371: Specifying character set when fuzzy-matching allows characters not in the set - self.assertEqual(regex.search(r"\b(?e)(?:\d{6,20}){i<=5:[\-\\\/]}\b", - "cat dog starting at 00:01132.000. hello world"), None) - - # Git issue 385: Comments in expressions - self.assertEqual(bool(regex.compile('(?#)')), True) - self.assertEqual(bool(regex.compile('(?x)(?#)')), True) - - # Git issue 394: Unexpected behaviour in fuzzy matching with limited character set with IGNORECASE flag - self.assertEqual(regex.findall(r'(\d+){i<=2:[ab]}', '123X4Y5'), - ['123', '4', '5']) - self.assertEqual(regex.findall(r'(?i)(\d+){i<=2:[ab]}', '123X4Y5'), - ['123', '4', '5']) - - # Git issue 403: Fuzzy matching with wrong distance (unnecessary substitutions) - self.assertEqual(regex.match(r'^(test){e<=5}$', 'terstin', - flags=regex.B).fuzzy_counts, (0, 3, 0)) - - # Git issue 408: regex fails with a quantified backreference but succeeds with repeated backref - self.assertEqual(bool(regex.match(r"(?:(x*)\1\1\1)*x$", "x" * 5)), True) - self.assertEqual(bool(regex.match(r"(?:(x*)\1{3})*x$", "x" * 5)), True) - - # Git issue 415: Fuzzy character restrictions don't apply to insertions at "right edge" - self.assertEqual(regex.match(r't(?:es){s<=1:\d}t', 'te5t').group(), - 'te5t') - self.assertEqual(regex.match(r't(?:es){s<=1:\d}t', 'tezt'), None) - self.assertEqual(regex.match(r't(?:es){i<=1:\d}t', 'tes5t').group(), - 'tes5t') - self.assertEqual(regex.match(r't(?:es){i<=1:\d}t', 'teszt'), None) - self.assertEqual(regex.match(r't(?:es){i<=1:\d}t', - 'tes5t').fuzzy_changes, ([], [3], [])) - self.assertEqual(regex.match(r't(es){i<=1,0.*)(?PCTTCC){e<=1}(?P([ACGT]){4,6})(?PCAATACCGACTCCTCACTGTGT){e<=2}(?P([ACGT]){0,6}$)' - - m = regex.match(pattern, sequence, flags=regex.BESTMATCH) - self.assertEqual(m.span(), (0, 50)) - self.assertEqual(m.groupdict(), {'insert': 'TTCAGACGTGTGCT', 'anchor': 'CTTCC', 'umi': 'GATCT', 'sid': 'CAATACCGACTCCTCACTGTGT', 'end': 'GTCT'}) - - m = regex.match(pattern, sequence, flags=regex.ENHANCEMATCH) - self.assertEqual(m.span(), (0, 50)) - self.assertEqual(m.groupdict(), {'insert': 'TTCAGACGTGTGCT', 'anchor': 'CTTCC', 'umi': 'GATCT', 'sid': 'CAATACCGACTCCTCACTGTGT', 'end': 'GTCT'}) - - # Git issue 433: Disagreement between fuzzy_counts and fuzzy_changes - pattern = r'(?P.*)(?PAACACTGG){e<=1}(?P([AT][CG]){5}){e<=2}(?PGTAACCGAAG){e<=2}(?P([ACGT]){0,6}$)' - - sequence = 'GGAAAACACTGGTCTCAGTCTCGTAACCGAAGTGGTCG' - m = regex.match(pattern, sequence, flags=regex.BESTMATCH) - self.assertEqual(m.fuzzy_counts, (0, 0, 0)) - self.assertEqual(m.fuzzy_changes, ([], [], [])) - - sequence = 'GGAAAACACTGGTCTCAGTCTCGTCCCCGAAGTGGTCG' - m = regex.match(pattern, sequence, flags=regex.BESTMATCH) - self.assertEqual(m.fuzzy_counts, (2, 0, 0)) - self.assertEqual(m.fuzzy_changes, ([24, 25], [], [])) - - # Git issue 439: Unmatched groups: sub vs subf - self.assertEqual(regex.sub(r'(test1)|(test2)', r'matched: \1\2', 'test1'), 'matched: test1') - self.assertEqual(regex.subf(r'(test1)|(test2)', r'matched: {1}{2}', 'test1'), 'matched: test1') - self.assertEqual(regex.search(r'(test1)|(test2)', 'matched: test1').expand(r'matched: \1\2'), 'matched: test1'), - self.assertEqual(regex.search(r'(test1)|(test2)', 'matched: test1').expandf(r'matched: {1}{2}'), 'matched: test1') - - # Git issue 442: Fuzzy regex matching doesn't seem to test insertions correctly - self.assertEqual(regex.search(r"(?:\bha\b){i:[ ]}", "having"), None) - self.assertEqual(regex.search(r"(?:\bha\b){i:[ ]}", "having", flags=regex.I), None) - - # Git issue 467: Scoped inline flags 'a', 'u' and 'L' affect global flags - self.assertEqual(regex.match(r'(?a:\w)\w', 'd\N{CYRILLIC SMALL LETTER ZHE}').span(), (0, 2)) - self.assertEqual(regex.match(r'(?a:\w)(?u:\w)', 'd\N{CYRILLIC SMALL LETTER ZHE}').span(), (0, 2)) - - # Git issue 473: Emoji classified as letter - self.assertEqual(regex.match(r'^\p{LC}+$', '\N{SMILING CAT FACE WITH OPEN MOUTH}'), None) - self.assertEqual(regex.match(r'^\p{So}+$', '\N{SMILING CAT FACE WITH OPEN MOUTH}').span(), (0, 1)) - - # Git issue 474: regex has no equivalent to `re.Match.groups()` for captures - self.assertEqual(regex.match(r'(.)+', 'abc').allcaptures(), (['abc'], ['a', 'b', 'c'])) - self.assertEqual(regex.match(r'(.)+', 'abc').allspans(), ([(0, 3)], [(0, 1), (1, 2), (2, 3)])) - - # Git issue 477: \v for vertical spacing - self.assertEqual(bool(regex.fullmatch(r'\p{HorizSpace}+', '\t \xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000')), True) - self.assertEqual(bool(regex.fullmatch(r'\p{VertSpace}+', '\n\v\f\r\x85\u2028\u2029')), True) - - # Git issue 479: Segmentation fault when using conditional pattern - self.assertEqual(regex.match(r'(?(?<=A)|(?(?![^B])C|D))', 'A'), None) - self.assertEqual(regex.search(r'(?(?<=A)|(?(?![^B])C|D))', 'A').span(), (1, 1)) - - # Git issue 494: Backtracking failure matching regex ^a?(a?)b?c\1$ against string abca - self.assertEqual(regex.search(r"^a?(a?)b?c\1$", "abca").span(), (0, 4)) - - # Git issue 498: Conditional negative lookahead inside positive lookahead fails to match - self.assertEqual(regex.match(r'(?(?=a).|..)', 'ab').span(), (0, 1)) - self.assertEqual(regex.match(r'(?(?=b).|..)', 'ab').span(), (0, 2)) - self.assertEqual(regex.match(r'(?(?!a).|..)', 'ab').span(), (0, 2)) - self.assertEqual(regex.match(r'(?(?!b).|..)', 'ab').span(), (0, 1)) - - # Git issue 525: segfault when fuzzy matching empty list - self.assertEqual(regex.match(r"(\L){e<=5}", "blah", foo=[]).span(), (0, 0)) - - # Git issue 527: `VERBOSE`/`X` flag breaks `\N` escapes - self.assertEqual(regex.compile(r'\N{LATIN SMALL LETTER A}').match('a').span(), (0, 1)) - self.assertEqual(regex.compile(r'\N{LATIN SMALL LETTER A}', flags=regex.X).match('a').span(), (0, 1)) - - # Git issue 539: Bug: Partial matching fails on a simple example - self.assertEqual(regex.match(r"[^/]*b/ccc", "b/ccc", partial=True).span(), (0, 5)) - self.assertEqual(regex.match(r"[^/]*b/ccc", "b/ccb", partial=True), None) - self.assertEqual(regex.match(r"[^/]*b/ccc", "b/cc", partial=True).span(), (0, 4)) - self.assertEqual(regex.match(r"[^/]*b/xyz", "b/xy", partial=True).span(), (0, 4)) - self.assertEqual(regex.match(r"[^/]*b/xyz", "b/yz", partial=True), None) - - self.assertEqual(regex.match(r"(?i)[^/]*b/ccc", "b/ccc", partial=True).span(), (0, 5)) - self.assertEqual(regex.match(r"(?i)[^/]*b/ccc", "b/ccb", partial=True), None) - self.assertEqual(regex.match(r"(?i)[^/]*b/ccc", "b/cc", partial=True).span(), (0, 4)) - self.assertEqual(regex.match(r"(?i)[^/]*b/xyz", "b/xy", partial=True).span(), (0, 4)) - self.assertEqual(regex.match(r"(?i)[^/]*b/xyz", "b/yz", partial=True), None) - - # Git issue 546: Partial match not working in some instances with non-greedy capture - self.assertEqual(bool(regex.match(r'.*?', '<', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', '.*?', '', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', 'x', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', 'xyz abc', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', 'xyz abc foo', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', 'xyz abc foo ', partial=True)), True) - self.assertEqual(bool(regex.match(r'.*?', 'xyz abc foo bar', partial=True)), True) - - def test_fuzzy_ext(self): - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:a){e<=1:[a-z]}', 'e')), - True) - self.assertEqual(bool(regex.fullmatch(r'(?:a){e<=1:[a-z]}', 'e')), - True) - self.assertEqual(bool(regex.fullmatch(r'(?:a){e<=1:[a-z]}', '-')), - False) - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:a){e<=1:[a-z]}', '-')), - False) - - self.assertEqual(bool(regex.fullmatch(r'(?:a){e<=1:[a-z]}', 'ae')), - True) - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:a){e<=1:[a-z]}', - 'ae')), True) - self.assertEqual(bool(regex.fullmatch(r'(?:a){e<=1:[a-z]}', 'a-')), - False) - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:a){e<=1:[a-z]}', - 'a-')), False) - - self.assertEqual(bool(regex.fullmatch(r'(?:ab){e<=1:[a-z]}', 'ae')), - True) - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:ab){e<=1:[a-z]}', - 'ae')), True) - self.assertEqual(bool(regex.fullmatch(r'(?:ab){e<=1:[a-z]}', 'a-')), - False) - self.assertEqual(bool(regex.fullmatch(r'(?r)(?:ab){e<=1:[a-z]}', - 'a-')), False) - - self.assertEqual(bool(regex.fullmatch(r'(a)\1{e<=1:[a-z]}', 'ae')), - True) - self.assertEqual(bool(regex.fullmatch(r'(?r)\1{e<=1:[a-z]}(a)', - 'ea')), True) - self.assertEqual(bool(regex.fullmatch(r'(a)\1{e<=1:[a-z]}', 'a-')), - False) - self.assertEqual(bool(regex.fullmatch(r'(?r)\1{e<=1:[a-z]}(a)', - '-a')), False) - - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 'ts')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 'st')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 'st')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 'ts')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - '-s')), False) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 's-')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - 's-')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(?:\N{LATIN SMALL LETTER SHARP S}){e<=1:[a-z]}', - '-s')), False) - - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - 'ssst')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - 'ssts')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)\1{e<=1:[a-z]}(\N{LATIN SMALL LETTER SHARP S})', - 'stss')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)\1{e<=1:[a-z]}(\N{LATIN SMALL LETTER SHARP S})', - 'tsss')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - 'ss-s')), False) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - 'sss-')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - '-s')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(\N{LATIN SMALL LETTER SHARP S})\1{e<=1:[a-z]}', - 's-')), False) - - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(ss)\1{e<=1:[a-z]}', - '\N{LATIN SMALL LETTER SHARP S}ts')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(ss)\1{e<=1:[a-z]}', - '\N{LATIN SMALL LETTER SHARP S}st')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)\1{e<=1:[a-z]}(ss)', - 'st\N{LATIN SMALL LETTER SHARP S}')), True) - self.assertEqual(bool(regex.fullmatch(r'(?firu)\1{e<=1:[a-z]}(ss)', - 'ts\N{LATIN SMALL LETTER SHARP S}')), True) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(ss)\1{e<=1:[a-z]}', - '\N{LATIN SMALL LETTER SHARP S}-s')), False) - self.assertEqual(bool(regex.fullmatch(r'(?fiu)(ss)\1{e<=1:[a-z]}', - '\N{LATIN SMALL LETTER SHARP S}s-')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(ss)\1{e<=1:[a-z]}', - 's-\N{LATIN SMALL LETTER SHARP S}')), False) - self.assertEqual(bool(regex.fullmatch(r'(?firu)(ss)\1{e<=1:[a-z]}', - '-s\N{LATIN SMALL LETTER SHARP S}')), False) - - def test_subscripted_captures(self): - self.assertEqual(regex.match(r'(?P.)+', - 'abc').expandf('{0} {0[0]} {0[-1]}'), 'abc abc abc') - self.assertEqual(regex.match(r'(?P.)+', - 'abc').expandf('{1} {1[0]} {1[1]} {1[2]} {1[-1]} {1[-2]} {1[-3]}'), - 'c a b c c b a') - self.assertEqual(regex.match(r'(?P.)+', - 'abc').expandf('{x} {x[0]} {x[1]} {x[2]} {x[-1]} {x[-2]} {x[-3]}'), - 'c a b c c b a') - - self.assertEqual(regex.subf(r'(?P.)+', r'{0} {0[0]} {0[-1]}', - 'abc'), 'abc abc abc') - self.assertEqual(regex.subf(r'(?P.)+', - '{1} {1[0]} {1[1]} {1[2]} {1[-1]} {1[-2]} {1[-3]}', 'abc'), - 'c a b c c b a') - self.assertEqual(regex.subf(r'(?P.)+', - '{x} {x[0]} {x[1]} {x[2]} {x[-1]} {x[-2]} {x[-3]}', 'abc'), - 'c a b c c b a') - - def test_more_zerowidth(self): - if sys.version_info >= (3, 7, 0): - self.assertEqual(regex.split(r'\b|:+', 'a::bc'), ['', 'a', '', '', - 'bc', '']) - self.assertEqual(regex.sub(r'\b|:+', '-', 'a::bc'), '-a---bc-') - self.assertEqual(regex.findall(r'\b|:+', 'a::bc'), ['', '', '::', - '', '']) - self.assertEqual([m.span() for m in regex.finditer(r'\b|:+', - 'a::bc')], [(0, 0), (1, 1), (1, 3), (3, 3), (5, 5)]) - self.assertEqual([m.span() for m in regex.finditer(r'(?m)^\s*?$', - 'foo\n\n\nbar')], [(4, 4), (4, 5), (5, 5)]) - - def test_line_ending(self): - self.assertEqual(regex.findall(r'\R', '\r\n\n\x0B\f\r\x85\u2028\u2029'), - ['\r\n', '\n', '\x0B', '\f', '\r', '\x85', '\u2028', '\u2029']) - self.assertEqual(regex.findall(br'\R', b'\r\n\n\x0B\f\r\x85'), [b'\r\n', - b'\n', b'\x0B', b'\f', b'\r']) - -def test_main(): - unittest.main(verbosity=2) - -if __name__ == "__main__": - test_main() diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/AUTHORS.rst b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/AUTHORS.rst deleted file mode 100644 index 54cb3c9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/AUTHORS.rst +++ /dev/null @@ -1,14 +0,0 @@ -Development Lead ----------------- - -- Ian Stapleton Cordasco - -Contributors ------------- - -- Thomas Weißschuh -- Kostya Esmukov -- Derek Higgins -- Victor Stinner -- Viktor Haag -- Seth Michael Larson diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/LICENSE deleted file mode 100644 index 72ce24c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2014 Ian Cordasco, Rackspace - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/METADATA deleted file mode 100644 index 2ddcde0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/METADATA +++ /dev/null @@ -1,230 +0,0 @@ -Metadata-Version: 2.1 -Name: rfc3986 -Version: 1.5.0 -Summary: Validating URI References per RFC 3986 -Home-page: http://rfc3986.readthedocs.io -Author: Ian Stapleton Cordasco -Author-email: graffatcolmingov@gmail.com -License: Apache 2.0 -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Provides-Extra: idna2008 -Requires-Dist: idna ; extra == 'idna2008' - -rfc3986 -======= - -A Python implementation of `RFC 3986`_ including validation and authority -parsing. - -Installation ------------- - -Use pip to install ``rfc3986`` like so:: - - pip install rfc3986 - -License -------- - -`Apache License Version 2.0`_ - -Example Usage -------------- - -The following are the two most common use cases envisioned for ``rfc3986``. - -Replacing ``urlparse`` -`````````````````````` - -To parse a URI and receive something very similar to the standard library's -``urllib.parse.urlparse`` - -.. code-block:: python - - from rfc3986 import urlparse - - ssh = urlparse('ssh://user@git.openstack.org:29418/openstack/glance.git') - print(ssh.scheme) # => ssh - print(ssh.userinfo) # => user - print(ssh.params) # => None - print(ssh.port) # => 29418 - -To create a copy of it with new pieces you can use ``copy_with``: - -.. code-block:: python - - new_ssh = ssh.copy_with( - scheme='https' - userinfo='', - port=443, - path='/openstack/glance' - ) - print(new_ssh.scheme) # => https - print(new_ssh.userinfo) # => None - # etc. - -Strictly Parsing a URI and Applying Validation -`````````````````````````````````````````````` - -To parse a URI into a convenient named tuple, you can simply: - -.. code-block:: python - - from rfc3986 import uri_reference - - example = uri_reference('http://example.com') - email = uri_reference('mailto:user@domain.com') - ssh = uri_reference('ssh://user@git.openstack.org:29418/openstack/keystone.git') - -With a parsed URI you can access data about the components: - -.. code-block:: python - - print(example.scheme) # => http - print(email.path) # => user@domain.com - print(ssh.userinfo) # => user - print(ssh.host) # => git.openstack.org - print(ssh.port) # => 29418 - -It can also parse URIs with unicode present: - -.. code-block:: python - - uni = uri_reference(b'http://httpbin.org/get?utf8=\xe2\x98\x83') # ☃ - print(uni.query) # utf8=%E2%98%83 - -With a parsed URI you can also validate it: - -.. code-block:: python - - if ssh.is_valid(): - subprocess.call(['git', 'clone', ssh.unsplit()]) - -You can also take a parsed URI and normalize it: - -.. code-block:: python - - mangled = uri_reference('hTTp://exAMPLe.COM') - print(mangled.scheme) # => hTTp - print(mangled.authority) # => exAMPLe.COM - - normal = mangled.normalize() - print(normal.scheme) # => http - print(mangled.authority) # => example.com - -But these two URIs are (functionally) equivalent: - -.. code-block:: python - - if normal == mangled: - webbrowser.open(normal.unsplit()) - -Your paths, queries, and fragments are safe with us though: - -.. code-block:: python - - mangled = uri_reference('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth') - normal = mangled.normalize() - assert normal == 'hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth' - assert normal == 'http://example.com/Some/reallY/biZZare/pAth' - assert normal != 'http://example.com/some/really/bizzare/path' - -If you do not actually need a real reference object and just want to normalize -your URI: - -.. code-block:: python - - from rfc3986 import normalize_uri - - assert (normalize_uri('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth') == - 'http://example.com/Some/reallY/biZZare/pAth') - -You can also very simply validate a URI: - -.. code-block:: python - - from rfc3986 import is_valid_uri - - assert is_valid_uri('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth') - -Requiring Components -~~~~~~~~~~~~~~~~~~~~ - -You can validate that a particular string is a valid URI and require -independent components: - -.. code-block:: python - - from rfc3986 import is_valid_uri - - assert is_valid_uri('http://localhost:8774/v2/resource', - require_scheme=True, - require_authority=True, - require_path=True) - - # Assert that a mailto URI is invalid if you require an authority - # component - assert is_valid_uri('mailto:user@example.com', require_authority=True) is False - -If you have an instance of a ``URIReference``, you can pass the same arguments -to ``URIReference#is_valid``, e.g., - -.. code-block:: python - - from rfc3986 import uri_reference - - http = uri_reference('http://localhost:8774/v2/resource') - assert uri.is_valid(require_scheme=True, - require_authority=True, - require_path=True) - - # Assert that a mailto URI is invalid if you require an authority - # component - mailto = uri_reference('mailto:user@example.com') - assert uri.is_valid(require_authority=True) is False - -Alternatives ------------- - -- `rfc3987 `_ - - This is a direct competitor to this library, with extra features, - licensed under the GPL. - -- `uritools `_ - - This can parse URIs in the manner of RFC 3986 but provides no validation and - only recently added Python 3 support. - -- Standard library's `urlparse`/`urllib.parse` - - The functions in these libraries can only split a URI (valid or not) and - provide no validation. - -Contributing ------------- - -This project follows and enforces the Python Software Foundation's `Code of -Conduct `_. - -If you would like to contribute but do not have a bug or feature in mind, feel -free to email Ian and find out how you can help. - -The git repository for this project is maintained at -https://github.com/python-hyper/rfc3986 - -.. _RFC 3986: http://tools.ietf.org/html/rfc3986 -.. _Apache License Version 2.0: https://www.apache.org/licenses/LICENSE-2.0 - - diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/RECORD deleted file mode 100644 index 2ee492c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/RECORD +++ /dev/null @@ -1,19 +0,0 @@ -rfc3986/__init__.py,sha256=Yc1nYWLNwBn1XUCt3lPMC6cPD3S82FKPPc4IpTaFjCE,1591 -rfc3986/_mixin.py,sha256=iFnLyRbd-QMQv9LlYwglAt-vNA4CxpBhnZMu-XyKP4w,13280 -rfc3986/abnf_regexp.py,sha256=hTIxwQQcngkTmmDn0T0m0_6dZZIiMovYEsITUrZIL3Q,9121 -rfc3986/api.py,sha256=UzjPnQ4_G0ludMVXEeq6CVYmFQ55rDpKvHakGZMxVe8,3887 -rfc3986/builder.py,sha256=vuI6u7B3UQbVrh47xDF7X5sducTxzkLQeuvW7vPavok,12757 -rfc3986/compat.py,sha256=51xDR7kfVhaM7GqTLmw-lQY4jv2mw2MbCNuBnG4PnbA,1644 -rfc3986/exceptions.py,sha256=dFYnm-TabVYpWUEPXqtGp8xfSg1wWYk09TaUjCetWYI,3847 -rfc3986/iri.py,sha256=BX1nFD0JyZnUfAHxDFqyz0hN8J-YfKxIhYJLyBZGAZo,5520 -rfc3986/misc.py,sha256=bye9xhySD_GshuL_MD0VTledl6jBw_ErG8kXtTNXzXQ,4163 -rfc3986/normalizers.py,sha256=f6oLvNUadxZDJDtx3JvqF_exGGD7PvLaibYQBUfh2NE,5294 -rfc3986/parseresult.py,sha256=NvbPpPzuuputHpJc4J2cjcNy6B7c6rscFqzSnksDWmc,14742 -rfc3986/uri.py,sha256=LYNAlr2ujVfCa6jcV8o1I1hOuviuuXsSRHpST2DyvAw,5225 -rfc3986/validators.py,sha256=qcvNnrpk2el-otJN-ZRGZ0PE4xaSEP97lKREXG_YtpM,13839 -rfc3986-1.5.0.dist-info/AUTHORS.rst,sha256=QjlDdMHiNeQv1lPqHeGQ4OtiEPCwFafJLu7t23AXDHo,223 -rfc3986-1.5.0.dist-info/LICENSE,sha256=wN3OM7-sSApmveQMWQ7eJkekyKcp3LDSzkbAFEc9Xdg,564 -rfc3986-1.5.0.dist-info/METADATA,sha256=qkuCB_ifgypthNS6-M-IOKli-F3YPR8xzOOXPHEu2Wo,6458 -rfc3986-1.5.0.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 -rfc3986-1.5.0.dist-info/top_level.txt,sha256=Z10Qesb0UV9AbxlTIV9AnOAwk-343WnE85K8xfN4OmA,8 -rfc3986-1.5.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/WHEEL deleted file mode 100644 index 01b8fc7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/top_level.txt deleted file mode 100644 index af30258..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986-1.5.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -rfc3986 diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/__init__.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/__init__.py deleted file mode 100644 index a052299..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -An implementation of semantics and validations described in RFC 3986. - -See http://rfc3986.readthedocs.io/ for detailed documentation. - -:copyright: (c) 2014 Rackspace -:license: Apache v2.0, see LICENSE for details -""" - -from .api import iri_reference -from .api import IRIReference -from .api import is_valid_uri -from .api import normalize_uri -from .api import uri_reference -from .api import URIReference -from .api import urlparse -from .parseresult import ParseResult - -__title__ = "rfc3986" -__author__ = "Ian Stapleton Cordasco" -__author_email__ = "graffatcolmingov@gmail.com" -__license__ = "Apache v2.0" -__copyright__ = "Copyright 2014 Rackspace; 2016 Ian Stapleton Cordasco" -__version__ = "1.5.0" - -__all__ = ( - "ParseResult", - "URIReference", - "IRIReference", - "is_valid_uri", - "normalize_uri", - "uri_reference", - "iri_reference", - "urlparse", - "__title__", - "__author__", - "__author_email__", - "__license__", - "__copyright__", - "__version__", -) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/_mixin.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/_mixin.py deleted file mode 100644 index 46e200e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/_mixin.py +++ /dev/null @@ -1,373 +0,0 @@ -"""Module containing the implementation of the URIMixin class.""" -import warnings - -from . import exceptions as exc -from . import misc -from . import normalizers -from . import validators - - -class URIMixin(object): - """Mixin with all shared methods for URIs and IRIs.""" - - __hash__ = tuple.__hash__ - - def authority_info(self): - """Return a dictionary with the ``userinfo``, ``host``, and ``port``. - - If the authority is not valid, it will raise a - :class:`~rfc3986.exceptions.InvalidAuthority` Exception. - - :returns: - ``{'userinfo': 'username:password', 'host': 'www.example.com', - 'port': '80'}`` - :rtype: dict - :raises rfc3986.exceptions.InvalidAuthority: - If the authority is not ``None`` and can not be parsed. - """ - if not self.authority: - return {"userinfo": None, "host": None, "port": None} - - match = self._match_subauthority() - - if match is None: - # In this case, we have an authority that was parsed from the URI - # Reference, but it cannot be further parsed by our - # misc.SUBAUTHORITY_MATCHER. In this case it must not be a valid - # authority. - raise exc.InvalidAuthority(self.authority.encode(self.encoding)) - - # We had a match, now let's ensure that it is actually a valid host - # address if it is IPv4 - matches = match.groupdict() - host = matches.get("host") - - if ( - host - and misc.IPv4_MATCHER.match(host) - and not validators.valid_ipv4_host_address(host) - ): - # If we have a host, it appears to be IPv4 and it does not have - # valid bytes, it is an InvalidAuthority. - raise exc.InvalidAuthority(self.authority.encode(self.encoding)) - - return matches - - def _match_subauthority(self): - return misc.SUBAUTHORITY_MATCHER.match(self.authority) - - @property - def host(self): - """If present, a string representing the host.""" - try: - authority = self.authority_info() - except exc.InvalidAuthority: - return None - return authority["host"] - - @property - def port(self): - """If present, the port extracted from the authority.""" - try: - authority = self.authority_info() - except exc.InvalidAuthority: - return None - return authority["port"] - - @property - def userinfo(self): - """If present, the userinfo extracted from the authority.""" - try: - authority = self.authority_info() - except exc.InvalidAuthority: - return None - return authority["userinfo"] - - def is_absolute(self): - """Determine if this URI Reference is an absolute URI. - - See http://tools.ietf.org/html/rfc3986#section-4.3 for explanation. - - :returns: ``True`` if it is an absolute URI, ``False`` otherwise. - :rtype: bool - """ - return bool(misc.ABSOLUTE_URI_MATCHER.match(self.unsplit())) - - def is_valid(self, **kwargs): - """Determine if the URI is valid. - - .. deprecated:: 1.1.0 - - Use the :class:`~rfc3986.validators.Validator` object instead. - - :param bool require_scheme: Set to ``True`` if you wish to require the - presence of the scheme component. - :param bool require_authority: Set to ``True`` if you wish to require - the presence of the authority component. - :param bool require_path: Set to ``True`` if you wish to require the - presence of the path component. - :param bool require_query: Set to ``True`` if you wish to require the - presence of the query component. - :param bool require_fragment: Set to ``True`` if you wish to require - the presence of the fragment component. - :returns: ``True`` if the URI is valid. ``False`` otherwise. - :rtype: bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - validators = [ - (self.scheme_is_valid, kwargs.get("require_scheme", False)), - (self.authority_is_valid, kwargs.get("require_authority", False)), - (self.path_is_valid, kwargs.get("require_path", False)), - (self.query_is_valid, kwargs.get("require_query", False)), - (self.fragment_is_valid, kwargs.get("require_fragment", False)), - ] - return all(v(r) for v, r in validators) - - def authority_is_valid(self, require=False): - """Determine if the authority component is valid. - - .. deprecated:: 1.1.0 - - Use the :class:`~rfc3986.validators.Validator` object instead. - - :param bool require: - Set to ``True`` to require the presence of this component. - :returns: - ``True`` if the authority is valid. ``False`` otherwise. - :rtype: - bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - try: - self.authority_info() - except exc.InvalidAuthority: - return False - - return validators.authority_is_valid( - self.authority, - host=self.host, - require=require, - ) - - def scheme_is_valid(self, require=False): - """Determine if the scheme component is valid. - - .. deprecated:: 1.1.0 - - Use the :class:`~rfc3986.validators.Validator` object instead. - - :param str require: Set to ``True`` to require the presence of this - component. - :returns: ``True`` if the scheme is valid. ``False`` otherwise. - :rtype: bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - return validators.scheme_is_valid(self.scheme, require) - - def path_is_valid(self, require=False): - """Determine if the path component is valid. - - .. deprecated:: 1.1.0 - - Use the :class:`~rfc3986.validators.Validator` object instead. - - :param str require: Set to ``True`` to require the presence of this - component. - :returns: ``True`` if the path is valid. ``False`` otherwise. - :rtype: bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - return validators.path_is_valid(self.path, require) - - def query_is_valid(self, require=False): - """Determine if the query component is valid. - - .. deprecated:: 1.1.0 - - Use the :class:`~rfc3986.validators.Validator` object instead. - - :param str require: Set to ``True`` to require the presence of this - component. - :returns: ``True`` if the query is valid. ``False`` otherwise. - :rtype: bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - return validators.query_is_valid(self.query, require) - - def fragment_is_valid(self, require=False): - """Determine if the fragment component is valid. - - .. deprecated:: 1.1.0 - - Use the Validator object instead. - - :param str require: Set to ``True`` to require the presence of this - component. - :returns: ``True`` if the fragment is valid. ``False`` otherwise. - :rtype: bool - """ - warnings.warn( - "Please use rfc3986.validators.Validator instead. " - "This method will be eventually removed.", - DeprecationWarning, - ) - return validators.fragment_is_valid(self.fragment, require) - - def normalized_equality(self, other_ref): - """Compare this URIReference to another URIReference. - - :param URIReference other_ref: (required), The reference with which - we're comparing. - :returns: ``True`` if the references are equal, ``False`` otherwise. - :rtype: bool - """ - return tuple(self.normalize()) == tuple(other_ref.normalize()) - - def resolve_with(self, base_uri, strict=False): - """Use an absolute URI Reference to resolve this relative reference. - - Assuming this is a relative reference that you would like to resolve, - use the provided base URI to resolve it. - - See http://tools.ietf.org/html/rfc3986#section-5 for more information. - - :param base_uri: Either a string or URIReference. It must be an - absolute URI or it will raise an exception. - :returns: A new URIReference which is the result of resolving this - reference using ``base_uri``. - :rtype: :class:`URIReference` - :raises rfc3986.exceptions.ResolutionError: - If the ``base_uri`` is not an absolute URI. - """ - if not isinstance(base_uri, URIMixin): - base_uri = type(self).from_string(base_uri) - - if not base_uri.is_absolute(): - raise exc.ResolutionError(base_uri) - - # This is optional per - # http://tools.ietf.org/html/rfc3986#section-5.2.1 - base_uri = base_uri.normalize() - - # The reference we're resolving - resolving = self - - if not strict and resolving.scheme == base_uri.scheme: - resolving = resolving.copy_with(scheme=None) - - # http://tools.ietf.org/html/rfc3986#page-32 - if resolving.scheme is not None: - target = resolving.copy_with( - path=normalizers.normalize_path(resolving.path) - ) - else: - if resolving.authority is not None: - target = resolving.copy_with( - scheme=base_uri.scheme, - path=normalizers.normalize_path(resolving.path), - ) - else: - if resolving.path is None: - if resolving.query is not None: - query = resolving.query - else: - query = base_uri.query - target = resolving.copy_with( - scheme=base_uri.scheme, - authority=base_uri.authority, - path=base_uri.path, - query=query, - ) - else: - if resolving.path.startswith("/"): - path = normalizers.normalize_path(resolving.path) - else: - path = normalizers.normalize_path( - misc.merge_paths(base_uri, resolving.path) - ) - target = resolving.copy_with( - scheme=base_uri.scheme, - authority=base_uri.authority, - path=path, - query=resolving.query, - ) - return target - - def unsplit(self): - """Create a URI string from the components. - - :returns: The URI Reference reconstituted as a string. - :rtype: str - """ - # See http://tools.ietf.org/html/rfc3986#section-5.3 - result_list = [] - if self.scheme: - result_list.extend([self.scheme, ":"]) - if self.authority: - result_list.extend(["//", self.authority]) - if self.path: - result_list.append(self.path) - if self.query is not None: - result_list.extend(["?", self.query]) - if self.fragment is not None: - result_list.extend(["#", self.fragment]) - return "".join(result_list) - - def copy_with( - self, - scheme=misc.UseExisting, - authority=misc.UseExisting, - path=misc.UseExisting, - query=misc.UseExisting, - fragment=misc.UseExisting, - ): - """Create a copy of this reference with the new components. - - :param str scheme: - (optional) The scheme to use for the new reference. - :param str authority: - (optional) The authority to use for the new reference. - :param str path: - (optional) The path to use for the new reference. - :param str query: - (optional) The query to use for the new reference. - :param str fragment: - (optional) The fragment to use for the new reference. - :returns: - New URIReference with provided components. - :rtype: - URIReference - """ - attributes = { - "scheme": scheme, - "authority": authority, - "path": path, - "query": query, - "fragment": fragment, - } - for key, value in list(attributes.items()): - if value is misc.UseExisting: - del attributes[key] - uri = self._replace(**attributes) - uri.encoding = self.encoding - return uri diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/abnf_regexp.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/abnf_regexp.py deleted file mode 100644 index a2e7ee7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/abnf_regexp.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module for the regular expressions crafted from ABNF.""" - -import sys - -# https://tools.ietf.org/html/rfc3986#page-13 -GEN_DELIMS = GENERIC_DELIMITERS = ":/?#[]@" -GENERIC_DELIMITERS_SET = set(GENERIC_DELIMITERS) -# https://tools.ietf.org/html/rfc3986#page-13 -SUB_DELIMS = SUB_DELIMITERS = "!$&'()*+,;=" -SUB_DELIMITERS_SET = set(SUB_DELIMITERS) -# Escape the '*' for use in regular expressions -SUB_DELIMITERS_RE = r"!$&'()\*+,;=" -RESERVED_CHARS_SET = GENERIC_DELIMITERS_SET.union(SUB_DELIMITERS_SET) -ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" -DIGIT = "0123456789" -# https://tools.ietf.org/html/rfc3986#section-2.3 -UNRESERVED = UNRESERVED_CHARS = ALPHA + DIGIT + r"._!-~" -UNRESERVED_CHARS_SET = set(UNRESERVED_CHARS) -NON_PCT_ENCODED_SET = RESERVED_CHARS_SET.union(UNRESERVED_CHARS_SET) -# We need to escape the '-' in this case: -UNRESERVED_RE = r"A-Za-z0-9._~\-" - -# Percent encoded character values -PERCENT_ENCODED = PCT_ENCODED = "%[A-Fa-f0-9]{2}" -PCHAR = "([" + UNRESERVED_RE + SUB_DELIMITERS_RE + ":@]|%s)" % PCT_ENCODED - -# NOTE(sigmavirus24): We're going to use more strict regular expressions -# than appear in Appendix B for scheme. This will prevent over-eager -# consuming of items that aren't schemes. -SCHEME_RE = "[a-zA-Z][a-zA-Z0-9+.-]*" -_AUTHORITY_RE = "[^\\\\/?#]*" -_PATH_RE = "[^?#]*" -_QUERY_RE = "[^#]*" -_FRAGMENT_RE = ".*" - -# Extracted from http://tools.ietf.org/html/rfc3986#appendix-B -COMPONENT_PATTERN_DICT = { - "scheme": SCHEME_RE, - "authority": _AUTHORITY_RE, - "path": _PATH_RE, - "query": _QUERY_RE, - "fragment": _FRAGMENT_RE, -} - -# See http://tools.ietf.org/html/rfc3986#appendix-B -# In this case, we name each of the important matches so we can use -# SRE_Match#groupdict to parse the values out if we so choose. This is also -# modified to ignore other matches that are not important to the parsing of -# the reference so we can also simply use SRE_Match#groups. -URL_PARSING_RE = ( - r"(?:(?P{scheme}):)?(?://(?P{authority}))?" - r"(?P{path})(?:\?(?P{query}))?" - r"(?:#(?P{fragment}))?" -).format(**COMPONENT_PATTERN_DICT) - - -# ######################### -# Authority Matcher Section -# ######################### - -# Host patterns, see: http://tools.ietf.org/html/rfc3986#section-3.2.2 -# The pattern for a regular name, e.g., www.google.com, api.github.com -REGULAR_NAME_RE = REG_NAME = "((?:{0}|[{1}])*)".format( - "%[0-9A-Fa-f]{2}", SUB_DELIMITERS_RE + UNRESERVED_RE -) -# The pattern for an IPv4 address, e.g., 192.168.255.255, 127.0.0.1, -IPv4_RE = r"([0-9]{1,3}\.){3}[0-9]{1,3}" -# Hexadecimal characters used in each piece of an IPv6 address -HEXDIG_RE = "[0-9A-Fa-f]{1,4}" -# Least-significant 32 bits of an IPv6 address -LS32_RE = "({hex}:{hex}|{ipv4})".format(hex=HEXDIG_RE, ipv4=IPv4_RE) -# Substitutions into the following patterns for IPv6 patterns defined -# http://tools.ietf.org/html/rfc3986#page-20 -_subs = {"hex": HEXDIG_RE, "ls32": LS32_RE} - -# Below: h16 = hexdig, see: https://tools.ietf.org/html/rfc5234 for details -# about ABNF (Augmented Backus-Naur Form) use in the comments -variations = [ - # 6( h16 ":" ) ls32 - "(%(hex)s:){6}%(ls32)s" % _subs, - # "::" 5( h16 ":" ) ls32 - "::(%(hex)s:){5}%(ls32)s" % _subs, - # [ h16 ] "::" 4( h16 ":" ) ls32 - "(%(hex)s)?::(%(hex)s:){4}%(ls32)s" % _subs, - # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - "((%(hex)s:)?%(hex)s)?::(%(hex)s:){3}%(ls32)s" % _subs, - # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - "((%(hex)s:){0,2}%(hex)s)?::(%(hex)s:){2}%(ls32)s" % _subs, - # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - "((%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s" % _subs, - # [ *4( h16 ":" ) h16 ] "::" ls32 - "((%(hex)s:){0,4}%(hex)s)?::%(ls32)s" % _subs, - # [ *5( h16 ":" ) h16 ] "::" h16 - "((%(hex)s:){0,5}%(hex)s)?::%(hex)s" % _subs, - # [ *6( h16 ":" ) h16 ] "::" - "((%(hex)s:){0,6}%(hex)s)?::" % _subs, -] - -IPv6_RE = "(({0})|({1})|({2})|({3})|({4})|({5})|({6})|({7})|({8}))".format( - *variations -) - -IPv_FUTURE_RE = r"v[0-9A-Fa-f]+\.[%s]+" % ( - UNRESERVED_RE + SUB_DELIMITERS_RE + ":" -) - -# RFC 6874 Zone ID ABNF -ZONE_ID = "(?:[" + UNRESERVED_RE + "]|" + PCT_ENCODED + ")+" - -IPv6_ADDRZ_RFC4007_RE = IPv6_RE + "(?:(?:%25|%)" + ZONE_ID + ")?" -IPv6_ADDRZ_RE = IPv6_RE + "(?:%25" + ZONE_ID + ")?" - -IP_LITERAL_RE = r"\[({0}|{1})\]".format( - IPv6_ADDRZ_RFC4007_RE, - IPv_FUTURE_RE, -) - -# Pattern for matching the host piece of the authority -HOST_RE = HOST_PATTERN = "({0}|{1}|{2})".format( - REG_NAME, - IPv4_RE, - IP_LITERAL_RE, -) -USERINFO_RE = ( - "^([" + UNRESERVED_RE + SUB_DELIMITERS_RE + ":]|%s)+" % (PCT_ENCODED) -) -PORT_RE = "[0-9]{1,5}" - -# #################### -# Path Matcher Section -# #################### - -# See http://tools.ietf.org/html/rfc3986#section-3.3 for more information -# about the path patterns defined below. -segments = { - "segment": PCHAR + "*", - # Non-zero length segment - "segment-nz": PCHAR + "+", - # Non-zero length segment without ":" - "segment-nz-nc": PCHAR.replace(":", "") + "+", -} - -# Path types taken from Section 3.3 (linked above) -PATH_EMPTY = "^$" -PATH_ROOTLESS = "%(segment-nz)s(/%(segment)s)*" % segments -PATH_NOSCHEME = "%(segment-nz-nc)s(/%(segment)s)*" % segments -PATH_ABSOLUTE = "/(%s)?" % PATH_ROOTLESS -PATH_ABEMPTY = "(/%(segment)s)*" % segments -PATH_RE = "^(%s|%s|%s|%s|%s)$" % ( - PATH_ABEMPTY, - PATH_ABSOLUTE, - PATH_NOSCHEME, - PATH_ROOTLESS, - PATH_EMPTY, -) - -FRAGMENT_RE = QUERY_RE = ( - "^([/?:@" + UNRESERVED_RE + SUB_DELIMITERS_RE + "]|%s)*$" % PCT_ENCODED -) - -# ########################## -# Relative reference matcher -# ########################## - -# See http://tools.ietf.org/html/rfc3986#section-4.2 for details -RELATIVE_PART_RE = "(//%s%s|%s|%s|%s)" % ( - COMPONENT_PATTERN_DICT["authority"], - PATH_ABEMPTY, - PATH_ABSOLUTE, - PATH_NOSCHEME, - PATH_EMPTY, -) - -# See http://tools.ietf.org/html/rfc3986#section-3 for definition -HIER_PART_RE = "(//%s%s|%s|%s|%s)" % ( - COMPONENT_PATTERN_DICT["authority"], - PATH_ABEMPTY, - PATH_ABSOLUTE, - PATH_ROOTLESS, - PATH_EMPTY, -) - -# ############### -# IRIs / RFC 3987 -# ############### - -# Only wide-unicode gets the high-ranges of UCSCHAR -if sys.maxunicode > 0xFFFF: # pragma: no cover - IPRIVATE = u"\uE000-\uF8FF\U000F0000-\U000FFFFD\U00100000-\U0010FFFD" - UCSCHAR_RE = ( - u"\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF" - u"\U00010000-\U0001FFFD\U00020000-\U0002FFFD" - u"\U00030000-\U0003FFFD\U00040000-\U0004FFFD" - u"\U00050000-\U0005FFFD\U00060000-\U0006FFFD" - u"\U00070000-\U0007FFFD\U00080000-\U0008FFFD" - u"\U00090000-\U0009FFFD\U000A0000-\U000AFFFD" - u"\U000B0000-\U000BFFFD\U000C0000-\U000CFFFD" - u"\U000D0000-\U000DFFFD\U000E1000-\U000EFFFD" - ) -else: # pragma: no cover - IPRIVATE = u"\uE000-\uF8FF" - UCSCHAR_RE = u"\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF" - -IUNRESERVED_RE = u"A-Za-z0-9\\._~\\-" + UCSCHAR_RE -IPCHAR = u"([" + IUNRESERVED_RE + SUB_DELIMITERS_RE + u":@]|%s)" % PCT_ENCODED - -isegments = { - "isegment": IPCHAR + u"*", - # Non-zero length segment - "isegment-nz": IPCHAR + u"+", - # Non-zero length segment without ":" - "isegment-nz-nc": IPCHAR.replace(":", "") + u"+", -} - -IPATH_ROOTLESS = u"%(isegment-nz)s(/%(isegment)s)*" % isegments -IPATH_NOSCHEME = u"%(isegment-nz-nc)s(/%(isegment)s)*" % isegments -IPATH_ABSOLUTE = u"/(?:%s)?" % IPATH_ROOTLESS -IPATH_ABEMPTY = u"(?:/%(isegment)s)*" % isegments -IPATH_RE = u"^(?:%s|%s|%s|%s|%s)$" % ( - IPATH_ABEMPTY, - IPATH_ABSOLUTE, - IPATH_NOSCHEME, - IPATH_ROOTLESS, - PATH_EMPTY, -) - -IREGULAR_NAME_RE = IREG_NAME = u"(?:{0}|[{1}])*".format( - u"%[0-9A-Fa-f]{2}", SUB_DELIMITERS_RE + IUNRESERVED_RE -) - -IHOST_RE = IHOST_PATTERN = u"({0}|{1}|{2})".format( - IREG_NAME, - IPv4_RE, - IP_LITERAL_RE, -) - -IUSERINFO_RE = ( - u"^(?:[" + IUNRESERVED_RE + SUB_DELIMITERS_RE + u":]|%s)+" % (PCT_ENCODED) -) - -IFRAGMENT_RE = ( - u"^(?:[/?:@" - + IUNRESERVED_RE - + SUB_DELIMITERS_RE - + u"]|%s)*$" % PCT_ENCODED -) -IQUERY_RE = ( - u"^(?:[/?:@" - + IUNRESERVED_RE - + SUB_DELIMITERS_RE - + IPRIVATE - + u"]|%s)*$" % PCT_ENCODED -) - -IRELATIVE_PART_RE = u"(//%s%s|%s|%s|%s)" % ( - COMPONENT_PATTERN_DICT["authority"], - IPATH_ABEMPTY, - IPATH_ABSOLUTE, - IPATH_NOSCHEME, - PATH_EMPTY, -) - -IHIER_PART_RE = u"(//%s%s|%s|%s|%s)" % ( - COMPONENT_PATTERN_DICT["authority"], - IPATH_ABEMPTY, - IPATH_ABSOLUTE, - IPATH_ROOTLESS, - PATH_EMPTY, -) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/api.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/api.py deleted file mode 100644 index 1e098b3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/api.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Module containing the simple and functional API for rfc3986. - -This module defines functions and provides access to the public attributes -and classes of rfc3986. -""" - -from .iri import IRIReference -from .parseresult import ParseResult -from .uri import URIReference - - -def uri_reference(uri, encoding="utf-8"): - """Parse a URI string into a URIReference. - - This is a convenience function. You could achieve the same end by using - ``URIReference.from_string(uri)``. - - :param str uri: The URI which needs to be parsed into a reference. - :param str encoding: The encoding of the string provided - :returns: A parsed URI - :rtype: :class:`URIReference` - """ - return URIReference.from_string(uri, encoding) - - -def iri_reference(iri, encoding="utf-8"): - """Parse a IRI string into an IRIReference. - - This is a convenience function. You could achieve the same end by using - ``IRIReference.from_string(iri)``. - - :param str iri: The IRI which needs to be parsed into a reference. - :param str encoding: The encoding of the string provided - :returns: A parsed IRI - :rtype: :class:`IRIReference` - """ - return IRIReference.from_string(iri, encoding) - - -def is_valid_uri(uri, encoding="utf-8", **kwargs): - """Determine if the URI given is valid. - - This is a convenience function. You could use either - ``uri_reference(uri).is_valid()`` or - ``URIReference.from_string(uri).is_valid()`` to achieve the same result. - - :param str uri: The URI to be validated. - :param str encoding: The encoding of the string provided - :param bool require_scheme: Set to ``True`` if you wish to require the - presence of the scheme component. - :param bool require_authority: Set to ``True`` if you wish to require the - presence of the authority component. - :param bool require_path: Set to ``True`` if you wish to require the - presence of the path component. - :param bool require_query: Set to ``True`` if you wish to require the - presence of the query component. - :param bool require_fragment: Set to ``True`` if you wish to require the - presence of the fragment component. - :returns: ``True`` if the URI is valid, ``False`` otherwise. - :rtype: bool - """ - return URIReference.from_string(uri, encoding).is_valid(**kwargs) - - -def normalize_uri(uri, encoding="utf-8"): - """Normalize the given URI. - - This is a convenience function. You could use either - ``uri_reference(uri).normalize().unsplit()`` or - ``URIReference.from_string(uri).normalize().unsplit()`` instead. - - :param str uri: The URI to be normalized. - :param str encoding: The encoding of the string provided - :returns: The normalized URI. - :rtype: str - """ - normalized_reference = URIReference.from_string(uri, encoding).normalize() - return normalized_reference.unsplit() - - -def urlparse(uri, encoding="utf-8"): - """Parse a given URI and return a ParseResult. - - This is a partial replacement of the standard library's urlparse function. - - :param str uri: The URI to be parsed. - :param str encoding: The encoding of the string provided. - :returns: A parsed URI - :rtype: :class:`~rfc3986.parseresult.ParseResult` - """ - return ParseResult.from_string(uri, encoding, strict=False) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/builder.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/builder.py deleted file mode 100644 index 8fc178c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/builder.py +++ /dev/null @@ -1,389 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017 Ian Stapleton Cordasco -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module containing the logic for the URIBuilder object.""" -from . import compat -from . import normalizers -from . import uri -from . import uri_reference - - -class URIBuilder(object): - """Object to aid in building up a URI Reference from parts. - - .. note:: - - This object should be instantiated by the user, but it's recommended - that it is not provided with arguments. Instead, use the available - method to populate the fields. - - """ - - def __init__( - self, - scheme=None, - userinfo=None, - host=None, - port=None, - path=None, - query=None, - fragment=None, - ): - """Initialize our URI builder. - - :param str scheme: - (optional) - :param str userinfo: - (optional) - :param str host: - (optional) - :param int port: - (optional) - :param str path: - (optional) - :param str query: - (optional) - :param str fragment: - (optional) - """ - self.scheme = scheme - self.userinfo = userinfo - self.host = host - self.port = port - self.path = path - self.query = query - self.fragment = fragment - - def __repr__(self): - """Provide a convenient view of our builder object.""" - formatstr = ( - "URIBuilder(scheme={b.scheme}, userinfo={b.userinfo}, " - "host={b.host}, port={b.port}, path={b.path}, " - "query={b.query}, fragment={b.fragment})" - ) - return formatstr.format(b=self) - - @classmethod - def from_uri(cls, reference): - """Initialize the URI builder from another URI. - - Takes the given URI reference and creates a new URI builder instance - populated with the values from the reference. If given a string it will - try to convert it to a reference before constructing the builder. - """ - if not isinstance(reference, uri.URIReference): - reference = uri_reference(reference) - return cls( - scheme=reference.scheme, - userinfo=reference.userinfo, - host=reference.host, - port=reference.port, - path=reference.path, - query=reference.query, - fragment=reference.fragment, - ) - - def add_scheme(self, scheme): - """Add a scheme to our builder object. - - After normalizing, this will generate a new URIBuilder instance with - the specified scheme and all other attributes the same. - - .. code-block:: python - - >>> URIBuilder().add_scheme('HTTPS') - URIBuilder(scheme='https', userinfo=None, host=None, port=None, - path=None, query=None, fragment=None) - - """ - scheme = normalizers.normalize_scheme(scheme) - return URIBuilder( - scheme=scheme, - userinfo=self.userinfo, - host=self.host, - port=self.port, - path=self.path, - query=self.query, - fragment=self.fragment, - ) - - def add_credentials(self, username, password): - """Add credentials as the userinfo portion of the URI. - - .. code-block:: python - - >>> URIBuilder().add_credentials('root', 's3crete') - URIBuilder(scheme=None, userinfo='root:s3crete', host=None, - port=None, path=None, query=None, fragment=None) - - >>> URIBuilder().add_credentials('root', None) - URIBuilder(scheme=None, userinfo='root', host=None, - port=None, path=None, query=None, fragment=None) - """ - if username is None: - raise ValueError("Username cannot be None") - userinfo = normalizers.normalize_username(username) - - if password is not None: - userinfo = "{}:{}".format( - userinfo, - normalizers.normalize_password(password), - ) - - return URIBuilder( - scheme=self.scheme, - userinfo=userinfo, - host=self.host, - port=self.port, - path=self.path, - query=self.query, - fragment=self.fragment, - ) - - def add_host(self, host): - """Add hostname to the URI. - - .. code-block:: python - - >>> URIBuilder().add_host('google.com') - URIBuilder(scheme=None, userinfo=None, host='google.com', - port=None, path=None, query=None, fragment=None) - - """ - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=normalizers.normalize_host(host), - port=self.port, - path=self.path, - query=self.query, - fragment=self.fragment, - ) - - def add_port(self, port): - """Add port to the URI. - - .. code-block:: python - - >>> URIBuilder().add_port(80) - URIBuilder(scheme=None, userinfo=None, host=None, port='80', - path=None, query=None, fragment=None) - - >>> URIBuilder().add_port(443) - URIBuilder(scheme=None, userinfo=None, host=None, port='443', - path=None, query=None, fragment=None) - - """ - port_int = int(port) - if port_int < 0: - raise ValueError( - "ports are not allowed to be negative. You provided {}".format( - port_int, - ) - ) - if port_int > 65535: - raise ValueError( - "ports are not allowed to be larger than 65535. " - "You provided {}".format( - port_int, - ) - ) - - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=self.host, - port="{}".format(port_int), - path=self.path, - query=self.query, - fragment=self.fragment, - ) - - def add_path(self, path): - """Add a path to the URI. - - .. code-block:: python - - >>> URIBuilder().add_path('sigmavirus24/rfc3985') - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/sigmavirus24/rfc3986', query=None, fragment=None) - - >>> URIBuilder().add_path('/checkout.php') - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/checkout.php', query=None, fragment=None) - - """ - if not path.startswith("/"): - path = "/{}".format(path) - - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=self.host, - port=self.port, - path=normalizers.normalize_path(path), - query=self.query, - fragment=self.fragment, - ) - - def extend_path(self, path): - """Extend the existing path value with the provided value. - - .. versionadded:: 1.5.0 - - .. code-block:: python - - >>> URIBuilder(path="/users").extend_path("/sigmavirus24") - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/users/sigmavirus24', query=None, fragment=None) - - >>> URIBuilder(path="/users/").extend_path("/sigmavirus24") - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/users/sigmavirus24', query=None, fragment=None) - - >>> URIBuilder(path="/users/").extend_path("sigmavirus24") - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/users/sigmavirus24', query=None, fragment=None) - - >>> URIBuilder(path="/users").extend_path("sigmavirus24") - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path='/users/sigmavirus24', query=None, fragment=None) - - """ - existing_path = self.path or "" - path = "{}/{}".format(existing_path.rstrip("/"), path.lstrip("/")) - - return self.add_path(path) - - def add_query_from(self, query_items): - """Generate and add a query a dictionary or list of tuples. - - .. code-block:: python - - >>> URIBuilder().add_query_from({'a': 'b c'}) - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query='a=b+c', fragment=None) - - >>> URIBuilder().add_query_from([('a', 'b c')]) - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query='a=b+c', fragment=None) - - """ - query = normalizers.normalize_query(compat.urlencode(query_items)) - - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=self.host, - port=self.port, - path=self.path, - query=query, - fragment=self.fragment, - ) - - def extend_query_with(self, query_items): - """Extend the existing query string with the new query items. - - .. versionadded:: 1.5.0 - - .. code-block:: python - - >>> URIBuilder(query='a=b+c').extend_query_with({'a': 'b c'}) - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query='a=b+c&a=b+c', fragment=None) - - >>> URIBuilder(query='a=b+c').extend_query_with([('a', 'b c')]) - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query='a=b+c&a=b+c', fragment=None) - """ - original_query_items = compat.parse_qsl(self.query or "") - if not isinstance(query_items, list): - query_items = list(query_items.items()) - - return self.add_query_from(original_query_items + query_items) - - def add_query(self, query): - """Add a pre-formated query string to the URI. - - .. code-block:: python - - >>> URIBuilder().add_query('a=b&c=d') - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query='a=b&c=d', fragment=None) - - """ - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=self.host, - port=self.port, - path=self.path, - query=normalizers.normalize_query(query), - fragment=self.fragment, - ) - - def add_fragment(self, fragment): - """Add a fragment to the URI. - - .. code-block:: python - - >>> URIBuilder().add_fragment('section-2.6.1') - URIBuilder(scheme=None, userinfo=None, host=None, port=None, - path=None, query=None, fragment='section-2.6.1') - - """ - return URIBuilder( - scheme=self.scheme, - userinfo=self.userinfo, - host=self.host, - port=self.port, - path=self.path, - query=self.query, - fragment=normalizers.normalize_fragment(fragment), - ) - - def finalize(self): - """Create a URIReference from our builder. - - .. code-block:: python - - >>> URIBuilder().add_scheme('https').add_host('github.com' - ... ).add_path('sigmavirus24/rfc3986').finalize().unsplit() - 'https://github.com/sigmavirus24/rfc3986' - - >>> URIBuilder().add_scheme('https').add_host('github.com' - ... ).add_path('sigmavirus24/rfc3986').add_credentials( - ... 'sigmavirus24', 'not-re@l').finalize().unsplit() - 'https://sigmavirus24:not-re%40l@github.com/sigmavirus24/rfc3986' - - """ - return uri.URIReference( - self.scheme, - normalizers.normalize_authority( - (self.userinfo, self.host, self.port) - ), - self.path, - self.query, - self.fragment, - ) - - def geturl(self): - """Generate the URL from this builder. - - .. versionadded:: 1.5.0 - - This is an alternative to calling :meth:`finalize` and keeping the - :class:`rfc3986.uri.URIReference` around. - """ - return self.finalize().unsplit() diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/compat.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/compat.py deleted file mode 100644 index 83e5c78..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/compat.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Compatibility module for Python 2 and 3 support.""" -import sys - -try: - from urllib.parse import quote as urlquote -except ImportError: # Python 2.x - from urllib import quote as urlquote - -try: - from urllib.parse import parse_qsl -except ImportError: # Python 2.x - from urlparse import parse_qsl - -try: - from urllib.parse import urlencode -except ImportError: # Python 2.x - from urllib import urlencode - -__all__ = ( - "to_bytes", - "to_str", - "urlquote", - "urlencode", - "parse_qsl", -) - -PY3 = (3, 0) <= sys.version_info < (4, 0) -PY2 = (2, 6) <= sys.version_info < (2, 8) - - -if PY3: - unicode = str # Python 3.x - - -def to_str(b, encoding="utf-8"): - """Ensure that b is text in the specified encoding.""" - if hasattr(b, "decode") and not isinstance(b, unicode): - b = b.decode(encoding) - return b - - -def to_bytes(s, encoding="utf-8"): - """Ensure that s is converted to bytes from the encoding.""" - if hasattr(s, "encode") and not isinstance(s, bytes): - s = s.encode(encoding) - return s diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/exceptions.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/exceptions.py deleted file mode 100644 index b117bc9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/exceptions.py +++ /dev/null @@ -1,124 +0,0 @@ -# -*- coding: utf-8 -*- -"""Exceptions module for rfc3986.""" - -from . import compat - - -class RFC3986Exception(Exception): - """Base class for all rfc3986 exception classes.""" - - pass - - -class InvalidAuthority(RFC3986Exception): - """Exception when the authority string is invalid.""" - - def __init__(self, authority): - """Initialize the exception with the invalid authority.""" - super(InvalidAuthority, self).__init__( - u"The authority ({0}) is not valid.".format( - compat.to_str(authority) - ) - ) - - -class InvalidPort(RFC3986Exception): - """Exception when the port is invalid.""" - - def __init__(self, port): - """Initialize the exception with the invalid port.""" - super(InvalidPort, self).__init__( - 'The port ("{0}") is not valid.'.format(port) - ) - - -class ResolutionError(RFC3986Exception): - """Exception to indicate a failure to resolve a URI.""" - - def __init__(self, uri): - """Initialize the error with the failed URI.""" - super(ResolutionError, self).__init__( - "{0} is not an absolute URI.".format(uri.unsplit()) - ) - - -class ValidationError(RFC3986Exception): - """Exception raised during Validation of a URI.""" - - pass - - -class MissingComponentError(ValidationError): - """Exception raised when a required component is missing.""" - - def __init__(self, uri, *component_names): - """Initialize the error with the missing component name.""" - verb = "was" - if len(component_names) > 1: - verb = "were" - - self.uri = uri - self.components = sorted(component_names) - components = ", ".join(self.components) - super(MissingComponentError, self).__init__( - "{} {} required but missing".format(components, verb), - uri, - self.components, - ) - - -class UnpermittedComponentError(ValidationError): - """Exception raised when a component has an unpermitted value.""" - - def __init__(self, component_name, component_value, allowed_values): - """Initialize the error with the unpermitted component.""" - super(UnpermittedComponentError, self).__init__( - "{} was required to be one of {!r} but was {!r}".format( - component_name, - list(sorted(allowed_values)), - component_value, - ), - component_name, - component_value, - allowed_values, - ) - self.component_name = component_name - self.component_value = component_value - self.allowed_values = allowed_values - - -class PasswordForbidden(ValidationError): - """Exception raised when a URL has a password in the userinfo section.""" - - def __init__(self, uri): - """Initialize the error with the URI that failed validation.""" - unsplit = getattr(uri, "unsplit", lambda: uri) - super(PasswordForbidden, self).__init__( - '"{}" contained a password when validation forbade it'.format( - unsplit() - ) - ) - self.uri = uri - - -class InvalidComponentsError(ValidationError): - """Exception raised when one or more components are invalid.""" - - def __init__(self, uri, *component_names): - """Initialize the error with the invalid component name(s).""" - verb = "was" - if len(component_names) > 1: - verb = "were" - - self.uri = uri - self.components = sorted(component_names) - components = ", ".join(self.components) - super(InvalidComponentsError, self).__init__( - "{} {} found to be invalid".format(components, verb), - uri, - self.components, - ) - - -class MissingDependencyError(RFC3986Exception): - """Exception raised when an IRI is encoded without the 'idna' module.""" diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/iri.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/iri.py deleted file mode 100644 index 540aa7b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/iri.py +++ /dev/null @@ -1,162 +0,0 @@ -"""Module containing the implementation of the IRIReference class.""" -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Copyright (c) 2015 Ian Stapleton Cordasco -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from collections import namedtuple - -from . import compat -from . import exceptions -from . import misc -from . import normalizers -from . import uri - - -try: - import idna -except ImportError: # pragma: no cover - idna = None - - -class IRIReference( - namedtuple("IRIReference", misc.URI_COMPONENTS), uri.URIMixin -): - """Immutable object representing a parsed IRI Reference. - - Can be encoded into an URIReference object via the procedure - specified in RFC 3987 Section 3.1 - - .. note:: - The IRI submodule is a new interface and may possibly change in - the future. Check for changes to the interface when upgrading. - """ - - slots = () - - def __new__( - cls, scheme, authority, path, query, fragment, encoding="utf-8" - ): - """Create a new IRIReference.""" - ref = super(IRIReference, cls).__new__( - cls, - scheme or None, - authority or None, - path or None, - query, - fragment, - ) - ref.encoding = encoding - return ref - - def __eq__(self, other): - """Compare this reference to another.""" - other_ref = other - if isinstance(other, tuple): - other_ref = self.__class__(*other) - elif not isinstance(other, IRIReference): - try: - other_ref = self.__class__.from_string(other) - except TypeError: - raise TypeError( - "Unable to compare {0}() to {1}()".format( - type(self).__name__, type(other).__name__ - ) - ) - - # See http://tools.ietf.org/html/rfc3986#section-6.2 - return tuple(self) == tuple(other_ref) - - def _match_subauthority(self): - return misc.ISUBAUTHORITY_MATCHER.match(self.authority) - - @classmethod - def from_string(cls, iri_string, encoding="utf-8"): - """Parse a IRI reference from the given unicode IRI string. - - :param str iri_string: Unicode IRI to be parsed into a reference. - :param str encoding: The encoding of the string provided - :returns: :class:`IRIReference` or subclass thereof - """ - iri_string = compat.to_str(iri_string, encoding) - - split_iri = misc.IRI_MATCHER.match(iri_string).groupdict() - return cls( - split_iri["scheme"], - split_iri["authority"], - normalizers.encode_component(split_iri["path"], encoding), - normalizers.encode_component(split_iri["query"], encoding), - normalizers.encode_component(split_iri["fragment"], encoding), - encoding, - ) - - def encode(self, idna_encoder=None): # noqa: C901 - """Encode an IRIReference into a URIReference instance. - - If the ``idna`` module is installed or the ``rfc3986[idna]`` - extra is used then unicode characters in the IRI host - component will be encoded with IDNA2008. - - :param idna_encoder: - Function that encodes each part of the host component - If not given will raise an exception if the IRI - contains a host component. - :rtype: uri.URIReference - :returns: A URI reference - """ - authority = self.authority - if authority: - if idna_encoder is None: - if idna is None: # pragma: no cover - raise exceptions.MissingDependencyError( - "Could not import the 'idna' module " - "and the IRI hostname requires encoding" - ) - - def idna_encoder(name): - if any(ord(c) > 128 for c in name): - try: - return idna.encode( - name.lower(), strict=True, std3_rules=True - ) - except idna.IDNAError: - raise exceptions.InvalidAuthority(self.authority) - return name - - authority = "" - if self.host: - authority = ".".join( - [ - compat.to_str(idna_encoder(part)) - for part in self.host.split(".") - ] - ) - - if self.userinfo is not None: - authority = ( - normalizers.encode_component(self.userinfo, self.encoding) - + "@" - + authority - ) - - if self.port is not None: - authority += ":" + str(self.port) - - return uri.URIReference( - self.scheme, - authority, - path=self.path, - query=self.query, - fragment=self.fragment, - encoding=self.encoding, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/misc.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/misc.py deleted file mode 100644 index 338b187..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/misc.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Module containing compiled regular expressions and constants. - -This module contains important constants, patterns, and compiled regular -expressions for parsing and validating URIs and their components. -""" - -import re - -from . import abnf_regexp - -# These are enumerated for the named tuple used as a superclass of -# URIReference -URI_COMPONENTS = ["scheme", "authority", "path", "query", "fragment"] - -important_characters = { - "generic_delimiters": abnf_regexp.GENERIC_DELIMITERS, - "sub_delimiters": abnf_regexp.SUB_DELIMITERS, - # We need to escape the '*' in this case - "re_sub_delimiters": abnf_regexp.SUB_DELIMITERS_RE, - "unreserved_chars": abnf_regexp.UNRESERVED_CHARS, - # We need to escape the '-' in this case: - "re_unreserved": abnf_regexp.UNRESERVED_RE, -} - -# For details about delimiters and reserved characters, see: -# http://tools.ietf.org/html/rfc3986#section-2.2 -GENERIC_DELIMITERS = abnf_regexp.GENERIC_DELIMITERS_SET -SUB_DELIMITERS = abnf_regexp.SUB_DELIMITERS_SET -RESERVED_CHARS = abnf_regexp.RESERVED_CHARS_SET -# For details about unreserved characters, see: -# http://tools.ietf.org/html/rfc3986#section-2.3 -UNRESERVED_CHARS = abnf_regexp.UNRESERVED_CHARS_SET -NON_PCT_ENCODED = abnf_regexp.NON_PCT_ENCODED_SET - -URI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE) - -SUBAUTHORITY_MATCHER = re.compile( - ( - "^(?:(?P{0})@)?" # userinfo - "(?P{1})" # host - ":?(?P{2})?$" # port - ).format( - abnf_regexp.USERINFO_RE, abnf_regexp.HOST_PATTERN, abnf_regexp.PORT_RE - ) -) - - -HOST_MATCHER = re.compile("^" + abnf_regexp.HOST_RE + "$") -IPv4_MATCHER = re.compile("^" + abnf_regexp.IPv4_RE + "$") -IPv6_MATCHER = re.compile(r"^\[" + abnf_regexp.IPv6_ADDRZ_RFC4007_RE + r"\]$") - -# Used by host validator -IPv6_NO_RFC4007_MATCHER = re.compile( - r"^\[%s\]$" % (abnf_regexp.IPv6_ADDRZ_RE) -) - -# Matcher used to validate path components -PATH_MATCHER = re.compile(abnf_regexp.PATH_RE) - - -# ################################## -# Query and Fragment Matcher Section -# ################################## - -QUERY_MATCHER = re.compile(abnf_regexp.QUERY_RE) - -FRAGMENT_MATCHER = QUERY_MATCHER - -# Scheme validation, see: http://tools.ietf.org/html/rfc3986#section-3.1 -SCHEME_MATCHER = re.compile("^{0}$".format(abnf_regexp.SCHEME_RE)) - -RELATIVE_REF_MATCHER = re.compile( - r"^%s(\?%s)?(#%s)?$" - % ( - abnf_regexp.RELATIVE_PART_RE, - abnf_regexp.QUERY_RE, - abnf_regexp.FRAGMENT_RE, - ) -) - -# See http://tools.ietf.org/html/rfc3986#section-4.3 -ABSOLUTE_URI_MATCHER = re.compile( - r"^%s:%s(\?%s)?$" - % ( - abnf_regexp.COMPONENT_PATTERN_DICT["scheme"], - abnf_regexp.HIER_PART_RE, - abnf_regexp.QUERY_RE[1:-1], - ) -) - -# ############### -# IRIs / RFC 3987 -# ############### - -IRI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE, re.UNICODE) - -ISUBAUTHORITY_MATCHER = re.compile( - ( - u"^(?:(?P{0})@)?" # iuserinfo - u"(?P{1})" # ihost - u":?(?P{2})?$" # port - ).format( - abnf_regexp.IUSERINFO_RE, abnf_regexp.IHOST_RE, abnf_regexp.PORT_RE - ), - re.UNICODE, -) - - -# Path merger as defined in http://tools.ietf.org/html/rfc3986#section-5.2.3 -def merge_paths(base_uri, relative_path): - """Merge a base URI's path with a relative URI's path.""" - if base_uri.path is None and base_uri.authority is not None: - return "/" + relative_path - else: - path = base_uri.path or "" - index = path.rfind("/") - return path[:index] + "/" + relative_path - - -UseExisting = object() diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/normalizers.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/normalizers.py deleted file mode 100644 index 0d702b6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/normalizers.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module with functions to normalize components.""" -import re - -from . import compat -from . import misc - - -def normalize_scheme(scheme): - """Normalize the scheme component.""" - return scheme.lower() - - -def normalize_authority(authority): - """Normalize an authority tuple to a string.""" - userinfo, host, port = authority - result = "" - if userinfo: - result += normalize_percent_characters(userinfo) + "@" - if host: - result += normalize_host(host) - if port: - result += ":" + port - return result - - -def normalize_username(username): - """Normalize a username to make it safe to include in userinfo.""" - return compat.urlquote(username) - - -def normalize_password(password): - """Normalize a password to make safe for userinfo.""" - return compat.urlquote(password) - - -def normalize_host(host): - """Normalize a host string.""" - if misc.IPv6_MATCHER.match(host): - percent = host.find("%") - if percent != -1: - percent_25 = host.find("%25") - - # Replace RFC 4007 IPv6 Zone ID delimiter '%' with '%25' - # from RFC 6874. If the host is '[%25]' then we - # assume RFC 4007 and normalize to '[%2525]' - if ( - percent_25 == -1 - or percent < percent_25 - or (percent == percent_25 and percent_25 == len(host) - 4) - ): - host = host.replace("%", "%25", 1) - - # Don't normalize the casing of the Zone ID - return host[:percent].lower() + host[percent:] - - return host.lower() - - -def normalize_path(path): - """Normalize the path string.""" - if not path: - return path - - path = normalize_percent_characters(path) - return remove_dot_segments(path) - - -def normalize_query(query): - """Normalize the query string.""" - if not query: - return query - return normalize_percent_characters(query) - - -def normalize_fragment(fragment): - """Normalize the fragment string.""" - if not fragment: - return fragment - return normalize_percent_characters(fragment) - - -PERCENT_MATCHER = re.compile("%[A-Fa-f0-9]{2}") - - -def normalize_percent_characters(s): - """All percent characters should be upper-cased. - - For example, ``"%3afoo%DF%ab"`` should be turned into ``"%3Afoo%DF%AB"``. - """ - matches = set(PERCENT_MATCHER.findall(s)) - for m in matches: - if not m.isupper(): - s = s.replace(m, m.upper()) - return s - - -def remove_dot_segments(s): - """Remove dot segments from the string. - - See also Section 5.2.4 of :rfc:`3986`. - """ - # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code - segments = s.split("/") # Turn the path into a list of segments - output = [] # Initialize the variable to use to store output - - for segment in segments: - # '.' is the current directory, so ignore it, it is superfluous - if segment == ".": - continue - # Anything other than '..', should be appended to the output - elif segment != "..": - output.append(segment) - # In this case segment == '..', if we can, we should pop the last - # element - elif output: - output.pop() - - # If the path starts with '/' and the output is empty or the first string - # is non-empty - if s.startswith("/") and (not output or output[0]): - output.insert(0, "") - - # If the path starts with '/.' or '/..' ensure we add one more empty - # string to add a trailing '/' - if s.endswith(("/.", "/..")): - output.append("") - - return "/".join(output) - - -def encode_component(uri_component, encoding): - """Encode the specific component in the provided encoding.""" - if uri_component is None: - return uri_component - - # Try to see if the component we're encoding is already percent-encoded - # so we can skip all '%' characters but still encode all others. - percent_encodings = len( - PERCENT_MATCHER.findall(compat.to_str(uri_component, encoding)) - ) - - uri_bytes = compat.to_bytes(uri_component, encoding) - is_percent_encoded = percent_encodings == uri_bytes.count(b"%") - - encoded_uri = bytearray() - - for i in range(0, len(uri_bytes)): - # Will return a single character bytestring on both Python 2 & 3 - byte = uri_bytes[i : i + 1] - byte_ord = ord(byte) - if (is_percent_encoded and byte == b"%") or ( - byte_ord < 128 and byte.decode() in misc.NON_PCT_ENCODED - ): - encoded_uri.extend(byte) - continue - encoded_uri.extend("%{0:02x}".format(byte_ord).encode().upper()) - - return encoded_uri.decode(encoding) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/parseresult.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/parseresult.py deleted file mode 100644 index 8887e8f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/parseresult.py +++ /dev/null @@ -1,479 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015 Ian Stapleton Cordasco -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module containing the urlparse compatibility logic.""" -from collections import namedtuple - -from . import compat -from . import exceptions -from . import misc -from . import normalizers -from . import uri - -__all__ = ("ParseResult", "ParseResultBytes") - -PARSED_COMPONENTS = ( - "scheme", - "userinfo", - "host", - "port", - "path", - "query", - "fragment", -) - - -class ParseResultMixin(object): - def _generate_authority(self, attributes): - # I swear I did not align the comparisons below. That's just how they - # happened to align based on pep8 and attribute lengths. - userinfo, host, port = ( - attributes[p] for p in ("userinfo", "host", "port") - ) - if ( - self.userinfo != userinfo - or self.host != host - or self.port != port - ): - if port: - port = "{0}".format(port) - return normalizers.normalize_authority( - ( - compat.to_str(userinfo, self.encoding), - compat.to_str(host, self.encoding), - port, - ) - ) - if isinstance(self.authority, bytes): - return self.authority.decode("utf-8") - return self.authority - - def geturl(self): - """Shim to match the standard library method.""" - return self.unsplit() - - @property - def hostname(self): - """Shim to match the standard library.""" - return self.host - - @property - def netloc(self): - """Shim to match the standard library.""" - return self.authority - - @property - def params(self): - """Shim to match the standard library.""" - return self.query - - -class ParseResult( - namedtuple("ParseResult", PARSED_COMPONENTS), ParseResultMixin -): - """Implementation of urlparse compatibility class. - - This uses the URIReference logic to handle compatibility with the - urlparse.ParseResult class. - """ - - slots = () - - def __new__( - cls, - scheme, - userinfo, - host, - port, - path, - query, - fragment, - uri_ref, - encoding="utf-8", - ): - """Create a new ParseResult.""" - parse_result = super(ParseResult, cls).__new__( - cls, - scheme or None, - userinfo or None, - host, - port or None, - path or None, - query, - fragment, - ) - parse_result.encoding = encoding - parse_result.reference = uri_ref - return parse_result - - @classmethod - def from_parts( - cls, - scheme=None, - userinfo=None, - host=None, - port=None, - path=None, - query=None, - fragment=None, - encoding="utf-8", - ): - """Create a ParseResult instance from its parts.""" - authority = "" - if userinfo is not None: - authority += userinfo + "@" - if host is not None: - authority += host - if port is not None: - authority += ":{0}".format(port) - uri_ref = uri.URIReference( - scheme=scheme, - authority=authority, - path=path, - query=query, - fragment=fragment, - encoding=encoding, - ).normalize() - userinfo, host, port = authority_from(uri_ref, strict=True) - return cls( - scheme=uri_ref.scheme, - userinfo=userinfo, - host=host, - port=port, - path=uri_ref.path, - query=uri_ref.query, - fragment=uri_ref.fragment, - uri_ref=uri_ref, - encoding=encoding, - ) - - @classmethod - def from_string( - cls, uri_string, encoding="utf-8", strict=True, lazy_normalize=True - ): - """Parse a URI from the given unicode URI string. - - :param str uri_string: Unicode URI to be parsed into a reference. - :param str encoding: The encoding of the string provided - :param bool strict: Parse strictly according to :rfc:`3986` if True. - If False, parse similarly to the standard library's urlparse - function. - :returns: :class:`ParseResult` or subclass thereof - """ - reference = uri.URIReference.from_string(uri_string, encoding) - if not lazy_normalize: - reference = reference.normalize() - userinfo, host, port = authority_from(reference, strict) - - return cls( - scheme=reference.scheme, - userinfo=userinfo, - host=host, - port=port, - path=reference.path, - query=reference.query, - fragment=reference.fragment, - uri_ref=reference, - encoding=encoding, - ) - - @property - def authority(self): - """Return the normalized authority.""" - return self.reference.authority - - def copy_with( - self, - scheme=misc.UseExisting, - userinfo=misc.UseExisting, - host=misc.UseExisting, - port=misc.UseExisting, - path=misc.UseExisting, - query=misc.UseExisting, - fragment=misc.UseExisting, - ): - """Create a copy of this instance replacing with specified parts.""" - attributes = zip( - PARSED_COMPONENTS, - (scheme, userinfo, host, port, path, query, fragment), - ) - attrs_dict = {} - for name, value in attributes: - if value is misc.UseExisting: - value = getattr(self, name) - attrs_dict[name] = value - authority = self._generate_authority(attrs_dict) - ref = self.reference.copy_with( - scheme=attrs_dict["scheme"], - authority=authority, - path=attrs_dict["path"], - query=attrs_dict["query"], - fragment=attrs_dict["fragment"], - ) - return ParseResult(uri_ref=ref, encoding=self.encoding, **attrs_dict) - - def encode(self, encoding=None): - """Convert to an instance of ParseResultBytes.""" - encoding = encoding or self.encoding - attrs = dict( - zip( - PARSED_COMPONENTS, - ( - attr.encode(encoding) if hasattr(attr, "encode") else attr - for attr in self - ), - ) - ) - return ParseResultBytes( - uri_ref=self.reference, encoding=encoding, **attrs - ) - - def unsplit(self, use_idna=False): - """Create a URI string from the components. - - :returns: The parsed URI reconstituted as a string. - :rtype: str - """ - parse_result = self - if use_idna and self.host: - hostbytes = self.host.encode("idna") - host = hostbytes.decode(self.encoding) - parse_result = self.copy_with(host=host) - return parse_result.reference.unsplit() - - -class ParseResultBytes( - namedtuple("ParseResultBytes", PARSED_COMPONENTS), ParseResultMixin -): - """Compatibility shim for the urlparse.ParseResultBytes object.""" - - def __new__( - cls, - scheme, - userinfo, - host, - port, - path, - query, - fragment, - uri_ref, - encoding="utf-8", - lazy_normalize=True, - ): - """Create a new ParseResultBytes instance.""" - parse_result = super(ParseResultBytes, cls).__new__( - cls, - scheme or None, - userinfo or None, - host, - port or None, - path or None, - query or None, - fragment or None, - ) - parse_result.encoding = encoding - parse_result.reference = uri_ref - parse_result.lazy_normalize = lazy_normalize - return parse_result - - @classmethod - def from_parts( - cls, - scheme=None, - userinfo=None, - host=None, - port=None, - path=None, - query=None, - fragment=None, - encoding="utf-8", - lazy_normalize=True, - ): - """Create a ParseResult instance from its parts.""" - authority = "" - if userinfo is not None: - authority += userinfo + "@" - if host is not None: - authority += host - if port is not None: - authority += ":{0}".format(int(port)) - uri_ref = uri.URIReference( - scheme=scheme, - authority=authority, - path=path, - query=query, - fragment=fragment, - encoding=encoding, - ) - if not lazy_normalize: - uri_ref = uri_ref.normalize() - to_bytes = compat.to_bytes - userinfo, host, port = authority_from(uri_ref, strict=True) - return cls( - scheme=to_bytes(scheme, encoding), - userinfo=to_bytes(userinfo, encoding), - host=to_bytes(host, encoding), - port=port, - path=to_bytes(path, encoding), - query=to_bytes(query, encoding), - fragment=to_bytes(fragment, encoding), - uri_ref=uri_ref, - encoding=encoding, - lazy_normalize=lazy_normalize, - ) - - @classmethod - def from_string( - cls, uri_string, encoding="utf-8", strict=True, lazy_normalize=True - ): - """Parse a URI from the given unicode URI string. - - :param str uri_string: Unicode URI to be parsed into a reference. - :param str encoding: The encoding of the string provided - :param bool strict: Parse strictly according to :rfc:`3986` if True. - If False, parse similarly to the standard library's urlparse - function. - :returns: :class:`ParseResultBytes` or subclass thereof - """ - reference = uri.URIReference.from_string(uri_string, encoding) - if not lazy_normalize: - reference = reference.normalize() - userinfo, host, port = authority_from(reference, strict) - - to_bytes = compat.to_bytes - return cls( - scheme=to_bytes(reference.scheme, encoding), - userinfo=to_bytes(userinfo, encoding), - host=to_bytes(host, encoding), - port=port, - path=to_bytes(reference.path, encoding), - query=to_bytes(reference.query, encoding), - fragment=to_bytes(reference.fragment, encoding), - uri_ref=reference, - encoding=encoding, - lazy_normalize=lazy_normalize, - ) - - @property - def authority(self): - """Return the normalized authority.""" - return self.reference.authority.encode(self.encoding) - - def copy_with( - self, - scheme=misc.UseExisting, - userinfo=misc.UseExisting, - host=misc.UseExisting, - port=misc.UseExisting, - path=misc.UseExisting, - query=misc.UseExisting, - fragment=misc.UseExisting, - lazy_normalize=True, - ): - """Create a copy of this instance replacing with specified parts.""" - attributes = zip( - PARSED_COMPONENTS, - (scheme, userinfo, host, port, path, query, fragment), - ) - attrs_dict = {} - for name, value in attributes: - if value is misc.UseExisting: - value = getattr(self, name) - if not isinstance(value, bytes) and hasattr(value, "encode"): - value = value.encode(self.encoding) - attrs_dict[name] = value - authority = self._generate_authority(attrs_dict) - to_str = compat.to_str - ref = self.reference.copy_with( - scheme=to_str(attrs_dict["scheme"], self.encoding), - authority=to_str(authority, self.encoding), - path=to_str(attrs_dict["path"], self.encoding), - query=to_str(attrs_dict["query"], self.encoding), - fragment=to_str(attrs_dict["fragment"], self.encoding), - ) - if not lazy_normalize: - ref = ref.normalize() - return ParseResultBytes( - uri_ref=ref, - encoding=self.encoding, - lazy_normalize=lazy_normalize, - **attrs_dict - ) - - def unsplit(self, use_idna=False): - """Create a URI bytes object from the components. - - :returns: The parsed URI reconstituted as a string. - :rtype: bytes - """ - parse_result = self - if use_idna and self.host: - # self.host is bytes, to encode to idna, we need to decode it - # first - host = self.host.decode(self.encoding) - hostbytes = host.encode("idna") - parse_result = self.copy_with(host=hostbytes) - if self.lazy_normalize: - parse_result = parse_result.copy_with(lazy_normalize=False) - uri = parse_result.reference.unsplit() - return uri.encode(self.encoding) - - -def split_authority(authority): - # Initialize our expected return values - userinfo = host = port = None - # Initialize an extra var we may need to use - extra_host = None - # Set-up rest in case there is no userinfo portion - rest = authority - - if "@" in authority: - userinfo, rest = authority.rsplit("@", 1) - - # Handle IPv6 host addresses - if rest.startswith("["): - host, rest = rest.split("]", 1) - host += "]" - - if ":" in rest: - extra_host, port = rest.split(":", 1) - elif not host and rest: - host = rest - - if extra_host and not host: - host = extra_host - - return userinfo, host, port - - -def authority_from(reference, strict): - try: - subauthority = reference.authority_info() - except exceptions.InvalidAuthority: - if strict: - raise - userinfo, host, port = split_authority(reference.authority) - else: - # Thanks to Richard Barrell for this idea: - # https://twitter.com/0x2ba22e11/status/617338811975139328 - userinfo, host, port = ( - subauthority.get(p) for p in ("userinfo", "host", "port") - ) - - if port: - try: - port = int(port) - except ValueError: - raise exceptions.InvalidPort(port) - return userinfo, host, port diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/uri.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/uri.py deleted file mode 100644 index 75c617d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/uri.py +++ /dev/null @@ -1,161 +0,0 @@ -"""Module containing the implementation of the URIReference class.""" -# -*- coding: utf-8 -*- -# Copyright (c) 2014 Rackspace -# Copyright (c) 2015 Ian Stapleton Cordasco -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from collections import namedtuple - -from . import compat -from . import misc -from . import normalizers -from ._mixin import URIMixin - - -class URIReference(namedtuple("URIReference", misc.URI_COMPONENTS), URIMixin): - """Immutable object representing a parsed URI Reference. - - .. note:: - - This class is not intended to be directly instantiated by the user. - - This object exposes attributes for the following components of a - URI: - - - scheme - - authority - - path - - query - - fragment - - .. attribute:: scheme - - The scheme that was parsed for the URI Reference. For example, - ``http``, ``https``, ``smtp``, ``imap``, etc. - - .. attribute:: authority - - Component of the URI that contains the user information, host, - and port sub-components. For example, - ``google.com``, ``127.0.0.1:5000``, ``username@[::1]``, - ``username:password@example.com:443``, etc. - - .. attribute:: path - - The path that was parsed for the given URI Reference. For example, - ``/``, ``/index.php``, etc. - - .. attribute:: query - - The query component for a given URI Reference. For example, ``a=b``, - ``a=b%20c``, ``a=b+c``, ``a=b,c=d,e=%20f``, etc. - - .. attribute:: fragment - - The fragment component of a URI. For example, ``section-3.1``. - - This class also provides extra attributes for easier access to information - like the subcomponents of the authority component. - - .. attribute:: userinfo - - The user information parsed from the authority. - - .. attribute:: host - - The hostname, IPv4, or IPv6 address parsed from the authority. - - .. attribute:: port - - The port parsed from the authority. - """ - - slots = () - - def __new__( - cls, scheme, authority, path, query, fragment, encoding="utf-8" - ): - """Create a new URIReference.""" - ref = super(URIReference, cls).__new__( - cls, - scheme or None, - authority or None, - path or None, - query, - fragment, - ) - ref.encoding = encoding - return ref - - __hash__ = tuple.__hash__ - - def __eq__(self, other): - """Compare this reference to another.""" - other_ref = other - if isinstance(other, tuple): - other_ref = URIReference(*other) - elif not isinstance(other, URIReference): - try: - other_ref = URIReference.from_string(other) - except TypeError: - raise TypeError( - "Unable to compare URIReference() to {0}()".format( - type(other).__name__ - ) - ) - - # See http://tools.ietf.org/html/rfc3986#section-6.2 - naive_equality = tuple(self) == tuple(other_ref) - return naive_equality or self.normalized_equality(other_ref) - - def normalize(self): - """Normalize this reference as described in Section 6.2.2. - - This is not an in-place normalization. Instead this creates a new - URIReference. - - :returns: A new reference object with normalized components. - :rtype: URIReference - """ - # See http://tools.ietf.org/html/rfc3986#section-6.2.2 for logic in - # this method. - return URIReference( - normalizers.normalize_scheme(self.scheme or ""), - normalizers.normalize_authority( - (self.userinfo, self.host, self.port) - ), - normalizers.normalize_path(self.path or ""), - normalizers.normalize_query(self.query), - normalizers.normalize_fragment(self.fragment), - self.encoding, - ) - - @classmethod - def from_string(cls, uri_string, encoding="utf-8"): - """Parse a URI reference from the given unicode URI string. - - :param str uri_string: Unicode URI to be parsed into a reference. - :param str encoding: The encoding of the string provided - :returns: :class:`URIReference` or subclass thereof - """ - uri_string = compat.to_str(uri_string, encoding) - - split_uri = misc.URI_MATCHER.match(uri_string).groupdict() - return cls( - split_uri["scheme"], - split_uri["authority"], - normalizers.encode_component(split_uri["path"], encoding), - normalizers.encode_component(split_uri["query"], encoding), - normalizers.encode_component(split_uri["fragment"], encoding), - encoding, - ) diff --git a/extensions/.local/lib/python3.11/site-packages/rfc3986/validators.py b/extensions/.local/lib/python3.11/site-packages/rfc3986/validators.py deleted file mode 100644 index f375248..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rfc3986/validators.py +++ /dev/null @@ -1,447 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017 Ian Stapleton Cordasco -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module containing the validation logic for rfc3986.""" -from . import exceptions -from . import misc -from . import normalizers - - -class Validator(object): - """Object used to configure validation of all objects in rfc3986. - - .. versionadded:: 1.0 - - Example usage:: - - >>> from rfc3986 import api, validators - >>> uri = api.uri_reference('https://github.com/') - >>> validator = validators.Validator().require_presence_of( - ... 'scheme', 'host', 'path', - ... ).allow_schemes( - ... 'http', 'https', - ... ).allow_hosts( - ... '127.0.0.1', 'github.com', - ... ) - >>> validator.validate(uri) - >>> invalid_uri = rfc3986.uri_reference('imap://mail.google.com') - >>> validator.validate(invalid_uri) - Traceback (most recent call last): - ... - rfc3986.exceptions.MissingComponentError: ('path was required but - missing', URIReference(scheme=u'imap', authority=u'mail.google.com', - path=None, query=None, fragment=None), ['path']) - - """ - - COMPONENT_NAMES = frozenset( - ["scheme", "userinfo", "host", "port", "path", "query", "fragment"] - ) - - def __init__(self): - """Initialize our default validations.""" - self.allowed_schemes = set() - self.allowed_hosts = set() - self.allowed_ports = set() - self.allow_password = True - self.required_components = { - "scheme": False, - "userinfo": False, - "host": False, - "port": False, - "path": False, - "query": False, - "fragment": False, - } - self.validated_components = self.required_components.copy() - - def allow_schemes(self, *schemes): - """Require the scheme to be one of the provided schemes. - - .. versionadded:: 1.0 - - :param schemes: - Schemes, without ``://`` that are allowed. - :returns: - The validator instance. - :rtype: - Validator - """ - for scheme in schemes: - self.allowed_schemes.add(normalizers.normalize_scheme(scheme)) - return self - - def allow_hosts(self, *hosts): - """Require the host to be one of the provided hosts. - - .. versionadded:: 1.0 - - :param hosts: - Hosts that are allowed. - :returns: - The validator instance. - :rtype: - Validator - """ - for host in hosts: - self.allowed_hosts.add(normalizers.normalize_host(host)) - return self - - def allow_ports(self, *ports): - """Require the port to be one of the provided ports. - - .. versionadded:: 1.0 - - :param ports: - Ports that are allowed. - :returns: - The validator instance. - :rtype: - Validator - """ - for port in ports: - port_int = int(port, base=10) - if 0 <= port_int <= 65535: - self.allowed_ports.add(port) - return self - - def allow_use_of_password(self): - """Allow passwords to be present in the URI. - - .. versionadded:: 1.0 - - :returns: - The validator instance. - :rtype: - Validator - """ - self.allow_password = True - return self - - def forbid_use_of_password(self): - """Prevent passwords from being included in the URI. - - .. versionadded:: 1.0 - - :returns: - The validator instance. - :rtype: - Validator - """ - self.allow_password = False - return self - - def check_validity_of(self, *components): - """Check the validity of the components provided. - - This can be specified repeatedly. - - .. versionadded:: 1.1 - - :param components: - Names of components from :attr:`Validator.COMPONENT_NAMES`. - :returns: - The validator instance. - :rtype: - Validator - """ - components = [c.lower() for c in components] - for component in components: - if component not in self.COMPONENT_NAMES: - raise ValueError( - '"{}" is not a valid component'.format(component) - ) - self.validated_components.update( - {component: True for component in components} - ) - return self - - def require_presence_of(self, *components): - """Require the components provided. - - This can be specified repeatedly. - - .. versionadded:: 1.0 - - :param components: - Names of components from :attr:`Validator.COMPONENT_NAMES`. - :returns: - The validator instance. - :rtype: - Validator - """ - components = [c.lower() for c in components] - for component in components: - if component not in self.COMPONENT_NAMES: - raise ValueError( - '"{}" is not a valid component'.format(component) - ) - self.required_components.update( - {component: True for component in components} - ) - return self - - def validate(self, uri): - """Check a URI for conditions specified on this validator. - - .. versionadded:: 1.0 - - :param uri: - Parsed URI to validate. - :type uri: - rfc3986.uri.URIReference - :raises MissingComponentError: - When a required component is missing. - :raises UnpermittedComponentError: - When a component is not one of those allowed. - :raises PasswordForbidden: - When a password is present in the userinfo component but is - not permitted by configuration. - :raises InvalidComponentsError: - When a component was found to be invalid. - """ - if not self.allow_password: - check_password(uri) - - required_components = [ - component - for component, required in self.required_components.items() - if required - ] - validated_components = [ - component - for component, required in self.validated_components.items() - if required - ] - if required_components: - ensure_required_components_exist(uri, required_components) - if validated_components: - ensure_components_are_valid(uri, validated_components) - - ensure_one_of(self.allowed_schemes, uri, "scheme") - ensure_one_of(self.allowed_hosts, uri, "host") - ensure_one_of(self.allowed_ports, uri, "port") - - -def check_password(uri): - """Assert that there is no password present in the uri.""" - userinfo = uri.userinfo - if not userinfo: - return - credentials = userinfo.split(":", 1) - if len(credentials) <= 1: - return - raise exceptions.PasswordForbidden(uri) - - -def ensure_one_of(allowed_values, uri, attribute): - """Assert that the uri's attribute is one of the allowed values.""" - value = getattr(uri, attribute) - if value is not None and allowed_values and value not in allowed_values: - raise exceptions.UnpermittedComponentError( - attribute, - value, - allowed_values, - ) - - -def ensure_required_components_exist(uri, required_components): - """Assert that all required components are present in the URI.""" - missing_components = sorted( - [ - component - for component in required_components - if getattr(uri, component) is None - ] - ) - if missing_components: - raise exceptions.MissingComponentError(uri, *missing_components) - - -def is_valid(value, matcher, require): - """Determine if a value is valid based on the provided matcher. - - :param str value: - Value to validate. - :param matcher: - Compiled regular expression to use to validate the value. - :param require: - Whether or not the value is required. - """ - if require: - return value is not None and matcher.match(value) - - # require is False and value is not None - return value is None or matcher.match(value) - - -def authority_is_valid(authority, host=None, require=False): - """Determine if the authority string is valid. - - :param str authority: - The authority to validate. - :param str host: - (optional) The host portion of the authority to validate. - :param bool require: - (optional) Specify if authority must not be None. - :returns: - ``True`` if valid, ``False`` otherwise - :rtype: - bool - """ - validated = is_valid(authority, misc.SUBAUTHORITY_MATCHER, require) - if validated and host is not None: - return host_is_valid(host, require) - return validated - - -def host_is_valid(host, require=False): - """Determine if the host string is valid. - - :param str host: - The host to validate. - :param bool require: - (optional) Specify if host must not be None. - :returns: - ``True`` if valid, ``False`` otherwise - :rtype: - bool - """ - validated = is_valid(host, misc.HOST_MATCHER, require) - if validated and host is not None and misc.IPv4_MATCHER.match(host): - return valid_ipv4_host_address(host) - elif validated and host is not None and misc.IPv6_MATCHER.match(host): - return misc.IPv6_NO_RFC4007_MATCHER.match(host) is not None - return validated - - -def scheme_is_valid(scheme, require=False): - """Determine if the scheme is valid. - - :param str scheme: - The scheme string to validate. - :param bool require: - (optional) Set to ``True`` to require the presence of a scheme. - :returns: - ``True`` if the scheme is valid. ``False`` otherwise. - :rtype: - bool - """ - return is_valid(scheme, misc.SCHEME_MATCHER, require) - - -def path_is_valid(path, require=False): - """Determine if the path component is valid. - - :param str path: - The path string to validate. - :param bool require: - (optional) Set to ``True`` to require the presence of a path. - :returns: - ``True`` if the path is valid. ``False`` otherwise. - :rtype: - bool - """ - return is_valid(path, misc.PATH_MATCHER, require) - - -def query_is_valid(query, require=False): - """Determine if the query component is valid. - - :param str query: - The query string to validate. - :param bool require: - (optional) Set to ``True`` to require the presence of a query. - :returns: - ``True`` if the query is valid. ``False`` otherwise. - :rtype: - bool - """ - return is_valid(query, misc.QUERY_MATCHER, require) - - -def fragment_is_valid(fragment, require=False): - """Determine if the fragment component is valid. - - :param str fragment: - The fragment string to validate. - :param bool require: - (optional) Set to ``True`` to require the presence of a fragment. - :returns: - ``True`` if the fragment is valid. ``False`` otherwise. - :rtype: - bool - """ - return is_valid(fragment, misc.FRAGMENT_MATCHER, require) - - -def valid_ipv4_host_address(host): - """Determine if the given host is a valid IPv4 address.""" - # If the host exists, and it might be IPv4, check each byte in the - # address. - return all([0 <= int(byte, base=10) <= 255 for byte in host.split(".")]) - - -_COMPONENT_VALIDATORS = { - "scheme": scheme_is_valid, - "path": path_is_valid, - "query": query_is_valid, - "fragment": fragment_is_valid, -} - -_SUBAUTHORITY_VALIDATORS = set(["userinfo", "host", "port"]) - - -def subauthority_component_is_valid(uri, component): - """Determine if the userinfo, host, and port are valid.""" - try: - subauthority_dict = uri.authority_info() - except exceptions.InvalidAuthority: - return False - - # If we can parse the authority into sub-components and we're not - # validating the port, we can assume it's valid. - if component == "host": - return host_is_valid(subauthority_dict["host"]) - elif component != "port": - return True - - try: - port = int(subauthority_dict["port"]) - except TypeError: - # If the port wasn't provided it'll be None and int(None) raises a - # TypeError - return True - - return 0 <= port <= 65535 - - -def ensure_components_are_valid(uri, validated_components): - """Assert that all components are valid in the URI.""" - invalid_components = set([]) - for component in validated_components: - if component in _SUBAUTHORITY_VALIDATORS: - if not subauthority_component_is_valid(uri, component): - invalid_components.add(component) - # Python's peephole optimizer means that while this continue *is* - # actually executed, coverage.py cannot detect that. See also, - # https://bitbucket.org/ned/coveragepy/issues/198/continue-marked-as-not-covered - continue # nocov: Python 2.7, 3.3, 3.4 - - validator = _COMPONENT_VALIDATORS[component] - if not validator(getattr(uri, component)): - invalid_components.add(component) - - if invalid_components: - raise exceptions.InvalidComponentsError(uri, *invalid_components) diff --git a/extensions/.local/lib/python3.11/site-packages/rpds/__init__.py b/extensions/.local/lib/python3.11/site-packages/rpds/__init__.py deleted file mode 100644 index 257da6a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .rpds import * - -__doc__ = rpds.__doc__ -if hasattr(rpds, "__all__"): - __all__ = rpds.__all__ \ No newline at end of file diff --git a/extensions/.local/lib/python3.11/site-packages/rpds/__init__.pyi b/extensions/.local/lib/python3.11/site-packages/rpds/__init__.pyi deleted file mode 100644 index 5af0e32..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds/__init__.pyi +++ /dev/null @@ -1,77 +0,0 @@ -from typing import ( - ItemsView, - Iterable, - Iterator, - KeysView, - Mapping, - TypeVar, - ValuesView, -) - -_T = TypeVar("_T") -_KT_co = TypeVar("_KT_co", covariant=True) -_VT_co = TypeVar("_VT_co", covariant=True) -_KU_co = TypeVar("_KU_co", covariant=True) -_VU_co = TypeVar("_VU_co", covariant=True) - -class HashTrieMap(Mapping[_KT_co, _VT_co]): - def __init__( - self, - value: Mapping[_KT_co, _VT_co] | Iterable[tuple[_KT_co, _VT_co]] = {}, - **kwds: Mapping[_KT_co, _VT_co], - ): ... - def __getitem__(self, key: _KT_co) -> _VT_co: ... - def __iter__(self) -> Iterator[_KT_co]: ... - def __len__(self) -> int: ... - def discard(self, key: _KT_co) -> HashTrieMap[_KT_co, _VT_co]: ... - def items(self) -> ItemsView[_KT_co, _VT_co]: ... - def keys(self) -> KeysView[_KT_co]: ... - def values(self) -> ValuesView[_VT_co]: ... - def remove(self, key: _KT_co) -> HashTrieMap[_KT_co, _VT_co]: ... - def insert( - self, - key: _KT_co, - val: _VT_co, - ) -> HashTrieMap[_KT_co, _VT_co]: ... - def update( - self, - *args: Mapping[_KU_co, _VU_co] | Iterable[tuple[_KU_co, _VU_co]], - ) -> HashTrieMap[_KT_co | _KU_co, _VT_co | _VU_co]: ... - @classmethod - def convert( - cls, - value: Mapping[_KT_co, _VT_co] | Iterable[tuple[_KT_co, _VT_co]], - ) -> HashTrieMap[_KT_co, _VT_co]: ... - @classmethod - def fromkeys( - cls, - keys: Iterable[_KT_co], - value: _VT_co = None, - ) -> HashTrieMap[_KT_co, _VT_co]: ... - -class HashTrieSet(frozenset[_T]): - def __init__(self, value: Iterable[_T] = ()): ... - def __iter__(self) -> Iterator[_T]: ... - def __len__(self) -> int: ... - def discard(self, value: _T) -> HashTrieSet[_T]: ... - def remove(self, value: _T) -> HashTrieSet[_T]: ... - def insert(self, value: _T) -> HashTrieSet[_T]: ... - def update(self, *args: Iterable[_T]) -> HashTrieSet[_T]: ... - -class List(Iterable[_T]): - def __init__(self, value: Iterable[_T] = (), *more: _T): ... - def __iter__(self) -> Iterator[_T]: ... - def __len__(self) -> int: ... - def push_front(self, value: _T) -> List[_T]: ... - def drop_first(self) -> List[_T]: ... - -class Queue(Iterable[_T]): - def __init__(self, value: Iterable[_T] = (), *more: _T): ... - def __iter__(self) -> Iterator[_T]: ... - def __len__(self) -> int: ... - def enqueue(self, value: _T) -> Queue[_T]: ... - def dequeue(self, value: _T) -> Queue[_T]: ... - @property - def is_empty(self) -> _T: ... - @property - def peek(self) -> _T: ... diff --git a/extensions/.local/lib/python3.11/site-packages/rpds/py.typed b/extensions/.local/lib/python3.11/site-packages/rpds/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/METADATA deleted file mode 100644 index e5e37d8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/METADATA +++ /dev/null @@ -1,99 +0,0 @@ -Metadata-Version: 2.4 -Name: rpds-py -Version: 0.24.0 -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Rust -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -License-File: LICENSE -Summary: Python bindings to Rust's persistent data structures (rpds) -Keywords: data structures,rust,persistent -Author-email: Julian Berman -License: MIT -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst; charset=UTF-8 -Project-URL: Documentation, https://rpds.readthedocs.io/ -Project-URL: Homepage, https://github.com/crate-py/rpds -Project-URL: Issues, https://github.com/crate-py/rpds/issues/ -Project-URL: Funding, https://github.com/sponsors/Julian -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-rpds-py?utm_source=pypi-rpds-py&utm_medium=referral&utm_campaign=pypi-link -Project-URL: Source, https://github.com/crate-py/rpds -Project-URL: Upstream, https://github.com/orium/rpds - -=========== -``rpds.py`` -=========== - -|PyPI| |Pythons| |CI| - -.. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg - :alt: PyPI version - :target: https://pypi.org/project/rpds-py/ - -.. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg - :alt: Supported Python versions - :target: https://pypi.org/project/rpds-py/ - -.. |CI| image:: https://github.com/crate-py/rpds/workflows/CI/badge.svg - :alt: Build status - :target: https://github.com/crate-py/rpds/actions?query=workflow%3ACI - -.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat - :alt: ReadTheDocs status - :target: https://referencing.readthedocs.io/en/stable/ - - -Python bindings to the `Rust rpds crate `_ for persistent data structures. - -What's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library `_). -If you see something missing (which is very likely), a PR is definitely welcome to add it. - -Installation ------------- - -The distribution on PyPI is named ``rpds.py`` (equivalently ``rpds-py``), and thus can be installed via e.g.: - -.. code:: sh - - $ pip install rpds-py - -Note that if you install ``rpds-py`` from source, you will need a Rust toolchain installed, as it is a build-time dependency. -An example of how to do so in a ``Dockerfile`` can be found `here `_. - -If you believe you are on a common platform which should have wheels built (i.e. and not need to compile from source), feel free to file an issue or pull request modifying the GitHub action used here to build wheels via ``maturin``. - -Usage ------ - -Methods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\ 's conventions, though probably a full drop-in ``pyrsistent``\ -compatible wrapper module is a good addition at some point). - -.. code:: python - - >>> from rpds import HashTrieMap, HashTrieSet, List - - >>> m = HashTrieMap({"foo": "bar", "baz": "quux"}) - >>> m.insert("spam", 37) == HashTrieMap({"foo": "bar", "baz": "quux", "spam": 37}) - True - >>> m.remove("foo") == HashTrieMap({"baz": "quux"}) - True - - >>> s = HashTrieSet({"foo", "bar", "baz", "quux"}) - >>> s.insert("spam") == HashTrieSet({"foo", "bar", "baz", "quux", "spam"}) - True - >>> s.remove("foo") == HashTrieSet({"bar", "baz", "quux"}) - True - - >>> L = List([1, 3, 5]) - >>> L.push_front(-1) == List([-1, 1, 3, 5]) - True - >>> L.rest == List([3, 5]) - True - diff --git a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/RECORD deleted file mode 100644 index a16d543..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -rpds_py-0.24.0.dist-info/METADATA,sha256=rtzK5QPON_cGqODWo0mr6JlQmOYBoXu5oPaBmyE83v4,4200 -rpds_py-0.24.0.dist-info/WHEEL,sha256=tAGdc4C2KTz7B2CZ8Jf3DcKSAviAbCg44UH9ma2gYww,96 -rpds_py-0.24.0.dist-info/licenses/LICENSE,sha256=i8tyyC6ornSAIpPEHZOtfVFDQAGwrkWmA6WvD1B67go,1076 -rpds/__init__.py,sha256=w3MgXW7lpTCICw0KXbw20QX573_kbsEnWIeMsCAugvM,99 -rpds/__init__.pyi,sha256=hHdetXV1qq5MjhEk3eTZhLYIqR-b6l2-cbnDt8U78i8,2647 -rpds/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -rpds/rpds.cp311-win_amd64.pyd,sha256=Ym73ZKuKHtXQCaoXLmhcT-affFY-2nIfNOEW0S9-LD0,650240 -rpds_py-0.24.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/WHEEL deleted file mode 100644 index 38ca2d9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.8.3) -Root-Is-Purelib: false -Tag: cp311-cp311-win_amd64 diff --git a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/licenses/LICENSE b/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/licenses/LICENSE deleted file mode 100644 index 119a1f2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/rpds_py-0.24.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2023 Julian Berman - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/LICENSE deleted file mode 100644 index e06d208..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/METADATA deleted file mode 100644 index 5974f5f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/METADATA +++ /dev/null @@ -1,124 +0,0 @@ -Metadata-Version: 2.1 -Name: segments -Version: 2.3.0 -Summary: Segmentation with orthography profiles -Home-page: https://github.com/cldf/segments -Author: Steven Moran and Robert Forkel -Author-email: dlce.rdm@eva.mpg.de -License: Apache 2.0 -Project-URL: Bug Tracker, https://github.com/cldf/segments/issues -Keywords: linguistics,tokenizer -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Science/Research -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: License :: OSI Approved :: Apache Software License -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: regex -Requires-Dist: csvw>=1.5.6 -Provides-Extra: dev -Requires-Dist: flake8; extra == "dev" -Requires-Dist: wheel; extra == "dev" -Requires-Dist: build; extra == "dev" -Requires-Dist: twine; extra == "dev" -Provides-Extra: test -Requires-Dist: pytest>=5; extra == "test" -Requires-Dist: pytest-mock; extra == "test" -Requires-Dist: pytest-cov; extra == "test" - -segments -======== - -[![Build Status](https://github.com/cldf/segments/workflows/tests/badge.svg)](https://github.com/cldf/segments/actions?query=workflow%3Atests) -[![PyPI](https://img.shields.io/pypi/v/segments.svg)](https://pypi.org/project/segments) - - -[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1051157.svg)](https://doi.org/10.5281/zenodo.1051157) - -The segments package provides Unicode Standard tokenization routines and orthography segmentation, -implementing the linear algorithm described in the orthography profile specification from -*The Unicode Cookbook* (Moran and Cysouw 2018 [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1296780.svg)](https://doi.org/10.5281/zenodo.1296780)). - - -Command line usage ------------------- - -Create a text file: -``` -$ echo "aäaaöaaüaa" > text.txt -``` - -Now look at the profile: -``` -$ cat text.txt | segments profile -Grapheme frequency mapping -a 7 a -ä 1 ä -ü 1 ü -ö 1 ö -``` - -Write the profile to a file: -``` -$ cat text.txt | segments profile > profile.prf -``` - -Edit the profile: - -``` -$ more profile.prf -Grapheme frequency mapping -aa 0 x -a 7 a -ä 1 ä -ü 1 ü -ö 1 ö -``` - -Now tokenize the text without profile: -``` -$ cat text.txt | segments tokenize -a ä a a ö a a ü a a -``` - -And with profile: -``` -$ cat text.txt | segments --profile=profile.prf tokenize -a ä aa ö aa ü aa - -$ cat text.txt | segments --mapping=mapping --profile=profile.prf tokenize -a ä x ö x ü x -``` - - -API ---- - -```python ->>> from segments import Profile, Tokenizer ->>> t = Tokenizer() ->>> t('abcd') -'a b c d' ->>> prf = Profile({'Grapheme': 'ab', 'mapping': 'x'}, {'Grapheme': 'cd', 'mapping': 'y'}) ->>> print(prf) -Grapheme mapping -ab x -cd y ->>> t = Tokenizer(profile=prf) ->>> t('abcd') -'ab cd' ->>> t('abcd', column='mapping') -'x y' -``` diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/RECORD deleted file mode 100644 index 8542066..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/RECORD +++ /dev/null @@ -1,13 +0,0 @@ -segments/__init__.py,sha256=Oe5ySNg2nR7TI2fq3GLygH_ZiITIreIFKTICkm6QZ8E,239 -segments/__main__.py,sha256=sy9UjYJ1bB9gjET_EMkkNDSalA4zbb23Qh8tMl3_Uv4,2623 -segments/errors.py,sha256=TpVcNUCx1YIZqZ1Urc-30oRptzOqD98gA4tpXFtQyCA,434 -segments/profile.py,sha256=dOraG_axfMgzuyA_V_nxdeTvGfAl9TdvC2KTh9emg_Y,5554 -segments/tokenizer.py,sha256=yyreV3YBt_gFwO8IP8oHzIR_El46wEXpscXw574o00w,12920 -segments/tree.py,sha256=AeTp31M7XB6youejSPNihTitzBjxkbnv9AzaK99Q5hM,2077 -segments/util.py,sha256=b7W64hyKe0CeefDfFu8zXCDJMkyY7zkdvMtvMuS66l8,187 -segments-2.3.0.dist-info/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325 -segments-2.3.0.dist-info/METADATA,sha256=qtnnRFmMljakKscbHve5Uk0rvlvvQuZ_DqNvAa_hLmI,3467 -segments-2.3.0.dist-info/WHEEL,sha256=TJ49d73sNs10F0aze1W_bTW2P_X7-F4YXOlBqoqA-jY,109 -segments-2.3.0.dist-info/entry_points.txt,sha256=Es_A2rNdxpgiq7SEXfjlrbm2nvmcRywVwrJEp4cY1gc,52 -segments-2.3.0.dist-info/top_level.txt,sha256=6c8xKq6vt3NBzy6MSfFICf-VMJL3FMsIX3g9bft7Bm0,9 -segments-2.3.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/WHEEL deleted file mode 100644 index 17c0299..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.2.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/entry_points.txt deleted file mode 100644 index ea34346..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -segments = segments.__main__:main diff --git a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/top_level.txt deleted file mode 100644 index cb27fb8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments-2.3.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -segments diff --git a/extensions/.local/lib/python3.11/site-packages/segments/__init__.py b/extensions/.local/lib/python3.11/site-packages/segments/__init__.py deleted file mode 100644 index 43f06a9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from segments.tokenizer import Tokenizer, Rules # noqa: F401 -from segments.profile import Profile # noqa: F401 -from segments.util import REPLACEMENT_MARKER # noqa: F401 - -__version__ = '2.3.0' -__all__ = ['Tokenizer', 'Profile', 'Rules'] diff --git a/extensions/.local/lib/python3.11/site-packages/segments/__main__.py b/extensions/.local/lib/python3.11/site-packages/segments/__main__.py deleted file mode 100644 index 961828c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/__main__.py +++ /dev/null @@ -1,80 +0,0 @@ -import sys -import logging -import pathlib -import argparse - -from segments import Tokenizer, Profile - - -class ParserError(Exception): - pass - - -def tokenize(args): - """ - Tokenize a string (passed as argument or read from stdin) - - segments [--profile=PATH/TO/PROFILE] tokenize [STRING] - """ - if args.profile and not pathlib.Path(args.profile).exists(): # pragma: no cover - raise ParserError('--profile must be a path for an existing file') - print(Tokenizer(profile=args.profile)(_read(args), column=args.mapping)) - - -def profile(args): - """ - Create an orthography profile for a string (passed as argument or read from stdin) - - segments profile [STRING] - """ - print(Profile.from_text(_read(args))) - - -def _read(args): - string = args.args[0] if args.args else sys.stdin.read() - if not isinstance(string, str): - string = string.decode(args.encoding) - return string.strip() - - -def main(parsed_args=None): - commands = {'tokenize': tokenize, 'profile': profile} - logging.basicConfig() - parser = argparse.ArgumentParser( - description="Main command line interface of the segments package.", - epilog="Use '%(prog)s help ' to get help about individual commands.") - parser.add_argument("--verbosity", help="increase output verbosity") - parser.add_argument('command', help=' | '.join(commands)) - parser.add_argument('args', nargs=argparse.REMAINDER) - parser.add_argument("--encoding", help='input encoding', default="utf8") - parser.add_argument("--profile", help='path to an orthography profile', default=None) - parser.add_argument( - "--mapping", - help='column name in ortho profile to map graphemes', - default=Profile.GRAPHEME_COL) - - args = parsed_args or parser.parse_args() - if args.command == 'help' and len(args.args): - # As help text for individual commands we simply re-use the docstrings of the - # callables registered for the command: - print(commands[args.args[0]].__doc__.strip() - if args.args[0] in commands else "Invalid command: '{}'".format(args.args[0])) - else: - if args.command not in commands: - print('invalid command') - parser.print_help() - sys.exit(64) - try: - commands[args.command](args) - except ParserError as e: - print(e) - print(commands[args.command].__doc__.strip()) - sys.exit(64) - except Exception as e: # pragma: no cover - print(e) - sys.exit(1) - sys.exit(0) - - -if __name__ == '__main__': # pragma: no cover - main() diff --git a/extensions/.local/lib/python3.11/site-packages/segments/errors.py b/extensions/.local/lib/python3.11/site-packages/segments/errors.py deleted file mode 100644 index 669806b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/errors.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Default implementations for error handlers -""" -import logging - -from segments.util import REPLACEMENT_MARKER - -log = logging.getLogger(__name__) - - -def strict(c): - log.debug('invalid grapheme: {0}'.format(c)) - raise ValueError('invalid grapheme') - - -def replace(c): - log.debug('replacing grapheme: {0}'.format(c)) - return REPLACEMENT_MARKER - - -def ignore(c): - log.debug('ignoring grapheme: {0}'.format(c)) - return '' diff --git a/extensions/.local/lib/python3.11/site-packages/segments/profile.py b/extensions/.local/lib/python3.11/site-packages/segments/profile.py deleted file mode 100644 index 5ac852d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/profile.py +++ /dev/null @@ -1,165 +0,0 @@ -import copy -import typing -import logging -import pathlib -import warnings -import collections -import unicodedata -import json.decoder - -from csvw import TableGroup, Column - -from segments.tree import Tree -from segments.util import grapheme_pattern - - -class Profile: - """ - An Orthography Profile as specified by Moran and Cysouw 2018. - """ - GRAPHEME_COL = 'Grapheme' - NULL = "NULL" - MD = { - "tables": [ - { - "dialect": { - "delimiter": "\t", - "header": True, - "encoding": "utf-8" - }, - "tableSchema": { - "columns": [ - { - "name": GRAPHEME_COL, - "datatype": "string", - "required": True - } - ], - "primaryKey": GRAPHEME_COL - } - } - ] - } - - @classmethod - def default_metadata(cls, fname=None) -> dict: - md = copy.copy(cls.MD) - md['tables'][0]['url'] = str(fname or '') - return md - - def __init__(self, *specs: dict, **kw): - """ - - Parameters - ---------- - specs : list of dict - A list of grapheme specifications. - kw : - The following keyword arguments are recognized: - - fname: Path of the profile or profile metadata. - - form: Unicode normalization to apply to the data in the profile before use. - - remaining keyword arguments are assigned as dict to `Profile.metadata`. - """ - self.graphemes = collections.OrderedDict() - self.column_labels = set() - self.fname = kw.pop('fname', None) - self.form = kw.pop('form', None) - self.metadata = kw - - log = logging.getLogger(__name__) - for i, spec in enumerate(specs): - if self.GRAPHEME_COL not in spec: - raise ValueError('invalid grapheme specification') - - if self.form: - spec = { - unicodedata.normalize(self.form, k): - None if v is None else unicodedata.normalize(self.form, v) - for k, v in spec.items()} - - grapheme = spec.pop(self.GRAPHEME_COL) - if not grapheme: - raise ValueError('Grapheme must not be empty') - - self.column_labels = self.column_labels.union(spec.keys()) - - # check for duplicates in the orthography profile (fail if dups) - if grapheme not in self.graphemes: - self.graphemes[grapheme] = spec - else: - log.warning( - 'line {0}:duplicate grapheme in profile: {1}'.format(i + 2, grapheme)) - self.tree = Tree(list(self.graphemes.keys())) - - def iteritems(self) -> typing.Generator[dict, None, None]: - for grapheme, spec in self.graphemes.items(): - res = {self.GRAPHEME_COL: grapheme} - res.update({k: None for k in self.column_labels}) - res.update({k: v for k, v in spec.items()}) - yield res - - @classmethod - def from_file(cls, fname, form=None) -> 'Profile': - """ - Read an orthography profile from a metadata file or a default tab-separated profile file. - """ - try: - tg = TableGroup.from_file(fname) - opfname = None - except json.decoder.JSONDecodeError: - tg = TableGroup.fromvalue(cls.default_metadata(fname)) - opfname = fname - if len(tg.tables) != 1: # pragma: no cover - raise ValueError('profile description must contain exactly one table') - metadata = tg.common_props - metadata.update(fname=pathlib.Path(fname), form=form) - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - res = cls( - *[{k: None if (k != cls.GRAPHEME_COL and v == cls.NULL) else v - for k, v in d.items()} - for d in tg.tables[0].iterdicts(fname=opfname)], - **metadata) - return res - - @classmethod - def from_text(cls, text: str, mapping='mapping') -> 'Profile': - """ - Create a Profile instance from the Unicode graphemes found in `text`. - - Parameters - ---------- - text - mapping - - Returns - ------- - A Profile instance. - - """ - graphemes = collections.Counter(grapheme_pattern.findall(text)) - specs = [ - collections.OrderedDict([ - (cls.GRAPHEME_COL, grapheme), - ('frequency', frequency), - (mapping, grapheme)]) - for grapheme, frequency in graphemes.most_common()] - return cls(*specs) - - @classmethod - def from_textfile(cls, fname, mapping='mapping') -> 'Profile': - with pathlib.Path(fname).open(encoding='utf-8') as fp: - lines = fp.readlines() - return cls.from_text(' '.join(lines), mapping=mapping) - - def __str__(self): - """ - A Profile is represented as tab-separated lines of grapheme specifications. - """ - tg = TableGroup.fromvalue(self.default_metadata()) - for col in self.column_labels: - if col != self.GRAPHEME_COL: - tg.tables[0].tableSchema.columns.append( - Column.fromvalue({"name": col, "null": self.NULL})) - - return tg.tables[0].write(self.iteritems(), fname=None).decode('utf8').strip() diff --git a/extensions/.local/lib/python3.11/site-packages/segments/tokenizer.py b/extensions/.local/lib/python3.11/site-packages/segments/tokenizer.py deleted file mode 100644 index 4facefa..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/tokenizer.py +++ /dev/null @@ -1,355 +0,0 @@ -""" -Tokenizer of Unicode characters, grapheme clusters and tailored grapheme clusters -(of orthographies) given an orthography profile. -""" -import typing -import pathlib -import unicodedata - -import regex -from csvw.dsv import reader - -from segments.util import nfd, grapheme_pattern -from segments import errors -from segments.profile import Profile - - -def iterlines(p: typing.Union[pathlib.Path, str]) -> typing.Generator[str, None, None]: - with pathlib.Path(p).open(encoding='utf-8') as fp: - for line in fp.readlines(): - line = line.strip() - if line and not line.startswith('#'): - yield unicodedata.normalize('NFD', line) - - -class Rules: - """ - Rules are given in tuple format, comma delimited. - Regular expressions are given in Python syntax. - """ - def __init__(self, *rules: typing.Tuple[str, str]): - self._rules = [(regex.compile(rule), replacement) for rule, replacement in rules] - - @classmethod - def from_file(cls, fname) -> 'Rules': - return cls(*list(reader(list(iterlines(fname))))) - - def apply(self, s): - for rule, replacement in self._rules: - s = rule.sub(replacement, s) - return s - - -class Tokenizer: - """ - Class for Unicode character and grapheme tokenization. - - This class provides extended functionality for - orthography-specific tokenization with orthography profiles. - - Parameters - ---------- - - profile : string or pathlib.Path or Profile instance (default = None) - Specifies an orthography profile to use. - - rules : string (default = None) - Filename of a rules file. - - Notes - ----- - The tokenizer can be used for pure Unicode character and grapheme - tokenization, i.e. it uses the Unicode standard grapheme parsing rules, as - implemented in the Python regex package by Matthew Barnett, to do basic tokenization - with the "\\X" grapheme regular expression match. This grapheme match - combines one or more Combining Diacritical Marks to their base character. - These are called "grapheme clusters" in Unicode parlance. With these functions - the Tokenizer is meant to do basic rudimentary parsing for things like generating - unigram models (segments and their counts) from input data. - - When a profile is passed, the Tokenizer reads the orthography profile and calls a helper - class to build a tree data structure, which stores the possible Unicode - character combinations that are specified in the orthography profile - (i.e. tailored grapheme clusters) that appear in the data source. - - For example, an orthography profile might specify that in source X - is a single grapheme (Unicode parlance: tailored grapheme) and - therefore it should be chunked as so. Given an orthography profile and - some data to tokenize, the process would look like this: - - input string example: uubo uubo - output string example: uu b o # uu b o - - >>> prf = Profile({'Grapheme': 'uu'}, {'Grapheme': 'b'}, {'Grapheme': 'o'}) - >>> t = Tokenizer(profile=prf) - >>> t('uubo uubo') - 'uu b o # uu b o' - - See also the test orthography profile and rules in the test directory. - - An additional method "combine_modifiers" handles the case where there are - Unicode Spacing Modifier Letters, which are not explicitly - combined to their base character in the Unicode Standard. These graphemes - are called "Tailored grapheme clusters" in Unicode. For more information - see the Unicode Standard Annex #29: Unicode Text Segmentation: - - * http://www.unicode.org/reports/tr29/ - - Additionally, the Tokenizer provides functionality to transform graphemes - into associated character(s) specified in additional columns in the orthography - profile. A dictionary is created that keeps a mapping between source-specific - graphemes and their counterparts (e.g. an IPA column in the orthography profile). - - Lastly, the Tokenizer can be used to transform text as specified in an - orthography rules file. These transformations are specified in a separate - file from the orthography profile (that specifics the document specific graphemes, - and possibly their IPA counterparts) and the orthography rules should - be applied to the output of a grapheme tokenization. - - In an orthography rules file, rules are given in order as regular - expressions, e.g. this rule replaces a vowel followed by an - followed by followed by a second vowel with first vowel - second vowel, e.g.:: - - $ (a|aÌ|e|eÌ|i|iÌ|o|oÌ|u|uÌ)(n)(\\s)(a|aÌ|e|eÌ|i|iÌ|o|oÌ|u|uÌ), \\1 \\2 \\4 - - """ - def __init__(self, - profile=None, - rules=None, - errors_strict: typing.Callable[[str], typing.Optional[str]] = errors.strict, - errors_replace: typing.Callable[[str], typing.Optional[str]] = errors.replace, - errors_ignore: typing.Callable[[str], typing.Optional[str]] = errors.ignore): - self.op = None - if isinstance(profile, Profile): - self.op = profile - elif profile is not None: - self.op = Profile.from_file(profile) - if not rules and self.op and self.op.fname: - _rules = self.op.fname.parent / (self.op.fname.stem + '.rules') - if _rules.exists(): - rules = _rules - self._rules = Rules.from_file(rules) if rules else None - self._errors = { - 'strict': errors_strict, - 'replace': errors_replace, - 'ignore': errors_ignore, - } - - def __call__(self, - string: str, - column: str = Profile.GRAPHEME_COL, - form: typing.Optional[typing.Literal['NFC', 'NFKC', 'NFD', 'NFKD']] = None, - ipa: bool = False, - segment_separator=' ', - separator=' # ', - errors: typing.Literal['replace', 'strict', 'ignore'] = 'replace') -> str: - """ - The main task of a Tokenizer is tokenizing! This is what happens when called. - - This function determines what to do given any combination - of orthography profile and rules or not orthography profile - or rules. - - Parameters - ---------- - string : str - The input string to be tokenized. - - column : str (default = "graphemes") - The column label for the transformation, if specified. - - form : None or unicode normalization form - Normalize return value if form is not None. - - ipa : bool - Tokenize IPA (work in progress) - - Returns - ------- - result : str - Result of the tokenization. - - """ - res = [] - for word in string.split(): - if ipa: - res.append(self.combine_modifiers(self.grapheme_clusters(nfd(word)))) - else: - if self.op: - res.append( - self.transform(word, column=column, error=self._errors[errors])) - else: - res.append(self.grapheme_clusters(nfd(word))) - - def pp(word): - res = segment_separator.join(word).strip() - res = self._rules.apply(res) if self._rules else res - return unicodedata.normalize(form, res) if form else res - - return separator.join(pp(word) for word in res) - - def characters(self, string, segment_separator=' ', separator=' # ',) -> str: - """ - Given a string as input, return a space-delimited string of Unicode characters - (code points rendered as glyphs). - Parameters - ---------- - string : str - A Unicode string to be tokenized into graphemes. - Returns - ------- - result : str - String returned is space-delimited on Unicode characters and contains "#" to - mark word boundaries. - The string is in NFD. - Notes - ----- - Input is first normalized according to Normalization Ford D(ecomposition). - String returned contains "#" to mark word boundaries. - """ - return separator.join(segment_separator.join(word) for word in nfd(string).split()) - - def grapheme_clusters(self, word): - """ - See: Unicode Standard Annex #29: UNICODE TEXT SEGMENTATION - http://www.unicode.org/reports/tr29/ - - Given a string as input, return a list of Unicode graphemes using the - "\\X" regular expression. - - Parameters - ---------- - word : str - A Unicode string to be tokenized into graphemes. - - Returns - ------- - result : list - List of Unicode graphemes in NFD. - - """ - # init the regex Unicode grapheme cluster match - return grapheme_pattern.findall(word) - - def transform(self, word, column=Profile.GRAPHEME_COL, error=errors.replace): - """ - Transform a string's graphemes into the mappings given in a different column - in the orthography profile. - - Parameters - ---------- - word : str - The input string to be tokenized. - - column : str (default = "Grapheme") - The label of the column to transform to. Default it to tokenize with - orthography profile. - - Returns - ------- - result : list of lists - Result of the transformation. - - """ - assert self.op, 'method can only be called with orthography profile.' - - if column != Profile.GRAPHEME_COL and column not in self.op.column_labels: - raise ValueError("Column {0} not found in profile.".format(column)) - - word = self.op.tree.parse(word, error) - if column == Profile.GRAPHEME_COL: - return word - out = [] - for token in word: - try: - target = self.op.graphemes[token][column] - except KeyError: - target = self._errors['replace'](token) - if target is not None: - if isinstance(target, (tuple, list)): - out.extend(target) - else: - out.append(target) - return out - - def rules(self, word): - """ - Function to tokenize input string and return output of str with ortho rules - applied. - - Parameters - ---------- - word : str - The input string to be tokenized. - - Returns - ------- - result : str - Result of the orthography rules applied to the input str. - - """ - return self._rules.apply(word) if self._rules else word - - def combine_modifiers(self, graphemes): - """ - Given a string that is space-delimited on Unicode grapheme clusters, - group Unicode modifier letters with their preceding base characters, - deal with tie bars, etc. - - Parameters - ---------- - string : str - A Unicode string tokenized into grapheme clusters to be tokenized into simple - IPA. - - """ - result = [] - temp = "" - count = len(graphemes) - for grapheme in reversed(graphemes): - count -= 1 - if len(grapheme) == 1 and unicodedata.category(grapheme) == "Lm" \ - and not ord(grapheme) in [712, 716] and len(graphemes) > 1: - temp = grapheme + temp - # hack for the cases where a space modifier is the first character in the - # string - if count == 0: - result[-1] = temp + result[-1] - continue # pragma: no cover - - # catch and repair stress marks - if len(grapheme) == 1 and (ord(grapheme) in [712, 716]) and result: - # If result == [], there's nothing to combine with ... - result[-1] = grapheme + result[-1] - temp = "" - continue - - # combine contour tone marks (non-accents) - if len(grapheme) == 1 and unicodedata.category(grapheme) == "Sk": - if len(result) == 0: - result.append(grapheme) - temp = "" - continue - else: - if unicodedata.category(result[-1][0]) == "Sk": - result[-1] = grapheme + temp + result[-1] - temp = "" - continue - - result.append(grapheme + temp) - temp = "" - - # last check for tie bars - segments = result[::-1] - i = 0 - r = [] - while i < len(segments): - # tie bars - if ord(segments[i][-1]) in [865, 860]: - r.append(segments[i] + segments[i + 1]) - i += 2 - else: - r.append(segments[i]) - i += 1 - return r diff --git a/extensions/.local/lib/python3.11/site-packages/segments/tree.py b/extensions/.local/lib/python3.11/site-packages/segments/tree.py deleted file mode 100644 index f06c0ce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/tree.py +++ /dev/null @@ -1,68 +0,0 @@ -from segments.errors import replace - - -class TreeNode: - """ - Private class that creates the tree data structure from the orthography profile for - parsing. - """ - - def __init__(self, char, sentinel=False): - self.char = char - self.children = {} - self.sentinel = sentinel - - -class Tree: - def __init__(self, graphemes): - def _multigraph(node, line): - # Internal function to add a multigraph starting at node. - for char in line: - node = node.children.setdefault(char, TreeNode(char)) - node.sentinel = True - - self.root = TreeNode('', sentinel=True) - for grapheme in graphemes: - _multigraph(self.root, grapheme) - - def parse(self, line, error=replace): - res, idx = self._parse(self.root, line, 0) - rem = line[idx:] - while rem: - # Chop off one character and try parsing the remainder: - res.append(error(rem[0])) - rem = rem[1:] - r, i = self._parse(self.root, rem, 0) - res.extend(r) - rem = rem[i:] - return res - - def _parse(self, root, line, idx): - """ - :param root: Tree node. - :param line: String to parse. - :param idx: Global counter of characters parsed. - :return: (list of parsed graphemes, incremented character count) - """ - # Base (or degenerate..) case. - if len(line) == 0: - return [], idx - - parse = [] - curr = 0 - node = root - cidx = idx - while curr < len(line): - node = node.children.get(line[curr]) - curr += 1 - if not node: - break - if node.sentinel: - subparse, cidx = self._parse(root, line[curr:], idx + curr) - # Always keep the latest valid parse, which will be - # the longest-matched (greedy match) graphemes. - parse = [line[:curr]] - parse.extend(subparse) - if parse: - idx = cidx - return parse, idx diff --git a/extensions/.local/lib/python3.11/site-packages/segments/util.py b/extensions/.local/lib/python3.11/site-packages/segments/util.py deleted file mode 100644 index ecaa056..0000000 --- a/extensions/.local/lib/python3.11/site-packages/segments/util.py +++ /dev/null @@ -1,8 +0,0 @@ -import functools -import unicodedata - -import regex - -REPLACEMENT_MARKER = '�' -nfd = functools.partial(unicodedata.normalize, 'NFD') -grapheme_pattern = regex.compile(r"\X", regex.UNICODE) diff --git a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/LICENSE deleted file mode 100644 index 1cc22a5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2010-2024 Benjamin Peterson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/METADATA deleted file mode 100644 index cfde03c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/METADATA +++ /dev/null @@ -1,43 +0,0 @@ -Metadata-Version: 2.1 -Name: six -Version: 1.17.0 -Summary: Python 2 and 3 compatibility utilities -Home-page: https://github.com/benjaminp/six -Author: Benjamin Peterson -Author-email: benjamin@python.org -License: MIT -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* -License-File: LICENSE - -.. image:: https://img.shields.io/pypi/v/six.svg - :target: https://pypi.org/project/six/ - :alt: six on PyPI - -.. image:: https://readthedocs.org/projects/six/badge/?version=latest - :target: https://six.readthedocs.io/ - :alt: six's documentation on Read the Docs - -.. image:: https://img.shields.io/badge/license-MIT-green.svg - :target: https://github.com/benjaminp/six/blob/master/LICENSE - :alt: MIT License badge - -Six is a Python 2 and 3 compatibility library. It provides utility functions -for smoothing over the differences between the Python versions with the goal of -writing Python code that is compatible on both Python versions. See the -documentation for more information on what is provided. - -Six supports Python 2.7 and 3.3+. It is contained in only one Python -file, so it can be easily copied into your project. (The copyright and license -notice must be retained.) - -Online documentation is at https://six.readthedocs.io/. - -Bugs can be reported to https://github.com/benjaminp/six. The code can also -be found there. diff --git a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/RECORD deleted file mode 100644 index 1b71f40..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/RECORD +++ /dev/null @@ -1,6 +0,0 @@ -six.py,sha256=xRyR9wPT1LNpbJI8tf7CE-BeddkhU5O--sfy-mo5BN8,34703 -six-1.17.0.dist-info/LICENSE,sha256=Q3W6IOK5xsTnytKUCmKP2Q6VzD1Q7pKq51VxXYuh-9A,1066 -six-1.17.0.dist-info/METADATA,sha256=ViBCB4wnUlSfbYp8htvF3XCAiKe-bYBnLsewcQC3JGg,1658 -six-1.17.0.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109 -six-1.17.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 -six-1.17.0.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/WHEEL deleted file mode 100644 index 104f387..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.6.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/top_level.txt deleted file mode 100644 index ffe2fce..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six-1.17.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -six diff --git a/extensions/.local/lib/python3.11/site-packages/six.py b/extensions/.local/lib/python3.11/site-packages/six.py deleted file mode 100644 index 3de5969..0000000 --- a/extensions/.local/lib/python3.11/site-packages/six.py +++ /dev/null @@ -1,1003 +0,0 @@ -# Copyright (c) 2010-2024 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -"""Utilities for writing code that runs on Python 2 and 3""" - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.17.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - -if PY34: - from importlib.util import spec_from_loader -else: - spec_from_loader = None - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def find_spec(self, fullname, path, target=None): - if fullname in self.known_modules: - return spec_from_loader(fullname, self) - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - - def create_module(self, spec): - return self.load_module(spec.name) - - def exec_module(self, module): - pass - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("getoutput", "commands", "subprocess"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("splitvalue", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), - MovedAttribute("parse_http_list", "urllib2", "urllib.request"), - MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), -] -if sys.version_info[:2] < (3, 14): - _urllib_request_moved_attributes.extend( - [ - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - ] - ) -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - del io - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" - _assertNotRegex = "assertNotRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -def assertNotRegex(self, *args, **kwargs): - return getattr(self, _assertNotRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - try: - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - try: - raise tp, value, tb - finally: - tb = None -""") - - -if sys.version_info[:2] > (3,): - exec_("""def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - # This does exactly the same what the :func:`py3:functools.update_wrapper` - # function does on Python versions after 3.2. It sets the ``__wrapped__`` - # attribute on ``wrapper`` object and it doesn't raise an error if any of - # the attributes mentioned in ``assigned`` and ``updated`` are missing on - # ``wrapped`` object. - def _update_wrapper(wrapper, wrapped, - assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - for attr in assigned: - try: - value = getattr(wrapped, attr) - except AttributeError: - continue - else: - setattr(wrapper, attr, value) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - wrapper.__wrapped__ = wrapped - return wrapper - _update_wrapper.__doc__ = functools.update_wrapper.__doc__ - - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - return functools.partial(_update_wrapper, wrapped=wrapped, - assigned=assigned, updated=updated) - wraps.__doc__ = functools.wraps.__doc__ - -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(type): - - def __new__(cls, name, this_bases, d): - if sys.version_info[:2] >= (3, 7): - # This version introduced PEP 560 that requires a bit - # of extra care (we mimic what is done by __build_class__). - resolved_bases = types.resolve_bases(bases) - if resolved_bases is not bases: - d['__orig_bases__'] = bases - else: - resolved_bases = bases - return meta(name, resolved_bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - if hasattr(cls, '__qualname__'): - orig_vars['__qualname__'] = cls.__qualname__ - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def ensure_binary(s, encoding='utf-8', errors='strict'): - """Coerce **s** to six.binary_type. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> encoded to `bytes` - - `bytes` -> `bytes` - """ - if isinstance(s, binary_type): - return s - if isinstance(s, text_type): - return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) - - -def ensure_str(s, encoding='utf-8', errors='strict'): - """Coerce *s* to `str`. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - # Optimization: Fast return for the common case. - if type(s) is str: - return s - if PY2 and isinstance(s, text_type): - return s.encode(encoding, errors) - elif PY3 and isinstance(s, binary_type): - return s.decode(encoding, errors) - elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) - return s - - -def ensure_text(s, encoding='utf-8', errors='strict'): - """Coerce *s* to six.text_type. - - For Python 2: - - `unicode` -> `unicode` - - `str` -> `unicode` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - if isinstance(s, binary_type): - return s.decode(encoding, errors) - elif isinstance(s, text_type): - return s - else: - raise TypeError("not expecting type '%s'" % type(s)) - - -def python_2_unicode_compatible(klass): - """ - A class decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/extensions/.local/lib/python3.11/site-packages/test/__init__.py b/extensions/.local/lib/python3.11/site-packages/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_espeak.py b/extensions/.local/lib/python3.11/site-packages/test/test_espeak.py deleted file mode 100644 index ce102a3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_espeak.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the espeak backend""" - -# pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name - -import os -import shutil -import pytest - -from phonemizer.backend import EspeakBackend -from phonemizer.backend.espeak.wrapper import EspeakWrapper -from phonemizer.separator import Separator, default_separator - - -def test_bad_text(): - backend = EspeakBackend('en-us') - text = 'hello world' - with pytest.raises(RuntimeError) as err: - backend.phonemize(text, default_separator, True) - assert 'input text to phonemize() is str' in str(err) - - assert backend.phonemize( - [text], default_separator, True) == ['hÉ™loÊŠ wÉœËld'] - - -def test_english(): - backend = EspeakBackend('en-us') - text = ['hello world', 'goodbye', 'third line', 'yet another'] - out = backend.phonemize(text, default_separator, True) - assert out == ['hÉ™loÊŠ wÉœËld', 'ɡʊdbaɪ', 'θɜËd laɪn', 'jÉ›t Énʌðɚ'] - - -def test_stress(): - backend = EspeakBackend('en-us', with_stress=False) - assert backend.phonemize( - ['hello world'], default_separator, True) == ['hÉ™loÊŠ wÉœËld'] - - backend = EspeakBackend('en-us', with_stress=True) - assert backend.phonemize( - ['hello world'], default_separator, True) == ['hÉ™lˈoÊŠ wˈɜËld'] - - -def test_french(): - backend = EspeakBackend('fr-fr') - text = ['bonjour le monde'] - sep = Separator(word=';eword ', syllable=None, phone=' ') - expected = ['b ɔ̃ Ê’ u Ê ;eword l É™ ;eword m ɔ̃ d ;eword '] - out = backend.phonemize(text, sep, False) - assert out == expected - - -@pytest.mark.skipif( - ( - not EspeakBackend.is_espeak_ng() or - # Arabic is not supported by the Windows msi installer from espeak-ng - # github release - not EspeakBackend.is_supported_language('ar')), - reason='Arabic is not supported') -def test_arabic(): - backend = EspeakBackend('ar') - text = ['السلام عليكم'] - sep = Separator() - - # Arabic seems to have changed starting at espeak-ng-1.49.3 - if EspeakBackend.version() >= (1, 49, 3): - expected = ['Ê”assalaËm Ê•liËkm '] - else: - expected = ['Ê”assalaam Ê•aliijkum '] - out = backend.phonemize(text, sep, False) - assert out == expected - - -# see https://github.com/bootphon/phonemizer/issues/31 -def test_phone_separator_simple(): - text = ['The lion and the tiger ran'] - sep = Separator(phone='_') - backend = EspeakBackend('en-us') - - output = backend.phonemize(text, separator=sep, strip=True) - expected = ['ð_É™ l_aɪə_n æ_n_d ð_É™ t_aɪ_É¡_Éš ɹ_æ_n'] - assert expected == output - - output = backend.phonemize(text, separator=sep, strip=False) - expected = ['ð_É™_ l_aɪə_n_ æ_n_d_ ð_É™_ t_aɪ_É¡_Éš_ ɹ_æ_n_ '] - assert expected == output - - -@pytest.mark.parametrize( - 'text, expected', - (('the hello but the', 'ð_É™ h_É™_l_oÊŠ b_ÊŒ_t ð_É™'), - # ('Here there and everywhere', 'h_ɪɹ ð_ɛɹ æ_n_d É›_v_ɹ_ɪ_w_ɛɹ'), - # ('He was hungry and tired.', 'h_iË w_ÊŒ_z h_ÊŒ_Å‹_É¡_ɹ_i æ_n_d t_aɪɚ_d'), - ('He was hungry but tired.', 'h_iË w_ÊŒ_z h_ÊŒ_Å‹_É¡_ɹ_i b_ÊŒ_t t_aɪɚ_d'))) -def test_phone_separator(text, expected): - sep = Separator(phone='_') - backend = EspeakBackend('en-us') - output = backend.phonemize([text], separator=sep, strip=True)[0] - assert output == expected - - -@pytest.mark.skipif( - 'PHONEMIZER_ESPEAK_LIBRARY' in os.environ, - reason='cannot modify environment') -def test_path_good(): - espeak = EspeakBackend.library() - try: - EspeakBackend.set_library(None) - assert espeak == EspeakBackend.library() - - library = EspeakWrapper().library_path - EspeakBackend.set_library(library) - - test_english() - - # restore the espeak path to default - finally: - EspeakBackend.set_library(None) - - -@pytest.mark.skipif( - 'PHONEMIZER_ESPEAK_LIBRARY' in os.environ, - reason='cannot modify environment') -def test_path_bad(): - try: - # corrupt the default espeak path, try to use python executable instead - binary = shutil.which('python') - EspeakBackend.set_library(binary) - - with pytest.raises(RuntimeError): - EspeakBackend('en-us') - with pytest.raises(RuntimeError): - EspeakBackend.version() - - EspeakBackend.set_library(__file__) - with pytest.raises(RuntimeError): - EspeakBackend('en-us') - - # restore the espeak path to default - finally: - EspeakBackend.set_library(None) - - -@pytest.mark.skipif( - 'PHONEMIZER_ESPEAK_LIBRARY' in os.environ, - reason='cannot modify environment') -def test_path_venv(): - try: - os.environ['PHONEMIZER_ESPEAK_LIBRARY'] = ( - shutil.which('python')) - with pytest.raises(RuntimeError): - EspeakBackend('en-us').phonemize(['hello']) - with pytest.raises(RuntimeError): - EspeakBackend.version() - - os.environ['PHONEMIZER_ESPEAK_LIBRARY'] = __file__ - with pytest.raises(RuntimeError): - EspeakBackend.version() - - finally: - try: - del os.environ['PHONEMIZER_ESPEAK_LIBRARY'] - except KeyError: - pass - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='tie only compatible with espeak-ng') -@pytest.mark.parametrize( - 'tie, expected', [ - (False, 'dÊ’_æ_k_i_ tʃ_æ_n_ '), - (True, 'd͡ʒæki t͡ʃæn '), - ('8', 'd8ʒæki t8ʃæn ')]) -def test_tie_simple(caplog, tie, expected): - backend = EspeakBackend('en-us', tie=tie) - assert backend.phonemize( - ['Jackie Chan'], - separator=Separator(word=' ', phone='_'))[0] == expected - - if tie: - messages = [msg[2] for msg in caplog.record_tuples] - assert ( - 'cannot use ties AND phone separation, ignoring phone separator' - in messages) - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='tie only compatible with espeak-ng') -def test_tie_utf8(): - # NOTE this is a bug in espeak to append ties on (en) language switch - # flags. For now phonemizer does not fix it. - backend = EspeakBackend('fr-fr', tie=True) - - # used to be 'bɔ̃͡ʒuÊ ' - assert backend.phonemize(['bonjour']) == ['bɔ̃ʒuÊ '] - - # used to be 'ty É›m lÉ™ (Í¡eÍ¡nÍ¡)fÊŠtbɔ͡Ël(Í¡fÍ¡rÍ¡)' - assert backend.phonemize( - ['tu aimes le football']) == ['ty É›m lÉ™ (Í¡eÍ¡n)fÊŠtbÉ”Ël(Í¡fÍ¡r) '] - - assert backend.phonemize( - ['bonjour apple']) == ['bɔ̃ʒuÊ (Í¡eÍ¡n)apə͡l(Í¡fÍ¡r) '] - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='tie only compatible with espeak-ng') -def test_tie_bad(): - with pytest.raises(RuntimeError): - EspeakBackend('en-us', tie='abc') diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_lang_switch.py b/extensions/.local/lib/python3.11/site-packages/test/test_espeak_lang_switch.py deleted file mode 100644 index 0269f6e..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_lang_switch.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the espeak backend language switch processing""" - -# pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name - -import pytest - -from phonemizer.backend import EspeakBackend -from phonemizer.separator import Separator - - -@pytest.fixture -def langswitch_text(): - return [ - "j'aime l'anglais", - "j'aime le football", - "football", - "surtout le real madrid", - "n'utilise pas google"] - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -@pytest.mark.parametrize('njobs', [1, 3]) -def test_language_switch_keep_flags(caplog, langswitch_text, njobs): - backend = EspeakBackend('fr-fr', language_switch='keep-flags') - out = backend.phonemize( - langswitch_text, separator=Separator(), strip=True, njobs=njobs) - assert out == [ - 'Ê’É›m lɑ̃ɡlÉ›', - 'Ê’É›m lÉ™ (en)fÊŠtbÉ”Ël(fr)', - '(en)fÊŠtbÉ”Ël(fr)', - 'syÊtu lÉ™ (en)ɹiÉ™l(fr) madÊid', - 'nytiliz pa (en)É¡uËɡəl(fr)'] - - messages = [msg[2] for msg in caplog.record_tuples] - assert ( - '4 utterances containing language switches on lines 2, 3, 4, 5' - in messages) - assert ( - 'language switch flags have been kept (applying "keep-flags" policy)' - in messages) - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -@pytest.mark.parametrize('njobs', [1, 3]) -def test_language_switch_default(caplog, langswitch_text, njobs): - # default behavior is to keep the flags - backend = EspeakBackend('fr-fr') - out = backend.phonemize( - langswitch_text, separator=Separator(), strip=True, njobs=njobs) - assert out == [ - 'Ê’É›m lɑ̃ɡlÉ›', - 'Ê’É›m lÉ™ (en)fÊŠtbÉ”Ël(fr)', - '(en)fÊŠtbÉ”Ël(fr)', - 'syÊtu lÉ™ (en)ɹiÉ™l(fr) madÊid', - 'nytiliz pa (en)É¡uËɡəl(fr)'] - - messages = [msg[2] for msg in caplog.record_tuples] - assert ( - '4 utterances containing language switches on lines 2, 3, 4, 5' - in messages) - assert ( - 'language switch flags have been kept (applying "keep-flags" policy)' - in messages) - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -@pytest.mark.parametrize('njobs', [1, 3]) -def test_language_switch_remove_flags(caplog, langswitch_text, njobs): - backend = EspeakBackend('fr-fr', language_switch='remove-flags') - out = backend.phonemize( - langswitch_text, separator=Separator(), strip=True, njobs=njobs) - assert out == [ - 'Ê’É›m lɑ̃ɡlÉ›', - 'Ê’É›m lÉ™ fÊŠtbÉ”Ël', - 'fÊŠtbÉ”Ël', - 'syÊtu lÉ™ ɹiÉ™l madÊid', - 'nytiliz pa É¡uËɡəl'] - - messages = [msg[2] for msg in caplog.record_tuples] - assert ( - '4 utterances containing language switches on lines 2, 3, 4, 5' - in messages) - assert ( - 'language switch flags have been removed ' - '(applying "remove-flags" policy)' - in messages) - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -@pytest.mark.parametrize('njobs', [1, 3]) -def test_language_switch_remove_utterance(caplog, langswitch_text, njobs): - backend = EspeakBackend('fr-fr', language_switch='remove-utterance') - out = backend.phonemize( - langswitch_text, separator=Separator(), strip=True, njobs=njobs) - assert out == ['Ê’É›m lɑ̃ɡlÉ›', '', '', '', ''] - - messages = [msg[2] for msg in caplog.record_tuples] - assert ( - 'removed 4 utterances containing language switches ' - '(applying "remove-utterance" policy)' - in messages) - - with pytest.raises(RuntimeError): - backend = EspeakBackend('fr-fr', language_switch='foo') - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -@pytest.mark.parametrize( - 'policy', ('keep-flags', 'remove-flags', 'remove-utterance')) -def test_no_switch(policy, caplog): - text = ["j'aime l'anglais", "tu parles le français"] - backend = EspeakBackend('fr-fr', language_switch=policy) - out = backend.phonemize(text, separator=Separator(), strip=True) - assert out == ['Ê’É›m lɑ̃ɡlÉ›', 'ty paÊl lÉ™ fÊɑ̃sÉ›'] - - messages = [msg[2] for msg in caplog.record_tuples] - assert not messages diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_word_mismatch.py b/extensions/.local/lib/python3.11/site-packages/test/test_espeak_word_mismatch.py deleted file mode 100644 index 37ae0d3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_word_mismatch.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Tests of the phonemizer.backend.espeak.words_mismatch module""" - -# pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name - -import pytest - -import re - -from phonemizer import phonemize -from phonemizer.backend.espeak.words_mismatch import Ignore -from phonemizer.separator import Separator, default_separator - - -@pytest.fixture -def text(): - return ["How are you?", "I have been busy", "I won't have time"] - - -def test_count_words(): - # pylint: disable=protected-access - count_words = lambda phn: Ignore._count_words( - phn, wordsep=default_separator.word) - assert count_words(['']) == [0] - assert count_words(['a']) == [1] - assert count_words(['aaa']) == [1] - assert count_words([' aaa ']) == [1] - assert count_words([' a a \taa ']) == [3] - - -def test_bad(): - with pytest.raises(RuntimeError): - phonemize('', words_mismatch='foo') - - with pytest.raises(RuntimeError): - phonemize('', backend='festival', words_mismatch='remove') - - -@pytest.mark.parametrize('mode', ['ignore', 'warn', 'remove']) -def test_mismatch(caplog, text, mode): - phn = phonemize( - text, backend='espeak', language='en-us', words_mismatch=mode) - - if mode == 'ignore': - assert phn == ['haÊŠ É‘Ëɹ juË ', 'aɪ hÉvbɪn bɪzi ', 'aɪ woÊŠntÉv taɪm '] - messages = [msg[2] for msg in caplog.record_tuples] - assert len(messages) == 1 - assert 'words count mismatch on 67.0% of the lines (2/3)' in messages - elif mode == 'remove': - assert phn == ['haÊŠ É‘Ëɹ juË ', '', ''] - messages = [msg[2] for msg in caplog.record_tuples] - assert len(messages) == 2 - assert 'words count mismatch on 67.0% of the lines (2/3)' in messages - assert 'removing the mismatched lines' in messages - elif mode == 'warn': - assert phn == ['haÊŠ É‘Ëɹ juË ', 'aɪ hÉvbɪn bɪzi ', 'aɪ woÊŠntÉv taɪm '] - messages = [msg[2] for msg in caplog.record_tuples] - assert len(messages) == 3 - assert ( - 'words count mismatch on line 2 (expected 4 words but get 3)' - in messages) - assert ( - 'words count mismatch on line 3 (expected 4 words but get 3)' - in messages) - assert 'words count mismatch on 67.0% of the lines (2/3)' in messages - - -# from https://github.com/bootphon/phonemizer/issues/169 -def test_custom_separator(caplog): - phn = phonemize( - 'try', - backend='espeak', - language='en-us', - separator=Separator(word='|', phone=' '), - words_mismatch='warn') - - assert phn == 't ɹ aɪ |' - messages = [msg[2] for msg in caplog.record_tuples] - assert len(messages) == 0 diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_wrapper.py b/extensions/.local/lib/python3.11/site-packages/test/test_espeak_wrapper.py deleted file mode 100644 index fa59dbf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_espeak_wrapper.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the EspeakWrapper class""" - -# pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name - -import os -import pathlib -import pickle -import sys - -import pytest - -from phonemizer.backend.espeak.wrapper import EspeakWrapper -from phonemizer.backend import EspeakMbrolaBackend - - -@pytest.fixture -def wrapper(): - return EspeakWrapper() - - -def test_basic(wrapper): - assert wrapper.version >= (1, 48) - assert 'espeak' in str(wrapper.library_path) - assert os.path.isabs(wrapper.library_path) - assert os.path.isabs(wrapper.data_path) # not None, no raise - - -def test_available_voices(wrapper): - espeak = set(wrapper.available_voices()) - assert espeak - - mbrola = set(wrapper.available_voices('mbrola')) - # can be empty if no mbrola voice installed (occurs only on Windows, at - # least within the github CI pipeline) - if mbrola: - assert not espeak.intersection(mbrola) - - -def test_set_get_voice(wrapper): - assert wrapper.voice is None - with pytest.raises(RuntimeError) as err: - wrapper.set_voice('') - assert 'invalid voice code ""' in str(err) - - wrapper.set_voice('fr-fr') - assert wrapper.voice.language == 'fr-fr' - assert wrapper.voice.name in ( - 'French (France)', # >1.48.3 - 'french') # older espeak - - wrapper.set_voice('en-us') - assert wrapper.voice.language == 'en-us' - assert wrapper.voice.name in ( - 'English (America)', # >1.48.3 - 'english-us') # older espeak - - # no mbrola voices available on Windows by default (at least on the github - # CI pipeline) - if sys.platform != 'win32': - wrapper.set_voice('mb-af1') - assert wrapper.voice.language == 'af' - assert wrapper.voice.name == 'afrikaans-mbrola-1' - - with pytest.raises(RuntimeError) as err: - wrapper.set_voice('some non existant voice code') - assert 'invalid voice code' in str(err) - - -def _test_pickle(voice): - # the wrapper is pickled when using espeak backend on multiple jobs - wrapper = EspeakWrapper() - wrapper.set_voice(voice) - - dump = pickle.dumps(wrapper) - wrapper2 = pickle.loads(dump) - - assert wrapper.version == wrapper2.version - assert wrapper.library_path == wrapper2.library_path - assert wrapper.data_path == wrapper2.data_path - assert wrapper.voice == wrapper2.voice - - -def test_pickle_en_us(): - _test_pickle('en-us') - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available() or - not EspeakMbrolaBackend.is_supported_language('mb-fr1'), - reason='mbrola or mb-fr1 voice not installed') -def test_pickle_mb_fr1(): - _test_pickle('mb-fr1') - - -def test_twice(): - wrapper1 = EspeakWrapper() - wrapper2 = EspeakWrapper() - - assert wrapper1.data_path == wrapper2.data_path - assert wrapper1.version == wrapper2.version - assert wrapper1.library_path == wrapper2.library_path - - wrapper1.set_voice('fr-fr') - assert wrapper1.voice.language == 'fr-fr' - wrapper2.set_voice('en-us') - assert wrapper2.voice.language == 'en-us' - assert wrapper1.voice.language == 'fr-fr' - - # pylint: disable=protected-access - assert wrapper1._espeak._tempdir != wrapper2._espeak._tempdir - - -@pytest.mark.skipif(sys.platform == 'win32', reason='not supported on Windows') -def test_deletion(): - # pylint: disable=protected-access - wrapper = EspeakWrapper() - path = pathlib.Path(wrapper._espeak._tempdir) - del wrapper - assert not path.exists() diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_festival.py b/extensions/.local/lib/python3.11/site-packages/test/test_festival.py deleted file mode 100644 index 063a7dc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_festival.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2015-2021 Thomas Schatz, Xuan Nga Cao, Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the festival backend""" - -# pylint: disable=missing-docstring - - -import os -import pathlib -import shutil - -import pytest - -from phonemizer.separator import Separator -from phonemizer.backend import FestivalBackend - - -def _test(text, separator=Separator( - word=' ', syllable='|', phone='-')): - backend = FestivalBackend('en-us') - # pylint: disable=protected-access - return backend._phonemize_aux(text, 0, separator, True) - - -@pytest.mark.skipif( - FestivalBackend.version() <= (2, 1), - reason='festival-2.1 gives different results than further versions ' - 'for syllable boundaries') -def test_hello(): - assert _test(['hello world']) == ['hh-ax|l-ow w-er-l-d'] - assert _test(['hello', 'world']) == ['hh-ax|l-ow', 'w-er-l-d'] - - -@pytest.mark.parametrize('text', ['', ' ', ' ', '(', '()', '"', "'"]) -def test_bad_input(text): - assert _test(text) == [] - - -def test_quote(): - assert _test(["it's"]) == ['ih-t-s'] - assert _test(["its"]) == ['ih-t-s'] - assert _test(["it s"]) == ['ih-t eh-s'] - assert _test(['it "s']) == ['ih-t eh-s'] - - -def test_im(): - sep = Separator(word=' ', syllable='', phone='') - assert _test(["I'm looking for an image"], sep) \ - == ['aym luhkaxng faor axn ihmaxjh'] - assert _test(["Im looking for an image"], sep) \ - == ['ihm luhkaxng faor axn ihmaxjh'] - - -@pytest.mark.skipif( - not shutil.which('festival'), reason='festival not in PATH') -def test_path_good(): - try: - binary = shutil.which('festival') - FestivalBackend.set_executable(binary) - assert FestivalBackend('en-us').executable() == pathlib.Path(binary) - # restore the festival path to default - finally: - FestivalBackend.set_executable(None) - - -@pytest.mark.skipif( - 'PHONEMIZER_FESTIVAL_EXECUTABLE' in os.environ, - reason='environment variable precedence') -def test_path_bad(): - try: - # corrupt the default espeak path, try to use python executable instead - binary = shutil.which('python') - FestivalBackend.set_executable(binary) - - with pytest.raises(RuntimeError): - FestivalBackend('en-us').phonemize(['hello']) - with pytest.raises(RuntimeError): - FestivalBackend.version() - - with pytest.raises(RuntimeError): - FestivalBackend.set_executable(__file__) - - # restore the festival path to default - finally: - FestivalBackend.set_executable(None) - - -@pytest.mark.skipif( - 'PHONEMIZER_FESTIVAL_EXECUTABLE' in os.environ, - reason='cannot modify environment') -def test_path_venv(): - try: - os.environ['PHONEMIZER_FESTIVAL_EXECUTABLE'] = shutil.which('python') - with pytest.raises(RuntimeError): - FestivalBackend('en-us').phonemize(['hello']) - with pytest.raises(RuntimeError): - FestivalBackend.version() - - os.environ['PHONEMIZER_FESTIVAL_EXECUTABLE'] = __file__ - with pytest.raises(RuntimeError): - FestivalBackend.version() - - finally: - try: - del os.environ['PHONEMIZER_FESTIVAL_EXECUTABLE'] - except KeyError: - pass diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_import.py b/extensions/.local/lib/python3.11/site-packages/test/test_import.py deleted file mode 100644 index 4f013b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_import.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Tests to import the phonemize function""" - -# pylint: disable=missing-docstring -# pylint: disable=import-outside-toplevel - - -def test_relative(): - from phonemizer import phonemize - assert phonemize('a') == 'eɪ ' - - -def test_absolute(): - from phonemizer.phonemize import phonemize - assert phonemize('a') == 'eɪ ' diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_main.py b/extensions/.local/lib/python3.11/site-packages/test/test_main.py deleted file mode 100644 index b9256a0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_main.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2015-2021 Thomas Schatz, Xuan Nga Cao, Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the command line interface""" - -# pylint: disable=missing-docstring - -import os -import pathlib -import tempfile -import shlex -import sys - -import pytest - -from phonemizer.backend import EspeakMbrolaBackend, EspeakBackend -from phonemizer import main, backend, logger - - -def _test(text, expected_output, args=''): - with tempfile.TemporaryDirectory() as tmpdir: - input_file = pathlib.Path(tmpdir) / 'input.txt' - output_file = pathlib.Path(tmpdir) / 'output.txt' - with open(input_file, 'wb') as finput: - finput.write(text.encode('utf8')) - - sys.argv = ['unused', f'{input_file}', '-o', f'{output_file}'] - if args: - sys.argv += shlex.split(args) - main.main() - - with open(output_file, 'rb') as foutput: - output = foutput.read().decode() - - # silly fix for windows - assert output.replace('\r', '').strip(os.linesep) \ - == expected_output.replace('\r', '') - - -def test_help(): - sys.argv = ['foo', '-h'] - with pytest.raises(SystemExit): - main.main() - - -def test_version(): - sys.argv = ['foo', '--version'] - main.main() - - -def test_list_languages(): - sys.argv = ['foo', '--list-languages'] - main.main() - - -def test_readme(): - _test('hello world', 'hÉ™loÊŠ wÉœËld ', '--verbose') - _test('hello world', 'hÉ™loÊŠ wÉœËld ', '--quiet') - _test('hello world', 'hello world | hÉ™loÊŠ wÉœËld ', '--prepend-text') - _test('hello world', 'hhaxlow werld', '-b festival --strip') - _test('bonjour le monde', 'bɔ̃ʒuÊ lÉ™ mɔ̃d ', '-l fr-fr') - _test('bonjour le monde', 'b ɔ̃ Ê’ u Ê ;eword l É™ ;eword m ɔ̃ d ;eword ', - '-l fr-fr -p " " -w ";eword "') - - -@pytest.mark.skipif( - '2.1' in backend.FestivalBackend.version(), - reason='festival-2.1 gives different results than further versions ' - 'for syllable boundaries') -def test_readme_festival_syll(): - _test('hello world', - 'hh ax ;esyll l ow ;esyll ;eword w er l d ;esyll ;eword ', - "-p ' ' -s ';esyll ' -w ';eword ' -b festival -l en-us") - - -@pytest.mark.parametrize('njobs', [1, 6]) -def test_njobs(njobs): - _test( - os.linesep.join(( - 'hello world', - 'goodbye', - 'third line', - 'yet another')), - os.linesep.join(( - 'h-É™-l-oÊŠ w-ÉœË-l-d', - 'É¡-ÊŠ-d-b-aɪ', - 'θ-ÉœË-d l-aɪ-n', - 'j-É›-t É-n-ÊŒ-ð-Éš')), - f'--strip -j {njobs} -l en-us -b espeak -p "-" -s "|" -w " "') - - -def test_unicode(): - _test('untuʼule', 'untṵËle ', '-l yucatec -b segments') - - -def test_logger(): - with pytest.raises(RuntimeError): - logger.get_logger(verbosity=1) - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available() or - not EspeakMbrolaBackend.is_supported_language('mb-fr1'), - reason='mbrola or mb-fr1 voice not installed') -def test_espeak_mbrola(): - _test('coucou toi!', 'k u k u t w a ', - '-b espeak-mbrola -l mb-fr1 -p" " --preserve-punctuation') - - -def test_espeak_path(): - espeak = pathlib.Path(backend.EspeakBackend.library()) - if sys.platform == 'win32': - espeak = str(espeak).replace('\\', '\\\\').replace(' ', '\\ ') - _test('hello world', 'hÉ™loÊŠ wÉœËld ', f'--espeak-library={espeak}') - - -def test_festival_path(): - festival = pathlib.Path(backend.FestivalBackend.executable()) - if sys.platform == 'win32': - festival = str(festival).replace('\\', '\\\\').replace(' ', '\\ ') - - _test('hello world', 'hhaxlow werld ', - f'--festival-executable={festival} -b festival') - - -@pytest.mark.parametrize( - 'args, expected', [ - ('', - 'hÉ™loÊŠ wÉœËld θɹiË ziəɹoÊŠziəɹoÊŠ ziəɹoÊŠ É”Ëɹ tuË fɪfti hÉ™loÊŠ '), - ('--preserve-punctuation', - 'hÉ™loÊŠ, ,wÉœËld? θɹiË,ziəɹoÊŠziəɹoÊŠ ziəɹoÊŠ, É”Ëɹ tuË.fɪfti. ¿hÉ™loÊŠ? '), - ('--preserve-punctuation ' - '--punctuation-marks-is-regex ' - '--punctuation-marks "[^a-zA-ZÀ-ÖØ-öø-ÿ0-9\'\\-]"', - 'hÉ™loÊŠ, ,wÉœËld? ‡ θɹiË,ziəɹoÊŠziəɹoÊŠ ziəɹoÊŠ, É”Ëɹ tuË.fɪfti. ¿hÉ™loÊŠ? '), - ('--preserve-punctuation ' - '--punctuation-marks-is-regex ' - '--punctuation-marks "[;:\\!?¡¿—…\\\"«»“â€]|[,.](?!\\d)"', - 'hÉ™loÊŠ, ,wÉœËld? θɹiË Î¸aÊŠzÉ™nd, É”Ëɹ tuË pɔɪnt faɪv ziəɹoÊŠ. ¿hÉ™loÊŠ? ')]) -def test_punctuation_is_regex(args, expected): - print(args) - _test("hello, ,world? ‡ 3,000, or 2.50. ¿hello?", expected, args) - - -def test_invalid_punctuation_regex(): - with pytest.raises(SystemExit): - _test('hello world', None, '--punctuation-marks-is-regex --punctuation-marks "[*,"') diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_mbrola.py b/extensions/.local/lib/python3.11/site-packages/test/test_mbrola.py deleted file mode 100644 index 5d00f3a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_mbrola.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the espeak-mbrola backend""" - -# pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name - -import pytest - -from phonemizer.backend import EspeakMbrolaBackend -from phonemizer.separator import Separator - - -@pytest.fixture(scope='session') -def backend(): - return EspeakMbrolaBackend('mb-fr1') - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available() or - not EspeakMbrolaBackend.is_supported_language('mb-fr1'), - reason='mbrola or mb-fr1 voice not installed') -@pytest.mark.parametrize( - 'text, expected', - [ - # plosives - ('pont', 'po~'), - ('bon', 'bo~'), - ('temps', 'ta~'), - ('dans', 'da~'), - ('quand', 'ka~'), - ('gant', 'ga~'), - # fricatives - ('femme', 'fam'), - ('vent', 'va~'), - ('sans', 'sa~'), - ('champ', 'Sa~'), - ('gens', 'Za~'), - ('ion', 'jo~'), - # nasals - ('mont', 'mo~'), - ('nom', 'no~'), - ('oignon', 'onjo~'), - ('ping', 'piN'), - # liquid glides - ('long', 'lo~'), - ('rond', 'Ro~'), - ('coin', 'kwe~'), - ('juin', 'Zye~'), - ('pierre', 'pjER'), - # vowels - ('si', 'si'), - ('ses', 'se'), - ('seize', 'sEz'), - ('patte', 'pat'), - ('pâte', 'pat'), - ('comme', 'kOm'), - ('gros', 'gRo'), - ('doux', 'du'), - ('du', 'dy'), - ('deux', 'd2'), - ('neuf', 'n9f'), - ('justement', 'Zystma~'), - ('vin', 've~'), - ('vent', 'va~'), - ('bon', 'bo~'), - ('brun', 'bR9~')]) -def test_sampa_fr(backend, text, expected): - assert expected == backend.phonemize( - [text], strip=True, separator=Separator(phone=''))[0] - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available() or - not EspeakMbrolaBackend.is_supported_language('mb-fr1'), - reason='mbrola or mb-fr1 voice not installed') -def test_french_sampa(backend): - text = ['bonjour le monde'] - sep = Separator(word=None, phone=' ') - - expected = ['b o~ Z u R l @ m o~ d '] - out = backend.phonemize(text, separator=sep, strip=False) - assert out == expected - - expected = ['b o~ Z u R l @ m o~ d'] - out = backend.phonemize(text, separator=sep, strip=True) - assert out == expected - - assert backend.phonemize([''], separator=sep, strip=True) == [''] - assert backend.phonemize(['"'], separator=sep, strip=True) == [''] - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available(), - reason='mbrola not installed') -def test_mbrola_bad_language(): - assert not EspeakMbrolaBackend.is_supported_language('foo-bar') diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_phonemize.py b/extensions/.local/lib/python3.11/site-packages/test/test_phonemize.py deleted file mode 100644 index 3e0e6fd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_phonemize.py +++ /dev/null @@ -1,291 +0,0 @@ -# Copyright 2015-2021 Thomas Schatz, Xuan Nga Cao, Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the phonemizer.phonemize function""" - -# pylint: disable=missing-docstring - -import os -import pytest - -from phonemizer.phonemize import phonemize -from phonemizer.separator import Separator -from phonemizer.backend import EspeakBackend, EspeakMbrolaBackend - - -def test_bad_backend(): - with pytest.raises(RuntimeError): - phonemize('', backend='fetiv') - - with pytest.raises(RuntimeError): - phonemize('', backend='foo') - - with pytest.raises(RuntimeError): - phonemize('', tie=True, backend='festival') - with pytest.raises(RuntimeError): - phonemize('', tie=True, backend='mbrola') - with pytest.raises(RuntimeError): - phonemize('', tie=True, backend='segments') - with pytest.raises(RuntimeError): - phonemize( - '', tie=True, backend='espeak', - separator=Separator(' ', None, '-')) - - -def test_bad_language(): - with pytest.raises(RuntimeError): - phonemize('', language='fr-fr', backend='festival') - - with pytest.raises(RuntimeError): - phonemize('', language='ffr', backend='espeak') - - with pytest.raises(RuntimeError): - phonemize('', language='/path/to/nonexisting/file', backend='segments') - - with pytest.raises(RuntimeError): - phonemize('', language='creep', backend='segments') - - -def test_text_type(): - text1 = ['one two', 'three', 'four five'] - text2 = os.linesep.join(text1) - - phn1 = phonemize(text1, language='en-us', backend='espeak', strip=True) - phn2 = phonemize(text2, language='en-us', backend='espeak', strip=True) - out3 = phonemize(text2, language='en-us', backend='espeak', strip=True, - prepend_text=True) - text3 = [o[0] for o in out3] - phn3 = [o[1] for o in out3] - - assert isinstance(phn1, list) - assert isinstance(phn2, str) - assert os.linesep.join(phn1) == phn2 - assert os.linesep.join(phn3) == phn2 - assert text3 == text1 - - -@pytest.mark.skipif( - not EspeakBackend.is_espeak_ng(), - reason='language switch only exists for espeak-ng') -def test_lang_switch(): - text = ['bonjour apple', 'bonjour toi'] - out = phonemize( - text, - language='fr-fr', - backend='espeak', - prepend_text=True, - language_switch='remove-utterance') - assert out == [('bonjour apple', ''), ('bonjour toi', 'bɔ̃ʒuÊ twa ')] - - -@pytest.mark.parametrize('njobs', [2, 4]) -def test_espeak(njobs): - text = ['one two', 'three', 'four five'] - - out = phonemize( - text, language='en-us', backend='espeak', - strip=True, njobs=njobs) - assert out == ['wÊŒn tuË', 'θɹiË', 'foËɹ faɪv'] - - out = phonemize( - ' '.join(text), language='en-us', backend='espeak', - strip=False, njobs=njobs) - assert out == ' '.join(['wÊŒn tuË', 'θɹiË', 'foËɹ faɪv ']) - - out = phonemize( - os.linesep.join(text), language='en-us', backend='espeak', - strip=False, njobs=njobs) - assert out == os.linesep.join(['wÊŒn tuË ', 'θɹiË ', 'foËɹ faɪv ']) - - -@pytest.mark.skipif( - not EspeakMbrolaBackend.is_available() or - not EspeakMbrolaBackend.is_supported_language('mb-fr1'), - reason='mbrola or mb-fr1 voice not installed') -@pytest.mark.parametrize('njobs', [2, 4]) -def test_espeak_mbrola(caplog, njobs): - text = ['un deux', 'trois', 'quatre cinq'] - - out = phonemize( - text, - language='mb-fr1', - backend='espeak-mbrola', - njobs=njobs, - preserve_punctuation=True) - assert out == ['9~d2', 'tRwa', 'katRse~k'] - - messages = [msg[2] for msg in caplog.record_tuples] - assert 'espeak-mbrola backend cannot preserve punctuation' in messages - assert 'espeak-mbrola backend cannot preserve word separation' in messages - - -@pytest.mark.parametrize('njobs', [2, 4]) -def test_festival(njobs): - text = ['one two', 'three', 'four five'] - - out = phonemize( - text, language='en-us', backend='festival', - strip=False, njobs=njobs) - assert out == ['wahn tuw ', 'thriy ', 'faor fayv '] - - out = phonemize( - ' '.join(text), language='en-us', backend='festival', - strip=True, njobs=njobs) - assert out == ' '.join(['wahn tuw', 'thriy', 'faor fayv']) - - out = phonemize( - os.linesep.join(text), language='en-us', backend='festival', - strip=True, njobs=njobs) - assert out == os.linesep.join(['wahn tuw', 'thriy', 'faor fayv']) - - -def test_festival_bad(): - # cannot use options valid for espeak only - text = ['one two', 'three', 'four five'] - - with pytest.raises(RuntimeError): - phonemize( - text, language='en-us', backend='festival', with_stress=True) - - with pytest.raises(RuntimeError): - phonemize( - text, language='en-us', backend='festival', - language_switch='remove-flags') - - -@pytest.mark.parametrize('njobs', [2, 4]) -def test_segments(njobs): - # one two three four five in Maya Yucatec - text = ['untuʼuleʼ kaʼapʼeʼel', 'oʼoxpʼeʼel', 'kantuʼuloʼon chincho'] - - out = phonemize( - text, language='yucatec', backend='segments', - strip=False, njobs=njobs) - assert out == [ - 'untṵËlḛ ka̰ËpʼḛËl ', 'o̰ËʃpʼḛËl ', 'kantṵËlo̰Ën t̠͡ʃint̠͡ʃo '] - out = phonemize( - ' '.join(text), language='yucatec', backend='segments', - strip=False, njobs=njobs) - assert out == ' '.join( - ['untṵËlḛ ka̰ËpʼḛËl', 'o̰ËʃpʼḛËl', 'kantṵËlo̰Ën t̠͡ʃint̠͡ʃo ']) - - out = phonemize( - os.linesep.join(text), language='yucatec', backend='segments', - strip=True, njobs=njobs) - assert out == os.linesep.join( - ['untṵËlḛ ka̰ËpʼḛËl', 'o̰ËʃpʼḛËl', 'kantṵËlo̰Ën t̠͡ʃint̠͡ʃo']) - - -@pytest.mark.parametrize( - 'backend, empty_lines, punctuation, prepend_text, text, expected', [ - ('espeak', False, False, False, - ['hello world!', '', 'goodbye'], - ['hÉ™loÊŠ wÉœËld ', 'ɡʊdbaɪ ']), - ('espeak', False, True, False, - ['hello world!', '', 'goodbye'], - ['hÉ™loÊŠ wÉœËld! ', 'ɡʊdbaɪ ']), - ('espeak', True, False, False, - ['hello world!', '', 'goodbye'], - ['hÉ™loÊŠ wÉœËld ', '', 'ɡʊdbaɪ ']), - ('espeak', True, True, False, - ['hello world!', '', 'goodbye'], - ['hÉ™loÊŠ wÉœËld! ', '', 'ɡʊdbaɪ ']), - ('segments', False, False, False, - ['achi acho?', '', 'achi acho'], - [u'ÊŒtʃɪ ÊŒtʃʊ ', u'ÊŒtʃɪ ÊŒtʃʊ ']), - ('segments', False, True, False, - ['achi acho?', '', 'achi acho'], - [u'ÊŒtʃɪ ÊŒtʃʊ? ', u'ÊŒtʃɪ ÊŒtʃʊ ']), - ('segments', True, False, False, - ['achi acho?', '', 'achi acho'], - [u'ÊŒtʃɪ ÊŒtʃʊ ', '', u'ÊŒtʃɪ ÊŒtʃʊ ']), - ('segments', True, True, False, - ['achi acho?', '', 'achi acho'], - [u'ÊŒtʃɪ ÊŒtʃʊ? ', '', u'ÊŒtʃɪ ÊŒtʃʊ ']), - ('festival', False, False, False, - ['hello world!', '', 'goodbye'], - ['hhaxlow werld ', 'guhdbay ']), - ('festival', False, True, False, - ['hello world!', '', 'goodbye'], - ['hhaxlow werld! ', 'guhdbay ']), - ('festival', True, False, False, - ['hello world!', '', 'goodbye'], - ['hhaxlow werld ', '', 'guhdbay ']), - ('festival', True, True, False, - ['hello world!', '', 'goodbye'], - ['hhaxlow werld! ', '', 'guhdbay ']), - ('espeak', False, False, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hÉ™loÊŠ wÉœËld '), ('goodbye', 'ɡʊdbaɪ ')]), - ('espeak', False, True, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hÉ™loÊŠ wÉœËld! '), ('goodbye', 'ɡʊdbaɪ ')]), - ('espeak', True, False, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hÉ™loÊŠ wÉœËld '), ('', ''), ('goodbye', 'ɡʊdbaɪ ')]), - ('espeak', True, True, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hÉ™loÊŠ wÉœËld! '), ('', ''), ('goodbye', 'ɡʊdbaɪ ')]), - ('segments', False, False, True, - ['achi acho?', '', 'achi acho'], - [('achi acho?', 'ÊŒtʃɪ ÊŒtʃʊ '), ('achi acho', u'ÊŒtʃɪ ÊŒtʃʊ ')]), - ('segments', False, True, True, - ['achi acho?', '', 'achi acho'], - [('achi acho?', 'ÊŒtʃɪ ÊŒtʃʊ? '), ('achi acho', u'ÊŒtʃɪ ÊŒtʃʊ ')]), - ('segments', True, False, True, - ['achi acho?', '', 'achi acho'], - [('achi acho?', u'ÊŒtʃɪ ÊŒtʃʊ '), ('', ''), ('achi acho', u'ÊŒtʃɪ ÊŒtʃʊ ')]), - ('segments', True, True, True, - ['achi acho?', '', 'achi acho'], - [('achi acho?', u'ÊŒtʃɪ ÊŒtʃʊ? '), ('', ''), ('achi acho', u'ÊŒtʃɪ ÊŒtʃʊ ')]), - ('festival', False, False, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hhaxlow werld '), ('goodbye', 'guhdbay ')]), - ('festival', False, True, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hhaxlow werld! '), ('goodbye', 'guhdbay ')]), - ('festival', True, False, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hhaxlow werld '), ('', ''), ('goodbye', 'guhdbay ')]), - ('festival', True, True, True, - ['hello world!', '', 'goodbye'], - [('hello world!', 'hhaxlow werld! '), ('', ''), ('goodbye', 'guhdbay ')])]) -def test_preserve_empty_lines(backend, empty_lines, punctuation, prepend_text, text, expected): - language = 'cree' if backend == 'segments' else 'en-us' - - assert expected == phonemize( - text, language=language, backend=backend, prepend_text=prepend_text, - preserve_punctuation=punctuation, preserve_empty_lines=empty_lines) - - -@pytest.mark.parametrize( - 'backend, empty_lines, punctuation, text, expected', [ - ('espeak', False, False, [''], []), - ('espeak', False, True, [''], []), - ('espeak', True, False, [''], ['']), - ('espeak', True, True, [''], ['']), - ('segments', False, False, [''], []), - ('segments', False, True, [''], []), - ('segments', True, False, [''], ['']), - ('segments', True, True, [''], ['']), - ('festival', False, False, [''], []), - ('festival', False, True, [''], []), - ('festival', True, False, [''], ['']), - ('festival', True, True, [''], [''])]) -def test_empty_input(backend, empty_lines, punctuation, text, expected): - language = 'cree' if backend == 'segments' else 'en-us' - - assert expected == phonemize( - text, language=language, backend=backend, - preserve_punctuation=punctuation, preserve_empty_lines=empty_lines) diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_punctuation.py b/extensions/.local/lib/python3.11/site-packages/test/test_punctuation.py deleted file mode 100644 index 7c31ee1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_punctuation.py +++ /dev/null @@ -1,274 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the punctuation processing""" - -# pylint: disable=missing-docstring -from pathlib import Path - -import pytest -import re - -from phonemizer.backend import EspeakBackend, FestivalBackend, SegmentsBackend -from phonemizer.punctuation import Punctuation -from phonemizer.phonemize import phonemize -from phonemizer.separator import Separator, default_separator - -# True if we are using espeak>=1.50 -ESPEAK_150 = (EspeakBackend.version() >= (1, 50)) - -# True if we are using espeak>=1.49.3 -ESPEAK_149 = (EspeakBackend.version() >= (1, 49, 3)) - -# True if we are using festival>=2.5 -FESTIVAL_25 = (FestivalBackend.version() >= (2, 5)) - - -@pytest.mark.parametrize( - 'inp, out', [ - ('a, b,c.', 'a b c'), - ('abc de', 'abc de'), - ('!d.d. dd?? d!', 'd d dd d')]) -def test_remove(inp, out): - assert Punctuation().remove(inp) == out - - -@pytest.mark.parametrize( - 'inp', [ - ['.a.b.c.'], - ['a, a?', 'b, b'], - ['a, a?', 'b, b', '!'], - ['a, a?', '!?', 'b, b'], - ['!?', 'a, a?', 'b, b'], - ['a, a, a'], - ['a, a?', 'aaa bb', '.bb, b', 'c', '!d.d. dd?? d!'], - ['Truly replied, "Yes".'], - ['hi; ho,"'], - ["!?"], - ["!'"], - ["It is ! (I think so)"], - ["This {is} right"], - ["[He] is right"], - ]) -def test_preserve(inp): - punct = Punctuation() - text, marks = punct.preserve(inp) - assert inp == punct.restore(text, marks, sep=default_separator, strip=True) - - -@pytest.mark.parametrize( - 'text, expected_restore, expected_output', [ - (['hi; hi,"'], ['hi; hi," '], ['haɪ; haɪ, ']), - (['hi; "hi,'], ['hi; "hi, '], ['haɪ; haɪ, '] if ESPEAK_149 else ['haɪ; haɪ, ']), - (['"hi; hi,'], ['"hi; hi, '], ['haɪ; haɪ, '] if ESPEAK_149 else [' haɪ; haɪ, '])]) -def test_preserve_2(text, expected_restore, expected_output): - marks = ".!;:,?" - punct = Punctuation(marks=marks) - assert expected_restore == punct.restore( - *punct.preserve(text), sep=default_separator, strip=False) - - output = phonemize( - text, backend="espeak", - preserve_punctuation=True, punctuation_marks=marks) - assert output == expected_output - - -def test_custom(): - punct = Punctuation() - assert set(punct.marks) == set(punct.default_marks()) - assert punct.remove('a,b.c') == 'a b c' - - with pytest.raises(ValueError): - punct.marks = ['?', '.'] - punct.marks = '?.' - assert len(punct.marks) == 2 - assert punct.remove('a,b.c') == 'a,b c' - - -def test_espeak(): - text = 'hello, world!' - expected1 = 'hÉ™loÊŠ wÉœËld' - expected2 = 'hÉ™loÊŠ, wÉœËld!' - expected3 = 'hÉ™loÊŠ wÉœËld ' - expected4 = 'hÉ™loÊŠ, wÉœËld! ' - - out1 = EspeakBackend('en-us', preserve_punctuation=False).phonemize( - [text], strip=True)[0] - assert out1 == expected1 - - out2 = EspeakBackend('en-us', preserve_punctuation=True).phonemize( - [text], strip=True)[0] - assert out2 == expected2 - - out3 = EspeakBackend('en-us', preserve_punctuation=False).phonemize( - [text], strip=False)[0] - assert out3 == expected3 - - out4 = EspeakBackend('en-us', preserve_punctuation=True).phonemize( - [text], strip=False)[0] - assert out4 == expected4 - - -def test_festival(): - text = 'hello, world!' - expected1 = 'hhaxlow werld' - expected2 = 'hhaxlow, werld!' - expected3 = 'hhaxlow werld ' - expected4 = 'hhaxlow, werld! ' - - out1 = FestivalBackend('en-us', preserve_punctuation=False).phonemize( - [text], strip=True)[0] - assert out1 == expected1 - - out2 = FestivalBackend('en-us', preserve_punctuation=True).phonemize( - [text], strip=True)[0] - assert out2 == expected2 - - out3 = FestivalBackend('en-us', preserve_punctuation=False).phonemize( - [text], strip=False)[0] - assert out3 == expected3 - - out4 = FestivalBackend('en-us', preserve_punctuation=True).phonemize( - [text], strip=False)[0] - assert out4 == expected4 - - -def test_segments(): - text = 'achi, acho!' - expected1 = 'ÊŒtʃɪ ÊŒtʃʊ' - expected2 = 'ÊŒtʃɪ, ÊŒtʃʊ!' - expected3 = 'ÊŒtʃɪ ÊŒtʃʊ ' - expected4 = 'ÊŒtʃɪ, ÊŒtʃʊ! ' - - out1 = SegmentsBackend('cree', preserve_punctuation=False).phonemize( - [text], strip=True)[0] - assert out1 == expected1 - - out2 = SegmentsBackend('cree', preserve_punctuation=True).phonemize( - [text], strip=True)[0] - assert out2 == expected2 - - out3 = SegmentsBackend('cree', preserve_punctuation=False).phonemize( - [text], strip=False)[0] - assert out3 == expected3 - - out4 = SegmentsBackend('cree', preserve_punctuation=True).phonemize( - [text], strip=False)[0] - assert out4 == expected4 - - -# see https://github.com/bootphon/phonemizer/issues/54 -@pytest.mark.parametrize( - 'text, expected', [("!'", "! "), ("'!", "! "), ("!'!", "!! "), ("'!'", "! ")]) -def test_issue_54(text, expected): - output = phonemize( - [text], language='en-us', backend='espeak', - preserve_punctuation=True)[0] - assert expected == output - - -# see https://github.com/bootphon/phonemizer/issues/55 -@pytest.mark.parametrize( - 'backend, marks, text, expected', [ - ('espeak', 'default', ['"Hey! "', '"hey,"'], ['"heɪ! " ', '"heɪ," ']), - ('espeak', '.!;:,?', ['"Hey! " ', '"hey," '], - ['heɪ! ', 'heɪ, '] if ESPEAK_150 else [' heɪ! ', ' heɪ, ']), - ('espeak', 'default', ['! ?', 'hey!'], ['! ? ', 'heɪ! ']), - ('espeak', '!', ['! ?', 'hey!'], ['! ', 'heɪ! ']), - ('segments', 'default', ['! ?', 'hey!'], ['! ? ', 'heËj! ']), - ('segments', '!', ['! ?', 'hey!'], ValueError), - ('festival', 'default', ['! ?', 'hey!'], ['! ? ', 'hhey! ']), - ('festival', '!', ['! ?', 'hey!'], ['! ', 'hhey! '])]) -def test_issue55(backend, marks, text, expected): - if marks == 'default': - marks = Punctuation.default_marks() - language = 'cree' if backend == 'segments' else 'en-us' - - try: - with pytest.raises(expected): - phonemize( - text, language=language, backend=backend, - preserve_punctuation=True, punctuation_marks=marks) - except TypeError: - try: - assert expected == phonemize( - text, language=language, backend=backend, - preserve_punctuation=True, punctuation_marks=marks) - except RuntimeError: - if backend == 'festival': - # TODO on some installations festival fails to phonemize "?". - # It ends with a segmentation fault. This seems to only appear - # with festival-2.5 (but is working on travis and docker image) - pass - - -@pytest.mark.parametrize( - 'punctuation_marks, text, expected', [ - (';:,.!?¡—…"«»“â€', - 'hello, ,world? ‡ 3,000, or 2.50. ¿hello?', - 'hÉ™loÊŠ, ,wÉœËld? θɹiË,ziəɹoÊŠziəɹoÊŠ ziəɹoÊŠ, É”Ëɹ tuË.fɪfti. hÉ™loÊŠ? '), - (re.compile(r"[^a-zA-ZÀ-ÖØ-öø-ÿ0-9'$@&+%\-=/\\]"), - 'hello, ,world? ‡ 3,000, or 2.50. ¿hello?', - 'hÉ™loÊŠ, ,wÉœËld? ‡ θɹiË,ziəɹoÊŠziəɹoÊŠ ziəɹoÊŠ, É”Ëɹ tuË.fɪfti. ¿hÉ™loÊŠ? '), - (re.compile(r"[^a-zA-ZÀ-ÖØ-öø-ÿ0-9',.$@&+%\-=/\\]|[,.](?!\d)"), - 'hello, ,world? ‡ 3,000, or 2.50. ¿hello?', - 'hÉ™loÊŠ, ,wÉœËld? ‡ θɹiË Î¸aÊŠzÉ™nd, É”Ëɹ tuË pɔɪnt faɪv ziəɹoÊŠ. ¿hÉ™loÊŠ? ') - ]) -def test_punctuation_marks_regex(punctuation_marks, text, expected): - assert expected == phonemize( - text, preserve_punctuation=True, punctuation_marks=punctuation_marks) - - -def test_marks_getter_with_regex(): - marks_re = re.compile(r"[^a-zA-Z0-9]") - punct = Punctuation(marks_re) - with pytest.raises(ValueError): - punct.marks == marks_re - - -def test_long_document(): - # testing issue raised by #108 - DATA_FOLDER = Path(__file__).parent / "data" - with open(DATA_FOLDER / "pg67147.txt") as txt_file: - phonemize(txt_file.read().split("\n"), backend="espeak", preserve_punctuation=True) - - -@pytest.mark.parametrize( - 'text', [ - ([ - 'worked david ford i started in deloitte and i was immediately', - ] - ), - ([ - 'worked david ford i started in deloitte, and i was immediately', - ] - ), - ([ - 'worked david ford i started in deloitte and i was immediately', - 'an offer of price waterhouse cooper and here i take may', - 'we are now as maximum plan for a customer time and', - "they're going to meet all the xvin so great it" - ] - ), - ([ - 'worked david ford i started in deloitte, and i was immediately', - 'an offer of price waterhouse cooper and here i take may', - 'we are now as maximum plan for a customer time and', - "they're going to meet all the xvin so great it." - ] - ), - ]) -def test_multiline_punctuation(text): - phonemized = phonemize(text, preserve_punctuation=True) - assert len(text) == len(phonemized) diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_segments.py b/extensions/.local/lib/python3.11/site-packages/test/test_segments.py deleted file mode 100644 index 9461cdf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_segments.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015-2021 Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the segments backend""" - -# pylint: disable=missing-docstring - -import os -import pytest - -from phonemizer.separator import Separator, default_separator -from phonemizer.backend import SegmentsBackend -from phonemizer.utils import get_package_resource - - -def test_multiline(): - backend = SegmentsBackend('cree') - assert backend.language == 'cree' - - assert backend.phonemize(['a']) == [u'ÊŒ '] - assert backend.phonemize(['aa']) == [u'ʌʌ '] - assert backend.phonemize(['a\n']) == [u'ÊŒ '] - assert backend.phonemize(['a\na']) == [u'ÊŒ ÊŒ '] - assert backend.phonemize(['a\na\n']) == [u'ÊŒ ÊŒ '] - assert backend.phonemize(['a', 'a']) == [u'ÊŒ ', 'ÊŒ '] - assert backend.phonemize(['a\n', 'a\n']) == [u'ÊŒ ', 'ÊŒ '] - - -def test_bad_morpheme(): - backend = SegmentsBackend('cree') - with pytest.raises(ValueError): - backend.phonemize(['A']) - - -def test_separator(): - backend = SegmentsBackend('cree') - text = ['achi acho'] - - sep = default_separator - assert backend.phonemize(text, separator=sep) == [u'ÊŒtʃɪ ÊŒtʃʊ '] - assert backend.phonemize(text, separator=sep, strip=True) == [u'ÊŒtʃɪ ÊŒtʃʊ'] - - -def test_separator_2(): - backend = SegmentsBackend('cree') - text = ['achi acho'] - - sep = Separator(word='_', phone=' ') - assert backend.phonemize(text, separator=sep) == [u'ÊŒ tʃ ɪ _ÊŒ tʃ ÊŠ _'] - assert backend.phonemize(text, separator=sep, strip=True) \ - == [u'ÊŒ tʃ ɪ_ÊŒ tʃ ÊŠ'] - - -def test_separator_3(): - backend = SegmentsBackend('cree') - text = ['achi acho'] - - sep = Separator(word=' ', syllable=None, phone='_') - assert backend.phonemize(text, separator=sep) == [u'ÊŒ_tʃ_ɪ_ ÊŒ_tʃ_ÊŠ_ '] - assert backend.phonemize(text, separator=sep, strip=True) \ - == [u'ÊŒ_tʃ_ɪ ÊŒ_tʃ_ÊŠ'] - - -def test_separator_4(): - backend = SegmentsBackend('cree') - text = ['achi acho'] - - # TODO bug when sep.phone == ' ' with no sep.word - sep = Separator(phone=' ', word='') - assert backend.phonemize(text, separator=sep) == [u'ÊŒ tʃ ɪ ÊŒ tʃ ÊŠ '] - assert backend.phonemize(text, separator=sep, strip=True) \ - == [u'ÊŒ tʃ ɪʌ tʃ ÊŠ'] - - -def test_separator_5(): - backend = SegmentsBackend('cree') - text = ['achi acho'] - - sep = Separator(phone=' ', word='_') - assert backend.phonemize(text, separator=sep) == [u'ÊŒ tʃ ɪ _ÊŒ tʃ ÊŠ _'] - assert backend.phonemize(text, separator=sep, strip=True) \ - == [u'ÊŒ tʃ ɪ_ÊŒ tʃ ÊŠ'] - - -def test_language(tmpdir): - # check languages by name - assert SegmentsBackend.is_supported_language('cree') - assert not SegmentsBackend.is_supported_language('unexisting') - - # check languages by g2p file - directory = get_package_resource('segments') - assert SegmentsBackend.is_supported_language( - os.path.join(directory, 'cree.g2p')) - assert not SegmentsBackend.is_supported_language( - os.path.join(directory, 'cree')) - assert not SegmentsBackend.is_supported_language( - os.path.join(directory, 'unexisting.g2p')) - - # bad syntax in g2p file - g2p = tmpdir.join('foo.g2p') - g2p.write('\n'.join(['a a', 'b b b', 'c'])) - assert not SegmentsBackend.is_supported_language(g2p) diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_separator.py b/extensions/.local/lib/python3.11/site-packages/test/test_separator.py deleted file mode 100644 index 050c48f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_separator.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2015-2021 Thomas Schatz, Xuan Nga Cao, Mathieu Bernard -# -# This file is part of phonemizer: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Phonemizer is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with phonemizer. If not, see . -"""Test of the Separator class""" - -# pylint: disable=missing-docstring - -import pytest - -from phonemizer.separator import Separator, default_separator - - -def test_prop(): - # read only attributes - with pytest.raises(AttributeError): - default_separator.phone = 'a' - - with pytest.raises(AttributeError): - default_separator.syllable = 'a' - - with pytest.raises(AttributeError): - default_separator.word = 'a' - - -@pytest.mark.parametrize('val', [None, '', False]) -def test_empty(val): - s = Separator(val, val, val) - assert s.phone == '' - assert s.syllable == '' - assert s.word == '' - - -def test_same(): - with pytest.raises(ValueError): - Separator(word=' ', phone=' ') - - -def test_str(): - separator = Separator(word='w', syllable='s', phone='p') - assert str(separator) == '(phone: "p", syllable: "s", word: "w")' - assert str(default_separator) == '(phone: "", syllable: "", word: " ")' - - -def test_equal(): - assert Separator() == Separator() - assert default_separator == Separator(phone='', syllable='', word=' ') - assert Separator(word=' ') != default_separator - - -def test_field_separator(): - sep = Separator(word='w', syllable='s', phone='p') - assert 'w' in sep - assert 'p' in sep - assert 'wp' not in sep - assert ' ' not in sep - - assert sep.input_output_separator(False) is False - assert sep.input_output_separator(None) is False - assert sep.input_output_separator('') is False - assert sep.input_output_separator(True) == '|' - assert sep.input_output_separator('io') == 'io' - - with pytest.raises(RuntimeError) as err: - sep.input_output_separator([1, 2]) - assert 'invalid input/output separator' in str(err) - with pytest.raises(RuntimeError) as err: - sep.input_output_separator('w') - assert 'cannot prepend input with "w"' in str(err) - - sep = Separator(phone='|', syllable='||', word='|||') - assert sep.input_output_separator(True) == '||||' diff --git a/extensions/.local/lib/python3.11/site-packages/test/test_utils.py b/extensions/.local/lib/python3.11/site-packages/test/test_utils.py deleted file mode 100644 index 1f8bb86..0000000 --- a/extensions/.local/lib/python3.11/site-packages/test/test_utils.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Test of the phonemizer.utils module""" - -# pylint: disable=missing-docstring -import os - -from phonemizer.utils import chunks, cumsum, str2list, list2str - - -def test_cumsum(): - assert cumsum([]) == [] - assert cumsum([0]) == [0] - assert cumsum([1, 2, 3]) == [1, 3, 6] - - -def test_list2str(): - assert list2str('') == '' - assert list2str([]) == '' - assert list2str(['']) == '' - assert list2str(['abc']) == 'abc' - assert list2str(['a', 'b', 'c']) == os.linesep.join('abc') - - -def test_str2list(): - assert str2list('') == [''] - assert str2list('a') == ['a'] - assert str2list('ab') == ['ab'] - assert str2list('a b') == ['a b'] - assert str2list(f'a{os.linesep}b') == ['a', 'b'] - assert str2list( - f'a{os.linesep}{os.linesep}b{os.linesep}') == ['a', '', 'b'] - - -def test_chunks(): - for i in range(1, 5): - assert chunks(['a'], i) == ([['a']], [0]) - - assert chunks(['a', 'a'], 1) == ([['a', 'a']], [0]) - assert chunks(['a', 'a'], 2) == ([['a'], ['a']], [0, 1]) - assert chunks(['a', 'a'], 10) == ([['a'], ['a']], [0, 1]) - - assert chunks(['a', 'a', 'a'], 1) == ([['a', 'a', 'a']], [0]) - assert chunks(['a', 'a', 'a'], 2) == ([['a'], ['a', 'a']], [0, 1]) - assert chunks(['a', 'a', 'a'], 3) == ([['a'], ['a'], ['a']], [0, 1, 2]) - assert chunks(['a', 'a', 'a'], 10) == ([['a'], ['a'], ['a']], [0, 1, 2]) - - assert chunks(['a', 'a', 'a', 'a'], 1) == ([['a', 'a', 'a', 'a']], [0]) - assert chunks(['a', 'a', 'a', 'a'], 2) == ( - [['a', 'a'], ['a', 'a']], [0, 2]) - assert chunks(['a', 'a', 'a', 'a'], 3) == ( - [['a'], ['a'], ['a', 'a']], [0, 1, 2]) - assert chunks(['a', 'a', 'a', 'a'], 10) == ( - [['a'], ['a'], ['a'], ['a']], [0, 1, 2, 3]) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/LICENCE b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/LICENCE deleted file mode 100644 index a8922b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/LICENCE +++ /dev/null @@ -1,49 +0,0 @@ -`tqdm` is a product of collaborative work. -Unless otherwise stated, all authors (see commit logs) retain copyright -for their respective work, and release the work under the MIT licence -(text below). - -Exceptions or notable authors are listed below -in reverse chronological order: - -* files: * - MPL-2.0 2015-2024 (c) Casper da Costa-Luis - [casperdcl](https://github.com/casperdcl). -* files: tqdm/_tqdm.py - MIT 2016 (c) [PR #96] on behalf of Google Inc. -* files: tqdm/_tqdm.py README.rst .gitignore - MIT 2013 (c) Noam Yorav-Raphael, original author. - -[PR #96]: https://github.com/tqdm/tqdm/pull/96 - - -Mozilla Public Licence (MPL) v. 2.0 - Exhibit A ------------------------------------------------ - -This Source Code Form is subject to the terms of the -Mozilla Public License, v. 2.0. -If a copy of the MPL was not distributed with this project, -You can obtain one at https://mozilla.org/MPL/2.0/. - - -MIT License (MIT) ------------------ - -Copyright (c) 2013 noamraph - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/METADATA deleted file mode 100644 index 181b4dc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/METADATA +++ /dev/null @@ -1,1594 +0,0 @@ -Metadata-Version: 2.1 -Name: tqdm -Version: 4.67.1 -Summary: Fast, Extensible Progress Meter -Maintainer-email: tqdm developers -License: MPL-2.0 AND MIT -Project-URL: homepage, https://tqdm.github.io -Project-URL: repository, https://github.com/tqdm/tqdm -Project-URL: changelog, https://tqdm.github.io/releases -Project-URL: wiki, https://github.com/tqdm/tqdm/wiki -Keywords: progressbar,progressmeter,progress,bar,meter,rate,eta,console,terminal,time -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Environment :: MacOS X -Classifier: Environment :: Other Environment -Classifier: Environment :: Win32 (MS Windows) -Classifier: Environment :: X11 Applications -Classifier: Framework :: IPython -Classifier: Framework :: Jupyter -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: Intended Audience :: End Users/Desktop -Classifier: Intended Audience :: Other Audience -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: MIT License -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Operating System :: MacOS -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft -Classifier: Operating System :: Microsoft :: MS-DOS -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: POSIX -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: BSD :: FreeBSD -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: POSIX :: SunOS/Solaris -Classifier: Operating System :: Unix -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: Implementation -Classifier: Programming Language :: Python :: Implementation :: IronPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Unix Shell -Classifier: Topic :: Desktop Environment -Classifier: Topic :: Education :: Computer Aided Instruction (CAI) -Classifier: Topic :: Education :: Testing -Classifier: Topic :: Office/Business -Classifier: Topic :: Other/Nonlisted Topic -Classifier: Topic :: Software Development :: Build Tools -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Pre-processors -Classifier: Topic :: Software Development :: User Interfaces -Classifier: Topic :: System :: Installation/Setup -Classifier: Topic :: System :: Logging -Classifier: Topic :: System :: Monitoring -Classifier: Topic :: System :: Shells -Classifier: Topic :: Terminals -Classifier: Topic :: Utilities -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -License-File: LICENCE -Requires-Dist: colorama; platform_system == "Windows" -Provides-Extra: dev -Requires-Dist: pytest>=6; extra == "dev" -Requires-Dist: pytest-cov; extra == "dev" -Requires-Dist: pytest-timeout; extra == "dev" -Requires-Dist: pytest-asyncio>=0.24; extra == "dev" -Requires-Dist: nbval; extra == "dev" -Provides-Extra: discord -Requires-Dist: requests; extra == "discord" -Provides-Extra: slack -Requires-Dist: slack-sdk; extra == "slack" -Provides-Extra: telegram -Requires-Dist: requests; extra == "telegram" -Provides-Extra: notebook -Requires-Dist: ipywidgets>=6; extra == "notebook" - -|Logo| - -tqdm -==== - -|Py-Versions| |Versions| |Conda-Forge-Status| |Docker| |Snapcraft| - -|Build-Status| |Coverage-Status| |Branch-Coverage-Status| |Codacy-Grade| |Libraries-Rank| |PyPI-Downloads| - -|LICENCE| |OpenHub-Status| |binder-demo| |awesome-python| - -``tqdm`` derives from the Arabic word *taqaddum* (تقدّم) which can mean "progress," -and is an abbreviation for "I love you so much" in Spanish (*te quiero demasiado*). - -Instantly make your loops show a smart progress meter - just wrap any -iterable with ``tqdm(iterable)``, and you're done! - -.. code:: python - - from tqdm import tqdm - for i in tqdm(range(10000)): - ... - -``76%|████████████████████████        | 7568/10000 [00:33<00:10, 229.00it/s]`` - -``trange(N)`` can be also used as a convenient shortcut for -``tqdm(range(N))``. - -|Screenshot| - |Video| |Slides| |Merch| - -It can also be executed as a module with pipes: - -.. code:: sh - - $ seq 9999999 | tqdm --bytes | wc -l - 75.2MB [00:00, 217MB/s] - 9999999 - - $ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \ - > backup.tgz - 32%|██████████■| 8.89G/27.9G [00:42<01:31, 223MB/s] - -Overhead is low -- about 60ns per iteration (80ns with ``tqdm.gui``), and is -unit tested against performance regression. -By comparison, the well-established -`ProgressBar `__ has -an 800ns/iter overhead. - -In addition to its low overhead, ``tqdm`` uses smart algorithms to predict -the remaining time and to skip unnecessary iteration displays, which allows -for a negligible overhead in most cases. - -``tqdm`` works on any platform -(Linux, Windows, Mac, FreeBSD, NetBSD, Solaris/SunOS), -in any console or in a GUI, and is also friendly with IPython/Jupyter notebooks. - -``tqdm`` does not require any dependencies (not even ``curses``!), just -Python and an environment supporting ``carriage return \r`` and -``line feed \n`` control characters. - ------------------------------------------- - -.. contents:: Table of contents - :backlinks: top - :local: - - -Installation ------------- - -Latest PyPI stable release -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -|Versions| |PyPI-Downloads| |Libraries-Dependents| - -.. code:: sh - - pip install tqdm - -Latest development release on GitHub -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -|GitHub-Status| |GitHub-Stars| |GitHub-Commits| |GitHub-Forks| |GitHub-Updated| - -Pull and install pre-release ``devel`` branch: - -.. code:: sh - - pip install "git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm" - -Latest Conda release -~~~~~~~~~~~~~~~~~~~~ - -|Conda-Forge-Status| - -.. code:: sh - - conda install -c conda-forge tqdm - -Latest Snapcraft release -~~~~~~~~~~~~~~~~~~~~~~~~ - -|Snapcraft| - -There are 3 channels to choose from: - -.. code:: sh - - snap install tqdm # implies --stable, i.e. latest tagged release - snap install tqdm --candidate # master branch - snap install tqdm --edge # devel branch - -Note that ``snap`` binaries are purely for CLI use (not ``import``-able), and -automatically set up ``bash`` tab-completion. - -Latest Docker release -~~~~~~~~~~~~~~~~~~~~~ - -|Docker| - -.. code:: sh - - docker pull tqdm/tqdm - docker run -i --rm tqdm/tqdm --help - -Other -~~~~~ - -There are other (unofficial) places where ``tqdm`` may be downloaded, particularly for CLI use: - -|Repology| - -.. |Repology| image:: https://repology.org/badge/tiny-repos/python:tqdm.svg - :target: https://repology.org/project/python:tqdm/versions - -Changelog ---------- - -The list of all changes is available either on GitHub's Releases: -|GitHub-Status|, on the -`wiki `__, or on the -`website `__. - - -Usage ------ - -``tqdm`` is very versatile and can be used in a number of ways. -The three main ones are given below. - -Iterable-based -~~~~~~~~~~~~~~ - -Wrap ``tqdm()`` around any iterable: - -.. code:: python - - from tqdm import tqdm - from time import sleep - - text = "" - for char in tqdm(["a", "b", "c", "d"]): - sleep(0.25) - text = text + char - -``trange(i)`` is a special optimised instance of ``tqdm(range(i))``: - -.. code:: python - - from tqdm import trange - - for i in trange(100): - sleep(0.01) - -Instantiation outside of the loop allows for manual control over ``tqdm()``: - -.. code:: python - - pbar = tqdm(["a", "b", "c", "d"]) - for char in pbar: - sleep(0.25) - pbar.set_description("Processing %s" % char) - -Manual -~~~~~~ - -Manual control of ``tqdm()`` updates using a ``with`` statement: - -.. code:: python - - with tqdm(total=100) as pbar: - for i in range(10): - sleep(0.1) - pbar.update(10) - -If the optional variable ``total`` (or an iterable with ``len()``) is -provided, predictive stats are displayed. - -``with`` is also optional (you can just assign ``tqdm()`` to a variable, -but in this case don't forget to ``del`` or ``close()`` at the end: - -.. code:: python - - pbar = tqdm(total=100) - for i in range(10): - sleep(0.1) - pbar.update(10) - pbar.close() - -Module -~~~~~~ - -Perhaps the most wonderful use of ``tqdm`` is in a script or on the command -line. Simply inserting ``tqdm`` (or ``python -m tqdm``) between pipes will pass -through all ``stdin`` to ``stdout`` while printing progress to ``stderr``. - -The example below demonstrate counting the number of lines in all Python files -in the current directory, with timing information included. - -.. code:: sh - - $ time find . -name '*.py' -type f -exec cat \{} \; | wc -l - 857365 - - real 0m3.458s - user 0m0.274s - sys 0m3.325s - - $ time find . -name '*.py' -type f -exec cat \{} \; | tqdm | wc -l - 857366it [00:03, 246471.31it/s] - 857365 - - real 0m3.585s - user 0m0.862s - sys 0m3.358s - -Note that the usual arguments for ``tqdm`` can also be specified. - -.. code:: sh - - $ find . -name '*.py' -type f -exec cat \{} \; | - tqdm --unit loc --unit_scale --total 857366 >> /dev/null - 100%|█████████████████████████████████| 857K/857K [00:04<00:00, 246Kloc/s] - -Backing up a large directory? - -.. code:: sh - - $ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \ - > backup.tgz - 44%|██████████████▊ | 153M/352M [00:14<00:18, 11.0MB/s] - -This can be beautified further: - -.. code:: sh - - $ BYTES=$(du -sb docs/ | cut -f1) - $ tar -cf - docs/ \ - | tqdm --bytes --total "$BYTES" --desc Processing | gzip \ - | tqdm --bytes --total "$BYTES" --desc Compressed --position 1 \ - > ~/backup.tgz - Processing: 100%|██████████████████████| 352M/352M [00:14<00:00, 30.2MB/s] - Compressed: 42%|█████████▎ | 148M/352M [00:14<00:19, 10.9MB/s] - -Or done on a file level using 7-zip: - -.. code:: sh - - $ 7z a -bd -r backup.7z docs/ | grep Compressing \ - | tqdm --total $(find docs/ -type f | wc -l) --unit files \ - | grep -v Compressing - 100%|██████████████████████████▉| 15327/15327 [01:00<00:00, 712.96files/s] - -Pre-existing CLI programs already outputting basic progress information will -benefit from ``tqdm``'s ``--update`` and ``--update_to`` flags: - -.. code:: sh - - $ seq 3 0.1 5 | tqdm --total 5 --update_to --null - 100%|████████████████████████████████████| 5.0/5 [00:00<00:00, 9673.21it/s] - $ seq 10 | tqdm --update --null # 1 + 2 + ... + 10 = 55 iterations - 55it [00:00, 90006.52it/s] - -FAQ and Known Issues --------------------- - -|GitHub-Issues| - -The most common issues relate to excessive output on multiple lines, instead -of a neat one-line progress bar. - -- Consoles in general: require support for carriage return (``CR``, ``\r``). - - * Some cloud logging consoles which don't support ``\r`` properly - (`cloudwatch `__, - `K8s `__) may benefit from - ``export TQDM_POSITION=-1``. - -- Nested progress bars: - - * Consoles in general: require support for moving cursors up to the - previous line. For example, - `IDLE `__, - `ConEmu `__ and - `PyCharm `__ (also - `here `__, - `here `__, and - `here `__) - lack full support. - * Windows: additionally may require the Python module ``colorama`` - to ensure nested bars stay within their respective lines. - -- Unicode: - - * Environments which report that they support unicode will have solid smooth - progressbars. The fallback is an ``ascii``-only bar. - * Windows consoles often only partially support unicode and thus - `often require explicit ascii=True `__ - (also `here `__). This is due to - either normal-width unicode characters being incorrectly displayed as - "wide", or some unicode characters not rendering. - -- Wrapping generators: - - * Generator wrapper functions tend to hide the length of iterables. - ``tqdm`` does not. - * Replace ``tqdm(enumerate(...))`` with ``enumerate(tqdm(...))`` or - ``tqdm(enumerate(x), total=len(x), ...)``. - The same applies to ``numpy.ndenumerate``. - * Replace ``tqdm(zip(a, b))`` with ``zip(tqdm(a), b)`` or even - ``zip(tqdm(a), tqdm(b))``. - * The same applies to ``itertools``. - * Some useful convenience functions can be found under ``tqdm.contrib``. - -- `No intermediate output in docker-compose `__: - use ``docker-compose run`` instead of ``docker-compose up`` and ``tty: true``. - -- Overriding defaults via environment variables: - e.g. in CI/cloud jobs, ``export TQDM_MININTERVAL=5`` to avoid log spam. - This override logic is handled by the ``tqdm.utils.envwrap`` decorator - (useful independent of ``tqdm``). - -If you come across any other difficulties, browse and file |GitHub-Issues|. - -Documentation -------------- - -|Py-Versions| |README-Hits| (Since 19 May 2016) - -.. code:: python - - class tqdm(): - """ - Decorate an iterable object, returning an iterator which acts exactly - like the original iterable, but prints a dynamically updating - progressbar every time a value is requested. - """ - - @envwrap("TQDM_") # override defaults via env vars - def __init__(self, iterable=None, desc=None, total=None, leave=True, - file=None, ncols=None, mininterval=0.1, - maxinterval=10.0, miniters=None, ascii=None, disable=False, - unit='it', unit_scale=False, dynamic_ncols=False, - smoothing=0.3, bar_format=None, initial=0, position=None, - postfix=None, unit_divisor=1000, write_bytes=False, - lock_args=None, nrows=None, colour=None, delay=0): - -Parameters -~~~~~~~~~~ - -* iterable : iterable, optional - Iterable to decorate with a progressbar. - Leave blank to manually manage the updates. -* desc : str, optional - Prefix for the progressbar. -* total : int or float, optional - The number of expected iterations. If unspecified, - len(iterable) is used if possible. If float("inf") or as a last - resort, only basic progress statistics are displayed - (no ETA, no progressbar). - If ``gui`` is True and this parameter needs subsequent updating, - specify an initial arbitrary large positive number, - e.g. 9e9. -* leave : bool, optional - If [default: True], keeps all traces of the progressbar - upon termination of iteration. - If ``None``, will leave only if ``position`` is ``0``. -* file : ``io.TextIOWrapper`` or ``io.StringIO``, optional - Specifies where to output the progress messages - (default: sys.stderr). Uses ``file.write(str)`` and ``file.flush()`` - methods. For encoding, see ``write_bytes``. -* ncols : int, optional - The width of the entire output message. If specified, - dynamically resizes the progressbar to stay within this bound. - If unspecified, attempts to use environment width. The - fallback is a meter width of 10 and no limit for the counter and - statistics. If 0, will not print any meter (only stats). -* mininterval : float, optional - Minimum progress display update interval [default: 0.1] seconds. -* maxinterval : float, optional - Maximum progress display update interval [default: 10] seconds. - Automatically adjusts ``miniters`` to correspond to ``mininterval`` - after long display update lag. Only works if ``dynamic_miniters`` - or monitor thread is enabled. -* miniters : int or float, optional - Minimum progress display update interval, in iterations. - If 0 and ``dynamic_miniters``, will automatically adjust to equal - ``mininterval`` (more CPU efficient, good for tight loops). - If > 0, will skip display of specified number of iterations. - Tweak this and ``mininterval`` to get very efficient loops. - If your progress is erratic with both fast and slow iterations - (network, skipping items, etc) you should set miniters=1. -* ascii : bool or str, optional - If unspecified or False, use unicode (smooth blocks) to fill - the meter. The fallback is to use ASCII characters " 123456789#". -* disable : bool, optional - Whether to disable the entire progressbar wrapper - [default: False]. If set to None, disable on non-TTY. -* unit : str, optional - String that will be used to define the unit of each iteration - [default: it]. -* unit_scale : bool or int or float, optional - If 1 or True, the number of iterations will be reduced/scaled - automatically and a metric prefix following the - International System of Units standard will be added - (kilo, mega, etc.) [default: False]. If any other non-zero - number, will scale ``total`` and ``n``. -* dynamic_ncols : bool, optional - If set, constantly alters ``ncols`` and ``nrows`` to the - environment (allowing for window resizes) [default: False]. -* smoothing : float, optional - Exponential moving average smoothing factor for speed estimates - (ignored in GUI mode). Ranges from 0 (average speed) to 1 - (current/instantaneous speed) [default: 0.3]. -* bar_format : str, optional - Specify a custom bar string formatting. May impact performance. - [default: '{l_bar}{bar}{r_bar}'], where - l_bar='{desc}: {percentage:3.0f}%|' and - r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' - '{rate_fmt}{postfix}]' - Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, - percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, - rate, rate_fmt, rate_noinv, rate_noinv_fmt, - rate_inv, rate_inv_fmt, postfix, unit_divisor, - remaining, remaining_s, eta. - Note that a trailing ": " is automatically removed after {desc} - if the latter is empty. -* initial : int or float, optional - The initial counter value. Useful when restarting a progress - bar [default: 0]. If using float, consider specifying ``{n:.3f}`` - or similar in ``bar_format``, or specifying ``unit_scale``. -* position : int, optional - Specify the line offset to print this bar (starting from 0) - Automatic if unspecified. - Useful to manage multiple bars at once (eg, from threads). -* postfix : dict or ``*``, optional - Specify additional stats to display at the end of the bar. - Calls ``set_postfix(**postfix)`` if possible (dict). -* unit_divisor : float, optional - [default: 1000], ignored unless ``unit_scale`` is True. -* write_bytes : bool, optional - Whether to write bytes. If (default: False) will write unicode. -* lock_args : tuple, optional - Passed to ``refresh`` for intermediate output - (initialisation, iterating, and updating). -* nrows : int, optional - The screen height. If specified, hides nested bars outside this - bound. If unspecified, attempts to use environment height. - The fallback is 20. -* colour : str, optional - Bar colour (e.g. 'green', '#00ff00'). -* delay : float, optional - Don't display until [default: 0] seconds have elapsed. - -Extra CLI Options -~~~~~~~~~~~~~~~~~ - -* delim : chr, optional - Delimiting character [default: '\n']. Use '\0' for null. - N.B.: on Windows systems, Python converts '\n' to '\r\n'. -* buf_size : int, optional - String buffer size in bytes [default: 256] - used when ``delim`` is specified. -* bytes : bool, optional - If true, will count bytes, ignore ``delim``, and default - ``unit_scale`` to True, ``unit_divisor`` to 1024, and ``unit`` to 'B'. -* tee : bool, optional - If true, passes ``stdin`` to both ``stderr`` and ``stdout``. -* update : bool, optional - If true, will treat input as newly elapsed iterations, - i.e. numbers to pass to ``update()``. Note that this is slow - (~2e5 it/s) since every input must be decoded as a number. -* update_to : bool, optional - If true, will treat input as total elapsed iterations, - i.e. numbers to assign to ``self.n``. Note that this is slow - (~2e5 it/s) since every input must be decoded as a number. -* null : bool, optional - If true, will discard input (no stdout). -* manpath : str, optional - Directory in which to install tqdm man pages. -* comppath : str, optional - Directory in which to place tqdm completion. -* log : str, optional - CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET. - -Returns -~~~~~~~ - -* out : decorated iterator. - -.. code:: python - - class tqdm(): - def update(self, n=1): - """ - Manually update the progress bar, useful for streams - such as reading files. - E.g.: - >>> t = tqdm(total=filesize) # Initialise - >>> for current_buffer in stream: - ... ... - ... t.update(len(current_buffer)) - >>> t.close() - The last line is highly recommended, but possibly not necessary if - ``t.update()`` will be called in such a way that ``filesize`` will be - exactly reached and printed. - - Parameters - ---------- - n : int or float, optional - Increment to add to the internal counter of iterations - [default: 1]. If using float, consider specifying ``{n:.3f}`` - or similar in ``bar_format``, or specifying ``unit_scale``. - - Returns - ------- - out : bool or None - True if a ``display()`` was triggered. - """ - - def close(self): - """Cleanup and (if leave=False) close the progressbar.""" - - def clear(self, nomove=False): - """Clear current bar display.""" - - def refresh(self): - """ - Force refresh the display of this bar. - - Parameters - ---------- - nolock : bool, optional - If ``True``, does not lock. - If [default: ``False``]: calls ``acquire()`` on internal lock. - lock_args : tuple, optional - Passed to internal lock's ``acquire()``. - If specified, will only ``display()`` if ``acquire()`` returns ``True``. - """ - - def unpause(self): - """Restart tqdm timer from last print time.""" - - def reset(self, total=None): - """ - Resets to 0 iterations for repeated use. - - Consider combining with ``leave=True``. - - Parameters - ---------- - total : int or float, optional. Total to use for the new bar. - """ - - def set_description(self, desc=None, refresh=True): - """ - Set/modify description of the progress bar. - - Parameters - ---------- - desc : str, optional - refresh : bool, optional - Forces refresh [default: True]. - """ - - def set_postfix(self, ordered_dict=None, refresh=True, **tqdm_kwargs): - """ - Set/modify postfix (additional stats) - with automatic formatting based on datatype. - - Parameters - ---------- - ordered_dict : dict or OrderedDict, optional - refresh : bool, optional - Forces refresh [default: True]. - kwargs : dict, optional - """ - - @classmethod - def write(cls, s, file=sys.stdout, end="\n"): - """Print a message via tqdm (without overlap with bars).""" - - @property - def format_dict(self): - """Public API for read-only member access.""" - - def display(self, msg=None, pos=None): - """ - Use ``self.sp`` to display ``msg`` in the specified ``pos``. - - Consider overloading this function when inheriting to use e.g.: - ``self.some_frontend(**self.format_dict)`` instead of ``self.sp``. - - Parameters - ---------- - msg : str, optional. What to display (default: ``repr(self)``). - pos : int, optional. Position to ``moveto`` - (default: ``abs(self.pos)``). - """ - - @classmethod - @contextmanager - def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs): - """ - stream : file-like object. - method : str, "read" or "write". The result of ``read()`` and - the first argument of ``write()`` should have a ``len()``. - - >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: - ... while True: - ... chunk = fobj.read(chunk_size) - ... if not chunk: - ... break - """ - - @classmethod - def pandas(cls, *targs, **tqdm_kwargs): - """Registers the current `tqdm` class with `pandas`.""" - - def trange(*args, **tqdm_kwargs): - """Shortcut for `tqdm(range(*args), **tqdm_kwargs)`.""" - -Convenience Functions -~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - def tqdm.contrib.tenumerate(iterable, start=0, total=None, - tqdm_class=tqdm.auto.tqdm, **tqdm_kwargs): - """Equivalent of `numpy.ndenumerate` or builtin `enumerate`.""" - - def tqdm.contrib.tzip(iter1, *iter2plus, **tqdm_kwargs): - """Equivalent of builtin `zip`.""" - - def tqdm.contrib.tmap(function, *sequences, **tqdm_kwargs): - """Equivalent of builtin `map`.""" - -Submodules -~~~~~~~~~~ - -.. code:: python - - class tqdm.notebook.tqdm(tqdm.tqdm): - """IPython/Jupyter Notebook widget.""" - - class tqdm.auto.tqdm(tqdm.tqdm): - """Automatically chooses beween `tqdm.notebook` and `tqdm.tqdm`.""" - - class tqdm.asyncio.tqdm(tqdm.tqdm): - """Asynchronous version.""" - @classmethod - def as_completed(cls, fs, *, loop=None, timeout=None, total=None, - **tqdm_kwargs): - """Wrapper for `asyncio.as_completed`.""" - - class tqdm.gui.tqdm(tqdm.tqdm): - """Matplotlib GUI version.""" - - class tqdm.tk.tqdm(tqdm.tqdm): - """Tkinter GUI version.""" - - class tqdm.rich.tqdm(tqdm.tqdm): - """`rich.progress` version.""" - - class tqdm.keras.TqdmCallback(keras.callbacks.Callback): - """Keras callback for epoch and batch progress.""" - - class tqdm.dask.TqdmCallback(dask.callbacks.Callback): - """Dask callback for task progress.""" - - -``contrib`` -+++++++++++ - -The ``tqdm.contrib`` package also contains experimental modules: - -- ``tqdm.contrib.itertools``: Thin wrappers around ``itertools`` -- ``tqdm.contrib.concurrent``: Thin wrappers around ``concurrent.futures`` -- ``tqdm.contrib.slack``: Posts to `Slack `__ bots -- ``tqdm.contrib.discord``: Posts to `Discord `__ bots -- ``tqdm.contrib.telegram``: Posts to `Telegram `__ bots -- ``tqdm.contrib.bells``: Automagically enables all optional features - - * ``auto``, ``pandas``, ``slack``, ``discord``, ``telegram`` - -Examples and Advanced Usage ---------------------------- - -- See the `examples `__ - folder; -- import the module and run ``help()``; -- consult the `wiki `__; - - * this has an - `excellent article `__ - on how to make a **great** progressbar; - -- check out the `slides from PyData London `__, or -- run the |binder-demo|. - -Description and additional stats -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Custom information can be displayed and updated dynamically on ``tqdm`` bars -with the ``desc`` and ``postfix`` arguments: - -.. code:: python - - from tqdm import tqdm, trange - from random import random, randint - from time import sleep - - with trange(10) as t: - for i in t: - # Description will be displayed on the left - t.set_description('GEN %i' % i) - # Postfix will be displayed on the right, - # formatted automatically based on argument's datatype - t.set_postfix(loss=random(), gen=randint(1,999), str='h', - lst=[1, 2]) - sleep(0.1) - - with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}", - postfix=["Batch", {"value": 0}]) as t: - for i in range(10): - sleep(0.1) - t.postfix[1]["value"] = i / 2 - t.update() - -Points to remember when using ``{postfix[...]}`` in the ``bar_format`` string: - -- ``postfix`` also needs to be passed as an initial argument in a compatible - format, and -- ``postfix`` will be auto-converted to a string if it is a ``dict``-like - object. To prevent this behaviour, insert an extra item into the dictionary - where the key is not a string. - -Additional ``bar_format`` parameters may also be defined by overriding -``format_dict``, and the bar itself may be modified using ``ascii``: - -.. code:: python - - from tqdm import tqdm - class TqdmExtraFormat(tqdm): - """Provides a `total_time` format parameter""" - @property - def format_dict(self): - d = super().format_dict - total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1) - d.update(total_time=self.format_interval(total_time) + " in total") - return d - - for i in TqdmExtraFormat( - range(9), ascii=" .oO0", - bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"): - if i == 4: - break - -.. code:: - - 00:00 in total: 44%|0000. | 4/9 [00:00<00:00, 962.93it/s] - -Note that ``{bar}`` also supports a format specifier ``[width][type]``. - -- ``width`` - - * unspecified (default): automatic to fill ``ncols`` - * ``int >= 0``: fixed width overriding ``ncols`` logic - * ``int < 0``: subtract from the automatic default - -- ``type`` - - * ``a``: ascii (``ascii=True`` override) - * ``u``: unicode (``ascii=False`` override) - * ``b``: blank (``ascii=" "`` override) - -This means a fixed bar with right-justified text may be created by using: -``bar_format="{l_bar}{bar:10}|{bar:-10b}right-justified"`` - -Nested progress bars -~~~~~~~~~~~~~~~~~~~~ - -``tqdm`` supports nested progress bars. Here's an example: - -.. code:: python - - from tqdm.auto import trange - from time import sleep - - for i in trange(4, desc='1st loop'): - for j in trange(5, desc='2nd loop'): - for k in trange(50, desc='3rd loop', leave=False): - sleep(0.01) - -For manual control over positioning (e.g. for multi-processing use), -you may specify ``position=n`` where ``n=0`` for the outermost bar, -``n=1`` for the next, and so on. -However, it's best to check if ``tqdm`` can work without manual ``position`` -first. - -.. code:: python - - from time import sleep - from tqdm import trange, tqdm - from multiprocessing import Pool, RLock, freeze_support - - L = list(range(9)) - - def progresser(n): - interval = 0.001 / (n + 2) - total = 5000 - text = f"#{n}, est. {interval * total:<04.2}s" - for _ in trange(total, desc=text, position=n): - sleep(interval) - - if __name__ == '__main__': - freeze_support() # for Windows support - tqdm.set_lock(RLock()) # for managing output contention - p = Pool(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),)) - p.map(progresser, L) - -Note that in Python 3, ``tqdm.write`` is thread-safe: - -.. code:: python - - from time import sleep - from tqdm import tqdm, trange - from concurrent.futures import ThreadPoolExecutor - - L = list(range(9)) - - def progresser(n): - interval = 0.001 / (n + 2) - total = 5000 - text = f"#{n}, est. {interval * total:<04.2}s" - for _ in trange(total, desc=text): - sleep(interval) - if n == 6: - tqdm.write("n == 6 completed.") - tqdm.write("`tqdm.write()` is thread-safe in py3!") - - if __name__ == '__main__': - with ThreadPoolExecutor() as p: - p.map(progresser, L) - -Hooks and callbacks -~~~~~~~~~~~~~~~~~~~ - -``tqdm`` can easily support callbacks/hooks and manual updates. -Here's an example with ``urllib``: - -**``urllib.urlretrieve`` documentation** - - | [...] - | If present, the hook function will be called once - | on establishment of the network connection and once after each block read - | thereafter. The hook will be passed three arguments; a count of blocks - | transferred so far, a block size in bytes, and the total size of the file. - | [...] - -.. code:: python - - import urllib, os - from tqdm import tqdm - urllib = getattr(urllib, 'request', urllib) - - class TqdmUpTo(tqdm): - """Provides `update_to(n)` which uses `tqdm.update(delta_n)`.""" - def update_to(self, b=1, bsize=1, tsize=None): - """ - b : int, optional - Number of blocks transferred so far [default: 1]. - bsize : int, optional - Size of each block (in tqdm units) [default: 1]. - tsize : int, optional - Total size (in tqdm units). If [default: None] remains unchanged. - """ - if tsize is not None: - self.total = tsize - return self.update(b * bsize - self.n) # also sets self.n = b * bsize - - eg_link = "https://caspersci.uk.to/matryoshka.zip" - with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1, - desc=eg_link.split('/')[-1]) as t: # all optional kwargs - urllib.urlretrieve(eg_link, filename=os.devnull, - reporthook=t.update_to, data=None) - t.total = t.n - -Inspired by `twine#242 `__. -Functional alternative in -`examples/tqdm_wget.py `__. - -It is recommend to use ``miniters=1`` whenever there is potentially -large differences in iteration speed (e.g. downloading a file over -a patchy connection). - -**Wrapping read/write methods** - -To measure throughput through a file-like object's ``read`` or ``write`` -methods, use ``CallbackIOWrapper``: - -.. code:: python - - from tqdm.auto import tqdm - from tqdm.utils import CallbackIOWrapper - - with tqdm(total=file_obj.size, - unit='B', unit_scale=True, unit_divisor=1024) as t: - fobj = CallbackIOWrapper(t.update, file_obj, "read") - while True: - chunk = fobj.read(chunk_size) - if not chunk: - break - t.reset() - # ... continue to use `t` for something else - -Alternatively, use the even simpler ``wrapattr`` convenience function, -which would condense both the ``urllib`` and ``CallbackIOWrapper`` examples -down to: - -.. code:: python - - import urllib, os - from tqdm import tqdm - - eg_link = "https://caspersci.uk.to/matryoshka.zip" - response = getattr(urllib, 'request', urllib).urlopen(eg_link) - with tqdm.wrapattr(open(os.devnull, "wb"), "write", - miniters=1, desc=eg_link.split('/')[-1], - total=getattr(response, 'length', None)) as fout: - for chunk in response: - fout.write(chunk) - -The ``requests`` equivalent is nearly identical: - -.. code:: python - - import requests, os - from tqdm import tqdm - - eg_link = "https://caspersci.uk.to/matryoshka.zip" - response = requests.get(eg_link, stream=True) - with tqdm.wrapattr(open(os.devnull, "wb"), "write", - miniters=1, desc=eg_link.split('/')[-1], - total=int(response.headers.get('content-length', 0))) as fout: - for chunk in response.iter_content(chunk_size=4096): - fout.write(chunk) - -**Custom callback** - -``tqdm`` is known for intelligently skipping unnecessary displays. To make a -custom callback take advantage of this, simply use the return value of -``update()``. This is set to ``True`` if a ``display()`` was triggered. - -.. code:: python - - from tqdm.auto import tqdm as std_tqdm - - def external_callback(*args, **kwargs): - ... - - class TqdmExt(std_tqdm): - def update(self, n=1): - displayed = super().update(n) - if displayed: - external_callback(**self.format_dict) - return displayed - -``asyncio`` -~~~~~~~~~~~ - -Note that ``break`` isn't currently caught by asynchronous iterators. -This means that ``tqdm`` cannot clean up after itself in this case: - -.. code:: python - - from tqdm.asyncio import tqdm - - async for i in tqdm(range(9)): - if i == 2: - break - -Instead, either call ``pbar.close()`` manually or use the context manager syntax: - -.. code:: python - - from tqdm.asyncio import tqdm - - with tqdm(range(9)) as pbar: - async for i in pbar: - if i == 2: - break - -Pandas Integration -~~~~~~~~~~~~~~~~~~ - -Due to popular demand we've added support for ``pandas`` -- here's an example -for ``DataFrame.progress_apply`` and ``DataFrameGroupBy.progress_apply``: - -.. code:: python - - import pandas as pd - import numpy as np - from tqdm import tqdm - - df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) - - # Register `pandas.progress_apply` and `pandas.Series.map_apply` with `tqdm` - # (can use `tqdm.gui.tqdm`, `tqdm.notebook.tqdm`, optional kwargs, etc.) - tqdm.pandas(desc="my bar!") - - # Now you can use `progress_apply` instead of `apply` - # and `progress_map` instead of `map` - df.progress_apply(lambda x: x**2) - # can also groupby: - # df.groupby(0).progress_apply(lambda x: x**2) - -In case you're interested in how this works (and how to modify it for your -own callbacks), see the -`examples `__ -folder or import the module and run ``help()``. - -Keras Integration -~~~~~~~~~~~~~~~~~ - -A ``keras`` callback is also available: - -.. code:: python - - from tqdm.keras import TqdmCallback - - ... - - model.fit(..., verbose=0, callbacks=[TqdmCallback()]) - -Dask Integration -~~~~~~~~~~~~~~~~ - -A ``dask`` callback is also available: - -.. code:: python - - from tqdm.dask import TqdmCallback - - with TqdmCallback(desc="compute"): - ... - arr.compute() - - # or use callback globally - cb = TqdmCallback(desc="global") - cb.register() - arr.compute() - -IPython/Jupyter Integration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -IPython/Jupyter is supported via the ``tqdm.notebook`` submodule: - -.. code:: python - - from tqdm.notebook import trange, tqdm - from time import sleep - - for i in trange(3, desc='1st loop'): - for j in tqdm(range(100), desc='2nd loop'): - sleep(0.01) - -In addition to ``tqdm`` features, the submodule provides a native Jupyter -widget (compatible with IPython v1-v4 and Jupyter), fully working nested bars -and colour hints (blue: normal, green: completed, red: error/interrupt, -light blue: no ETA); as demonstrated below. - -|Screenshot-Jupyter1| -|Screenshot-Jupyter2| -|Screenshot-Jupyter3| - -The ``notebook`` version supports percentage or pixels for overall width -(e.g.: ``ncols='100%'`` or ``ncols='480px'``). - -It is also possible to let ``tqdm`` automatically choose between -console or notebook versions by using the ``autonotebook`` submodule: - -.. code:: python - - from tqdm.autonotebook import tqdm - tqdm.pandas() - -Note that this will issue a ``TqdmExperimentalWarning`` if run in a notebook -since it is not meant to be possible to distinguish between ``jupyter notebook`` -and ``jupyter console``. Use ``auto`` instead of ``autonotebook`` to suppress -this warning. - -Note that notebooks will display the bar in the cell where it was created. -This may be a different cell from the one where it is used. -If this is not desired, either - -- delay the creation of the bar to the cell where it must be displayed, or -- create the bar with ``display=False``, and in a later cell call - ``display(bar.container)``: - -.. code:: python - - from tqdm.notebook import tqdm - pbar = tqdm(..., display=False) - -.. code:: python - - # different cell - display(pbar.container) - -The ``keras`` callback has a ``display()`` method which can be used likewise: - -.. code:: python - - from tqdm.keras import TqdmCallback - cbk = TqdmCallback(display=False) - -.. code:: python - - # different cell - cbk.display() - model.fit(..., verbose=0, callbacks=[cbk]) - -Another possibility is to have a single bar (near the top of the notebook) -which is constantly re-used (using ``reset()`` rather than ``close()``). -For this reason, the notebook version (unlike the CLI version) does not -automatically call ``close()`` upon ``Exception``. - -.. code:: python - - from tqdm.notebook import tqdm - pbar = tqdm() - -.. code:: python - - # different cell - iterable = range(100) - pbar.reset(total=len(iterable)) # initialise with new `total` - for i in iterable: - pbar.update() - pbar.refresh() # force print final status but don't `close()` - -Custom Integration -~~~~~~~~~~~~~~~~~~ - -To change the default arguments (such as making ``dynamic_ncols=True``), -simply use built-in Python magic: - -.. code:: python - - from functools import partial - from tqdm import tqdm as std_tqdm - tqdm = partial(std_tqdm, dynamic_ncols=True) - -For further customisation, -``tqdm`` may be inherited from to create custom callbacks (as with the -``TqdmUpTo`` example `above <#hooks-and-callbacks>`__) or for custom frontends -(e.g. GUIs such as notebook or plotting packages). In the latter case: - -1. ``def __init__()`` to call ``super().__init__(..., gui=True)`` to disable - terminal ``status_printer`` creation. -2. Redefine: ``close()``, ``clear()``, ``display()``. - -Consider overloading ``display()`` to use e.g. -``self.frontend(**self.format_dict)`` instead of ``self.sp(repr(self))``. - -Some submodule examples of inheritance: - -- `tqdm/notebook.py `__ -- `tqdm/gui.py `__ -- `tqdm/tk.py `__ -- `tqdm/contrib/slack.py `__ -- `tqdm/contrib/discord.py `__ -- `tqdm/contrib/telegram.py `__ - -Dynamic Monitor/Meter -~~~~~~~~~~~~~~~~~~~~~ - -You can use a ``tqdm`` as a meter which is not monotonically increasing. -This could be because ``n`` decreases (e.g. a CPU usage monitor) or ``total`` -changes. - -One example would be recursively searching for files. The ``total`` is the -number of objects found so far, while ``n`` is the number of those objects which -are files (rather than folders): - -.. code:: python - - from tqdm import tqdm - import os.path - - def find_files_recursively(path, show_progress=True): - files = [] - # total=1 assumes `path` is a file - t = tqdm(total=1, unit="file", disable=not show_progress) - if not os.path.exists(path): - raise IOError("Cannot find:" + path) - - def append_found_file(f): - files.append(f) - t.update() - - def list_found_dir(path): - """returns os.listdir(path) assuming os.path.isdir(path)""" - listing = os.listdir(path) - # subtract 1 since a "file" we found was actually this directory - t.total += len(listing) - 1 - # fancy way to give info without forcing a refresh - t.set_postfix(dir=path[-10:], refresh=False) - t.update(0) # may trigger a refresh - return listing - - def recursively_search(path): - if os.path.isdir(path): - for f in list_found_dir(path): - recursively_search(os.path.join(path, f)) - else: - append_found_file(path) - - recursively_search(path) - t.set_postfix(dir=path) - t.close() - return files - -Using ``update(0)`` is a handy way to let ``tqdm`` decide when to trigger a -display refresh to avoid console spamming. - -Writing messages -~~~~~~~~~~~~~~~~ - -This is a work in progress (see -`#737 `__). - -Since ``tqdm`` uses a simple printing mechanism to display progress bars, -you should not write any message in the terminal using ``print()`` while -a progressbar is open. - -To write messages in the terminal without any collision with ``tqdm`` bar -display, a ``.write()`` method is provided: - -.. code:: python - - from tqdm.auto import tqdm, trange - from time import sleep - - bar = trange(10) - for i in bar: - # Print using tqdm class method .write() - sleep(0.1) - if not (i % 3): - tqdm.write("Done task %i" % i) - # Can also use bar.write() - -By default, this will print to standard output ``sys.stdout``. but you can -specify any file-like object using the ``file`` argument. For example, this -can be used to redirect the messages writing to a log file or class. - -Redirecting writing -~~~~~~~~~~~~~~~~~~~ - -If using a library that can print messages to the console, editing the library -by replacing ``print()`` with ``tqdm.write()`` may not be desirable. -In that case, redirecting ``sys.stdout`` to ``tqdm.write()`` is an option. - -To redirect ``sys.stdout``, create a file-like class that will write -any input string to ``tqdm.write()``, and supply the arguments -``file=sys.stdout, dynamic_ncols=True``. - -A reusable canonical example is given below: - -.. code:: python - - from time import sleep - import contextlib - import sys - from tqdm import tqdm - from tqdm.contrib import DummyTqdmFile - - - @contextlib.contextmanager - def std_out_err_redirect_tqdm(): - orig_out_err = sys.stdout, sys.stderr - try: - sys.stdout, sys.stderr = map(DummyTqdmFile, orig_out_err) - yield orig_out_err[0] - # Relay exceptions - except Exception as exc: - raise exc - # Always restore sys.stdout/err if necessary - finally: - sys.stdout, sys.stderr = orig_out_err - - def some_fun(i): - print("Fee, fi, fo,".split()[i]) - - # Redirect stdout to tqdm.write() (don't forget the `as save_stdout`) - with std_out_err_redirect_tqdm() as orig_stdout: - # tqdm needs the original stdout - # and dynamic_ncols=True to autodetect console width - for i in tqdm(range(3), file=orig_stdout, dynamic_ncols=True): - sleep(.5) - some_fun(i) - - # After the `with`, printing is restored - print("Done!") - -Redirecting ``logging`` -~~~~~~~~~~~~~~~~~~~~~~~ - -Similar to ``sys.stdout``/``sys.stderr`` as detailed above, console ``logging`` -may also be redirected to ``tqdm.write()``. - -Warning: if also redirecting ``sys.stdout``/``sys.stderr``, make sure to -redirect ``logging`` first if needed. - -Helper methods are available in ``tqdm.contrib.logging``. For example: - -.. code:: python - - import logging - from tqdm import trange - from tqdm.contrib.logging import logging_redirect_tqdm - - LOG = logging.getLogger(__name__) - - if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - with logging_redirect_tqdm(): - for i in trange(9): - if i == 4: - LOG.info("console logging redirected to `tqdm.write()`") - # logging restored - -Monitoring thread, intervals and miniters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``tqdm`` implements a few tricks to increase efficiency and reduce overhead. - -- Avoid unnecessary frequent bar refreshing: ``mininterval`` defines how long - to wait between each refresh. ``tqdm`` always gets updated in the background, - but it will display only every ``mininterval``. -- Reduce number of calls to check system clock/time. -- ``mininterval`` is more intuitive to configure than ``miniters``. - A clever adjustment system ``dynamic_miniters`` will automatically adjust - ``miniters`` to the amount of iterations that fit into time ``mininterval``. - Essentially, ``tqdm`` will check if it's time to print without actually - checking time. This behaviour can be still be bypassed by manually setting - ``miniters``. - -However, consider a case with a combination of fast and slow iterations. -After a few fast iterations, ``dynamic_miniters`` will set ``miniters`` to a -large number. When iteration rate subsequently slows, ``miniters`` will -remain large and thus reduce display update frequency. To address this: - -- ``maxinterval`` defines the maximum time between display refreshes. - A concurrent monitoring thread checks for overdue updates and forces one - where necessary. - -The monitoring thread should not have a noticeable overhead, and guarantees -updates at least every 10 seconds by default. -This value can be directly changed by setting the ``monitor_interval`` of -any ``tqdm`` instance (i.e. ``t = tqdm.tqdm(...); t.monitor_interval = 2``). -The monitor thread may be disabled application-wide by setting -``tqdm.tqdm.monitor_interval = 0`` before instantiation of any ``tqdm`` bar. - - -Merch ------ - -You can buy `tqdm branded merch `__ now! - -Contributions -------------- - -|GitHub-Commits| |GitHub-Issues| |GitHub-PRs| |OpenHub-Status| |GitHub-Contributions| |CII Best Practices| - -All source code is hosted on `GitHub `__. -Contributions are welcome. - -See the -`CONTRIBUTING `__ -file for more information. - -Developers who have made significant contributions, ranked by *SLoC* -(surviving lines of code, -`git fame `__ ``-wMC --excl '\.(png|gif|jpg)$'``), -are: - -==================== ======================================================== ==== ================================ -Name ID SLoC Notes -==================== ======================================================== ==== ================================ -Casper da Costa-Luis `casperdcl `__ ~80% primary maintainer |Gift-Casper| -Stephen Larroque `lrq3000 `__ ~9% team member -Martin Zugnoni `martinzugnoni `__ ~3% -Daniel Ecer `de-code `__ ~2% -Richard Sheridan `richardsheridan `__ ~1% -Guangshuo Chen `chengs `__ ~1% -Helio Machado `0x2b3bfa0 `__ ~1% -Kyle Altendorf `altendky `__ <1% -Noam Yorav-Raphael `noamraph `__ <1% original author -Matthew Stevens `mjstevens777 `__ <1% -Hadrien Mary `hadim `__ <1% team member -Mikhail Korobov `kmike `__ <1% team member -==================== ======================================================== ==== ================================ - -Ports to Other Languages -~~~~~~~~~~~~~~~~~~~~~~~~ - -A list is available on -`this wiki page `__. - - -LICENCE -------- - -Open Source (OSI approved): |LICENCE| - -Citation information: |DOI| - -|README-Hits| (Since 19 May 2016) - -.. |Logo| image:: https://tqdm.github.io/img/logo.gif -.. |Screenshot| image:: https://tqdm.github.io/img/tqdm.gif -.. |Video| image:: https://tqdm.github.io/img/video.jpg - :target: https://tqdm.github.io/video -.. |Slides| image:: https://tqdm.github.io/img/slides.jpg - :target: https://tqdm.github.io/PyData2019/slides.html -.. |Merch| image:: https://tqdm.github.io/img/merch.jpg - :target: https://tqdm.github.io/merch -.. |Build-Status| image:: https://img.shields.io/github/actions/workflow/status/tqdm/tqdm/test.yml?branch=master&label=tqdm&logo=GitHub - :target: https://github.com/tqdm/tqdm/actions/workflows/test.yml -.. |Coverage-Status| image:: https://img.shields.io/coveralls/github/tqdm/tqdm/master?logo=coveralls - :target: https://coveralls.io/github/tqdm/tqdm -.. |Branch-Coverage-Status| image:: https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg - :target: https://codecov.io/gh/tqdm/tqdm -.. |Codacy-Grade| image:: https://app.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177 - :target: https://www.codacy.com/gh/tqdm/tqdm/dashboard -.. |CII Best Practices| image:: https://bestpractices.coreinfrastructure.org/projects/3264/badge - :target: https://bestpractices.coreinfrastructure.org/projects/3264 -.. |GitHub-Status| image:: https://img.shields.io/github/tag/tqdm/tqdm.svg?maxAge=86400&logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/releases -.. |GitHub-Forks| image:: https://img.shields.io/github/forks/tqdm/tqdm.svg?logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/network -.. |GitHub-Stars| image:: https://img.shields.io/github/stars/tqdm/tqdm.svg?logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/stargazers -.. |GitHub-Commits| image:: https://img.shields.io/github/commit-activity/y/tqdm/tqdm.svg?logo=git&logoColor=white - :target: https://github.com/tqdm/tqdm/graphs/commit-activity -.. |GitHub-Issues| image:: https://img.shields.io/github/issues-closed/tqdm/tqdm.svg?logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/issues?q= -.. |GitHub-PRs| image:: https://img.shields.io/github/issues-pr-closed/tqdm/tqdm.svg?logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/pulls -.. |GitHub-Contributions| image:: https://img.shields.io/github/contributors/tqdm/tqdm.svg?logo=github&logoColor=white - :target: https://github.com/tqdm/tqdm/graphs/contributors -.. |GitHub-Updated| image:: https://img.shields.io/github/last-commit/tqdm/tqdm/master.svg?logo=github&logoColor=white&label=pushed - :target: https://github.com/tqdm/tqdm/pulse -.. |Gift-Casper| image:: https://img.shields.io/badge/dynamic/json.svg?color=ff69b4&label=gifts%20received&prefix=%C2%A3&query=%24..sum&url=https%3A%2F%2Fcaspersci.uk.to%2Fgifts.json - :target: https://cdcl.ml/sponsor -.. |Versions| image:: https://img.shields.io/pypi/v/tqdm.svg - :target: https://tqdm.github.io/releases -.. |PyPI-Downloads| image:: https://img.shields.io/pypi/dm/tqdm.svg?label=pypi%20downloads&logo=PyPI&logoColor=white - :target: https://pepy.tech/project/tqdm -.. |Py-Versions| image:: https://img.shields.io/pypi/pyversions/tqdm.svg?logo=python&logoColor=white - :target: https://pypi.org/project/tqdm -.. |Conda-Forge-Status| image:: https://img.shields.io/conda/v/conda-forge/tqdm.svg?label=conda-forge&logo=conda-forge - :target: https://anaconda.org/conda-forge/tqdm -.. |Snapcraft| image:: https://img.shields.io/badge/snap-install-82BEA0.svg?logo=snapcraft - :target: https://snapcraft.io/tqdm -.. |Docker| image:: https://img.shields.io/badge/docker-pull-blue.svg?logo=docker&logoColor=white - :target: https://hub.docker.com/r/tqdm/tqdm -.. |Libraries-Rank| image:: https://img.shields.io/librariesio/sourcerank/pypi/tqdm.svg?logo=koding&logoColor=white - :target: https://libraries.io/pypi/tqdm -.. |Libraries-Dependents| image:: https://img.shields.io/librariesio/dependent-repos/pypi/tqdm.svg?logo=koding&logoColor=white - :target: https://github.com/tqdm/tqdm/network/dependents -.. |OpenHub-Status| image:: https://www.openhub.net/p/tqdm/widgets/project_thin_badge?format=gif - :target: https://www.openhub.net/p/tqdm?ref=Thin+badge -.. |awesome-python| image:: https://awesome.re/mentioned-badge.svg - :target: https://github.com/vinta/awesome-python -.. |LICENCE| image:: https://img.shields.io/pypi/l/tqdm.svg - :target: https://raw.githubusercontent.com/tqdm/tqdm/master/LICENCE -.. |DOI| image:: https://img.shields.io/badge/DOI-10.5281/zenodo.595120-blue.svg - :target: https://doi.org/10.5281/zenodo.595120 -.. |binder-demo| image:: https://mybinder.org/badge_logo.svg - :target: https://mybinder.org/v2/gh/tqdm/tqdm/master?filepath=DEMO.ipynb -.. |Screenshot-Jupyter1| image:: https://tqdm.github.io/img/jupyter-1.gif -.. |Screenshot-Jupyter2| image:: https://tqdm.github.io/img/jupyter-2.gif -.. |Screenshot-Jupyter3| image:: https://tqdm.github.io/img/jupyter-3.gif -.. |README-Hits| image:: https://cgi.cdcl.ml/hits?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif - :target: https://cgi.cdcl.ml/hits?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif&style=social diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/RECORD deleted file mode 100644 index 80cf5d4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/RECORD +++ /dev/null @@ -1,40 +0,0 @@ -tqdm/__init__.py,sha256=9mQNYSSqP99JasubEC1POJLMmhkkBH6cJZxPIR5G2pQ,1572 -tqdm/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 -tqdm/_dist_ver.py,sha256=m5AdYI-jB-v6P0VJ_70isH_p24EzSOGSwVvuAZmkmKY,23 -tqdm/_main.py,sha256=9ySvgmi_2Sw4CAo5UDW0Q2dxfTryboEWGHohfCJz0sA,283 -tqdm/_monitor.py,sha256=Uku-DPWgzJ7dO5CK08xKJK-E_F6qQ-JB3ksuXczSYR0,3699 -tqdm/_tqdm.py,sha256=LfLCuJ6bpsVo9xilmtBXyEm1vGnUCFrliW85j3J-nD4,283 -tqdm/_tqdm_gui.py,sha256=03Hc8KayxJveieI5-0-2NGiDpLvw9jZekofJUV7CCwk,287 -tqdm/_tqdm_notebook.py,sha256=BuHiLuxu6uEfZFaPJW3RPpPaxaVctEQA3kdSJSDL1hw,307 -tqdm/_tqdm_pandas.py,sha256=c9jptUgigN6axRDhRd4Rif98Tmxeopc1nFNFhIpbFUE,888 -tqdm/_utils.py,sha256=_4E73bfDj4f1s3sM42NLHNrZDOkijZoWq-n6xWLkdZ8,553 -tqdm/asyncio.py,sha256=Kp2rSkNRf9KRqa3d9YpgeZQ7L7EZf2Ki4bSc7UPIyoo,2757 -tqdm/auto.py,sha256=nDZflj6p2zKkjBCNBourrhS81zYfZy1_dQvbckrdW8o,871 -tqdm/autonotebook.py,sha256=Yb9F5uaiBPhfbDDFpbtoG8I2YUw3uQJ89rUDLbfR6ws,956 -tqdm/cli.py,sha256=SbKlN8QyZ2ogenqt-wT_p6_sx2OOdCjCyhoZBFnlmyI,11010 -tqdm/completion.sh,sha256=j79KbSmpIj_E11jfTfBXrGnUTzKXVpQ1vGVQvsyDRl4,946 -tqdm/dask.py,sha256=9Ei58eVqTossRLhAfWyUFCduXYKjmLmwkaXIy-CHYfs,1319 -tqdm/gui.py,sha256=STIB3K8iDzDgkNUqWIpvcI_u0OGtbGNy5NwpALXhfWs,5479 -tqdm/keras.py,sha256=op9sBkb6q6c6dw2wJ0SD2ZwpPK7yM1Vbg4l1Qiy3MIo,4373 -tqdm/notebook.py,sha256=GtZ3IapLL1v8WNDaTSvPw0bJGTyfp71Vfz5HDnAzx1M,10895 -tqdm/rich.py,sha256=YyMPkEHVyYUVUR3adJKbVX26iTmNKpNMf3DEqmm-m60,5021 -tqdm/std.py,sha256=tWjz6-QCa92aqYjz7PIdkLUCAfiy-lJZheBtZyIIyO0,57461 -tqdm/tk.py,sha256=Gu0uwXwLCGPRGHORdi3WvBLGiseUp_xxX_h_gp9VpK0,6701 -tqdm/tqdm.1,sha256=aILyUPk2S4OPe_uWy2P4AMjUf0oQ6PUW0nLYXB-BWwI,7889 -tqdm/utils.py,sha256=6E0BQw3Sg7uGWKBM_cDn3P42tXswRhzkggbhBgLDjl8,11821 -tqdm/version.py,sha256=-1yWjfu3P0eghVsysHH07fbzdiADNRdzRtYPqOaqR2A,333 -tqdm/contrib/__init__.py,sha256=OgSwVXm-vlDJ-2imtoQ9z8qdom4snMSRztH72KMA82A,2494 -tqdm/contrib/bells.py,sha256=Yx1HqGCmHrESCAO700j5wE__JCleNODJxedh1ijPLD0,837 -tqdm/contrib/concurrent.py,sha256=K1yjloKS5WRNFyjLRth0DmU5PAnDbF0A-GD27N-J4a8,3986 -tqdm/contrib/discord.py,sha256=MtVIL1s_dxH21G4sL8FBgQ4Wei23ho9Ek5T-AommvNc,5243 -tqdm/contrib/itertools.py,sha256=WdKKQU5eSzsqHu29SN_oH12huYZo0Jihqoi9-nVhwz4,774 -tqdm/contrib/logging.py,sha256=NsYtnKttj2mMrGm58mEdo5a9DP_2vv8pZyrimSuWulA,3760 -tqdm/contrib/slack.py,sha256=eP_Mr5sQonYniHxxQNGue3jk2JkIPmPWFZqIYxnOui0,4007 -tqdm/contrib/telegram.py,sha256=vn_9SATMbbwn2PAbzSDyOX6av3eBB01QBug11P4H-Og,5008 -tqdm/contrib/utils_worker.py,sha256=HJP5Mz1S1xyzEke2JaqJ2sYLHXADYoo2epT5AzQ38eA,1207 -tqdm-4.67.1.dist-info/LICENCE,sha256=3DMlLoKQFeOxUAhvubOkD2rW-zLC9GEM6BL6Z301mGo,1985 -tqdm-4.67.1.dist-info/METADATA,sha256=aIoWMt9SWhmP7FLc_vsSRtMerO6cA1qsrC1-r42P9mk,57675 -tqdm-4.67.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91 -tqdm-4.67.1.dist-info/entry_points.txt,sha256=ReJCH7Ui3Zyh6M16E4OhsZ1oU7WtMXCfbtoyBhGO29Y,39 -tqdm-4.67.1.dist-info/top_level.txt,sha256=NLiUJNfmc9At15s7JURiwvqMEjUi9G5PMGRrmMYzNSM,5 -tqdm-4.67.1.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/WHEEL deleted file mode 100644 index ae527e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.6.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/entry_points.txt deleted file mode 100644 index 540e60f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -tqdm = tqdm.cli:main diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/top_level.txt deleted file mode 100644 index 78620c4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm-4.67.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -tqdm diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/__init__.py b/extensions/.local/lib/python3.11/site-packages/tqdm/__init__.py deleted file mode 100644 index 8081f77..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -from ._monitor import TMonitor, TqdmSynchronisationWarning -from ._tqdm_pandas import tqdm_pandas -from .cli import main # TODO: remove in v5.0.0 -from .gui import tqdm as tqdm_gui # TODO: remove in v5.0.0 -from .gui import trange as tgrange # TODO: remove in v5.0.0 -from .std import ( - TqdmDeprecationWarning, TqdmExperimentalWarning, TqdmKeyError, TqdmMonitorWarning, - TqdmTypeError, TqdmWarning, tqdm, trange) -from .version import __version__ - -__all__ = ['tqdm', 'tqdm_gui', 'trange', 'tgrange', 'tqdm_pandas', - 'tqdm_notebook', 'tnrange', 'main', 'TMonitor', - 'TqdmTypeError', 'TqdmKeyError', - 'TqdmWarning', 'TqdmDeprecationWarning', - 'TqdmExperimentalWarning', - 'TqdmMonitorWarning', 'TqdmSynchronisationWarning', - '__version__'] - - -def tqdm_notebook(*args, **kwargs): # pragma: no cover - """See tqdm.notebook.tqdm for full documentation""" - from warnings import warn - - from .notebook import tqdm as _tqdm_notebook - warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.notebook.tqdm` instead of `tqdm.tqdm_notebook`", - TqdmDeprecationWarning, stacklevel=2) - return _tqdm_notebook(*args, **kwargs) - - -def tnrange(*args, **kwargs): # pragma: no cover - """Shortcut for `tqdm.notebook.tqdm(range(*args), **kwargs)`.""" - from warnings import warn - - from .notebook import trange as _tnrange - warn("Please use `tqdm.notebook.trange` instead of `tqdm.tnrange`", - TqdmDeprecationWarning, stacklevel=2) - return _tnrange(*args, **kwargs) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/__main__.py b/extensions/.local/lib/python3.11/site-packages/tqdm/__main__.py deleted file mode 100644 index 4e28416..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .cli import main - -main() diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_dist_ver.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_dist_ver.py deleted file mode 100644 index 61af7d5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_dist_ver.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = '4.67.1' diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_main.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_main.py deleted file mode 100644 index 04fdeef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_main.py +++ /dev/null @@ -1,9 +0,0 @@ -from warnings import warn - -from .cli import * # NOQA -from .cli import __all__ # NOQA -from .std import TqdmDeprecationWarning - -warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.cli.*` instead of `tqdm._main.*`", - TqdmDeprecationWarning, stacklevel=2) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_monitor.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_monitor.py deleted file mode 100644 index f71aa56..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_monitor.py +++ /dev/null @@ -1,95 +0,0 @@ -import atexit -from threading import Event, Thread, current_thread -from time import time -from warnings import warn - -__all__ = ["TMonitor", "TqdmSynchronisationWarning"] - - -class TqdmSynchronisationWarning(RuntimeWarning): - """tqdm multi-thread/-process errors which may cause incorrect nesting - but otherwise no adverse effects""" - pass - - -class TMonitor(Thread): - """ - Monitoring thread for tqdm bars. - Monitors if tqdm bars are taking too much time to display - and readjusts miniters automatically if necessary. - - Parameters - ---------- - tqdm_cls : class - tqdm class to use (can be core tqdm or a submodule). - sleep_interval : float - Time to sleep between monitoring checks. - """ - _test = {} # internal vars for unit testing - - def __init__(self, tqdm_cls, sleep_interval): - Thread.__init__(self) - self.daemon = True # kill thread when main killed (KeyboardInterrupt) - self.woken = 0 # last time woken up, to sync with monitor - self.tqdm_cls = tqdm_cls - self.sleep_interval = sleep_interval - self._time = self._test.get("time", time) - self.was_killed = self._test.get("Event", Event)() - atexit.register(self.exit) - self.start() - - def exit(self): - self.was_killed.set() - if self is not current_thread(): - self.join() - return self.report() - - def get_instances(self): - # returns a copy of started `tqdm_cls` instances - return [i for i in self.tqdm_cls._instances.copy() - # Avoid race by checking that the instance started - if hasattr(i, 'start_t')] - - def run(self): - cur_t = self._time() - while True: - # After processing and before sleeping, notify that we woke - # Need to be done just before sleeping - self.woken = cur_t - # Sleep some time... - self.was_killed.wait(self.sleep_interval) - # Quit if killed - if self.was_killed.is_set(): - return - # Then monitor! - # Acquire lock (to access _instances) - with self.tqdm_cls.get_lock(): - cur_t = self._time() - # Check tqdm instances are waiting too long to print - instances = self.get_instances() - for instance in instances: - # Check event in loop to reduce blocking time on exit - if self.was_killed.is_set(): - return - # Only if mininterval > 1 (else iterations are just slow) - # and last refresh exceeded maxinterval - if ( - instance.miniters > 1 - and (cur_t - instance.last_print_t) >= instance.maxinterval - ): - # force bypassing miniters on next iteration - # (dynamic_miniters adjusts mininterval automatically) - instance.miniters = 1 - # Refresh now! (works only for manual tqdm) - instance.refresh(nolock=True) - # Remove accidental long-lived strong reference - del instance - if instances != self.get_instances(): # pragma: nocover - warn("Set changed size during iteration" + - " (see https://github.com/tqdm/tqdm/issues/481)", - TqdmSynchronisationWarning, stacklevel=2) - # Remove accidental long-lived strong references - del instances - - def report(self): - return not self.was_killed.is_set() diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm.py deleted file mode 100644 index 7fc4962..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm.py +++ /dev/null @@ -1,9 +0,0 @@ -from warnings import warn - -from .std import * # NOQA -from .std import __all__ # NOQA -from .std import TqdmDeprecationWarning - -warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.std.*` instead of `tqdm._tqdm.*`", - TqdmDeprecationWarning, stacklevel=2) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_gui.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_gui.py deleted file mode 100644 index f32aa89..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_gui.py +++ /dev/null @@ -1,9 +0,0 @@ -from warnings import warn - -from .gui import * # NOQA -from .gui import __all__ # NOQA -from .std import TqdmDeprecationWarning - -warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.gui.*` instead of `tqdm._tqdm_gui.*`", - TqdmDeprecationWarning, stacklevel=2) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_notebook.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_notebook.py deleted file mode 100644 index f225fbf..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_notebook.py +++ /dev/null @@ -1,9 +0,0 @@ -from warnings import warn - -from .notebook import * # NOQA -from .notebook import __all__ # NOQA -from .std import TqdmDeprecationWarning - -warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.notebook.*` instead of `tqdm._tqdm_notebook.*`", - TqdmDeprecationWarning, stacklevel=2) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_pandas.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_pandas.py deleted file mode 100644 index c4fe6ef..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_tqdm_pandas.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys - -__author__ = "github.com/casperdcl" -__all__ = ['tqdm_pandas'] - - -def tqdm_pandas(tclass, **tqdm_kwargs): - """ - Registers the given `tqdm` instance with - `pandas.core.groupby.DataFrameGroupBy.progress_apply`. - """ - from tqdm import TqdmDeprecationWarning - - if isinstance(tclass, type) or (getattr(tclass, '__name__', '').startswith( - 'tqdm_')): # delayed adapter case - TqdmDeprecationWarning( - "Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm, ...)`.", - fp_write=getattr(tqdm_kwargs.get('file', None), 'write', sys.stderr.write)) - tclass.pandas(**tqdm_kwargs) - else: - TqdmDeprecationWarning( - "Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm(...))`.", - fp_write=getattr(tclass.fp, 'write', sys.stderr.write)) - type(tclass).pandas(deprecated_t=tclass) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/_utils.py b/extensions/.local/lib/python3.11/site-packages/tqdm/_utils.py deleted file mode 100644 index 385e849..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/_utils.py +++ /dev/null @@ -1,11 +0,0 @@ -from warnings import warn - -from .std import TqdmDeprecationWarning -from .utils import ( # NOQA, pylint: disable=unused-import - CUR_OS, IS_NIX, IS_WIN, RE_ANSI, Comparable, FormatReplace, SimpleTextIOWrapper, - _environ_cols_wrapper, _is_ascii, _is_utf, _screen_shape_linux, _screen_shape_tput, - _screen_shape_windows, _screen_shape_wrapper, _supports_unicode, _term_move_up, colorama) - -warn("This function will be removed in tqdm==5.0.0\n" - "Please use `tqdm.utils.*` instead of `tqdm._utils.*`", - TqdmDeprecationWarning, stacklevel=2) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/asyncio.py b/extensions/.local/lib/python3.11/site-packages/tqdm/asyncio.py deleted file mode 100644 index 2d00a0a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/asyncio.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Asynchronous progressbar decorator for iterators. -Includes a default `range` iterator printing to `stderr`. - -Usage: ->>> from tqdm.asyncio import trange, tqdm ->>> async for i in trange(10): -... ... -""" -import asyncio -from sys import version_info - -from .std import tqdm as std_tqdm - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['tqdm_asyncio', 'tarange', 'tqdm', 'trange'] - - -class tqdm_asyncio(std_tqdm): - """ - Asynchronous-friendly version of tqdm. - """ - def __init__(self, iterable=None, *args, **kwargs): - super().__init__(iterable, *args, **kwargs) - self.iterable_awaitable = False - if iterable is not None: - if hasattr(iterable, "__anext__"): - self.iterable_next = iterable.__anext__ - self.iterable_awaitable = True - elif hasattr(iterable, "__next__"): - self.iterable_next = iterable.__next__ - else: - self.iterable_iterator = iter(iterable) - self.iterable_next = self.iterable_iterator.__next__ - - def __aiter__(self): - return self - - async def __anext__(self): - try: - if self.iterable_awaitable: - res = await self.iterable_next() - else: - res = self.iterable_next() - self.update() - return res - except StopIteration: - self.close() - raise StopAsyncIteration - except BaseException: - self.close() - raise - - def send(self, *args, **kwargs): - return self.iterable.send(*args, **kwargs) - - @classmethod - def as_completed(cls, fs, *, loop=None, timeout=None, total=None, **tqdm_kwargs): - """ - Wrapper for `asyncio.as_completed`. - """ - if total is None: - total = len(fs) - kwargs = {} - if version_info[:2] < (3, 10): - kwargs['loop'] = loop - yield from cls(asyncio.as_completed(fs, timeout=timeout, **kwargs), - total=total, **tqdm_kwargs) - - @classmethod - async def gather(cls, *fs, loop=None, timeout=None, total=None, **tqdm_kwargs): - """ - Wrapper for `asyncio.gather`. - """ - async def wrap_awaitable(i, f): - return i, await f - - ifs = [wrap_awaitable(i, f) for i, f in enumerate(fs)] - res = [await f for f in cls.as_completed(ifs, loop=loop, timeout=timeout, - total=total, **tqdm_kwargs)] - return [i for _, i in sorted(res)] - - -def tarange(*args, **kwargs): - """ - A shortcut for `tqdm.asyncio.tqdm(range(*args), **kwargs)`. - """ - return tqdm_asyncio(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_asyncio -trange = tarange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/auto.py b/extensions/.local/lib/python3.11/site-packages/tqdm/auto.py deleted file mode 100644 index 206c440..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/auto.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Enables multiple commonly used features. - -Method resolution order: - -- `tqdm.autonotebook` without import warnings -- `tqdm.asyncio` -- `tqdm.std` base class - -Usage: ->>> from tqdm.auto import trange, tqdm ->>> for i in trange(10): -... ... -""" -import warnings - -from .std import TqdmExperimentalWarning - -with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=TqdmExperimentalWarning) - from .autonotebook import tqdm as notebook_tqdm - -from .asyncio import tqdm as asyncio_tqdm -from .std import tqdm as std_tqdm - -if notebook_tqdm != std_tqdm: - class tqdm(notebook_tqdm, asyncio_tqdm): # pylint: disable=inconsistent-mro - pass -else: - tqdm = asyncio_tqdm - - -def trange(*args, **kwargs): - """ - A shortcut for `tqdm.auto.tqdm(range(*args), **kwargs)`. - """ - return tqdm(range(*args), **kwargs) - - -__all__ = ["tqdm", "trange"] diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/autonotebook.py b/extensions/.local/lib/python3.11/site-packages/tqdm/autonotebook.py deleted file mode 100644 index a09f2ec..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/autonotebook.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Automatically choose between `tqdm.notebook` and `tqdm.std`. - -Usage: ->>> from tqdm.autonotebook import trange, tqdm ->>> for i in trange(10): -... ... -""" -import sys -from warnings import warn - -try: - get_ipython = sys.modules['IPython'].get_ipython - if 'IPKernelApp' not in get_ipython().config: # pragma: no cover - raise ImportError("console") - from .notebook import WARN_NOIPYW, IProgress - if IProgress is None: - from .std import TqdmWarning - warn(WARN_NOIPYW, TqdmWarning, stacklevel=2) - raise ImportError('ipywidgets') -except Exception: - from .std import tqdm, trange -else: # pragma: no cover - from .notebook import tqdm, trange - from .std import TqdmExperimentalWarning - warn("Using `tqdm.autonotebook.tqdm` in notebook mode." - " Use `tqdm.tqdm` instead to force console mode" - " (e.g. in jupyter console)", TqdmExperimentalWarning, stacklevel=2) -__all__ = ["tqdm", "trange"] diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/cli.py b/extensions/.local/lib/python3.11/site-packages/tqdm/cli.py deleted file mode 100644 index e54a7fc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/cli.py +++ /dev/null @@ -1,324 +0,0 @@ -""" -Module version for monitoring CLI pipes (`... | python -m tqdm | ...`). -""" -import logging -import re -import sys -from ast import literal_eval as numeric -from textwrap import indent - -from .std import TqdmKeyError, TqdmTypeError, tqdm -from .version import __version__ - -__all__ = ["main"] -log = logging.getLogger(__name__) - - -def cast(val, typ): - log.debug((val, typ)) - if " or " in typ: - for t in typ.split(" or "): - try: - return cast(val, t) - except TqdmTypeError: - pass - raise TqdmTypeError(f"{val} : {typ}") - - # sys.stderr.write('\ndebug | `val:type`: `' + val + ':' + typ + '`.\n') - if typ == 'bool': - if (val == 'True') or (val == ''): - return True - if val == 'False': - return False - raise TqdmTypeError(val + ' : ' + typ) - if typ == 'chr': - if len(val) == 1: - return val.encode() - if re.match(r"^\\\w+$", val): - return eval(f'"{val}"').encode() - raise TqdmTypeError(f"{val} : {typ}") - if typ == 'str': - return val - if typ == 'int': - try: - return int(val) - except ValueError as exc: - raise TqdmTypeError(f"{val} : {typ}") from exc - if typ == 'float': - try: - return float(val) - except ValueError as exc: - raise TqdmTypeError(f"{val} : {typ}") from exc - raise TqdmTypeError(f"{val} : {typ}") - - -def posix_pipe(fin, fout, delim=b'\\n', buf_size=256, - callback=lambda float: None, callback_len=True): - """ - Params - ------ - fin : binary file with `read(buf_size : int)` method - fout : binary file with `write` (and optionally `flush`) methods. - callback : function(float), e.g.: `tqdm.update` - callback_len : If (default: True) do `callback(len(buffer))`. - Otherwise, do `callback(data) for data in buffer.split(delim)`. - """ - fp_write = fout.write - - if not delim: - while True: - tmp = fin.read(buf_size) - - # flush at EOF - if not tmp: - getattr(fout, 'flush', lambda: None)() - return - - fp_write(tmp) - callback(len(tmp)) - # return - - buf = b'' - len_delim = len(delim) - # n = 0 - while True: - tmp = fin.read(buf_size) - - # flush at EOF - if not tmp: - if buf: - fp_write(buf) - if callback_len: - # n += 1 + buf.count(delim) - callback(1 + buf.count(delim)) - else: - for i in buf.split(delim): - callback(i) - getattr(fout, 'flush', lambda: None)() - return # n - - while True: - i = tmp.find(delim) - if i < 0: - buf += tmp - break - fp_write(buf + tmp[:i + len(delim)]) - # n += 1 - callback(1 if callback_len else (buf + tmp[:i])) - buf = b'' - tmp = tmp[i + len_delim:] - - -# ((opt, type), ... ) -RE_OPTS = re.compile(r'\n {4}(\S+)\s{2,}:\s*([^,]+)') -# better split method assuming no positional args -RE_SHLEX = re.compile(r'\s*(? : \2', d) - split = RE_OPTS.split(d) - opt_types_desc = zip(split[1::3], split[2::3], split[3::3]) - d = ''.join(('\n --{0} : {2}{3}' if otd[1] == 'bool' else - '\n --{0}=<{1}> : {2}{3}').format( - otd[0].replace('_', '-'), otd[0], *otd[1:]) - for otd in opt_types_desc if otd[0] not in UNSUPPORTED_OPTS) - - help_short = "Usage:\n tqdm [--help | options]\n" - d = help_short + """ -Options: - -h, --help Print this help and exit. - -v, --version Print version and exit. -""" + d.strip('\n') + '\n' - - # opts = docopt(d, version=__version__) - if any(v in argv for v in ('-v', '--version')): - sys.stdout.write(__version__ + '\n') - sys.exit(0) - elif any(v in argv for v in ('-h', '--help')): - sys.stdout.write(d + '\n') - sys.exit(0) - elif argv and argv[0][:2] != '--': - sys.stderr.write(f"Error:Unknown argument:{argv[0]}\n{help_short}") - - argv = RE_SHLEX.split(' '.join(["tqdm"] + argv)) - opts = dict(zip(argv[1::3], argv[3::3])) - - log.debug(opts) - opts.pop('log', True) - - tqdm_args = {'file': fp} - try: - for (o, v) in opts.items(): - o = o.replace('-', '_') - try: - tqdm_args[o] = cast(v, opt_types[o]) - except KeyError as e: - raise TqdmKeyError(str(e)) - log.debug('args:' + str(tqdm_args)) - - delim_per_char = tqdm_args.pop('bytes', False) - update = tqdm_args.pop('update', False) - update_to = tqdm_args.pop('update_to', False) - if sum((delim_per_char, update, update_to)) > 1: - raise TqdmKeyError("Can only have one of --bytes --update --update_to") - except Exception: - fp.write("\nError:\n" + help_short) - stdin, stdout_write = sys.stdin, sys.stdout.write - for i in stdin: - stdout_write(i) - raise - else: - buf_size = tqdm_args.pop('buf_size', 256) - delim = tqdm_args.pop('delim', b'\\n') - tee = tqdm_args.pop('tee', False) - manpath = tqdm_args.pop('manpath', None) - comppath = tqdm_args.pop('comppath', None) - if tqdm_args.pop('null', False): - class stdout(object): - @staticmethod - def write(_): - pass - else: - stdout = sys.stdout - stdout = getattr(stdout, 'buffer', stdout) - stdin = getattr(sys.stdin, 'buffer', sys.stdin) - if manpath or comppath: - try: # py<3.9 - import importlib_resources as resources - except ImportError: - from importlib import resources - from pathlib import Path - - def cp(name, dst): - """copy resource `name` to `dst`""" - fi = resources.files('tqdm') / name - dst.write_bytes(fi.read_bytes()) - log.info("written:%s", dst) - if manpath is not None: - cp('tqdm.1', Path(manpath) / 'tqdm.1') - if comppath is not None: - cp('completion.sh', Path(comppath) / 'tqdm_completion.sh') - sys.exit(0) - if tee: - stdout_write = stdout.write - fp_write = getattr(fp, 'buffer', fp).write - - class stdout(object): # pylint: disable=function-redefined - @staticmethod - def write(x): - with tqdm.external_write_mode(file=fp): - fp_write(x) - stdout_write(x) - if delim_per_char: - tqdm_args.setdefault('unit', 'B') - tqdm_args.setdefault('unit_scale', True) - tqdm_args.setdefault('unit_divisor', 1024) - log.debug(tqdm_args) - with tqdm(**tqdm_args) as t: - posix_pipe(stdin, stdout, '', buf_size, t.update) - elif delim == b'\\n': - log.debug(tqdm_args) - write = stdout.write - if update or update_to: - with tqdm(**tqdm_args) as t: - if update: - def callback(i): - t.update(numeric(i.decode())) - else: # update_to - def callback(i): - t.update(numeric(i.decode()) - t.n) - for i in stdin: - write(i) - callback(i) - else: - for i in tqdm(stdin, **tqdm_args): - write(i) - else: - log.debug(tqdm_args) - with tqdm(**tqdm_args) as t: - callback_len = False - if update: - def callback(i): - t.update(numeric(i.decode())) - elif update_to: - def callback(i): - t.update(numeric(i.decode()) - t.n) - else: - callback = t.update - callback_len = True - posix_pipe(stdin, stdout, delim, buf_size, callback, callback_len) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/completion.sh b/extensions/.local/lib/python3.11/site-packages/tqdm/completion.sh deleted file mode 100644 index 9f61c7f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/completion.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -_tqdm(){ - local cur prv - cur="${COMP_WORDS[COMP_CWORD]}" - prv="${COMP_WORDS[COMP_CWORD - 1]}" - - case ${prv} in - --bar_format|--buf_size|--colour|--comppath|--delay|--delim|--desc|--initial|--lock_args|--manpath|--maxinterval|--mininterval|--miniters|--ncols|--nrows|--position|--postfix|--smoothing|--total|--unit|--unit_divisor) - # await user input - ;; - "--log") - COMPREPLY=($(compgen -W 'CRITICAL FATAL ERROR WARN WARNING INFO DEBUG NOTSET' -- ${cur})) - ;; - *) - COMPREPLY=($(compgen -W '--ascii --bar_format --buf_size --bytes --colour --comppath --delay --delim --desc --disable --dynamic_ncols --help --initial --leave --lock_args --log --manpath --maxinterval --mininterval --miniters --ncols --nrows --null --position --postfix --smoothing --tee --total --unit --unit_divisor --unit_scale --update --update_to --version --write_bytes -h -v' -- ${cur})) - ;; - esac -} -complete -F _tqdm tqdm diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/__init__.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/__init__.py deleted file mode 100644 index d059461..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/__init__.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Thin wrappers around common functions. - -Subpackages contain potentially unstable extensions. -""" -from warnings import warn - -from ..auto import tqdm as tqdm_auto -from ..std import TqdmDeprecationWarning, tqdm -from ..utils import ObjectWrapper - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['tenumerate', 'tzip', 'tmap'] - - -class DummyTqdmFile(ObjectWrapper): - """Dummy file-like that will write to tqdm""" - - def __init__(self, wrapped): - super().__init__(wrapped) - self._buf = [] - - def write(self, x, nolock=False): - nl = b"\n" if isinstance(x, bytes) else "\n" - pre, sep, post = x.rpartition(nl) - if sep: - blank = type(nl)() - tqdm.write(blank.join(self._buf + [pre, sep]), - end=blank, file=self._wrapped, nolock=nolock) - self._buf = [post] - else: - self._buf.append(x) - - def __del__(self): - if self._buf: - blank = type(self._buf[0])() - try: - tqdm.write(blank.join(self._buf), end=blank, file=self._wrapped) - except (OSError, ValueError): - pass - - -def builtin_iterable(func): - """Returns `func`""" - warn("This function has no effect, and will be removed in tqdm==5.0.0", - TqdmDeprecationWarning, stacklevel=2) - return func - - -def tenumerate(iterable, start=0, total=None, tqdm_class=tqdm_auto, **tqdm_kwargs): - """ - Equivalent of `numpy.ndenumerate` or builtin `enumerate`. - - Parameters - ---------- - tqdm_class : [default: tqdm.auto.tqdm]. - """ - try: - import numpy as np - except ImportError: - pass - else: - if isinstance(iterable, np.ndarray): - return tqdm_class(np.ndenumerate(iterable), total=total or iterable.size, - **tqdm_kwargs) - return enumerate(tqdm_class(iterable, total=total, **tqdm_kwargs), start) - - -def tzip(iter1, *iter2plus, **tqdm_kwargs): - """ - Equivalent of builtin `zip`. - - Parameters - ---------- - tqdm_class : [default: tqdm.auto.tqdm]. - """ - kwargs = tqdm_kwargs.copy() - tqdm_class = kwargs.pop("tqdm_class", tqdm_auto) - for i in zip(tqdm_class(iter1, **kwargs), *iter2plus): - yield i - - -def tmap(function, *sequences, **tqdm_kwargs): - """ - Equivalent of builtin `map`. - - Parameters - ---------- - tqdm_class : [default: tqdm.auto.tqdm]. - """ - for i in tzip(*sequences, **tqdm_kwargs): - yield function(*i) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/bells.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/bells.py deleted file mode 100644 index 5b8f4b9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/bells.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Even more features than `tqdm.auto` (all the bells & whistles): - -- `tqdm.auto` -- `tqdm.tqdm.pandas` -- `tqdm.contrib.telegram` - + uses `${TQDM_TELEGRAM_TOKEN}` and `${TQDM_TELEGRAM_CHAT_ID}` -- `tqdm.contrib.discord` - + uses `${TQDM_DISCORD_TOKEN}` and `${TQDM_DISCORD_CHANNEL_ID}` -""" -__all__ = ['tqdm', 'trange'] -import warnings -from os import getenv - -if getenv("TQDM_SLACK_TOKEN") and getenv("TQDM_SLACK_CHANNEL"): - from .slack import tqdm, trange -elif getenv("TQDM_TELEGRAM_TOKEN") and getenv("TQDM_TELEGRAM_CHAT_ID"): - from .telegram import tqdm, trange -elif getenv("TQDM_DISCORD_TOKEN") and getenv("TQDM_DISCORD_CHANNEL_ID"): - from .discord import tqdm, trange -else: - from ..auto import tqdm, trange - -with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=FutureWarning) - tqdm.pandas() diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/concurrent.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/concurrent.py deleted file mode 100644 index cd81d62..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/concurrent.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -Thin wrappers around `concurrent.futures`. -""" -from contextlib import contextmanager -from operator import length_hint -from os import cpu_count - -from ..auto import tqdm as tqdm_auto -from ..std import TqdmWarning - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['thread_map', 'process_map'] - - -@contextmanager -def ensure_lock(tqdm_class, lock_name=""): - """get (create if necessary) and then restore `tqdm_class`'s lock""" - old_lock = getattr(tqdm_class, '_lock', None) # don't create a new lock - lock = old_lock or tqdm_class.get_lock() # maybe create a new lock - lock = getattr(lock, lock_name, lock) # maybe subtype - tqdm_class.set_lock(lock) - yield lock - if old_lock is None: - del tqdm_class._lock - else: - tqdm_class.set_lock(old_lock) - - -def _executor_map(PoolExecutor, fn, *iterables, **tqdm_kwargs): - """ - Implementation of `thread_map` and `process_map`. - - Parameters - ---------- - tqdm_class : [default: tqdm.auto.tqdm]. - max_workers : [default: min(32, cpu_count() + 4)]. - chunksize : [default: 1]. - lock_name : [default: "":str]. - """ - kwargs = tqdm_kwargs.copy() - if "total" not in kwargs: - kwargs["total"] = length_hint(iterables[0]) - tqdm_class = kwargs.pop("tqdm_class", tqdm_auto) - max_workers = kwargs.pop("max_workers", min(32, cpu_count() + 4)) - chunksize = kwargs.pop("chunksize", 1) - lock_name = kwargs.pop("lock_name", "") - with ensure_lock(tqdm_class, lock_name=lock_name) as lk: - # share lock in case workers are already using `tqdm` - with PoolExecutor(max_workers=max_workers, initializer=tqdm_class.set_lock, - initargs=(lk,)) as ex: - return list(tqdm_class(ex.map(fn, *iterables, chunksize=chunksize), **kwargs)) - - -def thread_map(fn, *iterables, **tqdm_kwargs): - """ - Equivalent of `list(map(fn, *iterables))` - driven by `concurrent.futures.ThreadPoolExecutor`. - - Parameters - ---------- - tqdm_class : optional - `tqdm` class to use for bars [default: tqdm.auto.tqdm]. - max_workers : int, optional - Maximum number of workers to spawn; passed to - `concurrent.futures.ThreadPoolExecutor.__init__`. - [default: max(32, cpu_count() + 4)]. - """ - from concurrent.futures import ThreadPoolExecutor - return _executor_map(ThreadPoolExecutor, fn, *iterables, **tqdm_kwargs) - - -def process_map(fn, *iterables, **tqdm_kwargs): - """ - Equivalent of `list(map(fn, *iterables))` - driven by `concurrent.futures.ProcessPoolExecutor`. - - Parameters - ---------- - tqdm_class : optional - `tqdm` class to use for bars [default: tqdm.auto.tqdm]. - max_workers : int, optional - Maximum number of workers to spawn; passed to - `concurrent.futures.ProcessPoolExecutor.__init__`. - [default: min(32, cpu_count() + 4)]. - chunksize : int, optional - Size of chunks sent to worker processes; passed to - `concurrent.futures.ProcessPoolExecutor.map`. [default: 1]. - lock_name : str, optional - Member of `tqdm_class.get_lock()` to use [default: mp_lock]. - """ - from concurrent.futures import ProcessPoolExecutor - if iterables and "chunksize" not in tqdm_kwargs: - # default `chunksize=1` has poor performance for large iterables - # (most time spent dispatching items to workers). - longest_iterable_len = max(map(length_hint, iterables)) - if longest_iterable_len > 1000: - from warnings import warn - warn("Iterable length %d > 1000 but `chunksize` is not set." - " This may seriously degrade multiprocess performance." - " Set `chunksize=1` or more." % longest_iterable_len, - TqdmWarning, stacklevel=2) - if "lock_name" not in tqdm_kwargs: - tqdm_kwargs = tqdm_kwargs.copy() - tqdm_kwargs["lock_name"] = "mp_lock" - return _executor_map(ProcessPoolExecutor, fn, *iterables, **tqdm_kwargs) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/discord.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/discord.py deleted file mode 100644 index 574baa8..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/discord.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -Sends updates to a Discord bot. - -Usage: ->>> from tqdm.contrib.discord import tqdm, trange ->>> for i in trange(10, token='{token}', channel_id='{channel_id}'): -... ... - -![screenshot](https://tqdm.github.io/img/screenshot-discord.png) -""" -from os import getenv -from warnings import warn - -from requests import Session -from requests.utils import default_user_agent - -from ..auto import tqdm as tqdm_auto -from ..std import TqdmWarning -from ..version import __version__ -from .utils_worker import MonoWorker - -__author__ = {"github.com/": ["casperdcl", "guigoruiz1"]} -__all__ = ['DiscordIO', 'tqdm_discord', 'tdrange', 'tqdm', 'trange'] - - -class DiscordIO(MonoWorker): - """Non-blocking file-like IO using a Discord Bot.""" - API = "https://discord.com/api/v10" - UA = f"tqdm (https://tqdm.github.io, {__version__}) {default_user_agent()}" - - def __init__(self, token, channel_id): - """Creates a new message in the given `channel_id`.""" - super().__init__() - self.token = token - self.channel_id = channel_id - self.session = Session() - self.text = self.__class__.__name__ - self.message_id - - @property - def message_id(self): - if hasattr(self, '_message_id'): - return self._message_id - try: - res = self.session.post( - f'{self.API}/channels/{self.channel_id}/messages', - headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA}, - json={'content': f"`{self.text}`"}).json() - except Exception as e: - tqdm_auto.write(str(e)) - else: - if res.get('error_code') == 429: - warn("Creation rate limit: try increasing `mininterval`.", - TqdmWarning, stacklevel=2) - else: - self._message_id = res['id'] - return self._message_id - - def write(self, s): - """Replaces internal `message_id`'s text with `s`.""" - if not s: - s = "..." - s = s.replace('\r', '').strip() - if s == self.text: - return # avoid duplicate message Bot error - message_id = self.message_id - if message_id is None: - return - self.text = s - try: - future = self.submit( - self.session.patch, - f'{self.API}/channels/{self.channel_id}/messages/{message_id}', - headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA}, - json={'content': f"`{self.text}`"}) - except Exception as e: - tqdm_auto.write(str(e)) - else: - return future - - def delete(self): - """Deletes internal `message_id`.""" - try: - future = self.submit( - self.session.delete, - f'{self.API}/channels/{self.channel_id}/messages/{self.message_id}', - headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA}) - except Exception as e: - tqdm_auto.write(str(e)) - else: - return future - - -class tqdm_discord(tqdm_auto): - """ - Standard `tqdm.auto.tqdm` but also sends updates to a Discord Bot. - May take a few seconds to create (`__init__`). - - - create a discord bot (not public, no requirement of OAuth2 code - grant, only send message permissions) & invite it to a channel: - - - copy the bot `{token}` & `{channel_id}` and paste below - - >>> from tqdm.contrib.discord import tqdm, trange - >>> for i in tqdm(iterable, token='{token}', channel_id='{channel_id}'): - ... ... - """ - def __init__(self, *args, **kwargs): - """ - Parameters - ---------- - token : str, required. Discord bot token - [default: ${TQDM_DISCORD_TOKEN}]. - channel_id : int, required. Discord channel ID - [default: ${TQDM_DISCORD_CHANNEL_ID}]. - - See `tqdm.auto.tqdm.__init__` for other parameters. - """ - if not kwargs.get('disable'): - kwargs = kwargs.copy() - self.dio = DiscordIO( - kwargs.pop('token', getenv('TQDM_DISCORD_TOKEN')), - kwargs.pop('channel_id', getenv('TQDM_DISCORD_CHANNEL_ID'))) - super().__init__(*args, **kwargs) - - def display(self, **kwargs): - super().display(**kwargs) - fmt = self.format_dict - if fmt.get('bar_format', None): - fmt['bar_format'] = fmt['bar_format'].replace( - '', '{bar:10u}').replace('{bar}', '{bar:10u}') - else: - fmt['bar_format'] = '{l_bar}{bar:10u}{r_bar}' - self.dio.write(self.format_meter(**fmt)) - - def clear(self, *args, **kwargs): - super().clear(*args, **kwargs) - if not self.disable: - self.dio.write("") - - def close(self): - if self.disable: - return - super().close() - if not (self.leave or (self.leave is None and self.pos == 0)): - self.dio.delete() - - -def tdrange(*args, **kwargs): - """Shortcut for `tqdm.contrib.discord.tqdm(range(*args), **kwargs)`.""" - return tqdm_discord(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_discord -trange = tdrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/itertools.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/itertools.py deleted file mode 100644 index e67651a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/itertools.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Thin wrappers around `itertools`. -""" -import itertools - -from ..auto import tqdm as tqdm_auto - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['product'] - - -def product(*iterables, **tqdm_kwargs): - """ - Equivalent of `itertools.product`. - - Parameters - ---------- - tqdm_class : [default: tqdm.auto.tqdm]. - """ - kwargs = tqdm_kwargs.copy() - tqdm_class = kwargs.pop("tqdm_class", tqdm_auto) - try: - lens = list(map(len, iterables)) - except TypeError: - total = None - else: - total = 1 - for i in lens: - total *= i - kwargs.setdefault("total", total) - with tqdm_class(**kwargs) as t: - it = itertools.product(*iterables) - for i in it: - yield i - t.update() diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/logging.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/logging.py deleted file mode 100644 index e06febe..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/logging.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -Helper functionality for interoperability with stdlib `logging`. -""" -import logging -import sys -from contextlib import contextmanager - -try: - from typing import Iterator, List, Optional, Type # noqa: F401 -except ImportError: - pass - -from ..std import tqdm as std_tqdm - - -class _TqdmLoggingHandler(logging.StreamHandler): - def __init__( - self, - tqdm_class=std_tqdm # type: Type[std_tqdm] - ): - super().__init__() - self.tqdm_class = tqdm_class - - def emit(self, record): - try: - msg = self.format(record) - self.tqdm_class.write(msg, file=self.stream) - self.flush() - except (KeyboardInterrupt, SystemExit): - raise - except: # noqa pylint: disable=bare-except - self.handleError(record) - - -def _is_console_logging_handler(handler): - return (isinstance(handler, logging.StreamHandler) - and handler.stream in {sys.stdout, sys.stderr}) - - -def _get_first_found_console_logging_handler(handlers): - for handler in handlers: - if _is_console_logging_handler(handler): - return handler - - -@contextmanager -def logging_redirect_tqdm( - loggers=None, # type: Optional[List[logging.Logger]], - tqdm_class=std_tqdm # type: Type[std_tqdm] -): - # type: (...) -> Iterator[None] - """ - Context manager redirecting console logging to `tqdm.write()`, leaving - other logging handlers (e.g. log files) unaffected. - - Parameters - ---------- - loggers : list, optional - Which handlers to redirect (default: [logging.root]). - tqdm_class : optional - - Example - ------- - ```python - import logging - from tqdm import trange - from tqdm.contrib.logging import logging_redirect_tqdm - - LOG = logging.getLogger(__name__) - - if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - with logging_redirect_tqdm(): - for i in trange(9): - if i == 4: - LOG.info("console logging redirected to `tqdm.write()`") - # logging restored - ``` - """ - if loggers is None: - loggers = [logging.root] - original_handlers_list = [logger.handlers for logger in loggers] - try: - for logger in loggers: - tqdm_handler = _TqdmLoggingHandler(tqdm_class) - orig_handler = _get_first_found_console_logging_handler(logger.handlers) - if orig_handler is not None: - tqdm_handler.setFormatter(orig_handler.formatter) - tqdm_handler.stream = orig_handler.stream - logger.handlers = [ - handler for handler in logger.handlers - if not _is_console_logging_handler(handler)] + [tqdm_handler] - yield - finally: - for logger, original_handlers in zip(loggers, original_handlers_list): - logger.handlers = original_handlers - - -@contextmanager -def tqdm_logging_redirect( - *args, - # loggers=None, # type: Optional[List[logging.Logger]] - # tqdm=None, # type: Optional[Type[tqdm.tqdm]] - **kwargs -): - # type: (...) -> Iterator[None] - """ - Convenience shortcut for: - ```python - with tqdm_class(*args, **tqdm_kwargs) as pbar: - with logging_redirect_tqdm(loggers=loggers, tqdm_class=tqdm_class): - yield pbar - ``` - - Parameters - ---------- - tqdm_class : optional, (default: tqdm.std.tqdm). - loggers : optional, list. - **tqdm_kwargs : passed to `tqdm_class`. - """ - tqdm_kwargs = kwargs.copy() - loggers = tqdm_kwargs.pop('loggers', None) - tqdm_class = tqdm_kwargs.pop('tqdm_class', std_tqdm) - with tqdm_class(*args, **tqdm_kwargs) as pbar: - with logging_redirect_tqdm(loggers=loggers, tqdm_class=tqdm_class): - yield pbar diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/slack.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/slack.py deleted file mode 100644 index 9bca8ee..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/slack.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -Sends updates to a Slack app. - -Usage: ->>> from tqdm.contrib.slack import tqdm, trange ->>> for i in trange(10, token='{token}', channel='{channel}'): -... ... - -![screenshot](https://tqdm.github.io/img/screenshot-slack.png) -""" -import logging -from os import getenv - -try: - from slack_sdk import WebClient -except ImportError: - raise ImportError("Please `pip install slack-sdk`") - -from ..auto import tqdm as tqdm_auto -from .utils_worker import MonoWorker - -__author__ = {"github.com/": ["0x2b3bfa0", "casperdcl"]} -__all__ = ['SlackIO', 'tqdm_slack', 'tsrange', 'tqdm', 'trange'] - - -class SlackIO(MonoWorker): - """Non-blocking file-like IO using a Slack app.""" - def __init__(self, token, channel): - """Creates a new message in the given `channel`.""" - super().__init__() - self.client = WebClient(token=token) - self.text = self.__class__.__name__ - try: - self.message = self.client.chat_postMessage(channel=channel, text=self.text) - except Exception as e: - tqdm_auto.write(str(e)) - self.message = None - - def write(self, s): - """Replaces internal `message`'s text with `s`.""" - if not s: - s = "..." - s = s.replace('\r', '').strip() - if s == self.text: - return # skip duplicate message - message = self.message - if message is None: - return - self.text = s - try: - future = self.submit(self.client.chat_update, channel=message['channel'], - ts=message['ts'], text='`' + s + '`') - except Exception as e: - tqdm_auto.write(str(e)) - else: - return future - - -class tqdm_slack(tqdm_auto): - """ - Standard `tqdm.auto.tqdm` but also sends updates to a Slack app. - May take a few seconds to create (`__init__`). - - - create a Slack app with the `chat:write` scope & invite it to a - channel: - - copy the bot `{token}` & `{channel}` and paste below - >>> from tqdm.contrib.slack import tqdm, trange - >>> for i in tqdm(iterable, token='{token}', channel='{channel}'): - ... ... - """ - def __init__(self, *args, **kwargs): - """ - Parameters - ---------- - token : str, required. Slack token - [default: ${TQDM_SLACK_TOKEN}]. - channel : int, required. Slack channel - [default: ${TQDM_SLACK_CHANNEL}]. - mininterval : float, optional. - Minimum of [default: 1.5] to avoid rate limit. - - See `tqdm.auto.tqdm.__init__` for other parameters. - """ - if not kwargs.get('disable'): - kwargs = kwargs.copy() - logging.getLogger("HTTPClient").setLevel(logging.WARNING) - self.sio = SlackIO( - kwargs.pop('token', getenv("TQDM_SLACK_TOKEN")), - kwargs.pop('channel', getenv("TQDM_SLACK_CHANNEL"))) - kwargs['mininterval'] = max(1.5, kwargs.get('mininterval', 1.5)) - super().__init__(*args, **kwargs) - - def display(self, **kwargs): - super().display(**kwargs) - fmt = self.format_dict - if fmt.get('bar_format', None): - fmt['bar_format'] = fmt['bar_format'].replace( - '', '`{bar:10}`').replace('{bar}', '`{bar:10u}`') - else: - fmt['bar_format'] = '{l_bar}`{bar:10}`{r_bar}' - if fmt['ascii'] is False: - fmt['ascii'] = [":black_square:", ":small_blue_diamond:", ":large_blue_diamond:", - ":large_blue_square:"] - fmt['ncols'] = 336 - self.sio.write(self.format_meter(**fmt)) - - def clear(self, *args, **kwargs): - super().clear(*args, **kwargs) - if not self.disable: - self.sio.write("") - - -def tsrange(*args, **kwargs): - """Shortcut for `tqdm.contrib.slack.tqdm(range(*args), **kwargs)`.""" - return tqdm_slack(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_slack -trange = tsrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/telegram.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/telegram.py deleted file mode 100644 index 0191518..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/telegram.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -Sends updates to a Telegram bot. - -Usage: ->>> from tqdm.contrib.telegram import tqdm, trange ->>> for i in trange(10, token='{token}', chat_id='{chat_id}'): -... ... - -![screenshot](https://tqdm.github.io/img/screenshot-telegram.gif) -""" -from os import getenv -from warnings import warn - -from requests import Session - -from ..auto import tqdm as tqdm_auto -from ..std import TqdmWarning -from .utils_worker import MonoWorker - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['TelegramIO', 'tqdm_telegram', 'ttgrange', 'tqdm', 'trange'] - - -class TelegramIO(MonoWorker): - """Non-blocking file-like IO using a Telegram Bot.""" - API = 'https://api.telegram.org/bot' - - def __init__(self, token, chat_id): - """Creates a new message in the given `chat_id`.""" - super().__init__() - self.token = token - self.chat_id = chat_id - self.session = Session() - self.text = self.__class__.__name__ - self.message_id - - @property - def message_id(self): - if hasattr(self, '_message_id'): - return self._message_id - try: - res = self.session.post( - self.API + '%s/sendMessage' % self.token, - data={'text': '`' + self.text + '`', 'chat_id': self.chat_id, - 'parse_mode': 'MarkdownV2'}).json() - except Exception as e: - tqdm_auto.write(str(e)) - else: - if res.get('error_code') == 429: - warn("Creation rate limit: try increasing `mininterval`.", - TqdmWarning, stacklevel=2) - else: - self._message_id = res['result']['message_id'] - return self._message_id - - def write(self, s): - """Replaces internal `message_id`'s text with `s`.""" - if not s: - s = "..." - s = s.replace('\r', '').strip() - if s == self.text: - return # avoid duplicate message Bot error - message_id = self.message_id - if message_id is None: - return - self.text = s - try: - future = self.submit( - self.session.post, self.API + '%s/editMessageText' % self.token, - data={'text': '`' + s + '`', 'chat_id': self.chat_id, - 'message_id': message_id, 'parse_mode': 'MarkdownV2'}) - except Exception as e: - tqdm_auto.write(str(e)) - else: - return future - - def delete(self): - """Deletes internal `message_id`.""" - try: - future = self.submit( - self.session.post, self.API + '%s/deleteMessage' % self.token, - data={'chat_id': self.chat_id, 'message_id': self.message_id}) - except Exception as e: - tqdm_auto.write(str(e)) - else: - return future - - -class tqdm_telegram(tqdm_auto): - """ - Standard `tqdm.auto.tqdm` but also sends updates to a Telegram Bot. - May take a few seconds to create (`__init__`). - - - create a bot - - copy its `{token}` - - add the bot to a chat and send it a message such as `/start` - - go to to find out - the `{chat_id}` - - paste the `{token}` & `{chat_id}` below - - >>> from tqdm.contrib.telegram import tqdm, trange - >>> for i in tqdm(iterable, token='{token}', chat_id='{chat_id}'): - ... ... - """ - def __init__(self, *args, **kwargs): - """ - Parameters - ---------- - token : str, required. Telegram token - [default: ${TQDM_TELEGRAM_TOKEN}]. - chat_id : str, required. Telegram chat ID - [default: ${TQDM_TELEGRAM_CHAT_ID}]. - - See `tqdm.auto.tqdm.__init__` for other parameters. - """ - if not kwargs.get('disable'): - kwargs = kwargs.copy() - self.tgio = TelegramIO( - kwargs.pop('token', getenv('TQDM_TELEGRAM_TOKEN')), - kwargs.pop('chat_id', getenv('TQDM_TELEGRAM_CHAT_ID'))) - super().__init__(*args, **kwargs) - - def display(self, **kwargs): - super().display(**kwargs) - fmt = self.format_dict - if fmt.get('bar_format', None): - fmt['bar_format'] = fmt['bar_format'].replace( - '', '{bar:10u}').replace('{bar}', '{bar:10u}') - else: - fmt['bar_format'] = '{l_bar}{bar:10u}{r_bar}' - self.tgio.write(self.format_meter(**fmt)) - - def clear(self, *args, **kwargs): - super().clear(*args, **kwargs) - if not self.disable: - self.tgio.write("") - - def close(self): - if self.disable: - return - super().close() - if not (self.leave or (self.leave is None and self.pos == 0)): - self.tgio.delete() - - -def ttgrange(*args, **kwargs): - """Shortcut for `tqdm.contrib.telegram.tqdm(range(*args), **kwargs)`.""" - return tqdm_telegram(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_telegram -trange = ttgrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/utils_worker.py b/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/utils_worker.py deleted file mode 100644 index 2a03a2a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/contrib/utils_worker.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -IO/concurrency helpers for `tqdm.contrib`. -""" -from collections import deque -from concurrent.futures import ThreadPoolExecutor - -from ..auto import tqdm as tqdm_auto - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['MonoWorker'] - - -class MonoWorker(object): - """ - Supports one running task and one waiting task. - The waiting task is the most recent submitted (others are discarded). - """ - def __init__(self): - self.pool = ThreadPoolExecutor(max_workers=1) - self.futures = deque([], 2) - - def submit(self, func, *args, **kwargs): - """`func(*args, **kwargs)` may replace currently waiting task.""" - futures = self.futures - if len(futures) == futures.maxlen: - running = futures.popleft() - if not running.done(): - if len(futures): # clear waiting - waiting = futures.pop() - waiting.cancel() - futures.appendleft(running) # re-insert running - try: - waiting = self.pool.submit(func, *args, **kwargs) - except Exception as e: - tqdm_auto.write(str(e)) - else: - futures.append(waiting) - return waiting diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/dask.py b/extensions/.local/lib/python3.11/site-packages/tqdm/dask.py deleted file mode 100644 index 57f1b66..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/dask.py +++ /dev/null @@ -1,44 +0,0 @@ -from functools import partial - -from dask.callbacks import Callback - -from .auto import tqdm as tqdm_auto - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['TqdmCallback'] - - -class TqdmCallback(Callback): - """Dask callback for task progress.""" - def __init__(self, start=None, pretask=None, tqdm_class=tqdm_auto, - **tqdm_kwargs): - """ - Parameters - ---------- - tqdm_class : optional - `tqdm` class to use for bars [default: `tqdm.auto.tqdm`]. - tqdm_kwargs : optional - Any other arguments used for all bars. - """ - super().__init__(start=start, pretask=pretask) - if tqdm_kwargs: - tqdm_class = partial(tqdm_class, **tqdm_kwargs) - self.tqdm_class = tqdm_class - - def _start_state(self, _, state): - self.pbar = self.tqdm_class(total=sum( - len(state[k]) for k in ['ready', 'waiting', 'running', 'finished'])) - - def _posttask(self, *_, **__): - self.pbar.update() - - def _finish(self, *_, **__): - self.pbar.close() - - def display(self): - """Displays in the current cell in Notebooks.""" - container = getattr(self.bar, 'container', None) - if container is None: - return - from .notebook import display - display(container) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/gui.py b/extensions/.local/lib/python3.11/site-packages/tqdm/gui.py deleted file mode 100644 index cb52fb9..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/gui.py +++ /dev/null @@ -1,179 +0,0 @@ -""" -Matplotlib GUI progressbar decorator for iterators. - -Usage: ->>> from tqdm.gui import trange, tqdm ->>> for i in trange(10): -... ... -""" -# future division is important to divide integers and get as -# a result precise floating numbers (instead of truncated int) -import re -from warnings import warn - -# to inherit from the tqdm class -from .std import TqdmExperimentalWarning -from .std import tqdm as std_tqdm - -# import compatibility functions and utilities - -__author__ = {"github.com/": ["casperdcl", "lrq3000"]} -__all__ = ['tqdm_gui', 'tgrange', 'tqdm', 'trange'] - - -class tqdm_gui(std_tqdm): # pragma: no cover - """Experimental Matplotlib GUI version of tqdm!""" - # TODO: @classmethod: write() on GUI? - def __init__(self, *args, **kwargs): - from collections import deque - - import matplotlib as mpl - import matplotlib.pyplot as plt - kwargs = kwargs.copy() - kwargs['gui'] = True - colour = kwargs.pop('colour', 'g') - super().__init__(*args, **kwargs) - - if self.disable: - return - - warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2) - self.mpl = mpl - self.plt = plt - - # Remember if external environment uses toolbars - self.toolbar = self.mpl.rcParams['toolbar'] - self.mpl.rcParams['toolbar'] = 'None' - - self.mininterval = max(self.mininterval, 0.5) - self.fig, ax = plt.subplots(figsize=(9, 2.2)) - # self.fig.subplots_adjust(bottom=0.2) - total = self.__len__() # avoids TypeError on None #971 - if total is not None: - self.xdata = [] - self.ydata = [] - self.zdata = [] - else: - self.xdata = deque([]) - self.ydata = deque([]) - self.zdata = deque([]) - self.line1, = ax.plot(self.xdata, self.ydata, color='b') - self.line2, = ax.plot(self.xdata, self.zdata, color='k') - ax.set_ylim(0, 0.001) - if total is not None: - ax.set_xlim(0, 100) - ax.set_xlabel("percent") - self.fig.legend((self.line1, self.line2), ("cur", "est"), - loc='center right') - # progressbar - self.hspan = plt.axhspan(0, 0.001, xmin=0, xmax=0, color=colour) - else: - # ax.set_xlim(-60, 0) - ax.set_xlim(0, 60) - ax.invert_xaxis() - ax.set_xlabel("seconds") - ax.legend(("cur", "est"), loc='lower left') - ax.grid() - # ax.set_xlabel('seconds') - ax.set_ylabel((self.unit if self.unit else "it") + "/s") - if self.unit_scale: - plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0)) - ax.yaxis.get_offset_text().set_x(-0.15) - - # Remember if external environment is interactive - self.wasion = plt.isinteractive() - plt.ion() - self.ax = ax - - def close(self): - if self.disable: - return - - self.disable = True - - with self.get_lock(): - self._instances.remove(self) - - # Restore toolbars - self.mpl.rcParams['toolbar'] = self.toolbar - # Return to non-interactive mode - if not self.wasion: - self.plt.ioff() - if self.leave: - self.display() - else: - self.plt.close(self.fig) - - def clear(self, *_, **__): - pass - - def display(self, *_, **__): - n = self.n - cur_t = self._time() - elapsed = cur_t - self.start_t - delta_it = n - self.last_print_n - delta_t = cur_t - self.last_print_t - - # Inline due to multiple calls - total = self.total - xdata = self.xdata - ydata = self.ydata - zdata = self.zdata - ax = self.ax - line1 = self.line1 - line2 = self.line2 - hspan = getattr(self, 'hspan', None) - # instantaneous rate - y = delta_it / delta_t - # overall rate - z = n / elapsed - # update line data - xdata.append(n * 100.0 / total if total else cur_t) - ydata.append(y) - zdata.append(z) - - # Discard old values - # xmin, xmax = ax.get_xlim() - # if (not total) and elapsed > xmin * 1.1: - if (not total) and elapsed > 66: - xdata.popleft() - ydata.popleft() - zdata.popleft() - - ymin, ymax = ax.get_ylim() - if y > ymax or z > ymax: - ymax = 1.1 * y - ax.set_ylim(ymin, ymax) - ax.figure.canvas.draw() - - if total: - line1.set_data(xdata, ydata) - line2.set_data(xdata, zdata) - if hspan: - hspan.set_xy((0, ymin)) - hspan.set_height(ymax - ymin) - hspan.set_width(n / total) - else: - t_ago = [cur_t - i for i in xdata] - line1.set_data(t_ago, ydata) - line2.set_data(t_ago, zdata) - - d = self.format_dict - # remove {bar} - d['bar_format'] = (d['bar_format'] or "{l_bar}{r_bar}").replace( - "{bar}", "") - msg = self.format_meter(**d) - if '' in msg: - msg = "".join(re.split(r'\|?\|?', msg, maxsplit=1)) - ax.set_title(msg, fontname="DejaVu Sans Mono", fontsize=11) - self.plt.pause(1e-9) - - -def tgrange(*args, **kwargs): - """Shortcut for `tqdm.gui.tqdm(range(*args), **kwargs)`.""" - return tqdm_gui(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_gui -trange = tgrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/keras.py b/extensions/.local/lib/python3.11/site-packages/tqdm/keras.py deleted file mode 100644 index cce9467..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/keras.py +++ /dev/null @@ -1,122 +0,0 @@ -from copy import copy -from functools import partial - -from .auto import tqdm as tqdm_auto - -try: - import keras -except (ImportError, AttributeError) as e: - try: - from tensorflow import keras - except ImportError: - raise e -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['TqdmCallback'] - - -class TqdmCallback(keras.callbacks.Callback): - """Keras callback for epoch and batch progress.""" - @staticmethod - def bar2callback(bar, pop=None, delta=(lambda logs: 1)): - def callback(_, logs=None): - n = delta(logs) - if logs: - if pop: - logs = copy(logs) - [logs.pop(i, 0) for i in pop] - bar.set_postfix(logs, refresh=False) - bar.update(n) - - return callback - - def __init__(self, epochs=None, data_size=None, batch_size=None, verbose=1, - tqdm_class=tqdm_auto, **tqdm_kwargs): - """ - Parameters - ---------- - epochs : int, optional - data_size : int, optional - Number of training pairs. - batch_size : int, optional - Number of training pairs per batch. - verbose : int - 0: epoch, 1: batch (transient), 2: batch. [default: 1]. - Will be set to `0` unless both `data_size` and `batch_size` - are given. - tqdm_class : optional - `tqdm` class to use for bars [default: `tqdm.auto.tqdm`]. - tqdm_kwargs : optional - Any other arguments used for all bars. - """ - if tqdm_kwargs: - tqdm_class = partial(tqdm_class, **tqdm_kwargs) - self.tqdm_class = tqdm_class - self.epoch_bar = tqdm_class(total=epochs, unit='epoch') - self.on_epoch_end = self.bar2callback(self.epoch_bar) - if data_size and batch_size: - self.batches = batches = (data_size + batch_size - 1) // batch_size - else: - self.batches = batches = None - self.verbose = verbose - if verbose == 1: - self.batch_bar = tqdm_class(total=batches, unit='batch', leave=False) - self.on_batch_end = self.bar2callback( - self.batch_bar, pop=['batch', 'size'], - delta=lambda logs: logs.get('size', 1)) - - def on_train_begin(self, *_, **__): - params = self.params.get - auto_total = params('epochs', params('nb_epoch', None)) - if auto_total is not None and auto_total != self.epoch_bar.total: - self.epoch_bar.reset(total=auto_total) - - def on_epoch_begin(self, epoch, *_, **__): - if self.epoch_bar.n < epoch: - ebar = self.epoch_bar - ebar.n = ebar.last_print_n = ebar.initial = epoch - if self.verbose: - params = self.params.get - total = params('samples', params( - 'nb_sample', params('steps', None))) or self.batches - if self.verbose == 2: - if hasattr(self, 'batch_bar'): - self.batch_bar.close() - self.batch_bar = self.tqdm_class( - total=total, unit='batch', leave=True, - unit_scale=1 / (params('batch_size', 1) or 1)) - self.on_batch_end = self.bar2callback( - self.batch_bar, pop=['batch', 'size'], - delta=lambda logs: logs.get('size', 1)) - elif self.verbose == 1: - self.batch_bar.unit_scale = 1 / (params('batch_size', 1) or 1) - self.batch_bar.reset(total=total) - else: - raise KeyError('Unknown verbosity') - - def on_train_end(self, *_, **__): - if hasattr(self, 'batch_bar'): - self.batch_bar.close() - self.epoch_bar.close() - - def display(self): - """Displays in the current cell in Notebooks.""" - container = getattr(self.epoch_bar, 'container', None) - if container is None: - return - from .notebook import display - display(container) - batch_bar = getattr(self, 'batch_bar', None) - if batch_bar is not None: - display(batch_bar.container) - - @staticmethod - def _implements_train_batch_hooks(): - return True - - @staticmethod - def _implements_test_batch_hooks(): - return True - - @staticmethod - def _implements_predict_batch_hooks(): - return True diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/notebook.py b/extensions/.local/lib/python3.11/site-packages/tqdm/notebook.py deleted file mode 100644 index 77b91bd..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/notebook.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -IPython/Jupyter Notebook progressbar decorator for iterators. -Includes a default `range` iterator printing to `stderr`. - -Usage: ->>> from tqdm.notebook import trange, tqdm ->>> for i in trange(10): -... ... -""" -# import compatibility functions and utilities -import re -import sys -from html import escape -from weakref import proxy - -# to inherit from the tqdm class -from .std import tqdm as std_tqdm - -if True: # pragma: no cover - # import IPython/Jupyter base widget and display utilities - IPY = 0 - try: # IPython 4.x - import ipywidgets - IPY = 4 - except ImportError: # IPython 3.x / 2.x - IPY = 32 - import warnings - with warnings.catch_warnings(): - warnings.filterwarnings( - 'ignore', message=".*The `IPython.html` package has been deprecated.*") - try: - import IPython.html.widgets as ipywidgets # NOQA: F401 - except ImportError: - pass - - try: # IPython 4.x / 3.x - if IPY == 32: - from IPython.html.widgets import HTML - from IPython.html.widgets import FloatProgress as IProgress - from IPython.html.widgets import HBox - IPY = 3 - else: - from ipywidgets import HTML - from ipywidgets import FloatProgress as IProgress - from ipywidgets import HBox - except ImportError: - try: # IPython 2.x - from IPython.html.widgets import HTML - from IPython.html.widgets import ContainerWidget as HBox - from IPython.html.widgets import FloatProgressWidget as IProgress - IPY = 2 - except ImportError: - IPY = 0 - IProgress = None - HBox = object - - try: - from IPython.display import display # , clear_output - except ImportError: - pass - -__author__ = {"github.com/": ["lrq3000", "casperdcl", "alexanderkuk"]} -__all__ = ['tqdm_notebook', 'tnrange', 'tqdm', 'trange'] -WARN_NOIPYW = ("IProgress not found. Please update jupyter and ipywidgets." - " See https://ipywidgets.readthedocs.io/en/stable" - "/user_install.html") - - -class TqdmHBox(HBox): - """`ipywidgets.HBox` with a pretty representation""" - def _json_(self, pretty=None): - pbar = getattr(self, 'pbar', None) - if pbar is None: - return {} - d = pbar.format_dict - if pretty is not None: - d["ascii"] = not pretty - return d - - def __repr__(self, pretty=False): - pbar = getattr(self, 'pbar', None) - if pbar is None: - return super().__repr__() - return pbar.format_meter(**self._json_(pretty)) - - def _repr_pretty_(self, pp, *_, **__): - pp.text(self.__repr__(True)) - - -class tqdm_notebook(std_tqdm): - """ - Experimental IPython/Jupyter Notebook widget using tqdm! - """ - @staticmethod - def status_printer(_, total=None, desc=None, ncols=None): - """ - Manage the printing of an IPython/Jupyter Notebook progress bar widget. - """ - # Fallback to text bar if there's no total - # DEPRECATED: replaced with an 'info' style bar - # if not total: - # return super(tqdm_notebook, tqdm_notebook).status_printer(file) - - # fp = file - - # Prepare IPython progress bar - if IProgress is None: # #187 #451 #558 #872 - raise ImportError(WARN_NOIPYW) - if total: - pbar = IProgress(min=0, max=total) - else: # No total? Show info style bar with no progress tqdm status - pbar = IProgress(min=0, max=1) - pbar.value = 1 - pbar.bar_style = 'info' - if ncols is None: - pbar.layout.width = "20px" - - ltext = HTML() - rtext = HTML() - if desc: - ltext.value = desc - container = TqdmHBox(children=[ltext, pbar, rtext]) - # Prepare layout - if ncols is not None: # use default style of ipywidgets - # ncols could be 100, "100px", "100%" - ncols = str(ncols) # ipywidgets only accepts string - try: - if int(ncols) > 0: # isnumeric and positive - ncols += 'px' - except ValueError: - pass - pbar.layout.flex = '2' - container.layout.width = ncols - container.layout.display = 'inline-flex' - container.layout.flex_flow = 'row wrap' - - return container - - def display(self, msg=None, pos=None, - # additional signals - close=False, bar_style=None, check_delay=True): - # Note: contrary to native tqdm, msg='' does NOT clear bar - # goal is to keep all infos if error happens so user knows - # at which iteration the loop failed. - - # Clear previous output (really necessary?) - # clear_output(wait=1) - - if not msg and not close: - d = self.format_dict - # remove {bar} - d['bar_format'] = (d['bar_format'] or "{l_bar}{r_bar}").replace( - "{bar}", "") - msg = self.format_meter(**d) - - ltext, pbar, rtext = self.container.children - pbar.value = self.n - - if msg: - msg = msg.replace(' ', u'\u2007') # fix html space padding - # html escape special characters (like '&') - if '' in msg: - left, right = map(escape, re.split(r'\|?\|?', msg, maxsplit=1)) - else: - left, right = '', escape(msg) - - # Update description - ltext.value = left - # never clear the bar (signal: msg='') - if right: - rtext.value = right - - # Change bar style - if bar_style: - # Hack-ish way to avoid the danger bar_style being overridden by - # success because the bar gets closed after the error... - if pbar.bar_style != 'danger' or bar_style != 'success': - pbar.bar_style = bar_style - - # Special signal to close the bar - if close and pbar.bar_style != 'danger': # hide only if no error - try: - self.container.close() - except AttributeError: - self.container.visible = False - self.container.layout.visibility = 'hidden' # IPYW>=8 - - if check_delay and self.delay > 0 and not self.displayed: - display(self.container) - self.displayed = True - - @property - def colour(self): - if hasattr(self, 'container'): - return self.container.children[-2].style.bar_color - - @colour.setter - def colour(self, bar_color): - if hasattr(self, 'container'): - self.container.children[-2].style.bar_color = bar_color - - def __init__(self, *args, **kwargs): - """ - Supports the usual `tqdm.tqdm` parameters as well as those listed below. - - Parameters - ---------- - display : Whether to call `display(self.container)` immediately - [default: True]. - """ - kwargs = kwargs.copy() - # Setup default output - file_kwarg = kwargs.get('file', sys.stderr) - if file_kwarg is sys.stderr or file_kwarg is None: - kwargs['file'] = sys.stdout # avoid the red block in IPython - - # Initialize parent class + avoid printing by using gui=True - kwargs['gui'] = True - # convert disable = None to False - kwargs['disable'] = bool(kwargs.get('disable', False)) - colour = kwargs.pop('colour', None) - display_here = kwargs.pop('display', True) - super().__init__(*args, **kwargs) - if self.disable or not kwargs['gui']: - self.disp = lambda *_, **__: None - return - - # Get bar width - self.ncols = '100%' if self.dynamic_ncols else kwargs.get("ncols", None) - - # Replace with IPython progress bar display (with correct total) - unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1 - total = self.total * unit_scale if self.total else self.total - self.container = self.status_printer(self.fp, total, self.desc, self.ncols) - self.container.pbar = proxy(self) - self.displayed = False - if display_here and self.delay <= 0: - display(self.container) - self.displayed = True - self.disp = self.display - self.colour = colour - - # Print initial bar state - if not self.disable: - self.display(check_delay=False) - - def __iter__(self): - try: - it = super().__iter__() - for obj in it: - # return super(tqdm...) will not catch exception - yield obj - # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt - except: # NOQA - self.disp(bar_style='danger') - raise - # NB: don't `finally: close()` - # since this could be a shared bar which the user will `reset()` - - def update(self, n=1): - try: - return super().update(n=n) - # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt - except: # NOQA - # cannot catch KeyboardInterrupt when using manual tqdm - # as the interrupt will most likely happen on another statement - self.disp(bar_style='danger') - raise - # NB: don't `finally: close()` - # since this could be a shared bar which the user will `reset()` - - def close(self): - if self.disable: - return - super().close() - # Try to detect if there was an error or KeyboardInterrupt - # in manual mode: if n < total, things probably got wrong - if self.total and self.n < self.total: - self.disp(bar_style='danger', check_delay=False) - else: - if self.leave: - self.disp(bar_style='success', check_delay=False) - else: - self.disp(close=True, check_delay=False) - - def clear(self, *_, **__): - pass - - def reset(self, total=None): - """ - Resets to 0 iterations for repeated use. - - Consider combining with `leave=True`. - - Parameters - ---------- - total : int or float, optional. Total to use for the new bar. - """ - if self.disable: - return super().reset(total=total) - _, pbar, _ = self.container.children - pbar.bar_style = '' - if total is not None: - pbar.max = total - if not self.total and self.ncols is None: # no longer unknown total - pbar.layout.width = None # reset width - return super().reset(total=total) - - -def tnrange(*args, **kwargs): - """Shortcut for `tqdm.notebook.tqdm(range(*args), **kwargs)`.""" - return tqdm_notebook(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_notebook -trange = tnrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/rich.py b/extensions/.local/lib/python3.11/site-packages/tqdm/rich.py deleted file mode 100644 index 3d392ed..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/rich.py +++ /dev/null @@ -1,151 +0,0 @@ -""" -`rich.progress` decorator for iterators. - -Usage: ->>> from tqdm.rich import trange, tqdm ->>> for i in trange(10): -... ... -""" -from warnings import warn - -from rich.progress import ( - BarColumn, Progress, ProgressColumn, Text, TimeElapsedColumn, TimeRemainingColumn, filesize) - -from .std import TqdmExperimentalWarning -from .std import tqdm as std_tqdm - -__author__ = {"github.com/": ["casperdcl"]} -__all__ = ['tqdm_rich', 'trrange', 'tqdm', 'trange'] - - -class FractionColumn(ProgressColumn): - """Renders completed/total, e.g. '0.5/2.3 G'.""" - def __init__(self, unit_scale=False, unit_divisor=1000): - self.unit_scale = unit_scale - self.unit_divisor = unit_divisor - super().__init__() - - def render(self, task): - """Calculate common unit for completed and total.""" - completed = int(task.completed) - total = int(task.total) - if self.unit_scale: - unit, suffix = filesize.pick_unit_and_suffix( - total, - ["", "K", "M", "G", "T", "P", "E", "Z", "Y"], - self.unit_divisor, - ) - else: - unit, suffix = filesize.pick_unit_and_suffix(total, [""], 1) - precision = 0 if unit == 1 else 1 - return Text( - f"{completed/unit:,.{precision}f}/{total/unit:,.{precision}f} {suffix}", - style="progress.download") - - -class RateColumn(ProgressColumn): - """Renders human readable transfer speed.""" - def __init__(self, unit="", unit_scale=False, unit_divisor=1000): - self.unit = unit - self.unit_scale = unit_scale - self.unit_divisor = unit_divisor - super().__init__() - - def render(self, task): - """Show data transfer speed.""" - speed = task.speed - if speed is None: - return Text(f"? {self.unit}/s", style="progress.data.speed") - if self.unit_scale: - unit, suffix = filesize.pick_unit_and_suffix( - speed, - ["", "K", "M", "G", "T", "P", "E", "Z", "Y"], - self.unit_divisor, - ) - else: - unit, suffix = filesize.pick_unit_and_suffix(speed, [""], 1) - precision = 0 if unit == 1 else 1 - return Text(f"{speed/unit:,.{precision}f} {suffix}{self.unit}/s", - style="progress.data.speed") - - -class tqdm_rich(std_tqdm): # pragma: no cover - """Experimental rich.progress GUI version of tqdm!""" - # TODO: @classmethod: write()? - def __init__(self, *args, **kwargs): - """ - This class accepts the following parameters *in addition* to - the parameters accepted by `tqdm`. - - Parameters - ---------- - progress : tuple, optional - arguments for `rich.progress.Progress()`. - options : dict, optional - keyword arguments for `rich.progress.Progress()`. - """ - kwargs = kwargs.copy() - kwargs['gui'] = True - # convert disable = None to False - kwargs['disable'] = bool(kwargs.get('disable', False)) - progress = kwargs.pop('progress', None) - options = kwargs.pop('options', {}).copy() - super().__init__(*args, **kwargs) - - if self.disable: - return - - warn("rich is experimental/alpha", TqdmExperimentalWarning, stacklevel=2) - d = self.format_dict - if progress is None: - progress = ( - "[progress.description]{task.description}" - "[progress.percentage]{task.percentage:>4.0f}%", - BarColumn(bar_width=None), - FractionColumn( - unit_scale=d['unit_scale'], unit_divisor=d['unit_divisor']), - "[", TimeElapsedColumn(), "<", TimeRemainingColumn(), - ",", RateColumn(unit=d['unit'], unit_scale=d['unit_scale'], - unit_divisor=d['unit_divisor']), "]" - ) - options.setdefault('transient', not self.leave) - self._prog = Progress(*progress, **options) - self._prog.__enter__() - self._task_id = self._prog.add_task(self.desc or "", **d) - - def close(self): - if self.disable: - return - self.display() # print 100%, vis #1306 - super().close() - self._prog.__exit__(None, None, None) - - def clear(self, *_, **__): - pass - - def display(self, *_, **__): - if not hasattr(self, '_prog'): - return - self._prog.update(self._task_id, completed=self.n, description=self.desc) - - def reset(self, total=None): - """ - Resets to 0 iterations for repeated use. - - Parameters - ---------- - total : int or float, optional. Total to use for the new bar. - """ - if hasattr(self, '_prog'): - self._prog.reset(total=total) - super().reset(total=total) - - -def trrange(*args, **kwargs): - """Shortcut for `tqdm.rich.tqdm(range(*args), **kwargs)`.""" - return tqdm_rich(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_rich -trange = trrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/std.py b/extensions/.local/lib/python3.11/site-packages/tqdm/std.py deleted file mode 100644 index e91ad30..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/std.py +++ /dev/null @@ -1,1524 +0,0 @@ -""" -Customisable progressbar decorator for iterators. -Includes a default `range` iterator printing to `stderr`. - -Usage: ->>> from tqdm import trange, tqdm ->>> for i in trange(10): -... ... -""" -import sys -from collections import OrderedDict, defaultdict -from contextlib import contextmanager -from datetime import datetime, timedelta, timezone -from numbers import Number -from time import time -from warnings import warn -from weakref import WeakSet - -from ._monitor import TMonitor -from .utils import ( - CallbackIOWrapper, Comparable, DisableOnWriteError, FormatReplace, SimpleTextIOWrapper, - _is_ascii, _screen_shape_wrapper, _supports_unicode, _term_move_up, disp_len, disp_trim, - envwrap) - -__author__ = "https://github.com/tqdm/tqdm#contributions" -__all__ = ['tqdm', 'trange', - 'TqdmTypeError', 'TqdmKeyError', 'TqdmWarning', - 'TqdmExperimentalWarning', 'TqdmDeprecationWarning', - 'TqdmMonitorWarning'] - - -class TqdmTypeError(TypeError): - pass - - -class TqdmKeyError(KeyError): - pass - - -class TqdmWarning(Warning): - """base class for all tqdm warnings. - - Used for non-external-code-breaking errors, such as garbled printing. - """ - def __init__(self, msg, fp_write=None, *a, **k): - if fp_write is not None: - fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n') - else: - super().__init__(msg, *a, **k) - - -class TqdmExperimentalWarning(TqdmWarning, FutureWarning): - """beta feature, unstable API and behaviour""" - pass - - -class TqdmDeprecationWarning(TqdmWarning, DeprecationWarning): - # not suppressed if raised - pass - - -class TqdmMonitorWarning(TqdmWarning, RuntimeWarning): - """tqdm monitor errors which do not affect external functionality""" - pass - - -def TRLock(*args, **kwargs): - """threading RLock""" - try: - from threading import RLock - return RLock(*args, **kwargs) - except (ImportError, OSError): # pragma: no cover - pass - - -class TqdmDefaultWriteLock(object): - """ - Provide a default write lock for thread and multiprocessing safety. - Works only on platforms supporting `fork` (so Windows is excluded). - You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance - before forking in order for the write lock to work. - On Windows, you need to supply the lock from the parent to the children as - an argument to joblib or the parallelism lib you use. - """ - # global thread lock so no setup required for multithreading. - # NB: Do not create multiprocessing lock as it sets the multiprocessing - # context, disallowing `spawn()`/`forkserver()` - th_lock = TRLock() - - def __init__(self): - # Create global parallelism locks to avoid racing issues with parallel - # bars works only if fork available (Linux/MacOSX, but not Windows) - cls = type(self) - root_lock = cls.th_lock - if root_lock is not None: - root_lock.acquire() - cls.create_mp_lock() - self.locks = [lk for lk in [cls.mp_lock, cls.th_lock] if lk is not None] - if root_lock is not None: - root_lock.release() - - def acquire(self, *a, **k): - for lock in self.locks: - lock.acquire(*a, **k) - - def release(self): - for lock in self.locks[::-1]: # Release in inverse order of acquisition - lock.release() - - def __enter__(self): - self.acquire() - - def __exit__(self, *exc): - self.release() - - @classmethod - def create_mp_lock(cls): - if not hasattr(cls, 'mp_lock'): - try: - from multiprocessing import RLock - cls.mp_lock = RLock() - except (ImportError, OSError): # pragma: no cover - cls.mp_lock = None - - @classmethod - def create_th_lock(cls): - assert hasattr(cls, 'th_lock') - warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2) - - -class Bar(object): - """ - `str.format`-able bar with format specifiers: `[width][type]` - - - `width` - + unspecified (default): use `self.default_len` - + `int >= 0`: overrides `self.default_len` - + `int < 0`: subtract from `self.default_len` - - `type` - + `a`: ascii (`charset=self.ASCII` override) - + `u`: unicode (`charset=self.UTF` override) - + `b`: blank (`charset=" "` override) - """ - ASCII = " 123456789#" - UTF = u" " + u''.join(map(chr, range(0x258F, 0x2587, -1))) - BLANK = " " - COLOUR_RESET = '\x1b[0m' - COLOUR_RGB = '\x1b[38;2;%d;%d;%dm' - COLOURS = {'BLACK': '\x1b[30m', 'RED': '\x1b[31m', 'GREEN': '\x1b[32m', - 'YELLOW': '\x1b[33m', 'BLUE': '\x1b[34m', 'MAGENTA': '\x1b[35m', - 'CYAN': '\x1b[36m', 'WHITE': '\x1b[37m'} - - def __init__(self, frac, default_len=10, charset=UTF, colour=None): - if not 0 <= frac <= 1: - warn("clamping frac to range [0, 1]", TqdmWarning, stacklevel=2) - frac = max(0, min(1, frac)) - assert default_len > 0 - self.frac = frac - self.default_len = default_len - self.charset = charset - self.colour = colour - - @property - def colour(self): - return self._colour - - @colour.setter - def colour(self, value): - if not value: - self._colour = None - return - try: - if value.upper() in self.COLOURS: - self._colour = self.COLOURS[value.upper()] - elif value[0] == '#' and len(value) == 7: - self._colour = self.COLOUR_RGB % tuple( - int(i, 16) for i in (value[1:3], value[3:5], value[5:7])) - else: - raise KeyError - except (KeyError, AttributeError): - warn("Unknown colour (%s); valid choices: [hex (#00ff00), %s]" % ( - value, ", ".join(self.COLOURS)), - TqdmWarning, stacklevel=2) - self._colour = None - - def __format__(self, format_spec): - if format_spec: - _type = format_spec[-1].lower() - try: - charset = {'a': self.ASCII, 'u': self.UTF, 'b': self.BLANK}[_type] - except KeyError: - charset = self.charset - else: - format_spec = format_spec[:-1] - if format_spec: - N_BARS = int(format_spec) - if N_BARS < 0: - N_BARS += self.default_len - else: - N_BARS = self.default_len - else: - charset = self.charset - N_BARS = self.default_len - - nsyms = len(charset) - 1 - bar_length, frac_bar_length = divmod(int(self.frac * N_BARS * nsyms), nsyms) - - res = charset[-1] * bar_length - if bar_length < N_BARS: # whitespace padding - res = res + charset[frac_bar_length] + charset[0] * (N_BARS - bar_length - 1) - return self.colour + res + self.COLOUR_RESET if self.colour else res - - -class EMA(object): - """ - Exponential moving average: smoothing to give progressively lower - weights to older values. - - Parameters - ---------- - smoothing : float, optional - Smoothing factor in range [0, 1], [default: 0.3]. - Increase to give more weight to recent values. - Ranges from 0 (yields old value) to 1 (yields new value). - """ - def __init__(self, smoothing=0.3): - self.alpha = smoothing - self.last = 0 - self.calls = 0 - - def __call__(self, x=None): - """ - Parameters - ---------- - x : float - New value to include in EMA. - """ - beta = 1 - self.alpha - if x is not None: - self.last = self.alpha * x + beta * self.last - self.calls += 1 - return self.last / (1 - beta ** self.calls) if self.calls else self.last - - -class tqdm(Comparable): - """ - Decorate an iterable object, returning an iterator which acts exactly - like the original iterable, but prints a dynamically updating - progressbar every time a value is requested. - - Parameters - ---------- - iterable : iterable, optional - Iterable to decorate with a progressbar. - Leave blank to manually manage the updates. - desc : str, optional - Prefix for the progressbar. - total : int or float, optional - The number of expected iterations. If unspecified, - len(iterable) is used if possible. If float("inf") or as a last - resort, only basic progress statistics are displayed - (no ETA, no progressbar). - If `gui` is True and this parameter needs subsequent updating, - specify an initial arbitrary large positive number, - e.g. 9e9. - leave : bool, optional - If [default: True], keeps all traces of the progressbar - upon termination of iteration. - If `None`, will leave only if `position` is `0`. - file : `io.TextIOWrapper` or `io.StringIO`, optional - Specifies where to output the progress messages - (default: sys.stderr). Uses `file.write(str)` and `file.flush()` - methods. For encoding, see `write_bytes`. - ncols : int, optional - The width of the entire output message. If specified, - dynamically resizes the progressbar to stay within this bound. - If unspecified, attempts to use environment width. The - fallback is a meter width of 10 and no limit for the counter and - statistics. If 0, will not print any meter (only stats). - mininterval : float, optional - Minimum progress display update interval [default: 0.1] seconds. - maxinterval : float, optional - Maximum progress display update interval [default: 10] seconds. - Automatically adjusts `miniters` to correspond to `mininterval` - after long display update lag. Only works if `dynamic_miniters` - or monitor thread is enabled. - miniters : int or float, optional - Minimum progress display update interval, in iterations. - If 0 and `dynamic_miniters`, will automatically adjust to equal - `mininterval` (more CPU efficient, good for tight loops). - If > 0, will skip display of specified number of iterations. - Tweak this and `mininterval` to get very efficient loops. - If your progress is erratic with both fast and slow iterations - (network, skipping items, etc) you should set miniters=1. - ascii : bool or str, optional - If unspecified or False, use unicode (smooth blocks) to fill - the meter. The fallback is to use ASCII characters " 123456789#". - disable : bool, optional - Whether to disable the entire progressbar wrapper - [default: False]. If set to None, disable on non-TTY. - unit : str, optional - String that will be used to define the unit of each iteration - [default: it]. - unit_scale : bool or int or float, optional - If 1 or True, the number of iterations will be reduced/scaled - automatically and a metric prefix following the - International System of Units standard will be added - (kilo, mega, etc.) [default: False]. If any other non-zero - number, will scale `total` and `n`. - dynamic_ncols : bool, optional - If set, constantly alters `ncols` and `nrows` to the - environment (allowing for window resizes) [default: False]. - smoothing : float, optional - Exponential moving average smoothing factor for speed estimates - (ignored in GUI mode). Ranges from 0 (average speed) to 1 - (current/instantaneous speed) [default: 0.3]. - bar_format : str, optional - Specify a custom bar string formatting. May impact performance. - [default: '{l_bar}{bar}{r_bar}'], where - l_bar='{desc}: {percentage:3.0f}%|' and - r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' - '{rate_fmt}{postfix}]' - Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, - percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, - rate, rate_fmt, rate_noinv, rate_noinv_fmt, - rate_inv, rate_inv_fmt, postfix, unit_divisor, - remaining, remaining_s, eta. - Note that a trailing ": " is automatically removed after {desc} - if the latter is empty. - initial : int or float, optional - The initial counter value. Useful when restarting a progress - bar [default: 0]. If using float, consider specifying `{n:.3f}` - or similar in `bar_format`, or specifying `unit_scale`. - position : int, optional - Specify the line offset to print this bar (starting from 0) - Automatic if unspecified. - Useful to manage multiple bars at once (eg, from threads). - postfix : dict or *, optional - Specify additional stats to display at the end of the bar. - Calls `set_postfix(**postfix)` if possible (dict). - unit_divisor : float, optional - [default: 1000], ignored unless `unit_scale` is True. - write_bytes : bool, optional - Whether to write bytes. If (default: False) will write unicode. - lock_args : tuple, optional - Passed to `refresh` for intermediate output - (initialisation, iterating, and updating). - nrows : int, optional - The screen height. If specified, hides nested bars outside this - bound. If unspecified, attempts to use environment height. - The fallback is 20. - colour : str, optional - Bar colour (e.g. 'green', '#00ff00'). - delay : float, optional - Don't display until [default: 0] seconds have elapsed. - gui : bool, optional - WARNING: internal parameter - do not use. - Use tqdm.gui.tqdm(...) instead. If set, will attempt to use - matplotlib animations for a graphical output [default: False]. - - Returns - ------- - out : decorated iterator. - """ - - monitor_interval = 10 # set to 0 to disable the thread - monitor = None - _instances = WeakSet() - - @staticmethod - def format_sizeof(num, suffix='', divisor=1000): - """ - Formats a number (greater than unity) with SI Order of Magnitude - prefixes. - - Parameters - ---------- - num : float - Number ( >= 1) to format. - suffix : str, optional - Post-postfix [default: '']. - divisor : float, optional - Divisor between prefixes [default: 1000]. - - Returns - ------- - out : str - Number with Order of Magnitude SI unit postfix. - """ - for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']: - if abs(num) < 999.5: - if abs(num) < 99.95: - if abs(num) < 9.995: - return f'{num:1.2f}{unit}{suffix}' - return f'{num:2.1f}{unit}{suffix}' - return f'{num:3.0f}{unit}{suffix}' - num /= divisor - return f'{num:3.1f}Y{suffix}' - - @staticmethod - def format_interval(t): - """ - Formats a number of seconds as a clock time, [H:]MM:SS - - Parameters - ---------- - t : int - Number of seconds. - - Returns - ------- - out : str - [H:]MM:SS - """ - mins, s = divmod(int(t), 60) - h, m = divmod(mins, 60) - return f'{h:d}:{m:02d}:{s:02d}' if h else f'{m:02d}:{s:02d}' - - @staticmethod - def format_num(n): - """ - Intelligent scientific notation (.3g). - - Parameters - ---------- - n : int or float or Numeric - A Number. - - Returns - ------- - out : str - Formatted number. - """ - f = f'{n:.3g}'.replace('e+0', 'e+').replace('e-0', 'e-') - n = str(n) - return f if len(f) < len(n) else n - - @staticmethod - def status_printer(file): - """ - Manage the printing and in-place updating of a line of characters. - Note that if the string is longer than a line, then in-place - updating may not work (it will print a new line at each refresh). - """ - fp = file - fp_flush = getattr(fp, 'flush', lambda: None) # pragma: no cover - if fp in (sys.stderr, sys.stdout): - getattr(sys.stderr, 'flush', lambda: None)() - getattr(sys.stdout, 'flush', lambda: None)() - - def fp_write(s): - fp.write(str(s)) - fp_flush() - - last_len = [0] - - def print_status(s): - len_s = disp_len(s) - fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0))) - last_len[0] = len_s - - return print_status - - @staticmethod - def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False, unit='it', - unit_scale=False, rate=None, bar_format=None, postfix=None, - unit_divisor=1000, initial=0, colour=None, **extra_kwargs): - """ - Return a string-based progress bar given some parameters - - Parameters - ---------- - n : int or float - Number of finished iterations. - total : int or float - The expected total number of iterations. If meaningless (None), - only basic progress statistics are displayed (no ETA). - elapsed : float - Number of seconds passed since start. - ncols : int, optional - The width of the entire output message. If specified, - dynamically resizes `{bar}` to stay within this bound - [default: None]. If `0`, will not print any bar (only stats). - The fallback is `{bar:10}`. - prefix : str, optional - Prefix message (included in total width) [default: '']. - Use as {desc} in bar_format string. - ascii : bool, optional or str, optional - If not set, use unicode (smooth blocks) to fill the meter - [default: False]. The fallback is to use ASCII characters - " 123456789#". - unit : str, optional - The iteration unit [default: 'it']. - unit_scale : bool or int or float, optional - If 1 or True, the number of iterations will be printed with an - appropriate SI metric prefix (k = 10^3, M = 10^6, etc.) - [default: False]. If any other non-zero number, will scale - `total` and `n`. - rate : float, optional - Manual override for iteration rate. - If [default: None], uses n/elapsed. - bar_format : str, optional - Specify a custom bar string formatting. May impact performance. - [default: '{l_bar}{bar}{r_bar}'], where - l_bar='{desc}: {percentage:3.0f}%|' and - r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' - '{rate_fmt}{postfix}]' - Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, - percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, - rate, rate_fmt, rate_noinv, rate_noinv_fmt, - rate_inv, rate_inv_fmt, postfix, unit_divisor, - remaining, remaining_s, eta. - Note that a trailing ": " is automatically removed after {desc} - if the latter is empty. - postfix : *, optional - Similar to `prefix`, but placed at the end - (e.g. for additional stats). - Note: postfix is usually a string (not a dict) for this method, - and will if possible be set to postfix = ', ' + postfix. - However other types are supported (#382). - unit_divisor : float, optional - [default: 1000], ignored unless `unit_scale` is True. - initial : int or float, optional - The initial counter value [default: 0]. - colour : str, optional - Bar colour (e.g. 'green', '#00ff00'). - - Returns - ------- - out : Formatted meter and stats, ready to display. - """ - - # sanity check: total - if total and n >= (total + 0.5): # allow float imprecision (#849) - total = None - - # apply custom scale if necessary - if unit_scale and unit_scale not in (True, 1): - if total: - total *= unit_scale - n *= unit_scale - if rate: - rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt - unit_scale = False - - elapsed_str = tqdm.format_interval(elapsed) - - # if unspecified, attempt to use rate = average speed - # (we allow manual override since predicting time is an arcane art) - if rate is None and elapsed: - rate = (n - initial) / elapsed - inv_rate = 1 / rate if rate else None - format_sizeof = tqdm.format_sizeof - rate_noinv_fmt = ((format_sizeof(rate) if unit_scale else f'{rate:5.2f}') - if rate else '?') + unit + '/s' - rate_inv_fmt = ( - (format_sizeof(inv_rate) if unit_scale else f'{inv_rate:5.2f}') - if inv_rate else '?') + 's/' + unit - rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt - - if unit_scale: - n_fmt = format_sizeof(n, divisor=unit_divisor) - total_fmt = format_sizeof(total, divisor=unit_divisor) if total is not None else '?' - else: - n_fmt = str(n) - total_fmt = str(total) if total is not None else '?' - - try: - postfix = ', ' + postfix if postfix else '' - except TypeError: - pass - - remaining = (total - n) / rate if rate and total else 0 - remaining_str = tqdm.format_interval(remaining) if rate else '?' - try: - eta_dt = (datetime.now() + timedelta(seconds=remaining) - if rate and total else datetime.fromtimestamp(0, timezone.utc)) - except OverflowError: - eta_dt = datetime.max - - # format the stats displayed to the left and right sides of the bar - if prefix: - # old prefix setup work around - bool_prefix_colon_already = (prefix[-2:] == ": ") - l_bar = prefix if bool_prefix_colon_already else prefix + ": " - else: - l_bar = '' - - r_bar = f'| {n_fmt}/{total_fmt} [{elapsed_str}<{remaining_str}, {rate_fmt}{postfix}]' - - # Custom bar formatting - # Populate a dict with all available progress indicators - format_dict = { - # slight extension of self.format_dict - 'n': n, 'n_fmt': n_fmt, 'total': total, 'total_fmt': total_fmt, - 'elapsed': elapsed_str, 'elapsed_s': elapsed, - 'ncols': ncols, 'desc': prefix or '', 'unit': unit, - 'rate': inv_rate if inv_rate and inv_rate > 1 else rate, - 'rate_fmt': rate_fmt, 'rate_noinv': rate, - 'rate_noinv_fmt': rate_noinv_fmt, 'rate_inv': inv_rate, - 'rate_inv_fmt': rate_inv_fmt, - 'postfix': postfix, 'unit_divisor': unit_divisor, - 'colour': colour, - # plus more useful definitions - 'remaining': remaining_str, 'remaining_s': remaining, - 'l_bar': l_bar, 'r_bar': r_bar, 'eta': eta_dt, - **extra_kwargs} - - # total is known: we can predict some stats - if total: - # fractional and percentage progress - frac = n / total - percentage = frac * 100 - - l_bar += f'{percentage:3.0f}%|' - - if ncols == 0: - return l_bar[:-1] + r_bar[1:] - - format_dict.update(l_bar=l_bar) - if bar_format: - format_dict.update(percentage=percentage) - - # auto-remove colon for empty `{desc}` - if not prefix: - bar_format = bar_format.replace("{desc}: ", '') - else: - bar_format = "{l_bar}{bar}{r_bar}" - - full_bar = FormatReplace() - nobar = bar_format.format(bar=full_bar, **format_dict) - if not full_bar.format_called: - return nobar # no `{bar}`; nothing else to do - - # Formatting progress bar space available for bar's display - full_bar = Bar(frac, - max(1, ncols - disp_len(nobar)) if ncols else 10, - charset=Bar.ASCII if ascii is True else ascii or Bar.UTF, - colour=colour) - if not _is_ascii(full_bar.charset) and _is_ascii(bar_format): - bar_format = str(bar_format) - res = bar_format.format(bar=full_bar, **format_dict) - return disp_trim(res, ncols) if ncols else res - - elif bar_format: - # user-specified bar_format but no total - l_bar += '|' - format_dict.update(l_bar=l_bar, percentage=0) - full_bar = FormatReplace() - nobar = bar_format.format(bar=full_bar, **format_dict) - if not full_bar.format_called: - return nobar - full_bar = Bar(0, - max(1, ncols - disp_len(nobar)) if ncols else 10, - charset=Bar.BLANK, colour=colour) - res = bar_format.format(bar=full_bar, **format_dict) - return disp_trim(res, ncols) if ncols else res - else: - # no total: no progressbar, ETA, just progress stats - return (f'{(prefix + ": ") if prefix else ""}' - f'{n_fmt}{unit} [{elapsed_str}, {rate_fmt}{postfix}]') - - def __new__(cls, *_, **__): - instance = object.__new__(cls) - with cls.get_lock(): # also constructs lock if non-existent - cls._instances.add(instance) - # create monitoring thread - if cls.monitor_interval and (cls.monitor is None - or not cls.monitor.report()): - try: - cls.monitor = TMonitor(cls, cls.monitor_interval) - except Exception as e: # pragma: nocover - warn("tqdm:disabling monitor support" - " (monitor_interval = 0) due to:\n" + str(e), - TqdmMonitorWarning, stacklevel=2) - cls.monitor_interval = 0 - return instance - - @classmethod - def _get_free_pos(cls, instance=None): - """Skips specified instance.""" - positions = {abs(inst.pos) for inst in cls._instances - if inst is not instance and hasattr(inst, "pos")} - return min(set(range(len(positions) + 1)).difference(positions)) - - @classmethod - def _decr_instances(cls, instance): - """ - Remove from list and reposition another unfixed bar - to fill the new gap. - - This means that by default (where all nested bars are unfixed), - order is not maintained but screen flicker/blank space is minimised. - (tqdm<=4.44.1 moved ALL subsequent unfixed bars up.) - """ - with cls._lock: - try: - cls._instances.remove(instance) - except KeyError: - # if not instance.gui: # pragma: no cover - # raise - pass # py2: maybe magically removed already - # else: - if not instance.gui: - last = (instance.nrows or 20) - 1 - # find unfixed (`pos >= 0`) overflow (`pos >= nrows - 1`) - instances = list(filter( - lambda i: hasattr(i, "pos") and last <= i.pos, - cls._instances)) - # set first found to current `pos` - if instances: - inst = min(instances, key=lambda i: i.pos) - inst.clear(nolock=True) - inst.pos = abs(instance.pos) - - @classmethod - def write(cls, s, file=None, end="\n", nolock=False): - """Print a message via tqdm (without overlap with bars).""" - fp = file if file is not None else sys.stdout - with cls.external_write_mode(file=file, nolock=nolock): - # Write the message - fp.write(s) - fp.write(end) - - @classmethod - @contextmanager - def external_write_mode(cls, file=None, nolock=False): - """ - Disable tqdm within context and refresh tqdm when exits. - Useful when writing to standard output stream - """ - fp = file if file is not None else sys.stdout - - try: - if not nolock: - cls.get_lock().acquire() - # Clear all bars - inst_cleared = [] - for inst in getattr(cls, '_instances', []): - # Clear instance if in the target output file - # or if write output + tqdm output are both either - # sys.stdout or sys.stderr (because both are mixed in terminal) - if hasattr(inst, "start_t") and (inst.fp == fp or all( - f in (sys.stdout, sys.stderr) for f in (fp, inst.fp))): - inst.clear(nolock=True) - inst_cleared.append(inst) - yield - # Force refresh display of bars we cleared - for inst in inst_cleared: - inst.refresh(nolock=True) - finally: - if not nolock: - cls._lock.release() - - @classmethod - def set_lock(cls, lock): - """Set the global lock.""" - cls._lock = lock - - @classmethod - def get_lock(cls): - """Get the global lock. Construct it if it does not exist.""" - if not hasattr(cls, '_lock'): - cls._lock = TqdmDefaultWriteLock() - return cls._lock - - @classmethod - def pandas(cls, **tqdm_kwargs): - """ - Registers the current `tqdm` class with - pandas.core. - ( frame.DataFrame - | series.Series - | groupby.(generic.)DataFrameGroupBy - | groupby.(generic.)SeriesGroupBy - ).progress_apply - - A new instance will be created every time `progress_apply` is called, - and each instance will automatically `close()` upon completion. - - Parameters - ---------- - tqdm_kwargs : arguments for the tqdm instance - - Examples - -------- - >>> import pandas as pd - >>> import numpy as np - >>> from tqdm import tqdm - >>> from tqdm.gui import tqdm as tqdm_gui - >>> - >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) - >>> tqdm.pandas(ncols=50) # can use tqdm_gui, optional kwargs, etc - >>> # Now you can use `progress_apply` instead of `apply` - >>> df.groupby(0).progress_apply(lambda x: x**2) - - References - ---------- - - """ - from warnings import catch_warnings, simplefilter - - from pandas.core.frame import DataFrame - from pandas.core.series import Series - try: - with catch_warnings(): - simplefilter("ignore", category=FutureWarning) - from pandas import Panel - except ImportError: # pandas>=1.2.0 - Panel = None - Rolling, Expanding = None, None - try: # pandas>=1.0.0 - from pandas.core.window.rolling import _Rolling_and_Expanding - except ImportError: - try: # pandas>=0.18.0 - from pandas.core.window import _Rolling_and_Expanding - except ImportError: # pandas>=1.2.0 - try: # pandas>=1.2.0 - from pandas.core.window.expanding import Expanding - from pandas.core.window.rolling import Rolling - _Rolling_and_Expanding = Rolling, Expanding - except ImportError: # pragma: no cover - _Rolling_and_Expanding = None - try: # pandas>=0.25.0 - from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy - from pandas.core.groupby.generic import DataFrameGroupBy - except ImportError: # pragma: no cover - try: # pandas>=0.23.0 - from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy - except ImportError: - from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy - try: # pandas>=0.23.0 - from pandas.core.groupby.groupby import GroupBy - except ImportError: # pragma: no cover - from pandas.core.groupby import GroupBy - - try: # pandas>=0.23.0 - from pandas.core.groupby.groupby import PanelGroupBy - except ImportError: - try: - from pandas.core.groupby import PanelGroupBy - except ImportError: # pandas>=0.25.0 - PanelGroupBy = None - - tqdm_kwargs = tqdm_kwargs.copy() - deprecated_t = [tqdm_kwargs.pop('deprecated_t', None)] - - def inner_generator(df_function='apply'): - def inner(df, func, *args, **kwargs): - """ - Parameters - ---------- - df : (DataFrame|Series)[GroupBy] - Data (may be grouped). - func : function - To be applied on the (grouped) data. - **kwargs : optional - Transmitted to `df.apply()`. - """ - - # Precompute total iterations - total = tqdm_kwargs.pop("total", getattr(df, 'ngroups', None)) - if total is None: # not grouped - if df_function == 'applymap': - total = df.size - elif isinstance(df, Series): - total = len(df) - elif (_Rolling_and_Expanding is None or - not isinstance(df, _Rolling_and_Expanding)): - # DataFrame or Panel - axis = kwargs.get('axis', 0) - if axis == 'index': - axis = 0 - elif axis == 'columns': - axis = 1 - # when axis=0, total is shape[axis1] - total = df.size // df.shape[axis] - - # Init bar - if deprecated_t[0] is not None: - t = deprecated_t[0] - deprecated_t[0] = None - else: - t = cls(total=total, **tqdm_kwargs) - - if len(args) > 0: - # *args intentionally not supported (see #244, #299) - TqdmDeprecationWarning( - "Except func, normal arguments are intentionally" + - " not supported by" + - " `(DataFrame|Series|GroupBy).progress_apply`." + - " Use keyword arguments instead.", - fp_write=getattr(t.fp, 'write', sys.stderr.write)) - - try: # pandas>=1.3.0 - from pandas.core.common import is_builtin_func - except ImportError: - is_builtin_func = df._is_builtin_func - try: - func = is_builtin_func(func) - except TypeError: - pass - - # Define bar updating wrapper - def wrapper(*args, **kwargs): - # update tbar correctly - # it seems `pandas apply` calls `func` twice - # on the first column/row to decide whether it can - # take a fast or slow code path; so stop when t.total==t.n - t.update(n=1 if not t.total or t.n < t.total else 0) - return func(*args, **kwargs) - - # Apply the provided function (in **kwargs) - # on the df using our wrapper (which provides bar updating) - try: - return getattr(df, df_function)(wrapper, **kwargs) - finally: - t.close() - - return inner - - # Monkeypatch pandas to provide easy methods - # Enable custom tqdm progress in pandas! - Series.progress_apply = inner_generator() - SeriesGroupBy.progress_apply = inner_generator() - Series.progress_map = inner_generator('map') - SeriesGroupBy.progress_map = inner_generator('map') - - DataFrame.progress_apply = inner_generator() - DataFrameGroupBy.progress_apply = inner_generator() - DataFrame.progress_applymap = inner_generator('applymap') - DataFrame.progress_map = inner_generator('map') - DataFrameGroupBy.progress_map = inner_generator('map') - - if Panel is not None: - Panel.progress_apply = inner_generator() - if PanelGroupBy is not None: - PanelGroupBy.progress_apply = inner_generator() - - GroupBy.progress_apply = inner_generator() - GroupBy.progress_aggregate = inner_generator('aggregate') - GroupBy.progress_transform = inner_generator('transform') - - if Rolling is not None and Expanding is not None: - Rolling.progress_apply = inner_generator() - Expanding.progress_apply = inner_generator() - elif _Rolling_and_Expanding is not None: - _Rolling_and_Expanding.progress_apply = inner_generator() - - # override defaults via env vars - @envwrap("TQDM_", is_method=True, types={'total': float, 'ncols': int, 'miniters': float, - 'position': int, 'nrows': int}) - def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None, - ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None, - ascii=None, disable=False, unit='it', unit_scale=False, - dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0, - position=None, postfix=None, unit_divisor=1000, write_bytes=False, - lock_args=None, nrows=None, colour=None, delay=0.0, gui=False, - **kwargs): - """see tqdm.tqdm for arguments""" - if file is None: - file = sys.stderr - - if write_bytes: - # Despite coercing unicode into bytes, py2 sys.std* streams - # should have bytes written to them. - file = SimpleTextIOWrapper( - file, encoding=getattr(file, 'encoding', None) or 'utf-8') - - file = DisableOnWriteError(file, tqdm_instance=self) - - if disable is None and hasattr(file, "isatty") and not file.isatty(): - disable = True - - if total is None and iterable is not None: - try: - total = len(iterable) - except (TypeError, AttributeError): - total = None - if total == float("inf"): - # Infinite iterations, behave same as unknown - total = None - - if disable: - self.iterable = iterable - self.disable = disable - with self._lock: - self.pos = self._get_free_pos(self) - self._instances.remove(self) - self.n = initial - self.total = total - self.leave = leave - return - - if kwargs: - self.disable = True - with self._lock: - self.pos = self._get_free_pos(self) - self._instances.remove(self) - raise ( - TqdmDeprecationWarning( - "`nested` is deprecated and automated.\n" - "Use `position` instead for manual control.\n", - fp_write=getattr(file, 'write', sys.stderr.write)) - if "nested" in kwargs else - TqdmKeyError("Unknown argument(s): " + str(kwargs))) - - # Preprocess the arguments - if ( - (ncols is None or nrows is None) and (file in (sys.stderr, sys.stdout)) - ) or dynamic_ncols: # pragma: no cover - if dynamic_ncols: - dynamic_ncols = _screen_shape_wrapper() - if dynamic_ncols: - ncols, nrows = dynamic_ncols(file) - else: - _dynamic_ncols = _screen_shape_wrapper() - if _dynamic_ncols: - _ncols, _nrows = _dynamic_ncols(file) - if ncols is None: - ncols = _ncols - if nrows is None: - nrows = _nrows - - if miniters is None: - miniters = 0 - dynamic_miniters = True - else: - dynamic_miniters = False - - if mininterval is None: - mininterval = 0 - - if maxinterval is None: - maxinterval = 0 - - if ascii is None: - ascii = not _supports_unicode(file) - - if bar_format and ascii is not True and not _is_ascii(ascii): - # Convert bar format into unicode since terminal uses unicode - bar_format = str(bar_format) - - if smoothing is None: - smoothing = 0 - - # Store the arguments - self.iterable = iterable - self.desc = desc or '' - self.total = total - self.leave = leave - self.fp = file - self.ncols = ncols - self.nrows = nrows - self.mininterval = mininterval - self.maxinterval = maxinterval - self.miniters = miniters - self.dynamic_miniters = dynamic_miniters - self.ascii = ascii - self.disable = disable - self.unit = unit - self.unit_scale = unit_scale - self.unit_divisor = unit_divisor - self.initial = initial - self.lock_args = lock_args - self.delay = delay - self.gui = gui - self.dynamic_ncols = dynamic_ncols - self.smoothing = smoothing - self._ema_dn = EMA(smoothing) - self._ema_dt = EMA(smoothing) - self._ema_miniters = EMA(smoothing) - self.bar_format = bar_format - self.postfix = None - self.colour = colour - self._time = time - if postfix: - try: - self.set_postfix(refresh=False, **postfix) - except TypeError: - self.postfix = postfix - - # Init the iterations counters - self.last_print_n = initial - self.n = initial - - # if nested, at initial sp() call we replace '\r' by '\n' to - # not overwrite the outer progress bar - with self._lock: - # mark fixed positions as negative - self.pos = self._get_free_pos(self) if position is None else -position - - if not gui: - # Initialize the screen printer - self.sp = self.status_printer(self.fp) - if delay <= 0: - self.refresh(lock_args=self.lock_args) - - # Init the time counter - self.last_print_t = self._time() - # NB: Avoid race conditions by setting start_t at the very end of init - self.start_t = self.last_print_t - - def __bool__(self): - if self.total is not None: - return self.total > 0 - if self.iterable is None: - raise TypeError('bool() undefined when iterable == total == None') - return bool(self.iterable) - - def __len__(self): - return ( - self.total if self.iterable is None - else self.iterable.shape[0] if hasattr(self.iterable, "shape") - else len(self.iterable) if hasattr(self.iterable, "__len__") - else self.iterable.__length_hint__() if hasattr(self.iterable, "__length_hint__") - else getattr(self, "total", None)) - - def __reversed__(self): - try: - orig = self.iterable - except AttributeError: - raise TypeError("'tqdm' object is not reversible") - else: - self.iterable = reversed(self.iterable) - return self.__iter__() - finally: - self.iterable = orig - - def __contains__(self, item): - contains = getattr(self.iterable, '__contains__', None) - return contains(item) if contains is not None else item in self.__iter__() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - try: - self.close() - except AttributeError: - # maybe eager thread cleanup upon external error - if (exc_type, exc_value, traceback) == (None, None, None): - raise - warn("AttributeError ignored", TqdmWarning, stacklevel=2) - - def __del__(self): - self.close() - - def __str__(self): - return self.format_meter(**self.format_dict) - - @property - def _comparable(self): - return abs(getattr(self, "pos", 1 << 31)) - - def __hash__(self): - return id(self) - - def __iter__(self): - """Backward-compatibility to use: for x in tqdm(iterable)""" - - # Inlining instance variables as locals (speed optimisation) - iterable = self.iterable - - # If the bar is disabled, then just walk the iterable - # (note: keep this check outside the loop for performance) - if self.disable: - for obj in iterable: - yield obj - return - - mininterval = self.mininterval - last_print_t = self.last_print_t - last_print_n = self.last_print_n - min_start_t = self.start_t + self.delay - n = self.n - time = self._time - - try: - for obj in iterable: - yield obj - # Update and possibly print the progressbar. - # Note: does not call self.update(1) for speed optimisation. - n += 1 - - if n - last_print_n >= self.miniters: - cur_t = time() - dt = cur_t - last_print_t - if dt >= mininterval and cur_t >= min_start_t: - self.update(n - last_print_n) - last_print_n = self.last_print_n - last_print_t = self.last_print_t - finally: - self.n = n - self.close() - - def update(self, n=1): - """ - Manually update the progress bar, useful for streams - such as reading files. - E.g.: - >>> t = tqdm(total=filesize) # Initialise - >>> for current_buffer in stream: - ... ... - ... t.update(len(current_buffer)) - >>> t.close() - The last line is highly recommended, but possibly not necessary if - `t.update()` will be called in such a way that `filesize` will be - exactly reached and printed. - - Parameters - ---------- - n : int or float, optional - Increment to add to the internal counter of iterations - [default: 1]. If using float, consider specifying `{n:.3f}` - or similar in `bar_format`, or specifying `unit_scale`. - - Returns - ------- - out : bool or None - True if a `display()` was triggered. - """ - if self.disable: - return - - if n < 0: - self.last_print_n += n # for auto-refresh logic to work - self.n += n - - # check counter first to reduce calls to time() - if self.n - self.last_print_n >= self.miniters: - cur_t = self._time() - dt = cur_t - self.last_print_t - if dt >= self.mininterval and cur_t >= self.start_t + self.delay: - cur_t = self._time() - dn = self.n - self.last_print_n # >= n - if self.smoothing and dt and dn: - # EMA (not just overall average) - self._ema_dn(dn) - self._ema_dt(dt) - self.refresh(lock_args=self.lock_args) - if self.dynamic_miniters: - # If no `miniters` was specified, adjust automatically to the - # maximum iteration rate seen so far between two prints. - # e.g.: After running `tqdm.update(5)`, subsequent - # calls to `tqdm.update()` will only cause an update after - # at least 5 more iterations. - if self.maxinterval and dt >= self.maxinterval: - self.miniters = dn * (self.mininterval or self.maxinterval) / dt - elif self.smoothing: - # EMA miniters update - self.miniters = self._ema_miniters( - dn * (self.mininterval / dt if self.mininterval and dt - else 1)) - else: - # max iters between two prints - self.miniters = max(self.miniters, dn) - - # Store old values for next call - self.last_print_n = self.n - self.last_print_t = cur_t - return True - - def close(self): - """Cleanup and (if leave=False) close the progressbar.""" - if self.disable: - return - - # Prevent multiple closures - self.disable = True - - # decrement instance pos and remove from internal set - pos = abs(self.pos) - self._decr_instances(self) - - if self.last_print_t < self.start_t + self.delay: - # haven't ever displayed; nothing to clear - return - - # GUI mode - if getattr(self, 'sp', None) is None: - return - - # annoyingly, _supports_unicode isn't good enough - def fp_write(s): - self.fp.write(str(s)) - - try: - fp_write('') - except ValueError as e: - if 'closed' in str(e): - return - raise # pragma: no cover - - leave = pos == 0 if self.leave is None else self.leave - - with self._lock: - if leave: - # stats for overall rate (no weighted average) - self._ema_dt = lambda: None - self.display(pos=0) - fp_write('\n') - else: - # clear previous display - if self.display(msg='', pos=pos) and not pos: - fp_write('\r') - - def clear(self, nolock=False): - """Clear current bar display.""" - if self.disable: - return - - if not nolock: - self._lock.acquire() - pos = abs(self.pos) - if pos < (self.nrows or 20): - self.moveto(pos) - self.sp('') - self.fp.write('\r') # place cursor back at the beginning of line - self.moveto(-pos) - if not nolock: - self._lock.release() - - def refresh(self, nolock=False, lock_args=None): - """ - Force refresh the display of this bar. - - Parameters - ---------- - nolock : bool, optional - If `True`, does not lock. - If [default: `False`]: calls `acquire()` on internal lock. - lock_args : tuple, optional - Passed to internal lock's `acquire()`. - If specified, will only `display()` if `acquire()` returns `True`. - """ - if self.disable: - return - - if not nolock: - if lock_args: - if not self._lock.acquire(*lock_args): - return False - else: - self._lock.acquire() - self.display() - if not nolock: - self._lock.release() - return True - - def unpause(self): - """Restart tqdm timer from last print time.""" - if self.disable: - return - cur_t = self._time() - self.start_t += cur_t - self.last_print_t - self.last_print_t = cur_t - - def reset(self, total=None): - """ - Resets to 0 iterations for repeated use. - - Consider combining with `leave=True`. - - Parameters - ---------- - total : int or float, optional. Total to use for the new bar. - """ - self.n = 0 - if total is not None: - self.total = total - if self.disable: - return - self.last_print_n = 0 - self.last_print_t = self.start_t = self._time() - self._ema_dn = EMA(self.smoothing) - self._ema_dt = EMA(self.smoothing) - self._ema_miniters = EMA(self.smoothing) - self.refresh() - - def set_description(self, desc=None, refresh=True): - """ - Set/modify description of the progress bar. - - Parameters - ---------- - desc : str, optional - refresh : bool, optional - Forces refresh [default: True]. - """ - self.desc = desc + ': ' if desc else '' - if refresh: - self.refresh() - - def set_description_str(self, desc=None, refresh=True): - """Set/modify description without ': ' appended.""" - self.desc = desc or '' - if refresh: - self.refresh() - - def set_postfix(self, ordered_dict=None, refresh=True, **kwargs): - """ - Set/modify postfix (additional stats) - with automatic formatting based on datatype. - - Parameters - ---------- - ordered_dict : dict or OrderedDict, optional - refresh : bool, optional - Forces refresh [default: True]. - kwargs : dict, optional - """ - # Sort in alphabetical order to be more deterministic - postfix = OrderedDict([] if ordered_dict is None else ordered_dict) - for key in sorted(kwargs.keys()): - postfix[key] = kwargs[key] - # Preprocess stats according to datatype - for key in postfix.keys(): - # Number: limit the length of the string - if isinstance(postfix[key], Number): - postfix[key] = self.format_num(postfix[key]) - # Else for any other type, try to get the string conversion - elif not isinstance(postfix[key], str): - postfix[key] = str(postfix[key]) - # Else if it's a string, don't need to preprocess anything - # Stitch together to get the final postfix - self.postfix = ', '.join(key + '=' + postfix[key].strip() - for key in postfix.keys()) - if refresh: - self.refresh() - - def set_postfix_str(self, s='', refresh=True): - """ - Postfix without dictionary expansion, similar to prefix handling. - """ - self.postfix = str(s) - if refresh: - self.refresh() - - def moveto(self, n): - # TODO: private method - self.fp.write('\n' * n + _term_move_up() * -n) - getattr(self.fp, 'flush', lambda: None)() - - @property - def format_dict(self): - """Public API for read-only member access.""" - if self.disable and not hasattr(self, 'unit'): - return defaultdict(lambda: None, { - 'n': self.n, 'total': self.total, 'elapsed': 0, 'unit': 'it'}) - if self.dynamic_ncols: - self.ncols, self.nrows = self.dynamic_ncols(self.fp) - return { - 'n': self.n, 'total': self.total, - 'elapsed': self._time() - self.start_t if hasattr(self, 'start_t') else 0, - 'ncols': self.ncols, 'nrows': self.nrows, 'prefix': self.desc, - 'ascii': self.ascii, 'unit': self.unit, 'unit_scale': self.unit_scale, - 'rate': self._ema_dn() / self._ema_dt() if self._ema_dt() else None, - 'bar_format': self.bar_format, 'postfix': self.postfix, - 'unit_divisor': self.unit_divisor, 'initial': self.initial, - 'colour': self.colour} - - def display(self, msg=None, pos=None): - """ - Use `self.sp` to display `msg` in the specified `pos`. - - Consider overloading this function when inheriting to use e.g.: - `self.some_frontend(**self.format_dict)` instead of `self.sp`. - - Parameters - ---------- - msg : str, optional. What to display (default: `repr(self)`). - pos : int, optional. Position to `moveto` - (default: `abs(self.pos)`). - """ - if pos is None: - pos = abs(self.pos) - - nrows = self.nrows or 20 - if pos >= nrows - 1: - if pos >= nrows: - return False - if msg or msg is None: # override at `nrows - 1` - msg = " ... (more hidden) ..." - - if not hasattr(self, "sp"): - raise TqdmDeprecationWarning( - "Please use `tqdm.gui.tqdm(...)`" - " instead of `tqdm(..., gui=True)`\n", - fp_write=getattr(self.fp, 'write', sys.stderr.write)) - - if pos: - self.moveto(pos) - self.sp(self.__str__() if msg is None else msg) - if pos: - self.moveto(-pos) - return True - - @classmethod - @contextmanager - def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs): - """ - stream : file-like object. - method : str, "read" or "write". The result of `read()` and - the first argument of `write()` should have a `len()`. - - >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: - ... while True: - ... chunk = fobj.read(chunk_size) - ... if not chunk: - ... break - """ - with cls(total=total, **tqdm_kwargs) as t: - if bytes: - t.unit = "B" - t.unit_scale = True - t.unit_divisor = 1024 - yield CallbackIOWrapper(t.update, stream, method) - - -def trange(*args, **kwargs): - """Shortcut for tqdm(range(*args), **kwargs).""" - return tqdm(range(*args), **kwargs) diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/tk.py b/extensions/.local/lib/python3.11/site-packages/tqdm/tk.py deleted file mode 100644 index 788303c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/tk.py +++ /dev/null @@ -1,196 +0,0 @@ -""" -Tkinter GUI progressbar decorator for iterators. - -Usage: ->>> from tqdm.tk import trange, tqdm ->>> for i in trange(10): -... ... -""" -import re -import sys -import tkinter -import tkinter.ttk as ttk -from warnings import warn - -from .std import TqdmExperimentalWarning, TqdmWarning -from .std import tqdm as std_tqdm - -__author__ = {"github.com/": ["richardsheridan", "casperdcl"]} -__all__ = ['tqdm_tk', 'ttkrange', 'tqdm', 'trange'] - - -class tqdm_tk(std_tqdm): # pragma: no cover - """ - Experimental Tkinter GUI version of tqdm! - - Note: Window interactivity suffers if `tqdm_tk` is not running within - a Tkinter mainloop and values are generated infrequently. In this case, - consider calling `tqdm_tk.refresh()` frequently in the Tk thread. - """ - - # TODO: @classmethod: write()? - - def __init__(self, *args, **kwargs): - """ - This class accepts the following parameters *in addition* to - the parameters accepted by `tqdm`. - - Parameters - ---------- - grab : bool, optional - Grab the input across all windows of the process. - tk_parent : `tkinter.Wm`, optional - Parent Tk window. - cancel_callback : Callable, optional - Create a cancel button and set `cancel_callback` to be called - when the cancel or window close button is clicked. - """ - kwargs = kwargs.copy() - kwargs['gui'] = True - # convert disable = None to False - kwargs['disable'] = bool(kwargs.get('disable', False)) - self._warn_leave = 'leave' in kwargs - grab = kwargs.pop('grab', False) - tk_parent = kwargs.pop('tk_parent', None) - self._cancel_callback = kwargs.pop('cancel_callback', None) - super().__init__(*args, **kwargs) - - if self.disable: - return - - if tk_parent is None: # Discover parent widget - try: - tk_parent = tkinter._default_root - except AttributeError: - raise AttributeError( - "`tk_parent` required when using `tkinter.NoDefaultRoot()`") - if tk_parent is None: # use new default root window as display - self._tk_window = tkinter.Tk() - else: # some other windows already exist - self._tk_window = tkinter.Toplevel() - else: - self._tk_window = tkinter.Toplevel(tk_parent) - - warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2) - self._tk_dispatching = self._tk_dispatching_helper() - - self._tk_window.protocol("WM_DELETE_WINDOW", self.cancel) - self._tk_window.wm_title(self.desc) - self._tk_window.wm_attributes("-topmost", 1) - self._tk_window.after(0, lambda: self._tk_window.wm_attributes("-topmost", 0)) - self._tk_n_var = tkinter.DoubleVar(self._tk_window, value=0) - self._tk_text_var = tkinter.StringVar(self._tk_window) - pbar_frame = ttk.Frame(self._tk_window, padding=5) - pbar_frame.pack() - _tk_label = ttk.Label(pbar_frame, textvariable=self._tk_text_var, - wraplength=600, anchor="center", justify="center") - _tk_label.pack() - self._tk_pbar = ttk.Progressbar( - pbar_frame, variable=self._tk_n_var, length=450) - if self.total is not None: - self._tk_pbar.configure(maximum=self.total) - else: - self._tk_pbar.configure(mode="indeterminate") - self._tk_pbar.pack() - if self._cancel_callback is not None: - _tk_button = ttk.Button(pbar_frame, text="Cancel", command=self.cancel) - _tk_button.pack() - if grab: - self._tk_window.grab_set() - - def close(self): - if self.disable: - return - - self.disable = True - - with self.get_lock(): - self._instances.remove(self) - - def _close(): - self._tk_window.after('idle', self._tk_window.destroy) - if not self._tk_dispatching: - self._tk_window.update() - - self._tk_window.protocol("WM_DELETE_WINDOW", _close) - - # if leave is set but we are self-dispatching, the left window is - # totally unresponsive unless the user manually dispatches - if not self.leave: - _close() - elif not self._tk_dispatching: - if self._warn_leave: - warn("leave flag ignored if not in tkinter mainloop", - TqdmWarning, stacklevel=2) - _close() - - def clear(self, *_, **__): - pass - - def display(self, *_, **__): - self._tk_n_var.set(self.n) - d = self.format_dict - # remove {bar} - d['bar_format'] = (d['bar_format'] or "{l_bar}{r_bar}").replace( - "{bar}", "") - msg = self.format_meter(**d) - if '' in msg: - msg = "".join(re.split(r'\|?\|?', msg, maxsplit=1)) - self._tk_text_var.set(msg) - if not self._tk_dispatching: - self._tk_window.update() - - def set_description(self, desc=None, refresh=True): - self.set_description_str(desc, refresh) - - def set_description_str(self, desc=None, refresh=True): - self.desc = desc - if not self.disable: - self._tk_window.wm_title(desc) - if refresh and not self._tk_dispatching: - self._tk_window.update() - - def cancel(self): - """ - `cancel_callback()` followed by `close()` - when close/cancel buttons clicked. - """ - if self._cancel_callback is not None: - self._cancel_callback() - self.close() - - def reset(self, total=None): - """ - Resets to 0 iterations for repeated use. - - Parameters - ---------- - total : int or float, optional. Total to use for the new bar. - """ - if hasattr(self, '_tk_pbar'): - if total is None: - self._tk_pbar.configure(maximum=100, mode="indeterminate") - else: - self._tk_pbar.configure(maximum=total, mode="determinate") - super().reset(total=total) - - @staticmethod - def _tk_dispatching_helper(): - """determine if Tkinter mainloop is dispatching events""" - codes = {tkinter.mainloop.__code__, tkinter.Misc.mainloop.__code__} - for frame in sys._current_frames().values(): - while frame: - if frame.f_code in codes: - return True - frame = frame.f_back - return False - - -def ttkrange(*args, **kwargs): - """Shortcut for `tqdm.tk.tqdm(range(*args), **kwargs)`.""" - return tqdm_tk(range(*args), **kwargs) - - -# Aliases -tqdm = tqdm_tk -trange = ttkrange diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/tqdm.1 b/extensions/.local/lib/python3.11/site-packages/tqdm/tqdm.1 deleted file mode 100644 index b90ab4b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/tqdm.1 +++ /dev/null @@ -1,314 +0,0 @@ -.\" Automatically generated by Pandoc 1.19.2 -.\" -.TH "TQDM" "1" "2015\-2021" "tqdm User Manuals" "" -.hy -.SH NAME -.PP -tqdm \- fast, extensible progress bar for Python and CLI -.SH SYNOPSIS -.PP -tqdm [\f[I]options\f[]] -.SH DESCRIPTION -.PP -See . -Can be used as a pipe: -.IP -.nf -\f[C] -$\ #\ count\ lines\ of\ code -$\ cat\ *.py\ |\ tqdm\ |\ wc\ \-l -327it\ [00:00,\ 981773.38it/s] -327 - -$\ #\ find\ all\ files -$\ find\ .\ \-name\ "*.py"\ |\ tqdm\ |\ wc\ \-l -432it\ [00:00,\ 833842.30it/s] -432 - -#\ ...\ and\ more\ info -$\ find\ .\ \-name\ \[aq]*.py\[aq]\ \-exec\ wc\ \-l\ \\{}\ \\;\ \\ -\ \ |\ tqdm\ \-\-total\ 432\ \-\-unit\ files\ \-\-desc\ counting\ \\ -\ \ |\ awk\ \[aq]{\ sum\ +=\ $1\ };\ END\ {\ print\ sum\ }\[aq] -counting:\ 100%|█████████|\ 432/432\ [00:00<00:00,\ 794361.83files/s] -131998 -\f[] -.fi -.SH OPTIONS -.TP -.B \-h, \-\-help -Print this help and exit. -.RS -.RE -.TP -.B \-v, \-\-version -Print version and exit. -.RS -.RE -.TP -.B \-\-desc=\f[I]desc\f[] -str, optional. -Prefix for the progressbar. -.RS -.RE -.TP -.B \-\-total=\f[I]total\f[] -int or float, optional. -The number of expected iterations. -If unspecified, len(iterable) is used if possible. -If float("inf") or as a last resort, only basic progress statistics are -displayed (no ETA, no progressbar). -If \f[C]gui\f[] is True and this parameter needs subsequent updating, -specify an initial arbitrary large positive number, e.g. -9e9. -.RS -.RE -.TP -.B \-\-leave -bool, optional. -If [default: True], keeps all traces of the progressbar upon termination -of iteration. -If \f[C]None\f[], will leave only if \f[C]position\f[] is \f[C]0\f[]. -.RS -.RE -.TP -.B \-\-ncols=\f[I]ncols\f[] -int, optional. -The width of the entire output message. -If specified, dynamically resizes the progressbar to stay within this -bound. -If unspecified, attempts to use environment width. -The fallback is a meter width of 10 and no limit for the counter and -statistics. -If 0, will not print any meter (only stats). -.RS -.RE -.TP -.B \-\-mininterval=\f[I]mininterval\f[] -float, optional. -Minimum progress display update interval [default: 0.1] seconds. -.RS -.RE -.TP -.B \-\-maxinterval=\f[I]maxinterval\f[] -float, optional. -Maximum progress display update interval [default: 10] seconds. -Automatically adjusts \f[C]miniters\f[] to correspond to -\f[C]mininterval\f[] after long display update lag. -Only works if \f[C]dynamic_miniters\f[] or monitor thread is enabled. -.RS -.RE -.TP -.B \-\-miniters=\f[I]miniters\f[] -int or float, optional. -Minimum progress display update interval, in iterations. -If 0 and \f[C]dynamic_miniters\f[], will automatically adjust to equal -\f[C]mininterval\f[] (more CPU efficient, good for tight loops). -If > 0, will skip display of specified number of iterations. -Tweak this and \f[C]mininterval\f[] to get very efficient loops. -If your progress is erratic with both fast and slow iterations (network, -skipping items, etc) you should set miniters=1. -.RS -.RE -.TP -.B \-\-ascii=\f[I]ascii\f[] -bool or str, optional. -If unspecified or False, use unicode (smooth blocks) to fill the meter. -The fallback is to use ASCII characters " 123456789#". -.RS -.RE -.TP -.B \-\-disable -bool, optional. -Whether to disable the entire progressbar wrapper [default: False]. -If set to None, disable on non\-TTY. -.RS -.RE -.TP -.B \-\-unit=\f[I]unit\f[] -str, optional. -String that will be used to define the unit of each iteration [default: -it]. -.RS -.RE -.TP -.B \-\-unit\-scale=\f[I]unit_scale\f[] -bool or int or float, optional. -If 1 or True, the number of iterations will be reduced/scaled -automatically and a metric prefix following the International System of -Units standard will be added (kilo, mega, etc.) [default: False]. -If any other non\-zero number, will scale \f[C]total\f[] and \f[C]n\f[]. -.RS -.RE -.TP -.B \-\-dynamic\-ncols -bool, optional. -If set, constantly alters \f[C]ncols\f[] and \f[C]nrows\f[] to the -environment (allowing for window resizes) [default: False]. -.RS -.RE -.TP -.B \-\-smoothing=\f[I]smoothing\f[] -float, optional. -Exponential moving average smoothing factor for speed estimates (ignored -in GUI mode). -Ranges from 0 (average speed) to 1 (current/instantaneous speed) -[default: 0.3]. -.RS -.RE -.TP -.B \-\-bar\-format=\f[I]bar_format\f[] -str, optional. -Specify a custom bar string formatting. -May impact performance. -[default: \[aq]{l_bar}{bar}{r_bar}\[aq]], where l_bar=\[aq]{desc}: -{percentage:3.0f}%|\[aq] and r_bar=\[aq]| {n_fmt}/{total_fmt} -[{elapsed}<{remaining}, \[aq] \[aq]{rate_fmt}{postfix}]\[aq] Possible -vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, percentage, -elapsed, elapsed_s, ncols, nrows, desc, unit, rate, rate_fmt, -rate_noinv, rate_noinv_fmt, rate_inv, rate_inv_fmt, postfix, -unit_divisor, remaining, remaining_s, eta. -Note that a trailing ": " is automatically removed after {desc} if the -latter is empty. -.RS -.RE -.TP -.B \-\-initial=\f[I]initial\f[] -int or float, optional. -The initial counter value. -Useful when restarting a progress bar [default: 0]. -If using float, consider specifying \f[C]{n:.3f}\f[] or similar in -\f[C]bar_format\f[], or specifying \f[C]unit_scale\f[]. -.RS -.RE -.TP -.B \-\-position=\f[I]position\f[] -int, optional. -Specify the line offset to print this bar (starting from 0) Automatic if -unspecified. -Useful to manage multiple bars at once (eg, from threads). -.RS -.RE -.TP -.B \-\-postfix=\f[I]postfix\f[] -dict or *, optional. -Specify additional stats to display at the end of the bar. -Calls \f[C]set_postfix(**postfix)\f[] if possible (dict). -.RS -.RE -.TP -.B \-\-unit\-divisor=\f[I]unit_divisor\f[] -float, optional. -[default: 1000], ignored unless \f[C]unit_scale\f[] is True. -.RS -.RE -.TP -.B \-\-write\-bytes -bool, optional. -Whether to write bytes. -If (default: False) will write unicode. -.RS -.RE -.TP -.B \-\-lock\-args=\f[I]lock_args\f[] -tuple, optional. -Passed to \f[C]refresh\f[] for intermediate output (initialisation, -iterating, and updating). -.RS -.RE -.TP -.B \-\-nrows=\f[I]nrows\f[] -int, optional. -The screen height. -If specified, hides nested bars outside this bound. -If unspecified, attempts to use environment height. -The fallback is 20. -.RS -.RE -.TP -.B \-\-colour=\f[I]colour\f[] -str, optional. -Bar colour (e.g. -\[aq]green\[aq], \[aq]#00ff00\[aq]). -.RS -.RE -.TP -.B \-\-delay=\f[I]delay\f[] -float, optional. -Don\[aq]t display until [default: 0] seconds have elapsed. -.RS -.RE -.TP -.B \-\-delim=\f[I]delim\f[] -chr, optional. -Delimiting character [default: \[aq]\\n\[aq]]. -Use \[aq]\\0\[aq] for null. -N.B.: on Windows systems, Python converts \[aq]\\n\[aq] to -\[aq]\\r\\n\[aq]. -.RS -.RE -.TP -.B \-\-buf\-size=\f[I]buf_size\f[] -int, optional. -String buffer size in bytes [default: 256] used when \f[C]delim\f[] is -specified. -.RS -.RE -.TP -.B \-\-bytes -bool, optional. -If true, will count bytes, ignore \f[C]delim\f[], and default -\f[C]unit_scale\f[] to True, \f[C]unit_divisor\f[] to 1024, and -\f[C]unit\f[] to \[aq]B\[aq]. -.RS -.RE -.TP -.B \-\-tee -bool, optional. -If true, passes \f[C]stdin\f[] to both \f[C]stderr\f[] and -\f[C]stdout\f[]. -.RS -.RE -.TP -.B \-\-update -bool, optional. -If true, will treat input as newly elapsed iterations, i.e. -numbers to pass to \f[C]update()\f[]. -Note that this is slow (~2e5 it/s) since every input must be decoded as -a number. -.RS -.RE -.TP -.B \-\-update\-to -bool, optional. -If true, will treat input as total elapsed iterations, i.e. -numbers to assign to \f[C]self.n\f[]. -Note that this is slow (~2e5 it/s) since every input must be decoded as -a number. -.RS -.RE -.TP -.B \-\-null -bool, optional. -If true, will discard input (no stdout). -.RS -.RE -.TP -.B \-\-manpath=\f[I]manpath\f[] -str, optional. -Directory in which to install tqdm man pages. -.RS -.RE -.TP -.B \-\-comppath=\f[I]comppath\f[] -str, optional. -Directory in which to place tqdm completion. -.RS -.RE -.TP -.B \-\-log=\f[I]log\f[] -str, optional. -CRITICAL|FATAL|ERROR|WARN(ING)|[default: \[aq]INFO\[aq]]|DEBUG|NOTSET. -.RS -.RE -.SH AUTHORS -tqdm developers . diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/utils.py b/extensions/.local/lib/python3.11/site-packages/tqdm/utils.py deleted file mode 100644 index af3ec7d..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/utils.py +++ /dev/null @@ -1,399 +0,0 @@ -""" -General helpers required for `tqdm.std`. -""" -import os -import re -import sys -from functools import partial, partialmethod, wraps -from inspect import signature -# TODO consider using wcswidth third-party package for 0-width characters -from unicodedata import east_asian_width -from warnings import warn -from weakref import proxy - -_range, _unich, _unicode, _basestring = range, chr, str, str -CUR_OS = sys.platform -IS_WIN = any(CUR_OS.startswith(i) for i in ['win32', 'cygwin']) -IS_NIX = any(CUR_OS.startswith(i) for i in ['aix', 'linux', 'darwin', 'freebsd']) -RE_ANSI = re.compile(r"\x1b\[[;\d]*[A-Za-z]") - -try: - if IS_WIN: - import colorama - else: - raise ImportError -except ImportError: - colorama = None -else: - try: - colorama.init(strip=False) - except TypeError: - colorama.init() - - -def envwrap(prefix, types=None, is_method=False): - """ - Override parameter defaults via `os.environ[prefix + param_name]`. - Maps UPPER_CASE env vars map to lower_case param names. - camelCase isn't supported (because Windows ignores case). - - Precedence (highest first): - - - call (`foo(a=3)`) - - environ (`FOO_A=2`) - - signature (`def foo(a=1)`) - - Parameters - ---------- - prefix : str - Env var prefix, e.g. "FOO_" - types : dict, optional - Fallback mappings `{'param_name': type, ...}` if types cannot be - inferred from function signature. - Consider using `types=collections.defaultdict(lambda: ast.literal_eval)`. - is_method : bool, optional - Whether to use `functools.partialmethod`. If (default: False) use `functools.partial`. - - Examples - -------- - ``` - $ cat foo.py - from tqdm.utils import envwrap - @envwrap("FOO_") - def test(a=1, b=2, c=3): - print(f"received: a={a}, b={b}, c={c}") - - $ FOO_A=42 FOO_C=1337 python -c 'import foo; foo.test(c=99)' - received: a=42, b=2, c=99 - ``` - """ - if types is None: - types = {} - i = len(prefix) - env_overrides = {k[i:].lower(): v for k, v in os.environ.items() if k.startswith(prefix)} - part = partialmethod if is_method else partial - - def wrap(func): - params = signature(func).parameters - # ignore unknown env vars - overrides = {k: v for k, v in env_overrides.items() if k in params} - # infer overrides' `type`s - for k in overrides: - param = params[k] - if param.annotation is not param.empty: # typehints - for typ in getattr(param.annotation, '__args__', (param.annotation,)): - try: - overrides[k] = typ(overrides[k]) - except Exception: - pass - else: - break - elif param.default is not None: # type of default value - overrides[k] = type(param.default)(overrides[k]) - else: - try: # `types` fallback - overrides[k] = types[k](overrides[k]) - except KeyError: # keep unconverted (`str`) - pass - return part(func, **overrides) - return wrap - - -class FormatReplace(object): - """ - >>> a = FormatReplace('something') - >>> f"{a:5d}" - 'something' - """ # NOQA: P102 - def __init__(self, replace=''): - self.replace = replace - self.format_called = 0 - - def __format__(self, _): - self.format_called += 1 - return self.replace - - -class Comparable(object): - """Assumes child has self._comparable attr/@property""" - def __lt__(self, other): - return self._comparable < other._comparable - - def __le__(self, other): - return (self < other) or (self == other) - - def __eq__(self, other): - return self._comparable == other._comparable - - def __ne__(self, other): - return not self == other - - def __gt__(self, other): - return not self <= other - - def __ge__(self, other): - return not self < other - - -class ObjectWrapper(object): - def __getattr__(self, name): - return getattr(self._wrapped, name) - - def __setattr__(self, name, value): - return setattr(self._wrapped, name, value) - - def wrapper_getattr(self, name): - """Actual `self.getattr` rather than self._wrapped.getattr""" - try: - return object.__getattr__(self, name) - except AttributeError: # py2 - return getattr(self, name) - - def wrapper_setattr(self, name, value): - """Actual `self.setattr` rather than self._wrapped.setattr""" - return object.__setattr__(self, name, value) - - def __init__(self, wrapped): - """ - Thin wrapper around a given object - """ - self.wrapper_setattr('_wrapped', wrapped) - - -class SimpleTextIOWrapper(ObjectWrapper): - """ - Change only `.write()` of the wrapped object by encoding the passed - value and passing the result to the wrapped object's `.write()` method. - """ - # pylint: disable=too-few-public-methods - def __init__(self, wrapped, encoding): - super().__init__(wrapped) - self.wrapper_setattr('encoding', encoding) - - def write(self, s): - """ - Encode `s` and pass to the wrapped object's `.write()` method. - """ - return self._wrapped.write(s.encode(self.wrapper_getattr('encoding'))) - - def __eq__(self, other): - return self._wrapped == getattr(other, '_wrapped', other) - - -class DisableOnWriteError(ObjectWrapper): - """ - Disable the given `tqdm_instance` upon `write()` or `flush()` errors. - """ - @staticmethod - def disable_on_exception(tqdm_instance, func): - """ - Quietly set `tqdm_instance.miniters=inf` if `func` raises `errno=5`. - """ - tqdm_instance = proxy(tqdm_instance) - - def inner(*args, **kwargs): - try: - return func(*args, **kwargs) - except OSError as e: - if e.errno != 5: - raise - try: - tqdm_instance.miniters = float('inf') - except ReferenceError: - pass - except ValueError as e: - if 'closed' not in str(e): - raise - try: - tqdm_instance.miniters = float('inf') - except ReferenceError: - pass - return inner - - def __init__(self, wrapped, tqdm_instance): - super().__init__(wrapped) - if hasattr(wrapped, 'write'): - self.wrapper_setattr( - 'write', self.disable_on_exception(tqdm_instance, wrapped.write)) - if hasattr(wrapped, 'flush'): - self.wrapper_setattr( - 'flush', self.disable_on_exception(tqdm_instance, wrapped.flush)) - - def __eq__(self, other): - return self._wrapped == getattr(other, '_wrapped', other) - - -class CallbackIOWrapper(ObjectWrapper): - def __init__(self, callback, stream, method="read"): - """ - Wrap a given `file`-like object's `read()` or `write()` to report - lengths to the given `callback` - """ - super().__init__(stream) - func = getattr(stream, method) - if method == "write": - @wraps(func) - def write(data, *args, **kwargs): - res = func(data, *args, **kwargs) - callback(len(data)) - return res - self.wrapper_setattr('write', write) - elif method == "read": - @wraps(func) - def read(*args, **kwargs): - data = func(*args, **kwargs) - callback(len(data)) - return data - self.wrapper_setattr('read', read) - else: - raise KeyError("Can only wrap read/write methods") - - -def _is_utf(encoding): - try: - u'\u2588\u2589'.encode(encoding) - except UnicodeEncodeError: - return False - except Exception: - try: - return encoding.lower().startswith('utf-') or ('U8' == encoding) - except Exception: - return False - else: - return True - - -def _supports_unicode(fp): - try: - return _is_utf(fp.encoding) - except AttributeError: - return False - - -def _is_ascii(s): - if isinstance(s, str): - for c in s: - if ord(c) > 255: - return False - return True - return _supports_unicode(s) - - -def _screen_shape_wrapper(): # pragma: no cover - """ - Return a function which returns console dimensions (width, height). - Supported: linux, osx, windows, cygwin. - """ - _screen_shape = None - if IS_WIN: - _screen_shape = _screen_shape_windows - if _screen_shape is None: - _screen_shape = _screen_shape_tput - if IS_NIX: - _screen_shape = _screen_shape_linux - return _screen_shape - - -def _screen_shape_windows(fp): # pragma: no cover - try: - import struct - from ctypes import create_string_buffer, windll - from sys import stdin, stdout - - io_handle = -12 # assume stderr - if fp == stdin: - io_handle = -10 - elif fp == stdout: - io_handle = -11 - - h = windll.kernel32.GetStdHandle(io_handle) - csbi = create_string_buffer(22) - res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) - if res: - (_bufx, _bufy, _curx, _cury, _wattr, left, top, right, bottom, - _maxx, _maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) - return right - left, bottom - top # +1 - except Exception: # nosec - pass - return None, None - - -def _screen_shape_tput(*_): # pragma: no cover - """cygwin xterm (windows)""" - try: - import shlex - from subprocess import check_call # nosec - return [int(check_call(shlex.split('tput ' + i))) - 1 - for i in ('cols', 'lines')] - except Exception: # nosec - pass - return None, None - - -def _screen_shape_linux(fp): # pragma: no cover - - try: - from array import array - from fcntl import ioctl - from termios import TIOCGWINSZ - except ImportError: - return None, None - else: - try: - rows, cols = array('h', ioctl(fp, TIOCGWINSZ, '\0' * 8))[:2] - return cols, rows - except Exception: - try: - return [int(os.environ[i]) - 1 for i in ("COLUMNS", "LINES")] - except (KeyError, ValueError): - return None, None - - -def _environ_cols_wrapper(): # pragma: no cover - """ - Return a function which returns console width. - Supported: linux, osx, windows, cygwin. - """ - warn("Use `_screen_shape_wrapper()(file)[0]` instead of" - " `_environ_cols_wrapper()(file)`", DeprecationWarning, stacklevel=2) - shape = _screen_shape_wrapper() - if not shape: - return None - - @wraps(shape) - def inner(fp): - return shape(fp)[0] - - return inner - - -def _term_move_up(): # pragma: no cover - return '' if (os.name == 'nt') and (colorama is None) else '\x1b[A' - - -def _text_width(s): - return sum(2 if east_asian_width(ch) in 'FW' else 1 for ch in str(s)) - - -def disp_len(data): - """ - Returns the real on-screen length of a string which may contain - ANSI control codes and wide chars. - """ - return _text_width(RE_ANSI.sub('', data)) - - -def disp_trim(data, length): - """ - Trim a string which may contain ANSI control characters. - """ - if len(data) == disp_len(data): - return data[:length] - - ansi_present = bool(RE_ANSI.search(data)) - while disp_len(data) > length: # carefully delete one char at a time - data = data[:-1] - if ansi_present and bool(RE_ANSI.search(data)): - # assume ANSI reset is required - return data if data.endswith("\033[0m") else data + "\033[0m" - return data diff --git a/extensions/.local/lib/python3.11/site-packages/tqdm/version.py b/extensions/.local/lib/python3.11/site-packages/tqdm/version.py deleted file mode 100644 index 11cbaea..0000000 --- a/extensions/.local/lib/python3.11/site-packages/tqdm/version.py +++ /dev/null @@ -1,9 +0,0 @@ -"""`tqdm` version detector. Precedence: installed dist, git, 'UNKNOWN'.""" -try: - from ._dist_ver import __version__ -except ImportError: - try: - from setuptools_scm import get_version - __version__ = get_version(root='..', relative_to=__file__) - except (ImportError, LookupError): - __version__ = "UNKNOWN" diff --git a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/METADATA deleted file mode 100644 index 4b0732f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/METADATA +++ /dev/null @@ -1,68 +0,0 @@ -Metadata-Version: 2.4 -Name: typing_extensions -Version: 4.13.2 -Summary: Backported and Experimental Type Hints for Python 3.8+ -Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing -Author-email: "Guido van Rossum, Jukka Lehtosalo, Åukasz Langa, Michael Lee" -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-Expression: PSF-2.0 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Topic :: Software Development -License-File: LICENSE -Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues -Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md -Project-URL: Documentation, https://typing-extensions.readthedocs.io/ -Project-URL: Home, https://github.com/python/typing_extensions -Project-URL: Q & A, https://github.com/python/typing/discussions -Project-URL: Repository, https://github.com/python/typing_extensions - -# Typing Extensions - -[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) - -[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – -[PyPI](https://pypi.org/project/typing-extensions/) - -## Overview - -The `typing_extensions` module serves two related purposes: - -- Enable use of new type system features on older Python versions. For example, - `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows - users on previous Python versions to use it too. -- Enable experimentation with new type system PEPs before they are accepted and - added to the `typing` module. - -`typing_extensions` is treated specially by static type checkers such as -mypy and pyright. Objects defined in `typing_extensions` are treated the same -way as equivalent forms in `typing`. - -`typing_extensions` uses -[Semantic Versioning](https://semver.org/). The -major version will be incremented only for backwards-incompatible changes. -Therefore, it's safe to depend -on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`, -where `x.y` is the first version that includes all features you need. - -## Included items - -See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a -complete listing of module contents. - -## Contributing - -See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) -for how to contribute to `typing_extensions`. - diff --git a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/RECORD deleted file mode 100644 index 1f2f82b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/RECORD +++ /dev/null @@ -1,5 +0,0 @@ -typing_extensions.py,sha256=o48qcATlT6qQcRLzOvazSjPXHU0nCbw5LShwl0jrtag,172654 -typing_extensions-4.13.2.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 -typing_extensions-4.13.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -typing_extensions-4.13.2.dist-info/METADATA,sha256=3Q3zz7ibkx8jTCcEQi4tw9kRURQwuy3f3_Y7Wc7T6LM,2994 -typing_extensions-4.13.2.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/licenses/LICENSE b/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/licenses/LICENSE deleted file mode 100644 index f26bcf4..0000000 --- a/extensions/.local/lib/python3.11/site-packages/typing_extensions-4.13.2.dist-info/licenses/LICENSE +++ /dev/null @@ -1,279 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations, which became -Zope Corporation. In 2001, the Python Software Foundation (PSF, see -https://www.python.org/psf/) was formed, a non-profit organization -created specifically to own Python-related Intellectual Property. -Zope Corporation was a sponsoring member of the PSF. - -All Python releases are Open Source (see https://opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2 and above 2.1.1 2001-now PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -Python software and documentation are licensed under the -Python Software Foundation License Version 2. - -Starting with Python 3.8.6, examples, recipes, and other code in -the documentation are dual licensed under the PSF License Version 2 -and the Zero-Clause BSD license. - -Some software incorporated into Python is under different licenses. -The licenses are listed with code falling under that license. - - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ----------------------------------------------------------------------- - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/extensions/.local/lib/python3.11/site-packages/typing_extensions.py b/extensions/.local/lib/python3.11/site-packages/typing_extensions.py deleted file mode 100644 index fa89c83..0000000 --- a/extensions/.local/lib/python3.11/site-packages/typing_extensions.py +++ /dev/null @@ -1,4584 +0,0 @@ -import abc -import builtins -import collections -import collections.abc -import contextlib -import enum -import functools -import inspect -import keyword -import operator -import sys -import types as _types -import typing -import warnings - -__all__ = [ - # Super-special typing primitives. - 'Any', - 'ClassVar', - 'Concatenate', - 'Final', - 'LiteralString', - 'ParamSpec', - 'ParamSpecArgs', - 'ParamSpecKwargs', - 'Self', - 'Type', - 'TypeVar', - 'TypeVarTuple', - 'Unpack', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'Buffer', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'NamedTuple', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsAbs', - 'SupportsBytes', - 'SupportsComplex', - 'SupportsFloat', - 'SupportsIndex', - 'SupportsInt', - 'SupportsRound', - - # One-off things. - 'Annotated', - 'assert_never', - 'assert_type', - 'clear_overloads', - 'dataclass_transform', - 'deprecated', - 'Doc', - 'evaluate_forward_ref', - 'get_overloads', - 'final', - 'Format', - 'get_annotations', - 'get_args', - 'get_origin', - 'get_original_bases', - 'get_protocol_members', - 'get_type_hints', - 'IntVar', - 'is_protocol', - 'is_typeddict', - 'Literal', - 'NewType', - 'overload', - 'override', - 'Protocol', - 'reveal_type', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeAliasType', - 'TypeForm', - 'TypeGuard', - 'TypeIs', - 'TYPE_CHECKING', - 'Never', - 'NoReturn', - 'ReadOnly', - 'Required', - 'NotRequired', - 'NoDefault', - 'NoExtraItems', - - # Pure aliases, have always been in typing - 'AbstractSet', - 'AnyStr', - 'BinaryIO', - 'Callable', - 'Collection', - 'Container', - 'Dict', - 'ForwardRef', - 'FrozenSet', - 'Generator', - 'Generic', - 'Hashable', - 'IO', - 'ItemsView', - 'Iterable', - 'Iterator', - 'KeysView', - 'List', - 'Mapping', - 'MappingView', - 'Match', - 'MutableMapping', - 'MutableSequence', - 'MutableSet', - 'Optional', - 'Pattern', - 'Reversible', - 'Sequence', - 'Set', - 'Sized', - 'TextIO', - 'Tuple', - 'Union', - 'ValuesView', - 'cast', - 'no_type_check', - 'no_type_check_decorator', -] - -# for backward compatibility -PEP_560 = True -GenericMeta = type -_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta") - -# Added with bpo-45166 to 3.10.1+ and some 3.9 versions -_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__ - -# The functions below are modified copies of typing internal helpers. -# They are needed by _ProtocolMeta and they provide support for PEP 646. - - -class _Sentinel: - def __repr__(self): - return "" - - -_marker = _Sentinel() - - -if sys.version_info >= (3, 10): - def _should_collect_from_parameters(t): - return isinstance( - t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) - ) -elif sys.version_info >= (3, 9): - def _should_collect_from_parameters(t): - return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) -else: - def _should_collect_from_parameters(t): - return isinstance(t, typing._GenericAlias) and not t._special - - -NoReturn = typing.NoReturn - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - - -if sys.version_info >= (3, 11): - from typing import Any -else: - - class _AnyMeta(type): - def __instancecheck__(self, obj): - if self is Any: - raise TypeError("typing_extensions.Any cannot be used with isinstance()") - return super().__instancecheck__(obj) - - def __repr__(self): - if self is Any: - return "typing_extensions.Any" - return super().__repr__() - - class Any(metaclass=_AnyMeta): - """Special type indicating an unconstrained type. - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. - Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance - checks. - """ - def __new__(cls, *args, **kwargs): - if cls is Any: - raise TypeError("Any cannot be instantiated") - return super().__new__(cls, *args, **kwargs) - - -ClassVar = typing.ClassVar - - -class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - -Final = typing.Final - -if sys.version_info >= (3, 11): - final = typing.final -else: - # @final exists in 3.8+, but we backport it for all versions - # before 3.11 to keep support for the __final__ attribute. - # See https://bugs.python.org/issue46342 - def final(f): - """This decorator can be used to indicate to type checkers that - the decorated method cannot be overridden, and decorated class - cannot be subclassed. For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... - - There is no runtime checking of these properties. The decorator - sets the ``__final__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - """ - try: - f.__final__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return f - - -def IntVar(name): - return typing.TypeVar(name) - - -# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 -if sys.version_info >= (3, 10, 1): - Literal = typing.Literal -else: - def _flatten_literal_params(parameters): - """An internal helper for Literal creation: flatten Literals among parameters""" - params = [] - for p in parameters: - if isinstance(p, _LiteralGenericAlias): - params.extend(p.__args__) - else: - params.append(p) - return tuple(params) - - def _value_and_type_iter(params): - for p in params: - yield p, type(p) - - class _LiteralGenericAlias(typing._GenericAlias, _root=True): - def __eq__(self, other): - if not isinstance(other, _LiteralGenericAlias): - return NotImplemented - these_args_deduped = set(_value_and_type_iter(self.__args__)) - other_args_deduped = set(_value_and_type_iter(other.__args__)) - return these_args_deduped == other_args_deduped - - def __hash__(self): - return hash(frozenset(_value_and_type_iter(self.__args__))) - - class _LiteralForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, doc: str): - self._name = 'Literal' - self._doc = self.__doc__ = doc - - def __getitem__(self, parameters): - if not isinstance(parameters, tuple): - parameters = (parameters,) - - parameters = _flatten_literal_params(parameters) - - val_type_pairs = list(_value_and_type_iter(parameters)) - try: - deduped_pairs = set(val_type_pairs) - except TypeError: - # unhashable parameters - pass - else: - # similar logic to typing._deduplicate on Python 3.9+ - if len(deduped_pairs) < len(val_type_pairs): - new_parameters = [] - for pair in val_type_pairs: - if pair in deduped_pairs: - new_parameters.append(pair[0]) - deduped_pairs.remove(pair) - assert not deduped_pairs, deduped_pairs - parameters = tuple(new_parameters) - - return _LiteralGenericAlias(self, parameters) - - Literal = _LiteralForm(doc="""\ - A type that can be used to indicate to type checkers - that the corresponding value has a value literally equivalent - to the provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to - the value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime - checking verifying that the parameter is actually a value - instead of a type.""") - - -_overload_dummy = typing._overload_dummy - - -if hasattr(typing, "get_overloads"): # 3.11+ - overload = typing.overload - get_overloads = typing.get_overloads - clear_overloads = typing.clear_overloads -else: - # {module: {qualname: {firstlineno: func}}} - _overload_registry = collections.defaultdict( - functools.partial(collections.defaultdict, dict) - ) - - def overload(func): - """Decorator for overloaded functions/methods. - - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here - - The overloads for a function can be retrieved at runtime using the - get_overloads() function. - """ - # classmethod and staticmethod - f = getattr(func, "__func__", func) - try: - _overload_registry[f.__module__][f.__qualname__][ - f.__code__.co_firstlineno - ] = func - except AttributeError: - # Not a normal function; ignore. - pass - return _overload_dummy - - def get_overloads(func): - """Return all defined overloads for *func* as a sequence.""" - # classmethod and staticmethod - f = getattr(func, "__func__", func) - if f.__module__ not in _overload_registry: - return [] - mod_dict = _overload_registry[f.__module__] - if f.__qualname__ not in mod_dict: - return [] - return list(mod_dict[f.__qualname__].values()) - - def clear_overloads(): - """Clear all overloads in the registry.""" - _overload_registry.clear() - - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator -Deque = typing.Deque -DefaultDict = typing.DefaultDict -OrderedDict = typing.OrderedDict -Counter = typing.Counter -ChainMap = typing.ChainMap -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -if sys.version_info >= (3, 13, 0, "beta"): - from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator -else: - def _is_dunder(attr): - return attr.startswith('__') and attr.endswith('__') - - # Python <3.9 doesn't have typing._SpecialGenericAlias - _special_generic_alias_base = getattr( - typing, "_SpecialGenericAlias", typing._GenericAlias - ) - - class _SpecialGenericAlias(_special_generic_alias_base, _root=True): - def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()): - if _special_generic_alias_base is typing._GenericAlias: - # Python <3.9 - self.__origin__ = origin - self._nparams = nparams - super().__init__(origin, nparams, special=True, inst=inst, name=name) - else: - # Python >= 3.9 - super().__init__(origin, nparams, inst=inst, name=name) - self._defaults = defaults - - def __setattr__(self, attr, val): - allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'} - if _special_generic_alias_base is typing._GenericAlias: - # Python <3.9 - allowed_attrs.add("__origin__") - if _is_dunder(attr) or attr in allowed_attrs: - object.__setattr__(self, attr, val) - else: - setattr(self.__origin__, attr, val) - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) - if ( - self._defaults - and len(params) < self._nparams - and len(params) + len(self._defaults) >= self._nparams - ): - params = (*params, *self._defaults[len(params) - self._nparams:]) - actual_len = len(params) - - if actual_len != self._nparams: - if self._defaults: - expected = f"at least {self._nparams - len(self._defaults)}" - else: - expected = str(self._nparams) - if not self._nparams: - raise TypeError(f"{self} is not a generic class") - raise TypeError( - f"Too {'many' if actual_len > self._nparams else 'few'}" - f" arguments for {self};" - f" actual {actual_len}, expected {expected}" - ) - return self.copy_with(params) - - _NoneType = type(None) - Generator = _SpecialGenericAlias( - collections.abc.Generator, 3, defaults=(_NoneType, _NoneType) - ) - AsyncGenerator = _SpecialGenericAlias( - collections.abc.AsyncGenerator, 2, defaults=(_NoneType,) - ) - ContextManager = _SpecialGenericAlias( - contextlib.AbstractContextManager, - 2, - name="ContextManager", - defaults=(typing.Optional[bool],) - ) - AsyncContextManager = _SpecialGenericAlias( - contextlib.AbstractAsyncContextManager, - 2, - name="AsyncContextManager", - defaults=(typing.Optional[bool],) - ) - - -_PROTO_ALLOWLIST = { - 'collections.abc': [ - 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', - ], - 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], - 'typing_extensions': ['Buffer'], -} - - -_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | { - "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__", - "__final__", -} - - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in {'Protocol', 'Generic'}: - continue - annotations = getattr(base, '__annotations__', {}) - for attr in (*base.__dict__, *annotations): - if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): - attrs.add(attr) - return attrs - - -def _caller(depth=2): - try: - return sys._getframe(depth).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): # For platforms without _getframe() - return None - - -# `__match_args__` attribute was removed from protocol members in 3.13, -# we want to backport this change to older Python versions. -if sys.version_info >= (3, 13): - Protocol = typing.Protocol -else: - def _allow_reckless_class_checks(depth=3): - """Allow instance and class checks for special stdlib modules. - The abc and functools modules indiscriminately call isinstance() and - issubclass() on the whole MRO of a user class, which may contain protocols. - """ - return _caller(depth) in {'abc', 'functools', None} - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - def _type_check_issubclass_arg_1(arg): - """Raise TypeError if `arg` is not an instance of `type` - in `issubclass(arg, )`. - - In most cases, this is verified by type.__subclasscheck__. - Checking it again unnecessarily would slow down issubclass() checks, - so, we don't perform this check unless we absolutely have to. - - For various error paths, however, - we want to ensure that *this* error message is shown to the user - where relevant, rather than a typing.py-specific error message. - """ - if not isinstance(arg, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') - - # Inheriting from typing._ProtocolMeta isn't actually desirable, - # but is necessary to allow typing.Protocol and typing_extensions.Protocol - # to mix without getting TypeErrors about "metaclass conflict" - class _ProtocolMeta(type(typing.Protocol)): - # This metaclass is somewhat unfortunate, - # but is necessary for several reasons... - # - # NOTE: DO NOT call super() in any methods in this class - # That would call the methods on typing._ProtocolMeta on Python 3.8-3.11 - # and those are slow - def __new__(mcls, name, bases, namespace, **kwargs): - if name == "Protocol" and len(bases) < 2: - pass - elif {Protocol, typing.Protocol} & set(bases): - for base in bases: - if not ( - base in {object, typing.Generic, Protocol, typing.Protocol} - or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) - or is_protocol(base) - ): - raise TypeError( - f"Protocols can only inherit from other protocols, " - f"got {base!r}" - ) - return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) - - def __init__(cls, *args, **kwargs): - abc.ABCMeta.__init__(cls, *args, **kwargs) - if getattr(cls, "_is_protocol", False): - cls.__protocol_attrs__ = _get_protocol_attrs(cls) - - def __subclasscheck__(cls, other): - if cls is Protocol: - return type.__subclasscheck__(cls, other) - if ( - getattr(cls, '_is_protocol', False) - and not _allow_reckless_class_checks() - ): - if not getattr(cls, '_is_runtime_protocol', False): - _type_check_issubclass_arg_1(other) - raise TypeError( - "Instance and class checks can only be used with " - "@runtime_checkable protocols" - ) - if ( - # this attribute is set by @runtime_checkable: - cls.__non_callable_proto_members__ - and cls.__dict__.get("__subclasshook__") is _proto_hook - ): - _type_check_issubclass_arg_1(other) - non_method_attrs = sorted(cls.__non_callable_proto_members__) - raise TypeError( - "Protocols with non-method members don't support issubclass()." - f" Non-method members: {str(non_method_attrs)[1:-1]}." - ) - return abc.ABCMeta.__subclasscheck__(cls, other) - - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if cls is Protocol: - return type.__instancecheck__(cls, instance) - if not getattr(cls, "_is_protocol", False): - # i.e., it's a concrete subclass of a protocol - return abc.ABCMeta.__instancecheck__(cls, instance) - - if ( - not getattr(cls, '_is_runtime_protocol', False) and - not _allow_reckless_class_checks() - ): - raise TypeError("Instance and class checks can only be used with" - " @runtime_checkable protocols") - - if abc.ABCMeta.__instancecheck__(cls, instance): - return True - - for attr in cls.__protocol_attrs__: - try: - val = inspect.getattr_static(instance, attr) - except AttributeError: - break - # this attribute is set by @runtime_checkable: - if val is None and attr not in cls.__non_callable_proto_members__: - break - else: - return True - - return False - - def __eq__(cls, other): - # Hack so that typing.Generic.__class_getitem__ - # treats typing_extensions.Protocol - # as equivalent to typing.Protocol - if abc.ABCMeta.__eq__(cls, other) is True: - return True - return cls is Protocol and other is typing.Protocol - - # This has to be defined, or the abc-module cache - # complains about classes with this metaclass being unhashable, - # if we define only __eq__! - def __hash__(cls) -> int: - return type.__hash__(cls) - - @classmethod - def _proto_hook(cls, other): - if not cls.__dict__.get('_is_protocol', False): - return NotImplemented - - for attr in cls.__protocol_attrs__: - for base in other.__mro__: - # Check if the members appears in the class dictionary... - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - - # ...or in annotations, if it is a sub-protocol. - annotations = getattr(base, '__annotations__', {}) - if ( - isinstance(annotations, collections.abc.Mapping) - and attr in annotations - and is_protocol(other) - ): - break - else: - return NotImplemented - return True - - class Protocol(typing.Generic, metaclass=_ProtocolMeta): - __doc__ = typing.Protocol.__doc__ - __slots__ = () - _is_protocol = True - _is_runtime_protocol = False - - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', False): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # Prohibit instantiation for protocol classes - if cls._is_protocol and cls.__init__ is Protocol.__init__: - cls.__init__ = _no_init - - -if sys.version_info >= (3, 13): - runtime_checkable = typing.runtime_checkable -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol. - - Such protocol can be used with isinstance() and issubclass(). - Raise TypeError if applied to a non-protocol class. - This allows a simple-minded structural check very similar to - one trick ponies in collections.abc such as Iterable. - - For example:: - - @runtime_checkable - class Closable(Protocol): - def close(self): ... - - assert isinstance(open('/some/file'), Closable) - - Warning: this will check only the presence of the required methods, - not their type signatures! - """ - if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False): - raise TypeError(f'@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - - # typing.Protocol classes on <=3.11 break if we execute this block, - # because typing.Protocol classes on <=3.11 don't have a - # `__protocol_attrs__` attribute, and this block relies on the - # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+ - # break if we *don't* execute this block, because *they* assume that all - # protocol classes have a `__non_callable_proto_members__` attribute - # (which this block sets) - if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2): - # PEP 544 prohibits using issubclass() - # with protocols that have non-method members. - # See gh-113320 for why we compute this attribute here, - # rather than in `_ProtocolMeta.__init__` - cls.__non_callable_proto_members__ = set() - for attr in cls.__protocol_attrs__: - try: - is_callable = callable(getattr(cls, attr, None)) - except Exception as e: - raise TypeError( - f"Failed to determine whether protocol member {attr!r} " - "is a method member" - ) from e - else: - if not is_callable: - cls.__non_callable_proto_members__.add(attr) - - return cls - - -# The "runtime" alias exists for backwards compatibility. -runtime = runtime_checkable - - -# Our version of runtime-checkable protocols is faster on Python 3.8-3.11 -if sys.version_info >= (3, 12): - SupportsInt = typing.SupportsInt - SupportsFloat = typing.SupportsFloat - SupportsComplex = typing.SupportsComplex - SupportsBytes = typing.SupportsBytes - SupportsIndex = typing.SupportsIndex - SupportsAbs = typing.SupportsAbs - SupportsRound = typing.SupportsRound -else: - @runtime_checkable - class SupportsInt(Protocol): - """An ABC with one abstract method __int__.""" - __slots__ = () - - @abc.abstractmethod - def __int__(self) -> int: - pass - - @runtime_checkable - class SupportsFloat(Protocol): - """An ABC with one abstract method __float__.""" - __slots__ = () - - @abc.abstractmethod - def __float__(self) -> float: - pass - - @runtime_checkable - class SupportsComplex(Protocol): - """An ABC with one abstract method __complex__.""" - __slots__ = () - - @abc.abstractmethod - def __complex__(self) -> complex: - pass - - @runtime_checkable - class SupportsBytes(Protocol): - """An ABC with one abstract method __bytes__.""" - __slots__ = () - - @abc.abstractmethod - def __bytes__(self) -> bytes: - pass - - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - @runtime_checkable - class SupportsAbs(Protocol[T_co]): - """ - An ABC with one abstract method __abs__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __abs__(self) -> T_co: - pass - - @runtime_checkable - class SupportsRound(Protocol[T_co]): - """ - An ABC with one abstract method __round__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __round__(self, ndigits: int = 0) -> T_co: - pass - - -def _ensure_subclassable(mro_entries): - def inner(func): - if sys.implementation.name == "pypy" and sys.version_info < (3, 9): - cls_dict = { - "__call__": staticmethod(func), - "__mro_entries__": staticmethod(mro_entries) - } - t = type(func.__name__, (), cls_dict) - return functools.update_wrapper(t(), func) - else: - func.__mro_entries__ = mro_entries - return func - return inner - - -_NEEDS_SINGLETONMETA = ( - not hasattr(typing, "NoDefault") or not hasattr(typing, "NoExtraItems") -) - -if _NEEDS_SINGLETONMETA: - class SingletonMeta(type): - def __setattr__(cls, attr, value): - # TypeError is consistent with the behavior of NoneType - raise TypeError( - f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" - ) - - -if hasattr(typing, "NoDefault"): - NoDefault = typing.NoDefault -else: - class NoDefaultType(metaclass=SingletonMeta): - """The type of the NoDefault singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoDefault") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoDefault" - - def __reduce__(self): - return "NoDefault" - - NoDefault = NoDefaultType() - del NoDefaultType - -if hasattr(typing, "NoExtraItems"): - NoExtraItems = typing.NoExtraItems -else: - class NoExtraItemsType(metaclass=SingletonMeta): - """The type of the NoExtraItems singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoExtraItems") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoExtraItems" - - def __reduce__(self): - return "NoExtraItems" - - NoExtraItems = NoExtraItemsType() - del NoExtraItemsType - -if _NEEDS_SINGLETONMETA: - del SingletonMeta - - -# Update this to something like >=3.13.0b1 if and when -# PEP 728 is implemented in CPython -_PEP_728_IMPLEMENTED = False - -if _PEP_728_IMPLEMENTED: - # The standard library TypedDict in Python 3.8 does not store runtime information - # about which (if any) keys are optional. See https://bugs.python.org/issue38834 - # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" - # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 - # The standard library TypedDict below Python 3.11 does not store runtime - # information about optional and required keys when using Required or NotRequired. - # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. - # Aaaand on 3.12 we add __orig_bases__ to TypedDict - # to enable better runtime introspection. - # On 3.13 we deprecate some odd ways of creating TypedDicts. - # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier. - # PEP 728 (still pending) makes more changes. - TypedDict = typing.TypedDict - _TypedDictMeta = typing._TypedDictMeta - is_typeddict = typing.is_typeddict -else: - # 3.10.0 and later - _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters - - def _get_typeddict_qualifiers(annotation_type): - while True: - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - else: - break - elif annotation_origin is Required: - yield Required - annotation_type, = get_args(annotation_type) - elif annotation_origin is NotRequired: - yield NotRequired - annotation_type, = get_args(annotation_type) - elif annotation_origin is ReadOnly: - yield ReadOnly - annotation_type, = get_args(annotation_type) - else: - break - - class _TypedDictMeta(type): - - def __new__(cls, name, bases, ns, *, total=True, closed=None, - extra_items=NoExtraItems): - """Create new typed dict class object. - - This method is called when TypedDict is subclassed, - or when TypedDict is instantiated. This way - TypedDict supports all three syntax forms described in its docstring. - Subclasses and instances of TypedDict return actual dictionaries. - """ - for base in bases: - if type(base) is not _TypedDictMeta and base is not typing.Generic: - raise TypeError('cannot inherit from both a TypedDict type ' - 'and a non-TypedDict base class') - if closed is not None and extra_items is not NoExtraItems: - raise TypeError(f"Cannot combine closed={closed!r} and extra_items") - - if any(issubclass(b, typing.Generic) for b in bases): - generic_base = (typing.Generic,) - else: - generic_base = () - - # typing.py generally doesn't let you inherit from plain Generic, unless - # the name of the class happens to be "Protocol" - tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) - tp_dict.__name__ = name - if tp_dict.__qualname__ == "Protocol": - tp_dict.__qualname__ = name - - if not hasattr(tp_dict, '__orig_bases__'): - tp_dict.__orig_bases__ = bases - - annotations = {} - if "__annotations__" in ns: - own_annotations = ns["__annotations__"] - elif "__annotate__" in ns: - # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated - own_annotations = ns["__annotate__"](1) - else: - own_annotations = {} - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - if _TAKES_MODULE: - own_annotations = { - n: typing._type_check(tp, msg, module=tp_dict.__module__) - for n, tp in own_annotations.items() - } - else: - own_annotations = { - n: typing._type_check(tp, msg) - for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - readonly_keys = set() - mutable_keys = set() - extra_items_type = extra_items - - for base in bases: - base_dict = base.__dict__ - - annotations.update(base_dict.get('__annotations__', {})) - required_keys.update(base_dict.get('__required_keys__', ())) - optional_keys.update(base_dict.get('__optional_keys__', ())) - readonly_keys.update(base_dict.get('__readonly_keys__', ())) - mutable_keys.update(base_dict.get('__mutable_keys__', ())) - - # This was specified in an earlier version of PEP 728. Support - # is retained for backwards compatibility, but only for Python - # 3.13 and lower. - if (closed and sys.version_info < (3, 14) - and "__extra_items__" in own_annotations): - annotation_type = own_annotations.pop("__extra_items__") - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - if Required in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "Required" - ) - if NotRequired in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "NotRequired" - ) - extra_items_type = annotation_type - - annotations.update(own_annotations) - for annotation_key, annotation_type in own_annotations.items(): - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - - if Required in qualifiers: - required_keys.add(annotation_key) - elif NotRequired in qualifiers: - optional_keys.add(annotation_key) - elif total: - required_keys.add(annotation_key) - else: - optional_keys.add(annotation_key) - if ReadOnly in qualifiers: - mutable_keys.discard(annotation_key) - readonly_keys.add(annotation_key) - else: - mutable_keys.add(annotation_key) - readonly_keys.discard(annotation_key) - - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - tp_dict.__readonly_keys__ = frozenset(readonly_keys) - tp_dict.__mutable_keys__ = frozenset(mutable_keys) - tp_dict.__total__ = total - tp_dict.__closed__ = closed - tp_dict.__extra_items__ = extra_items_type - return tp_dict - - __call__ = dict # static method - - def __subclasscheck__(cls, other): - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - - __instancecheck__ = __subclasscheck__ - - _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) - - @_ensure_subclassable(lambda bases: (_TypedDict,)) - def TypedDict( - typename, - fields=_marker, - /, - *, - total=True, - closed=None, - extra_items=NoExtraItems, - **kwargs - ): - """A simple typed namespace. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type such that a type checker will expect all - instances to have a certain set of keys, where each key is - associated with a value of a consistent type. This expectation - is not checked at runtime. - - Usage:: - - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') - - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. - TypedDict supports an additional equivalent form:: - - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - By default, all keys must be present in a TypedDict. It is possible - to override this by specifying totality:: - - class Point2D(TypedDict, total=False): - x: int - y: int - - This means that a Point2D TypedDict can have any of the keys omitted. A type - checker is only expected to support a literal False or True as the value of - the total argument. True is the default, and makes all items defined in the - class body be required. - - The Required and NotRequired special forms can also be used to mark - individual keys as being required or not required:: - - class Point2D(TypedDict): - x: int # the "x" key must always be present (Required is the default) - y: NotRequired[int] # the "y" key can be omitted - - See PEP 655 for more details on Required and NotRequired. - """ - if fields is _marker or fields is None: - if fields is _marker: - deprecated_thing = "Failing to pass a value for the 'fields' parameter" - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - - example = f"`{typename} = TypedDict({typename!r}, {{}})`" - deprecation_msg = ( - f"{deprecated_thing} is deprecated and will be disallowed in " - "Python 3.15. To create a TypedDict class with 0 fields " - "using the functional syntax, pass an empty dictionary, e.g. " - ) + example + "." - warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) - # Support a field called "closed" - if closed is not False and closed is not True and closed is not None: - kwargs["closed"] = closed - closed = None - # Or "extra_items" - if extra_items is not NoExtraItems: - kwargs["extra_items"] = extra_items - extra_items = NoExtraItems - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - if kwargs: - if sys.version_info >= (3, 13): - raise TypeError("TypedDict takes no keyword arguments") - warnings.warn( - "The kwargs-based syntax for TypedDict definitions is deprecated " - "in Python 3.11, will be removed in Python 3.13, and may not be " - "understood by third-party type checkers.", - DeprecationWarning, - stacklevel=2, - ) - - ns = {'__annotations__': dict(fields)} - module = _caller() - if module is not None: - # Setting correct module is necessary to make typed dict classes pickleable. - ns['__module__'] = module - - td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, - extra_items=extra_items) - td.__orig_bases__ = (TypedDict,) - return td - - if hasattr(typing, "_TypedDictMeta"): - _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) - else: - _TYPEDDICT_TYPES = (_TypedDictMeta,) - - def is_typeddict(tp): - """Check if an annotation is a TypedDict class - - For example:: - class Film(TypedDict): - title: str - year: int - - is_typeddict(Film) # => True - is_typeddict(Union[list, str]) # => False - """ - # On 3.8, this would otherwise return True - if hasattr(typing, "TypedDict") and tp is typing.TypedDict: - return False - return isinstance(tp, _TYPEDDICT_TYPES) - - -if hasattr(typing, "assert_type"): - assert_type = typing.assert_type - -else: - def assert_type(val, typ, /): - """Assert (to the type checker) that the value is of the given type. - - When the type checker encounters a call to assert_type(), it - emits an error if the value is not of the specified type:: - - def greet(name: str) -> None: - assert_type(name, str) # ok - assert_type(name, int) # type checker error - - At runtime this returns the first argument unchanged and otherwise - does nothing. - """ - return val - - -if hasattr(typing, "ReadOnly"): # 3.13+ - get_type_hints = typing.get_type_hints -else: # <=3.13 - # replaces _strip_annotations() - def _strip_extras(t): - """Strips Annotated, Required and NotRequired from a given type.""" - if isinstance(t, _AnnotatedAlias): - return _strip_extras(t.__origin__) - if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly): - return _strip_extras(t.__args__[0]) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return t.copy_with(stripped_args) - if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return _types.GenericAlias(t.__origin__, stripped_args) - if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return functools.reduce(operator.or_, stripped_args) - - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' - (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - if hasattr(typing, "Annotated"): # 3.9+ - hint = typing.get_type_hints( - obj, globalns=globalns, localns=localns, include_extras=True - ) - else: # 3.8 - hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) - if sys.version_info < (3, 11): - _clean_optional(obj, hint, globalns, localns) - if sys.version_info < (3, 9): - # In 3.8 eval_type does not flatten Optional[ForwardRef] correctly - # This will recreate and and cache Unions. - hint = { - k: (t - if get_origin(t) != Union - else Union[t.__args__]) - for k, t in hint.items() - } - if include_extras: - return hint - return {k: _strip_extras(t) for k, t in hint.items()} - - _NoneType = type(None) - - def _could_be_inserted_optional(t): - """detects Union[..., None] pattern""" - # 3.8+ compatible checking before _UnionGenericAlias - if get_origin(t) is not Union: - return False - # Assume if last argument is not None they are user defined - if t.__args__[-1] is not _NoneType: - return False - return True - - # < 3.11 - def _clean_optional(obj, hints, globalns=None, localns=None): - # reverts injected Union[..., None] cases from typing.get_type_hints - # when a None default value is used. - # see https://github.com/python/typing_extensions/issues/310 - if not hints or isinstance(obj, type): - return - defaults = typing._get_defaults(obj) # avoid accessing __annotations___ - if not defaults: - return - original_hints = obj.__annotations__ - for name, value in hints.items(): - # Not a Union[..., None] or replacement conditions not fullfilled - if (not _could_be_inserted_optional(value) - or name not in defaults - or defaults[name] is not None - ): - continue - original_value = original_hints[name] - # value=NoneType should have caused a skip above but check for safety - if original_value is None: - original_value = _NoneType - # Forward reference - if isinstance(original_value, str): - if globalns is None: - if isinstance(obj, _types.ModuleType): - globalns = obj.__dict__ - else: - nsobj = obj - # Find globalns for the unwrapped object. - while hasattr(nsobj, '__wrapped__'): - nsobj = nsobj.__wrapped__ - globalns = getattr(nsobj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: - localns = globalns - if sys.version_info < (3, 9): - original_value = ForwardRef(original_value) - else: - original_value = ForwardRef( - original_value, - is_argument=not isinstance(obj, _types.ModuleType) - ) - original_evaluated = typing._eval_type(original_value, globalns, localns) - if sys.version_info < (3, 9) and get_origin(original_evaluated) is Union: - # Union[str, None, "str"] is not reduced to Union[str, None] - original_evaluated = Union[original_evaluated.__args__] - # Compare if values differ. Note that even if equal - # value might be cached by typing._tp_cache contrary to original_evaluated - if original_evaluated != value or ( - # 3.10: ForwardRefs of UnionType might be turned into _UnionGenericAlias - hasattr(_types, "UnionType") - and isinstance(original_evaluated, _types.UnionType) - and not isinstance(value, _types.UnionType) - ): - hints[name] = original_evaluated - -# Python 3.9+ has PEP 593 (Annotated) -if hasattr(typing, 'Annotated'): - Annotated = typing.Annotated - # Not exported and not a public API, but needed for get_origin() and get_args() - # to work. - _AnnotatedAlias = typing._AnnotatedAlias -# 3.8 -else: - class _AnnotatedAlias(typing._GenericAlias, _root=True): - """Runtime representation of an annotated type. - - At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' - with extra annotations. The alias behaves like a normal typing alias, - instantiating is the same as instantiating the underlying type, binding - it to types is also the same. - """ - def __init__(self, origin, metadata): - if isinstance(origin, _AnnotatedAlias): - metadata = origin.__metadata__ + metadata - origin = origin.__origin__ - super().__init__(origin, origin) - self.__metadata__ = metadata - - def copy_with(self, params): - assert len(params) == 1 - new_type = params[0] - return _AnnotatedAlias(new_type, self.__metadata__) - - def __repr__(self): - return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " - f"{', '.join(repr(a) for a in self.__metadata__)}]") - - def __reduce__(self): - return operator.getitem, ( - Annotated, (self.__origin__, *self.__metadata__) - ) - - def __eq__(self, other): - if not isinstance(other, _AnnotatedAlias): - return NotImplemented - if self.__origin__ != other.__origin__: - return False - return self.__metadata__ == other.__metadata__ - - def __hash__(self): - return hash((self.__origin__, self.__metadata__)) - - class Annotated: - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type (and will be in - the __origin__ field), the remaining arguments are kept as a tuple in - the __extra__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - - __slots__ = () - - def __new__(cls, *args, **kwargs): - raise TypeError("Type Annotated cannot be instantiated.") - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be used " - "with at least two arguments (a type and an " - "annotation).") - allowed_special_forms = (ClassVar, Final) - if get_origin(params[0]) in allowed_special_forms: - origin = params[0] - else: - msg = "Annotated[t, ...]: t must be a type." - origin = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return _AnnotatedAlias(origin, metadata) - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - f"Cannot subclass {cls.__module__}.Annotated" - ) - -# Python 3.8 has get_origin() and get_args() but those implementations aren't -# Annotated-aware, so we can't use those. Python 3.9's versions don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -if sys.version_info[:2] >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.8-3.9 -else: - try: - # 3.9+ - from typing import _BaseGenericAlias - except ImportError: - _BaseGenericAlias = typing._GenericAlias - try: - # 3.9+ - from typing import GenericAlias as _typing_GenericAlias - except ImportError: - _typing_GenericAlias = typing._GenericAlias - - def get_origin(tp): - """Get the unsubscripted version of a type. - - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P - """ - if isinstance(tp, _AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, - ParamSpecArgs, ParamSpecKwargs)): - return tp.__origin__ - if tp is typing.Generic: - return typing.Generic - return None - - def get_args(tp): - """Get type arguments with all substitutions performed. - - For unions, basic simplifications used by Union constructor are performed. - Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) - """ - if isinstance(tp, _AnnotatedAlias): - return (tp.__origin__, *tp.__metadata__) - if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): - if getattr(tp, "_special", False): - return () - res = tp.__args__ - if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: - res = (list(res[:-1]), res[-1]) - return res - return () - - -# 3.10+ -if hasattr(typing, 'TypeAlias'): - TypeAlias = typing.TypeAlias -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_ExtensionsSpecialForm - def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - raise TypeError(f"{self} is not subscriptable") -# 3.8 -else: - TypeAlias = _ExtensionsSpecialForm( - 'TypeAlias', - doc="""Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example - above.""" - ) - - -def _set_default(type_param, default): - type_param.has_default = lambda: default is not NoDefault - type_param.__default__ = default - - -def _set_module(typevarlike): - # for pickling: - def_mod = _caller(depth=3) - if def_mod != 'typing_extensions': - typevarlike.__module__ = def_mod - - -class _DefaultMixin: - """Mixin for TypeVarLike defaults.""" - - __slots__ = () - __init__ = _set_default - - -# Classes using this metaclass must provide a _backported_typevarlike ClassVar -class _TypeVarLikeMeta(type): - def __instancecheck__(cls, __instance: Any) -> bool: - return isinstance(__instance, cls._backported_typevarlike) - - -if _PEP_696_IMPLEMENTED: - from typing import TypeVar -else: - # Add default and infer_variance parameters from PEP 696 and 695 - class TypeVar(metaclass=_TypeVarLikeMeta): - """Type variable.""" - - _backported_typevarlike = typing.TypeVar - - def __new__(cls, name, *constraints, bound=None, - covariant=False, contravariant=False, - default=NoDefault, infer_variance=False): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant, - infer_variance=infer_variance) - else: - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant) - if infer_variance and (covariant or contravariant): - raise ValueError("Variance cannot be specified with infer_variance.") - typevar.__infer_variance__ = infer_variance - - _set_default(typevar, default) - _set_module(typevar) - - def _tvar_prepare_subst(alias, args): - if ( - typevar.has_default() - and alias.__parameters__.index(typevar) == len(args) - ): - args += (typevar.__default__,) - return args - - typevar.__typing_prepare_subst__ = _tvar_prepare_subst - return typevar - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.8-3.9 -else: - class _Immutable: - """Mixin to indicate that object should not be copied.""" - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - - class ParamSpecArgs(_Immutable): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - class ParamSpecKwargs(_Immutable): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - - -if _PEP_696_IMPLEMENTED: - from typing import ParamSpec - -# 3.10+ -elif hasattr(typing, 'ParamSpec'): - - # Add default parameter - PEP 696 - class ParamSpec(metaclass=_TypeVarLikeMeta): - """Parameter specification.""" - - _backported_typevarlike = typing.ParamSpec - - def __new__(cls, name, *, bound=None, - covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented, can pass infer_variance to typing.TypeVar - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant, - infer_variance=infer_variance) - else: - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant) - paramspec.__infer_variance__ = infer_variance - - _set_default(paramspec, default) - _set_module(paramspec) - - def _paramspec_prepare_subst(alias, args): - params = alias.__parameters__ - i = params.index(paramspec) - if i == len(args) and paramspec.has_default(): - args = [*args, paramspec.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {alias}") - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. - if len(params) == 1 and not typing._is_param_expr(args[0]): - assert i == 0 - args = (args,) - # Convert lists to tuples to help other libraries cache the results. - elif isinstance(args[i], list): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - return args - - paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst - return paramspec - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") - -# 3.8-3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list, _DefaultMixin): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or s the first argument to ``Callable``. In Python 3.10 and higher, - they are also supported in user-defined Generics at runtime. - See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'T' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - @property - def args(self): - return ParamSpecArgs(self) - - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - list.__init__(self, [self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - self.__infer_variance__ = bool(infer_variance) - if bound: - self.__bound__ = typing._type_check(bound, 'Bound must be a type.') - else: - self.__bound__ = None - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if self.__infer_variance__: - prefix = '' - elif self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - # Hack to get typing._type_check to pass. - def __call__(self, *args, **kwargs): - pass - - -# 3.8-3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - - # 3.9.0-1 - if not hasattr(typing, '_type_convert'): - def _type_convert(arg, module=None, *, allow_special_forms=False): - """For converting None to type(None), and strings to ForwardRef.""" - if arg is None: - return type(None) - if isinstance(arg, str): - if sys.version_info <= (3, 9, 6): - return ForwardRef(arg) - if sys.version_info <= (3, 9, 7): - return ForwardRef(arg, module=module) - return ForwardRef(arg, module=module, is_class=allow_special_forms) - return arg - else: - _type_convert = typing._type_convert - - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - __class__ = typing._GenericAlias - - # Flag in 3.8. - _special = False - - def __init__(self, origin, args): - super().__init__(args) - self.__origin__ = origin - self.__args__ = args - - def __repr__(self): - _type_repr = typing._type_repr - return (f'{_type_repr(self.__origin__)}' - f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - - def __hash__(self): - return hash((self.__origin__, self.__args__)) - - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass - - @property - def __parameters__(self): - return tuple( - tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) - ) - - # 3.8; needed for typing._subst_tvars - # 3.9 used by __getitem__ below - def copy_with(self, params): - if isinstance(params[-1], _ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - elif (not (params[-1] is ... or isinstance(params[-1], ParamSpec))): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return self.__class__(self.__origin__, params) - - # 3.9; accessed during GenericAlias.__getitem__ when substituting - def __getitem__(self, args): - if self.__origin__ in (Generic, Protocol): - # Can't subscript Generic[...] or Protocol[...]. - raise TypeError(f"Cannot subscript already-subscripted {self}") - if not self.__parameters__: - raise TypeError(f"{self} is not a generic class") - - if not isinstance(args, tuple): - args = (args,) - args = _unpack_args(*(_type_convert(p) for p in args)) - params = self.__parameters__ - for param in params: - prepare = getattr(param, "__typing_prepare_subst__", None) - if prepare is not None: - args = prepare(self, args) - # 3.8 - 3.9 & typing.ParamSpec - elif isinstance(param, ParamSpec): - i = params.index(param) - if ( - i == len(args) - and getattr(param, '__default__', NoDefault) is not NoDefault - ): - args = [*args, param.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {self}") - # Special case for Z[[int, str, bool]] == Z[int, str, bool] - if len(params) == 1 and not _is_param_expr(args[0]): - assert i == 0 - args = (args,) - elif ( - isinstance(args[i], list) - # 3.8 - 3.9 - # This class inherits from list do not convert - and not isinstance(args[i], _ConcatenateGenericAlias) - ): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - - alen = len(args) - plen = len(params) - if alen != plen: - raise TypeError( - f"Too {'many' if alen > plen else 'few'} arguments for {self};" - f" actual {alen}, expected {plen}" - ) - - subst = dict(zip(self.__parameters__, args)) - # determine new args - new_args = [] - for arg in self.__args__: - if isinstance(arg, type): - new_args.append(arg) - continue - if isinstance(arg, TypeVar): - arg = subst[arg] - if ( - (isinstance(arg, typing._GenericAlias) and _is_unpack(arg)) - or ( - hasattr(_types, "GenericAlias") - and isinstance(arg, _types.GenericAlias) - and getattr(arg, "__unpacked__", False) - ) - ): - raise TypeError(f"{arg} is not valid as type argument") - - elif isinstance(arg, - typing._GenericAlias - if not hasattr(_types, "GenericAlias") else - (typing._GenericAlias, _types.GenericAlias) - ): - subparams = arg.__parameters__ - if subparams: - subargs = tuple(subst[x] for x in subparams) - arg = arg[subargs] - new_args.append(arg) - return self.copy_with(tuple(new_args)) - -# 3.10+ -else: - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias - - # 3.10 - if sys.version_info < (3, 11): - - class _ConcatenateGenericAlias(typing._ConcatenateGenericAlias, _root=True): - # needed for checks in collections.abc.Callable to accept this class - __module__ = "typing" - - def copy_with(self, params): - if isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - if isinstance(params[-1], typing._ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return super(typing._ConcatenateGenericAlias, self).copy_with(params) - - def __getitem__(self, args): - value = super().__getitem__(args) - if isinstance(value, tuple) and any(_is_unpack(t) for t in value): - return tuple(_unpack_args(*(n for n in value))) - return value - - -# 3.8-3.9.2 -class _EllipsisDummy: ... - - -# 3.8-3.10 -def _create_concatenate_alias(origin, parameters): - if parameters[-1] is ... and sys.version_info < (3, 9, 2): - # Hack: Arguments must be types, replace it with one. - parameters = (*parameters[:-1], _EllipsisDummy) - if sys.version_info >= (3, 10, 3): - concatenate = _ConcatenateGenericAlias(origin, parameters, - _typevar_types=(TypeVar, ParamSpec), - _paramspec_tvars=True) - else: - concatenate = _ConcatenateGenericAlias(origin, parameters) - if parameters[-1] is not _EllipsisDummy: - return concatenate - # Remove dummy again - concatenate.__args__ = tuple(p if p is not _EllipsisDummy else ... - for p in concatenate.__args__) - if sys.version_info < (3, 10): - # backport needs __args__ adjustment only - return concatenate - concatenate.__parameters__ = tuple(p for p in concatenate.__parameters__ - if p is not _EllipsisDummy) - return concatenate - - -# 3.8-3.10 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = (*(typing._type_check(p, msg) for p in parameters[:-1]), - parameters[-1]) - return _create_concatenate_alias(self, parameters) - - -# 3.11+; Concatenate does not accept ellipsis in 3.10 -if sys.version_info >= (3, 11): - Concatenate = typing.Concatenate -# 3.9-3.10 -elif sys.version_info[:2] >= (3, 9): - @_ExtensionsSpecialForm - def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - return _concatenate_getitem(self, parameters) -# 3.8 -else: - class _ConcatenateForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateForm( - 'Concatenate', - doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """) - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_ExtensionsSpecialForm - def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) -# 3.8 -else: - class _TypeGuardForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - TypeGuard = _TypeGuardForm( - 'TypeGuard', - doc="""Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """) - -# 3.13+ -if hasattr(typing, 'TypeIs'): - TypeIs = typing.TypeIs -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_ExtensionsSpecialForm - def TypeIs(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type narrower function. ``TypeIs`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeIs[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeIs`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the intersection of the type inside ``TypeIs`` and the argument's - previously known type. - - For example:: - - def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: - return hasattr(val, '__await__') - - def f(val: Union[int, Awaitable[int]]) -> int: - if is_awaitable(val): - assert_type(val, Awaitable[int]) - else: - assert_type(val, int) - - ``TypeIs`` also works with type variables. For more information, see - PEP 742 (Narrowing types with TypeIs). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) -# 3.8 -else: - class _TypeIsForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - TypeIs = _TypeIsForm( - 'TypeIs', - doc="""Special typing form used to annotate the return type of a user-defined - type narrower function. ``TypeIs`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeIs[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeIs`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the intersection of the type inside ``TypeIs`` and the argument's - previously known type. - - For example:: - - def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: - return hasattr(val, '__await__') - - def f(val: Union[int, Awaitable[int]]) -> int: - if is_awaitable(val): - assert_type(val, Awaitable[int]) - else: - assert_type(val, int) - - ``TypeIs`` also works with type variables. For more information, see - PEP 742 (Narrowing types with TypeIs). - """) - -# 3.14+? -if hasattr(typing, 'TypeForm'): - TypeForm = typing.TypeForm -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeFormForm(_ExtensionsSpecialForm, _root=True): - # TypeForm(X) is equivalent to X but indicates to the type checker - # that the object is a TypeForm. - def __call__(self, obj, /): - return obj - - @_TypeFormForm - def TypeForm(self, parameters): - """A special form representing the value that results from the evaluation - of a type expression. This value encodes the information supplied in the - type expression, and it represents the type described by that type expression. - - When used in a type expression, TypeForm describes a set of type form objects. - It accepts a single type argument, which must be a valid type expression. - ``TypeForm[T]`` describes the set of all type form objects that represent - the type T or types that are assignable to T. - - Usage: - - def cast[T](typ: TypeForm[T], value: Any) -> T: ... - - reveal_type(cast(int, "x")) # int - - See PEP 747 for more information. - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) -# 3.8 -else: - class _TypeFormForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - def __call__(self, obj, /): - return obj - - TypeForm = _TypeFormForm( - 'TypeForm', - doc="""A special form representing the value that results from the evaluation - of a type expression. This value encodes the information supplied in the - type expression, and it represents the type described by that type expression. - - When used in a type expression, TypeForm describes a set of type form objects. - It accepts a single type argument, which must be a valid type expression. - ``TypeForm[T]`` describes the set of all type form objects that represent - the type T or types that are assignable to T. - - Usage: - - def cast[T](typ: TypeForm[T], value: Any) -> T: ... - - reveal_type(cast(int, "x")) # int - - See PEP 747 for more information. - """) - - -# Vendored from cpython typing._SpecialFrom -class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name - - raise AttributeError(item) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") - - def __repr__(self): - return f'typing_extensions.{self._name}' - - def __reduce__(self): - return self._name - - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass()") - - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) - - -if hasattr(typing, "LiteralString"): # 3.11+ - LiteralString = typing.LiteralString -else: - @_SpecialForm - def LiteralString(self, params): - """Represents an arbitrary literal string. - - Example:: - - from typing_extensions import LiteralString - - def query(sql: LiteralString) -> ...: - ... - - query("SELECT * FROM table") # ok - query(f"SELECT * FROM {input()}") # not ok - - See PEP 675 for details. - - """ - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Self"): # 3.11+ - Self = typing.Self -else: - @_SpecialForm - def Self(self, params): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Never"): # 3.11+ - Never = typing.Never -else: - @_SpecialForm - def Never(self, params): - """The bottom type, a type that has no members. - - This can be used to define a function that should never be - called, or a function that never returns:: - - from typing_extensions import Never - - def never_call_me(arg: Never) -> None: - pass - - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, 'Required'): # 3.11+ - Required = typing.Required - NotRequired = typing.NotRequired -elif sys.version_info[:2] >= (3, 9): # 3.9-3.10 - @_ExtensionsSpecialForm - def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - @_ExtensionsSpecialForm - def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - -else: # 3.8 - class _RequiredForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - Required = _RequiredForm( - 'Required', - doc="""A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """) - NotRequired = _RequiredForm( - 'NotRequired', - doc="""A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """) - - -if hasattr(typing, 'ReadOnly'): - ReadOnly = typing.ReadOnly -elif sys.version_info[:2] >= (3, 9): # 3.9-3.12 - @_ExtensionsSpecialForm - def ReadOnly(self, parameters): - """A special typing construct to mark an item of a TypedDict as read-only. - - For example: - - class Movie(TypedDict): - title: ReadOnly[str] - year: int - - def mutate_movie(m: Movie) -> None: - m["year"] = 1992 # allowed - m["title"] = "The Matrix" # typechecker error - - There is no runtime checking for this property. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - -else: # 3.8 - class _ReadOnlyForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - ReadOnly = _ReadOnlyForm( - 'ReadOnly', - doc="""A special typing construct to mark a key of a TypedDict as read-only. - - For example: - - class Movie(TypedDict): - title: ReadOnly[str] - year: int - - def mutate_movie(m: Movie) -> None: - m["year"] = 1992 # allowed - m["title"] = "The Matrix" # typechecker error - - There is no runtime checking for this propery. - """) - - -_UNPACK_DOC = """\ -Type unpack operator. - -The type unpack operator takes the child types from some container type, -such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For -example: - - # For some generic class `Foo`: - Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] - - Ts = TypeVarTuple('Ts') - # Specifies that `Bar` is generic in an arbitrary number of types. - # (Think of `Ts` as a tuple of an arbitrary number of individual - # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the - # `Generic[]`.) - class Bar(Generic[Unpack[Ts]]): ... - Bar[int] # Valid - Bar[int, str] # Also valid - -From Python 3.11, this can also be done using the `*` operator: - - Foo[*tuple[int, str]] - class Bar(Generic[*Ts]): ... - -The operator can also be used along with a `TypedDict` to annotate -`**kwargs` in a function signature. For instance: - - class Movie(TypedDict): - name: str - year: int - - # This function expects two keyword arguments - *name* of type `str` and - # *year* of type `int`. - def foo(**kwargs: Unpack[Movie]): ... - -Note that there is only some runtime checking of this operator. Not -everything the runtime allows may be accepted by static type checkers. - -For more information, see PEP 646 and PEP 692. -""" - - -if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[] - Unpack = typing.Unpack - - def _is_unpack(obj): - return get_origin(obj) is Unpack - -elif sys.version_info[:2] >= (3, 9): # 3.9+ - class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, getitem): - super().__init__(getitem) - self.__doc__ = _UNPACK_DOC - - class _UnpackAlias(typing._GenericAlias, _root=True): - if sys.version_info < (3, 11): - # needed for compatibility with Generic[Unpack[Ts]] - __class__ = typing.TypeVar - - @property - def __typing_unpacked_tuple_args__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - arg, = self.__args__ - if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)): - if arg.__origin__ is not tuple: - raise TypeError("Unpack[...] must be used with a tuple type") - return arg.__args__ - return None - - @property - def __typing_is_unpacked_typevartuple__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - return isinstance(self.__args__[0], TypeVarTuple) - - def __getitem__(self, args): - if self.__typing_is_unpacked_typevartuple__: - return args - return super().__getitem__(args) - - @_UnpackSpecialForm - def Unpack(self, parameters): - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - -else: # 3.8 - class _UnpackAlias(typing._GenericAlias, _root=True): - __class__ = typing.TypeVar - - @property - def __typing_unpacked_tuple_args__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - arg, = self.__args__ - if isinstance(arg, typing._GenericAlias): - if arg.__origin__ is not tuple: - raise TypeError("Unpack[...] must be used with a tuple type") - return arg.__args__ - return None - - @property - def __typing_is_unpacked_typevartuple__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - return isinstance(self.__args__[0], TypeVarTuple) - - def __getitem__(self, args): - if self.__typing_is_unpacked_typevartuple__: - return args - return super().__getitem__(args) - - class _UnpackForm(_ExtensionsSpecialForm, _root=True): - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - Unpack = _UnpackForm('Unpack', doc=_UNPACK_DOC) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - - -def _unpack_args(*args): - newargs = [] - for arg in args: - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs is not None and (not (subargs and subargs[-1] is ...)): - newargs.extend(subargs) - else: - newargs.append(arg) - return newargs - - -if _PEP_696_IMPLEMENTED: - from typing import TypeVarTuple - -elif hasattr(typing, "TypeVarTuple"): # 3.11+ - - # Add default parameter - PEP 696 - class TypeVarTuple(metaclass=_TypeVarLikeMeta): - """Type variable tuple.""" - - _backported_typevarlike = typing.TypeVarTuple - - def __new__(cls, name, *, default=NoDefault): - tvt = typing.TypeVarTuple(name) - _set_default(tvt, default) - _set_module(tvt) - - def _typevartuple_prepare_subst(alias, args): - params = alias.__parameters__ - typevartuple_index = params.index(tvt) - for param in params[typevartuple_index + 1:]: - if isinstance(param, TypeVarTuple): - raise TypeError( - f"More than one TypeVarTuple parameter in {alias}" - ) - - alen = len(args) - plen = len(params) - left = typevartuple_index - right = plen - typevartuple_index - 1 - var_tuple_index = None - fillarg = None - for k, arg in enumerate(args): - if not isinstance(arg, type): - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs and len(subargs) == 2 and subargs[-1] is ...: - if var_tuple_index is not None: - raise TypeError( - "More than one unpacked " - "arbitrary-length tuple argument" - ) - var_tuple_index = k - fillarg = subargs[0] - if var_tuple_index is not None: - left = min(left, var_tuple_index) - right = min(right, alen - var_tuple_index - 1) - elif left + right > alen: - raise TypeError(f"Too few arguments for {alias};" - f" actual {alen}, expected at least {plen - 1}") - if left == alen - right and tvt.has_default(): - replacement = _unpack_args(tvt.__default__) - else: - replacement = args[left: alen - right] - - return ( - *args[:left], - *([fillarg] * (typevartuple_index - left)), - replacement, - *([fillarg] * (plen - right - left - typevartuple_index - 1)), - *args[alen - right:], - ) - - tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst - return tvt - - def __init_subclass__(self, *args, **kwds): - raise TypeError("Cannot subclass special typing classes") - -else: # <=3.10 - class TypeVarTuple(_DefaultMixin): - """Type variable tuple. - - Usage:: - - Ts = TypeVarTuple('Ts') - - In the same way that a normal type variable is a stand-in for a single - type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* - type such as ``Tuple[int, str]``. - - Type variable tuples can be used in ``Generic`` declarations. - Consider the following example:: - - class Array(Generic[*Ts]): ... - - The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, - where ``T1`` and ``T2`` are type variables. To use these type variables - as type parameters of ``Array``, we must *unpack* the type variable tuple using - the star operator: ``*Ts``. The signature of ``Array`` then behaves - as if we had simply written ``class Array(Generic[T1, T2]): ...``. - In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows - us to parameterise the class with an *arbitrary* number of type parameters. - - Type variable tuples can be used anywhere a normal ``TypeVar`` can. - This includes class definitions, as shown above, as well as function - signatures and variable annotations:: - - class Array(Generic[*Ts]): - - def __init__(self, shape: Tuple[*Ts]): - self._shape: Tuple[*Ts] = shape - - def get_shape(self) -> Tuple[*Ts]: - return self._shape - - shape = (Height(480), Width(640)) - x: Array[Height, Width] = Array(shape) - y = abs(x) # Inferred type is Array[Height, Width] - z = x + x # ... is Array[Height, Width] - x.get_shape() # ... is tuple[Height, Width] - - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - def __iter__(self): - yield self.__unpacked__ - - def __init__(self, name, *, default=NoDefault): - self.__name__ = name - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - self.__unpacked__ = Unpack[self] - - def __repr__(self): - return self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(self, *args, **kwds): - if '_root' not in kwds: - raise TypeError("Cannot subclass special typing classes") - - -if hasattr(typing, "reveal_type"): # 3.11+ - reveal_type = typing.reveal_type -else: # <=3.10 - def reveal_type(obj: T, /) -> T: - """Reveal the inferred type of a variable. - - When a static type checker encounters a call to ``reveal_type()``, - it will emit the inferred type of the argument:: - - x: int = 1 - reveal_type(x) - - Running a static type checker (e.g., ``mypy``) on this example - will produce output similar to 'Revealed type is "builtins.int"'. - - At runtime, the function prints the runtime type of the - argument and returns it unchanged. - - """ - print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) - return obj - - -if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"): # 3.11+ - _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH -else: # <=3.10 - _ASSERT_NEVER_REPR_MAX_LENGTH = 100 - - -if hasattr(typing, "assert_never"): # 3.11+ - assert_never = typing.assert_never -else: # <=3.10 - def assert_never(arg: Never, /) -> Never: - """Assert to the type checker that a line of code is unreachable. - - Example:: - - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - assert_never(arg) - - If a type checker finds that a call to assert_never() is - reachable, it will emit an error. - - At runtime, this throws an exception when called. - - """ - value = repr(arg) - if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: - value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...' - raise AssertionError(f"Expected code to be unreachable, but got: {value}") - - -if sys.version_info >= (3, 12): # 3.12+ - # dataclass_transform exists in 3.11 but lacks the frozen_default parameter - dataclass_transform = typing.dataclass_transform -else: # <=3.11 - def dataclass_transform( - *, - eq_default: bool = True, - order_default: bool = False, - kw_only_default: bool = False, - frozen_default: bool = False, - field_specifiers: typing.Tuple[ - typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], - ... - ] = (), - **kwargs: typing.Any, - ) -> typing.Callable[[T], T]: - """Decorator that marks a function, class, or metaclass as providing - dataclass-like behavior. - - Example: - - from typing_extensions import dataclass_transform - - _T = TypeVar("_T") - - # Used on a decorator function - @dataclass_transform() - def create_model(cls: type[_T]) -> type[_T]: - ... - return cls - - @create_model - class CustomerModel: - id: int - name: str - - # Used on a base class - @dataclass_transform() - class ModelBase: ... - - class CustomerModel(ModelBase): - id: int - name: str - - # Used on a metaclass - @dataclass_transform() - class ModelMeta(type): ... - - class ModelBase(metaclass=ModelMeta): ... - - class CustomerModel(ModelBase): - id: int - name: str - - Each of the ``CustomerModel`` classes defined in this example will now - behave similarly to a dataclass created with the ``@dataclasses.dataclass`` - decorator. For example, the type checker will synthesize an ``__init__`` - method. - - The arguments to this decorator can be used to customize this behavior: - - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - True or False if it is omitted by the caller. - - ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - - See PEP 681 for details. - - """ - def decorator(cls_or_fn): - cls_or_fn.__dataclass_transform__ = { - "eq_default": eq_default, - "order_default": order_default, - "kw_only_default": kw_only_default, - "frozen_default": frozen_default, - "field_specifiers": field_specifiers, - "kwargs": kwargs, - } - return cls_or_fn - return decorator - - -if hasattr(typing, "override"): # 3.12+ - override = typing.override -else: # <=3.11 - _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) - - def override(arg: _F, /) -> _F: - """Indicate that a method is intended to override a method in a base class. - - Usage: - - class Base: - def method(self) -> None: - pass - - class Child(Base): - @override - def method(self) -> None: - super().method() - - When this decorator is applied to a method, the type checker will - validate that it overrides a method with the same name on a base class. - This helps prevent bugs that may occur when a base class is changed - without an equivalent change to a child class. - - There is no runtime checking of these properties. The decorator - sets the ``__override__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - - See PEP 698 for details. - - """ - try: - arg.__override__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return arg - - -# Python 3.13.3+ contains a fix for the wrapped __new__ -if sys.version_info >= (3, 13, 3): - deprecated = warnings.deprecated -else: - _T = typing.TypeVar("_T") - - class deprecated: - """Indicate that a class, function or overload is deprecated. - - When this decorator is applied to an object, the type checker - will generate a diagnostic on usage of the deprecated object. - - Usage: - - @deprecated("Use B instead") - class A: - pass - - @deprecated("Use g instead") - def f(): - pass - - @overload - @deprecated("int support is deprecated") - def g(x: int) -> int: ... - @overload - def g(x: str) -> int: ... - - The warning specified by *category* will be emitted at runtime - on use of deprecated objects. For functions, that happens on calls; - for classes, on instantiation and on creation of subclasses. - If the *category* is ``None``, no warning is emitted at runtime. - The *stacklevel* determines where the - warning is emitted. If it is ``1`` (the default), the warning - is emitted at the direct caller of the deprecated object; if it - is higher, it is emitted further up the stack. - Static type checker behavior is not affected by the *category* - and *stacklevel* arguments. - - The deprecation message passed to the decorator is saved in the - ``__deprecated__`` attribute on the decorated object. - If applied to an overload, the decorator - must be after the ``@overload`` decorator for the attribute to - exist on the overload as returned by ``get_overloads()``. - - See PEP 702 for details. - - """ - def __init__( - self, - message: str, - /, - *, - category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, - stacklevel: int = 1, - ) -> None: - if not isinstance(message, str): - raise TypeError( - "Expected an object of type str for 'message', not " - f"{type(message).__name__!r}" - ) - self.message = message - self.category = category - self.stacklevel = stacklevel - - def __call__(self, arg: _T, /) -> _T: - # Make sure the inner functions created below don't - # retain a reference to self. - msg = self.message - category = self.category - stacklevel = self.stacklevel - if category is None: - arg.__deprecated__ = msg - return arg - elif isinstance(arg, type): - import functools - from types import MethodType - - original_new = arg.__new__ - - @functools.wraps(original_new) - def __new__(cls, /, *args, **kwargs): - if cls is arg: - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - if original_new is not object.__new__: - return original_new(cls, *args, **kwargs) - # Mirrors a similar check in object.__new__. - elif cls.__init__ is object.__init__ and (args or kwargs): - raise TypeError(f"{cls.__name__}() takes no arguments") - else: - return original_new(cls) - - arg.__new__ = staticmethod(__new__) - - original_init_subclass = arg.__init_subclass__ - # We need slightly different behavior if __init_subclass__ - # is a bound method (likely if it was implemented in Python) - if isinstance(original_init_subclass, MethodType): - original_init_subclass = original_init_subclass.__func__ - - @functools.wraps(original_init_subclass) - def __init_subclass__(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return original_init_subclass(*args, **kwargs) - - arg.__init_subclass__ = classmethod(__init_subclass__) - # Or otherwise, which likely means it's a builtin such as - # object's implementation of __init_subclass__. - else: - @functools.wraps(original_init_subclass) - def __init_subclass__(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return original_init_subclass(*args, **kwargs) - - arg.__init_subclass__ = __init_subclass__ - - arg.__deprecated__ = __new__.__deprecated__ = msg - __init_subclass__.__deprecated__ = msg - return arg - elif callable(arg): - import asyncio.coroutines - import functools - import inspect - - @functools.wraps(arg) - def wrapper(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return arg(*args, **kwargs) - - if asyncio.coroutines.iscoroutinefunction(arg): - if sys.version_info >= (3, 12): - wrapper = inspect.markcoroutinefunction(wrapper) - else: - wrapper._is_coroutine = asyncio.coroutines._is_coroutine - - arg.__deprecated__ = wrapper.__deprecated__ = msg - return wrapper - else: - raise TypeError( - "@deprecated decorator with non-None category must be applied to " - f"a class or callable, not {arg!r}" - ) - -if sys.version_info < (3, 10): - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias) - ) -else: - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, - ( - tuple, - list, - ParamSpec, - _ConcatenateGenericAlias, - typing._ConcatenateGenericAlias, - ), - ) - - -# We have to do some monkey patching to deal with the dual nature of -# Unpack/TypeVarTuple: -# - We want Unpack to be a kind of TypeVar so it gets accepted in -# Generic[Unpack[Ts]] -# - We want it to *not* be treated as a TypeVar for the purposes of -# counting generic parameters, so that when we subscript a generic, -# the runtime doesn't try to substitute the Unpack with the subscripted type. -if not hasattr(typing, "TypeVarTuple"): - def _check_generic(cls, parameters, elen=_marker): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - # If substituting a single ParamSpec with multiple arguments - # we do not check the count - if (inspect.isclass(cls) and issubclass(cls, typing.Generic) - and len(cls.__parameters__) == 1 - and isinstance(cls.__parameters__[0], ParamSpec) - and parameters - and not _is_param_expr(parameters[0]) - ): - # Generic modifies parameters variable, but here we cannot do this - return - - if not elen: - raise TypeError(f"{cls} is not a generic class") - if elen is _marker: - if not hasattr(cls, "__parameters__") or not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - elen = len(cls.__parameters__) - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) - if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): - return - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - things = "arguments" if sys.version_info >= (3, 10) else "parameters" - raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}" - f" for {cls}; actual {alen}, expected {expect_val}") -else: - # Python 3.11+ - - def _check_generic(cls, parameters, elen): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - if not elen: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments" - f" for {cls}; actual {alen}, expected {expect_val}") - -if not _PEP_696_IMPLEMENTED: - typing._check_generic = _check_generic - - -def _has_generic_or_protocol_as_origin() -> bool: - try: - frame = sys._getframe(2) - # - Catch AttributeError: not all Python implementations have sys._getframe() - # - Catch ValueError: maybe we're called from an unexpected module - # and the call stack isn't deep enough - except (AttributeError, ValueError): - return False # err on the side of leniency - else: - # If we somehow get invoked from outside typing.py, - # also err on the side of leniency - if frame.f_globals.get("__name__") != "typing": - return False - origin = frame.f_locals.get("origin") - # Cannot use "in" because origin may be an object with a buggy __eq__ that - # throws an error. - return origin is typing.Generic or origin is Protocol or origin is typing.Protocol - - -_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)} - - -def _is_unpacked_typevartuple(x) -> bool: - if get_origin(x) is not Unpack: - return False - args = get_args(x) - return ( - bool(args) - and len(args) == 1 - and type(args[0]) in _TYPEVARTUPLE_TYPES - ) - - -# Python 3.11+ _collect_type_vars was renamed to _collect_parameters -if hasattr(typing, '_collect_type_vars'): - def _collect_type_vars(types, typevar_types=None): - """Collect all type variable contained in types in order of - first appearance (lexicographic order). For example:: - - _collect_type_vars((T, List[S, T])) == (T, S) - """ - if typevar_types is None: - typevar_types = typing.TypeVar - tvars = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with a default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in types: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - elif ( - isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias) - and t not in tvars - ): - if enforce_default_ordering: - has_default = getattr(t, '__default__', NoDefault) is not NoDefault - if has_default: - if type_var_tuple_encountered: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - tvars.append(t) - if _should_collect_from_parameters(t): - tvars.extend([t for t in t.__parameters__ if t not in tvars]) - elif isinstance(t, tuple): - # Collect nested type_vars - # tuple wrapped by _prepare_paramspec_params(cls, params) - for x in t: - for collected in _collect_type_vars([x]): - if collected not in tvars: - tvars.append(collected) - return tuple(tvars) - - typing._collect_type_vars = _collect_type_vars -else: - def _collect_parameters(args): - """Collect all type variables and parameter specifications in args - in order of first appearance (lexicographic order). - - For example:: - - assert _collect_parameters((T, Callable[P, T])) == (T, P) - """ - parameters = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in args: - if isinstance(t, type): - # We don't want __parameters__ descriptor of a bare Python class. - pass - elif isinstance(t, tuple): - # `t` might be a tuple, when `ParamSpec` is substituted with - # `[T, int]`, or `[int, *Ts]`, etc. - for x in t: - for collected in _collect_parameters([x]): - if collected not in parameters: - parameters.append(collected) - elif hasattr(t, '__typing_subst__'): - if t not in parameters: - if enforce_default_ordering: - has_default = ( - getattr(t, '__default__', NoDefault) is not NoDefault - ) - - if type_var_tuple_encountered and has_default: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - - if has_default: - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - parameters.append(t) - else: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - for x in getattr(t, '__parameters__', ()): - if x not in parameters: - parameters.append(x) - - return tuple(parameters) - - if not _PEP_696_IMPLEMENTED: - typing._collect_parameters = _collect_parameters - -# Backport typing.NamedTuple as it exists in Python 3.13. -# In 3.11, the ability to define generic `NamedTuple`s was supported. -# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. -# On 3.12, we added __orig_bases__ to call-based NamedTuples -# On 3.13, we deprecated kwargs-based NamedTuples -if sys.version_info >= (3, 13): - NamedTuple = typing.NamedTuple -else: - def _make_nmtuple(name, types, module, defaults=()): - fields = [n for n, t in types] - annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") - for n, t in types} - nm_tpl = collections.namedtuple(name, fields, - defaults=defaults, module=module) - nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations - # The `_field_types` attribute was removed in 3.9; - # in earlier versions, it is the same as the `__annotations__` attribute - if sys.version_info < (3, 9): - nm_tpl._field_types = annotations - return nm_tpl - - _prohibited_namedtuple_fields = typing._prohibited - _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) - - class _NamedTupleMeta(type): - def __new__(cls, typename, bases, ns): - assert _NamedTuple in bases - for base in bases: - if base is not _NamedTuple and base is not typing.Generic: - raise TypeError( - 'can only inherit from a NamedTuple type and Generic') - bases = tuple(tuple if base is _NamedTuple else base for base in bases) - if "__annotations__" in ns: - types = ns["__annotations__"] - elif "__annotate__" in ns: - # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated - types = ns["__annotate__"](1) - else: - types = {} - default_names = [] - for field_name in types: - if field_name in ns: - default_names.append(field_name) - elif default_names: - raise TypeError(f"Non-default namedtuple field {field_name} " - f"cannot follow default field" - f"{'s' if len(default_names) > 1 else ''} " - f"{', '.join(default_names)}") - nm_tpl = _make_nmtuple( - typename, types.items(), - defaults=[ns[n] for n in default_names], - module=ns['__module__'] - ) - nm_tpl.__bases__ = bases - if typing.Generic in bases: - if hasattr(typing, '_generic_class_getitem'): # 3.12+ - nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) - else: - class_getitem = typing.Generic.__class_getitem__.__func__ - nm_tpl.__class_getitem__ = classmethod(class_getitem) - # update from user namespace without overriding special namedtuple attributes - for key, val in ns.items(): - if key in _prohibited_namedtuple_fields: - raise AttributeError("Cannot overwrite NamedTuple attribute " + key) - elif key not in _special_namedtuple_fields: - if key not in nm_tpl._fields: - setattr(nm_tpl, key, ns[key]) - try: - set_name = type(val).__set_name__ - except AttributeError: - pass - else: - try: - set_name(val, nm_tpl, key) - except BaseException as e: - msg = ( - f"Error calling __set_name__ on {type(val).__name__!r} " - f"instance {key!r} in {typename!r}" - ) - # BaseException.add_note() existed on py311, - # but the __set_name__ machinery didn't start - # using add_note() until py312. - # Making sure exceptions are raised in the same way - # as in "normal" classes seems most important here. - if sys.version_info >= (3, 12): - e.add_note(msg) - raise - else: - raise RuntimeError(msg) from e - - if typing.Generic in bases: - nm_tpl.__init_subclass__() - return nm_tpl - - _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) - - def _namedtuple_mro_entries(bases): - assert NamedTuple in bases - return (_NamedTuple,) - - @_ensure_subclassable(_namedtuple_mro_entries) - def NamedTuple(typename, fields=_marker, /, **kwargs): - """Typed version of namedtuple. - - Usage:: - - class Employee(NamedTuple): - name: str - id: int - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - The resulting class has an extra __annotations__ attribute, giving a - dict that maps field names to types. (The field names are also in - the _fields attribute, which is part of the namedtuple API.) - An alternative equivalent functional syntax is also accepted:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) - """ - if fields is _marker: - if kwargs: - deprecated_thing = "Creating NamedTuple classes using keyword arguments" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "Use the class-based or functional syntax instead." - ) - else: - deprecated_thing = "Failing to pass a value for the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif fields is None: - if kwargs: - raise TypeError( - "Cannot pass `None` as the 'fields' parameter " - "and also specify fields using keyword arguments" - ) - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif kwargs: - raise TypeError("Either list of fields or keywords" - " can be provided to NamedTuple, not both") - if fields is _marker or fields is None: - warnings.warn( - deprecation_msg.format(name=deprecated_thing, remove="3.15"), - DeprecationWarning, - stacklevel=2, - ) - fields = kwargs.items() - nt = _make_nmtuple(typename, fields, module=_caller()) - nt.__orig_bases__ = (NamedTuple,) - return nt - - -if hasattr(collections.abc, "Buffer"): - Buffer = collections.abc.Buffer -else: - class Buffer(abc.ABC): # noqa: B024 - """Base class for classes that implement the buffer protocol. - - The buffer protocol allows Python objects to expose a low-level - memory buffer interface. Before Python 3.12, it is not possible - to implement the buffer protocol in pure Python code, or even - to check whether a class implements the buffer protocol. In - Python 3.12 and higher, the ``__buffer__`` method allows access - to the buffer protocol from Python code, and the - ``collections.abc.Buffer`` ABC allows checking whether a class - implements the buffer protocol. - - To indicate support for the buffer protocol in earlier versions, - inherit from this ABC, either in a stub file or at runtime, - or use ABC registration. This ABC provides no methods, because - there is no Python-accessible methods shared by pre-3.12 buffer - classes. It is useful primarily for static checks. - - """ - - # As a courtesy, register the most common stdlib buffer classes. - Buffer.register(memoryview) - Buffer.register(bytearray) - Buffer.register(bytes) - - -# Backport of types.get_original_bases, available on 3.12+ in CPython -if hasattr(_types, "get_original_bases"): - get_original_bases = _types.get_original_bases -else: - def get_original_bases(cls, /): - """Return the class's "original" bases prior to modification by `__mro_entries__`. - - Examples:: - - from typing import TypeVar, Generic - from typing_extensions import NamedTuple, TypedDict - - T = TypeVar("T") - class Foo(Generic[T]): ... - class Bar(Foo[int], float): ... - class Baz(list[str]): ... - Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) - Spam = TypedDict("Spam", {"a": int, "b": str}) - - assert get_original_bases(Bar) == (Foo[int], float) - assert get_original_bases(Baz) == (list[str],) - assert get_original_bases(Eggs) == (NamedTuple,) - assert get_original_bases(Spam) == (TypedDict,) - assert get_original_bases(int) == (object,) - """ - try: - return cls.__dict__.get("__orig_bases__", cls.__bases__) - except AttributeError: - raise TypeError( - f'Expected an instance of type, not {type(cls).__name__!r}' - ) from None - - -# NewType is a class on Python 3.10+, making it pickleable -# The error message for subclassing instances of NewType was improved on 3.11+ -if sys.version_info >= (3, 11): - NewType = typing.NewType -else: - class NewType: - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy callable that simply returns its argument. Usage:: - UserId = NewType('UserId', int) - def name_by_id(user_id: UserId) -> str: - ... - UserId('user') # Fails type check - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - num = UserId(5) + 1 # type: int - """ - - def __call__(self, obj, /): - return obj - - def __init__(self, name, tp): - self.__qualname__ = name - if '.' in name: - name = name.rpartition('.')[-1] - self.__name__ = name - self.__supertype__ = tp - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __mro_entries__(self, bases): - # We defined __mro_entries__ to get a better error message - # if a user attempts to subclass a NewType instance. bpo-46170 - supercls_name = self.__name__ - - class Dummy: - def __init_subclass__(cls): - subcls_name = cls.__name__ - raise TypeError( - f"Cannot subclass an instance of NewType. " - f"Perhaps you were looking for: " - f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" - ) - - return (Dummy,) - - def __repr__(self): - return f'{self.__module__}.{self.__qualname__}' - - def __reduce__(self): - return self.__qualname__ - - if sys.version_info >= (3, 10): - # PEP 604 methods - # It doesn't make sense to have these methods on Python <3.10 - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - -if sys.version_info >= (3, 14): - TypeAliasType = typing.TypeAliasType -# 3.8-3.13 -else: - if sys.version_info >= (3, 12): - # 3.12-3.14 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - typing.TypeAliasType, - TypeAliasType, - )) - else: - # 3.8-3.11 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - TypeAliasType, - )) - - if sys.version_info < (3, 10): - # Copied and pasted from https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Objects/genericaliasobject.c#L568-L582, - # so that we emulate the behaviour of `types.GenericAlias` - # on the latest versions of CPython - _ATTRIBUTE_DELEGATION_EXCLUSIONS = frozenset({ - "__class__", - "__bases__", - "__origin__", - "__args__", - "__unpacked__", - "__parameters__", - "__typing_unpacked_tuple_args__", - "__mro_entries__", - "__reduce_ex__", - "__reduce__", - "__copy__", - "__deepcopy__", - }) - - class _TypeAliasGenericAlias(typing._GenericAlias, _root=True): - def __getattr__(self, attr): - if attr in _ATTRIBUTE_DELEGATION_EXCLUSIONS: - return object.__getattr__(self, attr) - return getattr(self.__origin__, attr) - - if sys.version_info < (3, 9): - def __getitem__(self, item): - result = super().__getitem__(item) - result.__class__ = type(self) - return result - - class TypeAliasType: - """Create named, parameterized type aliases. - - This provides a backport of the new `type` statement in Python 3.12: - - type ListOrSet[T] = list[T] | set[T] - - is equivalent to: - - T = TypeVar("T") - ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) - - The name ListOrSet can then be used as an alias for the type it refers to. - - The type_params argument should contain all the type parameters used - in the value of the type alias. If the alias is not generic, this - argument is omitted. - - Static type checkers should only support type aliases declared using - TypeAliasType that follow these rules: - - - The first argument (the name) must be a string literal. - - The TypeAliasType instance must be immediately assigned to a variable - of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, - as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). - - """ - - def __init__(self, name: str, value, *, type_params=()): - if not isinstance(name, str): - raise TypeError("TypeAliasType name must be a string") - if not isinstance(type_params, tuple): - raise TypeError("type_params must be a tuple") - self.__value__ = value - self.__type_params__ = type_params - - default_value_encountered = False - parameters = [] - for type_param in type_params: - if ( - not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec)) - # 3.8-3.11 - # Unpack Backport passes isinstance(type_param, TypeVar) - or _is_unpack(type_param) - ): - raise TypeError(f"Expected a type param, got {type_param!r}") - has_default = ( - getattr(type_param, '__default__', NoDefault) is not NoDefault - ) - if default_value_encountered and not has_default: - raise TypeError(f"non-default type parameter '{type_param!r}'" - " follows default type parameter") - if has_default: - default_value_encountered = True - if isinstance(type_param, TypeVarTuple): - parameters.extend(type_param) - else: - parameters.append(type_param) - self.__parameters__ = tuple(parameters) - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - # Setting this attribute closes the TypeAliasType from further modification - self.__name__ = name - - def __setattr__(self, name: str, value: object, /) -> None: - if hasattr(self, "__name__"): - self._raise_attribute_error(name) - super().__setattr__(name, value) - - def __delattr__(self, name: str, /) -> Never: - self._raise_attribute_error(name) - - def _raise_attribute_error(self, name: str) -> Never: - # Match the Python 3.12 error messages exactly - if name == "__name__": - raise AttributeError("readonly attribute") - elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}: - raise AttributeError( - f"attribute '{name}' of 'typing.TypeAliasType' objects " - "is not writable" - ) - else: - raise AttributeError( - f"'typing.TypeAliasType' object has no attribute '{name}'" - ) - - def __repr__(self) -> str: - return self.__name__ - - if sys.version_info < (3, 11): - def _check_single_param(self, param, recursion=0): - # Allow [], [int], [int, str], [int, ...], [int, T] - if param is ...: - return ... - if param is None: - return None - # Note in <= 3.9 _ConcatenateGenericAlias inherits from list - if isinstance(param, list) and recursion == 0: - return [self._check_single_param(arg, recursion+1) - for arg in param] - return typing._type_check( - param, f'Subscripting {self.__name__} requires a type.' - ) - - def _check_parameters(self, parameters): - if sys.version_info < (3, 11): - return tuple( - self._check_single_param(item) - for item in parameters - ) - return tuple(typing._type_check( - item, f'Subscripting {self.__name__} requires a type.' - ) - for item in parameters - ) - - def __getitem__(self, parameters): - if not self.__type_params__: - raise TypeError("Only generic type aliases are subscriptable") - if not isinstance(parameters, tuple): - parameters = (parameters,) - # Using 3.9 here will create problems with Concatenate - if sys.version_info >= (3, 10): - return _types.GenericAlias(self, parameters) - type_vars = _collect_type_vars(parameters) - parameters = self._check_parameters(parameters) - alias = _TypeAliasGenericAlias(self, parameters) - # alias.__parameters__ is not complete if Concatenate is present - # as it is converted to a list from which no parameters are extracted. - if alias.__parameters__ != type_vars: - alias.__parameters__ = type_vars - return alias - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - "type 'typing_extensions.TypeAliasType' is not an acceptable base type" - ) - - # The presence of this method convinces typing._type_check - # that TypeAliasTypes are types. - def __call__(self): - raise TypeError("Type alias is not callable") - - if sys.version_info >= (3, 10): - def __or__(self, right): - # For forward compatibility with 3.12, reject Unions - # that are not accepted by the built-in Union. - if not _is_unionable(right): - return NotImplemented - return typing.Union[self, right] - - def __ror__(self, left): - if not _is_unionable(left): - return NotImplemented - return typing.Union[left, self] - - -if hasattr(typing, "is_protocol"): - is_protocol = typing.is_protocol - get_protocol_members = typing.get_protocol_members -else: - def is_protocol(tp: type, /) -> bool: - """Return True if the given type is a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, is_protocol - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> is_protocol(P) - True - >>> is_protocol(int) - False - """ - return ( - isinstance(tp, type) - and getattr(tp, '_is_protocol', False) - and tp is not Protocol - and tp is not typing.Protocol - ) - - def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: - """Return the set of members defined in a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, get_protocol_members - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> get_protocol_members(P) - frozenset({'a', 'b'}) - - Raise a TypeError for arguments that are not Protocols. - """ - if not is_protocol(tp): - raise TypeError(f'{tp!r} is not a Protocol') - if hasattr(tp, '__protocol_attrs__'): - return frozenset(tp.__protocol_attrs__) - return frozenset(_get_protocol_attrs(tp)) - - -if hasattr(typing, "Doc"): - Doc = typing.Doc -else: - class Doc: - """Define the documentation of a type annotation using ``Annotated``, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute ``documentation``. - - Example:: - - >>> from typing_extensions import Annotated, Doc - >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... - """ - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation - - -_CapsuleType = getattr(_types, "CapsuleType", None) - -if _CapsuleType is None: - try: - import _socket - except ImportError: - pass - else: - _CAPI = getattr(_socket, "CAPI", None) - if _CAPI is not None: - _CapsuleType = type(_CAPI) - -if _CapsuleType is not None: - CapsuleType = _CapsuleType - __all__.append("CapsuleType") - - -# Using this convoluted approach so that this keeps working -# whether we end up using PEP 649 as written, PEP 749, or -# some other variation: in any case, inspect.get_annotations -# will continue to exist and will gain a `format` parameter. -_PEP_649_OR_749_IMPLEMENTED = ( - hasattr(inspect, 'get_annotations') - and inspect.get_annotations.__kwdefaults__ is not None - and "format" in inspect.get_annotations.__kwdefaults__ -) - - -class Format(enum.IntEnum): - VALUE = 1 - FORWARDREF = 2 - STRING = 3 - - -if _PEP_649_OR_749_IMPLEMENTED: - get_annotations = inspect.get_annotations -else: - def get_annotations(obj, *, globals=None, locals=None, eval_str=False, - format=Format.VALUE): - """Compute the annotations dict for an object. - - obj may be a callable, class, or module. - Passing in an object of any other type raises TypeError. - - Returns a dict. get_annotations() returns a new dict every time - it's called; calling it twice on the same object will return two - different but equivalent dicts. - - This is a backport of `inspect.get_annotations`, which has been - in the standard library since Python 3.10. See the standard library - documentation for more: - - https://docs.python.org/3/library/inspect.html#inspect.get_annotations - - This backport adds the *format* argument introduced by PEP 649. The - three formats supported are: - * VALUE: the annotations are returned as-is. This is the default and - it is compatible with the behavior on previous Python versions. - * FORWARDREF: return annotations as-is if possible, but replace any - undefined names with ForwardRef objects. The implementation proposed by - PEP 649 relies on language changes that cannot be backported; the - typing-extensions implementation simply returns the same result as VALUE. - * STRING: return annotations as strings, in a format close to the original - source. Again, this behavior cannot be replicated directly in a backport. - As an approximation, typing-extensions retrieves the annotations under - VALUE semantics and then stringifies them. - - The purpose of this backport is to allow users who would like to use - FORWARDREF or STRING semantics once PEP 649 is implemented, but who also - want to support earlier Python versions, to simply write: - - typing_extensions.get_annotations(obj, format=Format.FORWARDREF) - - """ - format = Format(format) - - if eval_str and format is not Format.VALUE: - raise ValueError("eval_str=True is only supported with format=Format.VALUE") - - if isinstance(obj, type): - # class - obj_dict = getattr(obj, '__dict__', None) - if obj_dict and hasattr(obj_dict, 'get'): - ann = obj_dict.get('__annotations__', None) - if isinstance(ann, _types.GetSetDescriptorType): - ann = None - else: - ann = None - - obj_globals = None - module_name = getattr(obj, '__module__', None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - obj_globals = getattr(module, '__dict__', None) - obj_locals = dict(vars(obj)) - unwrap = obj - elif isinstance(obj, _types.ModuleType): - # module - ann = getattr(obj, '__annotations__', None) - obj_globals = obj.__dict__ - obj_locals = None - unwrap = None - elif callable(obj): - # this includes types.Function, types.BuiltinFunctionType, - # types.BuiltinMethodType, functools.partial, functools.singledispatch, - # "class funclike" from Lib/test/test_inspect... on and on it goes. - ann = getattr(obj, '__annotations__', None) - obj_globals = getattr(obj, '__globals__', None) - obj_locals = None - unwrap = obj - elif hasattr(obj, '__annotations__'): - ann = obj.__annotations__ - obj_globals = obj_locals = unwrap = None - else: - raise TypeError(f"{obj!r} is not a module, class, or callable.") - - if ann is None: - return {} - - if not isinstance(ann, dict): - raise ValueError(f"{obj!r}.__annotations__ is neither a dict nor None") - - if not ann: - return {} - - if not eval_str: - if format is Format.STRING: - return { - key: value if isinstance(value, str) else typing._type_repr(value) - for key, value in ann.items() - } - return dict(ann) - - if unwrap is not None: - while True: - if hasattr(unwrap, '__wrapped__'): - unwrap = unwrap.__wrapped__ - continue - if isinstance(unwrap, functools.partial): - unwrap = unwrap.func - continue - break - if hasattr(unwrap, "__globals__"): - obj_globals = unwrap.__globals__ - - if globals is None: - globals = obj_globals - if locals is None: - locals = obj_locals or {} - - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - if type_params := getattr(obj, "__type_params__", ()): - locals = {param.__name__: param for param in type_params} | locals - - return_value = {key: - value if not isinstance(value, str) else eval(value, globals, locals) - for key, value in ann.items() } - return return_value - - -if hasattr(typing, "evaluate_forward_ref"): - evaluate_forward_ref = typing.evaluate_forward_ref -else: - # Implements annotationlib.ForwardRef.evaluate - def _eval_with_owner( - forward_ref, *, owner=None, globals=None, locals=None, type_params=None - ): - if forward_ref.__forward_evaluated__: - return forward_ref.__forward_value__ - if getattr(forward_ref, "__cell__", None) is not None: - try: - value = forward_ref.__cell__.cell_contents - except ValueError: - pass - else: - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - if owner is None: - owner = getattr(forward_ref, "__owner__", None) - - if ( - globals is None - and getattr(forward_ref, "__forward_module__", None) is not None - ): - globals = getattr( - sys.modules.get(forward_ref.__forward_module__, None), "__dict__", None - ) - if globals is None: - globals = getattr(forward_ref, "__globals__", None) - if globals is None: - if isinstance(owner, type): - module_name = getattr(owner, "__module__", None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - globals = getattr(module, "__dict__", None) - elif isinstance(owner, _types.ModuleType): - globals = getattr(owner, "__dict__", None) - elif callable(owner): - globals = getattr(owner, "__globals__", None) - - # If we pass None to eval() below, the globals of this module are used. - if globals is None: - globals = {} - - if locals is None: - locals = {} - if isinstance(owner, type): - locals.update(vars(owner)) - - if type_params is None and owner is not None: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - type_params = getattr(owner, "__type_params__", None) - - # type parameters require some special handling, - # as they exist in their own scope - # but `eval()` does not have a dedicated parameter for that scope. - # For classes, names in type parameter scopes should override - # names in the global scope (which here are called `localns`!), - # but should in turn be overridden by names in the class scope - # (which here are called `globalns`!) - if type_params is not None: - globals = dict(globals) - locals = dict(locals) - for param in type_params: - param_name = param.__name__ - if ( - _FORWARD_REF_HAS_CLASS and not forward_ref.__forward_is_class__ - ) or param_name not in globals: - globals[param_name] = param - locals.pop(param_name, None) - - arg = forward_ref.__forward_arg__ - if arg.isidentifier() and not keyword.iskeyword(arg): - if arg in locals: - value = locals[arg] - elif arg in globals: - value = globals[arg] - elif hasattr(builtins, arg): - return getattr(builtins, arg) - else: - raise NameError(arg) - else: - code = forward_ref.__forward_code__ - value = eval(code, globals, locals) - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - - def _lax_type_check( - value, msg, is_argument=True, *, module=None, allow_special_forms=False - ): - """ - A lax Python 3.11+ like version of typing._type_check - """ - if hasattr(typing, "_type_convert"): - if ( - sys.version_info >= (3, 10, 3) - or (3, 9, 10) < sys.version_info[:3] < (3, 10) - ): - # allow_special_forms introduced later cpython/#30926 (bpo-46539) - type_ = typing._type_convert( - value, - module=module, - allow_special_forms=allow_special_forms, - ) - # module was added with bpo-41249 before is_class (bpo-46539) - elif "__forward_module__" in typing.ForwardRef.__slots__: - type_ = typing._type_convert(value, module=module) - else: - type_ = typing._type_convert(value) - else: - if value is None: - return type(None) - if isinstance(value, str): - return ForwardRef(value) - type_ = value - invalid_generic_forms = (Generic, Protocol) - if not allow_special_forms: - invalid_generic_forms += (ClassVar,) - if is_argument: - invalid_generic_forms += (Final,) - if ( - isinstance(type_, typing._GenericAlias) - and get_origin(type_) in invalid_generic_forms - ): - raise TypeError(f"{type_} is not valid as type argument") from None - if type_ in (Any, LiteralString, NoReturn, Never, Self, TypeAlias): - return type_ - if allow_special_forms and type_ in (ClassVar, Final): - return type_ - if ( - isinstance(type_, (_SpecialForm, typing._SpecialForm)) - or type_ in (Generic, Protocol) - ): - raise TypeError(f"Plain {type_} is not valid as type argument") from None - if type(type_) is tuple: # lax version with tuple instead of callable - raise TypeError(f"{msg} Got {type_!r:.100}.") - return type_ - - def evaluate_forward_ref( - forward_ref, - *, - owner=None, - globals=None, - locals=None, - type_params=None, - format=Format.VALUE, - _recursive_guard=frozenset(), - ): - """Evaluate a forward reference as a type hint. - - This is similar to calling the ForwardRef.evaluate() method, - but unlike that method, evaluate_forward_ref() also: - - * Recursively evaluates forward references nested within the type hint. - * Rejects certain objects that are not valid type hints. - * Replaces type hints that evaluate to None with types.NoneType. - * Supports the *FORWARDREF* and *STRING* formats. - - *forward_ref* must be an instance of ForwardRef. *owner*, if given, - should be the object that holds the annotations that the forward reference - derived from, such as a module, class object, or function. It is used to - infer the namespaces to use for looking up names. *globals* and *locals* - can also be explicitly given to provide the global and local namespaces. - *type_params* is a tuple of type parameters that are in scope when - evaluating the forward reference. This parameter must be provided (though - it may be an empty tuple) if *owner* is not given and the forward reference - does not already have an owner set. *format* specifies the format of the - annotation and is a member of the annotationlib.Format enum. - - """ - if format == Format.STRING: - return forward_ref.__forward_arg__ - if forward_ref.__forward_arg__ in _recursive_guard: - return forward_ref - - # Evaluate the forward reference - try: - value = _eval_with_owner( - forward_ref, - owner=owner, - globals=globals, - locals=locals, - type_params=type_params, - ) - except NameError: - if format == Format.FORWARDREF: - return forward_ref - else: - raise - - msg = "Forward references must evaluate to types." - if not _FORWARD_REF_HAS_CLASS: - allow_special_forms = not forward_ref.__forward_is_argument__ - else: - allow_special_forms = forward_ref.__forward_is_class__ - type_ = _lax_type_check( - value, - msg, - is_argument=forward_ref.__forward_is_argument__, - allow_special_forms=allow_special_forms, - ) - - # Recursively evaluate the type - if isinstance(type_, ForwardRef): - if getattr(type_, "__forward_module__", True) is not None: - globals = None - return evaluate_forward_ref( - type_, - globals=globals, - locals=locals, - type_params=type_params, owner=owner, - _recursive_guard=_recursive_guard, format=format - ) - if sys.version_info < (3, 12, 5) and type_params: - # Make use of type_params - locals = dict(locals) if locals else {} - for tvar in type_params: - if tvar.__name__ not in locals: # lets not overwrite something present - locals[tvar.__name__] = tvar - if sys.version_info < (3, 9): - return typing._eval_type( - type_, - globals, - locals, - ) - if sys.version_info < (3, 12, 5): - return typing._eval_type( - type_, - globals, - locals, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - if sys.version_info < (3, 14): - return typing._eval_type( - type_, - globals, - locals, - type_params, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - return typing._eval_type( - type_, - globals, - locals, - type_params, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - format=format, - owner=owner, - ) - - -# Aliases for items that have always been in typing. -# Explicitly assign these (rather than using `from typing import *` at the top), -# so that we get a CI error if one of these is deleted from typing.py -# in a future version of Python -AbstractSet = typing.AbstractSet -AnyStr = typing.AnyStr -BinaryIO = typing.BinaryIO -Callable = typing.Callable -Collection = typing.Collection -Container = typing.Container -Dict = typing.Dict -ForwardRef = typing.ForwardRef -FrozenSet = typing.FrozenSet -Generic = typing.Generic -Hashable = typing.Hashable -IO = typing.IO -ItemsView = typing.ItemsView -Iterable = typing.Iterable -Iterator = typing.Iterator -KeysView = typing.KeysView -List = typing.List -Mapping = typing.Mapping -MappingView = typing.MappingView -Match = typing.Match -MutableMapping = typing.MutableMapping -MutableSequence = typing.MutableSequence -MutableSet = typing.MutableSet -Optional = typing.Optional -Pattern = typing.Pattern -Reversible = typing.Reversible -Sequence = typing.Sequence -Set = typing.Set -Sized = typing.Sized -TextIO = typing.TextIO -Tuple = typing.Tuple -Union = typing.Union -ValuesView = typing.ValuesView -cast = typing.cast -no_type_check = typing.no_type_check -no_type_check_decorator = typing.no_type_check_decorator diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/LICENSE b/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/LICENSE deleted file mode 100644 index 41c87e7..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -This software is made available under the terms of *either* of the licenses -found in LICENSE.APACHE or LICENSE.BSD. Contributions to uritemplate are -made under the terms of *both* these licenses. diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/METADATA deleted file mode 100644 index 97001a2..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/METADATA +++ /dev/null @@ -1,92 +0,0 @@ -Metadata-Version: 2.1 -Name: uritemplate -Version: 4.1.1 -Summary: Implementation of RFC 6570 URI Templates -Home-page: https://uritemplate.readthedocs.org -Author: Ian Stapleton Cordasco -Author-email: graffatcolmingov@gmail.com -License: BSD 3-Clause License or Apache License, Version 2.0 -Keywords: rfc 6570 uri template -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved -Classifier: License :: OSI Approved :: Apache Software License -Classifier: License :: OSI Approved :: BSD License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: Implementation :: CPython -Requires-Python: >=3.6 -Description-Content-Type: text/x-rst -License-File: LICENSE - -uritemplate -=========== - -Documentation_ -- GitHub_ -- Travis-CI_ - -Simple python library to deal with `URI Templates`_. The API looks like - -.. code-block:: python - - from uritemplate import URITemplate, expand - - # NOTE: URI params must be strings not integers - - gist_uri = 'https://api.github.com/users/sigmavirus24/gists{/gist_id}' - t = URITemplate(gist_uri) - print(t.expand(gist_id='123456')) - # => https://api.github.com/users/sigmavirus24/gists/123456 - - # or - print(expand(gist_uri, gist_id='123456')) - - # also - t.expand({'gist_id': '123456'}) - print(expand(gist_uri, {'gist_id': '123456'})) - -Where it might be useful to have a class - -.. code-block:: python - - import requests - - class GitHubUser(object): - url = URITemplate('https://api.github.com/user{/login}') - def __init__(self, name): - self.api_url = url.expand(login=name) - response = requests.get(self.api_url) - if response.status_code == 200: - self.__dict__.update(response.json()) - -When the module containing this class is loaded, ``GitHubUser.url`` is -evaluated and so the template is created once. It's often hard to notice in -Python, but object creation can consume a great deal of time and so can the -``re`` module which uritemplate relies on. Constructing the object once should -reduce the amount of time your code takes to run. - -Installing ----------- - -:: - - pip install uritemplate - -License -------- - -Modified BSD license_ - - -.. _Documentation: https://uritemplate.readthedocs.io/ -.. _GitHub: https://github.com/python-hyper/uritemplate -.. _Travis-CI: https://travis-ci.org/python-hyper/uritemplate -.. _URI Templates: https://tools.ietf.org/html/rfc6570 -.. _license: https://github.com/python-hyper/uritemplate/blob/master/LICENSE - - diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/RECORD deleted file mode 100644 index 7a2ae36..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -uritemplate/__init__.py,sha256=toWdtJeaNWsftVzhDASD_2wwxkd84HdXg22rFwMkVkc,816 -uritemplate/api.py,sha256=eQ3DdgNNDlnoedSE-rQ5AQv8JvMzdljPX8l-187myfI,2305 -uritemplate/orderedset.py,sha256=4Z8u8uw339D_RWvbUslv5d6EnA2wxQC66317oTLzp0o,3367 -uritemplate/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -uritemplate/template.py,sha256=qXcNZxcGPGxgQnaRDIafaKsrTnvBzplOBBPAM8Hbq7g,4774 -uritemplate/variable.py,sha256=HixfLuF7R3f7zwIQohB9cFVRVZsN_8Y2RIZDRHpNg40,12870 -uritemplate-4.1.1.dist-info/LICENSE,sha256=PPyfAc3uySkA8ijPVnf_pX5-0wTEJjUyvK2cvZlp5Gw,196 -uritemplate-4.1.1.dist-info/METADATA,sha256=rotEEWL5rUie3gKyYHhxXqjdpYw16kLCT0Aw0bvta9o,2882 -uritemplate-4.1.1.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 -uritemplate-4.1.1.dist-info/top_level.txt,sha256=WJzkFEINWbgwuzuUEP8kD8Sk2fFHYQzBgrjO3viyubE,12 -uritemplate-4.1.1.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/WHEEL deleted file mode 100644 index b733a60..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.37.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/top_level.txt deleted file mode 100644 index 2d76f01..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate-4.1.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -uritemplate diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/__init__.py b/extensions/.local/lib/python3.11/site-packages/uritemplate/__init__.py deleted file mode 100644 index 65015c1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -""" - -uritemplate -=========== - -URI templates implemented as close to :rfc:`6570` as possible - -See http://uritemplate.rtfd.org/ for documentation - -:copyright: - (c) 2013 Ian Stapleton Cordasco -:license: - Modified BSD Apache License (Version 2.0), see LICENSE for more details - and either LICENSE.BSD or LICENSE.APACHE for the details of those specific - licenses - -""" - -__title__ = "uritemplate" -__author__ = "Ian Stapleton Cordasco" -__license__ = "Modified BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2013 Ian Stapleton Cordasco" -__version__ = "4.1.1" -__version_info__ = tuple( - int(i) for i in __version__.split(".") if i.isdigit() -) - -from uritemplate.api import ( - URITemplate, - expand, - partial, - variables, -) - -__all__ = ("URITemplate", "expand", "partial", "variables") diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/api.py b/extensions/.local/lib/python3.11/site-packages/uritemplate/api.py deleted file mode 100644 index ac75473..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate/api.py +++ /dev/null @@ -1,85 +0,0 @@ -""" - -uritemplate.api -=============== - -This module contains the very simple API provided by uritemplate. - -""" -import typing as t - -from uritemplate import variable -from uritemplate.orderedset import OrderedSet -from uritemplate.template import URITemplate - -__all__ = ("OrderedSet", "URITemplate", "expand", "partial", "variables") - - -def expand( - uri: str, - var_dict: t.Optional[variable.VariableValueDict] = None, - **kwargs: variable.VariableValue, -) -> str: - """Expand the template with the given parameters. - - :param str uri: The templated URI to expand - :param dict var_dict: Optional dictionary with variables and values - :param kwargs: Alternative way to pass arguments - :returns: str - - Example:: - - expand('https://api.github.com{/end}', {'end': 'users'}) - expand('https://api.github.com{/end}', end='gists') - - .. note:: Passing values by both parts, may override values in - ``var_dict``. For example:: - - expand('https://{var}', {'var': 'val1'}, var='val2') - - ``val2`` will be used instead of ``val1``. - - """ - return URITemplate(uri).expand(var_dict, **kwargs) - - -def partial( - uri: str, - var_dict: t.Optional[variable.VariableValueDict] = None, - **kwargs: variable.VariableValue, -) -> URITemplate: - """Partially expand the template with the given parameters. - - If all of the parameters for the template are not given, return a - partially expanded template. - - :param dict var_dict: Optional dictionary with variables and values - :param kwargs: Alternative way to pass arguments - :returns: :class:`URITemplate` - - Example:: - - t = URITemplate('https://api.github.com{/end}') - t.partial() # => URITemplate('https://api.github.com{/end}') - - """ - return URITemplate(uri).partial(var_dict, **kwargs) - - -def variables(uri: str) -> OrderedSet: - """Parse the variables of the template. - - This returns all of the variable names in the URI Template. - - :returns: Set of variable names - :rtype: set - - Example:: - - variables('https://api.github.com{/end}) - # => {'end'} - variables('https://api.github.com/repos{/username}{/repository}') - # => {'username', 'repository'} - - """ - return OrderedSet(URITemplate(uri).variable_names) diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/orderedset.py b/extensions/.local/lib/python3.11/site-packages/uritemplate/orderedset.py deleted file mode 100644 index dd7cd1a..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate/orderedset.py +++ /dev/null @@ -1,92 +0,0 @@ -# From: https://github.com/ActiveState/code/blob/master/recipes/Python/576696_OrderedSet_with_Weakrefs/ # noqa -import typing as t -import weakref - - -class Link: - """Representation of one item in a doubly-linked list.""" - - __slots__ = ("prev", "next", "key", "__weakref__") - prev: "Link" - next: "Link" - key: str - - -class OrderedSet(t.MutableSet[str]): - """A set that remembers the order in which items were added.""" - - # Big-O running times for all methods are the same as for regular sets. - # The internal self.__map dictionary maps keys to links in a doubly linked - # list. The circular doubly linked list starts and ends with a sentinel - # element. The sentinel element never gets deleted (this simplifies the - # algorithm). The prev/next links are weakref proxies (to prevent circular - # references). Individual links are kept alive by the hard reference in - # self.__map. Those hard references disappear when a key is deleted from - # an OrderedSet. - - def __init__(self, iterable: t.Optional[t.Iterable[str]] = None): - self.__root = root = Link() # sentinel node for doubly linked list - root.prev = root.next = root - self.__map: t.MutableMapping[str, Link] = {} # key --> link - if iterable is not None: - self |= iterable # type: ignore - - def __len__(self) -> int: - return len(self.__map) - - def __contains__(self, key: object) -> bool: - return key in self.__map - - def add(self, key: str) -> None: - # Store new key in a new link at the end of the linked list - if key not in self.__map: - self.__map[key] = link = Link() - root = self.__root - last = root.prev - link.prev, link.next, link.key = last, root, key - last.next = root.prev = weakref.proxy(link) - - def discard(self, key: str) -> None: - # Remove an existing item using self.__map to find the link which is - # then removed by updating the links in the predecessor and successors. - if key in self.__map: - link = self.__map.pop(key) - link.prev.next = link.next - link.next.prev = link.prev - - def __iter__(self) -> t.Generator[str, None, None]: - # Traverse the linked list in order. - root = self.__root - curr = root.next - while curr is not root: - yield curr.key - curr = curr.next - - def __reversed__(self) -> t.Generator[str, None, None]: - # Traverse the linked list in reverse order. - root = self.__root - curr = root.prev - while curr is not root: - yield curr.key - curr = curr.prev - - def pop(self, last: bool = True) -> str: - if not self: - raise KeyError("set is empty") - key = next(reversed(self)) if last else next(iter(self)) - self.discard(key) - return key - - def __repr__(self) -> str: - if not self: - return f"{self.__class__.__name__}()" - return f"{self.__class__.__name__}({list(self)!r})" - - def __str__(self) -> str: - return self.__repr__() - - def __eq__(self, other: object) -> bool: - if isinstance(other, OrderedSet): - return len(self) == len(other) and list(self) == list(other) - other = t.cast(t.Iterable[str], other) - return not self.isdisjoint(other) diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/py.typed b/extensions/.local/lib/python3.11/site-packages/uritemplate/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/template.py b/extensions/.local/lib/python3.11/site-packages/uritemplate/template.py deleted file mode 100644 index 73ef89c..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate/template.py +++ /dev/null @@ -1,169 +0,0 @@ -""" - -uritemplate.template -==================== - -This module contains the essential inner workings of uritemplate. - -What treasures await you: - -- URITemplate class - -You see a treasure chest of knowledge in front of you. -What do you do? -> - -""" -import re -import typing as t - -from uritemplate import orderedset -from uritemplate import variable - -template_re = re.compile("{([^}]+)}") - - -def _merge( - var_dict: t.Optional[variable.VariableValueDict], - overrides: variable.VariableValueDict, -) -> variable.VariableValueDict: - if var_dict: - opts = var_dict.copy() - opts.update(overrides) - return opts - return overrides - - -class URITemplate: - - """This parses the template and will be used to expand it. - - This is the most important object as the center of the API. - - Example:: - - from uritemplate import URITemplate - import requests - - - t = URITemplate( - 'https://api.github.com/users/sigmavirus24/gists{/gist_id}' - ) - uri = t.expand(gist_id=123456) - resp = requests.get(uri) - for gist in resp.json(): - print(gist['html_url']) - - Please note:: - - str(t) - # 'https://api.github.com/users/sigmavirus24/gists{/gistid}' - repr(t) # is equivalent to - # URITemplate(str(t)) - # Where str(t) is interpreted as the URI string. - - Also, ``URITemplates`` are hashable so they can be used as keys in - dictionaries. - - """ - - def __init__(self, uri: str): - #: The original URI to be parsed. - self.uri: str = uri - #: A list of the variables in the URI. They are stored as - #: :class:`~uritemplate.variable.URIVariable`\ s - self.variables: t.List[variable.URIVariable] = [ - variable.URIVariable(m.groups()[0]) - for m in template_re.finditer(self.uri) - ] - #: A set of variable names in the URI. - self.variable_names = orderedset.OrderedSet() - for var in self.variables: - for name in var.variable_names: - self.variable_names.add(name) - - def __repr__(self) -> str: - return 'URITemplate("%s")' % self - - def __str__(self) -> str: - return self.uri - - def __eq__(self, other: object) -> bool: - if not isinstance(other, URITemplate): - return NotImplemented - return self.uri == other.uri - - def __hash__(self) -> int: - return hash(self.uri) - - def _expand( - self, var_dict: variable.VariableValueDict, replace: bool - ) -> str: - if not self.variables: - return self.uri - - expansion = var_dict - expanded: t.Dict[str, str] = {} - for v in self.variables: - expanded.update(v.expand(expansion)) - - def replace_all(match: "re.Match[str]") -> str: - return expanded.get(match.groups()[0], "") - - def replace_partial(match: "re.Match[str]") -> str: - match_group = match.groups()[0] - var = "{%s}" % match_group - return expanded.get(match_group) or var - - replace_func = replace_partial if replace else replace_all - - return template_re.sub(replace_func, self.uri) - - def expand( - self, - var_dict: t.Optional[variable.VariableValueDict] = None, - **kwargs: variable.VariableValue, - ) -> str: - """Expand the template with the given parameters. - - :param dict var_dict: Optional dictionary with variables and values - :param kwargs: Alternative way to pass arguments - :returns: str - - Example:: - - t = URITemplate('https://api.github.com{/end}') - t.expand({'end': 'users'}) - t.expand(end='gists') - - .. note:: Passing values by both parts, may override values in - ``var_dict``. For example:: - - expand('https://{var}', {'var': 'val1'}, var='val2') - - ``val2`` will be used instead of ``val1``. - - """ - return self._expand(_merge(var_dict, kwargs), False) - - def partial( - self, - var_dict: t.Optional[variable.VariableValueDict] = None, - **kwargs: variable.VariableValue, - ) -> "URITemplate": - """Partially expand the template with the given parameters. - - If all of the parameters for the template are not given, return a - partially expanded template. - - :param dict var_dict: Optional dictionary with variables and values - :param kwargs: Alternative way to pass arguments - :returns: :class:`URITemplate` - - Example:: - - t = URITemplate('https://api.github.com{/end}') - t.partial() # => URITemplate('https://api.github.com{/end}') - - """ - return URITemplate(self._expand(_merge(var_dict, kwargs), True)) diff --git a/extensions/.local/lib/python3.11/site-packages/uritemplate/variable.py b/extensions/.local/lib/python3.11/site-packages/uritemplate/variable.py deleted file mode 100644 index da406ca..0000000 --- a/extensions/.local/lib/python3.11/site-packages/uritemplate/variable.py +++ /dev/null @@ -1,419 +0,0 @@ -""" - -uritemplate.variable -==================== - -This module contains the URIVariable class which powers the URITemplate class. - -What treasures await you: - -- URIVariable class - -You see a hammer in front of you. -What do you do? -> - -""" -import collections.abc -import typing as t -import urllib.parse - -ScalarVariableValue = t.Union[int, float, complex, str] -VariableValue = t.Union[ - t.Sequence[ScalarVariableValue], - t.Mapping[str, ScalarVariableValue], - t.Tuple[str, ScalarVariableValue], - ScalarVariableValue, -] -VariableValueDict = t.Dict[str, VariableValue] - - -class URIVariable: - - """This object validates everything inside the URITemplate object. - - It validates template expansions and will truncate length as decided by - the template. - - Please note that just like the :class:`URITemplate `, this - object's ``__str__`` and ``__repr__`` methods do not return the same - information. Calling ``str(var)`` will return the original variable. - - This object does the majority of the heavy lifting. The ``URITemplate`` - object finds the variables in the URI and then creates ``URIVariable`` - objects. Expansions of the URI are handled by each ``URIVariable`` - object. ``URIVariable.expand()`` returns a dictionary of the original - variable and the expanded value. Check that method's documentation for - more information. - - """ - - operators = ("+", "#", ".", "/", ";", "?", "&", "|", "!", "@") - reserved = ":/?#[]@!$&'()*+,;=" - - def __init__(self, var: str): - #: The original string that comes through with the variable - self.original: str = var - #: The operator for the variable - self.operator: str = "" - #: List of safe characters when quoting the string - self.safe: str = "" - #: List of variables in this variable - self.variables: t.List[ - t.Tuple[str, t.MutableMapping[str, t.Any]] - ] = [] - #: List of variable names - self.variable_names: t.List[str] = [] - #: List of defaults passed in - self.defaults: t.MutableMapping[str, ScalarVariableValue] = {} - # Parse the variable itself. - self.parse() - self.post_parse() - - def __repr__(self) -> str: - return "URIVariable(%s)" % self - - def __str__(self) -> str: - return self.original - - def parse(self) -> None: - """Parse the variable. - - This finds the: - - operator, - - set of safe characters, - - variables, and - - defaults. - - """ - var_list_str = self.original - if self.original[0] in URIVariable.operators: - self.operator = self.original[0] - var_list_str = self.original[1:] - - if self.operator in URIVariable.operators[:2]: - self.safe = URIVariable.reserved - - var_list = var_list_str.split(",") - - for var in var_list: - default_val = None - name = var - if "=" in var: - name, default_val = tuple(var.split("=", 1)) - - explode = False - if name.endswith("*"): - explode = True - name = name[:-1] - - prefix: t.Optional[int] = None - if ":" in name: - name, prefix_str = tuple(name.split(":", 1)) - prefix = int(prefix_str) - - if default_val: - self.defaults[name] = default_val - - self.variables.append( - (name, {"explode": explode, "prefix": prefix}) - ) - - self.variable_names = [varname for (varname, _) in self.variables] - - def post_parse(self) -> None: - """Set ``start``, ``join_str`` and ``safe`` attributes. - - After parsing the variable, we need to set up these attributes and it - only makes sense to do it in a more easily testable way. - """ - self.safe = "" - self.start = self.join_str = self.operator - if self.operator == "+": - self.start = "" - if self.operator in ("+", "#", ""): - self.join_str = "," - if self.operator == "#": - self.start = "#" - if self.operator == "?": - self.start = "?" - self.join_str = "&" - - if self.operator in ("+", "#"): - self.safe = URIVariable.reserved - - def _query_expansion( - self, - name: str, - value: VariableValue, - explode: bool, - prefix: t.Optional[int], - ) -> t.Optional[str]: - """Expansion method for the '?' and '&' operators.""" - if value is None: - return None - - tuples, items = is_list_of_tuples(value) - - safe = self.safe - if list_test(value) and not tuples: - if not value: - return None - value = t.cast(t.Sequence[ScalarVariableValue], value) - if explode: - return self.join_str.join( - f"{name}={quote(v, safe)}" for v in value - ) - else: - value = ",".join(quote(v, safe) for v in value) - return f"{name}={value}" - - if dict_test(value) or tuples: - if not value: - return None - value = t.cast(t.Mapping[str, ScalarVariableValue], value) - items = items or sorted(value.items()) - if explode: - return self.join_str.join( - f"{quote(k, safe)}={quote(v, safe)}" for k, v in items - ) - else: - value = ",".join( - f"{quote(k, safe)},{quote(v, safe)}" for k, v in items - ) - return f"{name}={value}" - - if value: - value = t.cast(t.Text, value) - value = value[:prefix] if prefix else value - return f"{name}={quote(value, safe)}" - return name + "=" - - def _label_path_expansion( - self, - name: str, - value: VariableValue, - explode: bool, - prefix: t.Optional[int], - ) -> t.Optional[str]: - """Label and path expansion method. - - Expands for operators: '/', '.' - - """ - join_str = self.join_str - safe = self.safe - - if value is None or ( - not isinstance(value, (str, int, float, complex)) - and len(value) == 0 - ): - return None - - tuples, items = is_list_of_tuples(value) - - if list_test(value) and not tuples: - if not explode: - join_str = "," - - value = t.cast(t.Sequence[ScalarVariableValue], value) - fragments = [quote(v, safe) for v in value if v is not None] - return join_str.join(fragments) if fragments else None - - if dict_test(value) or tuples: - value = t.cast(t.Mapping[str, ScalarVariableValue], value) - items = items or sorted(value.items()) - format_str = "%s=%s" - if not explode: - format_str = "%s,%s" - join_str = "," - - expanded = join_str.join( - format_str % (quote(k, safe), quote(v, safe)) - for k, v in items - if v is not None - ) - return expanded if expanded else None - - value = t.cast(t.Text, value) - value = value[:prefix] if prefix else value - return quote(value, safe) - - def _semi_path_expansion( - self, - name: str, - value: VariableValue, - explode: bool, - prefix: t.Optional[int], - ) -> t.Optional[str]: - """Expansion method for ';' operator.""" - join_str = self.join_str - safe = self.safe - - if value is None: - return None - - if self.operator == "?": - join_str = "&" - - tuples, items = is_list_of_tuples(value) - - if list_test(value) and not tuples: - value = t.cast(t.Sequence[ScalarVariableValue], value) - if explode: - expanded = join_str.join( - f"{name}={quote(v, safe)}" for v in value if v is not None - ) - return expanded if expanded else None - else: - value = ",".join(quote(v, safe) for v in value) - return f"{name}={value}" - - if dict_test(value) or tuples: - value = t.cast(t.Mapping[str, ScalarVariableValue], value) - items = items or sorted(value.items()) - - if explode: - return join_str.join( - f"{quote(k, safe)}={quote(v, safe)}" - for k, v in items - if v is not None - ) - else: - expanded = ",".join( - f"{quote(k, safe)},{quote(v, safe)}" - for k, v in items - if v is not None - ) - return f"{name}={expanded}" - - value = t.cast(t.Text, value) - value = value[:prefix] if prefix else value - if value: - return f"{name}={quote(value, safe)}" - - return name - - def _string_expansion( - self, - name: str, - value: VariableValue, - explode: bool, - prefix: t.Optional[int], - ) -> t.Optional[str]: - if value is None: - return None - - tuples, items = is_list_of_tuples(value) - - if list_test(value) and not tuples: - value = t.cast(t.Sequence[ScalarVariableValue], value) - return ",".join(quote(v, self.safe) for v in value) - - if dict_test(value) or tuples: - value = t.cast(t.Mapping[str, ScalarVariableValue], value) - items = items or sorted(value.items()) - format_str = "%s=%s" if explode else "%s,%s" - - return ",".join( - format_str % (quote(k, self.safe), quote(v, self.safe)) - for k, v in items - ) - - value = t.cast(t.Text, value) - value = value[:prefix] if prefix else value - return quote(value, self.safe) - - def expand( - self, var_dict: t.Optional[VariableValueDict] = None - ) -> t.Mapping[str, str]: - """Expand the variable in question. - - Using ``var_dict`` and the previously parsed defaults, expand this - variable and subvariables. - - :param dict var_dict: dictionary of key-value pairs to be used during - expansion - :returns: dict(variable=value) - - Examples:: - - # (1) - v = URIVariable('/var') - expansion = v.expand({'var': 'value'}) - print(expansion) - # => {'/var': '/value'} - - # (2) - v = URIVariable('?var,hello,x,y') - expansion = v.expand({'var': 'value', 'hello': 'Hello World!', - 'x': '1024', 'y': '768'}) - print(expansion) - # => {'?var,hello,x,y': - # '?var=value&hello=Hello%20World%21&x=1024&y=768'} - - """ - return_values = [] - if var_dict is None: - return {self.original: self.original} - - for name, opts in self.variables: - value = var_dict.get(name, None) - if not value and value != "" and name in self.defaults: - value = self.defaults[name] - - if value is None: - continue - - expanded = None - if self.operator in ("/", "."): - expansion = self._label_path_expansion - elif self.operator in ("?", "&"): - expansion = self._query_expansion - elif self.operator == ";": - expansion = self._semi_path_expansion - else: - expansion = self._string_expansion - - expanded = expansion(name, value, opts["explode"], opts["prefix"]) - - if expanded is not None: - return_values.append(expanded) - - value = "" - if return_values: - value = self.start + self.join_str.join(return_values) - return {self.original: value} - - -def is_list_of_tuples( - value: t.Any, -) -> t.Tuple[bool, t.Optional[t.Sequence[t.Tuple[str, ScalarVariableValue]]]]: - if ( - not value - or not isinstance(value, (list, tuple)) - or not all(isinstance(t, tuple) and len(t) == 2 for t in value) - ): - return False, None - - return True, value - - -def list_test(value: t.Any) -> bool: - return isinstance(value, (list, tuple)) - - -def dict_test(value: t.Any) -> bool: - return isinstance(value, (dict, collections.abc.MutableMapping)) - - -def _encode(value: t.AnyStr, encoding: str = "utf-8") -> bytes: - if isinstance(value, str): - return value.encode(encoding) - return value - - -def quote(value: t.Any, safe: str) -> str: - if not isinstance(value, (str, bytes)): - value = str(value) - return urllib.parse.quote(_encode(value), safe) diff --git a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/METADATA b/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/METADATA deleted file mode 100644 index 2c43da6..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/METADATA +++ /dev/null @@ -1,47 +0,0 @@ -Metadata-Version: 2.1 -Name: vosk -Version: 0.3.41 -Summary: Offline open source speech recognition API based on Kaldi and Vosk -Home-page: https://github.com/alphacep/vosk-api -Author: Alpha Cephei Inc -Author-email: contact@alphacephei.com -License: UNKNOWN -Platform: UNKNOWN -Classifier: Programming Language :: Python :: 3 -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3 -Description-Content-Type: text/markdown -Requires-Dist: cffi (>=1.0) -Requires-Dist: requests -Requires-Dist: tqdm - -This is a Python module for Vosk. - -Vosk is an offline open source speech recognition toolkit. It enables -speech recognition for 20+ languages and dialects - English, Indian -English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, -Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, -Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come. - -Vosk models are small (50 Mb) but provide continuous large vocabulary -transcription, zero-latency response with streaming API, reconfigurable -vocabulary and speaker identification. - -Vosk supplies speech recognition for chatbots, smart home appliances, -virtual assistants. It can also create subtitles for movies, -transcription for lectures and interviews. - -Vosk scales from small devices like Raspberry Pi or Android smartphone to -big clusters. - -# Documentation - -For installation instructions, examples and documentation visit [Vosk -Website](https://alphacephei.com/vosk). See also our project on -[Github](https://github.com/alphacep/vosk-api). - - diff --git a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/RECORD b/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/RECORD deleted file mode 100644 index 79ee543..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/RECORD +++ /dev/null @@ -1,14 +0,0 @@ -vosk/__init__.py,sha256=4kL5LSRPbQcX5286y7Renz0PkDfOjQfqUgr58WB-TtM,8570 -vosk/libgcc_s_seh-1.dll,sha256=4W3oPUgkfN4lgew2J5EC3aALfXs2VYytchZOPEyq4KQ,1266641 -vosk/libstdc++-6.dll,sha256=F2b24lJBAIbCZACrCF4BfnrV6Jk_PRndqHoToel48KI,19442799 -vosk/libvosk.dll,sha256=9WEQi17oN6yyrG-F6lHFQtUy7QxmevAAi4Wz9whqVZA,25989632 -vosk/libwinpthread-1.dll,sha256=W2CQffQgCfG6Q35_KmJ4ZRvpf0mThpEF2KMQhhOORXA,592104 -vosk/vosk_cffi.py,sha256=jBkc7FF_5Tvx96wV9hE4zFP-kUZenfr687HqfIXOH_E,3859 -vosk/transcriber/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -vosk/transcriber/cli.py,sha256=x2oVNi5zhTa4BWEW2dvTCZdAsZuGLLZoZrvDojXXpX8,2387 -vosk/transcriber/transcriber.py,sha256=WNauWVXkUsR9id_9PSgoR1-uJfeM7IYgaP1dZY4w8H4,3157 -vosk-0.3.41.dist-info/METADATA,sha256=dJ8pXkD-Pk_tw1gfSLvi6f8--JtWH_-PGrr7fBKbjHY,1778 -vosk-0.3.41.dist-info/WHEEL,sha256=5M5xWEErikXCBzw-ULgxpYH97bPSs-4QjD668kpnw9Q,98 -vosk-0.3.41.dist-info/entry_points.txt,sha256=6cwdLQGvAuoLKoxRB1m2sz741-ags2_IinvQwyJvziI,64 -vosk-0.3.41.dist-info/top_level.txt,sha256=VyhCKFInHWKAvlbaAYoqHJ2Y35GrQNYA-Ul2CRc30Uk,5 -vosk-0.3.41.dist-info/RECORD,, diff --git a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/WHEEL b/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/WHEEL deleted file mode 100644 index f873c86..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.32.3) -Root-Is-Purelib: true -Tag: py3-none-win_amd64 - diff --git a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/entry_points.txt b/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/entry_points.txt deleted file mode 100644 index e08b71f..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -vosk-transcriber = vosk.transcriber.cli:main - diff --git a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/top_level.txt b/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/top_level.txt deleted file mode 100644 index 929ccb5..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk-0.3.41.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -vosk diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/__init__.py b/extensions/.local/lib/python3.11/site-packages/vosk/__init__.py deleted file mode 100644 index 45e2706..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/__init__.py +++ /dev/null @@ -1,235 +0,0 @@ -import os -import sys - -import requests -from urllib.request import urlretrieve -from zipfile import ZipFile -from re import match -from pathlib import Path -from .vosk_cffi import ffi as _ffi -from tqdm import tqdm - -# Remote location of the models and local folders -MODEL_PRE_URL = 'https://alphacephei.com/vosk/models/' -MODEL_LIST_URL = MODEL_PRE_URL + 'model-list.json' -MODEL_DIRS = [os.getenv('VOSK_MODEL_PATH'), Path('/usr/share/vosk'), Path.home() / 'AppData/Local/vosk', Path.home() / '.cache/vosk'] - -def open_dll(): - dlldir = os.path.abspath(os.path.dirname(__file__)) - if sys.platform == 'win32': - # We want to load dependencies too - os.environ["PATH"] = dlldir + os.pathsep + os.environ['PATH'] - if hasattr(os, 'add_dll_directory'): - os.add_dll_directory(dlldir) - return _ffi.dlopen(os.path.join(dlldir, "libvosk.dll")) - elif sys.platform == 'linux': - return _ffi.dlopen(os.path.join(dlldir, "libvosk.so")) - elif sys.platform == 'darwin': - return _ffi.dlopen(os.path.join(dlldir, "libvosk.dyld")) - else: - raise TypeError("Unsupported platform") - -_c = open_dll() - -def list_models(): - response = requests.get(MODEL_LIST_URL) - for model in response.json(): - print(model['name']) - -def list_languages(): - response = requests.get(MODEL_LIST_URL) - languages = set([m['lang'] for m in response.json()]) - for lang in languages: - print (lang) - -class Model(object): - def __init__(self, model_path=None, model_name=None, lang=None): - if model_path != None: - self._handle = _c.vosk_model_new(model_path.encode('utf-8')) - else: - model_path = self.get_model_path(model_name, lang) - self._handle = _c.vosk_model_new(model_path.encode('utf-8')) - if self._handle == _ffi.NULL: - raise Exception("Failed to create a model") - - def __del__(self): - _c.vosk_model_free(self._handle) - - def vosk_model_find_word(self, word): - return _c.vosk_model_find_word(self._handle, word.encode('utf-8')) - - def get_model_path(self, model_name, lang): - if model_name is None: - model_path = self.get_model_by_lang(lang) - else: - model_path = self.get_model_by_name(model_name) - return str(model_path) - - def get_model_by_name(self, model_name): - for directory in MODEL_DIRS: - if directory is None or not Path(directory).exists(): - continue - model_file_list = os.listdir(directory) - model_file = [model for model in model_file_list if model == model_name] - if model_file != []: - return Path(directory, model_file[0]) - response = requests.get(MODEL_LIST_URL) - result_model = [model['name'] for model in response.json() if model['name'] == model_name] - if result_model == []: - raise Exception("model name %s does not exist" % (model_name)) - else: - self.download_model(Path(directory, result_model[0])) - return Path(directory, result_model[0]) - - def get_model_by_lang(self, lang): - for directory in MODEL_DIRS: - if directory is None or not Path(directory).exists(): - continue - model_file_list = os.listdir(directory) - model_file = [model for model in model_file_list if match(f"vosk-model(-small)?-{lang}", model)] - if model_file != []: - return Path(directory, model_file[0]) - response = requests.get(MODEL_LIST_URL) - result_model = [model['name'] for model in response.json() if model['lang'] == lang and model['type'] == 'small' and model['obsolete'] == 'false'] - if result_model == []: - raise Exception("lang %s does not exist" % (lang)) - else: - self.download_model(Path(directory, result_model[0])) - return Path(directory, result_model[0]) - - def download_model(self, model_name): - if not MODEL_DIRS[3].exists(): - MODEL_DIRS[3].mkdir() - with tqdm(unit='B', unit_scale=True, unit_divisor=1024, miniters=1, - desc=(MODEL_PRE_URL + str(model_name.name) + '.zip').split('/')[-1]) as t: - reporthook = self.download_progress_hook(t) - urlretrieve(MODEL_PRE_URL + str(model_name.name) + '.zip', str(model_name) + '.zip', - reporthook=reporthook, data=None) - t.total = t.n - with ZipFile(str(model_name) + '.zip', 'r') as model_ref: - model_ref.extractall(model_name.parent) - Path(str(model_name) + '.zip').unlink() - - def download_progress_hook(self, t): - last_b = [0] - def update_to(b=1, bsize=1, tsize=None): - if tsize not in (None, -1): - t.total = tsize - displayed = t.update((b - last_b[0]) * bsize) - last_b[0] = b - return displayed - return update_to - -class SpkModel(object): - - def __init__(self, model_path): - self._handle = _c.vosk_spk_model_new(model_path.encode('utf-8')) - - if self._handle == _ffi.NULL: - raise Exception("Failed to create a speaker model") - - def __del__(self): - _c.vosk_spk_model_free(self._handle) - -class KaldiRecognizer(object): - - def __init__(self, *args): - if len(args) == 2: - self._handle = _c.vosk_recognizer_new(args[0]._handle, args[1]) - elif len(args) == 3 and type(args[2]) is SpkModel: - self._handle = _c.vosk_recognizer_new_spk(args[0]._handle, args[1], args[2]._handle) - elif len(args) == 3 and type(args[2]) is str: - self._handle = _c.vosk_recognizer_new_grm(args[0]._handle, args[1], args[2].encode('utf-8')) - else: - raise TypeError("Unknown arguments") - - if self._handle == _ffi.NULL: - raise Exception("Failed to create a recognizer") - - def __del__(self): - _c.vosk_recognizer_free(self._handle) - - def SetMaxAlternatives(self, max_alternatives): - _c.vosk_recognizer_set_max_alternatives(self._handle, max_alternatives) - - def SetWords(self, enable_words): - _c.vosk_recognizer_set_words(self._handle, 1 if enable_words else 0) - - def SetPartialWords(self, enable_partial_words): - _c.vosk_recognizer_set_partial_words(self._handle, 1 if enable_partial_words else 0) - - def SetNLSML(self, enable_nlsml): - _c.vosk_recognizer_set_nlsml(self._handle, 1 if enable_nlsml else 0) - - def SetSpkModel(self, spk_model): - _c.vosk_recognizer_set_spk_model(self._handle, spk_model._handle) - - def AcceptWaveform(self, data): - res = _c.vosk_recognizer_accept_waveform(self._handle, data, len(data)) - if res < 0: - raise Exception("Failed to process waveform") - return res - - def Result(self): - return _ffi.string(_c.vosk_recognizer_result(self._handle)).decode('utf-8') - - def PartialResult(self): - return _ffi.string(_c.vosk_recognizer_partial_result(self._handle)).decode('utf-8') - - def FinalResult(self): - return _ffi.string(_c.vosk_recognizer_final_result(self._handle)).decode('utf-8') - - def Reset(self): - return _c.vosk_recognizer_reset(self._handle) - - -def SetLogLevel(level): - return _c.vosk_set_log_level(level) - - -def GpuInit(): - _c.vosk_gpu_init() - - -def GpuThreadInit(): - _c.vosk_gpu_thread_init() - -class BatchModel(object): - - def __init__(self, *args): - self._handle = _c.vosk_batch_model_new() - - if self._handle == _ffi.NULL: - raise Exception("Failed to create a model") - - def __del__(self): - _c.vosk_batch_model_free(self._handle) - - def Wait(self): - _c.vosk_batch_model_wait(self._handle) - -class BatchRecognizer(object): - - def __init__(self, *args): - self._handle = _c.vosk_batch_recognizer_new(args[0]._handle, args[1]) - - if self._handle == _ffi.NULL: - raise Exception("Failed to create a recognizer") - - def __del__(self): - _c.vosk_batch_recognizer_free(self._handle) - - def AcceptWaveform(self, data): - res = _c.vosk_batch_recognizer_accept_waveform(self._handle, data, len(data)) - - def Result(self): - ptr = _c.vosk_batch_recognizer_front_result(self._handle) - res = _ffi.string(ptr).decode('utf-8') - _c.vosk_batch_recognizer_pop(self._handle) - return res - - def FinishStream(self): - _c.vosk_batch_recognizer_finish_stream(self._handle) - - def GetPendingChunks(self): - return _c.vosk_batch_recognizer_get_pending_chunks(self._handle) diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/libgcc_s_seh-1.dll b/extensions/.local/lib/python3.11/site-packages/vosk/libgcc_s_seh-1.dll deleted file mode 100644 index 1ea37e0..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/libgcc_s_seh-1.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e16de83d48247cde2581ec36279102dda00b7d7b36558cad72164e3c4caae0a4 -size 1266641 diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/libstdc++-6.dll b/extensions/.local/lib/python3.11/site-packages/vosk/libstdc++-6.dll deleted file mode 100644 index c80694b..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/libstdc++-6.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1766f6e252410086c26400ab085e017e7ad5e8993f3d19dda87a13a1e978f0a2 -size 19442799 diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/libvosk.dll b/extensions/.local/lib/python3.11/site-packages/vosk/libvosk.dll deleted file mode 100644 index 8a588b1..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/libvosk.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f561108b5ee837acb2ac6f85ea51c542d532ed0c667af0008b85b3f7086a5590 -size 25989632 diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/libwinpthread-1.dll b/extensions/.local/lib/python3.11/site-packages/vosk/libwinpthread-1.dll deleted file mode 100644 index 9ce2e18..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/libwinpthread-1.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5b60907df42009f1ba437e7f2a6278651be97f4993869105d8a31086138e4570 -size 592104 diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/__init__.py b/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/cli.py b/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/cli.py deleted file mode 100644 index dc4f8cc..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/cli.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 - -import logging -import argparse - -from pathlib import Path -from vosk import list_models, list_languages -from vosk.transcriber.transcriber import Transcriber - -parser = argparse.ArgumentParser( - description = 'Transcribe audio file and save result in selected format') -parser.add_argument( - '--model', '-m', type=str, - help='model path') -parser.add_argument( - '--list-models', default=False, action='store_true', - help='list available models') -parser.add_argument( - '--list-languages', default=False, action='store_true', - help='list available languages') -parser.add_argument( - '--model-name', '-n', type=str, - help='select model by name') -parser.add_argument( - '--lang', '-l', default='en-us', type=str, - help='select model by language') -parser.add_argument( - '--input', '-i', type=str, - help='audiofile') -parser.add_argument( - '--output', '-o', default='', type=str, - help='optional output filename path') -parser.add_argument( - '--output-type', '-t', default='txt', type=str, - help='optional arg output data type') -parser.add_argument( - '--log-level', default='INFO', - help='logging level') - -def main(): - - args = parser.parse_args() - log_level = args.log_level.upper() - logging.getLogger().setLevel(log_level) - - if args.list_models == True: - list_models() - return - - if args.list_languages == True: - list_languages() - return - - if not args.input: - logging.info('Please specify input file or directory') - exit(1) - - if not Path(args.input).exists(): - logging.info('File %s does not exist, please specify an existing file/directory' % (args.input)) - exit(1) - - if args.output !='' and not Path(args.output).exists(): - logging.info('Output %s does not exist, please specify an existing file' % (args.output)) - exit(1) - - transcriber = Transcriber(args) - - if Path(args.input).is_dir() and Path(args.output).is_dir(): - transcriber.process_dir(args) - return - elif Path(args.input).is_file() and (args.output=='' or Path(args.output).is_file()): - transcriber.process_file(args) - else: - logging.info('Wrong arguments, input and output must be same type') - exit(1) - -if __name__ == "__main__": - main() diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/transcriber.py b/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/transcriber.py deleted file mode 100644 index 2861fd3..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/transcriber/transcriber.py +++ /dev/null @@ -1,89 +0,0 @@ -import json -import subprocess -import srt -import datetime -import os -import logging - -from pathlib import Path -from timeit import default_timer as timer -from vosk import KaldiRecognizer, Model - -class Transcriber: - - def __init__(self, args): - self.model = Model(model_path=args.model, model_name=args.model_name, lang=args.lang) - self.args = args - - def recognize_stream(self, rec, stream): - tot_samples = 0 - result = [] - while True: - data = stream.stdout.read(4000) - if len(data) == 0: - break - if rec.AcceptWaveform(data): - tot_samples += len(data) - result.append(json.loads(rec.Result())) - result.append(json.loads(rec.FinalResult())) - return result, tot_samples - - def format_result(self, result, words_per_line=7): - final_result = '' - if self.args.output_type == 'srt': - subs = [] - for i, res in enumerate(result): - if not 'result' in res: - continue - words = res['result'] - for j in range(0, len(words), words_per_line): - line = words[j : j + words_per_line] - s = srt.Subtitle(index=len(subs), - content = ' '.join([l['word'] for l in line]), - start=datetime.timedelta(seconds=line[0]['start']), - end=datetime.timedelta(seconds=line[-1]['end'])) - subs.append(s) - final_result = srt.compose(subs) - elif self.args.output_type == 'txt': - for part in result: - final_result += part['text'] + ' ' - return final_result - - - def resample_ffmpeg(self, infile): - stream = subprocess.Popen( - ['ffmpeg', '-nostdin', '-loglevel', 'quiet', '-i', - infile, - '-ar', '16000','-ac', '1', '-f', 's16le', '-'], - stdout=subprocess.PIPE) - return stream - - - def process_entry(self, inputdata): - logging.info(f'Recognizing {inputdata[0]}') - - rec = KaldiRecognizer(self.model, 16000) - rec.SetWords(True) - - stream = self.resample_ffmpeg(inputdata[0]) - result, tot_samples = self.recognize_stream(rec, stream) - final_result = self.format_result(result) - - if inputdata[1] != '': - with open(inputdata[1], 'w', encoding='utf-8') as fh: - fh.write(final_result) - else: - print(final_result) - return final_result, tot_samples - - - def process_directory(self,args): - task_list = [(Path(args.input, fn), Path(args.output, Path(fn).stem).with_suffix('.' + args.output_type)) for fn in os.listdir(args.input)] - with Pool() as pool: - pool.map(self.process_entry, file_list) - - def process_file(self, args): - start_time = timer() - final_result, tot_samples = self.process_entry([args.input, args.output]) - elapsed = timer() - start_time - logging.info(f'''Execution time: {elapsed:.3f} sec; xRT: {format(tot_samples / 16000.0 / float(elapsed), '.3f')}''') diff --git a/extensions/.local/lib/python3.11/site-packages/vosk/vosk_cffi.py b/extensions/.local/lib/python3.11/site-packages/vosk/vosk_cffi.py deleted file mode 100644 index 81db425..0000000 --- a/extensions/.local/lib/python3.11/site-packages/vosk/vosk_cffi.py +++ /dev/null @@ -1,10 +0,0 @@ -# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('vosk.vosk_cffi', - _version = 0x2601, - _types = b'\x00\x00\x03\x0D\x00\x00\x00\x0F\x00\x00\x1B\x0D\x00\x00\x5B\x03\x00\x00\x0D\x01\x00\x00\x00\x0F\x00\x00\x0A\x0D\x00\x00\x60\x03\x00\x00\x00\x0F\x00\x00\x1E\x0D\x00\x00\x5D\x03\x00\x00\x0D\x01\x00\x00\x00\x0F\x00\x00\x1E\x0D\x00\x00\x0A\x11\x00\x00\x0D\x01\x00\x00\x5F\x03\x00\x00\x00\x0F\x00\x00\x1E\x0D\x00\x00\x0A\x11\x00\x00\x0D\x01\x00\x00\x07\x11\x00\x00\x00\x0F\x00\x00\x10\x0D\x00\x00\x07\x11\x00\x00\x00\x0F\x00\x00\x07\x0D\x00\x00\x5C\x03\x00\x00\x00\x0F\x00\x00\x07\x0D\x00\x00\x5E\x03\x00\x00\x00\x0F\x00\x00\x2A\x0D\x00\x00\x1B\x11\x00\x00\x00\x0F\x00\x00\x2A\x0D\x00\x00\x0A\x11\x00\x00\x07\x11\x00\x00\x00\x0F\x00\x00\x2A\x0D\x00\x00\x1E\x11\x00\x00\x07\x11\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x2A\x0D\x00\x00\x1E\x11\x00\x00\x04\x03\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x2A\x0D\x00\x00\x1E\x11\x00\x00\x61\x03\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x03\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1B\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1B\x11\x00\x00\x07\x11\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1B\x11\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x0A\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1E\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1E\x11\x00\x00\x10\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x1E\x11\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x10\x11\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x62\x0D\x00\x00\x00\x0F\x00\x00\x00\x09\x00\x00\x01\x09\x00\x00\x02\x09\x00\x00\x03\x09\x00\x00\x04\x09\x00\x00\x02\x01\x00\x00\x05\x01\x00\x00\x00\x01', - _globals = (b'\x00\x00\x36\x23vosk_batch_model_free',0,b'\x00\x00\x00\x23vosk_batch_model_new',0,b'\x00\x00\x36\x23vosk_batch_model_wait',0,b'\x00\x00\x3C\x23vosk_batch_recognizer_accept_waveform',0,b'\x00\x00\x39\x23vosk_batch_recognizer_finish_stream',0,b'\x00\x00\x39\x23vosk_batch_recognizer_free',0,b'\x00\x00\x1A\x23vosk_batch_recognizer_front_result',0,b'\x00\x00\x20\x23vosk_batch_recognizer_get_pending_chunks',0,b'\x00\x00\x02\x23vosk_batch_recognizer_new',0,b'\x00\x00\x39\x23vosk_batch_recognizer_pop',0,b'\x00\x00\x41\x23vosk_batch_recognizer_set_nlsml',0,b'\x00\x00\x59\x23vosk_gpu_init',0,b'\x00\x00\x59\x23vosk_gpu_thread_init',0,b'\x00\x00\x23\x23vosk_model_find_word',0,b'\x00\x00\x45\x23vosk_model_free',0,b'\x00\x00\x06\x23vosk_model_new',0,b'\x00\x00\x27\x23vosk_recognizer_accept_waveform',0,b'\x00\x00\x2C\x23vosk_recognizer_accept_waveform_f',0,b'\x00\x00\x31\x23vosk_recognizer_accept_waveform_s',0,b'\x00\x00\x1D\x23vosk_recognizer_final_result',0,b'\x00\x00\x48\x23vosk_recognizer_free',0,b'\x00\x00\x09\x23vosk_recognizer_new',0,b'\x00\x00\x12\x23vosk_recognizer_new_grm',0,b'\x00\x00\x0D\x23vosk_recognizer_new_spk',0,b'\x00\x00\x1D\x23vosk_recognizer_partial_result',0,b'\x00\x00\x48\x23vosk_recognizer_reset',0,b'\x00\x00\x1D\x23vosk_recognizer_result',0,b'\x00\x00\x4F\x23vosk_recognizer_set_max_alternatives',0,b'\x00\x00\x4F\x23vosk_recognizer_set_nlsml',0,b'\x00\x00\x4F\x23vosk_recognizer_set_partial_words',0,b'\x00\x00\x4B\x23vosk_recognizer_set_spk_model',0,b'\x00\x00\x4F\x23vosk_recognizer_set_words',0,b'\x00\x00\x56\x23vosk_set_log_level',0,b'\x00\x00\x53\x23vosk_spk_model_free',0,b'\x00\x00\x17\x23vosk_spk_model_new',0), - _struct_unions = ((b'\x00\x00\x00\x5B\x00\x00\x00\x10VoskBatchModel',),(b'\x00\x00\x00\x5C\x00\x00\x00\x10VoskBatchRecognizer',),(b'\x00\x00\x00\x5D\x00\x00\x00\x10VoskModel',),(b'\x00\x00\x00\x5E\x00\x00\x00\x10VoskRecognizer',),(b'\x00\x00\x00\x5F\x00\x00\x00\x10VoskSpkModel',)), - _typenames = (b'\x00\x00\x00\x5BVoskBatchModel',b'\x00\x00\x00\x5CVoskBatchRecognizer',b'\x00\x00\x00\x5DVoskModel',b'\x00\x00\x00\x5EVoskRecognizer',b'\x00\x00\x00\x5FVoskSpkModel'), -)